OSDN Git Service

compiler-calculated maximum value for `m_SourceDefs` (#966)
[winmerge-jp/winmerge-jp.git] / Externals / crystaledit / editlib / parsers / xml.cpp
1 ///////////////////////////////////////////////////////////////////////////
2 //  File:    xml.cpp
3 //  Version: 1.1.0.4
4 //  Updated: 19-Jul-1998
5 //
6 //  Copyright:  Ferdinand Prantl, portions by Stcherbatchenko Andrei
7 //  E-mail:     prantl@ff.cuni.cz
8 //
9 //  XML syntax highlighing definition
10 //
11 //  You are free to use or modify this code to the following restrictions:
12 //  - Acknowledge me somewhere in your about box, simple "Parts of code by.."
13 //  will be enough. If you can't (or don't want to), contact me personally.
14 //  - LEAVE THIS HEADER INTACT
15 ////////////////////////////////////////////////////////////////////////////
16
17 #include "StdAfx.h"
18 #include "crystallineparser.h"
19 #include "../SyntaxColors.h"
20 #include "../utils/string_util.h"
21
22 #ifdef _DEBUG
23 #define new DEBUG_NEW
24 #endif
25
26 //  C++ keywords (MSVC5.0 + POET5.0)
27 static const TCHAR * s_apszXmlKeywordList[] =
28   {
29     _T ("ATTLIST"),
30     _T ("DOCTYPE"),
31     _T ("ELEMENT"),
32     _T ("ENTITY"),
33     _T ("NOTATION"),
34     _T ("xml"),
35   };
36
37 static const TCHAR * s_apszUser1KeywordList[] =
38   {
39     _T ("#FIXED"),
40     _T ("#IMPLIED"),
41     _T ("#REQUIRED"),
42     _T ("ANY"),
43     _T ("CDATA"),
44     _T ("EMPTY"),
45     _T ("ENTITIES"),
46     _T ("ENTITY"),
47     _T ("ID"),
48     _T ("IDREF"),
49     _T ("IDREFS"),
50     _T ("IGNORE"),
51     _T ("INCLUDE"),
52     _T ("NDATA"),
53     _T ("NMTOKEN"),
54     _T ("NMTOKENS"),
55     _T ("PCDATA"),
56     _T ("PUBLIC"),
57     _T ("SYSTEM"),
58     _T ("encoding"),
59     _T ("standalone"),
60     _T ("version"),
61   };
62
63 static bool
64 IsXmlKeyword (const TCHAR *pszChars, int nLength)
65 {
66   return ISXKEYWORDI (s_apszXmlKeywordList, pszChars, nLength);
67 }
68
69 static bool
70 IsUser1Keyword (const TCHAR *pszChars, int nLength)
71 {
72   return ISXKEYWORDI (s_apszUser1KeywordList, pszChars, nLength);
73 }
74
75 unsigned
76 CrystalLineParser::ParseLineXml (unsigned dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems)
77 {
78   if (nLength == 0)
79     return dwCookie & COOKIE_EXT_COMMENT;
80
81   bool bRedefineBlock = true;
82   bool bDecIndex = false;
83   int nIdentBegin = -1;
84   int nPrevI = -1;
85   int I=0;
86   for (I = 0;; nPrevI = I, I = static_cast<int>(::CharNext(pszChars+I) - pszChars))
87     {
88       if (I == nPrevI)
89         {
90           // CharNext did not advance, so we're at the end of the string
91           // and we already handled this character, so stop
92           break;
93         }
94
95       if (bRedefineBlock)
96         {
97           int nPos = I;
98           if (bDecIndex)
99             nPos = nPrevI;
100           if (dwCookie & (COOKIE_COMMENT | COOKIE_EXT_COMMENT))
101             {
102               DEFINE_BLOCK (nPos, COLORINDEX_COMMENT);
103             }
104           else if (dwCookie & (COOKIE_CHAR | COOKIE_STRING))
105             {
106               DEFINE_BLOCK (nPos, COLORINDEX_STRING);
107             }
108           else if (dwCookie & COOKIE_PREPROCESSOR)
109             {
110               DEFINE_BLOCK (nPos, COLORINDEX_PREPROCESSOR);
111             }
112           else
113             {
114               if (xisalnum (pszChars[nPos]) || pszChars[nPos] == '.')
115                 {
116                   DEFINE_BLOCK (nPos, COLORINDEX_NORMALTEXT);
117                 }
118               else
119                 {
120                   DEFINE_BLOCK (nPos, COLORINDEX_OPERATOR);
121                   bRedefineBlock = true;
122                   bDecIndex = true;
123                   goto out;
124                 }
125             }
126           bRedefineBlock = false;
127           bDecIndex = false;
128         }
129 out:
130
131       // Can be bigger than length if there is binary data
132       // See bug #1474782 Crash when comparing SQL with with binary data
133       if (I >= nLength || pszChars[I] == 0)
134         break;
135
136       if (dwCookie & COOKIE_COMMENT)
137         {
138           DEFINE_BLOCK (I, COLORINDEX_COMMENT);
139           dwCookie |= COOKIE_COMMENT;
140           break;
141         }
142
143       //  String constant "...."
144       if (dwCookie & COOKIE_STRING)
145         {
146           if (pszChars[I] == '"')
147             {
148               dwCookie &= ~COOKIE_STRING;
149               bRedefineBlock = true;
150             }
151           continue;
152         }
153
154       //  Char constant '..'
155       if (dwCookie & COOKIE_CHAR)
156         {
157           if (pszChars[I] == '\'')
158             {
159               dwCookie &= ~COOKIE_CHAR;
160               bRedefineBlock = true;
161             }
162           continue;
163         }
164
165       //  Extended comment <!--....-->
166       if (dwCookie & COOKIE_EXT_COMMENT)
167         {
168           if (I > 1 && pszChars[I] == '>' && pszChars[nPrevI] == '-' && *::CharPrev(pszChars, pszChars + nPrevI) == '-')
169             {
170               dwCookie &= ~COOKIE_EXT_COMMENT;
171               bRedefineBlock = true;
172             }
173           continue;
174         }
175
176       //  Extended comment <?....?>
177       if (dwCookie & COOKIE_EXT_USER1)
178         {
179           if (I > 0 && pszChars[I] == '>' && pszChars[nPrevI] == '?')
180             {
181               dwCookie &= ~COOKIE_EXT_USER1;
182               bRedefineBlock = true;
183             }
184           continue;
185         }
186
187       //  Normal text
188       if (pszChars[I] == '"')
189         {
190           DEFINE_BLOCK (I, COLORINDEX_STRING);
191           dwCookie |= COOKIE_STRING;
192           continue;
193         }
194       if (pszChars[I] == '\'')
195         {
196           // if (I + 1 < nLength && pszChars[I + 1] == '\'' || I + 2 < nLength && pszChars[I + 1] != '\\' && pszChars[I + 2] == '\'' || I + 3 < nLength && pszChars[I + 1] == '\\' && pszChars[I + 3] == '\'')
197           if (!I || !xisalnum (pszChars[nPrevI]))
198             {
199               DEFINE_BLOCK (I, COLORINDEX_STRING);
200               dwCookie |= COOKIE_CHAR;
201               continue;
202             }
203         }
204       if (!(dwCookie & COOKIE_EXT_USER1) && I < nLength - 3 && pszChars[I] == '<' && pszChars[I + 1] == '!' && pszChars[I + 2] == '-' && pszChars[I + 3] == '-')
205         {
206           DEFINE_BLOCK (I, COLORINDEX_COMMENT);
207           I += 3;
208           dwCookie |= COOKIE_EXT_COMMENT;
209           dwCookie &= ~COOKIE_PREPROCESSOR;
210           continue;
211         }
212
213       if (pBuf == nullptr)
214         continue;               //  We don't need to extract keywords,
215       //  for faster parsing skip the rest of loop
216
217       if (xisalnum (pszChars[I]) || pszChars[I] == '.')
218         {
219           if (nIdentBegin == -1)
220             nIdentBegin = I;
221         }
222       else
223         {
224           if (nIdentBegin >= 0)
225             {
226               if (dwCookie & COOKIE_PREPROCESSOR)
227                 {
228                   if (IsXmlKeyword (pszChars + nIdentBegin, I - nIdentBegin))
229                     {
230                       DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
231                     }
232                   else if (IsUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
233                     {
234                       DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
235                     }
236                   else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
237                     {
238                       DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
239                     }
240                   else
241                     {
242                       goto next;
243                     }
244                 }
245               else if (dwCookie & COOKIE_USER1)
246                 {
247                   if (IsHtmlUser2Keyword (pszChars + nIdentBegin, I - nIdentBegin))
248                     {
249                       DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER2);
250                     }
251                   else
252                     {
253                       goto next;
254                     }
255                 }
256               else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
257                 {
258                   DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
259                 }
260               else
261                 {
262                   goto next;
263                 }
264               bRedefineBlock = true;
265               bDecIndex = true;
266               nIdentBegin = -1;
267 next:
268               ;
269             }
270           //  Preprocessor start: < or bracket
271           if (!(dwCookie & COOKIE_EXT_USER1) && pszChars[I] == '<' && !(I < nLength - 3 && pszChars[I + 1] == '!' && pszChars[I + 2] == '-' && pszChars[I + 3] == '-') || pszChars[I] == '{')
272             {
273               DEFINE_BLOCK (I, COLORINDEX_PREPROCESSOR);
274               dwCookie |= COOKIE_PREPROCESSOR;
275               nIdentBegin = -1;
276               continue;
277             }
278
279           //  Preprocessor end: > or bracket
280           if (dwCookie & COOKIE_PREPROCESSOR)
281             {
282               if (pszChars[I] == '>' || pszChars[I] == '}')
283                 {
284                   dwCookie &= ~COOKIE_PREPROCESSOR;
285                   nIdentBegin = -1;
286                   bRedefineBlock = true;
287                   continue;
288                 }
289             }
290           //  Preprocessor start: &
291           if (pszChars[I] == '&')
292             {
293               dwCookie |= COOKIE_USER1;
294               nIdentBegin = -1;
295               continue;
296             }
297
298           //  Preprocessor end: ;
299           if (dwCookie & COOKIE_USER1)
300             {
301               if (pszChars[I] == ';')
302                 {
303                   dwCookie &= ~COOKIE_USER1;
304                   nIdentBegin = -1;
305                   continue;
306                 }
307             }
308         }
309     }
310
311   if (nIdentBegin >= 0 && (dwCookie & COOKIE_PREPROCESSOR))
312     {
313       if (IsXmlKeyword (pszChars + nIdentBegin, I - nIdentBegin))
314         {
315           DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
316         }
317       else if (IsUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
318         {
319           DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
320         }
321       else if (IsHtmlUser2Keyword (pszChars + nIdentBegin, I - nIdentBegin))
322         {
323           DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER2);
324         }
325       else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
326         {
327           DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
328         }
329     }
330   //  Preprocessor start: < or {
331   if (!(dwCookie & COOKIE_EXT_USER1) && pszChars[I] == '<' && !(I < nLength - 3 && pszChars[I + 1] == '!' && pszChars[I + 2] == '-' && pszChars[I + 3] == '-') || pszChars[I] == '{')
332     {
333       DEFINE_BLOCK (I + 1, COLORINDEX_PREPROCESSOR);
334       dwCookie |= COOKIE_PREPROCESSOR;
335       nIdentBegin = -1;
336       goto end;
337     }
338
339   //  Preprocessor end: > or }
340   if (dwCookie & COOKIE_PREPROCESSOR)
341     {
342       if (pszChars[I] == '>' || pszChars[I] == '}')
343         {
344           dwCookie &= ~COOKIE_PREPROCESSOR;
345           nIdentBegin = -1;
346         }
347     }
348 end:
349   dwCookie &= (COOKIE_EXT_COMMENT | COOKIE_STRING | COOKIE_PREPROCESSOR | COOKIE_EXT_USER1);
350   return dwCookie;
351 }