1 /**
2 * @file lv_fs_stdio.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "../../../lvgl.h"
10 #if LV_USE_FS_STDIO != '\0'
11
12 #include <stdio.h>
13 #ifndef WIN32
14 #include <dirent.h>
15 #include <unistd.h>
16 #else
17 #include <windows.h>
18 #endif
19
20 /*********************
21 * DEFINES
22 *********************/
23 #define MAX_PATH_LEN 256
24
25 /**********************
26 * TYPEDEFS
27 **********************/
28 typedef struct {
29 #ifdef WIN32
30 HANDLE dir_p;
31 char next_fn[MAX_PATH_LEN];
32 #else
33 DIR * dir_p;
34 #endif
35 } dir_handle_t;
36
37 /**********************
38 * STATIC PROTOTYPES
39 **********************/
40 static void * fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode);
41 static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p);
42 static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
43 static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
44 static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence);
45 static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
46 static void * fs_dir_open(lv_fs_drv_t * drv, const char * path);
47 static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn);
48 static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * dir_p);
49
50 /**********************
51 * STATIC VARIABLES
52 **********************/
53
54 /**********************
55 * MACROS
56 **********************/
57
58 /**********************
59 * GLOBAL FUNCTIONS
60 **********************/
61
62 /**
63 * Register a driver for the File system interface
64 */
lv_fs_stdio_init(void)65 void lv_fs_stdio_init(void)
66 {
67 /*---------------------------------------------------
68 * Register the file system interface in LVGL
69 *--------------------------------------------------*/
70
71 /*Add a simple drive to open images*/
72 static lv_fs_drv_t fs_drv; /*A driver descriptor*/
73 lv_fs_drv_init(&fs_drv);
74
75 /*Set up fields...*/
76 fs_drv.letter = LV_FS_STDIO_LETTER;
77 fs_drv.cache_size = LV_FS_STDIO_CACHE_SIZE;
78
79 fs_drv.open_cb = fs_open;
80 fs_drv.close_cb = fs_close;
81 fs_drv.read_cb = fs_read;
82 fs_drv.write_cb = fs_write;
83 fs_drv.seek_cb = fs_seek;
84 fs_drv.tell_cb = fs_tell;
85
86 fs_drv.dir_close_cb = fs_dir_close;
87 fs_drv.dir_open_cb = fs_dir_open;
88 fs_drv.dir_read_cb = fs_dir_read;
89
90 lv_fs_drv_register(&fs_drv);
91 }
92
93 /**********************
94 * STATIC FUNCTIONS
95 **********************/
96
97 /**
98 * Open a file
99 * @param drv pointer to a driver where this function belongs
100 * @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt)
101 * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR
102 * @return pointer to FIL struct or NULL in case of fail
103 */
fs_open(lv_fs_drv_t * drv,const char * path,lv_fs_mode_t mode)104 static void * fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode)
105 {
106 LV_UNUSED(drv);
107
108 const char * flags = "";
109
110 if(mode == LV_FS_MODE_WR) flags = "wb";
111 else if(mode == LV_FS_MODE_RD) flags = "rb";
112 else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) flags = "rb+";
113
114 /*Make the path relative to the current directory (the projects root folder)*/
115
116 char buf[MAX_PATH_LEN];
117 lv_snprintf(buf, sizeof(buf), LV_FS_STDIO_PATH "%s", path);
118
119 return fopen(buf, flags);
120 }
121
122 /**
123 * Close an opened file
124 * @param drv pointer to a driver where this function belongs
125 * @param file_p pointer to a FILE variable. (opened with fs_open)
126 * @return LV_FS_RES_OK: no error, the file is read
127 * any error from lv_fs_res_t enum
128 */
fs_close(lv_fs_drv_t * drv,void * file_p)129 static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p)
130 {
131 LV_UNUSED(drv);
132 fclose(file_p);
133 return LV_FS_RES_OK;
134 }
135
136 /**
137 * Read data from an opened file
138 * @param drv pointer to a driver where this function belongs
139 * @param file_p pointer to a FILE variable.
140 * @param buf pointer to a memory block where to store the read data
141 * @param btr number of Bytes To Read
142 * @param br the real number of read bytes (Byte Read)
143 * @return LV_FS_RES_OK: no error, the file is read
144 * any error from lv_fs_res_t enum
145 */
fs_read(lv_fs_drv_t * drv,void * file_p,void * buf,uint32_t btr,uint32_t * br)146 static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
147 {
148 LV_UNUSED(drv);
149 *br = fread(buf, 1, btr, file_p);
150 return (int32_t)(*br) < 0 ? LV_FS_RES_UNKNOWN : LV_FS_RES_OK;
151 }
152
153 /**
154 * Write into a file
155 * @param drv pointer to a driver where this function belongs
156 * @param file_p pointer to a FILE variable
157 * @param buf pointer to a buffer with the bytes to write
158 * @param btw Bytes To Write
159 * @param bw the number of real written bytes (Bytes Written). NULL if unused.
160 * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
161 */
fs_write(lv_fs_drv_t * drv,void * file_p,const void * buf,uint32_t btw,uint32_t * bw)162 static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
163 {
164 LV_UNUSED(drv);
165 *bw = fwrite(buf, 1, btw, file_p);
166 return (int32_t)(*bw) < 0 ? LV_FS_RES_UNKNOWN : LV_FS_RES_OK;
167 }
168
169 /**
170 * Set the read write pointer. Also expand the file size if necessary.
171 * @param drv pointer to a driver where this function belongs
172 * @param file_p pointer to a FILE variable. (opened with fs_open )
173 * @param pos the new position of read write pointer
174 * @return LV_FS_RES_OK: no error, the file is read
175 * any error from lv_fs_res_t enum
176 */
fs_seek(lv_fs_drv_t * drv,void * file_p,uint32_t pos,lv_fs_whence_t whence)177 static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence)
178 {
179 LV_UNUSED(drv);
180 fseek(file_p, pos, whence);
181 return LV_FS_RES_OK;
182 }
183
184 /**
185 * Give the position of the read write pointer
186 * @param drv pointer to a driver where this function belongs
187 * @param file_p pointer to a FILE variable.
188 * @param pos_p pointer to to store the result
189 * @return LV_FS_RES_OK: no error, the file is read
190 * any error from lv_fs_res_t enum
191 */
fs_tell(lv_fs_drv_t * drv,void * file_p,uint32_t * pos_p)192 static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
193 {
194 LV_UNUSED(drv);
195 *pos_p = ftell(file_p);
196 return LV_FS_RES_OK;
197 }
198
199 /**
200 * Initialize a 'DIR' or 'HANDLE' variable for directory reading
201 * @param drv pointer to a driver where this function belongs
202 * @param path path to a directory
203 * @return pointer to an initialized 'DIR' or 'HANDLE' variable
204 */
fs_dir_open(lv_fs_drv_t * drv,const char * path)205 static void * fs_dir_open(lv_fs_drv_t * drv, const char * path)
206 {
207 LV_UNUSED(drv);
208 dir_handle_t * handle = (dir_handle_t *)lv_mem_alloc(sizeof(dir_handle_t));
209 #ifndef WIN32
210 /*Make the path relative to the current directory (the projects root folder)*/
211 char buf[MAX_PATH_LEN];
212 lv_snprintf(buf, sizeof(buf), LV_FS_STDIO_PATH "%s", path);
213 handle->dir_p = opendir(buf);
214 if(handle->dir_p == NULL) {
215 lv_mem_free(handle);
216 return NULL;
217 }
218 return handle;
219 #else
220 handle->dir_p = INVALID_HANDLE_VALUE;
221 WIN32_FIND_DATAA fdata;
222
223 /*Make the path relative to the current directory (the projects root folder)*/
224 char buf[MAX_PATH_LEN];
225 lv_snprintf(buf, sizeof(buf), LV_FS_STDIO_PATH "%s\\*", path);
226
227 strcpy(handle->next_fn, "");
228 handle->dir_p = FindFirstFileA(buf, &fdata);
229 do {
230 if(strcmp(fdata.cFileName, ".") == 0 || strcmp(fdata.cFileName, "..") == 0) {
231 continue;
232 }
233 else {
234 if(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
235 lv_snprintf(handle->next_fn, sizeof(handle->next_fn), "/%s", fdata.cFileName);
236 }
237 else {
238 lv_snprintf(handle->next_fn, sizeof(handle->next_fn), "%s", fdata.cFileName);
239 }
240 break;
241 }
242 } while(FindNextFileA(handle->dir_p, &fdata));
243
244 if(handle->dir_p == INVALID_HANDLE_VALUE) {
245 lv_mem_free(handle);
246 return INVALID_HANDLE_VALUE;
247 }
248 return handle;
249 #endif
250 }
251
252 /**
253 * Read the next filename form a directory.
254 * The name of the directories will begin with '/'
255 * @param drv pointer to a driver where this function belongs
256 * @param dir_p pointer to an initialized 'DIR' or 'HANDLE' variable
257 * @param fn pointer to a buffer to store the filename
258 * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
259 */
fs_dir_read(lv_fs_drv_t * drv,void * dir_p,char * fn)260 static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn)
261 {
262 LV_UNUSED(drv);
263 dir_handle_t * handle = (dir_handle_t *)dir_p;
264 #ifndef WIN32
265 struct dirent * entry;
266 do {
267 entry = readdir(handle->dir_p);
268 if(entry) {
269 if(entry->d_type == DT_DIR) lv_snprintf(fn, MAX_PATH_LEN, "/%s", entry->d_name);
270 else strcpy(fn, entry->d_name);
271 }
272 else {
273 strcpy(fn, "");
274 }
275 } while(strcmp(fn, "/.") == 0 || strcmp(fn, "/..") == 0);
276 #else
277 strcpy(fn, handle->next_fn);
278
279 strcpy(handle->next_fn, "");
280 WIN32_FIND_DATAA fdata;
281
282 if(FindNextFileA(handle->dir_p, &fdata) == false) return LV_FS_RES_OK;
283 do {
284 if(strcmp(fdata.cFileName, ".") == 0 || strcmp(fdata.cFileName, "..") == 0) {
285 continue;
286 }
287 else {
288 if(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
289 lv_snprintf(handle->next_fn, sizeof(handle->next_fn), "/%s", fdata.cFileName);
290 }
291 else {
292 lv_snprintf(handle->next_fn, sizeof(handle->next_fn), "%s", fdata.cFileName);
293 }
294 break;
295 }
296 } while(FindNextFileA(handle->dir_p, &fdata));
297
298 #endif
299 return LV_FS_RES_OK;
300 }
301
302 /**
303 * Close the directory reading
304 * @param drv pointer to a driver where this function belongs
305 * @param dir_p pointer to an initialized 'DIR' or 'HANDLE' variable
306 * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
307 */
fs_dir_close(lv_fs_drv_t * drv,void * dir_p)308 static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * dir_p)
309 {
310 LV_UNUSED(drv);
311 dir_handle_t * handle = (dir_handle_t *)dir_p;
312 #ifndef WIN32
313 closedir(handle->dir_p);
314 #else
315 FindClose(handle->dir_p);
316 #endif
317 lv_mem_free(handle);
318 return LV_FS_RES_OK;
319 }
320
321 #else /*LV_USE_FS_STDIO == 0*/
322
323 #if defined(LV_FS_STDIO_LETTER) && LV_FS_STDIO_LETTER != '\0'
324 #warning "LV_USE_FS_STDIO is not enabled but LV_FS_STDIO_LETTER is set"
325 #endif
326
327 #endif /*LV_USE_FS_POSIX*/
328