blob: 5d86d9b8ad2fb81f46f9897638c0a0226f98626c [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.com571c70b2013-07-10 17:09:50 +0000431 return ret;
432 }
433
edisonn@google.com2fd5d362013-07-23 19:43:48 +0000434 const SkPdfObject* get(const SkPdfObject* key) const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000435 SkASSERT(fObjectType == kDictionary_PdfObjectType);
436 SkASSERT(key->fObjectType == kName_PdfObjectType);
437
438 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
439 // TODO(edisonn): report err
edisonn@google.com3fc48262013-07-22 15:29:55 +0000440 return NULL;
edisonn@google.com571c70b2013-07-10 17:09:50 +0000441 }
442
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000443 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0');
edisonn@google.com571c70b2013-07-10 17:09:50 +0000444
edisonn@google.comd761e322013-07-22 17:29:43 +0000445 return get(key->fStr.fBuffer, key->fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000446 }
447
edisonn@google.com571c70b2013-07-10 17:09:50 +0000448 const SkPdfObject* get(const char* key) const {
edisonn@google.comd761e322013-07-22 17:29:43 +0000449 return get((const unsigned char*)key, strlen(key));
450 }
451
452 const SkPdfObject* get(const unsigned char* key, size_t len) const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000453 SkASSERT(fObjectType == kDictionary_PdfObjectType);
454 SkASSERT(key);
455 if (fObjectType != kDictionary_PdfObjectType) {
456 // TODO(edisonn): report err
457 return NULL;
458 }
459 SkPdfObject* ret = NULL;
edisonn@google.comd761e322013-07-22 17:29:43 +0000460 fMap->find((const char*)key, len, &ret);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000461 return ret;
462 }
463
464 const SkPdfObject* get(const char* key, const char* abr) const {
465 const 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 SkPdfObject* get(const char* key, const char* abr) {
475 SkPdfObject* ret = get(key);
476 // TODO(edisonn): / is a valid name, and it might be an abreviation, so "" should not be like NULL
477 // make this distiontion in generator, and remove "" from condition
478 if (ret != NULL || abr == NULL || *abr == '\0') {
479 return ret;
480 }
481 return get(abr);
482 }
483
484 SkPdfDictionary* asDictionary() {
485 SkASSERT(isDictionary());
486 if (!isDictionary()) {
487 return NULL;
488 }
489 return (SkPdfDictionary*) this;
490 }
491
492 const SkPdfDictionary* asDictionary() const {
493 SkASSERT(isDictionary());
494 if (!isDictionary()) {
495 return NULL;
496 }
497 return (SkPdfDictionary*) this;
498 }
499
500
501 bool isReference() const {
502 return fObjectType == kReference_PdfObjectType;
503 }
504
505 bool isBoolean() const {
506 return fObjectType == kBoolean_PdfObjectType;
507 }
508
509 bool isInteger() const {
510 return fObjectType == kInteger_PdfObjectType;
511 }
512private:
513 bool isReal() const {
514 return fObjectType == kReal_PdfObjectType;
515 }
516public:
517 bool isNumber() const {
518 return fObjectType == kInteger_PdfObjectType || fObjectType == kReal_PdfObjectType;
519 }
520
521 bool isKeywordReference() const {
522 return fObjectType == kKeyword_PdfObjectType && fStr.fBytes == 1 && fStr.fBuffer[0] == 'R';
523 }
524
525 bool isKeyword() const {
526 return fObjectType == kKeyword_PdfObjectType;
527 }
528
edisonn@google.com4ef4bed2013-07-29 22:14:45 +0000529 bool isKeyword(const char* keyword) const {
530 if (!isKeyword()) {
531 return false;
532 }
533
534 if (strlen(keyword) != fStr.fBytes) {
535 return false;
536 }
537
538 if (strncmp(keyword, (const char*)fStr.fBuffer, fStr.fBytes) != 0) {
539 return false;
540 }
541
542 return true;
543 }
544
edisonn@google.com571c70b2013-07-10 17:09:50 +0000545 bool isName() const {
546 return fObjectType == kName_PdfObjectType;
547 }
548
edisonn@google.com78b38b12013-07-15 18:20:58 +0000549 bool isName(const char* name) const {
550 return fObjectType == kName_PdfObjectType && fStr.fBytes == strlen(name) && strncmp((const char*)fStr.fBuffer, name, fStr.fBytes) == 0;
551 }
552
edisonn@google.com571c70b2013-07-10 17:09:50 +0000553 bool isArray() const {
554 return fObjectType == kArray_PdfObjectType;
555 }
556
557 bool isDate() const {
558 return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType;
559 }
560
561 bool isDictionary() const {
562 return fObjectType == kDictionary_PdfObjectType;
563 }
564
565 bool isFunction() const {
566 return false; // NYI
567 }
568
569 bool isRectangle() const {
570 return fObjectType == kArray_PdfObjectType && fArray->count() == 4; // NYI + and elems are numbers
571 }
572
573 // TODO(edisonn): has stream .. or is stream ... TBD
574 bool hasStream() const {
575 return isDictionary() && fStr.fBuffer != NULL;
576 }
577
578 // TODO(edisonn): has stream .. or is stream ... TBD
579 const SkPdfStream* getStream() const {
580 return hasStream() ? (const SkPdfStream*)this : NULL;
581 }
582
583 SkPdfStream* getStream() {
584 return hasStream() ? (SkPdfStream*)this : NULL;
585 }
586
587 bool isAnyString() const {
588 return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType;
589 }
590
591 bool isMatrix() const {
592 return fObjectType == kArray_PdfObjectType && fArray->count() == 6; // NYI + and elems are numbers
593 }
594
595 inline int64_t intValue() const {
596 SkASSERT(fObjectType == kInteger_PdfObjectType);
597
598 if (fObjectType != kInteger_PdfObjectType) {
599 // TODO(edisonn): log err
600 return 0;
601 }
602 return fIntegerValue;
603 }
604private:
605 inline double realValue() const {
606 SkASSERT(fObjectType == kReal_PdfObjectType);
607
608 if (fObjectType != kReal_PdfObjectType) {
609 // TODO(edisonn): log err
610 return 0;
611 }
612 return fRealValue;
613 }
614public:
615 inline double numberValue() const {
616 SkASSERT(isNumber());
617
618 if (!isNumber()) {
619 // TODO(edisonn): log err
620 return 0;
621 }
622 return fObjectType == kReal_PdfObjectType ? fRealValue : fIntegerValue;
623 }
624
edisonn@google.coma0cefa12013-07-28 18:34:14 +0000625 inline SkScalar scalarValue() const {
626 SkASSERT(isNumber());
627
628 if (!isNumber()) {
629 // TODO(edisonn): log err
630 return SkIntToScalar(0);
631 }
632 return fObjectType == kReal_PdfObjectType ? SkDoubleToScalar(fRealValue) :
633 SkIntToScalar(fIntegerValue);
634 }
635
edisonn@google.com571c70b2013-07-10 17:09:50 +0000636 int referenceId() const {
637 SkASSERT(fObjectType == kReference_PdfObjectType);
638 return fRef.fId;
639 }
640
641 int referenceGeneration() const {
642 SkASSERT(fObjectType == kReference_PdfObjectType);
643 return fRef.fGen;
644 }
645
646 inline const char* nameValue() const {
647 SkASSERT(fObjectType == kName_PdfObjectType);
648
649 if (fObjectType != kName_PdfObjectType) {
650 // TODO(edisonn): log err
651 return "";
652 }
653 return (const char*)fStr.fBuffer;
654 }
655
656 inline const char* stringValue() const {
657 SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType);
658
659 if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
660 // TODO(edisonn): log err
661 return "";
662 }
663 return (const char*)fStr.fBuffer;
664 }
665
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000666 inline NotOwnedString strRef() {
667 switch (fObjectType) {
668 case kString_PdfObjectType:
669 case kHexString_PdfObjectType:
670 case kKeyword_PdfObjectType:
671 return fStr;
672
673 default:
674 // TODO(edisonn): report/warning
675 return NotOwnedString();
676 }
677 }
678
edisonn@google.com571c70b2013-07-10 17:09:50 +0000679 // TODO(edisonn): nameValue2 and stringValue2 are used to make code generation easy,
680 // but it is not a performat way to do it, since it will create an extra copy
681 // remove these functions and make code generated faster
682 inline std::string nameValue2() const {
683 SkASSERT(fObjectType == kName_PdfObjectType);
684
685 if (fObjectType != kName_PdfObjectType) {
686 // TODO(edisonn): log err
687 return "";
688 }
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000689 return std::string((const char*)fStr.fBuffer, fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000690 }
691
692 inline std::string stringValue2() const {
693 SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType);
694
695 if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
696 // TODO(edisonn): log err
697 return "";
698 }
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000699 return std::string((const char*)fStr.fBuffer, fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000700 }
701
702 inline bool boolValue() const {
703 SkASSERT(fObjectType == kBoolean_PdfObjectType);
704
edisonn@google.comf111a4b2013-07-31 18:22:36 +0000705 if (fObjectType != kBoolean_PdfObjectType) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000706 // TODO(edisonn): log err
707 return false;
708 }
709 return fBooleanValue;
710 }
711
712 SkRect rectangleValue() const {
713 SkASSERT(isRectangle());
714 if (!isRectangle()) {
715 return SkRect::MakeEmpty();
716 }
717
718 double array[4];
719 for (int i = 0; i < 4; i++) {
720 // TODO(edisonn): version where we could resolve references?
721 const SkPdfObject* elem = objAtAIndex(i);
722 if (elem == NULL || !elem->isNumber()) {
723 // TODO(edisonn): report error
724 return SkRect::MakeEmpty();
725 }
726 array[i] = elem->numberValue();
727 }
728
729 return SkRect::MakeLTRB(SkDoubleToScalar(array[0]),
730 SkDoubleToScalar(array[1]),
731 SkDoubleToScalar(array[2]),
732 SkDoubleToScalar(array[3]));
733 }
734
735 SkMatrix matrixValue() const {
736 SkASSERT(isMatrix());
737 if (!isMatrix()) {
738 return SkMatrix::I();
739 }
740
741 double array[6];
742 for (int i = 0; i < 6; i++) {
743 // TODO(edisonn): version where we could resolve references?
744 const SkPdfObject* elem = objAtAIndex(i);
745 if (elem == NULL || !elem->isNumber()) {
746 // TODO(edisonn): report error
747 return SkMatrix::I();
748 }
749 array[i] = elem->numberValue();
750 }
751
752 return SkMatrixFromPdfMatrix(array);
753 }
754
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000755 bool filterStream();
edisonn@google.com571c70b2013-07-10 17:09:50 +0000756
757
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000758 bool GetFilteredStreamRef(unsigned char const** buffer, size_t* len) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000759 // TODO(edisonn): add params that couls let the last filter in place if it is jpeg or png to fast load images
760 if (!hasStream()) {
761 return false;
762 }
763
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000764 filterStream();
edisonn@google.com571c70b2013-07-10 17:09:50 +0000765
766 if (buffer) {
767 *buffer = fStr.fBuffer;
768 }
769
770 if (len) {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000771 *len = fStr.fBytes >> 2; // last 2 bits
edisonn@google.com571c70b2013-07-10 17:09:50 +0000772 }
773
774 return true;
775 }
776
777 bool isStreamFiltered() const {
778 return hasStream() && ((fStr.fBytes & 1) == kFilteredStreamBit);
779 }
780
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000781 bool isStreamOwned() const {
782 return hasStream() && ((fStr.fBytes & 2) == kOwnedStreamBit);
783 }
784
785 bool GetUnfilteredStreamRef(unsigned char const** buffer, size_t* len) const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000786 if (isStreamFiltered()) {
787 return false;
788 }
789
790 if (!hasStream()) {
791 return false;
792 }
793
794 if (buffer) {
795 *buffer = fStr.fBuffer;
796 }
797
798 if (len) {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000799 *len = fStr.fBytes >> 2; // remove last 2 bits
edisonn@google.com571c70b2013-07-10 17:09:50 +0000800 }
801
802 return true;
803 }
804
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000805 bool addStream(const unsigned char* buffer, size_t len) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000806 SkASSERT(!hasStream());
807 SkASSERT(isDictionary());
808
809 if (!isDictionary() || hasStream()) {
810 return false;
811 }
812
813 fStr.fBuffer = buffer;
814 fStr.fBytes = (len << 2) + kUnfilteredStreamBit;
815
816 return true;
817 }
818
819 SkString toString() {
820 SkString str;
821 switch (fObjectType) {
822 case kInvalid_PdfObjectType:
823 str.append("Invalid");
824 break;
825
826 case kBoolean_PdfObjectType:
827 str.appendf("Boolean: %s", fBooleanValue ? "true" : "false");
828 break;
829
830 case kInteger_PdfObjectType:
831 str.appendf("Integer: %i", (int)fIntegerValue);
832 break;
833
834 case kReal_PdfObjectType:
835 str.appendf("Real: %f", fRealValue);
836 break;
837
838 case kString_PdfObjectType:
839 str.appendf("String, len() = %u: ", (unsigned int)fStr.fBytes);
840 str.append((const char*)fStr.fBuffer, fStr.fBytes);
841 break;
842
843 case kHexString_PdfObjectType:
844 str.appendf("HexString, len() = %u: ", (unsigned int)fStr.fBytes);
845 str.append((const char*)fStr.fBuffer, fStr.fBytes);
846 break;
847
848 case kName_PdfObjectType:
849 str.appendf("Name, len() = %u: ", (unsigned int)fStr.fBytes);
850 str.append((const char*)fStr.fBuffer, fStr.fBytes);
851 break;
852
853 case kKeyword_PdfObjectType:
854 str.appendf("Keyword, len() = %u: ", (unsigned int)fStr.fBytes);
855 str.append((const char*)fStr.fBuffer, fStr.fBytes);
856 break;
857
858 case kArray_PdfObjectType:
859 str.append("Array, size() = %i [", size());
860 for (unsigned int i = 0; i < size(); i++) {
861 str.append(objAtAIndex(i)->toString());
862 }
863 str.append("]");
864 break;
865
866 case kDictionary_PdfObjectType:
867 // TODO(edisonn): NYI
868 str.append("Dictionary: NYI");
869 if (hasStream()) {
870 str.append(" HAS_STREAM");
871 }
872 break;
873
874 case kNull_PdfObjectType:
875 str = "NULL";
876 break;
877
878 case kReference_PdfObjectType:
879 str.appendf("Reference: %i %i", fRef.fId, fRef.fGen);
880 break;
881
882 case kUndefined_PdfObjectType:
883 str = "Undefined";
884 break;
885
886 default:
887 str = "Internal Error Object Type";
888 break;
889 }
890
891 return str;
892 }
893
894private:
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000895 static void makeStringCore(const unsigned char* start, SkPdfObject* obj, ObjectType type) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000896 makeStringCore(start, strlen((const char*)start), obj, type);
897 }
898
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000899 static void makeStringCore(const unsigned char* start, const unsigned char* end, SkPdfObject* obj, ObjectType type) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000900 makeStringCore(start, end - start, obj, type);
901 }
902
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000903 static void makeStringCore(const unsigned char* start, size_t bytes, SkPdfObject* obj, ObjectType type) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000904 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
905
906 obj->fObjectType = type;
907 obj->fStr.fBuffer = start;
908 obj->fStr.fBytes = bytes;
909 }
910
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000911 bool applyFilter(const char* name);
912 bool applyFlateDecodeFilter();
913 bool applyDCTDecodeFilter();
edisonn@google.com571c70b2013-07-10 17:09:50 +0000914};
915
916class SkPdfStream : public SkPdfObject {};
917class SkPdfArray : public SkPdfObject {};
918class SkPdfString : public SkPdfObject {};
919class SkPdfHexString : public SkPdfObject {};
920class SkPdfInteger : public SkPdfObject {};
921class SkPdfReal : public SkPdfObject {};
922class SkPdfNumber : public SkPdfObject {};
923
edisonn@google.com78b38b12013-07-15 18:20:58 +0000924class SkPdfName : public SkPdfObject {
925 SkPdfName() : SkPdfObject() {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000926 SkPdfObject::makeName((const unsigned char*)"", this);
edisonn@google.com78b38b12013-07-15 18:20:58 +0000927 }
928public:
929 SkPdfName(char* name) : SkPdfObject() {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000930 this->makeName((const unsigned char*)name, this);
edisonn@google.com78b38b12013-07-15 18:20:58 +0000931 }
932};
933
edisonn@google.com571c70b2013-07-10 17:09:50 +0000934#endif // EXPERIMENTAL_PDFVIEWER_PDFPARSER_NATIVE_SKPDFOBJECT_H_