Coverage Report

Created: 2025-06-24 07:03

/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