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