trans.c 3.37 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11
/*
 *  linux/fs/hfs/trans.c
 *
 * Copyright (C) 1995-1997  Paul H. Hargrove
 * This file may be distributed under the terms of the GNU General Public License.
 *
 * This file contains routines for converting between the Macintosh
 * character set and various other encodings.  This includes dealing
 * with ':' vs. '/' as the path-element separator.
 */

Roman Zippel's avatar
Roman Zippel committed
12 13 14
#include <linux/types.h>
#include <linux/nls.h>

Linus Torvalds's avatar
Linus Torvalds committed
15 16 17 18 19
#include "hfs_fs.h"

/*================ Global functions ================*/

/*
Roman Zippel's avatar
Roman Zippel committed
20
 * hfs_mac2asc()
Linus Torvalds's avatar
Linus Torvalds committed
21 22 23 24 25 26 27 28 29 30 31 32
 *
 * Given a 'Pascal String' (a string preceded by a length byte) in
 * the Macintosh character set produce the corresponding filename using
 * the 'trivial' name-mangling scheme, returning the length of the
 * mangled filename.  Note that the output string is not NULL
 * terminated.
 *
 * The name-mangling works as follows:
 * The character '/', which is illegal in Linux filenames is replaced
 * by ':' which never appears in HFS filenames.	 All other characters
 * are passed unchanged from input to output.
 */
Roman Zippel's avatar
Roman Zippel committed
33
int hfs_mac2asc(struct super_block *sb, char *out, const struct hfs_name *in)
Linus Torvalds's avatar
Linus Torvalds committed
34
{
Roman Zippel's avatar
Roman Zippel committed
35 36 37 38 39 40 41 42
	struct nls_table *nls_disk = HFS_SB(sb)->nls_disk;
	struct nls_table *nls_io = HFS_SB(sb)->nls_io;
	const char *src;
	char *dst;
	int srclen, dstlen, size;

	src = in->name;
	srclen = in->len;
43 44
	if (srclen > HFS_NAMELEN)
		srclen = HFS_NAMELEN;
Roman Zippel's avatar
Roman Zippel committed
45 46 47 48
	dst = out;
	dstlen = HFS_MAX_NAMELEN;
	if (nls_io) {
		wchar_t ch;
Linus Torvalds's avatar
Linus Torvalds committed
49

Roman Zippel's avatar
Roman Zippel committed
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
		while (srclen > 0) {
			if (nls_disk) {
				size = nls_disk->char2uni(src, srclen, &ch);
				if (size <= 0) {
					ch = '?';
					size = 1;
				}
				src += size;
				srclen -= size;
			} else {
				ch = *src++;
				srclen--;
			}
			if (ch == '/')
				ch = ':';
			size = nls_io->uni2char(ch, dst, dstlen);
			if (size < 0) {
				if (size == -ENAMETOOLONG)
					goto out;
				*dst = '?';
				size = 1;
			}
			dst += size;
			dstlen -= size;
		}
	} else {
		char ch;

		while (--srclen >= 0)
			*dst++ = (ch = *src++) == '/' ? ':' : ch;
Linus Torvalds's avatar
Linus Torvalds committed
80
	}
Roman Zippel's avatar
Roman Zippel committed
81 82
out:
	return dst - out;
Linus Torvalds's avatar
Linus Torvalds committed
83 84 85
}

/*
Roman Zippel's avatar
Roman Zippel committed
86
 * hfs_asc2mac()
Linus Torvalds's avatar
Linus Torvalds committed
87 88 89 90 91 92 93 94 95 96
 *
 * Given an ASCII string (not null-terminated) and its length,
 * generate the corresponding filename in the Macintosh character set
 * using the 'trivial' name-mangling scheme, returning the length of
 * the mangled filename.  Note that the output string is not NULL
 * terminated.
 *
 * This routine is a inverse to hfs_mac2triv().
 * A ':' is replaced by a '/'.
 */
97
void hfs_asc2mac(struct super_block *sb, struct hfs_name *out, const struct qstr *in)
Linus Torvalds's avatar
Linus Torvalds committed
98
{
Roman Zippel's avatar
Roman Zippel committed
99 100
	struct nls_table *nls_disk = HFS_SB(sb)->nls_disk;
	struct nls_table *nls_io = HFS_SB(sb)->nls_io;
Linus Torvalds's avatar
Linus Torvalds committed
101
	const char *src;
Roman Zippel's avatar
Roman Zippel committed
102 103
	char *dst;
	int srclen, dstlen, size;
Linus Torvalds's avatar
Linus Torvalds committed
104 105

	src = in->name;
Roman Zippel's avatar
Roman Zippel committed
106
	srclen = in->len;
Linus Torvalds's avatar
Linus Torvalds committed
107
	dst = out->name;
Roman Zippel's avatar
Roman Zippel committed
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
	dstlen = HFS_NAMELEN;
	if (nls_io) {
		wchar_t ch;

		while (srclen > 0) {
			size = nls_io->char2uni(src, srclen, &ch);
			if (size < 0) {
				ch = '?';
				size = 1;
			}
			src += size;
			srclen -= size;
			if (ch == ':')
				ch = '/';
			if (nls_disk) {
				size = nls_disk->uni2char(ch, dst, dstlen);
				if (size < 0) {
					if (size == -ENAMETOOLONG)
						goto out;
					*dst = '?';
					size = 1;
				}
				dst += size;
				dstlen -= size;
			} else {
				*dst++ = ch > 0xff ? '?' : ch;
				dstlen--;
			}
		}
	} else {
		char ch;

		if (dstlen > srclen)
			dstlen = srclen;
		while (--dstlen >= 0)
			*dst++ = (ch = *src++) == ':' ? '/' : ch;
Linus Torvalds's avatar
Linus Torvalds committed
144
	}
Roman Zippel's avatar
Roman Zippel committed
145 146 147 148
out:
	out->len = dst - (char *)out->name;
	dstlen = HFS_NAMELEN - out->len;
	while (--dstlen >= 0)
Linus Torvalds's avatar
Linus Torvalds committed
149 150
		*dst++ = 0;
}