Coverage Report

Created: 2026-09-01 07:05

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
25.3k
{
110
25.3k
  txSlot* slot;
111
112
25.3k
  fxNewInstance(the);
113
25.3k
  mxPull(mxObjectPrototype);
114
  
115
25.3k
  mxPush(mxObjectPrototype);
116
25.3k
  fxNewFunctionInstance(the, XS_NO_ID);
117
25.3k
  mxPull(mxFunctionPrototype);
118
  
119
25.3k
  mxPush(mxObjectPrototype);
120
25.3k
  slot = fxNewObjectInstance(the);
121
25.3k
  mxPull(mxIteratorPrototype);
122
  
123
25.3k
  fxBuildHostFunction(the, mxCallback(fx_isFinite), 1, mxID(_isFinite));
124
25.3k
  mxPull(mxIsFiniteFunction);
125
25.3k
  fxBuildHostFunction(the, mxCallback(fx_isNaN), 1, mxID(_isNaN));
126
25.3k
  mxPull(mxIsNaNFunction);
127
25.3k
  fxBuildHostFunction(the, mxCallback(fx_parseFloat), 1, mxID(_parseFloat));
128
25.3k
  mxPull(mxParseFloatFunction);
129
25.3k
  fxBuildHostFunction(the, mxCallback(fx_parseInt), 2, mxID(_parseInt));
130
25.3k
  mxPull(mxParseIntFunction);
131
25.3k
  fxBuildHostFunction(the, mxCallback(fx_decodeURI), 1, mxID(_decodeURI));
132
25.3k
  mxPull(mxDecodeURIFunction);
133
25.3k
  fxBuildHostFunction(the, mxCallback(fx_decodeURIComponent), 1, mxID(_decodeURIComponent));
134
25.3k
  mxPull(mxDecodeURIComponentFunction);
135
25.3k
  fxBuildHostFunction(the, mxCallback(fx_encodeURI), 1, mxID(_encodeURI));
136
25.3k
  mxPull(mxEncodeURIFunction);
137
25.3k
  fxBuildHostFunction(the, mxCallback(fx_encodeURIComponent), 1, mxID(_encodeURIComponent));
138
25.3k
  mxPull(mxEncodeURIComponentFunction);
139
25.3k
  fxBuildHostFunction(the, mxCallback(fx_escape), 1, mxID(_escape));
140
25.3k
  mxPull(mxEscapeFunction);
141
25.3k
  fxBuildHostFunction(the, mxCallback(fx_eval), 1, mxID(_eval));
142
25.3k
  mxPull(mxEvalFunction);
143
25.3k
  fxBuildHostFunction(the, mxCallback(fx_unescape), 1, mxID(_unescape));
144
25.3k
  mxPull(mxUnescapeFunction);
145
146
25.3k
  slot = fxBuildHostFunction(the, mxCallback(fx_trace), 1, mxID(_trace));
147
25.3k
  slot = fxLastProperty(the, slot);
148
25.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_trace_center), 1, mxID(_center), XS_DONT_ENUM_FLAG);
149
25.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_trace_left), 1, mxID(_left), XS_DONT_ENUM_FLAG);
150
25.3k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_trace_right), 1, mxID(_right), XS_DONT_ENUM_FLAG);
151
25.3k
    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
25.3k
  fxNewHostFunction(the, mxCallback(fxThrowTypeError), 0, XS_NO_ID, XS_NO_ID);
161
25.3k
  mxThrowTypeErrorFunction = *the->stack;
162
25.3k
  slot = the->stack->value.reference;
163
25.3k
  slot->flag |= XS_DONT_PATCH_FLAG;
164
25.3k
  slot = slot->next;
165
126k
  while (slot) {
166
101k
    slot->flag |= XS_DONT_DELETE_FLAG | XS_DONT_SET_FLAG;
167
101k
    slot = slot->next;
168
101k
  }
169
25.3k
  mxPop();
170
25.3k
}
171
172
txSlot* fxNewGlobalInstance(txMachine* the)
173
90.4k
{
174
90.4k
  txSlot* instance;
175
90.4k
  txSlot* property;
176
90.4k
  txSize size = fxMultiplyChunkSizes(the, XS_INTRINSICS_COUNT, sizeof(txSlot*));
177
90.4k
  instance = fxNewSlot(the);
178
90.4k
  instance->flag = XS_EXOTIC_FLAG;
179
90.4k
  instance->kind = XS_INSTANCE_KIND;
180
90.4k
  instance->value.instance.garbage = C_NULL;
181
90.4k
  instance->value.instance.prototype = the->stack->value.reference;
182
90.4k
  the->stack->value.reference = instance;
183
90.4k
  the->stack->kind = XS_REFERENCE_KIND;
184
90.4k
  property = instance->next = fxNewSlot(the);
185
90.4k
  property->value.table.address = (txSlot**)fxNewChunk(the, size);
186
90.4k
  c_memset(property->value.table.address, 0, size);
187
90.4k
  property->value.table.length = XS_INTRINSICS_COUNT;
188
90.4k
  property->flag = XS_INTERNAL_FLAG;
189
90.4k
  property->ID = XS_GLOBAL_BEHAVIOR;
190
90.4k
  property->kind = XS_GLOBAL_KIND;
191
90.4k
  return instance;
192
90.4k
}
193
194
txBoolean fxGlobalDeleteProperty(txMachine* the, txSlot* instance, txID id, txIndex index) 
195
250k
{
196
250k
  txBoolean result = fxOrdinaryDeleteProperty(the, instance, id, index);
197
250k
  if ((XS_SYMBOL_ID_COUNT <= id) && (id < XS_INTRINSICS_COUNT) && result) {
198
90.1k
    txSlot* globals = instance->next;
199
90.1k
    globals->value.table.address[id] = C_NULL;
200
90.1k
  }
201
250k
  return result;
202
250k
}
203
204
txSlot* fxGlobalGetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag) 
205
161M
{
206
161M
  txSlot* result = C_NULL;
207
161M
  if ((XS_SYMBOL_ID_COUNT <= id) && (id < XS_INTRINSICS_COUNT)) {
208
28.1M
    txSlot* globals = instance->next;
209
28.1M
    result = globals->value.table.address[id];
210
28.1M
    if (!result) {
211
35.4k
      result = fxOrdinaryGetProperty(the, instance, id, index, flag);
212
35.4k
      globals->value.table.address[id] = result;
213
35.4k
    }
214
28.1M
  }
215
161M
  if (!result)
216
133M
    result = fxOrdinaryGetProperty(the, instance, id, index, flag);
217
161M
  return result;
218
161M
}
219
220
txSlot* fxGlobalSetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag) 
221
44.1M
{
222
44.1M
  txSlot* result = C_NULL;
223
44.1M
  if ((XS_SYMBOL_ID_COUNT <= id) && (id < XS_INTRINSICS_COUNT)) {
224
218k
    txSlot* globals = instance->next;
225
218k
    result = globals->value.table.address[id];
226
218k
    if (!result) {
227
1
      result = fxOrdinarySetProperty(the, instance, id, index, flag);
228
1
      globals->value.table.address[id] = result;
229
1
    }
230
218k
  }
231
44.1M
  if (!result)
232
43.9M
    result = fxOrdinarySetProperty(the, instance, id, index, flag);
233
44.1M
  return result;
234
44.1M
}
235
236
void fx_decodeURI(txMachine* the)
237
689k
{
238
689k
  if (mxArgc < 1)
239
1
    mxSyntaxError("no URI parameter");
240
689k
  fxDecodeURI(the, (txString)gxURIReservedSet);
241
689k
}
242
243
void fx_decodeURIComponent(txMachine* the)
244
66.4k
{
245
66.4k
  if (mxArgc < 1)
246
0
    mxSyntaxError("no URI Component parameter");
247
66.4k
  fxDecodeURI(the, (txString)gxURIEmptySet);
248
66.4k
}
249
250
void fx_encodeURI(txMachine* the)
251
10.4k
{
252
10.4k
  if (mxArgc < 1)
253
0
    mxSyntaxError("no URI parameter");
254
10.4k
  fxEncodeURI(the, (txString)gxURIReservedAndUnescapedSet);
255
10.4k
}
256
257
void fx_encodeURIComponent(txMachine* the)
258
83
{
259
83
  if (mxArgc < 1)
260
0
    mxSyntaxError("no URI Component parameter");
261
83
  fxEncodeURI(the, (txString)gxURIUnescapedSet);
262
83
}
263
264
void fx_escape(txMachine* the)
265
106k
{
266
106k
  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
106k
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x                    */
269
106k
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x                    */
270
106k
     0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1, /* 2x   !"#$%&'()*+,-./  */
271
106k
     1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, /* 3x  0123456789:;<=>?  */
272
106k
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4x  @ABCDEFGHIJKLMNO  */
273
106k
     1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, /* 5X  PQRSTUVWXYZ[\]^_  */
274
106k
     0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6x  `abcdefghijklmno  */
275
106k
     1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0  /* 7X  pqrstuvwxyz{|}~   */
276
106k
  };
277
106k
  txString src;
278
106k
  txInteger length;
279
106k
  txInteger c;
280
106k
  txString dst;
281
  
282
106k
  if (mxArgc < 1) {
283
276
    mxResult->value.string = mxUndefinedString.value.string;
284
276
    mxResult->kind = mxUndefinedString.kind;
285
276
    return;
286
276
  }
287
105k
  src = fxToString(the, mxArgv(0));
288
105k
  length = 0;
289
2.99M
  while (((src = mxStringByteDecode(src, &c))) && (c != C_EOF)) {
290
2.89M
    if ((c < 128) && c_read8(gxSet + (int)c))
291
1.26M
      length = fxAddChunkSizes(the, length, 1);
292
1.62M
    else if (c < 256)
293
1.50M
      length = fxAddChunkSizes(the, length, 3);
294
121k
    else if (c < 0x10000)
295
118k
      length = fxAddChunkSizes(the, length, 6);
296
3.15k
    else
297
3.15k
      length = fxAddChunkSizes(the, length, 12);
298
2.89M
  }
299
105k
  length = fxAddChunkSizes(the, length, 1);
300
105k
  if (length == (src - mxArgv(0)->value.string)) {
301
528
    mxResult->value.string = mxArgv(0)->value.string;
302
528
    mxResult->kind = mxArgv(0)->kind;
303
528
    return;
304
528
  }
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
2.99M
  while (((src = mxStringByteDecode(src, &c))) && (c != C_EOF)) {
310
2.89M
    if ((c < 128) && c_read8(gxSet + (int)c))
311
1.26M
      *dst++ = (char)c;
312
1.62M
    else if (c < 256) {
313
1.50M
      *dst++ = '%';
314
1.50M
      dst = fxStringifyHexEscape(dst, c);
315
1.50M
    }
316
121k
    else {
317
121k
      *dst++ = '%'; 
318
121k
      *dst++ = 'u'; 
319
121k
      dst = fxStringifyUnicodeEscape(dst, c, '%');
320
121k
    }
321
2.89M
  }
322
105k
  *dst = 0;
323
105k
}
324
325
void fx_eval(txMachine* the)
326
5.31k
{
327
5.31k
  txStringStream aStream;
328
5.31k
  txSlot* realm;
329
5.31k
  txSlot* module = mxFunctionInstanceHome(mxFunction->value.reference)->value.home.module;
330
5.31k
  if (!module) module = mxProgram.value.reference;
331
  
332
5.31k
  realm = mxModuleInstanceInternal(module)->value.module.realm;
333
5.31k
  if (mxArgc < 1)
334
1
    return;
335
5.31k
  if (!mxIsStringPrimitive(mxArgv(0))) {
336
5.31k
    *mxResult = *mxArgv(0);
337
5.31k
    return;
338
5.31k
  }
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
11
{
358
//@@#ifdef mxDebug
359
11
  int i;
360
22
  for (i = 0; i < mxArgc; i++) {
361
11
    fxToString(the, mxArgv(i));
362
11
    fxReport(the, "%s", mxArgv(i)->value.string);
363
11
  }
364
//#endif
365
11
}
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
756k
{
486
756k
  txString src;
487
756k
  txInteger length;
488
756k
  txInteger c, d;
489
756k
  const txUTF8Sequence *sequence;
490
756k
  txInteger size;
491
756k
  txString dst;
492
  
493
756k
  src = fxToString(the, mxArgv(0));
494
756k
  length = 0;
495
27.4M
  while ((c = c_read8(src++))) {
496
26.8M
    if (c == '%') {
497
910k
      if (!fxParseHexEscape(&src, &d))
498
63.5k
        mxURIError("invalid URI");
499
847k
      if ((d < 128) && c_read8(theSet + d))
500
450k
        length += 3;
501
396k
      else {
502
550k
        for (sequence = gxUTF8Sequences; sequence->size; sequence++) {
503
550k
          if ((d & sequence->cmask) == sequence->cval)
504
396k
            break;
505
550k
        }
506
396k
        if (!sequence->size)
507
5
          mxURIError("invalid URI");
508
396k
        size = sequence->size - 1;
509
427k
        while (size > 0) {
510
124k
          c = c_read8(src++);
511
124k
          if (c != '%')
512
17
            mxURIError("invalid URI");
513
123k
          if (!fxParseHexEscape(&src, &c))
514
92.4k
            mxURIError("invalid URI");
515
31.5k
          if ((c & 0xC0) != 0x80)
516
9
            mxURIError("invalid URI");
517
31.5k
          d = (d << 6) | (c & 0x3F);
518
31.5k
          size--;
519
31.5k
        }
520
303k
        d &= sequence->lmask;
521
303k
        if (sequence != gxUTF8Sequences) {
522
647
          if ((sequence[-1].lmask >= (txU4)d) || ((d >= 0xD800) & (d <= 0xDFFF)) || (d >= 0x110000))
523
142
            mxURIError("invalid URI");
524
647
        }
525
526
303k
        length += mxStringByteLength(d);
527
303k
      }
528
847k
    }
529
25.9M
    else
530
25.9M
      length += 1;
531
26.8M
  }    
532
599k
  length += 1;
533
599k
  if (length == (src - mxArgv(0)->value.string)) {
534
296k
    mxResult->value.string = mxArgv(0)->value.string;
535
296k
    mxResult->kind = mxArgv(0)->kind;
536
296k
    return;
537
296k
  }
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
1.01k
          src++;
558
1.01k
          fxParseHexEscape(&src, &c);
559
1.01k
          d = (d << 6) | (c & 0x3F);
560
1.01k
          size--;
561
1.01k
        }
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
10.4k
{
574
10.4k
  txString src;
575
10.4k
  txInteger length;
576
10.4k
  txInteger c;
577
10.4k
  txString dst;
578
579
10.4k
  src = fxToString(the, mxArgv(0));
580
10.4k
  length = 0;
581
82.4k
  while (((src = mxStringByteDecode(src, &c))) && (c != C_EOF)) {
582
82.1k
    if (c < 0x80) {
583
37.4k
      if (c_read8(theSet + c))
584
21.4k
        length += 1;
585
15.9k
      else
586
15.9k
        length += 3;
587
37.4k
    }
588
44.7k
    else if (c < 0x800)
589
2.86k
      length += 6;
590
41.8k
    else if ((0xD800 <= c) && (c <= 0xDFFF))
591
10.2k
      mxURIError("invalid string");
592
31.6k
    else if (c < 0x10000)
593
29.1k
      length += 9;
594
2.49k
    else
595
2.49k
      length += 12;
596
82.1k
  }
597
244
  length += 1;
598
244
  if (length == (src - mxArgv(0)->value.string)) {
599
134
    mxResult->value.string = mxArgv(0)->value.string;
600
134
    mxResult->kind = mxArgv(0)->kind;
601
134
    return;
602
134
  }
603
110
  mxResult->value.string = fxNewChunk(the, length);
604
110
  mxResult->kind = XS_STRING_KIND;
605
110
  src = mxArgv(0)->value.string;
606
110
  dst = mxResult->value.string;
607
71.4k
  while (((src = mxStringByteDecode(src, &c))) && (c != C_EOF)) {
608
71.3k
    if (c < 0x80) {
609
36.9k
      if (c_read8(theSet + c))
610
21.0k
        *dst++ = (char)c;
611
15.9k
      else {
612
15.9k
        *dst++ = '%';
613
15.9k
        dst = fxStringifyHexEscape(dst, c);
614
15.9k
      }
615
36.9k
    }
616
34.3k
    else if (c < 0x800) {
617
2.86k
      *dst++ = '%';
618
2.86k
      dst = fxStringifyHexEscape(dst, 0xC0 | (c >> 6));
619
2.86k
      *dst++ = '%';
620
2.86k
      dst = fxStringifyHexEscape(dst, 0x80 | (c & 0x3F));
621
2.86k
    }
622
31.5k
    else if (c < 0x10000) {
623
29.0k
      *dst++ = '%';
624
29.0k
      dst = fxStringifyHexEscape(dst, 0xE0 | (c >> 12));
625
29.0k
      *dst++ = '%';
626
29.0k
      dst = fxStringifyHexEscape(dst, 0x80 | ((c >> 6) & 0x3F));
627
29.0k
      *dst++ = '%';
628
29.0k
      dst = fxStringifyHexEscape(dst, 0x80 | (c & 0x3F));
629
29.0k
    }
630
2.49k
    else {
631
2.49k
      *dst++ = '%';
632
2.49k
      dst = fxStringifyHexEscape(dst, 0xF0 | (c >> 18));
633
2.49k
      *dst++ = '%';
634
2.49k
      dst = fxStringifyHexEscape(dst, 0x80 | ((c >> 12) & 0x3F));
635
2.49k
      *dst++ = '%';
636
2.49k
      dst = fxStringifyHexEscape(dst, 0x80 | ((c >> 6) & 0x3F));
637
2.49k
      *dst++ = '%';
638
2.49k
      dst = fxStringifyHexEscape(dst, 0x80 | (c & 0x3F));
639
2.49k
    }
640
71.3k
  }
641
110
  *dst = 0;
642
110
}