blob: ff647987b0ca0acf954d1fabd7b18bf00b989eb1 [file] [log] [blame]
edisonn@google.com571c70b2013-07-10 17:09:50 +00001#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
edisonn@google.com222382b2013-07-10 22:33:10 +000089 SkPdfObject() : fObjectType(kInvalid_PdfObjectType), fMap(NULL), fData(NULL) {}
edisonn@google.com571c70b2013-07-10 17:09:50 +000090
91 inline void* data() {
92 return fData;
93 }
94
95 inline void setData(void* data) {
96 fData = data;
97 }
98
edisonn@google.com222382b2013-07-10 22:33:10 +000099// ~SkPdfObject() {
100// //reset(); must be called manually!
101// }
edisonn@google.com571c70b2013-07-10 17:09:50 +0000102
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
edisonn@google.com3fc48262013-07-22 15:29:55 +0000407 return NULL;
edisonn@google.com571c70b2013-07-10 17:09:50 +0000408 }
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
edisonn@google.com3fc48262013-07-22 15:29:55 +0000433 return NULL;
edisonn@google.com571c70b2013-07-10 17:09:50 +0000434 }
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
edisonn@google.com78b38b12013-07-15 18:20:58 +0000523 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
edisonn@google.com571c70b2013-07-10 17:09:50 +0000527 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
edisonn@google.com78b38b12013-07-15 18:20:58 +0000870class 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
edisonn@google.com571c70b2013-07-10 17:09:50 +0000880#endif // EXPERIMENTAL_PDFVIEWER_PDFPARSER_NATIVE_SKPDFOBJECT_H_