diff options
Diffstat (limited to 'dep/CascLib/src/common')
-rw-r--r-- | dep/CascLib/src/common/Array.h | 33 | ||||
-rw-r--r-- | dep/CascLib/src/common/ArraySparse.h | 286 | ||||
-rw-r--r-- | dep/CascLib/src/common/Common.cpp | 127 | ||||
-rw-r--r-- | dep/CascLib/src/common/Common.h | 87 | ||||
-rw-r--r-- | dep/CascLib/src/common/Csv.cpp | 37 | ||||
-rw-r--r-- | dep/CascLib/src/common/Csv.h | 2 | ||||
-rw-r--r-- | dep/CascLib/src/common/Directory.cpp | 62 | ||||
-rw-r--r-- | dep/CascLib/src/common/Directory.h | 18 | ||||
-rw-r--r-- | dep/CascLib/src/common/FileStream.cpp | 32 | ||||
-rw-r--r-- | dep/CascLib/src/common/FileTree.cpp | 13 | ||||
-rw-r--r-- | dep/CascLib/src/common/FileTree.h | 10 | ||||
-rw-r--r-- | dep/CascLib/src/common/ListFile.cpp | 4 | ||||
-rw-r--r-- | dep/CascLib/src/common/Mime.cpp | 454 | ||||
-rw-r--r-- | dep/CascLib/src/common/Mime.h | 54 | ||||
-rw-r--r-- | dep/CascLib/src/common/Path.h | 95 | ||||
-rw-r--r-- | dep/CascLib/src/common/RootHandler.cpp | 2 | ||||
-rw-r--r-- | dep/CascLib/src/common/Sockets.cpp | 41 | ||||
-rw-r--r-- | dep/CascLib/src/common/Sockets.h | 2 |
18 files changed, 884 insertions, 475 deletions
diff --git a/dep/CascLib/src/common/Array.h b/dep/CascLib/src/common/Array.h index 832a230a8ed..b46f257e8a4 100644 --- a/dep/CascLib/src/common/Array.h +++ b/dep/CascLib/src/common/Array.h @@ -42,8 +42,11 @@ class CASC_ARRAY // Creates an array with a custom element size int Create(size_t ItemSize, size_t ItemCountMax) { + // Sanity check + assert(ItemCountMax != 0); + // Create the array - if ((m_pItemArray = CASC_ALLOC<BYTE>(ItemSize * ItemCountMax)) == NULL) + if((m_pItemArray = CASC_ALLOC<BYTE>(ItemSize * ItemCountMax)) == NULL) return ERROR_NOT_ENOUGH_MEMORY; m_ItemCountMax = ItemCountMax; @@ -58,7 +61,7 @@ class CASC_ARRAY void * pNewItems; // Try to enlarge the buffer, if needed - if (!EnlargeArray(m_ItemCount + NewItemCount, bEnlargeAllowed)) + if(!EnlargeArray(m_ItemCount + NewItemCount, bEnlargeAllowed)) return NULL; pNewItems = m_pItemArray + (m_ItemCount * m_ItemSize); @@ -75,7 +78,7 @@ class CASC_ARRAY void * pNewItem = Insert(NewItemCount, bEnlargeAllowed); // Copy the item(s) to the array, if any - if (pNewItem && NewItems) + if(pNewItem && NewItems) memcpy(pNewItem, NewItems, (NewItemCount * m_ItemSize)); return pNewItem; } @@ -108,7 +111,7 @@ class CASC_ARRAY m_ItemCount = CASCLIB_MAX(m_ItemCount, ItemIndex+1); // If we inserted an item past the current end, we need to clear the items in-between - if (pbNewItem > pbLastItem) + if(pbNewItem > pbLastItem) { memset(pbLastItem, 0, (pbNewItem - pbLastItem)); m_ItemCount = ItemIndex + 1; @@ -167,6 +170,24 @@ class CASC_ARRAY m_ItemCountMax = m_ItemCount = m_ItemSize = 0; } +#ifdef _DEBUG + size_t BytesAllocated() + { + return m_ItemCountMax * m_ItemSize; + } + + void Dump(const char * szFileName) + { + FILE * fp; + + if((fp = fopen(szFileName, "wb")) != NULL) + { + fwrite(m_pItemArray, m_ItemSize, m_ItemCount, fp); + fclose(fp); + } + } +#endif + protected: bool EnlargeArray(size_t NewItemCount, bool bEnlargeAllowed) @@ -179,7 +200,7 @@ class CASC_ARRAY assert(m_ItemCountMax != 0); // Shall we enlarge the table? - if (NewItemCount > m_ItemCountMax) + if(NewItemCount > m_ItemCountMax) { // Deny enlarge if not allowed if(bEnlargeAllowed == false) @@ -192,7 +213,7 @@ class CASC_ARRAY // Allocate new table NewItemArray = CASC_REALLOC(m_pItemArray, (ItemCountMax * m_ItemSize)); - if (NewItemArray == NULL) + if(NewItemArray == NULL) return false; // Set the new table size diff --git a/dep/CascLib/src/common/ArraySparse.h b/dep/CascLib/src/common/ArraySparse.h new file mode 100644 index 00000000000..eb7d478cf3e --- /dev/null +++ b/dep/CascLib/src/common/ArraySparse.h @@ -0,0 +1,286 @@ +/*****************************************************************************/ +/* ArraySparse.h Copyright (c) Ladislav Zezula 2022 */ +/*---------------------------------------------------------------------------*/ +/* This is somewhat more effective version of CASC_ARRAY, used for mapping */ +/* of uint32_t -> pointer. Works better when there are large gaps in seqs */ +/* of the source integers and when there is large gap at the beginning */ +/* of the array. */ +/* */ +/* This ofject works as multi-level table, where each byte from the mapping */ +/* integer is an index to the appropriate sub-table */ +/* */ +/* Example: Mapping of 11223344 -> POINTER */ +/* */ +/* The source uint_32_t is divided into 4 bytes. Each byte is an index to */ +/* the corresponding level-N sub-table */ +/* */ +/* [*] 0x11223344 -> {0x11, 0x22, 0x33, 0x44} */ +/* */ +/* 0x11 is the index to the level-0 table. Contains pointer to level-1 table */ +/* 0x22 is the index to the level-1 table. Contains pointer to level-2 table */ +/* 0x33 is the index to the level-2 table. Contains pointer to level-3 table */ +/* 0x44 is the index to the level-3 table. Contains the result POINTER */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 14.12.22 1.00 Lad Created */ +/*****************************************************************************/ + +#ifndef __CASC_SPARSE_ARRAY_H__ +#define __CASC_SPARSE_ARRAY_H__ + +//----------------------------------------------------------------------------- +// Structure of the 256-item sub-table. Each table item contains either +// pointer to the lower sub-table (if present) or the pointer to the target item + +struct CASC_ARRAY_256 +{ + CASC_ARRAY_256() + { + memset(Pointers, 0, sizeof(Pointers)); + } + + CASC_ARRAY_256 * GetLowerLevel(size_t nIndex) + { + return (CASC_ARRAY_256 *)(Pointers[nIndex & 0xFF]); + } + + CASC_ARRAY_256 ** SubTable(size_t ItemIndex, size_t nLevel) + { + // Calculate the bit shift for getting the level index + size_t nShift = 0x20 - (nLevel * 8); + size_t nIndex = (ItemIndex >> nShift) & 0xFF; + + // Return reference to the item + return (CASC_ARRAY_256 **)(&Pointers[nIndex]); + } + + void Reset(size_t nLevel) + { + CASC_ARRAY_256 * pLower; + + // For levels 0, 1, 2, free the sub-items, if any + if(nLevel < 3) + { + for(size_t i = 0; i < _countof(Pointers); i++) + { + if((pLower = GetLowerLevel(i)) != NULL) + { + pLower->Reset(nLevel + 1); + } + } + } + + // Set all pointers to NULL for level 3 + else + { + memset(Pointers, 0, sizeof(CASC_ARRAY_256)); + } + } + + void Free(size_t nLevel) + { + CASC_ARRAY_256 * pLower; + + // For levels 0, 1, 2, free the sub-items, if any + if(nLevel < 3) + { + for(size_t i = 0; i < _countof(Pointers); i++) + { + if((pLower = GetLowerLevel(i)) != NULL) + { + pLower->Free(nLevel + 1); + delete pLower; + } + } + } + + // Set all pointers to NULL + memset(Pointers, 0, sizeof(CASC_ARRAY_256)); + } + + void * Pointers[0x100]; +}; + +//----------------------------------------------------------------------------- +// Interface to the sparse array class + +class CASC_SPARSE_ARRAY +{ + public: + + CASC_SPARSE_ARRAY() + { + m_LevelsAllocated = 0; + m_ItemCount = 0; + m_pLevel0 = NULL; + } + + ~CASC_SPARSE_ARRAY() + { + Free(); + } + + // Creates an array with a custom element type + template<typename TYPE> + DWORD Create(size_t /* ItemCountMax */) + { + if((m_pLevel0 = new CASC_ARRAY_256()) != NULL) + { + m_LevelsAllocated++; + return ERROR_SUCCESS; + } + return ERROR_NOT_ENOUGH_MEMORY; + } + + // Returns pointer to the cell given index + void ** ItemAt(size_t ItemIndex) + { + CASC_ARRAY_256 * pLevelN; + + // The index must be 32-bit only + assert((DWORD)(ItemIndex) == ItemIndex); + + // Get the level-0 index + if((pLevelN = m_pLevel0) != NULL) + { + if((pLevelN = GetLowerLevelTable(pLevelN, ItemIndex, 1)) != NULL) + { + if((pLevelN = GetLowerLevelTable(pLevelN, ItemIndex, 2)) != NULL) + { + if((pLevelN = GetLowerLevelTable(pLevelN, ItemIndex, 3)) != NULL) + { + return &pLevelN->Pointers[ItemIndex & 0xFF]; + } + } + } + } + + // Not present + return NULL; + } + + // Inserts an item at a given index and returns pointer to its cell + void ** InsertAt(size_t ItemIndex) + { + CASC_ARRAY_256 * pLevelN; + + // The index must be 32-bit only + assert((DWORD)(ItemIndex) == ItemIndex); + + // Get the level-0 index + if((pLevelN = m_pLevel0) != NULL) + { + if((pLevelN = EnsureLowerLevelTable(pLevelN, ItemIndex, 1)) != NULL) + { + if((pLevelN = EnsureLowerLevelTable(pLevelN, ItemIndex, 2)) != NULL) + { + if((pLevelN = EnsureLowerLevelTable(pLevelN, ItemIndex, 3)) != NULL) + { + // Increment the max index and return the pointer to the appropriate cell + if(ItemIndex >= m_ItemCount) + m_ItemCount = ItemIndex + 1; + return &pLevelN->Pointers[ItemIndex & 0xFF]; + } + } + } + } + + // Not enough memory + return NULL; + } + + // Invalidates the entire array, but keeps memory allocated + void Reset() + { + if(m_pLevel0 != NULL) + { + m_pLevel0->Reset(0); + } + } + + // Frees the array + void Free() + { + if(m_pLevel0 != NULL) + { + m_pLevel0->Free(0); + delete m_pLevel0; + } + } + + size_t ItemCount() + { + return m_ItemCount; + } + + size_t ItemCountMax() + { + return 0xFFFFFFFF; + } + + size_t ItemSize() + { + return sizeof(void *); + } + + bool IsInitialized() + { + return (m_pLevel0 != NULL); + } + +#ifdef _DEBUG + size_t BytesAllocated() + { + return m_LevelsAllocated * sizeof(CASC_ARRAY_256); + } + + void Dump(const char * szFileName) + { + FILE * fp; + size_t * RefItem; + size_t Item; + + if((fp = fopen(szFileName, "wb")) != NULL) + { + for(size_t i = 0; i < m_ItemCount; i++) + { + RefItem = (size_t *)ItemAt(i); + Item = (RefItem != NULL) ? RefItem[0] : 0; + fwrite(&Item, ItemSize(), 1, fp); + } + fclose(fp); + } + } +#endif + + protected: + + CASC_ARRAY_256 * GetLowerLevelTable(CASC_ARRAY_256 * pTable, size_t ItemIndex, size_t nLevel) + { + CASC_ARRAY_256 ** SubTable = pTable->SubTable(ItemIndex, nLevel); + + // Get the n-th item from the table + return SubTable[0]; + } + + CASC_ARRAY_256 * EnsureLowerLevelTable(CASC_ARRAY_256 * pTable, size_t ItemIndex, size_t nLevel) + { + CASC_ARRAY_256 ** SubTable = pTable->SubTable(ItemIndex, nLevel); + + // Is there an item? + if(SubTable[0] == NULL) + { + SubTable[0] = new CASC_ARRAY_256(); + m_LevelsAllocated++; + } + return SubTable[0]; + } + + // Level-0 subitem table + CASC_ARRAY_256 * m_pLevel0; // Array of level 0 of pointers + size_t m_LevelsAllocated; // Number of CASC_ARRAY_256's allocated (for debugging purposes) + size_t m_ItemCount; // The number of items inserted +}; + +#endif // __CASC_SPARSE_ARRAY_H__ diff --git a/dep/CascLib/src/common/Common.cpp b/dep/CascLib/src/common/Common.cpp index ac06e8df53e..63fb4301d57 100644 --- a/dep/CascLib/src/common/Common.cpp +++ b/dep/CascLib/src/common/Common.cpp @@ -69,7 +69,7 @@ unsigned char AsciiToHexTable[128] = 0xFF, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; unsigned char IntToHexChar[] = "0123456789abcdef"; @@ -229,10 +229,10 @@ void CascStrCopy(char * szTarget, size_t cchTarget, const char * szSource, size_ { size_t cchToCopy; - if (cchTarget > 0) + if(cchTarget > 0) { // Make sure we know the length - if (cchSource == -1) + if(cchSource == -1) cchSource = strlen(szSource); cchToCopy = CASCLIB_MIN((cchTarget - 1), cchSource); @@ -246,10 +246,10 @@ void CascStrCopy(char * szTarget, size_t cchTarget, const wchar_t * szSource, si { size_t cchToCopy; - if (cchTarget > 0) + if(cchTarget > 0) { // Make sure we know the length - if (cchSource == -1) + if(cchSource == -1) cchSource = wcslen(szSource); cchToCopy = CASCLIB_MIN((cchTarget - 1), cchSource); @@ -262,10 +262,10 @@ void CascStrCopy(wchar_t * szTarget, size_t cchTarget, const char * szSource, si { size_t cchToCopy; - if (cchTarget > 0) + if(cchTarget > 0) { // Make sure we know the length - if (cchSource == -1) + if(cchSource == -1) cchSource = strlen(szSource); cchToCopy = CASCLIB_MIN((cchTarget - 1), cchSource); @@ -278,10 +278,10 @@ void CascStrCopy(wchar_t * szTarget, size_t cchTarget, const wchar_t * szSource, { size_t cchToCopy; - if (cchTarget > 0) + if(cchTarget > 0) { // Make sure we know the length - if (cchSource == -1) + if(cchSource == -1) cchSource = wcslen(szSource); cchToCopy = CASCLIB_MIN((cchTarget - 1), cchSource); @@ -293,46 +293,58 @@ void CascStrCopy(wchar_t * szTarget, size_t cchTarget, const wchar_t * szSource, //----------------------------------------------------------------------------- // Safe version of s(w)printf -size_t CascStrPrintf(char * buffer, size_t nCount, const char * format, ...) +size_t CascStrPrintfV(char * buffer, size_t nCount, const char * format, va_list argList) { char * buffend; - va_list argList; - // Start the argument list - va_start(argList, format); - #ifdef CASCLIB_PLATFORM_WINDOWS StringCchVPrintfExA(buffer, nCount, &buffend, NULL, 0, format, argList); -// buffend = buffer + vsnprintf(buffer, nCount, format, argList); #else buffend = buffer + vsnprintf(buffer, nCount, format, argList); #endif - - // End the argument list - va_end(argList); + return (buffend - buffer); } -size_t CascStrPrintf(wchar_t * buffer, size_t nCount, const wchar_t * format, ...) +size_t CascStrPrintf(char * buffer, size_t nCount, const char * format, ...) { - wchar_t * buffend; va_list argList; + size_t length; // Start the argument list va_start(argList, format); + length = CascStrPrintfV(buffer, nCount, format, argList); + va_end(argList); + + return length; +} + +size_t CascStrPrintfV(wchar_t * buffer, size_t nCount, const wchar_t * format, va_list argList) +{ + wchar_t * buffend; #ifdef CASCLIB_PLATFORM_WINDOWS StringCchVPrintfExW(buffer, nCount, &buffend, NULL, 0, format, argList); -// buffend = buffer + vswprintf(buffer, nCount, format, argList); #else buffend = buffer + vswprintf(buffer, nCount, format, argList); #endif - // End the argument list - va_end(argList); return (buffend - buffer); } +size_t CascStrPrintf(wchar_t * buffer, size_t nCount, const wchar_t * format, ...) +{ + va_list argList; + size_t length; + + // Start the argument list + va_start(argList, format); + length = CascStrPrintfV(buffer, nCount, format, argList); + va_end(argList); + + return length; +} + //----------------------------------------------------------------------------- // String allocation @@ -413,74 +425,7 @@ LPTSTR CascNewStrA2T(LPCSTR szString, size_t nCharsToReserve) } //----------------------------------------------------------------------------- -// String merging - -LPTSTR GetLastPathPart(LPTSTR szWorkPath) -{ - size_t nLength = _tcslen(szWorkPath); - - // Go one character back - if(nLength > 0) - nLength--; - - // Cut ending (back)slashes, if any - while(nLength > 0 && (szWorkPath[nLength] == _T('\\') || szWorkPath[nLength] == _T('/'))) - nLength--; - - // Cut the last path part - while(nLength > 0) - { - // End of path? - if(szWorkPath[nLength] == _T('\\') || szWorkPath[nLength] == _T('/')) - { - return szWorkPath + nLength; - } - - // Go one character back - nLength--; - } - - return NULL; -} - -bool CutLastPathPart(LPTSTR szWorkPath) -{ - // Get the last part of the path - szWorkPath = GetLastPathPart(szWorkPath); - if(szWorkPath == NULL) - return false; - - szWorkPath[0] = 0; - return true; -} - -size_t CombinePath(LPTSTR szBuffer, size_t nMaxChars, va_list argList) -{ - CASC_PATH<TCHAR> Path(PATH_SEP_CHAR); - LPCTSTR szFragment; - bool bWithSeparator = false; - - // Combine all parts of the path here - while((szFragment = va_arg(argList, LPTSTR)) != NULL) - { - Path.AppendString(szFragment, bWithSeparator); - bWithSeparator = true; - } - - return Path.Copy(szBuffer, nMaxChars); -} - -size_t CombinePath(LPTSTR szBuffer, size_t nMaxChars, ...) -{ - va_list argList; - size_t nLength; - - va_start(argList, nMaxChars); - nLength = CombinePath(szBuffer, nMaxChars, argList); - va_end(argList); - - return nLength; -} +// String normalization size_t NormalizeFileName(const unsigned char * NormTable, char * szNormName, const char * szFileName, size_t cchMaxChars) { diff --git a/dep/CascLib/src/common/Common.h b/dep/CascLib/src/common/Common.h index 3fbbf0d842c..5abc5c77b9a 100644 --- a/dep/CascLib/src/common/Common.h +++ b/dep/CascLib/src/common/Common.h @@ -124,7 +124,7 @@ typedef CASC_CKEY_ENTRY *PCASC_CKEY_ENTRY; extern unsigned char AsciiToLowerTable_Slash[256]; extern unsigned char AsciiToUpperTable_BkSlash[256]; -extern unsigned char AsciiToHexTable[0x80]; +extern unsigned char AsciiToHexTable[128]; extern unsigned char IntToHexChar[]; //----------------------------------------------------------------------------- @@ -186,7 +186,7 @@ inline DWORD Rol32(DWORD dwValue, DWORD dwRolCount) //----------------------------------------------------------------------------- // Big endian number manipulation -inline DWORD ConvertBytesToInteger_2(LPBYTE ValueAsBytes) +inline USHORT ConvertBytesToInteger_2(LPBYTE ValueAsBytes) { USHORT Value = 0; @@ -325,7 +325,9 @@ void CascStrCopy(wchar_t * szTarget, size_t cchTarget, const wchar_t * szSource, //----------------------------------------------------------------------------- // Safe version of s(w)printf +size_t CascStrPrintfV(char * buffer, size_t nCount, const char * format, va_list argList); size_t CascStrPrintf(char * buffer, size_t nCount, const char * format, ...); +size_t CascStrPrintfV(wchar_t * buffer, size_t nCount, const wchar_t * format, va_list argList); size_t CascStrPrintf(wchar_t * buffer, size_t nCount, const wchar_t * format, ...); //----------------------------------------------------------------------------- @@ -337,11 +339,6 @@ wchar_t * CascNewStr(const wchar_t * szString, size_t nCharsToReserve = 0); LPSTR CascNewStrT2A(LPCTSTR szString, size_t nCharsToReserve = 0); LPTSTR CascNewStrA2T(LPCSTR szString, size_t nCharsToReserve = 0); -size_t CombinePath(LPTSTR szBuffer, size_t nMaxChars, va_list argList); -size_t CombinePath(LPTSTR szBuffer, size_t nMaxChars, ...); -LPTSTR GetLastPathPart(LPTSTR szWorkPath); -bool CutLastPathPart(LPTSTR szWorkPath); - size_t NormalizeFileName_UpperBkSlash(char * szNormName, const char * szFileName, size_t cchMaxChars); size_t NormalizeFileName_LowerSlash(char * szNormName, const char * szFileName, size_t cchMaxChars); @@ -351,6 +348,12 @@ ULONGLONG CalcFileNameHash(const char * szFileName); //----------------------------------------------------------------------------- // String conversion functions +template <typename xchar> +bool IsHexadecimalDigit(xchar ch) +{ + return ((ch < sizeof(AsciiToHexTable)) && (AsciiToHexTable[ch] != 0xFF)); +} + template <typename xchar, typename INTXX> DWORD ConvertStringToInt(const xchar * szString, size_t nMaxDigits, INTXX & RefValue, const xchar ** PtrStringEnd = NULL) { @@ -448,34 +451,75 @@ xchar * StringFromBinary(LPBYTE pbBinary, size_t cbBinary, xchar * szBuffer) //----------------------------------------------------------------------------- // Structures for data blobs -struct QUERY_KEY +struct CASC_BLOB { - QUERY_KEY() + CASC_BLOB() { - pbData = NULL; - cbData = 0; + Reset(); } - ~QUERY_KEY() + ~CASC_BLOB() { - CASC_FREE(pbData); - cbData = 0; + Free(); + } + + void MoveFrom(CASC_BLOB & Source) + { + // Free current data, if any + Free(); + + // Take the source data + pbData = Source.pbData; + cbData = Source.cbData; + + // Reset the source data without freeing + Source.Reset(); } DWORD SetData(const void * pv, size_t cb) { - if((pbData = CASC_ALLOC<BYTE>(cb)) == NULL) + if(SetSize(cb) != ERROR_SUCCESS) return ERROR_NOT_ENOUGH_MEMORY; memcpy(pbData, pv, cb); + return ERROR_SUCCESS; + } + + DWORD SetSize(size_t cb) + { + Free(); + + // Always leave one extra byte for NUL character + if((pbData = CASC_ALLOC<BYTE>(cb + 1)) == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + cbData = cb; return ERROR_SUCCESS; } + void Reset() + { + pbData = NULL; + cbData = 0; + } + + void Free() + { + if(pbData != NULL) + CASC_FREE(pbData); + pbData = NULL; + cbData = 0; + } + + LPBYTE End() const + { + return pbData + cbData; + } + LPBYTE pbData; size_t cbData; }; -typedef QUERY_KEY *PQUERY_KEY; +typedef CASC_BLOB *PCASC_BLOB; //----------------------------------------------------------------------------- // File name utilities @@ -526,22 +570,11 @@ bool CascCheckWildCard(const char * szString, const char * szWildCard); //----------------------------------------------------------------------------- // Hashing functions -ULONGLONG HashStringJenkins(const char * szFileName); - bool CascIsValidMD5(LPBYTE pbMd5); void CascCalculateDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE md5_hash); bool CascVerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expected_md5); //----------------------------------------------------------------------------- -// Scanning a directory - -typedef bool (*INDEX_FILE_FOUND)(LPCTSTR szFileName, void * pvContext); - -bool DirectoryExists(LPCTSTR szDirectory); - -int ScanIndexDirectory(LPCTSTR szIndexPath, INDEX_FILE_FOUND pfnOnFileFound, void * pvContext); - -//----------------------------------------------------------------------------- // Argument structure versioning // Safely retrieves field value from a structure // intended for cases where users upgrade CascLib by simply dropping in a new .dll without recompiling their app diff --git a/dep/CascLib/src/common/Csv.cpp b/dep/CascLib/src/common/Csv.cpp index 589c711571a..ba333399479 100644 --- a/dep/CascLib/src/common/Csv.cpp +++ b/dep/CascLib/src/common/Csv.cpp @@ -42,7 +42,7 @@ static char * NextColumn_Default(void * /* pvUserData */, char * szColumn) szColumn++; // Terminate the column - if (szColumn[0] == '|') + if(szColumn[0] == '|') { *szColumn++ = 0; return szColumn; @@ -158,7 +158,6 @@ CASC_CSV::CASC_CSV(size_t nLinesMax, bool bHasHeader) m_pvUserData = NULL; m_szCsvFile = NULL; m_szCsvPtr = NULL; - m_nCsvFile = 0; m_nLines = 0; m_bHasHeader = bHasHeader; @@ -185,8 +184,9 @@ CASC_CSV::CASC_CSV(size_t nLinesMax, bool bHasHeader) CASC_CSV::~CASC_CSV() { if(m_pLines != NULL) + { delete[] m_pLines; - CASC_FREE(m_szCsvFile); + } } DWORD CASC_CSV::SetNextLineProc(CASC_CSV_NEXTPROC PfnNextLineProc, CASC_CSV_NEXTPROC PfnNextColProc, void * pvUserData) @@ -206,24 +206,18 @@ DWORD CASC_CSV::SetNextLineProc(CASC_CSV_NEXTPROC PfnNextLineProc, CASC_CSV_NEXT DWORD CASC_CSV::Load(LPCTSTR szFileName) { - DWORD cbFileData = 0; - DWORD dwErrCode = ERROR_SUCCESS; + DWORD dwErrCode; - m_szCsvFile = (char *)LoadFileToMemory(szFileName, &cbFileData); - if (m_szCsvFile != NULL) + dwErrCode = LoadFileToMemory(szFileName, CsvFile); + if(dwErrCode == ERROR_SUCCESS) { // Assign the data to the CSV object + m_szCsvFile = (char *)CsvFile.pbData; m_szCsvPtr = m_szCsvFile; - m_nCsvFile = cbFileData; // Parse the data dwErrCode = ParseCsvData() ? ERROR_SUCCESS : ERROR_BAD_FORMAT; } - else - { - dwErrCode = GetCascError(); - } - return dwErrCode; } @@ -231,19 +225,16 @@ DWORD CASC_CSV::Load(LPBYTE pbData, size_t cbData) { DWORD dwErrCode = ERROR_NOT_ENOUGH_MEMORY; - m_szCsvFile = CASC_ALLOC<char>(cbData + 1); - if (m_szCsvFile != NULL) + if((dwErrCode = CsvFile.SetData(pbData, cbData)) == ERROR_SUCCESS) { // Copy the entire data and terminate them with zero - memcpy(m_szCsvFile, pbData, cbData); - m_szCsvFile[cbData] = 0; + m_szCsvFile = (char *)CsvFile.pbData; + m_szCsvFile[CsvFile.cbData] = 0; m_szCsvPtr = m_szCsvFile; - m_nCsvFile = cbData; // Parse the data dwErrCode = ParseCsvData() ? ERROR_SUCCESS : ERROR_BAD_FORMAT; } - return dwErrCode; } @@ -303,7 +294,7 @@ bool CASC_CSV::LoadNextLine(CASC_CSV_LINE & Line) m_szCsvPtr = PfnNextLine(m_pvUserData, m_szCsvPtr); // Initialize the line - if (Line.SetLine(this, szCsvLine)) + if(Line.SetLine(this, szCsvLine)) return true; } @@ -320,7 +311,7 @@ bool CASC_CSV::ParseCsvData() if(m_bHasHeader) { // Load the current line to the header - if (!LoadNextLine(Header)) + if(!LoadNextLine(Header)) return false; // Initialize the hash table @@ -345,14 +336,14 @@ bool CASC_CSV::ParseCsvData() const CASC_CSV_COLUMN & CASC_CSV::operator[](const char * szColumnName) const { - if (m_pLines == NULL || m_nLines == 0) + if(m_pLines == NULL || m_nLines == 0) return NullColumn; return m_pLines[0][GetColumnIndex(szColumnName)]; } const CASC_CSV_LINE & CASC_CSV::operator[](size_t nIndex) const { - if (m_pLines == NULL || nIndex >= m_nLines) + if(m_pLines == NULL || nIndex >= m_nLines) return NullLine; return m_pLines[nIndex]; } diff --git a/dep/CascLib/src/common/Csv.h b/dep/CascLib/src/common/Csv.h index 8df99c63456..1878344b24c 100644 --- a/dep/CascLib/src/common/Csv.h +++ b/dep/CascLib/src/common/Csv.h @@ -113,11 +113,11 @@ class CASC_CSV CASC_CSV_LINE * m_pLines; CASC_CSV_LINE Header; + CASC_BLOB CsvFile; BYTE HashTable[CSV_HASH_TABLE_SIZE]; void * m_pvUserData; char * m_szCsvFile; char * m_szCsvPtr; - size_t m_nCsvFile; size_t m_nLinesMax; size_t m_nLines; bool m_bHasHeader; diff --git a/dep/CascLib/src/common/Directory.cpp b/dep/CascLib/src/common/Directory.cpp index efabda45171..cef7dfa6319 100644 --- a/dep/CascLib/src/common/Directory.cpp +++ b/dep/CascLib/src/common/Directory.cpp @@ -52,37 +52,47 @@ bool MakeDirectory(LPCTSTR szDirectory) #endif } -int ScanIndexDirectory( - LPCTSTR szIndexPath, - INDEX_FILE_FOUND pfnOnFileFound, +DWORD ScanDirectory( + LPCTSTR szDirectory, + DIRECTORY_CALLBACK PfnFolderCallback, + DIRECTORY_CALLBACK PfnFileCallback, void * pvContext) { #ifdef CASCLIB_PLATFORM_WINDOWS + CASC_PATH<TCHAR> SearchMask(szDirectory, _T("*"), NULL); WIN32_FIND_DATA wf; HANDLE hFind; - TCHAR szSearchMask[MAX_PATH]; - - // Prepare the search mask - CombinePath(szSearchMask, _countof(szSearchMask), szIndexPath, _T("*"), NULL); // Prepare directory search - hFind = FindFirstFile(szSearchMask, &wf); + hFind = FindFirstFile(SearchMask, &wf); if(hFind != INVALID_HANDLE_VALUE) { // Skip the first file as it's always just "." or ".." while(FindNextFile(hFind, &wf)) { - // If the found object is a file, pass it to the handler - if(!(wf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + // If we found a folder, we call the directory callback + if(wf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if(PfnFolderCallback != NULL) + { + if(!PfnFolderCallback(wf.cFileName, pvContext)) + break; + } + } + else { - // Let the callback scan the file name - pfnOnFileFound(wf.cFileName, pvContext); + if(PfnFileCallback != NULL) + { + if(!PfnFileCallback(wf.cFileName, pvContext)) + break; + } } } // Close the search handle FindClose(hFind); + return ERROR_SUCCESS; } #else // CASCLIB_PLATFORM_WINDOWS @@ -90,21 +100,39 @@ int ScanIndexDirectory( struct dirent * dir_entry; DIR * dir; - dir = opendir(szIndexPath); - if(dir != NULL) + // Prepare directory search + if((dir = opendir(szDirectory)) != NULL) { + // Read (the next) directory entry while((dir_entry = readdir(dir)) != NULL) { - if(dir_entry->d_type != DT_DIR) + if(dir_entry->d_type == DT_DIR) + { + if(PfnFolderCallback != NULL) + { + if(!PfnFolderCallback(dir_entry->d_name, pvContext)) + { + break; + } + } + } + else { - pfnOnFileFound(dir_entry->d_name, pvContext); + if(PfnFileCallback != NULL) + { + if(!PfnFileCallback(dir_entry->d_name, pvContext)) + { + break; + } + } } } closedir(dir); + return ERROR_SUCCESS; } #endif - return ERROR_SUCCESS; + return ERROR_PATH_NOT_FOUND; } diff --git a/dep/CascLib/src/common/Directory.h b/dep/CascLib/src/common/Directory.h index 30c7e384284..f2f0d5e4c65 100644 --- a/dep/CascLib/src/common/Directory.h +++ b/dep/CascLib/src/common/Directory.h @@ -14,13 +14,21 @@ //----------------------------------------------------------------------------- // Scanning a directory -bool DirectoryExists(LPCTSTR szDirectory); +// If the callback returns false, the directory enumeration stops +typedef bool (*DIRECTORY_CALLBACK)(LPCTSTR szPathName, void * pvContext); -bool MakeDirectory(LPCTSTR szDirectory); +bool DirectoryExists( + LPCTSTR szDirectory + ); + +bool MakeDirectory( + LPCTSTR szDirectory + ); -int ScanIndexDirectory( - LPCTSTR szIndexPath, - INDEX_FILE_FOUND pfnOnFileFound, +DWORD ScanDirectory( + LPCTSTR szDirectory, + DIRECTORY_CALLBACK PfnFolderCallback, // Can be NULL if the caller doesn't care about folders + DIRECTORY_CALLBACK PfnFileCallback, // Can be NULL if the caller doesn't care about files void * pvContext ); diff --git a/dep/CascLib/src/common/FileStream.cpp b/dep/CascLib/src/common/FileStream.cpp index 622af421a82..7151ca9f36d 100644 --- a/dep/CascLib/src/common/FileStream.cpp +++ b/dep/CascLib/src/common/FileStream.cpp @@ -672,20 +672,22 @@ static DWORD BaseHttp_ParseURL(TFileStream * pStream, LPCTSTR szFileName, int * static bool BaseHttp_Download(TFileStream * pStream) { + CASC_MIME_RESPONSE MimeResponse; + CASC_BLOB FileData; CASC_MIME Mime; const char * request_mask = "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: Keep-Alive\r\n\r\n"; char * server_response; char * fileName = pStream->Base.Socket.fileName; char request[0x100]; - size_t response_length = 0; size_t request_length = 0; - DWORD dwErrCode; + DWORD dwErrCode = ERROR_SUCCESS; // If we already have the data, it's success if(pStream->Base.Socket.fileData == NULL) { // Reset the file data length as well pStream->Base.Socket.fileDataLength = 0; + dwErrCode = ERROR_BAD_FORMAT; // Construct the request, either HTTP or Ribbit (https://wowdev.wiki/Ribbit). // Note that Ribbit requests don't start with slash @@ -698,31 +700,31 @@ static bool BaseHttp_Download(TFileStream * pStream) // Send the request and receive decoded response request_length = CascStrPrintf(request, _countof(request), request_mask, fileName, pStream->Base.Socket.hostName); - server_response = pStream->Base.Socket.pSocket->ReadResponse(request, request_length, &response_length); + server_response = pStream->Base.Socket.pSocket->ReadResponse(request, request_length, MimeResponse); if(server_response != NULL) { - // Check for non-zero data - if(response_length != 0) + // Decode the MIME document + if((dwErrCode = Mime.Load(server_response, MimeResponse)) == ERROR_SUCCESS) { - // Decode the MIME document - if((dwErrCode = Mime.Load(server_response, response_length)) == ERROR_SUCCESS) + // Move the data from MIME to HTTP stream + if((dwErrCode = Mime.GiveAway(FileData)) == ERROR_SUCCESS) { - // Move the data from MIME to HTTP stream - pStream->Base.Socket.fileData = Mime.GiveAway(&pStream->Base.Socket.fileDataLength); + pStream->Base.Socket.fileData = FileData.pbData; + pStream->Base.Socket.fileDataLength = FileData.cbData; + pStream->Base.Socket.fileDataPos = 0; + FileData.Reset(); } } - else - { - SetCascError(ERROR_BAD_FORMAT); - } // Free the buffer CASC_FREE(server_response); } } - // If we have data loaded, return true - return (pStream->Base.Socket.fileData != NULL); + // Process error codes + if(dwErrCode != ERROR_SUCCESS) + SetCascError(dwErrCode); + return (dwErrCode == ERROR_SUCCESS); } static bool BaseHttp_Open(TFileStream * pStream, LPCTSTR szFileName, DWORD dwStreamFlags) diff --git a/dep/CascLib/src/common/FileTree.cpp b/dep/CascLib/src/common/FileTree.cpp index 490698122e5..fa21863c5e9 100644 --- a/dep/CascLib/src/common/FileTree.cpp +++ b/dep/CascLib/src/common/FileTree.cpp @@ -177,7 +177,7 @@ bool CASC_FILE_TREE::RebuildNameMaps() if(NameMap.Create(nMaxItems, sizeof(ULONGLONG), FIELD_OFFSET(CASC_FILE_NODE, FileNameHash)) != ERROR_SUCCESS) return false; - // Reset the entire array, but keep the buffer allocated + // Reset the entire array, but buffers allocated FileDataIds.Reset(); // Parse all items and insert them to the map @@ -393,13 +393,22 @@ PCASC_FILE_NODE CASC_FILE_TREE::ItemAt(size_t nItemIndex) PCASC_FILE_NODE CASC_FILE_TREE::PathAt(char * szBuffer, size_t cchBuffer, size_t nItemIndex) { + PCASC_FILE_NODE * RefFileNode; PCASC_FILE_NODE pFileNode = NULL; // If we have FileDataId, then we need to enumerate the files by FileDataId if(FileDataIds.IsInitialized()) - pFileNode = *(PCASC_FILE_NODE *)FileDataIds.ItemAt(nItemIndex); + { + RefFileNode = (PCASC_FILE_NODE *)FileDataIds.ItemAt(nItemIndex); + if(RefFileNode != NULL) + { + pFileNode = *(PCASC_FILE_NODE *)FileDataIds.ItemAt(nItemIndex); + } + } else + { pFileNode = (PCASC_FILE_NODE)NodeTable.ItemAt(nItemIndex); + } // Construct the entire path PathAt(szBuffer, cchBuffer, pFileNode); diff --git a/dep/CascLib/src/common/FileTree.h b/dep/CascLib/src/common/FileTree.h index 38bc4e07e9f..69a2c15c496 100644 --- a/dep/CascLib/src/common/FileTree.h +++ b/dep/CascLib/src/common/FileTree.h @@ -82,6 +82,13 @@ class CASC_FILE_TREE // Retrieve the maximum FileDataId ever inserted DWORD GetNextFileDataId(); +#ifdef _DEBUG + void DumpFileDataIds(const char * szFileName) + { + FileDataIds.Dump(szFileName); + } +#endif + protected: PCASC_FILE_NODE InsertNew(PCASC_CKEY_ENTRY pCKeyEntry); @@ -95,7 +102,8 @@ class CASC_FILE_TREE CASC_ARRAY NodeTable; // Dynamic array that holds all CASC_FILE_NODEs CASC_ARRAY NameTable; // Dynamic array that holds all node names - CASC_ARRAY FileDataIds; // Dynamic array that maps FileDataId -> CASC_FILE_NODE + CASC_SPARSE_ARRAY FileDataIds; // Dynamic array that maps FileDataId -> CASC_FILE_NODE + //CASC_ARRAY FileDataIds; // Dynamic array that maps FileDataId -> CASC_FILE_NODE CASC_MAP NameMap; // Map of FileNameHash -> CASC_FILE_NODE size_t FileDataIdOffset; // If nonzero, this is the offset of the "FileDataId" field in the CASC_FILE_NODE diff --git a/dep/CascLib/src/common/ListFile.cpp b/dep/CascLib/src/common/ListFile.cpp index a91922cd9b1..4545ada62e9 100644 --- a/dep/CascLib/src/common/ListFile.cpp +++ b/dep/CascLib/src/common/ListFile.cpp @@ -303,14 +303,14 @@ LPBYTE ListFile_GetData(void * pvListFile, PDWORD PtrDataSize) DWORD cbData = 0; // Get data from the list file cache - if (pvListFile != NULL) + if(pvListFile != NULL) { pbData = (LPBYTE)pCache->pBegin; cbData = (DWORD)(pCache->pEnd - pCache->pBegin); } // Give the data to the caller - if (PtrDataSize != NULL) + if(PtrDataSize != NULL) PtrDataSize[0] = cbData; return pbData; } diff --git a/dep/CascLib/src/common/Mime.cpp b/dep/CascLib/src/common/Mime.cpp index faa3402d832..5aa7401ff24 100644 --- a/dep/CascLib/src/common/Mime.cpp +++ b/dep/CascLib/src/common/Mime.cpp @@ -37,45 +37,90 @@ static size_t DecodeValueInt32(const char * string, const char * string_end) return result; } -size_t CASC_MIME_HTTP::IsDataComplete(const char * response, size_t response_length, size_t * ptr_content_length) +static const char * GetContentLengthValue(const char * response, const char * end) { - const char * content_length_ptr; - const char * content_begin_ptr; + const char * ptr; - // Do not parse the HTTP response multiple times - if((http_flags & HTTP_HEADER_COMPLETE) == 0 && response_length > 8) + if((ptr = strstr(response, "Content-Length: ")) != NULL && ptr < end) + return ptr; + if((ptr = strstr(response, "content-length: ")) != NULL && ptr < end) + return ptr; + return NULL; +} + +bool CASC_MIME_RESPONSE::ParseResponse(const char * response, size_t length, bool final) +{ + const char * ptr; + + // Only parse the data if there was an increment + if(length > response_length) { - // Check the begin of the response - if(!strncmp(response, "HTTP/1.1", 8)) + // Set the header offset + header_offset = 0; + + // Check for the complete header + if(header_length == CASC_INVALID_SIZE_T) { - // Check if there's begin of the content - if((content_begin_ptr = strstr(response, "\r\n\r\n")) != NULL) + if((ptr = strstr(response, "\r\n\r\n")) != NULL) { - // HTTP responses contain "Content-Length: %u\n\r" - if((content_length_ptr = strstr(response, "Content-Length: ")) == NULL) - content_length_ptr = strstr(response, "content-length: "); - if(content_length_ptr != NULL) - { - // The content length info must be before the actual content - if(content_length_ptr < content_begin_ptr) - { - // Fill the HTTP info cache - content_offset = (content_begin_ptr + 4) - response; - content_length = DecodeValueInt32(content_length_ptr + 16, content_begin_ptr); - total_length = content_offset + content_length; - http_flags = HTTP_HEADER_COMPLETE; - } - } + header_length = (ptr - response) - header_offset; + content_offset = header_length + 4; } } + + // Determine the presence of the HTTP field + if(http_presence == FieldPresenceUnknown && header_length != CASC_INVALID_SIZE_T) + { + const char * http_ptr = (response + header_offset); + + if(!_strnicmp(http_ptr, "HTTP/1.1 ", 9)) + { + http_presence = FieldPresencePresent; + http_code = DecodeValueInt32(response + 9, response + 13); + } + else + { + http_presence = FieldPresenceNotPresent; + } + } + + // Determine the presence of content length + if(clength_presence == FieldPresenceUnknown && header_length != CASC_INVALID_SIZE_T) + { + const char * clength_ptr = GetContentLengthValue(response + header_offset, response + header_length); + + if(clength_ptr != NULL) + { + content_length = DecodeValueInt32(clength_ptr + 16, response + header_length); + clength_presence = FieldPresencePresent; + } + else + { + clength_presence = FieldPresenceNotPresent; + } + } + + // Update the length + response_length = length; + } + + // If this is a final response parsing we calculate the content length + if(content_length == CASC_INVALID_SIZE_T && final == true && (content_offset + 2) < length) + { + // The field must end with \r\n (0D 0A) + const char * end_ptr = (response + length - 2); + + // Is the MIME data terminated with "\r\n"? + if(end_ptr[0] == 0x0D && end_ptr[1] == 0x0A) + { + content_length = (response + length - 2) - (response + content_offset); + } } - // Update flags - if((http_flags & HTTP_HEADER_COMPLETE) && (ptr_content_length != NULL)) - ptr_content_length[0] = content_length; - if(total_length == response_length) - http_flags |= HTTP_DATA_COMPLETE; - return http_flags; + // Determine if we are finished or not + if(header_length != CASC_INVALID_SIZE_T && content_length != CASC_INVALID_SIZE_T) + return (length >= content_offset + content_length); + return false; } //----------------------------------------------------------------------------- @@ -141,33 +186,27 @@ CASC_MIME_ELEMENT::~CASC_MIME_ELEMENT() if(folder.pNext != NULL) delete folder.pNext; folder.pNext = NULL; - - // Free the data - if(data.begin != NULL) - CASC_FREE(data.begin); - data.begin = NULL; } -unsigned char * CASC_MIME_ELEMENT::GiveAway(size_t * ptr_data_length) +DWORD CASC_MIME_ELEMENT::GiveAway(CASC_BLOB & target) { - unsigned char * give_away_data = data.begin; - size_t give_away_length = data.length; - - // Clear the data (DO NOT FREE) - data.begin = NULL; - data.length = 0; + if(data.pbData && data.cbData) + { + target.MoveFrom(data); + return ERROR_SUCCESS; + } + return ERROR_HANDLE_EOF; +} - // Copy the data to local buffer - if(ptr_data_length != NULL) - ptr_data_length[0] = give_away_length; - return give_away_data; +DWORD CASC_MIME_ELEMENT::LoadSingle(char * data_ptr, size_t data_length) +{ + return data.SetData(data_ptr, data_length); } DWORD CASC_MIME_ELEMENT::Load(char * mime_data_begin, char * mime_data_end, const char * boundary_ptr) { CASC_MIME_ENCODING Encoding = MimeEncodingTextPlain; CASC_MIME_BLOB mime_data(mime_data_begin, mime_data_end); - CASC_MIME_HTTP HttpInfo; size_t length_begin; size_t length_end; char * mime_line; @@ -176,18 +215,6 @@ DWORD CASC_MIME_ELEMENT::Load(char * mime_data_begin, char * mime_data_end, cons DWORD dwErrCode = ERROR_SUCCESS; bool mime_version = false; - // Diversion for HTTP: No need to parse the entire headers and stuff. - // Just give the data right away - if(HttpInfo.IsDataComplete(mime_data_begin, (mime_data_end - mime_data_begin))) - { - if((data.begin = CASC_ALLOC<BYTE>(HttpInfo.content_length)) == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - memcpy(data.begin, mime_data_begin + HttpInfo.content_offset, HttpInfo.content_length); - data.length = HttpInfo.content_length; - return ERROR_SUCCESS; - } - // Reset the boundary boundary[0] = 0; @@ -298,9 +325,7 @@ DWORD CASC_MIME_ELEMENT::Load(char * mime_data_begin, char * mime_data_end, cons else { CASC_MIME_BLOB content(mime_data.ptr, NULL); - unsigned char * data_buffer; - size_t data_length = 0; - size_t raw_length; + CASC_BLOB data_buffer; // If we have boundary pointer, we need to cut the data up to the boundary end. // Otherwise, we decode the data to the end of the document @@ -323,47 +348,26 @@ DWORD CASC_MIME_ELEMENT::Load(char * mime_data_begin, char * mime_data_end, cons return ERROR_BAD_FORMAT; } - // Allocate buffer for decoded data. - // Make it the same size like source data plus zero at the end - raw_length = (content.end - content.ptr); - data_buffer = CASC_ALLOC<unsigned char>(raw_length); - if(data_buffer != NULL) + // Decode the data + switch(Encoding) { - // Decode the data - switch(Encoding) - { - case MimeEncodingTextPlain: - dwErrCode = DecodeTextPlain(content.ptr, content.end, data_buffer, &data_length); - break; + case MimeEncodingTextPlain: + dwErrCode = DecodeTextPlain(content.ptr, content.end, data); + break; - case MimeEncodingQuotedPrintable: - dwErrCode = DecodeQuotedPrintable(content.ptr, content.end, data_buffer, &data_length); - break; + case MimeEncodingQuotedPrintable: + dwErrCode = DecodeQuotedPrintable(content.ptr, content.end, data); + break; - case MimeEncodingBase64: - dwErrCode = DecodeBase64(content.ptr, content.end, data_buffer, &data_length); - break; + case MimeEncodingBase64: + dwErrCode = DecodeBase64(content.ptr, content.end, data); + break; - default:; - // to remove warning - } - - // If failed, free the buffer back - if(dwErrCode != ERROR_SUCCESS) - { - CASC_FREE(data_buffer); - data_buffer = NULL; - data_length = 0; - } - } - else - { - dwErrCode = ERROR_NOT_ENOUGH_MEMORY; + default: + dwErrCode = ERROR_NOT_SUPPORTED; + assert(false); + break; } - - // Put the data there, even if they are invalid - data.begin = data_buffer; - data.length = data_length; } } else @@ -400,15 +404,15 @@ void CASC_MIME_ELEMENT::Print(size_t nLevel, size_t nIndex) { char data_printable[0x20] = {0}; - for(size_t i = 0; (i < data.length && i < _countof(data_printable) - 1); i++) + for(size_t i = 0; (i < data.cbData && i < _countof(data_printable) - 1); i++) { - if(0x20 <= data.begin[i] && data.begin[i] <= 0x7F) - data_printable[i] = data.begin[i]; + if(0x20 <= data.pbData[i] && data.pbData[i] <= 0x7F) + data_printable[i] = data.pbData[i]; else data_printable[i] = '.'; } - printf("Data item (%u bytes): \"%s\"\n", (int)data.length, data_printable); + printf("Data item (%u bytes): \"%s\"\n", (int)data.cbData, data_printable); } // Do we have a next element? @@ -481,127 +485,124 @@ bool CASC_MIME_ELEMENT::ExtractBoundary(const char * line) return false; } -DWORD CASC_MIME_ELEMENT::DecodeTextPlain(char * content_begin, char * content_end, unsigned char * data_buffer, size_t * ptr_length) +DWORD CASC_MIME_ELEMENT::DecodeTextPlain(char * content_begin, char * content_end, CASC_BLOB & output) { - size_t data_length = (size_t)(content_end - content_begin); - - // Sanity checks - assert(content_begin && content_end); - assert(content_end > content_begin); - - // Plain copy - memcpy(data_buffer, content_begin, data_length); - - // Give the result - if(ptr_length != NULL) - ptr_length[0] = data_length; - return ERROR_SUCCESS; + return output.SetData(content_begin, (content_end - content_begin)); } -DWORD CASC_MIME_ELEMENT::DecodeQuotedPrintable(char * content_begin, char * content_end, unsigned char * data_buffer, size_t * ptr_length) +DWORD CASC_MIME_ELEMENT::DecodeQuotedPrintable(char * content_begin, char * content_end, CASC_BLOB & output) { - unsigned char * save_data_buffer = data_buffer; - char * content_ptr; DWORD dwErrCode; // Sanity checks assert(content_begin && content_end); assert(content_end > content_begin); - // Decode the data - for(content_ptr = content_begin; content_ptr < content_end; ) + // Allocate space for the output + if((dwErrCode = output.SetSize(content_end - content_begin)) == ERROR_SUCCESS) { - // If the data begins with '=', there is either newline or 2-char hexa number - if(content_ptr[0] == '=') + unsigned char * output_ptr = output.pbData; + char * content_ptr; + + // Decode the data + for(content_ptr = content_begin; content_ptr < content_end; ) { - // Is there a newline after the equal sign? - if(content_ptr[1] == 0x0D && content_ptr[2] == 0x0A) + // If the data begins with '=', there is either newline or 2-char hexa number + if(content_ptr[0] == '=') { + // Is there a newline after the equal sign? + if(content_ptr[1] == 0x0D && content_ptr[2] == 0x0A) + { + content_ptr += 3; + continue; + } + + // Is there hexa number after the equal sign? + dwErrCode = BinaryFromString(content_ptr + 1, 2, output_ptr); + if(dwErrCode != ERROR_SUCCESS) + return dwErrCode; + content_ptr += 3; + output_ptr++; continue; } - - // Is there hexa number after the equal sign? - dwErrCode = BinaryFromString(content_ptr + 1, 2, data_buffer); - if(dwErrCode != ERROR_SUCCESS) - return dwErrCode; - - content_ptr += 3; - data_buffer++; - continue; - } - else - { - *data_buffer++ = (unsigned char)(*content_ptr++); + else + { + *output_ptr++ = (unsigned char)(*content_ptr++); + } } - } - if(ptr_length != NULL) - ptr_length[0] = (size_t)(data_buffer - save_data_buffer); - return ERROR_SUCCESS; + // Set the real length + output.cbData = (size_t)(output_ptr - output.pbData); + } + return dwErrCode; } -DWORD CASC_MIME_ELEMENT::DecodeBase64(char * content_begin, char * content_end, unsigned char * data_buffer, size_t * ptr_length) +DWORD CASC_MIME_ELEMENT::DecodeBase64(char * content_begin, char * content_end, CASC_BLOB & output) { - unsigned char * save_data_buffer = data_buffer; + DWORD dwErrCode; DWORD BitBuffer = 0; DWORD BitCount = 0; BYTE OneByte; - // One time preparation of the conversion table - if(CascBase64ToBits[0] == 0) + if((dwErrCode = output.SetSize(content_end - content_begin)) == ERROR_SUCCESS) { - // Fill the entire table with 0xFF to mark invalid characters - memset(CascBase64ToBits, BASE64_INVALID_CHAR, sizeof(CascBase64ToBits)); - - // Set all whitespace characters - for(BYTE i = 1; i <= 0x20; i++) - CascBase64ToBits[i] = BASE64_WHITESPACE_CHAR; + unsigned char * output_ptr = output.pbData; - // Set all valid characters - for(BYTE i = 0; CascBase64Table[i] != 0; i++) + // One time preparation of the conversion table + if(CascBase64ToBits[0] == 0) { - OneByte = CascBase64Table[i]; - CascBase64ToBits[OneByte] = i; - } - } + // Fill the entire table with 0xFF to mark invalid characters + memset(CascBase64ToBits, BASE64_INVALID_CHAR, sizeof(CascBase64ToBits)); - // Do the decoding - while(content_begin < content_end && content_begin[0] != '=') - { - // Check for end of string - if(content_begin[0] > sizeof(CascBase64ToBits)) - return ERROR_BAD_FORMAT; - if((OneByte = CascBase64ToBits[*content_begin++]) == BASE64_INVALID_CHAR) - return ERROR_BAD_FORMAT; - if(OneByte == BASE64_WHITESPACE_CHAR) - continue; + // Set all whitespace characters + for(BYTE i = 1; i <= 0x20; i++) + CascBase64ToBits[i] = BASE64_WHITESPACE_CHAR; - // Put the 6 bits into the bit buffer - BitBuffer = (BitBuffer << 6) | OneByte; - BitCount += 6; + // Set all valid characters + for(BYTE i = 0; CascBase64Table[i] != 0; i++) + { + OneByte = CascBase64Table[i]; + CascBase64ToBits[OneByte] = i; + } + } - // Flush all values - while(BitCount >= 8) + // Do the decoding + while(content_begin < content_end && content_begin[0] != '=') { - // Decrement the bit count in the bit buffer - BitCount -= 8; + // Check for end of string + if(content_begin[0] > sizeof(CascBase64ToBits)) + return ERROR_BAD_FORMAT; + if((OneByte = CascBase64ToBits[*content_begin++]) == BASE64_INVALID_CHAR) + return ERROR_BAD_FORMAT; + if(OneByte == BASE64_WHITESPACE_CHAR) + continue; + + // Put the 6 bits into the bit buffer + BitBuffer = (BitBuffer << 6) | OneByte; + BitCount += 6; - // The byte is the upper 8 bits of the bit buffer - OneByte = (BYTE)(BitBuffer >> BitCount); - BitBuffer = BitBuffer % (1 << BitCount); + // Flush all values + while(BitCount >= 8) + { + // Decrement the bit count in the bit buffer + BitCount -= 8; + + // The byte is the upper 8 bits of the bit buffer + OneByte = (BYTE)(BitBuffer >> BitCount); + BitBuffer = BitBuffer % (1 << BitCount); - // Put the byte value. The buffer can not overflow, - // because it is guaranteed to be equal to the length of the base64 string - *data_buffer++ = OneByte; + // Put the byte value. The buffer can not overflow, + // because it is guaranteed to be equal to the length of the base64 string + *output_ptr++ = OneByte; + } } - } - // Return the decoded length - if(ptr_length != NULL) - ptr_length[0] = (data_buffer - save_data_buffer); - return ERROR_SUCCESS; + // Set the decoded length + output.cbData = (output_ptr - output.pbData); + } + return dwErrCode; } //----------------------------------------------------------------------------- @@ -613,62 +614,57 @@ CASC_MIME::CASC_MIME() CASC_MIME::~CASC_MIME() {} -unsigned char * CASC_MIME::GiveAway(size_t * ptr_data_length) +DWORD CASC_MIME::GiveAway(CASC_BLOB & target) { - CASC_MIME_ELEMENT * pElement = &root; - unsigned char * data; + CASC_MIME_ELEMENT * pElement; // 1) Give the data from the root - if((data = root.GiveAway(ptr_data_length)) != NULL) - return data; + if(root.GiveAway(target) == ERROR_SUCCESS) + return ERROR_SUCCESS; // 2) If we have children, then give away from the first child - pElement = root.GetChild(); - if(pElement && (data = pElement->GiveAway(ptr_data_length)) != NULL) - return data; - - // Return NULL - if(ptr_data_length != NULL) - ptr_data_length[0] = 0; - return NULL; -} + if((pElement = root.GetChild()) != NULL) + return pElement->GiveAway(target); -DWORD CASC_MIME::Load(char * data, size_t length) -{ - // Clear the root element - memset(&root, 0, sizeof(CASC_MIME_ELEMENT)); - - //FILE * fp = fopen("E:\\html_response.txt", "wb"); - //if(fp != NULL) - //{ - // fwrite(data, 1, length, fp); - // fclose(fp); - //} - - // Load the root element - return root.Load(data, data + length); + return ERROR_CAN_NOT_COMPLETE; } -DWORD CASC_MIME::Load(LPCTSTR szFileName) +DWORD CASC_MIME::Load(char * data, CASC_MIME_RESPONSE & MimeResponse) { - char * szFileData; - DWORD cbFileData = 0; - DWORD dwErrCode = ERROR_SUCCESS; + // Avoid parsing empty responses + if(MimeResponse.response_length == 0) + return ERROR_BAD_FORMAT; + if(MimeResponse.header_offset == CASC_INVALID_SIZE_T || MimeResponse.header_length == CASC_INVALID_SIZE_T) + return ERROR_BAD_FORMAT; + if(MimeResponse.content_offset == CASC_INVALID_SIZE_T || MimeResponse.content_offset == 0) + return ERROR_BAD_FORMAT; + if(MimeResponse.content_length == CASC_INVALID_SIZE_T || MimeResponse.content_length == 0) + return ERROR_BAD_FORMAT; + + // Avoid parsing responses where the data are incomplete + // Example: http://level3.blizzard.com/tpr/wow/data/c6/50/c650c203d52b9e5bdcf1d4b2b8b5bd16.index + if(MimeResponse.response_length < (MimeResponse.content_offset + MimeResponse.content_length)) + return ERROR_BAD_FORMAT; + + // Debug: dump the MIME data to file +#ifdef _DEBUG + //CascDumpData("E:\\mime_raw_data.txt", data, MimeResponse.response_length); +#endif - // Note that LoadFileToMemory allocated one byte more and puts zero at the end - // Thus, we can treat it as zero-terminated string - szFileData = (char *)LoadFileToMemory(szFileName, &cbFileData); - if(szFileData != NULL) + // Special handling of HTTP responses + if(MimeResponse.http_presence == FieldPresencePresent) { - dwErrCode = Load(szFileData, cbFileData); - CASC_FREE(szFileData); - } - else - { - dwErrCode = GetCascError(); + // Avoid parsing of failed HTTP requests + if(MimeResponse.http_code != 200) + return ERROR_FILE_NOT_FOUND; + + // Directly setup the root item + return root.LoadSingle(data + MimeResponse.content_offset, MimeResponse.content_length); } - return dwErrCode; + // Load the root element + memset(&root, 0, sizeof(CASC_MIME_ELEMENT)); + return root.Load(data, data + MimeResponse.response_length); } #ifdef _DEBUG diff --git a/dep/CascLib/src/common/Mime.h b/dep/CascLib/src/common/Mime.h index dc7db517179..9142c33bfd3 100644 --- a/dep/CascLib/src/common/Mime.h +++ b/dep/CascLib/src/common/Mime.h @@ -16,7 +16,7 @@ #define MAX_LENGTH_BOUNDARY 128 -// Flags returned by CASC_MIME_HTTP::IsDataComplete() +// Flags returned by CASC_MIME_HTTP::GetHttpReplyFlags() #define HTTP_HEADER_COMPLETE 0x01 // HTML header is complete #define HTTP_DATA_COMPLETE 0x02 // HTML data is complete @@ -28,22 +28,37 @@ enum CASC_MIME_ENCODING MimeEncodingMax }; +enum CASC_PRESENCE +{ + FieldPresenceUnknown, + FieldPresencePresent, + FieldPresenceNotPresent +}; + //----------------------------------------------------------------------------- // Structure for caching parsed HTTP response information -struct CASC_MIME_HTTP +struct CASC_MIME_RESPONSE { - CASC_MIME_HTTP() + CASC_MIME_RESPONSE() { - total_length = content_offset = content_length = http_flags = 0; + header_offset = header_length = CASC_INVALID_SIZE_T; + content_offset = content_length = CASC_INVALID_SIZE_T; + http_code = CASC_INVALID_SIZE_T; + clength_presence = http_presence = FieldPresenceUnknown; + response_length = 0; } - size_t IsDataComplete(const char * response, size_t response_length, size_t * ptr_content_length = NULL); + bool ParseResponse(const char * response, size_t length, bool final = false); - size_t content_length; // Parsed value of "Content-Length" - size_t content_offset; // Offset of the HTTP data, relative to the begin of the response - size_t total_length; // Expected total length of the HTTP response (content_offset + content_size) - size_t http_flags; // Nonzero if this is an already parsed HTTP response + size_t response_length; // Previous length of the response + size_t header_offset; // Offset of the response header, usually 0 + size_t header_length; // Length of the header, if known + size_t content_offset; // Offset of the content + size_t content_length; // Length of the content, if known + size_t http_code; // HTTP code, if present + CASC_PRESENCE clength_presence; // State of the "content length" field + CASC_PRESENCE http_presence; // Presence of the "HTTP" field }; //----------------------------------------------------------------------------- @@ -70,8 +85,9 @@ class CASC_MIME_ELEMENT CASC_MIME_ELEMENT(); ~CASC_MIME_ELEMENT(); - unsigned char * GiveAway(size_t * ptr_data_length); + DWORD GiveAway(CASC_BLOB & target); + DWORD LoadSingle(char * data, size_t data_length); DWORD Load(char * mime_data_begin, char * mime_data_end, const char * boundary_ptr = NULL); CASC_MIME_ELEMENT * GetChild() { return folder.pChild; } @@ -86,9 +102,9 @@ class CASC_MIME_ELEMENT bool ExtractEncoding(const char * line, CASC_MIME_ENCODING & Encoding); bool ExtractBoundary(const char * line); - DWORD DecodeTextPlain(char * content_begin, char * content_end, unsigned char * data_ptr, size_t * ptr_length); - DWORD DecodeQuotedPrintable(char * content_begin, char * content_end, unsigned char * data_ptr, size_t * ptr_length); - DWORD DecodeBase64(char * content_begin, char * content_end, unsigned char * data_ptr, size_t * ptr_length); + DWORD DecodeTextPlain(char * content_begin, char * content_end, CASC_BLOB & output); + DWORD DecodeQuotedPrintable(char * content_begin, char * content_end, CASC_BLOB & output); + DWORD DecodeBase64(char * content_begin, char * content_end, CASC_BLOB & output); struct { @@ -96,12 +112,7 @@ class CASC_MIME_ELEMENT CASC_MIME_ELEMENT * pNext; // Pointer to the next-in-folder element } folder; - struct - { - unsigned char * begin; - size_t length; - } data; - + CASC_BLOB data; char boundary[MAX_LENGTH_BOUNDARY]; }; @@ -112,10 +123,9 @@ class CASC_MIME CASC_MIME(); ~CASC_MIME(); - unsigned char * GiveAway(size_t * ptr_data_length); + DWORD GiveAway(CASC_BLOB & target); - DWORD Load(char * data, size_t length); - DWORD Load(LPCTSTR fileName); + DWORD Load(char * data, CASC_MIME_RESPONSE & MimeResponse); #ifdef _DEBUG void Print(); diff --git a/dep/CascLib/src/common/Path.h b/dep/CascLib/src/common/Path.h index 56489c5f4d9..082ce6ea61c 100644 --- a/dep/CascLib/src/common/Path.h +++ b/dep/CascLib/src/common/Path.h @@ -17,13 +17,20 @@ template <typename xchar> struct CASC_PATH { - CASC_PATH(int chSeparator = PATH_SEP_CHAR) + CASC_PATH(const xchar * szRoot, ...) { - m_szBufferBegin = m_szBufferPtr = m_Buffer; - m_szBufferEnd = m_szBufferBegin + _countof(m_Buffer); - m_chSeparator = (xchar)chSeparator; - m_bLocalCache = 0; - m_Buffer[0] = 0; + va_list argList; + + Initialize(PATH_SEP_CHAR); + + va_start(argList, szRoot); + Create(szRoot, argList); + va_end(argList); + } + + CASC_PATH(xchar chSeparator = PATH_SEP_CHAR) + { + Initialize(chSeparator); } ~CASC_PATH() @@ -34,10 +41,53 @@ struct CASC_PATH } } - // LPCTSTR szPath = Path; - operator const xchar *() const + void Create(const xchar * szRoot, ...) { - return m_szBufferBegin; + va_list argList; + + va_start(argList, szRoot); + Create(szRoot, argList); + va_end(argList); + } + + void Create(const xchar * szRoot, va_list argList) + { + const xchar * szPathPart; + + // Fill-in the root path + SetPathRoot(szRoot); + + // Append all parts until there is NULL + while((szPathPart = va_arg(argList, const xchar *)) != NULL) + { + AppendString(szPathPart, true); + } + } + + bool CutLastPart() + { + xchar * szBufferPtr; + + // Cut ending (back)slashes, if any + while((m_szBufferPtr > m_szBufferBegin) && (m_szBufferPtr[-1] == _T('\\') || m_szBufferPtr[-1] == _T('/'))) + m_szBufferPtr--; + szBufferPtr = m_szBufferPtr - 1; + + // Cut the last path part + while(szBufferPtr > m_szBufferBegin) + { + // End of path? + if(szBufferPtr[0] == _T('\\') || szBufferPtr[0] == _T('/')) + { + m_szBufferPtr = szBufferPtr; + m_szBufferPtr[0] = 0; + return true; + } + + // Go one character back + szBufferPtr--; + } + return false; } void SetLocalCaching(int bLocalCache) @@ -50,11 +100,22 @@ struct CASC_PATH return (m_bLocalCache != 0); } + // LPCTSTR szPath = Path; + operator const xchar * () const + { + return m_szBufferBegin; + } + // LPTSTR szPath = Path.New(); - xchar * New() + xchar * New(bool bCutLastPart = false) { xchar * szNewStr; + if(bCutLastPart) + { + CutLastPart(); + } + if((szNewStr = CASC_ALLOC<xchar>(Length() + 1)) != NULL) { memcpy(szNewStr, m_szBufferBegin, Length() * sizeof(xchar)); @@ -77,12 +138,11 @@ struct CASC_PATH m_szBufferPtr[0] = 0; return true; } - return false; } - // Path.Copy(szBuffer, _countof(szBuffer)); - bool Copy(xchar * szBuffer, size_t cchBuffer) + // Path.CopyTo(szBuffer, _countof(szBuffer)); + bool CopyTo(xchar * szBuffer, size_t cchBuffer) { if((Length() + 1) > cchBuffer) return false; @@ -183,6 +243,15 @@ struct CASC_PATH protected: + void Initialize(xchar chSeparator) + { + m_szBufferBegin = m_szBufferPtr = m_Buffer; + m_szBufferEnd = m_szBufferBegin + _countof(m_Buffer); + m_chSeparator = chSeparator; + m_bLocalCache = 0; + m_Buffer[0] = 0; + } + xchar * m_szBufferBegin; xchar * m_szBufferPtr; xchar * m_szBufferEnd; diff --git a/dep/CascLib/src/common/RootHandler.cpp b/dep/CascLib/src/common/RootHandler.cpp index fa34346b9ce..95fa106e1bd 100644 --- a/dep/CascLib/src/common/RootHandler.cpp +++ b/dep/CascLib/src/common/RootHandler.cpp @@ -87,7 +87,7 @@ PCASC_CKEY_ENTRY TFileTreeRoot::Search(TCascSearch * pSearch, PCASC_FIND_DATA pF if(!(pFileNode->Flags & CFN_FLAG_FOLDER)) { // Check the wildcard - if (CascCheckWildCard(pFindData->szFileName, pSearch->szMask)) + if(CascCheckWildCard(pFindData->szFileName, pSearch->szMask)) { // Retrieve the extra values (FileDataId, file size and locale flags) FileTree.GetExtras(pFileNode, &pFindData->dwFileDataId, &pFindData->dwLocaleFlags, &pFindData->dwContentFlags); diff --git a/dep/CascLib/src/common/Sockets.cpp b/dep/CascLib/src/common/Sockets.cpp index cf3ffe9d0b1..bb490505b15 100644 --- a/dep/CascLib/src/common/Sockets.cpp +++ b/dep/CascLib/src/common/Sockets.cpp @@ -24,21 +24,16 @@ CASC_SOCKET_CACHE SocketCache; // CASC_SOCKET functions // Guarantees that there is zero terminator after the response -char * CASC_SOCKET::ReadResponse(const char * request, size_t request_length, size_t * PtrLength) +char * CASC_SOCKET::ReadResponse(const char * request, size_t request_length, CASC_MIME_RESPONSE & MimeResponse) { - CASC_MIME_HTTP HttpInfo; char * server_response = NULL; - size_t content_length = 0; size_t total_received = 0; size_t buffer_length = BUFFER_INITIAL_SIZE; size_t buffer_delta = BUFFER_INITIAL_SIZE; - size_t http_flags = 0; DWORD dwErrCode = ERROR_SUCCESS; int bytes_received = 0; // Pre-set the result length - if(PtrLength != NULL) - PtrLength[0] = 0; if(request_length == 0) request_length = strlen(request); @@ -59,9 +54,10 @@ char * CASC_SOCKET::ReadResponse(const char * request, size_t request_length, si } // Allocate buffer for server response. Allocate one extra byte for zero terminator - if((server_response = CASC_ALLOC<char>(buffer_length + 1)) != NULL) + if((server_response = CASC_ALLOC_ZERO<char>(buffer_length + 1)) != NULL) { - while((http_flags & HTTP_DATA_COMPLETE) == 0) + // Keep working until the response parser says it's finished + for(;;) { // Reallocate the buffer size, if needed if(total_received == buffer_length) @@ -80,7 +76,10 @@ char * CASC_SOCKET::ReadResponse(const char * request, size_t request_length, si // Return value 0 means "connection closed", -1 means an error bytes_received = recv(sock, server_response + total_received, (int)(buffer_length - total_received), 0); if(bytes_received <= 0) + { + MimeResponse.ParseResponse(server_response, total_received, true); break; + } // Verify buffer overflow if((total_received + bytes_received) < total_received) @@ -93,23 +92,29 @@ char * CASC_SOCKET::ReadResponse(const char * request, size_t request_length, si total_received += bytes_received; server_response[total_received] = 0; - // On a HTTP protocol, we need to check whether we received all data - http_flags = HttpInfo.IsDataComplete(server_response, total_received, &content_length); - if(http_flags & HTTP_HEADER_COMPLETE) + // Parse the MIME response + if(MimeResponse.ParseResponse(server_response, total_received, false)) + break; + + // If we know the content length (HTTP only), we temporarily increment + // the buffer delta. This will make next reallocation to make buffer + // large enough to prevent abundant reallocations and memory memcpy's + if(MimeResponse.clength_presence == FieldPresencePresent && MimeResponse.content_length != CASC_INVALID_SIZE_T) { + // Calculate the final length of the buffer, including the terminating EOLs + size_t content_end = MimeResponse.content_offset + MimeResponse.content_length + 2; + // Check for maximum file size - if(content_length > CASC_MAX_ONLINE_FILE_SIZE) + if(content_end > CASC_MAX_ONLINE_FILE_SIZE) { dwErrCode = ERROR_NOT_ENOUGH_MEMORY; break; } - // If we just retrieved the content length, we temporarily increment - // the buffer delta. This will make next reallocation to make buffer - // large enough to prevent abundant reallocations and memory memcpy's - if(content_length > buffer_length) + // Estimate the total buffer size + if(content_end > buffer_length) { - buffer_delta = (HttpInfo.content_offset + content_length) - buffer_length; + buffer_delta = content_end - buffer_length; } } } @@ -127,8 +132,6 @@ char * CASC_SOCKET::ReadResponse(const char * request, size_t request_length, si } // Give the result to the caller - if(PtrLength != NULL) - PtrLength[0] = total_received; return server_response; } diff --git a/dep/CascLib/src/common/Sockets.h b/dep/CascLib/src/common/Sockets.h index 5d1aa677f85..c821748802b 100644 --- a/dep/CascLib/src/common/Sockets.h +++ b/dep/CascLib/src/common/Sockets.h @@ -48,7 +48,7 @@ class CASC_SOCKET { public: - char * ReadResponse(const char * request, size_t request_length = 0, size_t * PtrLength = NULL); + char * ReadResponse(const char * request, size_t request_length, CASC_MIME_RESPONSE & MimeResponse); DWORD AddRef(); void Release(); |