mirror of https://github.com/qpdf/qpdf.git
SparseOHArray
This commit is contained in:
parent
04419d7c32
commit
e83f3308fb
|
@ -275,6 +275,14 @@ class QPDFObjectHandle
|
||||||
QPDF_DLL
|
QPDF_DLL
|
||||||
bool isReserved();
|
bool isReserved();
|
||||||
|
|
||||||
|
// True for objects that are direct nulls or have previously been
|
||||||
|
// resolved to be nulls. Does not attempt to resolve objects. This
|
||||||
|
// is intended for internal use, but it can be used as an
|
||||||
|
// efficient way to check for nulls if you don't mind unresolved
|
||||||
|
// indirect nulls being false negatives.
|
||||||
|
QPDF_DLL
|
||||||
|
bool isResolvedNull() const;
|
||||||
|
|
||||||
// This returns true in addition to the query for the specific
|
// This returns true in addition to the query for the specific
|
||||||
// type for indirect objects.
|
// type for indirect objects.
|
||||||
QPDF_DLL
|
QPDF_DLL
|
||||||
|
@ -926,6 +934,7 @@ class QPDFObjectHandle
|
||||||
friend class QPDF_Dictionary;
|
friend class QPDF_Dictionary;
|
||||||
friend class QPDF_Array;
|
friend class QPDF_Array;
|
||||||
friend class QPDF_Stream;
|
friend class QPDF_Stream;
|
||||||
|
friend class SparseOHArray;
|
||||||
private:
|
private:
|
||||||
static void releaseResolved(QPDFObjectHandle& o)
|
static void releaseResolved(QPDFObjectHandle& o)
|
||||||
{
|
{
|
||||||
|
|
|
@ -248,6 +248,10 @@ class QPDFObjectTypeAccessor
|
||||||
{
|
{
|
||||||
return (o && dynamic_cast<T*>(o));
|
return (o && dynamic_cast<T*>(o));
|
||||||
}
|
}
|
||||||
|
static bool check(QPDFObject const* o)
|
||||||
|
{
|
||||||
|
return (o && dynamic_cast<T const*>(o));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -257,6 +261,12 @@ QPDFObjectHandle::isBool()
|
||||||
return QPDFObjectTypeAccessor<QPDF_Bool>::check(m->obj.getPointer());
|
return QPDFObjectTypeAccessor<QPDF_Bool>::check(m->obj.getPointer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
QPDFObjectHandle::isResolvedNull() const
|
||||||
|
{
|
||||||
|
return QPDFObjectTypeAccessor<QPDF_Null>::check(m->obj.getPointer());
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
QPDFObjectHandle::isNull()
|
QPDFObjectHandle::isNull()
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
#include <qpdf/SparseOHArray.hh>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
SparseOHArray::SparseOHArray() :
|
||||||
|
n_elements(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
SparseOHArray::size() const
|
||||||
|
{
|
||||||
|
return this->n_elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SparseOHArray::append(QPDFObjectHandle oh)
|
||||||
|
{
|
||||||
|
if (! oh.isResolvedNull())
|
||||||
|
{
|
||||||
|
this->elements[this->n_elements] = oh;
|
||||||
|
}
|
||||||
|
++this->n_elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPDFObjectHandle
|
||||||
|
SparseOHArray::at(size_t idx) const
|
||||||
|
{
|
||||||
|
if (idx >= this->n_elements)
|
||||||
|
{
|
||||||
|
throw std::logic_error(
|
||||||
|
"INTERNAL ERROR: bounds error accessing SparseOHArray element");
|
||||||
|
}
|
||||||
|
std::map<size_t, QPDFObjectHandle>::const_iterator iter =
|
||||||
|
this->elements.find(idx);
|
||||||
|
if (iter == this->elements.end())
|
||||||
|
{
|
||||||
|
return QPDFObjectHandle::newNull();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (*iter).second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SparseOHArray::remove_last()
|
||||||
|
{
|
||||||
|
if (this->n_elements == 0)
|
||||||
|
{
|
||||||
|
throw std::logic_error(
|
||||||
|
"INTERNAL ERROR: attempt to remove"
|
||||||
|
" last item from empty SparseOHArray");
|
||||||
|
}
|
||||||
|
--this->n_elements;
|
||||||
|
this->elements.erase(this->n_elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SparseOHArray::releaseResolved()
|
||||||
|
{
|
||||||
|
for (std::map<size_t, QPDFObjectHandle>::iterator iter =
|
||||||
|
this->elements.begin();
|
||||||
|
iter != this->elements.end(); ++iter)
|
||||||
|
{
|
||||||
|
QPDFObjectHandle::ReleaseResolver::releaseResolved((*iter).second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SparseOHArray::setAt(size_t idx, QPDFObjectHandle oh)
|
||||||
|
{
|
||||||
|
if (idx >= this->n_elements)
|
||||||
|
{
|
||||||
|
throw std::logic_error("bounds error setting item in SparseOHArray");
|
||||||
|
}
|
||||||
|
if (oh.isResolvedNull())
|
||||||
|
{
|
||||||
|
this->elements.erase(idx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->elements[idx] = oh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SparseOHArray::erase(size_t idx)
|
||||||
|
{
|
||||||
|
if (idx >= this->n_elements)
|
||||||
|
{
|
||||||
|
throw std::logic_error("bounds error erasing item from SparseOHArray");
|
||||||
|
}
|
||||||
|
std::map<size_t, QPDFObjectHandle> dest;
|
||||||
|
for (std::map<size_t, QPDFObjectHandle>::iterator iter =
|
||||||
|
this->elements.begin();
|
||||||
|
iter != this->elements.end(); ++iter)
|
||||||
|
{
|
||||||
|
if ((*iter).first < idx)
|
||||||
|
{
|
||||||
|
dest.insert(*iter);
|
||||||
|
}
|
||||||
|
else if ((*iter).first > idx)
|
||||||
|
{
|
||||||
|
dest[(*iter).first - 1] = (*iter).second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->elements = dest;
|
||||||
|
--this->n_elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SparseOHArray::insert(size_t idx, QPDFObjectHandle oh)
|
||||||
|
{
|
||||||
|
if (idx > this->n_elements)
|
||||||
|
{
|
||||||
|
throw std::logic_error("bounds error inserting item to SparseOHArray");
|
||||||
|
}
|
||||||
|
else if (idx == this->n_elements)
|
||||||
|
{
|
||||||
|
// Allow inserting to the last position
|
||||||
|
append(oh);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::map<size_t, QPDFObjectHandle> dest;
|
||||||
|
for (std::map<size_t, QPDFObjectHandle>::iterator iter =
|
||||||
|
this->elements.begin();
|
||||||
|
iter != this->elements.end(); ++iter)
|
||||||
|
{
|
||||||
|
if ((*iter).first < idx)
|
||||||
|
{
|
||||||
|
dest.insert(*iter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dest[(*iter).first + 1] = (*iter).second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->elements = dest;
|
||||||
|
this->elements[idx] = oh;
|
||||||
|
++this->n_elements;
|
||||||
|
}
|
||||||
|
}
|
|
@ -76,6 +76,7 @@ SRCS_libqpdf = \
|
||||||
libqpdf/QUtil.cc \
|
libqpdf/QUtil.cc \
|
||||||
libqpdf/RC4.cc \
|
libqpdf/RC4.cc \
|
||||||
libqpdf/SecureRandomDataProvider.cc \
|
libqpdf/SecureRandomDataProvider.cc \
|
||||||
|
libqpdf/SparseOHArray.cc \
|
||||||
libqpdf/qpdf-c.cc \
|
libqpdf/qpdf-c.cc \
|
||||||
libqpdf/rijndael.cc \
|
libqpdf/rijndael.cc \
|
||||||
libqpdf/sha2.c \
|
libqpdf/sha2.c \
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef QPDF_SPARSEOHARRAY_HH
|
||||||
|
#define QPDF_SPARSEOHARRAY_HH
|
||||||
|
|
||||||
|
#include <qpdf/QPDFObjectHandle.hh>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
class SparseOHArray
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QPDF_DLL
|
||||||
|
SparseOHArray();
|
||||||
|
QPDF_DLL
|
||||||
|
size_t size() const;
|
||||||
|
QPDF_DLL
|
||||||
|
void append(QPDFObjectHandle oh);
|
||||||
|
QPDF_DLL
|
||||||
|
QPDFObjectHandle at(size_t idx) const;
|
||||||
|
QPDF_DLL
|
||||||
|
void remove_last();
|
||||||
|
QPDF_DLL
|
||||||
|
void releaseResolved();
|
||||||
|
QPDF_DLL
|
||||||
|
void setAt(size_t idx, QPDFObjectHandle oh);
|
||||||
|
QPDF_DLL
|
||||||
|
void erase(size_t idx);
|
||||||
|
QPDF_DLL
|
||||||
|
void insert(size_t idx, QPDFObjectHandle oh);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<size_t, QPDFObjectHandle> elements;
|
||||||
|
size_t n_elements;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QPDF_SPARSEOHARRAY_HH
|
|
@ -22,7 +22,8 @@ BINS_libtests = \
|
||||||
random \
|
random \
|
||||||
rc4 \
|
rc4 \
|
||||||
runlength \
|
runlength \
|
||||||
sha2
|
sha2 \
|
||||||
|
sparse_array
|
||||||
|
|
||||||
TARGETS_libtests = $(foreach B,$(BINS_libtests),libtests/$(OUTPUT_DIR)/$(call binname,$(B)))
|
TARGETS_libtests = $(foreach B,$(BINS_libtests),libtests/$(OUTPUT_DIR)/$(call binname,$(B)))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
require 5.008;
|
||||||
|
use warnings;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
require TestDriver;
|
||||||
|
|
||||||
|
my $td = new TestDriver('sparse array');
|
||||||
|
|
||||||
|
$td->runtest("sparse_array",
|
||||||
|
{$td->COMMAND => "sparse_array"},
|
||||||
|
{$td->STRING => "sparse array tests done\n",
|
||||||
|
$td->EXIT_STATUS => 0},
|
||||||
|
$td->NORMALIZE_NEWLINES);
|
||||||
|
|
||||||
|
$td->report(1);
|
|
@ -0,0 +1,82 @@
|
||||||
|
#include <qpdf/SparseOHArray.hh>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
SparseOHArray a;
|
||||||
|
assert(a.size() == 0);
|
||||||
|
|
||||||
|
a.append(QPDFObjectHandle::parse("1"));
|
||||||
|
a.append(QPDFObjectHandle::parse("(potato)"));
|
||||||
|
a.append(QPDFObjectHandle::parse("null"));
|
||||||
|
a.append(QPDFObjectHandle::parse("null"));
|
||||||
|
a.append(QPDFObjectHandle::parse("/Quack"));
|
||||||
|
assert(a.size() == 5);
|
||||||
|
assert(a.at(0).isInteger() && (a.at(0).getIntValue() == 1));
|
||||||
|
assert(a.at(1).isString() && (a.at(1).getStringValue() == "potato"));
|
||||||
|
assert(a.at(2).isNull());
|
||||||
|
assert(a.at(3).isNull());
|
||||||
|
assert(a.at(4).isName() && (a.at(4).getName() == "/Quack"));
|
||||||
|
|
||||||
|
a.insert(4, QPDFObjectHandle::parse("/BeforeQuack"));
|
||||||
|
assert(a.size() == 6);
|
||||||
|
assert(a.at(0).isInteger() && (a.at(0).getIntValue() == 1));
|
||||||
|
assert(a.at(4).isName() && (a.at(4).getName() == "/BeforeQuack"));
|
||||||
|
assert(a.at(5).isName() && (a.at(5).getName() == "/Quack"));
|
||||||
|
|
||||||
|
a.insert(2, QPDFObjectHandle::parse("/Third"));
|
||||||
|
assert(a.size() == 7);
|
||||||
|
assert(a.at(1).isString() && (a.at(1).getStringValue() == "potato"));
|
||||||
|
assert(a.at(2).isName() && (a.at(2).getName() == "/Third"));
|
||||||
|
assert(a.at(3).isNull());
|
||||||
|
assert(a.at(6).isName() && (a.at(6).getName() == "/Quack"));
|
||||||
|
|
||||||
|
a.insert(0, QPDFObjectHandle::parse("/First"));
|
||||||
|
assert(a.size() == 8);
|
||||||
|
assert(a.at(0).isName() && (a.at(0).getName() == "/First"));
|
||||||
|
assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));
|
||||||
|
assert(a.at(7).isName() && (a.at(7).getName() == "/Quack"));
|
||||||
|
|
||||||
|
a.erase(6);
|
||||||
|
assert(a.size() == 7);
|
||||||
|
assert(a.at(0).isName() && (a.at(0).getName() == "/First"));
|
||||||
|
assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));
|
||||||
|
assert(a.at(5).isNull());
|
||||||
|
assert(a.at(6).isName() && (a.at(6).getName() == "/Quack"));
|
||||||
|
|
||||||
|
a.erase(6);
|
||||||
|
assert(a.size() == 6);
|
||||||
|
assert(a.at(0).isName() && (a.at(0).getName() == "/First"));
|
||||||
|
assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));
|
||||||
|
assert(a.at(3).isName() && (a.at(3).getName() == "/Third"));
|
||||||
|
assert(a.at(4).isNull());
|
||||||
|
assert(a.at(5).isNull());
|
||||||
|
|
||||||
|
a.setAt(4, QPDFObjectHandle::parse("12"));
|
||||||
|
assert(a.at(4).isInteger() && (a.at(4).getIntValue() == 12));
|
||||||
|
a.setAt(4, QPDFObjectHandle::newNull());
|
||||||
|
assert(a.at(4).isNull());
|
||||||
|
|
||||||
|
a.remove_last();
|
||||||
|
assert(a.size() == 5);
|
||||||
|
assert(a.at(0).isName() && (a.at(0).getName() == "/First"));
|
||||||
|
assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));
|
||||||
|
assert(a.at(3).isName() && (a.at(3).getName() == "/Third"));
|
||||||
|
assert(a.at(4).isNull());
|
||||||
|
|
||||||
|
a.remove_last();
|
||||||
|
assert(a.size() == 4);
|
||||||
|
assert(a.at(0).isName() && (a.at(0).getName() == "/First"));
|
||||||
|
assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));
|
||||||
|
assert(a.at(3).isName() && (a.at(3).getName() == "/Third"));
|
||||||
|
|
||||||
|
a.remove_last();
|
||||||
|
assert(a.size() == 3);
|
||||||
|
assert(a.at(0).isName() && (a.at(0).getName() == "/First"));
|
||||||
|
assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));
|
||||||
|
assert(a.at(2).isString() && (a.at(2).getStringValue() == "potato"));
|
||||||
|
|
||||||
|
std::cout << "sparse array tests done" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue