1 | #include "mupdf/fitz.h" |
2 | #include "xps-imp.h" |
3 | |
4 | #include <string.h> |
5 | |
6 | static void xps_init_document(fz_context *ctx, xps_document *doc); |
7 | |
8 | static xps_part * |
9 | xps_new_part(fz_context *ctx, xps_document *doc, char *name, fz_buffer *data) |
10 | { |
11 | xps_part *part; |
12 | |
13 | part = fz_malloc_struct(ctx, xps_part); |
14 | fz_try(ctx) |
15 | { |
16 | part->name = fz_strdup(ctx, name); |
17 | part->data = data; /* take ownership of buffer */ |
18 | } |
19 | fz_catch(ctx) |
20 | { |
21 | fz_drop_buffer(ctx, data); |
22 | fz_free(ctx, part); |
23 | fz_rethrow(ctx); |
24 | } |
25 | |
26 | return part; |
27 | } |
28 | |
29 | void |
30 | xps_drop_part(fz_context *ctx, xps_document *doc, xps_part *part) |
31 | { |
32 | fz_free(ctx, part->name); |
33 | fz_drop_buffer(ctx, part->data); |
34 | fz_free(ctx, part); |
35 | } |
36 | |
37 | /* |
38 | * Read and interleave split parts from a ZIP file. |
39 | */ |
40 | xps_part * |
41 | xps_read_part(fz_context *ctx, xps_document *doc, char *partname) |
42 | { |
43 | fz_archive *zip = doc->zip; |
44 | fz_buffer *buf = NULL; |
45 | fz_buffer *tmp = NULL; |
46 | char path[2048]; |
47 | int count; |
48 | char *name; |
49 | int seen_last; |
50 | |
51 | fz_var(buf); |
52 | fz_var(tmp); |
53 | |
54 | name = partname; |
55 | if (name[0] == '/') |
56 | name ++; |
57 | |
58 | fz_try(ctx) |
59 | { |
60 | /* All in one piece */ |
61 | if (fz_has_archive_entry(ctx, zip, name)) |
62 | { |
63 | buf = fz_read_archive_entry(ctx, zip, name); |
64 | } |
65 | |
66 | /* Assemble all the pieces */ |
67 | else |
68 | { |
69 | buf = fz_new_buffer(ctx, 512); |
70 | seen_last = 0; |
71 | for (count = 0; !seen_last; ++count) |
72 | { |
73 | fz_snprintf(path, sizeof path, "%s/[%d].piece" , name, count); |
74 | if (fz_has_archive_entry(ctx, zip, path)) |
75 | { |
76 | tmp = fz_read_archive_entry(ctx, zip, path); |
77 | fz_append_buffer(ctx, buf, tmp); |
78 | fz_drop_buffer(ctx, tmp); |
79 | tmp = NULL; |
80 | } |
81 | else |
82 | { |
83 | fz_snprintf(path, sizeof path, "%s/[%d].last.piece" , name, count); |
84 | if (fz_has_archive_entry(ctx, zip, path)) |
85 | { |
86 | tmp = fz_read_archive_entry(ctx, zip, path); |
87 | fz_append_buffer(ctx, buf, tmp); |
88 | fz_drop_buffer(ctx, tmp); |
89 | tmp = NULL; |
90 | seen_last = 1; |
91 | } |
92 | else |
93 | fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find all pieces for part '%s'" , partname); |
94 | } |
95 | } |
96 | } |
97 | |
98 | } |
99 | fz_catch(ctx) |
100 | { |
101 | fz_drop_buffer(ctx, tmp); |
102 | fz_drop_buffer(ctx, buf); |
103 | fz_rethrow(ctx); |
104 | } |
105 | |
106 | return xps_new_part(ctx, doc, partname, buf); |
107 | } |
108 | |
109 | int |
110 | xps_has_part(fz_context *ctx, xps_document *doc, char *name) |
111 | { |
112 | char buf[2048]; |
113 | if (name[0] == '/') |
114 | name++; |
115 | if (fz_has_archive_entry(ctx, doc->zip, name)) |
116 | return 1; |
117 | fz_snprintf(buf, sizeof buf, "%s/[0].piece" , name); |
118 | if (fz_has_archive_entry(ctx, doc->zip, buf)) |
119 | return 1; |
120 | fz_snprintf(buf, sizeof buf, "%s/[0].last.piece" , name); |
121 | if (fz_has_archive_entry(ctx, doc->zip, buf)) |
122 | return 1; |
123 | return 0; |
124 | } |
125 | |
126 | static fz_document * |
127 | xps_open_document_with_directory(fz_context *ctx, const char *directory) |
128 | { |
129 | xps_document *doc; |
130 | |
131 | doc = fz_malloc_struct(ctx, xps_document); |
132 | xps_init_document(ctx, doc); |
133 | |
134 | fz_try(ctx) |
135 | { |
136 | doc->zip = fz_open_directory(ctx, directory); |
137 | xps_read_page_list(ctx, doc); |
138 | } |
139 | fz_catch(ctx) |
140 | { |
141 | fz_drop_document(ctx, &doc->super); |
142 | fz_rethrow(ctx); |
143 | } |
144 | |
145 | return (fz_document*)doc; |
146 | } |
147 | |
148 | fz_document * |
149 | xps_open_document_with_stream(fz_context *ctx, fz_stream *file) |
150 | { |
151 | xps_document *doc; |
152 | |
153 | doc = fz_malloc_struct(ctx, xps_document); |
154 | xps_init_document(ctx, doc); |
155 | |
156 | fz_try(ctx) |
157 | { |
158 | doc->zip = fz_open_zip_archive_with_stream(ctx, file); |
159 | xps_read_page_list(ctx, doc); |
160 | } |
161 | fz_catch(ctx) |
162 | { |
163 | fz_drop_document(ctx, &doc->super); |
164 | fz_rethrow(ctx); |
165 | } |
166 | |
167 | return (fz_document*)doc; |
168 | } |
169 | |
170 | fz_document * |
171 | xps_open_document(fz_context *ctx, const char *filename) |
172 | { |
173 | fz_stream *file; |
174 | char *p; |
175 | fz_document *doc = NULL; |
176 | |
177 | if (strstr(filename, "/_rels/.rels" ) || strstr(filename, "\\_rels\\.rels" )) |
178 | { |
179 | char *buf = fz_strdup(ctx, filename); |
180 | p = strstr(buf, "/_rels/.rels" ); |
181 | if (!p) |
182 | p = strstr(buf, "\\_rels\\.rels" ); |
183 | *p = 0; |
184 | fz_try(ctx) |
185 | doc = xps_open_document_with_directory(ctx, buf); |
186 | fz_always(ctx) |
187 | fz_free(ctx, buf); |
188 | fz_catch(ctx) |
189 | fz_rethrow(ctx); |
190 | return doc; |
191 | } |
192 | |
193 | file = fz_open_file(ctx, filename); |
194 | |
195 | fz_try(ctx) |
196 | doc = xps_open_document_with_stream(ctx, file); |
197 | fz_always(ctx) |
198 | fz_drop_stream(ctx, file); |
199 | fz_catch(ctx) |
200 | fz_rethrow(ctx); |
201 | |
202 | return (fz_document*)doc; |
203 | } |
204 | |
205 | static void |
206 | xps_drop_document(fz_context *ctx, fz_document *doc_) |
207 | { |
208 | xps_document *doc = (xps_document*)doc_; |
209 | xps_font_cache *font, *next; |
210 | |
211 | if (doc->zip) |
212 | fz_drop_archive(ctx, doc->zip); |
213 | |
214 | font = doc->font_table; |
215 | while (font) |
216 | { |
217 | next = font->next; |
218 | fz_drop_font(ctx, font->font); |
219 | fz_free(ctx, font->name); |
220 | fz_free(ctx, font); |
221 | font = next; |
222 | } |
223 | |
224 | xps_drop_page_list(ctx, doc); |
225 | |
226 | fz_free(ctx, doc->start_part); |
227 | } |
228 | |
229 | static int |
230 | xps_lookup_metadata(fz_context *ctx, fz_document *doc_, const char *key, char *buf, int size) |
231 | { |
232 | if (!strcmp(key, "format" )) |
233 | return (int)fz_strlcpy(buf, "XPS" , size); |
234 | return -1; |
235 | } |
236 | |
237 | static void |
238 | xps_init_document(fz_context *ctx, xps_document *doc) |
239 | { |
240 | doc->super.refs = 1; |
241 | doc->super.drop_document = xps_drop_document; |
242 | doc->super.load_outline = xps_load_outline; |
243 | doc->super.resolve_link = xps_lookup_link_target; |
244 | doc->super.count_pages = xps_count_pages; |
245 | doc->super.load_page = xps_load_page; |
246 | doc->super.lookup_metadata = xps_lookup_metadata; |
247 | } |
248 | |