1 | #include "mupdf/fitz.h" |
2 | |
3 | #include <string.h> |
4 | #include <errno.h> |
5 | #include <sys/stat.h> |
6 | |
7 | #ifdef _MSC_VER |
8 | #define stat _stat |
9 | #endif |
10 | |
11 | typedef struct fz_directory_s fz_directory; |
12 | struct fz_directory_s |
13 | { |
14 | fz_archive super; |
15 | |
16 | char *path; |
17 | }; |
18 | |
19 | static void drop_directory(fz_context *ctx, fz_archive *arch) |
20 | { |
21 | fz_directory *dir = (fz_directory *) arch; |
22 | |
23 | fz_free(ctx, dir->path); |
24 | } |
25 | |
26 | static fz_stream *open_dir_entry(fz_context *ctx, fz_archive *arch, const char *name) |
27 | { |
28 | fz_directory *dir = (fz_directory *) arch; |
29 | char path[2048]; |
30 | fz_strlcpy(path, dir->path, sizeof path); |
31 | fz_strlcat(path, "/" , sizeof path); |
32 | fz_strlcat(path, name, sizeof path); |
33 | return fz_open_file(ctx, path); |
34 | } |
35 | |
36 | static fz_buffer *read_dir_entry(fz_context *ctx, fz_archive *arch, const char *name) |
37 | { |
38 | fz_directory *dir = (fz_directory *) arch; |
39 | char path[2048]; |
40 | fz_strlcpy(path, dir->path, sizeof path); |
41 | fz_strlcat(path, "/" , sizeof path); |
42 | fz_strlcat(path, name, sizeof path); |
43 | return fz_read_file(ctx, path); |
44 | } |
45 | |
46 | static int has_dir_entry(fz_context *ctx, fz_archive *arch, const char *name) |
47 | { |
48 | fz_directory *dir = (fz_directory *) arch; |
49 | char path[2048]; |
50 | fz_strlcpy(path, dir->path, sizeof path); |
51 | fz_strlcat(path, "/" , sizeof path); |
52 | fz_strlcat(path, name, sizeof path); |
53 | return fz_file_exists(ctx, path); |
54 | } |
55 | |
56 | int |
57 | fz_is_directory(fz_context *ctx, const char *path) |
58 | { |
59 | struct stat info; |
60 | |
61 | if (stat(path, &info) < 0) |
62 | return 0; |
63 | |
64 | return S_ISDIR(info.st_mode); |
65 | } |
66 | |
67 | /* |
68 | Open a directory as if it was an archive. |
69 | |
70 | A special case where a directory is opened as if it was an |
71 | archive. |
72 | |
73 | Note that for directories it is not possible to retrieve the |
74 | number of entries or list the entries. It is however possible |
75 | to check if the archive has a particular entry. |
76 | |
77 | path: a path to a directory as it would be given to opendir(3). |
78 | */ |
79 | fz_archive * |
80 | fz_open_directory(fz_context *ctx, const char *path) |
81 | { |
82 | fz_directory *dir; |
83 | |
84 | if (!fz_is_directory(ctx, path)) |
85 | fz_throw(ctx, FZ_ERROR_GENERIC, "'%s' is not a directory" , path); |
86 | |
87 | dir = fz_new_derived_archive(ctx, NULL, fz_directory); |
88 | dir->super.format = "dir" ; |
89 | dir->super.has_entry = has_dir_entry; |
90 | dir->super.read_entry = read_dir_entry; |
91 | dir->super.open_entry = open_dir_entry; |
92 | dir->super.drop_archive = drop_directory; |
93 | |
94 | fz_try(ctx) |
95 | { |
96 | dir->path = fz_strdup(ctx, path); |
97 | } |
98 | fz_catch(ctx) |
99 | { |
100 | fz_drop_archive(ctx, &dir->super); |
101 | fz_rethrow(ctx); |
102 | } |
103 | |
104 | return &dir->super; |
105 | } |
106 | |