Commit 50b329ee9f13e0c615fa8d1d637597ab3929e433
Committed by
Jay Berkenbilt
1 parent
5cf4090a
Add QPDFWriter::getWrittenXRefTable()
Showing
3 changed files
with
114 additions
and
0 deletions
include/qpdf/QPDFWriter.hh
| ... | ... | @@ -470,6 +470,11 @@ class QPDFWriter |
| 470 | 470 | QPDF_DLL |
| 471 | 471 | QPDFObjGen getRenumberedObjGen(QPDFObjGen); |
| 472 | 472 | |
| 473 | + // Return XRef entry that was written into the final file. | |
| 474 | + // This method can be used after calling write(). | |
| 475 | + QPDF_DLL | |
| 476 | + std::map<QPDFObjGen, QPDFXRefEntry> getWrittenXRefTable(); | |
| 477 | + | |
| 473 | 478 | private: |
| 474 | 479 | // flags used by unparseObject |
| 475 | 480 | static int const f_stream = 1 << 0; | ... | ... |
libqpdf/QPDFWriter.cc
| ... | ... | @@ -2747,6 +2747,23 @@ QPDFWriter::getRenumberedObjGen(QPDFObjGen og) |
| 2747 | 2747 | return QPDFObjGen(this->m->obj_renumber[og], 0); |
| 2748 | 2748 | } |
| 2749 | 2749 | |
| 2750 | +std::map<QPDFObjGen, QPDFXRefEntry> | |
| 2751 | +QPDFWriter::getWrittenXRefTable() | |
| 2752 | +{ | |
| 2753 | + std::map<QPDFObjGen, QPDFXRefEntry> result; | |
| 2754 | + | |
| 2755 | + for (std::map<int, QPDFXRefEntry>::iterator iter = this->m->xref.begin(); | |
| 2756 | + iter != this->m->xref.end(); ++iter) | |
| 2757 | + { | |
| 2758 | + if (iter->first != 0 && iter->second.getType() != 0) | |
| 2759 | + { | |
| 2760 | + result[QPDFObjGen(iter->first, 0)] = iter->second; | |
| 2761 | + } | |
| 2762 | + } | |
| 2763 | + | |
| 2764 | + return result; | |
| 2765 | +} | |
| 2766 | + | |
| 2750 | 2767 | void |
| 2751 | 2768 | QPDFWriter::enqueuePart(std::vector<QPDFObjectHandle>& part) |
| 2752 | 2769 | { | ... | ... |
qpdf/test_renumber.cc
| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | #include <qpdf/QPDFObjectHandle.hh> |
| 6 | 6 | #include <qpdf/QPDFObjGen.hh> |
| 7 | 7 | #include <qpdf/QPDFWriter.hh> |
| 8 | +#include <qpdf/QPDFXRefEntry.hh> | |
| 8 | 9 | |
| 9 | 10 | #include <algorithm> |
| 10 | 11 | #include <iostream> |
| ... | ... | @@ -158,6 +159,77 @@ bool compare(QPDFObjectHandle a, QPDFObjectHandle b) |
| 158 | 159 | return true; |
| 159 | 160 | } |
| 160 | 161 | |
| 162 | +bool compare_xref_table(std::map<QPDFObjGen, QPDFXRefEntry> a, | |
| 163 | + std::map<QPDFObjGen, QPDFXRefEntry> b) | |
| 164 | +{ | |
| 165 | + if (a.size() != b.size()) | |
| 166 | + { | |
| 167 | + std::cerr | |
| 168 | + << "different size" | |
| 169 | + << std::endl; | |
| 170 | + return false; | |
| 171 | + } | |
| 172 | + | |
| 173 | + for (std::map<QPDFObjGen, QPDFXRefEntry>::iterator iter = a.begin(); | |
| 174 | + iter != a.end(); ++iter) | |
| 175 | + { | |
| 176 | + std::cout | |
| 177 | + << "xref entry for " | |
| 178 | + << iter->first.getObj() << "/" << iter->first.getGen() | |
| 179 | + << std::endl; | |
| 180 | + | |
| 181 | + if (b.count(iter->first) == 0) | |
| 182 | + { | |
| 183 | + std::cerr | |
| 184 | + << "not found" | |
| 185 | + << std::endl; | |
| 186 | + return false; | |
| 187 | + } | |
| 188 | + | |
| 189 | + QPDFXRefEntry xref_a = iter->second; | |
| 190 | + QPDFXRefEntry xref_b = b[iter->first]; | |
| 191 | + if (xref_a.getType() != xref_b.getType()) | |
| 192 | + { | |
| 193 | + std::cerr | |
| 194 | + << "different xref entry type" | |
| 195 | + << std::endl; | |
| 196 | + return false; | |
| 197 | + } | |
| 198 | + | |
| 199 | + switch (xref_a.getType()) | |
| 200 | + { | |
| 201 | + case 0: | |
| 202 | + break; | |
| 203 | + case 1: | |
| 204 | + if (xref_a.getOffset() != xref_a.getOffset()) | |
| 205 | + { | |
| 206 | + std::cerr | |
| 207 | + << "different offset" | |
| 208 | + << std::endl; | |
| 209 | + return false; | |
| 210 | + } | |
| 211 | + break; | |
| 212 | + case 2: | |
| 213 | + if (xref_a.getObjStreamNumber() != xref_a.getObjStreamNumber() || | |
| 214 | + xref_a.getObjStreamIndex() != xref_a.getObjStreamIndex()) | |
| 215 | + { | |
| 216 | + std::cerr | |
| 217 | + << "different stream number or index" | |
| 218 | + << std::endl; | |
| 219 | + return false; | |
| 220 | + } | |
| 221 | + break; | |
| 222 | + default: | |
| 223 | + std::cerr | |
| 224 | + << "unknown xref entry type" | |
| 225 | + << std::endl; | |
| 226 | + std::exit(2); | |
| 227 | + } | |
| 228 | + } | |
| 229 | + | |
| 230 | + return true; | |
| 231 | +} | |
| 232 | + | |
| 161 | 233 | int main(int argc, char *argv[]) |
| 162 | 234 | { |
| 163 | 235 | if (argc < 2) |
| ... | ... | @@ -226,13 +298,20 @@ int main(int argc, char *argv[]) |
| 226 | 298 | w.setPreserveUnreferencedObjects(bpreserve_unreferenced); |
| 227 | 299 | w.write(); |
| 228 | 300 | |
| 301 | + std::map<QPDFObjGen, QPDFXRefEntry> xrefs_w | |
| 302 | + = w.getWrittenXRefTable(); | |
| 229 | 303 | PointerHolder<Buffer> buf = w.getBuffer(); |
| 230 | 304 | |
| 231 | 305 | QPDF qpdf_ren; |
| 232 | 306 | qpdf_ren.processMemoryFile("renumbered", |
| 233 | 307 | reinterpret_cast<char*>(buf->getBuffer()), |
| 234 | 308 | buf->getSize()); |
| 309 | + std::map<QPDFObjGen, QPDFXRefEntry> xrefs_ren | |
| 310 | + = qpdf_ren.getXRefTable(); | |
| 235 | 311 | |
| 312 | + std::cout | |
| 313 | + << "--- compare between input and renumbered objects ---" | |
| 314 | + << std::endl; | |
| 236 | 315 | for (std::vector<QPDFObjectHandle>::iterator iter = objs_in.begin(); |
| 237 | 316 | iter != objs_in.end(); ++iter) |
| 238 | 317 | { |
| ... | ... | @@ -260,6 +339,19 @@ int main(int argc, char *argv[]) |
| 260 | 339 | std::exit(2); |
| 261 | 340 | } |
| 262 | 341 | } |
| 342 | + std::cout << "complete" << std::endl; | |
| 343 | + | |
| 344 | + std::cout | |
| 345 | + << "--- compare between written and reloaded xref tables ---" | |
| 346 | + << std::endl; | |
| 347 | + if (!compare_xref_table(xrefs_w, xrefs_ren)) | |
| 348 | + { | |
| 349 | + std::cerr | |
| 350 | + << "different" | |
| 351 | + << std::endl; | |
| 352 | + std::exit(2); | |
| 353 | + } | |
| 354 | + std::cout << "complete" << std::endl; | |
| 263 | 355 | |
| 264 | 356 | std::cout << "succeeded" << std::endl; |
| 265 | 357 | } | ... | ... |