18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * unicode.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * PURPOSE 58c2ecf20Sopenharmony_ci * Routines for converting between UTF-8 and OSTA Compressed Unicode. 68c2ecf20Sopenharmony_ci * Also handles filename mangling 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * DESCRIPTION 98c2ecf20Sopenharmony_ci * OSTA Compressed Unicode is explained in the OSTA UDF specification. 108c2ecf20Sopenharmony_ci * http://www.osta.org/ 118c2ecf20Sopenharmony_ci * UTF-8 is explained in the IETF RFC XXXX. 128c2ecf20Sopenharmony_ci * ftp://ftp.internic.net/rfc/rfcxxxx.txt 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * COPYRIGHT 158c2ecf20Sopenharmony_ci * This file is distributed under the terms of the GNU General Public 168c2ecf20Sopenharmony_ci * License (GPL). Copies of the GPL can be obtained from: 178c2ecf20Sopenharmony_ci * ftp://prep.ai.mit.edu/pub/gnu/GPL 188c2ecf20Sopenharmony_ci * Each contributing author retains all rights to their own work. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "udfdecl.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/kernel.h> 248c2ecf20Sopenharmony_ci#include <linux/string.h> /* for memset */ 258c2ecf20Sopenharmony_ci#include <linux/nls.h> 268c2ecf20Sopenharmony_ci#include <linux/crc-itu-t.h> 278c2ecf20Sopenharmony_ci#include <linux/slab.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "udf_sb.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define PLANE_SIZE 0x10000 328c2ecf20Sopenharmony_ci#define UNICODE_MAX 0x10ffff 338c2ecf20Sopenharmony_ci#define SURROGATE_MASK 0xfffff800 348c2ecf20Sopenharmony_ci#define SURROGATE_PAIR 0x0000d800 358c2ecf20Sopenharmony_ci#define SURROGATE_LOW 0x00000400 368c2ecf20Sopenharmony_ci#define SURROGATE_CHAR_BITS 10 378c2ecf20Sopenharmony_ci#define SURROGATE_CHAR_MASK ((1 << SURROGATE_CHAR_BITS) - 1) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define ILLEGAL_CHAR_MARK '_' 408c2ecf20Sopenharmony_ci#define EXT_MARK '.' 418c2ecf20Sopenharmony_ci#define CRC_MARK '#' 428c2ecf20Sopenharmony_ci#define EXT_SIZE 5 438c2ecf20Sopenharmony_ci/* Number of chars we need to store generated CRC to make filename unique */ 448c2ecf20Sopenharmony_ci#define CRC_LEN 5 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic unicode_t get_utf16_char(const uint8_t *str_i, int str_i_max_len, 478c2ecf20Sopenharmony_ci int str_i_idx, int u_ch, unicode_t *ret) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci unicode_t c; 508c2ecf20Sopenharmony_ci int start_idx = str_i_idx; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* Expand OSTA compressed Unicode to Unicode */ 538c2ecf20Sopenharmony_ci c = str_i[str_i_idx++]; 548c2ecf20Sopenharmony_ci if (u_ch > 1) 558c2ecf20Sopenharmony_ci c = (c << 8) | str_i[str_i_idx++]; 568c2ecf20Sopenharmony_ci if ((c & SURROGATE_MASK) == SURROGATE_PAIR) { 578c2ecf20Sopenharmony_ci unicode_t next; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* Trailing surrogate char */ 608c2ecf20Sopenharmony_ci if (str_i_idx >= str_i_max_len) { 618c2ecf20Sopenharmony_ci c = UNICODE_MAX + 1; 628c2ecf20Sopenharmony_ci goto out; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* Low surrogate must follow the high one... */ 668c2ecf20Sopenharmony_ci if (c & SURROGATE_LOW) { 678c2ecf20Sopenharmony_ci c = UNICODE_MAX + 1; 688c2ecf20Sopenharmony_ci goto out; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci WARN_ON_ONCE(u_ch != 2); 728c2ecf20Sopenharmony_ci next = str_i[str_i_idx++] << 8; 738c2ecf20Sopenharmony_ci next |= str_i[str_i_idx++]; 748c2ecf20Sopenharmony_ci if ((next & SURROGATE_MASK) != SURROGATE_PAIR || 758c2ecf20Sopenharmony_ci !(next & SURROGATE_LOW)) { 768c2ecf20Sopenharmony_ci c = UNICODE_MAX + 1; 778c2ecf20Sopenharmony_ci goto out; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci c = PLANE_SIZE + 818c2ecf20Sopenharmony_ci ((c & SURROGATE_CHAR_MASK) << SURROGATE_CHAR_BITS) + 828c2ecf20Sopenharmony_ci (next & SURROGATE_CHAR_MASK); 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ciout: 858c2ecf20Sopenharmony_ci *ret = c; 868c2ecf20Sopenharmony_ci return str_i_idx - start_idx; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic int udf_name_conv_char(uint8_t *str_o, int str_o_max_len, 918c2ecf20Sopenharmony_ci int *str_o_idx, 928c2ecf20Sopenharmony_ci const uint8_t *str_i, int str_i_max_len, 938c2ecf20Sopenharmony_ci int *str_i_idx, 948c2ecf20Sopenharmony_ci int u_ch, int *needsCRC, 958c2ecf20Sopenharmony_ci int (*conv_f)(wchar_t, unsigned char *, int), 968c2ecf20Sopenharmony_ci int translate) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci unicode_t c; 998c2ecf20Sopenharmony_ci int illChar = 0; 1008c2ecf20Sopenharmony_ci int len, gotch = 0; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci while (!gotch && *str_i_idx < str_i_max_len) { 1038c2ecf20Sopenharmony_ci if (*str_o_idx >= str_o_max_len) { 1048c2ecf20Sopenharmony_ci *needsCRC = 1; 1058c2ecf20Sopenharmony_ci return gotch; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci len = get_utf16_char(str_i, str_i_max_len, *str_i_idx, u_ch, 1098c2ecf20Sopenharmony_ci &c); 1108c2ecf20Sopenharmony_ci /* These chars cannot be converted. Replace them. */ 1118c2ecf20Sopenharmony_ci if (c == 0 || c > UNICODE_MAX || (conv_f && c > MAX_WCHAR_T) || 1128c2ecf20Sopenharmony_ci (translate && c == '/')) { 1138c2ecf20Sopenharmony_ci illChar = 1; 1148c2ecf20Sopenharmony_ci if (!translate) 1158c2ecf20Sopenharmony_ci gotch = 1; 1168c2ecf20Sopenharmony_ci } else if (illChar) 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci else 1198c2ecf20Sopenharmony_ci gotch = 1; 1208c2ecf20Sopenharmony_ci *str_i_idx += len; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci if (illChar) { 1238c2ecf20Sopenharmony_ci *needsCRC = 1; 1248c2ecf20Sopenharmony_ci c = ILLEGAL_CHAR_MARK; 1258c2ecf20Sopenharmony_ci gotch = 1; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci if (gotch) { 1288c2ecf20Sopenharmony_ci if (conv_f) { 1298c2ecf20Sopenharmony_ci len = conv_f(c, &str_o[*str_o_idx], 1308c2ecf20Sopenharmony_ci str_o_max_len - *str_o_idx); 1318c2ecf20Sopenharmony_ci } else { 1328c2ecf20Sopenharmony_ci len = utf32_to_utf8(c, &str_o[*str_o_idx], 1338c2ecf20Sopenharmony_ci str_o_max_len - *str_o_idx); 1348c2ecf20Sopenharmony_ci if (len < 0) 1358c2ecf20Sopenharmony_ci len = -ENAMETOOLONG; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci /* Valid character? */ 1388c2ecf20Sopenharmony_ci if (len >= 0) 1398c2ecf20Sopenharmony_ci *str_o_idx += len; 1408c2ecf20Sopenharmony_ci else if (len == -ENAMETOOLONG) { 1418c2ecf20Sopenharmony_ci *needsCRC = 1; 1428c2ecf20Sopenharmony_ci gotch = 0; 1438c2ecf20Sopenharmony_ci } else { 1448c2ecf20Sopenharmony_ci str_o[(*str_o_idx)++] = ILLEGAL_CHAR_MARK; 1458c2ecf20Sopenharmony_ci *needsCRC = 1; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci return gotch; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic int udf_name_from_CS0(struct super_block *sb, 1528c2ecf20Sopenharmony_ci uint8_t *str_o, int str_max_len, 1538c2ecf20Sopenharmony_ci const uint8_t *ocu, int ocu_len, 1548c2ecf20Sopenharmony_ci int translate) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci uint32_t c; 1578c2ecf20Sopenharmony_ci uint8_t cmp_id; 1588c2ecf20Sopenharmony_ci int idx, len; 1598c2ecf20Sopenharmony_ci int u_ch; 1608c2ecf20Sopenharmony_ci int needsCRC = 0; 1618c2ecf20Sopenharmony_ci int ext_i_len, ext_max_len; 1628c2ecf20Sopenharmony_ci int str_o_len = 0; /* Length of resulting output */ 1638c2ecf20Sopenharmony_ci int ext_o_len = 0; /* Extension output length */ 1648c2ecf20Sopenharmony_ci int ext_crc_len = 0; /* Extension output length if used with CRC */ 1658c2ecf20Sopenharmony_ci int i_ext = -1; /* Extension position in input buffer */ 1668c2ecf20Sopenharmony_ci int o_crc = 0; /* Rightmost possible output pos for CRC+ext */ 1678c2ecf20Sopenharmony_ci unsigned short valueCRC; 1688c2ecf20Sopenharmony_ci uint8_t ext[EXT_SIZE * NLS_MAX_CHARSET_SIZE + 1]; 1698c2ecf20Sopenharmony_ci uint8_t crc[CRC_LEN]; 1708c2ecf20Sopenharmony_ci int (*conv_f)(wchar_t, unsigned char *, int); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (str_max_len <= 0) 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (ocu_len == 0) { 1768c2ecf20Sopenharmony_ci memset(str_o, 0, str_max_len); 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (UDF_SB(sb)->s_nls_map) 1818c2ecf20Sopenharmony_ci conv_f = UDF_SB(sb)->s_nls_map->uni2char; 1828c2ecf20Sopenharmony_ci else 1838c2ecf20Sopenharmony_ci conv_f = NULL; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci cmp_id = ocu[0]; 1868c2ecf20Sopenharmony_ci if (cmp_id != 8 && cmp_id != 16) { 1878c2ecf20Sopenharmony_ci memset(str_o, 0, str_max_len); 1888c2ecf20Sopenharmony_ci pr_err("unknown compression code (%u)\n", cmp_id); 1898c2ecf20Sopenharmony_ci return -EINVAL; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci u_ch = cmp_id >> 3; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci ocu++; 1948c2ecf20Sopenharmony_ci ocu_len--; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (ocu_len % u_ch) { 1978c2ecf20Sopenharmony_ci pr_err("incorrect filename length (%d)\n", ocu_len + 1); 1988c2ecf20Sopenharmony_ci return -EINVAL; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (translate) { 2028c2ecf20Sopenharmony_ci /* Look for extension */ 2038c2ecf20Sopenharmony_ci for (idx = ocu_len - u_ch, ext_i_len = 0; 2048c2ecf20Sopenharmony_ci (idx >= 0) && (ext_i_len < EXT_SIZE); 2058c2ecf20Sopenharmony_ci idx -= u_ch, ext_i_len++) { 2068c2ecf20Sopenharmony_ci c = ocu[idx]; 2078c2ecf20Sopenharmony_ci if (u_ch > 1) 2088c2ecf20Sopenharmony_ci c = (c << 8) | ocu[idx + 1]; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (c == EXT_MARK) { 2118c2ecf20Sopenharmony_ci if (ext_i_len) 2128c2ecf20Sopenharmony_ci i_ext = idx; 2138c2ecf20Sopenharmony_ci break; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci if (i_ext >= 0) { 2178c2ecf20Sopenharmony_ci /* Convert extension */ 2188c2ecf20Sopenharmony_ci ext_max_len = min_t(int, sizeof(ext), str_max_len); 2198c2ecf20Sopenharmony_ci ext[ext_o_len++] = EXT_MARK; 2208c2ecf20Sopenharmony_ci idx = i_ext + u_ch; 2218c2ecf20Sopenharmony_ci while (udf_name_conv_char(ext, ext_max_len, &ext_o_len, 2228c2ecf20Sopenharmony_ci ocu, ocu_len, &idx, 2238c2ecf20Sopenharmony_ci u_ch, &needsCRC, 2248c2ecf20Sopenharmony_ci conv_f, translate)) { 2258c2ecf20Sopenharmony_ci if ((ext_o_len + CRC_LEN) < str_max_len) 2268c2ecf20Sopenharmony_ci ext_crc_len = ext_o_len; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci idx = 0; 2328c2ecf20Sopenharmony_ci while (1) { 2338c2ecf20Sopenharmony_ci if (translate && (idx == i_ext)) { 2348c2ecf20Sopenharmony_ci if (str_o_len > (str_max_len - ext_o_len)) 2358c2ecf20Sopenharmony_ci needsCRC = 1; 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (!udf_name_conv_char(str_o, str_max_len, &str_o_len, 2408c2ecf20Sopenharmony_ci ocu, ocu_len, &idx, 2418c2ecf20Sopenharmony_ci u_ch, &needsCRC, conv_f, translate)) 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (translate && 2458c2ecf20Sopenharmony_ci (str_o_len <= (str_max_len - ext_o_len - CRC_LEN))) 2468c2ecf20Sopenharmony_ci o_crc = str_o_len; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (translate) { 2508c2ecf20Sopenharmony_ci if (str_o_len > 0 && str_o_len <= 2 && str_o[0] == '.' && 2518c2ecf20Sopenharmony_ci (str_o_len == 1 || str_o[1] == '.')) 2528c2ecf20Sopenharmony_ci needsCRC = 1; 2538c2ecf20Sopenharmony_ci if (needsCRC) { 2548c2ecf20Sopenharmony_ci str_o_len = o_crc; 2558c2ecf20Sopenharmony_ci valueCRC = crc_itu_t(0, ocu, ocu_len); 2568c2ecf20Sopenharmony_ci crc[0] = CRC_MARK; 2578c2ecf20Sopenharmony_ci crc[1] = hex_asc_upper_hi(valueCRC >> 8); 2588c2ecf20Sopenharmony_ci crc[2] = hex_asc_upper_lo(valueCRC >> 8); 2598c2ecf20Sopenharmony_ci crc[3] = hex_asc_upper_hi(valueCRC); 2608c2ecf20Sopenharmony_ci crc[4] = hex_asc_upper_lo(valueCRC); 2618c2ecf20Sopenharmony_ci len = min_t(int, CRC_LEN, str_max_len - str_o_len); 2628c2ecf20Sopenharmony_ci memcpy(&str_o[str_o_len], crc, len); 2638c2ecf20Sopenharmony_ci str_o_len += len; 2648c2ecf20Sopenharmony_ci ext_o_len = ext_crc_len; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci if (ext_o_len > 0) { 2678c2ecf20Sopenharmony_ci memcpy(&str_o[str_o_len], ext, ext_o_len); 2688c2ecf20Sopenharmony_ci str_o_len += ext_o_len; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return str_o_len; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic int udf_name_to_CS0(struct super_block *sb, 2768c2ecf20Sopenharmony_ci uint8_t *ocu, int ocu_max_len, 2778c2ecf20Sopenharmony_ci const uint8_t *str_i, int str_len) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci int i, len; 2808c2ecf20Sopenharmony_ci unsigned int max_val; 2818c2ecf20Sopenharmony_ci int u_len, u_ch; 2828c2ecf20Sopenharmony_ci unicode_t uni_char; 2838c2ecf20Sopenharmony_ci int (*conv_f)(const unsigned char *, int, wchar_t *); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (ocu_max_len <= 0) 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (UDF_SB(sb)->s_nls_map) 2898c2ecf20Sopenharmony_ci conv_f = UDF_SB(sb)->s_nls_map->char2uni; 2908c2ecf20Sopenharmony_ci else 2918c2ecf20Sopenharmony_ci conv_f = NULL; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci memset(ocu, 0, ocu_max_len); 2948c2ecf20Sopenharmony_ci ocu[0] = 8; 2958c2ecf20Sopenharmony_ci max_val = 0xff; 2968c2ecf20Sopenharmony_ci u_ch = 1; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_citry_again: 2998c2ecf20Sopenharmony_ci u_len = 1; 3008c2ecf20Sopenharmony_ci for (i = 0; i < str_len; i += len) { 3018c2ecf20Sopenharmony_ci /* Name didn't fit? */ 3028c2ecf20Sopenharmony_ci if (u_len + u_ch > ocu_max_len) 3038c2ecf20Sopenharmony_ci return 0; 3048c2ecf20Sopenharmony_ci if (conv_f) { 3058c2ecf20Sopenharmony_ci wchar_t wchar; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci len = conv_f(&str_i[i], str_len - i, &wchar); 3088c2ecf20Sopenharmony_ci if (len > 0) 3098c2ecf20Sopenharmony_ci uni_char = wchar; 3108c2ecf20Sopenharmony_ci } else { 3118c2ecf20Sopenharmony_ci len = utf8_to_utf32(&str_i[i], str_len - i, 3128c2ecf20Sopenharmony_ci &uni_char); 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci /* Invalid character, deal with it */ 3158c2ecf20Sopenharmony_ci if (len <= 0 || uni_char > UNICODE_MAX) { 3168c2ecf20Sopenharmony_ci len = 1; 3178c2ecf20Sopenharmony_ci uni_char = '?'; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (uni_char > max_val) { 3218c2ecf20Sopenharmony_ci unicode_t c; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (max_val == 0xff) { 3248c2ecf20Sopenharmony_ci max_val = 0xffff; 3258c2ecf20Sopenharmony_ci ocu[0] = 0x10; 3268c2ecf20Sopenharmony_ci u_ch = 2; 3278c2ecf20Sopenharmony_ci goto try_again; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci /* 3308c2ecf20Sopenharmony_ci * Use UTF-16 encoding for chars outside we 3318c2ecf20Sopenharmony_ci * cannot encode directly. 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_ci if (u_len + 2 * u_ch > ocu_max_len) 3348c2ecf20Sopenharmony_ci return 0; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci uni_char -= PLANE_SIZE; 3378c2ecf20Sopenharmony_ci c = SURROGATE_PAIR | 3388c2ecf20Sopenharmony_ci ((uni_char >> SURROGATE_CHAR_BITS) & 3398c2ecf20Sopenharmony_ci SURROGATE_CHAR_MASK); 3408c2ecf20Sopenharmony_ci ocu[u_len++] = (uint8_t)(c >> 8); 3418c2ecf20Sopenharmony_ci ocu[u_len++] = (uint8_t)(c & 0xff); 3428c2ecf20Sopenharmony_ci uni_char = SURROGATE_PAIR | SURROGATE_LOW | 3438c2ecf20Sopenharmony_ci (uni_char & SURROGATE_CHAR_MASK); 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (max_val == 0xffff) 3478c2ecf20Sopenharmony_ci ocu[u_len++] = (uint8_t)(uni_char >> 8); 3488c2ecf20Sopenharmony_ci ocu[u_len++] = (uint8_t)(uni_char & 0xff); 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return u_len; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci/* 3558c2ecf20Sopenharmony_ci * Convert CS0 dstring to output charset. Warning: This function may truncate 3568c2ecf20Sopenharmony_ci * input string if it is too long as it is used for informational strings only 3578c2ecf20Sopenharmony_ci * and it is better to truncate the string than to refuse mounting a media. 3588c2ecf20Sopenharmony_ci */ 3598c2ecf20Sopenharmony_ciint udf_dstrCS0toChar(struct super_block *sb, uint8_t *utf_o, int o_len, 3608c2ecf20Sopenharmony_ci const uint8_t *ocu_i, int i_len) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci int s_len = 0; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (i_len > 0) { 3658c2ecf20Sopenharmony_ci s_len = ocu_i[i_len - 1]; 3668c2ecf20Sopenharmony_ci if (s_len >= i_len) { 3678c2ecf20Sopenharmony_ci pr_warn("incorrect dstring lengths (%d/%d)," 3688c2ecf20Sopenharmony_ci " truncating\n", s_len, i_len); 3698c2ecf20Sopenharmony_ci s_len = i_len - 1; 3708c2ecf20Sopenharmony_ci /* 2-byte encoding? Need to round properly... */ 3718c2ecf20Sopenharmony_ci if (ocu_i[0] == 16) 3728c2ecf20Sopenharmony_ci s_len -= (s_len - 1) & 2; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci return udf_name_from_CS0(sb, utf_o, o_len, ocu_i, s_len, 0); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ciint udf_get_filename(struct super_block *sb, const uint8_t *sname, int slen, 3808c2ecf20Sopenharmony_ci uint8_t *dname, int dlen) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci int ret; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (!slen) 3858c2ecf20Sopenharmony_ci return -EIO; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (dlen <= 0) 3888c2ecf20Sopenharmony_ci return 0; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci ret = udf_name_from_CS0(sb, dname, dlen, sname, slen, 1); 3918c2ecf20Sopenharmony_ci /* Zero length filename isn't valid... */ 3928c2ecf20Sopenharmony_ci if (ret == 0) 3938c2ecf20Sopenharmony_ci ret = -EINVAL; 3948c2ecf20Sopenharmony_ci return ret; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ciint udf_put_filename(struct super_block *sb, const uint8_t *sname, int slen, 3988c2ecf20Sopenharmony_ci uint8_t *dname, int dlen) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci return udf_name_to_CS0(sb, dname, dlen, sname, slen); 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 403