mirror of https://github.com/qpdf/qpdf.git
Add QPDFWriter::getRenumberedObjGen()
This commit is contained in:
parent
46ac3e21b3
commit
5cf4090aee
|
@ -465,6 +465,11 @@ class QPDFWriter
|
|||
QPDF_DLL
|
||||
void write();
|
||||
|
||||
// Return renumbered ObjGen that was written into the final file.
|
||||
// This method can be used after calling write().
|
||||
QPDF_DLL
|
||||
QPDFObjGen getRenumberedObjGen(QPDFObjGen);
|
||||
|
||||
private:
|
||||
// flags used by unparseObject
|
||||
static int const f_stream = 1 << 0;
|
||||
|
|
|
@ -2741,6 +2741,12 @@ QPDFWriter::write()
|
|||
indicateProgress(false, true);
|
||||
}
|
||||
|
||||
QPDFObjGen
|
||||
QPDFWriter::getRenumberedObjGen(QPDFObjGen og)
|
||||
{
|
||||
return QPDFObjGen(this->m->obj_renumber[og], 0);
|
||||
}
|
||||
|
||||
void
|
||||
QPDFWriter::enqueuePart(std::vector<QPDFObjectHandle>& part)
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ BINS_qpdf = \
|
|||
test_large_file \
|
||||
test_pdf_doc_encoding \
|
||||
test_pdf_unicode \
|
||||
test_renumber \
|
||||
test_tokenizer \
|
||||
test_unicode_filenames \
|
||||
test_xref
|
||||
|
|
|
@ -4034,6 +4034,65 @@ $td->runtest("with object streams",
|
|||
$td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
|
||||
show_ntests();
|
||||
# ----------
|
||||
$td->notify("--- Renumber Objects / XRef ---");
|
||||
$n_tests += 8;
|
||||
|
||||
$td->runtest("w/o objstm",
|
||||
{$td->COMMAND => "test_renumber minimal.pdf"},
|
||||
{$td->REGEXP => "succeeded\n",
|
||||
$td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
|
||||
$td->runtest("w/ objstm",
|
||||
{$td->COMMAND => "test_renumber digitally-signed.pdf"},
|
||||
{$td->REGEXP => "succeeded\n",
|
||||
$td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
|
||||
$td->runtest("w/o objstm, --object-streams=generate",
|
||||
{$td->COMMAND =>
|
||||
"test_renumber --object-streams=generate minimal.pdf"},
|
||||
{$td->REGEXP => "succeeded\n",
|
||||
$td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
|
||||
$td->runtest("w/ objstm, --object-streams=generate",
|
||||
{$td->COMMAND =>
|
||||
"test_renumber --object-streams=generate digitally-signed.pdf"},
|
||||
{$td->REGEXP => "succeeded\n",
|
||||
$td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
|
||||
$td->runtest("w/o objstm, --linearize",
|
||||
{$td->COMMAND =>
|
||||
"test_renumber --linearize minimal.pdf"},
|
||||
{$td->REGEXP => "succeeded\n",
|
||||
$td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
|
||||
$td->runtest("w/ objstm, --linearize",
|
||||
{$td->COMMAND =>
|
||||
"test_renumber --linearize digitally-signed.pdf"},
|
||||
{$td->REGEXP => "succeeded\n",
|
||||
$td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
|
||||
$td->runtest("w/o objstm, --preserve-unreferenced",
|
||||
{$td->COMMAND =>
|
||||
"test_renumber --preserve-unreferenced minimal.pdf"},
|
||||
{$td->REGEXP => "succeeded\n",
|
||||
$td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
|
||||
$td->runtest("w/ objstm, --preserve-unreferenced",
|
||||
{$td->COMMAND =>
|
||||
"test_renumber --preserve-unreferenced digitally-signed.pdf"},
|
||||
{$td->REGEXP => "succeeded\n",
|
||||
$td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
|
||||
show_ntests();
|
||||
# ----------
|
||||
$td->notify("--- Large File Tests ---");
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
#include <qpdf/Buffer.hh>
|
||||
#include <qpdf/PointerHolder.hh>
|
||||
#include <qpdf/QPDF.hh>
|
||||
#include <qpdf/QPDFObject.hh>
|
||||
#include <qpdf/QPDFObjectHandle.hh>
|
||||
#include <qpdf/QPDFObjGen.hh>
|
||||
#include <qpdf/QPDFWriter.hh>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
|
||||
void usage()
|
||||
{
|
||||
std::cerr
|
||||
<< "Usage: test_renumber [OPTION] INPUT.pdf"
|
||||
<< std::endl
|
||||
<< "Option:"
|
||||
<< std::endl
|
||||
<< " --object-streams=preserve|disable|generate"
|
||||
<< std::endl
|
||||
<< " --linearize"
|
||||
<< std::endl
|
||||
<< " --preserve-unreferenced"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
bool compare(QPDFObjectHandle a, QPDFObjectHandle b)
|
||||
{
|
||||
static std::set<QPDFObjGen> visited;
|
||||
if (a.isIndirect())
|
||||
{
|
||||
if (visited.count(a.getObjGen()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
visited.insert(a.getObjGen());
|
||||
}
|
||||
|
||||
if (a.getTypeCode() != b.getTypeCode())
|
||||
{
|
||||
std::cerr
|
||||
<< "different type code"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (a.getTypeCode())
|
||||
{
|
||||
case QPDFObject::ot_boolean:
|
||||
if (a.getBoolValue() != b.getBoolValue())
|
||||
{
|
||||
std::cerr
|
||||
<< "different boolean"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case QPDFObject::ot_integer:
|
||||
if (a.getIntValue() != b.getIntValue())
|
||||
{
|
||||
std::cerr
|
||||
<< "different integer"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case QPDFObject::ot_real:
|
||||
if (a.getRealValue() != b.getRealValue())
|
||||
{
|
||||
std::cerr
|
||||
<< "different real"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case QPDFObject::ot_string:
|
||||
if (a.getStringValue() != b.getStringValue())
|
||||
{
|
||||
std::cerr
|
||||
<< "different string"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case QPDFObject::ot_name:
|
||||
if (a.getName() != b.getName())
|
||||
{
|
||||
std::cerr
|
||||
<< "different name"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case QPDFObject::ot_array:
|
||||
{
|
||||
std::vector<QPDFObjectHandle> objs_a = a.getArrayAsVector();
|
||||
std::vector<QPDFObjectHandle> objs_b = b.getArrayAsVector();
|
||||
size_t items = objs_a.size();
|
||||
if (items != objs_b.size())
|
||||
{
|
||||
std::cerr
|
||||
<< "different array size"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < items; ++i)
|
||||
{
|
||||
if (!compare(objs_a[i], objs_b[i]))
|
||||
{
|
||||
std::cerr
|
||||
<< "different array item"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QPDFObject::ot_dictionary:
|
||||
{
|
||||
std::set<std::string> keys_a = a.getKeys();
|
||||
std::set<std::string> keys_b = b.getKeys();
|
||||
if (keys_a != keys_b)
|
||||
{
|
||||
std::cerr
|
||||
<< "different dictionary keys"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for(std::set<std::string>::iterator iter = keys_a.begin();
|
||||
iter != keys_a.end(); ++iter)
|
||||
{
|
||||
if (!compare(a.getKey(*iter), b.getKey(*iter)))
|
||||
{
|
||||
std::cerr
|
||||
<< "different dictionary item"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QPDFObject::ot_null:
|
||||
break;
|
||||
case QPDFObject::ot_stream:
|
||||
std::cout << "stream objects are not compared" << std::endl;
|
||||
break;
|
||||
default:
|
||||
std::cerr << "unknown object type" << std::endl;
|
||||
std::exit(2);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
usage();
|
||||
std::exit(2);
|
||||
}
|
||||
|
||||
qpdf_object_stream_e mode = qpdf_o_preserve;
|
||||
bool blinearize = false;
|
||||
bool bpreserve_unreferenced = false;
|
||||
std::string filename_input;
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (argv[i][0] == '-')
|
||||
{
|
||||
std::string opt = argv[i];
|
||||
if (opt == "--object-streams=preserve")
|
||||
{
|
||||
mode = qpdf_o_preserve;
|
||||
}
|
||||
else if (opt == "--object-streams=disable")
|
||||
{
|
||||
mode = qpdf_o_disable;
|
||||
}
|
||||
else if (opt == "--object-streams=generate")
|
||||
{
|
||||
mode = qpdf_o_generate;
|
||||
}
|
||||
else if (opt == "--linearize")
|
||||
{
|
||||
blinearize = true;
|
||||
}
|
||||
else if (opt == "--preserve-unreferenced")
|
||||
{
|
||||
bpreserve_unreferenced = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
usage();
|
||||
std::exit(2);
|
||||
}
|
||||
}
|
||||
else if (argc == i + 1)
|
||||
{
|
||||
filename_input = argv[i];
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
usage();
|
||||
std::exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
QPDF qpdf_in;
|
||||
qpdf_in.processFile(filename_input.c_str ());
|
||||
std::vector<QPDFObjectHandle> objs_in = qpdf_in.getAllObjects();
|
||||
|
||||
QPDFWriter w(qpdf_in);
|
||||
w.setOutputMemory();
|
||||
w.setObjectStreamMode(mode);
|
||||
w.setLinearization(blinearize);
|
||||
w.setPreserveUnreferencedObjects(bpreserve_unreferenced);
|
||||
w.write();
|
||||
|
||||
PointerHolder<Buffer> buf = w.getBuffer();
|
||||
|
||||
QPDF qpdf_ren;
|
||||
qpdf_ren.processMemoryFile("renumbered",
|
||||
reinterpret_cast<char*>(buf->getBuffer()),
|
||||
buf->getSize());
|
||||
|
||||
for (std::vector<QPDFObjectHandle>::iterator iter = objs_in.begin();
|
||||
iter != objs_in.end(); ++iter)
|
||||
{
|
||||
QPDFObjGen og_in = iter->getObjGen();
|
||||
QPDFObjGen og_ren = w.getRenumberedObjGen(og_in);
|
||||
|
||||
std::cout
|
||||
<< "input "
|
||||
<< og_in.getObj() << "/" << og_in.getGen()
|
||||
<< " -> renumbered "
|
||||
<< og_ren.getObj() << "/" << og_ren.getGen()
|
||||
<< std::endl;
|
||||
|
||||
if (og_ren.getObj() == 0)
|
||||
{
|
||||
std::cout << "deleted" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!compare(*iter, qpdf_ren.getObjectByObjGen(og_ren)))
|
||||
{
|
||||
std::cerr
|
||||
<< "different"
|
||||
<< std::endl;
|
||||
std::exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "succeeded" << std::endl;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
std::exit(2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue