| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkPdfConfig.h" |
| 9 #include "SkPdfNativeObject.h" |
| 8 #include "SkPdfNativeTokenizer.h" | 10 #include "SkPdfNativeTokenizer.h" |
| 9 #include "SkPdfNativeObject.h" | 11 #include "SkPdfUtils.h" |
| 10 #include "SkPdfConfig.h" | |
| 11 | 12 |
| 12 // TODO(edisonn): mac builder does not find the header ... but from headers is o
k | 13 // TODO(edisonn): mac builder does not find the header ... but from headers is o
k |
| 13 //#include "SkPdfStreamCommonDictionary_autogen.h" | 14 //#include "SkPdfStreamCommonDictionary_autogen.h" |
| 14 //#include "SkPdfImageDictionary_autogen.h" | 15 //#include "SkPdfImageDictionary_autogen.h" |
| 15 #include "SkPdfHeaders_autogen.h" | 16 #include "SkPdfHeaders_autogen.h" |
| 16 | 17 |
| 17 | 18 |
| 18 // TODO(edisonn): perf!!! | 19 // TODO(edisonn): Perf, Make this function run faster. |
| 19 // there could be 0s between start and end! but not in the needle. | 20 // There could be 0s between start and end. |
| 21 // needle will not contain 0s. |
| 20 static char* strrstrk(char* hayStart, char* hayEnd, const char* needle) { | 22 static char* strrstrk(char* hayStart, char* hayEnd, const char* needle) { |
| 21 int needleLen = strlen(needle); | 23 int needleLen = strlen(needle); |
| 22 if ((isPdfWhiteSpaceOrPdfDelimiter(*(hayStart+needleLen)) || (hayStart+needl
eLen == hayEnd)) && | 24 if ((isPdfWhiteSpaceOrPdfDelimiter(*(hayStart+needleLen)) || (hayStart+needl
eLen == hayEnd)) && |
| 23 strncmp(hayStart, needle, needleLen) == 0) { | 25 strncmp(hayStart, needle, needleLen) == 0) { |
| 24 return hayStart; | 26 return hayStart; |
| 25 } | 27 } |
| 26 | 28 |
| 27 hayStart++; | 29 hayStart++; |
| 28 | 30 |
| 29 while (hayStart < hayEnd) { | 31 while (hayStart < hayEnd) { |
| 30 if (isPdfWhiteSpaceOrPdfDelimiter(*(hayStart-1)) && | 32 if (isPdfWhiteSpaceOrPdfDelimiter(*(hayStart-1)) && |
| 31 (isPdfWhiteSpaceOrPdfDelimiter(*(hayStart+needleLen)) || (haySta
rt+needleLen == hayEnd)) && | 33 (isPdfWhiteSpaceOrPdfDelimiter(*(hayStart+needleLen)) || |
| 34 (hayStart+needleLen == hayEnd)) && |
| 32 strncmp(hayStart, needle, needleLen) == 0) { | 35 strncmp(hayStart, needle, needleLen) == 0) { |
| 33 return hayStart; | 36 return hayStart; |
| 34 } | 37 } |
| 35 hayStart++; | 38 hayStart++; |
| 36 } | 39 } |
| 37 return NULL; | 40 return NULL; |
| 38 } | 41 } |
| 39 | 42 |
| 40 #ifdef PDF_TRACE_TOKENIZER | |
| 41 | |
| 42 static void TRACE_COMMENT(char ch) { | |
| 43 printf("%c", ch); | |
| 44 } | |
| 45 | |
| 46 static void TRACE_TK(char ch) { | |
| 47 printf("%c", ch); | |
| 48 } | |
| 49 | |
| 50 static void TRACE_NAME(const unsigned char* start, const unsigned char* end) { | |
| 51 while (start < end) { | |
| 52 printf("%c", *start); | |
| 53 start++; | |
| 54 } | |
| 55 printf("\n"); | |
| 56 } | |
| 57 | |
| 58 static void TRACE_STRING(const unsigned char* start, const unsigned char* end) { | |
| 59 while (start < end) { | |
| 60 printf("%c", *start); | |
| 61 start++; | |
| 62 } | |
| 63 printf("\n"); | |
| 64 } | |
| 65 | |
| 66 static void TRACE_HEXSTRING(const unsigned char* start, const unsigned char* end
) { | |
| 67 while (start < end) { | |
| 68 printf("%c", *start); | |
| 69 start++; | |
| 70 } | |
| 71 printf("\n"); | |
| 72 } | |
| 73 | |
| 74 #else | |
| 75 #define TRACE_COMMENT(ch) | |
| 76 #define TRACE_TK(ch) | |
| 77 #define TRACE_NAME(start,end) | |
| 78 #define TRACE_STRING(start,end) | |
| 79 #define TRACE_HEXSTRING(start,end) | |
| 80 #endif | |
| 81 | |
| 82 const unsigned char* skipPdfWhiteSpaces(const unsigned char* start, const unsign
ed char* end) { | 43 const unsigned char* skipPdfWhiteSpaces(const unsigned char* start, const unsign
ed char* end) { |
| 83 while (start < end && (isPdfWhiteSpace(*start) || *start == kComment_PdfDeli
miter)) { | 44 while (start < end && (isPdfWhiteSpace(*start) || *start == kComment_PdfDeli
miter)) { |
| 84 TRACE_COMMENT(*start); | 45 TRACE_COMMENT(*start); |
| 85 if (*start == kComment_PdfDelimiter) { | 46 if (*start == kComment_PdfDelimiter) { |
| 86 // skip the comment until end of line | 47 // skip the comment until end of line |
| 87 while (start < end && !isPdfEOL(*start)) { | 48 while (start < end && !isPdfEOL(*start)) { |
| 88 //*start = '\0'; | |
| 89 start++; | 49 start++; |
| 90 TRACE_COMMENT(*start); | 50 TRACE_COMMENT(*start); |
| 91 } | 51 } |
| 92 } else { | 52 } else { |
| 93 //*start = '\0'; | |
| 94 start++; | 53 start++; |
| 95 } | 54 } |
| 96 } | 55 } |
| 97 return start; | 56 return start; |
| 98 } | 57 } |
| 99 | 58 |
| 100 // TODO(edisonn) '(' can be used, will it break the string a delimiter or space
inside () ? | |
| 101 const unsigned char* endOfPdfToken(const unsigned char* start, const unsigned ch
ar* end) { | 59 const unsigned char* endOfPdfToken(const unsigned char* start, const unsigned ch
ar* end) { |
| 102 SkASSERT(!isPdfWhiteSpace(*start)); | 60 SkASSERT(!isPdfWhiteSpace(*start)); |
| 103 | 61 |
| 104 if (start < end && isPdfDelimiter(*start)) { | 62 if (start < end && isPdfDelimiter(*start)) { |
| 105 TRACE_TK(*start); | 63 TRACE_TK(*start); |
| 106 start++; | 64 start++; |
| 107 return start; | 65 return start; |
| 108 } | 66 } |
| 109 | 67 |
| 110 while (start < end && !isPdfWhiteSpaceOrPdfDelimiter(*start)) { | 68 while (start < end && !isPdfWhiteSpaceOrPdfDelimiter(*start)) { |
| 111 TRACE_TK(*start); | 69 TRACE_TK(*start); |
| 112 start++; | 70 start++; |
| 113 } | 71 } |
| 114 return start; | 72 return start; |
| 115 } | 73 } |
| 116 | 74 |
| 117 // last elem has to be ] | 75 // The parsing should end with a ]. |
| 118 static const unsigned char* readArray(const unsigned char* start, const unsigned
char* end, SkPdfNativeObject* array, SkPdfAllocator* allocator, SkPdfNativeDoc*
doc) { | 76 static const unsigned char* readArray(const unsigned char* start, const unsigned
char* end, |
| 77 SkPdfNativeObject* array, |
| 78 SkPdfAllocator* allocator, SkPdfNativeDoc*
doc) { |
| 119 SkPdfNativeObject::makeEmptyArray(array); | 79 SkPdfNativeObject::makeEmptyArray(array); |
| 120 // PUT_TRACK_STREAM(array, start, start) | 80 // PUT_TRACK_STREAM(array, start, start) |
| 121 | 81 |
| 122 if (allocator == NULL) { | 82 if (allocator == NULL) { |
| 123 // TODO(edisonn): report/warning error | 83 // TODO(edisonn): report/warning error/assert |
| 124 return end; | 84 return end; |
| 125 } | 85 } |
| 126 | 86 |
| 127 while (start < end) { | 87 while (start < end) { |
| 128 // skip white spaces | 88 // skip white spaces |
| 129 start = skipPdfWhiteSpaces(start, end); | 89 start = skipPdfWhiteSpaces(start, end); |
| 130 | 90 |
| 131 const unsigned char* endOfToken = endOfPdfToken(start, end); | 91 const unsigned char* endOfToken = endOfPdfToken(start, end); |
| 132 | 92 |
| 133 if (endOfToken == start) { | 93 if (endOfToken == start) { |
| 134 // TODO(edisonn): report error in pdf file (end of stream with ] for
end of aray | 94 // TODO(edisonn): report error in pdf file (end of stream with ] for
end of aray |
| 135 return start; | 95 return start; |
| 136 } | 96 } |
| 137 | 97 |
| 138 if (endOfToken == start + 1 && *start == kClosedSquareBracket_PdfDelimit
er) { | 98 if (endOfToken == start + 1 && *start == kClosedSquareBracket_PdfDelimit
er) { |
| 139 return endOfToken; | 99 return endOfToken; |
| 140 } | 100 } |
| 141 | 101 |
| 142 SkPdfNativeObject* newObj = allocator->allocObject(); | 102 SkPdfNativeObject* newObj = allocator->allocObject(); |
| 143 start = nextObject(start, end, newObj, allocator, doc); | 103 start = nextObject(start, end, newObj, allocator, doc); |
| 144 // TODO(edisonn): perf/memory: put the variables on the stack, and flush
them on the array only when | 104 // TODO(edisonn): perf/memory: put the variables on the stack, and flush
them on the array |
| 145 // we are sure they are not references! | 105 // only when we are sure they are not references! |
| 146 if (newObj->isKeywordReference() && array->size() >= 2 && array->objAtAI
ndex(array->size() - 1)->isInteger() && array->objAtAIndex(array->size() - 2)->i
sInteger()) { | 106 if (newObj->isKeywordReference() && array->size() >= 2 && |
| 107 array->objAtAIndex(array->size() - 1)->isInteger() && |
| 108 array->objAtAIndex(array->size() - 2)->isInteger()) { |
| 147 SkPdfNativeObject* gen = array->removeLastInArray(); | 109 SkPdfNativeObject* gen = array->removeLastInArray(); |
| 148 SkPdfNativeObject* id = array->removeLastInArray(); | 110 SkPdfNativeObject* id = array->removeLastInArray(); |
| 149 | 111 |
| 150 SkPdfNativeObject::resetAndMakeReference((unsigned int)id->intValue(
), (unsigned int)gen->intValue(), newObj); | 112 SkPdfNativeObject::resetAndMakeReference((unsigned int)id->intValue(
), |
| 113 (unsigned int)gen->intValue
(), newObj); |
| 151 // newObj PUT_TRACK_PARAMETERS_OBJ2(id, newObj) - store end, as now | 114 // newObj PUT_TRACK_PARAMETERS_OBJ2(id, newObj) - store end, as now |
| 152 | |
| 153 } | 115 } |
| 154 array->appendInArray(newObj); | 116 array->appendInArray(newObj); |
| 155 } | 117 } |
| 156 // TODO(edisonn): report not reached, we should never get here | 118 // TODO(edisonn): report not reached, we should never get here |
| 157 // TODO(edisonn): there might be a bug here, enable an assert and run it on
files | 119 // TODO(edisonn): there might be a bug here, enable an assert and run it on
files |
| 158 // or it might be that the files were actually corrupted | 120 // or it might be that the files were actually corrupted |
| 159 return start; | 121 return start; |
| 160 } | 122 } |
| 161 | 123 |
| 162 // When we read strings we will rewrite the string so we will reuse the memory | 124 static const unsigned char* readString(const unsigned char* start, const unsigne
d char* end, |
| 163 // when we start to read the string, we already consumed the opened bracket | 125 unsigned char* out) { |
| 164 | |
| 165 // TODO(edisonn): space: add paramater, taht would report if we need to allocate
new buffer, or we can reuse the one we have | |
| 166 | |
| 167 static const unsigned char* readString(const unsigned char* start, const unsigne
d char* end, unsigned char* out) { | |
| 168 const unsigned char* in = start; | 126 const unsigned char* in = start; |
| 169 bool hasOut = (out != NULL); | 127 bool hasOut = (out != NULL); |
| 170 | 128 |
| 171 int openRoundBrackets = 1; | 129 int openRoundBrackets = 1; |
| 172 while (in < end) { | 130 while (in < end) { |
| 173 openRoundBrackets += ((*in) == kOpenedRoundBracket_PdfDelimiter); | 131 openRoundBrackets += ((*in) == kOpenedRoundBracket_PdfDelimiter); |
| 174 openRoundBrackets -= ((*in) == kClosedRoundBracket_PdfDelimiter); | 132 openRoundBrackets -= ((*in) == kClosedRoundBracket_PdfDelimiter); |
| 175 if (openRoundBrackets == 0) { | 133 if (openRoundBrackets == 0) { |
| 176 in++; // consumed ) | 134 in++; // consumed ) |
| 177 break; | 135 break; |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 253 } | 211 } |
| 254 } | 212 } |
| 255 if (i > 0) { | 213 if (i > 0) { |
| 256 if (hasOut) { *out = code & 0xff; } | 214 if (hasOut) { *out = code & 0xff; } |
| 257 out++; | 215 out++; |
| 258 } | 216 } |
| 259 } | 217 } |
| 260 break; | 218 break; |
| 261 | 219 |
| 262 default: | 220 default: |
| 263 // Per spec, backslash is ignored is escaped ch is unkno
wn | 221 // Per spec, backslash is ignored if escaped ch is unkno
wn |
| 264 in++; | 222 in++; |
| 265 break; | 223 break; |
| 266 } | 224 } |
| 267 } else { | 225 } else { |
| 268 in++; | 226 in++; |
| 269 } | 227 } |
| 270 } else { | 228 } else { |
| 271 // TODO(edisonn): perf, avoid copy into itself, maybe first do a sim
ple scan until found backslash ? | |
| 272 // we could have one look that first just inc current, and when we f
ind the backslash | |
| 273 // we go to this loop | |
| 274 if (hasOut) { *out = *in; } | 229 if (hasOut) { *out = *in; } |
| 275 in++; | 230 in++; |
| 276 out++; | 231 out++; |
| 277 } | 232 } |
| 278 } | 233 } |
| 279 | 234 |
| 280 if (hasOut) { | 235 if (hasOut) { |
| 281 return in; // consumed already ) at the end of the string | 236 return in; // consumed already ) at the end of the string |
| 282 } else { | 237 } else { |
| 283 return start + (out - (const unsigned char*)NULL); // return where the s
tring would end if we reuse the string | 238 // return where the string would end if we reuse the string |
| 239 return start + (out - (const unsigned char*)NULL); |
| 284 } | 240 } |
| 285 } | 241 } |
| 286 | 242 |
| 287 static int readStringLength(const unsigned char* start, const unsigned char* end
) { | 243 static int readStringLength(const unsigned char* start, const unsigned char* end
) { |
| 288 return readString(start, end, NULL) - start; | 244 return readString(start, end, NULL) - start; |
| 289 } | 245 } |
| 290 | 246 |
| 291 static const unsigned char* readString(const unsigned char* start, const unsigne
d char* end, SkPdfNativeObject* str, SkPdfAllocator* allocator) { | 247 static const unsigned char* readString(const unsigned char* start, const unsigne
d char* end, |
| 248 SkPdfNativeObject* str, SkPdfAllocator* a
llocator) { |
| 292 if (!allocator) { | 249 if (!allocator) { |
| 250 // TODO(edisonn): report error/warn/assert |
| 293 return end; | 251 return end; |
| 294 } | 252 } |
| 253 |
| 295 int outLength = readStringLength(start, end); | 254 int outLength = readStringLength(start, end); |
| 296 // TODO(edisonn): optimize the allocation, don't allocate new string, but pu
t it in a preallocated buffer | |
| 297 unsigned char* out = (unsigned char*)allocator->alloc(outLength); | 255 unsigned char* out = (unsigned char*)allocator->alloc(outLength); |
| 298 const unsigned char* now = readString(start, end, out); | 256 const unsigned char* now = readString(start, end, out); |
| 299 SkPdfNativeObject::makeString(out, out + outLength, str); | 257 SkPdfNativeObject::makeString(out, out + outLength, str); |
| 300 // PUT_TRACK_STREAM(str, start, now) | 258 // PUT_TRACK_STREAM(str, start, now) |
| 301 TRACE_STRING(out, out + outLength); | 259 TRACE_STRING(out, out + outLength); |
| 302 return now; // consumed already ) at the end of the string | 260 return now; // consumed already ) at the end of the string |
| 303 } | 261 } |
| 304 | 262 |
| 305 static const unsigned char* readHexString(const unsigned char* start, const unsi
gned char* end, unsigned char* out) { | 263 static const unsigned char* readHexString(const unsigned char* start, const unsi
gned char* end, |
| 264 unsigned char* out) { |
| 306 bool hasOut = (out != NULL); | 265 bool hasOut = (out != NULL); |
| 307 const unsigned char* in = start; | 266 const unsigned char* in = start; |
| 308 | 267 |
| 309 unsigned char code = 0; | 268 unsigned char code = 0; |
| 310 | 269 |
| 311 while (in < end) { | 270 while (in < end) { |
| 312 while (in < end && isPdfWhiteSpace(*in)) { | 271 while (in < end && isPdfWhiteSpace(*in)) { |
| 313 in++; | 272 in++; |
| 314 } | 273 } |
| 315 | 274 |
| 316 if (*in == kClosedInequityBracket_PdfDelimiter) { | 275 if (*in == kClosedInequityBracket_PdfDelimiter) { |
| 317 //*in = '\0'; | |
| 318 in++; // consume > | 276 in++; // consume > |
| 319 // normal exit | 277 // normal exit |
| 320 break; | 278 break; |
| 321 } | 279 } |
| 322 | 280 |
| 323 if (in >= end) { | 281 if (in >= end) { |
| 324 // end too soon | 282 // end too soon |
| 325 break; | 283 break; |
| 326 } | 284 } |
| 327 | 285 |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 default: | 376 default: |
| 419 break; | 377 break; |
| 420 } | 378 } |
| 421 | 379 |
| 422 if (hasOut) { *out = code; } | 380 if (hasOut) { *out = code; } |
| 423 out++; | 381 out++; |
| 424 in++; | 382 in++; |
| 425 } | 383 } |
| 426 | 384 |
| 427 if (hasOut) { | 385 if (hasOut) { |
| 428 return in; // consumed already > at the end of the string | 386 return in; // consumed already ) at the end of the string |
| 429 } else { | 387 } else { |
| 430 return start + (out - (const unsigned char*)NULL); // return where the s
tring would end if we reuse the string | 388 // return where the string would end if we reuse the string |
| 389 return start + (out - (const unsigned char*)NULL); |
| 431 } | 390 } |
| 432 } | 391 } |
| 433 | 392 |
| 434 static int readHexStringLength(const unsigned char* start, const unsigned char*
end) { | 393 static int readHexStringLength(const unsigned char* start, const unsigned char*
end) { |
| 435 return readHexString(start, end, NULL) - start; | 394 return readHexString(start, end, NULL) - start; |
| 436 } | 395 } |
| 437 | 396 |
| 438 static const unsigned char* readHexString(const unsigned char* start, const unsi
gned char* end, SkPdfNativeObject* str, SkPdfAllocator* allocator) { | 397 static const unsigned char* readHexString(const unsigned char* start, const unsi
gned char* end, SkPdfNativeObject* str, SkPdfAllocator* allocator) { |
| 439 if (!allocator) { | 398 if (!allocator) { |
| 399 // TODO(edisonn): report error/warn/assert |
| 440 return end; | 400 return end; |
| 441 } | 401 } |
| 442 int outLength = readHexStringLength(start, end); | 402 int outLength = readHexStringLength(start, end); |
| 443 // TODO(edisonn): optimize the allocation, don't allocate new string, but pu
t it in a preallocated buffer | |
| 444 unsigned char* out = (unsigned char*)allocator->alloc(outLength); | 403 unsigned char* out = (unsigned char*)allocator->alloc(outLength); |
| 445 const unsigned char* now = readHexString(start, end, out); | 404 const unsigned char* now = readHexString(start, end, out); |
| 446 SkPdfNativeObject::makeHexString(out, out + outLength, str); | 405 SkPdfNativeObject::makeHexString(out, out + outLength, str); |
| 447 // str PUT_TRACK_STREAM(start, now) | 406 // str PUT_TRACK_STREAM(start, now) |
| 448 TRACE_HEXSTRING(out, out + outLength); | 407 TRACE_HEXSTRING(out, out + outLength); |
| 449 return now; // consumed already > at the end of the string | 408 return now; // consumed already > at the end of the string |
| 450 } | 409 } |
| 451 | 410 |
| 452 // TODO(edisonn): before PDF 1.2 name could not have special characters, add ver
sion parameter | 411 // TODO(edisonn): add version parameter, before PDF 1.2 name could not have spec
ial characters. |
| 453 static const unsigned char* readName(const unsigned char* start, const unsigned
char* end, unsigned char* out) { | 412 static const unsigned char* readName(const unsigned char* start, const unsigned
char* end, |
| 413 unsigned char* out) { |
| 454 bool hasOut = (out != NULL); | 414 bool hasOut = (out != NULL); |
| 455 const unsigned char* in = start; | 415 const unsigned char* in = start; |
| 456 | 416 |
| 457 unsigned char code = 0; | 417 unsigned char code = 0; |
| 458 | 418 |
| 459 while (in < end) { | 419 while (in < end) { |
| 460 if (isPdfWhiteSpaceOrPdfDelimiter(*in)) { | 420 if (isPdfWhiteSpaceOrPdfDelimiter(*in)) { |
| 461 break; | 421 break; |
| 462 } | 422 } |
| 463 | 423 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 out++; | 503 out++; |
| 544 in++; | 504 in++; |
| 545 } else { | 505 } else { |
| 546 if (hasOut) { *out = *in; } | 506 if (hasOut) { *out = *in; } |
| 547 out++; | 507 out++; |
| 548 in++; | 508 in++; |
| 549 } | 509 } |
| 550 } | 510 } |
| 551 | 511 |
| 552 if (hasOut) { | 512 if (hasOut) { |
| 553 return in; | 513 return in; // consumed already ) at the end of the string |
| 554 } else { | 514 } else { |
| 555 return start + (out - (const unsigned char*)NULL); // return where the s
tring would end if we reuse the string | 515 // return where the string would end if we reuse the string |
| 516 return start + (out - (const unsigned char*)NULL); |
| 556 } | 517 } |
| 557 } | 518 } |
| 558 | 519 |
| 559 static int readNameLength(const unsigned char* start, const unsigned char* end)
{ | 520 static int readNameLength(const unsigned char* start, const unsigned char* end)
{ |
| 560 return readName(start, end, NULL) - start; | 521 return readName(start, end, NULL) - start; |
| 561 } | 522 } |
| 562 | 523 |
| 563 static const unsigned char* readName(const unsigned char* start, const unsigned
char* end, SkPdfNativeObject* name, SkPdfAllocator* allocator) { | 524 static const unsigned char* readName(const unsigned char* start, const unsigned
char* end, |
| 525 SkPdfNativeObject* name, SkPdfAllocator* al
locator) { |
| 564 if (!allocator) { | 526 if (!allocator) { |
| 527 // TODO(edisonn): report error/warn/assert |
| 565 return end; | 528 return end; |
| 566 } | 529 } |
| 567 int outLength = readNameLength(start, end); | 530 int outLength = readNameLength(start, end); |
| 568 // TODO(edisonn): optimize the allocation, don't allocate new string, but pu
t it in a preallocated buffer | |
| 569 unsigned char* out = (unsigned char*)allocator->alloc(outLength); | 531 unsigned char* out = (unsigned char*)allocator->alloc(outLength); |
| 570 const unsigned char* now = readName(start, end, out); | 532 const unsigned char* now = readName(start, end, out); |
| 571 SkPdfNativeObject::makeName(out, out + outLength, name); | 533 SkPdfNativeObject::makeName(out, out + outLength, name); |
| 572 //PUT_TRACK_STREAM(start, now) | 534 //PUT_TRACK_STREAM(start, now) |
| 573 TRACE_NAME(out, out + outLength); | 535 TRACE_NAME(out, out + outLength); |
| 574 return now; | 536 return now; |
| 575 } | 537 } |
| 576 | 538 |
| 577 // TODO(edisonn): pdf spec let Length to be an indirect object define after the
stream | 539 // TODO(edisonn): pdf spec let Length to be an indirect object define after the
stream |
| 578 // that makes for an interesting scenario, where the stream itself contains ends
tream, together | 540 // that makes for an interesting scenario, where the stream itself contains ends
tream, together |
| (...skipping 11 matching lines...) Expand all Loading... |
| 590 endobj | 552 endobj |
| 591 endstream | 553 endstream |
| 592 8 0 obj #real obj | 554 8 0 obj #real obj |
| 593 << 100 >> #real obj | 555 << 100 >> #real obj |
| 594 endobj | 556 endobj |
| 595 and it could get worse, with multiple object like this | 557 and it could get worse, with multiple object like this |
| 596 */ | 558 */ |
| 597 | 559 |
| 598 // right now implement the silly algorithm that assumes endstream is finishing t
he stream | 560 // right now implement the silly algorithm that assumes endstream is finishing t
he stream |
| 599 | 561 |
| 600 | 562 static const unsigned char* readStream(const unsigned char* start, const unsigne
d char* end, |
| 601 static const unsigned char* readStream(const unsigned char* start, const unsigne
d char* end, SkPdfNativeObject* dict, SkPdfNativeDoc* doc) { | 563 SkPdfNativeObject* dict, SkPdfNativeDoc*
doc) { |
| 602 start = skipPdfWhiteSpaces(start, end); | 564 start = skipPdfWhiteSpaces(start, end); |
| 603 if (!(start[0] == 's' && start[1] == 't' && start[2] == 'r' && start[3] == '
e' && start[4] == 'a' && start[5] == 'm')) { | 565 if (!( start[0] == 's' && |
| 566 start[1] == 't' && |
| 567 start[2] == 'r' && |
| 568 start[3] == 'e' && |
| 569 start[4] == 'a' && |
| 570 start[5] == 'm')) { |
| 604 // no stream. return. | 571 // no stream. return. |
| 605 return start; | 572 return start; |
| 606 } | 573 } |
| 607 | 574 |
| 608 start += 6; // strlen("stream") | 575 start += 6; // strlen("stream") |
| 609 if (start[0] == kCR_PdfWhiteSpace && start[1] == kLF_PdfWhiteSpace) { | 576 if (start[0] == kCR_PdfWhiteSpace && start[1] == kLF_PdfWhiteSpace) { |
| 610 start += 2; | 577 start += 2; |
| 611 } else if (start[0] == kLF_PdfWhiteSpace) { | 578 } else if (start[0] == kLF_PdfWhiteSpace) { |
| 612 start += 1; | 579 start += 1; |
| 613 } else if (isPdfWhiteSpace(start[0])) { | 580 } else if (isPdfWhiteSpace(start[0])) { |
| 614 start += 1; | 581 start += 1; |
| 615 } else { | 582 } else { |
| 616 // TODO(edisonn): warn it should be isPdfDelimiter(start[0])) ? | 583 // TODO(edisonn): warn it should be isPdfDelimiter(start[0])) ? |
| 617 // TODO(edisonn): warning? | |
| 618 } | 584 } |
| 619 | 585 |
| 620 SkPdfStreamCommonDictionary* stream = (SkPdfStreamCommonDictionary*) dict; | 586 SkPdfStreamCommonDictionary* stream = (SkPdfStreamCommonDictionary*) dict; |
| 621 // TODO(edisonn): load Length | 587 // TODO(edisonn): load Length |
| 622 int64_t length = -1; | 588 int64_t length = -1; |
| 623 | 589 |
| 624 // TODO(edisonn): very basic implementation | 590 // TODO(edisonn): very basic implementation |
| 625 if (stream->has_Length() && stream->Length(doc) > 0) { | 591 if (stream->has_Length() && stream->Length(doc) > 0) { |
| 626 length = stream->Length(doc); | 592 length = stream->Length(doc); |
| 627 } | 593 } |
| 628 | 594 |
| 629 // TODO(edisonn): laod external streams | 595 // TODO(edisonn): load external streams |
| 630 // TODO(edisonn): look at the last filter, to determione how to deal with po
ssible issue | 596 // TODO(edisonn): look at the last filter, to determine how to deal with pos
sible parsing |
| 631 | 597 // issues. The last filter can have special rules to terminate a stream, whi
ch we could |
| 598 // use to determine end of stream. |
| 632 | 599 |
| 633 if (length >= 0) { | 600 if (length >= 0) { |
| 634 const unsigned char* endstream = start + length; | 601 const unsigned char* endstream = start + length; |
| 635 | 602 |
| 636 if (endstream[0] == kCR_PdfWhiteSpace && endstream[1] == kLF_PdfWhiteSpa
ce) { | 603 if (endstream[0] == kCR_PdfWhiteSpace && endstream[1] == kLF_PdfWhiteSpa
ce) { |
| 637 endstream += 2; | 604 endstream += 2; |
| 638 } else if (endstream[0] == kLF_PdfWhiteSpace) { | 605 } else if (endstream[0] == kLF_PdfWhiteSpace) { |
| 639 endstream += 1; | 606 endstream += 1; |
| 640 } | 607 } |
| 641 | 608 |
| 642 if (strncmp((const char*)endstream, "endstream", strlen("endstream")) !=
0) { | 609 if (strncmp((const char*)endstream, "endstream", strlen("endstream")) !=
0) { |
| 643 length = -1; | 610 length = -1; |
| 644 } | 611 } |
| 645 } | 612 } |
| 646 | 613 |
| 647 if (length < 0) { | 614 if (length < 0) { |
| 648 // scan the buffer, until we find first endstream | 615 // scan the buffer, until we find first endstream |
| 649 // TODO(edisonn): all buffers must have a 0 at the end now, | 616 // TODO(edisonn): all buffers must have a 0 at the end now, |
| 650 const unsigned char* endstream = (const unsigned char*)strrstrk((char*)s
tart, (char*)end, "endstream"); | 617 const unsigned char* endstream = (const unsigned char*)strrstrk((char*)s
tart, (char*)end, |
| 618 "endstre
am"); |
| 651 | 619 |
| 652 if (endstream) { | 620 if (endstream) { |
| 653 length = endstream - start; | 621 length = endstream - start; |
| 654 if (*(endstream-1) == kLF_PdfWhiteSpace) length--; | 622 if (*(endstream-1) == kLF_PdfWhiteSpace) length--; |
| 655 if (*(endstream-2) == kCR_PdfWhiteSpace) length--; | 623 if (*(endstream-2) == kCR_PdfWhiteSpace) length--; |
| 656 } | 624 } |
| 657 } | 625 } |
| 658 if (length >= 0) { | 626 if (length >= 0) { |
| 659 const unsigned char* endstream = start + length; | 627 const unsigned char* endstream = start + length; |
| 660 | 628 |
| 661 if (endstream[0] == kCR_PdfWhiteSpace && endstream[1] == kLF_PdfWhiteSpa
ce) { | 629 if (endstream[0] == kCR_PdfWhiteSpace && endstream[1] == kLF_PdfWhiteSpa
ce) { |
| 662 endstream += 2; | 630 endstream += 2; |
| 663 } else if (endstream[0] == kLF_PdfWhiteSpace) { | 631 } else if (endstream[0] == kLF_PdfWhiteSpace) { |
| 664 endstream += 1; | 632 endstream += 1; |
| 665 } | 633 } |
| 666 | 634 |
| 667 // TODO(edisonn): verify the next bytes are "endstream" | 635 // TODO(edisonn): verify the next bytes are "endstream" |
| 668 | 636 |
| 669 endstream += strlen("endstream"); | 637 endstream += strlen("endstream"); |
| 670 // TODO(edisonn): Assert? report error/warning? | 638 // TODO(edisonn): Assert? report error/warning? |
| 671 dict->addStream(start, (size_t)length); | 639 dict->addStream(start, (size_t)length); |
| 672 return endstream; | 640 return endstream; |
| 673 } | 641 } |
| 674 return start; | 642 return start; |
| 675 } | 643 } |
| 676 | 644 |
| 677 static const unsigned char* readInlineImageStream(const unsigned char* start, co
nst unsigned char* end, SkPdfImageDictionary* inlineImage, SkPdfNativeDoc* doc)
{ | 645 static const unsigned char* readInlineImageStream(const unsigned char* start, |
| 646 const unsigned char* end, |
| 647 SkPdfImageDictionary* inlineIm
age, |
| 648 SkPdfNativeDoc* doc) { |
| 678 // We already processed ID keyword, and we should be positioned immediately
after it | 649 // We already processed ID keyword, and we should be positioned immediately
after it |
| 679 | 650 |
| 680 // TODO(edisonn): security: read after end check, or make buffers with extra
2 bytes | 651 // TODO(edisonn): security: either make all streams to have extra 2 bytes at
the end, |
| 652 // instead of this if. |
| 653 //if (end - start <= 2) { |
| 654 // // TODO(edisonn): warning? |
| 655 // return end; // but can we have a pixel image encoded in 1-2 bytes? |
| 656 //} |
| 657 |
| 681 if (start[0] == kCR_PdfWhiteSpace && start[1] == kLF_PdfWhiteSpace) { | 658 if (start[0] == kCR_PdfWhiteSpace && start[1] == kLF_PdfWhiteSpace) { |
| 682 start += 2; | 659 start += 2; |
| 683 } else if (start[0] == kLF_PdfWhiteSpace) { | 660 } else if (start[0] == kLF_PdfWhiteSpace) { |
| 684 start += 1; | 661 start += 1; |
| 685 } else if (isPdfWhiteSpace(start[0])) { | 662 } else if (isPdfWhiteSpace(start[0])) { |
| 686 start += 1; | 663 start += 1; |
| 687 } else { | 664 } else { |
| 688 SkASSERT(isPdfDelimiter(start[0])); | 665 SkASSERT(isPdfDelimiter(start[0])); |
| 689 // TODO(edisonn): warning? | 666 // TODO(edisonn): warning? |
| 690 } | 667 } |
| 691 | 668 |
| 692 const unsigned char* endstream = (const unsigned char*)strrstrk((char*)start
, (char*)end, "EI"); | 669 const unsigned char* endstream = (const unsigned char*)strrstrk((char*)start
, (char*)end, "EI"); |
| 693 const unsigned char* endEI = endstream ? endstream + 2 : NULL; // 2 == strl
en("EI") | 670 const unsigned char* endEI = endstream ? endstream + 2 : NULL; // 2 == strl
en("EI") |
| 694 | 671 |
| 695 if (endstream) { | 672 if (endstream) { |
| 696 int length = endstream - start; | 673 int length = endstream - start; |
| 697 if (*(endstream-1) == kLF_PdfWhiteSpace) length--; | 674 if (*(endstream-1) == kLF_PdfWhiteSpace) length--; |
| 698 if (*(endstream-2) == kCR_PdfWhiteSpace) length--; | 675 if (*(endstream-2) == kCR_PdfWhiteSpace) length--; |
| 699 inlineImage->addStream(start, (size_t)length); | 676 inlineImage->addStream(start, (size_t)length); |
| 700 } else { | 677 } else { |
| 701 // TODO(edisonn): report error in inline image stream (ID-EI) section | 678 // TODO(edisonn): report error in inline image stream (ID-EI) section |
| 702 // TODO(edisonn): based on filter, try to ignore a missing EI, and read
data properly | 679 // TODO(edisonn): based on filter, try to ignore a missing EI, and read
data properly |
| 703 return end; | 680 return end; |
| 704 } | 681 } |
| 705 return endEI; | 682 return endEI; |
| 706 } | 683 } |
| 707 | 684 |
| 708 static const unsigned char* readDictionary(const unsigned char* start, const uns
igned char* end, SkPdfNativeObject* dict, SkPdfAllocator* allocator, SkPdfNative
Doc* doc) { | 685 static const unsigned char* readDictionary(const unsigned char* start, const uns
igned char* end, |
| 686 SkPdfNativeObject* dict, |
| 687 SkPdfAllocator* allocator, SkPdfNativ
eDoc* doc) { |
| 709 if (allocator == NULL) { | 688 if (allocator == NULL) { |
| 710 // TODO(edisonn): report/warning error | 689 // TODO(edisonn): report/warning error |
| 711 return end; | 690 return end; |
| 712 } | 691 } |
| 713 SkPdfNativeObject::makeEmptyDictionary(dict); | 692 SkPdfNativeObject::makeEmptyDictionary(dict); |
| 714 // PUT_TRACK_STREAM(dict, start, start) | 693 // PUT_TRACK_STREAM(dict, start, start) |
| 715 | 694 |
| 716 start = skipPdfWhiteSpaces(start, end); | 695 start = skipPdfWhiteSpaces(start, end); |
| 717 SkPdfAllocator tmpStorage; // keys will be stored in dict, we can free them
immediately after set. | 696 SkPdfAllocator tmpStorage; // keys will be stored in dict, we can free them
after set. |
| 718 | 697 |
| 719 while (start < end && *start == kNamed_PdfDelimiter) { | 698 while (start < end && *start == kNamed_PdfDelimiter) { |
| 720 SkPdfNativeObject key; | 699 SkPdfNativeObject key; |
| 721 //*start = '\0'; | 700 //*start = '\0'; |
| 722 start++; | 701 start++; |
| 723 start = readName(start, end, &key, &tmpStorage); | 702 start = readName(start, end, &key, &tmpStorage); |
| 724 start = skipPdfWhiteSpaces(start, end); | 703 start = skipPdfWhiteSpaces(start, end); |
| 725 | 704 |
| 726 if (start < end) { | 705 if (start < end) { |
| 727 SkPdfNativeObject* value = allocator->allocObject(); | 706 SkPdfNativeObject* value = allocator->allocObject(); |
| 728 start = nextObject(start, end, value, allocator, doc); | 707 start = nextObject(start, end, value, allocator, doc); |
| 729 | 708 |
| 730 start = skipPdfWhiteSpaces(start, end); | 709 start = skipPdfWhiteSpaces(start, end); |
| 731 | 710 |
| 732 if (start < end) { | 711 if (start < end) { |
| 733 // seems we have an indirect reference | 712 // We should have an indirect reference |
| 734 if (isPdfDigit(*start)) { | 713 if (isPdfDigit(*start)) { |
| 735 SkPdfNativeObject generation; | 714 SkPdfNativeObject generation; |
| 736 start = nextObject(start, end, &generation, allocator, doc); | 715 start = nextObject(start, end, &generation, allocator, doc); |
| 737 | 716 |
| 738 SkPdfNativeObject keywordR; | 717 SkPdfNativeObject keywordR; |
| 739 start = nextObject(start, end, &keywordR, allocator, doc); | 718 start = nextObject(start, end, &keywordR, allocator, doc); |
| 740 | 719 |
| 741 if (value->isInteger() && generation.isInteger() && keywordR
.isKeywordReference()) { | 720 if (value->isInteger() && generation.isInteger() && |
| 721 keywordR.isKeywordReference()) { |
| 742 int64_t id = value->intValue(); | 722 int64_t id = value->intValue(); |
| 743 SkPdfNativeObject::resetAndMakeReference((unsigned int)i
d, (unsigned int)generation.intValue(), value); | 723 SkPdfNativeObject::resetAndMakeReference( |
| 724 (unsigned int)id, |
| 725 (unsigned int)generation.intValue(), |
| 726 value); |
| 744 // PUT_TRACK_PARAMETERS_OBJ2(value, &generation) | 727 // PUT_TRACK_PARAMETERS_OBJ2(value, &generation) |
| 745 dict->set(&key, value); | 728 dict->set(&key, value); |
| 746 } else { | 729 } else { |
| 747 // error, ignore | 730 // TODO(edisonn) error?, ignore it for now. |
| 748 dict->set(&key, value); | 731 dict->set(&key, value); |
| 749 } | 732 } |
| 750 } else { | 733 } else { |
| 751 // next elem is not a digit, but it might not be / either! | 734 // next elem is not a digit, but it might not be / either! |
| 752 dict->set(&key, value); | 735 dict->set(&key, value); |
| 753 } | 736 } |
| 754 } else { | 737 } else { |
| 755 // /key >> | 738 // /key >> |
| 756 dict->set(&key, value); | 739 dict->set(&key, value); |
| 757 return end; | 740 return end; |
| 758 } | 741 } |
| 759 start = skipPdfWhiteSpaces(start, end); | 742 start = skipPdfWhiteSpaces(start, end); |
| 760 } else { | 743 } else { |
| 761 dict->set(&key, &SkPdfNativeObject::kNull); | 744 dict->set(&key, &SkPdfNativeObject::kNull); |
| 762 return end; | 745 return end; |
| 763 } | 746 } |
| 764 } | 747 } |
| 765 | 748 |
| 766 // TODO(edisonn): options to ignore these errors | |
| 767 | |
| 768 // now we should expect >> | 749 // now we should expect >> |
| 769 start = skipPdfWhiteSpaces(start, end); | 750 start = skipPdfWhiteSpaces(start, end); |
| 770 if (*start != kClosedInequityBracket_PdfDelimiter) { | 751 if (*start != kClosedInequityBracket_PdfDelimiter) { |
| 771 // TODO(edisonn): report/warning | 752 // TODO(edisonn): report/warning |
| 772 } | 753 } |
| 773 //*start = '\0'; | 754 |
| 774 start++; // skip > | 755 start++; // skip > |
| 775 if (*start != kClosedInequityBracket_PdfDelimiter) { | 756 if (*start != kClosedInequityBracket_PdfDelimiter) { |
| 776 // TODO(edisonn): report/warning | 757 // TODO(edisonn): report/warning |
| 777 } | 758 } |
| 778 //*start = '\0'; | 759 |
| 779 start++; // skip > | 760 start++; // skip > |
| 780 | 761 |
| 781 //STORE_TRACK_PARAMETER_OFFSET_END(dict,start); | 762 //STORE_TRACK_PARAMETER_OFFSET_END(dict,start); |
| 782 | 763 |
| 783 start = readStream(start, end, dict, doc); | 764 start = readStream(start, end, dict, doc); |
| 784 | 765 |
| 785 return start; | 766 return start; |
| 786 } | 767 } |
| 787 | 768 |
| 788 const unsigned char* nextObject(const unsigned char* start, const unsigned char*
end, SkPdfNativeObject* token, SkPdfAllocator* allocator, SkPdfNativeDoc* doc)
{ | 769 const unsigned char* nextObject(const unsigned char* start, const unsigned char*
end, |
| 770 SkPdfNativeObject* token, |
| 771 SkPdfAllocator* allocator, SkPdfNativeDoc* doc)
{ |
| 789 const unsigned char* current; | 772 const unsigned char* current; |
| 790 | 773 |
| 791 // skip white spaces | 774 // skip white spaces |
| 792 start = skipPdfWhiteSpaces(start, end); | 775 start = skipPdfWhiteSpaces(start, end); |
| 793 | 776 |
| 794 if (start >= end) { | 777 if (start >= end) { |
| 795 return end; | 778 return end; |
| 796 } | 779 } |
| 797 | 780 |
| 798 current = endOfPdfToken(start, end); | 781 current = endOfPdfToken(start, end); |
| 799 | 782 |
| 800 // no token, len would be 0 | 783 // no token, len would be 0 |
| 801 if (current == start || current == end) { | 784 if (current == start || current == end) { |
| 802 return end; | 785 return end; |
| 803 } | 786 } |
| 804 | 787 |
| 805 int tokenLen = current - start; | 788 int tokenLen = current - start; |
| 806 | 789 |
| 807 if (tokenLen == 1) { | 790 if (tokenLen == 1) { |
| 808 // start array | 791 // start array |
| 809 switch (*start) { | 792 switch (*start) { |
| 810 case kOpenedSquareBracket_PdfDelimiter: | 793 case kOpenedSquareBracket_PdfDelimiter: |
| 811 //*start = '\0'; | |
| 812 return readArray(current, end, token, allocator, doc); | 794 return readArray(current, end, token, allocator, doc); |
| 813 | 795 |
| 814 case kOpenedRoundBracket_PdfDelimiter: | 796 case kOpenedRoundBracket_PdfDelimiter: |
| 815 //*start = '\0'; | |
| 816 return readString(start + 1, end, token, allocator); | 797 return readString(start + 1, end, token, allocator); |
| 817 | 798 |
| 818 case kOpenedInequityBracket_PdfDelimiter: | 799 case kOpenedInequityBracket_PdfDelimiter: |
| 819 //*start = '\0'; | |
| 820 if (end > start + 1 && start[1] == kOpenedInequityBracket_PdfDel
imiter) { | 800 if (end > start + 1 && start[1] == kOpenedInequityBracket_PdfDel
imiter) { |
| 821 //start[1] = '\0'; // optional | |
| 822 // TODO(edisonn): pass here the length somehow? | 801 // TODO(edisonn): pass here the length somehow? |
| 823 return readDictionary(start + 2, end, token, allocator, doc)
; // skip << | 802 return readDictionary(start + 2, end, token, allocator, doc)
; // skip << |
| 824 } else { | 803 } else { |
| 825 return readHexString(start + 1, end, token, allocator); //
skip < | 804 return readHexString(start + 1, end, token, allocator); //
skip < |
| 826 } | 805 } |
| 827 | 806 |
| 828 case kNamed_PdfDelimiter: | 807 case kNamed_PdfDelimiter: |
| 829 //*start = '\0'; | |
| 830 return readName(start + 1, end, token, allocator); | 808 return readName(start + 1, end, token, allocator); |
| 831 | 809 |
| 832 // TODO(edisonn): what to do curly brackets? read spec! | 810 // TODO(edisonn): what to do curly brackets? |
| 833 case kOpenedCurlyBracket_PdfDelimiter: | 811 case kOpenedCurlyBracket_PdfDelimiter: |
| 834 default: | 812 default: |
| 835 break; | 813 break; |
| 836 } | 814 } |
| 837 | 815 |
| 838 SkASSERT(!isPdfWhiteSpace(*start)); | 816 SkASSERT(!isPdfWhiteSpace(*start)); |
| 839 if (isPdfDelimiter(*start)) { | 817 if (isPdfDelimiter(*start)) { |
| 840 // TODO(edisonn): how stream ] } > ) will be handled? | 818 // TODO(edisonn): how unexpected stream ] } > ) will be handled? |
| 841 // for now ignore, and it will become a keyword to be ignored | 819 // for now ignore, and it will become a keyword to be ignored |
| 842 } | 820 } |
| 843 } | 821 } |
| 844 | 822 |
| 845 if (tokenLen == 4 && start[0] == 'n' && start[1] == 'u' && start[2] == 'l' &
& start[3] == 'l') { | 823 if (tokenLen == 4 && start[0] == 'n' && start[1] == 'u' && start[2] == 'l' &
& start[3] == 'l') { |
| 846 SkPdfNativeObject::makeNull(token); | 824 SkPdfNativeObject::makeNull(token); |
| 847 // PUT_TRACK_STREAM(start, start + 4) | 825 // PUT_TRACK_STREAM(start, start + 4) |
| 848 return current; | 826 return current; |
| 849 } | 827 } |
| 850 | 828 |
| 851 if (tokenLen == 4 && start[0] == 't' && start[1] == 'r' && start[2] == 'u' &
& start[3] == 'e') { | 829 if (tokenLen == 4 && start[0] == 't' && start[1] == 'r' && start[2] == 'u' &
& start[3] == 'e') { |
| 852 SkPdfNativeObject::makeBoolean(true, token); | 830 SkPdfNativeObject::makeBoolean(true, token); |
| 853 // PUT_TRACK_STREAM(start, start + 4) | 831 // PUT_TRACK_STREAM(start, start + 4) |
| 854 return current; | 832 return current; |
| 855 } | 833 } |
| 856 | 834 |
| 857 if (tokenLen == 5 && start[0] == 'f' && start[1] == 'a' && start[2] == 'l' &
& start[3] == 's' && start[4] == 'e') { | 835 // TODO(edisonn): again, make all buffers have 5 extra bytes |
| 836 if (tokenLen == 5 && start[0] == 'f' && |
| 837 start[1] == 'a' && |
| 838 start[2] == 'l' && |
| 839 start[3] == 's' && |
| 840 start[4] == 'e') { |
| 858 SkPdfNativeObject::makeBoolean(false, token); | 841 SkPdfNativeObject::makeBoolean(false, token); |
| 859 // PUT_TRACK_STREAM(start, start + 5) | 842 // PUT_TRACK_STREAM(start, start + 5) |
| 860 return current; | 843 return current; |
| 861 } | 844 } |
| 862 | 845 |
| 863 if (isPdfNumeric(*start)) { | 846 if (isPdfNumeric(*start)) { |
| 864 SkPdfNativeObject::makeNumeric(start, current, token); | 847 SkPdfNativeObject::makeNumeric(start, current, token); |
| 865 // PUT_TRACK_STREAM(start, current) | 848 // PUT_TRACK_STREAM(start, current) |
| 866 } else { | 849 } else { |
| 867 SkPdfNativeObject::makeKeyword(start, current, token); | 850 SkPdfNativeObject::makeKeyword(start, current, token); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 895 if (fCurrentUsed >= BUFFER_SIZE) { | 878 if (fCurrentUsed >= BUFFER_SIZE) { |
| 896 fHistory.push(fCurrent); | 879 fHistory.push(fCurrent); |
| 897 fCurrent = allocBlock(); | 880 fCurrent = allocBlock(); |
| 898 fCurrentUsed = 0; | 881 fCurrentUsed = 0; |
| 899 fSizeInBytes += sizeof(SkPdfNativeObject*); | 882 fSizeInBytes += sizeof(SkPdfNativeObject*); |
| 900 } | 883 } |
| 901 fCurrentUsed++; | 884 fCurrentUsed++; |
| 902 return &fCurrent[fCurrentUsed - 1]; | 885 return &fCurrent[fCurrentUsed - 1]; |
| 903 } | 886 } |
| 904 | 887 |
| 905 // TODO(edisonn): perf: do no copy the buffers, but use them, and mark cache the
result, so there is no need of a second pass | 888 // TODO(edisonn): perf: do no copy the buffers, but reuse them, and mark cache t
he result, |
| 906 SkPdfNativeTokenizer::SkPdfNativeTokenizer(SkPdfNativeObject* objWithStream, SkP
dfAllocator* allocator, SkPdfNativeDoc* doc) : fDoc(doc), fAllocator(allocator),
fUncompressedStream(NULL), fUncompressedStreamEnd(NULL), fEmpty(false), fHasPut
Back(false) { | 889 // so there is no need of a second pass |
| 890 SkPdfNativeTokenizer::SkPdfNativeTokenizer(SkPdfNativeObject* objWithStream, |
| 891 SkPdfAllocator* allocator, |
| 892 SkPdfNativeDoc* doc) |
| 893 : fDoc(doc) |
| 894 , fAllocator(allocator) |
| 895 , fUncompressedStream(NULL) |
| 896 , fUncompressedStreamEnd(NULL) |
| 897 , fEmpty(false) |
| 898 , fHasPutBack(false) { |
| 907 const unsigned char* buffer = NULL; | 899 const unsigned char* buffer = NULL; |
| 908 size_t len = 0; | 900 size_t len = 0; |
| 909 objWithStream->GetFilteredStreamRef(&buffer, &len); | 901 objWithStream->GetFilteredStreamRef(&buffer, &len); |
| 910 // TODO(edisonn): hack, find end of object | 902 // TODO(edisonn): really bad hack, find end of object (endobj might be in a
comment!) |
| 903 // we need to do now for perf, and our generated pdfs do not have comments, |
| 904 // but we need to remove this hack for pdfs in the wild |
| 911 char* endobj = strrstrk((char*)buffer, (char*)buffer + len, "endobj"); | 905 char* endobj = strrstrk((char*)buffer, (char*)buffer + len, "endobj"); |
| 912 if (endobj) { | 906 if (endobj) { |
| 913 len = endobj - (char*)buffer + strlen("endobj"); | 907 len = endobj - (char*)buffer + strlen("endobj"); |
| 914 } | 908 } |
| 915 fUncompressedStreamStart = fUncompressedStream = buffer; | 909 fUncompressedStreamStart = fUncompressedStream = buffer; |
| 916 fUncompressedStreamEnd = fUncompressedStream + len; | 910 fUncompressedStreamEnd = fUncompressedStream + len; |
| 917 } | 911 } |
| 918 | 912 |
| 919 SkPdfNativeTokenizer::SkPdfNativeTokenizer(const unsigned char* buffer, int len,
SkPdfAllocator* allocator, SkPdfNativeDoc* doc) : fDoc(doc), fAllocator(allocat
or), fEmpty(false), fHasPutBack(false) { | 913 SkPdfNativeTokenizer::SkPdfNativeTokenizer(const unsigned char* buffer, int len, |
| 920 // TODO(edisonn): hack, find end of object | 914 SkPdfAllocator* allocator, |
| 915 SkPdfNativeDoc* doc) : fDoc(doc) |
| 916 , fAllocator(all
ocator) |
| 917 , fEmpty(false) |
| 918 , fHasPutBack(fa
lse) { |
| 919 // TODO(edisonn): really bad hack, find end of object (endobj might be in a
comment!) |
| 920 // we need to do now for perf, and our generated pdfs do not have comments, |
| 921 // but we need to remove this hack for pdfs in the wild |
| 921 char* endobj = strrstrk((char*)buffer, (char*)buffer + len, "endobj"); | 922 char* endobj = strrstrk((char*)buffer, (char*)buffer + len, "endobj"); |
| 922 if (endobj) { | 923 if (endobj) { |
| 923 len = endobj - (char*)buffer + strlen("endobj"); | 924 len = endobj - (char*)buffer + strlen("endobj"); |
| 924 } | 925 } |
| 925 fUncompressedStreamStart = fUncompressedStream = buffer; | 926 fUncompressedStreamStart = fUncompressedStream = buffer; |
| 926 fUncompressedStreamEnd = fUncompressedStream + len; | 927 fUncompressedStreamEnd = fUncompressedStream + len; |
| 927 } | 928 } |
| 928 | 929 |
| 929 SkPdfNativeTokenizer::~SkPdfNativeTokenizer() { | 930 SkPdfNativeTokenizer::~SkPdfNativeTokenizer() { |
| 930 } | 931 } |
| 931 | 932 |
| 932 bool SkPdfNativeTokenizer::readTokenCore(PdfToken* token) { | 933 bool SkPdfNativeTokenizer::readTokenCore(PdfToken* token) { |
| 933 SkPdfNativeObject obj; | |
| 934 #ifdef PDF_TRACE_READ_TOKEN | 934 #ifdef PDF_TRACE_READ_TOKEN |
| 935 static int read_op = 0; | 935 static int read_op = 0; |
| 936 #endif | 936 #endif |
| 937 |
| 937 token->fKeyword = NULL; | 938 token->fKeyword = NULL; |
| 938 token->fObject = NULL; | 939 token->fObject = NULL; |
| 939 | 940 |
| 940 fUncompressedStream = skipPdfWhiteSpaces(fUncompressedStream, fUncompressedS
treamEnd); | 941 fUncompressedStream = skipPdfWhiteSpaces(fUncompressedStream, fUncompressedS
treamEnd); |
| 941 if (fUncompressedStream >= fUncompressedStreamEnd) { | 942 if (fUncompressedStream >= fUncompressedStreamEnd) { |
| 942 return false; | 943 return false; |
| 943 } | 944 } |
| 944 | 945 |
| 946 SkPdfNativeObject obj; |
| 945 fUncompressedStream = nextObject(fUncompressedStream, fUncompressedStreamEnd
, &obj, fAllocator, fDoc); | 947 fUncompressedStream = nextObject(fUncompressedStream, fUncompressedStreamEnd
, &obj, fAllocator, fDoc); |
| 946 // PUT_TRACK_STREAM_ARGS_EXPL2(fStreamId, fUncompressedStreamStart) | 948 // PUT_TRACK_STREAM_ARGS_EXPL2(fStreamId, fUncompressedStreamStart) |
| 947 | 949 |
| 948 // If it is a keyword, we will only get the pointer of the string | 950 // If it is a keyword, we will only get the pointer of the string. |
| 949 if (obj.type() == SkPdfNativeObject::kKeyword_PdfObjectType) { | 951 if (obj.type() == SkPdfNativeObject::kKeyword_PdfObjectType) { |
| 950 token->fKeyword = obj.c_str(); | 952 token->fKeyword = obj.c_str(); |
| 951 token->fKeywordLength = obj.lenstr(); | 953 token->fKeywordLength = obj.lenstr(); |
| 952 token->fType = kKeyword_TokenType; | 954 token->fType = kKeyword_TokenType; |
| 953 } else { | 955 } else { |
| 954 SkPdfNativeObject* pobj = fAllocator->allocObject(); | 956 SkPdfNativeObject* pobj = fAllocator->allocObject(); |
| 955 *pobj = obj; | 957 *pobj = obj; |
| 956 token->fObject = pobj; | 958 token->fObject = pobj; |
| 957 token->fType = kObject_TokenType; | 959 token->fType = kObject_TokenType; |
| 958 } | 960 } |
| 959 | 961 |
| 960 #ifdef PDF_TRACE_READ_TOKEN | 962 #ifdef PDF_TRACE_READ_TOKEN |
| 961 read_op++; | 963 read_op++; |
| 962 #if 0 | 964 #if 0 |
| 963 if (548 == read_op) { | 965 if (548 == read_op) { |
| 964 printf("break;\n"); | 966 printf("break;\n"); |
| 965 } | 967 } |
| 966 #endif | 968 #endif |
| 967 printf("%i READ %s %s\n", read_op, token->fType == kKeyword_TokenType ? "Key
word" : "Object", token->fKeyword ? SkString(token->fKeyword, token->fKeywordLen
gth).c_str() : token->fObject->toString().c_str()); | 969 printf("%i READ %s %s\n", read_op, token->fType == kKeyword_TokenType ? "Key
word" : "Object", |
| 970 token->fKeyword ? SkString(token->fKeyword, token->fKeywordLength).c_
str() : |
| 971 token->fObject->toString().c_str()); |
| 968 #endif | 972 #endif |
| 969 | 973 |
| 970 return true; | 974 return true; |
| 971 } | 975 } |
| 972 | 976 |
| 973 void SkPdfNativeTokenizer::PutBack(PdfToken token) { | 977 void SkPdfNativeTokenizer::PutBack(PdfToken token) { |
| 974 SkASSERT(!fHasPutBack); | 978 SkASSERT(!fHasPutBack); |
| 975 fHasPutBack = true; | 979 fHasPutBack = true; |
| 976 fPutBack = token; | 980 fPutBack = token; |
| 977 #ifdef PDF_TRACE_READ_TOKEN | 981 #ifdef PDF_TRACE_READ_TOKEN |
| 978 printf("PUT_BACK %s %s\n", token.fType == kKeyword_TokenType ? "Keyword" : "
Object", token.fKeyword ? SkString(token.fKeyword, token.fKeywordLength).c_str()
: token.fObject->toString().c_str()); | 982 printf("PUT_BACK %s %s\n", token.fType == kKeyword_TokenType ? "Keyword" : "
Object", |
| 983 token.fKeyword ? SkString(token.fKeyword, token.fKeywordLength).c_str
() : |
| 984 token.fObject->toString().c_str()); |
| 979 #endif | 985 #endif |
| 980 } | 986 } |
| 981 | 987 |
| 982 bool SkPdfNativeTokenizer::readToken(PdfToken* token) { | 988 bool SkPdfNativeTokenizer::readToken(PdfToken* token) { |
| 983 if (fHasPutBack) { | 989 if (fHasPutBack) { |
| 984 *token = fPutBack; | 990 *token = fPutBack; |
| 985 fHasPutBack = false; | 991 fHasPutBack = false; |
| 986 #ifdef PDF_TRACE_READ_TOKEN | 992 #ifdef PDF_TRACE_READ_TOKEN |
| 987 printf("READ_BACK %s %s\n", token->fType == kKeyword_TokenType ? "Keyword" :
"Object", token->fKeyword ? SkString(token->fKeyword, token->fKeywordLength).c_
str() : token->fObject->toString().c_str()); | 993 printf("READ_BACK %s %s\n", token->fType == kKeyword_TokenType ? "Keyword" :
"Object", |
| 994 token->fKeyword ? SkString(token->fKeyword, token->fKeywordLength).c_
str() : |
| 995 token->fObject->toString().c_str()); |
| 988 #endif | 996 #endif |
| 989 return true; | 997 return true; |
| 990 } | 998 } |
| 991 | 999 |
| 992 if (fEmpty) { | 1000 if (fEmpty) { |
| 993 #ifdef PDF_TRACE_READ_TOKEN | 1001 #ifdef PDF_TRACE_READ_TOKEN |
| 994 printf("EMPTY TOKENIZER\n"); | 1002 printf("EMPTY TOKENIZER\n"); |
| 995 #endif | 1003 #endif |
| 996 return false; | 1004 return false; |
| 997 } | 1005 } |
| 998 | 1006 |
| 999 return readTokenCore(token); | 1007 return readTokenCore(token); |
| 1000 } | 1008 } |
| 1001 | 1009 |
| 1002 #define DECLARE_PDF_NAME(longName) SkPdfName longName((char*)#longName) | 1010 #define DECLARE_PDF_NAME(longName) SkPdfName longName((char*)#longName) |
| 1003 | 1011 |
| 1004 // keys | 1012 // keys |
| 1005 DECLARE_PDF_NAME(BitsPerComponent); | 1013 DECLARE_PDF_NAME(BitsPerComponent); |
| 1006 DECLARE_PDF_NAME(ColorSpace); | 1014 DECLARE_PDF_NAME(ColorSpace); |
| 1007 DECLARE_PDF_NAME(Decode); | 1015 DECLARE_PDF_NAME(Decode); |
| 1008 DECLARE_PDF_NAME(DecodeParms); | 1016 DECLARE_PDF_NAME(DecodeParms); |
| 1009 DECLARE_PDF_NAME(Filter); | 1017 DECLARE_PDF_NAME(Filter); |
| 1010 DECLARE_PDF_NAME(Height); | 1018 DECLARE_PDF_NAME(Height); |
| 1011 DECLARE_PDF_NAME(ImageMask); | 1019 DECLARE_PDF_NAME(ImageMask); |
| 1012 DECLARE_PDF_NAME(Intent); // PDF 1.1 - the key, or the abreviations? | 1020 DECLARE_PDF_NAME(Intent); // PDF 1.1 - the key, or the abBreviations? |
| 1013 DECLARE_PDF_NAME(Interpolate); | 1021 DECLARE_PDF_NAME(Interpolate); |
| 1014 DECLARE_PDF_NAME(Width); | 1022 DECLARE_PDF_NAME(Width); |
| 1015 | 1023 |
| 1016 // values | 1024 // values |
| 1017 DECLARE_PDF_NAME(DeviceGray); | 1025 DECLARE_PDF_NAME(DeviceGray); |
| 1018 DECLARE_PDF_NAME(DeviceRGB); | 1026 DECLARE_PDF_NAME(DeviceRGB); |
| 1019 DECLARE_PDF_NAME(DeviceCMYK); | 1027 DECLARE_PDF_NAME(DeviceCMYK); |
| 1020 DECLARE_PDF_NAME(Indexed); | 1028 DECLARE_PDF_NAME(Indexed); |
| 1021 DECLARE_PDF_NAME(ASCIIHexDecode); | 1029 DECLARE_PDF_NAME(ASCIIHexDecode); |
| 1022 DECLARE_PDF_NAME(ASCII85Decode); | 1030 DECLARE_PDF_NAME(ASCII85Decode); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1072 | 1080 |
| 1073 SkPdfImageDictionary* SkPdfNativeTokenizer::readInlineImage() { | 1081 SkPdfImageDictionary* SkPdfNativeTokenizer::readInlineImage() { |
| 1074 // BI already processed | 1082 // BI already processed |
| 1075 fUncompressedStream = skipPdfWhiteSpaces(fUncompressedStream, fUncompressedS
treamEnd); | 1083 fUncompressedStream = skipPdfWhiteSpaces(fUncompressedStream, fUncompressedS
treamEnd); |
| 1076 if (fUncompressedStream >= fUncompressedStreamEnd) { | 1084 if (fUncompressedStream >= fUncompressedStreamEnd) { |
| 1077 return NULL; | 1085 return NULL; |
| 1078 } | 1086 } |
| 1079 | 1087 |
| 1080 SkPdfImageDictionary* inlineImage = (SkPdfImageDictionary*)fAllocator->alloc
Object(); | 1088 SkPdfImageDictionary* inlineImage = (SkPdfImageDictionary*)fAllocator->alloc
Object(); |
| 1081 SkPdfNativeObject::makeEmptyDictionary(inlineImage); | 1089 SkPdfNativeObject::makeEmptyDictionary(inlineImage); |
| 1082 // PUT_TRACK_STREAM_ARGS_EXPL(fStreamId, fUncompressedStream - fUncompresse
dStreamStart, fUncompressedStream - fUncompressedStreamStart) | 1090 // PUT_TRACK_STREAM_ARGS_EXPL(fStreamId, fUncompressedStream - fUncompresse
dStreamStart, |
| 1091 // fUncompressedStream - fUncompressedStreamStar
t) |
| 1083 | 1092 |
| 1084 while (fUncompressedStream < fUncompressedStreamEnd) { | 1093 while (fUncompressedStream < fUncompressedStreamEnd) { |
| 1085 SkPdfNativeObject* key = fAllocator->allocObject(); | 1094 SkPdfNativeObject* key = fAllocator->allocObject(); |
| 1086 fUncompressedStream = nextObject(fUncompressedStream, fUncompressedStrea
mEnd, key, fAllocator, fDoc); | 1095 fUncompressedStream = nextObject(fUncompressedStream, fUncompressedStrea
mEnd, key, |
| 1096 fAllocator, fDoc); |
| 1087 // PUT_TRACK_STREAM_ARGS_EXPL2(fStreamId, fUncompressedStreamStart)s | 1097 // PUT_TRACK_STREAM_ARGS_EXPL2(fStreamId, fUncompressedStreamStart)s |
| 1088 | 1098 |
| 1089 if (key->isKeyword() && key->lenstr() == 2 && key->c_str()[0] == 'I' &&
key->c_str()[1] == 'D') { // ID | 1099 if (key->isKeyword() && key->lenstr() == 2 && |
| 1090 fUncompressedStream = readInlineImageStream(fUncompressedStream, fUn
compressedStreamEnd, inlineImage, fDoc); | 1100 key->c_str()[0] == 'I' && key->c_str()[1] == 'D') { // ID |
| 1101 fUncompressedStream = readInlineImageStream(fUncompressedStream, fUn
compressedStreamEnd, |
| 1102 inlineImage, fDoc); |
| 1091 return inlineImage; | 1103 return inlineImage; |
| 1092 } else { | 1104 } else { |
| 1093 SkPdfNativeObject* obj = fAllocator->allocObject(); | 1105 SkPdfNativeObject* obj = fAllocator->allocObject(); |
| 1094 fUncompressedStream = nextObject(fUncompressedStream, fUncompressedS
treamEnd, obj, fAllocator, fDoc); | 1106 fUncompressedStream = nextObject(fUncompressedStream, fUncompressedS
treamEnd, obj, |
| 1107 fAllocator, fDoc); |
| 1095 // PUT_TRACK_STREAM_ARGS_EXPL2(fStreamId, fUncompressedStreamStart)
s | 1108 // PUT_TRACK_STREAM_ARGS_EXPL2(fStreamId, fUncompressedStreamStart)
s |
| 1096 // TODO(edisonn): perf maybe we should not expand abreviation like t
his | 1109 // TODO(edisonn): perf maybe we should not expand abBreviation like
this |
| 1097 inlineImage->set(inlineImageKeyAbbreviationExpand(key), | 1110 inlineImage->set(inlineImageKeyAbbreviationExpand(key), |
| 1098 inlineImageValueAbbreviationExpand(obj)); | 1111 inlineImageValueAbbreviationExpand(obj)); |
| 1099 } | 1112 } |
| 1100 } | 1113 } |
| 1101 // TODO(edisonn): report end of data with inline image without an EI | 1114 // TODO(edisonn): report end of data with inline image without an EI |
| 1102 return inlineImage; | 1115 return inlineImage; |
| 1103 } | 1116 } |
| OLD | NEW |