Branch data Line data Source code
1 : : /*
2 : : * This file is part of the MicroPython project, http://micropython.org/
3 : : *
4 : : * The MIT License (MIT)
5 : : *
6 : : * Copyright (c) 2014 Paul Sokolovsky
7 : : *
8 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
9 : : * of this software and associated documentation files (the "Software"), to deal
10 : : * in the Software without restriction, including without limitation the rights
11 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : : * copies of the Software, and to permit persons to whom the Software is
13 : : * furnished to do so, subject to the following conditions:
14 : : *
15 : : * The above copyright notice and this permission notice shall be included in
16 : : * all copies or substantial portions of the Software.
17 : : *
18 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 : : * THE SOFTWARE.
25 : : */
26 : :
27 : : #include <stdio.h>
28 : : #include <assert.h>
29 : : #include <string.h>
30 : :
31 : : #include "py/runtime.h"
32 : : #include "py/binary.h"
33 : : #include "py/objstr.h"
34 : :
35 : : #if MICROPY_PY_BINASCII
36 : :
37 : : #if MICROPY_PY_BUILTINS_BYTES_HEX
38 : 12 : static mp_obj_t bytes_hex_as_bytes(size_t n_args, const mp_obj_t *args) {
39 : 12 : return mp_obj_bytes_hex(n_args, args, &mp_type_bytes);
40 : : }
41 : : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_hex_as_bytes_obj, 1, 2, bytes_hex_as_bytes);
42 : :
43 : 12 : static mp_obj_t bytes_fromhex_bytes(mp_obj_t data) {
44 : 12 : return mp_obj_bytes_fromhex(MP_OBJ_FROM_PTR(&mp_type_bytes), data);
45 : : }
46 : : static MP_DEFINE_CONST_FUN_OBJ_1(bytes_fromhex_obj, bytes_fromhex_bytes);
47 : : #endif
48 : :
49 : : // If ch is a character in the base64 alphabet, and is not a pad character, then
50 : : // the corresponding integer between 0 and 63, inclusively, is returned.
51 : : // Otherwise, -1 is returned.
52 : 268 : static int mod_binascii_sextet(byte ch) {
53 [ + + + + : 268 : if (ch >= 'A' && ch <= 'Z') {
+ + ]
54 : 90 : return ch - 'A';
55 : : } else if (ch >= 'a' && ch <= 'z') {
56 : 112 : return ch - 'a' + 26;
57 : : } else if (ch >= '0' && ch <= '9') {
58 : 28 : return ch - '0' + 52;
59 : : } else if (ch == '+') {
60 : : return 62;
61 : : } else if (ch == '/') {
62 : 2 : return 63;
63 : : } else {
64 : 34 : return -1;
65 : : }
66 : : }
67 : :
68 : 42 : static mp_obj_t mod_binascii_a2b_base64(mp_obj_t data) {
69 : 42 : mp_buffer_info_t bufinfo;
70 : 42 : mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
71 : 42 : byte *in = bufinfo.buf;
72 : :
73 : 42 : vstr_t vstr;
74 : 42 : vstr_init(&vstr, (bufinfo.len * 3) / 4 + 1); // Potentially over-allocate
75 : 42 : byte *out = (byte *)vstr.buf;
76 : :
77 : 42 : uint shift = 0;
78 : 42 : int nbits = 0; // Number of meaningful bits in shift
79 : 42 : bool hadpad = false; // Had a pad character since last valid character
80 [ + + ]: 310 : for (size_t i = 0; i < bufinfo.len; i++) {
81 [ + + ]: 280 : if (in[i] == '=') {
82 [ + + + + ]: 38 : if ((nbits == 2) || ((nbits == 4) && hadpad)) {
83 : : nbits = 0;
84 : : break;
85 : : }
86 : : hadpad = true;
87 : : }
88 : :
89 : 268 : int sextet = mod_binascii_sextet(in[i]);
90 [ + + ]: 268 : if (sextet == -1) {
91 : 34 : continue;
92 : : }
93 : 234 : hadpad = false;
94 : 234 : shift = (shift << 6) | sextet;
95 : 234 : nbits += 6;
96 : :
97 [ + + ]: 234 : if (nbits >= 8) {
98 : 168 : nbits -= 8;
99 : 168 : out[vstr.len++] = (shift >> nbits) & 0xFF;
100 : : }
101 : : }
102 : :
103 [ + + ]: 42 : if (nbits) {
104 : 8 : mp_raise_ValueError(MP_ERROR_TEXT("incorrect padding"));
105 : : }
106 : :
107 : 34 : return mp_obj_new_bytes_from_vstr(&vstr);
108 : : }
109 : : static MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_a2b_base64_obj, mod_binascii_a2b_base64);
110 : :
111 : 28 : static mp_obj_t mod_binascii_b2a_base64(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
112 : 28 : enum { ARG_newline };
113 : 28 : static const mp_arg_t allowed_args[] = {
114 : : { MP_QSTR_newline, MP_ARG_BOOL, {.u_bool = true} },
115 : : };
116 : :
117 : 28 : mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
118 : 28 : mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
119 : 28 : uint8_t newline = args[ARG_newline].u_bool;
120 : 28 : mp_buffer_info_t bufinfo;
121 : 28 : mp_get_buffer_raise(pos_args[0], &bufinfo, MP_BUFFER_READ);
122 : :
123 : 28 : vstr_t vstr;
124 [ + + ]: 28 : vstr_init_len(&vstr, ((bufinfo.len != 0) ? (((bufinfo.len - 1) / 3) + 1) * 4 : 0) + newline);
125 : :
126 : : // First pass, we convert input buffer to numeric base 64 values
127 : 28 : byte *in = bufinfo.buf, *out = (byte *)vstr.buf;
128 : 28 : mp_uint_t i;
129 [ + + ]: 66 : for (i = bufinfo.len; i >= 3; i -= 3) {
130 : 38 : *out++ = (in[0] & 0xFC) >> 2;
131 : 38 : *out++ = (in[0] & 0x03) << 4 | (in[1] & 0xF0) >> 4;
132 : 38 : *out++ = (in[1] & 0x0F) << 2 | (in[2] & 0xC0) >> 6;
133 : 38 : *out++ = in[2] & 0x3F;
134 : 38 : in += 3;
135 : : }
136 [ + + ]: 28 : if (i != 0) {
137 : 12 : *out++ = (in[0] & 0xFC) >> 2;
138 [ + + ]: 12 : if (i == 2) {
139 : 8 : *out++ = (in[0] & 0x03) << 4 | (in[1] & 0xF0) >> 4;
140 : 8 : *out++ = (in[1] & 0x0F) << 2;
141 : : } else {
142 : 4 : *out++ = (in[0] & 0x03) << 4;
143 : 4 : *out++ = 64;
144 : : }
145 : 12 : *out = 64;
146 : : }
147 : :
148 : : // Second pass, we convert number base 64 values to actual base64 ascii encoding
149 : 28 : out = (byte *)vstr.buf;
150 [ + + ]: 228 : for (mp_uint_t j = vstr.len - newline; j--;) {
151 [ + + ]: 200 : if (*out < 26) {
152 : 92 : *out += 'A';
153 [ + + ]: 108 : } else if (*out < 52) {
154 : 68 : *out += 'a' - 26;
155 [ + + ]: 40 : } else if (*out < 62) {
156 : 20 : *out += '0' - 52;
157 [ + + ]: 20 : } else if (*out == 62) {
158 : 2 : *out = '+';
159 [ + + ]: 18 : } else if (*out == 63) {
160 : 2 : *out = '/';
161 : : } else {
162 : 16 : *out = '=';
163 : : }
164 : 200 : out++;
165 : : }
166 [ + + ]: 28 : if (newline) {
167 : 26 : *out = '\n';
168 : : }
169 : 28 : return mp_obj_new_bytes_from_vstr(&vstr);
170 : : }
171 : : static MP_DEFINE_CONST_FUN_OBJ_KW(mod_binascii_b2a_base64_obj, 1, mod_binascii_b2a_base64);
172 : :
173 : : #if MICROPY_PY_BINASCII_CRC32 && MICROPY_PY_DEFLATE
174 : : #include "lib/uzlib/uzlib.h"
175 : :
176 : 24 : static mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) {
177 : 24 : mp_buffer_info_t bufinfo;
178 : 24 : mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
179 [ + + ]: 24 : uint32_t crc = (n_args > 1) ? mp_obj_get_int_truncated(args[1]) : 0;
180 : 24 : crc = uzlib_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff);
181 : 24 : return mp_obj_new_int_from_uint(crc ^ 0xffffffff);
182 : : }
183 : : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj, 1, 2, mod_binascii_crc32);
184 : : #endif
185 : :
186 : : static const mp_rom_map_elem_t mp_module_binascii_globals_table[] = {
187 : : { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_binascii) },
188 : : #if MICROPY_PY_BUILTINS_BYTES_HEX
189 : : { MP_ROM_QSTR(MP_QSTR_hexlify), MP_ROM_PTR(&bytes_hex_as_bytes_obj) },
190 : : { MP_ROM_QSTR(MP_QSTR_unhexlify), MP_ROM_PTR(&bytes_fromhex_obj) },
191 : : #endif
192 : : { MP_ROM_QSTR(MP_QSTR_a2b_base64), MP_ROM_PTR(&mod_binascii_a2b_base64_obj) },
193 : : { MP_ROM_QSTR(MP_QSTR_b2a_base64), MP_ROM_PTR(&mod_binascii_b2a_base64_obj) },
194 : : #if MICROPY_PY_BINASCII_CRC32 && MICROPY_PY_DEFLATE
195 : : { MP_ROM_QSTR(MP_QSTR_crc32), MP_ROM_PTR(&mod_binascii_crc32_obj) },
196 : : #endif
197 : : };
198 : :
199 : : static MP_DEFINE_CONST_DICT(mp_module_binascii_globals, mp_module_binascii_globals_table);
200 : :
201 : : const mp_obj_module_t mp_module_binascii = {
202 : : .base = { &mp_type_module },
203 : : .globals = (mp_obj_dict_t *)&mp_module_binascii_globals,
204 : : };
205 : :
206 : : MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_binascii, mp_module_binascii);
207 : :
208 : : #endif // MICROPY_PY_BINASCII
|