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 */
7cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com
83aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com#include "SkPdfNativeDoc.h"
9571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
10571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com#include <stdio.h>
11571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com#include <string.h>
12571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com#include <sys/types.h>
13571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com#include <sys/stat.h>
14571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
15c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com#include "SkPdfMapper_autogen.h"
16c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com#include "SkPdfNativeObject.h"
17c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com#include "SkPdfNativeTokenizer.h"
18c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com#include "SkPdfReporter.h"
19c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com#include "SkStream.h"
20c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com
2133f11b6fcdb7dfce27f953803be40fbacedc7450edisonn@google.com// TODO(edisonn): for some reason on mac these files are found here, but are found from headers
2233f11b6fcdb7dfce27f953803be40fbacedc7450edisonn@google.com//#include "SkPdfFileTrailerDictionary_autogen.h"
2333f11b6fcdb7dfce27f953803be40fbacedc7450edisonn@google.com//#include "SkPdfCatalogDictionary_autogen.h"
2433f11b6fcdb7dfce27f953803be40fbacedc7450edisonn@google.com//#include "SkPdfPageObjectDictionary_autogen.h"
2533f11b6fcdb7dfce27f953803be40fbacedc7450edisonn@google.com//#include "SkPdfPageTreeNodeDictionary_autogen.h"
2633f11b6fcdb7dfce27f953803be40fbacedc7450edisonn@google.com#include "SkPdfHeaders_autogen.h"
2733f11b6fcdb7dfce27f953803be40fbacedc7450edisonn@google.com
28a3356fce903ff75dc332b53dd3a860ba810b9519edisonn@google.comstatic long getFileSize(const char* filename)
29571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com{
30571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    struct stat stat_buf;
31571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    int rc = stat(filename, &stat_buf);
32a3356fce903ff75dc332b53dd3a860ba810b9519edisonn@google.com    return rc == 0 ? (long)stat_buf.st_size : -1;
33571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
34571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
352ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.comstatic const unsigned char* lineHome(const unsigned char* start, const unsigned char* current) {
36571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    while (current > start && !isPdfEOL(*(current - 1))) {
37571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        current--;
38571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
39571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return current;
40571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
41571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
42c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.comstatic const unsigned char* previousLineHome(const unsigned char* start,
43c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                             const unsigned char* current) {
44571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (current > start && isPdfEOL(*(current - 1))) {
45571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        current--;
46571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
47571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
48571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    // allows CR+LF, LF+CR but not two CR+CR or LF+LF
49571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (current > start && isPdfEOL(*(current - 1)) && *current != *(current - 1)) {
50571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        current--;
51571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
52571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
53571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    while (current > start && !isPdfEOL(*(current - 1))) {
54571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        current--;
55571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
56571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
57571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return current;
58571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
59571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
602ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.comstatic const unsigned char* ignoreLine(const unsigned char* current, const unsigned char* end) {
61571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    while (current < end && !isPdfEOL(*current)) {
62571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        current++;
63571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
64571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    current++;
65571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (current < end && isPdfEOL(*current) && *current != *(current - 1)) {
66571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        current++;
67571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
68571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return current;
69571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
70571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
713aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comSkPdfNativeDoc* gDoc = NULL;
72571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
733aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comSkPdfNativeDoc::SkPdfNativeDoc(SkStream* stream)
74147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com        : fAllocator(new SkPdfAllocator())
75147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com        , fFileContent(NULL)
76147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com        , fContentLength(0)
77147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com        , fRootCatalogRef(NULL)
78147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com        , fRootCatalog(NULL) {
79147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com    size_t size = stream->getLength();
80147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com    void* ptr = sk_malloc_throw(size);
81147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com    stream->read(ptr, size);
82147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com
83147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com    init(ptr, size);
84147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com}
85147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com
863aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comSkPdfNativeDoc::SkPdfNativeDoc(const char* path)
87432640ae0b9f4bc40e3447651ff5be0cd2be6b11edisonn@google.com        : fAllocator(new SkPdfAllocator())
88147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com        , fFileContent(NULL)
89147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com        , fContentLength(0)
90432640ae0b9f4bc40e3447651ff5be0cd2be6b11edisonn@google.com        , fRootCatalogRef(NULL)
91432640ae0b9f4bc40e3447651ff5be0cd2be6b11edisonn@google.com        , fRootCatalog(NULL) {
92222382b30a176db9d9044d9df1ae14e0fbe27181edisonn@google.com    gDoc = this;
93571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    FILE* file = fopen(path, "r");
94e57c62d039cbd67a4e52776b3e95c5d002b818d2edisonn@google.com    // TODO(edisonn): put this in a function that can return NULL
95e57c62d039cbd67a4e52776b3e95c5d002b818d2edisonn@google.com    if (file) {
96e57c62d039cbd67a4e52776b3e95c5d002b818d2edisonn@google.com        size_t size = getFileSize(path);
97e57c62d039cbd67a4e52776b3e95c5d002b818d2edisonn@google.com        void* content = sk_malloc_throw(size);
98e57c62d039cbd67a4e52776b3e95c5d002b818d2edisonn@google.com        bool ok = (0 != fread(content, size, 1, file));
99e57c62d039cbd67a4e52776b3e95c5d002b818d2edisonn@google.com        fclose(file);
100e57c62d039cbd67a4e52776b3e95c5d002b818d2edisonn@google.com        if (!ok) {
101e57c62d039cbd67a4e52776b3e95c5d002b818d2edisonn@google.com            sk_free(content);
102c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            SkPdfReport(kFatalError_SkPdfIssueSeverity, kReadStreamError_SkPdfIssue,
103c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                        "could not read file", NULL, NULL);
104e57c62d039cbd67a4e52776b3e95c5d002b818d2edisonn@google.com            // TODO(edisonn): not nice to return like this from constructor, create a static
105e57c62d039cbd67a4e52776b3e95c5d002b818d2edisonn@google.com            // function that can report NULL for failures.
106e57c62d039cbd67a4e52776b3e95c5d002b818d2edisonn@google.com            return;  // Doc will have 0 pages
107e57c62d039cbd67a4e52776b3e95c5d002b818d2edisonn@google.com        }
108e57c62d039cbd67a4e52776b3e95c5d002b818d2edisonn@google.com
109e57c62d039cbd67a4e52776b3e95c5d002b818d2edisonn@google.com        init(content, size);
110620edc503938e3bfb7621923c2f50e77451fecaeedisonn@google.com    }
111147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com}
112147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com
1133aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comvoid SkPdfNativeDoc::init(const void* bytes, size_t length) {
114147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com    fFileContent = (const unsigned char*)bytes;
115147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com    fContentLength = length;
1162ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    const unsigned char* eofLine = lineHome(fFileContent, fFileContent + fContentLength - 1);
1172ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    const unsigned char* xrefByteOffsetLine = previousLineHome(fFileContent, eofLine);
1182ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    const unsigned char* xrefstartKeywordLine = previousLineHome(fFileContent, xrefByteOffsetLine);
119571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
120571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (strcmp((char*)xrefstartKeywordLine, "startxref") != 0) {
121c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        SkPdfReport(kWarning_SkPdfIssueSeverity, kMissingToken_SkPdfIssue,
122c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                    "Could not find startxref", NULL, NULL);
123571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
124571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
125571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    long xrefByteOffset = atol((const char*)xrefByteOffsetLine);
126571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
127571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    bool storeCatalog = true;
128571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    while (xrefByteOffset >= 0) {
129909228992c1671ea7451d1c6bc588a8ec991841escroggo@google.com        const unsigned char* trailerStart = this->readCrossReferenceSection(fFileContent + xrefByteOffset,
130909228992c1671ea7451d1c6bc588a8ec991841escroggo@google.com                                                                            xrefstartKeywordLine);
13124cdf13b314889a2bfa50969c5a85b74aa49ea1dedisonn@google.com        xrefByteOffset = -1;
13224cdf13b314889a2bfa50969c5a85b74aa49ea1dedisonn@google.com        if (trailerStart < xrefstartKeywordLine) {
133909228992c1671ea7451d1c6bc588a8ec991841escroggo@google.com            this->readTrailer(trailerStart, xrefstartKeywordLine, storeCatalog, &xrefByteOffset, false);
13424cdf13b314889a2bfa50969c5a85b74aa49ea1dedisonn@google.com            storeCatalog = false;
13524cdf13b314889a2bfa50969c5a85b74aa49ea1dedisonn@google.com        }
136571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
137571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
138571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    // TODO(edisonn): warn/error expect fObjects[fRefCatalogId].fGeneration == fRefCatalogGeneration
139571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    // TODO(edisonn): security, verify that SkPdfCatalogDictionary is indeed using mapper
1403aac1f9f308192f3787265830fe86ce8874e7382edisonn@google.com
141432640ae0b9f4bc40e3447651ff5be0cd2be6b11edisonn@google.com    if (fRootCatalogRef) {
142432640ae0b9f4bc40e3447651ff5be0cd2be6b11edisonn@google.com        fRootCatalog = (SkPdfCatalogDictionary*)resolveReference(fRootCatalogRef);
143608c35e5c4ce61a79b7a0567c8eca569332c2ddeedisonn@google.com        if (fRootCatalog != NULL && fRootCatalog->isDictionary() && fRootCatalog->valid()) {
1448bad7375d7e0ebe28af4d905665f34227843bd16edisonn@google.com            SkPdfPageTreeNodeDictionary* tree = fRootCatalog->Pages(this);
1458bad7375d7e0ebe28af4d905665f34227843bd16edisonn@google.com            if (tree && tree->isDictionary() && tree->valid()) {
1468bad7375d7e0ebe28af4d905665f34227843bd16edisonn@google.com                fillPages(tree);
1478bad7375d7e0ebe28af4d905665f34227843bd16edisonn@google.com            }
1488bad7375d7e0ebe28af4d905665f34227843bd16edisonn@google.com        }
149432640ae0b9f4bc40e3447651ff5be0cd2be6b11edisonn@google.com    }
1503aac1f9f308192f3787265830fe86ce8874e7382edisonn@google.com
1514ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    if (pages() == 0) {
152c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // TODO(edisonn): probably it would be better to return NULL and make a clean document.
1534ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        loadWithoutXRef();
1544ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    }
1554ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
156c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // TODO(edisonn): corrupted pdf, read it from beginning and rebuild
157c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // (xref, trailer, or just read all objects)
1583aac1f9f308192f3787265830fe86ce8874e7382edisonn@google.com}
1593aac1f9f308192f3787265830fe86ce8874e7382edisonn@google.com
1603aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comvoid SkPdfNativeDoc::loadWithoutXRef() {
1614ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    const unsigned char* current = fFileContent;
1624ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    const unsigned char* end = fFileContent + fContentLength;
1634ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
1644ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    // TODO(edisonn): read pdf version
1654ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    current = ignoreLine(current, end);
1664ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
167598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    current = skipPdfWhiteSpaces(current, end);
1684ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    while (current < end) {
1693aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com        SkPdfNativeObject token;
170598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        current = nextObject(current, end, &token, NULL, NULL);
1714ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        if (token.isInteger()) {
1724ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            int id = (int)token.intValue();
1734ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
1744ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            token.reset();
175598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com            current = nextObject(current, end, &token, NULL, NULL);
176c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            // TODO(edisonn): generation ignored for now (used in pdfs with updates)
177c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            // int generation = (int)token.intValue();
1784ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
1794ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            token.reset();
180598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com            current = nextObject(current, end, &token, NULL, NULL);
181c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            // TODO(edisonn): keywork must be "obj". Add ability to report error instead ignoring.
1824ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            if (!token.isKeyword("obj")) {
183c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                SkPdfReport(kWarning_SkPdfIssueSeverity, kMissingToken_SkPdfIssue,
184c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                            "Could not find obj", NULL, NULL);
1854ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com                continue;
1864ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            }
1874ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
1884ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            while (fObjects.count() < id + 1) {
1894ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com                reset(fObjects.append());
1904ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            }
1914ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
1924ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            fObjects[id].fOffset = current - fFileContent;
1934ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
1943aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com            SkPdfNativeObject* obj = fAllocator->allocObject();
195598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com            current = nextObject(current, end, obj, fAllocator, this);
1964ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
1974ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            fObjects[id].fResolvedReference = obj;
1984ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            fObjects[id].fObj = obj;
199af54a513a5b7723b53f61730afe0ad6256881749edisonn@google.com            fObjects[id].fIsReferenceResolved = true;
2004ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        } else if (token.isKeyword("trailer")) {
2014ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            long dummy;
2024ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            current = readTrailer(current, end, true, &dummy, true);
2034ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        } else if (token.isKeyword("startxref")) {
2044ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            token.reset();
205c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            current = nextObject(current, end, &token, NULL, NULL);  // ignore startxref
2064ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        }
2074ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
208598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        current = skipPdfWhiteSpaces(current, end);
2094ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    }
2104ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
211c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // TODO(edisonn): quick hack, detect root catalog. When we implement linearized support we
212c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // might not need it.
2134f898b78bb1c04e4763eca59a6e1defef555e696edisonn@google.com    if (!fRootCatalogRef) {
2144f898b78bb1c04e4763eca59a6e1defef555e696edisonn@google.com        for (unsigned int i = 0 ; i < objects(); i++) {
2153aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com            SkPdfNativeObject* obj = object(i);
2163aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com            SkPdfNativeObject* root = (obj && obj->isDictionary()) ? obj->get("Root") : NULL;
2174f898b78bb1c04e4763eca59a6e1defef555e696edisonn@google.com            if (root && root->isReference()) {
2184f898b78bb1c04e4763eca59a6e1defef555e696edisonn@google.com                fRootCatalogRef = root;
2194f898b78bb1c04e4763eca59a6e1defef555e696edisonn@google.com            }
2204f898b78bb1c04e4763eca59a6e1defef555e696edisonn@google.com        }
2214f898b78bb1c04e4763eca59a6e1defef555e696edisonn@google.com    }
2224f898b78bb1c04e4763eca59a6e1defef555e696edisonn@google.com
2234ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    if (fRootCatalogRef) {
2244ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        fRootCatalog = (SkPdfCatalogDictionary*)resolveReference(fRootCatalogRef);
225608c35e5c4ce61a79b7a0567c8eca569332c2ddeedisonn@google.com        if (fRootCatalog != NULL && fRootCatalog->isDictionary() && fRootCatalog->valid()) {
2264ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            SkPdfPageTreeNodeDictionary* tree = fRootCatalog->Pages(this);
2274ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            if (tree && tree->isDictionary() && tree->valid()) {
2284ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com                fillPages(tree);
2294ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            }
2304ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        }
2314ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    }
2324ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
2334f898b78bb1c04e4763eca59a6e1defef555e696edisonn@google.com
2344ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com}
2354ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
2363aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comSkPdfNativeDoc::~SkPdfNativeDoc() {
237147adb10f7f80ae721879e08474fd575e719487cedisonn@google.com    sk_free((void*)fFileContent);
238571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    delete fAllocator;
239571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
240571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
241c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.comconst unsigned char* SkPdfNativeDoc::readCrossReferenceSection(const unsigned char* xrefStart,
242c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                                               const unsigned char* trailerEnd) {
2433aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com    SkPdfNativeObject xref;
244598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    const unsigned char* current = nextObject(xrefStart, trailerEnd, &xref, NULL, NULL);
2452273f9b45fb78b0cc7df81f96f74b0c3c0e6cc37edisonn@google.com
2462273f9b45fb78b0cc7df81f96f74b0c3c0e6cc37edisonn@google.com    if (!xref.isKeyword("xref")) {
247c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        SkPdfReport(kWarning_SkPdfIssueSeverity, kMissingToken_SkPdfIssue, "Could not find sref",
248c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                    NULL, NULL);
2492273f9b45fb78b0cc7df81f96f74b0c3c0e6cc37edisonn@google.com        return trailerEnd;
2502273f9b45fb78b0cc7df81f96f74b0c3c0e6cc37edisonn@google.com    }
251571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
2523aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com    SkPdfNativeObject token;
253571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    while (current < trailerEnd) {
254571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        token.reset();
2552ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com        const unsigned char* previous = current;
256598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        current = nextObject(current, trailerEnd, &token, NULL, NULL);
257571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (!token.isInteger()) {
258c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            SkPdfReport(kInfo_SkPdfIssueSeverity, kNoIssue_SkPdfIssue,
259c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                        "Done readCrossReferenceSection", NULL, NULL);
260571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            return previous;
261571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
262571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
263a3356fce903ff75dc332b53dd3a860ba810b9519edisonn@google.com        int startId = (int)token.intValue();
264571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        token.reset();
265598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        current = nextObject(current, trailerEnd, &token, NULL, NULL);
266571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
267571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (!token.isInteger()) {
268c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "readCrossReferenceSection",
269c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                      &token, SkPdfNativeObject::kInteger_PdfObjectType, NULL);
270571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            return current;
271571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
272571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
273a3356fce903ff75dc332b53dd3a860ba810b9519edisonn@google.com        int entries = (int)token.intValue();
274571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
275571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        for (int i = 0; i < entries; i++) {
276571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            token.reset();
277598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com            current = nextObject(current, trailerEnd, &token, NULL, NULL);
278571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            if (!token.isInteger()) {
279c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity,
280c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                          "readCrossReferenceSection",
281c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                          &token, SkPdfNativeObject::kInteger_PdfObjectType, NULL);
282571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                return current;
283571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            }
284a3356fce903ff75dc332b53dd3a860ba810b9519edisonn@google.com            int offset = (int)token.intValue();
285571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
286571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            token.reset();
287598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com            current = nextObject(current, trailerEnd, &token, NULL, NULL);
288571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            if (!token.isInteger()) {
289c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity,
290c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                          "readCrossReferenceSection",
291c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                          &token, SkPdfNativeObject::kInteger_PdfObjectType, NULL);
292571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                return current;
293571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            }
294a3356fce903ff75dc332b53dd3a860ba810b9519edisonn@google.com            int generation = (int)token.intValue();
295571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
296571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            token.reset();
297598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com            current = nextObject(current, trailerEnd, &token, NULL, NULL);
298c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            if (!token.isKeyword() || token.lenstr() != 1 ||
299c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                (*token.c_str() != 'f' && *token.c_str() != 'n')) {
300c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity,
301c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                          "readCrossReferenceSection: f or n expected",
302c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                          &token, SkPdfNativeObject::kKeyword_PdfObjectType, NULL);
303571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                return current;
304571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            }
305571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
306909228992c1671ea7451d1c6bc588a8ec991841escroggo@google.com            this->addCrossSectionInfo(startId + i, generation, offset, *token.c_str() == 'f');
307571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
308571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
309c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    SkPdfReport(kInfo_SkPdfIssueSeverity, kNoIssue_SkPdfIssue,
310c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                "Unexpected end of readCrossReferenceSection", NULL, NULL);
311571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return current;
312571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
313571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
314c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.comconst unsigned char* SkPdfNativeDoc::readTrailer(const unsigned char* trailerStart,
315c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                                 const unsigned char* trailerEnd,
316c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                                 bool storeCatalog, long* prev, bool skipKeyword) {
3174ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    *prev = -1;
3184ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
3194ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    const unsigned char* current = trailerStart;
3204ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    if (!skipKeyword) {
3213aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com        SkPdfNativeObject trailerKeyword;
322c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // Use null allocator, and let it just fail if memory, it should not crash.
323598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com        current = nextObject(current, trailerEnd, &trailerKeyword, NULL, NULL);
3244ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com
3254ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        if (!trailerKeyword.isKeyword() || strlen("trailer") != trailerKeyword.lenstr() ||
3264ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            strncmp(trailerKeyword.c_str(), "trailer", strlen("trailer")) != 0) {
327c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity,
328c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                      "readTrailer: trailer keyword expected",
329c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                      &trailerKeyword,
330c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                      SkPdfNativeObject::kKeyword_PdfObjectType, NULL);
3314ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            return current;
3324ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        }
3332ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    }
334571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
3353aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com    SkPdfNativeObject token;
336598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    current = nextObject(current, trailerEnd, &token, fAllocator, NULL);
337432640ae0b9f4bc40e3447651ff5be0cd2be6b11edisonn@google.com    if (!token.isDictionary()) {
3384ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        return current;
339432640ae0b9f4bc40e3447651ff5be0cd2be6b11edisonn@google.com    }
340571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    SkPdfFileTrailerDictionary* trailer = (SkPdfFileTrailerDictionary*)&token;
341432640ae0b9f4bc40e3447651ff5be0cd2be6b11edisonn@google.com    if (!trailer->valid()) {
3424ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        return current;
343432640ae0b9f4bc40e3447651ff5be0cd2be6b11edisonn@google.com    }
344571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
345571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (storeCatalog) {
3463aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com        SkPdfNativeObject* ref = trailer->Root(NULL);
347571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (ref == NULL || !ref->isReference()) {
348c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity,
349c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                      "readTrailer: unexpected root reference",
350c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                      ref, SkPdfNativeObject::kReference_PdfObjectType, NULL);
3514ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com            return current;
352571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
353571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        fRootCatalogRef = ref;
354571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
355571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
356571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (trailer->has_Prev()) {
3574ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com        *prev = (long)trailer->Prev(NULL);
358571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
359571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
3604ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    return current;
361571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
362571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
3633aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comvoid SkPdfNativeDoc::addCrossSectionInfo(int id, int generation, int offset, bool isFreed) {
364c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // TODO(edisonn): security here, verify id
365571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    while (fObjects.count() < id + 1) {
366909228992c1671ea7451d1c6bc588a8ec991841escroggo@google.com        this->reset(fObjects.append());
367571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
368571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
369571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    fObjects[id].fOffset = offset;
370571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    fObjects[id].fObj = NULL;
3714ef4bed00efd247a0ea005b95b7239a9d4c14c68edisonn@google.com    fObjects[id].fResolvedReference = NULL;
372f68aed33819cbc98a95edeadde1da9303eca7fb2edisonn@google.com    fObjects[id].fIsReferenceResolved = false;
373571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
374571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
3753aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comSkPdfNativeObject* SkPdfNativeDoc::readObject(int id/*, int expectedGeneration*/) {
376571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    long startOffset = fObjects[id].fOffset;
377571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    //long endOffset = fObjects[id].fOffsetEnd;
378571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    // TODO(edisonn): use hinted endOffset
3792ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    const unsigned char* current = fFileContent + startOffset;
3802ccc3afa474f9485c39c2e863252ddaa3f35724bedisonn@google.com    const unsigned char* end = fFileContent + fContentLength;
381571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
3825f008652f69ce7809b920b9fa573bc72216acd51scroggo@google.com    SkPdfNativeTokenizer tokenizer(current, (int) (end - current), fAllocator, this);
383571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
3843aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com    SkPdfNativeObject idObj;
3853aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com    SkPdfNativeObject generationObj;
3863aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com    SkPdfNativeObject objKeyword;
3873aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com    SkPdfNativeObject* dict = fAllocator->allocObject();
388571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
389598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    current = nextObject(current, end, &idObj, NULL, NULL);
390571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (current >= end) {
391c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kReadStreamError_SkPdfIssue, "reading id",
392c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                    NULL, NULL);
393571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        return NULL;
394571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
395571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
396598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    current = nextObject(current, end, &generationObj, NULL, NULL);
397571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (current >= end) {
398c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kReadStreamError_SkPdfIssue,
399c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                    "reading generation", NULL, NULL);
400571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        return NULL;
401571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
402571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
403598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    current = nextObject(current, end, &objKeyword, NULL, NULL);
404571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (current >= end) {
405c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kReadStreamError_SkPdfIssue,
406c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                    "reading keyword obj", NULL, NULL);
407571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        return NULL;
408571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
409571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
410af54a513a5b7723b53f61730afe0ad6256881749edisonn@google.com    if (!idObj.isInteger() || id != idObj.intValue()) {
411c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "readObject: unexpected id",
412c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                  &idObj, SkPdfNativeObject::kInteger_PdfObjectType, NULL);
413af54a513a5b7723b53f61730afe0ad6256881749edisonn@google.com    }
414af54a513a5b7723b53f61730afe0ad6256881749edisonn@google.com
415af54a513a5b7723b53f61730afe0ad6256881749edisonn@google.com    // TODO(edisonn): verify that the generation is the right one
416af54a513a5b7723b53f61730afe0ad6256881749edisonn@google.com    if (!generationObj.isInteger() /* || generation != generationObj.intValue()*/) {
417c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity,
418c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                  "readObject: unexpected generation",
419c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                  &generationObj, SkPdfNativeObject::kInteger_PdfObjectType, NULL);
420571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
421571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
422571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (!objKeyword.isKeyword() || strcmp(objKeyword.c_str(), "obj") != 0) {
423c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity,
424c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                  "readObject: unexpected obj keyword",
425c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                                  &objKeyword, SkPdfNativeObject::kKeyword_PdfObjectType, NULL);
426571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
427571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
428598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    current = nextObject(current, end, dict, fAllocator, this);
429571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
430c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    // TODO(edisonn): report warning/error - verify that the last token is endobj
431571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
432571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return dict;
433571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
434571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
4353aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comvoid SkPdfNativeDoc::fillPages(SkPdfPageTreeNodeDictionary* tree) {
436b0145ce60ea1a3bacc786ec1285218c6fe70c8a3edisonn@google.com    SkPdfArray* kids = tree->Kids(this);
437571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (kids == NULL) {
438571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        *fPages.append() = (SkPdfPageObjectDictionary*)tree;
439571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        return;
440571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
441571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
4425f008652f69ce7809b920b9fa573bc72216acd51scroggo@google.com    int cnt = (int) kids->size();
443571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    for (int i = 0; i < cnt; i++) {
4443aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com        SkPdfNativeObject* obj = resolveReference(kids->objAtAIndex(i));
4453aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com        if (fMapper->mapPageObjectDictionary(obj) != kPageObjectDictionary_SkPdfNativeObjectType) {
446571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            *fPages.append() = (SkPdfPageObjectDictionary*)obj;
447571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        } else {
448571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            // TODO(edisonn): verify that it is a page tree indeed
449571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            fillPages((SkPdfPageTreeNodeDictionary*)obj);
450571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
451571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
452571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
453571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
4543aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comint SkPdfNativeDoc::pages() const {
455571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return fPages.count();
456571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
457571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
4583aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comSkPdfPageObjectDictionary* SkPdfNativeDoc::page(int page) {
45988fc03dd1f47ad33b08d60c47013de860f8fa69fedisonn@google.com    SkASSERT(page >= 0 && page < fPages.count());
46088fc03dd1f47ad33b08d60c47013de860f8fa69fedisonn@google.com    return fPages[page];
46188fc03dd1f47ad33b08d60c47013de860f8fa69fedisonn@google.com}
46288fc03dd1f47ad33b08d60c47013de860f8fa69fedisonn@google.com
46388fc03dd1f47ad33b08d60c47013de860f8fa69fedisonn@google.com
4643aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comSkPdfResourceDictionary* SkPdfNativeDoc::pageResources(int page) {
46588fc03dd1f47ad33b08d60c47013de860f8fa69fedisonn@google.com    SkASSERT(page >= 0 && page < fPages.count());
466571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return fPages[page]->Resources(this);
467571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
468571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
469c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com// TODO(edisonn): Partial implemented.
470c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com// Move the logics directly in the code generator for inheritable and default values?
4713aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comSkRect SkPdfNativeDoc::MediaBox(int page) {
472571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    SkPdfPageObjectDictionary* current = fPages[page];
473571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    while (!current->has_MediaBox() && current->has_Parent()) {
474571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        current = (SkPdfPageObjectDictionary*)current->Parent(this);
475571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
476571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (current) {
477571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        return current->MediaBox(this);
478571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
479571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return SkRect::MakeEmpty();
480571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
481571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
4823aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comsize_t SkPdfNativeDoc::objects() const {
483571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return fObjects.count();
484571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
485571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
4863aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comSkPdfNativeObject* SkPdfNativeDoc::object(int i) {
487571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    SkASSERT(!(i < 0 || i > fObjects.count()));
488571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
489571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (i < 0 || i > fObjects.count()) {
490571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        return NULL;
491571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
492571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
493571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (fObjects[i].fObj == NULL) {
494571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        fObjects[i].fObj = readObject(i);
495c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // TODO(edisonn): For perf, when we read the cross reference sections, we should take
496c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // advantage of the boundaries of known objects, to minimize the risk of just parsing a bad
497c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // stream, and fail quickly, in case we default to sequential stream read.
498571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
499571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
500571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return fObjects[i].fObj;
501571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
502571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
5033aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comconst SkPdfMapper* SkPdfNativeDoc::mapper() const {
504571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return fMapper;
505571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
506571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
5073aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comSkPdfReal* SkPdfNativeDoc::createReal(double value) const {
5083aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com    SkPdfNativeObject* obj = fAllocator->allocObject();
509598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    SkPdfNativeObject::makeReal(value, obj);
510c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    TRACK_OBJECT_SRC(obj);
511571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return (SkPdfReal*)obj;
512571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
513571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
5143aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comSkPdfInteger* SkPdfNativeDoc::createInteger(int value) const {
5153aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com    SkPdfNativeObject* obj = fAllocator->allocObject();
516598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    SkPdfNativeObject::makeInteger(value, obj);
517c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    TRACK_OBJECT_SRC(obj);
518571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return (SkPdfInteger*)obj;
519571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
520571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
5213aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comSkPdfString* SkPdfNativeDoc::createString(const unsigned char* sz, size_t len) const {
5223aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com    SkPdfNativeObject* obj = fAllocator->allocObject();
523598cf5d3cfc428108cf21ab45d73a995d7e5c2a8edisonn@google.com    SkPdfNativeObject::makeString(sz, len, obj);
524c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com    TRACK_OBJECT_SRC(obj);
525571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return (SkPdfString*)obj;
526571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
527571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
5283aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comSkPdfAllocator* SkPdfNativeDoc::allocator() const {
529571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    return fAllocator;
530571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com}
531571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
5323aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comSkPdfNativeObject* SkPdfNativeDoc::resolveReference(SkPdfNativeObject* ref) {
533571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    if (ref && ref->isReference()) {
534571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        int id = ref->referenceId();
535571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        // TODO(edisonn): generation/updates not supported now
536571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        //int gen = ref->referenceGeneration();
537571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
538641cce90c99f17e7c4d3d6407c3c4bbf591c5a3fedisonn@google.com        // TODO(edisonn): verify id and gen expected
539641cce90c99f17e7c4d3d6407c3c4bbf591c5a3fedisonn@google.com        if (id < 0 || id >= fObjects.count()) {
540c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kReadStreamError_SkPdfIssue,
541c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                        "resolve reference id out of bounds", NULL, NULL);
542571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            return NULL;
543571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
544571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
545f68aed33819cbc98a95edeadde1da9303eca7fb2edisonn@google.com        if (fObjects[id].fIsReferenceResolved) {
546c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com            SkPdfReportIf(!fObjects[id].fResolvedReference, kIgnoreError_SkPdfIssueSeverity,
547c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com                          kBadReference_SkPdfIssue, "ref is NULL", NULL, NULL);
548571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            return fObjects[id].fResolvedReference;
549571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
550571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
551c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // TODO(edisonn): there are pdfs in the crashing suite that cause a stack overflow
552c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // here unless we check for resolved reference on next line.
553c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // Determine if the pdf is corrupted, or we have a bug here.
554f68aed33819cbc98a95edeadde1da9303eca7fb2edisonn@google.com
555c8fda9d96be0bd944d37a6e23f7adad5f247c51dedisonn@google.com        // Avoids recursive calls
556f68aed33819cbc98a95edeadde1da9303eca7fb2edisonn@google.com        fObjects[id].fIsReferenceResolved = true;
557f68aed33819cbc98a95edeadde1da9303eca7fb2edisonn@google.com
558571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        if (fObjects[id].fObj == NULL) {
559571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            fObjects[id].fObj = readObject(id);
560571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
561571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
562608c35e5c4ce61a79b7a0567c8eca569332c2ddeedisonn@google.com        if (fObjects[id].fObj != NULL && fObjects[id].fResolvedReference == NULL) {
563571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            if (!fObjects[id].fObj->isReference()) {
564571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                fObjects[id].fResolvedReference = fObjects[id].fObj;
565571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            } else {
566571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com                fObjects[id].fResolvedReference = resolveReference(fObjects[id].fObj);
567571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com            }
568571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        }
569571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com
570571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com        return fObjects[id].fResolvedReference;
571571c70b95f56e22b5a7d6f4f288aa6c9a925a64fedisonn@google.com    }
572276fed9e0ae2e4457efd61eeb14738040feb65f1edisonn@google.com
5733aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.com    return (SkPdfNativeObject*)ref;
5743aac1f9f308192f3787265830fe86ce8874e7382edisonn@google.com}
575a5aaa7998fc18489701660f781d7daa33ffc6f6eedisonn@google.com
5763aa355527a3b91d3e12b8bee49e5637d00a736caedisonn@google.comsize_t SkPdfNativeDoc::bytesUsed() const {
577a5aaa7998fc18489701660f781d7daa33ffc6f6eedisonn@google.com    return fAllocator->bytesUsed() +
578a5aaa7998fc18489701660f781d7daa33ffc6f6eedisonn@google.com           fContentLength +
579a5aaa7998fc18489701660f781d7daa33ffc6f6eedisonn@google.com           fObjects.count() * sizeof(PublicObjectEntry) +
580a5aaa7998fc18489701660f781d7daa33ffc6f6eedisonn@google.com           fPages.count() * sizeof(SkPdfPageObjectDictionary*) +
581a5aaa7998fc18489701660f781d7daa33ffc6f6eedisonn@google.com           sizeof(*this);
582a5aaa7998fc18489701660f781d7daa33ffc6f6eedisonn@google.com}
583