blob: 1fb4e1fccb78019116d0d3f7e4b5247b7fe6b313 [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
edisonn@google.comb0145ce2013-08-05 16:23:23 +000052 enum DataType {
53 kEmpty_Data,
54 kFont_Data,
55 kBitmap_Data,
56 };
57
edisonn@google.com571c70b2013-07-10 17:09:50 +000058private:
edisonn@google.com571c70b2013-07-10 17:09:50 +000059 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 errors
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, otherwise, use pointers, or classes with up to 8 bytes in footprint
81 SkTDArray<SkPdfObject*>* fArray;
82 Reference fRef;
83 };
84 SkTDict<SkPdfObject*>* fMap;
edisonn@google.comb0145ce2013-08-05 16:23:23 +000085
86 // TODO(edisonn): rename data with cache
edisonn@google.com571c70b2013-07-10 17:09:50 +000087 void* fData;
edisonn@google.comb0145ce2013-08-05 16:23:23 +000088 DataType fDataType;
edisonn@google.com571c70b2013-07-10 17:09:50 +000089
90
91public:
92
edisonn@google.comb0145ce2013-08-05 16:23:23 +000093 SkPdfObject() : fObjectType(kInvalid_PdfObjectType), fMap(NULL), fData(NULL), fDataType(kEmpty_Data) {}
edisonn@google.com571c70b2013-07-10 17:09:50 +000094
edisonn@google.comb0145ce2013-08-05 16:23:23 +000095
96 inline bool hasData(DataType type) {
97 return type == fDataType;
edisonn@google.com571c70b2013-07-10 17:09:50 +000098 }
99
edisonn@google.comb0145ce2013-08-05 16:23:23 +0000100 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;
edisonn@google.com571c70b2013-07-10 17:09:50 +0000107 fData = data;
108 }
109
edisonn@google.comb0145ce2013-08-05 16:23:23 +0000110 void releaseData();
111
edisonn@google.com222382b2013-07-10 22:33:10 +0000112// ~SkPdfObject() {
113// //reset(); must be called manually!
114// }
edisonn@google.com571c70b2013-07-10 17:09:50 +0000115
116 void reset() {
117 switch (fObjectType) {
118 case kArray_PdfObjectType:
119 delete fArray;
120 break;
121
122 case kDictionary_PdfObjectType:
123 delete fMap;
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000124 if (isStreamOwned()) {
125 delete[] fStr.fBuffer;
126 fStr.fBuffer = NULL;
127 fStr.fBytes = 0;
128 }
edisonn@google.com571c70b2013-07-10 17:09:50 +0000129 break;
130
131 default:
132 break;
133 }
134 fObjectType = kInvalid_PdfObjectType;
edisonn@google.comb0145ce2013-08-05 16:23:23 +0000135 releaseData();
edisonn@google.com571c70b2013-07-10 17:09:50 +0000136 }
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:
edisonn@google.com276fed92013-08-01 21:20:47 +0000145 case kName_PdfObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000146 return (const char*)fStr.fBuffer;
147
148 default:
149 // TODO(edisonn): report/warning
150 return NULL;
151 }
152 }
153
edisonn@google.come878e722013-07-29 19:10:58 +0000154 size_t lenstr() const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000155 switch (fObjectType) {
156 case kString_PdfObjectType:
157 case kHexString_PdfObjectType:
158 case kKeyword_PdfObjectType:
edisonn@google.com276fed92013-08-01 21:20:47 +0000159 case kName_PdfObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000160 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
edisonn@google.com571c70b2013-07-10 17:09:50 +0000193 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
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000235 static void makeNumeric(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000236 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;
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000241 for (const unsigned char* current = start; current < end; current++) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000242 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* obj) {
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
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000264 static void makeString(const unsigned char* start, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000265 makeStringCore(start, strlen((const char*)start), obj, kString_PdfObjectType);
266 }
267
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000268 static void makeString(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000269 makeStringCore(start, end - start, obj, kString_PdfObjectType);
270 }
271
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000272 static void makeString(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000273 makeStringCore(start, bytes, obj, kString_PdfObjectType);
274 }
275
276
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000277 static void makeHexString(const unsigned char* start, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000278 makeStringCore(start, strlen((const char*)start), obj, kHexString_PdfObjectType);
279 }
280
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000281 static void makeHexString(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000282 makeStringCore(start, end - start, obj, kHexString_PdfObjectType);
283 }
284
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000285 static void makeHexString(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000286 makeStringCore(start, bytes, obj, kHexString_PdfObjectType);
287 }
288
289
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000290 static void makeName(const unsigned char* start, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000291 makeStringCore(start, strlen((const char*)start), obj, kName_PdfObjectType);
292 }
293
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000294 static void makeName(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000295 makeStringCore(start, end - start, obj, kName_PdfObjectType);
296 }
297
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000298 static void makeName(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000299 makeStringCore(start, bytes, obj, kName_PdfObjectType);
300 }
301
302
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000303 static void makeKeyword(const unsigned char* start, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000304 makeStringCore(start, strlen((const char*)start), obj, kKeyword_PdfObjectType);
305 }
306
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000307 static void makeKeyword(const unsigned char* start, const unsigned char* end, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000308 makeStringCore(start, end - start, obj, kKeyword_PdfObjectType);
309 }
310
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000311 static void makeKeyword(const unsigned char* start, size_t bytes, SkPdfObject* obj) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000312 makeStringCore(start, bytes, obj, kKeyword_PdfObjectType);
313 }
314
315
316
317 // TODO(edisonn): make the functions to return SkPdfArray, move these functions 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 functions 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 function
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/hash
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!
edisonn@google.com2fd5d362013-07-23 19:43:48 +0000395 bool set(const SkPdfObject* key, SkPdfObject* value) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000396 SkASSERT(fObjectType == kDictionary_PdfObjectType);
397 SkASSERT(key->fObjectType == kName_PdfObjectType);
398
399 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
400 // TODO(edisonn): report err
401 return false;
402 }
403
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000404 //// 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');
edisonn@google.com571c70b2013-07-10 17:09:50 +0000406
edisonn@google.comd761e322013-07-22 17:29:43 +0000407 return set(key->fStr.fBuffer, key->fStr.fBytes, value);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000408 }
409
410 bool set(const char* key, SkPdfObject* value) {
edisonn@google.comd761e322013-07-22 17:29:43 +0000411 return set((const unsigned char*)key, strlen(key), value);
412 }
413
414 bool set(const unsigned char* key, size_t len, SkPdfObject* value) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000415 SkASSERT(fObjectType == kDictionary_PdfObjectType);
416
417 if (fObjectType != kDictionary_PdfObjectType) {
418 // TODO(edisonn): report err
419 return false;
420 }
421
edisonn@google.comd761e322013-07-22 17:29:43 +0000422 return fMap->set((const char*)key, len, value);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000423 }
424
edisonn@google.com2fd5d362013-07-23 19:43:48 +0000425 SkPdfObject* get(const SkPdfObject* key) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000426 SkASSERT(fObjectType == kDictionary_PdfObjectType);
427 SkASSERT(key->fObjectType == kName_PdfObjectType);
428
429 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
430 // TODO(edisonn): report err
edisonn@google.com3fc48262013-07-22 15:29:55 +0000431 return NULL;
edisonn@google.com571c70b2013-07-10 17:09:50 +0000432 }
433
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000434 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0');
edisonn@google.com571c70b2013-07-10 17:09:50 +0000435
edisonn@google.comd761e322013-07-22 17:29:43 +0000436 return get(key->fStr.fBuffer, key->fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000437 }
438
439 SkPdfObject* get(const char* key) {
edisonn@google.comd761e322013-07-22 17:29:43 +0000440 return get((const unsigned char*)key, strlen(key));
441 }
442
443 SkPdfObject* get(const unsigned char* key, size_t len) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000444 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;
edisonn@google.comd761e322013-07-22 17:29:43 +0000451 fMap->find((const char*)key, len, &ret);
edisonn@google.com9a43c182013-08-01 20:06:42 +0000452
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
edisonn@google.com571c70b2013-07-10 17:09:50 +0000459 return ret;
460 }
461
edisonn@google.com2fd5d362013-07-23 19:43:48 +0000462 const SkPdfObject* get(const SkPdfObject* key) const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000463 SkASSERT(fObjectType == kDictionary_PdfObjectType);
464 SkASSERT(key->fObjectType == kName_PdfObjectType);
465
466 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
467 // TODO(edisonn): report err
edisonn@google.com3fc48262013-07-22 15:29:55 +0000468 return NULL;
edisonn@google.com571c70b2013-07-10 17:09:50 +0000469 }
470
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000471 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0');
edisonn@google.com571c70b2013-07-10 17:09:50 +0000472
edisonn@google.comd761e322013-07-22 17:29:43 +0000473 return get(key->fStr.fBuffer, key->fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000474 }
475
edisonn@google.com571c70b2013-07-10 17:09:50 +0000476 const SkPdfObject* get(const char* key) const {
edisonn@google.comd761e322013-07-22 17:29:43 +0000477 return get((const unsigned char*)key, strlen(key));
478 }
479
480 const SkPdfObject* get(const unsigned char* key, size_t len) const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000481 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;
edisonn@google.comd761e322013-07-22 17:29:43 +0000488 fMap->find((const char*)key, len, &ret);
edisonn@google.com9a43c182013-08-01 20:06:42 +0000489
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
edisonn@google.com571c70b2013-07-10 17:09:50 +0000496 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 }
547private:
548 bool isReal() const {
549 return fObjectType == kReal_PdfObjectType;
550 }
551public:
552 bool isNumber() const {
553 return fObjectType == kInteger_PdfObjectType || fObjectType == kReal_PdfObjectType;
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
edisonn@google.com4ef4bed2013-07-29 22:14:45 +0000564 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
edisonn@google.com571c70b2013-07-10 17:09:50 +0000580 bool isName() const {
581 return fObjectType == kName_PdfObjectType;
582 }
583
edisonn@google.com78b38b12013-07-15 18:20:58 +0000584 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
edisonn@google.com571c70b2013-07-10 17:09:50 +0000588 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; // NYI + 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
edisonn@google.comb0145ce2013-08-05 16:23:23 +0000626 bool isHexString() const {
627 return fObjectType == kHexString_PdfObjectType;
628 }
629
edisonn@google.com571c70b2013-07-10 17:09:50 +0000630 bool isMatrix() const {
631 return fObjectType == kArray_PdfObjectType && fArray->count() == 6; // NYI + 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 }
643private:
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 }
653public:
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
edisonn@google.coma0cefa12013-07-28 18:34:14 +0000664 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
edisonn@google.com571c70b2013-07-10 17:09:50 +0000675 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 == kHexString_PdfObjectType);
697
698 if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
699 // TODO(edisonn): log err
700 return "";
701 }
702 return (const char*)fStr.fBuffer;
703 }
704
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000705 inline NotOwnedString strRef() {
706 switch (fObjectType) {
707 case kString_PdfObjectType:
708 case kHexString_PdfObjectType:
709 case kKeyword_PdfObjectType:
edisonn@google.com276fed92013-08-01 21:20:47 +0000710 case kName_PdfObjectType:
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000711 return fStr;
712
713 default:
714 // TODO(edisonn): report/warning
715 return NotOwnedString();
716 }
717 }
718
edisonn@google.com571c70b2013-07-10 17:09:50 +0000719 // TODO(edisonn): nameValue2 and stringValue2 are used to make code generation easy,
720 // but it is not a performat way to do it, since it will create an extra copy
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 }
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000729 return std::string((const char*)fStr.fBuffer, fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000730 }
731
732 inline std::string stringValue2() const {
733 SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType);
734
735 if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
736 // TODO(edisonn): log err
737 return "";
738 }
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000739 return std::string((const char*)fStr.fBuffer, fStr.fBytes);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000740 }
741
742 inline bool boolValue() const {
743 SkASSERT(fObjectType == kBoolean_PdfObjectType);
744
edisonn@google.comf111a4b2013-07-31 18:22:36 +0000745 if (fObjectType != kBoolean_PdfObjectType) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000746 // 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
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000795 bool filterStream();
edisonn@google.com571c70b2013-07-10 17:09:50 +0000796
797
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000798 bool GetFilteredStreamRef(unsigned char const** buffer, size_t* len) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000799 // 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
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000804 filterStream();
edisonn@google.com571c70b2013-07-10 17:09:50 +0000805
806 if (buffer) {
807 *buffer = fStr.fBuffer;
808 }
809
810 if (len) {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000811 *len = fStr.fBytes >> 2; // last 2 bits
edisonn@google.com571c70b2013-07-10 17:09:50 +0000812 }
813
814 return true;
815 }
816
817 bool isStreamFiltered() const {
818 return hasStream() && ((fStr.fBytes & 1) == kFilteredStreamBit);
819 }
820
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000821 bool isStreamOwned() const {
822 return hasStream() && ((fStr.fBytes & 2) == kOwnedStreamBit);
823 }
824
825 bool GetUnfilteredStreamRef(unsigned char const** buffer, size_t* len) const {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000826 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) {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000839 *len = fStr.fBytes >> 2; // remove last 2 bits
edisonn@google.com571c70b2013-07-10 17:09:50 +0000840 }
841
842 return true;
843 }
844
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000845 bool addStream(const unsigned char* buffer, size_t len) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000846 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
edisonn@google.com276fed92013-08-01 21:20:47 +0000859 static void appendSpaces(SkString* str, int level) {
edisonn@google.com9a43c182013-08-01 20:06:42 +0000860 for (int i = 0 ; i < level; i++) {
861 str->append(" ");
862 }
863 }
864
edisonn@google.come2e01ff2013-08-02 20:24:48 +0000865 SkString toString(int firstRowLevel = 0, int level = 0) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000866 SkString str;
edisonn@google.com9a43c182013-08-01 20:06:42 +0000867 appendSpaces(&str, firstRowLevel);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000868 switch (fObjectType) {
869 case kInvalid_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000870 str.append("__Invalid");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000871 break;
872
873 case kBoolean_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000874 str.appendf("%s", fBooleanValue ? "true" : "false");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000875 break;
876
877 case kInteger_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000878 str.appendf("%i", (int)fIntegerValue);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000879 break;
880
881 case kReal_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000882 str.appendf("%f", fRealValue);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000883 break;
884
885 case kString_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000886 str.append("\"");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000887 str.append((const char*)fStr.fBuffer, fStr.fBytes);
edisonn@google.com9a43c182013-08-01 20:06:42 +0000888 str.append("\"");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000889 break;
890
891 case kHexString_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000892 str.append("<");
edisonn@google.comb0145ce2013-08-05 16:23:23 +0000893 for (unsigned int i = 0 ; i < fStr.fBytes; i++) {
894 str.appendf("%02x", (unsigned int)fStr.fBuffer[i]);
895 }
edisonn@google.com9a43c182013-08-01 20:06:42 +0000896 str.append(">");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000897 break;
898
899 case kName_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000900 str.append("/");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000901 str.append((const char*)fStr.fBuffer, fStr.fBytes);
902 break;
903
904 case kKeyword_PdfObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000905 str.append((const char*)fStr.fBuffer, fStr.fBytes);
906 break;
907
908 case kArray_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000909 str.append("[\n");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000910 for (unsigned int i = 0; i < size(); i++) {
edisonn@google.com9a43c182013-08-01 20:06:42 +0000911 str.append(objAtAIndex(i)->toString(level + 1, level + 1));
912 if (i < size() - 1) {
913 str.append(",");
914 }
915 str.append("\n");
edisonn@google.com571c70b2013-07-10 17:09:50 +0000916 }
edisonn@google.com9a43c182013-08-01 20:06:42 +0000917 appendSpaces(&str, level);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000918 str.append("]");
919 break;
920
edisonn@google.com9a43c182013-08-01 20:06:42 +0000921 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 + strlen(key) + 4).c_str());
929 }
930 appendSpaces(&str, level);
931 str.append(">>");
932 if (hasStream()) {
edisonn@google.come2e01ff2013-08-02 20:24:48 +0000933 const unsigned char* stream = NULL;
934 size_t length = 0;
935 if (GetFilteredStreamRef(&stream, &length)) {
edisonn@google.comb0145ce2013-08-05 16:23:23 +0000936 str.append("stream\n");
edisonn@google.come2e01ff2013-08-02 20:24:48 +0000937 str.append((const char*)stream, length > 256 ? 256 : length);
edisonn@google.comb0145ce2013-08-05 16:23:23 +0000938 str.append("\nendstream");
edisonn@google.come2e01ff2013-08-02 20:24:48 +0000939 } else {
940 str.append("stream STREAM_ERROR endstream");
941 }
edisonn@google.com9a43c182013-08-01 20:06:42 +0000942 }
edisonn@google.com571c70b2013-07-10 17:09:50 +0000943 }
944 break;
945
946 case kNull_PdfObjectType:
947 str = "NULL";
948 break;
949
950 case kReference_PdfObjectType:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000951 str.appendf("%i %i R", fRef.fId, fRef.fGen);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000952 break;
953
954 case kUndefined_PdfObjectType:
955 str = "Undefined";
956 break;
957
958 default:
edisonn@google.com9a43c182013-08-01 20:06:42 +0000959 str = "Error";
edisonn@google.com571c70b2013-07-10 17:09:50 +0000960 break;
961 }
962
963 return str;
964 }
965
966private:
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000967 static void makeStringCore(const unsigned char* start, SkPdfObject* obj, ObjectType type) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000968 makeStringCore(start, strlen((const char*)start), obj, type);
969 }
970
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000971 static void makeStringCore(const unsigned char* start, const unsigned char* end, SkPdfObject* obj, ObjectType type) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000972 makeStringCore(start, end - start, obj, type);
973 }
974
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000975 static void makeStringCore(const unsigned char* start, size_t bytes, SkPdfObject* obj, ObjectType type) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000976 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
977
978 obj->fObjectType = type;
979 obj->fStr.fBuffer = start;
980 obj->fStr.fBytes = bytes;
981 }
982
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000983 bool applyFilter(const char* name);
984 bool applyFlateDecodeFilter();
985 bool applyDCTDecodeFilter();
edisonn@google.com571c70b2013-07-10 17:09:50 +0000986};
987
988class SkPdfStream : public SkPdfObject {};
989class SkPdfArray : public SkPdfObject {};
990class SkPdfString : public SkPdfObject {};
991class SkPdfHexString : public SkPdfObject {};
992class SkPdfInteger : public SkPdfObject {};
993class SkPdfReal : public SkPdfObject {};
994class SkPdfNumber : public SkPdfObject {};
995
edisonn@google.com78b38b12013-07-15 18:20:58 +0000996class SkPdfName : public SkPdfObject {
997 SkPdfName() : SkPdfObject() {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000998 SkPdfObject::makeName((const unsigned char*)"", this);
edisonn@google.com78b38b12013-07-15 18:20:58 +0000999 }
1000public:
1001 SkPdfName(char* name) : SkPdfObject() {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +00001002 this->makeName((const unsigned char*)name, this);
edisonn@google.com78b38b12013-07-15 18:20:58 +00001003 }
1004};
1005
edisonn@google.com571c70b2013-07-10 17:09:50 +00001006#endif // EXPERIMENTAL_PDFVIEWER_PDFPARSER_NATIVE_SKPDFOBJECT_H_