/*
|
/*
|
* linux/fs/isofs/joliet.c
|
* linux/fs/isofs/joliet.c
|
*
|
*
|
* (C) 1996 Gordon Chaffee
|
* (C) 1996 Gordon Chaffee
|
*
|
*
|
* Joliet: Microsoft's Unicode extensions to iso9660
|
* Joliet: Microsoft's Unicode extensions to iso9660
|
*/
|
*/
|
|
|
#include <linux/string.h>
|
#include <linux/string.h>
|
#include <linux/nls.h>
|
#include <linux/nls.h>
|
#include <linux/malloc.h>
|
#include <linux/malloc.h>
|
#include <linux/iso_fs.h>
|
#include <linux/iso_fs.h>
|
|
|
/*
|
/*
|
* Convert Unicode 16 to UTF8 or ascii.
|
* Convert Unicode 16 to UTF8 or ascii.
|
*/
|
*/
|
static int
|
static int
|
uni16_to_x8(unsigned char *ascii, unsigned char *uni, int len,
|
uni16_to_x8(unsigned char *ascii, unsigned char *uni, int len,
|
struct nls_table *nls)
|
struct nls_table *nls)
|
{
|
{
|
unsigned char *ip, *op;
|
unsigned char *ip, *op;
|
unsigned char ch, cl;
|
unsigned char ch, cl;
|
unsigned char *uni_page;
|
unsigned char *uni_page;
|
|
|
ip = uni;
|
ip = uni;
|
op = ascii;
|
op = ascii;
|
|
|
while ((*ip || ip[1]) && len) {
|
while ((*ip || ip[1]) && len) {
|
ch = *ip++;
|
ch = *ip++;
|
cl = *ip++;
|
cl = *ip++;
|
|
|
uni_page = nls->page_uni2charset[ch];
|
uni_page = nls->page_uni2charset[ch];
|
if (uni_page && uni_page[cl]) {
|
if (uni_page && uni_page[cl]) {
|
*op++ = uni_page[cl];
|
*op++ = uni_page[cl];
|
} else {
|
} else {
|
*op++ = '?';
|
*op++ = '?';
|
}
|
}
|
len--;
|
len--;
|
}
|
}
|
*op = 0;
|
*op = 0;
|
return (op - ascii);
|
return (op - ascii);
|
}
|
}
|
|
|
/* Convert big endian wide character string to utf8 */
|
/* Convert big endian wide character string to utf8 */
|
static int
|
static int
|
wcsntombs_be(__u8 *s, const __u8 *pwcs, int inlen, int maxlen)
|
wcsntombs_be(__u8 *s, const __u8 *pwcs, int inlen, int maxlen)
|
{
|
{
|
const __u8 *ip;
|
const __u8 *ip;
|
__u8 *op;
|
__u8 *op;
|
int size;
|
int size;
|
__u16 c;
|
__u16 c;
|
|
|
op = s;
|
op = s;
|
ip = pwcs;
|
ip = pwcs;
|
while ((*ip || ip[1]) && (maxlen > 0) && (inlen > 0)) {
|
while ((*ip || ip[1]) && (maxlen > 0) && (inlen > 0)) {
|
c = (*ip << 8) | ip[1];
|
c = (*ip << 8) | ip[1];
|
if (c > 0x7f) {
|
if (c > 0x7f) {
|
size = utf8_wctomb(op, c, maxlen);
|
size = utf8_wctomb(op, c, maxlen);
|
if (size == -1) {
|
if (size == -1) {
|
/* Ignore character and move on */
|
/* Ignore character and move on */
|
maxlen--;
|
maxlen--;
|
} else {
|
} else {
|
op += size;
|
op += size;
|
maxlen -= size;
|
maxlen -= size;
|
}
|
}
|
} else {
|
} else {
|
*op++ = (__u8) c;
|
*op++ = (__u8) c;
|
}
|
}
|
ip += 2;
|
ip += 2;
|
inlen--;
|
inlen--;
|
}
|
}
|
return (op - s);
|
return (op - s);
|
}
|
}
|
|
|
int
|
int
|
get_joliet_filename(struct iso_directory_record * de, struct inode * inode,
|
get_joliet_filename(struct iso_directory_record * de, struct inode * inode,
|
unsigned char *outname)
|
unsigned char *outname)
|
{
|
{
|
unsigned char utf8;
|
unsigned char utf8;
|
struct nls_table *nls;
|
struct nls_table *nls;
|
unsigned char len = 0;
|
unsigned char len = 0;
|
int i;
|
int i;
|
char c;
|
char c;
|
|
|
utf8 = inode->i_sb->u.isofs_sb.s_utf8;
|
utf8 = inode->i_sb->u.isofs_sb.s_utf8;
|
nls = inode->i_sb->u.isofs_sb.s_nls_iocharset;
|
nls = inode->i_sb->u.isofs_sb.s_nls_iocharset;
|
|
|
if (utf8) {
|
if (utf8) {
|
len = wcsntombs_be(outname, de->name,
|
len = wcsntombs_be(outname, de->name,
|
de->name_len[0] >> 1, PAGE_SIZE);
|
de->name_len[0] >> 1, PAGE_SIZE);
|
} else {
|
} else {
|
len = uni16_to_x8(outname, de->name,
|
len = uni16_to_x8(outname, de->name,
|
de->name_len[0] >> 1, nls);
|
de->name_len[0] >> 1, nls);
|
}
|
}
|
if ((len > 2) && (outname[len-2] == ';') && (outname[len-1] == '1')) {
|
if ((len > 2) && (outname[len-2] == ';') && (outname[len-1] == '1')) {
|
len -= 2;
|
len -= 2;
|
}
|
}
|
|
|
/*
|
/*
|
* Windows doesn't like periods at the end of a name
|
* Windows doesn't like periods at the end of a name
|
*/
|
*/
|
while (len >= 2 && (outname[len-1] == '.')) {
|
while (len >= 2 && (outname[len-1] == '.')) {
|
len--;
|
len--;
|
}
|
}
|
|
|
if (inode->i_sb->u.isofs_sb.s_name_check == 'r') {
|
if (inode->i_sb->u.isofs_sb.s_name_check == 'r') {
|
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
c = outname[i];
|
c = outname[i];
|
/* lower case */
|
/* lower case */
|
if (c >= 'A' && c <= 'Z') c |= 0x20;
|
if (c >= 'A' && c <= 'Z') c |= 0x20;
|
if (c == ';') c = '.';
|
if (c == ';') c = '.';
|
outname[i] = c;
|
outname[i] = c;
|
}
|
}
|
}
|
}
|
|
|
return len;
|
return len;
|
}
|
}
|
|
|