*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "frotz.h"
};
extern zword object_name (zword);
+extern zword get_window_font (zword);
-static zchar decoded[10];
-static zword encoded[3];
+zchar* decoded;
+zchar* encoded;
+static int resolution;
/*
* According to Matteo De Luigi <matteo.de.luigi@libero.it>,
* Sat Apr 21, 2001
*/
static zchar zscii_to_latin1[] = {
- 0xe4, 0xf6, 0xfc, 0xc4, 0xd6, 0xdc, 0xdf, 0xbb,
- 0xab, 0xeb, 0xef, 0xff, 0xcb, 0xcf, 0xe1, 0xe9,
- 0xed, 0xf3, 0xfa, 0xfd, 0xc1, 0xc9, 0xcd, 0xd3,
- 0xda, 0xdd, 0xe0, 0xe8, 0xec, 0xf2, 0xf9, 0xc0,
- 0xc8, 0xcc, 0xd2, 0xd9, 0xe2, 0xea, 0xee, 0xf4,
- 0xfb, 0xc2, 0xca, 0xce, 0xd4, 0xdb, 0xe5, 0xc5,
- 0xf8, 0xd8, 0xe3, 0xf1, 0xf5, 0xc3, 0xd1, 0xd5,
- 0xe6, 0xc6, 0xe7, 0xc7, 0xfe, 0xf0, 0xde, 0xd0,
- 0xa3, 0x00, 0x00, 0xa1, 0xbf
+ 0x0e4, 0x0f6, 0x0fc, 0x0c4, 0x0d6, 0x0dc, 0x0df, 0x0bb,
+ 0x0ab, 0x0eb, 0x0ef, 0x0ff, 0x0cb, 0x0cf, 0x0e1, 0x0e9,
+ 0x0ed, 0x0f3, 0x0fa, 0x0fd, 0x0c1, 0x0c9, 0x0cd, 0x0d3,
+ 0x0da, 0x0dd, 0x0e0, 0x0e8, 0x0ec, 0x0f2, 0x0f9, 0x0c0,
+ 0x0c8, 0x0cc, 0x0d2, 0x0d9, 0x0e2, 0x0ea, 0x0ee, 0x0f4,
+ 0x0fb, 0x0c2, 0x0ca, 0x0ce, 0x0d4, 0x0db, 0x0e5, 0x0c5,
+ 0x0f8, 0x0d8, 0x0e3, 0x0f1, 0x0f5, 0x0c3, 0x0d1, 0x0d5,
+ 0x0e6, 0x0c6, 0x0e7, 0x0c7, 0x0fe, 0x0f0, 0x0de, 0x0d0,
+ 0x0a3, 0x153, 0x152, 0x0a1, 0x0bf
};
+/*
+ * init_text
+ *
+ * Initialize text variables.
+ *
+ */
+
+void init_text (void)
+{
+ decoded = NULL;
+ encoded = NULL;
+
+ resolution = 0;
+}
+
/*
* translate_from_zscii
*
- * Map a ZSCII character onto the ISO Latin-1 alphabet.
+ * Map a ZSCII character into Unicode.
*
*/
LOW_WORD (addr, unicode)
- return (unicode < 0x100) ? (zchar) unicode : '?';
+ if (unicode < 0x20)
+ return '?';
+
+ return unicode;
} else return '?';
if (c <= 0xdf) {
- if (c == 0xdc || c == 0xdd) /* Oe and oe ligatures */
- return '?'; /* are not ISO-Latin 1 */
-
return zscii_to_latin1[c - 0x9b];
} else return '?';
}
- return c;
+ return (zchar) c;
}/* translate_from_zscii */
/*
- * translate_to_zscii
+ * unicode_to_zscii
*
- * Map an ISO Latin-1 character onto the ZSCII alphabet.
+ * Convert a Unicode character to ZSCII, returning 0 on failure.
*
*/
-zbyte translate_to_zscii (zchar c)
+zbyte unicode_to_zscii (zchar c)
{
int i;
- if (c == ZC_SINGLE_CLICK)
- return 0xfe;
- if (c == ZC_DOUBLE_CLICK)
- return 0xfd;
- if (c == ZC_MENU_CLICK)
- return 0xfc;
-
if (c >= ZC_LATIN1_MIN) {
if (hx_unicode_table != 0) { /* game has its own Unicode table */
}
- return '?';
+ return 0;
} else { /* game uses standard set */
if (c == zscii_to_latin1[i - 0x9b])
return (zbyte) i;
- return '?';
+ return 0;
}
}
- if (c == 0) /* Safety thing from David Kinder */
- c = '?'; /* regarding his Unicode patches */
- /* Sept 15, 2002 */
+ return (zbyte) c;
- return c;
+}/* unicode_to_zscii */
+
+/*
+ * translate_to_zscii
+ *
+ * Map a Unicode character onto the ZSCII alphabet.
+ *
+ */
+
+zbyte translate_to_zscii (zchar c)
+{
+
+ if (c == ZC_SINGLE_CLICK)
+ return 0xfe;
+ if (c == ZC_DOUBLE_CLICK)
+ return 0xfd;
+ if (c == ZC_MENU_CLICK)
+ return 0xfc;
+ if (c == 0)
+ return 0;
+
+ c = unicode_to_zscii (c);
+ if (c == 0)
+ c = '?';
+
+ return (zbyte) c;
}/* translate_to_zscii */
static zchar alphabet (int set, int index)
{
+ if (h_version > V1 && set == 2 && index == 1)
+ return 0x0D; /* always newline */
if (h_alphabet != 0) { /* game uses its own alphabet */
}/* alphabet */
+/*
+ * find_resolution
+ *
+ * Find the number of bytes used for dictionary resolution.
+ *
+ */
+
+static void find_resolution (void)
+{
+ zword dct = h_dictionary;
+ zword entry_count;
+ zbyte sep_count;
+ zbyte entry_len;
+
+ LOW_BYTE (dct, sep_count)
+ dct += 1 + sep_count; /* skip word separators */
+ LOW_BYTE (dct, entry_len)
+ dct += 1; /* skip entry length */
+ LOW_WORD (dct, entry_count)
+ dct += 2; /* get number of entries */
+
+ if (h_version < V9) {
+
+ resolution = (h_version <= V3) ? 2 : 3;
+
+ } else {
+
+ zword addr = dct;
+ zword code;
+
+ if (entry_count == 0) {
+
+ runtime_error (ERR_DICT_LEN);
+
+ }
+
+ /* check the first word in the dictionary */
+
+ do {
+
+ LOW_WORD (addr, code)
+ addr += 2;
+
+ } while (!(code & 0x8000) && (addr - dct < entry_len + 1));
+
+ resolution = (addr - dct) / 2;
+
+ }
+
+ if (2 * resolution > entry_len) {
+
+ runtime_error (ERR_DICT_LEN);
+
+ }
+
+ decoded = (zchar *)malloc (sizeof (zchar) * (3 * resolution) + 1);
+ encoded = (zchar *)malloc (sizeof (zchar) * resolution);
+
+}/* find_resolution */
+
/*
* load_string
*
static void load_string (zword addr, zword length)
{
- int resolution = (h_version <= V3) ? 2 : 3;
int i = 0;
+ if (resolution == 0) find_resolution();
+
while (i < 3 * resolution)
if (i < length) {
* Encode the Unicode text in the global "decoded" string then write
* the result to the global "encoded" array. (This is used to look up
* words in the dictionary.) Up to V3 the vocabulary resolution is
- * two, since V4 it is three words. Because each word contains three
- * Z-characters, that makes six or nine Z-characters respectively.
- * Longer words are chopped to the proper size, shorter words are are
- * padded out with 5's. For word completion we pad with 0s and 31s,
- * the minimum and maximum Z-characters.
+ * two, from V4 it is three, and from V9 it is any number of words.
+ * Because each word contains three Z-characters, that makes six or
+ * nine Z-characters respectively. Longer words are chopped to the
+ * proper size, shorter words are are padded out with 5's. For word
+ * completion we pad with 0s and 31s, the minimum and maximum
+ * Z-characters.
*
*/
static void encode_text (int padding)
{
- static zchar again[] = { 'a', 'g', 'a', 'i', 'n', 0 };
- static zchar examine[] = { 'e', 'x', 'a', 'm', 'i', 'n', 'e', 0 };
- static zchar wait[] = { 'w', 'a', 'i', 't', 0 };
+ static zchar again[] = { 'a', 'g', 'a', 'i', 'n', 0, 0, 0, 0 };
+ static zchar examine[] = { 'e', 'x', 'a', 'm', 'i', 'n', 'e', 0, 0 };
+ static zchar wait[] = { 'w', 'a', 'i', 't', 0, 0, 0, 0, 0 };
- zbyte zchars[12];
- const zchar *ptr = decoded;
+ zbyte *zchars;
+ const zchar *ptr;
zchar c;
- int resolution = (h_version <= V3) ? 2 : 3;
int i = 0;
+ if (resolution == 0) find_resolution();
+
+ zchars = (zbyte *)malloc (sizeof (zbyte) * 3 * (resolution + 1));
+ ptr = decoded;
+
/* Expand abbreviations that some old Infocom games lack */
- if (f_setup.expand_abbreviations)
+ if (option_expand_abbreviations && (h_version <= V8))
if (padding == 0x05 && decoded[1] == 0)
int index, set;
zbyte c2;
+ if (c == 32) {
+
+ zchars[i++] = 0;
+
+ continue;
+
+ }
+
/* Search character in the alphabet */
for (set = 0; set < 3; set++)
encoded[resolution - 1] |= 0x8000;
+ free (zchars);
+
}/* encode_text */
/*
- * z_check_unicode, test if a unicode character can be read and printed.
+ * z_check_unicode, test if a unicode character can be printed (bit 0) and read (bit 1).
*
* zargs[0] = Unicode
*
void z_check_unicode (void)
{
zword c = zargs[0];
+ zword result = 0;
- if (c >= 0x20 && c <= 0x7e)
- store (3);
- else if (c == 0xa0)
- store (1);
- else if (c >= 0xa1 && c <= 0xff)
- store (3);
+ if (c <= 0x1f)
+ {
+ if ((c == 0x08) || (c == 0x0d) || (c == 0x1b))
+ result = 2;
+ }
+ else if (c <= 0x7e)
+ result = 3;
else
- store (0);
+ result = 1; // we support unicode
+
+ store (result);
}/* z_check_unicode */
encode_text (0x05);
- for (i = 0; i < 3; i++)
+ for (i = 0; i < resolution; i++)
storew ((zword) (zargs[3] + 2 * i), encoded[i]);
}/* z_encode_text */
ptr = NULL; /* makes compilers shut up */
byte_addr = 0;
+ if (resolution == 0) find_resolution();
+
/* Calculate the byte address if necessary */
if (st == ABBREVIATION)
byte_addr = (long) addr << 2;
else if (h_version <= V7)
byte_addr = ((long) addr << 2) + ((long) h_strings_offset << 3);
- else /* h_version == V8 */
+ else if (h_version <= V8)
byte_addr = (long) addr << 3;
+ else /* h_version == V9 */ {
+ long indirect = (long) addr << 2;
+ HIGH_LONG(indirect, byte_addr);
+ }
if (byte_addr >= story_size)
runtime_error (ERR_ILL_PRINT_ADDR);
zword abbr_addr;
zword ptr_addr;
+ zchar zc;
c = (code >> i) & 0x1f;
case 3: /* ZSCII character - second part */
- c2 = translate_from_zscii ((prev_c << 5) | c);
- outchar (c2);
+ zc = (prev_c << 5) | c;
+
+ if (zc > 767) { /* Unicode escape */
+
+ while (zc-- > 767) {
+
+ if (st == LOW_STRING || st == VOCABULARY) {
+ LOW_WORD (addr, c2)
+ addr += 2;
+ } else if (st == HIGH_STRING || st == ABBREVIATION) {
+ HIGH_WORD (byte_addr, c2)
+ byte_addr += 2;
+ } else
+ CODE_WORD (c2)
+
+ outchar (c2 ^ 0xFFFF);
+ }
+
+ } else {
+
+ c2 = translate_from_zscii (zc);
+ outchar (c2);
+
+ }
status = 0;
break;
void z_print_unicode (void)
{
- print_char ((zargs[0] <= 0xff) ? zargs[0] : '?');
+ if (zargs[0] < 0x20)
+ print_char ('?');
+ else
+ print_char (zargs[0]);
}/* z_print_unicode */
zword addr;
zbyte entry_len;
zbyte sep_count;
- int resolution = (h_version <= V3) ? 2 : 3;
int entry_number;
int lower, upper;
int i;
bool sorted;
+ if (resolution == 0) find_resolution();
+
encode_text (padding);
LOW_BYTE (dct, sep_count) /* skip word separators */
*result = 0;
+ if (resolution == 0) find_resolution();
+
/* Copy last word to "decoded" string */
len = 0;
if (c != ' ') {
- if (len < 9)
+ if (len < 3 * resolution)
decoded[len++] = c;
} else len = 0;
return (minaddr == maxaddr) ? 0 : 1;
}/* completion */
+
+/*
+ * unicode_tolower
+ *
+ * Convert a Unicode character to lowercase.
+ * Taken from Zip2000 by Kevin Bracey.
+ *
+ */
+
+zchar unicode_tolower (zchar c)
+{
+ const static unsigned char tolower_basic_latin[0x100] = {
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+ 0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x5B,0x5C,0x5D,0x5E,0x5F,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
+ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xD7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xDF,
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
+ };
+ const static unsigned char tolower_latin_extended_a[0x80] = {
+ 0x01,0x01,0x03,0x03,0x05,0x05,0x07,0x07,0x09,0x09,0x0B,0x0B,0x0D,0x0D,0x0F,0x0F,
+ 0x11,0x11,0x13,0x13,0x15,0x15,0x17,0x17,0x19,0x19,0x1B,0x1B,0x1D,0x1D,0x1F,0x1F,
+ 0x21,0x21,0x23,0x23,0x25,0x25,0x27,0x27,0x29,0x29,0x2B,0x2B,0x2D,0x2D,0x2F,0x2F,
+ 0x00,0x31,0x33,0x33,0x35,0x35,0x37,0x37,0x38,0x3A,0x3A,0x3C,0x3C,0x3E,0x3E,0x40,
+ 0x40,0x42,0x42,0x44,0x44,0x46,0x46,0x48,0x48,0x49,0x4B,0x4B,0x4D,0x4D,0x4F,0x4F,
+ 0x51,0x51,0x53,0x53,0x55,0x55,0x57,0x57,0x59,0x59,0x5B,0x5B,0x5D,0x5D,0x5F,0x5F,
+ 0x61,0x61,0x63,0x63,0x65,0x65,0x67,0x67,0x69,0x69,0x6B,0x6B,0x6D,0x6D,0x6F,0x6F,
+ 0x71,0x71,0x73,0x73,0x75,0x75,0x77,0x77,0x00,0x7A,0x7A,0x7C,0x7C,0x7E,0x7E,0x7F
+ };
+ const static unsigned char tolower_greek[0x50] = {
+ 0x80,0x81,0x82,0x83,0x84,0x85,0xAC,0x87,0xAD,0xAE,0xAF,0x8B,0xCC,0x8D,0xCD,0xCE,
+ 0x90,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
+ 0xC0,0xC1,0xA2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xAC,0xAD,0xAE,0xAF,
+ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF
+ };
+ const static unsigned char tolower_cyrillic[0x60] = {
+ 0x00,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F
+ };
+
+ if (c < 0x0100)
+ c = tolower_basic_latin[c];
+ else if (c == 0x0130)
+ c = 0x0069; /* Capital I with dot -> lower case i */
+ else if (c == 0x0178)
+ c = 0x00FF; /* Capital Y diaeresis -> lower case y diaeresis */
+ else if (c < 0x0180)
+ c = tolower_latin_extended_a[c-0x100] + 0x100;
+ else if (c >= 0x380 && c < 0x3D0)
+ c = tolower_greek[c-0x380] + 0x300;
+ else if (c >= 0x400 && c < 0x460)
+ c = tolower_cyrillic[c-0x400] + 0x400;
+
+ return c;
+}
+