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>
21 #include "mtp_support.h"
22 #include "ptp_datacodes.h"
28 static mtp_char *__util_conv_int_to_hex_str(mtp_int32 int_val, mtp_char *str);
34 void _util_conv_byte_order(void *data, mtp_int32 size)
39 mtp_uchar *l_data = (mtp_uchar *)data;
42 retm_if(size <= 1, "size(%d) is invalid", size);
45 for (idx = 0; idx < h_size; idx++) {
47 l_data[idx] = l_data[size - idx - 1];
48 l_data[size - idx - 1] = temp;
54 void _util_conv_byte_order_wstring(mtp_uint16 *wstr, mtp_int32 size)
56 _util_conv_byte_order_gen_str(wstr, size, sizeof(mtp_uint16));
60 void _util_conv_byte_order_gen_str(void *str, mtp_int32 size, mtp_int32 elem_sz)
63 mtp_int32 f_size = size * elem_sz;
64 mtp_uchar *l_str = (mtp_uchar *)str;
67 retm_if(elem_sz <= 1, "elem_sz(%d) is invalid", elem_sz);
69 for (idx = 0; idx < f_size; idx += elem_sz)
70 _util_conv_byte_order(&(l_str[idx]), elem_sz);
77 * If items_written is greater than or equal to dest_size,
78 * src is truncated when it is copied to dest.
80 mtp_int32 _util_utf16_to_utf8(char *dest, mtp_int32 dest_size,
86 glong items_written = 0;
87 const gunichar2 *utf16 = (const gunichar2 *)src;
89 retv_if(src == NULL, 0);
90 retv_if(dest == NULL, 0);
92 utf8 = g_utf16_to_utf8(utf16, -1, &items_read, &items_written, &error);
95 ERR("%s\n", error->message);
102 g_strlcpy(dest, (char *)utf8, dest_size);
106 return (mtp_int32)items_written;
110 * If items_written is greater than or equal to dest_items,
111 * src is truncated when it is copied to dest.
113 mtp_int32 _util_utf8_to_utf16(mtp_wchar *dest, mtp_int32 dest_items,
116 GError *error = NULL;
117 glong items_read = 0;
118 gunichar2 *utf16 = NULL;
119 glong items_written = 0;
121 retv_if(src == NULL, 0);
122 retv_if(dest == NULL, 0);
124 utf16 = g_utf8_to_utf16(src, -1, &items_read, &items_written, &error);
126 /* LCOV_EXCL_START */
127 ERR("%s\n", error->message);
131 dest[0] = (mtp_wchar)'\0';
135 _util_wchar_ncpy(dest, utf16, dest_items);
139 return (mtp_int32)items_written;
144 * Copies a unicode string.
145 * @param[in] src Null-terminated source string
146 * @param[out] dest Destination buffer
149 /* LCOV_EXCL_START */
150 void _util_wchar_cpy(mtp_wchar *dest, const mtp_wchar *src)
153 ret_if(dest == NULL);
155 if (!((int)dest & 0x1) && !((int)src & 0x1)) {
157 mtp_wchar *temp = dest;
159 while ((*temp++ = *src++) != '\0')
162 /* not-aligned, byte to byte approach - slow */
163 mtp_char *pc1 = (mtp_char *)dest;
164 mtp_char *pc2 = (mtp_char *)src;
166 while (*pc2 || *(pc2 + 1)) {
168 *(pc1 + 1) = *(pc2 + 1);
180 * Copies a unicode string a given numbers of character.
181 * @param[in] src Null-terminated source string
182 * @param[out] dest Destination buffer
185 void _util_wchar_ncpy(mtp_wchar *dest, const mtp_wchar *src, unsigned long n)
189 mtp_wchar *temp = NULL;
192 ret_if(dest == NULL);
194 if (!((int)dest & 0x1) && !((int)src & 0x1)) { /* 2-byte aligned */
197 while (n && (*temp++ = *src++))
204 } else { /* not-aligned, byte to byte approach - slow */
209 /* LCOV_EXCL_START */
210 while (n && (*pc2 || *(pc2 + 1))) {
228 * Returns the length of wide character string
229 * @param[in] src Wide char string
232 size_t _util_wchar_len(const mtp_wchar *s)
234 if (!((int)s & 0x1)) { /* 2-byte aligned */
235 mtp_wchar *temp = (mtp_wchar *)s;
240 DBG("Length : %d\n", temp - s - 1);
241 return ((size_t)(temp - s - 1));
242 } else { /* not-aligned, byte to byte approach - slow */
244 unsigned char *temp = (unsigned char *)s;
246 while (*temp || *(temp + 1))
249 DBG("Length : %d\n", (temp - (unsigned char *)s) / 2);
250 return ((size_t) (temp - (unsigned char *)s) / 2);
254 static mtp_char* __util_conv_int_to_hex_str(mtp_int32 int_val, mtp_char *str)
256 mtp_char *nstr = str;
257 mtp_int32 val = int_val;
258 mtp_char hex[] = { "0123456789ABCDEF" };
260 retv_if(str == NULL, NULL);
265 for (val = int_val; val; val <<= 4)
266 *nstr++ = hex[(val >> (sizeof(int) * 8 - 4)) & 0xF];
273 * This is very minimal implementation.
274 * Be cautious using this function.
276 mtp_err_t _util_wchar_swprintf(mtp_wchar *mtp_wstr, mtp_int32 size,
277 mtp_char *format, ...)
282 mtp_wchar *wbuf = mtp_wstr;
283 mtp_char *bptr_val = NULL;
284 mtp_wchar *wstr_val = NULL;
285 mtp_int32 int_val = 0, len = 0;
286 mtp_char buf[MTP_MAX_PATHNAME_SIZE + 1];
289 va_start(arg_list, format);
290 for (ptr = format; *ptr && count < (size - 1); ptr++) {
292 switch (*(ptr + 1)) {
294 int_val = va_arg(arg_list, int);
295 wbuf[count++] = (mtp_wchar) (int_val + '0');
299 bptr_val = va_arg(arg_list, char *);
300 wstr_val = (mtp_wchar *) bptr_val;
301 len = _util_wchar_len(wstr_val);
302 if (len + count > size - 1) {
303 len = size - 1 - count;
304 _util_wchar_ncpy(&wbuf[count], wstr_val,
307 _util_wchar_cpy(&wbuf[count], wstr_val);
313 int_val = va_arg(arg_list, int);
314 __util_conv_int_to_hex_str(int_val, buf);
315 _util_utf8_to_utf16(wsHex,
316 sizeof(wsHex) / WCHAR_SIZ, buf);
318 if (len + count > size - 1) {
319 len = size - 1 - count;
320 _util_wchar_ncpy(&wbuf[count], wsHex,
323 _util_wchar_cpy(&wbuf[count], wsHex);
330 DBG("swprintf not handling: %c", *(ptr + 1));
334 wbuf[count++] = (mtp_wchar)(*ptr);
339 wbuf[count] = (mtp_wchar)'\0';
340 _util_utf16_to_utf8(buf, sizeof(buf), wbuf);
342 return MTP_ERROR_NONE;
346 mtp_uint16 _util_get_fmtcode(const mtp_char *extn)
348 static fmt_code_t fmt_code_table[] = {
349 {"ALB", MTP_FMT_ABSTRACT_AUDIO_ALBUM},
350 {"MP3", PTP_FMT_MP3},
351 {"WMA", MTP_FMT_WMA},
352 {"WMV", MTP_FMT_WMV},
353 {"JPG", PTP_FMT_IMG_EXIF},
354 {"GIF", PTP_FMT_IMG_GIF},
355 {"BMP", PTP_FMT_IMG_BMP},
356 {"PNG", PTP_FMT_IMG_PNG},
357 {"ASF", PTP_FMT_ASF},
358 {"WAV", PTP_FMT_WAVE},
359 {"AVI", PTP_FMT_AVI},
360 {"MPG", PTP_FMT_MPEG},
361 {"TXT", PTP_FMT_TEXT},
362 {"3GP", MTP_FMT_3GP},
363 {"ODF", MTP_FMT_3GP},
364 {"O4A", MTP_FMT_3GP},
365 {"O4V", MTP_FMT_3GP},
366 {"MP4", MTP_FMT_MP4},
367 {"FLAC", MTP_FMT_FLAC},
371 fmt_code_t *p = NULL;
374 while (p->fmt_code != PTP_FMT_UNDEF) {
375 if (!strncasecmp(extn, p->extn, strlen(p->extn)))
381 /* will return FormatCode or PTP_FORMATCODE_UNDEFINED
382 * if we hit end of list.
388 * This function gets the file extension.
389 * @param[in] fileName Specifies the file name.
390 * @param[out] file_extn holds the extension of the file.
391 * @return Returns TRUE on success and FALSE on failure.
393 mtp_bool _util_get_file_extn(const mtp_char *f_name, mtp_char *f_extn)
397 retv_if(NULL == f_name, FALSE);
398 retv_if(NULL == f_extn, FALSE);
400 ptr = strrchr(f_name, '.');
403 g_strlcpy(f_extn, ptr + 1, MTP_MAX_PATHNAME_SIZE);
410 mtp_bool _util_get_file_name(const mtp_char *fullpath, mtp_char *f_name)
414 retv_if(f_name == NULL, FALSE);
415 retv_if(fullpath == NULL, FALSE);
417 i = strlen(fullpath);
419 for (j = 0; i >= 0; i--) {
420 if (fullpath[i] == '/') {
421 g_strlcpy(f_name, &fullpath[i + 1], j);
426 g_strlcpy(f_name, fullpath, j);
431 * This function gives file name without extension.
432 * @param[in] fullpath pointer to absolute file path
433 * @param[out] f_name gets filled with filename w/o extension
434 * @return True or False based on success or failure
436 /* LCOV_EXCL_START */
437 mtp_bool _util_get_file_name_wo_extn(const mtp_char *fullpath, mtp_char *f_name)
440 mtp_uint32 fname_len;
441 mtp_char *extn_ptr = NULL;
443 retv_if(f_name == NULL, FALSE);
444 retv_if(fullpath == NULL, FALSE);
446 fname_ptr = strrchr(fullpath, '/');
448 if (fname_ptr == NULL) {
449 ERR("Invalid File Name");
453 fname_ptr = fname_ptr + sizeof(char);
454 fname_len = strlen(fname_ptr);
455 extn_ptr = strrchr(fname_ptr, '.');
457 if (extn_ptr == NULL) {
458 g_strlcpy(f_name, fname_ptr, fname_len + 1);
462 g_strlcpy(f_name, fname_ptr, ((mtp_uint32)(extn_ptr - fname_ptr) + 1));
467 mtp_bool _util_is_path_len_valid(const mtp_char *path)
469 mtp_uint32 limit = 0;
470 mtp_uint32 mtp_path_len = 0;
471 mtp_uint32 root_path_len = 0;
473 static mtp_uint32 max_store_len = 0;
474 static mtp_bool is_initialized = FALSE;
475 static mtp_uint32 internal_store_len = 0;
476 static mtp_uint32 external_store_len = 0;
478 char ext_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
479 char inter_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
481 retv_if(path == NULL, FALSE);
483 _util_get_external_path(ext_path);
484 _util_get_internal_path(inter_path);
486 if (!is_initialized) {
487 is_initialized = TRUE;
488 internal_store_len = strlen(inter_path);
489 external_store_len = strlen(ext_path);
491 max_store_len = internal_store_len > external_store_len ?
492 internal_store_len : external_store_len;
494 DBG("max store len : [%u]\n", max_store_len);
497 if (!strncmp(path, inter_path, internal_store_len)) {
498 root_path_len = internal_store_len;
499 } else if (!strncmp(path, ext_path, external_store_len)) {
500 root_path_len = external_store_len;
502 ERR("Unknown store's path : %s\n", path);
506 /* Path len should be calculated except root path(eg. /opt/usr/media) */
507 mtp_path_len = strlen(path) - root_path_len;
509 /* MTP_MAX_PATHNAME_SIZE includes maximum length of root path */
510 limit = MTP_MAX_PATHNAME_SIZE - max_store_len;
512 if (mtp_path_len > limit) {
513 ERR("Too long path : [%u] > [%u]\n", mtp_path_len, limit);
520 mtp_bool _util_create_path(mtp_char *path, mtp_uint32 size, const mtp_char *dir,
521 const mtp_char *filename)
526 retv_if(dir == NULL, FALSE);
527 retv_if(path == NULL, FALSE);
528 retv_if(filename == NULL, FALSE);
530 len = strlen(filename);
531 if (len > MTP_MAX_FILENAME_SIZE) {
532 /* LCOV_EXCL_START */
533 ERR("filename is too long :[%u] > [%u]\n", len,
534 MTP_MAX_FILENAME_SIZE);
538 ret = g_snprintf(path, size, "%s/%s", dir, filename);
540 ERR("path is truncated");
544 if (_util_is_path_len_valid(path) == FALSE) {
545 ERR("path length exceeds the limit");
553 * This function gets the parent path.
554 * @param[in] fullpath Pointer to a buffer containing full file path.
555 * @param[out] p_path Points the buffer to hold parent path.
558 void _util_get_parent_path(const mtp_char *fullpath, mtp_char *p_path)
560 mtp_char *ptr = NULL;
562 ret_if(NULL == p_path);
563 ret_if(NULL == fullpath);
565 ptr = strrchr(fullpath, '/');
567 ERR("Path does not have parent path");
571 g_strlcpy(p_path, fullpath, (mtp_uint32)(ptr - fullpath) + 1);
575 void _util_conv_wstr_to_guid(mtp_wchar *wstr, mtp_uint64 *guid)
581 mtp_int32 cpy_sz = 0;
583 ret_if(wstr == NULL);
584 ret_if(guid == NULL);
586 while (wstr[count] != 0)
589 memset(guid, 0, sizeof(temp));
590 skip_idx = sizeof(temp) / sizeof(mtp_wchar);
592 for (cur_idx = 0; cur_idx < count; cur_idx += skip_idx) {
594 memset(temp, 0, sizeof(temp));
595 cpy_sz = (count - cur_idx) * sizeof(mtp_wchar);
596 if (cpy_sz > sizeof(temp))
597 cpy_sz = sizeof(temp);
599 memcpy(temp, &(wstr[cur_idx]), cpy_sz);
607 mtp_bool _util_get_unique_dir_path(const mtp_char *exist_path,
608 mtp_char *new_path, mtp_uint32 new_path_buf_len)
610 mtp_uint32 num_bytes = 0;
611 mtp_uint32 max_value = 1;
612 mtp_uint32 count = 1;
614 mtp_char *buf = NULL;
615 mtp_uint32 len = strlen(exist_path);
617 retv_if(new_path == NULL, FALSE);
618 retv_if(exist_path == NULL, FALSE);
621 num_bytes = new_path_buf_len - len - 1;
622 if (num_bytes <= 0) {
623 ERR("No space to append data[%d]\n", num_bytes);
627 if (num_bytes >= MTP_BUF_SIZE_FOR_INT - 1) {
628 max_value = UINT_MAX;
630 while (count <= num_bytes) {
634 DBG("max_value[%u]\n", max_value);
637 buf = (mtp_char *)g_malloc(new_path_buf_len);
639 ERR("g_malloc Fail");
642 g_strlcpy(buf, exist_path, new_path_buf_len);
643 while (val < max_value) {
644 /* Including NUL and '_' */
645 g_snprintf(&buf[len], num_bytes + 2, "_%u", val++);
646 if (access(buf, F_OK) < 0)
651 ERR("Unable to generate Unique Dir Name");
655 g_strlcpy(new_path, buf, new_path_buf_len);
657 DBG_SECURE("Unique dir name[%s]\n", new_path);
661 mtp_int32 _util_system_cmd_wait(const mtp_char *cmd)
679 argv[2] = (char*)cmd;
681 execv("/bin/sh", argv);
686 if (waitpid(pid, &status, 0) == -1) {