Coverage Report

Created: 2025-08-08 07:31

/src/xpdf-4.05/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
#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
1.50M
#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
2.58k
         GString *userPassword, PDFCore *coreA) {
220
#ifdef _WIN32
221
  int n, i;
222
#endif
223
224
2.58k
  init(coreA);
225
226
2.58k
  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
2.58k
  } else {
237
2.58k
    fileName = NULL;
238
#ifdef _WIN32
239
    fileNameU = NULL;
240
#endif
241
2.58k
  }
242
2.58k
  str = strA;
243
2.58k
  ok = setup(ownerPassword, userPassword);
244
2.58k
}
245
246
2.58k
void PDFDoc::init(PDFCore *coreA) {
247
2.58k
  ok = gFalse;
248
2.58k
  errCode = errNone;
249
2.58k
  core = coreA;
250
2.58k
  file = NULL;
251
2.58k
  str = NULL;
252
2.58k
  xref = NULL;
253
2.58k
  catalog = NULL;
254
2.58k
  annots = NULL;
255
2.58k
#ifndef DISABLE_OUTLINE
256
2.58k
  outline = NULL;
257
2.58k
#endif
258
2.58k
  optContent = NULL;
259
2.58k
}
260
261
2.58k
GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) {
262
263
2.58k
  str->reset();
264
265
  // check header
266
2.58k
  checkHeader();
267
268
  // read the xref and catalog
269
2.58k
  if (!PDFDoc::setup2(ownerPassword, userPassword, gFalse)) {
270
2.55k
    if (errCode == errDamaged || errCode == errBadCatalog) {
271
      // try repairing the xref table
272
2.55k
      error(errSyntaxWarning, -1,
273
2.55k
      "PDF file is damaged - attempting to reconstruct xref table...");
274
2.55k
      if (!PDFDoc::setup2(ownerPassword, userPassword, gTrue)) {
275
1.29k
  return gFalse;
276
1.29k
      }
277
2.55k
    } else {
278
0
      return gFalse;
279
0
    }
280
2.55k
  }
281
282
1.28k
#ifndef DISABLE_OUTLINE
283
  // read outline
284
1.28k
  outline = new Outline(catalog->getOutline(), xref);
285
1.28k
#endif
286
287
  // read the optional content info
288
1.28k
  optContent = new OptionalContent(this);
289
290
291
  // done
292
1.28k
  return gTrue;
293
2.58k
}
294
295
GBool PDFDoc::setup2(GString *ownerPassword, GString *userPassword,
296
5.14k
         GBool repairXRef) {
297
  // read xref table
298
5.14k
  xref = new XRef(str, repairXRef);
299
5.14k
  if (!xref->isOk()) {
300
3.64k
    error(errSyntaxError, -1, "Couldn't read xref table");
301
3.64k
    errCode = xref->getErrorCode();
302
3.64k
    delete xref;
303
3.64k
    xref = NULL;
304
3.64k
    return gFalse;
305
3.64k
  }
306
307
  // check for encryption
308
1.49k
  if (!checkEncryption(ownerPassword, userPassword)) {
309
15
    errCode = errEncrypted;
310
15
    delete xref;
311
15
    xref = NULL;
312
15
    return gFalse;
313
15
  }
314
315
  // read catalog
316
1.48k
  catalog = new Catalog(this);
317
1.48k
  if (!catalog->isOk()) {
318
192
    error(errSyntaxError, -1, "Couldn't read page catalog");
319
192
    errCode = errBadCatalog;
320
192
    delete catalog;
321
192
    catalog = NULL;
322
192
    delete xref;
323
192
    xref = NULL;
324
192
    return gFalse;
325
192
  }
326
327
  // initialize the Annots object
328
1.28k
  annots = new Annots(this);
329
330
1.28k
  return gTrue;
331
1.48k
}
332
333
2.57k
PDFDoc::~PDFDoc() {
334
2.57k
  if (optContent) {
335
1.27k
    delete optContent;
336
1.27k
  }
337
2.57k
#ifndef DISABLE_OUTLINE
338
2.57k
  if (outline) {
339
1.27k
    delete outline;
340
1.27k
  }
341
2.57k
#endif
342
2.57k
  if (annots) {
343
1.27k
    delete annots;
344
1.27k
  }
345
2.57k
  if (catalog) {
346
1.27k
    delete catalog;
347
1.27k
  }
348
2.57k
  if (xref) {
349
1.27k
    delete xref;
350
1.27k
  }
351
2.57k
  if (str) {
352
2.57k
    delete str;
353
2.57k
  }
354
2.57k
  if (file) {
355
0
    fclose(file);
356
0
  }
357
2.57k
  if (fileName) {
358
0
    delete fileName;
359
0
  }
360
#ifdef _WIN32
361
  if (fileNameU) {
362
    gfree(fileNameU);
363
  }
364
#endif
365
2.57k
}
366
367
// Check for a PDF header on this stream.  Skip past some garbage
368
// if necessary.
369
2.58k
void PDFDoc::checkHeader() {
370
2.58k
  char hdrBuf[headerSearchSize+1];
371
2.58k
  char *p;
372
2.58k
  int i;
373
374
2.58k
  pdfVersion = 0;
375
2.58k
  memset(hdrBuf, 0, headerSearchSize + 1);
376
2.58k
  str->getBlock(hdrBuf, headerSearchSize);
377
1.49M
  for (i = 0; i < headerSearchSize - 5; ++i) {
378
1.49M
    if (!strncmp(&hdrBuf[i], "%PDF-", 5)) {
379
1.50k
      break;
380
1.50k
    }
381
1.49M
  }
382
2.58k
  if (i >= headerSearchSize - 5) {
383
1.08k
    error(errSyntaxWarning, -1, "May not be a PDF file (continuing anyway)");
384
1.08k
    return;
385
1.08k
  }
386
1.50k
  str->moveStart(i);
387
1.50k
  if (!(p = strtok(&hdrBuf[i+5], " \t\n\r"))) {
388
8
    error(errSyntaxWarning, -1, "May not be a PDF file (continuing anyway)");
389
8
    return;
390
8
  }
391
1.49k
  pdfVersion = atof(p);
392
1.49k
  if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') ||
393
1.49k
      pdfVersion > supportedPDFVersionNum + 0.0001) {
394
409
    error(errSyntaxWarning, -1,
395
409
    "PDF version {0:s} -- xpdf supports version {1:s} (continuing anyway)",
396
409
    p, supportedPDFVersionStr);
397
409
  }
398
1.49k
}
399
400
1.47k
GBool PDFDoc::checkEncryption(GString *ownerPassword, GString *userPassword) {
401
1.47k
  Object encrypt;
402
1.47k
  GBool encrypted;
403
1.47k
  SecurityHandler *secHdlr;
404
1.47k
  GBool ret;
405
406
1.47k
  xref->getTrailerDict()->dictLookup("Encrypt", &encrypt);
407
1.47k
  if ((encrypted = encrypt.isDict())) {
408
146
    if ((secHdlr = SecurityHandler::make(this, &encrypt))) {
409
143
      if (secHdlr->isUnencrypted()) {
410
  // no encryption
411
0
  ret = gTrue;
412
143
      } else if (secHdlr->checkEncryption(ownerPassword, userPassword)) {
413
  // authorization succeeded
414
131
        xref->setEncryption(secHdlr->getPermissionFlags(),
415
131
          secHdlr->getOwnerPasswordOk(),
416
131
          secHdlr->getFileKey(),
417
131
          secHdlr->getFileKeyLength(),
418
131
          secHdlr->getEncVersion(),
419
131
          secHdlr->getEncAlgorithm());
420
131
  ret = gTrue;
421
131
      } else {
422
  // authorization failed
423
12
  ret = gFalse;
424
12
      }
425
143
      delete secHdlr;
426
143
    } else {
427
      // couldn't find the matching security handler
428
3
      ret = gFalse;
429
3
    }
430
1.33k
  } else {
431
    // document is not encrypted
432
1.33k
    ret = gTrue;
433
1.33k
  }
434
1.47k
  encrypt.free();
435
1.47k
  return ret;
436
1.47k
}
437
438
void PDFDoc::displayPage(OutputDev *out, int page,
439
       double hDPI, double vDPI, int rotate,
440
       GBool useMediaBox, GBool crop, GBool printing,
441
       GBool (*abortCheckCbk)(void *data),
442
0
       void *abortCheckCbkData) {
443
0
  if (globalParams->getPrintCommands()) {
444
0
    printf("***** page %d *****\n", page);
445
0
  }
446
0
  catalog->getPage(page)->display(out, hDPI, vDPI,
447
0
          rotate, useMediaBox, crop, printing,
448
0
          abortCheckCbk, abortCheckCbkData);
449
0
}
450
451
void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage,
452
        double hDPI, double vDPI, int rotate,
453
        GBool useMediaBox, GBool crop, GBool printing,
454
        GBool (*abortCheckCbk)(void *data),
455
0
        void *abortCheckCbkData) {
456
0
  int page;
457
458
0
  for (page = firstPage; page <= lastPage; ++page) {
459
0
    if (globalParams->getPrintStatusInfo()) {
460
0
      fflush(stderr);
461
0
      printf("[processing page %d]\n", page);
462
0
      fflush(stdout);
463
0
    }
464
0
    displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, printing,
465
0
    abortCheckCbk, abortCheckCbkData);
466
0
    catalog->doneWithPage(page);
467
0
  }
468
0
}
469
470
void PDFDoc::displayPageSlice(OutputDev *out, int page,
471
            double hDPI, double vDPI, int rotate,
472
            GBool useMediaBox, GBool crop, GBool printing,
473
            int sliceX, int sliceY, int sliceW, int sliceH,
474
            GBool (*abortCheckCbk)(void *data),
475
0
            void *abortCheckCbkData) {
476
0
  catalog->getPage(page)->displaySlice(out, hDPI, vDPI,
477
0
               rotate, useMediaBox, crop,
478
0
               sliceX, sliceY, sliceW, sliceH,
479
0
               printing,
480
0
               abortCheckCbk, abortCheckCbkData);
481
0
}
482
483
484
0
Links *PDFDoc::getLinks(int page) {
485
0
  return catalog->getPage(page)->getLinks();
486
0
}
487
488
0
void PDFDoc::processLinks(OutputDev *out, int page) {
489
0
  catalog->getPage(page)->processLinks(out);
490
0
}
491
492
#ifndef DISABLE_OUTLINE
493
0
int PDFDoc::getOutlineTargetPage(OutlineItem *outlineItem) {
494
0
  LinkAction *action;
495
0
  LinkActionKind kind;
496
0
  LinkDest *dest;
497
0
  GString *namedDest;
498
0
  Ref pageRef;
499
0
  int pg;
500
501
0
  if (outlineItem->pageNum >= 0) {
502
0
    return outlineItem->pageNum;
503
0
  }
504
0
  if (!(action = outlineItem->getAction())) {
505
0
    outlineItem->pageNum = 0;
506
0
    return 0;
507
0
  }
508
0
  kind = action->getKind();
509
0
  if (kind != actionGoTo) {
510
0
    outlineItem->pageNum = 0;
511
0
    return 0;
512
0
  }
513
0
  if ((dest = ((LinkGoTo *)action)->getDest())) {
514
0
    dest = dest->copy();
515
0
  } else if ((namedDest = ((LinkGoTo *)action)->getNamedDest())) {
516
0
    dest = findDest(namedDest);
517
0
  }
518
0
  pg = 0;
519
0
  if (dest) {
520
0
    if (dest->isPageRef()) {
521
0
      pageRef = dest->getPageRef();
522
0
      pg = findPage(pageRef.num, pageRef.gen);
523
0
    } else {
524
0
      pg = dest->getPageNum();
525
0
    }
526
0
    delete dest;
527
0
  }
528
0
  outlineItem->pageNum = pg;
529
0
  return pg;
530
0
}
531
#endif
532
533
0
GBool PDFDoc::isLinearized() {
534
0
  Parser *parser;
535
0
  Object obj1, obj2, obj3, obj4, obj5;
536
0
  GBool lin;
537
538
0
  lin = gFalse;
539
0
  obj1.initNull();
540
0
  parser = new Parser(xref,
541
0
       new Lexer(xref,
542
0
         str->makeSubStream(str->getStart(), gFalse, 0, &obj1)),
543
0
       gTrue);
544
0
  parser->getObj(&obj1);
545
0
  parser->getObj(&obj2);
546
0
  parser->getObj(&obj3);
547
0
  parser->getObj(&obj4);
548
0
  if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") &&
549
0
      obj4.isDict()) {
550
0
    obj4.dictLookup("Linearized", &obj5);
551
0
    if (obj5.isNum() && obj5.getNum() > 0) {
552
0
      lin = gTrue;
553
0
    }
554
0
    obj5.free();
555
0
  }
556
0
  obj4.free();
557
0
  obj3.free();
558
0
  obj2.free();
559
0
  obj1.free();
560
0
  delete parser;
561
0
  return lin;
562
0
}
563
564
0
GBool PDFDoc::saveAs(GString *name) {
565
0
  FILE *f;
566
0
  char buf[4096];
567
0
  int n;
568
569
0
  if (!(f = fopen(name->getCString(), "wb"))) {
570
0
    error(errIO, -1, "Couldn't open file '{0:t}'", name);
571
0
    return gFalse;
572
0
  }
573
0
  str->reset();
574
0
  while ((n = str->getBlock(buf, sizeof(buf))) > 0) {
575
0
    fwrite(buf, 1, n, f);
576
0
  }
577
0
  str->close();
578
0
  fclose(f);
579
0
  return gTrue;
580
0
}
581
582
0
GBool PDFDoc::saveEmbeddedFile(int idx, const char *path) {
583
0
  FILE *f;
584
0
  GBool ret;
585
586
0
  if (!(f = fopen(path, "wb"))) {
587
0
    return gFalse;
588
0
  }
589
0
  ret = saveEmbeddedFile2(idx, f);
590
0
  fclose(f);
591
0
  return ret;
592
0
}
593
594
0
GBool PDFDoc::saveEmbeddedFileU(int idx, const char *path) {
595
0
  FILE *f;
596
0
  GBool ret;
597
598
0
  if (!(f = openFile(path, "wb"))) {
599
0
    return gFalse;
600
0
  }
601
0
  ret = saveEmbeddedFile2(idx, f);
602
0
  fclose(f);
603
0
  return ret;
604
0
}
605
606
#ifdef _WIN32
607
GBool PDFDoc::saveEmbeddedFile(int idx, const wchar_t *path, int pathLen) {
608
  FILE *f;
609
  OSVERSIONINFO version;
610
  wchar_t path2w[winMaxLongPath + 1];
611
  char path2c[MAX_PATH + 1];
612
  int i;
613
  GBool ret;
614
615
  // NB: _wfopen is only available in NT
616
  version.dwOSVersionInfoSize = sizeof(version);
617
  GetVersionEx(&version);
618
  if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
619
    for (i = 0; i < pathLen && i < winMaxLongPath; ++i) {
620
      path2w[i] = path[i];
621
    }
622
    path2w[i] = 0;
623
    f = _wfopen(path2w, L"wb");
624
  } else {
625
    for (i = 0; i < pathLen && i < MAX_PATH; ++i) {
626
      path2c[i] = (char)path[i];
627
    }
628
    path2c[i] = 0;
629
    f = fopen(path2c, "wb");
630
  }
631
  if (!f) {
632
    return gFalse;
633
  }
634
  ret = saveEmbeddedFile2(idx, f);
635
  fclose(f);
636
  return ret;
637
}
638
#endif
639
640
0
GBool PDFDoc::saveEmbeddedFile2(int idx, FILE *f) {
641
0
  Object strObj;
642
0
  char buf[4096];
643
0
  int n;
644
645
0
  if (!catalog->getEmbeddedFileStreamObj(idx, &strObj)) {
646
0
    return gFalse;
647
0
  }
648
0
  strObj.streamReset();
649
0
  while ((n = strObj.streamGetBlock(buf, sizeof(buf))) > 0) {
650
0
    fwrite(buf, 1, n, f);
651
0
  }
652
0
  strObj.streamClose();
653
0
  strObj.free();
654
0
  return gTrue;
655
0
}
656
657
0
char *PDFDoc::getEmbeddedFileMem(int idx, int *size) {
658
0
  Object strObj;
659
0
  char *buf;
660
0
  int bufSize, sizeInc, n;
661
662
0
  if (!catalog->getEmbeddedFileStreamObj(idx, &strObj)) {
663
0
    return NULL;
664
0
  }
665
0
  strObj.streamReset();
666
0
  bufSize = 0;
667
0
  buf = NULL;
668
0
  do {
669
0
    sizeInc = bufSize ? bufSize : 1024;
670
0
    if (bufSize > INT_MAX - sizeInc) {
671
0
      error(errIO, -1, "embedded file is too large");
672
0
      *size = 0;
673
0
      return NULL;
674
0
    }
675
0
    buf = (char *)grealloc(buf, bufSize + sizeInc);
676
0
    n = strObj.streamGetBlock(buf + bufSize, sizeInc);
677
0
    bufSize += n;
678
0
  } while (n == sizeInc);
679
0
  strObj.streamClose();
680
0
  strObj.free();
681
0
  *size = bufSize;
682
0
  return buf;
683
0
}
684