#include "wfassoc_utils.h" #pragma region WFString WFERROR WFString_Alloc_Wchar(WFString** strl, const wchar_t* raw_data) { if (raw_data == NULL) return WFERROR_NULLPTR; WFERROR ec; if ((ec = WFString_Alloc(strl)) != WFERROR_OK) return ec; if ((ec = WFString_SetData(*strl, raw_data)) != WFERROR_OK) return ec; return WFERROR_OK; } WFERROR WFString_Alloc_Char(WFString** strl, const char* raw_data, BOOL is_utf8) { if (raw_data == NULL) return WFERROR_NULLPTR; // init string WFERROR ec; if ((ec = WFString_Alloc(strl)) != WFERROR_OK) return ec; // compute expected string length uint32_t sourceLength = strlen(raw_data); int destLength = MultiByteToWideChar(is_utf8 ? CP_UTF8 : CP_ACP, 0, raw_data, sourceLength, NULL, 0); if (destLength <= 0) return WFERROR_CRT; --destLength; // remove terminal char // resize string if ((ec = WFString_Resize(*strl, destLength)) != WFERROR_OK) return ec; // clear buffer and write data wchar_t* buffer; if ((ec = WFString_GetData(*strl, &buffer)) != WFERROR_OK) return ec; memset(buffer, 0, sizeof(WCHAR) * destLength); int crt_error = MultiByteToWideChar(is_utf8 ? CP_UTF8 : CP_ACP, 0, raw_data, sourceLength, buffer, destLength); if (crt_error <= 0) return WFERROR_CRT; return WFERROR_OK; } WFERROR WFString_Alloc_Capacity(WFString** strl, uint32_t size) { *strl = WFNEW(WFString); if (*strl == NULL) return WFERROR_ALLOC; // init struct data (*strl)->mCapacity = size; (*strl)->mRealCapacity = size + 1; (*strl)->mLength = 0; (*strl)->mRealLength = 1; (*strl)->mRawData = malloc((*strl)->mRealCapacity * sizeof(wchar_t)); if ((*strl)->mRawData == NULL) return WFERROR_ALLOC; (*strl)->mRawData[(*strl)->mRealLength - 1] = 0; return WFERROR_OK; } WFERROR WFString_Alloc(WFString** strl) { return WFString_Alloc_Capacity(strl, 256); } WFERROR WFString_Free(WFString* strl) { if (strl == NULL) return WFERROR_OK; if (strl->mRawData == NULL) return WFERROR_NULLPTR; free(strl->mRawData); free(strl); return WFERROR_OK; } WFERROR WFString_Resize(WFString* strl, uint32_t new_size) { // if remain data is not enough, we need alloc new one if (new_size >= strl->mCapacity) { strl->mCapacity = new_size * 2; strl->mRealCapacity = strl->mCapacity + 1; // alloc buffer if (strl->mRawData != NULL) strl->mRawData = realloc(strl->mRawData, strl->mRealCapacity * sizeof(wchar_t)); else strl->mRawData = malloc(strl->mRealCapacity * sizeof(wchar_t)); if (strl->mRawData == NULL) return WFERROR_ALLOC; } // set length as new length strl->mLength = new_size; strl->mRealLength = strl->mLength + 1; // set the last one is zero strl->mRawData[strl->mRealLength - 1] = 0; return WFERROR_OK; } WFERROR WFString_GetData(WFString* strl, wchar_t** pdata) { if (strl == NULL) return WFERROR_NULLPTR; *pdata = strl->mRawData; return WFERROR_OK; } WFERROR WFString_SetData(WFString* strl, const wchar_t* data) { if (strl == NULL || data == NULL) return WFERROR_NULLPTR; // get length and resize buffer WFERROR ec; uint32_t size = wcslen(data); ec = WFString_Resize(strl, size); if (ec != WFERROR_OK) return ec; // copy data if (size != 0) memcpy(strl->mRawData, data, sizeof(wchar_t) * size); return WFERROR_OK; } WFERROR WFString_GetLength(WFString* strl, uint32_t* len) { if (strl == NULL) return WFERROR_NULLPTR; *len = strl->mLength; return WFERROR_OK; } WFERROR WFString_Printf(WFString* strl, const wchar_t* format, ...) { if (strl == NULL) return WFERROR_NULLPTR; // get expected size va_list argptr; va_start(argptr, format); uint32_t count = _vsnwprintf(NULL, 0, format, argptr); //count++; va_end(argptr); // resize string and get buffer ptr WFERROR ec; wchar_t* buffer; if ((ec = WFString_Resize(strl, count)) != WFERROR_OK) return ec; if ((ec = WFString_GetData(strl, &buffer)) != WFERROR_OK) return ec; // write data to buffer buffer[count - 1] = L'\0'; va_start(argptr, format); int write_result = _vsnwprintf(buffer, count, format, argptr); va_end(argptr); if (write_result < 0 || write_result >= count) return WFERROR_CRT; return WFERROR_OK; } WFERROR WFString_Concat_Wchar(WFString* strl, const wchar_t* extra) { if (strl == NULL) return WFERROR_NULLPTR; if (extra == NULL) return WFERROR_OK; uint32_t count = wcslen(extra); uint32_t oldlen = strl->mLength; // if extra strl count is 0, do not copy any data. if (count == 0) return WFERROR_OK; WFERROR ec; if ((ec = WFString_Resize(strl, oldlen + count)) != WFERROR_OK) return ec; memcpy(strl->mRawData + oldlen, extra, sizeof(wchar_t) * count); return WFERROR_OK; } WFERROR WFString_Concat_String(WFString* strl, WFString* extra) { if (strl == NULL) return WFERROR_NULLPTR; if (extra == NULL) return WFERROR_OK; return WFString_Concat_Wchar(strl, extra->mRawData); } WFERROR WFString_SubString(WFString* strl, WFString* substring, uint32_t start_index, uint32_t length) { if (strl == NULL) return WFERROR_NULLPTR; if (start_index >= strl->mLength || length > strl->mLength - start_index) return WFERROR_INVALID_ARGUMENTS; WFERROR ec; if ((ec = WFString_Resize(substring, length)) != WFERROR_OK) return ec; if (length != 0) { memcpy(substring->mRawData, strl->mRawData + start_index, sizeof(wchar_t) * length); } return WFERROR_OK; } #pragma endregion #pragma region WFLinkedList WFERROR WFLinkedList_Alloc(WFLinkedList** list) { *list = WFNEW(WFLinkedList); if (*list == NULL) return WFERROR_ALLOC; return WFERROR_OK; } WFERROR WFLinkedList_Free(WFLinkedList* list) { return WFLinkedList_Free_Full(list, NULL); } WFERROR WFLinkedList_Free_Full(WFLinkedList* list, WFLinkedListNode_FreeDataFunc free_func) { if (list == NULL) return WFERROR_OK; // iterate full list and remove data and node WFLinkedListNode* node = list->mHead, * free_node = NULL; while (node != NULL) { // free raw data if (free_func != NULL) (*free_func)(node->mRawData); // move to next node and free current node free_node = node; node = node->mNext; free(free_node); } // free list self free(list); return WFERROR_OK; } WFERROR WFLinkedList_Add(WFLinkedList* list, void* data) { if (list == NULL) return WFERROR_NULLPTR; WFLinkedListNode* new_item = WFNEW(WFLinkedListNode); if (new_item == NULL) return WFERROR_ALLOC; new_item->mNext = NULL; new_item->mRawData = data; if (list->mLength == 0) { list->mHead = list->mTail = new_item; } else { list->mTail->mNext = new_item; list->mTail = new_item; } ++list->mLength; return WFERROR_OK; } WFERROR WFLinkedList_NodeIterator(WFLinkedList* list, WFLinkedListNode** node_ptr) { if (list == NULL) return WFERROR_NULLPTR; if (*node_ptr == NULL) { // if node_ptr is NULL, it mean that wo should iterate this list from head *node_ptr = list->mHead; } else { // otherwise, move to next node *node_ptr = (*node_ptr)->mNext; } // if the header is null, return end of tail error to notice caller stop iterate if (*node_ptr == NULL) return WFERROR_END_OF_TAIL; else return WFERROR_OK; } WFERROR WFLinkedListNode_GetData(WFLinkedListNode* node, void** pdata) { if (node == NULL) return WFERROR_NULLPTR; *pdata = node->mRawData; return WFERROR_OK; } #pragma endregion