modified: openstmerge.py
[GalaxyCodeBases.git] / etc / Windows / vlmcsd / src / helpers.c
blob20df22ad28e52663080d7e9ed3d00eb017900ae3
1 /*
2 * Helper functions used by other modules
3 */
5 #ifndef _CRT_SECURE_NO_WARNINGS
6 #define _CRT_SECURE_NO_WARNINGS
7 #endif
9 #ifndef CONFIG
10 #define CONFIG "config.h"
11 #endif // CONFIG
12 #include CONFIG
14 #ifndef _WIN32
15 #include <errno.h>
16 #endif // _WIN32
17 #ifndef _MSC_VER
18 #include <getopt.h>
19 #else
20 #include "wingetopt.h"
21 #endif
22 #include <string.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include "helpers.h"
26 #include "output.h"
27 #include "endian.h"
28 #include "shared_globals.h"
33 * UCS2 <-> UTF-8 functions
34 * All functions use little endian UCS2 since we only need it to communicate with Windows via RPC
37 // Convert one character from UTF-8 to UCS2
38 // Returns 0xffff, if utf-8 evaluates to > 0xfffe (outside basic multilingual pane)
39 WCHAR utf8_to_ucs2_char(const unsigned char *input, const unsigned char **end_ptr)
41 *end_ptr = input;
42 if (input[0] == 0)
43 return ~0;
45 if (input[0] < 0x80) {
46 *end_ptr = input + 1;
47 return LE16(input[0]);
50 if ((input[0] & 0xE0) == 0xE0) {
52 if (input[1] == 0 || input[2] == 0)
53 return ~0;
55 *end_ptr = input + 3;
57 return
58 LE16((input[0] & 0x0F) << 12 |
59 (input[1] & 0x3F) << 6 |
60 (input[2] & 0x3F));
63 if ((input[0] & 0xC0) == 0xC0) {
64 if (input[1] == 0)
65 return ~0;
67 *end_ptr = input + 2;
69 return
70 LE16((input[0] & 0x1F) << 6 |
71 (input[1] & 0x3F));
73 return ~0;
76 // Convert one character from UCS2 to UTF-8
77 // Returns length of UTF-8 char (1, 2 or 3) or -1 on error (UTF-16 outside UCS2)
78 // char *utf8 must be large enough to hold 3 bytes
79 int ucs2_to_utf8_char(const WCHAR ucs2_le, char *utf8)
81 const WCHAR ucs2 = LE16(ucs2_le);
83 if (ucs2 < 0x80) {
84 utf8[0] = (char)ucs2;
85 utf8[1] = '\0';
86 return 1;
89 if (ucs2 >= 0x80 && ucs2 < 0x800) {
90 utf8[0] = (ucs2 >> 6) | 0xC0;
91 utf8[1] = (ucs2 & 0x3F) | 0x80;
92 utf8[2] = '\0';
93 return 2;
96 if (ucs2 >= 0x800 && ucs2 < 0xFFFF) {
98 if (ucs2 >= 0xD800 && ucs2 <= 0xDFFF) {
99 /* Ill-formed (UTF-16 ouside of BMP) */
100 return -1;
103 utf8[0] = ((ucs2 >> 12)) | 0xE0;
104 utf8[1] = ((ucs2 >> 6) & 0x3F) | 0x80;
105 utf8[2] = ((ucs2) & 0x3F) | 0x80;
106 utf8[3] = '\0';
107 return 3;
110 return -1;
114 // Converts UTF8 to UCS2. Returns size in bytes of the converted string or -1 on error
115 size_t utf8_to_ucs2(WCHAR* const ucs2_le, const char* const utf8, const size_t maxucs2, const size_t maxutf8)
117 const unsigned char* current_utf8 = (unsigned char*)utf8;
118 WCHAR* current_ucs2_le = ucs2_le;
120 for (; *current_utf8; current_ucs2_le++)
122 size_t size = (char*)current_utf8 - utf8;
124 if (size >= maxutf8) return (size_t)-1;
125 if (((*current_utf8 & 0xc0) == 0xc0) && (size >= maxutf8 - 1)) return (size_t)-1;
126 if (((*current_utf8 & 0xe0) == 0xe0) && (size >= maxutf8 - 2)) return (size_t)-1;
127 if (current_ucs2_le - ucs2_le >= (intptr_t)maxucs2 - 1) return (size_t)-1;
129 *current_ucs2_le = utf8_to_ucs2_char(current_utf8, &current_utf8);
130 current_ucs2_le[1] = 0;
132 if (*current_ucs2_le == (WCHAR)-1) return (size_t)-1;
134 return current_ucs2_le - ucs2_le;
137 // Converts UCS2 to UTF-8. Return TRUE or FALSE
138 BOOL ucs2_to_utf8(const WCHAR* const ucs2_le, char* utf8, size_t maxucs2, size_t maxutf8)
140 char utf8_char[4];
141 const WCHAR* current_ucs2 = ucs2_le;
142 unsigned int index_utf8 = 0;
144 for (*utf8 = 0; *current_ucs2; current_ucs2++)
146 if (current_ucs2 - ucs2_le > (intptr_t)maxucs2) return FALSE;
147 int len = ucs2_to_utf8_char(*current_ucs2, utf8_char);
148 if (index_utf8 + len > maxutf8) return FALSE;
149 strncat(utf8, utf8_char, len);
150 index_utf8 += len;
153 return TRUE;
156 /* End of UTF-8 <-> UCS2 conversion */
159 // Checks, whether a string is a valid integer number between min and max. Returns TRUE or FALSE. Puts int value in *value
160 BOOL stringToInt(const char *const szValue, const unsigned int min, const unsigned int max, unsigned int *const value)
162 char *nextchar;
164 errno = 0;
165 long long result = vlmcsd_strtoll(szValue, &nextchar, 10);
167 if (errno || result < (long long)min || result >(long long)max || *nextchar)
169 return FALSE;
172 *value = (unsigned int)result;
173 return TRUE;
177 //Converts a String Guid to a host binary guid in host endianess
178 int_fast8_t string2Uuid(const char *const restrict input, GUID *const restrict guid)
180 int i;
182 if (strlen(input) < GUID_STRING_LENGTH) return FALSE;
183 if (input[8] != '-' || input[13] != '-' || input[18] != '-' || input[23] != '-') return FALSE;
185 for (i = 0; i < GUID_STRING_LENGTH; i++)
187 if (i == 8 || i == 13 || i == 18 || i == 23) continue;
189 const char c = (char)toupper((int)input[i]);
191 if (c < '0' || c > 'F' || (c > '9' && c < 'A')) return FALSE;
194 char inputCopy[GUID_STRING_LENGTH + 1];
195 strncpy(inputCopy, input, GUID_STRING_LENGTH + 1);
196 inputCopy[8] = inputCopy[13] = inputCopy[18] = 0;
198 hex2bin((BYTE*)&guid->Data1, inputCopy, 8);
199 hex2bin((BYTE*)&guid->Data2, inputCopy + 9, 4);
200 hex2bin((BYTE*)&guid->Data3, inputCopy + 14, 4);
201 hex2bin(guid->Data4, input + 19, 16);
203 guid->Data1 = BE32(guid->Data1);
204 guid->Data2 = BE16(guid->Data2);
205 guid->Data3 = BE16(guid->Data3);
206 return TRUE;
210 // convert GUID to little-endian
211 void LEGUID(GUID *const restrict out, const GUID* const restrict in)
213 # if __BYTE_ORDER != __LITTLE_ENDIAN
214 out->Data1 = LE32(in->Data1);
215 out->Data2 = LE16(in->Data2);
216 out->Data3 = LE16(in->Data3);
217 memcpy(out->Data4, in->Data4, sizeof(out->Data4));
218 # else
219 memcpy(out, in, sizeof(GUID));
220 # endif
223 __pure int IsEqualGuidLE(const GUID *const restrict first, const GUID *const restrict second)
225 # if __BYTE_ORDER != __LITTLE_ENDIAN
226 GUID guid;
227 LEGUID(&guid, first);
228 return IsEqualGUID(&guid, second);
229 # else
230 return IsEqualGUID(first, second);
231 # endif
234 #if !IS_LIBRARY
235 //Checks a command line argument if it is numeric and between min and max. Returns the numeric value or exits on error
236 __pure unsigned int getOptionArgumentInt(const char o, const unsigned int min, const unsigned int max)
238 unsigned int result;
240 if (!stringToInt(optarg, min, max, &result))
242 printerrorf("Fatal: Option \"-%c\" must be numeric between %u and %u.\n", o, min, max);
243 exit(VLMCSD_EINVAL);
246 return result;
249 // Resets getopt() to start parsing from the beginning
250 void optReset(void)
252 #if __minix__ || defined(__BSD__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
253 optind = 1;
254 optreset = 1; // Makes newer BSD getopt happy
255 #elif defined(__UCLIBC__) // uClibc headers also define __GLIBC__ so be careful here
256 optind = 0; // uClibc seeks compatibility with GLIBC
257 #elif defined(__GLIBC__)
258 optind = 0; // Makes GLIBC getopt happy
259 #else // Standard for most systems
260 optind = 1;
261 #endif
263 #endif // !IS_LIBRARY
265 #if defined(_WIN32) || defined(USE_MSRPC)
267 // Returns a static message buffer containing text for a given Win32 error. Not thread safe (same as strerror)
268 char* win_strerror(const int message)
270 #define STRERROR_BUFFER_SIZE 256
271 static char buffer[STRERROR_BUFFER_SIZE];
273 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, message, 0, buffer, STRERROR_BUFFER_SIZE, NULL);
274 return buffer;
277 #endif // defined(_WIN32) || defined(USE_MSRPC)
281 * parses an address in the form host:[port] in addr
282 * returns host and port in seperate strings
284 void parseAddress(char *const addr, char** szHost, char** szPort)
286 *szHost = addr;
288 # ifndef NO_SOCKETS
289 *szPort = (char*)defaultport;
290 # else // NO_SOCKETS
291 *szPort = "1688";
292 # endif // NO_SOCKETS
294 char *lastcolon = strrchr(addr, ':');
295 char *firstcolon = strchr(addr, ':');
296 char *closingbracket = strrchr(addr, ']');
298 if (*addr == '[' && closingbracket) //Address in brackets
300 *closingbracket = 0;
301 (*szHost)++;
303 if (closingbracket[1] == ':')
304 *szPort = closingbracket + 2;
306 else if (firstcolon && firstcolon == lastcolon) //IPv4 address or hostname with port
308 *firstcolon = 0;
309 *szPort = firstcolon + 1;
314 // Initialize random generator (needs to be done in each thread)
315 void randomNumberInit()
317 # if _MSC_VER
318 srand(GetTickCount());
319 # else
320 struct timeval tv;
321 gettimeofday(&tv, NULL);
322 srand((unsigned int)(tv.tv_sec ^ tv.tv_usec));
323 # endif
327 // We always exit immediately if any OOM condition occurs
328 __noreturn void OutOfMemory(void)
330 errorout("Fatal: Out of memory");
331 exit(VLMCSD_ENOMEM);
335 void* vlmcsd_malloc(size_t len)
337 void* buf = malloc(len);
338 if (!buf) OutOfMemory();
339 return buf;
344 * Converts hex digits to bytes in big-endian order.
345 * Ignores any non-hex characters
347 void hex2bin(BYTE *const bin, const char *hex, const size_t maxbin)
349 static const char *const hexdigits = "0123456789ABCDEF";
350 char* nextchar;
351 size_t i;
353 for (i = 0; (i < 16) && utf8_to_ucs2_char((const unsigned char*)hex, (const unsigned char**)&nextchar) != (WCHAR)-1; hex = nextchar)
355 const char* pos = strchr(hexdigits, toupper((int)*hex));
356 if (!pos) continue;
358 if (!(i & 1)) bin[i >> 1] = 0;
359 bin[i >> 1] |= (char)(pos - hexdigits);
360 if (!(i & 1)) bin[i >> 1] <<= 4;
361 i++;
362 if (i >> 1 > maxbin) break;
367 __pure BOOL getArgumentBool(int_fast8_t *result, const char *const argument)
369 if (
370 !strncasecmp(argument, "true", 4) ||
371 !strncasecmp(argument, "on", 2) ||
372 !strncasecmp(argument, "yes", 3) ||
373 !strncasecmp(argument, "1", 1)
376 *result = TRUE;
377 return TRUE;
379 else if (
380 !strncasecmp(argument, "false", 5) ||
381 !strncasecmp(argument, "off", 3) ||
382 !strncasecmp(argument, "no", 2) ||
383 !strncasecmp(argument, "0", 1)
386 *result = FALSE;
387 return TRUE;
390 return FALSE;
393 #if __ANDROID__ && !defined(USE_THREADS) // Bionic does not wrap these syscalls (intentionally because Google fears, developers don't know how to use it)
395 #ifdef __NR_shmget
396 int shmget(key_t key, size_t size, int shmflg)
398 return syscall(__NR_shmget, key, size, shmflg);
400 #endif // __NR_shmget
402 #ifdef __NR_shmat
403 void *shmat(int shmid, const void *shmaddr, int shmflg)
405 return (void *)syscall(__NR_shmat, shmid, shmaddr, shmflg);
407 #endif // __NR_shmat
409 #ifdef __NR_shmdt
410 int shmdt(const void *shmaddr)
412 return syscall(__NR_shmdt, shmaddr);
414 #endif // __NR_shmdt
416 #ifdef __NR_shmctl
417 int shmctl(int shmid, int cmd, /*struct shmid_ds*/void *buf)
419 return syscall(__NR_shmctl, shmid, cmd, buf);
421 #endif // __NR_shmctl
423 #endif // __ANDROID__ && !defined(USE_THREADS)