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