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 ZipEntry$nameLen
= scanField(ZipEntry
.class, "nameLen", "nameLength");
109 if (ZipEntry$nameLen
== null)
111 ZipEntry$nameLen
.setAccessible(true);
113 final Field ZipFile$mRaf
= scanField(ZipFile
.class, "mRaf", "raf");
114 if (ZipFile$mRaf
== null)
116 ZipFile$mRaf
.setAccessible(true);
118 final Field ZipEntry$mLocalHeaderRelOffset
= scanField(ZipEntry
.class, "mLocalHeaderRelOffset", "localHeaderRelOffset");
119 if (ZipEntry$mLocalHeaderRelOffset
== null)
121 ZipEntry$mLocalHeaderRelOffset
.setAccessible(true);
123 final Method ZipFile$getInputStream
= findMethod(ZipFile
.class, "getInputStream", ZipEntry
.class);
124 if (ZipFile$getInputStream
== null)
127 MS
.hookMethod(ZipFile
.class, ZipFile$getInputStream
,
128 new MS
.MethodAlteration
<ZipFile
, InputStream
>() {
129 public InputStream
invoked(ZipFile thiz
, Object
... args
)
132 ZipEntry entry
= (ZipEntry
) args
[0];
134 RandomAccessFile raf
= (RandomAccessFile
) ZipFile$mRaf
.get(thiz
);
136 raf
.seek(ZipEntry$mLocalHeaderRelOffset
.getLong(entry
));
139 if ((raf
.readShort() & 0x0080) != 0)
140 throw new ZipException("bug #9695860 [" + thiz
.getName() + "]");
144 int length
= raf
.readShort() & 0xffff;
145 if (length
!= ZipEntry$nameLen
.getInt(entry
))
146 throw new ZipException("bug #9950697 [" + thiz
.getName() + "]");
148 if ((raf
.readShort() & 0x0080) != 0)
149 throw new ZipException("bug #9695860 [" + thiz
.getName() + "]");
152 return invoke(thiz
, args
);
158 private static void fixZipFile$
readCentralDir() {
159 final Field ZipFile$entries
= scanField(ZipFile
.class, "mEntries", "entries");
160 if (ZipFile$entries
== null)
162 ZipFile$entries
.setAccessible(true);
164 final Method ZipFile$readCentralDir
= findMethod(ZipFile
.class, "readCentralDir");
165 if (ZipFile$readCentralDir
== null)
168 MS
.hookMethod(ZipFile
.class, ZipFile$readCentralDir
,
169 new MS
.MethodAlteration
<ZipFile
, Void
>() {
170 public Void
invoked(ZipFile thiz
, Object
... args
)
173 ZipFile$entries
.set(thiz
, new LinkedHashMap
<String
, ZipEntry
>() {
174 public ZipEntry
put(String key
, ZipEntry value
) {
175 if (super.put(key
, value
) != null)
176 throw new WrongException(new ZipException("bug #8219321 [" + key
+ "]"));
182 return invoke(thiz
, args
);
183 } catch (WrongException wrong
) {
184 throw wrong
.getCause();
191 public static void initialize() {
193 fixZipFile$
getInputStream();
194 fixZipFile$
readCentralDir();