1 /**
2 * \file win32.c
3 * \brief Miscellaneous utility functions for Windows.
4 *
5 * Copyright (C) 2003-2016 Meltytech, LLC
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <errno.h>
23 #include <time.h>
24 #include <windows.h>
25 #include <pthread.h>
26
27 #include <iconv.h>
28 #include <locale.h>
29 #include <ctype.h>
30 #include <stdio.h>
31 #include "../framework/mlt_properties.h"
32 #include "../framework/mlt_log.h"
33
usleep(unsigned int useconds)34 int usleep(unsigned int useconds)
35 {
36 HANDLE timer;
37 LARGE_INTEGER due;
38
39 due.QuadPart = -(10 * (__int64)useconds);
40
41 timer = CreateWaitableTimer(NULL, TRUE, NULL);
42 SetWaitableTimer(timer, &due, 0, NULL, NULL, 0);
43 WaitForSingleObject(timer, INFINITE);
44 CloseHandle(timer);
45 return 0;
46 }
47
48
nanosleep(const struct timespec * rqtp,struct timespec * rmtp)49 int nanosleep( const struct timespec * rqtp, struct timespec * rmtp )
50 {
51 if (rqtp->tv_nsec > 999999999) {
52 /* The time interval specified 1,000,000 or more microseconds. */
53 errno = EINVAL;
54 return -1;
55 }
56 return usleep( rqtp->tv_sec * 1000000 + rqtp->tv_nsec / 1000 );
57 }
58
setenv(const char * name,const char * value,int overwrite)59 int setenv(const char *name, const char *value, int overwrite)
60 {
61 int result = 1;
62 if (overwrite == 0 && getenv (name)) {
63 result = 0;
64 } else {
65 result = SetEnvironmentVariable (name,value);
66 }
67
68 return result;
69 }
70
iconv_from_utf8(mlt_properties properties,const char * prop_name,const char * prop_name_out,const char * encoding)71 static int iconv_from_utf8( mlt_properties properties, const char *prop_name, const char *prop_name_out, const char* encoding )
72 {
73 char *text = mlt_properties_get( properties, prop_name );
74 int result = 0;
75
76 if ( text ) {
77 iconv_t cd = iconv_open( encoding, "UTF-8" );
78 if ( cd != (iconv_t) -1 ) {
79 size_t inbuf_n = strlen( text );
80 size_t outbuf_n = inbuf_n * 6;
81 char *outbuf = mlt_pool_alloc( outbuf_n );
82 char *outbuf_p = outbuf;
83
84 memset( outbuf, 0, outbuf_n );
85
86 if ( text != NULL && strcmp( text, "" ) && iconv( cd, &text, &inbuf_n, &outbuf_p, &outbuf_n ) != -1 )
87 mlt_properties_set( properties, prop_name_out, outbuf );
88 else
89 mlt_properties_set( properties, prop_name_out, "" );
90
91 mlt_pool_release( outbuf );
92 result = iconv_close( cd );
93 } else {
94 result = -1;
95 }
96 }
97 return result;
98 }
99
iconv_to_utf8(mlt_properties properties,const char * prop_name,const char * prop_name_out,const char * encoding)100 static int iconv_to_utf8( mlt_properties properties, const char *prop_name, const char *prop_name_out, const char* encoding )
101 {
102 char *text = mlt_properties_get( properties, prop_name );
103 int result = 0;
104
105 if ( text ) {
106 iconv_t cd = iconv_open( "UTF-8", encoding );
107 if ( cd != (iconv_t) -1 ) {
108 size_t inbuf_n = strlen( text );
109 size_t outbuf_n = inbuf_n * 6;
110 char *outbuf = mlt_pool_alloc( outbuf_n );
111 char *outbuf_p = outbuf;
112
113 memset( outbuf, 0, outbuf_n );
114
115 if ( text != NULL && strcmp( text, "" ) && iconv( cd, &text, &inbuf_n, &outbuf_p, &outbuf_n ) != -1 )
116 mlt_properties_set( properties, prop_name_out, outbuf );
117 else
118 mlt_properties_set( properties, prop_name_out, "" );
119
120 mlt_pool_release( outbuf );
121 result = iconv_close( cd );
122 } else {
123 result = -1;
124 }
125 }
126 return result;
127 }
128
mlt_properties_from_utf8(mlt_properties properties,const char * prop_name,const char * prop_name_out)129 int mlt_properties_from_utf8( mlt_properties properties, const char *prop_name, const char *prop_name_out )
130 {
131 int result = -1;
132 UINT codepage = GetACP();
133
134 if ( codepage > 0 ) {
135 // numeric code page
136 char codepage_str[10];
137 snprintf( codepage_str, sizeof(codepage_str), "CP%u", codepage );
138 codepage_str[sizeof(codepage_str) - 1] = '\0';
139 result = iconv_from_utf8( properties, prop_name, prop_name_out, codepage_str );
140 }
141 if ( result < 0 ) {
142 result = mlt_properties_set( properties, prop_name_out,
143 mlt_properties_get( properties, prop_name ) );
144 mlt_log_warning( NULL, "iconv failed to convert \"%s\" from UTF-8 to code page %u: %s\n",
145 prop_name, codepage, mlt_properties_get( properties, prop_name ) );
146 }
147 return result;
148 }
149
mlt_properties_to_utf8(mlt_properties properties,const char * prop_name,const char * prop_name_out)150 int mlt_properties_to_utf8( mlt_properties properties, const char *prop_name, const char *prop_name_out )
151 {
152 int result = -1;
153 UINT codepage = GetACP();
154
155 if ( codepage > 0 ) {
156 // numeric code page
157 char codepage_str[10];
158 snprintf( codepage_str, sizeof(codepage_str), "CP%u", codepage );
159 codepage_str[sizeof(codepage_str) - 1] = '\0';
160 result = iconv_to_utf8( properties, prop_name, prop_name_out, codepage_str );
161 }
162 if ( result < 0 ) {
163 result = mlt_properties_set( properties, prop_name_out,
164 mlt_properties_get( properties, prop_name ) );
165 mlt_log_warning( NULL, "iconv failed to convert \"%s\" from code page %u to UTF-8\n", prop_name, codepage );
166 }
167 return result;
168 }
169
170 /* Adapted from g_win32_getlocale() - free() the result */
getlocale()171 char* getlocale()
172 {
173 LCID lcid;
174 LANGID langid;
175 char *ev;
176 int primary, sub;
177 char iso639[10];
178 char iso3166[10];
179 const char *script = "";
180 char result[33];
181
182 /* Let the user override the system settings through environment
183 * variables, as on POSIX systems.
184 */
185 if (((ev = getenv ("LC_ALL")) != NULL && ev[0] != '\0')
186 || ((ev = getenv ("LC_MESSAGES")) != NULL && ev[0] != '\0')
187 || ((ev = getenv ("LANG")) != NULL && ev[0] != '\0'))
188 return strdup (ev);
189
190 lcid = GetThreadLocale ();
191
192 if (!GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, sizeof (iso639)) ||
193 !GetLocaleInfo (lcid, LOCALE_SISO3166CTRYNAME, iso3166, sizeof (iso3166)))
194 return strdup ("C");
195
196 /* Strip off the sorting rules, keep only the language part. */
197 langid = LANGIDFROMLCID (lcid);
198
199 /* Split into language and territory part. */
200 primary = PRIMARYLANGID (langid);
201 sub = SUBLANGID (langid);
202
203 /* Handle special cases */
204 switch (primary)
205 {
206 case LANG_AZERI:
207 switch (sub)
208 {
209 case SUBLANG_AZERI_LATIN:
210 script = "@Latn";
211 break;
212 case SUBLANG_AZERI_CYRILLIC:
213 script = "@Cyrl";
214 break;
215 }
216 break;
217 case LANG_SERBIAN: /* LANG_CROATIAN == LANG_SERBIAN */
218 switch (sub)
219 {
220 case SUBLANG_SERBIAN_LATIN:
221 case 0x06: /* Serbian (Latin) - Bosnia and Herzegovina */
222 script = "@Latn";
223 break;
224 }
225 break;
226 case LANG_UZBEK:
227 switch (sub)
228 {
229 case SUBLANG_UZBEK_LATIN:
230 script = "@Latn";
231 break;
232 case SUBLANG_UZBEK_CYRILLIC:
233 script = "@Cyrl";
234 break;
235 }
236 break;
237 }
238 snprintf (result, sizeof(result), "%s_%s%s", iso639, iso3166, script);
239 result[sizeof(result) - 1] = '\0';
240 return strdup (result);
241 }
242
win32_fopen(const char * filename_utf8,const char * mode_utf8)243 FILE* win32_fopen(const char *filename_utf8, const char *mode_utf8)
244 {
245 // Convert UTF-8 to wide chars.
246 int n = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filename_utf8, -1, NULL, 0);
247 if (n > 0) {
248 wchar_t *filename_w = (wchar_t *) calloc(n, sizeof(wchar_t));
249 if (filename_w) {
250 int m = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, mode_utf8, -1, NULL, 0);
251 if (m > 0) {
252 wchar_t *mode_w = (wchar_t *) calloc(m, sizeof(wchar_t));
253 if (mode_w) {
254 MultiByteToWideChar(CP_UTF8, 0, filename_utf8, -1, filename_w, n);
255 MultiByteToWideChar(CP_UTF8, 0, mode_utf8, -1, mode_w, n);
256 FILE *fh = _wfopen(filename_w, mode_w);
257 free(filename_w);
258 if (fh)
259 return fh;
260 }
261 }
262 }
263 }
264 // Try with regular old fopen.
265 return fopen(filename_utf8, mode_utf8);
266 }
267