1 /*
2 * Copyright (c) 2023-2024 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 "ecmascript/base/json_helper.h"
17 #include "ecmascript/base/utf_helper.h"
18
19 #include <algorithm>
20 #include <iomanip>
21 #include <sstream>
22
23 namespace panda::ecmascript::base {
24 constexpr unsigned char CODE_SPACE = 0x20;
25 constexpr int FOUR_HEX = 4;
26 constexpr char ZERO_FIRST = static_cast<char>(0xc0); // \u0000 => c0 80
27 constexpr char ALONE_SURROGATE_3B_FIRST = static_cast<char>(0xed);
28 constexpr char ALONE_SURROGATE_3B_SECOND_START = static_cast<char>(0xa0);
29 constexpr char ALONE_SURROGATE_3B_SECOND_END = static_cast<char>(0xbf);
30 constexpr char ALONE_SURROGATE_3B_THIRD_START = static_cast<char>(0x80);
31 constexpr char ALONE_SURROGATE_3B_THIRD_END = static_cast<char>(0xbf);
32
IsFastValueToQuotedString(const char * value)33 bool JsonHelper::IsFastValueToQuotedString(const char *value)
34 {
35 if (strpbrk(value, "\"\\\b\f\n\r\t") != nullptr) {
36 return false;
37 }
38 while (*value != '\0') {
39 if ((*value > 0 && *value < CODE_SPACE) || *value == ZERO_FIRST || *value == ALONE_SURROGATE_3B_FIRST) {
40 return false;
41 }
42 value++;
43 }
44 return true;
45 }
46
ValueToQuotedString(CString str)47 CString JsonHelper::ValueToQuotedString(CString str)
48 {
49 CString product;
50 const char *value = str.c_str();
51 // fast mode
52 bool isFast = IsFastValueToQuotedString(value);
53 if (isFast) {
54 product += "\"";
55 product += str;
56 product += "\"";
57 return product;
58 }
59 // 1. Let product be code unit 0x0022 (QUOTATION MARK).
60 product += "\"";
61 // 2. For each code unit C in value
62 for (const char *c = value; *c != 0; ++c) {
63 switch (*c) {
64 /*
65 * a. If C is 0x0022 (QUOTATION MARK) or 0x005C (REVERSE SOLIDUS), then
66 * i. Let product be the concatenation of product and code unit 0x005C (REVERSE SOLIDUS).
67 * ii. Let product be the concatenation of product and C.
68 */
69 case '\"':
70 product += "\\\"";
71 break;
72 case '\\':
73 product += "\\\\";
74 break;
75 /*
76 * b. Else if C is 0x0008 (BACKSPACE), 0x000C (FORM FEED), 0x000A (LINE FEED), 0x000D (CARRIAGE RETURN),
77 * or 0x000B (LINE TABULATION), then
78 * i. Let product be the concatenation of product and code unit 0x005C (REVERSE SOLIDUS).
79 * ii. Let abbrev be the String value corresponding to the value of C as follows:
80 * BACKSPACE "b"
81 * FORM FEED (FF) "f"
82 * LINE FEED (LF) "n"
83 * CARRIAGE RETURN (CR) "r"
84 * LINE TABULATION "t"
85 * iii. Let product be the concatenation of product and abbrev.
86 */
87 case '\b':
88 product += "\\b";
89 break;
90 case '\f':
91 product += "\\f";
92 break;
93 case '\n':
94 product += "\\n";
95 break;
96 case '\r':
97 product += "\\r";
98 break;
99 case '\t':
100 product += "\\t";
101 break;
102 case ZERO_FIRST:
103 product += "\\u0000";
104 ++c;
105 break;
106 case ALONE_SURROGATE_3B_FIRST:
107 if (*(c + 1) && *(c + 1) >= ALONE_SURROGATE_3B_SECOND_START &&
108 *(c + 1) <= ALONE_SURROGATE_3B_SECOND_END &&
109 *(c + 2) >= ALONE_SURROGATE_3B_THIRD_START && // 2 : The third character after c
110 *(c + 2) <= ALONE_SURROGATE_3B_THIRD_END) { // 2 : The third character after c
111 auto unicodeRes = utf_helper::ConvertUtf8ToUnicodeChar((uint8_t *)c, 3);
112 std::ostringstream oss;
113 oss << "\\u" << std::hex << std::setfill('0') << std::setw(FOUR_HEX) <<
114 static_cast<int>(unicodeRes.first);
115 product += oss.str();
116 c += 2; // 2 : Skip 2 characters
117 break;
118 }
119 [[fallthrough]];
120 default:
121 // c. Else if C has a code unit value less than 0x0020 (SPACE), then
122 if (*c > 0 && *c < CODE_SPACE) {
123 /*
124 * i. Let product be the concatenation of product and code unit 0x005C (REVERSE SOLIDUS).
125 * ii. Let product be the concatenation of product and "u".
126 * iii. Let hex be the string result of converting the numeric code unit value of C to a String of
127 * four hexadecimal digits. Alphabetic hexadecimal digits are presented as lowercase Latin letters.
128 * iv. Let product be the concatenation of product and hex.
129 */
130 std::ostringstream oss;
131 oss << "\\u" << std::hex << std::setfill('0') << std::setw(FOUR_HEX) << static_cast<int>(*c);
132 product += oss.str();
133 } else {
134 // Else,
135 // i. Let product be the concatenation of product and C.
136 product += *c;
137 }
138 }
139 }
140 // 3. Let product be the concatenation of product and code unit 0x0022 (QUOTATION MARK).
141 product += "\"";
142 // Return product.
143 return product;
144 }
145 } // namespace panda::ecmascript::base