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