Commit e01ae1968b79841797b2ae59eda00b867604e3f9
1 parent
df493c35
Split page handling APIs into a separate source file
Showing
3 changed files
with
196 additions
and
189 deletions
libqpdf/QPDF.cc
| ... | ... | @@ -4,7 +4,6 @@ |
| 4 | 4 | #include <map> |
| 5 | 5 | #include <string.h> |
| 6 | 6 | #include <memory.h> |
| 7 | -#include <assert.h> | |
| 8 | 7 | |
| 9 | 8 | #include <qpdf/QTC.hh> |
| 10 | 9 | #include <qpdf/QUtil.hh> |
| ... | ... | @@ -2165,191 +2164,3 @@ QPDF::decodeStreams() |
| 2165 | 2164 | } |
| 2166 | 2165 | } |
| 2167 | 2166 | } |
| 2168 | - | |
| 2169 | -std::vector<QPDFObjectHandle> const& | |
| 2170 | -QPDF::getAllPages() | |
| 2171 | -{ | |
| 2172 | - if (this->all_pages.empty()) | |
| 2173 | - { | |
| 2174 | - getAllPagesInternal( | |
| 2175 | - this->trailer.getKey("/Root").getKey("/Pages"), this->all_pages); | |
| 2176 | - } | |
| 2177 | - return this->all_pages; | |
| 2178 | -} | |
| 2179 | - | |
| 2180 | -void | |
| 2181 | -QPDF::getAllPagesInternal(QPDFObjectHandle cur_pages, | |
| 2182 | - std::vector<QPDFObjectHandle>& result) | |
| 2183 | -{ | |
| 2184 | - std::string type = cur_pages.getKey("/Type").getName(); | |
| 2185 | - if (type == "/Pages") | |
| 2186 | - { | |
| 2187 | - QPDFObjectHandle kids = cur_pages.getKey("/Kids"); | |
| 2188 | - int n = kids.getArrayNItems(); | |
| 2189 | - for (int i = 0; i < n; ++i) | |
| 2190 | - { | |
| 2191 | - getAllPagesInternal(kids.getArrayItem(i), result); | |
| 2192 | - } | |
| 2193 | - } | |
| 2194 | - else if (type == "/Page") | |
| 2195 | - { | |
| 2196 | - result.push_back(cur_pages); | |
| 2197 | - } | |
| 2198 | - else | |
| 2199 | - { | |
| 2200 | - throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), | |
| 2201 | - this->last_object_description, | |
| 2202 | - this->file->getLastOffset(), | |
| 2203 | - ": invalid Type in page tree"); | |
| 2204 | - } | |
| 2205 | -} | |
| 2206 | - | |
| 2207 | -// FIXXX here down | |
| 2208 | - | |
| 2209 | -void | |
| 2210 | -QPDF::clearPagesCache() | |
| 2211 | -{ | |
| 2212 | - this->all_pages.clear(); | |
| 2213 | - this->pageobj_to_pages_pos.clear(); | |
| 2214 | -} | |
| 2215 | - | |
| 2216 | -void | |
| 2217 | -QPDF::flattenPagesTree() | |
| 2218 | -{ | |
| 2219 | - clearPagesCache(); | |
| 2220 | - | |
| 2221 | - // FIXME: more specific method, we don't want to generate the extra stuff. | |
| 2222 | - // We also need cheap fixup after addPage/removePage. | |
| 2223 | - | |
| 2224 | - // no compressed objects to be produced here... | |
| 2225 | - std::map<int, int> object_stream_data; | |
| 2226 | - optimize(object_stream_data); // push down inheritance | |
| 2227 | - | |
| 2228 | - std::vector<QPDFObjectHandle> kids = this->getAllPages(); | |
| 2229 | - QPDFObjectHandle pages = this->trailer.getKey("/Root").getKey("/Pages"); | |
| 2230 | - | |
| 2231 | - const int len = kids.size(); | |
| 2232 | - for (int pos = 0; pos < len; ++pos) | |
| 2233 | - { | |
| 2234 | - // populate pageobj_to_pages_pos | |
| 2235 | - ObjGen og(kids[pos].getObjectID(), kids[pos].getGeneration()); | |
| 2236 | - if (! this->pageobj_to_pages_pos.insert(std::make_pair(og, pos)).second) | |
| 2237 | - { | |
| 2238 | - // insert failed: duplicate entry found | |
| 2239 | - *out_stream << "WARNING: duplicate page reference found, " | |
| 2240 | - << "but currently not fully supported." << std::endl; | |
| 2241 | - } | |
| 2242 | - | |
| 2243 | - // fix parent links | |
| 2244 | - kids[pos].replaceKey("/Parent", pages); | |
| 2245 | - } | |
| 2246 | - | |
| 2247 | - pages.replaceKey("/Kids", QPDFObjectHandle::newArray(kids)); | |
| 2248 | - // /Count has not changed | |
| 2249 | - assert(pages.getKey("/Count").getIntValue() == len); | |
| 2250 | -} | |
| 2251 | - | |
| 2252 | -int | |
| 2253 | -QPDF::findPage(int objid, int generation) | |
| 2254 | -{ | |
| 2255 | - if (this->pageobj_to_pages_pos.empty()) | |
| 2256 | - { | |
| 2257 | - flattenPagesTree(); | |
| 2258 | - } | |
| 2259 | - std::map<ObjGen, int>::iterator it = | |
| 2260 | - this->pageobj_to_pages_pos.find(ObjGen(objid, generation)); | |
| 2261 | - if (it != this->pageobj_to_pages_pos.end()) | |
| 2262 | - { | |
| 2263 | - return (*it).second; | |
| 2264 | - } | |
| 2265 | - return -1; // throw? | |
| 2266 | -} | |
| 2267 | - | |
| 2268 | -int | |
| 2269 | -QPDF::findPage(QPDFObjectHandle const& pageoh) | |
| 2270 | -{ | |
| 2271 | - if (!pageoh.isInitialized()) | |
| 2272 | - { | |
| 2273 | - return -1; | |
| 2274 | - // TODO? throw | |
| 2275 | - } | |
| 2276 | - return findPage(pageoh.getObjectID(), pageoh.getGeneration()); | |
| 2277 | -} | |
| 2278 | - | |
| 2279 | -void | |
| 2280 | -QPDF::addPage(QPDFObjectHandle newpage, bool first) | |
| 2281 | -{ | |
| 2282 | - if (this->pageobj_to_pages_pos.empty()) | |
| 2283 | - { | |
| 2284 | - flattenPagesTree(); | |
| 2285 | - } | |
| 2286 | - | |
| 2287 | - newpage.assertPageObject(); // FIXME: currently private | |
| 2288 | - | |
| 2289 | - QPDFObjectHandle pages = this->trailer.getKey("/Root").getKey("/Pages"); | |
| 2290 | - QPDFObjectHandle kids = pages.getKey("/Kids"); | |
| 2291 | - | |
| 2292 | - newpage.replaceKey("/Parent", pages); | |
| 2293 | - if (first) | |
| 2294 | - { | |
| 2295 | - kids.insertItem(0, newpage); | |
| 2296 | - } | |
| 2297 | - else | |
| 2298 | - { | |
| 2299 | - kids.appendItem(newpage); | |
| 2300 | - } | |
| 2301 | - pages.replaceKey("/Count", | |
| 2302 | - QPDFObjectHandle::newInteger(kids.getArrayNItems())); | |
| 2303 | - | |
| 2304 | - // FIXME: this is overkill, but cache is now stale | |
| 2305 | - clearPagesCache(); | |
| 2306 | -} | |
| 2307 | - | |
| 2308 | -void | |
| 2309 | -QPDF::addPageAt(QPDFObjectHandle newpage, bool before, | |
| 2310 | - QPDFObjectHandle const &refpage) | |
| 2311 | -{ | |
| 2312 | - int refpos = findPage(refpage); // also ensures flat /Pages | |
| 2313 | - if (refpos == -1) | |
| 2314 | - { | |
| 2315 | - throw "Could not find refpage"; | |
| 2316 | - } | |
| 2317 | - | |
| 2318 | - newpage.assertPageObject(); | |
| 2319 | - | |
| 2320 | - QPDFObjectHandle pages = this->trailer.getKey("/Root").getKey("/Pages"); | |
| 2321 | - QPDFObjectHandle kids = pages.getKey("/Kids"); | |
| 2322 | - | |
| 2323 | - if (! before) | |
| 2324 | - { | |
| 2325 | - ++refpos; | |
| 2326 | - } | |
| 2327 | - | |
| 2328 | - newpage.replaceKey("/Parent", pages); | |
| 2329 | - kids.insertItem(refpos, newpage); | |
| 2330 | - pages.replaceKey("/Count", | |
| 2331 | - QPDFObjectHandle::newInteger(kids.getArrayNItems())); | |
| 2332 | - | |
| 2333 | - // FIXME: this is overkill, but cache is now stale | |
| 2334 | - clearPagesCache(); | |
| 2335 | -} | |
| 2336 | - | |
| 2337 | -void | |
| 2338 | -QPDF::removePage(QPDFObjectHandle const& pageoh) | |
| 2339 | -{ | |
| 2340 | - int pos = findPage(pageoh); // also ensures flat /Pages | |
| 2341 | - if (pos == -1) | |
| 2342 | - { | |
| 2343 | - throw "Can't remove non-existing page"; | |
| 2344 | - } | |
| 2345 | - | |
| 2346 | - QPDFObjectHandle pages = this->trailer.getKey("/Root").getKey("/Pages"); | |
| 2347 | - QPDFObjectHandle kids = pages.getKey("/Kids"); | |
| 2348 | - | |
| 2349 | - kids.eraseItem(pos); | |
| 2350 | - pages.replaceKey("/Count", | |
| 2351 | - QPDFObjectHandle::newInteger(kids.getArrayNItems())); | |
| 2352 | - | |
| 2353 | - // FIXME: this is overkill, but cache is now stale | |
| 2354 | - clearPagesCache(); | |
| 2355 | -} | ... | ... |
libqpdf/QPDF_pages.cc
0 โ 100644
| 1 | +#include <qpdf/QPDF.hh> | |
| 2 | + | |
| 3 | +#include <assert.h> | |
| 4 | + | |
| 5 | +#include <qpdf/QTC.hh> | |
| 6 | +#include <qpdf/QUtil.hh> | |
| 7 | +#include <qpdf/QPDFExc.hh> | |
| 8 | + | |
| 9 | +std::vector<QPDFObjectHandle> const& | |
| 10 | +QPDF::getAllPages() | |
| 11 | +{ | |
| 12 | + if (this->all_pages.empty()) | |
| 13 | + { | |
| 14 | + getAllPagesInternal( | |
| 15 | + this->trailer.getKey("/Root").getKey("/Pages"), this->all_pages); | |
| 16 | + } | |
| 17 | + return this->all_pages; | |
| 18 | +} | |
| 19 | + | |
| 20 | +void | |
| 21 | +QPDF::getAllPagesInternal(QPDFObjectHandle cur_pages, | |
| 22 | + std::vector<QPDFObjectHandle>& result) | |
| 23 | +{ | |
| 24 | + std::string type = cur_pages.getKey("/Type").getName(); | |
| 25 | + if (type == "/Pages") | |
| 26 | + { | |
| 27 | + QPDFObjectHandle kids = cur_pages.getKey("/Kids"); | |
| 28 | + int n = kids.getArrayNItems(); | |
| 29 | + for (int i = 0; i < n; ++i) | |
| 30 | + { | |
| 31 | + getAllPagesInternal(kids.getArrayItem(i), result); | |
| 32 | + } | |
| 33 | + } | |
| 34 | + else if (type == "/Page") | |
| 35 | + { | |
| 36 | + result.push_back(cur_pages); | |
| 37 | + } | |
| 38 | + else | |
| 39 | + { | |
| 40 | + throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(), | |
| 41 | + this->last_object_description, | |
| 42 | + this->file->getLastOffset(), | |
| 43 | + ": invalid Type in page tree"); | |
| 44 | + } | |
| 45 | +} | |
| 46 | + | |
| 47 | +// FIXXX here down | |
| 48 | + | |
| 49 | +void | |
| 50 | +QPDF::clearPagesCache() | |
| 51 | +{ | |
| 52 | + this->all_pages.clear(); | |
| 53 | + this->pageobj_to_pages_pos.clear(); | |
| 54 | +} | |
| 55 | + | |
| 56 | +void | |
| 57 | +QPDF::flattenPagesTree() | |
| 58 | +{ | |
| 59 | + clearPagesCache(); | |
| 60 | + | |
| 61 | + // FIXME: more specific method, we don't want to generate the extra stuff. | |
| 62 | + // We also need cheap fixup after addPage/removePage. | |
| 63 | + | |
| 64 | + // no compressed objects to be produced here... | |
| 65 | + std::map<int, int> object_stream_data; | |
| 66 | + optimize(object_stream_data); // push down inheritance | |
| 67 | + | |
| 68 | + std::vector<QPDFObjectHandle> kids = this->getAllPages(); | |
| 69 | + QPDFObjectHandle pages = this->trailer.getKey("/Root").getKey("/Pages"); | |
| 70 | + | |
| 71 | + const int len = kids.size(); | |
| 72 | + for (int pos = 0; pos < len; ++pos) | |
| 73 | + { | |
| 74 | + // populate pageobj_to_pages_pos | |
| 75 | + ObjGen og(kids[pos].getObjectID(), kids[pos].getGeneration()); | |
| 76 | + if (! this->pageobj_to_pages_pos.insert(std::make_pair(og, pos)).second) | |
| 77 | + { | |
| 78 | + // insert failed: duplicate entry found | |
| 79 | + *out_stream << "WARNING: duplicate page reference found, " | |
| 80 | + << "but currently not fully supported." << std::endl; | |
| 81 | + } | |
| 82 | + | |
| 83 | + // fix parent links | |
| 84 | + kids[pos].replaceKey("/Parent", pages); | |
| 85 | + } | |
| 86 | + | |
| 87 | + pages.replaceKey("/Kids", QPDFObjectHandle::newArray(kids)); | |
| 88 | + // /Count has not changed | |
| 89 | + assert(pages.getKey("/Count").getIntValue() == len); | |
| 90 | +} | |
| 91 | + | |
| 92 | +int | |
| 93 | +QPDF::findPage(int objid, int generation) | |
| 94 | +{ | |
| 95 | + if (this->pageobj_to_pages_pos.empty()) | |
| 96 | + { | |
| 97 | + flattenPagesTree(); | |
| 98 | + } | |
| 99 | + std::map<ObjGen, int>::iterator it = | |
| 100 | + this->pageobj_to_pages_pos.find(ObjGen(objid, generation)); | |
| 101 | + if (it != this->pageobj_to_pages_pos.end()) | |
| 102 | + { | |
| 103 | + return (*it).second; | |
| 104 | + } | |
| 105 | + return -1; // throw? | |
| 106 | +} | |
| 107 | + | |
| 108 | +int | |
| 109 | +QPDF::findPage(QPDFObjectHandle const& pageoh) | |
| 110 | +{ | |
| 111 | + if (!pageoh.isInitialized()) | |
| 112 | + { | |
| 113 | + return -1; | |
| 114 | + // TODO? throw | |
| 115 | + } | |
| 116 | + return findPage(pageoh.getObjectID(), pageoh.getGeneration()); | |
| 117 | +} | |
| 118 | + | |
| 119 | +void | |
| 120 | +QPDF::addPage(QPDFObjectHandle newpage, bool first) | |
| 121 | +{ | |
| 122 | + if (this->pageobj_to_pages_pos.empty()) | |
| 123 | + { | |
| 124 | + flattenPagesTree(); | |
| 125 | + } | |
| 126 | + | |
| 127 | + newpage.assertPageObject(); // FIXME: currently private | |
| 128 | + | |
| 129 | + QPDFObjectHandle pages = this->trailer.getKey("/Root").getKey("/Pages"); | |
| 130 | + QPDFObjectHandle kids = pages.getKey("/Kids"); | |
| 131 | + | |
| 132 | + newpage.replaceKey("/Parent", pages); | |
| 133 | + if (first) | |
| 134 | + { | |
| 135 | + kids.insertItem(0, newpage); | |
| 136 | + } | |
| 137 | + else | |
| 138 | + { | |
| 139 | + kids.appendItem(newpage); | |
| 140 | + } | |
| 141 | + pages.replaceKey("/Count", | |
| 142 | + QPDFObjectHandle::newInteger(kids.getArrayNItems())); | |
| 143 | + | |
| 144 | + // FIXME: this is overkill, but cache is now stale | |
| 145 | + clearPagesCache(); | |
| 146 | +} | |
| 147 | + | |
| 148 | +void | |
| 149 | +QPDF::addPageAt(QPDFObjectHandle newpage, bool before, | |
| 150 | + QPDFObjectHandle const &refpage) | |
| 151 | +{ | |
| 152 | + int refpos = findPage(refpage); // also ensures flat /Pages | |
| 153 | + if (refpos == -1) | |
| 154 | + { | |
| 155 | + throw "Could not find refpage"; | |
| 156 | + } | |
| 157 | + | |
| 158 | + newpage.assertPageObject(); | |
| 159 | + | |
| 160 | + QPDFObjectHandle pages = this->trailer.getKey("/Root").getKey("/Pages"); | |
| 161 | + QPDFObjectHandle kids = pages.getKey("/Kids"); | |
| 162 | + | |
| 163 | + if (! before) | |
| 164 | + { | |
| 165 | + ++refpos; | |
| 166 | + } | |
| 167 | + | |
| 168 | + newpage.replaceKey("/Parent", pages); | |
| 169 | + kids.insertItem(refpos, newpage); | |
| 170 | + pages.replaceKey("/Count", | |
| 171 | + QPDFObjectHandle::newInteger(kids.getArrayNItems())); | |
| 172 | + | |
| 173 | + // FIXME: this is overkill, but cache is now stale | |
| 174 | + clearPagesCache(); | |
| 175 | +} | |
| 176 | + | |
| 177 | +void | |
| 178 | +QPDF::removePage(QPDFObjectHandle const& pageoh) | |
| 179 | +{ | |
| 180 | + int pos = findPage(pageoh); // also ensures flat /Pages | |
| 181 | + if (pos == -1) | |
| 182 | + { | |
| 183 | + throw "Can't remove non-existing page"; | |
| 184 | + } | |
| 185 | + | |
| 186 | + QPDFObjectHandle pages = this->trailer.getKey("/Root").getKey("/Pages"); | |
| 187 | + QPDFObjectHandle kids = pages.getKey("/Kids"); | |
| 188 | + | |
| 189 | + kids.eraseItem(pos); | |
| 190 | + pages.replaceKey("/Count", | |
| 191 | + QPDFObjectHandle::newInteger(kids.getArrayNItems())); | |
| 192 | + | |
| 193 | + // FIXME: this is overkill, but cache is now stale | |
| 194 | + clearPagesCache(); | |
| 195 | +} | ... | ... |