...
 
Commits (4)
......@@ -28,6 +28,7 @@
#include <config.h>
#include <cassert>
#include <memory>
#include "Object.h"
#include "Array.h"
......@@ -46,14 +47,22 @@ Array::Array(XRef *xrefA) {
Array::~Array() {
}
Object Array::copy(XRef *xrefA) const {
Array *Array::copy(XRef *xrefA, bool deep) const {
arrayLocker();
Array *a = new Array(xrefA);
auto a = std::make_unique<Array>(xrefA);
a->elems.reserve(elems.size());
for (const auto& elem : elems) {
a->elems.push_back(elem.copy());
if (deep) {
auto copiedElem = elem.deepCopy(xrefA);
if (copiedElem.isNone()) {
return nullptr;
}
a->elems.push_back(std::move(copiedElem));
} else {
a->elems.push_back(elem.copy());
}
}
return Object(a);
return a.release();
}
void Array::add(Object &&elem) {
......
......@@ -57,7 +57,7 @@ public:
int getLength() const { return elems.size(); }
// Copy array with new xref
Object copy(XRef *xrefA) const;
Array *copy(XRef *xrefA, bool deep = false) const;
// Add an element
// elem becomes a dead object after this call
......
......@@ -32,6 +32,7 @@
#include <config.h>
#include <algorithm>
#include <memory>
#include "XRef.h"
#include "Dict.h"
......@@ -63,28 +64,26 @@ Dict::Dict(XRef *xrefA) {
sorted = false;
}
Dict::Dict(const Dict* dictA) {
xref = dictA->xref;
ref = 1;
entries.reserve(dictA->entries.size());
for (const auto& entry : dictA->entries) {
entries.emplace_back(entry.first, entry.second.copy());
}
sorted = dictA->sorted.load();
}
Dict *Dict::copy(XRef *xrefA) const {
Dict *Dict::copy(XRef *xrefA, bool deep) const {
dictLocker();
Dict *dictA = new Dict(this);
dictA->xref = xrefA;
for (auto &entry : dictA->entries) {
if (entry.second.getType() == objDict) {
entry.second = Object(entry.second.getDict()->copy(xrefA));
auto dictA = std::make_unique<Dict>(xrefA);
dictA->entries.reserve(entries.size());
for (const auto& entry : entries) {
if (deep) {
auto copiedObj = entry.second.deepCopy(xrefA);
if (copiedObj.isNone()) {
return nullptr;
}
dictA->entries.emplace_back(entry.first, std::move(copiedObj));
} else {
dictA->entries.emplace_back(entry.first, entry.second.copy());
}
}
return dictA;
dictA->sorted = sorted.load();
return dictA.release();
}
void Dict::add(const char *key, Object &&val) {
......
......@@ -48,8 +48,7 @@ public:
// Constructor.
Dict(XRef *xrefA);
Dict(const Dict *dictA);
Dict *copy(XRef *xrefA) const;
Dict *copy(XRef *xrefA, bool deep = false) const;
Dict(const Dict &) = delete;
Dict& operator=(const Dict &) = delete;
......
......@@ -323,7 +323,7 @@ GfxResources::GfxResources(XRef *xrefA, Dict *resDictA, GfxResources *nextA) :
if (resDictA) {
// build font dictionary
Dict *resDict = resDictA->copy(xref);
Dict *resDict = resDictA->copy(xref, true);
fonts = nullptr;
const Object &obj1 = resDict->lookupNF("Font");
if (obj1.isRef()) {
......
......@@ -55,7 +55,7 @@ static const char *objTypeNames[numObjTypes] = {
"dead"
};
Object Object::copy() const {
Object Object::doCopy(XRef *xref) const {
CHECK_NOT_DEAD;
Object obj;
......@@ -70,13 +70,34 @@ Object Object::copy() const {
obj.cString = copyString(cString);
break;
case objArray:
array->incRef();
if (xref) {
obj.array = array->copy(xref, true);
if (!obj.array) {
// Deep-copying the array elements failed.
obj.type = objNone;
}
} else {
array->incRef();
}
break;
case objDict:
dict->incRef();
if (xref) {
obj.dict = dict->copy(xref, true);
if (!obj.dict) {
// Deep-copying the dict entries failed.
obj.type = objNone;
}
} else {
dict->incRef();
}
break;
case objStream:
stream->incRef();
if (xref) {
// Deep-copying of streams is not supported.
obj.type = objNone;
} else {
stream->incRef();
}
break;
default:
break;
......
......@@ -205,8 +205,10 @@ public:
// Set object to null.
void setToNull() { free(); type = objNull; }
// Copy this to obj
Object copy() const;
// Shallow-copy this object
Object copy() const { return doCopy(nullptr); }
// Deep-copy this object and its child objects or return none if this is not possible
Object deepCopy(XRef *xref) const { return doCopy(xref); }
// If object is a Ref, fetch and return the referenced object.
// Otherwise, return a copy of the object.
......@@ -311,6 +313,8 @@ private:
// Free object contents.
void free();
Object doCopy(XRef *xref) const;
ObjType type; // object type
union { // value for each type:
bool booln; // boolean
......
......@@ -333,19 +333,19 @@ Object *Page::getResourceDictObject()
Dict *Page::getResourceDictCopy(XRef *xrefA) {
pageLocker();
Dict *dict = attrs->getResourceDict();
return dict ? dict->copy(xrefA) : nullptr;
return dict ? dict->copy(xrefA, true) : nullptr;
}
void Page::replaceXRef(XRef *xrefA) {
Object obj1;
Dict *pageDict = pageObj.getDict()->copy(xrefA);
Dict *pageDict = pageObj.getDict()->copy(xrefA, true);
xref = xrefA;
trans = pageDict->lookupNF("Trans").copy();
annotsObj = pageDict->lookupNF("Annots").copy();
contents = pageDict->lookupNF("Contents").copy();
if (contents.isArray()) {
obj1 = pageDict->lookupNF("Contents").copy();
contents = obj1.getArray()->copy(xrefA);
contents = Object{obj1.getArray()->copy(xrefA)};
}
thumb = pageDict->lookupNF("Thumb").copy();
actions = pageDict->lookupNF("AA").copy();
......
......@@ -224,7 +224,7 @@ Object ObjectStream::getObject(int objIdx, int objNum) {
#define xrefLocker() std::unique_lock<std::recursive_mutex> locker(mutex)
XRef::XRef() : objStrs{5} {
XRef::XRef() : objs{3}, objStrs{5} {
ok = true;
errCode = errNone;
entries = nullptr;
......@@ -1089,6 +1089,10 @@ Object XRef::fetch(int num, int gen, int recursion) {
return e->obj.copy();
}
if (const Object *obj = objs.lookup(Ref{num, gen})) {
return obj->deepCopy(this);
}
switch (e->type) {
case xrefEntryUncompressed:
......@@ -1128,6 +1132,12 @@ Object XRef::fetch(int num, int gen, int recursion) {
}
Object obj = parser.getObj(false, (encrypted && !e->getFlag(XRefEntry::Unencrypted)) ? fileKey : nullptr,
encAlgorithm, keyLength, num, gen, recursion);
auto cachedObj = obj.deepCopy(this);
if (!cachedObj.isNone()) {
objs.put(Ref{num, gen}, new Object{std::move(cachedObj)});
}
return obj;
}
......
......@@ -220,6 +220,7 @@ private:
Goffset *streamEnds; // 'endstream' positions - only used in
// damaged files
int streamEndsLen; // number of valid entries in streamEnds
PopplerCache<Ref, Object> objs; // cached objects
PopplerCache<Goffset, ObjectStream> objStrs; // cached object streams
bool encrypted; // true if file is encrypted
int encRevision;
......