#include <libxml/tree.h>
#include <dlog.h>
#include <pkgmgr-info.h>
+#include <system_info.h>
#include <widget_service.h>
#include <widget_service_internal.h>
#define SCHEME_HTTP "http://"
#define SCHEME_HTTPS "https://"
#define SCHEME_FILE "file://"
+#define SHARED_RES_PATH "/shared/res/"
#if !defined(WIDGET_COUNT_OF_SIZE_TYPE)
#define WIDGET_COUNT_OF_SIZE_TYPE 13
static struct {
const char *dbfile;
sqlite3 *handle;
+ struct _resolution {
+ int initialized;
+ int width;
+ int height;
+ } resolution;
} s_info = {
.dbfile = "/opt/dbspace/.widget.db",
.handle = NULL,
+ .resolution = {
+ .initialized = 0,
+ .width = 0,
+ .height = 0,
+ },
};
+static void initialize_resolution(void)
+{
+ int ret;
+
+ if (s_info.resolution.initialized) {
+ return;
+ }
+
+ ret = system_info_get_platform_int("http://tizen.org/feature/screen.width", &s_info.resolution.width);
+ if (ret != SYSTEM_INFO_ERROR_NONE) {
+ ErrPrint("Failed to get platform value\n");
+ return;
+ }
+
+ ret = system_info_get_platform_int("http://tizen.org/feature/screen.height", &s_info.resolution.height);
+ if (ret != SYSTEM_INFO_ERROR_NONE) {
+ ErrPrint("Failed to get platform value\n");
+ return;
+ }
+
+ s_info.resolution.initialized = 1;
+ return;
+}
+
static int is_scheme(const char *path)
{
if (!strncasecmp(path, SCHEME_HTTP, strlen(SCHEME_HTTP))) {
* And if the input path is not started with '/',
* Copy the root path into it.
*/
-static inline xmlChar *abspath_strdup(const xmlChar *root_path, xmlChar *src, int *root_len)
+static inline xmlChar *abspath_strdup(const xmlChar *root_path, const xmlChar *src, int *root_len)
{
int _root_len = 0;
xmlChar *ptr;
+ int ptr_len;
if (!root_len) {
root_len = &_root_len;
*root_len = 0;
}
- ptr = xmlMalloc(*root_len + xmlStrlen(src) + 4);
+ ptr_len = *root_len + xmlStrlen(src) + 4;
+ ptr = xmlMalloc(ptr_len);
if (*root_len) {
- strcpy((char *)ptr, (char *)root_path);
- ptr[*root_len] = '/';
- (*root_len)++;
+ int eoc_idx;
+ strncpy((char *)ptr, (char *)root_path, ptr_len);
+ eoc_idx = *root_len;
+ while (eoc_idx > 0) {
+ if (ptr[eoc_idx - 1] != '/') {
+ ptr[eoc_idx] = '\0';
+ DbgPrint("Last trails are removed: [%s]\n", (char *)ptr);
+ break;
+ }
+ eoc_idx--;
+ }
+ if (eoc_idx == 0) {
+ ErrPrint("Root path is not valid [%s]\n", root_path);
+ }
+ *root_len = eoc_idx;
}
return ptr;
}
+static xmlChar *verify_path(const xmlChar *base, const xmlChar *preview, int check_resolution)
+{
+ xmlChar *res_path = NULL;
+ xmlChar *tmp_preview;
+ int res_len = 0;
+ int root_len = 0;
+
+ if (check_resolution) {
+ initialize_resolution();
+
+ if (s_info.resolution.initialized) {
+ char size_str[16];
+ int base_len;
+ char *delimeter;
+
+ res_len = snprintf(size_str, sizeof(size_str) - 1, "%dx%d", s_info.resolution.width, s_info.resolution.height);
+ if (res_len < 0) {
+ ErrPrint("snprintf: %d\n", errno);
+ return (xmlChar *)NULL;
+ }
+
+ base_len = xmlStrlen(base);
+ res_len += base_len + 3;
+ res_path = xmlMalloc(res_len);
+ if (!res_path) {
+ ErrPrint("xmlMalloc: %d\n", errno);
+ return (xmlChar *)NULL;
+ }
+
+ if (base_len == 0 || base[base_len - 1] != '/') {
+ delimeter = "/";
+ } else {
+ delimeter = "";
+ }
+
+ if (snprintf((char *)res_path, res_len, "%s%s%s", (char *)base, delimeter, size_str) < 0) {
+ ErrPrint("snprintf: %d\n", errno);
+ xmlFree(res_path);
+ return (xmlChar *)NULL;
+ }
+ } else {
+ ErrPrint("Resolution is not initialized\n");
+ }
+ }
+
+ if (!res_path) {
+ res_path = xmlStrdup(base);
+ }
+
+ tmp_preview = abspath_strdup(res_path, preview, &root_len);
+ xmlFree(res_path);
+ if (!tmp_preview) {
+ return (xmlChar *)NULL;
+ }
+
+ abspath((char *)preview, ((char *)tmp_preview) + root_len);
+ DbgPrint("Path: [%s]\n", (char *)tmp_preview);
+ if (access((const char *)tmp_preview, F_OK) != 0) {
+ xmlFree(tmp_preview);
+ return (xmlChar *)NULL;
+ }
+
+ return tmp_preview;
+}
+
int begin_transaction(void)
{
sqlite3_stmt *stmt;
widget->i18n_list = dlist_append(widget->i18n_list, i18n);
}
-static void update_i18n_icon(struct widget *widget, xmlNodePtr node, const xmlChar *root_path)
+static void update_i18n_icon(struct widget *widget, xmlNodePtr node, const xmlChar *root_path, const xmlChar *res_path)
{
struct i18n *i18n;
struct dlist *l;
xmlChar *lang;
xmlChar *icon;
- int root_len;
icon = xmlNodeGetContent(node);
if (!icon) {
}
i18n->icon = icon;
- icon = abspath_strdup(root_path, i18n->icon, &root_len);
+
+ /**
+ * Try to do the latest version of path resolution first.
+ */
+ icon = verify_path(res_path, i18n->icon, 0);
if (!icon) {
- ErrPrint("strdup: %d\n", errno);
- } else {
- abspath((char *)i18n->icon, ((char *)icon) + root_len);
+ icon = verify_path(root_path, i18n->icon, 0);
+ }
+
+ if (icon) {
xmlFree(i18n->icon);
i18n->icon = icon;
+ DbgPrint("Icon[%s] - [%s] replaced\n", i18n->lang, i18n->icon);
}
+
return;
}
}
}
i18n->icon = icon;
- icon = abspath_strdup(root_path, i18n->icon, &root_len);
+ /**
+ * Try to do the latest version of path resolution first.
+ */
+ icon = verify_path(res_path, i18n->icon, 0);
if (!icon) {
- ErrPrint("strdup: %d\n", errno);
- } else {
- abspath((char *)i18n->icon, ((char *)icon) + root_len);
+ icon = verify_path(root_path, i18n->icon, 0);
+ }
+
+ if (icon) {
xmlFree(i18n->icon);
i18n->icon = icon;
}
+
i18n->lang = lang;
DbgPrint("Icon[%s] - [%s] added\n", i18n->lang, i18n->icon);
widget->i18n_list = dlist_append(widget->i18n_list, i18n);
}
}
-static void update_size_info(struct widget *widget, int idx, xmlNodePtr node, const xmlChar *root_path)
+static void update_size_info(struct widget *widget, int idx, xmlNodePtr node, const xmlChar *root_path, const xmlChar *res_path)
{
if (xmlHasProp(node, (const xmlChar *)"preview")) {
xmlChar *tmp_preview;
- int root_len;
widget->preview[idx] = xmlGetProp(node, (const xmlChar *)"preview");
+
+ tmp_preview = verify_path(res_path, widget->preview[idx], 1);
+ if (!tmp_preview) {
+ tmp_preview = verify_path(root_path, widget->preview[idx], 1);
+ }
- tmp_preview = abspath_strdup(root_path, widget->preview[idx], &root_len);
if (!tmp_preview) {
- ErrPrint("strdup: %d\n", errno);
- } else {
- abspath((char *)widget->preview[idx], ((char *)tmp_preview) + root_len);
+ tmp_preview = verify_path(res_path, widget->preview[idx], 0);
+ if (!tmp_preview) {
+ tmp_preview = verify_path(root_path, widget->preview[idx], 0);
+ }
+ }
+
+ if (tmp_preview) {
xmlFree(widget->preview[idx]);
widget->preview[idx] = tmp_preview;
}
}
}
-static void update_support_size(struct widget *widget, xmlNodePtr node, const xmlChar *root_path)
+static void update_support_size(struct widget *widget, xmlNodePtr node, const xmlChar *root_path, const xmlChar *res_path)
{
xmlChar *size;
int is_easy = 0;
if (!xmlStrcasecmp(size, (const xmlChar *)"1x1")) {
if (is_easy) {
widget->size_list |= WIDGET_SIZE_TYPE_EASY_1x1;
- update_size_info(widget, 9, node, root_path);
+ update_size_info(widget, 9, node, root_path, res_path);
} else {
widget->size_list |= WIDGET_SIZE_TYPE_1x1;
- update_size_info(widget, 0, node, root_path);
+ update_size_info(widget, 0, node, root_path, res_path);
}
} else if (!xmlStrcasecmp(size, (const xmlChar *)"3x1")) {
if (is_easy) {
widget->size_list |= WIDGET_SIZE_TYPE_EASY_3x1;
- update_size_info(widget, 10, node, root_path);
+ update_size_info(widget, 10, node, root_path, res_path);
} else {
ErrPrint("Invalid size tag (%s)\n", size);
}
} else if (!xmlStrcasecmp(size, (const xmlChar *)"3x3")) {
if (is_easy) {
widget->size_list |= WIDGET_SIZE_TYPE_EASY_3x3;
- update_size_info(widget, 11, node, root_path);
+ update_size_info(widget, 11, node, root_path, res_path);
} else {
ErrPrint("Invalid size tag (%s)\n", size);
}
} else if (!xmlStrcasecmp(size, (const xmlChar *)"2x1")) {
widget->size_list |= WIDGET_SIZE_TYPE_2x1;
- update_size_info(widget, 1, node, root_path);
+ update_size_info(widget, 1, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"2x2")) {
widget->size_list |= WIDGET_SIZE_TYPE_2x2;
- update_size_info(widget, 2, node, root_path);
+ update_size_info(widget, 2, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"4x1")) {
widget->size_list |= WIDGET_SIZE_TYPE_4x1;
- update_size_info(widget, 3, node, root_path);
+ update_size_info(widget, 3, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"4x2")) {
widget->size_list |= WIDGET_SIZE_TYPE_4x2;
- update_size_info(widget, 4, node, root_path);
+ update_size_info(widget, 4, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"4x3")) {
widget->size_list |= WIDGET_SIZE_TYPE_4x3;
- update_size_info(widget, 5, node, root_path);
+ update_size_info(widget, 5, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"4x4")) {
widget->size_list |= WIDGET_SIZE_TYPE_4x4;
- update_size_info(widget, 6, node, root_path);
+ update_size_info(widget, 6, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"4x5")) {
widget->size_list |= WIDGET_SIZE_TYPE_4x5;
- update_size_info(widget, 7, node, root_path);
+ update_size_info(widget, 7, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"4x6")) {
widget->size_list |= WIDGET_SIZE_TYPE_4x6;
- update_size_info(widget, 8, node, root_path);
+ update_size_info(widget, 8, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"21x21")) {
widget->size_list |= WIDGET_SIZE_TYPE_EASY_1x1;
- update_size_info(widget, 9, node, root_path);
+ update_size_info(widget, 9, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"23x21")) {
widget->size_list |= WIDGET_SIZE_TYPE_EASY_3x1;
- update_size_info(widget, 10, node, root_path);
+ update_size_info(widget, 10, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"23x23")) {
widget->size_list |= WIDGET_SIZE_TYPE_EASY_3x3;
- update_size_info(widget, 11, node, root_path);
+ update_size_info(widget, 11, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"0x0")) {
widget->size_list |= WIDGET_SIZE_TYPE_FULL;
- update_size_info(widget, 12, node, root_path);
+ update_size_info(widget, 12, node, root_path, res_path);
} else {
ErrPrint("Invalid size tag (%s)\n", size);
}
xmlFree(size);
}
-static void update_box(struct widget *widget, xmlNodePtr node, const xmlChar *root_path)
+static void update_box(struct widget *widget, xmlNodePtr node, const xmlChar *root_path, const xmlChar *res_path)
{
int root_len;
if (!xmlStrcasecmp(size, (const xmlChar *)"1x1")) {
if (is_easy) {
widget->size_list |= WIDGET_SIZE_TYPE_EASY_1x1;
- update_size_info(widget, 9, node, root_path);
+ update_size_info(widget, 9, node, root_path, res_path);
} else {
widget->size_list |= WIDGET_SIZE_TYPE_1x1;
- update_size_info(widget, 0, node, root_path);
+ update_size_info(widget, 0, node, root_path, res_path);
}
} else if (!xmlStrcasecmp(size, (const xmlChar *)"3x1")) {
if (is_easy) {
widget->size_list |= WIDGET_SIZE_TYPE_EASY_3x1;
- update_size_info(widget, 10, node, root_path);
+ update_size_info(widget, 10, node, root_path, res_path);
} else {
ErrPrint("Invalid size tag (%s)\n", size);
}
} else if (!xmlStrcasecmp(size, (const xmlChar *)"3x3")) {
if (is_easy) {
widget->size_list |= WIDGET_SIZE_TYPE_EASY_3x3;
- update_size_info(widget, 11, node, root_path);
+ update_size_info(widget, 11, node, root_path, res_path);
} else {
ErrPrint("Invalid size tag (%s)\n", size);
}
} else if (!xmlStrcasecmp(size, (const xmlChar *)"2x1")) {
widget->size_list |= WIDGET_SIZE_TYPE_2x1;
- update_size_info(widget, 1, node, root_path);
+ update_size_info(widget, 1, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"2x2")) {
widget->size_list |= WIDGET_SIZE_TYPE_2x2;
- update_size_info(widget, 2, node, root_path);
+ update_size_info(widget, 2, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"4x1")) {
widget->size_list |= WIDGET_SIZE_TYPE_4x1;
- update_size_info(widget, 3, node, root_path);
+ update_size_info(widget, 3, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"4x2")) {
widget->size_list |= WIDGET_SIZE_TYPE_4x2;
- update_size_info(widget, 4, node, root_path);
+ update_size_info(widget, 4, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"4x3")) {
widget->size_list |= WIDGET_SIZE_TYPE_4x3;
- update_size_info(widget, 5, node, root_path);
+ update_size_info(widget, 5, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"4x4")) {
widget->size_list |= WIDGET_SIZE_TYPE_4x4;
- update_size_info(widget, 6, node, root_path);
+ update_size_info(widget, 6, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"4x5")) {
widget->size_list |= WIDGET_SIZE_TYPE_4x5;
- update_size_info(widget, 7, node, root_path);
+ update_size_info(widget, 7, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"4x6")) {
widget->size_list |= WIDGET_SIZE_TYPE_4x6;
- update_size_info(widget, 8, node, root_path);
+ update_size_info(widget, 8, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"21x21")) {
widget->size_list |= WIDGET_SIZE_TYPE_EASY_1x1;
- update_size_info(widget, 9, node, root_path);
+ update_size_info(widget, 9, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"23x21")) {
widget->size_list |= WIDGET_SIZE_TYPE_EASY_3x1;
- update_size_info(widget, 10, node, root_path);
+ update_size_info(widget, 10, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"23x23")) {
widget->size_list |= WIDGET_SIZE_TYPE_EASY_3x3;
- update_size_info(widget, 11, node, root_path);
+ update_size_info(widget, 11, node, root_path, res_path);
} else if (!xmlStrcasecmp(size, (const xmlChar *)"0x0")) {
widget->size_list |= WIDGET_SIZE_TYPE_FULL;
- update_size_info(widget, 12, node, root_path);
+ update_size_info(widget, 12, node, root_path, res_path);
} else {
ErrPrint("Invalid size tag (%s)\n", size);
}
xmlChar *pkgid;
xmlChar *tmp;
xmlChar *root_path;
+ xmlChar *res_path;
+ int res_path_len;
root_path = pkgmgr_get_root_path(appid);
DbgPrint("RootPath is %s\n", (char *)root_path);
+ res_path_len = xmlStrlen(root_path) + strlen(SHARED_RES_PATH) + 2;
+ res_path = xmlMalloc(res_path_len);
+ if (!res_path) {
+ ErrPrint("Unable to allocate heap for shared res path\n");
+ xmlFree(root_path);
+ return -ENOMEM;
+ }
+
+ if (snprintf((char *)res_path, res_path_len - 1, "%s"SHARED_RES_PATH, root_path) < 0) {
+ ErrPrint("Unable to prepare res_path: %d\n", errno);
+ xmlFree(root_path);
+ xmlFree(res_path);
+ return -EFAULT;
+ }
+ DbgPrint("ResPath is %s\n", res_path);
if (!xmlHasProp(node, (const xmlChar *)"appid")) {
ErrPrint("Missing appid\n");
xmlFree(root_path);
+ xmlFree(res_path);
return -EINVAL;
}
ErrPrint("Invalid appid\n");
xmlFree(pkgid);
xmlFree(root_path);
+ xmlFree(res_path);
return -EINVAL;
}
ErrPrint("calloc: %d\n", errno);
xmlFree(pkgid);
xmlFree(root_path);
+ xmlFree(res_path);
return -ENOMEM;
}
ErrPrint("ABI is NIL\n");
widget_destroy(widget);
xmlFree(root_path);
+ xmlFree(res_path);
return -EFAULT;
}
}
ErrPrint("libexec is NIL\n");
widget_destroy(widget);
xmlFree(root_path);
+ xmlFree(res_path);
return -EFAULT;
}
ErrPrint("strdup: %d\n", errno);
widget_destroy(widget);
xmlFree(root_path);
+ xmlFree(res_path);
return -EFAULT;
}
ErrPrint("xmlstrdup: %d\n", errno);
widget_destroy(widget);
xmlFree(root_path);
+ xmlFree(res_path);
return -ENOMEM;
}
} else if (xmlStrcasecmp(widget->abi, (const xmlChar *)"c") && xmlStrcasecmp(widget->abi, (const xmlChar *)"cpp")) {
ErrPrint("libexec is NIL\n");
widget_destroy(widget);
xmlFree(root_path);
+ xmlFree(res_path);
return -EFAULT;
}
ErrPrint("strdup: %d\n", errno);
widget_destroy(widget);
xmlFree(root_path);
+ xmlFree(res_path);
return -EFAULT;
}
ErrPrint("xmlstrdup: %d\n", errno);
widget_destroy(widget);
xmlFree(root_path);
+ xmlFree(res_path);
return -ENOMEM;
}
} else if (xmlStrcasecmp(widget->abi, (const xmlChar *)"app")) {
}
if (!xmlStrcasecmp(node->name, (const xmlChar *)"icon")) {
- update_i18n_icon(widget, node, root_path);
+ update_i18n_icon(widget, node, root_path, res_path);
continue;
}
if (!xmlStrcasecmp(node->name, (const xmlChar *)"box")) {
- update_box(widget, node, root_path);
+ update_box(widget, node, root_path, res_path);
continue;
}
if (!xmlStrcasecmp(node->name, (const xmlChar *)"support-size")) {
- update_support_size(widget, node, root_path);
+ update_support_size(widget, node, root_path, res_path);
continue;
}
if (update_category(widget, node) < 0) {
widget_destroy(widget);
xmlFree(root_path);
+ xmlFree(res_path);
return -EINVAL;
}
}
xmlFree(root_path);
+ xmlFree(res_path);
return db_insert_widget(widget, appid);
}
struct widget *widget;
xmlChar *pkgid;
xmlChar *root_path;
+ xmlChar *res_path;
+ int res_path_len;
root_path = pkgmgr_get_root_path(appid);
DbgPrint("RootPath is %s\n", root_path);
+ res_path_len = xmlStrlen(root_path) + strlen(SHARED_RES_PATH) + 2;
+ res_path = xmlMalloc(res_path_len);
+ if (!res_path) {
+ ErrPrint("Unable to allocate heap for shared res path\n");
+ xmlFree(root_path);
+ return -ENOMEM;
+ }
+
+ if (snprintf((char *)res_path, res_path_len - 1, "%s"SHARED_RES_PATH, root_path) < 0) {
+ ErrPrint("Unable to prepare res_path: %d\n", errno);
+ xmlFree(root_path);
+ xmlFree(res_path);
+ return -EFAULT;
+ }
+ DbgPrint("ResPath is %s\n", res_path);
if (!xmlHasProp(node, (const xmlChar *)"appid")) {
ErrPrint("Missing appid\n");
xmlFree(root_path);
+ xmlFree(res_path);
return -EINVAL;
}
ErrPrint("Invalid appid\n");
xmlFree(pkgid);
xmlFree(root_path);
+ xmlFree(res_path);
return -EINVAL;
}
ErrPrint("strdup: %d\n", errno);
xmlFree(pkgid);
xmlFree(root_path);
+ xmlFree(res_path);
return -ENOMEM;
}
ErrPrint("libexec is NIL\n");
widget_destroy(widget);
xmlFree(root_path);
+ xmlFree(res_path);
return -EFAULT;
}
}
}
if (!xmlStrcasecmp(node->name, (const xmlChar *)"icon")) {
- update_i18n_icon(widget, node, root_path);
+ update_i18n_icon(widget, node, root_path, res_path);
continue;
}
}
xmlFree(root_path);
+ xmlFree(res_path);
return db_insert_widget(widget, appid);
}