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