Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4680 right-hear 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_is_stream(pdf_xref *xref, int num, int gen)
9
{
10
	fz_error error;
11
 
12
	if (num < 0 || num >= xref->len)
13
		return 0;
14
 
15
	error = pdf_cache_object(xref, num, gen);
16
	if (error)
17
	{
18
		fz_catch(error, "cannot load object, ignoring error");
19
		return 0;
20
	}
21
 
22
	return xref->table[num].stm_ofs > 0;
23
}
24
 
25
/*
26
 * Scan stream dictionary for an explicit /Crypt filter
27
 */
28
static int
29
pdf_stream_has_crypt(fz_obj *stm)
30
{
31
	fz_obj *filters;
32
	fz_obj *obj;
33
	int i;
34
 
35
	filters = fz_dict_getsa(stm, "Filter", "F");
36
	if (filters)
37
	{
38
		if (!strcmp(fz_to_name(filters), "Crypt"))
39
			return 1;
40
		if (fz_is_array(filters))
41
		{
42
			for (i = 0; i < fz_array_len(filters); i++)
43
			{
44
				obj = fz_array_get(filters, i);
45
				if (!strcmp(fz_to_name(obj), "Crypt"))
46
					return 1;
47
			}
48
		}
49
	}
50
	return 0;
51
}
52
 
53
/*
54
 * Create a filter given a name and param dictionary.
55
 */
56
static fz_stream *
57
build_filter(fz_stream *chain, pdf_xref * xref, fz_obj * f, fz_obj * p, int num, int gen)
58
{
59
	fz_error error;
60
	char *s;
61
 
62
	s = fz_to_name(f);
63
 
64
	if (!strcmp(s, "ASCIIHexDecode") || !strcmp(s, "AHx"))
65
		return fz_open_ahxd(chain);
66
 
67
	else if (!strcmp(s, "ASCII85Decode") || !strcmp(s, "A85"))
68
		return fz_open_a85d(chain);
69
 
70
	else if (!strcmp(s, "CCITTFaxDecode") || !strcmp(s, "CCF"))
71
		return fz_open_faxd(chain, p);
72
 
73
	else if (!strcmp(s, "DCTDecode") || !strcmp(s, "DCT"))
74
		return fz_open_dctd(chain, p);
75
 
76
	else if (!strcmp(s, "RunLengthDecode") || !strcmp(s, "RL"))
77
		return fz_open_rld(chain);
78
 
79
	else if (!strcmp(s, "FlateDecode") || !strcmp(s, "Fl"))
80
	{
81
		fz_obj *obj = fz_dict_gets(p, "Predictor");
82
		if (fz_to_int(obj) > 1)
83
			return fz_open_predict(fz_open_flated(chain), p);
84
		return fz_open_flated(chain);
85
	}
86
 
87
	else if (!strcmp(s, "LZWDecode") || !strcmp(s, "LZW"))
88
	{
89
		fz_obj *obj = fz_dict_gets(p, "Predictor");
90
		if (fz_to_int(obj) > 1)
91
			return fz_open_predict(fz_open_lzwd(chain, p), p);
92
		return fz_open_lzwd(chain, p);
93
	}
94
 
95
	else if (!strcmp(s, "JBIG2Decode"))
96
	{
97
		fz_obj *obj = fz_dict_gets(p, "JBIG2Globals");
98
		if (obj)
99
		{
100
			fz_buffer *globals;
101
			error = pdf_load_stream(&globals, xref, fz_to_num(obj), fz_to_gen(obj));
102
			if (error)
103
				fz_catch(error, "cannot load jbig2 global segments");
104
			chain = fz_open_jbig2d(chain, globals);
105
			fz_drop_buffer(globals);
106
			return chain;
107
		}
108
		return fz_open_jbig2d(chain, NULL);
109
	}
110
 
111
	else if (!strcmp(s, "JPXDecode"))
112
		return chain; /* JPX decoding is special cased in the image loading code */
113
 
114
	else if (!strcmp(s, "Crypt"))
115
	{
116
		fz_obj *name;
117
 
118
		if (!xref->crypt)
119
		{
120
			fz_warn("crypt filter in unencrypted document");
121
			return chain;
122
		}
123
 
124
		name = fz_dict_gets(p, "Name");
125
		if (fz_is_name(name))
126
			return pdf_open_crypt_with_filter(chain, xref->crypt, fz_to_name(name), num, gen);
127
 
128
		return chain;
129
	}
130
 
131
	fz_warn("unknown filter name (%s)", s);
132
	return chain;
133
}
134
 
135
/*
136
 * Build a chain of filters given filter names and param dicts.
137
 * If head is given, start filter chain with it.
138
 * Assume ownership of head.
139
 */
140
static fz_stream *
141
build_filter_chain(fz_stream *chain, pdf_xref *xref, fz_obj *fs, fz_obj *ps, int num, int gen)
142
{
143
	fz_obj *f;
144
	fz_obj *p;
145
	int i;
146
 
147
	for (i = 0; i < fz_array_len(fs); i++)
148
	{
149
		f = fz_array_get(fs, i);
150
		p = fz_array_get(ps, i);
151
		chain = build_filter(chain, xref, f, p, num, gen);
152
	}
153
 
154
	return chain;
155
}
156
 
157
/*
158
 * Build a filter for reading raw stream data.
159
 * This is a null filter to constrain reading to the
160
 * stream length, followed by a decryption filter.
161
 */
162
static fz_stream *
163
pdf_open_raw_filter(fz_stream *chain, pdf_xref *xref, fz_obj *stmobj, int num, int gen)
164
{
165
	int hascrypt;
166
	int len;
167
 
168
	/* don't close chain when we close this filter */
169
	fz_keep_stream(chain);
170
 
171
	len = fz_to_int(fz_dict_gets(stmobj, "Length"));
172
	chain = fz_open_null(chain, len);
173
 
174
	hascrypt = pdf_stream_has_crypt(stmobj);
175
	if (xref->crypt && !hascrypt)
176
		chain = pdf_open_crypt(chain, xref->crypt, num, gen);
177
 
178
	return chain;
179
}
180
 
181
/*
182
 * Construct a filter to decode a stream, constraining
183
 * to stream length and decrypting.
184
 */
185
static fz_stream *
186
pdf_open_filter(fz_stream *chain, pdf_xref *xref, fz_obj *stmobj, int num, int gen)
187
{
188
	fz_obj *filters;
189
	fz_obj *params;
190
 
191
	filters = fz_dict_getsa(stmobj, "Filter", "F");
192
	params = fz_dict_getsa(stmobj, "DecodeParms", "DP");
193
 
194
	chain = pdf_open_raw_filter(chain, xref, stmobj, num, gen);
195
 
196
	if (fz_is_name(filters))
197
		return build_filter(chain, xref, filters, params, num, gen);
198
	if (fz_array_len(filters) > 0)
199
		return build_filter_chain(chain, xref, filters, params, num, gen);
200
 
201
	return chain;
202
}
203
 
204
/*
205
 * Construct a filter to decode a stream, without
206
 * constraining to stream length, and without decryption.
207
 */
208
fz_stream *
209
pdf_open_inline_stream(fz_stream *chain, pdf_xref *xref, fz_obj *stmobj, int length)
210
{
211
	fz_obj *filters;
212
	fz_obj *params;
213
 
214
	filters = fz_dict_getsa(stmobj, "Filter", "F");
215
	params = fz_dict_getsa(stmobj, "DecodeParms", "DP");
216
 
217
	/* don't close chain when we close this filter */
218
	fz_keep_stream(chain);
219
 
220
	if (fz_is_name(filters))
221
		return build_filter(chain, xref, filters, params, 0, 0);
222
	if (fz_array_len(filters) > 0)
223
		return build_filter_chain(chain, xref, filters, params, 0, 0);
224
 
225
	return fz_open_null(chain, length);
226
}
227
 
228
/*
229
 * Open a stream for reading the raw (compressed but decrypted) data.
230
 * Using xref->file while this is open is a bad idea.
231
 */
232
fz_error
233
pdf_open_raw_stream(fz_stream **stmp, pdf_xref *xref, int num, int gen)
234
{
235
	pdf_xref_entry *x;
236
	fz_error error;
237
 
238
	if (num < 0 || num >= xref->len)
239
		return fz_throw("object id out of range (%d %d R)", num, gen);
240
 
241
	x = xref->table + num;
242
 
243
	error = pdf_cache_object(xref, num, gen);
244
	if (error)
245
		return fz_rethrow(error, "cannot load stream object (%d %d R)", num, gen);
246
 
247
	if (x->stm_ofs)
248
	{
249
		*stmp = pdf_open_raw_filter(xref->file, xref, x->obj, num, gen);
250
		fz_seek(xref->file, x->stm_ofs, 0);
251
		return fz_okay;
252
	}
253
 
254
	return fz_throw("object is not a stream");
255
}
256
 
257
/*
258
 * Open a stream for reading uncompressed data.
259
 * Put the opened file in xref->stream.
260
 * Using xref->file while a stream is open is a Bad idea.
261
 */
262
fz_error
263
pdf_open_stream(fz_stream **stmp, pdf_xref *xref, int num, int gen)
264
{
265
	pdf_xref_entry *x;
266
	fz_error error;
267
 
268
	if (num < 0 || num >= xref->len)
269
		return fz_throw("object id out of range (%d %d R)", num, gen);
270
 
271
	x = xref->table + num;
272
 
273
	error = pdf_cache_object(xref, num, gen);
274
	if (error)
275
		return fz_rethrow(error, "cannot load stream object (%d %d R)", num, gen);
276
 
277
	if (x->stm_ofs)
278
	{
279
		*stmp = pdf_open_filter(xref->file, xref, x->obj, num, gen);
280
		fz_seek(xref->file, x->stm_ofs, 0);
281
		return fz_okay;
282
	}
283
 
284
	return fz_throw("object is not a stream");
285
}
286
 
287
fz_error
288
pdf_open_stream_at(fz_stream **stmp, pdf_xref *xref, int num, int gen, fz_obj *dict, int stm_ofs)
289
{
290
	if (stm_ofs)
291
	{
292
		*stmp = pdf_open_filter(xref->file, xref, dict, num, gen);
293
		fz_seek(xref->file, stm_ofs, 0);
294
		return fz_okay;
295
	}
296
	return fz_throw("object is not a stream");
297
}
298
 
299
/*
300
 * Load raw (compressed but decrypted) contents of a stream into buf.
301
 */
302
fz_error
303
pdf_load_raw_stream(fz_buffer **bufp, pdf_xref *xref, int num, int gen)
304
{
305
	fz_error error;
306
	fz_stream *stm;
307
	fz_obj *dict;
308
	int len;
309
 
310
	error = pdf_load_object(&dict, xref, num, gen);
311
	if (error)
312
		return fz_rethrow(error, "cannot load stream dictionary (%d %d R)", num, gen);
313
 
314
	len = fz_to_int(fz_dict_gets(dict, "Length"));
315
 
316
	fz_drop_obj(dict);
317
 
318
	error = pdf_open_raw_stream(&stm, xref, num, gen);
319
	if (error)
320
		return fz_rethrow(error, "cannot open raw stream (%d %d R)", num, gen);
321
 
322
	error = fz_read_all(bufp, stm, len);
323
	if (error)
324
	{
325
		fz_close(stm);
326
		return fz_rethrow(error, "cannot read raw stream (%d %d R)", num, gen);
327
	}
328
 
329
	fz_close(stm);
330
	return fz_okay;
331
}
332
 
333
static int
334
pdf_guess_filter_length(int len, char *filter)
335
{
336
	if (!strcmp(filter, "ASCIIHexDecode"))
337
		return len / 2;
338
	if (!strcmp(filter, "ASCII85Decode"))
339
		return len * 4 / 5;
340
	if (!strcmp(filter, "FlateDecode"))
341
		return len * 3;
342
	if (!strcmp(filter, "RunLengthDecode"))
343
		return len * 3;
344
	if (!strcmp(filter, "LZWDecode"))
345
		return len * 2;
346
	return len;
347
}
348
 
349
/*
350
 * Load uncompressed contents of a stream into buf.
351
 */
352
fz_error
353
pdf_load_stream(fz_buffer **bufp, pdf_xref *xref, int num, int gen)
354
{
355
	fz_error error;
356
	fz_stream *stm;
357
	fz_obj *dict, *obj;
358
	int i, len;
359
 
360
	error = pdf_open_stream(&stm, xref, num, gen);
361
	if (error)
362
		return fz_rethrow(error, "cannot open stream (%d %d R)", num, gen);
363
 
364
	error = pdf_load_object(&dict, xref, num, gen);
365
	if (error)
366
		return fz_rethrow(error, "cannot load stream dictionary (%d %d R)", num, gen);
367
 
368
	len = fz_to_int(fz_dict_gets(dict, "Length"));
369
	obj = fz_dict_gets(dict, "Filter");
370
	len = pdf_guess_filter_length(len, fz_to_name(obj));
371
	for (i = 0; i < fz_array_len(obj); i++)
372
		len = pdf_guess_filter_length(len, fz_to_name(fz_array_get(obj, i)));
373
 
374
	fz_drop_obj(dict);
375
 
376
	error = fz_read_all(bufp, stm, len);
377
	if (error)
378
	{
379
		fz_close(stm);
380
		return fz_rethrow(error, "cannot read raw stream (%d %d R)", num, gen);
381
	}
382
 
383
	fz_close(stm);
384
	return fz_okay;
385
}