119b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard/* 219b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard * Copyright (C) 2017 The Android Open Source Project 319b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard * 419b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard * Licensed under the Apache License, Version 2.0 (the "License"); 519b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard * you may not use this file except in compliance with the License. 619b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard * You may obtain a copy of the License at 719b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard * 819b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard * http://www.apache.org/licenses/LICENSE-2.0 919b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard * 1019b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard * Unless required by applicable law or agreed to in writing, software 1119b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard * distributed under the License is distributed on an "AS IS" BASIS, 1219b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1319b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard * See the License for the specific language governing permissions and 1419b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard * limitations under the License. 1519b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard */ 1619b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 1719b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard#define LOG_TAG "ValidateAudioConfig" 1819b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard#include <utils/Log.h> 1919b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 2019b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard#define LIBXML_SCHEMAS_ENABLED 2119b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard#include <libxml/xmlschemastypes.h> 2219b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard#define LIBXML_XINCLUDE_ENABLED 2319b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard#include <libxml/xinclude.h> 2419b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 2519b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard#include <memory> 2619b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard#include <string> 2719b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 2819b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard#include "ValidateXml.h" 2919b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 3019b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardnamespace android { 3119b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardnamespace hardware { 3219b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardnamespace audio { 3319b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardnamespace test { 3419b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 3519b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard/** Map libxml2 structures to their corresponding deleters. */ 3619b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardtemplate <class T> 3719b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardconstexpr void (*xmlDeleter)(T* t); 3819b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardtemplate <> 3919b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardconstexpr auto xmlDeleter<xmlSchema> = xmlSchemaFree; 4019b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardtemplate <> 4119b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardconstexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc; 4219b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardtemplate <> 4319b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardconstexpr auto xmlDeleter<xmlSchemaParserCtxt> = xmlSchemaFreeParserCtxt; 4419b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardtemplate <> 4519b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardconstexpr auto xmlDeleter<xmlSchemaValidCtxt> = xmlSchemaFreeValidCtxt; 4619b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 4719b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard/** @return a unique_ptr with the correct deleter for the libxml2 object. */ 4819b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardtemplate <class T> 4919b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardconstexpr auto make_xmlUnique(T* t) { 5019b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard // Wrap deleter in lambda to enable empty base optimization 5119b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard auto deleter = [](T* t) { xmlDeleter<T>(t); }; 5219b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard return std::unique_ptr<T, decltype(deleter)>{t, deleter}; 5319b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard} 5419b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 5519b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard/** Class that handles libxml2 initialization and cleanup. NOT THREAD SAFE*/ 5619b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocardstruct Libxml2Global { 5719b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard Libxml2Global() { 5819b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard xmlLineNumbersDefault(1); // Better error message 5919b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard xmlSetGenericErrorFunc(this, errorCb); 6019b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard } 6119b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard ~Libxml2Global() { 6219b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard // TODO: check if all those cleanup are needed 6319b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard xmlSetGenericErrorFunc(nullptr, nullptr); 6419b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard xmlSchemaCleanupTypes(); 6519b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard xmlCleanupParser(); 6619b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard xmlCleanupThreads(); 6719b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard } 6819b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 6919b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard const std::string& getErrors() { return errors; } 7019b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 7119b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard private: 7219b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard static void errorCb(void* ctxt, const char* msg, ...) { 7319b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard auto* self = static_cast<Libxml2Global*>(ctxt); 7419b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard va_list args; 7519b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard va_start(args, msg); 7619b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 7719b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard char* formatedMsg; 7819b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard if (vasprintf(&formatedMsg, msg, args) >= 0) { 7919b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard LOG_PRI(ANDROID_LOG_ERROR, LOG_TAG, "%s", formatedMsg); 8019b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard self->errors += "Error: "; 8119b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard self->errors += formatedMsg; 8219b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard } 8319b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard free(formatedMsg); 8419b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 8519b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard va_end(args); 8619b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard } 8719b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard std::string errors; 8819b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard}; 8919b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 9019b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard::testing::AssertionResult validateXml(const char* xmlFilePathExpr, 9119b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard const char* xsdFilePathExpr, 9219b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard const char* xmlFilePath, 9319b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard const char* xsdFilePath) { 9419b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard Libxml2Global libxml2; 9519b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 9619b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard auto context = [&]() { 9719b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard return std::string() + " While validating: " + xmlFilePathExpr + 9819b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard "\n Which is: " + xmlFilePath + 9919b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard "\nAgainst the schema: " + xsdFilePathExpr + 10019b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard "\n Which is: " + xsdFilePath + "Libxml2 errors\n" + 10119b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard libxml2.getErrors(); 10219b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard }; 10319b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 10419b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard auto schemaParserCtxt = make_xmlUnique(xmlSchemaNewParserCtxt(xsdFilePath)); 10519b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard auto schema = make_xmlUnique(xmlSchemaParse(schemaParserCtxt.get())); 10619b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard if (schema == nullptr) { 10719b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard return ::testing::AssertionFailure() << "Failed to parse schema (xsd)\n" 10819b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard << context(); 10919b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard } 11019b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 11119b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard auto doc = make_xmlUnique(xmlReadFile(xmlFilePath, nullptr, 0)); 11219b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard if (doc == nullptr) { 11319b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard return ::testing::AssertionFailure() << "Failed to parse xml\n" 11419b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard << context(); 11519b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard } 11619b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 11719b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard if (xmlXIncludeProcess(doc.get()) == -1) { 11819b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard return ::testing::AssertionFailure() 11919b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard << "Failed to resolve xincludes in xml\n" 12019b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard << context(); 12119b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard } 12219b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 12319b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard auto schemaCtxt = make_xmlUnique(xmlSchemaNewValidCtxt(schema.get())); 12419b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard int ret = xmlSchemaValidateDoc(schemaCtxt.get(), doc.get()); 12519b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard if (ret > 0) { 12619b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard return ::testing::AssertionFailure() 12719b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard << "xml is not valid according to the xsd.\n" 12819b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard << context(); 12919b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard } 13019b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard if (ret < 0) { 13119b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard return ::testing::AssertionFailure() << "Internal or API error\n" 13219b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard << context(); 13319b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard } 13419b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 13519b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard return ::testing::AssertionSuccess(); 13619b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard} 13719b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard 13819b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard} // namespace test 13919b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard} // namespace audio 14019b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard} // namespace hardware 14119b3e43fb4e639985fde0219bb1bb491abf88537Kevin Rocard} // namespace android 142