OLD | NEW |
| (Empty) |
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 "xfa/src/fde/css/fde_csssyntax.h" | |
8 | |
9 #include "xfa/src/fde/css/fde_cssdatatable.h" | |
10 #include "xfa/src/fgas/crt/fgas_codepage.h" | |
11 | |
12 #ifdef _cplusplus | |
13 extern "C" { | |
14 #endif | |
15 | |
16 inline FX_BOOL FDE_IsSelectorStart(FX_WCHAR wch) { | |
17 return wch == '.' || wch == '#' || wch == '*' || (wch >= 'a' && wch <= 'z') || | |
18 (wch >= 'A' && wch <= 'Z'); | |
19 } | |
20 | |
21 #ifdef _cplusplus | |
22 }; | |
23 #endif | |
24 | |
25 IFDE_CSSSyntaxParser* IFDE_CSSSyntaxParser::Create() { | |
26 return new CFDE_CSSSyntaxParser; | |
27 } | |
28 CFDE_CSSSyntaxParser::CFDE_CSSSyntaxParser() | |
29 : m_pStream(NULL), | |
30 m_iStreamPos(0), | |
31 m_iPlaneSize(0), | |
32 m_iTextDatLen(0), | |
33 m_dwCheck((FX_DWORD)-1), | |
34 m_eMode(FDE_CSSSYNTAXMODE_RuleSet), | |
35 m_eStatus(FDE_CSSSYNTAXSTATUS_None) {} | |
36 CFDE_CSSSyntaxParser::~CFDE_CSSSyntaxParser() { | |
37 m_TextData.Reset(); | |
38 m_TextPlane.Reset(); | |
39 } | |
40 FX_BOOL CFDE_CSSSyntaxParser::Init(IFX_Stream* pStream, | |
41 int32_t iCSSPlaneSize, | |
42 int32_t iTextDataSize, | |
43 FX_BOOL bOnlyDeclaration) { | |
44 FXSYS_assert(pStream != NULL && iCSSPlaneSize > 0 && iTextDataSize > 0); | |
45 Reset(bOnlyDeclaration); | |
46 if (!m_TextData.EstimateSize(iTextDataSize)) { | |
47 return FALSE; | |
48 } | |
49 uint8_t bom[4]; | |
50 m_pStream = pStream; | |
51 m_iStreamPos = m_pStream->GetBOM(bom); | |
52 m_iPlaneSize = iCSSPlaneSize; | |
53 return TRUE; | |
54 } | |
55 FX_BOOL CFDE_CSSSyntaxParser::Init(const FX_WCHAR* pBuffer, | |
56 int32_t iBufferSize, | |
57 int32_t iTextDatSize, | |
58 FX_BOOL bOnlyDeclaration) { | |
59 FXSYS_assert(pBuffer != NULL && iBufferSize > 0 && iTextDatSize > 0); | |
60 Reset(bOnlyDeclaration); | |
61 if (!m_TextData.EstimateSize(iTextDatSize)) { | |
62 return FALSE; | |
63 } | |
64 return m_TextPlane.AttachBuffer(pBuffer, iBufferSize); | |
65 } | |
66 void CFDE_CSSSyntaxParser::Reset(FX_BOOL bOnlyDeclaration) { | |
67 m_TextPlane.Reset(); | |
68 m_TextData.Reset(); | |
69 m_pStream = NULL; | |
70 m_iStreamPos = 0; | |
71 m_iTextDatLen = 0; | |
72 m_dwCheck = (FX_DWORD)-1; | |
73 m_eStatus = FDE_CSSSYNTAXSTATUS_None; | |
74 m_eMode = bOnlyDeclaration ? FDE_CSSSYNTAXMODE_PropertyName | |
75 : FDE_CSSSYNTAXMODE_RuleSet; | |
76 } | |
77 FDE_CSSSYNTAXSTATUS CFDE_CSSSyntaxParser::DoSyntaxParse() { | |
78 while (m_eStatus >= FDE_CSSSYNTAXSTATUS_None) { | |
79 if (m_TextPlane.IsEOF()) { | |
80 if (m_pStream == NULL) { | |
81 if (m_eMode == FDE_CSSSYNTAXMODE_PropertyValue && | |
82 m_TextData.GetLength() > 0) { | |
83 SaveTextData(); | |
84 return m_eStatus = FDE_CSSSYNTAXSTATUS_PropertyValue; | |
85 } | |
86 return m_eStatus = FDE_CSSSYNTAXSTATUS_EOS; | |
87 } | |
88 FX_BOOL bEOS; | |
89 int32_t iLen = m_TextPlane.LoadFromStream(m_pStream, m_iStreamPos, | |
90 m_iPlaneSize, bEOS); | |
91 m_iStreamPos = m_pStream->GetPosition(); | |
92 if (iLen < 1) { | |
93 if (m_eMode == FDE_CSSSYNTAXMODE_PropertyValue && | |
94 m_TextData.GetLength() > 0) { | |
95 SaveTextData(); | |
96 return m_eStatus = FDE_CSSSYNTAXSTATUS_PropertyValue; | |
97 } | |
98 return m_eStatus = FDE_CSSSYNTAXSTATUS_EOS; | |
99 } | |
100 } | |
101 FX_WCHAR wch; | |
102 while (!m_TextPlane.IsEOF()) { | |
103 wch = m_TextPlane.GetChar(); | |
104 switch (m_eMode) { | |
105 case FDE_CSSSYNTAXMODE_RuleSet: | |
106 switch (wch) { | |
107 case '@': | |
108 m_TextPlane.MoveNext(); | |
109 SwitchMode(FDE_CSSSYNTAXMODE_AtRule); | |
110 break; | |
111 case '}': | |
112 m_TextPlane.MoveNext(); | |
113 if (RestoreMode()) { | |
114 return FDE_CSSSYNTAXSTATUS_DeclClose; | |
115 } else { | |
116 return m_eStatus = FDE_CSSSYNTAXSTATUS_Error; | |
117 } | |
118 break; | |
119 case '/': | |
120 if (m_TextPlane.GetNextChar() == '*') { | |
121 m_ModeStack.Push(m_eMode); | |
122 SwitchMode(FDE_CSSSYNTAXMODE_Comment); | |
123 break; | |
124 } | |
125 default: | |
126 if (wch <= ' ') { | |
127 m_TextPlane.MoveNext(); | |
128 } else if (FDE_IsSelectorStart(wch)) { | |
129 SwitchMode(FDE_CSSSYNTAXMODE_Selector); | |
130 return FDE_CSSSYNTAXSTATUS_StyleRule; | |
131 } else { | |
132 return m_eStatus = FDE_CSSSYNTAXSTATUS_Error; | |
133 } | |
134 break; | |
135 } | |
136 break; | |
137 case FDE_CSSSYNTAXMODE_Selector: | |
138 switch (wch) { | |
139 case ',': | |
140 m_TextPlane.MoveNext(); | |
141 SwitchMode(FDE_CSSSYNTAXMODE_Selector); | |
142 if (m_iTextDatLen > 0) { | |
143 return FDE_CSSSYNTAXSTATUS_Selector; | |
144 } | |
145 break; | |
146 case '{': | |
147 if (m_TextData.GetLength() > 0) { | |
148 SaveTextData(); | |
149 return FDE_CSSSYNTAXSTATUS_Selector; | |
150 } else { | |
151 m_TextPlane.MoveNext(); | |
152 m_ModeStack.Push(FDE_CSSSYNTAXMODE_RuleSet); | |
153 SwitchMode(FDE_CSSSYNTAXMODE_PropertyName); | |
154 return FDE_CSSSYNTAXSTATUS_DeclOpen; | |
155 } | |
156 break; | |
157 case '/': | |
158 if (m_TextPlane.GetNextChar() == '*') { | |
159 if (SwitchToComment() > 0) { | |
160 return FDE_CSSSYNTAXSTATUS_Selector; | |
161 } | |
162 break; | |
163 } | |
164 default: | |
165 AppendChar(wch); | |
166 break; | |
167 } | |
168 break; | |
169 case FDE_CSSSYNTAXMODE_PropertyName: | |
170 switch (wch) { | |
171 case ':': | |
172 m_TextPlane.MoveNext(); | |
173 SwitchMode(FDE_CSSSYNTAXMODE_PropertyValue); | |
174 return FDE_CSSSYNTAXSTATUS_PropertyName; | |
175 case '}': | |
176 m_TextPlane.MoveNext(); | |
177 if (RestoreMode()) { | |
178 return FDE_CSSSYNTAXSTATUS_DeclClose; | |
179 } else { | |
180 return m_eStatus = FDE_CSSSYNTAXSTATUS_Error; | |
181 } | |
182 break; | |
183 case '/': | |
184 if (m_TextPlane.GetNextChar() == '*') { | |
185 if (SwitchToComment() > 0) { | |
186 return FDE_CSSSYNTAXSTATUS_PropertyName; | |
187 } | |
188 break; | |
189 } | |
190 default: | |
191 AppendChar(wch); | |
192 break; | |
193 } | |
194 break; | |
195 case FDE_CSSSYNTAXMODE_PropertyValue: | |
196 switch (wch) { | |
197 case ';': | |
198 m_TextPlane.MoveNext(); | |
199 case '}': | |
200 SwitchMode(FDE_CSSSYNTAXMODE_PropertyName); | |
201 return FDE_CSSSYNTAXSTATUS_PropertyValue; | |
202 case '/': | |
203 if (m_TextPlane.GetNextChar() == '*') { | |
204 if (SwitchToComment() > 0) { | |
205 return FDE_CSSSYNTAXSTATUS_PropertyValue; | |
206 } | |
207 break; | |
208 } | |
209 default: | |
210 AppendChar(wch); | |
211 break; | |
212 } | |
213 break; | |
214 case FDE_CSSSYNTAXMODE_Comment: | |
215 if (wch == '/' && m_TextData.GetLength() > 0 && | |
216 m_TextData.GetAt(m_TextData.GetLength() - 1) == '*') { | |
217 RestoreMode(); | |
218 } else { | |
219 m_TextData.AppendChar(wch); | |
220 } | |
221 m_TextPlane.MoveNext(); | |
222 break; | |
223 case FDE_CSSSYNTAXMODE_MediaType: | |
224 switch (wch) { | |
225 case ',': | |
226 m_TextPlane.MoveNext(); | |
227 SwitchMode(FDE_CSSSYNTAXMODE_MediaType); | |
228 if (m_iTextDatLen > 0) { | |
229 return FDE_CSSSYNTAXSTATUS_MediaType; | |
230 } | |
231 break; | |
232 case '{': { | |
233 FDE_CSSSYNTAXMODE* pMode = m_ModeStack.GetTopElement(); | |
234 if (pMode == NULL || *pMode != FDE_CSSSYNTAXMODE_MediaRule) { | |
235 return m_eStatus = FDE_CSSSYNTAXSTATUS_Error; | |
236 } | |
237 if (m_TextData.GetLength() > 0) { | |
238 SaveTextData(); | |
239 return FDE_CSSSYNTAXSTATUS_MediaType; | |
240 } else { | |
241 m_TextPlane.MoveNext(); | |
242 *pMode = FDE_CSSSYNTAXMODE_RuleSet; | |
243 SwitchMode(FDE_CSSSYNTAXMODE_RuleSet); | |
244 return FDE_CSSSYNTAXSTATUS_DeclOpen; | |
245 } | |
246 } break; | |
247 case ';': { | |
248 FDE_CSSSYNTAXMODE* pMode = m_ModeStack.GetTopElement(); | |
249 if (pMode == NULL || *pMode != FDE_CSSSYNTAXMODE_Import) { | |
250 return m_eStatus = FDE_CSSSYNTAXSTATUS_Error; | |
251 } | |
252 if (m_TextData.GetLength() > 0) { | |
253 SaveTextData(); | |
254 if (IsImportEnabled()) { | |
255 return FDE_CSSSYNTAXSTATUS_MediaType; | |
256 } | |
257 } else { | |
258 FX_BOOL bEnabled = IsImportEnabled(); | |
259 m_TextPlane.MoveNext(); | |
260 m_ModeStack.Pop(); | |
261 SwitchMode(FDE_CSSSYNTAXMODE_RuleSet); | |
262 if (bEnabled) { | |
263 DisableImport(); | |
264 return FDE_CSSSYNTAXSTATUS_ImportClose; | |
265 } | |
266 } | |
267 } break; | |
268 case '/': | |
269 if (m_TextPlane.GetNextChar() == '*') { | |
270 if (SwitchToComment() > 0) { | |
271 return FDE_CSSSYNTAXSTATUS_MediaType; | |
272 } | |
273 break; | |
274 } | |
275 default: | |
276 AppendChar(wch); | |
277 break; | |
278 } | |
279 break; | |
280 case FDE_CSSSYNTAXMODE_URI: { | |
281 FDE_CSSSYNTAXMODE* pMode = m_ModeStack.GetTopElement(); | |
282 if (pMode == NULL || *pMode != FDE_CSSSYNTAXMODE_Import) { | |
283 return m_eStatus = FDE_CSSSYNTAXSTATUS_Error; | |
284 } | |
285 if (wch <= ' ' || wch == ';') { | |
286 int32_t iURIStart, iURILength = m_TextData.GetLength(); | |
287 if (iURILength > 0 && | |
288 FDE_ParseCSSURI(m_TextData.GetBuffer(), iURILength, iURIStart, | |
289 iURILength)) { | |
290 m_TextData.Subtract(iURIStart, iURILength); | |
291 SwitchMode(FDE_CSSSYNTAXMODE_MediaType); | |
292 if (IsImportEnabled()) { | |
293 return FDE_CSSSYNTAXSTATUS_URI; | |
294 } else { | |
295 break; | |
296 } | |
297 } | |
298 } | |
299 AppendChar(wch); | |
300 } break; | |
301 case FDE_CSSSYNTAXMODE_AtRule: | |
302 if (wch > ' ') { | |
303 AppendChar(wch); | |
304 } else { | |
305 int32_t iLen = m_TextData.GetLength(); | |
306 const FX_WCHAR* psz = m_TextData.GetBuffer(); | |
307 if (FXSYS_wcsncmp(L"charset", psz, iLen) == 0) { | |
308 SwitchMode(FDE_CSSSYNTAXMODE_Charset); | |
309 } else if (FXSYS_wcsncmp(L"import", psz, iLen) == 0) { | |
310 m_ModeStack.Push(FDE_CSSSYNTAXMODE_Import); | |
311 SwitchMode(FDE_CSSSYNTAXMODE_URI); | |
312 if (IsImportEnabled()) { | |
313 return FDE_CSSSYNTAXSTATUS_ImportRule; | |
314 } else { | |
315 break; | |
316 } | |
317 } else if (FXSYS_wcsncmp(L"media", psz, iLen) == 0) { | |
318 m_ModeStack.Push(FDE_CSSSYNTAXMODE_MediaRule); | |
319 SwitchMode(FDE_CSSSYNTAXMODE_MediaType); | |
320 return FDE_CSSSYNTAXSTATUS_MediaRule; | |
321 } else if (FXSYS_wcsncmp(L"font-face", psz, iLen) == 0) { | |
322 SwitchMode(FDE_CSSSYNTAXMODE_Selector); | |
323 return FDE_CSSSYNTAXSTATUS_FontFaceRule; | |
324 } else if (FXSYS_wcsncmp(L"page", psz, iLen) == 0) { | |
325 SwitchMode(FDE_CSSSYNTAXMODE_Selector); | |
326 return FDE_CSSSYNTAXSTATUS_PageRule; | |
327 } else { | |
328 SwitchMode(FDE_CSSSYNTAXMODE_UnknownRule); | |
329 } | |
330 } | |
331 break; | |
332 case FDE_CSSSYNTAXMODE_Charset: | |
333 if (wch == ';') { | |
334 m_TextPlane.MoveNext(); | |
335 SwitchMode(FDE_CSSSYNTAXMODE_RuleSet); | |
336 if (IsCharsetEnabled()) { | |
337 DisableCharset(); | |
338 if (m_iTextDatLen > 0) { | |
339 if (m_pStream != NULL) { | |
340 FX_WORD wCodePage = FX_GetCodePageFormStringW( | |
341 m_TextData.GetBuffer(), m_iTextDatLen); | |
342 if (wCodePage < 0xFFFF && | |
343 m_pStream->GetCodePage() != wCodePage) { | |
344 m_pStream->SetCodePage(wCodePage); | |
345 } | |
346 } | |
347 return FDE_CSSSYNTAXSTATUS_Charset; | |
348 } | |
349 } | |
350 } else { | |
351 AppendChar(wch); | |
352 } | |
353 break; | |
354 case FDE_CSSSYNTAXMODE_UnknownRule: | |
355 if (wch == ';') { | |
356 SwitchMode(FDE_CSSSYNTAXMODE_RuleSet); | |
357 } | |
358 m_TextPlane.MoveNext(); | |
359 break; | |
360 default: | |
361 FXSYS_assert(FALSE); | |
362 break; | |
363 } | |
364 } | |
365 } | |
366 return m_eStatus; | |
367 } | |
368 FX_BOOL CFDE_CSSSyntaxParser::IsImportEnabled() const { | |
369 if ((m_dwCheck & FDE_CSSSYNTAXCHECK_AllowImport) == 0) { | |
370 return FALSE; | |
371 } | |
372 if (m_ModeStack.GetSize() > 1) { | |
373 return FALSE; | |
374 } | |
375 return TRUE; | |
376 } | |
377 inline FX_BOOL CFDE_CSSSyntaxParser::AppendChar(FX_WCHAR wch) { | |
378 m_TextPlane.MoveNext(); | |
379 if (m_TextData.GetLength() > 0 || wch > ' ') { | |
380 m_TextData.AppendChar(wch); | |
381 return TRUE; | |
382 } | |
383 return FALSE; | |
384 } | |
385 inline int32_t CFDE_CSSSyntaxParser::SaveTextData() { | |
386 m_iTextDatLen = m_TextData.TrimEnd(); | |
387 m_TextData.Clear(); | |
388 return m_iTextDatLen; | |
389 } | |
390 inline void CFDE_CSSSyntaxParser::SwitchMode(FDE_CSSSYNTAXMODE eMode) { | |
391 m_eMode = eMode; | |
392 SaveTextData(); | |
393 } | |
394 inline int32_t CFDE_CSSSyntaxParser::SwitchToComment() { | |
395 int32_t iLength = m_TextData.GetLength(); | |
396 m_ModeStack.Push(m_eMode); | |
397 SwitchMode(FDE_CSSSYNTAXMODE_Comment); | |
398 return iLength; | |
399 } | |
400 inline FX_BOOL CFDE_CSSSyntaxParser::RestoreMode() { | |
401 FDE_CSSSYNTAXMODE* pMode = m_ModeStack.GetTopElement(); | |
402 if (pMode == NULL) { | |
403 return FALSE; | |
404 } | |
405 SwitchMode(*pMode); | |
406 m_ModeStack.Pop(); | |
407 return TRUE; | |
408 } | |
409 const FX_WCHAR* CFDE_CSSSyntaxParser::GetCurrentString(int32_t& iLength) const { | |
410 iLength = m_iTextDatLen; | |
411 return m_TextData.GetBuffer(); | |
412 } | |
413 CFDE_CSSTextBuf::CFDE_CSSTextBuf() | |
414 : m_bExtBuf(FALSE), | |
415 m_pBuffer(NULL), | |
416 m_iBufLen(0), | |
417 m_iDatLen(0), | |
418 m_iDatPos(0) {} | |
419 CFDE_CSSTextBuf::~CFDE_CSSTextBuf() { | |
420 Reset(); | |
421 } | |
422 void CFDE_CSSTextBuf::Reset() { | |
423 if (!m_bExtBuf) { | |
424 FX_Free(m_pBuffer); | |
425 m_pBuffer = NULL; | |
426 } | |
427 m_iDatPos = m_iDatLen = m_iBufLen; | |
428 } | |
429 FX_BOOL CFDE_CSSTextBuf::AttachBuffer(const FX_WCHAR* pBuffer, | |
430 int32_t iBufLen) { | |
431 Reset(); | |
432 m_pBuffer = (FX_WCHAR*)pBuffer; | |
433 m_iDatLen = m_iBufLen = iBufLen; | |
434 return m_bExtBuf = TRUE; | |
435 } | |
436 FX_BOOL CFDE_CSSTextBuf::EstimateSize(int32_t iAllocSize) { | |
437 FXSYS_assert(iAllocSize > 0); | |
438 Clear(); | |
439 m_bExtBuf = FALSE; | |
440 return ExpandBuf(iAllocSize); | |
441 } | |
442 int32_t CFDE_CSSTextBuf::LoadFromStream(IFX_Stream* pTxtStream, | |
443 int32_t iStreamOffset, | |
444 int32_t iMaxChars, | |
445 FX_BOOL& bEOS) { | |
446 FXSYS_assert(iStreamOffset >= 0 && iMaxChars > 0); | |
447 Clear(); | |
448 m_bExtBuf = FALSE; | |
449 if (!ExpandBuf(iMaxChars)) { | |
450 return 0; | |
451 } | |
452 if (pTxtStream->GetPosition() != iStreamOffset) { | |
453 pTxtStream->Seek(FX_STREAMSEEK_Begin, iStreamOffset); | |
454 } | |
455 m_iDatLen = pTxtStream->ReadString(m_pBuffer, iMaxChars, bEOS); | |
456 return m_iDatLen; | |
457 } | |
458 FX_BOOL CFDE_CSSTextBuf::ExpandBuf(int32_t iDesiredSize) { | |
459 if (m_bExtBuf) { | |
460 return FALSE; | |
461 } | |
462 if (!m_pBuffer) { | |
463 m_pBuffer = FX_Alloc(FX_WCHAR, iDesiredSize); | |
464 } else if (m_iBufLen != iDesiredSize) { | |
465 m_pBuffer = FX_Realloc(FX_WCHAR, m_pBuffer, iDesiredSize); | |
466 } else { | |
467 return TRUE; | |
468 } | |
469 if (!m_pBuffer) { | |
470 m_iBufLen = 0; | |
471 return FALSE; | |
472 } | |
473 m_iBufLen = iDesiredSize; | |
474 return TRUE; | |
475 } | |
476 void CFDE_CSSTextBuf::Subtract(int32_t iStart, int32_t iLength) { | |
477 FXSYS_assert(iStart >= 0 && iLength > 0); | |
478 if (iLength > m_iDatLen - iStart) { | |
479 iLength = m_iDatLen - iStart; | |
480 } | |
481 if (iLength < 0) { | |
482 iLength = 0; | |
483 } else { | |
484 FXSYS_memmove(m_pBuffer, m_pBuffer + iStart, iLength * sizeof(FX_WCHAR)); | |
485 } | |
486 m_iDatLen = iLength; | |
487 } | |
OLD | NEW |