4 * Copyright (c) 2010 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
26 #include <image_util.h>
27 #include <unicode/ulocdata.h>
28 #include <unicode/uset.h>
29 #include <unicode/ustring.h>
30 #include <libexif/exif-data.h>
33 #include "ctsvc_internal.h"
34 #include "ctsvc_db_utils.h"
35 #include "ctsvc_mutex.h"
36 #include "ctsvc_db_sqlite.h"
37 #include "ctsvc_db_schema.h"
38 #include "ctsvc_notification.h"
39 #include "ctsvc_struct.h"
40 #include "ctsvc_normalize.h"
41 #include "ctsvc_localize.h"
42 #include "ctsvc_localize_utils.h"
43 #include "ctsvc_server_setting.h"
44 #include "ctsvc_notify.h"
45 #include "ctsvc_image_util.h"
47 #ifdef _CONTACTS_IPC_SERVER
48 #include "ctsvc_server_change_subject.h"
51 static __thread int transaction_count = 0;
52 static __thread int transaction_ver = 0;
53 static __thread bool version_up = false;
55 #define CTS_SECURITY_IMAGE_PERMISSION 0440
56 #define CTS_COMMIT_TRY_MAX 500000 /* For 3second */
58 int ctsvc_begin_trans(void)
60 int ret = -1, progress;
62 if (transaction_count <= 0) {
63 ret = ctsvc_query_exec("BEGIN IMMEDIATE TRANSACTION");
65 while (CONTACTS_ERROR_DB == ret && progress < CTS_COMMIT_TRY_MAX) {
67 ret = ctsvc_query_exec("BEGIN IMMEDIATE TRANSACTION");
70 if (CONTACTS_ERROR_NONE != ret) {
72 ERR("ctsvc_query_exec() Fail(%d)", ret);
77 transaction_count = 0;
79 const char *query = "SELECT ver FROM "CTS_TABLE_VERSION;
80 ret = ctsvc_query_get_first_int_result(query, &transaction_ver);
84 INFO("transaction_count : %d.", transaction_count);
85 return CONTACTS_ERROR_NONE;
88 int ctsvc_end_trans(bool is_success)
90 int ret = -1, progress;
91 char query[CTS_SQL_MIN_LEN] = {0};
94 INFO("%s, transaction_count : %d", is_success ? "True" : "False", transaction_count);
96 if (0 != transaction_count) {
97 DBG("contact transaction_count : %d.", transaction_count);
98 return CONTACTS_ERROR_NONE;
101 if (false == is_success) {
102 ctsvc_nofitication_cancel();
103 ctsvc_change_subject_clear_changed_info();
104 ret = ctsvc_query_exec("ROLLBACK TRANSACTION");
106 return CONTACTS_ERROR_NONE;
111 snprintf(query, sizeof(query), "UPDATE %s SET ver = %d",
112 CTS_TABLE_VERSION, transaction_ver);
113 ret = ctsvc_query_exec(query);
114 if (CONTACTS_ERROR_NONE != ret)
115 /* LCOV_EXCL_START */
116 ERR("ctsvc_query_exec(version up) Fail(%d)", ret);
120 INFO("start commit");
122 ret = ctsvc_query_exec("COMMIT TRANSACTION");
123 while (CONTACTS_ERROR_DB == ret && progress < CTS_COMMIT_TRY_MAX) {
125 ret = ctsvc_query_exec("COMMIT TRANSACTION");
128 INFO("%s", (CONTACTS_ERROR_NONE == ret) ? "commit" : "rollback");
130 if (CONTACTS_ERROR_NONE != ret) {
131 /* LCOV_EXCL_START */
133 ERR("ctsvc_query_exec() Fail(%d)", ret);
134 ctsvc_nofitication_cancel();
135 ctsvc_change_subject_clear_changed_info();
137 tmp_ret = ctsvc_query_exec("ROLLBACK TRANSACTION");
138 if (CONTACTS_ERROR_NONE != tmp_ret)
139 ERR("ctsvc_query_exec(ROLLBACK) Fail(%d)", tmp_ret);
145 ctsvc_notification_send();
146 ctsvc_change_subject_publish_changed_info();
148 DBG("Transaction shut down! : (%d)\n", transaction_ver);
150 return CONTACTS_ERROR_NONE;
153 const char* ctsvc_get_display_column(void)
155 contacts_name_display_order_e order;
157 ctsvc_setting_get_name_display_order(&order);
158 if (CONTACTS_NAME_DISPLAY_ORDER_FIRSTLAST == order)
159 return "display_name";
161 return "reverse_display_name";
164 const char* ctsvc_get_sort_name_column(void)
166 contacts_name_sorting_order_e order;
168 ctsvc_setting_get_name_sorting_order(&order);
169 if (CONTACTS_NAME_SORTING_ORDER_FIRSTLAST == order)
170 return "sort_name, display_name_language";
172 return "reverse_sort_name, reverse_display_name_language";
175 const char* ctsvc_get_sort_column(void)
177 contacts_name_sorting_order_e order;
179 ctsvc_setting_get_name_sorting_order(&order);
180 if (CONTACTS_NAME_SORTING_ORDER_FIRSTLAST == order)
181 return "display_name_language, sortkey";
183 return "reverse_display_name_language, reverse_sortkey";
186 void ctsvc_utils_make_image_file_name(int parent_id, int id, char *src_img, char *dest,
193 ext = strrchr(src_img, '.');
194 if (NULL == ext || strchr(ext, '/'))
197 lower_ext = strdup(ext);
198 if (NULL == lower_ext) {
199 /* LCOV_EXCL_START */
200 ERR("strdup() Fail");
206 *temp = tolower(*temp);
211 snprintf(dest, dest_size, "%d_%d%s", parent_id, id, lower_ext);
213 snprintf(dest, dest_size, "%d%s", id, ext);
217 static inline bool _ctsvc_check_available_image_space(int need_size)
223 ret = statfs(CTSVC_IMG_REPERTORY, &buf);
224 RETVM_IF(ret != 0, false, "statfs() Fail(%d)", ret);
226 size = (long long)buf.f_bavail * (buf.f_bsize);
228 if (need_size < size) /* if available space to copy a image is larger than need_size */
233 static image_util_rotation_e _ctsvc_image_get_rotation_info(const char *path)
237 image_util_rotation_e rotation = IMAGE_UTIL_ROTATION_NONE;
240 ed = exif_data_new_from_file(path);
242 /* LCOV_EXCL_START */
243 ERR("exif_data_new_from_file() Fail");
244 return IMAGE_UTIL_ROTATION_NONE;
248 entry = exif_data_get_entry(ed, EXIF_TAG_ORIENTATION);
250 ExifByteOrder mByteOrder = exif_data_get_byte_order(ed);
251 orientation = (int)exif_get_short(entry->data, mByteOrder);
252 if (orientation < 0 || 8 < orientation)
259 switch (orientation) {
260 case 1: /* Top-left */
261 rotation = IMAGE_UTIL_ROTATION_NONE;
263 case 2: /* Top-right */
264 rotation = IMAGE_UTIL_ROTATION_FLIP_HORZ;
266 case 3: /* Bottom-right */
267 rotation = IMAGE_UTIL_ROTATION_180;
269 case 4: /* Bottom-left */
270 rotation = IMAGE_UTIL_ROTATION_FLIP_VERT;
272 case 6: /* Right-top */
273 rotation = IMAGE_UTIL_ROTATION_90;
275 case 8: /* Left-bottom */
276 rotation = IMAGE_UTIL_ROTATION_270;
278 case 5: /* Left-top */
279 case 7: /* Right-bottom */
296 static bool _ctsvc_image_util_supported_jpeg_colorspace_cb(
297 image_util_colorspace_e colorspace, void *user_data)
304 unsigned int size_decode = 0;
306 void *buffer_temp = NULL;
308 image_util_rotation_e rotation;
309 image_info *info = user_data;
311 ret = ctsvc_image_util_get_mimetype(colorspace, &mimetype);
312 if (CONTACTS_ERROR_NONE != ret) {
313 info->ret = CONTACTS_ERROR_SYSTEM;
317 image_util_decode_h dh = NULL;
319 unsigned long l_width = 0;
320 unsigned long l_height = 0;
321 unsigned long long ll_size_decode = 0;
323 ret = image_util_decode_create(&dh);
324 if (IMAGE_UTIL_ERROR_NONE != ret)
326 ret = image_util_decode_set_input_path(dh, info->src);
327 if (IMAGE_UTIL_ERROR_NONE != ret)
329 ret = image_util_decode_set_colorspace(dh, colorspace);
330 if (IMAGE_UTIL_ERROR_NONE != ret)
332 ret = image_util_decode_set_output_buffer(dh, (unsigned char **)&buffer);
333 if (IMAGE_UTIL_ERROR_NONE != ret)
335 ret = image_util_decode_run(dh, &l_width, &l_height, &ll_size_decode);
336 if (IMAGE_UTIL_ERROR_NONE != ret)
339 width = (int)l_width;
340 height = (int)l_height;
341 size_decode = (unsigned int)ll_size_decode;
344 ret = image_util_decode_destroy(dh);
345 if (IMAGE_UTIL_ERROR_NONE != ret || 0 == width || 0 == height) {
346 /* LCOV_EXCL_START */
347 info->ret = CONTACTS_ERROR_SYSTEM;
351 size = (uint64_t)size_decode;
353 rotation = _ctsvc_image_get_rotation_info(info->src);
354 if (IMAGE_UTIL_ROTATION_NONE != rotation) { /* need rotate */
356 media_packet_h packet;
358 fmt = ctsvc_image_util_create_media_format(mimetype, width, height);
360 /* LCOV_EXCL_START */
361 ERR("ctsvc_image_util_create_media_format() Fail");
362 info->ret = CONTACTS_ERROR_SYSTEM;
368 packet = ctsvc_image_util_create_media_packet(fmt, buffer, (unsigned int)size);
371 if (NULL == packet) {
372 /* LCOV_EXCL_START */
373 ERR("ctsvc_image_util_create_media_packet() Fail");
374 media_format_unref(fmt);
375 info->ret = CONTACTS_ERROR_SYSTEM;
380 ret = ctsvc_image_util_rotate(packet, rotation, &buffer_temp, &size);
382 media_packet_destroy(packet);
383 media_format_unref(fmt);
385 if (CONTACTS_ERROR_NONE != ret) {
386 /* LCOV_EXCL_START */
387 info->ret = CONTACTS_ERROR_SYSTEM;
392 if (rotation == IMAGE_UTIL_ROTATION_90 || rotation == IMAGE_UTIL_ROTATION_270) {
397 buffer = buffer_temp;
400 if (info->max_size < width || info->max_size < height) { /* need resize */
404 media_packet_h packet;
407 if (width > height) {
408 resized_width = info->max_size;
409 resized_height = height * info->max_size / width;
411 resized_height = info->max_size;
412 resized_width = width * info->max_size / height;
415 if (resized_height % 8)
416 resized_height += (8 - (resized_height % 8));
418 if (resized_width % 8)
419 resized_width += (8 - (resized_width % 8));
421 fmt = ctsvc_image_util_create_media_format(mimetype, width, height);
423 /* LCOV_EXCL_START */
424 ERR("ctsvc_image_util_create_media_format() Fail");
425 info->ret = CONTACTS_ERROR_SYSTEM;
431 packet = ctsvc_image_util_create_media_packet(fmt, buffer, (unsigned int)size);
434 if (NULL == packet) {
435 /* LCOV_EXCL_START */
436 ERR("ctsvc_image_util_create_media_packet() Fail");
437 media_format_unref(fmt);
438 info->ret = CONTACTS_ERROR_SYSTEM;
443 ret = ctsvc_image_util_resize(packet, resized_width, resized_height, &buffer_temp,
446 media_packet_destroy(packet);
447 media_format_unref(fmt);
449 if (CONTACTS_ERROR_NONE != ret) {
453 buffer = buffer_temp;
455 width = resized_width;
456 height = resized_height;
459 image_util_encode_h eh = NULL;
461 unsigned long long ll_size_encode = 0;
463 ret = image_util_encode_create(IMAGE_UTIL_JPEG, &eh);
464 if (IMAGE_UTIL_ERROR_NONE != ret)
466 ret = image_util_encode_set_input_buffer(eh, buffer);
467 if (IMAGE_UTIL_ERROR_NONE != ret)
469 ret = image_util_encode_set_resolution(eh, width, height);
470 if (IMAGE_UTIL_ERROR_NONE != ret)
472 ret = image_util_encode_set_colorspace(eh, colorspace);
473 if (IMAGE_UTIL_ERROR_NONE != ret)
475 ret = image_util_encode_set_quality(eh, CTSVC_IMAGE_ENCODE_QUALITY);
476 if (IMAGE_UTIL_ERROR_NONE != ret)
478 ret = image_util_encode_set_output_path(eh, info->dest);
479 if (IMAGE_UTIL_ERROR_NONE != ret)
481 ret = image_util_encode_run(eh, &ll_size_encode);
484 ret = image_util_encode_destroy(eh);
486 if (IMAGE_UTIL_ERROR_NONE != ret) {
487 /* LCOV_EXCL_START */
488 ERR("image_util_encode_jpeg Fail(%d)", ret);
489 info->ret = CONTACTS_ERROR_SYSTEM;
494 dest_fd = open(info->dest, O_RDONLY);
496 /* LCOV_EXCL_START */
497 ERR("System : Open Fail(%d)", errno);
498 info->ret = CONTACTS_ERROR_SYSTEM;
503 ret = fchmod(dest_fd, CTS_SECURITY_IMAGE_PERMISSION);
505 /* LCOV_EXCL_START */
506 ERR("fchmod Fail(%d)", errno);
507 info->ret = CONTACTS_ERROR_SYSTEM;
514 info->ret = CONTACTS_ERROR_NONE;
518 static int _ctsvc_image_encode(const char *src, const char *dest, int max_size)
521 image_info info = {src, dest, max_size, CONTACTS_ERROR_SYSTEM};
523 ret = image_util_foreach_supported_colorspace(IMAGE_UTIL_JPEG,
524 _ctsvc_image_util_supported_jpeg_colorspace_cb, &info);
526 if (IMAGE_UTIL_ERROR_NONE != ret)
527 return CONTACTS_ERROR_SYSTEM;
532 #define CTSVC_COPY_SIZE_MAX 4096
533 int ctsvc_utils_copy_image(const char *dir, const char *src, const char *file)
538 char buf[CTSVC_COPY_SIZE_MAX] = {0};
540 if (NULL == file || *file == '\0')
541 return CONTACTS_ERROR_INVALID_PARAMETER;
543 char dest[strlen(dir) + strlen(file) + 2];
544 snprintf(dest, sizeof(dest), "%s/%s", dir, file);
546 if (false == _ctsvc_check_available_image_space(1204 * 1204)) /*need larger than 1M*/
547 return CONTACTS_ERROR_FILE_NO_SPACE;
549 ret = _ctsvc_image_encode(src, dest, CTSVC_IMAGE_MAX_SIZE);
550 if (CONTACTS_ERROR_NONE == ret)
554 /* LCOV_EXCL_START */
555 ERR("_ctsvc_image_encode Fail(%d)", ret);
558 src_fd = open(src, O_RDONLY);
560 /* LCOV_EXCL_START */
561 ERR("System : Open(%s) Fail(%d)", src, errno);
562 return CONTACTS_ERROR_SYSTEM;
566 dest_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, 0660);
568 /* LCOV_EXCL_START */
569 ERR("Open Fail(%d)", errno);
571 return CONTACTS_ERROR_SYSTEM;
575 while (0 < (size = read(src_fd, buf, CTSVC_COPY_SIZE_MAX))) {
576 ret = write(dest_fd, buf, size);
578 if (EINTR == errno) {
581 /* LCOV_EXCL_START */
582 ERR("write() Fail(%d)", errno);
584 ret = CONTACTS_ERROR_FILE_NO_SPACE; /* No space */
586 ret = CONTACTS_ERROR_SYSTEM; /* IO error */
596 ret = fchmod(dest_fd, CTS_SECURITY_IMAGE_PERMISSION);
598 /* LCOV_EXCL_START */
599 ERR("fchmod() Fail(%d)", ret);
605 return CONTACTS_ERROR_NONE;
608 char* ctsvc_utils_get_thumbnail_path(const char *image_path, bool check_file)
612 char *thumbnail_path = NULL;
615 RETV_IF(NULL == image_path, NULL);
616 RETV_IF(NULL != strstr(image_path, CTSVC_IMAGE_THUMBNAIL_SUFFIX), NULL);
618 full_len = strlen(image_path) + strlen(CTSVC_IMAGE_THUMBNAIL_SUFFIX) + 1;
619 thumbnail_path = calloc(1, full_len);
620 if (NULL == thumbnail_path) {
621 /* LCOV_EXCL_START */
622 ERR("calloc() Fail");
627 ext = strrchr(image_path, '.');
629 name_len = ext -image_path;
630 strncpy(thumbnail_path, image_path, name_len);
631 snprintf(thumbnail_path+name_len, full_len-name_len, "%s%s", CTSVC_IMAGE_THUMBNAIL_SUFFIX, ext);
633 snprintf(thumbnail_path, full_len, "%s%s", image_path, CTSVC_IMAGE_THUMBNAIL_SUFFIX);
637 char full_path[CTSVC_IMG_FULL_PATH_SIZE_MAX] = {0};
638 if (NULL != strstr(thumbnail_path, CTSVC_CONTACT_IMG_FULL_LOCATION))
639 snprintf(full_path, sizeof(full_path), "%s", thumbnail_path);
641 snprintf(full_path, sizeof(full_path), "%s/%s", CTSVC_CONTACT_IMG_FULL_LOCATION, thumbnail_path);
643 if (0 != access(full_path, F_OK)) {
644 free(thumbnail_path);
645 /* The original image is used as a thumbnail when the thumbnail is not made */
646 return strdup(image_path);
650 return thumbnail_path;
653 char* ctsvc_utils_get_image_path(const char *thumbnail_path)
657 char *image_path = NULL;
660 RETV_IF(NULL == thumbnail_path, NULL);
662 if (NULL == strstr(thumbnail_path, CTSVC_IMAGE_THUMBNAIL_SUFFIX)) {
663 /* The original image is used as a thumbnail when the thumbnail is not made */
664 return strdup(thumbnail_path);
668 full_len = strlen(thumbnail_path) - strlen(CTSVC_IMAGE_THUMBNAIL_SUFFIX) + 1;
669 image_path = calloc(1, full_len);
670 if (NULL == image_path) {
671 /* LCOV_EXCL_START */
672 ERR("calloc() Fail");
677 ext = strrchr(thumbnail_path, '.');
679 name_len = ext -thumbnail_path - strlen(CTSVC_IMAGE_THUMBNAIL_SUFFIX);
680 strncpy(image_path, thumbnail_path, name_len);
681 snprintf(image_path + name_len, full_len -name_len, "%s", ext);
683 name_len = strlen(thumbnail_path) - strlen(CTSVC_IMAGE_THUMBNAIL_SUFFIX);
684 strncpy(image_path, thumbnail_path, name_len);
689 char* ctsvc_utils_make_thumbnail(const char *image_path)
692 char src[CTSVC_IMG_FULL_PATH_SIZE_MAX] = {0};
693 char dest[CTSVC_IMG_FULL_PATH_SIZE_MAX] = {0};
694 char *thumbnail_path = NULL;
696 RETV_IF(NULL == image_path, NULL);
697 RETV_IF(NULL != strstr(image_path, CTSVC_IMAGE_THUMBNAIL_SUFFIX), NULL);
699 if (false == _ctsvc_check_available_image_space(
700 CTSVC_IMAGE_THUMBNAIL_SIZE * CTSVC_IMAGE_THUMBNAIL_SIZE)) {
701 /* LCOV_EXCL_START */
702 ERR("No space to make thumbnail");
707 thumbnail_path = ctsvc_utils_get_thumbnail_path(image_path, FALSE);
708 if (NULL == thumbnail_path) {
709 /* LCOV_EXCL_START */
710 ERR("ctsvc_image_util_get_thumbnail_path() Fail");
715 snprintf(src, sizeof(src), "%s/%s", CTSVC_CONTACT_IMG_FULL_LOCATION, image_path);
716 snprintf(dest, sizeof(dest), "%s/%s", CTSVC_CONTACT_IMG_FULL_LOCATION, thumbnail_path);
718 if (0 == access(dest, F_OK)) {
719 DBG("already exist");
720 return thumbnail_path;
723 ret = _ctsvc_image_encode(src, dest, CTSVC_IMAGE_THUMBNAIL_SIZE);
724 if (CONTACTS_ERROR_NONE != ret) {
725 /* LCOV_EXCL_START */
726 ERR("_ctsvc_image_encode() Fail(%d)", ret);
727 free(thumbnail_path);
728 /* The original image is used as a thumbnail when the thumbnail is not made */
729 return strdup(image_path);
733 return thumbnail_path;
736 int ctsvc_get_next_ver(void)
742 if (0 < transaction_count) {
744 return transaction_ver + 1;
747 query = "SELECT ver FROM "CTS_TABLE_VERSION;
748 ret = ctsvc_query_get_first_int_result(query, &version);
750 /* In this case, contacts-service already works abnormally. */
751 if (CONTACTS_ERROR_NONE != ret)
752 /* LCOV_EXCL_START */
753 ERR("ctsvc_query_get_first_int_result : get version error(%d)", ret);
756 return (1 + version);
759 int ctsvc_get_current_version(int *out_current_version)
761 if (transaction_count <= 0) {
764 const char *query = "SELECT ver FROM "CTS_TABLE_VERSION;
766 ret = ctsvc_query_get_first_int_result(query, &version);
767 if (CONTACTS_ERROR_NONE != ret) {
768 /* LCOV_EXCL_START */
769 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
774 *out_current_version = version;
776 *out_current_version = transaction_ver;
778 return CONTACTS_ERROR_NONE;
781 int ctsvc_get_transaction_ver(void)
783 return transaction_ver;
786 int SAFE_SNPRINTF(char **buf, int *buf_size, int len, const char *src)
794 remain = *buf_size - len;
795 if (strlen(src) + 1 < remain) {
796 temp_len = snprintf((*buf)+len, remain, "%s", src);
801 temp = realloc(*buf, *buf_size*2);
805 *buf_size = *buf_size * 2;
806 remain = *buf_size - len;
807 if (strlen(src) + 1 < remain)
810 temp_len = snprintf((*buf)+len, remain, "%s", src);