1
1
/*
2
- * This file is part of the Micro Python project, http://micropython.org/
2
+ * This file is part of the MicroPython project, http://micropython.org/
3
3
*
4
4
* The MIT License (MIT)
5
5
*
@@ -82,47 +82,38 @@ STATIC mp_uint_t get_fmt_num(const char **p) {
82
82
return val ;
83
83
}
84
84
85
- STATIC uint calcsize_items (const char * fmt ) {
86
- uint cnt = 0 ;
87
- while (* fmt ) {
88
- int num = 1 ;
89
- if (unichar_isdigit (* fmt )) {
90
- num = get_fmt_num (& fmt );
91
- if (* fmt == 's' ) {
92
- num = 1 ;
93
- }
94
- }
95
- cnt += num ;
96
- fmt ++ ;
97
- }
98
- return cnt ;
99
- }
100
-
101
- STATIC mp_obj_t struct_calcsize (mp_obj_t fmt_in ) {
102
- const char * fmt = mp_obj_str_get_str (fmt_in );
85
+ STATIC size_t calc_size_items (const char * fmt , size_t * total_sz ) {
103
86
char fmt_type = get_fmt_type (& fmt );
104
- mp_uint_t size ;
87
+ size_t total_cnt = 0 ;
88
+ size_t size ;
105
89
for (size = 0 ; * fmt ; fmt ++ ) {
106
90
mp_uint_t cnt = 1 ;
107
91
if (unichar_isdigit (* fmt )) {
108
92
cnt = get_fmt_num (& fmt );
109
93
}
110
94
111
95
if (* fmt == 's' ) {
96
+ total_cnt += 1 ;
112
97
size += cnt ;
113
98
} else {
99
+ total_cnt += cnt ;
114
100
mp_uint_t align ;
115
101
size_t sz = mp_binary_get_size (fmt_type , * fmt , & align );
116
- if (sz == 0 ) {
117
- mp_raise_ValueError ("unsupported format" );
118
- }
119
102
while (cnt -- ) {
120
103
// Apply alignment
121
104
size = (size + align - 1 ) & ~(align - 1 );
122
105
size += sz ;
123
106
}
124
107
}
125
108
}
109
+ * total_sz = size ;
110
+ return total_cnt ;
111
+ }
112
+
113
+ STATIC mp_obj_t struct_calcsize (mp_obj_t fmt_in ) {
114
+ const char * fmt = mp_obj_str_get_str (fmt_in );
115
+ size_t size ;
116
+ calc_size_items (fmt , & size );
126
117
return MP_OBJ_NEW_SMALL_INT (size );
127
118
}
128
119
MP_DEFINE_CONST_FUN_OBJ_1 (struct_calcsize_obj , struct_calcsize );
@@ -133,8 +124,9 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) {
133
124
// Since we implement unpack and unpack_from using the same function
134
125
// we relax the "exact" requirement, and only implement "big enough".
135
126
const char * fmt = mp_obj_str_get_str (args [0 ]);
127
+ size_t total_sz ;
128
+ size_t num_items = calc_size_items (fmt , & total_sz );
136
129
char fmt_type = get_fmt_type (& fmt );
137
- uint num_items = calcsize_items (fmt );
138
130
mp_obj_tuple_t * res = MP_OBJ_TO_PTR (mp_obj_new_tuple (num_items , NULL ));
139
131
mp_buffer_info_t bufinfo ;
140
132
mp_get_buffer_raise (args [1 ], & bufinfo , MP_BUFFER_READ );
@@ -155,21 +147,23 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) {
155
147
p += offset ;
156
148
}
157
149
158
- for (uint i = 0 ; i < num_items ;) {
159
- mp_uint_t sz = 1 ;
150
+ // Check that the input buffer is big enough to unpack all the values
151
+ if (p + total_sz > end_p ) {
152
+ mp_raise_ValueError ("buffer too small" );
153
+ }
154
+
155
+ for (size_t i = 0 ; i < num_items ;) {
156
+ mp_uint_t cnt = 1 ;
160
157
if (unichar_isdigit (* fmt )) {
161
- sz = get_fmt_num (& fmt );
162
- }
163
- if (p + sz > end_p ) {
164
- mp_raise_ValueError ("buffer too small" );
158
+ cnt = get_fmt_num (& fmt );
165
159
}
166
160
mp_obj_t item ;
167
161
if (* fmt == 's' ) {
168
- item = mp_obj_new_bytes (p , sz );
169
- p += sz ;
162
+ item = mp_obj_new_bytes (p , cnt );
163
+ p += cnt ;
170
164
res -> items [i ++ ] = item ;
171
165
} else {
172
- while (sz -- ) {
166
+ while (cnt -- ) {
173
167
item = mp_binary_get_val (fmt_type , * fmt , & p );
174
168
res -> items [i ++ ] = item ;
175
169
}
@@ -180,36 +174,35 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) {
180
174
}
181
175
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (struct_unpack_from_obj , 2 , 3 , struct_unpack_from );
182
176
183
- STATIC void struct_pack_into_internal (mp_obj_t fmt_in , byte * p , byte * end_p , size_t n_args , const mp_obj_t * args ) {
177
+ // This function assumes there is enough room in p to store all the values
178
+ STATIC void struct_pack_into_internal (mp_obj_t fmt_in , byte * p , size_t n_args , const mp_obj_t * args ) {
184
179
const char * fmt = mp_obj_str_get_str (fmt_in );
185
180
char fmt_type = get_fmt_type (& fmt );
186
181
187
182
size_t i ;
188
183
for (i = 0 ; i < n_args ;) {
189
- mp_uint_t sz = 1 ;
184
+ mp_uint_t cnt = 1 ;
190
185
if (* fmt == '\0' ) {
191
186
// more arguments given than used by format string; CPython raises struct.error here
192
187
break ;
193
188
}
194
189
if (unichar_isdigit (* fmt )) {
195
- sz = get_fmt_num (& fmt );
196
- }
197
- if (p + sz > end_p ) {
198
- mp_raise_ValueError ("buffer too small" );
190
+ cnt = get_fmt_num (& fmt );
199
191
}
200
192
201
193
if (* fmt == 's' ) {
202
194
mp_buffer_info_t bufinfo ;
203
195
mp_get_buffer_raise (args [i ++ ], & bufinfo , MP_BUFFER_READ );
204
- mp_uint_t to_copy = sz ;
196
+ mp_uint_t to_copy = cnt ;
205
197
if (bufinfo .len < to_copy ) {
206
198
to_copy = bufinfo .len ;
207
199
}
208
200
memcpy (p , bufinfo .buf , to_copy );
209
- memset (p + to_copy , 0 , sz - to_copy );
210
- p += sz ;
201
+ memset (p + to_copy , 0 , cnt - to_copy );
202
+ p += cnt ;
211
203
} else {
212
- while (sz -- ) {
204
+ // If we run out of args then we just finish; CPython would raise struct.error
205
+ while (cnt -- && i < n_args ) {
213
206
mp_binary_set_val (fmt_type , * fmt , args [i ++ ], & p );
214
207
}
215
208
}
@@ -224,8 +217,7 @@ STATIC mp_obj_t struct_pack(size_t n_args, const mp_obj_t *args) {
224
217
vstr_init_len (& vstr , size );
225
218
byte * p = (byte * )vstr .buf ;
226
219
memset (p , 0 , size );
227
- byte * end_p = & p [size ];
228
- struct_pack_into_internal (args [0 ], p , end_p , n_args - 1 , & args [1 ]);
220
+ struct_pack_into_internal (args [0 ], p , n_args - 1 , & args [1 ]);
229
221
return mp_obj_new_str_from_vstr (& mp_type_bytes , & vstr );
230
222
}
231
223
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (struct_pack_obj , 1 , MP_OBJ_FUN_ARGS_MAX , struct_pack );
@@ -245,7 +237,13 @@ STATIC mp_obj_t struct_pack_into(size_t n_args, const mp_obj_t *args) {
245
237
byte * end_p = & p [bufinfo .len ];
246
238
p += offset ;
247
239
248
- struct_pack_into_internal (args [0 ], p , end_p , n_args - 3 , & args [3 ]);
240
+ // Check that the output buffer is big enough to hold all the values
241
+ mp_int_t sz = MP_OBJ_SMALL_INT_VALUE (struct_calcsize (args [0 ]));
242
+ if (p + sz > end_p ) {
243
+ mp_raise_ValueError ("buffer too small" );
244
+ }
245
+
246
+ struct_pack_into_internal (args [0 ], p , n_args - 3 , & args [3 ]);
249
247
return mp_const_none ;
250
248
}
251
249
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (struct_pack_into_obj , 3 , MP_OBJ_FUN_ARGS_MAX , struct_pack_into );
0 commit comments