java.util.zip.ZipException: Cannot read local header version 45

Crash & ANR

For some weird reason, my Calgary +15 App, stopped working! #@$#$#!

crash

It had been running smoothly, and I didn’t change anything with my codes, so what happened? It turns out, my data source – one of the data sets  published by the City of Calgary, under their Open Data initiative, had some tell-tale signs of updates…

When I got home, I plugged in my phone to the computer, and started the ADB session. Viola! the error says:


java.util.zip.ZipException: Cannot read local header version 45
at java.util.zip.ZipInputStream.getNextEntry(ZipInputStream.java:237)

What is that???? So, I immediately headed over to the Android Source Code, for ZipInputStream class to check it out. The exception, is thrown by the code on line # 252 (search for the exception message).

if (version > ZIPLocalHeaderVersionNeeded) {
throw new ZipException("Cannot read local header version " + version);
}

What the heck? ZIPLocalHeaderVersionNeeded is a constant (line #73) with a value of 20.  So, the KMZ file from the open data site, returns 45? After some research, it looks like when a ZIP file, is generated in Zip64 mode, the header value will be 45.

But as of this posting, the native Zip implementation of Android (as seen on the source code), doesn’t support this yet, so I guess I am left to my own devices…

I found an alternative library (Compress), by Apache Commons, which looked like will serve my needs. First of all, I try to stick with Android native libraries, to keep my APK size down. Also, using third-party libraries can create some dependency issues, as they may not be targeted/optimized for Android.

Having said that, I ported my native unzip code, to use the Apache Commons compress library, and the app worked again, yay!  The APK got a little bit bigger though :-(

Since I use Android Studio, I added the dependency to my gradle build file

compile 'org.apache.commons:commons-compress:1.8'

The “unzip” code, could then be implemented to a familiar Java Unzip code something like this:

private static String unzip(final File src, final File destFolder) throws IOException, ArchiveException {
 final InputStream is = new FileInputStream(src);
 String actualFilename = "blahblah.kml";
 final ArchiveInputStream in = new ArchiveStreamFactory().createArchiveInputStream("zip", is);
 dest.mkdirs();
 ZipArchiveEntry ze;
 while ((ze = (ZipArchiveEntry)in.getNextEntry()) != null) {
  final byte[] buffer = new byte[8192];
  int count;
  final String temp = ze.getName();
  if (!temp.endsWith("kml")) {
  continue;
  }
  actualFilename = temp;
  final FileOutputStream fos = new FileOutputStream(new File(destFolder, actualFilename));
  final BufferedOutputStream out = new BufferedOutputStream(fos);
  try {
   while ((count = in.read(buffer)) != -1) {
    out.write(buffer, 0, count);
   }
   out.flush();
  } finally {
   fos.getFD().sync();
   out.close();
  }
 }
 in.close();
 return actualFilename;
}

Hope this post/rant helped you, and hopefully, the Android team updates the native library to handle Zip64 archives…

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer’s view in any way.
Posted in Android, Rant
  • Mmax

    Thanks for solution!