Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "util/Text.h"
8 :
9 : #include "mozilla/PodOperations.h"
10 :
11 : #include "gc/GC.h"
12 : #include "js/GCAPI.h"
13 : #include "vm/JSContext.h"
14 : #include "vm/StringType.h"
15 :
16 : using namespace JS;
17 : using namespace js;
18 : using js::gc::AutoSuppressGC;
19 : using mozilla::PodCopy;
20 :
21 : template <typename CharT>
22 : const CharT*
23 0 : js_strchr_limit(const CharT* s, char16_t c, const CharT* limit)
24 : {
25 0 : while (s < limit) {
26 0 : if (*s == c)
27 : return s;
28 0 : s++;
29 : }
30 : return nullptr;
31 : }
32 :
33 : template const Latin1Char*
34 : js_strchr_limit(const Latin1Char* s, char16_t c, const Latin1Char* limit);
35 :
36 : template const char16_t*
37 : js_strchr_limit(const char16_t* s, char16_t c, const char16_t* limit);
38 :
39 : int32_t
40 0 : js_fputs(const char16_t* s, FILE* f)
41 : {
42 0 : while (*s != 0) {
43 0 : if (fputwc(wchar_t(*s), f) == WEOF)
44 : return WEOF;
45 0 : s++;
46 : }
47 : return 1;
48 : }
49 :
50 : UniqueChars
51 1 : js::DuplicateString(JSContext* cx, const char* s)
52 : {
53 1266 : size_t n = strlen(s) + 1;
54 1266 : auto ret = cx->make_pod_array<char>(n);
55 1266 : if (!ret)
56 : return ret;
57 0 : PodCopy(ret.get(), s, n);
58 1266 : return ret;
59 : }
60 :
61 : UniqueTwoByteChars
62 20 : js::DuplicateString(JSContext* cx, const char16_t* s)
63 : {
64 0 : size_t n = js_strlen(s) + 1;
65 20 : auto ret = cx->make_pod_array<char16_t>(n);
66 20 : if (!ret)
67 : return ret;
68 0 : PodCopy(ret.get(), s, n);
69 20 : return ret;
70 : }
71 :
72 : UniqueChars
73 15438 : js::DuplicateString(const char* s)
74 : {
75 0 : size_t n = strlen(s) + 1;
76 30876 : UniqueChars ret(js_pod_malloc<char>(n));
77 15438 : if (!ret)
78 : return ret;
79 0 : PodCopy(ret.get(), s, n);
80 15438 : return ret;
81 : }
82 :
83 : UniqueChars
84 0 : js::DuplicateString(const char* s, size_t n)
85 : {
86 0 : UniqueChars ret(js_pod_malloc<char>(n + 1));
87 0 : if (!ret)
88 : return nullptr;
89 0 : PodCopy(ret.get(), s, n);
90 0 : ret[n] = 0;
91 : return ret;
92 : }
93 :
94 : UniqueTwoByteChars
95 0 : js::DuplicateString(const char16_t* s)
96 : {
97 0 : return DuplicateString(s, js_strlen(s));
98 : }
99 :
100 : UniqueTwoByteChars
101 0 : js::DuplicateString(const char16_t* s, size_t n)
102 : {
103 0 : UniqueTwoByteChars ret(js_pod_malloc<char16_t>(n + 1));
104 36 : if (!ret)
105 : return nullptr;
106 36 : PodCopy(ret.get(), s, n);
107 0 : ret[n] = 0;
108 : return ret;
109 : }
110 :
111 : char16_t*
112 0 : js::InflateString(JSContext* cx, const char* bytes, size_t length)
113 : {
114 299 : char16_t* chars = cx->pod_malloc<char16_t>(length + 1);
115 299 : if (!chars)
116 : return nullptr;
117 299 : CopyAndInflateChars(chars, bytes, length);
118 0 : chars[length] = 0;
119 299 : return chars;
120 : }
121 :
122 : template <typename CharT>
123 : bool
124 0 : js::DeflateStringToBuffer(JSContext* maybecx, const CharT* src, size_t srclen,
125 : char* dst, size_t* dstlenp)
126 : {
127 1695 : size_t dstlen = *dstlenp;
128 1695 : if (srclen > dstlen) {
129 0 : for (size_t i = 0; i < dstlen; i++)
130 0 : dst[i] = char(src[i]);
131 0 : if (maybecx) {
132 0 : AutoSuppressGC suppress(maybecx);
133 0 : JS_ReportErrorNumberASCII(maybecx, GetErrorMessage, nullptr,
134 : JSMSG_BUFFER_TOO_SMALL);
135 : }
136 : return false;
137 : }
138 1 : for (size_t i = 0; i < srclen; i++)
139 1 : dst[i] = char(src[i]);
140 1695 : *dstlenp = srclen;
141 1695 : return true;
142 : }
143 :
144 : template bool
145 : js::DeflateStringToBuffer(JSContext* maybecx, const Latin1Char* src, size_t srclen,
146 : char* dst, size_t* dstlenp);
147 :
148 : template bool
149 : js::DeflateStringToBuffer(JSContext* maybecx, const char16_t* src, size_t srclen,
150 : char* dst, size_t* dstlenp);
151 :
152 : /*
153 : * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
154 : * least 4 bytes long. Return the number of UTF-8 bytes of data written.
155 : */
156 : uint32_t
157 0 : js::OneUcs4ToUtf8Char(uint8_t* utf8Buffer, uint32_t ucs4Char)
158 : {
159 0 : MOZ_ASSERT(ucs4Char <= unicode::NonBMPMax);
160 :
161 0 : if (ucs4Char < 0x80) {
162 0 : utf8Buffer[0] = uint8_t(ucs4Char);
163 0 : return 1;
164 : }
165 :
166 0 : uint32_t a = ucs4Char >> 11;
167 0 : uint32_t utf8Length = 2;
168 0 : while (a) {
169 0 : a >>= 5;
170 0 : utf8Length++;
171 : }
172 :
173 0 : MOZ_ASSERT(utf8Length <= 4);
174 :
175 : uint32_t i = utf8Length;
176 0 : while (--i) {
177 0 : utf8Buffer[i] = uint8_t((ucs4Char & 0x3F) | 0x80);
178 0 : ucs4Char >>= 6;
179 : }
180 :
181 0 : utf8Buffer[0] = uint8_t(0x100 - (1 << (8 - utf8Length)) + ucs4Char);
182 0 : return utf8Length;
183 : }
184 :
185 : size_t
186 0 : js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, JSLinearString* str,
187 : uint32_t quote)
188 : {
189 0 : size_t len = str->length();
190 0 : AutoCheckCannotGC nogc;
191 0 : return str->hasLatin1Chars()
192 0 : ? PutEscapedStringImpl(buffer, bufferSize, out, str->latin1Chars(nogc), len, quote)
193 0 : : PutEscapedStringImpl(buffer, bufferSize, out, str->twoByteChars(nogc), len, quote);
194 : }
195 :
196 : template <typename CharT>
197 : size_t
198 0 : js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const CharT* chars,
199 : size_t length, uint32_t quote)
200 : {
201 : enum {
202 : STOP, FIRST_QUOTE, LAST_QUOTE, CHARS, ESCAPE_START, ESCAPE_MORE
203 : } state;
204 :
205 0 : MOZ_ASSERT(quote == 0 || quote == '\'' || quote == '"');
206 0 : MOZ_ASSERT_IF(!buffer, bufferSize == 0);
207 0 : MOZ_ASSERT_IF(out, !buffer);
208 :
209 0 : if (bufferSize == 0)
210 : buffer = nullptr;
211 : else
212 0 : bufferSize--;
213 :
214 0 : const CharT* charsEnd = chars + length;
215 0 : size_t n = 0;
216 0 : state = FIRST_QUOTE;
217 0 : unsigned shift = 0;
218 0 : unsigned hex = 0;
219 0 : unsigned u = 0;
220 0 : char c = 0; /* to quell GCC warnings */
221 :
222 : for (;;) {
223 0 : switch (state) {
224 : case STOP:
225 : goto stop;
226 : case FIRST_QUOTE:
227 : state = CHARS;
228 : goto do_quote;
229 : case LAST_QUOTE:
230 0 : state = STOP;
231 : do_quote:
232 0 : if (quote == 0)
233 : continue;
234 0 : c = (char)quote;
235 0 : break;
236 : case CHARS:
237 0 : if (chars == charsEnd) {
238 : state = LAST_QUOTE;
239 : continue;
240 : }
241 0 : u = *chars++;
242 0 : if (u < ' ') {
243 0 : if (u != 0) {
244 0 : const char* escape = strchr(js_EscapeMap, (int)u);
245 0 : if (escape) {
246 0 : u = escape[1];
247 0 : goto do_escape;
248 : }
249 : }
250 : goto do_hex_escape;
251 : }
252 0 : if (u < 127) {
253 0 : if (u == quote || u == '\\')
254 : goto do_escape;
255 0 : c = (char)u;
256 0 : } else if (u < 0x100) {
257 : goto do_hex_escape;
258 : } else {
259 : shift = 16;
260 : hex = u;
261 : u = 'u';
262 : goto do_escape;
263 : }
264 0 : break;
265 : do_hex_escape:
266 0 : shift = 8;
267 0 : hex = u;
268 0 : u = 'x';
269 : do_escape:
270 0 : c = '\\';
271 0 : state = ESCAPE_START;
272 0 : break;
273 : case ESCAPE_START:
274 0 : MOZ_ASSERT(' ' <= u && u < 127);
275 0 : c = (char)u;
276 0 : state = ESCAPE_MORE;
277 0 : break;
278 : case ESCAPE_MORE:
279 0 : if (shift == 0) {
280 : state = CHARS;
281 : continue;
282 : }
283 0 : shift -= 4;
284 0 : u = 0xF & (hex >> shift);
285 0 : c = (char)(u + (u < 10 ? '0' : 'A' - 10));
286 0 : break;
287 : }
288 0 : if (buffer) {
289 0 : MOZ_ASSERT(n <= bufferSize);
290 0 : if (n != bufferSize) {
291 0 : buffer[n] = c;
292 : } else {
293 0 : buffer[n] = '\0';
294 0 : buffer = nullptr;
295 : }
296 0 : } else if (out) {
297 0 : if (!out->put(&c, 1))
298 : return size_t(-1);
299 : }
300 0 : n++;
301 : }
302 : stop:
303 0 : if (buffer)
304 0 : buffer[n] = '\0';
305 : return n;
306 : }
307 :
308 : template size_t
309 : js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const Latin1Char* chars,
310 : size_t length, uint32_t quote);
311 :
312 : template size_t
313 : js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const char* chars,
314 : size_t length, uint32_t quote);
315 :
316 : template size_t
317 : js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const char16_t* chars,
318 : size_t length, uint32_t quote);
319 :
320 : template size_t
321 : js::PutEscapedString(char* buffer, size_t bufferSize, const Latin1Char* chars, size_t length,
322 : uint32_t quote);
323 :
324 : template size_t
325 : js::PutEscapedString(char* buffer, size_t bufferSize, const char16_t* chars, size_t length,
326 : uint32_t quote);
|