FX Bool considered harmful, part 3
[pdfium.git] / core / src / fpdfapi / fpdf_parser / fpdf_parser_utility.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "../../../include/fpdfapi/fpdf_parser.h"
8 const char PDF_CharType[256] = {
9   //NUL  SOH  STX  ETX  EOT  ENQ  ACK  BEL  BS   HT   LF   VT   FF   CR   SO   SI
10     'W', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'W', 'W', 'R', 'W', 'W', 'R', 'R',
11
12   //DLE  DC1  DC2  DC3  DC4  NAK  SYN  ETB  CAN  EM   SUB  ESC  FS   GS   RS   US
13     'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R',
14
15   //SP    !    "    #    $    %    &    ยด    (    )    *    +    ,    -    .    /
16     'W', 'R', 'R', 'R', 'R', 'D', 'R', 'R', 'D', 'D', 'R', 'N', 'R', 'N', 'N', 'D',
17
18   // 0    1    2    3    4    5    6    7    8    9    :    ;    <    =    >    ?
19     'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'R', 'R', 'D', 'R', 'D', 'R',
20
21   // @    A    B    C    D    E    F    G    H    I    J    K    L    M    N    O
22     'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R',
23
24   // P    Q    R    S    T    U    V    W    X    Y    Z    [    \    ]    ^    _
25     'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'D', 'R', 'D', 'R', 'R',
26
27   // `    a    b    c    d    e    f    g    h    i    j    k    l    m    n    o
28     'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R',
29
30   // p    q    r    s    t    u    v    w    x    y    z    {    |    }    ~   DEL
31     'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'D', 'R', 'D', 'R', 'R',
32
33     'W', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R',
34     'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R',
35     'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R',
36     'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R',
37     'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R',
38     'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R',
39     'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R',
40     'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'W'
41 };
42
43 #ifndef MAX_PATH
44 #define MAX_PATH 4096
45 #endif
46 CPDF_SimpleParser::CPDF_SimpleParser(const uint8_t* pData, FX_DWORD dwSize)
47 {
48     m_pData = pData;
49     m_dwSize = dwSize;
50     m_dwCurPos = 0;
51 }
52 CPDF_SimpleParser::CPDF_SimpleParser(const CFX_ByteStringC& str)
53 {
54     m_pData = str.GetPtr();
55     m_dwSize = str.GetLength();
56     m_dwCurPos = 0;
57 }
58 void CPDF_SimpleParser::ParseWord(const uint8_t*& pStart, FX_DWORD& dwSize, int& type)
59 {
60     pStart = NULL;
61     dwSize = 0;
62     type = PDFWORD_EOF;
63     uint8_t ch;
64     char chartype;
65     while (1) {
66         if (m_dwSize <= m_dwCurPos) {
67             return;
68         }
69         ch = m_pData[m_dwCurPos++];
70         chartype = PDF_CharType[ch];
71         while (chartype == 'W') {
72             if (m_dwSize <= m_dwCurPos) {
73                 return;
74             }
75             ch = m_pData[m_dwCurPos++];
76             chartype = PDF_CharType[ch];
77         }
78         if (ch != '%') {
79             break;
80         }
81         while (1) {
82             if (m_dwSize <= m_dwCurPos) {
83                 return;
84             }
85             ch = m_pData[m_dwCurPos++];
86             if (ch == '\r' || ch == '\n') {
87                 break;
88             }
89         }
90         chartype = PDF_CharType[ch];
91     }
92     FX_DWORD start_pos = m_dwCurPos - 1;
93     pStart = m_pData + start_pos;
94     if (chartype == 'D') {
95         if (ch == '/') {
96             while (1) {
97                 if (m_dwSize <= m_dwCurPos) {
98                     return;
99                 }
100                 ch = m_pData[m_dwCurPos++];
101                 chartype = PDF_CharType[ch];
102                 if (chartype != 'R' && chartype != 'N') {
103                     m_dwCurPos --;
104                     dwSize = m_dwCurPos - start_pos;
105                     type = PDFWORD_NAME;
106                     return;
107                 }
108             }
109         } else {
110             type = PDFWORD_DELIMITER;
111             dwSize = 1;
112             if (ch == '<') {
113                 if (m_dwSize <= m_dwCurPos) {
114                     return;
115                 }
116                 ch = m_pData[m_dwCurPos++];
117                 if (ch == '<') {
118                     dwSize = 2;
119                 } else {
120                     m_dwCurPos --;
121                 }
122             } else if (ch == '>') {
123                 if (m_dwSize <= m_dwCurPos) {
124                     return;
125                 }
126                 ch = m_pData[m_dwCurPos++];
127                 if (ch == '>') {
128                     dwSize = 2;
129                 } else {
130                     m_dwCurPos --;
131                 }
132             }
133         }
134         return;
135     }
136     type = PDFWORD_NUMBER;
137     dwSize = 1;
138     while (1) {
139         if (chartype != 'N') {
140             type = PDFWORD_TEXT;
141         }
142         if (m_dwSize <= m_dwCurPos) {
143             return;
144         }
145         ch = m_pData[m_dwCurPos++];
146         chartype = PDF_CharType[ch];
147         if (chartype == 'D' || chartype == 'W') {
148             m_dwCurPos --;
149             break;
150         }
151         dwSize ++;
152     }
153 }
154 CFX_ByteStringC CPDF_SimpleParser::GetWord()
155 {
156     const uint8_t* pStart;
157     FX_DWORD dwSize;
158     int type;
159     ParseWord(pStart, dwSize, type);
160     if (dwSize == 1 && pStart[0] == '<') {
161         while (m_dwCurPos < m_dwSize && m_pData[m_dwCurPos] != '>') {
162             m_dwCurPos ++;
163         }
164         if (m_dwCurPos < m_dwSize) {
165             m_dwCurPos ++;
166         }
167         return CFX_ByteStringC(pStart, (FX_STRSIZE)(m_dwCurPos - (pStart - m_pData)));
168     }
169     if (dwSize == 1 && pStart[0] == '(') {
170         int level = 1;
171         while (m_dwCurPos < m_dwSize) {
172             if (m_pData[m_dwCurPos] == ')') {
173                 level --;
174                 if (level == 0) {
175                     break;
176                 }
177             }
178             if (m_pData[m_dwCurPos] == '\\') {
179                 if (m_dwSize <= m_dwCurPos) {
180                     break;
181                 }
182                 m_dwCurPos ++;
183             } else if (m_pData[m_dwCurPos] == '(') {
184                 level ++;
185             }
186             if (m_dwSize <= m_dwCurPos) {
187                 break;
188             }
189             m_dwCurPos ++;
190         }
191         if (m_dwCurPos < m_dwSize) {
192             m_dwCurPos ++;
193         }
194         return CFX_ByteStringC(pStart, (FX_STRSIZE)(m_dwCurPos - (pStart - m_pData)));
195     }
196     return CFX_ByteStringC(pStart, dwSize);
197 }
198 bool CPDF_SimpleParser::SearchToken(const CFX_ByteStringC& token)
199 {
200     int token_len = token.GetLength();
201     while (m_dwCurPos < m_dwSize - token_len) {
202         if (FXSYS_memcmp(m_pData + m_dwCurPos, token.GetPtr(), token_len) == 0) {
203             break;
204         }
205         m_dwCurPos ++;
206     }
207     if (m_dwCurPos == m_dwSize - token_len) {
208         return false;
209     }
210     m_dwCurPos += token_len;
211     return true;
212 }
213 bool CPDF_SimpleParser::SkipWord(const CFX_ByteStringC& token)
214 {
215     while (1) {
216         CFX_ByteStringC word = GetWord();
217         if (word.IsEmpty()) {
218             return false;
219         }
220         if (word == token) {
221             return true;
222         }
223     }
224     return false;
225 }
226 bool CPDF_SimpleParser::FindTagPair(const CFX_ByteStringC& start_token, const CFX_ByteStringC& end_token,
227                                        FX_DWORD& start_pos, FX_DWORD& end_pos)
228 {
229     if (!start_token.IsEmpty()) {
230         if (!SkipWord(start_token)) {
231             return false;
232         }
233         start_pos = m_dwCurPos;
234     }
235     while (1) {
236         end_pos = m_dwCurPos;
237         CFX_ByteStringC word = GetWord();
238         if (word.IsEmpty()) {
239             return false;
240         }
241         if (word == end_token) {
242             return true;
243         }
244     }
245     return false;
246 }
247 bool CPDF_SimpleParser::FindTagParam(const CFX_ByteStringC& token, int nParams)
248 {
249     nParams ++;
250     FX_DWORD* pBuf = FX_Alloc(FX_DWORD, nParams);
251     int buf_index = 0;
252     int buf_count = 0;
253     while (1) {
254         pBuf[buf_index++] = m_dwCurPos;
255         if (buf_index == nParams) {
256             buf_index = 0;
257         }
258         buf_count ++;
259         if (buf_count > nParams) {
260             buf_count = nParams;
261         }
262         CFX_ByteStringC word = GetWord();
263         if (word.IsEmpty()) {
264             FX_Free(pBuf);
265             return false;
266         }
267         if (word == token) {
268             if (buf_count < nParams) {
269                 continue;
270             }
271             m_dwCurPos = pBuf[buf_index];
272             FX_Free(pBuf);
273             return true;
274         }
275     }
276     return false;
277 }
278 static int _hex2dec(char ch)
279 {
280     if (ch >= '0' && ch <= '9') {
281         return ch - '0';
282     }
283     if (ch >= 'a' && ch <= 'f') {
284         return ch - 'a' + 10;
285     }
286     if (ch >= 'A' && ch <= 'F') {
287         return ch - 'A' + 10;
288     }
289     return 0;
290 }
291 CFX_ByteString PDF_NameDecode(const CFX_ByteStringC& bstr)
292 {
293     int size = bstr.GetLength();
294     const FX_CHAR* pSrc = bstr.GetCStr();
295     if (FXSYS_memchr(pSrc, '#', size) == NULL) {
296         return bstr;
297     }
298     CFX_ByteString result;
299     FX_CHAR* pDestStart = result.GetBuffer(size);
300     FX_CHAR* pDest = pDestStart;
301     for (int i = 0; i < size; i ++) {
302         if (pSrc[i] == '#' && i < size - 2) {
303             *pDest ++ = _hex2dec(pSrc[i + 1]) * 16 + _hex2dec(pSrc[i + 2]);
304             i += 2;
305         } else {
306             *pDest ++ = pSrc[i];
307         }
308     }
309     result.ReleaseBuffer((FX_STRSIZE)(pDest - pDestStart));
310     return result;
311 }
312 CFX_ByteString PDF_NameDecode(const CFX_ByteString& orig)
313 {
314     if (FXSYS_memchr(orig.c_str(), '#', orig.GetLength()) == NULL) {
315         return orig;
316     }
317     return PDF_NameDecode(CFX_ByteStringC(orig));
318 }
319 CFX_ByteString PDF_NameEncode(const CFX_ByteString& orig)
320 {
321     uint8_t* src_buf = (uint8_t*)orig.c_str();
322     int src_len = orig.GetLength();
323     int dest_len = 0;
324     int i;
325     for (i = 0; i < src_len; i ++) {
326         uint8_t ch = src_buf[i];
327         if (ch >= 0x80 || PDF_CharType[ch] == 'W' || ch == '#' ||
328                 PDF_CharType[ch] == 'D') {
329             dest_len += 3;
330         } else {
331             dest_len ++;
332         }
333     }
334     if (dest_len == src_len) {
335         return orig;
336     }
337     CFX_ByteString res;
338     FX_CHAR* dest_buf = res.GetBuffer(dest_len);
339     dest_len = 0;
340     for (i = 0; i < src_len; i ++) {
341         uint8_t ch = src_buf[i];
342         if (ch >= 0x80 || PDF_CharType[ch] == 'W' || ch == '#' ||
343                 PDF_CharType[ch] == 'D') {
344             dest_buf[dest_len++] = '#';
345             dest_buf[dest_len++] = "0123456789ABCDEF"[ch / 16];
346             dest_buf[dest_len++] = "0123456789ABCDEF"[ch % 16];
347         } else {
348             dest_buf[dest_len++] = ch;
349         }
350     }
351     dest_buf[dest_len] = 0;
352     res.ReleaseBuffer();
353     return res;
354 }
355 CFX_ByteTextBuf& operator << (CFX_ByteTextBuf& buf, const CPDF_Object* pObj)
356 {
357     if (pObj == NULL) {
358         buf << FX_BSTRC(" null");
359         return buf;
360     }
361     switch (pObj->GetType()) {
362         case PDFOBJ_NULL:
363             buf << FX_BSTRC(" null");
364             break;
365         case PDFOBJ_BOOLEAN:
366         case PDFOBJ_NUMBER:
367             buf << " " << pObj->GetString();
368             break;
369         case PDFOBJ_STRING: {
370                 CFX_ByteString str = pObj->GetString();
371                 bool bHex = ((CPDF_String*)pObj)->IsHex();
372                 buf << PDF_EncodeString(str, bHex);
373                 break;
374             }
375         case PDFOBJ_NAME: {
376                 CFX_ByteString str = pObj->GetString();
377                 buf << FX_BSTRC("/") << PDF_NameEncode(str);
378                 break;
379             }
380         case PDFOBJ_REFERENCE: {
381                 CPDF_Reference* p = (CPDF_Reference*)pObj;
382                 buf << " " << p->GetRefObjNum() << FX_BSTRC(" 0 R ");
383                 break;
384             }
385         case PDFOBJ_ARRAY: {
386                 CPDF_Array* p = (CPDF_Array*)pObj;
387                 buf << FX_BSTRC("[");
388                 for (FX_DWORD i = 0; i < p->GetCount(); i ++) {
389                     CPDF_Object* pElement = p->GetElement(i);
390                     if (pElement->GetObjNum()) {
391                         buf << " " << pElement->GetObjNum() << FX_BSTRC(" 0 R");
392                     } else {
393                         buf << pElement;
394                     }
395                 }
396                 buf << FX_BSTRC("]");
397                 break;
398             }
399         case PDFOBJ_DICTIONARY: {
400                 CPDF_Dictionary* p = (CPDF_Dictionary*)pObj;
401                 buf << FX_BSTRC("<<");
402                 FX_POSITION pos = p->GetStartPos();
403                 while (pos) {
404                     CFX_ByteString key;
405                     CPDF_Object* pValue = p->GetNextElement(pos, key);
406                     buf << FX_BSTRC("/") << PDF_NameEncode(key);
407                     if (pValue->GetObjNum()) {
408                         buf << " " << pValue->GetObjNum() << FX_BSTRC(" 0 R ");
409                     } else {
410                         buf << pValue;
411                     }
412                 }
413                 buf << FX_BSTRC(">>");
414                 break;
415             }
416         case PDFOBJ_STREAM: {
417                 CPDF_Stream* p = (CPDF_Stream*)pObj;
418                 buf << p->GetDict() << FX_BSTRC("stream\r\n");
419                 CPDF_StreamAcc acc;
420                 acc.LoadAllData(p, true);
421                 buf.AppendBlock(acc.GetData(), acc.GetSize());
422                 buf << FX_BSTRC("\r\nendstream");
423                 break;
424             }
425         default:
426             ASSERT(false);
427             break;
428     }
429     return buf;
430 }
431 FX_FLOAT PDF_ClipFloat(FX_FLOAT f)
432 {
433     if (f < 0) {
434         return 0;
435     }
436     if (f > 1.0f) {
437         return 1.0f;
438     }
439     return f;
440 }
441 static CPDF_Object* SearchNumberNode(CPDF_Dictionary* pNode, int num)
442 {
443     CPDF_Array* pLimits = pNode->GetArray("Limits");
444     if (pLimits && (num < pLimits->GetInteger(0) || num > pLimits->GetInteger(1))) {
445         return NULL;
446     }
447     CPDF_Array* pNumbers = pNode->GetArray("Nums");
448     if (pNumbers) {
449         FX_DWORD dwCount = pNumbers->GetCount() / 2;
450         for (FX_DWORD i = 0; i < dwCount; i ++) {
451             int index = pNumbers->GetInteger(i * 2);
452             if (num == index) {
453                 return pNumbers->GetElementValue(i * 2 + 1);
454             }
455             if (index > num) {
456                 break;
457             }
458         }
459         return NULL;
460     }
461     CPDF_Array* pKids = pNode->GetArray("Kids");
462     if (pKids == NULL) {
463         return NULL;
464     }
465     for (FX_DWORD i = 0; i < pKids->GetCount(); i ++) {
466         CPDF_Dictionary* pKid = pKids->GetDict(i);
467         if (pKid == NULL) {
468             continue;
469         }
470         CPDF_Object* pFound = SearchNumberNode(pKid, num);
471         if (pFound) {
472             return pFound;
473         }
474     }
475     return NULL;
476 }
477 CPDF_Object* CPDF_NumberTree::LookupValue(int num)
478 {
479     return SearchNumberNode(m_pRoot, num);
480 }