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