Index: fileio.c
===================================================================
--- fileio.c.orig	2009-12-02 18:29:49.734262007 +0100
+++ fileio.c	2009-12-02 18:29:49.790239786 +0100
@@ -2074,9 +2074,9 @@ int do_string(__G__ length, option)   /*
                 /* translate the text coded in the entry's host-dependent
                    "extended ASCII" charset into the compiler's (system's)
                    internal text code page */
-                Ext_ASCII_TO_Native((char *)G.outbuf, G.pInfo->hostnum,
-                                    G.pInfo->hostver, G.pInfo->HasUxAtt,
-                                    FALSE);
+                Ext_ASCII_TO_Native((char *)G.outbuf, OUTBUFSIZ,
+				    G.pInfo->hostnum, G.pInfo->hostver,
+				    G.pInfo->HasUxAtt, FALSE);
 #ifdef WINDLL
                 /* translate to ANSI (RTL internal codepage may be OEM) */
                 INTERN_TO_ISO((char *)G.outbuf, (char *)G.outbuf);
@@ -2156,7 +2156,8 @@ int do_string(__G__ length, option)   /*
 
         /* translate the Zip entry filename coded in host-dependent "extended
            ASCII" into the compiler's (system's) internal text code page */
-        Ext_ASCII_TO_Native(G.filename, G.pInfo->hostnum, G.pInfo->hostver,
+        Ext_ASCII_TO_Native(G.filename, FILNAMSIZ,
+			    G.pInfo->hostnum, G.pInfo->hostver,
                             G.pInfo->HasUxAtt, (option == DS_FN_L));
 
         if (G.pInfo->lcflag)      /* replace with lowercase filename */
Index: unix/unix.c
===================================================================
--- unix/unix.c.orig	2009-12-02 18:29:49.702239787 +0100
+++ unix/unix.c	2009-12-02 18:29:49.794239606 +0100
@@ -30,6 +30,10 @@
 #define UNZIP_INTERNAL
 #include "unzip.h"
 
+#include <locale.h>
+#include <iconv.h>
+#include <langinfo.h>
+
 #ifdef SCO_XENIX
 #  define SYSNDIR
 #else  /* SCO Unix, AIX, DNIX, TI SysV, Coherent 4.x, ... */
@@ -1666,3 +1670,116 @@ static void qlfix(__G__ ef_ptr, ef_len)
     }
 }
 #endif /* QLZIP */
+
+
+static struct {
+	const char *iso_name;
+	const char *cp_name;
+} enc_map[] = {
+	{ "ISO-8859-1", "CP850" },
+	{ "ISO-8859-2", "CP852" },
+	{ "ISO-8859-5", "CP866" },
+	{ "ISO-8859-6", "CP864" },
+	{ "ISO-8859-7", "CP869" },
+	{ "ISO-8859-8", "CP862" },
+	{ "ISO-8859-9", "CP857" },
+	{ "TIS-620", "CP874" },
+	{ "EUC-JP", "CP932" },
+	{ "EUC-KR", "CP949" },
+	{ "GB2312", "CP936" },
+	{ "BIG5", "CP950" },
+};
+
+static const char *from_enc = "CP850";
+static const char *to_enc = "UTF-8";
+
+void init_encodings (void) {
+	const char *saved_locale, *non_utf8;
+	char *loc, *p;
+	int i;
+
+	loc = getenv ("LC_ALL") ?: getenv ("LANG");
+	if (!loc || !(loc = strdup (loc)))  return;
+
+
+	/*  save the locale anyway -- we don't know whether program
+	   do setlocale() itself or not...
+	*/
+	saved_locale = setlocale (LC_ALL, NULL);
+
+	setlocale (LC_ALL, "");
+	to_enc = nl_langinfo (CODESET);
+
+	/*  The idea to obtain "from_enc" is:
+	  Remove codeset part of LC_ALL/LANG (leave only language/country),
+	  and see what charmap would be used. By this "non-utf8" charmap
+	  we try to guess the correspond OEM/DOS codepage...
+	*/
+	p = strchr (loc, '.');
+	if (p)  *p = '\0';
+
+	/*  temporary...  */
+	setlocale (LC_ALL, loc);
+	non_utf8 = nl_langinfo (CODESET);
+
+	for (i = 0; i < sizeof (enc_map) / sizeof (*enc_map); i++) {
+
+	    if (!strcasecmp (non_utf8, enc_map[i].iso_name)) {
+
+		from_enc = enc_map[i].cp_name;
+
+		/*  need some more work for latin1 ...  */
+		if (!strcmp (enc_map[i].iso_name, "ISO-8859-1")) {
+		    char *lang = getenv ("LC_ALL") ?: getenv ("LANG");
+		    if (lang) {
+			if (!strncasecmp (lang, "da", 2) ||
+			    !strncasecmp (lang, "nb", 2) ||
+			    !strncasecmp (lang, "nn", 2) ||
+			    !strncasecmp (lang, "no", 2)
+			)  from_enc = "CP865";
+			else if (!strncasecmp (lang, "is", 2))
+				from_enc = "CP861";
+			else if (!strncasecmp (lang, "lt", 2) ||
+				 !strncasecmp (lang, "lv", 2)
+			)  from_enc = "CP775";
+		    }
+		}
+
+		break;
+	    }
+	}
+
+	setlocale (LC_ALL, saved_locale);
+
+	return;
+}
+
+void oem_to_local (char *str, size_t size) {
+	iconv_t conv;
+	size_t in_len, out_len;
+	char *out, *out_ptr, *in_ptr;
+
+
+	conv = iconv_open (to_enc, from_enc);
+	if (conv == (iconv_t) -1)  return;	/*  foo on you   */
+
+	in_len = strlen (str);
+	in_ptr = str;
+
+	out_len = 4 * in_len + 1;	/*  assume enough even for utf8 ...  */
+	if (out_len > size)  out_len = size;
+	out_len--;		/*  for terminating '\0'   */
+	out = out_ptr = alloca (out_len);
+
+	if (iconv (conv, &in_ptr, &in_len, &out_ptr, &out_len) < 0)
+		return;		/*  foo on you   */
+
+	out_len = (out_ptr - out);
+	if (out_len >= size)
+		return;		/*  paranoia   */
+
+	memcpy (str, out, out_len);
+	str[out_len] = '\0';
+
+	return;
+}
Index: unzip.c
===================================================================
--- unzip.c.orig	2009-12-02 18:29:49.445742905 +0100
+++ unzip.c	2009-12-02 18:29:49.873812802 +0100
@@ -668,6 +668,10 @@ int unzip(__G__ argc, argv)
 
     SETLOCALE(LC_CTYPE,"");
 
+#ifdef UNIX
+    init_encodings ();
+#endif
+
 #if (defined(__IBMC__) && defined(__DEBUG_ALLOC__))
     extern void DebugMalloc(void);
 
Index: unzpriv.h
===================================================================
--- unzpriv.h.orig	2009-12-02 18:29:49.670231009 +0100
+++ unzpriv.h	2009-12-02 18:29:49.906078155 +0100
@@ -2576,14 +2576,20 @@ char    *GetLoadPath     OF((__GPRO));
  * All other ports are assumed to code zip entry filenames in ISO 8859-1.
  */
 #ifndef Ext_ASCII_TO_Native
-#  define Ext_ASCII_TO_Native(string, hostnum, hostver, isuxatt, islochdr) \
+#ifndef UNIX
+#define _OEM_INTERN_SIZE(STR,SIZE)	_OEM_INTERN((STR))
+#else
+extern void oem_to_local (char *str, size_t size);
+#define _OEM_INTERN_SIZE(STR,SIZE)	oem_to_local ((STR), (SIZE))
+#endif
+#  define Ext_ASCII_TO_Native(string, size, hostnum, hostver, isuxatt, islochdr) \
     if (uO.no_conv_enc == FALSE) { \
     if (((hostnum) == FS_FAT_ && \
          !(((islochdr) || (isuxatt)) && \
            ((hostver) == 25 || (hostver) == 26 || (hostver) == 40))) || \
         (hostnum) == FS_HPFS_ || \
         ((hostnum) == FS_NTFS_ && (hostver) == 50)) { \
-        _OEM_INTERN((string)); \
+        _OEM_INTERN_SIZE((string),(size)); \
     } else { \
         _ISO_INTERN((string)); \
     }}
