1 //========================================================================
5 // This file is licensed under the GPLv2 or later
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 //========================================================================
19 #include "Linearization.h"
25 #include "SecurityHandler.h"
29 //------------------------------------------------------------------------
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 ",
46 XRefEntry
*pageObjectFirstXRefEntry
= xref
->getEntry(pageObjectFirst
);
47 if (!pageObjectFirstXRefEntry
) {
48 error(errSyntaxWarning
, -1, "No XRef entry for first page object");
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
);
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");
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));
79 groupHasSignature
= NULL
;
80 groupNumObjects
= NULL
;
81 groupXRefOffset
= NULL
;
83 readTables(str
, linearization
, xref
, secHdlr
);
93 for (int i
=0; i
< nPages
; i
++) {
94 if (numSharedObject
[i
]) {
95 gfree(sharedObjectId
[i
]);
98 gfree(sharedObjectId
);
99 gfree(numSharedObject
);
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();
118 int bufLength
= hintsLength
+ hintsLength2
;
120 std::vector
<char> buf(bufLength
);
124 Stream
*s
= str
->makeSubStream(hintsOffset
, gFalse
, hintsLength
, &obj
);
126 for (Guint i
=0; i
< hintsLength
; i
++) { *p
++ = s
->getChar(); }
129 if (hintsOffset2
&& hintsLength2
) {
131 s
= str
->makeSubStream(hintsOffset2
, gFalse
, hintsLength2
, &obj
);
133 for (Guint i
=0; i
< hintsLength2
; i
++) { *p
++ = s
->getChar(); }
138 MemStream
*memStream
= new MemStream (&buf
[0], 0, bufLength
, &obj
);
141 parser
= new Parser(xref
, new Lexer(xref
, memStream
), gTrue
);
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
);
166 error(errSyntaxWarning
, -1, "Invalid shared object hint table offset");
169 error(errSyntaxWarning
, -1, "Failed parsing hints table object");
176 void Hints::readPageOffsetTable(Stream
*str
)
179 error(errSyntaxWarning
, -1, "Invalid number of pages reading page offset hints table");
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");
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
);
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;
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;
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
;
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");
296 if ((!nSharedGroupsFirst
) || (nSharedGroupsFirst
> nSharedGroups
)) {
297 error(errSyntaxWarning
, -1, "Invalid number of first page shared object groups");
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");
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
]) {
342 inputBits
= 0; // reset on byte boundary. Not in specs!
343 for (Guint i
=0; i
<nSharedGroups
; 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
];
370 return pageOffset
[0];
373 std::vector
<ByteRange
>* Hints::getPageRanges(int page
)
375 if ((page
< 1) || (page
> nPages
)) return NULL
;
378 if (page
-1 > pageFirst
)
380 else if (page
-1 < pageFirst
)
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
);
411 Guint
Hints::readBit(Stream
*str
)
416 if (inputBits
== 0) {
417 if ((c
= str
->getChar()) == EOF
) {
423 bit
= (bitsBuffer
>> (inputBits
- 1)) & 1;
428 Guint
Hints::readBits(int n
, Stream
*str
)
432 if (n
< 0) return -1;
433 if (n
== 0) return 0;
438 bit
= (readBit(str
) << (n
-1));
439 if (bit
== (Guint
) -1)
442 bits
= readBits(n
-1, str
);
443 if (bits
== (Guint
) -1)
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
];
457 return pageObjectNum
[0];