modio.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /*
  2. * This file is part of the MicroPython project, http://micropython.org/
  3. *
  4. * The MIT License (MIT)
  5. *
  6. * Copyright (c) 2013, 2014 Damien P. George
  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. #include <assert.h>
  27. #include <string.h>
  28. #include "py/runtime.h"
  29. #include "py/builtin.h"
  30. #include "py/stream.h"
  31. #include "py/objstringio.h"
  32. #include "py/frozenmod.h"
  33. #if MICROPY_PY_IO
  34. extern const mp_obj_type_t mp_type_fileio;
  35. extern const mp_obj_type_t mp_type_textio;
  36. #if MICROPY_PY_IO_BUFFEREDWRITER
  37. typedef struct _mp_obj_bufwriter_t {
  38. mp_obj_base_t base;
  39. mp_obj_t stream;
  40. size_t alloc;
  41. size_t len;
  42. byte buf[0];
  43. } mp_obj_bufwriter_t;
  44. STATIC mp_obj_t bufwriter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
  45. mp_arg_check_num(n_args, n_kw, 2, 2, false);
  46. size_t alloc = mp_obj_get_int(args[1]);
  47. mp_obj_bufwriter_t *o = m_new_obj_var(mp_obj_bufwriter_t, byte, alloc);
  48. o->base.type = type;
  49. o->stream = args[0];
  50. o->alloc = alloc;
  51. o->len = 0;
  52. return o;
  53. }
  54. STATIC mp_uint_t bufwriter_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
  55. mp_obj_bufwriter_t *self = MP_OBJ_TO_PTR(self_in);
  56. mp_uint_t org_size = size;
  57. while (size > 0) {
  58. mp_uint_t rem = self->alloc - self->len;
  59. if (size < rem) {
  60. memcpy(self->buf + self->len, buf, size);
  61. self->len += size;
  62. return org_size;
  63. }
  64. // Buffer flushing policy here is to flush entire buffer all the time.
  65. // This allows e.g. to have a block device as backing storage and write
  66. // entire block to it. memcpy below is not ideal and could be optimized
  67. // in some cases. But the way it is now it at least ensures that buffer
  68. // is word-aligned, to guard against obscure cases when it matters, e.g.
  69. // https://github.com/micropython/micropython/issues/1863
  70. memcpy(self->buf + self->len, buf, rem);
  71. buf = (byte*)buf + rem;
  72. size -= rem;
  73. mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->alloc, errcode);
  74. if (*errcode != 0) {
  75. return MP_STREAM_ERROR;
  76. }
  77. // TODO: try to recover from a case of non-blocking stream, e.g. move
  78. // remaining chunk to the beginning of buffer.
  79. assert(out_sz == self->alloc);
  80. self->len = 0;
  81. }
  82. return org_size;
  83. }
  84. STATIC mp_obj_t bufwriter_flush(mp_obj_t self_in) {
  85. mp_obj_bufwriter_t *self = MP_OBJ_TO_PTR(self_in);
  86. if (self->len != 0) {
  87. int err;
  88. mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->len, &err);
  89. // TODO: try to recover from a case of non-blocking stream, e.g. move
  90. // remaining chunk to the beginning of buffer.
  91. assert(out_sz == self->len);
  92. self->len = 0;
  93. if (err != 0) {
  94. mp_raise_OSError(err);
  95. }
  96. }
  97. return mp_const_none;
  98. }
  99. STATIC MP_DEFINE_CONST_FUN_OBJ_1(bufwriter_flush_obj, bufwriter_flush);
  100. STATIC const mp_rom_map_elem_t bufwriter_locals_dict_table[] = {
  101. { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
  102. { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&bufwriter_flush_obj) },
  103. };
  104. STATIC MP_DEFINE_CONST_DICT(bufwriter_locals_dict, bufwriter_locals_dict_table);
  105. STATIC const mp_stream_p_t bufwriter_stream_p = {
  106. .write = bufwriter_write,
  107. };
  108. STATIC const mp_obj_type_t bufwriter_type = {
  109. { &mp_type_type },
  110. .name = MP_QSTR_BufferedWriter,
  111. .make_new = bufwriter_make_new,
  112. .protocol = &bufwriter_stream_p,
  113. .locals_dict = (mp_obj_dict_t*)&bufwriter_locals_dict,
  114. };
  115. #endif // MICROPY_PY_IO_BUFFEREDWRITER
  116. #if MICROPY_MODULE_FROZEN_STR
  117. STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) {
  118. VSTR_FIXED(path_buf, MICROPY_ALLOC_PATH_MAX);
  119. size_t len;
  120. // As an extension to pkg_resources.resource_stream(), we support
  121. // package parameter being None, the path_in is interpreted as a
  122. // raw path.
  123. if (package_in != mp_const_none) {
  124. mp_obj_t args[5];
  125. args[0] = package_in;
  126. args[1] = mp_const_none; // TODO should be globals
  127. args[2] = mp_const_none; // TODO should be locals
  128. args[3] = mp_const_true; // Pass sentinel "non empty" value to force returning of leaf module
  129. args[4] = MP_OBJ_NEW_SMALL_INT(0);
  130. // TODO lookup __import__ and call that instead of going straight to builtin implementation
  131. mp_obj_t pkg = mp_builtin___import__(5, args);
  132. mp_obj_t dest[2];
  133. mp_load_method_maybe(pkg, MP_QSTR___path__, dest);
  134. if (dest[0] == MP_OBJ_NULL) {
  135. mp_raise_TypeError(NULL);
  136. }
  137. const char *path = mp_obj_str_get_data(dest[0], &len);
  138. vstr_add_strn(&path_buf, path, len);
  139. vstr_add_byte(&path_buf, '/');
  140. }
  141. const char *path = mp_obj_str_get_data(path_in, &len);
  142. vstr_add_strn(&path_buf, path, len);
  143. len = path_buf.len;
  144. const char *data = mp_find_frozen_str(path_buf.buf, &len);
  145. if (data != NULL) {
  146. mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t);
  147. o->base.type = &mp_type_bytesio;
  148. o->vstr = m_new_obj(vstr_t);
  149. vstr_init_fixed_buf(o->vstr, len + 1, (char*)data);
  150. o->vstr->len = len;
  151. o->pos = 0;
  152. return MP_OBJ_FROM_PTR(o);
  153. }
  154. mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len, false);
  155. return mp_builtin_open(1, &path_out, (mp_map_t*)&mp_const_empty_map);
  156. }
  157. MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream);
  158. #endif
  159. STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = {
  160. { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uio) },
  161. // Note: mp_builtin_open_obj should be defined by port, it's not
  162. // part of the core.
  163. { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) },
  164. #if MICROPY_PY_IO_RESOURCE_STREAM
  165. { MP_ROM_QSTR(MP_QSTR_resource_stream), MP_ROM_PTR(&resource_stream_obj) },
  166. #endif
  167. #if MICROPY_PY_IO_FILEIO
  168. { MP_ROM_QSTR(MP_QSTR_FileIO), MP_ROM_PTR(&mp_type_fileio) },
  169. #if MICROPY_CPYTHON_COMPAT
  170. { MP_ROM_QSTR(MP_QSTR_TextIOWrapper), MP_ROM_PTR(&mp_type_textio) },
  171. #endif
  172. #endif
  173. { MP_ROM_QSTR(MP_QSTR_StringIO), MP_ROM_PTR(&mp_type_stringio) },
  174. #if MICROPY_PY_IO_BYTESIO
  175. { MP_ROM_QSTR(MP_QSTR_BytesIO), MP_ROM_PTR(&mp_type_bytesio) },
  176. #endif
  177. #if MICROPY_PY_IO_BUFFEREDWRITER
  178. { MP_ROM_QSTR(MP_QSTR_BufferedWriter), MP_ROM_PTR(&bufwriter_type) },
  179. #endif
  180. };
  181. STATIC MP_DEFINE_CONST_DICT(mp_module_io_globals, mp_module_io_globals_table);
  182. const mp_obj_module_t mp_module_io = {
  183. .base = { &mp_type_module },
  184. .globals = (mp_obj_dict_t*)&mp_module_io_globals,
  185. };
  186. #endif