/src/xpdf-4.04/xpdf/PDFDoc.cc
Line | Count | Source (jump to first uncovered line) |
1 | | //======================================================================== |
2 | | // |
3 | | // PDFDoc.cc |
4 | | // |
5 | | // Copyright 1996-2003 Glyph & Cog, LLC |
6 | | // |
7 | | //======================================================================== |
8 | | |
9 | | #include <aconf.h> |
10 | | |
11 | | #ifdef USE_GCC_PRAGMAS |
12 | | #pragma implementation |
13 | | #endif |
14 | | |
15 | | #include <stdio.h> |
16 | | #include <stdlib.h> |
17 | | #include <stddef.h> |
18 | | #include <string.h> |
19 | | #ifdef _WIN32 |
20 | | # include <windows.h> |
21 | | #endif |
22 | | #include "gmempp.h" |
23 | | #include "GString.h" |
24 | | #include "gfile.h" |
25 | | #include "config.h" |
26 | | #include "GlobalParams.h" |
27 | | #include "Page.h" |
28 | | #include "Catalog.h" |
29 | | #include "Stream.h" |
30 | | #include "XRef.h" |
31 | | #include "Link.h" |
32 | | #include "OutputDev.h" |
33 | | #include "Error.h" |
34 | | #include "ErrorCodes.h" |
35 | | #include "Lexer.h" |
36 | | #include "Parser.h" |
37 | | #include "SecurityHandler.h" |
38 | | #include "UTF8.h" |
39 | | #ifndef DISABLE_OUTLINE |
40 | | #include "Outline.h" |
41 | | #endif |
42 | | #include "OptionalContent.h" |
43 | | #include "PDFDoc.h" |
44 | | |
45 | | //------------------------------------------------------------------------ |
46 | | |
47 | 31.5k | #define headerSearchSize 1024 // read this many bytes at beginning of |
48 | | // file to look for '%PDF' |
49 | | |
50 | | // Avoid sharing files with child processes on Windows, where sharing |
51 | | // can cause problems. |
52 | | #ifdef _WIN32 |
53 | | # define fopenReadMode "rbN" |
54 | | # define wfopenReadMode L"rbN" |
55 | | #else |
56 | 0 | # define fopenReadMode "rb" |
57 | | #endif |
58 | | |
59 | | //------------------------------------------------------------------------ |
60 | | // PDFDoc |
61 | | //------------------------------------------------------------------------ |
62 | | |
63 | | PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, |
64 | 0 | GString *userPassword, PDFCore *coreA) { |
65 | 0 | Object obj; |
66 | 0 | GString *fileName1, *fileName2; |
67 | | #ifdef _WIN32 |
68 | | int n, i; |
69 | | #endif |
70 | |
|
71 | 0 | init(coreA); |
72 | |
|
73 | 0 | fileName = fileNameA; |
74 | | #ifdef _WIN32 |
75 | | n = fileName->getLength(); |
76 | | fileNameU = (wchar_t *)gmallocn(n + 1, sizeof(wchar_t)); |
77 | | for (i = 0; i < n; ++i) { |
78 | | fileNameU[i] = (wchar_t)(fileName->getChar(i) & 0xff); |
79 | | } |
80 | | fileNameU[n] = L'\0'; |
81 | | #endif |
82 | |
|
83 | 0 | fileName1 = fileName; |
84 | | |
85 | | // try to open file |
86 | 0 | fileName2 = NULL; |
87 | | #ifdef VMS |
88 | | if (!(file = fopen(fileName1->getCString(), fopenReadMode, "ctx=stm"))) { |
89 | | error(errIO, -1, "Couldn't open file '{0:t}'", fileName1); |
90 | | errCode = errOpenFile; |
91 | | return; |
92 | | } |
93 | | #else |
94 | 0 | if (!(file = fopen(fileName1->getCString(), fopenReadMode))) { |
95 | 0 | fileName2 = fileName->copy(); |
96 | 0 | fileName2->lowerCase(); |
97 | 0 | if (!(file = fopen(fileName2->getCString(), fopenReadMode))) { |
98 | 0 | fileName2->upperCase(); |
99 | 0 | if (!(file = fopen(fileName2->getCString(), fopenReadMode))) { |
100 | 0 | error(errIO, -1, "Couldn't open file '{0:t}'", fileName); |
101 | 0 | delete fileName2; |
102 | 0 | errCode = errOpenFile; |
103 | 0 | return; |
104 | 0 | } |
105 | 0 | } |
106 | 0 | delete fileName2; |
107 | 0 | } |
108 | 0 | #endif |
109 | | |
110 | | // create stream |
111 | 0 | obj.initNull(); |
112 | 0 | str = new FileStream(file, 0, gFalse, 0, &obj); |
113 | |
|
114 | 0 | ok = setup(ownerPassword, userPassword); |
115 | 0 | } |
116 | | |
117 | | #ifdef _WIN32 |
118 | | PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword, |
119 | | GString *userPassword, PDFCore *coreA) { |
120 | | OSVERSIONINFO version; |
121 | | Object obj; |
122 | | int i; |
123 | | |
124 | | init(coreA); |
125 | | |
126 | | // handle a Windows shortcut |
127 | | wchar_t wPath[winMaxLongPath + 1]; |
128 | | int n = fileNameLen < winMaxLongPath ? fileNameLen : winMaxLongPath; |
129 | | memcpy(wPath, fileNameA, n * sizeof(wchar_t)); |
130 | | wPath[n] = L'\0'; |
131 | | readWindowsShortcut(wPath, winMaxLongPath + 1); |
132 | | int wPathLen = (int)wcslen(wPath); |
133 | | |
134 | | // save both Unicode and 8-bit copies of the file name |
135 | | fileName = new GString(); |
136 | | fileNameU = (wchar_t *)gmallocn(wPathLen + 1, sizeof(wchar_t)); |
137 | | memcpy(fileNameU, wPath, (wPathLen + 1) * sizeof(wchar_t)); |
138 | | for (i = 0; i < wPathLen; ++i) { |
139 | | fileName->append((char)fileNameA[i]); |
140 | | } |
141 | | |
142 | | // try to open file |
143 | | // NB: _wfopen is only available in NT |
144 | | version.dwOSVersionInfoSize = sizeof(version); |
145 | | GetVersionEx(&version); |
146 | | if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { |
147 | | file = _wfopen(fileNameU, wfopenReadMode); |
148 | | } else { |
149 | | file = fopen(fileName->getCString(), fopenReadMode); |
150 | | } |
151 | | if (!file) { |
152 | | error(errIO, -1, "Couldn't open file '{0:t}'", fileName); |
153 | | errCode = errOpenFile; |
154 | | return; |
155 | | } |
156 | | |
157 | | // create stream |
158 | | obj.initNull(); |
159 | | str = new FileStream(file, 0, gFalse, 0, &obj); |
160 | | |
161 | | ok = setup(ownerPassword, userPassword); |
162 | | } |
163 | | #endif |
164 | | |
165 | | PDFDoc::PDFDoc(char *fileNameA, GString *ownerPassword, |
166 | 0 | GString *userPassword, PDFCore *coreA) { |
167 | | #ifdef _WIN32 |
168 | | OSVERSIONINFO version; |
169 | | #endif |
170 | 0 | Object obj; |
171 | | #ifdef _WIN32 |
172 | | Unicode u; |
173 | | int i, j; |
174 | | #endif |
175 | |
|
176 | 0 | init(coreA); |
177 | |
|
178 | 0 | fileName = new GString(fileNameA); |
179 | |
|
180 | | #if defined(_WIN32) |
181 | | wchar_t wPath[winMaxLongPath + 1]; |
182 | | i = 0; |
183 | | j = 0; |
184 | | while (j < winMaxLongPath && getUTF8(fileName, &i, &u)) { |
185 | | wPath[j++] = (wchar_t)u; |
186 | | } |
187 | | wPath[j] = L'\0'; |
188 | | readWindowsShortcut(wPath, winMaxLongPath + 1); |
189 | | int wPathLen = (int)wcslen(wPath); |
190 | | |
191 | | fileNameU = (wchar_t *)gmallocn(wPathLen + 1, sizeof(wchar_t)); |
192 | | memcpy(fileNameU, wPath, (wPathLen + 1) * sizeof(wchar_t)); |
193 | | |
194 | | // NB: _wfopen is only available in NT |
195 | | version.dwOSVersionInfoSize = sizeof(version); |
196 | | GetVersionEx(&version); |
197 | | if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { |
198 | | file = _wfopen(fileNameU, wfopenReadMode); |
199 | | } else { |
200 | | file = fopen(fileName->getCString(), fopenReadMode); |
201 | | } |
202 | | #elif defined(VMS) |
203 | | file = fopen(fileName->getCString(), fopenReadMode, "ctx=stm"); |
204 | | #else |
205 | 0 | file = fopen(fileName->getCString(), fopenReadMode); |
206 | 0 | #endif |
207 | |
|
208 | 0 | if (!file) { |
209 | 0 | error(errIO, -1, "Couldn't open file '{0:t}'", fileName); |
210 | 0 | errCode = errOpenFile; |
211 | 0 | return; |
212 | 0 | } |
213 | | |
214 | | // create stream |
215 | 0 | obj.initNull(); |
216 | 0 | str = new FileStream(file, 0, gFalse, 0, &obj); |
217 | |
|
218 | 0 | ok = setup(ownerPassword, userPassword); |
219 | 0 | } |
220 | | |
221 | | PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, |
222 | 36 | GString *userPassword, PDFCore *coreA) { |
223 | | #ifdef _WIN32 |
224 | | int n, i; |
225 | | #endif |
226 | | |
227 | 36 | init(coreA); |
228 | | |
229 | 36 | if (strA->getFileName()) { |
230 | 0 | fileName = strA->getFileName()->copy(); |
231 | | #ifdef _WIN32 |
232 | | n = fileName->getLength(); |
233 | | fileNameU = (wchar_t *)gmallocn(n + 1, sizeof(wchar_t)); |
234 | | for (i = 0; i < n; ++i) { |
235 | | fileNameU[i] = (wchar_t)(fileName->getChar(i) & 0xff); |
236 | | } |
237 | | fileNameU[n] = L'\0'; |
238 | | #endif |
239 | 36 | } else { |
240 | 36 | fileName = NULL; |
241 | | #ifdef _WIN32 |
242 | | fileNameU = NULL; |
243 | | #endif |
244 | 36 | } |
245 | 36 | str = strA; |
246 | 36 | ok = setup(ownerPassword, userPassword); |
247 | 36 | } |
248 | | |
249 | 36 | void PDFDoc::init(PDFCore *coreA) { |
250 | 36 | ok = gFalse; |
251 | 36 | errCode = errNone; |
252 | 36 | core = coreA; |
253 | 36 | file = NULL; |
254 | 36 | str = NULL; |
255 | 36 | xref = NULL; |
256 | 36 | catalog = NULL; |
257 | 36 | #ifndef DISABLE_OUTLINE |
258 | 36 | outline = NULL; |
259 | 36 | #endif |
260 | 36 | optContent = NULL; |
261 | 36 | } |
262 | | |
263 | 36 | GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { |
264 | | |
265 | 36 | str->reset(); |
266 | | |
267 | | // check header |
268 | 36 | checkHeader(); |
269 | | |
270 | | // read the xref and catalog |
271 | 36 | if (!PDFDoc::setup2(ownerPassword, userPassword, gFalse)) { |
272 | 36 | if (errCode == errDamaged || errCode == errBadCatalog) { |
273 | | // try repairing the xref table |
274 | 36 | error(errSyntaxWarning, -1, |
275 | 36 | "PDF file is damaged - attempting to reconstruct xref table..."); |
276 | 36 | if (!PDFDoc::setup2(ownerPassword, userPassword, gTrue)) { |
277 | 36 | return gFalse; |
278 | 36 | } |
279 | 36 | } else { |
280 | 0 | return gFalse; |
281 | 0 | } |
282 | 36 | } |
283 | | |
284 | 0 | #ifndef DISABLE_OUTLINE |
285 | | // read outline |
286 | 0 | outline = new Outline(catalog->getOutline(), xref); |
287 | 0 | #endif |
288 | | |
289 | | // read the optional content info |
290 | 0 | optContent = new OptionalContent(this); |
291 | | |
292 | | |
293 | | // done |
294 | 0 | return gTrue; |
295 | 36 | } |
296 | | |
297 | | GBool PDFDoc::setup2(GString *ownerPassword, GString *userPassword, |
298 | 72 | GBool repairXRef) { |
299 | | // read xref table |
300 | 72 | xref = new XRef(str, repairXRef); |
301 | 72 | if (!xref->isOk()) { |
302 | 69 | error(errSyntaxError, -1, "Couldn't read xref table"); |
303 | 69 | errCode = xref->getErrorCode(); |
304 | 69 | delete xref; |
305 | 69 | xref = NULL; |
306 | 69 | return gFalse; |
307 | 69 | } |
308 | | |
309 | | // check for encryption |
310 | 3 | if (!checkEncryption(ownerPassword, userPassword)) { |
311 | 0 | errCode = errEncrypted; |
312 | 0 | delete xref; |
313 | 0 | xref = NULL; |
314 | 0 | return gFalse; |
315 | 0 | } |
316 | | |
317 | | // read catalog |
318 | 3 | catalog = new Catalog(this); |
319 | 3 | if (!catalog->isOk()) { |
320 | 3 | error(errSyntaxError, -1, "Couldn't read page catalog"); |
321 | 3 | errCode = errBadCatalog; |
322 | 3 | delete catalog; |
323 | 3 | catalog = NULL; |
324 | 3 | delete xref; |
325 | 3 | xref = NULL; |
326 | 3 | return gFalse; |
327 | 3 | } |
328 | | |
329 | 0 | return gTrue; |
330 | 3 | } |
331 | | |
332 | 36 | PDFDoc::~PDFDoc() { |
333 | 36 | if (optContent) { |
334 | 0 | delete optContent; |
335 | 0 | } |
336 | 36 | #ifndef DISABLE_OUTLINE |
337 | 36 | if (outline) { |
338 | 0 | delete outline; |
339 | 0 | } |
340 | 36 | #endif |
341 | 36 | if (catalog) { |
342 | 0 | delete catalog; |
343 | 0 | } |
344 | 36 | if (xref) { |
345 | 0 | delete xref; |
346 | 0 | } |
347 | 36 | if (str) { |
348 | 36 | delete str; |
349 | 36 | } |
350 | 36 | if (file) { |
351 | 0 | fclose(file); |
352 | 0 | } |
353 | 36 | if (fileName) { |
354 | 0 | delete fileName; |
355 | 0 | } |
356 | | #ifdef _WIN32 |
357 | | if (fileNameU) { |
358 | | gfree(fileNameU); |
359 | | } |
360 | | #endif |
361 | 36 | } |
362 | | |
363 | | // Check for a PDF header on this stream. Skip past some garbage |
364 | | // if necessary. |
365 | 36 | void PDFDoc::checkHeader() { |
366 | 36 | char hdrBuf[headerSearchSize+1]; |
367 | 36 | char *p; |
368 | 36 | int i; |
369 | | |
370 | 36 | pdfVersion = 0; |
371 | 36 | memset(hdrBuf, 0, headerSearchSize + 1); |
372 | 36 | str->getBlock(hdrBuf, headerSearchSize); |
373 | 31.4k | for (i = 0; i < headerSearchSize - 5; ++i) { |
374 | 31.3k | if (!strncmp(&hdrBuf[i], "%PDF-", 5)) { |
375 | 6 | break; |
376 | 6 | } |
377 | 31.3k | } |
378 | 36 | if (i >= headerSearchSize - 5) { |
379 | 30 | error(errSyntaxWarning, -1, "May not be a PDF file (continuing anyway)"); |
380 | 30 | return; |
381 | 30 | } |
382 | 6 | str->moveStart(i); |
383 | 6 | if (!(p = strtok(&hdrBuf[i+5], " \t\n\r"))) { |
384 | 0 | error(errSyntaxWarning, -1, "May not be a PDF file (continuing anyway)"); |
385 | 0 | return; |
386 | 0 | } |
387 | 6 | pdfVersion = atof(p); |
388 | 6 | if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') || |
389 | 6 | pdfVersion > supportedPDFVersionNum + 0.0001) { |
390 | 0 | error(errSyntaxWarning, -1, |
391 | 0 | "PDF version {0:s} -- xpdf supports version {1:s} (continuing anyway)", |
392 | 0 | p, supportedPDFVersionStr); |
393 | 0 | } |
394 | 6 | } |
395 | | |
396 | 3 | GBool PDFDoc::checkEncryption(GString *ownerPassword, GString *userPassword) { |
397 | 3 | Object encrypt; |
398 | 3 | GBool encrypted; |
399 | 3 | SecurityHandler *secHdlr; |
400 | 3 | GBool ret; |
401 | | |
402 | 3 | xref->getTrailerDict()->dictLookup("Encrypt", &encrypt); |
403 | 3 | if ((encrypted = encrypt.isDict())) { |
404 | 0 | if ((secHdlr = SecurityHandler::make(this, &encrypt))) { |
405 | 0 | if (secHdlr->isUnencrypted()) { |
406 | | // no encryption |
407 | 0 | ret = gTrue; |
408 | 0 | } else if (secHdlr->checkEncryption(ownerPassword, userPassword)) { |
409 | | // authorization succeeded |
410 | 0 | xref->setEncryption(secHdlr->getPermissionFlags(), |
411 | 0 | secHdlr->getOwnerPasswordOk(), |
412 | 0 | secHdlr->getFileKey(), |
413 | 0 | secHdlr->getFileKeyLength(), |
414 | 0 | secHdlr->getEncVersion(), |
415 | 0 | secHdlr->getEncAlgorithm()); |
416 | 0 | ret = gTrue; |
417 | 0 | } else { |
418 | | // authorization failed |
419 | 0 | ret = gFalse; |
420 | 0 | } |
421 | 0 | delete secHdlr; |
422 | 0 | } else { |
423 | | // couldn't find the matching security handler |
424 | 0 | ret = gFalse; |
425 | 0 | } |
426 | 3 | } else { |
427 | | // document is not encrypted |
428 | 3 | ret = gTrue; |
429 | 3 | } |
430 | 3 | encrypt.free(); |
431 | 3 | return ret; |
432 | 3 | } |
433 | | |
434 | | void PDFDoc::displayPage(OutputDev *out, int page, |
435 | | double hDPI, double vDPI, int rotate, |
436 | | GBool useMediaBox, GBool crop, GBool printing, |
437 | | GBool (*abortCheckCbk)(void *data), |
438 | 0 | void *abortCheckCbkData) { |
439 | 0 | if (globalParams->getPrintCommands()) { |
440 | 0 | printf("***** page %d *****\n", page); |
441 | 0 | } |
442 | 0 | catalog->getPage(page)->display(out, hDPI, vDPI, |
443 | 0 | rotate, useMediaBox, crop, printing, |
444 | 0 | abortCheckCbk, abortCheckCbkData); |
445 | 0 | } |
446 | | |
447 | | void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, |
448 | | double hDPI, double vDPI, int rotate, |
449 | | GBool useMediaBox, GBool crop, GBool printing, |
450 | | GBool (*abortCheckCbk)(void *data), |
451 | 0 | void *abortCheckCbkData) { |
452 | 0 | int page; |
453 | |
|
454 | 0 | for (page = firstPage; page <= lastPage; ++page) { |
455 | 0 | if (globalParams->getPrintStatusInfo()) { |
456 | 0 | fflush(stderr); |
457 | 0 | printf("[processing page %d]\n", page); |
458 | 0 | fflush(stdout); |
459 | 0 | } |
460 | 0 | displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, printing, |
461 | 0 | abortCheckCbk, abortCheckCbkData); |
462 | 0 | catalog->doneWithPage(page); |
463 | 0 | } |
464 | 0 | } |
465 | | |
466 | | void PDFDoc::displayPageSlice(OutputDev *out, int page, |
467 | | double hDPI, double vDPI, int rotate, |
468 | | GBool useMediaBox, GBool crop, GBool printing, |
469 | | int sliceX, int sliceY, int sliceW, int sliceH, |
470 | | GBool (*abortCheckCbk)(void *data), |
471 | 0 | void *abortCheckCbkData) { |
472 | 0 | catalog->getPage(page)->displaySlice(out, hDPI, vDPI, |
473 | 0 | rotate, useMediaBox, crop, |
474 | 0 | sliceX, sliceY, sliceW, sliceH, |
475 | 0 | printing, |
476 | 0 | abortCheckCbk, abortCheckCbkData); |
477 | 0 | } |
478 | | |
479 | 0 | Links *PDFDoc::getLinks(int page) { |
480 | 0 | return catalog->getPage(page)->getLinks(); |
481 | 0 | } |
482 | | |
483 | 0 | void PDFDoc::processLinks(OutputDev *out, int page) { |
484 | 0 | catalog->getPage(page)->processLinks(out); |
485 | 0 | } |
486 | | |
487 | | #ifndef DISABLE_OUTLINE |
488 | 0 | int PDFDoc::getOutlineTargetPage(OutlineItem *outlineItem) { |
489 | 0 | LinkAction *action; |
490 | 0 | LinkActionKind kind; |
491 | 0 | LinkDest *dest; |
492 | 0 | GString *namedDest; |
493 | 0 | Ref pageRef; |
494 | 0 | int pg; |
495 | |
|
496 | 0 | if (outlineItem->pageNum >= 0) { |
497 | 0 | return outlineItem->pageNum; |
498 | 0 | } |
499 | 0 | if (!(action = outlineItem->getAction())) { |
500 | 0 | outlineItem->pageNum = 0; |
501 | 0 | return 0; |
502 | 0 | } |
503 | 0 | kind = action->getKind(); |
504 | 0 | if (kind != actionGoTo) { |
505 | 0 | outlineItem->pageNum = 0; |
506 | 0 | return 0; |
507 | 0 | } |
508 | 0 | if ((dest = ((LinkGoTo *)action)->getDest())) { |
509 | 0 | dest = dest->copy(); |
510 | 0 | } else if ((namedDest = ((LinkGoTo *)action)->getNamedDest())) { |
511 | 0 | dest = findDest(namedDest); |
512 | 0 | } |
513 | 0 | pg = 0; |
514 | 0 | if (dest) { |
515 | 0 | if (dest->isPageRef()) { |
516 | 0 | pageRef = dest->getPageRef(); |
517 | 0 | pg = findPage(pageRef.num, pageRef.gen); |
518 | 0 | } else { |
519 | 0 | pg = dest->getPageNum(); |
520 | 0 | } |
521 | 0 | delete dest; |
522 | 0 | } |
523 | 0 | outlineItem->pageNum = pg; |
524 | 0 | return pg; |
525 | 0 | } |
526 | | #endif |
527 | | |
528 | 0 | GBool PDFDoc::isLinearized() { |
529 | 0 | Parser *parser; |
530 | 0 | Object obj1, obj2, obj3, obj4, obj5; |
531 | 0 | GBool lin; |
532 | |
|
533 | 0 | lin = gFalse; |
534 | 0 | obj1.initNull(); |
535 | 0 | parser = new Parser(xref, |
536 | 0 | new Lexer(xref, |
537 | 0 | str->makeSubStream(str->getStart(), gFalse, 0, &obj1)), |
538 | 0 | gTrue); |
539 | 0 | parser->getObj(&obj1); |
540 | 0 | parser->getObj(&obj2); |
541 | 0 | parser->getObj(&obj3); |
542 | 0 | parser->getObj(&obj4); |
543 | 0 | if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && |
544 | 0 | obj4.isDict()) { |
545 | 0 | obj4.dictLookup("Linearized", &obj5); |
546 | 0 | if (obj5.isNum() && obj5.getNum() > 0) { |
547 | 0 | lin = gTrue; |
548 | 0 | } |
549 | 0 | obj5.free(); |
550 | 0 | } |
551 | 0 | obj4.free(); |
552 | 0 | obj3.free(); |
553 | 0 | obj2.free(); |
554 | 0 | obj1.free(); |
555 | 0 | delete parser; |
556 | 0 | return lin; |
557 | 0 | } |
558 | | |
559 | 0 | GBool PDFDoc::saveAs(GString *name) { |
560 | 0 | FILE *f; |
561 | 0 | char buf[4096]; |
562 | 0 | int n; |
563 | |
|
564 | 0 | if (!(f = fopen(name->getCString(), "wb"))) { |
565 | 0 | error(errIO, -1, "Couldn't open file '{0:t}'", name); |
566 | 0 | return gFalse; |
567 | 0 | } |
568 | 0 | str->reset(); |
569 | 0 | while ((n = str->getBlock(buf, sizeof(buf))) > 0) { |
570 | 0 | fwrite(buf, 1, n, f); |
571 | 0 | } |
572 | 0 | str->close(); |
573 | 0 | fclose(f); |
574 | 0 | return gTrue; |
575 | 0 | } |
576 | | |
577 | 0 | GBool PDFDoc::saveEmbeddedFile(int idx, const char *path) { |
578 | 0 | FILE *f; |
579 | 0 | GBool ret; |
580 | |
|
581 | 0 | if (!(f = fopen(path, "wb"))) { |
582 | 0 | return gFalse; |
583 | 0 | } |
584 | 0 | ret = saveEmbeddedFile2(idx, f); |
585 | 0 | fclose(f); |
586 | 0 | return ret; |
587 | 0 | } |
588 | | |
589 | 0 | GBool PDFDoc::saveEmbeddedFileU(int idx, const char *path) { |
590 | 0 | FILE *f; |
591 | 0 | GBool ret; |
592 | |
|
593 | 0 | if (!(f = openFile(path, "wb"))) { |
594 | 0 | return gFalse; |
595 | 0 | } |
596 | 0 | ret = saveEmbeddedFile2(idx, f); |
597 | 0 | fclose(f); |
598 | 0 | return ret; |
599 | 0 | } |
600 | | |
601 | | #ifdef _WIN32 |
602 | | GBool PDFDoc::saveEmbeddedFile(int idx, const wchar_t *path, int pathLen) { |
603 | | FILE *f; |
604 | | OSVERSIONINFO version; |
605 | | wchar_t path2w[winMaxLongPath + 1]; |
606 | | char path2c[MAX_PATH + 1]; |
607 | | int i; |
608 | | GBool ret; |
609 | | |
610 | | // NB: _wfopen is only available in NT |
611 | | version.dwOSVersionInfoSize = sizeof(version); |
612 | | GetVersionEx(&version); |
613 | | if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { |
614 | | for (i = 0; i < pathLen && i < winMaxLongPath; ++i) { |
615 | | path2w[i] = path[i]; |
616 | | } |
617 | | path2w[i] = 0; |
618 | | f = _wfopen(path2w, L"wb"); |
619 | | } else { |
620 | | for (i = 0; i < pathLen && i < MAX_PATH; ++i) { |
621 | | path2c[i] = (char)path[i]; |
622 | | } |
623 | | path2c[i] = 0; |
624 | | f = fopen(path2c, "wb"); |
625 | | } |
626 | | if (!f) { |
627 | | return gFalse; |
628 | | } |
629 | | ret = saveEmbeddedFile2(idx, f); |
630 | | fclose(f); |
631 | | return ret; |
632 | | } |
633 | | #endif |
634 | | |
635 | 0 | GBool PDFDoc::saveEmbeddedFile2(int idx, FILE *f) { |
636 | 0 | Object strObj; |
637 | 0 | char buf[4096]; |
638 | 0 | int n; |
639 | |
|
640 | 0 | if (!catalog->getEmbeddedFileStreamObj(idx, &strObj)) { |
641 | 0 | return gFalse; |
642 | 0 | } |
643 | 0 | strObj.streamReset(); |
644 | 0 | while ((n = strObj.streamGetBlock(buf, sizeof(buf))) > 0) { |
645 | 0 | fwrite(buf, 1, n, f); |
646 | 0 | } |
647 | 0 | strObj.streamClose(); |
648 | 0 | strObj.free(); |
649 | 0 | return gTrue; |
650 | 0 | } |
651 | | |
652 | 0 | char *PDFDoc::getEmbeddedFileMem(int idx, int *size) { |
653 | 0 | Object strObj; |
654 | 0 | char *buf; |
655 | 0 | int bufSize, sizeInc, n; |
656 | |
|
657 | 0 | if (!catalog->getEmbeddedFileStreamObj(idx, &strObj)) { |
658 | 0 | return NULL; |
659 | 0 | } |
660 | 0 | strObj.streamReset(); |
661 | 0 | bufSize = 0; |
662 | 0 | buf = NULL; |
663 | 0 | do { |
664 | 0 | sizeInc = bufSize ? bufSize : 1024; |
665 | 0 | if (bufSize > INT_MAX - sizeInc) { |
666 | 0 | error(errIO, -1, "embedded file is too large"); |
667 | 0 | *size = 0; |
668 | 0 | return NULL; |
669 | 0 | } |
670 | 0 | buf = (char *)grealloc(buf, bufSize + sizeInc); |
671 | 0 | n = strObj.streamGetBlock(buf + bufSize, sizeInc); |
672 | 0 | bufSize += n; |
673 | 0 | } while (n == sizeInc); |
674 | 0 | strObj.streamClose(); |
675 | 0 | strObj.free(); |
676 | 0 | *size = bufSize; |
677 | 0 | return buf; |
678 | 0 | } |
679 | | |