2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-05-29 00:10:54 +00:00

Optimize QPDFParser for non-sparse QPDF_Arrays

Stop using nullptr to represent null objects.
Count null array elements and trigger creation of sparse arrays if null count is
greater than 100.
This commit is contained in:
m-holger 2023-03-26 20:02:49 +01:00
parent 18c1ffe0df
commit 8fdc3f0964
3 changed files with 29 additions and 19 deletions

View File

@ -27,16 +27,15 @@ namespace
struct StackFrame
{
StackFrame(std::shared_ptr<InputSource> input) :
offset(input->tell()),
contents_string(""),
contents_offset(-1)
offset(input->tell())
{
}
std::vector<std::shared_ptr<QPDFObject>> olist;
qpdf_offset_t offset;
std::string contents_string;
qpdf_offset_t contents_offset;
std::string contents_string{""};
qpdf_offset_t contents_offset{-1};
int null_count{0};
};
} // namespace
@ -50,6 +49,7 @@ QPDFParser::parse(bool& empty, bool content_stream)
// this, it will cause a logic error to be thrown from
// QPDF::inParse().
const static std::shared_ptr<QPDFObject> null_oh = QPDF_Null::create();
QPDF::ParseGuard pg(context);
empty = false;
@ -67,7 +67,6 @@ QPDFParser::parse(bool& empty, bool content_stream)
int good_count = 0;
bool b_contents = false;
bool is_null = false;
auto null_oh = QPDF_Null::create();
while (!done) {
bool bad = false;
@ -156,6 +155,8 @@ QPDFParser::parse(bool& empty, bool content_stream)
case QPDFTokenizer::tt_null:
is_null = true;
++frame.null_count;
break;
case QPDFTokenizer::tt_integer:
@ -301,9 +302,11 @@ QPDFParser::parse(bool& empty, bool content_stream)
case st_dictionary:
case st_array:
if (!indirect_ref && !is_null) {
// No need to set description for direct nulls - they will
// become implicit.
if (is_null) {
object = null_oh;
// No need to set description for direct nulls - they probably
// will become implicit.
} else if (!indirect_ref) {
setDescription(object, input->getLastOffset());
}
set_offset = true;
@ -326,7 +329,8 @@ QPDFParser::parse(bool& empty, bool content_stream)
parser_state_e old_state = state_stack.back();
state_stack.pop_back();
if (old_state == st_array) {
object = QPDF_Array::create(std::move(olist));
object = QPDF_Array::create(
std::move(olist), frame.null_count > 100);
setDescription(object, offset - 1);
// The `offset` points to the next of "[". Set the rewind
// offset to point to the beginning of "[". This has been
@ -381,7 +385,7 @@ QPDFParser::parse(bool& empty, bool content_stream)
// Calculate value.
std::shared_ptr<QPDFObject> val;
if (iter != olist.end()) {
val = *iter ? *iter : QPDF_Null::create();
val = *iter;
++iter;
} else {
QTC::TC("qpdf", "QPDFParser no val for last key");

View File

@ -11,15 +11,19 @@ QPDF_Array::QPDF_Array(std::vector<QPDFObjectHandle> const& v) :
setFromVector(v);
}
QPDF_Array::QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& v) :
QPDFValue(::ot_array, "array")
QPDF_Array::QPDF_Array(
std::vector<std::shared_ptr<QPDFObject>>&& v, bool sparse) :
QPDFValue(::ot_array, "array"),
sparse(sparse)
{
setFromVector(std::move(v));
}
QPDF_Array::QPDF_Array(SparseOHArray const& items) :
QPDFValue(::ot_array, "array"),
sparse(true),
sp_elements(items)
{
}
@ -37,9 +41,10 @@ QPDF_Array::create(std::vector<QPDFObjectHandle> const& items)
}
std::shared_ptr<QPDFObject>
QPDF_Array::create(std::vector<std::shared_ptr<QPDFObject>>&& items)
QPDF_Array::create(
std::vector<std::shared_ptr<QPDFObject>>&& items, bool sparse)
{
return do_create(new QPDF_Array(std::move(items)));
return do_create(new QPDF_Array(std::move(items), sparse));
}
std::shared_ptr<QPDFObject>
@ -196,8 +201,9 @@ QPDF_Array::setFromVector(std::vector<std::shared_ptr<QPDFObject>>&& v)
if (sparse) {
sp_elements = SparseOHArray();
for (auto&& item: v) {
if (item) {
sp_elements.append(item);
if (item->getTypeCode() != ::ot_null ||
item->getObjGen().isIndirect()) {
sp_elements.append(std::move(item));
} else {
++sp_elements.n_elements;
}

View File

@ -15,7 +15,7 @@ class QPDF_Array: public QPDFValue
static std::shared_ptr<QPDFObject>
create(std::vector<QPDFObjectHandle> const& items);
static std::shared_ptr<QPDFObject>
create(std::vector<std::shared_ptr<QPDFObject>>&& items);
create(std::vector<std::shared_ptr<QPDFObject>>&& items, bool sparse);
static std::shared_ptr<QPDFObject> create(SparseOHArray const& items);
static std::shared_ptr<QPDFObject> create(OHArray const& items);
virtual std::shared_ptr<QPDFObject> copy(bool shallow = false);
@ -36,7 +36,7 @@ class QPDF_Array: public QPDFValue
private:
QPDF_Array(std::vector<QPDFObjectHandle> const& items);
QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& items);
QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& items, bool sparse);
QPDF_Array(SparseOHArray const& items);
QPDF_Array(OHArray const& items);
bool sparse{false};