2 // Copyright (c) 2016 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.
17 #include <app_manager.h>
21 #include <libxml/parser.h>
22 #include <libxml/tree.h>
23 #include <pkgmgr-info.h>
24 #include <pkgmgr_installer_info.h>
27 #include <sys/types.h>
29 #include <tzplatform_config.h>
31 #include <gum/gum-user.h>
32 #include <gum/gum-user-service.h>
33 #include <gum/common/gum-user-types.h>
35 /* Define EXPORT_API */
37 #define EXPORT_API __attribute__((visibility("default")))
43 #define LOG_TAG "tts-engine-parser"
45 #define TTS_TAG_ENGINE_BASE "tts-engine"
46 #define TTS_TAG_ENGINE_NAME "name"
47 #define TTS_TAG_ENGINE_ID "id"
48 #define TTS_TAG_ENGINE_SETTING "setting"
49 #define TTS_TAG_ENGINE_VOICE_SET "voices"
50 #define TTS_TAG_ENGINE_VOICE "voice"
51 #define TTS_TAG_ENGINE_VOICE_TYPE "type"
52 #define TTS_TAG_ENGINE_PITCH_SUPPORT "pitch-support"
53 #define TTS_TAG_ENGINE_CREDENTIAL "credential"
54 #define TTS_TAG_ENGINE_TEXT_SIZE "text-size"
56 #define TTS_TAG_VOICE_BASE "tts-voice"
58 #define TTS_VOICE_INFO tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "voice/tts/1.0/tts-voice.xml")
60 #define TTS_GLOBAL_CONFIG_BASE tzplatform_mkpath(tzplatform_getid("TZ_SYS_GLOBALUSER_DATA"), ".voice")
61 #define TTS_GLOBAL_HOME tzplatform_mkpath(tzplatform_getid("TZ_SYS_GLOBALUSER_DATA"), ".voice/tts")
62 #define TTS_GLOBAL_ENGINE_INFO tzplatform_mkpath(tzplatform_getid("TZ_SYS_GLOBALUSER_DATA"), ".voice/tts/engine-info")
65 #define TTS_METADATA_NAME "http://tizen.org/metadata/tts-engine/name"
66 #define TTS_METADATA_LANGUAGE "http://tizen.org/metadata/tts-engine/language"
67 #define TTS_METADATA_CREDENTIAL_REQUIRED "http://tizen.org/metadata/tts-engine/credential-required"
68 #define TTS_METADATA_SETTING "http://tizen.org/metadata/tts-engine/setting"
69 #define TTS_METADATA_TEXT_SIZE "http://tizen.org/metadata/tts-engine/text-size"
70 #define TTS_METADATA_PITCH_SUPPORT "http://tizen.org/metadata/tts-engine/pitch-support"
72 #define TTS_MAX_TEXT_SIZE "2000"
75 #define FREE(x) { if (NULL != x) { free(x); x = NULL; } }
76 #define G_FREE(x) { if (NULL != x) { g_free(x); x = NULL; } }
78 typedef struct metadata {
89 voice_info_s *voice_info;
93 static xmlDocPtr g_doc;
94 static GumUser *g_guser = NULL;
95 static uid_t g_uid = 301; // app_fw
96 static gid_t g_gid = 301; // app_fw
97 static gchar *g_user_type = NULL;
99 static char *g_dir_config_base = NULL;
100 static char *g_dir_home = NULL;
101 static char *g_dir_engine_info = NULL;
103 static GSList *g_voice_info_list = NULL;
105 static int __create_engine_info_xml(const char *pkgid)
107 LOGD("@@@ Create engine info doc");
108 g_doc = xmlNewDoc((xmlChar*)"1.0");
110 LOGE("[ERROR] Fail to new doc");
117 static int __save_engine_info_xml(const char *pkgid, gchar *ut, uid_t uid, gid_t gid)
119 LOGD("@@@ Save engine info doc");
120 char *dir_config_base = NULL;
121 char *dir_home = NULL;
122 char *dir_engine_info = NULL;
124 if (NULL == ut || (NULL != ut && 0 == strcmp(ut, "none"))) {
125 LOGE("[ERROR] Usertype is NONE");
132 LOGD("uid(%u)", uid);
134 dir_config_base = strdup(TTS_GLOBAL_CONFIG_BASE);
135 dir_home = strdup(TTS_GLOBAL_HOME);
136 dir_engine_info = strdup(TTS_GLOBAL_ENGINE_INFO);
137 tmp_uid = 301; // app_fw
138 tmp_gid = 301; // app_fw
141 if (NULL == dir_config_base || NULL == dir_home || NULL == dir_engine_info) {
142 LOGE("[ERROR] Fail to allocate memory");
143 FREE(dir_config_base)
145 FREE(dir_engine_info)
150 LOGD("[DEBUG] dir_engine_info(%s)", dir_engine_info);
153 /* Make directories */
155 // if (0 != access(dir_config_base, F_OK)) {
156 fd = open(dir_config_base, O_DIRECTORY);
158 LOGE("[INFO] No directory : %s, errno : %d", dir_config_base, errno);
159 if (0 != mkdir(dir_config_base, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
160 LOGE("[ERROR] Fail to make directory : %s, errno : %d", dir_config_base, errno);
161 FREE(dir_config_base)
163 FREE(dir_engine_info)
166 LOGD("Success to make directory : %s", dir_config_base);
167 if (0 != chown(dir_config_base, tmp_uid, tmp_gid)) {
168 LOGD("[ERROR] Fail to change user and group, errno : %d", errno);
170 LOGD("[DEBUG] Success to change user and group");
177 // if (0 != access(dir_home, F_OK)) {
178 fd = open(dir_home, O_DIRECTORY);
180 LOGE("[INFO] No directory : %s, errno : %d", dir_home, errno);
181 if (0 != mkdir(dir_home, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
182 LOGE("[ERROR] Fail to make directory : %s, errno : %d", dir_home, errno);
183 FREE(dir_config_base)
185 FREE(dir_engine_info)
188 LOGD("Success to make directory : %s", dir_home);
189 if (0 != chown(dir_home, tmp_uid, tmp_gid)) {
190 LOGD("[ERROR] Fail to change user and group, errno : %d", errno);
192 LOGD("[DEBUG] Success to change user and group");
199 // if (0 != access(dir_engine_info, F_OK)) {
200 fd = open(dir_engine_info, O_DIRECTORY);
202 LOGE("[INFO] No directory : %s, errno : %d", dir_engine_info, errno);
203 if (0 != mkdir(dir_engine_info, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
204 LOGE("[ERROR] Fail to make directory : %s, errno : %d", dir_engine_info, errno);
205 FREE(dir_config_base)
207 FREE(dir_engine_info)
210 LOGD("Success to make directory : %s", dir_engine_info);
211 if (0 != chown(dir_engine_info, tmp_uid, tmp_gid)) {
212 LOGD("[ERROR] Fail to change user and group, errno : %d", errno);
214 LOGD("[DEBUG] Success to change user and group");
222 char path[256] = {'\0',};
223 snprintf(path, 256, "%s/%s.xml", dir_engine_info, pkgid);
224 int ret = xmlSaveFormatFile(path, g_doc, 1);
225 LOGD("xmlSaveFile (%d)", ret);
227 if (0 != chown(path, tmp_uid, tmp_gid)) {
228 LOGD("[ERROR] Fail to change user and group");
230 LOGD("[DEBUG] Success to change user and group");
234 FREE(dir_config_base)
236 FREE(dir_engine_info)
242 static int __remove_engine_info_xml(const char *pkgid, gchar *ut, uid_t uid)
244 LOGD("@@@ Remove engine info doc");
246 char *dir_engine_info = NULL;
248 if (NULL == ut || (NULL != ut && 0 == strcmp(ut, "none"))) {
249 LOGE("[ERROR] Usertype is NONE");
253 // uid_t globalapp_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
255 LOGD("uid(%u)", uid);
257 dir_engine_info = strdup(TTS_GLOBAL_ENGINE_INFO);
259 if (NULL == dir_engine_info) {
260 LOGE("[ERROR] Fail to allocate memory");
264 LOGD("[DEBUG] dir_engine_info(%s)", dir_engine_info);
267 char path[256] = {'\0',};
268 snprintf(path, 256, "%s/%s.xml", dir_engine_info, pkgid);
269 LOGD("Remove engine info xml(%s)", path);
270 if (0 != remove(path)) {
271 LOGE("[ERROR] Fail to Remove engine info xml(%s)", path);
274 FREE(dir_engine_info)
280 static void __insert_language_from_metadata(xmlNodePtr root, const char *language)
282 LOGD("@@@ Insert language");
286 if (NULL == root || NULL == language) {
287 LOGE("Invalid parameter, root(%p), language(%s)", root, language);
291 char *tmp_lang = NULL;
292 char *tmp_free = NULL;
293 tmp_free = tmp_lang = strdup(language);
294 if (NULL == tmp_lang) {
295 LOGE("Fail to memory allocation");
298 xmlNodePtr voices_node = NULL;
299 xmlNodePtr voice_node = NULL;
301 voices_node = xmlNewNode(NULL, (const xmlChar*)TTS_TAG_ENGINE_VOICE_SET);
303 voice = strsep(&tmp_lang, ",");
304 while (NULL != voice) {
305 LOGD("voice (%s)", voice);
306 voice_node = xmlNewNode(NULL, (const xmlChar*)TTS_TAG_ENGINE_VOICE);
307 lang = strsep(&voice, ":");
308 LOGD("lang (%s)", lang);
309 type = strsep(&voice, " ");
310 LOGD("type (%s)", type);
311 xmlSetProp(voice_node, (const xmlChar*)TTS_TAG_ENGINE_VOICE_TYPE, (const xmlChar*)type);
312 xmlNodeSetContent(voice_node, (const xmlChar*)lang);
313 xmlAddChild(voices_node, voice_node);
314 voice = strsep(&tmp_lang, ",");
317 /* add extra voices */
318 LOGD("Add extra voices");
319 if (NULL != g_voice_info_list) {
321 for (iter = g_voice_info_list ; iter != NULL ; iter = g_slist_next(iter)) {
322 voice_info_s *extra_voice = (voice_info_s*)iter->data;
323 if (NULL != extra_voice) {
324 lang = strdup(extra_voice->lang);
325 type = strdup(extra_voice->type);
326 LOGD("lang(%s), type(%s)", lang, type);
329 voice_node = xmlNewNode(NULL, (const xmlChar*)TTS_TAG_ENGINE_VOICE);
330 xmlSetProp(voice_node, (const xmlChar*)TTS_TAG_ENGINE_VOICE_TYPE, (const xmlChar*)type);
331 xmlNodeSetContent(voice_node, (const xmlChar*)lang);
332 xmlAddChild(voices_node, voice_node);
335 LOGD("Finish to add voice node");
343 LOGD("Memory release");
345 if (NULL != extra_voice->lang) {
346 free(extra_voice->lang);
348 if (NULL != extra_voice->type) {
349 free(extra_voice->type);
351 LOGD("Free extra_voice");
357 LOGD("Free voice info list");
358 g_slist_free(g_voice_info_list);
359 g_voice_info_list = NULL;
362 xmlAddChild(root, voices_node);
367 static int __get_voice_inxml()
369 xmlDocPtr doc = NULL;
370 xmlNodePtr cur = NULL;
372 LOGD("TTS voice info xml (%s)", TTS_VOICE_INFO);
374 if (0 != access(TTS_VOICE_INFO, F_OK)) {
375 LOGD("There is no extra voice info.");
378 doc = xmlParseFile(TTS_VOICE_INFO);
380 LOGE("Fail to parse file");
384 cur = xmlDocGetRootElement(doc);
386 LOGE("Empty document");
391 if (xmlStrcmp(cur->name, (const xmlChar *)TTS_TAG_VOICE_BASE)) {
392 LOGE("root node is NOT %s", TTS_TAG_VOICE_BASE);
397 cur = cur->xmlChildrenNode;
399 LOGE("<tts-voice> child NULL");
407 while (NULL != cur) {
408 if (0 == xmlStrcmp(cur->name, (const xmlChar *)TTS_TAG_ENGINE_VOICE_SET)) {
410 xmlNodePtr voice_node = NULL;
411 voice_node = cur->xmlChildrenNode;
413 while (NULL != voice_node) {
414 if (0 == xmlStrcmp(voice_node->name, (const xmlChar *)TTS_TAG_ENGINE_VOICE)) {
415 voice_info_s *voice_info = (voice_info_s *)calloc(1, sizeof(voice_info_s));
416 if (NULL == voice_info) {
417 LOGE("Fail to allocate memory");
422 LOGD("Get property and keys");
423 xmlChar *attr = xmlGetProp(voice_node, (const xmlChar *)TTS_TAG_ENGINE_VOICE_TYPE);
425 // strncpy(type, (char*)attr, strlen((char*)attr));
426 voice_info->type = strdup((char*)attr);
427 LOGD("type(%s)", voice_info->type);
431 LOGD("No voice type");
434 xmlChar *key = xmlNodeGetContent(voice_node);
436 // strncpy(lang, (char*)key, strlen((char*)key));
437 voice_info->lang = strdup((char*)key);
438 LOGD("lang(%s)", voice_info->lang);
442 LOGD("No voice info");
445 g_voice_info_list = g_slist_append(g_voice_info_list, voice_info);
448 voice_node = voice_node->next;
451 LOGD("Unknown tag (%s)", (const char*)cur->name);
463 static int __write_metadata_inxml(const char *pkgid, const char *appid, GList *list)
468 bool isTextsize = false;
470 __create_engine_info_xml(pkgid);
472 xmlNodePtr root = NULL;
473 xmlNodePtr cur = NULL;
475 root = xmlNewNode(NULL, (const xmlChar*)TTS_TAG_ENGINE_BASE);
477 LOGE("[ERROR] Fail to get new node");
478 // xmlFreeDoc(g_doc);
481 xmlDocSetRootElement(g_doc, root);
484 // cur = xmlNewNode(NULL, (const xmlChar*)TTS_TAG_ENGINE_NAME);
485 // xmlNodeSetContent(cur, (const xmlChar*)pkgid);
486 // xmlAddChild(root, cur);
489 iter = g_list_first(list);
490 while (NULL != iter) {
491 md = (metadata *)iter->data;
492 if (NULL != md && NULL != md->key) {
493 LOGD(" - key(%s) value(%s)", md->key, md->value);
494 if (!strcmp(md->key, TTS_METADATA_LANGUAGE)) {
496 __insert_language_from_metadata(root, md->value);
497 } else if (!strcmp(md->key, TTS_METADATA_CREDENTIAL_REQUIRED)) {
498 cur = xmlNewNode(NULL, (const xmlChar*)TTS_TAG_ENGINE_CREDENTIAL);
499 xmlNodeSetContent(cur, (const xmlChar*)md->value);
500 xmlAddChild(root, cur);
501 } else if (!strcmp(md->key, TTS_METADATA_SETTING)) {
502 cur = xmlNewNode(NULL, (const xmlChar*)TTS_TAG_ENGINE_SETTING);
503 xmlNodeSetContent(cur, (const xmlChar*)md->value);
504 xmlAddChild(root, cur);
505 } else if (!strcmp(md->key, TTS_METADATA_NAME)) {
506 cur = xmlNewNode(NULL, (const xmlChar*)TTS_TAG_ENGINE_NAME);
507 xmlNodeSetContent(cur, (const xmlChar*)md->value);
508 xmlAddChild(root, cur);
509 } else if (!strcmp(md->key, TTS_METADATA_TEXT_SIZE)) {
510 cur = xmlNewNode(NULL, (const xmlChar*)TTS_TAG_ENGINE_TEXT_SIZE);
511 xmlNodeSetContent(cur, (const xmlChar*)md->value);
512 xmlAddChild(root, cur);
514 } else if (!strcmp(md->key, TTS_METADATA_PITCH_SUPPORT)) {
515 cur = xmlNewNode(NULL, (const xmlChar*)TTS_TAG_ENGINE_PITCH_SUPPORT);
516 xmlNodeSetContent(cur, (const xmlChar*)md->value);
517 xmlAddChild(root, cur);
519 LOGW("[WARNING] Unknown metadata type");
522 iter = g_list_next(iter);
525 if (false == isTextsize) {
526 cur = xmlNewNode(NULL, (const xmlChar*)TTS_TAG_ENGINE_TEXT_SIZE);
527 xmlNodeSetContent(cur, (const xmlChar*)TTS_MAX_TEXT_SIZE);
528 xmlAddChild(root, cur);
529 LOGD("[DEBUG] Max text size is set as %s.", TTS_MAX_TEXT_SIZE);
532 cur = xmlNewNode(NULL, (const xmlChar*)TTS_TAG_ENGINE_ID);
533 xmlNodeSetContent(cur, (const xmlChar*)pkgid);
534 xmlAddChild(root, cur);
542 static gchar* __get_user_type(GumUser *user)
544 GumUserType gumut = GUM_USERTYPE_NONE;
545 g_object_get(G_OBJECT(user), "usertype", &gumut, NULL);
546 gchar* user_type = g_strdup(gum_user_type_to_string(gumut));
550 static int __get_global_user_type(uid_t globalapp_uid)
552 if (globalapp_uid == g_uid) {
553 g_user_type = g_strdup("admin");
555 g_guser = gum_user_get_sync(g_uid, FALSE);
556 if (NULL == g_guser) {
557 LOGE("[ERROR] g_guser is NULL");
561 g_object_get(G_OBJECT(g_guser), "gid", &g_gid, NULL);
562 g_user_type = __get_user_type(g_guser);
565 if (NULL == g_user_type) {
566 LOGE("[ERROR] Fail to allocate memory");
567 g_object_unref(g_guser);
572 if (0 == strcmp(g_user_type, "none")) {
573 /* GUM_USERTYPE_NONE */
574 LOGE("[ERROR] Fail to get target uid");
575 g_object_unref(g_guser);
585 int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgid, const char *appid, GList *list)
587 LOGD("METADATA INSTALL");
588 LOGD("pkgid(%s) appid(%s) list(%u)", pkgid, appid, g_list_length(list));
590 if (0 > pkgmgr_installer_info_get_target_uid(&g_uid)) {
591 LOGE("[ERROR] Fail to get target uid");
595 LOGD("uid(%u)", g_uid);
596 printf("[Parser Debug][DEBUG] uid(%u)", g_uid);
598 uid_t globalapp_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
599 if (0 != __get_global_user_type(globalapp_uid)) {
603 /* global directory */
604 LOGD("[DEBUG] usertype: %s", g_user_type);
605 if (0 >= g_list_length(list)) {
606 LOGE("[ERROR] No Engine Metadata");
611 if (0 != __write_metadata_inxml(pkgid, appid, list)) {
612 LOGE("[ERROR] Fail to write metadata in the xml");
618 /* Save in /opt/usr/data/ */
619 g_dir_config_base = strdup(TTS_GLOBAL_CONFIG_BASE);
620 g_dir_home = strdup(TTS_GLOBAL_HOME);
621 g_dir_engine_info = strdup(TTS_GLOBAL_ENGINE_INFO);
623 if (NULL == g_dir_config_base || NULL == g_dir_home || NULL == g_dir_engine_info) {
624 LOGE("[ERROR] Fail to allocate memory");
625 FREE(g_dir_config_base)
627 FREE(g_dir_engine_info)
634 if (0 != __save_engine_info_xml(pkgid, g_user_type, g_uid, g_gid)) {
635 LOGE("[ERROR] Fail to make engine info file");
643 if (NULL != g_guser) {
644 g_object_unref(g_guser);
649 FREE(g_dir_config_base)
651 FREE(g_dir_engine_info)
657 int PKGMGR_MDPARSER_PLUGIN_UNINSTALL(const char *pkgid, const char *appid, GList *list)
659 LOGD("METADATA UNINSTALL");
660 LOGD("pkgid(%s) appid(%s) list(%u)", pkgid, appid, g_list_length(list));
662 if (0 > pkgmgr_installer_info_get_target_uid(&g_uid)) {
663 LOGE("[ERROR] Fail to get target uid");
667 LOGD("uid(%u)", g_uid);
668 printf("[Parser Debug][DEBUG] uid(%u)", g_uid);
670 uid_t globalapp_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
671 if (0 != __get_global_user_type(globalapp_uid)) {
675 /* global directory */
676 LOGD("[DEBUG] usertype: %s", g_user_type);
678 /* Remove files in /opt/usr/data/ */
679 g_dir_engine_info = strdup(TTS_GLOBAL_ENGINE_INFO);
680 if (NULL == g_dir_engine_info) {
681 LOGE("[ERROR] Fail to allocate memory");
686 if (0 != __remove_engine_info_xml(pkgid, g_user_type, g_uid)) {
687 LOGE("[ERROR] Fail to remove engine info file");
691 if (NULL != g_guser) {
692 g_object_unref(g_guser);
697 FREE(g_dir_engine_info)
704 int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgid, const char *appid, GList *list)
706 LOGD("METADATA UPGRADE");
707 LOGD("pkgid(%s) appid(%s) list(%u)", pkgid, appid, g_list_length(list));
709 PKGMGR_MDPARSER_PLUGIN_UNINSTALL(pkgid, appid, list);
710 PKGMGR_MDPARSER_PLUGIN_INSTALL(pkgid, appid, list);