SkPdfNativeObject.h revision a0cefa18fc25cca4264be04ce30c0c9692487a02
1#ifndef EXPERIMENTAL_PDFVIEWER_PDFPARSER_NATIVE_SKPDFOBJECT_H_
2#define EXPERIMENTAL_PDFVIEWER_PDFPARSER_NATIVE_SKPDFOBJECT_H_
3
4#include <stdint.h>
5#include <string.h>
6#include <string>
7#include "SkTDArray.h"
8#include "SkTDict.h"
9#include "SkRect.h"
10#include "SkMatrix.h"
11#include "SkString.h"
12
13#include "SkPdfNYI.h"
14#include "SkPdfConfig.h"
15
16class SkPdfDictionary;
17class SkPdfStream;
18class SkPdfAllocator;
19
20// TODO(edisonn): macro it and move it to utils
21SkMatrix SkMatrixFromPdfMatrix(double array[6]);
22
23
24#define kFilteredStreamBit 0
25#define kUnfilteredStreamBit 1
26#define kOwnedStreamBit 2
27
28class SkPdfObject {
29 public:
30     enum ObjectType {
31         kInvalid_PdfObjectType,
32
33         kBoolean_PdfObjectType,
34         kInteger_PdfObjectType,
35         kReal_PdfObjectType,
36         kString_PdfObjectType,
37         kHexString_PdfObjectType,
38         kName_PdfObjectType,
39         kKeyword_PdfObjectType,
40         //kStream_PdfObjectType,  //  attached to a Dictionary
41         kArray_PdfObjectType,
42         kDictionary_PdfObjectType,
43         kNull_PdfObjectType,
44
45         // TODO(edisonn): after the pdf has been loaded completely, resolve all references
46         // try the same thing with delayed loaded ...
47         kReference_PdfObjectType,
48
49         kUndefined_PdfObjectType,  // per 1.4 spec, if the same key appear twice in the dictionary, the value is undefined
50     };
51
52private:
53    struct Reference {
54        unsigned int fId;
55        unsigned int fGen;
56    };
57
58    // TODO(edisonn): add stream start, stream end, where stream is weither the file
59    // or decoded/filtered pdf stream
60
61    // TODO(edisonn): add warning/report per object
62    // TODO(edisonn): add flag fUsed, to be used once the parsing is complete,
63    // so we could show what parts have been proccessed, ignored, or generated errors
64
65    ObjectType fObjectType;
66
67    union {
68        bool fBooleanValue;
69        int64_t fIntegerValue;
70        // TODO(edisonn): double, float? typedefed
71        double fRealValue;
72        NotOwnedString fStr;
73
74        // TODO(edisonn): make sure the foorprint of fArray and fMap is small, otherwise, use pointers, or classes with up to 8 bytes in footprint
75        SkTDArray<SkPdfObject*>* fArray;
76        Reference fRef;
77    };
78    SkTDict<SkPdfObject*>* fMap;
79    void* fData;
80
81
82public:
83
84    SkPdfObject() : fObjectType(kInvalid_PdfObjectType), fMap(NULL), fData(NULL) {}
85
86    inline void* data() {
87        return fData;
88    }
89
90    inline void setData(void* data) {
91        fData = data;
92    }
93
94//    ~SkPdfObject() {
95//        //reset();  must be called manually!
96//    }
97
98    void reset() {
99        switch (fObjectType) {
100            case kArray_PdfObjectType:
101                delete fArray;
102                break;
103
104            case kDictionary_PdfObjectType:
105                delete fMap;
106                if (isStreamOwned()) {
107                    delete[] fStr.fBuffer;
108                    fStr.fBuffer = NULL;
109                    fStr.fBytes = 0;
110                }
111                break;
112
113            default:
114                break;
115        }
116        fObjectType = kInvalid_PdfObjectType;
117    }
118
119    ObjectType type() { return fObjectType; }
120
121    const char* c_str() const {
122        switch (fObjectType) {
123            case kString_PdfObjectType:
124            case kHexString_PdfObjectType:
125            case kKeyword_PdfObjectType:
126                return (const char*)fStr.fBuffer;
127
128            default:
129                // TODO(edisonn): report/warning
130                return NULL;
131        }
132    }
133
134    size_t len() const {
135        switch (fObjectType) {
136            case kString_PdfObjectType:
137            case kHexString_PdfObjectType:
138            case kKeyword_PdfObjectType:
139                return fStr.fBytes;
140
141            default:
142                // TODO(edisonn): report/warning
143                return 0;
144        }
145    }
146
147
148    // TODO(edisonn): NYI
149    SkPdfDate& dateValue() const {
150        static SkPdfDate nyi;
151        return nyi;
152    }
153
154    // TODO(edisonn): NYI
155    SkPdfFunction& functionValue() const {
156        static SkPdfFunction nyi;
157        return nyi;
158    }
159
160    // TODO(edisonn): NYI
161    SkPdfFileSpec& fileSpecValue() const {
162        static SkPdfFileSpec nyi;
163        return nyi;
164    }
165
166    // TODO(edisonn): NYI
167    SkPdfTree& treeValue() const {
168        static SkPdfTree nyi;
169        return nyi;
170    }
171
172
173    static void makeBoolean(bool value, SkPdfObject* obj) {
174        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
175
176        obj->fObjectType = kBoolean_PdfObjectType;
177        obj->fBooleanValue = value;
178    }
179
180    static SkPdfObject makeBoolean(bool value) {
181        SkPdfObject obj;
182        obj.fObjectType = kBoolean_PdfObjectType;
183        obj.fBooleanValue = value;
184        return obj;
185    }
186
187    static void makeInteger(int64_t value, SkPdfObject* obj) {
188        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
189
190        obj->fObjectType = kInteger_PdfObjectType;
191        obj->fIntegerValue = value;
192    }
193
194    static void makeReal(double value, SkPdfObject* obj) {
195        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
196
197        obj->fObjectType = kReal_PdfObjectType;
198        obj->fRealValue = value;
199    }
200
201    static void makeNull(SkPdfObject* obj) {
202        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
203
204        obj->fObjectType = kNull_PdfObjectType;
205    }
206
207    static SkPdfObject makeNull() {
208        SkPdfObject obj;
209        obj.fObjectType = kNull_PdfObjectType;
210        return obj;
211    }
212
213    static SkPdfObject kNull;
214
215    static void makeNumeric(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
216        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
217
218        // TODO(edisonn): NYI properly
219        // if has dot (impl), or exceeds max int, is real, otherwise is int
220        bool isInt = true;
221        for (const unsigned char* current = start; current < end; current++) {
222            if (*current == '.') {
223                isInt = false;
224                break;
225            }
226            // TODO(edisonn): report parse issue with numbers like "24asdasd123"
227        }
228        if (isInt) {
229            makeInteger(atol((const char*)start), obj);
230        } else {
231            makeReal(atof((const char*)start), obj);
232        }
233    }
234
235    static void makeReference(unsigned int id, unsigned int gen, SkPdfObject* obj) {
236        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
237
238        obj->fObjectType = kReference_PdfObjectType;
239        obj->fRef.fId = id;
240        obj->fRef.fGen = gen;
241    }
242
243
244    static void makeString(const unsigned char* start, SkPdfObject* obj) {
245        makeStringCore(start, strlen((const char*)start), obj, kString_PdfObjectType);
246    }
247
248    static void makeString(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
249        makeStringCore(start, end - start, obj, kString_PdfObjectType);
250    }
251
252    static void makeString(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
253        makeStringCore(start, bytes, obj, kString_PdfObjectType);
254    }
255
256
257    static void makeHexString(const unsigned char* start, SkPdfObject* obj) {
258        makeStringCore(start, strlen((const char*)start), obj, kHexString_PdfObjectType);
259    }
260
261    static void makeHexString(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
262        makeStringCore(start, end - start, obj, kHexString_PdfObjectType);
263    }
264
265    static void makeHexString(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
266        makeStringCore(start, bytes, obj, kHexString_PdfObjectType);
267    }
268
269
270    static void makeName(const unsigned char* start, SkPdfObject* obj) {
271        makeStringCore(start, strlen((const char*)start), obj, kName_PdfObjectType);
272    }
273
274    static void makeName(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
275        makeStringCore(start, end - start, obj, kName_PdfObjectType);
276    }
277
278    static void makeName(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
279        makeStringCore(start, bytes, obj, kName_PdfObjectType);
280    }
281
282
283    static void makeKeyword(const unsigned char* start, SkPdfObject* obj) {
284        makeStringCore(start, strlen((const char*)start), obj, kKeyword_PdfObjectType);
285    }
286
287    static void makeKeyword(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
288        makeStringCore(start, end - start, obj, kKeyword_PdfObjectType);
289    }
290
291    static void makeKeyword(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
292        makeStringCore(start, bytes, obj, kKeyword_PdfObjectType);
293    }
294
295
296
297    // TODO(edisonn): make the functions to return SkPdfArray, move these functions in SkPdfArray
298    static void makeEmptyArray(SkPdfObject* obj) {
299        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
300
301        obj->fObjectType = kArray_PdfObjectType;
302        obj->fArray = new SkTDArray<SkPdfObject*>();
303        // return (SkPdfArray*)obj;
304    }
305
306    bool appendInArray(SkPdfObject* obj) {
307        SkASSERT(fObjectType == kArray_PdfObjectType);
308        if (fObjectType != kArray_PdfObjectType) {
309            // TODO(edisonn): report err
310            return false;
311        }
312
313        fArray->push(obj);
314        return true;
315    }
316
317    size_t size() const {
318        SkASSERT(fObjectType == kArray_PdfObjectType);
319
320        return fArray->count();
321    }
322
323    SkPdfObject* objAtAIndex(int i) {
324        SkASSERT(fObjectType == kArray_PdfObjectType);
325
326        return (*fArray)[i];
327    }
328
329    SkPdfObject* removeLastInArray() {
330        SkASSERT(fObjectType == kArray_PdfObjectType);
331
332        SkPdfObject* ret = NULL;
333        fArray->pop(&ret);
334
335        return ret;
336    }
337
338
339    const SkPdfObject* objAtAIndex(int i) const {
340        SkASSERT(fObjectType == kArray_PdfObjectType);
341
342        return (*fArray)[i];
343    }
344
345    SkPdfObject* operator[](int i) {
346        SkASSERT(fObjectType == kArray_PdfObjectType);
347
348        return (*fArray)[i];
349    }
350
351    const SkPdfObject* operator[](int i) const {
352        SkASSERT(fObjectType == kArray_PdfObjectType);
353
354        return (*fArray)[i];
355    }
356
357
358    // TODO(edisonn): make the functions to return SkPdfDictionary, move these functions in SkPdfDictionary
359    static void makeEmptyDictionary(SkPdfObject* obj) {
360        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
361
362        obj->fObjectType = kDictionary_PdfObjectType;
363        obj->fMap = new SkTDict<SkPdfObject*>(1);
364        obj->fStr.fBuffer = NULL;
365        obj->fStr.fBytes = 0;
366    }
367
368    // TODO(edisonn): get all the possible names from spec, and compute a hash function
369    // that would create no overlaps in the same dictionary
370    // or build a tree of chars that when followed goes to a unique id/index/hash
371    // TODO(edisonn): generate constants like kDictFoo, kNameDict_name
372    // which will be used in code
373    // add function SkPdfFastNameKey key(const char* key);
374    // TODO(edisonn): setting the same key twike, will make the value undefined!
375    bool set(const SkPdfObject* key, SkPdfObject* value) {
376        SkASSERT(fObjectType == kDictionary_PdfObjectType);
377        SkASSERT(key->fObjectType == kName_PdfObjectType);
378
379        if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
380            // TODO(edisonn): report err
381            return false;
382        }
383
384        //// we rewrite all delimiters and white spaces with '\0', so we expect the end of name to be '\0'
385        //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0');
386
387        return set(key->fStr.fBuffer, key->fStr.fBytes, value);
388    }
389
390    bool set(const char* key, SkPdfObject* value) {
391        return set((const unsigned char*)key, strlen(key), value);
392    }
393
394    bool set(const unsigned char* key, size_t len, SkPdfObject* value) {
395        SkASSERT(fObjectType == kDictionary_PdfObjectType);
396
397        if (fObjectType != kDictionary_PdfObjectType) {
398            // TODO(edisonn): report err
399            return false;
400        }
401
402        return fMap->set((const char*)key, len, value);
403    }
404
405    SkPdfObject* get(const SkPdfObject* key) {
406        SkASSERT(fObjectType == kDictionary_PdfObjectType);
407        SkASSERT(key->fObjectType == kName_PdfObjectType);
408
409        if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
410            // TODO(edisonn): report err
411            return NULL;
412        }
413
414        //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0');
415
416        return get(key->fStr.fBuffer, key->fStr.fBytes);
417    }
418
419    SkPdfObject* get(const char* key) {
420        return get((const unsigned char*)key, strlen(key));
421    }
422
423    SkPdfObject* get(const unsigned char* key, size_t len) {
424        SkASSERT(fObjectType == kDictionary_PdfObjectType);
425        SkASSERT(key);
426        if (fObjectType != kDictionary_PdfObjectType) {
427            // TODO(edisonn): report err
428            return NULL;
429        }
430        SkPdfObject* ret = NULL;
431        fMap->find((const char*)key, len, &ret);
432        return ret;
433    }
434
435    const SkPdfObject* get(const SkPdfObject* key) const {
436        SkASSERT(fObjectType == kDictionary_PdfObjectType);
437        SkASSERT(key->fObjectType == kName_PdfObjectType);
438
439        if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
440            // TODO(edisonn): report err
441            return NULL;
442        }
443
444        //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0');
445
446        return get(key->fStr.fBuffer, key->fStr.fBytes);
447    }
448
449    const SkPdfObject* get(const char* key) const {
450        return get((const unsigned char*)key, strlen(key));
451    }
452
453    const SkPdfObject* get(const unsigned char* key, size_t len) const {
454        SkASSERT(fObjectType == kDictionary_PdfObjectType);
455        SkASSERT(key);
456        if (fObjectType != kDictionary_PdfObjectType) {
457            // TODO(edisonn): report err
458            return NULL;
459        }
460        SkPdfObject* ret = NULL;
461        fMap->find((const char*)key, len, &ret);
462        return ret;
463    }
464
465    const SkPdfObject* get(const char* key, const char* abr) const {
466        const SkPdfObject* ret = get(key);
467        // TODO(edisonn): / is a valid name, and it might be an abreviation, so "" should not be like NULL
468        // make this distiontion in generator, and remove "" from condition
469        if (ret != NULL || abr == NULL || *abr == '\0') {
470            return ret;
471        }
472        return get(abr);
473    }
474
475    SkPdfObject* get(const char* key, const char* abr) {
476        SkPdfObject* ret = get(key);
477        // TODO(edisonn): / is a valid name, and it might be an abreviation, so "" should not be like NULL
478        // make this distiontion in generator, and remove "" from condition
479        if (ret != NULL || abr == NULL || *abr == '\0') {
480            return ret;
481        }
482        return get(abr);
483    }
484
485    SkPdfDictionary* asDictionary() {
486        SkASSERT(isDictionary());
487        if (!isDictionary()) {
488            return NULL;
489        }
490        return (SkPdfDictionary*) this;
491    }
492
493    const SkPdfDictionary* asDictionary() const {
494        SkASSERT(isDictionary());
495        if (!isDictionary()) {
496            return NULL;
497        }
498        return (SkPdfDictionary*) this;
499    }
500
501
502    bool isReference() const {
503        return fObjectType == kReference_PdfObjectType;
504    }
505
506    bool isBoolean() const {
507        return fObjectType == kBoolean_PdfObjectType;
508    }
509
510    bool isInteger() const {
511        return fObjectType == kInteger_PdfObjectType;
512    }
513private:
514    bool isReal() const {
515        return fObjectType == kReal_PdfObjectType;
516    }
517public:
518    bool isNumber() const {
519        return fObjectType == kInteger_PdfObjectType || fObjectType == kReal_PdfObjectType;
520    }
521
522    bool isKeywordReference() const {
523        return fObjectType == kKeyword_PdfObjectType && fStr.fBytes == 1 && fStr.fBuffer[0] == 'R';
524    }
525
526    bool isKeyword() const {
527        return fObjectType == kKeyword_PdfObjectType;
528    }
529
530    bool isName() const {
531        return fObjectType == kName_PdfObjectType;
532    }
533
534    bool isName(const char* name) const {
535        return fObjectType == kName_PdfObjectType && fStr.fBytes == strlen(name) && strncmp((const char*)fStr.fBuffer, name, fStr.fBytes) == 0;
536    }
537
538    bool isArray() const {
539        return fObjectType == kArray_PdfObjectType;
540    }
541
542    bool isDate() const {
543        return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType;
544    }
545
546    bool isDictionary() const {
547        return fObjectType == kDictionary_PdfObjectType;
548    }
549
550    bool isFunction() const {
551        return false;  // NYI
552    }
553
554    bool isRectangle() const {
555        return fObjectType == kArray_PdfObjectType && fArray->count() == 4; // NYI + and elems are numbers
556    }
557
558    // TODO(edisonn): has stream .. or is stream ... TBD
559    bool hasStream() const {
560        return isDictionary() && fStr.fBuffer != NULL;
561    }
562
563    // TODO(edisonn): has stream .. or is stream ... TBD
564    const SkPdfStream* getStream() const {
565        return hasStream() ? (const SkPdfStream*)this : NULL;
566    }
567
568    SkPdfStream* getStream() {
569        return hasStream() ? (SkPdfStream*)this : NULL;
570    }
571
572    bool isAnyString() const {
573        return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType;
574    }
575
576    bool isMatrix() const {
577        return fObjectType == kArray_PdfObjectType && fArray->count() == 6; // NYI + and elems are numbers
578    }
579
580    inline int64_t intValue() const {
581        SkASSERT(fObjectType == kInteger_PdfObjectType);
582
583        if (fObjectType != kInteger_PdfObjectType) {
584            // TODO(edisonn): log err
585            return 0;
586        }
587        return fIntegerValue;
588    }
589private:
590    inline double realValue() const {
591        SkASSERT(fObjectType == kReal_PdfObjectType);
592
593        if (fObjectType != kReal_PdfObjectType) {
594            // TODO(edisonn): log err
595            return 0;
596        }
597        return fRealValue;
598    }
599public:
600    inline double numberValue() const {
601        SkASSERT(isNumber());
602
603        if (!isNumber()) {
604            // TODO(edisonn): log err
605            return 0;
606        }
607        return fObjectType == kReal_PdfObjectType ? fRealValue : fIntegerValue;
608    }
609
610    inline SkScalar scalarValue() const {
611        SkASSERT(isNumber());
612
613        if (!isNumber()) {
614            // TODO(edisonn): log err
615            return SkIntToScalar(0);
616        }
617        return fObjectType == kReal_PdfObjectType ? SkDoubleToScalar(fRealValue) :
618                                                    SkIntToScalar(fIntegerValue);
619    }
620
621    int referenceId() const {
622        SkASSERT(fObjectType == kReference_PdfObjectType);
623        return fRef.fId;
624    }
625
626    int referenceGeneration() const {
627        SkASSERT(fObjectType == kReference_PdfObjectType);
628        return fRef.fGen;
629    }
630
631    inline const char* nameValue() const {
632        SkASSERT(fObjectType == kName_PdfObjectType);
633
634        if (fObjectType != kName_PdfObjectType) {
635            // TODO(edisonn): log err
636            return "";
637        }
638        return (const char*)fStr.fBuffer;
639    }
640
641    inline const char* stringValue() const {
642        SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType);
643
644        if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
645            // TODO(edisonn): log err
646            return "";
647        }
648        return (const char*)fStr.fBuffer;
649    }
650
651    inline NotOwnedString strRef() {
652        switch (fObjectType) {
653            case kString_PdfObjectType:
654            case kHexString_PdfObjectType:
655            case kKeyword_PdfObjectType:
656                return fStr;
657
658            default:
659                // TODO(edisonn): report/warning
660                return NotOwnedString();
661        }
662    }
663
664    // TODO(edisonn): nameValue2 and stringValue2 are used to make code generation easy,
665    // but it is not a performat way to do it, since it will create an extra copy
666    // remove these functions and make code generated faster
667    inline std::string nameValue2() const {
668        SkASSERT(fObjectType == kName_PdfObjectType);
669
670        if (fObjectType != kName_PdfObjectType) {
671            // TODO(edisonn): log err
672            return "";
673        }
674        return std::string((const char*)fStr.fBuffer, fStr.fBytes);
675    }
676
677    inline std::string stringValue2() const {
678        SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType);
679
680        if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
681            // TODO(edisonn): log err
682            return "";
683        }
684        return std::string((const char*)fStr.fBuffer, fStr.fBytes);
685    }
686
687    inline bool boolValue() const {
688        SkASSERT(fObjectType == kBoolean_PdfObjectType);
689
690        if (fObjectType == kBoolean_PdfObjectType) {
691            // TODO(edisonn): log err
692            return false;
693        }
694        return fBooleanValue;
695    }
696
697    SkRect rectangleValue() const {
698        SkASSERT(isRectangle());
699        if (!isRectangle()) {
700            return SkRect::MakeEmpty();
701        }
702
703        double array[4];
704        for (int i = 0; i < 4; i++) {
705            // TODO(edisonn): version where we could resolve references?
706            const SkPdfObject* elem = objAtAIndex(i);
707            if (elem == NULL || !elem->isNumber()) {
708                // TODO(edisonn): report error
709                return SkRect::MakeEmpty();
710            }
711            array[i] = elem->numberValue();
712        }
713
714        return SkRect::MakeLTRB(SkDoubleToScalar(array[0]),
715                                SkDoubleToScalar(array[1]),
716                                SkDoubleToScalar(array[2]),
717                                SkDoubleToScalar(array[3]));
718    }
719
720    SkMatrix matrixValue() const {
721        SkASSERT(isMatrix());
722        if (!isMatrix()) {
723            return SkMatrix::I();
724        }
725
726        double array[6];
727        for (int i = 0; i < 6; i++) {
728            // TODO(edisonn): version where we could resolve references?
729            const SkPdfObject* elem = objAtAIndex(i);
730            if (elem == NULL || !elem->isNumber()) {
731                // TODO(edisonn): report error
732                return SkMatrix::I();
733            }
734            array[i] = elem->numberValue();
735        }
736
737        return SkMatrixFromPdfMatrix(array);
738    }
739
740    bool filterStream();
741
742
743    bool GetFilteredStreamRef(unsigned char const** buffer, size_t* len) {
744        // TODO(edisonn): add params that couls let the last filter in place if it is jpeg or png to fast load images
745        if (!hasStream()) {
746            return false;
747        }
748
749        filterStream();
750
751        if (buffer) {
752            *buffer = fStr.fBuffer;
753        }
754
755        if (len) {
756            *len = fStr.fBytes >> 2;  // last 2 bits
757        }
758
759        return true;
760    }
761
762    bool isStreamFiltered() const {
763        return hasStream() && ((fStr.fBytes & 1) == kFilteredStreamBit);
764    }
765
766    bool isStreamOwned() const {
767        return hasStream() && ((fStr.fBytes & 2) == kOwnedStreamBit);
768    }
769
770    bool GetUnfilteredStreamRef(unsigned char const** buffer, size_t* len) const {
771        if (isStreamFiltered()) {
772            return false;
773        }
774
775        if (!hasStream()) {
776            return false;
777        }
778
779        if (buffer) {
780            *buffer = fStr.fBuffer;
781        }
782
783        if (len) {
784            *len = fStr.fBytes >> 2;  // remove last 2 bits
785        }
786
787        return true;
788    }
789
790    bool addStream(const unsigned char* buffer, size_t len) {
791        SkASSERT(!hasStream());
792        SkASSERT(isDictionary());
793
794        if (!isDictionary() || hasStream()) {
795            return false;
796        }
797
798        fStr.fBuffer = buffer;
799        fStr.fBytes = (len << 2) + kUnfilteredStreamBit;
800
801        return true;
802    }
803
804    SkString toString() {
805        SkString str;
806        switch (fObjectType) {
807            case kInvalid_PdfObjectType:
808                str.append("Invalid");
809                break;
810
811            case kBoolean_PdfObjectType:
812                str.appendf("Boolean: %s", fBooleanValue ? "true" : "false");
813                break;
814
815            case kInteger_PdfObjectType:
816                str.appendf("Integer: %i", (int)fIntegerValue);
817                break;
818
819            case kReal_PdfObjectType:
820                str.appendf("Real: %f", fRealValue);
821                break;
822
823            case kString_PdfObjectType:
824                str.appendf("String, len() = %u: ", (unsigned int)fStr.fBytes);
825                str.append((const char*)fStr.fBuffer, fStr.fBytes);
826                break;
827
828            case kHexString_PdfObjectType:
829                str.appendf("HexString, len() = %u: ", (unsigned int)fStr.fBytes);
830                str.append((const char*)fStr.fBuffer, fStr.fBytes);
831                break;
832
833            case kName_PdfObjectType:
834                str.appendf("Name, len() = %u: ", (unsigned int)fStr.fBytes);
835                str.append((const char*)fStr.fBuffer, fStr.fBytes);
836                break;
837
838            case kKeyword_PdfObjectType:
839                str.appendf("Keyword, len() = %u: ", (unsigned int)fStr.fBytes);
840                str.append((const char*)fStr.fBuffer, fStr.fBytes);
841                break;
842
843            case kArray_PdfObjectType:
844                str.append("Array, size() = %i [", size());
845                for (unsigned int i = 0; i < size(); i++) {
846                    str.append(objAtAIndex(i)->toString());
847                }
848                str.append("]");
849                break;
850
851            case kDictionary_PdfObjectType:
852                // TODO(edisonn): NYI
853                str.append("Dictionary: NYI");
854                if (hasStream()) {
855                    str.append(" HAS_STREAM");
856                }
857                break;
858
859            case kNull_PdfObjectType:
860                str = "NULL";
861                break;
862
863            case kReference_PdfObjectType:
864                str.appendf("Reference: %i %i", fRef.fId, fRef.fGen);
865                break;
866
867            case kUndefined_PdfObjectType:
868                str = "Undefined";
869                break;
870
871            default:
872                str = "Internal Error Object Type";
873                break;
874        }
875
876        return str;
877    }
878
879private:
880    static void makeStringCore(const unsigned char* start, SkPdfObject* obj, ObjectType type) {
881        makeStringCore(start, strlen((const char*)start), obj, type);
882    }
883
884    static void makeStringCore(const unsigned char* start, const unsigned char* end, SkPdfObject* obj, ObjectType type) {
885        makeStringCore(start, end - start, obj, type);
886    }
887
888    static void makeStringCore(const unsigned char* start, size_t bytes, SkPdfObject* obj, ObjectType type) {
889        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
890
891        obj->fObjectType = type;
892        obj->fStr.fBuffer = start;
893        obj->fStr.fBytes = bytes;
894    }
895
896    bool applyFilter(const char* name);
897    bool applyFlateDecodeFilter();
898    bool applyDCTDecodeFilter();
899};
900
901class SkPdfStream : public SkPdfObject {};
902class SkPdfArray : public SkPdfObject {};
903class SkPdfString : public SkPdfObject {};
904class SkPdfHexString : public SkPdfObject {};
905class SkPdfInteger : public SkPdfObject {};
906class SkPdfReal : public SkPdfObject {};
907class SkPdfNumber : public SkPdfObject {};
908
909class SkPdfName : public SkPdfObject {
910    SkPdfName() : SkPdfObject() {
911        SkPdfObject::makeName((const unsigned char*)"", this);
912    }
913public:
914    SkPdfName(char* name) : SkPdfObject() {
915        this->makeName((const unsigned char*)name, this);
916    }
917};
918
919#endif  // EXPERIMENTAL_PDFVIEWER_PDFPARSER_NATIVE_SKPDFOBJECT_H_
920