mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1168407 - Pre: Add GeckoJarReader.extractStream. r=rnewman
The use case is to ship a classes.dex file in a Gecko add-on. This makes it easy to extract such a file from an add-on to a temporary location. (Sadly, the Android Dex loading classes expect files, not streams.)
This commit is contained in:
parent
858076ed5f
commit
c88c530673
@ -5,21 +5,23 @@
|
||||
package org.mozilla.gecko.util;
|
||||
|
||||
import android.content.Context;
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
import org.mozilla.gecko.mozglue.GeckoLoader;
|
||||
import org.mozilla.gecko.mozglue.NativeZip;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.util.Log;
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
import org.mozilla.gecko.mozglue.GeckoLoader;
|
||||
import org.mozilla.gecko.mozglue.NativeZip;
|
||||
import org.mozilla.gecko.mozglue.RobocopTarget;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Stack;
|
||||
@ -107,6 +109,68 @@ public final class GeckoJarReader {
|
||||
return new NativeZip(fileUrl.getPath());
|
||||
}
|
||||
|
||||
@RobocopTarget
|
||||
/**
|
||||
* Extract a (possibly nested) file from an archive and write it to a temporary file.
|
||||
*
|
||||
* @param context Android context.
|
||||
* @param url to open. Can include jar: to "reach into" nested archives.
|
||||
* @param dir to write temporary file to.
|
||||
* @return a <code>File</code>, if one could be written; otherwise null.
|
||||
* @throws IOException if an error occured.
|
||||
*/
|
||||
public static File extractStream(Context context, String url, File dir, String suffix) throws IOException {
|
||||
InputStream input = null;
|
||||
try {
|
||||
try {
|
||||
final URI fileURI = new URI(url);
|
||||
// We don't check the scheme because we want to catch bare files, not just file:// URIs.
|
||||
// If we let bare files through, we'd try to open them as ZIP files later -- and crash in native code.
|
||||
if (fileURI != null && fileURI.getPath() != null) {
|
||||
final File inputFile = new File(fileURI.getPath());
|
||||
if (inputFile != null && inputFile.exists()) {
|
||||
input = new FileInputStream(inputFile);
|
||||
}
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
// Not a file:// URI.
|
||||
}
|
||||
if (input == null) {
|
||||
// No luck with file:// URI; maybe some other URI?
|
||||
input = getStream(context, url);
|
||||
}
|
||||
if (input == null) {
|
||||
// Not found!
|
||||
return null;
|
||||
}
|
||||
|
||||
// n.b.: createTempFile does not in fact delete the file.
|
||||
final File file = File.createTempFile("extractStream", suffix, dir);
|
||||
OutputStream output = null;
|
||||
try {
|
||||
output = new FileOutputStream(file);
|
||||
byte[] buf = new byte[8192];
|
||||
int len;
|
||||
while ((len = input.read(buf)) >= 0) {
|
||||
output.write(buf, 0, len);
|
||||
}
|
||||
return file;
|
||||
} finally {
|
||||
if (output != null) {
|
||||
output.close();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (input != null) {
|
||||
try {
|
||||
input.close();
|
||||
} catch (IOException e) {
|
||||
Log.w(LOGTAG, "Got exception closing stream; ignoring.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RobocopTarget
|
||||
public static InputStream getStream(Context context, String url) {
|
||||
Stack<String> jarUrls = parseUrl(url);
|
||||
|
@ -3,10 +3,14 @@
|
||||
|
||||
package org.mozilla.tests.browser.junit3;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Stack;
|
||||
|
||||
import android.test.InstrumentationTestCase;
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
import org.mozilla.gecko.util.FileUtils;
|
||||
import org.mozilla.gecko.util.GeckoJarReader;
|
||||
|
||||
import android.content.Context;
|
||||
@ -46,4 +50,69 @@ public class TestJarReader extends InstrumentationTestCase {
|
||||
stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png");
|
||||
assertNull(stream);
|
||||
}
|
||||
|
||||
protected void assertExtractStream(String url) throws IOException {
|
||||
final File file = GeckoJarReader.extractStream(getInstrumentation().getTargetContext(), url, getInstrumentation().getContext().getCacheDir(), ".test");
|
||||
assertNotNull(file);
|
||||
try {
|
||||
assertTrue(file.getName().endsWith("temp"));
|
||||
final String contents = FileUtils.getFileContents(file);
|
||||
assertNotNull(contents);
|
||||
assertTrue(contents.length() > 0);
|
||||
} finally {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
public void testExtractStream() throws IOException {
|
||||
String appPath = getInstrumentation().getTargetContext().getPackageResourcePath();
|
||||
assertNotNull(appPath);
|
||||
|
||||
// We don't have a lot of good files to choose from. package-name.txt isn't included in Gradle APKs.
|
||||
assertExtractStream("jar:file://" + appPath + "!/resources.arsc");
|
||||
|
||||
final String url = GeckoJarReader.getJarURL(getInstrumentation().getTargetContext(), "chrome.manifest");
|
||||
assertExtractStream(url);
|
||||
|
||||
// Now use an extracted copy of chrome.manifest to test further.
|
||||
final File file = GeckoJarReader.extractStream(getInstrumentation().getTargetContext(), url, getInstrumentation().getContext().getCacheDir(), ".test");
|
||||
assertNotNull(file);
|
||||
try {
|
||||
assertExtractStream("file://" + file.getAbsolutePath()); // file:// URI.
|
||||
assertExtractStream(file.getAbsolutePath()); // Vanilla path.
|
||||
} finally {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertExtractStreamFails(String url) throws IOException {
|
||||
final File file = GeckoJarReader.extractStream(getInstrumentation().getTargetContext(), url, getInstrumentation().getContext().getCacheDir(), ".test");
|
||||
assertNull(file);
|
||||
}
|
||||
|
||||
public void testExtractStreamFailureCases() throws IOException {
|
||||
String appPath = getInstrumentation().getTargetContext().getPackageResourcePath();
|
||||
assertNotNull(appPath);
|
||||
|
||||
// First, a bad APK.
|
||||
assertExtractStreamFails("jar:file://" + appPath + "BAD!/resources.arsc");
|
||||
|
||||
// Second, a bad file in the APK.
|
||||
assertExtractStreamFails("jar:file://" + appPath + "!/BADresources.arsc");
|
||||
|
||||
// Now a bad file in the omnijar.
|
||||
final String badUrl = GeckoJarReader.getJarURL(getInstrumentation().getTargetContext(), "BADchrome.manifest");
|
||||
assertExtractStreamFails(badUrl);
|
||||
|
||||
// Now use an extracted copy of chrome.manifest to test further.
|
||||
final String goodUrl = GeckoJarReader.getJarURL(getInstrumentation().getTargetContext(), "chrome.manifest");
|
||||
final File file = GeckoJarReader.extractStream(getInstrumentation().getTargetContext(), goodUrl, getInstrumentation().getContext().getCacheDir(), ".test");
|
||||
assertNotNull(file);
|
||||
try {
|
||||
assertExtractStreamFails("file://" + file.getAbsolutePath() + "BAD"); // Bad file:// URI.
|
||||
assertExtractStreamFails(file.getAbsolutePath() + "BAD"); //Bad vanilla path.
|
||||
} finally {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user