/src/moddable/modules/data/base64/modBase64.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2016-2021 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 | | /* |
39 | | modeled on FskStrB64Decode and FskStrB64Encode from KPR. |
40 | | */ |
41 | | |
42 | | #include "xsmc.h" |
43 | | #include "xsHost.h" |
44 | | |
45 | | void xs_base64_encode(xsMachine *the) |
46 | 0 | { |
47 | 0 | static const char b64[] ICACHE_XS6RO2_ATTR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
48 | 0 | xsType srcType; |
49 | 0 | uint8_t *src, *dst; |
50 | 0 | uint32_t srcSize, dstSize; |
51 | 0 | uint8_t a, b, c; |
52 | |
|
53 | 0 | srcType = xsmcTypeOf(xsArg(0)); |
54 | 0 | if (xsStringType == srcType) { |
55 | 0 | src = (uint8_t *)xsmcToString(xsArg(0)); |
56 | 0 | srcSize = c_strlen((char *)src); |
57 | 0 | } |
58 | 0 | else |
59 | 0 | xsmcGetBufferReadable(xsArg(0), (void **)&src, &srcSize); |
60 | 0 | dstSize = (((srcSize + 2) / 3) * 4) + 1; |
61 | |
|
62 | 0 | xsResult = xsStringBuffer(NULL, dstSize); |
63 | 0 | if (xsStringType == srcType) |
64 | 0 | src = (uint8_t *)xsmcToString(xsArg(0)); // refresh pointer |
65 | 0 | else |
66 | 0 | xsmcGetBufferReadable(xsArg(0), (void **)&src, &srcSize); |
67 | 0 | dst = (uint8_t *)xsmcToString(xsResult); |
68 | |
|
69 | 0 | while (srcSize > 2) { |
70 | 0 | a = c_read8(src++); |
71 | 0 | b = c_read8(src++); |
72 | 0 | c = c_read8(src++); |
73 | 0 | *dst++ = c_read8(b64 + ((a & 0xfc) >> 2)); |
74 | 0 | *dst++ = c_read8(b64 + (((a & 0x3) << 4) | ((b & 0xf0) >> 4))); |
75 | 0 | *dst++ = c_read8(b64 + (((b & 0xf) << 2) | ((c & 0xc0) >> 6))); |
76 | 0 | *dst++ = c_read8(b64 + (c & 0x3f)); |
77 | 0 | srcSize -= 3; |
78 | 0 | } |
79 | |
|
80 | 0 | if (srcSize == 2) { |
81 | 0 | a = c_read8(src++); |
82 | 0 | b = c_read8(src++); |
83 | 0 | *dst++ = c_read8(b64 + ((a & 0xfc) >> 2)); |
84 | 0 | *dst++ = c_read8(b64 + (((a & 0x3) << 4) | ((b & 0xf0) >> 4))); |
85 | 0 | *dst++ = c_read8(b64 + ((b & 0xf) << 2)); |
86 | 0 | *dst++ = '='; |
87 | 0 | } |
88 | 0 | else if (srcSize == 1) { |
89 | 0 | a = c_read8(src++); |
90 | 0 | *dst++ = c_read8(b64 + ((a & 0xfc) >> 2)); |
91 | 0 | *dst++ = c_read8(b64 + ((a & 0x3) << 4)); |
92 | 0 | *dst++ = '='; |
93 | 0 | *dst++ = '='; |
94 | 0 | } |
95 | |
|
96 | 0 | *dst++ = 0; |
97 | 0 | } |
98 | | |
99 | | void xs_base64_decode(xsMachine *the) |
100 | 0 | { |
101 | 0 | uint8_t *src; |
102 | 0 | uint32_t srcSize, dstSize, srcIndex, dstIndex; |
103 | 0 | uint8_t aFlag = 0; |
104 | 0 | uint8_t aByte; |
105 | 0 | uint8_t aBuffer[4]; |
106 | 0 | uint8_t *dst, *dstStart; |
107 | |
|
108 | 0 | src = (uint8_t *)xsmcToString(xsArg(0)); |
109 | 0 | srcSize = c_strlen((char *)src); |
110 | |
|
111 | 0 | dstSize = (srcSize / 4) * 3; |
112 | 0 | if (c_read8(src + srcSize - 1) == '=') |
113 | 0 | dstSize--; |
114 | 0 | if (c_read8(src + srcSize - 2) == '=') |
115 | 0 | dstSize--; |
116 | 0 | srcIndex = 0; |
117 | |
|
118 | 0 | xsmcSetArrayBufferResizable(xsResult, NULL, dstSize, dstSize); |
119 | 0 | dst = dstStart = xsmcToArrayBuffer(xsResult); |
120 | |
|
121 | 0 | src = (uint8_t *)xsmcToString(xsArg(0)); // refresh pointer |
122 | |
|
123 | 0 | dstIndex = 3; |
124 | 0 | while ((aByte = c_read8(src++))) { |
125 | 0 | if (('A' <= aByte) && (aByte <= 'Z')) |
126 | 0 | aByte = aByte - 'A'; |
127 | 0 | else if (('a' <= aByte) && (aByte <= 'z')) |
128 | 0 | aByte = aByte - 'a' + 26; |
129 | 0 | else if (('0' <= aByte) && (aByte <= '9')) |
130 | 0 | aByte = aByte - '0' + 52; |
131 | 0 | else if (aByte == '+') |
132 | 0 | aByte = 62; |
133 | 0 | else if (aByte == '/') |
134 | 0 | aByte = 63; |
135 | 0 | else if (aByte == '=') { |
136 | 0 | if (srcIndex == 2) { |
137 | 0 | if (c_read8(src) == '=') { |
138 | 0 | aBuffer[srcIndex++] = 0; |
139 | 0 | dstIndex = 1; |
140 | 0 | aByte = 0; |
141 | 0 | aFlag = 1; |
142 | 0 | } |
143 | 0 | else |
144 | 0 | continue; |
145 | 0 | } |
146 | 0 | else if (srcIndex == 3) { |
147 | 0 | dstIndex = 2; |
148 | 0 | aByte = 0; |
149 | 0 | aFlag = 1; |
150 | 0 | } |
151 | 0 | else |
152 | 0 | continue; |
153 | 0 | } |
154 | 0 | else |
155 | 0 | continue; |
156 | 0 | aBuffer[srcIndex++] = aByte; |
157 | 0 | if (srcIndex == 4) { |
158 | 0 | *dst++ = (aBuffer[0] << 2) | ((aBuffer[1] & 0x30) >> 4); |
159 | 0 | if (dstIndex > 1) |
160 | 0 | *dst++ = ((aBuffer[1] & 0x0F) << 4) | ((aBuffer[2] & 0x3C) >> 2); |
161 | 0 | if (dstIndex > 2) |
162 | 0 | *dst++ = ((aBuffer[2] & 0x03) << 6) | (aBuffer[3] & 0x3F); |
163 | 0 | srcIndex = 0; |
164 | 0 | } |
165 | 0 | if (aFlag) |
166 | 0 | break; |
167 | 0 | } |
168 | |
|
169 | 0 | xsmcSetArrayBufferLength(xsResult, dst - dstStart); |
170 | 0 | } |
171 | | |
172 | | void modInstallBase64(xsMachine *the) |
173 | 0 | { |
174 | 0 | #define kNamespace (0) |
175 | 0 | #define kScratch (1) |
176 | |
|
177 | 0 | xsBeginHost(the); |
178 | 0 | xsmcVars(2); |
179 | |
|
180 | 0 | xsVar(kNamespace) = xsNewObject(); |
181 | 0 | xsmcDefine(xsGlobal, xsID("Base64"), xsVar(kNamespace), xsDontEnum); |
182 | 0 | xsVar(kScratch) = xsNewHostFunction(xs_base64_encode, 1); |
183 | 0 | xsmcDefine(xsVar(kNamespace), xsID("encode"), xsVar(kScratch), xsDontEnum); |
184 | 0 | xsVar(kScratch) = xsNewHostFunction(xs_base64_decode, 1); |
185 | 0 | xsmcDefine(xsVar(kNamespace), xsID("decode"), xsVar(kScratch), xsDontEnum); |
186 | |
|
187 | 0 | xsEndHost(the); |
188 | 0 | } |