SmartPDF - lightweight pdf viewer app for rosapps
[reactos.git] / rosapps / smartpdf / fitz / mupdf / pdf_doctor.c
1 #include <fitz.h>
2 #include <mupdf.h>
3
4 /*
5 * Sweep and mark reachable objects
6 */
7
8 static fz_error *sweepref(pdf_xref *xref, fz_obj *ref);
9
10 static fz_error *
11 sweepobj(pdf_xref *xref, fz_obj *obj)
12 {
13 fz_error *error;
14 int i;
15
16 if (fz_isdict(obj))
17 {
18 for (i = 0; i < fz_dictlen(obj); i++)
19 {
20 error = sweepobj(xref, fz_dictgetval(obj, i));
21 if (error)
22 return error;
23 }
24 }
25
26 if (fz_isarray(obj))
27 {
28 for (i = 0; i < fz_arraylen(obj); i++)
29 {
30 error = sweepobj(xref, fz_arrayget(obj, i));
31 if (error)
32 return error;
33 }
34 }
35
36 if (fz_isindirect(obj))
37 return sweepref(xref, obj);
38
39 return nil;
40 }
41
42 static fz_error *
43 sweepref(pdf_xref *xref, fz_obj *ref)
44 {
45 fz_error *error;
46 fz_obj *obj;
47 int oid;
48
49 oid = fz_tonum(ref);
50
51 if (oid < 0 || oid >= xref->len)
52 return fz_throw("rangecheck: object number out of range");
53
54 if (xref->table[oid].mark)
55 return nil;
56
57 xref->table[oid].mark = 1;
58
59 error = pdf_loadindirect(&obj, xref, ref);
60 if (error)
61 return error;
62
63 error = sweepobj(xref, obj);
64 fz_dropobj(obj);
65 return error;
66 }
67
68 /*
69 * Garbage collect objects not reachable from
70 * the trailer dictionary
71 */
72
73 fz_error *
74 pdf_garbagecollect(pdf_xref *xref)
75 {
76 fz_error *error;
77 int i, g;
78
79 pdf_logxref("garbage collect {\n");
80
81 for (i = 0; i < xref->len; i++)
82 xref->table[i].mark = 0;
83
84 error = sweepobj(xref, xref->trailer);
85 if (error)
86 return error;
87
88 for (i = 0; i < xref->len; i++)
89 {
90 pdf_xrefentry *x = xref->table + i;
91 g = x->gen;
92 if (x->type == 'o')
93 g = 0;
94 if (!x->mark && x->type != 'f' && x->type != 'd')
95 pdf_deleteobject(xref, i, g);
96 }
97
98 pdf_logxref("}\n");
99
100 return nil;
101 }
102
103 /*
104 * Transplant (copy) objects and streams from one file to another
105 */
106
107 struct pair
108 {
109 int soid, sgen;
110 int doid, dgen;
111 };
112
113 static fz_error *
114 remaprefs(fz_obj **newp, fz_obj *old, struct pair *map, int n)
115 {
116 fz_error *error;
117 int i, o, g;
118 fz_obj *tmp, *key;
119
120 if (fz_isindirect(old))
121 {
122 o = fz_tonum(old);
123 g = fz_togen(old);
124 for (i = 0; i < n; i++)
125 if (map[i].soid == o && map[i].sgen == g)
126 return fz_newindirect(newp, map[i].doid, map[i].dgen);
127 }
128
129 else if (fz_isarray(old))
130 {
131 error = fz_newarray(newp, fz_arraylen(old));
132 if (error)
133 return error;
134 for (i = 0; i < fz_arraylen(old); i++)
135 {
136 tmp = fz_arrayget(old, i);
137 error = remaprefs(&tmp, tmp, map, n);
138 if (error)
139 goto cleanup;
140 error = fz_arraypush(*newp, tmp);
141 fz_dropobj(tmp);
142 if (error)
143 goto cleanup;
144 }
145 }
146
147 else if (fz_isdict(old))
148 {
149 error = fz_newdict(newp, fz_dictlen(old));
150 if (error)
151 return error;
152 for (i = 0; i < fz_dictlen(old); i++)
153 {
154 key = fz_dictgetkey(old, i);
155 tmp = fz_dictgetval(old, i);
156 error = remaprefs(&tmp, tmp, map, n);
157 if (error)
158 goto cleanup;
159 error = fz_dictput(*newp, key, tmp);
160 fz_dropobj(tmp);
161 if (error)
162 goto cleanup;
163 }
164 }
165
166 else
167 {
168 *newp = fz_keepobj(old);
169 }
170
171 return nil;
172
173 cleanup:
174 fz_dropobj(*newp);
175 return error;
176 }
177
178 /*
179 * Recursively copy objects from src to dst xref.
180 * Start with root object in src xref.
181 * Put the dst copy of root into newp.
182 */
183 fz_error *
184 pdf_transplant(pdf_xref *dst, pdf_xref *src, fz_obj **newp, fz_obj *root)
185 {
186 fz_error *error;
187 struct pair *map;
188 fz_obj *old, *new;
189 fz_buffer *stm;
190 int i, n;
191
192 pdf_logxref("transplant {\n");
193
194 for (i = 0; i < src->len; i++)
195 src->table[i].mark = 0;
196
197 error = sweepobj(src, root);
198 if (error)
199 return error;
200
201 for (n = 0, i = 0; i < src->len; i++)
202 if (src->table[i].mark)
203 n++;
204
205 pdf_logxref("marked %d\n", n);
206
207 map = fz_malloc(sizeof(struct pair) * n);
208 if (!map)
209 return fz_outofmem;
210
211 for (n = 0, i = 0; i < src->len; i++)
212 {
213 if (src->table[i].mark)
214 {
215 map[n].soid = i;
216 map[n].sgen = src->table[i].gen;
217 if (src->table[i].type == 'o')
218 map[n].sgen = 0;
219 error = pdf_allocobject(dst, &map[n].doid, &map[n].dgen);
220 if (error)
221 goto cleanup;
222 n++;
223 }
224 }
225
226 error = remaprefs(newp, root, map, n);
227 if (error)
228 goto cleanup;
229
230 for (i = 0; i < n; i++)
231 {
232 pdf_logxref("copyfrom %d %d to %d %d\n",
233 map[i].soid, map[i].sgen,
234 map[i].doid, map[i].dgen);
235
236 error = pdf_loadobject(&old, src, map[i].soid, map[i].sgen);
237 if (error)
238 goto cleanup;
239
240 if (pdf_isstream(src, map[i].soid, map[i].sgen))
241 {
242 error = pdf_loadrawstream(&stm, src, map[i].soid, map[i].sgen);
243 if (error)
244 goto cleanup;
245 pdf_updatestream(dst, map[i].doid, map[i].dgen, stm);
246 fz_dropbuffer(stm);
247 }
248
249 error = remaprefs(&new, old, map, n);
250 fz_dropobj(old);
251 if (error)
252 goto cleanup;
253
254 pdf_updateobject(dst, map[i].doid, map[i].dgen, new);
255 fz_dropobj(new);
256 }
257
258 pdf_logxref("}\n");
259
260 fz_free(map);
261 return nil;
262
263 cleanup:
264 fz_free(map);
265 return error;
266 }
267