SkPdfNativeObject.h revision 3fc482620e8af9442f588e3bf364e198c41ba913
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
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 NotOwnedString {
54        unsigned char* fBuffer;
55        size_t fBytes;
56    };
57
58    struct Reference {
59        unsigned int fId;
60        unsigned int fGen;
61    };
62
63    // TODO(edisonn): add stream start, stream end, where stream is weither the file
64    // or decoded/filtered pdf stream
65
66    // TODO(edisonn): add warning/report per object
67    // TODO(edisonn): add flag fUsed, to be used once the parsing is complete,
68    // so we could show what parts have been proccessed, ignored, or generated errors
69
70    ObjectType fObjectType;
71
72    union {
73        bool fBooleanValue;
74        int64_t fIntegerValue;
75        // TODO(edisonn): double, float? typedefed
76        double fRealValue;
77        NotOwnedString fStr;
78
79        // TODO(edisonn): make sure the foorprint of fArray and fMap is small, otherwise, use pointers, or classes with up to 8 bytes in footprint
80        SkTDArray<SkPdfObject*>* fArray;
81        Reference fRef;
82    };
83    SkTDict<SkPdfObject*>* fMap;
84    void* fData;
85
86
87public:
88
89    SkPdfObject() : fObjectType(kInvalid_PdfObjectType), fMap(NULL), fData(NULL) {}
90
91    inline void* data() {
92        return fData;
93    }
94
95    inline void setData(void* data) {
96        fData = data;
97    }
98
99//    ~SkPdfObject() {
100//        //reset();  must be called manually!
101//    }
102
103    void reset() {
104        switch (fObjectType) {
105            case kArray_PdfObjectType:
106                delete fArray;
107                break;
108
109            case kDictionary_PdfObjectType:
110                delete fMap;
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(unsigned char* start, 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 (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(unsigned char* start, SkPdfObject* obj) {
245        makeStringCore(start, strlen((const char*)start), obj, kString_PdfObjectType);
246    }
247
248    static void makeString(unsigned char* start, unsigned char* end, SkPdfObject* obj) {
249        makeStringCore(start, end - start, obj, kString_PdfObjectType);
250    }
251
252    static void makeString(unsigned char* start, size_t bytes, SkPdfObject* obj) {
253        makeStringCore(start, bytes, obj, kString_PdfObjectType);
254    }
255
256
257    static void makeHexString(unsigned char* start, SkPdfObject* obj) {
258        makeStringCore(start, strlen((const char*)start), obj, kHexString_PdfObjectType);
259    }
260
261    static void makeHexString(unsigned char* start, unsigned char* end, SkPdfObject* obj) {
262        makeStringCore(start, end - start, obj, kHexString_PdfObjectType);
263    }
264
265    static void makeHexString(unsigned char* start, size_t bytes, SkPdfObject* obj) {
266        makeStringCore(start, bytes, obj, kHexString_PdfObjectType);
267    }
268
269
270    static void makeName(unsigned char* start, SkPdfObject* obj) {
271        makeStringCore(start, strlen((const char*)start), obj, kName_PdfObjectType);
272    }
273
274    static void makeName(unsigned char* start, unsigned char* end, SkPdfObject* obj) {
275        makeStringCore(start, end - start, obj, kName_PdfObjectType);
276    }
277
278    static void makeName(unsigned char* start, size_t bytes, SkPdfObject* obj) {
279        makeStringCore(start, bytes, obj, kName_PdfObjectType);
280    }
281
282
283    static void makeKeyword(unsigned char* start, SkPdfObject* obj) {
284        makeStringCore(start, strlen((const char*)start), obj, kKeyword_PdfObjectType);
285    }
286
287    static void makeKeyword(unsigned char* start, unsigned char* end, SkPdfObject* obj) {
288        makeStringCore(start, end - start, obj, kKeyword_PdfObjectType);
289    }
290
291    static void makeKeyword(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(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((char*)key->fStr.fBuffer, value);
388    }
389
390    bool set(const char* key, SkPdfObject* value) {
391        SkASSERT(fObjectType == kDictionary_PdfObjectType);
392
393        if (fObjectType != kDictionary_PdfObjectType) {
394            // TODO(edisonn): report err
395            return false;
396        }
397
398        return fMap->set(key, value);
399    }
400
401    SkPdfObject* get(SkPdfObject* key) {
402        SkASSERT(fObjectType == kDictionary_PdfObjectType);
403        SkASSERT(key->fObjectType == kName_PdfObjectType);
404
405        if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
406            // TODO(edisonn): report err
407            return NULL;
408        }
409
410        SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0');
411
412        return get((char*)key->fStr.fBuffer);
413    }
414
415    SkPdfObject* get(const char* key) {
416        SkASSERT(fObjectType == kDictionary_PdfObjectType);
417        SkASSERT(key);
418        if (fObjectType != kDictionary_PdfObjectType) {
419            // TODO(edisonn): report err
420            return NULL;
421        }
422        SkPdfObject* ret = NULL;
423        fMap->find(key, &ret);
424        return ret;
425    }
426
427    const SkPdfObject* get(SkPdfObject* key) const {
428        SkASSERT(fObjectType == kDictionary_PdfObjectType);
429        SkASSERT(key->fObjectType == kName_PdfObjectType);
430
431        if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
432            // TODO(edisonn): report err
433            return NULL;
434        }
435
436        SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0');
437
438        return get((char*)key->fStr.fBuffer);
439    }
440
441
442    const SkPdfObject* get(const char* key) const {
443        SkASSERT(fObjectType == kDictionary_PdfObjectType);
444        SkASSERT(key);
445        if (fObjectType != kDictionary_PdfObjectType) {
446            // TODO(edisonn): report err
447            return NULL;
448        }
449        SkPdfObject* ret = NULL;
450        fMap->find(key, &ret);
451        return ret;
452    }
453
454    const SkPdfObject* get(const char* key, const char* abr) const {
455        const SkPdfObject* ret = get(key);
456        // TODO(edisonn): / is a valid name, and it might be an abreviation, so "" should not be like NULL
457        // make this distiontion in generator, and remove "" from condition
458        if (ret != NULL || abr == NULL || *abr == '\0') {
459            return ret;
460        }
461        return get(abr);
462    }
463
464    SkPdfObject* get(const char* key, const char* abr) {
465        SkPdfObject* ret = get(key);
466        // TODO(edisonn): / is a valid name, and it might be an abreviation, so "" should not be like NULL
467        // make this distiontion in generator, and remove "" from condition
468        if (ret != NULL || abr == NULL || *abr == '\0') {
469            return ret;
470        }
471        return get(abr);
472    }
473
474    SkPdfDictionary* asDictionary() {
475        SkASSERT(isDictionary());
476        if (!isDictionary()) {
477            return NULL;
478        }
479        return (SkPdfDictionary*) this;
480    }
481
482    const SkPdfDictionary* asDictionary() const {
483        SkASSERT(isDictionary());
484        if (!isDictionary()) {
485            return NULL;
486        }
487        return (SkPdfDictionary*) this;
488    }
489
490
491    bool isReference() const {
492        return fObjectType == kReference_PdfObjectType;
493    }
494
495    bool isBoolean() const {
496        return fObjectType == kBoolean_PdfObjectType;
497    }
498
499    bool isInteger() const {
500        return fObjectType == kInteger_PdfObjectType;
501    }
502private:
503    bool isReal() const {
504        return fObjectType == kReal_PdfObjectType;
505    }
506public:
507    bool isNumber() const {
508        return fObjectType == kInteger_PdfObjectType || fObjectType == kReal_PdfObjectType;
509    }
510
511    bool isKeywordReference() const {
512        return fObjectType == kKeyword_PdfObjectType && fStr.fBytes == 1 && fStr.fBuffer[0] == 'R';
513    }
514
515    bool isKeyword() const {
516        return fObjectType == kKeyword_PdfObjectType;
517    }
518
519    bool isName() const {
520        return fObjectType == kName_PdfObjectType;
521    }
522
523    bool isName(const char* name) const {
524        return fObjectType == kName_PdfObjectType && fStr.fBytes == strlen(name) && strncmp((const char*)fStr.fBuffer, name, fStr.fBytes) == 0;
525    }
526
527    bool isArray() const {
528        return fObjectType == kArray_PdfObjectType;
529    }
530
531    bool isDate() const {
532        return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType;
533    }
534
535    bool isDictionary() const {
536        return fObjectType == kDictionary_PdfObjectType;
537    }
538
539    bool isFunction() const {
540        return false;  // NYI
541    }
542
543    bool isRectangle() const {
544        return fObjectType == kArray_PdfObjectType && fArray->count() == 4; // NYI + and elems are numbers
545    }
546
547    // TODO(edisonn): has stream .. or is stream ... TBD
548    bool hasStream() const {
549        return isDictionary() && fStr.fBuffer != NULL;
550    }
551
552    // TODO(edisonn): has stream .. or is stream ... TBD
553    const SkPdfStream* getStream() const {
554        return hasStream() ? (const SkPdfStream*)this : NULL;
555    }
556
557    SkPdfStream* getStream() {
558        return hasStream() ? (SkPdfStream*)this : NULL;
559    }
560
561    bool isAnyString() const {
562        return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType;
563    }
564
565    bool isMatrix() const {
566        return fObjectType == kArray_PdfObjectType && fArray->count() == 6; // NYI + and elems are numbers
567    }
568
569    inline int64_t intValue() const {
570        SkASSERT(fObjectType == kInteger_PdfObjectType);
571
572        if (fObjectType != kInteger_PdfObjectType) {
573            // TODO(edisonn): log err
574            return 0;
575        }
576        return fIntegerValue;
577    }
578private:
579    inline double realValue() const {
580        SkASSERT(fObjectType == kReal_PdfObjectType);
581
582        if (fObjectType != kReal_PdfObjectType) {
583            // TODO(edisonn): log err
584            return 0;
585        }
586        return fRealValue;
587    }
588public:
589    inline double numberValue() const {
590        SkASSERT(isNumber());
591
592        if (!isNumber()) {
593            // TODO(edisonn): log err
594            return 0;
595        }
596        return fObjectType == kReal_PdfObjectType ? fRealValue : fIntegerValue;
597    }
598
599    int referenceId() const {
600        SkASSERT(fObjectType == kReference_PdfObjectType);
601        return fRef.fId;
602    }
603
604    int referenceGeneration() const {
605        SkASSERT(fObjectType == kReference_PdfObjectType);
606        return fRef.fGen;
607    }
608
609    inline const char* nameValue() const {
610        SkASSERT(fObjectType == kName_PdfObjectType);
611
612        if (fObjectType != kName_PdfObjectType) {
613            // TODO(edisonn): log err
614            return "";
615        }
616        return (const char*)fStr.fBuffer;
617    }
618
619    inline const char* stringValue() const {
620        SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType);
621
622        if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
623            // TODO(edisonn): log err
624            return "";
625        }
626        return (const char*)fStr.fBuffer;
627    }
628
629    // TODO(edisonn): nameValue2 and stringValue2 are used to make code generation easy,
630    // but it is not a performat way to do it, since it will create an extra copy
631    // remove these functions and make code generated faster
632    inline std::string nameValue2() const {
633        SkASSERT(fObjectType == kName_PdfObjectType);
634
635        if (fObjectType != kName_PdfObjectType) {
636            // TODO(edisonn): log err
637            return "";
638        }
639        return (const char*)fStr.fBuffer;
640    }
641
642    inline std::string stringValue2() const {
643        SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType);
644
645        if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
646            // TODO(edisonn): log err
647            return "";
648        }
649        return (const char*)fStr.fBuffer;
650    }
651
652    inline bool boolValue() const {
653        SkASSERT(fObjectType == kBoolean_PdfObjectType);
654
655        if (fObjectType == kBoolean_PdfObjectType) {
656            // TODO(edisonn): log err
657            return false;
658        }
659        return fBooleanValue;
660    }
661
662    SkRect rectangleValue() const {
663        SkASSERT(isRectangle());
664        if (!isRectangle()) {
665            return SkRect::MakeEmpty();
666        }
667
668        double array[4];
669        for (int i = 0; i < 4; i++) {
670            // TODO(edisonn): version where we could resolve references?
671            const SkPdfObject* elem = objAtAIndex(i);
672            if (elem == NULL || !elem->isNumber()) {
673                // TODO(edisonn): report error
674                return SkRect::MakeEmpty();
675            }
676            array[i] = elem->numberValue();
677        }
678
679        return SkRect::MakeLTRB(SkDoubleToScalar(array[0]),
680                                SkDoubleToScalar(array[1]),
681                                SkDoubleToScalar(array[2]),
682                                SkDoubleToScalar(array[3]));
683    }
684
685    SkMatrix matrixValue() const {
686        SkASSERT(isMatrix());
687        if (!isMatrix()) {
688            return SkMatrix::I();
689        }
690
691        double array[6];
692        for (int i = 0; i < 6; i++) {
693            // TODO(edisonn): version where we could resolve references?
694            const SkPdfObject* elem = objAtAIndex(i);
695            if (elem == NULL || !elem->isNumber()) {
696                // TODO(edisonn): report error
697                return SkMatrix::I();
698            }
699            array[i] = elem->numberValue();
700        }
701
702        return SkMatrixFromPdfMatrix(array);
703    }
704
705    bool filterStream(SkPdfAllocator* allocator);
706
707
708    bool GetFilteredStreamRef(unsigned char** buffer, size_t* len, SkPdfAllocator* allocator) {
709        // TODO(edisonn): add params that couls let the last filter in place if it is jpeg or png to fast load images
710        if (!hasStream()) {
711            return false;
712        }
713
714        filterStream(allocator);
715
716        if (buffer) {
717            *buffer = fStr.fBuffer;
718        }
719
720        if (len) {
721            *len = fStr.fBytes >> 1;  // last bit
722        }
723
724        return true;
725    }
726
727    bool isStreamFiltered() const {
728        return hasStream() && ((fStr.fBytes & 1) == kFilteredStreamBit);
729    }
730
731    bool GetUnfilteredStreamRef(unsigned char** buffer, size_t* len) const {
732        if (isStreamFiltered()) {
733            return false;
734        }
735
736        if (!hasStream()) {
737            return false;
738        }
739
740        if (buffer) {
741            *buffer = fStr.fBuffer;
742        }
743
744        if (len) {
745            *len = fStr.fBytes >> 1;  // remove slast bit
746        }
747
748        return true;
749    }
750
751    bool addStream(unsigned char* buffer, size_t len) {
752        SkASSERT(!hasStream());
753        SkASSERT(isDictionary());
754
755        if (!isDictionary() || hasStream()) {
756            return false;
757        }
758
759        fStr.fBuffer = buffer;
760        fStr.fBytes = (len << 2) + kUnfilteredStreamBit;
761
762        return true;
763    }
764
765    SkString toString() {
766        SkString str;
767        switch (fObjectType) {
768            case kInvalid_PdfObjectType:
769                str.append("Invalid");
770                break;
771
772            case kBoolean_PdfObjectType:
773                str.appendf("Boolean: %s", fBooleanValue ? "true" : "false");
774                break;
775
776            case kInteger_PdfObjectType:
777                str.appendf("Integer: %i", (int)fIntegerValue);
778                break;
779
780            case kReal_PdfObjectType:
781                str.appendf("Real: %f", fRealValue);
782                break;
783
784            case kString_PdfObjectType:
785                str.appendf("String, len() = %u: ", (unsigned int)fStr.fBytes);
786                str.append((const char*)fStr.fBuffer, fStr.fBytes);
787                break;
788
789            case kHexString_PdfObjectType:
790                str.appendf("HexString, len() = %u: ", (unsigned int)fStr.fBytes);
791                str.append((const char*)fStr.fBuffer, fStr.fBytes);
792                break;
793
794            case kName_PdfObjectType:
795                str.appendf("Name, len() = %u: ", (unsigned int)fStr.fBytes);
796                str.append((const char*)fStr.fBuffer, fStr.fBytes);
797                break;
798
799            case kKeyword_PdfObjectType:
800                str.appendf("Keyword, len() = %u: ", (unsigned int)fStr.fBytes);
801                str.append((const char*)fStr.fBuffer, fStr.fBytes);
802                break;
803
804            case kArray_PdfObjectType:
805                str.append("Array, size() = %i [", size());
806                for (unsigned int i = 0; i < size(); i++) {
807                    str.append(objAtAIndex(i)->toString());
808                }
809                str.append("]");
810                break;
811
812            case kDictionary_PdfObjectType:
813                // TODO(edisonn): NYI
814                str.append("Dictionary: NYI");
815                if (hasStream()) {
816                    str.append(" HAS_STREAM");
817                }
818                break;
819
820            case kNull_PdfObjectType:
821                str = "NULL";
822                break;
823
824            case kReference_PdfObjectType:
825                str.appendf("Reference: %i %i", fRef.fId, fRef.fGen);
826                break;
827
828            case kUndefined_PdfObjectType:
829                str = "Undefined";
830                break;
831
832            default:
833                str = "Internal Error Object Type";
834                break;
835        }
836
837        return str;
838    }
839
840private:
841    static void makeStringCore(unsigned char* start, SkPdfObject* obj, ObjectType type) {
842        makeStringCore(start, strlen((const char*)start), obj, type);
843    }
844
845    static void makeStringCore(unsigned char* start, unsigned char* end, SkPdfObject* obj, ObjectType type) {
846        makeStringCore(start, end - start, obj, type);
847    }
848
849    static void makeStringCore(unsigned char* start, size_t bytes, SkPdfObject* obj, ObjectType type) {
850        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
851
852        obj->fObjectType = type;
853        obj->fStr.fBuffer = start;
854        obj->fStr.fBytes = bytes;
855    }
856
857    bool applyFilter(const char* name, SkPdfAllocator* allocator);
858    bool applyFlateDecodeFilter(SkPdfAllocator* allocator);
859    bool applyDCTDecodeFilter(SkPdfAllocator* allocator);
860};
861
862class SkPdfStream : public SkPdfObject {};
863class SkPdfArray : public SkPdfObject {};
864class SkPdfString : public SkPdfObject {};
865class SkPdfHexString : public SkPdfObject {};
866class SkPdfInteger : public SkPdfObject {};
867class SkPdfReal : public SkPdfObject {};
868class SkPdfNumber : public SkPdfObject {};
869
870class SkPdfName : public SkPdfObject {
871    SkPdfName() : SkPdfObject() {
872        SkPdfObject::makeName((unsigned char*)"", this);
873    }
874public:
875    SkPdfName(char* name) : SkPdfObject() {
876        this->makeName((unsigned char*)name, this);
877    }
878};
879
880#endif  // EXPERIMENTAL_PDFVIEWER_PDFPARSER_NATIVE_SKPDFOBJECT_H_
881