aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TODO-pages.md4
-rw-r--r--TODO.md6
-rw-r--r--fuzz/qtest/fuzz.test2
-rw-r--r--fuzz/tiffpredictor_fuzzer.cc4
-rw-r--r--fuzz/tiffpredictor_fuzzer_seed_corpus/2b124d759b85547cfec13a8e9a9fee44be041029bin0 -> 1048576 bytes
-rw-r--r--libqpdf/Pl_TIFFPredictor.cc95
-rw-r--r--libqpdf/qpdf/Pl_TIFFPredictor.hh8
7 files changed, 69 insertions, 50 deletions
diff --git a/TODO-pages.md b/TODO-pages.md
index b99c6f84..83de0fff 100644
--- a/TODO-pages.md
+++ b/TODO-pages.md
@@ -447,7 +447,7 @@ Most of chapter 12 applies. See Document-level navigation (12.3).
# Feature to Issue Mapping
-Last checked: 2024-01-11
+Last checked: 2024-01-18
```
gh search issues label:pages --repo qpdf/qpdf --limit 200 --state=open
@@ -546,6 +546,8 @@ gh search issues label:pages --repo qpdf/qpdf --limit 200 --state=open
* There is some helpful discussion in #343 including
* Preserving open/closed status
* Preserving javascript actions
+* Split pages: write pages to memory
+ * Issues: #1130
# Other use cases
diff --git a/TODO.md b/TODO.md
index 0f12696f..938fda93 100644
--- a/TODO.md
+++ b/TODO.md
@@ -337,9 +337,9 @@ so, I find it useful to make reference to them in this list.
Note that there's nothing that says an indirect object in one update can't refer to an object that
doesn't appear until a later update. This means that QPDF has to hang onto indirect nulls,
including when they appear as dictionary values. In this case, QPDF_Dictionary::getKeys() ignores
- all keys with null values, and hasKey() returns false for keys that have null values. We would
- probably want to make QPDF_Dictionary able to handle the special case of keys that are indirect
- nulls and basically never have it drop any keys that are indirect objects. We also have to make
+ all keys with null values, and hasKey() returns false for keys that have null values. QPDF_Dictionary
+ already handles the special case of keys that are indirect nulls, which is used to reserve foreign
+ objects, including foreign pages which may or may not be copied. We also have to make
sure that the testing for this handles non-trivial cases of the targets of indirect nulls being
replaced by real objects in an update. Such indirect nulls should appear in tests as dictionary
values and as array values. In the distant past, qpdf used to replace indirect nulls with direct
diff --git a/fuzz/qtest/fuzz.test b/fuzz/qtest/fuzz.test
index 7ca371fd..a15e6281 100644
--- a/fuzz/qtest/fuzz.test
+++ b/fuzz/qtest/fuzz.test
@@ -19,7 +19,7 @@ my @fuzzers = (
['lzw' => 2],
['pngpredictor' => 1],
['runlength' => 6],
- ['tiffpredictor' => 1],
+ ['tiffpredictor' => 2],
['qpdf' => 56], # increment when adding new files
);
diff --git a/fuzz/tiffpredictor_fuzzer.cc b/fuzz/tiffpredictor_fuzzer.cc
index fd0e4c6e..21b7f61d 100644
--- a/fuzz/tiffpredictor_fuzzer.cc
+++ b/fuzz/tiffpredictor_fuzzer.cc
@@ -29,6 +29,10 @@ FuzzHelper::doChecks()
Pl_TIFFPredictor p("decoder", &discard, Pl_TIFFPredictor::a_decode, 16, 1, 8);
p.write(const_cast<unsigned char*>(data), size);
p.finish();
+ // Exercise with strange values for some of the parameters.
+ Pl_TIFFPredictor p2("decoder", &discard, Pl_TIFFPredictor::a_decode, 16, 2, 5);
+ p2.write(const_cast<unsigned char*>(data), size);
+ p2.finish();
}
void
diff --git a/fuzz/tiffpredictor_fuzzer_seed_corpus/2b124d759b85547cfec13a8e9a9fee44be041029 b/fuzz/tiffpredictor_fuzzer_seed_corpus/2b124d759b85547cfec13a8e9a9fee44be041029
new file mode 100644
index 00000000..6b1ffd1e
--- /dev/null
+++ b/fuzz/tiffpredictor_fuzzer_seed_corpus/2b124d759b85547cfec13a8e9a9fee44be041029
Binary files differ
diff --git a/libqpdf/Pl_TIFFPredictor.cc b/libqpdf/Pl_TIFFPredictor.cc
index 51594d11..ec477049 100644
--- a/libqpdf/Pl_TIFFPredictor.cc
+++ b/libqpdf/Pl_TIFFPredictor.cc
@@ -3,12 +3,9 @@
#include <qpdf/BitStream.hh>
#include <qpdf/BitWriter.hh>
#include <qpdf/QTC.hh>
-#include <qpdf/QUtil.hh>
#include <climits>
-#include <cstring>
#include <stdexcept>
-#include <vector>
Pl_TIFFPredictor::Pl_TIFFPredictor(
char const* identifier,
@@ -22,7 +19,7 @@ Pl_TIFFPredictor::Pl_TIFFPredictor(
columns(columns),
samples_per_pixel(samples_per_pixel),
bits_per_sample(bits_per_sample),
- pos(0)
+ p_next(getNext())
{
if (samples_per_pixel < 1) {
throw std::runtime_error("TIFFPredictor created with invalid samples_per_pixel");
@@ -35,71 +32,83 @@ Pl_TIFFPredictor::Pl_TIFFPredictor(
throw std::runtime_error("TIFFPredictor created with invalid columns value");
}
this->bytes_per_row = bpr & UINT_MAX;
- this->cur_row = QUtil::make_shared_array<unsigned char>(this->bytes_per_row);
- memset(this->cur_row.get(), 0, this->bytes_per_row);
}
void
Pl_TIFFPredictor::write(unsigned char const* data, size_t len)
{
- size_t left = this->bytes_per_row - this->pos;
- size_t offset = 0;
- while (len >= left) {
+ auto end = data + len;
+ auto row_end = data + (bytes_per_row - cur_row.size());
+ while (row_end <= end) {
// finish off current row
- memcpy(this->cur_row.get() + this->pos, data + offset, left);
- offset += left;
- len -= left;
+ cur_row.insert(cur_row.end(), data, row_end);
+ data = row_end;
+ row_end += bytes_per_row;
processRow();
// Prepare for next row
- memset(this->cur_row.get(), 0, this->bytes_per_row);
- left = this->bytes_per_row;
- this->pos = 0;
+ cur_row.clear();
}
- if (len) {
- memcpy(this->cur_row.get() + this->pos, data + offset, len);
- }
- this->pos += len;
+
+ cur_row.insert(cur_row.end(), data, end);
}
void
Pl_TIFFPredictor::processRow()
{
QTC::TC("libtests", "Pl_TIFFPredictor processRow", (action == a_decode ? 0 : 1));
- BitWriter bw(this->getNext());
- BitStream in(this->cur_row.get(), this->bytes_per_row);
- std::vector<long long> prev;
- for (unsigned int i = 0; i < this->samples_per_pixel; ++i) {
- long long sample = in.getBitsSigned(this->bits_per_sample);
- bw.writeBitsSigned(sample, this->bits_per_sample);
- prev.push_back(sample);
- }
- for (unsigned int col = 1; col < this->columns; ++col) {
- for (unsigned int i = 0; i < this->samples_per_pixel; ++i) {
- long long sample = in.getBitsSigned(this->bits_per_sample);
- long long new_sample = sample;
- if (action == a_encode) {
- new_sample -= prev[i];
- prev[i] = sample;
- } else {
- new_sample += prev[i];
- prev[i] = new_sample;
+ previous.assign(samples_per_pixel, 0);
+ if (bits_per_sample != 8) {
+ BitWriter bw(p_next);
+ BitStream in(cur_row.data(), cur_row.size());
+ for (unsigned int col = 0; col < this->columns; ++col) {
+ for (auto& prev: previous) {
+ long long sample = in.getBitsSigned(this->bits_per_sample);
+ long long new_sample = sample;
+ if (action == a_encode) {
+ new_sample -= prev;
+ prev = sample;
+ } else {
+ new_sample += prev;
+ prev = new_sample;
+ }
+ bw.writeBitsSigned(new_sample, this->bits_per_sample);
+ }
+ }
+ bw.flush();
+ } else {
+ out.clear();
+ auto next = cur_row.begin();
+ auto cr_end = cur_row.end();
+ auto pr_end = previous.end();
+
+ while (next != cr_end) {
+ for (auto prev = previous.begin(); prev != pr_end && next != cr_end; ++prev, ++next) {
+ long long sample = *next;
+ long long new_sample = sample;
+ if (action == a_encode) {
+ new_sample -= *prev;
+ *prev = sample;
+ } else {
+ new_sample += *prev;
+ *prev = new_sample;
+ }
+ out.push_back(static_cast<unsigned char>(255U & new_sample));
}
- bw.writeBitsSigned(new_sample, this->bits_per_sample);
}
+ p_next->write(out.data(), out.size());
}
- bw.flush();
}
void
Pl_TIFFPredictor::finish()
{
- if (this->pos) {
+ if (!cur_row.empty()) {
// write partial row
+ cur_row.insert(cur_row.end(), bytes_per_row - cur_row.size(), 0);
processRow();
}
- this->pos = 0;
- memset(this->cur_row.get(), 0, this->bytes_per_row);
- getNext()->finish();
+ cur_row.clear();
+ p_next->finish();
}
diff --git a/libqpdf/qpdf/Pl_TIFFPredictor.hh b/libqpdf/qpdf/Pl_TIFFPredictor.hh
index 21757593..276ed54d 100644
--- a/libqpdf/qpdf/Pl_TIFFPredictor.hh
+++ b/libqpdf/qpdf/Pl_TIFFPredictor.hh
@@ -6,6 +6,8 @@
#include <qpdf/Pipeline.hh>
+#include<vector>
+
class Pl_TIFFPredictor: public Pipeline
{
public:
@@ -31,8 +33,10 @@ class Pl_TIFFPredictor: public Pipeline
unsigned int bytes_per_row;
unsigned int samples_per_pixel;
unsigned int bits_per_sample;
- std::shared_ptr<unsigned char> cur_row;
- size_t pos;
+ std::vector<unsigned char> cur_row;
+ std::vector<long long> previous;
+ std::vector<unsigned char> out;
+ Pipeline* p_next;
};
#endif // PL_TIFFPREDICTOR_HH