diff --git a/source/duke3d/src/gameexec.cpp b/source/duke3d/src/gameexec.cpp index b40ee93bf..d451b9e88 100644 --- a/source/duke3d/src/gameexec.cpp +++ b/source/duke3d/src/gameexec.cpp @@ -4392,40 +4392,52 @@ finish_qsprintf: if (kFile < 0) continue; - int const numElements = Gv_GetArrayElementSize(arrayNum) ? kfilelength(kFile) / min(Gv_GetArrayElementSize(arrayNum), sizeof(uint32_t)) : 1; + size_t const filelength = kfilelength(kFile); + size_t const numElements = Gv_GetArrayCountFromFile(arrayNum, filelength); if (numElements > 0) { - int numBytes = numElements * Gv_GetArrayElementSize(arrayNum); + size_t const newBytes = Gv_GetArrayAllocSizeForCount(arrayNum, numElements); + size_t const oldBytes = Gv_GetArrayAllocSize(arrayNum); - aGameArrays[arrayNum].size = numBytes ? numElements : kfilelength(kFile); + intptr_t *& pValues = aGameArrays[arrayNum].pValues; - if (numBytes != Gv_GetArrayAllocSize(arrayNum)) + if (newBytes != oldBytes) { - Baligned_free(aGameArrays[arrayNum].pValues); - aGameArrays[arrayNum].pValues = (intptr_t *) Xaligned_alloc(ACTOR_VAR_ALIGNMENT, Gv_GetArrayAllocSize(arrayNum)); + Baligned_free(pValues); + pValues = (intptr_t *) Xaligned_alloc(ACTOR_VAR_ALIGNMENT, newBytes); } - numBytes = Gv_GetArrayAllocSize(arrayNum); + aGameArrays[arrayNum].size = numElements; - switch (aGameArrays[arrayNum].flags & GAMEARRAY_SIZE_MASK) + uintptr_t const flags = aGameArrays[arrayNum].flags; + + switch (flags & GAMEARRAY_SIZE_MASK) { case 0: #ifdef BITNESS64 { - int32_t * const pArray = (int32_t *)Xcalloc(1, numBytes); + void * const pArray = Xcalloc(1, newBytes); - kread(kFile, pArray, numBytes); + kread(kFile, pArray, newBytes); - for (bssize_t i = 0; i < numElements; i++) - aGameArrays[arrayNum].pValues[i] = pArray[i]; + if (flags & GAMEARRAY_UNSIGNED) + { + for (size_t i = 0; i < numElements; ++i) + pValues[i] = ((uint32_t *)pArray)[i]; + } + else + { + for (size_t i = 0; i < numElements; ++i) + pValues[i] = ((int32_t *)pArray)[i]; + } Bfree(pArray); break; } #endif default: - kread(kFile, aGameArrays[arrayNum].pValues, Gv_GetArrayAllocSize(arrayNum)); + kread(kFile, pValues, newBytes); break; } } diff --git a/source/duke3d/src/gamevars.cpp b/source/duke3d/src/gamevars.cpp index 56e04bc60..ee9642a58 100644 --- a/source/duke3d/src/gamevars.cpp +++ b/source/duke3d/src/gamevars.cpp @@ -582,12 +582,27 @@ static int Gv_GetArrayIndex(const char *szArrayLabel) return arrayIdx; } -int __fastcall Gv_GetArrayAllocSize(int const arrayIdx) +size_t __fastcall Gv_GetArrayAllocSizeForCount(int const arrayIdx, size_t const count) { if (aGameArrays[arrayIdx].flags & GAMEARRAY_BITMAP) - return (aGameArrays[arrayIdx].size + 7) >> 3; + return (count + 7) >> 3; - return aGameArrays[arrayIdx].size * Gv_GetArrayElementSize(arrayIdx); + return count * Gv_GetArrayElementSize(arrayIdx); +} + +size_t __fastcall Gv_GetArrayAllocSize(int const arrayIdx) +{ + return Gv_GetArrayAllocSizeForCount(arrayIdx, aGameArrays[arrayIdx].size); +} + +size_t __fastcall Gv_GetArrayCountFromFile(int const arrayIdx, size_t const filelength) +{ + if (aGameArrays[arrayIdx].flags & GAMEARRAY_BITMAP) + return filelength << 3; + + size_t const elementSize = Gv_GetArrayElementSize(arrayIdx); + size_t const denominator = min(elementSize, sizeof(uint32_t)); + return filelength / denominator; } int __fastcall Gv_GetArrayValue(int const id, int index) diff --git a/source/duke3d/src/gamevars.h b/source/duke3d/src/gamevars.h index 070b168b7..c127a06e9 100644 --- a/source/duke3d/src/gamevars.h +++ b/source/duke3d/src/gamevars.h @@ -105,7 +105,9 @@ extern int32_t g_gameVarCount; extern int32_t g_gameArrayCount; unsigned __fastcall Gv_GetArrayElementSize(int const arrayIdx); -int __fastcall Gv_GetArrayAllocSize(int const arrayIdx); +size_t __fastcall Gv_GetArrayAllocSizeForCount(int const arrayIdx, size_t const count); +size_t __fastcall Gv_GetArrayAllocSize(int const arrayIdx); +size_t __fastcall Gv_GetArrayCountFromFile(int const arrayIdx, size_t const filelength); int __fastcall Gv_GetArrayValue(int const id, int index); int __fastcall Gv_GetVar(int id, int spriteNum, int playerNum); void __fastcall Gv_SetVar(int const id, int const lValue, int const spriteNum, int const playerNum);