blob: 29780d07cc23ec3bdf127728fc0645be98daa835 [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:
edisonn@google.com276fed92013-08-01 21:20:47 +0000126 case kName_PdfObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000127 return (const char*)fStr.fBuffer;
128
129 default:
130 // TODO(edisonn): report/warning
131 return NULL;
132 }
133 }
134
edisonn@google.come878e722013-07-29 19:10:58 +0000135 size_t lenstr() const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000136 switch (fObjectType) {
137 case kString_PdfObjectType:
138 case kHexString_PdfObjectType:
139 case kKeyword_PdfObjectType:
edisonn@google.com276fed92013-08-01 21:20:47 +0000140 case kName_PdfObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000141 return fStr.fBytes;
142
143 default:
144 // TODO(edisonn): report/warning
145 return 0;
146 }
147 }
148
149
150 // TODO(edisonn): NYI
151 SkPdfDate& dateValue() const {
152 static SkPdfDate nyi;
153 return nyi;
154 }
155
156 // TODO(edisonn): NYI
157 SkPdfFunction& functionValue() const {
158 static SkPdfFunction nyi;
159 return nyi;
160 }
161
162 // TODO(edisonn): NYI
163 SkPdfFileSpec& fileSpecValue() const {
164 static SkPdfFileSpec nyi;
165 return nyi;
166 }
167
168 // TODO(edisonn): NYI
169 SkPdfTree& treeValue() const {
170 static SkPdfTree nyi;
171 return nyi;
172 }
173
edisonn@google.com571c70b2013-07-10 17:09:50 +0000174 static void makeBoolean(bool value, SkPdfObject* obj) {
175 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
176
177 obj->fObjectType = kBoolean_PdfObjectType;
178 obj->fBooleanValue = value;
179 }
180
181 static SkPdfObject makeBoolean(bool value) {
182 SkPdfObject obj;
183 obj.fObjectType = kBoolean_PdfObjectType;
184 obj.fBooleanValue = value;
185 return obj;
186 }
187
188 static void makeInteger(int64_t value, SkPdfObject* obj) {
189 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
190
191 obj->fObjectType = kInteger_PdfObjectType;
192 obj->fIntegerValue = value;
193 }
194
195 static void makeReal(double value, SkPdfObject* obj) {
196 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
197
198 obj->fObjectType = kReal_PdfObjectType;
199 obj->fRealValue = value;
200 }
201
202 static void makeNull(SkPdfObject* obj) {
203 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
204
205 obj->fObjectType = kNull_PdfObjectType;
206 }
207
208 static SkPdfObject makeNull() {
209 SkPdfObject obj;
210 obj.fObjectType = kNull_PdfObjectType;
211 return obj;
212 }
213
214 static SkPdfObject kNull;
215
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000216 static void makeNumeric(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000217 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
218
219 // TODO(edisonn): NYI properly
220 // if has dot (impl), or exceeds max int, is real, otherwise is int
221 bool isInt = true;
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000222 for (const unsigned char* current = start; current < end; current++) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000223 if (*current == '.') {
224 isInt = false;
225 break;
226 }
227 // TODO(edisonn): report parse issue with numbers like "24asdasd123"
228 }
229 if (isInt) {
230 makeInteger(atol((const char*)start), obj);
231 } else {
232 makeReal(atof((const char*)start), obj);
233 }
234 }
235
236 static void makeReference(unsigned int id, unsigned int gen, SkPdfObject* obj) {
237 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
238
239 obj->fObjectType = kReference_PdfObjectType;
240 obj->fRef.fId = id;
241 obj->fRef.fGen = gen;
242 }
243
244
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000245 static void makeString(const unsigned char* start, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000246 makeStringCore(start, strlen((const char*)start), obj, kString_PdfObjectType);
247 }
248
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000249 static void makeString(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000250 makeStringCore(start, end - start, obj, kString_PdfObjectType);
251 }
252
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000253 static void makeString(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000254 makeStringCore(start, bytes, obj, kString_PdfObjectType);
255 }
256
257
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000258 static void makeHexString(const unsigned char* start, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000259 makeStringCore(start, strlen((const char*)start), obj, kHexString_PdfObjectType);
260 }
261
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000262 static void makeHexString(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000263 makeStringCore(start, end - start, obj, kHexString_PdfObjectType);
264 }
265
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000266 static void makeHexString(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000267 makeStringCore(start, bytes, obj, kHexString_PdfObjectType);
268 }
269
270
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000271 static void makeName(const unsigned char* start, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000272 makeStringCore(start, strlen((const char*)start), obj, kName_PdfObjectType);
273 }
274
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000275 static void makeName(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000276 makeStringCore(start, end - start, obj, kName_PdfObjectType);
277 }
278
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000279 static void makeName(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000280 makeStringCore(start, bytes, obj, kName_PdfObjectType);
281 }
282
283
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000284 static void makeKeyword(const unsigned char* start, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000285 makeStringCore(start, strlen((const char*)start), obj, kKeyword_PdfObjectType);
286 }
287
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000288 static void makeKeyword(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000289 makeStringCore(start, end - start, obj, kKeyword_PdfObjectType);
290 }
291
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000292 static void makeKeyword(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000293 makeStringCore(start, bytes, obj, kKeyword_PdfObjectType);
294 }
295
296
297
298 // TODO(edisonn): make the functions to return SkPdfArray, move these functions in SkPdfArray
299 static void makeEmptyArray(SkPdfObject* obj) {
300 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
301
302 obj->fObjectType = kArray_PdfObjectType;
303 obj->fArray = new SkTDArray<SkPdfObject*>();
304 // return (SkPdfArray*)obj;
305 }
306
307 bool appendInArray(SkPdfObject* obj) {
308 SkASSERT(fObjectType == kArray_PdfObjectType);
309 if (fObjectType != kArray_PdfObjectType) {
310 // TODO(edisonn): report err
311 return false;
312 }
313
314 fArray->push(obj);
315 return true;
316 }
317
318 size_t size() const {
319 SkASSERT(fObjectType == kArray_PdfObjectType);
320
321 return fArray->count();
322 }
323
324 SkPdfObject* objAtAIndex(int i) {
325 SkASSERT(fObjectType == kArray_PdfObjectType);
326
327 return (*fArray)[i];
328 }
329
330 SkPdfObject* removeLastInArray() {
331 SkASSERT(fObjectType == kArray_PdfObjectType);
332
333 SkPdfObject* ret = NULL;
334 fArray->pop(&ret);
335
336 return ret;
337 }
338
339
340 const SkPdfObject* objAtAIndex(int i) const {
341 SkASSERT(fObjectType == kArray_PdfObjectType);
342
343 return (*fArray)[i];
344 }
345
346 SkPdfObject* operator[](int i) {
347 SkASSERT(fObjectType == kArray_PdfObjectType);
348
349 return (*fArray)[i];
350 }
351
352 const SkPdfObject* operator[](int i) const {
353 SkASSERT(fObjectType == kArray_PdfObjectType);
354
355 return (*fArray)[i];
356 }
357
358
359 // TODO(edisonn): make the functions to return SkPdfDictionary, move these functions in SkPdfDictionary
360 static void makeEmptyDictionary(SkPdfObject* obj) {
361 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
362
363 obj->fObjectType = kDictionary_PdfObjectType;
364 obj->fMap = new SkTDict<SkPdfObject*>(1);
365 obj->fStr.fBuffer = NULL;
366 obj->fStr.fBytes = 0;
367 }
368
369 // TODO(edisonn): get all the possible names from spec, and compute a hash function
370 // that would create no overlaps in the same dictionary
371 // or build a tree of chars that when followed goes to a unique id/index/hash
372 // TODO(edisonn): generate constants like kDictFoo, kNameDict_name
373 // which will be used in code
374 // add function SkPdfFastNameKey key(const char* key);
375 // TODO(edisonn): setting the same key twike, will make the value undefined!
edisonn@google.com2fd5d362013-07-23 19:43:48 +0000376 bool set(const SkPdfObject* key, SkPdfObject* value) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000377 SkASSERT(fObjectType == kDictionary_PdfObjectType);
378 SkASSERT(key->fObjectType == kName_PdfObjectType);
379
380 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
381 // TODO(edisonn): report err
382 return false;
383 }
384
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000385 //// we rewrite all delimiters and white spaces with '\0', so we expect the end of name to be '\0'
386 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0');
edisonn@google.com571c70b2013-07-10 17:09:50 +0000387
edisonn@google.comd761e322013-07-22 17:29:43 +0000388 return set(key->fStr.fBuffer, key->fStr.fBytes, value);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000389 }
390
391 bool set(const char* key, SkPdfObject* value) {
edisonn@google.comd761e322013-07-22 17:29:43 +0000392 return set((const unsigned char*)key, strlen(key), value);
393 }
394
395 bool set(const unsigned char* key, size_t len, SkPdfObject* value) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000396 SkASSERT(fObjectType == kDictionary_PdfObjectType);
397
398 if (fObjectType != kDictionary_PdfObjectType) {
399 // TODO(edisonn): report err
400 return false;
401 }
402
edisonn@google.comd761e322013-07-22 17:29:43 +0000403 return fMap->set((const char*)key, len, value);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000404 }
405
edisonn@google.com2fd5d362013-07-23 19:43:48 +0000406 SkPdfObject* get(const SkPdfObject* key) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000407 SkASSERT(fObjectType == kDictionary_PdfObjectType);
408 SkASSERT(key->fObjectType == kName_PdfObjectType);
409
410 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
411 // TODO(edisonn): report err
edisonn@google.com3fc48262013-07-22 15:29:55 +0000412 return NULL;
edisonn@google.com571c70b2013-07-10 17:09:50 +0000413 }
414
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000415 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0');
edisonn@google.com571c70b2013-07-10 17:09:50 +0000416
edisonn@google.comd761e322013-07-22 17:29:43 +0000417 return get(key->fStr.fBuffer, key->fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000418 }
419
420 SkPdfObject* get(const char* key) {
edisonn@google.comd761e322013-07-22 17:29:43 +0000421 return get((const unsigned char*)key, strlen(key));
422 }
423
424 SkPdfObject* get(const unsigned char* key, size_t len) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000425 SkASSERT(fObjectType == kDictionary_PdfObjectType);
426 SkASSERT(key);
427 if (fObjectType != kDictionary_PdfObjectType) {
428 // TODO(edisonn): report err
429 return NULL;
430 }
431 SkPdfObject* ret = NULL;
edisonn@google.comd761e322013-07-22 17:29:43 +0000432 fMap->find((const char*)key, len, &ret);
edisonn@google.com9a43c182013-08-01 20:06:42 +0000433
434#ifdef PDF_TRACE
435 SkString _key;
436 _key.append((const char*)key, len);
437 printf("\nget(/%s) = %s\n", _key.c_str(), ret ? ret->toString(0, len + 9).c_str() : "_NOT_FOUND");
438#endif
439
edisonn@google.com571c70b2013-07-10 17:09:50 +0000440 return ret;
441 }
442
edisonn@google.com2fd5d362013-07-23 19:43:48 +0000443 const SkPdfObject* get(const SkPdfObject* key) const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000444 SkASSERT(fObjectType == kDictionary_PdfObjectType);
445 SkASSERT(key->fObjectType == kName_PdfObjectType);
446
447 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
448 // TODO(edisonn): report err
edisonn@google.com3fc48262013-07-22 15:29:55 +0000449 return NULL;
edisonn@google.com571c70b2013-07-10 17:09:50 +0000450 }
451
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000452 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0');
edisonn@google.com571c70b2013-07-10 17:09:50 +0000453
edisonn@google.comd761e322013-07-22 17:29:43 +0000454 return get(key->fStr.fBuffer, key->fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000455 }
456
edisonn@google.com571c70b2013-07-10 17:09:50 +0000457 const SkPdfObject* get(const char* key) const {
edisonn@google.comd761e322013-07-22 17:29:43 +0000458 return get((const unsigned char*)key, strlen(key));
459 }
460
461 const SkPdfObject* get(const unsigned char* key, size_t len) const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000462 SkASSERT(fObjectType == kDictionary_PdfObjectType);
463 SkASSERT(key);
464 if (fObjectType != kDictionary_PdfObjectType) {
465 // TODO(edisonn): report err
466 return NULL;
467 }
468 SkPdfObject* ret = NULL;
edisonn@google.comd761e322013-07-22 17:29:43 +0000469 fMap->find((const char*)key, len, &ret);
edisonn@google.com9a43c182013-08-01 20:06:42 +0000470
471#ifdef PDF_TRACE
472 SkString _key;
473 _key.append((const char*)key, len);
474 printf("\nget(/%s) = %s\n", _key.c_str(), ret ? ret->toString(0, len + 9).c_str() : "_NOT_FOUND");
475#endif
476
edisonn@google.com571c70b2013-07-10 17:09:50 +0000477 return ret;
478 }
479
480 const SkPdfObject* get(const char* key, const char* abr) const {
481 const SkPdfObject* ret = get(key);
482 // TODO(edisonn): / is a valid name, and it might be an abreviation, so "" should not be like NULL
483 // make this distiontion in generator, and remove "" from condition
484 if (ret != NULL || abr == NULL || *abr == '\0') {
485 return ret;
486 }
487 return get(abr);
488 }
489
490 SkPdfObject* get(const char* key, const char* abr) {
491 SkPdfObject* ret = get(key);
492 // TODO(edisonn): / is a valid name, and it might be an abreviation, so "" should not be like NULL
493 // make this distiontion in generator, and remove "" from condition
494 if (ret != NULL || abr == NULL || *abr == '\0') {
495 return ret;
496 }
497 return get(abr);
498 }
499
500 SkPdfDictionary* asDictionary() {
501 SkASSERT(isDictionary());
502 if (!isDictionary()) {
503 return NULL;
504 }
505 return (SkPdfDictionary*) this;
506 }
507
508 const SkPdfDictionary* asDictionary() const {
509 SkASSERT(isDictionary());
510 if (!isDictionary()) {
511 return NULL;
512 }
513 return (SkPdfDictionary*) this;
514 }
515
516
517 bool isReference() const {
518 return fObjectType == kReference_PdfObjectType;
519 }
520
521 bool isBoolean() const {
522 return fObjectType == kBoolean_PdfObjectType;
523 }
524
525 bool isInteger() const {
526 return fObjectType == kInteger_PdfObjectType;
527 }
528private:
529 bool isReal() const {
530 return fObjectType == kReal_PdfObjectType;
531 }
532public:
533 bool isNumber() const {
534 return fObjectType == kInteger_PdfObjectType || fObjectType == kReal_PdfObjectType;
535 }
536
537 bool isKeywordReference() const {
538 return fObjectType == kKeyword_PdfObjectType && fStr.fBytes == 1 && fStr.fBuffer[0] == 'R';
539 }
540
541 bool isKeyword() const {
542 return fObjectType == kKeyword_PdfObjectType;
543 }
544
edisonn@google.com4ef4bed2013-07-29 22:14:45 +0000545 bool isKeyword(const char* keyword) const {
546 if (!isKeyword()) {
547 return false;
548 }
549
550 if (strlen(keyword) != fStr.fBytes) {
551 return false;
552 }
553
554 if (strncmp(keyword, (const char*)fStr.fBuffer, fStr.fBytes) != 0) {
555 return false;
556 }
557
558 return true;
559 }
560
edisonn@google.com571c70b2013-07-10 17:09:50 +0000561 bool isName() const {
562 return fObjectType == kName_PdfObjectType;
563 }
564
edisonn@google.com78b38b12013-07-15 18:20:58 +0000565 bool isName(const char* name) const {
566 return fObjectType == kName_PdfObjectType && fStr.fBytes == strlen(name) && strncmp((const char*)fStr.fBuffer, name, fStr.fBytes) == 0;
567 }
568
edisonn@google.com571c70b2013-07-10 17:09:50 +0000569 bool isArray() const {
570 return fObjectType == kArray_PdfObjectType;
571 }
572
573 bool isDate() const {
574 return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType;
575 }
576
577 bool isDictionary() const {
578 return fObjectType == kDictionary_PdfObjectType;
579 }
580
581 bool isFunction() const {
582 return false; // NYI
583 }
584
585 bool isRectangle() const {
586 return fObjectType == kArray_PdfObjectType && fArray->count() == 4; // NYI + and elems are numbers
587 }
588
589 // TODO(edisonn): has stream .. or is stream ... TBD
590 bool hasStream() const {
591 return isDictionary() && fStr.fBuffer != NULL;
592 }
593
594 // TODO(edisonn): has stream .. or is stream ... TBD
595 const SkPdfStream* getStream() const {
596 return hasStream() ? (const SkPdfStream*)this : NULL;
597 }
598
599 SkPdfStream* getStream() {
600 return hasStream() ? (SkPdfStream*)this : NULL;
601 }
602
603 bool isAnyString() const {
604 return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType;
605 }
606
607 bool isMatrix() const {
608 return fObjectType == kArray_PdfObjectType && fArray->count() == 6; // NYI + and elems are numbers
609 }
610
611 inline int64_t intValue() const {
612 SkASSERT(fObjectType == kInteger_PdfObjectType);
613
614 if (fObjectType != kInteger_PdfObjectType) {
615 // TODO(edisonn): log err
616 return 0;
617 }
618 return fIntegerValue;
619 }
620private:
621 inline double realValue() const {
622 SkASSERT(fObjectType == kReal_PdfObjectType);
623
624 if (fObjectType != kReal_PdfObjectType) {
625 // TODO(edisonn): log err
626 return 0;
627 }
628 return fRealValue;
629 }
630public:
631 inline double numberValue() const {
632 SkASSERT(isNumber());
633
634 if (!isNumber()) {
635 // TODO(edisonn): log err
636 return 0;
637 }
638 return fObjectType == kReal_PdfObjectType ? fRealValue : fIntegerValue;
639 }
640
edisonn@google.coma0cefa12013-07-28 18:34:14 +0000641 inline SkScalar scalarValue() const {
642 SkASSERT(isNumber());
643
644 if (!isNumber()) {
645 // TODO(edisonn): log err
646 return SkIntToScalar(0);
647 }
648 return fObjectType == kReal_PdfObjectType ? SkDoubleToScalar(fRealValue) :
649 SkIntToScalar(fIntegerValue);
650 }
651
edisonn@google.com571c70b2013-07-10 17:09:50 +0000652 int referenceId() const {
653 SkASSERT(fObjectType == kReference_PdfObjectType);
654 return fRef.fId;
655 }
656
657 int referenceGeneration() const {
658 SkASSERT(fObjectType == kReference_PdfObjectType);
659 return fRef.fGen;
660 }
661
662 inline const char* nameValue() const {
663 SkASSERT(fObjectType == kName_PdfObjectType);
664
665 if (fObjectType != kName_PdfObjectType) {
666 // TODO(edisonn): log err
667 return "";
668 }
669 return (const char*)fStr.fBuffer;
670 }
671
672 inline const char* stringValue() const {
673 SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType);
674
675 if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
676 // TODO(edisonn): log err
677 return "";
678 }
679 return (const char*)fStr.fBuffer;
680 }
681
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000682 inline NotOwnedString strRef() {
683 switch (fObjectType) {
684 case kString_PdfObjectType:
685 case kHexString_PdfObjectType:
686 case kKeyword_PdfObjectType:
edisonn@google.com276fed92013-08-01 21:20:47 +0000687 case kName_PdfObjectType:
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000688 return fStr;
689
690 default:
691 // TODO(edisonn): report/warning
692 return NotOwnedString();
693 }
694 }
695
edisonn@google.com571c70b2013-07-10 17:09:50 +0000696 // TODO(edisonn): nameValue2 and stringValue2 are used to make code generation easy,
697 // but it is not a performat way to do it, since it will create an extra copy
698 // remove these functions and make code generated faster
699 inline std::string nameValue2() const {
700 SkASSERT(fObjectType == kName_PdfObjectType);
701
702 if (fObjectType != kName_PdfObjectType) {
703 // TODO(edisonn): log err
704 return "";
705 }
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000706 return std::string((const char*)fStr.fBuffer, fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000707 }
708
709 inline std::string stringValue2() const {
710 SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType);
711
712 if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
713 // TODO(edisonn): log err
714 return "";
715 }
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000716 return std::string((const char*)fStr.fBuffer, fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000717 }
718
719 inline bool boolValue() const {
720 SkASSERT(fObjectType == kBoolean_PdfObjectType);
721
edisonn@google.comf111a4b2013-07-31 18:22:36 +0000722 if (fObjectType != kBoolean_PdfObjectType) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000723 // TODO(edisonn): log err
724 return false;
725 }
726 return fBooleanValue;
727 }
728
729 SkRect rectangleValue() const {
730 SkASSERT(isRectangle());
731 if (!isRectangle()) {
732 return SkRect::MakeEmpty();
733 }
734
735 double array[4];
736 for (int i = 0; i < 4; i++) {
737 // TODO(edisonn): version where we could resolve references?
738 const SkPdfObject* elem = objAtAIndex(i);
739 if (elem == NULL || !elem->isNumber()) {
740 // TODO(edisonn): report error
741 return SkRect::MakeEmpty();
742 }
743 array[i] = elem->numberValue();
744 }
745
746 return SkRect::MakeLTRB(SkDoubleToScalar(array[0]),
747 SkDoubleToScalar(array[1]),
748 SkDoubleToScalar(array[2]),
749 SkDoubleToScalar(array[3]));
750 }
751
752 SkMatrix matrixValue() const {
753 SkASSERT(isMatrix());
754 if (!isMatrix()) {
755 return SkMatrix::I();
756 }
757
758 double array[6];
759 for (int i = 0; i < 6; i++) {
760 // TODO(edisonn): version where we could resolve references?
761 const SkPdfObject* elem = objAtAIndex(i);
762 if (elem == NULL || !elem->isNumber()) {
763 // TODO(edisonn): report error
764 return SkMatrix::I();
765 }
766 array[i] = elem->numberValue();
767 }
768
769 return SkMatrixFromPdfMatrix(array);
770 }
771
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000772 bool filterStream();
edisonn@google.com571c70b2013-07-10 17:09:50 +0000773
774
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000775 bool GetFilteredStreamRef(unsigned char const** buffer, size_t* len) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000776 // TODO(edisonn): add params that couls let the last filter in place if it is jpeg or png to fast load images
777 if (!hasStream()) {
778 return false;
779 }
780
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000781 filterStream();
edisonn@google.com571c70b2013-07-10 17:09:50 +0000782
783 if (buffer) {
784 *buffer = fStr.fBuffer;
785 }
786
787 if (len) {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000788 *len = fStr.fBytes >> 2; // last 2 bits
edisonn@google.com571c70b2013-07-10 17:09:50 +0000789 }
790
791 return true;
792 }
793
794 bool isStreamFiltered() const {
795 return hasStream() && ((fStr.fBytes & 1) == kFilteredStreamBit);
796 }
797
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000798 bool isStreamOwned() const {
799 return hasStream() && ((fStr.fBytes & 2) == kOwnedStreamBit);
800 }
801
802 bool GetUnfilteredStreamRef(unsigned char const** buffer, size_t* len) const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000803 if (isStreamFiltered()) {
804 return false;
805 }
806
807 if (!hasStream()) {
808 return false;
809 }
810
811 if (buffer) {
812 *buffer = fStr.fBuffer;
813 }
814
815 if (len) {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000816 *len = fStr.fBytes >> 2; // remove last 2 bits
edisonn@google.com571c70b2013-07-10 17:09:50 +0000817 }
818
819 return true;
820 }
821
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000822 bool addStream(const unsigned char* buffer, size_t len) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000823 SkASSERT(!hasStream());
824 SkASSERT(isDictionary());
825
826 if (!isDictionary() || hasStream()) {
827 return false;
828 }
829
830 fStr.fBuffer = buffer;
831 fStr.fBytes = (len << 2) + kUnfilteredStreamBit;
832
833 return true;
834 }
835
edisonn@google.com276fed92013-08-01 21:20:47 +0000836 static void appendSpaces(SkString* str, int level) {
edisonn@google.com9a43c182013-08-01 20:06:42 +0000837 for (int i = 0 ; i < level; i++) {
838 str->append(" ");
839 }
840 }
841
edisonn@google.come2e01ff2013-08-02 20:24:48 +0000842 SkString toString(int firstRowLevel = 0, int level = 0) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000843 SkString str;
edisonn@google.com9a43c182013-08-01 20:06:42 +0000844 appendSpaces(&str, firstRowLevel);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000845 switch (fObjectType) {
846 case kInvalid_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000847 str.append("__Invalid");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000848 break;
849
850 case kBoolean_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000851 str.appendf("%s", fBooleanValue ? "true" : "false");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000852 break;
853
854 case kInteger_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000855 str.appendf("%i", (int)fIntegerValue);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000856 break;
857
858 case kReal_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000859 str.appendf("%f", fRealValue);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000860 break;
861
862 case kString_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000863 str.append("\"");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000864 str.append((const char*)fStr.fBuffer, fStr.fBytes);
edisonn@google.com9a43c182013-08-01 20:06:42 +0000865 str.append("\"");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000866 break;
867
868 case kHexString_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000869 str.append("<");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000870 str.append((const char*)fStr.fBuffer, fStr.fBytes);
edisonn@google.com9a43c182013-08-01 20:06:42 +0000871 str.append(">");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000872 break;
873
874 case kName_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000875 str.append("/");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000876 str.append((const char*)fStr.fBuffer, fStr.fBytes);
877 break;
878
879 case kKeyword_PdfObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000880 str.append((const char*)fStr.fBuffer, fStr.fBytes);
881 break;
882
883 case kArray_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000884 str.append("[\n");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000885 for (unsigned int i = 0; i < size(); i++) {
edisonn@google.com9a43c182013-08-01 20:06:42 +0000886 str.append(objAtAIndex(i)->toString(level + 1, level + 1));
887 if (i < size() - 1) {
888 str.append(",");
889 }
890 str.append("\n");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000891 }
edisonn@google.com9a43c182013-08-01 20:06:42 +0000892 appendSpaces(&str, level);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000893 str.append("]");
894 break;
895
edisonn@google.com9a43c182013-08-01 20:06:42 +0000896 case kDictionary_PdfObjectType: {
897 SkTDict<SkPdfObject*>::Iter iter(*fMap);
898 SkPdfObject* obj = NULL;
899 const char* key = NULL;
900 str.append("<<\n");
901 while ((key = iter.next(&obj)) != NULL) {
902 appendSpaces(&str, level + 2);
903 str.appendf("/%s %s\n", key, obj->toString(0, level + strlen(key) + 4).c_str());
904 }
905 appendSpaces(&str, level);
906 str.append(">>");
907 if (hasStream()) {
edisonn@google.come2e01ff2013-08-02 20:24:48 +0000908 const unsigned char* stream = NULL;
909 size_t length = 0;
910 if (GetFilteredStreamRef(&stream, &length)) {
911 str.append("stream");
912 str.append((const char*)stream, length > 256 ? 256 : length);
913 str.append("endstream");
914 } else {
915 str.append("stream STREAM_ERROR endstream");
916 }
edisonn@google.com9a43c182013-08-01 20:06:42 +0000917 }
edisonn@google.com571c70b2013-07-10 17:09:50 +0000918 }
919 break;
920
921 case kNull_PdfObjectType:
922 str = "NULL";
923 break;
924
925 case kReference_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000926 str.appendf("%i %i R", fRef.fId, fRef.fGen);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000927 break;
928
929 case kUndefined_PdfObjectType:
930 str = "Undefined";
931 break;
932
933 default:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000934 str = "Error";
edisonn@google.com571c70b2013-07-10 17:09:50 +0000935 break;
936 }
937
938 return str;
939 }
940
941private:
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000942 static void makeStringCore(const unsigned char* start, SkPdfObject* obj, ObjectType type) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000943 makeStringCore(start, strlen((const char*)start), obj, type);
944 }
945
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000946 static void makeStringCore(const unsigned char* start, const unsigned char* end, SkPdfObject* obj, ObjectType type) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000947 makeStringCore(start, end - start, obj, type);
948 }
949
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000950 static void makeStringCore(const unsigned char* start, size_t bytes, SkPdfObject* obj, ObjectType type) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000951 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
952
953 obj->fObjectType = type;
954 obj->fStr.fBuffer = start;
955 obj->fStr.fBytes = bytes;
956 }
957
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000958 bool applyFilter(const char* name);
959 bool applyFlateDecodeFilter();
960 bool applyDCTDecodeFilter();
edisonn@google.com571c70b2013-07-10 17:09:50 +0000961};
962
963class SkPdfStream : public SkPdfObject {};
964class SkPdfArray : public SkPdfObject {};
965class SkPdfString : public SkPdfObject {};
966class SkPdfHexString : public SkPdfObject {};
967class SkPdfInteger : public SkPdfObject {};
968class SkPdfReal : public SkPdfObject {};
969class SkPdfNumber : public SkPdfObject {};
970
edisonn@google.com78b38b12013-07-15 18:20:58 +0000971class SkPdfName : public SkPdfObject {
972 SkPdfName() : SkPdfObject() {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000973 SkPdfObject::makeName((const unsigned char*)"", this);
edisonn@google.com78b38b12013-07-15 18:20:58 +0000974 }
975public:
976 SkPdfName(char* name) : SkPdfObject() {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000977 this->makeName((const unsigned char*)name, this);
edisonn@google.com78b38b12013-07-15 18:20:58 +0000978 }
979};
980
edisonn@google.com571c70b2013-07-10 17:09:50 +0000981#endif // EXPERIMENTAL_PDFVIEWER_PDFPARSER_NATIVE_SKPDFOBJECT_H_