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 |