Coverage Report

Created: 2026-03-15 06:39

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