#define __CASCLIB_SELF__
#include "../CascLib.h"
#include "../CascCommon.h"
#define LISTFILE_FLAG_USES_FILEDATAID 0x0001
typedef struct _LISTFILE_CACHE
{
char * pBegin; char * pPos; char * pEnd; DWORD Flags;
} LISTFILE_CACHE, *PLISTFILE_CACHE;
static PLISTFILE_CACHE ListFile_CreateCache(DWORD dwFileSize)
{
PLISTFILE_CACHE pCache;
pCache = (PLISTFILE_CACHE)CASC_ALLOC<BYTE>(sizeof(LISTFILE_CACHE) + dwFileSize);
if(pCache != NULL)
{
pCache->pBegin =
pCache->pPos = (char *)(pCache + 1);
pCache->pEnd = pCache->pBegin + dwFileSize;
pCache->Flags = 0;
}
return pCache;
}
static char * ListFile_SkipSpaces(PLISTFILE_CACHE pCache)
{
while(pCache->pPos < pCache->pEnd && pCache->pPos[0] <= 0x20)
pCache->pPos++;
return pCache->pPos;
}
static void ListFile_CheckFormat(PLISTFILE_CACHE pCache)
{
const size_t nSizeLimit = 0x20;
if((pCache->pEnd - pCache->pBegin) > nSizeLimit)
{
char * szPtr = pCache->pBegin;
size_t nDigitCount = 0;
while(nDigitCount <= nSizeLimit && '0' <= szPtr[nDigitCount] && szPtr[nDigitCount] <= '9')
nDigitCount++;
if(nDigitCount <= 10 && szPtr[nDigitCount] == ';')
{
pCache->Flags |= LISTFILE_FLAG_USES_FILEDATAID;
}
}
}
static int ListFile_GetFileDataId(PLISTFILE_CACHE pCache, PDWORD PtrFileDataId)
{
char * szLineBegin = ListFile_SkipSpaces(pCache);
char * szLineEnd;
DWORD dwNewInt32 = 0;
DWORD dwInt32 = 0;
szLineEnd = CASCLIB_MIN((szLineBegin + 20), pCache->pEnd);
while(szLineBegin < szLineEnd && '0' <= szLineBegin[0] && szLineBegin[0] <= '9')
{
dwNewInt32 = (dwInt32 * 10) + (szLineBegin[0] - '0');
if(dwNewInt32 < dwInt32)
return ERROR_BAD_FORMAT;
dwInt32 = dwNewInt32;
szLineBegin++;
}
if(szLineBegin < szLineEnd)
{
if(szLineBegin[0] != ';' || dwInt32 >= 0xA00000)
return ERROR_BAD_FORMAT;
pCache->pPos = szLineBegin + 1;
PtrFileDataId[0] = dwInt32;
return ERROR_SUCCESS;
}
return ERROR_NO_MORE_FILES;
}
void * ListFile_OpenExternal(LPCTSTR szListFile)
{
PLISTFILE_CACHE pCache = NULL;
TFileStream * pStream;
ULONGLONG FileSize = 0;
pStream = FileStream_OpenFile(szListFile, STREAM_FLAG_READ_ONLY);
if(pStream != NULL)
{
FileStream_GetSize(pStream, &FileSize);
if(0 < FileSize && FileSize <= 0x30000000)
{
pCache = ListFile_CreateCache((DWORD)FileSize);
if(pCache != NULL)
{
if(FileStream_Read(pStream, NULL, pCache->pBegin, (DWORD)FileSize))
{
ListFile_CheckFormat(pCache);
}
else
{
CASC_FREE(pCache);
}
}
}
FileStream_Close(pStream);
}
return pCache;
}
void * ListFile_FromBuffer(LPBYTE pbBuffer, DWORD cbBuffer)
{
PLISTFILE_CACHE pCache = NULL;
pCache = ListFile_CreateCache(cbBuffer);
if(pCache != NULL)
memcpy(pCache->pBegin, pbBuffer, cbBuffer);
return pCache;
}
bool ListFile_VerifyMD5(void * pvListFile, LPBYTE pbHashMD5)
{
PLISTFILE_CACHE pCache = (PLISTFILE_CACHE)pvListFile;
assert(pCache->pPos == pCache->pBegin);
return CascVerifyDataBlockHash(pCache->pBegin, (DWORD)(pCache->pEnd - pCache->pBegin), pbHashMD5);
}
size_t ListFile_GetNextLine(void * pvListFile, const char ** pszLineBegin, const char ** pszLineEnd)
{
PLISTFILE_CACHE pCache = (PLISTFILE_CACHE)pvListFile;
char * szExtraString = NULL;
char * szLineBegin;
char * szLineEnd;
szLineBegin = ListFile_SkipSpaces(pCache);
while(pCache->pPos < pCache->pEnd)
{
if(pCache->pPos[0] == '\x0A' || pCache->pPos[0] == '\x0D' || pCache->pPos[0] == '\x85')
break;
if(pCache->pPos[0] == '~')
szExtraString = pCache->pPos;
pCache->pPos++;
}
szLineEnd = (szExtraString != NULL && szExtraString[0] == '~' && szExtraString[1] == 'P') ? szExtraString : pCache->pPos;
pszLineBegin[0] = szLineBegin;
pszLineEnd[0] = szLineEnd;
return (size_t)(szLineEnd - szLineBegin);
}
size_t ListFile_GetNextLine(void * pvListFile, char * szBuffer, size_t nMaxChars)
{
const char * szLineBegin = NULL;
const char * szLineEnd = NULL;
size_t nLength;
DWORD dwErrCode = ERROR_SUCCESS;
nLength = ListFile_GetNextLine(pvListFile, &szLineBegin, &szLineEnd);
if(nLength < nMaxChars)
{
memcpy(szBuffer, szLineBegin, nLength);
szBuffer[nLength] = 0;
}
else
{
dwErrCode = ERROR_INSUFFICIENT_BUFFER;
nLength = 0;
}
if(nLength == 0)
SetCascError(dwErrCode);
return nLength;
}
size_t ListFile_GetNext(void * pvListFile, char * szBuffer, size_t nMaxChars, PDWORD PtrFileDataId)
{
PLISTFILE_CACHE pCache = (PLISTFILE_CACHE)pvListFile;
const char * szTemp;
size_t nLength = 0;
DWORD dwErrCode = ERROR_SUCCESS;
for(;;)
{
DWORD FileDataId = CASC_INVALID_ID;
if(pCache->Flags & LISTFILE_FLAG_USES_FILEDATAID)
{
dwErrCode = ListFile_GetFileDataId(pCache, &FileDataId);
if(dwErrCode == ERROR_NO_MORE_FILES)
break;
if(dwErrCode != ERROR_SUCCESS || FileDataId == CASC_INVALID_ID)
{
ListFile_GetNextLine(pvListFile, &szTemp, &szTemp);
continue;
}
}
nLength = ListFile_GetNextLine(pvListFile, szBuffer, nMaxChars);
if(nLength == 0)
{
dwErrCode = GetCascError();
break;
}
PtrFileDataId[0] = FileDataId;
return nLength;
}
if(dwErrCode != ERROR_SUCCESS)
SetCascError(dwErrCode);
return nLength;
}
LPBYTE ListFile_GetData(void * pvListFile, PDWORD PtrDataSize)
{
PLISTFILE_CACHE pCache = (PLISTFILE_CACHE)pvListFile;
LPBYTE pbData = NULL;
DWORD cbData = 0;
if(pvListFile != NULL)
{
pbData = (LPBYTE)pCache->pBegin;
cbData = (DWORD)(pCache->pEnd - pCache->pBegin);
}
if(PtrDataSize != NULL)
PtrDataSize[0] = cbData;
return pbData;
}