Upstream version 6.35.131.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / common / manifest.cc
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.
4
5 #include "xwalk/application/common/manifest.h"
6
7 #include <list>
8
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"
18
19 namespace errors = xwalk::application_manifest_errors;
20 namespace keys   = xwalk::application_manifest_keys;
21 namespace widget_keys = xwalk::application_widget_keys;
22
23 namespace xwalk {
24 namespace application {
25 namespace {
26 const char kLocaleUnlocalized[] = "@unlocalized";
27 #if defined(OS_TIZEN)
28 const char kLocaleAuto[] = "en-gb";
29 #else
30 const char kLocaleAuto[] = "en-us";
31 #endif
32 const char kLocaleFirstOne[] = "*";
33
34 const char kWidgetNamePath[] = "widget.name";
35 const char kWidgetDecriptionPath[] = "widget.description";
36 const char kWidgetLicensePath[] = "widget.license";
37
38 const char kPathConnectSymbol = '.';
39
40 typedef std::list<std::string> List;
41
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;
48 }
49
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);
54     size_t position;
55     do {
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);
60   }
61   return expansion_list.Pass();
62 }
63
64 }  // namespace
65
66 Manifest::Manifest(SourceType source_type,
67         scoped_ptr<base::DictionaryValue> value)
68     : source_type_(source_type),
69       data_(value.Pass()),
70       i18n_data_(new base::DictionaryValue),
71       type_(TYPE_UNKNOWN) {
72   if (data_->HasKey(keys::kAppKey)) {
73     if (data_->Get(keys::kWebURLsKey, NULL) ||
74         data_->Get(keys::kLaunchWebURLKey, NULL)) {
75       type_ = TYPE_HOSTED_APP;
76     } else if (data_->Get(keys::kAppMainKey, NULL) ||
77                data_->Get(keys::kLaunchLocalPathKey, NULL)) {
78       type_ = TYPE_PACKAGED_APP;
79     }
80   }
81
82   if (data_->HasKey(widget_keys::kWidgetKey) &&
83       data_->Get(widget_keys::kWidgetKey, NULL))
84     package_type_ = TYPE_WGT;
85   else
86     package_type_ = TYPE_XPK;
87
88   if (IsWGTPackaged())
89     ParseWGTI18n();
90
91   // Unittest may not have an xwalkrunner, so we should check here.
92   if (XWalkRunner* xwalk_runner = XWalkRunner::GetInstance())
93     SetSystemLocale(xwalk_runner->GetLocale());
94   else
95     SetSystemLocale(kLocaleUnlocalized);
96 }
97
98 Manifest::~Manifest() {
99 }
100
101 bool Manifest::ValidateManifest(
102     std::string* error,
103     std::vector<InstallWarning>* warnings) const {
104   // TODO(changbin): field 'manifest_version' of manifest.json is not clearly
105   // defined at present. Temporarily disable check of this field.
106   /*
107   *error = "";
108   if (type_ == Manifest::TYPE_PACKAGED_APP && GetManifestVersion() < 2) {
109     *error = errors::kPlatformAppNeedsManifestVersion2;
110     return false;
111   }
112   */
113
114   // TODO(xiang): support features validation
115   return true;
116 }
117
118 bool Manifest::HasKey(const std::string& key) const {
119   return CanAccessKey(key) && data_->HasKey(key);
120 }
121
122 bool Manifest::HasPath(const std::string& path) const {
123   base::Value* ignored = NULL;
124   return CanAccessPath(path) && data_->Get(path, &ignored);
125 }
126
127 bool Manifest::Get(
128     const std::string& path, const base::Value** out_value) const {
129   return CanAccessPath(path) && data_->Get(path, out_value);
130 }
131
132 bool Manifest::Get(
133     const std::string& path, base::Value** out_value) const {
134   return this->Get(
135       path,
136       const_cast<const base::Value**>(out_value));
137 }
138
139 bool Manifest::GetBoolean(
140     const std::string& path, bool* out_value) const {
141   return CanAccessPath(path) && data_->GetBoolean(path, out_value);
142 }
143
144 bool Manifest::GetInteger(
145     const std::string& path, int* out_value) const {
146   return CanAccessPath(path) && data_->GetInteger(path, out_value);
147 }
148
149 bool Manifest::GetString(
150     const std::string& path, std::string* out_value) const {
151   if (!CanAccessPath(path))
152     return false;
153
154   if (i18n_data_->Get(path, NULL)) {
155     List::const_iterator it = user_agent_locales_->begin();
156     for (; it != user_agent_locales_->end(); ++it) {
157       if (i18n_data_->GetString(GetLocalizedKey(path, *it), out_value))
158         return true;
159     }
160     return false;
161   }
162
163   return data_->GetString(path, out_value);
164 }
165
166 bool Manifest::GetString(
167     const std::string& path, base::string16* out_value) const {
168   if (!CanAccessPath(path))
169     return false;
170
171   if (i18n_data_->Get(path, NULL)) {
172     List::const_iterator it = user_agent_locales_->begin();
173     for (; it != user_agent_locales_->end(); ++it) {
174       if (i18n_data_->GetString(GetLocalizedKey(path, *it), out_value))
175         return true;
176     }
177     return false;
178   }
179
180   return data_->GetString(path, out_value);
181 }
182
183 bool Manifest::GetDictionary(
184     const std::string& path, const base::DictionaryValue** out_value) const {
185   return CanAccessPath(path) && data_->GetDictionary(path, out_value);
186 }
187
188 bool Manifest::GetList(
189     const std::string& path, const base::ListValue** out_value) const {
190   return CanAccessPath(path) && data_->GetList(path, out_value);
191 }
192
193 Manifest* Manifest::DeepCopy() const {
194   Manifest* manifest = new Manifest(
195       source_type_, scoped_ptr<base::DictionaryValue>(data_->DeepCopy()));
196   manifest->SetApplicationID(application_id_);
197   return manifest;
198 }
199
200 bool Manifest::Equals(const Manifest* other) const {
201   return other && data_->Equals(other->value());
202 }
203
204 int Manifest::GetManifestVersion() const {
205   int manifest_version = 1;
206   data_->GetInteger(keys::kManifestVersionKey, &manifest_version);
207   return manifest_version;
208 }
209
210 bool Manifest::CanAccessPath(const std::string& path) const {
211   return true;
212 }
213
214 bool Manifest::CanAccessKey(const std::string& key) const {
215   return true;
216 }
217
218 void Manifest::SetSystemLocale(const std::string& locale) {
219   scoped_ptr<List> list_for_expand(new List);
220   list_for_expand->push_back(locale);
221   list_for_expand->push_back(default_locale_);
222   list_for_expand->push_back(kLocaleUnlocalized);
223   list_for_expand->push_back(kLocaleAuto);
224   list_for_expand->push_back(kLocaleFirstOne);
225   user_agent_locales_ = ExpandUserAgentLocalesList(list_for_expand);
226 }
227
228 void Manifest::ParseWGTI18n() {
229   data_->GetString(application_widget_keys::kDefaultLocaleKey,
230                    &default_locale_);
231   default_locale_ = StringToLowerASCII(default_locale_);
232
233   ParseWGTI18nEachPath(kWidgetNamePath);
234   ParseWGTI18nEachPath(kWidgetDecriptionPath);
235   ParseWGTI18nEachPath(kWidgetLicensePath);
236 }
237
238 // We might get one element of a list of element from path,
239 // and we parse each element for fast access.
240 // For example config.xml is:
241 // <widget>
242 //   <name>unlocalized name</name>
243 //   <name xml:lang="zh-CN">zh-CN name</name>
244 //   <name xml:lang="en-US" short="en-US short">en-US name</name>
245 // </widget>
246 // The path for value in i18n_data_ are :
247 // "widget.name.#text.@unlocalized" => "unlocalized name".
248 // "widget.name.#text.zh-cn" => "zh-CN name".
249 // "widget.name.#text.en-us" => "en-US name".
250 // "widget.name.@short.en-us" => "en-US short".
251 // "widget.name.#text.*" => "unlocalized name". (the first one)
252 // "widget.name.@short.*" => "". (the first one do not have a short name)
253 void Manifest::ParseWGTI18nEachPath(const std::string& path) {
254   base::Value* value = NULL;
255   if (!data_->Get(path, &value))
256     return;
257
258   if (value->IsType(base::Value::TYPE_DICTIONARY)) {
259     ParseWGTI18nEachElement(value, path);
260     ParseWGTI18nEachElement(value, path, kLocaleFirstOne);
261   } else if (value->IsType(base::Value::TYPE_LIST)) {
262     base::ListValue* list;
263     value->GetAsList(&list);
264
265     bool get_first_one = false;
266     for (base::ListValue::iterator it = list->begin();
267         it != list->end(); ++it) {
268       ParseWGTI18nEachElement(*it, path);
269       if (!get_first_one)
270         get_first_one = ParseWGTI18nEachElement(*it, path, kLocaleFirstOne);
271     }
272   }
273   // After Parse we remove this path from data_ for saving memory.
274   scoped_ptr<base::Value> remove_value;
275   data_->Remove(path, &remove_value);
276 }
277
278 bool Manifest::ParseWGTI18nEachElement(base::Value* value,
279                                        const std::string& path,
280                                        const std::string& locale) {
281   base::DictionaryValue* dict;
282   if (!value->GetAsDictionary(&dict))
283     return false;
284
285   std::string xml_lang(locale);
286   if (locale.empty())
287     dict->GetString(application_widget_keys::kXmlLangKey, &xml_lang);
288
289   base::DictionaryValue::Iterator iter(*dict);
290   while (!iter.IsAtEnd()) {
291     std::string locale_key(
292         GetLocalizedKey(path + kPathConnectSymbol + iter.key(), xml_lang));
293     if (!i18n_data_->Get(locale_key, NULL))
294       i18n_data_->Set(locale_key, iter.value().DeepCopy());
295
296     iter.Advance();
297   }
298
299   return true;
300 }
301
302 }  // namespace application
303 }  // namespace xwalk