Get rid of FX_LPCSTR cast.
[pdfium.git] / core / src / fpdfapi / fpdf_parser / fpdf_parser_utility.cpp
index cc3d29c..e5e68c2 100644 (file)
-// Copyright 2014 PDFium Authors. All rights reserved.\r
-// Use of this source code is governed by a BSD-style license that can be\r
-// found in the LICENSE file.\r
\r
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
-\r
-#include "../../../include/fpdfapi/fpdf_parser.h"\r
-extern const FX_LPCSTR _PDF_CharType =\r
-    "WRRRRRRRRWWRWWRRRRRRRRRRRRRRRRRR"\r
-    "WRRRRDRRDDRNRNNDNNNNNNNNNNRRDRDR"\r
-    "RRRRRRRRRRRRRRRRRRRRRRRRRRRDRDRR"\r
-    "RRRRRRRRRRRRRRRRRRRRRRRRRRRDRDRR"\r
-    "WRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"\r
-    "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"\r
-    "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"\r
-    "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRW";\r
-#ifndef MAX_PATH\r
-#define MAX_PATH 4096\r
-#endif\r
-CPDF_SimpleParser::CPDF_SimpleParser(FX_LPCBYTE pData, FX_DWORD dwSize)\r
-{\r
-    m_pData = pData;\r
-    m_dwSize = dwSize;\r
-    m_dwCurPos = 0;\r
-}\r
-CPDF_SimpleParser::CPDF_SimpleParser(FX_BSTR str)\r
-{\r
-    m_pData = str;\r
-    m_dwSize = str.GetLength();\r
-    m_dwCurPos = 0;\r
-}\r
-void CPDF_SimpleParser::ParseWord(FX_LPCBYTE& pStart, FX_DWORD& dwSize, int& type)\r
-{\r
-    pStart = NULL;\r
-    dwSize = 0;\r
-    type = PDFWORD_EOF;\r
-    FX_BYTE ch;\r
-    char chartype;\r
-    while (1) {\r
-        if (m_dwSize <= m_dwCurPos) {\r
-            return;\r
-        }\r
-        ch = m_pData[m_dwCurPos++];\r
-        chartype = _PDF_CharType[ch];\r
-        while (chartype == 'W') {\r
-            if (m_dwSize <= m_dwCurPos) {\r
-                return;\r
-            }\r
-            ch = m_pData[m_dwCurPos++];\r
-            chartype = _PDF_CharType[ch];\r
-        }\r
-        if (ch != '%') {\r
-            break;\r
-        }\r
-        while (1) {\r
-            if (m_dwSize <= m_dwCurPos) {\r
-                return;\r
-            }\r
-            ch = m_pData[m_dwCurPos++];\r
-            if (ch == '\r' || ch == '\n') {\r
-                break;\r
-            }\r
-        }\r
-        chartype = _PDF_CharType[ch];\r
-    }\r
-    FX_DWORD start_pos = m_dwCurPos - 1;\r
-    pStart = m_pData + start_pos;\r
-    if (chartype == 'D') {\r
-        if (ch == '/') {\r
-            while (1) {\r
-                if (m_dwSize <= m_dwCurPos) {\r
-                    return;\r
-                }\r
-                ch = m_pData[m_dwCurPos++];\r
-                chartype = _PDF_CharType[ch];\r
-                if (chartype != 'R' && chartype != 'N') {\r
-                    m_dwCurPos --;\r
-                    dwSize = m_dwCurPos - start_pos;\r
-                    type = PDFWORD_NAME;\r
-                    return;\r
-                }\r
-            }\r
-        } else {\r
-            type = PDFWORD_DELIMITER;\r
-            dwSize = 1;\r
-            if (ch == '<') {\r
-                if (m_dwSize <= m_dwCurPos) {\r
-                    return;\r
-                }\r
-                ch = m_pData[m_dwCurPos++];\r
-                if (ch == '<') {\r
-                    dwSize = 2;\r
-                } else {\r
-                    m_dwCurPos --;\r
-                }\r
-            } else if (ch == '>') {\r
-                if (m_dwSize <= m_dwCurPos) {\r
-                    return;\r
-                }\r
-                ch = m_pData[m_dwCurPos++];\r
-                if (ch == '>') {\r
-                    dwSize = 2;\r
-                } else {\r
-                    m_dwCurPos --;\r
-                }\r
-            }\r
-        }\r
-        return;\r
-    }\r
-    type = PDFWORD_NUMBER;\r
-    dwSize = 1;\r
-    while (1) {\r
-        if (chartype != 'N') {\r
-            type = PDFWORD_TEXT;\r
-        }\r
-        if (m_dwSize <= m_dwCurPos) {\r
-            return;\r
-        }\r
-        ch = m_pData[m_dwCurPos++];\r
-        chartype = _PDF_CharType[ch];\r
-        if (chartype == 'D' || chartype == 'W') {\r
-            m_dwCurPos --;\r
-            break;\r
-        }\r
-        dwSize ++;\r
-    }\r
-}\r
-CFX_ByteStringC CPDF_SimpleParser::GetWord()\r
-{\r
-    FX_LPCBYTE pStart;\r
-    FX_DWORD dwSize;\r
-    int type;\r
-    ParseWord(pStart, dwSize, type);\r
-    if (dwSize == 1 && pStart[0] == '<') {\r
-        while (m_dwCurPos < m_dwSize && m_pData[m_dwCurPos] != '>') {\r
-            m_dwCurPos ++;\r
-        }\r
-        if (m_dwCurPos < m_dwSize) {\r
-            m_dwCurPos ++;\r
-        }\r
-        return CFX_ByteStringC(pStart, (FX_STRSIZE)(m_dwCurPos - (pStart - m_pData)));\r
-    } else if (dwSize == 1 && pStart[0] == '(') {\r
-        int level = 1;\r
-        while (m_dwCurPos < m_dwSize) {\r
-            if (m_pData[m_dwCurPos] == ')') {\r
-                level --;\r
-                if (level == 0) {\r
-                    break;\r
-                }\r
-            }\r
-            if (m_pData[m_dwCurPos] == '\\') {\r
-                if (m_dwSize <= m_dwCurPos) {\r
-                    break;\r
-                }\r
-                m_dwCurPos ++;\r
-            } else if (m_pData[m_dwCurPos] == '(') {\r
-                level ++;\r
-            }\r
-            if (m_dwSize <= m_dwCurPos) {\r
-                break;\r
-            }\r
-            m_dwCurPos ++;\r
-        }\r
-        if (m_dwCurPos < m_dwSize) {\r
-            m_dwCurPos ++;\r
-        }\r
-        return CFX_ByteStringC(pStart, (FX_STRSIZE)(m_dwCurPos - (pStart - m_pData)));\r
-    }\r
-    return CFX_ByteStringC(pStart, dwSize);\r
-}\r
-FX_BOOL CPDF_SimpleParser::SearchToken(FX_BSTR token)\r
-{\r
-    int token_len = token.GetLength();\r
-    while (m_dwCurPos < m_dwSize - token_len) {\r
-        if (FXSYS_memcmp32(m_pData + m_dwCurPos, token, token_len) == 0) {\r
-            break;\r
-        }\r
-        m_dwCurPos ++;\r
-    }\r
-    if (m_dwCurPos == m_dwSize - token_len) {\r
-        return FALSE;\r
-    }\r
-    m_dwCurPos += token_len;\r
-    return TRUE;\r
-}\r
-FX_BOOL CPDF_SimpleParser::SkipWord(FX_BSTR token)\r
-{\r
-    while (1) {\r
-        CFX_ByteStringC word = GetWord();\r
-        if (word.IsEmpty()) {\r
-            return FALSE;\r
-        }\r
-        if (word == token) {\r
-            return TRUE;\r
-        }\r
-    }\r
-    return FALSE;\r
-}\r
-FX_BOOL CPDF_SimpleParser::FindTagPair(FX_BSTR start_token, FX_BSTR end_token,\r
-                                       FX_DWORD& start_pos, FX_DWORD& end_pos)\r
-{\r
-    if (!start_token.IsEmpty()) {\r
-        if (!SkipWord(start_token)) {\r
-            return FALSE;\r
-        }\r
-        start_pos = m_dwCurPos;\r
-    }\r
-    while (1) {\r
-        end_pos = m_dwCurPos;\r
-        CFX_ByteStringC word = GetWord();\r
-        if (word.IsEmpty()) {\r
-            return FALSE;\r
-        }\r
-        if (word == end_token) {\r
-            return TRUE;\r
-        }\r
-    }\r
-    return FALSE;\r
-}\r
-FX_BOOL CPDF_SimpleParser::FindTagParam(FX_BSTR token, int nParams)\r
-{\r
-    nParams ++;\r
-    FX_DWORD* pBuf = FX_Alloc(FX_DWORD, nParams);\r
-    int buf_index = 0;\r
-    int buf_count = 0;\r
-    while (1) {\r
-        pBuf[buf_index++] = m_dwCurPos;\r
-        if (buf_index == nParams) {\r
-            buf_index = 0;\r
-        }\r
-        buf_count ++;\r
-        if (buf_count > nParams) {\r
-            buf_count = nParams;\r
-        }\r
-        CFX_ByteStringC word = GetWord();\r
-        if (word.IsEmpty()) {\r
-            FX_Free(pBuf);\r
-            return FALSE;\r
-        }\r
-        if (word == token) {\r
-            if (buf_count < nParams) {\r
-                continue;\r
-            }\r
-            m_dwCurPos = pBuf[buf_index];\r
-            FX_Free(pBuf);\r
-            return TRUE;\r
-        }\r
-    }\r
-    return FALSE;\r
-}\r
-static int _hex2dec(char ch)\r
-{\r
-    if (ch >= '0' && ch <= '9') {\r
-        return ch - '0';\r
-    }\r
-    if (ch >= 'a' && ch <= 'f') {\r
-        return ch - 'a' + 10;\r
-    }\r
-    if (ch >= 'A' && ch <= 'F') {\r
-        return ch - 'A' + 10;\r
-    }\r
-    return 0;\r
-}\r
-CFX_ByteString PDF_NameDecode(FX_BSTR bstr)\r
-{\r
-    int size = bstr.GetLength();\r
-    FX_LPCSTR pSrc = bstr.GetCStr();\r
-    if (FXSYS_memchr(pSrc, '#', size) == NULL) {\r
-        return bstr;\r
-    }\r
-    CFX_ByteString result;\r
-    FX_LPSTR pDestStart = result.GetBuffer(size);\r
-    FX_LPSTR pDest = pDestStart;\r
-    for (int i = 0; i < size; i ++) {\r
-        if (pSrc[i] == '#' && i < size - 2) {\r
-            *pDest ++ = _hex2dec(pSrc[i + 1]) * 16 + _hex2dec(pSrc[i + 2]);\r
-            i += 2;\r
-        } else {\r
-            *pDest ++ = pSrc[i];\r
-        }\r
-    }\r
-    result.ReleaseBuffer((FX_STRSIZE)(pDest - pDestStart));\r
-    return result;\r
-}\r
-CFX_ByteString PDF_NameDecode(const CFX_ByteString& orig)\r
-{\r
-    if (FXSYS_memchr((FX_LPCSTR)orig, '#', orig.GetLength()) == NULL) {\r
-        return orig;\r
-    }\r
-    return PDF_NameDecode(CFX_ByteStringC(orig));\r
-}\r
-CFX_ByteString PDF_NameEncode(const CFX_ByteString& orig)\r
-{\r
-    FX_LPBYTE src_buf = (FX_LPBYTE)(FX_LPCSTR)orig;\r
-    int src_len = orig.GetLength();\r
-    int dest_len = 0;\r
-    int i;\r
-    for (i = 0; i < src_len; i ++) {\r
-        FX_BYTE ch = src_buf[i];\r
-        if (ch >= 0x80 || _PDF_CharType[ch] == 'W' || ch == '#' ||\r
-                _PDF_CharType[ch] == 'D') {\r
-            dest_len += 3;\r
-        } else {\r
-            dest_len ++;\r
-        }\r
-    }\r
-    if (dest_len == src_len) {\r
-        return orig;\r
-    }\r
-    CFX_ByteString res;\r
-    FX_LPSTR dest_buf = res.GetBuffer(dest_len);\r
-    dest_len = 0;\r
-    for (i = 0; i < src_len; i ++) {\r
-        FX_BYTE ch = src_buf[i];\r
-        if (ch >= 0x80 || _PDF_CharType[ch] == 'W' || ch == '#' ||\r
-                _PDF_CharType[ch] == 'D') {\r
-            dest_buf[dest_len++] = '#';\r
-            dest_buf[dest_len++] = "0123456789ABCDEF"[ch / 16];\r
-            dest_buf[dest_len++] = "0123456789ABCDEF"[ch % 16];\r
-        } else {\r
-            dest_buf[dest_len++] = ch;\r
-        }\r
-    }\r
-    dest_buf[dest_len] = 0;\r
-    res.ReleaseBuffer();\r
-    return res;\r
-}\r
-CFX_ByteTextBuf& operator << (CFX_ByteTextBuf& buf, const CPDF_Object* pObj)\r
-{\r
-    if (pObj == NULL) {\r
-        buf << FX_BSTRC(" null");\r
-        return buf;\r
-    }\r
-    switch (pObj->GetType()) {\r
-        case PDFOBJ_NULL:\r
-            buf << FX_BSTRC(" null");\r
-            break;\r
-        case PDFOBJ_BOOLEAN:\r
-        case PDFOBJ_NUMBER:\r
-            buf << " " << pObj->GetString();\r
-            break;\r
-        case PDFOBJ_STRING: {\r
-                CFX_ByteString str = pObj->GetString();\r
-                FX_BOOL bHex = ((CPDF_String*)pObj)->IsHex();\r
-                buf << PDF_EncodeString(str, bHex);\r
-                break;\r
-            }\r
-        case PDFOBJ_NAME: {\r
-                CFX_ByteString str = pObj->GetString();\r
-                buf << FX_BSTRC("/") << PDF_NameEncode(str);\r
-                break;\r
-            }\r
-        case PDFOBJ_REFERENCE: {\r
-                CPDF_Reference* p = (CPDF_Reference*)pObj;\r
-                buf << " " << p->GetRefObjNum() << FX_BSTRC(" 0 R ");\r
-                break;\r
-            }\r
-        case PDFOBJ_ARRAY: {\r
-                CPDF_Array* p = (CPDF_Array*)pObj;\r
-                buf << FX_BSTRC("[");\r
-                for (FX_DWORD i = 0; i < p->GetCount(); i ++) {\r
-                    CPDF_Object* pElement = p->GetElement(i);\r
-                    if (pElement->GetObjNum()) {\r
-                        buf << " " << pElement->GetObjNum() << FX_BSTRC(" 0 R");\r
-                    } else {\r
-                        buf << pElement;\r
-                    }\r
-                }\r
-                buf << FX_BSTRC("]");\r
-                break;\r
-            }\r
-        case PDFOBJ_DICTIONARY: {\r
-                CPDF_Dictionary* p = (CPDF_Dictionary*)pObj;\r
-                buf << FX_BSTRC("<<");\r
-                FX_POSITION pos = p->GetStartPos();\r
-                while (pos) {\r
-                    CFX_ByteString key;\r
-                    CPDF_Object* pValue = p->GetNextElement(pos, key);\r
-                    buf << FX_BSTRC("/") << PDF_NameEncode(key);\r
-                    if (pValue->GetObjNum()) {\r
-                        buf << " " << pValue->GetObjNum() << FX_BSTRC(" 0 R ");\r
-                    } else {\r
-                        buf << pValue;\r
-                    }\r
-                }\r
-                buf << FX_BSTRC(">>");\r
-                break;\r
-            }\r
-        case PDFOBJ_STREAM: {\r
-                CPDF_Stream* p = (CPDF_Stream*)pObj;\r
-                buf << p->GetDict() << FX_BSTRC("stream\r\n");\r
-                CPDF_StreamAcc acc;\r
-                acc.LoadAllData(p, TRUE);\r
-                buf.AppendBlock(acc.GetData(), acc.GetSize());\r
-                buf << FX_BSTRC("\r\nendstream");\r
-                break;\r
-            }\r
-        default:\r
-            ASSERT(FALSE);\r
-            break;\r
-    }\r
-    return buf;\r
-}\r
-FX_FLOAT PDF_ClipFloat(FX_FLOAT f)\r
-{\r
-    if (f < 0) {\r
-        return 0;\r
-    }\r
-    if (f > 1.0f) {\r
-        return 1.0f;\r
-    }\r
-    return f;\r
-}\r
-static CPDF_Object* SearchNumberNode(CPDF_Dictionary* pNode, int num)\r
-{\r
-    CPDF_Array* pLimits = pNode->GetArray("Limits");\r
-    if (pLimits && (num < pLimits->GetInteger(0) || num > pLimits->GetInteger(1))) {\r
-        return NULL;\r
-    }\r
-    CPDF_Array* pNumbers = pNode->GetArray("Nums");\r
-    if (pNumbers) {\r
-        FX_DWORD dwCount = pNumbers->GetCount() / 2;\r
-        for (FX_DWORD i = 0; i < dwCount; i ++) {\r
-            int index = pNumbers->GetInteger(i * 2);\r
-            if (num == index) {\r
-                return pNumbers->GetElementValue(i * 2 + 1);\r
-            }\r
-            if (index > num) {\r
-                break;\r
-            }\r
-        }\r
-        return NULL;\r
-    }\r
-    CPDF_Array* pKids = pNode->GetArray("Kids");\r
-    if (pKids == NULL) {\r
-        return NULL;\r
-    }\r
-    for (FX_DWORD i = 0; i < pKids->GetCount(); i ++) {\r
-        CPDF_Dictionary* pKid = pKids->GetDict(i);\r
-        if (pKid == NULL) {\r
-            continue;\r
-        }\r
-        CPDF_Object* pFound = SearchNumberNode(pKid, num);\r
-        if (pFound) {\r
-            return pFound;\r
-        }\r
-    }\r
-    return NULL;\r
-}\r
-CPDF_Object* CPDF_NumberTree::LookupValue(int num)\r
-{\r
-    return SearchNumberNode(m_pRoot, num);\r
-}\r
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "../../../include/fpdfapi/fpdf_parser.h"
+extern const FX_LPCSTR _PDF_CharType =
+    "WRRRRRRRRWWRWWRRRRRRRRRRRRRRRRRR"
+    "WRRRRDRRDDRNRNNDNNNNNNNNNNRRDRDR"
+    "RRRRRRRRRRRRRRRRRRRRRRRRRRRDRDRR"
+    "RRRRRRRRRRRRRRRRRRRRRRRRRRRDRDRR"
+    "WRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"
+    "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"
+    "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"
+    "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRW";
+#ifndef MAX_PATH
+#define MAX_PATH 4096
+#endif
+CPDF_SimpleParser::CPDF_SimpleParser(FX_LPCBYTE pData, FX_DWORD dwSize)
+{
+    m_pData = pData;
+    m_dwSize = dwSize;
+    m_dwCurPos = 0;
+}
+CPDF_SimpleParser::CPDF_SimpleParser(FX_BSTR str)
+{
+    m_pData = str;
+    m_dwSize = str.GetLength();
+    m_dwCurPos = 0;
+}
+void CPDF_SimpleParser::ParseWord(FX_LPCBYTE& pStart, FX_DWORD& dwSize, int& type)
+{
+    pStart = NULL;
+    dwSize = 0;
+    type = PDFWORD_EOF;
+    FX_BYTE ch;
+    char chartype;
+    while (1) {
+        if (m_dwSize <= m_dwCurPos) {
+            return;
+        }
+        ch = m_pData[m_dwCurPos++];
+        chartype = _PDF_CharType[ch];
+        while (chartype == 'W') {
+            if (m_dwSize <= m_dwCurPos) {
+                return;
+            }
+            ch = m_pData[m_dwCurPos++];
+            chartype = _PDF_CharType[ch];
+        }
+        if (ch != '%') {
+            break;
+        }
+        while (1) {
+            if (m_dwSize <= m_dwCurPos) {
+                return;
+            }
+            ch = m_pData[m_dwCurPos++];
+            if (ch == '\r' || ch == '\n') {
+                break;
+            }
+        }
+        chartype = _PDF_CharType[ch];
+    }
+    FX_DWORD start_pos = m_dwCurPos - 1;
+    pStart = m_pData + start_pos;
+    if (chartype == 'D') {
+        if (ch == '/') {
+            while (1) {
+                if (m_dwSize <= m_dwCurPos) {
+                    return;
+                }
+                ch = m_pData[m_dwCurPos++];
+                chartype = _PDF_CharType[ch];
+                if (chartype != 'R' && chartype != 'N') {
+                    m_dwCurPos --;
+                    dwSize = m_dwCurPos - start_pos;
+                    type = PDFWORD_NAME;
+                    return;
+                }
+            }
+        } else {
+            type = PDFWORD_DELIMITER;
+            dwSize = 1;
+            if (ch == '<') {
+                if (m_dwSize <= m_dwCurPos) {
+                    return;
+                }
+                ch = m_pData[m_dwCurPos++];
+                if (ch == '<') {
+                    dwSize = 2;
+                } else {
+                    m_dwCurPos --;
+                }
+            } else if (ch == '>') {
+                if (m_dwSize <= m_dwCurPos) {
+                    return;
+                }
+                ch = m_pData[m_dwCurPos++];
+                if (ch == '>') {
+                    dwSize = 2;
+                } else {
+                    m_dwCurPos --;
+                }
+            }
+        }
+        return;
+    }
+    type = PDFWORD_NUMBER;
+    dwSize = 1;
+    while (1) {
+        if (chartype != 'N') {
+            type = PDFWORD_TEXT;
+        }
+        if (m_dwSize <= m_dwCurPos) {
+            return;
+        }
+        ch = m_pData[m_dwCurPos++];
+        chartype = _PDF_CharType[ch];
+        if (chartype == 'D' || chartype == 'W') {
+            m_dwCurPos --;
+            break;
+        }
+        dwSize ++;
+    }
+}
+CFX_ByteStringC CPDF_SimpleParser::GetWord()
+{
+    FX_LPCBYTE pStart;
+    FX_DWORD dwSize;
+    int type;
+    ParseWord(pStart, dwSize, type);
+    if (dwSize == 1 && pStart[0] == '<') {
+        while (m_dwCurPos < m_dwSize && m_pData[m_dwCurPos] != '>') {
+            m_dwCurPos ++;
+        }
+        if (m_dwCurPos < m_dwSize) {
+            m_dwCurPos ++;
+        }
+        return CFX_ByteStringC(pStart, (FX_STRSIZE)(m_dwCurPos - (pStart - m_pData)));
+    } else if (dwSize == 1 && pStart[0] == '(') {
+        int level = 1;
+        while (m_dwCurPos < m_dwSize) {
+            if (m_pData[m_dwCurPos] == ')') {
+                level --;
+                if (level == 0) {
+                    break;
+                }
+            }
+            if (m_pData[m_dwCurPos] == '\\') {
+                if (m_dwSize <= m_dwCurPos) {
+                    break;
+                }
+                m_dwCurPos ++;
+            } else if (m_pData[m_dwCurPos] == '(') {
+                level ++;
+            }
+            if (m_dwSize <= m_dwCurPos) {
+                break;
+            }
+            m_dwCurPos ++;
+        }
+        if (m_dwCurPos < m_dwSize) {
+            m_dwCurPos ++;
+        }
+        return CFX_ByteStringC(pStart, (FX_STRSIZE)(m_dwCurPos - (pStart - m_pData)));
+    }
+    return CFX_ByteStringC(pStart, dwSize);
+}
+FX_BOOL CPDF_SimpleParser::SearchToken(FX_BSTR token)
+{
+    int token_len = token.GetLength();
+    while (m_dwCurPos < m_dwSize - token_len) {
+        if (FXSYS_memcmp32(m_pData + m_dwCurPos, token, token_len) == 0) {
+            break;
+        }
+        m_dwCurPos ++;
+    }
+    if (m_dwCurPos == m_dwSize - token_len) {
+        return FALSE;
+    }
+    m_dwCurPos += token_len;
+    return TRUE;
+}
+FX_BOOL CPDF_SimpleParser::SkipWord(FX_BSTR token)
+{
+    while (1) {
+        CFX_ByteStringC word = GetWord();
+        if (word.IsEmpty()) {
+            return FALSE;
+        }
+        if (word == token) {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+FX_BOOL CPDF_SimpleParser::FindTagPair(FX_BSTR start_token, FX_BSTR end_token,
+                                       FX_DWORD& start_pos, FX_DWORD& end_pos)
+{
+    if (!start_token.IsEmpty()) {
+        if (!SkipWord(start_token)) {
+            return FALSE;
+        }
+        start_pos = m_dwCurPos;
+    }
+    while (1) {
+        end_pos = m_dwCurPos;
+        CFX_ByteStringC word = GetWord();
+        if (word.IsEmpty()) {
+            return FALSE;
+        }
+        if (word == end_token) {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+FX_BOOL CPDF_SimpleParser::FindTagParam(FX_BSTR token, int nParams)
+{
+    nParams ++;
+    FX_DWORD* pBuf = FX_Alloc(FX_DWORD, nParams);
+    int buf_index = 0;
+    int buf_count = 0;
+    while (1) {
+        pBuf[buf_index++] = m_dwCurPos;
+        if (buf_index == nParams) {
+            buf_index = 0;
+        }
+        buf_count ++;
+        if (buf_count > nParams) {
+            buf_count = nParams;
+        }
+        CFX_ByteStringC word = GetWord();
+        if (word.IsEmpty()) {
+            FX_Free(pBuf);
+            return FALSE;
+        }
+        if (word == token) {
+            if (buf_count < nParams) {
+                continue;
+            }
+            m_dwCurPos = pBuf[buf_index];
+            FX_Free(pBuf);
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+static int _hex2dec(char ch)
+{
+    if (ch >= '0' && ch <= '9') {
+        return ch - '0';
+    }
+    if (ch >= 'a' && ch <= 'f') {
+        return ch - 'a' + 10;
+    }
+    if (ch >= 'A' && ch <= 'F') {
+        return ch - 'A' + 10;
+    }
+    return 0;
+}
+CFX_ByteString PDF_NameDecode(FX_BSTR bstr)
+{
+    int size = bstr.GetLength();
+    FX_LPCSTR pSrc = bstr.GetCStr();
+    if (FXSYS_memchr(pSrc, '#', size) == NULL) {
+        return bstr;
+    }
+    CFX_ByteString result;
+    FX_LPSTR pDestStart = result.GetBuffer(size);
+    FX_LPSTR pDest = pDestStart;
+    for (int i = 0; i < size; i ++) {
+        if (pSrc[i] == '#' && i < size - 2) {
+            *pDest ++ = _hex2dec(pSrc[i + 1]) * 16 + _hex2dec(pSrc[i + 2]);
+            i += 2;
+        } else {
+            *pDest ++ = pSrc[i];
+        }
+    }
+    result.ReleaseBuffer((FX_STRSIZE)(pDest - pDestStart));
+    return result;
+}
+CFX_ByteString PDF_NameDecode(const CFX_ByteString& orig)
+{
+    if (FXSYS_memchr(orig.c_str(), '#', orig.GetLength()) == NULL) {
+        return orig;
+    }
+    return PDF_NameDecode(CFX_ByteStringC(orig));
+}
+CFX_ByteString PDF_NameEncode(const CFX_ByteString& orig)
+{
+    FX_LPBYTE src_buf = (FX_LPBYTE)orig.c_str();
+    int src_len = orig.GetLength();
+    int dest_len = 0;
+    int i;
+    for (i = 0; i < src_len; i ++) {
+        FX_BYTE ch = src_buf[i];
+        if (ch >= 0x80 || _PDF_CharType[ch] == 'W' || ch == '#' ||
+                _PDF_CharType[ch] == 'D') {
+            dest_len += 3;
+        } else {
+            dest_len ++;
+        }
+    }
+    if (dest_len == src_len) {
+        return orig;
+    }
+    CFX_ByteString res;
+    FX_LPSTR dest_buf = res.GetBuffer(dest_len);
+    dest_len = 0;
+    for (i = 0; i < src_len; i ++) {
+        FX_BYTE ch = src_buf[i];
+        if (ch >= 0x80 || _PDF_CharType[ch] == 'W' || ch == '#' ||
+                _PDF_CharType[ch] == 'D') {
+            dest_buf[dest_len++] = '#';
+            dest_buf[dest_len++] = "0123456789ABCDEF"[ch / 16];
+            dest_buf[dest_len++] = "0123456789ABCDEF"[ch % 16];
+        } else {
+            dest_buf[dest_len++] = ch;
+        }
+    }
+    dest_buf[dest_len] = 0;
+    res.ReleaseBuffer();
+    return res;
+}
+CFX_ByteTextBuf& operator << (CFX_ByteTextBuf& buf, const CPDF_Object* pObj)
+{
+    if (pObj == NULL) {
+        buf << FX_BSTRC(" null");
+        return buf;
+    }
+    switch (pObj->GetType()) {
+        case PDFOBJ_NULL:
+            buf << FX_BSTRC(" null");
+            break;
+        case PDFOBJ_BOOLEAN:
+        case PDFOBJ_NUMBER:
+            buf << " " << pObj->GetString();
+            break;
+        case PDFOBJ_STRING: {
+                CFX_ByteString str = pObj->GetString();
+                FX_BOOL bHex = ((CPDF_String*)pObj)->IsHex();
+                buf << PDF_EncodeString(str, bHex);
+                break;
+            }
+        case PDFOBJ_NAME: {
+                CFX_ByteString str = pObj->GetString();
+                buf << FX_BSTRC("/") << PDF_NameEncode(str);
+                break;
+            }
+        case PDFOBJ_REFERENCE: {
+                CPDF_Reference* p = (CPDF_Reference*)pObj;
+                buf << " " << p->GetRefObjNum() << FX_BSTRC(" 0 R ");
+                break;
+            }
+        case PDFOBJ_ARRAY: {
+                CPDF_Array* p = (CPDF_Array*)pObj;
+                buf << FX_BSTRC("[");
+                for (FX_DWORD i = 0; i < p->GetCount(); i ++) {
+                    CPDF_Object* pElement = p->GetElement(i);
+                    if (pElement->GetObjNum()) {
+                        buf << " " << pElement->GetObjNum() << FX_BSTRC(" 0 R");
+                    } else {
+                        buf << pElement;
+                    }
+                }
+                buf << FX_BSTRC("]");
+                break;
+            }
+        case PDFOBJ_DICTIONARY: {
+                CPDF_Dictionary* p = (CPDF_Dictionary*)pObj;
+                buf << FX_BSTRC("<<");
+                FX_POSITION pos = p->GetStartPos();
+                while (pos) {
+                    CFX_ByteString key;
+                    CPDF_Object* pValue = p->GetNextElement(pos, key);
+                    buf << FX_BSTRC("/") << PDF_NameEncode(key);
+                    if (pValue->GetObjNum()) {
+                        buf << " " << pValue->GetObjNum() << FX_BSTRC(" 0 R ");
+                    } else {
+                        buf << pValue;
+                    }
+                }
+                buf << FX_BSTRC(">>");
+                break;
+            }
+        case PDFOBJ_STREAM: {
+                CPDF_Stream* p = (CPDF_Stream*)pObj;
+                buf << p->GetDict() << FX_BSTRC("stream\r\n");
+                CPDF_StreamAcc acc;
+                acc.LoadAllData(p, TRUE);
+                buf.AppendBlock(acc.GetData(), acc.GetSize());
+                buf << FX_BSTRC("\r\nendstream");
+                break;
+            }
+        default:
+            ASSERT(FALSE);
+            break;
+    }
+    return buf;
+}
+FX_FLOAT PDF_ClipFloat(FX_FLOAT f)
+{
+    if (f < 0) {
+        return 0;
+    }
+    if (f > 1.0f) {
+        return 1.0f;
+    }
+    return f;
+}
+static CPDF_Object* SearchNumberNode(CPDF_Dictionary* pNode, int num)
+{
+    CPDF_Array* pLimits = pNode->GetArray("Limits");
+    if (pLimits && (num < pLimits->GetInteger(0) || num > pLimits->GetInteger(1))) {
+        return NULL;
+    }
+    CPDF_Array* pNumbers = pNode->GetArray("Nums");
+    if (pNumbers) {
+        FX_DWORD dwCount = pNumbers->GetCount() / 2;
+        for (FX_DWORD i = 0; i < dwCount; i ++) {
+            int index = pNumbers->GetInteger(i * 2);
+            if (num == index) {
+                return pNumbers->GetElementValue(i * 2 + 1);
+            }
+            if (index > num) {
+                break;
+            }
+        }
+        return NULL;
+    }
+    CPDF_Array* pKids = pNode->GetArray("Kids");
+    if (pKids == NULL) {
+        return NULL;
+    }
+    for (FX_DWORD i = 0; i < pKids->GetCount(); i ++) {
+        CPDF_Dictionary* pKid = pKids->GetDict(i);
+        if (pKid == NULL) {
+            continue;
+        }
+        CPDF_Object* pFound = SearchNumberNode(pKid, num);
+        if (pFound) {
+            return pFound;
+        }
+    }
+    return NULL;
+}
+CPDF_Object* CPDF_NumberTree::LookupValue(int num)
+{
+    return SearchNumberNode(m_pRoot, num);
+}