53c1f4b53f26662a34fb4340344960a0dfb979df
[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.value = GetValue();
210         element.lang = GetLanguageTag();
211         element.ns = GetNamespace();
212
213         LogDebug("value: " << element.value <<
214                  ", lang: " << element.lang <<
215                  ", ns: " << element.ns << ")");
216
217         parser->Accept(element);
218         ParseNodeElementAttributes(parser);
219     }
220
221     void ParseNodeElementAttributes(const ElementParserPtr& parser)
222     {
223         Assert(m_reader);
224
225         int count = xmlTextReaderAttributeCount(m_reader);
226         for (int i = 0; i < count; ++i) {
227             xmlTextReaderMoveToAttributeNo(m_reader, i);
228
229             XmlAttribute attribute;
230             attribute.ns = GetAttributeNamespace();
231             attribute.name = GetNameWithoutNamespace();
232             attribute.value = GetValue();
233             attribute.lang = GetLanguageTag();
234             LogDebug("Attribute name: " << attribute.name <<
235                      ", value: " << attribute.value <<
236                      ", namespace: " << attribute.ns <<
237                      ", lang: " << attribute.lang);
238             parser->Accept(attribute);
239         }
240     }
241
242     void ParseNodeText(const ElementParserPtr& parser)
243     {
244         Text text;
245         text.value = GetValue();
246         text.lang = GetLanguageTag();
247         parser->Accept(text);
248     }
249
250     DPL::String GetValue() const
251     {
252         DPL::String ret_value;
253         const xmlChar* value = xmlTextReaderConstValue(m_reader);
254         if (value) {
255             ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
256         }
257
258         return ret_value;
259     }
260
261     DPL::String GetAttributeValue(int pos) const
262     {
263         DPL::String ret_value;
264         const xmlChar* value = xmlTextReaderGetAttributeNo(m_reader, pos);
265         if (value) {
266             ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
267         }
268         xmlFree(const_cast<xmlChar*>(value));
269
270         return ret_value;
271     }
272
273     DPL::String GetAttributeNamespace() const
274     {
275         DPL::String ret_value;
276         const xmlChar* value = xmlTextReaderLookupNamespace(m_reader, NULL);
277         if (value) {
278             ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
279         }
280         xmlFree(const_cast<xmlChar*>(value));
281
282         return ret_value;
283     }
284
285     DPL::String GetName() const
286     {
287         DPL::String ret_value;
288         const xmlChar* value = xmlTextReaderConstName(m_reader);
289         if (value) {
290             ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
291         }
292
293         return ret_value;
294     }
295
296     DPL::String GetNameWithoutNamespace() const
297     {
298         DPL::String ret_value;
299         const xmlChar* value = xmlTextReaderLocalName(m_reader);
300         if (value) {
301             ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
302         }
303
304         return ret_value;
305     }
306
307     DPL::String GetNamespace() const
308     {
309         DPL::String ret_value;
310
311         const xmlChar* value = xmlTextReaderConstNamespaceUri(m_reader);
312         if (value) {
313             ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
314         }
315
316         return ret_value;
317     }
318
319     DPL::String GetLanguageTag() const
320     {
321         DPL::String ret_value;
322         const xmlChar* value = xmlTextReaderConstXmlLang(m_reader);
323         if (value) {
324             ret_value = DPL::FromUTF8String(reinterpret_cast<const char*>(value));
325         }
326
327         return ret_value;
328     }
329
330     void ErrorHandler(const DPL::String& msg)
331     {
332         LogError("LibXML:  " << msg);
333         m_parsingError = true;
334         m_errorMsg = m_errorMsg + DPL::FromASCIIString("\n");
335         m_errorMsg = m_errorMsg + msg;
336     }
337
338     void StructuredErrorHandler(xmlErrorPtr error)
339     {
340         LogError("LibXML:  " << error->message);
341         m_parsingError = true;
342         m_errorMsg = m_errorMsg + DPL::FromASCIIString("\n");
343         m_errorMsg = m_errorMsg + DPL::FromUTF8String(error->message);
344     }
345
346     void CleanupParserRunner()
347     {
348         while (!m_stack.empty()) {
349             m_stack.pop();
350         }
351         if (m_reader) {
352             xmlFreeTextReader(m_reader);
353         }
354         m_reader = NULL;
355     }
356
357   private:
358     xmlTextReaderPtr m_reader;
359     ElementStack m_stack;
360     bool m_parsingError;
361     DPL::String m_errorMsg;
362 };
363
364 ParserRunner::ParserRunner() :
365     m_impl(new ParserRunner::Impl())
366 {
367 }
368
369 void ParserRunner::Parse(const std::string& filename,
370         ElementParserPtr root)
371 {
372     m_impl->Parse(filename, root);
373 }
374
375 void ParserRunner::Parse(DPL::AbstractInput *input,
376         ElementParserPtr root)
377 {
378     m_impl->Parse(input, root);
379 }
380
381 ParserRunner::~ParserRunner()
382 {
383     delete m_impl;
384 }