代码拉取完成,页面将自动刷新
/*
* Copyright (c) 2021-2024 Huawei Device Co., Ltd.
* 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.
*/
package escompat;
interface UrlDataInterface {
port: number;
isSpecialPath: boolean;
path: Array<string>;
password: string;
scheme: string;
query: string;
username: string;
fragment: string;
host: string;
}
class UrlData implements UrlDataInterface {
port: number = -1;
isSpecialPath: boolean = false;
path: Array<string> = new Array<string>();
password: string = '';
scheme: string = '';
query: string = '';
username: string = '';
fragment: string = '';
host: string = '';
}
enum BitsetStatusFlag {
BIT0 = 0,
BIT1 = 1,
BIT2 = 2,
BIT3 = 3,
BIT4 = 4,
BIT5 = 5,
BIT6 = 6,
BIT7 = 7,
BIT8 = 8,
BIT9 = 9,
BIT10 = 10,
BIT11 = 11,
BIT_STATUS_11 = 11 // 可以使用这个枚举值作为上限
}
export class URL
{
private static readonly MAX_BIT_SIZE: number = 128;
private specialCharSet: Set<number> = new Set<number>();
private g_head: Map<string, number> = new Map<string, number>();
public constructor() {
this.specialCharSet = new Set<number>();
this.PreliminaryWork();
this.g_head = new Map<string, number>([
["ftp:", 21],
["file:", -1],
["gopher:", 70],
["http:", 80],
["https:", 443],
["ws:", 80],
["wss:", 443]
] as [string, number][]);
}
static parseURL(inputUrl: string, baseUrl?: string | URL): URL
{
return new URL(inputUrl);
}
public getLength(): int
{
return this.inputUrl_.length as int;
}
public IsASCIITabOrNewline(ch: string): boolean
{
return ch === '\t' || ch === '\n' || ch === '\r';
}
private setFlag(flag: int): void {
if (flag >= 0 && flag < this.urlStatus.length) {
this.urlStatus[flag] = 1;
}
}
private isAlpha(char: string): boolean {
return (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z');
}
// Helper private to check if a character is alphanumeric (a-z, A-Z, 0-9)
private isAlphanumeric(char: string): boolean {
return (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9');
}
// Helper private to check if a character is uppercase
private isUppercase(char: string): boolean {
return char >= 'A' && char <= 'Z';
}
private isSpecial(scheme: string): boolean {
const specialSchemes = [
"ftp:", "file:", "gopher:", "http:", "https:", "ws:", "wss:"
];
for (let i = 0; i < specialSchemes.length; i++) {
if (specialSchemes[i] === scheme) {
return true;
}
}
return false;
}
private isFileNoHost(path: string): boolean {
return path.length == 2 && string(path[1]) == ':';
}
private isNumber(str: string, radix: number): boolean {
const num = parseInt(str, 10); // 默认解析为十进制
if (!isNaN(num)) {
radix = 10; // 将进制设为 10
return true;
}
return false;
}
private binaryConversion(num: string, radix: number): string {
let val: number = 0;
if (radix == 16) { // 16: hex
if (num.substring(2).length == 0) { // 跳过 "0x" 前缀
return "0";
}
val = parseInt(num, 16);
if (isNaN(val)) {
return num; // 转换失败,返回原始字符串
}
return string(val); // 返回十进制字符串
} else if (radix == 8) { // 8: octal
if (num.substring(1).length == 0) { // 跳过 "0" 前缀
return "0";
}
val = parseInt(num, 8);
if (isNaN(val)) {
return num; // 转换失败,返回原始字符串
}
return string(val); // 返回十进制字符串
} else {
return num; // 不支持的进制,返回原始字符串
}
}
private RemovalIpv4(temp: Array<string>, str: string, urlStatus: number[]): boolean {
const parts = str.split('.'); // 使用 split 来分割字符串
const tmpLen = parts.length;
const res: string[] = [];
// Process each part and convert if valid number
for (let i = 0; i < tmpLen; ++i) {
let radix = 0;
if (this.isNumber(parts[i], radix)) {
res[res.length] = this.binaryConversion(parts[i], radix);
} else {
return false;
}
}
// 使用 for 循环替换 push(...res)
for (let i = 0; i < res.length; i++) {
temp.push(res[i]);
}
let isIpv4 = true;
// Check for empty strings and update urlStatus
for (let i = 0; i < tmpLen; ++i) {
if (temp[i] === "") {
isIpv4 = false;
this.urlStatus[0] = 1; // Setting BIT0 to 1
if (i == tmpLen - 1) {
temp.push(""); // Append an empty string
this.urlStatus[0] = 0; // Reset BIT0 to 0
}
}
}
return isIpv4;
}
private SplitNum(num: string, number: number): string {
// 如果数字字符串的长度大于 8,直接返回该数字并将number设置为其长度
if (num.length > 8) {
number = num.length;
return num;
}
// 将字符串转换为整数
let val = parseInt(num, 10);
const nums: string[] = [];
let res = "";
// 将数字分解为 IPv4 地址的每个部分(每部分 <= 255)
while (val > 0) {
const numConver = val % 256; // 获取当前部分
nums[nums.length] = string(numConver);
val = Math.floor(val / 256); // 更新剩余的值
}
// 拼接每一部分,形成最终的字符串
for (let i = nums.length - 1; i >= 0; --i) {
res += nums[i] + ".";
}
// 设置number为分割后的部分数
number = nums.length;
// 返回去掉最后一个多余的点
return res.slice(0, res.length - 1);
}
private toLower(str: string): string {
return str.toLowerCase();
}
private IsFormatIpv4(nums: Array<string>): number {
const len = nums.length;
// Iterate through each part of the IPv4 address
for (let i = 0; i < len; ++i) {
// Check if any part of the number is too large (greater than 8 digits)
if (nums[i].length > 8) { // 8: maximum size for an IPv4 part
return i;
}
// Check if the number is valid (not empty and less than or equal to 255)
const num = parseInt(nums[i], 10);
if (nums[i] !== "" && (num > 255 || isNaN(num))) { // 255: IPv4 max value
return i;
}
}
return -1; // Return -1 if all parts are valid
}
private FormatIpv4(nums: Array<string>, host: string, urlStatus: number[]): void {
const len = nums.length;
const index: number = this.IsFormatIpv4(nums); // 获取格式验证结果
let res = "";
if (index == -1) {
// 如果格式验证通过,拼接 IPv4 地址,并补零
for (let i = 0; i < len - 1; ++i) {
res += nums[i] + ".";
}
for (let i = 0; i < 4 - len; ++i) { // 4: ipv4 最大部分数
res += "0.";
}
res += nums[len - 1];
host = res;
this.urlStatus[4] = 1; // 设置 BitsetStatusFlag.BIT4 为 1
} else if (index == len - 1) {
// 如果格式验证失败但是最后一部分,处理补全
for (let i = 0; i < len - 1; ++i) {
res += nums[i] + ".";
}
let number: number = 0;
let temp = this.SplitNum(nums[index], number); // 获取最后一部分的拆分结果
if (number + (len - 1) > 4) { // 4: ipv4 最大部分数
this.urlStatus[0] = 1; // 设置 BitsetStatusFlag.BIT0 为 1
return;
}
// 补全零以保证有 4 个部分
for (let i = 0; i < 4 - (len - 1 + number); ++i) { // 4: ipv4 最大部分数
temp = "0." + temp;
}
host = res + temp;
this.urlStatus[4] = 1; // 设置 BitsetStatusFlag.BIT4 为 1
} else {
// 如果格式验证失败且不是最后一部分,返回
this.urlStatus[0] = 1; // 设置 BitsetStatusFlag.BIT0 为 1
return;
}
}
private toHex(num: number): string {
const hexDigits = "0123456789abcdef"; // 十六进制字符集
let hexStr = "";
while (num > 0) {
const remainder = num % 16; // 获取当前最低位
hexStr = hexDigits[remainder] + hexStr; // 拼接对应的十六进制字符
num = Math.floor(num / 16); // 除以16,准备下一位
}
// 如果结果为空,说明数字是0,返回"0"
return hexStr || "0";
}
private DealIpv4(str: string, urlStatus: number[]): string {
const temp: string[] = [];
let pos = str.lastIndexOf(":");
let index = pos;
let left = pos + 1;
let hexVal: string;
let val: string = "";
// 查找 IPv4 地址中的每个部分,并将其转换为十六进制
while ((pos = str.indexOf(".", left)) != -1) {
val = str.substring(left, pos);
// 手动转换为两位十六进制
const num = parseInt(val, 10);
if (isNaN(num)) {
this.urlStatus[0] = 1; // 设置urlStatus为错误
return str;
}
// 使用自定义的十六进制转换函数
hexVal = this.toHex(num);
// 确保每个十六进制值是两位
if (hexVal.length == 1) {
hexVal = '0' + hexVal; // 如果长度小于2,前面补零
}
temp[temp.length] = hexVal;
left = pos + 1;
}
// 处理最后一部分
val = str.substring(left);
const num = parseInt(val, 10);
if (isNaN(num)) {
this.urlStatus[0] = 1; // 设置urlStatus为错误
return str;
}
hexVal = this.toHex(num);
if (hexVal.length == 1) {
hexVal = '0' + hexVal; // 如果长度小于2,前面补零
}
temp[temp.length] = hexVal;
// 构建最终的IPv6地址
let res = str.substring(0, index);
res = res + ":" + temp[0] + temp[1] + ":" + temp[2] + temp[3]; // 连接转换后的IPv6地址部分
return res;
}
private checkCharacter(data: string, rule: Array<number>): boolean {
let dataLen = data.length;
for (let i = 0; i < dataLen; ++i) {
// 获取当前字符的 ASCII 码
let charCode = data.charCodeAt(i);
// 检查字符是否在合法范围内
if (charCode >= 0 && charCode < rule.length) {
// 检查该字符是否在规则中非法
if (rule[charCode]) {
return false; // 如果字符非法,返回 false
}
}
}
return true; // 如果所有字符都合法,返回 true
}
private isHexDigit(ch: string): boolean {
// 确保输入是一个单个字符
if (ch.length != 1) {
return false;
}
// 检查字符是否是数字或字母 A-F/a-f
return (
(ch >= '0' && ch <= '9') || // 数字 0-9
(ch >= 'A' && ch <= 'F') || // 大写字母 A-F
(ch >= 'a' && ch <= 'f') // 小写字母 a-f
);
}
private decodeSpecialChars(input: string): string {
let temp = input;
let len = temp.length;
if (input === "") {
return temp;
}
let pos = temp.indexOf("%");
while (pos != -1 && pos < len - 2) { // 2:end subscript backspace
if (this.isHexDigit(string(temp[pos + 1])) && this.isHexDigit(string(temp[pos + 2]))) { // 2: Determine the second character after %
let subStr = temp.substr(pos + 1, 2); // 2: Truncate the last two digits of the %
// Convert the hex string to an integer
let octNum = parseInt(subStr, 16);
if (isNaN(octNum)) {
return temp;
}
// Convert the hex number to a character and replace in the string
let convertedChar = String.fromCharCode(octNum);
temp = temp.slice(0, pos) + convertedChar + temp.slice(pos + 3); // Replace the percent character with the corresponding char
len = len - 2; // After the replacement, the length of the string is reduced by two
}
pos = temp.indexOf("%", pos + 1); // Find the next occurrence of '%'
}
return temp;
}
private SkipSlashSymbol(input: string, pos: number): void {
let inputLen = input.length;
while (pos < inputLen) {
if (string(input[pos]) == '/' || string(input[pos]) == '\\') {
pos++;
continue;
}
break;
}
input = input.substr(pos);
}
private JudgePos(pos: number, length: number, input: string) {
for (pos = 0; pos < length; pos++) {
if (string(input[pos]) == '/' || string(input[pos]) == '\\') {
break;
}
}
}
private ParsingHostAndPath(input: string, UrlData: UrlData, pos: number, urlStatus: number[]) {
let special = true;
const length = input.length;
this.JudgePos(pos, length, input);
let strHost = input.substring(0, pos);
let strPath = input.substring(pos + 1);
if (strHost.indexOf('@')!= -1) {
this.AnalysisUsernameAndPasswd(strHost, UrlData.username, UrlData.password, this.urlStatus);
}
if (strHost === "") {
this.urlStatus[0] = 1;
return;
}
const lastIndex = strHost.length - 1;
if (string(strHost[lastIndex])!= ']' && (pos = strHost.lastIndexOf(':'))!= -1) {
if (pos!= -1) {
const port = strHost.substring(pos + 1);
strHost = strHost.substring(0, pos);
this.AnalysisPort(port, UrlData, this.urlStatus);
}
}
if (string(strHost[lastIndex])!= ']' && strHost.lastIndexOf(':')!= -1 && this.urlStatus[0]) {
return;
}
this.AnalysisHost(strHost, UrlData.host, this.urlStatus, special);
this.AnalysisPath(strPath, UrlData.path, this.urlStatus, special);
}
private FormatIpv6(str: string): string {
let pos = str.indexOf("::");
let index = pos;
if (pos!= -1) {
let left: number = 0;
let count = 0;
while ((pos = str.indexOf(":", left))!= -1) {
count++;
left = pos + 1;
}
const size = 7 - (count - 2);
let temp = "";
for (let i = 0; i < size - 1; i++) {
temp += ":0";
}
temp += ":";
str = str.replace(str.substring(index, index + 2), temp);
if (index == 0) {
str = "0" + str;
}
}
return str;
}
private RemoveLeadingZeros(ipv6: Array<string>) {
const len = ipv6.length;
for (let i = 0; i < len; i++) {
const strLen = ipv6[i].length;
let count = 0;
let j = 0;
for (j = 0; j < strLen; j++) {
if (string(ipv6[i][j])!= '0') {
break;
}
count++;
}
if (count == strLen) {
ipv6[i] = "0";
} else if (count!= 0) {
ipv6[i] = ipv6[i].substring(j);
}
}
}
private ZeroCompression(ipv6: Array<string>): string {
let maxIndex = 0;
let maxSize = 0;
let index = 0;
let size = 0;
let isNeedZeroCompression = false;
const len = ipv6.length;
for (let i = 0; i < len; i++) {
index = i;
size = 0;
while (i < len && ipv6[i] === "0") {
isNeedZeroCompression = true;
size++;
i++;
}
if (maxSize < size) {
maxSize = size;
maxIndex = index;
}
}
let res = "";
const ipv6Len = ipv6.length;
for (let i = 0; i < ipv6Len; i++) {
if (isNeedZeroCompression && i == maxIndex) {
if (maxIndex == 0) {
res += "::";
} else {
res += ":";
}
i += maxSize - 1;
continue;
}
res += ipv6[i];
if (i!= ipv6Len - 1) {
res += ":";
}
}
return res;
}
private Compress(str: string): string {
let temp: Array<string> = new Array<string>();
let pos: number = 0;
let left: number = 0;
while ((pos = str.indexOf(":"))!= -1) {
temp.push(str.substring(left, pos));
left = pos + 1;
}
temp.push(str.substring(left));
this.RemoveLeadingZeros(temp);
let res: string = this.ZeroCompression(temp);
res = res.toLowerCase();
return res;
}
private IPv6Host(input: string, host: string, urlStatus: number[]) {
const ipv6 = new RegExp(
"(::|(:((:[0-9A-Fa-f]{1,4}){1,7}))|(([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|:))|(((:(:[0-9A-Fa-f]{1,4}){0,5}:)|(([0-9A-Fa-f]{1,4}:){1}(:[0-9A-Fa-f]{1,4}){0,4}:)|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}:)|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){0,2}:)|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4})?:)|(([0-9A-Fa-f]{1,4}:){5}:)|(([0-9A-Fa-f]{1,4}:){6}))((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)))(%[a-zA-Z0-9._]+)?");
if (!input.match(ipv6)) {
this.urlStatus[0] = 1;
return;
}
let pos: number = 0;
pos = input.indexOf('.');
if (pos!= -1) {
input = this.DealIpv4(input, this.urlStatus);
}
input = this.FormatIpv6(input);
input = this.Compress(input);
host = "[" + input + "]";
this.urlStatus[4] = 1;
this.urlStatus[10] = 1;
}
private AnalysisNoDefaultProtocol(input: string, UrlData: UrlData, urlStatus: number[]) {
if (UrlData.scheme.length == 2) {
this.AnalysisFilescheme(input, UrlData, this.urlStatus);
return;
}
if (string(input[0]) === '/' && string(input[1]) === '/' && string(input[2])!== '/') {
const hostandpath = input.substring(2);
if (hostandpath === "") {
return;
}
let i: number = 0;
let special = false;
let strHost = "";
if (hostandpath.indexOf('/')!= -1) {
i = hostandpath.indexOf('/');
strHost = hostandpath.substring(0, i);
let strPath = hostandpath.substring(i + 1);
if (strHost.indexOf('@')!= -1) {
this.AnalysisUsernameAndPasswd(strHost, UrlData.username, UrlData.password, this.urlStatus);
}
if (strHost === "") {
this.urlStatus[0] = 1;
return;
}
let pos: number = 0;
if (string(strHost[strHost.length - 1])!= ']' && (pos = strHost.lastIndexOf(':'))!= -1) {
let port = strHost.substring(pos + 1);
strHost = strHost.substring(0, pos);
this.AnalysisPort(port, UrlData, this.urlStatus);
}
if (string(strHost[strHost.length - 1])!= ']' && (pos = strHost.lastIndexOf(':'))!= -1 &&
this.urlStatus[0]) {
return;
}
this.AnalysisHost(strHost, UrlData.host, this.urlStatus, special);
this.AnalysisPath(strPath, UrlData.path, this.urlStatus, special);
} else {
strHost = hostandpath;
this.AnalyStrHost(strHost, UrlData, this.urlStatus);
this.AnalyHostPath(strHost, this.urlStatus, UrlData);
this.AnalysisHost(strHost, UrlData.host, this.urlStatus, special);
}
} else if (string(input[0]) == '/' && string(input[1]) == '/') {
let strOfPath = input.substring(1);
this.AnalysisPath(strOfPath, UrlData.path, this.urlStatus, false);
} else {
this.AnalyInfoPath(this.urlStatus, UrlData, input);
}
}
private AnalyInfoPath(urlStatus: number[], UrlData: UrlData, input: string) {
this.urlStatus[9] = 1;
if (UrlData.path.length == 0) {
UrlData.path.push("");
}
UrlData.path[0] = input;
this.urlStatus[6] = 1;
}
private AnalyHostPath(strHost: string, urlStatus: number[], UrlData: UrlData) {
let pos: number = 0;
const lastIndex = strHost.length - 1;
if (string(strHost[lastIndex])!= ']' && (pos = strHost.lastIndexOf(':'))!= -1) {
const port: string = strHost.substring(pos + 1);
strHost = strHost.substring(0, pos);
this.AnalysisPort(port, UrlData, this.urlStatus);
if (this.urlStatus[0]) {
return;
}
}
}
private AnalysisFilescheme(input: string, UrlData: UrlData, urlStatus: number[]) {
let strPath = UrlData.scheme + input;
UrlData.scheme = "file:";
this.urlStatus[1] = 0;
this.AnalysisFilePath(strPath, UrlData, this.urlStatus);
}
private AnalysisOnlyHost(input: string, UrlData: UrlData, urlStatus: number[], pos: number) {
let strHost = input;
if (strHost.indexOf('@')!= -1) {
this.AnalysisUsernameAndPasswd(strHost, UrlData.username, UrlData.password, this.urlStatus);
}
if (strHost === "") {
this.urlStatus[0] = 1;
return;
}
if (string(strHost[strHost.length - 1])!= ']') {
pos = strHost.lastIndexOf(':');
if (pos!= -1) {
let port = strHost.substring(pos + 1);
strHost = strHost.substring(0, pos);
this.AnalysisPort(port, UrlData, this.urlStatus);
}
pos = strHost.lastIndexOf(':');
if (pos!= -1 && this.urlStatus[0]) {
return;
}
}
this.AnalysisHost(strHost, UrlData.host, this.urlStatus, true);
}
private AnalysisPort(input: string, UrlData: UrlData, urlStatus: number[]) {
if (input.length == 0) {
return;
}
for (let i = 0; i < input.length; i++) {
if (isNaN(Number(input[i])) ||!Number.isInteger(Number(input[i]))) {
this.urlStatus[0] = 1;
return;
}
}
if (input.length >= 6) {
this.urlStatus[0] = 1;
return;
}
const it = parseInt(input);
const maxPort = 65535;
if (it > maxPort) {
this.urlStatus[0] = 1;
return;
}
this.urlStatus[5] = 1;
for (const element of this.g_head) {
if (element[0] == UrlData.scheme && element[1] == it) {
UrlData.port = -1;
this.urlStatus[5] = 0;
return;
}
}
UrlData.port = it;
}
private AnalyseIPv4(input: string, host: string, urlStatus: number[]): void {
let isIpv4 = false;
let temp:Array<string> = new Array<string>();
isIpv4 = this.RemovalIpv4(temp, input, this.urlStatus);
const tempLen = temp.length;
const lastSize = temp[tempLen - 1].length;
if (isIpv4 && lastSize > 8) { // 8: ipv4 last number size
this.urlStatus[0] = 1; // equivalent to flags.set(BitsetStatusFlag.BIT0)
return;
}
let res = "";
for (let i = 0; i < tempLen; ++i) {
res += temp[i];
if (i != tempLen - 1) {
res += ".";
}
}
if (isIpv4) {
if (tempLen > 4) { // 4: ipv4 max size
res = this.toLower(res);
host = res;
this.urlStatus[4] = 1; // equivalent to flags.set(BitsetStatusFlag.BIT4)
} else if (tempLen == 4) { // 4: ipv4 max size
if (this.IsFormatIpv4(temp) == -1) {
host = res;
this.urlStatus[4] = 1; // equivalent to flags.set(BitsetStatusFlag.BIT4)
} else {
this.urlStatus[0] = 1; // equivalent to flags.set(BitsetStatusFlag.BIT0)
}
} else {
this.FormatIpv4(temp, host, this.urlStatus);
}
} else {
res = this.toLower(res);
host = res;
this.urlStatus[4] = 1; // equivalent to flags.set(BitsetStatusFlag.BIT4)
}
}
private AnalysisScheme(input: string, scheme: string, urlStatus: number[]): boolean {
if (input.length == 0 || !this.isAlpha(string(input[0]))) {
// Set BIT0 (index 0 in urlStatus) to 1 if the first character is not a letter
this.urlStatus[0] = 1;
return false;
} else {
const strlen = input.length;
for (let i = 0; i < strlen - 1; ++i) {
const char = string(input[i]);
if (this.isAlphanumeric(char) || char == '+' || char == '-' || char == '.') {
// If it's uppercase, convert it to lowercase
if (this.isUppercase(char)) {
input = input.slice(0, i) + char.toLowerCase() + input.slice(i + 1);
}
} else {
// Set BIT0 (index 0 in urlStatus) to 1 if invalid character found
this.urlStatus[0] = 1;
return false;
}
}
this.urlData_.scheme = input;
if (this.isSpecial(this.urlData_.scheme)) {
// Set BIT1 (index 1 in urlStatus) to 1 if it's a special scheme
this.urlStatus[1] = 1;
}
return true;
}
}
private AnalysisFragment(input: string, fragment: string, urlStatus: number[]): void {
fragment = input;
this.urlStatus[8] = 1;
}
private AnalysisQuery(input: string, query: string, urlStatus: number[]): void {
query = input;
this.urlStatus[7] = 1;
}
private AnalysisUsernameAndPasswd(input: string, username: string, password: string, urlStatus: number[]): void {
let pos: number = input.length - 1;
for (; pos >= 0; pos--) {
if (string(input[pos]) == '@') {
break;
}
}
let userAndPasswd: string = input.substring(0, pos);
input = input.substring(pos + 1);
if (userAndPasswd === "") {
return;
}
if (userAndPasswd.indexOf('@')!= -1) {
while (true) {
const posTmp: number = userAndPasswd.indexOf('@');
if (posTmp!= -1) {
userAndPasswd = userAndPasswd.replace('@', '%40');
} else {
break;
}
}
}
let position: number = userAndPasswd.indexOf(':');
if (position!= -1) {
const user: string = userAndPasswd.substring(0, position);
const keyWord: string = userAndPasswd.substring(position + 1);
if (user!== "") {
username = user;
this.urlStatus[2] = 1;
}
if (keyWord!== "") {
password = keyWord;
this.urlStatus[3] = 1;
}
} else {
username = userAndPasswd;
this.urlStatus[2] = 1;
}
}
private AnalysisFilePath(input: string, UrlData: UrlData, urlStatus: number[]): void {
const temp: string[] = [];
let pos: number;
// Split the input string by '/' or '\\' manually, without using indexOf
while (true) {
let pos1 = input.indexOf('/');
let pos2 = input.indexOf('\\');
// Find the first occurrence of either '/' or '\\'
pos = (pos1 != -1 && (pos2 == -1 || pos1 < pos2)) ? pos1 : pos2;
// If no more separators are found, exit the loop
if (pos == -1) break;
temp[temp.length] = input.substring(0, pos);
input = input.substring(pos + 1);
}
// Add the last segment (after the final separator)
temp[temp.length] = input;
const length = temp.length;
for (let i = 0; i < length; ++i) {
// Manually check if the segment exists in doubleSegmentList_ (without indexOf)
let found = false;
for (let j = 0; j < this.doubleSegmentList_.length; j++) {
if (this.doubleSegmentList_[j] === temp[i]) {
found = true;
break;
}
}
if (found) {
if (UrlData.path.length == 1 && this.isFileNoHost(UrlData.path[0]) && UrlData.path[0].length == 2) {
// Handle special case for file paths (e.g., "C:")
UrlData.path[0] = UrlData.path[0].charAt(0) + ':'; // Modify to "C:"
} else if (UrlData.path.length > 0) {
UrlData.path.pop(); // Remove last path segment
}
if (i == temp.length - 1) {
UrlData.path.push(""); // Add empty string for last segment
}
continue;
}
// Manually check if the segment exists in g_singlesegment (without indexOf)
found = false;
for (let j = 0; j < this.singleSegmentList_.length; j++) {
if (this.singleSegmentList_[j] === temp[i]) {
found = true;
break;
}
}
if (found) {
if (i == temp.length - 1) {
UrlData.path.push(""); // Add empty string for last segment
}
continue;
}
// Normal segment handling
UrlData.path.push(temp[i]);
this.urlStatus[6] = 1; // Set BIT6 to indicate path modification
}
const it = UrlData.path[0];
if (this.isAlpha(string(it[0])) && (string(it[1]) == ':' || string(it[1]) == '|')) {
if (it.length == 2) { // Handle special case for single character paths like "C:"
UrlData.path[0] = it[0] + ':';
this.urlStatus[4] = 0; // Set BIT4 to 0
UrlData.host = ""; // Clear host information
}
}
}
private AnalysisOpaqueHost(input: string, urlStatus: number[], host: string): void {
const strlen = input.length;
// 遍历输入字符串中的每个字符
for (let i = 0; i < strlen; ++i) {
const ch = input[i];
// 手动检查字符是否是特殊字符
let isSpecialCharacter = false;
for (let j = 0; j < this.specialCharsList_.length; ++j) {
if (ch == this.specialCharsList_[j]) {
isSpecialCharacter = true;
break; // 找到特殊字符,提前退出循环
}
}
if (string(ch) != '%' && isSpecialCharacter) {
// 如果字符不是 '%' 且是特殊字符,设置 BIT0
this.urlStatus[0] = 1;
return;
}
}
// 如果没有找到特殊字符,设置 host 并设置 BIT4
host = input;
this.urlStatus[4] = 1;
}
private AnalysisHost(input: string, host: string, urlStatus: number[], special: boolean): void {
// 检查输入是否为空,如果为空设置标志位为 BIT0
if (input === '') {
this.urlStatus[0] = 1; // 设置 BIT0
return;
}
// 如果输入以 [ 开头并以 ] 结尾,处理为 IPv6 地址
if (string(input[0]) == '[') {
if (string(input[input.length - 1]) == ']') {
let b = input.length;
input = input.substring(1, b - 1); // 去掉 [] 括号
this.IPv6Host(input, host, this.urlStatus); // 处理 IPv6 地址
return;
} else {
this.urlStatus[0] = 1; // 设置 BIT0 标记错误
return;
}
}
// 如果 special 为 false,处理为不透明主机
if (!special) {
this.AnalysisOpaqueHost(input, this.urlStatus, host);
return;
}
// 解码输入中的特殊字符
const decodeInput = this.decodeSpecialChars(input);
// 检查输入中是否含有特殊字符
if (!this.checkCharacter(decodeInput, this.specialCharForBit_)) {
this.urlStatus[0] = 1; // 设置 BIT0 标记错误
return;
}
// 如果包含特殊字符,进一步解析 IPv4 地址
this.AnalyseIPv4(decodeInput, host, this.urlStatus);
}
private AnalysisSpecialFile(temp: string, pos: number, UrlData: UrlData, urlStatus: number[]): void {
const strHost = temp.substring(0, pos);
const strPath = temp.substring(pos + 1);
let special = true;
if (!this.isFileNoHost(strHost)) {
this.AnalysisHost(strHost, UrlData.host, this.urlStatus, special);
} else if (!this.isFileNoHost(strHost) && this.urlStatus[0]) {
return;
}
if (!this.isFileNoHost(strHost)) {
this.AnalysisFilePath(strPath, UrlData, this.urlStatus);
} else {
this.AnalysisFilePath(temp, UrlData, this.urlStatus);
}
}
private AnalysisFile(input: string, UrlData: UrlData, urlStatus: number[]): void {
let special = true;
if ((string(input[0]) == '/' || string(input[0]) == '\\') && (string(input[1]) == '/' || string(input[1]) == '\\')) {
const temp = input.substring(2);
let pos: number = 0;
if (((pos = temp.indexOf('/'))!= -1 || (pos = temp.indexOf('\\'))!= -1) && pos == 0) {
const newTemp = temp.substring(1);
this.AnalysisFilePath(newTemp, UrlData, this.urlStatus);
} else if (((pos = temp.indexOf('/'))!= -1 || (pos = temp.indexOf('\\'))!= -1) && pos!= 0) {
this.AnalysisSpecialFile(temp, pos, UrlData, this.urlStatus);
} else {
if (temp.length > 0 && this.urlStatus[0]) {
this.AnalysisHost(temp, UrlData.host, this.urlStatus, special);
} else if (temp.length > 0 &&!this.urlStatus[0]) {
this.AnalysisHost(temp, UrlData.host, this.urlStatus, special);
return;
}
}
} else {
if (string(input[0]) == '/' || string(input[0]) == '\\') {
input = input.substring(1);
}
this.AnalysisFilePath(input, UrlData, this.urlStatus);
}
}
private AnalyStrHost(strHost: string, UrlData: UrlData, urlStatus: number[]) {
// 检查字符串中是否存在'@'符号,若存在则调用AnalysisUsernameAndPasswd函数进行处理
if (strHost.indexOf('@')!= -1) {
this.AnalysisUsernameAndPasswd(strHost, UrlData.username, UrlData.password, this.urlStatus);
}
// 如果strHost为空字符串,设置urlStatus数组中对应BIT0的元素为1,表示相应状态
if (strHost === "") {
this.urlStatus[0] = 1;
return;
}
}
private AnalysisPath(input: string, path: Array<string>, urlStatus: number[], isSpecial: boolean) {
let temp: Array<string> = new Array<string>();
let pos: number = 0;
while (((pos = input.indexOf('/'))!= -1) || ((pos = input.indexOf('\\'))!= -1 && isSpecial)) {
temp.push(input.substring(0, pos));
input = input.substring(pos + 1);
}
temp.push(input);
const length: number = temp.length;
for (let it = 0; it < length; it++) {
let result: string = "";
for (let index = 0; index < this.doubleSegmentList_.length; index++) {
if (this.doubleSegmentList_[index] == temp[it]) {
result = this.doubleSegmentList_[index];
break;
}
}
if (result) {
if (path.length == 0 && it == length - 1) {
path.push("");
this.urlStatus[6] = 1;
}
if (path.length == 0) {
continue;
}
path.pop();
if (it == length - 1) {
path.push("");
this.urlStatus[6] = 1;
}
continue;
}
// 使用for循环替换后的查找逻辑,用于查找g_singlesegment中的元素
let singleResult: string = "";
for (let index = 0; index < this.singleSegmentList_.length; index++) {
if (this.singleSegmentList_[index] === temp[it]) {
singleResult = this.singleSegmentList_[index];
break;
}
}
if (singleResult && it == length - 1) {
path.push("");
this.urlStatus[6] = 1;
continue;
}
if (!singleResult) {
path.push(temp[it]);
this.urlStatus[6] = 1;
}
}
}
private AnalysisHostAndPath(input: string, UrlData: UrlData, urlStatus: number[]) {
if (this.urlStatus[1]) {
let pos: number = 0;
this.SkipSlashSymbol(input, pos);
if (input.length == 0) {
this.urlStatus[0] = 1;
return;
} else if (input.indexOf('/')!= -1 || input.indexOf('\\')!= -1) {
this.ParsingHostAndPath(input, UrlData, pos, this.urlStatus);
} else if (input.length!= 0 && input.indexOf('/') == -1 && input.indexOf('\\') == -1) {
this.AnalysisOnlyHost(input, UrlData, this.urlStatus, pos);
}
} else {
const inputLen: number = input.length;
if (inputLen > 0) {
UrlData.isSpecialPath = string(input[0])!== '/'? true : false;
}
this.AnalysisNoDefaultProtocol(input, UrlData, this.urlStatus);
}
}
private AnalysisInput(input: string, urlData: UrlData, urlStatus: number[]) {
let pos: number = 0;
if (input.indexOf('#')!= -1) {
pos = input.indexOf('#');
const fragment: string = input.substring(pos);
this.AnalysisFragment(fragment, urlData.fragment, this.urlStatus);
input = input.substring(0, pos);
}
if (input.indexOf('?')!= -1) {
pos = input.indexOf('?');
const query: string = input.substring(pos);
this.AnalysisQuery(query, urlData.query, this.urlStatus);
input = input.substring(0, pos);
}
let special: boolean = this.urlStatus[1] == 1? true : false;
let pathStr: string = "";
pathStr = input;
this.AnalysisPath(pathStr, urlData.path, this.urlStatus, special);
}
private BaseInfoToUrl(baseInfo: UrlData, baseflags: number[], urlData: UrlData, urlStatus: number[], inputIsEmpty: boolean) {
urlData.scheme = baseInfo.scheme;
this.urlStatus[1] = this.urlStatus[1] == 1? 1 : 0;
urlData.host = baseInfo.host;
this.urlStatus[4] = 1;
urlData.username = baseInfo.username;
this.urlStatus[2] = this.urlStatus[2] == 1? 1 : 0;
urlData.password = baseInfo.password;
this.urlStatus[3] = this.urlStatus[3] == 1? 1 : 0;
urlData.port = baseInfo.port;
this.urlStatus[5] = this.urlStatus[5] == 1? 1 : 0;
if (inputIsEmpty) {
urlData.path = baseInfo.path;
this.urlStatus[6] = this.urlStatus[6] == 1? 1 : 0;
urlData.query = baseInfo.query;
this.urlStatus[7] = this.urlStatus[7] == 1? 1 : 0;
urlData.fragment = baseInfo.fragment;
this.urlStatus[8] = this.urlStatus[8] == 1? 1 : 0;
}
this.urlStatus[9] = this.urlStatus[9] == 1? 1 : 0;
this.urlStatus[10] = this.urlStatus[10] == 1? 1 : 0;
}
// TODO - refer to ArkTS1.0 commonlibrary/ets_utils/js_api_module/url/js_url.cpp PreliminaryWork()
public PreliminaryWork()
{
// Same as ArkTS1.0 g_head
let specialProtocolsList: [string, number][] = [["ftp:", 21], ["file:", -1], ["gopher:", 70], ["http:", 80], ["https:", 443], ["ws:", 80], ["wss:", 443]];
this.specialProtocols_ = new Map<string, number>(Array.from(specialProtocolsList));
this.specialCharForBit_ = new Array<number>(URL.MAX_BIT_SIZE);
// TODO
const specialSymbolsTmp: string[] = ['#', '%', '/', ':', '?', '@', '[', '\\', ']', '<', '>', '^', '|'];
// 假设 BIT_ASCII_32 是 32, 代表 ASCII 字符集的某个字符范围(例如空格符)
const invalidCharLength = 32;
// 设置 0 到 invalidCharLength 范围内的所有字符(假设是控制字符和空格符)
for (let i = 0; i <= invalidCharLength; i++) {
this.specialCharSet.add(i); // 将 ASCII 码添加到 Set 中
}
// 将特殊符号的 ASCII 码加入 Set
for (const symbol of specialSymbolsTmp) {
this.specialCharSet.add(symbol.charCodeAt(0)); // 获取字符的 ASCII 码并添加
}
// 设置 ASCII 127 为特殊字符
this.specialCharSet.add(127);
}
// TODO - refer to ArkTS1.0 commonlibrary/ets_utils/js_api_module/url/js_url.cpp DeleteC0OrSpace(std::string& str)
public DeleteC0OrSpace(str: string): string {
if (str.length == 0) {
return str; // 如果字符串为空,直接返回
}
// 从字符串的开始删除 C0 控制字符和空格
let i = 0;
const len = str.length;
while (i < len) {
if (str.charCodeAt(i) <= 32) { // 空白字符包括 '\0' 到 ' ',charCodeAt 返回字符的 Unicode 编码
i++;
continue;
}
break;
}
// 截取去除前导空白字符后的字符串
str = str.substring(i);
// 如果字符串为空,直接返回
if (str.length == 0) {
return str;
}
// 从字符串的末尾删除 C0 控制字符和空格
let j = str.length - 1;
while (j >= 0) {
if (str.charCodeAt(j) <= 32) { // 空白字符包括 '\0' 到 ' '
j--;
continue;
}
break;
}
// 截取去除尾部空白字符后的字符串
return str.substring(0, j + 1);
}
// TODO - refer to ArkTS1.0 commonlibrary/ets_utils/js_api_module/url/js_url.cpp DeleteTabOrNewline(std::string& str1)
public DeleteTabOrNewline(input: string): string {
let result = ''; // 用于存放处理后的字符串
for (let i = 0; i < input.length; i++) {
// 获取当前字符的 Unicode 编码
let ch = input.charCodeAt(i);
// 判断是否是 Tab 或换行符
if (ch != 9 && ch != 10 && ch != 13) { // Tab: 9, Newline: 10, Carriage return: 13
result += input[i]; // 如果不是 Tab 或换行符,加入到结果中
}
}
return result; // 返回处理后的字符串
}
public InitOnlyInput(input: string, urlData: UrlData, urlStatus: number[]) {
if (input === "") {
this.urlStatus[0] = 1;
return;
}
if (input.indexOf(':')!= -1) {
let pos = input.indexOf(':');
pos++;
let scheme = input.substring(0, pos);
if (!this.AnalysisScheme(scheme, this.urlData_.scheme, this.urlStatus)) {
return;
}
if (input.indexOf('#')!= -1) {
let posTmp = input.indexOf('#');
let fragment = input.substring(posTmp);
this.AnalysisFragment(fragment, urlData.fragment, this.urlStatus);
input = input.substring(0, posTmp);
}
if (input.indexOf('?')!= -1) {
let position = input.indexOf('?');
let query = input.substring(position);
this.AnalysisQuery(query, urlData.query, this.urlStatus);
input = input.substring(0, position);
}
let str = input.substring(pos);
if (urlData.scheme === "file:") {
this.AnalysisFile(str, urlData, this.urlStatus);
} else {
this.AnalysisHostAndPath(str, urlData, this.urlStatus);
}
} else {
this.urlStatus[0] = 1;
return;
}
}
private ToolHasBase(input: string, strInput: string, urlData: UrlData, urlStatus: number[]) {
if (input!= "" && string(input[0]) == '/') {
strInput = input.substring(1);
this.AnalysisInput(strInput, urlData, this.urlStatus);
} else if (input!== "" && string(input[0])!== '/') {
this.AnalysisInput(strInput, urlData, this.urlStatus);
}
}
private ShorteningPath(urlData: UrlData, baseData: UrlData, isFile: boolean) {
if (baseData.path.length == 0) {
return;
}
if (urlData.path.length == 1 && urlData.path[0] == "") {
urlData.path.pop();
return;
}
if (baseData.path.length == 1 && isFile &&
((string(baseData.path[0][0]) >= 'a' && string(baseData.path[0][0]) <= 'z') || (string(baseData.path[0][0]) >= 'A' && string(baseData.path[0][0]) <= 'Z')) &&
string(baseData.path[0][1]) == ':') {
return;
}
baseData.path.pop();
}
private BasePathToStr(urlData: UrlData): string {
let temp: string = "";
const length: number = urlData.path.length;
for (let i: number = 0; i < length; i++) {
if (i < length - 1) {
temp += urlData.path[i] + "/";
} else {
temp += urlData.path[i];
}
}
return temp;
}
// TODO - refer to ArkTS1.0 commonlibrary/ets_utils/js_api_module/url/js_url.cpp URL::URL(const std::string& input)
private constructor(inputUrl: string)
{
this.inputUrl_ = inputUrl;
this.PreliminaryWork();
this.DeleteC0OrSpace(inputUrl);
this.DeleteTabOrNewline(inputUrl);
this.InitOnlyInput(inputUrl, this.urlData_, this.urlStatus);
}
private DelCont(strBase: string, strInput: string, baseInfo: UrlData, urlStatus: number[])
{
this.DeleteC0OrSpace(strBase);
this.DeleteTabOrNewline(strBase);
this.DeleteC0OrSpace(strInput);
this.DeleteTabOrNewline(strInput);
this.InitOnlyInput(strBase, baseInfo, this.urlStatus);
}
private constructor(input: string, base: string) {
let baseUrlStatus: number[] = [];
let baseInfo: UrlData = new UrlData();
let strBase: string = base;
let strInput: string = input;
if (strBase === "") {
baseUrlStatus[0] = 1; // 模拟设置对应位,假设这里索引0对应类似BIT0的情况,按实际需求调整
}
this.DelCont(strBase, strInput, baseInfo, baseUrlStatus);
if (baseUrlStatus[0] == 1) {
this.urlStatus[0] = 1;
return;
} else if (baseUrlStatus[0]!= 1) {
this.InitOnlyInput(strInput, this.urlData_, this.urlStatus);
if (!this.urlStatus[0]) {
return;
}
if ((string(input[0]) == '/') && (string(input[1]) == '/' || (string(input[1]) == '\\' && baseUrlStatus[1] == 1))) {
let newInput: string = baseInfo.scheme + input;
this.urlStatus[0] = 0;
this.InitOnlyInput(newInput, this.urlData_, this.urlStatus);
return;
}
if (!baseUrlStatus[9]) {
this.urlStatus[0] = 0;
this.BaseInfoToUrl(baseInfo, baseUrlStatus, this.urlData_, this.urlStatus, input === "");
this.ToolHasBase(input, strInput, this.urlData_, this.urlStatus);
if (input!= "" && string(input[0])!== '/' && this.urlData_.path == "") {
this.urlData_.path = baseInfo.path;
this.urlStatus[6] = baseUrlStatus[6];
}
if (input!= "" && string(input[0])!= '/' && this.urlData_.path!= "") {
let isFile: boolean = (this.urlData_.scheme === "file:");
this.ShorteningPath(this.urlData_, baseInfo, isFile);
let basePathStr: string = this.BasePathToStr(baseInfo);
basePathStr === ""? basePathStr = strInput : basePathStr += "/" + strInput;
this.urlData_.path.length = 0;
this.AnalysisInput(basePathStr, this.urlData_, this.urlStatus);
this.urlStatus[6] = 1;
}
} else if (baseUrlStatus[9]) {
this.urlStatus[0] = 1;
return;
}
}
}
private constructor(input: string, base: URL) {
let strInput: string = input;
let baseInfo: UrlData = base.urlData_;
let baseUrlStatus: number[] = base.urlStatus;
this.DeleteC0OrSpace(strInput);
this.DeleteTabOrNewline(strInput);
this.InitOnlyInput(strInput, this.urlData_, this.urlStatus);
if (!this.urlStatus[0]) {
return;
}
if ((string(input[0]) == '/') && (string(input[1]) == '/' || (string(input[1]) == '\\' && baseUrlStatus[1] == 1))) {
let newInput: string = baseInfo.scheme + input;
this.urlStatus[0] = 0;
this.InitOnlyInput(newInput, this.urlData_, this.urlStatus);
return;
}
if (!baseUrlStatus[9]) {
this.urlStatus[0] = 0;
this.BaseInfoToUrl(baseInfo, baseUrlStatus, this.urlData_, this.urlStatus, input === "");
this.ToolHasBase(input, strInput, this.urlData_, this.urlStatus);
if (input!= "" && string(input[0])!= '/' && this.urlData_.path == "") {
this.urlData_.path = baseInfo.path;
this.urlStatus[6] = baseUrlStatus[6];
}
if (input!= "" && string(input[0])!= '/' && this.urlData_.path!= "") {
let isFile: boolean = (this.urlData_.scheme === "file:");
this.ShorteningPath(this.urlData_, baseInfo, isFile);
let basePathStr: string = this.BasePathToStr(baseInfo);
basePathStr === ""? basePathStr = strInput : basePathStr += "/" + strInput;
this.urlData_.path.length = 0;
this.AnalysisInput(basePathStr, this.urlData_, this.urlStatus);
this.urlStatus[6] = 1;
}
} else if (baseUrlStatus[9]) {
this.urlStatus[0] = 1;
return;
}
}
public customEncodeURI(str: string, keepCharacters: object): string {
let encodedStr = '';
try {
encodedStr = encodeURI(str);
} catch (error) {
encodedStr = encodeURI(str.toWellFormed());
}
for (let key in keepCharacters) {
encodedStr = encodedStr.replaceAll(`${key}`, keepCharacters[key]);
}
return encodedStr;
}
public toJSON(): string {
return this.href_;
}
public toString(): string {
return this.href_;
}
public gethash(): string{
return this.hash_;
}
public gethost(): string{
return this.host_;
}
public gethostname(): string{
return this.hostname_;
}
public gethref(): string{
return this.href_;
}
public getpassword(): string{
return this.password_;
}
public getpathname(): string{
return this.pathname_;
}
public getport(): string{
return this.port_;
}
public getprotocol(): string{
return this.protocol_;
}
public getorigin(): string {
let kOpaqueOrigin: string = 'null';
switch (this.protocol_) {
case 'ftp:':
case 'gopher:':
case 'http:':
case 'https:':
case 'ws:':
case 'wss:':
return this.origin_;
}
return kOpaqueOrigin;
}
public getsearch(): string {
return this.search_;
}
public getusername(): string {
return this.username_;
}
private inputUrl_: string = "";
private urlData_ = new UrlData();
// Same as ArkTS1.0 URL::flags
private urlStatus: number[] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
private href_: string = '';
private search_: string = '';
private origin_: string = '';
private username_: string = '';
private password_: string = '';
private hostname_: string = '';
private host_: string = '';
private hash_: string = '';
private protocol_: string = '';
private pathname_: string = '';
private port_: string = '';
private specialProtocols_: Map<string, number> = new Map<string, number>();
// Same as ArkTS1.0 g_doubleSegment
private doubleSegmentList_: string[] = ["..", ".%2e", ".%2E", "%2e.", "%2E.", "%2e%2e", "%2E%2E", "%2e%2E", "%2E%2e"];
// Same as ArkTS1.0 g_singlesegment
private singleSegmentList_: string[] = [".", "%2e", "%2E"];
// Same as ArkTS1.0 g_specialSymbols
private specialSymbolsList_: string[] = ["@", "%40", "#", "%23", "=", "%3D", ":", "%3A", "/", "%2F", ";", "%3B", "?", "%3F"];
// Same as ArkTS1.0 g_specialcharacter
private specialCharsList_: char[] = [ c'\0', c'\t', c'\n', c'\r', c' ', c'#', c'%', c'/', c':', c'?', c'@', c'[', c'\\', c']'];
// Same as ArkTS1.0 g_specialCharForBit
private specialCharForBit_: Array<number> = new Array<number>();
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。