diff options
author | Jay Berkenbilt <ejb@ql.org> | 2012-06-24 21:26:28 +0200 |
---|---|---|
committer | Jay Berkenbilt <ejb@ql.org> | 2012-06-24 21:56:50 +0200 |
commit | 8318d81ada86d4ec8e343c47103932b6bbe45a42 (patch) | |
tree | a1ff22dc1584d84829d32c7b1d8698a332877763 /qpdf | |
parent | 781c313058e26b6ab6fda060a652a395d27cdb7a (diff) | |
download | qpdf-8318d81ada86d4ec8e343c47103932b6bbe45a42.tar.zst |
Fix and test support for files >= 4 GB
Diffstat (limited to 'qpdf')
-rw-r--r-- | qpdf/build.mk | 2 | ||||
-rw-r--r-- | qpdf/qpdf-ctest.c | 8 | ||||
-rw-r--r-- | qpdf/qtest/qpdf.test | 107 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/large_file-check-linearized.out | 5 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/large_file-check-normal.out | 5 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/large_file-check-ostream-linearized.out | 5 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/large_file-check-ostream.out | 5 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/large_file.out | 200 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/large_file_xref_reconstruct.out | 203 | ||||
-rw-r--r-- | qpdf/test_large_file.cc | 368 |
10 files changed, 905 insertions, 3 deletions
diff --git a/qpdf/build.mk b/qpdf/build.mk index dfe169ab..e3d50976 100644 --- a/qpdf/build.mk +++ b/qpdf/build.mk @@ -1,4 +1,4 @@ -BINS_qpdf = qpdf test_driver pdf_from_scratch +BINS_qpdf = qpdf test_driver pdf_from_scratch test_large_file CBINS_qpdf = qpdf-ctest TARGETS_qpdf = $(foreach B,$(BINS_qpdf) $(CBINS_qpdf),qpdf/$(OUTPUT_DIR)/$(call binname,$(B))) diff --git a/qpdf/qpdf-ctest.c b/qpdf/qpdf-ctest.c index ffb1fff8..0b6c5f1f 100644 --- a/qpdf/qpdf-ctest.c +++ b/qpdf/qpdf-ctest.c @@ -17,7 +17,10 @@ static void report_errors() printf("warning: %s\n", qpdf_get_error_full_text(qpdf, e)); printf(" code: %d\n", qpdf_get_error_code(qpdf, e)); printf(" file: %s\n", qpdf_get_error_filename(qpdf, e)); - printf(" pos : %ld\n", qpdf_get_error_file_position(qpdf, e)); + /* If your compiler doesn't support %lld, change to %ld and + * lose precision in the error message. + */ + printf(" pos : %lld\n", qpdf_get_error_file_position(qpdf, e)); printf(" text: %s\n", qpdf_get_error_message_detail(qpdf, e)); } if (qpdf_has_error(qpdf)) @@ -27,7 +30,8 @@ static void report_errors() printf("error: %s\n", qpdf_get_error_full_text(qpdf, e)); printf(" code: %d\n", qpdf_get_error_code(qpdf, e)); printf(" file: %s\n", qpdf_get_error_filename(qpdf, e)); - printf(" pos : %ld\n", qpdf_get_error_file_position(qpdf, e)); + /* see above comment about %lld */ + printf(" pos : %lld\n", qpdf_get_error_file_position(qpdf, e)); printf(" text: %s\n", qpdf_get_error_message_detail(qpdf, e)); } else diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index 94252db4..fa26597d 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -21,6 +21,7 @@ if ((exists $ENV{'SKIP_TEST_COMPARE_IMAGES'}) && { $compare_images = 0; } +my $large_file_test_path = $ENV{'LARGE_FILE_TEST_PATH'} || undef; my $have_acroread = 0; @@ -1447,8 +1448,114 @@ for (my $n = 1; $n <= 2; ++$n) } show_ntests(); +# ---------- +$td->notify("--- Large File Tests ---"); +my $nlarge = 1; +if (defined $large_file_test_path) +{ + $nlarge = 2; +} +else +{ + $td->notify("--- Skipping tests on actual large files ---"); +} +$n_tests += $nlarge * 13; +for (my $large = 0; $large < $nlarge; ++$large) +{ + if ($large) + { + $td->notify("--- Running tests on actual large files ---"); + } + else + { + $td->notify("--- Running large file tests on small files ---"); + } + my $size = ($large ? "large" : "small"); + my $file = $large ? "$large_file_test_path/a.pdf" : "a.pdf"; + $td->runtest("write test file", + {$td->COMMAND => "test_large_file write $size $file"}, + {$td->FILE => "large_file.out", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + $td->runtest("read test file", + {$td->COMMAND => "test_large_file read $size $file"}, + {$td->FILE => "large_file.out", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + $td->runtest("check", + {$td->COMMAND => "qpdf --suppress-recovery --check $file", + $td->FILTER => "grep -v checking"}, + {$td->FILE => "large_file-check-normal.out", + $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + + for my $ostream (0, 1) + { + for my $linearize (0, 1) + { + if (($ostream == 0) && ($linearize == 0)) + { + # Original file has no object streams and is not linearized. + next; + } + my $args = ""; + my $omode = $ostream ? "generate" : "disable"; + my $lin = $linearize ? "--linearize" : ""; + my $newfile = "$file-new"; + + $td->runtest("transform: ostream=$ostream, linearize=$linearize", + {$td->COMMAND => + "qpdf --stream-data=preserve" . + " --object-streams=$omode" . + " $lin $file $newfile"}, + {$td->STRING => "", $td->EXIT_STATUS => 0}); + $td->runtest("read test file", + {$td->COMMAND => + "test_large_file read $size $newfile"}, + {$td->FILE => "large_file.out", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + my $check_out = + ($linearize + ? ($ostream + ? "large_file-check-ostream-linearized.out" + : "large_file-check-linearized.out") + : ($ostream + ? "large_file-check-ostream.out" + : "large_file-check-normal.out")); + $td->runtest("check: ostream=$ostream, linearize=$linearize", + {$td->COMMAND => + "qpdf --suppress-recovery --check $newfile", + $td->FILTER => "grep -v checking"}, + {$td->FILE => $check_out, $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + unlink $newfile; + } + } + + # Clobber xref + open(F, "+<$file") or die; + seek(F, -50, 2); + my $pos = tell F; + my $buf; + read(F, $buf, 50); + die unless $buf =~ m/^(.*startxref\n)\d+/s; + $pos += length($1); + seek(F, $pos, 0) or die; + print F "oops" or die; + close(F); + my $cmd = +{$td->COMMAND => "test_large_file read $size $file"}; + if ($large) + { + $cmd->{$td->FILTER} = "sed -e s,$large_file_test_path/,,"; + } + $td->runtest("reconstruct xref table", + $cmd, + {$td->FILE => "large_file_xref_reconstruct.out", + $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + unlink $file; +} # ---------- + cleanup(); # See comments at beginning about calculation of number of tests. We diff --git a/qpdf/qtest/qpdf/large_file-check-linearized.out b/qpdf/qtest/qpdf/large_file-check-linearized.out new file mode 100644 index 00000000..6d3407bd --- /dev/null +++ b/qpdf/qtest/qpdf/large_file-check-linearized.out @@ -0,0 +1,5 @@ +PDF Version: 1.3 +File is not encrypted +File is linearized +No syntax or stream encoding errors found; the file may still contain +errors that qpdf cannot detect diff --git a/qpdf/qtest/qpdf/large_file-check-normal.out b/qpdf/qtest/qpdf/large_file-check-normal.out new file mode 100644 index 00000000..c5cc5b5f --- /dev/null +++ b/qpdf/qtest/qpdf/large_file-check-normal.out @@ -0,0 +1,5 @@ +PDF Version: 1.3 +File is not encrypted +File is not linearized +No syntax or stream encoding errors found; the file may still contain +errors that qpdf cannot detect diff --git a/qpdf/qtest/qpdf/large_file-check-ostream-linearized.out b/qpdf/qtest/qpdf/large_file-check-ostream-linearized.out new file mode 100644 index 00000000..079bb65d --- /dev/null +++ b/qpdf/qtest/qpdf/large_file-check-ostream-linearized.out @@ -0,0 +1,5 @@ +PDF Version: 1.5 +File is not encrypted +File is linearized +No syntax or stream encoding errors found; the file may still contain +errors that qpdf cannot detect diff --git a/qpdf/qtest/qpdf/large_file-check-ostream.out b/qpdf/qtest/qpdf/large_file-check-ostream.out new file mode 100644 index 00000000..8ea0e86f --- /dev/null +++ b/qpdf/qtest/qpdf/large_file-check-ostream.out @@ -0,0 +1,5 @@ +PDF Version: 1.5 +File is not encrypted +File is not linearized +No syntax or stream encoding errors found; the file may still contain +errors that qpdf cannot detect diff --git a/qpdf/qtest/qpdf/large_file.out b/qpdf/qtest/qpdf/large_file.out new file mode 100644 index 00000000..b1990d25 --- /dev/null +++ b/qpdf/qtest/qpdf/large_file.out @@ -0,0 +1,200 @@ +page 1 of 200 +page 2 of 200 +page 3 of 200 +page 4 of 200 +page 5 of 200 +page 6 of 200 +page 7 of 200 +page 8 of 200 +page 9 of 200 +page 10 of 200 +page 11 of 200 +page 12 of 200 +page 13 of 200 +page 14 of 200 +page 15 of 200 +page 16 of 200 +page 17 of 200 +page 18 of 200 +page 19 of 200 +page 20 of 200 +page 21 of 200 +page 22 of 200 +page 23 of 200 +page 24 of 200 +page 25 of 200 +page 26 of 200 +page 27 of 200 +page 28 of 200 +page 29 of 200 +page 30 of 200 +page 31 of 200 +page 32 of 200 +page 33 of 200 +page 34 of 200 +page 35 of 200 +page 36 of 200 +page 37 of 200 +page 38 of 200 +page 39 of 200 +page 40 of 200 +page 41 of 200 +page 42 of 200 +page 43 of 200 +page 44 of 200 +page 45 of 200 +page 46 of 200 +page 47 of 200 +page 48 of 200 +page 49 of 200 +page 50 of 200 +page 51 of 200 +page 52 of 200 +page 53 of 200 +page 54 of 200 +page 55 of 200 +page 56 of 200 +page 57 of 200 +page 58 of 200 +page 59 of 200 +page 60 of 200 +page 61 of 200 +page 62 of 200 +page 63 of 200 +page 64 of 200 +page 65 of 200 +page 66 of 200 +page 67 of 200 +page 68 of 200 +page 69 of 200 +page 70 of 200 +page 71 of 200 +page 72 of 200 +page 73 of 200 +page 74 of 200 +page 75 of 200 +page 76 of 200 +page 77 of 200 +page 78 of 200 +page 79 of 200 +page 80 of 200 +page 81 of 200 +page 82 of 200 +page 83 of 200 +page 84 of 200 +page 85 of 200 +page 86 of 200 +page 87 of 200 +page 88 of 200 +page 89 of 200 +page 90 of 200 +page 91 of 200 +page 92 of 200 +page 93 of 200 +page 94 of 200 +page 95 of 200 +page 96 of 200 +page 97 of 200 +page 98 of 200 +page 99 of 200 +page 100 of 200 +page 101 of 200 +page 102 of 200 +page 103 of 200 +page 104 of 200 +page 105 of 200 +page 106 of 200 +page 107 of 200 +page 108 of 200 +page 109 of 200 +page 110 of 200 +page 111 of 200 +page 112 of 200 +page 113 of 200 +page 114 of 200 +page 115 of 200 +page 116 of 200 +page 117 of 200 +page 118 of 200 +page 119 of 200 +page 120 of 200 +page 121 of 200 +page 122 of 200 +page 123 of 200 +page 124 of 200 +page 125 of 200 +page 126 of 200 +page 127 of 200 +page 128 of 200 +page 129 of 200 +page 130 of 200 +page 131 of 200 +page 132 of 200 +page 133 of 200 +page 134 of 200 +page 135 of 200 +page 136 of 200 +page 137 of 200 +page 138 of 200 +page 139 of 200 +page 140 of 200 +page 141 of 200 +page 142 of 200 +page 143 of 200 +page 144 of 200 +page 145 of 200 +page 146 of 200 +page 147 of 200 +page 148 of 200 +page 149 of 200 +page 150 of 200 +page 151 of 200 +page 152 of 200 +page 153 of 200 +page 154 of 200 +page 155 of 200 +page 156 of 200 +page 157 of 200 +page 158 of 200 +page 159 of 200 +page 160 of 200 +page 161 of 200 +page 162 of 200 +page 163 of 200 +page 164 of 200 +page 165 of 200 +page 166 of 200 +page 167 of 200 +page 168 of 200 +page 169 of 200 +page 170 of 200 +page 171 of 200 +page 172 of 200 +page 173 of 200 +page 174 of 200 +page 175 of 200 +page 176 of 200 +page 177 of 200 +page 178 of 200 +page 179 of 200 +page 180 of 200 +page 181 of 200 +page 182 of 200 +page 183 of 200 +page 184 of 200 +page 185 of 200 +page 186 of 200 +page 187 of 200 +page 188 of 200 +page 189 of 200 +page 190 of 200 +page 191 of 200 +page 192 of 200 +page 193 of 200 +page 194 of 200 +page 195 of 200 +page 196 of 200 +page 197 of 200 +page 198 of 200 +page 199 of 200 +page 200 of 200 diff --git a/qpdf/qtest/qpdf/large_file_xref_reconstruct.out b/qpdf/qtest/qpdf/large_file_xref_reconstruct.out new file mode 100644 index 00000000..da5b25b1 --- /dev/null +++ b/qpdf/qtest/qpdf/large_file_xref_reconstruct.out @@ -0,0 +1,203 @@ +WARNING: a.pdf: file is damaged +WARNING: a.pdf: can't find startxref +WARNING: a.pdf: Attempting to reconstruct cross-reference table +page 1 of 200 +page 2 of 200 +page 3 of 200 +page 4 of 200 +page 5 of 200 +page 6 of 200 +page 7 of 200 +page 8 of 200 +page 9 of 200 +page 10 of 200 +page 11 of 200 +page 12 of 200 +page 13 of 200 +page 14 of 200 +page 15 of 200 +page 16 of 200 +page 17 of 200 +page 18 of 200 +page 19 of 200 +page 20 of 200 +page 21 of 200 +page 22 of 200 +page 23 of 200 +page 24 of 200 +page 25 of 200 +page 26 of 200 +page 27 of 200 +page 28 of 200 +page 29 of 200 +page 30 of 200 +page 31 of 200 +page 32 of 200 +page 33 of 200 +page 34 of 200 +page 35 of 200 +page 36 of 200 +page 37 of 200 +page 38 of 200 +page 39 of 200 +page 40 of 200 +page 41 of 200 +page 42 of 200 +page 43 of 200 +page 44 of 200 +page 45 of 200 +page 46 of 200 +page 47 of 200 +page 48 of 200 +page 49 of 200 +page 50 of 200 +page 51 of 200 +page 52 of 200 +page 53 of 200 +page 54 of 200 +page 55 of 200 +page 56 of 200 +page 57 of 200 +page 58 of 200 +page 59 of 200 +page 60 of 200 +page 61 of 200 +page 62 of 200 +page 63 of 200 +page 64 of 200 +page 65 of 200 +page 66 of 200 +page 67 of 200 +page 68 of 200 +page 69 of 200 +page 70 of 200 +page 71 of 200 +page 72 of 200 +page 73 of 200 +page 74 of 200 +page 75 of 200 +page 76 of 200 +page 77 of 200 +page 78 of 200 +page 79 of 200 +page 80 of 200 +page 81 of 200 +page 82 of 200 +page 83 of 200 +page 84 of 200 +page 85 of 200 +page 86 of 200 +page 87 of 200 +page 88 of 200 +page 89 of 200 +page 90 of 200 +page 91 of 200 +page 92 of 200 +page 93 of 200 +page 94 of 200 +page 95 of 200 +page 96 of 200 +page 97 of 200 +page 98 of 200 +page 99 of 200 +page 100 of 200 +page 101 of 200 +page 102 of 200 +page 103 of 200 +page 104 of 200 +page 105 of 200 +page 106 of 200 +page 107 of 200 +page 108 of 200 +page 109 of 200 +page 110 of 200 +page 111 of 200 +page 112 of 200 +page 113 of 200 +page 114 of 200 +page 115 of 200 +page 116 of 200 +page 117 of 200 +page 118 of 200 +page 119 of 200 +page 120 of 200 +page 121 of 200 +page 122 of 200 +page 123 of 200 +page 124 of 200 +page 125 of 200 +page 126 of 200 +page 127 of 200 +page 128 of 200 +page 129 of 200 +page 130 of 200 +page 131 of 200 +page 132 of 200 +page 133 of 200 +page 134 of 200 +page 135 of 200 +page 136 of 200 +page 137 of 200 +page 138 of 200 +page 139 of 200 +page 140 of 200 +page 141 of 200 +page 142 of 200 +page 143 of 200 +page 144 of 200 +page 145 of 200 +page 146 of 200 +page 147 of 200 +page 148 of 200 +page 149 of 200 +page 150 of 200 +page 151 of 200 +page 152 of 200 +page 153 of 200 +page 154 of 200 +page 155 of 200 +page 156 of 200 +page 157 of 200 +page 158 of 200 +page 159 of 200 +page 160 of 200 +page 161 of 200 +page 162 of 200 +page 163 of 200 +page 164 of 200 +page 165 of 200 +page 166 of 200 +page 167 of 200 +page 168 of 200 +page 169 of 200 +page 170 of 200 +page 171 of 200 +page 172 of 200 +page 173 of 200 +page 174 of 200 +page 175 of 200 +page 176 of 200 +page 177 of 200 +page 178 of 200 +page 179 of 200 +page 180 of 200 +page 181 of 200 +page 182 of 200 +page 183 of 200 +page 184 of 200 +page 185 of 200 +page 186 of 200 +page 187 of 200 +page 188 of 200 +page 189 of 200 +page 190 of 200 +page 191 of 200 +page 192 of 200 +page 193 of 200 +page 194 of 200 +page 195 of 200 +page 196 of 200 +page 197 of 200 +page 198 of 200 +page 199 of 200 +page 200 of 200 diff --git a/qpdf/test_large_file.cc b/qpdf/test_large_file.cc new file mode 100644 index 00000000..c1ee4060 --- /dev/null +++ b/qpdf/test_large_file.cc @@ -0,0 +1,368 @@ +#include <qpdf/QPDF.hh> +#include <qpdf/QPDFWriter.hh> +#include <qpdf/QPDFObjectHandle.hh> +#include <qpdf/QUtil.hh> +#include <iostream> +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +// Run "test_large_file write small a.pdf" to get a PDF file that you +// can look at in a reader. + +// This program reads and writes specially crafted files for testing +// large file support. In write mode, write a file of npages pages +// where each page contains unique text and a unique image. The image +// is a binary representation of the page number. The image contains +// horizontal stripes with light stripes representing 1, dark stripes +// representing 0, and the high bit on top. In read mode, read the +// file back checking to make sure all the image data and page +// contents are as expected. + +// Running this is small mode produces a small file that is easy to +// look at in any viewer. Since there is no question about proper +// functionality for small files, writing and reading the small file +// allows the qpdf library to test this test program. Writing and +// reading the large file then allows us to verify large file support +// with confidence. + +static char const* whoami = 0; + +// Height should be a multiple of 10 +static int const nstripes = 10; +static int const stripesize_large = 500; +static int const stripesize_small = 5; +static int const npages = 200; + +// initialized in main +int stripesize = 0; +int width = 0; +int height = 0; +static unsigned char* buf = 0; + +static inline unsigned char get_pixel_color(int n, int row) +{ + return (n & (1 << (nstripes - 1 - row))) ? '\xc0' : '\x40'; +} + +class ImageChecker: public Pipeline +{ + public: + ImageChecker(int n); + virtual ~ImageChecker(); + virtual void write(unsigned char* data, size_t len); + virtual void finish(); + + private: + int n; + size_t offset; + bool okay; +}; + +ImageChecker::ImageChecker(int n) : + Pipeline("image checker", 0), + n(n), + offset(0), + okay(true) +{ +} + +ImageChecker::~ImageChecker() +{ +} + +void +ImageChecker::write(unsigned char* data, size_t len) +{ + for (size_t i = 0; i < len; ++i) + { + int y = (this->offset + i) / width / stripesize; + unsigned char color = get_pixel_color(n, y); + if (data[i] != color) + { + okay = false; + } + } + this->offset += len; +} + +void +ImageChecker::finish() +{ + if (! okay) + { + std::cout << "errors found checking image data for page " << n + << std::endl; + } +} + +class ImageProvider: public QPDFObjectHandle::StreamDataProvider +{ + public: + ImageProvider(int n); + virtual ~ImageProvider(); + virtual void provideStreamData(int objid, int generation, + Pipeline* pipeline); + size_t getLength() const; + + private: + int n; +}; + +ImageProvider::ImageProvider(int n) : + n(n) +{ +} + +ImageProvider::~ImageProvider() +{ +} + +void +ImageProvider::provideStreamData(int objid, int generation, + Pipeline* pipeline) +{ + if (buf == 0) + { + buf = new unsigned char[width * stripesize]; + } + std::cout << "page " << n << " of " << npages << std::endl; + for (int y = 0; y < nstripes; ++y) + { + unsigned char color = get_pixel_color(n, y); + memset(buf, (int) color, width * stripesize); + pipeline->write(buf, width * stripesize); + } + pipeline->finish(); +} + +size_t +ImageProvider::getLength() const +{ + return width * height; +} + +void usage() +{ + std::cerr << "Usage: " << whoami << " {read|write} {large|small} outfile" + << std::endl; + exit(2); +} + +static void set_parameters(bool large) +{ + stripesize = large ? stripesize_large : stripesize_small; + height = nstripes * stripesize; + width = height; +} + +std::string generate_page_contents(int pageno) +{ + std::string contents = + "BT /F1 24 Tf 72 720 Td (page " + QUtil::int_to_string(pageno) + + ") Tj ET\n" + "q 468 0 0 468 72 72 cm /Im1 Do Q\n"; + return contents; +} + +static QPDFObjectHandle create_page_contents(QPDF& pdf, int pageno) +{ + std::string contents = generate_page_contents(pageno); + PointerHolder<Buffer> b = new Buffer(contents.length()); + unsigned char* bp = b->getBuffer(); + memcpy(bp, (char*)contents.c_str(), contents.length()); + return QPDFObjectHandle::newStream(&pdf, b); +} + +QPDFObjectHandle newName(std::string const& name) +{ + return QPDFObjectHandle::newName(name); +} + +QPDFObjectHandle newInteger(int val) +{ + return QPDFObjectHandle::newInteger(val); +} + +static void create_pdf(char const* filename) +{ + QPDF pdf; + + pdf.emptyPDF(); + + QPDFObjectHandle font = pdf.makeIndirectObject( + QPDFObjectHandle::newDictionary()); + font.replaceKey("/Type", newName("/Font")); + font.replaceKey("/Subtype", newName("/Type1")); + font.replaceKey("/Name", newName("/F1")); + font.replaceKey("/BaseFont", newName("/Helvetica")); + font.replaceKey("/Encoding", newName("/WinAnsiEncoding")); + + QPDFObjectHandle procset = + pdf.makeIndirectObject(QPDFObjectHandle::newArray()); + procset.appendItem(newName("/PDF")); + procset.appendItem(newName("/Text")); + procset.appendItem(newName("/ImageC")); + + QPDFObjectHandle rfont = QPDFObjectHandle::newDictionary(); + rfont.replaceKey("/F1", font); + + QPDFObjectHandle mediabox = QPDFObjectHandle::newArray(); + mediabox.appendItem(newInteger(0)); + mediabox.appendItem(newInteger(0)); + mediabox.appendItem(newInteger(612)); + mediabox.appendItem(newInteger(792)); + + for (int pageno = 1; pageno <= npages; ++pageno) + { + QPDFObjectHandle image = QPDFObjectHandle::newStream(&pdf); + QPDFObjectHandle image_dict = image.getDict(); + image_dict.replaceKey("/Type", newName("/XObject")); + image_dict.replaceKey("/Subtype", newName("/Image")); + image_dict.replaceKey("/ColorSpace", newName("/DeviceGray")); + image_dict.replaceKey("/BitsPerComponent", newInteger(8)); + image_dict.replaceKey("/Width", newInteger(width)); + image_dict.replaceKey("/Height", newInteger(height)); + ImageProvider* p = new ImageProvider(pageno); + PointerHolder<QPDFObjectHandle::StreamDataProvider> provider(p); + image.replaceStreamData(provider, + QPDFObjectHandle::newNull(), + QPDFObjectHandle::newNull(), + p->getLength()); + + QPDFObjectHandle xobject = QPDFObjectHandle::newDictionary(); + xobject.replaceKey("/Im1", image); + + QPDFObjectHandle resources = QPDFObjectHandle::newDictionary(); + resources.replaceKey("/ProcSet", procset); + resources.replaceKey("/Font", rfont); + resources.replaceKey("/XObject", xobject); + + QPDFObjectHandle contents = create_page_contents(pdf, pageno); + + QPDFObjectHandle page = pdf.makeIndirectObject( + QPDFObjectHandle::newDictionary()); + page.replaceKey("/Type", newName("/Page")); + page.replaceKey("/MediaBox", mediabox); + page.replaceKey("/Contents", contents); + page.replaceKey("/Resources", resources); + + pdf.addPage(page, false); + } + + QPDFWriter w(pdf, filename); + w.setStaticID(true); // for testing only + w.setStreamDataMode(qpdf_s_preserve); + w.setObjectStreamMode(qpdf_o_disable); + w.write(); +} + +static void check_page_contents(int pageno, QPDFObjectHandle page) +{ + PointerHolder<Buffer> buf = + page.getKey("/Contents").getStreamData(); + std::string actual_contents = + std::string((char *)(buf->getBuffer()), buf->getSize()); + std::string expected_contents = generate_page_contents(pageno); + if (expected_contents != actual_contents) + { + std::cout << "page contents wrong for page " << pageno << std::endl + << "ACTUAL: " << actual_contents + << "EXPECTED: " << expected_contents + << "----\n"; + } +} + +static void check_image(int pageno, QPDFObjectHandle page) +{ + QPDFObjectHandle image = + page.getKey("/Resources").getKey("/XObject").getKey("/Im1"); + ImageChecker ic(pageno); + image.pipeStreamData(&ic, true, false, false); +} + +static void check_pdf(char const* filename) +{ + QPDF pdf; + pdf.processFile(filename); + std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages(); + assert(pages.size() == (size_t)npages); + for (int i = 0; i < npages; ++i) + { + int pageno = i + 1; + std::cout << "page " << pageno << " of " << npages << std::endl; + check_page_contents(pageno, pages[i]); + check_image(pageno, pages[i]); + } +} + +int main(int argc, char* argv[]) +{ + whoami = QUtil::getWhoami(argv[0]); + QUtil::setLineBuf(stdout); + + // For libtool's sake.... + if (strncmp(whoami, "lt-", 3) == 0) + { + whoami += 3; + } + if (argc != 4) + { + usage(); + } + char const* operation = argv[1]; + char const* size = argv[2]; + char const* filename = argv[3]; + + bool op_write = false; + bool size_large = false; + + if (strcmp(operation, "write") == 0) + { + op_write = true; + } + else if (strcmp(operation, "read") == 0) + { + op_write = false; + } + else + { + usage(); + } + + if (strcmp(size, "large") == 0) + { + size_large = true; + } + else if (strcmp(size, "small") == 0) + { + size_large = false; + } + else + { + usage(); + } + + set_parameters(size_large); + + try + { + if (op_write) + { + create_pdf(filename); + } + else + { + check_pdf(filename); + } + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + exit(2); + } + + delete [] buf; + + return 0; +} |