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 <unicode/locid.h>
28 #include <unique_ptr.h>
29 #include <runtime_info.h>
31 #include <FBaseResult.h>
32 #include <FBaseSysLog.h>
33 #include <FBase_StringConverter.h>
34 #include <FBaseColHashMap.h>
37 #include <FIoDirectory.h>
39 #include <FApp_AppInfo.h>
40 #include <FAppPkgPackageInfo.h>
41 #include "FAppPkg_PackageManagerImpl.h"
42 #include "FAppPkg_PackageInfoImpl.h"
44 #include "FApp_AppResourceImpl.h"
45 #include "FApp_AppResourceString.h"
47 using namespace Tizen::App::Package;
48 using namespace Tizen::Base;
49 using namespace Tizen::Base::Collection;
50 using namespace Tizen::Io;
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";
58 void operator ()(_xmlDoc* p)
67 namespace Tizen { namespace App
70 _AppResourceString::_AppResourceString(void)
72 , __pLockOfParser(null)
77 _AppResourceString::~_AppResourceString(void)
85 __pXmlNodeMap->RemoveAll(true);
88 delete __pLockOfParser;
91 // Exception: E_OUT_OF_MEMORY, E_APP_NOT_INSTALLED, E_SYSTEM
93 _AppResourceString::Get_AppResourceStringN(int type, const Tizen::Base::String& value)
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));
99 String resourceFolder;
102 case APP_RESOURCE_DEFAULT:
103 case APP_RESOURCE_BY_LIBRARY_NAME:
105 resourceFolder = _AppInfo::GetAppRootPath();
106 resourceFolder.Append(L"res/");
107 resourceFolder.Append(value);
108 resourceFolder.Append(L"/");
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));
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));
120 resourceFolder = pPkgInfoImpl->GetAppRootPath();
121 resourceFolder.Append(L"/res/");
125 result r = pAppResourceString->Initialize(resourceFolder);
126 SysTryReturn(NID_APP, !IsFailed(r), null,
127 r, "[%s] Failed to initialize AppResourceString", GetErrorMessage(r));
130 return pAppResourceString.release();
134 _AppResourceString::Initialize(String& resourceFolder)
136 result r = E_SUCCESS;
137 if (__pLockOfParser == null)
139 __pLockOfParser = new (std::nothrow) Tizen::Base::Runtime::Mutex();
140 SysTryReturnResult(NID_APP, __pLockOfParser != null, E_OUT_OF_MEMORY, "Failed to initialize resource parser.");
142 r = __pLockOfParser->Create();
143 SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] Failed to Create Mutex.", GetErrorMessage(r));
146 r = __pLockOfParser->Acquire();
147 SysTryCatch(NID_APP, !IsFailed(r), r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to Acquire Mutex [%s].", GetErrorMessage(r));
149 r = InitializeStringInfo(resourceFolder);
150 __pLockOfParser->Release();
152 SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] Failed to InitializeStringInfo.", GetErrorMessage(r));
156 delete __pLockOfParser;
157 __pLockOfParser = null;
163 _AppResourceString::InitializeStringInfo(String& resourceFolder)
166 int ret = runtime_info_get_value_string(RUNTIME_INFO_KEY_LANGUAGE, &pVal);
167 SysTryReturnResult(NID_APP, ret == 0, E_SYSTEM, "runtime_info_get_value_string returns %d.", ret);
169 U_ICU_NAMESPACE::Locale icuLcl(pVal);
170 String language(icuLcl.getISO3Language());
171 String country(icuLcl.getCountry());
178 result r = resFilename.Format(256 * 2 + 10, L"%ls-%ls.xml", language.GetPointer(), country.GetPointer());
179 SysTryReturn(NID_APP, !IsFailed(r), E_SYSTEM, r, "[E_SYSTEM] Failed to format path string [%s]", GetErrorMessage(r));
181 if (!resourceFolder.EndsWith(L'/'))
183 resourceFolder.Append(L'/');
186 std::unique_ptr< _xmlDoc, FreeXmlDoc > pDoc(ParseXmlFile(resourceFolder + resFilename));
191 r = dir.Construct(resourceFolder);
194 // read all directory entries
195 DirEnumerator* pDirEnum = dir.ReadN();
196 if (pDirEnum != null)
198 const String starts = language + L"-";
199 const String ends = L".xml";
201 // loop through all directory entries
202 while (pDirEnum->MoveNext() == E_SUCCESS)
204 // get several properties of each directory entry.
205 resFilename = pDirEnum->GetCurrentDirEntry().GetName();
206 if (resFilename.StartsWith(starts, 0) && resFilename.EndsWith(ends))
208 pDoc.reset(ParseXmlFile(resourceFolder + resFilename));
220 pDoc.reset(ParseXmlFile(resourceFolder + L"eng-GB.xml"));
225 pDoc.reset(ParseXmlFile(resourceFolder + L"eng-US.xml"));
230 pDoc.reset(ParseXmlFile(resourceFolder + L"English.xml"));
233 SysTryLogReturn(NID_APP, pDoc != null, E_SUCCESS, "Can't find xml resource file.");
235 xmlNodePtr cur = xmlDocGetRootElement(pDoc.get());
236 SysTryReturnResult(NID_APP, cur != null, E_SYSTEM, "Empty document.");
238 ret = xmlStrcmp(cur->name, (const xmlChar*) AR_ROOT_NODE_NAME);
239 SysTryReturnResult(NID_APP, ret == 0, E_SYSTEM, "Document root node is not <string_table>.");
241 std::unique_ptr< HashMap, AllElementsDeleter > pXmlNodeMap (new (std::nothrow) HashMap());
242 SysTryReturnResult(NID_APP, pXmlNodeMap != null, E_OUT_OF_MEMORY, " Memory allocation failed.");
244 r = pXmlNodeMap->Construct();
245 SysTryReturnResult(NID_APP, !IsFailed(r), E_SYSTEM, "Unable to construct xml node map [%s]", GetErrorMessage(r));
247 xmlChar* pxmlValue = null;
248 cur = cur->xmlChildrenNode;
251 if ((!xmlStrcmp(cur->name, (const xmlChar*) AR_CHILD_NODE_1)))
253 pxmlValue = xmlGetProp(cur, (const xmlChar*) AR_ATTRIBUTE);
254 if (cur->type == (xmlElementType) XML_ELEMENT_NODE)
256 xmlChar* pContent = xmlNodeListGetString( pDoc.get(), cur->xmlChildrenNode, 1);
258 std::unique_ptr< String > pKey(new (std::nothrow) String);
259 SysTryReturnResult(NID_APP, pKey != null, E_OUT_OF_MEMORY, " Memory allocation failed.");
260 Tizen::Base::Utility::StringUtil::Utf8ToString((char*) pxmlValue, *pKey);
262 std::unique_ptr< String > pValue(new (std::nothrow) String);
263 SysTryReturnResult(NID_APP, pValue != null, E_OUT_OF_MEMORY, " Memory allocation failed.");
264 Tizen::Base::Utility::StringUtil::Utf8ToString((char*) pContent, *pValue);
266 pXmlNodeMap->Add(*pKey, *pValue);
294 __pXmlNodeMap->RemoveAll(true);
295 delete __pXmlNodeMap;
298 __pDoc = pDoc.release();
299 __pXmlNodeMap = pXmlNodeMap.release();
304 _AppResourceString::ParseXmlFile(const String& path)
306 xmlDocPtr pDoc = null;
307 if (File::IsFileExist(path))
309 std::unique_ptr<char[]> pBuf(_StringConverter::CopyToCharArrayN(path));
310 pDoc = xmlParseFile(pBuf.get());
317 _AppResourceString::GetString(const String resourceId, String& loadedString)
319 #if defined(ENABLE_XPATH)
320 SysTryReturnResult(NID_APP, __pDoc != null, E_FAILURE, "Can't find xml resource file.");
322 xmlXPathContextPtr __pXpathCtx = null;
323 xmlXPathObjectPtr __pXpathObj = null;
326 key.Format(1024, L"/string_table/text[@id='%ls']", resourceId.GetPointer());
328 xmlChar* pXpathExpr = (xmlChar*) (_StringConverter::CopyToCharArrayN(key));
329 xmlChar* pContent = null;
330 // Create xpath evaluation context
331 __pXpathCtx = xmlXPathNewContext(__pDoc);
332 if (__pXpathCtx == null)
334 SysLogException(NID_APP, E_INVALID_STATE, "[E_INVALID_STATE] XPathNewContext must not be null.");
337 return E_INVALID_STATE;
340 // Evaluate xpath expression
341 __pXpathObj = xmlXPathEvalExpression(pXpathExpr, __pXpathCtx);
342 if (null == __pXpathObj ||
343 null == __pXpathObj->nodesetval ||
344 null == __pXpathObj->nodesetval->nodeTab ||
345 null == __pXpathObj->nodesetval->nodeTab[0]->children
348 SysLog(NID_APP, "xpath expression is invalid.");
350 xmlXPathFreeContext(__pXpathCtx);
353 return E_INVALID_ARG;
357 pContent = __pXpathObj->nodesetval->nodeTab[0]->children->content;
358 loadedString = String((char*) pContent);
360 SysLog(NID_APP, "content : %s.", pContent);
363 // Cleanup of XPath data
364 xmlXPathFreeObject(__pXpathObj);
366 xmlXPathFreeContext(__pXpathCtx);
369 SysLog(NID_APP, "Free xpath data.");
374 SysTryReturnResult(NID_APP, !resourceId.IsEmpty(), E_INVALID_ARG, "Wrong resource Id.");
375 SysTryReturnResult(NID_APP, __pDoc != null, E_FAILURE, "Application string resource was not initialized.");
376 SysTryReturnResult(NID_APP, __pLockOfParser != null, E_FAILURE, "__pLockOfParser was not initialized.");
378 result r = __pLockOfParser->Acquire();
379 SysTryReturnResult(NID_APP, !IsFailed(r), E_FAILURE, "Failed to Acquire Mutex [%s].", GetErrorMessage(r));
381 String* pkeyValue = static_cast< String* > (__pXmlNodeMap->GetValue(resourceId));
382 r = E_FAILURE; //GetLastResult();
385 loadedString = *pkeyValue;
386 if (HasSpecialString(loadedString))
388 String rawString(loadedString);
389 ConvertToCstyleString(rawString, loadedString);
394 __pLockOfParser->Release();
401 _AppResourceString::HasSpecialString(const String& resourceStr)
404 return((resourceStr.IndexOf("<", 0, foundIndex) == E_SUCCESS)
405 || (resourceStr.IndexOf("&", 0, foundIndex) == E_SUCCESS)
406 || (resourceStr.IndexOf(">", 0, foundIndex) == E_SUCCESS)
407 || (resourceStr.IndexOf("'", 0, foundIndex) == E_SUCCESS)
408 || (resourceStr.IndexOf(""", 0, foundIndex) == E_SUCCESS)
409 || (resourceStr.IndexOf("&", 0, foundIndex) == E_SUCCESS)
410 || (resourceStr.IndexOf("\\", 0, foundIndex) == E_SUCCESS));
415 _AppResourceString::ConvertToCstyleString(const String& resourceStr, String& convertedStr)
417 SysTryReturnResult(NID_APP, resourceStr.GetLength() > 0, E_INVALID_ARG, "resource string must be greater than 0.");
419 std::unique_ptr<char[]> pBuffer(_StringConverter::CopyToCharArrayN(resourceStr));
420 SysTryReturnResult(NID_APP, pBuffer != null, E_OUT_OF_MEMORY, "Memory allocation failure.");
424 int len = strlen(pBuffer.get());// len = String_length((MString)pBuffer);
427 if (pBuffer[i] == '\\')
429 if (pBuffer[i + 1] == 'n')
435 else if (pBuffer[i + 1] == 't')
441 else if (pBuffer[i + 1] == '\\')
452 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'l') && (pBuffer[i + 2] == 't') &&
453 (pBuffer[i + 3] == ';'))
459 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'g') && (pBuffer[i + 2] == 't') &&
460 (pBuffer[i + 3] == ';'))
466 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'a') && (pBuffer[i + 2] == 'm') &&
467 (pBuffer[i + 3] == 'p') && (pBuffer[i + 4] == ';'))
473 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'a') && (pBuffer[i + 2] == 'p') &&
474 (pBuffer[i + 3] == 'o') && (pBuffer[i + 4] == 's') && (pBuffer[i + 5] == ';'))
476 pBuffer[j] = 39; // '
480 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'q') && (pBuffer[i + 2] == 'u') &&
481 (pBuffer[i + 3] == 'o') && (pBuffer[i + 4] == 't') && (pBuffer[i + 5] == ';'))
483 pBuffer[j] = 34; // "
489 pBuffer[j] = pBuffer[i];
502 convertedStr = pBuffer.get();