[Scummvm-cvs-logs] SF.net SVN: scummvm:[55676] scummvm/trunk/engines/gob

drmccoy at users.sourceforge.net drmccoy at users.sourceforge.net
Mon Jan 31 11:49:43 CET 2011


Revision: 55676
          http://scummvm.svn.sourceforge.net/scummvm/?rev=55676&view=rev
Author:   drmccoy
Date:     2011-01-31 10:49:43 +0000 (Mon, 31 Jan 2011)

Log Message:
-----------
GOB: Add support for dBase III files

Implementing o7_opendBase, o7_closedBase and o7_getDBString

Modified Paths:
--------------
    scummvm/trunk/engines/gob/inter.h
    scummvm/trunk/engines/gob/inter_v7.cpp
    scummvm/trunk/engines/gob/module.mk

Added Paths:
-----------
    scummvm/trunk/engines/gob/databases.cpp
    scummvm/trunk/engines/gob/databases.h
    scummvm/trunk/engines/gob/dbase.cpp
    scummvm/trunk/engines/gob/dbase.h

Added: scummvm/trunk/engines/gob/databases.cpp
===================================================================
--- scummvm/trunk/engines/gob/databases.cpp	                        (rev 0)
+++ scummvm/trunk/engines/gob/databases.cpp	2011-01-31 10:49:43 UTC (rev 55676)
@@ -0,0 +1,175 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/file.h"
+
+#include "gob/databases.h"
+
+namespace Gob {
+
+Databases::Databases() : _language(Common::UNK_LANG) {
+}
+
+Databases::~Databases() {
+}
+
+void Databases::setLanguage(Common::Language language) {
+	Common::String lang;
+
+	if      (language == Common::UNK_LANG)
+		lang = "";
+	else if (language == Common::EN_ANY)
+		lang = "E";
+	else if (language == Common::EN_GRB)
+		lang = "E";
+	else if (language == Common::EN_USA)
+		lang = "E";
+	else if (language == Common::DE_DEU)
+		lang = "G";
+	else if (language == Common::FR_FRA)
+		lang = "F";
+	else
+		warning("Databases::setLanguage(): Language \"%s\" not supported",
+				Common::getLanguageDescription(language));
+
+	if (!_databases.empty() && (lang != _language))
+		warning("Databases::setLanguage(): \"%s\" != \"%s\" and there's still databases open!",
+				_language.c_str(), lang.c_str());
+
+	_language = lang;
+}
+
+bool Databases::open(const Common::String &id, const Common::String &file) {
+	if (_databases.contains(id)) {
+		warning("Databases::open(): A database with the ID \"%s\" already exists", id.c_str());
+		return false;
+	}
+
+	Common::File dbFile;
+	if (!dbFile.open(file)) {
+		warning("Databases::open(): No such file \"%s\"", file.c_str());
+		return false;
+	}
+
+	dBase db;
+	if (!db.load(dbFile)) {
+		warning("Databases::open(): Failed loading database file \"%s\"", file.c_str());
+		return false;
+	}
+
+	_databases.setVal(id, Common::StringMap());
+	DBMap::iterator map = _databases.find(id);
+	assert(map != _databases.end());
+
+	if (!buildMap(db, map->_value)) {
+		warning("Databases::open(): Failed building a map for database \"%s\"", file.c_str());
+		_databases.erase(map);
+		return false;
+	}
+
+	return true;
+}
+
+bool Databases::close(const Common::String &id) {
+	DBMap::iterator db = _databases.find(id);
+	if (db == _databases.end()) {
+		warning("Databases::open(): A database with the ID \"%s\" does not exist", id.c_str());
+		return false;
+	}
+
+	_databases.erase(db);
+	return true;
+}
+
+bool Databases::getString(const Common::String &id, Common::String group,
+		Common::String section, Common::String keyword, Common::String &result) const {
+
+	DBMap::iterator db = _databases.find(id);
+	if (db == _databases.end()) {
+		warning("Databases::getString(): A database with the ID \"%s\" does not exist", id.c_str());
+		return false;
+	}
+
+	if (_language.empty()) {
+		warning("Databases::getString(): No language set");
+		return false;
+	}
+
+	Common::String key = _language + ":" + group + ":" + section + ":" + keyword;
+
+	Common::StringMap::const_iterator entry = db->_value.find(key);
+	if (entry == db->_value.end())
+		return false;
+
+	result = entry->_value;
+	return true;
+}
+
+int Databases::findField(const dBase &db, const Common::String &field,
+		dBase::Type type) const {
+
+	const Common::Array<dBase::Field> &fields = db.getFields();
+
+	for (uint i = 0; i < fields.size(); i++) {
+		if (!fields[i].name.equalsIgnoreCase(field))
+			continue;
+
+		if (fields[i].type != type)
+			return -1;
+
+		return i;
+	}
+
+	return -1;
+}
+
+bool Databases::buildMap(const dBase &db, Common::StringMap &map) const {
+	int fLanguage = findField(db, "Langage", dBase::kTypeString);
+	int fGroup    = findField(db, "Nom"    , dBase::kTypeString);
+	int fSection  = findField(db, "Section", dBase::kTypeString);
+	int fKeyword  = findField(db, "Motcle" , dBase::kTypeString);
+	int fText     = findField(db, "Texte"  , dBase::kTypeString);
+
+	if ((fLanguage < 0) || (fGroup < 0) || (fSection < 0) || (fKeyword < 0) || (fText < 0))
+		return false;
+
+	const Common::Array<dBase::Record> &records = db.getRecords();
+
+	Common::Array<dBase::Record>::const_iterator record;
+	for (record = records.begin(); record != records.end(); ++record) {
+		Common::String key;
+
+		key += db.getString(*record, fLanguage) + ":";
+		key += db.getString(*record, fGroup   ) + ":";
+		key += db.getString(*record, fSection ) + ":";
+		key += db.getString(*record, fKeyword );
+
+		map.setVal(key, db.getString(*record, fText));
+	}
+
+	return true;
+}
+
+} // End of namespace Gob


Property changes on: scummvm/trunk/engines/gob/databases.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/engines/gob/databases.h
===================================================================
--- scummvm/trunk/engines/gob/databases.h	                        (rev 0)
+++ scummvm/trunk/engines/gob/databases.h	2011-01-31 10:49:43 UTC (rev 55676)
@@ -0,0 +1,64 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef GOB_DATABASES_H
+#define GOB_DATABASES_H
+
+#include "common/str.h"
+#include "common/hashmap.h"
+#include "common/hash-str.h"
+#include "common/util.h"
+
+#include "gob/dbase.h"
+
+namespace Gob {
+
+class Databases {
+public:
+	Databases();
+	~Databases();
+
+	void setLanguage(Common::Language language);
+
+	bool open(const Common::String &id, const Common::String &file);
+	bool close(const Common::String &id);
+
+	bool getString(const Common::String &id, Common::String group,
+			Common::String section, Common::String keyword, Common::String &result) const;
+
+private:
+	typedef Common::HashMap<Common::String, Common::StringMap, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> DBMap;
+
+	DBMap _databases;
+
+	Common::String _language;
+
+	int findField(const dBase &db, const Common::String &field, dBase::Type type) const;
+	bool buildMap(const dBase &db, Common::StringMap &map) const;
+};
+
+} // End of namespace Gob
+
+#endif // GOB_DATABASES_H


Property changes on: scummvm/trunk/engines/gob/databases.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/engines/gob/dbase.cpp
===================================================================
--- scummvm/trunk/engines/gob/dbase.cpp	                        (rev 0)
+++ scummvm/trunk/engines/gob/dbase.cpp	2011-01-31 10:49:43 UTC (rev 55676)
@@ -0,0 +1,195 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "gob/dbase.h"
+
+namespace Gob {
+
+dBase::dBase() : _recordData(0) {
+	clear();
+}
+
+dBase::~dBase() {
+	clear();
+}
+
+bool dBase::load(Common::SeekableReadStream &stream) {
+	clear();
+
+	uint32 startPos = stream.pos();
+
+	_version = stream.readByte();
+	if ((_version != 0x03) && (_version != 0x83))
+		// Unsupported version
+		return false;
+
+	// TODO: Add support for memo files. A memo file is an external data file
+	//       .DBT, segmented into "blocks". Each memo field in a record is an
+	//       index this file.
+	_hasMemo = (_version & 0x80) != 0;
+
+	_lastUpdate.tm_year = stream.readByte();
+	_lastUpdate.tm_mon  = stream.readByte();
+	_lastUpdate.tm_mday = stream.readByte();
+	_lastUpdate.tm_hour = 0;
+	_lastUpdate.tm_min  = 0;
+	_lastUpdate.tm_sec  = 0;
+
+	uint32 recordCount = stream.readUint32LE();
+	uint32 headerSize  = stream.readUint16LE();
+	uint32 recordSize  = stream.readUint16LE();
+
+	stream.skip(20); // Reserved
+
+	// Read all field descriptions, 0x0D is the end marker
+	uint32 fieldsLength = 0;
+	while (!stream.eos() && !stream.err() && (stream.readByte() != 0x0D)) {
+		Field field;
+
+		stream.skip(-1);
+
+		field.name = readString(stream, 11);
+		field.type = (Type) stream.readByte();
+
+		stream.skip(4); // Field data address
+
+		field.size     = stream.readByte();
+		field.decimals = stream.readByte();
+
+		fieldsLength += field.size;
+
+		stream.skip(14); // Reserved and/or useless for us
+
+		_fields.push_back(field);
+	}
+
+	if (stream.eos() || stream.err())
+		return false;
+
+	if ((stream.pos() - startPos) != headerSize)
+		// Corrupted file / unknown format
+		return false;
+
+	if (recordSize != (fieldsLength + 1))
+		// Corrupted file / unknown format
+		return false;
+
+	_recordData = new byte[recordSize * recordCount];
+	if (stream.read(_recordData, recordSize * recordCount) != (recordSize * recordCount))
+		return false;
+
+	if (stream.readByte() != 0x1A)
+		// Missing end marker
+		return false;
+
+	uint32 fieldCount = _fields.size();
+
+	// Create the records array
+	_records.resize(recordCount);
+	for (uint32 i = 0; i < recordCount; i++) {
+		Record &record = _records[i];
+		const byte *data = _recordData + i * recordSize;
+
+		char status = *data++;
+		if ((status != ' ') && (status != '*'))
+			// Corrupted file / unknown format
+			return false;
+
+		record.deleted = status == '*';
+
+		record.fields.resize(fieldCount);
+		for (uint32 j = 0; j < fieldCount; j++) {
+			record.fields[j] = data;
+			data += _fields[j].size;
+		}
+	}
+
+	return true;
+}
+
+void dBase::clear() {
+	memset(&_lastUpdate, 0, sizeof(_lastUpdate));
+
+	_version = 0;
+	_hasMemo = false;
+
+	_fields.clear();
+	_records.clear();
+
+	delete[] _recordData;
+	_recordData = 0;
+}
+
+byte dBase::getVersion() const {
+	return _version;
+}
+
+TimeDate dBase::getLastUpdate() const {
+	return _lastUpdate;
+}
+
+const Common::Array<dBase::Field> &dBase::getFields() const {
+	return _fields;
+}
+
+const Common::Array<dBase::Record> &dBase::getRecords() const {
+	return _records;
+}
+
+Common::String dBase::getString(const Record &record, int field) const {
+	assert(_fields[field].type == kTypeString);
+
+	uint32 fieldLength = stringLength(record.fields[field], _fields[field].size);
+	return Common::String((const char *) record.fields[field], fieldLength);
+}
+
+// String fields are padded with spaces. This finds the real length.
+inline uint32 dBase::stringLength(const byte *data, uint32 max) {
+	while (max-- > 0)
+		if ((data[max] != 0x20) && (data[max] != 0x00))
+			return max + 1;
+
+	return 0;
+}
+
+// Read a constant-length string out of a stream.
+inline Common::String dBase::readString(Common::SeekableReadStream &stream, int n) {
+	Common::String str;
+
+	char c;
+	while (n-- > 0) {
+		if ((c = stream.readByte()) == '\0')
+			break;
+
+		str += c;
+	}
+
+	if (n > 0)
+		stream.skip(n);
+
+	return str;
+}
+
+} // End of namespace Gob


Property changes on: scummvm/trunk/engines/gob/dbase.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/engines/gob/dbase.h
===================================================================
--- scummvm/trunk/engines/gob/dbase.h	                        (rev 0)
+++ scummvm/trunk/engines/gob/dbase.h	2011-01-31 10:49:43 UTC (rev 55676)
@@ -0,0 +1,103 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef GOB_DBASE_H
+#define GOB_DBASE_H
+
+#include "common/system.h"
+#include "common/util.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/array.h"
+
+namespace Gob {
+
+/**
+ * A class for reading dBase files.
+ *
+ * Only dBase III files supported for now, and only field type
+ * string is actually useful. Further missing is reading of MDX
+ * index files and support for the external "Memo" data file.
+ */
+class dBase {
+public:
+	enum Type {
+		kTypeString = 0x43, // 'C'
+		kTypeDate   = 0x44, // 'D'
+		kTypeBool   = 0x4C, // 'L'
+		kTypeMemo   = 0x4D, // 'M'
+		kTypeNumber = 0x4E  // 'N'
+	};
+
+	/** A field description. */
+	struct Field {
+		Common::String name; ///< Name of the field.
+
+		Type  type;     ///< Type of the field.
+		uint8 size;     ///< Size of raw field data in bytes.
+		uint8 decimals; ///< Number of decimals the field holds.
+	};
+
+	/** A record. */
+	struct Record {
+		bool deleted; ///< Has this record been deleted?
+		Common::Array<const byte *> fields; ///< Raw field data.
+	};
+
+	dBase();
+	~dBase();
+
+	bool load(Common::SeekableReadStream &stream);
+	void clear();
+
+	byte getVersion() const;
+
+	/** Return the date the database was last updated. */
+	TimeDate getLastUpdate() const;
+
+	const Common::Array<Field>  &getFields()  const;
+	const Common::Array<Record> &getRecords() const;
+
+	/** Extract a string out of raw field data. */
+	Common::String getString(const Record &record, int field) const;
+
+private:
+	byte _version;
+	bool _hasMemo;
+
+	TimeDate _lastUpdate;
+
+	Common::Array<Field>  _fields;
+	Common::Array<Record> _records;
+
+	byte *_recordData;
+
+	static inline uint32 stringLength(const byte *data, uint32 max);
+	static inline Common::String readString(Common::SeekableReadStream &stream, int n);
+};
+
+} // End of namespace Gob
+
+#endif // GOB_DBASE_H


Property changes on: scummvm/trunk/engines/gob/dbase.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Modified: scummvm/trunk/engines/gob/inter.h
===================================================================
--- scummvm/trunk/engines/gob/inter.h	2011-01-31 10:49:03 UTC (rev 55675)
+++ scummvm/trunk/engines/gob/inter.h	2011-01-31 10:49:43 UTC (rev 55676)
@@ -32,6 +32,7 @@
 #include "gob/goblin.h"
 #include "gob/variables.h"
 #include "gob/iniconfig.h"
+#include "gob/databases.h"
 
 namespace Gob {
 
@@ -625,6 +626,7 @@
 
 private:
 	INIConfig _inis;
+	Databases _databases;
 
 	void storeValue(uint16 index, uint16 type, uint32 value);
 	void storeValue(uint32 value);

Modified: scummvm/trunk/engines/gob/inter_v7.cpp
===================================================================
--- scummvm/trunk/engines/gob/inter_v7.cpp	2011-01-31 10:49:03 UTC (rev 55675)
+++ scummvm/trunk/engines/gob/inter_v7.cpp	2011-01-31 10:49:43 UTC (rev 55676)
@@ -413,17 +413,23 @@
 
 	dbFile += ".DBF";
 
-	warning("Addy Stub: Open dBase \"%s\" (\"%s\")", id.c_str(), dbFile.c_str());
+	if (!_databases.open(id, dbFile)) {
+		WRITE_VAR(27, 0); // Failure
+		return;
+	}
 
-	WRITE_VAR(27, 0); // Failure
+	_databases.setLanguage(_vm->_language);
+
+	WRITE_VAR(27, 1); // Success
 }
 
 void Inter_v7::o7_closedBase() {
 	Common::String id = _vm->_game->_script->evalString();
 
-	warning("Addy Stub: Close dBase \"%s\"", id.c_str());
-
-	WRITE_VAR(27, 0); // Failure
+	if (_databases.close(id))
+		WRITE_VAR(27, 1); // Success
+	else
+		WRITE_VAR(27, 0); // Failure
 }
 
 void Inter_v7::o7_getDBString() {
@@ -432,12 +438,15 @@
 	Common::String section = _vm->_game->_script->evalString();
 	Common::String keyword = _vm->_game->_script->evalString();
 
-	uint16 varIndex = _vm->_game->_script->readVarIndex();
+	Common::String result;
+	if (!_databases.getString(id, group, section, keyword, result)) {
+		WRITE_VAR(27, 0); // Failure
+		storeString("");
+		return;
+	}
 
-	warning("Addy Stub: Get DB string: \"%s\", \"%s\", \"%s\", \"%s\", %d",
-			id.c_str(), group.c_str(), section.c_str(), keyword.c_str(), varIndex);
-
-	WRITE_VAR(27, 0); // Failure
+	storeString(result.c_str());
+	WRITE_VAR(27, 1); // Success
 }
 
 void Inter_v7::o7_oemToANSI(OpGobParams &params) {
@@ -470,23 +479,40 @@
 }
 
 void Inter_v7::storeString(uint16 index, uint16 type, const char *value) {
-	if (type == TYPE_VAR_STR) {
-		char *str = GET_VARO_STR(index);
+	uint32 maxLength = _vm->_global->_inter_animDataSize * 4 - 1;
+	char  *str       = GET_VARO_STR(index);
 
-		strncpy(str, value, _vm->_global->_inter_animDataSize);
-		str[_vm->_global->_inter_animDataSize - 1] = '\0';
+	switch (type) {
+	case TYPE_VAR_STR:
+		if (strlen(value) > maxLength)
+			warning("Inter_v7::storeString(): String too long");
 
-	} else if (type == TYPE_IMM_INT8) {
+		Common::strlcpy(str, value, maxLength);
+		break;
 
-		strcpy(GET_VARO_STR(index), value);
+	case TYPE_IMM_INT8:
+	case TYPE_VAR_INT8:
+		strcpy(str, value);
+		break;
 
-	} else if (type == TYPE_VAR_INT32) {
+	case TYPE_ARRAY_INT8:
+		WRITE_VARO_UINT8(index, atoi(value));
+		break;
 
+	case TYPE_VAR_INT16:
+	case TYPE_VAR_INT32_AS_INT16:
+	case TYPE_ARRAY_INT16:
+		WRITE_VARO_UINT16(index, atoi(value));
+		break;
+
+	case TYPE_VAR_INT32:
+	case TYPE_ARRAY_INT32:
 		WRITE_VARO_UINT32(index, atoi(value));
+		break;
 
-	} else if (type == TYPE_VAR_INT16) {
-
-		WRITE_VARO_UINT16(index, atoi(value));
+	default:
+		warning("Inter_v7::storeString(): Requested to store a string into type %d", type);
+		break;
 	}
 }
 

Modified: scummvm/trunk/engines/gob/module.mk
===================================================================
--- scummvm/trunk/engines/gob/module.mk	2011-01-31 10:49:03 UTC (rev 55675)
+++ scummvm/trunk/engines/gob/module.mk	2011-01-31 10:49:43 UTC (rev 55676)
@@ -3,6 +3,8 @@
 MODULE_OBJS := \
 	console.o \
 	dataio.o \
+	databases.o \
+	dbase.o \
 	detection.o \
 	draw.o \
 	draw_v1.o \


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