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,6 +239,8 @@ class QPDF
239 QPDFObjectHandle getTrailer(); 239 QPDFObjectHandle getTrailer();
240 QPDF_DLL 240 QPDF_DLL
241 QPDFObjectHandle getRoot(); 241 QPDFObjectHandle getRoot();
  242 + QPDF_DLL
  243 + std::map<QPDFObjGen, QPDFXRefEntry> getXRefTable();
242 244
243 // Install this object handle as an indirect object and return an 245 // Install this object handle as an indirect object and return an
244 // indirect reference to it. 246 // indirect reference to it.
@@ -1400,6 +1402,7 @@ class QPDF @@ -1400,6 +1402,7 @@ class QPDF
1400 bool fixed_dangling_refs; 1402 bool fixed_dangling_refs;
1401 bool immediate_copy_from; 1403 bool immediate_copy_from;
1402 bool in_parse; 1404 bool in_parse;
  1405 + bool parsed;
1403 1406
1404 // Linearization data 1407 // Linearization data
1405 qpdf_offset_t first_xref_item_offset; // actual value from file 1408 qpdf_offset_t first_xref_item_offset; // actual value from file
libqpdf/QPDF.cc
@@ -155,6 +155,7 @@ QPDF::Members::Members() : @@ -155,6 +155,7 @@ QPDF::Members::Members() :
155 fixed_dangling_refs(false), 155 fixed_dangling_refs(false),
156 immediate_copy_from(false), 156 immediate_copy_from(false),
157 in_parse(false), 157 in_parse(false),
  158 + parsed(false),
158 first_xref_item_offset(0), 159 first_xref_item_offset(0),
159 uncompressed_after_compressed(false) 160 uncompressed_after_compressed(false)
160 { 161 {
@@ -431,6 +432,7 @@ QPDF::parse(char const* password) @@ -431,6 +432,7 @@ QPDF::parse(char const* password)
431 432
432 initializeEncryption(); 433 initializeEncryption();
433 findAttachmentStreams(); 434 findAttachmentStreams();
  435 + this->m->parsed = true;
434 } 436 }
435 437
436 void 438 void
@@ -2620,6 +2622,17 @@ QPDF::getRoot() @@ -2620,6 +2622,17 @@ QPDF::getRoot()
2620 return root; 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 void 2636 void
2624 QPDF::getObjectStreamData(std::map<int, int>& omap) 2637 QPDF::getObjectStreamData(std::map<int, int>& omap)
2625 { 2638 {
qpdf/build.mk
@@ -6,7 +6,8 @@ BINS_qpdf = \ @@ -6,7 +6,8 @@ BINS_qpdf = \
6 test_pdf_doc_encoding \ 6 test_pdf_doc_encoding \
7 test_pdf_unicode \ 7 test_pdf_unicode \
8 test_tokenizer \ 8 test_tokenizer \
9 - test_unicode_filenames 9 + test_unicode_filenames \
  10 + test_xref
10 CBINS_qpdf = qpdf-ctest 11 CBINS_qpdf = qpdf-ctest
11 12
12 TARGETS_qpdf = $(foreach B,$(BINS_qpdf) $(CBINS_qpdf),qpdf/$(OUTPUT_DIR)/$(call binname,$(B))) 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,6 +4019,23 @@ foreach my $i (qw(preserve disable generate))
4019 4019
4020 show_ntests(); 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 $td->notify("--- Large File Tests ---"); 4039 $td->notify("--- Large File Tests ---");
4023 my $nlarge = 1; 4040 my $nlarge = 1;
4024 if (defined $large_file_test_path) 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 +}