xref: /linux/fs/jfs/jfs_unicode.c (revision bd628c1bed7902ec1f24ba0fe70758949146abbe)
1 /*
2  *   Copyright (C) International Business Machines Corp., 2000-2004
3  *
4  *   This program is free software;  you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License as published by
6  *   the Free Software Foundation; either version 2 of the License, or
7  *   (at your option) any later version.
8  *
9  *   This program is distributed in the hope that it will be useful,
10  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
12  *   the GNU General Public License for more details.
13  *
14  *   You should have received a copy of the GNU General Public License
15  *   along with this program;  if not, write to the Free Software
16  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */
18 
19 #include <linux/fs.h>
20 #include <linux/slab.h>
21 #include "jfs_incore.h"
22 #include "jfs_filsys.h"
23 #include "jfs_unicode.h"
24 #include "jfs_debug.h"
25 
26 /*
27  * NAME:	jfs_strfromUCS()
28  *
29  * FUNCTION:	Convert little-endian unicode string to character string
30  *
31  */
32 int jfs_strfromUCS_le(char *to, const __le16 * from,
33 		      int len, struct nls_table *codepage)
34 {
35 	int i;
36 	int outlen = 0;
37 	static int warn_again = 5;	/* Only warn up to 5 times total */
38 	int warn = !!warn_again;	/* once per string */
39 
40 	if (codepage) {
41 		for (i = 0; (i < len) && from[i]; i++) {
42 			int charlen;
43 			charlen =
44 			    codepage->uni2char(le16_to_cpu(from[i]),
45 					       &to[outlen],
46 					       NLS_MAX_CHARSET_SIZE);
47 			if (charlen > 0)
48 				outlen += charlen;
49 			else
50 				to[outlen++] = '?';
51 		}
52 	} else {
53 		for (i = 0; (i < len) && from[i]; i++) {
54 			if (unlikely(le16_to_cpu(from[i]) & 0xff00)) {
55 				to[i] = '?';
56 				if (unlikely(warn)) {
57 					warn--;
58 					warn_again--;
59 					printk(KERN_ERR
60 			"non-latin1 character 0x%x found in JFS file name\n",
61 					       le16_to_cpu(from[i]));
62 					printk(KERN_ERR
63 				"mount with iocharset=utf8 to access\n");
64 				}
65 
66 			}
67 			else
68 				to[i] = (char) (le16_to_cpu(from[i]));
69 		}
70 		outlen = i;
71 	}
72 	to[outlen] = 0;
73 	return outlen;
74 }
75 
76 /*
77  * NAME:	jfs_strtoUCS()
78  *
79  * FUNCTION:	Convert character string to unicode string
80  *
81  */
82 static int jfs_strtoUCS(wchar_t * to, const unsigned char *from, int len,
83 		struct nls_table *codepage)
84 {
85 	int charlen;
86 	int i;
87 
88 	if (codepage) {
89 		for (i = 0; len && *from; i++, from += charlen, len -= charlen)
90 		{
91 			charlen = codepage->char2uni(from, len, &to[i]);
92 			if (charlen < 1) {
93 				jfs_err("jfs_strtoUCS: char2uni returned %d.",
94 					charlen);
95 				jfs_err("charset = %s, char = 0x%x",
96 					codepage->charset, *from);
97 				return charlen;
98 			}
99 		}
100 	} else {
101 		for (i = 0; (i < len) && from[i]; i++)
102 			to[i] = (wchar_t) from[i];
103 	}
104 
105 	to[i] = 0;
106 	return i;
107 }
108 
109 /*
110  * NAME:	get_UCSname()
111  *
112  * FUNCTION:	Allocate and translate to unicode string
113  *
114  */
115 int get_UCSname(struct component_name * uniName, struct dentry *dentry)
116 {
117 	struct nls_table *nls_tab = JFS_SBI(dentry->d_sb)->nls_tab;
118 	int length = dentry->d_name.len;
119 
120 	if (length > JFS_NAME_MAX)
121 		return -ENAMETOOLONG;
122 
123 	uniName->name =
124 	    kmalloc_array(length + 1, sizeof(wchar_t), GFP_NOFS);
125 
126 	if (uniName->name == NULL)
127 		return -ENOMEM;
128 
129 	uniName->namlen = jfs_strtoUCS(uniName->name, dentry->d_name.name,
130 				       length, nls_tab);
131 
132 	if (uniName->namlen < 0) {
133 		kfree(uniName->name);
134 		return uniName->namlen;
135 	}
136 
137 	return 0;
138 }
139