SmartPDF - lightweight pdf viewer app for rosapps
[reactos.git] / rosapps / smartpdf / fitz / mupdf / pdf_save.c
1 #include <fitz.h>
2 #include <mupdf.h>
3
4 #define TIGHT 1
5
6 static fz_error *
7 writestream(fz_stream *out, pdf_xref *xref, pdf_crypt *encrypt, int oid, int gen)
8 {
9 fz_error *error;
10 fz_stream *dststm;
11 fz_stream *srcstm;
12 unsigned char buf[4096];
13 fz_filter *ef;
14 int n;
15
16 fz_print(out, "stream\n");
17
18 if (encrypt)
19 {
20 error = pdf_cryptstream(&ef, encrypt, oid, gen);
21 if (error)
22 return error;
23
24 error = fz_openrfilter(&dststm, ef, out);
25 fz_dropfilter(ef);
26 if (error)
27 return error;
28 }
29 else
30 {
31 dststm = fz_keepstream(out);
32 }
33
34 error = pdf_openrawstream(&srcstm, xref, oid, gen);
35 if (error)
36 goto cleanupdst;
37
38 while (1)
39 {
40 n = fz_read(srcstm, buf, sizeof buf);
41 if (n == 0)
42 break;
43 if (n < 0)
44 {
45 error = fz_ioerror(srcstm);
46 goto cleanupsrc;
47 }
48
49 n = fz_write(dststm, buf, n);
50 if (n < 0)
51 {
52 error = fz_ioerror(dststm);
53 goto cleanupsrc;
54 }
55 }
56
57 fz_dropstream(srcstm);
58 fz_dropstream(dststm);
59
60 fz_print(out, "endstream\n");
61
62 return nil;
63
64 cleanupsrc:
65 fz_dropstream(srcstm);
66 cleanupdst:
67 fz_dropstream(dststm);
68 return error;
69 }
70
71 static fz_error *
72 writeobject(fz_stream *out, pdf_xref *xref, pdf_crypt *encrypt, int oid, int gen)
73 {
74 pdf_xrefentry *x = xref->table + oid;
75 fz_error *error;
76
77 error = pdf_cacheobject(xref, oid, gen);
78 if (error)
79 return error;
80
81 if (encrypt)
82 pdf_cryptobj(encrypt, x->obj, oid, gen);
83
84 fz_print(out, "%d %d obj\n", oid, gen);
85 fz_printobj(out, x->obj, TIGHT);
86 fz_print(out, "\n");
87
88 if (encrypt)
89 pdf_cryptobj(encrypt, x->obj, oid, gen);
90
91 if (pdf_isstream(xref, oid, gen))
92 {
93 error = writestream(out, xref, encrypt, oid, gen);
94 if (error)
95 return error;
96 }
97
98 fz_print(out, "endobj\n\n");
99
100 return nil;
101 }
102
103 static int countmodified(pdf_xref *xref, int oid)
104 {
105 int i;
106 for (i = oid; i < xref->len; i++)
107 if (xref->table[i].type != 'a' && xref->table[i].type != 'd')
108 return i - oid;
109 return i - oid;
110 }
111
112 fz_error *
113 pdf_updatexref(pdf_xref *xref, char *path)
114 {
115 fz_error *error;
116 fz_stream *out;
117 int oid;
118 int i, n;
119 int startxref;
120 fz_obj *obj;
121
122 pdf_logxref("updatexref '%s' %p\n", path, xref);
123
124 error = fz_openafile(&out, path);
125 if (error)
126 return error;
127
128 fz_print(out, "\n");
129
130 for (oid = 0; oid < xref->len; oid++)
131 {
132 if (xref->table[oid].type == 'a')
133 {
134 xref->table[oid].ofs = fz_tell(out);
135 error = writeobject(out, xref, xref->crypt, oid, xref->table[oid].gen);
136 if (error)
137 goto cleanup;
138 }
139 }
140
141 /* always write out entry 0 in appended xref sections */
142 xref->table[0].type = 'd';
143
144 startxref = fz_tell(out);
145 fz_print(out, "xref\n");
146
147 oid = 0;
148 while (oid < xref->len)
149 {
150 n = countmodified(xref, oid);
151
152 pdf_logxref(" section %d +%d\n", oid, n);
153
154 fz_print(out, "%d %d\n", oid, n);
155
156 for (i = 0; i < n; i++)
157 {
158 if (xref->table[oid + i].type == 'd')
159 xref->table[oid + i].type = 'f';
160 if (xref->table[oid + i].type == 'a')
161 xref->table[oid + i].type = 'n';
162
163 fz_print(out, "%010d %05d %c \n",
164 xref->table[oid + i].ofs,
165 xref->table[oid + i].gen,
166 xref->table[oid + i].type);
167 }
168
169 oid += n;
170 while (oid < xref->len &&
171 xref->table[oid].type != 'a' &&
172 xref->table[oid].type != 'd')
173 oid ++;
174 }
175
176 fz_print(out, "\n");
177
178 fz_print(out, "trailer\n<<\n /Size %d\n /Prev %d", xref->len, xref->startxref);
179
180 obj = fz_dictgets(xref->trailer, "Root");
181 fz_print(out,"\n /Root %d %d R", fz_tonum(obj), fz_togen(obj));
182
183 obj = fz_dictgets(xref->trailer, "Info");
184 if (obj)
185 fz_print(out,"\n /Info %d %d R", fz_tonum(obj), fz_togen(obj));
186
187 obj = fz_dictgets(xref->trailer, "Encrypt");
188 if (obj) {
189 fz_print(out,"\n /Encrypt ");
190 fz_printobj(out, obj, TIGHT);
191 }
192
193 obj = fz_dictgets(xref->trailer, "ID");
194 if (obj) {
195 fz_print(out,"\n /ID ");
196 fz_printobj(out, obj, TIGHT);
197 }
198
199 fz_print(out, "\n>>\n\n");
200
201 fz_print(out, "startxref\n");
202 fz_print(out, "%d\n", startxref);
203 fz_print(out, "%%%%EOF\n");
204
205 xref->startxref = startxref;
206
207 fz_dropstream(out);
208 return nil;
209
210 cleanup:
211 fz_dropstream(out);
212 return error;
213 }
214
215 fz_error *
216 pdf_savexref(pdf_xref *xref, char *path, pdf_crypt *encrypt)
217 {
218 fz_error *error;
219 fz_stream *out;
220 int oid;
221 int startxref;
222 int *ofsbuf;
223 fz_obj *obj;
224 int eoid, egen;
225
226 pdf_logxref("savexref '%s' %p\n", path, xref);
227
228 /* need to add encryption object for acrobat < 6 */
229 if (encrypt)
230 {
231 pdf_logxref("make encryption dict\n");
232
233 error = pdf_allocobject(xref, &eoid, &egen);
234 if (error)
235 return error;
236
237 pdf_cryptobj(encrypt, encrypt->encrypt, eoid, egen);
238
239 error = pdf_updateobject(xref, eoid, egen, encrypt->encrypt);
240 if (error)
241 return error;
242 }
243
244 ofsbuf = fz_malloc(sizeof(int) * xref->len);
245 if (!ofsbuf)
246 return fz_outofmem;
247
248 error = fz_openwfile(&out, path);
249 if (error)
250 {
251 fz_free(ofsbuf);
252 return error;
253 }
254
255 fz_print(out, "%%PDF-%1.1f\n", xref->version);
256 fz_print(out, "%%\342\343\317\323\n\n");
257
258 for (oid = 0; oid < xref->len; oid++)
259 {
260 pdf_xrefentry *x = xref->table + oid;
261 if (x->type == 'n' || x->type == 'o' || x->type == 'a')
262 {
263 ofsbuf[oid] = fz_tell(out);
264 error = writeobject(out, xref, encrypt, oid, x->type == 'o' ? 0 : x->gen);
265 if (error)
266 goto cleanup;
267 }
268 else
269 {
270 ofsbuf[oid] = x->ofs;
271 }
272 }
273
274 startxref = fz_tell(out);
275 fz_print(out, "xref\n");
276 fz_print(out, "0 %d\n", xref->len);
277
278 for (oid = 0; oid < xref->len; oid++)
279 {
280 int gen = xref->table[oid].gen;
281 int type = xref->table[oid].type;
282 if (type == 'o')
283 gen = 0;
284 if (type == 'a' || type == 'o')
285 type = 'n';
286 if (type == 'd')
287 type = 'f';
288 fz_print(out, "%010d %05d %c \n", ofsbuf[oid], gen, type);
289 }
290
291 fz_print(out, "\n");
292
293 fz_print(out, "trailer\n<<\n /Size %d", xref->len);
294 obj = fz_dictgets(xref->trailer, "Root");
295 fz_print(out, "\n /Root %d %d R", fz_tonum(obj), fz_togen(obj));
296 obj = fz_dictgets(xref->trailer, "Info");
297 if (obj)
298 fz_print(out, "\n /Info %d %d R", fz_tonum(obj), fz_togen(obj));
299 if (encrypt)
300 {
301 fz_print(out, "\n /Encrypt %d %d R", eoid, egen);
302 fz_print(out, "\n /ID [");
303 fz_printobj(out, encrypt->id, 1);
304 fz_printobj(out, encrypt->id, 1);
305 fz_print(out, "]");
306
307 pdf_cryptobj(encrypt, encrypt->encrypt, eoid, egen);
308 }
309 fz_print(out, "\n>>\n\n");
310
311 fz_print(out, "startxref\n");
312 fz_print(out, "%d\n", startxref);
313 fz_print(out, "%%%%EOF\n");
314
315 xref->startxref = startxref;
316
317 if(ofsbuf) fz_free(ofsbuf);
318 fz_dropstream(out);
319 return nil;
320
321 cleanup:
322 if(ofsbuf) fz_free(ofsbuf);
323 fz_dropstream(out);
324 return error;
325 }
326