aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine/memobj.h
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/engine/memobj.h')
-rw-r--r--engines/sci/engine/memobj.h556
1 files changed, 556 insertions, 0 deletions
diff --git a/engines/sci/engine/memobj.h b/engines/sci/engine/memobj.h
new file mode 100644
index 0000000000..a871d2dcb6
--- /dev/null
+++ b/engines/sci/engine/memobj.h
@@ -0,0 +1,556 @@
+/* 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$
+ *
+ */
+
+#ifndef SCI_ENGINE_MEMOBJ_H
+#define SCI_ENGINE_MEMOBJ_H
+
+#include "common/serializer.h"
+#include "sci/engine/vm_types.h" // for reg_t
+
+//#include "common/util.h"
+
+namespace Sci {
+
+enum MemObjectType {
+ MEM_OBJ_INVALID = 0,
+ MEM_OBJ_SCRIPT = 1,
+ MEM_OBJ_CLONES = 2,
+ MEM_OBJ_LOCALS = 3,
+ MEM_OBJ_STACK = 4,
+ MEM_OBJ_SYS_STRINGS = 5,
+ MEM_OBJ_LISTS = 6,
+ MEM_OBJ_NODES = 7,
+ MEM_OBJ_HUNK = 8,
+ MEM_OBJ_DYNMEM = 9,
+ MEM_OBJ_STRING_FRAG = 10,
+
+ MEM_OBJ_MAX // For sanity checking
+};
+
+struct MemObject : public Common::Serializable {
+ MemObjectType _type;
+ int _segmgrId; /**< Internal value used by the seg_manager's hash map */
+
+ typedef void (*NoteCallback)(void *param, reg_t addr); // FIXME: Bad choice of name
+
+public:
+ static MemObject *createMemObject(MemObjectType type);
+
+public:
+ virtual ~MemObject() {}
+
+ inline MemObjectType getType() const { return _type; }
+ inline int getSegMgrId() const { return _segmgrId; }
+
+ /**
+ * Dereferences a raw memory pointer.
+ * @param reg reference to dereference
+ * @param size if not NULL, set to the theoretical maximum size of the referenced data block
+ * @return the data block referenced
+ */
+ virtual byte *dereference(reg_t pointer, int *size);
+
+ /**
+ * Finds the canonic address associated with sub_reg.
+ *
+ * For each valid address a, there exists a canonic address c(a) such that c(a) = c(c(a)).
+ * This address "governs" a in the sense that deallocating c(a) will deallocate a.
+ *
+ * @param sub_addr base address whose canonic address is to be found
+ */
+ virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr) { return sub_addr; }
+
+ /**
+ * Deallocates all memory associated with the specified address.
+ * @param sub_addr address (within the given segment) to deallocate
+ */
+ virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr) {}
+
+ /**
+ * Iterates over and reports all addresses within the current segment.
+ * @param note Invoked for each address on which free_at_address() makes sense
+ * @param param parameter passed to 'note'
+ */
+ virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {}
+
+ /**
+ * Iterates over all references reachable from the specified object.
+ * @param object object (within the current segment) to analyse
+ * @param param parameter passed to 'note'
+ * @param note Invoked for each outgoing reference within the object
+ * Note: This function may also choose to report numbers (segment 0) as adresses
+ */
+ virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note) {}
+};
+
+
+// TODO: Implement the following class
+struct StringFrag : public MemObject {
+ virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+struct IntMapper;
+
+enum {
+ SYS_STRINGS_MAX = 4,
+
+ SYS_STRING_SAVEDIR = 0,
+ SYS_STRING_PARSER_BASE = 1,
+
+ MAX_PARSER_BASE = 64
+};
+
+struct SystemString {
+ char *name;
+ int max_size;
+ reg_t *value;
+};
+
+struct SystemStrings : public MemObject {
+ SystemString strings[SYS_STRINGS_MAX];
+
+public:
+ SystemStrings() {
+ memset(strings, 0, sizeof(strings));
+ }
+ ~SystemStrings() {
+ for (int i = 0; i < SYS_STRINGS_MAX; i++) {
+ SystemString *str = &strings[i];
+ if (str->name) {
+ free(str->name);
+ str->name = NULL;
+
+ free(str->value);
+ str->value = NULL;
+
+ str->max_size = 0;
+ }
+ }
+ }
+
+ virtual byte *dereference(reg_t pointer, int *size);
+
+ virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+/** This struct is used to buffer the list of send calls in send_selector() */
+struct CallsStruct {
+ union {
+ reg_t func;
+ reg_t *var;
+ } address;
+ StackPtr argp;
+ int argc;
+ Selector selector;
+ StackPtr sp; /**< Stack pointer */
+ int type; /**< Same as ExecStack.type */
+};
+
+struct LocalVariables : public MemObject {
+ int script_id; /**< Script ID this local variable block belongs to */
+ Common::Array<reg_t> _locals;
+
+public:
+ LocalVariables() {
+ script_id = 0;
+ }
+
+ virtual byte *dereference(reg_t pointer, int *size);
+ virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr);
+ virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
+
+ virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+/** Clone has been marked as 'freed' */
+#define OBJECT_FLAG_FREED (0x1 << 0)
+
+struct Object {
+ int flags;
+ reg_t pos; /**< Object offset within its script; for clones, this is their base */
+ int variable_names_nr; /**< Number of variable names, may be less than variables_nr */
+ int methods_nr;
+ byte *base; /**< Points to a buffer all relative references (code, strings) point to */
+ byte *base_obj; /**< base + object offset within base */
+ uint16 *base_method; /**< Pointer to the method selector area for this object */
+ uint16 *base_vars; /**< Pointer to the varselector area for this object */
+ Common::Array<reg_t> _variables;
+};
+
+struct CodeBlock {
+ reg_t pos;
+ int size;
+};
+
+#define VM_OBJECT_GET_VARSELECTOR(obj, i) \
+ (s->version < SCI_VERSION_1_1 ? \
+ READ_LE_UINT16(obj->base_obj + obj->_variables.size() * 2 + i*2) : \
+ *(obj->base_vars + i))
+#define VM_OBJECT_READ_PROPERTY(obj, i) (obj->_variables[i])
+#define VM_OBJECT_GET_FUNCSELECTOR(obj, i) \
+ (s->version < SCI_VERSION_1_1 ? \
+ READ_LE_UINT16((byte *) (obj->base_method + i)) : \
+ READ_LE_UINT16((byte *) (obj->base_method + i*2 + 1)))
+#define VM_OBJECT_READ_FUNCTION(obj, i) \
+ (s->version < SCI_VERSION_1_1 ? \
+ make_reg(obj->pos.segment, \
+ READ_LE_UINT16((byte *) (obj->base_method \
+ + obj->methods_nr + 1 \
+ + i))) : \
+ make_reg(obj->pos.segment, \
+ READ_LE_UINT16((byte *) (obj->base_method \
+ + i * 2 + 2))))
+
+
+
+
+struct Script : public MemObject {
+ int nr; /**< Script number */
+ byte *buf; /**< Static data buffer, or NULL if not used */
+ size_t buf_size;
+ size_t script_size;
+ size_t heap_size;
+
+ byte *synonyms; /**< Synonyms block or 0 if not present*/
+ byte *heap_start; /**< Start of heap if SCI1.1, NULL otherwise */
+ uint16 *export_table; /**< Abs. offset of the export table or 0 if not present */
+
+ IntMapper *obj_indices;
+
+ int exports_nr; /**< Number of entries in the exports table */
+ int synonyms_nr; /**< Number of entries in the synonyms block */
+ int lockers; /**< Number of classes and objects that require this script */
+
+ /**
+ * Table for objects, contains property variables.
+ * Indexed by the value stored at SCRIPT_LOCALVARPTR_OFFSET,
+ * see VM_OBJECT_[GS]ET_INDEX()
+ */
+ Common::Array<Object> _objects;
+
+ int locals_offset;
+ int locals_segment; /**< The local variable segment */
+ LocalVariables *locals_block;
+
+ Common::Array<CodeBlock> _codeBlocks;
+ int relocated;
+ bool _markedAsDeleted;
+
+public:
+ Script() {
+ nr = 0;
+ buf = NULL;
+ buf_size = 0;
+ script_size = 0;
+ heap_size = 0;
+
+ synonyms = NULL;
+ heap_start = NULL;
+ export_table = NULL;
+
+ obj_indices = NULL;
+
+ locals_offset = 0;
+ locals_segment = 0;
+ locals_block = NULL;
+
+ relocated = 0;
+ _markedAsDeleted = 0;
+ }
+
+ ~Script() {
+ freeScript();
+ }
+
+ void freeScript();
+
+ virtual byte *dereference(reg_t pointer, int *size);
+ virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr);
+ virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr);
+ virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note);
+ virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
+
+ virtual void saveLoadWithSerializer(Common::Serializer &ser);
+
+ // script lock operations
+
+ /** Increments the number of lockers of this script by one. */
+ void incrementLockers();
+
+ /** Decrements the number of lockers of this script by one. */
+ void decrementLockers();
+
+ /**
+ * Retrieves the number of locks held on this script.
+ * @return the number of locks held on the previously identified script
+ */
+ int getLockers() const;
+
+ /** Sets the number of locks held on this script. */
+ void setLockers(int lockers);
+
+ /**
+ * Retrieves a pointer to the synonyms associated with this script
+ * @return pointer to the synonyms, in non-parsed format.
+ */
+ byte *getSynonyms() const;
+
+ /**
+ * Retrieves the number of synonyms associated with this script.
+ * @return the number of synonyms associated with this script
+ */
+ int getSynonymsNr() const;
+
+
+ /**
+ * Sets the script-relative offset of the exports table.
+ * @param offset script-relative exports table offset
+ */
+ void setExportTableOffset(int offset);
+
+ /**
+ * Sets the script-relative offset of the synonyms associated with this script.
+ * @param offset script-relative offset of the synonyms block
+ */
+ void setSynonymsOffset(int offset);
+
+ /**
+ * Sets the number of synonyms associated with this script,
+ * @param nr number of synonyms, as to be stored within the script
+ */
+ void setSynonymsNr(int nr);
+
+
+ /**
+ * Copies a byte string into a script's heap representation.
+ * @param dst script-relative offset of the destination area
+ * @param src pointer to the data source location
+ * @param n number of bytes to copy
+ */
+ void mcpyInOut(int dst, const void *src, size_t n);
+
+
+ /**
+ * Marks the script as deleted.
+ * This will not actually delete the script. If references remain present on the
+ * heap or the stack, the script will stay in memory in a quasi-deleted state until
+ * either unreachable (resulting in its eventual deletion) or reloaded (resulting
+ * in its data being updated).
+ */
+ void markDeleted() {
+ _markedAsDeleted = true;
+ }
+
+ /**
+ * Marks the script as not deleted.
+ */
+ void unmarkDeleted() {
+ _markedAsDeleted = false;
+ }
+
+ /**
+ * Determines whether the script is marked as being deleted.
+ */
+ bool isMarkedAsDeleted() const {
+ return _markedAsDeleted;
+ }
+
+ /**
+ * Retrieves a 16 bit value from within a script's heap representation.
+ * @param offset offset to read from
+ * @return the value read from the specified location
+ */
+ int16 getHeap(uint16 offset) const;
+
+};
+
+/** Data stack */
+struct DataStack : MemObject {
+ int nr; /**< Number of stack entries */
+ reg_t *entries;
+
+public:
+ DataStack() {
+ nr = 0;
+ entries = NULL;
+ }
+ ~DataStack() {
+ free(entries);
+ entries = NULL;
+ }
+
+ virtual byte *dereference(reg_t pointer, int *size);
+ virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr);
+ virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
+
+ virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+#define CLONE_USED -1
+#define CLONE_NONE -1
+
+typedef Object Clone;
+
+struct Node {
+ reg_t pred; /**< Predecessor node */
+ reg_t succ; /**< Successor node */
+ reg_t key;
+ reg_t value;
+}; /* List nodes */
+
+struct List {
+ reg_t first;
+ reg_t last;
+};
+
+struct Hunk {
+ void *mem;
+ unsigned int size;
+ const char *type;
+};
+
+template<typename T>
+struct Table : public MemObject {
+ typedef T value_type;
+ struct Entry : public T {
+ int next_free; /* Only used for free entries */
+ };
+ enum { HEAPENTRY_INVALID = -1 };
+
+
+ int first_free; /**< Beginning of a singly linked list for entries */
+ int entries_used; /**< Statistical information */
+
+ Common::Array<Entry> _table;
+
+public:
+ Table() {
+ initTable();
+ }
+
+ void initTable() {
+ entries_used = 0;
+ first_free = HEAPENTRY_INVALID;
+ _table.clear();
+ }
+
+ int allocEntry() {
+ entries_used++;
+ if (first_free != HEAPENTRY_INVALID) {
+ int oldff = first_free;
+ first_free = _table[oldff].next_free;
+
+ _table[oldff].next_free = oldff;
+ return oldff;
+ } else {
+ uint newIdx = _table.size();
+ _table.push_back(Entry());
+ _table[newIdx].next_free = newIdx; // Tag as 'valid'
+ return newIdx;
+ }
+ }
+
+ bool isValidEntry(int idx) {
+ return idx >= 0 && (uint)idx < _table.size() && _table[idx].next_free == idx;
+ }
+
+ virtual void freeEntry(int idx) {
+ if (idx < 0 || (uint)idx >= _table.size())
+ ::error("Table::freeEntry: Attempt to release invalid table index %d", idx);
+
+ _table[idx].next_free = first_free;
+ first_free = idx;
+ entries_used--;
+ }
+
+ virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note);
+};
+
+
+/* CloneTable */
+struct CloneTable : public Table<Clone> {
+ virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr);
+ virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
+
+ virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+
+/* NodeTable */
+struct NodeTable : public Table<Node> {
+ virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr);
+ virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
+
+ virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+
+/* ListTable */
+struct ListTable : public Table<List> {
+ virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr);
+ virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note);
+
+ virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+
+/* HunkTable */
+struct HunkTable : public Table<Hunk> {
+ virtual void freeEntry(int idx) {
+ Table<Hunk>::freeEntry(idx);
+
+ free(_table[idx].mem);
+ }
+
+ virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+
+// Free-style memory
+struct DynMem : public MemObject {
+ int _size;
+ char *_description;
+ byte *_buf;
+
+public:
+ DynMem() : _size(0), _description(0), _buf(0) {}
+ ~DynMem() {
+ free(_description);
+ _description = NULL;
+ free(_buf);
+ _buf = NULL;
+ }
+
+ virtual byte *dereference(reg_t pointer, int *size);
+ virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr);
+ virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note);
+
+ virtual void saveLoadWithSerializer(Common::Serializer &ser);
+};
+
+
+} // End of namespace Sci
+
+#endif // SCI_ENGINE_VM_H