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