OLD | NEW |
| (Empty) |
1 #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 | |
16 class SkPdfDictionary; | |
17 class SkPdfStream; | |
18 class SkPdfAllocator; | |
19 | |
20 // TODO(edisonn): macro it and move it to utils | |
21 SkMatrix SkMatrixFromPdfMatrix(double array[6]); | |
22 | |
23 | |
24 #define kFilteredStreamBit 0 | |
25 #define kUnfilteredStreamBit 1 | |
26 #define kOwnedStreamBit 2 | |
27 | |
28 class 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 twic
e in the dictionary, the value is undefined | |
50 }; | |
51 | |
52 enum DataType { | |
53 kEmpty_Data, | |
54 kFont_Data, | |
55 kBitmap_Data, | |
56 }; | |
57 | |
58 private: | |
59 struct Reference { | |
60 unsigned int fId; | |
61 unsigned int fGen; | |
62 }; | |
63 | |
64 // TODO(edisonn): add stream start, stream end, where stream is weither the
file | |
65 // or decoded/filtered pdf stream | |
66 | |
67 // TODO(edisonn): add warning/report per object | |
68 // TODO(edisonn): add flag fUsed, to be used once the parsing is complete, | |
69 // so we could show what parts have been proccessed, ignored, or generated e
rrors | |
70 | |
71 ObjectType fObjectType; | |
72 | |
73 union { | |
74 bool fBooleanValue; | |
75 int64_t fIntegerValue; | |
76 // TODO(edisonn): double, float? typedefed | |
77 double fRealValue; | |
78 NotOwnedString fStr; | |
79 | |
80 // TODO(edisonn): make sure the foorprint of fArray and fMap is small, o
therwise, use pointers, or classes with up to 8 bytes in footprint | |
81 SkTDArray<SkPdfObject*>* fArray; | |
82 Reference fRef; | |
83 }; | |
84 SkTDict<SkPdfObject*>* fMap; | |
85 | |
86 // TODO(edisonn): rename data with cache | |
87 void* fData; | |
88 DataType fDataType; | |
89 | |
90 | |
91 public: | |
92 | |
93 SkPdfObject() : fObjectType(kInvalid_PdfObjectType), fMap(NULL), fData(NULL)
, fDataType(kEmpty_Data) {} | |
94 | |
95 | |
96 inline bool hasData(DataType type) { | |
97 return type == fDataType; | |
98 } | |
99 | |
100 inline void* data(DataType type) { | |
101 return type == fDataType ? fData : NULL; | |
102 } | |
103 | |
104 inline void setData(void* data, DataType type) { | |
105 releaseData(); | |
106 fDataType = type; | |
107 fData = data; | |
108 } | |
109 | |
110 void releaseData(); | |
111 | |
112 // ~SkPdfObject() { | |
113 // //reset(); must be called manually! | |
114 // } | |
115 | |
116 void reset() { | |
117 switch (fObjectType) { | |
118 case kArray_PdfObjectType: | |
119 delete fArray; | |
120 break; | |
121 | |
122 case kDictionary_PdfObjectType: | |
123 delete fMap; | |
124 if (isStreamOwned()) { | |
125 delete[] fStr.fBuffer; | |
126 fStr.fBuffer = NULL; | |
127 fStr.fBytes = 0; | |
128 } | |
129 break; | |
130 | |
131 default: | |
132 break; | |
133 } | |
134 fObjectType = kInvalid_PdfObjectType; | |
135 releaseData(); | |
136 } | |
137 | |
138 ObjectType type() { return fObjectType; } | |
139 | |
140 const char* c_str() const { | |
141 switch (fObjectType) { | |
142 case kString_PdfObjectType: | |
143 case kHexString_PdfObjectType: | |
144 case kKeyword_PdfObjectType: | |
145 case kName_PdfObjectType: | |
146 return (const char*)fStr.fBuffer; | |
147 | |
148 default: | |
149 // TODO(edisonn): report/warning | |
150 return NULL; | |
151 } | |
152 } | |
153 | |
154 size_t lenstr() const { | |
155 switch (fObjectType) { | |
156 case kString_PdfObjectType: | |
157 case kHexString_PdfObjectType: | |
158 case kKeyword_PdfObjectType: | |
159 case kName_PdfObjectType: | |
160 return fStr.fBytes; | |
161 | |
162 default: | |
163 // TODO(edisonn): report/warning | |
164 return 0; | |
165 } | |
166 } | |
167 | |
168 | |
169 // TODO(edisonn): NYI | |
170 SkPdfDate& dateValue() const { | |
171 static SkPdfDate nyi; | |
172 return nyi; | |
173 } | |
174 | |
175 // TODO(edisonn): NYI | |
176 SkPdfFunction& functionValue() const { | |
177 static SkPdfFunction nyi; | |
178 return nyi; | |
179 } | |
180 | |
181 // TODO(edisonn): NYI | |
182 SkPdfFileSpec& fileSpecValue() const { | |
183 static SkPdfFileSpec nyi; | |
184 return nyi; | |
185 } | |
186 | |
187 // TODO(edisonn): NYI | |
188 SkPdfTree& treeValue() const { | |
189 static SkPdfTree nyi; | |
190 return nyi; | |
191 } | |
192 | |
193 static void makeBoolean(bool value, SkPdfObject* obj) { | |
194 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); | |
195 | |
196 obj->fObjectType = kBoolean_PdfObjectType; | |
197 obj->fBooleanValue = value; | |
198 } | |
199 | |
200 static SkPdfObject makeBoolean(bool value) { | |
201 SkPdfObject obj; | |
202 obj.fObjectType = kBoolean_PdfObjectType; | |
203 obj.fBooleanValue = value; | |
204 return obj; | |
205 } | |
206 | |
207 static void makeInteger(int64_t value, SkPdfObject* obj) { | |
208 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); | |
209 | |
210 obj->fObjectType = kInteger_PdfObjectType; | |
211 obj->fIntegerValue = value; | |
212 } | |
213 | |
214 static void makeReal(double value, SkPdfObject* obj) { | |
215 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); | |
216 | |
217 obj->fObjectType = kReal_PdfObjectType; | |
218 obj->fRealValue = value; | |
219 } | |
220 | |
221 static void makeNull(SkPdfObject* obj) { | |
222 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); | |
223 | |
224 obj->fObjectType = kNull_PdfObjectType; | |
225 } | |
226 | |
227 static SkPdfObject makeNull() { | |
228 SkPdfObject obj; | |
229 obj.fObjectType = kNull_PdfObjectType; | |
230 return obj; | |
231 } | |
232 | |
233 static SkPdfObject kNull; | |
234 | |
235 static void makeNumeric(const unsigned char* start, const unsigned char* end
, SkPdfObject* obj) { | |
236 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); | |
237 | |
238 // TODO(edisonn): NYI properly | |
239 // if has dot (impl), or exceeds max int, is real, otherwise is int | |
240 bool isInt = true; | |
241 for (const unsigned char* current = start; current < end; current++) { | |
242 if (*current == '.') { | |
243 isInt = false; | |
244 break; | |
245 } | |
246 // TODO(edisonn): report parse issue with numbers like "24asdasd123" | |
247 } | |
248 if (isInt) { | |
249 makeInteger(atol((const char*)start), obj); | |
250 } else { | |
251 makeReal(atof((const char*)start), obj); | |
252 } | |
253 } | |
254 | |
255 static void makeReference(unsigned int id, unsigned int gen, SkPdfObject* ob
j) { | |
256 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); | |
257 | |
258 obj->fObjectType = kReference_PdfObjectType; | |
259 obj->fRef.fId = id; | |
260 obj->fRef.fGen = gen; | |
261 } | |
262 | |
263 | |
264 static void makeString(const unsigned char* start, SkPdfObject* obj) { | |
265 makeStringCore(start, strlen((const char*)start), obj, kString_PdfObject
Type); | |
266 } | |
267 | |
268 static void makeString(const unsigned char* start, const unsigned char* end,
SkPdfObject* obj) { | |
269 makeStringCore(start, end - start, obj, kString_PdfObjectType); | |
270 } | |
271 | |
272 static void makeString(const unsigned char* start, size_t bytes, SkPdfObject
* obj) { | |
273 makeStringCore(start, bytes, obj, kString_PdfObjectType); | |
274 } | |
275 | |
276 | |
277 static void makeHexString(const unsigned char* start, SkPdfObject* obj) { | |
278 makeStringCore(start, strlen((const char*)start), obj, kHexString_PdfObj
ectType); | |
279 } | |
280 | |
281 static void makeHexString(const unsigned char* start, const unsigned char* e
nd, SkPdfObject* obj) { | |
282 makeStringCore(start, end - start, obj, kHexString_PdfObjectType); | |
283 } | |
284 | |
285 static void makeHexString(const unsigned char* start, size_t bytes, SkPdfObj
ect* obj) { | |
286 makeStringCore(start, bytes, obj, kHexString_PdfObjectType); | |
287 } | |
288 | |
289 | |
290 static void makeName(const unsigned char* start, SkPdfObject* obj) { | |
291 makeStringCore(start, strlen((const char*)start), obj, kName_PdfObjectTy
pe); | |
292 } | |
293 | |
294 static void makeName(const unsigned char* start, const unsigned char* end, S
kPdfObject* obj) { | |
295 makeStringCore(start, end - start, obj, kName_PdfObjectType); | |
296 } | |
297 | |
298 static void makeName(const unsigned char* start, size_t bytes, SkPdfObject*
obj) { | |
299 makeStringCore(start, bytes, obj, kName_PdfObjectType); | |
300 } | |
301 | |
302 | |
303 static void makeKeyword(const unsigned char* start, SkPdfObject* obj) { | |
304 makeStringCore(start, strlen((const char*)start), obj, kKeyword_PdfObjec
tType); | |
305 } | |
306 | |
307 static void makeKeyword(const unsigned char* start, const unsigned char* end
, SkPdfObject* obj) { | |
308 makeStringCore(start, end - start, obj, kKeyword_PdfObjectType); | |
309 } | |
310 | |
311 static void makeKeyword(const unsigned char* start, size_t bytes, SkPdfObjec
t* obj) { | |
312 makeStringCore(start, bytes, obj, kKeyword_PdfObjectType); | |
313 } | |
314 | |
315 | |
316 | |
317 // TODO(edisonn): make the functions to return SkPdfArray, move these functi
ons in SkPdfArray | |
318 static void makeEmptyArray(SkPdfObject* obj) { | |
319 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); | |
320 | |
321 obj->fObjectType = kArray_PdfObjectType; | |
322 obj->fArray = new SkTDArray<SkPdfObject*>(); | |
323 // return (SkPdfArray*)obj; | |
324 } | |
325 | |
326 bool appendInArray(SkPdfObject* obj) { | |
327 SkASSERT(fObjectType == kArray_PdfObjectType); | |
328 if (fObjectType != kArray_PdfObjectType) { | |
329 // TODO(edisonn): report err | |
330 return false; | |
331 } | |
332 | |
333 fArray->push(obj); | |
334 return true; | |
335 } | |
336 | |
337 size_t size() const { | |
338 SkASSERT(fObjectType == kArray_PdfObjectType); | |
339 | |
340 return fArray->count(); | |
341 } | |
342 | |
343 SkPdfObject* objAtAIndex(int i) { | |
344 SkASSERT(fObjectType == kArray_PdfObjectType); | |
345 | |
346 return (*fArray)[i]; | |
347 } | |
348 | |
349 SkPdfObject* removeLastInArray() { | |
350 SkASSERT(fObjectType == kArray_PdfObjectType); | |
351 | |
352 SkPdfObject* ret = NULL; | |
353 fArray->pop(&ret); | |
354 | |
355 return ret; | |
356 } | |
357 | |
358 | |
359 const SkPdfObject* objAtAIndex(int i) const { | |
360 SkASSERT(fObjectType == kArray_PdfObjectType); | |
361 | |
362 return (*fArray)[i]; | |
363 } | |
364 | |
365 SkPdfObject* operator[](int i) { | |
366 SkASSERT(fObjectType == kArray_PdfObjectType); | |
367 | |
368 return (*fArray)[i]; | |
369 } | |
370 | |
371 const SkPdfObject* operator[](int i) const { | |
372 SkASSERT(fObjectType == kArray_PdfObjectType); | |
373 | |
374 return (*fArray)[i]; | |
375 } | |
376 | |
377 | |
378 // TODO(edisonn): make the functions to return SkPdfDictionary, move these f
unctions in SkPdfDictionary | |
379 static void makeEmptyDictionary(SkPdfObject* obj) { | |
380 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); | |
381 | |
382 obj->fObjectType = kDictionary_PdfObjectType; | |
383 obj->fMap = new SkTDict<SkPdfObject*>(1); | |
384 obj->fStr.fBuffer = NULL; | |
385 obj->fStr.fBytes = 0; | |
386 } | |
387 | |
388 // TODO(edisonn): get all the possible names from spec, and compute a hash f
unction | |
389 // that would create no overlaps in the same dictionary | |
390 // or build a tree of chars that when followed goes to a unique id/index/has
h | |
391 // TODO(edisonn): generate constants like kDictFoo, kNameDict_name | |
392 // which will be used in code | |
393 // add function SkPdfFastNameKey key(const char* key); | |
394 // TODO(edisonn): setting the same key twike, will make the value undefined! | |
395 bool set(const SkPdfObject* key, SkPdfObject* value) { | |
396 SkASSERT(fObjectType == kDictionary_PdfObjectType); | |
397 SkASSERT(key->fObjectType == kName_PdfObjectType); | |
398 | |
399 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionar
y_PdfObjectType) { | |
400 // TODO(edisonn): report err | |
401 return false; | |
402 } | |
403 | |
404 //// we rewrite all delimiters and white spaces with '\0', so we expect
the end of name to be '\0' | |
405 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0'); | |
406 | |
407 return set(key->fStr.fBuffer, key->fStr.fBytes, value); | |
408 } | |
409 | |
410 bool set(const char* key, SkPdfObject* value) { | |
411 return set((const unsigned char*)key, strlen(key), value); | |
412 } | |
413 | |
414 bool set(const unsigned char* key, size_t len, SkPdfObject* value) { | |
415 SkASSERT(fObjectType == kDictionary_PdfObjectType); | |
416 | |
417 if (fObjectType != kDictionary_PdfObjectType) { | |
418 // TODO(edisonn): report err | |
419 return false; | |
420 } | |
421 | |
422 return fMap->set((const char*)key, len, value); | |
423 } | |
424 | |
425 SkPdfObject* get(const SkPdfObject* key) { | |
426 SkASSERT(fObjectType == kDictionary_PdfObjectType); | |
427 SkASSERT(key->fObjectType == kName_PdfObjectType); | |
428 | |
429 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionar
y_PdfObjectType) { | |
430 // TODO(edisonn): report err | |
431 return NULL; | |
432 } | |
433 | |
434 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0'); | |
435 | |
436 return get(key->fStr.fBuffer, key->fStr.fBytes); | |
437 } | |
438 | |
439 SkPdfObject* get(const char* key) { | |
440 return get((const unsigned char*)key, strlen(key)); | |
441 } | |
442 | |
443 SkPdfObject* get(const unsigned char* key, size_t len) { | |
444 SkASSERT(fObjectType == kDictionary_PdfObjectType); | |
445 SkASSERT(key); | |
446 if (fObjectType != kDictionary_PdfObjectType) { | |
447 // TODO(edisonn): report err | |
448 return NULL; | |
449 } | |
450 SkPdfObject* ret = NULL; | |
451 fMap->find((const char*)key, len, &ret); | |
452 | |
453 #ifdef PDF_TRACE | |
454 SkString _key; | |
455 _key.append((const char*)key, len); | |
456 printf("\nget(/%s) = %s\n", _key.c_str(), ret ? ret->toString(0, len + 9
).c_str() : "_NOT_FOUND"); | |
457 #endif | |
458 | |
459 return ret; | |
460 } | |
461 | |
462 const SkPdfObject* get(const SkPdfObject* key) const { | |
463 SkASSERT(fObjectType == kDictionary_PdfObjectType); | |
464 SkASSERT(key->fObjectType == kName_PdfObjectType); | |
465 | |
466 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionar
y_PdfObjectType) { | |
467 // TODO(edisonn): report err | |
468 return NULL; | |
469 } | |
470 | |
471 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0'); | |
472 | |
473 return get(key->fStr.fBuffer, key->fStr.fBytes); | |
474 } | |
475 | |
476 const SkPdfObject* get(const char* key) const { | |
477 return get((const unsigned char*)key, strlen(key)); | |
478 } | |
479 | |
480 const SkPdfObject* get(const unsigned char* key, size_t len) const { | |
481 SkASSERT(fObjectType == kDictionary_PdfObjectType); | |
482 SkASSERT(key); | |
483 if (fObjectType != kDictionary_PdfObjectType) { | |
484 // TODO(edisonn): report err | |
485 return NULL; | |
486 } | |
487 SkPdfObject* ret = NULL; | |
488 fMap->find((const char*)key, len, &ret); | |
489 | |
490 #ifdef PDF_TRACE | |
491 SkString _key; | |
492 _key.append((const char*)key, len); | |
493 printf("\nget(/%s) = %s\n", _key.c_str(), ret ? ret->toString(0, len + 9
).c_str() : "_NOT_FOUND"); | |
494 #endif | |
495 | |
496 return ret; | |
497 } | |
498 | |
499 const SkPdfObject* get(const char* key, const char* abr) const { | |
500 const SkPdfObject* ret = get(key); | |
501 // TODO(edisonn): / is a valid name, and it might be an abreviation, so
"" should not be like NULL | |
502 // make this distiontion in generator, and remove "" from condition | |
503 if (ret != NULL || abr == NULL || *abr == '\0') { | |
504 return ret; | |
505 } | |
506 return get(abr); | |
507 } | |
508 | |
509 SkPdfObject* get(const char* key, const char* abr) { | |
510 SkPdfObject* ret = get(key); | |
511 // TODO(edisonn): / is a valid name, and it might be an abreviation, so
"" should not be like NULL | |
512 // make this distiontion in generator, and remove "" from condition | |
513 if (ret != NULL || abr == NULL || *abr == '\0') { | |
514 return ret; | |
515 } | |
516 return get(abr); | |
517 } | |
518 | |
519 SkPdfDictionary* asDictionary() { | |
520 SkASSERT(isDictionary()); | |
521 if (!isDictionary()) { | |
522 return NULL; | |
523 } | |
524 return (SkPdfDictionary*) this; | |
525 } | |
526 | |
527 const SkPdfDictionary* asDictionary() const { | |
528 SkASSERT(isDictionary()); | |
529 if (!isDictionary()) { | |
530 return NULL; | |
531 } | |
532 return (SkPdfDictionary*) this; | |
533 } | |
534 | |
535 | |
536 bool isReference() const { | |
537 return fObjectType == kReference_PdfObjectType; | |
538 } | |
539 | |
540 bool isBoolean() const { | |
541 return fObjectType == kBoolean_PdfObjectType; | |
542 } | |
543 | |
544 bool isInteger() const { | |
545 return fObjectType == kInteger_PdfObjectType; | |
546 } | |
547 private: | |
548 bool isReal() const { | |
549 return fObjectType == kReal_PdfObjectType; | |
550 } | |
551 public: | |
552 bool isNumber() const { | |
553 return fObjectType == kInteger_PdfObjectType || fObjectType == kReal_Pdf
ObjectType; | |
554 } | |
555 | |
556 bool isKeywordReference() const { | |
557 return fObjectType == kKeyword_PdfObjectType && fStr.fBytes == 1 && fStr
.fBuffer[0] == 'R'; | |
558 } | |
559 | |
560 bool isKeyword() const { | |
561 return fObjectType == kKeyword_PdfObjectType; | |
562 } | |
563 | |
564 bool isKeyword(const char* keyword) const { | |
565 if (!isKeyword()) { | |
566 return false; | |
567 } | |
568 | |
569 if (strlen(keyword) != fStr.fBytes) { | |
570 return false; | |
571 } | |
572 | |
573 if (strncmp(keyword, (const char*)fStr.fBuffer, fStr.fBytes) != 0) { | |
574 return false; | |
575 } | |
576 | |
577 return true; | |
578 } | |
579 | |
580 bool isName() const { | |
581 return fObjectType == kName_PdfObjectType; | |
582 } | |
583 | |
584 bool isName(const char* name) const { | |
585 return fObjectType == kName_PdfObjectType && fStr.fBytes == strlen(name)
&& strncmp((const char*)fStr.fBuffer, name, fStr.fBytes) == 0; | |
586 } | |
587 | |
588 bool isArray() const { | |
589 return fObjectType == kArray_PdfObjectType; | |
590 } | |
591 | |
592 bool isDate() const { | |
593 return fObjectType == kString_PdfObjectType || fObjectType == kHexString
_PdfObjectType; | |
594 } | |
595 | |
596 bool isDictionary() const { | |
597 return fObjectType == kDictionary_PdfObjectType; | |
598 } | |
599 | |
600 bool isFunction() const { | |
601 return false; // NYI | |
602 } | |
603 | |
604 bool isRectangle() const { | |
605 return fObjectType == kArray_PdfObjectType && fArray->count() == 4; // N
YI + and elems are numbers | |
606 } | |
607 | |
608 // TODO(edisonn): has stream .. or is stream ... TBD | |
609 bool hasStream() const { | |
610 return isDictionary() && fStr.fBuffer != NULL; | |
611 } | |
612 | |
613 // TODO(edisonn): has stream .. or is stream ... TBD | |
614 const SkPdfStream* getStream() const { | |
615 return hasStream() ? (const SkPdfStream*)this : NULL; | |
616 } | |
617 | |
618 SkPdfStream* getStream() { | |
619 return hasStream() ? (SkPdfStream*)this : NULL; | |
620 } | |
621 | |
622 bool isAnyString() const { | |
623 return fObjectType == kString_PdfObjectType || fObjectType == kHexString
_PdfObjectType; | |
624 } | |
625 | |
626 bool isHexString() const { | |
627 return fObjectType == kHexString_PdfObjectType; | |
628 } | |
629 | |
630 bool isMatrix() const { | |
631 return fObjectType == kArray_PdfObjectType && fArray->count() == 6; // N
YI + and elems are numbers | |
632 } | |
633 | |
634 inline int64_t intValue() const { | |
635 SkASSERT(fObjectType == kInteger_PdfObjectType); | |
636 | |
637 if (fObjectType != kInteger_PdfObjectType) { | |
638 // TODO(edisonn): log err | |
639 return 0; | |
640 } | |
641 return fIntegerValue; | |
642 } | |
643 private: | |
644 inline double realValue() const { | |
645 SkASSERT(fObjectType == kReal_PdfObjectType); | |
646 | |
647 if (fObjectType != kReal_PdfObjectType) { | |
648 // TODO(edisonn): log err | |
649 return 0; | |
650 } | |
651 return fRealValue; | |
652 } | |
653 public: | |
654 inline double numberValue() const { | |
655 SkASSERT(isNumber()); | |
656 | |
657 if (!isNumber()) { | |
658 // TODO(edisonn): log err | |
659 return 0; | |
660 } | |
661 return fObjectType == kReal_PdfObjectType ? fRealValue : fIntegerValue; | |
662 } | |
663 | |
664 inline SkScalar scalarValue() const { | |
665 SkASSERT(isNumber()); | |
666 | |
667 if (!isNumber()) { | |
668 // TODO(edisonn): log err | |
669 return SkIntToScalar(0); | |
670 } | |
671 return fObjectType == kReal_PdfObjectType ? SkDoubleToScalar(fRealValue)
: | |
672 SkIntToScalar(fIntegerValue)
; | |
673 } | |
674 | |
675 int referenceId() const { | |
676 SkASSERT(fObjectType == kReference_PdfObjectType); | |
677 return fRef.fId; | |
678 } | |
679 | |
680 int referenceGeneration() const { | |
681 SkASSERT(fObjectType == kReference_PdfObjectType); | |
682 return fRef.fGen; | |
683 } | |
684 | |
685 inline const char* nameValue() const { | |
686 SkASSERT(fObjectType == kName_PdfObjectType); | |
687 | |
688 if (fObjectType != kName_PdfObjectType) { | |
689 // TODO(edisonn): log err | |
690 return ""; | |
691 } | |
692 return (const char*)fStr.fBuffer; | |
693 } | |
694 | |
695 inline const char* stringValue() const { | |
696 SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexStri
ng_PdfObjectType); | |
697 | |
698 if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_Pd
fObjectType) { | |
699 // TODO(edisonn): log err | |
700 return ""; | |
701 } | |
702 return (const char*)fStr.fBuffer; | |
703 } | |
704 | |
705 inline NotOwnedString strRef() { | |
706 switch (fObjectType) { | |
707 case kString_PdfObjectType: | |
708 case kHexString_PdfObjectType: | |
709 case kKeyword_PdfObjectType: | |
710 case kName_PdfObjectType: | |
711 return fStr; | |
712 | |
713 default: | |
714 // TODO(edisonn): report/warning | |
715 return NotOwnedString(); | |
716 } | |
717 } | |
718 | |
719 // TODO(edisonn): nameValue2 and stringValue2 are used to make code generati
on easy, | |
720 // but it is not a performat way to do it, since it will create an extra cop
y | |
721 // remove these functions and make code generated faster | |
722 inline std::string nameValue2() const { | |
723 SkASSERT(fObjectType == kName_PdfObjectType); | |
724 | |
725 if (fObjectType != kName_PdfObjectType) { | |
726 // TODO(edisonn): log err | |
727 return ""; | |
728 } | |
729 return std::string((const char*)fStr.fBuffer, fStr.fBytes); | |
730 } | |
731 | |
732 inline std::string stringValue2() const { | |
733 SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexStri
ng_PdfObjectType); | |
734 | |
735 if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_Pd
fObjectType) { | |
736 // TODO(edisonn): log err | |
737 return ""; | |
738 } | |
739 return std::string((const char*)fStr.fBuffer, fStr.fBytes); | |
740 } | |
741 | |
742 inline bool boolValue() const { | |
743 SkASSERT(fObjectType == kBoolean_PdfObjectType); | |
744 | |
745 if (fObjectType != kBoolean_PdfObjectType) { | |
746 // TODO(edisonn): log err | |
747 return false; | |
748 } | |
749 return fBooleanValue; | |
750 } | |
751 | |
752 SkRect rectangleValue() const { | |
753 SkASSERT(isRectangle()); | |
754 if (!isRectangle()) { | |
755 return SkRect::MakeEmpty(); | |
756 } | |
757 | |
758 double array[4]; | |
759 for (int i = 0; i < 4; 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 SkRect::MakeEmpty(); | |
765 } | |
766 array[i] = elem->numberValue(); | |
767 } | |
768 | |
769 return SkRect::MakeLTRB(SkDoubleToScalar(array[0]), | |
770 SkDoubleToScalar(array[1]), | |
771 SkDoubleToScalar(array[2]), | |
772 SkDoubleToScalar(array[3])); | |
773 } | |
774 | |
775 SkMatrix matrixValue() const { | |
776 SkASSERT(isMatrix()); | |
777 if (!isMatrix()) { | |
778 return SkMatrix::I(); | |
779 } | |
780 | |
781 double array[6]; | |
782 for (int i = 0; i < 6; i++) { | |
783 // TODO(edisonn): version where we could resolve references? | |
784 const SkPdfObject* elem = objAtAIndex(i); | |
785 if (elem == NULL || !elem->isNumber()) { | |
786 // TODO(edisonn): report error | |
787 return SkMatrix::I(); | |
788 } | |
789 array[i] = elem->numberValue(); | |
790 } | |
791 | |
792 return SkMatrixFromPdfMatrix(array); | |
793 } | |
794 | |
795 bool filterStream(); | |
796 | |
797 | |
798 bool GetFilteredStreamRef(unsigned char const** buffer, size_t* len) { | |
799 // TODO(edisonn): add params that couls let the last filter in place if
it is jpeg or png to fast load images | |
800 if (!hasStream()) { | |
801 return false; | |
802 } | |
803 | |
804 filterStream(); | |
805 | |
806 if (buffer) { | |
807 *buffer = fStr.fBuffer; | |
808 } | |
809 | |
810 if (len) { | |
811 *len = fStr.fBytes >> 2; // last 2 bits | |
812 } | |
813 | |
814 return true; | |
815 } | |
816 | |
817 bool isStreamFiltered() const { | |
818 return hasStream() && ((fStr.fBytes & 1) == kFilteredStreamBit); | |
819 } | |
820 | |
821 bool isStreamOwned() const { | |
822 return hasStream() && ((fStr.fBytes & 2) == kOwnedStreamBit); | |
823 } | |
824 | |
825 bool GetUnfilteredStreamRef(unsigned char const** buffer, size_t* len) const
{ | |
826 if (isStreamFiltered()) { | |
827 return false; | |
828 } | |
829 | |
830 if (!hasStream()) { | |
831 return false; | |
832 } | |
833 | |
834 if (buffer) { | |
835 *buffer = fStr.fBuffer; | |
836 } | |
837 | |
838 if (len) { | |
839 *len = fStr.fBytes >> 2; // remove last 2 bits | |
840 } | |
841 | |
842 return true; | |
843 } | |
844 | |
845 bool addStream(const unsigned char* buffer, size_t len) { | |
846 SkASSERT(!hasStream()); | |
847 SkASSERT(isDictionary()); | |
848 | |
849 if (!isDictionary() || hasStream()) { | |
850 return false; | |
851 } | |
852 | |
853 fStr.fBuffer = buffer; | |
854 fStr.fBytes = (len << 2) + kUnfilteredStreamBit; | |
855 | |
856 return true; | |
857 } | |
858 | |
859 static void appendSpaces(SkString* str, int level) { | |
860 for (int i = 0 ; i < level; i++) { | |
861 str->append(" "); | |
862 } | |
863 } | |
864 | |
865 SkString toString(int firstRowLevel = 0, int level = 0) { | |
866 SkString str; | |
867 appendSpaces(&str, firstRowLevel); | |
868 switch (fObjectType) { | |
869 case kInvalid_PdfObjectType: | |
870 str.append("__Invalid"); | |
871 break; | |
872 | |
873 case kBoolean_PdfObjectType: | |
874 str.appendf("%s", fBooleanValue ? "true" : "false"); | |
875 break; | |
876 | |
877 case kInteger_PdfObjectType: | |
878 str.appendf("%i", (int)fIntegerValue); | |
879 break; | |
880 | |
881 case kReal_PdfObjectType: | |
882 str.appendf("%f", fRealValue); | |
883 break; | |
884 | |
885 case kString_PdfObjectType: | |
886 str.append("\""); | |
887 str.append((const char*)fStr.fBuffer, fStr.fBytes); | |
888 str.append("\""); | |
889 break; | |
890 | |
891 case kHexString_PdfObjectType: | |
892 str.append("<"); | |
893 for (unsigned int i = 0 ; i < fStr.fBytes; i++) { | |
894 str.appendf("%02x", (unsigned int)fStr.fBuffer[i]); | |
895 } | |
896 str.append(">"); | |
897 break; | |
898 | |
899 case kName_PdfObjectType: | |
900 str.append("/"); | |
901 str.append((const char*)fStr.fBuffer, fStr.fBytes); | |
902 break; | |
903 | |
904 case kKeyword_PdfObjectType: | |
905 str.append((const char*)fStr.fBuffer, fStr.fBytes); | |
906 break; | |
907 | |
908 case kArray_PdfObjectType: | |
909 str.append("[\n"); | |
910 for (unsigned int i = 0; i < size(); i++) { | |
911 str.append(objAtAIndex(i)->toString(level + 1, level + 1)); | |
912 if (i < size() - 1) { | |
913 str.append(","); | |
914 } | |
915 str.append("\n"); | |
916 } | |
917 appendSpaces(&str, level); | |
918 str.append("]"); | |
919 break; | |
920 | |
921 case kDictionary_PdfObjectType: { | |
922 SkTDict<SkPdfObject*>::Iter iter(*fMap); | |
923 SkPdfObject* obj = NULL; | |
924 const char* key = NULL; | |
925 str.append("<<\n"); | |
926 while ((key = iter.next(&obj)) != NULL) { | |
927 appendSpaces(&str, level + 2); | |
928 str.appendf("/%s %s\n", key, obj->toString(0, level + st
rlen(key) + 4).c_str()); | |
929 } | |
930 appendSpaces(&str, level); | |
931 str.append(">>"); | |
932 if (hasStream()) { | |
933 const unsigned char* stream = NULL; | |
934 size_t length = 0; | |
935 if (GetFilteredStreamRef(&stream, &length)) { | |
936 str.append("stream\n"); | |
937 str.append((const char*)stream, length > 256 ? 256 :
length); | |
938 str.append("\nendstream"); | |
939 } else { | |
940 str.append("stream STREAM_ERROR endstream"); | |
941 } | |
942 } | |
943 } | |
944 break; | |
945 | |
946 case kNull_PdfObjectType: | |
947 str = "NULL"; | |
948 break; | |
949 | |
950 case kReference_PdfObjectType: | |
951 str.appendf("%i %i R", fRef.fId, fRef.fGen); | |
952 break; | |
953 | |
954 case kUndefined_PdfObjectType: | |
955 str = "Undefined"; | |
956 break; | |
957 | |
958 default: | |
959 str = "Error"; | |
960 break; | |
961 } | |
962 | |
963 return str; | |
964 } | |
965 | |
966 private: | |
967 static void makeStringCore(const unsigned char* start, SkPdfObject* obj, Obj
ectType type) { | |
968 makeStringCore(start, strlen((const char*)start), obj, type); | |
969 } | |
970 | |
971 static void makeStringCore(const unsigned char* start, const unsigned char*
end, SkPdfObject* obj, ObjectType type) { | |
972 makeStringCore(start, end - start, obj, type); | |
973 } | |
974 | |
975 static void makeStringCore(const unsigned char* start, size_t bytes, SkPdfOb
ject* obj, ObjectType type) { | |
976 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); | |
977 | |
978 obj->fObjectType = type; | |
979 obj->fStr.fBuffer = start; | |
980 obj->fStr.fBytes = bytes; | |
981 } | |
982 | |
983 bool applyFilter(const char* name); | |
984 bool applyFlateDecodeFilter(); | |
985 bool applyDCTDecodeFilter(); | |
986 }; | |
987 | |
988 class SkPdfStream : public SkPdfObject {}; | |
989 class SkPdfArray : public SkPdfObject {}; | |
990 class SkPdfString : public SkPdfObject {}; | |
991 class SkPdfHexString : public SkPdfObject {}; | |
992 class SkPdfInteger : public SkPdfObject {}; | |
993 class SkPdfReal : public SkPdfObject {}; | |
994 class SkPdfNumber : public SkPdfObject {}; | |
995 | |
996 class SkPdfName : public SkPdfObject { | |
997 SkPdfName() : SkPdfObject() { | |
998 SkPdfObject::makeName((const unsigned char*)"", this); | |
999 } | |
1000 public: | |
1001 SkPdfName(char* name) : SkPdfObject() { | |
1002 this->makeName((const unsigned char*)name, this); | |
1003 } | |
1004 }; | |
1005 | |
1006 #endif // EXPERIMENTAL_PDFVIEWER_PDFPARSER_NATIVE_SKPDFOBJECT_H_ | |
OLD | NEW |