a patch for ttc fonts with bad index
[luatex.git] / source / libs / poppler / poppler-0.36.0 / poppler / Hints.cc
blobbdd0d32261250a81e4bf639eacdd3984f4cfbd82
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 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 pageOffsetFirst = xref->getEntry(pageObjectFirst)->offset;
48 if (nPages >= INT_MAX / (int)sizeof(Guint)) {
49 error(errSyntaxWarning, -1, "Invalid number of pages ({0:d}) for hints table", nPages);
50 nPages = 0;
52 nObjects = (Guint *) gmallocn_checkoverflow(nPages, sizeof(Guint));
53 pageObjectNum = (int *) gmallocn_checkoverflow(nPages, sizeof(int));
54 xRefOffset = (Guint *) gmallocn_checkoverflow(nPages, sizeof(Guint));
55 pageLength = (Guint *) gmallocn_checkoverflow(nPages, sizeof(Guint));
56 pageOffset = (Goffset *) gmallocn_checkoverflow(nPages, sizeof(Goffset));
57 numSharedObject = (Guint *) gmallocn_checkoverflow(nPages, sizeof(Guint));
58 sharedObjectId = (Guint **) gmallocn_checkoverflow(nPages, sizeof(Guint*));
59 if (!nObjects || !pageObjectNum || !xRefOffset || !pageLength || !pageOffset ||
60 !numSharedObject || !sharedObjectId) {
61 error(errSyntaxWarning, -1, "Failed to allocate memory for hints table");
62 nPages = 0;
65 memset(pageLength, 0, nPages * sizeof(Guint));
66 memset(pageOffset, 0, nPages * sizeof(Guint));
67 memset(numSharedObject, 0, nPages * sizeof(Guint));
68 memset(pageObjectNum, 0, nPages * sizeof(int));
70 nSharedGroups = 0;
71 groupLength = NULL;
72 groupOffset = NULL;
73 groupHasSignature = NULL;
74 groupNumObjects = NULL;
75 groupXRefOffset = NULL;
77 readTables(str, linearization, xref, secHdlr);
80 Hints::~Hints()
82 gfree(nObjects);
83 gfree(pageObjectNum);
84 gfree(xRefOffset);
85 gfree(pageLength);
86 gfree(pageOffset);
87 for (int i=0; i< nPages; i++) {
88 if (numSharedObject[i]) {
89 gfree(sharedObjectId[i]);
92 gfree(sharedObjectId);
93 gfree(numSharedObject);
95 gfree(groupLength);
96 gfree(groupOffset);
97 gfree(groupHasSignature);
98 gfree(groupNumObjects);
99 gfree(groupXRefOffset);
102 void Hints::readTables(BaseStream *str, Linearization *linearization, XRef *xref, SecurityHandler *secHdlr)
104 hintsOffset = linearization->getHintsOffset();
105 hintsLength = linearization->getHintsLength();
106 hintsOffset2 = linearization->getHintsOffset2();
107 hintsLength2 = linearization->getHintsLength2();
109 Parser *parser;
110 Object obj;
112 int bufLength = hintsLength + hintsLength2;
114 std::vector<char> buf(bufLength);
115 char *p = &buf[0];
117 obj.initNull();
118 Stream *s = str->makeSubStream(hintsOffset, gFalse, hintsLength, &obj);
119 s->reset();
120 for (Guint i=0; i < hintsLength; i++) { *p++ = s->getChar(); }
121 delete s;
123 if (hintsOffset2 && hintsLength2) {
124 obj.initNull();
125 s = str->makeSubStream(hintsOffset2, gFalse, hintsLength2, &obj);
126 s->reset();
127 for (Guint i=0; i < hintsLength2; i++) { *p++ = s->getChar(); }
128 delete s;
131 obj.initNull();
132 MemStream *memStream = new MemStream (&buf[0], 0, bufLength, &obj);
134 obj.initNull();
135 parser = new Parser(xref, new Lexer(xref, memStream), gTrue);
137 int num, gen;
138 if (parser->getObj(&obj)->isInt() &&
139 (num = obj.getInt(), obj.free(), parser->getObj(&obj)->isInt()) &&
140 (gen = obj.getInt(), obj.free(), parser->getObj(&obj)->isCmd("obj")) &&
141 (obj.free(), parser->getObj(&obj, gFalse,
142 secHdlr ? secHdlr->getFileKey() : (Guchar *)NULL,
143 secHdlr ? secHdlr->getEncAlgorithm() : cryptRC4,
144 secHdlr ? secHdlr->getFileKeyLength() : 0,
145 num, gen, 0, gTrue)->isStream())) {
146 Stream *hintsStream = obj.getStream();
147 Dict *hintsDict = obj.streamGetDict();
149 int sharedStreamOffset = 0;
150 if (hintsDict->lookupInt("S", NULL, &sharedStreamOffset) &&
151 sharedStreamOffset > 0) {
153 hintsStream->reset();
154 readPageOffsetTable(hintsStream);
156 hintsStream->reset();
157 for (int i=0; i<sharedStreamOffset; i++) hintsStream->getChar();
158 readSharedObjectsTable(hintsStream);
159 } else {
160 error(errSyntaxWarning, -1, "Invalid shared object hint table offset");
162 } else {
163 error(errSyntaxWarning, -1, "Failed parsing hints table object");
165 obj.free();
167 delete parser;
170 void Hints::readPageOffsetTable(Stream *str)
172 if (nPages < 1) {
173 error(errSyntaxWarning, -1, "Invalid number of pages reading page offset hints table");
174 return;
177 inputBits = 0; // reset on byte boundary.
179 nObjectLeast = readBits(32, str);
180 if (nObjectLeast < 1) {
181 error(errSyntaxWarning, -1, "Invalid least number of objects reading page offset hints table");
182 nPages = 0;
183 return;
186 objectOffsetFirst = readBits(32, str);
187 if (objectOffsetFirst >= hintsOffset) objectOffsetFirst += hintsLength;
189 nBitsDiffObjects = readBits(16, str);
191 pageLengthLeast = readBits(32, str);
193 nBitsDiffPageLength = readBits(16, str);
195 OffsetStreamLeast = readBits(32, str);
197 nBitsOffsetStream = readBits(16, str);
199 lengthStreamLeast = readBits(32, str);
201 nBitsLengthStream = readBits(16, str);
203 nBitsNumShared = readBits(16, str);
205 nBitsShared = readBits(16, str);
207 nBitsNumerator = readBits(16, str);
209 denominator = readBits(16, str);
211 for (int i=0; i<nPages; i++) {
212 nObjects[i] = nObjectLeast + readBits(nBitsDiffObjects, str);
215 nObjects[0] = 0;
216 xRefOffset[0] = mainXRefEntriesOffset + 20;
217 for (int i=1; i<nPages; i++) {
218 xRefOffset[i] = xRefOffset[i-1] + 20*nObjects[i-1];
221 pageObjectNum[0] = 1;
222 for (int i=1; i<nPages; i++) {
223 pageObjectNum[i] = pageObjectNum[i-1] + nObjects[i-1];
225 pageObjectNum[0] = pageObjectFirst;
227 inputBits = 0; // reset on byte boundary. Not in specs!
228 for (int i=0; i<nPages; i++) {
229 pageLength[i] = pageLengthLeast + readBits(nBitsDiffPageLength, str);
232 inputBits = 0; // reset on byte boundary. Not in specs!
233 numSharedObject[0] = readBits(nBitsNumShared, str);
234 numSharedObject[0] = 0; // Do not trust the read value to be 0.
235 sharedObjectId[0] = NULL;
236 for (int i=1; i<nPages; i++) {
237 numSharedObject[i] = readBits(nBitsNumShared, str);
238 if (numSharedObject[i] >= INT_MAX / (int)sizeof(Guint)) {
239 error(errSyntaxWarning, -1, "Invalid number of shared objects");
240 numSharedObject[i] = 0;
241 return;
243 sharedObjectId[i] = (Guint *) gmallocn_checkoverflow(numSharedObject[i], sizeof(Guint));
244 if (numSharedObject[i] && !sharedObjectId[i]) {
245 error(errSyntaxWarning, -1, "Failed to allocate memory for shared object IDs");
246 numSharedObject[i] = 0;
247 return;
251 inputBits = 0; // reset on byte boundary. Not in specs!
252 for (int i=1; i<nPages; i++) {
253 for (Guint j=0; j < numSharedObject[i]; j++) {
254 sharedObjectId[i][j] = readBits(nBitsShared, str);
258 pageOffset[0] = pageOffsetFirst;
259 // find pageOffsets.
260 for (int i=1; i<nPages; i++) {
261 pageOffset[i] = pageOffset[i-1] + pageLength[i-1];
266 void Hints::readSharedObjectsTable(Stream *str)
268 inputBits = 0; // reset on byte boundary.
270 Guint firstSharedObjectNumber = readBits(32, str);
272 Guint firstSharedObjectOffset = readBits(32, str);
273 firstSharedObjectOffset += hintsLength;
275 Guint nSharedGroupsFirst = readBits(32, str);
277 Guint nSharedGroups = readBits(32, str);
279 Guint nBitsNumObjects = readBits(16, str);
281 Guint groupLengthLeast = readBits(32, str);
283 Guint nBitsDiffGroupLength = readBits(16, str);
285 if ((!nSharedGroups) || (nSharedGroups >= INT_MAX / (int)sizeof(Guint))) {
286 error(errSyntaxWarning, -1, "Invalid number of shared object groups");
287 nSharedGroups = 0;
288 return;
290 if ((!nSharedGroupsFirst) || (nSharedGroupsFirst > nSharedGroups)) {
291 error(errSyntaxWarning, -1, "Invalid number of first page shared object groups");
292 nSharedGroups = 0;
293 return;
296 groupLength = (Guint *) gmallocn_checkoverflow(nSharedGroups, sizeof(Guint));
297 groupOffset = (Guint *) gmallocn_checkoverflow(nSharedGroups, sizeof(Guint));
298 groupHasSignature = (Guint *) gmallocn_checkoverflow(nSharedGroups, sizeof(Guint));
299 groupNumObjects = (Guint *) gmallocn_checkoverflow(nSharedGroups, sizeof(Guint));
300 groupXRefOffset = (Guint *) gmallocn_checkoverflow(nSharedGroups, sizeof(Guint));
301 if (!groupLength || !groupOffset || !groupHasSignature ||
302 !groupNumObjects || !groupXRefOffset) {
303 error(errSyntaxWarning, -1, "Failed to allocate memory for shared object groups");
304 nSharedGroups = 0;
305 return;
308 inputBits = 0; // reset on byte boundary. Not in specs!
309 for (Guint i=0; i<nSharedGroups; i++) {
310 groupLength[i] = groupLengthLeast + readBits(nBitsDiffGroupLength, str);
313 groupOffset[0] = objectOffsetFirst;
314 for (Guint i=1; i<nSharedGroupsFirst; i++) {
315 groupOffset[i] = groupOffset[i-1] + groupLength[i-1];
317 if (nSharedGroups > nSharedGroupsFirst ) {
318 groupOffset[nSharedGroupsFirst] = firstSharedObjectOffset;
319 for (Guint i=nSharedGroupsFirst+1; i<nSharedGroups; i++) {
320 groupOffset[i] = groupOffset[i-1] + groupLength[i-1];
324 inputBits = 0; // reset on byte boundary. Not in specs!
325 for (Guint i=0; i<nSharedGroups; i++) {
326 groupHasSignature[i] = readBits(1, str);
329 inputBits = 0; // reset on byte boundary. Not in specs!
330 for (Guint i=0; i<nSharedGroups; i++) {
331 if (groupHasSignature[i]) {
332 readBits(128, str);
336 inputBits = 0; // reset on byte boundary. Not in specs!
337 for (Guint i=0; i<nSharedGroups; i++) {
338 groupNumObjects[i] =
339 nBitsNumObjects ? 1 + readBits(nBitsNumObjects, str) : 1;
342 for (Guint i=0; i<nSharedGroupsFirst; i++) {
343 groupNumObjects[i] = 0;
344 groupXRefOffset[i] = 0;
346 if (nSharedGroups > nSharedGroupsFirst ) {
347 groupXRefOffset[nSharedGroupsFirst] =
348 mainXRefEntriesOffset + 20*firstSharedObjectNumber;
349 for (Guint i=nSharedGroupsFirst+1; i<nSharedGroups; i++) {
350 groupXRefOffset[i] = groupXRefOffset[i-1] + 20*groupNumObjects[i-1];
355 Goffset Hints::getPageOffset(int page)
357 if ((page < 1) || (page > nPages)) return 0;
359 if (page-1 > pageFirst)
360 return pageOffset[page-1];
361 else if (page-1 < pageFirst)
362 return pageOffset[page];
363 else
364 return pageOffset[0];
367 std::vector<ByteRange>* Hints::getPageRanges(int page)
369 if ((page < 1) || (page > nPages)) return NULL;
371 int idx;
372 if (page-1 > pageFirst)
373 idx = page-1;
374 else if (page-1 < pageFirst)
375 idx = page;
376 else
377 idx = 0;
379 ByteRange pageRange;
380 std::vector<ByteRange> *v = new std::vector<ByteRange>;
382 pageRange.offset = pageOffset[idx];
383 pageRange.length = pageLength[idx];
384 v->push_back(pageRange);
386 pageRange.offset = xRefOffset[idx];
387 pageRange.length = 20*nObjects[idx];
388 v->push_back(pageRange);
390 for (Guint j=0; j<numSharedObject[idx]; j++) {
391 Guint k = sharedObjectId[idx][j];
393 pageRange.offset = groupOffset[k];
394 pageRange.length = groupLength[k];
395 v->push_back(pageRange);
397 pageRange.offset = groupXRefOffset[k];
398 pageRange.length = 20*groupNumObjects[k];
399 v->push_back(pageRange);
402 return v;
405 Guint Hints::readBit(Stream *str)
407 Guint bit;
408 int c;
410 if (inputBits == 0) {
411 if ((c = str->getChar()) == EOF) {
412 return (Guint) -1;
414 bitsBuffer = c;
415 inputBits = 8;
417 bit = (bitsBuffer >> (inputBits - 1)) & 1;
418 --inputBits;
419 return bit;
422 Guint Hints::readBits(int n, Stream *str)
424 Guint bit, bits;
426 if (n < 0) return -1;
427 if (n == 0) return 0;
429 if (n == 1)
430 return readBit(str);
432 bit = (readBit(str) << (n-1));
433 if (bit == (Guint) -1)
434 return -1;
436 bits = readBits(n-1, str);
437 if (bits == (Guint) -1)
438 return -1;
440 return bit | bits;
443 int Hints::getPageObjectNum(int page) {
444 if ((page < 1) || (page > nPages)) return 0;
446 if (page-1 > pageFirst)
447 return pageObjectNum[page-1];
448 else if (page-1 < pageFirst)
449 return pageObjectNum[page];
450 else
451 return pageObjectNum[0];