/src/moddable/modules/data/text/encoder/textencoder.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2021-2022 Moddable Tech, Inc. |
3 | | * |
4 | | * This file is part of the Moddable SDK Runtime. |
5 | | * |
6 | | * The Moddable SDK Runtime is free software: you can redistribute it and/or modify |
7 | | * it under the terms of the GNU Lesser General Public License as published by |
8 | | * the Free Software Foundation, either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * The Moddable SDK Runtime is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public License |
17 | | * along with the Moddable SDK Runtime. If not, see <http://www.gnu.org/licenses/>. |
18 | | * |
19 | | */ |
20 | | |
21 | | #include "xsmc.h" |
22 | | #include "xsHost.h" |
23 | | #ifdef kPocoRotation |
24 | | // Moddable SDK |
25 | | #include "mc.xs.h" // for xsID_ values |
26 | | |
27 | | #define VALIDATE 1 |
28 | | #else |
29 | | // xst, xsnap, etc |
30 | | #include <stdbool.h> |
31 | | |
32 | | #define xsID_read (xsID("read")) |
33 | | #define xsID_String (xsID("String")) |
34 | | #define xsID_Uint8Array (xsID("Uint8Array")) |
35 | | #define xsID_written (xsID("written")) |
36 | | #endif |
37 | | |
38 | | #if !VALIDATE |
39 | | void xs_textencoder(xsMachine *the) |
40 | 0 | { |
41 | 0 | xsmcGet(xsResult, xsTarget, xsID("prototype")); |
42 | 0 | xsResult = xsNewHostInstance(xsResult); |
43 | 0 | } |
44 | | #endif |
45 | | |
46 | | /* |
47 | | null character maps to 0xC0, 0x80 |
48 | | surrogate pair pattern: ED Ax xx ED Bx xx |
49 | | */ |
50 | | |
51 | | void xs_textencoder_encode(xsMachine *the) |
52 | 0 | { |
53 | 0 | uint8_t *src, *dst; |
54 | 0 | int length = 0; |
55 | 0 | uint8_t remap = false; |
56 | |
|
57 | 0 | xsArg(0) = xsCall1(xsGlobal, xsID_String, xsArg(0)); |
58 | 0 | src = (uint8_t *)xsmcToString(xsArg(0)); |
59 | |
|
60 | 0 | while (true) { |
61 | 0 | uint8_t c = c_read8(src++); |
62 | 0 | if (!c) break; |
63 | | |
64 | 0 | if ((0xED == c) && |
65 | 0 | (0xA0 == (0xF0 & c_read8(src))) && |
66 | 0 | (0xED == c_read8(src + 2)) && |
67 | 0 | (0xB0 == (0xF0 & c_read8(src + 3)))) { |
68 | 0 | src += 5; |
69 | 0 | length += 4; |
70 | 0 | remap = true; |
71 | 0 | continue; |
72 | 0 | } |
73 | | |
74 | 0 | length += 1; |
75 | 0 | if ((0xC0 == c) && (0x80 == c_read8(src))) { |
76 | 0 | src += 1; |
77 | 0 | remap = true; |
78 | 0 | } |
79 | 0 | } |
80 | |
|
81 | 0 | xsmcSetArrayBuffer(xsResult, NULL, length); |
82 | 0 | src = (uint8_t *)xsmcToString(xsArg(0)); |
83 | 0 | dst = xsmcToArrayBuffer(xsResult); |
84 | 0 | if (remap) { |
85 | 0 | while (true) { |
86 | 0 | uint8_t c = c_read8(src++); |
87 | 0 | if (!c) break; |
88 | | |
89 | 0 | if ((0xED == c) && |
90 | 0 | (0xA0 == (0xF0 & c_read8(src))) && |
91 | 0 | (0xED == c_read8(src + 2)) && |
92 | 0 | (0xB0 == (0xF0 & c_read8(src + 3)))) { |
93 | 0 | xsIntegerValue high, low; |
94 | |
|
95 | 0 | fxUTF8Decode((xsStringValue)(src - 1), &high); |
96 | 0 | fxUTF8Decode((xsStringValue)(src + 2), &low); |
97 | 0 | fxUTF8Encode((xsStringValue)dst, 0x10000 + ((high & 0x3FF) << 10) + (low & 0x3FF)); |
98 | 0 | src += 5; |
99 | 0 | dst += 4; |
100 | 0 | continue; |
101 | 0 | } |
102 | | |
103 | 0 | if ((0xC0 == c) && (0x80 == c_read8(src))) { |
104 | 0 | *dst++ = 0; |
105 | 0 | src += 1; |
106 | 0 | } |
107 | 0 | else |
108 | 0 | *dst++ = c; |
109 | 0 | } |
110 | 0 | } |
111 | 0 | else |
112 | 0 | c_memcpy(dst, src, length); |
113 | |
|
114 | 0 | xsResult = xsNew1(xsGlobal, xsID_Uint8Array, xsResult); |
115 | 0 | } |
116 | | |
117 | | void xs_textencoder_encodeInto(xsMachine *the) |
118 | 0 | { |
119 | 0 | uint8_t *src, *dst; |
120 | 0 | xsUnsignedValue dstTotal, dstRemaining; |
121 | 0 | int read = 0; |
122 | |
|
123 | 0 | if (!xsmcIsInstanceOf(xsArg(1), xsTypedArrayPrototype)) //@@ limit to Uint8Array |
124 | 0 | xsUnknownError("Uint8Array only"); |
125 | | |
126 | 0 | xsArg(0) = xsCall1(xsGlobal, xsID_String, xsArg(0)); |
127 | 0 | xsmcGetBufferWritable(xsArg(1), (void **)&dst, &dstTotal); |
128 | 0 | dstRemaining = dstTotal; |
129 | 0 | src = (uint8_t *)xsmcToString(xsArg(0)); |
130 | |
|
131 | 0 | while (dstRemaining) { |
132 | 0 | uint8_t first = c_read8(src++); |
133 | 0 | if (!first) break; |
134 | | |
135 | 0 | if (first < 0x80) { |
136 | 0 | *dst++ = first; |
137 | 0 | dstRemaining -= 1; |
138 | 0 | } |
139 | 0 | else if (0xC0 == (first & 0xE0)) { |
140 | 0 | if ((0xC0 == first) && (0x80 == c_read8(src))) { |
141 | 0 | *dst++ = 0; |
142 | 0 | dstRemaining -= 1; |
143 | 0 | src += 1; |
144 | 0 | read += 1; |
145 | 0 | continue; |
146 | 0 | } |
147 | | |
148 | 0 | if (dstRemaining < 2) |
149 | 0 | break; |
150 | | |
151 | 0 | *dst++ = first; |
152 | 0 | *dst++ = c_read8(src++); |
153 | | |
154 | 0 | dstRemaining -= 2; |
155 | 0 | } |
156 | 0 | else if (0xE0 == (first & 0xF0)) { |
157 | 0 | if ((0xED == first) && |
158 | 0 | (0xA0 == (0xF0 & c_read8(src))) && |
159 | 0 | (0xED == c_read8(src + 2)) && |
160 | 0 | (0xB0 == (0xF0 & c_read8(src + 3)))) { |
161 | 0 | xsIntegerValue high, low; |
162 | |
|
163 | 0 | if (dstRemaining < 4) |
164 | 0 | break; |
165 | | |
166 | 0 | fxUTF8Decode((xsStringValue)(src - 1), &high); |
167 | 0 | fxUTF8Decode((xsStringValue)(src + 2), &low); |
168 | 0 | fxUTF8Encode((xsStringValue)dst, 0x10000 + ((high & 0x3FF) << 10) + (low & 0x3FF)); |
169 | 0 | src += 5; |
170 | 0 | dst += 4; |
171 | 0 | dstRemaining -= 4; |
172 | 0 | read += 2; |
173 | 0 | continue; |
174 | 0 | } |
175 | | |
176 | 0 | if (dstRemaining < 3) |
177 | 0 | break; |
178 | | |
179 | 0 | *dst++ = first; |
180 | 0 | *dst++ = c_read8(src++); |
181 | 0 | *dst++ = c_read8(src++); |
182 | | |
183 | 0 | dstRemaining -= 3; |
184 | 0 | } |
185 | 0 | else if (0xF0 == (first & 0xF0)) { |
186 | 0 | if (dstRemaining < 4) |
187 | 0 | break; |
188 | | |
189 | 0 | *dst++ = first; |
190 | 0 | *dst++ = c_read8(src++); |
191 | 0 | *dst++ = c_read8(src++); |
192 | 0 | *dst++ = c_read8(src++); |
193 | | |
194 | 0 | dstRemaining -= 4; |
195 | 0 | } |
196 | 0 | else |
197 | 0 | fxAbort(the, xsFatalCheckExit); |
198 | | |
199 | 0 | read += 1; |
200 | 0 | } |
201 | |
|
202 | 0 | xsmcSetNewObject(xsResult); |
203 | |
|
204 | 0 | xsmcVars(1); |
205 | 0 | xsmcSetInteger(xsVar(0), read); |
206 | 0 | xsmcSet(xsResult, xsID_read, xsVar(0)); |
207 | |
|
208 | 0 | xsmcSetInteger(xsVar(0), dstTotal - dstRemaining); |
209 | 0 | xsmcSet(xsResult, xsID_written, xsVar(0)); |
210 | 0 | } |
211 | | |
212 | | #if !VALIDATE |
213 | | void modInstallTextEncoder(xsMachine *the) |
214 | 0 | { |
215 | 0 | #define kPrototype (0) |
216 | 0 | #define kConstructor (1) |
217 | 0 | #define kScratch (2) |
218 | |
|
219 | 0 | xsBeginHost(the); |
220 | 0 | xsmcVars(3); |
221 | |
|
222 | 0 | xsmcSetNewObject(xsVar(kPrototype)); |
223 | 0 | xsVar(kConstructor) = xsNewHostConstructor(xs_textencoder, 1, xsVar(kPrototype)); |
224 | 0 | xsmcDefine(xsGlobal, xsID("TextEncoder"), xsVar(kConstructor), xsDontEnum); |
225 | |
|
226 | 0 | xsVar(kScratch) = xsNewHostFunction(xs_textencoder_encode, 1); |
227 | 0 | xsmcDefine(xsVar(kPrototype), xsID("encode"), xsVar(kScratch), xsDontEnum); |
228 | 0 | xsVar(kScratch) = xsNewHostFunction(xs_textencoder_encodeInto, 2); |
229 | 0 | xsmcDefine(xsVar(kPrototype), xsID("encodeInto"), xsVar(kScratch), xsDontEnum); |
230 | |
|
231 | 0 | xsEndHost(the); |
232 | 0 | } |
233 | | #endif |