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