tizen 2.4 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 #include "stdio.h"
25
26 #include <stack>
27 #include <libxml/xmlreader.h>
28 #include <dpl/binary_queue.h>
29 #include <dpl/assert.h>
30 #include <dpl/file_input.h>
31 #include <dpl/log/secure_log.h>
32
33 class ParserRunner::Impl
34 {
35     static void logErrorLibxml2(void *, const char *msg, ...)
36     {
37         char buffer[300];
38         va_list args;
39         va_start(args, msg);
40         vsnprintf(buffer, 300, msg, args);
41         va_end(args);
42         _E("%s", buffer);
43     }
44
45     static void logWarningLibxml2(void *, const char *msg, ...)
46     {
47         char buffer[300];
48         va_list args;
49         va_start(args, msg);
50         vsnprintf(buffer, 300, msg, args);
51         va_end(args);
52         _W("%s", buffer);
53     }
54
55   public:
56     bool Validate(const std::string& filename, const std::string& schema)
57     {
58         int ret = -1;
59         xmlSchemaParserCtxtPtr ctx;
60         xmlSchemaValidCtxtPtr vctx;
61         xmlSchemaPtr xschema;
62         ctx = xmlSchemaNewParserCtxt(schema.c_str());
63         if (ctx == NULL) {
64             _E("xmlSchemaNewParserCtxt() Failed");
65             return false;
66         }
67         xschema = xmlSchemaParse(ctx);
68         if (xschema == NULL) {
69             _E("xmlSchemaParse() Failed");
70             return false;
71         }
72         vctx = xmlSchemaNewValidCtxt(xschema);
73         if (vctx == NULL) {
74             _E("xmlSchemaNewValidCtxt() Failed");
75             return false;
76         }
77         xmlSchemaSetValidErrors(vctx, (xmlSchemaValidityErrorFunc)&logErrorLibxml2, (xmlSchemaValidityWarningFunc) &logWarningLibxml2, NULL);
78         ret = xmlSchemaValidateFile(vctx, filename.c_str(), 0);
79         if (ret == -1) {
80             _E("xmlSchemaValidateFile() failed");
81             return false;
82         } else if (ret == 0) {
83             _E("Config is Valid");
84             return true;
85         } else {
86             _E("Config Validation Failed with error code %d", ret);
87             return false;
88         }
89     }
90
91     void Parse(const std::string& filename,
92                const ElementParserPtr& root)
93     {
94         DPL::FileInput input(filename);
95         Parse(&input, root);
96     }
97
98     void Parse (DPL::AbstractInput *input,
99                 const ElementParserPtr& root)
100     {
101         Try
102         {
103             m_reader = xmlReaderForIO(&IoRead,
104                                       &IoClose,
105                                       input,
106                                       NULL,
107                                       NULL,
108                                       XML_PARSE_NOENT);
109
110             if (m_reader == NULL) {
111                 _E("xmlReaderForIO() is failed");
112                 ThrowMsg(ElementParser::Exception::ParseError, "xmlReaderForIO() is failed");
113             }
114
115             xmlTextReaderSetErrorHandler(m_reader,
116                                          &xmlTextReaderErrorHandler,
117                                          this);
118             xmlTextReaderSetStructuredErrorHandler(
119                 m_reader,
120                 &xmlTextReaderStructuredErrorHandler,
121                 this);
122             SetCurrentElementParser(root);
123
124             while (xmlTextReaderRead(m_reader) == 1) {
125                 switch (xmlTextReaderNodeType(m_reader)) {
126                 case XML_READER_TYPE_END_ELEMENT:
127                     VerifyAndRemoveCurrentElementParser();
128                     break;
129
130                 case XML_READER_TYPE_ELEMENT:
131                 {
132                     // Elements without closing tag don't receive
133                     // XML_READER_TYPE_END_ELEMENT event.
134                     if (IsNoClosingTagElementLeft()) {
135                         VerifyAndRemoveCurrentElementParser();
136                     }
137
138                     DPL::String elementName = GetNameWithoutNamespace();
139                     DPL::String nameSpace = GetNamespace();
140                     ElementParserPtr parser = GetCurrentElementParser();
141                     parser = parser->GetElementParser(nameSpace,
142                                                       elementName) ();
143                     Assert(!!parser);
144                     SetCurrentElementParser(parser);
145                     ParseNodeElement(parser);
146                     break;
147                 }
148                 case XML_READER_TYPE_TEXT:
149                 case XML_READER_TYPE_CDATA:
150                 {
151                     ParseNodeText(GetCurrentElementParser());
152                     break;
153                 }
154                 default:
155                     _W("Ignoring Node of Type: %d", xmlTextReaderNodeType(m_reader));
156                     break;
157                 }
158
159                 if (m_parsingError) {
160                     _E("Parsing error occured: %ls", m_errorMsg.c_str());
161                     ThrowMsg(ElementParser::Exception::ParseError, m_errorMsg);
162                 }
163             }
164
165             if (m_parsingError) {
166                 _E("Parsing error occured: %ls", m_errorMsg.c_str());
167                 ThrowMsg(ElementParser::Exception::ParseError, m_errorMsg);
168             }
169
170             while (!m_stack.empty()) {
171                 VerifyAndRemoveCurrentElementParser();
172             }
173         }
174         Catch(ElementParser::Exception::Base)
175         {
176             CleanupParserRunner();
177             _E("%s", _rethrown_exception.DumpToString().c_str());
178             ReThrow(ElementParser::Exception::ParseError);
179         }
180         CleanupParserRunner();
181     }
182
183     Impl() :
184         m_reader(NULL),
185         m_parsingError(false)
186     {}
187
188     ~Impl()
189     {
190         CleanupParserRunner();
191     }
192
193   private:
194     typedef std::stack<ElementParserPtr> ElementStack;
195
196   private:
197     static void xmlTextReaderErrorHandler(void* arg,
198                                           const char* msg,
199                                           xmlParserSeverities /* severity */,
200                                           xmlTextReaderLocatorPtr /* locator */)
201     {
202         ParserRunner::Impl* impl = static_cast<ParserRunner::Impl*>(arg);
203         impl->ErrorHandler(DPL::FromASCIIString(msg));
204     }
205
206     static void xmlTextReaderStructuredErrorHandler(void* arg,
207                                                     xmlErrorPtr error)
208     {
209         ParserRunner::Impl* impl = static_cast<ParserRunner::Impl*>(arg);
210         impl->StructuredErrorHandler(error);
211     }
212
213     static int XMLCALL IoRead(void *context,
214                               char *buffer,
215                               int len)
216     {
217         DPL::AbstractInput *input = static_cast<DPL::AbstractInput *>(context);
218         DPL::BinaryQueueAutoPtr data = input->Read(static_cast<size_t>(len));
219         if (!data.get()) {
220             return -1;
221         }
222         data->Flatten(buffer, data->Size());
223         return static_cast<int>(data->Size());
224     }
225
226     static int XMLCALL IoClose(void */* context */)
227     {
228         // NOOP
229         return 0;
230     }
231
232   private:
233     void SetCurrentElementParser(const ElementParserPtr& elementParser)
234     {
235         Assert(elementParser);
236
237         m_stack.push(elementParser);
238     }
239
240     const ElementParserPtr& GetCurrentElementParser() const
241     {
242         Assert(!m_stack.empty());
243
244         return m_stack.top();
245     }
246
247     void VerifyAndRemoveCurrentElementParser()
248     {
249         Assert(!m_stack.empty());
250
251         m_stack.top()->Verify();
252         m_stack.pop();
253     }
254
255     bool IsNoClosingTagElementLeft() const
256     {
257         Assert(m_reader);
258
259         int depth = xmlTextReaderDepth(m_reader);
260         return (static_cast<int>(m_stack.size()) - 2 == depth);
261     }
262
263     void ParseNodeElement(const ElementParserPtr& parser)
264     {
265         Assert(m_reader);
266
267         Element element;
268         element.name = GetName();
269         element.value = GetValue();
270         element.lang = GetLanguageTag();
271         element.ns = GetNamespace();
272
273         _D("value: %ls, lang: %ls, ns: %ls",
274             element.value.c_str(), element.lang.c_str(), element.ns.c_str());
275
276         parser->Accept(element);
277         ParseNodeElementAttributes(parser);
278     }
279
280     void ParseNodeElementAttributes(const ElementParserPtr& parser)
281     {
282         Assert(m_reader);
283         int count = xmlTextReaderAttributeCount(m_reader);
284         for (int i = 0; i < count; ++i) {
285             xmlTextReaderMoveToAttributeNo(m_reader, i);
286
287             XmlAttribute attribute;
288             attribute.ns = GetAttributeNamespace();
289             attribute.prefix = GetNamePrefix();
290             attribute.name = GetNameWithoutNamespace();
291             attribute.value = GetValue();
292             attribute.lang = GetLanguageTag();
293             _D("Attribute name: %s, value: %s, prefix: %s, namespace: %s, lang: %s",
294                 DPL::ToUTF8String(attribute.name).c_str(), DPL::ToUTF8String(attribute.value).c_str(),
295                 DPL::ToUTF8String(attribute.prefix).c_str(), DPL::ToUTF8String(attribute.ns).c_str(),
296                 DPL::ToUTF8String(attribute.lang).c_str());
297             parser->Accept(attribute);
298         }
299     }
300
301     void ParseNodeText(const ElementParserPtr& parser)
302     {
303         Text text;
304         text.value = GetValue();
305         text.lang = GetLanguageTag();
306         parser->Accept(text);
307     }
308
309     DPL::String GetValue() const
310     {
311         DPL::String ret_value;
312         const xmlChar* value = xmlTextReaderConstValue(m_reader);
313         if (value) {
314             ret_value =
315                 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
316         }
317
318         return ret_value;
319     }
320
321     DPL::String GetAttributeValue(int pos) const
322     {
323         DPL::String ret_value;
324         const xmlChar* value = xmlTextReaderGetAttributeNo(m_reader, pos);
325         if (value) {
326             ret_value =
327                 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
328         }
329         xmlFree(const_cast<xmlChar*>(value));
330
331         return ret_value;
332     }
333
334     DPL::String GetAttributeNamespace() const
335     {
336         DPL::String ret_value;
337         const xmlChar* value = xmlTextReaderLookupNamespace(m_reader, NULL);
338         if (value) {
339             ret_value =
340                 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
341         }
342         xmlFree(const_cast<xmlChar*>(value));
343
344         return ret_value;
345     }
346
347     DPL::String GetName() const
348     {
349         DPL::String ret_value;
350         const xmlChar* value = xmlTextReaderConstName(m_reader);
351         if (value) {
352             ret_value =
353                 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
354         }
355
356         return ret_value;
357     }
358
359     DPL::String GetNamePrefix() const
360     {
361         DPL::String ret_value;
362         const xmlChar* value = xmlTextReaderPrefix(m_reader);
363         if (value) {
364             ret_value =
365                 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
366         }
367
368         return ret_value;
369     }
370
371     DPL::String GetNameWithoutNamespace() const
372     {
373         DPL::String ret_value;
374         const xmlChar* value = xmlTextReaderLocalName(m_reader);
375         if (value) {
376             ret_value =
377                 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
378         }
379
380         return ret_value;
381     }
382
383     DPL::String GetNamespace() const
384     {
385         DPL::String ret_value;
386
387         const xmlChar* value = xmlTextReaderConstNamespaceUri(m_reader);
388         if (value) {
389             ret_value =
390                 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
391         }
392
393         return ret_value;
394     }
395
396     DPL::String GetLanguageTag() const
397     {
398         DPL::String ret_value;
399         const xmlChar* value = xmlTextReaderConstXmlLang(m_reader);
400         if (value) {
401             ret_value =
402                 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
403         }
404
405         return ret_value;
406     }
407
408     void ErrorHandler(const DPL::String& msg)
409     {
410         _E("LibXML:  %ls", msg.c_str());
411         m_parsingError = true;
412         m_errorMsg = m_errorMsg + DPL::FromASCIIString("\n");
413         m_errorMsg = m_errorMsg + msg;
414     }
415
416     void StructuredErrorHandler(xmlErrorPtr error)
417     {
418         _E("LibXML:  %s", error->message);
419         m_parsingError = true;
420         m_errorMsg = m_errorMsg + DPL::FromASCIIString("\n");
421         m_errorMsg = m_errorMsg + DPL::FromUTF8String(error->message);
422     }
423
424     void CleanupParserRunner()
425     {
426         while (!m_stack.empty()) {
427             m_stack.pop();
428         }
429         if (m_reader) {
430             xmlFreeTextReader(m_reader);
431         }
432         m_reader = NULL;
433     }
434
435   private:
436     xmlTextReaderPtr m_reader;
437     ElementStack m_stack;
438     bool m_parsingError;
439     DPL::String m_errorMsg;
440 };
441
442 ParserRunner::ParserRunner() :
443     m_impl(new ParserRunner::Impl())
444 {}
445
446 bool ParserRunner::Validate(const std::string& filename, const std::string& schema)
447 {
448     return m_impl->Validate(filename, schema);
449 }
450
451 void ParserRunner::Parse(const std::string& filename,
452                          ElementParserPtr root)
453 {
454     m_impl->Parse(filename, root);
455 }
456
457 void ParserRunner::Parse(DPL::AbstractInput *input,
458                          ElementParserPtr root)
459 {
460     m_impl->Parse(input, root);
461 }
462
463 ParserRunner::~ParserRunner()
464 {
465     delete m_impl;
466 }