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
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
\r
7 #include "../../../foxitlib.h"
\r
8 #include "fde_csssyntax.h"
\r
9 #include "fde_cssdatatable.h"
\r
13 inline FX_BOOL FDE_IsSelectorStart(FX_WCHAR wch)
\r
15 return wch == '.' || wch == '#' || wch == '*'
\r
16 || (wch >= 'a' && wch <= 'z')
\r
17 || (wch >= 'A' && wch <= 'Z');
\r
22 IFDE_CSSSyntaxParser* IFDE_CSSSyntaxParser::Create()
\r
24 return FDE_New CFDE_CSSSyntaxParser;
\r
26 CFDE_CSSSyntaxParser::CFDE_CSSSyntaxParser()
\r
31 , m_dwCheck((FX_DWORD) - 1)
\r
32 , m_eMode(FDE_CSSSYNTAXMODE_RuleSet)
\r
33 , m_eStatus(FDE_CSSSYNTAXSTATUS_None)
\r
36 CFDE_CSSSyntaxParser::~CFDE_CSSSyntaxParser()
\r
39 m_TextPlane.Reset();
\r
41 FX_BOOL CFDE_CSSSyntaxParser::Init(IFX_Stream *pStream, FX_INT32 iCSSPlaneSize, FX_INT32 iTextDataSize , FX_BOOL bOnlyDeclaration )
\r
43 FXSYS_assert(pStream != NULL && iCSSPlaneSize > 0 && iTextDataSize > 0);
\r
44 Reset(bOnlyDeclaration);
\r
45 if (!m_TextData.EstimateSize(iTextDataSize)) {
\r
49 m_pStream = pStream;
\r
50 m_iStreamPos = m_pStream->GetBOM(bom);
\r
51 m_iPlaneSize = iCSSPlaneSize;
\r
54 FX_BOOL CFDE_CSSSyntaxParser::Init(FX_LPCWSTR pBuffer, FX_INT32 iBufferSize, FX_INT32 iTextDatSize , FX_BOOL bOnlyDeclaration )
\r
56 FXSYS_assert(pBuffer != NULL && iBufferSize > 0 && iTextDatSize > 0);
\r
57 Reset(bOnlyDeclaration);
\r
58 if (!m_TextData.EstimateSize(iTextDatSize)) {
\r
61 return m_TextPlane.AttachBuffer(pBuffer, iBufferSize);
\r
63 void CFDE_CSSSyntaxParser::Reset(FX_BOOL bOnlyDeclaration)
\r
65 m_TextPlane.Reset();
\r
70 m_dwCheck = (FX_DWORD) - 1;
\r
71 m_eStatus = FDE_CSSSYNTAXSTATUS_None;
\r
72 m_eMode = bOnlyDeclaration ? FDE_CSSSYNTAXMODE_PropertyName : FDE_CSSSYNTAXMODE_RuleSet;
\r
74 FDE_CSSSYNTAXSTATUS CFDE_CSSSyntaxParser::DoSyntaxParse()
\r
76 while (m_eStatus >= FDE_CSSSYNTAXSTATUS_None) {
\r
77 if (m_TextPlane.IsEOF()) {
\r
78 if (m_pStream == NULL) {
\r
79 if (m_eMode == FDE_CSSSYNTAXMODE_PropertyValue && m_TextData.GetLength() > 0) {
\r
81 return m_eStatus = FDE_CSSSYNTAXSTATUS_PropertyValue;
\r
83 return m_eStatus = FDE_CSSSYNTAXSTATUS_EOS;
\r
86 FX_INT32 iLen = m_TextPlane.LoadFromStream(m_pStream, m_iStreamPos, m_iPlaneSize, bEOS);
\r
87 m_iStreamPos = m_pStream->GetPosition();
\r
89 if (m_eMode == FDE_CSSSYNTAXMODE_PropertyValue && m_TextData.GetLength() > 0) {
\r
91 return m_eStatus = FDE_CSSSYNTAXSTATUS_PropertyValue;
\r
93 return m_eStatus = FDE_CSSSYNTAXSTATUS_EOS;
\r
97 while (!m_TextPlane.IsEOF()) {
\r
98 wch = m_TextPlane.GetChar();
\r
100 case FDE_CSSSYNTAXMODE_RuleSet:
\r
103 m_TextPlane.MoveNext();
\r
104 SwitchMode(FDE_CSSSYNTAXMODE_AtRule);
\r
107 m_TextPlane.MoveNext();
\r
108 if (RestoreMode()) {
\r
109 return FDE_CSSSYNTAXSTATUS_DeclClose;
\r
111 return m_eStatus = FDE_CSSSYNTAXSTATUS_Error;
\r
115 if (m_TextPlane.GetNextChar() == '*') {
\r
116 m_ModeStack.Push(m_eMode);
\r
117 SwitchMode(FDE_CSSSYNTAXMODE_Comment);
\r
122 m_TextPlane.MoveNext();
\r
123 } else if (FDE_IsSelectorStart(wch)) {
\r
124 SwitchMode(FDE_CSSSYNTAXMODE_Selector);
\r
125 return FDE_CSSSYNTAXSTATUS_StyleRule;
\r
127 return m_eStatus = FDE_CSSSYNTAXSTATUS_Error;
\r
132 case FDE_CSSSYNTAXMODE_Selector:
\r
135 m_TextPlane.MoveNext();
\r
136 SwitchMode(FDE_CSSSYNTAXMODE_Selector);
\r
137 if (m_iTextDatLen > 0) {
\r
138 return FDE_CSSSYNTAXSTATUS_Selector;
\r
142 if (m_TextData.GetLength() > 0) {
\r
144 return FDE_CSSSYNTAXSTATUS_Selector;
\r
146 m_TextPlane.MoveNext();
\r
147 m_ModeStack.Push(FDE_CSSSYNTAXMODE_RuleSet);
\r
148 SwitchMode(FDE_CSSSYNTAXMODE_PropertyName);
\r
149 return FDE_CSSSYNTAXSTATUS_DeclOpen;
\r
153 if (m_TextPlane.GetNextChar() == '*') {
\r
154 if (SwitchToComment() > 0) {
\r
155 return FDE_CSSSYNTAXSTATUS_Selector;
\r
164 case FDE_CSSSYNTAXMODE_PropertyName:
\r
167 m_TextPlane.MoveNext();
\r
168 SwitchMode(FDE_CSSSYNTAXMODE_PropertyValue);
\r
169 return FDE_CSSSYNTAXSTATUS_PropertyName;
\r
171 m_TextPlane.MoveNext();
\r
172 if (RestoreMode()) {
\r
173 return FDE_CSSSYNTAXSTATUS_DeclClose;
\r
175 return m_eStatus = FDE_CSSSYNTAXSTATUS_Error;
\r
179 if (m_TextPlane.GetNextChar() == '*') {
\r
180 if (SwitchToComment() > 0) {
\r
181 return FDE_CSSSYNTAXSTATUS_PropertyName;
\r
190 case FDE_CSSSYNTAXMODE_PropertyValue:
\r
193 m_TextPlane.MoveNext();
\r
195 SwitchMode(FDE_CSSSYNTAXMODE_PropertyName);
\r
196 return FDE_CSSSYNTAXSTATUS_PropertyValue;
\r
198 if (m_TextPlane.GetNextChar() == '*') {
\r
199 if (SwitchToComment() > 0) {
\r
200 return FDE_CSSSYNTAXSTATUS_PropertyValue;
\r
209 case FDE_CSSSYNTAXMODE_Comment:
\r
210 if (wch == '/' && m_TextData.GetLength() > 0
\r
211 && m_TextData.GetAt(m_TextData.GetLength() - 1) == '*') {
\r
214 m_TextData.AppendChar(wch);
\r
216 m_TextPlane.MoveNext();
\r
218 case FDE_CSSSYNTAXMODE_MediaType:
\r
221 m_TextPlane.MoveNext();
\r
222 SwitchMode(FDE_CSSSYNTAXMODE_MediaType);
\r
223 if (m_iTextDatLen > 0) {
\r
224 return FDE_CSSSYNTAXSTATUS_MediaType;
\r
228 FDE_CSSSYNTAXMODE *pMode = m_ModeStack.GetTopElement();
\r
229 if (pMode == NULL || *pMode != FDE_CSSSYNTAXMODE_MediaRule) {
\r
230 return m_eStatus = FDE_CSSSYNTAXSTATUS_Error;
\r
232 if (m_TextData.GetLength() > 0) {
\r
234 return FDE_CSSSYNTAXSTATUS_MediaType;
\r
236 m_TextPlane.MoveNext();
\r
237 *pMode = FDE_CSSSYNTAXMODE_RuleSet;
\r
238 SwitchMode(FDE_CSSSYNTAXMODE_RuleSet);
\r
239 return FDE_CSSSYNTAXSTATUS_DeclOpen;
\r
244 FDE_CSSSYNTAXMODE *pMode = m_ModeStack.GetTopElement();
\r
245 if (pMode == NULL || *pMode != FDE_CSSSYNTAXMODE_Import) {
\r
246 return m_eStatus = FDE_CSSSYNTAXSTATUS_Error;
\r
248 if (m_TextData.GetLength() > 0) {
\r
250 if (IsImportEnabled()) {
\r
251 return FDE_CSSSYNTAXSTATUS_MediaType;
\r
254 FX_BOOL bEnabled = IsImportEnabled();
\r
255 m_TextPlane.MoveNext();
\r
257 SwitchMode(FDE_CSSSYNTAXMODE_RuleSet);
\r
260 return FDE_CSSSYNTAXSTATUS_ImportClose;
\r
266 if (m_TextPlane.GetNextChar() == '*') {
\r
267 if (SwitchToComment() > 0) {
\r
268 return FDE_CSSSYNTAXSTATUS_MediaType;
\r
277 case FDE_CSSSYNTAXMODE_URI: {
\r
278 FDE_CSSSYNTAXMODE *pMode = m_ModeStack.GetTopElement();
\r
279 if (pMode == NULL || *pMode != FDE_CSSSYNTAXMODE_Import) {
\r
280 return m_eStatus = FDE_CSSSYNTAXSTATUS_Error;
\r
282 if (wch <= ' ' || wch == ';') {
\r
283 FX_INT32 iURIStart, iURILength = m_TextData.GetLength();
\r
284 if (iURILength > 0 && FDE_ParseCSSURI(m_TextData.GetBuffer(), iURILength, iURIStart, iURILength)) {
\r
285 m_TextData.Subtract(iURIStart, iURILength);
\r
286 SwitchMode(FDE_CSSSYNTAXMODE_MediaType);
\r
287 if (IsImportEnabled()) {
\r
288 return FDE_CSSSYNTAXSTATUS_URI;
\r
297 case FDE_CSSSYNTAXMODE_AtRule:
\r
301 FX_INT32 iLen = m_TextData.GetLength();
\r
302 FX_LPCWSTR psz = m_TextData.GetBuffer();
\r
303 if (FXSYS_wcsncmp(L"charset", psz, iLen) == 0) {
\r
304 SwitchMode(FDE_CSSSYNTAXMODE_Charset);
\r
305 } else if (FXSYS_wcsncmp(L"import", psz, iLen) == 0) {
\r
306 m_ModeStack.Push(FDE_CSSSYNTAXMODE_Import);
\r
307 SwitchMode(FDE_CSSSYNTAXMODE_URI);
\r
308 if (IsImportEnabled()) {
\r
309 return FDE_CSSSYNTAXSTATUS_ImportRule;
\r
313 } else if (FXSYS_wcsncmp(L"media", psz, iLen) == 0) {
\r
314 m_ModeStack.Push(FDE_CSSSYNTAXMODE_MediaRule);
\r
315 SwitchMode(FDE_CSSSYNTAXMODE_MediaType);
\r
316 return FDE_CSSSYNTAXSTATUS_MediaRule;
\r
317 } else if (FXSYS_wcsncmp(L"font-face", psz, iLen) == 0) {
\r
318 SwitchMode(FDE_CSSSYNTAXMODE_Selector);
\r
319 return FDE_CSSSYNTAXSTATUS_FontFaceRule;
\r
320 } else if (FXSYS_wcsncmp(L"page", psz, iLen) == 0) {
\r
321 SwitchMode(FDE_CSSSYNTAXMODE_Selector);
\r
322 return FDE_CSSSYNTAXSTATUS_PageRule;
\r
324 SwitchMode(FDE_CSSSYNTAXMODE_UnknownRule);
\r
328 case FDE_CSSSYNTAXMODE_Charset:
\r
330 m_TextPlane.MoveNext();
\r
331 SwitchMode(FDE_CSSSYNTAXMODE_RuleSet);
\r
332 if (IsCharsetEnabled()) {
\r
334 if (m_iTextDatLen > 0) {
\r
335 if (m_pStream != NULL) {
\r
336 FX_WORD wCodePage = FX_GetCodePageFormStringW(m_TextData.GetBuffer(), m_iTextDatLen);
\r
337 if (wCodePage < 0xFFFF && m_pStream->GetCodePage() != wCodePage) {
\r
338 m_pStream->SetCodePage(wCodePage);
\r
341 return FDE_CSSSYNTAXSTATUS_Charset;
\r
348 case FDE_CSSSYNTAXMODE_UnknownRule:
\r
350 SwitchMode(FDE_CSSSYNTAXMODE_RuleSet);
\r
352 m_TextPlane.MoveNext();
\r
355 FXSYS_assert(FALSE);
\r
362 FX_BOOL CFDE_CSSSyntaxParser::IsImportEnabled() const
\r
364 if ((m_dwCheck & FDE_CSSSYNTAXCHECK_AllowImport) == 0) {
\r
367 if (m_ModeStack.GetSize() > 1) {
\r
372 inline FX_BOOL CFDE_CSSSyntaxParser::AppendChar(FX_WCHAR wch)
\r
374 m_TextPlane.MoveNext();
\r
375 if (m_TextData.GetLength() > 0 || wch > ' ') {
\r
376 m_TextData.AppendChar(wch);
\r
381 inline FX_INT32 CFDE_CSSSyntaxParser::SaveTextData()
\r
383 m_iTextDatLen = m_TextData.TrimEnd();
\r
384 m_TextData.Clear();
\r
385 return m_iTextDatLen;
\r
387 inline void CFDE_CSSSyntaxParser::SwitchMode(FDE_CSSSYNTAXMODE eMode)
\r
392 inline FX_INT32 CFDE_CSSSyntaxParser::SwitchToComment()
\r
394 FX_INT32 iLength = m_TextData.GetLength();
\r
395 m_ModeStack.Push(m_eMode);
\r
396 SwitchMode(FDE_CSSSYNTAXMODE_Comment);
\r
399 inline FX_BOOL CFDE_CSSSyntaxParser::RestoreMode()
\r
401 FDE_CSSSYNTAXMODE *pMode = m_ModeStack.GetTopElement();
\r
402 if (pMode == NULL) {
\r
405 SwitchMode(*pMode);
\r
409 FX_LPCWSTR CFDE_CSSSyntaxParser::GetCurrentString(FX_INT32 &iLength) const
\r
411 iLength = m_iTextDatLen;
\r
412 return m_TextData.GetBuffer();
\r
414 CFDE_CSSTextBuf::CFDE_CSSTextBuf()
\r
422 CFDE_CSSTextBuf::~CFDE_CSSTextBuf()
\r
426 void CFDE_CSSTextBuf::Reset()
\r
428 if (!m_bExtBuf && m_pBuffer != NULL) {
\r
429 FDE_Free(m_pBuffer);
\r
432 m_iDatPos = m_iDatLen = m_iBufLen;
\r
434 FX_BOOL CFDE_CSSTextBuf::AttachBuffer(FX_LPCWSTR pBuffer, FX_INT32 iBufLen)
\r
437 m_pBuffer = (FX_LPWSTR)pBuffer;
\r
438 m_iDatLen = m_iBufLen = iBufLen;
\r
439 return m_bExtBuf = TRUE;
\r
441 FX_BOOL CFDE_CSSTextBuf::EstimateSize(FX_INT32 iAllocSize)
\r
443 FXSYS_assert(iAllocSize > 0);
\r
446 return ExpandBuf(iAllocSize);
\r
448 FX_INT32 CFDE_CSSTextBuf::LoadFromStream(IFX_Stream *pTxtStream, FX_INT32 iStreamOffset, FX_INT32 iMaxChars, FX_BOOL &bEOS)
\r
450 FXSYS_assert(iStreamOffset >= 0 && iMaxChars > 0);
\r
453 if (!ExpandBuf(iMaxChars)) {
\r
456 pTxtStream->Lock();
\r
457 if (pTxtStream->GetPosition() != iStreamOffset) {
\r
458 pTxtStream->Seek(FX_STREAMSEEK_Begin, iStreamOffset);
\r
460 m_iDatLen = pTxtStream->ReadString(m_pBuffer, iMaxChars, bEOS);
\r
461 pTxtStream->Unlock();
\r
464 FX_BOOL CFDE_CSSTextBuf::ExpandBuf(FX_INT32 iDesiredSize)
\r
468 } else if (m_pBuffer == NULL) {
\r
469 m_pBuffer = (FX_LPWSTR)FDE_Alloc(iDesiredSize * sizeof(FX_WCHAR));
\r
470 } else if (m_iBufLen != iDesiredSize) {
\r
471 m_pBuffer = (FX_LPWSTR)FDE_Realloc(m_pBuffer, iDesiredSize * sizeof(FX_WCHAR));
\r
475 if (m_pBuffer == NULL) {
\r
479 m_iBufLen = iDesiredSize;
\r
483 void CFDE_CSSTextBuf::Subtract(FX_INT32 iStart, FX_INT32 iLength)
\r
485 FXSYS_assert(iStart >= 0 && iLength > 0);
\r
486 if (iLength > m_iDatLen - iStart) {
\r
487 iLength = m_iDatLen - iStart;
\r
492 FXSYS_memmove(m_pBuffer, m_pBuffer + iStart, iLength * sizeof(FX_WCHAR));
\r
494 m_iDatLen = iLength;
\r