blob: f3832b2854892e653eea1a3ae1c5627ff8a128c6 [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
edisonn@google.com2ccc3af2013-07-23 17:43:18 +000026#define kOwnedStreamBit 2
edisonn@google.com571c70b2013-07-10 17:09:50 +000027
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:
edisonn@google.com571c70b2013-07-10 17:09:50 +000053 struct Reference {
54 unsigned int fId;
55 unsigned int fGen;
56 };
57
58 // TODO(edisonn): add stream start, stream end, where stream is weither the file
59 // or decoded/filtered pdf stream
60
61 // TODO(edisonn): add warning/report per object
62 // TODO(edisonn): add flag fUsed, to be used once the parsing is complete,
63 // so we could show what parts have been proccessed, ignored, or generated errors
64
65 ObjectType fObjectType;
66
67 union {
68 bool fBooleanValue;
69 int64_t fIntegerValue;
70 // TODO(edisonn): double, float? typedefed
71 double fRealValue;
72 NotOwnedString fStr;
73
74 // TODO(edisonn): make sure the foorprint of fArray and fMap is small, otherwise, use pointers, or classes with up to 8 bytes in footprint
75 SkTDArray<SkPdfObject*>* fArray;
76 Reference fRef;
77 };
78 SkTDict<SkPdfObject*>* fMap;
79 void* fData;
80
81
82public:
83
edisonn@google.com222382b2013-07-10 22:33:10 +000084 SkPdfObject() : fObjectType(kInvalid_PdfObjectType), fMap(NULL), fData(NULL) {}
edisonn@google.com571c70b2013-07-10 17:09:50 +000085
86 inline void* data() {
87 return fData;
88 }
89
90 inline void setData(void* data) {
91 fData = data;
92 }
93
edisonn@google.com222382b2013-07-10 22:33:10 +000094// ~SkPdfObject() {
95// //reset(); must be called manually!
96// }
edisonn@google.com571c70b2013-07-10 17:09:50 +000097
98 void reset() {
99 switch (fObjectType) {
100 case kArray_PdfObjectType:
101 delete fArray;
102 break;
103
104 case kDictionary_PdfObjectType:
105 delete fMap;
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000106 if (isStreamOwned()) {
107 delete[] fStr.fBuffer;
108 fStr.fBuffer = NULL;
109 fStr.fBytes = 0;
110 }
edisonn@google.com571c70b2013-07-10 17:09:50 +0000111 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
edisonn@google.come878e722013-07-29 19:10:58 +0000134 size_t lenstr() const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000135 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
edisonn@google.com571c70b2013-07-10 17:09:50 +0000172 static void makeBoolean(bool value, SkPdfObject* obj) {
173 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
174
175 obj->fObjectType = kBoolean_PdfObjectType;
176 obj->fBooleanValue = value;
177 }
178
179 static SkPdfObject makeBoolean(bool value) {
180 SkPdfObject obj;
181 obj.fObjectType = kBoolean_PdfObjectType;
182 obj.fBooleanValue = value;
183 return obj;
184 }
185
186 static void makeInteger(int64_t value, SkPdfObject* obj) {
187 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
188
189 obj->fObjectType = kInteger_PdfObjectType;
190 obj->fIntegerValue = value;
191 }
192
193 static void makeReal(double value, SkPdfObject* obj) {
194 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
195
196 obj->fObjectType = kReal_PdfObjectType;
197 obj->fRealValue = value;
198 }
199
200 static void makeNull(SkPdfObject* obj) {
201 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
202
203 obj->fObjectType = kNull_PdfObjectType;
204 }
205
206 static SkPdfObject makeNull() {
207 SkPdfObject obj;
208 obj.fObjectType = kNull_PdfObjectType;
209 return obj;
210 }
211
212 static SkPdfObject kNull;
213
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000214 static void makeNumeric(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000215 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
216
217 // TODO(edisonn): NYI properly
218 // if has dot (impl), or exceeds max int, is real, otherwise is int
219 bool isInt = true;
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000220 for (const unsigned char* current = start; current < end; current++) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000221 if (*current == '.') {
222 isInt = false;
223 break;
224 }
225 // TODO(edisonn): report parse issue with numbers like "24asdasd123"
226 }
227 if (isInt) {
228 makeInteger(atol((const char*)start), obj);
229 } else {
230 makeReal(atof((const char*)start), obj);
231 }
232 }
233
234 static void makeReference(unsigned int id, unsigned int gen, SkPdfObject* obj) {
235 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
236
237 obj->fObjectType = kReference_PdfObjectType;
238 obj->fRef.fId = id;
239 obj->fRef.fGen = gen;
240 }
241
242
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000243 static void makeString(const unsigned char* start, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000244 makeStringCore(start, strlen((const char*)start), obj, kString_PdfObjectType);
245 }
246
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000247 static void makeString(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000248 makeStringCore(start, end - start, obj, kString_PdfObjectType);
249 }
250
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000251 static void makeString(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000252 makeStringCore(start, bytes, obj, kString_PdfObjectType);
253 }
254
255
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000256 static void makeHexString(const unsigned char* start, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000257 makeStringCore(start, strlen((const char*)start), obj, kHexString_PdfObjectType);
258 }
259
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000260 static void makeHexString(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000261 makeStringCore(start, end - start, obj, kHexString_PdfObjectType);
262 }
263
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000264 static void makeHexString(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000265 makeStringCore(start, bytes, obj, kHexString_PdfObjectType);
266 }
267
268
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000269 static void makeName(const unsigned char* start, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000270 makeStringCore(start, strlen((const char*)start), obj, kName_PdfObjectType);
271 }
272
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000273 static void makeName(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000274 makeStringCore(start, end - start, obj, kName_PdfObjectType);
275 }
276
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000277 static void makeName(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000278 makeStringCore(start, bytes, obj, kName_PdfObjectType);
279 }
280
281
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000282 static void makeKeyword(const unsigned char* start, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000283 makeStringCore(start, strlen((const char*)start), obj, kKeyword_PdfObjectType);
284 }
285
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000286 static void makeKeyword(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000287 makeStringCore(start, end - start, obj, kKeyword_PdfObjectType);
288 }
289
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000290 static void makeKeyword(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000291 makeStringCore(start, bytes, obj, kKeyword_PdfObjectType);
292 }
293
294
295
296 // TODO(edisonn): make the functions to return SkPdfArray, move these functions in SkPdfArray
297 static void makeEmptyArray(SkPdfObject* obj) {
298 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
299
300 obj->fObjectType = kArray_PdfObjectType;
301 obj->fArray = new SkTDArray<SkPdfObject*>();
302 // return (SkPdfArray*)obj;
303 }
304
305 bool appendInArray(SkPdfObject* obj) {
306 SkASSERT(fObjectType == kArray_PdfObjectType);
307 if (fObjectType != kArray_PdfObjectType) {
308 // TODO(edisonn): report err
309 return false;
310 }
311
312 fArray->push(obj);
313 return true;
314 }
315
316 size_t size() const {
317 SkASSERT(fObjectType == kArray_PdfObjectType);
318
319 return fArray->count();
320 }
321
322 SkPdfObject* objAtAIndex(int i) {
323 SkASSERT(fObjectType == kArray_PdfObjectType);
324
325 return (*fArray)[i];
326 }
327
328 SkPdfObject* removeLastInArray() {
329 SkASSERT(fObjectType == kArray_PdfObjectType);
330
331 SkPdfObject* ret = NULL;
332 fArray->pop(&ret);
333
334 return ret;
335 }
336
337
338 const SkPdfObject* objAtAIndex(int i) const {
339 SkASSERT(fObjectType == kArray_PdfObjectType);
340
341 return (*fArray)[i];
342 }
343
344 SkPdfObject* operator[](int i) {
345 SkASSERT(fObjectType == kArray_PdfObjectType);
346
347 return (*fArray)[i];
348 }
349
350 const SkPdfObject* operator[](int i) const {
351 SkASSERT(fObjectType == kArray_PdfObjectType);
352
353 return (*fArray)[i];
354 }
355
356
357 // TODO(edisonn): make the functions to return SkPdfDictionary, move these functions in SkPdfDictionary
358 static void makeEmptyDictionary(SkPdfObject* obj) {
359 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
360
361 obj->fObjectType = kDictionary_PdfObjectType;
362 obj->fMap = new SkTDict<SkPdfObject*>(1);
363 obj->fStr.fBuffer = NULL;
364 obj->fStr.fBytes = 0;
365 }
366
367 // TODO(edisonn): get all the possible names from spec, and compute a hash function
368 // that would create no overlaps in the same dictionary
369 // or build a tree of chars that when followed goes to a unique id/index/hash
370 // TODO(edisonn): generate constants like kDictFoo, kNameDict_name
371 // which will be used in code
372 // add function SkPdfFastNameKey key(const char* key);
373 // TODO(edisonn): setting the same key twike, will make the value undefined!
edisonn@google.com2fd5d362013-07-23 19:43:48 +0000374 bool set(const SkPdfObject* key, SkPdfObject* value) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000375 SkASSERT(fObjectType == kDictionary_PdfObjectType);
376 SkASSERT(key->fObjectType == kName_PdfObjectType);
377
378 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
379 // TODO(edisonn): report err
380 return false;
381 }
382
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000383 //// we rewrite all delimiters and white spaces with '\0', so we expect the end of name to be '\0'
384 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0');
edisonn@google.com571c70b2013-07-10 17:09:50 +0000385
edisonn@google.comd761e322013-07-22 17:29:43 +0000386 return set(key->fStr.fBuffer, key->fStr.fBytes, value);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000387 }
388
389 bool set(const char* key, SkPdfObject* value) {
edisonn@google.comd761e322013-07-22 17:29:43 +0000390 return set((const unsigned char*)key, strlen(key), value);
391 }
392
393 bool set(const unsigned char* key, size_t len, SkPdfObject* value) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000394 SkASSERT(fObjectType == kDictionary_PdfObjectType);
395
396 if (fObjectType != kDictionary_PdfObjectType) {
397 // TODO(edisonn): report err
398 return false;
399 }
400
edisonn@google.comd761e322013-07-22 17:29:43 +0000401 return fMap->set((const char*)key, len, value);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000402 }
403
edisonn@google.com2fd5d362013-07-23 19:43:48 +0000404 SkPdfObject* get(const SkPdfObject* key) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000405 SkASSERT(fObjectType == kDictionary_PdfObjectType);
406 SkASSERT(key->fObjectType == kName_PdfObjectType);
407
408 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
409 // TODO(edisonn): report err
edisonn@google.com3fc48262013-07-22 15:29:55 +0000410 return NULL;
edisonn@google.com571c70b2013-07-10 17:09:50 +0000411 }
412
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000413 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0');
edisonn@google.com571c70b2013-07-10 17:09:50 +0000414
edisonn@google.comd761e322013-07-22 17:29:43 +0000415 return get(key->fStr.fBuffer, key->fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000416 }
417
418 SkPdfObject* get(const char* key) {
edisonn@google.comd761e322013-07-22 17:29:43 +0000419 return get((const unsigned char*)key, strlen(key));
420 }
421
422 SkPdfObject* get(const unsigned char* key, size_t len) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000423 SkASSERT(fObjectType == kDictionary_PdfObjectType);
424 SkASSERT(key);
425 if (fObjectType != kDictionary_PdfObjectType) {
426 // TODO(edisonn): report err
427 return NULL;
428 }
429 SkPdfObject* ret = NULL;
edisonn@google.comd761e322013-07-22 17:29:43 +0000430 fMap->find((const char*)key, len, &ret);
edisonn@google.com9a43c182013-08-01 20:06:42 +0000431
432#ifdef PDF_TRACE
433 SkString _key;
434 _key.append((const char*)key, len);
435 printf("\nget(/%s) = %s\n", _key.c_str(), ret ? ret->toString(0, len + 9).c_str() : "_NOT_FOUND");
436#endif
437
edisonn@google.com571c70b2013-07-10 17:09:50 +0000438 return ret;
439 }
440
edisonn@google.com2fd5d362013-07-23 19:43:48 +0000441 const SkPdfObject* get(const SkPdfObject* key) const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000442 SkASSERT(fObjectType == kDictionary_PdfObjectType);
443 SkASSERT(key->fObjectType == kName_PdfObjectType);
444
445 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
446 // TODO(edisonn): report err
edisonn@google.com3fc48262013-07-22 15:29:55 +0000447 return NULL;
edisonn@google.com571c70b2013-07-10 17:09:50 +0000448 }
449
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000450 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0');
edisonn@google.com571c70b2013-07-10 17:09:50 +0000451
edisonn@google.comd761e322013-07-22 17:29:43 +0000452 return get(key->fStr.fBuffer, key->fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000453 }
454
edisonn@google.com571c70b2013-07-10 17:09:50 +0000455 const SkPdfObject* get(const char* key) const {
edisonn@google.comd761e322013-07-22 17:29:43 +0000456 return get((const unsigned char*)key, strlen(key));
457 }
458
459 const SkPdfObject* get(const unsigned char* key, size_t len) const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000460 SkASSERT(fObjectType == kDictionary_PdfObjectType);
461 SkASSERT(key);
462 if (fObjectType != kDictionary_PdfObjectType) {
463 // TODO(edisonn): report err
464 return NULL;
465 }
466 SkPdfObject* ret = NULL;
edisonn@google.comd761e322013-07-22 17:29:43 +0000467 fMap->find((const char*)key, len, &ret);
edisonn@google.com9a43c182013-08-01 20:06:42 +0000468
469#ifdef PDF_TRACE
470 SkString _key;
471 _key.append((const char*)key, len);
472 printf("\nget(/%s) = %s\n", _key.c_str(), ret ? ret->toString(0, len + 9).c_str() : "_NOT_FOUND");
473#endif
474
edisonn@google.com571c70b2013-07-10 17:09:50 +0000475 return ret;
476 }
477
478 const SkPdfObject* get(const char* key, const char* abr) const {
479 const SkPdfObject* ret = get(key);
480 // TODO(edisonn): / is a valid name, and it might be an abreviation, so "" should not be like NULL
481 // make this distiontion in generator, and remove "" from condition
482 if (ret != NULL || abr == NULL || *abr == '\0') {
483 return ret;
484 }
485 return get(abr);
486 }
487
488 SkPdfObject* get(const char* key, const char* abr) {
489 SkPdfObject* ret = get(key);
490 // TODO(edisonn): / is a valid name, and it might be an abreviation, so "" should not be like NULL
491 // make this distiontion in generator, and remove "" from condition
492 if (ret != NULL || abr == NULL || *abr == '\0') {
493 return ret;
494 }
495 return get(abr);
496 }
497
498 SkPdfDictionary* asDictionary() {
499 SkASSERT(isDictionary());
500 if (!isDictionary()) {
501 return NULL;
502 }
503 return (SkPdfDictionary*) this;
504 }
505
506 const SkPdfDictionary* asDictionary() const {
507 SkASSERT(isDictionary());
508 if (!isDictionary()) {
509 return NULL;
510 }
511 return (SkPdfDictionary*) this;
512 }
513
514
515 bool isReference() const {
516 return fObjectType == kReference_PdfObjectType;
517 }
518
519 bool isBoolean() const {
520 return fObjectType == kBoolean_PdfObjectType;
521 }
522
523 bool isInteger() const {
524 return fObjectType == kInteger_PdfObjectType;
525 }
526private:
527 bool isReal() const {
528 return fObjectType == kReal_PdfObjectType;
529 }
530public:
531 bool isNumber() const {
532 return fObjectType == kInteger_PdfObjectType || fObjectType == kReal_PdfObjectType;
533 }
534
535 bool isKeywordReference() const {
536 return fObjectType == kKeyword_PdfObjectType && fStr.fBytes == 1 && fStr.fBuffer[0] == 'R';
537 }
538
539 bool isKeyword() const {
540 return fObjectType == kKeyword_PdfObjectType;
541 }
542
edisonn@google.com4ef4bed2013-07-29 22:14:45 +0000543 bool isKeyword(const char* keyword) const {
544 if (!isKeyword()) {
545 return false;
546 }
547
548 if (strlen(keyword) != fStr.fBytes) {
549 return false;
550 }
551
552 if (strncmp(keyword, (const char*)fStr.fBuffer, fStr.fBytes) != 0) {
553 return false;
554 }
555
556 return true;
557 }
558
edisonn@google.com571c70b2013-07-10 17:09:50 +0000559 bool isName() const {
560 return fObjectType == kName_PdfObjectType;
561 }
562
edisonn@google.com78b38b12013-07-15 18:20:58 +0000563 bool isName(const char* name) const {
564 return fObjectType == kName_PdfObjectType && fStr.fBytes == strlen(name) && strncmp((const char*)fStr.fBuffer, name, fStr.fBytes) == 0;
565 }
566
edisonn@google.com571c70b2013-07-10 17:09:50 +0000567 bool isArray() const {
568 return fObjectType == kArray_PdfObjectType;
569 }
570
571 bool isDate() const {
572 return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType;
573 }
574
575 bool isDictionary() const {
576 return fObjectType == kDictionary_PdfObjectType;
577 }
578
579 bool isFunction() const {
580 return false; // NYI
581 }
582
583 bool isRectangle() const {
584 return fObjectType == kArray_PdfObjectType && fArray->count() == 4; // NYI + and elems are numbers
585 }
586
587 // TODO(edisonn): has stream .. or is stream ... TBD
588 bool hasStream() const {
589 return isDictionary() && fStr.fBuffer != NULL;
590 }
591
592 // TODO(edisonn): has stream .. or is stream ... TBD
593 const SkPdfStream* getStream() const {
594 return hasStream() ? (const SkPdfStream*)this : NULL;
595 }
596
597 SkPdfStream* getStream() {
598 return hasStream() ? (SkPdfStream*)this : NULL;
599 }
600
601 bool isAnyString() const {
602 return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType;
603 }
604
605 bool isMatrix() const {
606 return fObjectType == kArray_PdfObjectType && fArray->count() == 6; // NYI + and elems are numbers
607 }
608
609 inline int64_t intValue() const {
610 SkASSERT(fObjectType == kInteger_PdfObjectType);
611
612 if (fObjectType != kInteger_PdfObjectType) {
613 // TODO(edisonn): log err
614 return 0;
615 }
616 return fIntegerValue;
617 }
618private:
619 inline double realValue() const {
620 SkASSERT(fObjectType == kReal_PdfObjectType);
621
622 if (fObjectType != kReal_PdfObjectType) {
623 // TODO(edisonn): log err
624 return 0;
625 }
626 return fRealValue;
627 }
628public:
629 inline double numberValue() const {
630 SkASSERT(isNumber());
631
632 if (!isNumber()) {
633 // TODO(edisonn): log err
634 return 0;
635 }
636 return fObjectType == kReal_PdfObjectType ? fRealValue : fIntegerValue;
637 }
638
edisonn@google.coma0cefa12013-07-28 18:34:14 +0000639 inline SkScalar scalarValue() const {
640 SkASSERT(isNumber());
641
642 if (!isNumber()) {
643 // TODO(edisonn): log err
644 return SkIntToScalar(0);
645 }
646 return fObjectType == kReal_PdfObjectType ? SkDoubleToScalar(fRealValue) :
647 SkIntToScalar(fIntegerValue);
648 }
649
edisonn@google.com571c70b2013-07-10 17:09:50 +0000650 int referenceId() const {
651 SkASSERT(fObjectType == kReference_PdfObjectType);
652 return fRef.fId;
653 }
654
655 int referenceGeneration() const {
656 SkASSERT(fObjectType == kReference_PdfObjectType);
657 return fRef.fGen;
658 }
659
660 inline const char* nameValue() const {
661 SkASSERT(fObjectType == kName_PdfObjectType);
662
663 if (fObjectType != kName_PdfObjectType) {
664 // TODO(edisonn): log err
665 return "";
666 }
667 return (const char*)fStr.fBuffer;
668 }
669
670 inline const char* stringValue() const {
671 SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType);
672
673 if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
674 // TODO(edisonn): log err
675 return "";
676 }
677 return (const char*)fStr.fBuffer;
678 }
679
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000680 inline NotOwnedString strRef() {
681 switch (fObjectType) {
682 case kString_PdfObjectType:
683 case kHexString_PdfObjectType:
684 case kKeyword_PdfObjectType:
685 return fStr;
686
687 default:
688 // TODO(edisonn): report/warning
689 return NotOwnedString();
690 }
691 }
692
edisonn@google.com571c70b2013-07-10 17:09:50 +0000693 // TODO(edisonn): nameValue2 and stringValue2 are used to make code generation easy,
694 // but it is not a performat way to do it, since it will create an extra copy
695 // remove these functions and make code generated faster
696 inline std::string nameValue2() const {
697 SkASSERT(fObjectType == kName_PdfObjectType);
698
699 if (fObjectType != kName_PdfObjectType) {
700 // TODO(edisonn): log err
701 return "";
702 }
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000703 return std::string((const char*)fStr.fBuffer, fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000704 }
705
706 inline std::string stringValue2() 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 }
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000713 return std::string((const char*)fStr.fBuffer, fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000714 }
715
716 inline bool boolValue() const {
717 SkASSERT(fObjectType == kBoolean_PdfObjectType);
718
edisonn@google.comf111a4b2013-07-31 18:22:36 +0000719 if (fObjectType != kBoolean_PdfObjectType) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000720 // TODO(edisonn): log err
721 return false;
722 }
723 return fBooleanValue;
724 }
725
726 SkRect rectangleValue() const {
727 SkASSERT(isRectangle());
728 if (!isRectangle()) {
729 return SkRect::MakeEmpty();
730 }
731
732 double array[4];
733 for (int i = 0; i < 4; i++) {
734 // TODO(edisonn): version where we could resolve references?
735 const SkPdfObject* elem = objAtAIndex(i);
736 if (elem == NULL || !elem->isNumber()) {
737 // TODO(edisonn): report error
738 return SkRect::MakeEmpty();
739 }
740 array[i] = elem->numberValue();
741 }
742
743 return SkRect::MakeLTRB(SkDoubleToScalar(array[0]),
744 SkDoubleToScalar(array[1]),
745 SkDoubleToScalar(array[2]),
746 SkDoubleToScalar(array[3]));
747 }
748
749 SkMatrix matrixValue() const {
750 SkASSERT(isMatrix());
751 if (!isMatrix()) {
752 return SkMatrix::I();
753 }
754
755 double array[6];
756 for (int i = 0; i < 6; i++) {
757 // TODO(edisonn): version where we could resolve references?
758 const SkPdfObject* elem = objAtAIndex(i);
759 if (elem == NULL || !elem->isNumber()) {
760 // TODO(edisonn): report error
761 return SkMatrix::I();
762 }
763 array[i] = elem->numberValue();
764 }
765
766 return SkMatrixFromPdfMatrix(array);
767 }
768
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000769 bool filterStream();
edisonn@google.com571c70b2013-07-10 17:09:50 +0000770
771
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000772 bool GetFilteredStreamRef(unsigned char const** buffer, size_t* len) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000773 // TODO(edisonn): add params that couls let the last filter in place if it is jpeg or png to fast load images
774 if (!hasStream()) {
775 return false;
776 }
777
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000778 filterStream();
edisonn@google.com571c70b2013-07-10 17:09:50 +0000779
780 if (buffer) {
781 *buffer = fStr.fBuffer;
782 }
783
784 if (len) {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000785 *len = fStr.fBytes >> 2; // last 2 bits
edisonn@google.com571c70b2013-07-10 17:09:50 +0000786 }
787
788 return true;
789 }
790
791 bool isStreamFiltered() const {
792 return hasStream() && ((fStr.fBytes & 1) == kFilteredStreamBit);
793 }
794
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000795 bool isStreamOwned() const {
796 return hasStream() && ((fStr.fBytes & 2) == kOwnedStreamBit);
797 }
798
799 bool GetUnfilteredStreamRef(unsigned char const** buffer, size_t* len) const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000800 if (isStreamFiltered()) {
801 return false;
802 }
803
804 if (!hasStream()) {
805 return false;
806 }
807
808 if (buffer) {
809 *buffer = fStr.fBuffer;
810 }
811
812 if (len) {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000813 *len = fStr.fBytes >> 2; // remove last 2 bits
edisonn@google.com571c70b2013-07-10 17:09:50 +0000814 }
815
816 return true;
817 }
818
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000819 bool addStream(const unsigned char* buffer, size_t len) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000820 SkASSERT(!hasStream());
821 SkASSERT(isDictionary());
822
823 if (!isDictionary() || hasStream()) {
824 return false;
825 }
826
827 fStr.fBuffer = buffer;
828 fStr.fBytes = (len << 2) + kUnfilteredStreamBit;
829
830 return true;
831 }
832
edisonn@google.com9a43c182013-08-01 20:06:42 +0000833 void appendSpaces(SkString* str, int level) {
834 for (int i = 0 ; i < level; i++) {
835 str->append(" ");
836 }
837 }
838
839 SkString toString(int firstRowLevel = 0, int level = 0) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000840 SkString str;
edisonn@google.com9a43c182013-08-01 20:06:42 +0000841 appendSpaces(&str, firstRowLevel);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000842 switch (fObjectType) {
843 case kInvalid_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000844 str.append("__Invalid");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000845 break;
846
847 case kBoolean_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000848 str.appendf("%s", fBooleanValue ? "true" : "false");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000849 break;
850
851 case kInteger_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000852 str.appendf("%i", (int)fIntegerValue);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000853 break;
854
855 case kReal_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000856 str.appendf("%f", fRealValue);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000857 break;
858
859 case kString_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000860 str.append("\"");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000861 str.append((const char*)fStr.fBuffer, fStr.fBytes);
edisonn@google.com9a43c182013-08-01 20:06:42 +0000862 str.append("\"");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000863 break;
864
865 case kHexString_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000866 str.append("<");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000867 str.append((const char*)fStr.fBuffer, fStr.fBytes);
edisonn@google.com9a43c182013-08-01 20:06:42 +0000868 str.append(">");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000869 break;
870
871 case kName_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000872 str.append("/");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000873 str.append((const char*)fStr.fBuffer, fStr.fBytes);
874 break;
875
876 case kKeyword_PdfObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000877 str.append((const char*)fStr.fBuffer, fStr.fBytes);
878 break;
879
880 case kArray_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000881 str.append("[\n");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000882 for (unsigned int i = 0; i < size(); i++) {
edisonn@google.com9a43c182013-08-01 20:06:42 +0000883 str.append(objAtAIndex(i)->toString(level + 1, level + 1));
884 if (i < size() - 1) {
885 str.append(",");
886 }
887 str.append("\n");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000888 }
edisonn@google.com9a43c182013-08-01 20:06:42 +0000889 appendSpaces(&str, level);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000890 str.append("]");
891 break;
892
edisonn@google.com9a43c182013-08-01 20:06:42 +0000893 case kDictionary_PdfObjectType: {
894 SkTDict<SkPdfObject*>::Iter iter(*fMap);
895 SkPdfObject* obj = NULL;
896 const char* key = NULL;
897 str.append("<<\n");
898 while ((key = iter.next(&obj)) != NULL) {
899 appendSpaces(&str, level + 2);
900 str.appendf("/%s %s\n", key, obj->toString(0, level + strlen(key) + 4).c_str());
901 }
902 appendSpaces(&str, level);
903 str.append(">>");
904 if (hasStream()) {
905 str.append("stream HAS_STREAM endstream");
906 }
edisonn@google.com571c70b2013-07-10 17:09:50 +0000907 }
908 break;
909
910 case kNull_PdfObjectType:
911 str = "NULL";
912 break;
913
914 case kReference_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000915 str.appendf("%i %i R", fRef.fId, fRef.fGen);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000916 break;
917
918 case kUndefined_PdfObjectType:
919 str = "Undefined";
920 break;
921
922 default:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000923 str = "Error";
edisonn@google.com571c70b2013-07-10 17:09:50 +0000924 break;
925 }
926
927 return str;
928 }
929
930private:
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000931 static void makeStringCore(const unsigned char* start, SkPdfObject* obj, ObjectType type) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000932 makeStringCore(start, strlen((const char*)start), obj, type);
933 }
934
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000935 static void makeStringCore(const unsigned char* start, const unsigned char* end, SkPdfObject* obj, ObjectType type) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000936 makeStringCore(start, end - start, obj, type);
937 }
938
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000939 static void makeStringCore(const unsigned char* start, size_t bytes, SkPdfObject* obj, ObjectType type) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000940 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
941
942 obj->fObjectType = type;
943 obj->fStr.fBuffer = start;
944 obj->fStr.fBytes = bytes;
945 }
946
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000947 bool applyFilter(const char* name);
948 bool applyFlateDecodeFilter();
949 bool applyDCTDecodeFilter();
edisonn@google.com571c70b2013-07-10 17:09:50 +0000950};
951
952class SkPdfStream : public SkPdfObject {};
953class SkPdfArray : public SkPdfObject {};
954class SkPdfString : public SkPdfObject {};
955class SkPdfHexString : public SkPdfObject {};
956class SkPdfInteger : public SkPdfObject {};
957class SkPdfReal : public SkPdfObject {};
958class SkPdfNumber : public SkPdfObject {};
959
edisonn@google.com78b38b12013-07-15 18:20:58 +0000960class SkPdfName : public SkPdfObject {
961 SkPdfName() : SkPdfObject() {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000962 SkPdfObject::makeName((const unsigned char*)"", this);
edisonn@google.com78b38b12013-07-15 18:20:58 +0000963 }
964public:
965 SkPdfName(char* name) : SkPdfObject() {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000966 this->makeName((const unsigned char*)name, this);
edisonn@google.com78b38b12013-07-15 18:20:58 +0000967 }
968};
969
edisonn@google.com571c70b2013-07-10 17:09:50 +0000970#endif // EXPERIMENTAL_PDFVIEWER_PDFPARSER_NATIVE_SKPDFOBJECT_H_