--- /dev/null
+// Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a apache 2.0 license that can be
+// found in the LICENSE file.
+
+#include "lib/tpk_archive_info.h"
+
+#include <package-manager-plugin.h>
+#include <pkgmgr-info.h>
+#include <vconf.h>
+
+#include <boost/filesystem/path.hpp>
+
+#include <tpk_manifest_handlers/tpk_config_parser.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/service_application_handler.h>
+#include <tpk_manifest_handlers/ui_application_handler.h>
+#include <tpk_manifest_handlers/watch_application_handler.h>
+#include <tpk_manifest_handlers/widget_application_handler.h>
+
+#include <common/utils/file_util.h>
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fstream>
+#include <string>
+#include <vector>
+
+namespace bf = boost::filesystem;
+namespace ci = common_installer;
+
+namespace {
+
+const char kVconfLanguageKey[] = "db/menu_widget/language";
+const std::vector<std::string> kEntries = {
+ "shared/res",
+ "tizen-manifest.xml"
+};
+
+bool ExtractPackageArchive(const char* file_path, const bf::path& tmp_dir) {
+ for (auto& entry : kEntries) {
+ if (!ci::ExtractToTmpDir(file_path, tmp_dir, entry)) {
+ LOG(ERROR) << "Failed to extract";
+ return false;
+ }
+ }
+ return true;
+}
+
+bool GetPackageInfo(const tpk::parse::TPKConfigParser& parser,
+ package_manager_pkg_detail_info_t* info) {
+ auto pkg_info =
+ std::static_pointer_cast<const tpk::parse::PackageInfo>(
+ parser.GetManifestData(tpk::parse::PackageInfo::key()));
+ if (!pkg_info)
+ return false;
+
+ snprintf(info->pkg_type, sizeof(info->pkg_type), "tpk");
+ snprintf(info->pkg_name, sizeof(info->pkg_name), "%s",
+ pkg_info->package().c_str());
+ snprintf(info->pkgid, sizeof(info->pkgid), "%s", pkg_info->package().c_str());
+ snprintf(info->version, sizeof(info->version), "%s",
+ pkg_info->version().c_str());
+ snprintf(info->api_version, sizeof(info->api_version), "%s",
+ pkg_info->api_version().c_str());
+
+ return true;
+}
+
+bool GetAuthorInfo(const tpk::parse::TPKConfigParser& parser,
+ package_manager_pkg_detail_info_t* info) {
+ auto author_info =
+ std::static_pointer_cast<const tpk::parse::AuthorInfo>(
+ parser.GetManifestData(tpk::parse::AuthorInfo::Key()));
+ if (!author_info)
+ return false;
+
+ snprintf(info->author, sizeof(info->author), "%s",
+ author_info->name().c_str());
+
+ return true;
+}
+
+bool GetPrivilegesInfo(const tpk::parse::TPKConfigParser& parser,
+ package_manager_pkg_detail_info_t* info) {
+ auto privileges_info =
+ std::static_pointer_cast<const tpk::parse::PrivilegesInfo>(
+ parser.GetManifestData(tpk::parse::PrivilegesInfo::key()));
+ if (!privileges_info)
+ return false;
+
+ const auto& privileges = privileges_info->GetPrivileges();
+ for (auto& priv : privileges) {
+ // TODO: remove duplicates
+ info->privilege_list = g_list_append(info->privilege_list,
+ strdup(priv.first.c_str()));
+ }
+
+ return true;
+}
+
+template <typename T>
+bool GetAppLabel(const tpk::parse::TPKConfigParser& parser,
+ const std::string& key, const char* locale,
+ package_manager_pkg_detail_info_t* info) {
+ auto apps = std::static_pointer_cast<const T>(parser.GetManifestData(key));
+ if (!apps)
+ return false;
+ for (auto& label : apps->items[0].label) {
+ if (label.xml_lang().empty())
+ continue;
+ if (!strcmp(label.xml_lang().c_str(), locale)) {
+ snprintf(info->label, sizeof(info->label), "%s", label.text().c_str());
+ return true;
+ }
+ }
+ for (auto& label : apps->items[0].label) {
+ if (label.xml_lang().empty()) {
+ snprintf(info->label, sizeof(info->label), "%s", label.text().c_str());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GetLabelInfo(const tpk::parse::TPKConfigParser& parser, const char* locale,
+ package_manager_pkg_detail_info_t* info) {
+ auto pkg_info =
+ std::static_pointer_cast<const tpk::parse::PackageInfo>(
+ parser.GetManifestData(tpk::parse::PackageInfo::key()));
+ // label for pkg is in PakageInfo
+ if (!pkg_info) {
+ LOG(ERROR) << "PackageInfo not found";
+ return false;
+ }
+
+ // search current locale first
+ for (auto& label : pkg_info->labels()) {
+ if (label.first.empty())
+ continue;
+ // There is label info in PackageInfo using below format:
+ // using LangTextPair = pair<lang, text>;
+ // Maybe this can be refactored.
+ if (!strcmp(label.first.c_str(), locale)) {
+ snprintf(info->label, sizeof(info->label), "%s", label.second.c_str());
+ return true;
+ }
+ }
+ // search again if cannot find label with current locale
+ for (auto& label : pkg_info->labels()) {
+ if (label.first.empty()) {
+ snprintf(info->label, sizeof(info->label), "%s", label.second.c_str());
+ return true;
+ }
+ }
+
+ // get label from app
+ if (GetAppLabel<tpk::parse::UIApplicationInfoList>(parser,
+ tpk::application_keys::kUIApplicationKey, locale, info))
+ return true;
+ if (GetAppLabel<tpk::parse::ServiceApplicationInfoList>(parser,
+ tpk::application_keys::kServiceApplicationKey, locale, info))
+ return true;
+ if (GetAppLabel<tpk::parse::WidgetApplicationInfoList>(parser,
+ tpk::application_keys::kWidgetApplicationKey, locale, info))
+ return true;
+ if (GetAppLabel<tpk::parse::WatchApplicationInfoList>(parser,
+ tpk::application_keys::kWatchApplicationKey, locale, info))
+ return true;
+
+ return false;
+}
+
+bool GetDescriptionInfo(const tpk::parse::TPKConfigParser& parser,
+ const char* locale, package_manager_pkg_detail_info_t* info) {
+ auto desc_info =
+ std::static_pointer_cast<const tpk::parse::DescriptionInfoList>(
+ parser.GetManifestData(tpk::parse::DescriptionInfoList::Key()));
+ if (!desc_info)
+ return false;
+
+ // search current locale first
+ if (locale) {
+ for (auto& desc : desc_info->descriptions) {
+ if (desc.xml_lang().empty())
+ continue;
+ if (!strcmp(desc.xml_lang().c_str(), locale)) {
+ snprintf(info->pkg_description, sizeof(info->pkg_description), "%s",
+ desc.description().c_str());
+ return true;
+ }
+ }
+ }
+ // search again if cannot find desc with current locale
+ for (auto& desc : desc_info->descriptions) {
+ if (desc.xml_lang().empty()) {
+ snprintf(info->pkg_description, sizeof(info->pkg_description), "%s",
+ desc.description().c_str());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ReadIcon(const bf::path& icon, const bf::path& tmp_dir,
+ package_manager_pkg_detail_info_t* info) {
+ bf::path icon_path;
+ if (icon.is_absolute())
+ icon_path = icon;
+ else
+ icon_path = tmp_dir / "shared/res" / icon;
+
+ LOG(INFO) << "Icon file path: " << icon_path;
+
+ std::ifstream ifs(icon_path.c_str(),
+ std::ifstream::in | std::ifstream::binary);
+ ifs.seekg(0, ifs.end);
+ int len = ifs.tellg();
+ ifs.seekg(0, ifs.beg);
+
+ if (len <= 0)
+ return false;
+
+ char* buf = static_cast<char*>(malloc(sizeof(char) * len));
+
+ LOG(INFO) << "Reading icon file, " << len << " bytes";
+ ifs.read(buf, len);
+
+ info->icon_buf = buf;
+ info->icon_size = len;
+
+ return true;
+}
+
+template <typename T>
+bool GetAppIcon(const tpk::parse::TPKConfigParser& parser,
+ const std::string& key, const char* locale, const bf::path tmp_dir,
+ package_manager_pkg_detail_info_t* info) {
+ auto apps = std::static_pointer_cast<const T>(parser.GetManifestData(key));
+ if (!apps)
+ return false;
+ for (auto& icon : apps->items[0].app_icons.icons()) {
+ if (icon.lang().empty())
+ continue;
+ if (!strcmp(icon.lang().c_str(), locale))
+ return ReadIcon(bf::path(icon.path()), tmp_dir, info);
+ }
+ for (auto& icon : apps->items[0].app_icons.icons()) {
+ if (icon.lang().empty())
+ return ReadIcon(bf::path(icon.path()), tmp_dir, info);
+ }
+ return false;
+}
+
+bool GetIconInfo(const tpk::parse::TPKConfigParser& parser, const char* locale,
+ const bf::path tmp_dir, package_manager_pkg_detail_info_t* info) {
+ // get icon from ui application
+ if (GetAppIcon<tpk::parse::UIApplicationInfoList>(parser,
+ tpk::application_keys::kUIApplicationKey, locale, tmp_dir, info))
+ return true;
+ if (GetAppIcon<tpk::parse::ServiceApplicationInfoList>(parser,
+ tpk::application_keys::kServiceApplicationKey, locale, tmp_dir, info))
+ return true;
+ if (GetAppIcon<tpk::parse::WidgetApplicationInfoList>(parser,
+ tpk::application_keys::kWidgetApplicationKey, locale, tmp_dir, info))
+ return true;
+ if (GetAppIcon<tpk::parse::WatchApplicationInfoList>(parser,
+ tpk::application_keys::kWatchApplicationKey, locale, tmp_dir, info))
+ return true;
+ return false;
+}
+
+} // namespace
+
+bool TpkArchiveInfo::GetArchiveInfo(const char* file_path,
+ package_manager_pkg_detail_info_t* info) {
+ bf::path tmp_dir = ci::GenerateTmpDir("/tmp");
+ if (!ci::CreateDir(tmp_dir))
+ return false;
+ LOG(DEBUG) << "Unpack at temporary dir: " << tmp_dir;
+ if (!ExtractPackageArchive(file_path, tmp_dir))
+ return false;
+
+ tpk::parse::TPKConfigParser parser;
+ bf::path manifest_path = tmp_dir / "tizen-manifest.xml";
+ if (!parser.ParseManifest(manifest_path)) {
+ LOG(ERROR) << "Failed to parse";
+ return false;
+ }
+
+ if (!GetPackageInfo(parser, info)) {
+ LOG(ERROR) << "Failed to get package info";
+ bf::remove_all(tmp_dir);
+ return false;
+ }
+ if (!GetAuthorInfo(parser, info))
+ LOG(WARNING) << "Failed to get author info";
+ if (!GetPrivilegesInfo(parser, info))
+ LOG(WARNING) << "Failed to get privilege info";
+
+ char* locale = vconf_get_str(kVconfLanguageKey);
+ LOG(INFO) << "Current locale: " << locale;
+ if (!GetLabelInfo(parser, locale, info))
+ LOG(WARNING) << "Failed to get label info";
+ if (!GetDescriptionInfo(parser, locale, info))
+ LOG(WARNING) << "Failed to get description info";
+ if (!GetIconInfo(parser, locale, tmp_dir, info))
+ LOG(WARNING) << "Failed to get icon info";
+
+ free(locale);
+ bf::remove_all(tmp_dir);
+
+ return true;
+}