2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
9 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 * @file FApp_AppResourceString.cpp
20 * @brief This is the implementation for the _AppResourceString class.
23 #include <libxml/parser.h>
24 #include <libxml/xpath.h>
25 #include <libxml/tree.h>
26 #include <unique_ptr.h>
27 #include <runtime_info.h>
28 #include <unicode/locid.h>
30 #include <FBaseObject.h>
31 #include <FBaseString.h>
32 #include <FBaseResult.h>
34 #include <FIoDirectory.h>
35 #include <FSysSystemInfo.h>
36 #include <FSys_SettingInfoImpl.h>
38 #include <FBaseSysLog.h>
39 #include <FAppPkgPackageManager.h>
40 #include <FAppPkgPackageInfo.h>
41 #include <FBase_StringConverter.h>
42 #include <FApp_AppInfo.h>
44 #include "FApp_AppResourceString.h"
45 #include "FAppPkg_PackageManagerImpl.h"
46 #include "FAppPkg_PackageInfoImpl.h"
48 using namespace Tizen::App::Package;
49 using namespace Tizen::Base;
50 using namespace Tizen::Io;
51 using namespace Tizen::Locales;
52 using namespace Tizen::System;
54 static const char* AR_ROOT_NODE_NAME = "string_table";
55 static const char* AR_CHILD_NODE_1 = "text";
56 static const char* AR_ATTRIBUTE = "id";
58 static xmlNodePtr gCur = 0;
60 namespace Tizen { namespace App
63 _AppResourceString::_AppResourceString(void)
65 , __pLockOfParser(null)
71 _AppResourceString::Construct(const Tizen::Locales::Locale& locale)
78 _AppResourceString::Construct(void)
84 _AppResourceString::Construct(const AppId& appId)
86 return Initialize(appId);
90 _AppResourceString::Initialize(void)
93 if (__pLockOfParser == null)
95 __pLockOfParser = new (std::nothrow) Tizen::Base::Runtime::Mutex();
96 SysTryReturnResult(NID_APP, __pLockOfParser != null, E_OUT_OF_MEMORY, "Failed to initialize resource parser.");
98 r = __pLockOfParser->Create();
99 SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] Failed to Create Mutex.", GetErrorMessage(r));
103 r = __pLockOfParser->Acquire();
104 SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] Failed to Acquire Mutex.", GetErrorMessage(r));
106 r = InitializeStringInfo();
107 SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] Failed to InitializeStringInfo.", GetErrorMessage(r));
109 __pLockOfParser->Release();
113 delete __pLockOfParser;
114 __pLockOfParser = null;
120 _AppResourceString::Initialize(const AppId& appId)
122 result r = E_SUCCESS;
123 if (__pLockOfParser == null)
125 __pLockOfParser = new (std::nothrow) Tizen::Base::Runtime::Mutex();
126 SysTryReturnResult(NID_APP, __pLockOfParser != null, E_OUT_OF_MEMORY, "Failed to initialize resource parser.");
128 r = __pLockOfParser->Create();
129 SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] Failed to Create Mutex.", GetErrorMessage(r));
132 r = __pLockOfParser->Acquire();
133 SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] Failed to Acquire Mutex.", GetErrorMessage(r));
135 r = InitializeStringInfo(appId);
136 SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] Failed to InitializeStringInfo.", GetErrorMessage(r));
138 __pLockOfParser->Release();
142 delete __pLockOfParser;
143 __pLockOfParser = null;
151 _AppResourceString::InitializeStringInfo(void)
155 SysLog(NID_APP, "__pDoc is freed to reinitialize.");
161 int ret = runtime_info_get_value_string(RUNTIME_INFO_KEY_LANGUAGE, &pValue);
162 SysTryReturnResult(NID_APP, ret == 0, E_FAILURE, "[E_SYSTEM] runtime_info_get_value_string returns %d.", ret);
164 U_ICU_NAMESPACE::Locale icuLcl(pValue);
166 String language(icuLcl.getISO3Language());
167 String country(icuLcl.getCountry());
169 // SysLog(NID_APP, "res/%ls-%ls.xml", language.GetPointer(), country.GetPointer());
172 result r = resFilename.Format(256 * 2 + 10, L"res/%ls-%ls.xml", language.GetPointer(), country.GetPointer());
173 SysTryReturn(NID_APP, !IsFailed(r), E_FAILURE, r, "[%s] Failed to format path string", GetErrorMessage(r));
175 const String& homePath = _AppInfo::GetAppRootPath();
176 __pDoc = ParseXmlFile( homePath + resFilename);
181 String dirName(L"res/");
183 DirEnumerator* pDirEnum = null;
186 r = dirName.Insert(homePath, 0);
187 SysTryReturn(NID_APP, !IsFailed(r), E_FAILURE, r, "[%s] Failed to insert string.", GetErrorMessage(r));
190 r = dir.Construct(dirName);
193 // read all directory entries
194 pDirEnum = dir.ReadN();
195 if (pDirEnum != null)
197 const String starts = language + L"-";
198 const String ends = L".xml";
200 // loop through all directory entries
201 while (pDirEnum->MoveNext() == E_SUCCESS)
203 // get several properties of each directory entry.
204 name = pDirEnum->GetCurrentDirEntry().GetName();
206 if (name.StartsWith(starts, 0) && name.EndsWith(ends))
208 resFilename = L"res/" + name;
209 __pDoc = ParseXmlFile(homePath + resFilename);
221 __pDoc = ParseXmlFile(homePath + L"res/eng-GB.xml");
226 __pDoc = ParseXmlFile(homePath + L"res/eng-US.xml");
231 __pDoc = ParseXmlFile(homePath + L"res/English.xml");
236 SysLog(NID_APP, "Can't find xml resource file.");
237 return E_SUCCESS; //E_FILE_NOT_FOUND;
240 xmlNodePtr cur = xmlDocGetRootElement(__pDoc);
241 SysTryReturnResult(NID_APP, cur != null, E_FAILURE, "Empty document.");
243 if (xmlStrcmp(cur->name, (const xmlChar*) AR_ROOT_NODE_NAME))
245 SysLogException(NID_APP, E_FAILURE, "[E_FAILURE] Document root node is not <string_table>.");
255 _AppResourceString::InitializeStringInfo(const AppId& appId)
259 SysLog(NID_APP, "__pDoc is freed to reinitialize.");
265 int ret = runtime_info_get_value_string(RUNTIME_INFO_KEY_LANGUAGE, &pValue);
266 SysTryReturnResult(NID_APP, ret == 0, E_FAILURE, "[E_SYSTEM] runtime_info_get_value_string returns %d.", ret);
269 U_ICU_NAMESPACE::Locale icuLcl(pValue);
271 String language(icuLcl.getISO3Language());
272 String country(icuLcl.getCountry());
274 // SysLog(NID_APP, "res/%ls-%ls.xml", language.GetPointer(), country.GetPointer());
277 result r = resFilename.Format(256 * 2 + 10, L"/res/%ls-%ls.xml", language.GetPointer(), country.GetPointer());
278 SysTryReturn(NID_APP, !IsFailed(r), E_FAILURE, r, "[%s] Failed to format path string", GetErrorMessage(r));
280 PackageInfo* pPkgInfo = null;
281 pPkgInfo = _PackageManagerImpl::GetInstance()->GetPackageInfoN(appId);
282 SysTryReturnResult(NID_APP, pPkgInfo != null, E_APP_NOT_INSTALLED, "Failed to get the package info");
284 _PackageInfoImpl* pPkgInfoImpl = _PackageInfoImpl::GetInstance(pPkgInfo);
285 SysTryReturnResult(NID_APP, pPkgInfoImpl != null, E_APP_NOT_INSTALLED, "Failed to get the package info impl");
287 const Tizen::Base::String& homePath = pPkgInfoImpl->GetAppRootPath();
289 __pDoc = ParseXmlFile( homePath + resFilename);
294 String dirName(L"/res/");
296 DirEnumerator* pDirEnum = null;
299 r = dirName.Insert(homePath, 0);
300 SysTryReturn(NID_APP, !IsFailed(r), E_FAILURE, r, "[%s] Failed to insert string.", GetErrorMessage(r));
303 r = dir.Construct(dirName);
306 // read all directory entries
307 pDirEnum = dir.ReadN();
308 if (pDirEnum != null)
310 const String starts = language + L"-";
311 const String ends = L".xml";
313 // loop through all directory entries
314 while (pDirEnum->MoveNext() == E_SUCCESS)
316 // get several properties of each directory entry.
317 name = pDirEnum->GetCurrentDirEntry().GetName();
319 if (name.StartsWith(starts, 0) && name.EndsWith(ends))
321 resFilename = L"/res/" + name;
322 __pDoc = ParseXmlFile(homePath + resFilename);
334 __pDoc = ParseXmlFile(homePath + L"/res/eng-GB.xml");
339 __pDoc = ParseXmlFile(homePath + L"/res/eng-US.xml");
344 __pDoc = ParseXmlFile(homePath + L"/res/English.xml");
349 SysLog(NID_APP, "Can't find xml resource file.");
350 return E_DATA_NOT_FOUND;
353 xmlNodePtr cur = xmlDocGetRootElement(__pDoc);
354 SysTryReturnResult(NID_APP, cur != null, E_FAILURE, "Empty document.");
356 if (xmlStrcmp(cur->name, (const xmlChar*) AR_ROOT_NODE_NAME))
358 SysLogException(NID_APP, E_FAILURE, "[E_FAILURE] Document root node is not <string_table>.");
369 _AppResourceString::ParseXmlFile(const String& path)
371 if (File::IsFileExist(path) == false )
373 SysLog(NID_APP, "'%ls' isn't exist.", path.GetPointer());
377 std::unique_ptr<char[]> pBuf(_StringConverter::CopyToCharArrayN(path));
378 xmlDocPtr docPtr = xmlParseFile(pBuf.get());
382 SysLog(NID_APP, "failed to parse resource file(%ls)", path.GetPointer());
386 SysLog(NID_APP, "'%ls' is parsed successfully.", path.GetPointer());
391 _AppResourceString::~_AppResourceString(void)
397 delete __pLockOfParser;
402 _AppResourceString::GetString(const String resourceId, String& loadedString)
404 SysTryReturnResult(NID_APP, __pDoc != null, E_INVALID_STATE, "Can't find xml resource file.");
406 #if defined(ENABLE_XPATH)
407 xmlXPathContextPtr __pXpathCtx = null;
408 xmlXPathObjectPtr __pXpathObj = null;
411 key.Format(1024, L"/string_table/text[@id='%ls']", resourceId.GetPointer());
413 xmlChar* pXpathExpr = (xmlChar*) (_StringConverter::CopyToCharArrayN(key));
414 xmlChar* pContent = null;
415 // Create xpath evaluation context
416 __pXpathCtx = xmlXPathNewContext(__pDoc);
417 if (__pXpathCtx == null)
419 SysLogException(NID_APP, E_INVALID_STATE, "[E_INVALID_STATE] XPathNewContext must not be null.");
422 return E_INVALID_STATE;
425 // Evaluate xpath expression
426 __pXpathObj = xmlXPathEvalExpression(pXpathExpr, __pXpathCtx);
427 if (null == __pXpathObj ||
428 null == __pXpathObj->nodesetval ||
429 null == __pXpathObj->nodesetval->nodeTab ||
430 null == __pXpathObj->nodesetval->nodeTab[0]->children
433 SysLog(NID_APP, "xpath expression is invalid.");
435 xmlXPathFreeContext(__pXpathCtx);
438 return E_INVALID_ARG;
442 pContent = __pXpathObj->nodesetval->nodeTab[0]->children->content;
443 loadedString = String((char*) pContent);
445 SysLog(NID_APP, "content : %s.", pContent);
448 // Cleanup of XPath data
449 xmlXPathFreeObject(__pXpathObj);
451 xmlXPathFreeContext(__pXpathCtx);
454 SysLog(NID_APP, "Free xpath data.");
459 xmlNodePtr cur = null;
460 xmlChar* pValue = null;
463 SysTryReturnResult(NID_APP, !resourceId.IsEmpty(), E_INVALID_ARG, "Wrong resource Id.");
464 SysTryReturnResult(NID_APP, gCur != null && __pDoc != null, E_INVALID_STATE,
465 "Application string resource was not initialized.");
466 SysTryReturnResult(NID_APP, __pLockOfParser != null, E_INVALID_STATE, "__pLockOfParser was not initialized.");
468 result r = __pLockOfParser->Acquire();
469 SysTryReturn(NID_APP, !IsFailed(r), r, r, "[%s] Failed to Acquire Mutex.", GetErrorMessage(r));
471 pId = (xmlChar*) (_StringConverter::CopyToCharArrayN(resourceId));
473 cur = cur->xmlChildrenNode;
476 if ((!xmlStrcmp(cur->name, (const xmlChar*) AR_CHILD_NODE_1)))
478 pValue = xmlGetProp(cur, (const xmlChar*) AR_ATTRIBUTE);
479 if (!xmlStrcmp(pValue, (const xmlChar*) pId))
481 xmlChar* pContent = xmlNodeListGetString( __pDoc, cur->xmlChildrenNode, 1);
482 SysLog(NID_APP, "xml content=%s", pContent);
483 loadedString = (char*) (pContent);
485 if (HasSpecialString(loadedString))
487 String rawString(loadedString);
488 ConvertToCstyleString(rawString, loadedString);
503 delete[] (char*) pId;
506 __pLockOfParser->Release();
519 delete[] (char*) pId;
522 __pLockOfParser->Release();
530 _AppResourceString::HasSpecialString(const String& resourceStr)
534 return((resourceStr.IndexOf("<", 0, foundIndex) == E_SUCCESS)
535 || (resourceStr.IndexOf("&", 0, foundIndex) == E_SUCCESS)
536 || (resourceStr.IndexOf(">", 0, foundIndex) == E_SUCCESS)
537 || (resourceStr.IndexOf("'", 0, foundIndex) == E_SUCCESS)
538 || (resourceStr.IndexOf(""", 0, foundIndex) == E_SUCCESS)
539 || (resourceStr.IndexOf("&", 0, foundIndex) == E_SUCCESS)
540 || (resourceStr.IndexOf("\\", 0, foundIndex) == E_SUCCESS));
545 _AppResourceString::ConvertToCstyleString(const String& resourceStr, String& convertedStr)
547 result r = E_SUCCESS;
553 SysTryReturnResult(NID_APP, resourceStr.GetLength() > 0, E_INVALID_ARG, "resource string must be greater than 0.");
555 std::unique_ptr<char[]> pBuffer(_StringConverter::CopyToCharArrayN(resourceStr));
556 // len = resourceStr.GetLength(); comment out because GetLength() returns UTF8 length.
557 SysTryReturnResult(NID_APP, pBuffer != null, E_OUT_OF_MEMORY, "Memory allocation failure.");
559 len = strlen(pBuffer.get());// len = String_length((MString)pBuffer);
563 if (pBuffer[i] == '\\')
565 if (pBuffer[i + 1] == 'n')
571 else if (pBuffer[i + 1] == 't')
577 else if (pBuffer[i + 1] == '\\')
588 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'l') && (pBuffer[i + 2] == 't') &&
589 (pBuffer[i + 3] == ';'))
595 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'g') && (pBuffer[i + 2] == 't') &&
596 (pBuffer[i + 3] == ';'))
602 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'a') && (pBuffer[i + 2] == 'm') &&
603 (pBuffer[i + 3] == 'p') && (pBuffer[i + 4] == ';'))
609 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'a') && (pBuffer[i + 2] == 'p') &&
610 (pBuffer[i + 3] == 'o') && (pBuffer[i + 4] == 's') && (pBuffer[i + 5] == ';'))
612 pBuffer[j] = 39; // '
616 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'q') && (pBuffer[i + 2] == 'u') &&
617 (pBuffer[i + 3] == 'o') && (pBuffer[i + 4] == 't') && (pBuffer[i + 5] == ';'))
619 pBuffer[j] = 34; // "
625 pBuffer[j] = pBuffer[i];
638 convertedStr = pBuffer.get();