Add QPDFObjectHandle::shallowCopy()

This commit is contained in:
Jay Berkenbilt 2012-06-21 16:14:34 -04:00
parent 9689f4cdcf
commit d1ebe30ff6
9 changed files with 208 additions and 10 deletions

View File

@ -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

View File

@ -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

View File

@ -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)
{

View File

@ -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

View File

@ -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 ---");

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
attempt to make a shallow copy of a stream

View File

@ -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 ") +