2 * Helper functions used by other modules
6 #define CONFIG "config.h"
20 #include "shared_globals.h"
24 * UCS2 <-> UTF-8 functions
25 * All functions use little endian UCS2 since we only need it to communicate with Windows via RPC
28 // Convert one character from UTF-8 to UCS2
29 // Returns 0xffff, if utf-8 evaluates to > 0xfffe (outside basic multilingual pane)
30 WCHAR
utf8_to_ucs2_char (const unsigned char *input
, const unsigned char **end_ptr
)
36 if (input
[0] < 0x80) {
38 return LE16(input
[0]);
41 if ((input
[0] & 0xE0) == 0xE0) {
43 if (input
[1] == 0 || input
[2] == 0)
49 LE16((input
[0] & 0x0F)<<12 |
50 (input
[1] & 0x3F)<<6 |
54 if ((input
[0] & 0xC0) == 0xC0) {
61 LE16((input
[0] & 0x1F)<<6 |
67 // Convert one character from UCS2 to UTF-8
68 // Returns length of UTF-8 char (1, 2 or 3) or -1 on error (UTF-16 outside UCS2)
69 // char *utf8 must be large enough to hold 3 bytes
70 int ucs2_to_utf8_char (const WCHAR ucs2_le
, char *utf8
)
72 const WCHAR ucs2
= LE16(ucs2_le
);
80 if (ucs2
>= 0x80 && ucs2
< 0x800) {
81 utf8
[0] = (ucs2
>> 6) | 0xC0;
82 utf8
[1] = (ucs2
& 0x3F) | 0x80;
87 if (ucs2
>= 0x800 && ucs2
< 0xFFFF) {
89 if (ucs2
>= 0xD800 && ucs2
<= 0xDFFF) {
90 /* Ill-formed (UTF-16 ouside of BMP) */
94 utf8
[0] = ((ucs2
>> 12) ) | 0xE0;
95 utf8
[1] = ((ucs2
>> 6 ) & 0x3F) | 0x80;
96 utf8
[2] = ((ucs2
) & 0x3F) | 0x80;
105 // Converts UTF8 to UCS2. Returns size in bytes of the converted string or -1 on error
106 size_t utf8_to_ucs2(WCHAR
* const ucs2_le
, const char* const utf8
, const size_t maxucs2
, const size_t maxutf8
)
108 const unsigned char* current_utf8
= (unsigned char*)utf8
;
109 WCHAR
* current_ucs2_le
= ucs2_le
;
111 for (; *current_utf8
; current_ucs2_le
++)
113 size_t size
= (char*)current_utf8
- utf8
;
115 if (size
>= maxutf8
) return (size_t)-1;
116 if (((*current_utf8
& 0xc0) == 0xc0) && (size
>= maxutf8
- 1)) return (size_t)-1;
117 if (((*current_utf8
& 0xe0) == 0xe0) && (size
>= maxutf8
- 2)) return (size_t)-1;
118 if (current_ucs2_le
- ucs2_le
>= (intptr_t)maxucs2
- 1) return (size_t)-1;
120 *current_ucs2_le
= utf8_to_ucs2_char(current_utf8
, ¤t_utf8
);
121 current_ucs2_le
[1] = 0;
123 if (*current_ucs2_le
== (WCHAR
)-1) return (size_t)-1;
125 return current_ucs2_le
- ucs2_le
;
128 // Converts UCS2 to UTF-8. Return TRUE or FALSE
129 BOOL
ucs2_to_utf8(const WCHAR
* const ucs2_le
, char* utf8
, size_t maxucs2
, size_t maxutf8
)
132 const WCHAR
* current_ucs2
= ucs2_le
;
133 unsigned int index_utf8
= 0;
135 for(*utf8
= 0; *current_ucs2
; current_ucs2
++)
137 if (current_ucs2
- ucs2_le
> (intptr_t)maxucs2
) return FALSE
;
138 int len
= ucs2_to_utf8_char(*current_ucs2
, utf8_char
);
139 if (index_utf8
+ len
> maxutf8
) return FALSE
;
140 strncat(utf8
, utf8_char
, len
);
147 /* End of UTF-8 <-> UCS2 conversion */
150 // Checks, whether a string is a valid integer number between min and max. Returns TRUE or FALSE. Puts int value in *value
151 BOOL
stringToInt(const char *const szValue
, const unsigned int min
, const unsigned int max
, unsigned int *const value
)
156 long long result
= strtoll(szValue
, &nextchar
, 10);
158 if (errno
|| result
< (long long)min
|| result
> (long long)max
|| *nextchar
)
163 *value
= (unsigned int)result
;
168 //Converts a String Guid to a host binary guid in host endianess
169 int_fast8_t string2Uuid(const char *const restrict input
, GUID
*const restrict guid
)
173 if (strlen(input
) < GUID_STRING_LENGTH
) return FALSE
;
174 if (input
[8] != '-' || input
[13] != '-' || input
[18] != '-' || input
[23] != '-') return FALSE
;
176 for (i
= 0; i
< GUID_STRING_LENGTH
; i
++)
178 if (i
== 8 || i
== 13 || i
== 18 || i
== 23) continue;
180 const char c
= toupper((int)input
[i
]);
182 if (c
< '0' || c
> 'F' || (c
> '9' && c
< 'A')) return FALSE
;
185 char inputCopy
[GUID_STRING_LENGTH
+ 1];
186 strncpy(inputCopy
, input
, GUID_STRING_LENGTH
+ 1);
187 inputCopy
[8] = inputCopy
[13] = inputCopy
[18] = 0;
189 hex2bin((BYTE
*)&guid
->Data1
, inputCopy
, 8);
190 hex2bin((BYTE
*)&guid
->Data2
, inputCopy
+ 9, 4);
191 hex2bin((BYTE
*)&guid
->Data3
, inputCopy
+ 14, 4);
192 hex2bin(guid
->Data4
, input
+ 19, 16);
194 guid
->Data1
= BE32(guid
->Data1
);
195 guid
->Data2
= BE16(guid
->Data2
);
196 guid
->Data3
= BE16(guid
->Data3
);
201 // convert GUID to little-endian
202 void LEGUID(GUID
*const restrict out
, const GUID
* const restrict in
)
204 #if __BYTE_ORDER != __LITTLE_ENDIAN
205 out
->Data1
= LE32(in
->Data1
);
206 out
->Data2
= LE16(in
->Data2
);
207 out
->Data3
= LE16(in
->Data3
);
208 memcpy(out
->Data4
, in
->Data4
, sizeof(out
->Data4
));
210 memcpy(out
, in
, sizeof(GUID
));
215 //Checks a command line argument if it is numeric and between min and max. Returns the numeric value or exits on error
216 __pure
unsigned int getOptionArgumentInt(const char o
, const unsigned int min
, const unsigned int max
)
220 if (!stringToInt(optarg
, min
, max
, &result
))
222 printerrorf("Fatal: Option \"-%c\" must be numeric between %u and %u.\n", o
, min
, max
);
230 // Resets getopt() to start parsing from the beginning
233 #if __minix__ || defined(__BSD__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
235 optreset
= 1; // Makes newer BSD getopt happy
236 #elif defined(__UCLIBC__) // uClibc headers also define __GLIBC__ so be careful here
237 optind
= 0; // uClibc seeks compatibility with GLIBC
238 #elif defined(__GLIBC__)
239 optind
= 0; // Makes GLIBC getopt happy
240 #else // Standard for most systems
246 #if defined(_WIN32) || defined(USE_MSRPC)
248 // Returns a static message buffer containing text for a given Win32 error. Not thread safe (same as strerror)
249 char* win_strerror(const int message
)
251 #define STRERROR_BUFFER_SIZE 256
252 static char buffer
[STRERROR_BUFFER_SIZE
];
254 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
| FORMAT_MESSAGE_MAX_WIDTH_MASK
, NULL
, message
, 0, buffer
, STRERROR_BUFFER_SIZE
, NULL
);
258 #endif // defined(_WIN32) || defined(USE_MSRPC)
262 * parses an address in the form host:[port] in addr
263 * returns host and port in seperate strings
265 void parseAddress(char *const addr
, char** szHost
, char** szPort
)
270 *szPort
= (char*)defaultport
;
273 # endif // NO_SOCKETS
275 char *lastcolon
= strrchr(addr
, ':');
276 char *firstcolon
= strchr(addr
, ':');
277 char *closingbracket
= strrchr(addr
, ']');
279 if (*addr
== '[' && closingbracket
) //Address in brackets
284 if (closingbracket
[1] == ':')
285 *szPort
= closingbracket
+ 2;
287 else if (firstcolon
&& firstcolon
== lastcolon
) //IPv4 address or hostname with port
290 *szPort
= firstcolon
+ 1;
295 // Initialize random generator (needs to be done in each thread)
296 void randomNumberInit()
299 gettimeofday(&tv
, NULL
);
300 srand((unsigned int)(tv
.tv_sec
^ tv
.tv_usec
));
304 // We always exit immediately if any OOM condition occurs
305 __noreturn
void OutOfMemory(void)
307 errorout("Fatal: Out of memory");
312 void* vlmcsd_malloc(size_t len
)
314 void* buf
= malloc(len
);
315 if (!buf
) OutOfMemory();
321 * Converts hex digits to bytes in big-endian order.
322 * Ignores any non-hex characters
324 void hex2bin(BYTE
*const bin
, const char *hex
, const size_t maxbin
)
326 static const char *const hexdigits
= "0123456789ABCDEF";
330 for (i
= 0; (i
< 16) && utf8_to_ucs2_char((const unsigned char*)hex
, (const unsigned char**)&nextchar
) != (WCHAR
)-1; hex
= nextchar
)
332 const char* pos
= strchr(hexdigits
, toupper((int)*hex
));
335 if (!(i
& 1)) bin
[i
>> 1] = 0;
336 bin
[i
>> 1] |= (char)(pos
- hexdigits
);
337 if (!(i
& 1)) bin
[i
>> 1] <<= 4;
339 if (i
>> 1 > maxbin
) break;
344 __pure BOOL
getArgumentBool(int_fast8_t *result
, const char *const argument
)
347 !strncasecmp(argument
, "true", 4) ||
348 !strncasecmp(argument
, "on", 2) ||
349 !strncasecmp(argument
, "yes", 3) ||
350 !strncasecmp(argument
, "1", 1)
357 !strncasecmp(argument
, "false", 5) ||
358 !strncasecmp(argument
, "off", 3) ||
359 !strncasecmp(argument
, "no", 2) ||
360 !strncasecmp(argument
, "0", 1)