Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/source/fitz/directory.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/source/fitz/directory.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,273 @@ +// Copyright (C) 2004-2024 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF 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 Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see <https://www.artifex.com/> or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + +#include "mupdf/fitz.h" + +#include <string.h> +#include <errno.h> +#include <sys/stat.h> + +#ifdef _WIN32 +#include <windows.h> +#include <errno.h> +#define stat _stat +#else +#include <dirent.h> +#endif + +typedef struct +{ + fz_archive super; + + char *path; + + int max_entries; + int num_entries; + char **entries; +} fz_directory; + +static void drop_directory(fz_context *ctx, fz_archive *arch) +{ + fz_directory *dir = (fz_directory *) arch; + int i; + + fz_free(ctx, dir->path); + for (i = 0; i < dir->num_entries; i++) + fz_free(ctx, dir->entries[i]); + fz_free(ctx, dir->entries); +} + +static void make_dir_path(char *output, fz_archive *arch, const char *tail, size_t size) +{ + /* Skip any leading ../ path segments, so we don't look outside the + * directory itself. The paths coming here have already been + * canonicalized with fz_cleanname so any remaining ".." parts are + * guaranteed to be at the start of the path. + */ + fz_directory *dir = (fz_directory *) arch; + while (tail[0] == '.' && tail[1] == '.' && tail[2] == '/') + tail += 3; + fz_strlcpy(output, dir->path, size); + fz_strlcat(output, "/", size); + fz_strlcat(output, tail, size); +} + +static fz_stream *open_dir_entry(fz_context *ctx, fz_archive *arch, const char *name) +{ + char path[PATH_MAX]; + make_dir_path(path, arch, name, sizeof path); + return fz_try_open_file(ctx, path); +} + +static fz_buffer *read_dir_entry(fz_context *ctx, fz_archive *arch, const char *name) +{ + char path[PATH_MAX]; + make_dir_path(path, arch, name, sizeof path); + return fz_try_read_file(ctx, path); +} + +static int has_dir_entry(fz_context *ctx, fz_archive *arch, const char *name) +{ + char path[PATH_MAX]; + make_dir_path(path, arch, name, sizeof path); + return fz_file_exists(ctx, path); +} + +int +fz_is_directory(fz_context *ctx, const char *path) +{ +#ifdef _WIN32 + wchar_t *wpath = fz_wchar_from_utf8(ctx, path); + struct stat info; + int ret; + + ret = _wstat(wpath, &info); + fz_free(ctx, wpath); + if (ret < 0) + return 0; + + return S_ISDIR(info.st_mode); +#else + struct stat info; + + if (stat(path, &info) < 0) + return 0; + + return S_ISDIR(info.st_mode); +#endif +} + +static int +count_dir_entries(fz_context *ctx, fz_archive *arch) +{ + fz_directory *dir = (fz_directory *) arch; + + return dir->num_entries; +} + +const char * +list_dir_entry(fz_context *ctx, fz_archive *arch, int n) +{ + fz_directory *dir = (fz_directory *) arch; + + if (n < 0 || n >= dir->num_entries) + return NULL; + + return dir->entries[n]; +} + +fz_archive * +fz_open_directory(fz_context *ctx, const char *path) +{ + fz_directory *dir; +#ifdef _WIN32 + WCHAR *wpath = NULL; + size_t z = 3; + HANDLE h = NULL; + WIN32_FIND_DATAW dw; + + fz_var(wpath); + fz_var(h); +#else + DIR *dp; + struct dirent *ep; + + fz_var(dp); +#endif + + if (!fz_is_directory(ctx, path)) + fz_throw(ctx, FZ_ERROR_FORMAT, "'%s' is not a directory", path); + + dir = fz_new_derived_archive(ctx, NULL, fz_directory); + dir->super.format = "dir"; + dir->super.count_entries = count_dir_entries; + dir->super.list_entry = list_dir_entry; + dir->super.has_entry = has_dir_entry; + dir->super.read_entry = read_dir_entry; + dir->super.open_entry = open_dir_entry; + dir->super.drop_archive = drop_directory; + + fz_try(ctx) + { +#ifdef _WIN32 + char const *p = path; + WCHAR *w; + while (*p) + { + int rune; + p += fz_chartorune(&rune, p); + if (rune >= 0x10000 || rune < 0) + { + errno = EINVAL; + fz_throw(ctx, FZ_ERROR_SYSTEM, "Unrepresentable UTF-8 char in directory name"); + } + z++; + } + w = wpath = fz_malloc(ctx, z * sizeof(WCHAR)); + p = path; + while (*p) + { + int rune; + p += fz_chartorune(&rune, p); + *w++ = rune; + } + w[0] = '\\'; + w[1] = '*'; + w[2] = 0; + + /* Now enumerate the paths. */ + h = FindFirstFileW(wpath, &dw); + if (h == INVALID_HANDLE_VALUE) + break; + + do + { + char *u; + + if (dir->max_entries == dir->num_entries) + { + int newmax = dir->max_entries * 2; + if (newmax == 0) + newmax = 32; + + dir->entries = fz_realloc(ctx, dir->entries, sizeof(*dir->entries) * newmax); + dir->max_entries = newmax; + } + + /* Count the len as utf-8. */ + w = dw.cFileName; + z = 1; + while (*w) + z += fz_runelen(*w++); + + u = dir->entries[dir->num_entries] = fz_malloc(ctx, z); + dir->num_entries++; + + /* Copy the name across. */ + w = dw.cFileName; + while (*w) + u += fz_runetochar(u, *w++); + *u = 0; + } + while (FindNextFileW(h, &dw)); +#else + dp = opendir(path); + if (dp == NULL) + break; + + while ((ep = readdir(dp)) != NULL) + { + if (dir->max_entries == dir->num_entries) + { + int newmax = dir->max_entries * 2; + if (newmax == 0) + newmax = 32; + + dir->entries = fz_realloc(ctx, dir->entries, sizeof(*dir->entries) * newmax); + dir->max_entries = newmax; + } + + dir->entries[dir->num_entries] = fz_strdup(ctx, ep->d_name); + dir->num_entries++; + } +#endif + dir->path = fz_strdup(ctx, path); + } + fz_always(ctx) + { +#ifdef _WIN32 + fz_free(ctx, wpath); + if (h) + (void)FindClose(h); +#else + if (dp) + (void)closedir(dp); +#endif + } + fz_catch(ctx) + { + fz_drop_archive(ctx, &dir->super); + fz_rethrow(ctx); + } + + return &dir->super; +}
