2012-03-22 11:11:49 -07:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
package org.mozilla.gecko;
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
import java.net.URL;
|
|
|
|
import java.util.EmptyStackException;
|
|
|
|
import java.util.Stack;
|
|
|
|
import java.util.zip.ZipFile;
|
|
|
|
import java.util.zip.ZipInputStream;
|
|
|
|
import java.util.zip.ZipEntry;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
|
2012-03-23 17:07:10 -07:00
|
|
|
import android.graphics.drawable.BitmapDrawable;
|
2012-03-22 11:11:49 -07:00
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
/* Reads out of a multiple level deep jar file such as
|
|
|
|
* jar:jar:file:///data/app/org.mozilla.fennec.apk!/omni.ja!/chrome/chrome/content/branding/favicon32.png
|
|
|
|
*/
|
2012-07-17 17:54:54 -07:00
|
|
|
public class GeckoJarReader {
|
|
|
|
private static String LOGTAG = "GeckoJarReader";
|
2012-03-22 11:11:49 -07:00
|
|
|
|
2012-03-23 17:07:10 -07:00
|
|
|
public static BitmapDrawable getBitmapDrawable(String url) {
|
2012-03-22 11:11:49 -07:00
|
|
|
Stack<String> jarUrls = parseUrl(url);
|
2012-03-23 17:07:10 -07:00
|
|
|
InputStream inputStream = null;
|
|
|
|
BitmapDrawable bitmap = null;
|
2012-03-22 11:11:49 -07:00
|
|
|
|
2012-03-22 15:11:39 -07:00
|
|
|
ZipFile zip = null;
|
2012-03-22 11:11:49 -07:00
|
|
|
try {
|
|
|
|
// Load the initial jar file as a zip
|
2012-03-23 17:07:10 -07:00
|
|
|
zip = getZipFile(jarUrls.pop());
|
|
|
|
inputStream = getStream(zip, jarUrls);
|
|
|
|
if (inputStream != null) {
|
|
|
|
bitmap = new BitmapDrawable(inputStream);
|
|
|
|
}
|
|
|
|
} catch (IOException ex) {
|
|
|
|
Log.e(LOGTAG, "Exception ", ex);
|
|
|
|
} finally {
|
|
|
|
if (inputStream != null) {
|
|
|
|
try {
|
|
|
|
inputStream.close();
|
|
|
|
} catch(IOException ex) {
|
|
|
|
Log.e(LOGTAG, "Error closing stream", ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (zip != null) {
|
|
|
|
try {
|
|
|
|
zip.close();
|
|
|
|
} catch(IOException ex) {
|
|
|
|
Log.e(LOGTAG, "Error closing zip", ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return bitmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static ZipFile getZipFile(String url) throws IOException {
|
|
|
|
URL fileUrl = new URL(url);
|
|
|
|
File file = new File(fileUrl.getPath());
|
|
|
|
return new ZipFile(file);
|
|
|
|
}
|
2012-03-22 11:11:49 -07:00
|
|
|
|
2012-03-23 17:07:10 -07:00
|
|
|
private static InputStream getStream(ZipFile zip, Stack<String> jarUrls) throws IOException {
|
|
|
|
ZipInputStream inputStream = null;
|
|
|
|
ZipEntry entry = null;
|
|
|
|
try {
|
2012-03-22 11:11:49 -07:00
|
|
|
// loop through children jar files until we reach the innermost one
|
|
|
|
while (jarUrls.peek() != null) {
|
|
|
|
String fileName = jarUrls.pop();
|
|
|
|
|
|
|
|
if (inputStream != null) {
|
|
|
|
entry = getEntryFromStream(inputStream, fileName);
|
|
|
|
} else {
|
|
|
|
entry = zip.getEntry(fileName);
|
|
|
|
}
|
|
|
|
|
|
|
|
// if there is nothing else on the stack, this will throw and break us out of the loop
|
|
|
|
jarUrls.peek();
|
|
|
|
|
|
|
|
if (inputStream != null) {
|
|
|
|
inputStream = new ZipInputStream(inputStream);
|
|
|
|
} else {
|
|
|
|
inputStream = new ZipInputStream(zip.getInputStream(entry));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entry == null) {
|
|
|
|
Log.d(LOGTAG, "No Entry for " + fileName);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (EmptyStackException ex) {
|
2012-03-23 17:07:10 -07:00
|
|
|
Log.d(LOGTAG, "Jar reader reached end of stack");
|
2012-03-22 11:11:49 -07:00
|
|
|
}
|
|
|
|
return inputStream;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Searches through a ZipInputStream for an entry with a given name */
|
2012-03-23 17:07:10 -07:00
|
|
|
private static ZipEntry getEntryFromStream(ZipInputStream zipStream, String entryName) {
|
2012-03-22 11:11:49 -07:00
|
|
|
ZipEntry entry = null;
|
|
|
|
|
|
|
|
try {
|
|
|
|
entry = zipStream.getNextEntry();
|
|
|
|
while(entry != null && !entry.getName().equals(entryName)) {
|
|
|
|
entry = zipStream.getNextEntry();
|
|
|
|
}
|
|
|
|
} catch (IOException ex) {
|
|
|
|
Log.e(LOGTAG, "Exception getting stream entry", ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns a stack of strings breaking the url up into pieces. Each piece
|
|
|
|
* is assumed to point to a jar file except for the final one. Callers should
|
|
|
|
* pass in the url to parse, and null for the parent parameter (used for recursion)
|
|
|
|
* For example, jar:jar:file:///data/app/org.mozilla.fennec.apk!/omni.ja!/chrome/chrome/content/branding/favicon32.png
|
|
|
|
* will return:
|
|
|
|
* file:///data/app/org.mozilla.fennec.apk
|
|
|
|
* omni.ja
|
|
|
|
* chrome/chrome/content/branding/favicon32.png
|
|
|
|
*/
|
2012-03-23 17:07:10 -07:00
|
|
|
private static Stack<String> parseUrl(String url) {
|
2012-03-22 11:11:49 -07:00
|
|
|
return parseUrl(url, null);
|
|
|
|
}
|
|
|
|
|
2012-03-23 17:07:10 -07:00
|
|
|
private static Stack<String> parseUrl(String url, Stack<String> results) {
|
2012-03-22 11:11:49 -07:00
|
|
|
if (results == null) {
|
|
|
|
results = new Stack<String>();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (url.startsWith("jar:")) {
|
|
|
|
int jarEnd = url.lastIndexOf("!");
|
|
|
|
String subStr = url.substring(4, jarEnd);
|
|
|
|
results.push(url.substring(jarEnd+2)); // remove the !/ characters
|
|
|
|
return parseUrl(subStr, results);
|
|
|
|
} else {
|
|
|
|
results.push(url);
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|