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>
20 #include "mtp_support.h"
21 #include "ptp_datacodes.h"
27 static mtp_char *__util_conv_int_to_hex_str(mtp_int32 int_val, mtp_char *str);
32 void _util_conv_byte_order(void *data, mtp_int32 size)
37 mtp_uchar *l_data = (mtp_uchar *)data;
40 retm_if(size <= 1, "size(%d) is invalid", size);
43 for (idx = 0; idx < h_size; idx++) {
45 l_data[idx] = l_data[size - idx - 1];
46 l_data[size - idx - 1] = temp;
52 void _util_conv_byte_order_wstring(mtp_uint16 *wstr, mtp_int32 size)
54 _util_conv_byte_order_gen_str(wstr, size, sizeof(mtp_uint16));
58 void _util_conv_byte_order_gen_str(void *str, mtp_int32 size, mtp_int32 elem_sz)
61 mtp_int32 f_size = size * elem_sz;
62 mtp_uchar *l_str = (mtp_uchar *)str;
65 retm_if(elem_sz <= 1, "elem_sz(%d) is invalid", elem_sz);
67 for (idx = 0; idx < f_size; idx += elem_sz)
68 _util_conv_byte_order(&(l_str[idx]), elem_sz);
74 * If items_written is greater than or equal to dest_size,
75 * src is truncated when it is copied to dest.
77 mtp_int32 _util_utf16_to_utf8(char *dest, mtp_int32 dest_size,
83 glong items_written = 0;
84 const gunichar2 *utf16 = (const gunichar2 *)src;
86 retv_if(src == NULL, 0);
87 retv_if(dest == NULL, 0);
89 utf8 = g_utf16_to_utf8(utf16, -1, &items_read, &items_written, &error);
91 ERR("%s\n", error->message);
97 g_strlcpy(dest, (char *)utf8, dest_size);
101 return (mtp_int32)items_written;
105 * If items_written is greater than or equal to dest_items,
106 * src is truncated when it is copied to dest.
108 mtp_int32 _util_utf8_to_utf16(mtp_wchar *dest, mtp_int32 dest_items,
111 GError *error = NULL;
112 glong items_read = 0;
113 gunichar2 *utf16 = NULL;
114 glong items_written = 0;
116 retv_if(src == NULL, 0);
117 retv_if(dest == NULL, 0);
119 utf16 = g_utf8_to_utf16(src, -1, &items_read, &items_written, &error);
121 ERR("%s\n", error->message);
125 dest[0] = (mtp_wchar)'\0';
128 _util_wchar_ncpy(dest, utf16, dest_items);
132 return (mtp_int32)items_written;
137 * Copies a unicode string.
138 * @param[in] src Null-terminated source string
139 * @param[out] dest Destination buffer
142 void _util_wchar_cpy(mtp_wchar *dest, const mtp_wchar *src)
145 ret_if(dest == NULL);
147 if (!((int)dest & 0x1) && !((int)src & 0x1)) {
149 mtp_wchar *temp = dest;
151 while ((*temp++ = *src++) != '\0')
154 /* not-aligned, byte to byte approach - slow */
155 mtp_char *pc1 = (mtp_char *)dest;
156 mtp_char *pc2 = (mtp_char *)src;
158 while (*pc2 || *(pc2 + 1)) {
160 *(pc1 + 1) = *(pc2 + 1);
171 * Copies a unicode string a given numbers of character.
172 * @param[in] src Null-terminated source string
173 * @param[out] dest Destination buffer
176 void _util_wchar_ncpy(mtp_wchar *dest, const mtp_wchar *src, unsigned long n)
180 mtp_wchar *temp = NULL;
183 ret_if(dest == NULL);
185 if (!((int)dest & 0x1) && !((int)src & 0x1)) { /* 2-byte aligned */
188 while (n && (*temp++ = *src++))
195 } else { /* not-aligned, byte to byte approach - slow */
200 while (n && (*pc2 || *(pc2 + 1))) {
218 * Returns the length of wide character string
219 * @param[in] src Wide char string
222 size_t _util_wchar_len(const mtp_wchar *s)
224 if (!((int)s & 0x1)) { /* 2-byte aligned */
225 mtp_wchar *temp = (mtp_wchar *)s;
230 DBG("Length : %d\n", temp - s - 1);
231 return ((size_t)(temp - s - 1));
232 } else { /* not-aligned, byte to byte approach - slow */
234 unsigned char *temp = (unsigned char *)s;
236 while (*temp || *(temp + 1))
239 DBG("Length : %d\n", (temp - (unsigned char *)s) / 2);
240 return ((size_t) (temp - (unsigned char *)s) / 2);
244 static mtp_char* __util_conv_int_to_hex_str(mtp_int32 int_val, mtp_char *str)
246 mtp_char *nstr = str;
247 mtp_int32 val = int_val;
248 mtp_char hex[] = { "0123456789ABCDEF" };
250 retv_if(str == NULL, NULL);
255 for (val = int_val; val; val <<= 4)
256 *nstr++ = hex[(val >> (sizeof(int) * 8 - 4)) & 0xF];
263 * This is very minimal implementation.
264 * Be cautious using this function.
266 mtp_err_t _util_wchar_swprintf(mtp_wchar *mtp_wstr, mtp_int32 size,
267 mtp_char *format, ...)
272 mtp_wchar *wbuf = mtp_wstr;
273 mtp_char *bptr_val = NULL;
274 mtp_wchar *wstr_val = NULL;
275 mtp_int32 int_val = 0, len = 0;
276 mtp_char buf[MTP_MAX_PATHNAME_SIZE + 1];
279 va_start(arg_list, format);
280 for (ptr = format; *ptr && count < (size - 1); ptr++) {
282 switch (*(ptr + 1)) {
284 int_val = va_arg(arg_list, int);
285 wbuf[count++] = (mtp_wchar) (int_val + '0');
289 bptr_val = va_arg(arg_list, char *);
290 wstr_val = (mtp_wchar *) bptr_val;
291 len = _util_wchar_len(wstr_val);
292 if (len + count > size - 1) {
293 len = size - 1 - count;
294 _util_wchar_ncpy(&wbuf[count], wstr_val,
297 _util_wchar_cpy(&wbuf[count], wstr_val);
303 int_val = va_arg(arg_list, int);
304 __util_conv_int_to_hex_str(int_val, buf);
305 _util_utf8_to_utf16(wsHex,
306 sizeof(wsHex) / WCHAR_SIZ, buf);
308 if (len + count > size - 1) {
309 len = size - 1 - count;
310 _util_wchar_ncpy(&wbuf[count], wsHex,
313 _util_wchar_cpy(&wbuf[count], wsHex);
320 DBG("swprintf not handling: %c", *(ptr + 1));
324 wbuf[count++] = (mtp_wchar)(*ptr);
329 wbuf[count] = (mtp_wchar)'\0';
330 _util_utf16_to_utf8(buf, sizeof(buf), wbuf);
332 return MTP_ERROR_NONE;
335 mtp_uint16 _util_get_fmtcode(const mtp_char *extn)
337 static fmt_code_t fmt_code_table[] = {
338 {"ALB", MTP_FMT_ABSTRACT_AUDIO_ALBUM},
339 {"MP3", PTP_FMT_MP3},
340 {"WMA", MTP_FMT_WMA},
341 {"WMV", MTP_FMT_WMV},
342 {"JPG", PTP_FMT_IMG_EXIF},
343 {"GIF", PTP_FMT_IMG_GIF},
344 {"BMP", PTP_FMT_IMG_BMP},
345 {"PNG", PTP_FMT_IMG_PNG},
346 {"ASF", PTP_FMT_ASF},
347 {"WAV", PTP_FMT_WAVE},
348 {"AVI", PTP_FMT_AVI},
349 {"MPG", PTP_FMT_MPEG},
350 {"TXT", PTP_FMT_TEXT},
351 {"3GP", MTP_FMT_3GP},
352 {"ODF", MTP_FMT_3GP},
353 {"O4A", MTP_FMT_3GP},
354 {"O4V", MTP_FMT_3GP},
355 {"MP4", MTP_FMT_MP4},
356 {"FLAC", MTP_FMT_FLAC},
360 fmt_code_t *p = NULL;
363 while (p->fmt_code != PTP_FMT_UNDEF) {
364 if (!strncasecmp(extn, p->extn, strlen(p->extn)))
370 /* will return FormatCode or PTP_FORMATCODE_UNDEFINED
371 * if we hit end of list.
377 * This function gets the file extension.
378 * @param[in] fileName Specifies the file name.
379 * @param[out] file_extn holds the extension of the file.
380 * @return Returns TRUE on success and FALSE on failure.
382 mtp_bool _util_get_file_extn(const mtp_char *f_name, mtp_char *f_extn)
386 retv_if(NULL == f_name, FALSE);
387 retv_if(NULL == f_extn, FALSE);
389 ptr = strrchr(f_name, '.');
392 g_strlcpy(f_extn, ptr + 1, MTP_MAX_PATHNAME_SIZE);
399 mtp_bool _util_get_file_name(const mtp_char *fullpath, mtp_char *f_name)
403 retv_if(f_name == NULL, FALSE);
404 retv_if(fullpath == NULL, FALSE);
406 i = strlen(fullpath);
408 for (j = 0; i >= 0; i--) {
409 if (fullpath[i] == '/') {
410 g_strlcpy(f_name, &fullpath[i + 1], j);
415 g_strlcpy(f_name, fullpath, j);
420 * This function gives file name without extension.
421 * @param[in] fullpath pointer to absolute file path
422 * @param[out] f_name gets filled with filename w/o extension
423 * @return True or False based on success or failure
425 mtp_bool _util_get_file_name_wo_extn(const mtp_char *fullpath, mtp_char *f_name)
428 mtp_uint32 fname_len;
429 mtp_char *extn_ptr = NULL;
431 retv_if(f_name == NULL, FALSE);
432 retv_if(fullpath == NULL, FALSE);
434 fname_ptr = strrchr(fullpath, '/');
436 if (fname_ptr == NULL) {
437 ERR("Invalid File Name");
441 fname_ptr = fname_ptr + sizeof(char);
442 fname_len = strlen(fname_ptr);
443 extn_ptr = strrchr(fname_ptr, '.');
445 if (extn_ptr == NULL) {
446 g_strlcpy(f_name, fname_ptr, fname_len + 1);
450 g_strlcpy(f_name, fname_ptr, ((mtp_uint32)(extn_ptr - fname_ptr) + 1));
454 mtp_bool _util_is_path_len_valid(const mtp_char *path)
456 mtp_uint32 limit = 0;
457 mtp_uint32 mtp_path_len = 0;
458 mtp_uint32 root_path_len = 0;
460 static mtp_uint32 max_store_len = 0;
461 static mtp_bool is_initialized = FALSE;
462 static mtp_uint32 internal_store_len = 0;
463 static mtp_uint32 external_store_len = 0;
465 char ext_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
466 char inter_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
468 retv_if(path == NULL, FALSE);
470 _util_get_external_path(ext_path);
471 _util_get_internal_path(inter_path);
473 if (!is_initialized) {
474 is_initialized = TRUE;
475 internal_store_len = strlen(inter_path);
476 external_store_len = strlen(ext_path);
478 max_store_len = internal_store_len > external_store_len ?
479 internal_store_len : external_store_len;
481 DBG("max store len : [%u]\n", max_store_len);
484 if (!strncmp(path, inter_path, internal_store_len)) {
485 root_path_len = internal_store_len;
486 } else if (!strncmp(path, ext_path, external_store_len)) {
487 root_path_len = external_store_len;
489 ERR("Unknown store's path : %s\n", path);
493 /* Path len should be calculated except root path(eg. /opt/usr/media) */
494 mtp_path_len = strlen(path) - root_path_len;
496 /* MTP_MAX_PATHNAME_SIZE includes maximum length of root path */
497 limit = MTP_MAX_PATHNAME_SIZE - max_store_len;
499 if (mtp_path_len > limit) {
500 ERR("Too long path : [%u] > [%u]\n", mtp_path_len, limit);
507 mtp_bool _util_create_path(mtp_char *path, mtp_uint32 size, const mtp_char *dir,
508 const mtp_char *filename)
513 retv_if(dir == NULL, FALSE);
514 retv_if(path == NULL, FALSE);
515 retv_if(filename == NULL, FALSE);
517 len = strlen(filename);
518 if (len > MTP_MAX_FILENAME_SIZE) {
519 ERR("filename is too long :[%u] > [%u]\n", len,
520 MTP_MAX_FILENAME_SIZE);
524 ret = g_snprintf(path, size, "%s/%s", dir, filename);
526 ERR("path is truncated");
530 if (_util_is_path_len_valid(path) == FALSE) {
531 ERR("path length exceeds the limit");
539 * This function gets the parent path.
540 * @param[in] fullpath Pointer to a buffer containing full file path.
541 * @param[out] p_path Points the buffer to hold parent path.
544 void _util_get_parent_path(const mtp_char *fullpath, mtp_char *p_path)
546 mtp_char *ptr = NULL;
548 ret_if(NULL == p_path);
549 ret_if(NULL == fullpath);
551 ptr = strrchr(fullpath, '/');
553 ERR("Path does not have parent path");
557 g_strlcpy(p_path, fullpath, (mtp_uint32)(ptr - fullpath) + 1);
561 void _util_conv_wstr_to_guid(mtp_wchar *wstr, mtp_uint64 *guid)
567 mtp_int32 cpy_sz = 0;
569 ret_if(wstr == NULL);
570 ret_if(guid == NULL);
572 while (wstr[count] != 0)
575 memset(guid, 0, sizeof(temp));
576 skip_idx = sizeof(temp) / sizeof(mtp_wchar);
578 for (cur_idx = 0; cur_idx < count; cur_idx += skip_idx) {
580 memset(temp, 0, sizeof(temp));
581 cpy_sz = (count - cur_idx) * sizeof(mtp_wchar);
582 if (cpy_sz > sizeof(temp))
583 cpy_sz = sizeof(temp);
585 memcpy(temp, &(wstr[cur_idx]), cpy_sz);
593 mtp_bool _util_get_unique_dir_path(const mtp_char *exist_path,
594 mtp_char *new_path, mtp_uint32 new_path_buf_len)
596 mtp_uint32 num_bytes = 0;
597 mtp_uint32 max_value = 1;
598 mtp_uint32 count = 1;
600 mtp_char *buf = NULL;
601 mtp_uint32 len = strlen(exist_path);
603 retv_if(new_path == NULL, FALSE);
604 retv_if(exist_path == NULL, FALSE);
607 num_bytes = new_path_buf_len - len - 1;
608 if (num_bytes <= 0) {
609 ERR("No space to append data[%d]\n", num_bytes);
613 if (num_bytes >= MTP_BUF_SIZE_FOR_INT - 1) {
614 max_value = UINT_MAX;
616 while (count <= num_bytes) {
620 DBG("max_value[%u]\n", max_value);
623 buf = (mtp_char *)g_malloc(new_path_buf_len);
625 ERR("g_malloc Fail");
628 g_strlcpy(buf, exist_path, new_path_buf_len);
629 while (val < max_value) {
630 /* Including NUL and '_' */
631 g_snprintf(&buf[len], num_bytes + 2, "_%u", val++);
632 if (access(buf, F_OK) < 0)
637 ERR("Unable to generate Unique Dir Name");
641 g_strlcpy(new_path, buf, new_path_buf_len);
643 DBG_SECURE("Unique dir name[%s]\n", new_path);