[Widget-manifest-parser] Added parser's base 17/34917/6
authorJakub Izydorczyk <j.izydorczyk@samsung.com>
Wed, 28 Jan 2015 13:23:53 +0000 (14:23 +0100)
committerPawel Sikorski <p.sikorski@samsung.com>
Thu, 12 Feb 2015 09:45:26 +0000 (01:45 -0800)
Change-Id: Ic7325a08d9ed1359a6e6be77e0d62b3dbe046e7f

23 files changed:
CMakeLists.txt
packaging/app-installers.spec
src/utils/CMakeLists.txt
src/utils/string_util.cc [new file with mode: 0644]
src/utils/string_util.h [new file with mode: 0644]
src/wgt/CMakeLists.txt
src/wgt/step/step_parse.h
src/widget-manifest-parser/CMakeLists.txt
src/widget-manifest-parser/application_data.cc [new file with mode: 0644]
src/widget-manifest-parser/application_data.h [new file with mode: 0644]
src/widget-manifest-parser/manifest_handler.cc [new file with mode: 0644]
src/widget-manifest-parser/manifest_handler.h [new file with mode: 0644]
src/widget-manifest-parser/manifest_handlers/permissions_handler.cc [new file with mode: 0644]
src/widget-manifest-parser/manifest_handlers/permissions_handler.h [new file with mode: 0644]
src/widget-manifest-parser/manifest_handlers/tizen_application_handler.cc [new file with mode: 0644]
src/widget-manifest-parser/manifest_handlers/tizen_application_handler.h [new file with mode: 0644]
src/widget-manifest-parser/manifest_handlers/widget_handler.cc [new file with mode: 0644]
src/widget-manifest-parser/manifest_handlers/widget_handler.h [new file with mode: 0644]
src/widget-manifest-parser/manifest_util.cc [new file with mode: 0644]
src/widget-manifest-parser/manifest_util.h [new file with mode: 0644]
src/widget-manifest-parser/permission_types.h [new file with mode: 0644]
src/widget-manifest-parser/widget_manifest_parser.cc [new file with mode: 0644]
src/widget-manifest-parser/widget_manifest_parser.h [new file with mode: 0644]

index 24c34a4..5a9d621 100644 (file)
@@ -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)
 
index fbd4746..25f1741 100644 (file)
@@ -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
index b0814d9..eb52ff5 100644 (file)
@@ -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 (file)
index 0000000..bd6fbd8
--- /dev/null
@@ -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 <string>
+
+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<typename STR>
+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 (file)
index 0000000..ebc0c4b
--- /dev/null
@@ -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 <string>
+
+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_
index 31a8ab0..0a40355 100644 (file)
@@ -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})
index 8331657..2a9227c 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <boost/filesystem.hpp>
 
-#include <widget-manifest-parser/widget-manifest-parser.h>
+#include <widget-manifest-parser/widget_manifest_parser.h>
 
 #include "common/app_installer.h"
 #include "common/context_installer.h"
index 659a4dd..33bd14e 100644 (file)
@@ -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 (file)
index 0000000..dae0de3
--- /dev/null
@@ -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 <cassert>
+#include <iostream>
+#include <regex>
+
+#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> ApplicationData::Create(
+    const bf::path& path, const std::string& explicit_id,
+    SourceType source_type, std::unique_ptr<Manifest> manifest,
+    std::string* error_message) {
+  assert(error_message);
+  std::u16string error;
+  if (!manifest->ValidateManifest(error_message))
+    return nullptr;
+
+  std::shared_ptr<ApplicationData> 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<ApplicationData::ManifestData> 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)
+    : 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<TizenApplicationInfo*>(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<WidgetInfo*>(
+          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 (file)
index 0000000..cff8b29
--- /dev/null
@@ -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 <boost/filesystem/path.hpp>
+#include <string.h>
+
+#include <algorithm>
+#include <iosfwd>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#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<ApplicationData> {
+ 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<const std::string, std::shared_ptr<ManifestData> >
+      ManifestDataMap;
+  typedef std::map<std::string,
+      std::shared_ptr<ApplicationData>, 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<ApplicationData> Create(const bf::path& app_path,
+      const std::string& explicit_id, SourceType source_type,
+          std::unique_ptr<Manifest> 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<ManifestData> 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> 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> 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 (file)
index 0000000..124dad1
--- /dev/null
@@ -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 <cassert>
+#include <set>
+
+#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<const CategoryInfoList*>(
+//                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<const ApplicationData> 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<std::string> ManifestHandler::PrerequisiteKeys() const {
+  return std::vector<std::string>();
+}
+
+ManifestHandlerRegistry* ManifestHandlerRegistry::widget_registry_ = NULL;
+
+ManifestHandlerRegistry::ManifestHandlerRegistry(
+    const std::vector<ManifestHandler*>& handlers) {
+  for (std::vector<ManifestHandler*>::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<ManifestHandler*> 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<std::string>& keys = handler->Keys();
+  for (size_t i = 0; i < keys.size(); ++i) {
+    handlers_[keys[i]] = handler;
+  }
+}
+
+bool ManifestHandlerRegistry::ParseAppManifest(
+    std::shared_ptr<ApplicationData> application, std::u16string* error) {
+  std::map<int, ManifestHandler*> 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<int, ManifestHandler*>::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<const ApplicationData> 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<ManifestHandler*> 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<ManifestHandler*> next_unsorted_handlers;
+    for (std::set<ManifestHandler*>::const_iterator iter =
+             unsorted_handlers.begin();
+         iter != unsorted_handlers.end(); ++iter) {
+      ManifestHandler* handler = *iter;
+      const std::vector<std::string>& 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 (file)
index 0000000..556eeb2
--- /dev/null
@@ -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 <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#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<ApplicationData> 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<const ApplicationData> 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<std::string> PrerequisiteKeys() const;
+
+  // The keys to register handler for (in Register).
+  virtual std::vector<std::string> Keys() const = 0;
+};
+
+class ManifestHandlerRegistry final {
+ public:
+  ~ManifestHandlerRegistry();
+
+  static ManifestHandlerRegistry* GetInstance(Manifest::Type type);
+
+  bool ParseAppManifest(
+      std::shared_ptr<ApplicationData> application, std::u16string* error);
+  bool ValidateAppManifest(std::shared_ptr<const ApplicationData> application,
+      std::string* error);
+
+ private:
+  friend class ScopedTestingManifestHandlerRegistry;
+  explicit ManifestHandlerRegistry(
+      const std::vector<ManifestHandler*>& 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<std::string, ManifestHandler*> ManifestHandlerMap;
+  typedef std::map<ManifestHandler*, int> 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 (file)
index 0000000..38578fc
--- /dev/null
@@ -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 <iostream>
+
+#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<ApplicationData> application, std::u16string* error) {
+  std::shared_ptr<PermissionsInfo> 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<utils::ListValue> 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<std::string> PermissionsHandler::Keys() const {
+  return std::vector<std::string>(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 (file)
index 0000000..c00c491
--- /dev/null
@@ -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 <string>
+#include <vector>
+
+#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<ApplicationData> application,
+                     std::u16string* error) override;
+  bool AlwaysParseForType(Manifest::Type type) const override;
+  std::vector<std::string> 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 (file)
index 0000000..f40ec5b
--- /dev/null
@@ -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 <cassert>
+#include <map>
+#include <regex>
+#include <utility>
+
+#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<ApplicationData> application, std::u16string* error) {
+  std::shared_ptr<TizenApplicationInfo> 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<const ApplicationData> application,
+    std::string* error) const {
+  const TizenApplicationInfo* app_info =
+      static_cast<const TizenApplicationInfo*>(
+          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<std::string> TizenApplicationHandler::Keys() const {
+  return std::vector<std::string>(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 (file)
index 0000000..7c2405e
--- /dev/null
@@ -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 <map>
+#include <string>
+#include <vector>
+
+#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<ApplicationData> application,
+             std::u16string* error) override;
+  bool Validate(std::shared_ptr<const ApplicationData> application,
+                std::string* error) const override;
+  bool AlwaysParseForType(Manifest::Type type) const override;
+  std::vector<std::string> 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 (file)
index 0000000..325529b
--- /dev/null
@@ -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 <string.h>
+
+#include <cassert>
+#include <map>
+#include <utility>
+#include <set>
+
+#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<std::string, std::string> KeyMap;
+typedef std::map<std::string, std::string>::const_iterator KeyMapIterator;
+typedef std::pair<std::string, std::string> 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<std::string>* 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<ApplicationData> application,
+                          std::u16string* error) {
+  std::shared_ptr<WidgetInfo> 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<std::string> 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<const ApplicationData> 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<std::string> WidgetHandler::Keys() const {
+  return std::vector<std::string>(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 (file)
index 0000000..e86a0ec
--- /dev/null
@@ -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 <map>
+#include <string>
+#include <vector>
+
+#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<utils::DictionaryValue> value_;
+};
+
+class WidgetHandler : public ManifestHandler {
+ public:
+  WidgetHandler();
+  virtual ~WidgetHandler();
+
+  bool Parse(std::shared_ptr<ApplicationData> application,
+             std::u16string* error) override;
+  bool AlwaysParseForType(Manifest::Type type) const override;
+  std::vector<std::string> Keys() const override;
+
+  bool Validate(std::shared_ptr<const ApplicationData> 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 (file)
index 0000000..02fcae7
--- /dev/null
@@ -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 <boost/filesystem/operations.hpp>
+#include <libxml2/libxml/tree.h>
+
+#include <algorithm>
+#include <cassert>
+#include <map>
+#include <vector>
+
+#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<char *>(ptr);
+}
+
+inline const char* ToConstCharPointer(const void* ptr) {
+  return reinterpret_cast<const char*>(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></e>                             "e":{"#text": ""}
+// <e>textA</e>                        "e":{"#text":"textA"}
+// <e attr="val">textA</e>             "e":{ "@attr":"val", "#text": "textA"}
+// <e> <a>textA</a> <b>textB</b> </e>  "e":{
+//                                       "a":{"#text":"textA"}
+//                                       "b":{"#text":"textB"}
+//                                     }
+// <e> <a>textX</a> <a>textY</a> </e>  "e":{
+//                                       "a":[ {"#text":"textX"},
+//                                             {"#text":"textY"}]
+//                                     }
+// <e> textX <a>textY</a> </e>         "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:
+// <e xmln="linkA" xmlns:N="LinkB">
+//   <sub-e1> text1 </sub-e>
+//   <N:sub-e2 text2 />
+// </e>
+// 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<std::u16string*,std::u16string*>> or
+// std::map<std::u16string*, std::map<std::u16string*,std::u16string>>
+
+std::unique_ptr<utils::DictionaryValue> LoadXMLNode(
+    xmlNode* root, const std::string& inherit_dir = "") {
+  std::unique_ptr<utils::DictionaryValue> 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<utils::DictionaryValue> 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, &current_value);
+
+      current_value->GetString(kNamespaceKey, &current_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<Manifest> 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<utils::DictionaryValue> dv = LoadXMLNode(root_node);
+  std::unique_ptr<utils::DictionaryValue> result(new utils::DictionaryValue);
+  if (dv)
+    result->Set(ToConstCharPointer(root_node->name), dv.release());
+
+  return std::unique_ptr<Manifest>(
+      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 (file)
index 0000000..5c83dc4
--- /dev/null
@@ -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 <boost/filesystem/path.hpp>
+
+#include <string>
+#include <map>
+#include <memory>
+
+#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<Manifest> 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 (file)
index 0000000..e6e9777
--- /dev/null
@@ -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 <map>
+#include <set>
+#include <string>
+
+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<std::string, StoredPermission> StoredPermissionMap;
+typedef std::set<std::string> 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 (file)
index 0000000..a24903b
--- /dev/null
@@ -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 <boost/filesystem/path.hpp>
+
+#include <algorithm>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#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<std::string>& 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<std::string> privileges_;
+  std::vector<const char*> 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<LocalManifestData> 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<LocalError>(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<std::shared_ptr<LocalManifestData>>
+      LocalManifestDataVector;
+  typedef std::vector<std::shared_ptr<LocalError>> 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<common_installer::widget_manifest_parser::WidgetInfo*>(
+        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<common_installer::widget_manifest_parser::WidgetInfo*>(
+        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<common_installer::widget_manifest_parser::WidgetInfo*>(
+        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<std::string>* 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<std::string> 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<std::string>* value, const char** error) {
+    const common_installer::widget_manifest_parser::PermissionsInfo* perm_info =
+        static_cast<common_installer::widget_manifest_parser::PermissionsInfo*>(
+            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<common_installer::widget_manifest_parser::Manifest> 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<common_installer::widget_manifest_parser::ApplicationData>
+      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<std::string> 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<std::string> privileges;
+  if (!ExtractPrivileges(*app_data, &privileges, error))
+    return false;
+
+  if (data) {
+    std::shared_ptr<LocalManifestData> 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 (file)
index 0000000..d4bd60a
--- /dev/null
@@ -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_