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
12 {
13 	fz_archive super;
14 
15 	char *path;
16 } fz_directory;
17 
drop_directory(fz_context * ctx,fz_archive * arch)18 static void drop_directory(fz_context *ctx, fz_archive *arch)
19 {
20 	fz_directory *dir = (fz_directory *) arch;
21 
22 	fz_free(ctx, dir->path);
23 }
24 
open_dir_entry(fz_context * ctx,fz_archive * arch,const char * name)25 static fz_stream *open_dir_entry(fz_context *ctx, fz_archive *arch, const char *name)
26 {
27 	fz_directory *dir = (fz_directory *) arch;
28 	char path[2048];
29 	fz_strlcpy(path, dir->path, sizeof path);
30 	fz_strlcat(path, "/", sizeof path);
31 	fz_strlcat(path, name, sizeof path);
32 	return fz_open_file(ctx, path);
33 }
34 
read_dir_entry(fz_context * ctx,fz_archive * arch,const char * name)35 static fz_buffer *read_dir_entry(fz_context *ctx, fz_archive *arch, const char *name)
36 {
37 	fz_directory *dir = (fz_directory *) arch;
38 	char path[2048];
39 	fz_strlcpy(path, dir->path, sizeof path);
40 	fz_strlcat(path, "/", sizeof path);
41 	fz_strlcat(path, name, sizeof path);
42 	return fz_read_file(ctx, path);
43 }
44 
has_dir_entry(fz_context * ctx,fz_archive * arch,const char * name)45 static int has_dir_entry(fz_context *ctx, fz_archive *arch, const char *name)
46 {
47 	fz_directory *dir = (fz_directory *) arch;
48 	char path[2048];
49 	fz_strlcpy(path, dir->path, sizeof path);
50 	fz_strlcat(path, "/", sizeof path);
51 	fz_strlcat(path, name, sizeof path);
52 	return fz_file_exists(ctx, path);
53 }
54 
55 int
fz_is_directory(fz_context * ctx,const char * path)56 fz_is_directory(fz_context *ctx, const char *path)
57 {
58 	struct stat info;
59 
60 	if (stat(path, &info) < 0)
61 		return 0;
62 
63 	return S_ISDIR(info.st_mode);
64 }
65 
66 fz_archive *
fz_open_directory(fz_context * ctx,const char * path)67 fz_open_directory(fz_context *ctx, const char *path)
68 {
69 	fz_directory *dir;
70 
71 	if (!fz_is_directory(ctx, path))
72 		fz_throw(ctx, FZ_ERROR_GENERIC, "'%s' is not a directory", path);
73 
74 	dir = fz_new_derived_archive(ctx, NULL, fz_directory);
75 	dir->super.format = "dir";
76 	dir->super.has_entry = has_dir_entry;
77 	dir->super.read_entry = read_dir_entry;
78 	dir->super.open_entry = open_dir_entry;
79 	dir->super.drop_archive = drop_directory;
80 
81 	fz_try(ctx)
82 	{
83 		dir->path = fz_strdup(ctx, path);
84 	}
85 	fz_catch(ctx)
86 	{
87 		fz_drop_archive(ctx, &dir->super);
88 		fz_rethrow(ctx);
89 	}
90 
91 	return &dir->super;
92 }
93