3 pièce(s) jointe(s)
	
	
		Patch probleme java.util.zip
	
	
		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:
	
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:
	Code:
	
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;
	} | 
 Dans la version originale, l'appel se fait avec getUTF8String et le plantage se situe
	Code:
	
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:
	
1 2
   | FILE_SEPARATOR = System.getProperty("file.separator");
FILE_ENCODING = System.getProperty("file.encoding"); |