• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (c) 2022 Huawei Device Co., Ltd.
3   * Licensed under the Apache License, Version 2.0 (the "License");
4   * you may not use this file except in compliance with the License.
5   * You may obtain a copy of the License at
6   *
7   *     http://www.apache.org/licenses/LICENSE-2.0
8   *
9   * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  
16  #include "js_url.h"
17  #include <regex>
18  #include <sstream>
19  #include "securec.h"
20  #include "unicode/stringpiece.h"
21  #include "unicode/unistr.h"
22  #include "utils/log.h"
23  namespace OHOS::Url {
24      std::map<std::string, int> g_head = {
25          {"ftp:", 21}, {"file:", -1}, {"gopher:", 70}, {"http:", 80},
26          {"https:", 443}, {"ws:", 80}, {"wss:", 443}
27      };
28  
29      std::vector<std::string> g_doubleSegment = {
30          "..", ".%2e", ".%2E", "%2e.", "%2E.",
31          "%2e%2e", "%2E%2E", "%2e%2E", "%2E%2e"
32      };
33  
34      std::vector<std::string> g_singlesegment = { ".", "%2e", "%2E" };
35      std::vector<std::string> g_specialSymbols = {
36          "@", "%40", "#", "%23", "=", "%3D", ":", "%3A",
37          "/", "%2F", ";", "%3B", "?", "%3F"
38      };
39      std::vector<char> g_specialcharacter = {
40          '\0', '\t', '\n', '\r', ' ', '#', '%', '/', ':', '?',
41          '@', '[', '\\', ']'
42      };
43  
ReplaceSpecialSymbols(std::string & input,std::string & oldstr,std::string & newstr)44      void ReplaceSpecialSymbols(std::string& input, std::string& oldstr, std::string& newstr)
45      {
46          size_t oldlen = oldstr.size();
47          while (true) {
48              size_t pos = 0;
49              if ((pos = input.find(oldstr)) != std::string::npos) {
50                  input.replace(pos, oldlen, newstr);
51                  continue;
52              }
53                  break;
54          }
55      }
56  
57      template<typename T>
IsASCIITabOrNewline(const T ch)58      bool IsASCIITabOrNewline(const T ch)
59      {
60          return (ch == '\t' || ch == '\n' || ch == '\r');
61      }
62  
63      template<typename T>
IsHexDigit(const T ch)64      bool IsHexDigit(const T ch)
65      {
66          if (isdigit(ch) || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
67              return true;
68          }
69          return false;
70      }
71  
AsciiToHex(const unsigned char pram)72      unsigned AsciiToHex(const unsigned char pram)
73      {
74          if (pram >= '0' && pram <= '9') {
75              return pram - '0';
76          } else if (pram >= 'A' && pram <= 'F') {
77              return pram - 'A' + 10; // 10:Convert to hexadecimal
78          } else if (pram >= 'a' && pram <= 'f') {
79              return pram - 'a' + 10; // 10:Convert to hexadecimal
80          }
81          return static_cast<unsigned>(pram);
82      }
83  
DecodePercent(const char * input,size_t len)84      std::string DecodePercent(const char *input, size_t len)
85      {
86          std::string temp;
87          if (len == 0) {
88              return temp;
89          }
90          temp.reserve(len);
91          const char *it = input;
92          const char *end = input + len;
93          while (it < end) {
94              const char ch = it[0];
95              size_t left = end - it - 1;
96              if (ch != '%' || left < 2 || (ch == '%' && (!IsHexDigit(it[1]) || // 2:The length is less than 2
97                  !IsHexDigit(it[2])))) { // 2:The number of characters is less than 2
98                  temp += ch;
99                  it++;
100                  continue;
101              } else {
102                  unsigned first = AsciiToHex(it[1]);
103                  unsigned second = AsciiToHex(it[2]); // 2:Subscript 2
104                  char pram = static_cast<char>(first * 16 + second); // 16:Convert hex
105                  temp += pram;
106                  it += 3; // 3:Move the pointer to the right by 3 digits.
107              }
108          }
109          return temp;
110      }
111  
DeleteC0OrSpace(std::string & str)112      void DeleteC0OrSpace(std::string& str)
113      {
114          if (str.empty()) {
115              return;
116          }
117          size_t i = 0;
118          size_t strlen = str.size();
119          while (i < strlen) {
120              if (str[i] >= '\0' && str[i] <= ' ') {
121                  i++;
122                  continue;
123              }
124                  break;
125          }
126          str = str.substr(i);
127          strlen = str.size();
128          for (i = strlen - 1; i != 0; i--) {
129              if (str[i] >= '\0' && str[i] <= ' ') {
130                  str.pop_back();
131                  continue;
132              }
133                  break;
134          }
135      }
136  
DeleteTabOrNewline(std::string & str1)137      void DeleteTabOrNewline(std::string& str1)
138      {
139          for (auto item = str1.begin(); item != str1.end();) {
140              if (IsASCIITabOrNewline(*item)) {
141                  item = str1.erase(item);
142              } else {
143                  ++item;
144              }
145          }
146      }
147  
IsSpecial(std::string scheme)148      bool IsSpecial(std::string scheme)
149      {
150          auto temp = g_head.count(scheme);
151          if (temp > 0) {
152              return true;
153          }
154          return false;
155      }
156  
AnalysisScheme(std::string & input,std::string & scheme,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)157      bool AnalysisScheme(std::string& input, std::string& scheme,
158          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
159      {
160          if (!isalpha(input[0])) {
161              flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
162              return false;
163          } else {
164              size_t strlen = input.size();
165              for (size_t i = 0; i < strlen - 1; ++i) {
166                  if ((isalnum(input[i]) || input[i] == '+' || input[i] == '-' || input[i] == '.') &&
167                      isupper(input[i])) {
168                          input[i] = static_cast<size_t>(tolower(input[i]));
169                  }
170                  if (!isalnum(input[i]) && input[i] != '+' && input[i] != '-' && input[i] != '.') {
171                      flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
172                      // 0:Bit 0 Set to true,The URL analysis failed
173                      return false;
174                  }
175              }
176              scheme = input;
177              if (IsSpecial(scheme)) {
178                  flags.set(static_cast<size_t>(BitsetStatusFlag::BIT1));
179              }
180              return true;
181          }
182      }
183  
AnalysisFragment(const std::string & input,std::string & fragment,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)184      void AnalysisFragment(const std::string& input, std::string& fragment,
185          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
186      {
187          fragment = input;
188          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT8));
189      }
190  
AnalysisQuery(const std::string & input,std::string & query,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)191      void AnalysisQuery(const std::string& input, std::string& query,
192          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
193      {
194          query = input;
195          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT7));
196      }
AnalysisUsernameAndPasswd(std::string & input,std::string & username,std::string & password,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)197      void AnalysisUsernameAndPasswd(std::string& input, std::string& username, std::string& password,
198          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
199      {
200          int pos = static_cast<int>(input.size()) - 1;
201          for (; pos >= 0; pos--) {
202              if (input[pos] == '@') {
203                  break;
204              }
205          }
206          std::string userAndPasswd = input.substr(0, pos);
207          input = input.substr(pos + 1);
208          if (userAndPasswd.empty()) {
209              return;
210          }
211          if (userAndPasswd.find('@') != std::string::npos) {
212              while (true) {
213                  size_t pos = 0;
214                  if ((pos = userAndPasswd.find('@')) != std::string::npos) {
215                      userAndPasswd = userAndPasswd.replace(pos, 1, "%40");
216                  } else {
217                      break;
218                  }
219              }
220          }
221  
222          if (userAndPasswd.find(':') != std::string::npos) {
223              size_t position = userAndPasswd.find(':');
224              std::string user = userAndPasswd.substr(0, position);
225              std::string keyWord = userAndPasswd.substr(position + 1);
226              if (!user.empty()) {
227                  username = user;
228                  flags.set(static_cast<size_t>(BitsetStatusFlag::BIT2));
229              }
230              if (!keyWord.empty()) {
231                  password = keyWord;
232                  flags.set(static_cast<size_t>(BitsetStatusFlag::BIT3));
233              }
234          } else {
235              username = userAndPasswd;
236              flags.set(static_cast<size_t>(BitsetStatusFlag::BIT2));
237          }
238      }
239  
AnalysisPath(std::string & input,std::vector<std::string> & path,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags,bool isSpecial)240      void AnalysisPath(std::string& input, std::vector<std::string>& path,
241          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags, bool isSpecial)
242      {
243          std::vector<std::string> temp;
244          size_t pos = 0;
245          while (((pos = input.find('/')) != std::string::npos) ||
246              ((pos = input.find('\\')) != std::string::npos && isSpecial)) {
247              temp.push_back(input.substr(0, pos));
248              input = input.substr(pos + 1);
249          }
250          temp.push_back(input);
251          size_t length = temp.size();
252          for (size_t it = 0; it < length; ++it) {
253              auto result = find(g_doubleSegment.begin(), g_doubleSegment.end(), temp[it]);
254              if (result != g_doubleSegment.end()) {
255                  if (path.empty() && it == length - 1) {
256                      path.emplace_back("");
257                      flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
258                  }
259                  if (path.empty()) {
260                      continue;
261                  }
262                  path.pop_back();
263                  if (it == length - 1) {
264                      path.emplace_back("");
265                      flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
266                  }
267                  continue;
268              }
269              result = find(g_singlesegment.begin(), g_singlesegment.end(), temp[it]);
270              if (result != g_singlesegment.end() && it == length - 1) {
271                  path.emplace_back("");
272                  flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
273                  continue;
274              }
275              if (result == g_singlesegment.end()) {
276                  path.push_back(temp[it]);
277                  flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
278              }
279          }
280      }
281  
AnalysisPort(std::string input,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)282      void AnalysisPort(std::string input, UrlData& urlinfo,
283          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
284      {
285          for (auto i : input) {
286              if (!isdigit(i)) {
287                  flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
288                  return;
289              }
290          }
291          int it = stoi(input);
292          const int maxPort = 65535; // 65535:Maximum port number
293          if (it > maxPort) {
294              flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
295              return;
296          }
297          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT5));
298          for (auto i : g_head) {
299              if (i.first == urlinfo.scheme && i.second == it) {
300                  urlinfo.port = -1;
301                  flags.set(static_cast<size_t>(BitsetStatusFlag::BIT5), 0);
302                  return;
303              }
304          }
305          urlinfo.port = it;
306      }
307  
AnalysisOpaqueHost(std::string input,std::string & host,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)308      void AnalysisOpaqueHost(std::string input, std::string& host,
309          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
310      {
311          size_t strlen = input.size();
312          for (size_t i = 0; i < strlen; ++i) {
313              char ch = input[i];
314              auto result = find(g_specialcharacter.begin(), g_specialcharacter.end(), ch);
315              if (ch != '%' && (result != g_specialcharacter.end())) {
316                  flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
317                  return;
318              }
319          }
320          host = input;
321          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
322      }
323  
DealIpv4(std::string str)324      std::string DealIpv4(std::string str)
325      {
326          std::vector<std::string> temp;
327          size_t pos = str.rfind(":");
328          size_t index = pos;
329          size_t left = pos + 1;
330          char hexVal[3] = { 0 };
331          std::string val = "";
332          while ((pos = str.find(".", left)) != std::string::npos) {
333              val = str.substr(left, pos - left);
334              if (sprintf_s(hexVal, sizeof(hexVal), "%02x", stoi(val)) < 0) {
335                  HILOG_ERROR("sprintf_s is falie");
336              }
337  
338              temp.push_back(hexVal);
339              left = pos + 1;
340              }
341          val = str.substr(left);
342          if (sprintf_s(hexVal, sizeof(hexVal), "%02x", stoi(val)) < 0) {
343              HILOG_ERROR("sprintf_s is falie");
344          }
345          temp.push_back(hexVal);
346          std::string res = str.substr(0, index);
347          res = res + ":" + temp[0] + temp[1] + ":" + temp[2] + temp[3]; // 2:subscript 3:subscript
348          return res;
349      }
350  
FormatIpv6(std::string & str)351      void FormatIpv6(std::string& str)
352      {
353          size_t pos = str.find("::");
354          size_t index = pos;
355          if (pos != std::string::npos) {
356              size_t left = 0;
357              int count = 0;
358              while ((pos = str.find(":", left)) != std::string::npos) {
359                  count++;
360                  left = pos + 1;
361              }
362              int size = 7 - (count - 2); // 7:point number 2:Continuous colon number
363              std::string temp = "";
364              for (int i = 0; i < size - 1; ++i) {
365                  temp += ":0";
366              }
367              temp += ":";
368              str.replace(index, 2, temp); // 2:jump"::"
369              if (index == 0) {
370                  str = "0" + str;
371              }
372          }
373      }
374  
RemoveLeadingZeros(std::vector<std::string> & ipv6)375      void RemoveLeadingZeros(std::vector<std::string> &ipv6)
376      {
377          size_t len = ipv6.size();
378          for (size_t i = 0; i < len; ++i) {
379              size_t strLen = ipv6[i].size();
380              size_t count = 0;
381              size_t j = 0;
382              for (j = 0; j < strLen; ++j) {
383                  if (ipv6[i][j] != '0') {
384                      break;
385          }
386                      count++;
387                  }
388              if (count == strLen) {
389                  ipv6[i] = "0";
390              } else if (count != 0) {
391                  ipv6[i] = ipv6[i].substr(j);
392                  }
393              }
394          }
395  
ZeroCompression(std::vector<std::string> & ipv6)396      std::string ZeroCompression(std::vector<std::string> &ipv6)
397      {
398          size_t maxIndex = 0;
399          size_t maxSize = 0;
400          size_t index = 0;
401          size_t size = 0;
402          bool isNeedZeroCompression = false;
403          size_t len = ipv6.size();
404          for (size_t i = 0; i < len; ++i) {
405              index = i;
406              size = 0;
407              while (i < len && ipv6[i] == "0") {
408                  isNeedZeroCompression = true;
409                  size++;
410                  i++;
411                  }
412              if (maxSize < size) {
413                  maxSize = size;
414                  maxIndex = index;
415              }
416              }
417          std::string res = "";
418          size_t ipv6Len = ipv6.size();
419          for (size_t i = 0; i < ipv6Len; ++i) {
420              if (isNeedZeroCompression && i == maxIndex) {
421                  if (maxIndex == 0) {
422                      res += "::";
423          } else {
424                      res += ":";
425          }
426                  i += maxSize - 1;
427                  continue;
428      }
429              res += ipv6[i];
430              i != (ipv6Len - 1) ? res += ":" : "";
431          }
432          return res;
433      }
434  
ToLower(std::string & str)435      void ToLower(std::string &str)
436      {
437          size_t strLen = str.size();
438          for (size_t i = 0; i < strLen; ++i) {
439              if (isupper(str[i])) {
440                  str[i] = static_cast<size_t>(tolower(str[i]));
441          }
442      }
443      }
444  
Compress(std::string str)445      std::string Compress(std::string str)
446      {
447          std::vector<std::string> temp;
448          size_t pos = 0;
449          size_t left = 0;
450          while ((pos = str.find(":", left)) != std::string::npos) {
451              temp.push_back(str.substr(left, pos - left));
452              left = pos + 1;
453          }
454          temp.push_back(str.substr(left));
455          RemoveLeadingZeros(temp);
456          std::string res = ZeroCompression(temp);
457          ToLower(res);
458          return res;
459          }
460  
IPv6Host(std::string & input,std::string & host,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)461      void IPv6Host(std::string& input, std::string& host,
462          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
463      {
464          std::regex ipv6("(::|(:((:[0-9A-Fa-f]{1,4}){1,7}))|(([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|"
465                          "(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|:))|(([0-9A-Fa-f]{1,4}:){2}"
466                          "(((:[0-9A-Fa-f]{1,4}){1,5})|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})"
467                          "|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|:))|(([0-9A-Fa-f]{1,4}:){5}"
468                          "(((:[0-9A-Fa-f]{1,4}){1,2})|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|:))|"
469                          "(((:(:[0-9A-Fa-f]{1,4}){0,5}:)|(([0-9A-Fa-f]{1,4}:){1}(:[0-9A-Fa-f]{1,4}){0,4}:)"
470                          "|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}:)|(([0-9A-Fa-f]{1,4}:){3}"
471                          "(:[0-9A-Fa-f]{1,4}){0,2}:)|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4})?:)|"
472                          "(([0-9A-Fa-f]{1,4}:){5}:)|(([0-9A-Fa-f]{1,4}:){6}))((25[0-5]|2[0-4]\\d|1\\d{2}|"
473                          "[1-9]\\d|\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)))(%[a-zA-Z0-9._]+)?");
474          if (!std::regex_match(input, ipv6)) {
475                  flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
476                  return;
477              }
478          size_t pos = 0;
479          pos = input.find('.');
480          if (pos != std::string::npos) {
481              input = DealIpv4(input);
482          }
483          FormatIpv6(input);
484          input = Compress(input);
485          host = "[" + input + "]";
486          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
487          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT10));
488      }
489  
IsRadix(std::string num,std::string radix)490      bool IsRadix(std::string num, std::string radix)
491      {
492          size_t len = num.size();
493          for (size_t i = 0; i < len; ++i) {
494              if (radix.find(num[i]) == std::string::npos) {
495                  return false;
496                  }
497              }
498          return true;
499          }
500  
IsNumber(std::string num,int & radix)501      bool IsNumber(std::string num, int &radix)
502      {
503          size_t len = num.size();
504          if (len > 2 && num[0] == '0' && (num[1] == 'x' || num[1] == 'X')) { // 2:hex head length
505              radix = 16; // 16:hex
506              return IsRadix(num.substr(2), "0123456789abcdefABCDEF"); // 2:jump 0x
507          } else if (len > 1 && num[0] == '0') {
508              radix = 8; // 8:octal
509              return IsRadix(num.substr(1), "01234567");
510          } else if (IsRadix(num, "0123456789")) {
511              radix = 10; // 10:decimal
512              return true;
513      }
514  
515          return false;
516          }
517  
BinaryConversion(std::string num,int radix)518      std::string BinaryConversion(std::string num, int radix)
519      {
520          int val = 0;
521          if (radix == 16) { // 16:hex
522              if (sscanf_s(num.c_str(), "%x", &val) == EOK) {
523                  HILOG_ERROR("sscanf_s is falie");
524          }
525              return std::to_string(val);
526          } else if (radix == 8) { // 8:octal
527              if (sscanf_s(num.c_str(), "%o", &val) == EOK) {
528                  HILOG_ERROR("sscanf_s is falie");
529              }
530              return std::to_string(val);
531          } else {
532              return num;
533          }
534      }
535  
RemovalIpv4(std::vector<std::string> & temp,std::string str)536      bool RemovalIpv4(std::vector<std::string> &temp, std::string str)
537      {
538          size_t pos = 0;
539          size_t left = 0;
540          while ((pos = str.find(".", left)) != std::string::npos) {
541              temp.push_back(str.substr(left, pos - left));
542              left = pos + 1;
543              }
544          temp.push_back(str.substr(left));
545          size_t tmpLen = temp.size();
546          std::vector<std::string> res;
547          for (size_t i = 0; i < tmpLen; ++i) {
548              int radix = 0;
549              if (IsNumber(temp[i], radix)) {
550                  res.push_back(BinaryConversion(temp[i], radix));
551              } else {
552                  return false;
553              }
554          }
555          temp = res;
556          return true;
557      }
558  
IsFormatIpv4(std::vector<std::string> nums)559      int IsFormatIpv4(std::vector<std::string> nums)
560      {
561          size_t len = nums.size();
562          for (size_t i = 0; i < len; ++i) {
563              if (stoi(nums[i]) > 255) { // 255:ipv4 max value
564                  return i;
565              }
566          }
567          return -1;
568      }
569  
SplitNum(std::string num,size_t & number)570      std::string SplitNum(std::string num, size_t &number)
571      {
572          int val = stoi(num);
573          std::vector<std::string> nums;
574          std::string res = "";
575          while (val > 0) {
576              int num = val % 256; // 256:ipv4 max value
577              nums.push_back(std::to_string(num));
578              val /= 256; // 256:ipv4 max value
579              }
580          for (int i = static_cast<int>(nums.size()) - 1; i >= 0; --i) {
581              res += nums[i] + ".";
582          }
583          number = nums.size();
584          return res.substr(0, res.size() - 1);
585      }
586  
FormatIpv4(std::vector<std::string> nums,std::string & host,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)587      void FormatIpv4(std::vector<std::string> nums, std::string& host,
588          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> &flags)
589      {
590          size_t len = nums.size();
591          int index = IsFormatIpv4(nums);
592          std::string res = "";
593          if (index == -1) {
594              for (size_t i = 0; i < len - 1; ++i) {
595                  res += nums[i] + ".";
596                  }
597              for (size_t i = 0; i < 4 - len; ++i) { // 4:ipv4 max size
598                  res += "0.";
599              }
600              res += nums[len - 1];
601              host = res;
602              flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
603          } else if (index == static_cast<int>(len - 1)) {
604              for (size_t i = 0; i < len - 1; ++i) {
605                  res += nums[i] + ".";
606          }
607              size_t number = 0;
608              std::string temp = SplitNum(nums[index], number);
609              if (number + (len - 1) > 4) { // 4:ipv4 max size
610                  flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
611                  return;
612          }
613              for (size_t i = 0; i < 4 - (len - 1 + number); ++i) { // 4:ipv4 max size
614                  temp = "0." + temp;
615          }
616              host = res + temp;
617              flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
618          } else {
619              flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
620              return;
621              }
622              }
623  
AnalyseIPv4(const std::string & input,std::string & host,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)624      void AnalyseIPv4(const std::string& input, std::string& host,
625          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
626      {
627          bool isipv4 = false;
628          std::vector<std::string> temp;
629          isipv4 = RemovalIpv4(temp, input);
630          size_t tempLen = temp.size();
631          std::string res = "";
632          for (size_t i = 0; i < tempLen; ++i) {
633              res += temp[i];
634              if (i != tempLen - 1) {
635                  res += ".";
636              }
637          }
638          if (isipv4) {
639              if (tempLen > 4) { // 4:ipv4 max size
640                  ToLower(res);
641                  host = res;
642                  flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
643              } else if (tempLen == 4) { // 4:ipv4 max size
644                  if (IsFormatIpv4(temp) == -1) {
645                      host = res;
646                      flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
647              } else {
648                      flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
649                  }
650              } else {
651                  FormatIpv4(temp, host, flags);
652              }
653          } else {
654              ToLower(res);
655              host = res;
656          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
657          }
658      }
AnalysisHost(std::string & input,std::string & host,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags,bool special)659      void AnalysisHost(std::string& input, std::string& host,
660          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags, bool special)
661      {
662          if (input.empty()) {
663              flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
664              return;
665          }
666          if (input[0] == '[') {
667              if ((input[input.length() - 1]) == ']') {
668                  size_t  b = input.length();
669                  input = input.substr(1, b - 2); // 2:Truncating Strings
670                  IPv6Host(input, host, flags);
671                  return;
672              } else {
673                  flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
674                  return;
675              }
676          }
677          if (!special) {
678              AnalysisOpaqueHost(input, host, flags);
679              return;
680          }
681          std::string decodeInput = DecodePercent(input.c_str(), input.length());
682          size_t strlen = decodeInput.size();
683          for (size_t pos = 0; pos < strlen; ++pos) {
684              char ch = decodeInput[pos];
685              auto result = find(g_specialcharacter.begin(), g_specialcharacter.end(), ch);
686              if (result != g_specialcharacter.end()) {
687                  flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
688                  return;
689              }
690          }
691          AnalyseIPv4(decodeInput, host, flags);
692      }
ISFileNohost(const std::string & input)693      bool ISFileNohost(const std::string& input)
694      {
695          if ((isalpha(input[0]) && (input[1] == ':' || input[1] == '|'))) {
696              return true;
697          }
698          return false;
699      }
AnalysisFilePath(std::string & input,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)700      void AnalysisFilePath(std::string& input, UrlData& urlinfo,
701          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
702      {
703          std::vector<std::string> temp;
704          size_t pos = 0;
705          while (((pos = input.find('/')) != std::string::npos) || ((pos = input.find('\\')) != std::string::npos)) {
706              temp.push_back(input.substr(0, pos));
707              input = input.substr(pos + 1);
708          }
709          temp.push_back(input);
710          size_t length = temp.size();
711          for (size_t i = 0; i < length; ++i) {
712              auto a = find(g_doubleSegment.begin(), g_doubleSegment.end(), temp[i]);
713              if (a != g_doubleSegment.end()) {
714                  if ((urlinfo.path.size() == 1) && ISFileNohost(urlinfo.path[0]) &&
715                      urlinfo.path[0].size() == 2) { // 2:The interception length is 2
716                      urlinfo.path[0][1] = ':';
717                  } else if (!urlinfo.path.empty()) {
718                      urlinfo.path.pop_back();
719                  }
720                  if (i == temp.size() - 1) {
721                      urlinfo.path.push_back("");
722                  }
723                  continue;
724              }
725              a = find(g_singlesegment.begin(), g_singlesegment.end(), temp[i]);
726              if (a != g_singlesegment.end()) {
727                  if (i == temp.size() - 1) {
728                      urlinfo.path.push_back("");
729                  }
730                  continue;
731              }
732              urlinfo.path.push_back(temp[i]);
733              flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
734          }
735          std::string it = urlinfo.path[0];
736          if (isalpha(it[0]) && (it[1] == ':' || it[1] == '|')) {
737              if (it.size() == 2) { // 2:The length is 2
738                  it[1] = ':';
739                  flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4), 0);
740                  urlinfo.host.clear();
741              }
742          }
743      }
744  
AnalysisSpecialFile(std::string & temp,size_t pos,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)745      void AnalysisSpecialFile(std::string& temp, size_t pos, UrlData& urlinfo,
746          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
747      {
748          std::string strHost = temp.substr(0, pos);
749          std::string strPath = temp.substr(pos + 1);
750          bool special = true;
751          if (!ISFileNohost(strHost)) {
752              AnalysisHost(strHost, urlinfo.host, flags, special);
753          } else if (!ISFileNohost(strHost) && flags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
754              return;
755          }
756          if (!ISFileNohost(strHost)) {
757              AnalysisFilePath(strPath, urlinfo, flags);
758          } else {
759              AnalysisFilePath(temp, urlinfo, flags);
760          }
761      }
AnalysisFile(std::string & input,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)762      void AnalysisFile(std::string& input, UrlData& urlinfo,
763          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
764      {
765          bool special = true;
766          if ((input[0] == '/' || input[0] == '\\') && (input[1] == '/' || input[1] == '\\')) {
767              std::string temp = input.substr(2); // 2:Intercept from 2 subscripts
768              size_t pos = 0;
769              if ((((pos = temp.find('/')) != std::string::npos) ||
770                  ((pos = temp.find('\\')) != std::string::npos)) && pos == 0) {
771                  temp = temp.substr(1);
772                  AnalysisFilePath(temp, urlinfo, flags);
773              } else if ((((pos = temp.find('/')) != std::string::npos) ||
774                  ((pos = temp.find('\\')) != std::string::npos)) && pos != 0) {
775                  AnalysisSpecialFile(temp, pos, urlinfo, flags);
776              } else {
777                  if (!temp.empty() && flags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
778                      AnalysisHost(temp, urlinfo.host, flags, special);
779                  } else if (!temp.empty() && !flags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
780                      AnalysisHost(temp, urlinfo.host, flags, special);
781                      return;
782                  }
783              }
784          } else {
785              if (input[0] == '/' || input[0] == '\\') {
786                  input = input.substr(1);
787              }
788              AnalysisFilePath(input, urlinfo, flags);
789          }
790      }
791  
AnalysisFilescheme(std::string & input,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)792      void AnalysisFilescheme(std::string& input, UrlData& urlinfo,
793          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
794      {
795          std::string strPath = urlinfo.scheme + input;
796          urlinfo.scheme = "file:";
797          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT1));
798          AnalysisFilePath(strPath, urlinfo, flags);
799      }
800  
AnalyInfoPath(std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags,UrlData & urlinfo,std::string & input)801      void AnalyInfoPath(std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> &flags,
802          UrlData& urlinfo, std::string& input)
803      {
804          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT9));
805          if (urlinfo.path.empty()) {
806              urlinfo.path.emplace_back("");
807          }
808          urlinfo.path[0] = input;
809          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
810          return;
811      }
812  
AnalyHostPath(std::string & strHost,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags,UrlData & urlinfo)813      void AnalyHostPath(std::string &strHost, std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags,
814          UrlData& urlinfo)
815      {
816          size_t pos = 0;
817          if (strHost[strHost.size() - 1] != ']' && (pos = strHost.find_last_of(':')) != std::string::npos) {
818              std::string port = strHost.substr(pos + 1);
819              strHost = strHost.substr(0, pos);
820              AnalysisPort(port, urlinfo, flags);
821              if (flags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
822                  return;
823              }
824          }
825      }
AnalyStrHost(std::string & strHost,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)826      void AnalyStrHost(std::string &strHost, UrlData& urlinfo,
827          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> &flags)
828      {
829          if (strHost.find('@') != std::string::npos) {
830              AnalysisUsernameAndPasswd(strHost, urlinfo.username, urlinfo.password, flags);
831          }
832          if (strHost.empty()) {
833              flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
834              return;
835          }
836      }
837  
AnalysisNoDefaultProtocol(std::string & input,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)838      void AnalysisNoDefaultProtocol(std::string& input, UrlData& urlinfo,
839          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
840      {
841          if (urlinfo.scheme.size() == 2) { // 2:The length is 2
842              AnalysisFilescheme(input, urlinfo, flags);
843              return;
844          }
845          if (input[0] == '/' && input[1] == '/') {
846              std::string hostandpath = input.substr(2); // 2:Intercept from 2 subscripts
847              if (hostandpath.empty()) {
848                  return;
849              }
850              size_t i = 0;
851              bool special = false;
852              std::string strHost = "";
853              if (hostandpath.find('/') != std::string::npos) {
854                  i = hostandpath.find('/');
855                  strHost = hostandpath.substr(0, i);
856                  std::string strPath = hostandpath.substr(i + 1);
857                  if (strHost.find('@') != std::string::npos) {
858                      AnalysisUsernameAndPasswd(strHost, urlinfo.username, urlinfo.password, flags);
859                  }
860                  if (strHost.empty()) {
861                      flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
862                      return;
863                  }
864                  size_t pos = 0;
865                  if (strHost[strHost.size() - 1] != ']' && (pos = strHost.find_last_of(':')) != std::string::npos) {
866                      std::string port = strHost.substr(pos + 1);
867                      strHost = strHost.substr(0, pos);
868                      AnalysisPort(port, urlinfo, flags);
869                  }
870                  if (strHost[strHost.size() - 1] != ']' && (pos = strHost.find_last_of(':')) != std::string::npos &&
871                      flags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
872                      return;
873                  }
874                  AnalysisHost(strHost, urlinfo.host, flags, special);
875                  AnalysisPath(strPath, urlinfo.path, flags, special);
876              } else {
877                  strHost = hostandpath;
878                  AnalyStrHost(strHost, urlinfo, flags);
879                  AnalyHostPath(strHost, flags, urlinfo);
880                  AnalysisHost(strHost, urlinfo.host, flags, special);
881              }
882          } else if (input[1] == '/') {
883              std::string strOfPath = input.substr(1);
884              AnalysisPath(strOfPath, urlinfo.path, flags, false);
885          } else {
886              AnalyInfoPath(flags, urlinfo, input);
887          }
888      }
889  
AnalysisOnlyHost(std::string & input,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags,size_t pos)890      void AnalysisOnlyHost(std::string& input, UrlData& urlinfo,
891          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags, size_t pos)
892      {
893          std::string strHost = input;
894          if (strHost.find('@') != std::string::npos) {
895              AnalysisUsernameAndPasswd(strHost, urlinfo.username, urlinfo.password, flags);
896          }
897          if (strHost.empty()) {
898              flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
899              return;
900          }
901          if (strHost[strHost.size() - 1] != ']') {
902              if ((pos = strHost.find_last_of(':')) != std::string::npos) {
903                  std::string port = strHost.substr(pos + 1);
904                  strHost = strHost.substr(0, pos);
905                  AnalysisPort(port, urlinfo, flags);
906              }
907              if ((pos = strHost.find_last_of(':')) != std::string::npos &&
908                  flags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
909                  return;
910              }
911          }
912          AnalysisHost(strHost, urlinfo.host, flags, true);
913      }
JudgePos(size_t & pos,size_t & length,std::string & input)914      void JudgePos(size_t &pos, size_t &length, std::string& input)
915      {
916          for (pos = 0; pos < length; pos++) {
917              if (input[pos] == '/' || input[pos] == '\\') {
918                  break;
919              }
920          }
921      }
AnalysisHostAndPath(std::string & input,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)922      void AnalysisHostAndPath(std::string& input, UrlData& urlinfo,
923          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
924      {
925          if (flags.test(static_cast<size_t>(BitsetStatusFlag::BIT1))) {
926              size_t pos = 0;
927              bool special = true;
928              size_t inputLen = input.size();
929              while (pos < inputLen) {
930                  if (input[pos] == '/' || input[pos] == '\\') {
931                      pos++;
932                      continue;
933                  }
934                      break;
935              }
936              input = input.substr(pos);
937              if (input.size() == 0) {
938                  flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
939                  return;
940              } else if (input.size() != 0 && (input.find('/') != std::string::npos ||
941                  input.find('\\') != std::string::npos)) {
942                  size_t length = input.size();
943                  JudgePos(pos, length, input);
944                  std::string strHost = input.substr(0, pos);
945                  std::string strPath = input.substr(pos + 1);
946                  if (strHost.find('@') != std::string::npos) {
947                      AnalysisUsernameAndPasswd(strHost, urlinfo.username, urlinfo.password, flags);
948                  }
949                  if (strHost.empty()) {
950                      flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
951                      return;
952                  }
953                  if (strHost[strHost.size() - 1] != ']' && (pos = strHost.find_last_of(':')) != std::string::npos) {
954                      std::string port = strHost.substr(pos + 1);
955                      strHost = strHost.substr(0, pos);
956                      AnalysisPort(port, urlinfo, flags);
957                  }
958                  if (strHost[strHost.size() - 1] != ']' && (pos = strHost.find_last_of(':')) != std::string::npos &&
959                      flags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
960                      return;
961                  }
962                  AnalysisHost(strHost, urlinfo.host, flags, special);
963                  AnalysisPath(strPath, urlinfo.path, flags, special);
964              } else if (input.size() != 0 && input.find('/') == std::string::npos &&
965                  input.find('\\') == std::string::npos) {
966                  AnalysisOnlyHost(input, urlinfo, flags, pos);
967              }
968          } else {
969              AnalysisNoDefaultProtocol(input, urlinfo, flags);
970          }
971      }
972  
AnalysisInput(std::string & input,UrlData & urlData,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)973      void AnalysisInput(std::string& input, UrlData& urlData,
974          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
975      {
976          size_t pos = 0;
977          if (input.find('#') != std::string::npos) {
978              pos = input.find('#');
979              std::string fragment = input.substr(pos);
980              AnalysisFragment(fragment, urlData.fragment, flags);
981              input = input.substr(0, pos);
982          }
983          if (input.find('?') != std::string::npos) {
984              pos = input.find('?');
985              std::string query = input.substr(pos);
986              AnalysisQuery(query, urlData.query, flags);
987              input = input.substr(0, pos);
988          }
989          bool special = (flags.test(static_cast<size_t>(BitsetStatusFlag::BIT1)) ? true : false);
990          AnalysisPath(input, urlData.path, flags, special);
991      }
992  
BaseInfoToUrl(const UrlData & baseInfo,const std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> baseflags,UrlData & urlData,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags,bool inputIsEmpty)993      void BaseInfoToUrl(const UrlData& baseInfo,
994          const std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> baseflags, UrlData& urlData,
995          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags, bool inputIsEmpty)
996      {
997          urlData.scheme = baseInfo.scheme;
998          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT1),
999              baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT1)));
1000          urlData.host = baseInfo.host;
1001          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
1002          urlData.username = baseInfo.username;
1003          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT2),
1004              baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT2)));
1005          urlData.password = baseInfo.password;
1006          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT3),
1007              baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT3)));
1008          urlData.port = baseInfo.port;
1009          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT5),
1010              baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT5)));
1011          if (inputIsEmpty) {
1012              urlData.path = baseInfo.path;
1013              flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6),
1014                  baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT6)));
1015              urlData.query = baseInfo.query;
1016              flags.set(static_cast<size_t>(BitsetStatusFlag::BIT7),
1017                  baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT7)));
1018              urlData.fragment = baseInfo.fragment;
1019              flags.set(static_cast<size_t>(BitsetStatusFlag::BIT8),
1020                  baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT8)));
1021          }
1022          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT9),
1023              baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT9)));
1024          flags.set(static_cast<size_t>(BitsetStatusFlag::BIT10),
1025              baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT10)));
1026      }
1027  
ShorteningPath(UrlData & baseData,bool isFile)1028      void ShorteningPath(UrlData& baseData, bool isFile)
1029      {
1030          if (baseData.path.empty()) {
1031              return;
1032          }
1033          if ((baseData.path.size() == 1) && isFile &&
1034              isalpha(baseData.path[0][0]) && (baseData.path[0][1] == ':')) {
1035              return;
1036          }
1037          baseData.path.pop_back();
1038      }
InitOnlyInput(std::string & input,UrlData & urlData,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)1039      void InitOnlyInput(std::string& input, UrlData& urlData,
1040          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
1041      {
1042          if (input.empty()) {
1043              flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1044              return;
1045          }
1046          if (input.find(':') != std::string::npos) {
1047              size_t pos = input.find(':');
1048              pos++;
1049              std::string scheme = input.substr(0, pos);
1050              if (!AnalysisScheme(scheme, urlData.scheme, flags)) {
1051                  return;
1052              }
1053              if (input.find('#') != std::string::npos) {
1054                  size_t pos = input.find('#');
1055                  std::string fragment = input.substr(pos);
1056                  AnalysisFragment(fragment, urlData.fragment, flags);
1057                  input = input.substr(0, pos);
1058              }
1059              if (input.find('?') != std::string::npos) {
1060                  size_t position = input.find('?');
1061                  std::string query = input.substr(position);
1062                  AnalysisQuery(query, urlData.query, flags);
1063                  input = input.substr(0, position);
1064              }
1065              std::string str = input.substr(pos);
1066              if (urlData.scheme == "file:") {
1067                  AnalysisFile(str, urlData, flags);
1068              } else {
1069                  AnalysisHostAndPath(str, urlData, flags);
1070              }
1071          } else {
1072              flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1073              return;
1074          }
1075      }
ToolHasBase(std::string input,std::string & strInput,UrlData & urlData,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)1076      void ToolHasBase(std::string input, std::string &strInput, UrlData &urlData,
1077          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> &flags)
1078      {
1079          if (!input.empty() && input[0] == '/') {
1080              strInput = input.substr(1);
1081              AnalysisInput(strInput, urlData, flags);
1082          } else if (!input.empty() && input[0] != '/') {
1083              AnalysisInput(strInput, urlData, flags);
1084          }
1085      }
1086  
URL(const std::string & input)1087      URL::URL(const std::string& input)
1088      {
1089          std::string str = input;
1090          DeleteC0OrSpace(str);
1091          DeleteTabOrNewline(str);
1092          InitOnlyInput(str, urlData_, flags_);
1093      }
1094  
DelCont(std::string strBase,std::string & strInput,UrlData & baseInfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & baseflags)1095      void DelCont(std::string strBase, std::string &strInput, UrlData &baseInfo,
1096          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> &baseflags)
1097      {
1098          DeleteC0OrSpace(strBase);
1099          DeleteTabOrNewline(strBase);
1100          DeleteC0OrSpace(strInput);
1101          DeleteTabOrNewline(strInput);
1102          InitOnlyInput(strBase, baseInfo, baseflags);
1103      }
1104  
URL(const std::string & input,const std::string & base)1105      URL::URL(const std::string& input, const std::string& base)
1106      {
1107          UrlData baseInfo;
1108          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> baseflags;
1109          std::string strBase = base;
1110          std::string strInput = input;
1111          if (strBase.empty()) {
1112              baseflags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1113          }
1114          DelCont(strBase, strInput, baseInfo, baseflags);
1115          if (baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1116              flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1117              return;
1118          } else if (!baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1119              InitOnlyInput(strInput, urlData_, flags_);
1120              if (!flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1121                  return;
1122              }
1123              if ((input[0] == '/') && (input[1] == '/' || (input[1] == '\\' &&
1124                  baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT1))))) {
1125                  std::string newInput = baseInfo.scheme + input;
1126                  flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0), 0);
1127                  InitOnlyInput(newInput, urlData_, flags_);
1128                  return;
1129              }
1130              if (!baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1131                  flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0), 0);
1132                  BaseInfoToUrl(baseInfo, baseflags, urlData_, flags_, input.empty());
1133                  ToolHasBase(input, strInput, urlData_, flags_);
1134                  if (!input.empty() && input[0] != '/' && urlData_.path.empty()) {
1135                      urlData_.path = baseInfo.path;
1136                      flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6),
1137                          baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT6)));
1138                  }
1139                  if (!input.empty() && input[0] != '/' && !urlData_.path.empty()) {
1140                      bool isFile = ((urlData_.scheme == "file:") ? true : false);
1141                      ShorteningPath(baseInfo, isFile);
1142                      baseInfo.path.insert(baseInfo.path.end(), urlData_.path.begin(), urlData_.path.end());
1143                      urlData_.path = baseInfo.path;
1144                      flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
1145                  }
1146              } else if (baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1147                  flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1148                  return;
1149              }
1150          }
1151      }
1152  
URL(const std::string & input,const URL & base)1153      URL::URL(const std::string& input, const URL& base)
1154      {
1155          std::string strInput = input;
1156          UrlData baseInfo = base.urlData_;
1157          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> baseflags = base.flags_;
1158          DeleteC0OrSpace(strInput);
1159          DeleteTabOrNewline(strInput);
1160          InitOnlyInput(strInput, urlData_, flags_);
1161          if (!flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1162              return;
1163          }
1164          if ((input[0] == '/') && (input[1] == '/' || (input[1] == '\\' &&
1165              baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT1))))) {
1166              std::string newInput = baseInfo.scheme + input;
1167              flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0), 0);
1168              InitOnlyInput(newInput, urlData_, flags_);
1169              return;
1170          }
1171          if (!baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1172              flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0), 0);
1173              BaseInfoToUrl(baseInfo, baseflags, urlData_, flags_, input.empty());
1174              if (!input.empty() && input[0] == '/') {
1175                  strInput = input.substr(1);
1176                  AnalysisInput(strInput, urlData_, flags_);
1177              }
1178              if (!input.empty() && input[0] != '/') {
1179                  AnalysisInput(strInput, urlData_, flags_);
1180                  if (urlData_.path.empty()) {
1181                      urlData_.path = baseInfo.path;
1182                      flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6),
1183                          baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT6)));
1184                  } else {
1185                      bool isFile = ((urlData_.scheme == "file:") ? true : false);
1186                      ShorteningPath(baseInfo, isFile);
1187                      baseInfo.path.insert(baseInfo.path.end(), urlData_.path.begin(), urlData_.path.end());
1188                      urlData_.path = baseInfo.path;
1189                      flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
1190                  }
1191              }
1192          } else if (baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1193              flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1194              return;
1195          }
1196      }
1197  
GetHostname(napi_env env) const1198      napi_value URL::GetHostname(napi_env env) const
1199      {
1200          napi_value result;
1201          std::string temp = "";
1202          if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT4))) {
1203              temp = urlData_.host;
1204          }
1205          NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1206          return result;
1207      }
1208  
GetSearch(napi_env env) const1209      napi_value URL::GetSearch(napi_env env) const
1210      {
1211          napi_value result;
1212          std::string temp = "";
1213          if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT7)) && !(urlData_.query.size() == 1)) {
1214              temp = urlData_.query;
1215          }
1216          NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1217          return result;
1218      }
1219  
GetUsername(napi_env env) const1220      napi_value URL::GetUsername(napi_env env) const
1221      {
1222          napi_value result;
1223          std::string temp = "";
1224          if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT2))) {
1225              temp = urlData_.username;
1226          }
1227          NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1228          return result;
1229      }
1230  
GetPassword(napi_env env) const1231      napi_value URL::GetPassword(napi_env env) const
1232      {
1233          napi_value result;
1234          std::string temp = "";
1235          if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT3))) {
1236              temp = urlData_.password;
1237          }
1238          NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1239          return result;
1240      }
1241  
GetFragment(napi_env env) const1242      napi_value URL::GetFragment(napi_env env) const
1243      {
1244          napi_value result;
1245          std::string temp = "";
1246          if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT8)) && !(urlData_.fragment.size() == 1)) {
1247              temp = urlData_.fragment;
1248          }
1249          NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1250          return result;
1251      }
1252  
GetScheme(napi_env env) const1253      napi_value URL::GetScheme(napi_env env) const
1254      {
1255          napi_value result;
1256          std::string temp = "";
1257          if (!urlData_.scheme.empty()) {
1258              temp = urlData_.scheme;
1259          }
1260          NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1261          return result;
1262      }
1263  
GetPath(napi_env env) const1264      napi_value URL::GetPath(napi_env env) const
1265      {
1266          napi_value result;
1267          std::string temp = "/";
1268          if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT6))) {
1269              size_t length = urlData_.path.size();
1270              for (size_t i = 0; i < length; i++) {
1271                  if (i < length - 1) {
1272                      temp += urlData_.path[i] + "/";
1273                  } else {
1274                      temp += urlData_.path[i];
1275                  }
1276              }
1277          } else {
1278              bool special = IsSpecial(urlData_.scheme);
1279              if (!special) {
1280                  temp = "";
1281              }
1282          }
1283          NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1284          return result;
1285      }
1286  
1287  
GetPort(napi_env env) const1288      napi_value URL::GetPort(napi_env env) const
1289      {
1290          napi_value result;
1291          std::string temp = "";
1292          if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT5))) {
1293              temp = std::to_string(urlData_.port);
1294          }
1295          NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1296          return result;
1297      }
1298  
GetHost(napi_env env) const1299      napi_value URL::GetHost(napi_env env) const
1300      {
1301          napi_value result;
1302          std::string temp = urlData_.host;
1303          if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT5))) {
1304              temp += ":";
1305              temp += std::to_string(urlData_.port);
1306          }
1307          NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1308          return result;
1309      }
1310  
GetOnOrOff(napi_env env) const1311      napi_value URL::GetOnOrOff(napi_env env) const
1312      {
1313          napi_value result;
1314          if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1315              bool flag = false;
1316              NAPI_CALL(env, napi_get_boolean(env, flag, &result));
1317          } else {
1318              bool flag = true;
1319              NAPI_CALL(env, napi_get_boolean(env, flag, &result));
1320          }
1321          return result;
1322      }
1323  
GetIsIpv6(napi_env env) const1324      napi_value URL::GetIsIpv6(napi_env env) const
1325      {
1326          napi_value result;
1327          if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT10))) {
1328              NAPI_CALL(env, napi_get_boolean(env, true, &result));
1329          } else {
1330              NAPI_CALL(env, napi_get_boolean(env, false, &result));
1331          }
1332          return result;
1333      }
1334  
SetHostname(const std::string & input)1335      void URL::SetHostname(const std::string& input)
1336      {
1337          if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1338              return;
1339          }
1340          std::string strHost = input;
1341          size_t length = strHost.size();
1342          for (size_t pos = 0; pos < length; pos++) {
1343              if ((strHost[pos] == ':') || (strHost[pos] == '?') || (strHost[pos] == '#') ||
1344                  (strHost[pos] == '/') || (strHost[pos] == '\\')) {
1345                  strHost = strHost.substr(0, pos);
1346                  break;
1347              }
1348          }
1349          if (strHost.size() == 0) {
1350              return;
1351          }
1352          bool special = IsSpecial(urlData_.scheme);
1353          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFlags;
1354          std::string thisHostname = "";
1355          AnalysisHost(strHost, thisHostname, thisFlags, special);
1356          if (thisFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT4))) {
1357              if ((urlData_.scheme == "file:") && (thisHostname == "localhost")) {
1358                  thisHostname = "";
1359              }
1360              urlData_.host = thisHostname;
1361              flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
1362          }
1363      }
1364  
SetHref(const std::string & input)1365      void URL::SetHref(const std::string& input)
1366      {
1367          std::string str = input;
1368          DeleteC0OrSpace(str);
1369          DeleteTabOrNewline(str);
1370          UrlData thisNewUrl;
1371          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisNewFlags;
1372          InitOnlyInput(str, thisNewUrl, thisNewFlags);
1373          if (!thisNewFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1374              urlData_ = thisNewUrl;
1375              flags_ = thisNewFlags;
1376          }
1377      }
1378  
SetPath(const std::string & input)1379      void URL::SetPath(const std::string& input)
1380      {
1381          std::string strPath = input;
1382          if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT9)) || strPath.empty()) {
1383              return;
1384          }
1385          std::string oldstr = "%3A";
1386          std::string newstr = ":";
1387          ReplaceSpecialSymbols(strPath, oldstr, newstr);
1388          bool special = IsSpecial(urlData_.scheme);
1389          if (urlData_.scheme == "file:") {
1390              UrlData thisFileDate;
1391              std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFileFlag;
1392              if ((strPath[0] == '/') || (strPath[0] == '\\' &&
1393                  flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT1)))) {
1394                  strPath = strPath.substr(1);
1395              }
1396              AnalysisFilePath(strPath, thisFileDate, thisFileFlag);
1397              if (thisFileFlag.test(static_cast<size_t>(BitsetStatusFlag::BIT6))) {
1398                  urlData_.path = thisFileDate.path;
1399                  flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
1400              }
1401          } else {
1402              std::vector<std::string> thisPath;
1403              std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFlags;
1404              if ((strPath[0] == '/') || (strPath[0] == '\\' &&
1405                  flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT1)))) {
1406                  strPath = strPath.substr(1);
1407              }
1408              AnalysisPath(strPath, thisPath, thisFlags, special);
1409              if (thisFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT6))) {
1410                  urlData_.path = thisPath;
1411                  flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
1412              }
1413          }
1414      }
1415  
SplitString(const std::string & input,std::string & strHost,std::string & port)1416      void SplitString(const std::string& input, std::string& strHost, std::string& port)
1417      {
1418          size_t strlen = input.size();
1419          for (size_t pos = 0; pos < strlen; pos++) {
1420              if ((input[pos] == ':') || (input[pos] == '?') || (input[pos] == '#') ||
1421                  (input[pos] == '/') || (input[pos] == '\\')) {
1422                  strHost = input.substr(0, pos);
1423                  if (input[pos] == ':') {
1424                      pos++;
1425                      port = input.substr(pos);
1426                  }
1427                  break;
1428              }
1429          }
1430      }
1431  
SetHost(const std::string & input)1432      void URL::SetHost(const std::string& input)
1433      {
1434          if (input.empty() || flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1435              return;
1436          }
1437          std::string strHost = input;
1438          std::string port = "";
1439          SplitString(input, strHost, port);
1440          if (strHost.size() == 0) {
1441              return;
1442          }
1443          bool special = IsSpecial(urlData_.scheme);
1444          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> hostnameflags;
1445          std::string thisHostname = "";
1446          AnalysisHost(strHost, thisHostname, hostnameflags, special);
1447          if (hostnameflags.test(static_cast<size_t>(BitsetStatusFlag::BIT4))) {
1448              if ((urlData_.scheme == "file:") && (thisHostname == "localhost")) {
1449                  thisHostname = "";
1450              }
1451              urlData_.host = thisHostname;
1452              flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
1453          } else {
1454              return;
1455          }
1456          if (port.size() > 0) {
1457              size_t strlen = port.size();
1458              for (size_t pos = 0; pos < strlen; pos++) {
1459                  if ((port[pos] == '?') || (port[pos] == '#') || (port[pos] == '/') || (port[pos] == '\\')) {
1460                      port = port.substr(0, pos);
1461                      break;
1462                  }
1463              }
1464              if (port.size() > 0) {
1465                  std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFlags;
1466                  UrlData thisport;
1467                  AnalysisPort(port, thisport, thisFlags);
1468                  if (thisFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT5))) {
1469                      flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT5));
1470                      urlData_.port = thisport.port;
1471                  }
1472              }
1473          }
1474      }
1475  
SetPort(const std::string & input)1476      void URL::SetPort(const std::string& input)
1477      {
1478          std::string port = input;
1479          size_t portlen = port.size();
1480          for (size_t pos = 0; pos < portlen; pos++) {
1481              if ((port[pos] == '?') || (port[pos] == '#') || (port[pos] == '/') || (port[pos] == '\\')) {
1482                  port = port.substr(0, pos);
1483                  break;
1484              }
1485          }
1486          if (port.size() > 0) {
1487              std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFlags;
1488              UrlData thisport;
1489              AnalysisPort(port, thisport, thisFlags);
1490              if (thisFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT5))) {
1491                  flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT5));
1492                  urlData_.port = thisport.port;
1493              }
1494          }
1495      }
1496  
SetSearch(const std::string & input)1497      void URL::SetSearch(const std::string& input)
1498      {
1499          std::string temp;
1500          if (input.size() == 0) {
1501              urlData_.query = "";
1502              flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT7), 0);
1503          } else {
1504              if (input[0] != '?') {
1505                  temp = "?";
1506                  temp += input;
1507              } else {
1508                  temp = input;
1509              }
1510              std::string oldstr = "#";
1511              std::string newstr = "%23";
1512              ReplaceSpecialSymbols(temp, oldstr, newstr);
1513              AnalysisQuery(temp, urlData_.query, flags_);
1514          }
1515      }
1516  
SetFragment(const std::string & input)1517      void URL::SetFragment(const std::string& input)
1518      {
1519          std::string temp;
1520          if (input.size() == 0) {
1521              urlData_.fragment = "";
1522              flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT8), 0);
1523          } else {
1524              if (input[0] != '#') {
1525                  temp = "#";
1526                  temp += input;
1527              } else {
1528                  temp = input;
1529              }
1530              AnalysisFragment(temp, urlData_.fragment, flags_);
1531          }
1532      }
1533  
SetScheme(const std::string & input)1534      void URL::SetScheme(const std::string& input)
1535      {
1536          std::string strInput = input;
1537          bool special = IsSpecial(urlData_.scheme);
1538          bool inputIsSpecial = IsSpecial(input);
1539          if ((special != inputIsSpecial) || ((input == "file") &&
1540              (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT2)) ||
1541              flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT3)) ||
1542              flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT5))))) {
1543              return;
1544          }
1545          std::string thisScheme = "";
1546          std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFlags;
1547          if (AnalysisScheme(strInput, thisScheme, thisFlags)) {
1548              if (thisFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT1))) {
1549                  flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT1));
1550              }
1551              urlData_.scheme = thisScheme;
1552          }
1553      }
1554  
SetUsername(const std::string & input)1555      void URL::SetUsername(const std::string& input)
1556      {
1557          if (input.size() == 0) {
1558              urlData_.username = "";
1559              flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT2), 0);
1560          } else {
1561                  std::string usname = input;
1562              size_t len = g_specialSymbols.size() - 2; // 2:Maximum position of subscript
1563              for (size_t i = 0; i <= len; i += 2) { // 2:Shift subscript right 2
1564              ReplaceSpecialSymbols(usname, g_specialSymbols[i], g_specialSymbols[i + 1]);
1565              }
1566                  urlData_.username = usname;
1567                  flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT2));
1568          }
1569      }
1570  
SetPassword(const std::string & input)1571      void URL::SetPassword(const std::string& input)
1572      {
1573          if (input.size() == 0) {
1574              urlData_.password = "";
1575              flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT3), 0);
1576          } else {
1577                  std::string keyWord = input;
1578              size_t len = g_specialSymbols.size() - 2; // 2:Maximum position of subscript
1579              for (size_t i = 0; i <= len; i += 2) { // 2:Shift subscript right 2
1580              ReplaceSpecialSymbols(keyWord, g_specialSymbols[i], g_specialSymbols[i + 1]);
1581              }
1582                  urlData_.password = keyWord;
1583                  flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT3));
1584          }
1585      }
1586  
IsEscapeRange(const char ch)1587      bool IsEscapeRange(const char ch)
1588      {
1589          if ((ch > 0 && ch < '*') || (ch > '*' && ch < '-') || (ch == '/') ||
1590              (ch > '9' && ch < 'A') || (ch > 'Z' && ch < '_') || (ch == '`') || (ch > 'z')) {
1591              return true;
1592          }
1593          return false;
1594      }
1595  
ReviseStr(std::string str,std::string * reviseChar)1596      std::string ReviseStr(std::string str, std::string *reviseChar)
1597      {
1598          icu::StringPiece sp(str.c_str());
1599          icu::UnicodeString wstr = icu::UnicodeString::fromUTF8(sp);
1600          const size_t lenStr = static_cast<size_t>(wstr.length());
1601          if (lenStr == 0) {
1602              return "";
1603          }
1604          std::string output = "";
1605          size_t numOfAscii = 128; // 128:Number of ASCII characters
1606          size_t i = 0;
1607          for (; i < lenStr; i++) {
1608              auto charaEncode = static_cast<size_t>(wstr[i]);
1609              if (charaEncode >= 0 && charaEncode < numOfAscii) {
1610                  // 2:Defines the escape range of ASCII characters
1611                  if (IsEscapeRange(charaEncode)) {
1612                      output += reviseChar[charaEncode];
1613                  } else {
1614                      output += str.substr(i, 1);
1615                  }
1616              } else if (charaEncode <= 0x000007FF) { // Convert the Unicode code into two bytes
1617                  std::string output1 = reviseChar[0x000000C0 | (charaEncode / 64)]; // 64:the first byte
1618                  std::string output2 = reviseChar[numOfAscii | (charaEncode & 0x0000003F)];
1619                  output += output1 + output2;
1620              } else if ((charaEncode >= 0x0000E000) || (charaEncode <= 0x0000D7FF)) {
1621                  std::string output1 = reviseChar[0x000000E0 | (charaEncode / 4096)]; // 4096:Acquisition method
1622                  std::string output2 = reviseChar[numOfAscii | ((charaEncode / 64) & 0x0000003F)]; // 64:second byte
1623                  std::string output3 = reviseChar[numOfAscii | (charaEncode & 0x0000003F)];
1624                  output += output1 + output2 + output3;
1625              } else {
1626                  const size_t charaEncode1 = static_cast<size_t>(str[++i]) & 1023; // 1023:Convert codes
1627                  charaEncode = 65536 + (((charaEncode & 1023) << 10) | charaEncode1); // 65536:Specific transcoding
1628                  std::string output1 = reviseChar[0x000000F0 | (charaEncode / 262144)]; // 262144:the first byte
1629                  std::string output2 = reviseChar[numOfAscii | ((charaEncode / 4096) & 0x0000003F)]; // 4096:second byte
1630                  std::string output3 = reviseChar[numOfAscii | ((charaEncode / 64) & 0x0000003F)]; // 64:third byte
1631                  std::string output4 = reviseChar[numOfAscii | (charaEncode & 0x0000003F)];
1632                  output += output1 + output2 + output3 + output4;
1633              }
1634          }
1635          return output;
1636      }
1637  
ToString(napi_env env)1638      napi_value URLSearchParams::ToString(napi_env env)
1639      {
1640          std::string output = "";
1641          std::string reviseChar[256] = {""}; // 256:Array length
1642          for (size_t i = 0; i < 256; ++i) { // 256:Array length
1643              size_t j = i;
1644              std::stringstream ioss;
1645              std::string str1 = "";
1646              ioss << std::hex << j;
1647              ioss >> str1;
1648              transform(str1.begin(), str1.end(), str1.begin(), ::toupper);
1649              if (i < 16) { // 16:Total number of 0-F
1650                  reviseChar[i] = '%' + ("0" + str1);
1651              } else {
1652                  reviseChar[i] = '%' + str1;
1653              }
1654          }
1655          reviseChar[0x20] = "+"; // 0x20:ASCII value of spaces
1656          const size_t lenStr = searchParams.size();
1657          napi_value result = nullptr;
1658          if (lenStr == 0) {
1659              napi_create_string_utf8(env, output.c_str(), output.size(), &result);
1660              return result;
1661          }
1662          std::string firstStrKey = ReviseStr(searchParams[0], reviseChar);
1663          std::string firstStrValue = ReviseStr(searchParams[1], reviseChar);
1664          output = firstStrKey + "=" + firstStrValue;
1665          if (lenStr % 2 == 0) { // 2:Divisible by 2
1666              size_t pos = 2; // 2:Initial Position
1667              for (; pos < lenStr; pos += 2) { // 2:Searching for the number and number of keys and values
1668                  std::string strKey = ReviseStr(searchParams[pos], reviseChar);
1669                  std::string strValue = ReviseStr(searchParams[pos + 1], reviseChar);
1670                  output += +"&" + strKey + "=" + strValue;
1671              }
1672          }
1673          napi_create_string_utf8(env, output.c_str(), output.size(), &result);
1674          return result;
1675      }
HandleIllegalChar(std::wstring & inputStr,std::wstring::const_iterator it)1676      void URLSearchParams::HandleIllegalChar(std::wstring& inputStr, std::wstring::const_iterator it)
1677      {
1678          std::wstring::iterator iter = inputStr.begin();
1679          advance(iter, std::distance<std::wstring::const_iterator>(iter, it));
1680          while (iter != inputStr.end()) {
1681              char16_t ch = *iter;
1682              if (!((ch & 0xF800) == 0xD800)) {
1683                  ++iter;
1684                  continue;
1685              } else if ((ch & 0x400) != 0 || iter == inputStr.end() - 1) {
1686                  *iter = 0xFFFD;
1687              } else {
1688                  char16_t dh = *(iter + 1);
1689                  if ((dh & 0xFC00) == 0xDC00) {
1690                      ++iter;
1691                  } else {
1692                      *iter = 0xFFFD;
1693                  }
1694              }
1695              ++iter;
1696          }
1697      }
ToUSVString(std::string inputStr)1698      std::string URLSearchParams::ToUSVString(std::string inputStr)
1699      {
1700          std::wstring winput(inputStr.length(), L' ');
1701          std::copy(inputStr.begin(), inputStr.end(), winput.begin());
1702          const char *expr = "(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])";
1703          size_t exprLen = strlen(expr);
1704          wchar_t *exprPtr = nullptr;
1705          size_t exprSize = mbstowcs(exprPtr, expr, 0) + 1;
1706          if (exprSize > 0) {
1707              exprPtr = new wchar_t[exprSize];
1708              mbstowcs(exprPtr, expr, exprLen);
1709          }
1710          std::wregex wexpr(exprPtr);
1711          delete[] exprPtr;
1712          std::wsmatch result;
1713          std::wstring::const_iterator iterStart = winput.begin();
1714          std::wstring::const_iterator iterEnd = winput.end();
1715          if (!regex_search(iterStart, iterEnd, result, wexpr)) {
1716              return inputStr;
1717          }
1718          HandleIllegalChar(winput, result[0].first);
1719          size_t inputLen = wcslen(winput.c_str());
1720          char *rePtr = nullptr;
1721          std::string reStr = "";
1722          size_t reSize = wcstombs(rePtr, winput.c_str(), 0) + 1;
1723          if (reSize > 0) {
1724              rePtr = new char[reSize];
1725              if (memset_s(rePtr, reSize, 0, reSize) != EOK) {
1726                  HILOG_ERROR("ToUSVString memset_s failed");
1727                  delete[] rePtr;
1728                  return reStr;
1729              } else {
1730                  wcstombs(rePtr, winput.c_str(), inputLen);
1731                  reStr = rePtr;
1732              }
1733          }
1734          delete[] rePtr;
1735          return reStr;
1736      }
Get(napi_env env,napi_value buffer)1737      napi_value URLSearchParams::Get(napi_env env, napi_value buffer)
1738      {
1739          std::string name = "";
1740          size_t nameSize = 0;
1741          if (napi_get_value_string_utf8(env, buffer, nullptr, 0, &nameSize) != napi_ok) {
1742              HILOG_ERROR("can not get buffer size");
1743              return nullptr;
1744          }
1745          name.reserve(nameSize);
1746          name.resize(nameSize);
1747          if (napi_get_value_string_utf8(env, buffer, name.data(), nameSize + 1, &nameSize) != napi_ok) {
1748              HILOG_ERROR("can not get buffer value");
1749              return nullptr;
1750          }
1751          std::string temp = name;
1752          std::string sname = ToUSVString(temp);
1753          napi_value result = nullptr;
1754          if (searchParams.size() == 0) {
1755              return result;
1756          }
1757          size_t size = searchParams.size() - 1;
1758          for (size_t i = 0; i < size; i += 2) { // 2:Searching for the number and number of keys and values
1759              if (searchParams[i] == sname) {
1760                  std::string str = searchParams[i + 1];
1761                  napi_create_string_utf8(env, searchParams[i + 1].c_str(), searchParams[i + 1].length(), &result);
1762                  return result;
1763              }
1764          }
1765          return result;
1766      }
GetAll(napi_env env,napi_value buffer)1767      napi_value URLSearchParams::GetAll(napi_env env, napi_value buffer)
1768      {
1769          std::string name = "";
1770          size_t nameSize = 0;
1771          if (napi_get_value_string_utf8(env, buffer, nullptr, 0, &nameSize) != napi_ok) {
1772              HILOG_ERROR("can not get buffer size");
1773              return nullptr;
1774          }
1775          name.reserve(nameSize);
1776          name.resize(nameSize);
1777          if (napi_get_value_string_utf8(env, buffer, name.data(), nameSize + 1, &nameSize) != napi_ok) {
1778              HILOG_ERROR("can not get buffer value");
1779              return nullptr;
1780          }
1781          std::string sname = ToUSVString(name);
1782  
1783          napi_value result = nullptr;
1784          napi_value napiStr = nullptr;
1785          NAPI_CALL(env, napi_create_array(env, &result));
1786          size_t flag = 0;
1787          if (searchParams.size() == 0) {
1788              return result;
1789          }
1790          size_t size = searchParams.size() - 1;
1791          for (size_t i = 0; i < size; i += 2) { // 2:Searching for the number and number of keys and values
1792              if (searchParams[i] == sname) {
1793                  napi_create_string_utf8(env, searchParams[i + 1].c_str(), searchParams[i + 1].length(), &napiStr);
1794                  NAPI_CALL(env, napi_set_element(env, result, flag, napiStr));
1795                  flag++;
1796              }
1797          }
1798          return result;
1799      }
Append(napi_env env,napi_value buffer,napi_value temp)1800      void URLSearchParams::Append(napi_env env, napi_value buffer, napi_value temp)
1801      {
1802          std::string name = "";
1803          size_t nameSize = 0;
1804          if (napi_get_value_string_utf8(env, buffer, nullptr, 0, &nameSize) != napi_ok) {
1805              HILOG_ERROR("can not get buffer size");
1806              return;
1807          }
1808          name.reserve(nameSize);
1809          name.resize(nameSize);
1810          if (napi_get_value_string_utf8(env, buffer, name.data(), nameSize + 1, &nameSize) != napi_ok) {
1811              HILOG_ERROR("can not get buffer value");
1812              return;
1813          }
1814          std::string tempName = name;
1815          std::string value = "";
1816          size_t valueSize = 0;
1817          if (napi_get_value_string_utf8(env, temp, nullptr, 0, &valueSize) != napi_ok) {
1818              HILOG_ERROR("can not get temp size");
1819              return;
1820          }
1821          value.reserve(valueSize);
1822          value.resize(valueSize);
1823          if (napi_get_value_string_utf8(env, temp, value.data(), valueSize + 1, &valueSize) != napi_ok) {
1824              HILOG_ERROR("can not get temp value");
1825              return;
1826          }
1827          std::string tempValue = value;
1828          searchParams.push_back(tempName);
1829          searchParams.push_back(tempValue);
1830      }
Delete(napi_env env,napi_value buffer)1831      void URLSearchParams::Delete(napi_env env, napi_value buffer)
1832      {
1833          std::string name = "";
1834          size_t nameSize = 0;
1835          if (napi_get_value_string_utf8(env, buffer, nullptr, 0, &nameSize) != napi_ok) {
1836              HILOG_ERROR("can not get buffer size");
1837              return;
1838          }
1839          name.reserve(nameSize);
1840          name.resize(nameSize);
1841          if (napi_get_value_string_utf8(env, buffer, name.data(), nameSize + 1, &nameSize) != napi_ok) {
1842              HILOG_ERROR("can not get buffer value");
1843              return;
1844          }
1845          std::string sname = ToUSVString(name);
1846          for (auto iter = searchParams.begin(); iter != searchParams.end();) {
1847              if (*iter == sname) {
1848                  iter = searchParams.erase(iter, iter + 2); // 2:Searching for the number and number of keys and values
1849              } else {
1850                  iter += 2; // 2:Searching for the number and number of keys and values
1851              }
1852          }
1853      }
Entries(napi_env env) const1854      napi_value URLSearchParams::Entries(napi_env env) const
1855      {
1856          napi_value resend = nullptr;
1857          napi_value firNapiStr = nullptr;
1858          napi_value secNapiStr = nullptr;
1859          napi_create_array(env, &resend);
1860          if (searchParams.size() == 0) {
1861              return resend;
1862          }
1863          size_t size = searchParams.size() - 1;
1864          for (size_t i = 0; i < size; i += 2) { // 2:Searching for the number and number of keys and values
1865              napi_value result = nullptr;
1866              napi_create_array(env, &result);
1867              napi_create_string_utf8(env, searchParams[i].c_str(), searchParams[i].length(), &firNapiStr);
1868              napi_create_string_utf8(env, searchParams[i + 1].c_str(), searchParams[i + 1].length(), &secNapiStr);
1869              napi_set_element(env, result, 0, firNapiStr);
1870              napi_set_element(env, result, 1, secNapiStr);
1871              napi_set_element(env, resend, i / 2, result); // 2:Find the number of keys
1872          }
1873          return resend;
1874      }
1875  
IsHas(napi_env env,napi_value name) const1876      napi_value URLSearchParams::IsHas(napi_env env, napi_value name) const
1877      {
1878          size_t bufferSize = 0;
1879          if (napi_get_value_string_utf8(env, name, nullptr, 0, &bufferSize) != napi_ok) {
1880              HILOG_ERROR("can not get name size");
1881              return nullptr;
1882          }
1883          std::string buf = "";
1884          buf.resize(bufferSize);
1885          if (napi_get_value_string_utf8(env, name, buf.data(), bufferSize + 1, &bufferSize) != napi_ok) {
1886              HILOG_ERROR("can not get name value");
1887              return nullptr;
1888          }
1889          bool flag = false;
1890          napi_value result = nullptr;
1891          size_t lenStr = searchParams.size();
1892          for (size_t i = 0; i != lenStr; i += 2) { // 2:Searching for the number and number of keys and values
1893              if (searchParams[i] == buf) {
1894                  flag = true;
1895                  napi_get_boolean(env, flag, &result);
1896                  return result;
1897              }
1898          }
1899          napi_get_boolean(env, flag, &result);
1900          return result;
1901      }
Set(napi_env env,napi_value name,napi_value value)1902      void URLSearchParams::Set(napi_env env, napi_value name, napi_value value)
1903      {
1904          std::string buffer = "";
1905          size_t bufferSize = 0;
1906          if (napi_get_value_string_utf8(env, name, nullptr, 0, &bufferSize) != napi_ok) {
1907              HILOG_ERROR("can not get name size");
1908              return;
1909          }
1910          buffer.reserve(bufferSize);
1911          buffer.resize(bufferSize);
1912          if (napi_get_value_string_utf8(env, name, buffer.data(), bufferSize + 1, &bufferSize) != napi_ok) {
1913              HILOG_ERROR("can not get name value");
1914              return;
1915          }
1916          std::string cppName = buffer;
1917          std::string temp = "";
1918          size_t tempSize = 0;
1919          if (napi_get_value_string_utf8(env, value, nullptr, 0, &tempSize) != napi_ok) {
1920              HILOG_ERROR("can not get value size");
1921              return;
1922          }
1923          temp.reserve(tempSize);
1924          temp.resize(tempSize);
1925          if (napi_get_value_string_utf8(env, value, temp.data(), tempSize + 1, &tempSize) != napi_ok) {
1926              HILOG_ERROR("can not get value value");
1927              return;
1928          }
1929          std::string cppValue = temp;
1930          bool flag = false;
1931          for (auto it = searchParams.begin(); it < (searchParams.end() - 1);) {
1932              if (*it == cppName) {
1933                  if (!flag) {
1934                      *(it + 1) = cppValue;
1935                      flag = true;
1936                      it += 2; // 2:Searching for the number and number of keys and values
1937                  } else {
1938                      it = searchParams.erase(it, it + 2); // 2:Searching for the number and number of keys and values
1939                  }
1940              } else {
1941                  it += 2; // 2:Searching for the number and number of keys and values
1942              }
1943          }
1944          if (!flag) {
1945              searchParams.push_back(cppName);
1946              searchParams.push_back(cppValue);
1947          }
1948      }
Sort()1949      void URLSearchParams::Sort()
1950      {
1951          size_t len = searchParams.size();
1952          if (len <= 2 && (len % 2 != 0)) { // 2: Iterate over key-value pairs
1953              return;
1954          }
1955          size_t i = 0;
1956          for (; i < len - 2; i += 2) { // 2:Iterate over key-value pairs
1957              size_t j = i + 2; // 2:Iterate over key-value pairs
1958              for (; j < len; j += 2) { // 2:Iterate over key-value pairs
1959                  bool tmp = (searchParams[i] > searchParams[j]);
1960                  if (tmp) {
1961                      const std::string curKey = searchParams[i];
1962                      const std::string curVal = searchParams[i + 1];
1963                      searchParams[i] = searchParams[j];
1964                      searchParams[i + 1] = searchParams[j + 1];
1965                      searchParams[j] = curKey;
1966                      searchParams[j + 1] = curVal;
1967                  }
1968              }
1969          }
1970      }
IterByKeys(napi_env env)1971      napi_value URLSearchParams::IterByKeys(napi_env env)
1972      {
1973          std::vector<std::string> toKeys;
1974          napi_value result = nullptr;
1975          napi_value napiStr = nullptr;
1976          napi_create_array(env, &result);
1977          size_t stepSize = 2; // 2:Searching for the number and number of keys and values
1978          size_t lenStr = searchParams.size();
1979          if (lenStr % 2 == 0) { // 2:Get the number of values
1980              for (auto it = searchParams.begin(); it != searchParams.end(); it += stepSize) {
1981                  toKeys.push_back(*it);
1982              }
1983              size_t lenToKeys = toKeys.size();
1984              for (size_t i = 0; i < lenToKeys; i++) {
1985                  napi_create_string_utf8(env, toKeys[i].c_str(), toKeys[i].length(), &napiStr);
1986                  napi_set_element(env, result, i, napiStr);
1987              }
1988          }
1989          return result;
1990      }
IterByValues(napi_env env)1991      napi_value URLSearchParams::IterByValues(napi_env env)
1992      {
1993          std::vector<std::string> toKeys;
1994          napi_value result = nullptr;
1995          napi_value napiStr = nullptr;
1996          napi_create_array(env, &result);
1997          size_t stepSize = 2; // 2:Searching for the number and number of keys and values
1998          size_t lenStr = searchParams.size();
1999          if (lenStr % 2 == 0) { // 2:Get the number of values
2000              for (auto it = searchParams.begin();
2001                  it != searchParams.end();
2002                  it += stepSize) {
2003                  toKeys.push_back(*(it + 1));
2004              }
2005              size_t lenToKeys = toKeys.size();
2006              for (size_t i = 0; i < lenToKeys; i++) {
2007                  napi_create_string_utf8(env, toKeys[i].c_str(), toKeys[i].length(), &napiStr);
2008                  napi_set_element(env, result, i, napiStr);
2009              }
2010          }
2011          return result;
2012      }
SetArray(napi_env env,const std::vector<std::string> vec)2013      void URLSearchParams::SetArray(napi_env env, const std::vector<std::string> vec)
2014      {
2015          searchParams = vec;
2016      }
GetArray(napi_env env) const2017      napi_value URLSearchParams::GetArray(napi_env env) const
2018      {
2019          napi_value arr = nullptr;
2020          napi_create_array(env, &arr);
2021          size_t length = searchParams.size();
2022          for (size_t i = 0; i < length; i++) {
2023              napi_value result = nullptr;
2024              napi_create_string_utf8(env, searchParams[i].c_str(), searchParams[i].size(), &result);
2025              napi_set_element(env, arr, i, result);
2026          }
2027          return arr;
2028      }
2029  } // namespace OHOS::Url
2030