5 * Routines for converting between UTF-8 and OSTA Compressed Unicode.
6 * Also handles filename mangling
9 * OSTA Compressed Unicode is explained in the OSTA UDF specification.
10 * http://www.osta.org/
11 * UTF-8 is explained in the IETF RFC XXXX.
12 * ftp://ftp.internic.net/rfc/rfcxxxx.txt
15 * E-mail regarding any portion of the Linux UDF file system should be
16 * directed to the development team's mailing list (run by majordomo):
17 * linux_udf@hpesjro.fc.hp.com
20 * This file is distributed under the terms of the GNU General Public
21 * License (GPL). Copies of the GPL can be obtained from:
22 * ftp://prep.ai.mit.edu/pub/gnu/GPL
23 * Each contributing author retains all rights to their own work.
28 #include <linux/kernel.h>
29 #include <linux/string.h> /* for memset */
30 #include <linux/nls.h>
31 #include <linux/udf_fs.h>
35 int udf_ustr_to_dchars(uint8_t *dest, const struct ustr *src, int strlen)
37 if ( (!dest) || (!src) || (!strlen) || (src->u_len > strlen) )
39 memcpy(dest+1, src->u_name, src->u_len);
40 dest[0] = src->u_cmpID;
41 return src->u_len + 1;
44 int udf_ustr_to_char(uint8_t *dest, const struct ustr *src, int strlen)
46 if ( (!dest) || (!src) || (!strlen) || (src->u_len >= strlen) )
48 memcpy(dest, src->u_name, src->u_len);
52 int udf_ustr_to_dstring(dstring *dest, const struct ustr *src, int dlength)
54 if ( udf_ustr_to_dchars(dest, src, dlength-1) )
56 dest[dlength-1] = src->u_len + 1;
63 int udf_dchars_to_ustr(struct ustr *dest, const uint8_t *src, int strlen)
65 if ( (!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN) )
67 memset(dest, 0, sizeof(struct ustr));
68 memcpy(dest->u_name, src+1, strlen-1);
69 dest->u_cmpID = src[0];
70 dest->u_len = strlen-1;
74 int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen)
76 if ( (!dest) || (!src) || (!strlen) || (strlen >= UDF_NAME_LEN) )
78 memset(dest, 0, sizeof(struct ustr));
79 memcpy(dest->u_name, src, strlen);
86 int udf_dstring_to_ustr(struct ustr *dest, const dstring *src, int dlength)
88 if ( dlength && udf_dchars_to_ustr(dest, src, src[dlength-1]) )
97 int udf_build_ustr(struct ustr *dest, dstring *ptr, int size)
101 if ( (!dest) || (!ptr) || (!size) )
104 memset(dest, 0, sizeof(struct ustr));
105 usesize= (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size;
106 dest->u_cmpID=ptr[0];
107 dest->u_len=ptr[size-1];
108 memcpy(dest->u_name, ptr+1, usesize-1);
113 * udf_build_ustr_exact
115 int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
117 if ( (!dest) || (!ptr) || (!exactsize) )
120 memset(dest, 0, sizeof(struct ustr));
121 dest->u_cmpID=ptr[0];
122 dest->u_len=exactsize-1;
123 memcpy(dest->u_name, ptr+1, exactsize-1);
131 * Convert OSTA Compressed Unicode to the UTF-8 equivalent.
134 * This routine is only called by udf_filldir().
137 * utf Pointer to UTF-8 output buffer.
138 * ocu Pointer to OSTA Compressed Unicode input buffer
139 * of size UDF_NAME_LEN bytes.
140 * both of type "struct ustr *"
143 * <return> Zero on success.
146 * November 12, 1997 - Andrew E. Mileski
147 * Written, tested, and released.
149 int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i)
153 uint8_t cmp_id, ocu_len;
158 ocu_len = ocu_i->u_len;
159 cmp_id = ocu_i->u_cmpID;
164 memset(utf_o, 0, sizeof(struct ustr));
170 if ((cmp_id != 8) && (cmp_id != 16))
172 printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name);
176 for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN-3)) ;)
179 /* Expand OSTA compressed Unicode to Unicode */
182 c = (c << 8) | ocu[i++];
184 /* Compress Unicode to UTF-8 */
186 utf_o->u_name[utf_o->u_len++] = (uint8_t)c;
189 utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xc0 | (c >> 6));
190 utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f));
194 utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xe0 | (c >> 12));
195 utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | ((c >> 6) & 0x3f));
196 utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f));
209 * Convert UTF-8 to the OSTA Compressed Unicode equivalent.
212 * This routine is only called by udf_lookup().
215 * ocu Pointer to OSTA Compressed Unicode output
216 * buffer of size UDF_NAME_LEN bytes.
217 * utf Pointer to UTF-8 input buffer.
218 * utf_len Length of UTF-8 input buffer in bytes.
221 * <return> Zero on success.
224 * November 12, 1997 - Andrew E. Mileski
225 * Written, tested, and released.
227 int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
229 unsigned c, i, max_val, utf_char;
233 memset(ocu, 0, sizeof(dstring) * length);
240 for (i = 0U; i < utf->u_len; i++)
242 c = (uint8_t)utf->u_name[i];
244 /* Complete a multi-byte UTF-8 character */
247 utf_char = (utf_char << 6) | (c & 0x3fU);
253 /* Check for a multi-byte UTF-8 character */
256 /* Start a multi-byte UTF-8 character */
257 if ((c & 0xe0U) == 0xc0U)
259 utf_char = c & 0x1fU;
262 else if ((c & 0xf0U) == 0xe0U)
264 utf_char = c & 0x0fU;
267 else if ((c & 0xf8U) == 0xf0U)
269 utf_char = c & 0x07U;
272 else if ((c & 0xfcU) == 0xf8U)
274 utf_char = c & 0x03U;
277 else if ((c & 0xfeU) == 0xfcU)
279 utf_char = c & 0x01U;
286 /* Single byte UTF-8 character (most common) */
290 /* Choose no compression if necessary */
291 if (utf_char > max_val)
293 if ( 0xffU == max_val )
296 ocu[0] = (uint8_t)0x10U;
302 if (max_val == 0xffffU)
304 ocu[++u_len] = (uint8_t)(utf_char >> 8);
306 ocu[++u_len] = (uint8_t)(utf_char & 0xffU);
313 printk(KERN_ERR "udf: bad UTF-8 character\n");
317 ocu[length - 1] = (uint8_t)u_len + 1;
321 int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, struct ustr *ocu_i)
325 uint8_t cmp_id, ocu_len;
330 ocu_len = ocu_i->u_len;
331 cmp_id = ocu_i->u_cmpID;
336 memset(utf_o, 0, sizeof(struct ustr));
342 if ((cmp_id != 8) && (cmp_id != 16))
344 printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name);
348 for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN-3)) ;)
350 /* Expand OSTA compressed Unicode to Unicode */
353 c = (c << 8) | ocu[i++];
355 utf_o->u_len += nls->uni2char(c, &utf_o->u_name[utf_o->u_len],
356 UDF_NAME_LEN - utf_o->u_len);
363 int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, int length)
365 unsigned len, i, max_val;
370 memset(ocu, 0, sizeof(dstring) * length);
377 for (i = 0U; i < uni->u_len; i++)
379 len = nls->char2uni(&uni->u_name[i], uni->u_len-i, &uni_char);
381 if (len == 2 && max_val == 0xff)
384 ocu[0] = (uint8_t)0x10U;
388 if (max_val == 0xffffU)
390 ocu[++u_len] = (uint8_t)(uni_char >> 8);
393 ocu[++u_len] = (uint8_t)(uni_char & 0xffU);
396 ocu[length - 1] = (uint8_t)u_len + 1;
400 int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname, int flen)
402 struct ustr filename, unifilename;
405 if (udf_build_ustr_exact(&unifilename, sname, flen))
410 if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8))
412 if (!udf_CS0toUTF8(&filename, &unifilename) )
414 udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
418 else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
420 if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, &filename, &unifilename) )
422 udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
429 if ((len = udf_translate_to_linux(dname, filename.u_name, filename.u_len,
430 unifilename.u_name, unifilename.u_len)))
437 #define ILLEGAL_CHAR_MARK '_'
442 int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen, uint8_t *fidName, int fidNameLen)
444 int index, newIndex = 0, needsCRC = 0;
445 int extIndex = 0, newExtIndex = 0, hasExt = 0;
446 unsigned short valueCRC;
448 const uint8_t hexChar[] = "0123456789ABCDEF";
450 if (udfName[0] == '.' && (udfLen == 1 ||
451 (udfLen == 2 && udfName[1] == '.')))
455 memcpy(newName, udfName, udfLen);
459 for (index = 0; index < udfLen; index++)
461 curr = udfName[index];
462 if (curr == '/' || curr == 0)
465 curr = ILLEGAL_CHAR_MARK;
466 while (index+1 < udfLen && (udfName[index+1] == '/' ||
467 udfName[index+1] == 0))
470 if (curr == EXT_MARK && (udfLen - index - 1) <= EXT_SIZE)
472 if (udfLen == index + 1)
478 newExtIndex = newIndex;
482 newName[newIndex++] = curr;
489 uint8_t ext[EXT_SIZE];
490 int localExtIndex = 0;
495 for(index = 0; index<EXT_SIZE && extIndex + index +1 < udfLen;
498 curr = udfName[extIndex + index + 1];
500 if (curr == '/' || curr == 0)
503 curr = ILLEGAL_CHAR_MARK;
504 while(extIndex + index + 2 < udfLen && (index + 1 < EXT_SIZE
505 && (udfName[extIndex + index + 2] == '/' ||
506 udfName[extIndex + index + 2] == 0)))
509 ext[localExtIndex++] = curr;
511 maxFilenameLen = 250 - localExtIndex;
512 if (newIndex > maxFilenameLen)
513 newIndex = maxFilenameLen;
515 newIndex = newExtIndex;
517 else if (newIndex > 250)
519 newName[newIndex++] = CRC_MARK;
520 valueCRC = udf_crc(fidName, fidNameLen, 0);
521 newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12];
522 newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8];
523 newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4];
524 newName[newIndex++] = hexChar[(valueCRC & 0x000f)];
528 newName[newIndex++] = EXT_MARK;
529 for (index = 0;index < localExtIndex ;index++ )
530 newName[newIndex++] = ext[index];