1 #include "mupdf/fitz.h"
2
3 #include <string.h>
4
5 /* Return non-null terminated pointers to key/value entries in comma separated
6 * option string. A plain key has the default value 'yes'. Use strncmp to compare
7 * key/value strings. */
8 static const char *
fz_get_option(fz_context * ctx,const char ** key,const char ** val,const char * opts)9 fz_get_option(fz_context *ctx, const char **key, const char **val, const char *opts)
10 {
11 if (!opts || *opts == 0)
12 return NULL;
13
14 if (*opts == ',')
15 ++opts;
16
17 *key = opts;
18 while (*opts != 0 && *opts != ',' && *opts != '=')
19 ++opts;
20
21 if (*opts == '=')
22 {
23 *val = ++opts;
24 while (*opts != 0 && *opts != ',')
25 ++opts;
26 }
27 else
28 {
29 *val = "yes";
30 }
31
32 return opts;
33 }
34
35 int
fz_has_option(fz_context * ctx,const char * opts,const char * key,const char ** val)36 fz_has_option(fz_context *ctx, const char *opts, const char *key, const char **val)
37 {
38 const char *straw;
39 size_t n = strlen(key);
40 while ((opts = fz_get_option(ctx, &straw, val, opts)))
41 if (!strncmp(straw, key, n) && (straw[n] == '=' || straw[n] == ',' || straw[n] == 0))
42 return 1;
43 return 0;
44 }
45
46 int
fz_option_eq(const char * a,const char * b)47 fz_option_eq(const char *a, const char *b)
48 {
49 size_t n = strlen(b);
50 return !strncmp(a, b, n) && (a[n] == ',' || a[n] == 0);
51 }
52
53 size_t
fz_copy_option(fz_context * ctx,const char * val,char * dest,size_t maxlen)54 fz_copy_option(fz_context *ctx, const char *val, char *dest, size_t maxlen)
55 {
56 const char *e = val;
57 size_t len, len2;
58
59 if (val == NULL) {
60 if (maxlen)
61 *dest = 0;
62 return 0;
63 }
64
65 while (*e != ',' && *e != 0)
66 e++;
67
68 len = e-val;
69 len2 = len+1; /* Allow for terminator */
70 if (len > maxlen)
71 len = maxlen;
72 memcpy(dest, val, len);
73 if (len < maxlen)
74 memset(dest+len, 0, maxlen-len);
75
76 return len2 >= maxlen ? len2 - maxlen : 0;
77 }
78
fz_new_document_writer_of_size(fz_context * ctx,size_t size,fz_document_writer_begin_page_fn * begin_page,fz_document_writer_end_page_fn * end_page,fz_document_writer_close_writer_fn * close,fz_document_writer_drop_writer_fn * drop)79 fz_document_writer *fz_new_document_writer_of_size(fz_context *ctx, size_t size, fz_document_writer_begin_page_fn *begin_page,
80 fz_document_writer_end_page_fn *end_page, fz_document_writer_close_writer_fn *close, fz_document_writer_drop_writer_fn *drop)
81 {
82 fz_document_writer *wri = Memento_label(fz_calloc(ctx, 1, size), "fz_document_writer");
83
84 wri->begin_page = begin_page;
85 wri->end_page = end_page;
86 wri->close_writer = close;
87 wri->drop_writer = drop;
88
89 return wri;
90 }
91
fz_new_png_pixmap_writer(fz_context * ctx,const char * path,const char * options)92 fz_document_writer *fz_new_png_pixmap_writer(fz_context *ctx, const char *path, const char *options)
93 {
94 return fz_new_pixmap_writer(ctx, path, options, "out-%04d.png", 0, fz_save_pixmap_as_png);
95 }
96
fz_new_pam_pixmap_writer(fz_context * ctx,const char * path,const char * options)97 fz_document_writer *fz_new_pam_pixmap_writer(fz_context *ctx, const char *path, const char *options)
98 {
99 return fz_new_pixmap_writer(ctx, path, options, "out-%04d.pam", 0, fz_save_pixmap_as_pam);
100 }
101
fz_new_pnm_pixmap_writer(fz_context * ctx,const char * path,const char * options)102 fz_document_writer *fz_new_pnm_pixmap_writer(fz_context *ctx, const char *path, const char *options)
103 {
104 return fz_new_pixmap_writer(ctx, path, options, "out-%04d.pnm", 0, fz_save_pixmap_as_pnm);
105 }
106
fz_new_pgm_pixmap_writer(fz_context * ctx,const char * path,const char * options)107 fz_document_writer *fz_new_pgm_pixmap_writer(fz_context *ctx, const char *path, const char *options)
108 {
109 return fz_new_pixmap_writer(ctx, path, options, "out-%04d.pgm", 1, fz_save_pixmap_as_pnm);
110 }
111
fz_new_ppm_pixmap_writer(fz_context * ctx,const char * path,const char * options)112 fz_document_writer *fz_new_ppm_pixmap_writer(fz_context *ctx, const char *path, const char *options)
113 {
114 return fz_new_pixmap_writer(ctx, path, options, "out-%04d.ppm", 3, fz_save_pixmap_as_pnm);
115 }
116
fz_new_pbm_pixmap_writer(fz_context * ctx,const char * path,const char * options)117 fz_document_writer *fz_new_pbm_pixmap_writer(fz_context *ctx, const char *path, const char *options)
118 {
119 return fz_new_pixmap_writer(ctx, path, options, "out-%04d.pbm", 1, fz_save_pixmap_as_pbm);
120 }
121
fz_new_pkm_pixmap_writer(fz_context * ctx,const char * path,const char * options)122 fz_document_writer *fz_new_pkm_pixmap_writer(fz_context *ctx, const char *path, const char *options)
123 {
124 return fz_new_pixmap_writer(ctx, path, options, "out-%04d.pkm", 4, fz_save_pixmap_as_pkm);
125 }
126
is_extension(const char * a,const char * ext)127 static int is_extension(const char *a, const char *ext)
128 {
129 if (a[0] == '.')
130 ++a;
131 return !fz_strcasecmp(a, ext);
132 }
133
prev_period(const char * start,const char * p)134 static const char *prev_period(const char *start, const char *p)
135 {
136 while (--p > start)
137 if (*p == '.')
138 return p;
139 return NULL;
140 }
141
142 fz_document_writer *
fz_new_document_writer(fz_context * ctx,const char * path,const char * explicit_format,const char * options)143 fz_new_document_writer(fz_context *ctx, const char *path, const char *explicit_format, const char *options)
144 {
145 const char *format = explicit_format;
146 if (!format)
147 format = strrchr(path, '.');
148 while (format)
149 {
150 #if FZ_ENABLE_PDF
151 if (is_extension(format, "pdf"))
152 return fz_new_pdf_writer(ctx, path, options);
153 #endif
154
155 if (is_extension(format, "cbz"))
156 return fz_new_cbz_writer(ctx, path, options);
157
158 if (is_extension(format, "svg"))
159 return fz_new_svg_writer(ctx, path, options);
160
161 if (is_extension(format, "png"))
162 return fz_new_png_pixmap_writer(ctx, path, options);
163 if (is_extension(format, "pam"))
164 return fz_new_pam_pixmap_writer(ctx, path, options);
165 if (is_extension(format, "pnm"))
166 return fz_new_pnm_pixmap_writer(ctx, path, options);
167 if (is_extension(format, "pgm"))
168 return fz_new_pgm_pixmap_writer(ctx, path, options);
169 if (is_extension(format, "ppm"))
170 return fz_new_ppm_pixmap_writer(ctx, path, options);
171 if (is_extension(format, "pbm"))
172 return fz_new_pbm_pixmap_writer(ctx, path, options);
173 if (is_extension(format, "pkm"))
174 return fz_new_pkm_pixmap_writer(ctx, path, options);
175
176 if (is_extension(format, "pcl"))
177 return fz_new_pcl_writer(ctx, path, options);
178 if (is_extension(format, "pclm"))
179 return fz_new_pclm_writer(ctx, path, options);
180 if (is_extension(format, "ps"))
181 return fz_new_ps_writer(ctx, path, options);
182 if (is_extension(format, "pwg"))
183 return fz_new_pwg_writer(ctx, path, options);
184
185 if (is_extension(format, "txt") || is_extension(format, "text"))
186 return fz_new_text_writer(ctx, "text", path, options);
187 if (is_extension(format, "html"))
188 return fz_new_text_writer(ctx, "html", path, options);
189 if (is_extension(format, "xhtml"))
190 return fz_new_text_writer(ctx, "xhtml", path, options);
191 if (is_extension(format, "stext") || is_extension(format, "stext.xml"))
192 return fz_new_text_writer(ctx, "stext.xml", path, options);
193 if (is_extension(format, "stext.json"))
194 return fz_new_text_writer(ctx, "stext.json", path, options);
195
196 if (format != explicit_format)
197 format = prev_period(path, format);
198 else
199 format = NULL;
200 }
201 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot detect document format");
202 }
203
204 fz_document_writer *
fz_new_document_writer_with_output(fz_context * ctx,fz_output * out,const char * format,const char * options)205 fz_new_document_writer_with_output(fz_context *ctx, fz_output *out, const char *format, const char *options)
206 {
207 if (is_extension(format, "cbz"))
208 return fz_new_cbz_writer_with_output(ctx, out, options);
209 #if FZ_ENABLE_PDF
210 if (is_extension(format, "pdf"))
211 return fz_new_pdf_writer_with_output(ctx, out, options);
212 #endif
213
214 if (is_extension(format, "pcl"))
215 return fz_new_pcl_writer_with_output(ctx, out, options);
216 if (is_extension(format, "pclm"))
217 return fz_new_pclm_writer_with_output(ctx, out, options);
218 if (is_extension(format, "ps"))
219 return fz_new_ps_writer_with_output(ctx, out, options);
220 if (is_extension(format, "pwg"))
221 return fz_new_pwg_writer_with_output(ctx, out, options);
222
223 if (is_extension(format, "txt") || is_extension(format, "text"))
224 return fz_new_text_writer_with_output(ctx, "text", out, options);
225 if (is_extension(format, "html"))
226 return fz_new_text_writer_with_output(ctx, "html", out, options);
227 if (is_extension(format, "xhtml"))
228 return fz_new_text_writer_with_output(ctx, "xhtml", out, options);
229 if (is_extension(format, "stext") || is_extension(format, "stext.xml"))
230 return fz_new_text_writer_with_output(ctx, "stext.xml", out, options);
231 if (is_extension(format, "stext.json"))
232 return fz_new_text_writer_with_output(ctx, "stext.json", out, options);
233
234 fz_throw(ctx, FZ_ERROR_GENERIC, "unknown output document format: %s", format);
235 }
236
237 void
fz_close_document_writer(fz_context * ctx,fz_document_writer * wri)238 fz_close_document_writer(fz_context *ctx, fz_document_writer *wri)
239 {
240 if (wri->close_writer)
241 wri->close_writer(ctx, wri);
242 wri->close_writer = NULL;
243 }
244
245 void
fz_drop_document_writer(fz_context * ctx,fz_document_writer * wri)246 fz_drop_document_writer(fz_context *ctx, fz_document_writer *wri)
247 {
248 if (!wri)
249 return;
250
251 if (wri->close_writer)
252 fz_warn(ctx, "dropping unclosed document writer");
253 if (wri->drop_writer)
254 wri->drop_writer(ctx, wri);
255 if (wri->dev)
256 fz_drop_device(ctx, wri->dev);
257 fz_free(ctx, wri);
258 }
259
260 fz_device *
fz_begin_page(fz_context * ctx,fz_document_writer * wri,fz_rect mediabox)261 fz_begin_page(fz_context *ctx, fz_document_writer *wri, fz_rect mediabox)
262 {
263 if (!wri)
264 return NULL;
265 if (wri->dev)
266 fz_throw(ctx, FZ_ERROR_GENERIC, "called begin page without ending the previous page");
267 wri->dev = wri->begin_page(ctx, wri, mediabox);
268 return wri->dev;
269 }
270
271 void
fz_end_page(fz_context * ctx,fz_document_writer * wri)272 fz_end_page(fz_context *ctx, fz_document_writer *wri)
273 {
274 fz_device *dev;
275
276 if (!wri)
277 return;
278 dev = wri->dev;
279 wri->dev = NULL;
280 wri->end_page(ctx, wri, dev);
281 }
282
283 void
fz_write_document(fz_context * ctx,fz_document_writer * wri,fz_document * doc)284 fz_write_document(fz_context *ctx, fz_document_writer *wri, fz_document *doc)
285 {
286 int i, n;
287 fz_page *page = NULL;
288 fz_device *dev;
289
290 fz_var(page);
291
292 n = fz_count_pages(ctx, doc);
293 fz_try(ctx)
294 {
295 for (i = 0; i < n; i++)
296 {
297 page = fz_load_page(ctx, doc, i);
298 dev = fz_begin_page(ctx, wri, fz_bound_page(ctx, page));
299 fz_run_page(ctx, page, dev, fz_identity, NULL);
300 fz_drop_page(ctx, page);
301 page = NULL;
302 fz_end_page(ctx, wri);
303 }
304 }
305 fz_catch(ctx)
306 {
307 fz_drop_page(ctx, page);
308 fz_rethrow(ctx);
309 }
310 }
311