Index: experimental/PdfViewer/pdfparser/native/SkPdfObject.h |
=================================================================== |
--- experimental/PdfViewer/pdfparser/native/SkPdfObject.h (revision 0) |
+++ experimental/PdfViewer/pdfparser/native/SkPdfObject.h (revision 0) |
@@ -0,0 +1,866 @@ |
+#ifndef EXPERIMENTAL_PDFVIEWER_PDFPARSER_NATIVE_SKPDFOBJECT_H_ |
+#define EXPERIMENTAL_PDFVIEWER_PDFPARSER_NATIVE_SKPDFOBJECT_H_ |
+ |
+#include <stdint.h> |
+#include <string.h> |
+#include <string> |
+#include "SkTDArray.h" |
+#include "SkTDict.h" |
+#include "SkRect.h" |
+#include "SkMatrix.h" |
+#include "SkString.h" |
+ |
+#include "SkPdfNYI.h" |
+#include "SkPdfConfig.h" |
+ |
+class SkPdfDictionary; |
+class SkPdfStream; |
+class SkPdfAllocator; |
+ |
+// TODO(edisonn): macro it and move it to utils |
+SkMatrix SkMatrixFromPdfMatrix(double array[6]); |
+ |
+ |
+#define kFilteredStreamBit 0 |
+#define kUnfilteredStreamBit 1 |
+ |
+ |
+class SkPdfObject { |
+ public: |
+ enum ObjectType { |
+ kInvalid_PdfObjectType, |
+ |
+ kBoolean_PdfObjectType, |
+ kInteger_PdfObjectType, |
+ kReal_PdfObjectType, |
+ kString_PdfObjectType, |
+ kHexString_PdfObjectType, |
+ kName_PdfObjectType, |
+ kKeyword_PdfObjectType, |
+ //kStream_PdfObjectType, // attached to a Dictionary |
+ kArray_PdfObjectType, |
+ kDictionary_PdfObjectType, |
+ kNull_PdfObjectType, |
+ |
+ // TODO(edisonn): after the pdf has been loaded completely, resolve all references |
+ // try the same thing with delayed loaded ... |
+ kReference_PdfObjectType, |
+ |
+ kUndefined_PdfObjectType, // per 1.4 spec, if the same key appear twice in the dictionary, the value is undefined |
+ }; |
+ |
+private: |
+ struct NotOwnedString { |
+ unsigned char* fBuffer; |
+ size_t fBytes; |
+ }; |
+ |
+ struct Reference { |
+ unsigned int fId; |
+ unsigned int fGen; |
+ }; |
+ |
+ // TODO(edisonn): add stream start, stream end, where stream is weither the file |
+ // or decoded/filtered pdf stream |
+ |
+ // TODO(edisonn): add warning/report per object |
+ // TODO(edisonn): add flag fUsed, to be used once the parsing is complete, |
+ // so we could show what parts have been proccessed, ignored, or generated errors |
+ |
+ ObjectType fObjectType; |
+ |
+ union { |
+ bool fBooleanValue; |
+ int64_t fIntegerValue; |
+ // TODO(edisonn): double, float? typedefed |
+ double fRealValue; |
+ NotOwnedString fStr; |
+ |
+ // TODO(edisonn): make sure the foorprint of fArray and fMap is small, otherwise, use pointers, or classes with up to 8 bytes in footprint |
+ SkTDArray<SkPdfObject*>* fArray; |
+ Reference fRef; |
+ }; |
+ SkTDict<SkPdfObject*>* fMap; |
+ void* fData; |
+ |
+ |
+public: |
+ |
+ SkPdfObject() : fObjectType(kInvalid_PdfObjectType), fData(NULL) {} |
+ |
+ inline void* data() { |
+ return fData; |
+ } |
+ |
+ inline void setData(void* data) { |
+ fData = data; |
+ } |
+ |
+ ~SkPdfObject() { |
+ reset(); |
+ } |
+ |
+ void reset() { |
+ switch (fObjectType) { |
+ case kArray_PdfObjectType: |
+ delete fArray; |
+ break; |
+ |
+ case kDictionary_PdfObjectType: |
+ delete fMap; |
+ break; |
+ |
+ default: |
+ break; |
+ } |
+ fObjectType = kInvalid_PdfObjectType; |
+ } |
+ |
+ ObjectType type() { return fObjectType; } |
+ |
+ const char* c_str() const { |
+ switch (fObjectType) { |
+ case kString_PdfObjectType: |
+ case kHexString_PdfObjectType: |
+ case kKeyword_PdfObjectType: |
+ return (const char*)fStr.fBuffer; |
+ |
+ default: |
+ // TODO(edisonn): report/warning |
+ return NULL; |
+ } |
+ } |
+ |
+ size_t len() const { |
+ switch (fObjectType) { |
+ case kString_PdfObjectType: |
+ case kHexString_PdfObjectType: |
+ case kKeyword_PdfObjectType: |
+ return fStr.fBytes; |
+ |
+ default: |
+ // TODO(edisonn): report/warning |
+ return 0; |
+ } |
+ } |
+ |
+ |
+ // TODO(edisonn): NYI |
+ SkPdfDate& dateValue() const { |
+ static SkPdfDate nyi; |
+ return nyi; |
+ } |
+ |
+ // TODO(edisonn): NYI |
+ SkPdfFunction& functionValue() const { |
+ static SkPdfFunction nyi; |
+ return nyi; |
+ } |
+ |
+ // TODO(edisonn): NYI |
+ SkPdfFileSpec& fileSpecValue() const { |
+ static SkPdfFileSpec nyi; |
+ return nyi; |
+ } |
+ |
+ // TODO(edisonn): NYI |
+ SkPdfTree& treeValue() const { |
+ static SkPdfTree nyi; |
+ return nyi; |
+ } |
+ |
+ |
+ static void makeBoolean(bool value, SkPdfObject* obj) { |
+ SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); |
+ |
+ obj->fObjectType = kBoolean_PdfObjectType; |
+ obj->fBooleanValue = value; |
+ } |
+ |
+ static SkPdfObject makeBoolean(bool value) { |
+ SkPdfObject obj; |
+ obj.fObjectType = kBoolean_PdfObjectType; |
+ obj.fBooleanValue = value; |
+ return obj; |
+ } |
+ |
+ static void makeInteger(int64_t value, SkPdfObject* obj) { |
+ SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); |
+ |
+ obj->fObjectType = kInteger_PdfObjectType; |
+ obj->fIntegerValue = value; |
+ } |
+ |
+ static void makeReal(double value, SkPdfObject* obj) { |
+ SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); |
+ |
+ obj->fObjectType = kReal_PdfObjectType; |
+ obj->fRealValue = value; |
+ } |
+ |
+ static void makeNull(SkPdfObject* obj) { |
+ SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); |
+ |
+ obj->fObjectType = kNull_PdfObjectType; |
+ } |
+ |
+ static SkPdfObject makeNull() { |
+ SkPdfObject obj; |
+ obj.fObjectType = kNull_PdfObjectType; |
+ return obj; |
+ } |
+ |
+ static SkPdfObject kNull; |
+ |
+ static void makeNumeric(unsigned char* start, unsigned char* end, SkPdfObject* obj) { |
+ SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); |
+ |
+ // TODO(edisonn): NYI properly |
+ // if has dot (impl), or exceeds max int, is real, otherwise is int |
+ bool isInt = true; |
+ for (unsigned char* current = start; current < end; current++) { |
+ if (*current == '.') { |
+ isInt = false; |
+ break; |
+ } |
+ // TODO(edisonn): report parse issue with numbers like "24asdasd123" |
+ } |
+ if (isInt) { |
+ makeInteger(atol((const char*)start), obj); |
+ } else { |
+ makeReal(atof((const char*)start), obj); |
+ } |
+ } |
+ |
+ static void makeReference(unsigned int id, unsigned int gen, SkPdfObject* obj) { |
+ SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); |
+ |
+ obj->fObjectType = kReference_PdfObjectType; |
+ obj->fRef.fId = id; |
+ obj->fRef.fGen = gen; |
+ } |
+ |
+ |
+ static void makeString(unsigned char* start, SkPdfObject* obj) { |
+ makeStringCore(start, strlen((const char*)start), obj, kString_PdfObjectType); |
+ } |
+ |
+ static void makeString(unsigned char* start, unsigned char* end, SkPdfObject* obj) { |
+ makeStringCore(start, end - start, obj, kString_PdfObjectType); |
+ } |
+ |
+ static void makeString(unsigned char* start, size_t bytes, SkPdfObject* obj) { |
+ makeStringCore(start, bytes, obj, kString_PdfObjectType); |
+ } |
+ |
+ |
+ static void makeHexString(unsigned char* start, SkPdfObject* obj) { |
+ makeStringCore(start, strlen((const char*)start), obj, kHexString_PdfObjectType); |
+ } |
+ |
+ static void makeHexString(unsigned char* start, unsigned char* end, SkPdfObject* obj) { |
+ makeStringCore(start, end - start, obj, kHexString_PdfObjectType); |
+ } |
+ |
+ static void makeHexString(unsigned char* start, size_t bytes, SkPdfObject* obj) { |
+ makeStringCore(start, bytes, obj, kHexString_PdfObjectType); |
+ } |
+ |
+ |
+ static void makeName(unsigned char* start, SkPdfObject* obj) { |
+ makeStringCore(start, strlen((const char*)start), obj, kName_PdfObjectType); |
+ } |
+ |
+ static void makeName(unsigned char* start, unsigned char* end, SkPdfObject* obj) { |
+ makeStringCore(start, end - start, obj, kName_PdfObjectType); |
+ } |
+ |
+ static void makeName(unsigned char* start, size_t bytes, SkPdfObject* obj) { |
+ makeStringCore(start, bytes, obj, kName_PdfObjectType); |
+ } |
+ |
+ |
+ static void makeKeyword(unsigned char* start, SkPdfObject* obj) { |
+ makeStringCore(start, strlen((const char*)start), obj, kKeyword_PdfObjectType); |
+ } |
+ |
+ static void makeKeyword(unsigned char* start, unsigned char* end, SkPdfObject* obj) { |
+ makeStringCore(start, end - start, obj, kKeyword_PdfObjectType); |
+ } |
+ |
+ static void makeKeyword(unsigned char* start, size_t bytes, SkPdfObject* obj) { |
+ makeStringCore(start, bytes, obj, kKeyword_PdfObjectType); |
+ } |
+ |
+ |
+ |
+ // TODO(edisonn): make the functions to return SkPdfArray, move these functions in SkPdfArray |
+ static void makeEmptyArray(SkPdfObject* obj) { |
+ SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); |
+ |
+ obj->fObjectType = kArray_PdfObjectType; |
+ obj->fArray = new SkTDArray<SkPdfObject*>(); |
+ // return (SkPdfArray*)obj; |
+ } |
+ |
+ bool appendInArray(SkPdfObject* obj) { |
+ SkASSERT(fObjectType == kArray_PdfObjectType); |
+ if (fObjectType != kArray_PdfObjectType) { |
+ // TODO(edisonn): report err |
+ return false; |
+ } |
+ |
+ fArray->push(obj); |
+ return true; |
+ } |
+ |
+ size_t size() const { |
+ SkASSERT(fObjectType == kArray_PdfObjectType); |
+ |
+ return fArray->count(); |
+ } |
+ |
+ SkPdfObject* objAtAIndex(int i) { |
+ SkASSERT(fObjectType == kArray_PdfObjectType); |
+ |
+ return (*fArray)[i]; |
+ } |
+ |
+ SkPdfObject* removeLastInArray() { |
+ SkASSERT(fObjectType == kArray_PdfObjectType); |
+ |
+ SkPdfObject* ret = NULL; |
+ fArray->pop(&ret); |
+ |
+ return ret; |
+ } |
+ |
+ |
+ const SkPdfObject* objAtAIndex(int i) const { |
+ SkASSERT(fObjectType == kArray_PdfObjectType); |
+ |
+ return (*fArray)[i]; |
+ } |
+ |
+ SkPdfObject* operator[](int i) { |
+ SkASSERT(fObjectType == kArray_PdfObjectType); |
+ |
+ return (*fArray)[i]; |
+ } |
+ |
+ const SkPdfObject* operator[](int i) const { |
+ SkASSERT(fObjectType == kArray_PdfObjectType); |
+ |
+ return (*fArray)[i]; |
+ } |
+ |
+ |
+ // TODO(edisonn): make the functions to return SkPdfDictionary, move these functions in SkPdfDictionary |
+ static void makeEmptyDictionary(SkPdfObject* obj) { |
+ SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); |
+ |
+ obj->fObjectType = kDictionary_PdfObjectType; |
+ obj->fMap = new SkTDict<SkPdfObject*>(1); |
+ obj->fStr.fBuffer = NULL; |
+ obj->fStr.fBytes = 0; |
+ } |
+ |
+ // TODO(edisonn): get all the possible names from spec, and compute a hash function |
+ // that would create no overlaps in the same dictionary |
+ // or build a tree of chars that when followed goes to a unique id/index/hash |
+ // TODO(edisonn): generate constants like kDictFoo, kNameDict_name |
+ // which will be used in code |
+ // add function SkPdfFastNameKey key(const char* key); |
+ // TODO(edisonn): setting the same key twike, will make the value undefined! |
+ bool set(SkPdfObject* key, SkPdfObject* value) { |
+ SkASSERT(fObjectType == kDictionary_PdfObjectType); |
+ SkASSERT(key->fObjectType == kName_PdfObjectType); |
+ |
+ if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) { |
+ // TODO(edisonn): report err |
+ return false; |
+ } |
+ |
+ // we rewrite all delimiters and white spaces with '\0', so we expect the end of name to be '\0' |
+ SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0'); |
+ |
+ return set((char*)key->fStr.fBuffer, value); |
+ } |
+ |
+ bool set(const char* key, SkPdfObject* value) { |
+ SkASSERT(fObjectType == kDictionary_PdfObjectType); |
+ |
+ if (fObjectType != kDictionary_PdfObjectType) { |
+ // TODO(edisonn): report err |
+ return false; |
+ } |
+ |
+ return fMap->set(key, value); |
+ } |
+ |
+ SkPdfObject* get(SkPdfObject* key) { |
+ SkASSERT(fObjectType == kDictionary_PdfObjectType); |
+ SkASSERT(key->fObjectType == kName_PdfObjectType); |
+ |
+ if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) { |
+ // TODO(edisonn): report err |
+ return false; |
+ } |
+ |
+ SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0'); |
+ |
+ return get((char*)key->fStr.fBuffer); |
+ } |
+ |
+ SkPdfObject* get(const char* key) { |
+ SkASSERT(fObjectType == kDictionary_PdfObjectType); |
+ SkASSERT(key); |
+ if (fObjectType != kDictionary_PdfObjectType) { |
+ // TODO(edisonn): report err |
+ return NULL; |
+ } |
+ SkPdfObject* ret = NULL; |
+ fMap->find(key, &ret); |
+ return ret; |
+ } |
+ |
+ const SkPdfObject* get(SkPdfObject* key) const { |
+ SkASSERT(fObjectType == kDictionary_PdfObjectType); |
+ SkASSERT(key->fObjectType == kName_PdfObjectType); |
+ |
+ if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) { |
+ // TODO(edisonn): report err |
+ return false; |
+ } |
+ |
+ SkASSERT(key->fStr.fBuffer[key->fStr.fBytes] == '\0'); |
+ |
+ return get((char*)key->fStr.fBuffer); |
+ } |
+ |
+ |
+ const SkPdfObject* get(const char* key) const { |
+ SkASSERT(fObjectType == kDictionary_PdfObjectType); |
+ SkASSERT(key); |
+ if (fObjectType != kDictionary_PdfObjectType) { |
+ // TODO(edisonn): report err |
+ return NULL; |
+ } |
+ SkPdfObject* ret = NULL; |
+ fMap->find(key, &ret); |
+ return ret; |
+ } |
+ |
+ const SkPdfObject* get(const char* key, const char* abr) const { |
+ const SkPdfObject* ret = get(key); |
+ // TODO(edisonn): / is a valid name, and it might be an abreviation, so "" should not be like NULL |
+ // make this distiontion in generator, and remove "" from condition |
+ if (ret != NULL || abr == NULL || *abr == '\0') { |
+ return ret; |
+ } |
+ return get(abr); |
+ } |
+ |
+ SkPdfObject* get(const char* key, const char* abr) { |
+ SkPdfObject* ret = get(key); |
+ // TODO(edisonn): / is a valid name, and it might be an abreviation, so "" should not be like NULL |
+ // make this distiontion in generator, and remove "" from condition |
+ if (ret != NULL || abr == NULL || *abr == '\0') { |
+ return ret; |
+ } |
+ return get(abr); |
+ } |
+ |
+ SkPdfDictionary* asDictionary() { |
+ SkASSERT(isDictionary()); |
+ if (!isDictionary()) { |
+ return NULL; |
+ } |
+ return (SkPdfDictionary*) this; |
+ } |
+ |
+ const SkPdfDictionary* asDictionary() const { |
+ SkASSERT(isDictionary()); |
+ if (!isDictionary()) { |
+ return NULL; |
+ } |
+ return (SkPdfDictionary*) this; |
+ } |
+ |
+ |
+ bool isReference() const { |
+ return fObjectType == kReference_PdfObjectType; |
+ } |
+ |
+ bool isBoolean() const { |
+ return fObjectType == kBoolean_PdfObjectType; |
+ } |
+ |
+ bool isInteger() const { |
+ return fObjectType == kInteger_PdfObjectType; |
+ } |
+private: |
+ bool isReal() const { |
+ return fObjectType == kReal_PdfObjectType; |
+ } |
+public: |
+ bool isNumber() const { |
+ return fObjectType == kInteger_PdfObjectType || fObjectType == kReal_PdfObjectType; |
+ } |
+ |
+ bool isKeywordReference() const { |
+ return fObjectType == kKeyword_PdfObjectType && fStr.fBytes == 1 && fStr.fBuffer[0] == 'R'; |
+ } |
+ |
+ bool isKeyword() const { |
+ return fObjectType == kKeyword_PdfObjectType; |
+ } |
+ |
+ bool isName() const { |
+ return fObjectType == kName_PdfObjectType; |
+ } |
+ |
+ bool isArray() const { |
+ return fObjectType == kArray_PdfObjectType; |
+ } |
+ |
+ bool isDate() const { |
+ return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType; |
+ } |
+ |
+ bool isDictionary() const { |
+ return fObjectType == kDictionary_PdfObjectType; |
+ } |
+ |
+ bool isFunction() const { |
+ return false; // NYI |
+ } |
+ |
+ bool isRectangle() const { |
+ return fObjectType == kArray_PdfObjectType && fArray->count() == 4; // NYI + and elems are numbers |
+ } |
+ |
+ // TODO(edisonn): has stream .. or is stream ... TBD |
+ bool hasStream() const { |
+ return isDictionary() && fStr.fBuffer != NULL; |
+ } |
+ |
+ // TODO(edisonn): has stream .. or is stream ... TBD |
+ const SkPdfStream* getStream() const { |
+ return hasStream() ? (const SkPdfStream*)this : NULL; |
+ } |
+ |
+ SkPdfStream* getStream() { |
+ return hasStream() ? (SkPdfStream*)this : NULL; |
+ } |
+ |
+ bool isAnyString() const { |
+ return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType; |
+ } |
+ |
+ bool isMatrix() const { |
+ return fObjectType == kArray_PdfObjectType && fArray->count() == 6; // NYI + and elems are numbers |
+ } |
+ |
+ inline int64_t intValue() const { |
+ SkASSERT(fObjectType == kInteger_PdfObjectType); |
+ |
+ if (fObjectType != kInteger_PdfObjectType) { |
+ // TODO(edisonn): log err |
+ return 0; |
+ } |
+ return fIntegerValue; |
+ } |
+private: |
+ inline double realValue() const { |
+ SkASSERT(fObjectType == kReal_PdfObjectType); |
+ |
+ if (fObjectType != kReal_PdfObjectType) { |
+ // TODO(edisonn): log err |
+ return 0; |
+ } |
+ return fRealValue; |
+ } |
+public: |
+ inline double numberValue() const { |
+ SkASSERT(isNumber()); |
+ |
+ if (!isNumber()) { |
+ // TODO(edisonn): log err |
+ return 0; |
+ } |
+ return fObjectType == kReal_PdfObjectType ? fRealValue : fIntegerValue; |
+ } |
+ |
+ int referenceId() const { |
+ SkASSERT(fObjectType == kReference_PdfObjectType); |
+ return fRef.fId; |
+ } |
+ |
+ int referenceGeneration() const { |
+ SkASSERT(fObjectType == kReference_PdfObjectType); |
+ return fRef.fGen; |
+ } |
+ |
+ inline const char* nameValue() const { |
+ SkASSERT(fObjectType == kName_PdfObjectType); |
+ |
+ if (fObjectType != kName_PdfObjectType) { |
+ // TODO(edisonn): log err |
+ return ""; |
+ } |
+ return (const char*)fStr.fBuffer; |
+ } |
+ |
+ inline const char* stringValue() const { |
+ SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType); |
+ |
+ if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) { |
+ // TODO(edisonn): log err |
+ return ""; |
+ } |
+ return (const char*)fStr.fBuffer; |
+ } |
+ |
+ // TODO(edisonn): nameValue2 and stringValue2 are used to make code generation easy, |
+ // but it is not a performat way to do it, since it will create an extra copy |
+ // remove these functions and make code generated faster |
+ inline std::string nameValue2() const { |
+ SkASSERT(fObjectType == kName_PdfObjectType); |
+ |
+ if (fObjectType != kName_PdfObjectType) { |
+ // TODO(edisonn): log err |
+ return ""; |
+ } |
+ return (const char*)fStr.fBuffer; |
+ } |
+ |
+ inline std::string stringValue2() const { |
+ SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType); |
+ |
+ if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) { |
+ // TODO(edisonn): log err |
+ return ""; |
+ } |
+ return (const char*)fStr.fBuffer; |
+ } |
+ |
+ inline bool boolValue() const { |
+ SkASSERT(fObjectType == kBoolean_PdfObjectType); |
+ |
+ if (fObjectType == kBoolean_PdfObjectType) { |
+ // TODO(edisonn): log err |
+ return false; |
+ } |
+ return fBooleanValue; |
+ } |
+ |
+ SkRect rectangleValue() const { |
+ SkASSERT(isRectangle()); |
+ if (!isRectangle()) { |
+ return SkRect::MakeEmpty(); |
+ } |
+ |
+ double array[4]; |
+ for (int i = 0; i < 4; i++) { |
+ // TODO(edisonn): version where we could resolve references? |
+ const SkPdfObject* elem = objAtAIndex(i); |
+ if (elem == NULL || !elem->isNumber()) { |
+ // TODO(edisonn): report error |
+ return SkRect::MakeEmpty(); |
+ } |
+ array[i] = elem->numberValue(); |
+ } |
+ |
+ return SkRect::MakeLTRB(SkDoubleToScalar(array[0]), |
+ SkDoubleToScalar(array[1]), |
+ SkDoubleToScalar(array[2]), |
+ SkDoubleToScalar(array[3])); |
+ } |
+ |
+ SkMatrix matrixValue() const { |
+ SkASSERT(isMatrix()); |
+ if (!isMatrix()) { |
+ return SkMatrix::I(); |
+ } |
+ |
+ double array[6]; |
+ for (int i = 0; i < 6; i++) { |
+ // TODO(edisonn): version where we could resolve references? |
+ const SkPdfObject* elem = objAtAIndex(i); |
+ if (elem == NULL || !elem->isNumber()) { |
+ // TODO(edisonn): report error |
+ return SkMatrix::I(); |
+ } |
+ array[i] = elem->numberValue(); |
+ } |
+ |
+ return SkMatrixFromPdfMatrix(array); |
+ } |
+ |
+ bool filterStream(SkPdfAllocator* allocator); |
+ |
+ |
+ bool GetFilteredStreamRef(unsigned char** buffer, size_t* len, SkPdfAllocator* allocator) { |
+ // TODO(edisonn): add params that couls let the last filter in place if it is jpeg or png to fast load images |
+ if (!hasStream()) { |
+ return false; |
+ } |
+ |
+ filterStream(allocator); |
+ |
+ if (buffer) { |
+ *buffer = fStr.fBuffer; |
+ } |
+ |
+ if (len) { |
+ *len = fStr.fBytes >> 1; // last bit |
+ } |
+ |
+ return true; |
+ } |
+ |
+ bool isStreamFiltered() const { |
+ return hasStream() && ((fStr.fBytes & 1) == kFilteredStreamBit); |
+ } |
+ |
+ bool GetUnfilteredStreamRef(unsigned char** buffer, size_t* len) const { |
+ if (isStreamFiltered()) { |
+ return false; |
+ } |
+ |
+ if (!hasStream()) { |
+ return false; |
+ } |
+ |
+ if (buffer) { |
+ *buffer = fStr.fBuffer; |
+ } |
+ |
+ if (len) { |
+ *len = fStr.fBytes >> 1; // remove slast bit |
+ } |
+ |
+ return true; |
+ } |
+ |
+ bool addStream(unsigned char* buffer, size_t len) { |
+ SkASSERT(!hasStream()); |
+ SkASSERT(isDictionary()); |
+ |
+ if (!isDictionary() || hasStream()) { |
+ return false; |
+ } |
+ |
+ fStr.fBuffer = buffer; |
+ fStr.fBytes = (len << 2) + kUnfilteredStreamBit; |
+ |
+ return true; |
+ } |
+ |
+ SkString toString() { |
+ SkString str; |
+ switch (fObjectType) { |
+ case kInvalid_PdfObjectType: |
+ str.append("Invalid"); |
+ break; |
+ |
+ case kBoolean_PdfObjectType: |
+ str.appendf("Boolean: %s", fBooleanValue ? "true" : "false"); |
+ break; |
+ |
+ case kInteger_PdfObjectType: |
+ str.appendf("Integer: %i", (int)fIntegerValue); |
+ break; |
+ |
+ case kReal_PdfObjectType: |
+ str.appendf("Real: %f", fRealValue); |
+ break; |
+ |
+ case kString_PdfObjectType: |
+ str.appendf("String, len() = %u: ", (unsigned int)fStr.fBytes); |
+ str.append((const char*)fStr.fBuffer, fStr.fBytes); |
+ break; |
+ |
+ case kHexString_PdfObjectType: |
+ str.appendf("HexString, len() = %u: ", (unsigned int)fStr.fBytes); |
+ str.append((const char*)fStr.fBuffer, fStr.fBytes); |
+ break; |
+ |
+ case kName_PdfObjectType: |
+ str.appendf("Name, len() = %u: ", (unsigned int)fStr.fBytes); |
+ str.append((const char*)fStr.fBuffer, fStr.fBytes); |
+ break; |
+ |
+ case kKeyword_PdfObjectType: |
+ str.appendf("Keyword, len() = %u: ", (unsigned int)fStr.fBytes); |
+ str.append((const char*)fStr.fBuffer, fStr.fBytes); |
+ break; |
+ |
+ case kArray_PdfObjectType: |
+ str.append("Array, size() = %i [", size()); |
+ for (unsigned int i = 0; i < size(); i++) { |
+ str.append(objAtAIndex(i)->toString()); |
+ } |
+ str.append("]"); |
+ break; |
+ |
+ case kDictionary_PdfObjectType: |
+ // TODO(edisonn): NYI |
+ str.append("Dictionary: NYI"); |
+ if (hasStream()) { |
+ str.append(" HAS_STREAM"); |
+ } |
+ break; |
+ |
+ case kNull_PdfObjectType: |
+ str = "NULL"; |
+ break; |
+ |
+ case kReference_PdfObjectType: |
+ str.appendf("Reference: %i %i", fRef.fId, fRef.fGen); |
+ break; |
+ |
+ case kUndefined_PdfObjectType: |
+ str = "Undefined"; |
+ break; |
+ |
+ default: |
+ str = "Internal Error Object Type"; |
+ break; |
+ } |
+ |
+ return str; |
+ } |
+ |
+private: |
+ static void makeStringCore(unsigned char* start, SkPdfObject* obj, ObjectType type) { |
+ makeStringCore(start, strlen((const char*)start), obj, type); |
+ } |
+ |
+ static void makeStringCore(unsigned char* start, unsigned char* end, SkPdfObject* obj, ObjectType type) { |
+ makeStringCore(start, end - start, obj, type); |
+ } |
+ |
+ static void makeStringCore(unsigned char* start, size_t bytes, SkPdfObject* obj, ObjectType type) { |
+ SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); |
+ |
+ obj->fObjectType = type; |
+ obj->fStr.fBuffer = start; |
+ obj->fStr.fBytes = bytes; |
+ } |
+ |
+ bool applyFilter(const char* name, SkPdfAllocator* allocator); |
+ bool applyFlateDecodeFilter(SkPdfAllocator* allocator); |
+ bool applyDCTDecodeFilter(SkPdfAllocator* allocator); |
+}; |
+ |
+class SkPdfStream : public SkPdfObject {}; |
+class SkPdfArray : public SkPdfObject {}; |
+class SkPdfString : public SkPdfObject {}; |
+class SkPdfHexString : public SkPdfObject {}; |
+class SkPdfInteger : public SkPdfObject {}; |
+class SkPdfReal : public SkPdfObject {}; |
+class SkPdfNumber : public SkPdfObject {}; |
+ |
+#endif // EXPERIMENTAL_PDFVIEWER_PDFPARSER_NATIVE_SKPDFOBJECT_H_ |