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
11typedef struct fz_directory_s fz_directory;
12struct fz_directory_s
13{
14 fz_archive super;
15
16 char *path;
17};
18
19static 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
26static 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
36static 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
46static 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
56int
57fz_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*/
79fz_archive *
80fz_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