Commit 46ac3e21b362a8d5c7fd45c9c0384a52fc86fb9e

Authored by Masamichi Hosoda
Committed by Jay Berkenbilt
1 parent 06b818dc

Add QPDF::getXRefTable()

include/qpdf/QPDF.hh
... ... @@ -239,6 +239,8 @@ class QPDF
239 239 QPDFObjectHandle getTrailer();
240 240 QPDF_DLL
241 241 QPDFObjectHandle getRoot();
  242 + QPDF_DLL
  243 + std::map<QPDFObjGen, QPDFXRefEntry> getXRefTable();
242 244  
243 245 // Install this object handle as an indirect object and return an
244 246 // indirect reference to it.
... ... @@ -1400,6 +1402,7 @@ class QPDF
1400 1402 bool fixed_dangling_refs;
1401 1403 bool immediate_copy_from;
1402 1404 bool in_parse;
  1405 + bool parsed;
1403 1406  
1404 1407 // Linearization data
1405 1408 qpdf_offset_t first_xref_item_offset; // actual value from file
... ...
libqpdf/QPDF.cc
... ... @@ -155,6 +155,7 @@ QPDF::Members::Members() :
155 155 fixed_dangling_refs(false),
156 156 immediate_copy_from(false),
157 157 in_parse(false),
  158 + parsed(false),
158 159 first_xref_item_offset(0),
159 160 uncompressed_after_compressed(false)
160 161 {
... ... @@ -431,6 +432,7 @@ QPDF::parse(char const* password)
431 432  
432 433 initializeEncryption();
433 434 findAttachmentStreams();
  435 + this->m->parsed = true;
434 436 }
435 437  
436 438 void
... ... @@ -2620,6 +2622,17 @@ QPDF::getRoot()
2620 2622 return root;
2621 2623 }
2622 2624  
  2625 +std::map<QPDFObjGen, QPDFXRefEntry>
  2626 +QPDF::getXRefTable()
  2627 +{
  2628 + if (! this->m->parsed)
  2629 + {
  2630 + throw std::logic_error("QPDF::getXRefTable called before parsing.");
  2631 + }
  2632 +
  2633 + return this->m->xref_table;
  2634 +}
  2635 +
2623 2636 void
2624 2637 QPDF::getObjectStreamData(std::map<int, int>& omap)
2625 2638 {
... ...
qpdf/build.mk
... ... @@ -6,7 +6,8 @@ BINS_qpdf = \
6 6 test_pdf_doc_encoding \
7 7 test_pdf_unicode \
8 8 test_tokenizer \
9   - test_unicode_filenames
  9 + test_unicode_filenames \
  10 + test_xref
10 11 CBINS_qpdf = qpdf-ctest
11 12  
12 13 TARGETS_qpdf = $(foreach B,$(BINS_qpdf) $(CBINS_qpdf),qpdf/$(OUTPUT_DIR)/$(call binname,$(B)))
... ...
qpdf/qtest/qpdf.test
... ... @@ -4019,6 +4019,23 @@ foreach my $i (qw(preserve disable generate))
4019 4019  
4020 4020 show_ntests();
4021 4021 # ----------
  4022 +$td->notify("--- Get XRef Table ---");
  4023 +$n_tests += 2;
  4024 +
  4025 +$td->runtest("without object streams",
  4026 + {$td->COMMAND => "test_xref minimal.pdf"},
  4027 + {$td->FILE => "minimal-xref.out",
  4028 + $td->EXIT_STATUS => 0},
  4029 + $td->NORMALIZE_NEWLINES);
  4030 +
  4031 +$td->runtest("with object streams",
  4032 + {$td->COMMAND => "test_xref digitally-signed.pdf"},
  4033 + {$td->FILE => "digitally-signed-xref.out",
  4034 + $td->EXIT_STATUS => 0},
  4035 + $td->NORMALIZE_NEWLINES);
  4036 +
  4037 +show_ntests();
  4038 +# ----------
4022 4039 $td->notify("--- Large File Tests ---");
4023 4040 my $nlarge = 1;
4024 4041 if (defined $large_file_test_path)
... ...
qpdf/qtest/qpdf/digitally-signed-xref.out 0 โ†’ 100644
  1 +1/0, uncompressed, offset = 64450 (0xfbc2)
  2 +2/0, uncompressed, offset = 65177 (0xfe99)
  3 +3/0, uncompressed, offset = 68242 (0x10a92)
  4 +4/0, uncompressed, offset = 68383 (0x10b1f)
  5 +5/0, uncompressed, offset = 68538 (0x10bba)
  6 +6/0, compressed, stream number = 1, stream index = 0
  7 +7/0, compressed, stream number = 1, stream index = 1
  8 +8/0, compressed, stream number = 1, stream index = 2
  9 +9/0, compressed, stream number = 3, stream index = 0
  10 +10/0, compressed, stream number = 4, stream index = 0
  11 +11/0, uncompressed, offset = 16 (0x10)
  12 +12/0, uncompressed, offset = 649 (0x289)
  13 +13/0, uncompressed, offset = 726 (0x2d6)
  14 +14/0, uncompressed, offset = 900 (0x384)
  15 +15/0, uncompressed, offset = 1049 (0x419)
  16 +16/0, uncompressed, offset = 1256 (0x4e8)
  17 +17/0, uncompressed, offset = 1382 (0x566)
  18 +18/0, uncompressed, offset = 2411 (0x96b)
  19 +19/0, uncompressed, offset = 57705 (0xe169)
  20 +20/0, uncompressed, offset = 59412 (0xe814)
  21 +21/0, uncompressed, offset = 59506 (0xe872)
  22 +22/0, uncompressed, offset = 116 (0x74)
  23 +23/0, compressed, stream number = 19, stream index = 0
  24 +24/0, compressed, stream number = 19, stream index = 1
  25 +25/0, compressed, stream number = 19, stream index = 2
  26 +26/0, compressed, stream number = 19, stream index = 3
  27 +27/0, compressed, stream number = 19, stream index = 4
  28 +28/0, compressed, stream number = 19, stream index = 5
  29 +29/0, compressed, stream number = 19, stream index = 6
  30 +30/0, uncompressed, offset = 471 (0x1d7)
... ...
qpdf/qtest/qpdf/minimal-xref.out 0 โ†’ 100644
  1 +1/0, uncompressed, offset = 9 (0x9)
  2 +2/0, uncompressed, offset = 63 (0x3f)
  3 +3/0, uncompressed, offset = 135 (0x87)
  4 +4/0, uncompressed, offset = 307 (0x133)
  5 +5/0, uncompressed, offset = 403 (0x193)
  6 +6/0, uncompressed, offset = 438 (0x1b6)
... ...
qpdf/test_xref.cc 0 โ†’ 100644
  1 +#include <qpdf/QPDF.hh>
  2 +#include <qpdf/QPDFObjGen.hh>
  3 +#include <qpdf/QPDFXRefEntry.hh>
  4 +
  5 +#include <iostream>
  6 +#include <map>
  7 +#include <string>
  8 +#include <cstdlib>
  9 +
  10 +int main(int argc, char *argv[])
  11 +{
  12 + if (argc != 2)
  13 + {
  14 + std::cerr << "usage: test_xref INPUT.pdf" << std::endl;
  15 + std::exit(2);
  16 + }
  17 +
  18 + try
  19 + {
  20 + QPDF qpdf;
  21 + qpdf.processFile(argv[1]);
  22 +
  23 + std::map<QPDFObjGen, QPDFXRefEntry> xref
  24 + = qpdf.getXRefTable();
  25 +
  26 + for (std::map<QPDFObjGen, QPDFXRefEntry>::iterator iter = xref.begin();
  27 + iter != xref.end(); ++iter)
  28 + {
  29 + std::cout
  30 + << iter->first.getObj() << "/" << iter->first.getGen()
  31 + << ", ";
  32 + switch (iter->second.getType())
  33 + {
  34 + case 0:
  35 + std::cout
  36 + << "free entry"
  37 + << std::endl;
  38 + break;
  39 + case 1:
  40 + std::cout
  41 + << "uncompressed, offset = "
  42 + << iter->second.getOffset()
  43 + << " (0x"
  44 + << std::hex << iter->second.getOffset() << std::dec
  45 + << ")"
  46 + << std::endl;
  47 + break;
  48 + case 2:
  49 + std::cout
  50 + << "compressed, stream number = "
  51 + << iter->second.getObjStreamNumber()
  52 + << ", stream index = "
  53 + << iter->second.getObjStreamIndex()
  54 + << std::endl;
  55 + break;
  56 + default:
  57 + std::cerr
  58 + << "unknown"
  59 + << std::endl;
  60 + std::exit(2);
  61 + }
  62 + }
  63 + }
  64 + catch (std::exception& e)
  65 + {
  66 + std::cerr << e.what() << std::endl;
  67 + std::exit(2);
  68 + }
  69 +
  70 + return 0;
  71 +}
... ...