1/*
2 *  linux/fs/isofs/joliet.c
3 *
4 *  (C) 1996 Gordon Chaffee
5 *
6 *  Joliet: Microsoft's Unicode extensions to iso9660
7 */
8
9#include <linux/types.h>
10#include <linux/nls.h>
11#include "isofs.h"
12
13/*
14 * Convert Unicode 16 to UTF-8 or ASCII.
15 */
16static int
17uni16_to_x8(unsigned char *ascii, __be16 *uni, int len, struct nls_table *nls)
18{
19	__be16 *ip, ch;
20	unsigned char *op;
21
22	ip = uni;
23	op = ascii;
24
25	while ((ch = get_unaligned(ip)) && len) {
26		int llen;
27		llen = nls->uni2char(be16_to_cpu(ch), op, NLS_MAX_CHARSET_SIZE);
28		if (llen > 0)
29			op += llen;
30		else
31			*op++ = '?';
32		ip++;
33
34		len--;
35	}
36	*op = 0;
37	return (op - ascii);
38}
39
40/* Convert big endian wide character string to utf8 */
41static int
42wcsntombs_be(__u8 *s, const __u8 *pwcs, int inlen, int maxlen)
43{
44	const __u8 *ip;
45	__u8 *op;
46	int size;
47	__u16 c;
48
49	op = s;
50	ip = pwcs;
51	while ((*ip || ip[1]) && (maxlen > 0) && (inlen > 0)) {
52		c = (*ip << 8) | ip[1];
53		if (c > 0x7f) {
54			size = utf8_wctomb(op, c, maxlen);
55			if (size == -1) {
56				/* Ignore character and move on */
57				maxlen--;
58			} else {
59				op += size;
60				maxlen -= size;
61			}
62		} else {
63			*op++ = (__u8) c;
64		}
65		ip += 2;
66		inlen--;
67	}
68	return (op - s);
69}
70
71int
72get_joliet_filename(struct iso_directory_record * de, unsigned char *outname, struct inode * inode)
73{
74	unsigned char utf8;
75	struct nls_table *nls;
76	unsigned char len = 0;
77
78	utf8 = ISOFS_SB(inode->i_sb)->s_utf8;
79	nls = ISOFS_SB(inode->i_sb)->s_nls_iocharset;
80
81	if (utf8) {
82		len = wcsntombs_be(outname, de->name,
83				   de->name_len[0] >> 1, PAGE_SIZE);
84	} else {
85		len = uni16_to_x8(outname, (__be16 *) de->name,
86				  de->name_len[0] >> 1, nls);
87	}
88	if ((len > 2) && (outname[len-2] == ';') && (outname[len-1] == '1')) {
89		len -= 2;
90	}
91
92	/*
93	 * Windows doesn't like periods at the end of a name,
94	 * so neither do we
95	 */
96	while (len >= 2 && (outname[len-1] == '.')) {
97		len--;
98	}
99
100	return len;
101}
102