liyujie
2025-08-28 786ff4f4ca2374bdd9177f2e24b503d43e7a3b93
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
#ifndef _XEXMLPARSER_HPP
#define _XEXMLPARSER_HPP
/*-------------------------------------------------------------------------
 * drawElements Quality Program Test Executor
 * ------------------------------------------
 *
 * Copyright 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief XML Parser.
 *
 * \todo [2012-06-07 pyry] Not supported / handled properly:
 *  - xml namespaces (<ns:Element>)
 *  - backslash escapes in strings
 *  - &quot; -style escapes
 *  - utf-8
 *//*--------------------------------------------------------------------*/
 
#include "xeDefs.hpp"
#include "deRingBuffer.hpp"
 
#include <string>
#include <map>
 
namespace xe
{
namespace xml
{
 
enum Token
{
   TOKEN_INCOMPLETE = 0,                    //!< Not enough data to determine token.
   TOKEN_END_OF_STRING,                    //!< End of document string.
   TOKEN_DATA,                                //!< Block of data (anything outside tags).
   TOKEN_COMMENT,                            //!< <!-- comment -->
   TOKEN_IDENTIFIER,                        //!< Identifier (in tags).
   TOKEN_STRING,                            //!< String (in tags).
   TOKEN_TAG_START,                        //!< <
   TOKEN_TAG_END,                            //!< >
   TOKEN_END_TAG_START,                    //!< </
   TOKEN_EMPTY_ELEMENT_END,                //!< />
   TOKEN_PROCESSING_INSTRUCTION_START,        //!< <?
   TOKEN_PROCESSING_INSTRUCTION_END,        //!< ?>
   TOKEN_EQUAL,                            //!< =
   TOKEN_ENTITY,                            //!< Entity reference, such as &amp;
 
   TOKEN_LAST
};
 
enum Element
{
   ELEMENT_INCOMPLETE = 0,    //!< Incomplete element.
   ELEMENT_START,            //!< Element start.
   ELEMENT_END,            //!< Element end.
   ELEMENT_DATA,            //!< Data element.
   ELEMENT_END_OF_STRING,    //!< End of document string.
 
   ELEMENT_LAST
};
 
const char* getTokenName (Token token);
 
// \todo [2012-10-17 pyry] Add line number etc.
class ParseError : public xe::ParseError
{
public:
   ParseError (const std::string& message) : xe::ParseError(message) {}
};
 
class Tokenizer
{
public:
                       Tokenizer            (void);
                       ~Tokenizer            (void);
 
   void                clear                (void);        //!< Resets tokenizer to initial state.
 
   void                feed                (const deUint8* bytes, int numBytes);
   void                advance                (void);
 
   Token                getToken            (void) const        { return m_curToken;    }
   int                    getTokenLen            (void) const        { return m_curTokenLen;    }
   deUint8                getTokenByte        (int offset) const    { DE_ASSERT(m_curToken != TOKEN_INCOMPLETE && m_curToken != TOKEN_END_OF_STRING); return m_buf.peekBack(offset); }
   void                getTokenStr            (std::string& dst) const;
   void                appendTokenStr        (std::string& dst) const;
 
   void                getString            (std::string& dst) const;
 
private:
                       Tokenizer            (const Tokenizer& other);
   Tokenizer&            operator=            (const Tokenizer& other);
 
   int                    getChar                (int offset) const;
 
   void                error                (const std::string& what);
 
   enum State
   {
       STATE_DATA = 0,
       STATE_TAG,
       STATE_IDENTIFIER,
       STATE_VALUE,
       STATE_COMMENT,
       STATE_ENTITY,
 
       STATE_LAST
   };
 
   enum
   {
       END_OF_STRING    = 0,            //!< End of string (0).
       END_OF_BUFFER    = 0xffffffff    //!< End of current data buffer.
   };
 
   Token                        m_curToken;            //!< Current token.
   int                            m_curTokenLen;        //!< Length of current token.
 
   State                        m_state;            //!< Tokenization state.
 
   de::RingBuffer<deUint8>        m_buf;
};
 
class Parser
{
public:
   typedef std::map<std::string, std::string>        AttributeMap;
   typedef AttributeMap::const_iterator            AttributeIter;
 
                       Parser                (void);
                       ~Parser                (void);
 
   void                clear                (void);        //!< Resets parser to initial state.
 
   void                feed                (const deUint8* bytes, int numBytes);
   void                advance                (void);
 
   Element                getElement            (void) const                        { return m_element;                                        }
 
   // For ELEMENT_START / ELEMENT_END.
   const char*            getElementName        (void) const                        { return m_elementName.c_str();                            }
 
   // For ELEMENT_START.
   bool                hasAttribute        (const char* name) const            { return m_attributes.find(name) != m_attributes.end();    }
   const char*            getAttribute        (const char* name) const            { return m_attributes.find(name)->second.c_str();        }
   const AttributeMap&    attributes            (void) const                        { return m_attributes;                                    }
 
   // For ELEMENT_DATA.
   int                    getDataSize            (void) const;
   deUint8                getDataByte            (int offset) const;
   void                getDataStr            (std::string& dst) const;
   void                appendDataStr        (std::string& dst) const;
 
private:
                       Parser                (const Parser& other);
   Parser&                operator=            (const Parser& other);
 
   void                parseEntityValue    (void);
 
   void                error                (const std::string& what);
 
   enum State
   {
       STATE_DATA = 0,                        //!< Initial state - assuming data or tag open.
       STATE_ENTITY,                        //!< Parsed entity is stored - overrides data.
       STATE_IN_PROCESSING_INSTRUCTION,    //!< In processing instruction.
       STATE_START_TAG_OPEN,                //!< Start tag open.
       STATE_END_TAG_OPEN,                    //!< End tag open.
       STATE_EXPECTING_END_TAG_CLOSE,        //!< Expecting end tag close.
       STATE_ATTRIBUTE_LIST,                //!< Expecting attribute list.
       STATE_EXPECTING_ATTRIBUTE_EQ,        //!< Got attribute name, expecting =.
       STATE_EXPECTING_ATTRIBUTE_VALUE,    //!< Expecting attribute value.
       STATE_YIELD_EMPTY_ELEMENT_END,        //!< Empty element: start has been reported but not end.
 
       STATE_LAST
   };
 
   Tokenizer            m_tokenizer;
 
   Element                m_element;
   std::string            m_elementName;
   AttributeMap        m_attributes;
 
   State                m_state;
   std::string            m_attribName;
   std::string            m_entityValue;        //!< Data override, such as entity value.
};
 
// Inline implementations
 
inline void Tokenizer::getTokenStr (std::string& dst) const
{
   DE_ASSERT(m_curToken != TOKEN_INCOMPLETE && m_curToken != TOKEN_END_OF_STRING);
   dst.resize(m_curTokenLen);
   for (int ndx = 0; ndx < m_curTokenLen; ndx++)
       dst[ndx] = m_buf.peekBack(ndx);
}
 
inline void Tokenizer::appendTokenStr (std::string& dst) const
{
   DE_ASSERT(m_curToken != TOKEN_INCOMPLETE && m_curToken != TOKEN_END_OF_STRING);
 
   size_t oldLen = dst.size();
   dst.resize(oldLen+m_curTokenLen);
 
   for (int ndx = 0; ndx < m_curTokenLen; ndx++)
       dst[oldLen+ndx] = m_buf.peekBack(ndx);
}
 
inline int Parser::getDataSize (void) const
{
   if (m_state != STATE_ENTITY)
       return m_tokenizer.getTokenLen();
   else
       return (int)m_entityValue.size();
}
 
inline deUint8 Parser::getDataByte (int offset) const
{
   if (m_state != STATE_ENTITY)
       return m_tokenizer.getTokenByte(offset);
   else
       return (deUint8)m_entityValue[offset];
}
 
inline void Parser::getDataStr (std::string& dst) const
{
   if (m_state != STATE_ENTITY)
       return m_tokenizer.getTokenStr(dst);
   else
       dst = m_entityValue;
}
 
inline void Parser::appendDataStr (std::string& dst) const
{
   if (m_state != STATE_ENTITY)
       return m_tokenizer.appendTokenStr(dst);
   else
       dst += m_entityValue;
}
 
} // xml
} // xe
 
#endif // _XEXMLPARSER_HPP