1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "xwalk/application/common/manifest.h"
9 #include "base/basictypes.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "xwalk/application/common/application_manifest_constants.h"
17 #include "xwalk/runtime/browser/xwalk_runner.h"
19 namespace errors = xwalk::application_manifest_errors;
20 namespace keys = xwalk::application_manifest_keys;
21 namespace widget_keys = xwalk::application_widget_keys;
24 namespace application {
26 const char kLocaleUnlocalized[] = "@unlocalized";
28 const char kLocaleAuto[] = "en-gb";
30 const char kLocaleAuto[] = "en-us";
32 const char kLocaleFirstOne[] = "*";
34 const char kWidgetNamePath[] = "widget.name";
35 const char kWidgetDecriptionPath[] = "widget.description";
36 const char kWidgetLicensePath[] = "widget.license";
38 const char kPathConnectSymbol = '.';
40 typedef std::list<std::string> List;
42 std::string GetLocalizedKey(const std::string& key,
43 const std::string& local) {
44 std::string lower_local = StringToLowerASCII(local);
45 if (lower_local.empty())
46 lower_local = kLocaleUnlocalized;
47 return key + kPathConnectSymbol + lower_local;
50 scoped_ptr<List> ExpandUserAgentLocalesList(const scoped_ptr<List>& list) {
51 scoped_ptr<List> expansion_list(new List);
52 for (List::const_iterator it = list->begin(); it != list->end(); ++it) {
53 std::string copy_locale(*it);
56 expansion_list->push_back(copy_locale);
57 position = copy_locale.find_last_of("-");
58 copy_locale = copy_locale.substr(0, position);
59 } while (position != std::string::npos);
61 return expansion_list.Pass();
66 Manifest::Manifest(SourceType source_type,
67 scoped_ptr<base::DictionaryValue> value)
68 : source_type_(source_type),
70 i18n_data_(new base::DictionaryValue),
72 if (data_->Get(keys::kStartURLKey, NULL)) {
73 type_ = TYPE_PACKAGED_APP;
74 } else if (data_->HasKey(keys::kAppKey)) {
75 if (data_->Get(keys::kWebURLsKey, NULL) ||
76 data_->Get(keys::kLaunchWebURLKey, NULL)) {
77 type_ = TYPE_HOSTED_APP;
78 } else if (data_->Get(keys::kLaunchLocalPathKey, NULL)) {
79 type_ = TYPE_PACKAGED_APP;
83 if (data_->HasKey(widget_keys::kWidgetKey) &&
84 data_->Get(widget_keys::kWidgetKey, NULL))
85 package_type_ = TYPE_WGT;
87 package_type_ = TYPE_XPK;
92 // Unittest may not have an xwalkrunner, so we should check here.
93 if (XWalkRunner* xwalk_runner = XWalkRunner::GetInstance())
94 SetSystemLocale(xwalk_runner->GetLocale());
96 SetSystemLocale(kLocaleUnlocalized);
99 Manifest::~Manifest() {
102 bool Manifest::ValidateManifest(
104 std::vector<InstallWarning>* warnings) const {
105 // TODO(changbin): field 'manifest_version' of manifest.json is not clearly
106 // defined at present. Temporarily disable check of this field.
109 if (type_ == Manifest::TYPE_PACKAGED_APP && GetManifestVersion() < 2) {
110 *error = errors::kPlatformAppNeedsManifestVersion2;
115 // TODO(xiang): support features validation
119 bool Manifest::HasKey(const std::string& key) const {
120 return CanAccessKey(key) && data_->HasKey(key);
123 bool Manifest::HasPath(const std::string& path) const {
124 base::Value* ignored = NULL;
125 return CanAccessPath(path) && data_->Get(path, &ignored);
129 const std::string& path, const base::Value** out_value) const {
130 return CanAccessPath(path) && data_->Get(path, out_value);
134 const std::string& path, base::Value** out_value) const {
137 const_cast<const base::Value**>(out_value));
140 bool Manifest::GetBoolean(
141 const std::string& path, bool* out_value) const {
142 return CanAccessPath(path) && data_->GetBoolean(path, out_value);
145 bool Manifest::GetInteger(
146 const std::string& path, int* out_value) const {
147 return CanAccessPath(path) && data_->GetInteger(path, out_value);
150 bool Manifest::GetString(
151 const std::string& path, std::string* out_value) const {
152 if (!CanAccessPath(path))
155 if (i18n_data_->Get(path, NULL)) {
156 List::const_iterator it = user_agent_locales_->begin();
157 for (; it != user_agent_locales_->end(); ++it) {
158 if (i18n_data_->GetString(GetLocalizedKey(path, *it), out_value))
164 return data_->GetString(path, out_value);
167 bool Manifest::GetString(
168 const std::string& path, base::string16* out_value) const {
169 if (!CanAccessPath(path))
172 if (i18n_data_->Get(path, NULL)) {
173 List::const_iterator it = user_agent_locales_->begin();
174 for (; it != user_agent_locales_->end(); ++it) {
175 if (i18n_data_->GetString(GetLocalizedKey(path, *it), out_value))
181 return data_->GetString(path, out_value);
184 bool Manifest::GetDictionary(
185 const std::string& path, const base::DictionaryValue** out_value) const {
186 return CanAccessPath(path) && data_->GetDictionary(path, out_value);
189 bool Manifest::GetList(
190 const std::string& path, const base::ListValue** out_value) const {
191 return CanAccessPath(path) && data_->GetList(path, out_value);
194 Manifest* Manifest::DeepCopy() const {
195 Manifest* manifest = new Manifest(
196 source_type_, scoped_ptr<base::DictionaryValue>(data_->DeepCopy()));
197 manifest->SetApplicationID(application_id_);
201 bool Manifest::Equals(const Manifest* other) const {
202 return other && data_->Equals(other->value());
205 int Manifest::GetManifestVersion() const {
206 int manifest_version = 1;
207 data_->GetInteger(keys::kManifestVersionKey, &manifest_version);
208 return manifest_version;
211 bool Manifest::CanAccessPath(const std::string& path) const {
215 bool Manifest::CanAccessKey(const std::string& key) const {
219 void Manifest::SetSystemLocale(const std::string& locale) {
220 scoped_ptr<List> list_for_expand(new List);
221 list_for_expand->push_back(locale);
222 list_for_expand->push_back(default_locale_);
223 list_for_expand->push_back(kLocaleUnlocalized);
224 list_for_expand->push_back(kLocaleAuto);
225 list_for_expand->push_back(kLocaleFirstOne);
226 user_agent_locales_ = ExpandUserAgentLocalesList(list_for_expand);
229 void Manifest::ParseWGTI18n() {
230 data_->GetString(application_widget_keys::kDefaultLocaleKey,
232 default_locale_ = StringToLowerASCII(default_locale_);
234 ParseWGTI18nEachPath(kWidgetNamePath);
235 ParseWGTI18nEachPath(kWidgetDecriptionPath);
236 ParseWGTI18nEachPath(kWidgetLicensePath);
239 // We might get one element of a list of element from path,
240 // and we parse each element for fast access.
241 // For example config.xml is:
243 // <name>unlocalized name</name>
244 // <name xml:lang="zh-CN">zh-CN name</name>
245 // <name xml:lang="en-US" short="en-US short">en-US name</name>
247 // The path for value in i18n_data_ are :
248 // "widget.name.#text.@unlocalized" => "unlocalized name".
249 // "widget.name.#text.zh-cn" => "zh-CN name".
250 // "widget.name.#text.en-us" => "en-US name".
251 // "widget.name.@short.en-us" => "en-US short".
252 // "widget.name.#text.*" => "unlocalized name". (the first one)
253 // "widget.name.@short.*" => "". (the first one do not have a short name)
254 void Manifest::ParseWGTI18nEachPath(const std::string& path) {
255 base::Value* value = NULL;
256 if (!data_->Get(path, &value))
259 if (value->IsType(base::Value::TYPE_DICTIONARY)) {
260 ParseWGTI18nEachElement(value, path);
261 ParseWGTI18nEachElement(value, path, kLocaleFirstOne);
262 } else if (value->IsType(base::Value::TYPE_LIST)) {
263 base::ListValue* list;
264 value->GetAsList(&list);
266 bool get_first_one = false;
267 for (base::ListValue::iterator it = list->begin();
268 it != list->end(); ++it) {
269 ParseWGTI18nEachElement(*it, path);
271 get_first_one = ParseWGTI18nEachElement(*it, path, kLocaleFirstOne);
276 bool Manifest::ParseWGTI18nEachElement(base::Value* value,
277 const std::string& path,
278 const std::string& locale) {
279 base::DictionaryValue* dict;
280 if (!value->GetAsDictionary(&dict))
283 std::string xml_lang(locale);
285 dict->GetString(application_widget_keys::kXmlLangKey, &xml_lang);
287 base::DictionaryValue::Iterator iter(*dict);
288 while (!iter.IsAtEnd()) {
289 std::string locale_key(
290 GetLocalizedKey(path + kPathConnectSymbol + iter.key(), xml_lang));
291 if (!i18n_data_->Get(locale_key, NULL))
292 i18n_data_->Set(locale_key, iter.value().DeepCopy());
300 } // namespace application