Update privilege string, PackageAppInfo for wgt
[platform/framework/native/appfw.git] / src / app / FApp_AppResourceString.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 /**
19  * @file        FApp_AppResourceString.cpp
20  * @brief       This is the implementation for the _AppResourceString class.
21  */
22
23 #include <libxml/parser.h>
24 #include <libxml/xpath.h>
25 #include <libxml/tree.h>
26 #include <unicode/locid.h>
27
28 #include <unique_ptr.h>
29 #include <runtime_info.h>
30
31 #include <FBaseResult.h>
32 #include <FBaseSysLog.h>
33 #include <FBase_StringConverter.h>
34 #include <FBaseColHashMap.h>
35
36 #include <FIoFile.h>
37 #include <FIoDirectory.h>
38
39 #include <FApp_AppInfo.h>
40 #include <FAppPkgPackageInfo.h>
41 #include "FAppPkg_PackageManagerImpl.h"
42 #include "FAppPkg_PackageInfoImpl.h"
43
44 #include "FApp_AppResourceImpl.h"
45 #include "FApp_AppResourceString.h"
46
47 using namespace Tizen::App::Package;
48 using namespace Tizen::Base;
49 using namespace Tizen::Base::Collection;
50 using namespace Tizen::Io;
51
52 static const char* AR_ROOT_NODE_NAME = "string_table";
53 static const char* AR_CHILD_NODE_1 = "text";
54 static const char* AR_ATTRIBUTE = "id";
55
56 struct FreeXmlDoc
57 {
58         void operator ()(_xmlDoc* p)
59         {
60                 if (p != null)
61                 {
62                         xmlFreeDoc(p);
63                 }
64         }
65 };
66
67 namespace Tizen { namespace App
68 {
69
70 _AppResourceString::_AppResourceString(void)
71         : __pDoc(null)
72         , __pLockOfParser(null)
73         , __pXmlNodeMap(null)
74 {
75 }
76
77 _AppResourceString::~_AppResourceString(void)
78 {
79         if (__pDoc != null)
80         {
81                 xmlFreeDoc(__pDoc);
82         }
83         if (__pXmlNodeMap)
84         {
85                 __pXmlNodeMap->RemoveAll(true);
86                 delete __pXmlNodeMap;
87         }
88         delete __pLockOfParser;
89 }
90
91 // Exception: E_OUT_OF_MEMORY, E_APP_NOT_INSTALLED, E_SYSTEM
92 _AppResourceString*
93 _AppResourceString::Get_AppResourceStringN(int type, const Tizen::Base::String& value)
94 {
95         std::unique_ptr< _AppResourceString > pAppResourceString(new (std::nothrow) _AppResourceString);
96         SysTryReturn(NID_APP, pAppResourceString != null, null,
97                         E_OUT_OF_MEMORY, "[%s] Unable to allocate memory for _AppResourceString", GetErrorMessage(E_OUT_OF_MEMORY));
98
99         String resourceFolder;
100         switch(type)
101         {
102         case APP_RESOURCE_DEFAULT:
103         case APP_RESOURCE_BY_LIBRARY_NAME:
104         default:
105                 resourceFolder = _AppInfo::GetAppRootPath();
106                 resourceFolder.Append(L"res/");
107                 resourceFolder.Append(value);
108                 resourceFolder.Append(L"/");
109                 break;
110
111         case APP_RESOURCE_BY_APP_ID:
112                 std::unique_ptr< PackageInfo> pPkgInfo(_PackageManagerImpl::GetInstance()->GetPackageInfoN(value));
113                 SysTryReturn(NID_APP, pPkgInfo != null, null,
114                                 E_APP_NOT_INSTALLED, "[%s] Failed to get the package info", GetErrorMessage(E_APP_NOT_INSTALLED));
115
116                 _PackageInfoImpl* pPkgInfoImpl = _PackageInfoImpl::GetInstance(pPkgInfo.get());
117                 SysTryReturn(NID_APP, pPkgInfoImpl != null, null,
118                                 E_APP_NOT_INSTALLED, "[%s] Failed to get the package info impl", GetErrorMessage(E_APP_NOT_INSTALLED));
119
120                 resourceFolder = pPkgInfoImpl->GetAppRootPath();
121                 resourceFolder.Append(L"/res/");
122                 break;
123         }
124
125         result r = pAppResourceString->Initialize(resourceFolder);
126         SysTryReturn(NID_APP, !IsFailed(r), null,
127                                 r, "[%s] Failed to initialize AppResourceString", GetErrorMessage(r));
128
129         ClearLastResult();
130         return pAppResourceString.release();
131 }
132
133 result
134 _AppResourceString::Initialize(String& resourceFolder)
135 {
136         result r = E_SUCCESS;
137         if (__pLockOfParser == null)
138         {
139                 __pLockOfParser = new (std::nothrow) Tizen::Base::Runtime::Mutex();
140                 SysTryReturnResult(NID_APP, __pLockOfParser != null, E_OUT_OF_MEMORY, "Failed to initialize resource parser.");
141
142                 r = __pLockOfParser->Create();
143                 SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] Failed to Create Mutex.", GetErrorMessage(r));
144         }
145
146         r = __pLockOfParser->Acquire();
147         SysTryCatch(NID_APP, !IsFailed(r), r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to Acquire Mutex [%s].", GetErrorMessage(r));
148
149         r = InitializeStringInfo(resourceFolder);
150         __pLockOfParser->Release();
151
152         SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] Failed to InitializeStringInfo.", GetErrorMessage(r));
153         return E_SUCCESS;
154
155 CATCH:
156         delete __pLockOfParser;
157         __pLockOfParser = null;
158
159         return r;
160 }
161
162 result
163 _AppResourceString::InitializeStringInfo(String& resourceFolder)
164 {
165         char* pValue = null;
166         int ret = runtime_info_get_value_string(RUNTIME_INFO_KEY_LANGUAGE, &pValue);
167         SysTryReturnResult(NID_APP, ret == 0, E_SYSTEM, "runtime_info_get_value_string returns %d.", ret);
168
169         U_ICU_NAMESPACE::Locale icuLcl(pValue);
170         String language(icuLcl.getISO3Language());
171         String country(icuLcl.getCountry());
172
173         String resFilename;
174         result r = resFilename.Format(256 * 2 + 10, L"%ls-%ls.xml", language.GetPointer(), country.GetPointer());
175         SysTryReturn(NID_APP, !IsFailed(r), E_SYSTEM, r, "[E_SYSTEM] Failed to format path string [%s]", GetErrorMessage(r));
176
177         if (!resourceFolder.EndsWith(L'/'))
178         {
179                 resourceFolder.Append(L'/');
180         }
181
182         std::unique_ptr< _xmlDoc, FreeXmlDoc > pDoc(ParseXmlFile(resourceFolder + resFilename));
183         if (pDoc == null)
184         {
185                 // open directory
186                 Directory dir;
187                 r = dir.Construct(resourceFolder);
188                 if (r == E_SUCCESS)
189                 {
190                         // read all directory entries
191                         DirEnumerator* pDirEnum = dir.ReadN();
192                         if (pDirEnum != null)
193                         {
194                                 const String starts = language + L"-";
195                                 const String ends = L".xml";
196
197                                 // loop through all directory entries
198                                 while (pDirEnum->MoveNext() == E_SUCCESS)
199                                 {
200                                         // get several properties of each directory entry.
201                                         resFilename = pDirEnum->GetCurrentDirEntry().GetName();
202                                         if (resFilename.StartsWith(starts, 0) && resFilename.EndsWith(ends))
203                                         {
204                                                 pDoc.reset(ParseXmlFile(resourceFolder + resFilename));
205                                                 break;
206                                         }
207                                 }
208                                 // Delete enumerator
209                                 delete pDirEnum;
210                         }
211                 }
212         }
213
214         if (pDoc == null)
215         {
216                 pDoc.reset(ParseXmlFile(resourceFolder + L"eng-GB.xml"));
217         }
218
219         if (pDoc == null)
220         {
221                 pDoc.reset(ParseXmlFile(resourceFolder + L"eng-US.xml"));
222         }
223
224         if (pDoc == null)
225         {
226                 pDoc.reset(ParseXmlFile(resourceFolder + L"English.xml"));
227         }
228
229         SysTryLogReturn(NID_APP, pDoc != null, E_SUCCESS, "Can't find xml resource file.");
230
231         xmlNodePtr cur = xmlDocGetRootElement(pDoc.get());
232         SysTryReturnResult(NID_APP, cur != null, E_SYSTEM, "Empty document.");
233
234         ret = xmlStrcmp(cur->name, (const xmlChar*) AR_ROOT_NODE_NAME);
235         SysTryReturnResult(NID_APP, ret == 0, E_SYSTEM, "Document root node is not <string_table>.");
236
237         std::unique_ptr< HashMap, AllElementsDeleter > pXmlNodeMap (new (std::nothrow) HashMap());
238         SysTryReturnResult(NID_APP, pXmlNodeMap != null, E_OUT_OF_MEMORY, " Memory allocation failed.");
239
240         r = pXmlNodeMap->Construct();
241         SysTryReturnResult(NID_APP, !IsFailed(r), E_SYSTEM, "Unable to construct xml node map [%s]", GetErrorMessage(r));
242
243         xmlChar* pxmlValue = null;
244         cur = cur->xmlChildrenNode;
245         while (cur != null)
246         {
247                 if ((!xmlStrcmp(cur->name, (const xmlChar*) AR_CHILD_NODE_1)))
248                 {
249                         pxmlValue = xmlGetProp(cur, (const xmlChar*) AR_ATTRIBUTE);
250                         if (cur->type == (xmlElementType)  XML_ELEMENT_NODE)
251                         {
252                                 xmlChar* pContent = xmlNodeListGetString( pDoc.get(), cur->xmlChildrenNode, 1);
253
254                                 std::unique_ptr< String > pKey(new (std::nothrow) String);
255                                 SysTryReturnResult(NID_APP, pKey != null, E_OUT_OF_MEMORY, " Memory allocation failed.");
256                                 Tizen::Base::Utility::StringUtil::Utf8ToString((char*) pxmlValue, *pKey);
257
258                                 std::unique_ptr< String > pValue(new (std::nothrow) String);
259                                 SysTryReturnResult(NID_APP, pValue != null, E_OUT_OF_MEMORY, " Memory allocation failed.");
260                                 Tizen::Base::Utility::StringUtil::Utf8ToString((char*) pContent, *pValue);
261
262                                 pXmlNodeMap->Add(*pKey, *pValue);
263                                 pKey.release();
264                                 pValue.release();
265                         }
266
267                 }
268                 cur =  cur->next;
269         }
270
271         if (__pDoc != null)
272         {
273                 xmlFreeDoc(__pDoc);
274                 __pDoc = null;
275         }
276
277         if (__pXmlNodeMap)
278         {
279                 __pXmlNodeMap->RemoveAll(true);
280                 delete __pXmlNodeMap;
281         }
282
283         __pDoc = pDoc.release();
284         __pXmlNodeMap = pXmlNodeMap.release();
285         return E_SUCCESS;
286 }
287
288 xmlDocPtr
289 _AppResourceString::ParseXmlFile(const String& path)
290 {
291         xmlDocPtr pDoc = null;
292         if (File::IsFileExist(path))
293         {
294                 std::unique_ptr<char[]> pBuf(_StringConverter::CopyToCharArrayN(path));
295                 pDoc = xmlParseFile(pBuf.get());
296         }
297         return pDoc;
298 }
299
300
301 result
302 _AppResourceString::GetString(const String resourceId, String& loadedString)
303 {
304 #if defined(ENABLE_XPATH)
305         SysTryReturnResult(NID_APP, __pDoc != null, E_FAILURE, "Can't find xml resource file.");
306
307         xmlXPathContextPtr __pXpathCtx = null;
308         xmlXPathObjectPtr __pXpathObj = null;
309
310         String key;
311         key.Format(1024, L"/string_table/text[@id='%ls']", resourceId.GetPointer());
312
313         xmlChar* pXpathExpr = (xmlChar*) (_StringConverter::CopyToCharArrayN(key));
314         xmlChar* pContent = null;
315         // Create xpath evaluation context
316         __pXpathCtx = xmlXPathNewContext(__pDoc);
317         if (__pXpathCtx == null)
318         {
319                 SysLogException(NID_APP, E_INVALID_STATE, "[E_INVALID_STATE] XPathNewContext must not be null.");
320
321                 delete[] pXpathExpr;
322                 return E_INVALID_STATE;
323         }
324
325         // Evaluate xpath expression
326         __pXpathObj = xmlXPathEvalExpression(pXpathExpr, __pXpathCtx);
327         if (null == __pXpathObj ||
328                 null == __pXpathObj->nodesetval ||
329                 null == __pXpathObj->nodesetval->nodeTab ||
330                 null == __pXpathObj->nodesetval->nodeTab[0]->children
331                 )
332         {
333                 SysLog(NID_APP, "xpath expression is invalid.");
334
335                 xmlXPathFreeContext(__pXpathCtx);
336                 __pXpathCtx = null;
337                 delete[] pXpathExpr;
338                 return E_INVALID_ARG;
339         }
340         delete[] pXpathExpr;
341
342         pContent = __pXpathObj->nodesetval->nodeTab[0]->children->content;
343         loadedString = String((char*) pContent);
344
345         SysLog(NID_APP, "content : %s.", pContent);
346
347         // file close & open
348         // Cleanup of XPath data
349         xmlXPathFreeObject(__pXpathObj);
350         __pXpathObj = null;
351         xmlXPathFreeContext(__pXpathCtx);
352         __pXpathCtx = null;
353
354         SysLog(NID_APP, "Free xpath data.");
355
356         return E_SUCCESS;
357
358 #else
359         SysTryReturnResult(NID_APP, !resourceId.IsEmpty(), E_INVALID_ARG, "Wrong resource Id.");
360         SysTryReturnResult(NID_APP, __pDoc != null, E_FAILURE, "Application string resource was not initialized.");
361         SysTryReturnResult(NID_APP, __pLockOfParser != null, E_FAILURE, "__pLockOfParser was not initialized.");
362
363         result r = __pLockOfParser->Acquire();
364         SysTryReturnResult(NID_APP, !IsFailed(r), E_FAILURE, "Failed to Acquire Mutex [%s].", GetErrorMessage(r));
365
366         String* pkeyValue = static_cast< String* > (__pXmlNodeMap->GetValue(resourceId));
367         r = E_FAILURE; //GetLastResult();
368         if (pkeyValue)
369         {
370                 loadedString = *pkeyValue;
371                 if (HasSpecialString(loadedString))
372                 {
373                         String rawString(loadedString);
374                         ConvertToCstyleString(rawString, loadedString);
375                 }
376                 r = E_SUCCESS;
377         }
378
379         __pLockOfParser->Release();
380         return r;
381 #endif
382 }
383
384
385 bool
386 _AppResourceString::HasSpecialString(const String& resourceStr)
387 {
388         int foundIndex = 0;
389         return((resourceStr.IndexOf("&lt;", 0, foundIndex) == E_SUCCESS)
390                 || (resourceStr.IndexOf("&amp;", 0, foundIndex) == E_SUCCESS)
391                 || (resourceStr.IndexOf("&gt;", 0, foundIndex) == E_SUCCESS)
392                 || (resourceStr.IndexOf("&apos;", 0, foundIndex) == E_SUCCESS)
393                 || (resourceStr.IndexOf("&quot", 0, foundIndex) == E_SUCCESS)
394                 || (resourceStr.IndexOf("&amp;", 0, foundIndex) == E_SUCCESS)
395                 || (resourceStr.IndexOf("\\", 0, foundIndex) == E_SUCCESS));
396 }
397
398
399 result
400 _AppResourceString::ConvertToCstyleString(const String& resourceStr, String& convertedStr)
401 {
402         SysTryReturnResult(NID_APP, resourceStr.GetLength() > 0, E_INVALID_ARG, "resource string must be greater than 0.");
403
404         std::unique_ptr<char[]> pBuffer(_StringConverter::CopyToCharArrayN(resourceStr));
405         SysTryReturnResult(NID_APP, pBuffer != null, E_OUT_OF_MEMORY, "Memory allocation failure.");
406
407         int i = 0;
408         int j = 0;
409         int len = strlen(pBuffer.get());//      len = String_length((MString)pBuffer);
410         while (i < len)
411         {
412                 if (pBuffer[i] == '\\')
413                 {
414                         if (pBuffer[i + 1] == 'n')
415                         {
416                                 pBuffer[j] = '\n';
417                                 i += 2;
418                                 j++;
419                         }
420                         else if (pBuffer[i + 1] == 't')
421                         {
422                                 pBuffer[j] = '\t';
423                                 i += 2;
424                                 j++;
425                         }
426                         else if (pBuffer[i + 1] == '\\')
427                         {
428                                 pBuffer[j] = '\\';
429                                 i += 2;
430                                 j++;
431                         }
432                         else
433                         {
434                                 i++;
435                         }
436                 }
437                 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'l') && (pBuffer[i + 2] == 't') &&
438                                  (pBuffer[i + 3] == ';'))
439                 {
440                         pBuffer[j] = '<';
441                         i += 4;
442                         j++;
443                 }
444                 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'g') && (pBuffer[i + 2] == 't') &&
445                                  (pBuffer[i + 3] == ';'))
446                 {
447                         pBuffer[j] = '>';
448                         i += 4;
449                         j++;
450                 }
451                 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'a') && (pBuffer[i + 2] == 'm') &&
452                                  (pBuffer[i + 3] == 'p') && (pBuffer[i + 4] == ';'))
453                 {
454                         pBuffer[j] = '&';
455                         i += 5;
456                         j++;
457                 }
458                 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'a') && (pBuffer[i + 2] == 'p') &&
459                                  (pBuffer[i + 3] == 'o') && (pBuffer[i + 4] == 's') && (pBuffer[i + 5] == ';'))
460                 {
461                         pBuffer[j] = 39; // '
462                         i += 6;
463                         j++;
464                 }
465                 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'q') && (pBuffer[i + 2] == 'u') &&
466                                  (pBuffer[i + 3] == 'o') && (pBuffer[i + 4] == 't') && (pBuffer[i + 5] == ';'))
467                 {
468                         pBuffer[j] = 34; // "
469                         i += 6;
470                         j++;
471                 }
472                 else
473                 {
474                         pBuffer[j] = pBuffer[i];
475                         i++;
476                         j++;
477                 }
478         }
479         if (j != i)
480         {
481                 for (; j <= i; j++)
482                 {
483                         pBuffer[j] = '\0';
484                 }
485         }
486
487         convertedStr = pBuffer.get();
488         return E_SUCCESS;
489 }
490
491
492 } } // Tizen::App