Commit 63d1dcb414ad92cae857da636f242b34acac394b
Committed by
Jay Berkenbilt
1 parent
dbc5f07b
Split QPDFObjectHandle::shallowCopyInternal and copyObject
Have separate versions for unsafeShallowCopy, shallowCopy and makeDirect.
Showing
2 changed files
with
180 additions
and
6 deletions
include/qpdf/QPDFObjectHandle.hh
| ... | ... | @@ -1628,12 +1628,23 @@ class QPDFObjectHandle |
| 1628 | 1628 | void objectWarning(std::string const& warning); |
| 1629 | 1629 | void assertType(char const* type_name, bool istype); |
| 1630 | 1630 | bool dereference(); |
| 1631 | + void copyObject1( | |
| 1632 | + std::set<QPDFObjGen>& visited, | |
| 1633 | + bool cross_indirect, | |
| 1634 | + bool first_level_only, | |
| 1635 | + bool stop_at_streams); | |
| 1636 | + void shallowCopyInternal1(QPDFObjectHandle& oh, bool first_level_only); | |
| 1637 | + void copyObject2( | |
| 1638 | + std::set<QPDFObjGen>& visited, | |
| 1639 | + bool cross_indirect, | |
| 1640 | + bool first_level_only, | |
| 1641 | + bool stop_at_streams); | |
| 1642 | + void shallowCopyInternal2(QPDFObjectHandle& oh, bool first_level_only); | |
| 1631 | 1643 | void copyObject( |
| 1632 | 1644 | std::set<QPDFObjGen>& visited, |
| 1633 | 1645 | bool cross_indirect, |
| 1634 | 1646 | bool first_level_only, |
| 1635 | 1647 | bool stop_at_streams); |
| 1636 | - void shallowCopyInternal(QPDFObjectHandle& oh, bool first_level_only); | |
| 1637 | 1648 | void disconnect(); |
| 1638 | 1649 | void setParsedOffset(qpdf_offset_t offset); |
| 1639 | 1650 | void parseContentStream_internal( | ... | ... |
libqpdf/QPDFObjectHandle.cc
| ... | ... | @@ -2201,32 +2201,195 @@ QPDFObjectHandle |
| 2201 | 2201 | QPDFObjectHandle::shallowCopy() |
| 2202 | 2202 | { |
| 2203 | 2203 | QPDFObjectHandle result; |
| 2204 | - shallowCopyInternal(result, false); | |
| 2204 | + shallowCopyInternal1(result, false); | |
| 2205 | 2205 | return result; |
| 2206 | 2206 | } |
| 2207 | 2207 | |
| 2208 | +void | |
| 2209 | +QPDFObjectHandle::shallowCopyInternal1( | |
| 2210 | + QPDFObjectHandle& new_obj, bool first_level_only) | |
| 2211 | +{ | |
| 2212 | + assertInitialized(); | |
| 2213 | + | |
| 2214 | + if (isStream()) { | |
| 2215 | + QTC::TC("qpdf", "QPDFObjectHandle ERR shallow copy stream"); | |
| 2216 | + throw std::runtime_error("attempt to make a shallow copy of a stream"); | |
| 2217 | + } | |
| 2218 | + new_obj = QPDFObjectHandle(obj->copy(true)); | |
| 2219 | + | |
| 2220 | + std::set<QPDFObjGen> visited; | |
| 2221 | + new_obj.copyObject1(visited, false, first_level_only, false); | |
| 2222 | +} | |
| 2223 | + | |
| 2224 | +void | |
| 2225 | +QPDFObjectHandle::copyObject1( | |
| 2226 | + std::set<QPDFObjGen>& visited, | |
| 2227 | + bool cross_indirect, | |
| 2228 | + bool first_level_only, | |
| 2229 | + bool stop_at_streams) | |
| 2230 | +{ | |
| 2231 | + assertInitialized(); | |
| 2232 | + | |
| 2233 | + if (isStream()) { | |
| 2234 | + if (stop_at_streams) { | |
| 2235 | + return; | |
| 2236 | + } | |
| 2237 | + throw std::runtime_error( | |
| 2238 | + "attempt to make a stream into a direct object"); | |
| 2239 | + } | |
| 2240 | + | |
| 2241 | + auto cur_og = getObjGen(); | |
| 2242 | + if (cur_og.getObj() != 0) { | |
| 2243 | + if (visited.count(cur_og)) { | |
| 2244 | + throw std::runtime_error( | |
| 2245 | + "loop detected while converting object from " | |
| 2246 | + "indirect to direct"); | |
| 2247 | + } | |
| 2248 | + visited.insert(cur_og); | |
| 2249 | + } | |
| 2250 | + | |
| 2251 | + if (isReserved()) { | |
| 2252 | + throw std::logic_error("QPDFObjectHandle: attempting to make a" | |
| 2253 | + " reserved object handle direct"); | |
| 2254 | + } | |
| 2255 | + | |
| 2256 | + std::shared_ptr<QPDFObject> new_obj; | |
| 2257 | + | |
| 2258 | + if (isBool() || isInteger() || isName() || isNull() || isReal() || | |
| 2259 | + isString()) { | |
| 2260 | + new_obj = obj->copy(true); | |
| 2261 | + } else if (isArray()) { | |
| 2262 | + std::vector<QPDFObjectHandle> items; | |
| 2263 | + auto array = asArray(); | |
| 2264 | + int n = array->getNItems(); | |
| 2265 | + for (int i = 0; i < n; ++i) { | |
| 2266 | + items.push_back(array->getItem(i)); | |
| 2267 | + if ((!first_level_only) && | |
| 2268 | + (cross_indirect || (!items.back().isIndirect()))) { | |
| 2269 | + items.back().copyObject1( | |
| 2270 | + visited, cross_indirect, first_level_only, stop_at_streams); | |
| 2271 | + } | |
| 2272 | + } | |
| 2273 | + new_obj = QPDF_Array::create(items); | |
| 2274 | + } else if (isDictionary()) { | |
| 2275 | + std::map<std::string, QPDFObjectHandle> items; | |
| 2276 | + auto dict = asDictionary(); | |
| 2277 | + for (auto const& key: getKeys()) { | |
| 2278 | + items[key] = dict->getKey(key); | |
| 2279 | + if ((!first_level_only) && | |
| 2280 | + (cross_indirect || (!items[key].isIndirect()))) { | |
| 2281 | + items[key].copyObject1( | |
| 2282 | + visited, cross_indirect, first_level_only, stop_at_streams); | |
| 2283 | + } | |
| 2284 | + } | |
| 2285 | + new_obj = QPDF_Dictionary::create(items); | |
| 2286 | + } else { | |
| 2287 | + throw std::logic_error("QPDFObjectHandle::makeDirectInternal: " | |
| 2288 | + "unknown object type"); | |
| 2289 | + } | |
| 2290 | + | |
| 2291 | + this->obj = new_obj; | |
| 2292 | + | |
| 2293 | + if (cur_og.getObj()) { | |
| 2294 | + visited.erase(cur_og); | |
| 2295 | + } | |
| 2296 | +} | |
| 2297 | + | |
| 2208 | 2298 | QPDFObjectHandle |
| 2209 | 2299 | QPDFObjectHandle::unsafeShallowCopy() |
| 2210 | 2300 | { |
| 2211 | 2301 | QPDFObjectHandle result; |
| 2212 | - shallowCopyInternal(result, true); | |
| 2302 | + shallowCopyInternal2(result, true); | |
| 2213 | 2303 | return result; |
| 2214 | 2304 | } |
| 2215 | 2305 | |
| 2216 | 2306 | void |
| 2217 | -QPDFObjectHandle::shallowCopyInternal( | |
| 2307 | +QPDFObjectHandle::shallowCopyInternal2( | |
| 2218 | 2308 | QPDFObjectHandle& new_obj, bool first_level_only) |
| 2219 | 2309 | { |
| 2220 | 2310 | assertInitialized(); |
| 2221 | 2311 | |
| 2222 | 2312 | if (isStream()) { |
| 2223 | - QTC::TC("qpdf", "QPDFObjectHandle ERR shallow copy stream"); | |
| 2224 | 2313 | throw std::runtime_error("attempt to make a shallow copy of a stream"); |
| 2225 | 2314 | } |
| 2226 | 2315 | new_obj = QPDFObjectHandle(obj->copy(true)); |
| 2227 | 2316 | |
| 2228 | 2317 | std::set<QPDFObjGen> visited; |
| 2229 | - new_obj.copyObject(visited, false, first_level_only, false); | |
| 2318 | + new_obj.copyObject2(visited, false, first_level_only, false); | |
| 2319 | +} | |
| 2320 | + | |
| 2321 | +void | |
| 2322 | +QPDFObjectHandle::copyObject2( | |
| 2323 | + std::set<QPDFObjGen>& visited, | |
| 2324 | + bool cross_indirect, | |
| 2325 | + bool first_level_only, | |
| 2326 | + bool stop_at_streams) | |
| 2327 | +{ | |
| 2328 | + assertInitialized(); | |
| 2329 | + | |
| 2330 | + if (isStream()) { | |
| 2331 | + if (stop_at_streams) { | |
| 2332 | + return; | |
| 2333 | + } | |
| 2334 | + throw std::runtime_error( | |
| 2335 | + "attempt to make a stream into a direct object"); | |
| 2336 | + } | |
| 2337 | + | |
| 2338 | + auto cur_og = getObjGen(); | |
| 2339 | + if (cur_og.getObj() != 0) { | |
| 2340 | + if (visited.count(cur_og)) { | |
| 2341 | + throw std::runtime_error( | |
| 2342 | + "loop detected while converting object from " | |
| 2343 | + "indirect to direct"); | |
| 2344 | + } | |
| 2345 | + visited.insert(cur_og); | |
| 2346 | + } | |
| 2347 | + | |
| 2348 | + if (isReserved()) { | |
| 2349 | + throw std::logic_error("QPDFObjectHandle: attempting to make a" | |
| 2350 | + " reserved object handle direct"); | |
| 2351 | + } | |
| 2352 | + | |
| 2353 | + std::shared_ptr<QPDFObject> new_obj; | |
| 2354 | + | |
| 2355 | + if (isBool() || isInteger() || isName() || isNull() || isReal() || | |
| 2356 | + isString()) { | |
| 2357 | + new_obj = obj->copy(true); | |
| 2358 | + } else if (isArray()) { | |
| 2359 | + std::vector<QPDFObjectHandle> items; | |
| 2360 | + auto array = asArray(); | |
| 2361 | + int n = array->getNItems(); | |
| 2362 | + for (int i = 0; i < n; ++i) { | |
| 2363 | + items.push_back(array->getItem(i)); | |
| 2364 | + if ((!first_level_only) && | |
| 2365 | + (cross_indirect || (!items.back().isIndirect()))) { | |
| 2366 | + items.back().copyObject2( | |
| 2367 | + visited, cross_indirect, first_level_only, stop_at_streams); | |
| 2368 | + } | |
| 2369 | + } | |
| 2370 | + new_obj = QPDF_Array::create(items); | |
| 2371 | + } else if (isDictionary()) { | |
| 2372 | + std::map<std::string, QPDFObjectHandle> items; | |
| 2373 | + auto dict = asDictionary(); | |
| 2374 | + for (auto const& key: getKeys()) { | |
| 2375 | + items[key] = dict->getKey(key); | |
| 2376 | + if ((!first_level_only) && | |
| 2377 | + (cross_indirect || (!items[key].isIndirect()))) { | |
| 2378 | + items[key].copyObject2( | |
| 2379 | + visited, cross_indirect, first_level_only, stop_at_streams); | |
| 2380 | + } | |
| 2381 | + } | |
| 2382 | + new_obj = QPDF_Dictionary::create(items); | |
| 2383 | + } else { | |
| 2384 | + throw std::logic_error("QPDFObjectHandle::makeDirectInternal: " | |
| 2385 | + "unknown object type"); | |
| 2386 | + } | |
| 2387 | + | |
| 2388 | + this->obj = new_obj; | |
| 2389 | + | |
| 2390 | + if (cur_og.getObj()) { | |
| 2391 | + visited.erase(cur_og); | |
| 2392 | + } | |
| 2230 | 2393 | } |
| 2231 | 2394 | |
| 2232 | 2395 | void | ... | ... |