Created
May 15, 2020 19:43
-
-
Save mingsai/bb7bb71779ab018af63aec2ed6081297 to your computer and use it in GitHub Desktop.
URI encode/decode library for Dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Encode/Decode functions for Dart | |
* | |
* Copyright 2011 Google Inc. | |
* Neil Fraser (fraser@google.com) | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
#library('URI Encode Decode'); | |
/** | |
* Implementation of JavaScript's encodeURI function. | |
* [text] is the string to escape. | |
* Returns the escaped string. | |
*/ | |
String encodeURI(text) { | |
StringBuffer encodedText = new StringBuffer(); | |
final String whiteList = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + | |
'abcdefghijklmnopqrstuvwxyz' + | |
'0123456789-_.!~*\'()#;,/?:@&=+\$'; | |
final String hexDigits = '0123456789ABCDEF'; | |
for (int i = 0; i < text.length; i++) { | |
if (whiteList.indexOf(text[i]) != -1) { | |
// This character doesn't need encoding. | |
encodedText.add(text[i]); | |
continue; | |
} | |
int charCode = text.charCodeAt(i); | |
List<int> byteList = []; | |
if (charCode < 0x80) { | |
// One-byte code. | |
// 0xxxxxxx | |
byteList.add(charCode); | |
} else if (charCode < 0x800) { | |
// Two-byte code. | |
// 110xxxxx 10xxxxxx | |
byteList.add(charCode >> 6 | 0xC0); | |
byteList.add(charCode & 0x3F | 0x80); | |
} else if (0xD800 <= charCode && charCode < 0xDC00) { | |
// Low surrogate. Next char must be a high surrogate. | |
int nextCharCode = text.length == i + 1 ? 0 : text.charCodeAt(i + 1); | |
if (0xDC00 <= nextCharCode && nextCharCode < 0xE000) { | |
// Four-byte surrogate pair. | |
// 11110xxx 10xxxxxx 10xxyyyy 10yyyyyy | |
// Where xxxxxxxxxxx is offset by 1000000 (0x40) | |
charCode += 0x40; | |
byteList.add(charCode >> 8 & 0x7 | 0xF0); | |
byteList.add(charCode >> 2 & 0x3F | 0x80); | |
byteList.add(((charCode & 0x3) << 4) | | |
(nextCharCode >> 6 & 0xF) | 0x80); | |
byteList.add(nextCharCode & 0x3F | 0x80); | |
} else { | |
throw new | |
IllegalArgumentException('URI malformed: Orphaned low surrogate.'); | |
} | |
// Skip next character. | |
i++; | |
} else if (0xDC00 <= charCode && charCode < 0xE000) { | |
throw new | |
IllegalArgumentException('URI malformed: Orphaned high surrogate.'); | |
} else if (charCode < 0x10000) { | |
// Three-byte code. | |
// 1110xxxx 10xxxxxx 10xxxxxx | |
byteList.add(charCode >> 12 | 0xE0); | |
byteList.add(charCode >> 6 & 0x3F | 0x80); | |
byteList.add(charCode & 0x3F | 0x80); | |
} | |
for (int i = 0; i < byteList.length; i++) { | |
encodedText.add('%').add(hexDigits[byteList[i] >> 4]) | |
.add(hexDigits[byteList[i] & 0xF]); | |
} | |
} | |
return encodedText.toString(); | |
} | |
/** | |
* Implementation of JavaScript's encodeURIComponent function. | |
* [text] is the string to escape. | |
* Return the escaped string. | |
*/ | |
String encodeURIComponent(text) { | |
// This is the same as encodeURI except the following are also escaped: | |
// #;,/?:@&=+$ -> %23%3B%2C%2F%3F%3A%40%26%3D%2B%24 | |
text = encodeURI(text); | |
return text.replaceAll('#', '%23') | |
.replaceAll(';', '%3B') | |
.replaceAll(',', '%2C') | |
.replaceAll('/', '%2F') | |
.replaceAll('?', '%3F') | |
.replaceAll(':', '%3A') | |
.replaceAll('@', '%40') | |
.replaceAll('&', '%26') | |
.replaceAll('=', '%3D') | |
.replaceAll('+', '%2B') | |
.replaceAll('\$', '%24'); | |
} | |
/** | |
* Implementation of JavaScript's decodeURI function. | |
* [text] is the string to unescape. | |
* Returns the unescaped string. | |
*/ | |
String decodeURI(text) { | |
final String hexDigits = '0123456789ABCDEF'; | |
// First, break up the text into parts. | |
List<String> parts = text.split('%'); | |
int state = 0; | |
int multiByte; // Temp register for assembling a multi-byte value. | |
bool surrogate = false; | |
// Skip the first element, it's guaranteed to be a (possibly empty) string. | |
for (int i = 1; i < parts.length; i++) { | |
String part = parts[i]; | |
if (part.length < 2) { | |
throw new IllegalArgumentException('URI malformed: Missing digits.'); | |
} | |
int hex1 = hexDigits.indexOf(part[0].toUpperCase()); | |
int hex2 = hexDigits.indexOf(part[1].toUpperCase()); | |
parts[i] = part.substring(2); | |
if (hex1 == -1 || hex2 == -1) { | |
throw new IllegalArgumentException('URI malformed: Invalid digits.'); | |
} | |
int charCode = hex1 * 16 + hex2; | |
if (state == 0) { | |
if (charCode < 0x80) { | |
// One-byte code. | |
// 0xxxxxxx | |
multiByte = charCode; | |
state = 0; | |
} else if ((charCode & 0xE0) == 0xC0) { | |
// Two-byte code. | |
// 110xxxxx 10xxxxxx | |
multiByte = charCode & 0x1F; | |
state = 1; | |
} else if ((charCode & 0xF0) == 0xE0) { | |
// Three-byte code. | |
// 1110xxxx 10xxxxxx 10xxxxxx | |
multiByte = charCode & 0xF; | |
state = 2; | |
} else if ((charCode & 0xF8) == 0xF0) { | |
// Four-byte surrogate pair. | |
// 11110xxx 10xxxxxx 10xxyyyy 10yyyyyy | |
multiByte = charCode & 0x7; | |
state = 3; | |
surrogate = true; | |
} else { | |
throw new IllegalArgumentException('URI malformed: Unknown Unicode.'); | |
} | |
} else { | |
// All continuation bytes are in the form 10xxxxxx. | |
if ((charCode & 0xC0) != 0x80) { | |
throw new IllegalArgumentException('URI malformed: Expect 10xxxxxx.'); | |
} | |
multiByte = (multiByte << 6) | (charCode & 0x3F); | |
state--; | |
} | |
if (state == 0) { | |
// Character is fully assembled. Add to string. | |
if (surrogate) { | |
surrogate = false; | |
// Insert surrogate pair. | |
// xxxxxxxxxxxyyyyyyyyyy (21 bits) | |
// Where xxxxxxxxxxx is offset by 1000000 (0x40) | |
int x = (multiByte >> 10) - 0x40 + 0xD800; | |
int y = (multiByte & 0x3FF) + 0xDC00; | |
if (x >= 0xDC00 || y >= 0xE000) { | |
throw new | |
IllegalArgumentException('URI malformed: Invalid surrogate.'); | |
} | |
parts.insertRange(i, 1, new String.fromCharCodes([x, y])); | |
} else { | |
// Insert a single character. | |
parts.insertRange(i, 1, new String.fromCharCodes([multiByte])); | |
} | |
// Skip the element we just inserted. | |
i++; | |
} else { | |
// This code must be directly followed by another code. | |
if (!parts[i].isEmpty()) { | |
throw new IllegalArgumentException('URI malformed: Incomplete code.'); | |
} | |
} | |
} | |
if (state != 0) { | |
throw new IllegalArgumentException('URI malformed: Truncated code.'); | |
} | |
return Strings.join(parts, ''); | |
} | |
/** | |
* Implementation of JavaScript's decodeURIComponent function. | |
* [text] is the string to unescape. | |
* Returns the unescaped string. | |
*/ | |
String decodeURIComponent(text) { | |
return decodeURI(text); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment