mp_flipper_fileio.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. #include <stdio.h>
  2. #include <stdbool.h>
  3. #include <stdint.h>
  4. #include <string.h>
  5. #include "py/obj.h"
  6. #include "py/stream.h"
  7. #include "py/runtime.h"
  8. #include "py/mperrno.h"
  9. #include "mp_flipper_fileio.h"
  10. extern const mp_obj_type_t mp_flipper_binary_fileio_type;
  11. extern const mp_obj_type_t mp_flipper_text_fileio_type;
  12. typedef struct _mp_flipper_fileio_file_descriptor_t {
  13. mp_obj_base_t base;
  14. void* handle;
  15. mp_obj_t name;
  16. uint8_t access_mode;
  17. uint8_t open_mode;
  18. } mp_flipper_fileio_file_descriptor_t;
  19. void* mp_flipper_file_new_file_descriptor(void* handle, const char* name, uint8_t access_mode, uint8_t open_mode, bool is_text) {
  20. mp_flipper_fileio_file_descriptor_t* fd = mp_obj_malloc_with_finaliser(
  21. mp_flipper_fileio_file_descriptor_t, is_text ? &mp_flipper_text_fileio_type : &mp_flipper_binary_fileio_type);
  22. fd->handle = handle;
  23. fd->name = mp_obj_new_str(name, strlen(name));
  24. fd->access_mode = access_mode;
  25. fd->open_mode = open_mode;
  26. return fd;
  27. }
  28. static mp_uint_t mp_flipper_fileio_read(mp_obj_t self, void* buf, mp_uint_t size, int* errcode) {
  29. mp_flipper_fileio_file_descriptor_t* fd = MP_OBJ_TO_PTR(self);
  30. if(fd->handle == NULL) {
  31. *errcode = MP_EIO;
  32. return MP_STREAM_ERROR;
  33. }
  34. return mp_flipper_file_read(fd->handle, buf, size, errcode);
  35. }
  36. static mp_uint_t mp_flipper_fileio_write(mp_obj_t self, const void* buf, mp_uint_t size, int* errcode) {
  37. mp_flipper_fileio_file_descriptor_t* fd = MP_OBJ_TO_PTR(self);
  38. if(fd->handle == NULL) {
  39. *errcode = MP_EIO;
  40. return MP_STREAM_ERROR;
  41. }
  42. return mp_flipper_file_write(fd->handle, buf, size, errcode);
  43. }
  44. static mp_uint_t mp_flipper_fileio_ioctl(mp_obj_t self, mp_uint_t request, uintptr_t arg, int* errcode) {
  45. mp_flipper_fileio_file_descriptor_t* fd = MP_OBJ_TO_PTR(self);
  46. if(fd->handle == NULL) {
  47. *errcode = MP_EIO;
  48. return MP_STREAM_ERROR;
  49. }
  50. if(request == MP_STREAM_SEEK) {
  51. struct mp_stream_seek_t* seek = (struct mp_stream_seek_t*)(uintptr_t)arg;
  52. size_t position;
  53. bool success;
  54. switch(seek->whence) {
  55. case MP_SEEK_SET:
  56. mp_flipper_file_seek(fd->handle, seek->offset);
  57. break;
  58. case MP_SEEK_CUR:
  59. position = mp_flipper_file_tell(fd->handle);
  60. mp_flipper_file_seek(fd->handle, position + seek->offset);
  61. break;
  62. case MP_SEEK_END:
  63. position = mp_flipper_file_size(fd->handle);
  64. mp_flipper_file_seek(fd->handle, position + seek->offset);
  65. break;
  66. }
  67. seek->offset = mp_flipper_file_tell(fd->handle);
  68. return 0;
  69. }
  70. if(request == MP_STREAM_FLUSH) {
  71. if(!mp_flipper_file_sync(fd->handle)) {
  72. *errcode = MP_EIO;
  73. return MP_STREAM_ERROR;
  74. }
  75. return 0;
  76. }
  77. if(request == MP_STREAM_CLOSE) {
  78. if(!mp_flipper_file_close(fd->handle)) {
  79. *errcode = MP_EIO;
  80. fd->handle = NULL;
  81. return MP_STREAM_ERROR;
  82. }
  83. fd->handle = NULL;
  84. return 0;
  85. }
  86. *errcode = MP_EINVAL;
  87. return MP_STREAM_ERROR;
  88. }
  89. static mp_obj_t mp_flipper_fileio_name(mp_obj_t self) {
  90. mp_flipper_fileio_file_descriptor_t* fd = MP_OBJ_TO_PTR(self);
  91. return fd->name;
  92. }
  93. static MP_DEFINE_CONST_FUN_OBJ_1(mp_flipper_fileio_name_obj, mp_flipper_fileio_name);
  94. static mp_obj_t mp_flipper_fileio_readable(mp_obj_t self) {
  95. mp_flipper_fileio_file_descriptor_t* fd = MP_OBJ_TO_PTR(self);
  96. return (fd->access_mode & MP_FLIPPER_FILE_ACCESS_MODE_READ) ? mp_const_true : mp_const_false;
  97. }
  98. static MP_DEFINE_CONST_FUN_OBJ_1(mp_flipper_fileio_readable_obj, mp_flipper_fileio_readable);
  99. static mp_obj_t mp_flipper_fileio_writable(mp_obj_t self) {
  100. mp_flipper_fileio_file_descriptor_t* fd = MP_OBJ_TO_PTR(self);
  101. return (fd->access_mode & MP_FLIPPER_FILE_ACCESS_MODE_WRITE) ? mp_const_true : mp_const_false;
  102. }
  103. static MP_DEFINE_CONST_FUN_OBJ_1(mp_flipper_fileio_writable_obj, mp_flipper_fileio_writable);
  104. static const mp_map_elem_t mp_flipper_file_locals_dict_table[] = {
  105. {MP_OBJ_NEW_QSTR(MP_QSTR_name), MP_ROM_PTR(&mp_flipper_fileio_name_obj)},
  106. {MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj)},
  107. {MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)},
  108. {MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj)},
  109. {MP_OBJ_NEW_QSTR(MP_QSTR_readable), MP_ROM_PTR(&mp_flipper_fileio_readable_obj)},
  110. {MP_OBJ_NEW_QSTR(MP_QSTR_writable), MP_ROM_PTR(&mp_flipper_fileio_writable_obj)},
  111. {MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj)},
  112. {MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj)},
  113. {MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj)},
  114. {MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj)},
  115. {MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj)},
  116. {MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj)},
  117. {MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj)},
  118. {MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&mp_stream___exit___obj)},
  119. };
  120. static MP_DEFINE_CONST_DICT(mp_flipper_file_locals_dict, mp_flipper_file_locals_dict_table);
  121. static const mp_stream_p_t mp_flipper_binary_fileio_stream_p = {
  122. .read = mp_flipper_fileio_read,
  123. .write = mp_flipper_fileio_write,
  124. .ioctl = mp_flipper_fileio_ioctl,
  125. .is_text = false,
  126. };
  127. MP_DEFINE_CONST_OBJ_TYPE(
  128. mp_flipper_binary_fileio_type,
  129. MP_QSTR_BinaryFileIO,
  130. MP_TYPE_FLAG_ITER_IS_STREAM,
  131. protocol,
  132. &mp_flipper_binary_fileio_stream_p,
  133. locals_dict,
  134. &mp_flipper_file_locals_dict);
  135. static const mp_stream_p_t mp_flipper_text_fileio_stream_p = {
  136. .read = mp_flipper_fileio_read,
  137. .write = mp_flipper_fileio_write,
  138. .ioctl = mp_flipper_fileio_ioctl,
  139. .is_text = true,
  140. };
  141. MP_DEFINE_CONST_OBJ_TYPE(
  142. mp_flipper_text_fileio_type,
  143. MP_QSTR_TextFileIO,
  144. MP_TYPE_FLAG_ITER_IS_STREAM,
  145. protocol,
  146. &mp_flipper_text_fileio_stream_p,
  147. locals_dict,
  148. &mp_flipper_file_locals_dict);
  149. mp_obj_t mp_flipper_builtin_open(size_t n_args, const mp_obj_t* args, mp_map_t* kwargs) {
  150. const char* file_name = mp_obj_str_get_str(args[0]);
  151. uint8_t access_mode = MP_FLIPPER_FILE_ACCESS_MODE_READ;
  152. uint8_t open_mode = MP_FLIPPER_FILE_OPEN_MODE_OPEN_EXIST;
  153. bool is_text = true;
  154. if(n_args > 1) {
  155. size_t len;
  156. const char* mode = mp_obj_str_get_data(args[1], &len);
  157. for(size_t i = 0; i < len; i++) {
  158. if(i == 0 && mode[i] == 'r') {
  159. access_mode = MP_FLIPPER_FILE_ACCESS_MODE_READ;
  160. open_mode = MP_FLIPPER_FILE_OPEN_MODE_OPEN_EXIST;
  161. continue;
  162. }
  163. if(i == 0 && mode[i] == 'w') {
  164. access_mode = MP_FLIPPER_FILE_ACCESS_MODE_WRITE;
  165. open_mode = MP_FLIPPER_FILE_OPEN_MODE_CREATE_ALWAYS;
  166. continue;
  167. }
  168. if(i == 1 && mode[i] == 'b') {
  169. is_text = false;
  170. continue;
  171. }
  172. if(i == 1 && mode[i] == 't') {
  173. is_text = true;
  174. continue;
  175. }
  176. if(i >= 1 && mode[i] == '+') {
  177. access_mode = MP_FLIPPER_FILE_ACCESS_MODE_READ | MP_FLIPPER_FILE_ACCESS_MODE_WRITE;
  178. open_mode = MP_FLIPPER_FILE_OPEN_MODE_OPEN_APPEND;
  179. continue;
  180. }
  181. mp_raise_OSError(MP_EINVAL);
  182. }
  183. }
  184. void* handle = mp_flipper_file_open(file_name, access_mode, open_mode);
  185. void* fd = mp_flipper_file_new_file_descriptor(handle, file_name, access_mode, open_mode, is_text);
  186. if(handle == NULL) {
  187. mp_raise_OSError(MP_ENOENT);
  188. }
  189. return MP_OBJ_FROM_PTR(fd);
  190. }
  191. MP_DEFINE_CONST_FUN_OBJ_KW(mp_flipper_builtin_open_obj, 1, mp_flipper_builtin_open);
  192. static const mp_rom_map_elem_t mp_module_io_globals_table[] = {
  193. {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_io)},
  194. {MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_flipper_builtin_open_obj)},
  195. {MP_ROM_QSTR(MP_QSTR_BinaryFileIO), MP_ROM_PTR(&mp_flipper_binary_fileio_type)},
  196. {MP_ROM_QSTR(MP_QSTR_TextFileIO), MP_ROM_PTR(&mp_flipper_text_fileio_type)},
  197. };
  198. static MP_DEFINE_CONST_DICT(mp_module_io_globals, mp_module_io_globals_table);
  199. const mp_obj_module_t mp_module_io = {
  200. .base = {&mp_type_module},
  201. .globals = (mp_obj_dict_t*)&mp_module_io_globals,
  202. };
  203. MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_io, mp_module_io);