1/* Copyright 1995 David C. Niemi 2 * Copyright 1996-1998,2000-2002,2008,2009 Alain Knaff. 3 * This file is part of mtools. 4 * 5 * Mtools is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * Mtools is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with Mtools. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19#include "sysincludes.h" 20#include "msdos.h" 21#include "mtools.h" 22#include "vfat.h" 23#include "codepage.h" 24#include "file_name.h" 25 26/* Write a DOS name + extension into a legal unix-style name. */ 27char *unix_normalize (doscp_t *cp, char *ans, dos_name_t *dn) 28{ 29 char buffer[13]; 30 wchar_t wbuffer[13]; 31 char *a; 32 int j; 33 34 for (a=buffer,j=0; (j<8) && (dn->base[j] > ' '); ++j,++a) 35 *a = dn->base[j]; 36 if(dn->ext[0] > ' ') { 37 *a++ = '.'; 38 for (j=0; j<3 && dn->ext[j] > ' '; ++j,++a) 39 *a = dn->ext[j]; 40 } 41 *a++ = '\0'; 42 dos_to_wchar(cp, buffer, wbuffer, 13); 43 wchar_to_native(wbuffer, ans, 13); 44 return ans; 45} 46 47typedef enum Case_l { 48 NONE, 49 UPPER, 50 LOWER 51} Case_t; 52 53static void TranslateToDos(doscp_t *toDos, const char *in, char *out, int count, 54 char *end, Case_t *Case, int *mangled) 55{ 56 wchar_t buffer[12]; 57 wchar_t *s=buffer; 58 wchar_t *t=buffer; 59 60 /* first convert to wchar, so we get to use towupper etc. */ 61 native_to_wchar(in, buffer, count, end, mangled); 62 buffer[count]='\0'; 63 64 *Case = NONE; 65 for( ; *s ; s++) { 66 if(!count) { 67 *mangled |= 3; 68 break; 69 } 70 /* skip spaces & dots */ 71 if(*s == ' ' || *s == '.') { 72 *mangled |= 3; 73 continue; 74 } 75 76 if (iswcntrl(*s)) { 77 /* "control" characters */ 78 *mangled |= 3; 79 *t = '_'; 80 } else if (iswlower(*s)) { 81 *t = towupper(*s); 82 if(*Case == UPPER && !mtools_no_vfat) 83 *mangled |= 1; 84 else 85 *Case = LOWER; 86 } else if (iswupper(*s)) { 87 *t = *s; 88 if(*Case == LOWER && !mtools_no_vfat) 89 *mangled |= 1; 90 else 91 *Case = UPPER; 92 } else 93 *t = *s; 94 count--; 95 t++; 96 } 97 wchar_to_dos(toDos, buffer, out, t - buffer, mangled); 98} 99 100/* dos_name 101 * 102 * Convert a Unix-style filename to a legal MSDOS name and extension. 103 * Will truncate file and extension names, will substitute 104 * the character '~' for any illegal character(s) in the name. 105 */ 106void dos_name(doscp_t *toDos, const char *name, int verbose, int *mangled, 107 dos_name_t *dn) 108{ 109 char *s, *ext; 110 register int i; 111 Case_t BaseCase, ExtCase; 112 113 *mangled = 0; 114 115 /* skip drive letter */ 116 if (name[0] && name[1] == ':') 117 name = &name[2]; 118 119 /* zap the leading path */ 120 name = (char *) _basename(name); 121 if ((s = strrchr(name, '\\'))) 122 name = s + 1; 123 124 memset(dn, ' ', 11); 125 126 /* skip leading dots and spaces */ 127 i = strspn(name, ". "); 128 if(i) { 129 name += i; 130 *mangled = 3; 131 } 132 133 ext = strrchr(name, '.'); 134 135 /* main name */ 136 TranslateToDos(toDos, name, dn->base, 8, ext, &BaseCase, mangled); 137 if(ext) 138 TranslateToDos(toDos, ext+1, dn->ext, 3, 0, &ExtCase, mangled); 139 140 if(*mangled & 2) 141 autorename_short(dn, 0); 142 143 if(!*mangled) { 144 if(BaseCase == LOWER) 145 *mangled |= BASECASE; 146 if(ExtCase == LOWER) 147 *mangled |= EXTCASE; 148 if((BaseCase == LOWER || ExtCase == LOWER) && 149 !mtools_no_vfat) { 150 *mangled |= 1; 151 } 152 } 153} 154 155 156/* 157 * Get rid of spaces in an MSDOS 'raw' name (one that has come from the 158 * directory structure) so that it can be used for regular expression 159 * matching with a Unix filename. Also used to 'unfix' a name that has 160 * been altered by dos_name(). 161 */ 162 163wchar_t *unix_name(doscp_t *dosCp, 164 const char *base, const char *ext, char Case, wchar_t *ret) 165{ 166 char *s, tname[9], text[4], ans[13]; 167 int i; 168 169 strncpy(tname, base, 8); 170 tname[8] = '\0'; 171 if ((s = strchr(tname, ' '))) 172 *s = '\0'; 173 174 if(!(Case & (BASECASE | EXTCASE)) && mtools_ignore_short_case) 175 Case |= BASECASE | EXTCASE; 176 177 if(Case & BASECASE) 178 for(i=0;i<8 && tname[i];i++) 179 tname[i] = tolower(tname[i]); 180 181 strncpy(text, ext, 3); 182 text[3] = '\0'; 183 if ((s = strchr(text, ' '))) 184 *s = '\0'; 185 186 if(Case & EXTCASE) 187 for(i=0;i<3 && text[i];i++) 188 text[i] = tolower(text[i]); 189 190 if (*text) { 191 strcpy(ans, tname); 192 strcat(ans, "."); 193 strcat(ans, text); 194 } else 195 strcpy(ans, tname); 196 197 /* fix special characters (above 0x80) */ 198 dos_to_wchar(dosCp, ans, ret, 12); 199 return ret; 200} 201 202/* If null encountered, set *end to 0x40 and write nulls rest of way 203 * 950820: Win95 does not like this! It complains about bad characters. 204 * So, instead: If null encountered, set *end to 0x40, write the null, and 205 * write 0xff the rest of the way (that is what Win95 seems to do; hopefully 206 * that will make it happy) 207 */ 208/* Always return num */ 209int unicode_write(wchar_t *in, struct unicode_char *out, int num, int *end_p) 210{ 211 int j; 212 213 for (j=0; j<num; ++j) { 214 if (*end_p) 215 /* Fill with 0xff */ 216 out->uchar = out->lchar = (char) 0xff; 217 else { 218 out->uchar = *in >> 8; 219 out->lchar = *in; 220 if (! *in) { 221 *end_p = VSE_LAST; 222 } 223 } 224 225 ++out; 226 ++in; 227 } 228 return num; 229} 230