From 629c9b58c8d3a5a234d44256f04bb075f4eed6ae Mon Sep 17 00:00:00 2001 From: Jakub Izydorczyk Date: Wed, 28 Jan 2015 14:23:53 +0100 Subject: [PATCH] [Widget-manifest-parser] Added parser's base Change-Id: Ic7325a08d9ed1359a6e6be77e0d62b3dbe046e7f --- CMakeLists.txt | 1 - packaging/app-installers.spec | 1 - src/utils/CMakeLists.txt | 1 + src/utils/string_util.cc | 158 ++++++++ src/utils/string_util.h | 25 ++ src/wgt/CMakeLists.txt | 2 +- src/wgt/step/step_parse.h | 2 +- src/widget-manifest-parser/CMakeLists.txt | 7 + src/widget-manifest-parser/application_data.cc | 228 +++++++++++ src/widget-manifest-parser/application_data.h | 176 +++++++++ src/widget-manifest-parser/manifest_handler.cc | 216 ++++++++++ src/widget-manifest-parser/manifest_handler.h | 97 +++++ .../manifest_handlers/permissions_handler.cc | 97 +++++ .../manifest_handlers/permissions_handler.h | 53 +++ .../manifest_handlers/tizen_application_handler.cc | 136 +++++++ .../manifest_handlers/tizen_application_handler.h | 71 ++++ .../manifest_handlers/widget_handler.cc | 195 +++++++++ .../manifest_handlers/widget_handler.h | 62 +++ src/widget-manifest-parser/manifest_util.cc | 376 ++++++++++++++++++ src/widget-manifest-parser/manifest_util.h | 29 ++ src/widget-manifest-parser/permission_types.h | 44 +++ .../widget_manifest_parser.cc | 439 +++++++++++++++++++++ .../widget_manifest_parser.h | 40 ++ 23 files changed, 2452 insertions(+), 4 deletions(-) create mode 100644 src/utils/string_util.cc create mode 100644 src/utils/string_util.h create mode 100644 src/widget-manifest-parser/application_data.cc create mode 100644 src/widget-manifest-parser/application_data.h create mode 100644 src/widget-manifest-parser/manifest_handler.cc create mode 100644 src/widget-manifest-parser/manifest_handler.h create mode 100644 src/widget-manifest-parser/manifest_handlers/permissions_handler.cc create mode 100644 src/widget-manifest-parser/manifest_handlers/permissions_handler.h create mode 100644 src/widget-manifest-parser/manifest_handlers/tizen_application_handler.cc create mode 100644 src/widget-manifest-parser/manifest_handlers/tizen_application_handler.h create mode 100644 src/widget-manifest-parser/manifest_handlers/widget_handler.cc create mode 100644 src/widget-manifest-parser/manifest_handlers/widget_handler.h create mode 100644 src/widget-manifest-parser/manifest_util.cc create mode 100644 src/widget-manifest-parser/manifest_util.h create mode 100644 src/widget-manifest-parser/permission_types.h create mode 100644 src/widget-manifest-parser/widget_manifest_parser.cc create mode 100644 src/widget-manifest-parser/widget_manifest_parser.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 24c34a4..5a9d621 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,6 @@ PKG_CHECK_MODULES(OPENSSL_DEPS REQUIRED openssl) PKG_CHECK_MODULES(TZPLATFORM_CONFIG_DEPS REQUIRED libtzplatform-config) PKG_CHECK_MODULES(LIBXML_DEPS REQUIRED libxml-2.0) PKG_CHECK_MODULES(XMLSEC1_DEPS REQUIRED xmlsec1) -PKG_CHECK_MODULES(WIDGET_MANIFEST_PARSER_DEPS REQUIRED widget-manifest-parser) PKG_CHECK_MODULES(SECURITY_MANAGER_DEPS REQUIRED security-manager) PKG_CHECK_MODULES(VCONF_DEPS REQUIRED vconf) diff --git a/packaging/app-installers.spec b/packaging/app-installers.spec index fbd4746..25f1741 100644 --- a/packaging/app-installers.spec +++ b/packaging/app-installers.spec @@ -22,7 +22,6 @@ BuildRequires: pkgconfig(minizip) BuildRequires: pkgconfig(libzip) BuildRequires: pkgconfig(libtzplatform-config) BuildRequires: pkgconfig(xmlsec1) -BuildRequires: pkgconfig(widget-manifest-parser) BuildRequires: pkgconfig(vconf) Requires: ca-certificates-tizen diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index b0814d9..eb52ff5 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -2,6 +2,7 @@ SET(SRCS system_locale.cc utf_converter.cc + string_util.cc values.cc ) # Target - definition diff --git a/src/utils/string_util.cc b/src/utils/string_util.cc new file mode 100644 index 0000000..bd6fbd8 --- /dev/null +++ b/src/utils/string_util.cc @@ -0,0 +1,158 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#include "utils/string_util.h" + +#include + +namespace common_installer { +namespace utils { + +#define WHITESPACE_UNICODE \ + 0x0009, /* CHARACTER TABULATION */ \ + 0x000A, /* LINE FEED (LF) */ \ + 0x000B, /* LINE TABULATION */ \ + 0x000C, /* FORM FEED (FF) */ \ + 0x000D, /* CARRIAGE RETURN (CR) */ \ + 0x0020, /* SPACE */ \ + 0x0085, /* NEXT LINE (NEL) */ \ + 0x00A0, /* NO-BREAK SPACE */ \ + 0x1680, /* OGHAM SPACE MARK */ \ + 0x2000, /* EN QUAD */ \ + 0x2001, /* EM QUAD */ \ + 0x2002, /* EN SPACE */ \ + 0x2003, /* EM SPACE */ \ + 0x2004, /* THREE-PER-EM SPACE */ \ + 0x2005, /* FOUR-PER-EM SPACE */ \ + 0x2006, /* SIX-PER-EM SPACE */ \ + 0x2007, /* FIGURE SPACE */ \ + 0x2008, /* PUNCTUATION SPACE */ \ + 0x2009, /* THIN SPACE */ \ + 0x200A, /* HAIR SPACE */ \ + 0x2028, /* LINE SEPARATOR */ \ + 0x2029, /* PARAGRAPH SEPARATOR */ \ + 0x202F, /* NARROW NO-BREAK SPACE */ \ + 0x205F, /* MEDIUM MATHEMATICAL SPACE */ \ + 0x3000, /* IDEOGRAPHIC SPACE */ \ + 0 + +const char16_t kRightToLeftMark = 0x200F; +const char16_t kLeftToRightMark = 0x200E; +const char16_t kLeftToRightEmbeddingMark = 0x202A; +const char16_t kRightToLeftEmbeddingMark = 0x202B; +const char16_t kPopDirectionalFormatting = 0x202C; +const char16_t kLeftToRightOverride = 0x202D; +const char16_t kRightToLeftOverride = 0x202E; + +const char kDirLTRKey[] = "ltr"; +const char kDirRTLKey[] = "rtl"; +const char kDirLROKey[] = "lro"; +const char kDirRLOKey[] = "rlo"; + +namespace { +const wchar_t kWhitespaceWide[] = { + WHITESPACE_UNICODE +}; + +// Returns true if it's a whitespace character. +inline bool IsWhitespace(wchar_t c) { + return wcschr(kWhitespaceWide, c) != nullptr; +} + +template +STR CollapseWhitespaceT(const STR& text, + bool trim_sequences_with_line_breaks) { + STR result; + result.resize(text.size()); + + // Set flags to pretend we're already in a trimmed whitespace sequence, so we + // will trim any leading whitespace. + bool in_whitespace = true; + bool already_trimmed = true; + + int chars_written = 0; + for (typename STR::const_iterator i(text.begin()); i != text.end(); ++i) { + if (IsWhitespace(*i)) { + if (!in_whitespace) { + // Reduce all whitespace sequences to a single space. + in_whitespace = true; + result[chars_written++] = L' '; + } + if (trim_sequences_with_line_breaks && !already_trimmed && + ((*i == '\n') || (*i == '\r'))) { + // Whitespace sequences containing CR or LF are eliminated entirely. + already_trimmed = true; + --chars_written; + } + } else { + // Non-whitespace chracters are copied straight across. + in_whitespace = false; + already_trimmed = false; + result[chars_written++] = *i; + } + } + + if (in_whitespace && !already_trimmed) { + // Any trailing whitespace is eliminated. + --chars_written; + } + + result.resize(chars_written); + return result; +} +} // namespace + +std::string CollapseWhitespace(const std::string& text, + bool trim_sequences_with_line_breaks) { + return CollapseWhitespaceT(text, trim_sequences_with_line_breaks); +} + +std::u16string CollapseWhitespace(const std::u16string& text, + bool trim_sequences_with_line_breaks) { + return CollapseWhitespaceT(text, trim_sequences_with_line_breaks); +} + +std::u16string StripWrappingBidiControlCharacters(const std::u16string& text) { + if (text.empty()) + return text; + size_t begin_index = 0; + char16_t begin = text[begin_index]; + if (begin == kLeftToRightEmbeddingMark || + begin == kRightToLeftEmbeddingMark || + begin == kLeftToRightOverride || + begin == kRightToLeftOverride) + ++begin_index; + size_t end_index = text.length() - 1; + if (text[end_index] == kPopDirectionalFormatting) + --end_index; + return text.substr(begin_index, end_index - begin_index + 1); +} + +std::u16string GetDirText(const std::u16string& text, const std::string& dir) { + if (dir == kDirLTRKey) + return kLeftToRightEmbeddingMark + + text + + kPopDirectionalFormatting; + + if (dir == kDirRTLKey) + return kRightToLeftEmbeddingMark + + text + + kPopDirectionalFormatting; + + if (dir == kDirLROKey) + return kLeftToRightOverride + + text + + kPopDirectionalFormatting; + + if (dir == kDirRLOKey) + return kRightToLeftOverride + + text + + kPopDirectionalFormatting; + + return text; +} + +} // namespace utils +} // namespace common_installer diff --git a/src/utils/string_util.h b/src/utils/string_util.h new file mode 100644 index 0000000..ebc0c4b --- /dev/null +++ b/src/utils/string_util.h @@ -0,0 +1,25 @@ +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#ifndef UTILS_STRING_UTIL_H_ +#define UTILS_STRING_UTIL_H_ + +#include + +namespace common_installer { +namespace utils { + +std::string CollapseWhitespace(const std::string& text, + bool trim_sequences_with_line_breaks); +std::u16string CollapseWhitespace(const std::u16string& text, + bool trim_sequences_with_line_breaks); +std::u16string StripWrappingBidiControlCharacters(const std::u16string& text); +std::u16string GetDirText(const std::u16string& text, const std::string& dir); +void WrapStringWithLTRFormatting(std::u16string* text); +bool AdjustStringForLocaleDirection(std::u16string* text); +} // namespace utils +} // namespace common_installer + +#endif // UTILS_STRING_UTIL_H_ diff --git a/src/wgt/CMakeLists.txt b/src/wgt/CMakeLists.txt index 31a8ab0..0a40355 100644 --- a/src/wgt/CMakeLists.txt +++ b/src/wgt/CMakeLists.txt @@ -19,11 +19,11 @@ TARGET_INCLUDE_DIRECTORIES(${TARGET_WGT_BACKEND} PUBLIC "${CMAKE_CURRENT_SOURCE_ # Target - deps APPLY_PKG_CONFIG(${TARGET_WGT_BACKEND} PUBLIC PKGMGR_INSTALLER_DEPS - WIDGET_MANIFEST_PARSER_DEPS ) # Target - in-package deps TARGET_LINK_LIBRARIES(${TARGET_WGT_BACKEND} PUBLIC ${TARGET_LIBNAME_COMMON}) +TARGET_LINK_LIBRARIES(${TARGET_WGT_BACKEND} PUBLIC ${TARGET_LIBNAME_WIDGET_MANIFEST_PARSER}) # Install INSTALL(TARGETS ${TARGET_WGT_BACKEND} DESTINATION ${BINDIR}) diff --git a/src/wgt/step/step_parse.h b/src/wgt/step/step_parse.h index 8331657..2a9227c 100644 --- a/src/wgt/step/step_parse.h +++ b/src/wgt/step/step_parse.h @@ -5,7 +5,7 @@ #include -#include +#include #include "common/app_installer.h" #include "common/context_installer.h" diff --git a/src/widget-manifest-parser/CMakeLists.txt b/src/widget-manifest-parser/CMakeLists.txt index 659a4dd..33bd14e 100644 --- a/src/widget-manifest-parser/CMakeLists.txt +++ b/src/widget-manifest-parser/CMakeLists.txt @@ -1,7 +1,14 @@ # Target - sources SET(SRCS + application_data.cc application_manifest_constants.cc manifest.cc + manifest_handler.cc + manifest_handlers/permissions_handler.cc + manifest_handlers/tizen_application_handler.cc + manifest_handlers/widget_handler.cc + manifest_util.cc + widget_manifest_parser.cc ) # Target - definition ADD_LIBRARY(${TARGET_LIBNAME_WIDGET_MANIFEST_PARSER} SHARED ${SRCS}) diff --git a/src/widget-manifest-parser/application_data.cc b/src/widget-manifest-parser/application_data.cc new file mode 100644 index 0000000..dae0de3 --- /dev/null +++ b/src/widget-manifest-parser/application_data.cc @@ -0,0 +1,228 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#include "widget-manifest-parser/application_data.h" + +#include +#include +#include + +#include "utils/logging.h" +#include "utils/utf_converter.h" +#include "widget-manifest-parser/application_manifest_constants.h" +#include "widget-manifest-parser/manifest.h" +#include "widget-manifest-parser/manifest_handler.h" +#include "widget-manifest-parser/manifest_handlers/permissions_handler.h" +#include "widget-manifest-parser/manifest_handlers/widget_handler.h" +#include "widget-manifest-parser/manifest_handlers/tizen_application_handler.h" + +namespace keys = common_installer::application_manifest_keys; +namespace widget_keys = common_installer::application_widget_keys; +namespace errors = common_installer::application_manifest_errors; + +namespace { +const char kApplicationScheme[] = "app"; +const char kWGTAppIdPattern[] = "\\A([0-9a-zA-Z]{10})[.][0-9a-zA-Z]{1,52}\\z"; +const std::string kAppIdPrefix("xwalk."); + +const size_t kIdSize = 16; + +bool IsValidWGTID(const std::string& id) { + std::regex regex(kWGTAppIdPattern); + return std::regex_match (id, regex); +} + +std::string AppIdToPkgId(const std::string& id) { + std::string package_id; + if (!IsValidWGTID(id)) { + LOG(WARNING) << "Cannot get package_id from invalid app id"; + return std::string(); + } + return package_id; +} + +} // namespace + +namespace common_installer { +namespace widget_manifest_parser { + +// static +std::shared_ptr ApplicationData::Create( + const bf::path& path, const std::string& explicit_id, + SourceType source_type, std::unique_ptr manifest, + std::string* error_message) { + assert(error_message); + std::u16string error; + if (!manifest->ValidateManifest(error_message)) + return nullptr; + + std::shared_ptr app_data( + new ApplicationData(path, source_type, std::move(manifest))); + if (!app_data->Init(explicit_id, &error)) { + *error_message = utils::utf_converter::UTF16ToUTF8(error); + return nullptr; + } + + ManifestHandlerRegistry* registry = + ManifestHandlerRegistry::GetInstance(app_data->manifest_type()); + + if (!registry->ValidateAppManifest(app_data, error_message)) + return nullptr; + return app_data; +} + +// static +std::string ApplicationData::GetBaseURLFromApplicationId( + const std::string& application_id) { + return (std::string(kApplicationScheme) + + "://" + application_id + "/"); +} + +ApplicationData::ManifestData* ApplicationData::GetManifestData( + const std::string& key) const { + assert(finished_parsing_manifest_); + ManifestDataMap::const_iterator iter = manifest_data_.find(key); + if (iter != manifest_data_.end()) + return iter->second.get(); + return nullptr; +} + +void ApplicationData::SetManifestData(const std::string& key, + std::shared_ptr data) { + assert(!finished_parsing_manifest_); + manifest_data_[key] = data; +} + +std::string ApplicationData::GetPackageID() const { + return AppIdToPkgId(application_id_); +} + +const std::string ApplicationData::VersionString() const { + if (!version_.empty()) + return Version(); + return ""; +} + +bool ApplicationData::IsHostedApp() const { + bool hosted = source_type_ == EXTERNAL_URL; + if (manifest_->HasPath(widget_keys::kContentNamespace)) { + std::string ns; + if (manifest_->GetString(widget_keys::kContentNamespace, &ns) && + ns == widget_keys::kTizenNamespacePrefix) + hosted = true; + } + return hosted; +} + +ApplicationData::ApplicationData(const bf::path& path, + SourceType source_type, std::unique_ptr manifest) + : manifest_version_(0), + path_(path), + manifest_(std::move(manifest)), + finished_parsing_manifest_(false), + source_type_(source_type) { + assert(path_.empty() || path_.is_absolute()); +} + +ApplicationData::~ApplicationData() { +} + +bool ApplicationData::Init(const std::string& explicit_id, + std::u16string* error) { + assert(error); + ManifestHandlerRegistry* registry = + ManifestHandlerRegistry::GetInstance(manifest_type()); + if (!registry->ParseAppManifest(shared_from_this(), error)) + return false; + + if (!LoadID(explicit_id, error)) + return false; + if (!LoadName(error)) + return false; + if (!LoadVersion(error)) + return false; + + application_url_ = ApplicationData::GetBaseURLFromApplicationId(ID()); + finished_parsing_manifest_ = true; + return true; +} + +bool ApplicationData::LoadID(const std::string& explicit_id, + std::u16string* error) { + std::string application_id; + auto iter = manifest_data_.find(widget_keys::kTizenApplicationKey); + if (iter == manifest_data_.end()) + return false; + const TizenApplicationInfo* tizen_app_info = + static_cast(iter->second.get()); + assert(tizen_app_info); + application_id = tizen_app_info->id(); + if (!application_id.empty()) { + application_id_ = application_id; + return true; + } + if (!explicit_id.empty()) { + application_id_ = explicit_id; + return true; + } + return false; +} + +bool ApplicationData::LoadName(std::u16string* error) { + assert(error); + std::u16string localized_name; + std::string name_key(GetNameKey(manifest_type())); + + if (!manifest_->GetString(name_key, &localized_name) && + manifest_type() == Manifest::TYPE_MANIFEST) { + *error = errors::kInvalidName; + return false; + } + non_localized_name_ = common_installer::utils::utf_converter::UTF16ToUTF8( + localized_name); + + // TODO(jizydorczyk): This needs to be implemented + // utils::AdjustStringForLocaleDirection(&localized_name); + name_ = common_installer::utils::utf_converter::UTF16ToUTF8(localized_name); + return true; +} + +bool ApplicationData::LoadVersion(std::u16string* error) { + assert(error); + std::string version_str; + + version_ = ""; + + bool ok = manifest_->GetString(widget_keys::kVersionKey, &version_str); + if (!ok) { + *error = errors::kInvalidVersion; + return true; + } + + version_ = std::string(version_str); + return true; +} + +bool ApplicationData::SetApplicationLocale(const std::string& locale, + std::u16string* error) { + manifest_->SetSystemLocale(locale); + if (!LoadName(error)) + return false; + + if (WidgetInfo* widget_info = static_cast( + GetManifestData(widget_keys::kWidgetKey))) { + std::string string_value; + if (manifest_->GetString(widget_keys::kNameKey, &string_value)) + widget_info->SetName(string_value); + if (manifest_->GetString(widget_keys::kShortNameKey, &string_value)) + widget_info->SetShortName(string_value); + if (manifest_->GetString(widget_keys::kDescriptionKey, &string_value)) + widget_info->SetDescription(string_value); + } + return true; +} + +} // namespace widget_manifest_parser +} // namespace common_installer diff --git a/src/widget-manifest-parser/application_data.h b/src/widget-manifest-parser/application_data.h new file mode 100644 index 0000000..cff8b29 --- /dev/null +++ b/src/widget-manifest-parser/application_data.h @@ -0,0 +1,176 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#ifndef WIDGET_MANIFEST_PARSER_APPLICATION_DATA_H_ +#define WIDGET_MANIFEST_PARSER_APPLICATION_DATA_H_ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils/values.h" +#include "widget-manifest-parser/manifest.h" +#include "widget-manifest-parser/permission_types.h" +// TODO(jizydorczyk) Conver package from xwalk for our needs +// #include "widget-manifest-parser/package/package.h" + +namespace bf = boost::filesystem; + +namespace common_installer { +namespace widget_manifest_parser { + +// TODO(t.iwanek): there should be private inheritence +// FIX ME! +class ApplicationData : public std::enable_shared_from_this { + public: + // Where an application was loaded from. + enum SourceType { + INTERNAL, // From internal application registry. + LOCAL_DIRECTORY, // From a persistently stored unpacked application + TEMP_DIRECTORY, // From a temporary folder + EXTERNAL_URL // From an arbitrary URL + }; + + struct ManifestData; + + struct ApplicationIdCompare { + bool operator()(const std::string& s1, const std::string& s2) const { + return strcasecmp(s1.c_str(), s2.c_str()) < 0; + } + }; + + typedef std::map > + ManifestDataMap; + typedef std::map, ApplicationIdCompare> + ApplicationDataMap; + typedef ApplicationDataMap::iterator ApplicationDataMapIterator; + + // A base class for parsed manifest data that APIs want to store on + // the application. Related to base::SupportsUserData, but with an immutable + // thread-safe interface to match Application. + struct ManifestData { + virtual ~ManifestData() {} + }; + + static std::shared_ptr Create(const bf::path& app_path, + const std::string& explicit_id, SourceType source_type, + std::unique_ptr manifest, std::string* error_message); + + // Returns the base application url for a given |application_id|. + static std::string GetBaseURLFromApplicationId( + const std::string& application_id); + + // Get the manifest data associated with the key, or NULL if there is none. + // Can only be called after InitValue is finished. + ManifestData* GetManifestData(const std::string& key) const; + + // Sets |data| to be associated with the key. Takes ownership of |data|. + // Can only be called before InitValue is finished. Not thread-safe; + // all SetManifestData calls should be on only one thread. + void SetManifestData(const std::string& key, + std::shared_ptr data); + + // Accessors: + const bf::path& path() const { return path_; } + const std::string& URL() const { return application_url_; } + SourceType source_type() const { return source_type_; } + Manifest::Type manifest_type() const { return manifest_->type(); } + const std::string& ID() const { return application_id_; } + std::string GetPackageID() const; + const std::string Version() const { return version_; } + const std::string VersionString() const; + const std::string& Name() const { return name_; } + const std::string& NonLocalizedName() const { return non_localized_name_; } + const std::string& Description() const { return description_; } + + const Manifest* GetManifest() const { + return manifest_.get(); + } + + // App-related. + bool IsHostedApp() const; + + bool SetApplicationLocale(const std::string& locale, std::u16string* error); + + virtual ~ApplicationData(); + + private: + ApplicationData(const bf::path& path, + SourceType source_type, std::unique_ptr manifest); + + // Initialize the application from a parsed manifest. + bool Init(const std::string& explicit_id, std::u16string* error); + + // Chooses the application ID for an application based on a variety of + // criteria. The chosen ID will be set in |manifest|. + bool LoadID(const std::string& explicit_id, std::u16string* error); + // The following are helpers for InitFromValue to load various features of the + // application from the manifest. + bool LoadName(std::u16string* error); + bool LoadVersion(std::u16string* error); + + // The application's human-readable name. Name is used for display purpose. It + // might be wrapped with unicode bidi control characters so that it is + // displayed correctly in RTL context. + // NOTE: Name is UTF-8 and may contain non-ascii characters. + std::string name_; + + // A non-localized version of the application's name. This is useful for + // debug output. + std::string non_localized_name_; + + // The version of this application's manifest. We increase the manifest + // version when making breaking changes to the application system. + // Version 1 was the first manifest version (implied by a lack of a + // manifest_version attribute in the application's manifest). We initialize + // this member variable to 0 to distinguish the "uninitialized" case from + // the case when we know the manifest version actually is 1. + int manifest_version_; + + // The absolute path to the directory the application is stored in. + bf::path path_; + + // A persistent, globally unique ID. An application's ID is used in things + // like directory structures and URLs, and is expected to not change across + // versions. + std::string application_id_; + + // The base application url for the application. + std::string application_url_; + + // The application's version. + std::string version_; + + // An optional longer description of the application. + std::string description_; + + // The manifest from which this application was created. + std::unique_ptr manifest_; + + // Stored parsed manifest data. + ManifestDataMap manifest_data_; + + // Set to true at the end of InitValue when initialization is finished. + bool finished_parsing_manifest_; + + // The source the application was loaded from. + SourceType source_type_; + +// DISALLOW_COPY_AND_ASSIGN(ApplicationData); +}; + +} // namespace widget_manifest_parser +} // namespace common_installer + +#endif // WIDGET_MANIFEST_PARSER_APPLICATION_DATA_H_ diff --git a/src/widget-manifest-parser/manifest_handler.cc b/src/widget-manifest-parser/manifest_handler.cc new file mode 100644 index 0000000..124dad1 --- /dev/null +++ b/src/widget-manifest-parser/manifest_handler.cc @@ -0,0 +1,216 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#include "widget-manifest-parser/manifest_handler.h" + +#include +#include + +#include "widget-manifest-parser/application_manifest_constants.h" + +#include "widget-manifest-parser/manifest_handlers/permissions_handler.h" +#include "widget-manifest-parser/manifest_handlers/tizen_application_handler.h" +#include "widget-manifest-parser/manifest_handlers/widget_handler.h" + +// TODO(t.iwanek): add following handlers +// #include "widget-manifest-parser/manifest_handlers/tizen_appwidget_handler.h" +// #include "widget-manifest-parser/manifest_handlers/tizen_category_handler.h" +// #include "widget-manifest-parser/manifest_handlers/tizen_ime_handler.h" +// #include "widget-manifest-parser/manifest_handlers/tizen_metadata_handler.h" +// #include "widget-manifest-parser/manifest_handlers/tizen_navigation_handler.h" +// #include "widget-manifest-parser/manifest_handlers/tizen_setting_handler.h" +// #include "widget-manifest-parser/manifest_handlers/tizen_splash_screen_handler.h" + +namespace common_installer { +namespace widget_manifest_parser { + +namespace { + +bool ValidateImeCategory( + const common_installer::widget_manifest_parser::ApplicationData& + application, + std::string* error) { + namespace keys = common_installer::application_widget_keys; + // if config contains tizen:ime tag, proper category should be specified + + // TODO(t.iwanek): fix me - add IME handler and uncomment + +// if (application.GetManifestData(keys::kTizenImeKey)) { +// const common_installer::widget_manifest_parser::CategoryInfoList* +// categories_list = +// static_cast( +// application.GetManifestData(keys::kTizenCategoryKey)); + +// if (categories_list) { +// const char imeCategory[] = "http://tizen.org/category/ime"; +// for (const std::string& category : categories_list->categories) { +// if (category == imeCategory) +// return true; +// } +// } +// *error = "tizen:ime is specified but not proper category added"; +// return false; +// } + return true; +} + +} // namespace + +ManifestHandler::~ManifestHandler() { +} + +bool ManifestHandler::Validate( + std::shared_ptr application, + std::string* error) const { + return true; +} + +bool ManifestHandler::AlwaysParseForType(Manifest::Type type) const { + return false; +} + +bool ManifestHandler::AlwaysValidateForType(Manifest::Type type) const { + return false; +} + +std::vector ManifestHandler::PrerequisiteKeys() const { + return std::vector(); +} + +ManifestHandlerRegistry* ManifestHandlerRegistry::widget_registry_ = NULL; + +ManifestHandlerRegistry::ManifestHandlerRegistry( + const std::vector& handlers) { + for (std::vector::const_iterator it = handlers.begin(); + it != handlers.end(); ++it) { + Register(*it); + } + + ReorderHandlersGivenDependencies(); +} + +ManifestHandlerRegistry::~ManifestHandlerRegistry() { +} + +ManifestHandlerRegistry* +ManifestHandlerRegistry::GetInstance(Manifest::Type type) { + return GetInstanceForWGT(); +} + +ManifestHandlerRegistry* +ManifestHandlerRegistry::GetInstanceForWGT() { + if (widget_registry_) + return widget_registry_; + + std::vector handlers; + // We can put WGT specific manifest handlers here. + handlers.push_back(new WidgetHandler); + handlers.push_back(new TizenApplicationHandler); + handlers.push_back(new PermissionsHandler); + + widget_registry_ = new ManifestHandlerRegistry(handlers); + return widget_registry_; +} + +void ManifestHandlerRegistry::Register(ManifestHandler* handler) { + const std::vector& keys = handler->Keys(); + for (size_t i = 0; i < keys.size(); ++i) { + handlers_[keys[i]] = handler; + } +} + +bool ManifestHandlerRegistry::ParseAppManifest( + std::shared_ptr application, std::u16string* error) { + std::map handlers_by_order; + for (ManifestHandlerMap::iterator iter = handlers_.begin(); + iter != handlers_.end(); ++iter) { + ManifestHandler* handler = iter->second; + if (application->GetManifest()->HasPath(iter->first) || + handler->AlwaysParseForType(application->manifest_type())) { + handlers_by_order[order_map_[handler]] = handler; + } + } + for (std::map::iterator iter = + handlers_by_order.begin(); + iter != handlers_by_order.end(); ++iter) { + if (!(iter->second)->Parse(application, error)) { + return false; + } + } + return true; +} + +bool ManifestHandlerRegistry::ValidateAppManifest( + std::shared_ptr application, + std::string* error) { + for (ManifestHandlerMap::iterator iter = handlers_.begin(); + iter != handlers_.end(); ++iter) { + ManifestHandler* handler = iter->second; + if ((application->GetManifest()->HasPath(iter->first) || + handler->AlwaysValidateForType(application->manifest_type())) && + !handler->Validate(application, error)) + return false; + } + + if (!ValidateImeCategory(*application, error)) + return false; + + return true; +} + +// static +void ManifestHandlerRegistry::SetInstanceForTesting( + ManifestHandlerRegistry* registry, Manifest::Type type) { + widget_registry_ = registry; + return; +} + +void ManifestHandlerRegistry::ReorderHandlersGivenDependencies() { + std::set unsorted_handlers; + for (ManifestHandlerMap::const_iterator iter = handlers_.begin(); + iter != handlers_.end(); ++iter) { + unsorted_handlers.insert(iter->second); + } + + int order = 0; + while (true) { + std::set next_unsorted_handlers; + for (std::set::const_iterator iter = + unsorted_handlers.begin(); + iter != unsorted_handlers.end(); ++iter) { + ManifestHandler* handler = *iter; + const std::vector& prerequisites = + handler->PrerequisiteKeys(); + int unsatisfied = prerequisites.size(); + for (size_t i = 0; i < prerequisites.size(); ++i) { + ManifestHandlerMap::const_iterator prereq_iter = + handlers_.find(prerequisites[i]); + assert(prereq_iter != handlers_.end() && + "Application manifest handler depends on unrecognized key "); + // Prerequisite is in our map. + if (order_map_.find(prereq_iter->second) != order_map_.end()) + unsatisfied--; + } + if (unsatisfied == 0) { + order_map_[handler] = order; + order++; + } else { + // Put in the list for next time. + next_unsorted_handlers.insert(handler); + } + } + if (next_unsorted_handlers.size() == unsorted_handlers.size()) + break; + unsorted_handlers.swap(next_unsorted_handlers); + } + + // If there are any leftover unsorted handlers, they must have had + // circular dependencies. + assert(unsorted_handlers.empty() && + "Application manifest handlers have circular dependencies!"); +} + +} // namespace widget_manifest_parser +} // namespace common_installer diff --git a/src/widget-manifest-parser/manifest_handler.h b/src/widget-manifest-parser/manifest_handler.h new file mode 100644 index 0000000..556eeb2 --- /dev/null +++ b/src/widget-manifest-parser/manifest_handler.h @@ -0,0 +1,97 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#ifndef WIDGET_MANIFEST_PARSER_MANIFEST_HANDLER_H_ +#define WIDGET_MANIFEST_PARSER_MANIFEST_HANDLER_H_ + +#include +#include +#include +#include + +#include "widget-manifest-parser/manifest.h" +#include "widget-manifest-parser/application_data.h" + +namespace common_installer { +namespace widget_manifest_parser { + +class ManifestHandler { + public: + virtual ~ManifestHandler(); + + // Returns false in case of failure and sets writes error message + // in |error| if present. + virtual bool Parse(std::shared_ptr application, + std::u16string* error) = 0; + + // Returns false in case of failure and sets writes error message + // in |error| if present. + virtual bool Validate(std::shared_ptr application, + std::string* error) const; + + // If false (the default), only parse the manifest if a registered + // key is present in the manifest. If true, always attempt to parse + // the manifest for this application type, even if no registered keys + // are present. This allows specifying a default parsed value for + // application that don't declare our key in the manifest. + virtual bool AlwaysParseForType(Manifest::Type type) const; + + // Same as AlwaysParseForType, but for Validate instead of Parse. + virtual bool AlwaysValidateForType(Manifest::Type type) const; + + // The list of keys that, if present, should be parsed before calling our + // Parse (typically, because our Parse needs to read those keys). + // Defaults to empty. + virtual std::vector PrerequisiteKeys() const; + + // The keys to register handler for (in Register). + virtual std::vector Keys() const = 0; +}; + +class ManifestHandlerRegistry final { + public: + ~ManifestHandlerRegistry(); + + static ManifestHandlerRegistry* GetInstance(Manifest::Type type); + + bool ParseAppManifest( + std::shared_ptr application, std::u16string* error); + bool ValidateAppManifest(std::shared_ptr application, + std::string* error); + + private: + friend class ScopedTestingManifestHandlerRegistry; + explicit ManifestHandlerRegistry( + const std::vector& handlers); + + // Register a manifest handler for keys, which are provided by Keys() method + // in ManifestHandler implementer. + void Register(ManifestHandler* handler); + + void ReorderHandlersGivenDependencies(); + + // Sets a new global registry, for testing purposes. + static void SetInstanceForTesting(ManifestHandlerRegistry* registry, + Manifest::Type type); + + static ManifestHandlerRegistry* GetInstanceForWGT(); + static ManifestHandlerRegistry* GetInstanceForXPK(); + + typedef std::map ManifestHandlerMap; + typedef std::map ManifestHandlerOrderMap; + + ManifestHandlerMap handlers_; + + // Handlers are executed in order; lowest order first. + ManifestHandlerOrderMap order_map_; + + static ManifestHandlerRegistry* xpk_registry_; + static ManifestHandlerRegistry* widget_registry_; +}; + +} // namespace widget_manifest_parser +} // namespace common_installer + +#endif // WIDGET_MANIFEST_PARSER_MANIFEST_HANDLER_H_ diff --git a/src/widget-manifest-parser/manifest_handlers/permissions_handler.cc b/src/widget-manifest-parser/manifest_handlers/permissions_handler.cc new file mode 100644 index 0000000..38578fc --- /dev/null +++ b/src/widget-manifest-parser/manifest_handlers/permissions_handler.cc @@ -0,0 +1,97 @@ +// Copyright (c) 2014 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#include "widget-manifest-parser/manifest_handlers/permissions_handler.h" + +#include + +#include "utils/logging.h" +#include "utils/values.h" +#include "widget-manifest-parser/application_manifest_constants.h" + +namespace common_installer { + +namespace keys = application_widget_keys; + +namespace widget_manifest_parser { + +PermissionsInfo::PermissionsInfo() { +} + +PermissionsInfo::~PermissionsInfo() { +} + +PermissionsHandler::PermissionsHandler() { +} + +PermissionsHandler::~PermissionsHandler() { +} + +bool PermissionsHandler::Parse( + std::shared_ptr application, std::u16string* error) { + std::shared_ptr permissions_info(new PermissionsInfo); + if (!application->GetManifest()->HasPath(keys::kTizenPermissionsKey)) { + application->SetManifestData( + keys::kTizenPermissionsKey, permissions_info); + return true; + } + + utils::Value* value; + if (!application->GetManifest()->Get(keys::kTizenPermissionsKey, &value)) { + *error = u"Invalid value of tizen permissions."; + return false; + } + + std::unique_ptr permission_list; + if (value->IsType(utils::Value::TYPE_DICTIONARY)) { + permission_list.reset(new utils::ListValue); + permission_list->Append(value->DeepCopy()); + } else { + utils::ListValue* list = nullptr; + value->GetAsList(&list); + if (list) + permission_list.reset(list->DeepCopy()); + } + + if (!permission_list) { + *error = u"Invalid value of permissions."; + return false; + } + PermissionSet api_permissions; + for (utils::ListValue::const_iterator it = permission_list->begin(); + it != permission_list->end(); ++it) { + utils::DictionaryValue* dictionary_value = nullptr; + (*it)->GetAsDictionary(&dictionary_value); + + std::string permission; + if (!dictionary_value || + !dictionary_value->GetString( + keys::kTizenPermissionsNameKey, &permission) || + permission.empty()) + continue; + + if (api_permissions.find(permission) != api_permissions.end()) + LOG(WARNING) << "Duplicated permission names found."; + + api_permissions.insert(permission); + } + + permissions_info->SetAPIPermissions(api_permissions); + application->SetManifestData(keys::kTizenPermissionsKey, + permissions_info); + + return true; +} + +bool PermissionsHandler::AlwaysParseForType(Manifest::Type type) const { + return type == Manifest::TYPE_WIDGET; +} + +std::vector PermissionsHandler::Keys() const { + return std::vector(1, keys::kTizenPermissionsKey); +} + +} // namespace widget_manifest_parser +} // namespace common_installer diff --git a/src/widget-manifest-parser/manifest_handlers/permissions_handler.h b/src/widget-manifest-parser/manifest_handlers/permissions_handler.h new file mode 100644 index 0000000..c00c491 --- /dev/null +++ b/src/widget-manifest-parser/manifest_handlers/permissions_handler.h @@ -0,0 +1,53 @@ +// Copyright (c) 2014 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#ifndef WIDGET_MANIFEST_PARSER_MANIFEST_HANDLERS_PERMISSIONS_HANDLER_H_ +#define WIDGET_MANIFEST_PARSER_MANIFEST_HANDLERS_PERMISSIONS_HANDLER_H_ + +#include +#include + +#include "utils/macros.h" + +#include "widget-manifest-parser/manifest_handler.h" +#include "widget-manifest-parser/permission_types.h" + +namespace common_installer { +namespace widget_manifest_parser { + +class PermissionsInfo: public ApplicationData::ManifestData { + public: + PermissionsInfo(); + virtual ~PermissionsInfo(); + + const PermissionSet& GetAPIPermissions() const { + return api_permissions_;} + void SetAPIPermissions(const PermissionSet& api_permissions) { + api_permissions_ = api_permissions; + } + + private: + PermissionSet api_permissions_; + DISALLOW_COPY_AND_ASSIGN(PermissionsInfo); +}; + +class PermissionsHandler: public ManifestHandler { + public: + PermissionsHandler(); + virtual ~PermissionsHandler(); + + bool Parse(std::shared_ptr application, + std::u16string* error) override; + bool AlwaysParseForType(Manifest::Type type) const override; + std::vector Keys() const override; + + private: + DISALLOW_COPY_AND_ASSIGN(PermissionsHandler); +}; + +} // namespace widget_manifest_parser +} // namespace common_installer + +#endif // WIDGET_MANIFEST_PARSER_MANIFEST_HANDLERS_PERMISSIONS_HANDLER_H_ diff --git a/src/widget-manifest-parser/manifest_handlers/tizen_application_handler.cc b/src/widget-manifest-parser/manifest_handlers/tizen_application_handler.cc new file mode 100644 index 0000000..f40ec5b --- /dev/null +++ b/src/widget-manifest-parser/manifest_handlers/tizen_application_handler.cc @@ -0,0 +1,136 @@ +// Copyright (c) 2014 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#include "widget-manifest-parser/manifest_handlers/tizen_application_handler.h" + +#include +#include +#include +#include + +#include "utils/values.h" +#include "widget-manifest-parser/application_manifest_constants.h" + +namespace { +const char kTizenWebAPIVersion[] = "2.2"; +} + +namespace common_installer { + +namespace keys = application_widget_keys; + +namespace widget_manifest_parser { + +TizenApplicationInfo::TizenApplicationInfo() { +} + +TizenApplicationInfo::~TizenApplicationInfo() { +} + +TizenApplicationHandler::TizenApplicationHandler() {} + +TizenApplicationHandler::~TizenApplicationHandler() {} + +bool TizenApplicationHandler::Parse( + std::shared_ptr application, std::u16string* error) { + std::shared_ptr app_info(new TizenApplicationInfo); + const Manifest* manifest = application->GetManifest(); + assert(manifest); + + utils::Value* app_value = nullptr; + manifest->Get(keys::kTizenApplicationKey, &app_value); + // Find an application element with tizen namespace + utils::DictionaryValue* app_dict; + std::string value; + bool find = false; + if (app_value && app_value->IsType(utils::Value::TYPE_DICTIONARY)) { + app_value->GetAsDictionary(&app_dict); + find = app_dict->GetString(keys::kNamespaceKey, &value); + find = find && (value == keys::kTizenNamespacePrefix); + } else if (app_value && app_value->IsType(utils::Value::TYPE_LIST)) { + utils::ListValue* list; + app_value->GetAsList(&list); + for (utils::ListValue::iterator it = list->begin(); + it != list->end(); ++it) { + (*it)->GetAsDictionary(&app_dict); + find = app_dict->GetString(keys::kNamespaceKey, &value); + find = find && (value == keys::kTizenNamespacePrefix); + if (find) + break; + } + } + + if (!find) { + *error = u"Cannot find application element with tizen namespace " + u"or the tizen namespace prefix is incorrect.\n"; + return false; + } + if (app_dict->GetString(keys::kTizenApplicationIdKey, &value)) + app_info->set_id(value); + if (app_dict->GetString(keys::kTizenApplicationPackageKey, &value)) { + app_info->set_package(value); + } + if (app_dict->GetString(keys::kTizenApplicationRequiredVersionKey, &value)) + app_info->set_required_version(value); + + application->SetManifestData(keys::kTizenApplicationKey, + app_info); + return true; +} + +bool TizenApplicationHandler::Validate( + std::shared_ptr application, + std::string* error) const { + const TizenApplicationInfo* app_info = + static_cast( + application->GetManifestData(keys::kTizenApplicationKey)); + + const char kIdPattern[] = "\\A[0-9a-zA-Z]{10}[.][0-9a-zA-Z]{1,52}\\z"; + const char kPackagePattern[] = "\\A[0-9a-zA-Z]{10}\\z"; + std::regex package_regex(kPackagePattern); + std::regex id_regex(kIdPattern); + if (std::regex_search(app_info->id(), id_regex)) { + *error = "The id property of application element " + "does not match the format\n"; + return false; + } + if (std::regex_search(app_info->package(), package_regex)) { + *error = "The package property of application element " + "does not match the format\n"; + return false; + } + if (app_info->id().find(app_info->package()) != 0) { + *error = "The application element property id " + "does not start with package.\n"; + fprintf(stderr, "app_info->id() = %s\n", app_info->id().c_str()); + fprintf(stderr, "app_info->package() = %s\n", app_info->package().c_str()); + return false; + } + if (app_info->required_version().empty()) { + *error = "The required_version property of application " + "element does not exist.\n"; + return false; + } + + const std::string supported_version = kTizenWebAPIVersion; + if (supported_version.compare(app_info->required_version()) < 0) { + *error = "The required_version of Tizen Web API " + "is not supported.\n"; + return false; + } + + return true; +} + +std::vector TizenApplicationHandler::Keys() const { + return std::vector(1, keys::kTizenApplicationKey); +} + +bool TizenApplicationHandler::AlwaysParseForType(Manifest::Type type) const { + return true; +} + +} // namespace widget_manifest_parser +} // namespace common_installer diff --git a/src/widget-manifest-parser/manifest_handlers/tizen_application_handler.h b/src/widget-manifest-parser/manifest_handlers/tizen_application_handler.h new file mode 100644 index 0000000..7c2405e --- /dev/null +++ b/src/widget-manifest-parser/manifest_handlers/tizen_application_handler.h @@ -0,0 +1,71 @@ +// Copyright (c) 2014 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#ifndef WIDGET_MANIFEST_PARSER_MANIFEST_HANDLERS_TIZEN_APPLICATION_HANDLER_H_ +#define WIDGET_MANIFEST_PARSER_MANIFEST_HANDLERS_TIZEN_APPLICATION_HANDLER_H_ + +#include +#include +#include + +#include "utils/macros.h" +#include "utils/values.h" +#include "widget-manifest-parser/application_manifest_constants.h" +#include "widget-manifest-parser/manifest_handler.h" + +namespace common_installer { +namespace widget_manifest_parser { + +class TizenApplicationInfo : public ApplicationData::ManifestData { + public: + TizenApplicationInfo(); + virtual ~TizenApplicationInfo(); + + void set_id(const std::string& id) { + id_ = id; + } + void set_package(const std::string& package) { + package_ = package; + } + void set_required_version( + const std::string& required_version) { + required_version_ = required_version; + } + const std::string& id() const { + return id_; + } + const std::string& package() const { + return package_; + } + const std::string& required_version() const { + return required_version_; + } + + private: + std::string id_; + std::string package_; + std::string required_version_; +}; + +class TizenApplicationHandler : public ManifestHandler { + public: + TizenApplicationHandler(); + virtual ~TizenApplicationHandler(); + + bool Parse(std::shared_ptr application, + std::u16string* error) override; + bool Validate(std::shared_ptr application, + std::string* error) const override; + bool AlwaysParseForType(Manifest::Type type) const override; + std::vector Keys() const override; + + private: + DISALLOW_COPY_AND_ASSIGN(TizenApplicationHandler); +}; + +} // namespace widget_manifest_parser +} // namespace common_installer + +#endif // WIDGET_MANIFEST_PARSER_MANIFEST_HANDLERS_TIZEN_APPLICATION_HANDLER_H_ diff --git a/src/widget-manifest-parser/manifest_handlers/widget_handler.cc b/src/widget-manifest-parser/manifest_handlers/widget_handler.cc new file mode 100644 index 0000000..325529b --- /dev/null +++ b/src/widget-manifest-parser/manifest_handlers/widget_handler.cc @@ -0,0 +1,195 @@ +// Copyright (c) 2014 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#include "widget-manifest-parser/manifest_handlers/widget_handler.h" + +#include + +#include +#include +#include +#include + +#include "utils/utf_converter.h" +#include "utils/values.h" +#include "widget-manifest-parser/application_manifest_constants.h" + +namespace common_installer { + +namespace keys = application_widget_keys; + +namespace { +// Below key names are readable from Javascript widget interface. +const char kAuthor[] = "author"; +const char kDecription[] = "description"; +const char kName[] = "name"; +const char kShortName[] = "shortName"; +const char kVersion[] = "version"; +const char kID[] = "id"; +const char kAuthorEmail[] = "authorEmail"; +const char kAuthorHref[] = "authorHref"; +const char kHeight[] = "height"; +const char kWidth[] = "width"; +const char kPreferences[] = "preferences"; + +// Child keys inside 'preferences' key. +const char kPreferencesName[] = "name"; +const char kPreferencesValue[] = "value"; +const char kPreferencesReadonly[] = "readonly"; + +typedef std::map KeyMap; +typedef std::map::const_iterator KeyMapIterator; +typedef std::pair KeyPair; + +const KeyMap& GetWidgetKeyPairs() { + static KeyMap map; + if (map.empty()) { + map.insert(KeyPair(keys::kAuthorKey, kAuthor)); + map.insert(KeyPair(keys::kDescriptionKey, kDecription)); + map.insert(KeyPair(keys::kNameKey, kName)); + map.insert(KeyPair(keys::kShortNameKey, kShortName)); + map.insert(KeyPair(keys::kVersionKey, kVersion)); + map.insert(KeyPair(keys::kIDKey, kID)); + map.insert(KeyPair(keys::kAuthorEmailKey, kAuthorEmail)); + map.insert(KeyPair(keys::kAuthorHrefKey, kAuthorHref)); + map.insert(KeyPair(keys::kHeightKey, kHeight)); + map.insert(KeyPair(keys::kWidthKey, kWidth)); + } + + return map; +} + +bool ParsePreferenceItem(const utils::DictionaryValue* in_value, + utils::DictionaryValue* out_value, + std::set* used) { + assert(in_value && in_value->IsType(utils::Value::TYPE_DICTIONARY)); + + std::string pref_name; + std::string pref_value; + std::string pref_readonly; + if (in_value->GetString(keys::kPreferencesNameKey, &pref_name) + && used->find(pref_name) == used->end()) { + out_value->SetString(kPreferencesName, pref_name); + used->insert(pref_name); + } else { + return false; + } + + if (in_value->GetString(keys::kPreferencesValueKey, &pref_value)) + out_value->SetString(kPreferencesValue, pref_value); + + if (in_value->GetString(keys::kPreferencesReadonlyKey, &pref_readonly)) + out_value->SetBoolean(kPreferencesReadonly, pref_readonly == "true"); + return true; +} + +} // namespace + +namespace widget_manifest_parser { + +WidgetInfo::WidgetInfo() + : value_(new utils::DictionaryValue) {} + +WidgetInfo::~WidgetInfo() {} + +void WidgetInfo::SetString(const std::string& key, const std::string& value) { + value_->SetString(key, value); +} + +void WidgetInfo::Set(const std::string& key, utils::Value* value) { + value_->Set(key, value); +} + +void WidgetInfo::SetName(const std::string& name) { + value_->SetString(kName, name); +} + +void WidgetInfo::SetShortName(const std::string& short_name) { + fprintf(stderr, "setting short name: %s\n", short_name.c_str()); + value_->SetString(kShortName, short_name); +} + +void WidgetInfo::SetDescription(const std::string& description) { + value_->SetString(kDecription, description); +} + +WidgetHandler::WidgetHandler() {} + +WidgetHandler::~WidgetHandler() {} + +bool WidgetHandler::Parse(std::shared_ptr application, + std::u16string* error) { + std::shared_ptr widget_info(new WidgetInfo()); + const Manifest* manifest = application->GetManifest(); + assert(manifest); + + const KeyMap& map = GetWidgetKeyPairs(); + + for (KeyMapIterator iter = map.begin(); iter != map.end(); ++iter) { + std::string string; + bool result = manifest->GetString(iter->first, &string); + if (result && !string.empty() && iter->first == keys::kAuthorHrefKey) + // When authorhref is an invalid URI, reset it an empty string. + string.clear(); + widget_info->SetString(iter->second, result ? string : ""); + } + + utils::Value* pref_value = nullptr; + manifest->Get(keys::kPreferencesKey, &pref_value); + + std::set preference_names_used; + if (pref_value && pref_value->IsType(utils::Value::TYPE_DICTIONARY)) { + utils::DictionaryValue* preferences = new utils::DictionaryValue; + utils::DictionaryValue* dict; + pref_value->GetAsDictionary(&dict); + if (ParsePreferenceItem(dict, preferences, &preference_names_used)) + widget_info->Set(kPreferences, preferences); + } else if (pref_value && pref_value->IsType(utils::Value::TYPE_LIST)) { + utils::ListValue* preferences = new utils::ListValue; + utils::ListValue* list; + pref_value->GetAsList(&list); + + for (utils::ListValue::iterator it = list->begin(); + it != list->end(); ++it) { + utils::DictionaryValue* pref = new utils::DictionaryValue; + utils::DictionaryValue* dict; + (*it)->GetAsDictionary(&dict); + if (ParsePreferenceItem(dict, pref, &preference_names_used)) + preferences->Append(pref); + } + widget_info->Set(kPreferences, preferences); + } + + application->SetManifestData(keys::kWidgetKey, widget_info); + return true; +} + +bool WidgetHandler::Validate( + std::shared_ptr application, + std::string* error) const { + const Manifest* manifest = application->GetManifest(); + assert(manifest); + std::string ns_value; + if (!manifest->GetString(keys::kWidgetNamespaceKey, &ns_value)) { + *error = "Failed to retrieve the widget's namespace."; + return false; + } + if (strcasecmp(keys::kWidgetNamespacePrefix, ns_value.c_str()) != 0) { + *error = "The widget namespace is invalid."; + return false; + } + return true; +} + +bool WidgetHandler::AlwaysParseForType(Manifest::Type type) const { + return true; +} + +std::vector WidgetHandler::Keys() const { + return std::vector(1, keys::kWidgetKey); +} + +} // namespace widget_manifest_parser +} // namespace common_installer diff --git a/src/widget-manifest-parser/manifest_handlers/widget_handler.h b/src/widget-manifest-parser/manifest_handlers/widget_handler.h new file mode 100644 index 0000000..e86a0ec --- /dev/null +++ b/src/widget-manifest-parser/manifest_handlers/widget_handler.h @@ -0,0 +1,62 @@ +// Copyright (c) 2014 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#ifndef WIDGET_MANIFEST_PARSER_MANIFEST_HANDLERS_WIDGET_HANDLER_H_ +#define WIDGET_MANIFEST_PARSER_MANIFEST_HANDLERS_WIDGET_HANDLER_H_ + +#include +#include +#include + +#include "utils/macros.h" +#include "utils/values.h" +#include "widget-manifest-parser/application_data.h" +#include "widget-manifest-parser/manifest_handler.h" + +namespace common_installer { +namespace widget_manifest_parser { + +class WidgetInfo : public ApplicationData::ManifestData { + public: + WidgetInfo(); + virtual ~WidgetInfo(); + void SetString(const std::string& key, const std::string& value); + void Set(const std::string& key, utils::Value* value); + + // Name, shrot name and description are i18n items, they will be set + // if their value were changed after loacle was changed. + void SetName(const std::string& name); + void SetShortName(const std::string& short_name); + void SetDescription(const std::string& description); + + utils::DictionaryValue* GetWidgetInfo() { + return value_.get(); + } + + private: + std::unique_ptr value_; +}; + +class WidgetHandler : public ManifestHandler { + public: + WidgetHandler(); + virtual ~WidgetHandler(); + + bool Parse(std::shared_ptr application, + std::u16string* error) override; + bool AlwaysParseForType(Manifest::Type type) const override; + std::vector Keys() const override; + + bool Validate(std::shared_ptr application, + std::string* error) const override; + + private: + DISALLOW_COPY_AND_ASSIGN(WidgetHandler); +}; + +} // namespace widget_manifest_parser +} // namespace common_installer + +#endif // WIDGET_MANIFEST_PARSER_MANIFEST_HANDLERS_WIDGET_HANDLER_H_ diff --git a/src/widget-manifest-parser/manifest_util.cc b/src/widget-manifest-parser/manifest_util.cc new file mode 100644 index 0000000..02fcae7 --- /dev/null +++ b/src/widget-manifest-parser/manifest_util.cc @@ -0,0 +1,376 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#include "widget-manifest-parser/manifest_util.h" + +#include +#include + +#include +#include +#include +#include + +#include "utils/string_util.h" +#include "utils/utf_converter.h" +#include "utils/values.h" +#include "widget-manifest-parser/application_data.h" +#include "widget-manifest-parser/application_manifest_constants.h" +#include "widget-manifest-parser/manifest.h" +#include "widget-manifest-parser/manifest_handler.h" + +namespace errors = common_installer::application_manifest_errors; +namespace keys = common_installer::application_manifest_keys; +namespace widget_keys = common_installer::application_widget_keys; + +namespace bf = boost::filesystem; + +namespace { +const char kAttributePrefix[] = "@"; +const char kNamespaceKey[] = "@namespace"; +const char kTextKey[] = "#text"; + +const char kContentKey[] = "content"; + +const xmlChar kWidgetNodeKey[] = "widget"; +const xmlChar kNameNodeKey[] = "name"; +const xmlChar kDescriptionNodeKey[] = "description"; +const xmlChar kAuthorNodeKey[] = "author"; +const xmlChar kLicenseNodeKey[] = "license"; +const xmlChar kIconNodeKey[] = "icon"; + +const xmlChar kVersionAttributeKey[] = "version"; +const xmlChar kShortAttributeKey[] = "short"; +const xmlChar kDirAttributeKey[] = "dir"; +const xmlChar kEmailAttributeKey[] = "email"; +const xmlChar kHrefAttributeKey[] = "href"; +const xmlChar kIdAttributeKey[] = "id"; +const xmlChar kDefaultLocaleAttributeKey[] = "defaultlocale"; +const xmlChar kPathAttributeKey[] = "path"; + +const char* kSingletonElements[] = { + "allow-navigation", + "author", + "content-security-policy-report-only", + "content-security-policy", + "content" +}; + +inline char* ToCharPointer(void* ptr) { + return reinterpret_cast(ptr); +} + +inline const char* ToConstCharPointer(const void* ptr) { + return reinterpret_cast(ptr); +} + +std::u16string ToSting16(const xmlChar* string_ptr) { + return common_installer::utils::utf_converter::UTF8ToUTF16( + std::string(ToConstCharPointer(string_ptr))); +} + +std::string GetNodeDir(xmlNode* node, const std::string& inherit_dir) { + assert(node); + std::string dir(inherit_dir); + + xmlAttr* prop = nullptr; + for (prop = node->properties; prop; prop = prop->next) { + if (xmlStrEqual(prop->name, kDirAttributeKey)) { + char* prop_value = ToCharPointer(xmlNodeListGetString( + node->doc, prop->children, 1)); + dir = prop_value; + xmlFree(prop_value); + break; + } + } + return dir; +} + +std::u16string GetNodeText(xmlNode* root, const std::string& inherit_dir) { + assert(root); + if (root->type != XML_ELEMENT_NODE) + return std::u16string(); + + std::string current_dir(GetNodeDir(root, inherit_dir)); + std::u16string text; + for (xmlNode* node = root->children; node; node = node->next) { +// TODO(jizydorczyk): +// i18n support is needed + if (node->type == XML_TEXT_NODE || node->type == XML_CDATA_SECTION_NODE) { + text = text + common_installer::utils::StripWrappingBidiControlCharacters( + ToSting16(node->content)); + } else { + text = text + GetNodeText(node, current_dir); + } + } + return common_installer::utils::GetDirText(text, current_dir); +} + +// According to widget specification, this two prop need to support dir. +// see detail on http://www.w3.org/TR/widgets/#the-dir-attribute +inline bool IsPropSupportDir(xmlNode* root, xmlAttr* prop) { + if (xmlStrEqual(root->name, kWidgetNodeKey) + && xmlStrEqual(prop->name, kVersionAttributeKey)) + return true; + if (xmlStrEqual(root->name, kNameNodeKey) + && xmlStrEqual(prop->name, kShortAttributeKey)) + return true; + return false; +} + +// Only this four items need to support span and ignore other element. +// Besides xmlNodeListGetString can not support dir prop of span. +// See http://www.w3.org/TR/widgets/#the-span-element-and-its-attributes +inline bool IsElementSupportSpanAndDir(xmlNode* root) { + if (xmlStrEqual(root->name, kNameNodeKey) + || xmlStrEqual(root->name, kDescriptionNodeKey) + || xmlStrEqual(root->name, kAuthorNodeKey) + || xmlStrEqual(root->name, kLicenseNodeKey)) + return true; + return false; +} + +bool IsSingletonElement(const std::string& name) { + for (const char* str : kSingletonElements) + if (name == str) + return name != kContentKey; + return false; +} + +// According to spec 'name' and 'author' should be result of applying the rule +// for getting text content with normalized white space to this element. +// http://www.w3.org/TR/widgets/#rule-for-getting-text-content-with-normalized-white-space-0 +inline bool IsTrimRequiredForElement(xmlNode* root) { + if (xmlStrEqual(root->name, kNameNodeKey) || + xmlStrEqual(root->name, kAuthorNodeKey)) { + return true; + } + return false; +} + +// According to spec some attributes requaire applying the rule for getting +// a single attribute value. +// http://www.w3.org/TR/widgets/#rule-for-getting-a-single-attribute-value-0 +inline bool IsTrimRequiredForProp(xmlNode* root, xmlAttr* prop) { + if (xmlStrEqual(root->name, kWidgetNodeKey) && + (xmlStrEqual(prop->name, kIdAttributeKey) || + xmlStrEqual(prop->name, kVersionAttributeKey) || + xmlStrEqual(prop->name, kDefaultLocaleAttributeKey))) { + return true; + } + if (xmlStrEqual(root->name, kNameNodeKey) && + xmlStrEqual(prop->name, kShortAttributeKey)) { + return true; + } + if (xmlStrEqual(root->name, kAuthorNodeKey) && + (xmlStrEqual(prop->name, kEmailAttributeKey) || + xmlStrEqual(prop->name, kHrefAttributeKey))) { + return true; + } + if (xmlStrEqual(root->name, kLicenseNodeKey) && + xmlStrEqual(prop->name, kHrefAttributeKey)) { + return true; + } + if (xmlStrEqual(root->name, kIconNodeKey) && + xmlStrEqual(prop->name, kPathAttributeKey)) { + return true; + } + return false; +} + +} // namespace + +namespace common_installer { +namespace widget_manifest_parser { + +namespace { + +// Load XML node into Dictionary structure. +// The keys for the XML node to Dictionary mapping are described below: +// XML Dictionary +// "e":{"#text": ""} +// textA "e":{"#text":"textA"} +// textA "e":{ "@attr":"val", "#text": "textA"} +// textA textB "e":{ +// "a":{"#text":"textA"} +// "b":{"#text":"textB"} +// } +// textX textY "e":{ +// "a":[ {"#text":"textX"}, +// {"#text":"textY"}] +// } +// textX textY "e":{ "#text":"textX", +// "a":{"#text":"textY"} +// } +// +// For elements that are specified under a namespace, the dictionary +// will add '@namespace' key for them, e.g., +// XML: +// +// text1 +// +// +// will be saved in Dictionary as, +// "e":{ +// "#text": "", +// "@namespace": "linkA" +// "sub-e1": { +// "#text": "text1", +// "@namespace": "linkA" +// }, +// "sub-e2": { +// "#text":"text2" +// "@namespace": "linkB" +// } +// } + +// converting dictionaryvalue to std::map< +// std::u16string*, std::map> or +// std::map> + +std::unique_ptr LoadXMLNode( + xmlNode* root, const std::string& inherit_dir = "") { + std::unique_ptr value(new utils::DictionaryValue()); + if (root->type != XML_ELEMENT_NODE) + return nullptr; + + std::string current_dir(GetNodeDir(root, inherit_dir)); + + xmlAttr* prop = nullptr; + for (prop = root->properties; prop; prop = prop->next) { + xmlChar* value_ptr = xmlNodeListGetString(root->doc, prop->children, 1); + std::u16string prop_value(ToSting16(value_ptr)); + xmlFree(value_ptr); + + if (IsPropSupportDir(root, prop)) + prop_value = utils::GetDirText(prop_value, current_dir); + + if (IsTrimRequiredForProp(root, prop)) + prop_value = utils::CollapseWhitespace(prop_value, false); + + value->SetString( + std::string(kAttributePrefix) + ToConstCharPointer(prop->name), + prop_value); + } + + if (root->ns) + value->SetString(kNamespaceKey, ToConstCharPointer(root->ns->href)); + + for (xmlNode* node = root->children; node; node = node->next) { + std::string sub_node_name(ToConstCharPointer(node->name)); + std::unique_ptr sub_value = + LoadXMLNode(node, current_dir); + if (!sub_value) + continue; + + if (!value->HasKey(sub_node_name)) { + value->Set(sub_node_name, sub_value.release()); + continue; + } else if (IsSingletonElement(sub_node_name)) { + continue; + } else if (sub_node_name == kContentKey) { + std::string current_namespace, new_namespace; + utils::DictionaryValue* current_value; + value->GetDictionary(sub_node_name, ¤t_value); + + current_value->GetString(kNamespaceKey, ¤t_namespace); + sub_value->GetString(kNamespaceKey, &new_namespace); + if (current_namespace != new_namespace && + new_namespace == widget_keys::kTizenNamespacePrefix) + value->Set(sub_node_name, sub_value.release()); + continue; + } + + utils::Value* temp; + value->Get(sub_node_name, &temp); + assert(temp); + + if (temp->IsType(utils::Value::TYPE_LIST)) { + utils::ListValue* list; + temp->GetAsList(&list); + list->Append(sub_value.release()); + } else { + assert(temp->IsType(utils::Value::TYPE_DICTIONARY)); + utils::DictionaryValue* dict; + temp->GetAsDictionary(&dict); + utils::DictionaryValue* prev_value = dict->DeepCopy(); + + utils::ListValue* list = new utils::ListValue(); + list->Append(prev_value); + list->Append(sub_value.release()); + value->Set(sub_node_name, list); + } + } + + std::u16string text; + if (IsElementSupportSpanAndDir(root)) { + text = GetNodeText(root, current_dir); + } else { + xmlChar* text_ptr = xmlNodeListGetString(root->doc, root->children, 1); + if (text_ptr) { + text = ToSting16(text_ptr); + xmlFree(text_ptr); + } + } + + if (IsTrimRequiredForElement(root)) + text = utils::CollapseWhitespace(text, false); + + if (!text.empty()) + value->SetString(kTextKey, text); + + return value; +} + +} // namespace + +std::unique_ptr LoadManifest(const std::string& manifest_path, + Manifest::Type type, std::string* error) { + xmlDoc * doc = nullptr; + xmlNode* root_node = nullptr; + doc = xmlReadFile(manifest_path.c_str(), nullptr, 0); + if (!doc) { + *error = errors::kManifestUnreadable; + return nullptr; + } + root_node = xmlDocGetRootElement(doc); + std::unique_ptr dv = LoadXMLNode(root_node); + std::unique_ptr result(new utils::DictionaryValue); + if (dv) + result->Set(ToConstCharPointer(root_node->name), dv.release()); + + return std::unique_ptr( + new Manifest(std::move(result), Manifest::TYPE_WIDGET)); +} + +bf::path ApplicationURLToRelativeFilePath(const std::string& url) { + std::string url_path = url; + if (url_path.empty() || url_path[0] != '/') + return bf::path(); + + // TODO(jizydorczyk): + // We need to unescappe %-encoded UTF8 chars here + // for now its left undone + // Drop the leading slashes and convert %-encoded UTF8 to regular UTF8. +// std::string file_path = net::UnescapeURLComponent(url_path, +// net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS); +// size_t skip = file_path.find_first_not_of("/\\"); +// if (skip != file_path.npos) +// file_path = file_path.substr(skip); + + std::string file_path = url_path; + bf::path path(file_path); + + // It's still possible for someone to construct an annoying URL whose path + // would still wind up not being considered relative at this point. + // For example: app://id/c:////foo.html + if (path.is_absolute()) + return bf::path(); + + return path; +} + +} // namespace widget_manifest_parser +} // namespace common_installer diff --git a/src/widget-manifest-parser/manifest_util.h b/src/widget-manifest-parser/manifest_util.h new file mode 100644 index 0000000..5c83dc4 --- /dev/null +++ b/src/widget-manifest-parser/manifest_util.h @@ -0,0 +1,29 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#ifndef WIDGET_MANIFEST_PARSER_MANIFEST_UTIL_H_ +#define WIDGET_MANIFEST_PARSER_MANIFEST_UTIL_H_ + +#include + +#include +#include +#include + +#include "widget-manifest-parser/application_data.h" + +// Utilities for manipulating the on-disk storage of applications. +namespace common_installer { +namespace widget_manifest_parser { + +// Loads an application manifest from the specified directory. Returns NULL +// on failure, with a description of the error in |error|. +std::unique_ptr LoadManifest( + const std::string& file_path, Manifest::Type type, std::string* error); + +} // namespace widget_manifest_parser +} // namespace common_installer + +#endif // WIDGET_MANIFEST_PARSER_MANIFEST_UTIL_H_ diff --git a/src/widget-manifest-parser/permission_types.h b/src/widget-manifest-parser/permission_types.h new file mode 100644 index 0000000..e6e9777 --- /dev/null +++ b/src/widget-manifest-parser/permission_types.h @@ -0,0 +1,44 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#ifndef WIDGET_MANIFEST_PARSER_PERMISSION_TYPES_H_ +#define WIDGET_MANIFEST_PARSER_PERMISSION_TYPES_H_ + +#include +#include +#include + +namespace common_installer { +namespace widget_manifest_parser { + +enum PermissionType { + SESSION_PERMISSION, + PERSISTENT_PERMISSION, +}; + +enum RuntimePermission { + ALLOW_ONCE = 0, + ALLOW_SESSION, + ALLOW_ALWAYS, + DENY_ONCE, + DENY_SESSION, + DENY_ALWAYS, + UNDEFINED_RUNTIME_PERM, +}; + +enum StoredPermission { + ALLOW = 0, + DENY, + PROMPT, + UNDEFINED_STORED_PERM, +}; + +typedef std::map StoredPermissionMap; +typedef std::set PermissionSet; + +} // namespace widget_manifest_parser +} // namespace common_installer + +#endif // WIDGET_MANIFEST_PARSER_PERMISSION_TYPES_H_ diff --git a/src/widget-manifest-parser/widget_manifest_parser.cc b/src/widget-manifest-parser/widget_manifest_parser.cc new file mode 100644 index 0000000..a24903b --- /dev/null +++ b/src/widget-manifest-parser/widget_manifest_parser.cc @@ -0,0 +1,439 @@ +// Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#include "widget-manifest-parser/widget_manifest_parser.h" + +#include + +#include +#include +#include +#include +#include + +#include "utils/macros.h" +#include "utils/values.h" + +#include "widget-manifest-parser/application_data.h" +#include "widget-manifest-parser/application_manifest_constants.h" +#include "widget-manifest-parser/manifest_util.h" +#include "widget-manifest-parser/manifest_handlers/permissions_handler.h" +#include "widget-manifest-parser/manifest_handlers/tizen_application_handler.h" +#include "widget-manifest-parser/manifest_handlers/widget_handler.h" +#include "widget-manifest-parser/permission_types.h" + +#define API_EXPORT __attribute__((visibility("default"))) + +namespace bf = boost::filesystem; +namespace keys = common_installer::application_widget_keys; + +namespace { + +const char kErrMsgNoPath[] = + "Path not specified."; +const char kErrMsgInvalidPath[] = + "Invalid path."; +const char kErrMsgValueNotFound[] = + "Value not found. Value name: "; +const char kErrMsgInvalidDictionary[] = + "Cannot get key value as a dictionary. Key name: "; +const char kErrMsgInvalidList[] = + "Cannot get key value as a list. Key name: "; +const char kErrMsgNoMandatoryKey[] = + "Cannot find mandatory key. Key name: "; + +const char kName[] = "name"; +const char kShortName[] = "shortName"; +const char kVersion[] = "version"; +const char kWidgetPrivilegeFullKey[] = "widget.privilege"; +const char kWidgetPrivilegeNameKey[] = "@name"; +const char kWidgetIconFullKey[] = "widget.icon"; +const char kWidgetIconSrcKey[] = "@src"; + +class LocalManifestData { + public: + LocalManifestData() { + data_.package = package_.c_str(); + data_.id = id_.c_str(); + data_.name = name_.c_str(); + data_.short_name = short_name_.c_str(); + data_.version = version_.c_str(); + data_.icon = icon_.c_str(); + data_.api_version = api_version_.c_str(); + data_.privilege_count = privilege_list_.size(); + data_.privilege_list = privilege_list_.data(); + } + + void SetPackage(const std::string& value) { + package_ = value; + data_.package = package_.c_str(); + } + + void SetId(const std::string& value) { + id_ = value; + data_.id = id_.c_str(); + } + + void SetName(const std::string& value) { + name_ = value; + data_.name = name_.c_str(); + } + + void SetShortName(const std::string& value) { + short_name_ = value; + data_.short_name = short_name_.c_str(); + } + + void SetVersion(const std::string& value) { + version_ = value; + data_.version = version_.c_str(); + } + + void SetIcon(const std::string& value) { + icon_ = value; + data_.icon = icon_.c_str(); + } + + void SetApiVersion(const std::string& value) { + api_version_ = value; + data_.api_version = api_version_.c_str(); + } + + void SetPrivileges(const std::set& value) { + std::copy(value.begin(), value.end(), std::back_inserter(privileges_)); + privilege_list_.clear(); + for (const std::string& p : privileges_) + privilege_list_.push_back(p.c_str()); + data_.privilege_count = privilege_list_.size(); + data_.privilege_list = privilege_list_.data(); + } + + const ManifestData* GetManifestData() const { + return &data_; + } + + private: + std::string package_; + std::string id_; + std::string name_; + std::string short_name_; + std::string version_; + std::string icon_; + std::string api_version_; + std::vector privileges_; + std::vector privilege_list_; + ManifestData data_; + + DISALLOW_COPY_AND_ASSIGN(LocalManifestData); +}; + +typedef std::string LocalError; + +class LocalStorage { + public: + static LocalStorage* GetInstance() { + static LocalStorage instance; + return &instance; + } + + const ManifestData* Add(std::shared_ptr data) { + const ManifestData* result = data->GetManifestData(); + data_vector_.push_back(data); + return result; + } + + bool Remove(const ManifestData* data) { + LocalManifestDataVector::iterator it; + for (it = data_vector_.begin(); it != data_vector_.end(); ++it) + if ((*it)->GetManifestData() == data) { + data_vector_.erase(it); + return true; + } + return false; + } + + const char* Add(LocalError* error) { + const char* result = error->c_str(); + error_vector_.push_back(std::shared_ptr(error)); + return result; + } + + bool Remove(const char* error) { + ErrorVector::iterator it; + for (it = error_vector_.begin(); it != error_vector_.end(); ++it) + if ((*it)->c_str() == error) { + error_vector_.erase(it); + return true; + } + return false; + } + + private: + typedef std::vector> + LocalManifestDataVector; + typedef std::vector> ErrorVector; + + LocalManifestDataVector data_vector_; + ErrorVector error_vector_; + + LocalStorage() { } + + DISALLOW_COPY_AND_ASSIGN(LocalStorage); +}; + +void SetError(const std::string& message, const char** error) { + if (error) + *error = LocalStorage::GetInstance()->Add(new std::string(message)); +} + +void SetError(const std::string& message, const std::string& arg, + const char** error) { + if (error) + *error = LocalStorage::GetInstance()->Add(new std::string(message + arg)); +} + +bool ExtractPackage( + const common_installer::widget_manifest_parser::ApplicationData& app_data, + std::string* value) { + common_installer::widget_manifest_parser::TizenApplicationInfo* info = + static_cast< + common_installer::widget_manifest_parser::TizenApplicationInfo*>( + app_data.GetManifestData(keys::kTizenApplicationKey)); + if (!info) + return false; + *value = info->package(); + return true; +} + +bool ExtractId( + const common_installer::widget_manifest_parser::ApplicationData& app_data, + std::string* value) { + common_installer::widget_manifest_parser::TizenApplicationInfo* info = + static_cast< + common_installer::widget_manifest_parser::TizenApplicationInfo*>( + app_data.GetManifestData(keys::kTizenApplicationKey)); + if (!info) + return false; + *value = info->id(); + return true; +} + +bool ExtractName( + const common_installer::widget_manifest_parser::ApplicationData& app_data, + std::string* value) { + common_installer::widget_manifest_parser::WidgetInfo* info = + static_cast( + app_data.GetManifestData(keys::kWidgetKey)); + if (!info) + return false; + + return info->GetWidgetInfo()->GetString(kName, value); +} + +bool ExtractShortName( + const common_installer::widget_manifest_parser::ApplicationData& app_data, + std::string* value) { + common_installer::widget_manifest_parser::WidgetInfo* info = + static_cast( + app_data.GetManifestData(keys::kWidgetKey)); + if (!info) + return false; + return info->GetWidgetInfo()->GetString(kShortName, value); +} + +bool ExtractVersion( + const common_installer::widget_manifest_parser::ApplicationData& app_data, + std::string* value) { + common_installer::widget_manifest_parser::WidgetInfo* info = + static_cast( + app_data.GetManifestData(keys::kWidgetKey)); + if (!info) + return false; + return info->GetWidgetInfo()->GetString(kVersion, value); +} + +bool ExtractIconSrc(const common_installer::utils::Value& dict, + std::string* value, const char** error) { + const common_installer::utils::DictionaryValue* inner_dict; + if (!dict.GetAsDictionary(&inner_dict)) { + SetError(kErrMsgInvalidDictionary, kWidgetIconFullKey, error); + return false; + } + std::string src; + if (!inner_dict->GetString(kWidgetIconSrcKey, &src)) { + SetError(kErrMsgNoMandatoryKey, kWidgetIconSrcKey, error); + return false; + } + *value = src; + return true; +} + +bool ExtractIcons( + const common_installer::widget_manifest_parser::Manifest& manifest, + std::vector* value, const char** error) { + common_installer::utils::Value* key_value; + if (!manifest.Get(kWidgetIconFullKey, &key_value)) { + value->clear(); + return true; // no icon, no error + } + + std::vector icons; + if (key_value->IsType(common_installer::utils::Value::TYPE_DICTIONARY)) { + std::string icon; + if (!ExtractIconSrc(*key_value, &icon, error)) + return false; + icons.push_back(icon); + } else if (key_value->IsType(common_installer::utils::Value::TYPE_LIST)) { + const common_installer::utils::ListValue* list; + if (!key_value->GetAsList(&list)) { + SetError(kErrMsgInvalidList, kWidgetIconFullKey, error); + return false; + } + for (const common_installer::utils::Value* list_value : *list) { + std::string icon; + if (!ExtractIconSrc(*list_value, &icon, error)) + return false; + icons.push_back(icon); + } + } + + value->swap(icons); + return true; +} + +bool ExtractApiVersion( + const common_installer::widget_manifest_parser::ApplicationData& app_data, + std::string* value) { + common_installer::widget_manifest_parser::TizenApplicationInfo* info = + static_cast< + common_installer::widget_manifest_parser::TizenApplicationInfo*>( + app_data.GetManifestData(keys::kTizenApplicationKey)); + if (!info) + return false; + *value = info->required_version(); + return true; +} + +bool ExtractPrivileges( + const common_installer::widget_manifest_parser::ApplicationData& app_data, + std::set* value, const char** error) { + const common_installer::widget_manifest_parser::PermissionsInfo* perm_info = + static_cast( + app_data.GetManifestData(keys::kTizenPermissionsKey)); + common_installer::widget_manifest_parser::PermissionSet permissions = + perm_info->GetAPIPermissions(); + *value = permissions; + return true; +} + +} // namespace + +extern "C" { + +API_EXPORT bool ParseManifest(const char* path, + const ManifestData** data, const char** error) { + if (!path) { + SetError(kErrMsgNoPath, error); + return false; + } + std::string str_path = path; + if (str_path.empty()) { + SetError(kErrMsgInvalidPath, error); + return false; + } + + std::string local_error; + + std::unique_ptr manifest = + common_installer::widget_manifest_parser::LoadManifest( + path, common_installer::widget_manifest_parser::Manifest::TYPE_WIDGET, + &local_error); + if (!manifest) { + SetError(local_error, error); + return false; + } + + std::shared_ptr + app_data = + common_installer::widget_manifest_parser::ApplicationData::Create( + bf::path(), std::string(), + common_installer::widget_manifest_parser::ApplicationData::INTERNAL, + std::move(manifest), &local_error); + if (!app_data.get()) { + SetError(local_error, error); + return false; + } + + std::string package; + if (!ExtractPackage(*app_data, &package)) { + SetError(kErrMsgValueNotFound, "package id", error); + return false; + } + + std::string id; + if (!ExtractId(*app_data, &id)) { + SetError(kErrMsgValueNotFound, "application id", error); + return false; + } + + std::string name; + if (!ExtractName(*app_data, &name)) { + SetError(kErrMsgValueNotFound, "application name", error); + return false; + } + + std::string short_name; + if (!ExtractShortName(*app_data, &short_name)) { + SetError(kErrMsgValueNotFound, "application short name", error); + return false; + } + + std::string version; + if (!ExtractVersion(*app_data, &version)) { + SetError(kErrMsgValueNotFound, "application version", error); + return false; + } + + std::vector icons; + if (!ExtractIcons(*app_data->GetManifest(), &icons, error)) + return false; + + std::string api_version; + if (!ExtractApiVersion(*app_data, &api_version)) { + SetError(kErrMsgValueNotFound, "required api version", error); + return false; + } + + std::set privileges; + if (!ExtractPrivileges(*app_data, &privileges, error)) + return false; + + if (data) { + std::shared_ptr local_manifest_data( + new LocalManifestData); + local_manifest_data->SetPackage(package); + local_manifest_data->SetId(id); + local_manifest_data->SetName(name); + local_manifest_data->SetShortName(short_name); + local_manifest_data->SetVersion(version); + local_manifest_data->SetIcon(icons.empty() ? "" : icons.front()); + local_manifest_data->SetApiVersion(api_version); + local_manifest_data->SetPrivileges(privileges); + *data = LocalStorage::GetInstance()->Add(local_manifest_data); + } + + return true; +} + +API_EXPORT bool ReleaseData(const ManifestData* data, const char* error) { + bool result = true; + if (data) + result = result && LocalStorage::GetInstance()->Remove(data); + if (error) + result = result && LocalStorage::GetInstance()->Remove(error); + return result; +} + +} // extern "C" diff --git a/src/widget-manifest-parser/widget_manifest_parser.h b/src/widget-manifest-parser/widget_manifest_parser.h new file mode 100644 index 0000000..d4bd60a --- /dev/null +++ b/src/widget-manifest-parser/widget_manifest_parser.h @@ -0,0 +1,40 @@ +// Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-xwalk file. + +#ifndef WIDGET_MANIFEST_PARSER_WIDGET_MANIFEST_PARSER_H_ +#define WIDGET_MANIFEST_PARSER_WIDGET_MANIFEST_PARSER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// Represents a manifest data +struct ManifestData { + const char* package; + const char* id; + const char* name; + const char* short_name; + const char* version; + const char* icon; + const char* api_version; + unsigned int privilege_count; + const char** privilege_list; +}; + +// Reads manifest from specified file and filles specified data argument +// with read data. Returns true on success or false otherwise. If the error +// parameter is specified, it is also filled with proper message. +bool ParseManifest(const char* path, + const ManifestData** data, const char** error); + +// Releses the data and the error returned by ParseManifest. +// Returns true on success or false otherwise. +bool ReleaseData(const ManifestData* data, const char* error); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WIDGET_MANIFEST_PARSER_WIDGET_MANIFEST_PARSER_H_ -- 2.7.4