• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.  */
unix_normalize(doscp_t * cp,char * ans,dos_name_t * dn,size_t ans_size)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;
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, ans_size);
44 	return ans;
45 }
46 
47 typedef enum Case_l {
48 	NONE,
49 	UPPER,
50 	LOWER
51 } Case_t;
52 
TranslateToDos(doscp_t * toDos,const char * in,char * out,size_t count,char * end,Case_t * Case,int * mangled)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  */
dos_name(doscp_t * toDos,const char * name,int verbose UNUSEDP,int * mangled,dos_name_t * dn)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 */
115 	name = _basename(name);
116 	if ((s = strrchr(name, '\\')))
117 		name = s + 1;
118 
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 
unix_name(doscp_t * dosCp,const char * base,const char * ext,uint8_t Case,wchar_t * ret)154 wchar_t *unix_name(doscp_t *dosCp,
155 		   const char *base, const char *ext, uint8_t Case, wchar_t *ret)
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 */
unicode_write(wchar_t * in,struct unicode_char * out,int num,int * end_p)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 }
227