1 /* Backport - Bring New Fixes to old Androids
2 * Copyright (C) 2013 Jay Freeman (saurik)
5 /* GNU Lesser General Public License, Version 3 {{{ */
7 * Substrate is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
12 * Substrate is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 * License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with Substrate. If not, see <http://www.gnu.org/licenses/>.
22 package com
.saurik
.backport
;
24 import java
.lang
.reflect
.Constructor
;
25 import java
.lang
.reflect
.Field
;
26 import java
.lang
.reflect
.Method
;
28 import java
.io
.ByteArrayInputStream
;
29 import java
.io
.DataInputStream
;
30 import java
.io
.InputStream
;
31 import java
.io
.RandomAccessFile
;
33 import java
.util
.LinkedHashMap
;
35 import java
.util
.zip
.ZipEntry
;
36 import java
.util
.zip
.ZipException
;
37 import java
.util
.zip
.ZipFile
;
39 import android
.util
.Log
;
41 import com
.saurik
.substrate
.MS
;
44 private static class WrongException
45 extends RuntimeException
47 public WrongException(Throwable cause
) {
52 private static Field
scanField(Class clazz
, String
... names
) {
53 for (String name
: names
) try {
54 return clazz
.getDeclaredField(name
);
55 } catch (NoSuchFieldException e
) {}
59 private static Method
findMethod(Class
<?
> clazz
, String name
, Class
... args
) {
61 return clazz
.getDeclaredMethod(name
, args
);
62 } catch (NoSuchMethodException e
) {
67 private static Constructor
findConstructor(Class
<?
> clazz
, Class
... args
) {
69 return clazz
.getDeclaredConstructor(args
);
70 } catch (NoSuchMethodException e
) {
75 private static void fixZipEntry$init$
() {
76 final Constructor ZipEntry$init$
= findConstructor(ZipEntry
.class, byte[].class, InputStream
.class);
77 if (ZipEntry$init$
== null)
80 MS
.hookMethod(ZipEntry
.class, ZipEntry$init$
,
81 new MS
.MethodAlteration
<ZipEntry
, Void
>() {
82 public Void
invoked(ZipEntry thiz
, Object
... args
)
85 byte[] header
= (byte[]) args
[0];
89 DataInputStream in
= new DataInputStream(new ByteArrayInputStream(header
));
92 for (int i
= 0; i
!= 2; ++i
)
93 if ((in
.readShort() & 0x0080) != 0)
94 throw new ZipException("bug #9695860 [" + thiz
.getName() + "]");
97 for (int i
= 0; i
!= 3; ++i
)
98 if ((in
.readShort() & 0x0080) != 0)
99 throw new ZipException("bug #9695860 [" + thiz
.getName() + "]");
107 private static void fixZipFile$
getInputStream() {
108 final Field ZipFile$mRaf
= scanField(ZipFile
.class, "mRaf", "raf");
109 if (ZipFile$mRaf
== null)
111 ZipFile$mRaf
.setAccessible(true);
113 final Field ZipEntry$mLocalHeaderRelOffset
= scanField(ZipEntry
.class, "mLocalHeaderRelOffset", "localHeaderRelOffset");
114 if (ZipEntry$mLocalHeaderRelOffset
== null)
116 ZipEntry$mLocalHeaderRelOffset
.setAccessible(true);
118 final Method ZipFile$getInputStream
= findMethod(ZipFile
.class, "getInputStream", ZipEntry
.class);
119 if (ZipFile$getInputStream
== null)
122 MS
.hookMethod(ZipFile
.class, ZipFile$getInputStream
,
123 new MS
.MethodAlteration
<ZipFile
, InputStream
>() {
124 public InputStream
invoked(ZipFile thiz
, Object
... args
)
127 ZipEntry entry
= (ZipEntry
) args
[0];
129 RandomAccessFile raf
= (RandomAccessFile
) ZipFile$mRaf
.get(thiz
);
131 raf
.seek(ZipEntry$mLocalHeaderRelOffset
.getLong(entry
));
134 if ((raf
.readShort() & 0x0080) != 0)
135 throw new ZipException("bug #9695860 [" + thiz
.getName() + "]");
138 if ((raf
.readShort() & 0x0080) != 0)
139 throw new ZipException("bug #9695860 [" + thiz
.getName() + "]");
142 return invoke(thiz
, args
);
148 private static void fixZipFile$
readCentralDir() {
149 final Field ZipFile$entries
= scanField(ZipFile
.class, "mEntries", "entries");
150 if (ZipFile$entries
== null)
152 ZipFile$entries
.setAccessible(true);
154 final Method ZipFile$readCentralDir
= findMethod(ZipFile
.class, "readCentralDir");
155 if (ZipFile$readCentralDir
== null)
158 MS
.hookMethod(ZipFile
.class, ZipFile$readCentralDir
,
159 new MS
.MethodAlteration
<ZipFile
, Void
>() {
160 public Void
invoked(ZipFile thiz
, Object
... args
)
163 ZipFile$entries
.set(thiz
, new LinkedHashMap
<String
, ZipEntry
>() {
164 public ZipEntry
put(String key
, ZipEntry value
) {
165 if (super.put(key
, value
) != null)
166 throw new WrongException(new ZipException("bug #8219321 [" + key
+ "]"));
172 return invoke(thiz
, args
);
173 } catch (WrongException wrong
) {
174 throw wrong
.getCause();
181 public static void initialize() {
183 fixZipFile$
getInputStream();
184 fixZipFile$
readCentralDir();