diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/replicant/nx/win/nxstring.c | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/replicant/nx/win/nxstring.c')
-rw-r--r-- | Src/replicant/nx/win/nxstring.c | 756 |
1 files changed, 756 insertions, 0 deletions
diff --git a/Src/replicant/nx/win/nxstring.c b/Src/replicant/nx/win/nxstring.c new file mode 100644 index 00000000..fca479e2 --- /dev/null +++ b/Src/replicant/nx/win/nxstring.c @@ -0,0 +1,756 @@ +#include "nxstring.h" +#include "foundation/error.h" +#include <shlwapi.h> +#include "foundation/atomics.h" +#include <wchar.h> +#include <stdarg.h> +#include <stdio.h> +#include <assert.h> +#pragma comment(lib, "shlwapi.lib") + +//#define NX_STRING_STRICT_HEAP + +HANDLE string_heap = 0; + +int NXStringSetHeap(HANDLE _string_heap) +{ + if (!string_heap) + { + string_heap = _string_heap; + return NErr_Success; + } + else + { + return NErr_NoAction; + } +} + +// don't include null terminator here +static size_t NXStringMallocSize(size_t characters) +{ + /* TODO: overflow check? */ + const nx_string_t dummy=NULL; + size_t header = (size_t)&dummy->string[0] - (size_t)dummy; + return header + (characters+1) * sizeof(wchar_t); +} + +// don't include null terminator here +nx_string_t NXStringMalloc(size_t characters) +{ + if (!string_heap) + { + string_heap = GetProcessHeap(); + } + return NXStringMallocWithHeap(string_heap, characters); +} + +nx_string_t NXStringRealloc(nx_string_t str, size_t characters) +{ + nx_string_t new_str = (nx_string_t)HeapReAlloc(string_heap, 0, str, NXStringMallocSize(characters)); + // on failure, kick back the original block (TODO need to review this) + if (!new_str) + { + return str; + } + return new_str; +} + +nx_string_t NXStringMallocWithHeap(HANDLE heap, size_t characters) +{ +#ifdef NX_STRING_STRICT_HEAP + nx_string_t str; + size_t string_size = NXStringMallocSize(characters); + + size_t allocated_size = (string_size + 8191) & ~4095; + size_t offset = 4096 - (string_size & 4095); + size_t pages = allocated_size / 4096; + uint8_t *protect_start; + void *mem = VirtualAlloc(0, allocated_size, MEM_COMMIT, PAGE_READWRITE); + + if (!mem) + return 0; + + protect_start = (uint8_t *)mem + (pages-1)*4096; + VirtualProtect(protect_start, 4096, PAGE_NOACCESS, 0); + + str = (nx_string_t)((uint8_t *)mem + offset); + str->ref_count = 1; + str->len = characters; + return str; +#else + nx_string_t str = (nx_string_t)HeapAlloc(heap, 0, NXStringMallocSize(characters)); + if (str) + { + str->ref_count = 1; + str->len = characters; + } + return str; +#endif +} + +int NXStringFree(HANDLE heap, nx_string_t str) +{ +#ifdef NX_STRING_STRICT_HEAP + uint8_t *mem = (uint8_t *)((size_t)str & 4095); + VirtualProtect(mem, 4096, PAGE_NOACCESS, 0); + assert(_heapchk() == _HEAPOK); + return NErr_Success; +#else + if (HeapFree(heap, 0, str)) + { + return NErr_Success; + } + else + { + return NErr_Error; + } +#endif +} + +nx_string_t NXStringCreate(const wchar_t *str) +{ + size_t size; + nx_string_t nxstr; + + if (!str || (size_t)str <= 65536) + { + return 0; + } + + size = wcslen(str); + nxstr = NXStringMalloc(size); + if (nxstr) + { + memcpy(nxstr->string, str, size*sizeof(wchar_t)); + nxstr->string[size]=0; + } + return nxstr; +} + +int NXStringCreateEmpty(nx_string_t *new_string) +{ + nx_string_t nxstr = NXStringMalloc(0); + if (nxstr) + { + nxstr->string[0]=0; + *new_string = nxstr; + return NErr_Success; + } + else + { + return NErr_OutOfMemory; + } +} + +nx_string_t NXStringCreateWithHeap(HANDLE heap, const wchar_t *str) +{ + size_t size = wcslen(str); + nx_string_t nxstr = NXStringMallocWithHeap(heap, size); + if (nxstr) + { + memcpy(nxstr->string, str, size*sizeof(wchar_t)); + nxstr->string[size]=0; + } + return nxstr; +} + +nx_string_t NXStringCreateFromUTF8(const char *str) +{ + nx_string_t nxstr; + size_t size = MultiByteToWideChar(CP_UTF8, 0, str, -1, 0,0); + if (!size) + { + return 0; + } + + nxstr = NXStringMalloc(size-1); + if (nxstr) + { + if (!MultiByteToWideChar(CP_UTF8, 0, str, -1, nxstr->string, (int)size)) + { + NXStringFree(string_heap, nxstr); + return 0; + } + } + + return nxstr; +} + +int NXStringCreateWithUTF8(nx_string_t *new_value, const char *str) +{ + size_t size; + nx_string_t nxstr; + + if (!str) + { + return NErr_Empty; + } + + size = MultiByteToWideChar(CP_UTF8, 0, str, -1, 0,0); + if (!size) + { + return NErr_Error; + } + + nxstr = NXStringMalloc(size-1); + if (!nxstr) + { + return NErr_OutOfMemory; + } + + if (!MultiByteToWideChar(CP_UTF8, 0, str, -1, nxstr->string, (int)size)) + { + NXStringFree(string_heap, nxstr); + return NErr_Error; + } + + *new_value = nxstr; + return NErr_Success; +} + +int NXStringCreateWithUTF16(nx_string_t *new_value, const wchar_t *str) +{ + size_t size; + nx_string_t nxstr; + + if (!str) + { + return NErr_Empty; + } + + size = wcslen(str); + nxstr = NXStringMalloc(size); + if (!nxstr) + { + return NErr_OutOfMemory; + } + + memcpy(nxstr->string, str, size*sizeof(wchar_t)); + nxstr->string[size]=0; + *new_value = nxstr; + return NErr_Success; +} + +int NXStringCreateWithCString(nx_string_t *new_value, const char *str, nx_charset_t charset) +{ + nx_string_t nxstr; + size_t size = MultiByteToWideChar(charset, 0, str, -1, 0,0); + if (!size) + { + return NErr_Error; + } + + nxstr = NXStringMalloc(size-1); + if (!nxstr) + { + return NErr_OutOfMemory; + } + + if (!MultiByteToWideChar(charset, 0, str, -1, nxstr->string, (int)size)) + { + NXStringFree(string_heap, nxstr); + return NErr_Error; + } + + *new_value = nxstr; + return NErr_Success; +} + +nx_string_t NXStringRetain(nx_string_t string) +{ + if (!string) + { + return 0; + } + + nx_atomic_inc(&string->ref_count); + return string; +} + +void NXStringRelease(nx_string_t string) +{ + if (string) + { + if (nx_atomic_dec(&string->ref_count) == 0) + { + NXStringFree(string_heap, string); + } + } +} + +nx_string_t NXStringCreateFromPath(const wchar_t *folder, const wchar_t *filename) +{ + nx_string_t pathstr = NXStringMalloc(MAX_PATH); + if (pathstr) + { + PathCombineW(pathstr->string, folder, filename); + pathstr->len = wcslen(pathstr->string); + } + return pathstr; +} + +nx_string_t NXStringCreateFromUInt64(uint64_t value) +{ + nx_string_t intstr = NXStringMalloc(21); + if (intstr) + { + _ui64tow(value, intstr->string, 10); + intstr->len = wcslen(intstr->string); + } + return intstr; +} + +int NXStringCreateWithUInt64(nx_string_t *new_value, uint64_t value) +{ + nx_string_t intstr = NXStringMalloc(21); + if (!intstr) + { + return NErr_OutOfMemory; + } + + _ui64tow(value, intstr->string, 10); + intstr->len = wcslen(intstr->string); + *new_value = intstr; + return NErr_Success; +} + +int NXStringCreateWithInt64(nx_string_t *new_value, int64_t value) +{ + nx_string_t intstr = NXStringMalloc(21); + if (!intstr) + { + return NErr_OutOfMemory; + } + + _i64tow(value, intstr->string, 10); + intstr->len = wcslen(intstr->string); + *new_value = intstr; + return NErr_Success; +} + +int NXStringCreateWithBytes(nx_string_t *new_string, const void *data, size_t len, nx_charset_t charset) +{ + nx_string_t nxstr; + if (!len) + { + return NXStringCreateEmpty(new_string); + } + if (charset == nx_charset_utf16le) + { + nxstr = NXStringMalloc(len/2); + if (nxstr) + { + memcpy(nxstr->string, data, len); + nxstr->string[len/2]=0; + nxstr->len = len/2; + *new_string = nxstr; + return NErr_Success; + } + else + { + return NErr_OutOfMemory; + } + } + else if (charset == nx_charset_utf16be) + { + nxstr = NXStringMalloc(len/2); + if (nxstr) + { + LCMapString(LOCALE_INVARIANT, LCMAP_BYTEREV, (LPCWSTR)data, (int)len/2, nxstr->string, (int)len/2); + nxstr->string[len/2]=0; + nxstr->len = len/2; + *new_string = nxstr; + return NErr_Success; + } + else + { + return NErr_OutOfMemory; + } + } + else + { + int size = MultiByteToWideChar((UINT)charset, 0, (const char *)data, (int)len, 0, 0); + if (!size) + { + return NErr_Error; + } + + nxstr = NXStringMalloc(size); + if (nxstr) + { + if (!MultiByteToWideChar((UINT)charset, 0, (const char *)data, (int)len, nxstr->string, size)) + { + NXStringFree(string_heap, nxstr); + return NErr_Error; + } + nxstr->string[size]=0; + nxstr->len = size; + *new_string = nxstr; + return NErr_Success; + } + else + { + return NErr_OutOfMemory; + } + } +} + +size_t NXStringGetLength(nx_string_t string) +{ + return (string ? string->len : 0); +} + +/* --- Keyword (ASCII) comparison --- */ +int NXStringKeywordCompareWithCString(nx_string_t string, const char *compare_to) +{ + const wchar_t *src = string->string; + const char *dst = compare_to; + + int ret = 0 ; + + while( ! (ret = (int)((*src & ~0x20) - (*dst & ~0x20))) && *dst) + { + ++src, ++dst; + } + + if ( ret < 0 ) + { + ret = -1 ; + } + else if ( ret > 0 ) + { + ret = 1 ; + } + return( ret ); +} + +int NXStringKeywordCompare(nx_string_t string, nx_string_t compare_to) +{ + const wchar_t *src = string->string; + const wchar_t *dst = compare_to->string; + + int ret = 0 ; + + while( ! (ret = (int)((*src & ~0x20) - (*dst & ~0x20))) && *dst) + { + ++src, ++dst; + } + + if ( ret < 0 ) + { + ret = -1 ; + } + else if ( ret > 0 ) + { + ret = 1 ; + } + return( ret ); +} + +int NXStringKeywordCaseCompare(nx_string_t string, nx_string_t compare_to) +{ + const wchar_t *src = string->string; + const wchar_t *dst = compare_to->string; + + int ret = 0 ; + + while( ! (ret = (int)(*src - (wchar_t)*dst)) && *dst) + { + ++src, ++dst; + } + + if ( ret < 0 ) + { + ret = -1 ; + } + else if ( ret > 0 ) + { + ret = 1 ; + } + + return( ret ); +} + +int NXStringCreateBasePathFromFilename(nx_string_t filename, nx_string_t *basepath) +{ + nx_string_t nxstr; + size_t len = filename->len; + while (len && filename->string[len-1] != '\\' && filename->string[len-1] != '/') + { + len--; + } + + if (!len) + { + return NErr_Empty; + } + + nxstr = NXStringMalloc(len); + if (!nxstr) + { + return NErr_OutOfMemory; + } + + memcpy(nxstr->string, filename->string, sizeof(wchar_t)*len); + nxstr->string[len]=0; + *basepath = nxstr; + return NErr_Success; +} + +int NXStringGetCString(nx_string_t string, char *user_buffer, size_t user_buffer_length, const char **out_cstring, size_t *out_cstring_length) +{ + size_t size; + + /* TODO: error check this with large strings and small user_buffer_length sizes */ + if (!string) + { + return NErr_NullPointer; + } + + if (user_buffer_length == 0) + return NErr_Insufficient; + + size = WideCharToMultiByte(CP_ACP, 0, string->string, (int)string->len, user_buffer, (int)user_buffer_length-1, NULL, NULL); + if (size == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + size = user_buffer_length-1; + user_buffer[size]=0; + *out_cstring = user_buffer; + *out_cstring_length = (size_t)size; + return NErr_Success; +} + +int NXStringGetDoubleValue(nx_string_t string, double *value) +{ + if (!string) + return NErr_NullPointer; + + *value = wcstod(string->string, 0); + return NErr_Success; +} + +int NXStringGetBytesSize(size_t *byte_count, nx_string_t string, nx_charset_t charset, int flags) +{ + if (charset == nx_charset_utf16le) + { + if (flags & nx_string_get_bytes_size_null_terminate) + *byte_count = (string->len + 1)* sizeof(wchar_t); + else + *byte_count = string->len * sizeof(wchar_t); + return NErr_DirectPointer; + } + else + { + size_t size=0; + /*if (flags & nx_string_get_bytes_size_null_terminate) + size = WideCharToMultiByte(charset, 0, string->string, string->len, 0, 0, NULL, NULL); + else*/ + size = WideCharToMultiByte(charset, 0, string->string, (int)string->len, 0, 0, NULL, NULL); + + if (!size) + return NErr_Error; + + if (flags & nx_string_get_bytes_size_null_terminate) + *byte_count = size+1; + else + *byte_count = size; + + return NErr_Success; + } +} + +int NXStringGetBytesDirect(const void **bytes, size_t *length, nx_string_t string, nx_charset_t charset, int flags) +{ + if (charset == nx_charset_utf16le) + { + *bytes = string->string; + if (length) + { + if (flags & nx_string_get_bytes_size_null_terminate) + *length = (string->len+1) * sizeof(wchar_t); // TODO: overflow check + else + *length = string->len * sizeof(wchar_t); // TODO: overflow check + } + return NErr_Success; + } + else + { + return NErr_Error; + } + +} + +int NXStringGetBytes(size_t *bytes_copied, nx_string_t string, void *bytes, size_t length, nx_charset_t charset, int flags) +{ + if (charset == nx_charset_utf16le) + { + length/=2; + + if (flags & nx_string_get_bytes_size_null_terminate) + { + if (length == 0) + return NErr_Insufficient; + + length--; + } + + if (length > string->len) + length = string->len; + wmemcpy((wchar_t *)bytes, string->string, length); + + if (flags & nx_string_get_bytes_size_null_terminate) + ((wchar_t *)bytes)[length++]=0; + + if (bytes_copied) + *bytes_copied = length * 2; + return NErr_Success; + } + else + { + size_t size=0; + if (flags & nx_string_get_bytes_size_null_terminate) + { + size = WideCharToMultiByte(charset, 0, string->string, (int)string->len, (LPSTR)bytes, (int)length-1, NULL, NULL); + ((char *)bytes)[size]=0; + } + else + { + size = WideCharToMultiByte(charset, 0, string->string, (int)string->len, (LPSTR)bytes, (int)length, NULL, NULL); + } + + if (!size) + { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + if (flags & nx_string_get_bytes_size_null_terminate) + size = length-1; + else + size=length; + } + else + { + return NErr_Error; + } + } + + if (bytes_copied) + { + if (flags & nx_string_get_bytes_size_null_terminate) + { + if (size) + *bytes_copied = size+1; + else + *bytes_copied = length+1; + } + else + { + if (size) + *bytes_copied = size; + else + *bytes_copied = length; + } + } + return NErr_Success; + } +} + +int NXStringGetIntegerValue(nx_string_t string, int *value) +{ + *value = wcstol(string->string, 0, 10); + return NErr_Success; +} + +int NXStringGetGUIDValue(nx_string_t string, GUID *out_guid) +{ + /* TODO: it'd be nice if this was a bit more flexible on input, e.g. no dashes vs dashes */ + GUID guid = GUID_NULL; + size_t offset = 0; + int Data1, Data2, Data3; + int Data4[8] = {0}; + + for (;;) + { + if (string->string[offset] == '{') + { + offset++; + } + else if (string->string[offset] == ' ') + { + offset++; + } + else + { + break; + } + } + + //{ 0x1b3ca60c, 0xda98, 0x4826, { 0xb4, 0xa9, 0xd7, 0x97, 0x48, 0xa5, 0xfd, 0x73 } }; + swscanf( string->string, L"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + &Data1, &Data2, &Data3, Data4 + 0, Data4 + 1, + Data4 + 2, Data4 + 3, Data4 + 4, Data4 + 5, Data4 + 6, Data4 + 7 ); + + // Cross assign all the values + guid.Data1 = Data1; + guid.Data2 = Data2; + guid.Data3 = Data3; + guid.Data4[0] = Data4[0]; + guid.Data4[1] = Data4[1]; + guid.Data4[2] = Data4[2]; + guid.Data4[3] = Data4[3]; + guid.Data4[4] = Data4[4]; + guid.Data4[5] = Data4[5]; + guid.Data4[6] = Data4[6]; + guid.Data4[7] = Data4[7]; + + *out_guid = guid; + return NErr_Success; +} + +nx_compare_result NXStringCompare(nx_string_t string1, nx_string_t string2, nx_compare_options options) +{ + int compareFlags = 0; + + if (0 != (nx_compare_case_insensitive & options)) + { + compareFlags |= NORM_IGNORECASE; + } + return CompareString(LOCALE_USER_DEFAULT, compareFlags, string1->string, -1, string2->string, -1) - 2; +} + +int NXStringCreateWithFormatting(nx_string_t *new_string, const char *format, ...) +{ + size_t cch, ret; + char *temp = 0; + va_list v; + va_start(v, format); + + cch = _vscprintf(format, v); + if (cch == -1) + { + return NErr_Error; + } + + if (cch > 256) + { + temp = (char *)malloc(cch+1); + if (!temp) + { + return NErr_OutOfMemory; + } + vsprintf(temp, format, v); + + ret = NXStringCreateWithUTF8(new_string, temp); + free(temp); + } + else + { + temp = (char *)_malloca(cch+1); + if (!temp) + { + return NErr_OutOfMemory; + } + vsprintf(temp, format, v); + ret = NXStringCreateWithUTF8(new_string, temp); + } + va_end(v); + return (int)ret; +}
\ No newline at end of file |