URL localization fix
[platform/framework/web/wrt-commons.git] / modules / localization / src / w3c_file_localization.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file    w3c_file_localization.cpp
18  * @author  Lukasz Wrzosek (l.wrzosek@samsung.com)
19  * @version 1.0
20  */
21 #include <stddef.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25 #include <assert.h>
26
27 #include <dpl/localization/w3c_file_localization.h>
28
29 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
30 #include <dpl/localization/localization_utils.h>
31
32 #include <dpl/log/log.h>
33 #include <dpl/string.h>
34 #include <dpl/optional.h>
35 #include <dpl/foreach.h>
36
37 #include <LanguageTagsProvider.h>
38
39 using namespace WrtDB;
40
41 namespace {
42 const DPL::String FILE_URI_BEGIN = L"file://";
43 const DPL::String WIDGET_URI_BEGIN = L"widget://";
44 const DPL::String APP_URI_BEGIN = L"app://";
45 const DPL::String LOCALE_PREFIX = L"locales/";
46
47 DPL::Optional<std::string> GetFilePathInWidgetPackageInternal(
48     const std::string& basePath,
49     std::string filePath)
50 {
51     LogDebug("Looking for file: " << filePath << "  in: " << basePath);
52
53     const LanguageTags& ltags =
54         LanguageTagsProviderSingleton::Instance().getLanguageTags();
55
56     //Check if string isn't empty
57     if (filePath.size() == 0) {
58         return DPL::Optional<std::string>::Null;
59     }
60     //Removing preceding '/'
61     if (filePath[0] == '/') {
62         filePath.erase(0, 1);
63     }
64     // In some cases (start file localization) url has unnecessary "/" at the
65     // end
66     if (filePath[filePath.size() - 1] == '/') {
67         filePath.erase(filePath.size() - 1, 1);
68     }
69     //Check if string isn't empty
70     if (filePath.size() == 0) {
71         return DPL::Optional<std::string>::Null;
72     }
73
74     LogDebug("locales size = " << ltags.size());
75     for (LanguageTags::const_iterator it = ltags.begin();
76          it != ltags.end();
77          ++it)
78     {
79         LogDebug("Trying locale: " << *it);
80         std::string path = basePath;
81         if (path[path.size() - 1] == '/') {
82             path.erase(path.size() - 1);
83         }
84
85         if (it->empty()) {
86             path += "/" + filePath;
87         } else {
88             path += "/locales/" + DPL::ToUTF8String(*it) + "/" + filePath;
89         }
90
91         LogDebug("Trying locale: " << *it << " | " << path);
92         struct stat buf;
93         if (0 == stat(path.c_str(), &buf)) {
94             if ((buf.st_mode & S_IFMT) == S_IFREG) {
95                 path.erase(0, basePath.length());
96                 return DPL::Optional<std::string>(path);
97             }
98         }
99     }
100
101     return DPL::Optional<std::string>::Null;
102 }
103
104 DPL::Optional<DPL::String> GetFilePathInWidgetPackageInternal(
105     const DPL::String& basePath,
106     const DPL::String& filePath)
107 {
108     DPL::Optional<std::string> path =
109         GetFilePathInWidgetPackageInternal(DPL::ToUTF8String(basePath),
110                                            DPL::ToUTF8String(filePath));
111     DPL::Optional<DPL::String> dplPath;
112     if (!!path) {
113         dplPath = DPL::FromUTF8String(*path);
114     }
115     return dplPath;
116 }
117 }
118
119 namespace W3CFileLocalization {
120 DPL::Optional<DPL::String> getFilePathInWidgetPackageFromUrl(
121     DbWidgetHandle widgetHandle,
122     const DPL::String &url)
123 {
124     return getFilePathInWidgetPackageFromUrl(
125                WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(widgetHandle)),
126                url);
127 }
128
129 DPL::Optional<DPL::String> getFilePathInWidgetPackageFromUrl(
130     const WrtDB::WidgetPkgName &pkgname,
131     const DPL::String &url)
132 {
133     return getFilePathInWidgetPackageFromUrl(
134                WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(pkgname)),
135                url);
136 }
137
138 DPL::Optional<DPL::String> getFilePathInWidgetPackageFromUrl(
139     WrtDB::WidgetDAOReadOnlyPtr dao,
140     const DPL::String &url)
141 {
142     DPL::String req = url;
143
144     DPL::String::size_type pos = req.find_first_of('#');
145     if(pos != DPL::String::npos)
146     {
147         req.resize(pos); //truncate fragment identifier
148     }
149
150     pos = req.find_first_of('?');
151     if(pos != DPL::String::npos)
152     {
153         req.resize(pos); //truncate query string
154     }
155
156     if (req.find(WIDGET_URI_BEGIN) == 0) {
157         req.erase(0, WIDGET_URI_BEGIN.length());
158     } else if (req.find(FILE_URI_BEGIN) == 0) {
159         req.erase(0, FILE_URI_BEGIN.length());
160         if (req.find(dao->getPath()) == 0) {
161             req.erase(0, dao->getPath().length());
162         }
163         if (req.find(LOCALE_PREFIX) == 0) {
164             req.erase(0, LOCALE_PREFIX.length());
165             size_t position = req.find('/');
166             // should always be >0 as correct locales path is
167             // always locales/xx/ or locales/xx-XX/
168             if (position != std::string::npos && position > 0) {
169                 req.erase(0, position + 1);
170             }
171         }
172     } else if(req.find(APP_URI_BEGIN) == 0) {
173         req.erase(0, APP_URI_BEGIN.length());
174         DPL::String id = *dao->getTizenAppId();
175         if(req.substr(0, id.size()) != id)
176         {
177             LogError("Tizen id does not match, ignoring");
178             return DPL::Optional<DPL::String>::Null;
179         }
180         req.erase(0, id.length());
181     } else {
182         LogDebug("Unknown path format, ignoring");
183         return DPL::Optional<DPL::String>::Null;
184     }
185
186     auto widgetPath = dao->getPath();
187
188     LogDebug("Required path: " << req);
189     DPL::Optional<DPL::String> found =
190         GetFilePathInWidgetPackageInternal(widgetPath, req);
191
192     if (!found) {
193         LogError("Path not found within current locale in current widget");
194         return DPL::Optional<DPL::String>::Null;
195     }
196
197     found = widgetPath + *found;
198
199     return found;
200 }
201
202 DPL::Optional<DPL::String> getFilePathInWidgetPackage(
203     WrtDB::DbWidgetHandle widgetHandle,
204     const DPL::String& file)
205 {
206     return getFilePathInWidgetPackage(
207                WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(widgetHandle)),
208                file);
209 }
210
211 DPL::Optional<DPL::String> getFilePathInWidgetPackage(
212     const WrtDB::WidgetPkgName &pkgname,
213     const DPL::String& file)
214 {
215     return getFilePathInWidgetPackage(
216                WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(pkgname)),
217                file);
218 }
219
220 DPL::Optional<DPL::String> getFilePathInWidgetPackage(
221     WrtDB::WidgetDAOReadOnlyPtr dao,
222     const DPL::String& file)
223 {
224     return GetFilePathInWidgetPackageInternal(dao->getPath(), file);
225 }
226
227 DPL::OptionalString getStartFile(const WrtDB::WidgetPkgName & pkgname)
228 {
229     return getStartFile(WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(pkgname)));
230 }
231
232 DPL::OptionalString getStartFile(const WrtDB::DbWidgetHandle handle)
233 {
234     return getStartFile(WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(handle)));
235 }
236
237 DPL::OptionalString getStartFile(WrtDB::WidgetDAOReadOnlyPtr dao)
238 {
239     WidgetDAOReadOnly::LocalizedStartFileList locList =
240         dao->getLocalizedStartFileList();
241     WidgetDAOReadOnly::WidgetStartFileList list = dao->getStartFileList();
242     LanguageTags tagsList =
243         LanguageTagsProviderSingleton::Instance().getLanguageTags();
244
245     DPL::OptionalString defaultLoc = dao->getDefaultlocale();
246     if (!!defaultLoc) {
247         tagsList.push_back(*defaultLoc);
248     }
249
250     FOREACH(tag, tagsList)
251     {
252         FOREACH(sFile, locList)
253         {
254             if (*tag == sFile->widgetLocale) {
255                 FOREACH(it, list)
256                 {
257                     if (it->startFileId == sFile->startFileId) {
258                         return it->src;
259                     }
260                 }
261             }
262         }
263     }
264
265     return DPL::OptionalString::Null;
266 }
267
268 OptionalWidgetIcon getIcon(const WrtDB::WidgetPkgName & pkgname)
269 {
270     return getIcon(WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(pkgname)));
271 }
272
273 OptionalWidgetIcon getIcon(WrtDB::DbWidgetHandle widgetHandle)
274 {
275     return getIcon(WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(widgetHandle)));
276 }
277
278 OptionalWidgetIcon getIcon(WrtDB::WidgetDAOReadOnlyPtr dao)
279 {
280     WidgetDAOReadOnly::WidgetLocalizedIconList locList =
281         dao->getLocalizedIconList();
282     WidgetDAOReadOnly::WidgetIconList list = dao->getIconList();
283     LanguageTags tagsList =
284         LanguageTagsProviderSingleton::Instance().getLanguageTags();
285
286     DPL::OptionalString defaultLoc = dao->getDefaultlocale();
287     if (!!defaultLoc) {
288         tagsList.push_back(*defaultLoc);
289     }
290
291     FOREACH(tag, tagsList)
292     {
293         FOREACH(icon, locList)
294         {
295             if (*tag == icon->widgetLocale) {
296                 FOREACH(it, list)
297                 {
298                     if (it->iconId == icon->iconId) {
299                         WidgetIcon ret;
300                         ret.src = it->iconSrc;
301                         ret.width = it->iconWidth;
302                         ret.height = it->iconHeight;
303                         return ret;
304                     }
305                 }
306             }
307         }
308     }
309
310     return OptionalWidgetIcon::Null;
311 }
312
313 WidgetIconList getValidIconsList(WrtDB::DbWidgetHandle widgetHandle)
314 {
315     return getValidIconsList(
316                WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(widgetHandle)));
317 }
318
319 WidgetIconList getValidIconsList(const WrtDB::WidgetPkgName &pkgname)
320 {
321     return getValidIconsList(
322                WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(pkgname)));
323 }
324
325 WidgetIconList getValidIconsList(WrtDB::WidgetDAOReadOnlyPtr dao)
326 {
327     WidgetDAOReadOnly::WidgetIconList list = dao->getIconList();
328
329     WidgetIconList outlist;
330
331     FOREACH(it, list)
332     {
333         LogDebug(":" << it->iconSrc);
334         if (!!getFilePathInWidgetPackage(dao->getHandle(),
335                                          it->iconSrc))
336         {
337             WidgetIcon ret;
338             ret.src = it->iconSrc;
339             ret.width = it->iconWidth;
340             ret.height = it->iconHeight;
341             outlist.push_back(ret);
342         }
343     }
344     return outlist;
345 }
346
347 OptionalWidgetStartFileInfo getStartFileInfo(WrtDB::DbWidgetHandle widgetHandle)
348 {
349     return getStartFileInfo(
350                WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(widgetHandle)));
351 }
352
353 OptionalWidgetStartFileInfo getStartFileInfo(
354     const WrtDB::WidgetPkgName &pkgname)
355 {
356     return getStartFileInfo(
357                WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(pkgname)));
358 }
359
360 OptionalWidgetStartFileInfo getStartFileInfo(WrtDB::WidgetDAOReadOnlyPtr dao)
361 {
362     WidgetStartFileInfo info;
363
364     WidgetDAOReadOnly::LocalizedStartFileList locList =
365         dao->getLocalizedStartFileList();
366     WidgetDAOReadOnly::WidgetStartFileList list = dao->getStartFileList();
367     const LanguageTags tagsList =
368         LanguageTagsProviderSingleton::Instance().getLanguageTags();
369
370     FOREACH(tag, tagsList)
371     {
372         FOREACH(sFile, locList)
373         {
374             if (*tag == sFile->widgetLocale) {
375                 FOREACH(it, list)
376                 {
377                     if (it->startFileId ==
378                         sFile->startFileId)
379                     {
380                         info.file = it->src;
381                         info.encoding = sFile->encoding;
382                         info.type = sFile->type;
383                         if (tag->empty()) {
384                             info.localizedPath = it->src;
385                         } else {
386                             info.localizedPath = L"locales/" + *tag + L"/";
387                             info.localizedPath += it->src;
388                         }
389                         return info;
390                     }
391                 }
392             }
393         }
394     }
395
396     return OptionalWidgetStartFileInfo::Null;
397 }
398
399 WidgetLocalizedInfo getLocalizedInfo(const WrtDB::DbWidgetHandle handle)
400 {
401     return getLocalizedInfo(WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(handle)));
402 }
403
404 WidgetLocalizedInfo getLocalizedInfo(const WrtDB::WidgetPkgName & pkgname)
405 {
406     return getLocalizedInfo(WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(pkgname)));
407 }
408
409 WidgetLocalizedInfo getLocalizedInfo(WidgetDAOReadOnlyPtr dao)
410 {
411     LanguageTags languages =
412         LanguageTagsProviderSingleton::Instance().getLanguageTags();
413     DPL::OptionalString dl = dao->getDefaultlocale();
414     if (!!dl) {
415         languages.push_back(*dl);
416     }
417
418     WidgetLocalizedInfo result;
419     FOREACH(i, languages)
420     {
421         WidgetLocalizedInfo languageResult = dao->getLocalizedInfo(*i);
422
423 #define OVERWRITE_IF_NULL(FIELD) if (!result.FIELD) { \
424         result.FIELD = languageResult.FIELD; \
425 }
426
427         OVERWRITE_IF_NULL(name);
428         OVERWRITE_IF_NULL(shortName);
429         OVERWRITE_IF_NULL(description);
430         OVERWRITE_IF_NULL(license);
431         OVERWRITE_IF_NULL(licenseHref);
432
433 #undef OVERWRITE_IF_NULL
434     }
435
436     return result;
437 }
438 }