2 * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <glib/gprintf.h>
22 #include "mtp_support.h"
23 #include "ptp_datacodes.h"
29 static mtp_char *__util_conv_int_to_hex_str(mtp_int32 int_val, mtp_char *str);
35 void _util_conv_byte_order(void *data, mtp_int32 size)
40 mtp_uchar *l_data = (mtp_uchar *)data;
43 retm_if(size <= 1, "size(%d) is invalid", size);
46 for (idx = 0; idx < h_size; idx++) {
48 l_data[idx] = l_data[size - idx - 1];
49 l_data[size - idx - 1] = temp;
55 void _util_conv_byte_order_wstring(mtp_uint16 *wstr, mtp_int32 size)
57 _util_conv_byte_order_gen_str(wstr, size, sizeof(mtp_uint16));
61 void _util_conv_byte_order_gen_str(void *str, mtp_int32 size, mtp_int32 elem_sz)
64 mtp_int32 f_size = size * elem_sz;
65 mtp_uchar *l_str = (mtp_uchar *)str;
68 retm_if(elem_sz <= 1, "elem_sz(%d) is invalid", elem_sz);
70 for (idx = 0; idx < f_size; idx += elem_sz)
71 _util_conv_byte_order(&(l_str[idx]), elem_sz);
78 * If items_written is greater than or equal to dest_size,
79 * src is truncated when it is copied to dest.
81 mtp_int32 _util_utf16_to_utf8(char *dest, mtp_int32 dest_size,
87 glong items_written = 0;
88 const gunichar2 *utf16 = (const gunichar2 *)src;
90 retv_if(src == NULL, 0);
91 retv_if(dest == NULL, 0);
93 utf8 = g_utf16_to_utf8(utf16, -1, &items_read, &items_written, &error);
96 ERR("%s\n", error->message);
103 g_strlcpy(dest, (char *)utf8, dest_size);
107 return (mtp_int32)items_written;
111 * If items_written is greater than or equal to dest_items,
112 * src is truncated when it is copied to dest.
114 mtp_int32 _util_utf8_to_utf16(mtp_wchar *dest, mtp_int32 dest_items,
117 GError *error = NULL;
118 glong items_read = 0;
119 gunichar2 *utf16 = NULL;
120 glong items_written = 0;
122 retv_if(src == NULL, 0);
123 retv_if(dest == NULL, 0);
125 utf16 = g_utf8_to_utf16(src, -1, &items_read, &items_written, &error);
127 /* LCOV_EXCL_START */
128 ERR("%s\n", error->message);
132 dest[0] = (mtp_wchar)'\0';
136 _util_wchar_ncpy(dest, utf16, dest_items);
140 return (mtp_int32)items_written;
145 * Copies a unicode string.
146 * @param[in] src Null-terminated source string
147 * @param[out] dest Destination buffer
150 /* LCOV_EXCL_START */
151 void _util_wchar_cpy(mtp_wchar *dest, const mtp_wchar *src)
154 ret_if(dest == NULL);
156 if (!((uintptr_t)dest & 0x1) && !((uintptr_t)src & 0x1)) {
158 mtp_wchar *temp = dest;
160 while ((*temp++ = *src++) != '\0')
163 /* not-aligned, byte to byte approach - slow */
164 mtp_char *pc1 = (mtp_char *)dest;
165 mtp_char *pc2 = (mtp_char *)src;
167 while (*pc2 || *(pc2 + 1)) {
169 *(pc1 + 1) = *(pc2 + 1);
181 * Copies a unicode string a given numbers of character.
182 * @param[in] src Null-terminated source string
183 * @param[out] dest Destination buffer
186 void _util_wchar_ncpy(mtp_wchar *dest, const mtp_wchar *src, unsigned long n)
190 mtp_wchar *temp = NULL;
193 ret_if(dest == NULL);
195 if (!((uintptr_t)dest & 0x1) && !((uintptr_t)src & 0x1)) { /* 2-byte aligned */
198 while (n && (*temp++ = *src++))
205 } else { /* not-aligned, byte to byte approach - slow */
210 /* LCOV_EXCL_START */
211 while (n && (*pc2 || *(pc2 + 1))) {
229 * Returns the length of wide character string
230 * @param[in] src Wide char string
233 size_t _util_wchar_len(const mtp_wchar *s)
235 if (!((uintptr_t)s & 0x1)) { /* 2-byte aligned */
236 mtp_wchar *temp = (mtp_wchar *)s;
241 DBG("Length : %zd\n", temp - s - 1);
242 return ((size_t)(temp - s - 1));
243 } else { /* not-aligned, byte to byte approach - slow */
245 unsigned char *temp = (unsigned char *)s;
247 while (*temp || *(temp + 1))
250 DBG("Length : %zd\n", (temp - (unsigned char *)s) / 2);
251 return ((size_t) (temp - (unsigned char *)s) / 2);
255 static mtp_char* __util_conv_int_to_hex_str(mtp_int32 int_val, mtp_char *str)
257 mtp_char *nstr = str;
258 mtp_int32 val = int_val;
259 mtp_char hex[] = { "0123456789ABCDEF" };
261 retv_if(str == NULL, NULL);
266 for (val = int_val; val; val <<= 4)
267 *nstr++ = hex[(val >> (sizeof(int) * 8 - 4)) & 0xF];
274 * This is very minimal implementation.
275 * Be cautious using this function.
277 mtp_err_t _util_wchar_swprintf(mtp_wchar *mtp_wstr, mtp_int32 size,
278 mtp_char *format, ...)
283 mtp_wchar *wbuf = mtp_wstr;
284 mtp_char *bptr_val = NULL;
285 mtp_wchar *wstr_val = NULL;
286 mtp_int32 int_val = 0, len = 0;
287 mtp_char buf[MTP_MAX_PATHNAME_SIZE + 1];
290 va_start(arg_list, format);
291 for (ptr = format; *ptr && count < (size - 1); ptr++) {
293 switch (*(ptr + 1)) {
295 int_val = va_arg(arg_list, int);
296 wbuf[count++] = (mtp_wchar) (int_val + '0');
300 bptr_val = va_arg(arg_list, char *);
301 wstr_val = (mtp_wchar *) bptr_val;
302 len = _util_wchar_len(wstr_val);
303 if (len + count > size - 1) {
304 len = size - 1 - count;
305 _util_wchar_ncpy(&wbuf[count], wstr_val,
308 _util_wchar_cpy(&wbuf[count], wstr_val);
314 int_val = va_arg(arg_list, int);
315 __util_conv_int_to_hex_str(int_val, buf);
316 _util_utf8_to_utf16(wsHex,
317 sizeof(wsHex) / WCHAR_SIZ, buf);
319 if (len + count > size - 1) {
320 len = size - 1 - count;
321 _util_wchar_ncpy(&wbuf[count], wsHex,
324 _util_wchar_cpy(&wbuf[count], wsHex);
331 DBG("swprintf not handling: %c", *(ptr + 1));
335 wbuf[count++] = (mtp_wchar)(*ptr);
340 wbuf[count] = (mtp_wchar)'\0';
341 _util_utf16_to_utf8(buf, sizeof(buf), wbuf);
343 return MTP_ERROR_NONE;
347 mtp_uint16 _util_get_fmtcode(const mtp_char *extn)
349 static fmt_code_t fmt_code_table[] = {
350 {"ALB", MTP_FMT_ABSTRACT_AUDIO_ALBUM},
351 {"MP3", PTP_FMT_MP3},
352 {"WMA", MTP_FMT_WMA},
353 {"WMV", MTP_FMT_WMV},
354 {"JPG", PTP_FMT_IMG_EXIF},
355 {"GIF", PTP_FMT_IMG_GIF},
356 {"BMP", PTP_FMT_IMG_BMP},
357 {"PNG", PTP_FMT_IMG_PNG},
358 {"ASF", PTP_FMT_ASF},
359 {"WAV", PTP_FMT_WAVE},
360 {"AVI", PTP_FMT_AVI},
361 {"MPG", PTP_FMT_MPEG},
362 {"TXT", PTP_FMT_TEXT},
363 {"3GP", MTP_FMT_3GP},
364 {"ODF", MTP_FMT_3GP},
365 {"O4A", MTP_FMT_3GP},
366 {"O4V", MTP_FMT_3GP},
367 {"MP4", MTP_FMT_MP4},
368 {"FLAC", MTP_FMT_FLAC},
372 fmt_code_t *p = NULL;
375 while (p->fmt_code != PTP_FMT_UNDEF) {
376 if (!strncasecmp(extn, p->extn, strlen(p->extn)))
382 /* will return FormatCode or PTP_FORMATCODE_UNDEFINED
383 * if we hit end of list.
389 * This function gets the file extension.
390 * @param[in] fileName Specifies the file name.
391 * @param[out] file_extn holds the extension of the file.
392 * @return Returns TRUE on success and FALSE on failure.
394 mtp_bool _util_get_file_extn(const mtp_char *f_name, mtp_char *f_extn)
398 retv_if(NULL == f_name, FALSE);
399 retv_if(NULL == f_extn, FALSE);
401 ptr = strrchr(f_name, '.');
404 g_strlcpy(f_extn, ptr + 1, MTP_MAX_PATHNAME_SIZE);
411 mtp_bool _util_get_file_name(const mtp_char *fullpath, mtp_char *f_name)
415 retv_if(f_name == NULL, FALSE);
416 retv_if(fullpath == NULL, FALSE);
418 i = strlen(fullpath);
420 for (j = 0; i >= 0; i--) {
421 if (fullpath[i] == '/') {
422 g_strlcpy(f_name, &fullpath[i + 1], j);
427 g_strlcpy(f_name, fullpath, j);
432 * This function gives file name without extension.
433 * @param[in] fullpath pointer to absolute file path
434 * @param[out] f_name gets filled with filename w/o extension
435 * @return True or False based on success or failure
437 /* LCOV_EXCL_START */
438 mtp_bool _util_get_file_name_wo_extn(const mtp_char *fullpath, mtp_char *f_name)
441 mtp_uint32 fname_len;
442 mtp_char *extn_ptr = NULL;
444 retv_if(f_name == NULL, FALSE);
445 retv_if(fullpath == NULL, FALSE);
447 fname_ptr = strrchr(fullpath, '/');
449 if (fname_ptr == NULL) {
450 ERR("Invalid File Name");
454 fname_ptr = fname_ptr + sizeof(char);
455 fname_len = strlen(fname_ptr);
456 extn_ptr = strrchr(fname_ptr, '.');
458 if (extn_ptr == NULL) {
459 g_strlcpy(f_name, fname_ptr, fname_len + 1);
463 g_strlcpy(f_name, fname_ptr, ((mtp_uint32)(extn_ptr - fname_ptr) + 1));
468 mtp_bool _util_is_path_len_valid(const mtp_char *path)
470 mtp_uint32 limit = 0;
471 mtp_uint32 mtp_path_len = 0;
472 mtp_uint32 root_path_len = 0;
474 static mtp_uint32 max_store_len = 0;
475 static mtp_bool is_initialized = FALSE;
476 static mtp_uint32 internal_store_len = 0;
477 static mtp_uint32 external_store_len = 0;
479 char ext_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
480 char inter_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
482 retv_if(path == NULL, FALSE);
484 _util_get_external_path(ext_path);
485 _util_get_internal_path(inter_path);
487 if (!is_initialized) {
488 is_initialized = TRUE;
489 internal_store_len = strlen(inter_path);
490 external_store_len = strlen(ext_path);
492 max_store_len = internal_store_len > external_store_len ?
493 internal_store_len : external_store_len;
495 DBG("max store len : [%u]\n", max_store_len);
498 if (!strncmp(path, inter_path, internal_store_len)) {
499 root_path_len = internal_store_len;
500 } else if (!strncmp(path, ext_path, external_store_len)) {
501 root_path_len = external_store_len;
503 ERR("Unknown store's path : %s\n", path);
507 /* Path len should be calculated except root path(eg. /opt/usr/media) */
508 mtp_path_len = strlen(path) - root_path_len;
510 /* MTP_MAX_PATHNAME_SIZE includes maximum length of root path */
511 limit = MTP_MAX_PATHNAME_SIZE - max_store_len;
513 if (mtp_path_len > limit) {
514 ERR("Too long path : [%u] > [%u]\n", mtp_path_len, limit);
521 mtp_bool _util_create_path(mtp_char *path, mtp_uint32 size, const mtp_char *dir,
522 const mtp_char *filename)
527 retv_if(dir == NULL, FALSE);
528 retv_if(path == NULL, FALSE);
529 retv_if(filename == NULL, FALSE);
531 len = strlen(filename);
532 if (len > MTP_MAX_FILENAME_SIZE) {
533 /* LCOV_EXCL_START */
534 ERR("filename is too long :[%u] > [%u]\n", len,
535 MTP_MAX_FILENAME_SIZE);
539 ret = g_snprintf(path, size, "%s/%s", dir, filename);
541 ERR("path is truncated");
545 if (_util_is_path_len_valid(path) == FALSE) {
546 ERR("path length exceeds the limit");
554 * This function gets the parent path.
555 * @param[in] fullpath Pointer to a buffer containing full file path.
556 * @param[out] p_path Points the buffer to hold parent path.
559 void _util_get_parent_path(const mtp_char *fullpath, mtp_char *p_path)
561 mtp_char *ptr = NULL;
563 ret_if(NULL == p_path);
564 ret_if(NULL == fullpath);
566 ptr = strrchr(fullpath, '/');
568 ERR("Path does not have parent path");
572 g_strlcpy(p_path, fullpath, (mtp_uint32)(ptr - fullpath) + 1);
576 void _util_conv_wstr_to_guid(mtp_wchar *wstr, mtp_uint64 *guid)
582 mtp_int32 cpy_sz = 0;
584 ret_if(wstr == NULL);
585 ret_if(guid == NULL);
587 while (wstr[count] != 0)
590 memset(guid, 0, sizeof(temp));
591 skip_idx = sizeof(temp) / sizeof(mtp_wchar);
593 for (cur_idx = 0; cur_idx < count; cur_idx += skip_idx) {
595 memset(temp, 0, sizeof(temp));
596 cpy_sz = (count - cur_idx) * sizeof(mtp_wchar);
597 if (cpy_sz > sizeof(temp))
598 cpy_sz = sizeof(temp);
600 memcpy(temp, &(wstr[cur_idx]), cpy_sz);
608 mtp_bool _util_get_unique_dir_path(const mtp_char *exist_path,
609 mtp_char *new_path, mtp_uint32 new_path_buf_len)
611 mtp_uint32 num_bytes = 0;
612 mtp_uint32 max_value = 1;
613 mtp_uint32 count = 1;
615 mtp_char *buf = NULL;
616 mtp_uint32 len = strlen(exist_path);
618 retv_if(new_path == NULL, FALSE);
619 retv_if(exist_path == NULL, FALSE);
622 num_bytes = new_path_buf_len - len - 1;
623 if (num_bytes <= 0) {
624 ERR("No space to append data[%d]\n", num_bytes);
628 if (num_bytes >= MTP_BUF_SIZE_FOR_INT - 1) {
629 max_value = UINT_MAX;
631 while (count <= num_bytes) {
635 DBG("max_value[%u]\n", max_value);
638 buf = (mtp_char *)g_malloc(new_path_buf_len);
640 ERR("g_malloc Fail");
643 g_strlcpy(buf, exist_path, new_path_buf_len);
644 while (val < max_value) {
645 /* Including NUL and '_' */
646 g_snprintf(&buf[len], num_bytes + 2, "_%u", val++);
647 if (access(buf, F_OK) < 0)
652 ERR("Unable to generate Unique Dir Name");
656 g_strlcpy(new_path, buf, new_path_buf_len);
658 DBG_SECURE("Unique dir name[%s]\n", new_path);
662 mtp_int32 _util_system_cmd_wait(const mtp_char *cmd)
680 argv[2] = (char*)cmd;
682 execv("/bin/sh", argv);
687 if (waitpid(pid, &status, 0) == -1) {