1/*
2 *  linux/fs/hfs/trans.c
3 *
4 * Copyright (C) 1995-1997  Paul H. Hargrove
5 * This file may be distributed under the terms of the GNU General Public License.
6 *
7 * This file contains routines for converting between the Macintosh
8 * character set and various other encodings.  This includes dealing
9 * with ':' vs. '/' as the path-element separator.
10 */
11
12#include <linux/types.h>
13#include <linux/nls.h>
14
15#include "hfs_fs.h"
16
17/*================ Global functions ================*/
18
19/*
20 * hfs_mac2asc()
21 *
22 * Given a 'Pascal String' (a string preceded by a length byte) in
23 * the Macintosh character set produce the corresponding filename using
24 * the 'trivial' name-mangling scheme, returning the length of the
25 * mangled filename.  Note that the output string is not NULL
26 * terminated.
27 *
28 * The name-mangling works as follows:
29 * The character '/', which is illegal in Linux filenames is replaced
30 * by ':' which never appears in HFS filenames.	 All other characters
31 * are passed unchanged from input to output.
32 */
33int hfs_mac2asc(struct super_block *sb, char *out, const struct hfs_name *in)
34{
35	struct nls_table *nls_disk = HFS_SB(sb)->nls_disk;
36	struct nls_table *nls_io = HFS_SB(sb)->nls_io;
37	const char *src;
38	char *dst;
39	int srclen, dstlen, size;
40
41	src = in->name;
42	srclen = in->len;
43	if (srclen > HFS_NAMELEN)
44		srclen = HFS_NAMELEN;
45	dst = out;
46	dstlen = HFS_MAX_NAMELEN;
47	if (nls_io) {
48		wchar_t ch;
49
50		while (srclen > 0) {
51			if (nls_disk) {
52				size = nls_disk->char2uni(src, srclen, &ch);
53				if (size <= 0) {
54					ch = '?';
55					size = 1;
56				}
57				src += size;
58				srclen -= size;
59			} else {
60				ch = *src++;
61				srclen--;
62			}
63			if (ch == '/')
64				ch = ':';
65			size = nls_io->uni2char(ch, dst, dstlen);
66			if (size < 0) {
67				if (size == -ENAMETOOLONG)
68					goto out;
69				*dst = '?';
70				size = 1;
71			}
72			dst += size;
73			dstlen -= size;
74		}
75	} else {
76		char ch;
77
78		while (--srclen >= 0)
79			*dst++ = (ch = *src++) == '/' ? ':' : ch;
80	}
81out:
82	return dst - out;
83}
84
85/*
86 * hfs_asc2mac()
87 *
88 * Given an ASCII string (not null-terminated) and its length,
89 * generate the corresponding filename in the Macintosh character set
90 * using the 'trivial' name-mangling scheme, returning the length of
91 * the mangled filename.  Note that the output string is not NULL
92 * terminated.
93 *
94 * This routine is a inverse to hfs_mac2triv().
95 * A ':' is replaced by a '/'.
96 */
97void hfs_asc2mac(struct super_block *sb, struct hfs_name *out, const struct qstr *in)
98{
99	struct nls_table *nls_disk = HFS_SB(sb)->nls_disk;
100	struct nls_table *nls_io = HFS_SB(sb)->nls_io;
101	const char *src;
102	char *dst;
103	int srclen, dstlen, size;
104
105	src = in->name;
106	srclen = in->len;
107	dst = out->name;
108	dstlen = HFS_NAMELEN;
109	if (nls_io) {
110		wchar_t ch;
111
112		while (srclen > 0 && dstlen > 0) {
113			size = nls_io->char2uni(src, srclen, &ch);
114			if (size < 0) {
115				ch = '?';
116				size = 1;
117			}
118			src += size;
119			srclen -= size;
120			if (ch == ':')
121				ch = '/';
122			if (nls_disk) {
123				size = nls_disk->uni2char(ch, dst, dstlen);
124				if (size < 0) {
125					if (size == -ENAMETOOLONG)
126						goto out;
127					*dst = '?';
128					size = 1;
129				}
130				dst += size;
131				dstlen -= size;
132			} else {
133				*dst++ = ch > 0xff ? '?' : ch;
134				dstlen--;
135			}
136		}
137	} else {
138		char ch;
139
140		if (dstlen > srclen)
141			dstlen = srclen;
142		while (--dstlen >= 0)
143			*dst++ = (ch = *src++) == ':' ? '/' : ch;
144	}
145out:
146	out->len = dst - (char *)out->name;
147	dstlen = HFS_NAMELEN - out->len;
148	while (--dstlen >= 0)
149		*dst++ = 0;
150}
151