mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 10:58:58 +00:00
Globally replace 'this->m->' with 'm->'
Using search and replace.
This commit is contained in:
parent
2028e35928
commit
85d784952f
@ -42,7 +42,7 @@ class QPDFOutlineObjectHelper: public QPDFObjectHelper
|
||||
{
|
||||
// This must be cleared explicitly to avoid circular references
|
||||
// that prevent cleanup of pointer holders.
|
||||
this->m->parent = nullptr;
|
||||
m->parent = nullptr;
|
||||
}
|
||||
|
||||
// All constructors are private. You can only create one of these
|
||||
|
@ -66,8 +66,8 @@ Buffer::copy(Buffer const& rhs)
|
||||
if (this != &rhs) {
|
||||
this->m =
|
||||
std::unique_ptr<Members>(new Members(rhs.m->size, nullptr, true));
|
||||
if (this->m->size) {
|
||||
memcpy(this->m->buf, rhs.m->buf, this->m->size);
|
||||
if (m->size) {
|
||||
memcpy(m->buf, rhs.m->buf, m->size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -75,17 +75,17 @@ Buffer::copy(Buffer const& rhs)
|
||||
size_t
|
||||
Buffer::getSize() const
|
||||
{
|
||||
return this->m->size;
|
||||
return m->size;
|
||||
}
|
||||
|
||||
unsigned char const*
|
||||
Buffer::getBuffer() const
|
||||
{
|
||||
return this->m->buf;
|
||||
return m->buf;
|
||||
}
|
||||
|
||||
unsigned char*
|
||||
Buffer::getBuffer()
|
||||
{
|
||||
return this->m->buf;
|
||||
return m->buf;
|
||||
}
|
||||
|
@ -197,10 +197,10 @@ JSON::JSON_blob::write(Pipeline* p, size_t) const
|
||||
void
|
||||
JSON::write(Pipeline* p, size_t depth) const
|
||||
{
|
||||
if (nullptr == this->m->value) {
|
||||
if (nullptr == m->value) {
|
||||
*p << "null";
|
||||
} else {
|
||||
this->m->value->write(p, depth);
|
||||
m->value->write(p, depth);
|
||||
}
|
||||
}
|
||||
|
||||
@ -282,7 +282,7 @@ JSON::makeDictionary()
|
||||
JSON
|
||||
JSON::addDictionaryMember(std::string const& key, JSON const& val)
|
||||
{
|
||||
if (auto* obj = dynamic_cast<JSON_dictionary*>(this->m->value.get())) {
|
||||
if (auto* obj = dynamic_cast<JSON_dictionary*>(m->value.get())) {
|
||||
return obj->members[encode_string(key)] =
|
||||
val.m->value ? val : makeNull();
|
||||
} else {
|
||||
@ -294,7 +294,7 @@ JSON::addDictionaryMember(std::string const& key, JSON const& val)
|
||||
bool
|
||||
JSON::checkDictionaryKeySeen(std::string const& key)
|
||||
{
|
||||
auto* obj = dynamic_cast<JSON_dictionary*>(this->m->value.get());
|
||||
auto* obj = dynamic_cast<JSON_dictionary*>(m->value.get());
|
||||
if (nullptr == obj) {
|
||||
throw std::logic_error(
|
||||
"JSON::checkDictionaryKey called on non-dictionary");
|
||||
@ -315,7 +315,7 @@ JSON::makeArray()
|
||||
JSON
|
||||
JSON::addArrayElement(JSON const& val)
|
||||
{
|
||||
auto* arr = dynamic_cast<JSON_array*>(this->m->value.get());
|
||||
auto* arr = dynamic_cast<JSON_array*>(m->value.get());
|
||||
if (nullptr == arr) {
|
||||
throw std::runtime_error("JSON::addArrayElement called on non-array");
|
||||
}
|
||||
@ -385,7 +385,7 @@ bool
|
||||
JSON::getString(std::string& utf8) const
|
||||
{
|
||||
if (m->value->type_code == vt_string) {
|
||||
auto v = dynamic_cast<JSON_string const*>(this->m->value.get());
|
||||
auto v = dynamic_cast<JSON_string const*>(m->value.get());
|
||||
utf8 = v->utf8;
|
||||
return true;
|
||||
}
|
||||
@ -396,7 +396,7 @@ bool
|
||||
JSON::getNumber(std::string& value) const
|
||||
{
|
||||
if (m->value->type_code == vt_number) {
|
||||
auto v = dynamic_cast<JSON_number const*>(this->m->value.get());
|
||||
auto v = dynamic_cast<JSON_number const*>(m->value.get());
|
||||
value = v->encoded;
|
||||
return true;
|
||||
}
|
||||
@ -407,7 +407,7 @@ bool
|
||||
JSON::getBool(bool& value) const
|
||||
{
|
||||
if (m->value->type_code == vt_bool) {
|
||||
auto v = dynamic_cast<JSON_bool const*>(this->m->value.get());
|
||||
auto v = dynamic_cast<JSON_bool const*>(m->value.get());
|
||||
value = v->value;
|
||||
return true;
|
||||
}
|
||||
@ -424,7 +424,7 @@ bool
|
||||
JSON::forEachDictItem(
|
||||
std::function<void(std::string const& key, JSON value)> fn) const
|
||||
{
|
||||
auto v = dynamic_cast<JSON_dictionary const*>(this->m->value.get());
|
||||
auto v = dynamic_cast<JSON_dictionary const*>(m->value.get());
|
||||
if (v == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@ -437,7 +437,7 @@ JSON::forEachDictItem(
|
||||
bool
|
||||
JSON::forEachArrayItem(std::function<void(JSON value)> fn) const
|
||||
{
|
||||
auto v = dynamic_cast<JSON_array const*>(this->m->value.get());
|
||||
auto v = dynamic_cast<JSON_array const*>(m->value.get());
|
||||
if (v == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@ -451,7 +451,7 @@ bool
|
||||
JSON::checkSchema(JSON schema, std::list<std::string>& errors)
|
||||
{
|
||||
return checkSchemaInternal(
|
||||
this->m->value.get(), schema.m->value.get(), 0, errors, "");
|
||||
m->value.get(), schema.m->value.get(), 0, errors, "");
|
||||
}
|
||||
|
||||
bool
|
||||
@ -459,7 +459,7 @@ JSON::checkSchema(
|
||||
JSON schema, unsigned long flags, std::list<std::string>& errors)
|
||||
{
|
||||
return checkSchemaInternal(
|
||||
this->m->value.get(), schema.m->value.get(), flags, errors, "");
|
||||
m->value.get(), schema.m->value.get(), flags, errors, "");
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1429,23 +1429,23 @@ JSON::parse(std::string const& s)
|
||||
void
|
||||
JSON::setStart(qpdf_offset_t start)
|
||||
{
|
||||
this->m->start = start;
|
||||
m->start = start;
|
||||
}
|
||||
|
||||
void
|
||||
JSON::setEnd(qpdf_offset_t end)
|
||||
{
|
||||
this->m->end = end;
|
||||
m->end = end;
|
||||
}
|
||||
|
||||
qpdf_offset_t
|
||||
JSON::getStart() const
|
||||
{
|
||||
return this->m->start;
|
||||
return m->start;
|
||||
}
|
||||
|
||||
qpdf_offset_t
|
||||
JSON::getEnd() const
|
||||
{
|
||||
return this->m->end;
|
||||
return m->end;
|
||||
}
|
||||
|
@ -18,51 +18,51 @@ JSONHandler::usage(std::string const& msg)
|
||||
void
|
||||
JSONHandler::addAnyHandler(json_handler_t fn)
|
||||
{
|
||||
this->m->h.any_handler = fn;
|
||||
m->h.any_handler = fn;
|
||||
}
|
||||
|
||||
void
|
||||
JSONHandler::addNullHandler(void_handler_t fn)
|
||||
{
|
||||
this->m->h.null_handler = fn;
|
||||
m->h.null_handler = fn;
|
||||
}
|
||||
|
||||
void
|
||||
JSONHandler::addStringHandler(string_handler_t fn)
|
||||
{
|
||||
this->m->h.string_handler = fn;
|
||||
m->h.string_handler = fn;
|
||||
}
|
||||
|
||||
void
|
||||
JSONHandler::addNumberHandler(string_handler_t fn)
|
||||
{
|
||||
this->m->h.number_handler = fn;
|
||||
m->h.number_handler = fn;
|
||||
}
|
||||
|
||||
void
|
||||
JSONHandler::addBoolHandler(bool_handler_t fn)
|
||||
{
|
||||
this->m->h.bool_handler = fn;
|
||||
m->h.bool_handler = fn;
|
||||
}
|
||||
|
||||
void
|
||||
JSONHandler::addDictHandlers(json_handler_t start_fn, void_handler_t end_fn)
|
||||
{
|
||||
this->m->h.dict_start_handler = start_fn;
|
||||
this->m->h.dict_end_handler = end_fn;
|
||||
m->h.dict_start_handler = start_fn;
|
||||
m->h.dict_end_handler = end_fn;
|
||||
}
|
||||
|
||||
void
|
||||
JSONHandler::addDictKeyHandler(
|
||||
std::string const& key, std::shared_ptr<JSONHandler> dkh)
|
||||
{
|
||||
this->m->h.dict_handlers[key] = dkh;
|
||||
m->h.dict_handlers[key] = dkh;
|
||||
}
|
||||
|
||||
void
|
||||
JSONHandler::addFallbackDictHandler(std::shared_ptr<JSONHandler> fdh)
|
||||
{
|
||||
this->m->h.fallback_dict_handler = fdh;
|
||||
m->h.fallback_dict_handler = fdh;
|
||||
}
|
||||
|
||||
void
|
||||
@ -71,71 +71,71 @@ JSONHandler::addArrayHandlers(
|
||||
void_handler_t end_fn,
|
||||
std::shared_ptr<JSONHandler> ah)
|
||||
{
|
||||
this->m->h.array_start_handler = start_fn;
|
||||
this->m->h.array_end_handler = end_fn;
|
||||
this->m->h.array_item_handler = ah;
|
||||
m->h.array_start_handler = start_fn;
|
||||
m->h.array_end_handler = end_fn;
|
||||
m->h.array_item_handler = ah;
|
||||
}
|
||||
|
||||
void
|
||||
JSONHandler::handle(std::string const& path, JSON j)
|
||||
{
|
||||
if (this->m->h.any_handler) {
|
||||
this->m->h.any_handler(path, j);
|
||||
if (m->h.any_handler) {
|
||||
m->h.any_handler(path, j);
|
||||
return;
|
||||
}
|
||||
bool handled = false;
|
||||
bool bvalue = false;
|
||||
std::string s_value;
|
||||
if (this->m->h.null_handler && j.isNull()) {
|
||||
this->m->h.null_handler(path);
|
||||
if (m->h.null_handler && j.isNull()) {
|
||||
m->h.null_handler(path);
|
||||
handled = true;
|
||||
}
|
||||
if (this->m->h.string_handler && j.getString(s_value)) {
|
||||
this->m->h.string_handler(path, s_value);
|
||||
if (m->h.string_handler && j.getString(s_value)) {
|
||||
m->h.string_handler(path, s_value);
|
||||
handled = true;
|
||||
}
|
||||
if (this->m->h.number_handler && j.getNumber(s_value)) {
|
||||
this->m->h.number_handler(path, s_value);
|
||||
if (m->h.number_handler && j.getNumber(s_value)) {
|
||||
m->h.number_handler(path, s_value);
|
||||
handled = true;
|
||||
}
|
||||
if (this->m->h.bool_handler && j.getBool(bvalue)) {
|
||||
this->m->h.bool_handler(path, bvalue);
|
||||
if (m->h.bool_handler && j.getBool(bvalue)) {
|
||||
m->h.bool_handler(path, bvalue);
|
||||
handled = true;
|
||||
}
|
||||
if (this->m->h.dict_start_handler && j.isDictionary()) {
|
||||
this->m->h.dict_start_handler(path, j);
|
||||
if (m->h.dict_start_handler && j.isDictionary()) {
|
||||
m->h.dict_start_handler(path, j);
|
||||
std::string path_base = path;
|
||||
if (path_base != ".") {
|
||||
path_base += ".";
|
||||
}
|
||||
j.forEachDictItem([&path, &path_base, this](
|
||||
std::string const& k, JSON v) {
|
||||
auto i = this->m->h.dict_handlers.find(k);
|
||||
if (i == this->m->h.dict_handlers.end()) {
|
||||
if (this->m->h.fallback_dict_handler.get()) {
|
||||
this->m->h.fallback_dict_handler->handle(path_base + k, v);
|
||||
j.forEachDictItem(
|
||||
[&path, &path_base, this](std::string const& k, JSON v) {
|
||||
auto i = m->h.dict_handlers.find(k);
|
||||
if (i == m->h.dict_handlers.end()) {
|
||||
if (m->h.fallback_dict_handler.get()) {
|
||||
m->h.fallback_dict_handler->handle(path_base + k, v);
|
||||
} else {
|
||||
QTC::TC("libtests", "JSONHandler unexpected key");
|
||||
usage(
|
||||
"JSON handler found unexpected key " + k +
|
||||
" in object at " + path);
|
||||
}
|
||||
} else {
|
||||
QTC::TC("libtests", "JSONHandler unexpected key");
|
||||
usage(
|
||||
"JSON handler found unexpected key " + k +
|
||||
" in object at " + path);
|
||||
i->second->handle(path_base + k, v);
|
||||
}
|
||||
} else {
|
||||
i->second->handle(path_base + k, v);
|
||||
}
|
||||
});
|
||||
this->m->h.dict_end_handler(path);
|
||||
});
|
||||
m->h.dict_end_handler(path);
|
||||
handled = true;
|
||||
}
|
||||
if (this->m->h.array_start_handler && j.isArray()) {
|
||||
this->m->h.array_start_handler(path, j);
|
||||
if (m->h.array_start_handler && j.isArray()) {
|
||||
m->h.array_start_handler(path, j);
|
||||
size_t i = 0;
|
||||
j.forEachArrayItem([&i, &path, this](JSON v) {
|
||||
this->m->h.array_item_handler->handle(
|
||||
m->h.array_item_handler->handle(
|
||||
path + "[" + std::to_string(i) + "]", v);
|
||||
++i;
|
||||
});
|
||||
this->m->h.array_end_handler(path);
|
||||
m->h.array_end_handler(path);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
|
@ -20,8 +20,8 @@ Pl_Buffer::~Pl_Buffer()
|
||||
void
|
||||
Pl_Buffer::write(unsigned char const* buf, size_t len)
|
||||
{
|
||||
this->m->data.append(buf, len);
|
||||
this->m->ready = false;
|
||||
m->data.append(buf, len);
|
||||
m->ready = false;
|
||||
|
||||
if (getNext(true)) {
|
||||
getNext()->write(buf, len);
|
||||
@ -31,7 +31,7 @@ Pl_Buffer::write(unsigned char const* buf, size_t len)
|
||||
void
|
||||
Pl_Buffer::finish()
|
||||
{
|
||||
this->m->ready = true;
|
||||
m->ready = true;
|
||||
if (getNext(true)) {
|
||||
getNext()->finish();
|
||||
}
|
||||
@ -40,17 +40,17 @@ Pl_Buffer::finish()
|
||||
Buffer*
|
||||
Pl_Buffer::getBuffer()
|
||||
{
|
||||
if (!this->m->ready) {
|
||||
if (!m->ready) {
|
||||
throw std::logic_error("Pl_Buffer::getBuffer() called when not ready");
|
||||
}
|
||||
|
||||
auto size = this->m->data.length();
|
||||
auto size = m->data.length();
|
||||
auto* b = new Buffer(size);
|
||||
if (size > 0) {
|
||||
unsigned char* p = b->getBuffer();
|
||||
memcpy(p, this->m->data.data(), size);
|
||||
memcpy(p, m->data.data(), size);
|
||||
}
|
||||
this->m->data.clear();
|
||||
m->data.clear();
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -63,17 +63,17 @@ Pl_Buffer::getBufferSharedPointer()
|
||||
void
|
||||
Pl_Buffer::getMallocBuffer(unsigned char** buf, size_t* len)
|
||||
{
|
||||
if (!this->m->ready) {
|
||||
if (!m->ready) {
|
||||
throw std::logic_error(
|
||||
"Pl_Buffer::getMallocBuffer() called when not ready");
|
||||
}
|
||||
auto size = this->m->data.length();
|
||||
auto size = m->data.length();
|
||||
*len = size;
|
||||
if (size > 0) {
|
||||
*buf = reinterpret_cast<unsigned char*>(malloc(size));
|
||||
memcpy(*buf, this->m->data.data(), size);
|
||||
memcpy(*buf, m->data.data(), size);
|
||||
} else {
|
||||
*buf = nullptr;
|
||||
}
|
||||
this->m->data.clear();
|
||||
m->data.clear();
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ void
|
||||
Pl_Count::write(unsigned char const* buf, size_t len)
|
||||
{
|
||||
if (len) {
|
||||
this->m->count += QIntC::to_offset(len);
|
||||
this->m->last_char = buf[len - 1];
|
||||
m->count += QIntC::to_offset(len);
|
||||
m->last_char = buf[len - 1];
|
||||
getNext()->write(buf, len);
|
||||
}
|
||||
}
|
||||
@ -39,11 +39,11 @@ Pl_Count::finish()
|
||||
qpdf_offset_t
|
||||
Pl_Count::getCount() const
|
||||
{
|
||||
return this->m->count;
|
||||
return m->count;
|
||||
}
|
||||
|
||||
unsigned char
|
||||
Pl_Count::getLastChar() const
|
||||
{
|
||||
return this->m->last_char;
|
||||
return m->last_char;
|
||||
}
|
||||
|
@ -84,18 +84,18 @@ Pl_DCT::~Pl_DCT()
|
||||
void
|
||||
Pl_DCT::write(unsigned char const* data, size_t len)
|
||||
{
|
||||
this->m->buf.write(data, len);
|
||||
m->buf.write(data, len);
|
||||
}
|
||||
|
||||
void
|
||||
Pl_DCT::finish()
|
||||
{
|
||||
this->m->buf.finish();
|
||||
m->buf.finish();
|
||||
|
||||
// Using a std::shared_ptr<Buffer> here and passing it into compress
|
||||
// and decompress causes a memory leak with setjmp/longjmp. Just
|
||||
// use a pointer and delete it.
|
||||
Buffer* b = this->m->buf.getBuffer();
|
||||
Buffer* b = m->buf.getBuffer();
|
||||
if (b->getSize() == 0) {
|
||||
// Special case: empty data will never succeed and probably
|
||||
// means we're calling finish a second time from an exception
|
||||
@ -118,7 +118,7 @@ Pl_DCT::finish()
|
||||
// for exception handling.
|
||||
if (setjmp(jerr.jmpbuf) == 0) {
|
||||
try {
|
||||
if (this->m->action == a_compress) {
|
||||
if (m->action == a_compress) {
|
||||
compress(reinterpret_cast<void*>(&cinfo_compress), b);
|
||||
} else {
|
||||
decompress(reinterpret_cast<void*>(&cinfo_decompress), b);
|
||||
@ -135,10 +135,10 @@ Pl_DCT::finish()
|
||||
}
|
||||
delete b;
|
||||
|
||||
if (this->m->action == a_compress) {
|
||||
if (m->action == a_compress) {
|
||||
jpeg_destroy_compress(&cinfo_compress);
|
||||
}
|
||||
if (this->m->action == a_decompress) {
|
||||
if (m->action == a_decompress) {
|
||||
jpeg_destroy_decompress(&cinfo_decompress);
|
||||
}
|
||||
if (error) {
|
||||
@ -279,13 +279,13 @@ Pl_DCT::compress(void* cinfo_p, Buffer* b)
|
||||
unsigned char* outbuffer = outbuffer_ph.get();
|
||||
jpeg_pipeline_dest(cinfo, outbuffer, BUF_SIZE, this->getNext());
|
||||
|
||||
cinfo->image_width = this->m->image_width;
|
||||
cinfo->image_height = this->m->image_height;
|
||||
cinfo->input_components = this->m->components;
|
||||
cinfo->in_color_space = this->m->color_space;
|
||||
cinfo->image_width = m->image_width;
|
||||
cinfo->image_height = m->image_height;
|
||||
cinfo->input_components = m->components;
|
||||
cinfo->in_color_space = m->color_space;
|
||||
jpeg_set_defaults(cinfo);
|
||||
if (this->m->config_callback) {
|
||||
this->m->config_callback->apply(cinfo);
|
||||
if (m->config_callback) {
|
||||
m->config_callback->apply(cinfo);
|
||||
}
|
||||
|
||||
jpeg_start_compress(cinfo, TRUE);
|
||||
|
@ -72,21 +72,21 @@ Pl_Flate::~Pl_Flate()
|
||||
void
|
||||
Pl_Flate::setWarnCallback(std::function<void(char const*, int)> callback)
|
||||
{
|
||||
this->m->callback = callback;
|
||||
m->callback = callback;
|
||||
}
|
||||
|
||||
void
|
||||
Pl_Flate::warn(char const* msg, int code)
|
||||
{
|
||||
if (this->m->callback != nullptr) {
|
||||
this->m->callback(msg, code);
|
||||
if (m->callback != nullptr) {
|
||||
m->callback(msg, code);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Pl_Flate::write(unsigned char const* data, size_t len)
|
||||
{
|
||||
if (this->m->outbuf == nullptr) {
|
||||
if (m->outbuf == nullptr) {
|
||||
throw std::logic_error(
|
||||
this->identifier +
|
||||
": Pl_Flate: write() called after finish() called");
|
||||
@ -100,9 +100,7 @@ Pl_Flate::write(unsigned char const* data, size_t len)
|
||||
while (bytes_left > 0) {
|
||||
size_t bytes = (bytes_left >= max_bytes ? max_bytes : bytes_left);
|
||||
handleData(
|
||||
buf,
|
||||
bytes,
|
||||
(this->m->action == a_inflate ? Z_SYNC_FLUSH : Z_NO_FLUSH));
|
||||
buf, bytes, (m->action == a_inflate ? Z_SYNC_FLUSH : Z_NO_FLUSH));
|
||||
bytes_left -= bytes;
|
||||
buf += bytes;
|
||||
}
|
||||
@ -115,13 +113,13 @@ Pl_Flate::handleData(unsigned char const* data, size_t len, int flush)
|
||||
throw std::runtime_error("Pl_Flate: zlib doesn't support data"
|
||||
" blocks larger than int");
|
||||
}
|
||||
z_stream& zstream = *(static_cast<z_stream*>(this->m->zdata));
|
||||
z_stream& zstream = *(static_cast<z_stream*>(m->zdata));
|
||||
// zlib is known not to modify the data pointed to by next_in but
|
||||
// doesn't declare the field value const unless compiled to do so.
|
||||
zstream.next_in = const_cast<unsigned char*>(data);
|
||||
zstream.avail_in = QIntC::to_uint(len);
|
||||
|
||||
if (!this->m->initialized) {
|
||||
if (!m->initialized) {
|
||||
int err = Z_OK;
|
||||
|
||||
// deflateInit and inflateInit are macros that use old-style
|
||||
@ -132,7 +130,7 @@ Pl_Flate::handleData(unsigned char const* data, size_t len, int flush)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#endif
|
||||
if (this->m->action == a_deflate) {
|
||||
if (m->action == a_deflate) {
|
||||
err = deflateInit(&zstream, compression_level);
|
||||
} else {
|
||||
err = inflateInit(&zstream);
|
||||
@ -144,19 +142,19 @@ Pl_Flate::handleData(unsigned char const* data, size_t len, int flush)
|
||||
#endif
|
||||
|
||||
checkError("Init", err);
|
||||
this->m->initialized = true;
|
||||
m->initialized = true;
|
||||
}
|
||||
|
||||
int err = Z_OK;
|
||||
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
if (this->m->action == a_deflate) {
|
||||
if (m->action == a_deflate) {
|
||||
err = deflate(&zstream, flush);
|
||||
} else {
|
||||
err = inflate(&zstream, flush);
|
||||
}
|
||||
if ((this->m->action == a_inflate) && (err != Z_OK) && zstream.msg &&
|
||||
if ((m->action == a_inflate) && (err != Z_OK) && zstream.msg &&
|
||||
(strcmp(zstream.msg, "incorrect data check") == 0)) {
|
||||
// Other PDF readers ignore this specific error. Combining
|
||||
// this with Z_SYNC_FLUSH enables qpdf to handle some
|
||||
@ -191,11 +189,11 @@ Pl_Flate::handleData(unsigned char const* data, size_t len, int flush)
|
||||
done = true;
|
||||
}
|
||||
uLong ready =
|
||||
QIntC::to_ulong(this->m->out_bufsize - zstream.avail_out);
|
||||
QIntC::to_ulong(m->out_bufsize - zstream.avail_out);
|
||||
if (ready > 0) {
|
||||
this->getNext()->write(this->m->outbuf.get(), ready);
|
||||
zstream.next_out = this->m->outbuf.get();
|
||||
zstream.avail_out = QIntC::to_uint(this->m->out_bufsize);
|
||||
this->getNext()->write(m->outbuf.get(), ready);
|
||||
zstream.next_out = m->outbuf.get();
|
||||
zstream.avail_out = QIntC::to_uint(m->out_bufsize);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -211,23 +209,23 @@ void
|
||||
Pl_Flate::finish()
|
||||
{
|
||||
try {
|
||||
if (this->m->outbuf.get()) {
|
||||
if (this->m->initialized) {
|
||||
z_stream& zstream = *(static_cast<z_stream*>(this->m->zdata));
|
||||
if (m->outbuf.get()) {
|
||||
if (m->initialized) {
|
||||
z_stream& zstream = *(static_cast<z_stream*>(m->zdata));
|
||||
unsigned char buf[1];
|
||||
buf[0] = '\0';
|
||||
handleData(buf, 0, Z_FINISH);
|
||||
int err = Z_OK;
|
||||
if (this->m->action == a_deflate) {
|
||||
if (m->action == a_deflate) {
|
||||
err = deflateEnd(&zstream);
|
||||
} else {
|
||||
err = inflateEnd(&zstream);
|
||||
}
|
||||
this->m->initialized = false;
|
||||
m->initialized = false;
|
||||
checkError("End", err);
|
||||
}
|
||||
|
||||
this->m->outbuf = nullptr;
|
||||
m->outbuf = nullptr;
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
try {
|
||||
@ -249,10 +247,10 @@ Pl_Flate::setCompressionLevel(int level)
|
||||
void
|
||||
Pl_Flate::checkError(char const* prefix, int error_code)
|
||||
{
|
||||
z_stream& zstream = *(static_cast<z_stream*>(this->m->zdata));
|
||||
z_stream& zstream = *(static_cast<z_stream*>(m->zdata));
|
||||
if (error_code != Z_OK) {
|
||||
char const* action_str =
|
||||
(this->m->action == a_deflate ? "deflate" : "inflate");
|
||||
(m->action == a_deflate ? "deflate" : "inflate");
|
||||
std::string msg =
|
||||
this->identifier + ": " + action_str + ": " + prefix + ": ";
|
||||
|
||||
|
@ -52,7 +52,7 @@ Pl_Function::~Pl_Function()
|
||||
void
|
||||
Pl_Function::write(unsigned char const* buf, size_t len)
|
||||
{
|
||||
this->m->fn(buf, len);
|
||||
m->fn(buf, len);
|
||||
if (getNext(true)) {
|
||||
getNext()->write(buf, len);
|
||||
}
|
||||
|
@ -22,12 +22,12 @@ Pl_OStream::~Pl_OStream()
|
||||
void
|
||||
Pl_OStream::write(unsigned char const* buf, size_t len)
|
||||
{
|
||||
this->m->os.write(
|
||||
m->os.write(
|
||||
reinterpret_cast<char const*>(buf), static_cast<std::streamsize>(len));
|
||||
}
|
||||
|
||||
void
|
||||
Pl_OStream::finish()
|
||||
{
|
||||
this->m->os.flush();
|
||||
m->os.flush();
|
||||
}
|
||||
|
@ -33,37 +33,36 @@ Pl_QPDFTokenizer::~Pl_QPDFTokenizer()
|
||||
void
|
||||
Pl_QPDFTokenizer::write(unsigned char const* data, size_t len)
|
||||
{
|
||||
this->m->buf.write(data, len);
|
||||
m->buf.write(data, len);
|
||||
}
|
||||
|
||||
void
|
||||
Pl_QPDFTokenizer::finish()
|
||||
{
|
||||
this->m->buf.finish();
|
||||
m->buf.finish();
|
||||
auto input = std::shared_ptr<InputSource>(
|
||||
// line-break
|
||||
new BufferInputSource(
|
||||
"tokenizer data", this->m->buf.getBuffer(), true));
|
||||
new BufferInputSource("tokenizer data", m->buf.getBuffer(), true));
|
||||
|
||||
while (true) {
|
||||
QPDFTokenizer::Token token = this->m->tokenizer.readToken(
|
||||
QPDFTokenizer::Token token = m->tokenizer.readToken(
|
||||
input, "offset " + std::to_string(input->tell()), true);
|
||||
this->m->filter->handleToken(token);
|
||||
m->filter->handleToken(token);
|
||||
if (token.getType() == QPDFTokenizer::tt_eof) {
|
||||
break;
|
||||
} else if (token.isWord("ID")) {
|
||||
// Read the space after the ID.
|
||||
char ch = ' ';
|
||||
input->read(&ch, 1);
|
||||
this->m->filter->handleToken(
|
||||
m->filter->handleToken(
|
||||
// line-break
|
||||
QPDFTokenizer::Token(
|
||||
QPDFTokenizer::tt_space, std::string(1, ch)));
|
||||
QTC::TC("qpdf", "Pl_QPDFTokenizer found ID");
|
||||
this->m->tokenizer.expectInlineImage(input);
|
||||
m->tokenizer.expectInlineImage(input);
|
||||
}
|
||||
}
|
||||
this->m->filter->handleEOF();
|
||||
m->filter->handleEOF();
|
||||
QPDFObjectHandle::TokenFilter::PipelineAccessor::setPipeline(
|
||||
m->filter, nullptr);
|
||||
Pipeline* next = this->getNext(true);
|
||||
|
@ -26,7 +26,7 @@ Pl_RunLength::~Pl_RunLength()
|
||||
void
|
||||
Pl_RunLength::write(unsigned char const* data, size_t len)
|
||||
{
|
||||
if (this->m->action == a_encode) {
|
||||
if (m->action == a_encode) {
|
||||
encode(data, len);
|
||||
} else {
|
||||
decode(data, len);
|
||||
@ -37,35 +37,35 @@ void
|
||||
Pl_RunLength::encode(unsigned char const* data, size_t len)
|
||||
{
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
if ((this->m->state == st_top) != (this->m->length <= 1)) {
|
||||
if ((m->state == st_top) != (m->length <= 1)) {
|
||||
throw std::logic_error(
|
||||
"Pl_RunLength::encode: state/length inconsistency");
|
||||
}
|
||||
unsigned char ch = data[i];
|
||||
if ((this->m->length > 0) &&
|
||||
((this->m->state == st_copying) || (this->m->length < 128)) &&
|
||||
(ch == this->m->buf[this->m->length - 1])) {
|
||||
if ((m->length > 0) &&
|
||||
((m->state == st_copying) || (m->length < 128)) &&
|
||||
(ch == m->buf[m->length - 1])) {
|
||||
QTC::TC(
|
||||
"libtests",
|
||||
"Pl_RunLength: switch to run",
|
||||
(this->m->length == 128) ? 0 : 1);
|
||||
if (this->m->state == st_copying) {
|
||||
--this->m->length;
|
||||
(m->length == 128) ? 0 : 1);
|
||||
if (m->state == st_copying) {
|
||||
--m->length;
|
||||
flush_encode();
|
||||
this->m->buf[0] = ch;
|
||||
this->m->length = 1;
|
||||
m->buf[0] = ch;
|
||||
m->length = 1;
|
||||
}
|
||||
this->m->state = st_run;
|
||||
this->m->buf[this->m->length] = ch;
|
||||
++this->m->length;
|
||||
m->state = st_run;
|
||||
m->buf[m->length] = ch;
|
||||
++m->length;
|
||||
} else {
|
||||
if ((this->m->length == 128) || (this->m->state == st_run)) {
|
||||
if ((m->length == 128) || (m->state == st_run)) {
|
||||
flush_encode();
|
||||
} else if (this->m->length > 0) {
|
||||
this->m->state = st_copying;
|
||||
} else if (m->length > 0) {
|
||||
m->state = st_copying;
|
||||
}
|
||||
this->m->buf[this->m->length] = ch;
|
||||
++this->m->length;
|
||||
m->buf[m->length] = ch;
|
||||
++m->length;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -75,16 +75,16 @@ Pl_RunLength::decode(unsigned char const* data, size_t len)
|
||||
{
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
unsigned char ch = data[i];
|
||||
switch (this->m->state) {
|
||||
switch (m->state) {
|
||||
case st_top:
|
||||
if (ch < 128) {
|
||||
// length represents remaining number of bytes to copy
|
||||
this->m->length = 1U + ch;
|
||||
this->m->state = st_copying;
|
||||
m->length = 1U + ch;
|
||||
m->state = st_copying;
|
||||
} else if (ch > 128) {
|
||||
// length represents number of copies of next byte
|
||||
this->m->length = 257U - ch;
|
||||
this->m->state = st_run;
|
||||
m->length = 257U - ch;
|
||||
m->state = st_run;
|
||||
} else // ch == 128
|
||||
{
|
||||
// EOD; stay in this state
|
||||
@ -93,16 +93,16 @@ Pl_RunLength::decode(unsigned char const* data, size_t len)
|
||||
|
||||
case st_copying:
|
||||
this->getNext()->write(&ch, 1);
|
||||
if (--this->m->length == 0) {
|
||||
this->m->state = st_top;
|
||||
if (--m->length == 0) {
|
||||
m->state = st_top;
|
||||
}
|
||||
break;
|
||||
|
||||
case st_run:
|
||||
for (unsigned int j = 0; j < this->m->length; ++j) {
|
||||
for (unsigned int j = 0; j < m->length; ++j) {
|
||||
this->getNext()->write(&ch, 1);
|
||||
}
|
||||
this->m->state = st_top;
|
||||
m->state = st_top;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -111,32 +111,32 @@ Pl_RunLength::decode(unsigned char const* data, size_t len)
|
||||
void
|
||||
Pl_RunLength::flush_encode()
|
||||
{
|
||||
if (this->m->length == 128) {
|
||||
if (m->length == 128) {
|
||||
QTC::TC(
|
||||
"libtests",
|
||||
"Pl_RunLength flush full buffer",
|
||||
(this->m->state == st_copying ? 0
|
||||
: this->m->state == st_run ? 1
|
||||
: -1));
|
||||
(m->state == st_copying ? 0
|
||||
: m->state == st_run ? 1
|
||||
: -1));
|
||||
}
|
||||
if (this->m->length == 0) {
|
||||
if (m->length == 0) {
|
||||
QTC::TC("libtests", "Pl_RunLength flush empty buffer");
|
||||
}
|
||||
if (this->m->state == st_run) {
|
||||
if ((this->m->length < 2) || (this->m->length > 128)) {
|
||||
if (m->state == st_run) {
|
||||
if ((m->length < 2) || (m->length > 128)) {
|
||||
throw std::logic_error(
|
||||
"Pl_RunLength: invalid length in flush_encode for run");
|
||||
}
|
||||
auto ch = static_cast<unsigned char>(257 - this->m->length);
|
||||
auto ch = static_cast<unsigned char>(257 - m->length);
|
||||
this->getNext()->write(&ch, 1);
|
||||
this->getNext()->write(&this->m->buf[0], 1);
|
||||
} else if (this->m->length > 0) {
|
||||
auto ch = static_cast<unsigned char>(this->m->length - 1);
|
||||
this->getNext()->write(&m->buf[0], 1);
|
||||
} else if (m->length > 0) {
|
||||
auto ch = static_cast<unsigned char>(m->length - 1);
|
||||
this->getNext()->write(&ch, 1);
|
||||
this->getNext()->write(this->m->buf, this->m->length);
|
||||
this->getNext()->write(m->buf, m->length);
|
||||
}
|
||||
this->m->state = st_top;
|
||||
this->m->length = 0;
|
||||
m->state = st_top;
|
||||
m->length = 0;
|
||||
}
|
||||
|
||||
void
|
||||
@ -146,7 +146,7 @@ Pl_RunLength::finish()
|
||||
// data, which means the stream was terminated early, but we will
|
||||
// just ignore this case since this is the only sensible thing to
|
||||
// do.
|
||||
if (this->m->action == a_encode) {
|
||||
if (m->action == a_encode) {
|
||||
flush_encode();
|
||||
unsigned char ch = 128;
|
||||
this->getNext()->write(&ch, 1);
|
||||
|
@ -28,7 +28,7 @@ Pl_StdioFile::write(unsigned char const* buf, size_t len)
|
||||
{
|
||||
size_t so_far = 0;
|
||||
while (len > 0) {
|
||||
so_far = fwrite(buf, 1, len, this->m->file);
|
||||
so_far = fwrite(buf, 1, len, m->file);
|
||||
if (so_far == 0) {
|
||||
QUtil::throw_system_error(
|
||||
this->identifier + ": Pl_StdioFile::write");
|
||||
@ -42,7 +42,7 @@ Pl_StdioFile::write(unsigned char const* buf, size_t len)
|
||||
void
|
||||
Pl_StdioFile::finish()
|
||||
{
|
||||
if ((fflush(this->m->file) == -1) && (errno == EBADF)) {
|
||||
if ((fflush(m->file) == -1) && (errno == EBADF)) {
|
||||
throw std::logic_error(
|
||||
this->identifier + ": Pl_StdioFile::finish: stream already closed");
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ Pl_String::~Pl_String()
|
||||
void
|
||||
Pl_String::write(unsigned char const* buf, size_t len)
|
||||
{
|
||||
this->m->s.append(reinterpret_cast<char const*>(buf), len);
|
||||
m->s.append(reinterpret_cast<char const*>(buf), len);
|
||||
if (getNext(true)) {
|
||||
getNext()->write(buf, len);
|
||||
}
|
||||
|
333
libqpdf/QPDF.cc
333
libqpdf/QPDF.cc
@ -246,8 +246,8 @@ QPDF::~QPDF()
|
||||
// At this point, obviously no one is still using the QPDF object,
|
||||
// but we'll explicitly clear the xref table anyway just to
|
||||
// prevent any possibility of resolve() succeeding.
|
||||
this->m->xref_table.clear();
|
||||
for (auto const& iter: this->m->obj_cache) {
|
||||
m->xref_table.clear();
|
||||
for (auto const& iter: m->obj_cache) {
|
||||
iter.second.object->disconnect();
|
||||
if (iter.second.object->getTypeCode() != ::ot_null) {
|
||||
iter.second.object->destroy();
|
||||
@ -297,20 +297,20 @@ void
|
||||
QPDF::processInputSource(
|
||||
std::shared_ptr<InputSource> source, char const* password)
|
||||
{
|
||||
this->m->file = source;
|
||||
m->file = source;
|
||||
parse(password);
|
||||
}
|
||||
|
||||
void
|
||||
QPDF::closeInputSource()
|
||||
{
|
||||
this->m->file = std::shared_ptr<InputSource>(new InvalidInputSource());
|
||||
m->file = std::shared_ptr<InputSource>(new InvalidInputSource());
|
||||
}
|
||||
|
||||
void
|
||||
QPDF::setPasswordIsHexKey(bool val)
|
||||
{
|
||||
this->m->provided_password_is_hex_key = val;
|
||||
m->provided_password_is_hex_key = val;
|
||||
}
|
||||
|
||||
void
|
||||
@ -330,64 +330,64 @@ QPDF::registerStreamFilter(
|
||||
void
|
||||
QPDF::setIgnoreXRefStreams(bool val)
|
||||
{
|
||||
this->m->ignore_xref_streams = val;
|
||||
m->ignore_xref_streams = val;
|
||||
}
|
||||
|
||||
std::shared_ptr<QPDFLogger>
|
||||
QPDF::getLogger()
|
||||
{
|
||||
return this->m->log;
|
||||
return m->log;
|
||||
}
|
||||
|
||||
void
|
||||
QPDF::setLogger(std::shared_ptr<QPDFLogger> l)
|
||||
{
|
||||
this->m->log = l;
|
||||
m->log = l;
|
||||
}
|
||||
|
||||
void
|
||||
QPDF::setOutputStreams(std::ostream* out, std::ostream* err)
|
||||
{
|
||||
setLogger(QPDFLogger::create());
|
||||
this->m->log->setOutputStreams(out, err);
|
||||
m->log->setOutputStreams(out, err);
|
||||
}
|
||||
|
||||
void
|
||||
QPDF::setSuppressWarnings(bool val)
|
||||
{
|
||||
this->m->suppress_warnings = val;
|
||||
m->suppress_warnings = val;
|
||||
}
|
||||
|
||||
void
|
||||
QPDF::setAttemptRecovery(bool val)
|
||||
{
|
||||
this->m->attempt_recovery = val;
|
||||
m->attempt_recovery = val;
|
||||
}
|
||||
|
||||
void
|
||||
QPDF::setImmediateCopyFrom(bool val)
|
||||
{
|
||||
this->m->immediate_copy_from = val;
|
||||
m->immediate_copy_from = val;
|
||||
}
|
||||
|
||||
std::vector<QPDFExc>
|
||||
QPDF::getWarnings()
|
||||
{
|
||||
std::vector<QPDFExc> result = this->m->warnings;
|
||||
this->m->warnings.clear();
|
||||
std::vector<QPDFExc> result = m->warnings;
|
||||
m->warnings.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
QPDF::anyWarnings() const
|
||||
{
|
||||
return !this->m->warnings.empty();
|
||||
return !m->warnings.empty();
|
||||
}
|
||||
|
||||
size_t
|
||||
QPDF::numWarnings() const
|
||||
{
|
||||
return this->m->warnings.size();
|
||||
return m->warnings.size();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -413,8 +413,8 @@ QPDF::validatePDFVersion(char const*& p, std::string& version)
|
||||
bool
|
||||
QPDF::findHeader()
|
||||
{
|
||||
qpdf_offset_t global_offset = this->m->file->tell();
|
||||
std::string line = this->m->file->readLine(1024);
|
||||
qpdf_offset_t global_offset = m->file->tell();
|
||||
std::string line = m->file->readLine(1024);
|
||||
char const* p = line.c_str();
|
||||
if (strncmp(p, "%PDF-", 5) != 0) {
|
||||
throw std::logic_error("findHeader is not looking at %PDF-");
|
||||
@ -427,15 +427,15 @@ QPDF::findHeader()
|
||||
// advancement.
|
||||
bool valid = validatePDFVersion(p, version);
|
||||
if (valid) {
|
||||
this->m->pdf_version = version;
|
||||
m->pdf_version = version;
|
||||
if (global_offset != 0) {
|
||||
// Empirical evidence strongly suggests that when there is
|
||||
// leading material prior to the PDF header, all explicit
|
||||
// offsets in the file are such that 0 points to the
|
||||
// beginning of the header.
|
||||
QTC::TC("qpdf", "QPDF global offset");
|
||||
this->m->file = std::shared_ptr<InputSource>(
|
||||
new OffsetInputSource(this->m->file, global_offset));
|
||||
m->file = std::shared_ptr<InputSource>(
|
||||
new OffsetInputSource(m->file, global_offset));
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
@ -447,7 +447,7 @@ QPDF::findStartxref()
|
||||
if (readToken(m->file).isWord("startxref") &&
|
||||
readToken(m->file).isInteger()) {
|
||||
// Position in front of offset token
|
||||
this->m->file->seek(this->m->file->getLastOffset(), SEEK_SET);
|
||||
m->file->seek(m->file->getLastOffset(), SEEK_SET);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -457,30 +457,30 @@ void
|
||||
QPDF::parse(char const* password)
|
||||
{
|
||||
if (password) {
|
||||
this->m->encp->provided_password = password;
|
||||
m->encp->provided_password = password;
|
||||
}
|
||||
|
||||
// Find the header anywhere in the first 1024 bytes of the file.
|
||||
PatternFinder hf(*this, &QPDF::findHeader);
|
||||
if (!this->m->file->findFirst("%PDF-", 0, 1024, hf)) {
|
||||
if (!m->file->findFirst("%PDF-", 0, 1024, hf)) {
|
||||
QTC::TC("qpdf", "QPDF not a pdf file");
|
||||
warn(damagedPDF("", 0, "can't find PDF header"));
|
||||
// QPDFWriter writes files that usually require at least
|
||||
// version 1.2 for /FlateDecode
|
||||
this->m->pdf_version = "1.2";
|
||||
m->pdf_version = "1.2";
|
||||
}
|
||||
|
||||
// PDF spec says %%EOF must be found within the last 1024 bytes of
|
||||
// the file. We add an extra 30 characters to leave room for the
|
||||
// startxref stuff.
|
||||
this->m->file->seek(0, SEEK_END);
|
||||
qpdf_offset_t end_offset = this->m->file->tell();
|
||||
m->file->seek(0, SEEK_END);
|
||||
qpdf_offset_t end_offset = m->file->tell();
|
||||
qpdf_offset_t start_offset = (end_offset > 1054 ? end_offset - 1054 : 0);
|
||||
PatternFinder sf(*this, &QPDF::findStartxref);
|
||||
qpdf_offset_t xref_offset = 0;
|
||||
if (this->m->file->findLast("startxref", start_offset, 0, sf)) {
|
||||
if (m->file->findLast("startxref", start_offset, 0, sf)) {
|
||||
xref_offset =
|
||||
QUtil::string_to_ll(readToken(this->m->file).getValue().c_str());
|
||||
QUtil::string_to_ll(readToken(m->file).getValue().c_str());
|
||||
}
|
||||
|
||||
try {
|
||||
@ -497,7 +497,7 @@ QPDF::parse(char const* password)
|
||||
"", 0, std::string("error reading xref: ") + e.what());
|
||||
}
|
||||
} catch (QPDFExc& e) {
|
||||
if (this->m->attempt_recovery) {
|
||||
if (m->attempt_recovery) {
|
||||
reconstruct_xref(e);
|
||||
QTC::TC("qpdf", "QPDF reconstructed xref table");
|
||||
} else {
|
||||
@ -506,29 +506,28 @@ QPDF::parse(char const* password)
|
||||
}
|
||||
|
||||
initializeEncryption();
|
||||
this->m->parsed = true;
|
||||
m->parsed = true;
|
||||
}
|
||||
|
||||
void
|
||||
QPDF::inParse(bool v)
|
||||
{
|
||||
if (this->m->in_parse == v) {
|
||||
if (m->in_parse == v) {
|
||||
// This happens if QPDFParser::parse tries to
|
||||
// resolve an indirect object while it is parsing.
|
||||
throw std::logic_error(
|
||||
"QPDF: re-entrant parsing detected. This is a qpdf bug."
|
||||
" Please report at https://github.com/qpdf/qpdf/issues.");
|
||||
}
|
||||
this->m->in_parse = v;
|
||||
m->in_parse = v;
|
||||
}
|
||||
|
||||
void
|
||||
QPDF::warn(QPDFExc const& e)
|
||||
{
|
||||
this->m->warnings.push_back(e);
|
||||
if (!this->m->suppress_warnings) {
|
||||
*this->m->log->getWarn()
|
||||
<< "WARNING: " << this->m->warnings.back().what() << "\n";
|
||||
m->warnings.push_back(e);
|
||||
if (!m->suppress_warnings) {
|
||||
*m->log->getWarn() << "WARNING: " << m->warnings.back().what() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@ -545,25 +544,25 @@ QPDF::warn(
|
||||
void
|
||||
QPDF::setTrailer(QPDFObjectHandle obj)
|
||||
{
|
||||
if (this->m->trailer.isInitialized()) {
|
||||
if (m->trailer.isInitialized()) {
|
||||
return;
|
||||
}
|
||||
this->m->trailer = obj;
|
||||
m->trailer = obj;
|
||||
}
|
||||
|
||||
void
|
||||
QPDF::reconstruct_xref(QPDFExc& e)
|
||||
{
|
||||
if (this->m->reconstructed_xref) {
|
||||
if (m->reconstructed_xref) {
|
||||
// Avoid xref reconstruction infinite loops. This is getting
|
||||
// very hard to reproduce because qpdf is throwing many fewer
|
||||
// exceptions while parsing. Most situations are warnings now.
|
||||
throw e;
|
||||
}
|
||||
|
||||
this->m->reconstructed_xref = true;
|
||||
m->reconstructed_xref = true;
|
||||
// We may find more objects, which may contain dangling references.
|
||||
this->m->fixed_dangling_refs = false;
|
||||
m->fixed_dangling_refs = false;
|
||||
|
||||
warn(damagedPDF("", 0, "file is damaged"));
|
||||
warn(e);
|
||||
@ -571,53 +570,53 @@ QPDF::reconstruct_xref(QPDFExc& e)
|
||||
|
||||
// Delete all references to type 1 (uncompressed) objects
|
||||
std::set<QPDFObjGen> to_delete;
|
||||
for (auto const& iter: this->m->xref_table) {
|
||||
for (auto const& iter: m->xref_table) {
|
||||
if (iter.second.getType() == 1) {
|
||||
to_delete.insert(iter.first);
|
||||
}
|
||||
}
|
||||
for (auto const& iter: to_delete) {
|
||||
this->m->xref_table.erase(iter);
|
||||
m->xref_table.erase(iter);
|
||||
}
|
||||
|
||||
this->m->file->seek(0, SEEK_END);
|
||||
qpdf_offset_t eof = this->m->file->tell();
|
||||
this->m->file->seek(0, SEEK_SET);
|
||||
m->file->seek(0, SEEK_END);
|
||||
qpdf_offset_t eof = m->file->tell();
|
||||
m->file->seek(0, SEEK_SET);
|
||||
qpdf_offset_t line_start = 0;
|
||||
// Don't allow very long tokens here during recovery.
|
||||
static size_t const MAX_LEN = 100;
|
||||
while (this->m->file->tell() < eof) {
|
||||
this->m->file->findAndSkipNextEOL();
|
||||
qpdf_offset_t next_line_start = this->m->file->tell();
|
||||
this->m->file->seek(line_start, SEEK_SET);
|
||||
QPDFTokenizer::Token t1 = readToken(this->m->file, MAX_LEN);
|
||||
while (m->file->tell() < eof) {
|
||||
m->file->findAndSkipNextEOL();
|
||||
qpdf_offset_t next_line_start = m->file->tell();
|
||||
m->file->seek(line_start, SEEK_SET);
|
||||
QPDFTokenizer::Token t1 = readToken(m->file, MAX_LEN);
|
||||
qpdf_offset_t token_start =
|
||||
this->m->file->tell() - toO(t1.getValue().length());
|
||||
m->file->tell() - toO(t1.getValue().length());
|
||||
if (token_start >= next_line_start) {
|
||||
// don't process yet -- wait until we get to the line
|
||||
// containing this token
|
||||
} else if (t1.isInteger()) {
|
||||
QPDFTokenizer::Token t2 = readToken(this->m->file, MAX_LEN);
|
||||
QPDFTokenizer::Token t2 = readToken(m->file, MAX_LEN);
|
||||
if ((t2.isInteger()) &&
|
||||
(readToken(m->file, MAX_LEN).isWord("obj"))) {
|
||||
int obj = QUtil::string_to_int(t1.getValue().c_str());
|
||||
int gen = QUtil::string_to_int(t2.getValue().c_str());
|
||||
insertXrefEntry(obj, 1, token_start, gen, true);
|
||||
}
|
||||
} else if (!this->m->trailer.isInitialized() && t1.isWord("trailer")) {
|
||||
} else if (!m->trailer.isInitialized() && t1.isWord("trailer")) {
|
||||
QPDFObjectHandle t =
|
||||
readObject(this->m->file, "trailer", QPDFObjGen(), false);
|
||||
readObject(m->file, "trailer", QPDFObjGen(), false);
|
||||
if (!t.isDictionary()) {
|
||||
// Oh well. It was worth a try.
|
||||
} else {
|
||||
setTrailer(t);
|
||||
}
|
||||
}
|
||||
this->m->file->seek(next_line_start, SEEK_SET);
|
||||
m->file->seek(next_line_start, SEEK_SET);
|
||||
line_start = next_line_start;
|
||||
}
|
||||
|
||||
if (!this->m->trailer.isInitialized()) {
|
||||
if (!m->trailer.isInitialized()) {
|
||||
// We could check the last encountered object to see if it was
|
||||
// an xref stream. If so, we could try to get the trailer
|
||||
// from there. This may make it possible to recover files
|
||||
@ -648,7 +647,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset)
|
||||
visited.insert(xref_offset);
|
||||
char buf[7];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
this->m->file->seek(xref_offset, SEEK_SET);
|
||||
m->file->seek(xref_offset, SEEK_SET);
|
||||
// Some files miss the mark a little with startxref. We could
|
||||
// do a better job of searching in the neighborhood for
|
||||
// something that looks like either an xref table or stream,
|
||||
@ -659,11 +658,11 @@ QPDF::read_xref(qpdf_offset_t xref_offset)
|
||||
bool skipped_space = false;
|
||||
while (!done) {
|
||||
char ch;
|
||||
if (1 == this->m->file->read(&ch, 1)) {
|
||||
if (1 == m->file->read(&ch, 1)) {
|
||||
if (QUtil::is_space(ch)) {
|
||||
skipped_space = true;
|
||||
} else {
|
||||
this->m->file->unreadCh(ch);
|
||||
m->file->unreadCh(ch);
|
||||
done = true;
|
||||
}
|
||||
} else {
|
||||
@ -675,7 +674,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset)
|
||||
}
|
||||
}
|
||||
|
||||
this->m->file->read(buf, sizeof(buf) - 1);
|
||||
m->file->read(buf, sizeof(buf) - 1);
|
||||
// The PDF spec says xref must be followed by a line
|
||||
// terminator, but files exist in the wild where it is
|
||||
// terminated by arbitrary whitespace.
|
||||
@ -708,16 +707,16 @@ QPDF::read_xref(qpdf_offset_t xref_offset)
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->m->trailer.isInitialized()) {
|
||||
if (!m->trailer.isInitialized()) {
|
||||
throw damagedPDF("", 0, "unable to find trailer while reading xref");
|
||||
}
|
||||
int size = this->m->trailer.getKey("/Size").getIntValueAsInt();
|
||||
int size = m->trailer.getKey("/Size").getIntValueAsInt();
|
||||
int max_obj = 0;
|
||||
if (!this->m->xref_table.empty()) {
|
||||
max_obj = (*(this->m->xref_table.rbegin())).first.getObj();
|
||||
if (!m->xref_table.empty()) {
|
||||
max_obj = (*(m->xref_table.rbegin())).first.getObj();
|
||||
}
|
||||
if (!this->m->deleted_objects.empty()) {
|
||||
max_obj = std::max(max_obj, *(this->m->deleted_objects.rbegin()));
|
||||
if (!m->deleted_objects.empty()) {
|
||||
max_obj = std::max(max_obj, *(m->deleted_objects.rbegin()));
|
||||
}
|
||||
if ((size < 1) || (size - 1 != max_obj)) {
|
||||
QTC::TC("qpdf", "QPDF xref size mismatch");
|
||||
@ -731,7 +730,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset)
|
||||
|
||||
// We no longer need the deleted_objects table, so go ahead and
|
||||
// clear it out to make sure we never depend on its being set.
|
||||
this->m->deleted_objects.clear();
|
||||
m->deleted_objects.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -864,12 +863,12 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset)
|
||||
{
|
||||
std::vector<QPDFObjGen> deleted_items;
|
||||
|
||||
this->m->file->seek(xref_offset, SEEK_SET);
|
||||
m->file->seek(xref_offset, SEEK_SET);
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
char linebuf[51];
|
||||
memset(linebuf, 0, sizeof(linebuf));
|
||||
this->m->file->read(linebuf, sizeof(linebuf) - 1);
|
||||
m->file->read(linebuf, sizeof(linebuf) - 1);
|
||||
std::string line = linebuf;
|
||||
int obj = 0;
|
||||
int num = 0;
|
||||
@ -878,13 +877,13 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset)
|
||||
QTC::TC("qpdf", "QPDF invalid xref");
|
||||
throw damagedPDF("xref table", "xref syntax invalid");
|
||||
}
|
||||
this->m->file->seek(this->m->file->getLastOffset() + bytes, SEEK_SET);
|
||||
m->file->seek(m->file->getLastOffset() + bytes, SEEK_SET);
|
||||
for (qpdf_offset_t i = obj; i - num < obj; ++i) {
|
||||
if (i == 0) {
|
||||
// This is needed by checkLinearization()
|
||||
this->m->first_xref_item_offset = this->m->file->tell();
|
||||
m->first_xref_item_offset = m->file->tell();
|
||||
}
|
||||
std::string xref_entry = this->m->file->readLine(30);
|
||||
std::string xref_entry = m->file->readLine(30);
|
||||
// For xref_table, these will always be small enough to be ints
|
||||
qpdf_offset_t f1 = 0;
|
||||
int f2 = 0;
|
||||
@ -903,30 +902,30 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset)
|
||||
insertXrefEntry(toI(i), 1, f1, f2);
|
||||
}
|
||||
}
|
||||
qpdf_offset_t pos = this->m->file->tell();
|
||||
qpdf_offset_t pos = m->file->tell();
|
||||
if (readToken(m->file).isWord("trailer")) {
|
||||
done = true;
|
||||
} else {
|
||||
this->m->file->seek(pos, SEEK_SET);
|
||||
m->file->seek(pos, SEEK_SET);
|
||||
}
|
||||
}
|
||||
|
||||
// Set offset to previous xref table if any
|
||||
QPDFObjectHandle cur_trailer =
|
||||
readObject(this->m->file, "trailer", QPDFObjGen(), false);
|
||||
readObject(m->file, "trailer", QPDFObjGen(), false);
|
||||
if (!cur_trailer.isDictionary()) {
|
||||
QTC::TC("qpdf", "QPDF missing trailer");
|
||||
throw damagedPDF("", "expected trailer dictionary");
|
||||
}
|
||||
|
||||
if (!this->m->trailer.isInitialized()) {
|
||||
if (!m->trailer.isInitialized()) {
|
||||
setTrailer(cur_trailer);
|
||||
|
||||
if (!this->m->trailer.hasKey("/Size")) {
|
||||
if (!m->trailer.hasKey("/Size")) {
|
||||
QTC::TC("qpdf", "QPDF trailer lacks size");
|
||||
throw damagedPDF("trailer", "trailer dictionary lacks /Size key");
|
||||
}
|
||||
if (!this->m->trailer.getKey("/Size").isInteger()) {
|
||||
if (!m->trailer.getKey("/Size").isInteger()) {
|
||||
QTC::TC("qpdf", "QPDF trailer size not integer");
|
||||
throw damagedPDF(
|
||||
"trailer", "/Size key in trailer dictionary is not an integer");
|
||||
@ -934,7 +933,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset)
|
||||
}
|
||||
|
||||
if (cur_trailer.hasKey("/XRefStm")) {
|
||||
if (this->m->ignore_xref_streams) {
|
||||
if (m->ignore_xref_streams) {
|
||||
QTC::TC("qpdf", "QPDF ignoring XRefStm in trailer");
|
||||
} else {
|
||||
if (cur_trailer.getKey("/XRefStm").isInteger()) {
|
||||
@ -974,7 +973,7 @@ qpdf_offset_t
|
||||
QPDF::read_xrefStream(qpdf_offset_t xref_offset)
|
||||
{
|
||||
bool found = false;
|
||||
if (!this->m->ignore_xref_streams) {
|
||||
if (!m->ignore_xref_streams) {
|
||||
QPDFObjGen x_og;
|
||||
QPDFObjectHandle xref_obj;
|
||||
try {
|
||||
@ -1156,14 +1155,14 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj)
|
||||
|
||||
if (saw_first_compressed_object) {
|
||||
if (fields[0] != 2) {
|
||||
this->m->uncompressed_after_compressed = true;
|
||||
m->uncompressed_after_compressed = true;
|
||||
}
|
||||
} else if (fields[0] == 2) {
|
||||
saw_first_compressed_object = true;
|
||||
}
|
||||
if (obj == 0) {
|
||||
// This is needed by checkLinearization()
|
||||
this->m->first_xref_item_offset = xref_offset;
|
||||
m->first_xref_item_offset = xref_offset;
|
||||
}
|
||||
if (fields[0] == 0) {
|
||||
// Ignore fields[2], which we don't care about in this
|
||||
@ -1175,7 +1174,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj)
|
||||
insertXrefEntry(obj, toI(fields[0]), fields[1], toI(fields[2]));
|
||||
}
|
||||
|
||||
if (!this->m->trailer.isInitialized()) {
|
||||
if (!m->trailer.isInitialized()) {
|
||||
setTrailer(dict);
|
||||
}
|
||||
|
||||
@ -1211,16 +1210,16 @@ QPDF::insertXrefEntry(int obj, int f0, qpdf_offset_t f1, int f2, bool overwrite)
|
||||
{ // private scope
|
||||
int gen = (f0 == 2 ? 0 : f2);
|
||||
QPDFObjGen og(obj, gen);
|
||||
if (this->m->xref_table.count(og)) {
|
||||
if (m->xref_table.count(og)) {
|
||||
if (overwrite) {
|
||||
QTC::TC("qpdf", "QPDF xref overwrite object");
|
||||
this->m->xref_table.erase(og);
|
||||
m->xref_table.erase(og);
|
||||
} else {
|
||||
QTC::TC("qpdf", "QPDF xref reused object");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this->m->deleted_objects.count(obj)) {
|
||||
if (m->deleted_objects.count(obj)) {
|
||||
QTC::TC("qpdf", "QPDF xref deleted object");
|
||||
return;
|
||||
}
|
||||
@ -1228,17 +1227,17 @@ QPDF::insertXrefEntry(int obj, int f0, qpdf_offset_t f1, int f2, bool overwrite)
|
||||
|
||||
switch (f0) {
|
||||
case 0:
|
||||
this->m->deleted_objects.insert(obj);
|
||||
m->deleted_objects.insert(obj);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// f2 is generation
|
||||
QTC::TC("qpdf", "QPDF xref gen > 0", ((f2 > 0) ? 1 : 0));
|
||||
this->m->xref_table[QPDFObjGen(obj, f2)] = QPDFXRefEntry(f1);
|
||||
m->xref_table[QPDFObjGen(obj, f2)] = QPDFXRefEntry(f1);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
this->m->xref_table[QPDFObjGen(obj, 0)] = QPDFXRefEntry(toI(f1), f2);
|
||||
m->xref_table[QPDFObjGen(obj, 0)] = QPDFXRefEntry(toI(f1), f2);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1252,8 +1251,8 @@ QPDF::insertXrefEntry(int obj, int f0, qpdf_offset_t f1, int f2, bool overwrite)
|
||||
void
|
||||
QPDF::showXRefTable()
|
||||
{
|
||||
auto& cout = *this->m->log->getInfo();
|
||||
for (auto const& iter: this->m->xref_table) {
|
||||
auto& cout = *m->log->getInfo();
|
||||
for (auto const& iter: m->xref_table) {
|
||||
QPDFObjGen const& og = iter.first;
|
||||
QPDFXRefEntry const& entry = iter.second;
|
||||
cout << og.unparse('/') << ": ";
|
||||
@ -1263,7 +1262,7 @@ QPDF::showXRefTable()
|
||||
break;
|
||||
|
||||
case 2:
|
||||
*this->m->log->getInfo()
|
||||
*m->log->getInfo()
|
||||
<< "compressed; stream = " << entry.getObjStreamNumber()
|
||||
<< ", index = " << entry.getObjStreamIndex();
|
||||
break;
|
||||
@ -1273,7 +1272,7 @@ QPDF::showXRefTable()
|
||||
" showing xref_table");
|
||||
break;
|
||||
}
|
||||
this->m->log->info("\n");
|
||||
m->log->info("\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1282,11 +1281,11 @@ QPDF::showXRefTable()
|
||||
bool
|
||||
QPDF::resolveXRefTable()
|
||||
{
|
||||
bool may_change = !this->m->reconstructed_xref;
|
||||
for (auto& iter: this->m->xref_table) {
|
||||
bool may_change = !m->reconstructed_xref;
|
||||
for (auto& iter: m->xref_table) {
|
||||
if (isUnresolved(iter.first)) {
|
||||
resolve(iter.first);
|
||||
if (may_change && this->m->reconstructed_xref) {
|
||||
if (may_change && m->reconstructed_xref) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1299,14 +1298,14 @@ QPDF::resolveXRefTable()
|
||||
void
|
||||
QPDF::fixDanglingReferences(bool force)
|
||||
{
|
||||
if (this->m->fixed_dangling_refs) {
|
||||
if (m->fixed_dangling_refs) {
|
||||
return;
|
||||
}
|
||||
if (!resolveXRefTable()) {
|
||||
QTC::TC("qpdf", "QPDF fix dangling triggered xref reconstruction");
|
||||
resolveXRefTable();
|
||||
}
|
||||
this->m->fixed_dangling_refs = true;
|
||||
m->fixed_dangling_refs = true;
|
||||
}
|
||||
|
||||
size_t
|
||||
@ -1318,8 +1317,8 @@ QPDF::getObjectCount()
|
||||
// will also be in obj_cache.
|
||||
fixDanglingReferences();
|
||||
QPDFObjGen og;
|
||||
if (!this->m->obj_cache.empty()) {
|
||||
og = (*(this->m->obj_cache.rbegin())).first;
|
||||
if (!m->obj_cache.empty()) {
|
||||
og = (*(m->obj_cache.rbegin())).first;
|
||||
}
|
||||
return toS(og.getObj());
|
||||
}
|
||||
@ -1331,7 +1330,7 @@ QPDF::getAllObjects()
|
||||
// object cache.
|
||||
fixDanglingReferences();
|
||||
std::vector<QPDFObjectHandle> result;
|
||||
for (auto const& iter: this->m->obj_cache) {
|
||||
for (auto const& iter: m->obj_cache) {
|
||||
result.push_back(newIndirect(iter.first, iter.second.object));
|
||||
}
|
||||
return result;
|
||||
@ -1341,15 +1340,15 @@ void
|
||||
QPDF::setLastObjectDescription(
|
||||
std::string const& description, QPDFObjGen const& og)
|
||||
{
|
||||
this->m->last_object_description.clear();
|
||||
m->last_object_description.clear();
|
||||
if (!description.empty()) {
|
||||
this->m->last_object_description += description;
|
||||
m->last_object_description += description;
|
||||
if (og.isIndirect()) {
|
||||
this->m->last_object_description += ": ";
|
||||
m->last_object_description += ": ";
|
||||
}
|
||||
}
|
||||
if (og.isIndirect()) {
|
||||
this->m->last_object_description += "object " + og.unparse(' ');
|
||||
m->last_object_description += "object " + og.unparse(' ');
|
||||
}
|
||||
}
|
||||
|
||||
@ -1366,7 +1365,7 @@ QPDF::readObject(
|
||||
bool empty = false;
|
||||
std::shared_ptr<StringDecrypter> decrypter_ph;
|
||||
StringDecrypter* decrypter = nullptr;
|
||||
if (this->m->encp->encrypted && (!in_object_stream)) {
|
||||
if (m->encp->encrypted && (!in_object_stream)) {
|
||||
decrypter_ph = std::make_shared<StringDecrypter>(this, og);
|
||||
decrypter = decrypter_ph.get();
|
||||
}
|
||||
@ -1480,7 +1479,7 @@ QPDF::readObject(
|
||||
input, input->getLastOffset(), "expected endstream");
|
||||
}
|
||||
} catch (QPDFExc& e) {
|
||||
if (this->m->attempt_recovery) {
|
||||
if (m->attempt_recovery) {
|
||||
warn(e);
|
||||
length = recoverStreamLength(input, og, stream_offset);
|
||||
} else {
|
||||
@ -1507,7 +1506,7 @@ QPDF::findEndstream()
|
||||
// Find endstream or endobj. Position the input at that token.
|
||||
auto t = readToken(m->file, 20);
|
||||
if (t.isWord("endobj") || t.isWord("endstream")) {
|
||||
this->m->file->seek(this->m->file->getLastOffset(), SEEK_SET);
|
||||
m->file->seek(m->file->getLastOffset(), SEEK_SET);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -1526,12 +1525,12 @@ QPDF::recoverStreamLength(
|
||||
|
||||
PatternFinder ef(*this, &QPDF::findEndstream);
|
||||
size_t length = 0;
|
||||
if (this->m->file->findFirst("end", stream_offset, 0, ef)) {
|
||||
length = toS(this->m->file->tell() - stream_offset);
|
||||
if (m->file->findFirst("end", stream_offset, 0, ef)) {
|
||||
length = toS(m->file->tell() - stream_offset);
|
||||
// Reread endstream but, if it was endobj, don't skip that.
|
||||
QPDFTokenizer::Token t = readToken(this->m->file);
|
||||
QPDFTokenizer::Token t = readToken(m->file);
|
||||
if (t.getValue() == "endobj") {
|
||||
this->m->file->seek(this->m->file->getLastOffset(), SEEK_SET);
|
||||
m->file->seek(m->file->getLastOffset(), SEEK_SET);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1540,7 +1539,7 @@ QPDF::recoverStreamLength(
|
||||
QPDFObjGen this_og;
|
||||
|
||||
// Make sure this is inside this object
|
||||
for (auto const& iter: this->m->xref_table) {
|
||||
for (auto const& iter: m->xref_table) {
|
||||
QPDFXRefEntry const& entry = iter.second;
|
||||
if (entry.getType() == 1) {
|
||||
qpdf_offset_t obj_offset = entry.getOffset();
|
||||
@ -1580,8 +1579,8 @@ QPDF::recoverStreamLength(
|
||||
QPDFTokenizer::Token
|
||||
QPDF::readToken(std::shared_ptr<InputSource> input, size_t max_len)
|
||||
{
|
||||
return this->m->tokenizer.readToken(
|
||||
input, this->m->last_object_description, true, max_len);
|
||||
return m->tokenizer.readToken(
|
||||
input, m->last_object_description, true, max_len);
|
||||
}
|
||||
|
||||
QPDFObjectHandle
|
||||
@ -1608,7 +1607,7 @@ QPDF::readObjectAtOffset(
|
||||
}
|
||||
setLastObjectDescription(description, exp_og);
|
||||
|
||||
if (!this->m->attempt_recovery) {
|
||||
if (!m->attempt_recovery) {
|
||||
try_recovery = false;
|
||||
}
|
||||
|
||||
@ -1623,11 +1622,11 @@ QPDF::readObjectAtOffset(
|
||||
return QPDFObjectHandle::newNull();
|
||||
}
|
||||
|
||||
this->m->file->seek(offset, SEEK_SET);
|
||||
m->file->seek(offset, SEEK_SET);
|
||||
|
||||
QPDFTokenizer::Token tobjid = readToken(this->m->file);
|
||||
QPDFTokenizer::Token tgen = readToken(this->m->file);
|
||||
QPDFTokenizer::Token tobj = readToken(this->m->file);
|
||||
QPDFTokenizer::Token tobjid = readToken(m->file);
|
||||
QPDFTokenizer::Token tgen = readToken(m->file);
|
||||
QPDFTokenizer::Token tobj = readToken(m->file);
|
||||
|
||||
bool objidok = tobjid.isInteger();
|
||||
bool genok = tgen.isInteger();
|
||||
@ -1666,10 +1665,9 @@ QPDF::readObjectAtOffset(
|
||||
if (try_recovery) {
|
||||
// Try again after reconstructing xref table
|
||||
reconstruct_xref(e);
|
||||
if (this->m->xref_table.count(exp_og) &&
|
||||
(this->m->xref_table[exp_og].getType() == 1)) {
|
||||
qpdf_offset_t new_offset =
|
||||
this->m->xref_table[exp_og].getOffset();
|
||||
if (m->xref_table.count(exp_og) &&
|
||||
(m->xref_table[exp_og].getType() == 1)) {
|
||||
qpdf_offset_t new_offset = m->xref_table[exp_og].getOffset();
|
||||
QPDFObjectHandle result = readObjectAtOffset(
|
||||
false, new_offset, description, exp_og, og, false);
|
||||
QTC::TC("qpdf", "QPDF recovered in readObjectAtOffset");
|
||||
@ -1689,9 +1687,9 @@ QPDF::readObjectAtOffset(
|
||||
}
|
||||
}
|
||||
|
||||
QPDFObjectHandle oh = readObject(this->m->file, description, og, false);
|
||||
QPDFObjectHandle oh = readObject(m->file, description, og, false);
|
||||
|
||||
if (!readToken(this->m->file).isWord("endobj")) {
|
||||
if (!readToken(m->file).isWord("endobj")) {
|
||||
QTC::TC("qpdf", "QPDF err expected endobj");
|
||||
warn(damagedPDF("expected endobj"));
|
||||
}
|
||||
@ -1707,22 +1705,22 @@ QPDF::readObjectAtOffset(
|
||||
// linearization hint tables. Offsets and lengths of objects
|
||||
// may imply the end of an object to be anywhere between these
|
||||
// values.
|
||||
qpdf_offset_t end_before_space = this->m->file->tell();
|
||||
qpdf_offset_t end_before_space = m->file->tell();
|
||||
|
||||
// skip over spaces
|
||||
while (true) {
|
||||
char ch;
|
||||
if (this->m->file->read(&ch, 1)) {
|
||||
if (m->file->read(&ch, 1)) {
|
||||
if (!isspace(static_cast<unsigned char>(ch))) {
|
||||
this->m->file->seek(-1, SEEK_CUR);
|
||||
m->file->seek(-1, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
throw damagedPDF(m->file->tell(), "EOF after endobj");
|
||||
}
|
||||
}
|
||||
qpdf_offset_t end_after_space = this->m->file->tell();
|
||||
if (skip_cache_if_in_xref && this->m->xref_table.count(og)) {
|
||||
qpdf_offset_t end_after_space = m->file->tell();
|
||||
if (skip_cache_if_in_xref && m->xref_table.count(og)) {
|
||||
// Ordinarily, an object gets read here when resolved
|
||||
// through xref table or stream. In the special case of
|
||||
// the xref stream and linearization hint tables, the
|
||||
@ -1774,7 +1772,7 @@ QPDF::resolve(QPDFObjGen og)
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->m->resolving.count(og)) {
|
||||
if (m->resolving.count(og)) {
|
||||
// This can happen if an object references itself directly or
|
||||
// indirectly in some key that has to be resolved during
|
||||
// object parsing, such as stream length.
|
||||
@ -1787,7 +1785,7 @@ QPDF::resolve(QPDFObjGen og)
|
||||
ResolveRecorder rr(this, og);
|
||||
|
||||
if (m->xref_table.count(og) != 0) {
|
||||
QPDFXRefEntry const& entry = this->m->xref_table[og];
|
||||
QPDFXRefEntry const& entry = m->xref_table[og];
|
||||
try {
|
||||
switch (entry.getType()) {
|
||||
case 1:
|
||||
@ -1828,17 +1826,17 @@ QPDF::resolve(QPDFObjGen og)
|
||||
updateCache(og, QPDF_Null::create(), -1, -1);
|
||||
}
|
||||
|
||||
auto result(this->m->obj_cache[og].object);
|
||||
auto result(m->obj_cache[og].object);
|
||||
result->setDefaultDescription(this, og);
|
||||
}
|
||||
|
||||
void
|
||||
QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||
{
|
||||
if (this->m->resolved_object_streams.count(obj_stream_number)) {
|
||||
if (m->resolved_object_streams.count(obj_stream_number)) {
|
||||
return;
|
||||
}
|
||||
this->m->resolved_object_streams.insert(obj_stream_number);
|
||||
m->resolved_object_streams.insert(obj_stream_number);
|
||||
// Force resolution of object stream
|
||||
QPDFObjectHandle obj_stream = getObjectByID(obj_stream_number, 0);
|
||||
if (!obj_stream.isStream()) {
|
||||
@ -1850,10 +1848,8 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||
// For linearization data in the object, use the data from the
|
||||
// object stream for the objects in the stream.
|
||||
QPDFObjGen stream_og(obj_stream_number, 0);
|
||||
qpdf_offset_t end_before_space =
|
||||
this->m->obj_cache[stream_og].end_before_space;
|
||||
qpdf_offset_t end_after_space =
|
||||
this->m->obj_cache[stream_og].end_after_space;
|
||||
qpdf_offset_t end_before_space = m->obj_cache[stream_og].end_before_space;
|
||||
qpdf_offset_t end_after_space = m->obj_cache[stream_og].end_after_space;
|
||||
|
||||
QPDFObjectHandle dict = obj_stream.getDict();
|
||||
if (!dict.isDictionaryOfType("/ObjStm")) {
|
||||
@ -1878,7 +1874,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||
auto input = std::shared_ptr<InputSource>(
|
||||
// line-break
|
||||
new BufferInputSource(
|
||||
(this->m->file->getName() + " object stream " +
|
||||
(m->file->getName() + " object stream " +
|
||||
std::to_string(obj_stream_number)),
|
||||
bp.get()));
|
||||
|
||||
@ -1888,7 +1884,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||
if (!(tnum.isInteger() && toffset.isInteger())) {
|
||||
throw damagedPDF(
|
||||
input,
|
||||
this->m->last_object_description,
|
||||
m->last_object_description,
|
||||
input->getLastOffset(),
|
||||
"expected integer in object stream header");
|
||||
}
|
||||
@ -1905,7 +1901,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
|
||||
// xref table and only cache what would actually be resolved here.
|
||||
for (auto const& iter: offsets) {
|
||||
QPDFObjGen og(iter.first, 0);
|
||||
QPDFXRefEntry const& entry = this->m->xref_table[og];
|
||||
QPDFXRefEntry const& entry = m->xref_table[og];
|
||||
if ((entry.getType() == 2) &&
|
||||
(entry.getObjStreamNumber() == obj_stream_number)) {
|
||||
int offset = iter.second;
|
||||
@ -2146,7 +2142,7 @@ QPDF::copyForeignObject(QPDFObjectHandle foreign)
|
||||
"QPDF::copyForeign called with object from this QPDF");
|
||||
}
|
||||
|
||||
ObjCopier& obj_copier = this->m->object_copiers[other.m->unique_id];
|
||||
ObjCopier& obj_copier = m->object_copiers[other.m->unique_id];
|
||||
if (!obj_copier.visiting.empty()) {
|
||||
throw std::logic_error("obj_copier.visiting is not empty"
|
||||
" at the beginning of copyForeignObject");
|
||||
@ -2310,12 +2306,11 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
|
||||
|
||||
QPDFObjectHandle dict = result.getDict();
|
||||
QPDFObjectHandle old_dict = foreign.getDict();
|
||||
if (this->m->copied_stream_data_provider == nullptr) {
|
||||
this->m->copied_stream_data_provider =
|
||||
new CopiedStreamDataProvider(*this);
|
||||
this->m->copied_streams =
|
||||
if (m->copied_stream_data_provider == nullptr) {
|
||||
m->copied_stream_data_provider = new CopiedStreamDataProvider(*this);
|
||||
m->copied_streams =
|
||||
std::shared_ptr<QPDFObjectHandle::StreamDataProvider>(
|
||||
this->m->copied_stream_data_provider);
|
||||
m->copied_stream_data_provider);
|
||||
}
|
||||
QPDFObjGen local_og(result.getObjGen());
|
||||
// Copy information from the foreign stream so we can pipe its
|
||||
@ -2352,10 +2347,10 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
|
||||
} else if (stream_provider.get()) {
|
||||
// In this case, the remote stream's QPDF must stay in scope.
|
||||
QTC::TC("qpdf", "QPDF copy foreign stream with provider");
|
||||
this->m->copied_stream_data_provider->registerForeignStream(
|
||||
m->copied_stream_data_provider->registerForeignStream(
|
||||
local_og, foreign);
|
||||
result.replaceStreamData(
|
||||
this->m->copied_streams,
|
||||
m->copied_streams,
|
||||
dict.getKey("/Filter"),
|
||||
dict.getKey("/DecodeParms"));
|
||||
} else {
|
||||
@ -2366,10 +2361,10 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
|
||||
stream->getParsedOffset(),
|
||||
stream->getLength(),
|
||||
dict);
|
||||
this->m->copied_stream_data_provider->registerForeignStream(
|
||||
m->copied_stream_data_provider->registerForeignStream(
|
||||
local_og, foreign_stream_data);
|
||||
result.replaceStreamData(
|
||||
this->m->copied_streams,
|
||||
m->copied_streams,
|
||||
dict.getKey("/Filter"),
|
||||
dict.getKey("/DecodeParms"));
|
||||
}
|
||||
@ -2395,13 +2390,13 @@ QPDF::swapObjects(QPDFObjGen const& og1, QPDFObjGen const& og2)
|
||||
unsigned long long
|
||||
QPDF::getUniqueId() const
|
||||
{
|
||||
return this->m->unique_id;
|
||||
return m->unique_id;
|
||||
}
|
||||
|
||||
std::string
|
||||
QPDF::getFilename() const
|
||||
{
|
||||
return this->m->file->getName();
|
||||
return m->file->getName();
|
||||
}
|
||||
|
||||
PDFVersion
|
||||
@ -2424,7 +2419,7 @@ QPDF::getVersionAsPDFVersion()
|
||||
std::string
|
||||
QPDF::getPDFVersion() const
|
||||
{
|
||||
return this->m->pdf_version;
|
||||
return m->pdf_version;
|
||||
}
|
||||
|
||||
int
|
||||
@ -2450,13 +2445,13 @@ QPDF::getExtensionLevel()
|
||||
QPDFObjectHandle
|
||||
QPDF::getTrailer()
|
||||
{
|
||||
return this->m->trailer;
|
||||
return m->trailer;
|
||||
}
|
||||
|
||||
QPDFObjectHandle
|
||||
QPDF::getRoot()
|
||||
{
|
||||
QPDFObjectHandle root = this->m->trailer.getKey("/Root");
|
||||
QPDFObjectHandle root = m->trailer.getKey("/Root");
|
||||
if (!root.isDictionary()) {
|
||||
throw damagedPDF("", 0, "unable to find /Root dictionary");
|
||||
} else if (
|
||||
@ -2473,17 +2468,17 @@ QPDF::getRoot()
|
||||
std::map<QPDFObjGen, QPDFXRefEntry>
|
||||
QPDF::getXRefTable()
|
||||
{
|
||||
if (!this->m->parsed) {
|
||||
if (!m->parsed) {
|
||||
throw std::logic_error("QPDF::getXRefTable called before parsing.");
|
||||
}
|
||||
|
||||
return this->m->xref_table;
|
||||
return m->xref_table;
|
||||
}
|
||||
|
||||
void
|
||||
QPDF::getObjectStreamData(std::map<int, int>& omap)
|
||||
{
|
||||
for (auto const& iter: this->m->xref_table) {
|
||||
for (auto const& iter: m->xref_table) {
|
||||
QPDFObjGen const& og = iter.first;
|
||||
QPDFXRefEntry const& entry = iter.second;
|
||||
if (entry.getType() == 2) {
|
||||
@ -2505,12 +2500,12 @@ QPDF::getCompressibleObjGens()
|
||||
// orphaned items.
|
||||
|
||||
// Exclude encryption dictionary, if any
|
||||
QPDFObjectHandle encryption_dict = this->m->trailer.getKey("/Encrypt");
|
||||
QPDFObjectHandle encryption_dict = m->trailer.getKey("/Encrypt");
|
||||
QPDFObjGen encryption_dict_og = encryption_dict.getObjGen();
|
||||
|
||||
QPDFObjGen::set visited;
|
||||
std::list<QPDFObjectHandle> queue;
|
||||
queue.push_front(this->m->trailer);
|
||||
queue.push_front(m->trailer);
|
||||
std::vector<QPDFObjGen> result;
|
||||
while (!queue.empty()) {
|
||||
QPDFObjectHandle obj = queue.front();
|
||||
@ -2647,8 +2642,8 @@ QPDF::pipeStreamData(
|
||||
bool will_retry)
|
||||
{
|
||||
return pipeStreamData(
|
||||
this->m->encp,
|
||||
this->m->file,
|
||||
m->encp,
|
||||
m->file,
|
||||
*this,
|
||||
og,
|
||||
offset,
|
||||
@ -2753,13 +2748,13 @@ QPDF::damagedPDF(std::string const& message)
|
||||
bool
|
||||
QPDF::everCalledGetAllPages() const
|
||||
{
|
||||
return this->m->ever_called_get_all_pages;
|
||||
return m->ever_called_get_all_pages;
|
||||
}
|
||||
|
||||
bool
|
||||
QPDF::everPushedInheritedAttributesToPages() const
|
||||
{
|
||||
return this->m->ever_pushed_inherited_attributes_to_pages;
|
||||
return m->ever_pushed_inherited_attributes_to_pages;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -24,9 +24,9 @@ QPDFAcroFormDocumentHelper::QPDFAcroFormDocumentHelper(QPDF& qpdf) :
|
||||
void
|
||||
QPDFAcroFormDocumentHelper::invalidateCache()
|
||||
{
|
||||
this->m->cache_valid = false;
|
||||
this->m->field_to_annotations.clear();
|
||||
this->m->annotation_to_field.clear();
|
||||
m->cache_valid = false;
|
||||
m->field_to_annotations.clear();
|
||||
m->annotation_to_field.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -133,21 +133,20 @@ QPDFAcroFormDocumentHelper::removeFormFields(
|
||||
}
|
||||
|
||||
for (auto const& og: to_remove) {
|
||||
auto annotations = this->m->field_to_annotations.find(og);
|
||||
if (annotations != this->m->field_to_annotations.end()) {
|
||||
auto annotations = m->field_to_annotations.find(og);
|
||||
if (annotations != m->field_to_annotations.end()) {
|
||||
for (auto aoh: annotations->second) {
|
||||
this->m->annotation_to_field.erase(
|
||||
aoh.getObjectHandle().getObjGen());
|
||||
m->annotation_to_field.erase(aoh.getObjectHandle().getObjGen());
|
||||
}
|
||||
this->m->field_to_annotations.erase(og);
|
||||
m->field_to_annotations.erase(og);
|
||||
}
|
||||
auto name = this->m->field_to_name.find(og);
|
||||
if (name != this->m->field_to_name.end()) {
|
||||
this->m->name_to_fields[name->second].erase(og);
|
||||
if (this->m->name_to_fields[name->second].empty()) {
|
||||
this->m->name_to_fields.erase(name->second);
|
||||
auto name = m->field_to_name.find(og);
|
||||
if (name != m->field_to_name.end()) {
|
||||
m->name_to_fields[name->second].erase(og);
|
||||
if (m->name_to_fields[name->second].empty()) {
|
||||
m->name_to_fields.erase(name->second);
|
||||
}
|
||||
this->m->field_to_name.erase(og);
|
||||
m->field_to_name.erase(og);
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,7 +176,7 @@ QPDFAcroFormDocumentHelper::getFormFields()
|
||||
{
|
||||
analyze();
|
||||
std::vector<QPDFFormFieldObjectHelper> result;
|
||||
for (auto const& iter: this->m->field_to_annotations) {
|
||||
for (auto const& iter: m->field_to_annotations) {
|
||||
result.push_back(this->qpdf.getObject(iter.first));
|
||||
}
|
||||
return result;
|
||||
@ -188,8 +187,8 @@ QPDFAcroFormDocumentHelper::getFieldsWithQualifiedName(std::string const& name)
|
||||
{
|
||||
analyze();
|
||||
// Keep from creating an empty entry
|
||||
auto iter = this->m->name_to_fields.find(name);
|
||||
if (iter != this->m->name_to_fields.end()) {
|
||||
auto iter = m->name_to_fields.find(name);
|
||||
if (iter != m->name_to_fields.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
return {};
|
||||
@ -201,8 +200,8 @@ QPDFAcroFormDocumentHelper::getAnnotationsForField(QPDFFormFieldObjectHelper h)
|
||||
analyze();
|
||||
std::vector<QPDFAnnotationObjectHelper> result;
|
||||
QPDFObjGen og(h.getObjectHandle().getObjGen());
|
||||
if (this->m->field_to_annotations.count(og)) {
|
||||
result = this->m->field_to_annotations[og];
|
||||
if (m->field_to_annotations.count(og)) {
|
||||
result = m->field_to_annotations[og];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -238,8 +237,8 @@ QPDFAcroFormDocumentHelper::getFieldForAnnotation(QPDFAnnotationObjectHelper h)
|
||||
}
|
||||
analyze();
|
||||
QPDFObjGen og(oh.getObjGen());
|
||||
if (this->m->annotation_to_field.count(og)) {
|
||||
result = this->m->annotation_to_field[og];
|
||||
if (m->annotation_to_field.count(og)) {
|
||||
result = m->annotation_to_field[og];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -247,10 +246,10 @@ QPDFAcroFormDocumentHelper::getFieldForAnnotation(QPDFAnnotationObjectHelper h)
|
||||
void
|
||||
QPDFAcroFormDocumentHelper::analyze()
|
||||
{
|
||||
if (this->m->cache_valid) {
|
||||
if (m->cache_valid) {
|
||||
return;
|
||||
}
|
||||
this->m->cache_valid = true;
|
||||
m->cache_valid = true;
|
||||
QPDFObjectHandle acroform = this->qpdf.getRoot().getKey("/AcroForm");
|
||||
if (!(acroform.isDictionary() && acroform.hasKey("/Fields"))) {
|
||||
return;
|
||||
@ -286,7 +285,7 @@ QPDFAcroFormDocumentHelper::analyze()
|
||||
for (auto const& iter: getWidgetAnnotationsForPage(ph)) {
|
||||
QPDFObjectHandle annot(iter.getObjectHandle());
|
||||
QPDFObjGen og(annot.getObjGen());
|
||||
if (this->m->annotation_to_field.count(og) == 0) {
|
||||
if (m->annotation_to_field.count(og) == 0) {
|
||||
QTC::TC("qpdf", "QPDFAcroFormDocumentHelper orphaned widget");
|
||||
// This is not supposed to happen, but it's easy
|
||||
// enough for us to handle this case. Treat the
|
||||
@ -298,9 +297,8 @@ QPDFAcroFormDocumentHelper::analyze()
|
||||
annot.warnIfPossible(
|
||||
"this widget annotation is not"
|
||||
" reachable from /AcroForm in the document catalog");
|
||||
this->m->annotation_to_field[og] =
|
||||
QPDFFormFieldObjectHelper(annot);
|
||||
this->m->field_to_annotations[og].push_back(
|
||||
m->annotation_to_field[og] = QPDFFormFieldObjectHelper(annot);
|
||||
m->field_to_annotations[og].push_back(
|
||||
QPDFAnnotationObjectHelper(annot));
|
||||
}
|
||||
}
|
||||
@ -376,24 +374,24 @@ QPDFAcroFormDocumentHelper::traverseField(
|
||||
|
||||
if (is_annotation) {
|
||||
QPDFObjectHandle our_field = (is_field ? field : parent);
|
||||
this->m->field_to_annotations[our_field.getObjGen()].push_back(
|
||||
m->field_to_annotations[our_field.getObjGen()].push_back(
|
||||
QPDFAnnotationObjectHelper(field));
|
||||
this->m->annotation_to_field[og] = QPDFFormFieldObjectHelper(our_field);
|
||||
m->annotation_to_field[og] = QPDFFormFieldObjectHelper(our_field);
|
||||
}
|
||||
|
||||
if (is_field && (field.hasKey("/T"))) {
|
||||
QPDFFormFieldObjectHelper foh(field);
|
||||
auto f_og = field.getObjGen();
|
||||
std::string name = foh.getFullyQualifiedName();
|
||||
auto old = this->m->field_to_name.find(f_og);
|
||||
if (old != this->m->field_to_name.end()) {
|
||||
auto old = m->field_to_name.find(f_og);
|
||||
if (old != m->field_to_name.end()) {
|
||||
// We might be updating after a name change, so remove any
|
||||
// old information
|
||||
std::string old_name = old->second;
|
||||
this->m->name_to_fields[old_name].erase(f_og);
|
||||
m->name_to_fields[old_name].erase(f_og);
|
||||
}
|
||||
this->m->field_to_name[f_og] = name;
|
||||
this->m->name_to_fields[name].insert(f_og);
|
||||
m->field_to_name[f_og] = name;
|
||||
m->name_to_fields[name].insert(f_og);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,41 +45,41 @@ QPDFArgParser::QPDFArgParser(
|
||||
void
|
||||
QPDFArgParser::selectMainOptionTable()
|
||||
{
|
||||
this->m->option_table = &this->m->main_option_table;
|
||||
this->m->option_table_name = "main";
|
||||
m->option_table = &m->main_option_table;
|
||||
m->option_table_name = "main";
|
||||
}
|
||||
|
||||
void
|
||||
QPDFArgParser::selectHelpOptionTable()
|
||||
{
|
||||
this->m->option_table = &this->m->help_option_table;
|
||||
this->m->option_table_name = "help";
|
||||
m->option_table = &m->help_option_table;
|
||||
m->option_table_name = "help";
|
||||
}
|
||||
|
||||
void
|
||||
QPDFArgParser::selectOptionTable(std::string const& name)
|
||||
{
|
||||
auto t = this->m->option_tables.find(name);
|
||||
if (t == this->m->option_tables.end()) {
|
||||
auto t = m->option_tables.find(name);
|
||||
if (t == m->option_tables.end()) {
|
||||
QTC::TC("libtests", "QPDFArgParser select unregistered table");
|
||||
throw std::logic_error(
|
||||
"QPDFArgParser: selecting unregistered option table " + name);
|
||||
}
|
||||
this->m->option_table = &(t->second);
|
||||
this->m->option_table_name = name;
|
||||
m->option_table = &(t->second);
|
||||
m->option_table_name = name;
|
||||
}
|
||||
|
||||
void
|
||||
QPDFArgParser::registerOptionTable(
|
||||
std::string const& name, bare_arg_handler_t end_handler)
|
||||
{
|
||||
if (0 != this->m->option_tables.count(name)) {
|
||||
if (0 != m->option_tables.count(name)) {
|
||||
QTC::TC("libtests", "QPDFArgParser register registered table");
|
||||
throw std::logic_error(
|
||||
"QPDFArgParser: registering already registered option table " +
|
||||
name);
|
||||
}
|
||||
this->m->option_tables[name];
|
||||
m->option_tables[name];
|
||||
selectOptionTable(name);
|
||||
addBare("--", end_handler);
|
||||
}
|
||||
@ -87,13 +87,13 @@ QPDFArgParser::registerOptionTable(
|
||||
QPDFArgParser::OptionEntry&
|
||||
QPDFArgParser::registerArg(std::string const& arg)
|
||||
{
|
||||
if (0 != this->m->option_table->count(arg)) {
|
||||
if (0 != m->option_table->count(arg)) {
|
||||
QTC::TC("libtests", "QPDFArgParser duplicate handler");
|
||||
throw std::logic_error(
|
||||
"QPDFArgParser: adding a duplicate handler for option " + arg +
|
||||
" in " + this->m->option_table_name + " option table");
|
||||
" in " + m->option_table_name + " option table");
|
||||
}
|
||||
return ((*this->m->option_table)[arg]);
|
||||
return ((*m->option_table)[arg]);
|
||||
}
|
||||
|
||||
void
|
||||
@ -151,8 +151,8 @@ void
|
||||
QPDFArgParser::addInvalidChoiceHandler(
|
||||
std::string const& arg, param_arg_handler_t handler)
|
||||
{
|
||||
auto i = this->m->option_table->find(arg);
|
||||
if (i == this->m->option_table->end()) {
|
||||
auto i = m->option_table->find(arg);
|
||||
if (i == m->option_table->end()) {
|
||||
QTC::TC("libtests", "QPDFArgParser invalid choice handler to unknown");
|
||||
throw std::logic_error(
|
||||
"QPDFArgParser: attempt to add invalid choice handler"
|
||||
@ -165,42 +165,42 @@ QPDFArgParser::addInvalidChoiceHandler(
|
||||
void
|
||||
QPDFArgParser::addFinalCheck(bare_arg_handler_t handler)
|
||||
{
|
||||
this->m->final_check_handler = handler;
|
||||
m->final_check_handler = handler;
|
||||
}
|
||||
|
||||
bool
|
||||
QPDFArgParser::isCompleting() const
|
||||
{
|
||||
return this->m->bash_completion;
|
||||
return m->bash_completion;
|
||||
}
|
||||
|
||||
int
|
||||
QPDFArgParser::argsLeft() const
|
||||
{
|
||||
return this->m->argc - this->m->cur_arg - 1;
|
||||
return m->argc - m->cur_arg - 1;
|
||||
}
|
||||
|
||||
void
|
||||
QPDFArgParser::insertCompletion(std::string const& arg)
|
||||
{
|
||||
this->m->completions.insert(arg);
|
||||
m->completions.insert(arg);
|
||||
}
|
||||
|
||||
void
|
||||
QPDFArgParser::completionCommon(bool zsh)
|
||||
{
|
||||
std::string progname = this->m->argv[0];
|
||||
std::string progname = m->argv[0];
|
||||
std::string executable;
|
||||
std::string appdir;
|
||||
std::string appimage;
|
||||
if (QUtil::get_env(this->m->progname_env.c_str(), &executable)) {
|
||||
if (QUtil::get_env(m->progname_env.c_str(), &executable)) {
|
||||
progname = executable;
|
||||
} else if (
|
||||
QUtil::get_env("APPDIR", &appdir) &&
|
||||
QUtil::get_env("APPIMAGE", &appimage)) {
|
||||
// Detect if we're in an AppImage and adjust
|
||||
if ((appdir.length() < strlen(this->m->argv[0])) &&
|
||||
(strncmp(appdir.c_str(), this->m->argv[0], appdir.length()) == 0)) {
|
||||
if ((appdir.length() < strlen(m->argv[0])) &&
|
||||
(strncmp(appdir.c_str(), m->argv[0], appdir.length()) == 0)) {
|
||||
progname = appimage;
|
||||
}
|
||||
}
|
||||
@ -211,12 +211,12 @@ QPDFArgParser::completionCommon(bool zsh)
|
||||
if (!zsh) {
|
||||
std::cout << " -o nospace";
|
||||
}
|
||||
std::cout << " -C " << progname << " " << this->m->whoami << std::endl;
|
||||
std::cout << " -C " << progname << " " << m->whoami << std::endl;
|
||||
// Put output before error so calling from zsh works properly
|
||||
std::string path = progname;
|
||||
size_t slash = path.find('/');
|
||||
if ((slash != 0) && (slash != std::string::npos)) {
|
||||
std::cerr << "WARNING: " << this->m->whoami << " completion enabled"
|
||||
std::cerr << "WARNING: " << m->whoami << " completion enabled"
|
||||
<< " using relative path to executable" << std::endl;
|
||||
}
|
||||
}
|
||||
@ -252,11 +252,11 @@ QPDFArgParser::handleArgFileArguments()
|
||||
// Support reading arguments from files. Create a new argv. Ensure
|
||||
// that argv itself as well as all its contents are automatically
|
||||
// deleted by using shared pointers to back the pointers in argv.
|
||||
this->m->new_argv.push_back(QUtil::make_shared_cstr(this->m->argv[0]));
|
||||
for (int i = 1; i < this->m->argc; ++i) {
|
||||
m->new_argv.push_back(QUtil::make_shared_cstr(m->argv[0]));
|
||||
for (int i = 1; i < m->argc; ++i) {
|
||||
char const* argfile = nullptr;
|
||||
if ((strlen(this->m->argv[i]) > 1) && (this->m->argv[i][0] == '@')) {
|
||||
argfile = 1 + this->m->argv[i];
|
||||
if ((strlen(m->argv[i]) > 1) && (m->argv[i][0] == '@')) {
|
||||
argfile = 1 + m->argv[i];
|
||||
if (strcmp(argfile, "-") != 0) {
|
||||
if (!QUtil::file_can_be_opened(argfile)) {
|
||||
// The file's not there; treating as regular option
|
||||
@ -265,20 +265,18 @@ QPDFArgParser::handleArgFileArguments()
|
||||
}
|
||||
}
|
||||
if (argfile) {
|
||||
readArgsFromFile(1 + this->m->argv[i]);
|
||||
readArgsFromFile(1 + m->argv[i]);
|
||||
} else {
|
||||
this->m->new_argv.push_back(
|
||||
QUtil::make_shared_cstr(this->m->argv[i]));
|
||||
m->new_argv.push_back(QUtil::make_shared_cstr(m->argv[i]));
|
||||
}
|
||||
}
|
||||
this->m->argv_ph =
|
||||
QUtil::make_shared_array<char const*>(1 + this->m->new_argv.size());
|
||||
for (size_t i = 0; i < this->m->new_argv.size(); ++i) {
|
||||
this->m->argv_ph.get()[i] = this->m->new_argv.at(i).get();
|
||||
m->argv_ph = QUtil::make_shared_array<char const*>(1 + m->new_argv.size());
|
||||
for (size_t i = 0; i < m->new_argv.size(); ++i) {
|
||||
m->argv_ph.get()[i] = m->new_argv.at(i).get();
|
||||
}
|
||||
this->m->argc = QIntC::to_int(this->m->new_argv.size());
|
||||
this->m->argv_ph.get()[this->m->argc] = nullptr;
|
||||
this->m->argv = this->m->argv_ph.get();
|
||||
m->argc = QIntC::to_int(m->new_argv.size());
|
||||
m->argv_ph.get()[m->argc] = nullptr;
|
||||
m->argv = m->argv_ph.get();
|
||||
}
|
||||
|
||||
void
|
||||
@ -288,14 +286,14 @@ QPDFArgParser::handleBashArguments()
|
||||
// doesn't do everything the shell does (e.g. $(...), variable
|
||||
// expansion, arithmetic, globs, etc.), but it should be good
|
||||
// enough for purposes of handling completion. As we build up the
|
||||
// new argv, we can't use this->m->new_argv because this code has to
|
||||
// new argv, we can't use m->new_argv because this code has to
|
||||
// interoperate with @file arguments, so memory for both ways of
|
||||
// fabricating argv has to be protected.
|
||||
|
||||
bool last_was_backslash = false;
|
||||
enum { st_top, st_squote, st_dquote } state = st_top;
|
||||
std::string arg;
|
||||
for (char ch: this->m->bash_line) {
|
||||
for (char ch: m->bash_line) {
|
||||
if (last_was_backslash) {
|
||||
arg.append(1, ch);
|
||||
last_was_backslash = false;
|
||||
@ -307,8 +305,7 @@ QPDFArgParser::handleBashArguments()
|
||||
case st_top:
|
||||
if (QUtil::is_space(ch)) {
|
||||
if (!arg.empty()) {
|
||||
this->m->bash_argv.push_back(
|
||||
QUtil::make_shared_cstr(arg));
|
||||
m->bash_argv.push_back(QUtil::make_shared_cstr(arg));
|
||||
arg.clear();
|
||||
}
|
||||
} else if (ch == '"') {
|
||||
@ -341,27 +338,27 @@ QPDFArgParser::handleBashArguments()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this->m->bash_argv.empty()) {
|
||||
if (m->bash_argv.empty()) {
|
||||
// This can't happen if properly invoked by bash, but ensure
|
||||
// we have a valid argv[0] regardless.
|
||||
this->m->bash_argv.push_back(QUtil::make_shared_cstr(this->m->argv[0]));
|
||||
m->bash_argv.push_back(QUtil::make_shared_cstr(m->argv[0]));
|
||||
}
|
||||
// Explicitly discard any non-space-terminated word. The "current
|
||||
// word" is handled specially.
|
||||
this->m->bash_argv_ph =
|
||||
QUtil::make_shared_array<char const*>(1 + this->m->bash_argv.size());
|
||||
for (size_t i = 0; i < this->m->bash_argv.size(); ++i) {
|
||||
this->m->bash_argv_ph.get()[i] = this->m->bash_argv.at(i).get();
|
||||
m->bash_argv_ph =
|
||||
QUtil::make_shared_array<char const*>(1 + m->bash_argv.size());
|
||||
for (size_t i = 0; i < m->bash_argv.size(); ++i) {
|
||||
m->bash_argv_ph.get()[i] = m->bash_argv.at(i).get();
|
||||
}
|
||||
this->m->argc = QIntC::to_int(this->m->bash_argv.size());
|
||||
this->m->bash_argv_ph.get()[this->m->argc] = nullptr;
|
||||
this->m->argv = this->m->bash_argv_ph.get();
|
||||
m->argc = QIntC::to_int(m->bash_argv.size());
|
||||
m->bash_argv_ph.get()[m->argc] = nullptr;
|
||||
m->argv = m->bash_argv_ph.get();
|
||||
}
|
||||
|
||||
void
|
||||
QPDFArgParser::usage(std::string const& message)
|
||||
{
|
||||
if (this->m->bash_completion) {
|
||||
if (m->bash_completion) {
|
||||
// This will cause bash to fall back to regular file completion.
|
||||
exit(0);
|
||||
}
|
||||
@ -380,7 +377,7 @@ QPDFArgParser::readArgsFromFile(std::string const& filename)
|
||||
lines = QUtil::read_lines_from_file(filename.c_str());
|
||||
}
|
||||
for (auto const& line: lines) {
|
||||
this->m->new_argv.push_back(QUtil::make_shared_cstr(line));
|
||||
m->new_argv.push_back(QUtil::make_shared_cstr(line));
|
||||
}
|
||||
}
|
||||
|
||||
@ -395,17 +392,17 @@ QPDFArgParser::checkCompletion()
|
||||
// which bash doesn't set COMP_LINE. Therefore, enter this logic
|
||||
// if either COMP_LINE or COMP_POINT are set. They will both be
|
||||
// set together under ordinary circumstances.
|
||||
bool got_line = QUtil::get_env("COMP_LINE", &this->m->bash_line);
|
||||
bool got_line = QUtil::get_env("COMP_LINE", &m->bash_line);
|
||||
bool got_point = QUtil::get_env("COMP_POINT", &bash_point_env);
|
||||
if (got_line || got_point) {
|
||||
size_t p = QUtil::string_to_uint(bash_point_env.c_str());
|
||||
if (p < this->m->bash_line.length()) {
|
||||
if (p < m->bash_line.length()) {
|
||||
// Truncate the line. We ignore everything at or after the
|
||||
// cursor for completion purposes.
|
||||
this->m->bash_line = this->m->bash_line.substr(0, p);
|
||||
m->bash_line = m->bash_line.substr(0, p);
|
||||
}
|
||||
if (p > this->m->bash_line.length()) {
|
||||
p = this->m->bash_line.length();
|
||||
if (p > m->bash_line.length()) {
|
||||
p = m->bash_line.length();
|
||||
}
|
||||
// Set bash_cur and bash_prev based on bash_line rather than
|
||||
// relying on argv. This enables us to use bashcompinit to get
|
||||
@ -419,46 +416,44 @@ QPDFArgParser::checkCompletion()
|
||||
char sep(0);
|
||||
while (p > 0) {
|
||||
--p;
|
||||
char ch = this->m->bash_line.at(p);
|
||||
char ch = m->bash_line.at(p);
|
||||
if ((ch == ' ') || (ch == '=') || (ch == ':')) {
|
||||
sep = ch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (1 + p <= this->m->bash_line.length()) {
|
||||
this->m->bash_cur =
|
||||
this->m->bash_line.substr(1 + p, std::string::npos);
|
||||
if (1 + p <= m->bash_line.length()) {
|
||||
m->bash_cur = m->bash_line.substr(1 + p, std::string::npos);
|
||||
}
|
||||
if ((sep == ':') || (sep == '=')) {
|
||||
// Bash sets prev to the non-space separator if any.
|
||||
// Actually, if there are multiple separators in a row,
|
||||
// they are all included in prev, but that detail is not
|
||||
// important to us and not worth coding.
|
||||
this->m->bash_prev = this->m->bash_line.substr(p, 1);
|
||||
m->bash_prev = m->bash_line.substr(p, 1);
|
||||
} else {
|
||||
// Go back to the last separator and set prev based on
|
||||
// that.
|
||||
size_t p1 = p;
|
||||
while (p1 > 0) {
|
||||
--p1;
|
||||
char ch = this->m->bash_line.at(p1);
|
||||
char ch = m->bash_line.at(p1);
|
||||
if ((ch == ' ') || (ch == ':') || (ch == '=')) {
|
||||
this->m->bash_prev =
|
||||
this->m->bash_line.substr(p1 + 1, p - p1 - 1);
|
||||
m->bash_prev = m->bash_line.substr(p1 + 1, p - p1 - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this->m->bash_prev.empty()) {
|
||||
this->m->bash_prev = this->m->bash_line.substr(0, p);
|
||||
if (m->bash_prev.empty()) {
|
||||
m->bash_prev = m->bash_line.substr(0, p);
|
||||
}
|
||||
if (this->m->argc == 1) {
|
||||
if (m->argc == 1) {
|
||||
// This is probably zsh using bashcompinit. There are a
|
||||
// few differences in the expected output.
|
||||
this->m->zsh_completion = true;
|
||||
m->zsh_completion = true;
|
||||
}
|
||||
handleBashArguments();
|
||||
this->m->bash_completion = true;
|
||||
m->bash_completion = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -468,12 +463,11 @@ QPDFArgParser::parseArgs()
|
||||
selectMainOptionTable();
|
||||
checkCompletion();
|
||||
handleArgFileArguments();
|
||||
for (this->m->cur_arg = 1; this->m->cur_arg < this->m->argc;
|
||||
++this->m->cur_arg) {
|
||||
for (m->cur_arg = 1; m->cur_arg < m->argc; ++m->cur_arg) {
|
||||
bool help_option = false;
|
||||
bool end_option = false;
|
||||
auto oep = this->m->option_table->end();
|
||||
char const* arg = this->m->argv[this->m->cur_arg];
|
||||
auto oep = m->option_table->end();
|
||||
char const* arg = m->argv[m->cur_arg];
|
||||
std::string parameter;
|
||||
bool have_parameter = false;
|
||||
std::string o_arg(arg);
|
||||
@ -481,9 +475,9 @@ QPDFArgParser::parseArgs()
|
||||
if (strcmp(arg, "--") == 0) {
|
||||
// Special case for -- option, which is used to break out
|
||||
// of subparsers.
|
||||
oep = this->m->option_table->find("--");
|
||||
oep = m->option_table->find("--");
|
||||
end_option = true;
|
||||
if (oep == this->m->option_table->end()) {
|
||||
if (oep == m->option_table->end()) {
|
||||
// This is registered automatically, so this can't happen.
|
||||
throw std::logic_error(
|
||||
"QPDFArgParser: -- handler not registered");
|
||||
@ -513,32 +507,31 @@ QPDFArgParser::parseArgs()
|
||||
arg_s = arg_s.substr(0, equal_pos);
|
||||
}
|
||||
|
||||
if ((!this->m->bash_completion) && (this->m->argc == 2) &&
|
||||
(this->m->cur_arg == 1) &&
|
||||
this->m->help_option_table.count(arg_s)) {
|
||||
if ((!m->bash_completion) && (m->argc == 2) && (m->cur_arg == 1) &&
|
||||
m->help_option_table.count(arg_s)) {
|
||||
// Handle help option, which is only valid as the sole
|
||||
// option.
|
||||
QTC::TC("libtests", "QPDFArgParser help option");
|
||||
oep = this->m->help_option_table.find(arg_s);
|
||||
oep = m->help_option_table.find(arg_s);
|
||||
help_option = true;
|
||||
}
|
||||
|
||||
if (!(help_option || arg_s.empty() || (arg_s.at(0) == '-'))) {
|
||||
oep = this->m->option_table->find(arg_s);
|
||||
oep = m->option_table->find(arg_s);
|
||||
}
|
||||
} else {
|
||||
// The empty string maps to the positional argument
|
||||
// handler.
|
||||
QTC::TC("libtests", "QPDFArgParser positional");
|
||||
oep = this->m->option_table->find("");
|
||||
oep = m->option_table->find("");
|
||||
parameter = arg;
|
||||
}
|
||||
|
||||
if (oep == this->m->option_table->end()) {
|
||||
if (oep == m->option_table->end()) {
|
||||
QTC::TC("libtests", "QPDFArgParser unrecognized");
|
||||
std::string message = "unrecognized argument " + o_arg;
|
||||
if (this->m->option_table != &this->m->main_option_table) {
|
||||
message += " (" + this->m->option_table_name +
|
||||
if (m->option_table != &m->main_option_table) {
|
||||
message += " (" + m->option_table_name +
|
||||
" options must be terminated with --)";
|
||||
}
|
||||
usage(message);
|
||||
@ -589,7 +582,7 @@ QPDFArgParser::parseArgs()
|
||||
selectMainOptionTable();
|
||||
}
|
||||
}
|
||||
if (this->m->bash_completion) {
|
||||
if (m->bash_completion) {
|
||||
handleCompletion();
|
||||
} else {
|
||||
doFinalChecks();
|
||||
@ -599,19 +592,18 @@ QPDFArgParser::parseArgs()
|
||||
std::string
|
||||
QPDFArgParser::getProgname()
|
||||
{
|
||||
return this->m->whoami;
|
||||
return m->whoami;
|
||||
}
|
||||
|
||||
void
|
||||
QPDFArgParser::doFinalChecks()
|
||||
{
|
||||
if (this->m->option_table != &(this->m->main_option_table)) {
|
||||
if (m->option_table != &(m->main_option_table)) {
|
||||
QTC::TC("libtests", "QPDFArgParser missing --");
|
||||
usage(
|
||||
"missing -- at end of " + this->m->option_table_name + " options");
|
||||
usage("missing -- at end of " + m->option_table_name + " options");
|
||||
}
|
||||
if (this->m->final_check_handler != nullptr) {
|
||||
this->m->final_check_handler();
|
||||
if (m->final_check_handler != nullptr) {
|
||||
m->final_check_handler();
|
||||
}
|
||||
}
|
||||
|
||||
@ -625,7 +617,7 @@ QPDFArgParser::addChoicesToCompletions(
|
||||
OptionEntry& oe = option_table[option];
|
||||
for (auto const& choice: oe.choices) {
|
||||
QTC::TC("libtests", "QPDFArgParser complete choices");
|
||||
this->m->completions.insert(extra_prefix + choice);
|
||||
m->completions.insert(extra_prefix + choice);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -641,15 +633,15 @@ QPDFArgParser::addOptionsToCompletions(option_table_t& option_table)
|
||||
OptionEntry& oe = iter.second;
|
||||
std::string base = "--" + arg;
|
||||
if (oe.param_arg_handler) {
|
||||
if (this->m->zsh_completion) {
|
||||
if (m->zsh_completion) {
|
||||
// zsh doesn't treat = as a word separator, so add all
|
||||
// the options so we don't get a space after the =.
|
||||
addChoicesToCompletions(option_table, arg, base + "=");
|
||||
}
|
||||
this->m->completions.insert(base + "=");
|
||||
m->completions.insert(base + "=");
|
||||
}
|
||||
if (!oe.parameter_needed) {
|
||||
this->m->completions.insert(base);
|
||||
m->completions.insert(base);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -662,8 +654,7 @@ QPDFArgParser::insertCompletions(
|
||||
{
|
||||
if (!choice_option.empty()) {
|
||||
addChoicesToCompletions(option_table, choice_option, extra_prefix);
|
||||
} else if (
|
||||
(!this->m->bash_cur.empty()) && (this->m->bash_cur.at(0) == '-')) {
|
||||
} else if ((!m->bash_cur.empty()) && (m->bash_cur.at(0) == '-')) {
|
||||
addOptionsToCompletions(option_table);
|
||||
}
|
||||
}
|
||||
@ -672,26 +663,24 @@ void
|
||||
QPDFArgParser::handleCompletion()
|
||||
{
|
||||
std::string extra_prefix;
|
||||
if (this->m->completions.empty()) {
|
||||
if (m->completions.empty()) {
|
||||
// Detect --option=... Bash treats the = as a word separator.
|
||||
std::string choice_option;
|
||||
if (this->m->bash_cur.empty() && (this->m->bash_prev.length() > 2) &&
|
||||
(this->m->bash_prev.at(0) == '-') &&
|
||||
(this->m->bash_prev.at(1) == '-') &&
|
||||
(this->m->bash_line.at(this->m->bash_line.length() - 1) == '=')) {
|
||||
choice_option = this->m->bash_prev.substr(2, std::string::npos);
|
||||
if (m->bash_cur.empty() && (m->bash_prev.length() > 2) &&
|
||||
(m->bash_prev.at(0) == '-') && (m->bash_prev.at(1) == '-') &&
|
||||
(m->bash_line.at(m->bash_line.length() - 1) == '=')) {
|
||||
choice_option = m->bash_prev.substr(2, std::string::npos);
|
||||
} else if (
|
||||
(this->m->bash_prev == "=") &&
|
||||
(this->m->bash_line.length() > (this->m->bash_cur.length() + 1))) {
|
||||
(m->bash_prev == "=") &&
|
||||
(m->bash_line.length() > (m->bash_cur.length() + 1))) {
|
||||
// We're sitting at --option=x. Find previous option.
|
||||
size_t end_mark =
|
||||
this->m->bash_line.length() - this->m->bash_cur.length() - 1;
|
||||
char before_cur = this->m->bash_line.at(end_mark);
|
||||
size_t end_mark = m->bash_line.length() - m->bash_cur.length() - 1;
|
||||
char before_cur = m->bash_line.at(end_mark);
|
||||
if (before_cur == '=') {
|
||||
size_t space = this->m->bash_line.find_last_of(' ', end_mark);
|
||||
size_t space = m->bash_line.find_last_of(' ', end_mark);
|
||||
if (space != std::string::npos) {
|
||||
std::string candidate = this->m->bash_line.substr(
|
||||
space + 1, end_mark - space - 1);
|
||||
std::string candidate =
|
||||
m->bash_line.substr(space + 1, end_mark - space - 1);
|
||||
if ((candidate.length() > 2) && (candidate.at(0) == '-') &&
|
||||
(candidate.at(1) == '-')) {
|
||||
choice_option = candidate.substr(2, std::string::npos);
|
||||
@ -699,19 +688,19 @@ QPDFArgParser::handleCompletion()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this->m->zsh_completion && (!choice_option.empty())) {
|
||||
if (m->zsh_completion && (!choice_option.empty())) {
|
||||
// zsh wants --option=choice rather than just choice
|
||||
extra_prefix = "--" + choice_option + "=";
|
||||
}
|
||||
insertCompletions(*this->m->option_table, choice_option, extra_prefix);
|
||||
if (this->m->argc == 1) {
|
||||
insertCompletions(*m->option_table, choice_option, extra_prefix);
|
||||
if (m->argc == 1) {
|
||||
// Help options are valid only by themselves.
|
||||
insertCompletions(
|
||||
this->m->help_option_table, choice_option, extra_prefix);
|
||||
m->help_option_table, choice_option, extra_prefix);
|
||||
}
|
||||
}
|
||||
std::string prefix = extra_prefix + this->m->bash_cur;
|
||||
for (auto const& iter: this->m->completions) {
|
||||
std::string prefix = extra_prefix + m->bash_cur;
|
||||
for (auto const& iter: m->completions) {
|
||||
if (prefix.empty() || (iter.substr(0, prefix.length()) == prefix)) {
|
||||
std::cout << iter << std::endl;
|
||||
}
|
||||
@ -722,7 +711,7 @@ QPDFArgParser::handleCompletion()
|
||||
void
|
||||
QPDFArgParser::addHelpFooter(std::string const& text)
|
||||
{
|
||||
this->m->help_footer = "\n" + text;
|
||||
m->help_footer = "\n" + text;
|
||||
}
|
||||
|
||||
void
|
||||
@ -741,14 +730,14 @@ QPDFArgParser::addHelpTopic(
|
||||
throw std::logic_error(
|
||||
"QPDFArgParser: help topics must not start with -");
|
||||
}
|
||||
if (this->m->help_topics.count(topic)) {
|
||||
if (m->help_topics.count(topic)) {
|
||||
QTC::TC("libtests", "QPDFArgParser add existing topic");
|
||||
throw std::logic_error(
|
||||
"QPDFArgParser: topic " + topic + " has already been added");
|
||||
}
|
||||
|
||||
this->m->help_topics[topic] = HelpTopic(short_text, long_text);
|
||||
this->m->help_option_table["help"].choices.insert(topic);
|
||||
m->help_topics[topic] = HelpTopic(short_text, long_text);
|
||||
m->help_option_table["help"].choices.insert(topic);
|
||||
}
|
||||
|
||||
void
|
||||
@ -764,35 +753,35 @@ QPDFArgParser::addOptionHelp(
|
||||
throw std::logic_error(
|
||||
"QPDFArgParser: options for help must start with --");
|
||||
}
|
||||
if (this->m->option_help.count(option_name)) {
|
||||
if (m->option_help.count(option_name)) {
|
||||
QTC::TC("libtests", "QPDFArgParser duplicate option help");
|
||||
throw std::logic_error(
|
||||
"QPDFArgParser: option " + option_name + " already has help");
|
||||
}
|
||||
auto ht = this->m->help_topics.find(topic);
|
||||
if (ht == this->m->help_topics.end()) {
|
||||
auto ht = m->help_topics.find(topic);
|
||||
if (ht == m->help_topics.end()) {
|
||||
QTC::TC("libtests", "QPDFArgParser add to unknown topic");
|
||||
throw std::logic_error(
|
||||
"QPDFArgParser: unable to add option " + option_name +
|
||||
" to unknown help topic " + topic);
|
||||
}
|
||||
this->m->option_help[option_name] = HelpTopic(short_text, long_text);
|
||||
m->option_help[option_name] = HelpTopic(short_text, long_text);
|
||||
ht->second.options.insert(option_name);
|
||||
this->m->help_option_table["help"].choices.insert(option_name);
|
||||
m->help_option_table["help"].choices.insert(option_name);
|
||||
}
|
||||
|
||||
void
|
||||
QPDFArgParser::getTopHelp(std::ostringstream& msg)
|
||||
{
|
||||
msg << "Run \"" << this->m->whoami << " --help=topic\" for help on a topic."
|
||||
msg << "Run \"" << m->whoami << " --help=topic\" for help on a topic."
|
||||
<< std::endl
|
||||
<< "Run \"" << m->whoami << " --help=--option\" for help on an option."
|
||||
<< std::endl
|
||||
<< "Run \"" << m->whoami << " --help=all\" to see all available help."
|
||||
<< std::endl
|
||||
<< "Run \"" << this->m->whoami
|
||||
<< " --help=--option\" for help on an option." << std::endl
|
||||
<< "Run \"" << this->m->whoami
|
||||
<< " --help=all\" to see all available help." << std::endl
|
||||
<< std::endl
|
||||
<< "Topics:" << std::endl;
|
||||
for (auto const& i: this->m->help_topics) {
|
||||
for (auto const& i: m->help_topics) {
|
||||
msg << " " << i.first << ": " << i.second.short_text << std::endl;
|
||||
}
|
||||
}
|
||||
@ -811,8 +800,8 @@ QPDFArgParser::getAllHelp(std::ostringstream& msg)
|
||||
getTopicHelp(topic, i.second, msg);
|
||||
}
|
||||
};
|
||||
show(this->m->help_topics);
|
||||
show(this->m->option_help);
|
||||
show(m->help_topics);
|
||||
show(m->option_help);
|
||||
msg << std::endl << "====" << std::endl;
|
||||
}
|
||||
|
||||
@ -828,7 +817,7 @@ QPDFArgParser::getTopicHelp(
|
||||
if (!ht.options.empty()) {
|
||||
msg << std::endl << "Related options:" << std::endl;
|
||||
for (auto const& i: ht.options) {
|
||||
msg << " " << i << ": " << this->m->option_help[i].short_text
|
||||
msg << " " << i << ": " << m->option_help[i].short_text
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
@ -843,15 +832,15 @@ QPDFArgParser::getHelp(std::string const& arg)
|
||||
} else {
|
||||
if (arg == "all") {
|
||||
getAllHelp(msg);
|
||||
} else if (this->m->option_help.count(arg)) {
|
||||
getTopicHelp(arg, this->m->option_help[arg], msg);
|
||||
} else if (this->m->help_topics.count(arg)) {
|
||||
getTopicHelp(arg, this->m->help_topics[arg], msg);
|
||||
} else if (m->option_help.count(arg)) {
|
||||
getTopicHelp(arg, m->option_help[arg], msg);
|
||||
} else if (m->help_topics.count(arg)) {
|
||||
getTopicHelp(arg, m->help_topics[arg], msg);
|
||||
} else {
|
||||
// should not be possible
|
||||
getTopHelp(msg);
|
||||
}
|
||||
}
|
||||
msg << this->m->help_footer;
|
||||
msg << m->help_footer;
|
||||
return msg.str();
|
||||
}
|
||||
|
@ -73,32 +73,32 @@ QPDFCryptoProvider::getInstance()
|
||||
std::shared_ptr<QPDFCryptoImpl>
|
||||
QPDFCryptoProvider::getImpl_internal(std::string const& name) const
|
||||
{
|
||||
auto iter = this->m->providers.find(name);
|
||||
if (iter == this->m->providers.end()) {
|
||||
auto iter = m->providers.find(name);
|
||||
if (iter == m->providers.end()) {
|
||||
throw std::logic_error(
|
||||
"QPDFCryptoProvider requested unknown implementation \"" + name +
|
||||
"\"");
|
||||
}
|
||||
return this->m->providers[name]();
|
||||
return m->providers[name]();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
QPDFCryptoProvider::registerImpl_internal(std::string const& name)
|
||||
{
|
||||
this->m->providers[name] = std::make_shared<T>;
|
||||
m->providers[name] = std::make_shared<T>;
|
||||
}
|
||||
|
||||
void
|
||||
QPDFCryptoProvider::setDefaultProvider_internal(std::string const& name)
|
||||
{
|
||||
if (!this->m->providers.count(name)) {
|
||||
if (!m->providers.count(name)) {
|
||||
throw std::logic_error(
|
||||
"QPDFCryptoProvider: request to set default"
|
||||
" provider to unknown implementation \"" +
|
||||
name + "\"");
|
||||
}
|
||||
this->m->default_provider = name;
|
||||
m->default_provider = name;
|
||||
}
|
||||
|
||||
std::set<std::string>
|
||||
|
@ -40,9 +40,8 @@ QPDFEmbeddedFileDocumentHelper::QPDFEmbeddedFileDocumentHelper(QPDF& qpdf) :
|
||||
if (names.isDictionary()) {
|
||||
auto embedded_files = names.getKey("/EmbeddedFiles");
|
||||
if (embedded_files.isDictionary()) {
|
||||
this->m->embedded_files =
|
||||
std::make_shared<QPDFNameTreeObjectHelper>(
|
||||
embedded_files, qpdf);
|
||||
m->embedded_files = std::make_shared<QPDFNameTreeObjectHelper>(
|
||||
embedded_files, qpdf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -50,7 +49,7 @@ QPDFEmbeddedFileDocumentHelper::QPDFEmbeddedFileDocumentHelper(QPDF& qpdf) :
|
||||
bool
|
||||
QPDFEmbeddedFileDocumentHelper::hasEmbeddedFiles() const
|
||||
{
|
||||
return (this->m->embedded_files != nullptr);
|
||||
return (m->embedded_files != nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
@ -69,8 +68,7 @@ QPDFEmbeddedFileDocumentHelper::initEmbeddedFiles()
|
||||
if (!embedded_files.isDictionary()) {
|
||||
auto nth = QPDFNameTreeObjectHelper::newEmpty(this->qpdf);
|
||||
names.replaceKey("/EmbeddedFiles", nth.getObjectHandle());
|
||||
this->m->embedded_files =
|
||||
std::make_shared<QPDFNameTreeObjectHelper>(nth);
|
||||
m->embedded_files = std::make_shared<QPDFNameTreeObjectHelper>(nth);
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,9 +76,9 @@ std::shared_ptr<QPDFFileSpecObjectHelper>
|
||||
QPDFEmbeddedFileDocumentHelper::getEmbeddedFile(std::string const& name)
|
||||
{
|
||||
std::shared_ptr<QPDFFileSpecObjectHelper> result;
|
||||
if (this->m->embedded_files) {
|
||||
auto i = this->m->embedded_files->find(name);
|
||||
if (i != this->m->embedded_files->end()) {
|
||||
if (m->embedded_files) {
|
||||
auto i = m->embedded_files->find(name);
|
||||
if (i != m->embedded_files->end()) {
|
||||
result = std::make_shared<QPDFFileSpecObjectHelper>(i->second);
|
||||
}
|
||||
}
|
||||
@ -91,8 +89,8 @@ std::map<std::string, std::shared_ptr<QPDFFileSpecObjectHelper>>
|
||||
QPDFEmbeddedFileDocumentHelper::getEmbeddedFiles()
|
||||
{
|
||||
std::map<std::string, std::shared_ptr<QPDFFileSpecObjectHelper>> result;
|
||||
if (this->m->embedded_files) {
|
||||
for (auto const& i: *(this->m->embedded_files)) {
|
||||
if (m->embedded_files) {
|
||||
for (auto const& i: *(m->embedded_files)) {
|
||||
result[i.first] =
|
||||
std::make_shared<QPDFFileSpecObjectHelper>(i.second);
|
||||
}
|
||||
@ -105,7 +103,7 @@ QPDFEmbeddedFileDocumentHelper::replaceEmbeddedFile(
|
||||
std::string const& name, QPDFFileSpecObjectHelper const& fs)
|
||||
{
|
||||
initEmbeddedFiles();
|
||||
this->m->embedded_files->insert(name, fs.getObjectHandle());
|
||||
m->embedded_files->insert(name, fs.getObjectHandle());
|
||||
}
|
||||
|
||||
bool
|
||||
@ -114,8 +112,8 @@ QPDFEmbeddedFileDocumentHelper::removeEmbeddedFile(std::string const& name)
|
||||
if (!hasEmbeddedFiles()) {
|
||||
return false;
|
||||
}
|
||||
auto iter = this->m->embedded_files->find(name);
|
||||
if (iter == this->m->embedded_files->end()) {
|
||||
auto iter = m->embedded_files->find(name);
|
||||
if (iter == m->embedded_files->end()) {
|
||||
return false;
|
||||
}
|
||||
auto oh = iter->second;
|
||||
|
@ -323,46 +323,46 @@ QPDFJob::usage(std::string const& msg)
|
||||
void
|
||||
QPDFJob::setMessagePrefix(std::string const& message_prefix)
|
||||
{
|
||||
this->m->message_prefix = message_prefix;
|
||||
m->message_prefix = message_prefix;
|
||||
}
|
||||
|
||||
std::string
|
||||
QPDFJob::getMessagePrefix() const
|
||||
{
|
||||
return this->m->message_prefix;
|
||||
return m->message_prefix;
|
||||
}
|
||||
|
||||
std::shared_ptr<QPDFLogger>
|
||||
QPDFJob::getLogger()
|
||||
{
|
||||
return this->m->log;
|
||||
return m->log;
|
||||
}
|
||||
|
||||
void
|
||||
QPDFJob::setLogger(std::shared_ptr<QPDFLogger> l)
|
||||
{
|
||||
this->m->log = l;
|
||||
m->log = l;
|
||||
}
|
||||
|
||||
void
|
||||
QPDFJob::setOutputStreams(std::ostream* out, std::ostream* err)
|
||||
{
|
||||
setLogger(QPDFLogger::create());
|
||||
this->m->log->setOutputStreams(out, err);
|
||||
m->log->setOutputStreams(out, err);
|
||||
}
|
||||
|
||||
void
|
||||
QPDFJob::registerProgressReporter(std::function<void(int)> handler)
|
||||
{
|
||||
this->m->progress_handler = handler;
|
||||
m->progress_handler = handler;
|
||||
}
|
||||
|
||||
void
|
||||
QPDFJob::doIfVerbose(
|
||||
std::function<void(Pipeline&, std::string const& prefix)> fn)
|
||||
{
|
||||
if (this->m->verbose) {
|
||||
fn(*this->m->log->getInfo(), this->m->message_prefix);
|
||||
if (m->verbose) {
|
||||
fn(*m->log->getInfo(), m->message_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
@ -459,12 +459,12 @@ QPDFJob::createQPDF()
|
||||
// Allow certain operations to work when an incorrect
|
||||
// password is supplied.
|
||||
if (m->check_is_encrypted || m->check_requires_password) {
|
||||
this->m->encryption_status =
|
||||
m->encryption_status =
|
||||
qpdf_es_encrypted | qpdf_es_password_incorrect;
|
||||
return nullptr;
|
||||
}
|
||||
if (m->show_encryption && pdf_sp) {
|
||||
this->m->log->info("Incorrect password supplied\n");
|
||||
m->log->info("Incorrect password supplied\n");
|
||||
showEncryption(*pdf_sp);
|
||||
return nullptr;
|
||||
}
|
||||
@ -473,7 +473,7 @@ QPDFJob::createQPDF()
|
||||
}
|
||||
QPDF& pdf = *pdf_sp;
|
||||
if (pdf.isEncrypted()) {
|
||||
this->m->encryption_status = qpdf_es_encrypted;
|
||||
m->encryption_status = qpdf_es_encrypted;
|
||||
}
|
||||
|
||||
if (m->check_is_encrypted || m->check_requires_password) {
|
||||
@ -482,8 +482,8 @@ QPDFJob::createQPDF()
|
||||
|
||||
// If we are updating from JSON, this has to be done first before
|
||||
// other options may cause transformations to the input.
|
||||
if (!this->m->update_from_json.empty()) {
|
||||
pdf.updateFromJSON(this->m->update_from_json);
|
||||
if (!m->update_from_json.empty()) {
|
||||
pdf.updateFromJSON(m->update_from_json);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<QPDF>> page_heap;
|
||||
@ -509,17 +509,16 @@ QPDFJob::writeQPDF(QPDF& pdf)
|
||||
writeOutfile(pdf);
|
||||
}
|
||||
if (!pdf.getWarnings().empty()) {
|
||||
this->m->warnings = true;
|
||||
m->warnings = true;
|
||||
}
|
||||
if (this->m->warnings && (!this->m->suppress_warnings)) {
|
||||
if (m->warnings && (!m->suppress_warnings)) {
|
||||
if (createsOutput()) {
|
||||
*this->m->log->getWarn()
|
||||
<< this->m->message_prefix
|
||||
<< ": operation succeeded with warnings;"
|
||||
*m->log->getWarn()
|
||||
<< m->message_prefix << ": operation succeeded with warnings;"
|
||||
<< " resulting file may have some problems\n";
|
||||
} else {
|
||||
*this->m->log->getWarn() << this->m->message_prefix
|
||||
<< ": operation succeeded with warnings\n";
|
||||
*m->log->getWarn()
|
||||
<< m->message_prefix << ": operation succeeded with warnings\n";
|
||||
}
|
||||
}
|
||||
if (m->report_mem_usage) {
|
||||
@ -527,8 +526,7 @@ QPDFJob::writeQPDF(QPDF& pdf)
|
||||
// debugging, it's easier if print statements from
|
||||
// get_max_memory_usage are not interleaved with the output.
|
||||
auto mem_usage = QUtil::get_max_memory_usage();
|
||||
*this->m->log->getWarn()
|
||||
<< "qpdf-max-memory-usage " << mem_usage << "\n";
|
||||
*m->log->getWarn() << "qpdf-max-memory-usage " << mem_usage << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@ -544,7 +542,7 @@ QPDFJob::run()
|
||||
bool
|
||||
QPDFJob::hasWarnings() const
|
||||
{
|
||||
return this->m->warnings;
|
||||
return m->warnings;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -556,17 +554,17 @@ QPDFJob::createsOutput() const
|
||||
int
|
||||
QPDFJob::getExitCode() const
|
||||
{
|
||||
if (this->m->check_is_encrypted) {
|
||||
if (this->m->encryption_status & qpdf_es_encrypted) {
|
||||
if (m->check_is_encrypted) {
|
||||
if (m->encryption_status & qpdf_es_encrypted) {
|
||||
QTC::TC("qpdf", "QPDFJob check encrypted encrypted");
|
||||
return 0;
|
||||
} else {
|
||||
QTC::TC("qpdf", "QPDFJob check encrypted not encrypted");
|
||||
return EXIT_IS_NOT_ENCRYPTED;
|
||||
}
|
||||
} else if (this->m->check_requires_password) {
|
||||
if (this->m->encryption_status & qpdf_es_encrypted) {
|
||||
if (this->m->encryption_status & qpdf_es_password_incorrect) {
|
||||
} else if (m->check_requires_password) {
|
||||
if (m->encryption_status & qpdf_es_encrypted) {
|
||||
if (m->encryption_status & qpdf_es_password_incorrect) {
|
||||
QTC::TC("qpdf", "QPDFJob check password password incorrect");
|
||||
return 0;
|
||||
} else {
|
||||
@ -579,7 +577,7 @@ QPDFJob::getExitCode() const
|
||||
}
|
||||
}
|
||||
|
||||
if (this->m->warnings && (!this->m->warnings_exit_zero)) {
|
||||
if (m->warnings && (!m->warnings_exit_zero)) {
|
||||
return EXIT_WARNING;
|
||||
}
|
||||
return 0;
|
||||
@ -656,7 +654,7 @@ QPDFJob::checkConfiguration()
|
||||
save_to_stdout = true;
|
||||
}
|
||||
if (save_to_stdout) {
|
||||
this->m->log->saveToStandardOutput(true);
|
||||
m->log->saveToStandardOutput(true);
|
||||
}
|
||||
if ((!m->split_pages) &&
|
||||
QUtil::same_file(m->infilename.get(), m->outfilename.get())) {
|
||||
@ -681,13 +679,13 @@ QPDFJob::checkConfiguration()
|
||||
unsigned long
|
||||
QPDFJob::getEncryptionStatus()
|
||||
{
|
||||
return this->m->encryption_status;
|
||||
return m->encryption_status;
|
||||
}
|
||||
|
||||
void
|
||||
QPDFJob::setQPDFOptions(QPDF& pdf)
|
||||
{
|
||||
pdf.setLogger(this->m->log);
|
||||
pdf.setLogger(m->log);
|
||||
if (m->ignore_xref_streams) {
|
||||
pdf.setIgnoreXRefStreams(true);
|
||||
}
|
||||
@ -743,7 +741,7 @@ QPDFJob::showEncryption(QPDF& pdf)
|
||||
QPDF::encryption_method_e stream_method = QPDF::e_unknown;
|
||||
QPDF::encryption_method_e string_method = QPDF::e_unknown;
|
||||
QPDF::encryption_method_e file_method = QPDF::e_unknown;
|
||||
auto& cout = *this->m->log->getInfo();
|
||||
auto& cout = *m->log->getInfo();
|
||||
if (!pdf.isEncrypted(R, P, V, stream_method, string_method, file_method)) {
|
||||
cout << "File is not encrypted\n";
|
||||
} else {
|
||||
@ -796,7 +794,7 @@ QPDFJob::doCheck(QPDF& pdf)
|
||||
// continue to perform additional checks after finding
|
||||
// errors.
|
||||
bool okay = true;
|
||||
auto& cout = *this->m->log->getInfo();
|
||||
auto& cout = *m->log->getInfo();
|
||||
cout << "checking " << m->infilename.get() << "\n";
|
||||
QPDF::JobSetter::setCheckMode(pdf, true);
|
||||
try {
|
||||
@ -832,12 +830,12 @@ QPDFJob::doCheck(QPDF& pdf)
|
||||
page.parseContents(&discard_contents);
|
||||
} catch (QPDFExc& e) {
|
||||
okay = false;
|
||||
*this->m->log->getError()
|
||||
*m->log->getError()
|
||||
<< "ERROR: page " << pageno << ": " << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
*this->m->log->getError() << "ERROR: " << e.what() << "\n";
|
||||
*m->log->getError() << "ERROR: " << e.what() << "\n";
|
||||
okay = false;
|
||||
}
|
||||
if (!okay) {
|
||||
@ -845,11 +843,11 @@ QPDFJob::doCheck(QPDF& pdf)
|
||||
}
|
||||
|
||||
if (!pdf.getWarnings().empty()) {
|
||||
this->m->warnings = true;
|
||||
m->warnings = true;
|
||||
} else {
|
||||
*this->m->log->getInfo() << "No syntax or stream encoding errors"
|
||||
<< " found; the file may still contain\n"
|
||||
<< "errors that qpdf cannot detect\n";
|
||||
*m->log->getInfo() << "No syntax or stream encoding errors"
|
||||
<< " found; the file may still contain\n"
|
||||
<< "errors that qpdf cannot detect\n";
|
||||
}
|
||||
}
|
||||
|
||||
@ -873,18 +871,18 @@ QPDFJob::doShowObj(QPDF& pdf)
|
||||
} else {
|
||||
// If anything has been written to standard output,
|
||||
// this will fail.
|
||||
this->m->log->saveToStandardOutput(true);
|
||||
m->log->saveToStandardOutput(true);
|
||||
obj.pipeStreamData(
|
||||
this->m->log->getSave().get(),
|
||||
m->log->getSave().get(),
|
||||
(filter && m->normalize) ? qpdf_ef_normalize : 0,
|
||||
filter ? qpdf_dl_all : qpdf_dl_none);
|
||||
}
|
||||
} else {
|
||||
*this->m->log->getInfo() << "Object is stream. Dictionary:\n"
|
||||
<< obj.getDict().unparseResolved() << "\n";
|
||||
*m->log->getInfo() << "Object is stream. Dictionary:\n"
|
||||
<< obj.getDict().unparseResolved() << "\n";
|
||||
}
|
||||
} else {
|
||||
*this->m->log->getInfo() << obj.unparseResolved() << "\n";
|
||||
*m->log->getInfo() << obj.unparseResolved() << "\n";
|
||||
}
|
||||
if (error) {
|
||||
throw std::runtime_error(
|
||||
@ -896,7 +894,7 @@ void
|
||||
QPDFJob::doShowPages(QPDF& pdf)
|
||||
{
|
||||
int pageno = 0;
|
||||
auto& cout = *this->m->log->getInfo();
|
||||
auto& cout = *m->log->getInfo();
|
||||
for (auto& ph: QPDFPageDocumentHelper(pdf).getAllPages()) {
|
||||
QPDFObjectHandle page = ph.getObjectHandle();
|
||||
++pageno;
|
||||
@ -934,7 +932,7 @@ QPDFJob::doListAttachments(QPDF& pdf)
|
||||
for (auto const& i: efdh.getEmbeddedFiles()) {
|
||||
std::string const& key = i.first;
|
||||
auto efoh = i.second;
|
||||
*this->m->log->getInfo()
|
||||
*m->log->getInfo()
|
||||
<< key << " -> "
|
||||
<< efoh->getEmbeddedFileStream().getObjGen().unparse(',')
|
||||
<< "\n";
|
||||
@ -963,8 +961,7 @@ QPDFJob::doListAttachments(QPDF& pdf)
|
||||
});
|
||||
}
|
||||
} else {
|
||||
*this->m->log->getInfo()
|
||||
<< m->infilename.get() << " has no embedded files\n";
|
||||
*m->log->getInfo() << m->infilename.get() << " has no embedded files\n";
|
||||
}
|
||||
}
|
||||
|
||||
@ -980,8 +977,8 @@ QPDFJob::doShowAttachment(QPDF& pdf)
|
||||
auto efs = fs->getEmbeddedFileStream();
|
||||
// saveToStandardOutput has already been called, but it's harmless
|
||||
// to call it again, so do as defensive coding.
|
||||
this->m->log->saveToStandardOutput(true);
|
||||
efs.pipeStreamData(this->m->log->getSave().get(), 0, qpdf_dl_all);
|
||||
m->log->saveToStandardOutput(true);
|
||||
efs.pipeStreamData(m->log->getSave().get(), 0, qpdf_dl_all);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1019,17 +1016,16 @@ void
|
||||
QPDFJob::doJSONObject(
|
||||
Pipeline* p, bool& first, std::string const& key, QPDFObjectHandle& obj)
|
||||
{
|
||||
if (this->m->json_version == 1) {
|
||||
if (m->json_version == 1) {
|
||||
JSON::writeDictionaryItem(p, first, key, obj.getJSON(1, true), 2);
|
||||
} else {
|
||||
auto j = JSON::makeDictionary();
|
||||
if (obj.isStream()) {
|
||||
j.addDictionaryMember("stream", JSON::makeDictionary())
|
||||
.addDictionaryMember(
|
||||
"dict", obj.getDict().getJSON(this->m->json_version, true));
|
||||
"dict", obj.getDict().getJSON(m->json_version, true));
|
||||
} else {
|
||||
j.addDictionaryMember(
|
||||
"value", obj.getJSON(this->m->json_version, true));
|
||||
j.addDictionaryMember("value", obj.getJSON(m->json_version, true));
|
||||
}
|
||||
JSON::writeDictionaryItem(p, first, key, j, 2);
|
||||
}
|
||||
@ -1046,7 +1042,7 @@ QPDFJob::doJSONObjects(Pipeline* p, bool& first, QPDF& pdf)
|
||||
auto wanted_og = getWantedJSONObjects();
|
||||
for (auto& obj: pdf.getAllObjects()) {
|
||||
std::string key = obj.unparse();
|
||||
if (this->m->json_version > 1) {
|
||||
if (m->json_version > 1) {
|
||||
key = "obj:" + key;
|
||||
}
|
||||
if (all_objects || wanted_og.count(obj.getObjGen())) {
|
||||
@ -1060,20 +1056,20 @@ QPDFJob::doJSONObjects(Pipeline* p, bool& first, QPDF& pdf)
|
||||
JSON::writeDictionaryClose(p, first_object, 1);
|
||||
} else {
|
||||
std::set<std::string> json_objects;
|
||||
if (this->m->json_objects.count("trailer")) {
|
||||
if (m->json_objects.count("trailer")) {
|
||||
json_objects.insert("trailer");
|
||||
}
|
||||
for (auto og: getWantedJSONObjects()) {
|
||||
json_objects.emplace("obj:" + og.unparse(' ') + " R");
|
||||
}
|
||||
pdf.writeJSON(
|
||||
this->m->json_version,
|
||||
m->json_version,
|
||||
p,
|
||||
false,
|
||||
first,
|
||||
this->m->decode_level,
|
||||
this->m->json_stream_data,
|
||||
this->m->json_stream_prefix,
|
||||
m->decode_level,
|
||||
m->json_stream_data,
|
||||
m->json_stream_prefix,
|
||||
json_objects);
|
||||
}
|
||||
}
|
||||
@ -1096,12 +1092,12 @@ QPDFJob::doJSONObjectinfo(Pipeline* p, bool& first, QPDF& pdf)
|
||||
j_stream.addDictionaryMember(
|
||||
"length",
|
||||
(is_stream ? obj.getDict().getKey("/Length").getJSON(
|
||||
this->m->json_version, true)
|
||||
m->json_version, true)
|
||||
: JSON::makeNull()));
|
||||
j_stream.addDictionaryMember(
|
||||
"filter",
|
||||
(is_stream ? obj.getDict().getKey("/Filter").getJSON(
|
||||
this->m->json_version, true)
|
||||
m->json_version, true)
|
||||
: JSON::makeNull()));
|
||||
JSON::writeDictionaryItem(
|
||||
p, first_object, obj.unparse(), j_details, 2);
|
||||
@ -1123,8 +1119,7 @@ QPDFJob::doJSONPages(Pipeline* p, bool& first, QPDF& pdf)
|
||||
++pageno;
|
||||
JSON j_page = JSON::makeDictionary();
|
||||
QPDFObjectHandle page = ph.getObjectHandle();
|
||||
j_page.addDictionaryMember(
|
||||
"object", page.getJSON(this->m->json_version));
|
||||
j_page.addDictionaryMember("object", page.getJSON(m->json_version));
|
||||
JSON j_images = j_page.addDictionaryMember("images", JSON::makeArray());
|
||||
for (auto const& iter2: ph.getImages()) {
|
||||
JSON j_image = j_images.addArrayElement(JSON::makeDictionary());
|
||||
@ -1132,22 +1127,20 @@ QPDFJob::doJSONPages(Pipeline* p, bool& first, QPDF& pdf)
|
||||
QPDFObjectHandle image = iter2.second;
|
||||
QPDFObjectHandle dict = image.getDict();
|
||||
j_image.addDictionaryMember(
|
||||
"object", image.getJSON(this->m->json_version));
|
||||
"object", image.getJSON(m->json_version));
|
||||
j_image.addDictionaryMember(
|
||||
"width", dict.getKey("/Width").getJSON(this->m->json_version));
|
||||
"width", dict.getKey("/Width").getJSON(m->json_version));
|
||||
j_image.addDictionaryMember(
|
||||
"height",
|
||||
dict.getKey("/Height").getJSON(this->m->json_version));
|
||||
"height", dict.getKey("/Height").getJSON(m->json_version));
|
||||
j_image.addDictionaryMember(
|
||||
"colorspace",
|
||||
dict.getKey("/ColorSpace").getJSON(this->m->json_version));
|
||||
dict.getKey("/ColorSpace").getJSON(m->json_version));
|
||||
j_image.addDictionaryMember(
|
||||
"bitspercomponent",
|
||||
dict.getKey("/BitsPerComponent")
|
||||
.getJSON(this->m->json_version));
|
||||
dict.getKey("/BitsPerComponent").getJSON(m->json_version));
|
||||
QPDFObjectHandle filters = dict.getKey("/Filter").wrapInArray();
|
||||
j_image.addDictionaryMember(
|
||||
"filter", filters.getJSON(this->m->json_version));
|
||||
"filter", filters.getJSON(m->json_version));
|
||||
QPDFObjectHandle decode_parms = dict.getKey("/DecodeParms");
|
||||
QPDFObjectHandle dp_array;
|
||||
if (decode_parms.isArray()) {
|
||||
@ -1159,7 +1152,7 @@ QPDFJob::doJSONPages(Pipeline* p, bool& first, QPDF& pdf)
|
||||
}
|
||||
}
|
||||
j_image.addDictionaryMember(
|
||||
"decodeparms", dp_array.getJSON(this->m->json_version));
|
||||
"decodeparms", dp_array.getJSON(m->json_version));
|
||||
j_image.addDictionaryMember(
|
||||
"filterable",
|
||||
JSON::makeBool(
|
||||
@ -1169,11 +1162,10 @@ QPDFJob::doJSONPages(Pipeline* p, bool& first, QPDF& pdf)
|
||||
JSON j_contents =
|
||||
j_page.addDictionaryMember("contents", JSON::makeArray());
|
||||
for (auto& iter2: ph.getPageContents()) {
|
||||
j_contents.addArrayElement(iter2.getJSON(this->m->json_version));
|
||||
j_contents.addArrayElement(iter2.getJSON(m->json_version));
|
||||
}
|
||||
j_page.addDictionaryMember(
|
||||
"label",
|
||||
pldh.getLabelForPage(pageno).getJSON(this->m->json_version));
|
||||
"label", pldh.getLabelForPage(pageno).getJSON(m->json_version));
|
||||
JSON j_outlines =
|
||||
j_page.addDictionaryMember("outlines", JSON::makeArray());
|
||||
std::vector<QPDFOutlineObjectHelper> outlines =
|
||||
@ -1181,12 +1173,11 @@ QPDFJob::doJSONPages(Pipeline* p, bool& first, QPDF& pdf)
|
||||
for (auto& oiter: outlines) {
|
||||
JSON j_outline = j_outlines.addArrayElement(JSON::makeDictionary());
|
||||
j_outline.addDictionaryMember(
|
||||
"object",
|
||||
oiter.getObjectHandle().getJSON(this->m->json_version));
|
||||
"object", oiter.getObjectHandle().getJSON(m->json_version));
|
||||
j_outline.addDictionaryMember(
|
||||
"title", JSON::makeString(oiter.getTitle()));
|
||||
j_outline.addDictionaryMember(
|
||||
"dest", oiter.getDest().getJSON(this->m->json_version, true));
|
||||
"dest", oiter.getDest().getJSON(m->json_version, true));
|
||||
}
|
||||
j_page.addDictionaryMember("pageposfrom1", JSON::makeInt(1 + pageno));
|
||||
JSON::writeArrayItem(p, first_page, j_page, 2);
|
||||
@ -1213,10 +1204,10 @@ QPDFJob::doJSONPageLabels(Pipeline* p, bool& first, QPDF& pdf)
|
||||
}
|
||||
JSON j_label = j_labels.addArrayElement(JSON::makeDictionary());
|
||||
j_label.addDictionaryMember(
|
||||
"index", (*iter).getJSON(this->m->json_version));
|
||||
"index", (*iter).getJSON(m->json_version));
|
||||
++iter;
|
||||
j_label.addDictionaryMember(
|
||||
"label", (*iter).getJSON(this->m->json_version));
|
||||
"label", (*iter).getJSON(m->json_version));
|
||||
}
|
||||
}
|
||||
JSON::writeDictionaryItem(p, first, "pagelabels", j_labels, 1);
|
||||
@ -1231,10 +1222,10 @@ QPDFJob::addOutlinesToJson(
|
||||
for (auto& ol: outlines) {
|
||||
JSON jo = j.addArrayElement(JSON::makeDictionary());
|
||||
jo.addDictionaryMember(
|
||||
"object", ol.getObjectHandle().getJSON(this->m->json_version));
|
||||
"object", ol.getObjectHandle().getJSON(m->json_version));
|
||||
jo.addDictionaryMember("title", JSON::makeString(ol.getTitle()));
|
||||
jo.addDictionaryMember(
|
||||
"dest", ol.getDest().getJSON(this->m->json_version, true));
|
||||
"dest", ol.getDest().getJSON(m->json_version, true));
|
||||
jo.addDictionaryMember("open", JSON::makeBool(ol.getCount() >= 0));
|
||||
QPDFObjectHandle page = ol.getDestPage();
|
||||
JSON j_destpage = JSON::makeNull();
|
||||
@ -1283,11 +1274,11 @@ QPDFJob::doJSONAcroform(Pipeline* p, bool& first, QPDF& pdf)
|
||||
QPDFFormFieldObjectHelper ffh = afdh.getFieldForAnnotation(aoh);
|
||||
JSON j_field = j_fields.addArrayElement(JSON::makeDictionary());
|
||||
j_field.addDictionaryMember(
|
||||
"object", ffh.getObjectHandle().getJSON(this->m->json_version));
|
||||
"object", ffh.getObjectHandle().getJSON(m->json_version));
|
||||
j_field.addDictionaryMember(
|
||||
"parent",
|
||||
ffh.getObjectHandle().getKey("/Parent").getJSON(
|
||||
this->m->json_version));
|
||||
m->json_version));
|
||||
j_field.addDictionaryMember(
|
||||
"pageposfrom1", JSON::makeInt(pagepos1));
|
||||
j_field.addDictionaryMember(
|
||||
@ -1303,10 +1294,9 @@ QPDFJob::doJSONAcroform(Pipeline* p, bool& first, QPDF& pdf)
|
||||
j_field.addDictionaryMember(
|
||||
"mappingname", JSON::makeString(ffh.getMappingName()));
|
||||
j_field.addDictionaryMember(
|
||||
"value", ffh.getValue().getJSON(this->m->json_version));
|
||||
"value", ffh.getValue().getJSON(m->json_version));
|
||||
j_field.addDictionaryMember(
|
||||
"defaultvalue",
|
||||
ffh.getDefaultValue().getJSON(this->m->json_version));
|
||||
"defaultvalue", ffh.getDefaultValue().getJSON(m->json_version));
|
||||
j_field.addDictionaryMember(
|
||||
"quadding", JSON::makeInt(ffh.getQuadding()));
|
||||
j_field.addDictionaryMember(
|
||||
@ -1324,7 +1314,7 @@ QPDFJob::doJSONAcroform(Pipeline* p, bool& first, QPDF& pdf)
|
||||
JSON j_annot = j_field.addDictionaryMember(
|
||||
"annotation", JSON::makeDictionary());
|
||||
j_annot.addDictionaryMember(
|
||||
"object", aoh.getObjectHandle().getJSON(this->m->json_version));
|
||||
"object", aoh.getObjectHandle().getJSON(m->json_version));
|
||||
j_annot.addDictionaryMember(
|
||||
"appearancestate", JSON::makeString(aoh.getAppearanceState()));
|
||||
j_annot.addDictionaryMember(
|
||||
@ -1378,8 +1368,7 @@ QPDFJob::doJSONEncrypt(Pipeline* p, bool& first, QPDF& pdf)
|
||||
"modifyforms", JSON::makeBool(pdf.allowModifyForm()));
|
||||
/* cSpell:ignore moddifyannotations */
|
||||
std::string MODIFY_ANNOTATIONS =
|
||||
(this->m->json_version == 1 ? "moddifyannotations"
|
||||
: "modifyannotations");
|
||||
(m->json_version == 1 ? "moddifyannotations" : "modifyannotations");
|
||||
j_capabilities.addDictionaryMember(
|
||||
MODIFY_ANNOTATIONS, JSON::makeBool(pdf.allowModifyAnnotation()));
|
||||
j_capabilities.addDictionaryMember(
|
||||
@ -1722,7 +1711,7 @@ QPDFJob::doJSON(QPDF& pdf, Pipeline* p)
|
||||
|
||||
std::string captured_json;
|
||||
std::shared_ptr<Pl_String> pl_str;
|
||||
if (this->m->test_json_schema) {
|
||||
if (m->test_json_schema) {
|
||||
pl_str = std::make_shared<Pl_String>("capture json", p, captured_json);
|
||||
p = pl_str.get();
|
||||
}
|
||||
@ -1740,7 +1729,7 @@ QPDFJob::doJSON(QPDF& pdf, Pipeline* p)
|
||||
// ignore unrecognized keys, so we only update the version of a
|
||||
// key disappears or if its value changes meaning.
|
||||
JSON::writeDictionaryItem(
|
||||
p, first, "version", JSON::makeInt(this->m->json_version), 1);
|
||||
p, first, "version", JSON::makeInt(m->json_version), 1);
|
||||
JSON j_params = JSON::makeDictionary();
|
||||
std::string decode_level_str;
|
||||
switch (m->decode_level) {
|
||||
@ -1799,7 +1788,7 @@ QPDFJob::doJSON(QPDF& pdf, Pipeline* p)
|
||||
m->json_keys.count("qpdf")) {
|
||||
doJSONObjects(p, first, pdf);
|
||||
}
|
||||
if (this->m->json_version == 1) {
|
||||
if (m->json_version == 1) {
|
||||
// "objectinfo" is not needed for version >1 since you can
|
||||
// tell streams from other objects in "objects".
|
||||
if (all_keys || m->json_keys.count("objectinfo")) {
|
||||
@ -1810,16 +1799,16 @@ QPDFJob::doJSON(QPDF& pdf, Pipeline* p)
|
||||
JSON::writeDictionaryClose(p, first, 0);
|
||||
*p << "\n";
|
||||
|
||||
if (this->m->test_json_schema) {
|
||||
if (m->test_json_schema) {
|
||||
// Check against schema
|
||||
JSON schema = json_schema(this->m->json_version, &m->json_keys);
|
||||
JSON schema = json_schema(m->json_version, &m->json_keys);
|
||||
std::list<std::string> errors;
|
||||
JSON captured = JSON::parse(captured_json);
|
||||
if (!captured.checkSchema(schema, errors)) {
|
||||
this->m->log->error("QPDFJob didn't create JSON that complies with "
|
||||
"its own rules.\n");
|
||||
m->log->error("QPDFJob didn't create JSON that complies with "
|
||||
"its own rules.\n");
|
||||
for (auto const& error: errors) {
|
||||
*this->m->log->getError() << error << "\n";
|
||||
*m->log->getError() << error << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1828,7 +1817,7 @@ QPDFJob::doJSON(QPDF& pdf, Pipeline* p)
|
||||
void
|
||||
QPDFJob::doInspection(QPDF& pdf)
|
||||
{
|
||||
auto& cout = *this->m->log->getInfo();
|
||||
auto& cout = *m->log->getInfo();
|
||||
if (m->check) {
|
||||
doCheck(pdf);
|
||||
}
|
||||
@ -1846,7 +1835,7 @@ QPDFJob::doInspection(QPDF& pdf)
|
||||
} else if (pdf.checkLinearization()) {
|
||||
cout << m->infilename.get() << ": no linearization errors\n";
|
||||
} else {
|
||||
this->m->warnings = true;
|
||||
m->warnings = true;
|
||||
}
|
||||
}
|
||||
if (m->show_linearization) {
|
||||
@ -1872,7 +1861,7 @@ QPDFJob::doInspection(QPDF& pdf)
|
||||
doShowAttachment(pdf);
|
||||
}
|
||||
if (!pdf.getWarnings().empty()) {
|
||||
this->m->warnings = true;
|
||||
m->warnings = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1889,14 +1878,13 @@ QPDFJob::doProcessOnce(
|
||||
setQPDFOptions(*pdf);
|
||||
if (empty) {
|
||||
pdf->emptyPDF();
|
||||
} else if (main_input && this->m->json_input) {
|
||||
pdf->createFromJSON(this->m->infilename.get());
|
||||
} else if (main_input && m->json_input) {
|
||||
pdf->createFromJSON(m->infilename.get());
|
||||
} else {
|
||||
fn(pdf.get(), password);
|
||||
}
|
||||
if (used_for_input) {
|
||||
this->m->max_input_version.updateIfGreater(
|
||||
pdf->getVersionAsPDFVersion());
|
||||
m->max_input_version.updateIfGreater(pdf->getVersionAsPDFVersion());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2314,7 +2302,7 @@ QPDFJob::copyAttachments(QPDF& pdf)
|
||||
}
|
||||
|
||||
if (other->anyWarnings()) {
|
||||
this->m->warnings = true;
|
||||
m->warnings = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2917,8 +2905,8 @@ QPDFJob::maybeFixWritePassword(int R, std::string& password)
|
||||
password = encoded;
|
||||
} else {
|
||||
QTC::TC("qpdf", "QPDFJob bytes fallback warning");
|
||||
*this->m->log->getError()
|
||||
<< this->m->message_prefix << ": WARNING: "
|
||||
*m->log->getError()
|
||||
<< m->message_prefix << ": WARNING: "
|
||||
<< "supplied password looks like a Unicode"
|
||||
<< " password with characters not allowed in"
|
||||
<< " passwords for 40-bit and 128-bit "
|
||||
@ -2965,17 +2953,17 @@ QPDFJob::setEncryptionOptions(QPDF& pdf, QPDFWriter& w)
|
||||
throw std::logic_error("bad encryption keylen");
|
||||
}
|
||||
if ((R > 3) && (m->r3_accessibility == false)) {
|
||||
*this->m->log->getError() << this->m->message_prefix
|
||||
<< ": -accessibility=n is ignored for modern"
|
||||
<< " encryption formats\n";
|
||||
*m->log->getError()
|
||||
<< m->message_prefix << ": -accessibility=n is ignored for modern"
|
||||
<< " encryption formats\n";
|
||||
}
|
||||
maybeFixWritePassword(R, m->user_password);
|
||||
maybeFixWritePassword(R, m->owner_password);
|
||||
if ((R < 4) || ((R == 4) && (!m->use_aes))) {
|
||||
if (!m->allow_weak_crypto) {
|
||||
QTC::TC("qpdf", "QPDFJob weak crypto error");
|
||||
*this->m->log->getError()
|
||||
<< this->m->message_prefix
|
||||
*m->log->getError()
|
||||
<< m->message_prefix
|
||||
<< ": refusing to write a file with RC4, a weak "
|
||||
"cryptographic "
|
||||
"algorithm\n"
|
||||
@ -3141,7 +3129,7 @@ QPDFJob::setWriterOptions(QPDF& pdf, QPDFWriter& w)
|
||||
if (m->object_stream_set) {
|
||||
w.setObjectStreamMode(m->object_stream_mode);
|
||||
}
|
||||
w.setMinimumPDFVersion(this->m->max_input_version);
|
||||
w.setMinimumPDFVersion(m->max_input_version);
|
||||
if (!m->min_version.empty()) {
|
||||
std::string version;
|
||||
int extension_level = 0;
|
||||
@ -3155,22 +3143,19 @@ QPDFJob::setWriterOptions(QPDF& pdf, QPDFWriter& w)
|
||||
w.forcePDFVersion(version, extension_level);
|
||||
}
|
||||
if (m->progress) {
|
||||
if (this->m->progress_handler) {
|
||||
if (m->progress_handler) {
|
||||
w.registerProgressReporter(
|
||||
std::shared_ptr<QPDFWriter::ProgressReporter>(
|
||||
new QPDFWriter::FunctionProgressReporter(
|
||||
this->m->progress_handler)));
|
||||
m->progress_handler)));
|
||||
} else {
|
||||
char const* outfilename = this->m->outfilename
|
||||
? this->m->outfilename.get()
|
||||
: "standard output";
|
||||
char const* outfilename =
|
||||
m->outfilename ? m->outfilename.get() : "standard output";
|
||||
w.registerProgressReporter(
|
||||
std::shared_ptr<QPDFWriter::ProgressReporter>(
|
||||
// line-break
|
||||
new ProgressReporter(
|
||||
*this->m->log->getInfo(),
|
||||
this->m->message_prefix,
|
||||
outfilename)));
|
||||
*m->log->getInfo(), m->message_prefix, outfilename)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3291,19 +3276,19 @@ QPDFJob::writeOutfile(QPDF& pdf)
|
||||
} else if (strcmp(m->outfilename.get(), "-") == 0) {
|
||||
m->outfilename = nullptr;
|
||||
}
|
||||
if (this->m->json_version) {
|
||||
if (m->json_version) {
|
||||
writeJSON(pdf);
|
||||
} else {
|
||||
// QPDFWriter must have block scope so the output file will be
|
||||
// closed after write() finishes.
|
||||
QPDFWriter w(pdf);
|
||||
if (this->m->outfilename) {
|
||||
if (m->outfilename) {
|
||||
w.setOutputFilename(m->outfilename.get());
|
||||
} else {
|
||||
// saveToStandardOutput has already been called, but
|
||||
// calling it again is defensive and harmless.
|
||||
this->m->log->saveToStandardOutput(true);
|
||||
w.setOutputPipeline(this->m->log->getSave().get());
|
||||
m->log->saveToStandardOutput(true);
|
||||
w.setOutputPipeline(m->log->getSave().get());
|
||||
}
|
||||
setWriterOptions(pdf, w);
|
||||
w.write();
|
||||
@ -3327,17 +3312,17 @@ QPDFJob::writeOutfile(QPDF& pdf)
|
||||
QUtil::rename_file(m->infilename.get(), backup.c_str());
|
||||
QUtil::rename_file(temp_out.get(), m->infilename.get());
|
||||
if (warnings) {
|
||||
*this->m->log->getError()
|
||||
<< this->m->message_prefix
|
||||
*m->log->getError()
|
||||
<< m->message_prefix
|
||||
<< ": there are warnings; original file kept in " << backup
|
||||
<< "\n";
|
||||
} else {
|
||||
try {
|
||||
QUtil::remove_file(backup.c_str());
|
||||
} catch (QPDFSystemError& e) {
|
||||
*this->m->log->getError()
|
||||
<< this->m->message_prefix
|
||||
<< ": unable to delete original file (" << e.what() << ");"
|
||||
*m->log->getError()
|
||||
<< m->message_prefix << ": unable to delete original file ("
|
||||
<< e.what() << ");"
|
||||
<< " original file left in " << backup
|
||||
<< ", but the input was successfully replaced\n";
|
||||
}
|
||||
@ -3354,22 +3339,22 @@ QPDFJob::writeJSON(QPDF& pdf)
|
||||
std::shared_ptr<Pipeline> fp;
|
||||
if (m->outfilename.get()) {
|
||||
QTC::TC("qpdf", "QPDFJob write json to file");
|
||||
if (this->m->json_stream_prefix.empty()) {
|
||||
this->m->json_stream_prefix = this->m->outfilename.get();
|
||||
if (m->json_stream_prefix.empty()) {
|
||||
m->json_stream_prefix = m->outfilename.get();
|
||||
}
|
||||
fc = std::make_shared<QUtil::FileCloser>(
|
||||
QUtil::safe_fopen(this->m->outfilename.get(), "w"));
|
||||
QUtil::safe_fopen(m->outfilename.get(), "w"));
|
||||
fp = std::make_shared<Pl_StdioFile>("json output", fc->f);
|
||||
} else if (
|
||||
(this->m->json_stream_data == qpdf_sj_file) &&
|
||||
this->m->json_stream_prefix.empty()) {
|
||||
(m->json_stream_data == qpdf_sj_file) &&
|
||||
m->json_stream_prefix.empty()) {
|
||||
QTC::TC("qpdf", "QPDFJob need json-stream-prefix for stdout");
|
||||
usage("please specify --json-stream-prefix since the input file "
|
||||
"name is unknown");
|
||||
} else {
|
||||
QTC::TC("qpdf", "QPDFJob write json to stdout");
|
||||
this->m->log->saveToStandardOutput(true);
|
||||
fp = this->m->log->getSave();
|
||||
m->log->saveToStandardOutput(true);
|
||||
fp = m->log->getSave();
|
||||
}
|
||||
doJSON(pdf, fp.get());
|
||||
}
|
||||
|
@ -582,7 +582,7 @@ QPDFJob::initializeFromJson(std::string const& json, bool partial)
|
||||
JSON j = JSON::parse(json);
|
||||
if (!j.checkSchema(JOB_SCHEMA, JSON::f_optional, errors)) {
|
||||
std::ostringstream msg;
|
||||
msg << this->m->message_prefix << ": job json has errors:";
|
||||
msg << m->message_prefix << ": job json has errors:";
|
||||
for (auto const& error: errors) {
|
||||
msg << std::endl << " " << error;
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ QPDFLogger::info(std::string const& s)
|
||||
std::shared_ptr<Pipeline>
|
||||
QPDFLogger::getInfo(bool null_okay)
|
||||
{
|
||||
return throwIfNull(this->m->p_info, null_okay);
|
||||
return throwIfNull(m->p_info, null_okay);
|
||||
}
|
||||
|
||||
void
|
||||
@ -110,8 +110,8 @@ QPDFLogger::warn(std::string const& s)
|
||||
std::shared_ptr<Pipeline>
|
||||
QPDFLogger::getWarn(bool null_okay)
|
||||
{
|
||||
if (this->m->p_warn) {
|
||||
return this->m->p_warn;
|
||||
if (m->p_warn) {
|
||||
return m->p_warn;
|
||||
}
|
||||
return getError(null_okay);
|
||||
}
|
||||
@ -131,83 +131,83 @@ QPDFLogger::error(std::string const& s)
|
||||
std::shared_ptr<Pipeline>
|
||||
QPDFLogger::getError(bool null_okay)
|
||||
{
|
||||
return throwIfNull(this->m->p_error, null_okay);
|
||||
return throwIfNull(m->p_error, null_okay);
|
||||
}
|
||||
|
||||
std::shared_ptr<Pipeline>
|
||||
QPDFLogger::getSave(bool null_okay)
|
||||
{
|
||||
return throwIfNull(this->m->p_save, null_okay);
|
||||
return throwIfNull(m->p_save, null_okay);
|
||||
}
|
||||
|
||||
std::shared_ptr<Pipeline>
|
||||
QPDFLogger::standardOutput()
|
||||
{
|
||||
return this->m->p_stdout;
|
||||
return m->p_stdout;
|
||||
}
|
||||
|
||||
std::shared_ptr<Pipeline>
|
||||
QPDFLogger::standardError()
|
||||
{
|
||||
return this->m->p_stderr;
|
||||
return m->p_stderr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Pipeline>
|
||||
QPDFLogger::discard()
|
||||
{
|
||||
return this->m->p_discard;
|
||||
return m->p_discard;
|
||||
}
|
||||
|
||||
void
|
||||
QPDFLogger::setInfo(std::shared_ptr<Pipeline> p)
|
||||
{
|
||||
if (p == nullptr) {
|
||||
if (this->m->p_save == this->m->p_stdout) {
|
||||
p = this->m->p_stderr;
|
||||
if (m->p_save == m->p_stdout) {
|
||||
p = m->p_stderr;
|
||||
} else {
|
||||
p = this->m->p_stdout;
|
||||
p = m->p_stdout;
|
||||
}
|
||||
}
|
||||
this->m->p_info = p;
|
||||
m->p_info = p;
|
||||
}
|
||||
|
||||
void
|
||||
QPDFLogger::setWarn(std::shared_ptr<Pipeline> p)
|
||||
{
|
||||
this->m->p_warn = p;
|
||||
m->p_warn = p;
|
||||
}
|
||||
|
||||
void
|
||||
QPDFLogger::setError(std::shared_ptr<Pipeline> p)
|
||||
{
|
||||
if (p == nullptr) {
|
||||
p = this->m->p_stderr;
|
||||
p = m->p_stderr;
|
||||
}
|
||||
this->m->p_error = p;
|
||||
m->p_error = p;
|
||||
}
|
||||
|
||||
void
|
||||
QPDFLogger::setSave(std::shared_ptr<Pipeline> p, bool only_if_not_set)
|
||||
{
|
||||
if (only_if_not_set && (this->m->p_save != nullptr)) {
|
||||
if (only_if_not_set && (m->p_save != nullptr)) {
|
||||
return;
|
||||
}
|
||||
if (this->m->p_save == p) {
|
||||
if (m->p_save == p) {
|
||||
return;
|
||||
}
|
||||
if (p == this->m->p_stdout) {
|
||||
if (p == m->p_stdout) {
|
||||
auto pt = dynamic_cast<Pl_Track*>(p.get());
|
||||
if (pt->getUsed()) {
|
||||
throw std::logic_error(
|
||||
"QPDFLogger: called setSave on standard output after standard"
|
||||
" output has already been used");
|
||||
}
|
||||
if (this->m->p_info == this->m->p_stdout) {
|
||||
this->m->p_info = this->m->p_stderr;
|
||||
if (m->p_info == m->p_stdout) {
|
||||
m->p_info = m->p_stderr;
|
||||
}
|
||||
QUtil::binary_stdout();
|
||||
}
|
||||
this->m->p_save = p;
|
||||
m->p_save = p;
|
||||
}
|
||||
|
||||
void
|
||||
@ -229,22 +229,22 @@ QPDFLogger::setOutputStreams(std::ostream* out_stream, std::ostream* err_stream)
|
||||
std::shared_ptr<Pipeline> new_err;
|
||||
|
||||
if (out_stream == nullptr) {
|
||||
if (this->m->p_save == this->m->p_stdout) {
|
||||
new_out = this->m->p_stderr;
|
||||
if (m->p_save == m->p_stdout) {
|
||||
new_out = m->p_stderr;
|
||||
} else {
|
||||
new_out = this->m->p_stdout;
|
||||
new_out = m->p_stdout;
|
||||
}
|
||||
} else {
|
||||
new_out = std::make_shared<Pl_OStream>("output", *out_stream);
|
||||
}
|
||||
if (err_stream == nullptr) {
|
||||
new_err = this->m->p_stderr;
|
||||
new_err = m->p_stderr;
|
||||
} else {
|
||||
new_err = std::make_shared<Pl_OStream>("error output", *err_stream);
|
||||
}
|
||||
this->m->p_info = new_out;
|
||||
this->m->p_warn = nullptr;
|
||||
this->m->p_error = new_err;
|
||||
m->p_info = new_out;
|
||||
m->p_warn = nullptr;
|
||||
m->p_error = new_err;
|
||||
}
|
||||
|
||||
std::shared_ptr<Pipeline>
|
||||
|
@ -140,26 +140,26 @@ QPDFNameTreeObjectHelper::iterator::remove()
|
||||
QPDFNameTreeObjectHelper::iterator
|
||||
QPDFNameTreeObjectHelper::begin() const
|
||||
{
|
||||
return iterator(std::make_shared<NNTreeIterator>(this->m->impl->begin()));
|
||||
return iterator(std::make_shared<NNTreeIterator>(m->impl->begin()));
|
||||
}
|
||||
|
||||
QPDFNameTreeObjectHelper::iterator
|
||||
QPDFNameTreeObjectHelper::end() const
|
||||
{
|
||||
return iterator(std::make_shared<NNTreeIterator>(this->m->impl->end()));
|
||||
return iterator(std::make_shared<NNTreeIterator>(m->impl->end()));
|
||||
}
|
||||
|
||||
QPDFNameTreeObjectHelper::iterator
|
||||
QPDFNameTreeObjectHelper::last() const
|
||||
{
|
||||
return iterator(std::make_shared<NNTreeIterator>(this->m->impl->last()));
|
||||
return iterator(std::make_shared<NNTreeIterator>(m->impl->last()));
|
||||
}
|
||||
|
||||
QPDFNameTreeObjectHelper::iterator
|
||||
QPDFNameTreeObjectHelper::find(
|
||||
std::string const& key, bool return_prev_if_not_found)
|
||||
{
|
||||
auto i = this->m->impl->find(
|
||||
auto i = m->impl->find(
|
||||
QPDFObjectHandle::newUnicodeString(key), return_prev_if_not_found);
|
||||
return iterator(std::make_shared<NNTreeIterator>(i));
|
||||
}
|
||||
@ -167,8 +167,7 @@ QPDFNameTreeObjectHelper::find(
|
||||
QPDFNameTreeObjectHelper::iterator
|
||||
QPDFNameTreeObjectHelper::insert(std::string const& key, QPDFObjectHandle value)
|
||||
{
|
||||
auto i =
|
||||
this->m->impl->insert(QPDFObjectHandle::newUnicodeString(key), value);
|
||||
auto i = m->impl->insert(QPDFObjectHandle::newUnicodeString(key), value);
|
||||
return iterator(std::make_shared<NNTreeIterator>(i));
|
||||
}
|
||||
|
||||
@ -176,8 +175,7 @@ bool
|
||||
QPDFNameTreeObjectHelper::remove(
|
||||
std::string const& key, QPDFObjectHandle* value)
|
||||
{
|
||||
return this->m->impl->remove(
|
||||
QPDFObjectHandle::newUnicodeString(key), value);
|
||||
return m->impl->remove(QPDFObjectHandle::newUnicodeString(key), value);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -202,7 +200,7 @@ QPDFNameTreeObjectHelper::findObject(
|
||||
void
|
||||
QPDFNameTreeObjectHelper::setSplitThreshold(int t)
|
||||
{
|
||||
this->m->impl->setSplitThreshold(t);
|
||||
m->impl->setSplitThreshold(t);
|
||||
}
|
||||
|
||||
std::map<std::string, QPDFObjectHandle>
|
||||
|
@ -141,26 +141,26 @@ QPDFNumberTreeObjectHelper::iterator::remove()
|
||||
QPDFNumberTreeObjectHelper::iterator
|
||||
QPDFNumberTreeObjectHelper::begin() const
|
||||
{
|
||||
return iterator(std::make_shared<NNTreeIterator>(this->m->impl->begin()));
|
||||
return iterator(std::make_shared<NNTreeIterator>(m->impl->begin()));
|
||||
}
|
||||
|
||||
QPDFNumberTreeObjectHelper::iterator
|
||||
QPDFNumberTreeObjectHelper::end() const
|
||||
{
|
||||
return iterator(std::make_shared<NNTreeIterator>(this->m->impl->end()));
|
||||
return iterator(std::make_shared<NNTreeIterator>(m->impl->end()));
|
||||
}
|
||||
|
||||
QPDFNumberTreeObjectHelper::iterator
|
||||
QPDFNumberTreeObjectHelper::last() const
|
||||
{
|
||||
return iterator(std::make_shared<NNTreeIterator>(this->m->impl->last()));
|
||||
return iterator(std::make_shared<NNTreeIterator>(m->impl->last()));
|
||||
}
|
||||
|
||||
QPDFNumberTreeObjectHelper::iterator
|
||||
QPDFNumberTreeObjectHelper::find(
|
||||
numtree_number key, bool return_prev_if_not_found)
|
||||
{
|
||||
auto i = this->m->impl->find(
|
||||
auto i = m->impl->find(
|
||||
QPDFObjectHandle::newInteger(key), return_prev_if_not_found);
|
||||
return iterator(std::make_shared<NNTreeIterator>(i));
|
||||
}
|
||||
@ -168,14 +168,14 @@ QPDFNumberTreeObjectHelper::find(
|
||||
QPDFNumberTreeObjectHelper::iterator
|
||||
QPDFNumberTreeObjectHelper::insert(numtree_number key, QPDFObjectHandle value)
|
||||
{
|
||||
auto i = this->m->impl->insert(QPDFObjectHandle::newInteger(key), value);
|
||||
auto i = m->impl->insert(QPDFObjectHandle::newInteger(key), value);
|
||||
return iterator(std::make_shared<NNTreeIterator>(i));
|
||||
}
|
||||
|
||||
bool
|
||||
QPDFNumberTreeObjectHelper::remove(numtree_number key, QPDFObjectHandle* value)
|
||||
{
|
||||
return this->m->impl->remove(QPDFObjectHandle::newInteger(key), value);
|
||||
return m->impl->remove(QPDFObjectHandle::newInteger(key), value);
|
||||
}
|
||||
|
||||
QPDFNumberTreeObjectHelper::numtree_number
|
||||
@ -233,7 +233,7 @@ QPDFNumberTreeObjectHelper::findObjectAtOrBelow(
|
||||
void
|
||||
QPDFNumberTreeObjectHelper::setSplitThreshold(int t)
|
||||
{
|
||||
this->m->impl->setSplitThreshold(t);
|
||||
m->impl->setSplitThreshold(t);
|
||||
}
|
||||
|
||||
std::map<QPDFNumberTreeObjectHelper::numtree_number, QPDFObjectHandle>
|
||||
|
@ -2517,7 +2517,7 @@ QPDFObjectHandle::QPDFDictItems::QPDFDictItems(QPDFObjectHandle const& oh) :
|
||||
QPDFObjectHandle::QPDFDictItems::iterator&
|
||||
QPDFObjectHandle::QPDFDictItems::iterator::operator++()
|
||||
{
|
||||
++this->m->iter;
|
||||
++m->iter;
|
||||
updateIValue();
|
||||
return *this;
|
||||
}
|
||||
@ -2525,7 +2525,7 @@ QPDFObjectHandle::QPDFDictItems::iterator::operator++()
|
||||
QPDFObjectHandle::QPDFDictItems::iterator&
|
||||
QPDFObjectHandle::QPDFDictItems::iterator::operator--()
|
||||
{
|
||||
--this->m->iter;
|
||||
--m->iter;
|
||||
updateIValue();
|
||||
return *this;
|
||||
}
|
||||
@ -2548,10 +2548,10 @@ bool
|
||||
QPDFObjectHandle::QPDFDictItems::iterator::operator==(
|
||||
iterator const& other) const
|
||||
{
|
||||
if (this->m->is_end && other.m->is_end) {
|
||||
if (m->is_end && other.m->is_end) {
|
||||
return true;
|
||||
}
|
||||
if (this->m->is_end || other.m->is_end) {
|
||||
if (m->is_end || other.m->is_end) {
|
||||
return false;
|
||||
}
|
||||
return (this->ivalue.first == other.ivalue.first);
|
||||
@ -2567,13 +2567,13 @@ QPDFObjectHandle::QPDFDictItems::iterator::iterator(
|
||||
void
|
||||
QPDFObjectHandle::QPDFDictItems::iterator::updateIValue()
|
||||
{
|
||||
this->m->is_end = (this->m->iter == this->m->keys.end());
|
||||
if (this->m->is_end) {
|
||||
m->is_end = (m->iter == m->keys.end());
|
||||
if (m->is_end) {
|
||||
this->ivalue.first = "";
|
||||
this->ivalue.second = QPDFObjectHandle();
|
||||
} else {
|
||||
this->ivalue.first = *(this->m->iter);
|
||||
this->ivalue.second = this->m->oh.getKey(this->ivalue.first);
|
||||
this->ivalue.first = *(m->iter);
|
||||
this->ivalue.second = m->oh.getKey(this->ivalue.first);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2605,8 +2605,8 @@ QPDFObjectHandle::QPDFArrayItems::QPDFArrayItems(QPDFObjectHandle const& oh) :
|
||||
QPDFObjectHandle::QPDFArrayItems::iterator&
|
||||
QPDFObjectHandle::QPDFArrayItems::iterator::operator++()
|
||||
{
|
||||
if (!this->m->is_end) {
|
||||
++this->m->item_number;
|
||||
if (!m->is_end) {
|
||||
++m->item_number;
|
||||
updateIValue();
|
||||
}
|
||||
return *this;
|
||||
@ -2615,8 +2615,8 @@ QPDFObjectHandle::QPDFArrayItems::iterator::operator++()
|
||||
QPDFObjectHandle::QPDFArrayItems::iterator&
|
||||
QPDFObjectHandle::QPDFArrayItems::iterator::operator--()
|
||||
{
|
||||
if (this->m->item_number > 0) {
|
||||
--this->m->item_number;
|
||||
if (m->item_number > 0) {
|
||||
--m->item_number;
|
||||
updateIValue();
|
||||
}
|
||||
return *this;
|
||||
@ -2640,7 +2640,7 @@ bool
|
||||
QPDFObjectHandle::QPDFArrayItems::iterator::operator==(
|
||||
iterator const& other) const
|
||||
{
|
||||
return (this->m->item_number == other.m->item_number);
|
||||
return (m->item_number == other.m->item_number);
|
||||
}
|
||||
|
||||
QPDFObjectHandle::QPDFArrayItems::iterator::iterator(
|
||||
@ -2653,11 +2653,11 @@ QPDFObjectHandle::QPDFArrayItems::iterator::iterator(
|
||||
void
|
||||
QPDFObjectHandle::QPDFArrayItems::iterator::updateIValue()
|
||||
{
|
||||
this->m->is_end = (this->m->item_number >= this->m->oh.getArrayNItems());
|
||||
if (this->m->is_end) {
|
||||
m->is_end = (m->item_number >= m->oh.getArrayNItems());
|
||||
if (m->is_end) {
|
||||
this->ivalue = QPDFObjectHandle();
|
||||
} else {
|
||||
this->ivalue = this->m->oh.getArrayItem(this->m->item_number);
|
||||
this->ivalue = m->oh.getArrayItem(m->item_number);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ QPDFOutlineDocumentHelper::QPDFOutlineDocumentHelper(QPDF& qpdf) :
|
||||
QPDFObjectHandle cur = outlines.getKey("/First");
|
||||
QPDFObjGen::set seen;
|
||||
while (!cur.isNull() && seen.add(cur)) {
|
||||
this->m->outlines.push_back(
|
||||
m->outlines.push_back(
|
||||
QPDFOutlineObjectHelper::Accessor::create(cur, *this, 1));
|
||||
cur = cur.getKey("/Next");
|
||||
}
|
||||
@ -26,26 +26,25 @@ QPDFOutlineDocumentHelper::QPDFOutlineDocumentHelper(QPDF& qpdf) :
|
||||
bool
|
||||
QPDFOutlineDocumentHelper::hasOutlines()
|
||||
{
|
||||
return !this->m->outlines.empty();
|
||||
return !m->outlines.empty();
|
||||
}
|
||||
|
||||
std::vector<QPDFOutlineObjectHelper>
|
||||
QPDFOutlineDocumentHelper::getTopLevelOutlines()
|
||||
{
|
||||
return this->m->outlines;
|
||||
return m->outlines;
|
||||
}
|
||||
|
||||
void
|
||||
QPDFOutlineDocumentHelper::initializeByPage()
|
||||
{
|
||||
std::list<QPDFOutlineObjectHelper> queue;
|
||||
queue.insert(
|
||||
queue.end(), this->m->outlines.begin(), this->m->outlines.end());
|
||||
queue.insert(queue.end(), m->outlines.begin(), m->outlines.end());
|
||||
|
||||
while (!queue.empty()) {
|
||||
QPDFOutlineObjectHelper oh = queue.front();
|
||||
queue.pop_front();
|
||||
this->m->by_page[oh.getDestPage().getObjGen()].push_back(oh);
|
||||
m->by_page[oh.getDestPage().getObjGen()].push_back(oh);
|
||||
std::vector<QPDFOutlineObjectHelper> kids = oh.getKids();
|
||||
queue.insert(queue.end(), kids.begin(), kids.end());
|
||||
}
|
||||
@ -54,12 +53,12 @@ QPDFOutlineDocumentHelper::initializeByPage()
|
||||
std::vector<QPDFOutlineObjectHelper>
|
||||
QPDFOutlineDocumentHelper::getOutlinesForPage(QPDFObjGen const& og)
|
||||
{
|
||||
if (this->m->by_page.empty()) {
|
||||
if (m->by_page.empty()) {
|
||||
initializeByPage();
|
||||
}
|
||||
std::vector<QPDFOutlineObjectHelper> result;
|
||||
if (this->m->by_page.count(og)) {
|
||||
result = this->m->by_page[og];
|
||||
if (m->by_page.count(og)) {
|
||||
result = m->by_page[og];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -69,27 +68,26 @@ QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name)
|
||||
{
|
||||
QPDFObjectHandle result;
|
||||
if (name.isName()) {
|
||||
if (!this->m->dest_dict.isInitialized()) {
|
||||
this->m->dest_dict = this->qpdf.getRoot().getKey("/Dests");
|
||||
if (!m->dest_dict.isInitialized()) {
|
||||
m->dest_dict = this->qpdf.getRoot().getKey("/Dests");
|
||||
}
|
||||
if (this->m->dest_dict.isDictionary()) {
|
||||
if (m->dest_dict.isDictionary()) {
|
||||
QTC::TC("qpdf", "QPDFOutlineDocumentHelper name named dest");
|
||||
result = this->m->dest_dict.getKey(name.getName());
|
||||
result = m->dest_dict.getKey(name.getName());
|
||||
}
|
||||
} else if (name.isString()) {
|
||||
if (nullptr == this->m->names_dest) {
|
||||
if (nullptr == m->names_dest) {
|
||||
QPDFObjectHandle names = this->qpdf.getRoot().getKey("/Names");
|
||||
if (names.isDictionary()) {
|
||||
QPDFObjectHandle dests = names.getKey("/Dests");
|
||||
if (dests.isDictionary()) {
|
||||
this->m->names_dest =
|
||||
std::make_shared<QPDFNameTreeObjectHelper>(
|
||||
dests, this->qpdf);
|
||||
m->names_dest = std::make_shared<QPDFNameTreeObjectHelper>(
|
||||
dests, this->qpdf);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this->m->names_dest.get()) {
|
||||
if (this->m->names_dest->findObject(name.getUTF8Value(), result)) {
|
||||
if (m->names_dest.get()) {
|
||||
if (m->names_dest->findObject(name.getUTF8Value(), result)) {
|
||||
QTC::TC("qpdf", "QPDFOutlineDocumentHelper string named dest");
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ QPDFOutlineObjectHelper::QPDFOutlineObjectHelper(
|
||||
return;
|
||||
}
|
||||
if (QPDFOutlineDocumentHelper::Accessor::checkSeen(
|
||||
this->m->dh, this->oh.getObjGen())) {
|
||||
m->dh, this->oh.getObjGen())) {
|
||||
QTC::TC("qpdf", "QPDFOutlineObjectHelper loop");
|
||||
return;
|
||||
}
|
||||
@ -28,7 +28,7 @@ QPDFOutlineObjectHelper::QPDFOutlineObjectHelper(
|
||||
while (!cur.isNull()) {
|
||||
QPDFOutlineObjectHelper new_ooh(cur, dh, 1 + depth);
|
||||
new_ooh.m->parent = std::make_shared<QPDFOutlineObjectHelper>(*this);
|
||||
this->m->kids.push_back(new_ooh);
|
||||
m->kids.push_back(new_ooh);
|
||||
cur = cur.getKey("/Next");
|
||||
}
|
||||
}
|
||||
@ -36,13 +36,13 @@ QPDFOutlineObjectHelper::QPDFOutlineObjectHelper(
|
||||
std::shared_ptr<QPDFOutlineObjectHelper>
|
||||
QPDFOutlineObjectHelper::getParent()
|
||||
{
|
||||
return this->m->parent;
|
||||
return m->parent;
|
||||
}
|
||||
|
||||
std::vector<QPDFOutlineObjectHelper>
|
||||
QPDFOutlineObjectHelper::getKids()
|
||||
{
|
||||
return this->m->kids;
|
||||
return m->kids;
|
||||
}
|
||||
|
||||
QPDFObjectHandle
|
||||
@ -65,7 +65,7 @@ QPDFOutlineObjectHelper::getDest()
|
||||
|
||||
if (dest.isName() || dest.isString()) {
|
||||
QTC::TC("qpdf", "QPDFOutlineObjectHelper named dest");
|
||||
dest = this->m->dh.resolveNamedDest(dest);
|
||||
dest = m->dh.resolveNamedDest(dest);
|
||||
}
|
||||
|
||||
return dest;
|
||||
|
@ -8,7 +8,7 @@ QPDFPageLabelDocumentHelper::QPDFPageLabelDocumentHelper(QPDF& qpdf) :
|
||||
{
|
||||
QPDFObjectHandle root = qpdf.getRoot();
|
||||
if (root.hasKey("/PageLabels")) {
|
||||
this->m->labels = std::make_shared<QPDFNumberTreeObjectHelper>(
|
||||
m->labels = std::make_shared<QPDFNumberTreeObjectHelper>(
|
||||
root.getKey("/PageLabels"), this->qpdf);
|
||||
}
|
||||
}
|
||||
@ -16,7 +16,7 @@ QPDFPageLabelDocumentHelper::QPDFPageLabelDocumentHelper(QPDF& qpdf) :
|
||||
bool
|
||||
QPDFPageLabelDocumentHelper::hasPageLabels()
|
||||
{
|
||||
return nullptr != this->m->labels;
|
||||
return nullptr != m->labels;
|
||||
}
|
||||
|
||||
QPDFObjectHandle
|
||||
@ -28,7 +28,7 @@ QPDFPageLabelDocumentHelper::getLabelForPage(long long page_idx)
|
||||
}
|
||||
QPDFNumberTreeObjectHelper::numtree_number offset = 0;
|
||||
QPDFObjectHandle label;
|
||||
if (!this->m->labels->findObjectAtOrBelow(page_idx, label, offset)) {
|
||||
if (!m->labels->findObjectAtOrBelow(page_idx, label, offset)) {
|
||||
return result;
|
||||
}
|
||||
if (!label.isDictionary()) {
|
||||
@ -96,7 +96,7 @@ QPDFPageLabelDocumentHelper::getLabelsForPageRange(
|
||||
|
||||
long long int idx_offset = new_start_idx - start_idx;
|
||||
for (long long i = start_idx + 1; i <= end_idx; ++i) {
|
||||
if (this->m->labels->hasIndex(i) &&
|
||||
if (m->labels->hasIndex(i) &&
|
||||
(label = getLabelForPage(i)).isDictionary()) {
|
||||
new_labels.push_back(QPDFObjectHandle::newInteger(i + idx_offset));
|
||||
new_labels.push_back(label);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -774,27 +774,27 @@ QPDF::interpretCF(
|
||||
void
|
||||
QPDF::initializeEncryption()
|
||||
{
|
||||
if (this->m->encp->encryption_initialized) {
|
||||
if (m->encp->encryption_initialized) {
|
||||
return;
|
||||
}
|
||||
this->m->encp->encryption_initialized = true;
|
||||
m->encp->encryption_initialized = true;
|
||||
|
||||
// After we initialize encryption parameters, we must used stored
|
||||
// key information and never look at /Encrypt again. Otherwise,
|
||||
// things could go wrong if someone mutates the encryption
|
||||
// dictionary.
|
||||
|
||||
if (!this->m->trailer.hasKey("/Encrypt")) {
|
||||
if (!m->trailer.hasKey("/Encrypt")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Go ahead and set this->m->encrypted here. That way, isEncrypted
|
||||
// Go ahead and set m->encrypted here. That way, isEncrypted
|
||||
// will return true even if there were errors reading the
|
||||
// encryption dictionary.
|
||||
this->m->encp->encrypted = true;
|
||||
m->encp->encrypted = true;
|
||||
|
||||
std::string id1;
|
||||
QPDFObjectHandle id_obj = this->m->trailer.getKey("/ID");
|
||||
QPDFObjectHandle id_obj = m->trailer.getKey("/ID");
|
||||
if ((id_obj.isArray() && (id_obj.getArrayNItems() == 2) &&
|
||||
id_obj.getArrayItem(0).isString())) {
|
||||
id1 = id_obj.getArrayItem(0).getStringValue();
|
||||
@ -805,7 +805,7 @@ QPDF::initializeEncryption()
|
||||
warn(damagedPDF("trailer", "invalid /ID in trailer dictionary"));
|
||||
}
|
||||
|
||||
QPDFObjectHandle encryption_dict = this->m->trailer.getKey("/Encrypt");
|
||||
QPDFObjectHandle encryption_dict = m->trailer.getKey("/Encrypt");
|
||||
if (!encryption_dict.isDictionary()) {
|
||||
throw damagedPDF("/Encrypt in trailer dictionary is not a dictionary");
|
||||
}
|
||||
@ -814,16 +814,16 @@ QPDF::initializeEncryption()
|
||||
(encryption_dict.getKey("/Filter").getName() == "/Standard"))) {
|
||||
throw QPDFExc(
|
||||
qpdf_e_unsupported,
|
||||
this->m->file->getName(),
|
||||
m->file->getName(),
|
||||
"encryption dictionary",
|
||||
this->m->file->getLastOffset(),
|
||||
m->file->getLastOffset(),
|
||||
"unsupported encryption filter");
|
||||
}
|
||||
if (!encryption_dict.getKey("/SubFilter").isNull()) {
|
||||
warn(
|
||||
qpdf_e_unsupported,
|
||||
"encryption dictionary",
|
||||
this->m->file->getLastOffset(),
|
||||
m->file->getLastOffset(),
|
||||
"file uses encryption SubFilters, which qpdf does not support");
|
||||
}
|
||||
|
||||
@ -850,16 +850,16 @@ QPDF::initializeEncryption()
|
||||
((V == 1) || (V == 2) || (V == 4) || (V == 5)))) {
|
||||
throw QPDFExc(
|
||||
qpdf_e_unsupported,
|
||||
this->m->file->getName(),
|
||||
m->file->getName(),
|
||||
"encryption dictionary",
|
||||
this->m->file->getLastOffset(),
|
||||
m->file->getLastOffset(),
|
||||
"Unsupported /R or /V in encryption dictionary; R = " +
|
||||
std::to_string(R) + " (max 6), V = " + std::to_string(V) +
|
||||
" (max 5)");
|
||||
}
|
||||
|
||||
this->m->encp->encryption_V = V;
|
||||
this->m->encp->encryption_R = R;
|
||||
m->encp->encryption_V = V;
|
||||
m->encp->encryption_R = R;
|
||||
|
||||
// OE, UE, and Perms are only present if V >= 5.
|
||||
std::string OE;
|
||||
@ -916,9 +916,9 @@ QPDF::initializeEncryption()
|
||||
Length = 128;
|
||||
}
|
||||
|
||||
this->m->encp->encrypt_metadata = true;
|
||||
m->encp->encrypt_metadata = true;
|
||||
if ((V >= 4) && (encryption_dict.getKey("/EncryptMetadata").isBool())) {
|
||||
this->m->encp->encrypt_metadata =
|
||||
m->encp->encrypt_metadata =
|
||||
encryption_dict.getKey("/EncryptMetadata").getBoolValue();
|
||||
}
|
||||
|
||||
@ -945,15 +945,15 @@ QPDF::initializeEncryption()
|
||||
method = e_unknown;
|
||||
}
|
||||
}
|
||||
this->m->encp->crypt_filters[filter] = method;
|
||||
m->encp->crypt_filters[filter] = method;
|
||||
}
|
||||
}
|
||||
|
||||
QPDFObjectHandle StmF = encryption_dict.getKey("/StmF");
|
||||
QPDFObjectHandle StrF = encryption_dict.getKey("/StrF");
|
||||
QPDFObjectHandle EFF = encryption_dict.getKey("/EFF");
|
||||
this->m->encp->cf_stream = interpretCF(this->m->encp, StmF);
|
||||
this->m->encp->cf_string = interpretCF(this->m->encp, StrF);
|
||||
m->encp->cf_stream = interpretCF(m->encp, StmF);
|
||||
m->encp->cf_string = interpretCF(m->encp, StrF);
|
||||
if (EFF.isName()) {
|
||||
// qpdf does not use this for anything other than
|
||||
// informational purposes. This is intended to instruct
|
||||
@ -969,9 +969,9 @@ QPDF::initializeEncryption()
|
||||
// at a file generated by something else, such as Acrobat
|
||||
// when specifying that only attachments should be
|
||||
// encrypted.
|
||||
this->m->encp->cf_file = interpretCF(this->m->encp, EFF);
|
||||
m->encp->cf_file = interpretCF(m->encp, EFF);
|
||||
} else {
|
||||
this->m->encp->cf_file = this->m->encp->cf_stream;
|
||||
m->encp->cf_file = m->encp->cf_stream;
|
||||
}
|
||||
}
|
||||
|
||||
@ -986,59 +986,51 @@ QPDF::initializeEncryption()
|
||||
UE,
|
||||
Perms,
|
||||
id1,
|
||||
this->m->encp->encrypt_metadata);
|
||||
if (this->m->provided_password_is_hex_key) {
|
||||
m->encp->encrypt_metadata);
|
||||
if (m->provided_password_is_hex_key) {
|
||||
// ignore passwords in file
|
||||
} else {
|
||||
this->m->encp->owner_password_matched = check_owner_password(
|
||||
this->m->encp->user_password,
|
||||
this->m->encp->provided_password,
|
||||
data);
|
||||
if (this->m->encp->owner_password_matched && (V < 5)) {
|
||||
m->encp->owner_password_matched = check_owner_password(
|
||||
m->encp->user_password, m->encp->provided_password, data);
|
||||
if (m->encp->owner_password_matched && (V < 5)) {
|
||||
// password supplied was owner password; user_password has
|
||||
// been initialized for V < 5
|
||||
if (getTrimmedUserPassword() == this->m->encp->provided_password) {
|
||||
this->m->encp->user_password_matched = true;
|
||||
if (getTrimmedUserPassword() == m->encp->provided_password) {
|
||||
m->encp->user_password_matched = true;
|
||||
QTC::TC("qpdf", "QPDF_encryption user matches owner V < 5");
|
||||
}
|
||||
} else {
|
||||
this->m->encp->user_password_matched =
|
||||
check_user_password(this->m->encp->provided_password, data);
|
||||
if (this->m->encp->user_password_matched) {
|
||||
this->m->encp->user_password = this->m->encp->provided_password;
|
||||
m->encp->user_password_matched =
|
||||
check_user_password(m->encp->provided_password, data);
|
||||
if (m->encp->user_password_matched) {
|
||||
m->encp->user_password = m->encp->provided_password;
|
||||
}
|
||||
}
|
||||
if (this->m->encp->user_password_matched &&
|
||||
this->m->encp->owner_password_matched) {
|
||||
if (m->encp->user_password_matched && m->encp->owner_password_matched) {
|
||||
QTC::TC("qpdf", "QPDF_encryption same password", (V < 5) ? 0 : 1);
|
||||
}
|
||||
if (!(this->m->encp->owner_password_matched ||
|
||||
this->m->encp->user_password_matched)) {
|
||||
if (!(m->encp->owner_password_matched ||
|
||||
m->encp->user_password_matched)) {
|
||||
throw QPDFExc(
|
||||
qpdf_e_password,
|
||||
this->m->file->getName(),
|
||||
"",
|
||||
0,
|
||||
"invalid password");
|
||||
qpdf_e_password, m->file->getName(), "", 0, "invalid password");
|
||||
}
|
||||
}
|
||||
|
||||
if (this->m->provided_password_is_hex_key) {
|
||||
this->m->encp->encryption_key =
|
||||
QUtil::hex_decode(this->m->encp->provided_password);
|
||||
if (m->provided_password_is_hex_key) {
|
||||
m->encp->encryption_key = QUtil::hex_decode(m->encp->provided_password);
|
||||
} else if (V < 5) {
|
||||
// For V < 5, the user password is encrypted with the owner
|
||||
// password, and the user password is always used for
|
||||
// computing the encryption key.
|
||||
this->m->encp->encryption_key =
|
||||
compute_encryption_key(this->m->encp->user_password, data);
|
||||
m->encp->encryption_key =
|
||||
compute_encryption_key(m->encp->user_password, data);
|
||||
} else {
|
||||
// For V >= 5, either password can be used independently to
|
||||
// compute the encryption key, and neither password can be
|
||||
// used to recover the other.
|
||||
bool perms_valid;
|
||||
this->m->encp->encryption_key = recover_encryption_key_with_password(
|
||||
this->m->encp->provided_password, data, perms_valid);
|
||||
m->encp->encryption_key = recover_encryption_key_with_password(
|
||||
m->encp->provided_password, data, perms_valid);
|
||||
if (!perms_valid) {
|
||||
warn(damagedPDF(
|
||||
"encryption dictionary",
|
||||
@ -1080,8 +1072,8 @@ QPDF::decryptString(std::string& str, QPDFObjGen const& og)
|
||||
return;
|
||||
}
|
||||
bool use_aes = false;
|
||||
if (this->m->encp->encryption_V >= 4) {
|
||||
switch (this->m->encp->cf_string) {
|
||||
if (m->encp->encryption_V >= 4) {
|
||||
switch (m->encp->cf_string) {
|
||||
case e_none:
|
||||
return;
|
||||
|
||||
@ -1102,13 +1094,13 @@ QPDF::decryptString(std::string& str, QPDFObjGen const& og)
|
||||
"/Encrypt dictionary); strings may be decrypted improperly"));
|
||||
// To avoid repeated warnings, reset cf_string. Assume
|
||||
// we'd want to use AES if V == 4.
|
||||
this->m->encp->cf_string = e_aes;
|
||||
m->encp->cf_string = e_aes;
|
||||
use_aes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string key = getKeyForObject(this->m->encp, og, use_aes);
|
||||
std::string key = getKeyForObject(m->encp, og, use_aes);
|
||||
try {
|
||||
if (use_aes) {
|
||||
QTC::TC("qpdf", "QPDF_encryption aes decode string");
|
||||
@ -1320,13 +1312,13 @@ QPDF::compute_encryption_parameters_V5(
|
||||
std::string const&
|
||||
QPDF::getPaddedUserPassword() const
|
||||
{
|
||||
return this->m->encp->user_password;
|
||||
return m->encp->user_password;
|
||||
}
|
||||
|
||||
std::string
|
||||
QPDF::getTrimmedUserPassword() const
|
||||
{
|
||||
std::string result = this->m->encp->user_password;
|
||||
std::string result = m->encp->user_password;
|
||||
trim_user_password(result);
|
||||
return result;
|
||||
}
|
||||
@ -1334,13 +1326,13 @@ QPDF::getTrimmedUserPassword() const
|
||||
std::string
|
||||
QPDF::getEncryptionKey() const
|
||||
{
|
||||
return this->m->encp->encryption_key;
|
||||
return m->encp->encryption_key;
|
||||
}
|
||||
|
||||
bool
|
||||
QPDF::isEncrypted() const
|
||||
{
|
||||
return this->m->encp->encrypted;
|
||||
return m->encp->encrypted;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1360,7 +1352,7 @@ QPDF::isEncrypted(
|
||||
encryption_method_e& string_method,
|
||||
encryption_method_e& file_method)
|
||||
{
|
||||
if (this->m->encp->encrypted) {
|
||||
if (m->encp->encrypted) {
|
||||
QPDFObjectHandle trailer = getTrailer();
|
||||
QPDFObjectHandle encrypt = trailer.getKey("/Encrypt");
|
||||
QPDFObjectHandle Pkey = encrypt.getKey("/P");
|
||||
@ -1369,9 +1361,9 @@ QPDF::isEncrypted(
|
||||
P = static_cast<int>(Pkey.getIntValue());
|
||||
R = Rkey.getIntValueAsInt();
|
||||
V = Vkey.getIntValueAsInt();
|
||||
stream_method = this->m->encp->cf_stream;
|
||||
string_method = this->m->encp->cf_string;
|
||||
file_method = this->m->encp->cf_file;
|
||||
stream_method = m->encp->cf_stream;
|
||||
string_method = m->encp->cf_string;
|
||||
file_method = m->encp->cf_file;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@ -1381,13 +1373,13 @@ QPDF::isEncrypted(
|
||||
bool
|
||||
QPDF::ownerPasswordMatched() const
|
||||
{
|
||||
return this->m->encp->owner_password_matched;
|
||||
return m->encp->owner_password_matched;
|
||||
}
|
||||
|
||||
bool
|
||||
QPDF::userPasswordMatched() const
|
||||
{
|
||||
return this->m->encp->user_password_matched;
|
||||
return m->encp->user_password_matched;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -67,7 +67,7 @@ load_vector_vector(
|
||||
void
|
||||
QPDF::linearizationWarning(std::string_view msg)
|
||||
{
|
||||
this->m->linearization_warnings = true;
|
||||
m->linearization_warnings = true;
|
||||
warn(qpdf_e_linearization, "", 0, std::string(msg));
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ QPDF::isLinearized()
|
||||
{
|
||||
// If the first object in the file is a dictionary with a suitable
|
||||
// /Linearized key and has an /L key that accurately indicates the
|
||||
// file size, initialize this->m->lindict and return true.
|
||||
// file size, initialize m->lindict and return true.
|
||||
|
||||
// A linearized PDF spec's first object will be contained within
|
||||
// the first 1024 bytes of the file and will be a dictionary with
|
||||
@ -105,9 +105,9 @@ QPDF::isLinearized()
|
||||
|
||||
auto b = std::make_unique<char[]>(tbuf_size);
|
||||
char* buf = b.get();
|
||||
this->m->file->seek(0, SEEK_SET);
|
||||
m->file->seek(0, SEEK_SET);
|
||||
memset(buf, '\0', tbuf_size);
|
||||
this->m->file->read(buf, tbuf_size - 1);
|
||||
m->file->read(buf, tbuf_size - 1);
|
||||
|
||||
int lindict_obj = -1;
|
||||
char* p = buf;
|
||||
@ -121,12 +121,12 @@ QPDF::isLinearized()
|
||||
}
|
||||
// Seek to the digit. Then skip over digits for a potential
|
||||
// next iteration.
|
||||
this->m->file->seek(p - buf, SEEK_SET);
|
||||
m->file->seek(p - buf, SEEK_SET);
|
||||
while (((p - buf) < tbuf_size) && QUtil::is_digit(*p)) {
|
||||
++p;
|
||||
}
|
||||
|
||||
QPDFTokenizer::Token t1 = readToken(this->m->file);
|
||||
QPDFTokenizer::Token t1 = readToken(m->file);
|
||||
if (t1.isInteger() && readToken(m->file).isInteger() &&
|
||||
readToken(m->file).isWord("obj") &&
|
||||
(readToken(m->file).getType() == QPDFTokenizer::tt_dict_open)) {
|
||||
@ -151,16 +151,16 @@ QPDF::isLinearized()
|
||||
QPDFObjectHandle L = candidate.getKey("/L");
|
||||
if (L.isInteger()) {
|
||||
qpdf_offset_t Li = L.getIntValue();
|
||||
this->m->file->seek(0, SEEK_END);
|
||||
if (Li != this->m->file->tell()) {
|
||||
m->file->seek(0, SEEK_END);
|
||||
if (Li != m->file->tell()) {
|
||||
QTC::TC("qpdf", "QPDF /L mismatch");
|
||||
return false;
|
||||
} else {
|
||||
this->m->linp.file_size = Li;
|
||||
m->linp.file_size = Li;
|
||||
}
|
||||
}
|
||||
|
||||
this->m->lindict = candidate;
|
||||
m->lindict = candidate;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -177,12 +177,12 @@ QPDF::readLinearizationData()
|
||||
}
|
||||
|
||||
// /L is read and stored in linp by isLinearized()
|
||||
QPDFObjectHandle H = this->m->lindict.getKey("/H");
|
||||
QPDFObjectHandle O = this->m->lindict.getKey("/O");
|
||||
QPDFObjectHandle E = this->m->lindict.getKey("/E");
|
||||
QPDFObjectHandle N = this->m->lindict.getKey("/N");
|
||||
QPDFObjectHandle T = this->m->lindict.getKey("/T");
|
||||
QPDFObjectHandle P = this->m->lindict.getKey("/P");
|
||||
QPDFObjectHandle H = m->lindict.getKey("/H");
|
||||
QPDFObjectHandle O = m->lindict.getKey("/O");
|
||||
QPDFObjectHandle E = m->lindict.getKey("/E");
|
||||
QPDFObjectHandle N = m->lindict.getKey("/N");
|
||||
QPDFObjectHandle T = m->lindict.getKey("/T");
|
||||
QPDFObjectHandle P = m->lindict.getKey("/P");
|
||||
|
||||
if (!(H.isArray() && O.isInteger() && E.isInteger() && N.isInteger() &&
|
||||
T.isInteger() && (P.isInteger() || P.isNull()))) {
|
||||
@ -243,13 +243,13 @@ QPDF::readLinearizationData()
|
||||
}
|
||||
|
||||
// file_size initialized by isLinearized()
|
||||
this->m->linp.first_page_object = O.getIntValueAsInt();
|
||||
this->m->linp.first_page_end = E.getIntValue();
|
||||
this->m->linp.npages = N.getIntValueAsInt();
|
||||
this->m->linp.xref_zero_offset = T.getIntValue();
|
||||
this->m->linp.first_page = first_page;
|
||||
this->m->linp.H_offset = H0_offset;
|
||||
this->m->linp.H_length = H0_length;
|
||||
m->linp.first_page_object = O.getIntValueAsInt();
|
||||
m->linp.first_page_end = E.getIntValue();
|
||||
m->linp.npages = N.getIntValueAsInt();
|
||||
m->linp.xref_zero_offset = T.getIntValue();
|
||||
m->linp.first_page = first_page;
|
||||
m->linp.H_offset = H0_offset;
|
||||
m->linp.H_length = H0_length;
|
||||
|
||||
// Read hint streams
|
||||
|
||||
@ -296,7 +296,7 @@ QPDF::readLinearizationData()
|
||||
"/O (outline) offset is out of bounds");
|
||||
}
|
||||
readHGeneric(
|
||||
BitStream(h_buf + HOi, h_size - toS(HOi)), this->m->outline_hints);
|
||||
BitStream(h_buf + HOi, h_size - toS(HOi)), m->outline_hints);
|
||||
}
|
||||
}
|
||||
|
||||
@ -311,7 +311,7 @@ QPDF::readHintStream(Pipeline& pl, qpdf_offset_t offset, size_t length)
|
||||
QPDFObjGen(0, 0),
|
||||
og,
|
||||
false);
|
||||
ObjCache& oc = this->m->obj_cache[og];
|
||||
ObjCache& oc = m->obj_cache[og];
|
||||
qpdf_offset_t min_end_offset = oc.end_before_space;
|
||||
qpdf_offset_t max_end_offset = oc.end_after_space;
|
||||
if (!H.isStream()) {
|
||||
@ -331,7 +331,7 @@ QPDF::readHintStream(Pipeline& pl, qpdf_offset_t offset, size_t length)
|
||||
QTC::TC("qpdf", "QPDF hint table length indirect");
|
||||
// Force resolution
|
||||
(void)length_obj.getIntValue();
|
||||
ObjCache& oc2 = this->m->obj_cache[length_obj.getObjGen()];
|
||||
ObjCache& oc2 = m->obj_cache[length_obj.getObjGen()];
|
||||
min_end_offset = oc2.end_before_space;
|
||||
max_end_offset = oc2.end_after_space;
|
||||
} else {
|
||||
@ -356,7 +356,7 @@ QPDF::readHPageOffset(BitStream h)
|
||||
// All comments referring to the PDF spec refer to the spec for
|
||||
// version 1.4.
|
||||
|
||||
HPageOffset& t = this->m->page_offset_hints;
|
||||
HPageOffset& t = m->page_offset_hints;
|
||||
|
||||
t.min_nobjects = h.getBitsInt(32); // 1
|
||||
t.first_page_offset = h.getBitsInt(32); // 2
|
||||
@ -374,7 +374,7 @@ QPDF::readHPageOffset(BitStream h)
|
||||
|
||||
std::vector<HPageOffsetEntry>& entries = t.entries;
|
||||
entries.clear();
|
||||
int nitems = this->m->linp.npages;
|
||||
int nitems = m->linp.npages;
|
||||
load_vector_int(
|
||||
h,
|
||||
nitems,
|
||||
@ -424,7 +424,7 @@ QPDF::readHPageOffset(BitStream h)
|
||||
void
|
||||
QPDF::readHSharedObject(BitStream h)
|
||||
{
|
||||
HSharedObject& t = this->m->shared_object_hints;
|
||||
HSharedObject& t = m->shared_object_hints;
|
||||
|
||||
t.first_shared_obj = h.getBitsInt(32); // 1
|
||||
t.first_shared_offset = h.getBitsInt(32); // 2
|
||||
@ -485,7 +485,7 @@ QPDF::checkLinearizationInternal()
|
||||
|
||||
// Check all values in linearization parameter dictionary
|
||||
|
||||
LinParameters& p = this->m->linp;
|
||||
LinParameters& p = m->linp;
|
||||
|
||||
// L: file size in bytes -- checked by isLinearized
|
||||
|
||||
@ -506,7 +506,7 @@ QPDF::checkLinearizationInternal()
|
||||
for (size_t i = 0; i < toS(npages); ++i) {
|
||||
QPDFObjectHandle const& page = pages.at(i);
|
||||
QPDFObjGen og(page.getObjGen());
|
||||
if (this->m->xref_table[og].getType() == 2) {
|
||||
if (m->xref_table[og].getType() == 2) {
|
||||
linearizationWarning(
|
||||
"page dictionary for page " + std::to_string(i) +
|
||||
" is compressed");
|
||||
@ -514,22 +514,22 @@ QPDF::checkLinearizationInternal()
|
||||
}
|
||||
|
||||
// T: offset of whitespace character preceding xref entry for object 0
|
||||
this->m->file->seek(p.xref_zero_offset, SEEK_SET);
|
||||
m->file->seek(p.xref_zero_offset, SEEK_SET);
|
||||
while (true) {
|
||||
char ch;
|
||||
this->m->file->read(&ch, 1);
|
||||
m->file->read(&ch, 1);
|
||||
if (!((ch == ' ') || (ch == '\r') || (ch == '\n'))) {
|
||||
this->m->file->seek(-1, SEEK_CUR);
|
||||
m->file->seek(-1, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this->m->file->tell() != this->m->first_xref_item_offset) {
|
||||
if (m->file->tell() != m->first_xref_item_offset) {
|
||||
QTC::TC("qpdf", "QPDF err /T mismatch");
|
||||
linearizationWarning(
|
||||
"space before first xref item (/T) mismatch "
|
||||
"(computed = " +
|
||||
std::to_string(this->m->first_xref_item_offset) +
|
||||
"; file = " + std::to_string(this->m->file->tell()));
|
||||
std::to_string(m->first_xref_item_offset) +
|
||||
"; file = " + std::to_string(m->file->tell()));
|
||||
}
|
||||
|
||||
// P: first page number -- Implementation note 124 says Acrobat
|
||||
@ -540,7 +540,7 @@ QPDF::checkLinearizationInternal()
|
||||
// at the end of the containing xref section if any object streams
|
||||
// are in use.
|
||||
|
||||
if (this->m->uncompressed_after_compressed) {
|
||||
if (m->uncompressed_after_compressed) {
|
||||
linearizationWarning(
|
||||
"linearized file contains an uncompressed object"
|
||||
" after a compressed one in a cross-reference stream");
|
||||
@ -553,7 +553,7 @@ QPDF::checkLinearizationInternal()
|
||||
// uncompressed.
|
||||
{ // local scope
|
||||
std::map<int, int> object_stream_data;
|
||||
for (auto const& iter: this->m->xref_table) {
|
||||
for (auto const& iter: m->xref_table) {
|
||||
QPDFObjGen const& og = iter.first;
|
||||
QPDFXRefEntry const& entry = iter.second;
|
||||
if (entry.getType() == 2) {
|
||||
@ -575,18 +575,18 @@ QPDF::checkLinearizationInternal()
|
||||
// agree with pdlin. As of this writing, the test suite doesn't
|
||||
// contain any files with threads.
|
||||
|
||||
if (this->m->part6.empty()) {
|
||||
if (m->part6.empty()) {
|
||||
stopOnError("linearization part 6 unexpectedly empty");
|
||||
}
|
||||
qpdf_offset_t min_E = -1;
|
||||
qpdf_offset_t max_E = -1;
|
||||
for (auto const& oh: this->m->part6) {
|
||||
for (auto const& oh: m->part6) {
|
||||
QPDFObjGen og(oh.getObjGen());
|
||||
if (this->m->obj_cache.count(og) == 0) {
|
||||
if (m->obj_cache.count(og) == 0) {
|
||||
// All objects have to have been dereferenced to be classified.
|
||||
throw std::logic_error("linearization part6 object not in cache");
|
||||
}
|
||||
ObjCache const& oc = this->m->obj_cache[og];
|
||||
ObjCache const& oc = m->obj_cache[og];
|
||||
min_E = std::max(min_E, oc.end_before_space);
|
||||
max_E = std::max(max_E, oc.end_after_space);
|
||||
}
|
||||
@ -605,21 +605,21 @@ QPDF::checkLinearizationInternal()
|
||||
checkHPageOffset(pages, shared_idx_to_obj);
|
||||
checkHOutlines();
|
||||
|
||||
return !this->m->linearization_warnings;
|
||||
return !m->linearization_warnings;
|
||||
}
|
||||
|
||||
qpdf_offset_t
|
||||
QPDF::maxEnd(ObjUser const& ou)
|
||||
{
|
||||
if (this->m->obj_user_to_objects.count(ou) == 0) {
|
||||
if (m->obj_user_to_objects.count(ou) == 0) {
|
||||
stopOnError("no entry in object user table for requested object user");
|
||||
}
|
||||
qpdf_offset_t end = 0;
|
||||
for (auto const& og: this->m->obj_user_to_objects[ou]) {
|
||||
if (this->m->obj_cache.count(og) == 0) {
|
||||
for (auto const& og: m->obj_user_to_objects[ou]) {
|
||||
if (m->obj_cache.count(og) == 0) {
|
||||
stopOnError("unknown object referenced in object user table");
|
||||
}
|
||||
end = std::max(end, this->m->obj_cache[og].end_after_space);
|
||||
end = std::max(end, m->obj_cache[og].end_after_space);
|
||||
}
|
||||
return end;
|
||||
}
|
||||
@ -627,7 +627,7 @@ QPDF::maxEnd(ObjUser const& ou)
|
||||
qpdf_offset_t
|
||||
QPDF::getLinearizationOffset(QPDFObjGen const& og)
|
||||
{
|
||||
QPDFXRefEntry entry = this->m->xref_table[og];
|
||||
QPDFXRefEntry entry = m->xref_table[og];
|
||||
qpdf_offset_t result = 0;
|
||||
switch (entry.getType()) {
|
||||
case 1:
|
||||
@ -667,18 +667,17 @@ QPDF::lengthNextN(int first_object, int n)
|
||||
int length = 0;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
QPDFObjGen og(first_object + i, 0);
|
||||
if (this->m->xref_table.count(og) == 0) {
|
||||
if (m->xref_table.count(og) == 0) {
|
||||
linearizationWarning(
|
||||
"no xref table entry for " + std::to_string(first_object + i) +
|
||||
" 0");
|
||||
} else {
|
||||
if (this->m->obj_cache.count(og) == 0) {
|
||||
if (m->obj_cache.count(og) == 0) {
|
||||
stopOnError("found unknown object while"
|
||||
" calculating length for linearization data");
|
||||
}
|
||||
length +=
|
||||
toI(this->m->obj_cache[og].end_after_space -
|
||||
getLinearizationOffset(og));
|
||||
length += toI(
|
||||
m->obj_cache[og].end_after_space - getLinearizationOffset(og));
|
||||
}
|
||||
}
|
||||
return length;
|
||||
@ -708,9 +707,9 @@ QPDF::checkHPageOffset(
|
||||
|
||||
int npages = toI(pages.size());
|
||||
qpdf_offset_t table_offset =
|
||||
adjusted_offset(this->m->page_offset_hints.first_page_offset);
|
||||
adjusted_offset(m->page_offset_hints.first_page_offset);
|
||||
QPDFObjGen first_page_og(pages.at(0).getObjGen());
|
||||
if (this->m->xref_table.count(first_page_og) == 0) {
|
||||
if (m->xref_table.count(first_page_og) == 0) {
|
||||
stopOnError("supposed first page object is not known");
|
||||
}
|
||||
qpdf_offset_t offset = getLinearizationOffset(first_page_og);
|
||||
@ -721,17 +720,14 @@ QPDF::checkHPageOffset(
|
||||
for (int pageno = 0; pageno < npages; ++pageno) {
|
||||
QPDFObjGen page_og(pages.at(toS(pageno)).getObjGen());
|
||||
int first_object = page_og.getObj();
|
||||
if (this->m->xref_table.count(page_og) == 0) {
|
||||
if (m->xref_table.count(page_og) == 0) {
|
||||
stopOnError("unknown object in page offset hint table");
|
||||
}
|
||||
offset = getLinearizationOffset(page_og);
|
||||
|
||||
HPageOffsetEntry& he =
|
||||
this->m->page_offset_hints.entries.at(toS(pageno));
|
||||
CHPageOffsetEntry& ce =
|
||||
this->m->c_page_offset_data.entries.at(toS(pageno));
|
||||
int h_nobjects =
|
||||
he.delta_nobjects + this->m->page_offset_hints.min_nobjects;
|
||||
HPageOffsetEntry& he = m->page_offset_hints.entries.at(toS(pageno));
|
||||
CHPageOffsetEntry& ce = m->c_page_offset_data.entries.at(toS(pageno));
|
||||
int h_nobjects = he.delta_nobjects + m->page_offset_hints.min_nobjects;
|
||||
if (h_nobjects != ce.nobjects) {
|
||||
// This happens with pdlin when there are thumbnails.
|
||||
linearizationWarning(
|
||||
@ -743,8 +739,8 @@ QPDF::checkHPageOffset(
|
||||
// Use value for number of objects in hint table rather than
|
||||
// computed value if there is a discrepancy.
|
||||
int length = lengthNextN(first_object, h_nobjects);
|
||||
int h_length = toI(
|
||||
he.delta_page_length + this->m->page_offset_hints.min_page_length);
|
||||
int h_length =
|
||||
toI(he.delta_page_length + m->page_offset_hints.min_page_length);
|
||||
if (length != h_length) {
|
||||
// This condition almost certainly indicates a bad hint
|
||||
// table or a bug in this code.
|
||||
@ -778,10 +774,10 @@ QPDF::checkHPageOffset(
|
||||
|
||||
for (size_t i = 0; i < toS(ce.nshared_objects); ++i) {
|
||||
int idx = ce.shared_identifiers.at(i);
|
||||
if (idx >= this->m->c_shared_object_data.nshared_total) {
|
||||
if (idx >= m->c_shared_object_data.nshared_total) {
|
||||
stopOnError("index out of bounds for shared object hint table");
|
||||
}
|
||||
int obj = this->m->c_shared_object_data.entries.at(toS(idx)).object;
|
||||
int obj = m->c_shared_object_data.entries.at(toS(idx)).object;
|
||||
computed_shared.insert(obj);
|
||||
}
|
||||
|
||||
@ -831,7 +827,7 @@ QPDF::checkHSharedObject(
|
||||
// these whenever there are no shared objects not referenced by
|
||||
// the first page (i.e., nshared_total == nshared_first_page).
|
||||
|
||||
HSharedObject& so = this->m->shared_object_hints;
|
||||
HSharedObject& so = m->shared_object_hints;
|
||||
if (so.nshared_total < so.nshared_first_page) {
|
||||
linearizationWarning("shared object hint table: ntotal < nfirst_page");
|
||||
} else {
|
||||
@ -842,11 +838,11 @@ QPDF::checkHSharedObject(
|
||||
for (int i = 0; i < so.nshared_total; ++i) {
|
||||
if (i == so.nshared_first_page) {
|
||||
QTC::TC("qpdf", "QPDF lin check shared past first page");
|
||||
if (this->m->part8.empty()) {
|
||||
if (m->part8.empty()) {
|
||||
linearizationWarning("part 8 is empty but nshared_total > "
|
||||
"nshared_first_page");
|
||||
} else {
|
||||
int obj = this->m->part8.at(0).getObjectID();
|
||||
int obj = m->part8.at(0).getObjectID();
|
||||
if (obj != so.first_shared_obj) {
|
||||
linearizationWarning(
|
||||
"first shared object number mismatch: "
|
||||
@ -859,7 +855,7 @@ QPDF::checkHSharedObject(
|
||||
cur_object = so.first_shared_obj;
|
||||
|
||||
QPDFObjGen og(cur_object, 0);
|
||||
if (this->m->xref_table.count(og) == 0) {
|
||||
if (m->xref_table.count(og) == 0) {
|
||||
stopOnError("unknown object in shared object hint table");
|
||||
}
|
||||
qpdf_offset_t offset = getLinearizationOffset(og);
|
||||
@ -901,13 +897,12 @@ QPDF::checkHOutlines()
|
||||
// wrong starting place). pdlin appears to generate correct
|
||||
// values in those cases.
|
||||
|
||||
if (this->m->c_outline_data.nobjects == this->m->outline_hints.nobjects) {
|
||||
if (this->m->c_outline_data.nobjects == 0) {
|
||||
if (m->c_outline_data.nobjects == m->outline_hints.nobjects) {
|
||||
if (m->c_outline_data.nobjects == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->m->c_outline_data.first_object ==
|
||||
this->m->outline_hints.first_object) {
|
||||
if (m->c_outline_data.first_object == m->outline_hints.first_object) {
|
||||
// Check length and offset. Acrobat gets these wrong.
|
||||
QPDFObjectHandle outlines = getRoot().getKey("/Outlines");
|
||||
if (!outlines.isIndirect()) {
|
||||
@ -919,21 +914,21 @@ QPDF::checkHOutlines()
|
||||
return;
|
||||
}
|
||||
QPDFObjGen og(outlines.getObjGen());
|
||||
if (this->m->xref_table.count(og) == 0) {
|
||||
if (m->xref_table.count(og) == 0) {
|
||||
stopOnError("unknown object in outlines hint table");
|
||||
}
|
||||
qpdf_offset_t offset = getLinearizationOffset(og);
|
||||
ObjUser ou(ObjUser::ou_root_key, "/Outlines");
|
||||
int length = toI(maxEnd(ou) - offset);
|
||||
qpdf_offset_t table_offset =
|
||||
adjusted_offset(this->m->outline_hints.first_object_offset);
|
||||
adjusted_offset(m->outline_hints.first_object_offset);
|
||||
if (offset != table_offset) {
|
||||
linearizationWarning(
|
||||
"incorrect offset in outlines table: hint table = " +
|
||||
std::to_string(table_offset) +
|
||||
"; computed = " + std::to_string(offset));
|
||||
}
|
||||
int table_length = this->m->outline_hints.group_length;
|
||||
int table_length = m->outline_hints.group_length;
|
||||
if (length != table_length) {
|
||||
linearizationWarning(
|
||||
"incorrect length in outlines table: hint table = " +
|
||||
@ -964,28 +959,28 @@ QPDF::showLinearizationData()
|
||||
void
|
||||
QPDF::dumpLinearizationDataInternal()
|
||||
{
|
||||
*this->m->log->getInfo()
|
||||
<< this->m->file->getName() << ": linearization data:\n\n";
|
||||
*m->log->getInfo() << m->file->getName() << ": linearization data:\n\n";
|
||||
|
||||
*this->m->log->getInfo()
|
||||
<< "file_size: " << this->m->linp.file_size << "\n"
|
||||
<< "first_page_object: " << this->m->linp.first_page_object << "\n"
|
||||
<< "first_page_end: " << this->m->linp.first_page_end << "\n"
|
||||
<< "npages: " << this->m->linp.npages << "\n"
|
||||
<< "xref_zero_offset: " << this->m->linp.xref_zero_offset << "\n"
|
||||
<< "first_page: " << this->m->linp.first_page << "\n"
|
||||
<< "H_offset: " << this->m->linp.H_offset << "\n"
|
||||
<< "H_length: " << this->m->linp.H_length << "\n"
|
||||
<< "\n";
|
||||
*m->log->getInfo() << "file_size: " << m->linp.file_size << "\n"
|
||||
<< "first_page_object: " << m->linp.first_page_object
|
||||
<< "\n"
|
||||
<< "first_page_end: " << m->linp.first_page_end << "\n"
|
||||
<< "npages: " << m->linp.npages << "\n"
|
||||
<< "xref_zero_offset: " << m->linp.xref_zero_offset
|
||||
<< "\n"
|
||||
<< "first_page: " << m->linp.first_page << "\n"
|
||||
<< "H_offset: " << m->linp.H_offset << "\n"
|
||||
<< "H_length: " << m->linp.H_length << "\n"
|
||||
<< "\n";
|
||||
|
||||
*this->m->log->getInfo() << "Page Offsets Hint Table\n\n";
|
||||
*m->log->getInfo() << "Page Offsets Hint Table\n\n";
|
||||
dumpHPageOffset();
|
||||
*this->m->log->getInfo() << "\nShared Objects Hint Table\n\n";
|
||||
*m->log->getInfo() << "\nShared Objects Hint Table\n\n";
|
||||
dumpHSharedObject();
|
||||
|
||||
if (this->m->outline_hints.nobjects > 0) {
|
||||
*this->m->log->getInfo() << "\nOutlines Hint Table\n\n";
|
||||
dumpHGeneric(this->m->outline_hints);
|
||||
if (m->outline_hints.nobjects > 0) {
|
||||
*m->log->getInfo() << "\nOutlines Hint Table\n\n";
|
||||
dumpHGeneric(m->outline_hints);
|
||||
}
|
||||
}
|
||||
|
||||
@ -995,8 +990,8 @@ QPDF::adjusted_offset(qpdf_offset_t offset)
|
||||
// All offsets >= H_offset have to be increased by H_length
|
||||
// since all hint table location values disregard the hint table
|
||||
// itself.
|
||||
if (offset >= this->m->linp.H_offset) {
|
||||
return offset + this->m->linp.H_length;
|
||||
if (offset >= m->linp.H_offset) {
|
||||
return offset + m->linp.H_length;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
@ -1004,8 +999,8 @@ QPDF::adjusted_offset(qpdf_offset_t offset)
|
||||
void
|
||||
QPDF::dumpHPageOffset()
|
||||
{
|
||||
HPageOffset& t = this->m->page_offset_hints;
|
||||
*this->m->log->getInfo()
|
||||
HPageOffset& t = m->page_offset_hints;
|
||||
*m->log->getInfo()
|
||||
<< "min_nobjects: " << t.min_nobjects << "\n"
|
||||
<< "first_page_offset: " << adjusted_offset(t.first_page_offset) << "\n"
|
||||
<< "nbits_delta_nobjects: " << t.nbits_delta_nobjects << "\n"
|
||||
@ -1022,9 +1017,9 @@ QPDF::dumpHPageOffset()
|
||||
<< "nbits_shared_numerator: " << t.nbits_shared_numerator << "\n"
|
||||
<< "shared_denominator: " << t.shared_denominator << "\n";
|
||||
|
||||
for (size_t i1 = 0; i1 < toS(this->m->linp.npages); ++i1) {
|
||||
for (size_t i1 = 0; i1 < toS(m->linp.npages); ++i1) {
|
||||
HPageOffsetEntry& pe = t.entries.at(i1);
|
||||
*this->m->log->getInfo()
|
||||
*m->log->getInfo()
|
||||
<< "Page " << i1 << ":\n"
|
||||
<< " nobjects: " << pe.delta_nobjects + t.min_nobjects << "\n"
|
||||
<< " length: " << pe.delta_page_length + t.min_page_length
|
||||
@ -1036,10 +1031,10 @@ QPDF::dumpHPageOffset()
|
||||
<< pe.delta_content_length + t.min_content_length << "\n"
|
||||
<< " nshared_objects: " << pe.nshared_objects << "\n";
|
||||
for (size_t i2 = 0; i2 < toS(pe.nshared_objects); ++i2) {
|
||||
*this->m->log->getInfo() << " identifier " << i2 << ": "
|
||||
<< pe.shared_identifiers.at(i2) << "\n";
|
||||
*this->m->log->getInfo() << " numerator " << i2 << ": "
|
||||
<< pe.shared_numerators.at(i2) << "\n";
|
||||
*m->log->getInfo() << " identifier " << i2 << ": "
|
||||
<< pe.shared_identifiers.at(i2) << "\n";
|
||||
*m->log->getInfo() << " numerator " << i2 << ": "
|
||||
<< pe.shared_numerators.at(i2) << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1047,30 +1042,30 @@ QPDF::dumpHPageOffset()
|
||||
void
|
||||
QPDF::dumpHSharedObject()
|
||||
{
|
||||
HSharedObject& t = this->m->shared_object_hints;
|
||||
*this->m->log->getInfo()
|
||||
<< "first_shared_obj: " << t.first_shared_obj << "\n"
|
||||
<< "first_shared_offset: " << adjusted_offset(t.first_shared_offset)
|
||||
<< "\n"
|
||||
<< "nshared_first_page: " << t.nshared_first_page << "\n"
|
||||
<< "nshared_total: " << t.nshared_total << "\n"
|
||||
<< "nbits_nobjects: " << t.nbits_nobjects << "\n"
|
||||
<< "min_group_length: " << t.min_group_length << "\n"
|
||||
<< "nbits_delta_group_length: " << t.nbits_delta_group_length << "\n";
|
||||
HSharedObject& t = m->shared_object_hints;
|
||||
*m->log->getInfo() << "first_shared_obj: " << t.first_shared_obj << "\n"
|
||||
<< "first_shared_offset: "
|
||||
<< adjusted_offset(t.first_shared_offset) << "\n"
|
||||
<< "nshared_first_page: " << t.nshared_first_page << "\n"
|
||||
<< "nshared_total: " << t.nshared_total << "\n"
|
||||
<< "nbits_nobjects: " << t.nbits_nobjects << "\n"
|
||||
<< "min_group_length: " << t.min_group_length << "\n"
|
||||
<< "nbits_delta_group_length: "
|
||||
<< t.nbits_delta_group_length << "\n";
|
||||
|
||||
for (size_t i = 0; i < toS(t.nshared_total); ++i) {
|
||||
HSharedObjectEntry& se = t.entries.at(i);
|
||||
*this->m->log->getInfo()
|
||||
<< "Shared Object " << i << ":\n"
|
||||
<< " group length: " << se.delta_group_length + t.min_group_length
|
||||
<< "\n";
|
||||
*m->log->getInfo() << "Shared Object " << i << ":\n"
|
||||
<< " group length: "
|
||||
<< se.delta_group_length + t.min_group_length
|
||||
<< "\n";
|
||||
// PDF spec says signature present nobjects_minus_one are
|
||||
// always 0, so print them only if they have a non-zero value.
|
||||
if (se.signature_present) {
|
||||
*this->m->log->getInfo() << " signature present\n";
|
||||
*m->log->getInfo() << " signature present\n";
|
||||
}
|
||||
if (se.nobjects_minus_one != 0) {
|
||||
*this->m->log->getInfo()
|
||||
*m->log->getInfo()
|
||||
<< " nobjects: " << se.nobjects_minus_one + 1 << "\n";
|
||||
}
|
||||
}
|
||||
@ -1079,12 +1074,11 @@ QPDF::dumpHSharedObject()
|
||||
void
|
||||
QPDF::dumpHGeneric(HGeneric& t)
|
||||
{
|
||||
*this->m->log->getInfo()
|
||||
<< "first_object: " << t.first_object << "\n"
|
||||
<< "first_object_offset: " << adjusted_offset(t.first_object_offset)
|
||||
<< "\n"
|
||||
<< "nobjects: " << t.nobjects << "\n"
|
||||
<< "group_length: " << t.group_length << "\n";
|
||||
*m->log->getInfo() << "first_object: " << t.first_object << "\n"
|
||||
<< "first_object_offset: "
|
||||
<< adjusted_offset(t.first_object_offset) << "\n"
|
||||
<< "nobjects: " << t.nobjects << "\n"
|
||||
<< "group_length: " << t.group_length << "\n";
|
||||
}
|
||||
|
||||
void
|
||||
@ -1097,7 +1091,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
// this function. Note that actual offsets and lengths are not
|
||||
// computed here, but anything related to object ordering is.
|
||||
|
||||
if (this->m->object_to_obj_users.empty()) {
|
||||
if (m->object_to_obj_users.empty()) {
|
||||
// Note that we can't call optimize here because we don't know
|
||||
// whether it should be called with or without allow changes.
|
||||
throw std::logic_error(
|
||||
@ -1152,15 +1146,15 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
|
||||
// * outlines: part 6 or 9
|
||||
|
||||
this->m->part4.clear();
|
||||
this->m->part6.clear();
|
||||
this->m->part7.clear();
|
||||
this->m->part8.clear();
|
||||
this->m->part9.clear();
|
||||
this->m->c_linp = LinParameters();
|
||||
this->m->c_page_offset_data = CHPageOffset();
|
||||
this->m->c_shared_object_data = CHSharedObject();
|
||||
this->m->c_outline_data = HGeneric();
|
||||
m->part4.clear();
|
||||
m->part6.clear();
|
||||
m->part7.clear();
|
||||
m->part8.clear();
|
||||
m->part9.clear();
|
||||
m->c_linp = LinParameters();
|
||||
m->c_page_offset_data = CHPageOffset();
|
||||
m->c_shared_object_data = CHSharedObject();
|
||||
m->c_outline_data = HGeneric();
|
||||
|
||||
QPDFObjectHandle root = getRoot();
|
||||
bool outlines_in_first_page = false;
|
||||
@ -1199,7 +1193,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
std::set<QPDFObjGen> lc_outlines;
|
||||
std::set<QPDFObjGen> lc_root;
|
||||
|
||||
for (auto& oiter: this->m->object_to_obj_users) {
|
||||
for (auto& oiter: m->object_to_obj_users) {
|
||||
QPDFObjGen const& og = oiter.first;
|
||||
std::set<ObjUser>& ous = oiter.second;
|
||||
|
||||
@ -1315,9 +1309,8 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
// npages is the size of the existing pages vector, which has been
|
||||
// created by traversing the pages tree, and as such is a
|
||||
// reasonable size.
|
||||
this->m->c_linp.npages = npages;
|
||||
this->m->c_page_offset_data.entries =
|
||||
std::vector<CHPageOffsetEntry>(toS(npages));
|
||||
m->c_linp.npages = npages;
|
||||
m->c_page_offset_data.entries = std::vector<CHPageOffsetEntry>(toS(npages));
|
||||
|
||||
// Part 4: open document objects. We don't care about the order.
|
||||
|
||||
@ -1325,9 +1318,9 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
stopOnError("found other than one root while"
|
||||
" calculating linearization data");
|
||||
}
|
||||
this->m->part4.push_back(getObject(*(lc_root.begin())));
|
||||
m->part4.push_back(getObject(*(lc_root.begin())));
|
||||
for (auto const& og: lc_open_document) {
|
||||
this->m->part4.push_back(getObject(og));
|
||||
m->part4.push_back(getObject(og));
|
||||
}
|
||||
|
||||
// Part 6: first page objects. Note: implementation note 124
|
||||
@ -1347,8 +1340,8 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
"object not in lc_first_page_private");
|
||||
}
|
||||
lc_first_page_private.erase(first_page_og);
|
||||
this->m->c_linp.first_page_object = pages.at(0).getObjectID();
|
||||
this->m->part6.push_back(pages.at(0));
|
||||
m->c_linp.first_page_object = pages.at(0).getObjectID();
|
||||
m->part6.push_back(pages.at(0));
|
||||
|
||||
// The PDF spec "recommends" an order for the rest of the objects,
|
||||
// but we are going to disregard it except to the extent that it
|
||||
@ -1356,16 +1349,16 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
// hint tables.
|
||||
|
||||
for (auto const& og: lc_first_page_private) {
|
||||
this->m->part6.push_back(getObject(og));
|
||||
m->part6.push_back(getObject(og));
|
||||
}
|
||||
|
||||
for (auto const& og: lc_first_page_shared) {
|
||||
this->m->part6.push_back(getObject(og));
|
||||
m->part6.push_back(getObject(og));
|
||||
}
|
||||
|
||||
// Place the outline dictionary if it goes in the first page section.
|
||||
if (outlines_in_first_page) {
|
||||
pushOutlinesToPart(this->m->part6, lc_outlines, object_stream_data);
|
||||
pushOutlinesToPart(m->part6, lc_outlines, object_stream_data);
|
||||
}
|
||||
|
||||
// Fill in page offset hint table information for the first page.
|
||||
@ -1374,8 +1367,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
// in garbage values for all the shared object identifiers on the
|
||||
// first page.
|
||||
|
||||
this->m->c_page_offset_data.entries.at(0).nobjects =
|
||||
toI(this->m->part6.size());
|
||||
m->c_page_offset_data.entries.at(0).nobjects = toI(m->part6.size());
|
||||
|
||||
// Part 7: other pages' private objects
|
||||
|
||||
@ -1391,23 +1383,23 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
std::to_string(i) + " not in lc_other_page_private");
|
||||
}
|
||||
lc_other_page_private.erase(page_og);
|
||||
this->m->part7.push_back(pages.at(i));
|
||||
m->part7.push_back(pages.at(i));
|
||||
|
||||
// Place all non-shared objects referenced by this page,
|
||||
// updating the page object count for the hint table.
|
||||
|
||||
this->m->c_page_offset_data.entries.at(i).nobjects = 1;
|
||||
m->c_page_offset_data.entries.at(i).nobjects = 1;
|
||||
|
||||
ObjUser ou(ObjUser::ou_page, toI(i));
|
||||
if (this->m->obj_user_to_objects.count(ou) == 0) {
|
||||
if (m->obj_user_to_objects.count(ou) == 0) {
|
||||
stopOnError("found unreferenced page while"
|
||||
" calculating linearization data");
|
||||
}
|
||||
for (auto const& og: this->m->obj_user_to_objects[ou]) {
|
||||
for (auto const& og: m->obj_user_to_objects[ou]) {
|
||||
if (lc_other_page_private.count(og)) {
|
||||
lc_other_page_private.erase(og);
|
||||
this->m->part7.push_back(getObject(og));
|
||||
++this->m->c_page_offset_data.entries.at(i).nobjects;
|
||||
m->part7.push_back(getObject(og));
|
||||
++m->c_page_offset_data.entries.at(i).nobjects;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1423,7 +1415,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
|
||||
// Order is unimportant.
|
||||
for (auto const& og: lc_other_page_shared) {
|
||||
this->m->part8.push_back(getObject(og));
|
||||
m->part8.push_back(getObject(og));
|
||||
}
|
||||
|
||||
// Part 9: other objects
|
||||
@ -1437,7 +1429,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
|
||||
// Place the pages tree.
|
||||
std::set<QPDFObjGen> pages_ogs =
|
||||
this->m->obj_user_to_objects[ObjUser(ObjUser::ou_root_key, "/Pages")];
|
||||
m->obj_user_to_objects[ObjUser(ObjUser::ou_root_key, "/Pages")];
|
||||
if (pages_ogs.empty()) {
|
||||
stopOnError("found empty pages tree while"
|
||||
" calculating linearization data");
|
||||
@ -1445,7 +1437,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
for (auto const& og: pages_ogs) {
|
||||
if (lc_other.count(og)) {
|
||||
lc_other.erase(og);
|
||||
this->m->part9.push_back(getObject(og));
|
||||
m->part9.push_back(getObject(og));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1460,7 +1452,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
QPDFObjGen thumb_og(thumb.getObjGen());
|
||||
if (lc_thumbnail_private.count(thumb_og)) {
|
||||
lc_thumbnail_private.erase(thumb_og);
|
||||
this->m->part9.push_back(thumb);
|
||||
m->part9.push_back(thumb);
|
||||
} else {
|
||||
// No internal error this time...there's nothing to
|
||||
// stop this object from having been referred to
|
||||
@ -1475,7 +1467,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
for (auto const& og: ogs) {
|
||||
if (lc_thumbnail_private.count(og)) {
|
||||
lc_thumbnail_private.erase(og);
|
||||
this->m->part9.push_back(getObject(og));
|
||||
m->part9.push_back(getObject(og));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1488,24 +1480,24 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
|
||||
// Place shared thumbnail objects
|
||||
for (auto const& og: lc_thumbnail_shared) {
|
||||
this->m->part9.push_back(getObject(og));
|
||||
m->part9.push_back(getObject(og));
|
||||
}
|
||||
|
||||
// Place outlines unless in first page
|
||||
if (!outlines_in_first_page) {
|
||||
pushOutlinesToPart(this->m->part9, lc_outlines, object_stream_data);
|
||||
pushOutlinesToPart(m->part9, lc_outlines, object_stream_data);
|
||||
}
|
||||
|
||||
// Place all remaining objects
|
||||
for (auto const& og: lc_other) {
|
||||
this->m->part9.push_back(getObject(og));
|
||||
m->part9.push_back(getObject(og));
|
||||
}
|
||||
|
||||
// Make sure we got everything exactly once.
|
||||
|
||||
size_t num_placed = this->m->part4.size() + this->m->part6.size() +
|
||||
this->m->part7.size() + this->m->part8.size() + this->m->part9.size();
|
||||
size_t num_wanted = this->m->object_to_obj_users.size();
|
||||
size_t num_placed = m->part4.size() + m->part6.size() + m->part7.size() +
|
||||
m->part8.size() + m->part9.size();
|
||||
size_t num_wanted = m->object_to_obj_users.size();
|
||||
if (num_placed != num_wanted) {
|
||||
stopOnError(
|
||||
"INTERNAL ERROR: QPDF::calculateLinearizationData: wrong "
|
||||
@ -1527,31 +1519,27 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
// can map from object number only without regards to generation.
|
||||
std::map<int, int> obj_to_index;
|
||||
|
||||
this->m->c_shared_object_data.nshared_first_page =
|
||||
toI(this->m->part6.size());
|
||||
this->m->c_shared_object_data.nshared_total =
|
||||
this->m->c_shared_object_data.nshared_first_page +
|
||||
toI(this->m->part8.size());
|
||||
m->c_shared_object_data.nshared_first_page = toI(m->part6.size());
|
||||
m->c_shared_object_data.nshared_total =
|
||||
m->c_shared_object_data.nshared_first_page + toI(m->part8.size());
|
||||
|
||||
std::vector<CHSharedObjectEntry>& shared =
|
||||
this->m->c_shared_object_data.entries;
|
||||
for (auto& oh: this->m->part6) {
|
||||
std::vector<CHSharedObjectEntry>& shared = m->c_shared_object_data.entries;
|
||||
for (auto& oh: m->part6) {
|
||||
int obj = oh.getObjectID();
|
||||
obj_to_index[obj] = toI(shared.size());
|
||||
shared.push_back(CHSharedObjectEntry(obj));
|
||||
}
|
||||
QTC::TC("qpdf", "QPDF lin part 8 empty", this->m->part8.empty() ? 1 : 0);
|
||||
if (!this->m->part8.empty()) {
|
||||
this->m->c_shared_object_data.first_shared_obj =
|
||||
this->m->part8.at(0).getObjectID();
|
||||
for (auto& oh: this->m->part8) {
|
||||
QTC::TC("qpdf", "QPDF lin part 8 empty", m->part8.empty() ? 1 : 0);
|
||||
if (!m->part8.empty()) {
|
||||
m->c_shared_object_data.first_shared_obj = m->part8.at(0).getObjectID();
|
||||
for (auto& oh: m->part8) {
|
||||
int obj = oh.getObjectID();
|
||||
obj_to_index[obj] = toI(shared.size());
|
||||
shared.push_back(CHSharedObjectEntry(obj));
|
||||
}
|
||||
}
|
||||
if (static_cast<size_t>(this->m->c_shared_object_data.nshared_total) !=
|
||||
this->m->c_shared_object_data.entries.size()) {
|
||||
if (static_cast<size_t>(m->c_shared_object_data.nshared_total) !=
|
||||
m->c_shared_object_data.entries.size()) {
|
||||
stopOnError("shared object hint table has wrong number of entries");
|
||||
}
|
||||
|
||||
@ -1559,14 +1547,14 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
|
||||
// first page.
|
||||
|
||||
for (size_t i = 1; i < toS(npages); ++i) {
|
||||
CHPageOffsetEntry& pe = this->m->c_page_offset_data.entries.at(i);
|
||||
CHPageOffsetEntry& pe = m->c_page_offset_data.entries.at(i);
|
||||
ObjUser ou(ObjUser::ou_page, toI(i));
|
||||
if (this->m->obj_user_to_objects.count(ou) == 0) {
|
||||
if (m->obj_user_to_objects.count(ou) == 0) {
|
||||
stopOnError("found unreferenced page while"
|
||||
" calculating linearization data");
|
||||
}
|
||||
for (auto const& og: this->m->obj_user_to_objects[ou]) {
|
||||
if ((this->m->object_to_obj_users[og].size() > 1) &&
|
||||
for (auto const& og: m->obj_user_to_objects[ou]) {
|
||||
if ((m->object_to_obj_users[og].size() > 1) &&
|
||||
(obj_to_index.count(og.getObj()) > 0)) {
|
||||
int idx = obj_to_index[og.getObj()];
|
||||
++pe.nshared_objects;
|
||||
@ -1592,16 +1580,16 @@ QPDF::pushOutlinesToPart(
|
||||
QTC::TC(
|
||||
"qpdf",
|
||||
"QPDF lin outlines in part",
|
||||
((&part == (&this->m->part6)) ? 0
|
||||
: (&part == (&this->m->part9)) ? 1
|
||||
: 9999)); // can't happen
|
||||
this->m->c_outline_data.first_object = outlines_og.getObj();
|
||||
this->m->c_outline_data.nobjects = 1;
|
||||
((&part == (&m->part6)) ? 0
|
||||
: (&part == (&m->part9)) ? 1
|
||||
: 9999)); // can't happen
|
||||
m->c_outline_data.first_object = outlines_og.getObj();
|
||||
m->c_outline_data.nobjects = 1;
|
||||
lc_outlines.erase(outlines_og);
|
||||
part.push_back(outlines);
|
||||
for (auto const& og: lc_outlines) {
|
||||
part.push_back(getObject(og));
|
||||
++this->m->c_outline_data.nobjects;
|
||||
++m->c_outline_data.nobjects;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1615,11 +1603,11 @@ QPDF::getLinearizedParts(
|
||||
std::vector<QPDFObjectHandle>& part9)
|
||||
{
|
||||
calculateLinearizationData(object_stream_data);
|
||||
part4 = this->m->part4;
|
||||
part6 = this->m->part6;
|
||||
part7 = this->m->part7;
|
||||
part8 = this->m->part8;
|
||||
part9 = this->m->part9;
|
||||
part4 = m->part4;
|
||||
part6 = m->part6;
|
||||
part7 = m->part7;
|
||||
part8 = m->part8;
|
||||
part9 = m->part9;
|
||||
}
|
||||
|
||||
static inline int
|
||||
@ -1668,7 +1656,7 @@ QPDF::calculateHPageOffset(
|
||||
|
||||
std::vector<QPDFObjectHandle> const& pages = getAllPages();
|
||||
size_t npages = pages.size();
|
||||
CHPageOffset& cph = this->m->c_page_offset_data;
|
||||
CHPageOffset& cph = m->c_page_offset_data;
|
||||
std::vector<CHPageOffsetEntry>& cphe = cph.entries;
|
||||
|
||||
// Calculate minimum and maximum values for number of objects per
|
||||
@ -1681,7 +1669,7 @@ QPDF::calculateHPageOffset(
|
||||
int max_length = min_length;
|
||||
int max_shared = cphe.at(0).nshared_objects;
|
||||
|
||||
HPageOffset& ph = this->m->page_offset_hints;
|
||||
HPageOffset& ph = m->page_offset_hints;
|
||||
std::vector<HPageOffsetEntry>& phe = ph.entries;
|
||||
// npages is the size of the existing pages array.
|
||||
phe = std::vector<HPageOffsetEntry>(npages);
|
||||
@ -1717,8 +1705,7 @@ QPDF::calculateHPageOffset(
|
||||
ph.min_page_length = min_length;
|
||||
ph.nbits_delta_page_length = nbits(max_length - min_length);
|
||||
ph.nbits_nshared_objects = nbits(max_shared);
|
||||
ph.nbits_shared_identifier =
|
||||
nbits(this->m->c_shared_object_data.nshared_total);
|
||||
ph.nbits_shared_identifier = nbits(m->c_shared_object_data.nshared_total);
|
||||
ph.shared_denominator = 4; // doesn't matter
|
||||
|
||||
// It isn't clear how to compute content offset and content
|
||||
@ -1754,9 +1741,9 @@ QPDF::calculateHSharedObject(
|
||||
std::map<int, qpdf_offset_t> const& lengths,
|
||||
std::map<int, int> const& obj_renumber)
|
||||
{
|
||||
CHSharedObject& cso = this->m->c_shared_object_data;
|
||||
CHSharedObject& cso = m->c_shared_object_data;
|
||||
std::vector<CHSharedObjectEntry>& csoe = cso.entries;
|
||||
HSharedObject& so = this->m->shared_object_hints;
|
||||
HSharedObject& so = m->shared_object_hints;
|
||||
std::vector<HSharedObjectEntry>& soe = so.entries;
|
||||
soe.clear();
|
||||
|
||||
@ -1804,13 +1791,13 @@ QPDF::calculateHOutline(
|
||||
std::map<int, qpdf_offset_t> const& lengths,
|
||||
std::map<int, int> const& obj_renumber)
|
||||
{
|
||||
HGeneric& cho = this->m->c_outline_data;
|
||||
HGeneric& cho = m->c_outline_data;
|
||||
|
||||
if (cho.nobjects == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
HGeneric& ho = this->m->outline_hints;
|
||||
HGeneric& ho = m->outline_hints;
|
||||
|
||||
ho.first_object = (*(obj_renumber.find(cho.first_object))).second;
|
||||
ho.first_object_offset = (*(xref.find(ho.first_object))).second.getOffset();
|
||||
@ -1861,7 +1848,7 @@ write_vector_vector(
|
||||
void
|
||||
QPDF::writeHPageOffset(BitWriter& w)
|
||||
{
|
||||
HPageOffset& t = this->m->page_offset_hints;
|
||||
HPageOffset& t = m->page_offset_hints;
|
||||
|
||||
w.writeBitsInt(t.min_nobjects, 32); // 1
|
||||
w.writeBitsInt(toI(t.first_page_offset), 32); // 2
|
||||
@ -1929,7 +1916,7 @@ QPDF::writeHPageOffset(BitWriter& w)
|
||||
void
|
||||
QPDF::writeHSharedObject(BitWriter& w)
|
||||
{
|
||||
HSharedObject& t = this->m->shared_object_hints;
|
||||
HSharedObject& t = m->shared_object_hints;
|
||||
|
||||
w.writeBitsInt(t.first_shared_obj, 32); // 1
|
||||
w.writeBitsInt(toI(t.first_shared_offset), 32); // 2
|
||||
@ -2004,9 +1991,9 @@ QPDF::generateHintStream(
|
||||
S = toI(c.getCount());
|
||||
writeHSharedObject(w);
|
||||
O = 0;
|
||||
if (this->m->outline_hints.nobjects > 0) {
|
||||
if (m->outline_hints.nobjects > 0) {
|
||||
O = toI(c.getCount());
|
||||
writeHGeneric(w, this->m->outline_hints);
|
||||
writeHGeneric(w, m->outline_hints);
|
||||
}
|
||||
c.finish();
|
||||
|
||||
|
@ -59,7 +59,7 @@ QPDF::optimize(
|
||||
bool allow_changes,
|
||||
std::function<int(QPDFObjectHandle&)> skip_stream_parameters)
|
||||
{
|
||||
if (!this->m->obj_user_to_objects.empty()) {
|
||||
if (!m->obj_user_to_objects.empty()) {
|
||||
// already optimized
|
||||
return;
|
||||
}
|
||||
@ -77,26 +77,26 @@ QPDF::optimize(
|
||||
}
|
||||
|
||||
// Traverse pages tree pushing all inherited resources down to the
|
||||
// page level. This also initializes this->m->all_pages.
|
||||
// page level. This also initializes m->all_pages.
|
||||
pushInheritedAttributesToPage(allow_changes, false);
|
||||
|
||||
// Traverse pages
|
||||
int n = toI(this->m->all_pages.size());
|
||||
int n = toI(m->all_pages.size());
|
||||
for (int pageno = 0; pageno < n; ++pageno) {
|
||||
updateObjectMaps(
|
||||
ObjUser(ObjUser::ou_page, pageno),
|
||||
this->m->all_pages.at(toS(pageno)),
|
||||
m->all_pages.at(toS(pageno)),
|
||||
skip_stream_parameters);
|
||||
}
|
||||
|
||||
// Traverse document-level items
|
||||
for (auto const& key: this->m->trailer.getKeys()) {
|
||||
for (auto const& key: m->trailer.getKeys()) {
|
||||
if (key == "/Root") {
|
||||
// handled separately
|
||||
} else {
|
||||
updateObjectMaps(
|
||||
ObjUser(ObjUser::ou_trailer_key, key),
|
||||
this->m->trailer.getKey(key),
|
||||
m->trailer.getKey(key),
|
||||
skip_stream_parameters);
|
||||
}
|
||||
}
|
||||
@ -116,8 +116,8 @@ QPDF::optimize(
|
||||
|
||||
ObjUser root_ou = ObjUser(ObjUser::ou_root);
|
||||
auto root_og = QPDFObjGen(root.getObjGen());
|
||||
this->m->obj_user_to_objects[root_ou].insert(root_og);
|
||||
this->m->object_to_obj_users[root_og].insert(root_ou);
|
||||
m->obj_user_to_objects[root_ou].insert(root_og);
|
||||
m->object_to_obj_users[root_og].insert(root_ou);
|
||||
|
||||
filterCompressedObjects(object_stream_data);
|
||||
}
|
||||
@ -138,7 +138,7 @@ QPDF::pushInheritedAttributesToPage(bool allow_changes, bool warn_skipped_keys)
|
||||
// The record of whether we've done this is cleared by
|
||||
// updateAllPagesCache(). If we're warning for skipped keys,
|
||||
// re-traverse unconditionally.
|
||||
if (this->m->pushed_inherited_attributes_to_pages && (!warn_skipped_keys)) {
|
||||
if (m->pushed_inherited_attributes_to_pages && (!warn_skipped_keys)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -151,7 +151,7 @@ QPDF::pushInheritedAttributesToPage(bool allow_changes, bool warn_skipped_keys)
|
||||
// Pages nodes that contain values for them.
|
||||
std::map<std::string, std::vector<QPDFObjectHandle>> key_ancestors;
|
||||
pushInheritedAttributesToPageInternal(
|
||||
this->m->trailer.getKey("/Root").getKey("/Pages"),
|
||||
m->trailer.getKey("/Root").getKey("/Pages"),
|
||||
key_ancestors,
|
||||
allow_changes,
|
||||
warn_skipped_keys);
|
||||
@ -159,8 +159,8 @@ QPDF::pushInheritedAttributesToPage(bool allow_changes, bool warn_skipped_keys)
|
||||
throw std::logic_error("key_ancestors not empty after"
|
||||
" pushing inherited attributes to pages");
|
||||
}
|
||||
this->m->pushed_inherited_attributes_to_pages = true;
|
||||
this->m->ever_pushed_inherited_attributes_to_pages = true;
|
||||
m->pushed_inherited_attributes_to_pages = true;
|
||||
m->ever_pushed_inherited_attributes_to_pages = true;
|
||||
}
|
||||
|
||||
void
|
||||
@ -182,9 +182,9 @@ QPDF::pushInheritedAttributesToPageInternal(
|
||||
if (!allow_changes) {
|
||||
throw QPDFExc(
|
||||
qpdf_e_internal,
|
||||
this->m->file->getName(),
|
||||
this->m->last_object_description,
|
||||
this->m->file->getLastOffset(),
|
||||
m->file->getName(),
|
||||
m->last_object_description,
|
||||
m->file->getLastOffset(),
|
||||
"optimize detected an "
|
||||
"inheritable attribute when called "
|
||||
"in no-change mode");
|
||||
@ -226,7 +226,7 @@ QPDF::pushInheritedAttributesToPageInternal(
|
||||
setLastObjectDescription("Pages object", cur_pages.getObjGen());
|
||||
warn(
|
||||
qpdf_e_pages,
|
||||
this->m->last_object_description,
|
||||
m->last_object_description,
|
||||
0,
|
||||
("Unknown key " + key +
|
||||
" in /Pages object"
|
||||
@ -314,8 +314,8 @@ QPDF::updateObjectMapsInternal(
|
||||
QTC::TC("qpdf", "QPDF opt loop detected");
|
||||
return;
|
||||
}
|
||||
this->m->obj_user_to_objects[ou].insert(og);
|
||||
this->m->object_to_obj_users[og].insert(ou);
|
||||
m->obj_user_to_objects[ou].insert(og);
|
||||
m->object_to_obj_users[og].insert(ou);
|
||||
}
|
||||
|
||||
if (oh.isArray()) {
|
||||
@ -380,7 +380,7 @@ QPDF::filterCompressedObjects(std::map<int, int> const& object_stream_data)
|
||||
std::map<ObjUser, std::set<QPDFObjGen>> t_obj_user_to_objects;
|
||||
std::map<QPDFObjGen, std::set<ObjUser>> t_object_to_obj_users;
|
||||
|
||||
for (auto const& i1: this->m->obj_user_to_objects) {
|
||||
for (auto const& i1: m->obj_user_to_objects) {
|
||||
ObjUser const& ou = i1.first;
|
||||
// Loop over objects.
|
||||
for (auto const& og: i1.second) {
|
||||
@ -393,7 +393,7 @@ QPDF::filterCompressedObjects(std::map<int, int> const& object_stream_data)
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& i1: this->m->object_to_obj_users) {
|
||||
for (auto const& i1: m->object_to_obj_users) {
|
||||
QPDFObjGen const& og = i1.first;
|
||||
// Loop over obj_users.
|
||||
for (auto const& ou: i1.second) {
|
||||
@ -406,6 +406,6 @@ QPDF::filterCompressedObjects(std::map<int, int> const& object_stream_data)
|
||||
}
|
||||
}
|
||||
|
||||
this->m->obj_user_to_objects = t_obj_user_to_objects;
|
||||
this->m->object_to_obj_users = t_object_to_obj_users;
|
||||
m->obj_user_to_objects = t_obj_user_to_objects;
|
||||
m->object_to_obj_users = t_object_to_obj_users;
|
||||
}
|
||||
|
@ -52,9 +52,9 @@ std::vector<QPDFObjectHandle> const&
|
||||
QPDF::getAllPages()
|
||||
{
|
||||
// Note that pushInheritedAttributesToPage may also be used to
|
||||
// initialize this->m->all_pages.
|
||||
if (this->m->all_pages.empty()) {
|
||||
this->m->ever_called_get_all_pages = true;
|
||||
// initialize m->all_pages.
|
||||
if (m->all_pages.empty()) {
|
||||
m->ever_called_get_all_pages = true;
|
||||
QPDFObjGen::set visited;
|
||||
QPDFObjGen::set seen;
|
||||
QPDFObjectHandle pages = getRoot().getKey("/Pages");
|
||||
@ -86,7 +86,7 @@ QPDF::getAllPages()
|
||||
getAllPagesInternal(pages, visited, seen);
|
||||
}
|
||||
}
|
||||
return this->m->all_pages;
|
||||
return m->all_pages;
|
||||
}
|
||||
|
||||
void
|
||||
@ -96,8 +96,8 @@ QPDF::getAllPagesInternal(
|
||||
if (!visited.add(cur_node)) {
|
||||
throw QPDFExc(
|
||||
qpdf_e_pages,
|
||||
this->m->file->getName(),
|
||||
this->m->last_object_description,
|
||||
m->file->getName(),
|
||||
m->last_object_description,
|
||||
0,
|
||||
"Loop detected in /Pages structure (getAllPages)");
|
||||
}
|
||||
@ -150,9 +150,9 @@ QPDF::updateAllPagesCache()
|
||||
// it that they got from calls to getAllPages(). We can defer
|
||||
// recalculation of pageobj_to_pages_pos until needed.
|
||||
QTC::TC("qpdf", "QPDF updateAllPagesCache");
|
||||
this->m->all_pages.clear();
|
||||
this->m->pageobj_to_pages_pos.clear();
|
||||
this->m->pushed_inherited_attributes_to_pages = false;
|
||||
m->all_pages.clear();
|
||||
m->pageobj_to_pages_pos.clear();
|
||||
m->pushed_inherited_attributes_to_pages = false;
|
||||
getAllPages();
|
||||
}
|
||||
|
||||
@ -162,27 +162,27 @@ QPDF::flattenPagesTree()
|
||||
// If not already done, flatten the /Pages structure and
|
||||
// initialize pageobj_to_pages_pos.
|
||||
|
||||
if (!this->m->pageobj_to_pages_pos.empty()) {
|
||||
if (!m->pageobj_to_pages_pos.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Push inherited objects down to the /Page level. As a side
|
||||
// effect this->m->all_pages will also be generated.
|
||||
// effect m->all_pages will also be generated.
|
||||
pushInheritedAttributesToPage(true, true);
|
||||
|
||||
QPDFObjectHandle pages = getRoot().getKey("/Pages");
|
||||
|
||||
size_t const len = this->m->all_pages.size();
|
||||
size_t const len = m->all_pages.size();
|
||||
for (size_t pos = 0; pos < len; ++pos) {
|
||||
// Populate pageobj_to_pages_pos and fix parent pointer. There
|
||||
// should be no duplicates at this point because
|
||||
// pushInheritedAttributesToPage calls getAllPages which
|
||||
// resolves duplicates.
|
||||
insertPageobjToPage(this->m->all_pages.at(pos), toI(pos), true);
|
||||
this->m->all_pages.at(pos).replaceKey("/Parent", pages);
|
||||
insertPageobjToPage(m->all_pages.at(pos), toI(pos), true);
|
||||
m->all_pages.at(pos).replaceKey("/Parent", pages);
|
||||
}
|
||||
|
||||
pages.replaceKey("/Kids", QPDFObjectHandle::newArray(this->m->all_pages));
|
||||
pages.replaceKey("/Kids", QPDFObjectHandle::newArray(m->all_pages));
|
||||
// /Count has not changed
|
||||
if (pages.getKey("/Count").getUIntValue() != len) {
|
||||
throw std::runtime_error("/Count is wrong after flattening pages tree");
|
||||
@ -195,22 +195,21 @@ QPDF::insertPageobjToPage(
|
||||
{
|
||||
QPDFObjGen og(obj.getObjGen());
|
||||
if (check_duplicate) {
|
||||
if (!this->m->pageobj_to_pages_pos.insert(std::make_pair(og, pos))
|
||||
.second) {
|
||||
if (!m->pageobj_to_pages_pos.insert(std::make_pair(og, pos)).second) {
|
||||
// The library never calls insertPageobjToPage in a way
|
||||
// that causes this to happen.
|
||||
setLastObjectDescription(
|
||||
"page " + std::to_string(pos) + " (numbered from zero)", og);
|
||||
throw QPDFExc(
|
||||
qpdf_e_pages,
|
||||
this->m->file->getName(),
|
||||
this->m->last_object_description,
|
||||
m->file->getName(),
|
||||
m->last_object_description,
|
||||
0,
|
||||
"duplicate page reference found;"
|
||||
" this would cause loss of data");
|
||||
}
|
||||
} else {
|
||||
this->m->pageobj_to_pages_pos[og] = pos;
|
||||
m->pageobj_to_pages_pos[og] = pos;
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,7 +246,7 @@ QPDF::insertPage(QPDFObjectHandle newpage, int pos)
|
||||
2); // insert in middle
|
||||
|
||||
auto og = newpage.getObjGen();
|
||||
if (this->m->pageobj_to_pages_pos.count(og)) {
|
||||
if (m->pageobj_to_pages_pos.count(og)) {
|
||||
QTC::TC("qpdf", "QPDF resolve duplicated page in insert");
|
||||
newpage = makeIndirectObject(QPDFObjectHandle(newpage).shallowCopy());
|
||||
}
|
||||
@ -259,9 +258,9 @@ QPDF::insertPage(QPDFObjectHandle newpage, int pos)
|
||||
kids.insertItem(pos, newpage);
|
||||
int npages = kids.getArrayNItems();
|
||||
pages.replaceKey("/Count", QPDFObjectHandle::newInteger(npages));
|
||||
this->m->all_pages.insert(this->m->all_pages.begin() + pos, newpage);
|
||||
m->all_pages.insert(m->all_pages.begin() + pos, newpage);
|
||||
for (int i = pos + 1; i < npages; ++i) {
|
||||
insertPageobjToPage(this->m->all_pages.at(toS(i)), i, false);
|
||||
insertPageobjToPage(m->all_pages.at(toS(i)), i, false);
|
||||
}
|
||||
insertPageobjToPage(newpage, pos, true);
|
||||
}
|
||||
@ -284,10 +283,10 @@ QPDF::removePage(QPDFObjectHandle page)
|
||||
kids.eraseItem(pos);
|
||||
int npages = kids.getArrayNItems();
|
||||
pages.replaceKey("/Count", QPDFObjectHandle::newInteger(npages));
|
||||
this->m->all_pages.erase(this->m->all_pages.begin() + pos);
|
||||
this->m->pageobj_to_pages_pos.erase(page.getObjGen());
|
||||
m->all_pages.erase(m->all_pages.begin() + pos);
|
||||
m->pageobj_to_pages_pos.erase(page.getObjGen());
|
||||
for (int i = pos; i < npages; ++i) {
|
||||
insertPageobjToPage(this->m->all_pages.at(toS(i)), i, false);
|
||||
insertPageobjToPage(m->all_pages.at(toS(i)), i, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -323,14 +322,14 @@ int
|
||||
QPDF::findPage(QPDFObjGen const& og)
|
||||
{
|
||||
flattenPagesTree();
|
||||
auto it = this->m->pageobj_to_pages_pos.find(og);
|
||||
if (it == this->m->pageobj_to_pages_pos.end()) {
|
||||
auto it = m->pageobj_to_pages_pos.find(og);
|
||||
if (it == m->pageobj_to_pages_pos.end()) {
|
||||
QTC::TC("qpdf", "QPDF_pages findPage not found");
|
||||
setLastObjectDescription("page object", og);
|
||||
throw QPDFExc(
|
||||
qpdf_e_pages,
|
||||
this->m->file->getName(),
|
||||
this->m->last_object_description,
|
||||
m->file->getName(),
|
||||
m->last_object_description,
|
||||
0,
|
||||
"page object not referenced in /Pages tree");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user