| OLD | NEW |
| 1 #include "SkNativeParsedPDF.h" | 1 #include "SkNativeParsedPDF.h" |
| 2 #include "SkPdfNativeTokenizer.h" | 2 #include "SkPdfNativeTokenizer.h" |
| 3 #include "SkPdfBasics.h" | 3 #include "SkPdfBasics.h" |
| 4 #include "SkPdfObject.h" | 4 #include "SkPdfObject.h" |
| 5 | 5 |
| 6 #include <stdio.h> | 6 #include <stdio.h> |
| 7 #include <string.h> | 7 #include <string.h> |
| 8 #include <sys/types.h> | 8 #include <sys/types.h> |
| 9 #include <sys/stat.h> | 9 #include <sys/stat.h> |
| 10 | 10 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 | 116 |
| 117 if (strcmp((char*)xrefstartKeywordLine, "startxref") != 0) { | 117 if (strcmp((char*)xrefstartKeywordLine, "startxref") != 0) { |
| 118 // TODO(edisonn): report/issue | 118 // TODO(edisonn): report/issue |
| 119 } | 119 } |
| 120 | 120 |
| 121 long xrefByteOffset = atol((const char*)xrefByteOffsetLine); | 121 long xrefByteOffset = atol((const char*)xrefByteOffsetLine); |
| 122 | 122 |
| 123 bool storeCatalog = true; | 123 bool storeCatalog = true; |
| 124 while (xrefByteOffset >= 0) { | 124 while (xrefByteOffset >= 0) { |
| 125 const unsigned char* trailerStart = readCrossReferenceSection(fFileConte
nt + xrefByteOffset, xrefstartKeywordLine); | 125 const unsigned char* trailerStart = readCrossReferenceSection(fFileConte
nt + xrefByteOffset, xrefstartKeywordLine); |
| 126 xrefByteOffset = readTrailer(trailerStart, xrefstartKeywordLine, storeCa
talog); | 126 readTrailer(trailerStart, xrefstartKeywordLine, storeCatalog, &xrefByteO
ffset, false); |
| 127 storeCatalog = false; | 127 storeCatalog = false; |
| 128 } | 128 } |
| 129 | 129 |
| 130 // TODO(edisonn): warn/error expect fObjects[fRefCatalogId].fGeneration == f
RefCatalogGeneration | 130 // TODO(edisonn): warn/error expect fObjects[fRefCatalogId].fGeneration == f
RefCatalogGeneration |
| 131 // TODO(edisonn): security, verify that SkPdfCatalogDictionary is indeed usi
ng mapper | 131 // TODO(edisonn): security, verify that SkPdfCatalogDictionary is indeed usi
ng mapper |
| 132 // load catalog | 132 // load catalog |
| 133 | 133 |
| 134 if (fRootCatalogRef) { | 134 if (fRootCatalogRef) { |
| 135 fRootCatalog = (SkPdfCatalogDictionary*)resolveReference(fRootCatalogRef
); | 135 fRootCatalog = (SkPdfCatalogDictionary*)resolveReference(fRootCatalogRef
); |
| 136 if (fRootCatalog->isDictionary() && fRootCatalog->valid()) { | 136 if (fRootCatalog->isDictionary() && fRootCatalog->valid()) { |
| 137 SkPdfPageTreeNodeDictionary* tree = fRootCatalog->Pages(this); | 137 SkPdfPageTreeNodeDictionary* tree = fRootCatalog->Pages(this); |
| 138 if (tree && tree->isDictionary() && tree->valid()) { | 138 if (tree && tree->isDictionary() && tree->valid()) { |
| 139 fillPages(tree); | 139 fillPages(tree); |
| 140 } | 140 } |
| 141 } | 141 } |
| 142 } | 142 } |
| 143 | 143 |
| 144 // TODO(edisonn): clean up this doc, or better, let the caller call again an
d build a new doc |
| 145 // caller should be a static function. |
| 146 if (pages() == 0) { |
| 147 loadWithoutXRef(); |
| 148 } |
| 149 |
| 144 // TODO(edisonn): corrupted pdf, read it from beginning and rebuild (xref, t
railer, or just reall all objects) | 150 // TODO(edisonn): corrupted pdf, read it from beginning and rebuild (xref, t
railer, or just reall all objects) |
| 145 // 0 pages | 151 // 0 pages |
| 146 | 152 |
| 147 // now actually read all objects if we want, or do it lazyly | 153 // now actually read all objects if we want, or do it lazyly |
| 148 // and resolve references?... or not ... | 154 // and resolve references?... or not ... |
| 149 } | 155 } |
| 150 | 156 |
| 157 void SkNativeParsedPDF::loadWithoutXRef() { |
| 158 const unsigned char* current = fFileContent; |
| 159 const unsigned char* end = fFileContent + fContentLength; |
| 160 |
| 161 // TODO(edisonn): read pdf version |
| 162 current = ignoreLine(current, end); |
| 163 |
| 164 current = skipPdfWhiteSpaces(0, current, end); |
| 165 while (current < end) { |
| 166 SkPdfObject token; |
| 167 current = nextObject(0, current, end, &token, NULL, NULL); |
| 168 if (token.isInteger()) { |
| 169 int id = (int)token.intValue(); |
| 170 |
| 171 token.reset(); |
| 172 current = nextObject(0, current, end, &token, NULL, NULL); |
| 173 // int generation = (int)token.intValue(); // TODO(edisonn): ignore
d for now |
| 174 |
| 175 token.reset(); |
| 176 current = nextObject(0, current, end, &token, NULL, NULL); |
| 177 // TODO(edisonn): must be obj, return error if not? ignore ? |
| 178 if (!token.isKeyword("obj")) { |
| 179 continue; |
| 180 } |
| 181 |
| 182 while (fObjects.count() < id + 1) { |
| 183 reset(fObjects.append()); |
| 184 } |
| 185 |
| 186 fObjects[id].fOffset = current - fFileContent; |
| 187 |
| 188 SkPdfObject* obj = fAllocator->allocObject(); |
| 189 current = nextObject(0, current, end, obj, fAllocator, this); |
| 190 |
| 191 fObjects[id].fResolvedReference = obj; |
| 192 fObjects[id].fObj = obj; |
| 193 |
| 194 // set objects |
| 195 } else if (token.isKeyword("trailer")) { |
| 196 long dummy; |
| 197 current = readTrailer(current, end, true, &dummy, true); |
| 198 } else if (token.isKeyword("startxref")) { |
| 199 token.reset(); |
| 200 current = nextObject(0, current, end, &token, NULL, NULL); // ignor
e |
| 201 } |
| 202 |
| 203 current = skipPdfWhiteSpaces(0, current, end); |
| 204 } |
| 205 |
| 206 if (fRootCatalogRef) { |
| 207 fRootCatalog = (SkPdfCatalogDictionary*)resolveReference(fRootCatalogRef
); |
| 208 if (fRootCatalog->isDictionary() && fRootCatalog->valid()) { |
| 209 SkPdfPageTreeNodeDictionary* tree = fRootCatalog->Pages(this); |
| 210 if (tree && tree->isDictionary() && tree->valid()) { |
| 211 fillPages(tree); |
| 212 } |
| 213 } |
| 214 } |
| 215 |
| 216 } |
| 217 |
| 151 // TODO(edisonn): NYI | 218 // TODO(edisonn): NYI |
| 152 SkNativeParsedPDF::~SkNativeParsedPDF() { | 219 SkNativeParsedPDF::~SkNativeParsedPDF() { |
| 153 sk_free((void*)fFileContent); | 220 sk_free((void*)fFileContent); |
| 154 delete fAllocator; | 221 delete fAllocator; |
| 155 } | 222 } |
| 156 | 223 |
| 157 const unsigned char* SkNativeParsedPDF::readCrossReferenceSection(const unsigned
char* xrefStart, const unsigned char* trailerEnd) { | 224 const unsigned char* SkNativeParsedPDF::readCrossReferenceSection(const unsigned
char* xrefStart, const unsigned char* trailerEnd) { |
| 158 const unsigned char* current = ignoreLine(xrefStart, trailerEnd); // TODO(e
disonn): verify next keyord is "xref", use nextObject here | 225 const unsigned char* current = ignoreLine(xrefStart, trailerEnd); // TODO(e
disonn): verify next keyord is "xref", use nextObject here |
| 159 | 226 |
| 160 SkPdfObject token; | 227 SkPdfObject token; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 return current; | 268 return current; |
| 202 } | 269 } |
| 203 | 270 |
| 204 addCrossSectionInfo(startId + i, generation, offset, *token.c_str()
== 'f'); | 271 addCrossSectionInfo(startId + i, generation, offset, *token.c_str()
== 'f'); |
| 205 } | 272 } |
| 206 } | 273 } |
| 207 // TODO(edisonn): it should never get here? there is no trailer? | 274 // TODO(edisonn): it should never get here? there is no trailer? |
| 208 return current; | 275 return current; |
| 209 } | 276 } |
| 210 | 277 |
| 211 long SkNativeParsedPDF::readTrailer(const unsigned char* trailerStart, const uns
igned char* trailerEnd, bool storeCatalog) { | 278 const unsigned char* SkNativeParsedPDF::readTrailer(const unsigned char* trailer
Start, const unsigned char* trailerEnd, bool storeCatalog, long* prev, bool skip
Keyword) { |
| 212 SkPdfObject trailerKeyword; | 279 *prev = -1; |
| 213 // TODO(edisonn): use null allocator, and let it just fail if memory | |
| 214 // needs allocated (but no crash)! | |
| 215 const unsigned char* current = | |
| 216 nextObject(0, trailerStart, trailerEnd, &trailerKeyword, NULL, NULL)
; | |
| 217 | 280 |
| 218 if (!trailerKeyword.isKeyword() || strlen("trailer") != trailerKeyword.lenst
r() || | 281 const unsigned char* current = trailerStart; |
| 219 strncmp(trailerKeyword.c_str(), "trailer", strlen("trailer")) != 0) { | 282 if (!skipKeyword) { |
| 220 // TODO(edisonn): report warning, rebuild trailer from objects. | 283 SkPdfObject trailerKeyword; |
| 221 return -1; | 284 // TODO(edisonn): use null allocator, and let it just fail if memory |
| 285 // needs allocated (but no crash)! |
| 286 current = nextObject(0, current, trailerEnd, &trailerKeyword, NULL, NULL
); |
| 287 |
| 288 if (!trailerKeyword.isKeyword() || strlen("trailer") != trailerKeyword.l
enstr() || |
| 289 strncmp(trailerKeyword.c_str(), "trailer", strlen("trailer")) != 0)
{ |
| 290 // TODO(edisonn): report warning, rebuild trailer from objects. |
| 291 return current; |
| 292 } |
| 222 } | 293 } |
| 223 | 294 |
| 224 SkPdfObject token; | 295 SkPdfObject token; |
| 225 current = nextObject(0, current, trailerEnd, &token, fAllocator, NULL); | 296 current = nextObject(0, current, trailerEnd, &token, fAllocator, NULL); |
| 226 if (!token.isDictionary()) { | 297 if (!token.isDictionary()) { |
| 227 return -1; | 298 return current; |
| 228 } | 299 } |
| 229 SkPdfFileTrailerDictionary* trailer = (SkPdfFileTrailerDictionary*)&token; | 300 SkPdfFileTrailerDictionary* trailer = (SkPdfFileTrailerDictionary*)&token; |
| 230 if (!trailer->valid()) { | 301 if (!trailer->valid()) { |
| 231 return -1; | 302 return current; |
| 232 } | 303 } |
| 233 | 304 |
| 234 if (storeCatalog) { | 305 if (storeCatalog) { |
| 235 const SkPdfObject* ref = trailer->Root(NULL); | 306 const SkPdfObject* ref = trailer->Root(NULL); |
| 236 if (ref == NULL || !ref->isReference()) { | 307 if (ref == NULL || !ref->isReference()) { |
| 237 // TODO(edisonn): oops, we have to fix the corrup pdf file | 308 // TODO(edisonn): oops, we have to fix the corrup pdf file |
| 238 return -1; | 309 return current; |
| 239 } | 310 } |
| 240 fRootCatalogRef = ref; | 311 fRootCatalogRef = ref; |
| 241 } | 312 } |
| 242 | 313 |
| 243 if (trailer->has_Prev()) { | 314 if (trailer->has_Prev()) { |
| 244 return (long)trailer->Prev(NULL); | 315 *prev = (long)trailer->Prev(NULL); |
| 245 } | 316 } |
| 246 | 317 |
| 247 return -1; | 318 return current; |
| 248 } | 319 } |
| 249 | 320 |
| 250 void SkNativeParsedPDF::addCrossSectionInfo(int id, int generation, int offset,
bool isFreed) { | 321 void SkNativeParsedPDF::addCrossSectionInfo(int id, int generation, int offset,
bool isFreed) { |
| 251 // TODO(edisonn): security here | 322 // TODO(edisonn): security here |
| 252 while (fObjects.count() < id + 1) { | 323 while (fObjects.count() < id + 1) { |
| 253 reset(fObjects.append()); | 324 reset(fObjects.append()); |
| 254 } | 325 } |
| 255 | 326 |
| 256 fObjects[id].fOffset = offset; | 327 fObjects[id].fOffset = offset; |
| 257 fObjects[id].fObj = NULL; | 328 fObjects[id].fObj = NULL; |
| 329 fObjects[id].fResolvedReference = NULL; |
| 258 } | 330 } |
| 259 | 331 |
| 260 SkPdfObject* SkNativeParsedPDF::readObject(int id/*, int expectedGeneration*/) { | 332 SkPdfObject* SkNativeParsedPDF::readObject(int id/*, int expectedGeneration*/) { |
| 261 long startOffset = fObjects[id].fOffset; | 333 long startOffset = fObjects[id].fOffset; |
| 262 //long endOffset = fObjects[id].fOffsetEnd; | 334 //long endOffset = fObjects[id].fOffsetEnd; |
| 263 // TODO(edisonn): use hinted endOffset | 335 // TODO(edisonn): use hinted endOffset |
| 264 // TODO(edisonn): current implementation will result in a lot of memory usag
e | 336 // TODO(edisonn): current implementation will result in a lot of memory usag
e |
| 265 // to decrease memory usage, we wither need to be smart and know where objec
ts end, and we will | 337 // to decrease memory usage, we wither need to be smart and know where objec
ts end, and we will |
| 266 // alocate only the chancks needed, or the tokenizer will not make copies, b
ut then it needs to | 338 // alocate only the chancks needed, or the tokenizer will not make copies, b
ut then it needs to |
| 267 // cache the results so it does not go twice on the same buffer | 339 // cache the results so it does not go twice on the same buffer |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 460 return (SkPdfObject*)ref; | 532 return (SkPdfObject*)ref; |
| 461 } | 533 } |
| 462 | 534 |
| 463 size_t SkNativeParsedPDF::bytesUsed() const { | 535 size_t SkNativeParsedPDF::bytesUsed() const { |
| 464 return fAllocator->bytesUsed() + | 536 return fAllocator->bytesUsed() + |
| 465 fContentLength + | 537 fContentLength + |
| 466 fObjects.count() * sizeof(PublicObjectEntry) + | 538 fObjects.count() * sizeof(PublicObjectEntry) + |
| 467 fPages.count() * sizeof(SkPdfPageObjectDictionary*) + | 539 fPages.count() * sizeof(SkPdfPageObjectDictionary*) + |
| 468 sizeof(*this); | 540 sizeof(*this); |
| 469 } | 541 } |
| OLD | NEW |