summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2012-06-21 22:14:34 +0200
committerJay Berkenbilt <ejb@ql.org>2012-06-21 22:15:09 +0200
commitd1ebe30ff63a2f79da041e2d0c4718523db1beda (patch)
tree01daee6636708e83732e526cbe7c49172cc0d759
parent9689f4cdcff33babafad71378fb26259f0556a99 (diff)
downloadqpdf-d1ebe30ff63a2f79da041e2d0c4718523db1beda.tar.zst
Add QPDFObjectHandle::shallowCopy()
-rw-r--r--ChangeLog2
-rw-r--r--include/qpdf/QPDFObjectHandle.hh7
-rw-r--r--libqpdf/QPDFObjectHandle.cc32
-rw-r--r--qpdf/qpdf.testcov4
-rw-r--r--qpdf/qtest/qpdf.test14
-rw-r--r--qpdf/qtest/qpdf/shallow_array-out.pdf40
-rw-r--r--qpdf/qtest/qpdf/shallow_array.pdf80
-rw-r--r--qpdf/qtest/qpdf/shallow_stream.out1
-rw-r--r--qpdf/test_driver.cc38
9 files changed, 208 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index 3b164e56..d67a82e6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,7 @@
2012-06-21 Jay Berkenbilt <ejb@ql.org>
+ * QPDFObjectHandle: add shallowCopy() method
+
* QPDF: add new APIs for adding and removing pages. This includes
addPage(), addPageAt(), and removePage(). Also a method
updateAllPagesCache() is now available to force update of the
diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh
index 3a4bff13..e431d8a7 100644
--- a/include/qpdf/QPDFObjectHandle.hh
+++ b/include/qpdf/QPDFObjectHandle.hh
@@ -190,6 +190,13 @@ class QPDFObjectHandle
QPDF_DLL
bool isOrHasName(std::string const&);
+ // Create a shallow copy of an object as a direct object. Since
+ // this is a shallow copy, for dictionaries and arrays, any keys
+ // or items that were indirect objects will still be indirect
+ // objects that point to the same place.
+ QPDF_DLL
+ QPDFObjectHandle shallowCopy();
+
// Mutator methods. Use with caution.
// Recursively copy this object, making it direct. Throws an
diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc
index 53d9414c..4e28c405 100644
--- a/libqpdf/QPDFObjectHandle.cc
+++ b/libqpdf/QPDFObjectHandle.cc
@@ -663,6 +663,38 @@ QPDFObjectHandle::newStream(QPDF* qpdf, PointerHolder<Buffer> data)
return result;
}
+QPDFObjectHandle
+QPDFObjectHandle::shallowCopy()
+{
+ assertInitialized();
+
+ if (isStream())
+ {
+ QTC::TC("qpdf", "QPDFObjectHandle ERR shallow copy stream");
+ throw std::runtime_error(
+ "attempt to make a shallow copy of a stream");
+ }
+
+ QPDFObjectHandle new_obj;
+ if (isArray())
+ {
+ QTC::TC("qpdf", "QPDFObjectHandle shallow copy array");
+ new_obj = newArray(getArrayAsVector());
+ }
+ else if (isDictionary())
+ {
+ QTC::TC("qpdf", "QPDFObjectHandle shallow copy dictionary");
+ new_obj = newDictionary(getDictAsMap());
+ }
+ else
+ {
+ QTC::TC("qpdf", "QPDFObjectHandle shallow copy scalar");
+ new_obj = *this;
+ }
+
+ return new_obj;
+}
+
void
QPDFObjectHandle::makeDirectInternal(std::set<int>& visited)
{
diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov
index c7207bc8..5c40037e 100644
--- a/qpdf/qpdf.testcov
+++ b/qpdf/qpdf.testcov
@@ -209,3 +209,7 @@ QPDF insert page 2
QPDF updateAllPagesCache 0
QPDF insert non-indirect page 0
QPDF insert indirect page 0
+QPDFObjectHandle ERR shallow copy stream 0
+QPDFObjectHandle shallow copy array 0
+QPDFObjectHandle shallow copy dictionary 0
+QPDFObjectHandle shallow copy scalar 0
diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test
index 053fb3b2..a1a76ce3 100644
--- a/qpdf/qtest/qpdf.test
+++ b/qpdf/qtest/qpdf.test
@@ -144,7 +144,7 @@ $td->runtest("duplicate page",
$td->NORMALIZE_NEWLINES);
# ----------
$td->notify("--- Miscellaneous Tests ---");
-$n_tests += 37;
+$n_tests += 40;
$td->runtest("qpdf version",
{$td->COMMAND => "qpdf --version"},
@@ -338,6 +338,18 @@ $td->runtest("check output",
{$td->FILE => "c-info-out.pdf"});
unlink "a.pdf" or die;
+$td->runtest("shallow copy an array",
+ {$td->COMMAND => "test_driver 20 shallow_array.pdf"},
+ {$td->STRING => "test 20 done\n", $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
+$td->runtest("check output",
+ {$td->FILE => "a.pdf"},
+ {$td->FILE => "shallow_array-out.pdf"});
+$td->runtest("shallow copy a stream",
+ {$td->COMMAND => "test_driver 21 shallow_array.pdf"},
+ {$td->FILE => "shallow_stream.out", $td->EXIT_STATUS => 2},
+ $td->NORMALIZE_NEWLINES);
+
show_ntests();
# ----------
$td->notify("--- Error Condition Tests ---");
diff --git a/qpdf/qtest/qpdf/shallow_array-out.pdf b/qpdf/qtest/qpdf/shallow_array-out.pdf
new file mode 100644
index 00000000..31d86ecc
--- /dev/null
+++ b/qpdf/qtest/qpdf/shallow_array-out.pdf
@@ -0,0 +1,40 @@
+%PDF-1.3
+%¿÷¢þ
+1 0 obj
+<< /Pages 2 0 R /Type /Catalog >>
+endobj
+2 0 obj
+<< /Count 1 /Kids [ 3 0 R ] /Type /Pages >>
+endobj
+3 0 obj
+<< /Contents 4 0 R /MediaBox [ 0 0 612 792 ] /Parent 2 0 R /Resources << /Font << /F1 5 0 R >> /ProcSet 6 0 R >> /Type /Page >>
+endobj
+4 0 obj
+<< /Length 44 >>
+stream
+BT
+ /F1 24 Tf
+ 72 720 Td
+ (Potato) Tj
+ET
+endstream
+endobj
+5 0 obj
+<< /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >>
+endobj
+6 0 obj
+[ /PDF /Text ]
+endobj
+xref
+0 7
+0000000000 65535 f
+0000000015 00000 n
+0000000064 00000 n
+0000000123 00000 n
+0000000266 00000 n
+0000000359 00000 n
+0000000466 00000 n
+trailer << /QTest [ /A 1 0 R /B ] /QTest2 [ /A 1 0 R /B 7 ] /Root 1 0 R /Size 7 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >>
+startxref
+496
+%%EOF
diff --git a/qpdf/qtest/qpdf/shallow_array.pdf b/qpdf/qtest/qpdf/shallow_array.pdf
new file mode 100644
index 00000000..63c39b09
--- /dev/null
+++ b/qpdf/qtest/qpdf/shallow_array.pdf
@@ -0,0 +1,80 @@
+%PDF-1.3
+1 0 obj
+<<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+endobj
+
+2 0 obj
+<<
+ /Type /Pages
+ /Kids [
+ 3 0 R
+ ]
+ /Count 1
+>>
+endobj
+
+3 0 obj
+<<
+ /Type /Page
+ /Parent 2 0 R
+ /MediaBox [0 0 612 792]
+ /Contents 4 0 R
+ /Resources <<
+ /ProcSet 5 0 R
+ /Font <<
+ /F1 6 0 R
+ >>
+ >>
+>>
+endobj
+
+4 0 obj
+<<
+ /Length 44
+>>
+stream
+BT
+ /F1 24 Tf
+ 72 720 Td
+ (Potato) Tj
+ET
+endstream
+endobj
+
+5 0 obj
+[
+ /PDF
+ /Text
+]
+endobj
+
+6 0 obj
+<<
+ /Type /Font
+ /Subtype /Type1
+ /Name /F1
+ /BaseFont /Helvetica
+ /Encoding /WinAnsiEncoding
+>>
+endobj
+
+xref
+0 7
+0000000000 65535 f
+0000000009 00000 n
+0000000063 00000 n
+0000000135 00000 n
+0000000307 00000 n
+0000000403 00000 n
+0000000438 00000 n
+trailer <<
+ /Size 7
+ /Root 1 0 R
+ /QTest [ /A 1 0 R /B ]
+>>
+startxref
+556
+%%EOF
diff --git a/qpdf/qtest/qpdf/shallow_stream.out b/qpdf/qtest/qpdf/shallow_stream.out
new file mode 100644
index 00000000..fec1aa83
--- /dev/null
+++ b/qpdf/qtest/qpdf/shallow_stream.out
@@ -0,0 +1 @@
+attempt to make a shallow copy of a stream
diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc
index b2ceca5c..d2869317 100644
--- a/qpdf/test_driver.cc
+++ b/qpdf/test_driver.cc
@@ -691,17 +691,15 @@ void runtest(int n, char const* filename)
// dictionary and modify it. Using the results of
// getDictAsMap to create a new dictionary effectively creates
// a shallow copy.
- std::map<std::string, QPDFObjectHandle> page_dict_keys =
- QPDFObjectHandle(pages[0]).getDictAsMap();
+ QPDFObjectHandle page_tempate = pages[0];
std::vector<QPDFObjectHandle> new_pages;
for (std::vector<QPDFObjectHandle>::iterator iter = contents.begin();
iter != contents.end(); ++iter)
{
// We will retain indirect object references to other
// indirect objects other than page content.
- page_dict_keys["/Contents"] = *iter;
- QPDFObjectHandle page =
- QPDFObjectHandle::newDictionary(page_dict_keys);
+ QPDFObjectHandle page = page_tempate.shallowCopy();
+ page.replaceKey("/Contents", *iter);
if (iter == contents.begin())
{
// leave direct
@@ -745,12 +743,10 @@ void runtest(int n, char const* filename)
std::vector<QPDFObjectHandle> const& all_pages = pdf.getAllPages();
QPDFObjectHandle contents = createPageContents(pdf, "New page 10");
- std::map<std::string, QPDFObjectHandle> page_dict_keys =
- QPDFObjectHandle(all_pages[0]).getDictAsMap();
- page_dict_keys["/Contents"] = contents;
QPDFObjectHandle page =
pdf.makeIndirectObject(
- QPDFObjectHandle::newDictionary(page_dict_keys));
+ QPDFObjectHandle(all_pages[0]).shallowCopy());
+ page.replaceKey("/Contents", contents);
// Insert the page manually.
QPDFObjectHandle root = pdf.getRoot();
@@ -807,6 +803,30 @@ void runtest(int n, char const* filename)
pdf.addPage(pages[5], false);
std::cout << "you can't see this" << std::endl;
}
+ else if (n == 20)
+ {
+ // Shallow copy an array
+ QPDFObjectHandle trailer = pdf.getTrailer();
+ QPDFObjectHandle qtest = trailer.getKey("/QTest");
+ QPDFObjectHandle copy = qtest.shallowCopy();
+ // Append shallow copy of a scalar
+ copy.appendItem(trailer.getKey("/Size").shallowCopy());
+ trailer.replaceKey("/QTest2", copy);
+
+ QPDFWriter w(pdf, "a.pdf");
+ w.setStaticID(true);
+ w.setStreamDataMode(qpdf_s_preserve);
+ w.write();
+ }
+ else if (n == 21)
+ {
+ // Try to shallow copy a stream
+ std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages();
+ QPDFObjectHandle page = pages[0];
+ QPDFObjectHandle contents = page.getKey("/Contents");
+ contents.shallowCopy();
+ std::cout << "you can't see this" << std::endl;
+ }
else
{
throw std::runtime_error(std::string("invalid test ") +