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 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 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
);
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");
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));
73 groupHasSignature
= NULL
;
74 groupNumObjects
= NULL
;
75 groupXRefOffset
= NULL
;
77 readTables(str
, linearization
, xref
, secHdlr
);
87 for (int i
=0; i
< nPages
; i
++) {
88 if (numSharedObject
[i
]) {
89 gfree(sharedObjectId
[i
]);
92 gfree(sharedObjectId
);
93 gfree(numSharedObject
);
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();
112 int bufLength
= hintsLength
+ hintsLength2
;
114 std::vector
<char> buf(bufLength
);
118 Stream
*s
= str
->makeSubStream(hintsOffset
, gFalse
, hintsLength
, &obj
);
120 for (Guint i
=0; i
< hintsLength
; i
++) { *p
++ = s
->getChar(); }
123 if (hintsOffset2
&& hintsLength2
) {
125 s
= str
->makeSubStream(hintsOffset2
, gFalse
, hintsLength2
, &obj
);
127 for (Guint i
=0; i
< hintsLength2
; i
++) { *p
++ = s
->getChar(); }
132 MemStream
*memStream
= new MemStream (&buf
[0], 0, bufLength
, &obj
);
135 parser
= new Parser(xref
, new Lexer(xref
, memStream
), gTrue
);
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
);
160 error(errSyntaxWarning
, -1, "Invalid shared object hint table offset");
163 error(errSyntaxWarning
, -1, "Failed parsing hints table object");
170 void Hints::readPageOffsetTable(Stream
*str
)
173 error(errSyntaxWarning
, -1, "Invalid number of pages reading page offset hints table");
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");
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
);
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;
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;
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
;
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");
290 if ((!nSharedGroupsFirst
) || (nSharedGroupsFirst
> nSharedGroups
)) {
291 error(errSyntaxWarning
, -1, "Invalid number of first page shared object groups");
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");
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
]) {
336 inputBits
= 0; // reset on byte boundary. Not in specs!
337 for (Guint i
=0; i
<nSharedGroups
; 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
];
364 return pageOffset
[0];
367 std::vector
<ByteRange
>* Hints::getPageRanges(int page
)
369 if ((page
< 1) || (page
> nPages
)) return NULL
;
372 if (page
-1 > pageFirst
)
374 else if (page
-1 < pageFirst
)
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
);
405 Guint
Hints::readBit(Stream
*str
)
410 if (inputBits
== 0) {
411 if ((c
= str
->getChar()) == EOF
) {
417 bit
= (bitsBuffer
>> (inputBits
- 1)) & 1;
422 Guint
Hints::readBits(int n
, Stream
*str
)
426 if (n
< 0) return -1;
427 if (n
== 0) return 0;
432 bit
= (readBit(str
) << (n
-1));
433 if (bit
== (Guint
) -1)
436 bits
= readBits(n
-1, str
);
437 if (bits
== (Guint
) -1)
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
];
451 return pageObjectNum
[0];