From b4571378c2d0461774a56b2ab27274865c634e1b Mon Sep 17 00:00:00 2001 From: Vincent Torri Date: Sat, 6 Nov 2010 21:01:36 +0000 Subject: [PATCH] and add file SVN revision: 54251 --- legacy/eina/src/lib/eina_file_win32.c | 575 ++++++++++++++++++++++++++ 1 file changed, 575 insertions(+) create mode 100644 legacy/eina/src/lib/eina_file_win32.c diff --git a/legacy/eina/src/lib/eina_file_win32.c b/legacy/eina/src/lib/eina_file_win32.c new file mode 100644 index 0000000000..1027b94977 --- /dev/null +++ b/legacy/eina/src/lib/eina_file_win32.c @@ -0,0 +1,575 @@ +/* EINA - EFL data type library + * Copyright (C) 2010 Vincent Torri + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see . + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_ALLOCA_H +# include +#elif defined __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include +# define alloca _alloca +#else +# include +# ifdef __cplusplus +extern "C" +# endif +void *alloca (size_t); +#endif + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN + +#include "eina_config.h" +#include "eina_private.h" + +/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */ +#include "eina_safety_checks.h" +#include "eina_file.h" +#include "eina_stringshare.h" + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +typedef struct _Eina_File_Iterator Eina_File_Iterator; +typedef struct _Eina_File_Direct_Iterator Eina_File_Direct_Iterator; + +struct _Eina_File_Iterator +{ + Eina_Iterator iterator; + + WIN32_FIND_DATA data; + HANDLE handle; + int length; + Eina_Bool is_last : 1; + + char dir[1]; +}; + +struct _Eina_File_Direct_Iterator +{ + Eina_Iterator iterator; + + WIN32_FIND_DATA data; + HANDLE handle; + int length; + Eina_Bool is_last : 1; + + Eina_File_Direct_Info info; + + char dir[1]; +}; + +static void +_eina_file_win32_backslash_change(char *dir) +{ + char *tmp; + + tmp = dir; + while (*tmp) + { + if (*tmp == '/') *tmp = '\\'; + tmp++; + } +} + +static Eina_Bool +_eina_file_win32_is_dir(const char *dir) +{ +#ifdef UNICODE + wchar_t *wdir = NULL; +#endif + DWORD attr; + + /* check if it's a directory */ +#ifdef UNICODE + wdir = evil_char_to_wchar(dir); + if (!wdir) + return EINA_FALSE; + + attr = GetFileAttributes(wdir); + free(wdir); +#else + attr = GetFileAttributes(dir); +#endif + + if (attr == 0xFFFFFFFF) + return EINA_FALSE; + + if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) + return EINA_FALSE; + + return EINA_TRUE; +} + +static char * +_eina_file_win32_dir_new(const char *dir) +{ + char *new_dir; + size_t length; + + length = strlen(dir); + + new_dir = (char *)malloc(sizeof(char) * length + 5); + if (!new_dir) + return NULL; + + memcpy(new_dir, dir, length); + memcpy(new_dir + length, "\\*.*", 5); + _eina_file_win32_backslash_change(new_dir); + + return new_dir; +} + +static HANDLE +_eina_file_win32_first_file(const char *dir, WIN32_FIND_DATA *fd) +{ + HANDLE h; +#ifdef UNICODE + wchar_t *wdir = NULL; + + wdir = evil_char_to_wchar(dir); + if (!wdir) + return NULL; + + h = FindFirstFile(wdir, fd); + free(wdir); +#else + h = FindFirstFile(dir, fd); +#endif + + if (!h) + return NULL; + + while ((fd->cFileName[0] == '.') && + ((fd->cFileName[1] == '\0') || + ((fd->cFileName[1] == '.') && (fd->cFileName[2] == '\0')))) + { + if (!FindNextFile(h, fd)) + return NULL; + } + + return h; +} + +static Eina_Bool +_eina_file_win32_ls_iterator_next(Eina_File_Iterator *it, void **data) +{ + char *old_name; + char *name; + char *cname; + size_t length; + Eina_Bool is_last; + Eina_Bool res = EINA_TRUE; + + if (it->handle == INVALID_HANDLE_VALUE) + return EINA_FALSE; + + is_last = it->is_last; + old_name = strdup(it->data.cFileName); + if (!old_name) + return EINA_FALSE; + + do { + if (!FindNextFile(it->handle, &it->data)) + { + if (GetLastError() == ERROR_NO_MORE_FILES) + it->is_last = EINA_TRUE; + else + res = EINA_FALSE; + } + } while ((it->data.cFileName[0] == '.') && + ((it->data.cFileName[1] == '\0') || + ((it->data.cFileName[1] == '.') && (it->data.cFileName[2] == '\0')))); + +#ifdef UNICODE + cname = evil_wchar_to_char(old_name); + if (!cname) + return EINA_FALSE; +#else + cname = old_name; +#endif + + length = strlen(cname); + name = alloca(length + 2 + it->length); + + memcpy(name, it->dir, it->length); + memcpy(name + it->length, "\\", 1); + memcpy(name + it->length + 1, cname, length + 1); + + *data = (char *)eina_stringshare_add(name); + +#ifdef UNICODE + free(cname); +#endif + free(old_name); + + if (is_last) + res = EINA_FALSE; + + return res; +} + +static HANDLE +_eina_file_win32_ls_iterator_container(Eina_File_Iterator *it) +{ + return it->handle; +} + +static void +_eina_file_win32_ls_iterator_free(Eina_File_Iterator *it) +{ + if (it->handle != INVALID_HANDLE_VALUE) + FindClose(it->handle); + + EINA_MAGIC_SET(&it->iterator, 0); + free(it); +} + +static Eina_Bool +_eina_file_win32_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data) +{ + char *old_name; + char *cname; + size_t length; + DWORD attr; + Eina_Bool is_last; + Eina_Bool res = EINA_TRUE; + + if (it->handle == INVALID_HANDLE_VALUE) + return EINA_FALSE; + + attr = it->data.dwFileAttributes; + is_last = it->is_last; + old_name = strdup(it->data.cFileName); + if (!old_name) + return EINA_FALSE; + + do { + if (!FindNextFile(it->handle, &it->data)) + { + if (GetLastError() == ERROR_NO_MORE_FILES) + it->is_last = EINA_TRUE; + else + res = EINA_FALSE; + } + + length = strlen(old_name); + if (it->info.name_start + length + 1 >= PATH_MAX) + { + free(old_name); + old_name = strdup(it->data.cFileName); + continue; + } + + } while ((it->data.cFileName[0] == '.') && + ((it->data.cFileName[1] == '\0') || + ((it->data.cFileName[1] == '.') && (it->data.cFileName[2] == '\0')))); + +#ifdef UNICODE + cname = evil_wchar_to_char(old_name); + if (!cname) + return EINA_FALSE; +#else + cname = old_name; +#endif + + memcpy(it->info.path + it->info.name_start, cname, length); + it->info.name_length = length; + it->info.path_length = it->info.name_start + length; + it->info.path[it->info.path_length] = '\0'; + + if (attr & FILE_ATTRIBUTE_DIRECTORY) + it->info.type = EINA_FILE_DIR; + else if (attr & FILE_ATTRIBUTE_REPARSE_POINT) + it->info.type = EINA_FILE_LNK; + else if (attr & (FILE_ATTRIBUTE_ARCHIVE | + FILE_ATTRIBUTE_COMPRESSED | + FILE_ATTRIBUTE_COMPRESSED | + FILE_ATTRIBUTE_HIDDEN | + FILE_ATTRIBUTE_NORMAL | + FILE_ATTRIBUTE_SPARSE_FILE | + FILE_ATTRIBUTE_TEMPORARY)) + it->info.type = EINA_FILE_REG; + else + it->info.type = EINA_FILE_UNKNOWN; + + *data = &it->info; + +#ifdef UNICODE + free(cname); +#endif + + free(old_name); + + if (is_last) + res = EINA_FALSE; + + return res; +} + +static HANDLE +_eina_file_win32_direct_ls_iterator_container(Eina_File_Direct_Iterator *it) +{ + return it->handle; +} + +static void +_eina_file_win32_direct_ls_iterator_free(Eina_File_Direct_Iterator *it) +{ + if (it->handle != INVALID_HANDLE_VALUE) + FindClose(it->handle); + + EINA_MAGIC_SET(&it->iterator, 0); + free(it); +} + + +/** + * @endcond + */ + +/*============================================================================* + * Global * + *============================================================================*/ + +/*============================================================================* + * API * + *============================================================================*/ + +EAPI Eina_Bool +eina_file_dir_list(const char *dir, + Eina_Bool recursive, + Eina_File_Dir_List_Cb cb, + void *data) +{ + WIN32_FIND_DATA file; + HANDLE h; + char *new_dir; + + EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE); + + if (!_eina_file_win32_is_dir(dir)) + return EINA_FALSE; + + new_dir = _eina_file_win32_dir_new(dir); + if (!new_dir) + return EINA_FALSE; + + h = _eina_file_win32_first_file(new_dir, &file); + + if (h == INVALID_HANDLE_VALUE) + return EINA_FALSE; + + do + { + char *filename; + +# ifdef UNICODE + filename = evil_wchar_to_char(file.cFileName); +# else + filename = file.cFileName; +# endif /* ! UNICODE */ + if (!strcmp(filename, ".") || !strcmp(filename, "..")) + continue; + + cb(filename, dir, data); + + if (recursive == EINA_TRUE) + { + char *path; + + path = alloca(strlen(dir) + strlen(filename) + 2); + strcpy(path, dir); + strcat(path, "/"); + strcat(path, filename); + + if (!(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + continue; + + eina_file_dir_list(path, recursive, cb, data); + } + +# ifdef UNICODE + free(filename); +# endif /* UNICODE */ + + } while (FindNextFile(h, &file)); + FindClose(h); + + return EINA_TRUE; +} + +EAPI Eina_Array * +eina_file_split(char *path) +{ + Eina_Array *ea; + char *current; + size_t length; + + EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL); + + ea = eina_array_new(16); + + if (!ea) + return NULL; + + for (current = strchr(path, '\\'); + current; + path = current + 1, current = strchr(path, '\\')) + { + length = current - path; + + if (length <= 0) + continue; + + eina_array_push(ea, path); + *current = '\0'; + } + + if (*path != '\0') + eina_array_push(ea, path); + + return ea; +} + +EAPI Eina_Iterator * +eina_file_ls(const char *dir) +{ + Eina_File_Iterator *it; + char *new_dir; + size_t length; + + if (!dir || !*dir) + return NULL; + + if (!_eina_file_win32_is_dir(dir)) + return NULL; + + length = strlen(dir); + + it = calloc(1, sizeof (Eina_File_Iterator) + length); + if (!it) + return NULL; + + EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); + + new_dir = _eina_file_win32_dir_new(dir); + if (!new_dir) + goto free_it; + + it->handle = _eina_file_win32_first_file(new_dir, &it->data); + free(new_dir); + if (it->handle == INVALID_HANDLE_VALUE) + goto free_it; + + memcpy(it->dir, dir, length + 1); + if (dir[length - 1] != '\\') + it->length = length; + else + it->length = length - 1; + _eina_file_win32_backslash_change(it->dir); + + it->iterator.version = EINA_ITERATOR_VERSION; + it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_win32_ls_iterator_next); + it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_win32_ls_iterator_container); + it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_win32_ls_iterator_free); + + return &it->iterator; + + free_it: + free(it); + + return NULL; +} + +EAPI Eina_Iterator * +eina_file_direct_ls(const char *dir) +{ + Eina_File_Direct_Iterator *it; + char *new_dir; + size_t length; + + if (!dir || !*dir) + return NULL; + + length = strlen(dir); + + if (length + 12 + 2 >= MAX_PATH) + return NULL; + + it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length); + if (!it) + return NULL; + + EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); + + new_dir = _eina_file_win32_dir_new(dir); + if (!new_dir) + goto free_it; + + it->handle = _eina_file_win32_first_file(new_dir, &it->data); + free(new_dir); + if (it->handle == INVALID_HANDLE_VALUE) + goto free_it; + + memcpy(it->dir, dir, length + 1); + it->length = length; + _eina_file_win32_backslash_change(it->dir); + + memcpy(it->info.path, dir, length); + if (dir[length - 1] == '\\') + it->info.name_start = length; + else + { + it->info.path[length] = '\\'; + it->info.name_start = length + 1; + } + _eina_file_win32_backslash_change(it->info.path); + + it->iterator.version = EINA_ITERATOR_VERSION; + it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_win32_direct_ls_iterator_next); + it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_win32_direct_ls_iterator_container); + it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_win32_direct_ls_iterator_free); + + return &it->iterator; + + free_it: + free(it); + + return NULL; +} + +EAPI Eina_Iterator * +eina_file_stat_ls(const char *dir) +{ + return eina_file_direct_ls(dir); +}