Change the translation of the "Help" menu item to "?", so that the menu can be displa...
[reactos.git] / rosapps / smartpdf / fitz / mupdf / pdf_stream.c
1 #include "fitz.h"
2 #include "mupdf.h"
3
4 /*
5 * Check if an object is a stream or not.
6 */
7 int
8 pdf_isstream(pdf_xref *xref, int oid, int gen)
9 {
10 fz_error *error;
11
12 if (oid < 0 || oid >= xref->len)
13 return 0;
14
15 error = pdf_cacheobject(xref, oid, gen);
16 if (error) {
17 fz_warn("%s", error->msg);
18 fz_droperror(error);
19 return 0;
20 }
21
22 return xref->table[oid].stmbuf || xref->table[oid].stmofs;
23 }
24
25 /*
26 * Create a filter given a name and param dictionary.
27 */
28 static fz_error *
29 buildonefilter(fz_filter **fp, fz_obj *f, fz_obj *p)
30 {
31 fz_filter *decompress;
32 fz_filter *predict;
33 fz_error *error;
34 char *s;
35
36 s = fz_toname(f);
37
38 if (!strcmp(s, "ASCIIHexDecode") || !strcmp(s, "AHx"))
39 return fz_newahxd(fp, p);
40
41 if (!strcmp(s, "ASCII85Decode") || !strcmp(s, "A85"))
42 return fz_newa85d(fp, p);
43
44 if (!strcmp(s, "CCITTFaxDecode") || !strcmp(s, "CCF"))
45 return fz_newfaxd(fp, p);
46
47 if (!strcmp(s, "DCTDecode") || !strcmp(s, "DCT"))
48 return fz_newdctd(fp, p);
49
50 if (!strcmp(s, "RunLengthDecode") || !strcmp(s, "RL"))
51 return fz_newrld(fp, p);
52
53 if (!strcmp(s, "FlateDecode") || !strcmp(s, "Fl"))
54 {
55 if (fz_isdict(p))
56 {
57 fz_obj *obj = fz_dictgets(p, "Predictor");
58 if (obj)
59 {
60 error = fz_newflated(&decompress, p);
61 if (error)
62 return error;
63
64 error = fz_newpredictd(&predict, p);
65 if (error)
66 {
67 fz_dropfilter(decompress);
68 return error;
69 }
70
71 error = fz_newpipeline(fp, decompress, predict);
72 fz_dropfilter(decompress);
73 fz_dropfilter(predict);
74 return error;
75 }
76 }
77 return fz_newflated(fp, p);
78 }
79
80 if (!strcmp(s, "LZWDecode") || !strcmp(s, "LZW"))
81 {
82 if (fz_isdict(p))
83 {
84 fz_obj *obj = fz_dictgets(p, "Predictor");
85 if (obj)
86 {
87 error = fz_newlzwd(&decompress, p);
88 if (error)
89 return error;
90
91 error = fz_newpredictd(&predict, p);
92 if (error)
93 {
94 fz_dropfilter(decompress);
95 return error;
96 }
97
98 error = fz_newpipeline(fp, decompress, predict);
99 fz_dropfilter(decompress);
100 fz_dropfilter(predict);
101 return error;
102 }
103 }
104 return fz_newlzwd(fp, p);
105 }
106
107 #ifdef HAVE_JBIG2DEC
108 if (!strcmp(s, "JBIG2Decode"))
109 {
110 /* TODO: extract and feed JBIG2Global */
111 return fz_newjbig2d(fp, p);
112 }
113 #endif
114
115 #ifdef HAVE_JASPER
116 if (!strcmp(s, "JPXDecode"))
117 return fz_newjpxd(fp, p);
118 #endif
119
120 return fz_throw("syntaxerror: unknown filter: %s", s);
121 }
122
123 /*
124 * Build a chain of filters given filter names and param dicts.
125 * If head is given, start filter chain with it.
126 * Assume ownership of head.
127 */
128 static fz_error *
129 buildfilterchain(fz_filter **filterp, fz_filter *head, fz_obj *fs, fz_obj *ps)
130 {
131 fz_error *error;
132 fz_filter *newhead;
133 fz_filter *tail;
134 fz_obj *f;
135 fz_obj *p;
136 int i;
137
138 for (i = 0; i < fz_arraylen(fs); i++)
139 {
140 f = fz_arrayget(fs, i);
141 if (fz_isarray(ps))
142 p = fz_arrayget(ps, i);
143 else
144 p = nil;
145
146 error = buildonefilter(&tail, f, p);
147 if (error)
148 return error;
149
150 if (head)
151 {
152 error = fz_newpipeline(&newhead, head, tail);
153 fz_dropfilter(head);
154 fz_dropfilter(tail);
155 if (error)
156 {
157 fz_dropfilter(newhead);
158 return error;
159 }
160 head = newhead;
161 }
162 else
163 head = tail;
164 }
165
166 *filterp = head;
167 return nil;
168 }
169
170 /*
171 * Build a filter for reading raw stream data.
172 * This is a null filter to constrain reading to the
173 * stream length, followed by a decryption filter.
174 */
175 static fz_error *
176 buildrawfilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj, int oid, int gen)
177 {
178 fz_error *error;
179 fz_filter *base;
180 fz_obj *stmlen;
181 int len;
182
183 stmlen = fz_dictgets(stmobj, "Length");
184 error = pdf_resolve(&stmlen, xref);
185 if (error)
186 return error;
187 len = fz_toint(stmlen);
188 fz_dropobj(stmlen);
189
190 error = fz_newnullfilter(&base, len);
191 if (error)
192 return error;
193
194 if (xref->crypt)
195 {
196 fz_filter *crypt;
197 fz_filter *pipe;
198
199 error = pdf_cryptstream(&crypt, xref->crypt, oid, gen);
200 if (error)
201 {
202 fz_dropfilter(base);
203 return error;
204 }
205
206 error = fz_newpipeline(&pipe, base, crypt);
207 fz_dropfilter(base);
208 fz_dropfilter(crypt);
209 if (error)
210 return error;
211
212 *filterp = pipe;
213 }
214 else
215 {
216 *filterp = base;
217 }
218
219 return nil;
220 }
221
222 /*
223 * Construct a filter to decode a stream, without
224 * constraining to stream length, and without decryption.
225 */
226 fz_error *
227 pdf_buildinlinefilter(fz_filter **filterp, fz_obj *stmobj)
228 {
229 fz_obj *filters;
230 fz_obj *params;
231
232 filters = fz_dictgetsa(stmobj, "Filter", "F");
233 params = fz_dictgetsa(stmobj, "DecodeParms", "DP");
234
235 *filterp = nil;
236
237 if (filters)
238 {
239 if (fz_isname(filters))
240 return buildonefilter(filterp, filters, params);
241 else if (fz_arraylen(filters) > 0)
242 return buildfilterchain(filterp, nil, filters, params);
243 }
244
245 /* uh oh, no filter */
246
247 return nil;
248 }
249
250 /*
251 * Construct a filter to decode a stream, constraining
252 * to stream length and decrypting.
253 */
254 static fz_error *
255 pdf_buildfilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj, int oid, int gen)
256 {
257 fz_error *error;
258 fz_filter *base, *pipe, *tmp;
259 fz_obj *filters;
260 fz_obj *params;
261
262 error = buildrawfilter(&base, xref, stmobj, oid, gen);
263 if (error)
264 return error;
265
266 filters = fz_dictgetsa(stmobj, "Filter", "F");
267 params = fz_dictgetsa(stmobj, "DecodeParms", "DP");
268
269 if (filters)
270 {
271 error = pdf_resolve(&filters, xref);
272 if (error)
273 goto cleanup0;
274
275 if (params)
276 {
277 error = pdf_resolve(&params, xref);
278 if (error)
279 goto cleanup1;
280 }
281
282 if (fz_isname(filters))
283 {
284 error = buildonefilter(&tmp, filters, params);
285 if (error)
286 goto cleanup2;
287
288 error = fz_newpipeline(&pipe, base, tmp);
289 fz_dropfilter(base);
290 fz_dropfilter(tmp);
291 if (error)
292 goto cleanup2;
293 }
294 else
295 {
296 error = buildfilterchain(&pipe, base, filters, params);
297 if (error)
298 goto cleanup2;
299 }
300
301 if (params)
302 fz_dropobj(params);
303
304 fz_dropobj(filters);
305
306 *filterp = pipe;
307 }
308 else
309 {
310 *filterp = base;
311 }
312
313 return nil;
314
315 cleanup2:
316 if (params)
317 fz_dropobj(params);
318 cleanup1:
319 fz_dropobj(filters);
320 cleanup0:
321 fz_dropfilter(base);
322 return error;
323 }
324
325 /*
326 * Open a stream for reading the raw (compressed but decrypted) data.
327 * Using xref->file while this is open is a bad idea.
328 */
329 fz_error *
330 pdf_openrawstream(fz_stream **stmp, pdf_xref *xref, int oid, int gen)
331 {
332 pdf_xrefentry *x;
333 fz_error *error;
334 fz_filter *filter;
335 int n;
336
337 if (oid < 0 || oid >= xref->len)
338 return fz_throw("rangecheck: object id out of range");
339
340 x = xref->table + oid;
341
342 error = pdf_cacheobject(xref, oid, gen);
343 if (error)
344 return error;
345
346 if (x->stmbuf)
347 {
348 return fz_openrbuffer(stmp, x->stmbuf);
349 }
350
351 if (x->stmofs)
352 {
353 error = buildrawfilter(&filter, xref, x->obj, oid, gen);
354 if (error)
355 return error;
356
357 n = fz_seek(xref->file, x->stmofs, 0);
358 if (n == -1)
359 {
360 fz_dropfilter(filter);
361 return fz_ioerror(xref->file);
362 }
363
364 error = fz_openrfilter(stmp, filter, xref->file);
365
366 fz_dropfilter(filter);
367
368 if (error)
369 return error;
370
371 return nil;
372 }
373
374 return fz_throw("syntaxerror: object is not a stream");
375 }
376
377 /*
378 * Open a stream for reading uncompressed data.
379 * Put the opened file in xref->stream.
380 * Using xref->file while a stream is open is a Bad idea.
381 */
382 fz_error *
383 pdf_openstream(fz_stream **stmp, pdf_xref *xref, int oid, int gen)
384 {
385 pdf_xrefentry *x;
386 fz_error *error;
387 fz_stream *rawstm;
388 fz_filter *filter;
389 int n;
390
391 if (oid < 0 || oid >= xref->len)
392 return fz_throw("rangecheck: object id out of range");
393
394 x = xref->table + oid;
395
396 error = pdf_cacheobject(xref, oid, gen);
397 if (error)
398 return error;
399
400 if (x->stmbuf)
401 {
402 error = pdf_buildfilter(&filter, xref, x->obj, oid, gen);
403 if (error)
404 return error;
405
406 error = fz_openrbuffer(&rawstm, x->stmbuf);
407 if (error)
408 {
409 fz_dropfilter(filter);
410 return error;
411 }
412
413 error = fz_openrfilter(stmp, filter, rawstm);
414 fz_dropfilter(filter);
415 fz_dropstream(rawstm);
416 return error;
417 }
418
419 if (x->stmofs)
420 {
421 error = pdf_buildfilter(&filter, xref, x->obj, oid, gen);
422 if (error)
423 return error;
424
425 n = fz_seek(xref->file, x->stmofs, 0);
426 if (n == -1)
427 {
428 fz_dropfilter(filter);
429 return fz_ioerror(xref->file);
430 }
431
432 error = fz_openrfilter(stmp, filter, xref->file);
433 fz_dropfilter(filter);
434 if (error)
435 return error;
436
437 return nil;
438 }
439
440 return fz_throw("syntaxerror: object is not a stream");
441 }
442
443 /*
444 * Load raw (compressed but decrypted) contents of a stream into buf.
445 */
446 fz_error *
447 pdf_loadrawstream(fz_buffer **bufp, pdf_xref *xref, int oid, int gen)
448 {
449 fz_error *error;
450 fz_stream *stm;
451 int n;
452
453 error = pdf_openrawstream(&stm, xref, oid, gen);
454 if (error)
455 return error;
456
457 n = fz_readall(bufp, stm);
458 if (n < 0)
459 error = fz_ioerror(stm);
460 else
461 error = nil;
462
463 fz_dropstream(stm);
464
465 return error;
466 }
467
468 /*
469 * Load uncompressed contents of a stream into buf.
470 */
471 fz_error *
472 pdf_loadstream(fz_buffer **bufp, pdf_xref *xref, int oid, int gen)
473 {
474 fz_error *error;
475 fz_stream *stm;
476 int n;
477
478 error = pdf_openstream(&stm, xref, oid, gen);
479 if (error)
480 return error;
481
482 n = fz_readall(bufp, stm);
483 if (n < 0)
484 error = fz_ioerror(stm);
485 else
486 error = nil;
487
488 fz_dropstream(stm);
489
490 return error;
491 }
492