aboutsummaryrefslogtreecommitdiff
path: root/dep/CascLib/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'dep/CascLib/src/common')
-rw-r--r--dep/CascLib/src/common/Array.h33
-rw-r--r--dep/CascLib/src/common/ArraySparse.h286
-rw-r--r--dep/CascLib/src/common/Common.cpp127
-rw-r--r--dep/CascLib/src/common/Common.h87
-rw-r--r--dep/CascLib/src/common/Csv.cpp37
-rw-r--r--dep/CascLib/src/common/Csv.h2
-rw-r--r--dep/CascLib/src/common/Directory.cpp62
-rw-r--r--dep/CascLib/src/common/Directory.h18
-rw-r--r--dep/CascLib/src/common/FileStream.cpp32
-rw-r--r--dep/CascLib/src/common/FileTree.cpp13
-rw-r--r--dep/CascLib/src/common/FileTree.h10
-rw-r--r--dep/CascLib/src/common/ListFile.cpp4
-rw-r--r--dep/CascLib/src/common/Mime.cpp454
-rw-r--r--dep/CascLib/src/common/Mime.h54
-rw-r--r--dep/CascLib/src/common/Path.h95
-rw-r--r--dep/CascLib/src/common/RootHandler.cpp2
-rw-r--r--dep/CascLib/src/common/Sockets.cpp41
-rw-r--r--dep/CascLib/src/common/Sockets.h2
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();