aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/gui/gui_memmgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/gui/gui_memmgr.cpp')
-rw-r--r--engines/sci/gui/gui_memmgr.cpp373
1 files changed, 373 insertions, 0 deletions
diff --git a/engines/sci/gui/gui_memmgr.cpp b/engines/sci/gui/gui_memmgr.cpp
new file mode 100644
index 0000000000..3b42da274e
--- /dev/null
+++ b/engines/sci/gui/gui_memmgr.cpp
@@ -0,0 +1,373 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "sci/sci.h"
+#include "sci/gui/gui_helpers.h"
+#include "sci/gui/gui_memmgr.h"
+
+namespace Sci {
+
+static tagHandle *pHandles = 0;
+static int16 nHandles = 0;
+static byte *_heap = 0;
+SCIHANDLE _firstfree = 0;
+Common::HashMap<HEAPHANDLE, tagHeapInfo> heapInfo;
+#define HEAP_BOTTOM 1000
+
+//----------------------
+void FreeMem(void) {
+ // deleting handles
+ if (pHandles) {
+ for (uint16 i = 0; i < nHandles; i++)
+ hunkDisposeHandle(i);
+ delete[] pHandles;
+ pHandles = 0;
+ }
+ // deleting heap
+ if (_heap) {
+ delete[] _heap;
+ _heap = 0;
+ }
+}
+//----------------------
+bool InitMem(int16 max_handles) {
+ // heap
+ _heap = new byte[HEAP_SIZE];
+ memset(_heap, 0x55, HEAP_SIZE);
+ _firstfree = HEAP_START;
+ heapSetBlockSize(_firstfree, HEAP_SIZE - 1 - HEAP_START);
+ heapSetBlockNext(_firstfree, (SCIHANDLE)(HEAP_SIZE - 1));
+ //hunk
+ pHandles = new tagHandle[max_handles];
+ if (pHandles) {
+ nHandles = max_handles;
+ memset(pHandles, 0, sizeof(tagHandle) * max_handles); // zerofy all
+ return 1;
+ }
+ return 0;
+}
+//----------------------
+SCIHANDLE hunkNeedHandle(uint16 size, uint32 resId) {
+ SCIHANDLE newh = 0;
+ // see if there is an empty handle available
+ for (int16 i = 1; i < nHandles; i++)
+ if (pHandles[i].ptr == 0) {
+ newh = i;
+ break;
+ }
+ // if unused handle was found - allocate memory and return it
+ if (newh == nHandles)
+ return 0;
+ pHandles[newh].ptr = (byte*)malloc(size);
+ assert(pHandles[newh].ptr);
+ if (pHandles[newh].ptr) {
+ pHandles[newh].size = size;
+ pHandles[newh].resId = resId;
+ debug(
+ 5,
+ " MemMgr: Requested %6db for res %08X, allocated handle %04X",
+ size, resId, newh);
+ return newh;
+ }
+ return 0;
+}
+//----------------------
+void hunkDisposeHandle(SCIHANDLE handle) {
+// if (handle > 0 && handle < nHandles && pHandles[handle].ptr) {
+// debug(
+// 5,
+// " MemMgr: disposing handle 0x%04X, size=%8db, associated res %08X",
+// handle, pHandles[handle].size, pHandles[handle].resId);
+// free(pHandles[handle].ptr);
+// pHandles[handle].ptr = 0;
+// // deleting associated resource handler
+// // Check that this don't fail on delete as ResGetLoaded could return 0;
+// if (pHandles[handle].resId != 0xFFFFFFFF)
+// delete g_sci->ResMgr.ResGetLoaded(pHandles[handle].resId);
+// }
+}
+//----------------------
+byte *hunk2Ptr(SCIHANDLE handle) {
+ if (handle > 0 && handle < nHandles && pHandles[handle].ptr)
+ return (byte *)pHandles[handle].ptr;
+ return 0;
+}
+//----------------------
+SCIHANDLE ptr2hunk(byte *ptr) {
+ for (int i = 0; i < nHandles; i++) {
+ if (ptr >= pHandles[i].ptr && ptr <= pHandles[i].ptr + pHandles[i].size)
+ return i;
+ }
+return 0;
+}
+//----------------------
+uint32 hunkHandleSize(SCIHANDLE handle) {
+ if (handle > 0 && handle < nHandles && pHandles[handle].ptr)
+ return pHandles[handle].size;
+ return 0;
+}
+//----------------------
+// int16 hunkResourceNum(SCIHANDLE handle) {
+// if (handle > 0 && handle < nHandles && pHandles[handle].ptr)
+// return RES_ID2NUM(pHandles[handle].resId);
+// return -1;
+// }
+
+//----------------------
+void hunkDump() {
+ debug("\nMemMgr: Hunk dump:");
+ uint32 size = 0;
+ for (int i = 0; i < nHandles; i++)
+ if (pHandles[i].ptr) {
+ debug(" %04X, size=%8db, associated res %08X", i,
+ pHandles[i].size, pHandles[i].resId);
+ size += pHandles[i].size;
+ }
+ debug("Total memory allocated: %db", size);
+ debug("End dump");
+}
+
+uint32 hunkUsed() {
+ uint32 size = 0;
+ for (int i = 0; i < nHandles; i++)
+ if (pHandles[i].ptr)
+ size += pHandles[i].size;
+ return size;
+}
+//----------------------
+// HEAP
+//----------------------
+//---------------------------------------------
+// TODO : make sure that STRING, STACK and SCRIPT DATA is never allocated below HEAP_BOTTOM=1000
+// otherwise it will cause problems with kernel string fuctions that assumes that anything below 1000 is res number
+HEAPHANDLE heapNewPtr(uint16 size, kDataType type, const char *info) {
+ if (size == 0)
+ warning("Zero Heap Allocation Request!");
+
+ HEAPHANDLE ptr, prev, next;
+ ptr = prev = _firstfree;
+ // 2 bytes block header header + block size must be odd
+ size += 2 + (size & 1);
+ // looking for an empty block to use
+ uint16 blocksize;
+ bool bBottomSafe = !(type == kDataString || type == kDataUnknown);
+
+ while (ptr < HEAP_SIZE - 1) {
+ blocksize = heapGetBlockSize(ptr);
+ next = heapGetBlockNext(ptr);
+ if (blocksize >= size) {
+ if (bBottomSafe || (!bBottomSafe && ptr > HEAP_BOTTOM)) {
+ if (blocksize <= size + 4) { // use all block
+ size = blocksize;
+ heapSetBlockNext(prev, next);
+ } else { // split block in 2 blocks
+ HEAPHANDLE newblock = ptr + size;
+ heapSetBlockNext(prev, newblock);
+ heapSetBlockSize(newblock, blocksize - size);
+ heapSetBlockNext(newblock, next);
+ next = newblock;
+ }
+ // setting allocated block
+ heapSetBlockSize(ptr, size);
+ // updating firstfree pointer
+ if (ptr == _firstfree)
+ _firstfree = next;
+ setHeapInfo(ptr, type, info);
+ return ptr;
+ } //if (bBottomSafe || (!bBottomSafe && ptr>HEAP_BOTTOM))
+ else { // !bottomsafe && ptr < HEAP_BOTTOM
+ if (blocksize + ptr - HEAP_BOTTOM >= size) {
+ // splitting the block into 3 parts
+ // [2][ptr...999] [2][1002...1000+size-1] [2][1002+size...ptr+blocksize]
+ // free returned free
+ heapSetBlockSize(ptr, HEAP_BOTTOM-ptr + 2);
+ heapSetBlockSize(HEAP_BOTTOM+2, size);
+ heapSetBlockSize(HEAP_BOTTOM+2 + size, blocksize - size
+ - (HEAP_BOTTOM-ptr + 2));
+
+ heapSetBlockNext(HEAP_BOTTOM+2 + size, next);
+ heapSetBlockNext(ptr, HEAP_BOTTOM+2 + size);
+ setHeapInfo(HEAP_BOTTOM+2, type, info);
+ return HEAP_BOTTOM + 2;
+ }
+ }
+ } // if (blocksize >= size)
+ // block too small - moving to next one
+ prev = ptr;
+ ptr = next;
+ }
+ // allocation error - out of heap
+ warning("Out of heap space");
+ return 0;
+}
+//--------------------------------------------
+void heapDisposePtr(HEAPHANDLE handle) {
+ HEAPHANDLE prev, next;
+ prev = next = _firstfree;
+ // searching for prev and next free blocks (before & after deleted block)
+ while (next < handle) {
+ prev = next;
+ next = heapGetBlockNext(prev);
+ }
+ // if deleted block is before 1st free space then it'll be 1st free space
+ if (handle < _firstfree) {
+ next = _firstfree;
+ _firstfree = handle;
+ } else
+ heapSetBlockNext(prev, handle);
+
+ heapSetBlockNext(handle, next);
+ //Try to merge with previous
+ if (prev + heapGetBlockSize(prev) == handle) {
+ heapSetBlockSize(prev, heapGetBlockSize(prev)
+ + heapGetBlockSize(handle));
+ heapSetBlockNext(prev, next);
+ handle = prev;
+ }
+ //Try to merge with next
+ if (handle + heapGetBlockSize(handle) == next && next != (HEAP_SIZE - 1)) {
+ heapSetBlockSize(handle, heapGetBlockSize(handle) + heapGetBlockSize(
+ next));
+ heapSetBlockNext(handle, heapGetBlockNext(next));
+ }
+}
+//-------------------------------------
+uint16 heapFreeSize() {
+ HEAPHANDLE free = _firstfree;
+ uint16 szFree = 0;
+ while (free < HEAP_SIZE - 1) {
+ int size = heapGetBlockSize(free);
+ free = heapGetBlockNext(free);
+ szFree += size;
+ }
+ return szFree;
+}
+//-------------------------------------
+uint16 heapLargestFreeSize() {
+ HEAPHANDLE free = _firstfree;
+ uint16 maxFree = 0;
+ while (free < HEAP_SIZE - 1) {
+ int size = heapGetBlockSize(free);
+ free = heapGetBlockNext(free);
+ if (size > maxFree)
+ maxFree = size;
+ }
+ return maxFree ? maxFree - 2 : 0;
+}
+//-------------------------------------
+void heapDump() {
+ debug("\nMemMgr:Heap dump:");
+ HEAPHANDLE ptr = HEAP_START;
+ HEAPHANDLE free = _firstfree;
+
+ uint16 szFree = 0, szUsed = 0;
+ while (ptr < HEAP_SIZE - 1) {
+ int size = heapGetBlockSize(ptr);
+ if (ptr == free) {
+ free = heapGetBlockNext(free);
+ debug(" %04X %6u size:%6d FREE next=%04X", ptr, ptr,
+ heapGetDataSize(ptr), free);
+ szFree += size;
+ } else {
+ debug(" %04X %6u size:%6d USED", ptr, ptr, heapGetDataSize(ptr));
+ szUsed += size;
+ }
+ ptr += size;
+ }
+ debug("Total %db used, %db free\nEnd Dump", szUsed, szFree);
+}
+//----------------------------
+inline byte *heap2Ptr(HEAPHANDLE ptr) {
+ return (ptr >= HEAP_START) ? (byte *)(_heap + ptr) : NULL;
+}
+//----------------------------
+HEAPHANDLE ptr2heap(byte *ptr) {
+ return ptr > _heap && ptr < (_heap + HEAP_SIZE) ? (HEAPHANDLE)(ptr - _heap)
+ : 0;
+}
+//----------------------------
+uint16 heapGetBlockSize(HEAPHANDLE ptr) {
+ return READ_UINT16(_heap + ptr - 2);
+}
+//----------------------------
+uint16 heapGetDataSize(HEAPHANDLE ptr) {
+ return heapGetBlockSize(ptr) - 2;
+}
+//----------------------------
+void heapFillPtr(HEAPHANDLE ptr, byte filler) {
+ memset(heap2Ptr(ptr), filler, heapGetDataSize(ptr));
+}
+//----------------------------
+void heapClearPtr(HEAPHANDLE ptr) {
+ heapFillPtr(ptr, 0);
+}
+//----------------------------
+void heapSetBlockSize(HEAPHANDLE ptr, uint16 nbytes) {
+ WRITE_UINT16(_heap + ptr - 2, nbytes);
+}
+//----------------------------
+HEAPHANDLE heapGetBlockNext(HEAPHANDLE ptr) {
+ return READ_UINT16(_heap + ptr);
+}
+//----------------------------
+void heapSetBlockNext(HEAPHANDLE ptr, SCIHANDLE next) {
+ WRITE_UINT16(_heap + ptr, next);
+}
+//----------------------------
+void heapDisposePtr(byte *ptr) {
+ heapDisposePtr(ptr - _heap);
+}
+//---------------------------------------------
+//
+//
+void setHeapInfo(HEAPHANDLE hnd, kDataType type, const char *szinfo) {
+ tagHeapInfo info = { kDataUnknown, 0 };
+ info.type = type;
+ if (szinfo)
+ strncpy(info.info, szinfo, 20);
+ heapInfo.setVal(hnd, info);
+}
+//--------------------------------
+bool saveMemState(Common::OutSaveFile *pFile) {
+ pFile->writeString("MEMORY\n");
+ // saving heap
+ pFile->write(_heap, HEAP_SIZE);
+ pFile->writeUint16LE(_firstfree);
+ // TODO : process and write hunk handles
+ //pFile->writeString("HUNK\n");
+ return true;
+}
+//--------------------------------
+bool restoreMemState(Common::InSaveFile *pFile) {
+ if (pFile->readLine() != "MEMORY")
+ return false;
+ pFile->read(_heap, HEAP_SIZE);
+ _firstfree = pFile->readUint16LE();
+
+ return true;
+}
+
+//-------------------------------
+}// end of namespace SCI