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