Blame view

fs/udf/unicode.c 11.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   * unicode.c
   *
   * PURPOSE
   *	Routines for converting between UTF-8 and OSTA Compressed Unicode.
   *      Also handles filename mangling
   *
   * DESCRIPTION
   *	OSTA Compressed Unicode is explained in the OSTA UDF specification.
   *		http://www.osta.org/
   *	UTF-8 is explained in the IETF RFC XXXX.
   *		ftp://ftp.internic.net/rfc/rfcxxxx.txt
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
20
21
22
23
24
25
   * COPYRIGHT
   *	This file is distributed under the terms of the GNU General Public
   *	License (GPL). Copies of the GPL can be obtained from:
   *		ftp://prep.ai.mit.edu/pub/gnu/GPL
   *	Each contributing author retains all rights to their own work.
   */
  
  #include "udfdecl.h"
  
  #include <linux/kernel.h>
  #include <linux/string.h>	/* for memset */
  #include <linux/nls.h>
f845fced9   Bob Copeland   udf: use crc_itu_...
26
  #include <linux/crc-itu-t.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
27
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
  
  #include "udf_sb.h"
  
  static int udf_translate_to_linux(uint8_t *, uint8_t *, int, uint8_t *, int);
28de7948a   Cyrill Gorcunov   UDF: coding style...
32
  static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  {
cb00ea352   Cyrill Gorcunov   UDF: coding style...
34
  	if ((!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN - 2))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  		return 0;
28de7948a   Cyrill Gorcunov   UDF: coding style...
36

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
40
  	memset(dest, 0, sizeof(struct ustr));
  	memcpy(dest->u_name, src, strlen);
  	dest->u_cmpID = 0x08;
  	dest->u_len = strlen;
28de7948a   Cyrill Gorcunov   UDF: coding style...
41

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
  	return strlen;
  }
  
  /*
   * udf_build_ustr
   */
28de7948a   Cyrill Gorcunov   UDF: coding style...
48
  int udf_build_ustr(struct ustr *dest, dstring *ptr, int size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
  {
  	int usesize;
6305a0a9d   Marcin Slusarz   udf: fix udf_buil...
51
  	if (!dest || !ptr || !size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  		return -1;
6305a0a9d   Marcin Slusarz   udf: fix udf_buil...
53
  	BUG_ON(size < 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

6305a0a9d   Marcin Slusarz   udf: fix udf_buil...
55
56
  	usesize = min_t(size_t, ptr[size - 1], sizeof(dest->u_name));
  	usesize = min(usesize, size - 2);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
57
  	dest->u_cmpID = ptr[0];
6305a0a9d   Marcin Slusarz   udf: fix udf_buil...
58
59
60
  	dest->u_len = usesize;
  	memcpy(dest->u_name, ptr + 1, usesize);
  	memset(dest->u_name + usesize, 0, sizeof(dest->u_name) - usesize);
28de7948a   Cyrill Gorcunov   UDF: coding style...
61

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
67
  	return 0;
  }
  
  /*
   * udf_build_ustr_exact
   */
28de7948a   Cyrill Gorcunov   UDF: coding style...
68
  static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  {
cb00ea352   Cyrill Gorcunov   UDF: coding style...
70
  	if ((!dest) || (!ptr) || (!exactsize))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
  		return -1;
  
  	memset(dest, 0, sizeof(struct ustr));
cb00ea352   Cyrill Gorcunov   UDF: coding style...
74
75
76
  	dest->u_cmpID = ptr[0];
  	dest->u_len = exactsize - 1;
  	memcpy(dest->u_name, ptr + 1, exactsize - 1);
28de7948a   Cyrill Gorcunov   UDF: coding style...
77

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
80
81
82
83
84
85
86
  	return 0;
  }
  
  /*
   * udf_ocu_to_utf8
   *
   * PURPOSE
   *	Convert OSTA Compressed Unicode to the UTF-8 equivalent.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
90
91
92
93
94
95
96
97
98
99
   * PRE-CONDITIONS
   *	utf			Pointer to UTF-8 output buffer.
   *	ocu			Pointer to OSTA Compressed Unicode input buffer
   *				of size UDF_NAME_LEN bytes.
   * 				both of type "struct ustr *"
   *
   * POST-CONDITIONS
   *	<return>		Zero on success.
   *
   * HISTORY
   *	November 12, 1997 - Andrew E. Mileski
   *	Written, tested, and released.
   */
79cfe0ff5   marcin.slusarz@gmail.com   udf: udf_CS0toUTF...
100
  int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
  {
79cfe0ff5   marcin.slusarz@gmail.com   udf: udf_CS0toUTF...
102
  	const uint8_t *ocu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
  	uint8_t cmp_id, ocu_len;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  	ocu_len = ocu_i->u_len;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
106
  	if (ocu_len == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
  		memset(utf_o, 0, sizeof(struct ustr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
  		return 0;
  	}
79cfe0ff5   marcin.slusarz@gmail.com   udf: udf_CS0toUTF...
110
111
112
  	cmp_id = ocu_i->u_cmpID;
  	if (cmp_id != 8 && cmp_id != 16) {
  		memset(utf_o, 0, sizeof(struct ustr));
78ace70c4   Joe Perches   udf: Convert prin...
113
114
  		pr_err("unknown compression code (%d) stri=%s
  ",
cb00ea352   Cyrill Gorcunov   UDF: coding style...
115
  		       cmp_id, ocu_i->u_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
  		return 0;
  	}
79cfe0ff5   marcin.slusarz@gmail.com   udf: udf_CS0toUTF...
118
119
  	ocu = ocu_i->u_name;
  	utf_o->u_len = 0;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
120
  	for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
  
  		/* Expand OSTA compressed Unicode to Unicode */
79cfe0ff5   marcin.slusarz@gmail.com   udf: udf_CS0toUTF...
123
  		uint32_t c = ocu[i++];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
127
  		if (cmp_id == 16)
  			c = (c << 8) | ocu[i++];
  
  		/* Compress Unicode to UTF-8 */
79cfe0ff5   marcin.slusarz@gmail.com   udf: udf_CS0toUTF...
128
  		if (c < 0x80U)
28de7948a   Cyrill Gorcunov   UDF: coding style...
129
  			utf_o->u_name[utf_o->u_len++] = (uint8_t)c;
79cfe0ff5   marcin.slusarz@gmail.com   udf: udf_CS0toUTF...
130
  		else if (c < 0x800U) {
4b11111ab   Marcin Slusarz   udf: fix coding s...
131
132
133
134
  			utf_o->u_name[utf_o->u_len++] =
  						(uint8_t)(0xc0 | (c >> 6));
  			utf_o->u_name[utf_o->u_len++] =
  						(uint8_t)(0x80 | (c & 0x3f));
cb00ea352   Cyrill Gorcunov   UDF: coding style...
135
  		} else {
4b11111ab   Marcin Slusarz   udf: fix coding s...
136
137
138
139
140
141
142
  			utf_o->u_name[utf_o->u_len++] =
  						(uint8_t)(0xe0 | (c >> 12));
  			utf_o->u_name[utf_o->u_len++] =
  						(uint8_t)(0x80 |
  							  ((c >> 6) & 0x3f));
  			utf_o->u_name[utf_o->u_len++] =
  						(uint8_t)(0x80 | (c & 0x3f));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
  		}
  	}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
145
  	utf_o->u_cmpID = 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  
  	return utf_o->u_len;
  }
  
  /*
   *
   * udf_utf8_to_ocu
   *
   * PURPOSE
   *	Convert UTF-8 to the OSTA Compressed Unicode equivalent.
   *
   * DESCRIPTION
   *	This routine is only called by udf_lookup().
   *
   * PRE-CONDITIONS
   *	ocu			Pointer to OSTA Compressed Unicode output
   *				buffer of size UDF_NAME_LEN bytes.
   *	utf			Pointer to UTF-8 input buffer.
   *	utf_len			Length of UTF-8 input buffer in bytes.
   *
   * POST-CONDITIONS
   *	<return>		Zero on success.
   *
   * HISTORY
   *	November 12, 1997 - Andrew E. Mileski
   *	Written, tested, and released.
   */
28de7948a   Cyrill Gorcunov   UDF: coding style...
173
  static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
177
178
179
180
  {
  	unsigned c, i, max_val, utf_char;
  	int utf_cnt, u_len;
  
  	memset(ocu, 0, sizeof(dstring) * length);
  	ocu[0] = 8;
  	max_val = 0xffU;
28de7948a   Cyrill Gorcunov   UDF: coding style...
181
  try_again:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
184
  	u_len = 0U;
  	utf_char = 0U;
  	utf_cnt = 0U;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
185
  	for (i = 0U; i < utf->u_len; i++) {
28de7948a   Cyrill Gorcunov   UDF: coding style...
186
  		c = (uint8_t)utf->u_name[i];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
188
  
  		/* Complete a multi-byte UTF-8 character */
cb00ea352   Cyrill Gorcunov   UDF: coding style...
189
  		if (utf_cnt) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
  			utf_char = (utf_char << 6) | (c & 0x3fU);
  			if (--utf_cnt)
  				continue;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
193
  		} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
  			/* Check for a multi-byte UTF-8 character */
cb00ea352   Cyrill Gorcunov   UDF: coding style...
195
  			if (c & 0x80U) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
  				/* Start a multi-byte UTF-8 character */
cb00ea352   Cyrill Gorcunov   UDF: coding style...
197
  				if ((c & 0xe0U) == 0xc0U) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
  					utf_char = c & 0x1fU;
  					utf_cnt = 1;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
200
  				} else if ((c & 0xf0U) == 0xe0U) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
  					utf_char = c & 0x0fU;
  					utf_cnt = 2;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
203
  				} else if ((c & 0xf8U) == 0xf0U) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
  					utf_char = c & 0x07U;
  					utf_cnt = 3;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
206
  				} else if ((c & 0xfcU) == 0xf8U) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
  					utf_char = c & 0x03U;
  					utf_cnt = 4;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
209
  				} else if ((c & 0xfeU) == 0xfcU) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
  					utf_char = c & 0x01U;
  					utf_cnt = 5;
28de7948a   Cyrill Gorcunov   UDF: coding style...
212
  				} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
  					goto error_out;
28de7948a   Cyrill Gorcunov   UDF: coding style...
214
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  				continue;
28de7948a   Cyrill Gorcunov   UDF: coding style...
216
  			} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
  				/* Single byte UTF-8 character (most common) */
  				utf_char = c;
28de7948a   Cyrill Gorcunov   UDF: coding style...
219
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
222
  		}
  
  		/* Choose no compression if necessary */
cb00ea352   Cyrill Gorcunov   UDF: coding style...
223
  		if (utf_char > max_val) {
28de7948a   Cyrill Gorcunov   UDF: coding style...
224
  			if (max_val == 0xffU) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  				max_val = 0xffffU;
28de7948a   Cyrill Gorcunov   UDF: coding style...
226
  				ocu[0] = (uint8_t)0x10U;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
230
  				goto try_again;
  			}
  			goto error_out;
  		}
4b11111ab   Marcin Slusarz   udf: fix coding s...
231
  		if (max_val == 0xffffU)
28de7948a   Cyrill Gorcunov   UDF: coding style...
232
  			ocu[++u_len] = (uint8_t)(utf_char >> 8);
28de7948a   Cyrill Gorcunov   UDF: coding style...
233
  		ocu[++u_len] = (uint8_t)(utf_char & 0xffU);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
  	}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
235
  	if (utf_cnt) {
28de7948a   Cyrill Gorcunov   UDF: coding style...
236
  error_out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
  		ocu[++u_len] = '?';
78ace70c4   Joe Perches   udf: Convert prin...
238
239
  		printk(KERN_DEBUG pr_fmt("bad UTF-8 character
  "));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  	}
28de7948a   Cyrill Gorcunov   UDF: coding style...
241
  	ocu[length - 1] = (uint8_t)u_len + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
  	return u_len + 1;
  }
cb00ea352   Cyrill Gorcunov   UDF: coding style...
244
  static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o,
34f953ddf   marcin.slusarz@gmail.com   udf: udf_CS0toNLS...
245
  			const struct ustr *ocu_i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  {
34f953ddf   marcin.slusarz@gmail.com   udf: udf_CS0toNLS...
247
  	const uint8_t *ocu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
  	uint8_t cmp_id, ocu_len;
59285c28d   Jan Kara   udf: Fix oops whe...
249
  	int i, len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
  
  	ocu_len = ocu_i->u_len;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
253
  	if (ocu_len == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  		memset(utf_o, 0, sizeof(struct ustr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
  		return 0;
  	}
34f953ddf   marcin.slusarz@gmail.com   udf: udf_CS0toNLS...
257
258
259
  	cmp_id = ocu_i->u_cmpID;
  	if (cmp_id != 8 && cmp_id != 16) {
  		memset(utf_o, 0, sizeof(struct ustr));
78ace70c4   Joe Perches   udf: Convert prin...
260
261
  		pr_err("unknown compression code (%d) stri=%s
  ",
cb00ea352   Cyrill Gorcunov   UDF: coding style...
262
  		       cmp_id, ocu_i->u_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
  		return 0;
  	}
34f953ddf   marcin.slusarz@gmail.com   udf: udf_CS0toNLS...
265
266
  	ocu = ocu_i->u_name;
  	utf_o->u_len = 0;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
267
  	for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  		/* Expand OSTA compressed Unicode to Unicode */
34f953ddf   marcin.slusarz@gmail.com   udf: udf_CS0toNLS...
269
  		uint32_t c = ocu[i++];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
  		if (cmp_id == 16)
  			c = (c << 8) | ocu[i++];
59285c28d   Jan Kara   udf: Fix oops whe...
272
273
274
275
276
277
278
  		len = nls->uni2char(c, &utf_o->u_name[utf_o->u_len],
  				    UDF_NAME_LEN - utf_o->u_len);
  		/* Valid character? */
  		if (len >= 0)
  			utf_o->u_len += len;
  		else
  			utf_o->u_name[utf_o->u_len++] = '?';
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
  	}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
280
  	utf_o->u_cmpID = 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
283
  
  	return utf_o->u_len;
  }
28de7948a   Cyrill Gorcunov   UDF: coding style...
284
  static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni,
cb00ea352   Cyrill Gorcunov   UDF: coding style...
285
  			int length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
  {
59285c28d   Jan Kara   udf: Fix oops whe...
287
288
  	int len;
  	unsigned i, max_val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
292
293
294
  	uint16_t uni_char;
  	int u_len;
  
  	memset(ocu, 0, sizeof(dstring) * length);
  	ocu[0] = 8;
  	max_val = 0xffU;
28de7948a   Cyrill Gorcunov   UDF: coding style...
295
  try_again:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  	u_len = 0U;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
297
298
  	for (i = 0U; i < uni->u_len; i++) {
  		len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char);
59285c28d   Jan Kara   udf: Fix oops whe...
299
  		if (!len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
  			continue;
59285c28d   Jan Kara   udf: Fix oops whe...
301
302
303
304
305
  		/* Invalid character, deal with it */
  		if (len < 0) {
  			len = 1;
  			uni_char = '?';
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306

cb00ea352   Cyrill Gorcunov   UDF: coding style...
307
  		if (uni_char > max_val) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  			max_val = 0xffffU;
28de7948a   Cyrill Gorcunov   UDF: coding style...
309
  			ocu[0] = (uint8_t)0x10U;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
  			goto try_again;
  		}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
312

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
  		if (max_val == 0xffffU)
28de7948a   Cyrill Gorcunov   UDF: coding style...
314
315
  			ocu[++u_len] = (uint8_t)(uni_char >> 8);
  		ocu[++u_len] = (uint8_t)(uni_char & 0xffU);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
  		i += len - 1;
  	}
28de7948a   Cyrill Gorcunov   UDF: coding style...
318
  	ocu[length - 1] = (uint8_t)u_len + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
  	return u_len + 1;
  }
28de7948a   Cyrill Gorcunov   UDF: coding style...
321
  int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname,
cb00ea352   Cyrill Gorcunov   UDF: coding style...
322
  		     int flen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
  {
530f1a5e3   Marcin Slusarz   udf: reduce stack...
324
325
  	struct ustr *filename, *unifilename;
  	int len = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326

530f1a5e3   Marcin Slusarz   udf: reduce stack...
327
328
  	filename = kmalloc(sizeof(struct ustr), GFP_NOFS);
  	if (!filename)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330

530f1a5e3   Marcin Slusarz   udf: reduce stack...
331
332
333
334
335
336
  	unifilename = kmalloc(sizeof(struct ustr), GFP_NOFS);
  	if (!unifilename)
  		goto out1;
  
  	if (udf_build_ustr_exact(unifilename, sname, flen))
  		goto out2;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
337
  	if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
530f1a5e3   Marcin Slusarz   udf: reduce stack...
338
  		if (!udf_CS0toUTF8(filename, unifilename)) {
4b11111ab   Marcin Slusarz   udf: fix coding s...
339
340
341
  			udf_debug("Failed in udf_get_filename: sname = %s
  ",
  				  sname);
530f1a5e3   Marcin Slusarz   udf: reduce stack...
342
  			goto out2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
  		}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
344
  	} else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) {
530f1a5e3   Marcin Slusarz   udf: reduce stack...
345
346
  		if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, filename,
  				  unifilename)) {
4b11111ab   Marcin Slusarz   udf: fix coding s...
347
348
349
  			udf_debug("Failed in udf_get_filename: sname = %s
  ",
  				  sname);
530f1a5e3   Marcin Slusarz   udf: reduce stack...
350
  			goto out2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
  		}
4b11111ab   Marcin Slusarz   udf: fix coding s...
352
  	} else
530f1a5e3   Marcin Slusarz   udf: reduce stack...
353
354
355
356
357
358
359
360
361
  		goto out2;
  
  	len = udf_translate_to_linux(dname, filename->u_name, filename->u_len,
  				     unifilename->u_name, unifilename->u_len);
  out2:
  	kfree(unifilename);
  out1:
  	kfree(filename);
  	return len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
  }
28de7948a   Cyrill Gorcunov   UDF: coding style...
363
364
  int udf_put_filename(struct super_block *sb, const uint8_t *sname,
  		     uint8_t *dname, int flen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
366
367
  {
  	struct ustr unifilename;
  	int namelen;
4b11111ab   Marcin Slusarz   udf: fix coding s...
368
  	if (!udf_char_to_ustr(&unifilename, sname, flen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370

cb00ea352   Cyrill Gorcunov   UDF: coding style...
371
  	if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
28de7948a   Cyrill Gorcunov   UDF: coding style...
372
  		namelen = udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN);
4b11111ab   Marcin Slusarz   udf: fix coding s...
373
  		if (!namelen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  			return 0;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
375
  	} else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) {
4b11111ab   Marcin Slusarz   udf: fix coding s...
376
377
378
  		namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname,
  					&unifilename, UDF_NAME_LEN);
  		if (!namelen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
  			return 0;
4b11111ab   Marcin Slusarz   udf: fix coding s...
380
  	} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
384
385
386
  		return 0;
  
  	return namelen;
  }
  
  #define ILLEGAL_CHAR_MARK	'_'
28de7948a   Cyrill Gorcunov   UDF: coding style...
387
388
389
  #define EXT_MARK		'.'
  #define CRC_MARK		'#'
  #define EXT_SIZE 		5
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390

4b11111ab   Marcin Slusarz   udf: fix coding s...
391
392
393
  static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName,
  				  int udfLen, uint8_t *fidName,
  				  int fidNameLen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  {
cb00ea352   Cyrill Gorcunov   UDF: coding style...
395
  	int index, newIndex = 0, needsCRC = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
398
399
  	int extIndex = 0, newExtIndex = 0, hasExt = 0;
  	unsigned short valueCRC;
  	uint8_t curr;
  	const uint8_t hexChar[] = "0123456789ABCDEF";
28de7948a   Cyrill Gorcunov   UDF: coding style...
400
401
  	if (udfName[0] == '.' &&
  	    (udfLen == 1 || (udfLen == 2 && udfName[1] == '.'))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
403
404
  		needsCRC = 1;
  		newIndex = udfLen;
  		memcpy(newName, udfName, udfLen);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
405
406
  	} else {
  		for (index = 0; index < udfLen; index++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
  			curr = udfName[index];
cb00ea352   Cyrill Gorcunov   UDF: coding style...
408
  			if (curr == '/' || curr == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
  				needsCRC = 1;
  				curr = ILLEGAL_CHAR_MARK;
4b11111ab   Marcin Slusarz   udf: fix coding s...
411
412
413
  				while (index + 1 < udfLen &&
  						(udfName[index + 1] == '/' ||
  						 udfName[index + 1] == 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
  					index++;
4b11111ab   Marcin Slusarz   udf: fix coding s...
415
416
417
418
  			}
  			if (curr == EXT_MARK &&
  					(udfLen - index - 1) <= EXT_SIZE) {
  				if (udfLen == index + 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
  					hasExt = 0;
4b11111ab   Marcin Slusarz   udf: fix coding s...
420
  				else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
423
424
425
426
427
428
429
430
431
  					hasExt = 1;
  					extIndex = index;
  					newExtIndex = newIndex;
  				}
  			}
  			if (newIndex < 256)
  				newName[newIndex++] = curr;
  			else
  				needsCRC = 1;
  		}
  	}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
432
  	if (needsCRC) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
  		uint8_t ext[EXT_SIZE];
  		int localExtIndex = 0;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
435
  		if (hasExt) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
  			int maxFilenameLen;
4b11111ab   Marcin Slusarz   udf: fix coding s...
437
438
439
  			for (index = 0;
  			     index < EXT_SIZE && extIndex + index + 1 < udfLen;
  			     index++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
  				curr = udfName[extIndex + index + 1];
cb00ea352   Cyrill Gorcunov   UDF: coding style...
441
  				if (curr == '/' || curr == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
  					needsCRC = 1;
  					curr = ILLEGAL_CHAR_MARK;
4b11111ab   Marcin Slusarz   udf: fix coding s...
444
445
446
447
  					while (extIndex + index + 2 < udfLen &&
  					      (index + 1 < EXT_SIZE &&
  						(udfName[extIndex + index + 2] == '/' ||
  						 udfName[extIndex + index + 2] == 0)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
450
451
452
453
454
455
456
  						index++;
  				}
  				ext[localExtIndex++] = curr;
  			}
  			maxFilenameLen = 250 - localExtIndex;
  			if (newIndex > maxFilenameLen)
  				newIndex = maxFilenameLen;
  			else
  				newIndex = newExtIndex;
4b11111ab   Marcin Slusarz   udf: fix coding s...
457
  		} else if (newIndex > 250)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
  			newIndex = 250;
  		newName[newIndex++] = CRC_MARK;
f845fced9   Bob Copeland   udf: use crc_itu_...
460
  		valueCRC = crc_itu_t(0, fidName, fidNameLen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
464
  		newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12];
  		newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8];
  		newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4];
  		newName[newIndex++] = hexChar[(valueCRC & 0x000f)];
cb00ea352   Cyrill Gorcunov   UDF: coding style...
465
  		if (hasExt) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
  			newName[newIndex++] = EXT_MARK;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
467
  			for (index = 0; index < localExtIndex; index++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
470
  				newName[newIndex++] = ext[index];
  		}
  	}
28de7948a   Cyrill Gorcunov   UDF: coding style...
471

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
  	return newIndex;
  }