sync with experimental
[luatex.git] / source / libs / poppler / poppler-src / poppler / Hints.cc
blob6c2fc259a611390d0bc74da5c90051a62a24df6e
1 //========================================================================
2 //
3 // Hints.cc
4 //
5 // This file is licensed under the GPLv2 or later
6 //
7 // Copyright 2010, 2012 Hib Eris <hib@hiberis.nl>
8 // Copyright 2010, 2011, 2013, 2014, 2016 Albert Astals Cid <aacid@kde.org>
9 // Copyright 2010, 2013 Pino Toscano <pino@kde.org>
10 // Copyright 2013 Adrian Johnson <ajohnson@redneon.com>
11 // Copyright 2014 Fabio D'Urso <fabiodurso@hotmail.it>
13 //========================================================================
15 #include <config.h>
17 #include "Hints.h"
19 #include "Linearization.h"
20 #include "Object.h"
21 #include "Stream.h"
22 #include "XRef.h"
23 #include "Parser.h"
24 #include "Lexer.h"
25 #include "SecurityHandler.h"
27 #include <limits.h>
29 //------------------------------------------------------------------------
30 // Hints
31 //------------------------------------------------------------------------
33 Hints::Hints(BaseStream *str, Linearization *linearization, XRef *xref, SecurityHandler *secHdlr)
35 mainXRefEntriesOffset = linearization->getMainXRefEntriesOffset();
36 nPages = linearization->getNumPages();
37 pageFirst = linearization->getPageFirst();
38 pageEndFirst = linearization->getEndFirst();
39 pageObjectFirst = linearization->getObjectNumberFirst();
40 if (pageObjectFirst < 0 || pageObjectFirst >= xref->getNumObjects()) {
41 error(errSyntaxWarning, -1,
42 "Invalid reference for first page object ({0:d}) in linearization table ",
43 pageObjectFirst);
44 pageObjectFirst = 0;
46 XRefEntry *pageObjectFirstXRefEntry = xref->getEntry(pageObjectFirst);
47 if (!pageObjectFirstXRefEntry) {
48 error(errSyntaxWarning, -1, "No XRef entry for first page object");
49 pageOffsetFirst = 0;
50 } else {
51 pageOffsetFirst = pageObjectFirstXRefEntry->offset;
54 if (nPages >= INT_MAX / (int)sizeof(Guint)) {
55 error(errSyntaxWarning, -1, "Invalid number of pages ({0:d}) for hints table", nPages);
56 nPages = 0;
58 nObjects = (Guint *) gmallocn_checkoverflow(nPages, sizeof(Guint));
59 pageObjectNum = (int *) gmallocn_checkoverflow(nPages, sizeof(int));
60 xRefOffset = (Guint *) gmallocn_checkoverflow(nPages, sizeof(Guint));
61 pageLength = (Guint *) gmallocn_checkoverflow(nPages, sizeof(Guint));
62 pageOffset = (Goffset *) gmallocn_checkoverflow(nPages, sizeof(Goffset));
63 numSharedObject = (Guint *) gmallocn_checkoverflow(nPages, sizeof(Guint));
64 sharedObjectId = (Guint **) gmallocn_checkoverflow(nPages, sizeof(Guint*));
65 if (!nObjects || !pageObjectNum || !xRefOffset || !pageLength || !pageOffset ||
66 !numSharedObject || !sharedObjectId) {
67 error(errSyntaxWarning, -1, "Failed to allocate memory for hints table");
68 nPages = 0;
71 memset(pageLength, 0, nPages * sizeof(Guint));
72 memset(pageOffset, 0, nPages * sizeof(Guint));
73 memset(numSharedObject, 0, nPages * sizeof(Guint));
74 memset(pageObjectNum, 0, nPages * sizeof(int));
76 nSharedGroups = 0;
77 groupLength = NULL;
78 groupOffset = NULL;
79 groupHasSignature = NULL;
80 groupNumObjects = NULL;
81 groupXRefOffset = NULL;
83 readTables(str, linearization, xref, secHdlr);
86 Hints::~Hints()
88 gfree(nObjects);
89 gfree(pageObjectNum);
90 gfree(xRefOffset);
91 gfree(pageLength);
92 gfree(pageOffset);
93 for (int i=0; i< nPages; i++) {
94 if (numSharedObject[i]) {
95 gfree(sharedObjectId[i]);
98 gfree(sharedObjectId);
99 gfree(numSharedObject);
101 gfree(groupLength);
102 gfree(groupOffset);
103 gfree(groupHasSignature);
104 gfree(groupNumObjects);
105 gfree(groupXRefOffset);
108 void Hints::readTables(BaseStream *str, Linearization *linearization, XRef *xref, SecurityHandler *secHdlr)
110 hintsOffset = linearization->getHintsOffset();
111 hintsLength = linearization->getHintsLength();
112 hintsOffset2 = linearization->getHintsOffset2();
113 hintsLength2 = linearization->getHintsLength2();
115 Parser *parser;
116 Object obj;
118 int bufLength = hintsLength + hintsLength2;
120 std::vector<char> buf(bufLength);
121 char *p = &buf[0];
123 obj.initNull();
124 Stream *s = str->makeSubStream(hintsOffset, gFalse, hintsLength, &obj);
125 s->reset();
126 for (Guint i=0; i < hintsLength; i++) { *p++ = s->getChar(); }
127 delete s;
129 if (hintsOffset2 && hintsLength2) {
130 obj.initNull();
131 s = str->makeSubStream(hintsOffset2, gFalse, hintsLength2, &obj);
132 s->reset();
133 for (Guint i=0; i < hintsLength2; i++) { *p++ = s->getChar(); }
134 delete s;
137 obj.initNull();
138 MemStream *memStream = new MemStream (&buf[0], 0, bufLength, &obj);
140 obj.initNull();
141 parser = new Parser(xref, new Lexer(xref, memStream), gTrue);
143 int num, gen;
144 if (parser->getObj(&obj)->isInt() &&
145 (num = obj.getInt(), obj.free(), parser->getObj(&obj)->isInt()) &&
146 (gen = obj.getInt(), obj.free(), parser->getObj(&obj)->isCmd("obj")) &&
147 (obj.free(), parser->getObj(&obj, gFalse,
148 secHdlr ? secHdlr->getFileKey() : (Guchar *)NULL,
149 secHdlr ? secHdlr->getEncAlgorithm() : cryptRC4,
150 secHdlr ? secHdlr->getFileKeyLength() : 0,
151 num, gen, 0, gTrue)->isStream())) {
152 Stream *hintsStream = obj.getStream();
153 Dict *hintsDict = obj.streamGetDict();
155 int sharedStreamOffset = 0;
156 if (hintsDict->lookupInt("S", NULL, &sharedStreamOffset) &&
157 sharedStreamOffset > 0) {
159 hintsStream->reset();
160 readPageOffsetTable(hintsStream);
162 hintsStream->reset();
163 for (int i=0; i<sharedStreamOffset; i++) hintsStream->getChar();
164 readSharedObjectsTable(hintsStream);
165 } else {
166 error(errSyntaxWarning, -1, "Invalid shared object hint table offset");
168 } else {
169 error(errSyntaxWarning, -1, "Failed parsing hints table object");
171 obj.free();
173 delete parser;
176 void Hints::readPageOffsetTable(Stream *str)
178 if (nPages < 1) {
179 error(errSyntaxWarning, -1, "Invalid number of pages reading page offset hints table");
180 return;
183 inputBits = 0; // reset on byte boundary.
185 nObjectLeast = readBits(32, str);
186 if (nObjectLeast < 1) {
187 error(errSyntaxWarning, -1, "Invalid least number of objects reading page offset hints table");
188 nPages = 0;
189 return;
192 objectOffsetFirst = readBits(32, str);
193 if (objectOffsetFirst >= hintsOffset) objectOffsetFirst += hintsLength;
195 nBitsDiffObjects = readBits(16, str);
197 pageLengthLeast = readBits(32, str);
199 nBitsDiffPageLength = readBits(16, str);
201 OffsetStreamLeast = readBits(32, str);
203 nBitsOffsetStream = readBits(16, str);
205 lengthStreamLeast = readBits(32, str);
207 nBitsLengthStream = readBits(16, str);
209 nBitsNumShared = readBits(16, str);
211 nBitsShared = readBits(16, str);
213 nBitsNumerator = readBits(16, str);
215 denominator = readBits(16, str);
217 for (int i=0; i<nPages; i++) {
218 nObjects[i] = nObjectLeast + readBits(nBitsDiffObjects, str);
221 nObjects[0] = 0;
222 xRefOffset[0] = mainXRefEntriesOffset + 20;
223 for (int i=1; i<nPages; i++) {
224 xRefOffset[i] = xRefOffset[i-1] + 20*nObjects[i-1];
227 pageObjectNum[0] = 1;
228 for (int i=1; i<nPages; i++) {
229 pageObjectNum[i] = pageObjectNum[i-1] + nObjects[i-1];
231 pageObjectNum[0] = pageObjectFirst;
233 inputBits = 0; // reset on byte boundary. Not in specs!
234 for (int i=0; i<nPages; i++) {
235 pageLength[i] = pageLengthLeast + readBits(nBitsDiffPageLength, str);
238 inputBits = 0; // reset on byte boundary. Not in specs!
239 numSharedObject[0] = readBits(nBitsNumShared, str);
240 numSharedObject[0] = 0; // Do not trust the read value to be 0.
241 sharedObjectId[0] = NULL;
242 for (int i=1; i<nPages; i++) {
243 numSharedObject[i] = readBits(nBitsNumShared, str);
244 if (numSharedObject[i] >= INT_MAX / (int)sizeof(Guint)) {
245 error(errSyntaxWarning, -1, "Invalid number of shared objects");
246 numSharedObject[i] = 0;
247 return;
249 sharedObjectId[i] = (Guint *) gmallocn_checkoverflow(numSharedObject[i], sizeof(Guint));
250 if (numSharedObject[i] && !sharedObjectId[i]) {
251 error(errSyntaxWarning, -1, "Failed to allocate memory for shared object IDs");
252 numSharedObject[i] = 0;
253 return;
257 inputBits = 0; // reset on byte boundary. Not in specs!
258 for (int i=1; i<nPages; i++) {
259 for (Guint j=0; j < numSharedObject[i]; j++) {
260 sharedObjectId[i][j] = readBits(nBitsShared, str);
264 pageOffset[0] = pageOffsetFirst;
265 // find pageOffsets.
266 for (int i=1; i<nPages; i++) {
267 pageOffset[i] = pageOffset[i-1] + pageLength[i-1];
272 void Hints::readSharedObjectsTable(Stream *str)
274 inputBits = 0; // reset on byte boundary.
276 Guint firstSharedObjectNumber = readBits(32, str);
278 Guint firstSharedObjectOffset = readBits(32, str);
279 firstSharedObjectOffset += hintsLength;
281 Guint nSharedGroupsFirst = readBits(32, str);
283 Guint nSharedGroups = readBits(32, str);
285 Guint nBitsNumObjects = readBits(16, str);
287 Guint groupLengthLeast = readBits(32, str);
289 Guint nBitsDiffGroupLength = readBits(16, str);
291 if ((!nSharedGroups) || (nSharedGroups >= INT_MAX / (int)sizeof(Guint))) {
292 error(errSyntaxWarning, -1, "Invalid number of shared object groups");
293 nSharedGroups = 0;
294 return;
296 if ((!nSharedGroupsFirst) || (nSharedGroupsFirst > nSharedGroups)) {
297 error(errSyntaxWarning, -1, "Invalid number of first page shared object groups");
298 nSharedGroups = 0;
299 return;
302 groupLength = (Guint *) gmallocn_checkoverflow(nSharedGroups, sizeof(Guint));
303 groupOffset = (Guint *) gmallocn_checkoverflow(nSharedGroups, sizeof(Guint));
304 groupHasSignature = (Guint *) gmallocn_checkoverflow(nSharedGroups, sizeof(Guint));
305 groupNumObjects = (Guint *) gmallocn_checkoverflow(nSharedGroups, sizeof(Guint));
306 groupXRefOffset = (Guint *) gmallocn_checkoverflow(nSharedGroups, sizeof(Guint));
307 if (!groupLength || !groupOffset || !groupHasSignature ||
308 !groupNumObjects || !groupXRefOffset) {
309 error(errSyntaxWarning, -1, "Failed to allocate memory for shared object groups");
310 nSharedGroups = 0;
311 return;
314 inputBits = 0; // reset on byte boundary. Not in specs!
315 for (Guint i=0; i<nSharedGroups; i++) {
316 groupLength[i] = groupLengthLeast + readBits(nBitsDiffGroupLength, str);
319 groupOffset[0] = objectOffsetFirst;
320 for (Guint i=1; i<nSharedGroupsFirst; i++) {
321 groupOffset[i] = groupOffset[i-1] + groupLength[i-1];
323 if (nSharedGroups > nSharedGroupsFirst ) {
324 groupOffset[nSharedGroupsFirst] = firstSharedObjectOffset;
325 for (Guint i=nSharedGroupsFirst+1; i<nSharedGroups; i++) {
326 groupOffset[i] = groupOffset[i-1] + groupLength[i-1];
330 inputBits = 0; // reset on byte boundary. Not in specs!
331 for (Guint i=0; i<nSharedGroups; i++) {
332 groupHasSignature[i] = readBits(1, str);
335 inputBits = 0; // reset on byte boundary. Not in specs!
336 for (Guint i=0; i<nSharedGroups; i++) {
337 if (groupHasSignature[i]) {
338 readBits(128, str);
342 inputBits = 0; // reset on byte boundary. Not in specs!
343 for (Guint i=0; i<nSharedGroups; i++) {
344 groupNumObjects[i] =
345 nBitsNumObjects ? 1 + readBits(nBitsNumObjects, str) : 1;
348 for (Guint i=0; i<nSharedGroupsFirst; i++) {
349 groupNumObjects[i] = 0;
350 groupXRefOffset[i] = 0;
352 if (nSharedGroups > nSharedGroupsFirst ) {
353 groupXRefOffset[nSharedGroupsFirst] =
354 mainXRefEntriesOffset + 20*firstSharedObjectNumber;
355 for (Guint i=nSharedGroupsFirst+1; i<nSharedGroups; i++) {
356 groupXRefOffset[i] = groupXRefOffset[i-1] + 20*groupNumObjects[i-1];
361 Goffset Hints::getPageOffset(int page)
363 if ((page < 1) || (page > nPages)) return 0;
365 if (page-1 > pageFirst)
366 return pageOffset[page-1];
367 else if (page-1 < pageFirst)
368 return pageOffset[page];
369 else
370 return pageOffset[0];
373 std::vector<ByteRange>* Hints::getPageRanges(int page)
375 if ((page < 1) || (page > nPages)) return NULL;
377 int idx;
378 if (page-1 > pageFirst)
379 idx = page-1;
380 else if (page-1 < pageFirst)
381 idx = page;
382 else
383 idx = 0;
385 ByteRange pageRange;
386 std::vector<ByteRange> *v = new std::vector<ByteRange>;
388 pageRange.offset = pageOffset[idx];
389 pageRange.length = pageLength[idx];
390 v->push_back(pageRange);
392 pageRange.offset = xRefOffset[idx];
393 pageRange.length = 20*nObjects[idx];
394 v->push_back(pageRange);
396 for (Guint j=0; j<numSharedObject[idx]; j++) {
397 Guint k = sharedObjectId[idx][j];
399 pageRange.offset = groupOffset[k];
400 pageRange.length = groupLength[k];
401 v->push_back(pageRange);
403 pageRange.offset = groupXRefOffset[k];
404 pageRange.length = 20*groupNumObjects[k];
405 v->push_back(pageRange);
408 return v;
411 Guint Hints::readBit(Stream *str)
413 Guint bit;
414 int c;
416 if (inputBits == 0) {
417 if ((c = str->getChar()) == EOF) {
418 return (Guint) -1;
420 bitsBuffer = c;
421 inputBits = 8;
423 bit = (bitsBuffer >> (inputBits - 1)) & 1;
424 --inputBits;
425 return bit;
428 Guint Hints::readBits(int n, Stream *str)
430 Guint bit, bits;
432 if (n < 0) return -1;
433 if (n == 0) return 0;
435 if (n == 1)
436 return readBit(str);
438 bit = (readBit(str) << (n-1));
439 if (bit == (Guint) -1)
440 return -1;
442 bits = readBits(n-1, str);
443 if (bits == (Guint) -1)
444 return -1;
446 return bit | bits;
449 int Hints::getPageObjectNum(int page) {
450 if ((page < 1) || (page > nPages)) return 0;
452 if (page-1 > pageFirst)
453 return pageObjectNum[page-1];
454 else if (page-1 < pageFirst)
455 return pageObjectNum[page];
456 else
457 return pageObjectNum[0];