Diffstat (limited to 'noncore/unsupported/qpdf/xpdf/XRef.cc') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/unsupported/qpdf/xpdf/XRef.cc | 80 |
1 files changed, 52 insertions, 28 deletions
diff --git a/noncore/unsupported/qpdf/xpdf/XRef.cc b/noncore/unsupported/qpdf/xpdf/XRef.cc index 5d526e9..0e1bbc9 100644 --- a/noncore/unsupported/qpdf/xpdf/XRef.cc +++ b/noncore/unsupported/qpdf/xpdf/XRef.cc | |||
@@ -1,11 +1,11 @@ | |||
1 | //======================================================================== | 1 | //======================================================================== |
2 | // | 2 | // |
3 | // XRef.cc | 3 | // XRef.cc |
4 | // | 4 | // |
5 | // Copyright 1996 Derek B. Noonburg | 5 | // Copyright 1996-2002 Glyph & Cog, LLC |
6 | // | 6 | // |
7 | //======================================================================== | 7 | //======================================================================== |
8 | 8 | ||
9 | #ifdef __GNUC__ | 9 | #ifdef __GNUC__ |
10 | #pragma implementation | 10 | #pragma implementation |
11 | #endif | 11 | #endif |
@@ -22,12 +22,13 @@ | |||
22 | #include "Parser.h" | 22 | #include "Parser.h" |
23 | #include "Dict.h" | 23 | #include "Dict.h" |
24 | #ifndef NO_DECRYPTION | 24 | #ifndef NO_DECRYPTION |
25 | #include "Decrypt.h" | 25 | #include "Decrypt.h" |
26 | #endif | 26 | #endif |
27 | #include "Error.h" | 27 | #include "Error.h" |
28 | #include "ErrorCodes.h" | ||
28 | #include "XRef.h" | 29 | #include "XRef.h" |
29 | 30 | ||
30 | //------------------------------------------------------------------------ | 31 | //------------------------------------------------------------------------ |
31 | 32 | ||
32 | #define xrefSearchSize 1024// read this many bytes at end of file | 33 | #define xrefSearchSize 1024// read this many bytes at end of file |
33 | // to look for 'startxref' | 34 | // to look for 'startxref' |
@@ -46,16 +47,17 @@ | |||
46 | 47 | ||
47 | //------------------------------------------------------------------------ | 48 | //------------------------------------------------------------------------ |
48 | // XRef | 49 | // XRef |
49 | //------------------------------------------------------------------------ | 50 | //------------------------------------------------------------------------ |
50 | 51 | ||
51 | XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { | 52 | XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { |
52 | int pos; | 53 | Guint pos; |
53 | int i; | 54 | int i; |
54 | 55 | ||
55 | ok = gTrue; | 56 | ok = gTrue; |
57 | errCode = errNone; | ||
56 | size = 0; | 58 | size = 0; |
57 | entries = NULL; | 59 | entries = NULL; |
58 | streamEnds = NULL; | 60 | streamEnds = NULL; |
59 | streamEndsLen = 0; | 61 | streamEndsLen = 0; |
60 | 62 | ||
61 | // read the trailer | 63 | // read the trailer |
@@ -64,31 +66,33 @@ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { | |||
64 | pos = readTrailer(); | 66 | pos = readTrailer(); |
65 | 67 | ||
66 | // if there was a problem with the trailer, | 68 | // if there was a problem with the trailer, |
67 | // try to reconstruct the xref table | 69 | // try to reconstruct the xref table |
68 | if (pos == 0) { | 70 | if (pos == 0) { |
69 | if (!(ok = constructXRef())) { | 71 | if (!(ok = constructXRef())) { |
72 | errCode = errDamaged; | ||
70 | return; | 73 | return; |
71 | } | 74 | } |
72 | 75 | ||
73 | // trailer is ok - read the xref table | 76 | // trailer is ok - read the xref table |
74 | } else { | 77 | } else { |
75 | entries = (XRefEntry *)gmalloc(size * sizeof(XRefEntry)); | 78 | entries = (XRefEntry *)gmalloc(size * sizeof(XRefEntry)); |
76 | for (i = 0; i < size; ++i) { | 79 | for (i = 0; i < size; ++i) { |
77 | entries[i].offset = -1; | 80 | entries[i].offset = 0xffffffff; |
78 | entries[i].used = gFalse; | 81 | entries[i].used = gFalse; |
79 | } | 82 | } |
80 | while (readXRef(&pos)) ; | 83 | while (readXRef(&pos)) ; |
81 | 84 | ||
82 | // if there was a problem with the xref table, | 85 | // if there was a problem with the xref table, |
83 | // try to reconstruct it | 86 | // try to reconstruct it |
84 | if (!ok) { | 87 | if (!ok) { |
85 | gfree(entries); | 88 | gfree(entries); |
86 | size = 0; | 89 | size = 0; |
87 | entries = NULL; | 90 | entries = NULL; |
88 | if (!(ok = constructXRef())) { | 91 | if (!(ok = constructXRef())) { |
92 | errCode = errDamaged; | ||
89 | return; | 93 | return; |
90 | } | 94 | } |
91 | } | 95 | } |
92 | } | 96 | } |
93 | 97 | ||
94 | // now set the trailer dictionary's xref pointer so we can fetch | 98 | // now set the trailer dictionary's xref pointer so we can fetch |
@@ -98,12 +102,13 @@ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { | |||
98 | // check for encryption | 102 | // check for encryption |
99 | #ifndef NO_DECRYPTION | 103 | #ifndef NO_DECRYPTION |
100 | encrypted = gFalse; | 104 | encrypted = gFalse; |
101 | #endif | 105 | #endif |
102 | if (checkEncrypted(ownerPassword, userPassword)) { | 106 | if (checkEncrypted(ownerPassword, userPassword)) { |
103 | ok = gFalse; | 107 | ok = gFalse; |
108 | errCode = errEncrypted; | ||
104 | return; | 109 | return; |
105 | } | 110 | } |
106 | } | 111 | } |
107 | 112 | ||
108 | XRef::~XRef() { | 113 | XRef::~XRef() { |
109 | gfree(entries); | 114 | gfree(entries); |
@@ -112,23 +117,24 @@ XRef::~XRef() { | |||
112 | gfree(streamEnds); | 117 | gfree(streamEnds); |
113 | } | 118 | } |
114 | } | 119 | } |
115 | 120 | ||
116 | // Read startxref position, xref table size, and root. Returns | 121 | // Read startxref position, xref table size, and root. Returns |
117 | // first xref position. | 122 | // first xref position. |
118 | int XRef::readTrailer() { | 123 | Guint XRef::readTrailer() { |
119 | Parser *parser; | 124 | Parser *parser; |
120 | Object obj; | 125 | Object obj; |
121 | char buf[xrefSearchSize+1]; | 126 | char buf[xrefSearchSize+1]; |
122 | int n, pos, pos1; | 127 | int n; |
128 | Guint pos, pos1; | ||
123 | char *p; | 129 | char *p; |
124 | int c; | 130 | int c; |
125 | int i; | 131 | int i; |
126 | 132 | ||
127 | // read last xrefSearchSize bytes | 133 | // read last xrefSearchSize bytes |
128 | str->setPos(-xrefSearchSize); | 134 | str->setPos(xrefSearchSize, -1); |
129 | for (n = 0; n < xrefSearchSize; ++n) { | 135 | for (n = 0; n < xrefSearchSize; ++n) { |
130 | if ((c = str->getChar()) == EOF) | 136 | if ((c = str->getChar()) == EOF) |
131 | break; | 137 | break; |
132 | buf[n] = c; | 138 | buf[n] = c; |
133 | } | 139 | } |
134 | buf[n] = '\0'; | 140 | buf[n] = '\0'; |
@@ -138,13 +144,13 @@ int XRef::readTrailer() { | |||
138 | if (!strncmp(&buf[i], "startxref", 9)) | 144 | if (!strncmp(&buf[i], "startxref", 9)) |
139 | break; | 145 | break; |
140 | } | 146 | } |
141 | if (i < 0) | 147 | if (i < 0) |
142 | return 0; | 148 | return 0; |
143 | for (p = &buf[i+9]; isspace(*p); ++p) ; | 149 | for (p = &buf[i+9]; isspace(*p); ++p) ; |
144 | pos = lastXRefPos = atoi(p); | 150 | pos = lastXRefPos = strToUnsigned(p); |
145 | 151 | ||
146 | // find trailer dict by looking after first xref table | 152 | // find trailer dict by looking after first xref table |
147 | // (NB: we can't just use the trailer dict at the end of the file -- | 153 | // (NB: we can't just use the trailer dict at the end of the file -- |
148 | // this won't work for linearized files.) | 154 | // this won't work for linearized files.) |
149 | str->setPos(start + pos); | 155 | str->setPos(start + pos); |
150 | for (i = 0; i < 4; ++i) | 156 | for (i = 0; i < 4; ++i) |
@@ -173,14 +179,15 @@ int XRef::readTrailer() { | |||
173 | pos1 += (p - buf) + n * 20; | 179 | pos1 += (p - buf) + n * 20; |
174 | } | 180 | } |
175 | pos1 += 7; | 181 | pos1 += 7; |
176 | 182 | ||
177 | // read trailer dict | 183 | // read trailer dict |
178 | obj.initNull(); | 184 | obj.initNull(); |
179 | parser = new Parser(NULL, new Lexer(NULL, str->makeSubStream(start + pos1, | 185 | parser = new Parser(NULL, |
180 | -1, &obj))); | 186 | new Lexer(NULL, |
187 | str->makeSubStream(start + pos1, gFalse, 0, &obj))); | ||
181 | parser->getObj(&trailerDict); | 188 | parser->getObj(&trailerDict); |
182 | if (trailerDict.isDict()) { | 189 | if (trailerDict.isDict()) { |
183 | trailerDict.dictLookupNF("Size", &obj); | 190 | trailerDict.dictLookupNF("Size", &obj); |
184 | if (obj.isInt()) | 191 | if (obj.isInt()) |
185 | size = obj.getInt(); | 192 | size = obj.getInt(); |
186 | else | 193 | else |
@@ -201,13 +208,13 @@ int XRef::readTrailer() { | |||
201 | 208 | ||
202 | // return first xref position | 209 | // return first xref position |
203 | return pos; | 210 | return pos; |
204 | } | 211 | } |
205 | 212 | ||
206 | // Read an xref table and the prev pointer from the trailer. | 213 | // Read an xref table and the prev pointer from the trailer. |
207 | GBool XRef::readXRef(int *pos) { | 214 | GBool XRef::readXRef(Guint *pos) { |
208 | Parser *parser; | 215 | Parser *parser; |
209 | Object obj, obj2; | 216 | Object obj, obj2; |
210 | char s[20]; | 217 | char s[20]; |
211 | GBool more; | 218 | GBool more; |
212 | int first, newSize, n, i, j; | 219 | int first, newSize, n, i, j; |
213 | int c; | 220 | int c; |
@@ -258,27 +265,27 @@ GBool XRef::readXRef(int *pos) { | |||
258 | // check for buggy PDF files with an incorrect (too small) xref | 265 | // check for buggy PDF files with an incorrect (too small) xref |
259 | // table size | 266 | // table size |
260 | if (first + n > size) { | 267 | if (first + n > size) { |
261 | newSize = size + 256; | 268 | newSize = size + 256; |
262 | entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); | 269 | entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); |
263 | for (i = size; i < newSize; ++i) { | 270 | for (i = size; i < newSize; ++i) { |
264 | entries[i].offset = -1; | 271 | entries[i].offset = 0xffffffff; |
265 | entries[i].used = gFalse; | 272 | entries[i].used = gFalse; |
266 | } | 273 | } |
267 | size = newSize; | 274 | size = newSize; |
268 | } | 275 | } |
269 | for (i = first; i < first + n; ++i) { | 276 | for (i = first; i < first + n; ++i) { |
270 | for (j = 0; j < 20; ++j) { | 277 | for (j = 0; j < 20; ++j) { |
271 | if ((c = str->getChar()) == EOF) { | 278 | if ((c = str->getChar()) == EOF) { |
272 | goto err2; | 279 | goto err2; |
273 | } | 280 | } |
274 | s[j] = (char)c; | 281 | s[j] = (char)c; |
275 | } | 282 | } |
276 | if (entries[i].offset < 0) { | 283 | if (entries[i].offset == 0xffffffff) { |
277 | s[10] = '\0'; | 284 | s[10] = '\0'; |
278 | entries[i].offset = atoi(s); | 285 | entries[i].offset = strToUnsigned(s); |
279 | s[16] = '\0'; | 286 | s[16] = '\0'; |
280 | entries[i].gen = atoi(&s[11]); | 287 | entries[i].gen = atoi(&s[11]); |
281 | if (s[17] == 'n') { | 288 | if (s[17] == 'n') { |
282 | entries[i].used = gTrue; | 289 | entries[i].used = gTrue; |
283 | } else if (s[17] == 'f') { | 290 | } else if (s[17] == 'f') { |
284 | entries[i].used = gFalse; | 291 | entries[i].used = gFalse; |
@@ -290,34 +297,35 @@ GBool XRef::readXRef(int *pos) { | |||
290 | // instead of 0. | 297 | // instead of 0. |
291 | if (i == 1 && first == 1 && | 298 | if (i == 1 && first == 1 && |
292 | entries[1].offset == 0 && entries[1].gen == 65535 && | 299 | entries[1].offset == 0 && entries[1].gen == 65535 && |
293 | !entries[1].used) { | 300 | !entries[1].used) { |
294 | i = first = 0; | 301 | i = first = 0; |
295 | entries[0] = entries[1]; | 302 | entries[0] = entries[1]; |
296 | entries[1].offset = -1; | 303 | entries[1].offset = 0xffffffff; |
297 | } | 304 | } |
298 | } | 305 | } |
299 | } | 306 | } |
300 | } | 307 | } |
301 | 308 | ||
302 | // read prev pointer from trailer dictionary | 309 | // read prev pointer from trailer dictionary |
303 | obj.initNull(); | 310 | obj.initNull(); |
304 | parser = new Parser(NULL, new Lexer(NULL, str->makeSubStream(str->getPos(), | 311 | parser = new Parser(NULL, |
305 | -1, &obj))); | 312 | new Lexer(NULL, |
313 | str->makeSubStream(str->getPos(), gFalse, 0, &obj))); | ||
306 | parser->getObj(&obj); | 314 | parser->getObj(&obj); |
307 | if (!obj.isCmd("trailer")) { | 315 | if (!obj.isCmd("trailer")) { |
308 | goto err1; | 316 | goto err1; |
309 | } | 317 | } |
310 | obj.free(); | 318 | obj.free(); |
311 | parser->getObj(&obj); | 319 | parser->getObj(&obj); |
312 | if (!obj.isDict()) { | 320 | if (!obj.isDict()) { |
313 | goto err1; | 321 | goto err1; |
314 | } | 322 | } |
315 | obj.getDict()->lookupNF("Prev", &obj2); | 323 | obj.getDict()->lookupNF("Prev", &obj2); |
316 | if (obj2.isInt()) { | 324 | if (obj2.isInt()) { |
317 | *pos = obj2.getInt(); | 325 | *pos = (Guint)obj2.getInt(); |
318 | more = gTrue; | 326 | more = gTrue; |
319 | } else { | 327 | } else { |
320 | more = gFalse; | 328 | more = gFalse; |
321 | } | 329 | } |
322 | obj.free(); | 330 | obj.free(); |
323 | obj2.free(); | 331 | obj2.free(); |
@@ -334,13 +342,13 @@ GBool XRef::readXRef(int *pos) { | |||
334 | 342 | ||
335 | // Attempt to construct an xref table for a damaged file. | 343 | // Attempt to construct an xref table for a damaged file. |
336 | GBool XRef::constructXRef() { | 344 | GBool XRef::constructXRef() { |
337 | Parser *parser; | 345 | Parser *parser; |
338 | Object obj; | 346 | Object obj; |
339 | char buf[256]; | 347 | char buf[256]; |
340 | int pos; | 348 | Guint pos; |
341 | int num, gen; | 349 | int num, gen; |
342 | int newSize; | 350 | int newSize; |
343 | int streamEndsSize; | 351 | int streamEndsSize; |
344 | char *p; | 352 | char *p; |
345 | int i; | 353 | int i; |
346 | GBool gotRoot; | 354 | GBool gotRoot; |
@@ -357,14 +365,15 @@ GBool XRef::constructXRef() { | |||
357 | } | 365 | } |
358 | p = buf; | 366 | p = buf; |
359 | 367 | ||
360 | // got trailer dictionary | 368 | // got trailer dictionary |
361 | if (!strncmp(p, "trailer", 7)) { | 369 | if (!strncmp(p, "trailer", 7)) { |
362 | obj.initNull(); | 370 | obj.initNull(); |
363 | parser = new Parser(NULL, new Lexer(NULL, | 371 | parser = new Parser(NULL, |
364 | str->makeSubStream(start + pos + 7, -1, &obj))); | 372 | new Lexer(NULL, |
373 | str->makeSubStream(start + pos + 7, gFalse, 0, &obj))); | ||
365 | if (!trailerDict.isNone()) | 374 | if (!trailerDict.isNone()) |
366 | trailerDict.free(); | 375 | trailerDict.free(); |
367 | parser->getObj(&trailerDict); | 376 | parser->getObj(&trailerDict); |
368 | if (trailerDict.isDict()) { | 377 | if (trailerDict.isDict()) { |
369 | trailerDict.dictLookupNF("Root", &obj); | 378 | trailerDict.dictLookupNF("Root", &obj); |
370 | if (obj.isRef()) { | 379 | if (obj.isRef()) { |
@@ -400,13 +409,13 @@ GBool XRef::constructXRef() { | |||
400 | if (!strncmp(p, "obj", 3)) { | 409 | if (!strncmp(p, "obj", 3)) { |
401 | if (num >= size) { | 410 | if (num >= size) { |
402 | newSize = (num + 1 + 255) & ~255; | 411 | newSize = (num + 1 + 255) & ~255; |
403 | entries = (XRefEntry *) | 412 | entries = (XRefEntry *) |
404 | grealloc(entries, newSize * sizeof(XRefEntry)); | 413 | grealloc(entries, newSize * sizeof(XRefEntry)); |
405 | for (i = size; i < newSize; ++i) { | 414 | for (i = size; i < newSize; ++i) { |
406 | entries[i].offset = -1; | 415 | entries[i].offset = 0xffffffff; |
407 | entries[i].used = gFalse; | 416 | entries[i].used = gFalse; |
408 | } | 417 | } |
409 | size = newSize; | 418 | size = newSize; |
410 | } | 419 | } |
411 | if (!entries[num].used || gen >= entries[num].gen) { | 420 | if (!entries[num].used || gen >= entries[num].gen) { |
412 | entries[num].offset = pos - start; | 421 | entries[num].offset = pos - start; |
@@ -418,13 +427,14 @@ GBool XRef::constructXRef() { | |||
418 | } | 427 | } |
419 | } | 428 | } |
420 | 429 | ||
421 | } else if (!strncmp(p, "endstream", 9)) { | 430 | } else if (!strncmp(p, "endstream", 9)) { |
422 | if (streamEndsLen == streamEndsSize) { | 431 | if (streamEndsLen == streamEndsSize) { |
423 | streamEndsSize += 64; | 432 | streamEndsSize += 64; |
424 | streamEnds = (int *)grealloc(streamEnds, streamEndsSize * sizeof(int)); | 433 | streamEnds = (Guint *)grealloc(streamEnds, |
434 | streamEndsSize * sizeof(int)); | ||
425 | } | 435 | } |
426 | streamEnds[streamEndsLen++] = pos; | 436 | streamEnds[streamEndsLen++] = pos; |
427 | } | 437 | } |
428 | } | 438 | } |
429 | 439 | ||
430 | if (gotRoot) | 440 | if (gotRoot) |
@@ -577,16 +587,17 @@ Object *XRef::fetch(int num, int gen, Object *obj) { | |||
577 | if (num < 0 || num >= size) { | 587 | if (num < 0 || num >= size) { |
578 | obj->initNull(); | 588 | obj->initNull(); |
579 | return obj; | 589 | return obj; |
580 | } | 590 | } |
581 | 591 | ||
582 | e = &entries[num]; | 592 | e = &entries[num]; |
583 | if (e->gen == gen && e->offset >= 0) { | 593 | if (e->gen == gen && e->offset != 0xffffffff) { |
584 | obj1.initNull(); | 594 | obj1.initNull(); |
585 | parser = new Parser(this, new Lexer(this, | 595 | parser = new Parser(this, |
586 | str->makeSubStream(start + e->offset, -1, &obj1))); | 596 | new Lexer(this, |
597 | str->makeSubStream(start + e->offset, gFalse, 0, &obj1))); | ||
587 | parser->getObj(&obj1); | 598 | parser->getObj(&obj1); |
588 | parser->getObj(&obj2); | 599 | parser->getObj(&obj2); |
589 | parser->getObj(&obj3); | 600 | parser->getObj(&obj3); |
590 | if (obj1.isInt() && obj1.getInt() == num && | 601 | if (obj1.isInt() && obj1.getInt() == num && |
591 | obj2.isInt() && obj2.getInt() == gen && | 602 | obj2.isInt() && obj2.getInt() == gen && |
592 | obj3.isCmd("obj")) { | 603 | obj3.isCmd("obj")) { |
@@ -615,18 +626,18 @@ Object *XRef::getDocInfo(Object *obj) { | |||
615 | 626 | ||
616 | // Added for the pdftex project. | 627 | // Added for the pdftex project. |
617 | Object *XRef::getDocInfoNF(Object *obj) { | 628 | Object *XRef::getDocInfoNF(Object *obj) { |
618 | return trailerDict.dictLookupNF("Info", obj); | 629 | return trailerDict.dictLookupNF("Info", obj); |
619 | } | 630 | } |
620 | 631 | ||
621 | int XRef::getStreamEnd(int streamStart) { | 632 | GBool XRef::getStreamEnd(Guint streamStart, Guint *streamEnd) { |
622 | int a, b, m; | 633 | int a, b, m; |
623 | 634 | ||
624 | if (streamEndsLen == 0 || | 635 | if (streamEndsLen == 0 || |
625 | streamStart > streamEnds[streamEndsLen - 1]) { | 636 | streamStart > streamEnds[streamEndsLen - 1]) { |
626 | return -1; | 637 | return gFalse; |
627 | } | 638 | } |
628 | 639 | ||
629 | a = -1; | 640 | a = -1; |
630 | b = streamEndsLen - 1; | 641 | b = streamEndsLen - 1; |
631 | // invariant: streamEnds[a] < streamStart <= streamEnds[b] | 642 | // invariant: streamEnds[a] < streamStart <= streamEnds[b] |
632 | while (b - a > 1) { | 643 | while (b - a > 1) { |
@@ -634,8 +645,21 @@ int XRef::getStreamEnd(int streamStart) { | |||
634 | if (streamStart <= streamEnds[m]) { | 645 | if (streamStart <= streamEnds[m]) { |
635 | b = m; | 646 | b = m; |
636 | } else { | 647 | } else { |
637 | a = m; | 648 | a = m; |
638 | } | 649 | } |
639 | } | 650 | } |
640 | return streamEnds[b]; | 651 | *streamEnd = streamEnds[b]; |
652 | return gTrue; | ||
653 | } | ||
654 | |||
655 | Guint XRef::strToUnsigned(char *s) { | ||
656 | Guint x; | ||
657 | char *p; | ||
658 | int i; | ||
659 | |||
660 | x = 0; | ||
661 | for (p = s, i = 0; *p && isdigit(*p) && i < 10; ++p, ++i) { | ||
662 | x = 10 * x + (*p - '0'); | ||
663 | } | ||
664 | return x; | ||
641 | } | 665 | } |