[Scummvm-cvs-logs] SF.net SVN: scummvm:[39430] scummvm/trunk

fingolfin at users.sourceforge.net fingolfin at users.sourceforge.net
Sun Mar 15 21:31:29 CET 2009


Revision: 39430
          http://scummvm.svn.sourceforge.net/scummvm/?rev=39430&view=rev
Author:   fingolfin
Date:     2009-03-15 20:31:29 +0000 (Sun, 15 Mar 2009)

Log Message:
-----------
SCI: Rewrote the save/load code, see also patch #2687400.

The new format is incompatible with the old one, and is still subject to
some further changes. Also, regressions are quite possible, so watch out.
Finally, the new code still contains some TODOs and FIXMEs. Several of
these will be more or less automatically resolved once other code gets
C++ified.

Modified Paths:
--------------
    scummvm/trunk/engines/sci/engine/intmap.cpp
    scummvm/trunk/engines/sci/engine/intmap.h
    scummvm/trunk/engines/sci/engine/savegame.cpp
    scummvm/trunk/engines/sci/engine/state.cpp
    scummvm/trunk/engines/sci/engine/state.h
    scummvm/trunk/engines/sci/module.mk

Removed Paths:
-------------
    scummvm/trunk/engines/sci/engine/savegame.cfsml
    scummvm/trunk/tools/sci/cfsml.pl

Modified: scummvm/trunk/engines/sci/engine/intmap.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/intmap.cpp	2009-03-15 20:31:15 UTC (rev 39429)
+++ scummvm/trunk/engines/sci/engine/intmap.cpp	2009-03-15 20:31:29 UTC (rev 39430)
@@ -45,15 +45,20 @@
 
 
 IntMapper::~IntMapper() {
-	int i;
+	clear();
 
-	for (i = 0; i < DCS_INT_HASH_MAX; i++)
+	// Trigger problems for people who forget to loose the reference
+	base_value = -42000;
+}
+
+void IntMapper::clear() {
+	for (int i = 0; i < DCS_INT_HASH_MAX; i++) {
 		free_node_recursive(nodes[i]);
+		nodes[i] = 0;
+	}
 
 	free_node_recursive(holes);
-
-	// Trigger problems for people who forget to loose the reference
-	base_value = -42000;
+	holes = 0;
 }
 
 int IntMapper::checkKey(int key, bool add, bool *was_added) {
@@ -91,6 +96,51 @@
 	return (*node)->idx;
 }
 
+void IntMapper::saveLoadWithSerializer(Common::Serializer &s) {
+	s.syncAsSint32LE(base_value);
+	if (s.isLoading()) {
+		uint32 key, idx;
+		clear();
+		while (true) {
+			s.syncAsSint32LE(key);
+			if (key == 0xDEADBEEF)
+				break;
+			s.syncAsSint32LE(idx);
+			// Insert into the IntMapper
+			insert(key, idx);
+		}
+	} else {
+		// Just write out all mapped pairs
+		// We terminate by writing 4 times the value 0xFF
+		for (int i = 0; i < DCS_INT_HASH_MAX; ++i) {
+			Node *node = nodes[i];
+
+			while (node) {
+				s.syncAsSint32LE(node->key);
+				s.syncAsSint32LE(node->idx);
+				node = node->next;
+			}
+		}
+		uint32 tmp = 0xDEADBEEF;
+		s.syncAsSint32LE(tmp);
+	}
+}
+
+void IntMapper::insert(int key, int idx) {
+	Node **node = &(nodes[HASH(key)]);
+
+	while (*node && (key != (*node)->key))
+		node = &((*node)->next);
+
+	assert(0 == *node);	// Error out if the key was already present.
+
+	*node = (Node*)malloc(sizeof(Node));
+	(*node)->key = key;
+	(*node)->idx = idx;
+	(*node)->next = NULL;
+}
+
+
 int IntMapper::removeKey(int key) {
 	Node **node = &(nodes[HASH(key)]);
 

Modified: scummvm/trunk/engines/sci/engine/intmap.h
===================================================================
--- scummvm/trunk/engines/sci/engine/intmap.h	2009-03-15 20:31:15 UTC (rev 39429)
+++ scummvm/trunk/engines/sci/engine/intmap.h	2009-03-15 20:31:29 UTC (rev 39430)
@@ -27,6 +27,7 @@
 #define SCI_ENGINE_INTMAP_H
 
 #include "common/scummsys.h"
+#include "common/serializer.h"
 
 namespace Sci {
 
@@ -50,8 +51,13 @@
  * All in all, this implementation is not very elegant, and wastes memory.
  * But it does the job. Any rewrite of this class would have to provide a
  * way to load the old savegames made using the current implementation.
+ *
+ * One approach to implement a replacement: Combine a Common::HashMap<int,int>
+ * with a bitfield which track which low-value integers are in use.
+ * That way, lookup just invokes the hashmap, and insertion (which requires
+ * finding an unmapped low-value integer) can still be implemented efficiently.
  */
-struct IntMapper {
+struct IntMapper : public Common::Serializable {
 
 	struct Node {
 		int key;
@@ -66,11 +72,17 @@
 				     ** to base_value  */
 
 	void free_node_recursive(Node *node);
+protected:
+	void insert(int key, int idx);	// For loading only
 
 public:
 	IntMapper();
 	~IntMapper();
 
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
+
+	void clear();
+
 	/**
 	 * Checks whether a key is in the map, adds it if neccessary.
 	 * @param value		The key to check for/add

Deleted: scummvm/trunk/engines/sci/engine/savegame.cfsml
===================================================================
--- scummvm/trunk/engines/sci/engine/savegame.cfsml	2009-03-15 20:31:15 UTC (rev 39429)
+++ scummvm/trunk/engines/sci/engine/savegame.cfsml	2009-03-15 20:31:29 UTC (rev 39430)
@@ -1,1141 +0,0 @@
-/* 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$
- *
- */
-
-/* Savegame handling for EngineState structs. Makes heavy use of cfsml magic. */
-/* DON'T EDIT savegame.cpp ! Only modify savegame.cfsml, if something needs
-** to be changed. Refer to freesci/docs/misc/cfsml.spec if you don't understand
-** savegame.cfsml. If this doesn't solve your problem, contact the maintainer.
-*/
-
-#include <time.h>	// FIXME: For struct tm
-#include "common/stream.h"
-#include "common/system.h"
-#include "sci/sci_memory.h"
-#include "sci/gfx/operations.h"
-#include "sci/gfx/menubar.h"
-#include "sci/gfx/gfx_state_internal.h"	// required for gfxw_port_t, gfxw_container_t
-#include "sci/sfx/core.h"
-#include "sci/sfx/iterator.h"
-#include "sci/engine/state.h"
-#include "sci/engine/intmap.h"
-#include "sci/engine/savegame.h"
-
-#ifdef _WIN32
-#pragma warning( disable : 4101 )
-#endif
-
-namespace Sci {
-
-/* Missing:
-** - SFXdriver
-** - File input/output state (this is likely not to happen)
-*/
-
-
-const unsigned int PRINTFBUFLEN = 128;
-int WSprintf(Common::WriteStream* str, const char *format, ...) {
-	va_list args;
-	char buf[PRINTFBUFLEN]; // default buffer to prevent new in common case
-	char* writebuf = buf;
-
-	unsigned int s = PRINTFBUFLEN;
-	unsigned int outsize;
-	while (true) {
-		va_start(args, format);
-		outsize = vsnprintf(writebuf, s, format, args);
-		va_end(args);
-
-		if (outsize == s) {
-			if (s > 16384) { // there are limits...
-				delete[] writebuf;
-				warning("Saving failed: line much too long");
-				return 0;
-			}
-			s *= 2;
-			if (writebuf != buf) delete[] writebuf;
-			writebuf = new char[s];
-		} else {
-			break;
-		}
-	}
-
-	uint32 ret = str->write(writebuf, outsize);
-
-	if (writebuf != buf) delete[] writebuf;
-
-	return ret;
-}
-
-int SRSgetc(Common::SeekableReadStream* str) {
-	char c = str->readSByte();
-	if (str->err() || str->eos())
-		return EOF;
-	return c;
-}
-
-char* SRSgets(char* s, int size, Common::SeekableReadStream* str) {
-	return str->readLine_NEW(s, size);
-}
-
-
-void write_reg_t(Common::WriteStream *fh, reg_t const *foo) {
-	WSprintf(fh, PREG, PRINT_REG(*foo));
-}
-
-int read_reg_t(Common::SeekableReadStream *fh, reg_t *foo, const char *lastval, int *line, int *hiteof) {
-	unsigned int segment, offset;
-
-	if (sscanf(lastval, PREG, &segment, &offset) < 2) {
-		sciprintf("Error parsing reg_t on line %d\n", *line);
-		return 1;
-	}
-
-	*foo = make_reg(segment, offset);
-	return 0;
-}
-
-void write_sci_version(Common::WriteStream *fh, sci_version_t const *foo) {
-	WSprintf(fh, "%d.%03d.%03d", SCI_VERSION_MAJOR(*foo), SCI_VERSION_MINOR(*foo), SCI_VERSION_PATCHLEVEL(*foo));
-}
-
-int read_sci_version(Common::SeekableReadStream *fh, sci_version_t *foo, const char *lastval, int *line, int *hiteof) {
-	return version_parse(lastval, foo);
-}
-
-void write_CommonString(Common::WriteStream *fh, Common::String const *string);
-int read_CommonString(Common::SeekableReadStream *fh, Common::String *string, const char *lastval, int *line, int *hiteof);
-
-void write_menubar_tp(Common::WriteStream *fh, const menubar_t * const *foo);
-int read_menubar_tp(Common::SeekableReadStream *fh, menubar_t **foo, const char *lastval, int *line, int *hiteof);
-
-void write_MemObjPtr(Common::WriteStream *fh, const MemObject * const *foo);
-int read_MemObjPtr(Common::SeekableReadStream *fh, MemObject **foo, const char *lastval, int *line, int *hiteof);
-
-void write_songlib_t(Common::WriteStream *fh, songlib_t const *foo);
-int read_songlib_t(Common::SeekableReadStream *fh, songlib_t *foo, const char *lastval, int *line, int *hiteof);
-
-int read_song_tp(Common::SeekableReadStream *fh, song_t **foo, const char *lastval, int *line, int *hiteof);
-
-void write_IntMapperPtr(Common::WriteStream *fh, const IntMapper * const *foo);
-int read_IntMapperPtr(Common::SeekableReadStream *fh, IntMapper **foo, const char *lastval, int *line, int *hiteof);
-
-void write_IntMapperNodePtr(Common::WriteStream *fh, const IntMapper::Node * const *foo);
-int read_IntMapperNodePtr(Common::SeekableReadStream *fh, IntMapper::Node **foo, const char *lastval, int *line, int *hiteof);
-
-void write_SegManagerPtr(Common::WriteStream *fh, const SegManager * const *foo);
-int read_SegManagerPtr(Common::SeekableReadStream *fh, SegManager **foo, const char *lastval, int *line, int *hiteof);
-
-typedef MemObject *mem_obj_ptr;
-
-// Unused types
-/*
-TYPE long "long" LIKE int;
-TYPE int16 "int16" LIKE int;
-
-RECORD synonym_t "synonym_t" {
-	int replaceant;
-	int replacement;
-}
-*/
-
-%CFSML
-
-TYPE bool "bool" LIKE int;
-TYPE byte "byte" LIKE int;
-TYPE Common::String ""Common::String" USING write_CommonString read_CommonString;
-TYPE SegmentId "SegmentId" LIKE int;
-TYPE sci_version_t "sci_version_t" USING write_sci_version read_sci_version;
-TYPE menubar_tp "menubar_t *" USING write_menubar_tp read_menubar_tp;
-TYPE MemObject "MemObject" USING write_MemObject read_MemObject;
-TYPE mem_obj_ptr "MemObject *" USING write_MemObjPtr read_MemObjPtr;
-TYPE reg_t "reg_t" USING write_reg_t read_reg_t;
-TYPE size_t "size_t" LIKE int;
-TYPE IntMapperPtr "IntMapper *" USING write_IntMapperPtr read_IntMapperPtr;
-TYPE IntMapperNodePtr "IntMapper::Node *" USING write_IntMapperNodePtr read_IntMapperNodePtr;
-TYPE songlib_t "songlib_t" USING write_songlib_t read_songlib_t;
-TYPE song_tp "song_t *" USING write_song_tp read_song_tp;
-TYPE song_handle_t "song_handle_t" LIKE int;
-TYPE SegManagerPtr "SegManager *" USING write_SegManagerPtr read_SegManagerPtr;
-
-RECORD song_t "song_t" {
-	song_handle_t handle;
-	int resource_num;
-	int priority;
-	int status;
-	int restore_behavior;
-	int restore_time;
-	int loops;
-	int hold;
-}
-
-RECORD IntMapper "IntMapper" {
-	int base_value;
-	IntMapperNodePtr nodes[STATIC DCS_INT_HASH_MAX];
-}
-
-RECORD menu_item_t "menu_item_t" {
-	int type;
-	string keytext;
-	int keytext_size;
-
-	int flags;
-	byte said[STATIC MENU_SAID_SPEC_SIZE];
-	reg_t said_pos;
-	string text;
-	reg_t text_pos;
-	int modifiers;
-	int key;
-	int enabled;
-	int tag;
-}
-
-RECORD menu_t "menu_t" {
-	string title;
-	int title_width;
-	int width;
-
-	menu_item_t items[DYNAMIC items_nr];
-}
-
-RECORD menubar_t "menubar_t" {
-	menu_t menus[DYNAMIC menus_nr];
-}
-
-RECORD SegManager "SegManager" {
-	IntMapperPtr id_seg_map;
-	mem_obj_ptr heap[DYNAMIC heap_size];
-	int heap_size;
-	int reserved_id;
-	int exports_wide;
-	int gc_mark_bits;
-	size_t mem_allocated;
-	SegmentId Clones_seg_id;
-	SegmentId Lists_seg_id;
-	SegmentId Nodes_seg_id;
-}
-
-RECORD Class "Class" {
-	int script;
-	reg_t reg;
-}
-
-RECORD sfx_state_t "sfx_state_t" {
-	songlib_t songlib;
-}
-
-RECORD SavegameMetadata "SavegameMetadata" {
-	Common::String savegame_name;
-	int savegame_version;
-	Common::String game_version;
-	sci_version_t version;
-	int savegame_date;
-	int savegame_time;
-}
-
-RECORD EngineState "EngineState" {
-	int savegame_version;
-
-	string game_version;
-	sci_version_t version;
-	menubar_tp menubar;
-	int status_bar_foreground;
-	int status_bar_background;
-	SegManagerPtr seg_manager;
-	int classtable_size;
-	Class classtable[DYNAMIC classtable_size];
-	sfx_state_t sound;
-}
-
-RECORD LocalVariables "LocalVariables" {
-	int script_id;
-	int nr;
-	reg_t locals[DYNAMIC nr];
-}
-
-RECORD Object "Object" {
-	int flags;
-	reg_t pos;
-	int variables_nr;
-	int variable_names_nr;
-	int methods_nr;
-	reg_t variables[DYNAMIC variables_nr];
-}
-
-RECORD Clone "Clone" {
-	int flags;
-	reg_t pos;
-	int variables_nr;
-	int variable_names_nr;
-	int methods_nr;
-	reg_t variables[DYNAMIC variables_nr];
-}
-
-RECORD List "List" {
-	reg_t first;
-	reg_t last;
-}
-
-RECORD Node "Node" {
-	reg_t pred;
-	reg_t succ;
-	reg_t key;
-	reg_t value;
-}
-
-RECORD CloneEntry "CloneEntry" {
-	int next_free;
-	Clone entry;
-}
-
-RECORD CloneTable "CloneTable" {
-	int entries_nr;
-	int first_free;
-	int entries_used;
-	int max_entry;
-	CloneEntry table[DYNAMIC entries_nr];
-}
-
-RECORD ListEntry "ListEntry" {
-	int next_free;
-	List entry;
-}
-
-RECORD ListTable "ListTable" {
-	int entries_nr;
-	int first_free;
-	int entries_used;
-	int max_entry;
-	ListEntry table[DYNAMIC entries_nr];
-}
-
-RECORD NodeEntry "NodeEntry" {
-	int next_free;
-	Node entry;
-}
-
-RECORD NodeTable "NodeTable" {
-	int entries_nr;
-	int first_free;
-	int entries_used;
-	int max_entry;
-	NodeEntry table[DYNAMIC entries_nr];
-}
-
-RECORD Script "Script" {
-	int nr;
-
-	size_t buf_size;
-	size_t script_size;
-	size_t heap_size;
-
-	IntMapperPtr obj_indices;
-	int exports_nr;
-	int synonyms_nr;
-	int lockers;
-	int objects_allocated;
-	int objects_nr;
-	Object objects[DYNAMIC objects_allocated];
-
-	int locals_offset;
-	int locals_segment;
-
-	int marked_as_deleted;
-}
-
-RECORD SystemString "SystemString" {
-	string name;
-	int max_size;
-	string value;
-}
-
-RECORD SystemStrings "SystemStrings" {
-	SystemString strings[STATIC SYS_STRINGS_MAX];
-}
-
-RECORD DynMem "DynMem" {
-	int size;
-	string description;
-	byte buf[DYNAMIC size];
-}
-
-%END CFSML
-
-void write_songlib_t(Common::WriteStream *fh, songlib_t const *songlib) {
-	song_t *seeker = *(songlib->lib);
-	int songcount = song_lib_count(*songlib);
-
-	WSprintf(fh, "{\n");
-	WSprintf(fh, "songcount = %d\n", songcount);
-	WSprintf(fh, "list = \n");
-	WSprintf(fh, "[\n");
-	while (seeker) {
-		seeker->restore_time = seeker->it->getTimepos();
-		%CFSMLWRITE song_t seeker INTO fh;
-		seeker = seeker->next;
-	}
-	WSprintf(fh, "]\n");
-	WSprintf(fh, "}\n");
-}
-
-int read_songlib_t(Common::SeekableReadStream *fh, songlib_t *songlib, const char *lastval, int *line, int *hiteof) {
-	int songcount;
-	int i;
-	song_t *newsong;
-
-	if (strcmp(lastval, "{")) {
-		_cfsml_error("Opening brackets expected at line %d\n", *line);
-		return CFSML_FAILURE;
-	}
-	// FIXME: error checking
-	Common::String l = fh->readLine();
-	sscanf(l.c_str(), "songcount = %d", &songcount);
-	l = fh->readLine(); // "list = "
-	l = fh->readLine(); // "["
-	*line += 4;
-	song_lib_init(songlib);
-	for (i = 0; i < songcount; i++) {
-		%CFSMLREAD song_tp &newsong FROM fh ERRVAR *hiteof FIRSTTOKEN lastval LINECOUNTER *line;
-		song_lib_add(*songlib, newsong);
-	}
-	l = fh->readLine(); // "]"
-	l = fh->readLine(); // "}"
-	*line += 2;
-	return 0;
-}
-
-void write_song_tp(Common::WriteStream *fh, const song_t * const *foo) {
-	%CFSMLWRITE song_t *foo INTO fh;
-}
-
-SongIterator *build_iterator(EngineState *s, int song_nr, int type, songit_id_t id);
-
-int read_song_tp(Common::SeekableReadStream *fh, song_t **foo, const char *lastval, int *line, int *hiteof) {
-	char *token;
-	int assignment;
-	*foo = (song_t*) malloc(sizeof(song_t));
-	token = _cfsml_get_identifier(fh, line, hiteof, &assignment);
-	%CFSMLREAD song_t (*foo) FROM fh ERRVAR *hiteof FIRSTTOKEN token LINECOUNTER *line;
-	(*foo)->_delay = 0;
-	(*foo)->it = NULL;
-	(*foo)->next_playing = (*foo)->next_stopping = (*foo)->next = NULL;
-	return 0;
-}
-
-void write_IntMapperPtr(Common::WriteStream *fh, const IntMapper * const *foo) {
-	%CFSMLWRITE IntMapper *foo INTO fh;
-}
-
-int read_IntMapperPtr(Common::SeekableReadStream *fh, IntMapper **foo, const char *lastval, int *line, int *hiteof) {
-	*foo = new IntMapper();
-	%CFSMLREAD IntMapper (*foo) FROM fh ERRVAR *hiteof FIRSTTOKEN lastval LINECOUNTER *line;
-	(*foo)->holes = NULL;
-	return 0;
-}
-
-void write_IntMapperNodePtr(Common::WriteStream *fh, const IntMapper::Node * const *foo) {
-	if (!(*foo)) {
-		WSprintf(fh, "\\null");
-	} else {
-		WSprintf(fh,"[\n%d=>%d\n", (*foo)->key, (*foo)->idx);
-		if ((*foo)->next) {
-			%CFSMLWRITE IntMapperNodePtr &((*foo)->next) INTO fh;
-		} else
-			WSprintf(fh, "L");
-		WSprintf(fh, "]");
-	}
-}
-
-int read_IntMapperNodePtr(Common::SeekableReadStream *fh, IntMapper::Node **foo, const char *lastval, int *line, int *hiteof) {
-	static char buffer[80];
-
-	if (lastval[0] == '\\') {
-		*foo = NULL; // No hash map node
-	} else {
-		*foo = (IntMapper::Node*)malloc(sizeof(IntMapper::Node));
-		if (lastval[0] != '[') {
-			sciprintf("Expected opening bracket in hash_map_node_t on line %d\n", *line);
-			return 1;
-		}
-
-		do {
-			(*line)++;
-			SRSgets(buffer, 80, fh);
-			if (buffer[0] == 'L') {
-				(*foo)->next = NULL;
-				buffer[0] = buffer[1];
-			} // HACK: deliberately no else clause here
-			if (buffer[0] == ']')  {
-				break;
-			} else if (buffer[0] == '[') {
-				if (read_IntMapperNodePtr(fh, &((*foo)->next), buffer, line, hiteof))
-					return 1;
-			} else if (sscanf(buffer, "%d=>%d", &((*foo)->key), &((*foo)->idx))<2) {
-				sciprintf("Error parsing hash_map_node_t on line %d\n", *line);
-				return 1;
-			}
-		} while (1);
-	}
-
-	return 0;
-}
-
-void write_menubar_tp(Common::WriteStream *fh, const menubar_t * const *foo) {
-	if (*foo) {
-		%CFSMLWRITE menubar_t (*foo) INTO fh;
-	} else { // Nothing to write
-		WSprintf(fh, "\\null\\");
-	}
-}
-
-
-int read_menubar_tp(Common::SeekableReadStream *fh, menubar_t **foo, const char *lastval, int *line, int *hiteof) {
-	if (lastval[0] == '\\') {
-		*foo = NULL; // No menu bar
-	} else {
-		*foo = (menubar_t *) sci_malloc(sizeof(menubar_t));
-		%CFSMLREAD menubar_t (*foo) FROM fh ERRVAR *hiteof FIRSTTOKEN lastval LINECOUNTER *line;
-	}
-	return *hiteof;
-}
-
-static struct {
-	int type;
-	const char *name;
-} mem_obj_string_names[] = {
-	{MEM_OBJ_INVALID, "INVALID"},
-	{MEM_OBJ_SCRIPT, "SCRIPT"},
-	{MEM_OBJ_CLONES, "CLONES"},
-	{MEM_OBJ_LOCALS, "LOCALS"},
-	{MEM_OBJ_STACK, "STACK"},
-	{MEM_OBJ_SYS_STRINGS,"SYS_STRINGS"},
-	{MEM_OBJ_LISTS,"LISTS"},
-	{MEM_OBJ_NODES,"NODES"},
-	{MEM_OBJ_HUNK,"HUNK"},
-	{MEM_OBJ_DYNMEM,"DYNMEM"},
-	{MEM_OBJ_STRING_FRAG,"STRING_FRAGS"},
-};
-
-int mem_obj_string_to_enum(const char *str) {
-	int i;
-
-	for (i = 0; i <= MEM_OBJ_MAX; i++) {
-		if (!scumm_stricmp(mem_obj_string_names[i].name, str))
-			return i;
-	}
-
-	return -1;
-}
-
-void write_MemObject(Common::WriteStream *fh, MemObject const *foo) {
-	WSprintf(fh, "%s\n", mem_obj_string_names[foo->type].name);
-	%CFSMLWRITE int &foo->segmgr_id INTO fh;
-	switch (foo->type) {
-	case MEM_OBJ_SCRIPT:
-		%CFSMLWRITE Script &foo->data.script INTO fh;
-		break;
-	case MEM_OBJ_CLONES:
-		%CFSMLWRITE CloneTable &foo->data.clones INTO fh;
-		break;
-	case MEM_OBJ_LOCALS:
-		%CFSMLWRITE LocalVariables &foo->data.locals INTO fh;
-		break;
-	case MEM_OBJ_SYS_STRINGS:
-		%CFSMLWRITE SystemStrings &foo->data.sys_strings INTO fh;
-		break;
-	case MEM_OBJ_STACK:
-		%CFSMLWRITE int &foo->data.stack.nr INTO fh;
-		break;
-	case MEM_OBJ_HUNK:
-		break;
-	case MEM_OBJ_STRING_FRAG:
-		break;
-	case MEM_OBJ_LISTS:
-		%CFSMLWRITE ListTable &foo->data.lists INTO fh;
-		break;
-	case MEM_OBJ_NODES:
-		%CFSMLWRITE NodeTable &foo->data.nodes INTO fh;
-		break;
-	case MEM_OBJ_DYNMEM:
-		%CFSMLWRITE DynMem  &foo->data.dynmem INTO fh;
-		break;
-	default:
-		break;
-	}
-}
-
-int read_MemObject(Common::SeekableReadStream *fh, MemObject *foo, const char *lastval, int *line, int *hiteof) {
-	foo->type = (memObjType)mem_obj_string_to_enum(lastval);
-	if (foo->type < 0) {
-		sciprintf("Unknown MemObject type %s on line %d\n", lastval, *line);
-		return 1;
-	}
-
-	%CFSMLREAD int &foo->segmgr_id FROM fh ERRVAR *hiteof LINECOUNTER *line;
-	switch (foo->type) {
-	case MEM_OBJ_SCRIPT:
-		%CFSMLREAD Script &foo->data.script FROM fh ERRVAR *hiteof LINECOUNTER *line;
-		break;
-	case MEM_OBJ_CLONES:
-		%CFSMLREAD CloneTable &foo->data.clones FROM fh ERRVAR *hiteof LINECOUNTER *line;
-		break;
-	case MEM_OBJ_LOCALS:
-		%CFSMLREAD LocalVariables &foo->data.locals FROM fh ERRVAR *hiteof LINECOUNTER *line;
-		break;
-	case MEM_OBJ_SYS_STRINGS:
-		%CFSMLREAD SystemStrings &foo->data.sys_strings FROM fh ERRVAR *hiteof LINECOUNTER *line;
-		break;
-	case MEM_OBJ_LISTS:
-		%CFSMLREAD ListTable &foo->data.lists FROM fh ERRVAR *hiteof LINECOUNTER *line;
-		break;
-	case MEM_OBJ_NODES:
-		%CFSMLREAD NodeTable &foo->data.nodes FROM fh ERRVAR *hiteof LINECOUNTER *line;
-		break;
-	case MEM_OBJ_STACK:
-		%CFSMLREAD int &foo->data.stack.nr FROM fh ERRVAR *hiteof LINECOUNTER *line;
-		foo->data.stack.entries = (reg_t *)sci_calloc(foo->data.stack.nr, sizeof(reg_t));
-		break;
-	case MEM_OBJ_HUNK:
-		init_Hunk_table(&foo->data.hunks);
-		break;
-	case MEM_OBJ_STRING_FRAG:
-		break;
-	case MEM_OBJ_DYNMEM:
-		%CFSMLREAD DynMem  &foo->data.dynmem FROM fh ERRVAR *hiteof LINECOUNTER *line;
-		break;
-	default:
-		break;
-	}
-
-	return *hiteof;
-}
-
-void write_MemObjPtr(Common::WriteStream *fh, const MemObject * const *foo) {
-	if (*foo) {
-		%CFSMLWRITE MemObject (*foo) INTO fh;
-	} else { // Nothing to write
-		WSprintf(fh, "\\null\\");
-	}
-}
-
-int read_MemObjPtr(Common::SeekableReadStream *fh, MemObject **foo, const char *lastval, int *line, int *hiteof) {
-	if (lastval[0] == '\\') {
-		*foo = NULL; // No menu bar
-	} else {
-		*foo = (MemObject *)sci_malloc(sizeof(MemObject));
-		%CFSMLREAD MemObject (*foo) FROM fh ERRVAR *hiteof FIRSTTOKEN lastval LINECOUNTER *line;
-		return *hiteof;
-	}
-	return 0;
-}
-
-void write_CommonString(Common::WriteStream *fh, Common::String const *string)
-{
-	const char *t = string->c_str();
-	%CFSMLWRITE string (&t) INTO fh;
-}
-
-int read_CommonString(Common::SeekableReadStream *fh, Common::String *string, const char *lastval, int *line, int *hiteof)
-{
-	char *t;
-	// Do an atomic read to prevent t from being freed if we hit an eof later
-	%CFSMLREAD-ATOMIC string (&t) FROM fh ERRVAR *hiteof FIRSTTOKEN lastval LINECOUNTER *line;
-	if (*hiteof) return *hiteof;
-	*string = t;
-	free(t);
-	return 0;
-}
-
-void write_SegManagerPtr(Common::WriteStream *fh, const SegManager * const *foo) {
-	%CFSMLWRITE bool &((*foo)->isSci1_1) INTO fh;
-	%CFSMLWRITE SegManager *foo INTO fh;
-}
-
-int read_SegManagerPtr(Common::SeekableReadStream *fh, SegManager **foo, const char *lastval, int *line, int *hiteof) {
-	char *token;
-	int assignment;
-	bool sci11;
-	%CFSMLREAD bool (&sci11) FROM fh ERRVAR *hiteof FIRSTTOKEN lastval LINECOUNTER *line;
-	*foo = new SegManager(sci11);
-	token = _cfsml_get_identifier(fh, line, hiteof, &assignment);
-	%CFSMLREAD SegManager (*foo) FROM fh ERRVAR *hiteof FIRSTTOKEN token LINECOUNTER *line;
-	return 0;
-}
-
-int gamestate_save(EngineState *s, Common::WriteStream *fh, const char* savename) {
-	tm curTime;
-	g_system->getTimeAndDate(curTime);
-
-	SavegameMetadata meta;
-	meta.savegame_version = FREESCI_CURRENT_SAVEGAME_VERSION;
-	meta.savegame_name = savename;
-	meta.version = s->version;
-	meta.game_version = s->game_version;
-	meta.savegame_date = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF);
-	meta.savegame_time = ((curTime.tm_hour & 0xFF) << 16) | (((curTime.tm_min) & 0xFF) << 8) | ((curTime.tm_sec) & 0xFF);
-
-	s->savegame_version = FREESCI_CURRENT_SAVEGAME_VERSION;
-	s->dyn_views_list_serial = (s->dyn_views)? s->dyn_views->serial : -2;
-	s->drop_views_list_serial = (s->drop_views)? s->drop_views->serial : -2;
-	s->port_serial = (s->port)? s->port->serial : -2;
-
-	if (s->execution_stack_base) {
-		sciprintf("Cannot save from below kernel function\n");
-		return 1;
-	}
-
-/*
-	if (s->sound_server) {
-		if ((s->sound_server->save)(s, dirname)) {
-			sciprintf("Saving failed for the sound subsystem\n");
-			chdir("..");
-			return 1;
-		}
-	}
-*/
-	// Calculate the time spent with this game
-	s->game_time = (g_system->getMillis() - s->game_start_time) / 1000;
-
-	%CFSMLWRITE SavegameMetadata (&meta) INTO fh;
-	%CFSMLWRITE EngineState s INTO fh;
-
-	return 0;
-}
-
-static SegmentId find_unique_seg_by_type(SegManager *self, int type) {
-	int i;
-
-	for (i = 0; i < self->heap_size; i++)
-		if (self->heap[i] &&
-		    self->heap[i]->type == type)
-			return i;
-	return -1;
-}
-
-static byte *find_unique_script_block(EngineState *s, byte *buf, int type) {
-	int magic_pos_adder = s->version >= SCI_VERSION_FTU_NEW_SCRIPT_HEADER ? 0 : 2;
-
-	buf += magic_pos_adder;
-	do {
-		int seeker_type = READ_LE_UINT16(buf);
-		int seeker_size;
-
-		if (seeker_type == 0) break;
-		if (seeker_type == type) return buf;
-
-		seeker_size = READ_LE_UINT16(buf + 2);
-		buf += seeker_size;
-	} while(1);
-
-	return NULL;
-}
-
-static void reconstruct_stack(EngineState *retval) {
-	SegmentId stack_seg = find_unique_seg_by_type(retval->seg_manager, MEM_OBJ_STACK);
-	dstack_t *stack = &(retval->seg_manager->heap[stack_seg]->data.stack);
-
-	retval->stack_segment = stack_seg;
-	retval->stack_base = stack->entries;
-	retval->stack_top = retval->stack_base + VM_STACK_SIZE;
-}
-
-static int clone_entry_used(CloneTable *table, int n) {
-	int backup;
-	int seeker = table->first_free;
-	CloneEntry *entries = table->table;
-
-	if (seeker == HEAPENTRY_INVALID) return 1;
-
-	do {
-		if (seeker == n) return 0;
-		backup = seeker;
-		seeker = entries[seeker].next_free;
-	} while (entries[backup].next_free != HEAPENTRY_INVALID);
-
-	return 1;
-}
-
-static void load_script(EngineState *s, SegmentId seg) {
-	Resource *script, *heap = NULL;
-	Script *scr = &(s->seg_manager->heap[seg]->data.script);
-
-	scr->buf = (byte *)malloc(scr->buf_size);
-
-	script = s->resmgr->findResource(kResourceTypeScript, scr->nr, 0);
-	if (s->version >= SCI_VERSION(1,001,000))
-		heap = s->resmgr->findResource(kResourceTypeHeap, scr->nr, 0);
-
-	switch (s->seg_manager->isSci1_1) {
-	case 0 :
-		s->seg_manager->mcpyInOut(0, script->data, script->size, seg, SEG_ID);
-		break;
-	case 1 :
-		s->seg_manager->mcpyInOut(0, script->data, script->size, seg, SEG_ID);
-		s->seg_manager->mcpyInOut(scr->script_size, heap->data, heap->size, seg, SEG_ID);
-		break;
-	}
-}
-
-static void reconstruct_scripts(EngineState *s, SegManager *self) {
-	int i;
-	MemObject *mobj;
-	for (i = 0; i < self->heap_size; i++) {
-		if (self->heap[i]) {
-			mobj = self->heap[i];
-			switch (mobj->type)  {
-			case MEM_OBJ_SCRIPT: {
-				int j;
-				Script *scr = &mobj->data.script;
-
-				load_script(s, i);
-				scr->locals_block = scr->locals_segment == 0 ? NULL : &s->seg_manager->heap[scr->locals_segment]->data.locals;
-				scr->export_table = (uint16 *) find_unique_script_block(s, scr->buf, sci_obj_exports);
-				scr->synonyms = find_unique_script_block(s, scr->buf, sci_obj_synonyms);
-				scr->code = NULL;
-				scr->code_blocks_nr = 0;
-				scr->code_blocks_allocated = 0;
-
-				if (!self->isSci1_1)
-					scr->export_table += 3;
-
-				for (j = 0; j < scr->objects_nr; j++) {
-					byte *data = scr->buf + scr->objects[j].pos.offset;
-					scr->objects[j].base = scr->buf;
-					scr->objects[j].base_obj = data;
-				}
-				break;
-			}
-			default:
-				break;
-			}
-		}
-	}
-
-	for (i = 0; i < self->heap_size; i++) {
-		if (self->heap[i]) {
-			mobj = self->heap[i];
-			switch (mobj->type)  {
-			case MEM_OBJ_SCRIPT: {
-				int j;
-				Script *scr = &mobj->data.script;
-
-				for (j = 0; j < scr->objects_nr; j++) {
-					byte *data = scr->buf + scr->objects[j].pos.offset;
-
-					if (self->isSci1_1) {
-						uint16 *funct_area = (uint16 *) (scr->buf + READ_LE_UINT16( data + 6 ));
-						uint16 *prop_area = (uint16 *) (scr->buf + READ_LE_UINT16( data + 4 ));
-
-						scr->objects[j].base_method = funct_area;
-						scr->objects[j].base_vars = prop_area;
-					} else {
-						int funct_area = READ_LE_UINT16( data + SCRIPT_FUNCTAREAPTR_OFFSET );
-						Object *base_obj;
-
-						base_obj = obj_get(s, scr->objects[j].variables[SCRIPT_SPECIES_SELECTOR]);
-
-						if (!base_obj) {
-							sciprintf("Object without a base class: Script %d, index %d (reg address "PREG"\n",
-								  scr->nr, j, PRINT_REG(scr->objects[j].variables[SCRIPT_SPECIES_SELECTOR]));
-							continue;
-						}
-						scr->objects[j].variable_names_nr = base_obj->variables_nr;
-						scr->objects[j].base_obj = base_obj->base_obj;
-
-						scr->objects[j].base_method = (uint16 *) (data + funct_area);
-						scr->objects[j].base_vars = (uint16 *) (data + scr->objects[j].variable_names_nr * 2 + SCRIPT_SELECTOR_OFFSET);
-					}
-				}
-				break;
-			}
-			default:
-				break;
-			}
-		}
-	}
-}
-
-void reconstruct_clones(EngineState *s, SegManager *self) {
-	int i;
-	MemObject *mobj;
-
-	for (i = 0; i < self->heap_size; i++) {
-		if (self->heap[i]) {
-			mobj = self->heap[i];
-			switch (mobj->type) {
-			case MEM_OBJ_CLONES: {
-				int j;
-				CloneEntry *seeker = mobj->data.clones.table;
-
-				sciprintf("Free list: ");
-				for (j = mobj->data.clones.first_free; j != HEAPENTRY_INVALID; j = mobj->data.clones.table[j].next_free) {
-					sciprintf("%d ", j);
-				}
-				sciprintf("\n");
-
-				sciprintf("Entries w/zero vars: ");
-				for (j = 0; j < mobj->data.clones.max_entry; j++) {
-					if (mobj->data.clones.table[j].entry.variables == NULL)
-						sciprintf("%d ", j);
-				}
-				sciprintf("\n");
-
-				for (j = 0; j < mobj->data.clones.max_entry; j++) {
-					Object *base_obj;
-
-					if (!clone_entry_used(&mobj->data.clones, j)) {
-						seeker++;
-						continue;
-					}
-					base_obj = obj_get(s, seeker->entry.variables[SCRIPT_SPECIES_SELECTOR]);
-					if (!base_obj) {
-						sciprintf("Clone entry without a base class: %d\n", j);
-						seeker->entry.base = seeker->entry.base_obj = NULL;
-						seeker->entry.base_vars = seeker->entry.base_method = NULL;
-						continue;
-					}
-					seeker->entry.base = base_obj->base;
-					seeker->entry.base_obj = base_obj->base_obj;
-					seeker->entry.base_vars = base_obj->base_vars;
-					seeker->entry.base_method = base_obj->base_method;
-
-					seeker++;
-				}
-
-				break;
-			}
-			default:
-				break;
-			}
-		}
-	}
-}
-
-int _reset_graphics_input(EngineState *s);
-
-static void reconstruct_sounds(EngineState *s) {
-	song_t *seeker;
-	int it_type = s->resmgr->_sciVersion >= SCI_VERSION_01 ? SCI_SONG_ITERATOR_TYPE_SCI1 : SCI_SONG_ITERATOR_TYPE_SCI0;
-
-	if (s->sound.songlib.lib)
-		seeker = *(s->sound.songlib.lib);
-	else {
-		song_lib_init(&s->sound.songlib);
-		seeker = NULL;
-	}
-
-	while (seeker) {
-		SongIterator *base, *ff;
-		int oldstatus;
-		SongIterator::Message msg;
-
-		base = ff = build_iterator(s, seeker->resource_num, it_type, seeker->handle);
-		if (seeker->restore_behavior == RESTORE_BEHAVIOR_CONTINUE)
-			ff = new_fast_forward_iterator(base, seeker->restore_time);
-		ff->init();
-
-		msg = SongIterator::Message(seeker->handle, SIMSG_SET_LOOPS(seeker->loops));
-		songit_handle_message(&ff, msg);
-		msg = SongIterator::Message(seeker->handle, SIMSG_SET_HOLD(seeker->hold));
-		songit_handle_message(&ff, msg);
-
-		oldstatus = seeker->status;
-		seeker->status = SOUND_STATUS_STOPPED;
-		seeker->it = ff;
-		sfx_song_set_status(&s->sound, seeker->handle, oldstatus);
-		seeker = seeker->next;
-	}
-}
-
-void internal_stringfrag_strncpy(EngineState *s, reg_t *dest, reg_t *src, int len);
-
-EngineState *gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
-	int read_eof = 0;
-	EngineState *retval;
-	songlib_t temp;
-
-/*
-	if (s->sound_server) {
-		if ((s->sound_server->restore)(s, dirname)) {
-			sciprintf("Restoring failed for the sound subsystem\n");
-			return NULL;
-		}
-	}
-*/
-
-	retval = new EngineState();
-
-	retval->savegame_version = -1;
-	retval->gfx_state = s->gfx_state;
-
-	SavegameMetadata meta;
-
-%CFSMLREAD-ATOMIC SavegameMetadata (&meta) FROM fh ERRVAR read_eof;
-
-	if (read_eof)
-		return false;
-
-	if ((meta.savegame_version < FREESCI_MINIMUM_SAVEGAME_VERSION) ||
-	    (meta.savegame_version > FREESCI_CURRENT_SAVEGAME_VERSION)) {
-		if (meta.savegame_version < FREESCI_MINIMUM_SAVEGAME_VERSION)
-			sciprintf("Old savegame version detected- can't load\n");
-		else
-			sciprintf("Savegame version is %d- maximum supported is %0d\n", meta.savegame_version, FREESCI_CURRENT_SAVEGAME_VERSION);
-
-		return NULL;
-	}
-
-	// Backwards compatibility settings
-	retval->dyn_views = NULL;
-	retval->drop_views = NULL;
-	retval->port = NULL;
-	retval->save_dir_copy_buf = NULL;
-
-	retval->sound_mute = s->sound_mute;
-	retval->sound_volume = s->sound_volume;
-
-	%CFSMLREAD-ATOMIC EngineState retval FROM fh ERRVAR read_eof;
-
-	sfx_exit(&s->sound);
-
-	// Set exec stack base to zero
-	retval->execution_stack_base = 0;
-	retval->execution_stack_pos = 0;
-
-	// Now copy all current state information
-	// Graphics and input state:
-	retval->animation_delay = s->animation_delay;
-	retval->animation_granularity = s->animation_granularity;
-	retval->gfx_state = s->gfx_state;
-
-	retval->resmgr = s->resmgr;
-
-	temp = retval->sound.songlib;
-	sfx_init(&retval->sound, retval->resmgr, s->sfx_init_flags);
-	retval->sfx_init_flags = s->sfx_init_flags;
-	song_lib_free(retval->sound.songlib);
-	retval->sound.songlib = temp;
-
-	_reset_graphics_input(retval);
-	reconstruct_stack(retval);
-	reconstruct_scripts(retval, retval->seg_manager);
-	reconstruct_clones(retval, retval->seg_manager);
-	retval->game_obj = s->game_obj;
-	retval->script_000 = &retval->seg_manager->heap[script_get_segment(s, 0, SCRIPT_GET_DONT_LOAD)]->data.script;
-	retval->gc_countdown = GC_INTERVAL - 1;
-	retval->save_dir_copy = make_reg(s->sys_strings_segment, SYS_STRING_SAVEDIR);
-	retval->save_dir_edit_offset = 0;
-	retval->sys_strings_segment = find_unique_seg_by_type(retval->seg_manager, MEM_OBJ_SYS_STRINGS);
-	retval->sys_strings = &(((MemObject *)(GET_SEGMENT(*retval->seg_manager, retval->sys_strings_segment, MEM_OBJ_SYS_STRINGS)))->data.sys_strings);
-
-	// Restore system strings
-	SystemString *str;
-
-	// First, pad memory
-	for (int i = 0; i < SYS_STRINGS_MAX; i++) {
-		str = &retval->sys_strings->strings[i];
-		char *data = (char *) str->value;
-		if (data) {
-			str->value = (reg_t *)sci_malloc(str->max_size + 1);
-			strcpy((char *)str->value, data);
-			free(data);
-		}
-	}
-
-	str = &retval->sys_strings->strings[SYS_STRING_SAVEDIR];
-	internal_stringfrag_strncpy(s, str->value, s->sys_strings->strings[SYS_STRING_SAVEDIR].value, str->max_size);
-	str->value[str->max_size].segment = s->string_frag_segment; // Make sure to terminate
-	str->value[str->max_size].offset &= 0xff00; // Make sure to terminate
-	
-	// Time state:
-	retval->last_wait_time = g_system->getMillis();
-	retval->game_start_time = g_system->getMillis() - retval->game_time * 1000;
-
-	// static parser information:
-	retval->parser_rules = s->parser_rules;
-	retval->parser_words_nr = s->parser_words_nr;
-	retval->parser_words = s->parser_words;
-	retval->_parserSuffixes = s->_parserSuffixes;
-	retval->parser_branches_nr = s->parser_branches_nr;
-	retval->parser_branches = s->parser_branches;
-
-	// static VM/Kernel information:
-	retval->_selectorNames = s->_selectorNames;
-	retval->kernel_names_nr = s->kernel_names_nr;
-	retval->kernel_names = s->kernel_names;
-	retval->kfunct_table = s->kfunct_table;
-	retval->kfunct_nr = s->kfunct_nr;
-	retval->opcodes = s->opcodes;
-
-	memcpy(&(retval->selector_map), &(s->selector_map), sizeof(selector_map_t));
-
-	retval->max_version = retval->version;
-	retval->min_version = retval->version;
-	retval->parser_base = make_reg(s->sys_strings_segment, SYS_STRING_PARSER_BASE);
-
-	// Copy breakpoint information from current game instance
-	retval->have_bp = s->have_bp;
-	retval->bp_list = s->bp_list;
-
-	retval->debug_mode = s->debug_mode;
-
-	retval->kernel_opt_flags = 0;
-	retval->have_mouse_flag = 1;
-
-	retval->successor = NULL;
-	retval->pic_priority_table = gfxop_get_pic_metainfo(retval->gfx_state);
-	retval->game_name = sci_strdup(obj_get_name(retval, retval->game_obj));
-
-	retval->sound.it = NULL;
-	retval->sound.flags = s->sound.flags;
-	retval->sound.song = NULL;
-	retval->sound.suspended = s->sound.suspended;
-	retval->sound.debug = s->sound.debug;
-	reconstruct_sounds(retval);
-
-	return retval;
-}
-
-bool get_savegame_metadata(Common::SeekableReadStream* stream, SavegameMetadata* meta) {
-	int read_eof = 0;
-
-	%CFSMLREAD-ATOMIC SavegameMetadata meta FROM stream ERRVAR read_eof;
-
-	if (read_eof)
-		return false;
-
-	if ((meta->savegame_version < FREESCI_MINIMUM_SAVEGAME_VERSION) ||
-	    (meta->savegame_version > FREESCI_CURRENT_SAVEGAME_VERSION)) {
-		if (meta->savegame_version < FREESCI_MINIMUM_SAVEGAME_VERSION)
-			sciprintf("Old savegame version detected- can't load\n");
-		else
-			sciprintf("Savegame version is %d- maximum supported is %0d\n", meta->savegame_version, FREESCI_CURRENT_SAVEGAME_VERSION);
-
-		return false;
-	}
-
-	return true;
-}
-
-} // End of namespace Sci

Modified: scummvm/trunk/engines/sci/engine/savegame.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/savegame.cpp	2009-03-15 20:31:15 UTC (rev 39429)
+++ scummvm/trunk/engines/sci/engine/savegame.cpp	2009-03-15 20:31:29 UTC (rev 39430)
@@ -23,15 +23,13 @@
  *
  */
 
-/* Savegame handling for EngineState structs. Makes heavy use of cfsml magic. */
-/* DON'T EDIT savegame.cpp ! Only modify savegame.cfsml, if something needs
-** to be changed. Refer to freesci/docs/misc/cfsml.spec if you don't understand
-** savegame.cfsml. If this doesn't solve your problem, contact the maintainer.
-*/
-
-#include <time.h>	// FIXME: For struct tm
 #include "common/stream.h"
 #include "common/system.h"
+#include "common/serializer.h"
+
+#include <time.h>	// FIXME: For struct tm
+
+
 #include "sci/sci_memory.h"
 #include "sci/gfx/operations.h"
 #include "sci/gfx/menubar.h"
@@ -42,4734 +40,438 @@
 #include "sci/engine/intmap.h"
 #include "sci/engine/savegame.h"
 
-#ifdef _WIN32
-#pragma warning( disable : 4101 )
-#endif
-
 namespace Sci {
 
-/* Missing:
-** - SFXdriver
-** - File input/output state (this is likely not to happen)
-*/
+// from ksound.cpp:
+SongIterator *build_iterator(EngineState *s, int song_nr, int type, songit_id_t id);
 
+#pragma mark -
 
-const unsigned int PRINTFBUFLEN = 128;
-int WSprintf(Common::WriteStream* str, const char *format, ...) {
-	va_list args;
-	char buf[PRINTFBUFLEN]; // default buffer to prevent new in common case
-	char* writebuf = buf;
+// TODO: Many of the following sync_*() methods should be turned into member funcs
+// of the classes they are syncing.
 
-	unsigned int s = PRINTFBUFLEN;
-	unsigned int outsize;
-	while (true) {
-		va_start(args, format);
-		outsize = vsnprintf(writebuf, s, format, args);
-		va_end(args);
+static void sync_MemObjPtr(Common::Serializer &s, MemObject *&obj);
+static void sync_songlib_t(Common::Serializer &s, songlib_t &obj);
 
-		if (outsize == s) {
-			if (s > 16384) { // there are limits...
-				delete[] writebuf;
-				warning("Saving failed: line much too long");
-				return 0;
-			}
-			s *= 2;
-			if (writebuf != buf) delete[] writebuf;
-			writebuf = new char[s];
-		} else {
-			break;
-		}
-	}
-
-	uint32 ret = str->write(writebuf, outsize);
-
-	if (writebuf != buf) delete[] writebuf;
-
-	return ret;
+static void sync_reg_t(Common::Serializer &s, reg_t &obj) {
+	s.syncAsUint16LE(obj.segment);
+	s.syncAsUint16LE(obj.offset);
 }
 
-int SRSgetc(Common::SeekableReadStream* str) {
-	char c = str->readSByte();
-	if (str->err() || str->eos())
-		return EOF;
-	return c;
-}
-
-char* SRSgets(char* s, int size, Common::SeekableReadStream* str) {
-	return str->readLine_NEW(s, size);
-}
-
-
-void write_reg_t(Common::WriteStream *fh, reg_t const *foo) {
-	WSprintf(fh, PREG, PRINT_REG(*foo));
-}
-
-int read_reg_t(Common::SeekableReadStream *fh, reg_t *foo, const char *lastval, int *line, int *hiteof) {
-	unsigned int segment, offset;
-
-	if (sscanf(lastval, PREG, &segment, &offset) < 2) {
-		sciprintf("Error parsing reg_t on line %d\n", *line);
-		return 1;
+// FIXME: Sync a C string, using malloc/free storage.
+// Much better to replace all of these by Common::String
+static void syncCStr(Common::Serializer &s, char **str) {
+	Common::String tmp;
+	if (s.isSaving() && *str)
+		tmp = *str;
+	s.syncString(tmp);
+	if (s.isLoading()) {
+		//free(*str);
+		*str = strdup(tmp.c_str());
 	}
-
-	*foo = make_reg(segment, offset);
-	return 0;
 }
 
-void write_sci_version(Common::WriteStream *fh, sci_version_t const *foo) {
-	WSprintf(fh, "%d.%03d.%03d", SCI_VERSION_MAJOR(*foo), SCI_VERSION_MINOR(*foo), SCI_VERSION_PATCHLEVEL(*foo));
-}
 
-int read_sci_version(Common::SeekableReadStream *fh, sci_version_t *foo, const char *lastval, int *line, int *hiteof) {
-	return version_parse(lastval, foo);
-}
-
-void write_CommonString(Common::WriteStream *fh, Common::String const *string);
-int read_CommonString(Common::SeekableReadStream *fh, Common::String *string, const char *lastval, int *line, int *hiteof);
-
-void write_menubar_tp(Common::WriteStream *fh, const menubar_t * const *foo);
-int read_menubar_tp(Common::SeekableReadStream *fh, menubar_t **foo, const char *lastval, int *line, int *hiteof);
-
-void write_MemObjPtr(Common::WriteStream *fh, const MemObject * const *foo);
-int read_MemObjPtr(Common::SeekableReadStream *fh, MemObject **foo, const char *lastval, int *line, int *hiteof);
-
-void write_songlib_t(Common::WriteStream *fh, songlib_t const *foo);
-int read_songlib_t(Common::SeekableReadStream *fh, songlib_t *foo, const char *lastval, int *line, int *hiteof);
-
-int read_song_tp(Common::SeekableReadStream *fh, song_t **foo, const char *lastval, int *line, int *hiteof);
-
-void write_IntMapperPtr(Common::WriteStream *fh, const IntMapper * const *foo);
-int read_IntMapperPtr(Common::SeekableReadStream *fh, IntMapper **foo, const char *lastval, int *line, int *hiteof);
-
-void write_IntMapperNodePtr(Common::WriteStream *fh, const IntMapper::Node * const *foo);
-int read_IntMapperNodePtr(Common::SeekableReadStream *fh, IntMapper::Node **foo, const char *lastval, int *line, int *hiteof);
-
-void write_SegManagerPtr(Common::WriteStream *fh, const SegManager * const *foo);
-int read_SegManagerPtr(Common::SeekableReadStream *fh, SegManager **foo, const char *lastval, int *line, int *hiteof);
-
-typedef MemObject *mem_obj_ptr;
-
-// Unused types
-/*
-TYPE long "long" LIKE int;
-TYPE int16 "int16" LIKE int;
-
-RECORD synonym_t "synonym_t" {
-	int replaceant;
-	int replacement;
-}
-*/
-
-
-// Auto-generated CFSML declaration and function block
-
-#line 739 "engines/sci/engine/savegame.cfsml"
-#define CFSML_SUCCESS 0
-#define CFSML_FAILURE 1
-
-#line 102 "engines/sci/engine/savegame.cfsml"
-
-#include <stdarg.h> // We need va_lists
-
-#ifdef CFSML_DEBUG_MALLOC
-/*
-#define free(p)        dbg_sci_free(p)
-#define malloc(s)      dbg_sci_malloc(s)
-#define calloc(n, s)   dbg_sci_calloc(n, s)
-#define realloc(p, s)  dbg_sci_realloc(p, s)
-*/
-#define free        dbg_sci_free
-#define malloc      dbg_sci_malloc
-#define calloc      dbg_sci_calloc
-#define realloc     dbg_sci_realloc
-#endif
-
-static void _cfsml_error(const char *fmt, ...) {
-	va_list argp;
-
-	fprintf(stderr, "Error: ");
-	va_start(argp, fmt);
-	vfprintf(stderr, fmt, argp);
-	va_end(argp);
-}
-
-
-static struct _cfsml_pointer_refstruct {
-	struct _cfsml_pointer_refstruct *next;
-	void *ptr;
-} *_cfsml_pointer_references = NULL;
-
-static struct _cfsml_pointer_refstruct **_cfsml_pointer_references_current = &_cfsml_pointer_references;
-
-static char *_cfsml_last_value_retrieved = NULL;
-static char *_cfsml_last_identifier_retrieved = NULL;
-
-static void _cfsml_free_pointer_references_recursively(struct _cfsml_pointer_refstruct *refs, int free_pointers) {
-	if (!refs)
-		return;
-
-	_cfsml_free_pointer_references_recursively(refs->next, free_pointers);
-
-	if (free_pointers)
-		free(refs->ptr);
-
-	free(refs);
-}
-
-static void _cfsml_free_pointer_references(struct _cfsml_pointer_refstruct **meta_ref, int free_pointers) {
-	_cfsml_free_pointer_references_recursively(*meta_ref, free_pointers);
-	*meta_ref = NULL;
-	_cfsml_pointer_references_current = meta_ref;
-}
-
-static struct _cfsml_pointer_refstruct **_cfsml_get_current_refpointer() {
-	return _cfsml_pointer_references_current;
-}
-
-static void _cfsml_register_pointer(void *ptr) {
-	struct _cfsml_pointer_refstruct *newref = (struct _cfsml_pointer_refstruct*)sci_malloc(sizeof (struct _cfsml_pointer_refstruct));
-	newref->next = *_cfsml_pointer_references_current;
-	newref->ptr = ptr;
-	*_cfsml_pointer_references_current = newref;
-}
-
-static char *_cfsml_mangle_string(const char *s) {
-	const char *source = s;
-	char c;
-	char *target = (char *)sci_malloc(1 + strlen(s) * 2); // We will probably need less than that
-	char *writer = target;
-
-	while ((c = *source++)) {
-		if (c < 32) { // Special character?
-			*writer++ = '\\'; // Escape...
-			c += ('a' - 1);
-		} else if (c == '\\' || c == '"')
-			*writer++ = '\\'; // Escape, but do not change
-		*writer++ = c;
+static void sync_song_t(Common::Serializer &s, song_t &obj) {
+	s.syncAsSint32LE(obj.handle);
+	s.syncAsSint32LE(obj.resource_num);
+	s.syncAsSint32LE(obj.priority);
+	s.syncAsSint32LE(obj.status);
+	s.syncAsSint32LE(obj.restore_behavior);
+	s.syncAsSint32LE(obj.restore_time);
+	s.syncAsSint32LE(obj.loops);
+	s.syncAsSint32LE(obj.hold);
+	
+	if (s.isLoading()) {
+		obj._delay = 0;
+		obj.it = 0;
+		obj.next_playing = 0;
+		obj.next_stopping = 0;
+		obj.next = 0;
 	}
-	*writer = 0; // Terminate string
-
-	return (char *)sci_realloc(target, strlen(target) + 1);
 }
 
-static char *_cfsml_unmangle_string(const char *s, unsigned int length) {
-	char *target = (char *)sci_malloc(1 + strlen(s));
-	char *writer = target;
-	const char *source = s;
-	const char *end = s + length;
-	char c;
-
-	while ((source != end) && (c = *source++) && (c > 31)) {
-		if (c == '\\') { // Escaped character?
-			c = *source++;
-			if ((c != '\\') && (c != '"')) // Un-escape 0-31 only
-				c -= ('a' - 1);
-		}
-		*writer++ = c;
-	}
-	*writer = 0; // Terminate string
-
-	return (char *)sci_realloc(target, strlen(target) + 1);
+static void sync_IntMapper(Common::Serializer &s, IntMapper &obj) {
+	obj.saveLoadWithSerializer(s);
 }
 
-static char *_cfsml_get_identifier(Common::SeekableReadStream *fd, int *line, int *hiteof, int *assignment) {
-	int c;
-	int mem = 32;
-	int pos = 0;
-	int done = 0;
-	char *retval = (char *)sci_malloc(mem);
+static void sync_menu_item_t(Common::Serializer &s, menu_item_t &obj) {
+	s.syncAsSint32LE(obj.type);
+	syncCStr(s, &obj.keytext);
+	s.syncAsSint32LE(obj.keytext_size);
 
-	if (_cfsml_last_identifier_retrieved) {
-		free(_cfsml_last_identifier_retrieved);
-		_cfsml_last_identifier_retrieved = NULL;
-	}
-
-	while (isspace(c = SRSgetc(fd)) && (c != EOF));
-	if (c == EOF) {
-	    _cfsml_error("Unexpected end of file at line %d\n", *line);
-	    free(retval);
-	    *hiteof = 1;
-	    return NULL;
-	}
-
-	int first = 1;
-	while ((first || (c = SRSgetc(fd)) != EOF) && ((pos == 0) || (c != '\n')) && (c != '=')) {
-		first = 0;
-		if (pos == mem - 1) // Need more memory?
-			retval = (char *)sci_realloc(retval, mem *= 2);
-		if (!isspace(c)) {
-			if (done) {
-				_cfsml_error("Single word identifier expected at line %d\n", *line);
-				free(retval);
-				return NULL;
-			}
-			retval[pos++] = c;
-		} else
-			if (pos != 0)
-				done = 1; // Finished the variable name
-			else if (c == '\n')
-				++(*line);
-	}
-
-	if (c == EOF) {
-		_cfsml_error("Unexpected end of file at line %d\n", *line);
-		free(retval);
-		*hiteof = 1;
-		return NULL;
-	}
-
-	if (c == '\n') {
-		++(*line);
-		if (assignment)
-			*assignment = 0;
-	} else
-		if (assignment)
-			*assignment = 1;
-
-	if (pos == 0) {
-		_cfsml_error("Missing identifier in assignment at line %d\n", *line);
-		free(retval);
-		return NULL;
-	}
-
-	if (pos == mem - 1) // Need more memory?
-		retval = (char *)sci_realloc(retval, mem += 1);
-
-	retval[pos] = 0; // Terminate string
-#line 280 "engines/sci/engine/savegame.cfsml"
-
-	return _cfsml_last_identifier_retrieved = retval;
+	s.syncAsSint32LE(obj.flags);
+	s.syncBytes(obj.said, MENU_SAID_SPEC_SIZE);
+	sync_reg_t(s, obj.said_pos);
+	syncCStr(s, &obj.text);
+	sync_reg_t(s, obj.text_pos);
+	s.syncAsSint32LE(obj.modifiers);
+	s.syncAsSint32LE(obj.key);
+	s.syncAsSint32LE(obj.enabled);
+	s.syncAsSint32LE(obj.tag);
 }
 
-static char *_cfsml_get_value(Common::SeekableReadStream *fd, int *line, int *hiteof) {
-	int c;
-	int mem = 64;
-	int pos = 0;
-	char *retval = (char *)sci_malloc(mem);
+static void sync_menu_t(Common::Serializer &s, menu_t &obj) {
+	syncCStr(s, &obj.title);
+	s.syncAsSint32LE(obj.title_width);
+	s.syncAsSint32LE(obj.width);
 
-	if (_cfsml_last_value_retrieved) {
-		free(_cfsml_last_value_retrieved);
-		_cfsml_last_value_retrieved = NULL;
-	}
+	s.syncAsSint32LE(obj.items_nr);
 
-	while (((c = SRSgetc(fd)) != EOF) && (c != '\n')) {
-		if (pos == mem - 1) // Need more memory?
-			retval = (char *)sci_realloc(retval, mem *= 2);
-
-		if (pos || (!isspace(c)))
-			retval[pos++] = c;
-	}
-
-	while ((pos > 0) && (isspace(retval[pos - 1])))
-		--pos; // Strip trailing whitespace
-
-	if (c == EOF)
-		*hiteof = 1;
-
-	if (pos == 0) {
-	    _cfsml_error("Missing value in assignment at line %d\n", *line);
-	    free(retval);
-	    return NULL;
-	}
-
-	if (c == '\n')
-		++(*line);
-
-	if (pos == mem - 1) // Need more memory?
-		retval = (char *)sci_realloc(retval, mem += 1);
-
-	retval[pos] = 0; // Terminate string
-#line 332 "engines/sci/engine/savegame.cfsml"
-	return (_cfsml_last_value_retrieved = (char *)sci_realloc(retval, strlen(retval) + 1));
-	// Re-allocate; this value might be used for quite some while (if we are restoring a string)
+	if (!obj.items && obj.items_nr)
+		obj.items = (menu_item_t *)sci_calloc(obj.items_nr, sizeof(menu_item_t));
+	for (int i = 0; i < obj.items_nr; ++i)
+		sync_menu_item_t(s, obj.items[i]);
 }
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_sfx_state_t(Common::WriteStream *fh, sfx_state_t const * save_struc);
-static int _cfsml_read_sfx_state_t(Common::SeekableReadStream *fh, sfx_state_t* save_struc, const char *lastval, int *line, int *hiteof);
 
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_string(Common::WriteStream *fh, const char * const * save_struc);
-static int _cfsml_read_string(Common::SeekableReadStream *fh, char ** save_struc, const char *lastval, int *line, int *hiteof);
+static void sync_menubar_t(Common::Serializer &s, menubar_t &obj) {
+	s.syncAsSint32LE(obj.menus_nr);
 
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_menubar_t(Common::WriteStream *fh, menubar_t const * save_struc);
-static int _cfsml_read_menubar_t(Common::SeekableReadStream *fh, menubar_t* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_CloneTable(Common::WriteStream *fh, CloneTable const * save_struc);
-static int _cfsml_read_CloneTable(Common::SeekableReadStream *fh, CloneTable* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_size_t(Common::WriteStream *fh, size_t const * save_struc);
-static int _cfsml_read_size_t(Common::SeekableReadStream *fh, size_t* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_SegmentId(Common::WriteStream *fh, SegmentId const * save_struc);
-static int _cfsml_read_SegmentId(Common::SeekableReadStream *fh, SegmentId* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_Node(Common::WriteStream *fh, Node const * save_struc);
-static int _cfsml_read_Node(Common::SeekableReadStream *fh, Node* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_SegManager(Common::WriteStream *fh, SegManager const * save_struc);
-static int _cfsml_read_SegManager(Common::SeekableReadStream *fh, SegManager* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_song_t(Common::WriteStream *fh, song_t const * save_struc);
-static int _cfsml_read_song_t(Common::SeekableReadStream *fh, song_t* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_menu_item_t(Common::WriteStream *fh, menu_item_t const * save_struc);
-static int _cfsml_read_menu_item_t(Common::SeekableReadStream *fh, menu_item_t* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_bool(Common::WriteStream *fh, bool const * save_struc);
-static int _cfsml_read_bool(Common::SeekableReadStream *fh, bool* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_NodeTable(Common::WriteStream *fh, NodeTable const * save_struc);
-static int _cfsml_read_NodeTable(Common::SeekableReadStream *fh, NodeTable* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_SystemString(Common::WriteStream *fh, SystemString const * save_struc);
-static int _cfsml_read_SystemString(Common::SeekableReadStream *fh, SystemString* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_byte(Common::WriteStream *fh, byte const * save_struc);
-static int _cfsml_read_byte(Common::SeekableReadStream *fh, byte* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_ListTable(Common::WriteStream *fh, ListTable const * save_struc);
-static int _cfsml_read_ListTable(Common::SeekableReadStream *fh, ListTable* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_Class(Common::WriteStream *fh, Class const * save_struc);
-static int _cfsml_read_Class(Common::SeekableReadStream *fh, Class* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_SystemStrings(Common::WriteStream *fh, SystemStrings const * save_struc);
-static int _cfsml_read_SystemStrings(Common::SeekableReadStream *fh, SystemStrings* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_song_handle_t(Common::WriteStream *fh, song_handle_t const * save_struc);
-static int _cfsml_read_song_handle_t(Common::SeekableReadStream *fh, song_handle_t* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_List(Common::WriteStream *fh, List const * save_struc);
-static int _cfsml_read_List(Common::SeekableReadStream *fh, List* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_NodeEntry(Common::WriteStream *fh, NodeEntry const * save_struc);
-static int _cfsml_read_NodeEntry(Common::SeekableReadStream *fh, NodeEntry* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_int(Common::WriteStream *fh, int const * save_struc);
-static int _cfsml_read_int(Common::SeekableReadStream *fh, int* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_EngineState(Common::WriteStream *fh, EngineState const * save_struc);
-static int _cfsml_read_EngineState(Common::SeekableReadStream *fh, EngineState* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_CloneEntry(Common::WriteStream *fh, CloneEntry const * save_struc);
-static int _cfsml_read_CloneEntry(Common::SeekableReadStream *fh, CloneEntry* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_SavegameMetadata(Common::WriteStream *fh, SavegameMetadata const * save_struc);
-static int _cfsml_read_SavegameMetadata(Common::SeekableReadStream *fh, SavegameMetadata* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_LocalVariables(Common::WriteStream *fh, LocalVariables const * save_struc);
-static int _cfsml_read_LocalVariables(Common::SeekableReadStream *fh, LocalVariables* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_IntMapper(Common::WriteStream *fh, IntMapper const * save_struc);
-static int _cfsml_read_IntMapper(Common::SeekableReadStream *fh, IntMapper* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_menu_t(Common::WriteStream *fh, menu_t const * save_struc);
-static int _cfsml_read_menu_t(Common::SeekableReadStream *fh, menu_t* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_Object(Common::WriteStream *fh, Object const * save_struc);
-static int _cfsml_read_Object(Common::SeekableReadStream *fh, Object* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_ListEntry(Common::WriteStream *fh, ListEntry const * save_struc);
-static int _cfsml_read_ListEntry(Common::SeekableReadStream *fh, ListEntry* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_Clone(Common::WriteStream *fh, Clone const * save_struc);
-static int _cfsml_read_Clone(Common::SeekableReadStream *fh, Clone* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_DynMem(Common::WriteStream *fh, DynMem const * save_struc);
-static int _cfsml_read_DynMem(Common::SeekableReadStream *fh, DynMem* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 383 "engines/sci/engine/savegame.cfsml"
-static void _cfsml_write_Script(Common::WriteStream *fh, Script const * save_struc);
-static int _cfsml_read_Script(Common::SeekableReadStream *fh, Script* save_struc, const char *lastval, int *line, int *hiteof);
-
-#line 396 "engines/sci/engine/savegame.cfsml"
-static void
-_cfsml_write_sfx_state_t(Common::WriteStream *fh, sfx_state_t const * save_struc)
-{
-#line 413 "engines/sci/engine/savegame.cfsml"
-	WSprintf(fh, "{\n");
-	WSprintf(fh, "songlib = ");
-	write_songlib_t(fh, (songlib_t const *) &(save_struc->songlib));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "}");
+	if (!obj.menus && obj.menus_nr)
+		obj.menus = (menu_t *)sci_calloc(obj.menus_nr, sizeof(menu_t));
+	for (int i = 0; i < obj.menus_nr; ++i)
+		sync_menu_t(s, obj.menus[i]);
 }
 
-#line 487 "engines/sci/engine/savegame.cfsml"
-static int
-_cfsml_read_sfx_state_t(Common::SeekableReadStream *fh, sfx_state_t* save_struc, const char *lastval, int *line, int *hiteof)
-{
-#line 542 "engines/sci/engine/savegame.cfsml"
-	char *token;
-	int assignment, closed;
+static void sync_SegManager(Common::Serializer &s, SegManager &obj) {
+	int allocated_heap_size = obj.heap_size;
+	s.syncAsSint32LE(obj.heap_size);
+	s.syncAsSint32LE(obj.reserved_id);
+	s.syncAsSint32LE(obj.exports_wide);
+	s.syncAsSint32LE(obj.gc_mark_bits);
+	s.syncAsUint32LE(obj.mem_allocated);
 
-	if (strcmp(lastval, "{")) {
-		_cfsml_error("Reading record sfx_state_t; expected opening braces in line %d, got \"%s\"\n", *line, lastval);
-		return CFSML_FAILURE;
-	};
-	closed = 0;
-	do {
-		const char *value;
-		token = _cfsml_get_identifier(fh, line, hiteof, &assignment);
+	sync_IntMapper(s, *obj.id_seg_map);
 
-		if (!token) {
-			_cfsml_error("Expected token at line %d\n", *line);
-			return CFSML_FAILURE;
-		}
-		if (!assignment) {
-			if (!strcmp(token, "}"))
-				closed = 1;
-			else {
-				_cfsml_error("Expected assignment or closing braces in line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-		} else {
-			value = "";
-			while (!value || !strcmp(value, ""))
-				value = _cfsml_get_value(fh, line, hiteof);
-			if (!value) {
-				_cfsml_error("Expected token at line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-				if (!strcmp(token, "songlib")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (read_songlib_t(fh, (songlib_t*) &(save_struc->songlib), value, line, hiteof)) {
-					_cfsml_error("Token expected by read_songlib_t() for songlib at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-#line 700 "engines/sci/engine/savegame.cfsml"
-			{
-				_cfsml_error("sfx_state_t: Assignment to invalid identifier '%s' in line %d\n", token, *line);
-				return CFSML_FAILURE;
-			}
-		}
-	} while (!closed); // Until closing braces are hit
-	return CFSML_SUCCESS;
-}
+	assert(obj.heap);
+	if (allocated_heap_size != obj.heap_size)
+		obj.heap = (MemObject**)sci_realloc((void *)obj.heap, obj.heap_size * sizeof(MemObject *));
+	for (int i = 0; i < obj.heap_size; ++i)
+		sync_MemObjPtr(s, obj.heap[i]);
 
-#line 396 "engines/sci/engine/savegame.cfsml"
-static void
-_cfsml_write_string(Common::WriteStream *fh, const char * const * save_struc)
-{
-#line 403 "engines/sci/engine/savegame.cfsml"
-	if (!(*save_struc))
-		WSprintf(fh, "\\null\\");
-	else {
-		char *token = _cfsml_mangle_string((const char *) *save_struc);
-		WSprintf(fh, "\"%s\"", token);
-		free(token);
-	}
+	s.syncAsSint32LE(obj.Clones_seg_id);
+	s.syncAsSint32LE(obj.Lists_seg_id);
+	s.syncAsSint32LE(obj.Nodes_seg_id);
 }
 
-#line 487 "engines/sci/engine/savegame.cfsml"
-static int
-_cfsml_read_string(Common::SeekableReadStream *fh, char ** save_struc, const char *lastval, int *line, int *hiteof)
-{
-#line 520 "engines/sci/engine/savegame.cfsml"
+static void sync_SegManagerPtr(Common::Serializer &s, SegManager *&obj) {
+	bool sci11 = false;
 
-	if (strcmp(lastval, "\\null\\")) { // null pointer?
-		unsigned int length = strlen(lastval);
-		if (*lastval == '"') { // Quoted string?
-			while (lastval[length] != '"')
-				--length;
-
-			if (!length) { // No matching double-quotes?
-				_cfsml_error("Unbalanced quotes at line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-
-			lastval++; // ...and skip the opening quotes locally
-			length--;
-		}
-		*save_struc = _cfsml_unmangle_string(lastval, length);
-		_cfsml_register_pointer(*save_struc);
-		return CFSML_SUCCESS;
-	} else {
-		*save_struc = NULL;
-		return CFSML_SUCCESS;
+	if (s.isSaving()) {
+		assert(obj);
+		sci11 = obj->isSci1_1;
 	}
-}
 
-#line 396 "engines/sci/engine/savegame.cfsml"
-static void
-_cfsml_write_menubar_t(Common::WriteStream *fh, menubar_t const * save_struc)
-{
-#line 413 "engines/sci/engine/savegame.cfsml"
-	WSprintf(fh, "{\n");
-	WSprintf(fh, "menus = ");
-	int min, max;
-	min = max = save_struc->menus_nr;
-	if (!save_struc->menus)
-		min = max = 0; /* Don't write if it points to NULL */
-#line 440 "engines/sci/engine/savegame.cfsml"
-	WSprintf(fh, "[%d][\n", max);
-	for (int i = 0; i < min; i++) {
-		_cfsml_write_menu_t(fh, &(save_struc->menus[i]));
-		WSprintf(fh, "\n");
-	}
-	WSprintf(fh, "]");
-	WSprintf(fh, "\n");
-	WSprintf(fh, "}");
-}
+	s.syncAsByte(sci11);
 
-#line 487 "engines/sci/engine/savegame.cfsml"
-static int
-_cfsml_read_menubar_t(Common::SeekableReadStream *fh, menubar_t* save_struc, const char *lastval, int *line, int *hiteof)
-{
-#line 542 "engines/sci/engine/savegame.cfsml"
-	char *token;
-	int assignment, closed;
-
-	if (strcmp(lastval, "{")) {
-		_cfsml_error("Reading record menubar_t; expected opening braces in line %d, got \"%s\"\n", *line, lastval);
-		return CFSML_FAILURE;
-	};
-	closed = 0;
-	do {
-		const char *value;
-		token = _cfsml_get_identifier(fh, line, hiteof, &assignment);
-
-		if (!token) {
-			_cfsml_error("Expected token at line %d\n", *line);
-			return CFSML_FAILURE;
-		}
-		if (!assignment) {
-			if (!strcmp(token, "}"))
-				closed = 1;
-			else {
-				_cfsml_error("Expected assignment or closing braces in line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-		} else {
-			value = "";
-			while (!value || !strcmp(value, ""))
-				value = _cfsml_get_value(fh, line, hiteof);
-			if (!value) {
-				_cfsml_error("Expected token at line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-				if (!strcmp(token, "menus")) {
-#line 605 "engines/sci/engine/savegame.cfsml"
-			if ((value[0] != '[') || (value[strlen(value) - 1] != '[')) {
-				_cfsml_error("Opening brackets expected at line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-			int max,done,i;
-#line 616 "engines/sci/engine/savegame.cfsml"
-			// Prepare to restore dynamic array
-			max = strtol(value + 1, NULL, 0);
-			if (max < 0) {
-				_cfsml_error("Invalid number of elements to allocate for dynamic array '%s' at line %d\n", token, *line);
-				return CFSML_FAILURE;
-			}
-
-			if (max) {
-				save_struc->menus = (menu_t *)sci_malloc(max * sizeof(menu_t));
-#ifdef SATISFY_PURIFY
-				memset(save_struc->menus, 0, max * sizeof(menu_t));
-#endif
-				_cfsml_register_pointer(save_struc->menus);
-			} else
-				save_struc->menus = NULL;
-#line 640 "engines/sci/engine/savegame.cfsml"
-			done = i = 0;
-			do {
-			if (!(value = _cfsml_get_identifier(fh, line, hiteof, NULL))) {
-#line 648 "engines/sci/engine/savegame.cfsml"
-				_cfsml_error("Token expected at line %d\n", *line);
-				return 1;
-			}
-			if (strcmp(value, "]")) {
-				if (i == max) {
-					_cfsml_error("More elements than space available (%d) in '%s' at line %d\n", max, token, *line);
-					return CFSML_FAILURE;
-				}
-				if (_cfsml_read_menu_t(fh, &(save_struc->menus[i++]), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_menu_t() for menus[i++] at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				done = 1;
-			} while (!done);
-			save_struc->menus_nr = max ; // Set array size accordingly
-			} else
-#line 700 "engines/sci/engine/savegame.cfsml"
-			{
-				_cfsml_error("menubar_t: Assignment to invalid identifier '%s' in line %d\n", token, *line);
-				return CFSML_FAILURE;
-			}
-		}
-	} while (!closed); // Until closing braces are hit
-	return CFSML_SUCCESS;
-}
-
-#line 396 "engines/sci/engine/savegame.cfsml"
-static void
-_cfsml_write_CloneTable(Common::WriteStream *fh, CloneTable const * save_struc)
-{
-#line 413 "engines/sci/engine/savegame.cfsml"
-	WSprintf(fh, "{\n");
-	WSprintf(fh, "entries_nr = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->entries_nr));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "first_free = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->first_free));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "entries_used = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->entries_used));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "max_entry = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->max_entry));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "table = ");
-	int min, max;
-	min = max = save_struc->entries_nr;
-	if (!save_struc->table)
-		min = max = 0; /* Don't write if it points to NULL */
-#line 440 "engines/sci/engine/savegame.cfsml"
-	WSprintf(fh, "[%d][\n", max);
-	for (int i = 0; i < min; i++) {
-		_cfsml_write_CloneEntry(fh, &(save_struc->table[i]));
-		WSprintf(fh, "\n");
+	if (s.isLoading()) {
+		// FIXME: Do in-place loading at some point, instead of creating a new EngineState instance from scratch.
+		delete obj;
+		obj = new SegManager(sci11);
 	}
-	WSprintf(fh, "]");
-	WSprintf(fh, "\n");
-	WSprintf(fh, "}");
+	
+	sync_SegManager(s, *obj);
 }
 
-#line 487 "engines/sci/engine/savegame.cfsml"
-static int
-_cfsml_read_CloneTable(Common::SeekableReadStream *fh, CloneTable* save_struc, const char *lastval, int *line, int *hiteof)
-{
-#line 542 "engines/sci/engine/savegame.cfsml"
-	char *token;
-	int assignment, closed;
 
-	if (strcmp(lastval, "{")) {
-		_cfsml_error("Reading record CloneTable; expected opening braces in line %d, got \"%s\"\n", *line, lastval);
-		return CFSML_FAILURE;
-	};
-	closed = 0;
-	do {
-		const char *value;
-		token = _cfsml_get_identifier(fh, line, hiteof, &assignment);
 
-		if (!token) {
-			_cfsml_error("Expected token at line %d\n", *line);
-			return CFSML_FAILURE;
-		}
-		if (!assignment) {
-			if (!strcmp(token, "}"))
-				closed = 1;
-			else {
-				_cfsml_error("Expected assignment or closing braces in line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-		} else {
-			value = "";
-			while (!value || !strcmp(value, ""))
-				value = _cfsml_get_value(fh, line, hiteof);
-			if (!value) {
-				_cfsml_error("Expected token at line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-				if (!strcmp(token, "entries_nr")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->entries_nr), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for entries_nr at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "first_free")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->first_free), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for first_free at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "entries_used")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->entries_used), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for entries_used at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "max_entry")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->max_entry), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for max_entry at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "table")) {
-#line 605 "engines/sci/engine/savegame.cfsml"
-			if ((value[0] != '[') || (value[strlen(value) - 1] != '[')) {
-				_cfsml_error("Opening brackets expected at line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-			int max,done,i;
-#line 616 "engines/sci/engine/savegame.cfsml"
-			// Prepare to restore dynamic array
-			max = strtol(value + 1, NULL, 0);
-			if (max < 0) {
-				_cfsml_error("Invalid number of elements to allocate for dynamic array '%s' at line %d\n", token, *line);
-				return CFSML_FAILURE;
-			}
-
-			if (max) {
-				save_struc->table = (CloneEntry *)sci_malloc(max * sizeof(CloneEntry));
-#ifdef SATISFY_PURIFY
-				memset(save_struc->table, 0, max * sizeof(CloneEntry));
-#endif
-				_cfsml_register_pointer(save_struc->table);
-			} else
-				save_struc->table = NULL;
-#line 640 "engines/sci/engine/savegame.cfsml"
-			done = i = 0;
-			do {
-			if (!(value = _cfsml_get_identifier(fh, line, hiteof, NULL))) {
-#line 648 "engines/sci/engine/savegame.cfsml"
-				_cfsml_error("Token expected at line %d\n", *line);
-				return 1;
-			}
-			if (strcmp(value, "]")) {
-				if (i == max) {
-					_cfsml_error("More elements than space available (%d) in '%s' at line %d\n", max, token, *line);
-					return CFSML_FAILURE;
-				}
-				if (_cfsml_read_CloneEntry(fh, &(save_struc->table[i++]), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_CloneEntry() for table[i++] at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				done = 1;
-			} while (!done);
-			save_struc->entries_nr = max ; // Set array size accordingly
-			} else
-#line 700 "engines/sci/engine/savegame.cfsml"
-			{
-				_cfsml_error("CloneTable: Assignment to invalid identifier '%s' in line %d\n", token, *line);
-				return CFSML_FAILURE;
-			}
-		}
-	} while (!closed); // Until closing braces are hit
-	return CFSML_SUCCESS;
+static void sync_Class(Common::Serializer &s, Class &obj) {
+	s.syncAsSint32LE(obj.script);
+	sync_reg_t(s, obj.reg);
 }
 
-#line 396 "engines/sci/engine/savegame.cfsml"
-static void
-_cfsml_write_size_t(Common::WriteStream *fh, size_t const * save_struc)
-{
-	WSprintf(fh, "%li", (long)*save_struc);
+static void sync_sfx_state_t(Common::Serializer &s, sfx_state_t &obj) {
+	sync_songlib_t(s, obj.songlib);
 }
 
-#line 487 "engines/sci/engine/savegame.cfsml"
-static int
-_cfsml_read_size_t(Common::SeekableReadStream *fh, size_t* save_struc, const char *lastval, int *line, int *hiteof)
-{
-#line 507 "engines/sci/engine/savegame.cfsml"
-	char *token;
+static void sync_SavegameMetadata(Common::Serializer &s, SavegameMetadata &obj) {
+	// TODO: It would be a good idea to store a magic number & a header size here,
+	// so that we can implement backward compatibility if the savegame format changes.
 
-	*save_struc = strtol(lastval, &token, 0);
-	if ((*save_struc == 0) && (token == lastval)) {
-		_cfsml_error("strtol failed at line %d\n", *line);
-		return CFSML_FAILURE;
-	}
-	if (*token != 0) {
-		_cfsml_error("Non-integer encountered while parsing int value at line %d\n", *line);
-		return CFSML_FAILURE;
-	}
-	return CFSML_SUCCESS;
+	s.syncString(obj.savegame_name);
+	s.syncAsSint32LE(obj.savegame_version);
+	s.syncString(obj.game_version);
+	s.syncAsSint32LE(obj.version);
+	s.syncAsSint32LE(obj.savegame_date);
+	s.syncAsSint32LE(obj.savegame_time);
 }
 
-#line 396 "engines/sci/engine/savegame.cfsml"
-static void
-_cfsml_write_SegmentId(Common::WriteStream *fh, SegmentId const * save_struc)
-{
-	WSprintf(fh, "%li", (long)*save_struc);
-}
+void EngineState::saveLoadWithSerializer(Common::Serializer &s) {
+	s.syncAsSint32LE(savegame_version);
 
-#line 487 "engines/sci/engine/savegame.cfsml"
-static int
-_cfsml_read_SegmentId(Common::SeekableReadStream *fh, SegmentId* save_struc, const char *lastval, int *line, int *hiteof)
-{
-#line 507 "engines/sci/engine/savegame.cfsml"
-	char *token;
+	syncCStr(s, &game_version);
+	s.syncAsSint32LE(version);
 
-	*save_struc = strtol(lastval, &token, 0);
-	if ((*save_struc == 0) && (token == lastval)) {
-		_cfsml_error("strtol failed at line %d\n", *line);
-		return CFSML_FAILURE;
-	}
-	if (*token != 0) {
-		_cfsml_error("Non-integer encountered while parsing int value at line %d\n", *line);
-		return CFSML_FAILURE;
-	}
-	return CFSML_SUCCESS;
-}
+	// FIXME: Do in-place loading at some point, instead of creating a new EngineState instance from scratch.
+	if (s.isLoading()) {
+		//free(menubar);
+		menubar = (menubar_t *)sci_calloc(1, sizeof(menubar_t));
+	} else
+		assert(menubar);
+	sync_menubar_t(s, *menubar);
 
-#line 396 "engines/sci/engine/savegame.cfsml"
-static void
-_cfsml_write_Node(Common::WriteStream *fh, Node const * save_struc)
-{
-#line 413 "engines/sci/engine/savegame.cfsml"
-	WSprintf(fh, "{\n");
-	WSprintf(fh, "pred = ");
-	write_reg_t(fh, (reg_t const *) &(save_struc->pred));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "succ = ");
-	write_reg_t(fh, (reg_t const *) &(save_struc->succ));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "key = ");
-	write_reg_t(fh, (reg_t const *) &(save_struc->key));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "value = ");
-	write_reg_t(fh, (reg_t const *) &(save_struc->value));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "}");
-}
+	s.syncAsSint32LE(status_bar_foreground);
+	s.syncAsSint32LE(status_bar_background);
 
-#line 487 "engines/sci/engine/savegame.cfsml"
-static int
-_cfsml_read_Node(Common::SeekableReadStream *fh, Node* save_struc, const char *lastval, int *line, int *hiteof)
-{
-#line 542 "engines/sci/engine/savegame.cfsml"
-	char *token;
-	int assignment, closed;
+	sync_SegManagerPtr(s, seg_manager);
 
-	if (strcmp(lastval, "{")) {
-		_cfsml_error("Reading record Node; expected opening braces in line %d, got \"%s\"\n", *line, lastval);
-		return CFSML_FAILURE;
-	};
-	closed = 0;
-	do {
-		const char *value;
-		token = _cfsml_get_identifier(fh, line, hiteof, &assignment);
 
-		if (!token) {
-			_cfsml_error("Expected token at line %d\n", *line);
-			return CFSML_FAILURE;
-		}
-		if (!assignment) {
-			if (!strcmp(token, "}"))
-				closed = 1;
-			else {
-				_cfsml_error("Expected assignment or closing braces in line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-		} else {
-			value = "";
-			while (!value || !strcmp(value, ""))
-				value = _cfsml_get_value(fh, line, hiteof);
-			if (!value) {
-				_cfsml_error("Expected token at line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-				if (!strcmp(token, "pred")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (read_reg_t(fh, (reg_t*) &(save_struc->pred), value, line, hiteof)) {
-					_cfsml_error("Token expected by read_reg_t() for pred at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "succ")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (read_reg_t(fh, (reg_t*) &(save_struc->succ), value, line, hiteof)) {
-					_cfsml_error("Token expected by read_reg_t() for succ at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "key")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (read_reg_t(fh, (reg_t*) &(save_struc->key), value, line, hiteof)) {
-					_cfsml_error("Token expected by read_reg_t() for key at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "value")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (read_reg_t(fh, (reg_t*) &(save_struc->value), value, line, hiteof)) {
-					_cfsml_error("Token expected by read_reg_t() for value at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-#line 700 "engines/sci/engine/savegame.cfsml"
-			{
-				_cfsml_error("Node: Assignment to invalid identifier '%s' in line %d\n", token, *line);
-				return CFSML_FAILURE;
-			}
-		}
-	} while (!closed); // Until closing braces are hit
-	return CFSML_SUCCESS;
-}
+	s.syncAsSint32LE(classtable_size);
 
-#line 396 "engines/sci/engine/savegame.cfsml"
-static void
-_cfsml_write_SegManager(Common::WriteStream *fh, SegManager const * save_struc)
-{
-#line 413 "engines/sci/engine/savegame.cfsml"
-	WSprintf(fh, "{\n");
-	WSprintf(fh, "id_seg_map = ");
-	write_IntMapperPtr(fh, (IntMapper * const *) &(save_struc->id_seg_map));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "heap = ");
-	int min, max;
-	min = max = save_struc->heap_size;
-	if (!save_struc->heap)
-		min = max = 0; /* Don't write if it points to NULL */
-#line 440 "engines/sci/engine/savegame.cfsml"
-	WSprintf(fh, "[%d][\n", max);
-	for (int i = 0; i < min; i++) {
-		write_MemObjPtr(fh, &(save_struc->heap[i]));
-		WSprintf(fh, "\n");
-	}
-	WSprintf(fh, "]");
-	WSprintf(fh, "\n");
-	WSprintf(fh, "heap_size = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->heap_size));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "reserved_id = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->reserved_id));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "exports_wide = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->exports_wide));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "gc_mark_bits = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->gc_mark_bits));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "mem_allocated = ");
-	_cfsml_write_size_t(fh, (size_t const *) &(save_struc->mem_allocated));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "Clones_seg_id = ");
-	_cfsml_write_SegmentId(fh, (SegmentId const *) &(save_struc->Clones_seg_id));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "Lists_seg_id = ");
-	_cfsml_write_SegmentId(fh, (SegmentId const *) &(save_struc->Lists_seg_id));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "Nodes_seg_id = ");
-	_cfsml_write_SegmentId(fh, (SegmentId const *) &(save_struc->Nodes_seg_id));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "}");
-}
+	if (!classtable && classtable_size)
+		classtable = (Class *)sci_calloc(classtable_size, sizeof(Class));
+	for (int i = 0; i < classtable_size; ++i)
+		sync_Class(s, classtable[i]);
 
-#line 487 "engines/sci/engine/savegame.cfsml"
-static int
-_cfsml_read_SegManager(Common::SeekableReadStream *fh, SegManager* save_struc, const char *lastval, int *line, int *hiteof)
-{
-#line 542 "engines/sci/engine/savegame.cfsml"
-	char *token;
-	int assignment, closed;
-
-	if (strcmp(lastval, "{")) {
-		_cfsml_error("Reading record SegManager; expected opening braces in line %d, got \"%s\"\n", *line, lastval);
-		return CFSML_FAILURE;
-	};
-	closed = 0;
-	do {
-		const char *value;
-		token = _cfsml_get_identifier(fh, line, hiteof, &assignment);
-
-		if (!token) {
-			_cfsml_error("Expected token at line %d\n", *line);
-			return CFSML_FAILURE;
-		}
-		if (!assignment) {
-			if (!strcmp(token, "}"))
-				closed = 1;
-			else {
-				_cfsml_error("Expected assignment or closing braces in line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-		} else {
-			value = "";
-			while (!value || !strcmp(value, ""))
-				value = _cfsml_get_value(fh, line, hiteof);
-			if (!value) {
-				_cfsml_error("Expected token at line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-				if (!strcmp(token, "id_seg_map")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (read_IntMapperPtr(fh, (IntMapper **) &(save_struc->id_seg_map), value, line, hiteof)) {
-					_cfsml_error("Token expected by read_IntMapperPtr() for id_seg_map at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "heap")) {
-#line 605 "engines/sci/engine/savegame.cfsml"
-			if ((value[0] != '[') || (value[strlen(value) - 1] != '[')) {
-				_cfsml_error("Opening brackets expected at line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-			int max,done,i;
-#line 616 "engines/sci/engine/savegame.cfsml"
-			// Prepare to restore dynamic array
-			max = strtol(value + 1, NULL, 0);
-			if (max < 0) {
-				_cfsml_error("Invalid number of elements to allocate for dynamic array '%s' at line %d\n", token, *line);
-				return CFSML_FAILURE;
-			}
-
-			if (max) {
-				save_struc->heap = (mem_obj_ptr *)sci_malloc(max * sizeof(mem_obj_ptr));
-#ifdef SATISFY_PURIFY
-				memset(save_struc->heap, 0, max * sizeof(mem_obj_ptr));
-#endif
-				_cfsml_register_pointer(save_struc->heap);
-			} else
-				save_struc->heap = NULL;
-#line 640 "engines/sci/engine/savegame.cfsml"
-			done = i = 0;
-			do {
-			if (!(value = _cfsml_get_identifier(fh, line, hiteof, NULL))) {
-#line 648 "engines/sci/engine/savegame.cfsml"
-				_cfsml_error("Token expected at line %d\n", *line);
-				return 1;
-			}
-			if (strcmp(value, "]")) {
-				if (i == max) {
-					_cfsml_error("More elements than space available (%d) in '%s' at line %d\n", max, token, *line);
-					return CFSML_FAILURE;
-				}
-				if (read_MemObjPtr(fh, &(save_struc->heap[i++]), value, line, hiteof)) {
-					_cfsml_error("Token expected by read_MemObjPtr() for heap[i++] at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				done = 1;
-			} while (!done);
-			save_struc->heap_size = max ; // Set array size accordingly
-			} else
-				if (!strcmp(token, "heap_size")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->heap_size), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for heap_size at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "reserved_id")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->reserved_id), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for reserved_id at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "exports_wide")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->exports_wide), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for exports_wide at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "gc_mark_bits")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->gc_mark_bits), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for gc_mark_bits at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "mem_allocated")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_size_t(fh, (size_t*) &(save_struc->mem_allocated), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_size_t() for mem_allocated at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "Clones_seg_id")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_SegmentId(fh, (SegmentId*) &(save_struc->Clones_seg_id), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_SegmentId() for Clones_seg_id at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "Lists_seg_id")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_SegmentId(fh, (SegmentId*) &(save_struc->Lists_seg_id), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_SegmentId() for Lists_seg_id at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "Nodes_seg_id")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_SegmentId(fh, (SegmentId*) &(save_struc->Nodes_seg_id), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_SegmentId() for Nodes_seg_id at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-#line 700 "engines/sci/engine/savegame.cfsml"
-			{
-				_cfsml_error("SegManager: Assignment to invalid identifier '%s' in line %d\n", token, *line);
-				return CFSML_FAILURE;
-			}
-		}
-	} while (!closed); // Until closing braces are hit
-	return CFSML_SUCCESS;
+	sync_sfx_state_t(s, sound);
 }
 
-#line 396 "engines/sci/engine/savegame.cfsml"
-static void
-_cfsml_write_song_t(Common::WriteStream *fh, song_t const * save_struc)
-{
-#line 413 "engines/sci/engine/savegame.cfsml"
-	WSprintf(fh, "{\n");
-	WSprintf(fh, "handle = ");
-	_cfsml_write_song_handle_t(fh, (song_handle_t const *) &(save_struc->handle));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "resource_num = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->resource_num));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "priority = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->priority));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "status = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->status));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "restore_behavior = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->restore_behavior));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "restore_time = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->restore_time));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "loops = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->loops));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "hold = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->hold));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "}");
-}
+static void sync_LocalVariables(Common::Serializer &s, LocalVariables &obj) {
+	s.syncAsSint32LE(obj.script_id);
+	s.syncAsSint32LE(obj.nr);
 
-#line 487 "engines/sci/engine/savegame.cfsml"
-static int
-_cfsml_read_song_t(Common::SeekableReadStream *fh, song_t* save_struc, const char *lastval, int *line, int *hiteof)
-{
-#line 542 "engines/sci/engine/savegame.cfsml"
-	char *token;
-	int assignment, closed;
-
-	if (strcmp(lastval, "{")) {
-		_cfsml_error("Reading record song_t; expected opening braces in line %d, got \"%s\"\n", *line, lastval);
-		return CFSML_FAILURE;
-	};
-	closed = 0;
-	do {
-		const char *value;
-		token = _cfsml_get_identifier(fh, line, hiteof, &assignment);
-
-		if (!token) {
-			_cfsml_error("Expected token at line %d\n", *line);
-			return CFSML_FAILURE;
-		}
-		if (!assignment) {
-			if (!strcmp(token, "}"))
-				closed = 1;
-			else {
-				_cfsml_error("Expected assignment or closing braces in line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-		} else {
-			value = "";
-			while (!value || !strcmp(value, ""))
-				value = _cfsml_get_value(fh, line, hiteof);
-			if (!value) {
-				_cfsml_error("Expected token at line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-				if (!strcmp(token, "handle")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_song_handle_t(fh, (song_handle_t*) &(save_struc->handle), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_song_handle_t() for handle at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "resource_num")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->resource_num), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for resource_num at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "priority")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->priority), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for priority at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "status")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->status), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for status at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "restore_behavior")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->restore_behavior), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for restore_behavior at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "restore_time")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->restore_time), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for restore_time at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "loops")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->loops), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for loops at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "hold")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->hold), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for hold at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-#line 700 "engines/sci/engine/savegame.cfsml"
-			{
-				_cfsml_error("song_t: Assignment to invalid identifier '%s' in line %d\n", token, *line);
-				return CFSML_FAILURE;
-			}
-		}
-	} while (!closed); // Until closing braces are hit
-	return CFSML_SUCCESS;
+	if (!obj.locals && obj.nr)
+		obj.locals = (reg_t *)sci_calloc(obj.nr, sizeof(reg_t));
+	for (int i = 0; i < obj.nr; ++i)
+		sync_reg_t(s, obj.locals[i]);
 }
 
-#line 396 "engines/sci/engine/savegame.cfsml"
-static void
-_cfsml_write_menu_item_t(Common::WriteStream *fh, menu_item_t const * save_struc)
-{
-#line 413 "engines/sci/engine/savegame.cfsml"
-	WSprintf(fh, "{\n");
-	WSprintf(fh, "type = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->type));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "keytext = ");
-	_cfsml_write_string(fh, (const char * const *) &(save_struc->keytext));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "keytext_size = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->keytext_size));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "flags = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->flags));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "said = ");
-	int min, max;
-	min = max = MENU_SAID_SPEC_SIZE;
-#line 440 "engines/sci/engine/savegame.cfsml"
-	WSprintf(fh, "[%d][\n", max);
-	for (int i = 0; i < min; i++) {
-		_cfsml_write_byte(fh, &(save_struc->said[i]));
-		WSprintf(fh, "\n");
-	}
-	WSprintf(fh, "]");
-	WSprintf(fh, "\n");
-	WSprintf(fh, "said_pos = ");
-	write_reg_t(fh, (reg_t const *) &(save_struc->said_pos));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "text = ");
-	_cfsml_write_string(fh, (const char * const *) &(save_struc->text));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "text_pos = ");
-	write_reg_t(fh, (reg_t const *) &(save_struc->text_pos));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "modifiers = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->modifiers));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "key = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->key));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "enabled = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->enabled));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "tag = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->tag));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "}");
-}
+static void sync_Object(Common::Serializer &s, Object &obj) {
+	s.syncAsSint32LE(obj.flags);
+	sync_reg_t(s, obj.pos);
+	s.syncAsSint32LE(obj.variables_nr);
+	s.syncAsSint32LE(obj.variable_names_nr);
+	s.syncAsSint32LE(obj.methods_nr);
 
-#line 487 "engines/sci/engine/savegame.cfsml"
-static int
-_cfsml_read_menu_item_t(Common::SeekableReadStream *fh, menu_item_t* save_struc, const char *lastval, int *line, int *hiteof)
-{
-#line 542 "engines/sci/engine/savegame.cfsml"
-	char *token;
-	int assignment, closed;
-
-	if (strcmp(lastval, "{")) {
-		_cfsml_error("Reading record menu_item_t; expected opening braces in line %d, got \"%s\"\n", *line, lastval);
-		return CFSML_FAILURE;
-	};
-	closed = 0;
-	do {
-		const char *value;
-		token = _cfsml_get_identifier(fh, line, hiteof, &assignment);
-
-		if (!token) {
-			_cfsml_error("Expected token at line %d\n", *line);
-			return CFSML_FAILURE;
-		}
-		if (!assignment) {
-			if (!strcmp(token, "}"))
-				closed = 1;
-			else {
-				_cfsml_error("Expected assignment or closing braces in line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-		} else {
-			value = "";
-			while (!value || !strcmp(value, ""))
-				value = _cfsml_get_value(fh, line, hiteof);
-			if (!value) {
-				_cfsml_error("Expected token at line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-				if (!strcmp(token, "type")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->type), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for type at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "keytext")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_string(fh, (char **) &(save_struc->keytext), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_string() for keytext at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "keytext_size")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->keytext_size), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for keytext_size at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "flags")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->flags), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for flags at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "said")) {
-#line 605 "engines/sci/engine/savegame.cfsml"
-			if ((value[0] != '[') || (value[strlen(value) - 1] != '[')) {
-				_cfsml_error("Opening brackets expected at line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-			int max,done,i;
-			// Prepare to restore static array
-			max = MENU_SAID_SPEC_SIZE;
-#line 640 "engines/sci/engine/savegame.cfsml"
-			done = i = 0;
-			do {
-			if (!(value = _cfsml_get_identifier(fh, line, hiteof, NULL))) {
-#line 648 "engines/sci/engine/savegame.cfsml"
-				_cfsml_error("Token expected at line %d\n", *line);
-				return 1;
-			}
-			if (strcmp(value, "]")) {
-				if (i == max) {
-					_cfsml_error("More elements than space available (%d) in '%s' at line %d\n", max, token, *line);
-					return CFSML_FAILURE;
-				}
-				if (_cfsml_read_byte(fh, &(save_struc->said[i++]), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_byte() for said[i++] at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				done = 1;
-			} while (!done);
-			} else
-				if (!strcmp(token, "said_pos")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (read_reg_t(fh, (reg_t*) &(save_struc->said_pos), value, line, hiteof)) {
-					_cfsml_error("Token expected by read_reg_t() for said_pos at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "text")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_string(fh, (char **) &(save_struc->text), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_string() for text at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "text_pos")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (read_reg_t(fh, (reg_t*) &(save_struc->text_pos), value, line, hiteof)) {
-					_cfsml_error("Token expected by read_reg_t() for text_pos at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "modifiers")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->modifiers), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for modifiers at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "key")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->key), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for key at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "enabled")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->enabled), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for enabled at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-				if (!strcmp(token, "tag")) {
-#line 691 "engines/sci/engine/savegame.cfsml"
-				if (_cfsml_read_int(fh, (int*) &(save_struc->tag), value, line, hiteof)) {
-					_cfsml_error("Token expected by _cfsml_read_int() for tag at line %d\n", *line);
-					return CFSML_FAILURE;
-				}
-			} else
-#line 700 "engines/sci/engine/savegame.cfsml"
-			{
-				_cfsml_error("menu_item_t: Assignment to invalid identifier '%s' in line %d\n", token, *line);
-				return CFSML_FAILURE;
-			}
-		}
-	} while (!closed); // Until closing braces are hit
-	return CFSML_SUCCESS;
+	if (!obj.variables && obj.variables_nr)
+		obj.variables = (reg_t *)sci_calloc(obj.variables_nr, sizeof(reg_t));
+	for (int i = 0; i < obj.variables_nr; ++i)
+		sync_reg_t(s, obj.variables[i]);
 }
 
-#line 396 "engines/sci/engine/savegame.cfsml"
-static void
-_cfsml_write_bool(Common::WriteStream *fh, bool const * save_struc)
-{
-	WSprintf(fh, "%li", (long)*save_struc);
-}
+static void sync_Clone(Common::Serializer &s, Clone &obj) {
+	s.syncAsSint32LE(obj.flags);
+	sync_reg_t(s, obj.pos);
+	s.syncAsSint32LE(obj.variables_nr);
+	s.syncAsSint32LE(obj.variable_names_nr);
+	s.syncAsSint32LE(obj.methods_nr);
 
-#line 487 "engines/sci/engine/savegame.cfsml"
-static int
-_cfsml_read_bool(Common::SeekableReadStream *fh, bool* save_struc, const char *lastval, int *line, int *hiteof)
-{
-#line 507 "engines/sci/engine/savegame.cfsml"
-	char *token;
-
-	*save_struc = strtol(lastval, &token, 0);
-	if ((*save_struc == 0) && (token == lastval)) {
-		_cfsml_error("strtol failed at line %d\n", *line);
-		return CFSML_FAILURE;
-	}
-	if (*token != 0) {
-		_cfsml_error("Non-integer encountered while parsing int value at line %d\n", *line);
-		return CFSML_FAILURE;
-	}
-	return CFSML_SUCCESS;
+	if (!obj.variables && obj.variables_nr)
+		obj.variables = (reg_t *)sci_calloc(obj.variables_nr, sizeof(reg_t));
+	for (int i = 0; i < obj.variables_nr; ++i)
+		sync_reg_t(s, obj.variables[i]);
 }
 
-#line 396 "engines/sci/engine/savegame.cfsml"
-static void
-_cfsml_write_NodeTable(Common::WriteStream *fh, NodeTable const * save_struc)
-{
-#line 413 "engines/sci/engine/savegame.cfsml"
-	WSprintf(fh, "{\n");
-	WSprintf(fh, "entries_nr = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->entries_nr));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "first_free = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->first_free));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "entries_used = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->entries_used));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "max_entry = ");
-	_cfsml_write_int(fh, (int const *) &(save_struc->max_entry));
-	WSprintf(fh, "\n");
-	WSprintf(fh, "table = ");
-	int min, max;
-	min = max = save_struc->entries_nr;
-	if (!save_struc->table)
-		min = max = 0; /* Don't write if it points to NULL */
-#line 440 "engines/sci/engine/savegame.cfsml"
-	WSprintf(fh, "[%d][\n", max);
-	for (int i = 0; i < min; i++) {
-		_cfsml_write_NodeEntry(fh, &(save_struc->table[i]));
-		WSprintf(fh, "\n");
-	}
-	WSprintf(fh, "]");
-	WSprintf(fh, "\n");
-	WSprintf(fh, "}");
+static void sync_List(Common::Serializer &s, List &obj) {
+	sync_reg_t(s, obj.first);
+	sync_reg_t(s, obj.last);
 }
 
-#line 487 "engines/sci/engine/savegame.cfsml"
-static int
-_cfsml_read_NodeTable(Common::SeekableReadStream *fh, NodeTable* save_struc, const char *lastval, int *line, int *hiteof)
-{
-#line 542 "engines/sci/engine/savegame.cfsml"
-	char *token;
-	int assignment, closed;
-
-	if (strcmp(lastval, "{")) {
-		_cfsml_error("Reading record NodeTable; expected opening braces in line %d, got \"%s\"\n", *line, lastval);
-		return CFSML_FAILURE;
-	};
-	closed = 0;
-	do {
-		const char *value;
-		token = _cfsml_get_identifier(fh, line, hiteof, &assignment);
-
-		if (!token) {
-			_cfsml_error("Expected token at line %d\n", *line);
-			return CFSML_FAILURE;
-		}
-		if (!assignment) {
-			if (!strcmp(token, "}"))
-				closed = 1;
-			else {
-				_cfsml_error("Expected assignment or closing braces in line %d\n", *line);
-				return CFSML_FAILURE;
-			}
-		} else {
-			value = "";
-			while (!value || !strcmp(value, ""))
-				value = _cfsml_get_value(fh, line, hiteof);
-			if (!value) {
-				_cfsml_error("Expected token at line %d\n", *line);

@@ Diff output truncated at 100000 characters. @@

This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list