Fix two issues shown by bug 489995
[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       CFX_ByteString str = pObj->GetString();
377       FX_BOOL bHex = ((CPDF_String*)pObj)->IsHex();
378       buf << PDF_EncodeString(str, bHex);
379       break;
380     }
381     case PDFOBJ_NAME: {
382       CFX_ByteString str = pObj->GetString();
383       buf << FX_BSTRC("/") << PDF_NameEncode(str);
384       break;
385     }
386     case PDFOBJ_REFERENCE: {
387       CPDF_Reference* p = (CPDF_Reference*)pObj;
388       buf << " " << p->GetRefObjNum() << FX_BSTRC(" 0 R ");
389       break;
390     }
391     case PDFOBJ_ARRAY: {
392       CPDF_Array* p = (CPDF_Array*)pObj;
393       buf << FX_BSTRC("[");
394       for (FX_DWORD i = 0; i < p->GetCount(); i++) {
395         CPDF_Object* pElement = p->GetElement(i);
396         if (pElement->GetObjNum()) {
397           buf << " " << pElement->GetObjNum() << FX_BSTRC(" 0 R");
398         } else {
399           buf << pElement;
400         }
401       }
402       buf << FX_BSTRC("]");
403       break;
404     }
405     case PDFOBJ_DICTIONARY: {
406       CPDF_Dictionary* p = (CPDF_Dictionary*)pObj;
407       buf << FX_BSTRC("<<");
408       FX_POSITION pos = p->GetStartPos();
409       while (pos) {
410         CFX_ByteString key;
411         CPDF_Object* pValue = p->GetNextElement(pos, key);
412         buf << FX_BSTRC("/") << PDF_NameEncode(key);
413         if (pValue && pValue->GetObjNum()) {
414           buf << " " << pValue->GetObjNum() << FX_BSTRC(" 0 R ");
415         } else {
416           buf << pValue;
417         }
418       }
419       buf << FX_BSTRC(">>");
420       break;
421     }
422     case PDFOBJ_STREAM: {
423       CPDF_Stream* p = (CPDF_Stream*)pObj;
424       buf << p->GetDict() << FX_BSTRC("stream\r\n");
425       CPDF_StreamAcc acc;
426       acc.LoadAllData(p, TRUE);
427       buf.AppendBlock(acc.GetData(), acc.GetSize());
428       buf << FX_BSTRC("\r\nendstream");
429       break;
430     }
431     default:
432       ASSERT(FALSE);
433       break;
434   }
435   return buf;
436 }
437 FX_FLOAT PDF_ClipFloat(FX_FLOAT f) {
438   if (f < 0) {
439     return 0;
440   }
441   if (f > 1.0f) {
442     return 1.0f;
443   }
444   return f;
445 }
446 static CPDF_Object* SearchNumberNode(CPDF_Dictionary* pNode, int num) {
447   CPDF_Array* pLimits = pNode->GetArray("Limits");
448   if (pLimits &&
449       (num < pLimits->GetInteger(0) || num > pLimits->GetInteger(1))) {
450     return NULL;
451   }
452   CPDF_Array* pNumbers = pNode->GetArray("Nums");
453   if (pNumbers) {
454     FX_DWORD dwCount = pNumbers->GetCount() / 2;
455     for (FX_DWORD i = 0; i < dwCount; i++) {
456       int index = pNumbers->GetInteger(i * 2);
457       if (num == index) {
458         return pNumbers->GetElementValue(i * 2 + 1);
459       }
460       if (index > num) {
461         break;
462       }
463     }
464     return NULL;
465   }
466   CPDF_Array* pKids = pNode->GetArray("Kids");
467   if (pKids == NULL) {
468     return NULL;
469   }
470   for (FX_DWORD i = 0; i < pKids->GetCount(); i++) {
471     CPDF_Dictionary* pKid = pKids->GetDict(i);
472     if (pKid == NULL) {
473       continue;
474     }
475     CPDF_Object* pFound = SearchNumberNode(pKid, num);
476     if (pFound) {
477       return pFound;
478     }
479   }
480   return NULL;
481 }
482 CPDF_Object* CPDF_NumberTree::LookupValue(int num) {
483   return SearchNumberNode(m_pRoot, num);
484 }