aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental/PdfViewer/pdfparser/native/SkPdfObject.h
diff options
context:
space:
mode:
Diffstat (limited to 'experimental/PdfViewer/pdfparser/native/SkPdfObject.h')
-rw-r--r--experimental/PdfViewer/pdfparser/native/SkPdfObject.h866
1 files changed, 866 insertions, 0 deletions
diff --git a/experimental/PdfViewer/pdfparser/native/SkPdfObject.h b/experimental/PdfViewer/pdfparser/native/SkPdfObject.h
new file mode 100644
index 0000000000..86963b0398
--- /dev/null
+++ b/experimental/PdfViewer/pdfparser/native/SkPdfObject.h
@@ -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_