Native tpk backend implementation: First version.
Only simple tizen-manifest.xml format can be parsed for now.
Signed-Off-By: Youmin Ha <youmin.ha@samsung.com>
Change-Id: I95037fa6b08639c6dd008d0ffb796cfd375c8060
SET(TARGET_WGT_BACKEND "wgt-backend")
SET(TARGET_XPK_BACKEND "xpk-backend")
SET(TARGET_NATIVE_BACKEND "native-backend")
+SET(TARGET_TPK_BACKEND "tpk-backend")
ADD_DEFINITIONS("-Wall")
ADD_DEFINITIONS("-Wextra")
%description -n xpk-backend
Backend for standard widget files XPK
+%package -n tpk-backend
+Summary: Backend of TPK files
+
+%description -n tpk-backend
+Backend for tizen package files
+
%prep
%setup -q
mkdir -p %{buildroot}/etc/package-manager/backend
ln -s %{_bindir}/wgt-backend %{buildroot}%{_sysconfdir}/package-manager/backend/wgt
ln -s %{_bindir}/xpk-backend %{buildroot}%{_sysconfdir}/package-manager/backend/xpk
+ln -s %{_bindir}/tpk-backend %{buildroot}%{_sysconfdir}/package-manager/backend/tpk
%post -p /sbin/ldconfig
%files -n xpk-backend
%{_sysconfdir}/package-manager/backend/xpk
+
+%files -n tpk-backend
+%{_sysconfdir}/package-manager/backend/tpk
+%{_bindir}/tpk-backend
+
ADD_SUBDIRECTORY(utils)
ADD_SUBDIRECTORY(wgt)
ADD_SUBDIRECTORY(widget-manifest-parser)
+ADD_SUBDIRECTORY(tpk)
#ADD_SUBDIRECTORY(xpk)
#ADD_SUBDIRECTORY(native)
--- /dev/null
+IF(NOT DEFINED TARGET_TPK_BACKEND)
+ SET(TARGET_TPK_BACKEND "tpk-backend")
+ENDIF(NOT DEFINED TARGET_TPK_BACKEND)
+
+SET(TARGET_TPK ${TARGET_TPK_BACKEND})
+OPTION(HOSTTEST "Option for the test on the host PC" OFF)
+SET(SRCS
+ main.cc
+ task.cc
+ step/step_parse.cc
+ step/step_symbolic_link.cc
+ manifest_parser.cc
+)
+ADD_EXECUTABLE(${TARGET_TPK} ${SRCS})
+
+SET(TPK_LDFLAGS -rdynamic)
+IF(${HOSTTEST})
+ MESSAGE("Host Test mode.")
+SET(TPK_CFLAGS ${TPK_CFLAGS} -DHOSTTEST)
+ SET(MOCK_MODULES test/mock_pkgmgr_installer.c)
+SET(SRCS ${SRCS} ${MOCK_MODULES})
+
+ELSE(${HOSTTEST})
+ SET(TPK_CFLAGS ${TPK_CFLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}/../)
+ ADD_DEFINITIONS(${TPK_CFLAGS})
+ENDIF(${HOSTTEST})
+
+APPLY_PKG_CONFIG(${TARGET_TPK} PUBLIC PKGMGR_DEPS)
+TARGET_LINK_LIBRARIES(${TARGET_TPK} PUBLIC ${TARGET_LIBNAME_COMMON})
+
+INSTALL(TARGETS ${TARGET_TPK} DESTINATION ${BINDIR})
--- /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_
--- /dev/null
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#include <iostream>
+#include <cerrno>
+#include "tpk/task.h"
+#include "tpk/exception.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();
+ 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_
--- /dev/null
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#include "tpk/step/step_parse.h"
+#include <boost/filesystem.hpp>
+#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"
+
+using std::vector;
+
+namespace tpk {
+namespace step {
+
+namespace {
+ const char kManifestFileName[] = "tizen-manifest.xml";
+} // namespace
+
+SCOPE_LOG_TAG(StepParse)
+
+/* short namespace/class name */
+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) {
+ return Status::ERROR;
+ } catch (FileOpenFailureException &e) {
+ return Status::ERROR;
+ }
+ return Status::OK;
+}
+
+
+/* in parse() : Get manifest file path from the package unzipped directory
+ */
+boost::filesystem::path StepParse::GetManifestFilePath(
+ const boost::filesystem::path& dir) {
+ path mPath(dir);
+ mPath /= kManifestFileName;
+
+ LOG(INFO) << "manifest file path: " << mPath;
+ if (!boost::filesystem::exists(mPath)) {
+ LOG(ERROR) << kManifestFileName << " not found from the package";
+ throw FileNotFoundException();
+ }
+ 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 << ")";
+
+ // 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)));
+
+ // set context_->manifest_data()
+ SetPkgInfoManifest(context_->manifest_data(), manifest);
+}
+
+void StepParse::SetPkgInfoManifest(manifest_x* m,
+ const XmlNodeManifest &manifest) {
+ // Common values
+ m->label = static_cast<label_x*>
+ (calloc(1, sizeof(label_x)));
+ m->description = static_cast<description_x*>
+ (calloc(1, sizeof(description_x)));
+ m->privileges = static_cast<privileges_x*>
+ (calloc(1, sizeof(privileges_x)));
+ m->privileges->next = nullptr;
+ m->privileges->privilege = nullptr;
+
+ // Basic values
+ m->package = strdup(reinterpret_cast<char*>(manifest.package));
+ 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));
+
+ // Privileges
+ vector<XmlNodePrivilege *> vp =
+ const_cast<XmlNodeManifest &>(manifest).privileges.getPrivilegeVector();
+ vector<XmlNodePrivilege *>::iterator it;
+ for (it = vp.begin(); it != vp.end(); it++) {
+ privilege_x *p =
+ static_cast<privilege_x *>(calloc(1, sizeof(privilege_x)));
+ // privilege data text
+ p->text = strdup(reinterpret_cast<char*>((*it)->data));
+ LISTADD(m->privileges->privilege, p);
+ LOG(INFO) << "add privilege: " << p->text;
+ }
+
+ // Other app data (null initialization)
+ m->serviceapplication = nullptr; // ignore service application
+ m->uiapplication = static_cast<uiapplication_x*>
+ (calloc (1, sizeof(uiapplication_x)));
+ m->uiapplication->icon = static_cast<icon_x*>
+ (calloc(1, sizeof(icon_x)));
+ m->uiapplication->label = static_cast<label_x*>
+ (calloc(1, sizeof(label_x)));
+ m->description = static_cast<description_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->next = nullptr;
+}
+
+} // namespace step
+} // namespace tpk
--- /dev/null
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#ifndef TPK_STEP_STEP_PARSE_H_
+#define TPK_STEP_STEP_PARSE_H_
+
+#include <boost/filesystem.hpp>
+#include "common/step/step.h"
+#include "tpk/manifest_parser.h"
+
+namespace tpk {
+namespace step {
+
+class StepParse : public common_installer::Step {
+ public:
+ using Step::Step;
+
+ Status process() override;
+ Status clean() override { return Status::OK; };
+ Status undo() override { return Status::OK; };
+
+
+ private:
+ boost::filesystem::path
+ GetManifestFilePath(const boost::filesystem::path& dir);
+ void SetContextByManifestParser(const ManifestParser &m);
+ void SetPkgInfoManifest(manifest_x* m, const XmlNodeManifest &manifest);
+};
+
+} // namespace step
+} // namespace tpk
+
+#endif // TPK_STEP_STEP_PARSE_H_
--- /dev/null
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#include "tpk/step/step_symbolic_link.h"
+#include <boost/filesystem.hpp>
+#include <iostream>
+#include "common/step/step.h"
+#include "common/app_installer.h"
+#include "common/context_installer.h"
+#include "common/utils.h"
+#include "utils/logging.h"
+
+
+namespace tpk {
+namespace step {
+
+namespace fs = boost::filesystem;
+using common_installer::ContextInstaller;
+typedef common_installer::Step::Status Status;
+
+SCOPE_LOG_TAG(SymbolicLink)
+
+namespace {
+
+template <typename T>
+bool CreateSymLink(T *app, ContextInstaller* context) {
+ boost::system::error_code error;
+
+ for (; app != nullptr; app=app->next) {
+ fs::path bindir = fs::path(context->pkg_path()) / fs::path(app->appid) /
+ fs::path("bin");
+ LOG(INFO) << "Creating dir: " << bindir;
+ if (!utils::CreateDir(bindir)) {
+ LOG(ERROR) << "Directory creation failure";
+ return false;
+ }
+
+ // Make a symlink with the name of appid, pointing exec file
+ fs::path symlink_path = bindir / fs::path(app->appid);
+ LOG(INFO) << "Creating symlink pointing " << symlink_path << " to " <<
+ app->exec;
+ fs::create_symlink(fs::path(app->exec), symlink_path, error);
+ if (error) {
+ LOG(ERROR) << "Symlink creation failure";
+ return false;
+ }
+
+ // Give a execution permission to the original executable
+ fs::path exec_path = bindir / fs::path(app->exec);
+ LOG(INFO) << "Giving exec permission to " << exec_path;
+ fs::permissions(exec_path, fs::owner_all |
+ fs::group_read | fs::group_exe |
+ fs::others_read | fs::others_exe, error);
+ if (error) {
+ LOG(ERROR) << "Permission change failure";
+ return false;
+ }
+ }
+ return true;
+}
+
+
+template <typename T>
+bool RemoveSymLink(T *app, ContextInstaller* context) {
+ /* NOTE: Unlike WRT app, tpk apps have bin/ directory by default.
+ * So we don't remove the bin/ directory itself.
+ */
+ for (; app != nullptr; app=app->next) {
+ fs::path exec_path = fs::path(context->pkg_path()) /
+ fs::path(app->appid) / fs::path("bin");
+ fs::remove_all(exec_path / fs::path(app->appid));
+ }
+ return true;
+}
+
+} // namespace
+
+
+
+Status StepSymbolicLink::process() {
+ // Get manifest_x
+ manifest_x *m = context_->manifest_data();
+ if (!m) {
+ LOG(ERROR) << "manifest_x is null";
+ return Status::ERROR;
+ }
+
+ // get ui-app and service-app
+ uiapplication_x *uiapp = m->uiapplication;
+ serviceapplication_x *svcapp = m->serviceapplication;
+ if (!(uiapp || svcapp)) {
+ LOG(ERROR) << "Neither ui-application nor service-application exists";
+ return Status::ERROR;
+ }
+ if (!CreateSymLink(uiapp, context_)) return Status::ERROR;
+ if (!CreateSymLink(svcapp, context_)) return Status::ERROR;
+
+ return Status::OK;
+}
+
+
+Status StepSymbolicLink::clean() {
+ return Status::OK;
+}
+
+
+Status StepSymbolicLink::undo() {
+ manifest_x* m = context_->manifest_data();
+ uiapplication_x *uiapp = m->uiapplication;
+ serviceapplication_x *svcapp = m->serviceapplication;
+ if (!RemoveSymLink(uiapp, context_)) return Status::ERROR;
+ if (!RemoveSymLink(svcapp, context_)) return Status::ERROR;
+
+ return Status::OK;
+}
+
+} // namespace step
+} // namespace tpk
--- /dev/null
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#ifndef TPK_STEP_STEP_SYMBOLIC_LINK_H_
+#define TPK_STEP_STEP_SYMBOLIC_LINK_H_
+
+#include "common/app_installer.h"
+
+namespace tpk {
+namespace step {
+
+class StepSymbolicLink : public common_installer::Step {
+ public:
+ using Step::Step;
+ Status process() override;
+ Status clean() override;
+ Status undo() override;
+};
+
+} // namespace step
+} // namespace tpk
+
+#endif // TPK_STEP_STEP_SYMBOLIC_LINK_H_
--- /dev/null
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#include "tpk/task.h"
+#ifdef HOSTTEST
+#include "test/mock_pkgmgr_installer.h"
+#else
+#include <pkgmgr_installer.h>
+#include "common/app_installer.h"
+#include "common/step/step_copy.h"
+#include "common/step/step_generate_xml.h"
+#include "common/step/step_parse.h"
+#include "common/step/step_record.h"
+#include "common/step/step_remove.h"
+#include "common/step/step_revoke_security.h"
+#include "common/step/step_security.h"
+#include "common/step/step_signal.h"
+#include "common/step/step_signature.h"
+#include "common/step/step_unregister.h"
+#include "common/step/step_unzip.h"
+#include "tpk/step/step_parse.h"
+#include "tpk/step/step_symbolic_link.h"
+#include "tpk/exception.h"
+#endif
+
+
+namespace ci = common_installer;
+
+namespace {
+ const char kPkgType[] = "tpk";
+} // namespace
+
+
+namespace tpk {
+
+/* 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_);
+}
+
+
+/* Destructor
+ */
+::tpk::Task::~Task() {
+ if (pi_) {
+ pkgmgr_installer_free(pi_);
+ pi_ = NULL;
+ }
+}
+
+
+void Task::Run(void) {
+ switch (request_) {
+ case PKGMGR_REQ_INSTALL:
+ Install();
+ break;
+ case PKGMGR_REQ_UNINSTALL:
+ Uninstall();
+ break;
+ case PKGMGR_REQ_REINSTALL:
+ Reinstall();
+ break;
+ default:
+ throw Exception("Unsupported request");
+ }
+}
+
+void Task::Install(void) {
+ ci::AppInstaller ai(pi_, kPkgType);
+
+ ai.AddStep<ci::unzip::StepUnzip>();
+ ai.AddStep<ci::signature::StepSignature>();
+ ai.AddStep<tpk::step::StepParse>();
+ ai.AddStep<ci::signal::StepSignal>();
+ ai.AddStep<ci::copy::StepCopy>();
+ ai.AddStep<tpk::step::StepSymbolicLink>();
+ ai.AddStep<ci::security::StepSecurity>();
+ ai.AddStep<ci::generate_xml::StepGenerateXml>();
+ ai.AddStep<ci::record::StepRecord>();
+
+ ai.Run();
+}
+
+void Task::Uninstall(void) {
+ ci::AppInstaller ai(pi_, kPkgType);
+
+ ai.AddStep<ci::parse::StepParse>();
+ ai.AddStep<ci::signal::StepSignal>();
+ ai.AddStep<ci::revoke_security::StepRevokeSecurity>();
+ ai.AddStep<ci::unregister::StepUnregister>();
+ ai.AddStep<ci::remove::StepRemove>();
+
+ ai.Run();
+}
+
+void Task::Reinstall(void) {
+}
+
+} // namespace tpk
+
--- /dev/null
+/* Copyright 2015 Samsung Electronics, license APACHE-2.0, see LICENSE file */
+#ifndef TPK_TASK_H_
+#define TPK_TASK_H_
+
+#ifdef HOSTTEST
+#include "test/mock_pkgmgr_installer.h"
+#else
+#include <pkgmgr_installer.h>
+#endif
+
+namespace tpk {
+
+class Task {
+ public:
+ Task(int argc, char** argv);
+ ~Task();
+ void Run();
+
+
+ private:
+ void Install();
+ void Uninstall();
+ void Reinstall();
+
+ pkgmgr_installer* pi_;
+ int request_;
+}; // class Task
+
+} // namespace tpk
+#endif // TPK_TASK_H_
--- /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() : name(NULL), data(NULL), depth(-1),
+ node_type(XML_READER_TYPE_NONE) {
+ }
+
+ 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_