tizen beta release
[framework/web/wrt-installer.git] / src / configuration_parser / parser_runner.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /**
17  * @file        parser_runner.cpp
18  * @author      Lukasz Wrzosek (l.wrzosek@samsung.com)
19  * @version     0.1
20  * @brief
21  */
22 #include "parser_runner.h"
23 #include "root_parser.h"
24
25 #include <stack>
26 #include <libxml/xmlreader.h>
27 #include <dpl/binary_queue.h>
28 #include <dpl/assert.h>
29 #include <dpl/file_input.h>
30 #include <dpl/log/log.h>
31
32 class ParserRunner::Impl
33 {
34   public:
35     void Parse(const std::string& filename,
36             const ElementParserPtr& root)
37     {
38         DPL::FileInput input(filename);
39         Parse(&input, root);
40     }
41
42     void Parse (DPL::AbstractInput *input,
43             const ElementParserPtr& root)
44     {
45         Try
46         {
47             m_reader = xmlReaderForIO(&IoRead,
48                                       &IoClose,
49                                       input,
50                                       NULL,
51                                       NULL,
52                                       XML_PARSE_NOENT);
53
54             xmlTextReaderSetErrorHandler(m_reader,
55                                          &xmlTextReaderErrorHandler,
56                                          this);
57             xmlTextReaderSetStructuredErrorHandler(
58                 m_reader,
59                 &xmlTextReaderStructuredErrorHandler,
60                 this);
61             SetCurrentElementParser(root);
62
63             while (xmlTextReaderRead(m_reader) == 1) {
64                 switch (xmlTextReaderNodeType(m_reader)) {
65                 case XML_READER_TYPE_END_ELEMENT:
66                     VerifyAndRemoveCurrentElementParser();
67                     break;
68
69                 case XML_READER_TYPE_ELEMENT:
70                 {
71                     // Elements without closing tag don't receive
72                     // XML_READER_TYPE_END_ELEMENT event.
73                     if (IsNoClosingTagElementLeft()) {
74                         VerifyAndRemoveCurrentElementParser();
75                     }
76
77                     DPL::String elementName = GetNameWithoutNamespace();
78                     DPL::String nameSpace = GetNamespace();
79                     ElementParserPtr parser = GetCurrentElementParser();
80                     parser = parser->GetElementParser(nameSpace,
81                                                       elementName) ();
82                     Assert(!!parser);
83                     SetCurrentElementParser(parser);
84                     ParseNodeElement(parser);
85                     break;
86                 }
87                 case XML_READER_TYPE_TEXT:
88                 case XML_READER_TYPE_CDATA:
89                 {
90                     ParseNodeText(GetCurrentElementParser());
91                     break;
92                 }
93                 default:
94                     LogWarning("Ignoring Node of Type: " <<
95                                xmlTextReaderNodeType(m_reader));
96                     break;
97                 }
98
99                 if (m_parsingError) {
100                     LogError("Parsing error occured: " << m_errorMsg);
101                     ThrowMsg(ElementParser::Exception::ParseError, m_errorMsg);
102                 }
103             }
104
105             if (m_parsingError) {
106                 LogError("Parsing error occured: " << m_errorMsg);
107                 ThrowMsg(ElementParser::Exception::ParseError, m_errorMsg);
108             }
109
110             while (!m_stack.empty()) {
111                 VerifyAndRemoveCurrentElementParser();
112             }
113         }
114         Catch(ElementParser::Exception::Base)
115         {
116             CleanupParserRunner();
117             LogError(_rethrown_exception.DumpToString());
118             ReThrow(ElementParser::Exception::ParseError);
119         }
120         CleanupParserRunner();
121     }
122
123     Impl() :
124         m_reader(NULL),
125         m_parsingError(false)
126     {
127     }
128
129     ~Impl()
130     {
131         CleanupParserRunner();
132     }
133
134   private:
135     typedef std::stack<ElementParserPtr> ElementStack;
136
137   private:
138     static void xmlTextReaderErrorHandler(void* arg,
139             const char* msg,
140             xmlParserSeverities /* severity */,
141             xmlTextReaderLocatorPtr /* locator */)
142     {
143         ParserRunner::Impl* impl = static_cast<ParserRunner::Impl*>(arg);
144         impl->ErrorHandler(DPL::FromASCIIString(msg));
145     }
146
147     static void xmlTextReaderStructuredErrorHandler(void* arg,
148             xmlErrorPtr error)
149     {
150         ParserRunner::Impl* impl = static_cast<ParserRunner::Impl*>(arg);
151         impl->StructuredErrorHandler(error);
152     }
153
154     static int XMLCALL IoRead(void *context,
155             char *buffer,
156             int len)
157     {
158         DPL::AbstractInput *input = static_cast<DPL::AbstractInput *>(context);
159         DPL::BinaryQueueAutoPtr data = input->Read(static_cast<size_t>(len));
160         if (!data.get()) {
161             return -1;
162         }
163         data->Flatten(buffer, data->Size());
164         return static_cast<int>(data->Size());
165     }
166
167     static int XMLCALL IoClose(void */* context */)
168     {
169         // NOOP
170         return 0;
171     }
172
173   private:
174     void SetCurrentElementParser(const ElementParserPtr& elementParser)
175     {
176         Assert(elementParser);
177
178         m_stack.push(elementParser);
179     }
180
181     const ElementParserPtr& GetCurrentElementParser() const
182     {
183         Assert(!m_stack.empty());
184
185         return m_stack.top();
186     }
187
188     void VerifyAndRemoveCurrentElementParser()
189     {
190         Assert(!m_stack.empty());
191
192         m_stack.top()->Verify();
193         m_stack.pop();
194     }
195
196     bool IsNoClosingTagElementLeft() const
197     {
198         Assert(m_reader);
199
200         int depth = xmlTextReaderDepth(m_reader);
201         return (static_cast<int>(m_stack.size()) - 2 == depth);
202     }
203
204     void ParseNodeElement(const ElementParserPtr& parser)
205     {
206         Assert(m_reader);
207
208         Element element;
209         element.name = GetNameWithoutNamespace();
210         element.value = GetValue();
211         element.lang = GetLanguageTag();
212         element.ns = GetNamespace();
213
214         LogDebug("value: " << element.value <<
215                  ", lang: " << element.lang <<
216                  ", ns: " << element.ns << ")");
217
218         parser->Accept(element);
219         ParseNodeElementAttributes(parser);
220     }
221
222     void ParseNodeElementAttributes(const ElementParserPtr& parser)
223     {
224         Assert(m_reader);
225
226         int count = xmlTextReaderAttributeCount(m_reader);
227         for (int i = 0; i < count; ++i) {
228             xmlTextReaderMoveToAttributeNo(m_reader, i);
229
230             XmlAttribute attribute;
231             attribute.name = GetName();
232             attribute.value = GetValue();
233             attribute.lang = GetLanguageTag();
234             LogDebug("Attribute name: " << attribute.name <<
235                      ", value: " << attribute.value <<
236                      ", lang: " << attribute.lang);
237             parser->Accept(attribute);
238         }
239     }
240
241     void ParseNodeText(const ElementParserPtr& parser)
242     {
243         Text text;
244         text.value = GetValue();
245         text.lang = GetLanguageTag();
246         parser->Accept(text);
247     }
248
249     DPL::String GetValue() const
250     {
251         DPL::String ret_value;
252         const xmlChar* value = xmlTextReaderConstValue(m_reader);
253         if (value) {
254             ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
255         }
256
257         return ret_value;
258     }
259
260     DPL::String GetAttributeValue(int pos) const
261     {
262         DPL::String ret_value;
263         const xmlChar* value = xmlTextReaderGetAttributeNo(m_reader, pos);
264         if (value) {
265             ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
266         }
267         xmlFree(const_cast<xmlChar*>(value));
268
269         return ret_value;
270     }
271
272     DPL::String GetName() const
273     {
274         DPL::String ret_value;
275         const xmlChar* value = xmlTextReaderConstName(m_reader);
276         if (value) {
277             ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
278         }
279
280         return ret_value;
281     }
282
283     DPL::String GetNameWithoutNamespace() const
284     {
285         DPL::String ret_value;
286         const xmlChar* value = xmlTextReaderLocalName(m_reader);
287         if (value) {
288             ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
289         }
290
291         return ret_value;
292     }
293
294     DPL::String GetNamespace() const
295     {
296         DPL::String ret_value;
297         const xmlChar* value = xmlTextReaderConstNamespaceUri(m_reader);
298         if (value) {
299             ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
300         }
301
302         return ret_value;
303     }
304
305     DPL::String GetLanguageTag() const
306     {
307         DPL::String ret_value;
308         const xmlChar* value = xmlTextReaderConstXmlLang(m_reader);
309         if (value) {
310             ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
311         }
312
313         return ret_value;
314     }
315
316     void ErrorHandler(const DPL::String& msg)
317     {
318         LogError("LibXML:  " << msg);
319         m_parsingError = true;
320         m_errorMsg = m_errorMsg + DPL::FromASCIIString("\n");
321         m_errorMsg = m_errorMsg + msg;
322     }
323
324     void StructuredErrorHandler(xmlErrorPtr error)
325     {
326         LogError("LibXML:  " << error->message);
327         m_parsingError = true;
328         m_errorMsg = m_errorMsg + DPL::FromASCIIString("\n");
329         m_errorMsg = m_errorMsg + DPL::FromUTF8String(error->message);
330     }
331
332     void CleanupParserRunner()
333     {
334         while (!m_stack.empty()) {
335             m_stack.pop();
336         }
337         if (m_reader) {
338             xmlFreeTextReader(m_reader);
339         }
340         m_reader = NULL;
341     }
342
343   private:
344     xmlTextReaderPtr m_reader;
345     ElementStack m_stack;
346     bool m_parsingError;
347     DPL::String m_errorMsg;
348 };
349
350 ParserRunner::ParserRunner() :
351     m_impl(new ParserRunner::Impl())
352 {
353 }
354
355 void ParserRunner::Parse(const std::string& filename,
356         ElementParserPtr root)
357 {
358     m_impl->Parse(filename, root);
359 }
360
361 void ParserRunner::Parse(DPL::AbstractInput *input,
362         ElementParserPtr root)
363 {
364     m_impl->Parse(input, root);
365 }
366
367 ParserRunner::~ParserRunner()
368 {
369     delete m_impl;
370 }