1/* 2 * Copyright (c) 2011-2014, Intel Corporation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation and/or 13 * other materials provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its contributors 16 * may be used to endorse or promote products derived from this software without 17 * specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "XmlDocSource.h" 32#include <libxml/tree.h> 33#include <libxml/xmlschemas.h> 34#include <libxml/parser.h> 35#include <libxml/xinclude.h> 36#include <libxml/xmlerror.h> 37#include <stdlib.h> 38 39using std::string; 40 41// Schedule for libxml2 library 42bool CXmlDocSource::_bLibXml2CleanupScheduled; 43 44CXmlDocSource::CXmlDocSource(_xmlDoc *pDoc, bool bValidateWithSchema, 45 _xmlNode *pRootNode) : 46 _pDoc(pDoc), 47 _pRootNode(pRootNode), 48 _strXmlSchemaFile(""), 49 _strRootElementType(""), 50 _strRootElementName(""), 51 _strNameAttributeName(""), 52 _bValidateWithSchema(bValidateWithSchema) 53{ 54 init(); 55} 56 57CXmlDocSource::CXmlDocSource(_xmlDoc *pDoc, bool bValidateWithSchema, 58 const string& strXmlSchemaFile, 59 const string& strRootElementType, 60 const string& strRootElementName, 61 const string& strNameAttributeName) : 62 _pDoc(pDoc), 63 _pRootNode(xmlDocGetRootElement(pDoc)), 64 _strXmlSchemaFile(strXmlSchemaFile), 65 _strRootElementType(strRootElementType), 66 _strRootElementName(strRootElementName), 67 _strNameAttributeName(strNameAttributeName), 68 _bValidateWithSchema(bValidateWithSchema) 69{ 70 init(); 71} 72 73CXmlDocSource::~CXmlDocSource() 74{ 75 if (_pDoc) { 76 // Free XML doc 77 xmlFreeDoc(_pDoc); 78 _pDoc = NULL; 79 } 80} 81 82void CXmlDocSource::getRootElement(CXmlElement& xmlRootElement) const 83{ 84 xmlRootElement.setXmlElement(_pRootNode); 85} 86 87string CXmlDocSource::getRootElementName() const 88{ 89 return (const char*)_pRootNode->name; 90} 91 92string CXmlDocSource::getRootElementAttributeString(const string& strAttributeName) const 93{ 94 CXmlElement topMostElement(_pRootNode); 95 96 return topMostElement.getAttributeString(strAttributeName); 97} 98 99_xmlDoc* CXmlDocSource::getDoc() const 100{ 101 return _pDoc; 102} 103 104bool CXmlDocSource::isParsable() const 105{ 106 // Check that the doc has been created 107 return _pDoc != NULL; 108} 109 110bool CXmlDocSource::populate(CXmlSerializingContext& serializingContext) 111{ 112 return validate(serializingContext); 113 114} 115 116bool CXmlDocSource::validate(CXmlSerializingContext& serializingContext) 117{ 118 // Check that the doc has been created 119 if (!_pDoc) { 120 121 serializingContext.setError("Could not parse document "); 122 123 return false; 124 } 125 126 // Validate if necessary 127 if (_bValidateWithSchema) 128 { 129 if (!isInstanceDocumentValid()) { 130 131 serializingContext.setError("Document is not valid"); 132 133 return false; 134 } 135 } 136 137 // Check Root element type 138 if (getRootElementName() != _strRootElementType) { 139 140 serializingContext.setError("Error: Wrong XML structure document "); 141 serializingContext.appendLineToError("Root Element " + getRootElementName() 142 + " mismatches expected type " + _strRootElementType); 143 144 return false; 145 } 146 147 if (!_strNameAttributeName.empty()) { 148 149 string strRootElementNameCheck = getRootElementAttributeString(_strNameAttributeName); 150 151 // Check Root element name attribute (if any) 152 if (!_strRootElementName.empty() && strRootElementNameCheck != _strRootElementName) { 153 154 serializingContext.setError("Error: Wrong XML structure document "); 155 serializingContext.appendLineToError(_strRootElementType + " element " 156 + _strRootElementName + " mismatches expected " 157 + _strRootElementType + " type " 158 + strRootElementNameCheck); 159 160 return false; 161 } 162 } 163 164 return true; 165} 166 167void CXmlDocSource::init() 168{ 169 if (!_bLibXml2CleanupScheduled) { 170 171 // Schedule cleanup 172 atexit(xmlCleanupParser); 173 174 _bLibXml2CleanupScheduled = true; 175 } 176} 177 178bool CXmlDocSource::isInstanceDocumentValid() 179{ 180#ifdef LIBXML_SCHEMAS_ENABLED 181 xmlDocPtr pSchemaDoc = xmlReadFile(_strXmlSchemaFile.c_str(), NULL, XML_PARSE_NONET); 182 183 if (!pSchemaDoc) { 184 // Unable to load Schema 185 return false; 186 } 187 188 xmlSchemaParserCtxtPtr pParserCtxt = xmlSchemaNewDocParserCtxt(pSchemaDoc); 189 190 if (!pParserCtxt) { 191 192 // Unable to create schema context 193 xmlFreeDoc(pSchemaDoc); 194 return false; 195 } 196 197 // Get Schema 198 xmlSchemaPtr pSchema = xmlSchemaParse(pParserCtxt); 199 200 if (!pSchema) { 201 202 // Invalid Schema 203 xmlSchemaFreeParserCtxt(pParserCtxt); 204 xmlFreeDoc(pSchemaDoc); 205 return false; 206 } 207 xmlSchemaValidCtxtPtr pValidationCtxt = xmlSchemaNewValidCtxt(pSchema); 208 209 if (!pValidationCtxt) { 210 211 // Unable to create validation context 212 xmlSchemaFree(pSchema); 213 xmlSchemaFreeParserCtxt(pParserCtxt); 214 xmlFreeDoc(pSchemaDoc); 215 return false; 216 } 217 218 xmlSetStructuredErrorFunc(this, schemaValidityStructuredErrorFunc); 219 220 bool isDocValid = xmlSchemaValidateDoc(pValidationCtxt, _pDoc) == 0; 221 222 xmlSchemaFreeValidCtxt(pValidationCtxt); 223 xmlSchemaFree(pSchema); 224 xmlSchemaFreeParserCtxt(pParserCtxt); 225 xmlFreeDoc(pSchemaDoc); 226 227 return isDocValid; 228#else 229 return true; 230#endif 231} 232 233void CXmlDocSource::schemaValidityStructuredErrorFunc(void* pUserData, _xmlError* pError) 234{ 235 (void)pUserData; 236 237#ifdef LIBXML_SCHEMAS_ENABLED 238 // Display message 239 puts(pError->message); 240#endif 241} 242 243_xmlDoc* CXmlDocSource::mkXmlDoc(const string& source, bool fromFile, bool xincludes, string& errorMsg) 244{ 245 _xmlDoc* doc = NULL; 246 if (fromFile) { 247 doc = xmlReadFile(source.c_str(), NULL, 0); 248 } else { 249 doc = xmlReadMemory(source.c_str(), (int)source.size(), "", NULL, 0); 250 } 251 252 if (doc == NULL) { 253 errorMsg = "libxml failed to read"; 254 if (fromFile) { 255 errorMsg += " \"" + source + "\""; 256 } 257 258 xmlError* details = xmlGetLastError(); 259 if (details != NULL) { 260 errorMsg += ": " + string(details->message); 261 } 262 263 return NULL; 264 } 265 266 if (xincludes and (xmlXIncludeProcess(doc) < 0)) { 267 errorMsg = "libxml failed to resolve XIncludes"; 268 xmlError* details = xmlGetLastError(); 269 if (details != NULL) { 270 errorMsg += ": " + string(details->message); 271 } 272 273 xmlFreeDoc(doc); 274 doc = NULL; 275 } 276 277 return doc; 278} 279