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