123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756 |
- #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;
- }
|