diff -ru openttd-2197/functions.h openttd-trunk/functions.h
--- openttd-2197/functions.h	2005-04-14 15:48:32.020298512 -0400
+++ openttd-trunk/functions.h	2005-04-14 16:20:38.574417768 -0400
@@ -254,6 +254,8 @@
 void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize);
 int GetLanguageList(char **languages, int max);
 
+void openttd_to_utf8(unsigned char *iso, size_t memsize, byte **utf);
+
 void CheckSwitchToEuro(void);
 
 void LoadFromConfig(void);
diff -ru openttd-2197/strings.c openttd-trunk/strings.c
--- openttd-2197/strings.c	2005-04-14 15:48:32.124282704 -0400
+++ openttd-trunk/strings.c	2005-04-14 16:22:46.194016640 -0400
@@ -130,6 +130,130 @@
 	return dst - 1;
 }
 
+// Note: Does not check size of wchar when inserting. Do that yourself.
+void openttd_to_wchar(byte *iso, uint32 memsize, uint32 *wchar)
+{
+	uint32 i;
+
+	for(i = 0; i < memsize; i++) {
+		switch (iso[i]) {
+			case 0x9F: // LATIN CAPITAL LETTER Y WITH DIAERESIS
+				wchar[i] = 0x0178;
+				break;
+			case 0xA0: // BLACK UP-POINTING TRIANGLE
+				wchar[i] = 0x25B2;
+				break;
+			case 0xA4: // EURO SIGN
+				wchar[i] = 0x20AC;
+				break;
+			case 0xAA: // BLACK DOWN-POINTING TRIANGLE
+				wchar[i] = 0x25BC;
+				break;
+			case 0xAC: // CHECK MARK
+				wchar[i] = 0x2713;
+				break;
+			case 0xAD: // BALLOT X
+				wchar[i] = 0x2717;
+				break;
+			case 0xAF: // BLACK RIGHT-POINTING TRIANGLE
+				wchar[i] = 0x25B6;
+				break;
+			case 0xB4: // TRAIN
+				wchar[i] = 0xF000;
+				break;
+			case 0xB5: // LORRY
+				wchar[i] = 0xF001;
+				break;
+			case 0xB6: // BUS
+				wchar[i] = 0xF002;
+				break;
+			case 0xB7: // PLANE
+				wchar[i] = 0xF003;
+				break;
+			case 0xB8: // SHIP
+				wchar[i] = 0xF004;
+				break;
+			case 0xB9: // SUPERSCRIPT NEGATIVE ONE
+				wchar[i] = 0xF005;
+				break;
+			case 0xBC: // BLACK UP-POINTING SMALL TRIANGLE
+				wchar[i] = 0x25B4;
+				break;
+			case 0xBD: // BLACK DOWN-POINTING SMALL TRIANGLE
+				wchar[i] = 0x25BE;
+				break;
+			default:
+				wchar[i] = iso[i];
+		}
+	}
+}
+
+byte *wchar_to_utf8(uint32 *wchar, uint32 memsize)
+{
+	uint32 i;
+	byte *mem, *ptr;
+	
+	mem = calloc(memsize * 6 + 1, 1);
+	ptr = mem;
+	
+	for(i = 0; i < memsize; i++)
+	{
+		if(wchar[i] < 0x80)
+		{
+			*ptr++ = wchar[i] & 0x7F;
+		}
+		else if(wchar[i] < 0x800)
+		{
+			*ptr++ = 0xC0 | ((wchar[i] >> 6) & 0x1F);
+			*ptr++ = 0x80 | (wchar[i] & 0x3F);
+		}
+		else if(wchar[i] < 0x10000)
+		{
+			*ptr++ = 0xE0 | ((wchar[i] >> 12) & 0x0F);
+			*ptr++ = 0x80 | ((wchar[i] >> 6) & 0x3F);
+			*ptr++ = 0x80 | (wchar[i] & 0x3F);
+		}
+		else if(wchar[i] < 0x200000)
+		{
+			*ptr++ = 0xF0 | ((wchar[i] >> 18) & 0x07);
+			*ptr++ = 0x80 | ((wchar[i] >> 12) & 0x3F);
+			*ptr++ = 0x80 | ((wchar[i] >> 6) & 0x3F);
+			*ptr++ = 0x80 | (wchar[i] & 0x3F);
+		}
+		else if(wchar[i] < 0x4000000)
+		{
+			*ptr++ = 0xF8 | ((wchar[i] >> 24) & 0x03);
+			*ptr++ = 0x80 | ((wchar[i] >> 18) & 0x3F);
+			*ptr++ = 0x80 | ((wchar[i] >> 12) & 0x3F);
+			*ptr++ = 0x80 | ((wchar[i] >> 6) & 0x3F);
+			*ptr++ = 0x80 | (wchar[i] & 0x3F);
+		}
+		else if(wchar[i] < 0x80000000)
+		{
+			*ptr++ = 0xFC | ((wchar[i] >> 30) & 0x01);
+			*ptr++ = 0x80 | ((wchar[i] >> 24) & 0x3F);
+			*ptr++ = 0x80 | ((wchar[i] >> 18) & 0x3F);
+			*ptr++ = 0x80 | ((wchar[i] >> 12) & 0x3F);
+			*ptr++ = 0x80 | ((wchar[i] >> 6) & 0x3F);
+			*ptr++ = 0x80 | (wchar[i] & 0x3F);
+		}
+	}
+	
+	mem = realloc(mem, ptr - mem + 1);
+	
+	return mem;
+}
+
+// Wraps conversion from OpenTTD encoding to wchar, and wchar to utf-8
+void openttd_to_utf8(char *iso, uint32 memsize, byte **utf)
+{
+	uint32 *wchar = calloc(sizeof(uint32) * (memsize + 1), 1);
+
+	openttd_to_wchar(iso, memsize, wchar);
+	*utf = wchar_to_utf8(wchar, memsize, utf);
+	free(wchar);
+}
+
 static const char *GetStringPtr(StringID string)
 {
 	return _langpack_offs[_langtab_start[string >> 11] + (string & 0x7FF)];

