| /* |
| * Copyright 2013 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef SkPdfNativeTokenizer_DEFINED |
| #define SkPdfNativeTokenizer_DEFINED |
| |
| #include <math.h> |
| #include <string.h> |
| |
| #include "SkPdfConfig.h" |
| #include "SkTDArray.h" |
| #include "SkTDict.h" |
| |
| // All these constants are defined by the PDF 1.4 Spec. |
| |
| class SkPdfDictionary; |
| class SkPdfImageDictionary; |
| class SkPdfNativeDoc; |
| class SkPdfNativeObject; |
| |
| |
| // White Spaces |
| #define kNUL_PdfWhiteSpace '\x00' |
| #define kHT_PdfWhiteSpace '\x09' |
| #define kLF_PdfWhiteSpace '\x0A' |
| #define kFF_PdfWhiteSpace '\x0C' |
| #define kCR_PdfWhiteSpace '\x0D' |
| #define kSP_PdfWhiteSpace '\x20' |
| |
| // PdfDelimiters |
| #define kOpenedRoundBracket_PdfDelimiter '(' |
| #define kClosedRoundBracket_PdfDelimiter ')' |
| #define kOpenedInequityBracket_PdfDelimiter '<' |
| #define kClosedInequityBracket_PdfDelimiter '>' |
| #define kOpenedSquareBracket_PdfDelimiter '[' |
| #define kClosedSquareBracket_PdfDelimiter ']' |
| #define kOpenedCurlyBracket_PdfDelimiter '{' |
| #define kClosedCurlyBracket_PdfDelimiter '}' |
| #define kNamed_PdfDelimiter '/' |
| #define kComment_PdfDelimiter '%' |
| |
| #define kEscape_PdfSpecial '\\' |
| #define kBackspace_PdfSpecial '\x08' |
| |
| // TODO(edisonn): what is the faster way for compiler/machine type to evaluate this expressions? |
| // we should evaluate all options. might be even different from one machine to another |
| // 1) expand expression, let compiler optimize it |
| // 2) binary search |
| // 3) linear search in array |
| // 4) vector (e.f. T type[256] .. return type[ch] ... |
| // 5) manually build the expression with least number of operators, e.g. for consecutive |
| // chars, we can use an binary equal ignoring last bit |
| #define isPdfWhiteSpace(ch) (((ch)==kNUL_PdfWhiteSpace)|| \ |
| ((ch)==kHT_PdfWhiteSpace)|| \ |
| ((ch)==kLF_PdfWhiteSpace)|| \ |
| ((ch)==kFF_PdfWhiteSpace)|| \ |
| ((ch)==kCR_PdfWhiteSpace)|| \ |
| ((ch)==kSP_PdfWhiteSpace)) |
| |
| #define isPdfEOL(ch) (((ch)==kLF_PdfWhiteSpace)||((ch)==kCR_PdfWhiteSpace)) |
| |
| |
| #define isPdfDelimiter(ch) (((ch)==kOpenedRoundBracket_PdfDelimiter)||\ |
| ((ch)==kClosedRoundBracket_PdfDelimiter)||\ |
| ((ch)==kOpenedInequityBracket_PdfDelimiter)||\ |
| ((ch)==kClosedInequityBracket_PdfDelimiter)||\ |
| ((ch)==kOpenedSquareBracket_PdfDelimiter)||\ |
| ((ch)==kClosedSquareBracket_PdfDelimiter)||\ |
| ((ch)==kOpenedCurlyBracket_PdfDelimiter)||\ |
| ((ch)==kClosedCurlyBracket_PdfDelimiter)||\ |
| ((ch)==kNamed_PdfDelimiter)||\ |
| ((ch)==kComment_PdfDelimiter)) |
| |
| #define isPdfWhiteSpaceOrPdfDelimiter(ch) (isPdfWhiteSpace(ch)||isPdfDelimiter(ch)) |
| |
| #define isPdfDigit(ch) ((ch)>='0'&&(ch)<='9') |
| #define isPdfNumeric(ch) (isPdfDigit(ch)||(ch)=='+'||(ch)=='-'||(ch)=='.') |
| |
| const unsigned char* skipPdfWhiteSpaces(const unsigned char* buffer, const unsigned char* end); |
| const unsigned char* endOfPdfToken(const unsigned char* start, const unsigned char* end); |
| |
| #define BUFFER_SIZE 1024 |
| |
| /** \class SkPdfAllocator |
| * |
| * An allocator only allocates memory, and it deletes it all when the allocator is destroyed. |
| * This strategy would allow us not to do any garbage collection while we parse and/or render |
| * a pdf. |
| * |
| */ |
| class SkPdfAllocator { |
| public: |
| SkPdfAllocator() { |
| fSizeInBytes = sizeof(*this); |
| fCurrent = allocBlock(); |
| fCurrentUsed = 0; |
| } |
| |
| ~SkPdfAllocator(); |
| |
| // Allocates an object. It will be reset automatically when ~SkPdfAllocator() is called. |
| SkPdfNativeObject* allocObject(); |
| |
| // Allocates a buffer. It will be freed automatically when ~SkPdfAllocator() is called. |
| void* alloc(size_t bytes) { |
| void* data = malloc(bytes); |
| fHandles.push(data); |
| fSizeInBytes += bytes; |
| return data; |
| } |
| |
| // Returns the number of bytes used in this allocator. |
| size_t bytesUsed() const { |
| return fSizeInBytes; |
| } |
| |
| private: |
| SkTDArray<SkPdfNativeObject*> fHistory; |
| SkTDArray<void*> fHandles; |
| SkPdfNativeObject* fCurrent; |
| int fCurrentUsed; |
| |
| SkPdfNativeObject* allocBlock(); |
| size_t fSizeInBytes; |
| }; |
| |
| // Type of a parsed token. |
| enum SkPdfTokenType { |
| kKeyword_TokenType, |
| kObject_TokenType, |
| }; |
| |
| |
| /** \struct PdfToken |
| * |
| * Stores the result of the parsing - a keyword or an object. |
| * |
| */ |
| struct PdfToken { |
| const char* fKeyword; |
| size_t fKeywordLength; |
| SkPdfNativeObject* fObject; |
| SkPdfTokenType fType; |
| |
| PdfToken() : fKeyword(NULL), fKeywordLength(0), fObject(NULL) {} |
| }; |
| |
| /** \class SkPdfNativeTokenizer |
| * |
| * Responsible to tokenize a stream in small tokens, eityh a keyword or an object. |
| * A renderer can feed on the tokens and render a pdf. |
| * |
| */ |
| class SkPdfNativeTokenizer { |
| public: |
| SkPdfNativeTokenizer(SkPdfNativeObject* objWithStream, |
| SkPdfAllocator* allocator, SkPdfNativeDoc* doc); |
| SkPdfNativeTokenizer(const unsigned char* buffer, int len, |
| SkPdfAllocator* allocator, SkPdfNativeDoc* doc); |
| |
| virtual ~SkPdfNativeTokenizer(); |
| |
| // Reads one token. Returns false if there are no more tokens. |
| // If writeDiff is true, and a token was read, create a PNG highlighting |
| // the difference caused by this command in /tmp/log_step_by_step. |
| // If PDF_TRACE_DIFF_IN_PNG is not defined, writeDiff does nothing. |
| bool readToken(PdfToken* token, bool writeDiff = false); |
| |
| // Put back a token to be read in the nextToken read. Only one token is allowed to be put |
| // back. Must not necesaarely be the last token read. |
| void PutBack(PdfToken token); |
| |
| // Reads the inline image that is present in the stream. At this point we just consumed the ID |
| // token already. |
| SkPdfImageDictionary* readInlineImage(); |
| |
| private: |
| bool readTokenCore(PdfToken* token); |
| |
| SkPdfNativeDoc* fDoc; |
| SkPdfAllocator* fAllocator; |
| |
| const unsigned char* fUncompressedStreamStart; |
| const unsigned char* fUncompressedStream; |
| const unsigned char* fUncompressedStreamEnd; |
| |
| bool fEmpty; |
| bool fHasPutBack; |
| PdfToken fPutBack; |
| }; |
| |
| const unsigned char* nextObject(const unsigned char* start, const unsigned char* end, |
| SkPdfNativeObject* token, |
| SkPdfAllocator* allocator, |
| SkPdfNativeDoc* doc); |
| |
| #endif // SkPdfNativeTokenizer_DEFINED |