2 * Helper functions used by other modules
5 #ifndef _CRT_SECURE_NO_WARNINGS
6 #define _CRT_SECURE_NO_WARNINGS
10 #define CONFIG "config.h"
20 #include "wingetopt.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
)
45 if (input
[0] < 0x80) {
47 return LE16(input
[0]);
50 if ((input
[0] & 0xE0) == 0xE0) {
52 if (input
[1] == 0 || input
[2] == 0)
58 LE16((input
[0] & 0x0F) << 12 |
59 (input
[1] & 0x3F) << 6 |
63 if ((input
[0] & 0xC0) == 0xC0) {
70 LE16((input
[0] & 0x1F) << 6 |
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
);
89 if (ucs2
>= 0x80 && ucs2
< 0x800) {
90 utf8
[0] = (ucs2
>> 6) | 0xC0;
91 utf8
[1] = (ucs2
& 0x3F) | 0x80;
96 if (ucs2
>= 0x800 && ucs2
< 0xFFFF) {
98 if (ucs2
>= 0xD800 && ucs2
<= 0xDFFF) {
99 /* Ill-formed (UTF-16 ouside of BMP) */
103 utf8
[0] = ((ucs2
>> 12)) | 0xE0;
104 utf8
[1] = ((ucs2
>> 6) & 0x3F) | 0x80;
105 utf8
[2] = ((ucs2
) & 0x3F) | 0x80;
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
, ¤t_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
)
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
);
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
)
165 long long result
= vlmcsd_strtoll(szValue
, &nextchar
, 10);
167 if (errno
|| result
< (long long)min
|| result
>(long long)max
|| *nextchar
)
172 *value
= (unsigned int)result
;
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
)
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
);
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
));
219 memcpy(out
, in
, sizeof(GUID
));
223 __pure
int IsEqualGuidLE(const GUID
*const restrict first
, const GUID
*const restrict second
)
225 # if __BYTE_ORDER != __LITTLE_ENDIAN
227 LEGUID(&guid
, first
);
228 return IsEqualGUID(&guid
, second
);
230 return IsEqualGUID(first
, second
);
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
)
240 if (!stringToInt(optarg
, min
, max
, &result
))
242 printerrorf("Fatal: Option \"-%c\" must be numeric between %u and %u.\n", o
, min
, max
);
249 // Resets getopt() to start parsing from the beginning
252 #if __minix__ || defined(__BSD__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
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
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
);
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
)
289 *szPort
= (char*)defaultport
;
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
303 if (closingbracket
[1] == ':')
304 *szPort
= closingbracket
+ 2;
306 else if (firstcolon
&& firstcolon
== lastcolon
) //IPv4 address or hostname with port
309 *szPort
= firstcolon
+ 1;
314 // Initialize random generator (needs to be done in each thread)
315 void randomNumberInit()
318 srand(GetTickCount());
321 gettimeofday(&tv
, NULL
);
322 srand((unsigned int)(tv
.tv_sec
^ tv
.tv_usec
));
327 // We always exit immediately if any OOM condition occurs
328 __noreturn
void OutOfMemory(void)
330 errorout("Fatal: Out of memory");
335 void* vlmcsd_malloc(size_t len
)
337 void* buf
= malloc(len
);
338 if (!buf
) OutOfMemory();
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";
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
));
358 if (!(i
& 1)) bin
[i
>> 1] = 0;
359 bin
[i
>> 1] |= (char)(pos
- hexdigits
);
360 if (!(i
& 1)) bin
[i
>> 1] <<= 4;
362 if (i
>> 1 > maxbin
) break;
367 __pure BOOL
getArgumentBool(int_fast8_t *result
, const char *const argument
)
370 !strncasecmp(argument
, "true", 4) ||
371 !strncasecmp(argument
, "on", 2) ||
372 !strncasecmp(argument
, "yes", 3) ||
373 !strncasecmp(argument
, "1", 1)
380 !strncasecmp(argument
, "false", 5) ||
381 !strncasecmp(argument
, "off", 3) ||
382 !strncasecmp(argument
, "no", 2) ||
383 !strncasecmp(argument
, "0", 1)
393 #if __ANDROID__ && !defined(USE_THREADS) // Bionic does not wrap these syscalls (intentionally because Google fears, developers don't know how to use it)
396 int shmget(key_t key
, size_t size
, int shmflg
)
398 return syscall(__NR_shmget
, key
, size
, shmflg
);
400 #endif // __NR_shmget
403 void *shmat(int shmid
, const void *shmaddr
, int shmflg
)
405 return (void *)syscall(__NR_shmat
, shmid
, shmaddr
, shmflg
);
410 int shmdt(const void *shmaddr
)
412 return syscall(__NR_shmdt
, shmaddr
);
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)