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