1 2 3#include "udfdecl.h" 4 5#include <linux/kernel.h> 6#include <linux/string.h> /* for memset */ 7#include <linux/nls.h> 8#include <linux/udf_fs.h> 9 10#include "udf_sb.h" 11 12static int udf_translate_to_linux(uint8_t *, uint8_t *, int, uint8_t *, int); 13 14static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen) 15{ 16 if ( (!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN-2) ) 17 return 0; 18 memset(dest, 0, sizeof(struct ustr)); 19 memcpy(dest->u_name, src, strlen); 20 dest->u_cmpID = 0x08; 21 dest->u_len = strlen; 22 return strlen; 23} 24 25/* 26 * udf_build_ustr 27 */ 28int udf_build_ustr(struct ustr *dest, dstring *ptr, int size) 29{ 30 int usesize; 31 32 if ( (!dest) || (!ptr) || (!size) ) 33 return -1; 34 35 memset(dest, 0, sizeof(struct ustr)); 36 usesize= (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size; 37 dest->u_cmpID=ptr[0]; 38 dest->u_len=ptr[size-1]; 39 memcpy(dest->u_name, ptr+1, usesize-1); 40 return 0; 41} 42 43/* 44 * udf_build_ustr_exact 45 */ 46static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) 47{ 48 if ( (!dest) || (!ptr) || (!exactsize) ) 49 return -1; 50 51 memset(dest, 0, sizeof(struct ustr)); 52 dest->u_cmpID=ptr[0]; 53 dest->u_len=exactsize-1; 54 memcpy(dest->u_name, ptr+1, exactsize-1); 55 return 0; 56} 57 58/* 59 * udf_ocu_to_utf8 60 * 61 * PURPOSE 62 * Convert OSTA Compressed Unicode to the UTF-8 equivalent. 63 * 64 * DESCRIPTION 65 * This routine is only called by udf_filldir(). 66 * 67 * PRE-CONDITIONS 68 * utf Pointer to UTF-8 output buffer. 69 * ocu Pointer to OSTA Compressed Unicode input buffer 70 * of size UDF_NAME_LEN bytes. 71 * both of type "struct ustr *" 72 * 73 * POST-CONDITIONS 74 * <return> Zero on success. 75 * 76 * HISTORY 77 * November 12, 1997 - Andrew E. Mileski 78 * Written, tested, and released. 79 */ 80int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i) 81{ 82 uint8_t *ocu; 83 uint32_t c; 84 uint8_t cmp_id, ocu_len; 85 int i; 86 87 ocu = ocu_i->u_name; 88 89 ocu_len = ocu_i->u_len; 90 cmp_id = ocu_i->u_cmpID; 91 utf_o->u_len = 0; 92 93 if (ocu_len == 0) 94 { 95 memset(utf_o, 0, sizeof(struct ustr)); 96 utf_o->u_cmpID = 0; 97 utf_o->u_len = 0; 98 return 0; 99 } 100 101 if ((cmp_id != 8) && (cmp_id != 16)) 102 { 103 printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name); 104 return 0; 105 } 106 107 for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN-3)) ;) 108 { 109 110 /* Expand OSTA compressed Unicode to Unicode */ 111 c = ocu[i++]; 112 if (cmp_id == 16) 113 c = (c << 8) | ocu[i++]; 114 115 /* Compress Unicode to UTF-8 */ 116 if (c < 0x80U) 117 utf_o->u_name[utf_o->u_len++] = (uint8_t)c; 118 else if (c < 0x800U) 119 { 120 utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xc0 | (c >> 6)); 121 utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f)); 122 } 123 else 124 { 125 utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xe0 | (c >> 12)); 126 utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | ((c >> 6) & 0x3f)); 127 utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f)); 128 } 129 } 130 utf_o->u_cmpID=8; 131 132 return utf_o->u_len; 133} 134 135/* 136 * 137 * udf_utf8_to_ocu 138 * 139 * PURPOSE 140 * Convert UTF-8 to the OSTA Compressed Unicode equivalent. 141 * 142 * DESCRIPTION 143 * This routine is only called by udf_lookup(). 144 * 145 * PRE-CONDITIONS 146 * ocu Pointer to OSTA Compressed Unicode output 147 * buffer of size UDF_NAME_LEN bytes. 148 * utf Pointer to UTF-8 input buffer. 149 * utf_len Length of UTF-8 input buffer in bytes. 150 * 151 * POST-CONDITIONS 152 * <return> Zero on success. 153 * 154 * HISTORY 155 * November 12, 1997 - Andrew E. Mileski 156 * Written, tested, and released. 157 */ 158static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) 159{ 160 unsigned c, i, max_val, utf_char; 161 int utf_cnt, u_len; 162 163 memset(ocu, 0, sizeof(dstring) * length); 164 ocu[0] = 8; 165 max_val = 0xffU; 166 167try_again: 168 u_len = 0U; 169 utf_char = 0U; 170 utf_cnt = 0U; 171 for (i = 0U; i < utf->u_len; i++) 172 { 173 c = (uint8_t)utf->u_name[i]; 174 175 /* Complete a multi-byte UTF-8 character */ 176 if (utf_cnt) 177 { 178 utf_char = (utf_char << 6) | (c & 0x3fU); 179 if (--utf_cnt) 180 continue; 181 } 182 else 183 { 184 /* Check for a multi-byte UTF-8 character */ 185 if (c & 0x80U) 186 { 187 /* Start a multi-byte UTF-8 character */ 188 if ((c & 0xe0U) == 0xc0U) 189 { 190 utf_char = c & 0x1fU; 191 utf_cnt = 1; 192 } 193 else if ((c & 0xf0U) == 0xe0U) 194 { 195 utf_char = c & 0x0fU; 196 utf_cnt = 2; 197 } 198 else if ((c & 0xf8U) == 0xf0U) 199 { 200 utf_char = c & 0x07U; 201 utf_cnt = 3; 202 } 203 else if ((c & 0xfcU) == 0xf8U) 204 { 205 utf_char = c & 0x03U; 206 utf_cnt = 4; 207 } 208 else if ((c & 0xfeU) == 0xfcU) 209 { 210 utf_char = c & 0x01U; 211 utf_cnt = 5; 212 } 213 else 214 goto error_out; 215 continue; 216 } else 217 /* Single byte UTF-8 character (most common) */ 218 utf_char = c; 219 } 220 221 /* Choose no compression if necessary */ 222 if (utf_char > max_val) 223 { 224 if ( 0xffU == max_val ) 225 { 226 max_val = 0xffffU; 227 ocu[0] = (uint8_t)0x10U; 228 goto try_again; 229 } 230 goto error_out; 231 } 232 233 if (max_val == 0xffffU) 234 { 235 ocu[++u_len] = (uint8_t)(utf_char >> 8); 236 } 237 ocu[++u_len] = (uint8_t)(utf_char & 0xffU); 238 } 239 240 241 if (utf_cnt) 242 { 243error_out: 244 ocu[++u_len] = '?'; 245 printk(KERN_DEBUG "udf: bad UTF-8 character\n"); 246 } 247 248 ocu[length - 1] = (uint8_t)u_len + 1; 249 return u_len + 1; 250} 251 252static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, struct ustr *ocu_i) 253{ 254 uint8_t *ocu; 255 uint32_t c; 256 uint8_t cmp_id, ocu_len; 257 int i; 258 259 ocu = ocu_i->u_name; 260 261 ocu_len = ocu_i->u_len; 262 cmp_id = ocu_i->u_cmpID; 263 utf_o->u_len = 0; 264 265 if (ocu_len == 0) 266 { 267 memset(utf_o, 0, sizeof(struct ustr)); 268 utf_o->u_cmpID = 0; 269 utf_o->u_len = 0; 270 return 0; 271 } 272 273 if ((cmp_id != 8) && (cmp_id != 16)) 274 { 275 printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name); 276 return 0; 277 } 278 279 for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN-3)) ;) 280 { 281 /* Expand OSTA compressed Unicode to Unicode */ 282 c = ocu[i++]; 283 if (cmp_id == 16) 284 c = (c << 8) | ocu[i++]; 285 286 utf_o->u_len += nls->uni2char(c, &utf_o->u_name[utf_o->u_len], 287 UDF_NAME_LEN - utf_o->u_len); 288 } 289 utf_o->u_cmpID=8; 290 291 return utf_o->u_len; 292} 293 294static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, int length) 295{ 296 unsigned len, i, max_val; 297 uint16_t uni_char; 298 int u_len; 299 300 memset(ocu, 0, sizeof(dstring) * length); 301 ocu[0] = 8; 302 max_val = 0xffU; 303 304try_again: 305 u_len = 0U; 306 for (i = 0U; i < uni->u_len; i++) 307 { 308 len = nls->char2uni(&uni->u_name[i], uni->u_len-i, &uni_char); 309 if (len <= 0) 310 continue; 311 312 if (uni_char > max_val) 313 { 314 max_val = 0xffffU; 315 ocu[0] = (uint8_t)0x10U; 316 goto try_again; 317 } 318 319 if (max_val == 0xffffU) 320 ocu[++u_len] = (uint8_t)(uni_char >> 8); 321 ocu[++u_len] = (uint8_t)(uni_char & 0xffU); 322 i += len - 1; 323 } 324 325 ocu[length - 1] = (uint8_t)u_len + 1; 326 return u_len + 1; 327} 328 329int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname, int flen) 330{ 331 struct ustr filename, unifilename; 332 int len; 333 334 if (udf_build_ustr_exact(&unifilename, sname, flen)) 335 { 336 return 0; 337 } 338 339 if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) 340 { 341 if (!udf_CS0toUTF8(&filename, &unifilename) ) 342 { 343 udf_debug("Failed in udf_get_filename: sname = %s\n", sname); 344 return 0; 345 } 346 } 347 else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) 348 { 349 if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, &filename, &unifilename) ) 350 { 351 udf_debug("Failed in udf_get_filename: sname = %s\n", sname); 352 return 0; 353 } 354 } 355 else 356 return 0; 357 358 if ((len = udf_translate_to_linux(dname, filename.u_name, filename.u_len, 359 unifilename.u_name, unifilename.u_len))) 360 { 361 return len; 362 } 363 return 0; 364} 365 366int udf_put_filename(struct super_block *sb, const uint8_t *sname, uint8_t *dname, int flen) 367{ 368 struct ustr unifilename; 369 int namelen; 370 371 if ( !(udf_char_to_ustr(&unifilename, sname, flen)) ) 372 { 373 return 0; 374 } 375 376 if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) 377 { 378 if ( !(namelen = udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN)) ) 379 { 380 return 0; 381 } 382 } 383 else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) 384 { 385 if ( !(namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname, &unifilename, UDF_NAME_LEN)) ) 386 { 387 return 0; 388 } 389 } 390 else 391 return 0; 392 393 return namelen; 394} 395 396#define ILLEGAL_CHAR_MARK '_' 397#define EXT_MARK '.' 398#define CRC_MARK '#' 399#define EXT_SIZE 5 400 401static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen, uint8_t *fidName, int fidNameLen) 402{ 403 int index, newIndex = 0, needsCRC = 0; 404 int extIndex = 0, newExtIndex = 0, hasExt = 0; 405 unsigned short valueCRC; 406 uint8_t curr; 407 const uint8_t hexChar[] = "0123456789ABCDEF"; 408 409 if (udfName[0] == '.' && (udfLen == 1 || 410 (udfLen == 2 && udfName[1] == '.'))) 411 { 412 needsCRC = 1; 413 newIndex = udfLen; 414 memcpy(newName, udfName, udfLen); 415 } 416 else 417 { 418 for (index = 0; index < udfLen; index++) 419 { 420 curr = udfName[index]; 421 if (curr == '/' || curr == 0) 422 { 423 needsCRC = 1; 424 curr = ILLEGAL_CHAR_MARK; 425 while (index+1 < udfLen && (udfName[index+1] == '/' || 426 udfName[index+1] == 0)) 427 index++; 428 } 429 if (curr == EXT_MARK && (udfLen - index - 1) <= EXT_SIZE) 430 { 431 if (udfLen == index + 1) 432 hasExt = 0; 433 else 434 { 435 hasExt = 1; 436 extIndex = index; 437 newExtIndex = newIndex; 438 } 439 } 440 if (newIndex < 256) 441 newName[newIndex++] = curr; 442 else 443 needsCRC = 1; 444 } 445 } 446 if (needsCRC) 447 { 448 uint8_t ext[EXT_SIZE]; 449 int localExtIndex = 0; 450 451 if (hasExt) 452 { 453 int maxFilenameLen; 454 for(index = 0; index<EXT_SIZE && extIndex + index +1 < udfLen; 455 index++ ) 456 { 457 curr = udfName[extIndex + index + 1]; 458 459 if (curr == '/' || curr == 0) 460 { 461 needsCRC = 1; 462 curr = ILLEGAL_CHAR_MARK; 463 while(extIndex + index + 2 < udfLen && (index + 1 < EXT_SIZE 464 && (udfName[extIndex + index + 2] == '/' || 465 udfName[extIndex + index + 2] == 0))) 466 index++; 467 } 468 ext[localExtIndex++] = curr; 469 } 470 maxFilenameLen = 250 - localExtIndex; 471 if (newIndex > maxFilenameLen) 472 newIndex = maxFilenameLen; 473 else 474 newIndex = newExtIndex; 475 } 476 else if (newIndex > 250) 477 newIndex = 250; 478 newName[newIndex++] = CRC_MARK; 479 valueCRC = udf_crc(fidName, fidNameLen, 0); 480 newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12]; 481 newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8]; 482 newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4]; 483 newName[newIndex++] = hexChar[(valueCRC & 0x000f)]; 484 485 if (hasExt) 486 { 487 newName[newIndex++] = EXT_MARK; 488 for (index = 0;index < localExtIndex ;index++ ) 489 newName[newIndex++] = ext[index]; 490 } 491 } 492 return newIndex; 493} 494