StepParseManifest 49/57749/3
authorTomasz Iwanek <t.iwanek@samsung.com>
Thu, 21 Jan 2016 12:47:23 +0000 (13:47 +0100)
committerTomasz Iwanek <t.iwanek@samsung.com>
Fri, 22 Jan 2016 14:03:05 +0000 (06:03 -0800)
StepParseManifest will replace:
 - common::StepOldManifest
 - common::StepParse
 - tpk::StepParse (most of code comes from here)

as tpk-manifest-parser needs to be used instead of pkgmgr-parser
in parsing manifest file in deinstallation and update modes of
tpk-backend as well as wgt-backend.

Change-Id: Ib05249c229d1a73d4c79ed5ebeedf72e783dad78

CMakeLists.txt
packaging/app-installers.spec
src/common/CMakeLists.txt
src/common/step/step_parse_manifest.cc [new file with mode: 0644]
src/common/step/step_parse_manifest.h [new file with mode: 0644]

index e86a679..62bea53 100644 (file)
@@ -51,6 +51,7 @@ PKG_CHECK_MODULES(PKGMGR_INFO_DEPS REQUIRED pkgmgr-info)
 PKG_CHECK_MODULES(LIBXML_DEPS REQUIRED libxml-2.0)
 PKG_CHECK_MODULES(PRIVILEGE_CHECKER_DEPS REQUIRED capi-security-privilege-manager)
 PKG_CHECK_MODULES(APPMANAGER_DEPS REQUIRED capi-appfw-app-manager)
+PKG_CHECK_MODULES(TPK_MANIFEST_HANDLERS_DEPS REQUIRED tpk-manifest-handlers)
 
 FIND_PACKAGE(Boost REQUIRED COMPONENTS system filesystem regex program_options)
 FIND_PACKAGE(GTest REQUIRED)
index 662bfd6..59aa38b 100644 (file)
@@ -31,6 +31,7 @@ BuildRequires:  pkgconfig(manifest-parser-utils)
 BuildRequires:  pkgconfig(delta-manifest-handlers)
 BuildRequires:  pkgconfig(capi-security-privilege-manager)
 BuildRequires:  pkgconfig(capi-appfw-app-manager)
+BuildRequires:  pkgconfig(tpk-manifest-handlers)
 
 Requires: ca-certificates-tizen
 Requires: libtzplatform-config
index 55e1e15..eae3ded 100644 (file)
@@ -25,6 +25,7 @@ SET(SRCS
   step/step_delta_patch.cc
   step/step_fail.cc
   step/step_kill_apps.cc
+  step/step_parse_manifest.cc
   step/step_recover_application.cc
   step/step_recover_files.cc
   step/step_recover_icons.cc
@@ -71,6 +72,7 @@ APPLY_PKG_CONFIG(${TARGET_LIBNAME_COMMON} PUBLIC
   PRIVILEGE_CHECKER_DEPS
   APPMANAGER_DEPS
   DELTA_MANIFEST_HANDLERS_DEPS
+  TPK_MANIFEST_HANDLERS_DEPS
   Boost
 )
 
diff --git a/src/common/step/step_parse_manifest.cc b/src/common/step/step_parse_manifest.cc
new file mode 100644 (file)
index 0000000..e540714
--- /dev/null
@@ -0,0 +1,692 @@
+// 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 "common/step/step_parse_manifest.h"
+
+#include <pkgmgr/pkgmgr_parser.h>
+#include <pkgmgr-info.h>
+
+#include <tpk_manifest_handlers/account_handler.h>
+#include <tpk_manifest_handlers/application_manifest_constants.h>
+#include <tpk_manifest_handlers/author_handler.h>
+#include <tpk_manifest_handlers/description_handler.h>
+#include <tpk_manifest_handlers/package_handler.h>
+#include <tpk_manifest_handlers/privileges_handler.h>
+#include <tpk_manifest_handlers/profile_handler.h>
+#include <tpk_manifest_handlers/service_application_handler.h>
+#include <tpk_manifest_handlers/shortcut_handler.h>
+#include <tpk_manifest_handlers/ui_application_handler.h>
+#include <tpk_manifest_handlers/widget_application_handler.h>
+
+#include <chrono>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <memory>
+#include <set>
+#include <type_traits>
+#include <string>
+#include <vector>
+
+#include "common/app_installer.h"
+#include "common/backup_paths.h"
+#include "common/installer_context.h"
+#include "common/step/step.h"
+#include "common/utils/glist_range.h"
+
+namespace app_keys = tpk::application_keys;
+namespace bf = boost::filesystem;
+
+namespace {
+
+const char kManifestFileName[] = "tizen-manifest.xml";
+
+}  // namepsace
+
+namespace common_installer {
+namespace parse {
+
+StepParseManifest::StepParseManifest(
+    InstallerContext* context, ManifestLocation manifest_location,
+    StoreLocation store_location)
+    : Step(context),
+      manifest_location_(manifest_location),
+      store_location_(store_location) {
+}
+
+Step::Status StepParseManifest::precheck() {
+  switch (manifest_location_) {
+    case ManifestLocation::RECOVERY:
+    case ManifestLocation::INSTALLED:
+      if (context_->pkgid.get().empty()) {
+        LOG(ERROR) << "Package id is not set";
+        return Status::INVALID_VALUE;
+      }
+      break;
+    case ManifestLocation::PACKAGE:
+      if (context_->unpacked_dir_path.get().empty()) {
+        LOG(ERROR) << "Unpacked directory doesn't exist";
+        return Status::INVALID_VALUE;
+      }
+      break;
+    default:
+      LOG(ERROR) << "Unknown manifest location";
+      return Status::INVALID_VALUE;
+  }
+  return Status::OK;
+}
+
+bool StepParseManifest::LocateConfigFile() {
+  boost::filesystem::path manifest;
+  switch (manifest_location_) {
+    case ManifestLocation::RECOVERY: {
+      context_->pkg_path.set(
+          context_->root_application_path.get() / context_->pkgid.get());
+      bf::path backup_path = common_installer::GetBackupPathForPackagePath(
+          context_->pkg_path.get()) / kManifestFileName;
+      bf::path in_package_path = context_->pkg_path.get() / kManifestFileName;
+      if (bf::exists(backup_path))
+        manifest = backup_path;
+      else if (bf::exists(in_package_path))
+        manifest = in_package_path;
+      break;
+    }
+    case ManifestLocation::INSTALLED: {
+      bf::path xml_path = bf::path(getUserManifestPath(context_->uid.get()))
+          / bf::path(context_->pkgid.get());
+      xml_path += ".xml";
+      context_->xml_path.set(xml_path);
+      manifest = context_->xml_path.get();
+      break;
+    }
+    case ManifestLocation::PACKAGE: {
+      manifest = context_->unpacked_dir_path.get();
+      manifest /= kManifestFileName;
+      break;
+    }
+    default: {
+      LOG(ERROR) << "Unknown manifest location value";
+      return false;
+    }
+  }
+
+  LOG(DEBUG) << "manifest path: " << manifest;
+
+  if (!boost::filesystem::exists(manifest))
+    return false;
+
+  path_ = manifest;
+  return true;
+}
+
+bool StepParseManifest::FillInstallationInfo(manifest_x* manifest) {
+  manifest->root_path = strdup(
+      (context_->root_application_path.get() / manifest->package).c_str());
+  manifest->installed_time =
+      strdup(std::to_string(std::chrono::system_clock::to_time_t(
+          std::chrono::system_clock::now())).c_str());
+  return true;
+}
+
+bool StepParseManifest::FillPackageInfo(manifest_x* manifest) {
+  std::shared_ptr<const tpk::parse::PackageInfo> pkg_info =
+      std::static_pointer_cast<const tpk::parse::PackageInfo>(
+          parser_->GetManifestData(app_keys::kManifestKey));
+  if (!pkg_info) {
+    LOG(ERROR) << "Package info manifest data has not been found.";
+    return false;
+  }
+
+  auto ui_application_list =
+      std::static_pointer_cast<const tpk::parse::UIApplicationInfoList>(
+          parser_->GetManifestData(app_keys::kUIApplicationKey));
+  auto service_application_list =
+      std::static_pointer_cast<const tpk::parse::ServiceApplicationInfoList>(
+          parser_->GetManifestData(app_keys::kServiceApplicationKey));
+  auto widget_application_list =
+      std::static_pointer_cast<const tpk::parse::WidgetApplicationInfoList>(
+          parser_->GetManifestData(app_keys::kWidgetApplicationKey));
+
+  // mandatory check
+  if (!ui_application_list && !service_application_list &&
+      !widget_application_list) {
+    LOG(ERROR) << "UI Application or Service Application or Widget Application "
+                  "are mandatory and has not been found.";
+    return false;
+  }
+
+  manifest->ns = strdup(pkg_info->xmlns().c_str());
+  manifest->package = strdup(pkg_info->package().c_str());
+  manifest->nodisplay_setting = strdup(pkg_info->nodisplay_setting().c_str());
+  manifest->appsetting = strdup("false");
+  manifest->support_disable = strdup("false");
+  manifest->version = strdup(pkg_info->version().c_str());
+  manifest->installlocation = strdup(pkg_info->install_location().c_str());
+  manifest->api_version = strdup(pkg_info->api_version().c_str());
+  if (context_->pkg_type.get().compare("rpm") == 0)
+    manifest->type = strdup("rpm");
+  else
+    manifest->type = strdup("tpk");
+
+  for (auto& pair : pkg_info->labels()) {
+    label_x* label = reinterpret_cast<label_x*>(calloc(1, sizeof(label_x)));
+    if (!pair.first.empty())
+      label->lang = strdup(pair.first.c_str());
+    else
+      label->lang = strdup(DEFAULT_LOCALE);
+    label->name = strdup(pair.second.c_str());
+    manifest->label = g_list_append(manifest->label, label);
+  }
+
+  std::shared_ptr<const tpk::parse::ProfileInfo> profile_info =
+      std::static_pointer_cast<const tpk::parse::ProfileInfo>(
+          parser_->GetManifestData(tpk::parse::ProfileInfo::Key()));
+  if (profile_info) {
+    for (auto& profile : profile_info->profiles()) {
+      manifest->deviceprofile = g_list_append(manifest->deviceprofile,
+                                              strdup(profile.c_str()));
+    }
+  }
+
+  if (ui_application_list) {
+    manifest->mainapp_id =
+        strdup(ui_application_list->items[0].app_info.appid().c_str());
+  } else if (service_application_list) {
+    manifest->mainapp_id =
+        strdup(service_application_list->items[0].app_info.appid().c_str());
+  } else if (widget_application_list) {
+    manifest->mainapp_id =
+        strdup(widget_application_list->items[0].app_info.appid().c_str());
+  }
+  return true;
+}
+
+bool StepParseManifest::FillAuthorInfo(manifest_x* manifest) {
+  std::shared_ptr<const tpk::parse::AuthorInfo> author_info =
+      std::static_pointer_cast<const tpk::parse::AuthorInfo>(
+          parser_->GetManifestData(app_keys::kAuthorKey));
+
+  if (!author_info) {
+    LOG(ERROR) << "Author data has not been found.";
+    return false;
+  }
+
+  author_x* author = reinterpret_cast<author_x*>(calloc(1, sizeof(author_x)));
+  author->text = strdup(author_info->name().c_str());
+  author->email = strdup(author_info->email().c_str());
+  author->href = strdup(author_info->href().c_str());
+  author->lang = strdup(DEFAULT_LOCALE);
+  manifest->author = g_list_append(manifest->author, author);
+  return true;
+}
+
+bool StepParseManifest::FillDescription(manifest_x* manifest) {
+  std::shared_ptr<const tpk::parse::DescriptionInfo> description_info =
+      std::static_pointer_cast<const tpk::parse::DescriptionInfo>(
+          parser_->GetManifestData(app_keys::kDescriptionKey));
+
+  if (!description_info) {
+    LOG(ERROR) << "Description data has not been found.";
+    return false;
+  }
+
+  description_x* description = reinterpret_cast<description_x*>
+      (calloc(1, sizeof(description_x)));
+  description->text = strdup(description_info->description().c_str());
+  description->lang = !description_info->xml_lang().empty() ?
+      strdup(description_info->xml_lang().c_str()) : strdup(DEFAULT_LOCALE);
+  manifest->description = g_list_append(manifest->description, description);
+  return true;
+}
+
+bool StepParseManifest::FillPrivileges(manifest_x* manifest) {
+  std::shared_ptr<const tpk::parse::PrivilegesInfo> perm_info =
+      std::static_pointer_cast<const tpk::parse::PrivilegesInfo>(
+          parser_->GetManifestData(app_keys::kPrivilegesKey));
+  if (!perm_info)
+    return true;
+
+  std::set<std::string> privileges = perm_info->GetPrivileges();
+  for (auto& priv : privileges) {
+    manifest->privileges = g_list_append(manifest->privileges,
+                                         strdup(priv.c_str()));
+  }
+  return true;
+}
+
+bool StepParseManifest::FillWidgetApplication(manifest_x* manifest) {
+  auto widget_application_list =
+      std::static_pointer_cast<const tpk::parse::WidgetApplicationInfoList>(
+          parser_->GetManifestData(app_keys::kWidgetApplicationKey));
+  if (!widget_application_list)
+    return true;
+
+  for (const auto& application : widget_application_list->items) {
+    // if there is no app yet, set this app as mainapp
+    bool main_app = manifest->application == nullptr;
+
+    application_x* widget_app =
+        static_cast<application_x*>(calloc(1, sizeof(application_x)));
+    widget_app->appid = strdup(application.app_info.appid().c_str());
+    widget_app->launch_mode =
+        strdup(application.app_info.launch_mode().c_str());
+    widget_app->multiple = strdup(application.app_info.multiple().c_str());
+    widget_app->nodisplay =
+        strdup(application.app_info.nodisplay().c_str());
+    widget_app->type = strdup("capp");
+    widget_app->component_type = strdup("widgetapp");
+    widget_app->hwacceleration =
+        strdup(application.app_info.hwacceleration().c_str());
+    widget_app->onboot = strdup("false");
+    widget_app->autorestart = strdup("false");
+    widget_app->mainapp = main_app ? strdup("true") : strdup("false");
+    widget_app->enabled = strdup("true");
+    widget_app->screenreader = strdup("use-system-setting");
+    widget_app->recentimage = strdup("false");
+    widget_app->launchcondition = strdup("false");
+    widget_app->guestmode_visibility = strdup("true");
+    widget_app->permission_type = strdup("normal");
+    widget_app->ambient_support = strdup("false");
+    widget_app->package = strdup(manifest->package);
+    widget_app->support_disable = strdup(manifest->support_disable);
+    manifest->application = g_list_append(manifest->application, widget_app);
+    if (strncmp(context_->pkg_type.get().c_str(), "rpm", strlen("rpm")) == 0)
+      widget_app->exec = strdup(application.app_info.exec().c_str());
+    else
+      widget_app->exec = strdup((context_->root_application_path.get()
+                            / manifest->package / "bin"
+                            / application.app_info.exec()).c_str());
+
+    if (!FillApplicationIconPaths(widget_app, application.app_icons))
+      return false;
+    if (!FillLabel(widget_app, application.label))
+      return false;
+    if (!FillImage(widget_app, application.app_images))
+      return false;
+    if (!FillMetadata(widget_app, application.meta_data))
+      return false;
+  }
+  return true;
+}
+
+bool StepParseManifest::FillServiceApplication(manifest_x* manifest) {
+  auto service_application_list =
+      std::static_pointer_cast<const tpk::parse::ServiceApplicationInfoList>(
+          parser_->GetManifestData(app_keys::kServiceApplicationKey));
+  if (!service_application_list)
+    return true;
+
+  for (const auto& application : service_application_list->items) {
+    // if there is no app yet, set this app as mainapp
+    bool main_app = manifest->application == nullptr;
+
+    application_x* service_app =
+        static_cast<application_x*>(calloc(1, sizeof(application_x)));
+    service_app->appid = strdup(application.app_info.appid().c_str());
+    service_app->autorestart =
+        strdup(application.app_info.auto_restart().c_str());
+    service_app->onboot = strdup(application.app_info.on_boot().c_str());
+    service_app->type = strdup(application.app_info.type().c_str());
+    service_app->process_pool =
+        strdup(application.app_info.process_pool().c_str());
+    service_app->component_type = strdup("svcapp");
+    service_app->mainapp = main_app ? strdup("true") : strdup("false");
+    service_app->enabled = strdup("true");
+    service_app->hwacceleration = strdup("default");
+    service_app->screenreader = strdup("use-system-setting");
+    service_app->recentimage = strdup("false");
+    service_app->launchcondition = strdup("false");
+    service_app->indicatordisplay = strdup("true");
+    service_app->effectimage_type = strdup("image");
+    service_app->guestmode_visibility = strdup("true");
+    service_app->permission_type = strdup("normal");
+    service_app->submode = strdup("false");
+    service_app->process_pool = strdup("false");
+    service_app->ambient_support = strdup("false");
+    service_app->package = strdup(manifest->package);
+    service_app->support_disable = strdup(manifest->support_disable);
+    manifest->application = g_list_append(manifest->application, service_app);
+    if (strncmp(context_->pkg_type.get().c_str(), "rpm", strlen("rpm")) == 0)
+      service_app->exec = strdup(application.app_info.exec().c_str());
+    else
+      service_app->exec = strdup((context_->root_application_path.get()
+                            / manifest->package / "bin"
+                            / application.app_info.exec()).c_str());
+
+    if (!FillAppControl(service_app,  application.app_control))
+      return false;
+    if (!FillDataControl(service_app, application.data_control))
+      return false;
+    if (!FillApplicationIconPaths(service_app, application.app_icons))
+      return false;
+    if (!FillLabel(service_app, application.label))
+      return false;
+    if (!FillMetadata(service_app, application.meta_data))
+      return false;
+    if (!FillBackgroundCategoryInfo(service_app,
+        application.background_category))
+      return false;
+  }
+  return true;
+}
+
+bool StepParseManifest::FillUIApplication(manifest_x* manifest) {
+  std::shared_ptr<const tpk::parse::UIApplicationInfoList> ui_application_list =
+      std::static_pointer_cast<const tpk::parse::UIApplicationInfoList>(
+          parser_->GetManifestData(app_keys::kUIApplicationKey));
+  if (!ui_application_list)
+    return true;
+
+  for (const auto& application : ui_application_list->items) {
+    // if there is no app yet, set this app as mainapp
+    bool main_app = manifest->application == nullptr;
+
+    application_x* ui_app =
+        static_cast<application_x*>(calloc(1, sizeof(application_x)));
+    ui_app->appid = strdup(application.app_info.appid().c_str());
+    ui_app->launch_mode = strdup(application.app_info.launch_mode().c_str());
+    ui_app->multiple = strdup(application.app_info.multiple().c_str());
+    ui_app->nodisplay = strdup(application.app_info.nodisplay().c_str());
+    ui_app->taskmanage = strdup(application.app_info.taskmanage().c_str());
+    ui_app->type = strdup(application.app_info.type().c_str());
+    ui_app->component_type = strdup("uiapp");
+    ui_app->ui_gadget = strdup(application.app_info.uigadget().c_str());
+    ui_app->process_pool = strdup(application.app_info.process_pool().c_str());
+    ui_app->submode = strdup(application.app_info.submode().c_str());
+    ui_app->indicatordisplay =
+        strdup(application.app_info.indicator_display().c_str());
+    ui_app->effectimage_type =
+        strdup(application.app_info.effectimage_type().c_str());
+    ui_app->portraitimg =
+        strdup(application.app_info.portrait_image().c_str());
+    ui_app->landscapeimg =
+        strdup(application.app_info.landscape_image().c_str());
+    ui_app->submode_mainid =
+        strdup(application.app_info.submode_mainid().c_str());
+    ui_app->hwacceleration =
+        strdup(application.app_info.hwacceleration().c_str());
+    ui_app->onboot = strdup("false");
+    ui_app->autorestart = strdup("false");
+    ui_app->component_type = strdup("uiapp");
+    ui_app->mainapp = main_app ? strdup("true") : strdup("false");
+    ui_app->enabled = strdup("true");
+    ui_app->screenreader = strdup("use-system-setting");
+    ui_app->recentimage = strdup("false");
+    ui_app->launchcondition = strdup("false");
+    ui_app->guestmode_visibility = strdup("true");
+    ui_app->permission_type = strdup("normal");
+    ui_app->ambient_support = strdup("false");
+    ui_app->package = strdup(manifest->package);
+    ui_app->support_disable = strdup(manifest->support_disable);
+    manifest->application = g_list_append(manifest->application, ui_app);
+    if (strncmp(context_->pkg_type.get().c_str(), "rpm", strlen("rpm")) == 0)
+      ui_app->exec = strdup(application.app_info.exec().c_str());
+    else
+      ui_app->exec = strdup((context_->root_application_path.get()
+                            / manifest->package / "bin"
+                            / application.app_info.exec()).c_str());
+
+
+    if (!FillAppControl(ui_app, application.app_control))
+      return false;
+    if (!FillDataControl(ui_app, application.data_control))
+      return false;
+    if (!FillApplicationIconPaths(ui_app, application.app_icons))
+      return false;
+    if (!FillLabel(ui_app, application.label))
+      return false;
+    if (!FillImage(ui_app, application.app_images))
+      return false;
+    if (!FillMetadata(ui_app, application.meta_data))
+      return false;
+    if (!FillBackgroundCategoryInfo(ui_app, application.background_category))
+      return false;
+  }
+  return true;
+}
+
+template <typename T>
+bool StepParseManifest::FillAppControl(application_x* app,
+                                       const T& app_control_list) {
+  if (app_control_list.empty())
+    return true;
+
+  for (const auto& control : app_control_list) {
+    appcontrol_x* app_control =
+          static_cast<appcontrol_x*>(calloc(1, sizeof(appcontrol_x)));
+    app_control->operation = strdup(control.operation().c_str());
+    if (!control.mime().empty())
+      app_control->mime = strdup(control.mime().c_str());
+    if (!control.uri().empty())
+      app_control->uri = strdup(control.uri().c_str());
+    app->appcontrol = g_list_append(app->appcontrol, app_control);
+  }
+  return true;
+}
+
+template <typename T>
+bool StepParseManifest::FillDataControl(application_x* app,
+                                const T& data_control_list) {
+  if (data_control_list.empty())
+    return true;
+
+  for (const auto& control : data_control_list) {
+    datacontrol_x* data_control =
+          static_cast<datacontrol_x*>(calloc(1, sizeof(datacontrol_x)));
+    data_control->access = strdup(control.access().c_str());
+    data_control->providerid = strdup(control.providerid().c_str());
+    data_control->type = strdup(control.type().c_str());
+    app->datacontrol = g_list_append(app->datacontrol, data_control);
+  }
+  return true;
+}
+
+template <typename T>
+bool StepParseManifest::FillApplicationIconPaths(application_x* app,
+                                         const T& icons_info) {
+  for (auto& application_icon : icons_info.icons()) {
+    icon_x* icon = reinterpret_cast<icon_x*> (calloc(1, sizeof(icon_x)));
+    // NOTE: name is an attribute, but the xml writer uses it as text.
+    // This must be fixed in whole app-installer modules, including wgt.
+    // Current implementation is just for compatibility.
+    bf::path text = context_->root_application_path.get()
+        / context_->pkgid.get() / "shared" / "res" / application_icon.path();
+    icon->text = strdup(text.c_str());
+    icon->name = strdup(application_icon.path().c_str());
+    icon->lang = strdup(DEFAULT_LOCALE);
+    app->icon = g_list_append(app->icon, icon);
+  }
+  return true;
+}
+
+template <typename T>
+bool StepParseManifest::FillLabel(application_x* app, const T& label_list) {
+  if (label_list.empty())
+    return true;
+
+  for (const auto& control : label_list) {
+    label_x* label =
+          static_cast<label_x*>(calloc(1, sizeof(label_x)));
+    // NOTE: name is an attribute, but the xml writer uses it as text.
+    // This must be fixed in whole app-installer modules, including wgt.
+    // Current implementation is just for compatibility.
+    label->text = strdup(control.text().c_str());
+    label->name = strdup(control.name().c_str());
+    label->lang = !control.xml_lang().empty() ?
+        strdup(control.xml_lang().c_str()) : strdup(DEFAULT_LOCALE);
+    app->label = g_list_append(app->label, label);
+  }
+  return true;
+}
+
+template <typename T>
+bool StepParseManifest::FillMetadata(application_x* app,
+                                     const T& meta_data_list) {
+  if (meta_data_list.empty())
+    return true;
+
+  for (auto& meta : meta_data_list) {
+    metadata_x* metadata =
+        static_cast<metadata_x*>(calloc(1, sizeof(metadata_x)));
+    metadata->key = strdup(meta.key().c_str());
+    metadata->value = strdup(meta.val().c_str());
+    app->metadata = g_list_append(app->metadata, metadata);
+  }
+  return true;
+}
+
+bool StepParseManifest::FillImage(application_x* app,
+                          const tpk::parse::ApplicationImagesInfo& image_list) {
+  for (auto& app_image : image_list.images) {
+    image_x* image =
+        static_cast<image_x*>(calloc(1, sizeof(image_x)));
+    image->name = strdup(app_image.name().c_str());
+    const std::string& lang = app_image.lang();
+    if (!lang.empty())
+      image->lang = strdup(lang.c_str());
+    else
+      image->lang = strdup(DEFAULT_LOCALE);
+    if (!app_image.section().empty())
+      image->section = strdup(app_image.section().c_str());
+    app->image = g_list_append(app->image, image);
+  }
+  return true;
+}
+
+bool StepParseManifest::FillAccounts() {
+  std::shared_ptr<const tpk::parse::AccountInfo> account_info =
+      std::static_pointer_cast<const tpk::parse::AccountInfo>(
+        parser_->GetManifestData(app_keys::kAccountKey));
+  if (!account_info)
+    return true;
+
+  AccountInfo info;
+  for (auto& account : account_info->accounts()) {
+    SingleAccountInfo single_info;
+    single_info.capabilities = account.capabilities;
+    single_info.icon_paths = account.icon_paths;
+    single_info.multiple_account_support = account.multiple_account_support;
+    single_info.names = account.labels;
+    // appid has the same value as package
+    single_info.appid =  account.app_id;
+    single_info.providerid = account.provider_id;
+    info.set_account(single_info);
+  }
+  context_->manifest_plugins_data.get().account_info.set(info);
+  return true;
+}
+
+bool StepParseManifest::FillShortcuts() {
+  std::shared_ptr<const tpk::parse::ShortcutListInfo> shortcut_info =
+      std::static_pointer_cast<const tpk::parse::ShortcutListInfo>(
+        parser_->GetManifestData(app_keys::kShortcutListKey));
+  if (!shortcut_info)
+    return true;
+
+  ShortcutListInfo list;
+  for (auto& shortcut : shortcut_info->shortcuts) {
+    ShortcutInfo single_info;
+    single_info.app_id = shortcut.app_id;
+    single_info.extra_data = shortcut.extra_data;
+    single_info.extra_key = shortcut.extra_key;
+    single_info.icon = shortcut.icon;
+    single_info.labels =  shortcut.labels;
+    list.push_back(single_info);
+  }
+  context_->manifest_plugins_data.get().shortcut_info.set(list);
+  return true;
+}
+
+template <typename T>
+bool StepParseManifest::FillBackgroundCategoryInfo(application_x* app,
+    const T& background_category_data_list) {
+  for (const auto& background_category : background_category_data_list) {
+    app->background_category = g_list_append(
+        app->background_category, strdup(background_category.value().c_str()));
+  }
+
+  return true;
+}
+
+bool StepParseManifest::FillManifestX(manifest_x* manifest) {
+  if (!FillPackageInfo(manifest))
+    return false;
+  if (!FillInstallationInfo(manifest))
+    return false;
+  if (!FillUIApplication(manifest))
+    return false;
+  if (!FillServiceApplication(manifest))
+    return false;
+  if (!FillWidgetApplication(manifest))
+    return false;
+  if (!FillPrivileges(manifest))
+    return false;
+  if (!FillAccounts())
+    return false;
+  if (!FillShortcuts())
+    return false;
+  return true;
+}
+
+Step::Status StepParseManifest::process() {
+  if (!LocateConfigFile()) {
+    // continue if this is recovery, manifest file may never been created
+    if (manifest_location_ == ManifestLocation::RECOVERY) {
+      LOG(DEBUG) << "Manifest for recovery not found";
+      return Step::Status::OK;
+    }
+    LOG(ERROR) << "No manifest file exists";
+    return Step::Status::MANIFEST_NOT_FOUND;
+  }
+  parser_.reset(new tpk::parse::TPKConfigParser());
+  if (!parser_->ParseManifest(path_)) {
+    LOG(ERROR) << "[Parse] Parse failed. " <<  parser_->GetErrorMessage();
+    return Step::Status::PARSE_ERROR;
+  }
+
+  // Copy data from ManifestData to InstallerContext
+  std::shared_ptr<const tpk::parse::PackageInfo> info =
+      std::static_pointer_cast<const tpk::parse::PackageInfo>(
+          parser_->GetManifestData(app_keys::kManifestKey));
+
+  context_->pkgid.set(info->package());
+  context_->pkg_path.set(
+      context_->root_application_path.get() / context_->pkgid.get());
+
+  manifest_x* manifest =
+      static_cast<manifest_x*>(calloc(1, sizeof(manifest_x)));
+
+  if (!FillManifestX(const_cast<manifest_x*>(manifest))) {
+    LOG(ERROR) << "[Parse] Storing manifest_x failed. "
+               <<  parser_->GetErrorMessage();
+    return Step::Status::PARSE_ERROR;
+  }
+
+  if (!context_->tep_path.get().empty())
+    manifest->tep_name = context_->tep_path.get().c_str();
+
+  // write pkgid for recovery file
+  if (context_->recovery_info.get().recovery_file) {
+    context_->recovery_info.get().recovery_file->set_pkgid(manifest->package);
+    context_->recovery_info.get().recovery_file->WriteAndCommitFileContent();
+  }
+
+  LOG(DEBUG) << "Parsed package id: " << info->package();
+
+  switch (store_location_) {
+    case StoreLocation::NORMAL:
+      context_->manifest_data.set(manifest);
+      break;
+    case StoreLocation::BACKUP:
+      context_->old_manifest_data.set(manifest);
+      break;
+    default:
+      LOG(ERROR) << "Unknown store location for parsed data";
+      return Step::Status::ERROR;
+  }
+  return Step::Status::OK;
+}
+
+}  // namespace parse
+}  // namespace common_installer
diff --git a/src/common/step/step_parse_manifest.h b/src/common/step/step_parse_manifest.h
new file mode 100644 (file)
index 0000000..749a3a0
--- /dev/null
@@ -0,0 +1,102 @@
+// 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.
+
+#ifndef COMMON_STEP_STEP_PARSE_MANIFEST_H_
+#define COMMON_STEP_STEP_PARSE_MANIFEST_H_
+
+#include <boost/filesystem.hpp>
+
+#include <common/app_installer.h>
+#include <common/installer_context.h>
+#include <common/step/step.h>
+
+#include <manifest_parser/utils/logging.h>
+#include <tpk_manifest_handlers/privileges_handler.h>
+#include <tpk_manifest_handlers/tpk_config_parser.h>
+#include <tpk_manifest_handlers/ui_and_service_application_infos.h>
+
+#include <memory>
+#include <set>
+#include <string>
+
+namespace common_installer {
+namespace parse {
+
+/**
+ * @brief The StepParseManifest class
+ *        Used to parse tpk manifest file and store information to context
+ *
+ * This step is parameterized according to:
+ *  - where to look for manifest file
+ *  - where to store information from manifest in context structure
+ *
+ * Different installation mode will choose different ManifestLocation and
+ * StoreLocation for its purpose but main goal of this step parsing tpk
+ * manifest doesn't change.
+ */
+class StepParseManifest : public common_installer::Step {
+ public:
+  enum class ManifestLocation {
+    PACKAGE,    // parse manifest file from unpacking diretory
+    INSTALLED,  // parse manfiest file from current package installation
+    RECOVERY    // parse manifest file from backup location or package location
+  };
+
+  enum class StoreLocation {
+    NORMAL,  // store in context as current application information (new)
+    BACKUP   // store in context as old version application information (update)
+  };
+
+  explicit StepParseManifest(common_installer::InstallerContext* context,
+      ManifestLocation manifest_location, StoreLocation store_location);
+
+  Status process() override;
+  Status clean() override { return Status::OK; }
+  Status undo() override { return Status::OK; }
+  Status precheck() override;
+
+ protected:
+  bool LocateConfigFile();
+  boost::filesystem::path path_;
+
+ private:
+  bool FillInstallationInfo(manifest_x* manifest);
+  bool FillPackageInfo(manifest_x* manifest);
+  bool FillAuthorInfo(manifest_x* manifest);
+  bool FillDescription(manifest_x* manifest);
+  bool FillPrivileges(manifest_x* manifest);
+  bool FillWidgetApplication(manifest_x* manifest);
+  bool FillServiceApplication(manifest_x* manifest);
+  bool FillUIApplication(manifest_x* manifest);
+  template <typename T>
+      bool FillAppControl(application_x* manifest, const T& app_control_list);
+  template <typename T>
+      bool FillDataControl(application_x* manifest, const T& data_control_list);
+  template <typename T>
+      bool FillApplicationIconPaths(application_x* manifest,
+                                    const T& icons_info);
+  template <typename T>
+      bool FillLabel(application_x* manifest, const T& label_list);
+  template <typename T>
+      bool FillMetadata(application_x* manifest, const T& meta_data_list);
+  bool FillImage(application_x* app,
+                 const tpk::parse::ApplicationImagesInfo& label_list);
+  bool FillAccounts();
+  bool FillShortcuts();
+  template <typename T>
+  bool FillBackgroundCategoryInfo(application_x* app,
+      const T& background_category_data_list);
+  bool FillManifestX(manifest_x* manifest);
+
+  std::unique_ptr<tpk::parse::TPKConfigParser> parser_;
+  ManifestLocation manifest_location_;
+  StoreLocation store_location_;
+
+  SCOPE_LOG_TAG(ParseManifest)
+};
+
+}  // namespace parse
+}  // namespace common_installer
+
+#endif  // COMMON_STEP_STEP_PARSE_MANIFEST_H_