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