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