Coverage Report

Created: 2025-11-24 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/sources/xsGlobal.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-2025  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
 * This file incorporates work covered by the following copyright and  
20
 * permission notice:  
21
 *
22
 *       Copyright (C) 2010-2016 Marvell International Ltd.
23
 *       Copyright (C) 2002-2010 Kinoma, Inc.
24
 *
25
 *       Licensed under the Apache License, Version 2.0 (the "License");
26
 *       you may not use this file except in compliance with the License.
27
 *       You may obtain a copy of the License at
28
 *
29
 *        http://www.apache.org/licenses/LICENSE-2.0
30
 *
31
 *       Unless required by applicable law or agreed to in writing, software
32
 *       distributed under the License is distributed on an "AS IS" BASIS,
33
 *       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34
 *       See the License for the specific language governing permissions and
35
 *       limitations under the License.
36
 */
37
38
#include "xsAll.h"
39
40
static void fx_trace_aux(txMachine* the, txInteger flags);
41
42
static const char ICACHE_RODATA_ATTR gxURIEmptySet[128] = {
43
  /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
44
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x                    */
45
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x                    */
46
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2x   !"#$%&'()*+,-./  */
47
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3x  0123456789:;<=>?  */
48
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4x  @ABCDEFGHIJKLMNO  */
49
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5X  PQRSTUVWXYZ[\]^_  */
50
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6x  `abcdefghijklmno  */
51
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0  /* 7X  pqrstuvwxyz{|}~   */
52
};
53
54
static const char ICACHE_RODATA_ATTR gxURIReservedSet[128] = {
55
  /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
56
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x                    */
57
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x                    */
58
   0,0,0,1,1,0,1,0,0,0,0,1,1,0,0,1, /* 2x   !"#$%&'()*+,-./  */
59
   0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,1, /* 3x  0123456789:;<=>?  */
60
   1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4x  @ABCDEFGHIJKLMNO  */
61
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5X  PQRSTUVWXYZ[\]^_  */
62
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6x  `abcdefghijklmno  */
63
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0  /* 7X  pqrstuvwxyz{|}~   */
64
};
65
66
static const char ICACHE_RODATA_ATTR gxURIUnescapedSet[128] = {
67
  /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
68
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x                    */
69
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x                    */
70
   0,1,0,0,0,0,0,1,1,1,1,0,0,1,1,0, /* 2x   !"#$%&'()*+,-./  */
71
   1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, /* 3x  0123456789:;<=>?  */
72
   0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4x  @ABCDEFGHIJKLMNO  */
73
   1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, /* 5X  PQRSTUVWXYZ[\]^_  */
74
   0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6x  `abcdefghijklmno  */
75
   1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,0  /* 7X  pqrstuvwxyz{|}~   */
76
};
77
78
static const char ICACHE_RODATA_ATTR gxURIReservedAndUnescapedSet[128] = {
79
  /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
80
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x                    */
81
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x                    */
82
   0,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1, /* 2x   !"#$%&'()*+,-./  */
83
   1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1, /* 3x  0123456789:;<=>?  */
84
   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4x  @ABCDEFGHIJKLMNO  */
85
   1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, /* 5X  PQRSTUVWXYZ[\]^_  */
86
   0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6x  `abcdefghijklmno  */
87
   1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,0  /* 7X  pqrstuvwxyz{|}~   */
88
};
89
90
const txBehavior ICACHE_FLASH_ATTR gxGlobalBehavior = {
91
  fxGlobalGetProperty,
92
  fxGlobalSetProperty,
93
  fxOrdinaryCall,
94
  fxOrdinaryConstruct,
95
  fxOrdinaryDefineOwnProperty,
96
  fxGlobalDeleteProperty,
97
  fxOrdinaryGetOwnProperty,
98
  fxOrdinaryGetPropertyValue,
99
  fxOrdinaryGetPrototype,
100
  fxOrdinaryHasProperty,
101
  fxOrdinaryIsExtensible,
102
  fxOrdinaryOwnKeys,
103
  fxOrdinaryPreventExtensions,
104
  fxOrdinarySetPropertyValue,
105
  fxOrdinarySetPrototype,
106
};
107
      
108
void fxBuildGlobal(txMachine* the)
109
33.8k
{
110
33.8k
  txSlot* slot;
111
112
33.8k
  fxNewInstance(the);
113
33.8k
  mxPull(mxObjectPrototype);
114
  
115
33.8k
  mxPush(mxObjectPrototype);
116
33.8k
  fxNewFunctionInstance(the, XS_NO_ID);
117
33.8k
  mxPull(mxFunctionPrototype);
118
  
119
33.8k
  mxPush(mxObjectPrototype);
120
33.8k
  slot = fxNewObjectInstance(the);
121
33.8k
  mxPull(mxIteratorPrototype);
122
  
123
33.8k
  fxBuildHostFunction(the, mxCallback(fx_isFinite), 1, mxID(_isFinite));
124
33.8k
  mxPull(mxIsFiniteFunction);
125
33.8k
  fxBuildHostFunction(the, mxCallback(fx_isNaN), 1, mxID(_isNaN));
126
33.8k
  mxPull(mxIsNaNFunction);
127
33.8k
  fxBuildHostFunction(the, mxCallback(fx_parseFloat), 1, mxID(_parseFloat));
128
33.8k
  mxPull(mxParseFloatFunction);
129
33.8k
  fxBuildHostFunction(the, mxCallback(fx_parseInt), 2, mxID(_parseInt));
130
33.8k
  mxPull(mxParseIntFunction);
131
33.8k
  fxBuildHostFunction(the, mxCallback(fx_decodeURI), 1, mxID(_decodeURI));
132
33.8k
  mxPull(mxDecodeURIFunction);
133
33.8k
  fxBuildHostFunction(the, mxCallback(fx_decodeURIComponent), 1, mxID(_decodeURIComponent));
134
33.8k
  mxPull(mxDecodeURIComponentFunction);
135
33.8k
  fxBuildHostFunction(the, mxCallback(fx_encodeURI), 1, mxID(_encodeURI));
136
33.8k
  mxPull(mxEncodeURIFunction);
137
33.8k
  fxBuildHostFunction(the, mxCallback(fx_encodeURIComponent), 1, mxID(_encodeURIComponent));
138
33.8k
  mxPull(mxEncodeURIComponentFunction);
139
33.8k
  fxBuildHostFunction(the, mxCallback(fx_escape), 1, mxID(_escape));
140
33.8k
  mxPull(mxEscapeFunction);
141
33.8k
  fxBuildHostFunction(the, mxCallback(fx_eval), 1, mxID(_eval));
142
33.8k
  mxPull(mxEvalFunction);
143
33.8k
  fxBuildHostFunction(the, mxCallback(fx_unescape), 1, mxID(_unescape));
144
33.8k
  mxPull(mxUnescapeFunction);
145
146
33.8k
  slot = fxBuildHostFunction(the, mxCallback(fx_trace), 1, mxID(_trace));
147
33.8k
  slot = fxLastProperty(the, slot);
148
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_trace_center), 1, mxID(_center), XS_DONT_ENUM_FLAG);
149
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_trace_left), 1, mxID(_left), XS_DONT_ENUM_FLAG);
150
33.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_trace_right), 1, mxID(_right), XS_DONT_ENUM_FLAG);
151
33.8k
    mxPull(mxTraceFunction);
152
    
153
#if mxNative  
154
  fxBuildHostFunction(the, mxCallback(fx_Native), 1, mxID(_Native));
155
  mxPull(mxNativeConstructor);
156
  fxBuildHostFunction(the, mxCallback(fx_native), 1, mxID(_native));
157
  mxPull(mxNativeFunction);
158
#endif  
159
  
160
33.8k
  fxNewHostFunction(the, mxCallback(fxThrowTypeError), 0, XS_NO_ID, XS_NO_ID);
161
33.8k
  mxThrowTypeErrorFunction = *the->stack;
162
33.8k
  slot = the->stack->value.reference;
163
33.8k
  slot->flag |= XS_DONT_PATCH_FLAG;
164
33.8k
  slot = slot->next;
165
169k
  while (slot) {
166
135k
    slot->flag |= XS_DONT_DELETE_FLAG | XS_DONT_SET_FLAG;
167
135k
    slot = slot->next;
168
135k
  }
169
33.8k
  mxPop();
170
33.8k
}
171
172
txSlot* fxNewGlobalInstance(txMachine* the)
173
34.6k
{
174
34.6k
  txSlot* instance;
175
34.6k
  txSlot* property;
176
34.6k
  txSize size = fxMultiplyChunkSizes(the, XS_INTRINSICS_COUNT, sizeof(txSlot*));
177
34.6k
  instance = fxNewSlot(the);
178
34.6k
  instance->flag = XS_EXOTIC_FLAG;
179
34.6k
  instance->kind = XS_INSTANCE_KIND;
180
34.6k
  instance->value.instance.garbage = C_NULL;
181
34.6k
  instance->value.instance.prototype = the->stack->value.reference;
182
34.6k
  the->stack->value.reference = instance;
183
34.6k
  the->stack->kind = XS_REFERENCE_KIND;
184
34.6k
  property = instance->next = fxNewSlot(the);
185
34.6k
  property->value.table.address = (txSlot**)fxNewChunk(the, size);
186
34.6k
  c_memset(property->value.table.address, 0, size);
187
34.6k
  property->value.table.length = XS_INTRINSICS_COUNT;
188
34.6k
  property->flag = XS_INTERNAL_FLAG;
189
34.6k
  property->ID = XS_GLOBAL_BEHAVIOR;
190
34.6k
  property->kind = XS_GLOBAL_KIND;
191
34.6k
  return instance;
192
34.6k
}
193
194
txBoolean fxGlobalDeleteProperty(txMachine* the, txSlot* instance, txID id, txIndex index) 
195
74.6k
{
196
74.6k
  txBoolean result = fxOrdinaryDeleteProperty(the, instance, id, index);
197
74.6k
  if ((XS_SYMBOL_ID_COUNT <= id) && (id < XS_INTRINSICS_COUNT) && result) {
198
18
    txSlot* globals = instance->next;
199
18
    globals->value.table.address[id] = C_NULL;
200
18
  }
201
74.6k
  return result;
202
74.6k
}
203
204
txSlot* fxGlobalGetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag) 
205
176M
{
206
176M
  txSlot* result = C_NULL;
207
176M
  if ((XS_SYMBOL_ID_COUNT <= id) && (id < XS_INTRINSICS_COUNT)) {
208
30.6M
    txSlot* globals = instance->next;
209
30.6M
    result = globals->value.table.address[id];
210
30.6M
    if (!result) {
211
42.4k
      result = fxOrdinaryGetProperty(the, instance, id, index, flag);
212
42.4k
      globals->value.table.address[id] = result;
213
42.4k
    }
214
30.6M
  }
215
176M
  if (!result)
216
146M
    result = fxOrdinaryGetProperty(the, instance, id, index, flag);
217
176M
  return result;
218
176M
}
219
220
txSlot* fxGlobalSetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag) 
221
49.0M
{
222
49.0M
  txSlot* result = C_NULL;
223
49.0M
  if ((XS_SYMBOL_ID_COUNT <= id) && (id < XS_INTRINSICS_COUNT)) {
224
411k
    txSlot* globals = instance->next;
225
411k
    result = globals->value.table.address[id];
226
411k
    if (!result) {
227
1
      result = fxOrdinarySetProperty(the, instance, id, index, flag);
228
1
      globals->value.table.address[id] = result;
229
1
    }
230
411k
  }
231
49.0M
  if (!result)
232
48.6M
    result = fxOrdinarySetProperty(the, instance, id, index, flag);
233
49.0M
  return result;
234
49.0M
}
235
236
void fx_decodeURI(txMachine* the)
237
578k
{
238
578k
  if (mxArgc < 1)
239
56
    mxSyntaxError("no URI parameter");
240
578k
  fxDecodeURI(the, (txString)gxURIReservedSet);
241
578k
}
242
243
void fx_decodeURIComponent(txMachine* the)
244
66.3k
{
245
66.3k
  if (mxArgc < 1)
246
0
    mxSyntaxError("no URI Component parameter");
247
66.3k
  fxDecodeURI(the, (txString)gxURIEmptySet);
248
66.3k
}
249
250
void fx_encodeURI(txMachine* the)
251
34.3k
{
252
34.3k
  if (mxArgc < 1)
253
0
    mxSyntaxError("no URI parameter");
254
34.3k
  fxEncodeURI(the, (txString)gxURIReservedAndUnescapedSet);
255
34.3k
}
256
257
void fx_encodeURIComponent(txMachine* the)
258
107
{
259
107
  if (mxArgc < 1)
260
0
    mxSyntaxError("no URI Component parameter");
261
107
  fxEncodeURI(the, (txString)gxURIUnescapedSet);
262
107
}
263
264
void fx_escape(txMachine* the)
265
109k
{
266
109k
  static const char ICACHE_RODATA_ATTR gxSet[128] = {
267
    /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
268
109k
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x                    */
269
109k
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x                    */
270
109k
     0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1, /* 2x   !"#$%&'()*+,-./  */
271
109k
     1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, /* 3x  0123456789:;<=>?  */
272
109k
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4x  @ABCDEFGHIJKLMNO  */
273
109k
     1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, /* 5X  PQRSTUVWXYZ[\]^_  */
274
109k
     0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6x  `abcdefghijklmno  */
275
109k
     1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0  /* 7X  pqrstuvwxyz{|}~   */
276
109k
  };
277
109k
  txString src;
278
109k
  txInteger length;
279
109k
  txInteger c;
280
109k
  txString dst;
281
  
282
109k
  if (mxArgc < 1) {
283
1.95k
    mxResult->value.string = mxUndefinedString.value.string;
284
1.95k
    mxResult->kind = mxUndefinedString.kind;
285
1.95k
    return;
286
1.95k
  }
287
107k
  src = fxToString(the, mxArgv(0));
288
107k
  length = 0;
289
2.00M
  while (((src = mxStringByteDecode(src, &c))) && (c != C_EOF)) {
290
1.90M
    if ((c < 128) && c_read8(gxSet + (int)c))
291
1.15M
      length = fxAddChunkSizes(the, length, 1);
292
743k
    else if (c < 256)
293
741k
      length = fxAddChunkSizes(the, length, 3);
294
2.33k
    else if (c < 0x10000)
295
2.29k
      length = fxAddChunkSizes(the, length, 6);
296
43
    else
297
43
      length = fxAddChunkSizes(the, length, 12);
298
1.90M
  }
299
107k
  if (length == (src - mxArgv(0)->value.string)) {
300
3.13k
    mxResult->value.string = mxArgv(0)->value.string;
301
3.13k
    mxResult->kind = mxArgv(0)->kind;
302
3.13k
    return;
303
3.13k
  }
304
104k
  mxResult->value.string = fxNewChunk(the, fxAddChunkSizes(the, length, 1));
305
104k
  mxResult->kind = XS_STRING_KIND;
306
104k
  src = mxArgv(0)->value.string;
307
104k
  dst = mxResult->value.string;
308
2.00M
  while (((src = mxStringByteDecode(src, &c))) && (c != C_EOF)) {
309
1.89M
    if ((c < 128) && c_read8(gxSet + (int)c))
310
1.15M
      *dst++ = (char)c;
311
740k
    else if (c < 256) {
312
737k
      *dst++ = '%';
313
737k
      dst = fxStringifyHexEscape(dst, c);
314
737k
    }
315
2.33k
    else {
316
2.33k
      *dst++ = '%'; 
317
2.33k
      *dst++ = 'u'; 
318
2.33k
      dst = fxStringifyUnicodeEscape(dst, c, '%');
319
2.33k
    }
320
1.89M
  }
321
104k
  *dst = 0;
322
104k
}
323
324
void fx_eval(txMachine* the)
325
5.37k
{
326
5.37k
  txStringStream aStream;
327
5.37k
  txSlot* realm;
328
5.37k
  txSlot* module = mxFunctionInstanceHome(mxFunction->value.reference)->value.home.module;
329
5.37k
  if (!module) module = mxProgram.value.reference;
330
  
331
5.37k
  realm = mxModuleInstanceInternal(module)->value.module.realm;
332
5.37k
  if (mxArgc < 1)
333
3
    return;
334
5.37k
  if (!mxIsStringPrimitive(mxArgv(0))) {
335
5.37k
    *mxResult = *mxArgv(0);
336
5.37k
    return;
337
5.37k
  }
338
2
  aStream.slot = mxArgv(0);
339
2
  aStream.offset = 0;
340
2
  aStream.size = mxStringLength(fxToString(the, mxArgv(0)));
341
2
  fxRunScript(the, fxParseScript(the, &aStream, fxStringGetter, mxProgramFlag | mxEvalFlag), mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, module);
342
2
  mxPullSlot(mxResult);
343
2
}
344
345
void fx_Native(txMachine* the)
346
0
{
347
0
  mxSyntaxError("invalid Native");
348
0
}
349
350
void fx_native(txMachine* the)
351
0
{
352
0
  mxSyntaxError("invalid native");
353
0
}
354
355
void fx_trace(txMachine* the)
356
8
{
357
//@@#ifdef mxDebug
358
8
  int i;
359
16
  for (i = 0; i < mxArgc; i++) {
360
8
    fxToString(the, mxArgv(i));
361
8
    fxReport(the, "%s", mxArgv(i)->value.string);
362
8
  }
363
//#endif
364
8
}
365
366
void fx_trace_aux(txMachine* the, txInteger flags)
367
0
{
368
0
  txSlot* conversation = C_NULL;
369
0
  void* message = C_NULL;
370
0
  txInteger length = 0;
371
0
  if (mxArgc > 1) {
372
0
    conversation = mxArgv(1);
373
0
    fxToString(the, conversation);
374
0
  }
375
0
  if ((mxArgc > 0) && (mxArgv(0)->kind == XS_REFERENCE_KIND)) {
376
0
    txSlot* slot = mxArgv(0)->value.reference->next;
377
0
    if (slot && (slot->kind == XS_ARRAY_BUFFER_KIND)) {
378
0
      txSlot* bufferInfo = slot->next;
379
0
      length = bufferInfo->value.bufferInfo.length;
380
0
      message = slot->value.arrayBuffer.address;
381
0
      flags |= XS_BUBBLE_BINARY;
382
0
    }
383
0
    else if (slot && (slot->kind == XS_HOST_KIND)) {
384
0
      txSlot* bufferInfo = slot->next;
385
0
      if (bufferInfo && (bufferInfo->kind == XS_BUFFER_INFO_KIND)) {
386
0
        length = bufferInfo->value.bufferInfo.length;
387
0
        message = slot->value.host.data;
388
0
        flags |= XS_BUBBLE_BINARY;
389
0
      }
390
0
    }
391
0
  }
392
0
  if (!message)
393
0
    message = fxToString(the, mxArgv(0));
394
0
  fxBubble(the, flags, message, length, (conversation) ? conversation->value.string : C_NULL);
395
0
}
396
397
void fx_trace_center(txMachine* the)
398
0
{
399
0
  fx_trace_aux(the, XS_NO_FLAG);
400
0
}
401
402
void fx_trace_left(txMachine* the)
403
0
{
404
0
  fx_trace_aux(the, XS_BUBBLE_LEFT);
405
0
}
406
407
void fx_trace_right(txMachine* the)
408
0
{
409
0
  fx_trace_aux(the, XS_BUBBLE_RIGHT);
410
0
}
411
412
void fx_unescape(txMachine* the)
413
0
{
414
0
  txString src;
415
0
  txInteger length;
416
0
  char c;
417
0
  txInteger d;
418
0
  txString dst;
419
420
0
  if (mxArgc < 1) {
421
0
    mxResult->value.string = mxUndefinedString.value.string;
422
0
    mxResult->kind = mxUndefinedString.kind;
423
0
    return;
424
0
  }
425
0
  src = fxToString(the, mxArgv(0));
426
0
  length = 0;
427
0
  while ((c = c_read8(src++))) {
428
0
    if (c == '%') {
429
0
      c = c_read8(src++);
430
0
      if (c == 'u') {
431
0
        if (fxParseUnicodeEscape(&src, &d, 0, '%'))
432
0
          length += mxStringByteLength(d);
433
0
        else
434
0
          length += 2;
435
0
      }
436
0
      else {
437
0
        src--;
438
0
        if (fxParseHexEscape(&src, &d))
439
0
          length += mxStringByteLength(d);
440
0
        else
441
0
          length += 1;
442
0
      }
443
0
    }
444
0
    else
445
0
      length += 1;
446
0
  }   
447
0
  length += 1;
448
0
  if (length == (src - mxArgv(0)->value.string)) {
449
0
    mxResult->value.string = mxArgv(0)->value.string;
450
0
    mxResult->kind = mxArgv(0)->kind;
451
0
    return;
452
0
  }
453
0
  mxResult->value.string = fxNewChunk(the, length);
454
0
  mxResult->kind = XS_STRING_KIND;
455
0
  src = mxArgv(0)->value.string;
456
0
  dst = mxResult->value.string;
457
0
  while ((c = c_read8(src++))) {
458
0
    if (c == '%') {
459
0
      c = c_read8(src++);
460
0
      d = 0;
461
0
      if (c == 'u') {
462
0
        if (fxParseUnicodeEscape(&src, &d, 0, '%'))
463
0
          dst = mxStringByteEncode(dst, d);
464
0
        else {
465
0
          *dst++ = '%';
466
0
          *dst++ = 'u';
467
0
        }
468
0
      }
469
0
      else {
470
0
        src--;
471
0
        if (fxParseHexEscape(&src, &d))
472
0
          dst = mxStringByteEncode(dst, d);
473
0
        else
474
0
          *dst++ = '%';
475
0
      }
476
0
    }
477
0
    else
478
0
      *dst++ = (txU1)c;
479
0
  }
480
0
  *dst = 0;
481
0
}
482
483
void fxDecodeURI(txMachine* the, txString theSet)
484
645k
{
485
645k
  txString src;
486
645k
  txInteger length;
487
645k
  txInteger c, d;
488
645k
  const txUTF8Sequence *sequence;
489
645k
  txInteger size;
490
645k
  txString dst;
491
  
492
645k
  src = fxToString(the, mxArgv(0));
493
645k
  length = 0;
494
21.7M
  while ((c = c_read8(src++))) {
495
21.2M
    if (c == '%') {
496
783k
      if (!fxParseHexEscape(&src, &d))
497
95.5k
        mxURIError("invalid URI");
498
688k
      if ((d < 128) && c_read8(theSet + d))
499
300k
        length += 3;
500
387k
      else {
501
576k
        for (sequence = gxUTF8Sequences; sequence->size; sequence++) {
502
575k
          if ((d & sequence->cmask) == sequence->cval)
503
386k
            break;
504
575k
        }
505
387k
        if (!sequence->size)
506
1.09k
          mxURIError("invalid URI");
507
386k
        size = sequence->size - 1;
508
475k
        while (size > 0) {
509
151k
          c = c_read8(src++);
510
151k
          if (c != '%')
511
15
            mxURIError("invalid URI");
512
151k
          if (!fxParseHexEscape(&src, &c))
513
62.6k
            mxURIError("invalid URI");
514
88.8k
          if ((c & 0xC0) != 0x80)
515
9
            mxURIError("invalid URI");
516
88.8k
          d = (d << 6) | (c & 0x3F);
517
88.8k
          size--;
518
88.8k
        }
519
323k
        d &= sequence->lmask;
520
323k
        if (sequence != gxUTF8Sequences) {
521
48.0k
          if ((sequence[-1].lmask >= (txU4)d) ||   // over-encoding
522
48.0k
            ((d >= 0xD800) & (d <= 0xDFFF)))    // half of surrogate pair
523
3
            mxURIError("invalid URI");
524
48.0k
        }
525
526
323k
        length += mxStringByteLength(d);
527
323k
      }
528
688k
    }
529
20.4M
    else
530
20.4M
      length += 1;
531
21.2M
  }    
532
485k
  length += 1;
533
485k
  if (length == (src - mxArgv(0)->value.string)) {
534
255k
    mxResult->value.string = mxArgv(0)->value.string;
535
255k
    mxResult->kind = mxArgv(0)->kind;
536
255k
    return;
537
255k
  }
538
229k
  mxResult->value.string = fxNewChunk(the, length);
539
229k
  mxResult->kind = XS_STRING_KIND;
540
229k
  src = mxArgv(0)->value.string;
541
229k
  dst = mxResult->value.string;
542
14.7M
  while ((c = c_read8(src++))) {
543
14.4M
    if (c == '%') {
544
553k
      fxParseHexEscape(&src, &d);
545
553k
      if ((d < 128) && c_read8(theSet + d)) {
546
229k
        *dst++ = c_read8(src - 3);
547
229k
        *dst++ = c_read8(src - 2);
548
229k
        *dst++ = c_read8(src - 1);
549
229k
      }
550
323k
      else {
551
412k
        for (sequence = gxUTF8Sequences; sequence->size; sequence++) {
552
412k
          if ((d & sequence->cmask) == sequence->cval)
553
323k
            break;
554
412k
        }
555
323k
        size = sequence->size - 1;
556
412k
        while (size > 0) {
557
88.8k
          src++;
558
88.8k
          fxParseHexEscape(&src, &c);
559
88.8k
          d = (d << 6) | (c & 0x3F);
560
88.8k
          size--;
561
88.8k
        }
562
323k
        d &= sequence->lmask;
563
323k
        dst = mxStringByteEncode(dst, d);
564
323k
      }
565
553k
    }
566
13.9M
    else
567
13.9M
      *dst++ = c;
568
14.4M
  }
569
229k
  *dst = 0;
570
229k
}
571
572
void fxEncodeURI(txMachine* the, txString theSet)
573
34.4k
{
574
34.4k
  txString src;
575
34.4k
  txInteger length;
576
34.4k
  txInteger c;
577
34.4k
  txString dst;
578
579
34.4k
  src = fxToString(the, mxArgv(0));
580
34.4k
  length = 0;
581
310k
  while (((src = mxStringByteDecode(src, &c))) && (c != C_EOF)) {
582
285k
    if (c < 0x80) {
583
156k
      if (c_read8(theSet + c))
584
93.6k
        length += 1;
585
63.3k
      else
586
63.3k
        length += 3;
587
156k
    }
588
128k
    else if (c < 0x800)
589
10.9k
      length += 6;
590
117k
    else if ((0xD800 <= c) && (c <= 0xDFFF))
591
9.22k
      mxURIError("invalid string");
592
108k
    else if (c < 0x10000)
593
105k
      length += 9;
594
3.09k
    else
595
3.09k
      length += 12;
596
285k
  }
597
25.2k
  length += 1;
598
25.2k
  if (length == (src - mxArgv(0)->value.string)) {
599
157
    mxResult->value.string = mxArgv(0)->value.string;
600
157
    mxResult->kind = mxArgv(0)->kind;
601
157
    return;
602
157
  }
603
25.1k
  mxResult->value.string = fxNewChunk(the, length);
604
25.1k
  mxResult->kind = XS_STRING_KIND;
605
25.1k
  src = mxArgv(0)->value.string;
606
25.1k
  dst = mxResult->value.string;
607
299k
  while (((src = mxStringByteDecode(src, &c))) && (c != C_EOF)) {
608
274k
    if (c < 0x80) {
609
155k
      if (c_read8(theSet + c))
610
92.5k
        *dst++ = (char)c;
611
62.8k
      else {
612
62.8k
        *dst++ = '%';
613
62.8k
        dst = fxStringifyHexEscape(dst, c);
614
62.8k
      }
615
155k
    }
616
118k
    else if (c < 0x800) {
617
10.8k
      *dst++ = '%';
618
10.8k
      dst = fxStringifyHexEscape(dst, 0xC0 | (c >> 6));
619
10.8k
      *dst++ = '%';
620
10.8k
      dst = fxStringifyHexEscape(dst, 0x80 | (c & 0x3F));
621
10.8k
    }
622
108k
    else if (c < 0x10000) {
623
104k
      *dst++ = '%';
624
104k
      dst = fxStringifyHexEscape(dst, 0xE0 | (c >> 12));
625
104k
      *dst++ = '%';
626
104k
      dst = fxStringifyHexEscape(dst, 0x80 | ((c >> 6) & 0x3F));
627
104k
      *dst++ = '%';
628
104k
      dst = fxStringifyHexEscape(dst, 0x80 | (c & 0x3F));
629
104k
    }
630
3.09k
    else {
631
3.09k
      *dst++ = '%';
632
3.09k
      dst = fxStringifyHexEscape(dst, 0xF0 | (c >> 18));
633
3.09k
      *dst++ = '%';
634
3.09k
      dst = fxStringifyHexEscape(dst, 0x80 | ((c >> 12) & 0x3F));
635
3.09k
      *dst++ = '%';
636
3.09k
      dst = fxStringifyHexEscape(dst, 0x80 | ((c >> 6) & 0x3F));
637
3.09k
      *dst++ = '%';
638
3.09k
      dst = fxStringifyHexEscape(dst, 0x80 | (c & 0x3F));
639
3.09k
    }
640
274k
  }
641
25.1k
  *dst = 0;
642
25.1k
}