1 #include <qpdf/QPDFNameTreeObjectHelper.hh>
2 #include <qpdf/NNTree.hh>
3 
4 class NameTreeDetails: public NNTreeDetails
5 {
6   public:
itemsKey() const7     virtual std::string const& itemsKey() const override
8     {
9         static std::string k("/Names");
10         return k;
11     }
keyValid(QPDFObjectHandle oh) const12     virtual bool keyValid(QPDFObjectHandle oh) const override
13     {
14         return oh.isString();
15     }
compareKeys(QPDFObjectHandle a,QPDFObjectHandle b) const16     virtual int compareKeys(
17         QPDFObjectHandle a, QPDFObjectHandle b) const override
18     {
19         if (! (keyValid(a) && keyValid(b)))
20         {
21             // We don't call this without calling keyValid first
22             throw std::logic_error("comparing invalid keys");
23         }
24         auto as = a.getUTF8Value();
25         auto bs = b.getUTF8Value();
26         return ((as < bs) ? -1 : (as > bs) ? 1 : 0);
27     }
28 };
29 
30 static NameTreeDetails name_tree_details;
31 
~Members()32 QPDFNameTreeObjectHelper::Members::~Members()
33 {
34 }
35 
Members(QPDFObjectHandle & oh,QPDF * q,bool auto_repair)36 QPDFNameTreeObjectHelper::Members::Members(
37     QPDFObjectHandle& oh, QPDF* q, bool auto_repair) :
38     impl(std::make_shared<NNTreeImpl>(name_tree_details, q, oh, auto_repair))
39 {
40 }
41 
QPDFNameTreeObjectHelper(QPDFObjectHandle oh,QPDF & q,bool auto_repair)42 QPDFNameTreeObjectHelper::QPDFNameTreeObjectHelper(
43     QPDFObjectHandle oh, QPDF& q, bool auto_repair) :
44     QPDFObjectHelper(oh),
45     m(new Members(oh, &q, auto_repair))
46 {
47 }
48 
QPDFNameTreeObjectHelper(QPDFObjectHandle oh)49 QPDFNameTreeObjectHelper::QPDFNameTreeObjectHelper(QPDFObjectHandle oh) :
50     QPDFObjectHelper(oh),
51     m(new Members(oh, nullptr, false))
52 {
53 }
54 
~QPDFNameTreeObjectHelper()55 QPDFNameTreeObjectHelper::~QPDFNameTreeObjectHelper()
56 {
57 }
58 
59 QPDFNameTreeObjectHelper
newEmpty(QPDF & qpdf,bool auto_repair)60 QPDFNameTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair)
61 {
62     return QPDFNameTreeObjectHelper(
63         qpdf.makeIndirectObject(
64             QPDFObjectHandle::parse("<< /Names [] >>")), qpdf, auto_repair);
65 }
66 
iterator(std::shared_ptr<NNTreeIterator> const & i)67 QPDFNameTreeObjectHelper::iterator::iterator(
68     std::shared_ptr<NNTreeIterator> const& i) :
69     impl(i)
70 {
71 }
72 
73 bool
valid() const74 QPDFNameTreeObjectHelper::iterator::valid() const
75 {
76     return impl->valid();
77 }
78 
79 QPDFNameTreeObjectHelper::iterator&
operator ++()80 QPDFNameTreeObjectHelper::iterator::operator++()
81 {
82     ++(*impl);
83     updateIValue();
84     return *this;
85 }
86 
87 QPDFNameTreeObjectHelper::iterator&
operator --()88 QPDFNameTreeObjectHelper::iterator::operator--()
89 {
90     --(*impl);
91     updateIValue();
92     return *this;
93 }
94 
95 void
updateIValue()96 QPDFNameTreeObjectHelper::iterator::updateIValue()
97 {
98     if (impl->valid())
99     {
100         auto p = *impl;
101         this->ivalue.first = p->first.getUTF8Value();
102         this->ivalue.second = p->second;
103     }
104     else
105     {
106         this->ivalue.first = "";
107         this->ivalue.second = QPDFObjectHandle();
108     }
109 }
110 
111 QPDFNameTreeObjectHelper::iterator::reference
operator *()112 QPDFNameTreeObjectHelper::iterator::operator*()
113 {
114     updateIValue();
115     return this->ivalue;
116 }
117 
118 QPDFNameTreeObjectHelper::iterator::pointer
operator ->()119 QPDFNameTreeObjectHelper::iterator::operator->()
120 {
121     updateIValue();
122     return &this->ivalue;
123 }
124 
125 bool
operator ==(iterator const & other) const126 QPDFNameTreeObjectHelper::iterator::operator==(iterator const& other) const
127 {
128     return *(impl) == *(other.impl);
129 }
130 
131 void
insertAfter(std::string const & key,QPDFObjectHandle value)132 QPDFNameTreeObjectHelper::iterator::insertAfter(
133     std::string const& key, QPDFObjectHandle value)
134 {
135     impl->insertAfter(QPDFObjectHandle::newUnicodeString(key), value);
136     updateIValue();
137 }
138 
139 void
remove()140 QPDFNameTreeObjectHelper::iterator::remove()
141 {
142     impl->remove();
143     updateIValue();
144 }
145 
146 QPDFNameTreeObjectHelper::iterator
begin() const147 QPDFNameTreeObjectHelper::begin() const
148 {
149     return iterator(std::make_shared<NNTreeIterator>(this->m->impl->begin()));
150 }
151 
152 QPDFNameTreeObjectHelper::iterator
end() const153 QPDFNameTreeObjectHelper::end() const
154 {
155     return iterator(std::make_shared<NNTreeIterator>(this->m->impl->end()));
156 }
157 
158 QPDFNameTreeObjectHelper::iterator
last() const159 QPDFNameTreeObjectHelper::last() const
160 {
161     return iterator(std::make_shared<NNTreeIterator>(this->m->impl->last()));
162 }
163 
164 QPDFNameTreeObjectHelper::iterator
find(std::string const & key,bool return_prev_if_not_found)165 QPDFNameTreeObjectHelper::find(std::string const& key,
166                                bool return_prev_if_not_found)
167 {
168     auto i = this->m->impl->find(QPDFObjectHandle::newUnicodeString(key),
169                                  return_prev_if_not_found);
170     return iterator(std::make_shared<NNTreeIterator>(i));
171 }
172 
173 QPDFNameTreeObjectHelper::iterator
insert(std::string const & key,QPDFObjectHandle value)174 QPDFNameTreeObjectHelper::insert(std::string const& key,
175                                  QPDFObjectHandle value)
176 {
177     auto i = this->m->impl->insert(
178         QPDFObjectHandle::newUnicodeString(key), value);
179     return iterator(std::make_shared<NNTreeIterator>(i));
180 }
181 
182 bool
remove(std::string const & key,QPDFObjectHandle * value)183 QPDFNameTreeObjectHelper::remove(std::string const& key,
184                                  QPDFObjectHandle* value)
185 {
186     return this->m->impl->remove(
187         QPDFObjectHandle::newUnicodeString(key), value);
188 }
189 
190 bool
hasName(std::string const & name)191 QPDFNameTreeObjectHelper::hasName(std::string const& name)
192 {
193     auto i = find(name);
194     return (i != end());
195 }
196 
197 bool
findObject(std::string const & name,QPDFObjectHandle & oh)198 QPDFNameTreeObjectHelper::findObject(
199     std::string const& name, QPDFObjectHandle& oh)
200 {
201     auto i = find(name);
202     if (i == end())
203     {
204         return false;
205     }
206     oh = i->second;
207     return true;
208 }
209 
210 void
setSplitThreshold(int t)211 QPDFNameTreeObjectHelper::setSplitThreshold(int t)
212 {
213     this->m->impl->setSplitThreshold(t);
214 }
215 
216 std::map<std::string, QPDFObjectHandle>
getAsMap() const217 QPDFNameTreeObjectHelper::getAsMap() const
218 {
219     std::map<std::string, QPDFObjectHandle> result;
220     result.insert(begin(), end());
221     return result;
222 }
223