aboutsummaryrefslogtreecommitdiff
path: root/engines/wintermute/utils
diff options
context:
space:
mode:
Diffstat (limited to 'engines/wintermute/utils')
-rw-r--r--engines/wintermute/utils/ConvertUTF.c612
-rw-r--r--engines/wintermute/utils/ConvertUTF.h149
-rw-r--r--engines/wintermute/utils/PathUtil.cpp204
-rw-r--r--engines/wintermute/utils/PathUtil.h56
-rw-r--r--engines/wintermute/utils/StringUtil.cpp393
-rw-r--r--engines/wintermute/utils/StringUtil.h70
-rw-r--r--engines/wintermute/utils/crc.cpp234
-rw-r--r--engines/wintermute/utils/crc.h81
-rw-r--r--engines/wintermute/utils/utils.cpp342
-rw-r--r--engines/wintermute/utils/utils.h71
10 files changed, 2212 insertions, 0 deletions
diff --git a/engines/wintermute/utils/ConvertUTF.c b/engines/wintermute/utils/ConvertUTF.c
new file mode 100644
index 0000000000..8f7d6d2124
--- /dev/null
+++ b/engines/wintermute/utils/ConvertUTF.c
@@ -0,0 +1,612 @@
+/*
+ * Copyright 2001-2004 Unicode, Inc.
+ *
+ * Disclaimer
+ *
+ * This source code is provided as is by Unicode, Inc. No claims are
+ * made as to fitness for any particular purpose. No warranties of any
+ * kind are expressed or implied. The recipient agrees to determine
+ * applicability of information provided. If this file has been
+ * purchased on magnetic or optical media from Unicode, Inc., the
+ * sole remedy for any claim will be exchange of defective media
+ * within 90 days of receipt.
+ *
+ * Limitations on Rights to Redistribute This Code
+ *
+ * Unicode, Inc. hereby grants the right to freely use the information
+ * supplied in this file in the creation of products supporting the
+ * Unicode Standard, and to make copies of this file in any form
+ * for internal or external distribution as long as this notice
+ * remains attached.
+ */
+
+/* ---------------------------------------------------------------------
+
+ Conversions between UTF32, UTF-16, and UTF-8. Source code file.
+ Author: Mark E. Davis, 1994.
+ Rev History: Rick McGowan, fixes & updates May 2001.
+ Sept 2001: fixed const & error conditions per
+ mods suggested by S. Parent & A. Lillich.
+ June 2002: Tim Dodd added detection and handling of incomplete
+ source sequences, enhanced error detection, added casts
+ to eliminate compiler warnings.
+ July 2003: slight mods to back out aggressive FFFE detection.
+ Jan 2004: updated switches in from-UTF8 conversions.
+ Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
+
+ See the header file "ConvertUTF.h" for complete documentation.
+
+------------------------------------------------------------------------ */
+
+
+#include "ConvertUTF.h"
+#ifdef CVTUTF_DEBUG
+#include <stdio.h>
+#endif
+
+static const int halfShift = 10; /* used for shifting by 10 bits */
+
+static const UTF32 halfBase = 0x0010000UL;
+static const UTF32 halfMask = 0x3FFUL;
+
+#define UNI_SUR_HIGH_START (UTF32)0xD800
+#define UNI_SUR_HIGH_END (UTF32)0xDBFF
+#define UNI_SUR_LOW_START (UTF32)0xDC00
+#define UNI_SUR_LOW_END (UTF32)0xDFFF
+#define false 0
+#define true 1
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF32toUTF16(
+ const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF32 *source = *sourceStart;
+ UTF16 *target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ if (target >= targetEnd) {
+ result = targetExhausted;
+ break;
+ }
+ ch = *source++;
+ if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+ /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = (UTF16)ch; /* normal case */
+ }
+ } else if (ch > UNI_MAX_LEGAL_UTF32) {
+ if (flags == strictConversion) {
+ result = sourceIllegal;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ /* target is a character in range 0xFFFF - 0x10FFFF. */
+ if (target + 1 >= targetEnd) {
+ --source; /* Back up source pointer! */
+ result = targetExhausted;
+ break;
+ }
+ ch -= halfBase;
+ *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+ *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF16toUTF32(
+ const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF16 *source = *sourceStart;
+ UTF32 *target = *targetStart;
+ UTF32 ch, ch2;
+ while (source < sourceEnd) {
+ const UTF16 *oldSource = source; /* In case we have to back up because of target overflow. */
+ ch = *source++;
+ /* If we have a surrogate pair, convert to UTF32 first. */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+ /* If the 16 bits following the high surrogate are in the source buffer... */
+ if (source < sourceEnd) {
+ ch2 = *source;
+ /* If it's a low surrogate, convert to UTF32. */
+ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+ ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ + (ch2 - UNI_SUR_LOW_START) + halfBase;
+ ++source;
+ } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ } else { /* We don't have the 16 bits following the high surrogate. */
+ --source; /* return to the high surrogate */
+ result = sourceExhausted;
+ break;
+ }
+ } else if (flags == strictConversion) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ if (target >= targetEnd) {
+ source = oldSource; /* Back up source pointer! */
+ result = targetExhausted;
+ break;
+ }
+ *target++ = ch;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+#ifdef CVTUTF_DEBUG
+ if (result == sourceIllegal) {
+ fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
+ fflush(stderr);
+ }
+#endif
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Index into the table below with the first byte of a UTF-8 sequence to
+ * get the number of trailing bytes that are supposed to follow it.
+ * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
+ * left as-is for anyone who may want to do such conversion, which was
+ * allowed in earlier algorithms.
+ */
+static const char trailingBytesForUTF8[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
+};
+
+/*
+ * Magic values subtracted from a buffer value during UTF8 conversion.
+ * This table contains as many values as there might be trailing bytes
+ * in a UTF-8 sequence.
+ */
+static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
+ 0x03C82080UL, 0xFA082080UL, 0x82082080UL
+ };
+
+/*
+ * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
+ * into the first byte, depending on how many bytes follow. There are
+ * as many entries in this table as there are UTF-8 sequence types.
+ * (I.e., one byte sequence, two byte... etc.). Remember that sequencs
+ * for *legal* UTF-8 will be 4 or fewer bytes total.
+ */
+static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+/* --------------------------------------------------------------------- */
+
+/* The interface converts a whole buffer to avoid function-call overhead.
+ * Constants have been gathered. Loops & conditionals have been removed as
+ * much as possible for efficiency, in favor of drop-through switches.
+ * (See "Note A" at the bottom of the file for equivalent code.)
+ * If your compiler supports it, the "isLegalUTF8" call can be turned
+ * into an inline function.
+ */
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF16toUTF8(
+ const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF16 *source = *sourceStart;
+ UTF8 *target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ unsigned short bytesToWrite = 0;
+ const UTF32 byteMask = 0xBF;
+ const UTF32 byteMark = 0x80;
+ const UTF16 *oldSource = source; /* In case we have to back up because of target overflow. */
+ ch = *source++;
+ /* If we have a surrogate pair, convert to UTF32 first. */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+ /* If the 16 bits following the high surrogate are in the source buffer... */
+ if (source < sourceEnd) {
+ UTF32 ch2 = *source;
+ /* If it's a low surrogate, convert to UTF32. */
+ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+ ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ + (ch2 - UNI_SUR_LOW_START) + halfBase;
+ ++source;
+ } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ } else { /* We don't have the 16 bits following the high surrogate. */
+ --source; /* return to the high surrogate */
+ result = sourceExhausted;
+ break;
+ }
+ } else if (flags == strictConversion) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ /* Figure out how many bytes the result will require */
+ if (ch < (UTF32)0x80) {
+ bytesToWrite = 1;
+ } else if (ch < (UTF32)0x800) {
+ bytesToWrite = 2;
+ } else if (ch < (UTF32)0x10000) {
+ bytesToWrite = 3;
+ } else if (ch < (UTF32)0x110000) {
+ bytesToWrite = 4;
+ } else {
+ bytesToWrite = 3;
+ ch = UNI_REPLACEMENT_CHAR;
+ }
+
+ target += bytesToWrite;
+ if (target > targetEnd) {
+ source = oldSource; /* Back up source pointer! */
+ target -= bytesToWrite;
+ result = targetExhausted;
+ break;
+ }
+ switch (bytesToWrite) { /* note: everything falls through. */
+ case 4:
+ *--target = (UTF8)((ch | byteMark) & byteMask);
+ ch >>= 6;
+ case 3:
+ *--target = (UTF8)((ch | byteMark) & byteMask);
+ ch >>= 6;
+ case 2:
+ *--target = (UTF8)((ch | byteMark) & byteMask);
+ ch >>= 6;
+ case 1:
+ *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
+ }
+ target += bytesToWrite;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Utility routine to tell whether a sequence of bytes is legal UTF-8.
+ * This must be called with the length pre-determined by the first byte.
+ * If not calling this from ConvertUTF8to*, then the length can be set by:
+ * length = trailingBytesForUTF8[*source]+1;
+ * and the sequence is illegal right away if there aren't that many bytes
+ * available.
+ * If presented with a length > 4, this returns false. The Unicode
+ * definition of UTF-8 goes up to 4-byte sequences.
+ */
+
+static Boolean isLegalUTF8(const UTF8 *source, int length) {
+ UTF8 a;
+ const UTF8 *srcptr = source + length;
+ switch (length) {
+ default:
+ return false;
+ /* Everything else falls through when "true"... */
+ case 4:
+ if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+ case 3:
+ if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+ case 2:
+ if ((a = (*--srcptr)) > 0xBF) return false;
+
+ switch (*source) {
+ /* no fall-through in this inner switch */
+ case 0xE0:
+ if (a < 0xA0) return false;
+ break;
+ case 0xED:
+ if (a > 0x9F) return false;
+ break;
+ case 0xF0:
+ if (a < 0x90) return false;
+ break;
+ case 0xF4:
+ if (a > 0x8F) return false;
+ break;
+ default:
+ if (a < 0x80) return false;
+ }
+
+ case 1:
+ if (*source >= 0x80 && *source < 0xC2) return false;
+ }
+ if (*source > 0xF4) return false;
+ return true;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Exported function to return whether a UTF-8 sequence is legal or not.
+ * This is not used here; it's just exported.
+ */
+Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
+ int length = trailingBytesForUTF8[*source] + 1;
+ if (source + length > sourceEnd) {
+ return false;
+ }
+ return isLegalUTF8(source, length);
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF8toUTF16(
+ const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF8 *source = *sourceStart;
+ UTF16 *target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch = 0;
+ unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+ if (source + extraBytesToRead >= sourceEnd) {
+ result = sourceExhausted;
+ break;
+ }
+ /* Do this check whether lenient or strict */
+ if (! isLegalUTF8(source, extraBytesToRead + 1)) {
+ result = sourceIllegal;
+ break;
+ }
+ /*
+ * The cases all fall through. See "Note A" below.
+ */
+ switch (extraBytesToRead) {
+ case 5:
+ ch += *source++;
+ ch <<= 6; /* remember, illegal UTF-8 */
+ case 4:
+ ch += *source++;
+ ch <<= 6; /* remember, illegal UTF-8 */
+ case 3:
+ ch += *source++;
+ ch <<= 6;
+ case 2:
+ ch += *source++;
+ ch <<= 6;
+ case 1:
+ ch += *source++;
+ ch <<= 6;
+ case 0:
+ ch += *source++;
+ }
+ ch -= offsetsFromUTF8[extraBytesToRead];
+
+ if (target >= targetEnd) {
+ source -= (extraBytesToRead + 1); /* Back up source pointer! */
+ result = targetExhausted;
+ break;
+ }
+ if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ source -= (extraBytesToRead + 1); /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = (UTF16)ch; /* normal case */
+ }
+ } else if (ch > UNI_MAX_UTF16) {
+ if (flags == strictConversion) {
+ result = sourceIllegal;
+ source -= (extraBytesToRead + 1); /* return to the start */
+ break; /* Bail out; shouldn't continue */
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ /* target is a character in range 0xFFFF - 0x10FFFF. */
+ if (target + 1 >= targetEnd) {
+ source -= (extraBytesToRead + 1); /* Back up source pointer! */
+ result = targetExhausted;
+ break;
+ }
+ ch -= halfBase;
+ *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+ *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF32toUTF8(
+ const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF32 *source = *sourceStart;
+ UTF8 *target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ unsigned short bytesToWrite = 0;
+ const UTF32 byteMask = 0xBF;
+ const UTF32 byteMark = 0x80;
+ ch = *source++;
+ if (flags == strictConversion) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ /*
+ * Figure out how many bytes the result will require. Turn any
+ * illegally large UTF32 things (> Plane 17) into replacement chars.
+ */
+ if (ch < (UTF32)0x80) {
+ bytesToWrite = 1;
+ } else if (ch < (UTF32)0x800) {
+ bytesToWrite = 2;
+ } else if (ch < (UTF32)0x10000) {
+ bytesToWrite = 3;
+ } else if (ch <= UNI_MAX_LEGAL_UTF32) {
+ bytesToWrite = 4;
+ } else {
+ bytesToWrite = 3;
+ ch = UNI_REPLACEMENT_CHAR;
+ result = sourceIllegal;
+ }
+
+ target += bytesToWrite;
+ if (target > targetEnd) {
+ --source; /* Back up source pointer! */
+ target -= bytesToWrite;
+ result = targetExhausted;
+ break;
+ }
+ switch (bytesToWrite) { /* note: everything falls through. */
+ case 4:
+ *--target = (UTF8)((ch | byteMark) & byteMask);
+ ch >>= 6;
+ case 3:
+ *--target = (UTF8)((ch | byteMark) & byteMask);
+ ch >>= 6;
+ case 2:
+ *--target = (UTF8)((ch | byteMark) & byteMask);
+ ch >>= 6;
+ case 1:
+ *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
+ }
+ target += bytesToWrite;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF8toUTF32(
+ const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF8 *source = *sourceStart;
+ UTF32 *target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch = 0;
+ unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+ if (source + extraBytesToRead >= sourceEnd) {
+ result = sourceExhausted;
+ break;
+ }
+ /* Do this check whether lenient or strict */
+ if (! isLegalUTF8(source, extraBytesToRead + 1)) {
+ result = sourceIllegal;
+ break;
+ }
+ /*
+ * The cases all fall through. See "Note A" below.
+ */
+ switch (extraBytesToRead) {
+ case 5:
+ ch += *source++;
+ ch <<= 6;
+ case 4:
+ ch += *source++;
+ ch <<= 6;
+ case 3:
+ ch += *source++;
+ ch <<= 6;
+ case 2:
+ ch += *source++;
+ ch <<= 6;
+ case 1:
+ ch += *source++;
+ ch <<= 6;
+ case 0:
+ ch += *source++;
+ }
+ ch -= offsetsFromUTF8[extraBytesToRead];
+
+ if (target >= targetEnd) {
+ source -= (extraBytesToRead + 1); /* Back up the source pointer! */
+ result = targetExhausted;
+ break;
+ }
+ if (ch <= UNI_MAX_LEGAL_UTF32) {
+ /*
+ * UTF-16 surrogate values are illegal in UTF-32, and anything
+ * over Plane 17 (> 0x10FFFF) is illegal.
+ */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ source -= (extraBytesToRead + 1); /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = ch;
+ }
+ } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
+ result = sourceIllegal;
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* ---------------------------------------------------------------------
+
+ Note A.
+ The fall-through switches in UTF-8 reading code save a
+ temp variable, some decrements & conditionals. The switches
+ are equivalent to the following loop:
+ {
+ int tmpBytesToRead = extraBytesToRead+1;
+ do {
+ ch += *source++;
+ --tmpBytesToRead;
+ if (tmpBytesToRead) ch <<= 6;
+ } while (tmpBytesToRead > 0);
+ }
+ In UTF-8 writing code, the switches on "bytesToWrite" are
+ similarly unrolled loops.
+
+ --------------------------------------------------------------------- */
diff --git a/engines/wintermute/utils/ConvertUTF.h b/engines/wintermute/utils/ConvertUTF.h
new file mode 100644
index 0000000000..03a8bb2bae
--- /dev/null
+++ b/engines/wintermute/utils/ConvertUTF.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2001-2004 Unicode, Inc.
+ *
+ * Disclaimer
+ *
+ * This source code is provided as is by Unicode, Inc. No claims are
+ * made as to fitness for any particular purpose. No warranties of any
+ * kind are expressed or implied. The recipient agrees to determine
+ * applicability of information provided. If this file has been
+ * purchased on magnetic or optical media from Unicode, Inc., the
+ * sole remedy for any claim will be exchange of defective media
+ * within 90 days of receipt.
+ *
+ * Limitations on Rights to Redistribute This Code
+ *
+ * Unicode, Inc. hereby grants the right to freely use the information
+ * supplied in this file in the creation of products supporting the
+ * Unicode Standard, and to make copies of this file in any form
+ * for internal or external distribution as long as this notice
+ * remains attached.
+ */
+
+/* ---------------------------------------------------------------------
+
+ Conversions between UTF32, UTF-16, and UTF-8. Header file.
+
+ Several funtions are included here, forming a complete set of
+ conversions between the three formats. UTF-7 is not included
+ here, but is handled in a separate source file.
+
+ Each of these routines takes pointers to input buffers and output
+ buffers. The input buffers are const.
+
+ Each routine converts the text between *sourceStart and sourceEnd,
+ putting the result into the buffer between *targetStart and
+ targetEnd. Note: the end pointers are *after* the last item: e.g.
+ *(sourceEnd - 1) is the last item.
+
+ The return result indicates whether the conversion was successful,
+ and if not, whether the problem was in the source or target buffers.
+ (Only the first encountered problem is indicated.)
+
+ After the conversion, *sourceStart and *targetStart are both
+ updated to point to the end of last text successfully converted in
+ the respective buffers.
+
+ Input parameters:
+ sourceStart - pointer to a pointer to the source buffer.
+ The contents of this are modified on return so that
+ it points at the next thing to be converted.
+ targetStart - similarly, pointer to pointer to the target buffer.
+ sourceEnd, targetEnd - respectively pointers to the ends of the
+ two buffers, for overflow checking only.
+
+ These conversion functions take a ConversionFlags argument. When this
+ flag is set to strict, both irregular sequences and isolated surrogates
+ will cause an error. When the flag is set to lenient, both irregular
+ sequences and isolated surrogates are converted.
+
+ Whether the flag is strict or lenient, all illegal sequences will cause
+ an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
+ or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
+ must check for illegal sequences.
+
+ When the flag is set to lenient, characters over 0x10FFFF are converted
+ to the replacement character; otherwise (when the flag is set to strict)
+ they constitute an error.
+
+ Output parameters:
+ The value "sourceIllegal" is returned from some routines if the input
+ sequence is malformed. When "sourceIllegal" is returned, the source
+ value will point to the illegal value that caused the problem. E.g.,
+ in UTF-8 when a sequence is malformed, it points to the start of the
+ malformed sequence.
+
+ Author: Mark E. Davis, 1994.
+ Rev History: Rick McGowan, fixes & updates May 2001.
+ Fixes & updates, Sept 2001.
+
+------------------------------------------------------------------------ */
+
+/* ---------------------------------------------------------------------
+ The following 4 definitions are compiler-specific.
+ The C standard does not guarantee that wchar_t has at least
+ 16 bits, so wchar_t is no less portable than unsigned short!
+ All should be unsigned values to avoid sign extension during
+ bit mask & shift operations.
+------------------------------------------------------------------------ */
+
+typedef unsigned long UTF32; /* at least 32 bits */
+typedef unsigned short UTF16; /* at least 16 bits */
+typedef unsigned char UTF8; /* typically 8 bits */
+typedef unsigned char Boolean; /* 0 or 1 */
+
+/* Some fundamental constants */
+#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
+#define UNI_MAX_BMP (UTF32)0x0000FFFF
+#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
+#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
+#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
+
+typedef enum {
+ conversionOK, /* conversion successful */
+ sourceExhausted, /* partial character in source, but hit end */
+ targetExhausted, /* insuff. room in target for conversion */
+ sourceIllegal /* source sequence is illegal/malformed */
+} ConversionResult;
+
+typedef enum {
+ strictConversion = 0,
+ lenientConversion
+} ConversionFlags;
+
+/* This is for C++ and does no harm in C */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ ConversionResult ConvertUTF8toUTF16(
+ const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags);
+
+ ConversionResult ConvertUTF16toUTF8(
+ const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags);
+
+ ConversionResult ConvertUTF8toUTF32(
+ const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags);
+
+ ConversionResult ConvertUTF32toUTF8(
+ const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags);
+
+ ConversionResult ConvertUTF16toUTF32(
+ const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags);
+
+ ConversionResult ConvertUTF32toUTF16(
+ const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags);
+
+ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* --------------------------------------------------------------------- */
diff --git a/engines/wintermute/utils/PathUtil.cpp b/engines/wintermute/utils/PathUtil.cpp
new file mode 100644
index 0000000000..dc722e2389
--- /dev/null
+++ b/engines/wintermute/utils/PathUtil.cpp
@@ -0,0 +1,204 @@
+/* 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.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "engines/wintermute/dcgf.h"
+#include <algorithm>
+#include <fstream>
+#include "PathUtil.h"
+#include "StringUtil.h"
+
+
+#ifdef __WIN32__
+# include <shlobj.h>
+#endif
+
+#ifdef __MACOSX__
+# include <CoreServices/CoreServices.h>
+#endif
+
+#ifdef __IPHONEOS__
+# include "ios_utils.h"
+#endif
+
+namespace WinterMute {
+
+//////////////////////////////////////////////////////////////////////////
+AnsiString PathUtil::UnifySeparators(const AnsiString &path) {
+ AnsiString newPath = path;
+
+ std::replace(newPath.begin(), newPath.end(), L'\\', L'/');
+ return newPath;
+}
+
+//////////////////////////////////////////////////////////////////////////
+AnsiString PathUtil::NormalizeFileName(const AnsiString &path) {
+ AnsiString newPath = UnifySeparators(path);
+ StringUtil::ToLowerCase(newPath);
+ return newPath;
+}
+
+//////////////////////////////////////////////////////////////////////////
+AnsiString PathUtil::Combine(const AnsiString &path1, const AnsiString &path2) {
+ AnsiString newPath1 = UnifySeparators(path1);
+ AnsiString newPath2 = UnifySeparators(path2);
+
+ if (!StringUtil::EndsWith(newPath1, "/", true) && !StringUtil::StartsWith(newPath2, "/", true))
+ newPath1 += "/";
+
+ return newPath1 + newPath2;
+}
+
+//////////////////////////////////////////////////////////////////////////
+AnsiString PathUtil::GetDirectoryName(const AnsiString &path) {
+ AnsiString newPath = UnifySeparators(path);
+
+ //size_t pos = newPath.find_last_of(L'/');
+ Common::String filename = GetFileName(path);
+ return Common::String(path.c_str(), path.size() - filename.size());
+ //if (pos == AnsiString::npos) return "";
+ //else return newPath.substr(0, pos + 1);
+}
+
+//////////////////////////////////////////////////////////////////////////
+AnsiString PathUtil::GetFileName(const AnsiString &path) {
+ AnsiString newPath = UnifySeparators(path);
+
+ //size_t pos = newPath.find_last_of(L'/'); TODO REMOVE.
+ Common::String lastPart = Common::lastPathComponent(path, '/');
+ if (lastPart[lastPart.size() - 1 ] != '/')
+ return lastPart;
+ else
+ return path;
+ //if (pos == AnsiString::npos) return path;
+ //else return newPath.substr(pos + 1);
+}
+
+//////////////////////////////////////////////////////////////////////////
+AnsiString PathUtil::GetFileNameWithoutExtension(const AnsiString &path) {
+ AnsiString fileName = GetFileName(path);
+
+ //size_t pos = fileName.find_last_of('.'); //TODO REMOVE!
+ // TODO: Prettify this.
+ Common::String extension = Common::lastPathComponent(path, '.');
+ Common::String filename = Common::String(path.c_str(), path.size() - extension.size());
+ return filename;
+ //if (pos == AnsiString::npos) return fileName;
+ //else return fileName.substr(0, pos);
+}
+
+//////////////////////////////////////////////////////////////////////////
+AnsiString PathUtil::GetExtension(const AnsiString &path) {
+ AnsiString fileName = GetFileName(path);
+
+ //size_t pos = fileName.find_last_of('.');
+ return Common::lastPathComponent(path, '.');
+ //if (pos == AnsiString::npos) return "";
+ //else return fileName.substr(pos);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+AnsiString PathUtil::GetSafeLogFileName() {
+ AnsiString logFileName = GetUserDirectory();
+
+#ifdef __WIN32__
+ char moduleName[MAX_PATH];
+ ::GetModuleFileName(NULL, moduleName, MAX_PATH);
+
+ AnsiString fileName = GetFileNameWithoutExtension(moduleName) + ".log";
+ fileName = Combine("/Wintermute Engine/Logs/", fileName);
+ logFileName = Combine(logFileName, fileName);
+
+#else
+ // !PORTME
+ logFileName = Combine(logFileName, "/Wintermute Engine/wme.log");
+#endif
+
+ CreateDirectory(GetDirectoryName(logFileName));
+ return logFileName;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool PathUtil::CreateDirectory(const AnsiString &path) {
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool PathUtil::MatchesMask(const AnsiString &fileName, const AnsiString &mask) {
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool PathUtil::FileExists(const AnsiString &fileName) {
+ std::ifstream stream;
+
+ stream.open(fileName.c_str());
+ bool ret = stream.is_open();
+ stream.close();
+
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+AnsiString PathUtil::GetUserDirectory() {
+ AnsiString userDir = "./";
+
+#ifdef __WIN32__
+ char buffer[MAX_PATH];
+ buffer[0] = '\0';
+ LPITEMIDLIST pidl = NULL;
+ LPMALLOC pMalloc;
+ if (SUCCEEDED(SHGetMalloc(&pMalloc))) {
+ SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidl);
+ if (pidl) {
+ SHGetPathFromIDList(pidl, buffer);
+ }
+ pMalloc->Free(pidl);
+ userDir = AnsiString(buffer);
+ }
+#elif __MACOSX__
+ FSRef fileRef;
+ OSStatus error = FSFindFolder(kUserDomain, kApplicationSupportFolderType, true, &fileRef);
+ if (error == noErr) {
+ char buffer[MAX_PATH];
+ error = FSRefMakePath(&fileRef, (UInt8 *)buffer, sizeof(buffer));
+ if (error == noErr)
+ userDir = buffer;
+
+ }
+#elif __IPHONEOS__
+ char path[MAX_PATH];
+ IOS_GetDataDir(path);
+ userDir = AnsiString(path);
+#endif
+
+ return userDir;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/utils/PathUtil.h b/engines/wintermute/utils/PathUtil.h
new file mode 100644
index 0000000000..0bc883a1fa
--- /dev/null
+++ b/engines/wintermute/utils/PathUtil.h
@@ -0,0 +1,56 @@
+/* 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.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef WINTERMUTE_PATHUTILS_H
+#define WINTERMUTE_PATHUTILS_H
+
+#include "engines/wintermute/PlatformSDL.h"
+
+namespace WinterMute {
+
+class PathUtil {
+public:
+ static AnsiString UnifySeparators(const AnsiString &path);
+ static AnsiString NormalizeFileName(const AnsiString &path);
+ static AnsiString Combine(const AnsiString &path1, const AnsiString &path2);
+ static AnsiString GetDirectoryName(const AnsiString &path);
+ static AnsiString GetFileName(const AnsiString &path);
+ static AnsiString GetFileNameWithoutExtension(const AnsiString &path);
+ static AnsiString GetExtension(const AnsiString &path);
+ static bool CreateDirectory(const AnsiString &path);
+ static bool MatchesMask(const AnsiString &fileName, const AnsiString &mask);
+
+ static bool FileExists(const AnsiString &fileName);
+
+ static AnsiString GetSafeLogFileName();
+ static AnsiString GetUserDirectory();
+};
+
+} // end of namespace WinterMute
+
+#endif // WINTERMUTE_PATHUTILS_H
diff --git a/engines/wintermute/utils/StringUtil.cpp b/engines/wintermute/utils/StringUtil.cpp
new file mode 100644
index 0000000000..cd4f99e034
--- /dev/null
+++ b/engines/wintermute/utils/StringUtil.cpp
@@ -0,0 +1,393 @@
+/* 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.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "engines/wintermute/dcgf.h"
+#include <algorithm>
+#include <string>
+#include <sstream>
+#include "common/tokenizer.h"
+#include "StringUtil.h"
+#include "ConvertUTF.h"
+
+namespace WinterMute {
+
+//////////////////////////////////////////////////////////////////////////
+void StringUtil::ToLowerCase(AnsiString &str) {
+ std::transform(str.begin(), str.end(), str.begin(), ::tolower);
+}
+
+//////////////////////////////////////////////////////////////////////////
+/*void StringUtil::ToLowerCase(WideString &str) {
+ std::transform(str.begin(), str.end(), str.begin(), ::towlower);
+}*/
+
+//////////////////////////////////////////////////////////////////////////
+void StringUtil::ToUpperCase(AnsiString &str) {
+ std::transform(str.begin(), str.end(), str.begin(), ::toupper);
+}
+
+//////////////////////////////////////////////////////////////////////////
+/*void StringUtil::ToUpperCase(WideString &str) {
+ std::transform(str.begin(), str.end(), str.begin(), ::towupper);
+}*/
+
+//////////////////////////////////////////////////////////////////////////
+bool StringUtil::CompareNoCase(const AnsiString &str1, const AnsiString &str2) {
+ AnsiString str1lc = str1;
+ AnsiString str2lc = str2;
+
+ ToLowerCase(str1lc);
+ ToLowerCase(str2lc);
+
+ return (str1lc == str2lc);
+}
+
+//////////////////////////////////////////////////////////////////////////
+/*bool StringUtil::CompareNoCase(const WideString &str1, const WideString &str2) {
+ WideString str1lc = str1;
+ WideString str2lc = str2;
+
+ ToLowerCase(str1lc);
+ ToLowerCase(str2lc);
+
+ return (str1lc == str2lc);
+}*/
+
+//////////////////////////////////////////////////////////////////////////
+WideString StringUtil::Utf8ToWide(const Utf8String &Utf8Str) {
+ error("StringUtil::Utf8ToWide - WideString not supported yet");
+ /* size_t WideSize = Utf8Str.size();
+
+ if (sizeof(wchar_t) == 2) {
+ wchar_t *WideStringNative = new wchar_t[WideSize + 1];
+
+ const UTF8 *SourceStart = reinterpret_cast<const UTF8 *>(Utf8Str.c_str());
+ const UTF8 *SourceEnd = SourceStart + WideSize;
+
+ UTF16 *TargetStart = reinterpret_cast<UTF16 *>(WideStringNative);
+ UTF16 *TargetEnd = TargetStart + WideSize + 1;
+
+ ConversionResult res = ConvertUTF8toUTF16(&SourceStart, SourceEnd, &TargetStart, TargetEnd, strictConversion);
+ if (res != conversionOK) {
+ delete [] WideStringNative;
+ return L"";
+ }
+ *TargetStart = 0;
+ WideString ResultString(WideStringNative);
+ delete [] WideStringNative;
+
+ return ResultString;
+ } else if (sizeof(wchar_t) == 4) {
+ wchar_t *WideStringNative = new wchar_t[WideSize + 1];
+
+ const UTF8 *SourceStart = reinterpret_cast<const UTF8 *>(Utf8Str.c_str());
+ const UTF8 *SourceEnd = SourceStart + WideSize;
+
+ UTF32 *TargetStart = reinterpret_cast<UTF32 *>(WideStringNative);
+ UTF32 *TargetEnd = TargetStart + WideSize;
+
+ ConversionResult res = ConvertUTF8toUTF32(&SourceStart, SourceEnd, &TargetStart, TargetEnd, strictConversion);
+ if (res != conversionOK) {
+ delete [] WideStringNative;
+ return L"";
+ }
+ *TargetStart = 0;
+ WideString ResultString(WideStringNative);
+ delete [] WideStringNative;
+
+ return ResultString;
+ } else {
+ return L"";
+ }*/
+ return "";
+}
+
+//////////////////////////////////////////////////////////////////////////
+Utf8String StringUtil::WideToUtf8(const WideString &WideStr) {
+ error("StringUtil::WideToUtf8 - Widestring not supported yet");
+ /* size_t WideSize = WideStr.length();
+
+ if (sizeof(wchar_t) == 2) {
+ size_t Utf8Size = 3 * WideSize + 1;
+ char *Utf8StringNative = new char[Utf8Size];
+
+ const UTF16 *SourceStart = reinterpret_cast<const UTF16 *>(WideStr.c_str());
+ const UTF16 *SourceEnd = SourceStart + WideSize;
+
+ UTF8 *TargetStart = reinterpret_cast<UTF8 *>(Utf8StringNative);
+ UTF8 *TargetEnd = TargetStart + Utf8Size;
+
+ ConversionResult res = ConvertUTF16toUTF8(&SourceStart, SourceEnd, &TargetStart, TargetEnd, strictConversion);
+ if (res != conversionOK) {
+ delete [] Utf8StringNative;
+ return (Utf8String)"";
+ }
+ *TargetStart = 0;
+ Utf8String ResultString(Utf8StringNative);
+ delete [] Utf8StringNative;
+ return ResultString;
+ } else if (sizeof(wchar_t) == 4) {
+ size_t Utf8Size = 4 * WideSize + 1;
+ char *Utf8StringNative = new char[Utf8Size];
+
+ const UTF32 *SourceStart = reinterpret_cast<const UTF32 *>(WideStr.c_str());
+ const UTF32 *SourceEnd = SourceStart + WideSize;
+
+ UTF8 *TargetStart = reinterpret_cast<UTF8 *>(Utf8StringNative);
+ UTF8 *TargetEnd = TargetStart + Utf8Size;
+
+ ConversionResult res = ConvertUTF32toUTF8(&SourceStart, SourceEnd, &TargetStart, TargetEnd, strictConversion);
+ if (res != conversionOK) {
+ delete [] Utf8StringNative;
+ return (Utf8String)"";
+ }
+ *TargetStart = 0;
+ Utf8String ResultString(Utf8StringNative);
+ delete [] Utf8StringNative;
+ return ResultString;
+ } else {
+ return (Utf8String)"";
+ }*/
+ return "";
+}
+
+//////////////////////////////////////////////////////////////////////////
+WideString StringUtil::AnsiToWide(const AnsiString &str) {
+ // using default os locale!
+ error("StringUtil::AnsiToWide - WideString not supported yet");
+ /* setlocale(LC_CTYPE, "");
+ size_t WideSize = mbstowcs(NULL, str.c_str(), 0) + 1;
+ wchar_t *wstr = new wchar_t[WideSize];
+ mbstowcs(wstr, str.c_str(), WideSize);
+ WideString ResultString(wstr);
+ delete [] wstr;
+ return ResultString;*/
+ return "";
+}
+
+//////////////////////////////////////////////////////////////////////////
+AnsiString StringUtil::WideToAnsi(const WideString &wstr) {
+ // using default os locale!
+ error("StringUtil::WideToAnsi - WideString not supported yet");
+ /* setlocale(LC_CTYPE, "");
+ size_t WideSize = wcstombs(NULL, wstr.c_str(), 0) + 1;
+ char *str = new char[WideSize];
+ wcstombs(str, wstr.c_str(), WideSize);
+ AnsiString ResultString(str);
+ delete [] str;
+ return ResultString;*/
+ return "";
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool StringUtil::StartsWith(const AnsiString &str, const AnsiString &pattern, bool ignoreCase) {
+ /* size_t strLength = str.size();
+ size_t patternLength = pattern.size();
+
+ if (strLength < patternLength || patternLength == 0)
+ return false;
+
+ AnsiString startPart = str.substr(0, patternLength);
+
+ if (ignoreCase) return CompareNoCase(startPart, pattern);
+ else return (startPart == pattern);*/
+ if (!ignoreCase)
+ return str.hasPrefix(pattern);
+ else {
+ size_t strLength = str.size();
+ size_t patternLength = pattern.size();
+
+ if (strLength < patternLength || patternLength == 0)
+ return false;
+
+ AnsiString startPart(str.c_str(), patternLength);
+ uint32 likeness = str.compareToIgnoreCase(pattern.c_str());
+ return (likeness == 0);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool StringUtil::EndsWith(const AnsiString &str, const AnsiString &pattern, bool ignoreCase) {
+ /* size_t strLength = str.size(); // TODO: Remove
+ size_t patternLength = pattern.size();
+
+ if (strLength < patternLength || patternLength == 0)
+ return false;
+
+ AnsiString endPart = str.substr(strLength - patternLength, patternLength);
+
+ if (ignoreCase) return CompareNoCase(endPart, pattern);
+ else return (endPart == pattern);*/
+ if (!ignoreCase) {
+ return str.hasSuffix(pattern);
+ } else {
+ size_t strLength = str.size();
+ size_t patternLength = pattern.size();
+
+ if (strLength < patternLength || patternLength == 0)
+ return false;
+
+ Common::String endPart(str.c_str() + (strLength - patternLength), patternLength);
+ uint32 likeness = str.compareToIgnoreCase(pattern.c_str());
+ return (likeness != 0);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool StringUtil::IsUtf8BOM(const byte *Buffer, uint32 BufferSize) {
+ if (BufferSize > 3 && Buffer[0] == 0xEF && Buffer[1] == 0xBB && Buffer[2] == 0xBF) return true;
+ else return false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+AnsiString StringUtil::Replace(const AnsiString &str, const AnsiString &from, const AnsiString &to) {
+ if (from.empty() || from == to) return str;
+
+ AnsiString result = str;
+ /*size_t pos = 0;*/
+
+ while (result.contains(from)) {
+ const char *startPtr = strstr(result.c_str(), from.c_str());
+ uint32 index = startPtr - result.c_str();
+
+ Common::String tail(result.c_str() + index + to.size());
+ result = Common::String(result.c_str(), index);
+ result += to;
+ result += tail;
+
+ /* pos = result.find(from, pos);
+ if (pos == result.npos) break;
+
+ result.replace(pos, from.size(), to);
+ pos += to.size();*/
+ }
+
+ return result;
+}
+
+//////////////////////////////////////////////////////////////////////////
+AnsiString StringUtil::Trim(const AnsiString &str, bool fromLeft, bool fromRight, const AnsiString &chars) {
+ AnsiString trimmedStr = str;
+
+ if (fromRight) {
+ //trimmedStr.erase(trimmedStr.find_last_not_of(chars) + 1); // TODO
+ warning("fromRight-trim not implemented yet, %s", chars.c_str());
+ }
+ if (fromLeft) {
+ uint32 lastOf = LastIndexOf(str, chars, 0);
+ trimmedStr = Common::String(trimmedStr.c_str() + lastOf);
+ //trimmedStr.erase(0, trimmedStr.find_first_not_of(chars));
+ }
+ return trimmedStr;
+}
+
+//////////////////////////////////////////////////////////////////////////
+int StringUtil::IndexOf(const WideString &str, const WideString &toFind, size_t startFrom) {
+ /*size_t pos = str.find(toFind, startFrom);
+ if (pos == str.npos) return -1;
+ else return pos;*/
+ const char *index = strstr(str.c_str(), toFind.c_str());
+ if (index == NULL)
+ return -1;
+ else
+ return index - str.c_str();
+}
+
+//////////////////////////////////////////////////////////////////////////
+int StringUtil::LastIndexOf(const WideString &str, const WideString &toFind, size_t startFrom) {
+ /*size_t pos = str.rfind(toFind, startFrom);
+ if (pos == str.npos) return -1;
+ else return pos;*/
+ int32 lastIndex = -1;
+ bool found = false;
+ for (size_t i = startFrom; i < str.size(); i++) {
+ found = false;
+ for (size_t j = 0; j < toFind.size(); j++) {
+ if (str[i + j] != toFind[j]) {
+ found = false;
+ break;
+ } else {
+ found = true;
+ }
+ }
+ if (found)
+ lastIndex = i;
+ }
+ return lastIndex;
+}
+
+//////////////////////////////////////////////////////////////////////////
+AnsiString StringUtil::ToString(size_t val) {
+ /* std::ostringstream str;
+ str << val;
+ return str.str();*/
+ return Common::String::format("%u", (uint32)val);
+}
+
+//////////////////////////////////////////////////////////////////////////
+AnsiString StringUtil::ToString(int val) {
+ /* std::ostringstream str;
+ str << val;
+ return str.str();*/
+ return Common::String::format("%d", val);
+}
+
+//////////////////////////////////////////////////////////////////////////
+AnsiString StringUtil::ToString(float val) {
+ /* std::ostringstream str;
+ str << val;
+ return str.str();*/
+ return Common::String::format("%f", val);
+}
+
+//////////////////////////////////////////////////////////////////////////
+AnsiString StringUtil::ToString(double val) {
+ /* std::ostringstream str;
+ str << val;
+ return str.str();*/
+ return Common::String::format("%f", val);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void StringUtil::Split(const AnsiString &list, const AnsiString &delimiters, AnsiStringArray &result, bool keepEmptyItems) {
+ result.clear();
+//TODO: Verify this, wrt keepEmptyItems.
+ Common::StringTokenizer tokenizer(list.c_str(), delimiters.c_str());
+ //typedef boost::char_separator<char> separator_t;
+ //typedef boost::tokenizer<separator_t, AnsiString::const_iterator, AnsiString> tokenizer_t;
+
+ //separator_t del(delimiters.c_str(), "", keepEmptyItems ? boost::keep_empty_tokens : boost::drop_empty_tokens);
+ //tokenizer_t tokens(list, del);
+ while (!tokenizer.empty()) {
+ Common::String copy(tokenizer.nextToken().c_str());
+ result.push_back(copy);
+ }
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/utils/StringUtil.h b/engines/wintermute/utils/StringUtil.h
new file mode 100644
index 0000000000..a4727fabbe
--- /dev/null
+++ b/engines/wintermute/utils/StringUtil.h
@@ -0,0 +1,70 @@
+/* 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.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef WINTERMUTE_STRINGUTIL_H
+#define WINTERMUTE_STRINGUTIL_H
+
+#include "engines/wintermute/PlatformSDL.h"
+
+namespace WinterMute {
+
+class StringUtil {
+public:
+ static void ToLowerCase(AnsiString &str);
+ //static void ToLowerCase(WideString &str);
+ static void ToUpperCase(AnsiString &str);
+ //static void ToUpperCase(WideString &str);
+ static bool CompareNoCase(const AnsiString &str1, const AnsiString &str2);
+ //static bool CompareNoCase(const WideString &str1, const WideString &str2);
+ static WideString Utf8ToWide(const Utf8String &Utf8Str);
+ static Utf8String WideToUtf8(const WideString &WideStr);
+ static WideString AnsiToWide(const AnsiString &str);
+ static AnsiString WideToAnsi(const WideString &str);
+
+ static bool StartsWith(const AnsiString &str, const AnsiString &pattern, bool ignoreCase = false);
+ static bool EndsWith(const AnsiString &str, const AnsiString &pattern, bool ignoreCase = false);
+
+ static bool IsUtf8BOM(const byte *buffer, uint32 bufferSize);
+
+ static AnsiString Replace(const AnsiString &str, const AnsiString &from, const AnsiString &to);
+ static AnsiString Trim(const AnsiString &str, bool fromLeft = true, bool fromRight = true, const AnsiString &chars = " \n\r\t");
+
+ static int IndexOf(const WideString &str, const WideString &toFind, size_t startFrom);
+ static int LastIndexOf(const WideString &str, const WideString &toFind, size_t startFrom);
+
+ static AnsiString ToString(size_t val);
+ static AnsiString ToString(int val);
+ static AnsiString ToString(float val);
+ static AnsiString ToString(double val);
+
+ static void Split(const AnsiString &list, const AnsiString &delimiters, AnsiStringArray &result, bool keepEmptyItems = false);
+};
+
+} // end of namespace WinterMute
+
+#endif // WINTERMUTE_STRINGUTIL_H
diff --git a/engines/wintermute/utils/crc.cpp b/engines/wintermute/utils/crc.cpp
new file mode 100644
index 0000000000..adfd5da624
--- /dev/null
+++ b/engines/wintermute/utils/crc.cpp
@@ -0,0 +1,234 @@
+/**********************************************************************
+ *
+ * Filename: crc.c
+ *
+ * Description: Slow and fast implementations of the CRC standards.
+ *
+ * Notes: The parameters for each supported CRC standard are
+ * defined in the header file crc.h. The implementations
+ * here should stand up to further additions to that list.
+ *
+ *
+ * Copyright (c) 2000 by Michael Barr. This software is placed into
+ * the public domain and may be used for any purpose. However, this
+ * notice must not be changed or removed and no warranty is either
+ * expressed or implied by its publication or distribution.
+ **********************************************************************/
+
+#include "crc.h"
+
+
+/*
+ * Derive parameters from the standard-specific parameters in crc.h.
+ */
+#define WIDTH (8 * sizeof(crc))
+#define TOPBIT (1 << (WIDTH - 1))
+
+#if (REFLECT_DATA == TRUE)
+#undef REFLECT_DATA
+#define REFLECT_DATA(X) ((unsigned char) reflect((X), 8))
+#else
+#undef REFLECT_DATA
+#define REFLECT_DATA(X) (X)
+#endif
+
+#if (REFLECT_REMAINDER == TRUE)
+#undef REFLECT_REMAINDER
+#define REFLECT_REMAINDER(X) ((crc) reflect((X), WIDTH))
+#else
+#undef REFLECT_REMAINDER
+#define REFLECT_REMAINDER(X) (X)
+#endif
+
+
+/*********************************************************************
+ *
+ * Function: reflect()
+ *
+ * Description: Reorder the bits of a binary sequence, by reflecting
+ * them about the middle position.
+ *
+ * Notes: No checking is done that nBits <= 32.
+ *
+ * Returns: The reflection of the original data.
+ *
+ *********************************************************************/
+static unsigned long
+reflect(unsigned long data, unsigned char nBits) {
+ unsigned long reflection = 0x00000000;
+ unsigned char bit;
+
+ /*
+ * Reflect the data about the center bit.
+ */
+ for (bit = 0; bit < nBits; ++bit) {
+ /*
+ * If the LSB bit is set, set the reflection of it.
+ */
+ if (data & 0x01) {
+ reflection |= (1 << ((nBits - 1) - bit));
+ }
+
+ data = (data >> 1);
+ }
+
+ return (reflection);
+
+} /* reflect() */
+
+
+/*********************************************************************
+ *
+ * Function: crcSlow()
+ *
+ * Description: Compute the CRC of a given message.
+ *
+ * Notes:
+ *
+ * Returns: The CRC of the message.
+ *
+ *********************************************************************/
+crc
+crcSlow(unsigned char const message[], int nBytes) {
+ crc remainder = INITIAL_REMAINDER;
+ int byte;
+ unsigned char bit;
+
+
+ /*
+ * Perform modulo-2 division, a byte at a time.
+ */
+ for (byte = 0; byte < nBytes; ++byte) {
+ /*
+ * Bring the next byte into the remainder.
+ */
+ remainder ^= (REFLECT_DATA(message[byte]) << (WIDTH - 8));
+
+ /*
+ * Perform modulo-2 division, a bit at a time.
+ */
+ for (bit = 8; bit > 0; --bit) {
+ /*
+ * Try to divide the current data bit.
+ */
+ if (remainder & TOPBIT) {
+ remainder = (remainder << 1) ^ POLYNOMIAL;
+ } else {
+ remainder = (remainder << 1);
+ }
+ }
+ }
+
+ /*
+ * The final remainder is the CRC result.
+ */
+ return (REFLECT_REMAINDER(remainder) ^ FINAL_XOR_VALUE);
+
+} /* crcSlow() */
+
+
+crc crcTable[256];
+
+
+/*********************************************************************
+ *
+ * Function: crcInit()
+ *
+ * Description: Populate the partial CRC lookup table.
+ *
+ * Notes: This function must be rerun any time the CRC standard
+ * is changed. If desired, it can be run "offline" and
+ * the table results stored in an embedded system's ROM.
+ *
+ * Returns: None defined.
+ *
+ *********************************************************************/
+void
+crcInit(void) {
+ crc remainder;
+ int dividend;
+ unsigned char bit;
+
+
+ /*
+ * Compute the remainder of each possible dividend.
+ */
+ for (dividend = 0; dividend < 256; ++dividend) {
+ /*
+ * Start with the dividend followed by zeros.
+ */
+ remainder = dividend << (WIDTH - 8);
+
+ /*
+ * Perform modulo-2 division, a bit at a time.
+ */
+ for (bit = 8; bit > 0; --bit) {
+ /*
+ * Try to divide the current data bit.
+ */
+ if (remainder & TOPBIT) {
+ remainder = (remainder << 1) ^ POLYNOMIAL;
+ } else {
+ remainder = (remainder << 1);
+ }
+ }
+
+ /*
+ * Store the result into the table.
+ */
+ crcTable[dividend] = remainder;
+ }
+
+} /* crcInit() */
+
+
+/*********************************************************************
+ *
+ * Function: crcFast()
+ *
+ * Description: Compute the CRC of a given message.
+ *
+ * Notes: crcInit() must be called first.
+ *
+ * Returns: The CRC of the message.
+ *
+ *********************************************************************/
+crc
+crcFast(unsigned char const message[], int nBytes) {
+ crc remainder = INITIAL_REMAINDER;
+ unsigned char data;
+ int byte;
+
+
+ /*
+ * Divide the message by the polynomial, a byte at a time.
+ */
+ for (byte = 0; byte < nBytes; ++byte) {
+ data = (unsigned char)(REFLECT_DATA(message[byte]) ^ (remainder >> (WIDTH - 8)));
+ remainder = crcTable[data] ^ (remainder << 8);
+ }
+
+ /*
+ * The final remainder is the CRC.
+ */
+ return (REFLECT_REMAINDER(remainder) ^ FINAL_XOR_VALUE);
+
+} /* crcFast() */
+
+
+
+crc crc_initialize(void) {
+ crcInit();
+ return INITIAL_REMAINDER;
+}
+
+crc crc_process_byte(unsigned char byte, crc remainder) {
+ unsigned char data;
+ data = (unsigned char)(REFLECT_DATA(byte) ^ (remainder >> (WIDTH - 8)));
+ remainder = crcTable[data] ^ (remainder << 8);
+ return remainder;
+}
+
+crc crc_finalize(crc remainder) {
+ return (REFLECT_REMAINDER(remainder) ^ FINAL_XOR_VALUE);
+}
diff --git a/engines/wintermute/utils/crc.h b/engines/wintermute/utils/crc.h
new file mode 100644
index 0000000000..578b423de8
--- /dev/null
+++ b/engines/wintermute/utils/crc.h
@@ -0,0 +1,81 @@
+/**********************************************************************
+ *
+ * Filename: crc.h
+ *
+ * Description: A header file describing the various CRC standards.
+ *
+ * Notes:
+ *
+ *
+ * Copyright (c) 2000 by Michael Barr. This software is placed into
+ * the public domain and may be used for any purpose. However, this
+ * notice must not be changed or removed and no warranty is either
+ * expressed or implied by its publication or distribution.
+ **********************************************************************/
+
+#ifndef _crc_h
+#define _crc_h
+
+#ifndef TRUE
+#define FALSE 0
+#define TRUE !FALSE
+#endif
+
+/*
+ * Select the CRC standard from the list that follows.
+ */
+#define CRC32
+
+
+#if defined(CRC_CCITT)
+
+typedef unsigned short crc;
+
+#define CRC_NAME "CRC-CCITT"
+#define POLYNOMIAL 0x1021
+#define INITIAL_REMAINDER 0xFFFF
+#define FINAL_XOR_VALUE 0x0000
+#define REFLECT_DATA FALSE
+#define REFLECT_REMAINDER FALSE
+#define CHECK_VALUE 0x29B1
+
+#elif defined(CRC16)
+
+typedef unsigned short crc;
+
+#define CRC_NAME "CRC-16"
+#define POLYNOMIAL 0x8005
+#define INITIAL_REMAINDER 0x0000
+#define FINAL_XOR_VALUE 0x0000
+#define REFLECT_DATA TRUE
+#define REFLECT_REMAINDER TRUE
+#define CHECK_VALUE 0xBB3D
+
+#elif defined(CRC32)
+
+typedef unsigned long crc;
+
+#define CRC_NAME "CRC-32"
+#define POLYNOMIAL 0x04C11DB7
+#define INITIAL_REMAINDER 0xFFFFFFFF
+#define FINAL_XOR_VALUE 0xFFFFFFFF
+#define REFLECT_DATA TRUE
+#define REFLECT_REMAINDER TRUE
+#define CHECK_VALUE 0xCBF43926
+
+#else
+
+#error "One of CRC_CCITT, CRC16, or CRC32 must be #define'd."
+
+#endif
+
+void crcInit(void);
+crc crcSlow(unsigned char const message[], int nBytes);
+crc crcFast(unsigned char const message[], int nBytes);
+
+extern "C" crc crc_initialize(void);
+extern "C" crc crc_process_byte(unsigned char byte, crc remainder);
+extern "C" crc crc_finalize(crc remainder);
+
+
+#endif /* _crc_h */
diff --git a/engines/wintermute/utils/utils.cpp b/engines/wintermute/utils/utils.cpp
new file mode 100644
index 0000000000..d1ce280639
--- /dev/null
+++ b/engines/wintermute/utils/utils.cpp
@@ -0,0 +1,342 @@
+/* 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.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "engines/wintermute/dcgf.h"
+#include "utils.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include "engines/wintermute/wintypes.h"
+#include "PathUtil.h"
+#include "engines/wintermute/Base/BGame.h"
+#include "common/str.h"
+#include "common/textconsole.h"
+
+namespace WinterMute {
+
+//////////////////////////////////////////////////////////////////////
+static inline unsigned Sqr(int x) {
+ return (x * x);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////
+void CBUtils::Clip(int *DestX, int *DestY, RECT *SrcRect, RECT *DestRect) {
+ // If it's partly off the right side of the screen
+ if (*DestX + (SrcRect->right - SrcRect->left) > DestRect->right)
+ SrcRect->right -= *DestX + (SrcRect->right - SrcRect->left) - DestRect->right;
+
+ if (SrcRect->right < 0) SrcRect->right = 0;
+
+ // Partly off the left side of the screen
+ if (*DestX < DestRect->left) {
+ SrcRect->left += DestRect->left - *DestX;
+ *DestX = DestRect->left;
+ }
+
+ // Partly off the top of the screen
+ if (*DestY < DestRect->top) {
+ SrcRect->top += DestRect->top - *DestY;
+ *DestY = DestRect->top;
+ }
+
+ // If it's partly off the bottom side of the screen
+ if (*DestY + (SrcRect->bottom - SrcRect->top) > DestRect->bottom)
+ SrcRect->bottom -= ((SrcRect->bottom - SrcRect->top) + *DestY) - DestRect->bottom;
+
+ if (SrcRect->bottom < 0) SrcRect->bottom = 0;
+
+ return;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Swap - swaps two integers
+//////////////////////////////////////////////////////////////////////////////////
+void CBUtils::Swap(int *a, int *b) {
+ int Temp = *a;
+ *a = *b;
+ *b = Temp;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CBUtils::StrBeginsI(const char *String, const char *Fragment) {
+ return (scumm_strnicmp(String, Fragment, strlen(Fragment)) == 0);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+float CBUtils::NormalizeAngle(float Angle) {
+ while (Angle > 360) Angle -= 360;
+ while (Angle < 0) Angle += 360;
+
+ return Angle;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+void CBUtils::CreatePath(const char *Path, bool PathOnly) {
+ AnsiString path;
+
+ if (!PathOnly) path = PathUtil::GetDirectoryName(Path);
+ else path = Path;
+
+// try {
+ warning("CBUtils::CreatePath - not implemented: %s", Path);
+// boost::filesystem::create_directories(path);
+// } catch (...) {
+ return;
+// }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CBUtils::DebugMessage(HWND hWnd, const char *Text) {
+ //MessageBox(hWnd, Text, "WME", MB_OK|MB_ICONINFORMATION);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CBUtils::SetString(char **String, const char *Value) {
+ delete[] *String;
+ *String = new char[strlen(Value) + 1];
+ if (*String) strcpy(*String, Value);
+ return *String;
+}
+
+//////////////////////////////////////////////////////////////////////////
+int CBUtils::StrNumEntries(const char *Str, const char Delim) {
+ int NumEntries = 1;
+ for (uint32 i = 0; i < strlen(Str); i++) {
+ if (Str[i] == Delim) NumEntries++;
+ }
+ return NumEntries;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CBUtils::StrEntry(int Entry, const char *Str, const char Delim) {
+ int NumEntries = 0;
+
+ const char *Start = NULL;
+ int Len = 0;
+
+ for (uint32 i = 0; i <= strlen(Str); i++) {
+ if (NumEntries == Entry) {
+ if (!Start) Start = Str + i;
+ else Len++;
+ }
+ if (Str[i] == Delim || Str[i] == '\0') {
+ NumEntries++;
+ if (Start) {
+ char *Ret = new char[Len + 1];
+ memset(Ret, 0, Len + 1);
+ strncpy(Ret, Start, Len);
+ return Ret;
+ }
+ }
+ }
+ return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+int CBUtils::RandomInt(int From, int To) {
+ if (To < From) {
+ int i = To;
+ To = From;
+ From = i;
+ }
+ return (rand() % (To - From + 1)) + From;
+}
+
+//////////////////////////////////////////////////////////////////////////
+float CBUtils::RandomFloat(float From, float To) {
+ float RandNum = (float)rand() / (float)RAND_MAX;
+ return From + (To - From) * RandNum;
+}
+
+//////////////////////////////////////////////////////////////////////////
+float CBUtils::RandomAngle(float From, float To) {
+ while (To < From) {
+ To += 360;
+ }
+ return NormalizeAngle(RandomFloat(From, To));
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CBUtils::MatchesPattern(const char *Pattern, const char *String) {
+ char stringc, patternc;
+
+ for (;; ++String) {
+ stringc = toupper(*String);
+ patternc = toupper(*Pattern++);
+
+ switch (patternc) {
+ case 0:
+ return (stringc == 0);
+
+ case '?':
+ if (stringc == 0) return false;
+ break;
+
+ case '*':
+ if (!*Pattern) return true;
+
+ if (*Pattern == '.') {
+ char *dot;
+ if (Pattern[1] == '*' && Pattern[2] == 0) return true;
+ dot = (char *)strchr(String, '.');
+ if (Pattern[1] == 0) return (dot == NULL || dot[1] == 0);
+ if (dot != NULL) {
+ String = dot;
+ if (strpbrk(Pattern, "*?[") == NULL && strchr(String + 1, '.') == NULL)
+ return(scumm_stricmp(Pattern + 1, String + 1) == 0);
+ }
+ }
+
+ while (*String)
+ if (CBUtils::MatchesPattern(Pattern, String++))
+ return true;
+ return false;
+
+ default:
+ if (patternc != stringc)
+ if (patternc == '.' && stringc == 0)
+ return(CBUtils::MatchesPattern(Pattern, String));
+ else
+ return false;
+ break;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+char *CBUtils::GetPath(const char *Filename) {
+ AnsiString path = PathUtil::GetDirectoryName(Filename);
+ //path = boost::filesystem::syste_complete(path).string();
+ warning("CBUtils::GetPath: (%s), not implemented", Filename);
+ char *ret = new char[path.size() + 1];
+ strcpy(ret, path.c_str());
+
+ return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////
+char *CBUtils::GetFilename(const char *Filename) {
+ AnsiString path = PathUtil::GetFileName(Filename);
+ char *ret = new char[path.size() + 1];
+ strcpy(ret, path.c_str());
+ return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////
+void CBUtils::RGBtoHSL(uint32 RGBColor, byte *OutH, byte *OutS, byte *OutL) {
+ float var_R = (D3DCOLGetR(RGBColor) / 255.0f);
+ float var_G = (D3DCOLGetG(RGBColor) / 255.0f);
+ float var_B = (D3DCOLGetB(RGBColor) / 255.0f);
+
+ //Min. value of RGB
+ float var_Min = MIN(var_R, var_G);
+ var_Min = MIN(var_Min, var_B);
+
+ //Max. value of RGB
+ float var_Max = MAX(var_R, var_G);
+ var_Max = MAX(var_Max, var_B);
+
+ //Delta RGB value
+ float del_Max = var_Max - var_Min;
+
+ float H, S, L;
+
+ L = (var_Max + var_Min) / 2.0f;
+
+ //This is a gray, no chroma...
+ if (del_Max == 0) {
+ H = 0;
+ S = 0;
+ }
+ //Chromatic data...
+ else {
+ if (L < 0.5f) S = del_Max / (var_Max + var_Min);
+ else S = del_Max / (2.0f - var_Max - var_Min);
+
+ float del_R = (((var_Max - var_R) / 6.0f) + (del_Max / 2.0f)) / del_Max;
+ float del_G = (((var_Max - var_G) / 6.0f) + (del_Max / 2.0f)) / del_Max;
+ float del_B = (((var_Max - var_B) / 6.0f) + (del_Max / 2.0f)) / del_Max;
+
+ if (var_R == var_Max) H = del_B - del_G;
+ else if (var_G == var_Max) H = (1.0f / 3.0f) + del_R - del_B;
+ else if (var_B == var_Max) H = (2.0f / 3.0f) + del_G - del_R;
+
+ if (H < 0) H += 1;
+ if (H > 1) H -= 1;
+ }
+
+ *OutH = (byte)(H * 255);
+ *OutS = (byte)(S * 255);
+ *OutL = (byte)(L * 255);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+uint32 CBUtils::HSLtoRGB(byte InH, byte InS, byte InL) {
+ float H = InH / 255.0f;
+ float S = InS / 255.0f;
+ float L = InL / 255.0f;
+
+ byte R, G, B;
+
+
+ if (S == 0) {
+ R = (byte)(L * 255);
+ G = (byte)(L * 255);
+ B = (byte)(L * 255);
+ } else {
+ float var_1, var_2;
+
+ if (L < 0.5) var_2 = L * (1.0 + S);
+ else var_2 = (L + S) - (S * L);
+
+ var_1 = 2.0f * L - var_2;
+
+ R = (byte)(255 * Hue2RGB(var_1, var_2, H + (1.0f / 3.0f)));
+ G = (byte)(255 * Hue2RGB(var_1, var_2, H));
+ B = (byte)(255 * Hue2RGB(var_1, var_2, H - (1.0f / 3.0f)));
+ }
+ return DRGBA(255, R, G, B);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+float CBUtils::Hue2RGB(float v1, float v2, float vH) {
+ if (vH < 0.0f) vH += 1.0f;
+ if (vH > 1.0f) vH -= 1.0f;
+ if ((6.0f * vH) < 1.0f) return (v1 + (v2 - v1) * 6.0f * vH);
+ if ((2.0f * vH) < 1.0f) return (v2);
+ if ((3.0f * vH) < 2.0f) return (v1 + (v2 - v1) * ((2.0f / 3.0f) - vH) * 6.0f);
+ return (v1);
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/utils/utils.h b/engines/wintermute/utils/utils.h
new file mode 100644
index 0000000000..46e895ff4d
--- /dev/null
+++ b/engines/wintermute/utils/utils.h
@@ -0,0 +1,71 @@
+/* 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.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef WINTERMUTE_UTILS_H
+#define WINTERMUTE_UTILS_H
+
+#include "engines/wintermute/wintypes.h"
+
+namespace WinterMute {
+
+class CBGame;
+
+class CBUtils {
+public:
+ static void Clip(int *DestX, int *DestY, RECT *SrcRect, RECT *DestRect);
+ static void Swap(int *a, int *b);
+ static bool StrBeginsI(const char *String, const char *Fragment);
+ static float NormalizeAngle(float Angle);
+
+ static void CreatePath(const char *Path, bool PathOnly = false);
+
+ static void DebugMessage(HWND hWnd, const char *Text);
+ static char *SetString(char **String, const char *Value);
+
+ static int StrNumEntries(const char *Str, const char Delim = ',');
+ static char *StrEntry(int Entry, const char *Str, const char Delim = ',');
+
+ static int RandomInt(int From, int To);
+ static float RandomFloat(float From, float To);
+ static float RandomAngle(float From, float To);
+
+ static bool MatchesPattern(const char *pattern, const char *string);
+
+ static char *GetPath(const char *Filename);
+ static char *GetFilename(const char *Filename);
+
+ static void RGBtoHSL(uint32 RGBColor, byte *OutH, byte *OutS, byte *OutL);
+ static uint32 HSLtoRGB(byte H, byte S, byte L);
+
+private:
+ static float Hue2RGB(float v1, float v2, float vH);
+};
+
+} // end of namespace WinterMute
+
+#endif