blob: 8dac0aa824b21adcd25ebcb4ce462feb003426ac [file] [log] [blame]
/* Copyright 1995 David C. Niemi
* Copyright 1996-1998,2000-2002,2008,2009 Alain Knaff.
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "vfat.h"
#include "codepage.h"
#include "file_name.h"
/* Write a DOS name + extension into a legal unix-style name. */
char *unix_normalize (doscp_t *cp, char *ans, dos_name_t *dn, size_t ans_size)
{
char buffer[13];
wchar_t wbuffer[13];
char *a;
int j;
for (a=buffer,j=0; (j<8) && (dn->base[j] > ' '); ++j,++a)
*a = dn->base[j];
if(dn->ext[0] > ' ') {
*a++ = '.';
for (j=0; j<3 && dn->ext[j] > ' '; ++j,++a)
*a = dn->ext[j];
}
*a++ = '\0';
dos_to_wchar(cp, buffer, wbuffer, 13);
wchar_to_native(wbuffer, ans, 13, ans_size);
return ans;
}
typedef enum Case_l {
NONE,
UPPER,
LOWER
} Case_t;
static void TranslateToDos(doscp_t *toDos, const char *in, char *out,
size_t count, char *end, Case_t *Case, int *mangled)
{
wchar_t buffer[12];
wchar_t *s=buffer;
size_t t_idx = 0;
/* first convert to wchar, so we get to use towupper etc. */
native_to_wchar(in, buffer, count, end, mangled);
buffer[count]='\0';
*Case = NONE;
for( ; *s ; s++) {
/* skip spaces & dots */
if(*s == ' ' || *s == '.') {
*mangled |= 3;
continue;
}
if (iswcntrl((wint_t)*s)) {
/* "control" characters */
*mangled |= 3;
buffer[t_idx] = '_';
} else if (iswlower((wint_t)*s)) {
buffer[t_idx] = ch_towupper(*s);
if(*Case == UPPER && !mtools_no_vfat)
*mangled |= 1;
else
*Case = LOWER;
} else if (iswupper((wint_t)*s)) {
buffer[t_idx] = *s;
if(*Case == LOWER && !mtools_no_vfat)
*mangled |= 1;
else
*Case = UPPER;
} else
buffer[t_idx] = *s;
t_idx++;
}
wchar_to_dos(toDos, buffer, out, t_idx, mangled);
}
/* dos_name
*
* Convert a Unix-style filename to a legal MSDOS name and extension.
* Will truncate file and extension names, will substitute
* the character '~' for any illegal character(s) in the name.
*/
void dos_name(doscp_t *toDos, const char *name, int verbose UNUSEDP,
int *mangled, dos_name_t *dn)
{
char *s, *ext;
size_t i;
Case_t BaseCase, ExtCase = UPPER;
*mangled = 0;
/* skip drive letter */
if (name[0] && name[1] == ':')
name = &name[2];
/* zap the leading path */
name = (char *) _basename(name);
if ((s = strrchr(name, '\\')))
name = s + 1;
memset(dn, ' ', 11);
/* skip leading dots and spaces */
i = strspn(name, ". ");
if(i) {
name += i;
*mangled = 3;
}
ext = strrchr(name, '.');
/* main name */
TranslateToDos(toDos, name, dn->base, 8, ext, &BaseCase, mangled);
if(ext)
TranslateToDos(toDos, ext+1, dn->ext, 3, 0, &ExtCase, mangled);
if(*mangled & 2)
autorename_short(dn, 0);
if(!*mangled) {
if(BaseCase == LOWER)
*mangled |= BASECASE;
if(ExtCase == LOWER)
*mangled |= EXTCASE;
}
}
/*
* Get rid of spaces in an MSDOS 'raw' name (one that has come from the
* directory structure) so that it can be used for regular expression
* matching with a Unix filename. Also used to 'unfix' a name that has
* been altered by dos_name().
*/
wchar_t *unix_name(doscp_t *dosCp,
const char *base, const char *ext, char Case, wchar_t *ret)
{
char *s, tname[9], text[4], ans[13];
int i;
strncpy(tname, base, 8);
tname[8] = '\0';
if ((s = strchr(tname, ' ')))
*s = '\0';
if (tname[0] == '\x05')
tname[0] = '\xE5';
if(!(Case & (BASECASE | EXTCASE)) && mtools_ignore_short_case)
Case |= BASECASE | EXTCASE;
if(Case & BASECASE)
for(i=0;i<8 && tname[i];i++)
tname[i] = ch_tolower(tname[i]);
strncpy(text, ext, 3);
text[3] = '\0';
if ((s = strchr(text, ' ')))
*s = '\0';
if(Case & EXTCASE)
for(i=0;i<3 && text[i];i++)
text[i] = ch_tolower(text[i]);
if (*text) {
strcpy(ans, tname);
strcat(ans, ".");
strcat(ans, text);
} else
strcpy(ans, tname);
/* fix special characters (above 0x80) */
dos_to_wchar(dosCp, ans, ret, 12);
return ret;
}
/* If null encountered, set *end to 0x40 and write nulls rest of way
* 950820: Win95 does not like this! It complains about bad characters.
* So, instead: If null encountered, set *end to 0x40, write the null, and
* write 0xff the rest of the way (that is what Win95 seems to do; hopefully
* that will make it happy)
*/
/* Always return num */
int unicode_write(wchar_t *in, struct unicode_char *out, int num, int *end_p)
{
int j;
for (j=0; j<num; ++j) {
if (*end_p)
/* Fill with 0xff */
out->uchar = out->lchar = 0xff;
else {
/* TODO / FIXME : handle case where wchat has more
* than 2 bytes (i.e. bytes 2 or 3 are set.
* ==> generate surrogate pairs?
*/
out->uchar = (*in & 0xffff) >> 8;
out->lchar = *in & 0xff;
if (! *in) {
*end_p = VSE_LAST;
}
}
++out;
++in;
}
return num;
}