Bonjour,
Le package java.util.zip génère une exception lors de la décompression de fichiers dont le nom comporte des caractères non UTF-8.
La résolution de ce bug est vivement souhaitée par les développeurs des 4 coins du monde, d'où sa présence à la 2ème place du top 25 des bugs JAVA:
http://bugs.sun.com/bugdatabase/top25_bugs.do
De plus, lors de la compression, le nom des entrées est mal converti pour les mêmes raisons.
Je propose de corriger ce bug ici et de l'envoyer à SUN pour l'inclure dans une prochaine release. (why not)
J'ai commencé à y jetter un coup d'oeil pour la décompression, et j'arrive à décompresser des fichiers ZIP avec des caractères accentués sans générer d'exception.
Vous trouverez l'ensemble des classes en PJ:
- Le ZipInputStream qui pose problème et qui a subit quelques modifs de ma part.
- ZipConstant n'a pas changé mais comme les constantes ne sont pas publiques, alors il a été nécessaire de le copier dans le package.
- ZipUtils, ma classe utilitaire ZIP, exploitable, mais pas dans sa version finale.
Utilisation: disposer de documents avec des accents ou autres caractères mal gérés dans le répertoire test, créés à la racine du projet ; les zipper avec Winzip (nom=fromWinzip.zip), Winrar (nom=fromWinrar.zip).
Exemple d'utilisation dans un petit test.java contenant un petit main:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 public static void main(String[] args) { String path = "test/"; try { ZipUtils.compress(path, new File(path+"fromJAVAZIP.zip")); ZipUtils.decompress(new File(path + "fromWinzip.zip"), path + "/unzippedWINZIP"); //ZipUtils.decompress(new File(path + "fromWInrar.zip"), path + "/unzippedWINRAR"); //ZipUtils.decompress(new File(path + "fromJAVAZIP.zip"), path + "/unzippedJAVAZIP"); } catch (Exception e) { e.printStackTrace(); } }
Pour ceux qui sont vraiment experts, et qui peuvent se passer de ce genre de tests, voici là où le problème se pose:Dans la version originale, l'appel se fait avec getUTF8String et le plantage se situe
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93 /** * Fetches a UTF8-encoded String from the specified byte array. */ private static String getUTF8String(byte[] b, int off, int len) { // First, count the number of characters in the sequence int count = 0; int max = off + len; int i = off; while (i < max) { int c = b[i++] & 0xff; switch (c >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: // 0xxxxxxx count++; break; case 12: case 13: // 110xxxxx 10xxxxxx if ((int) (b[i++] & 0xc0) != 0x80) { throw new IllegalArgumentException(); } count++; break; case 14: // 1110xxxx 10xxxxxx 10xxxxxx if (((int) (b[i++] & 0xc0) != 0x80) || ((int) (b[i++] & 0xc0) != 0x80)) { throw new IllegalArgumentException(); } count++; break; default: // 10xxxxxx, 1111xxxx throw new IllegalArgumentException(); } } if (i != max) { throw new IllegalArgumentException(); } // Now decode the characters... char[] cs = new char[count]; i = 0; while (off < max) { int c = b[off++] & 0xff; switch (c >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: // 0xxxxxxx cs[i++] = (char) c; break; case 12: case 13: // 110xxxxx 10xxxxxx cs[i++] = (char) (((c & 0x1f) << 6) | (b[off++] & 0x3f)); break; case 14: // 1110xxxx 10xxxxxx 10xxxxxx int t = (b[off++] & 0x3f) << 6; cs[i++] = (char) (((c & 0x0f) << 12) | t | (b[off++] & 0x3f)); break; default: // 10xxxxxx, 1111xxxx throw new IllegalArgumentException(); } } return new String(cs, 0, count); } private String getZipEntryName(byte[] b, int off, int len) { String result = null; try { result = new String(b, off, len, "UTF-8"); } catch (UnsupportedEncodingException e) { result = new String(b, off, len); } return result; }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 default: // 10xxxxxx, 1111xxxx throw new IllegalArgumentException();
Ma solution a consisté pour le moment à bifurquer l'appel vers getZipEntryName.
Mais je bloque, d'où la demande de la contribution de personnes plus confirmées que moi.
Cordialement,
Billy
EDIT: SystemUtils est une autre classe non incluse en PJ
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 FILE_SEPARATOR = System.getProperty("file.separator"); FILE_ENCODING = System.getProperty("file.encoding");
Partager