1 /* win-path.c
2
3 directory and file functions working on UTF-16 file and path names
4
5 Copyright (C) 2007,2008,2010 Michael Sabin
6
7 This software is provided 'as-is', without any express or implied
8 warranty. In no event will the authors be held liable for any damages
9 arising from the use of this software.
10
11 Permission is granted to anyone to use this software for any purpose,
12 including commercial applications, and to alter it and redistribute it
13 freely, subject to the following restrictions:
14
15 1. The origin of this software must not be misrepresented; you must not
16 claim that you wrote the original software. If you use this software
17 in a product, an acknowledgment in the product documentation would be
18 appreciated but is not required.
19 2. Altered source versions must be plainly marked as such, and must not be
20 misrepresented as being the original software.
21 3. This notice may not be removed or altered from any source distribution.
22 */
23
24 #include <wchar.h>
25 #include <windows.h>
26 #include "newlisp.h"
27 #include "protos.h"
28
29 /*
30 utf8_to_utf16
31 Uses the Windows API to convert a UTF-8 string to a UTF-16 string.
32 Returns a pointer to a WCHAR string, or NULL if there was an error
33 (like if an invalid utf8 string was provided).
34 Note that the returned string must be free()ed.
35 */
utf8_to_utf16(const char * utf8str)36 WCHAR * utf8_to_utf16(const char *utf8str)
37 {
38 int size = -1;
39 WCHAR *utf16str = NULL;
40
41 size = MultiByteToWideChar(
42 CP_UTF8,
43 0, /* no flags=ignore errors if possible */
44 utf8str,
45 -1, /* read until NULL character */
46 NULL,
47 0 /* just calculate size */
48 );
49
50 if (size == 0) return (NULL);
51
52 utf16str = (WCHAR*)callocMemory((size+1) * sizeof(WCHAR));
53
54 size = MultiByteToWideChar(
55 CP_UTF8,
56 0,
57 utf8str,
58 -1,
59 utf16str,
60 size
61 );
62
63 if (size == 0)
64 {
65 free(utf16str);
66 return(NULL);
67 }
68 else
69 return(utf16str);
70 }
71
72
73 /*
74 utf16_to_utf8ptr
75 Used in win_realpath,
76 but otherwise wrapped by utf16_to_utf8.
77 */
utf16_to_utf8ptr(const WCHAR * utf16str,char * utf8str,int size)78 int utf16_to_utf8ptr(const WCHAR *utf16str, char * utf8str, int size)
79 {
80
81 if (size < 1) return(-1);
82
83 size = WideCharToMultiByte(
84 CP_UTF8,
85 0,
86 utf16str,
87 -1,
88 utf8str,
89 size,
90 NULL,
91 NULL
92 );
93
94 if (size == 0)
95 return(-1);
96 else
97 return(0);
98 }
99
100 /*
101 utf16_to_utf8
102 Uses the Windows API to convert a UTF-16 string to a UTF-8 string.
103 Returns a pointer to a char string, or NULL if there was an error
104 (like if an invalid utf16 string was provided).
105 Note that the returned string must be free()ed.
106 */
utf16_to_utf8(const WCHAR * utf16str)107 char * utf16_to_utf8(const WCHAR *utf16str)
108 {
109 int size = -1;
110 char *utf8str = NULL;
111
112 size = WideCharToMultiByte(
113 CP_UTF8,
114 0,
115 utf16str,
116 -1,
117 0,
118 0,
119 NULL,
120 NULL
121 );
122
123 if (size == 0) return (NULL);
124
125 utf8str = (char*)callocMemory((size+1) * sizeof(char));
126
127 if (utf16_to_utf8ptr(utf16str, utf8str, size) == -1)
128 {
129 free(utf8str);
130 return(NULL);
131 }
132 else
133 return(utf8str);
134 }
135
136 /* wrapper to return a cell */
137
138 #if SUPPORT_UTF8
utf8_from_mbcs(void * str)139 CELL * utf8_from_mbcs(void * str)
140 {
141 WCHAR * utf16str;
142 char * utf8str;
143
144 utf16str = ansi_mbcs_to_utf16(str);
145 utf8str = utf16_to_utf8(utf16str);
146 free(utf16str);
147
148 if(utf8str != NULL)
149 return(makeStringCell(utf8str, strlen(utf8str)));
150 else
151 return(nilCell);
152 }
153 #endif
154
155 /*
156 mbcs_to_utf16
157 Uses the Windows API to convert a FileSystem/CommandArgs OEM CodePage string to a UTF-16 string.
158 Returns a pointer to a WCHAR string, or NULL if there was an error
159 */
ansi_mbcs_to_utf16(const char * mbcsStr)160 WCHAR * ansi_mbcs_to_utf16(const char *mbcsStr)
161 {
162 int size = -1;
163 WCHAR *utf16str = NULL;
164
165 size = MultiByteToWideChar(
166 CP_OEMCP,
167 0, /* no flags=ignore errors if possible */
168 mbcsStr,
169 -1, /* read until NULL character */
170 NULL,
171 0 /* just calculate size */
172 );
173
174 if (size == 0) return (NULL);
175
176 utf16str = (WCHAR*)callocMemory((size+1) * sizeof(WCHAR));
177
178 size = MultiByteToWideChar(
179 CP_OEMCP,
180 0,
181 mbcsStr,
182 -1,
183 utf16str,
184 size
185 );
186
187 if (size == 0)
188 {
189 free(utf16str);
190 return(NULL);
191 }
192 else
193 return(utf16str);
194 }
195
196 /*
197 win_realpath
198 Identical interface as realpath
199 for both ANSI and UTF-16 path names on Windows.
200 Has the following functional differences
201 * If GetFullPathNameW, first converts the UTF-8 file name to UTF-16 (WCHAR)
202 * Uses GetFullPathNameA or GetFullPathNameW to receive the char/WCHAR path
203 * If GetFullPathNameW, converts the UTF-16 WCHAR path back to UTF-8
204 */
win_realpath(const char * filepath,char * realpath)205 char *win_realpath(const char *filepath, char *realpath)
206 {
207
208 #ifdef USE_WIN_UTF16PATH
209
210 WCHAR * utf16filepath;
211 WCHAR utf16realpath[MAX_PATH + 2];
212 int err;
213
214 utf16filepath = utf8_to_utf16(filepath);
215 err = GetFullPathNameW(utf16filepath, MAX_PATH, utf16realpath, NULL);
216 free(utf16filepath);
217
218 if (err == 0)
219 return(NULL);
220
221 if (utf16_to_utf8ptr(utf16realpath, realpath, MAX_PATH) == -1)
222 return(NULL);
223
224 #else
225
226 if(GetFullPathNameA(filepath, MAX_PATH, realpath, NULL) == 0)
227 return(NULL);
228
229 #endif
230
231 return(isFile(realpath, 0) ? 0 : realpath);
232 }
233
234 /*
235 win_getModulePath - added by LM for version 10.4.7
236 used in newlisp.c:loadStartup(..) and newlisp.c:linkUnlink(...)
237 gets the full path for a loaded module (executable).
238 EXEName must be allocated by caller with PATH_MAX typically
239 */
240
win_getExePath(char * EXEName)241 char * win_getExePath(char * EXEName)
242 {
243 #ifdef SUPPORT_UTF8
244 WCHAR wEXEName[PATH_MAX] ;
245 GetModuleFileNameW(NULL, wEXEName, PATH_MAX);
246 utf16_to_utf8ptr(wEXEName, EXEName, PATH_MAX);
247 #else
248 GetModuleFileName(NULL, EXEName, PATH_MAX);
249 #endif
250
251 return(EXEName);
252 }
253
254 /* ----------------------------------------------------------------------------
255 Wrappers for wide-character functions.
256 Same interface as the standard functions, but accepts UTF-8 strings.
257 Adds the following functionality:
258 * first converts the UTF-8 string to UTF-16
259 * if there a conversion error, return fail
260 * calls the wide-character function
261 Note that errno is not set on UTF conversion failures.
262 ---------------------------------------------------------------------------- */
263
rename_utf16(const char * oldname8,const char * newname8)264 int rename_utf16(const char* oldname8, const char* newname8)
265 {
266 int i = -1;
267 WCHAR * oldname16;
268 WCHAR * newname16;
269
270 oldname16 = utf8_to_utf16(oldname8);
271 if (oldname16)
272 {
273 newname16 = utf8_to_utf16(newname8);
274 if (newname16)
275 {
276 i = _wrename(oldname16, newname16);
277 free(oldname16);
278 }
279 free(newname16);
280 }
281 return i;
282 }
283
stat_utf16(const char * filename8,struct stat * buf)284 int stat_utf16(const char* filename8, struct stat* buf)
285 {
286 int i = -1;
287 struct _stat st;
288 WCHAR * filename16 = utf8_to_utf16(filename8);
289 if (filename16)
290 {
291 i = _wstat(filename16, &st);
292 free(filename16);
293 }
294
295 if (i == 0) {
296 /* FIXME: incompatible type 'struct _stat' and 'struct stat' in MinGW64 ? */
297 buf->st_dev = st.st_dev;
298 buf->st_ino = st.st_ino;
299 buf->st_mode = st.st_mode;
300 buf->st_nlink = st.st_nlink;
301 buf->st_uid = st.st_uid;
302 buf->st_gid = st.st_gid;
303 buf->st_rdev = st.st_rdev;
304 buf->st_size = st.st_size;
305 buf->st_atime = st.st_atime;
306 buf->st_mtime = st.st_mtime;
307 buf->st_ctime = st.st_ctime;
308 }
309
310 return i;
311 }
312
chdir_utf16(const char * filename8)313 int chdir_utf16(const char* filename8)
314 {
315 int i = -1;
316 WCHAR * filename16 = utf8_to_utf16(filename8);
317 if (filename16)
318 {
319 i = _wchdir(filename16);
320 free(filename16);
321 }
322 return i;
323 }
324
open_utf16(const char * filename8,int flags,int mode)325 int open_utf16(const char* filename8, int flags, int mode)
326 {
327 int i = -1;
328 WCHAR * filename16 = utf8_to_utf16(filename8);
329 if (filename16)
330 {
331 i = _wopen(filename16, flags, mode);
332 free(filename16);
333 }
334 return i;
335 }
336
mkdir_utf16(const char * filename8)337 int mkdir_utf16(const char* filename8)
338 {
339 int i = -1;
340 WCHAR * filename16 = utf8_to_utf16(filename8);
341 if (filename16)
342 {
343 i = _wmkdir(filename16);
344 free(filename16);
345 }
346 return i;
347 }
348
rmdir_utf16(const char * filename8)349 int rmdir_utf16(const char* filename8)
350 {
351 int i = -1;
352 WCHAR * filename16 = utf8_to_utf16(filename8);
353 if (filename16)
354 {
355 i = _wrmdir(filename16);
356 free(filename16);
357 }
358 return i;
359 }
360
unlink_utf16(const char * filename8)361 int unlink_utf16(const char* filename8)
362 {
363 int i = -1;
364 WCHAR * filename16 = utf8_to_utf16(filename8);
365 if (filename16)
366 {
367 i = _wunlink(filename16);
368 free(filename16);
369 }
370 return i;
371 }
372
opendir_utf16(const char * dirname8)373 _WDIR * opendir_utf16(const char* dirname8)
374 {
375 _WDIR * dir = NULL;
376 WCHAR * dirname16 = utf8_to_utf16(dirname8);
377 if (dirname16)
378 {
379 dir = _wopendir(dirname16);
380 free(dirname16);
381 }
382 return dir;
383 }
384
385 /* eof */
386