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, &pValue);
167 SysTryReturnResult(NID_APP, ret == 0, E_SYSTEM, "runtime_info_get_value_string returns %d.", ret);
169 U_ICU_NAMESPACE::Locale icuLcl(pValue);
170 String language(icuLcl.getISO3Language());
171 String country(icuLcl.getCountry());
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));
177 if (!resourceFolder.EndsWith(L'/'))
179 resourceFolder.Append(L'/');
182 std::unique_ptr< _xmlDoc, FreeXmlDoc > pDoc(ParseXmlFile(resourceFolder + resFilename));
187 r = dir.Construct(resourceFolder);
190 // read all directory entries
191 DirEnumerator* pDirEnum = dir.ReadN();
192 if (pDirEnum != null)
194 const String starts = language + L"-";
195 const String ends = L".xml";
197 // loop through all directory entries
198 while (pDirEnum->MoveNext() == E_SUCCESS)
200 // get several properties of each directory entry.
201 resFilename = pDirEnum->GetCurrentDirEntry().GetName();
202 if (resFilename.StartsWith(starts, 0) && resFilename.EndsWith(ends))
204 pDoc.reset(ParseXmlFile(resourceFolder + resFilename));
216 pDoc.reset(ParseXmlFile(resourceFolder + L"eng-GB.xml"));
221 pDoc.reset(ParseXmlFile(resourceFolder + L"eng-US.xml"));
226 pDoc.reset(ParseXmlFile(resourceFolder + L"English.xml"));
229 SysTryLogReturn(NID_APP, pDoc != null, E_SUCCESS, "Can't find xml resource file.");
231 xmlNodePtr cur = xmlDocGetRootElement(pDoc.get());
232 SysTryReturnResult(NID_APP, cur != null, E_SYSTEM, "Empty document.");
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>.");
237 std::unique_ptr< HashMap, AllElementsDeleter > pXmlNodeMap (new (std::nothrow) HashMap());
238 SysTryReturnResult(NID_APP, pXmlNodeMap != null, E_OUT_OF_MEMORY, " Memory allocation failed.");
240 r = pXmlNodeMap->Construct();
241 SysTryReturnResult(NID_APP, !IsFailed(r), E_SYSTEM, "Unable to construct xml node map [%s]", GetErrorMessage(r));
243 xmlChar* pxmlValue = null;
244 cur = cur->xmlChildrenNode;
247 if ((!xmlStrcmp(cur->name, (const xmlChar*) AR_CHILD_NODE_1)))
249 pxmlValue = xmlGetProp(cur, (const xmlChar*) AR_ATTRIBUTE);
250 if (cur->type == (xmlElementType) XML_ELEMENT_NODE)
252 xmlChar* pContent = xmlNodeListGetString( pDoc.get(), cur->xmlChildrenNode, 1);
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);
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);
262 pXmlNodeMap->Add(*pKey, *pValue);
279 __pXmlNodeMap->RemoveAll(true);
280 delete __pXmlNodeMap;
283 __pDoc = pDoc.release();
284 __pXmlNodeMap = pXmlNodeMap.release();
289 _AppResourceString::ParseXmlFile(const String& path)
291 xmlDocPtr pDoc = null;
292 if (File::IsFileExist(path))
294 std::unique_ptr<char[]> pBuf(_StringConverter::CopyToCharArrayN(path));
295 pDoc = xmlParseFile(pBuf.get());
302 _AppResourceString::GetString(const String resourceId, String& loadedString)
304 #if defined(ENABLE_XPATH)
305 SysTryReturnResult(NID_APP, __pDoc != null, E_FAILURE, "Can't find xml resource file.");
307 xmlXPathContextPtr __pXpathCtx = null;
308 xmlXPathObjectPtr __pXpathObj = null;
311 key.Format(1024, L"/string_table/text[@id='%ls']", resourceId.GetPointer());
313 xmlChar* pXpathExpr = (xmlChar*) (_StringConverter::CopyToCharArrayN(key));
314 xmlChar* pContent = null;
315 // Create xpath evaluation context
316 __pXpathCtx = xmlXPathNewContext(__pDoc);
317 if (__pXpathCtx == null)
319 SysLogException(NID_APP, E_INVALID_STATE, "[E_INVALID_STATE] XPathNewContext must not be null.");
322 return E_INVALID_STATE;
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
333 SysLog(NID_APP, "xpath expression is invalid.");
335 xmlXPathFreeContext(__pXpathCtx);
338 return E_INVALID_ARG;
342 pContent = __pXpathObj->nodesetval->nodeTab[0]->children->content;
343 loadedString = String((char*) pContent);
345 SysLog(NID_APP, "content : %s.", pContent);
348 // Cleanup of XPath data
349 xmlXPathFreeObject(__pXpathObj);
351 xmlXPathFreeContext(__pXpathCtx);
354 SysLog(NID_APP, "Free xpath data.");
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.");
363 result r = __pLockOfParser->Acquire();
364 SysTryReturnResult(NID_APP, !IsFailed(r), E_FAILURE, "Failed to Acquire Mutex [%s].", GetErrorMessage(r));
366 String* pkeyValue = static_cast< String* > (__pXmlNodeMap->GetValue(resourceId));
367 r = E_FAILURE; //GetLastResult();
370 loadedString = *pkeyValue;
371 if (HasSpecialString(loadedString))
373 String rawString(loadedString);
374 ConvertToCstyleString(rawString, loadedString);
379 __pLockOfParser->Release();
386 _AppResourceString::HasSpecialString(const String& resourceStr)
389 return((resourceStr.IndexOf("<", 0, foundIndex) == E_SUCCESS)
390 || (resourceStr.IndexOf("&", 0, foundIndex) == E_SUCCESS)
391 || (resourceStr.IndexOf(">", 0, foundIndex) == E_SUCCESS)
392 || (resourceStr.IndexOf("'", 0, foundIndex) == E_SUCCESS)
393 || (resourceStr.IndexOf(""", 0, foundIndex) == E_SUCCESS)
394 || (resourceStr.IndexOf("&", 0, foundIndex) == E_SUCCESS)
395 || (resourceStr.IndexOf("\\", 0, foundIndex) == E_SUCCESS));
400 _AppResourceString::ConvertToCstyleString(const String& resourceStr, String& convertedStr)
402 SysTryReturnResult(NID_APP, resourceStr.GetLength() > 0, E_INVALID_ARG, "resource string must be greater than 0.");
404 std::unique_ptr<char[]> pBuffer(_StringConverter::CopyToCharArrayN(resourceStr));
405 SysTryReturnResult(NID_APP, pBuffer != null, E_OUT_OF_MEMORY, "Memory allocation failure.");
409 int len = strlen(pBuffer.get());// len = String_length((MString)pBuffer);
412 if (pBuffer[i] == '\\')
414 if (pBuffer[i + 1] == 'n')
420 else if (pBuffer[i + 1] == 't')
426 else if (pBuffer[i + 1] == '\\')
437 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'l') && (pBuffer[i + 2] == 't') &&
438 (pBuffer[i + 3] == ';'))
444 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'g') && (pBuffer[i + 2] == 't') &&
445 (pBuffer[i + 3] == ';'))
451 else if ((pBuffer[i] == '&') && (pBuffer[i + 1] == 'a') && (pBuffer[i + 2] == 'm') &&
452 (pBuffer[i + 3] == 'p') && (pBuffer[i + 4] == ';'))
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] == ';'))
461 pBuffer[j] = 39; // '
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] == ';'))
468 pBuffer[j] = 34; // "
474 pBuffer[j] = pBuffer[i];
487 convertedStr = pBuffer.get();