@agoric/xsnap 0.14.3-u14.0 → 0.14.3-u16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/README.md +3 -3
  2. package/api.js +4 -2
  3. package/build.env +1 -1
  4. package/moddable/modules/data/base64/base64.js +28 -0
  5. package/moddable/modules/data/base64/manifest.json +11 -0
  6. package/moddable/modules/data/base64/modBase64.c +188 -0
  7. package/moddable/modules/data/binaryMessage/BinaryMessage.js +106 -0
  8. package/moddable/modules/data/crc/crc.c +205 -0
  9. package/moddable/modules/data/crc/crc.js +36 -0
  10. package/moddable/modules/data/crc/manifest.json +8 -0
  11. package/moddable/modules/data/hex/hex.js +28 -0
  12. package/moddable/modules/data/hex/manifest.json +11 -0
  13. package/moddable/modules/data/hex/modHex.c +139 -0
  14. package/moddable/modules/data/logical/logical.js +32 -0
  15. package/moddable/modules/data/logical/modLogical.c +98 -0
  16. package/moddable/modules/data/qrcode/manifest.json +9 -0
  17. package/moddable/modules/data/qrcode/qrcode.c +93 -0
  18. package/moddable/modules/data/qrcode/qrcode.js +23 -0
  19. package/moddable/modules/data/qrcode/qrcodegen.c +1025 -0
  20. package/moddable/modules/data/qrcode/qrcodegen.h +267 -0
  21. package/moddable/modules/data/text/decoder/manifest.json +8 -0
  22. package/moddable/modules/data/text/decoder/textdecoder.c +480 -0
  23. package/moddable/modules/data/text/decoder/textdecoder.js +27 -0
  24. package/moddable/modules/data/text/encoder/manifest.json +8 -0
  25. package/moddable/modules/data/text/encoder/textencoder.c +232 -0
  26. package/moddable/modules/data/text/encoder/textencoder.js +24 -0
  27. package/moddable/modules/data/tinyint/tinyint.c +150 -0
  28. package/moddable/modules/data/tinyint/tinyint.js +53 -0
  29. package/moddable/modules/data/url/manifest.json +17 -0
  30. package/moddable/modules/data/url/url.c +1959 -0
  31. package/moddable/modules/data/url/url.js +210 -0
  32. package/moddable/modules/data/wavreader/manifest.json +8 -0
  33. package/moddable/modules/data/wavreader/wavreader.js +128 -0
  34. package/moddable/modules/data/zlib/deflate.c +161 -0
  35. package/moddable/modules/data/zlib/deflate.js +63 -0
  36. package/moddable/modules/data/zlib/inflate.c +145 -0
  37. package/moddable/modules/data/zlib/inflate.js +66 -0
  38. package/moddable/modules/data/zlib/manifest_deflate.json +9 -0
  39. package/moddable/modules/data/zlib/manifest_inflate.json +9 -0
  40. package/moddable/modules/data/zlib/miniz.c +4924 -0
  41. package/moddable/xs/includes/xs.d.ts +73 -0
  42. package/moddable/xs/includes/xs.h +1533 -0
  43. package/moddable/xs/includes/xsmc.h +206 -0
  44. package/moddable/xs/makefiles/lin/makefile +33 -0
  45. package/moddable/xs/makefiles/lin/xsc.mk +118 -0
  46. package/moddable/xs/makefiles/lin/xsid.mk +90 -0
  47. package/moddable/xs/makefiles/lin/xsl.mk +168 -0
  48. package/moddable/xs/makefiles/lin/xst.mk +201 -0
  49. package/moddable/xs/makefiles/mac/makefile +33 -0
  50. package/moddable/xs/makefiles/mac/xsc.mk +130 -0
  51. package/moddable/xs/makefiles/mac/xsid.mk +102 -0
  52. package/moddable/xs/makefiles/mac/xsl.mk +177 -0
  53. package/moddable/xs/makefiles/mac/xst.mk +203 -0
  54. package/moddable/xs/makefiles/mac/xst_no_asan.txt +52 -0
  55. package/moddable/xs/makefiles/win/build.bat +26 -0
  56. package/moddable/xs/makefiles/win/xsc.mak +142 -0
  57. package/moddable/xs/makefiles/win/xsid.mak +113 -0
  58. package/moddable/xs/makefiles/win/xsl.mak +186 -0
  59. package/moddable/xs/makefiles/win/xst.mak +195 -0
  60. package/moddable/xs/platforms/lin_xs.h +99 -0
  61. package/moddable/xs/platforms/mac_xs.h +97 -0
  62. package/moddable/xs/platforms/wasm_xs.h +79 -0
  63. package/moddable/xs/platforms/win_xs.h +104 -0
  64. package/moddable/xs/platforms/xsHost.h +63 -0
  65. package/moddable/xs/platforms/xsPlatform.h +618 -0
  66. package/moddable/xs/sources/xsAPI.c +2555 -0
  67. package/moddable/xs/sources/xsAll.c +294 -0
  68. package/moddable/xs/sources/xsAll.h +2741 -0
  69. package/moddable/xs/sources/xsArguments.c +222 -0
  70. package/moddable/xs/sources/xsArray.c +2657 -0
  71. package/moddable/xs/sources/xsAtomics.c +844 -0
  72. package/moddable/xs/sources/xsBigInt.c +1859 -0
  73. package/moddable/xs/sources/xsBoolean.c +109 -0
  74. package/moddable/xs/sources/xsCode.c +4493 -0
  75. package/moddable/xs/sources/xsCommon.c +1710 -0
  76. package/moddable/xs/sources/xsCommon.h +1142 -0
  77. package/moddable/xs/sources/xsDataView.c +2890 -0
  78. package/moddable/xs/sources/xsDate.c +1541 -0
  79. package/moddable/xs/sources/xsDebug.c +2710 -0
  80. package/moddable/xs/sources/xsDefaults.c +134 -0
  81. package/moddable/xs/sources/xsError.c +353 -0
  82. package/moddable/xs/sources/xsFunction.c +776 -0
  83. package/moddable/xs/sources/xsGenerator.c +865 -0
  84. package/moddable/xs/sources/xsGlobal.c +839 -0
  85. package/moddable/xs/sources/xsJSON.c +1091 -0
  86. package/moddable/xs/sources/xsLexical.c +1969 -0
  87. package/moddable/xs/sources/xsLockdown.c +933 -0
  88. package/moddable/xs/sources/xsMapSet.c +1649 -0
  89. package/moddable/xs/sources/xsMarshall.c +1020 -0
  90. package/moddable/xs/sources/xsMath.c +624 -0
  91. package/moddable/xs/sources/xsMemory.c +1941 -0
  92. package/moddable/xs/sources/xsModule.c +3101 -0
  93. package/moddable/xs/sources/xsNumber.c +560 -0
  94. package/moddable/xs/sources/xsObject.c +1102 -0
  95. package/moddable/xs/sources/xsPlatforms.c +480 -0
  96. package/moddable/xs/sources/xsProfile.c +577 -0
  97. package/moddable/xs/sources/xsPromise.c +1199 -0
  98. package/moddable/xs/sources/xsProperty.c +636 -0
  99. package/moddable/xs/sources/xsProxy.c +1014 -0
  100. package/moddable/xs/sources/xsRegExp.c +1168 -0
  101. package/moddable/xs/sources/xsRun.c +4889 -0
  102. package/moddable/xs/sources/xsScope.c +1293 -0
  103. package/moddable/xs/sources/xsScript.c +288 -0
  104. package/moddable/xs/sources/xsScript.h +1186 -0
  105. package/moddable/xs/sources/xsSnapshot.c +2161 -0
  106. package/moddable/xs/sources/xsSnapshot.h +51 -0
  107. package/moddable/xs/sources/xsSourceMap.c +218 -0
  108. package/moddable/xs/sources/xsString.c +3332 -0
  109. package/moddable/xs/sources/xsSymbol.c +503 -0
  110. package/moddable/xs/sources/xsSyntaxical.c +4193 -0
  111. package/moddable/xs/sources/xsTree.c +1893 -0
  112. package/moddable/xs/sources/xsType.c +1488 -0
  113. package/moddable/xs/sources/xsdtoa.c +6672 -0
  114. package/moddable/xs/sources/xsmc.c +340 -0
  115. package/moddable/xs/sources/xsre.c +7578 -0
  116. package/package.json +37 -20
  117. package/scripts/get_xsnap_version.sh +14 -0
  118. package/scripts/test-package.sh +21 -0
  119. package/src/avaAssertXS.js +6 -2
  120. package/src/avaHandler.cjs +2 -5
  121. package/src/avaXS.js +7 -8
  122. package/src/build.js +161 -28
  123. package/src/replay.js +0 -3
  124. package/src/xsnap.js +105 -91
  125. package/src/xsrepl.js +2 -3
  126. package/xsnap-native/xsnap/makefiles/lin/makefile +10 -0
  127. package/xsnap-native/xsnap/makefiles/lin/xsnap-worker.mk +156 -0
  128. package/xsnap-native/xsnap/makefiles/lin/xsnap.mk +144 -0
  129. package/xsnap-native/xsnap/makefiles/mac/makefile +10 -0
  130. package/xsnap-native/xsnap/makefiles/mac/xsnap-worker.mk +165 -0
  131. package/xsnap-native/xsnap/makefiles/mac/xsnap.mk +153 -0
  132. package/xsnap-native/xsnap/sources/xsnap-worker.c +1008 -0
  133. package/xsnap-native/xsnap/sources/xsnap.c +717 -0
  134. package/xsnap-native/xsnap/sources/xsnap.h +142 -0
  135. package/xsnap-native/xsnap/sources/xsnapPlatform.c +1501 -0
  136. package/xsnap-native/xsnap/sources/xsnapPlatform.h +105 -0
  137. package/CHANGELOG.md +0 -654
@@ -0,0 +1,1959 @@
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 "xsAll.h"
22
+ #ifdef kPocoRotation
23
+ #include "mc.xs.h"
24
+ #define MODDABLE_MODULE 1
25
+ #else
26
+ #define xsID_scheme fxID(the, "scheme")
27
+ #define xsID_username fxID(the, "username")
28
+ #define xsID_password fxID(the, "password")
29
+ #define xsID_host fxID(the, "host")
30
+ #define xsID_port fxID(the, "port")
31
+ #define xsID_path fxID(the, "path")
32
+ #define xsID_query fxID(the, "query")
33
+ #define xsID_fragment fxID(the, "fragment")
34
+ extern void fx_parseURL(txMachine* the);
35
+ extern void fx_serializeURL(txMachine* the);
36
+ extern void fx_parseQuery(txMachine* the);
37
+ extern void fx_serializeQuery(txMachine* the);
38
+ #endif
39
+
40
+
41
+ static void fx_parseURLCopyPart(txMachine* the, txSlot* src, txSlot* dst, txID id);
42
+ static void fx_parseURLCopyPath(txMachine* the, txSlot* src, txSlot* dst);
43
+ static txInteger fx_parseURLDecode(txMachine* the, txStringStream* stream);
44
+ static void fx_parseURLEncode(txMachine* the, txInteger c, txStringStream* dst);
45
+ static void fx_parseURLEmptyPart(txMachine* the, txSlot* target, txID id);
46
+ static txBoolean fx_parseURLHasOpaquePath(txMachine* the, txSlot* parts);
47
+ static txBoolean fx_parseURLHost(txMachine* the, txStringStream* src, txInteger from, txInteger to, txStringStream* dst, txBoolean special);
48
+ static txBoolean fx_parseURLHostIPv4(txMachine* the, txStringStream* src, txInteger from, txInteger to, txStringStream* dst);
49
+ static txBoolean fx_parseURLHostIPv6(txMachine* the, txStringStream* src, txInteger from, txInteger to, txStringStream* dst);
50
+ static txBoolean fx_parseURLHostNotSpecial(txMachine* the, txStringStream* src, txInteger from, txInteger to, txStringStream* dst);
51
+ static txBoolean fx_parseURLHostSpecial(txMachine* the, txStringStream* src, txInteger from, txInteger to, txStringStream* dst);
52
+ static void fx_parseURLNullPart(txMachine* the, txSlot* target, txID id);
53
+ static txBoolean fx_parseURLIsPartEmpty(txMachine* the, txSlot* parts, txID id);
54
+ static txBoolean fx_parseURLIsWindowsDriveLetter(txMachine* the, txString string, txBoolean startsWith);
55
+ static void fx_parseURLPercentEncode(txMachine* the, txInteger c, txStringStream* dst, const char* set);
56
+ static void fx_parseURLPushPath(txMachine* the, txSlot* path, txStringStream* dst, txBoolean flag);
57
+ static void fx_parseURLSetPart(txMachine* the, txSlot* target, txID id, txIndex index, txStringStream* dst);
58
+ static void fx_parseURLShortenPath(txMachine* the, txSlot* path);
59
+ static txInteger fx_parseURLSpecialScheme(txMachine* the, txString scheme);
60
+ static void fx_parseQueryPlus(txMachine* the, txSlot* string, txInteger from, txInteger to);
61
+ static void fx_serializeQueryPlus(txMachine* the, txString theSet);
62
+
63
+ static const char ICACHE_RODATA_ATTR gxControlSet[128] = {
64
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
65
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0x */
66
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 1x */
67
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2x !"#$%&'()*+,-./ */
68
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
69
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4x @ABCDEFGHIJKLMNO */
70
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5X PQRSTUVWXYZ[\]^_ */
71
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6x `abcdefghijklmno */
72
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 /* 7X pqrstuvwxyz{|}~ */
73
+ };
74
+
75
+ static const char ICACHE_RODATA_ATTR gxUserInfoSet[128] = {
76
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
77
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0x */
78
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 1x */
79
+ 1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1, /* 2x !"#$%&'()*+,-./ */
80
+ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1, /* 3x 0123456789:;<=>? */
81
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4x @ABCDEFGHIJKLMNO */
82
+ 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0, /* 5X PQRSTUVWXYZ[\]^_ */
83
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6x `abcdefghijklmno */
84
+ 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,1 /* 7X pqrstuvwxyz{|}~ */
85
+ };
86
+
87
+ static const char ICACHE_RODATA_ATTR gxNotSpecialHostSet[128] = {
88
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
89
+ 1,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0, /* 0x */
90
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x */
91
+ 1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1, /* 2x !"#$%&'()*+,-./ */
92
+ 0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,1, /* 3x 0123456789:;<=>? */
93
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4x @ABCDEFGHIJKLMNO */
94
+ 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0, /* 5X PQRSTUVWXYZ[\]^_ */
95
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6x `abcdefghijklmno */
96
+ 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0 /* 7X pqrstuvwxyz{|}~ */
97
+ };
98
+
99
+ static const char ICACHE_RODATA_ATTR gxSpecialHostSet[128] = {
100
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
101
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0x */
102
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 1x */
103
+ 1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1, /* 2x !"#$%&'()*+,-./ */
104
+ 0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,1, /* 3x 0123456789:;<=>? */
105
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4x @ABCDEFGHIJKLMNO */
106
+ 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0, /* 5X PQRSTUVWXYZ[\]^_ */
107
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6x `abcdefghijklmno */
108
+ 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1 /* 7X pqrstuvwxyz{|}~ */
109
+ };
110
+
111
+ static const char ICACHE_RODATA_ATTR gxPathSet[128] = {
112
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
113
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0x */
114
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 1x */
115
+ 1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 2x !"#$%&'()*+,-./ */
116
+ 0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1, /* 3x 0123456789:;<=>? */
117
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4x @ABCDEFGHIJKLMNO */
118
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5X PQRSTUVWXYZ[\]^_ */
119
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6x `abcdefghijklmno */
120
+ 0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1 /* 7X pqrstuvwxyz{|}~ */
121
+ };
122
+
123
+ static const char ICACHE_RODATA_ATTR gxQuerySet[128] = {
124
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
125
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0x */
126
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 1x */
127
+ 1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 2x !"#$%&'()*+,-./ */
128
+ 0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, /* 3x 0123456789:;<=>? */
129
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4x @ABCDEFGHIJKLMNO */
130
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5X PQRSTUVWXYZ[\]^_ */
131
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6x `abcdefghijklmno */
132
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 /* 7X pqrstuvwxyz{|}~ */
133
+ };
134
+ static const char ICACHE_RODATA_ATTR gxSpecialQuerySet[128] = {
135
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
136
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0x */
137
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 1x */
138
+ 1,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0, /* 2x !"#$%&'()*+,-./ */
139
+ 0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, /* 3x 0123456789:;<=>? */
140
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4x @ABCDEFGHIJKLMNO */
141
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5X PQRSTUVWXYZ[\]^_ */
142
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6x `abcdefghijklmno */
143
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 /* 7X pqrstuvwxyz{|}~ */
144
+ };
145
+
146
+ static const char ICACHE_RODATA_ATTR gxFragmentSet[128] = {
147
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
148
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0x */
149
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 1x */
150
+ 1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2x !"#$%&'()*+,-./ */
151
+ 0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, /* 3x 0123456789:;<=>? */
152
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4x @ABCDEFGHIJKLMNO */
153
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5X PQRSTUVWXYZ[\]^_ */
154
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6x `abcdefghijklmno */
155
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 /* 7X pqrstuvwxyz{|}~ */
156
+ };
157
+
158
+ static const char ICACHE_RODATA_ATTR gxFormSet[128] = {
159
+ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
160
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x */
161
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x */
162
+ 0,0,1,0,0,0,0,0,0,0,1,0,0,1,1,0, /* 2x !"#$%&'()*+,-./ */
163
+ 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
164
+ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4x @ABCDEFGHIJKLMNO */
165
+ 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, /* 5X PQRSTUVWXYZ[\]^_ */
166
+ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6x `abcdefghijklmno */
167
+ 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, /* 7X pqrstuvwxyz{|}~ */
168
+ };
169
+
170
+ static const char gxHexLower[] ICACHE_FLASH_ATTR = "0123456789abcdef";
171
+
172
+ #define mx_parseURLBufferSize 64
173
+ #define mx_parseURLSpecialSchemeCount 6
174
+ static const txString gx_parseURLSpecialSchemeNames[mx_parseURLSpecialSchemeCount] = {
175
+ "file",
176
+ "ftp",
177
+ "http",
178
+ "https",
179
+ "ws",
180
+ "wss",
181
+ };
182
+ static const txInteger gx_parseURLSpecialSchemePorts[mx_parseURLSpecialSchemeCount] = {
183
+ 0,
184
+ 21,
185
+ 80,
186
+ 443,
187
+ 80,
188
+ 443,
189
+ };
190
+
191
+ enum {
192
+ SCHEME_STATE = 1,
193
+ USERNAME_STATE,
194
+ PASSWORD_STATE,
195
+ HOST_PORT_STATE,
196
+ HOST_STATE,
197
+ PORT_STATE,
198
+ PATH_STATE,
199
+ QUERY_STATE,
200
+ FRAGMENT_STATE,
201
+ ORIGIN_STATE,
202
+ };
203
+
204
+ void fx_parseURL(txMachine* the)
205
+ {
206
+ txStringStream _src;
207
+ txStringStream* src = &_src;
208
+ txStringStream _dst;
209
+ txStringStream* dst = &_dst;
210
+
211
+ txInteger override = 0;
212
+ txInteger overrideSchemeIndex = -1;
213
+ txBoolean overrideSpecial = 0;
214
+
215
+ txSlot* base = C_NULL;
216
+ txInteger baseSchemeIndex = -1;
217
+ txBoolean baseSpecial = 0;
218
+
219
+ txSlot* result = C_NULL;
220
+ txInteger schemeIndex = -1;
221
+ txBoolean special = 0;
222
+
223
+ txInteger atOffset = -1;
224
+ txInteger colonOffset = -1;
225
+ txInteger hostOffset = -1;
226
+ txSize tmp;
227
+ txBoolean insideBracket = 0;
228
+
229
+ txIndex length;
230
+ txInteger c;
231
+ txNumber port;
232
+
233
+ fxVars(the, 3);
234
+ src->slot = mxArgv(0);
235
+ src->offset = 0;
236
+ src->size = mxStringLength(fxToString(the, mxArgv(0)));
237
+ mxVarv(0)->value.string = fxNewChunk(the, mx_parseURLBufferSize);
238
+ mxVarv(0)->kind = XS_STRING_KIND;
239
+ dst->slot = mxVarv(0);
240
+ dst->slot->value.string[0] = 0;
241
+ dst->offset = 0;
242
+ dst->size = mx_parseURLBufferSize;
243
+
244
+ if (mxArgc > 2) {
245
+ *mxResult = *mxArgv(1);
246
+ result = mxResult;
247
+
248
+ override = fxToInteger(the, mxArgv(2));
249
+ mxPushSlot(result);
250
+ mxGetID(xsID_scheme);
251
+ overrideSchemeIndex = fx_parseURLSpecialScheme(the, the->stack->value.string);
252
+ mxPop();
253
+ overrideSpecial = overrideSchemeIndex >= 0;
254
+
255
+ if (override == SCHEME_STATE) {
256
+ goto XS_URL_SCHEME_START;
257
+ }
258
+ schemeIndex = overrideSchemeIndex;
259
+ special = overrideSpecial;
260
+ if (override == USERNAME_STATE) {
261
+ if ((schemeIndex == 0) || fx_parseURLIsPartEmpty(the, result, xsID_host))
262
+ goto XS_URL_END;
263
+ goto XS_URL_USERNAME;
264
+ }
265
+ if (override == PASSWORD_STATE) {
266
+ if ((schemeIndex == 0) || fx_parseURLIsPartEmpty(the, result, xsID_host))
267
+ goto XS_URL_END;
268
+ goto XS_URL_PASSWORD;
269
+ }
270
+ if (override == HOST_PORT_STATE) {
271
+ if (fx_parseURLHasOpaquePath(the, result))
272
+ goto XS_URL_END;
273
+ hostOffset = 0;
274
+ if (schemeIndex == 0)
275
+ goto XS_URL_FILE_HOST;
276
+ goto XS_URL_HOST;
277
+ }
278
+ if (override == HOST_STATE) {
279
+ if (fx_parseURLHasOpaquePath(the, result))
280
+ goto XS_URL_END;
281
+ hostOffset = 0;
282
+ if (schemeIndex == 0)
283
+ goto XS_URL_FILE_HOST;
284
+ goto XS_URL_HOST;
285
+ }
286
+ if (override == PORT_STATE) {
287
+ if ((schemeIndex == 0) || fx_parseURLIsPartEmpty(the, result, xsID_host))
288
+ goto XS_URL_END;
289
+ goto XS_URL_PORT;
290
+ }
291
+ if (override == PATH_STATE) {
292
+ if (fx_parseURLHasOpaquePath(the, result))
293
+ goto XS_URL_END;
294
+ mxPushInteger(0);
295
+ mxPushSlot(result);
296
+ mxSetID(mxID(_length));
297
+ mxPop();
298
+ c = fx_parseURLDecode(the, src);
299
+ if ((c != '/') && (!special || (c != '\\')))
300
+ src->offset = 0;
301
+ goto XS_URL_PATH;
302
+ }
303
+ if (override == QUERY_STATE) {
304
+ if (src->size == 0) {
305
+ fx_parseURLNullPart(the, result, xsID_query);
306
+ goto XS_URL_END;
307
+ }
308
+ fx_parseURLEmptyPart(the, result, xsID_query);
309
+ c = fx_parseURLDecode(the, src);
310
+ if (c != '?')
311
+ src->offset = 0;
312
+ goto XS_URL_QUERY;
313
+ }
314
+ if (override == FRAGMENT_STATE) {
315
+ if (src->size == 0) {
316
+ fx_parseURLNullPart(the, result, xsID_fragment);
317
+ goto XS_URL_END;
318
+ }
319
+ fx_parseURLEmptyPart(the, result, xsID_fragment);
320
+ c = fx_parseURLDecode(the, src);
321
+ if (c != '#')
322
+ src->offset = 0;
323
+ goto XS_URL_FRAGMENT;
324
+ }
325
+ goto XS_URL_ERROR;
326
+ }
327
+ else {
328
+ fxNewArray(the, 0);
329
+ mxPullSlot(mxResult);
330
+ result = mxResult;
331
+
332
+ fx_parseURLEmptyPart(the, result, xsID_username);
333
+ fx_parseURLEmptyPart(the, result, xsID_password);
334
+ fx_parseURLNullPart(the, result, xsID_host);
335
+ fx_parseURLEmptyPart(the, result, xsID_port);
336
+ fx_parseURLNullPart(the, result, xsID_query);
337
+ fx_parseURLNullPart(the, result, xsID_fragment);
338
+
339
+ if ((mxArgc > 1) && mxIsReference(mxArgv(1))) {
340
+ base = mxArgv(1);
341
+ mxPushSlot(base);
342
+ mxGetID(xsID_scheme);
343
+ baseSchemeIndex = fx_parseURLSpecialScheme(the, the->stack->value.string);
344
+ mxPop();
345
+ baseSpecial = baseSchemeIndex >= 0;
346
+ }
347
+ }
348
+
349
+ for (;;) {
350
+ c = fx_parseURLDecode(the, src);
351
+ if (c == C_EOF)
352
+ break;
353
+ if ((c > 0x20) && (c != 0x7F)) {
354
+ fx_parseURLEncode(the, c, dst);
355
+ break;
356
+ }
357
+ }
358
+ if (c != C_EOF) {
359
+ tmp = -1;
360
+ for (;;) {
361
+ c = fx_parseURLDecode(the, src);
362
+ if (c == C_EOF)
363
+ break;
364
+ if ((c > 0x20) && (c != 0x7F))
365
+ tmp = -1;
366
+ else if (tmp < 0)
367
+ tmp = dst->offset;
368
+ if ((c != 9) && (c != 10) && (c != 13))
369
+ fx_parseURLEncode(the, c, dst);
370
+ }
371
+ if (tmp >= 0) {
372
+ dst->offset = tmp;
373
+ dst->slot->value.string[tmp] = 0;
374
+ }
375
+ }
376
+ src->slot = dst->slot;
377
+ src->offset = 0;
378
+ src->size = dst->size;
379
+ mxArgv(0)->value.string = fxNewChunk(the, mx_parseURLBufferSize);
380
+ mxArgv(0)->kind = XS_STRING_KIND;
381
+ dst->slot = mxArgv(0);
382
+ dst->slot->value.string[0] = 0;
383
+ dst->offset = 0;
384
+ dst->size = mx_parseURLBufferSize;
385
+
386
+
387
+ XS_URL_SCHEME_START:
388
+ c = fx_parseURLDecode(the, src);
389
+ if (('A' <= c) && (c <= 'Z')) {
390
+ fx_parseURLEncode(the, c - ('A' - 'a'), dst);
391
+ goto XS_URL_SCHEME;
392
+ }
393
+ if (('a' <= c) && (c <= 'z')) {
394
+ fx_parseURLEncode(the, c, dst);
395
+ goto XS_URL_SCHEME;
396
+ }
397
+ if (override)
398
+ goto XS_URL_ERROR;
399
+ src->offset = 0;
400
+ dst->offset = 0;
401
+ goto XS_URL_NO_SCHEME;
402
+
403
+ XS_URL_SCHEME:
404
+ c = fx_parseURLDecode(the, src);
405
+ if (('A' <= c) && (c <= 'Z')) {
406
+ fx_parseURLEncode(the, c - ('A' - 'a'), dst);
407
+ goto XS_URL_SCHEME;
408
+ }
409
+ if ((('a' <= c) && (c <= 'z')) || (('0' <= c) && (c <= '9')) || (c == '+') || (c == '-') || (c == '.')) {
410
+ fx_parseURLEncode(the, c, dst);
411
+ goto XS_URL_SCHEME;
412
+ }
413
+ if ((c == ':') || (override && (c == C_EOF))) {
414
+ schemeIndex = fx_parseURLSpecialScheme(the, dst->slot->value.string);
415
+ special = schemeIndex >= 0;
416
+ if (override) {
417
+ if (overrideSpecial != special)
418
+ goto XS_URL_END;
419
+ if (schemeIndex == 0) {
420
+ if (!fx_parseURLIsPartEmpty(the, result, xsID_username))
421
+ goto XS_URL_END;
422
+ if (!fx_parseURLIsPartEmpty(the, result, xsID_password))
423
+ goto XS_URL_END;
424
+ if (!fx_parseURLIsPartEmpty(the, result, xsID_port))
425
+ goto XS_URL_END;
426
+ }
427
+ if ((overrideSchemeIndex == 0) && (schemeIndex != 0)) {
428
+ if (fx_parseURLIsPartEmpty(the, result, xsID_host))
429
+ goto XS_URL_END;
430
+ }
431
+ }
432
+ fx_parseURLSetPart(the, result, xsID_scheme, 0, dst);
433
+ if (override) {
434
+ if (special) {
435
+ mxPushSlot(result);
436
+ mxGetID(xsID_port);
437
+ port = (the->stack->value.string[0]) ? fxToInteger(the, the->stack) : 0;
438
+ mxPop();
439
+ if (port == gx_parseURLSpecialSchemePorts[schemeIndex])
440
+ fx_parseURLEmptyPart(the, result, xsID_port);
441
+ }
442
+ goto XS_URL_END;
443
+ }
444
+ if (schemeIndex == 0)
445
+ goto XS_URL_FILE_START;
446
+ if (special) {
447
+ if (base && (baseSchemeIndex == schemeIndex))
448
+ goto XS_URL_RELATIVE;
449
+ goto XS_URL_AUTHORITY_START;
450
+ }
451
+
452
+ tmp = src->offset;
453
+ c = fx_parseURLDecode(the, src);
454
+ if (c == '/') {
455
+ tmp = src->offset;
456
+ c = fx_parseURLDecode(the, src);
457
+ if (c == '/')
458
+ goto XS_URL_AUTHORITY_START;
459
+ src->offset = tmp;
460
+ c = '/';
461
+ goto XS_URL_PATH;
462
+ }
463
+ src->offset = tmp;
464
+ goto XS_URL_OPAQUE_PATH;
465
+ }
466
+ if (override)
467
+ goto XS_URL_ERROR;
468
+ src->offset = 0;
469
+ dst->offset = 0;
470
+
471
+ XS_URL_NO_SCHEME:
472
+ if (!base)
473
+ goto XS_URL_ERROR;
474
+ fx_parseURLCopyPart(the, base, result, xsID_scheme);
475
+ schemeIndex = baseSchemeIndex;
476
+ special = baseSpecial;
477
+ if (schemeIndex == 0)
478
+ goto XS_URL_FILE_START;
479
+
480
+ if (fx_parseURLHasOpaquePath(the, base)) {
481
+ c = fx_parseURLDecode(the, src);
482
+ if (c == '#') {
483
+ fx_parseURLCopyPart(the, base, result, xsID_path);
484
+ fx_parseURLCopyPart(the, base, result, xsID_query);
485
+ goto XS_URL_FRAGMENT;
486
+ }
487
+ goto XS_URL_ERROR;
488
+ }
489
+ goto XS_URL_RELATIVE;
490
+
491
+ XS_URL_RELATIVE:
492
+ tmp = src->offset;
493
+ c = fx_parseURLDecode(the, src);
494
+ if ((c == '/') || (special && (c == '\\'))) {
495
+ c = fx_parseURLDecode(the, src);
496
+ if ((c == '/') || (special && (c == '\\'))) {
497
+ goto XS_URL_AUTHORITY_START;
498
+ }
499
+ }
500
+ src->offset = tmp;
501
+
502
+ fx_parseURLCopyPart(the, base, result, xsID_username);
503
+ fx_parseURLCopyPart(the, base, result, xsID_password);
504
+ fx_parseURLCopyPart(the, base, result, xsID_host);
505
+ fx_parseURLCopyPart(the, base, result, xsID_port);
506
+
507
+ c = fx_parseURLDecode(the, src);
508
+ if ((c == '/') || (special && (c == '\\')))
509
+ goto XS_URL_PATH;
510
+ fx_parseURLCopyPath(the, base, result);
511
+ if (c == '?')
512
+ goto XS_URL_QUERY;
513
+ fx_parseURLCopyPart(the, base, result, xsID_query);
514
+ if (c == '#')
515
+ goto XS_URL_FRAGMENT;
516
+ if (c != C_EOF) {
517
+ fx_parseURLShortenPath(the, result);
518
+ src->offset = tmp;
519
+ goto XS_URL_PATH;
520
+ }
521
+ goto XS_URL_END;
522
+
523
+ XS_URL_AUTHORITY_START:
524
+ tmp = src->offset;
525
+ c = fx_parseURLDecode(the, src);
526
+ if (special && ((c == '/') || (c == '\\')))
527
+ goto XS_URL_AUTHORITY_START;
528
+ src->offset = tmp;
529
+
530
+ XS_URL_AUTHORITY:
531
+ c = fx_parseURLDecode(the, src);
532
+ if (c == '@') {
533
+ atOffset = src->offset - 1;
534
+ }
535
+ else if (c == ':') {
536
+ if (colonOffset < 0)
537
+ colonOffset = src->offset - 1;
538
+ }
539
+ if ((c == C_EOF) || (c == '/') || (special && (c == '\\')) || (c == '?') || (c == '#')) {
540
+ txInteger endOffset = src->offset - 1;
541
+ src->offset = tmp;
542
+ if (atOffset >= 0) {
543
+ if (colonOffset > atOffset)
544
+ colonOffset = -1;
545
+ if (colonOffset >= 0) {
546
+ while (src->offset < colonOffset) {
547
+ c = fx_parseURLDecode(the, src);
548
+ fx_parseURLPercentEncode(the, c, dst, gxUserInfoSet);
549
+ }
550
+ fx_parseURLSetPart(the, result, xsID_username, 0, dst);
551
+ src->offset++;
552
+ while (src->offset < atOffset) {
553
+ c = fx_parseURLDecode(the, src);
554
+ fx_parseURLPercentEncode(the, c, dst, gxUserInfoSet);
555
+ }
556
+ fx_parseURLSetPart(the, result, xsID_password, 0, dst);
557
+ src->offset++;
558
+ }
559
+ else {
560
+ while (src->offset < atOffset) {
561
+ c = fx_parseURLDecode(the, src);
562
+ fx_parseURLPercentEncode(the, c, dst, gxUserInfoSet);
563
+ }
564
+ fx_parseURLSetPart(the, result, xsID_username, 0, dst);
565
+ src->offset++;
566
+ }
567
+ if (src->offset == endOffset)
568
+ goto XS_URL_ERROR;
569
+ }
570
+ hostOffset = src->offset;
571
+ goto XS_URL_HOST;
572
+ }
573
+ goto XS_URL_AUTHORITY;
574
+
575
+ XS_URL_USERNAME:
576
+ c = fx_parseURLDecode(the, src);
577
+ if (c == C_EOF) {
578
+ fx_parseURLSetPart(the, result, xsID_username, 0, dst);
579
+ goto XS_URL_END;
580
+ }
581
+ fx_parseURLPercentEncode(the, c, dst, gxUserInfoSet);
582
+ goto XS_URL_USERNAME;
583
+
584
+ XS_URL_PASSWORD:
585
+ c = fx_parseURLDecode(the, src);
586
+ if (c == C_EOF) {
587
+ fx_parseURLSetPart(the, result, xsID_password, 0, dst);
588
+ goto XS_URL_END;
589
+ }
590
+ fx_parseURLPercentEncode(the, c, dst, gxUserInfoSet);
591
+ goto XS_URL_PASSWORD;
592
+
593
+ XS_URL_HOST:
594
+ c = fx_parseURLDecode(the, src);
595
+ if ((c == ':') && !insideBracket) {
596
+ if (src->offset - 1 == hostOffset)
597
+ goto XS_URL_ERROR;
598
+ if (override == HOST_STATE)
599
+ goto XS_URL_END;
600
+ if (fx_parseURLHost(the, src, hostOffset, src->offset - 1, dst, special)) {
601
+ fx_parseURLSetPart(the, result, xsID_host, 0, dst);
602
+ goto XS_URL_PORT;
603
+ }
604
+ if (override)
605
+ goto XS_URL_END;
606
+ goto XS_URL_ERROR;
607
+ }
608
+ if ((c == C_EOF) || (c == '/') || (special && (c == '\\')) || (c == '?') || (c == '#')) {
609
+ if (special && (src->offset - 1 == hostOffset))
610
+ goto XS_URL_ERROR;
611
+ //@@
612
+ if (fx_parseURLHost(the, src, hostOffset, src->offset - 1, dst, special)) {
613
+ fx_parseURLSetPart(the, result, xsID_host, 0, dst);
614
+ if (c == C_EOF)
615
+ goto XS_URL_END;
616
+ if (c == '?')
617
+ goto XS_URL_QUERY;
618
+ if (c == '#')
619
+ goto XS_URL_FRAGMENT;
620
+ goto XS_URL_PATH;
621
+ }
622
+ if (override)
623
+ goto XS_URL_END;
624
+ goto XS_URL_ERROR;
625
+ }
626
+ if (c == '[')
627
+ insideBracket = 1;
628
+ if (c == ']')
629
+ insideBracket = 0;
630
+ goto XS_URL_HOST;
631
+
632
+ XS_URL_PORT:
633
+ c = fx_parseURLDecode(the, src);
634
+ if (('0' <= c) && (c <= '9')) {
635
+ fx_parseURLEncode(the, c, dst);
636
+ goto XS_URL_PORT;
637
+ }
638
+ if (override || (c == C_EOF) || (c == '/') || (special && (c == '\\')) || (c == '?') || (c == '#')) {
639
+ if (dst->offset != 0) {
640
+ mxPushSlot(dst->slot);
641
+ port = fxToNumber(the, the->stack);
642
+ mxPop();
643
+ if (port > 65535)
644
+ goto XS_URL_ERROR;
645
+ if (special && ((txInteger)port == gx_parseURLSpecialSchemePorts[schemeIndex])) {
646
+ fx_parseURLEmptyPart(the, result, xsID_port);
647
+ dst->offset = 0;
648
+ dst->slot->value.string[0] = 0;
649
+ }
650
+ else {
651
+ fxIntegerToString(the, (txInteger)port, dst->slot->value.string, dst->size);
652
+ fx_parseURLSetPart(the, result, xsID_port, 0, dst);
653
+ }
654
+ }
655
+ if (override || (c == C_EOF))
656
+ goto XS_URL_END;
657
+ if (c == '?')
658
+ goto XS_URL_QUERY;
659
+ if (c == '#')
660
+ goto XS_URL_FRAGMENT;
661
+ goto XS_URL_PATH;
662
+ }
663
+ goto XS_URL_ERROR;
664
+
665
+ XS_URL_FILE_START:
666
+ tmp = src->offset;
667
+ c = fx_parseURLDecode(the, src);
668
+ if ((c == '/') || (c == '\\'))
669
+ goto XS_URL_FILE_SLASH;
670
+ if (base && (baseSchemeIndex == 0)) {
671
+ fx_parseURLCopyPart(the, base, result, xsID_host);
672
+ if (fx_parseURLIsWindowsDriveLetter(the, src->slot->value.string + tmp, 1)) {
673
+ src->offset = tmp;
674
+ goto XS_URL_PATH;
675
+ }
676
+ fx_parseURLCopyPath(the, base, result);
677
+ if (c == '?')
678
+ goto XS_URL_QUERY;
679
+ fx_parseURLCopyPart(the, base, result, xsID_query);
680
+ if (c == '#')
681
+ goto XS_URL_FRAGMENT;
682
+ if (c != C_EOF) {
683
+ fx_parseURLShortenPath(the, result);
684
+ src->offset = tmp;
685
+ goto XS_URL_PATH;
686
+ }
687
+ goto XS_URL_END;
688
+ }
689
+ fx_parseURLEmptyPart(the, result, xsID_host);
690
+ if (c == '?')
691
+ goto XS_URL_QUERY;
692
+ if (c == '#')
693
+ goto XS_URL_FRAGMENT;
694
+ if (c != C_EOF) {
695
+ src->offset = tmp;
696
+ goto XS_URL_PATH;
697
+ }
698
+ goto XS_URL_END;
699
+
700
+ XS_URL_FILE_SLASH:
701
+ tmp = src->offset;
702
+ c = fx_parseURLDecode(the, src);
703
+ if ((c == '/') || (c == '\\')) {
704
+ hostOffset = src->offset;
705
+ goto XS_URL_FILE_HOST;
706
+ }
707
+ if (base && (baseSchemeIndex == 0)) {
708
+ fx_parseURLCopyPart(the, base, result, xsID_host);
709
+ if (fx_parseURLIsWindowsDriveLetter(the, src->slot->value.string + tmp, 1)) {
710
+ src->offset = tmp;
711
+ goto XS_URL_PATH;
712
+ }
713
+ mxPushSlot(base);
714
+ mxGetID(mxID(_length));
715
+ length = (txIndex)fxToLength(the, the->stack);
716
+ mxPop();
717
+ if (length > 0) {
718
+ mxPushSlot(base);
719
+ mxGetIndex(0);
720
+ if (fx_parseURLIsWindowsDriveLetter(the, the->stack->value.string, 0)) {
721
+ mxPushSlot(result);
722
+ mxSetIndex(0);
723
+ mxPop();
724
+ }
725
+ }
726
+ }
727
+ else
728
+ fx_parseURLEmptyPart(the, result, xsID_host);
729
+ src->offset = tmp;
730
+ goto XS_URL_PATH;
731
+
732
+ XS_URL_FILE_HOST:
733
+ c = fx_parseURLDecode(the, src);
734
+ if ((c == C_EOF) || (c == '/') || (c == '\\') || (c == '?') || (c == '#')) {
735
+ if (!override && fx_parseURLIsWindowsDriveLetter(the, src->slot->value.string + hostOffset, 1)) {
736
+ txInteger endOffset = src->offset - 1;
737
+ fx_parseURLEmptyPart(the, result, xsID_host);
738
+ src->offset = hostOffset;
739
+ while (src->offset < endOffset) {
740
+ txInteger d = fx_parseURLDecode(the, src);
741
+ fx_parseURLPercentEncode(the, d, dst, gxPathSet);
742
+ }
743
+ src->offset++;
744
+ fx_parseURLPushPath(the, result, dst, 0);
745
+ goto XS_URL_PATH_START;
746
+ }
747
+ if (fx_parseURLHost(the, src, hostOffset, src->offset - 1, dst, special)) {
748
+ if (!c_strcmp(dst->slot->value.string, "localhost")) {
749
+ dst->slot->value.string[0] = 0;
750
+ dst->offset = 0;
751
+ }
752
+ fx_parseURLSetPart(the, result, xsID_host, 0, dst);
753
+ goto XS_URL_PATH_START;
754
+ }
755
+ if (override)
756
+ goto XS_URL_END;
757
+ goto XS_URL_ERROR;
758
+ }
759
+ goto XS_URL_FILE_HOST;
760
+
761
+ XS_URL_PATH_START:
762
+ if (c == C_EOF)
763
+ goto XS_URL_END;
764
+ if (!override && (c == '?'))
765
+ goto XS_URL_QUERY;
766
+ if (!override && (c == '#'))
767
+ goto XS_URL_FRAGMENT;
768
+
769
+ XS_URL_PATH:
770
+ c = fx_parseURLDecode(the, src);
771
+ if (c == C_EOF) {
772
+ fx_parseURLPushPath(the, result, dst, 1);
773
+ goto XS_URL_END;
774
+ }
775
+ if ((c == '/') || (special && (c == '\\'))) {
776
+ fx_parseURLPushPath(the, result, dst, 0);
777
+ goto XS_URL_PATH;
778
+ }
779
+ if (!override && (c == '?')) {
780
+ fx_parseURLPushPath(the, result, dst, 1);
781
+ goto XS_URL_QUERY;
782
+ }
783
+ if (!override && (c == '#')) {
784
+ fx_parseURLPushPath(the, result, dst, 1);
785
+ goto XS_URL_FRAGMENT;
786
+ }
787
+ fx_parseURLPercentEncode(the, c, dst, gxPathSet);
788
+ goto XS_URL_PATH;
789
+
790
+ XS_URL_OPAQUE_PATH:
791
+ c = fx_parseURLDecode(the, src);
792
+ if (c == C_EOF) {
793
+ fx_parseURLSetPart(the, result, xsID_path, 0, dst);
794
+ goto XS_URL_END;
795
+ }
796
+ if (!override && (c == '?')) {
797
+ fx_parseURLSetPart(the, result, xsID_path, 0, dst);
798
+ goto XS_URL_QUERY;
799
+ }
800
+ if (!override && (c == '#')) {
801
+ fx_parseURLSetPart(the, result, xsID_path, 0, dst);
802
+ goto XS_URL_FRAGMENT;
803
+ }
804
+ fx_parseURLPercentEncode(the, c, dst, gxControlSet);
805
+ goto XS_URL_OPAQUE_PATH;
806
+
807
+ XS_URL_QUERY:
808
+ c = fx_parseURLDecode(the, src);
809
+ if (c == C_EOF) {
810
+ fx_parseURLSetPart(the, result, xsID_query, 0, dst);
811
+ goto XS_URL_END;
812
+ }
813
+ if (!override && (c == '#')) {
814
+ fx_parseURLSetPart(the, result, xsID_query, 0, dst);
815
+ goto XS_URL_FRAGMENT;
816
+ }
817
+ fx_parseURLPercentEncode(the, c, dst, (special) ? gxSpecialQuerySet : gxQuerySet);
818
+ goto XS_URL_QUERY;
819
+
820
+ XS_URL_FRAGMENT:
821
+ c = fx_parseURLDecode(the, src);
822
+ if (c == C_EOF) {
823
+ fx_parseURLSetPart(the, result, xsID_fragment, 0, dst);
824
+ goto XS_URL_END;
825
+ }
826
+ fx_parseURLPercentEncode(the, c, dst, gxFragmentSet);
827
+ goto XS_URL_FRAGMENT;
828
+
829
+ XS_URL_ERROR:
830
+ mxTypeError("invalid URL");
831
+
832
+ XS_URL_END:
833
+ return;
834
+ }
835
+
836
+ void fx_parseURLCopyPart(txMachine* the, txSlot* src, txSlot* dst, txID id)
837
+ {
838
+ mxPushSlot(src);
839
+ mxGetID(id);
840
+ mxPushSlot(dst);
841
+ mxSetID(id);
842
+ mxPop();
843
+ }
844
+
845
+ void fx_parseURLCopyPath(txMachine* the, txSlot* src, txSlot* dst)
846
+ {
847
+ txIndex length, i;
848
+
849
+ mxPushSlot(src);
850
+ mxGetID(mxID(_length));
851
+ length = (txIndex)fxToLength(the, the->stack);
852
+ mxPop();
853
+ i = 0;
854
+ while (i < length) {
855
+ mxPushSlot(src);
856
+ mxGetIndex(i);
857
+ mxPushSlot(dst);
858
+ mxSetIndex(i);
859
+ mxPop();
860
+ i++;
861
+ }
862
+ }
863
+
864
+ txInteger fx_parseURLDecode(txMachine* the, txStringStream* stream)
865
+ {
866
+ txInteger result;
867
+ txString string = stream->slot->value.string + stream->offset;
868
+ string = mxStringByteDecode(string, &result);
869
+ if ((0xD000 <= result) && (result <= 0xDFFF))
870
+ result = 0xFFFD;
871
+ stream->offset = string - stream->slot->value.string;
872
+ return result;
873
+ }
874
+
875
+ void fx_parseURLEncode(txMachine* the, txInteger c, txStringStream* dst)
876
+ {
877
+ txSize length = mxStringByteLength(c);
878
+ txString string;
879
+ if (dst->offset + length >= dst->size) {
880
+ txSize size = fxAddChunkSizes(the, dst->offset, length + 1);
881
+ txString string = fxRenewChunk(the, dst->slot->value.string, size);
882
+ if (!string) {
883
+ string = (txString)fxNewChunk(the, size);
884
+ c_memcpy(string, dst->slot->value.string, dst->offset);
885
+ }
886
+ dst->slot->value.string = string;
887
+ dst->size = size;
888
+ }
889
+ string = dst->slot->value.string + dst->offset;
890
+ string = mxStringByteEncode(string, c);
891
+ dst->offset += length;
892
+ *string = 0;
893
+ }
894
+
895
+ void fx_parseURLEmptyPart(txMachine* the, txSlot* target, txID id)
896
+ {
897
+ mxPush(mxEmptyString);
898
+ mxPushSlot(target);
899
+ mxSetID(id);
900
+ mxPop();
901
+ }
902
+
903
+ txBoolean fx_parseURLHasOpaquePath(txMachine* the, txSlot* parts)
904
+ {
905
+ mxPushSlot(parts);
906
+ return mxHasID(xsID_path);
907
+ }
908
+
909
+ txBoolean fx_parseURLHost(txMachine* the, txStringStream* src, txInteger from, txInteger to, txStringStream* dst, txBoolean special)
910
+ {
911
+ txString p = src->slot->value.string;
912
+ if ((to - from > 1) && (p[from] == '[') && (p[to - 1] == ']')) {
913
+ return fx_parseURLHostIPv6( the, src, from + 1, to - 1, dst);
914
+ }
915
+ if (special) {
916
+ if (fx_parseURLHostSpecial(the, src, from, to, dst))
917
+ return fx_parseURLHostIPv4(the, src, from, to, dst);
918
+ return 0;
919
+ }
920
+ return fx_parseURLHostNotSpecial(the, src, from, to, dst);
921
+ }
922
+
923
+ txBoolean fx_parseURLHostIPv4(txMachine* the, txStringStream* src, txInteger from, txInteger to, txStringStream* dst)
924
+ {
925
+ txS8 pieces[4];
926
+ txS8 value;
927
+ txS8 sum;
928
+ txInteger pieceCount = 0;
929
+ txInteger pieceIndex;
930
+ txString p = dst->slot->value.string;
931
+ txString q = dst->slot->value.string + dst->offset;
932
+ while (p < q) {
933
+ value = -1;
934
+ if (*p == '0') {
935
+ value = 0;
936
+ p++;
937
+ if ((p < q) && ((*p == 'x') || (*p == 'X'))) {
938
+ p++;
939
+ while (p < q) {
940
+ if (('0' <= *p) && (*p <= '9'))
941
+ value = (value * 16) + (*p - '0');
942
+ else if (('a' <= *p) && (*p <= 'f'))
943
+ value = (value * 16) + (10 + *p - 'a');
944
+ else if (('A' <= *p) && (*p <= 'F'))
945
+ value = (value * 16) + (10 + *p - 'A');
946
+ else
947
+ break;
948
+ p++;
949
+
950
+ }
951
+ }
952
+ else {
953
+ while (p < q) {
954
+ if (('0' <= *p) && (*p <= '7'))
955
+ value = (value * 8) + (*p - '0');
956
+ else if (('8' <= *p) && (*p <= '9'))
957
+ value += 0x0000000100000000;
958
+ else
959
+ break;
960
+ p++;
961
+ }
962
+ }
963
+ }
964
+ else if (('1' <= *p) && (*p <= '9')) {
965
+ value = *p - '0';
966
+ p++;
967
+ while (p < q) {
968
+ if (('0' <= *p) && (*p <= '9'))
969
+ value = (value * 10) + (*p - '0');
970
+ else
971
+ break;
972
+ p++;
973
+ }
974
+ }
975
+ if ((p < q) && (*p != '.')) {
976
+ value = -1;
977
+ while ((p < q) && (*p != '.'))
978
+ p++;
979
+ }
980
+ if (pieceCount < 4)
981
+ pieces[pieceCount] = value;
982
+ else
983
+ pieces[3] = value;
984
+ pieceCount++;
985
+ if (*p == '.')
986
+ p++;
987
+ }
988
+ if (pieceCount == 0)
989
+ return 1;
990
+ pieceIndex = pieceCount - 1;
991
+ if (pieceIndex > 3)
992
+ pieceIndex = 3;
993
+ if (pieces[pieceIndex] == -1)
994
+ return 1;
995
+ if (pieceCount > 4)
996
+ return 0;
997
+ sum = pieces[pieceIndex];
998
+ value = 256;
999
+ pieceCount = 4 - pieceCount;
1000
+ while (pieceCount > 0) {
1001
+ value <<= 8;
1002
+ pieceCount--;
1003
+ }
1004
+ if (sum >= value)
1005
+ return 0;
1006
+ pieceIndex--;
1007
+ while (pieceIndex >= 0) {
1008
+ value = pieces[pieceIndex];
1009
+ if ((value < 0) || (255 < value))
1010
+ return 0;
1011
+ pieceCount = 3 - pieceIndex;
1012
+ while (pieceCount > 0) {
1013
+ value <<= 8;
1014
+ pieceCount--;
1015
+ }
1016
+ sum += value;
1017
+ pieceIndex--;
1018
+ }
1019
+ if (sum > 0x00000000FFFFFFFF)
1020
+ return 0;
1021
+ pieces[0] = (sum & 0x00000000FF000000) >> 24;
1022
+ pieces[1] = (sum & 0x0000000000FF0000) >> 16;
1023
+ pieces[2] = (sum & 0x000000000000FF00) >> 8;
1024
+ pieces[3] = (sum & 0x00000000000000FF);
1025
+ dst->offset = 0;
1026
+ dst->slot->value.string[0] = 0;
1027
+ for (pieceIndex = 0; pieceIndex < 4; pieceIndex++) {
1028
+ value = pieces[pieceIndex];
1029
+ if (value >= 100) {
1030
+ fx_parseURLEncode(the, '0' + ((txInteger)value / 100), dst);
1031
+ value %= 100;
1032
+ fx_parseURLEncode(the, '0' + ((txInteger)value / 10), dst);
1033
+ value %= 10;
1034
+ }
1035
+ else if (value >= 10) {
1036
+ fx_parseURLEncode(the, '0' + ((txInteger)value / 10), dst);
1037
+ value %= 10;
1038
+ }
1039
+ fx_parseURLEncode(the, '0' + (txInteger)value, dst);
1040
+ if (pieceIndex < 3)
1041
+ fx_parseURLEncode(the, '.', dst);
1042
+ }
1043
+ return 1;
1044
+ }
1045
+
1046
+ txBoolean fx_parseURLHostIPv6(txMachine* the, txStringStream* src, txInteger from, txInteger to, txStringStream* dst)
1047
+ {
1048
+ txU2 pieces[8];
1049
+ txInteger pieceIndex = 0;
1050
+ txInteger compress = -1;
1051
+ txU2 value;
1052
+ txInteger length;
1053
+ txInteger numbersSeen;
1054
+ txString p = src->slot->value.string + from;
1055
+ txString q = src->slot->value.string + to;
1056
+ c_memset(pieces, 0, sizeof(pieces));
1057
+ if (p[0] == ':') {
1058
+ if (p[1] != ':')
1059
+ return 0;
1060
+ p += 2;
1061
+ pieceIndex++;
1062
+ compress = pieceIndex;
1063
+ }
1064
+ while (p < q) {
1065
+ if (pieceIndex == 8)
1066
+ return 0;
1067
+ if (*p == ':') {
1068
+ if (compress != -1)
1069
+ return 0;
1070
+ p++;
1071
+ pieceIndex++;
1072
+ compress = pieceIndex;
1073
+ continue;
1074
+ }
1075
+ value = 0;
1076
+ length = 0;
1077
+ while ((p < q) && (length < 4)) {
1078
+ if (('0' <= *p) && (*p <= '9'))
1079
+ value = (value * 16) + (*p - '0');
1080
+ else if (('a' <= *p) && (*p <= 'f'))
1081
+ value = (value * 16) + (10 + *p - 'a');
1082
+ else if (('A' <= *p) && (*p <= 'F'))
1083
+ value = (value * 16) + (10 + *p - 'A');
1084
+ else
1085
+ break;
1086
+ length++;
1087
+ p++;
1088
+ }
1089
+ if (*p == '.') {
1090
+ if (length == 0)
1091
+ return 0;
1092
+ p -= length;
1093
+ if (pieceIndex > 6)
1094
+ return 0;
1095
+ numbersSeen = 0;
1096
+ while (p < q) {
1097
+ txInteger ipv4Piece = -1;
1098
+ if (numbersSeen > 0) {
1099
+ if ((*p == '.') && (numbersSeen < 4))
1100
+ p++;
1101
+ else
1102
+ return 0;
1103
+ }
1104
+ if ((p < q) && ('0' <= *p) && (*p <= '9')) {
1105
+ while ((p < q) && ('0' <= *p) && (*p <= '9')) {
1106
+ if (ipv4Piece == 0)
1107
+ return 0;
1108
+ if (ipv4Piece < 0)
1109
+ ipv4Piece = *p - '0';
1110
+ else
1111
+ ipv4Piece = (ipv4Piece * 10) + (*p - '0');
1112
+ if (ipv4Piece > 255)
1113
+ return 0;
1114
+ p++;
1115
+ }
1116
+ pieces[pieceIndex] = (pieces[pieceIndex] * 256) + ipv4Piece;
1117
+ numbersSeen++;
1118
+ if ((numbersSeen == 2) || (numbersSeen == 4))
1119
+ pieceIndex++;
1120
+ }
1121
+ else
1122
+ return 0;
1123
+ }
1124
+ if (numbersSeen != 4)
1125
+ return 0;
1126
+ break;
1127
+ }
1128
+ else if (*p == ':') {
1129
+ p++;
1130
+ if (p == q)
1131
+ return 0;
1132
+ }
1133
+ else if (p < q)
1134
+ return 0;
1135
+ pieces[pieceIndex] = value;
1136
+ pieceIndex++;
1137
+ }
1138
+ if (compress != -1) {
1139
+ txInteger swaps = pieceIndex - compress;
1140
+ pieceIndex = 7;
1141
+ while ((pieceIndex != 0) && (swaps > 0)) {
1142
+ txU2 piece = pieces[compress + swaps - 1];
1143
+ pieces[compress + swaps - 1] = pieces[pieceIndex];
1144
+ pieces[pieceIndex] = piece;
1145
+ pieceIndex--;
1146
+ swaps--;
1147
+ }
1148
+ }
1149
+ else if (pieceIndex != 8)
1150
+ return 0;
1151
+
1152
+ compress = -1;
1153
+ length = 0;
1154
+ pieceIndex = 0;
1155
+ while (pieceIndex < 8) {
1156
+ if (pieces[pieceIndex] == 0) {
1157
+ txInteger zeroCompress = pieceIndex;
1158
+ txInteger zeroLength = 1;
1159
+ pieceIndex++;
1160
+ while (pieceIndex < 8) {
1161
+ if (pieces[pieceIndex] != 0)
1162
+ break;
1163
+ pieceIndex++;
1164
+ zeroLength++;
1165
+ }
1166
+ if (zeroLength > length) {
1167
+ compress = zeroCompress;
1168
+ length = zeroLength;
1169
+ }
1170
+
1171
+ }
1172
+ pieceIndex++;
1173
+ }
1174
+ if (length < 2)
1175
+ compress = -1;
1176
+
1177
+ txBoolean ignore0 = 0;
1178
+ fx_parseURLEncode(the, '[', dst);
1179
+ for (pieceIndex = 0; pieceIndex < 8; pieceIndex++) {
1180
+ value = pieces[pieceIndex];
1181
+ if (ignore0 && (value == 0))
1182
+ continue;
1183
+ else
1184
+ ignore0 = 0;
1185
+ if (compress == pieceIndex) {
1186
+ if (pieceIndex == 0)
1187
+ fx_parseURLEncode(the, ':', dst);
1188
+ fx_parseURLEncode(the, ':', dst);
1189
+ ignore0 = 1;
1190
+ continue;
1191
+ }
1192
+ txInteger flag = 0;
1193
+ txInteger shift = 12;
1194
+ while (shift > 0) {
1195
+ txInteger digit = (value >> shift) & 0x000F;
1196
+ flag |= digit;
1197
+ if (flag)
1198
+ fx_parseURLEncode(the, gxHexLower[digit], dst);
1199
+ shift -= 4;
1200
+ }
1201
+ fx_parseURLEncode(the, gxHexLower[value & 0x000F], dst);
1202
+ if (pieceIndex != 7)
1203
+ fx_parseURLEncode(the, ':', dst);
1204
+ }
1205
+ fx_parseURLEncode(the, ']', dst);
1206
+ return 1;
1207
+ }
1208
+
1209
+ txBoolean fx_parseURLHostNotSpecial(txMachine* the, txStringStream* src, txInteger from, txInteger to, txStringStream* dst)
1210
+ {
1211
+ txBoolean result = 1;
1212
+ txInteger offset = src->offset;
1213
+ src->offset = from;
1214
+ while (src->offset < to) {
1215
+ txInteger c = fx_parseURLDecode(the, src);
1216
+ if ((c < 0x80) && c_read8(gxNotSpecialHostSet + c)) {
1217
+ result = 0;
1218
+ break;
1219
+ }
1220
+ fx_parseURLPercentEncode(the, c, dst, gxControlSet);
1221
+ }
1222
+ src->offset = offset;
1223
+ return result;
1224
+ }
1225
+
1226
+ txBoolean fx_parseURLHostSpecial(txMachine* the, txStringStream* src, txInteger from, txInteger to, txStringStream* dst)
1227
+ {
1228
+ txBoolean result = 1;
1229
+ txInteger offset = src->offset;
1230
+ txInteger flag = 0;
1231
+ src->offset = from;
1232
+ while (src->offset < to) {
1233
+ txInteger c = fx_parseURLDecode(the, src);
1234
+ if (c < 0x80) {
1235
+ if (('A' <= c) && (c <= 'Z'))
1236
+ c -= ('A' - 'a');
1237
+ else if (c == '%')
1238
+ flag |= 1;
1239
+ else if (c_read8(gxSpecialHostSet + c)) {
1240
+ result = 0;
1241
+ break;
1242
+ }
1243
+ }
1244
+ else {
1245
+
1246
+ flag |= 2;
1247
+ }
1248
+ fx_parseURLEncode(the, c, dst);
1249
+ }
1250
+ if (result && (flag & 1)) {
1251
+ txStringStream _tmp;
1252
+ txStringStream* tmp = &_tmp;
1253
+ mxTry(the) {
1254
+ mxPush(mxGlobal);
1255
+ mxDub();
1256
+ mxGetID(mxID(_decodeURIComponent));
1257
+ mxCall();
1258
+ mxPushSlot(dst->slot);
1259
+ mxRunCount(1);
1260
+ tmp->slot = the->stack;
1261
+ tmp->offset = 0;
1262
+ tmp->size = 0;
1263
+ dst->offset = 0;
1264
+ dst->slot->value.string[0] = 0;
1265
+ for (;;) {
1266
+ txInteger c = fx_parseURLDecode(the, tmp);
1267
+ if (c == C_EOF)
1268
+ break;
1269
+ if (c < 0x80) {
1270
+ if (c_read8(gxSpecialHostSet + c)) {
1271
+ result = 0;
1272
+ break;
1273
+ }
1274
+ if (('A' <= c) && (c <= 'Z'))
1275
+ c -= ('A' - 'a');
1276
+ }
1277
+ else
1278
+ flag |= 2;
1279
+ fx_parseURLEncode(the, c, dst);
1280
+ }
1281
+ mxPop();
1282
+ }
1283
+ mxCatch(the) {
1284
+ result = 0;
1285
+ }
1286
+ }
1287
+ if (result && (flag & 2)) {
1288
+ // punycode
1289
+ mxSyntaxError("no punycode yet");
1290
+ result = 0;
1291
+ }
1292
+ src->offset = offset;
1293
+ return result;
1294
+ }
1295
+
1296
+ txBoolean fx_parseURLIsPartEmpty(txMachine* the, txSlot* parts, txID id)
1297
+ {
1298
+ txBoolean result;
1299
+ mxPushSlot(parts);
1300
+ mxGetID(id);
1301
+ result = the->stack->value.string[0] == 0;
1302
+ mxPop();
1303
+ return result;
1304
+ }
1305
+
1306
+ txBoolean fx_parseURLIsWindowsDriveLetter(txMachine* the, txString string, txBoolean startsWith)
1307
+ {
1308
+ char c = *string++;
1309
+ if ((('A' <= c) && (c <= 'Z')) || (('a' <= c) && (c <= 'z'))) {
1310
+ c = *string++;
1311
+ if ((c == ':') || (c == '|')) {
1312
+ c = *string++;
1313
+ if (c == 0)
1314
+ return 1;
1315
+ if (startsWith && ((c == '/') || (c == '\\') || (c == '?') || (c == '#')))
1316
+ return 1;
1317
+ }
1318
+ }
1319
+ return 0;
1320
+ }
1321
+
1322
+ void fx_parseURLNullPart(txMachine* the, txSlot* target, txID id)
1323
+ {
1324
+ mxPushNull();
1325
+ mxPushSlot(target);
1326
+ mxSetID(id);
1327
+ mxPop();
1328
+ }
1329
+
1330
+ void fx_parseURLPercentEncode(txMachine* the, txInteger c, txStringStream* dst, const char* set)
1331
+ {
1332
+ txSize length;
1333
+ txString string;
1334
+ if (c < 0x80) {
1335
+ if (c_read8(set + c))
1336
+ length = 3;
1337
+ else
1338
+ length = 1;
1339
+ }
1340
+ else if (c < 0x800) {
1341
+ length = 6;
1342
+ }
1343
+ else if (c < 0x10000) {
1344
+ length = 9;
1345
+ }
1346
+ else {
1347
+ length = 12;
1348
+ }
1349
+ if (dst->offset + length >= dst->size) {
1350
+ txSize size = fxAddChunkSizes(the, dst->offset, length + 1);
1351
+ txString string = fxRenewChunk(the, dst->slot->value.string, size);
1352
+ if (!string) {
1353
+ string = (txString)fxNewChunk(the, size);
1354
+ c_memcpy(string, dst->slot->value.string, dst->offset);
1355
+ }
1356
+ dst->slot->value.string = string;
1357
+ dst->size = size;
1358
+ }
1359
+ string = dst->slot->value.string + dst->offset;
1360
+ if (length == 1)
1361
+ *string++ = (char)c;
1362
+ else if (length == 3) {
1363
+ *string++ = '%';
1364
+ string = fxStringifyHexEscape(string, c);
1365
+ }
1366
+ else if (length == 6) {
1367
+ *string++ = '%';
1368
+ string = fxStringifyHexEscape(string, 0xC0 | (c >> 6));
1369
+ *string++ = '%';
1370
+ string = fxStringifyHexEscape(string, 0x80 | (c & 0x3F));
1371
+ }
1372
+ else if (length == 9) {
1373
+ *string++ = '%';
1374
+ string = fxStringifyHexEscape(string, 0xE0 | (c >> 12));
1375
+ *string++ = '%';
1376
+ string = fxStringifyHexEscape(string, 0x80 | ((c >> 6) & 0x3F));
1377
+ *string++ = '%';
1378
+ string = fxStringifyHexEscape(string, 0x80 | (c & 0x3F));
1379
+ }
1380
+ else {
1381
+ *string++ = '%';
1382
+ string = fxStringifyHexEscape(string, 0xF0 | (c >> 18));
1383
+ *string++ = '%';
1384
+ string = fxStringifyHexEscape(string, 0x80 | ((c >> 12) & 0x3F));
1385
+ *string++ = '%';
1386
+ string = fxStringifyHexEscape(string, 0x80 | ((c >> 6) & 0x3F));
1387
+ *string++ = '%';
1388
+ string = fxStringifyHexEscape(string, 0x80 | (c & 0x3F));
1389
+ }
1390
+ dst->offset += length;
1391
+ *string = 0;
1392
+ }
1393
+
1394
+ void fx_parseURLPushPath(txMachine* the, txSlot* path, txStringStream* dst, txBoolean flag)
1395
+ {
1396
+ txSize size;
1397
+ txString string;
1398
+ if ((c_strcmp(dst->slot->value.string, "..") == 0)
1399
+ || (c_strcmp(dst->slot->value.string, ".%2E") == 0)
1400
+ || (c_strcmp(dst->slot->value.string, "%2E.") == 0)
1401
+ || (c_strcmp(dst->slot->value.string, "%2E%2E") == 0)
1402
+ || (c_strcmp(dst->slot->value.string, ".%2e") == 0)
1403
+ || (c_strcmp(dst->slot->value.string, "%2e.") == 0)
1404
+ || (c_strcmp(dst->slot->value.string, "%2e%2e") == 0)) {
1405
+ fx_parseURLShortenPath(the, path);
1406
+ if (flag) {
1407
+ dst->slot->value.string[0] = 0;
1408
+ dst->offset = 0;
1409
+ }
1410
+ }
1411
+ else if ((c_strcmp(dst->slot->value.string, ".") == 0)
1412
+ || (c_strcmp(dst->slot->value.string, "%2E") == 0)
1413
+ || (c_strcmp(dst->slot->value.string, "%2e") == 0)) {
1414
+ if (flag) {
1415
+ dst->slot->value.string[0] = 0;
1416
+ dst->offset = 0;
1417
+ }
1418
+ }
1419
+ else {
1420
+ txIndex length;
1421
+ mxPushSlot(path);
1422
+ mxGetID(mxID(_length));
1423
+ length = (txIndex)fxToLength(the, the->stack);
1424
+ mxPop();
1425
+ if ((length == 0) && fx_parseURLIsWindowsDriveLetter(the, dst->slot->value.string, 0))
1426
+ dst->slot->value.string[1] = ':';
1427
+ flag = 1;
1428
+ }
1429
+ if (flag) {
1430
+ mxPushSlot(path);
1431
+ mxDub();
1432
+ mxGetID(mxID(_push));
1433
+ mxCall();
1434
+ size = dst->offset + 1;
1435
+ string = fxRenewChunk(the, dst->slot->value.string, size);
1436
+ if (!string) {
1437
+ string = (txString)fxNewChunk(the, size);
1438
+ c_memcpy(string, dst->slot->value.string, size);
1439
+ }
1440
+ mxPushString(string);
1441
+ mxRunCount(1);
1442
+ mxPop();
1443
+ }
1444
+ dst->slot->value.string = fxNewChunk(the, mx_parseURLBufferSize);
1445
+ dst->size = mx_parseURLBufferSize;
1446
+ dst->offset = 0;
1447
+ dst->slot->value.string[0] = 0;
1448
+ }
1449
+
1450
+ txInteger fx_parseURLSpecialScheme(txMachine* the, txString scheme)
1451
+ {
1452
+ txInteger i;
1453
+ for (i = 0; i < mx_parseURLSpecialSchemeCount; i++) {
1454
+ if (!c_strcmp(scheme, gx_parseURLSpecialSchemeNames[i]))
1455
+ return i;
1456
+ }
1457
+ return -1;
1458
+ }
1459
+
1460
+ void fx_parseURLSetPart(txMachine* the, txSlot* target, txID id, txIndex index, txStringStream* dst)
1461
+ {
1462
+ txSize size = dst->offset + 1;
1463
+ txString string = fxRenewChunk(the, dst->slot->value.string, size);
1464
+ if (!string) {
1465
+ string = (txString)fxNewChunk(the, size);
1466
+ c_memcpy(string, dst->slot->value.string, size);
1467
+ }
1468
+ mxPushString(string);
1469
+ mxPushSlot(target);
1470
+ mxSetAll(id, index);
1471
+ mxPop();
1472
+ dst->slot->value.string = fxNewChunk(the, mx_parseURLBufferSize);
1473
+ dst->size = mx_parseURLBufferSize;
1474
+ dst->offset = 0;
1475
+ dst->slot->value.string[0] = 0;
1476
+ }
1477
+
1478
+ void fx_parseURLShortenPath(txMachine* the, txSlot* path)
1479
+ {
1480
+ txIndex length;
1481
+ txBoolean flag;
1482
+ mxPushSlot(path);
1483
+ mxGetID(mxID(_length));
1484
+ length = (txIndex)fxToLength(the, the->stack);
1485
+ mxPop();
1486
+ if (length == 1) {
1487
+ mxPushSlot(path);
1488
+ mxGetIndex(0);
1489
+ flag = fx_parseURLIsWindowsDriveLetter(the, the->stack->value.string, 0);
1490
+ mxPop();
1491
+ if (flag)
1492
+ return;
1493
+ }
1494
+ if (length > 0) {
1495
+ length--;
1496
+ mxPushInteger(length);
1497
+ mxPushSlot(path);
1498
+ mxSetID(mxID(_length));
1499
+ mxPop();
1500
+ }
1501
+ }
1502
+
1503
+ void fx_serializeURL(txMachine* the)
1504
+ {
1505
+ txSlot* parts;
1506
+ txInteger schemeIndex;
1507
+ txIndex length;
1508
+ txInteger override = 0;
1509
+ txSlot* result;
1510
+
1511
+ fxVars(the, 3);
1512
+ result = mxResult;
1513
+ fxCopyStringC(the, result, "");
1514
+
1515
+ parts = mxArgv(0);
1516
+
1517
+ mxPushSlot(parts);
1518
+ mxGetID(xsID_scheme);
1519
+ schemeIndex = fx_parseURLSpecialScheme(the, the->stack->value.string);
1520
+ mxPop();
1521
+
1522
+ mxPushSlot(parts);
1523
+ mxGetID(mxID(_length));
1524
+ length = (txIndex)fxToLength(the, the->stack);
1525
+ mxPop();
1526
+
1527
+ if (mxArgc > 1) {
1528
+ override = fxToInteger(the, mxArgv(1));
1529
+ if (override == SCHEME_STATE) {
1530
+ goto XS_URL_SCHEME;
1531
+ }
1532
+ if (override == USERNAME_STATE) {
1533
+ goto XS_URL_USERNAME;
1534
+ }
1535
+ if (override == PASSWORD_STATE) {
1536
+ goto XS_URL_PASSWORD;
1537
+ }
1538
+ if (override == HOST_PORT_STATE) {
1539
+ goto XS_URL_HOST;
1540
+ }
1541
+ if (override == HOST_STATE) {
1542
+ goto XS_URL_HOST;
1543
+ }
1544
+ if (override == PORT_STATE) {
1545
+ goto XS_URL_PORT;
1546
+ }
1547
+ if (override == PATH_STATE) {
1548
+ goto XS_URL_PATH;
1549
+ }
1550
+ if (override == QUERY_STATE) {
1551
+ goto XS_URL_QUERY;
1552
+ }
1553
+ if (override == FRAGMENT_STATE) {
1554
+ goto XS_URL_FRAGMENT;
1555
+ }
1556
+ if (override == ORIGIN_STATE) {
1557
+ goto XS_URL_ORIGIN;
1558
+ }
1559
+ goto XS_URL_END;
1560
+ }
1561
+
1562
+ XS_URL_SCHEME:
1563
+ mxPushSlot(parts);
1564
+ mxGetID(xsID_scheme);
1565
+ fxConcatString(the, result, the->stack);
1566
+ mxPop();
1567
+ fxConcatStringC(the, result, ":");
1568
+ if (override == SCHEME_STATE)
1569
+ goto XS_URL_END;
1570
+
1571
+ mxPushSlot(parts);
1572
+ mxGetID(xsID_host);
1573
+ mxPullSlot(mxVarv(0));
1574
+ if (mxIsNull(mxVarv(0))) {
1575
+ if (length > 1) {
1576
+ mxPushSlot(parts);
1577
+ mxGetIndex(0);
1578
+ if (the->stack->value.string[0] == 0)
1579
+ fxConcatStringC(the, result, "/.");
1580
+ mxPop();
1581
+ }
1582
+ goto XS_URL_PATH;
1583
+ }
1584
+
1585
+ fxConcatStringC(the, result, "//");
1586
+
1587
+ mxPushSlot(parts);
1588
+ mxGetID(xsID_username);
1589
+ mxPullSlot(mxVarv(1));
1590
+ mxPushSlot(parts);
1591
+ mxGetID(xsID_password);
1592
+ mxPullSlot(mxVarv(2));
1593
+ if (mxVarv(1)->value.string[0] || mxVarv(2)->value.string[0]) {
1594
+ fxConcatString(the, result, mxVarv(1));
1595
+ if (mxVarv(2)->value.string[0]) {
1596
+ fxConcatStringC(the, result, ":");
1597
+ fxConcatString(the, result, mxVarv(2));
1598
+ }
1599
+ fxConcatStringC(the, result, "@");
1600
+ }
1601
+ fxConcatString(the, result, mxVarv(0));
1602
+ goto XS_URL_PORT;
1603
+
1604
+ XS_URL_USERNAME:
1605
+ mxPushSlot(parts);
1606
+ mxGetID(xsID_username);
1607
+ fxConcatString(the, result, the->stack);
1608
+ mxPop();
1609
+ goto XS_URL_END;
1610
+
1611
+ XS_URL_PASSWORD:
1612
+ mxPushSlot(parts);
1613
+ mxGetID(xsID_password);
1614
+ fxConcatString(the, result, the->stack);
1615
+ mxPop();
1616
+ goto XS_URL_END;
1617
+
1618
+ XS_URL_ORIGIN:
1619
+ if (schemeIndex < 0) {
1620
+ fxConcatStringC(the, result, "null");
1621
+ goto XS_URL_END;
1622
+ }
1623
+ mxPushSlot(parts);
1624
+ mxGetID(xsID_host);
1625
+ mxPullSlot(mxVarv(0));
1626
+ if (!mxVarv(0)->value.string[0]) {
1627
+ fxConcatStringC(the, result, "null");
1628
+ goto XS_URL_END;
1629
+ }
1630
+ mxPushSlot(parts);
1631
+ mxGetID(xsID_scheme);
1632
+ fxConcatString(the, result, the->stack);
1633
+ mxPop();
1634
+ fxConcatStringC(the, result, "://");
1635
+ fxConcatString(the, result, mxVarv(0));
1636
+ goto XS_URL_PORT;
1637
+
1638
+ XS_URL_HOST:
1639
+ mxPushSlot(parts);
1640
+ mxGetID(xsID_host);
1641
+ mxPullSlot(mxVarv(0));
1642
+ fxConcatString(the, result, mxVarv(0));
1643
+ if (override == HOST_STATE)
1644
+ goto XS_URL_END;
1645
+
1646
+ XS_URL_PORT:
1647
+ mxPushSlot(parts);
1648
+ mxGetID(xsID_port);
1649
+ mxPullSlot(mxVarv(0));
1650
+ if (mxVarv(0)->value.string[0]) {
1651
+ if (override != PORT_STATE)
1652
+ fxConcatStringC(the, result, ":");
1653
+ fxConcatString(the, result, mxVarv(0));
1654
+ }
1655
+ if ((override == HOST_PORT_STATE) || (override == PORT_STATE) || (override == ORIGIN_STATE))
1656
+ goto XS_URL_END;
1657
+
1658
+ XS_URL_PATH:
1659
+ mxPushSlot(parts);
1660
+ if (mxHasID(xsID_path)) {
1661
+ mxPushSlot(parts);
1662
+ mxGetID(xsID_path);
1663
+ fxConcatString(the, result, the->stack);
1664
+ mxPop();
1665
+ }
1666
+ else {
1667
+ if (length == 0) {
1668
+ if (schemeIndex >= 0)
1669
+ fxConcatStringC(the, result, "/");
1670
+ }
1671
+ else {
1672
+ txIndex index = 0;
1673
+ while (index < length) {
1674
+ fxConcatStringC(the, result, "/");
1675
+ mxPushSlot(parts);
1676
+ mxGetIndex(index);
1677
+ fxConcatString(the, result, the->stack);
1678
+ mxPop();
1679
+ index++;
1680
+ }
1681
+ }
1682
+ }
1683
+ if (override == PATH_STATE)
1684
+ goto XS_URL_END;
1685
+
1686
+ XS_URL_QUERY:
1687
+ mxPushSlot(parts);
1688
+ mxGetID(xsID_query);
1689
+ if (!mxIsNull(the->stack)) {
1690
+ if (!override || the->stack->value.string[0])
1691
+ fxConcatStringC(the, result, "?");
1692
+ fxConcatString(the, result, the->stack);
1693
+ }
1694
+ mxPop();
1695
+ if (override)
1696
+ goto XS_URL_END;
1697
+
1698
+ XS_URL_FRAGMENT:
1699
+ mxPushSlot(parts);
1700
+ mxGetID(xsID_fragment);
1701
+ if (!mxIsNull(the->stack)) {
1702
+ if (!override || the->stack->value.string[0])
1703
+ fxConcatStringC(the, result, "#");
1704
+ fxConcatString(the, result, the->stack);
1705
+ }
1706
+ mxPop();
1707
+
1708
+ XS_URL_END:
1709
+ return;
1710
+ }
1711
+
1712
+ void fx_parseQuery(txMachine* the)
1713
+ {
1714
+ txSlot* result;
1715
+ txSlot* string;
1716
+ txSlot* pair;
1717
+ txSlot* push;
1718
+ txInteger offset, ampersand, equal;
1719
+ fxVars(the, 2);
1720
+ result = mxResult;
1721
+ string = mxArgv(0);
1722
+ pair = mxVarv(0);
1723
+ push = mxVarv(1);
1724
+
1725
+ fxNewArray(the, 0);
1726
+ mxPullSlot(result);
1727
+
1728
+ fxToString(the, string);
1729
+
1730
+ mxPushSlot(result);
1731
+ mxGetID(mxID(_push));
1732
+ mxPullSlot(push);
1733
+
1734
+ offset = 0;
1735
+ ampersand = 0;
1736
+ equal = 0;
1737
+ if (string->value.string[0] == '?') {
1738
+ offset++;
1739
+ ampersand++;
1740
+ equal++;
1741
+ }
1742
+ for (;;) {
1743
+ char c = string->value.string[offset];
1744
+ if ((c == 0) || (c == '&')) {
1745
+ if (offset > ampersand) {
1746
+ mxPushSlot(result);
1747
+ mxPushSlot(push);
1748
+ mxCall();
1749
+
1750
+ fxNewInstance(the);
1751
+ mxPullSlot(pair);
1752
+
1753
+ if (equal == ampersand)
1754
+ equal = offset;
1755
+ fx_parseQueryPlus(the, string, ampersand, equal);
1756
+ mxPushSlot(pair);
1757
+ mxSetID(mxID(_name));
1758
+ mxPop();
1759
+
1760
+ equal++;
1761
+
1762
+ if (equal < offset)
1763
+ fx_parseQueryPlus(the, string, equal, offset);
1764
+ else
1765
+ mxPush(mxEmptyString);
1766
+ mxPushSlot(pair);
1767
+ mxSetID(mxID(_value));
1768
+ mxPop();
1769
+
1770
+ mxPushSlot(pair);
1771
+ mxRunCount(1);
1772
+ mxPop();
1773
+ }
1774
+ if (c == 0)
1775
+ break;
1776
+ ampersand = offset + 1;
1777
+ equal = offset + 1;
1778
+ }
1779
+ else if (c == '=') {
1780
+ equal = offset;
1781
+ }
1782
+ offset++;
1783
+ }
1784
+ }
1785
+
1786
+ void fx_parseQueryPlus(txMachine* the, txSlot* string, txInteger from, txInteger to)
1787
+ {
1788
+ txString src;
1789
+ txString limit;
1790
+ txInteger length;
1791
+ txInteger c, d;
1792
+ txString dst;
1793
+ src = string->value.string + from;
1794
+ limit = string->value.string + to;
1795
+ length = 0;
1796
+ while (src < limit) {
1797
+ c = c_read8(src++);
1798
+ if (c == '%')
1799
+ fxParseHexEscape(&src, &d);
1800
+ length++;
1801
+ }
1802
+ length += 1;
1803
+ mxPushUndefined();
1804
+ the->stack->value.string = fxNewChunk(the, length);
1805
+ the->stack->kind = XS_STRING_KIND;
1806
+ src = string->value.string + from;
1807
+ limit = string->value.string + to;
1808
+ dst = the->stack->value.string;
1809
+ while ((src < limit)) {
1810
+ c = c_read8(src++);
1811
+ if (c == '%') {
1812
+ if (fxParseHexEscape(&src, &d))
1813
+ *dst++ = (char)d;
1814
+ else
1815
+ *dst++ = '%';
1816
+ }
1817
+ else if (c == '+')
1818
+ *dst++ = ' ';
1819
+ else
1820
+ *dst++ = (char)c;
1821
+ }
1822
+ *dst = 0;
1823
+ }
1824
+
1825
+ void fx_serializeQuery(txMachine* the)
1826
+ {
1827
+ txSlot* pairs;
1828
+ txSlot* pair;
1829
+ txSlot* result;
1830
+
1831
+ txInteger length, index;
1832
+ fxVars(the, 3);
1833
+ pairs = mxVarv(0);
1834
+ pair = mxVarv(1);
1835
+ result = mxVarv(2);
1836
+
1837
+ mxPushSlot(mxArgv(0));
1838
+ mxPullSlot(pairs);
1839
+
1840
+ mxPush(mxEmptyString);
1841
+ mxPullSlot(result);
1842
+
1843
+ mxPushSlot(pairs);
1844
+ mxGetID(mxID(_length));
1845
+ length = (txIndex)fxToLength(the, the->stack);
1846
+ mxPop();
1847
+
1848
+ index = 0;
1849
+ while (index < length) {
1850
+ if (index > 0)
1851
+ fxConcatStringC(the, result, "&");
1852
+ mxPushSlot(pairs);
1853
+ mxGetIndex(index);
1854
+ mxPullSlot(pair);
1855
+
1856
+ mxPushSlot(pair);
1857
+ mxGetID(mxID(_name));
1858
+ mxPullSlot(mxArgv(0));
1859
+ fx_serializeQueryPlus(the, (txString)gxFormSet);
1860
+ fxConcatString(the, result, mxResult);
1861
+
1862
+ fxConcatStringC(the, result, "=");
1863
+
1864
+ mxPushSlot(pair);
1865
+ mxGetID(mxID(_value));
1866
+ mxPullSlot(mxArgv(0));
1867
+ fx_serializeQueryPlus(the, (txString)gxFormSet);
1868
+ fxConcatString(the, result, mxResult);
1869
+ index++;
1870
+ }
1871
+
1872
+ *mxResult = *result;
1873
+ }
1874
+
1875
+ void fx_serializeQueryPlus(txMachine* the, txString theSet)
1876
+ {
1877
+ txString src;
1878
+ txInteger length;
1879
+ txBoolean same = 1;
1880
+ txInteger c;
1881
+ txString dst;
1882
+
1883
+ src = fxToString(the, mxArgv(0));
1884
+ length = 0;
1885
+ while (((src = mxStringByteDecode(src, &c))) && (c != C_EOF)) {
1886
+ if (c < 0x80) {
1887
+ if (c == ' ') {
1888
+ length += 1;
1889
+ same = 0;
1890
+ }
1891
+ else if (c_read8(theSet + c))
1892
+ length += 1;
1893
+ else {
1894
+ length += 3;
1895
+ same = 0;
1896
+ }
1897
+ }
1898
+ else {
1899
+ if (c < 0x800)
1900
+ length += 6;
1901
+ else if ((0xD800 <= c) && (c <= 0xDFFF))
1902
+ mxURIError("invalid string");
1903
+ else if (c < 0x10000)
1904
+ length += 9;
1905
+ else
1906
+ length += 12;
1907
+ same = 0;
1908
+ }
1909
+ }
1910
+ length += 1;
1911
+ if (same) {
1912
+ mxResult->value.string = mxArgv(0)->value.string;
1913
+ mxResult->kind = mxArgv(0)->kind;
1914
+ return;
1915
+ }
1916
+ mxResult->value.string = fxNewChunk(the, length);
1917
+ mxResult->kind = XS_STRING_KIND;
1918
+ src = mxArgv(0)->value.string;
1919
+ dst = mxResult->value.string;
1920
+ while (((src = mxStringByteDecode(src, &c))) && (c != C_EOF)) {
1921
+ if (c < 0x80) {
1922
+ if (c == ' ')
1923
+ *dst++ = '+';
1924
+ else if (c_read8(theSet + c))
1925
+ *dst++ = (char)c;
1926
+ else {
1927
+ *dst++ = '%';
1928
+ dst = fxStringifyHexEscape(dst, c);
1929
+ }
1930
+ }
1931
+ else if (c < 0x800) {
1932
+ *dst++ = '%';
1933
+ dst = fxStringifyHexEscape(dst, 0xC0 | (c >> 6));
1934
+ *dst++ = '%';
1935
+ dst = fxStringifyHexEscape(dst, 0x80 | (c & 0x3F));
1936
+ }
1937
+ else if (c < 0x10000) {
1938
+ *dst++ = '%';
1939
+ dst = fxStringifyHexEscape(dst, 0xE0 | (c >> 12));
1940
+ *dst++ = '%';
1941
+ dst = fxStringifyHexEscape(dst, 0x80 | ((c >> 6) & 0x3F));
1942
+ *dst++ = '%';
1943
+ dst = fxStringifyHexEscape(dst, 0x80 | (c & 0x3F));
1944
+ }
1945
+ else {
1946
+ *dst++ = '%';
1947
+ dst = fxStringifyHexEscape(dst, 0xF0 | (c >> 18));
1948
+ *dst++ = '%';
1949
+ dst = fxStringifyHexEscape(dst, 0x80 | ((c >> 12) & 0x3F));
1950
+ *dst++ = '%';
1951
+ dst = fxStringifyHexEscape(dst, 0x80 | ((c >> 6) & 0x3F));
1952
+ *dst++ = '%';
1953
+ dst = fxStringifyHexEscape(dst, 0x80 | (c & 0x3F));
1954
+ }
1955
+ }
1956
+ *dst = 0;
1957
+ }
1958
+
1959
+