/* 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_SEGMAN_H #define SCI_ENGINE_SEGMAN_H #include "common/scummsys.h" #include "common/serializer.h" #include "sci/engine/vm.h" #include "sci/engine/segment.h" namespace Sci { /** * Verify the the given condition is true, output the message if condition is false, and exit. * @param cond condition to be verified * @param msg the message to be printed if condition fails */ #define VERIFY( cond, msg ) if (!(cond)) {\ error("%s, line, %d, %s", __FILE__, __LINE__, msg); \ } /** * Parameters for getScriptSegment(). */ enum ScriptLoadType { SCRIPT_GET_DONT_LOAD = 0, /**< Fail if not loaded */ SCRIPT_GET_LOAD = 1, /**< Load, if neccessary */ SCRIPT_GET_LOCK = 3 /**< Load, if neccessary, and lock */ }; class SegManager : public Common::Serializable { friend class Console; public: /** * Initialize the segment manager. */ SegManager(ResourceManager *resMan); /** * Deallocate all memory associated with the segment manager. */ ~SegManager(); void resetSegMan(); virtual void saveLoadWithSerializer(Common::Serializer &ser); // 1. Scripts /** * Allocate a script into the segment manager. * @param script_nr The number of the script to load * @param seg_id The segment ID of the newly allocated segment, * on success * @return 0 on failure, 1 on success */ Script *allocateScript(int script_nr, SegmentId *seg_id); // The script must then be initialised; see section (1b.), below. /** * Forcefully deallocate a previously allocated script. * @param script_nr number of the script to deallocate */ void deallocateScript(int script_nr); /** * Reconstructs scripts. Used when restoring saved games */ void reconstructScripts(EngineState *s); /** * Reconstructs the stack. Used when restoring saved games */ void reconstructStack(EngineState *s); /** * Determines the segment occupied by a certain script, if any. * @param script_nr Number of the script to look up * @return The script's segment ID, or 0 on failure */ SegmentId getScriptSegment(int script_nr) const; /** * Determines the segment occupied by a certain script. Optionally * load it, or load & lock it. * @param[in] script_nr Number of the script to look up * @param[in] load flag determining whether to load/lock the script * @return The script's segment ID, or 0 on failure */ SegmentId getScriptSegment(int script_nr, ScriptLoadType load); // TODO: document this reg_t getClassAddress(int classnr, ScriptLoadType lock, reg_t caller); /** * Return a pointer to the specified script. * If the id is invalid, does not refer to a script or the script is * not loaded, this will invoke error(). * @param seg ID of the script segment to check for * @return A pointer to the Script object */ Script *getScript(SegmentId seg); /** * Return a pointer to the specified script. * If the id is invalid, does not refer to a script, or * the script is not loaded, this will return NULL * @param seg ID of the script segment to check for * @return A pointer to the Script object, or NULL */ Script *getScriptIfLoaded(SegmentId seg); // 1b. Script Initialisation // The set of functions below are intended // to be used during script instantiation, // i.e. loading and linking. /** * Initializes a script's local variable block according to a prototype * @param segmentId Segment containing the script to initialize */ void scriptInitialiseLocals(SegmentId segmentId); // 2. Clones /** * Allocate a fresh clone * @param addr The offset of the freshly allocated clone * @return Reference to the memory allocated for the clone */ Clone *allocateClone(reg_t *addr); /** * Reconstructs clones. Used when restoring saved games */ void reconstructClones(); // 4. Stack /** * Allocates a data stack * @param size Number of stack entries to reserve * @param segid Segment ID of the stack * @return The physical stack */ DataStack *allocateStack(int size, SegmentId *segid); // 5. System Strings /** * Initializes the system string table. */ void initSysStrings(); // 6, 7. Lists and Nodes /** * Allocate a fresh list * @param[in] addr The offset of the freshly allocated list * @return Reference to the memory allocated for the list */ List *allocateList(reg_t *addr); /** * Allocate a fresh node * @param[in] addr The offset of the freshly allocated node * @return Reference to the memory allocated for the node */ Node *allocateNode(reg_t *addr); /** * Allocate and initialize a new list node. * @param[in] value The value to set the node to * @param[in] key The key to set * @return Pointer to the newly initialized list node */ reg_t newNode(reg_t value, reg_t key); /** * Resolves a list pointer to a list. * @param addr The address to resolve * @return The list referenced, or NULL on error */ List *lookupList(reg_t addr); /** * Resolves an address into a list node. * @param addr The address to resolve * @return The list node referenced, or NULL on error */ Node *lookupNode(reg_t addr); // 8. Hunk Memory /** * Allocate a fresh chunk of the hunk * @param[in] size Number of bytes to allocate for the hunk entry * @param[in] hunk_type A descriptive string for the hunk entry, for * debugging purposes * @return The offset of the freshly allocated hunk entry */ reg_t allocateHunkEntry(const char *hunk_type, int size); /** * Deallocates a hunk entry * @param[in] addr Offset of the hunk entry to delete */ void freeHunkEntry(reg_t addr); /** * Gets a pointer to the hunk memory referenced by a specified handle * @param[in] addr Offset of the hunk entry */ byte *getHunkPointer(reg_t addr); // 9. Dynamic Memory /** * Allocate some dynamic memory * @param[in] size Number of bytes to allocate * @param[in] description A descriptive string for debugging purposes * @param[out] addr The offset of the freshly allocated X * @return Raw pointer into the allocated dynamic * memory */ byte *allocDynmem(int size, const char *description, reg_t *addr); /** * Deallocates a piece of dynamic memory * @param[in] addr Offset of the dynmem chunk to free */ int freeDynmem(reg_t addr); // Generic Operations on Segments and Addresses /** * Dereferences a raw memory pointer * @param[in] reg The reference to dereference * @return The data block referenced */ SegmentRef dereference(reg_t pointer); /** * Dereferences a heap pointer pointing to raw memory. * @param pointer The pointer to dereference * @parm entries The number of values expected (for checkingO * @return A physical reference to the address pointed to, or NULL on error or * if not enough entries were available. */ byte *derefBulkPtr(reg_t pointer, int entries); /** * Dereferences a heap pointer pointing to a (list of) register(s). * Ensures alignedness of data. * @param pointer The pointer to dereference * @parm entries The number of values expected (for checking) * @return A physical reference to the address pointed to, or NULL on error or * if not enough entries were available. */ reg_t *derefRegPtr(reg_t pointer, int entries); /** * Dereferences a heap pointer pointing to raw memory. * @param pointer The pointer to dereference * @parm entries The number of values expected (for checking) * @return A physical reference to the address pointed to, or NULL on error or * if not enough entries were available. */ char *derefString(reg_t pointer, int entries = 0); /** * Return the string referenced by pointer. * pointer can point to either a raw or non-raw segment. * @param pointer The pointer to dereference * @parm entries The number of values expected (for checking) * @return The string referenced, or an empty string if not enough * entries were available. */ Common::String getString(reg_t pointer, int entries = 0); /** * Copies a string from src to dest. * src and dest can point to raw and non-raw segments. * Conversion is performed as required. */ void strcpy(reg_t dest, reg_t src); /** * Copies a string from src to dest. * dest can point to a raw or non-raw segment. * Conversion is performed as required. */ void strcpy(reg_t dest, const char *src); /** * Copies a string from src to dest. * src and dest can point to raw and non-raw segments. * Conversion is performed as required. At most n characters are copied. * TODO: determine if dest should always be null-terminated. */ void strncpy(reg_t dest, reg_t src, size_t n); /** * Copies a string from src to dest. * dest can point to a raw or non-raw segment. * Conversion is performed as required. At most n characters are copied. * TODO: determine if dest should always be null-terminated. */ void strncpy(reg_t dest, const char *src, size_t n); /** * Copies n bytes of data from src to dest. * src and dest can point to raw and non-raw segments. * Conversion is performed as required. */ void memcpy(reg_t dest, reg_t src, size_t n); /** * Copies n bytes of data from src to dest. * dest can point to a raw or non-raw segment. * Conversion is performed as required. */ void memcpy(reg_t dest, const byte* src, size_t n); /** * Copies n bytes of data from src to dest. * src can point to raw and non-raw segments. * Conversion is performed as required. */ void memcpy(byte *dest, reg_t src, size_t n); /** * Determine length of string at str. * str can point to a raw or non-raw segment. */ size_t strlen(reg_t str); /** * Finds a unique segment by type * @param type The type of the segment to find * @return The segment number, or -1 if the segment wasn't found */ SegmentId findSegmentByType(int type); // TODO: document this SegmentObj *getSegmentObj(SegmentId seg); // TODO: document this SegmentType getSegmentType(SegmentId seg); // TODO: document this SegmentObj *getSegment(SegmentId seg, SegmentType type); /** * Retrieves an object from the specified location * @param[in] offset Location (segment, offset) of the object * @return The object in question, or NULL if there is none */ Object *getObject(reg_t pos); /** * Checks whether a heap address contains an object * @parm obj The address to check * @return True if it is an object, false otherwise */ bool isObject(reg_t obj) { return getObject(obj) != NULL; } // TODO: document this bool isHeapObject(reg_t pos); /** * Determines the name of an object * @param[in] pos Location (segment, offset) of the object * @return A name for that object, or a string describing an error * that occurred while looking it up. The string is stored * in a static buffer and need not be freed (neither may * it be modified). */ const char *getObjectName(reg_t pos); /** * Find the address of an object by its name. In case multiple objects * with the same name occur, the optional index parameter can be used * to distinguish between them. If index is -1, then if there is a * unique object with the specified name, its address is returned; * if there are multiple matches, or none, then NULL_REG is returned. * * @param name the name of the object we are looking for * @param index the index of the object in case there are multiple * @return the address of the object, or NULL_REG */ reg_t findObjectByName(const Common::String &name, int index = -1); void scriptInitialiseClasses(SegmentId seg); void scriptInitialiseObjectsSci0(SegmentId seg); void scriptInitialiseObjectsSci11(SegmentId seg); uint32 classTableSize() { return _classTable.size(); } Class getClass(int index) { return _classTable[index]; } void setClassOffset(int index, reg_t offset) { _classTable[index].reg = offset; } void resizeClassTable(uint32 size) { _classTable.resize(size); } /** * Obtains the system strings segment ID */ SegmentId getSysStringsSegment() { return sysStringsSegment; } public: // TODO: make private Common::Array _heap; // Only accessible from saveLoadWithSerializer() Common::Array _classTable; /**< Table of all classes */ #ifdef ENABLE_SCI32 SciArray *allocateArray(reg_t *addr); SciArray *lookupArray(reg_t addr); void freeArray(reg_t addr); SciString *allocateString(reg_t *addr); SciString *lookupString(reg_t addr); void freeString(reg_t addr); SegmentId getStringSegmentId() { return String_seg_id; } #endif private: /** Map script ids to segment ids. */ Common::HashMap _scriptSegMap; ResourceManager *_resMan; SegmentId Clones_seg_id; ///< ID of the (a) clones segment SegmentId Lists_seg_id; ///< ID of the (a) list segment SegmentId Nodes_seg_id; ///< ID of the (a) node segment SegmentId Hunks_seg_id; ///< ID of the (a) hunk segment /* System strings */ SegmentId sysStringsSegment; public: // TODO: make private. Only kString() needs direct access SystemStrings *sysStrings; private: #ifdef ENABLE_SCI32 SegmentId Arrays_seg_id; SegmentId String_seg_id; #endif private: SegmentObj *allocSegment(SegmentObj *mem, SegmentId *segid); LocalVariables *allocLocalsSegment(Script *scr); int deallocate(SegmentId seg, bool recursive); void createClassTable(); SegmentId findFreeSegment() const; /** * Check segment validity * @param[in] seg The segment to validate * @return false if 'seg' is an invalid segment, true if * 'seg' is a valid segment */ bool check(SegmentId seg); }; } // End of namespace Sci #endif // SCI_ENGINE_SEGMAN_H