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