VR-Engage  2.2
Loading...
Searching...
No Matches
tinydir.h
Go to the documentation of this file.
1/*
2Copyright (c) 2013-2014, Cong Xu, Baudouin Feildel
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7
81. Redistributions of source code must retain the above copyright notice, this
9list of conditions and the following disclaimer.
102. Redistributions in binary form must reproduce the above copyright notice,
11this list of conditions and the following disclaimer in the documentation
12and/or other materials provided with the distribution.
13
14THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24*/
25#ifndef TINYDIR_H
26#define TINYDIR_H
27
28#include <errno.h>
29#include <stdlib.h>
30#include <string.h>
31#ifdef _MSC_VER
32#define WIN32_LEAN_AND_MEAN
33#include <windows.h>
34#pragma warning (disable : 4996)
35#else
36#include <dirent.h>
37#include <libgen.h>
38#include <sys/stat.h>
39#endif
40
41
42/* types */
43
44#define _TINYDIR_PATH_MAX 4096
45#ifdef _MSC_VER
46/* extra chars for the "\\*" mask */
47#define _TINYDIR_PATH_EXTRA 2
48#else
49#define _TINYDIR_PATH_EXTRA 0
50#endif
51#define _TINYDIR_FILENAME_MAX 256
52
53#ifdef _MSC_VER
54#define _TINYDIR_FUNC static __inline
55#else
56#define _TINYDIR_FUNC static __inline__
57#endif
58
59typedef struct
60{
66
67#ifdef _MSC_VER
68#else
69struct stat _s;
70#endif
72
73typedef struct
74{
77size_t n_files;
78
80#ifdef _MSC_VER
81HANDLE _h;
82WIN32_FIND_DATA _f;
83#else
84DIR *_d;
85struct dirent *_e;
86#endif
88
89
90/* declarations */
91
93int tinydir_open(tinydir_dir *dir, const char *path);
95int tinydir_open_sorted(tinydir_dir *dir, const char *path);
97void tinydir_close(tinydir_dir *dir);
98
100int tinydir_next(tinydir_dir *dir);
102int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
104int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
106int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
107
111int _tinydir_file_cmp(const void *a, const void *b);
112
113
114/* definitions*/
115
117int tinydir_open(tinydir_dir *dir, const char *path)
118{
119if (dir == NULL || path == NULL || strlen(path) == 0)
120{
121errno = EINVAL;
122return -1;
123}
124if (strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
125{
126errno = ENAMETOOLONG;
127return -1;
128}
129
130/* initialise dir */
131dir->_files = NULL;
132#ifdef _MSC_VER
133dir->_h = INVALID_HANDLE_VALUE;
134#else
135dir->_d = NULL;
136#endif
137tinydir_close(dir);
138
139strcpy(dir->path, path);
140#ifdef _MSC_VER
141strcat(dir->path, "\\*");
142dir->_h = FindFirstFile(dir->path, &dir->_f);
143dir->path[strlen(dir->path) - 2] = '\0';
144if (dir->_h == INVALID_HANDLE_VALUE)
145#else
146dir->_d = opendir(path);
147if (dir->_d == NULL)
148#endif
149{
150errno = ENOENT;
151goto bail;
152}
153
154/* read first file */
155dir->has_next = 1;
156#ifndef _MSC_VER
157dir->_e = readdir(dir->_d);
158if (dir->_e == NULL)
159{
160dir->has_next = 0;
161}
162#endif
163
164return 0;
165
166bail:
167tinydir_close(dir);
168return -1;
169}
170
172int tinydir_open_sorted(tinydir_dir *dir, const char *path)
173{
174/* Count the number of files first, to pre-allocate the files array */
175size_t n_files = 0;
176if (tinydir_open(dir, path) == -1)
177{
178return -1;
179}
180while (dir->has_next)
181{
182n_files++;
183if (tinydir_next(dir) == -1)
184{
185goto bail;
186}
187}
188tinydir_close(dir);
189
190if (tinydir_open(dir, path) == -1)
191{
192return -1;
193}
194
195dir->n_files = 0;
196dir->_files = (tinydir_file *)malloc(sizeof *dir->_files * n_files);
197if (dir->_files == NULL)
198{
199errno = ENOMEM;
200goto bail;
201}
202while (dir->has_next)
203{
204tinydir_file *p_file;
205dir->n_files++;
206
207p_file = &dir->_files[dir->n_files - 1];
208if (tinydir_readfile(dir, p_file) == -1)
209{
210goto bail;
211}
212
213if (tinydir_next(dir) == -1)
214{
215goto bail;
216}
217
218/* Just in case the number of files has changed between the first and
219second reads, terminate without writing into unallocated memory */
220if (dir->n_files == n_files)
221{
222break;
223}
224}
225
226qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
227
228return 0;
229
230bail:
231tinydir_close(dir);
232return -1;
233}
234
237{
238if (dir == NULL)
239{
240return;
241}
242
243memset(dir->path, 0, sizeof(dir->path));
244dir->has_next = 0;
245dir->n_files = 0;
246if (dir->_files != NULL)
247{
248free(dir->_files);
249}
250dir->_files = NULL;
251#ifdef _MSC_VER
252if (dir->_h != INVALID_HANDLE_VALUE)
253{
254FindClose(dir->_h);
255}
256dir->_h = INVALID_HANDLE_VALUE;
257#else
258if (dir->_d)
259{
260closedir(dir->_d);
261}
262dir->_d = NULL;
263dir->_e = NULL;
264#endif
265}
266
269{
270if (dir == NULL)
271{
272errno = EINVAL;
273return -1;
274}
275if (!dir->has_next)
276{
277errno = ENOENT;
278return -1;
279}
280
281#ifdef _MSC_VER
282if (FindNextFile(dir->_h, &dir->_f) == 0)
283#else
284dir->_e = readdir(dir->_d);
285if (dir->_e == NULL)
286#endif
287{
288dir->has_next = 0;
289#ifdef _MSC_VER
290if (GetLastError() != ERROR_SUCCESS &&
291GetLastError() != ERROR_NO_MORE_FILES)
292{
293tinydir_close(dir);
294errno = EIO;
295return -1;
296}
297#endif
298}
299
300return 0;
301}
302
305{
306if (dir == NULL || file == NULL)
307{
308errno = EINVAL;
309return -1;
310}
311#ifdef _MSC_VER
312if (dir->_h == INVALID_HANDLE_VALUE)
313#else
314if (dir->_e == NULL)
315#endif
316{
317errno = ENOENT;
318return -1;
319}
320if (strlen(dir->path) +
321strlen(
322#ifdef _MSC_VER
323dir->_f.cFileName
324#else
325dir->_e->d_name
326#endif
327) + 1 + _TINYDIR_PATH_EXTRA >=
329{
330/* the path for the file will be too long */
331errno = ENAMETOOLONG;
332return -1;
333}
334if (strlen(
335#ifdef _MSC_VER
336dir->_f.cFileName
337#else
338dir->_e->d_name
339#endif
341{
342errno = ENAMETOOLONG;
343return -1;
344}
345
346strcpy(file->path, dir->path);
347strcat(file->path, "/");
348strcpy(file->name,
349#ifdef _MSC_VER
350dir->_f.cFileName
351#else
352dir->_e->d_name
353#endif
354);
355strcat(file->path, file->name);
356#ifndef _MSC_VER
357if (stat(file->path, &file->_s) == -1)
358{
359return -1;
360}
361#endif
362_tinydir_get_ext(file);
363
364file->is_dir =
365#ifdef _MSC_VER
366!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
367#else
368S_ISDIR(file->_s.st_mode);
369#endif
370file->is_reg =
371#ifdef _MSC_VER
372!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
373(
374!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
375!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
376!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
377#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
378!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
379#endif
380#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
381!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
382#endif
383!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
384!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
385#else
386S_ISREG(file->_s.st_mode);
387#endif
388
389return 0;
390}
391
393int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
394{
395if (dir == NULL || file == NULL)
396{
397errno = EINVAL;
398return -1;
399}
400if (i >= dir->n_files)
401{
402errno = ENOENT;
403return -1;
404}
405
406memcpy(file, &dir->_files[i], sizeof(tinydir_file));
407_tinydir_get_ext(file);
408
409return 0;
410}
411
414{
415char path[_TINYDIR_PATH_MAX];
416if (dir == NULL)
417{
418errno = EINVAL;
419return -1;
420}
421if (i >= dir->n_files || !dir->_files[i].is_dir)
422{
423errno = ENOENT;
424return -1;
425}
426
427strcpy(path, dir->_files[i].path);
428tinydir_close(dir);
429if (tinydir_open_sorted(dir, path) == -1)
430{
431return -1;
432}
433
434return 0;
435}
436
437/* Open a single file given its path */
439int tinydir_file_open(tinydir_file *file, const char *path)
440{
441tinydir_dir dir;
442int result = 0;
443int found = 0;
444char dir_name_buf[_TINYDIR_PATH_MAX];
445char file_name_buf[_TINYDIR_FILENAME_MAX];
446char *dir_name;
447char *base_name;
448#ifdef _MSC_VER
449char drive_buf[_TINYDIR_PATH_MAX];
450char ext_buf[_TINYDIR_FILENAME_MAX];
451#endif
452
453if (file == NULL || path == NULL || strlen(path) == 0)
454{
455errno = EINVAL;
456return -1;
457}
458if (strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
459{
460errno = ENAMETOOLONG;
461return -1;
462}
463
464/* Get the parent path */
465#ifdef _MSC_VER
466if (_splitpath_s(
467path,
468drive_buf, sizeof drive_buf,
469dir_name_buf, sizeof dir_name_buf,
470file_name_buf, sizeof file_name_buf,
471ext_buf, sizeof ext_buf))
472{
473errno = EINVAL;
474return -1;
475}
476/* Concatenate the drive letter and dir name to form full dir name */
477strcat(drive_buf, dir_name_buf);
478dir_name = drive_buf;
479/* Concatenate the file name and extension to form base name */
480strcat(file_name_buf, ext_buf);
481base_name = file_name_buf;
482#else
483strcpy(dir_name_buf, path);
484dir_name = dirname(dir_name_buf);
485strcpy(file_name_buf, path);
486base_name = basename(file_name_buf);
487#endif
488
489/* Open the parent directory */
490if (tinydir_open(&dir, dir_name) == -1)
491{
492return -1;
493}
494
495/* Read through the parent directory and look for the file */
496while (dir.has_next)
497{
498if (tinydir_readfile(&dir, file) == -1)
499{
500result = -1;
501goto bail;
502}
503if (strcmp(file->name, base_name) == 0)
504{
505/* File found */
506found = 1;
507goto bail;
508}
509tinydir_next(&dir);
510}
511if (!found)
512{
513result = -1;
514errno = ENOENT;
515}
516
517bail:
518tinydir_close(&dir);
519return result;
520}
521
524{
525char *period = strrchr(file->name, '.');
526if (period == NULL)
527{
528file->extension = &(file->name[strlen(file->name)]);
529}
530else
531{
532file->extension = period + 1;
533}
534}
535
537int _tinydir_file_cmp(const void *a, const void *b)
538{
539const tinydir_file *fa = (const tinydir_file *)a;
540const tinydir_file *fb = (const tinydir_file *)b;
541if (fa->is_dir != fb->is_dir)
542{
543return -(fa->is_dir - fb->is_dir);
544}
545return strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
546}
547
548#endif
Definition tinydir.h:74
int has_next
Definition tinydir.h:76
char path[_TINYDIR_PATH_MAX]
Definition tinydir.h:75
tinydir_file * _files
Definition tinydir.h:79
DIR * _d
Definition tinydir.h:84
struct dirent * _e
Definition tinydir.h:85
size_t n_files
Definition tinydir.h:77
Definition tinydir.h:60
char * extension
Definition tinydir.h:63
int is_reg
Definition tinydir.h:65
int is_dir
Definition tinydir.h:64
struct stat _s
Definition tinydir.h:69
char path[_TINYDIR_PATH_MAX]
Definition tinydir.h:61
char name[_TINYDIR_FILENAME_MAX]
Definition tinydir.h:62
_TINYDIR_FUNC int _tinydir_file_cmp(const void *a, const void *b)
Definition tinydir.h:537
_TINYDIR_FUNC void tinydir_close(tinydir_dir *dir)
Definition tinydir.h:236
#define _TINYDIR_PATH_MAX
Definition tinydir.h:44
#define _TINYDIR_PATH_EXTRA
Definition tinydir.h:49
_TINYDIR_FUNC int tinydir_open(tinydir_dir *dir, const char *path)
Definition tinydir.h:117
_TINYDIR_FUNC int tinydir_open_sorted(tinydir_dir *dir, const char *path)
Definition tinydir.h:172
_TINYDIR_FUNC int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
Definition tinydir.h:393
_TINYDIR_FUNC int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
Definition tinydir.h:304
_TINYDIR_FUNC int tinydir_next(tinydir_dir *dir)
Definition tinydir.h:268
_TINYDIR_FUNC int tinydir_file_open(tinydir_file *file, const char *path)
Definition tinydir.h:439
#define _TINYDIR_FILENAME_MAX
Definition tinydir.h:51
#define _TINYDIR_FUNC
Definition tinydir.h:56
_TINYDIR_FUNC int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
Definition tinydir.h:413
_TINYDIR_FUNC void _tinydir_get_ext(tinydir_file *file)
Definition tinydir.h:523