package com.saurik.backport;
+import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
-import java.util.LinkedHashMap;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
-import java.util.jar.JarFile;
+import java.util.LinkedHashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
}
}
- public static void initialize() {
- MS.hookClassLoad("java.util.zip.ZipFile", new MS.ClassLoadHook() {
- public void classLoaded(Class<?> ZipFile$) {
- Field entries = null; {
- if (entries == null) try {
- entries = ZipFile$.getDeclaredField("entries");
- } catch (NoSuchFieldException e) {}
-
- if (entries == null) try {
- entries = ZipFile$.getDeclaredField("mEntries");
- } catch (NoSuchFieldException e) {}
+ private static Field scanField(Class clazz, String... names) {
+ for (String name : names) try {
+ return clazz.getDeclaredField(name);
+ } catch (NoSuchFieldException e) {}
+ return null;
+ }
+
+ private static Method findMethod(Class<?> clazz, String name, Class... args) {
+ try {
+ return clazz.getDeclaredMethod(name, args);
+ } catch (NoSuchMethodException e) {
+ return null;
+ }
+ }
+
+ private static Constructor findConstructor(Class<?> clazz, Class... args) {
+ try {
+ return clazz.getDeclaredConstructor(args);
+ } catch (NoSuchMethodException e) {
+ return null;
+ }
+ }
+
+ private static void fixZipEntry$init$() {
+ final Constructor ZipEntry$init$ = findConstructor(ZipEntry.class, byte[].class, InputStream.class);
+ if (ZipEntry$init$ == null)
+ return;
+
+ MS.hookMethod(ZipEntry.class, ZipEntry$init$,
+ new MS.MethodAlteration<ZipEntry, Void>() {
+ public Void invoked(ZipEntry thiz, Object... args)
+ throws Throwable
+ {
+ byte[] header = (byte[]) args[0];
+
+ invoke(thiz, args);
+
+ DataInputStream in = new DataInputStream(new ByteArrayInputStream(header));
+
+ in.skip(8);
+ for (int i = 0; i != 2; ++i)
+ if ((in.readShort() & 0x0080) != 0)
+ throw new ZipException("bug #99695860 [" + thiz.getName() + "]");
+
+ in.skip(16);
+ for (int i = 0; i != 3; ++i)
+ if ((in.readShort() & 0x0080) != 0)
+ throw new ZipException("bug #99695860 [" + thiz.getName() + "]");
+
+ return null;
}
+ }
+ );
+ }
+
+ private static void fixZipFile$getInputStream() {
+ final Field ZipFile$mRaf = scanField(ZipFile.class, "mRaf", "raf");
+ if (ZipFile$mRaf == null)
+ return;
+ ZipFile$mRaf.setAccessible(true);
+
+ final Field ZipEntry$mLocalHeaderRelOffset = scanField(ZipEntry.class, "mLocalHeaderRelOffset", "localHeaderRelOffset");
+ if (ZipEntry$mLocalHeaderRelOffset == null)
+ return;
+ ZipEntry$mLocalHeaderRelOffset.setAccessible(true);
+
+ final Method ZipFile$getInputStream = findMethod(ZipFile.class, "getInputStream", ZipEntry.class);
+ if (ZipFile$getInputStream == null)
+ return;
+
+ MS.hookMethod(ZipFile.class, ZipFile$getInputStream,
+ new MS.MethodAlteration<ZipFile, InputStream>() {
+ public InputStream invoked(ZipFile thiz, Object... args)
+ throws Throwable
+ {
+ ZipEntry entry = (ZipEntry) args[0];
- if (entries == null)
- return;
- final Field ZipFile$entries = entries;
- ZipFile$entries.setAccessible(true);
+ RandomAccessFile raf = (RandomAccessFile) ZipFile$mRaf.get(thiz);
+ synchronized (raf) {
+ raf.seek(ZipEntry$mLocalHeaderRelOffset.getLong(entry));
- final Method ZipFile$readCentralDir; try {
- ZipFile$readCentralDir = ZipFile$.getDeclaredMethod("readCentralDir");
- } catch (NoSuchMethodException e) {
- Log.e("Backport", "ZipFile$readCentralDir", e);
- return;
+ raf.skipBytes(6);
+ if ((raf.readShort() & 0x0080) != 0)
+ throw new ZipException("bug #99695860 [" + thiz.getName() + "]");
+
+ raf.skipBytes(20);
+ if ((raf.readShort() & 0x0080) != 0)
+ throw new ZipException("bug #99695860 [" + thiz.getName() + "]");
+ }
+
+ return invoke(thiz, args);
}
+ }
+ );
+ }
+
+ private static void fixZipFile$readCentralDir() {
+ final Field ZipFile$entries = scanField(ZipFile.class, "mEntries", "entries");
+ if (ZipFile$entries == null)
+ return;
+ ZipFile$entries.setAccessible(true);
- MS.hookMethod(ZipFile$, ZipFile$readCentralDir,
- new MS.MethodAlteration<ZipFile, Void>() {
- public Void invoked(ZipFile thiz, Object... args)
- throws Throwable
- {
- ZipFile$entries.set(thiz, new LinkedHashMap<String, ZipEntry>() {
- public ZipEntry put(String key, ZipEntry value) {
- if (super.put(key, value) != null)
- throw new WrongException(new ZipException("Duplicate entry name: " + key));
- return null;
- }
- });
-
- try {
- return invoke(thiz, args);
- } catch (WrongException wrong) {
- throw wrong.getCause();
- }
+ final Method ZipFile$readCentralDir = findMethod(ZipFile.class, "readCentralDir");
+ if (ZipFile$readCentralDir == null)
+ return;
+
+ MS.hookMethod(ZipFile.class, ZipFile$readCentralDir,
+ new MS.MethodAlteration<ZipFile, Void>() {
+ public Void invoked(ZipFile thiz, Object... args)
+ throws Throwable
+ {
+ ZipFile$entries.set(thiz, new LinkedHashMap<String, ZipEntry>() {
+ public ZipEntry put(String key, ZipEntry value) {
+ if (super.put(key, value) != null)
+ throw new WrongException(new ZipException("bug #8219321 [" + key + "]"));
+ return null;
}
+ });
+
+ try {
+ return invoke(thiz, args);
+ } catch (WrongException wrong) {
+ throw wrong.getCause();
}
- );
+ }
}
- });
+ );
+ }
+
+ public static void initialize() {
+ fixZipEntry$init$();
+ fixZipFile$getInputStream();
+ fixZipFile$readCentralDir();
}
}