Old manifest parser is replaced with the new general-purpose XmlParser.
With the XmlParser, the element hierarchy is fully preserved.
In addition, all exceptions are removed in this commit.
Change-Id: Id03384dc0b3c661bd876966bfbb3883b631cc68d
Signed-Off-By: Youmin Ha <youmin.ha@samsung.com>
task.cc
step/step_parse.cc
step/step_symbolic_link.cc
- manifest_parser.cc
+ ../xml_parser/xml_parser.cc
)
ADD_EXECUTABLE(${TARGET_TPK} ${SRCS})
+++ /dev/null
-/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
-#ifndef TPK_EXCEPTION_H_
-#define TPK_EXCEPTION_H_
-
-#include <execinfo.h>
-#include <string.h>
-#include <unistd.h>
-#include <exception>
-#include <iostream>
-#include "utils/logging.h"
-
-namespace tpk {
-
-class Exception: public std::exception {
-SCOPE_LOG_TAG(UncaughtException)
-
- public:
- Exception() {
- this->message_ = nullptr;
- StoreStackTrace();
- }
- explicit Exception(const char *message) {
- this->message_ = strdup(message);
- StoreStackTrace();
- }
- ~Exception() {
- if (message_) free(message_);
- }
- virtual void StoreStackTrace() {
- stack_size_ = backtrace(stack_, kMaxStackSize);
- }
- virtual void PrintStackTrace() {
- if (message_) {
- LOG(ERROR) << message_;
- }
- // Exclude top 1 stack entry (storeStackTrace)
- backtrace_symbols_fd(stack_+1, stack_size_-1, STDERR_FILENO);
- }
-
-
- protected:
- char* message_;
-
-
- private:
- static const size_t kMaxStackSize = 100;
- size_t stack_size_;
- void *stack_[kMaxStackSize];
-};
-
-} // namespace tpk
-#endif // TPK_EXCEPTION_H_
/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
#include <iostream>
-#include <cerrno>
#include "tpk/task.h"
-#include "tpk/exception.h"
+#include "utils/logging.h"
int main(const int argc, char* argv[]) {
- try {
- // Create a task to do
- tpk::Task t(argc, argv);
-
- // Do the task
- t.Run();
- } catch(tpk::Exception &e) {
- e.PrintStackTrace();
+ tpk::Task t;
+ if (!t.Init(argc, argv)) {
+ std::cerr << "Task init failure" << std::endl;
+ return -1;
+ }
+ if (!t.Run()) {
+ std::cerr << "Task run failure" << std::endl;
return -1;
}
return 0;
+++ /dev/null
-/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
-
-#include "tpk/manifest_parser.h"
-#include <libxml/xmlreader.h>
-#include <iostream>
-#include <vector>
-#include "tpk/xml_nodes.h"
-
-namespace tpk {
-
-
-template <typename T>
-void ManifestParser::CheckAndSetNode(xmlTextReaderPtr reader,
- const char* name,
- const T& xmlNode) {
- T& node = const_cast<T&>(xmlNode);
- if (xmlStrEqual(reinterpret_cast<const xmlChar*>(name),
- xmlTextReaderConstName(reader)) &&
- xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
- node.Init(reader);
- }
-}
-
-
-template <typename T>
-void ManifestParser::CheckAndAppendNode(xmlTextReaderPtr reader,
- const char* name,
- const std::vector<T*> &v) {
- if (xmlStrEqual(reinterpret_cast<const xmlChar*>(name),
- xmlTextReaderConstName(reader)) &&
- xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
- T *p = new T();
- p->Init(reader);
- std::vector<T*>& _v = const_cast<std::vector<T*>&>(v);
- _v.push_back(p);
- }
-}
-
-
-void ManifestParser::ProcessNode(xmlTextReaderPtr reader) {
- // For each node, find required node names and get data
- CheckAndSetNode(reader, "manifest", manifest);
- CheckAndSetNode(reader, "ui-application", manifest.ui_application);
- CheckAndSetNode(reader, "icon", manifest.ui_application.icon);
- CheckAndSetNode(reader, "label", manifest.ui_application.label);
- CheckAndSetNode(reader, "privileges", manifest.privileges);
- CheckAndAppendNode(reader, "privilege", manifest.privileges.v_privilege);
-}
-
-
-void ManifestParser::StreamFile(const char* filePath) {
- xmlTextReaderPtr reader;
- int ret;
-
- // TODO(youmin.ha@samsung.com): add DTD validation
- reader = xmlReaderForFile(filePath, NULL, 0);
- if (reader == nullptr) {
- throw FileOpenFailureException();
- } else {
- ret = xmlTextReaderRead(reader);
- while (ret == 1) {
- ProcessNode(reader);
- ret = xmlTextReaderRead(reader);
- }
- xmlFreeTextReader(reader);
- if (ret != 0) {
- throw ParseFailureException();
- }
- }
-}
-
-
-/* constructor
- */
-ManifestParser::ManifestParser(const char* filePath) {
- LIBXML_TEST_VERSION
-
- StreamFile(filePath);
-
- xmlCleanupParser();
- xmlMemoryDump();
-}
-
-
-/* destructor
- */
-ManifestParser::~ManifestParser() {
-}
-
-
-} // namespace tpk
+++ /dev/null
-/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
-#ifndef TPK_MANIFEST_PARSER_H_
-#define TPK_MANIFEST_PARSER_H_
-
-#include <boost/filesystem.hpp>
-#include <vector>
-#include "tpk/xml_nodes.h"
-#include "tpk/exception.h"
-
-
-namespace tpk {
-
-/* Internal exceptions */
-class FileOpenFailureException : public Exception {};
-class ParseFailureException : public Exception {};
-
-
-class ManifestParser {
- public:
- explicit ManifestParser(const char *manifestFilePath);
- ~ManifestParser();
- XmlNodeManifest manifest;
-
-
- private:
- template <typename T> void CheckAndSetNode(
- xmlTextReaderPtr reader, const char* name, const T &xmlNode);
- template <typename T> void CheckAndAppendNode(
- xmlTextReaderPtr reader, const char* name, const std::vector<T*> &v);
- void ProcessNode(xmlTextReaderPtr reader);
- void StreamFile(const char* filePath);
-};
-
-} // namespace tpk
-#endif // TPK_MANIFEST_PARSER_H_
/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
#include "tpk/step/step_parse.h"
#include <boost/filesystem.hpp>
+#include <memory>
#include <string>
#include <vector>
#include "common/context_installer.h"
#include "common/step/step.h"
-#include "tpk/manifest_parser.h"
-#include "tpk/xml_nodes.h"
#include "utils/logging.h"
+#include "xml_parser/xml_parser.h"
using std::vector;
+using std::string;
+using xml_parser::XmlParser;
+using xml_parser::XmlTree;
+using xml_parser::XmlElement;
+
namespace tpk {
namespace step {
namespace {
const char kManifestFileName[] = "tizen-manifest.xml";
+
+ XmlElement* Get1stChild(XmlTree *tree,
+ XmlElement* parent, const string element_name) {
+ vector<XmlElement*> v = tree->Children(parent, element_name);
+ if (!v.size() < 1) {
+ LOG(ERROR) << element_name << " is not found as a child of " <<
+ parent->name();
+ return nullptr;
+ }
+ return v[0]; // Always return only the 1st child
+ }
+
+
} // namespace
SCOPE_LOG_TAG(StepParse)
typedef common_installer::Step::Status Status;
using boost::filesystem::path;
-
-/* Internal exceptions */
-class FileNotFoundException : public std::exception {};
-
-
/* process()
* Parse tizen-manifest.xml and get the data from it
* Store the data into the context_
*/
Status StepParse::process() {
- try {
- boost::filesystem::path mPath = GetManifestFilePath(
- context_->unpacked_dir_path());
- ManifestParser m(mPath.c_str());
- SetContextByManifestParser(m);
- } catch (FileNotFoundException &e) {
+ std::unique_ptr<boost::filesystem::path> mPath(
+ GetManifestFilePath(context_->unpacked_dir_path()));
+ if (!mPath) {
return Status::ERROR;
- } catch (FileOpenFailureException &e) {
+ }
+
+ XmlParser parser;
+ std::unique_ptr<XmlTree> tree(parser.ParseAndGetNewTree(mPath->c_str()));
+ if (tree == nullptr) {
+ LOG(ERROR) << "Failure on parsing xml";
+ return Status::ERROR;
+ }
+ if (!SetContextByManifestParser(tree.get())) {
return Status::ERROR;
}
return Status::OK;
/* in parse() : Get manifest file path from the package unzipped directory
*/
-boost::filesystem::path StepParse::GetManifestFilePath(
+boost::filesystem::path* StepParse::GetManifestFilePath(
const boost::filesystem::path& dir) {
- path mPath(dir);
- mPath /= kManifestFileName;
+ path* mPath = new path(dir);
+ *mPath /= kManifestFileName;
- LOG(INFO) << "manifest file path: " << mPath;
- if (!boost::filesystem::exists(mPath)) {
+ LOG(INFO) << "manifest file path: " << mPath->string();
+ if (!boost::filesystem::exists(*mPath)) {
LOG(ERROR) << kManifestFileName << " not found from the package";
- throw FileNotFoundException();
+ return nullptr;
}
return mPath; // object copy
}
/* Read manifest xml, and set up context_ object
*/
-void StepParse::SetContextByManifestParser(const ManifestParser &m) {
- const XmlNodeManifest& manifest = m.manifest;
- LOG(DEBUG) << "Parse manifest xml values:";
- LOG(DEBUG) << "xmlns(" << manifest.xmlns << ") api_version(" <<
- manifest.api_version << ") package(" << manifest.package <<
- ") version(" << manifest.version << ")";
+bool StepParse::SetContextByManifestParser(XmlTree* tree) {
+ // Get required elements
+ XmlElement* manifest,
+ * ui_application, * label;
+
+ // manifest
+ if (nullptr == (manifest = tree->GetRootElement())) return false;
+
+ LOG(DEBUG) << "Getting manifest xml data";
+ LOG(DEBUG) << "manifest: xmlns='" << manifest->attr("xmlns") <<
+ "' api_version='" << manifest->attr("api_version") <<
+ "' package='" << manifest->attr("package") <<
+ "' versionr='" << manifest->attr("version") << "'";
+
+ // ui_application
+ if (nullptr == (ui_application = Get1stChild(tree,
+ manifest, "ui-application"))) return false;
+ if (nullptr == (label = Get1stChild(tree, ui_application, "label")))
+ return false;
// set context_
- context_->config_data()->set_application_name(
- std::string(reinterpret_cast<char*>(manifest.ui_application.label.data)));
- context_->config_data()->set_required_version(
- std::string(reinterpret_cast<char*>(manifest.api_version)));
-
- context_->set_pkgid(std::string(reinterpret_cast<char*>(manifest.package)));
+ context_->config_data()->set_application_name(label->content());
+ context_->config_data()->set_required_version(manifest->attr("api_version"));
+ context_->set_pkgid(manifest->attr("package"));
// set context_->manifest_data()
- SetPkgInfoManifest(context_->manifest_data(), manifest);
+ return SetPkgInfoManifest(context_->manifest_data(), tree, manifest);
}
-void StepParse::SetPkgInfoManifest(manifest_x* m,
- const XmlNodeManifest &manifest) {
+bool StepParse::SetPkgInfoManifest(manifest_x* m,
+ XmlTree* tree,
+ XmlElement* manifest) {
+ // Get required elements
+ XmlElement* ui_application, * label, * icon, * description;
+ if (nullptr == (ui_application = Get1stChild(tree,
+ manifest, "ui-application"))) return false;
+ if (nullptr == (label = Get1stChild(tree, ui_application, "label")))
+ return false;
+ if (nullptr == (icon = Get1stChild(tree, ui_application, "icon")))
+ return false;
+ if (nullptr == (description = Get1stChild(tree,
+ ui_application, "description"))) return false;
+
// Common values
m->label = static_cast<label_x*>
(calloc(1, sizeof(label_x)));
m->privileges->privilege = nullptr;
// Basic values
- m->package = strdup(reinterpret_cast<char*>(manifest.package));
+ m->package = strdup(manifest->attr("package").c_str());
m->type = strdup("tpk");
- m->version = strdup(reinterpret_cast<char*>(manifest.version));
- m->label->name = strdup(
- reinterpret_cast<char*>(manifest.ui_application.label.name));
- // TODO(youmin.ha@samsung.com): get name from XML if exists
- m->description->name = nullptr;
- m->mainapp_id = strdup(
- reinterpret_cast<char*>(manifest.ui_application.appid));
+ m->version = strdup(manifest->attr("version").c_str());
+ m->label->name = strdup(label->content().c_str());
+ m->description->name = strdup(description->content().c_str());
+ m->mainapp_id = strdup(ui_application->attr("appid").c_str());
// Privileges
- vector<XmlNodePrivilege *> vp =
- const_cast<XmlNodeManifest &>(manifest).privileges.getPrivilegeVector();
- vector<XmlNodePrivilege *>::iterator it;
- for (it = vp.begin(); it != vp.end(); it++) {
+ XmlElement* privileges;
+ if (nullptr == (privileges = Get1stChild(tree, manifest, "privileges"))) {
+ return false;
+ }
+ vector<XmlElement*> v_priv = tree->Children(privileges, "privilege");
+ for (auto& privilege : v_priv) {
privilege_x *p =
static_cast<privilege_x *>(calloc(1, sizeof(privilege_x)));
// privilege data text
- p->text = strdup(reinterpret_cast<char*>((*it)->data));
+ p->text = strdup(privilege->content().c_str());
LISTADD(m->privileges->privilege, p);
- LOG(INFO) << "add privilege: " << p->text;
+ LOG(INFO) << "Add a privilege: " << p->text;
}
// Other app data (null initialization)
- m->serviceapplication = nullptr; // ignore service application
+ m->serviceapplication = nullptr; // NOTE: ignore service application
m->uiapplication = static_cast<uiapplication_x*>
(calloc (1, sizeof(uiapplication_x)));
m->uiapplication->icon = static_cast<icon_x*>
(calloc(1, sizeof(description_x)));
m->uiapplication->appcontrol = nullptr;
- m->uiapplication->appid = strdup(
- reinterpret_cast<char*>(manifest.ui_application.appid));
- m->uiapplication->exec = strdup(
- reinterpret_cast<char*>(manifest.ui_application.exec));
- m->uiapplication->type = strdup(
- reinterpret_cast<char*>(manifest.ui_application.type));
-
- m->uiapplication->label->name = strdup(
- reinterpret_cast<char*>(manifest.ui_application.label.data));
- m->uiapplication->icon->name = strdup(
- reinterpret_cast<char*>(manifest.ui_application.icon.data));
+ m->uiapplication->appid = strdup(ui_application->attr("appid").c_str());
+ m->uiapplication->exec = strdup(ui_application->attr("exec").c_str());
+ m->uiapplication->type = strdup(ui_application->attr("type").c_str());
+
+ m->uiapplication->label->name = strdup(label->content().c_str());
+ m->uiapplication->icon->name = strdup(icon->content().c_str());
m->uiapplication->next = nullptr;
+
+ return true;
}
} // namespace step
#include <boost/filesystem.hpp>
#include "common/step/step.h"
-#include "tpk/manifest_parser.h"
+#include "xml_parser/xml_parser.h"
namespace tpk {
namespace step {
private:
- boost::filesystem::path
- GetManifestFilePath(const boost::filesystem::path& dir);
- void SetContextByManifestParser(const ManifestParser &m);
- void SetPkgInfoManifest(manifest_x* m, const XmlNodeManifest &manifest);
+ boost::filesystem::path* GetManifestFilePath(
+ const boost::filesystem::path& dir);
+ bool SetContextByManifestParser(xml_parser::XmlTree* tree);
+ bool SetPkgInfoManifest(manifest_x* m,
+ xml_parser::XmlTree* tree,
+ xml_parser::XmlElement* manifest);
};
} // namespace step
#include "common/step/step_unzip.h"
#include "tpk/step/step_parse.h"
#include "tpk/step/step_symbolic_link.h"
-#include "tpk/exception.h"
+#include "utils/logging.h"
#endif
const char kPkgType[] = "tpk";
} // namespace
-
namespace tpk {
+SCOPE_LOG_TAG(TpkTask)
+
/* Constructor
*/
-Task::Task(const int argc, char** argv) {
- pi_ = pkgmgr_installer_new();
- if (!pi_) {
- throw Exception("Not enough memory");
- }
- if (!!pkgmgr_installer_receive_request(pi_, argc, argv)) {
- throw Exception("Invalid Argument");
- }
- request_ = pkgmgr_installer_get_request_type(pi_);
+Task::Task() :
+ pi_(nullptr),
+ request_(PKGMGR_REQ_INVALID) {
}
::tpk::Task::~Task() {
if (pi_) {
pkgmgr_installer_free(pi_);
- pi_ = NULL;
+ pi_ = nullptr;
}
}
-void Task::Run(void) {
+bool Task::Init(int argc, char** argv) {
+ pi_ = pkgmgr_installer_new();
+ if (!pi_) {
+ LOG(ERROR) << "Failed to run pkgmgr_installer_new()";
+ return false;
+ }
+ if (!!pkgmgr_installer_receive_request(pi_, argc, argv)) {
+ LOG(ERROR) << "Invalid argument";
+ pkgmgr_installer_free(pi_);
+ pi_ = nullptr;
+ return false;
+ }
+ request_ = pkgmgr_installer_get_request_type(pi_);
+
+ return true;
+}
+
+
+bool Task::Run() {
+ bool ret = false;
switch (request_) {
case PKGMGR_REQ_INSTALL:
- Install();
+ ret = Install();
break;
case PKGMGR_REQ_UNINSTALL:
- Uninstall();
+ ret = Uninstall();
break;
case PKGMGR_REQ_REINSTALL:
- Reinstall();
+ ret = Reinstall();
break;
- default:
- throw Exception("Unsupported request");
}
+ return ret;
}
-void Task::Install(void) {
+bool Task::Install() {
ci::AppInstaller ai(pi_, kPkgType);
ai.AddStep<ci::unzip::StepUnzip>();
ai.AddStep<ci::generate_xml::StepGenerateXml>();
ai.AddStep<ci::record::StepRecord>();
- ai.Run();
+ return ai.Run();
}
-void Task::Uninstall(void) {
+bool Task::Uninstall() {
ci::AppInstaller ai(pi_, kPkgType);
ai.AddStep<ci::parse::StepParse>();
ai.AddStep<ci::unregister::StepUnregister>();
ai.AddStep<ci::remove::StepRemove>();
- ai.Run();
+ return ai.Run();
}
-void Task::Reinstall(void) {
+bool Task::Reinstall() {
+ return false;
}
} // namespace tpk
class Task {
public:
- Task(int argc, char** argv);
+ Task();
~Task();
- void Run();
+ bool Init(int argc, char** argv);
+ bool Run();
private:
- void Install();
- void Uninstall();
- void Reinstall();
+ bool Install();
+ bool Uninstall();
+ bool Reinstall();
pkgmgr_installer* pi_;
int request_;
+++ /dev/null
-/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
-#ifndef TPK_XML_NODES_H_
-#define TPK_XML_NODES_H_
-
-#include <libxml/globals.h>
-#include <libxml/xmlstring.h>
-#include <libxml/xmlreader.h>
-#include <vector>
-#include "tpk/exception.h"
-#include "utils/logging.h"
-
-using std::vector;
-
-namespace tpk {
-
-class InvalidNodeTypeException: public tpk::Exception {};
-class InvalidNodeNameException: public tpk::Exception {};
-
-
-class XmlNode {
- SCOPE_LOG_TAG(XmlNode)
-
- public:
- int depth;
- int node_type;
- xmlChar* name; // The name of node
- xmlChar* data; // Internal text of the node
-
- XmlNode()
- : depth(-1),
- node_type(XML_READER_TYPE_NONE),
- name(NULL),
- data(NULL) {
- }
-
- virtual ~XmlNode() {
- Free();
- }
-
- virtual void ReadBasicValues(xmlTextReaderPtr reader) {
- depth = xmlTextReaderDepth(reader);
- node_type = xmlTextReaderNodeType(reader);
- data = xmlTextReaderReadString(reader);
- }
-
- virtual void Init(xmlTextReaderPtr reader) {
- name = xmlTextReaderName(reader);
- if (!xmlStrEqual(name, node_name_)) {
- LOG(ERROR) << "Invalid node! actual name=" << name
- << ", expected name=" << node_name_ << std::endl;
- xmlFree(name);
- throw InvalidNodeNameException();
- }
- ReadBasicValues(reader);
- }
-
- virtual void Free() {
- xmlFree(name);
- xmlFree(data);
- }
-
- virtual void SetExpectedNodeName(const char* nodeName) {
- node_name_ = const_cast<xmlChar*>(
- reinterpret_cast<const xmlChar*>(nodeName));
- }
-
-
- private:
- xmlChar* node_name_;
-};
-
-
-class XmlNodeIcon : public XmlNode {
- public:
- XmlNodeIcon() {
- XmlNode::SetExpectedNodeName("icon");
- }
-
- virtual void Init(xmlTextReaderPtr reader) {
- XmlNode::Init(reader);
- }
-};
-
-
-class XmlNodeLabel : public XmlNode {
- public:
- XmlNodeLabel() {
- XmlNode::SetExpectedNodeName("label");
- }
- virtual void Init(xmlTextReaderPtr reader) {
- XmlNode::Init(reader);
- }
-};
-
-class XmlNodeProfile : public XmlNode {
- public:
- XmlNodeProfile() {
- XmlNode::SetExpectedNodeName("profile");
- }
-
- virtual void Init(xmlTextReaderPtr reader) {
- XmlNode::Init(reader);
- }
-};
-
-class XmlNodeUiApplication : public XmlNode {
- public:
- xmlChar *appid;
- xmlChar *exec;
- xmlChar *type;
- xmlChar *multiple;
- xmlChar *taskmanage;
- xmlChar *nodisplay;
-
- XmlNodeIcon icon;
- XmlNodeLabel label;
-
- XmlNodeUiApplication()
- : appid(NULL),
- exec(NULL),
- type(NULL),
- multiple(NULL),
- taskmanage(NULL),
- nodisplay(NULL) {
- XmlNode::SetExpectedNodeName("ui-application");
- }
-
- void Init(xmlTextReaderPtr reader) {
- XmlNode::Init(reader);
-
- appid = xmlTextReaderGetAttribute(reader,
- const_cast<xmlChar*>(reinterpret_cast<const xmlChar*>("appid")));
- exec = xmlTextReaderGetAttribute(reader,
- const_cast<xmlChar*>(reinterpret_cast<const xmlChar*>("exec")));
- type = xmlTextReaderGetAttribute(reader,
- const_cast<xmlChar*>(reinterpret_cast<const xmlChar*>("type")));
- multiple = xmlTextReaderGetAttribute(reader,
- const_cast<xmlChar*>(reinterpret_cast<const xmlChar*>("multiple")));
- taskmanage = xmlTextReaderGetAttribute(reader,
- const_cast<xmlChar*>(reinterpret_cast<const xmlChar*>("taskmanage")));
- nodisplay = xmlTextReaderGetAttribute(reader,
- const_cast<xmlChar*>(reinterpret_cast<const xmlChar*>("nodisplay")));
- }
- virtual ~XmlNodeUiApplication() {
- xmlFree(appid);
- xmlFree(exec);
- xmlFree(type);
- xmlFree(multiple);
- xmlFree(taskmanage);
- xmlFree(nodisplay);
- }
-};
-
-
-class XmlNodePrivilege : public XmlNode {
- public:
- XmlNodePrivilege() {
- XmlNode::SetExpectedNodeName("privilege");
- }
- virtual void Init(xmlTextReaderPtr reader) {
- XmlNode::Init(reader);
- }
-};
-
-class XmlNodePrivileges: public XmlNode {
- public:
- vector<XmlNodePrivilege *> v_privilege;
-
- XmlNodePrivileges() {
- XmlNode::SetExpectedNodeName("privileges");
- }
- ~XmlNodePrivileges() {
- // clear v_privilege
- vector<XmlNodePrivilege *>::iterator it;
- for (auto& ptr : v_privilege) {
- delete ptr;
- }
- }
- virtual void Init(xmlTextReaderPtr reader) {
- XmlNode::Init(reader);
- }
- virtual void addPrivilege(xmlTextReaderPtr reader) {
- if (xmlStrEqual(xmlTextReaderConstName(reader),
- reinterpret_cast<const xmlChar *>("privilege"))) {
- XmlNodePrivilege *p = new XmlNodePrivilege();
- p->Init(reader);
- v_privilege.push_back(p);
- }
- }
- vector<XmlNodePrivilege *> getPrivilegeVector(void) {
- return v_privilege;
- }
-};
-
-class XmlNodeManifest : public XmlNode {
- public:
- xmlChar *xmlns;
- xmlChar *api_version;
- xmlChar *package;
- xmlChar *version;
- XmlNodeProfile profile;
- XmlNodeUiApplication ui_application;
- XmlNodePrivileges privileges;
-
- XmlNodeManifest()
- : xmlns(NULL),
- api_version(NULL),
- package(NULL),
- version(NULL) {
- XmlNode::SetExpectedNodeName("manifest");
- }
-
- void Init(xmlTextReaderPtr reader) {
- XmlNode::Init(reader);
-
- xmlns = xmlTextReaderGetAttribute(reader,
- reinterpret_cast<const xmlChar*>("xmlns"));
- api_version = xmlTextReaderGetAttribute(reader,
- reinterpret_cast<const xmlChar*>("api-version"));
- package = xmlTextReaderGetAttribute(reader,
- reinterpret_cast<const xmlChar*>("package"));
- version = xmlTextReaderGetAttribute(reader,
- reinterpret_cast<const xmlChar*>("version"));
- }
-
- ~XmlNodeManifest() {
- xmlFree(xmlns);
- xmlFree(api_version);
- xmlFree(package);
- xmlFree(version);
- }
-};
-
-} // namespace tpk
-#endif // TPK_XML_NODES_H_
manifest_handler_unittest
manifest_util_unittest
widget_manifest_parser_unittest
+ xml_parser_unittest
)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../)
+
# Executables
ADD_EXECUTABLE(values_unittest
utils_values_unittest.cc)
widget_manifest_parser_manifest_util_unittest.cc)
ADD_EXECUTABLE(widget_manifest_parser_unittest
widget_manifest_parser_unittest.cc)
+ADD_EXECUTABLE(xml_parser_unittest
+ xml_parser_unittest.cc ../xml_parser/xml_parser.cc)
INSTALL(DIRECTORY test_samples/ DESTINATION ${SHAREDIR}/app-installers-ut/test_samples)
target_link_libraries(manifest_handler_unittest PUBLIC ${TARGET_LIBNAME_WIDGET_MANIFEST_PARSER} ${GTEST_MAIN_LIBRARIES})
target_link_libraries(manifest_util_unittest PUBLIC ${TARGET_LIBNAME_WIDGET_MANIFEST_PARSER} ${GTEST_MAIN_LIBRARIES})
target_link_libraries(widget_manifest_parser_unittest PUBLIC ${TARGET_LIBNAME_WIDGET_MANIFEST_PARSER} ${GTEST_MAIN_LIBRARIES})
+target_link_libraries(xml_parser_unittest PUBLIC ${TARGET_LIBNAME_XML_PARSER} ${GTEST_MAIN_LIBRARIES})
FOREACH(test ${TESTS})
INSTALL(TARGETS ${test} DESTINATION ${BINDIR}/app-installers-ut)
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="2.3" package="org.tizen.testapp" version="1.0.0">
+ <author email="tester@samsung.com" href="www.tizen.org">tester</author>
+ <description>This is default description</description>
+ <description xml:lang="en-us">This is test description</description>
+ <ui-application appid="org.tizen.testapp" exec="testapp" multiple="false" nodisplay="false" taskmanage="true" type="capp">
+ <label>testapp</label>
+ <label xml:lang="en-us">Test</label>
+ <icon>testapp.png</icon>
+ <app-control>
+ <mime name="EditMime"/>
+ <operation name="http://tizen.org/appcontrol/operation/edit"/>
+ <uri name="EditUri"/>
+ </app-control>
+ <app-control>
+ <operation name="http://tizen.org/appcontrol/operation/view"/>
+ <uri name="ViewUri"/>
+ <mime name="ViewMime"/>
+ </app-control>
+ <metadata key="metakey1" value="metaval1"/>
+ <metadata key="metakey2" value="metaval2"/>
+ <datacontrol access="ReadOnly" providerid="http://testapp.com/datacontrol/provider/testapp" type="Sql"/>
+ <datacontrol access="ReadOnly" providerid="http://testapp.com/datacontrol/provider/testapp" type="Map"/>
+ </ui-application>
+ <account>
+ <account-provider appid="org.tizen.testapp" multiple-accounts-support="false" providerid="com.samsung">
+ <icon section="account">testapp.png</icon>
+ <icon section="account-small">testapp.png</icon>
+ <label xml:lang="en-gb">account icon</label>
+ <label>Samsung</label>
+ <capability>http://tizen.org/account/capability/calendar</capability>
+ <capability>http://tizen.org/account/capability/photo</capability>
+ </account-provider>
+ </account>
+ <privileges>
+ <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
+ <privilege>http://tizen.org/privilege/packagemanager.info</privilege>
+ </privileges>
+ <feature name="http://tizen.org/feature/camera.front.flash">true</feature>
+ <feature name="http://tizen.org/feature/camera">true</feature>
+ <feature name="http://tizen.org/feature/camera.back.flash">true</feature>
+ <feature name="http://tizen.org/feature/camera.front">true</feature>
+</manifest>
--- /dev/null
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache 2.0 license that can be
+// found in the LICENSE file.
+
+#include <gtest/gtest.h>
+#include <boost/filesystem/path.hpp>
+#include <iostream>
+#include <memory>
+#include "xml_parser/xml_parser.h"
+
+namespace {
+
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::unique_ptr;
+using xml_parser::XmlElement;
+using xml_parser::XmlTree;
+using xml_parser::XmlParser;
+
+namespace bf = boost::filesystem;
+
+class TestXmlParser : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ }
+ virtual void TearDown() {
+ }
+};
+
+// Tests manifest parser with proper manifest
+TEST_F(TestXmlParser, ReadManifestXml) {
+ const char* filename = "/usr/share/app-installers-ut/test_samples/tpk-sample-manifest.xml";
+ XmlParser p;
+
+ unique_ptr<XmlTree> t(p.ParseAndGetNewTree(filename));
+ ASSERT_TRUE(t != nullptr);
+
+ XmlElement* root = t->GetRootElement();
+ ASSERT_TRUE(root->name() == "manifest");
+ ASSERT_TRUE(root->attr("api-version") == "2.3");
+
+ XmlElement* ui_application = t->Children(root, "ui-application")[0];
+ ASSERT_TRUE(ui_application->attr("appid") == "org.tizen.testapp");
+
+ XmlElement* app_control0 = t->Children(ui_application, "app-control")[0];
+ XmlElement* operation = t->Children(app_control0, "operation")[0];
+ ASSERT_TRUE(operation->attr("name") ==
+ "http://tizen.org/appcontrol/operation/edit");
+
+ XmlElement* privileges = t->Children(root, "privileges")[0];
+ XmlElement* privilege1 = t->Children(privileges, "privilege")[1];
+ ASSERT_TRUE(privilege1->content() ==
+ "http://tizen.org/privilege/packagemanager.info");
+
+ XmlElement* feature3 = t->Children(root, "feature")[3];
+ ASSERT_TRUE(feature3->attr("name") ==
+ "http://tizen.org/feature/camera.front");
+ ASSERT_TRUE(feature3->content() == "true");
+
+ // null_string equality test(should be true)
+ ASSERT_TRUE(feature3->attr("nonexist_attr") == XmlElement::null_string());
+
+}
+
+} // namespace
--- /dev/null
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#include "xml_parser/xml_parser.h"
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlstring.h>
+#include <iostream>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+using std::map;
+using std::string;
+using std::vector;
+
+namespace xml_parser {
+
+namespace { // static namespace
+
+string xmlChar2string(const xmlChar *str) {
+ return string(const_cast<char*>(reinterpret_cast<const char*>(str)));
+}
+
+} // namespace
+
+
+// class XmlElement
+XmlElement::XmlElement(xmlNode *node) {
+ name_ = xmlChar2string(node->name);
+ xmlChar* content = xmlNodeGetContent(node); // NOTE: Needs to be freed
+ content_ = xmlChar2string(content);
+ xmlFree(content);
+ SetAttrMap(node);
+ node_ = node;
+}
+
+XmlElement::~XmlElement() {
+ attr_map_.clear();
+}
+
+const string& XmlElement::attr(const string& attrName) {
+ map<string, string>::iterator it = attr_map_.find(attrName);
+ if (it != attr_map_.end()) {
+ return it->second;
+ }
+ return XmlElement::null_string();
+}
+
+void XmlElement::SetAttrMap(xmlNode* node) {
+ xmlAttr* attr;
+ const xmlChar* name;
+ xmlChar* value;
+
+ for (attr=node->properties; attr != nullptr; attr=attr->next) {
+ name = attr->name;
+ value = xmlGetProp(node, name); // NOTE: Needs to be freed
+
+ attr_map_.insert(map<string, string>::value_type(
+ xmlChar2string(name), xmlChar2string(value)));
+
+ xmlFree(value);
+ }
+}
+
+const string& XmlElement::null_string() {
+ // NOTE: check-coding-rule says that const/static string is to be changed to
+ // const char[], but here we need a string object reference, instead of
+ // C-style const char.
+ static const string nullstr = string("");
+ return nullstr;
+}
+
+
+// class XmlTree
+XmlTree::XmlTree(xmlDoc* doc) : doc_(doc), root_(nullptr) {
+}
+
+XmlTree::~XmlTree() {
+ xmlFreeDoc(doc_);
+
+ // Clear element_map_
+ for (auto& it : elements_map_) {
+ delete it.second;
+ }
+ elements_map_.clear();
+}
+
+void XmlTree::StoreElement(xmlNode* node, XmlElement *el) {
+ elements_map_.insert(std::pair<xmlNode*, XmlElement*>(node, el));
+}
+
+XmlElement* XmlTree::FindElement(xmlNode* node) {
+ map<xmlNode*, XmlElement*>::iterator it = elements_map_.find(node);
+ if (it != elements_map_.end()) {
+ return it->second;
+ }
+ return nullptr;
+}
+
+XmlElement* XmlTree::GetRootElement() {
+ if (root_) return root_;
+
+ xmlNode* root_node = xmlDocGetRootElement(doc_);
+ if (root_node == nullptr) {
+ return nullptr;
+ }
+
+ // Get information of the node
+ XmlElement* root = new XmlElement(root_node);
+ StoreElement(root_node, root);
+ root_ = root;
+
+ return root_;
+}
+
+vector<XmlElement*> XmlTree::Children(
+ XmlElement* parent,
+ const std::string& name) {
+ xmlNode* child;
+ XmlElement *el;
+ vector<XmlElement*> children;
+
+ for (child = xmlFirstElementChild(parent->node());
+ nullptr != child;
+ child = xmlNextElementSibling(child)) {
+ if (name == xmlChar2string(child->name)) {
+ // Found a matched node
+ // Search map
+ el = FindElement(child);
+ if (!el) { // Not in elements_map_
+ el = new XmlElement(child);
+ StoreElement(child, el);
+ }
+ // Add to children
+ children.push_back(el);
+ }
+ }
+ return children;
+}
+
+
+
+// class XmlParser
+XmlParser::XmlParser() {
+}
+
+XmlParser::~XmlParser() {
+ // NOTE: These libxml2 cleanup funcs must be called after all libxml2 funcs
+ // are compelte.
+
+ // xmlCleanupParser();
+ // xmlMemoryDump();
+}
+
+XmlTree* XmlParser::ParseAndGetNewTree(const char* xmlFilePath) {
+ LIBXML_TEST_VERSION
+
+ XmlTree* t = nullptr;
+ xmlDocPtr doc = xmlReadFile(xmlFilePath, NULL, 0);
+ if (doc) {
+ t = new XmlTree(doc);
+ } else {
+ // TODO(youmin.ha@samsung.com): Error log
+ }
+ return t;
+ // NOTE: doc will be freed by XmlTree.
+}
+
+} // namespace xml_parser
--- /dev/null
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#ifndef XML_PARSER_XML_PARSER_H_
+#define XML_PARSER_XML_PARSER_H_
+
+#include <libxml/tree.h>
+#include <map>
+#include <string>
+#include <vector>
+
+namespace xml_parser {
+
+class XmlElement {
+ public:
+ static const std::string& null_string();
+
+ explicit XmlElement(xmlNode *node);
+ ~XmlElement();
+ const std::string& name() { return name_; }
+ const std::string& content() { return content_; }
+ const std::string& attr(const std::string& attrName);
+ xmlNode* node() { return node_; }
+
+ private:
+ void SetAttrMap(xmlNode* node);
+
+ std::string name_;
+ std::string content_;
+ std::map<std::string, std::string> attr_map_;
+ xmlNode* node_;
+};
+
+class XmlTree {
+ public:
+ explicit XmlTree(xmlDoc* doc);
+ ~XmlTree();
+
+ // Note: Each XmlElement* is available when the XmlTree object is valid.
+ XmlElement* GetRootElement();
+ std::vector<XmlElement*> Children(XmlElement* parent,
+ const std::string& name = "");
+
+ private:
+ void StoreElement(xmlNode* node, XmlElement *el);
+ XmlElement* FindElement(xmlNode* node);
+
+ std::map<xmlNode*, XmlElement*> elements_map_;
+ XmlElement* root_;
+ xmlDoc* doc_;
+};
+
+
+class XmlParser {
+ public:
+ XmlParser();
+ ~XmlParser();
+ XmlTree* ParseAndGetNewTree(const char* xmlFilePath = "");
+
+ private:
+};
+
+} // namespace xml_parser
+
+#endif // XML_PARSER_XML_PARSER_H_