1 /**
2 * @file lv_fs_win32.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "../../../lvgl.h"
10 #if LV_USE_FS_WIN32 != '\0'
11
12 #include <windows.h>
13 #include <stdio.h>
14
15 /*********************
16 * DEFINES
17 *********************/
18 #define MAX_PATH_LEN 256
19
20 /**********************
21 * TYPEDEFS
22 **********************/
23 typedef struct {
24 HANDLE dir_p;
25 char next_fn[MAX_PATH_LEN];
26 lv_fs_res_t next_error;
27 } dir_handle_t;
28
29 /**********************
30 * STATIC PROTOTYPES
31 **********************/
32
33 static bool is_dots_name(const char * name);
34 static lv_fs_res_t fs_error_from_win32(DWORD error);
35 static void * fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode);
36 static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p);
37 static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
38 static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
39 static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence);
40 static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
41 static void * fs_dir_open(lv_fs_drv_t * drv, const char * path);
42 static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn);
43 static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * dir_p);
44
45 /**********************
46 * STATIC VARIABLES
47 **********************/
48
49 /**********************
50 * MACROS
51 **********************/
52
53 /**********************
54 * GLOBAL FUNCTIONS
55 **********************/
56
57 /**
58 * Register a driver for the File system interface
59 */
lv_fs_win32_init(void)60 void lv_fs_win32_init(void)
61 {
62 /*---------------------------------------------------
63 * Register the file system interface in LVGL
64 *--------------------------------------------------*/
65
66 /*Add a simple driver to open images*/
67 static lv_fs_drv_t fs_drv; /*A driver descriptor*/
68 lv_fs_drv_init(&fs_drv);
69
70 /*Set up fields...*/
71 fs_drv.letter = LV_FS_WIN32_LETTER;
72 fs_drv.cache_size = LV_FS_WIN32_CACHE_SIZE;
73
74 fs_drv.open_cb = fs_open;
75 fs_drv.close_cb = fs_close;
76 fs_drv.read_cb = fs_read;
77 fs_drv.write_cb = fs_write;
78 fs_drv.seek_cb = fs_seek;
79 fs_drv.tell_cb = fs_tell;
80
81 fs_drv.dir_close_cb = fs_dir_close;
82 fs_drv.dir_open_cb = fs_dir_open;
83 fs_drv.dir_read_cb = fs_dir_read;
84
85 lv_fs_drv_register(&fs_drv);
86 }
87
88 /**********************
89 * STATIC FUNCTIONS
90 **********************/
91
92 /**
93 * Check the dots name
94 * @param name file or dir name
95 * @return true if the name is dots name
96 */
is_dots_name(const char * name)97 static bool is_dots_name(const char * name)
98 {
99 return name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2]));
100 }
101
102 /**
103 * Convert Win32 error code to error from lv_fs_res_t enum
104 * @param error Win32 error code
105 * @return LV_FS_RES_OK: no error, the file is read
106 * any error from lv_fs_res_t enum
107 */
fs_error_from_win32(DWORD error)108 static lv_fs_res_t fs_error_from_win32(DWORD error)
109 {
110 lv_fs_res_t res;
111
112 switch(error) {
113 case ERROR_SUCCESS:
114 res = LV_FS_RES_OK;
115 break;
116 case ERROR_BAD_UNIT:
117 case ERROR_NOT_READY:
118 case ERROR_CRC:
119 case ERROR_SEEK:
120 case ERROR_NOT_DOS_DISK:
121 case ERROR_WRITE_FAULT:
122 case ERROR_READ_FAULT:
123 case ERROR_GEN_FAILURE:
124 case ERROR_WRONG_DISK:
125 res = LV_FS_RES_HW_ERR;
126 break;
127 case ERROR_INVALID_HANDLE:
128 case ERROR_INVALID_TARGET_HANDLE:
129 res = LV_FS_RES_FS_ERR;
130 break;
131 case ERROR_FILE_NOT_FOUND:
132 case ERROR_PATH_NOT_FOUND:
133 case ERROR_INVALID_DRIVE:
134 case ERROR_NO_MORE_FILES:
135 case ERROR_SECTOR_NOT_FOUND:
136 case ERROR_BAD_NETPATH:
137 case ERROR_BAD_NET_NAME:
138 case ERROR_BAD_PATHNAME:
139 case ERROR_FILENAME_EXCED_RANGE:
140 res = LV_FS_RES_NOT_EX;
141 break;
142 case ERROR_DISK_FULL:
143 res = LV_FS_RES_FULL;
144 break;
145 case ERROR_SHARING_VIOLATION:
146 case ERROR_LOCK_VIOLATION:
147 case ERROR_DRIVE_LOCKED:
148 res = LV_FS_RES_LOCKED;
149 break;
150 case ERROR_ACCESS_DENIED:
151 case ERROR_CURRENT_DIRECTORY:
152 case ERROR_WRITE_PROTECT:
153 case ERROR_NETWORK_ACCESS_DENIED:
154 case ERROR_CANNOT_MAKE:
155 case ERROR_FAIL_I24:
156 case ERROR_SEEK_ON_DEVICE:
157 case ERROR_NOT_LOCKED:
158 case ERROR_LOCK_FAILED:
159 res = LV_FS_RES_DENIED;
160 break;
161 case ERROR_BUSY:
162 res = LV_FS_RES_BUSY;
163 break;
164 case ERROR_TIMEOUT:
165 res = LV_FS_RES_TOUT;
166 break;
167 case ERROR_NOT_SAME_DEVICE:
168 case ERROR_DIRECT_ACCESS_HANDLE:
169 res = LV_FS_RES_NOT_IMP;
170 break;
171 case ERROR_TOO_MANY_OPEN_FILES:
172 case ERROR_ARENA_TRASHED:
173 case ERROR_NOT_ENOUGH_MEMORY:
174 case ERROR_INVALID_BLOCK:
175 case ERROR_OUT_OF_PAPER:
176 case ERROR_SHARING_BUFFER_EXCEEDED:
177 case ERROR_NOT_ENOUGH_QUOTA:
178 res = LV_FS_RES_OUT_OF_MEM;
179 break;
180 case ERROR_INVALID_FUNCTION:
181 case ERROR_INVALID_ACCESS:
182 case ERROR_INVALID_DATA:
183 case ERROR_BAD_COMMAND:
184 case ERROR_BAD_LENGTH:
185 case ERROR_INVALID_PARAMETER:
186 case ERROR_NEGATIVE_SEEK:
187 res = LV_FS_RES_INV_PARAM;
188 break;
189 default:
190 res = LV_FS_RES_UNKNOWN;
191 break;
192 }
193
194 return res;
195 }
196
197 /**
198 * Open a file
199 * @param drv pointer to a driver where this function belongs
200 * @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt)
201 * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR
202 * @return pointer to FIL struct or NULL in case of fail
203 */
fs_open(lv_fs_drv_t * drv,const char * path,lv_fs_mode_t mode)204 static void * fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode)
205 {
206 LV_UNUSED(drv);
207
208 DWORD desired_access = 0;
209
210 if(mode & LV_FS_MODE_RD) {
211 desired_access |= GENERIC_READ;
212 }
213
214 if(mode & LV_FS_MODE_WR) {
215 desired_access |= GENERIC_WRITE;
216 }
217
218 /*Make the path relative to the current directory (the projects root folder)*/
219
220 char buf[MAX_PATH];
221 lv_snprintf(buf, sizeof(buf), LV_FS_WIN32_PATH "%s", path);
222
223 return (void *)CreateFileA(
224 buf,
225 desired_access,
226 FILE_SHARE_READ,
227 NULL,
228 OPEN_EXISTING,
229 FILE_ATTRIBUTE_NORMAL,
230 NULL);
231 }
232
233 /**
234 * Close an opened file
235 * @param drv pointer to a driver where this function belongs
236 * @param file_p pointer to a FILE variable. (opened with fs_open)
237 * @return LV_FS_RES_OK: no error, the file is read
238 * any error from lv_fs_res_t enum
239 */
fs_close(lv_fs_drv_t * drv,void * file_p)240 static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p)
241 {
242 LV_UNUSED(drv);
243 return CloseHandle((HANDLE)file_p)
244 ? LV_FS_RES_OK
245 : fs_error_from_win32(GetLastError());
246 }
247
248 /**
249 * Read data from an opened file
250 * @param drv pointer to a driver where this function belongs
251 * @param file_p pointer to a FILE variable.
252 * @param buf pointer to a memory block where to store the read data
253 * @param btr number of Bytes To Read
254 * @param br the real number of read bytes (Byte Read)
255 * @return LV_FS_RES_OK: no error, the file is read
256 * any error from lv_fs_res_t enum
257 */
fs_read(lv_fs_drv_t * drv,void * file_p,void * buf,uint32_t btr,uint32_t * br)258 static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
259 {
260 LV_UNUSED(drv);
261 return ReadFile((HANDLE)file_p, buf, btr, (LPDWORD)br, NULL)
262 ? LV_FS_RES_OK
263 : fs_error_from_win32(GetLastError());
264 }
265
266 /**
267 * Write into a file
268 * @param drv pointer to a driver where this function belongs
269 * @param file_p pointer to a FILE variable
270 * @param buf pointer to a buffer with the bytes to write
271 * @param btw Bytes To Write
272 * @param bw the number of real written bytes (Bytes Written). NULL if unused.
273 * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
274 */
fs_write(lv_fs_drv_t * drv,void * file_p,const void * buf,uint32_t btw,uint32_t * bw)275 static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
276 {
277 LV_UNUSED(drv);
278 return WriteFile((HANDLE)file_p, buf, btw, (LPDWORD)bw, NULL)
279 ? LV_FS_RES_OK
280 : fs_error_from_win32(GetLastError());
281 }
282
283 /**
284 * Set the read write pointer. Also expand the file size if necessary.
285 * @param drv pointer to a driver where this function belongs
286 * @param file_p pointer to a FILE variable. (opened with fs_open )
287 * @param pos the new position of read write pointer
288 * @return LV_FS_RES_OK: no error, the file is read
289 * any error from lv_fs_res_t enum
290 */
fs_seek(lv_fs_drv_t * drv,void * file_p,uint32_t pos,lv_fs_whence_t whence)291 static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence)
292 {
293 LV_UNUSED(drv);
294
295 DWORD move_method = (DWORD) -1;
296 if(whence == LV_FS_SEEK_SET) {
297 move_method = FILE_BEGIN;
298 }
299 else if(whence == LV_FS_SEEK_CUR) {
300 move_method = FILE_CURRENT;
301 }
302 else if(whence == LV_FS_SEEK_END) {
303 move_method = FILE_END;
304 }
305
306 LARGE_INTEGER distance_to_move;
307 distance_to_move.QuadPart = pos;
308 return SetFilePointerEx((HANDLE)file_p, distance_to_move, NULL, move_method)
309 ? LV_FS_RES_OK
310 : fs_error_from_win32(GetLastError());
311 }
312
313 /**
314 * Give the position of the read write pointer
315 * @param drv pointer to a driver where this function belongs
316 * @param file_p pointer to a FILE variable.
317 * @param pos_p pointer to to store the result
318 * @return LV_FS_RES_OK: no error, the file is read
319 * any error from lv_fs_res_t enum
320 */
fs_tell(lv_fs_drv_t * drv,void * file_p,uint32_t * pos_p)321 static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
322 {
323 LV_UNUSED(drv);
324
325 if(!pos_p) {
326 return LV_FS_RES_INV_PARAM;
327 }
328
329 LARGE_INTEGER file_pointer;
330 file_pointer.QuadPart = 0;
331
332 LARGE_INTEGER distance_to_move;
333 distance_to_move.QuadPart = 0;
334 if(SetFilePointerEx(
335 (HANDLE)file_p,
336 distance_to_move,
337 &file_pointer,
338 FILE_CURRENT)) {
339 if(file_pointer.QuadPart > LONG_MAX) {
340 return LV_FS_RES_INV_PARAM;
341 }
342 else {
343 *pos_p = file_pointer.LowPart;
344 return LV_FS_RES_OK;
345 }
346 }
347 else {
348 return fs_error_from_win32(GetLastError());
349 }
350 }
351
352 /**
353 * Initialize a 'DIR' or 'HANDLE' variable for directory reading
354 * @param drv pointer to a driver where this function belongs
355 * @param path path to a directory
356 * @return pointer to an initialized 'DIR' or 'HANDLE' variable
357 */
fs_dir_open(lv_fs_drv_t * drv,const char * path)358 static void * fs_dir_open(lv_fs_drv_t * drv, const char * path)
359 {
360 LV_UNUSED(drv);
361 dir_handle_t * handle = (dir_handle_t *)lv_mem_alloc(sizeof(dir_handle_t));
362 handle->dir_p = INVALID_HANDLE_VALUE;
363 handle->next_error = LV_FS_RES_OK;
364 WIN32_FIND_DATAA fdata;
365
366 /*Make the path relative to the current directory (the projects root folder)*/
367 char buf[MAX_PATH_LEN];
368 #ifdef LV_FS_WIN32_PATH
369 lv_snprintf(buf, sizeof(buf), LV_FS_WIN32_PATH "%s\\*", path);
370 #else
371 lv_snprintf(buf, sizeof(buf), "%s\\*", path);
372 #endif
373
374 strcpy(handle->next_fn, "");
375 handle->dir_p = FindFirstFileA(buf, &fdata);
376 do {
377 if(is_dots_name(fdata.cFileName)) {
378 continue;
379 }
380 else {
381 if(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
382 lv_snprintf(handle->next_fn, sizeof(handle->next_fn), "/%s", fdata.cFileName);
383 }
384 else {
385 lv_snprintf(handle->next_fn, sizeof(handle->next_fn), "%s", fdata.cFileName);
386 }
387 break;
388 }
389 } while(FindNextFileA(handle->dir_p, &fdata));
390
391 if(handle->dir_p == INVALID_HANDLE_VALUE) {
392 lv_mem_free(handle);
393 handle->next_error = fs_error_from_win32(GetLastError());
394 return INVALID_HANDLE_VALUE;
395 }
396 else {
397 handle->next_error = LV_FS_RES_OK;
398 return handle;
399 }
400 }
401
402 /**
403 * Read the next filename from a directory.
404 * The name of the directories will begin with '/'
405 * @param drv pointer to a driver where this function belongs
406 * @param dir_p pointer to an initialized 'DIR' or 'HANDLE' variable
407 * @param fn pointer to a buffer to store the filename
408 * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
409 */
fs_dir_read(lv_fs_drv_t * drv,void * dir_p,char * fn)410 static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn)
411 {
412 LV_UNUSED(drv);
413 dir_handle_t * handle = (dir_handle_t *)dir_p;
414 strcpy(fn, handle->next_fn);
415 lv_fs_res_t current_error = handle->next_error;
416 strcpy(handle->next_fn, "");
417
418 WIN32_FIND_DATAA fdata;
419
420 while(FindNextFileA(handle->dir_p, &fdata)) {
421 if(is_dots_name(fdata.cFileName)) {
422 continue;
423 }
424 else {
425 if(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
426 lv_snprintf(handle->next_fn, sizeof(handle->next_fn), "/%s", fdata.cFileName);
427 }
428 else {
429 lv_snprintf(handle->next_fn, sizeof(handle->next_fn), "%s", fdata.cFileName);
430 }
431 break;
432 }
433 }
434
435 if(handle->next_fn[0] == '\0') {
436 handle->next_error = fs_error_from_win32(GetLastError());
437 }
438
439 return current_error;
440 }
441
442 /**
443 * Close the directory reading
444 * @param drv pointer to a driver where this function belongs
445 * @param dir_p pointer to an initialized 'DIR' or 'HANDLE' variable
446 * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
447 */
fs_dir_close(lv_fs_drv_t * drv,void * dir_p)448 static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * dir_p)
449 {
450 LV_UNUSED(drv);
451 dir_handle_t * handle = (dir_handle_t *)dir_p;
452 lv_fs_res_t res = FindClose(handle->dir_p)
453 ? LV_FS_RES_OK
454 : fs_error_from_win32(GetLastError());
455 lv_mem_free(handle);
456 return res;
457 }
458
459 #else /*LV_USE_FS_WIN32 == 0*/
460
461 #if defined(LV_FS_WIN32_LETTER) && LV_FS_WIN32_LETTER != '\0'
462 #warning "LV_USE_FS_WIN32 is not enabled but LV_FS_WIN32_LETTER is set"
463 #endif
464
465 #endif
466