GNU Linux-libre 5.10.219-gnu1
[releases.git] / fs / hfs / trans.c
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  */
33 int 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         }
81 out:
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  */
97 void 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         }
145 out:
146         out->len = dst - (char *)out->name;
147         dstlen = HFS_NAMELEN - out->len;
148         while (--dstlen >= 0)
149                 *dst++ = 0;
150 }