@@ -108,7 +108,8 @@ STATIC MP_DEFINE_CONST_OBJ_TYPE(
108
108
109
109
#endif // MICROPY_PY_IO_IOBASE
110
110
111
- #if MICROPY_PY_IO_BUFFEREDWRITER
111
+ #if MICROPY_PY_IO_BUFFEREDWRITER || MICROPY_PY_IO_BUFFEREDREADER
112
+ // The structure and the new method are shared by reader and writer
112
113
typedef struct _mp_obj_bufwriter_t {
113
114
mp_obj_base_t base ;
114
115
mp_obj_t stream ;
@@ -129,6 +130,9 @@ STATIC mp_obj_t bufwriter_make_new(const mp_obj_type_t *type, size_t n_args, siz
129
130
return o ;
130
131
}
131
132
133
+ #endif // MICROPY_PY_IO_BUFFEREDWRITER || MICROPY_PY_IO_BUFFEREDREADER
134
+
135
+ #if MICROPY_PY_IO_BUFFEREDWRITER
132
136
// Writes out the data stored in the buffer so far
133
137
STATIC int bufwriter_do_write (mp_obj_bufwriter_t * self ) {
134
138
int rv = 0 ;
@@ -240,6 +244,84 @@ STATIC MP_DEFINE_CONST_OBJ_TYPE(
240
244
);
241
245
#endif // MICROPY_PY_IO_BUFFEREDWRITER
242
246
247
+ #if MICROPY_PY_IO_BUFFEREDREADER
248
+ STATIC mp_uint_t bufreader_read (mp_obj_t self_in , void * buf , mp_uint_t size , int * errcode ) {
249
+ mp_obj_bufwriter_t * self = MP_OBJ_TO_PTR (self_in );
250
+
251
+ mp_uint_t org_size = size ;
252
+ // Cache this value since it should not change thus avoiding a dereference
253
+ size_t alloc = self -> alloc ;
254
+
255
+ * errcode = self -> error ;
256
+ self -> error = 0 ;
257
+
258
+ while (* errcode == 0 && size > 0 ) {
259
+ // Buffer filling policy here is to fill the entire buffer all the time.
260
+ // This allows e.g. to have a block device as backing storage and read
261
+ // entire blocks from it. memcpy below is not ideal and could be
262
+ // optimized in some cases. But the way it is now it at least ensures
263
+ // that buffer is word-aligned, to guard against obscure cases when it
264
+ // matters, e.g.
265
+ // https://github.com/micropython/micropython/issues/1863
266
+
267
+ // Buffer needs to have at least one byte
268
+ if (self -> len == 0 ) {
269
+ self -> len = mp_stream_read_exactly (self -> stream , self -> buf , alloc , errcode );
270
+ if (self -> len < alloc ) {
271
+ // If no data was read stop the loop as it is either an error or an EOF
272
+ // This check is moved here because it speeds up the more common case
273
+ // where the buffer was completely filled.
274
+ if (self -> len == 0 ) {
275
+ break ;
276
+ }
277
+ // Buffers may overlap, therefore we use memmove instead of memcpy
278
+ memmove (self -> buf + (alloc - self -> len ), self -> buf , self -> len );
279
+ }
280
+ }
281
+ mp_uint_t rem = MIN (self -> len , size );
282
+ memcpy (buf , self -> buf + (alloc - self -> len ), rem );
283
+ self -> len -= rem ;
284
+ buf = (byte * )buf + rem ;
285
+ size -= rem ;
286
+ }
287
+
288
+ // If there is a prior error
289
+ if (* errcode != 0 ) {
290
+ // If no data was read return it
291
+ if (size == org_size ) {
292
+ return MP_STREAM_ERROR ;
293
+ }
294
+ // Otherwise save it so we can fail on the next call
295
+ self -> error = * errcode ;
296
+ * errcode = 0 ;
297
+ }
298
+
299
+ // Return the data that has been read so far
300
+ return org_size - size ;
301
+ }
302
+
303
+ STATIC const mp_rom_map_elem_t bufreader_locals_dict_table [] = {
304
+ { MP_ROM_QSTR (MP_QSTR_read ), MP_ROM_PTR (& mp_stream_read_obj ) },
305
+ { MP_ROM_QSTR (MP_QSTR_readinto ), MP_ROM_PTR (& mp_stream_readinto_obj ) },
306
+ { MP_ROM_QSTR (MP_QSTR_readline ), MP_ROM_PTR (& mp_stream_unbuffered_readline_obj ) },
307
+ };
308
+ STATIC MP_DEFINE_CONST_DICT (bufreader_locals_dict , bufreader_locals_dict_table );
309
+
310
+ STATIC const mp_stream_p_t bufreader_stream_p = {
311
+ .read = bufreader_read ,
312
+ };
313
+
314
+ STATIC MP_DEFINE_CONST_OBJ_TYPE (
315
+ mp_type_bufreader ,
316
+ MP_QSTR_BufferedReader ,
317
+ MP_TYPE_FLAG_NONE ,
318
+ make_new , bufwriter_make_new ,
319
+ protocol , & bufreader_stream_p ,
320
+ locals_dict , & bufreader_locals_dict
321
+ );
322
+ #endif // MICROPY_PY_IO_BUFFEREDREADER
323
+
324
+
243
325
STATIC const mp_rom_map_elem_t mp_module_io_globals_table [] = {
244
326
{ MP_ROM_QSTR (MP_QSTR___name__ ), MP_ROM_QSTR (MP_QSTR_io ) },
245
327
// Note: mp_builtin_open_obj should be defined by port, it's not
@@ -255,6 +337,9 @@ STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = {
255
337
#if MICROPY_PY_IO_BUFFEREDWRITER
256
338
{ MP_ROM_QSTR (MP_QSTR_BufferedWriter ), MP_ROM_PTR (& mp_type_bufwriter ) },
257
339
#endif
340
+ #if MICROPY_PY_IO_BUFFEREDREADER
341
+ { MP_ROM_QSTR (MP_QSTR_BufferedReader ), MP_ROM_PTR (& mp_type_bufreader ) },
342
+ #endif
258
343
};
259
344
260
345
STATIC MP_DEFINE_CONST_DICT (mp_module_io_globals , mp_module_io_globals_table );
0 commit comments