[Scummvm-cvs-logs] SF.net SVN: scummvm:[44387] scummvm/trunk/engines/sci/engine

wjpalenstijn at users.sourceforge.net wjpalenstijn at users.sourceforge.net
Sun Sep 27 03:49:56 CEST 2009


Revision: 44387
          http://scummvm.svn.sourceforge.net/scummvm/?rev=44387&view=rev
Author:   wjpalenstijn
Date:     2009-09-27 01:49:56 +0000 (Sun, 27 Sep 2009)

Log Message:
-----------
SCI: Add utility functions for copying data between raw/non-raw segments

Modified Paths:
--------------
    scummvm/trunk/engines/sci/engine/seg_manager.cpp
    scummvm/trunk/engines/sci/engine/seg_manager.h
    scummvm/trunk/engines/sci/engine/segment.h

Modified: scummvm/trunk/engines/sci/engine/seg_manager.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/seg_manager.cpp	2009-09-27 01:49:35 UTC (rev 44386)
+++ scummvm/trunk/engines/sci/engine/seg_manager.cpp	2009-09-27 01:49:56 UTC (rev 44387)
@@ -836,7 +836,7 @@
 static void *_kernel_dereference_pointer(SegManager *segMan, reg_t pointer, int entries, bool wantRaw) {
 	SegmentRef ret = segMan->dereference(pointer);
 
-	if (!ret.raw)
+	if (!ret.isValid())
 		return NULL;
 
 	if (ret.isRaw != wantRaw) {
@@ -872,7 +872,270 @@
 	return (char *)_kernel_dereference_pointer(this, pointer, entries, true);
 }
 
+// TODO: memcpy, strcpy and strncpy could maybe be folded into a single function
+void SegManager::strncpy(reg_t dest, const char* src, size_t n) {
+	SegmentRef dest_r = dereference(dest);
+	if (!dest_r.isValid()) {
+		warning("Attempt to strncpy to invalid pointer %04x:%04x", PRINT_REG(dest));
+		return;
+	}
 
+	if (dest_r.isRaw) {
+		// raw -> raw
+		if (n == 0xFFFFFFFFU)
+			::strcpy((char*)dest_r.raw, src);
+		else
+			::strncpy((char*)dest_r.raw, src, n);
+	} else {
+		// raw -> non-raw
+		reg_t* d = dest_r.reg;
+		while (n > 0) {
+			d->segment = 0; // STRINGFRAG_SEGMENT?
+			if (n > 1 && src[0]) {
+				d->offset = src[0] | (src[1] << 8);
+			} else {
+				d->offset &= 0xff00;
+				d->offset |= src[0];
+				break;
+			}
+
+			if (!src[1])
+				break;
+			src += 2;
+			n -= 2;
+			d++;
+		}
+	}
+}
+
+void SegManager::strncpy(reg_t dest, reg_t src, size_t n) {
+	SegmentRef dest_r = dereference(dest);
+	const SegmentRef src_r = dereference(src);
+	if (!src_r.isValid()) {
+		warning("Attempt to strncpy from invalid pointer %04x:%04x", PRINT_REG(src));
+		return;
+	}
+
+	if (!dest_r.isValid()) {
+		warning("Attempt to strncpy to invalid pointer %04x:%04x", PRINT_REG(dest));
+		return;
+	}
+
+
+	if (src_r.isRaw) {
+		// raw -> *
+		strncpy(dest, (const char*)src_r.raw, n);
+	} else if (dest_r.isRaw && !src_r.isRaw) {
+		// non-raw -> raw
+		const reg_t* s = src_r.reg;
+		char *d = (char*)dest_r.raw;
+		reg_t x;
+		while (n > 0) {
+			x = *s++;
+			*d++ = x.offset & 0x00ff;
+			if (n > 1 && x.offset & 0x00ff) {
+				*d++ = x.offset >> 8;
+			} else {
+				break;
+			}
+			if (!(x.offset >> 8))
+				break;
+			n -= 2;
+		}
+	} else {
+		// non-raw -> non-raw
+		const reg_t* s = src_r.reg;
+		reg_t* d = dest_r.reg;
+		reg_t x;
+		while (n > 0) {
+			x = *s++;
+			if (n > 1 && x.offset & 0x00ff) {
+				*d++ = x;
+			} else {
+				d->offset &= 0xff00;
+				d->offset |= x.offset & 0x00ff;
+				break;
+			}
+			if (!(x.offset & 0xff00))
+				break;
+			n -= 2;
+		}
+	}
+}
+
+void SegManager::strcpy(reg_t dest, const char* src) {
+	strncpy(dest, src, 0xFFFFFFFFU);
+}
+
+void SegManager::strcpy(reg_t dest, reg_t src) {
+	strncpy(dest, src, 0xFFFFFFFFU);
+}
+
+void SegManager::memcpy(reg_t dest, const byte* src, size_t n) {
+	SegmentRef dest_r = dereference(dest);
+	if (!dest_r.isValid()) {
+		warning("Attempt to memcpy to invalid pointer %04x:%04x", PRINT_REG(dest));
+		return;
+	}
+	if ((int)n > dest_r.maxSize) {
+		warning("Trying to dereference pointer %04x:%04x beyond end of segment", PRINT_REG(dest));
+		return;
+	}
+
+	if (dest_r.isRaw) {
+		// raw -> raw
+		::memcpy((char*)dest_r.raw, src, n);
+	} else {
+		// raw -> non-raw
+		reg_t* d = dest_r.reg;
+		while (n > 0) {
+			d->segment = 0; // STRINGFRAG_SEGMENT?
+			if (n > 1) {
+				d->offset = src[0] | (src[1] << 8);
+			} else {
+				d->offset &= 0xff00;
+				d->offset |= src[0];
+				break;
+			}
+			src += 2;
+			n -= 2;
+			d++;
+		}
+	}
+}
+
+void SegManager::memcpy(reg_t dest, reg_t src, size_t n) {
+	SegmentRef dest_r = dereference(dest);
+	const SegmentRef src_r = dereference(src);
+	if (!dest_r.isValid()) {
+		warning("Attempt to memcpy to invalid pointer %04x:%04x", PRINT_REG(dest));
+		return;
+	}
+	if ((int)n > dest_r.maxSize) {
+		warning("Trying to dereference pointer %04x:%04x beyond end of segment", PRINT_REG(dest));
+		return;
+	}
+	if (!src_r.isValid()) {
+		warning("Attempt to memcpy from invalid pointer %04x:%04x", PRINT_REG(src));
+		return;
+	}
+	if ((int)n > src_r.maxSize) {
+		warning("Trying to dereference pointer %04x:%04x beyond end of segment", PRINT_REG(src));
+		return;
+	}
+
+	if (src_r.isRaw) {
+		// raw -> *
+		memcpy(dest, src_r.raw, n);
+	} else if (dest_r.isRaw) {
+		// * -> raw
+		memcpy(dest_r.raw, src, n);
+	} else {
+		// non-raw -> non-raw
+		const reg_t* s = src_r.reg;
+		reg_t* d = dest_r.reg;
+		reg_t x;
+		while (n > 0) {
+			x = *s++;
+			if (n > 1) {
+				*d++ = x;
+			} else {
+				d->offset &= 0xff00;
+				d->offset |= x.offset & 0x00ff;
+				break;
+			}
+			n -= 2;
+		}
+	}
+}
+
+void SegManager::memcpy(byte *dest, reg_t src, size_t n) {
+	const SegmentRef src_r = dereference(src);
+	if (!src_r.isValid()) {
+		warning("Attempt to memcpy from invalid pointer %04x:%04x", PRINT_REG(src));
+		return;
+	}
+	if ((int)n > src_r.maxSize) {
+		warning("Trying to dereference pointer %04x:%04x beyond end of segment", PRINT_REG(src));
+		return;
+	}
+
+	if (src_r.isRaw) {
+		// raw -> raw
+		::memcpy(dest, src_r.raw, n);
+	} else {
+		// non-raw -> raw
+		const reg_t* s = src_r.reg;
+		reg_t x;
+		while (n > 0) {
+			x = *s++;
+			*dest++ = x.offset & 0x00ff;
+			if (n > 1) {
+				*dest++ = x.offset >> 8;
+			} else {
+				break;
+			}
+			n -= 2;
+		}
+	}
+}
+
+size_t SegManager::strlen(reg_t str) {
+	SegmentRef str_r = dereference(str);
+	if (!str_r.isValid()) {
+		warning("Attempt to call strlen on invalid pointer %04x:%04x", PRINT_REG(str));
+		return 0;
+	}
+
+	if (str_r.isRaw) {
+		return ::strlen((const char*)str_r.raw);
+	} else {
+		const reg_t* s = str_r.reg;
+		size_t n = 0;
+		while ((s->offset & 0x00ff) && (s->offset >> 8)) {
+			++s;
+			n += 2;
+		}
+		if (s->offset & 0x00ff)
+			n++;
+		return n;
+	}
+}
+
+
+Common::String SegManager::getString(reg_t pointer, int entries)
+{
+	Common::String ret;
+	SegmentRef src_r = dereference(pointer);
+	if (!src_r.isValid()) {
+		warning("Attempt to dereference invalid pointer %04x:%04x", PRINT_REG(pointer));
+		return ret;
+	}
+	if (entries > src_r.maxSize) {
+		warning("Trying to dereference pointer %04x:%04x beyond end of segment", PRINT_REG(pointer));
+		return ret;
+	}
+	if (src_r.isRaw)
+		ret = (char*)src_r.raw;
+	else {
+		const reg_t* s = src_r.reg;
+		char c;
+		do {
+			c = s->offset & 0x00ff;
+			if (c) {
+				ret += c;
+				c = s->offset >> 8;
+				if (c) {
+					ret += c;
+					s++;
+				}
+			}
+		} while (c);
+	}
+	return ret;
+}
+
+
 byte *SegManager::allocDynmem(int size, const char *descr, reg_t *addr) {
 	SegmentId seg;
 	SegmentObj *mobj = allocSegment(new DynMem(), &seg);

Modified: scummvm/trunk/engines/sci/engine/seg_manager.h
===================================================================
--- scummvm/trunk/engines/sci/engine/seg_manager.h	2009-09-27 01:49:35 UTC (rev 44386)
+++ scummvm/trunk/engines/sci/engine/seg_manager.h	2009-09-27 01:49:56 UTC (rev 44387)
@@ -312,6 +312,74 @@
 	char *derefString(reg_t pointer, int entries = 0);
 
 	/**
+	 * Return the string referenced by pointer.
+	 * pointer can point to either a raw or non-raw segment.
+	 * @param pointer The pointer to dereference
+	 * @parm entries The number of values expected (for checking)
+	 * @return The string referenced, or an empty string if not enough
+	 * entries were available.
+	 */
+	Common::String getString(reg_t pointer, int entries = 0);
+
+
+	/**
+	 * Copies a string from src to dest.
+	 * src and dest can point to raw and non-raw segments.
+	 * Conversion is performed as required.
+	 */
+	void strcpy(reg_t dest, reg_t src);
+
+	/**
+	 * Copies a string from src to dest.
+	 * dest can point to a raw or non-raw segment.
+	 * Conversion is performed as required.
+	 */
+	void strcpy(reg_t dest, const char *src);
+
+	/**
+	 * Copies a string from src to dest.
+	 * src and dest can point to raw and non-raw segments.
+	 * Conversion is performed as required. At most n characters are copied.
+	 * TODO: determine if dest should always be null-terminated.
+	 */
+	void strncpy(reg_t dest, reg_t src, size_t n);
+
+	/**
+	 * Copies a string from src to dest.
+	 * dest can point to a raw or non-raw segment.
+	 * Conversion is performed as required. At most n characters are copied.
+	 * TODO: determine if dest should always be null-terminated.
+	 */
+	void strncpy(reg_t dest, const char *src, size_t n);
+
+	/**
+	 * Copies n bytes of data from src to dest.
+	 * src and dest can point to raw and non-raw segments.
+	 * Conversion is performed as required.
+	 */
+	void memcpy(reg_t dest, reg_t src, size_t n);
+
+	/**
+	 * Copies n bytes of data from src to dest.
+	 * dest can point to a raw or non-raw segment.
+	 * Conversion is performed as required.
+	 */
+	void memcpy(reg_t dest, const byte* src, size_t n);
+
+	/**
+	 * Copies n bytes of data from src to dest.
+	 * src can point to raw and non-raw segments.
+	 * Conversion is performed as required.
+	 */
+	void memcpy(byte *dest, reg_t src, size_t n);
+
+	/**
+	 * Determine length of string at str.
+	 * str can point to a raw or non-raw segment.
+	 */
+	size_t strlen(reg_t str);
+
+	/**
 	 * Finds a unique segment by type
 	 * @param type	The type of the segment to find
 	 * @return		The segment number, or -1 if the segment wasn't found

Modified: scummvm/trunk/engines/sci/engine/segment.h
===================================================================
--- scummvm/trunk/engines/sci/engine/segment.h	2009-09-27 01:49:35 UTC (rev 44386)
+++ scummvm/trunk/engines/sci/engine/segment.h	2009-09-27 01:49:56 UTC (rev 44387)
@@ -48,6 +48,8 @@
 	//SegmentType type;
 
 	SegmentRef() : isRaw(true), raw(0), maxSize(0) {}
+
+	bool isValid() const { return raw != 0; }
 };
 
 


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