2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @file FApp_AppResourceString.cpp
19 * @brief This is the implementation for the _AppResourceString class.
22 #include <libxml/parser.h>
23 #include <libxml/xpath.h>
24 #include <libxml/tree.h>
25 #include <unicode/locid.h>
27 #include <unique_ptr.h>
28 #include <runtime_info.h>
30 #include <FBaseResult.h>
31 #include <FBaseSysLog.h>
32 #include <FBase_StringConverter.h>
33 #include <FBaseColHashMap.h>
36 #include <FIoDirectory.h>
38 #include <FApp_AppInfo.h>
39 #include <FAppPkgPackageInfo.h>
40 #include "FAppPkg_PackageManagerImpl.h"
41 #include "FAppPkg_PackageInfoImpl.h"
43 #include "FApp_AppResourceImpl.h"
44 #include "FApp_AppResourceString.h"
46 using namespace Tizen::App::Package;
47 using namespace Tizen::Base;
48 using namespace Tizen::Base::Collection;
49 using namespace Tizen::Io;
51 static const char* AR_ROOT_NODE_NAME = "string_table";
52 static const char* AR_CHILD_NODE_1 = "text";
53 static const char* AR_ATTRIBUTE = "id";
57 void operator ()(_xmlDoc* p)
66 namespace Tizen { namespace App
69 _AppResourceString::_AppResourceString(void)
71 , __pLockOfParser(null)
76 _AppResourceString::~_AppResourceString(void)
84 __pXmlNodeMap->RemoveAll(true);
87 delete __pLockOfParser;
90 // Exception: E_OUT_OF_MEMORY, E_APP_NOT_INSTALLED, E_SYSTEM
92 _AppResourceString::Get_AppResourceStringN(int type, const Tizen::Base::String& value)
94 std::unique_ptr< _AppResourceString > pAppResourceString(new (std::nothrow) _AppResourceString);
95 SysTryReturn(NID_APP, pAppResourceString != null, null,
96 E_OUT_OF_MEMORY, "[%s] Unable to allocate memory for _AppResourceString", GetErrorMessage(E_OUT_OF_MEMORY));
98 String resourceFolder;
101 case APP_RESOURCE_DEFAULT:
102 case APP_RESOURCE_BY_LIBRARY_NAME:
104 resourceFolder = _AppInfo::GetAppRootPath();
105 resourceFolder.Append(L"res/");
106 resourceFolder.Append(value);
107 resourceFolder.Append(L"/");
110 case APP_RESOURCE_BY_APP_ID:
111 std::unique_ptr< PackageInfo> pPkgInfo(_PackageManagerImpl::GetInstance()->GetPackageInfoN(value));
112 SysTryReturn(NID_APP, pPkgInfo != null, null,
113 E_APP_NOT_INSTALLED, "[%s] Failed to get the package info", GetErrorMessage(E_APP_NOT_INSTALLED));
115 _PackageInfoImpl* pPkgInfoImpl = _PackageInfoImpl::GetInstance(pPkgInfo.get());
116 SysTryReturn(NID_APP, pPkgInfoImpl != null, null,
117 E_APP_NOT_INSTALLED, "[%s] Failed to get the package info impl", GetErrorMessage(E_APP_NOT_INSTALLED));
119 resourceFolder = pPkgInfoImpl->GetAppRootPath();
120 resourceFolder.Append(L"/res/");
124 result r = pAppResourceString->Initialize(resourceFolder);
125 SysTryReturn(NID_APP, !IsFailed(r), null,
126 r, "[%s] Failed to initialize AppResourceString", GetErrorMessage(r));
129 return pAppResourceString.release();
133 _AppResourceString::Initialize(String& resourceFolder)
135 result r = E_SUCCESS;
136 if (__pLockOfParser == null)
138 __pLockOfParser = new (std::nothrow) Tizen::Base::Runtime::Mutex();
139 SysTryReturnResult(NID_APP, __pLockOfParser != null, E_OUT_OF_MEMORY, "Failed to initialize resource parser.");
141 r = __pLockOfParser->Create();
142 SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] Failed to Create Mutex.", GetErrorMessage(r));
145 r = __pLockOfParser->Acquire();
146 SysTryCatch(NID_APP, !IsFailed(r), r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to Acquire Mutex [%s].", GetErrorMessage(r));
148 r = InitializeStringInfo(resourceFolder);
149 __pLockOfParser->Release();
151 SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] Failed to InitializeStringInfo.", GetErrorMessage(r));
155 delete __pLockOfParser;
156 __pLockOfParser = null;
162 _AppResourceString::InitializeStringInfo(String& resourceFolder)
165 int ret = runtime_info_get_value_string(RUNTIME_INFO_KEY_LANGUAGE, &pVal);
166 SysTryReturnResult(NID_APP, ret == 0, E_SYSTEM, "runtime_info_get_value_string returns %d.", ret);
168 U_ICU_NAMESPACE::Locale icuLcl(pVal);
169 String language(icuLcl.getISO3Language());
170 String country(icuLcl.getCountry());
177 result r = resFilename.Format(256 * 2 + 10, L"%ls-%ls.xml", language.GetPointer(), country.GetPointer());
178 SysTryReturn(NID_APP, !IsFailed(r), E_SYSTEM, r, "[E_SYSTEM] Failed to format path string [%s]", GetErrorMessage(r));
180 if (!resourceFolder.EndsWith(L'/'))
182 resourceFolder.Append(L'/');
185 std::unique_ptr< _xmlDoc, FreeXmlDoc > pDoc(ParseXmlFile(resourceFolder + resFilename));
190 r = dir.Construct(resourceFolder);
193 // read all directory entries
194 DirEnumerator* 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 resFilename = pDirEnum->GetCurrentDirEntry().GetName();
205 if (resFilename.StartsWith(starts, 0) && resFilename.EndsWith(ends))
207 pDoc.reset(ParseXmlFile(resourceFolder + resFilename));
219 pDoc.reset(ParseXmlFile(resourceFolder + L"eng-GB.xml"));
224 pDoc.reset(ParseXmlFile(resourceFolder + L"eng-US.xml"));
229 pDoc.reset(ParseXmlFile(resourceFolder + L"English.xml"));
232 SysTryLogReturn(NID_APP, pDoc != null, E_SUCCESS, "Can't find xml resource file.");
234 xmlNodePtr cur = xmlDocGetRootElement(pDoc.get());
235 SysTryReturnResult(NID_APP, cur != null, E_SYSTEM, "Empty document.");
237 ret = xmlStrcmp(cur->name, (const xmlChar*) AR_ROOT_NODE_NAME);
238 SysTryReturnResult(NID_APP, ret == 0, E_SYSTEM, "Document root node is not <string_table>.");
240 std::unique_ptr< HashMap, AllElementsDeleter > pXmlNodeMap (new (std::nothrow) HashMap());
241 SysTryReturnResult(NID_APP, pXmlNodeMap != null, E_OUT_OF_MEMORY, " Memory allocation failed.");
243 r = pXmlNodeMap->Construct();
244 SysTryReturnResult(NID_APP, !IsFailed(r), E_SYSTEM, "Unable to construct xml node map [%s]", GetErrorMessage(r));
246 xmlChar* pxmlValue = null;
247 cur = cur->xmlChildrenNode;
250 if ((!xmlStrcmp(cur->name, (const xmlChar*) AR_CHILD_NODE_1)))
252 pxmlValue = xmlGetProp(cur, (const xmlChar*) AR_ATTRIBUTE);
253 if (cur->type == (xmlElementType) XML_ELEMENT_NODE)
255 xmlChar* pContent = xmlNodeListGetString( pDoc.get(), cur->xmlChildrenNode, 1);
257 std::unique_ptr< String > pKey(new (std::nothrow) String);
258 SysTryReturnResult(NID_APP, pKey != null, E_OUT_OF_MEMORY, " Memory allocation failed.");
259 Tizen::Base::Utility::StringUtil::Utf8ToString((char*) pxmlValue, *pKey);
261 std::unique_ptr< String > pValue(new (std::nothrow) String);
262 SysTryReturnResult(NID_APP, pValue != null, E_OUT_OF_MEMORY, " Memory allocation failed.");
263 Tizen::Base::Utility::StringUtil::Utf8ToString((char*) pContent, *pValue);
265 pXmlNodeMap->Add(*pKey, *pValue);
293 __pXmlNodeMap->RemoveAll(true);
294 delete __pXmlNodeMap;
297 __pDoc = pDoc.release();
298 __pXmlNodeMap = pXmlNodeMap.release();
303 _AppResourceString::ParseXmlFile(const String& path)
305 xmlDocPtr pDoc = null;
306 if (File::IsFileExist(path))
308 std::unique_ptr<char[]> pBuf(_StringConverter::CopyToCharArrayN(path));
309 pDoc = xmlParseFile(pBuf.get());
316 _AppResourceString::GetString(const String resourceId, String& loadedString)
318 #if defined(ENABLE_XPATH)
319 SysTryReturnResult(NID_APP, __pDoc != null, E_FAILURE, "Can't find xml resource file.");
321 xmlXPathContextPtr __pXpathCtx = null;
322 xmlXPathObjectPtr __pXpathObj = null;
325 key.Format(1024, L"/string_table/text[@id='%ls']", resourceId.GetPointer());
327 xmlChar* pXpathExpr = (xmlChar*) (_StringConverter::CopyToCharArrayN(key));
328 xmlChar* pContent = null;
329 // Create xpath evaluation context
330 __pXpathCtx = xmlXPathNewContext(__pDoc);
331 if (__pXpathCtx == null)
333 SysLogException(NID_APP, E_INVALID_STATE, "[E_INVALID_STATE] XPathNewContext must not be null.");
336 return E_INVALID_STATE;
339 // Evaluate xpath expression
340 __pXpathObj = xmlXPathEvalExpression(pXpathExpr, __pXpathCtx);
341 if (null == __pXpathObj ||
342 null == __pXpathObj->nodesetval ||
343 null == __pXpathObj->nodesetval->nodeTab ||
344 null == __pXpathObj->nodesetval->nodeTab[0]->children
347 SysLog(NID_APP, "xpath expression is invalid.");
349 xmlXPathFreeContext(__pXpathCtx);
352 return E_INVALID_ARG;
356 pContent = __pXpathObj->nodesetval->nodeTab[0]->children->content;
357 loadedString = String((char*) pContent);
359 SysLog(NID_APP, "content : %s.", pContent);
362 // Cleanup of XPath data
363 xmlXPathFreeObject(__pXpathObj);
365 xmlXPathFreeContext(__pXpathCtx);
368 SysLog(NID_APP, "Free xpath data.");
373 SysTryReturnResult(NID_APP, !resourceId.IsEmpty(), E_INVALID_ARG, "Wrong resource Id.");
374 SysTryReturnResult(NID_APP, __pDoc != null, E_FAILURE, "Application string resource was not initialized.");
375 SysTryReturnResult(NID_APP, __pLockOfParser != null, E_FAILURE, "__pLockOfParser was not initialized.");
377 result r = __pLockOfParser->Acquire();
378 SysTryReturnResult(NID_APP, !IsFailed(r), E_FAILURE, "Failed to Acquire Mutex [%s].", GetErrorMessage(r));
380 String* pkeyValue = static_cast< String* > (__pXmlNodeMap->GetValue(resourceId));
381 r = E_FAILURE; //GetLastResult();
384 loadedString = *pkeyValue;
385 if (HasSpecialString(loadedString))
387 String rawString(loadedString);
388 ConvertToCstyleString(rawString, loadedString);
393 __pLockOfParser->Release();
400 _AppResourceString::HasSpecialString(const String& resourceStr)
403 return((resourceStr.IndexOf("<", 0, foundIndex) == E_SUCCESS)
404 || (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));
414 _AppResourceString::ConvertToCstyleString(const String& resourceStr, String& convertedStr)
416 SysTryReturnResult(NID_APP, resourceStr.GetLength() > 0, E_INVALID_ARG, "resource string must be greater than 0.");
418 std::unique_ptr<char[]> pBuffer(_StringConverter::CopyToCharArrayN(resourceStr));
419 SysTryReturnResult(NID_APP, pBuffer != null, E_OUT_OF_MEMORY, "Memory allocation failure.");
423 int len = strlen(pBuffer.get());// len = String_length((MString)pBuffer);
426 if (pBuffer[i] == '\\')
428 if (pBuffer[i + 1] == 'n')
434 else if (pBuffer[i + 1] == 't')
440 else if (pBuffer[i + 1] == '\\')
451 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'l') && (pBuffer[i + 2] == 't') &&
452 (pBuffer[i + 3] == ';'))
458 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'g') && (pBuffer[i + 2] == 't') &&
459 (pBuffer[i + 3] == ';'))
465 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'a') && (pBuffer[i + 2] == 'm') &&
466 (pBuffer[i + 3] == 'p') && (pBuffer[i + 4] == ';'))
472 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'a') && (pBuffer[i + 2] == 'p') &&
473 (pBuffer[i + 3] == 'o') && (pBuffer[i + 4] == 's') && (pBuffer[i + 5] == ';'))
475 pBuffer[j] = 39; // '
479 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'q') && (pBuffer[i + 2] == 'u') &&
480 (pBuffer[i + 3] == 'o') && (pBuffer[i + 4] == 't') && (pBuffer[i + 5] == ';'))
482 pBuffer[j] = 34; // "
488 pBuffer[j] = pBuffer[i];
501 convertedStr = pBuffer.get();