Coverage Report

Created: 2026-06-10 07:01

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
24.9k
{
110
24.9k
  txSlot* slot;
111
112
24.9k
  fxNewInstance(the);
113
24.9k
  mxPull(mxObjectPrototype);
114
  
115
24.9k
  mxPush(mxObjectPrototype);
116
24.9k
  fxNewFunctionInstance(the, XS_NO_ID);
117
24.9k
  mxPull(mxFunctionPrototype);
118
  
119
24.9k
  mxPush(mxObjectPrototype);
120
24.9k
  slot = fxNewObjectInstance(the);
121
24.9k
  mxPull(mxIteratorPrototype);
122
  
123
24.9k
  fxBuildHostFunction(the, mxCallback(fx_isFinite), 1, mxID(_isFinite));
124
24.9k
  mxPull(mxIsFiniteFunction);
125
24.9k
  fxBuildHostFunction(the, mxCallback(fx_isNaN), 1, mxID(_isNaN));
126
24.9k
  mxPull(mxIsNaNFunction);
127
24.9k
  fxBuildHostFunction(the, mxCallback(fx_parseFloat), 1, mxID(_parseFloat));
128
24.9k
  mxPull(mxParseFloatFunction);
129
24.9k
  fxBuildHostFunction(the, mxCallback(fx_parseInt), 2, mxID(_parseInt));
130
24.9k
  mxPull(mxParseIntFunction);
131
24.9k
  fxBuildHostFunction(the, mxCallback(fx_decodeURI), 1, mxID(_decodeURI));
132
24.9k
  mxPull(mxDecodeURIFunction);
133
24.9k
  fxBuildHostFunction(the, mxCallback(fx_decodeURIComponent), 1, mxID(_decodeURIComponent));
134
24.9k
  mxPull(mxDecodeURIComponentFunction);
135
24.9k
  fxBuildHostFunction(the, mxCallback(fx_encodeURI), 1, mxID(_encodeURI));
136
24.9k
  mxPull(mxEncodeURIFunction);
137
24.9k
  fxBuildHostFunction(the, mxCallback(fx_encodeURIComponent), 1, mxID(_encodeURIComponent));
138
24.9k
  mxPull(mxEncodeURIComponentFunction);
139
24.9k
  fxBuildHostFunction(the, mxCallback(fx_escape), 1, mxID(_escape));
140
24.9k
  mxPull(mxEscapeFunction);
141
24.9k
  fxBuildHostFunction(the, mxCallback(fx_eval), 1, mxID(_eval));
142
24.9k
  mxPull(mxEvalFunction);
143
24.9k
  fxBuildHostFunction(the, mxCallback(fx_unescape), 1, mxID(_unescape));
144
24.9k
  mxPull(mxUnescapeFunction);
145
146
24.9k
  slot = fxBuildHostFunction(the, mxCallback(fx_trace), 1, mxID(_trace));
147
24.9k
  slot = fxLastProperty(the, slot);
148
24.9k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_trace_center), 1, mxID(_center), XS_DONT_ENUM_FLAG);
149
24.9k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_trace_left), 1, mxID(_left), XS_DONT_ENUM_FLAG);
150
24.9k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_trace_right), 1, mxID(_right), XS_DONT_ENUM_FLAG);
151
24.9k
    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
24.9k
  fxNewHostFunction(the, mxCallback(fxThrowTypeError), 0, XS_NO_ID, XS_NO_ID);
161
24.9k
  mxThrowTypeErrorFunction = *the->stack;
162
24.9k
  slot = the->stack->value.reference;
163
24.9k
  slot->flag |= XS_DONT_PATCH_FLAG;
164
24.9k
  slot = slot->next;
165
124k
  while (slot) {
166
99.8k
    slot->flag |= XS_DONT_DELETE_FLAG | XS_DONT_SET_FLAG;
167
99.8k
    slot = slot->next;
168
99.8k
  }
169
24.9k
  mxPop();
170
24.9k
}
171
172
txSlot* fxNewGlobalInstance(txMachine* the)
173
25.6k
{
174
25.6k
  txSlot* instance;
175
25.6k
  txSlot* property;
176
25.6k
  txSize size = fxMultiplyChunkSizes(the, XS_INTRINSICS_COUNT, sizeof(txSlot*));
177
25.6k
  instance = fxNewSlot(the);
178
25.6k
  instance->flag = XS_EXOTIC_FLAG;
179
25.6k
  instance->kind = XS_INSTANCE_KIND;
180
25.6k
  instance->value.instance.garbage = C_NULL;
181
25.6k
  instance->value.instance.prototype = the->stack->value.reference;
182
25.6k
  the->stack->value.reference = instance;
183
25.6k
  the->stack->kind = XS_REFERENCE_KIND;
184
25.6k
  property = instance->next = fxNewSlot(the);
185
25.6k
  property->value.table.address = (txSlot**)fxNewChunk(the, size);
186
25.6k
  c_memset(property->value.table.address, 0, size);
187
25.6k
  property->value.table.length = XS_INTRINSICS_COUNT;
188
25.6k
  property->flag = XS_INTERNAL_FLAG;
189
25.6k
  property->ID = XS_GLOBAL_BEHAVIOR;
190
25.6k
  property->kind = XS_GLOBAL_KIND;
191
25.6k
  return instance;
192
25.6k
}
193
194
txBoolean fxGlobalDeleteProperty(txMachine* the, txSlot* instance, txID id, txIndex index) 
195
163k
{
196
163k
  txBoolean result = fxOrdinaryDeleteProperty(the, instance, id, index);
197
163k
  if ((XS_SYMBOL_ID_COUNT <= id) && (id < XS_INTRINSICS_COUNT) && result) {
198
89.8k
    txSlot* globals = instance->next;
199
89.8k
    globals->value.table.address[id] = C_NULL;
200
89.8k
  }
201
163k
  return result;
202
163k
}
203
204
txSlot* fxGlobalGetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag) 
205
154M
{
206
154M
  txSlot* result = C_NULL;
207
154M
  if ((XS_SYMBOL_ID_COUNT <= id) && (id < XS_INTRINSICS_COUNT)) {
208
26.1M
    txSlot* globals = instance->next;
209
26.1M
    result = globals->value.table.address[id];
210
26.1M
    if (!result) {
211
33.2k
      result = fxOrdinaryGetProperty(the, instance, id, index, flag);
212
33.2k
      globals->value.table.address[id] = result;
213
33.2k
    }
214
26.1M
  }
215
154M
  if (!result)
216
128M
    result = fxOrdinaryGetProperty(the, instance, id, index, flag);
217
154M
  return result;
218
154M
}
219
220
txSlot* fxGlobalSetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag) 
221
44.4M
{
222
44.4M
  txSlot* result = C_NULL;
223
44.4M
  if ((XS_SYMBOL_ID_COUNT <= id) && (id < XS_INTRINSICS_COUNT)) {
224
170k
    txSlot* globals = instance->next;
225
170k
    result = globals->value.table.address[id];
226
170k
    if (!result) {
227
1
      result = fxOrdinarySetProperty(the, instance, id, index, flag);
228
1
      globals->value.table.address[id] = result;
229
1
    }
230
170k
  }
231
44.4M
  if (!result)
232
44.2M
    result = fxOrdinarySetProperty(the, instance, id, index, flag);
233
44.4M
  return result;
234
44.4M
}
235
236
void fx_decodeURI(txMachine* the)
237
756k
{
238
756k
  if (mxArgc < 1)
239
1
    mxSyntaxError("no URI parameter");
240
756k
  fxDecodeURI(the, (txString)gxURIReservedSet);
241
756k
}
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
7.34k
{
252
7.34k
  if (mxArgc < 1)
253
0
    mxSyntaxError("no URI parameter");
254
7.34k
  fxEncodeURI(the, (txString)gxURIReservedAndUnescapedSet);
255
7.34k
}
256
257
void fx_encodeURIComponent(txMachine* the)
258
108
{
259
108
  if (mxArgc < 1)
260
0
    mxSyntaxError("no URI Component parameter");
261
108
  fxEncodeURI(the, (txString)gxURIUnescapedSet);
262
108
}
263
264
void fx_escape(txMachine* the)
265
148k
{
266
148k
  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
148k
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x                    */
269
148k
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x                    */
270
148k
     0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1, /* 2x   !"#$%&'()*+,-./  */
271
148k
     1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, /* 3x  0123456789:;<=>?  */
272
148k
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4x  @ABCDEFGHIJKLMNO  */
273
148k
     1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, /* 5X  PQRSTUVWXYZ[\]^_  */
274
148k
     0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6x  `abcdefghijklmno  */
275
148k
     1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0  /* 7X  pqrstuvwxyz{|}~   */
276
148k
  };
277
148k
  txString src;
278
148k
  txInteger length;
279
148k
  txInteger c;
280
148k
  txString dst;
281
  
282
148k
  if (mxArgc < 1) {
283
244
    mxResult->value.string = mxUndefinedString.value.string;
284
244
    mxResult->kind = mxUndefinedString.kind;
285
244
    return;
286
244
  }
287
148k
  src = fxToString(the, mxArgv(0));
288
148k
  length = 0;
289
3.34M
  while (((src = mxStringByteDecode(src, &c))) && (c != C_EOF)) {
290
3.19M
    if ((c < 128) && c_read8(gxSet + (int)c))
291
1.33M
      length = fxAddChunkSizes(the, length, 1);
292
1.85M
    else if (c < 256)
293
1.76M
      length = fxAddChunkSizes(the, length, 3);
294
96.9k
    else if (c < 0x10000)
295
94.2k
      length = fxAddChunkSizes(the, length, 6);
296
2.66k
    else
297
2.66k
      length = fxAddChunkSizes(the, length, 12);
298
3.19M
  }
299
148k
  length = fxAddChunkSizes(the, length, 1);
300
148k
  if (length == (src - mxArgv(0)->value.string)) {
301
43.1k
    mxResult->value.string = mxArgv(0)->value.string;
302
43.1k
    mxResult->kind = mxArgv(0)->kind;
303
43.1k
    return;
304
43.1k
  }
305
105k
  mxResult->value.string = fxNewChunk(the, length);
306
105k
  mxResult->kind = XS_STRING_KIND;
307
105k
  src = mxArgv(0)->value.string;
308
105k
  dst = mxResult->value.string;
309
3.21M
  while (((src = mxStringByteDecode(src, &c))) && (c != C_EOF)) {
310
3.10M
    if ((c < 128) && c_read8(gxSet + (int)c))
311
1.25M
      *dst++ = (char)c;
312
1.85M
    else if (c < 256) {
313
1.76M
      *dst++ = '%';
314
1.76M
      dst = fxStringifyHexEscape(dst, c);
315
1.76M
    }
316
96.9k
    else {
317
96.9k
      *dst++ = '%'; 
318
96.9k
      *dst++ = 'u'; 
319
96.9k
      dst = fxStringifyUnicodeEscape(dst, c, '%');
320
96.9k
    }
321
3.10M
  }
322
105k
  *dst = 0;
323
105k
}
324
325
void fx_eval(txMachine* the)
326
6.42k
{
327
6.42k
  txStringStream aStream;
328
6.42k
  txSlot* realm;
329
6.42k
  txSlot* module = mxFunctionInstanceHome(mxFunction->value.reference)->value.home.module;
330
6.42k
  if (!module) module = mxProgram.value.reference;
331
  
332
6.42k
  realm = mxModuleInstanceInternal(module)->value.module.realm;
333
6.42k
  if (mxArgc < 1)
334
1
    return;
335
6.42k
  if (!mxIsStringPrimitive(mxArgv(0))) {
336
6.42k
    *mxResult = *mxArgv(0);
337
6.42k
    return;
338
6.42k
  }
339
1
  aStream.slot = mxArgv(0);
340
1
  aStream.offset = 0;
341
1
  aStream.size = mxStringLength(fxToString(the, mxArgv(0)));
342
1
  fxRunScript(the, fxParseScript(the, &aStream, fxStringGetter, mxProgramFlag | mxEvalFlag), mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, module);
343
1
  mxPullSlot(mxResult);
344
1
}
345
346
void fx_Native(txMachine* the)
347
0
{
348
0
  mxSyntaxError("invalid Native");
349
0
}
350
351
void fx_native(txMachine* the)
352
0
{
353
0
  mxSyntaxError("invalid native");
354
0
}
355
356
void fx_trace(txMachine* the)
357
12
{
358
//@@#ifdef mxDebug
359
12
  int i;
360
24
  for (i = 0; i < mxArgc; i++) {
361
12
    fxToString(the, mxArgv(i));
362
12
    fxReport(the, "%s", mxArgv(i)->value.string);
363
12
  }
364
//#endif
365
12
}
366
367
void fx_trace_aux(txMachine* the, txInteger flags)
368
0
{
369
0
  txSlot* conversation = C_NULL;
370
0
  void* message = C_NULL;
371
0
  txInteger length = 0;
372
0
  if (mxArgc > 1) {
373
0
    conversation = mxArgv(1);
374
0
    fxToString(the, conversation);
375
0
  }
376
0
  if ((mxArgc > 0) && (mxArgv(0)->kind == XS_REFERENCE_KIND)) {
377
0
    txSlot* slot = mxArgv(0)->value.reference->next;
378
0
    if (slot && (slot->kind == XS_ARRAY_BUFFER_KIND)) {
379
0
      txSlot* bufferInfo = slot->next;
380
0
      length = bufferInfo->value.bufferInfo.length;
381
0
      message = slot->value.arrayBuffer.address;
382
0
      flags |= XS_BUBBLE_BINARY;
383
0
    }
384
0
    else if (slot && (slot->kind == XS_HOST_KIND)) {
385
0
      txSlot* bufferInfo = slot->next;
386
0
      if (bufferInfo && (bufferInfo->kind == XS_BUFFER_INFO_KIND)) {
387
0
        length = bufferInfo->value.bufferInfo.length;
388
0
        message = slot->value.host.data;
389
0
        flags |= XS_BUBBLE_BINARY;
390
0
      }
391
0
    }
392
0
  }
393
0
  if (!message)
394
0
    message = fxToString(the, mxArgv(0));
395
0
  fxBubble(the, flags, message, length, (conversation) ? conversation->value.string : C_NULL);
396
0
}
397
398
void fx_trace_center(txMachine* the)
399
0
{
400
0
  fx_trace_aux(the, XS_NO_FLAG);
401
0
}
402
403
void fx_trace_left(txMachine* the)
404
0
{
405
0
  fx_trace_aux(the, XS_BUBBLE_LEFT);
406
0
}
407
408
void fx_trace_right(txMachine* the)
409
0
{
410
0
  fx_trace_aux(the, XS_BUBBLE_RIGHT);
411
0
}
412
413
void fx_unescape(txMachine* the)
414
0
{
415
0
  txString src;
416
0
  txInteger length;
417
0
  char c;
418
0
  txInteger d;
419
0
  txString dst;
420
421
0
  if (mxArgc < 1) {
422
0
    mxResult->value.string = mxUndefinedString.value.string;
423
0
    mxResult->kind = mxUndefinedString.kind;
424
0
    return;
425
0
  }
426
0
  src = fxToString(the, mxArgv(0));
427
0
  length = 0;
428
0
  while ((c = c_read8(src++))) {
429
0
    if (c == '%') {
430
0
      c = c_read8(src++);
431
0
      if (c == 'u') {
432
0
        if (fxParseUnicodeEscape(&src, &d, 0, '%'))
433
0
          length += mxStringByteLength(d);
434
0
        else
435
0
          length += 2;
436
0
      }
437
0
      else {
438
0
        src--;
439
0
        if (fxParseHexEscape(&src, &d))
440
0
          length += mxStringByteLength(d);
441
0
        else
442
0
          length += 1;
443
0
      }
444
0
    }
445
0
    else
446
0
      length += 1;
447
0
  }   
448
0
  length += 1;
449
0
  if (length == (src - mxArgv(0)->value.string)) {
450
0
    mxResult->value.string = mxArgv(0)->value.string;
451
0
    mxResult->kind = mxArgv(0)->kind;
452
0
    return;
453
0
  }
454
0
  mxResult->value.string = fxNewChunk(the, length);
455
0
  mxResult->kind = XS_STRING_KIND;
456
0
  src = mxArgv(0)->value.string;
457
0
  dst = mxResult->value.string;
458
0
  while ((c = c_read8(src++))) {
459
0
    if (c == '%') {
460
0
      c = c_read8(src++);
461
0
      d = 0;
462
0
      if (c == 'u') {
463
0
        if (fxParseUnicodeEscape(&src, &d, 0, '%'))
464
0
          dst = mxStringByteEncode(dst, d);
465
0
        else {
466
0
          *dst++ = '%';
467
0
          *dst++ = 'u';
468
0
        }
469
0
      }
470
0
      else {
471
0
        src--;
472
0
        if (fxParseHexEscape(&src, &d))
473
0
          dst = mxStringByteEncode(dst, d);
474
0
        else
475
0
          *dst++ = '%';
476
0
      }
477
0
    }
478
0
    else
479
0
      *dst++ = (txU1)c;
480
0
  }
481
0
  *dst = 0;
482
0
}
483
484
void fxDecodeURI(txMachine* the, txString theSet)
485
822k
{
486
822k
  txString src;
487
822k
  txInteger length;
488
822k
  txInteger c, d;
489
822k
  const txUTF8Sequence *sequence;
490
822k
  txInteger size;
491
822k
  txString dst;
492
  
493
822k
  src = fxToString(the, mxArgv(0));
494
822k
  length = 0;
495
27.6M
  while ((c = c_read8(src++))) {
496
27.0M
    if (c == '%') {
497
941k
      if (!fxParseHexEscape(&src, &d))
498
63.5k
        mxURIError("invalid URI");
499
878k
      if ((d < 128) && c_read8(theSet + d))
500
450k
        length += 3;
501
427k
      else {
502
705k
        for (sequence = gxUTF8Sequences; sequence->size; sequence++) {
503
705k
          if ((d & sequence->cmask) == sequence->cval)
504
427k
            break;
505
705k
        }
506
427k
        if (!sequence->size)
507
5
          mxURIError("invalid URI");
508
427k
        size = sequence->size - 1;
509
458k
        while (size > 0) {
510
154k
          c = c_read8(src++);
511
154k
          if (c != '%')
512
10
            mxURIError("invalid URI");
513
154k
          if (!fxParseHexEscape(&src, &c))
514
123k
            mxURIError("invalid URI");
515
31.0k
          if ((c & 0xC0) != 0x80)
516
7
            mxURIError("invalid URI");
517
31.0k
          d = (d << 6) | (c & 0x3F);
518
31.0k
          size--;
519
31.0k
        }
520
303k
        d &= sequence->lmask;
521
303k
        if (sequence != gxUTF8Sequences) {
522
458
          if ((sequence[-1].lmask >= (txU4)d) || ((d >= 0xD800) & (d <= 0xDFFF)) || (d >= 0x110000))
523
9
            mxURIError("invalid URI");
524
458
        }
525
526
303k
        length += mxStringByteLength(d);
527
303k
      }
528
878k
    }
529
26.0M
    else
530
26.0M
      length += 1;
531
27.0M
  }    
532
635k
  length += 1;
533
635k
  if (length == (src - mxArgv(0)->value.string)) {
534
332k
    mxResult->value.string = mxArgv(0)->value.string;
535
332k
    mxResult->kind = mxArgv(0)->kind;
536
332k
    return;
537
332k
  }
538
302k
  mxResult->value.string = fxNewChunk(the, length);
539
302k
  mxResult->kind = XS_STRING_KIND;
540
302k
  src = mxArgv(0)->value.string;
541
302k
  dst = mxResult->value.string;
542
16.0M
  while ((c = c_read8(src++))) {
543
15.7M
    if (c == '%') {
544
606k
      fxParseHexEscape(&src, &d);
545
606k
      if ((d < 128) && c_read8(theSet + d)) {
546
302k
        *dst++ = c_read8(src - 3);
547
302k
        *dst++ = c_read8(src - 2);
548
302k
        *dst++ = c_read8(src - 1);
549
302k
      }
550
303k
      else {
551
304k
        for (sequence = gxUTF8Sequences; sequence->size; sequence++) {
552
304k
          if ((d & sequence->cmask) == sequence->cval)
553
303k
            break;
554
304k
        }
555
303k
        size = sequence->size - 1;
556
304k
        while (size > 0) {
557
853
          src++;
558
853
          fxParseHexEscape(&src, &c);
559
853
          d = (d << 6) | (c & 0x3F);
560
853
          size--;
561
853
        }
562
303k
        d &= sequence->lmask;
563
303k
        dst = mxStringByteEncode(dst, d);
564
303k
      }
565
606k
    }
566
15.1M
    else
567
15.1M
      *dst++ = c;
568
15.7M
  }
569
302k
  *dst = 0;
570
302k
}
571
572
void fxEncodeURI(txMachine* the, txString theSet)
573
7.45k
{
574
7.45k
  txString src;
575
7.45k
  txInteger length;
576
7.45k
  txInteger c;
577
7.45k
  txString dst;
578
579
7.45k
  src = fxToString(the, mxArgv(0));
580
7.45k
  length = 0;
581
93.9k
  while (((src = mxStringByteDecode(src, &c))) && (c != C_EOF)) {
582
93.6k
    if (c < 0x80) {
583
42.9k
      if (c_read8(theSet + c))
584
26.0k
        length += 1;
585
16.8k
      else
586
16.8k
        length += 3;
587
42.9k
    }
588
50.7k
    else if (c < 0x800)
589
3.59k
      length += 6;
590
47.1k
    else if ((0xD800 <= c) && (c <= 0xDFFF))
591
7.17k
      mxURIError("invalid string");
592
39.9k
    else if (c < 0x10000)
593
36.5k
      length += 9;
594
3.35k
    else
595
3.35k
      length += 12;
596
93.6k
  }
597
286
  length += 1;
598
286
  if (length == (src - mxArgv(0)->value.string)) {
599
163
    mxResult->value.string = mxArgv(0)->value.string;
600
163
    mxResult->kind = mxArgv(0)->kind;
601
163
    return;
602
163
  }
603
123
  mxResult->value.string = fxNewChunk(the, length);
604
123
  mxResult->kind = XS_STRING_KIND;
605
123
  src = mxArgv(0)->value.string;
606
123
  dst = mxResult->value.string;
607
85.5k
  while (((src = mxStringByteDecode(src, &c))) && (c != C_EOF)) {
608
85.4k
    if (c < 0x80) {
609
42.1k
      if (c_read8(theSet + c))
610
25.3k
        *dst++ = (char)c;
611
16.7k
      else {
612
16.7k
        *dst++ = '%';
613
16.7k
        dst = fxStringifyHexEscape(dst, c);
614
16.7k
      }
615
42.1k
    }
616
43.3k
    else if (c < 0x800) {
617
3.58k
      *dst++ = '%';
618
3.58k
      dst = fxStringifyHexEscape(dst, 0xC0 | (c >> 6));
619
3.58k
      *dst++ = '%';
620
3.58k
      dst = fxStringifyHexEscape(dst, 0x80 | (c & 0x3F));
621
3.58k
    }
622
39.7k
    else if (c < 0x10000) {
623
36.3k
      *dst++ = '%';
624
36.3k
      dst = fxStringifyHexEscape(dst, 0xE0 | (c >> 12));
625
36.3k
      *dst++ = '%';
626
36.3k
      dst = fxStringifyHexEscape(dst, 0x80 | ((c >> 6) & 0x3F));
627
36.3k
      *dst++ = '%';
628
36.3k
      dst = fxStringifyHexEscape(dst, 0x80 | (c & 0x3F));
629
36.3k
    }
630
3.34k
    else {
631
3.34k
      *dst++ = '%';
632
3.34k
      dst = fxStringifyHexEscape(dst, 0xF0 | (c >> 18));
633
3.34k
      *dst++ = '%';
634
3.34k
      dst = fxStringifyHexEscape(dst, 0x80 | ((c >> 12) & 0x3F));
635
3.34k
      *dst++ = '%';
636
3.34k
      dst = fxStringifyHexEscape(dst, 0x80 | ((c >> 6) & 0x3F));
637
3.34k
      *dst++ = '%';
638
3.34k
      dst = fxStringifyHexEscape(dst, 0x80 | (c & 0x3F));
639
3.34k
    }
640
85.4k
  }
641
123
  *dst = 0;
642
123
}