SkPdfNativeObject.h revision 0fd25d8b22ae092183f3dc67dec4c0c1bbde06bf
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 106 // Keep this the last entrys 107#ifdef PDF_TRACK_OBJECT_USAGE 108 mutable bool fUsed; 109#endif // PDF_TRACK_OBJECT_USAGE 110 111public: 112 113 SkPdfNativeObject() : fInRendering(0) 114 , fObjectType(kInvalid_PdfObjectType) 115 , fMap(NULL) 116 , fData(NULL) 117 , fDataType(kEmpty_Data) 118#ifdef PDF_TRACK_OBJECT_USAGE 119 , fUsed(false) 120#endif // PDF_TRACK_OBJECT_USAGE 121 {} 122 123 bool inRendering() const { return fInRendering != 0; } 124 void startRendering() {fInRendering = 1;} 125 void doneRendering() {fInRendering = 0;} 126 127 inline bool hasData(DataType type) { 128 return type == fDataType; 129 } 130 131 inline void* data(DataType type) { 132 return type == fDataType ? fData : NULL; 133 } 134 135 inline void setData(void* data, DataType type) { 136 releaseData(); 137 fDataType = type; 138 fData = data; 139 } 140 141 void releaseData(); 142 143// ~SkPdfNativeObject() { 144// //reset(); must be called manually! 145// } 146 147 void reset() { 148 SkPdfMarkObjectUnused(); 149 150 switch (fObjectType) { 151 case kArray_PdfObjectType: 152 delete fArray; 153 break; 154 155 case kDictionary_PdfObjectType: 156 delete fMap; 157 if (isStreamOwned()) { 158 delete[] fStr.fBuffer; 159 fStr.fBuffer = NULL; 160 fStr.fBytes = 0; 161 } 162 break; 163 164 default: 165 break; 166 } 167 fObjectType = kInvalid_PdfObjectType; 168 releaseData(); 169 } 170 171 ObjectType type() { 172 SkPdfMarkObjectUsed(); 173 174 return fObjectType; 175 } 176 177 const char* c_str() const { 178 SkPdfMarkObjectUsed(); 179 180 switch (fObjectType) { 181 case kString_PdfObjectType: 182 case kHexString_PdfObjectType: 183 case kKeyword_PdfObjectType: 184 case kName_PdfObjectType: 185 return (const char*)fStr.fBuffer; 186 187 default: 188 // TODO(edisonn): report/warning 189 return NULL; 190 } 191 } 192 193 size_t lenstr() const { 194 SkPdfMarkObjectUsed(); 195 196 switch (fObjectType) { 197 case kString_PdfObjectType: 198 case kHexString_PdfObjectType: 199 case kKeyword_PdfObjectType: 200 case kName_PdfObjectType: 201 return fStr.fBytes; 202 203 default: 204 // TODO(edisonn): report/warning 205 return 0; 206 } 207 } 208 209 210 // TODO(edisonn): NYI 211 SkPdfDate& dateValue() const { 212 static SkPdfDate nyi; 213 return nyi; 214 } 215 216 // TODO(edisonn): NYI 217 SkPdfFunction& functionValue() const { 218 static SkPdfFunction nyi; 219 return nyi; 220 } 221 222 // TODO(edisonn): NYI 223 SkPdfFileSpec& fileSpecValue() const { 224 static SkPdfFileSpec nyi; 225 return nyi; 226 } 227 228 // TODO(edisonn): NYI 229 SkPdfTree& treeValue() const { 230 static SkPdfTree nyi; 231 return nyi; 232 } 233 234 static void makeBoolean(bool value, SkPdfNativeObject* obj) { 235 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); 236 237 obj->fObjectType = kBoolean_PdfObjectType; 238 obj->fBooleanValue = value; 239 } 240 241 static SkPdfNativeObject makeBoolean(bool value) { 242 SkPdfNativeObject obj; 243 obj.fObjectType = kBoolean_PdfObjectType; 244 obj.fBooleanValue = value; 245 return obj; 246 } 247 248 static void makeInteger(int64_t value, SkPdfNativeObject* obj) { 249 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); 250 251 obj->fObjectType = kInteger_PdfObjectType; 252 obj->fIntegerValue = value; 253 } 254 255 static void makeReal(double value, SkPdfNativeObject* obj) { 256 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); 257 258 obj->fObjectType = kReal_PdfObjectType; 259 obj->fRealValue = value; 260 } 261 262 static void makeNull(SkPdfNativeObject* obj) { 263 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); 264 265 obj->fObjectType = kNull_PdfObjectType; 266 } 267 268 static SkPdfNativeObject makeNull() { 269 SkPdfNativeObject obj; 270 obj.fObjectType = kNull_PdfObjectType; 271 return obj; 272 } 273 274 static SkPdfNativeObject kNull; 275 276 static void makeNumeric(const unsigned char* start, const unsigned char* end, SkPdfNativeObject* obj) { 277 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); 278 279 // TODO(edisonn): NYI properly 280 // if has dot (impl), or exceeds max int, is real, otherwise is int 281 bool isInt = true; 282 for (const unsigned char* current = start; current < end; current++) { 283 if (*current == '.') { 284 isInt = false; 285 break; 286 } 287 // TODO(edisonn): report parse issue with numbers like "24asdasd123" 288 } 289 if (isInt) { 290 makeInteger(atol((const char*)start), obj); 291 } else { 292 makeReal(atof((const char*)start), obj); 293 } 294 } 295 296 static void makeReference(unsigned int id, unsigned int gen, SkPdfNativeObject* obj) { 297 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); 298 299 obj->fObjectType = kReference_PdfObjectType; 300 obj->fRef.fId = id; 301 obj->fRef.fGen = gen; 302 } 303 304 305 static void makeString(const unsigned char* start, SkPdfNativeObject* obj) { 306 makeStringCore(start, strlen((const char*)start), obj, kString_PdfObjectType); 307 } 308 309 static void makeString(const unsigned char* start, const unsigned char* end, SkPdfNativeObject* obj) { 310 makeStringCore(start, end - start, obj, kString_PdfObjectType); 311 } 312 313 static void makeString(const unsigned char* start, size_t bytes, SkPdfNativeObject* obj) { 314 makeStringCore(start, bytes, obj, kString_PdfObjectType); 315 } 316 317 318 static void makeHexString(const unsigned char* start, SkPdfNativeObject* obj) { 319 makeStringCore(start, strlen((const char*)start), obj, kHexString_PdfObjectType); 320 } 321 322 static void makeHexString(const unsigned char* start, const unsigned char* end, SkPdfNativeObject* obj) { 323 makeStringCore(start, end - start, obj, kHexString_PdfObjectType); 324 } 325 326 static void makeHexString(const unsigned char* start, size_t bytes, SkPdfNativeObject* obj) { 327 makeStringCore(start, bytes, obj, kHexString_PdfObjectType); 328 } 329 330 331 static void makeName(const unsigned char* start, SkPdfNativeObject* obj) { 332 makeStringCore(start, strlen((const char*)start), obj, kName_PdfObjectType); 333 } 334 335 static void makeName(const unsigned char* start, const unsigned char* end, SkPdfNativeObject* obj) { 336 makeStringCore(start, end - start, obj, kName_PdfObjectType); 337 } 338 339 static void makeName(const unsigned char* start, size_t bytes, SkPdfNativeObject* obj) { 340 makeStringCore(start, bytes, obj, kName_PdfObjectType); 341 } 342 343 344 static void makeKeyword(const unsigned char* start, SkPdfNativeObject* obj) { 345 makeStringCore(start, strlen((const char*)start), obj, kKeyword_PdfObjectType); 346 } 347 348 static void makeKeyword(const unsigned char* start, const unsigned char* end, SkPdfNativeObject* obj) { 349 makeStringCore(start, end - start, obj, kKeyword_PdfObjectType); 350 } 351 352 static void makeKeyword(const unsigned char* start, size_t bytes, SkPdfNativeObject* obj) { 353 makeStringCore(start, bytes, obj, kKeyword_PdfObjectType); 354 } 355 356 357 358 // TODO(edisonn): make the functions to return SkPdfArray, move these functions in SkPdfArray 359 static void makeEmptyArray(SkPdfNativeObject* obj) { 360 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); 361 362 obj->fObjectType = kArray_PdfObjectType; 363 obj->fArray = new SkTDArray<SkPdfNativeObject*>(); 364 // return (SkPdfArray*)obj; 365 } 366 367 bool appendInArray(SkPdfNativeObject* obj) { 368 SkASSERT(fObjectType == kArray_PdfObjectType); 369 if (fObjectType != kArray_PdfObjectType) { 370 // TODO(edisonn): report err 371 return false; 372 } 373 374 fArray->push(obj); 375 return true; 376 } 377 378 size_t size() const { 379 SkPdfMarkObjectUsed(); 380 381 SkASSERT(fObjectType == kArray_PdfObjectType); 382 383 return fArray->count(); 384 } 385 386 SkPdfNativeObject* objAtAIndex(int i) { 387 SkPdfMarkObjectUsed(); 388 389 SkASSERT(fObjectType == kArray_PdfObjectType); 390 391 return (*fArray)[i]; 392 } 393 394 SkPdfNativeObject* removeLastInArray() { 395 // SkPdfMarkObjectUsed(); 396 397 SkASSERT(fObjectType == kArray_PdfObjectType); 398 399 SkPdfNativeObject* ret = NULL; 400 fArray->pop(&ret); 401 402 return ret; 403 } 404 405 406 const SkPdfNativeObject* objAtAIndex(int i) const { 407 SkPdfMarkObjectUsed(); 408 409 SkASSERT(fObjectType == kArray_PdfObjectType); 410 411 return (*fArray)[i]; 412 } 413 414 SkPdfNativeObject* operator[](int i) { 415 SkASSERT(fObjectType == kArray_PdfObjectType); 416 417 return (*fArray)[i]; 418 } 419 420 const SkPdfNativeObject* operator[](int i) const { 421 SkPdfMarkObjectUsed(); 422 423 SkASSERT(fObjectType == kArray_PdfObjectType); 424 425 return (*fArray)[i]; 426 } 427 428 429 // TODO(edisonn): make the functions to return SkPdfDictionary, move these functions in SkPdfDictionary 430 static void makeEmptyDictionary(SkPdfNativeObject* obj) { 431 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); 432 433 obj->fObjectType = kDictionary_PdfObjectType; 434 obj->fMap = new SkTDict<SkPdfNativeObject*>(1); 435 obj->fStr.fBuffer = NULL; 436 obj->fStr.fBytes = 0; 437 } 438 439 // TODO(edisonn): get all the possible names from spec, and compute a hash function 440 // that would create no overlaps in the same dictionary 441 // or build a tree of chars that when followed goes to a unique id/index/hash 442 // TODO(edisonn): generate constants like kDictFoo, kNameDict_name 443 // which will be used in code 444 // add function SkPdfFastNameKey key(const char* key); 445 // TODO(edisonn): setting the same key twike, will make the value undefined! 446 bool set(const SkPdfNativeObject* key, SkPdfNativeObject* value) { 447 //SkPdfMarkObjectUsed(); 448 449 SkASSERT(fObjectType == kDictionary_PdfObjectType); 450 SkASSERT(key->fObjectType == kName_PdfObjectType); 451 452 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) { 453 // TODO(edisonn): report err 454 return false; 455 } 456 457 //// we rewrite all delimiters and white spaces with '\0', so we expect the end of name to be '\0' 458 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0'); 459 460 return set(key->fStr.fBuffer, key->fStr.fBytes, value); 461 } 462 463 bool set(const char* key, SkPdfNativeObject* value) { 464 //SkPdfMarkObjectUsed(); 465 466 return set((const unsigned char*)key, strlen(key), value); 467 } 468 469 bool set(const unsigned char* key, size_t len, SkPdfNativeObject* value) { 470 //SkPdfMarkObjectUsed(); 471 472 SkASSERT(fObjectType == kDictionary_PdfObjectType); 473 474 if (fObjectType != kDictionary_PdfObjectType) { 475 // TODO(edisonn): report err 476 return false; 477 } 478 479 return fMap->set((const char*)key, len, value); 480 } 481 482 SkPdfNativeObject* get(const SkPdfNativeObject* key) { 483 SkPdfMarkObjectUsed(); 484 485 SkASSERT(fObjectType == kDictionary_PdfObjectType); 486 SkASSERT(key->fObjectType == kName_PdfObjectType); 487 488 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) { 489 // TODO(edisonn): report err 490 return NULL; 491 } 492 493 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0'); 494 495 return get(key->fStr.fBuffer, key->fStr.fBytes); 496 } 497 498 SkPdfNativeObject* get(const char* key) { 499 SkPdfMarkObjectUsed(); 500 501 return get((const unsigned char*)key, strlen(key)); 502 } 503 504 SkPdfNativeObject* get(const unsigned char* key, size_t len) { 505 SkPdfMarkObjectUsed(); 506 507 SkASSERT(fObjectType == kDictionary_PdfObjectType); 508 SkASSERT(key); 509 if (fObjectType != kDictionary_PdfObjectType) { 510 // TODO(edisonn): report err 511 return NULL; 512 } 513 SkPdfNativeObject* ret = NULL; 514 fMap->find((const char*)key, len, &ret); 515 516#ifdef PDF_TRACE 517 SkString _key; 518 _key.append((const char*)key, len); 519 printf("\nget(/%s) = %s\n", _key.c_str(), ret ? ret->toString(0, len + 9).c_str() : "_NOT_FOUND"); 520#endif 521 522 return ret; 523 } 524 525 const SkPdfNativeObject* get(const SkPdfNativeObject* key) const { 526 SkPdfMarkObjectUsed(); 527 528 SkASSERT(fObjectType == kDictionary_PdfObjectType); 529 SkASSERT(key->fObjectType == kName_PdfObjectType); 530 531 if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) { 532 // TODO(edisonn): report err 533 return NULL; 534 } 535 536 //SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0'); 537 538 return get(key->fStr.fBuffer, key->fStr.fBytes); 539 } 540 541 const SkPdfNativeObject* get(const char* key) const { 542 SkPdfMarkObjectUsed(); 543 544 return get((const unsigned char*)key, strlen(key)); 545 } 546 547 const SkPdfNativeObject* get(const unsigned char* key, size_t len) const { 548 SkPdfMarkObjectUsed(); 549 550 SkASSERT(fObjectType == kDictionary_PdfObjectType); 551 SkASSERT(key); 552 if (fObjectType != kDictionary_PdfObjectType) { 553 // TODO(edisonn): report err 554 return NULL; 555 } 556 SkPdfNativeObject* ret = NULL; 557 fMap->find((const char*)key, len, &ret); 558 559#ifdef PDF_TRACE 560 SkString _key; 561 _key.append((const char*)key, len); 562 printf("\nget(/%s) = %s\n", _key.c_str(), ret ? ret->toString(0, len + 9).c_str() : "_NOT_FOUND"); 563#endif 564 565 return ret; 566 } 567 568 const SkPdfNativeObject* get(const char* key, const char* abr) const { 569 SkPdfMarkObjectUsed(); 570 571 const SkPdfNativeObject* ret = get(key); 572 // TODO(edisonn): / is a valid name, and it might be an abreviation, so "" should not be like NULL 573 // make this distiontion in generator, and remove "" from condition 574 if (ret != NULL || abr == NULL || *abr == '\0') { 575 return ret; 576 } 577 return get(abr); 578 } 579 580 SkPdfNativeObject* get(const char* key, const char* abr) { 581 SkPdfMarkObjectUsed(); 582 583 SkPdfNativeObject* ret = get(key); 584 // TODO(edisonn): / is a valid name, and it might be an abreviation, so "" should not be like NULL 585 // make this distiontion in generator, and remove "" from condition 586 if (ret != NULL || abr == NULL || *abr == '\0') { 587 return ret; 588 } 589 return get(abr); 590 } 591 592 SkPdfDictionary* asDictionary() { 593 SkPdfMarkObjectUsed(); 594 595 SkASSERT(isDictionary()); 596 if (!isDictionary()) { 597 return NULL; 598 } 599 return (SkPdfDictionary*) this; 600 } 601 602 const SkPdfDictionary* asDictionary() const { 603 SkPdfMarkObjectUsed(); 604 605 SkASSERT(isDictionary()); 606 if (!isDictionary()) { 607 return NULL; 608 } 609 return (SkPdfDictionary*) this; 610 } 611 612 613 bool isReference() const { 614 SkPdfMarkObjectUsed(); 615 616 return fObjectType == kReference_PdfObjectType; 617 } 618 619 bool isBoolean() const { 620 SkPdfMarkObjectUsed(); 621 622 return fObjectType == kBoolean_PdfObjectType; 623 } 624 625 bool isInteger() const { 626 SkPdfMarkObjectUsed(); 627 628 return fObjectType == kInteger_PdfObjectType; 629 } 630private: 631 bool isReal() const { 632 SkPdfMarkObjectUsed(); 633 634 return fObjectType == kReal_PdfObjectType; 635 } 636public: 637 bool isNumber() const { 638 SkPdfMarkObjectUsed(); 639 640 return fObjectType == kInteger_PdfObjectType || fObjectType == kReal_PdfObjectType; 641 } 642 643 bool isKeywordReference() const { 644 SkPdfMarkObjectUsed(); 645 646 return fObjectType == kKeyword_PdfObjectType && fStr.fBytes == 1 && fStr.fBuffer[0] == 'R'; 647 } 648 649 bool isKeyword() const { 650 SkPdfMarkObjectUsed(); 651 652 return fObjectType == kKeyword_PdfObjectType; 653 } 654 655 bool isKeyword(const char* keyword) const { 656 SkPdfMarkObjectUsed(); 657 658 if (!isKeyword()) { 659 return false; 660 } 661 662 if (strlen(keyword) != fStr.fBytes) { 663 return false; 664 } 665 666 if (strncmp(keyword, (const char*)fStr.fBuffer, fStr.fBytes) != 0) { 667 return false; 668 } 669 670 return true; 671 } 672 673 bool isName() const { 674 SkPdfMarkObjectUsed(); 675 676 return fObjectType == kName_PdfObjectType; 677 } 678 679 bool isName(const char* name) const { 680 SkPdfMarkObjectUsed(); 681 682 return fObjectType == kName_PdfObjectType && fStr.fBytes == strlen(name) && strncmp((const char*)fStr.fBuffer, name, fStr.fBytes) == 0; 683 } 684 685 bool isArray() const { 686 SkPdfMarkObjectUsed(); 687 688 return fObjectType == kArray_PdfObjectType; 689 } 690 691 bool isDate() const { 692 SkPdfMarkObjectUsed(); 693 694 return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType; 695 } 696 697 bool isDictionary() const { 698 SkPdfMarkObjectUsed(); 699 700 return fObjectType == kDictionary_PdfObjectType; 701 } 702 703 bool isFunction() const { 704 SkPdfMarkObjectUsed(); 705 706 return false; // NYI 707 } 708 709 bool isRectangle() const { 710 SkPdfMarkObjectUsed(); 711 712 return fObjectType == kArray_PdfObjectType && fArray->count() == 4; // NYI + and elems are numbers 713 } 714 715 // TODO(edisonn): has stream .. or is stream ... TBD 716 bool hasStream() const { 717 SkPdfMarkObjectUsed(); 718 719 return isDictionary() && fStr.fBuffer != NULL; 720 } 721 722 // TODO(edisonn): has stream .. or is stream ... TBD 723 const SkPdfStream* getStream() const { 724 SkPdfMarkObjectUsed(); 725 726 return hasStream() ? (const SkPdfStream*)this : NULL; 727 } 728 729 SkPdfStream* getStream() { 730 SkPdfMarkObjectUsed(); 731 732 return hasStream() ? (SkPdfStream*)this : NULL; 733 } 734 735 bool isAnyString() const { 736 SkPdfMarkObjectUsed(); 737 738 return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType; 739 } 740 741 bool isHexString() const { 742 SkPdfMarkObjectUsed(); 743 744 return fObjectType == kHexString_PdfObjectType; 745 } 746 747 bool isMatrix() const { 748 SkPdfMarkObjectUsed(); 749 750 return fObjectType == kArray_PdfObjectType && fArray->count() == 6; // NYI + and elems are numbers 751 } 752 753 inline int64_t intValue() const { 754 SkPdfMarkObjectUsed(); 755 756 SkASSERT(fObjectType == kInteger_PdfObjectType); 757 758 if (fObjectType != kInteger_PdfObjectType) { 759 // TODO(edisonn): log err 760 return 0; 761 } 762 return fIntegerValue; 763 } 764private: 765 inline double realValue() const { 766 SkPdfMarkObjectUsed(); 767 768 SkASSERT(fObjectType == kReal_PdfObjectType); 769 770 if (fObjectType != kReal_PdfObjectType) { 771 // TODO(edisonn): log err 772 return 0; 773 } 774 return fRealValue; 775 } 776public: 777 inline double numberValue() const { 778 SkPdfMarkObjectUsed(); 779 780 SkASSERT(isNumber()); 781 782 if (!isNumber()) { 783 // TODO(edisonn): log err 784 return 0; 785 } 786 return fObjectType == kReal_PdfObjectType ? fRealValue : fIntegerValue; 787 } 788 789 inline SkScalar scalarValue() const { 790 SkPdfMarkObjectUsed(); 791 792 SkASSERT(isNumber()); 793 794 if (!isNumber()) { 795 // TODO(edisonn): log err 796 return SkIntToScalar(0); 797 } 798 return fObjectType == kReal_PdfObjectType ? SkDoubleToScalar(fRealValue) : 799 SkIntToScalar(fIntegerValue); 800 } 801 802 int referenceId() const { 803 SkPdfMarkObjectUsed(); 804 805 SkASSERT(fObjectType == kReference_PdfObjectType); 806 return fRef.fId; 807 } 808 809 int referenceGeneration() const { 810 SkPdfMarkObjectUsed(); 811 812 SkASSERT(fObjectType == kReference_PdfObjectType); 813 return fRef.fGen; 814 } 815 816 inline const char* nameValue() const { 817 SkPdfMarkObjectUsed(); 818 819 SkASSERT(fObjectType == kName_PdfObjectType); 820 821 if (fObjectType != kName_PdfObjectType) { 822 // TODO(edisonn): log err 823 return ""; 824 } 825 return (const char*)fStr.fBuffer; 826 } 827 828 inline const char* stringValue() const { 829 SkPdfMarkObjectUsed(); 830 831 SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType); 832 833 if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) { 834 // TODO(edisonn): log err 835 return ""; 836 } 837 return (const char*)fStr.fBuffer; 838 } 839 840 inline NotOwnedString strRef() { 841 SkPdfMarkObjectUsed(); 842 843 switch (fObjectType) { 844 case kString_PdfObjectType: 845 case kHexString_PdfObjectType: 846 case kKeyword_PdfObjectType: 847 case kName_PdfObjectType: 848 return fStr; 849 850 default: 851 // TODO(edisonn): report/warning 852 return NotOwnedString(); 853 } 854 } 855 856 // TODO(edisonn): nameValue2 and stringValue2 are used to make code generation easy, 857 // but it is not a performat way to do it, since it will create an extra copy 858 // remove these functions and make code generated faster 859 inline SkString nameValue2() const { 860 SkPdfMarkObjectUsed(); 861 862 SkASSERT(fObjectType == kName_PdfObjectType); 863 864 if (fObjectType != kName_PdfObjectType) { 865 // TODO(edisonn): log err 866 return SkString(); 867 } 868 return SkString((const char*)fStr.fBuffer, fStr.fBytes); 869 } 870 871 inline SkString stringValue2() const { 872 SkPdfMarkObjectUsed(); 873 874 SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType); 875 876 if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) { 877 // TODO(edisonn): log err 878 return SkString(); 879 } 880 return SkString((const char*)fStr.fBuffer, fStr.fBytes); 881 } 882 883 inline bool boolValue() const { 884 SkPdfMarkObjectUsed(); 885 886 SkASSERT(fObjectType == kBoolean_PdfObjectType); 887 888 if (fObjectType != kBoolean_PdfObjectType) { 889 // TODO(edisonn): log err 890 return false; 891 } 892 return fBooleanValue; 893 } 894 895 SkRect rectangleValue() const { 896 SkPdfMarkObjectUsed(); 897 898 SkASSERT(isRectangle()); 899 if (!isRectangle()) { 900 return SkRect::MakeEmpty(); 901 } 902 903 double array[4]; 904 for (int i = 0; i < 4; i++) { 905 // TODO(edisonn): version where we could resolve references? 906 const SkPdfNativeObject* elem = objAtAIndex(i); 907 if (elem == NULL || !elem->isNumber()) { 908 // TODO(edisonn): report error 909 return SkRect::MakeEmpty(); 910 } 911 array[i] = elem->numberValue(); 912 } 913 914 return SkRect::MakeLTRB(SkDoubleToScalar(array[0]), 915 SkDoubleToScalar(array[1]), 916 SkDoubleToScalar(array[2]), 917 SkDoubleToScalar(array[3])); 918 } 919 920 SkMatrix matrixValue() const { 921 SkPdfMarkObjectUsed(); 922 923 SkASSERT(isMatrix()); 924 if (!isMatrix()) { 925 return SkMatrix::I(); 926 } 927 928 double array[6]; 929 for (int i = 0; i < 6; i++) { 930 // TODO(edisonn): version where we could resolve references? 931 const SkPdfNativeObject* elem = objAtAIndex(i); 932 if (elem == NULL || !elem->isNumber()) { 933 // TODO(edisonn): report error 934 return SkMatrix::I(); 935 } 936 array[i] = elem->numberValue(); 937 } 938 939 return SkMatrixFromPdfMatrix(array); 940 } 941 942 bool filterStream(); 943 944 945 bool GetFilteredStreamRef(unsigned char const** buffer, size_t* len) { 946 SkPdfMarkObjectUsed(); 947 948 // TODO(edisonn): add params that couls let the last filter in place if it is jpeg or png to fast load images 949 if (!hasStream()) { 950 return false; 951 } 952 953 filterStream(); 954 955 if (buffer) { 956 *buffer = fStr.fBuffer; 957 } 958 959 if (len) { 960 *len = fStr.fBytes >> 2; // last 2 bits 961 } 962 963 return true; 964 } 965 966 bool isStreamFiltered() const { 967 SkPdfMarkObjectUsed(); 968 969 return hasStream() && ((fStr.fBytes & 1) == kFilteredStreamBit); 970 } 971 972 bool isStreamOwned() const { 973 SkPdfMarkObjectUsed(); 974 975 return hasStream() && ((fStr.fBytes & 2) == kOwnedStreamBit); 976 } 977 978 bool GetUnfilteredStreamRef(unsigned char const** buffer, size_t* len) const { 979 SkPdfMarkObjectUsed(); 980 981 if (isStreamFiltered()) { 982 return false; 983 } 984 985 if (!hasStream()) { 986 return false; 987 } 988 989 if (buffer) { 990 *buffer = fStr.fBuffer; 991 } 992 993 if (len) { 994 *len = fStr.fBytes >> 2; // remove last 2 bits 995 } 996 997 return true; 998 } 999 1000 bool addStream(const unsigned char* buffer, size_t len) { 1001 //SkPdfMarkObjectUsed(); 1002 1003 SkASSERT(!hasStream()); 1004 SkASSERT(isDictionary()); 1005 1006 if (!isDictionary() || hasStream()) { 1007 return false; 1008 } 1009 1010 fStr.fBuffer = buffer; 1011 fStr.fBytes = (len << 2) + kUnfilteredStreamBit; 1012 1013 return true; 1014 } 1015 1016 static void appendSpaces(SkString* str, int level) { 1017 for (int i = 0 ; i < level; i++) { 1018 str->append(" "); 1019 } 1020 } 1021 1022 static void append(SkString* str, const char* data, size_t len, const char* prefix = "\\x") { 1023 for (unsigned int i = 0 ; i < len; i++) { 1024 if (data[i] == kNUL_PdfWhiteSpace) { 1025 str->append(prefix); 1026 str->append("00"); 1027 } else if (data[i] == kHT_PdfWhiteSpace) { 1028 str->append(prefix); 1029 str->append("09"); 1030 } else if (data[i] == kLF_PdfWhiteSpace) { 1031 str->append(prefix); 1032 str->append("0A"); 1033 } else if (data[i] == kFF_PdfWhiteSpace) { 1034 str->append(prefix); 1035 str->append("0C"); 1036 } else if (data[i] == kCR_PdfWhiteSpace) { 1037 str->append(prefix); 1038 str->append("0D"); 1039 } else { 1040 str->append(data + i, 1); 1041 } 1042 } 1043 } 1044 1045 SkString toString(int firstRowLevel = 0, int level = 0) { 1046 SkString str; 1047 appendSpaces(&str, firstRowLevel); 1048 switch (fObjectType) { 1049 case kInvalid_PdfObjectType: 1050 str.append("__Invalid"); 1051 break; 1052 1053 case kBoolean_PdfObjectType: 1054 str.appendf("%s", fBooleanValue ? "true" : "false"); 1055 break; 1056 1057 case kInteger_PdfObjectType: 1058 str.appendf("%i", (int)fIntegerValue); 1059 break; 1060 1061 case kReal_PdfObjectType: 1062 str.appendf("%f", fRealValue); 1063 break; 1064 1065 case kString_PdfObjectType: 1066 str.append("\""); 1067 append(&str, (const char*)fStr.fBuffer, fStr.fBytes); 1068 str.append("\""); 1069 break; 1070 1071 case kHexString_PdfObjectType: 1072 str.append("<"); 1073 for (unsigned int i = 0 ; i < fStr.fBytes; i++) { 1074 str.appendf("%02x", (unsigned int)fStr.fBuffer[i]); 1075 } 1076 str.append(">"); 1077 break; 1078 1079 case kName_PdfObjectType: 1080 str.append("/"); 1081 append(&str, (const char*)fStr.fBuffer, fStr.fBytes, "#"); 1082 break; 1083 1084 case kKeyword_PdfObjectType: 1085 append(&str, (const char*)fStr.fBuffer, fStr.fBytes); 1086 break; 1087 1088 case kArray_PdfObjectType: 1089 str.append("[\n"); 1090 for (unsigned int i = 0; i < size(); i++) { 1091 str.append(objAtAIndex(i)->toString(level + 1, level + 1)); 1092 if (i < size() - 1) { 1093 str.append(","); 1094 } 1095 str.append("\n"); 1096 } 1097 appendSpaces(&str, level); 1098 str.append("]"); 1099 break; 1100 1101 case kDictionary_PdfObjectType: { 1102 SkTDict<SkPdfNativeObject*>::Iter iter(*fMap); 1103 SkPdfNativeObject* obj = NULL; 1104 const char* key = NULL; 1105 str.append("<<\n"); 1106 while ((key = iter.next(&obj)) != NULL) { 1107 appendSpaces(&str, level + 2); 1108 str.appendf("/%s %s\n", key, obj->toString(0, level + strlen(key) + 4).c_str()); 1109 } 1110 appendSpaces(&str, level); 1111 str.append(">>"); 1112 if (hasStream()) { 1113 const unsigned char* stream = NULL; 1114 size_t length = 0; 1115 if (GetFilteredStreamRef(&stream, &length)) { 1116 str.append("stream\n"); 1117 append(&str, (const char*)stream, length > 256 ? 256 : length); 1118 str.append("\nendstream"); 1119 } else { 1120 str.append("stream STREAM_ERROR endstream"); 1121 } 1122 } 1123 } 1124 break; 1125 1126 case kNull_PdfObjectType: 1127 str = "NULL"; 1128 break; 1129 1130 case kReference_PdfObjectType: 1131 str.appendf("%i %i R", fRef.fId, fRef.fGen); 1132 break; 1133 1134 case kUndefined_PdfObjectType: 1135 str = "Undefined"; 1136 break; 1137 1138 default: 1139 str = "Error"; 1140 break; 1141 } 1142 1143 return str; 1144 } 1145 1146private: 1147 static void makeStringCore(const unsigned char* start, SkPdfNativeObject* obj, ObjectType type) { 1148 makeStringCore(start, strlen((const char*)start), obj, type); 1149 } 1150 1151 static void makeStringCore(const unsigned char* start, const unsigned char* end, SkPdfNativeObject* obj, ObjectType type) { 1152 makeStringCore(start, end - start, obj, type); 1153 } 1154 1155 static void makeStringCore(const unsigned char* start, size_t bytes, SkPdfNativeObject* obj, ObjectType type) { 1156 SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); 1157 1158 obj->fObjectType = type; 1159 obj->fStr.fBuffer = start; 1160 obj->fStr.fBytes = bytes; 1161 } 1162 1163 bool applyFilter(const char* name); 1164 bool applyFlateDecodeFilter(); 1165 bool applyDCTDecodeFilter(); 1166}; 1167 1168class SkPdfStream : public SkPdfNativeObject {}; 1169class SkPdfArray : public SkPdfNativeObject {}; 1170class SkPdfString : public SkPdfNativeObject {}; 1171class SkPdfHexString : public SkPdfNativeObject {}; 1172class SkPdfInteger : public SkPdfNativeObject {}; 1173class SkPdfReal : public SkPdfNativeObject {}; 1174class SkPdfNumber : public SkPdfNativeObject {}; 1175 1176class SkPdfName : public SkPdfNativeObject { 1177 SkPdfName() : SkPdfNativeObject() { 1178 SkPdfNativeObject::makeName((const unsigned char*)"", this); 1179 } 1180public: 1181 SkPdfName(char* name) : SkPdfNativeObject() { 1182 this->makeName((const unsigned char*)name, this); 1183 } 1184}; 1185 1186#endif // SkPdfNativeObject 1187