1
From: Giovanni Scafora <giovanni.archlinux.org>
2
Subject: unzip files encoded with non-latin, non-unicode file names
4
diff -r e812cb68e51d unix/unix.c
5
--- a/unix/unix.c Tue Jun 23 23:08:25 2009 -0500
6
+++ b/unix/unix.c Thu Jun 25 00:10:29 2009 -0500
12
+#include <langinfo.h>
16
#else /* SCO Unix, AIX, DNIX, TI SysV, Coherent 4.x, ... */
17
@@ -1874,3 +1877,90 @@
24
+ char *local_charset;
25
+ char *archive_charset;
28
+/* A mapping of local <-> archive charsets used by default to convert filenames
29
+ * of DOS/Windows Zip archives. Currently very basic. */
30
+static CHARSET_MAP dos_charset_map[] = {
31
+ { "ANSI_X3.4-1968", "CP850" },
32
+ { "ISO-8859-1", "CP850" },
33
+ { "CP1252", "CP850" },
34
+ { "UTF-8", "CP866" },
35
+ { "KOI8-R", "CP866" },
36
+ { "KOI8-U", "CP866" },
37
+ { "ISO-8859-5", "CP866" }
40
+char OEM_CP[MAX_CP_NAME] = "";
41
+char ISO_CP[MAX_CP_NAME] = "";
43
+/* Try to guess the default value of OEM_CP based on the current locale.
44
+ * ISO_CP is left alone for now. */
45
+void init_conversion_charsets()
47
+ const char *local_charset;
50
+ /* Make a guess only if OEM_CP not already set. */
51
+ if(*OEM_CP == '\0') {
52
+ local_charset = nl_langinfo(CODESET);
53
+ for(i = 0; i < sizeof(dos_charset_map)/sizeof(CHARSET_MAP); i++)
54
+ if(!strcasecmp(local_charset, dos_charset_map[i].local_charset)) {
55
+ strncpy(OEM_CP, dos_charset_map[i].archive_charset,
62
+/* Convert a string from one encoding to the current locale using iconv().
63
+ * Be as non-intrusive as possible. If error is encountered during covertion
64
+ * just leave the string intact. */
65
+static void charset_to_intern(char *string, char *from_charset)
69
+ size_t slen, dlen, buflen;
70
+ const char *local_charset;
72
+ if(*from_charset == '\0')
76
+ local_charset = nl_langinfo(CODESET);
78
+ if((cd = iconv_open(local_charset, from_charset)) == (iconv_t)-1)
81
+ slen = strlen(string);
83
+ dlen = buflen = 2*slen;
84
+ d = buf = malloc(buflen + 1);
88
+ if(iconv(cd, &s, &slen, &d, &dlen) == (size_t)-1)
90
+ strncpy(string, buf, buflen);
97
+/* Convert a string from OEM_CP to the current locale charset. */
98
+inline void oem_intern(char *string)
100
+ charset_to_intern(string, OEM_CP);
103
+/* Convert a string from ISO_CP to the current locale charset. */
104
+inline void iso_intern(char *string)
106
+ charset_to_intern(string, ISO_CP);
108
diff -r e812cb68e51d unix/unxcfg.h
109
--- a/unix/unxcfg.h Tue Jun 23 23:08:25 2009 -0500
110
+++ b/unix/unxcfg.h Thu Jun 25 00:10:29 2009 -0500
112
/* wild_dir, dirname, wildname, matchname[], dirnamelen, have_dirname, */
113
/* and notfirstcall are used by do_wild(). */
116
+#define MAX_CP_NAME 25
121
+#define SETLOCALE(category, locale) setlocale(category, locale)
127
+#define _ISO_INTERN(str1) iso_intern(str1)
132
+#ifndef IZ_OEM2ISO_ARRAY
133
+# define IZ_OEM2ISO_ARRAY
135
+#define _OEM_INTERN(str1) oem_intern(str1)
137
+void iso_intern(char *);
138
+void oem_intern(char *);
139
+void init_conversion_charsets(void);
141
#endif /* !__unxcfg_h */
142
diff -r e812cb68e51d unzip.c
143
--- a/unzip.c Tue Jun 23 23:08:25 2009 -0500
144
+++ b/unzip.c Thu Jun 25 00:10:29 2009 -0500
145
@@ -327,11 +327,21 @@
146
-2 just filenames but allow -h/-t/-z -l long Unix \"ls -l\" format\n\
147
-v verbose, multi-page format\n";
150
static ZCONST char Far ZipInfoUsageLine3[] = "miscellaneous options:\n\
151
-h print header line -t print totals for listed files or for all\n\
152
-z print zipfile comment -T print file times in sortable decimal format\
153
\n -C be case-insensitive %s\
154
-x exclude filenames that follow from listing\n";
156
+static ZCONST char Far ZipInfoUsageLine3[] = "miscellaneous options:\n\
157
+ -h print header line -t print totals for listed files or for all\n\
158
+ -z print zipfile comment %c-T%c print file times in sortable decimal format\
159
+\n %c-C%c be case-insensitive %s\
160
+ -x exclude filenames that follow from listing\n\
161
+ -O CHARSET specify a character encoding for DOS, Windows and OS/2 archives\n\
162
+ -I CHARSET specify a character encoding for UNIX and other archives\n";
165
static ZCONST char Far ZipInfoUsageLine4[] =
166
" -M page output through built-in \"more\"\n";
168
-U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields\n\
169
-C match filenames case-insensitively -L make (some) names \
170
lowercase\n %-42s -V retain VMS version numbers\n%s";
171
+#elif (defined UNIX)
172
+static ZCONST char Far UnzipUsageLine4[] = "\
174
+ -n never overwrite existing files -q quiet mode (-qq => quieter)\n\
175
+ -o overwrite files WITHOUT prompting -a auto-convert any text files\n\
176
+ -j junk paths (do not make directories) -aa treat ALL files as text\n\
177
+ -U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields\n\
178
+ -C match filenames case-insensitively -L make (some) names \
179
+lowercase\n %-42s -V retain VMS version numbers\n%s\
180
+ -O CHARSET specify a character encoding for DOS, Windows and OS/2 archives\n\
181
+ -I CHARSET specify a character encoding for UNIX and other archives\n\n";
183
static ZCONST char Far UnzipUsageLine4[] = "\
186
#endif /* UNICODE_SUPPORT */
190
+ init_conversion_charsets();
193
#if (defined(__IBMC__) && defined(__DEBUG_ALLOC__))
194
extern void DebugMalloc(void);
196
@@ -1336,6 +1361,11 @@
201
+ extern char OEM_CP[MAX_CP_NAME];
202
+ extern char ISO_CP[MAX_CP_NAME];
205
while (++argv, (--argc > 0 && *argv != NULL && **argv == '-')) {
207
while ((c = *s++) != 0) { /* "!= 0": prevent Turbo C warning */
208
@@ -1517,6 +1547,35 @@
215
+ Info(slide, 0x401, ((char *)slide,
216
+ "error: encodings can't be negated"));
219
+ if(*s) { /* Handle the -Icharset case */
220
+ /* Assume that charsets can't start with a dash to spot arguments misuse */
222
+ Info(slide, 0x401, ((char *)slide,
223
+ "error: a valid character encoding should follow the -I argument"));
226
+ strncpy(ISO_CP, s, sizeof(ISO_CP));
227
+ } else { /* -I charset */
229
+ if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
230
+ Info(slide, 0x401, ((char *)slide,
231
+ "error: a valid character encoding should follow the -I argument"));
235
+ strncpy(ISO_CP, s, sizeof(ISO_CP));
237
+ while(*(++s)); /* No params straight after charset name */
241
case ('j'): /* junk pathnames/directory structure */
243
uO.jflag = FALSE, negative = 0;
244
@@ -1592,6 +1651,35 @@
251
+ Info(slide, 0x401, ((char *)slide,
252
+ "error: encodings can't be negated"));
255
+ if(*s) { /* Handle the -Ocharset case */
256
+ /* Assume that charsets can't start with a dash to spot arguments misuse */
258
+ Info(slide, 0x401, ((char *)slide,
259
+ "error: a valid character encoding should follow the -I argument"));
262
+ strncpy(OEM_CP, s, sizeof(OEM_CP));
263
+ } else { /* -O charset */
265
+ if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
266
+ Info(slide, 0x401, ((char *)slide,
267
+ "error: a valid character encoding should follow the -O argument"));
271
+ strncpy(OEM_CP, s, sizeof(OEM_CP));
273
+ while(*(++s)); /* No params straight after charset name */
277
case ('p'): /* pipes: extract to stdout, no messages */
280
diff -r e812cb68e51d unzpriv.h
281
--- a/unzpriv.h Tue Jun 23 23:08:25 2009 -0500
282
+++ b/unzpriv.h Thu Jun 25 00:10:29 2009 -0500
283
@@ -3008,7 +3008,7 @@
284
!(((islochdr) || (isuxatt)) && \
285
((hostver) == 25 || (hostver) == 26 || (hostver) == 40))) || \
286
(hostnum) == FS_HPFS_ || \
287
- ((hostnum) == FS_NTFS_ && (hostver) == 50)) { \
288
+ ((hostnum) == FS_NTFS_ /* && (hostver) == 50 */ )) { \
289
_OEM_INTERN((string)); \
291
_ISO_INTERN((string)); \
292
diff -r e812cb68e51d zipinfo.c
293
--- a/zipinfo.c Tue Jun 23 23:08:25 2009 -0500
294
+++ b/zipinfo.c Thu Jun 25 00:10:29 2009 -0500
296
int tflag_slm=TRUE, tflag_2v=FALSE;
297
int explicit_h=FALSE, explicit_t=FALSE;
300
+ extern char OEM_CP[MAX_CP_NAME];
301
+ extern char ISO_CP[MAX_CP_NAME];
305
uO.lflag = LFLAG; /* reset default on each call */
313
+ Info(slide, 0x401, ((char *)slide,
314
+ "error: encodings can't be negated"));
317
+ if(*s) { /* Handle the -Icharset case */
318
+ /* Assume that charsets can't start with a dash to spot arguments misuse */
320
+ Info(slide, 0x401, ((char *)slide,
321
+ "error: a valid character encoding should follow the -I argument"));
324
+ strncpy(ISO_CP, s, sizeof(ISO_CP));
325
+ } else { /* -I charset */
327
+ if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
328
+ Info(slide, 0x401, ((char *)slide,
329
+ "error: a valid character encoding should follow the -I argument"));
333
+ strncpy(ISO_CP, s, sizeof(ISO_CP));
335
+ while(*(++s)); /* No params straight after charset name */
339
case 'l': /* longer form of "ls -l" type listing */
341
uO.lflag = -2, negative = 0;
349
+ Info(slide, 0x401, ((char *)slide,
350
+ "error: encodings can't be negated"));
353
+ if(*s) { /* Handle the -Ocharset case */
354
+ /* Assume that charsets can't start with a dash to spot arguments misuse */
356
+ Info(slide, 0x401, ((char *)slide,
357
+ "error: a valid character encoding should follow the -I argument"));
360
+ strncpy(OEM_CP, s, sizeof(OEM_CP));
361
+ } else { /* -O charset */
363
+ if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
364
+ Info(slide, 0x401, ((char *)slide,
365
+ "error: a valid character encoding should follow the -O argument"));
369
+ strncpy(OEM_CP, s, sizeof(OEM_CP));
371
+ while(*(++s)); /* No params straight after charset name */
375
case 's': /* default: shorter "ls -l" type listing */
377
uO.lflag = -2, negative = 0;