1#include "mupdf/fitz.h"
2#include "xps-imp.h"
3
4#include <string.h>
5
6static void xps_init_document(fz_context *ctx, xps_document *doc);
7
8static xps_part *
9xps_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
29void
30xps_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 */
40xps_part *
41xps_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
109int
110xps_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
126static fz_document *
127xps_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
148fz_document *
149xps_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
170fz_document *
171xps_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
205static void
206xps_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
229static int
230xps_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
237static void
238xps_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