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 #99695860 [" + thiz
.getName() + "]"); 
  97                     for (int i 
= 0; i 
!= 3; ++i
) 
  98                         if ((in
.readShort() & 0x0080) != 0) 
  99                             throw new ZipException("bug #99695860 [" + 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 #99695860 [" + thiz
.getName() + "]"); 
 138                         if ((raf
.readShort() & 0x0080) != 0) 
 139                             throw new ZipException("bug #99695860 [" + 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();