--- unarj.c~ 2002-03-11 14:04:23 +0300 +++ unarj.c 2005-10-20 17:48:34 +0400 @@ -58,6 +58,9 @@ #include #include #include +#include +#include +#include #else /* !MODERN */ extern void free(); extern void exit(); @@ -284,6 +287,91 @@ exit(EXIT_FAILURE); } +#define MAX_CP_NAME 25 + +typedef struct { + char *local_charset; + char *archive_charset; +} CHARSET_MAP; + +/* A mapping of local <-> archive charsets used by default to convert filenames + * of DOS/Windows Zip archives. Currently very basic. */ +static CHARSET_MAP dos_charset_map[] = { + { "ANSI_X3.4-1968", "CP850" }, + { "ISO-8859-1", "CP850" }, + { "CP1252", "CP850" }, + { "CP1251", "CP866" }, + { "KOI8-R", "CP866" }, + { "KOI8-U", "CP866" }, + { "ISO-8859-5", "CP866" } +}; + +char OEM_CP[MAX_CP_NAME] = ""; +char ISO_CP[MAX_CP_NAME] = ""; + +/* Try to guess the default value of OEM_CP based on the current locale. + * ISO_CP is left alone for now. */ +static void +init_conversion_charsets() +{ + const char *local_charset; + int i; + + /* Make a guess only if OEM_CP not already set. */ + if(*OEM_CP == '\0') { + local_charset = nl_langinfo(CODESET); + for(i = 0; i < sizeof(dos_charset_map)/sizeof(CHARSET_MAP); i++) + if(!strcasecmp(local_charset, dos_charset_map[i].local_charset)) { + strncpy(OEM_CP, dos_charset_map[i].archive_charset, + sizeof(OEM_CP)); + break; + } + } +} + +static void charset_to_intern(char *string, char *from_charset) +{ + iconv_t cd; + char *s, *d, *buf; + size_t slen, dlen, buflen; + const char *local_charset; + + if(*from_charset == '\0') + return; + + buf = NULL; + local_charset = nl_langinfo(CODESET); + + if((cd = iconv_open(local_charset, from_charset)) == (iconv_t)-1) + return; + + slen = dlen = buflen = strlen(string); + s = string; + d = buf = malloc(buflen + 1); + if(!d) + goto cleanup; + + if(iconv(cd, &s, &slen, &d, &dlen) == (size_t)-1) + goto cleanup; + strncpy(string, buf, buflen); + + cleanup: + free(buf); + iconv_close(cd); +} + +/* Convert a string from OEM_CP to the current locale charset. */ +void oem_intern(char *string) +{ + charset_to_intern(string, OEM_CP); +} + +/* Convert a string from ISO_CP to the current locale charset. */ +void iso_intern(char *string) +{ + charset_to_intern(string, ISO_CP); +} + static void strparity(p) uchar *p; @@ -636,14 +724,14 @@ hdr_filename = (char *)&header[first_hdr_size]; strncopy(filename, hdr_filename, sizeof(filename)); if (host_os != OS) - strparity((uchar *)filename); + oem_intern(filename); if ((arj_flags & PATHSYM_FLAG) != 0) decode_path(filename); hdr_comment = (char *)&header[first_hdr_size + strlen(hdr_filename) + 1]; strncopy(comment, hdr_comment, sizeof(comment)); if (host_os != OS) - strparity((uchar *)comment); + oem_intern(comment); /* if extheadersize == 0 then no CRC */ /* otherwise read extheader data and read 4 bytes for CRC */ @@ -989,6 +1077,9 @@ printf(M_VERSION); + setlocale(LC_CTYPE, ""); + init_conversion_charsets(); + if (argc == 1) { help();