Use get_image_info instead
[platform/core/multimedia/libmedia-service.git] / src / common / media-svc-util.c
1 /*
2  * libmedia-service
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <fcntl.h>
24 #include <sys/stat.h>
25 #include <sys/vfs.h>
26 #include <ctype.h>
27 #include <aul/aul.h>
28 #include <mm_file.h>
29 #include <libexif/exif-data.h>
30 #include <media-util.h>
31 #include <uuid/uuid.h>
32 #include <media-thumbnail.h>
33 #include "media-svc-util.h"
34 #include "media-svc-db-utils.h"
35 #include "media-svc-debug.h"
36 #include "media-svc-env.h"
37 #include "media-svc-album.h"
38 /*For ebook metadata */
39 #include <zip.h>
40 #include <libxml/xmlmemory.h>
41 #include <libxml/parser.h>
42 #include <libxml/HTMLparser.h>
43 #include <dlfcn.h>
44
45 #define MEDIA_SVC_FILE_EXT_LEN_MAX                              6                       /**< Maximum file ext lenth*/
46
47 #define MUSIC_MIME_NUM 29
48 #define SOUND_MIME_NUM 2
49 #define MIME_LENGTH 50
50 #define MEDIA_SVC_DEFAULT_FORMAT_LEN 19
51 #define IMAGE_PREFIX "image/"
52 #define IMAGE_PREFIX_LEN 6
53 #define AUDIO_PREFIX "audio/"
54 #define AUDIO_PREFIX_LEN 6
55 #define VIDEO_PREFIX "video/"
56 #define VIDEO_PREFIX_LEN 6
57
58 #define MEDIA_SVC_PDF_TAG_TAIL_LEN 12
59 #define MEDIA_SVC_PDF_BUF_SIZE 256
60
61 #define MEDIA_SVC_THUMB_WIDTH 320
62 #define MEDIA_SVC_THUMB_HEIGHT 240
63
64 #define PATH_PLUGIN_LIB                         PATH_LIBDIR"/libmedia-ebook-plugin.so"
65
66 enum Exif_Orientation {
67         NOT_AVAILABLE = 0,
68         NORMAL = 1,
69         HFLIP = 2,
70         ROT_180 = 3,
71         VFLIP = 4,
72         TRANSPOSE = 5,
73         ROT_90 = 6,
74         TRANSVERSE = 7,
75         ROT_270 = 8
76 };
77
78 static const char music_mime_table[MUSIC_MIME_NUM][MIME_LENGTH] = {
79         /*known mime types of normal files*/
80         "mpeg",
81         "ogg",
82         "x-ms-wma",
83         "x-flac",
84         "mp4",
85         "mp3",
86         "x-mp3", /*alias of audio/mpeg*/
87         "x-mpeg", /*alias of audio/mpeg*/
88         "3gpp",
89         "x-ogg", /*alias of audio/ogg*/
90         "vnd.ms-playready.media.pya:*.pya", /*playready*/
91         "wma",
92         "aac",
93         "x-m4a", /*alias of audio/mp4*/
94         /* below mimes are rare*/
95         "x-vorbis+ogg",
96         "x-flac+ogg",
97         "x-matroska",
98         "ac3",
99         "mp2",
100         "x-ape",
101         "x-ms-asx",
102         "vnd.rn-realaudio",
103
104         "x-vorbis", /*alias of audio/x-vorbis+ogg*/
105         "vorbis", /*alias of audio/x-vorbis+ogg*/
106         "x-oggflac",
107         "x-mp2", /*alias of audio/mp2*/
108         "x-pn-realaudio", /*alias of audio/vnd.rn-realaudio*/
109         "vnd.m-realaudio", /*alias of audio/vnd.rn-realaudio*/
110         "x-wav",
111 };
112
113 static const char sound_mime_table[SOUND_MIME_NUM][MIME_LENGTH] = {
114         "application/x-smaf",
115         "text/x-iMelody"
116 };
117
118 static char *__media_info_generate_uuid(void)
119 {
120         uuid_t uuid_value;
121         char uuid_unparsed[37];
122
123 RETRY_GEN:
124         uuid_generate(uuid_value);
125         uuid_unparse(uuid_value, uuid_unparsed);
126
127         if (strlen(uuid_unparsed) < 36) {
128                 media_svc_debug("INVALID UUID : %s. RETRY GENERATE.", uuid_unparsed);
129                 goto RETRY_GEN;
130         }
131
132         return g_strdup(uuid_unparsed);
133 }
134
135 static int __media_svc_get_exif_info(ExifData *ed, char *buf, int *i_value, ExifTag tagtype)
136 {
137         ExifEntry *entry;
138         ExifByteOrder mByteOrder;
139
140         media_svc_retv_if(!ed, MS_MEDIA_ERR_INVALID_PARAMETER);
141
142         entry = exif_data_get_entry(ed, tagtype);
143         media_svc_retv_if(!entry, MS_MEDIA_ERR_NONE);
144
145         switch (tagtype) {
146         case EXIF_TAG_ORIENTATION:
147         case EXIF_TAG_PIXEL_X_DIMENSION:
148         case EXIF_TAG_PIXEL_Y_DIMENSION:
149                 media_svc_retvm_if(!i_value, MS_MEDIA_ERR_INVALID_PARAMETER, "i_value is NULL");
150
151                 mByteOrder = exif_data_get_byte_order(ed);
152                 short exif_value = exif_get_short(entry->data, mByteOrder);
153                 *i_value = (int)exif_value;
154                 break;
155         default:
156                 media_svc_retvm_if(!buf, MS_MEDIA_ERR_INVALID_PARAMETER, "buf is NULL");
157
158                 exif_entry_get_value(entry, buf, MEDIA_SVC_METADATA_LEN_MAX);
159                 buf[strlen(buf)] = '\0';
160         }
161
162         return MS_MEDIA_ERR_NONE;
163 }
164
165 static int __media_svc_get_media_type(const char *path, const char *mime_type, media_svc_media_type_e *media_type)
166 {
167         int idx = 0;
168         int audio = 0;
169         int video = 0;
170
171         media_svc_retvm_if(!path, MS_MEDIA_ERR_INVALID_PARAMETER, "path is null");
172         media_svc_retvm_if(!mime_type, MS_MEDIA_ERR_INVALID_PARAMETER, "mime_type is null");
173         media_svc_retvm_if(!media_type, MS_MEDIA_ERR_INVALID_PARAMETER, "media_type is null");
174
175         /* Image */
176         if (strncmp(mime_type, IMAGE_PREFIX, IMAGE_PREFIX_LEN) == 0) {
177                 *media_type = MEDIA_SVC_MEDIA_TYPE_IMAGE;
178                 return MS_MEDIA_ERR_NONE;
179         }
180
181         /* Audio */
182         if (strncmp(mime_type, AUDIO_PREFIX, AUDIO_PREFIX_LEN) == 0) {
183                 *media_type = MEDIA_SVC_MEDIA_TYPE_SOUND;
184
185                 for (idx = 0; idx < MUSIC_MIME_NUM; idx++) {
186                         if (strcmp(mime_type + AUDIO_PREFIX_LEN, music_mime_table[idx]) == 0) {
187                                 *media_type = MEDIA_SVC_MEDIA_TYPE_MUSIC;
188                                 break;
189                         }
190                 }
191
192                 /* audio/x-mpegurl : .m3u file (playlist file) */
193                 if (strcmp(mime_type + AUDIO_PREFIX_LEN, "x-mpegurl") == 0)
194                         *media_type = MEDIA_SVC_MEDIA_TYPE_OTHER;
195
196                 return MS_MEDIA_ERR_NONE;
197         }
198
199         /* Video */
200         if (strncmp(mime_type, VIDEO_PREFIX, VIDEO_PREFIX_LEN) == 0) {
201                 *media_type = MEDIA_SVC_MEDIA_TYPE_VIDEO;
202
203                 /*some video files don't have video stream. in this case it is categorize as music. */
204                 if (strcmp(mime_type + VIDEO_PREFIX_LEN, "3gpp") == 0 ||
205                         strcmp(mime_type + VIDEO_PREFIX_LEN, "mp4") == 0) {
206                         if (mm_file_get_stream_info(path, &audio, &video) == FILEINFO_ERROR_NONE) {
207                                 if (audio > 0 && video == 0)
208                                         *media_type = MEDIA_SVC_MEDIA_TYPE_MUSIC;
209                         }
210                 }
211
212                 return MS_MEDIA_ERR_NONE;
213         }
214
215         /* ETC */
216         *media_type = MEDIA_SVC_MEDIA_TYPE_OTHER;
217
218         for (idx = 0; idx < SOUND_MIME_NUM; idx++) {
219                 if (strcmp(mime_type, sound_mime_table[idx]) == 0) {
220                         *media_type = MEDIA_SVC_MEDIA_TYPE_SOUND;
221                         return MS_MEDIA_ERR_NONE;
222                 }
223         }
224
225         /*"asf" must check video stream and then categorize in directly. */
226         if (strcmp(mime_type, "application/vnd.ms-asf") == 0) {
227                 if (mm_file_get_stream_info(path, &audio, &video) == FILEINFO_ERROR_NONE) {
228                         if (audio > 0 && video == 0)
229                                 *media_type = MEDIA_SVC_MEDIA_TYPE_MUSIC;
230                         else
231                                 *media_type = MEDIA_SVC_MEDIA_TYPE_VIDEO;
232                 }
233
234                 return MS_MEDIA_ERR_NONE;
235         }
236
237         if (strcmp(mime_type, "application/epub+zip") == 0 || strcmp(mime_type, "application/pdf") == 0)
238                 *media_type = MEDIA_SVC_MEDIA_TYPE_BOOK;
239
240         return MS_MEDIA_ERR_NONE;
241 }
242
243 static int __media_svc_get_mime_type(const char *path, char *mimetype)
244 {
245         media_svc_retvm_if(path == NULL, MS_MEDIA_ERR_INVALID_PARAMETER, "path is NULL");
246
247         if (aul_get_mime_from_file(path, mimetype, 255) < 0) {
248                 media_svc_error("aul_get_mime_from_file fail");
249                 return MS_MEDIA_ERR_INTERNAL;
250         }
251
252         return MS_MEDIA_ERR_NONE;
253 }
254
255 static bool __media_svc_get_file_ext(const char *file_path, char *file_ext)
256 {
257         int i = 0;
258
259         for (i = strlen(file_path); i >= 0; i--) {
260                 if (file_path[i] == '.') {
261                         SAFE_STRLCPY(file_ext, &file_path[i + 1], MEDIA_SVC_FILE_EXT_LEN_MAX);
262                         return true;
263                 }
264
265                 if (file_path[i] == '/')
266                         return false;
267         }
268         return false;
269 }
270
271 static int __media_svc_safe_atoi(char *buffer, int *si)
272 {
273         char *end = NULL;
274         errno = 0;
275         media_svc_retvm_if(buffer == NULL || si == NULL, MS_MEDIA_ERR_INTERNAL, "invalid parameter");
276
277         const long sl = strtol(buffer, &end, 10);
278
279         media_svc_retvm_if(end == buffer, MS_MEDIA_ERR_INTERNAL, "not a decimal number");
280         media_svc_retvm_if('\0' != *end, MS_MEDIA_ERR_INTERNAL, "extra characters at end of input: %s", end);
281         media_svc_retvm_if((LONG_MIN == sl || LONG_MAX == sl) && (ERANGE == errno), MS_MEDIA_ERR_INTERNAL, "out of range of type long");
282         media_svc_retvm_if(sl > INT_MAX, MS_MEDIA_ERR_INTERNAL, "greater than INT_MAX");
283         media_svc_retvm_if(sl < INT_MIN, MS_MEDIA_ERR_INTERNAL, "less than INT_MIN");
284
285         *si = (int)sl;
286
287         return MS_MEDIA_ERR_NONE;
288 }
289
290 static int __media_svc_save_image(unsigned char *image, unsigned int size, char *image_path, uid_t uid)
291 {
292         int ret = MS_MEDIA_ERR_NONE;
293         struct statfs fs;
294         char *thumb_path = NULL;
295         long bsize_kbytes = 0;
296         GError *error = NULL;
297
298         media_svc_retvm_if(!image || size == 0, MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid image");
299         media_svc_sec_debug("start save image, path [%s] image size [%d]", image_path, size);
300
301         ret = ms_user_get_root_thumb_store_path(uid, &thumb_path);
302         media_svc_retvm_if(ret != MS_MEDIA_ERR_NONE, ret, "ms_user_get_root_thumb_store_path error");
303
304         ret = statfs(thumb_path, &fs);
305         g_free(thumb_path);
306         media_svc_retvm_if(ret == -1, MS_MEDIA_ERR_INTERNAL, "statfs failed");
307
308         bsize_kbytes = fs.f_bsize >> 10;
309         media_svc_retvm_if((bsize_kbytes * fs.f_bavail) < 1024, MS_MEDIA_ERR_NOT_ENOUGH_SPACE, "Not enough space");
310
311         if (!g_file_set_contents(image_path, (const gchar *)image, (gssize)size, &error)) {
312                 media_svc_error("g_file_set_contents faild:%s", error->message);
313                 g_error_free(error);
314                 return MS_MEDIA_ERR_INTERNAL;
315         }
316
317         return MS_MEDIA_ERR_NONE;
318 }
319
320 static char *__media_svc_get_title_from_filename(const char *filename)
321 {
322         char *title = NULL;
323         char *last_dot = NULL;
324
325         media_svc_retvm_if(!STRING_VALID(filename), g_strdup(MEDIA_SVC_TAG_UNKNOWN), "Invalid path");
326
327         last_dot = strrchr(filename, '.');
328         if (last_dot) {
329                 title = g_strndup(filename, last_dot - filename);
330         } else {
331                 title = g_strdup(filename);
332         }
333
334         media_svc_debug("extract title is [%s]", title);
335
336         return title;
337 }
338
339 void _media_svc_remove_file(const char *path)
340 {
341         if (!STRING_VALID(path))
342                 return;
343
344         if (remove(path) != 0)
345                 media_svc_stderror("fail to remove file result");
346 }
347
348 static int __media_svc_get_thumbnail_path(char *thumb_path, const char *pathname, const char *img_format, uid_t uid)
349 {
350         int ret = MS_MEDIA_ERR_NONE;
351         char file_ext[MEDIA_SVC_FILE_EXT_LEN_MAX + 1] = {0, };
352         g_autofree gchar *hash = NULL;
353         g_autofree gchar *thumb_dir = NULL;
354
355         ret = ms_user_get_root_thumb_store_path(uid, &thumb_dir);
356         media_svc_retvm_if(!STRING_VALID(thumb_dir), ret, "ms_user_get_root_thumb_store_path failed");
357         media_svc_retvm_if(!g_file_test(thumb_dir, G_FILE_TEST_IS_DIR), MS_MEDIA_ERR_INTERNAL, "Not a directory");
358
359         memset(file_ext, 0, sizeof(file_ext));
360         if (!__media_svc_get_file_ext(pathname, file_ext))
361                 media_svc_error("get file ext fail");
362
363         hash = g_compute_checksum_for_string(G_CHECKSUM_MD5, pathname, -1);
364         media_svc_retvm_if(!hash, MS_MEDIA_ERR_INTERNAL, "Failed to create hashname");
365
366         if (img_format) {
367                 /* 'img_format' is mime-type */
368                 if (!g_str_has_prefix(img_format, IMAGE_PREFIX) || strlen(img_format) == IMAGE_PREFIX_LEN) {
369                         media_svc_error("Not proper img format");
370                         return MS_MEDIA_ERR_INTERNAL;
371                 }
372
373                 snprintf(thumb_path, MEDIA_SVC_PATHNAME_SIZE, "%s/.%s-%s.%s", thumb_dir, file_ext, hash, img_format + IMAGE_PREFIX_LEN);
374         } else {
375                 if (strcasecmp(file_ext, "PNG") == 0)
376                         snprintf(thumb_path, MEDIA_SVC_PATHNAME_SIZE, "%s/.%s-%s.png", thumb_dir, file_ext, hash);
377                 else
378                         snprintf(thumb_path, MEDIA_SVC_PATHNAME_SIZE, "%s/.%s-%s.jpg", thumb_dir, file_ext, hash);
379         }
380
381         return MS_MEDIA_ERR_NONE;
382 }
383
384 int _media_svc_get_file_time(const char *full_path)
385 {
386         struct stat statbuf = { 0, };
387
388         if (stat(full_path, &statbuf) == -1) {
389                 media_svc_stderror("stat fails.");
390                 return 0;
391         }
392
393         return statbuf.st_mtime;
394 }
395
396 int _media_svc_set_media_info(media_svc_content_info_s *content_info, const char *storage_id, const char *path, bool refresh)
397 {
398         int ret = MS_MEDIA_ERR_NONE;
399         char mime_type[256] = {0, };
400         media_svc_media_type_e media_type;
401
402         media_svc_retvm_if(!STRING_VALID(path), MS_MEDIA_ERR_INVALID_PARAMETER, "path is NULL");
403
404         content_info->path = g_strdup(path);
405         media_svc_retv_del_if(content_info->path == NULL, MS_MEDIA_ERR_INTERNAL, content_info);
406
407         struct stat st;
408         memset(&st, 0, sizeof(struct stat));
409         if (stat(path, &st) == 0) {
410                 content_info->modified_time = st.st_mtime;
411                 content_info->timeline = content_info->modified_time;
412                 content_info->size = st.st_size;
413         } else {
414                 media_svc_stderror("stat failed");
415         }
416
417         /* refresh is TRUE when file modified. so only modified_time and size are changed*/
418         if (refresh) {
419                 media_svc_debug("refresh");
420                 return MS_MEDIA_ERR_NONE;
421         }
422
423         content_info->storage_uuid = g_strdup(storage_id);
424         media_svc_retv_del_if(content_info->storage_uuid == NULL, MS_MEDIA_ERR_INTERNAL, content_info);
425
426         time(&content_info->added_time);
427
428         content_info->media_uuid = __media_info_generate_uuid();
429         media_svc_retv_del_if(content_info->media_uuid == NULL, MS_MEDIA_ERR_INTERNAL, content_info);
430
431         content_info->file_name = g_path_get_basename(path);
432         media_svc_retv_del_if(content_info->file_name == NULL, MS_MEDIA_ERR_INTERNAL, content_info);
433
434         ret = __media_svc_get_mime_type(path, mime_type);
435         media_svc_retv_del_if(ret != MS_MEDIA_ERR_NONE, ret, content_info);
436
437         media_svc_debug("mime [%s]", mime_type);
438
439         ret = __media_svc_get_media_type(path, mime_type, &media_type);
440         media_svc_retv_del_if(ret != MS_MEDIA_ERR_NONE, ret, content_info);
441
442         content_info->mime_type = g_strdup(mime_type);
443         media_svc_retv_del_if(content_info->mime_type == NULL, MS_MEDIA_ERR_INTERNAL, content_info);
444
445         media_svc_sec_debug("path[%s], media_type[%d]", path, media_type);
446
447         content_info->media_type = media_type;
448
449         return MS_MEDIA_ERR_NONE;
450 }
451
452 static char * __media_svc_get_title(MMHandleType tag, const char *filename)
453 {
454         int ret = FILEINFO_ERROR_NONE;
455         char *p = NULL;
456         int size = 0;
457
458         if (tag) {
459                 ret = mm_file_get_attrs(tag, MM_FILE_TAG_TITLE, &p, &size, NULL);
460                 if (ret == FILEINFO_ERROR_NONE && size > 0) {
461                         while(p && isspace(*p))
462                                 p++;
463
464                         return g_strdup(p);
465                 }
466         }
467
468         return __media_svc_get_title_from_filename(filename);
469 }
470
471 char * _media_svc_get_title_from_filename(const char *filename)
472 {
473         /* No MMHandleType in media-svc.c */
474         return __media_svc_get_title_from_filename(filename);
475 }
476
477 int _media_svc_extract_image_metadata(media_svc_content_info_s *content_info)
478 {
479         int orient_value = 0;
480         int exif_width = 0;
481         int exif_height = 0;
482         ExifData *ed = NULL;
483         bool has_datetaken = false;
484         char *path = NULL;
485
486         char buf[MEDIA_SVC_METADATA_LEN_MAX + 1] = { '\0' };
487
488         media_svc_retvm_if(!content_info, MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid content_info");
489         media_svc_retvm_if(content_info->media_type != MEDIA_SVC_MEDIA_TYPE_IMAGE, MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid media_type [%d]", content_info->media_type);
490         media_svc_retvm_if(!STRING_VALID(content_info->path), MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid path");
491
492         path = content_info->path;
493         content_info->media_meta.title = __media_svc_get_title_from_filename(content_info->file_name);
494
495         /* Not used. But to preserved the behavior, set MEDIA_SVC_TAG_UNKNOWN. */
496         content_info->media_meta.album = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
497         content_info->media_meta.artist = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
498         content_info->media_meta.album_artist = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
499         content_info->media_meta.genre = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
500         content_info->media_meta.year = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
501         content_info->media_meta.track_num = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
502
503         /* Load an ExifData object from an EXIF file */
504         ed = exif_data_new_from_file(path);
505         if (!ed) {
506                 media_svc_sec_debug("There is no exif data in [ %s ]", path);
507                 goto GET_WIDTH_HEIGHT;
508         }
509
510         memset(buf, 0x00, sizeof(buf));
511         if (!has_datetaken && __media_svc_get_exif_info(ed, buf, NULL, EXIF_TAG_DATE_TIME_ORIGINAL) == MS_MEDIA_ERR_NONE) {
512                 if (strlen(buf) > 0) {
513                         has_datetaken = true;
514                         content_info->media_meta.datetaken = g_strdup(buf);
515
516                         /* This is same as recorded_date */
517                         content_info->media_meta.recorded_date = g_strdup(buf);
518                 }
519         }
520
521         memset(buf, 0x00, sizeof(buf));
522         if (!has_datetaken && __media_svc_get_exif_info(ed, buf, NULL, EXIF_TAG_DATE_TIME) == MS_MEDIA_ERR_NONE) {
523                 if (strlen(buf) > 0) {
524                         has_datetaken = true;
525                         content_info->media_meta.datetaken = g_strdup(buf);
526
527                         /* This is same as recorded_date */
528                         content_info->media_meta.recorded_date = g_strdup(buf);
529                 }
530         }
531
532         if (content_info->media_meta.recorded_date == NULL)
533                 content_info->media_meta.recorded_date = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
534
535         /* Get orientation value from exif. */
536         if (__media_svc_get_exif_info(ed, NULL, &orient_value, EXIF_TAG_ORIENTATION) == MS_MEDIA_ERR_NONE) {
537                 if (orient_value >= NOT_AVAILABLE && orient_value <= ROT_270)
538                         content_info->media_meta.orientation = orient_value;
539         }
540
541         /* Get width value from exif. */
542         if (__media_svc_get_exif_info(ed, NULL, &exif_width, EXIF_TAG_PIXEL_X_DIMENSION) == MS_MEDIA_ERR_NONE) {
543                 if (exif_width > 0)
544                         content_info->media_meta.width = exif_width;
545         }
546
547         /* Get height value from exif. */
548         if (__media_svc_get_exif_info(ed, NULL, &exif_height, EXIF_TAG_PIXEL_Y_DIMENSION) == MS_MEDIA_ERR_NONE) {
549                 if (exif_height > 0)
550                         content_info->media_meta.height = exif_height;
551         }
552
553         if (ed)
554                 exif_data_unref(ed);
555
556 GET_WIDTH_HEIGHT:
557         if (content_info->media_meta.width == 0 || content_info->media_meta.height == 0) {
558                 /*Get image width, height*/
559                 unsigned int img_width = 0;
560                 unsigned int img_height = 0;
561
562                 if (get_image_info(path, &img_width, &img_height) != THUMB_OK)
563                         return MS_MEDIA_ERR_NONE;
564
565                 if (content_info->media_meta.width == 0)
566                         content_info->media_meta.width = img_width;
567
568                 if (content_info->media_meta.height == 0)
569                         content_info->media_meta.height = img_height;
570         }
571
572         return MS_MEDIA_ERR_NONE;
573 }
574
575 static char * __media_svc_get_tag_str_value(MMHandleType tag, const char *tag_name)
576 {
577         int ret = FILEINFO_ERROR_NONE;
578         char *p = NULL;
579         int size = 0;
580
581         ret = mm_file_get_attrs(tag, tag_name, &p, &size, NULL);
582         if (ret == FILEINFO_ERROR_NONE && size > 0)
583                 return g_strdup(p);
584
585         return g_strdup(MEDIA_SVC_TAG_UNKNOWN);
586 }
587
588 int _media_svc_extract_audio_metadata(sqlite3 *handle, bool is_direct, media_svc_content_info_s *content_info, uid_t uid)
589 {
590         MMHandleType tag = 0;
591         char *p = NULL;
592         unsigned char *image = NULL;
593         unsigned int size = 0;
594         int mmf_error = FILEINFO_ERROR_NONE;
595         int album_id = 0;
596         int ret = MS_MEDIA_ERR_NONE;
597         int convert_value = 0;
598         bool support_albumart = ms_user_thumb_support(uid, content_info->path);
599
600         /*Get Content Tag attribute ===========*/
601         if (support_albumart)
602                 mmf_error = mm_file_create_tag_attrs(&tag, content_info->path);
603         else
604                 mmf_error = mm_file_create_tag_attrs_no_albumart(&tag, content_info->path);
605
606         if (mmf_error == FILEINFO_ERROR_NONE) {
607                 content_info->media_meta.title = __media_svc_get_title(tag, content_info->file_name);
608                 content_info->media_meta.album = __media_svc_get_tag_str_value(tag, MM_FILE_TAG_ALBUM);
609                 content_info->media_meta.artist = __media_svc_get_tag_str_value(tag, MM_FILE_TAG_ARTIST);
610                 content_info->media_meta.album_artist = __media_svc_get_tag_str_value(tag, MM_FILE_TAG_ALBUM_ARTIST);
611                 content_info->media_meta.genre = __media_svc_get_tag_str_value(tag, MM_FILE_TAG_GENRE);
612                 content_info->media_meta.track_num = __media_svc_get_tag_str_value(tag, MM_FILE_TAG_TRACK_NUM);
613                 content_info->media_meta.copyright = __media_svc_get_tag_str_value(tag, MM_FILE_TAG_COPYRIGHT);
614
615                 mmf_error = mm_file_get_attrs(tag, MM_FILE_TAG_RECDATE, &p, &size, NULL);
616                 if ((mmf_error == FILEINFO_ERROR_NONE) && (size > 0)) {
617                         if (g_str_has_suffix(content_info->mime_type, "mp4") || g_str_has_suffix(content_info->mime_type, "3gpp")) {
618                                 /*Creation time format is 20130101 00:00:00 +0000. change it to 2013:01:01 00:00:00  +0000 like exif time format*/
619                                 char *p_value = g_strdelimit(g_strdup(p), "-", ':');
620                                 content_info->media_meta.recorded_date = g_strdup_printf("%s +0000", p_value);
621                                 g_free(p_value);
622                         } else {
623                                 content_info->media_meta.recorded_date = g_strdup(p);
624                         }
625                 }
626
627                 if (content_info->media_meta.recorded_date == NULL)
628                         content_info->media_meta.recorded_date = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
629
630                 mmf_error = mm_file_get_attrs(tag, MM_FILE_TAG_DATE, &p, &size, NULL);
631                 if (mmf_error == FILEINFO_ERROR_NONE && size == 4) {
632                         if (__media_svc_safe_atoi(p, &convert_value) == MS_MEDIA_ERR_NONE)
633                                 content_info->media_meta.year = g_strdup(p);
634                 }
635
636                 if (!content_info->media_meta.year)
637                                 content_info->media_meta.year = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
638
639                 /*Do not extract artwork for the USB Storage content*/
640                 if (support_albumart) {
641                         mmf_error = mm_file_get_attrs(tag, MM_FILE_TAG_ARTWORK, &image, &size, NULL);
642                         if (mmf_error != FILEINFO_ERROR_NONE)
643                                 media_svc_error("fail to get tag artwork - err(%x)", mmf_error);
644
645                         mmf_error = mm_file_get_attrs(tag, MM_FILE_TAG_ARTWORK_SIZE, &size, NULL);
646                         if (mmf_error != FILEINFO_ERROR_NONE)
647                                 media_svc_error("fail to get artwork size - err(%x)", mmf_error);
648
649                         if (image != NULL && size > 0) {
650                                 char thumb_path[MEDIA_SVC_PATHNAME_SIZE] = "\0";
651                                 int artwork_mime_size = -1;
652
653                                 mmf_error = mm_file_get_attrs(tag, MM_FILE_TAG_ARTWORK_MIME, &p, &artwork_mime_size, NULL);
654                                 if ((mmf_error == FILEINFO_ERROR_NONE) && (artwork_mime_size > 0)) {
655                                         ret = __media_svc_get_thumbnail_path(thumb_path, content_info->path, p, uid);
656                                         if (ret != MS_MEDIA_ERR_NONE) {
657                                                 media_svc_error("Fail to Get Thumbnail Path");
658                                         } else {
659                                                 ret = __media_svc_save_image(image, size, thumb_path, uid);
660                                                 if (ret != MS_MEDIA_ERR_NONE) {
661                                                         media_svc_error("Fail to Save Image");
662                                                 } else {
663                                                         content_info->thumbnail_path = g_strdup(thumb_path);
664                                                 }
665                                         }
666                                 }
667                         }
668                 }
669
670                 /*Initialize album_id to 0. below code will set the album_id*/
671                 content_info->album_id = album_id;
672                 ret = _media_svc_get_album_id(handle, content_info->media_meta.album, content_info->media_meta.artist, &album_id);
673                 if (ret != MS_MEDIA_ERR_NONE) {
674                         if (ret == MS_MEDIA_ERR_DB_NO_RECORD) {
675                                 media_svc_debug("album does not exist. So start to make album art");
676                                 if ((g_strcmp0(content_info->media_meta.album, MEDIA_SVC_TAG_UNKNOWN)) &&
677                                         (g_strcmp0(content_info->media_meta.artist, MEDIA_SVC_TAG_UNKNOWN)))
678                                         ret = _media_svc_append_album(handle, is_direct, content_info->media_meta.album, content_info->media_meta.artist, content_info->thumbnail_path, &album_id, uid);
679                                 else
680                                         ret = _media_svc_append_album(handle, is_direct, content_info->media_meta.album, content_info->media_meta.artist, NULL, &album_id, uid);
681
682                                 content_info->album_id = album_id;
683                         }
684                 } else {
685                         content_info->album_id = album_id;
686                 }
687
688                 mmf_error = mm_file_destroy_tag_attrs(tag);
689                 if (mmf_error != FILEINFO_ERROR_NONE)
690                         media_svc_error("fail to free tag attr - err(%x)", mmf_error);
691         }       else {
692                 content_info->media_meta.title = __media_svc_get_title_from_filename(content_info->file_name);
693                 content_info->album_id = album_id;
694         }
695
696         return MS_MEDIA_ERR_NONE;
697 }
698
699 int _media_svc_extract_video_metadata(media_svc_content_info_s *content_info)
700 {
701         int mmf_error = FILEINFO_ERROR_NONE;
702         MMHandleType tag = 0;
703         MMHandleType content = 0;
704         char *p = NULL;
705         unsigned int size = 0;
706
707         mmf_error = mm_file_create_tag_attrs_no_albumart(&tag, content_info->path);
708
709         if (mmf_error == FILEINFO_ERROR_NONE) {
710                 mmf_error = mm_file_get_attrs(tag, MM_FILE_TAG_RECDATE, &p, &size, NULL);
711                 if ((mmf_error == FILEINFO_ERROR_NONE) && (size > 0)) {
712                         if (g_str_has_suffix(content_info->mime_type, "mp4") || g_str_has_suffix(content_info->mime_type, "3gpp")) {
713                                 /*Creation time format is 20130101 00:00:00 +0000. change it to 2013:01:01 00:00:00  +0000 like exif time format*/
714                                 content_info->media_meta.recorded_date = g_strdelimit(g_strdup(p), "-", ':');
715                         } else {
716                                 content_info->media_meta.recorded_date = g_strdup(p);
717                         }
718                 }
719
720                 if (content_info->media_meta.recorded_date == NULL)
721                         content_info->media_meta.recorded_date = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
722                 content_info->media_meta.datetaken = g_strdup(content_info->media_meta.recorded_date);
723
724                 mmf_error = mm_file_destroy_tag_attrs(tag);
725                 if (mmf_error != FILEINFO_ERROR_NONE)
726                         media_svc_error("fail to free tag attr - err(%x)", mmf_error);
727         }
728         /*Get Content attribute ===========*/
729         mmf_error = mm_file_create_content_attrs_simple(&content, content_info->path);
730         media_svc_retvm_if(mmf_error != FILEINFO_ERROR_NONE, MS_MEDIA_ERR_NONE, "mm_file_create_content_attrs failed");
731
732         mm_file_get_attrs(content, MM_FILE_CONTENT_VIDEO_WIDTH, &content_info->media_meta.width,
733                 MM_FILE_CONTENT_VIDEO_HEIGHT, &content_info->media_meta.height,
734                 NULL);
735
736         mm_file_destroy_content_attrs(content);
737
738         content_info->media_meta.title = __media_svc_get_title_from_filename(content_info->file_name);
739         content_info->media_meta.album = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
740         content_info->media_meta.artist = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
741         content_info->media_meta.album_artist = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
742         content_info->media_meta.genre = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
743         content_info->media_meta.track_num = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
744         content_info->media_meta.year = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
745         content_info->media_meta.copyright = g_strdup(MEDIA_SVC_TAG_UNKNOWN);
746         content_info->album_id = 0;
747
748         return MS_MEDIA_ERR_NONE;
749 }
750
751 static gchar * __media_svc_get_zipfile_string(zip_t *z, const char *fname)
752 {
753         int err = 0;
754         zip_int64_t index_num = 0;
755         zip_file_t *file = NULL;
756         zip_stat_t sb = {0, };
757         gchar *buf = NULL;
758
759         media_svc_retvm_if(!z, NULL, "z is NULL");
760         media_svc_retvm_if(!fname, NULL, "fname is NULL");
761
762         index_num = zip_name_locate(z, fname, ZIP_FL_NOCASE);
763         media_svc_retvm_if(index_num == -1, NULL, "fname is not exists [%s]", fname);
764
765         err = zip_stat_index(z, index_num, ZIP_STAT_SIZE, &sb);
766         media_svc_retvm_if(err == -1, NULL, "zip_stat_index failed");
767
768         file = zip_fopen_index(z, index_num, ZIP_FL_UNCHANGED);
769         media_svc_retvm_if(!file, NULL, "zip_fopen_index failed");
770
771         buf = g_malloc0(sb.size + 1);
772
773         err = zip_fread(file, buf, sb.size);
774         zip_fclose(file);
775
776         if (err == -1) {
777                 g_free(buf);
778                 buf = NULL;
779         }
780
781         return buf;
782 }
783
784 static xmlNodePtr __media_svc_find_node(xmlNodePtr node, const char *key)
785 {
786         xmlNodePtr tmp = NULL;
787
788         media_svc_retvm_if(!node, NULL, "node is NULL");
789         media_svc_retvm_if(!key, NULL, "key is NULL");
790
791         for (tmp = node->children; tmp; tmp = tmp->next) {
792                 if (xmlIsBlankNode(tmp))
793                         continue;
794
795                 if (g_str_has_suffix((gchar *)tmp->name, key))
796                         return tmp;
797         }
798
799         return NULL;
800 }
801
802 static char * __media_svc_remove_escape_c(const char *value)
803 {
804         int start = -1;
805         int end = 0;
806         int len, i;
807
808         media_svc_retv_if(!value, NULL);
809
810         len = strlen(value);
811
812         for (i = 0; i < len; i++) {
813                 if (value[i] != 10 && value[i] != 32) { // 10='\n' 32=' '
814                         if (start == -1)
815                                 start = i;
816
817                         end = i;
818                 }
819         }
820
821         end = end - start + 1;
822
823         return g_strndup(value + start, end);
824 }
825
826 static char * __media_svc_find_and_get_value(xmlNodePtr node, const char *key)
827 {
828         xmlNodePtr tmp = NULL;
829         char *tmp_res = NULL;
830         char *res = NULL;
831
832         media_svc_retvm_if(!node, NULL, "node is NULL");
833         media_svc_retvm_if(!key, NULL, "key is NULL");
834
835         for (tmp = node->children; tmp; tmp = tmp->next) {
836                 if (xmlIsBlankNode(tmp))
837                         continue;
838
839                 if (tmp->children) {
840                         tmp_res = __media_svc_find_and_get_value(tmp, key);
841                         if (tmp_res) {
842                                 res = __media_svc_remove_escape_c(tmp_res);
843                                 xmlFree(tmp_res);
844                                 return res;
845                         }
846                 }
847
848                 if (g_str_has_suffix((gchar *)tmp->name, key))
849                         return (char *)xmlNodeGetContent(tmp);
850         }
851
852         return NULL;
853 }
854
855 static gboolean __media_svc_get_epub_root_file(zip_t *z, char **opf_file)
856 {
857         gchar *buf = NULL;
858         gchar *tmp_buf = NULL;
859         xmlDocPtr doc = NULL;
860         xmlNodePtr node = NULL;
861
862         media_svc_retvm_if(!z, FALSE, "z is NULL");
863         media_svc_retvm_if(!opf_file, FALSE, "opf_file is NULL");
864
865         buf = __media_svc_get_zipfile_string(z, "META-INF/container.xml");
866         media_svc_retvm_if(!buf, FALSE, "buf is NULL");
867
868         tmp_buf = g_strrstr(buf, ">");
869         if (tmp_buf)
870                 *(tmp_buf + 1) = '\0';
871
872         doc = xmlParseDoc((const xmlChar *)buf);
873         g_free(buf);
874         media_svc_retvm_if(!doc, FALSE, "doc is NULL");
875
876         node = xmlDocGetRootElement(doc);
877         node = __media_svc_find_node(node, "rootfiles");
878         node = __media_svc_find_node(node, "rootfile");
879
880         *opf_file = (char *)xmlGetProp(node, (const xmlChar *)"full-path");
881         media_svc_sec_debug("OPF [%s]", *opf_file);
882         xmlFreeDoc(doc);
883
884         return TRUE;
885 }
886
887 static gboolean __media_svc_get_xml_metadata(const xmlChar *buffer, gboolean is_pdf, media_svc_content_info_s *content_info)
888 {
889         xmlDocPtr doc = NULL;
890         xmlNodePtr root = NULL;
891
892         media_svc_retvm_if(!buffer, FALSE, "buffer is NULL");
893         media_svc_retvm_if(!content_info, FALSE, "content_info is NULL");
894
895         doc = xmlParseDoc(buffer);
896         media_svc_retv_if(!doc, FALSE);
897
898         root = xmlDocGetRootElement(doc);
899         if (!root) {
900                 xmlFreeDoc(doc);
901                 return FALSE;
902         }
903
904         content_info->media_meta.title = __media_svc_find_and_get_value(root, "title");
905         if (is_pdf && !content_info->media_meta.title) {
906                 xmlFreeDoc(doc);
907                 return FALSE;
908         }
909
910         content_info->media_meta.artist = __media_svc_find_and_get_value(root, "creator");
911         if (!content_info->media_meta.artist)
912                 content_info->media_meta.artist = __media_svc_find_and_get_value(root, "author");
913         content_info->media_meta.genre = __media_svc_find_and_get_value(root, "subject");
914         content_info->media_meta.copyright = __media_svc_find_and_get_value(root, "publisher");
915         content_info->media_meta.recorded_date = __media_svc_find_and_get_value(root, "date");
916
917         xmlFreeDoc(doc);
918
919         return TRUE;
920 }
921
922 static int __media_svc_get_epub_metadata(media_svc_content_info_s *content_info)
923 {
924         int err = 0;
925         zip_t *z = NULL;
926         gchar *buf = NULL;
927         char *opf_path = NULL;
928
929         media_svc_retvm_if(!content_info, MS_MEDIA_ERR_INVALID_PARAMETER, "content_info is NULL");
930
931         //1. open epub
932         z = zip_open(content_info->path, ZIP_RDONLY, &err);
933         media_svc_retvm_if(err == -1, MS_MEDIA_ERR_INTERNAL, "zip_open failed");
934
935         //2. find and read opf file
936         if (!__media_svc_get_epub_root_file(z, &opf_path)) {
937                 media_svc_error("__media_svc_get_epub_root_file failed");
938                 zip_close(z);
939                 return MS_MEDIA_ERR_INTERNAL;
940         }
941
942         //3. get metadata
943         buf = __media_svc_get_zipfile_string(z, opf_path);
944         xmlFree(opf_path);
945         zip_close(z);
946         media_svc_retvm_if(!buf, MS_MEDIA_ERR_INTERNAL, "__media_svc_get_zipfile_string failed");
947
948         if (!__media_svc_get_xml_metadata((const xmlChar *)buf, FALSE, content_info))
949                 media_svc_error("__media_svc_get_xml_metadata failed");
950
951         g_free(buf);
952
953         return MS_MEDIA_ERR_NONE;
954 }
955
956 static int __media_svc_get_pdf_metadata(media_svc_content_info_s *content_info)
957 {
958     int fd = 0;
959     int start_pos = 0;
960     int end_pos = 0;
961     int cur_pos = 0;
962     int search_limit = 0;
963     char tmp[MEDIA_SVC_PDF_BUF_SIZE + 1] = {0, };
964     gchar *meta_buf = NULL;
965     char *found = NULL;
966
967         media_svc_retvm_if(!content_info, MS_MEDIA_ERR_INVALID_PARAMETER, "content_info is NULL");
968         media_svc_retvm_if(content_info->size < 256, MS_MEDIA_ERR_INTERNAL, "open failed");
969
970         fd = open(content_info->path, O_RDONLY);
971         media_svc_retvm_if(fd < 0, MS_MEDIA_ERR_INTERNAL, "open failed");
972
973         search_limit = content_info->size - MEDIA_SVC_PDF_TAG_TAIL_LEN;
974
975         while (cur_pos <= search_limit) {
976                 if (lseek(fd, cur_pos, SEEK_SET) == -1)
977                         break;
978
979                 memset(&tmp, 0x00, MEDIA_SVC_PDF_BUF_SIZE + 1);
980
981                 if (read(fd, &tmp, MEDIA_SVC_PDF_BUF_SIZE) != MEDIA_SVC_PDF_BUF_SIZE) {
982                         media_svc_error("read failed");
983                         break;
984                 }
985
986                 //1.Find <x:xmpmeta .. </x:xmpmeta> block
987                 if (start_pos == 0 && (found = strstr(tmp, "<x:xmpmeta"))) {
988                         start_pos = cur_pos + (found - tmp);
989 //                      media_svc_error("FIND START_POS[%d]", start_pos);
990                         found = NULL;
991                 }
992
993
994                 if (start_pos != 0 && (found = strstr(tmp, "</x:xmpmeta>"))) {
995                         end_pos = cur_pos + (found - tmp) + MEDIA_SVC_PDF_TAG_TAIL_LEN;
996 //                      media_svc_error("FIND END_POS[%d]", end_pos);
997                         found = NULL;
998                 }
999
1000                 //2.get metadata using xml parser
1001                 if (start_pos && end_pos) {
1002                         if (lseek(fd, start_pos, SEEK_SET) == -1)
1003                                 break;
1004
1005                         meta_buf = g_malloc0(end_pos - start_pos + 1);
1006
1007                         if (read(fd, meta_buf, end_pos - start_pos) == end_pos - start_pos) {
1008                                 if (__media_svc_get_xml_metadata((const xmlChar *)meta_buf, TRUE, content_info)) {
1009                                         g_free(meta_buf);
1010                                         break;
1011                                 }
1012                         }
1013
1014                         g_free(meta_buf);
1015
1016                         start_pos = 0;
1017                         end_pos = 0;
1018                 }
1019
1020                 cur_pos += 240;
1021
1022         }
1023
1024         close(fd);
1025
1026         return MS_MEDIA_ERR_NONE;
1027 }
1028
1029 int _media_svc_extract_book_metadata(media_svc_content_info_s *content_info)
1030 {
1031         media_svc_retvm_if(!content_info, MS_MEDIA_ERR_INVALID_PARAMETER, "content info is NULL");
1032
1033         if (g_str_has_suffix(content_info->mime_type, "epub+zip"))
1034                 return __media_svc_get_epub_metadata(content_info);
1035         else
1036                 return __media_svc_get_pdf_metadata(content_info);
1037 }
1038
1039 void _media_svc_destroy_content_info(media_svc_content_info_s *content_info)
1040 {
1041         media_svc_retm_if(!content_info, "content info is NULL");
1042
1043         /* Delete media_svc_content_info_s */
1044         g_free(content_info->media_uuid);
1045         g_free(content_info->path);
1046         g_free(content_info->file_name);
1047         g_free(content_info->mime_type);
1048         g_free(content_info->thumbnail_path);
1049         g_free(content_info->storage_uuid);
1050
1051         /* Delete media_svc_content_meta_s */
1052         g_free(content_info->media_meta.title);
1053         g_free(content_info->media_meta.album);
1054         g_free(content_info->media_meta.artist);
1055         g_free(content_info->media_meta.album_artist);
1056         g_free(content_info->media_meta.genre);
1057         g_free(content_info->media_meta.year);
1058         g_free(content_info->media_meta.recorded_date);
1059         g_free(content_info->media_meta.copyright);
1060         g_free(content_info->media_meta.track_num);
1061         g_free(content_info->media_meta.datetaken);
1062 }
1063
1064 int _media_svc_create_thumbnail(const char *path, char *thumb_path, media_svc_media_type_e media_type, uid_t uid)
1065 {
1066         int ret = MS_MEDIA_ERR_NONE;
1067
1068         media_svc_retvm_if(!path, MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid path");
1069         media_svc_retvm_if(!thumb_path, MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid thumb_path");
1070         media_svc_retvm_if(!g_file_test(path, G_FILE_TEST_IS_REGULAR), MS_MEDIA_ERR_INVALID_PARAMETER, "File doesn't exist[%s]", path);
1071
1072         if (!ms_user_thumb_support(uid, path)) {
1073                 media_svc_sec_error("origin path(%s) is invalid", path);
1074                 return MS_MEDIA_ERR_INVALID_PARAMETER;
1075         }
1076
1077         media_svc_sec_debug("Path[%s] Type[%d]", path, media_type);
1078
1079         //1. make thumb path
1080         ret = __media_svc_get_thumbnail_path(thumb_path, path, NULL, uid);
1081         if (ret != MS_MEDIA_ERR_NONE) {
1082                 media_svc_error("Failed to create thumbnail path[%d]", ret);
1083                 SAFE_STRLCPY(thumb_path, "", MAX_FILEPATH_LEN);
1084                 return ret;
1085         }
1086
1087         //2. save thumbnail
1088         if (media_type == MEDIA_SVC_MEDIA_TYPE_IMAGE)
1089                 ret = create_image_thumbnail_to_file(path, MEDIA_SVC_THUMB_WIDTH, MEDIA_SVC_THUMB_HEIGHT, thumb_path, true);
1090         else
1091                 ret = create_video_thumbnail_to_file(path, MEDIA_SVC_THUMB_WIDTH, MEDIA_SVC_THUMB_HEIGHT, thumb_path, true);
1092
1093         return (ret == THUMB_OK) ? MS_MEDIA_ERR_NONE : MS_MEDIA_ERR_INTERNAL;
1094 }
1095
1096 int _media_svc_get_media_type(const char *path, int *mediatype)
1097 {
1098         int ret = MS_MEDIA_ERR_NONE;
1099         char mime_type[256] = {0};
1100         media_svc_media_type_e media_type = MEDIA_SVC_MEDIA_TYPE_OTHER;
1101
1102         media_svc_retvm_if(mediatype == NULL, MS_MEDIA_ERR_INVALID_PARAMETER, "mediatype is NULL");
1103
1104         ret = __media_svc_get_mime_type(path, mime_type);
1105         if (ret == MS_MEDIA_ERR_NONE)
1106                 __media_svc_get_media_type(path, mime_type, &media_type);
1107         else
1108                 media_svc_error("__media_svc_get_mime_type failed");
1109
1110         *mediatype = media_type;
1111
1112         return ret;
1113 }
1114
1115 bool _media_svc_is_keyword_included(const char *path, const char *keyword)
1116 {
1117         bool ret = false;
1118         void *handle = NULL;
1119         bool (*svc_search) (const char *, const char *);
1120
1121         media_svc_retvm_if(!path, false, "Invalid path");
1122         media_svc_retvm_if(!keyword, false, "Invalid keyword");
1123
1124         handle = dlopen(PATH_PLUGIN_LIB, RTLD_LAZY);
1125         media_svc_retvm_if(!handle, false, "dlopen failed");
1126
1127         if (g_str_has_suffix(path, "epub") || g_str_has_suffix(path, "EPUB"))
1128                 svc_search = dlsym(handle, "media_svc_epub_is_keyword_included");
1129         else
1130                 svc_search = dlsym(handle, "media_svc_pdf_is_keyword_included");
1131
1132         if (!svc_search) {
1133                 media_svc_error("dlsym failed - %s", dlerror());
1134                 dlclose(handle);
1135                 return false;
1136         }
1137
1138         ret = svc_search(path, keyword);
1139         dlclose(handle);
1140
1141         return ret;
1142 }
1143
1144 static int __media_svc_create_wordbook_db(const char *path, sqlite3 **handle)
1145 {
1146         int ret = SQLITE_OK;
1147         sqlite3 *db_handle = NULL;
1148         char *err = NULL;
1149
1150         ret = sqlite3_open_v2(path, &db_handle, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
1151         media_svc_retvm_if(ret != SQLITE_OK, ret, "sqlite3_open_v2 failed : %d", ret);
1152
1153         ret = sqlite3_exec(db_handle, "PRAGMA journal_mode = OFF;", NULL, NULL, &err);
1154         if (ret != SQLITE_OK)
1155                 goto ERROR;
1156
1157         ret = sqlite3_exec(db_handle, "CREATE TABLE IF NOT EXISTS files(id integer primary key autoincrement, path text unique, validity integer default 1);", NULL, NULL, &err);
1158         if (ret != SQLITE_OK)
1159                 goto ERROR;
1160
1161         ret = sqlite3_exec(db_handle, "CREATE TABLE IF NOT EXISTS words(file_id integer, word text, frequency integer default 1, unique(file_id, word));", NULL, NULL, &err);
1162         if (ret != SQLITE_OK)
1163                 goto ERROR;
1164
1165         ret = sqlite3_exec(db_handle, "CREATE TRIGGER IF NOT EXISTS TR_files_words DELETE ON files BEGIN DELETE FROM words WHERE file_id = old.id;END;", NULL, NULL, &err);
1166         if (ret != SQLITE_OK)
1167                 goto ERROR;
1168
1169         *handle = db_handle;
1170
1171         return SQLITE_OK;
1172
1173 ERROR:
1174         media_svc_error("sqlite3_exec failed : %s", err);
1175         SQLITE3_SAFE_FREE(err);
1176         sqlite3_close_v2(db_handle);
1177
1178         return ret;
1179 }
1180
1181 static bool __media_svc_get_wordbook_handle(uid_t uid, sqlite3 **handle)
1182 {
1183         int ret = SQLITE_OK;
1184         char *db_path = NULL;
1185
1186         ms_user_get_wordbook_db_path(uid, &db_path);
1187         if (!db_path)
1188                 return false;
1189
1190         ret = sqlite3_open_v2(db_path, handle, SQLITE_OPEN_READWRITE, NULL);
1191         if (ret != SQLITE_OK) {
1192                 ret = __media_svc_create_wordbook_db(db_path, handle);
1193                 free(db_path);
1194                 media_svc_retvm_if(ret != SQLITE_OK, false, "__media_svc_create_wordbook_db failed : %d", ret);
1195         } else {
1196                 ret = sqlite3_exec(*handle, "PRAGMA journal_mode = OFF;", NULL, NULL, NULL);
1197                 if (ret != SQLITE_OK)
1198                         media_svc_error("Failed to change journal mode [%d]", ret);
1199         }
1200
1201         return true;
1202 }
1203
1204 static bool __media_svc_is_exist_in_wordbook(sqlite3 *db_handle, const char *path)
1205 {
1206         int ret = SQLITE_OK;
1207         char *err = NULL;
1208         char *query = NULL;
1209
1210         query = sqlite3_mprintf("UPDATE files SET validity=1 WHERE path = %Q", path);
1211
1212         ret = sqlite3_exec(db_handle, query, NULL, NULL, &err);
1213         SQLITE3_SAFE_FREE(query);
1214         if (ret != SQLITE_OK) {
1215                 media_svc_error("Query failed. [%s]", err);
1216                 SQLITE3_SAFE_FREE(err);
1217                 return false;
1218         }
1219
1220         return sqlite3_changes(db_handle) > 0 ? true : false;
1221 }
1222
1223 static void __media_svc_insert_to_wordbook(sqlite3 *db_handle, const char *path)
1224 {
1225         void *handle = NULL;
1226         void (*svc_update) (sqlite3 *, const char *);
1227         char *query = NULL;
1228
1229         query = sqlite3_mprintf("INSERT INTO files(path) VALUES(%Q);", path);
1230         sqlite3_exec(db_handle, query, NULL, NULL, NULL);
1231         sqlite3_free(query);
1232
1233         handle = dlopen(PATH_PLUGIN_LIB, RTLD_LAZY);
1234         if (!handle) {
1235                 media_svc_error("dlopen failed");
1236                 return;
1237         }
1238
1239         if (g_str_has_suffix(path, "epub") || g_str_has_suffix(path, "EPUB"))
1240                 svc_update = dlsym(handle, "media_svc_epub_insert_to_db");
1241         else
1242                 svc_update = dlsym(handle, "media_svc_pdf_insert_to_db");
1243
1244         if (!svc_update) {
1245                 media_svc_error("dlsym failed - %s", dlerror());
1246                 dlclose(handle);
1247                 return;
1248         }
1249
1250         svc_update(db_handle, path);
1251         dlclose(handle);
1252 }
1253
1254 void _media_svc_update_wordbook(const char *path, uid_t uid)
1255 {
1256         sqlite3 *db_handle = NULL;
1257
1258         if (!path) {
1259                 media_svc_error("Invalid path");
1260                 return;
1261         }
1262
1263         // check db..
1264         if (!__media_svc_get_wordbook_handle(uid, &db_handle))
1265                 return;
1266
1267         if (__media_svc_is_exist_in_wordbook(db_handle, path)) {
1268                 sqlite3_close_v2(db_handle);
1269                 return;
1270         }
1271
1272         // if no item, insert to db..
1273         __media_svc_insert_to_wordbook(db_handle, path);
1274         sqlite3_close_v2(db_handle);
1275 }
1276
1277 void _media_svc_clean_wordbook(uid_t uid)
1278 {
1279         sqlite3 *db_handle = NULL;
1280
1281         if (!__media_svc_get_wordbook_handle(uid, &db_handle))
1282                 return;
1283
1284         sqlite3_exec(db_handle, "DELETE FROM files where validity = 0;", NULL, NULL, NULL);
1285         sqlite3_exec(db_handle, "UPDATE files SET validity = 0;", NULL, NULL, NULL);
1286         sqlite3_close_v2(db_handle);
1287 }
1288
1289 bool _media_svc_get_matched_list(const char *keyword, uid_t uid, GList **list)
1290 {
1291         int ret = SQLITE_OK;
1292         sqlite3 *handle = NULL;
1293         sqlite3_stmt *stmt = NULL;
1294         char *query = NULL;
1295
1296         media_svc_retvm_if(!list, false, "list is NULL");
1297         media_svc_retvm_if(!keyword, false, "keyword is NULL");
1298         media_svc_retvm_if(!__media_svc_get_wordbook_handle(uid, &handle), false, "Failed to get handle");
1299
1300         query = sqlite3_mprintf("SELECT files.path FROM files JOIN (SELECT file_id, sum(frequency) AS freq_sum FROM words WHERE word LIKE '%q%%' GROUP BY file_id ORDER BY freq_sum DESC) w ON files.id = w.file_id;", keyword);
1301         ret = sqlite3_prepare_v2(handle, query, -1, &stmt, NULL);
1302         SQLITE3_SAFE_FREE(query);
1303
1304         if (ret != SQLITE_OK) {
1305                 media_svc_error("Query failed[%d]", ret);
1306                 sqlite3_close_v2(handle);
1307                 return false;
1308         }
1309
1310         while (sqlite3_step(stmt) == SQLITE_ROW)
1311                 *list = g_list_append(*list, g_strdup((char *)sqlite3_column_text(stmt, 0)));
1312
1313         sqlite3_finalize(stmt);
1314         sqlite3_close_v2(handle);
1315
1316         return true;
1317 }