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