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