1cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com/*
2cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com * Copyright 2013 Google Inc.
3cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com *
4cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com * Use of this source code is governed by a BSD-style license that can be
5cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com * found in the LICENSE file.
6cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com */
73aac1f9f308192f3787265830fe86ce8874e7382edisonn@google.com
8571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com#include "SkPdfConfig.h"
95092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#include "SkPdfDiffEncoder.h"
10c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com#include "SkPdfNativeObject.h"
11c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com#include "SkPdfNativeTokenizer.h"
12c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com#include "SkPdfUtils.h"
133aac1f9f308192f3787265830fe86ce8874e7382edisonn@google.com
1433f11b6fcdb7dfce27f953803be40fbacedc7450edisonn@google.com// TODO(edisonn): mac builder does not find the header ... but from headers is ok
1533f11b6fcdb7dfce27f953803be40fbacedc7450edisonn@google.com//#include "SkPdfStreamCommonDictionary_autogen.h"
1633f11b6fcdb7dfce27f953803be40fbacedc7450edisonn@google.com//#include "SkPdfImageDictionary_autogen.h"
1733f11b6fcdb7dfce27f953803be40fbacedc7450edisonn@google.com#include "SkPdfHeaders_autogen.h"
1833f11b6fcdb7dfce27f953803be40fbacedc7450edisonn@google.com
1978b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
20c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com// TODO(edisonn): Perf, Make this function run faster.
21c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com// There could be 0s between start and end.
22c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com// needle will not contain 0s.
2378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comstatic char* strrstrk(char* hayStart, char* hayEnd, const char* needle) {
2478b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    int needleLen = strlen(needle);
2578b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    if ((isPdfWhiteSpaceOrPdfDelimiter(*(hayStart+needleLen)) || (hayStart+needleLen == hayEnd)) &&
2678b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com            strncmp(hayStart, needle, needleLen) == 0) {
2778b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        return hayStart;
2878b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    }
2978b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
3078b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    hayStart++;
3178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
3278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    while (hayStart < hayEnd) {
3378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        if (isPdfWhiteSpaceOrPdfDelimiter(*(hayStart-1)) &&
34c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                (isPdfWhiteSpaceOrPdfDelimiter(*(hayStart+needleLen)) ||
35c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                      (hayStart+needleLen == hayEnd)) &&
3678b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com                strncmp(hayStart, needle, needleLen) == 0) {
3778b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com            return hayStart;
3878b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        }
3978b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        hayStart++;
4078b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    }
4178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    return NULL;
4278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com}
4378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
44598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.comconst unsigned char* skipPdfWhiteSpaces(const unsigned char* start, const unsigned char* end) {
454ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    while (start < end && (isPdfWhiteSpace(*start) || *start == kComment_PdfDelimiter)) {
462ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com        TRACE_COMMENT(*start);
47571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (*start == kComment_PdfDelimiter) {
48571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            // skip the comment until end of line
49571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            while (start < end && !isPdfEOL(*start)) {
50571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                start++;
512ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com                TRACE_COMMENT(*start);
52571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            }
53571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        } else {
54571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            start++;
55571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
56571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
57571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return start;
58571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
59571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
60598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.comconst unsigned char* endOfPdfToken(const unsigned char* start, const unsigned char* end) {
61571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    SkASSERT(!isPdfWhiteSpace(*start));
62571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
63571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (start < end && isPdfDelimiter(*start)) {
642ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com        TRACE_TK(*start);
65571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        start++;
66571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        return start;
67571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
68571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
69571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    while (start < end && !isPdfWhiteSpaceOrPdfDelimiter(*start)) {
702ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com        TRACE_TK(*start);
71571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        start++;
72571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
73571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return start;
74571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
75571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
76c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com// The parsing should end with a ].
77c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.comstatic const unsigned char* readArray(const unsigned char* start, const unsigned char* end,
78c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                      SkPdfNativeObject* array,
79c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                      SkPdfAllocator* allocator, SkPdfNativeDoc* doc) {
80598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    SkPdfNativeObject::makeEmptyArray(array);
81598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    // PUT_TRACK_STREAM(array, start, start)
82bca421b468f53a591333918248f54bbd958389d2edisonn@google.com
831f080163ac58e0a5a621a720de5fc63e7b736765edisonn@google.com    if (allocator == NULL) {
84c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // TODO(edisonn): report/warning error/assert
851f080163ac58e0a5a621a720de5fc63e7b736765edisonn@google.com        return end;
861f080163ac58e0a5a621a720de5fc63e7b736765edisonn@google.com    }
871f080163ac58e0a5a621a720de5fc63e7b736765edisonn@google.com
88571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    while (start < end) {
89571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        // skip white spaces
90598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        start = skipPdfWhiteSpaces(start, end);
91571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
92598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        const unsigned char* endOfToken = endOfPdfToken(start, end);
93571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
94571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (endOfToken == start) {
95571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            // TODO(edisonn): report error in pdf file (end of stream with ] for end of aray
96571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            return start;
97571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
98571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
99571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (endOfToken == start + 1 && *start == kClosedSquareBracket_PdfDelimiter) {
100571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            return endOfToken;
101571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
102571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
1033aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com        SkPdfNativeObject* newObj = allocator->allocObject();
104598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        start = nextObject(start, end, newObj, allocator, doc);
105c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // TODO(edisonn): perf/memory: put the variables on the stack, and flush them on the array
106c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // only when we are sure they are not references!
107c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        if (newObj->isKeywordReference() && array->size() >= 2 &&
108c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                array->objAtAIndex(array->size() - 1)->isInteger() &&
109c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                array->objAtAIndex(array->size() - 2)->isInteger()) {
1103aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com            SkPdfNativeObject* gen = array->removeLastInArray();
1113aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com            SkPdfNativeObject* id = array->removeLastInArray();
112bca421b468f53a591333918248f54bbd958389d2edisonn@google.com
113c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            SkPdfNativeObject::resetAndMakeReference((unsigned int)id->intValue(),
114c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                                     (unsigned int)gen->intValue(), newObj);
115598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com            // newObj  PUT_TRACK_PARAMETERS_OBJ2(id, newObj) - store end, as now
116571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
117571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        array->appendInArray(newObj);
118571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
119571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    // TODO(edisonn): report not reached, we should never get here
1208bad7375d7e0ebe28af4d905665f34227843bd16edisonn@google.com    // TODO(edisonn): there might be a bug here, enable an assert and run it on files
1218bad7375d7e0ebe28af4d905665f34227843bd16edisonn@google.com    // or it might be that the files were actually corrupted
122571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return start;
123571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
124571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
125c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.comstatic const unsigned char* readString(const unsigned char* start, const unsigned char* end,
126c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                       unsigned char* out) {
1272ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    const unsigned char* in = start;
1282ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    bool hasOut = (out != NULL);
1292ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com
1302ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    int openRoundBrackets = 1;
1312ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    while (in < end) {
132571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        openRoundBrackets += ((*in) == kOpenedRoundBracket_PdfDelimiter);
133571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        openRoundBrackets -= ((*in) == kClosedRoundBracket_PdfDelimiter);
1342ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com        if (openRoundBrackets == 0) {
1352ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com            in++;   // consumed )
1362ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com            break;
1372ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com        }
1382ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com
139571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (*in == kEscape_PdfSpecial) {
140571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            if (in + 1 < end) {
141571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                switch (in[1]) {
142571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    case 'n':
1432ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com                        if (hasOut) { *out = kLF_PdfWhiteSpace; }
144571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        out++;
145571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        in += 2;
146571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        break;
147571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
148571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    case 'r':
1492ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com                        if (hasOut) { *out = kCR_PdfWhiteSpace; }
150571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        out++;
151571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        in += 2;
152571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        break;
153571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
154571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    case 't':
1552ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com                        if (hasOut) { *out = kHT_PdfWhiteSpace; }
156571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        out++;
157571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        in += 2;
158571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        break;
159571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
160571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    case 'b':
161571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        // TODO(edisonn): any special meaning to backspace?
1622ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com                        if (hasOut) { *out = kBackspace_PdfSpecial; }
163571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        out++;
164571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        in += 2;
165571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        break;
166571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
167571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    case 'f':
1681f080163ac58e0a5a621a720de5fc63e7b736765edisonn@google.com                        if (hasOut) { *out = kFF_PdfWhiteSpace; }
169571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        out++;
170571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        in += 2;
171571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        break;
172571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
173571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    case kOpenedRoundBracket_PdfDelimiter:
1742ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com                        if (hasOut) { *out = kOpenedRoundBracket_PdfDelimiter; }
175571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        out++;
176571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        in += 2;
177571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        break;
178571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
179571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    case kClosedRoundBracket_PdfDelimiter:
1802ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com                        if (hasOut) { *out = kClosedRoundBracket_PdfDelimiter; }
181571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        out++;
182571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        in += 2;
183571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        break;
184571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
185571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    case kEscape_PdfSpecial:
1862ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com                        if (hasOut) { *out = kEscape_PdfSpecial; }
187571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        out++;
188571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        in += 2;
189571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        break;
190571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
191571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    case '0':
192571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    case '1':
193571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    case '2':
194571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    case '3':
195571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    case '4':
196571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    case '5':
197571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    case '6':
198571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    case '7': {
199571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                            //read octals
200571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                            in++;   // consume backslash
201571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
202571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                            int code = 0;
203571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                            int i = 0;
204571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                            while (in < end && *in >= '0' && *in < '8') {
205571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                                code = (code << 3) + ((*in) - '0');  // code * 8 + d
206571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                                i++;
207571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                                in++;
208571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                                if (i == 3) {
2092ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com                                    if (hasOut) { *out = code & 0xff; }
210571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                                    out++;
211571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                                    i = 0;
212571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                                }
213571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                            }
214571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                            if (i > 0) {
2152ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com                                if (hasOut) { *out = code & 0xff; }
216571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                                out++;
217571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                            }
218571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        }
219571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        break;
220571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
221571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    default:
222c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                        // Per spec, backslash is ignored if escaped ch is unknown
223571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        in++;
224571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        break;
225571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                }
2268bad7375d7e0ebe28af4d905665f34227843bd16edisonn@google.com            } else {
2278bad7375d7e0ebe28af4d905665f34227843bd16edisonn@google.com                in++;
228571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            }
229571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        } else {
2302ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com            if (hasOut) { *out = *in; }
231571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            in++;
232571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            out++;
233571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
234571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
235571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
2362ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    if (hasOut) {
2372ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com        return in;  // consumed already ) at the end of the string
2382ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    } else {
239c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // return where the string would end if we reuse the string
240c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        return start + (out - (const unsigned char*)NULL);
2412ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    }
2422ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com}
2432ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com
244598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.comstatic int readStringLength(const unsigned char* start, const unsigned char* end) {
245598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    return readString(start, end, NULL) - start;
2462ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com}
247571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
248c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.comstatic const unsigned char* readString(const unsigned char* start, const unsigned char* end,
249c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                       SkPdfNativeObject* str, SkPdfAllocator* allocator) {
250b44334c1c07f307f3e2dbb9ee4ace4c14860a345edisonn@google.com    if (!allocator) {
251c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // TODO(edisonn): report error/warn/assert
252b44334c1c07f307f3e2dbb9ee4ace4c14860a345edisonn@google.com        return end;
253b44334c1c07f307f3e2dbb9ee4ace4c14860a345edisonn@google.com    }
254c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com
255598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    int outLength = readStringLength(start, end);
2562ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    unsigned char* out = (unsigned char*)allocator->alloc(outLength);
257598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    const unsigned char* now = readString(start, end, out);
258598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    SkPdfNativeObject::makeString(out, out + outLength, str);
259598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    //  PUT_TRACK_STREAM(str, start, now)
2602ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    TRACE_STRING(out, out + outLength);
261bca421b468f53a591333918248f54bbd958389d2edisonn@google.com    return now;  // consumed already ) at the end of the string
262571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
263571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
264c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.comstatic const unsigned char* readHexString(const unsigned char* start, const unsigned char* end,
265c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                          unsigned char* out) {
2662ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    bool hasOut = (out != NULL);
2672ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    const unsigned char* in = start;
268571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
269571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    unsigned char code = 0;
270571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
271571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    while (in < end) {
272571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        while (in < end && isPdfWhiteSpace(*in)) {
273571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            in++;
274571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
275571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
276571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (*in == kClosedInequityBracket_PdfDelimiter) {
2772ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com            in++;  // consume >
278571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            // normal exit
279571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            break;
280571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
281571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
282571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (in >= end) {
283571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            // end too soon
284571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            break;
285571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
286571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
287571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        switch (*in) {
288571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '0':
289571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '1':
290571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '2':
291571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '3':
292571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '4':
293571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '5':
294571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '6':
295571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '7':
296571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '8':
297571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '9':
298571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                code = (*in - '0') << 4;
299571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                break;
300571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
301571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'a':
302571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'b':
303571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'c':
304571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'd':
305571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'e':
306571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'f':
307571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                code = (*in - 'a' + 10) << 4;
308571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                break;
309571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
310571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'A':
311571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'B':
312571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'C':
313571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'D':
314571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'E':
315571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'F':
316571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                code = (*in - 'A' + 10) << 4;
317571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                break;
318571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
319571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            // TODO(edisonn): spec does not say how to handle this error
320571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            default:
321571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                break;
322571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
323571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
324571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        in++;  // advance
325571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
326571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        while (in < end && isPdfWhiteSpace(*in)) {
327571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            in++;
328571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
329571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
330571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        // TODO(edisonn): report error
331571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (in >= end) {
3322ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com            if (hasOut) { *out = code; }
333571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            out++;
334571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            break;
335571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
336571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
337571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (*in == kClosedInequityBracket_PdfDelimiter) {
3382ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com            if (hasOut) { *out = code; }
339571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            out++;
3401acab362fdde40948e47438edcc4326e04b9b52bedisonn@google.com            in++;
341571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            break;
342571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
343571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
344571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        switch (*in) {
345571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '0':
346571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '1':
347571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '2':
348571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '3':
349571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '4':
350571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '5':
351571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '6':
352571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '7':
353571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '8':
354571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case '9':
355571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                code += (*in - '0');
356571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                break;
357571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
358571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'a':
359571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'b':
360571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'c':
361571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'd':
362571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'e':
363571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'f':
364571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                code += (*in - 'a' + 10);
365571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                break;
366571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
367571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'A':
368571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'B':
369571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'C':
370571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'D':
371571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'E':
372571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case 'F':
373571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                code += (*in - 'A' + 10);
374571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                break;
375571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
376571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            // TODO(edisonn): spec does not say how to handle this error
377571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            default:
378571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                break;
379571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
380571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
3812ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com        if (hasOut) { *out = code; }
382571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        out++;
383571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        in++;
384571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
385571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
3862ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    if (hasOut) {
387c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        return in;  // consumed already ) at the end of the string
3882ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    } else {
389c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // return where the string would end if we reuse the string
390c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        return start + (out - (const unsigned char*)NULL);
391571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
3922ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com}
393571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
394598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.comstatic int readHexStringLength(const unsigned char* start, const unsigned char* end) {
395598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    return readHexString(start, end, NULL) - start;
3962ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com}
3972ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com
398598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.comstatic const unsigned char* readHexString(const unsigned char* start, const unsigned char* end, SkPdfNativeObject* str, SkPdfAllocator* allocator) {
399b44334c1c07f307f3e2dbb9ee4ace4c14860a345edisonn@google.com    if (!allocator) {
400c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // TODO(edisonn): report error/warn/assert
401b44334c1c07f307f3e2dbb9ee4ace4c14860a345edisonn@google.com        return end;
402b44334c1c07f307f3e2dbb9ee4ace4c14860a345edisonn@google.com    }
403598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    int outLength = readHexStringLength(start, end);
4042ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    unsigned char* out = (unsigned char*)allocator->alloc(outLength);
405598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    const unsigned char* now = readHexString(start, end, out);
406598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    SkPdfNativeObject::makeHexString(out, out + outLength, str);
407598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    // str PUT_TRACK_STREAM(start, now)
4082ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    TRACE_HEXSTRING(out, out + outLength);
409bca421b468f53a591333918248f54bbd958389d2edisonn@google.com    return now;  // consumed already > at the end of the string
410571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
411571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
412c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com// TODO(edisonn): add version parameter, before PDF 1.2 name could not have special characters.
413c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.comstatic const unsigned char* readName(const unsigned char* start, const unsigned char* end,
414c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                     unsigned char* out) {
4152ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    bool hasOut = (out != NULL);
4162ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    const unsigned char* in = start;
417571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
418571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    unsigned char code = 0;
419571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
420571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    while (in < end) {
421571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (isPdfWhiteSpaceOrPdfDelimiter(*in)) {
422571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            break;
423571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
424571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
425571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (*in == '#' && in + 2 < end) {
426571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            in++;
427571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            switch (*in) {
428571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '0':
429571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '1':
430571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '2':
431571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '3':
432571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '4':
433571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '5':
434571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '6':
435571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '7':
436571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '8':
437571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '9':
438571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    code = (*in - '0') << 4;
439571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    break;
440571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
441571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'a':
442571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'b':
443571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'c':
444571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'd':
445571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'e':
446571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'f':
447571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    code = (*in - 'a' + 10) << 4;
448571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    break;
449571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
450571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'A':
451571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'B':
452571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'C':
453571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'D':
454571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'E':
455571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'F':
456571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    code = (*in - 'A' + 10) << 4;
457571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    break;
458571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
459571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                // TODO(edisonn): spec does not say how to handle this error
460571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                default:
461571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    break;
462571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            }
463571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
464571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            in++;  // advance
465571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
466571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            switch (*in) {
467571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '0':
468571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '1':
469571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '2':
470571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '3':
471571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '4':
472571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '5':
473571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '6':
474571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '7':
475571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '8':
476571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case '9':
477571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    code += (*in - '0');
478571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    break;
479571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
480571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'a':
481571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'b':
482571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'c':
483571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'd':
484571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'e':
485571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'f':
486571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    code += (*in - 'a' + 10);
487571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    break;
488571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
489571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'A':
490571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'B':
491571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'C':
492571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'D':
493571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'E':
494571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                case 'F':
495571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    code += (*in - 'A' + 10);
496571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    break;
497571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
498571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                // TODO(edisonn): spec does not say how to handle this error
499571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                default:
500571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    break;
501571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            }
502571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
5032ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com            if (hasOut) { *out = code; }
504571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            out++;
505571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            in++;
506571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        } else {
5072ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com            if (hasOut) { *out = *in; }
508571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            out++;
509571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            in++;
510571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
511571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
512571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
5132ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    if (hasOut) {
514c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        return in;  // consumed already ) at the end of the string
5152ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    } else {
516c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // return where the string would end if we reuse the string
517c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        return start + (out - (const unsigned char*)NULL);
5182ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    }
5192ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com}
5202ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com
521598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.comstatic int readNameLength(const unsigned char* start, const unsigned char* end) {
522598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    return readName(start, end, NULL) - start;
5232ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com}
5242ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com
525c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.comstatic const unsigned char* readName(const unsigned char* start, const unsigned char* end,
526c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                     SkPdfNativeObject* name, SkPdfAllocator* allocator) {
527b44334c1c07f307f3e2dbb9ee4ace4c14860a345edisonn@google.com    if (!allocator) {
528c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // TODO(edisonn): report error/warn/assert
529b44334c1c07f307f3e2dbb9ee4ace4c14860a345edisonn@google.com        return end;
530b44334c1c07f307f3e2dbb9ee4ace4c14860a345edisonn@google.com    }
531598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    int outLength = readNameLength(start, end);
5322ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    unsigned char* out = (unsigned char*)allocator->alloc(outLength);
533598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    const unsigned char* now = readName(start, end, out);
534598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    SkPdfNativeObject::makeName(out, out + outLength, name);
535598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    //PUT_TRACK_STREAM(start, now)
5362ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    TRACE_NAME(out, out + outLength);
537bca421b468f53a591333918248f54bbd958389d2edisonn@google.com    return now;
538571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
539571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
540571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com// TODO(edisonn): pdf spec let Length to be an indirect object define after the stream
541571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com// that makes for an interesting scenario, where the stream itself contains endstream, together
542571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com// with a reference object with the length, but the real length object would be somewhere else
543571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com// it could confuse the parser
544571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com/*example:
545571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
546571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com7 0 obj
547571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com<< /length 8 0 R>>
548571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.comstream
549571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com...............
550571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.comendstream
551571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com8 0 obj #we are in stream actually, not a real object
552571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com<< 10 >> #we are in stream actually, not a real object
553571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.comendobj
554571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.comendstream
555571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com8 0 obj #real obj
556571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com<< 100 >> #real obj
557571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.comendobj
558571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.comand it could get worse, with multiple object like this
559571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com*/
560571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
561571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com// right now implement the silly algorithm that assumes endstream is finishing the stream
562571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
563c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.comstatic const unsigned char* readStream(const unsigned char* start, const unsigned char* end,
564c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                       SkPdfNativeObject* dict, SkPdfNativeDoc* doc) {
565598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    start = skipPdfWhiteSpaces(start, end);
566c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    if (!(  start[0] == 's' &&
567c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            start[1] == 't' &&
568c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            start[2] == 'r' &&
569c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            start[3] == 'e' &&
570c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            start[4] == 'a' &&
571c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            start[5] == 'm')) {
572571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        // no stream. return.
573571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        return start;
574571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
575571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
576571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    start += 6; // strlen("stream")
577571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (start[0] == kCR_PdfWhiteSpace && start[1] == kLF_PdfWhiteSpace) {
578571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        start += 2;
579571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    } else if (start[0] == kLF_PdfWhiteSpace) {
580571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        start += 1;
58178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    } else if (isPdfWhiteSpace(start[0])) {
58278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        start += 1;
58378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    } else {
58478b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        // TODO(edisonn): warn it should be isPdfDelimiter(start[0])) ?
585571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
586571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
587571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    SkPdfStreamCommonDictionary* stream = (SkPdfStreamCommonDictionary*) dict;
588571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    // TODO(edisonn): load Length
589a3356fce903ff75dc332b53dd3a860ba810b9519edisonn@google.com    int64_t length = -1;
590571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
591571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    // TODO(edisonn): very basic implementation
592951d6532de49003cd5a43f57caf91dd6d3efc33eedisonn@google.com    if (stream->has_Length() && stream->Length(doc) > 0) {
593951d6532de49003cd5a43f57caf91dd6d3efc33eedisonn@google.com        length = stream->Length(doc);
594571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
595571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
596c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // TODO(edisonn): load external streams
597c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // TODO(edisonn): look at the last filter, to determine how to deal with possible parsing
598c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // issues. The last filter can have special rules to terminate a stream, which we could
599c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // use to determine end of stream.
6004ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
6014ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    if (length >= 0) {
6024ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        const unsigned char* endstream = start + length;
6034ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
6044ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        if (endstream[0] == kCR_PdfWhiteSpace && endstream[1] == kLF_PdfWhiteSpace) {
6054ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            endstream += 2;
6064ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        } else if (endstream[0] == kLF_PdfWhiteSpace) {
6074ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            endstream += 1;
6084ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        }
6094ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
6104ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        if (strncmp((const char*)endstream, "endstream", strlen("endstream")) != 0) {
6114ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            length = -1;
6124ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        }
6134ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    }
6144ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
615571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (length < 0) {
616571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        // scan the buffer, until we find first endstream
617571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        // TODO(edisonn): all buffers must have a 0 at the end now,
618c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        const unsigned char* endstream = (const unsigned char*)strrstrk((char*)start, (char*)end,
619c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                                                        "endstream");
620571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
621571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (endstream) {
622571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            length = endstream - start;
623571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            if (*(endstream-1) == kLF_PdfWhiteSpace) length--;
62478b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com            if (*(endstream-2) == kCR_PdfWhiteSpace) length--;
625571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
626571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
627571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (length >= 0) {
6282ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com        const unsigned char* endstream = start + length;
629571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
630571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (endstream[0] == kCR_PdfWhiteSpace && endstream[1] == kLF_PdfWhiteSpace) {
631571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            endstream += 2;
632571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        } else if (endstream[0] == kLF_PdfWhiteSpace) {
633571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            endstream += 1;
634571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
635571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
636571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        // TODO(edisonn): verify the next bytes are "endstream"
637571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
638571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        endstream += strlen("endstream");
639571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        // TODO(edisonn): Assert? report error/warning?
640a3356fce903ff75dc332b53dd3a860ba810b9519edisonn@google.com        dict->addStream(start, (size_t)length);
641571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        return endstream;
642571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
643571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return start;
644571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
645571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
646c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.comstatic const unsigned char* readInlineImageStream(const unsigned char* start,
647c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                                  const unsigned char* end,
648c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                                  SkPdfImageDictionary* inlineImage,
649c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                                  SkPdfNativeDoc* doc) {
65078b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    // We already processed ID keyword, and we should be positioned immediately after it
65178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
652c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // TODO(edisonn): security: either make all streams to have extra 2 bytes at the end,
653c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // instead of this if.
654c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    //if (end - start <= 2) {
655c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    //    // TODO(edisonn): warning?
656c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    //    return end; // but can we have a pixel image encoded in 1-2 bytes?
657c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    //}
658c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com
65978b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    if (start[0] == kCR_PdfWhiteSpace && start[1] == kLF_PdfWhiteSpace) {
66078b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        start += 2;
66178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    } else if (start[0] == kLF_PdfWhiteSpace) {
66278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        start += 1;
66378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    } else if (isPdfWhiteSpace(start[0])) {
66478b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        start += 1;
66578b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    } else {
66678b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        SkASSERT(isPdfDelimiter(start[0]));
66778b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        // TODO(edisonn): warning?
66878b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    }
66978b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
6702ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    const unsigned char* endstream = (const unsigned char*)strrstrk((char*)start, (char*)end, "EI");
6712ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    const unsigned char* endEI = endstream ? endstream + 2 : NULL;  // 2 == strlen("EI")
67278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
67378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    if (endstream) {
67478b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        int length = endstream - start;
67578b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        if (*(endstream-1) == kLF_PdfWhiteSpace) length--;
67678b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        if (*(endstream-2) == kCR_PdfWhiteSpace) length--;
67778b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        inlineImage->addStream(start, (size_t)length);
67878b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    } else {
67978b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        // TODO(edisonn): report error in inline image stream (ID-EI) section
68078b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        // TODO(edisonn): based on filter, try to ignore a missing EI, and read data properly
68178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        return end;
68278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    }
68378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    return endEI;
68478b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com}
68578b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
686c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.comstatic const unsigned char* readDictionary(const unsigned char* start, const unsigned char* end,
687c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                           SkPdfNativeObject* dict,
688c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                           SkPdfAllocator* allocator, SkPdfNativeDoc* doc) {
6891f080163ac58e0a5a621a720de5fc63e7b736765edisonn@google.com    if (allocator == NULL) {
6901f080163ac58e0a5a621a720de5fc63e7b736765edisonn@google.com        // TODO(edisonn): report/warning error
6911f080163ac58e0a5a621a720de5fc63e7b736765edisonn@google.com        return end;
6921f080163ac58e0a5a621a720de5fc63e7b736765edisonn@google.com    }
693598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    SkPdfNativeObject::makeEmptyDictionary(dict);
694598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    // PUT_TRACK_STREAM(dict, start, start)
695571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
696598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    start = skipPdfWhiteSpaces(start, end);
697c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    SkPdfAllocator tmpStorage;  // keys will be stored in dict, we can free them after set.
698571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
699571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    while (start < end && *start == kNamed_PdfDelimiter) {
7003aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com        SkPdfNativeObject key;
7012ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com        //*start = '\0';
702571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        start++;
703598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        start = readName(start, end, &key, &tmpStorage);
704598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        start = skipPdfWhiteSpaces(start, end);
705571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
706571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (start < end) {
7073aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com            SkPdfNativeObject* value = allocator->allocObject();
708598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com            start = nextObject(start, end, value, allocator, doc);
709571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
710598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com            start = skipPdfWhiteSpaces(start, end);
711571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
712571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            if (start < end) {
713c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                // We should have an indirect reference
714571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                if (isPdfDigit(*start)) {
7153aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com                    SkPdfNativeObject generation;
716598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com                    start = nextObject(start, end, &generation, allocator, doc);
717571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
7183aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com                    SkPdfNativeObject keywordR;
719598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com                    start = nextObject(start, end, &keywordR, allocator, doc);
720571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
721c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                    if (value->isInteger() && generation.isInteger() &&
722c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                            keywordR.isKeywordReference()) {
723571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        int64_t id = value->intValue();
724c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                        SkPdfNativeObject::resetAndMakeReference(
725c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                (unsigned int)id,
726c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                (unsigned int)generation.intValue(),
727c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                value);
728598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com                        //  PUT_TRACK_PARAMETERS_OBJ2(value, &generation)
729571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        dict->set(&key, value);
730571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    } else {
731c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                        // TODO(edisonn) error?, ignore it for now.
732571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                        dict->set(&key, value);
733571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    }
734571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                } else {
735571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    // next elem is not a digit, but it might not be / either!
736571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    dict->set(&key, value);
737571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                }
738571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            } else {
739571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                // /key >>
740571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                dict->set(&key, value);
741571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                return end;
742571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            }
743598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com            start = skipPdfWhiteSpaces(start, end);
744571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        } else {
7453aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com            dict->set(&key, &SkPdfNativeObject::kNull);
746571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            return end;
747571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
748571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
749571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
750571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    // now we should expect >>
751598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    start = skipPdfWhiteSpaces(start, end);
75278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    if (*start != kClosedInequityBracket_PdfDelimiter) {
75378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        // TODO(edisonn): report/warning
75478b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    }
755c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com
75678b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    start++;  // skip >
75778b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    if (*start != kClosedInequityBracket_PdfDelimiter) {
75878b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        // TODO(edisonn): report/warning
75978b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    }
760c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com
76178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    start++;  // skip >
762571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
763598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    //STORE_TRACK_PARAMETER_OFFSET_END(dict,start);
764bca421b468f53a591333918248f54bbd958389d2edisonn@google.com
765598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    start = readStream(start, end, dict, doc);
766571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
767571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return start;
768571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
769571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
770c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.comconst unsigned char* nextObject(const unsigned char* start, const unsigned char* end,
771c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                SkPdfNativeObject* token,
772c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                SkPdfAllocator* allocator, SkPdfNativeDoc* doc) {
7732ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    const unsigned char* current;
774571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
775571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    // skip white spaces
776598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    start = skipPdfWhiteSpaces(start, end);
777571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
778af54a513a5b7723b53f61730afe0ad6256881749edisonn@google.com    if (start >= end) {
779af54a513a5b7723b53f61730afe0ad6256881749edisonn@google.com        return end;
780af54a513a5b7723b53f61730afe0ad6256881749edisonn@google.com    }
781af54a513a5b7723b53f61730afe0ad6256881749edisonn@google.com
782598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    current = endOfPdfToken(start, end);
783571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
784571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    // no token, len would be 0
785af54a513a5b7723b53f61730afe0ad6256881749edisonn@google.com    if (current == start || current == end) {
786af54a513a5b7723b53f61730afe0ad6256881749edisonn@google.com        return end;
787571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
788571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
789571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    int tokenLen = current - start;
790571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
791571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (tokenLen == 1) {
792571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        // start array
793571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        switch (*start) {
794571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case kOpenedSquareBracket_PdfDelimiter:
795598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com                return readArray(current, end, token, allocator, doc);
796571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
797571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case kOpenedRoundBracket_PdfDelimiter:
798598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com                return readString(start + 1, end, token, allocator);
799571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
800571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case kOpenedInequityBracket_PdfDelimiter:
801571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                if (end > start + 1 && start[1] == kOpenedInequityBracket_PdfDelimiter) {
802571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                    // TODO(edisonn): pass here the length somehow?
803598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com                    return readDictionary(start + 2, end, token, allocator, doc);  // skip <<
804571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                } else {
805598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com                    return readHexString(start + 1, end, token, allocator);  // skip <
806571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                }
807571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
808571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case kNamed_PdfDelimiter:
809598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com                return readName(start + 1, end, token, allocator);
810571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
811c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            // TODO(edisonn): what to do curly brackets?
812571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            case kOpenedCurlyBracket_PdfDelimiter:
813571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            default:
814571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                break;
815571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
816571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
817571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        SkASSERT(!isPdfWhiteSpace(*start));
818571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (isPdfDelimiter(*start)) {
819c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            // TODO(edisonn): how unexpected stream ] } > ) will be handled?
820571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            // for now ignore, and it will become a keyword to be ignored
821571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
822571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
823571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
824571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (tokenLen == 4 && start[0] == 'n' && start[1] == 'u' && start[2] == 'l' && start[3] == 'l') {
825598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        SkPdfNativeObject::makeNull(token);
826598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        // PUT_TRACK_STREAM(start, start + 4)
827571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        return current;
828571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
829571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
830571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (tokenLen == 4 && start[0] == 't' && start[1] == 'r' && start[2] == 'u' && start[3] == 'e') {
831598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        SkPdfNativeObject::makeBoolean(true, token);
832598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        // PUT_TRACK_STREAM(start, start + 4)
833571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        return current;
834571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
835571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
836c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // TODO(edisonn): again, make all buffers have 5 extra bytes
837c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    if (tokenLen == 5 && start[0] == 'f' &&
838c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                         start[1] == 'a' &&
839c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                         start[2] == 'l' &&
840c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                         start[3] == 's' &&
841c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                         start[4] == 'e') {
842598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        SkPdfNativeObject::makeBoolean(false, token);
843598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        // PUT_TRACK_STREAM(start, start + 5)
844571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        return current;
845571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
846571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
847571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (isPdfNumeric(*start)) {
848598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        SkPdfNativeObject::makeNumeric(start, current, token);
849598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        //  PUT_TRACK_STREAM(start, current)
850571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    } else {
851598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        SkPdfNativeObject::makeKeyword(start, current, token);
852598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        // PUT_TRACK_STREAM(start, current)
853571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
854571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return current;
855571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
856571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
8573aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comSkPdfNativeObject* SkPdfAllocator::allocBlock() {
8583aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com    fSizeInBytes += BUFFER_SIZE * sizeof(SkPdfNativeObject);
8593aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com    return new SkPdfNativeObject[BUFFER_SIZE];
860571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
861571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
862571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.comSkPdfAllocator::~SkPdfAllocator() {
863571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    for (int i = 0 ; i < fHandles.count(); i++) {
864571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        free(fHandles[i]);
865571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
866571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    for (int i = 0 ; i < fHistory.count(); i++) {
867222382b30a176db9d9044d9df1ae14e0fbe27181edisonn@google.com        for (int j = 0 ; j < BUFFER_SIZE; j++) {
868222382b30a176db9d9044d9df1ae14e0fbe27181edisonn@google.com            fHistory[i][j].reset();
869222382b30a176db9d9044d9df1ae14e0fbe27181edisonn@google.com        }
870571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        delete[] fHistory[i];
871571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
872222382b30a176db9d9044d9df1ae14e0fbe27181edisonn@google.com    for (int j = 0 ; j < BUFFER_SIZE; j++) {
873222382b30a176db9d9044d9df1ae14e0fbe27181edisonn@google.com        fCurrent[j].reset();
874222382b30a176db9d9044d9df1ae14e0fbe27181edisonn@google.com    }
875571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    delete[] fCurrent;
876571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
877571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
8783aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comSkPdfNativeObject* SkPdfAllocator::allocObject() {
879571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (fCurrentUsed >= BUFFER_SIZE) {
880571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        fHistory.push(fCurrent);
881571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        fCurrent = allocBlock();
882571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        fCurrentUsed = 0;
8833aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com        fSizeInBytes += sizeof(SkPdfNativeObject*);
884571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
885571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    fCurrentUsed++;
886571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return &fCurrent[fCurrentUsed - 1];
887571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
888571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
889c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com// TODO(edisonn): perf: do no copy the buffers, but reuse them, and mark cache the result,
890c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com// so there is no need of a second pass
891c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.comSkPdfNativeTokenizer::SkPdfNativeTokenizer(SkPdfNativeObject* objWithStream,
892c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                           SkPdfAllocator* allocator,
893c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                           SkPdfNativeDoc* doc)
894c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            : fDoc(doc)
895c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            , fAllocator(allocator)
896c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            , fUncompressedStream(NULL)
897c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            , fUncompressedStreamEnd(NULL)
898c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            , fEmpty(false)
899c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            , fHasPutBack(false) {
9002ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    const unsigned char* buffer = NULL;
901571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    size_t len = 0;
9022ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    objWithStream->GetFilteredStreamRef(&buffer, &len);
903c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // TODO(edisonn): really bad hack, find end of object (endobj might be in a comment!)
904c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // we need to do now for perf, and our generated pdfs do not have comments,
905c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // but we need to remove this hack for pdfs in the wild
90678b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    char* endobj = strrstrk((char*)buffer, (char*)buffer + len, "endobj");
907222382b30a176db9d9044d9df1ae14e0fbe27181edisonn@google.com    if (endobj) {
908222382b30a176db9d9044d9df1ae14e0fbe27181edisonn@google.com        len = endobj - (char*)buffer + strlen("endobj");
909222382b30a176db9d9044d9df1ae14e0fbe27181edisonn@google.com    }
9102ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    fUncompressedStreamStart = fUncompressedStream = buffer;
911571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    fUncompressedStreamEnd = fUncompressedStream + len;
912222382b30a176db9d9044d9df1ae14e0fbe27181edisonn@google.com}
913571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
914c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.comSkPdfNativeTokenizer::SkPdfNativeTokenizer(const unsigned char* buffer, int len,
915c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                           SkPdfAllocator* allocator,
916c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                           SkPdfNativeDoc* doc) : fDoc(doc)
917c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                                                , fAllocator(allocator)
918c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                                                , fEmpty(false)
919c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                                                , fHasPutBack(false) {
920c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // TODO(edisonn): really bad hack, find end of object (endobj might be in a comment!)
921c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // we need to do now for perf, and our generated pdfs do not have comments,
922c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // but we need to remove this hack for pdfs in the wild
92378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    char* endobj = strrstrk((char*)buffer, (char*)buffer + len, "endobj");
924222382b30a176db9d9044d9df1ae14e0fbe27181edisonn@google.com    if (endobj) {
925222382b30a176db9d9044d9df1ae14e0fbe27181edisonn@google.com        len = endobj - (char*)buffer + strlen("endobj");
926222382b30a176db9d9044d9df1ae14e0fbe27181edisonn@google.com    }
9272ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    fUncompressedStreamStart = fUncompressedStream = buffer;
928571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    fUncompressedStreamEnd = fUncompressedStream + len;
9293aac1f9f308192f3787265830fe86ce8874e7382edisonn@google.com}
9303aac1f9f308192f3787265830fe86ce8874e7382edisonn@google.com
9313aac1f9f308192f3787265830fe86ce8874e7382edisonn@google.comSkPdfNativeTokenizer::~SkPdfNativeTokenizer() {
932571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
933571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
934571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.combool SkPdfNativeTokenizer::readTokenCore(PdfToken* token) {
93591ce698cf24c0a86fbdd5e09d29e7f4507a77fecedisonn@google.com#ifdef PDF_TRACE_READ_TOKEN
93691ce698cf24c0a86fbdd5e09d29e7f4507a77fecedisonn@google.com    static int read_op = 0;
93791ce698cf24c0a86fbdd5e09d29e7f4507a77fecedisonn@google.com#endif
938c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com
939571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    token->fKeyword = NULL;
940571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    token->fObject = NULL;
941571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
942598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    fUncompressedStream = skipPdfWhiteSpaces(fUncompressedStream, fUncompressedStreamEnd);
943571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (fUncompressedStream >= fUncompressedStreamEnd) {
9445092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com        fEmpty = true;
945571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        return false;
946571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
947571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
948c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    SkPdfNativeObject obj;
949598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    fUncompressedStream = nextObject(fUncompressedStream, fUncompressedStreamEnd, &obj, fAllocator, fDoc);
950598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    //  PUT_TRACK_STREAM_ARGS_EXPL2(fStreamId, fUncompressedStreamStart)
951571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
952c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // If it is a keyword, we will only get the pointer of the string.
9533aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com    if (obj.type() == SkPdfNativeObject::kKeyword_PdfObjectType) {
954571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        token->fKeyword = obj.c_str();
955e878e726bd1c16a0d177543471e071c7338193f4edisonn@google.com        token->fKeywordLength = obj.lenstr();
956571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        token->fType = kKeyword_TokenType;
957571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    } else {
9583aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com        SkPdfNativeObject* pobj = fAllocator->allocObject();
959571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        *pobj = obj;
960571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        token->fObject = pobj;
961571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        token->fType = kObject_TokenType;
962571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
963571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
9642ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com#ifdef PDF_TRACE_READ_TOKEN
965571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    read_op++;
966b0145ce60ea1a3bacc786ec1285218c6fe70c8a3edisonn@google.com#if 0
967222382b30a176db9d9044d9df1ae14e0fbe27181edisonn@google.com    if (548 == read_op) {
968571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        printf("break;\n");
969571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
970b0145ce60ea1a3bacc786ec1285218c6fe70c8a3edisonn@google.com#endif
971c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    printf("%i READ %s %s\n", read_op, token->fType == kKeyword_TokenType ? "Keyword" : "Object",
972c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com           token->fKeyword ? SkString(token->fKeyword, token->fKeywordLength).c_str() :
973c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                             token->fObject->toString().c_str());
974571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com#endif
975571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
976571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return true;
977571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
978571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
979571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.comvoid SkPdfNativeTokenizer::PutBack(PdfToken token) {
980571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    SkASSERT(!fHasPutBack);
981571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    fHasPutBack = true;
982571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    fPutBack = token;
9832ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com#ifdef PDF_TRACE_READ_TOKEN
984c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    printf("PUT_BACK %s %s\n", token.fType == kKeyword_TokenType ? "Keyword" : "Object",
985c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com           token.fKeyword ? SkString(token.fKeyword, token.fKeywordLength).c_str() :
986c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                            token.fObject->toString().c_str());
987571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com#endif
988571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
989571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
9905092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.combool SkPdfNativeTokenizer::readToken(PdfToken* token, bool writeDiff) {
991571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (fHasPutBack) {
992571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        *token = fPutBack;
993571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        fHasPutBack = false;
9942ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com#ifdef PDF_TRACE_READ_TOKEN
9955092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com        printf("READ_BACK %s %s\n", token->fType == kKeyword_TokenType ? "Keyword" : "Object",
9965092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com               token->fKeyword ? SkString(token->fKeyword, token->fKeywordLength).c_str() :
9975092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                                 token->fObject->toString().c_str());
998571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com#endif
9995092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com        if (writeDiff) {
10005092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            SkPdfDiffEncoder::WriteToFile(token);
10015092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com        }
1002571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        return true;
1003571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
1004571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
1005571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (fEmpty) {
10062ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com#ifdef PDF_TRACE_READ_TOKEN
10075092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com        printf("EMPTY TOKENIZER\n");
1008571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com#endif
1009571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        return false;
1010571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
1011571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
10125092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    const bool result = readTokenCore(token);
10135092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    if (result && writeDiff) {
10145092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com        SkPdfDiffEncoder::WriteToFile(token);
10155092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    }
10165092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    return result;
10173aac1f9f308192f3787265830fe86ce8874e7382edisonn@google.com}
101878b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
101978b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com#define DECLARE_PDF_NAME(longName) SkPdfName longName((char*)#longName)
102078b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
102178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com// keys
102278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(BitsPerComponent);
102378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(ColorSpace);
102478b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(Decode);
102578b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(DecodeParms);
102678b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(Filter);
102778b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(Height);
102878b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(ImageMask);
1029c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.comDECLARE_PDF_NAME(Intent); // PDF 1.1 - the key, or the abBreviations?
103078b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(Interpolate);
103178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(Width);
103278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
103378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com// values
103478b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(DeviceGray);
103578b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(DeviceRGB);
103678b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(DeviceCMYK);
103778b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(Indexed);
103878b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(ASCIIHexDecode);
103978b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(ASCII85Decode);
104078b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(LZWDecode);
104178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(FlateDecode);  // PDF 1.2
104278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(RunLengthDecode);
104378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(CCITTFaxDecode);
104478b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comDECLARE_PDF_NAME(DCTDecode);
104578b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
104678b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com#define HANDLE_NAME_ABBR(obj,longName,shortName) if (obj->isName(#shortName)) return &longName;
104778b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
104878b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
10493aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comstatic SkPdfNativeObject* inlineImageKeyAbbreviationExpand(SkPdfNativeObject* key) {
105078b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    if (!key || !key->isName()) {
105178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        return key;
105278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    }
105378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
105478b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    // TODO(edisonn): use autogenerated code!
105578b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(key, BitsPerComponent, BPC);
105678b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(key, ColorSpace, CS);
105778b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(key, Decode, D);
105878b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(key, DecodeParms, DP);
105978b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(key, Filter, F);
106078b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(key, Height, H);
106178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(key, ImageMask, IM);
106278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com//    HANDLE_NAME_ABBR(key, Intent, );
106378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(key, Interpolate, I);
106478b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(key, Width, W);
106578b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
106678b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    return key;
106778b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com}
106878b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
10693aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comstatic SkPdfNativeObject* inlineImageValueAbbreviationExpand(SkPdfNativeObject* value) {
107078b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    if (!value || !value->isName()) {
107178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        return value;
107278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    }
107378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
107478b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    // TODO(edisonn): use autogenerated code!
107578b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(value, DeviceGray, G);
107678b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(value, DeviceRGB, RGB);
107778b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(value, DeviceCMYK, CMYK);
107878b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(value, Indexed, I);
107978b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(value, ASCIIHexDecode, AHx);
108078b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(value, ASCII85Decode, A85);
108178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(value, LZWDecode, LZW);
108278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(value, FlateDecode, Fl);  // (PDF 1.2)
108378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(value, RunLengthDecode, RL);
108478b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(value, CCITTFaxDecode, CCF);
108578b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    HANDLE_NAME_ABBR(value, DCTDecode, DCT);
108678b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
108778b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    return value;
108878b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com}
108978b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
109078b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.comSkPdfImageDictionary* SkPdfNativeTokenizer::readInlineImage() {
109178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    // BI already processed
1092598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    fUncompressedStream = skipPdfWhiteSpaces(fUncompressedStream, fUncompressedStreamEnd);
109378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    if (fUncompressedStream >= fUncompressedStreamEnd) {
109478b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        return NULL;
109578b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    }
109678b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
109778b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    SkPdfImageDictionary* inlineImage = (SkPdfImageDictionary*)fAllocator->allocObject();
1098598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    SkPdfNativeObject::makeEmptyDictionary(inlineImage);
1099c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    //  PUT_TRACK_STREAM_ARGS_EXPL(fStreamId, fUncompressedStream - fUncompressedStreamStart,
1100c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    //                             fUncompressedStream - fUncompressedStreamStart)
110178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
110278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    while (fUncompressedStream < fUncompressedStreamEnd) {
11033aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com        SkPdfNativeObject* key = fAllocator->allocObject();
1104c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        fUncompressedStream = nextObject(fUncompressedStream, fUncompressedStreamEnd, key,
1105c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                         fAllocator, fDoc);
1106598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        // PUT_TRACK_STREAM_ARGS_EXPL2(fStreamId, fUncompressedStreamStart)s
110778b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com
1108c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        if (key->isKeyword() && key->lenstr() == 2 &&
1109c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                    key->c_str()[0] == 'I' && key->c_str()[1] == 'D') { // ID
1110c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            fUncompressedStream = readInlineImageStream(fUncompressedStream, fUncompressedStreamEnd,
1111c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                                        inlineImage, fDoc);
111278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com            return inlineImage;
111378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        } else {
11143aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com            SkPdfNativeObject* obj = fAllocator->allocObject();
1115c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            fUncompressedStream = nextObject(fUncompressedStream, fUncompressedStreamEnd, obj,
1116c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                             fAllocator, fDoc);
1117598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com            //  PUT_TRACK_STREAM_ARGS_EXPL2(fStreamId, fUncompressedStreamStart)s
1118c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            // TODO(edisonn): perf maybe we should not expand abBreviation like this
111978b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com            inlineImage->set(inlineImageKeyAbbreviationExpand(key),
112078b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com                             inlineImageValueAbbreviationExpand(obj));
112178b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com        }
112278b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    }
112378b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    // TODO(edisonn): report end of data with inline image without an EI
112478b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com    return inlineImage;
112578b38b130deb8bcfa41611039875ce0162542ac1edisonn@google.com}
1126