Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 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. */ |
| 27 | char *unix_normalize (doscp_t *cp, char *ans, dos_name_t *dn, size_t ans_size) |
| 28 | { |
| 29 | char buffer[13]; |
| 30 | wchar_t wbuffer[13]; |
| 31 | char *a; |
| 32 | int j; |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 33 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 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, ans_size); |
| 44 | return ans; |
| 45 | } |
| 46 | |
| 47 | typedef enum Case_l { |
| 48 | NONE, |
| 49 | UPPER, |
| 50 | LOWER |
| 51 | } Case_t; |
| 52 | |
| 53 | static void TranslateToDos(doscp_t *toDos, const char *in, char *out, |
| 54 | size_t count, char *end, Case_t *Case, int *mangled) |
| 55 | { |
| 56 | wchar_t buffer[12]; |
| 57 | wchar_t *s=buffer; |
| 58 | size_t t_idx = 0; |
| 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 | /* skip spaces & dots */ |
| 67 | if(*s == ' ' || *s == '.') { |
| 68 | *mangled |= 3; |
| 69 | continue; |
| 70 | } |
| 71 | |
| 72 | if (iswcntrl((wint_t)*s)) { |
| 73 | /* "control" characters */ |
| 74 | *mangled |= 3; |
| 75 | buffer[t_idx] = '_'; |
| 76 | } else if (iswlower((wint_t)*s)) { |
| 77 | buffer[t_idx] = ch_towupper(*s); |
| 78 | if(*Case == UPPER && !mtools_no_vfat) |
| 79 | *mangled |= 1; |
| 80 | else |
| 81 | *Case = LOWER; |
| 82 | } else if (iswupper((wint_t)*s)) { |
| 83 | buffer[t_idx] = *s; |
| 84 | if(*Case == LOWER && !mtools_no_vfat) |
| 85 | *mangled |= 1; |
| 86 | else |
| 87 | *Case = UPPER; |
| 88 | } else |
| 89 | buffer[t_idx] = *s; |
| 90 | t_idx++; |
| 91 | } |
| 92 | wchar_to_dos(toDos, buffer, out, t_idx, mangled); |
| 93 | } |
| 94 | |
| 95 | /* dos_name |
| 96 | * |
| 97 | * Convert a Unix-style filename to a legal MSDOS name and extension. |
| 98 | * Will truncate file and extension names, will substitute |
| 99 | * the character '~' for any illegal character(s) in the name. |
| 100 | */ |
| 101 | void dos_name(doscp_t *toDos, const char *name, int verbose UNUSEDP, |
| 102 | int *mangled, dos_name_t *dn) |
| 103 | { |
| 104 | char *s, *ext; |
| 105 | size_t i; |
| 106 | Case_t BaseCase, ExtCase = UPPER; |
| 107 | |
| 108 | *mangled = 0; |
| 109 | |
| 110 | /* skip drive letter */ |
| 111 | if (name[0] && name[1] == ':') |
| 112 | name = &name[2]; |
| 113 | |
| 114 | /* zap the leading path */ |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 115 | name = _basename(name); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 116 | if ((s = strrchr(name, '\\'))) |
| 117 | name = s + 1; |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 118 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 119 | memset(dn, ' ', 11); |
| 120 | |
| 121 | /* skip leading dots and spaces */ |
| 122 | i = strspn(name, ". "); |
| 123 | if(i) { |
| 124 | name += i; |
| 125 | *mangled = 3; |
| 126 | } |
| 127 | |
| 128 | ext = strrchr(name, '.'); |
| 129 | |
| 130 | /* main name */ |
| 131 | TranslateToDos(toDos, name, dn->base, 8, ext, &BaseCase, mangled); |
| 132 | if(ext) |
| 133 | TranslateToDos(toDos, ext+1, dn->ext, 3, 0, &ExtCase, mangled); |
| 134 | |
| 135 | if(*mangled & 2) |
| 136 | autorename_short(dn, 0); |
| 137 | |
| 138 | if(!*mangled) { |
| 139 | if(BaseCase == LOWER) |
| 140 | *mangled |= BASECASE; |
| 141 | if(ExtCase == LOWER) |
| 142 | *mangled |= EXTCASE; |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | |
| 147 | /* |
| 148 | * Get rid of spaces in an MSDOS 'raw' name (one that has come from the |
| 149 | * directory structure) so that it can be used for regular expression |
| 150 | * matching with a Unix filename. Also used to 'unfix' a name that has |
| 151 | * been altered by dos_name(). |
| 152 | */ |
| 153 | |
| 154 | wchar_t *unix_name(doscp_t *dosCp, |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 155 | const char *base, const char *ext, uint8_t Case, wchar_t *ret) |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 156 | { |
| 157 | char *s, tname[9], text[4], ans[13]; |
| 158 | int i; |
| 159 | |
| 160 | strncpy(tname, base, 8); |
| 161 | tname[8] = '\0'; |
| 162 | if ((s = strchr(tname, ' '))) |
| 163 | *s = '\0'; |
| 164 | if (tname[0] == '\x05') |
| 165 | tname[0] = '\xE5'; |
| 166 | |
| 167 | if(!(Case & (BASECASE | EXTCASE)) && mtools_ignore_short_case) |
| 168 | Case |= BASECASE | EXTCASE; |
| 169 | |
| 170 | if(Case & BASECASE) |
| 171 | for(i=0;i<8 && tname[i];i++) |
| 172 | tname[i] = ch_tolower(tname[i]); |
| 173 | |
| 174 | strncpy(text, ext, 3); |
| 175 | text[3] = '\0'; |
| 176 | if ((s = strchr(text, ' '))) |
| 177 | *s = '\0'; |
| 178 | |
| 179 | if(Case & EXTCASE) |
| 180 | for(i=0;i<3 && text[i];i++) |
| 181 | text[i] = ch_tolower(text[i]); |
| 182 | |
| 183 | if (*text) { |
| 184 | strcpy(ans, tname); |
| 185 | strcat(ans, "."); |
| 186 | strcat(ans, text); |
| 187 | } else |
| 188 | strcpy(ans, tname); |
| 189 | |
| 190 | /* fix special characters (above 0x80) */ |
| 191 | dos_to_wchar(dosCp, ans, ret, 12); |
| 192 | return ret; |
| 193 | } |
| 194 | |
| 195 | /* If null encountered, set *end to 0x40 and write nulls rest of way |
| 196 | * 950820: Win95 does not like this! It complains about bad characters. |
| 197 | * So, instead: If null encountered, set *end to 0x40, write the null, and |
| 198 | * write 0xff the rest of the way (that is what Win95 seems to do; hopefully |
| 199 | * that will make it happy) |
| 200 | */ |
| 201 | /* Always return num */ |
| 202 | int unicode_write(wchar_t *in, struct unicode_char *out, int num, int *end_p) |
| 203 | { |
| 204 | int j; |
| 205 | |
| 206 | for (j=0; j<num; ++j) { |
| 207 | if (*end_p) |
| 208 | /* Fill with 0xff */ |
| 209 | out->uchar = out->lchar = 0xff; |
| 210 | else { |
| 211 | /* TODO / FIXME : handle case where wchat has more |
| 212 | * than 2 bytes (i.e. bytes 2 or 3 are set. |
| 213 | * ==> generate surrogate pairs? |
| 214 | */ |
| 215 | out->uchar = (*in & 0xffff) >> 8; |
| 216 | out->lchar = *in & 0xff; |
| 217 | if (! *in) { |
| 218 | *end_p = VSE_LAST; |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | ++out; |
| 223 | ++in; |
| 224 | } |
| 225 | return num; |
| 226 | } |