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