blob: 9df9a239e67e21079aff89c1b7b77e9853a275c8 [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
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
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000215 static void makeNumeric(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000216 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;
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000221 for (const unsigned char* current = start; current < end; current++) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000222 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
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000244 static void makeString(const unsigned char* start, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000245 makeStringCore(start, strlen((const char*)start), obj, kString_PdfObjectType);
246 }
247
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000248 static void makeString(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000249 makeStringCore(start, end - start, obj, kString_PdfObjectType);
250 }
251
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000252 static void makeString(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000253 makeStringCore(start, bytes, obj, kString_PdfObjectType);
254 }
255
256
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000257 static void makeHexString(const unsigned char* start, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000258 makeStringCore(start, strlen((const char*)start), obj, kHexString_PdfObjectType);
259 }
260
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000261 static void makeHexString(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000262 makeStringCore(start, end - start, obj, kHexString_PdfObjectType);
263 }
264
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000265 static void makeHexString(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000266 makeStringCore(start, bytes, obj, kHexString_PdfObjectType);
267 }
268
269
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000270 static void makeName(const unsigned char* start, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000271 makeStringCore(start, strlen((const char*)start), obj, kName_PdfObjectType);
272 }
273
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000274 static void makeName(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000275 makeStringCore(start, end - start, obj, kName_PdfObjectType);
276 }
277
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000278 static void makeName(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000279 makeStringCore(start, bytes, obj, kName_PdfObjectType);
280 }
281
282
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000283 static void makeKeyword(const unsigned char* start, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000284 makeStringCore(start, strlen((const char*)start), obj, kKeyword_PdfObjectType);
285 }
286
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000287 static void makeKeyword(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000288 makeStringCore(start, end - start, obj, kKeyword_PdfObjectType);
289 }
290
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000291 static void makeKeyword(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000292 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!
edisonn@google.com2fd5d362013-07-23 19:43:48 +0000375 bool set(const SkPdfObject* key, SkPdfObject* value) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000376 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
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000384 //// 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');
edisonn@google.com571c70b2013-07-10 17:09:50 +0000386
edisonn@google.comd761e322013-07-22 17:29:43 +0000387 return set(key->fStr.fBuffer, key->fStr.fBytes, value);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000388 }
389
390 bool set(const char* key, SkPdfObject* value) {
edisonn@google.comd761e322013-07-22 17:29:43 +0000391 return set((const unsigned char*)key, strlen(key), value);
392 }
393
394 bool set(const unsigned char* key, size_t len, SkPdfObject* value) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000395 SkASSERT(fObjectType == kDictionary_PdfObjectType);
396
397 if (fObjectType != kDictionary_PdfObjectType) {
398 // TODO(edisonn): report err
399 return false;
400 }
401
edisonn@google.comd761e322013-07-22 17:29:43 +0000402 return fMap->set((const char*)key, len, value);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000403 }
404
edisonn@google.com2fd5d362013-07-23 19:43:48 +0000405 SkPdfObject* get(const SkPdfObject* key) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000406 SkASSERT(fObjectType == kDictionary_PdfObjectType);
407 SkASSERT(key->fObjectType == kName_PdfObjectType);
408
409 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
410 // TODO(edisonn): report err
edisonn@google.com3fc48262013-07-22 15:29:55 +0000411 return NULL;
edisonn@google.com571c70b2013-07-10 17:09:50 +0000412 }
413
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000414 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0');
edisonn@google.com571c70b2013-07-10 17:09:50 +0000415
edisonn@google.comd761e322013-07-22 17:29:43 +0000416 return get(key->fStr.fBuffer, key->fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000417 }
418
419 SkPdfObject* get(const char* key) {
edisonn@google.comd761e322013-07-22 17:29:43 +0000420 return get((const unsigned char*)key, strlen(key));
421 }
422
423 SkPdfObject* get(const unsigned char* key, size_t len) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000424 SkASSERT(fObjectType == kDictionary_PdfObjectType);
425 SkASSERT(key);
426 if (fObjectType != kDictionary_PdfObjectType) {
427 // TODO(edisonn): report err
428 return NULL;
429 }
430 SkPdfObject* ret = NULL;
edisonn@google.comd761e322013-07-22 17:29:43 +0000431 fMap->find((const char*)key, len, &ret);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000432 return ret;
433 }
434
edisonn@google.com2fd5d362013-07-23 19:43:48 +0000435 const SkPdfObject* get(const SkPdfObject* key) const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000436 SkASSERT(fObjectType == kDictionary_PdfObjectType);
437 SkASSERT(key->fObjectType == kName_PdfObjectType);
438
439 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
440 // TODO(edisonn): report err
edisonn@google.com3fc48262013-07-22 15:29:55 +0000441 return NULL;
edisonn@google.com571c70b2013-07-10 17:09:50 +0000442 }
443
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000444 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0');
edisonn@google.com571c70b2013-07-10 17:09:50 +0000445
edisonn@google.comd761e322013-07-22 17:29:43 +0000446 return get(key->fStr.fBuffer, key->fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000447 }
448
edisonn@google.com571c70b2013-07-10 17:09:50 +0000449 const SkPdfObject* get(const char* key) const {
edisonn@google.comd761e322013-07-22 17:29:43 +0000450 return get((const unsigned char*)key, strlen(key));
451 }
452
453 const SkPdfObject* get(const unsigned char* key, size_t len) const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000454 SkASSERT(fObjectType == kDictionary_PdfObjectType);
455 SkASSERT(key);
456 if (fObjectType != kDictionary_PdfObjectType) {
457 // TODO(edisonn): report err
458 return NULL;
459 }
460 SkPdfObject* ret = NULL;
edisonn@google.comd761e322013-07-22 17:29:43 +0000461 fMap->find((const char*)key, len, &ret);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000462 return ret;
463 }
464
465 const SkPdfObject* get(const char* key, const char* abr) const {
466 const SkPdfObject* ret = get(key);
467 // TODO(edisonn): / is a valid name, and it might be an abreviation, so "" should not be like NULL
468 // make this distiontion in generator, and remove "" from condition
469 if (ret != NULL || abr == NULL || *abr == '\0') {
470 return ret;
471 }
472 return get(abr);
473 }
474
475 SkPdfObject* get(const char* key, const char* abr) {
476 SkPdfObject* ret = get(key);
477 // TODO(edisonn): / is a valid name, and it might be an abreviation, so "" should not be like NULL
478 // make this distiontion in generator, and remove "" from condition
479 if (ret != NULL || abr == NULL || *abr == '\0') {
480 return ret;
481 }
482 return get(abr);
483 }
484
485 SkPdfDictionary* asDictionary() {
486 SkASSERT(isDictionary());
487 if (!isDictionary()) {
488 return NULL;
489 }
490 return (SkPdfDictionary*) this;
491 }
492
493 const SkPdfDictionary* asDictionary() const {
494 SkASSERT(isDictionary());
495 if (!isDictionary()) {
496 return NULL;
497 }
498 return (SkPdfDictionary*) this;
499 }
500
501
502 bool isReference() const {
503 return fObjectType == kReference_PdfObjectType;
504 }
505
506 bool isBoolean() const {
507 return fObjectType == kBoolean_PdfObjectType;
508 }
509
510 bool isInteger() const {
511 return fObjectType == kInteger_PdfObjectType;
512 }
513private:
514 bool isReal() const {
515 return fObjectType == kReal_PdfObjectType;
516 }
517public:
518 bool isNumber() const {
519 return fObjectType == kInteger_PdfObjectType || fObjectType == kReal_PdfObjectType;
520 }
521
522 bool isKeywordReference() const {
523 return fObjectType == kKeyword_PdfObjectType && fStr.fBytes == 1 && fStr.fBuffer[0] == 'R';
524 }
525
526 bool isKeyword() const {
527 return fObjectType == kKeyword_PdfObjectType;
528 }
529
530 bool isName() const {
531 return fObjectType == kName_PdfObjectType;
532 }
533
edisonn@google.com78b38b12013-07-15 18:20:58 +0000534 bool isName(const char* name) const {
535 return fObjectType == kName_PdfObjectType && fStr.fBytes == strlen(name) && strncmp((const char*)fStr.fBuffer, name, fStr.fBytes) == 0;
536 }
537
edisonn@google.com571c70b2013-07-10 17:09:50 +0000538 bool isArray() const {
539 return fObjectType == kArray_PdfObjectType;
540 }
541
542 bool isDate() const {
543 return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType;
544 }
545
546 bool isDictionary() const {
547 return fObjectType == kDictionary_PdfObjectType;
548 }
549
550 bool isFunction() const {
551 return false; // NYI
552 }
553
554 bool isRectangle() const {
555 return fObjectType == kArray_PdfObjectType && fArray->count() == 4; // NYI + and elems are numbers
556 }
557
558 // TODO(edisonn): has stream .. or is stream ... TBD
559 bool hasStream() const {
560 return isDictionary() && fStr.fBuffer != NULL;
561 }
562
563 // TODO(edisonn): has stream .. or is stream ... TBD
564 const SkPdfStream* getStream() const {
565 return hasStream() ? (const SkPdfStream*)this : NULL;
566 }
567
568 SkPdfStream* getStream() {
569 return hasStream() ? (SkPdfStream*)this : NULL;
570 }
571
572 bool isAnyString() const {
573 return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType;
574 }
575
576 bool isMatrix() const {
577 return fObjectType == kArray_PdfObjectType && fArray->count() == 6; // NYI + and elems are numbers
578 }
579
580 inline int64_t intValue() const {
581 SkASSERT(fObjectType == kInteger_PdfObjectType);
582
583 if (fObjectType != kInteger_PdfObjectType) {
584 // TODO(edisonn): log err
585 return 0;
586 }
587 return fIntegerValue;
588 }
589private:
590 inline double realValue() const {
591 SkASSERT(fObjectType == kReal_PdfObjectType);
592
593 if (fObjectType != kReal_PdfObjectType) {
594 // TODO(edisonn): log err
595 return 0;
596 }
597 return fRealValue;
598 }
599public:
600 inline double numberValue() const {
601 SkASSERT(isNumber());
602
603 if (!isNumber()) {
604 // TODO(edisonn): log err
605 return 0;
606 }
607 return fObjectType == kReal_PdfObjectType ? fRealValue : fIntegerValue;
608 }
609
edisonn@google.coma0cefa12013-07-28 18:34:14 +0000610 inline SkScalar scalarValue() const {
611 SkASSERT(isNumber());
612
613 if (!isNumber()) {
614 // TODO(edisonn): log err
615 return SkIntToScalar(0);
616 }
617 return fObjectType == kReal_PdfObjectType ? SkDoubleToScalar(fRealValue) :
618 SkIntToScalar(fIntegerValue);
619 }
620
edisonn@google.com571c70b2013-07-10 17:09:50 +0000621 int referenceId() const {
622 SkASSERT(fObjectType == kReference_PdfObjectType);
623 return fRef.fId;
624 }
625
626 int referenceGeneration() const {
627 SkASSERT(fObjectType == kReference_PdfObjectType);
628 return fRef.fGen;
629 }
630
631 inline const char* nameValue() const {
632 SkASSERT(fObjectType == kName_PdfObjectType);
633
634 if (fObjectType != kName_PdfObjectType) {
635 // TODO(edisonn): log err
636 return "";
637 }
638 return (const char*)fStr.fBuffer;
639 }
640
641 inline const char* stringValue() const {
642 SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType);
643
644 if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
645 // TODO(edisonn): log err
646 return "";
647 }
648 return (const char*)fStr.fBuffer;
649 }
650
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000651 inline NotOwnedString strRef() {
652 switch (fObjectType) {
653 case kString_PdfObjectType:
654 case kHexString_PdfObjectType:
655 case kKeyword_PdfObjectType:
656 return fStr;
657
658 default:
659 // TODO(edisonn): report/warning
660 return NotOwnedString();
661 }
662 }
663
edisonn@google.com571c70b2013-07-10 17:09:50 +0000664 // TODO(edisonn): nameValue2 and stringValue2 are used to make code generation easy,
665 // but it is not a performat way to do it, since it will create an extra copy
666 // remove these functions and make code generated faster
667 inline std::string nameValue2() const {
668 SkASSERT(fObjectType == kName_PdfObjectType);
669
670 if (fObjectType != kName_PdfObjectType) {
671 // TODO(edisonn): log err
672 return "";
673 }
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000674 return std::string((const char*)fStr.fBuffer, fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000675 }
676
677 inline std::string stringValue2() const {
678 SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType);
679
680 if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
681 // TODO(edisonn): log err
682 return "";
683 }
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000684 return std::string((const char*)fStr.fBuffer, fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000685 }
686
687 inline bool boolValue() const {
688 SkASSERT(fObjectType == kBoolean_PdfObjectType);
689
690 if (fObjectType == kBoolean_PdfObjectType) {
691 // TODO(edisonn): log err
692 return false;
693 }
694 return fBooleanValue;
695 }
696
697 SkRect rectangleValue() const {
698 SkASSERT(isRectangle());
699 if (!isRectangle()) {
700 return SkRect::MakeEmpty();
701 }
702
703 double array[4];
704 for (int i = 0; i < 4; i++) {
705 // TODO(edisonn): version where we could resolve references?
706 const SkPdfObject* elem = objAtAIndex(i);
707 if (elem == NULL || !elem->isNumber()) {
708 // TODO(edisonn): report error
709 return SkRect::MakeEmpty();
710 }
711 array[i] = elem->numberValue();
712 }
713
714 return SkRect::MakeLTRB(SkDoubleToScalar(array[0]),
715 SkDoubleToScalar(array[1]),
716 SkDoubleToScalar(array[2]),
717 SkDoubleToScalar(array[3]));
718 }
719
720 SkMatrix matrixValue() const {
721 SkASSERT(isMatrix());
722 if (!isMatrix()) {
723 return SkMatrix::I();
724 }
725
726 double array[6];
727 for (int i = 0; i < 6; i++) {
728 // TODO(edisonn): version where we could resolve references?
729 const SkPdfObject* elem = objAtAIndex(i);
730 if (elem == NULL || !elem->isNumber()) {
731 // TODO(edisonn): report error
732 return SkMatrix::I();
733 }
734 array[i] = elem->numberValue();
735 }
736
737 return SkMatrixFromPdfMatrix(array);
738 }
739
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000740 bool filterStream();
edisonn@google.com571c70b2013-07-10 17:09:50 +0000741
742
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000743 bool GetFilteredStreamRef(unsigned char const** buffer, size_t* len) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000744 // TODO(edisonn): add params that couls let the last filter in place if it is jpeg or png to fast load images
745 if (!hasStream()) {
746 return false;
747 }
748
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000749 filterStream();
edisonn@google.com571c70b2013-07-10 17:09:50 +0000750
751 if (buffer) {
752 *buffer = fStr.fBuffer;
753 }
754
755 if (len) {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000756 *len = fStr.fBytes >> 2; // last 2 bits
edisonn@google.com571c70b2013-07-10 17:09:50 +0000757 }
758
759 return true;
760 }
761
762 bool isStreamFiltered() const {
763 return hasStream() && ((fStr.fBytes & 1) == kFilteredStreamBit);
764 }
765
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000766 bool isStreamOwned() const {
767 return hasStream() && ((fStr.fBytes & 2) == kOwnedStreamBit);
768 }
769
770 bool GetUnfilteredStreamRef(unsigned char const** buffer, size_t* len) const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000771 if (isStreamFiltered()) {
772 return false;
773 }
774
775 if (!hasStream()) {
776 return false;
777 }
778
779 if (buffer) {
780 *buffer = fStr.fBuffer;
781 }
782
783 if (len) {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000784 *len = fStr.fBytes >> 2; // remove last 2 bits
edisonn@google.com571c70b2013-07-10 17:09:50 +0000785 }
786
787 return true;
788 }
789
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000790 bool addStream(const unsigned char* buffer, size_t len) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000791 SkASSERT(!hasStream());
792 SkASSERT(isDictionary());
793
794 if (!isDictionary() || hasStream()) {
795 return false;
796 }
797
798 fStr.fBuffer = buffer;
799 fStr.fBytes = (len << 2) + kUnfilteredStreamBit;
800
801 return true;
802 }
803
804 SkString toString() {
805 SkString str;
806 switch (fObjectType) {
807 case kInvalid_PdfObjectType:
808 str.append("Invalid");
809 break;
810
811 case kBoolean_PdfObjectType:
812 str.appendf("Boolean: %s", fBooleanValue ? "true" : "false");
813 break;
814
815 case kInteger_PdfObjectType:
816 str.appendf("Integer: %i", (int)fIntegerValue);
817 break;
818
819 case kReal_PdfObjectType:
820 str.appendf("Real: %f", fRealValue);
821 break;
822
823 case kString_PdfObjectType:
824 str.appendf("String, len() = %u: ", (unsigned int)fStr.fBytes);
825 str.append((const char*)fStr.fBuffer, fStr.fBytes);
826 break;
827
828 case kHexString_PdfObjectType:
829 str.appendf("HexString, len() = %u: ", (unsigned int)fStr.fBytes);
830 str.append((const char*)fStr.fBuffer, fStr.fBytes);
831 break;
832
833 case kName_PdfObjectType:
834 str.appendf("Name, len() = %u: ", (unsigned int)fStr.fBytes);
835 str.append((const char*)fStr.fBuffer, fStr.fBytes);
836 break;
837
838 case kKeyword_PdfObjectType:
839 str.appendf("Keyword, len() = %u: ", (unsigned int)fStr.fBytes);
840 str.append((const char*)fStr.fBuffer, fStr.fBytes);
841 break;
842
843 case kArray_PdfObjectType:
844 str.append("Array, size() = %i [", size());
845 for (unsigned int i = 0; i < size(); i++) {
846 str.append(objAtAIndex(i)->toString());
847 }
848 str.append("]");
849 break;
850
851 case kDictionary_PdfObjectType:
852 // TODO(edisonn): NYI
853 str.append("Dictionary: NYI");
854 if (hasStream()) {
855 str.append(" HAS_STREAM");
856 }
857 break;
858
859 case kNull_PdfObjectType:
860 str = "NULL";
861 break;
862
863 case kReference_PdfObjectType:
864 str.appendf("Reference: %i %i", fRef.fId, fRef.fGen);
865 break;
866
867 case kUndefined_PdfObjectType:
868 str = "Undefined";
869 break;
870
871 default:
872 str = "Internal Error Object Type";
873 break;
874 }
875
876 return str;
877 }
878
879private:
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000880 static void makeStringCore(const unsigned char* start, SkPdfObject* obj, ObjectType type) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000881 makeStringCore(start, strlen((const char*)start), obj, type);
882 }
883
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000884 static void makeStringCore(const unsigned char* start, const unsigned char* end, SkPdfObject* obj, ObjectType type) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000885 makeStringCore(start, end - start, obj, type);
886 }
887
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000888 static void makeStringCore(const unsigned char* start, size_t bytes, SkPdfObject* obj, ObjectType type) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000889 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
890
891 obj->fObjectType = type;
892 obj->fStr.fBuffer = start;
893 obj->fStr.fBytes = bytes;
894 }
895
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000896 bool applyFilter(const char* name);
897 bool applyFlateDecodeFilter();
898 bool applyDCTDecodeFilter();
edisonn@google.com571c70b2013-07-10 17:09:50 +0000899};
900
901class SkPdfStream : public SkPdfObject {};
902class SkPdfArray : public SkPdfObject {};
903class SkPdfString : public SkPdfObject {};
904class SkPdfHexString : public SkPdfObject {};
905class SkPdfInteger : public SkPdfObject {};
906class SkPdfReal : public SkPdfObject {};
907class SkPdfNumber : public SkPdfObject {};
908
edisonn@google.com78b38b12013-07-15 18:20:58 +0000909class SkPdfName : public SkPdfObject {
910 SkPdfName() : SkPdfObject() {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000911 SkPdfObject::makeName((const unsigned char*)"", this);
edisonn@google.com78b38b12013-07-15 18:20:58 +0000912 }
913public:
914 SkPdfName(char* name) : SkPdfObject() {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000915 this->makeName((const unsigned char*)name, this);
edisonn@google.com78b38b12013-07-15 18:20:58 +0000916 }
917};
918
edisonn@google.com571c70b2013-07-10 17:09:50 +0000919#endif // EXPERIMENTAL_PDFVIEWER_PDFPARSER_NATIVE_SKPDFOBJECT_H_