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 "SkPdfNativeTokenizer.h" | 8 #include "SkPdfNativeTokenizer.h" |
9 #include "SkPdfNativeObject.h" | 9 #include "SkPdfNativeObject.h" |
10 #include "SkPdfConfig.h" | 10 #include "SkPdfConfig.h" |
(...skipping 20 matching lines...) Expand all Loading... |
31 (isPdfWhiteSpaceOrPdfDelimiter(*(hayStart+needleLen)) || (haySta
rt+needleLen == hayEnd)) && | 31 (isPdfWhiteSpaceOrPdfDelimiter(*(hayStart+needleLen)) || (haySta
rt+needleLen == hayEnd)) && |
32 strncmp(hayStart, needle, needleLen) == 0) { | 32 strncmp(hayStart, needle, needleLen) == 0) { |
33 return hayStart; | 33 return hayStart; |
34 } | 34 } |
35 hayStart++; | 35 hayStart++; |
36 } | 36 } |
37 return NULL; | 37 return NULL; |
38 } | 38 } |
39 | 39 |
40 #ifdef PDF_TRACE_TOKENIZER | 40 #ifdef PDF_TRACE_TOKENIZER |
41 static void TRACE_INDENT(int level, const char* type) { | |
42 static int id = 0; | |
43 id++; | |
44 #if 0 | |
45 if (478613 == id) { | |
46 printf("break;\n"); | |
47 } | |
48 #endif | |
49 // all types should have 2 letters, so the text is alligned nicely | |
50 printf("\n%10i %15s: ", id, type); | |
51 for (int i = 0 ; i < level; i++) { | |
52 printf(" "); | |
53 } | |
54 } | |
55 | 41 |
56 static void TRACE_COMMENT(char ch) { | 42 static void TRACE_COMMENT(char ch) { |
57 printf("%c", ch); | 43 printf("%c", ch); |
58 } | 44 } |
59 | 45 |
60 static void TRACE_TK(char ch) { | 46 static void TRACE_TK(char ch) { |
61 printf("%c", ch); | 47 printf("%c", ch); |
62 } | 48 } |
63 | 49 |
64 static void TRACE_NAME(const unsigned char* start, const unsigned char* end) { | 50 static void TRACE_NAME(const unsigned char* start, const unsigned char* end) { |
(...skipping 14 matching lines...) Expand all Loading... |
79 | 65 |
80 static void TRACE_HEXSTRING(const unsigned char* start, const unsigned char* end
) { | 66 static void TRACE_HEXSTRING(const unsigned char* start, const unsigned char* end
) { |
81 while (start < end) { | 67 while (start < end) { |
82 printf("%c", *start); | 68 printf("%c", *start); |
83 start++; | 69 start++; |
84 } | 70 } |
85 printf("\n"); | 71 printf("\n"); |
86 } | 72 } |
87 | 73 |
88 #else | 74 #else |
89 #define TRACE_INDENT(level,type) | |
90 #define TRACE_COMMENT(ch) | 75 #define TRACE_COMMENT(ch) |
91 #define TRACE_TK(ch) | 76 #define TRACE_TK(ch) |
92 #define TRACE_NAME(start,end) | 77 #define TRACE_NAME(start,end) |
93 #define TRACE_STRING(start,end) | 78 #define TRACE_STRING(start,end) |
94 #define TRACE_HEXSTRING(start,end) | 79 #define TRACE_HEXSTRING(start,end) |
95 #endif | 80 #endif |
96 | 81 |
97 const unsigned char* skipPdfWhiteSpaces(int level, const unsigned char* start, c
onst unsigned char* end) { | 82 const unsigned char* skipPdfWhiteSpaces(const unsigned char* start, const unsign
ed char* end) { |
98 TRACE_INDENT(level, "White Space"); | |
99 while (start < end && (isPdfWhiteSpace(*start) || *start == kComment_PdfDeli
miter)) { | 83 while (start < end && (isPdfWhiteSpace(*start) || *start == kComment_PdfDeli
miter)) { |
100 TRACE_COMMENT(*start); | 84 TRACE_COMMENT(*start); |
101 if (*start == kComment_PdfDelimiter) { | 85 if (*start == kComment_PdfDelimiter) { |
102 // skip the comment until end of line | 86 // skip the comment until end of line |
103 while (start < end && !isPdfEOL(*start)) { | 87 while (start < end && !isPdfEOL(*start)) { |
104 //*start = '\0'; | 88 //*start = '\0'; |
105 start++; | 89 start++; |
106 TRACE_COMMENT(*start); | 90 TRACE_COMMENT(*start); |
107 } | 91 } |
108 } else { | 92 } else { |
109 //*start = '\0'; | 93 //*start = '\0'; |
110 start++; | 94 start++; |
111 } | 95 } |
112 } | 96 } |
113 return start; | 97 return start; |
114 } | 98 } |
115 | 99 |
116 // TODO(edisonn) '(' can be used, will it break the string a delimiter or space
inside () ? | 100 // TODO(edisonn) '(' can be used, will it break the string a delimiter or space
inside () ? |
117 const unsigned char* endOfPdfToken(int level, const unsigned char* start, const
unsigned char* end) { | 101 const unsigned char* endOfPdfToken(const unsigned char* start, const unsigned ch
ar* end) { |
118 //int opened brackets | |
119 //TODO(edisonn): what out for special chars, like \n, \032 | |
120 TRACE_INDENT(level, "Token"); | |
121 | |
122 SkASSERT(!isPdfWhiteSpace(*start)); | 102 SkASSERT(!isPdfWhiteSpace(*start)); |
123 | 103 |
124 if (start < end && isPdfDelimiter(*start)) { | 104 if (start < end && isPdfDelimiter(*start)) { |
125 TRACE_TK(*start); | 105 TRACE_TK(*start); |
126 start++; | 106 start++; |
127 return start; | 107 return start; |
128 } | 108 } |
129 | 109 |
130 while (start < end && !isPdfWhiteSpaceOrPdfDelimiter(*start)) { | 110 while (start < end && !isPdfWhiteSpaceOrPdfDelimiter(*start)) { |
131 TRACE_TK(*start); | 111 TRACE_TK(*start); |
132 start++; | 112 start++; |
133 } | 113 } |
134 return start; | 114 return start; |
135 } | 115 } |
136 | 116 |
137 // last elem has to be ] | 117 // last elem has to be ] |
138 static const unsigned char* readArray(int level, const unsigned char* start, con
st unsigned char* end, SkPdfNativeObject* array, SkPdfAllocator* allocator, SkPd
fNativeDoc* doc GET_TRACK_STREAM) { | 118 static const unsigned char* readArray(const unsigned char* start, const unsigned
char* end, SkPdfNativeObject* array, SkPdfAllocator* allocator, SkPdfNativeDoc*
doc) { |
139 SkPdfNativeObject::makeEmptyArray(array PUT_TRACK_STREAM(start, start)); | 119 SkPdfNativeObject::makeEmptyArray(array); |
| 120 // PUT_TRACK_STREAM(array, start, start) |
140 | 121 |
141 if (allocator == NULL) { | 122 if (allocator == NULL) { |
142 // TODO(edisonn): report/warning error | 123 // TODO(edisonn): report/warning error |
143 return end; | 124 return end; |
144 } | 125 } |
145 | 126 |
146 TRACE_INDENT(level, "Array"); | |
147 while (start < end) { | 127 while (start < end) { |
148 // skip white spaces | 128 // skip white spaces |
149 start = skipPdfWhiteSpaces(level + 1, start, end); | 129 start = skipPdfWhiteSpaces(start, end); |
150 | 130 |
151 const unsigned char* endOfToken = endOfPdfToken(level + 1, start, end); | 131 const unsigned char* endOfToken = endOfPdfToken(start, end); |
152 | 132 |
153 if (endOfToken == start) { | 133 if (endOfToken == start) { |
154 // TODO(edisonn): report error in pdf file (end of stream with ] for
end of aray | 134 // TODO(edisonn): report error in pdf file (end of stream with ] for
end of aray |
155 return start; | 135 return start; |
156 } | 136 } |
157 | 137 |
158 if (endOfToken == start + 1 && *start == kClosedSquareBracket_PdfDelimit
er) { | 138 if (endOfToken == start + 1 && *start == kClosedSquareBracket_PdfDelimit
er) { |
159 return endOfToken; | 139 return endOfToken; |
160 } | 140 } |
161 | 141 |
162 SkPdfNativeObject* newObj = allocator->allocObject(); | 142 SkPdfNativeObject* newObj = allocator->allocObject(); |
163 start = nextObject(level + 1, start, end, newObj, allocator, doc PUT_TRA
CK_STREAM_ARGS); | 143 start = nextObject(start, end, newObj, allocator, doc); |
164 // TODO(edisonn): perf/memory: put the variables on the stack, and flush
them on the array only when | 144 // TODO(edisonn): perf/memory: put the variables on the stack, and flush
them on the array only when |
165 // we are sure they are not references! | 145 // we are sure they are not references! |
166 if (newObj->isKeywordReference() && array->size() >= 2 && array->objAtAI
ndex(array->size() - 1)->isInteger() && array->objAtAIndex(array->size() - 2)->i
sInteger()) { | 146 if (newObj->isKeywordReference() && array->size() >= 2 && array->objAtAI
ndex(array->size() - 1)->isInteger() && array->objAtAIndex(array->size() - 2)->i
sInteger()) { |
167 SkPdfNativeObject* gen = array->removeLastInArray(); | 147 SkPdfNativeObject* gen = array->removeLastInArray(); |
168 SkPdfNativeObject* id = array->removeLastInArray(); | 148 SkPdfNativeObject* id = array->removeLastInArray(); |
169 | 149 |
170 SkPdfNativeObject::resetAndMakeReference((unsigned int)id->intValue(
), (unsigned int)gen->intValue(), newObj PUT_TRACK_PARAMETERS_OBJ2(id, newObj)); | 150 SkPdfNativeObject::resetAndMakeReference((unsigned int)id->intValue(
), (unsigned int)gen->intValue(), newObj); |
| 151 // newObj PUT_TRACK_PARAMETERS_OBJ2(id, newObj) - store end, as now |
171 | 152 |
172 } | 153 } |
173 array->appendInArray(newObj); | 154 array->appendInArray(newObj); |
174 } | 155 } |
175 // TODO(edisonn): report not reached, we should never get here | 156 // TODO(edisonn): report not reached, we should never get here |
176 // TODO(edisonn): there might be a bug here, enable an assert and run it on
files | 157 // TODO(edisonn): there might be a bug here, enable an assert and run it on
files |
177 // or it might be that the files were actually corrupted | 158 // or it might be that the files were actually corrupted |
178 return start; | 159 return start; |
179 } | 160 } |
180 | 161 |
181 // When we read strings we will rewrite the string so we will reuse the memory | 162 // When we read strings we will rewrite the string so we will reuse the memory |
182 // when we start to read the string, we already consumed the opened bracket | 163 // when we start to read the string, we already consumed the opened bracket |
183 | 164 |
184 // TODO(edisonn): space: add paramater, taht would report if we need to allocate
new buffer, or we can reuse the one we have | 165 // TODO(edisonn): space: add paramater, taht would report if we need to allocate
new buffer, or we can reuse the one we have |
185 | 166 |
186 static const unsigned char* readString(int level, const unsigned char* start, co
nst unsigned char* end, unsigned char* out) { | 167 static const unsigned char* readString(const unsigned char* start, const unsigne
d char* end, unsigned char* out) { |
187 TRACE_INDENT(level, "String"); | |
188 const unsigned char* in = start; | 168 const unsigned char* in = start; |
189 bool hasOut = (out != NULL); | 169 bool hasOut = (out != NULL); |
190 | 170 |
191 int openRoundBrackets = 1; | 171 int openRoundBrackets = 1; |
192 while (in < end) { | 172 while (in < end) { |
193 openRoundBrackets += ((*in) == kOpenedRoundBracket_PdfDelimiter); | 173 openRoundBrackets += ((*in) == kOpenedRoundBracket_PdfDelimiter); |
194 openRoundBrackets -= ((*in) == kClosedRoundBracket_PdfDelimiter); | 174 openRoundBrackets -= ((*in) == kClosedRoundBracket_PdfDelimiter); |
195 if (openRoundBrackets == 0) { | 175 if (openRoundBrackets == 0) { |
196 in++; // consumed ) | 176 in++; // consumed ) |
197 break; | 177 break; |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 } | 277 } |
298 } | 278 } |
299 | 279 |
300 if (hasOut) { | 280 if (hasOut) { |
301 return in; // consumed already ) at the end of the string | 281 return in; // consumed already ) at the end of the string |
302 } else { | 282 } else { |
303 return start + (out - (const unsigned char*)NULL); // return where the s
tring would end if we reuse the string | 283 return start + (out - (const unsigned char*)NULL); // return where the s
tring would end if we reuse the string |
304 } | 284 } |
305 } | 285 } |
306 | 286 |
307 static int readStringLength(int level, const unsigned char* start, const unsigne
d char* end) { | 287 static int readStringLength(const unsigned char* start, const unsigned char* end
) { |
308 return readString(level, start, end, NULL) - start; | 288 return readString(start, end, NULL) - start; |
309 } | 289 } |
310 | 290 |
311 static const unsigned char* readString(int level, const unsigned char* start, co
nst unsigned char* end, SkPdfNativeObject* str, SkPdfAllocator* allocator GET_TR
ACK_STREAM) { | 291 static const unsigned char* readString(const unsigned char* start, const unsigne
d char* end, SkPdfNativeObject* str, SkPdfAllocator* allocator) { |
312 if (!allocator) { | 292 if (!allocator) { |
313 return end; | 293 return end; |
314 } | 294 } |
315 int outLength = readStringLength(level, start, end); | 295 int outLength = readStringLength(start, end); |
316 // TODO(edisonn): optimize the allocation, don't allocate new string, but pu
t it in a preallocated buffer | 296 // TODO(edisonn): optimize the allocation, don't allocate new string, but pu
t it in a preallocated buffer |
317 unsigned char* out = (unsigned char*)allocator->alloc(outLength); | 297 unsigned char* out = (unsigned char*)allocator->alloc(outLength); |
318 const unsigned char* now = readString(level, start, end, out); | 298 const unsigned char* now = readString(start, end, out); |
319 SkPdfNativeObject::makeString(out, out + outLength, str PUT_TRACK_STREAM(sta
rt, now)); | 299 SkPdfNativeObject::makeString(out, out + outLength, str); |
| 300 // PUT_TRACK_STREAM(str, start, now) |
320 TRACE_STRING(out, out + outLength); | 301 TRACE_STRING(out, out + outLength); |
321 return now; // consumed already ) at the end of the string | 302 return now; // consumed already ) at the end of the string |
322 } | 303 } |
323 | 304 |
324 static const unsigned char* readHexString(int level, const unsigned char* start,
const unsigned char* end, unsigned char* out) { | 305 static const unsigned char* readHexString(const unsigned char* start, const unsi
gned char* end, unsigned char* out) { |
325 TRACE_INDENT(level, "HexString"); | |
326 bool hasOut = (out != NULL); | 306 bool hasOut = (out != NULL); |
327 const unsigned char* in = start; | 307 const unsigned char* in = start; |
328 | 308 |
329 unsigned char code = 0; | 309 unsigned char code = 0; |
330 | 310 |
331 while (in < end) { | 311 while (in < end) { |
332 while (in < end && isPdfWhiteSpace(*in)) { | 312 while (in < end && isPdfWhiteSpace(*in)) { |
333 in++; | 313 in++; |
334 } | 314 } |
335 | 315 |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
444 in++; | 424 in++; |
445 } | 425 } |
446 | 426 |
447 if (hasOut) { | 427 if (hasOut) { |
448 return in; // consumed already > at the end of the string | 428 return in; // consumed already > at the end of the string |
449 } else { | 429 } else { |
450 return start + (out - (const unsigned char*)NULL); // return where the s
tring would end if we reuse the string | 430 return start + (out - (const unsigned char*)NULL); // return where the s
tring would end if we reuse the string |
451 } | 431 } |
452 } | 432 } |
453 | 433 |
454 static int readHexStringLength(int level, const unsigned char* start, const unsi
gned char* end) { | 434 static int readHexStringLength(const unsigned char* start, const unsigned char*
end) { |
455 return readHexString(level, start, end, NULL) - start; | 435 return readHexString(start, end, NULL) - start; |
456 } | 436 } |
457 | 437 |
458 static const unsigned char* readHexString(int level, const unsigned char* start,
const unsigned char* end, SkPdfNativeObject* str, SkPdfAllocator* allocator GET
_TRACK_STREAM) { | 438 static const unsigned char* readHexString(const unsigned char* start, const unsi
gned char* end, SkPdfNativeObject* str, SkPdfAllocator* allocator) { |
459 if (!allocator) { | 439 if (!allocator) { |
460 return end; | 440 return end; |
461 } | 441 } |
462 int outLength = readHexStringLength(level, start, end); | 442 int outLength = readHexStringLength(start, end); |
463 // TODO(edisonn): optimize the allocation, don't allocate new string, but pu
t it in a preallocated buffer | 443 // TODO(edisonn): optimize the allocation, don't allocate new string, but pu
t it in a preallocated buffer |
464 unsigned char* out = (unsigned char*)allocator->alloc(outLength); | 444 unsigned char* out = (unsigned char*)allocator->alloc(outLength); |
465 const unsigned char* now = readHexString(level, start, end, out); | 445 const unsigned char* now = readHexString(start, end, out); |
466 SkPdfNativeObject::makeHexString(out, out + outLength, str PUT_TRACK_STREAM(
start, now)); | 446 SkPdfNativeObject::makeHexString(out, out + outLength, str); |
| 447 // str PUT_TRACK_STREAM(start, now) |
467 TRACE_HEXSTRING(out, out + outLength); | 448 TRACE_HEXSTRING(out, out + outLength); |
468 return now; // consumed already > at the end of the string | 449 return now; // consumed already > at the end of the string |
469 } | 450 } |
470 | 451 |
471 // TODO(edisonn): before PDF 1.2 name could not have special characters, add ver
sion parameter | 452 // TODO(edisonn): before PDF 1.2 name could not have special characters, add ver
sion parameter |
472 static const unsigned char* readName(int level, const unsigned char* start, cons
t unsigned char* end, unsigned char* out) { | 453 static const unsigned char* readName(const unsigned char* start, const unsigned
char* end, unsigned char* out) { |
473 TRACE_INDENT(level, "Name"); | |
474 bool hasOut = (out != NULL); | 454 bool hasOut = (out != NULL); |
475 const unsigned char* in = start; | 455 const unsigned char* in = start; |
476 | 456 |
477 unsigned char code = 0; | 457 unsigned char code = 0; |
478 | 458 |
479 while (in < end) { | 459 while (in < end) { |
480 if (isPdfWhiteSpaceOrPdfDelimiter(*in)) { | 460 if (isPdfWhiteSpaceOrPdfDelimiter(*in)) { |
481 break; | 461 break; |
482 } | 462 } |
483 | 463 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
569 } | 549 } |
570 } | 550 } |
571 | 551 |
572 if (hasOut) { | 552 if (hasOut) { |
573 return in; | 553 return in; |
574 } else { | 554 } else { |
575 return start + (out - (const unsigned char*)NULL); // return where the s
tring would end if we reuse the string | 555 return start + (out - (const unsigned char*)NULL); // return where the s
tring would end if we reuse the string |
576 } | 556 } |
577 } | 557 } |
578 | 558 |
579 static int readNameLength(int level, const unsigned char* start, const unsigned
char* end) { | 559 static int readNameLength(const unsigned char* start, const unsigned char* end)
{ |
580 return readName(level, start, end, NULL) - start; | 560 return readName(start, end, NULL) - start; |
581 } | 561 } |
582 | 562 |
583 static const unsigned char* readName(int level, const unsigned char* start, cons
t unsigned char* end, SkPdfNativeObject* name, SkPdfAllocator* allocator GET_TRA
CK_STREAM) { | 563 static const unsigned char* readName(const unsigned char* start, const unsigned
char* end, SkPdfNativeObject* name, SkPdfAllocator* allocator) { |
584 if (!allocator) { | 564 if (!allocator) { |
585 return end; | 565 return end; |
586 } | 566 } |
587 int outLength = readNameLength(level, start, end); | 567 int outLength = readNameLength(start, end); |
588 // TODO(edisonn): optimize the allocation, don't allocate new string, but pu
t it in a preallocated buffer | 568 // TODO(edisonn): optimize the allocation, don't allocate new string, but pu
t it in a preallocated buffer |
589 unsigned char* out = (unsigned char*)allocator->alloc(outLength); | 569 unsigned char* out = (unsigned char*)allocator->alloc(outLength); |
590 const unsigned char* now = readName(level, start, end, out); | 570 const unsigned char* now = readName(start, end, out); |
591 SkPdfNativeObject::makeName(out, out + outLength, name PUT_TRACK_STREAM(star
t, now)); | 571 SkPdfNativeObject::makeName(out, out + outLength, name); |
| 572 //PUT_TRACK_STREAM(start, now) |
592 TRACE_NAME(out, out + outLength); | 573 TRACE_NAME(out, out + outLength); |
593 return now; | 574 return now; |
594 } | 575 } |
595 | 576 |
596 // TODO(edisonn): pdf spec let Length to be an indirect object define after the
stream | 577 // TODO(edisonn): pdf spec let Length to be an indirect object define after the
stream |
597 // that makes for an interesting scenario, where the stream itself contains ends
tream, together | 578 // that makes for an interesting scenario, where the stream itself contains ends
tream, together |
598 // with a reference object with the length, but the real length object would be
somewhere else | 579 // with a reference object with the length, but the real length object would be
somewhere else |
599 // it could confuse the parser | 580 // it could confuse the parser |
600 /*example: | 581 /*example: |
601 | 582 |
602 7 0 obj | 583 7 0 obj |
603 << /length 8 0 R>> | 584 << /length 8 0 R>> |
604 stream | 585 stream |
605 ............... | 586 ............... |
606 endstream | 587 endstream |
607 8 0 obj #we are in stream actually, not a real object | 588 8 0 obj #we are in stream actually, not a real object |
608 << 10 >> #we are in stream actually, not a real object | 589 << 10 >> #we are in stream actually, not a real object |
609 endobj | 590 endobj |
610 endstream | 591 endstream |
611 8 0 obj #real obj | 592 8 0 obj #real obj |
612 << 100 >> #real obj | 593 << 100 >> #real obj |
613 endobj | 594 endobj |
614 and it could get worse, with multiple object like this | 595 and it could get worse, with multiple object like this |
615 */ | 596 */ |
616 | 597 |
617 // right now implement the silly algorithm that assumes endstream is finishing t
he stream | 598 // right now implement the silly algorithm that assumes endstream is finishing t
he stream |
618 | 599 |
619 | 600 |
620 static const unsigned char* readStream(int level, const unsigned char* start, co
nst unsigned char* end, SkPdfNativeObject* dict, SkPdfNativeDoc* doc) { | 601 static const unsigned char* readStream(const unsigned char* start, const unsigne
d char* end, SkPdfNativeObject* dict, SkPdfNativeDoc* doc) { |
621 TRACE_INDENT(level, "Stream"); | 602 start = skipPdfWhiteSpaces(start, end); |
622 start = skipPdfWhiteSpaces(level, start, end); | |
623 if (!(start[0] == 's' && start[1] == 't' && start[2] == 'r' && start[3] == '
e' && start[4] == 'a' && start[5] == 'm')) { | 603 if (!(start[0] == 's' && start[1] == 't' && start[2] == 'r' && start[3] == '
e' && start[4] == 'a' && start[5] == 'm')) { |
624 // no stream. return. | 604 // no stream. return. |
625 return start; | 605 return start; |
626 } | 606 } |
627 | 607 |
628 start += 6; // strlen("stream") | 608 start += 6; // strlen("stream") |
629 if (start[0] == kCR_PdfWhiteSpace && start[1] == kLF_PdfWhiteSpace) { | 609 if (start[0] == kCR_PdfWhiteSpace && start[1] == kLF_PdfWhiteSpace) { |
630 start += 2; | 610 start += 2; |
631 } else if (start[0] == kLF_PdfWhiteSpace) { | 611 } else if (start[0] == kLF_PdfWhiteSpace) { |
632 start += 1; | 612 start += 1; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
687 // TODO(edisonn): verify the next bytes are "endstream" | 667 // TODO(edisonn): verify the next bytes are "endstream" |
688 | 668 |
689 endstream += strlen("endstream"); | 669 endstream += strlen("endstream"); |
690 // TODO(edisonn): Assert? report error/warning? | 670 // TODO(edisonn): Assert? report error/warning? |
691 dict->addStream(start, (size_t)length); | 671 dict->addStream(start, (size_t)length); |
692 return endstream; | 672 return endstream; |
693 } | 673 } |
694 return start; | 674 return start; |
695 } | 675 } |
696 | 676 |
697 static const unsigned char* readInlineImageStream(int level, const unsigned char
* start, const unsigned char* end, SkPdfImageDictionary* inlineImage, SkPdfNativ
eDoc* doc) { | 677 static const unsigned char* readInlineImageStream(const unsigned char* start, co
nst unsigned char* end, SkPdfImageDictionary* inlineImage, SkPdfNativeDoc* doc)
{ |
698 TRACE_INDENT(level, "Inline Image"); | |
699 // We already processed ID keyword, and we should be positioned immediately
after it | 678 // We already processed ID keyword, and we should be positioned immediately
after it |
700 | 679 |
701 // TODO(edisonn): security: read after end check, or make buffers with extra
2 bytes | 680 // TODO(edisonn): security: read after end check, or make buffers with extra
2 bytes |
702 if (start[0] == kCR_PdfWhiteSpace && start[1] == kLF_PdfWhiteSpace) { | 681 if (start[0] == kCR_PdfWhiteSpace && start[1] == kLF_PdfWhiteSpace) { |
703 start += 2; | 682 start += 2; |
704 } else if (start[0] == kLF_PdfWhiteSpace) { | 683 } else if (start[0] == kLF_PdfWhiteSpace) { |
705 start += 1; | 684 start += 1; |
706 } else if (isPdfWhiteSpace(start[0])) { | 685 } else if (isPdfWhiteSpace(start[0])) { |
707 start += 1; | 686 start += 1; |
708 } else { | 687 } else { |
(...skipping 10 matching lines...) Expand all Loading... |
719 if (*(endstream-2) == kCR_PdfWhiteSpace) length--; | 698 if (*(endstream-2) == kCR_PdfWhiteSpace) length--; |
720 inlineImage->addStream(start, (size_t)length); | 699 inlineImage->addStream(start, (size_t)length); |
721 } else { | 700 } else { |
722 // TODO(edisonn): report error in inline image stream (ID-EI) section | 701 // TODO(edisonn): report error in inline image stream (ID-EI) section |
723 // TODO(edisonn): based on filter, try to ignore a missing EI, and read
data properly | 702 // TODO(edisonn): based on filter, try to ignore a missing EI, and read
data properly |
724 return end; | 703 return end; |
725 } | 704 } |
726 return endEI; | 705 return endEI; |
727 } | 706 } |
728 | 707 |
729 static const unsigned char* readDictionary(int level, const unsigned char* start
, const unsigned char* end, SkPdfNativeObject* dict, SkPdfAllocator* allocator,
SkPdfNativeDoc* doc GET_TRACK_STREAM) { | 708 static const unsigned char* readDictionary(const unsigned char* start, const uns
igned char* end, SkPdfNativeObject* dict, SkPdfAllocator* allocator, SkPdfNative
Doc* doc) { |
730 if (allocator == NULL) { | 709 if (allocator == NULL) { |
731 // TODO(edisonn): report/warning error | 710 // TODO(edisonn): report/warning error |
732 return end; | 711 return end; |
733 } | 712 } |
734 TRACE_INDENT(level, "Dictionary"); | 713 SkPdfNativeObject::makeEmptyDictionary(dict); |
735 SkPdfNativeObject::makeEmptyDictionary(dict PUT_TRACK_STREAM(start, start)); | 714 // PUT_TRACK_STREAM(dict, start, start) |
736 | 715 |
737 start = skipPdfWhiteSpaces(level, start, end); | 716 start = skipPdfWhiteSpaces(start, end); |
738 SkPdfAllocator tmpStorage; // keys will be stored in dict, we can free them
immediately after set. | 717 SkPdfAllocator tmpStorage; // keys will be stored in dict, we can free them
immediately after set. |
739 | 718 |
740 while (start < end && *start == kNamed_PdfDelimiter) { | 719 while (start < end && *start == kNamed_PdfDelimiter) { |
741 SkPdfNativeObject key; | 720 SkPdfNativeObject key; |
742 //*start = '\0'; | 721 //*start = '\0'; |
743 start++; | 722 start++; |
744 start = readName(level + 1, start, end, &key, &tmpStorage PUT_TRACK_STRE
AM_ARGS); | 723 start = readName(start, end, &key, &tmpStorage); |
745 start = skipPdfWhiteSpaces(level + 1, start, end); | 724 start = skipPdfWhiteSpaces(start, end); |
746 | 725 |
747 if (start < end) { | 726 if (start < end) { |
748 SkPdfNativeObject* value = allocator->allocObject(); | 727 SkPdfNativeObject* value = allocator->allocObject(); |
749 start = nextObject(level + 1, start, end, value, allocator, doc PUT_
TRACK_STREAM_ARGS); | 728 start = nextObject(start, end, value, allocator, doc); |
750 | 729 |
751 start = skipPdfWhiteSpaces(level + 1, start, end); | 730 start = skipPdfWhiteSpaces(start, end); |
752 | 731 |
753 if (start < end) { | 732 if (start < end) { |
754 // seems we have an indirect reference | 733 // seems we have an indirect reference |
755 if (isPdfDigit(*start)) { | 734 if (isPdfDigit(*start)) { |
756 SkPdfNativeObject generation; | 735 SkPdfNativeObject generation; |
757 start = nextObject(level + 1, start, end, &generation, alloc
ator, doc PUT_TRACK_STREAM_ARGS); | 736 start = nextObject(start, end, &generation, allocator, doc); |
758 | 737 |
759 SkPdfNativeObject keywordR; | 738 SkPdfNativeObject keywordR; |
760 start = nextObject(level + 1, start, end, &keywordR, allocat
or, doc PUT_TRACK_STREAM_ARGS); | 739 start = nextObject(start, end, &keywordR, allocator, doc); |
761 | 740 |
762 if (value->isInteger() && generation.isInteger() && keywordR
.isKeywordReference()) { | 741 if (value->isInteger() && generation.isInteger() && keywordR
.isKeywordReference()) { |
763 int64_t id = value->intValue(); | 742 int64_t id = value->intValue(); |
764 SkPdfNativeObject::resetAndMakeReference((unsigned int)i
d, (unsigned int)generation.intValue(), value PUT_TRACK_PARAMETERS_OBJ2(value, &
generation)); | 743 SkPdfNativeObject::resetAndMakeReference((unsigned int)i
d, (unsigned int)generation.intValue(), value); |
| 744 // PUT_TRACK_PARAMETERS_OBJ2(value, &generation) |
765 dict->set(&key, value); | 745 dict->set(&key, value); |
766 } else { | 746 } else { |
767 // error, ignore | 747 // error, ignore |
768 dict->set(&key, value); | 748 dict->set(&key, value); |
769 } | 749 } |
770 } else { | 750 } else { |
771 // next elem is not a digit, but it might not be / either! | 751 // next elem is not a digit, but it might not be / either! |
772 dict->set(&key, value); | 752 dict->set(&key, value); |
773 } | 753 } |
774 } else { | 754 } else { |
775 // /key >> | 755 // /key >> |
776 dict->set(&key, value); | 756 dict->set(&key, value); |
777 return end; | 757 return end; |
778 } | 758 } |
779 start = skipPdfWhiteSpaces(level + 1, start, end); | 759 start = skipPdfWhiteSpaces(start, end); |
780 } else { | 760 } else { |
781 dict->set(&key, &SkPdfNativeObject::kNull); | 761 dict->set(&key, &SkPdfNativeObject::kNull); |
782 return end; | 762 return end; |
783 } | 763 } |
784 } | 764 } |
785 | 765 |
786 // TODO(edisonn): options to ignore these errors | 766 // TODO(edisonn): options to ignore these errors |
787 | 767 |
788 // now we should expect >> | 768 // now we should expect >> |
789 start = skipPdfWhiteSpaces(level, start, end); | 769 start = skipPdfWhiteSpaces(start, end); |
790 if (*start != kClosedInequityBracket_PdfDelimiter) { | 770 if (*start != kClosedInequityBracket_PdfDelimiter) { |
791 // TODO(edisonn): report/warning | 771 // TODO(edisonn): report/warning |
792 } | 772 } |
793 //*start = '\0'; | 773 //*start = '\0'; |
794 start++; // skip > | 774 start++; // skip > |
795 if (*start != kClosedInequityBracket_PdfDelimiter) { | 775 if (*start != kClosedInequityBracket_PdfDelimiter) { |
796 // TODO(edisonn): report/warning | 776 // TODO(edisonn): report/warning |
797 } | 777 } |
798 //*start = '\0'; | 778 //*start = '\0'; |
799 start++; // skip > | 779 start++; // skip > |
800 | 780 |
801 STORE_TRACK_PARAMETER_OFFSET_END(dict,start); | 781 //STORE_TRACK_PARAMETER_OFFSET_END(dict,start); |
802 | 782 |
803 start = readStream(level, start, end, dict, doc); | 783 start = readStream(start, end, dict, doc); |
804 | 784 |
805 return start; | 785 return start; |
806 } | 786 } |
807 | 787 |
808 const unsigned char* nextObject(int level, const unsigned char* start, const uns
igned char* end, SkPdfNativeObject* token, SkPdfAllocator* allocator, SkPdfNativ
eDoc* doc GET_TRACK_STREAM) { | 788 const unsigned char* nextObject(const unsigned char* start, const unsigned char*
end, SkPdfNativeObject* token, SkPdfAllocator* allocator, SkPdfNativeDoc* doc)
{ |
809 const unsigned char* current; | 789 const unsigned char* current; |
810 | 790 |
811 // skip white spaces | 791 // skip white spaces |
812 start = skipPdfWhiteSpaces(level, start, end); | 792 start = skipPdfWhiteSpaces(start, end); |
813 | 793 |
814 if (start >= end) { | 794 if (start >= end) { |
815 return end; | 795 return end; |
816 } | 796 } |
817 | 797 |
818 current = endOfPdfToken(level, start, end); | 798 current = endOfPdfToken(start, end); |
819 | 799 |
820 // no token, len would be 0 | 800 // no token, len would be 0 |
821 if (current == start || current == end) { | 801 if (current == start || current == end) { |
822 return end; | 802 return end; |
823 } | 803 } |
824 | 804 |
825 int tokenLen = current - start; | 805 int tokenLen = current - start; |
826 | 806 |
827 if (tokenLen == 1) { | 807 if (tokenLen == 1) { |
828 // start array | 808 // start array |
829 switch (*start) { | 809 switch (*start) { |
830 case kOpenedSquareBracket_PdfDelimiter: | 810 case kOpenedSquareBracket_PdfDelimiter: |
831 //*start = '\0'; | 811 //*start = '\0'; |
832 return readArray(level + 1, current, end, token, allocator, doc
PUT_TRACK_STREAM_ARGS); | 812 return readArray(current, end, token, allocator, doc); |
833 | 813 |
834 case kOpenedRoundBracket_PdfDelimiter: | 814 case kOpenedRoundBracket_PdfDelimiter: |
835 //*start = '\0'; | 815 //*start = '\0'; |
836 return readString(level, start + 1, end, token, allocator PUT_TR
ACK_STREAM_ARGS); | 816 return readString(start + 1, end, token, allocator); |
837 | 817 |
838 case kOpenedInequityBracket_PdfDelimiter: | 818 case kOpenedInequityBracket_PdfDelimiter: |
839 //*start = '\0'; | 819 //*start = '\0'; |
840 if (end > start + 1 && start[1] == kOpenedInequityBracket_PdfDel
imiter) { | 820 if (end > start + 1 && start[1] == kOpenedInequityBracket_PdfDel
imiter) { |
841 //start[1] = '\0'; // optional | 821 //start[1] = '\0'; // optional |
842 // TODO(edisonn): pass here the length somehow? | 822 // TODO(edisonn): pass here the length somehow? |
843 return readDictionary(level + 1, start + 2, end, token, allo
cator, doc PUT_TRACK_STREAM_ARGS); // skip << | 823 return readDictionary(start + 2, end, token, allocator, doc)
; // skip << |
844 } else { | 824 } else { |
845 return readHexString(level, start + 1, end, token, allocator
PUT_TRACK_STREAM_ARGS); // skip < | 825 return readHexString(start + 1, end, token, allocator); //
skip < |
846 } | 826 } |
847 | 827 |
848 case kNamed_PdfDelimiter: | 828 case kNamed_PdfDelimiter: |
849 //*start = '\0'; | 829 //*start = '\0'; |
850 return readName(level, start + 1, end, token, allocator PUT_TRAC
K_STREAM_ARGS); | 830 return readName(start + 1, end, token, allocator); |
851 | 831 |
852 // TODO(edisonn): what to do curly brackets? read spec! | 832 // TODO(edisonn): what to do curly brackets? read spec! |
853 case kOpenedCurlyBracket_PdfDelimiter: | 833 case kOpenedCurlyBracket_PdfDelimiter: |
854 default: | 834 default: |
855 break; | 835 break; |
856 } | 836 } |
857 | 837 |
858 SkASSERT(!isPdfWhiteSpace(*start)); | 838 SkASSERT(!isPdfWhiteSpace(*start)); |
859 if (isPdfDelimiter(*start)) { | 839 if (isPdfDelimiter(*start)) { |
860 // TODO(edisonn): how stream ] } > ) will be handled? | 840 // TODO(edisonn): how stream ] } > ) will be handled? |
861 // for now ignore, and it will become a keyword to be ignored | 841 // for now ignore, and it will become a keyword to be ignored |
862 } | 842 } |
863 } | 843 } |
864 | 844 |
865 if (tokenLen == 4 && start[0] == 'n' && start[1] == 'u' && start[2] == 'l' &
& start[3] == 'l') { | 845 if (tokenLen == 4 && start[0] == 'n' && start[1] == 'u' && start[2] == 'l' &
& start[3] == 'l') { |
866 SkPdfNativeObject::makeNull(token PUT_TRACK_STREAM(start, start + 4)); | 846 SkPdfNativeObject::makeNull(token); |
| 847 // PUT_TRACK_STREAM(start, start + 4) |
867 return current; | 848 return current; |
868 } | 849 } |
869 | 850 |
870 if (tokenLen == 4 && start[0] == 't' && start[1] == 'r' && start[2] == 'u' &
& start[3] == 'e') { | 851 if (tokenLen == 4 && start[0] == 't' && start[1] == 'r' && start[2] == 'u' &
& start[3] == 'e') { |
871 SkPdfNativeObject::makeBoolean(true, token PUT_TRACK_STREAM(start, start
+ 4)); | 852 SkPdfNativeObject::makeBoolean(true, token); |
| 853 // PUT_TRACK_STREAM(start, start + 4) |
872 return current; | 854 return current; |
873 } | 855 } |
874 | 856 |
875 if (tokenLen == 5 && start[0] == 'f' && start[1] == 'a' && start[2] == 'l' &
& start[3] == 's' && start[4] == 'e') { | 857 if (tokenLen == 5 && start[0] == 'f' && start[1] == 'a' && start[2] == 'l' &
& start[3] == 's' && start[4] == 'e') { |
876 SkPdfNativeObject::makeBoolean(false, token PUT_TRACK_STREAM(start, star
t + 5)); | 858 SkPdfNativeObject::makeBoolean(false, token); |
| 859 // PUT_TRACK_STREAM(start, start + 5) |
877 return current; | 860 return current; |
878 } | 861 } |
879 | 862 |
880 if (isPdfNumeric(*start)) { | 863 if (isPdfNumeric(*start)) { |
881 SkPdfNativeObject::makeNumeric(start, current, token PUT_TRACK_STREAM(st
art, current)); | 864 SkPdfNativeObject::makeNumeric(start, current, token); |
| 865 // PUT_TRACK_STREAM(start, current) |
882 } else { | 866 } else { |
883 SkPdfNativeObject::makeKeyword(start, current, token PUT_TRACK_STREAM(st
art, current)); | 867 SkPdfNativeObject::makeKeyword(start, current, token); |
| 868 // PUT_TRACK_STREAM(start, current) |
884 } | 869 } |
885 return current; | 870 return current; |
886 } | 871 } |
887 | 872 |
888 SkPdfNativeObject* SkPdfAllocator::allocBlock() { | 873 SkPdfNativeObject* SkPdfAllocator::allocBlock() { |
889 fSizeInBytes += BUFFER_SIZE * sizeof(SkPdfNativeObject); | 874 fSizeInBytes += BUFFER_SIZE * sizeof(SkPdfNativeObject); |
890 return new SkPdfNativeObject[BUFFER_SIZE]; | 875 return new SkPdfNativeObject[BUFFER_SIZE]; |
891 } | 876 } |
892 | 877 |
893 SkPdfAllocator::~SkPdfAllocator() { | 878 SkPdfAllocator::~SkPdfAllocator() { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
945 } | 930 } |
946 | 931 |
947 bool SkPdfNativeTokenizer::readTokenCore(PdfToken* token) { | 932 bool SkPdfNativeTokenizer::readTokenCore(PdfToken* token) { |
948 SkPdfNativeObject obj; | 933 SkPdfNativeObject obj; |
949 #ifdef PDF_TRACE_READ_TOKEN | 934 #ifdef PDF_TRACE_READ_TOKEN |
950 static int read_op = 0; | 935 static int read_op = 0; |
951 #endif | 936 #endif |
952 token->fKeyword = NULL; | 937 token->fKeyword = NULL; |
953 token->fObject = NULL; | 938 token->fObject = NULL; |
954 | 939 |
955 fUncompressedStream = skipPdfWhiteSpaces(0, fUncompressedStream, fUncompress
edStreamEnd); | 940 fUncompressedStream = skipPdfWhiteSpaces(fUncompressedStream, fUncompressedS
treamEnd); |
956 if (fUncompressedStream >= fUncompressedStreamEnd) { | 941 if (fUncompressedStream >= fUncompressedStreamEnd) { |
957 return false; | 942 return false; |
958 } | 943 } |
959 | 944 |
960 fUncompressedStream = nextObject(0, fUncompressedStream, fUncompressedStream
End, &obj, fAllocator, fDoc PUT_TRACK_STREAM_ARGS_EXPL2(fStreamId, fUncompressed
StreamStart)); | 945 fUncompressedStream = nextObject(fUncompressedStream, fUncompressedStreamEnd
, &obj, fAllocator, fDoc); |
| 946 // PUT_TRACK_STREAM_ARGS_EXPL2(fStreamId, fUncompressedStreamStart) |
961 | 947 |
962 // If it is a keyword, we will only get the pointer of the string | 948 // If it is a keyword, we will only get the pointer of the string |
963 if (obj.type() == SkPdfNativeObject::kKeyword_PdfObjectType) { | 949 if (obj.type() == SkPdfNativeObject::kKeyword_PdfObjectType) { |
964 token->fKeyword = obj.c_str(); | 950 token->fKeyword = obj.c_str(); |
965 token->fKeywordLength = obj.lenstr(); | 951 token->fKeywordLength = obj.lenstr(); |
966 token->fType = kKeyword_TokenType; | 952 token->fType = kKeyword_TokenType; |
967 } else { | 953 } else { |
968 SkPdfNativeObject* pobj = fAllocator->allocObject(); | 954 SkPdfNativeObject* pobj = fAllocator->allocObject(); |
969 *pobj = obj; | 955 *pobj = obj; |
970 token->fObject = pobj; | 956 token->fObject = pobj; |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1079 HANDLE_NAME_ABBR(value, FlateDecode, Fl); // (PDF 1.2) | 1065 HANDLE_NAME_ABBR(value, FlateDecode, Fl); // (PDF 1.2) |
1080 HANDLE_NAME_ABBR(value, RunLengthDecode, RL); | 1066 HANDLE_NAME_ABBR(value, RunLengthDecode, RL); |
1081 HANDLE_NAME_ABBR(value, CCITTFaxDecode, CCF); | 1067 HANDLE_NAME_ABBR(value, CCITTFaxDecode, CCF); |
1082 HANDLE_NAME_ABBR(value, DCTDecode, DCT); | 1068 HANDLE_NAME_ABBR(value, DCTDecode, DCT); |
1083 | 1069 |
1084 return value; | 1070 return value; |
1085 } | 1071 } |
1086 | 1072 |
1087 SkPdfImageDictionary* SkPdfNativeTokenizer::readInlineImage() { | 1073 SkPdfImageDictionary* SkPdfNativeTokenizer::readInlineImage() { |
1088 // BI already processed | 1074 // BI already processed |
1089 fUncompressedStream = skipPdfWhiteSpaces(0, fUncompressedStream, fUncompress
edStreamEnd); | 1075 fUncompressedStream = skipPdfWhiteSpaces(fUncompressedStream, fUncompressedS
treamEnd); |
1090 if (fUncompressedStream >= fUncompressedStreamEnd) { | 1076 if (fUncompressedStream >= fUncompressedStreamEnd) { |
1091 return NULL; | 1077 return NULL; |
1092 } | 1078 } |
1093 | 1079 |
1094 SkPdfImageDictionary* inlineImage = (SkPdfImageDictionary*)fAllocator->alloc
Object(); | 1080 SkPdfImageDictionary* inlineImage = (SkPdfImageDictionary*)fAllocator->alloc
Object(); |
1095 SkPdfNativeObject::makeEmptyDictionary(inlineImage PUT_TRACK_STREAM_ARGS_EXP
L(fStreamId, fUncompressedStream - fUncompressedStreamStart, fUncompressedStream
- fUncompressedStreamStart)); | 1081 SkPdfNativeObject::makeEmptyDictionary(inlineImage); |
| 1082 // PUT_TRACK_STREAM_ARGS_EXPL(fStreamId, fUncompressedStream - fUncompresse
dStreamStart, fUncompressedStream - fUncompressedStreamStart) |
1096 | 1083 |
1097 while (fUncompressedStream < fUncompressedStreamEnd) { | 1084 while (fUncompressedStream < fUncompressedStreamEnd) { |
1098 SkPdfNativeObject* key = fAllocator->allocObject(); | 1085 SkPdfNativeObject* key = fAllocator->allocObject(); |
1099 fUncompressedStream = nextObject(0, fUncompressedStream, fUncompressedSt
reamEnd, key, fAllocator, fDoc PUT_TRACK_STREAM_ARGS_EXPL2(fStreamId, fUncompres
sedStreamStart)); | 1086 fUncompressedStream = nextObject(fUncompressedStream, fUncompressedStrea
mEnd, key, fAllocator, fDoc); |
| 1087 // PUT_TRACK_STREAM_ARGS_EXPL2(fStreamId, fUncompressedStreamStart)s |
1100 | 1088 |
1101 if (key->isKeyword() && key->lenstr() == 2 && key->c_str()[0] == 'I' &&
key->c_str()[1] == 'D') { // ID | 1089 if (key->isKeyword() && key->lenstr() == 2 && key->c_str()[0] == 'I' &&
key->c_str()[1] == 'D') { // ID |
1102 fUncompressedStream = readInlineImageStream(0, fUncompressedStream,
fUncompressedStreamEnd, inlineImage, fDoc); | 1090 fUncompressedStream = readInlineImageStream(fUncompressedStream, fUn
compressedStreamEnd, inlineImage, fDoc); |
1103 return inlineImage; | 1091 return inlineImage; |
1104 } else { | 1092 } else { |
1105 SkPdfNativeObject* obj = fAllocator->allocObject(); | 1093 SkPdfNativeObject* obj = fAllocator->allocObject(); |
1106 fUncompressedStream = nextObject(0, fUncompressedStream, fUncompress
edStreamEnd, obj, fAllocator, fDoc PUT_TRACK_STREAM_ARGS_EXPL2(fStreamId, fUncom
pressedStreamStart)); | 1094 fUncompressedStream = nextObject(fUncompressedStream, fUncompressedS
treamEnd, obj, fAllocator, fDoc); |
| 1095 // PUT_TRACK_STREAM_ARGS_EXPL2(fStreamId, fUncompressedStreamStart)
s |
1107 // TODO(edisonn): perf maybe we should not expand abreviation like t
his | 1096 // TODO(edisonn): perf maybe we should not expand abreviation like t
his |
1108 inlineImage->set(inlineImageKeyAbbreviationExpand(key), | 1097 inlineImage->set(inlineImageKeyAbbreviationExpand(key), |
1109 inlineImageValueAbbreviationExpand(obj)); | 1098 inlineImageValueAbbreviationExpand(obj)); |
1110 } | 1099 } |
1111 } | 1100 } |
1112 // TODO(edisonn): report end of data with inline image without an EI | 1101 // TODO(edisonn): report end of data with inline image without an EI |
1113 return inlineImage; | 1102 return inlineImage; |
1114 } | 1103 } |
OLD | NEW |