/* * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "data/datamgr.h" struct folderdata; typedef bool (*get_media_list)(struct folderdata *fd, void *data); typedef int (*media_compare)(struct group_info *gi, app_media_info *info); typedef void *(*media_compare_data_get)(app_media_info *info); typedef char *(*group_name_get)(app_media_info *info); static bool _get_media_name_list(struct folderdata *fd, void *data); static int _compare_cb_name(const void *, const void *); static int _compare_title(struct group_info *, app_media_info *); static char *_get_title(app_media_info *); static void *_get_data_title(app_media_info *info); enum _filter_type { E_FILTER_FOLDER = 0, E_FILTER_MEDIA }; struct folderdata { Eina_List *folder_list; Eina_List *media_list; char *parent_id; const char *media_type; int source_type; }; struct _list_info { get_media_list get_list; Eina_Compare_Cb sort_cmp_cb; media_compare media_cmp; media_compare_data_get data_get; group_name_get name_get; }; static struct _list_info g_group_info[E_GROUP_FOLDER_MAX] = { [E_GROUP_FOLDER_MEDIA_NAME] = { .get_list = _get_media_name_list, .sort_cmp_cb = _compare_cb_name, .media_cmp = _compare_title, .name_get = _get_title, .data_get = _get_data_title, }, }; static bool _create_filter(struct folderdata *fd, filter_h *filter, const char *cond, int filter_type) { filter_h tmp_filter; int ret; char buf[1024]; ret = media_filter_create(&tmp_filter); if (ret != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to create media filter"); return false; } if (filter_type == E_FILTER_FOLDER) { if (cond) snprintf(buf, sizeof(buf), "%s", cond); media_filter_set_order(tmp_filter, MEDIA_CONTENT_ORDER_ASC, FOLDER_NAME, MEDIA_CONTENT_COLLATE_DEFAULT); } else { snprintf(buf, sizeof(buf), "%s", fd->media_type); if (fd->source_type != E_SOURCE_ALL) { char s1[256]; snprintf(s1, sizeof(s1), " AND MEDIA_STORAGE_TYPE=%d", fd->source_type); strncat(buf, s1, strlen(s1)); } if (cond) { char s2[256]; snprintf(s2, sizeof(s2), " AND %s", cond); strncat(buf, s2, strlen(s2)); } media_filter_set_order(tmp_filter, MEDIA_CONTENT_ORDER_ASC, MEDIA_TITLE, MEDIA_CONTENT_COLLATE_DEFAULT); } media_filter_set_condition(tmp_filter, buf, MEDIA_CONTENT_COLLATE_DEFAULT); *filter = tmp_filter; return true; } static int _compare_cb_name(const void *data1, const void *data2) { app_media *am1, *am2; app_media_info *mi1, *mi2; am1 = (app_media *)data1; am2 = (app_media *)data2; mi1 = app_media_get_info(am1); mi2 = app_media_get_info(am2); if (!mi1 || !mi2 || !mi1->title || !mi2->title) return -1; return strcasecmp(mi1->title, mi2->title); } static int _compare_title(struct group_info *gi, app_media_info *mi) { if (!gi->data || !mi->title) return -1; return strncasecmp(gi->data, mi->title, 1); } static void *_get_data_title(app_media_info *mi) { if (!mi->title) return NULL; return strdup(mi->title); } static char *_get_title(app_media_info *mi) { if (!mi->title) return NULL; return strndup(mi->title, 1); } static void _destroy_folder_info(struct folder_info *fi) { free(fi->id); free(fi->name); free(fi->path); free(fi); } static void _destroy_folder_list(Eina_List *list) { struct folder_info *fi; EINA_LIST_FREE(list, fi) _destroy_folder_info(fi); } static void _destroy_media_list(Eina_List *list) { app_media *am; EINA_LIST_FREE(list, am) app_media_destroy(am); } static bool _get_folder_id(media_folder_h folder, void *data) { struct folderdata *fd; if (!data) return false; fd = data; if (media_folder_get_folder_id(folder, &(fd->parent_id)) != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to fetch folder id"); return false; } return true; } static bool _get_each_folder_info(media_folder_h folder, void *data) { filter_h filter; struct folderdata *fd; struct folder_info *fi; if (!data) return false; fd = data; fi = calloc(1, sizeof(*fi)); if (!fi) { _ERR("failed to allocate memory"); return false; } if (!_create_filter(fd, &filter, NULL, E_FILTER_MEDIA)) { _ERR("failed to create filter"); free(fi); return false; } if (media_folder_get_folder_id(folder, &(fi->id)) != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to fetch folder id"); goto err; } if (media_folder_get_name(folder, &(fi->name)) != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to fetch folder name"); goto err; } if (media_folder_get_path(folder, &(fi->path)) != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to fetch folder path"); goto err; } if (media_folder_get_media_count_from_db(fi->id, filter, &(fi->count)) != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to get media count"); goto err; } fd->folder_list = eina_list_append(fd->folder_list, fi); media_filter_destroy(filter); return true; err: media_filter_destroy(filter); _destroy_folder_info(fi); return false; } static bool _get_each_media_info(media_info_h media_h, void *data) { struct folderdata *fd; app_media *am; if (!data) return false; fd = data; am = app_media_create(media_h); if (!am) { _ERR("failed to create app media"); return false; } fd->media_list = eina_list_append(fd->media_list, am); return true; } static bool _find_folder_id(struct folderdata *fd, const char *path) { filter_h filter; int ret; char buf[1024]; snprintf(buf, sizeof(buf), "FOLDER_PATH=\"%s\"", path); if (!_create_filter(fd, &filter, buf, E_FILTER_FOLDER)) { _ERR("failed to create filter"); return false; } ret = media_folder_foreach_folder_from_db(filter, _get_folder_id, fd); if (ret != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to get folder info"); media_filter_destroy(filter); return false; } media_filter_destroy(filter); return true; } static bool _get_sub_folder_list(struct folderdata *fd, const char *cond) { filter_h filter; int ret; if (!_create_filter(fd, &filter, cond, E_FILTER_FOLDER)) { _ERR("failed to create filter"); return false; } ret = media_folder_foreach_folder_from_db(filter, _get_each_folder_info, fd); if (ret != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to get folder info"); _destroy_folder_list(fd->folder_list); media_filter_destroy(filter); return false; } media_filter_destroy(filter); return true; } static bool _get_folder_list(struct folderdata *fd, char **path) { int ret; int i; char buf[1024] = {0,}; ret = media_content_connect(); if (ret != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to connect to media content"); return false; } i = 0; while (path[i++]) { char s[128]; if (!_find_folder_id(fd, path[i])) { _ERR("failed to find folder id"); media_content_disconnect(); return false; } //FIXME change a method of loading subfolder //due to deprecation of FOLDER_PARENT_FOLDER_ID if (strlen(buf)) { snprintf(s, sizeof(s), " OR FOLDER_PARENT_FOLDER_ID=\"%s\"", fd->parent_id); } else { snprintf(s, sizeof(s), "FOLDER_PARENT_FOLDER_ID=\"%s\"", fd->parent_id); } strncat(buf, s, strlen(s)); } if (!_get_sub_folder_list(fd, buf)) { _ERR("failed to get child folder list"); media_content_disconnect(); return false; } media_content_disconnect(); return true; } static bool _get_media_name_list(struct folderdata *fd, void *data) { filter_h filter; int ret; int i; char **path; path = data; if (fd->media_list) { _destroy_media_list(fd->media_list); fd->media_list = NULL; } ret = media_content_connect(); if (ret != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to connect to media content"); return false; } if (!_create_filter(fd, &filter, NULL, E_FILTER_MEDIA)) { _ERR("failed to create filter"); media_content_disconnect(); return false; } i = 0; while (path[i++]) { if (!_find_folder_id(fd, path[i])) { _ERR("failed to find folder id"); media_filter_destroy(filter); media_content_disconnect(); return false; } ret = media_folder_foreach_media_from_db(fd->parent_id, filter, _get_each_media_info, fd); if (ret != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to get media info"); _destroy_media_list(fd->media_list); media_filter_destroy(filter); media_content_disconnect(); return false; } } media_filter_destroy(filter); media_content_disconnect(); return true; } static void *_create(const char *media_type, int source_type) { struct folderdata *fd; if (!media_type) { _ERR("invalid argument"); return NULL; } fd = calloc(1, sizeof(*fd)); if (!fd) { _ERR("failed to allocate fd"); return NULL; } fd->media_type = media_type; fd->source_type = source_type; return (void *)fd; } static void _destroy(void *handle) { struct folderdata *fd; if (!handle) { _ERR("failed to get folderdata handle"); return; } fd = handle; _destroy_folder_list(fd->folder_list); _destroy_media_list(fd->media_list); free(fd->parent_id); free(fd); } static Eina_List *_get_list(void *handle, int type, void *data) { struct folderdata *fd; char **path; if (!handle) { _ERR("failed to get folderdata handle"); return NULL; } fd = handle; switch (type) { case E_LIST_FOLDER: path = data; _get_folder_list(fd, path); return fd->folder_list; default: break; } return NULL; } static int _get_count(void *handle, int type) { struct folderdata *fd; if (!handle) { _ERR("failed to get folderdata handle"); return -1; } fd = handle; return eina_list_count(fd->folder_list); } static void _free_group_list(Eina_List *list) { struct group_info *gi; EINA_LIST_FREE(list, gi) { free(gi->name); free(gi->data); _destroy_media_list(gi->list); free(gi); } } static void _free_group(Eina_List *list) { _free_group_list(list); } static Eina_List *_sort_list(Eina_List *list, int sort) { Eina_List *sorted_list; sorted_list = eina_list_sort(list, 0, g_group_info[sort].sort_cmp_cb); return sorted_list; } static Eina_List *_get_group(void *handle, int type, void *data) { Eina_List *list, *l; struct folderdata *fd; struct group_info *gi; app_media *am; app_media_info *mi; if (!handle) { _ERR("failed to get folderdata handle"); return NULL; } if (type < 0 || type >= E_GROUP_FOLDER_MAX || !data) { _ERR("invalid argument"); return NULL; } fd = handle; if (!g_group_info[type].get_list(fd, data)) { _ERR("failed to get list"); return NULL; } fd->media_list = _sort_list(fd->media_list, type); gi = NULL; list = NULL; EINA_LIST_FOREACH(fd->media_list, l, am) { mi = app_media_get_info(am); if (!mi) { _ERR("failed to get media info"); _free_group_list(list); return NULL; } if (!gi || g_group_info[type].media_cmp(gi, mi)) { gi = calloc(1, sizeof(*gi)); if (!gi) { _ERR("failed to create group info"); _free_group_list(list); return NULL; } gi->name = g_group_info[type].name_get(mi); gi->data = g_group_info[type].data_get(mi); list = eina_list_append(list, gi); } gi->list = eina_list_append(gi->list, am); } return list; } static void _set_source(void *handle, int source_type) { struct folderdata *fd; if (!handle) { _ERR("failed to get folderdata handle"); return; } fd = handle; fd->source_type = source_type; } static struct data_ops _ops = { .create = _create, .destroy = _destroy, .get_list = _get_list, .get_count = _get_count, .get_group = _get_group, .free_group = _free_group, .set_source = _set_source, }; struct data_ops *folderdata_get_ops(void) { return &_ops; };