2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * @file parser_runner.cpp
18 * @author Lukasz Wrzosek (l.wrzosek@samsung.com)
22 #include "parser_runner.h"
23 #include "root_parser.h"
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>
33 class ParserRunner::Impl
35 static void logErrorLibxml2(void *, const char *msg, ...)
40 vsnprintf(buffer, 300, msg, args);
45 static void logWarningLibxml2(void *, const char *msg, ...)
50 vsnprintf(buffer, 300, msg, args);
56 bool Validate(const std::string& filename, const std::string& schema)
59 xmlSchemaParserCtxtPtr ctx;
60 xmlSchemaValidCtxtPtr vctx;
62 ctx = xmlSchemaNewParserCtxt(schema.c_str());
64 _E("xmlSchemaNewParserCtxt() Failed");
67 xschema = xmlSchemaParse(ctx);
68 if (xschema == NULL) {
69 _E("xmlSchemaParse() Failed");
72 vctx = xmlSchemaNewValidCtxt(xschema);
74 _E("xmlSchemaNewValidCtxt() Failed");
77 xmlSchemaSetValidErrors(vctx, (xmlSchemaValidityErrorFunc)&logErrorLibxml2, (xmlSchemaValidityWarningFunc) &logWarningLibxml2, NULL);
78 ret = xmlSchemaValidateFile(vctx, filename.c_str(), 0);
80 _E("xmlSchemaValidateFile() failed");
82 } else if (ret == 0) {
83 _E("Config is Valid");
86 _E("Config Validation Failed with error code %d", ret);
91 void Parse(const std::string& filename,
92 const ElementParserPtr& root)
94 DPL::FileInput input(filename);
98 void Parse (DPL::AbstractInput *input,
99 const ElementParserPtr& root)
103 m_reader = xmlReaderForIO(&IoRead,
110 if (m_reader == NULL) {
111 _E("xmlReaderForIO() is failed");
112 ThrowMsg(ElementParser::Exception::ParseError, "xmlReaderForIO() is failed");
115 xmlTextReaderSetErrorHandler(m_reader,
116 &xmlTextReaderErrorHandler,
118 xmlTextReaderSetStructuredErrorHandler(
120 &xmlTextReaderStructuredErrorHandler,
122 SetCurrentElementParser(root);
124 while (xmlTextReaderRead(m_reader) == 1) {
125 switch (xmlTextReaderNodeType(m_reader)) {
126 case XML_READER_TYPE_END_ELEMENT:
127 VerifyAndRemoveCurrentElementParser();
130 case XML_READER_TYPE_ELEMENT:
132 // Elements without closing tag don't receive
133 // XML_READER_TYPE_END_ELEMENT event.
134 if (IsNoClosingTagElementLeft()) {
135 VerifyAndRemoveCurrentElementParser();
138 DPL::String elementName = GetNameWithoutNamespace();
139 DPL::String nameSpace = GetNamespace();
140 ElementParserPtr parser = GetCurrentElementParser();
141 parser = parser->GetElementParser(nameSpace,
144 SetCurrentElementParser(parser);
145 ParseNodeElement(parser);
148 case XML_READER_TYPE_TEXT:
149 case XML_READER_TYPE_CDATA:
151 ParseNodeText(GetCurrentElementParser());
155 _W("Ignoring Node of Type: %d", xmlTextReaderNodeType(m_reader));
159 if (m_parsingError) {
160 _E("Parsing error occured: %ls", m_errorMsg.c_str());
161 ThrowMsg(ElementParser::Exception::ParseError, m_errorMsg);
165 if (m_parsingError) {
166 _E("Parsing error occured: %ls", m_errorMsg.c_str());
167 ThrowMsg(ElementParser::Exception::ParseError, m_errorMsg);
170 while (!m_stack.empty()) {
171 VerifyAndRemoveCurrentElementParser();
174 Catch(ElementParser::Exception::Base)
176 CleanupParserRunner();
177 _E("%s", _rethrown_exception.DumpToString().c_str());
178 ReThrow(ElementParser::Exception::ParseError);
180 CleanupParserRunner();
185 m_parsingError(false)
190 CleanupParserRunner();
194 typedef std::stack<ElementParserPtr> ElementStack;
197 static void xmlTextReaderErrorHandler(void* arg,
199 xmlParserSeverities /* severity */,
200 xmlTextReaderLocatorPtr /* locator */)
202 ParserRunner::Impl* impl = static_cast<ParserRunner::Impl*>(arg);
203 impl->ErrorHandler(DPL::FromASCIIString(msg));
206 static void xmlTextReaderStructuredErrorHandler(void* arg,
209 ParserRunner::Impl* impl = static_cast<ParserRunner::Impl*>(arg);
210 impl->StructuredErrorHandler(error);
213 static int XMLCALL IoRead(void *context,
217 DPL::AbstractInput *input = static_cast<DPL::AbstractInput *>(context);
218 DPL::BinaryQueueAutoPtr data = input->Read(static_cast<size_t>(len));
222 data->Flatten(buffer, data->Size());
223 return static_cast<int>(data->Size());
226 static int XMLCALL IoClose(void */* context */)
233 void SetCurrentElementParser(const ElementParserPtr& elementParser)
235 Assert(elementParser);
237 m_stack.push(elementParser);
240 const ElementParserPtr& GetCurrentElementParser() const
242 Assert(!m_stack.empty());
244 return m_stack.top();
247 void VerifyAndRemoveCurrentElementParser()
249 Assert(!m_stack.empty());
251 m_stack.top()->Verify();
255 bool IsNoClosingTagElementLeft() const
259 int depth = xmlTextReaderDepth(m_reader);
260 return (static_cast<int>(m_stack.size()) - 2 == depth);
263 void ParseNodeElement(const ElementParserPtr& parser)
268 element.name = GetName();
269 element.value = GetValue();
270 element.lang = GetLanguageTag();
271 element.ns = GetNamespace();
273 _D("value: %ls, lang: %ls, ns: %ls",
274 element.value.c_str(), element.lang.c_str(), element.ns.c_str());
276 parser->Accept(element);
277 ParseNodeElementAttributes(parser);
280 void ParseNodeElementAttributes(const ElementParserPtr& parser)
283 int count = xmlTextReaderAttributeCount(m_reader);
284 for (int i = 0; i < count; ++i) {
285 xmlTextReaderMoveToAttributeNo(m_reader, i);
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);
301 void ParseNodeText(const ElementParserPtr& parser)
304 text.value = GetValue();
305 text.lang = GetLanguageTag();
306 parser->Accept(text);
309 DPL::String GetValue() const
311 DPL::String ret_value;
312 const xmlChar* value = xmlTextReaderConstValue(m_reader);
315 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
321 DPL::String GetAttributeValue(int pos) const
323 DPL::String ret_value;
324 const xmlChar* value = xmlTextReaderGetAttributeNo(m_reader, pos);
327 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
329 xmlFree(const_cast<xmlChar*>(value));
334 DPL::String GetAttributeNamespace() const
336 DPL::String ret_value;
337 const xmlChar* value = xmlTextReaderLookupNamespace(m_reader, NULL);
340 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
342 xmlFree(const_cast<xmlChar*>(value));
347 DPL::String GetName() const
349 DPL::String ret_value;
350 const xmlChar* value = xmlTextReaderConstName(m_reader);
353 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
359 DPL::String GetNamePrefix() const
361 DPL::String ret_value;
362 const xmlChar* value = xmlTextReaderPrefix(m_reader);
365 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
371 DPL::String GetNameWithoutNamespace() const
373 DPL::String ret_value;
374 const xmlChar* value = xmlTextReaderLocalName(m_reader);
377 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
383 DPL::String GetNamespace() const
385 DPL::String ret_value;
387 const xmlChar* value = xmlTextReaderConstNamespaceUri(m_reader);
390 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
396 DPL::String GetLanguageTag() const
398 DPL::String ret_value;
399 const xmlChar* value = xmlTextReaderConstXmlLang(m_reader);
402 DPL::FromUTF8String(reinterpret_cast<const char*>(value));
408 void ErrorHandler(const DPL::String& msg)
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;
416 void StructuredErrorHandler(xmlErrorPtr error)
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);
424 void CleanupParserRunner()
426 while (!m_stack.empty()) {
430 xmlFreeTextReader(m_reader);
436 xmlTextReaderPtr m_reader;
437 ElementStack m_stack;
439 DPL::String m_errorMsg;
442 ParserRunner::ParserRunner() :
443 m_impl(new ParserRunner::Impl())
446 bool ParserRunner::Validate(const std::string& filename, const std::string& schema)
448 return m_impl->Validate(filename, schema);
451 void ParserRunner::Parse(const std::string& filename,
452 ElementParserPtr root)
454 m_impl->Parse(filename, root);
457 void ParserRunner::Parse(DPL::AbstractInput *input,
458 ElementParserPtr root)
460 m_impl->Parse(input, root);
463 ParserRunner::~ParserRunner()