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                     if (thiz
.getName().indexOf(0) != -1) 
  90                         throw new ZipException("bug #10148349 [" + thiz
.getName() + "]"); 
  92                     DataInputStream in 
= new DataInputStream(new ByteArrayInputStream(header
)); 
  95                     for (int i 
= 0; i 
!= 2; ++i
) 
  96                         if ((in
.readShort() & 0x0080) != 0) 
  97                             throw new ZipException("bug #9695860 [" + thiz
.getName() + "]"); 
 100                     for (int i 
= 0; i 
!= 3; ++i
) 
 101                         if ((in
.readShort() & 0x0080) != 0) 
 102                             throw new ZipException("bug #9695860 [" + thiz
.getName() + "]"); 
 110     private static void fixZipFile$
getInputStream() { 
 111         final Field ZipEntry$nameLen 
= scanField(ZipEntry
.class, "nameLen", "nameLength"); 
 112         if (ZipEntry$nameLen 
== null) 
 114         ZipEntry$nameLen
.setAccessible(true); 
 116         final Field ZipFile$mRaf 
= scanField(ZipFile
.class, "mRaf", "raf"); 
 117         if (ZipFile$mRaf 
== null) 
 119         ZipFile$mRaf
.setAccessible(true); 
 121         final Field ZipEntry$mLocalHeaderRelOffset 
= scanField(ZipEntry
.class, "mLocalHeaderRelOffset", "localHeaderRelOffset"); 
 122         if (ZipEntry$mLocalHeaderRelOffset 
== null) 
 124         ZipEntry$mLocalHeaderRelOffset
.setAccessible(true); 
 126         final Method ZipFile$getInputStream 
= findMethod(ZipFile
.class, "getInputStream", ZipEntry
.class); 
 127         if (ZipFile$getInputStream 
== null) 
 130         MS
.hookMethod(ZipFile
.class, ZipFile$getInputStream
, 
 131             new MS
.MethodAlteration
<ZipFile
, InputStream
>() { 
 132                 public InputStream 
invoked(ZipFile thiz
, Object
... args
) 
 135                     ZipEntry entry 
= (ZipEntry
) args
[0]; 
 137                     RandomAccessFile raf 
= (RandomAccessFile
) ZipFile$mRaf
.get(thiz
); 
 139                         raf
.seek(ZipEntry$mLocalHeaderRelOffset
.getLong(entry
)); 
 142                         if ((raf
.readShort() & 0x0080) != 0) 
 143                             throw new ZipException("bug #9695860 [" + thiz
.getName() + "]"); 
 147                         int length 
= Short
.reverseBytes(raf
.readShort()) & 0xffff; 
 148                         if (length 
!= ZipEntry$nameLen
.getInt(entry
)) 
 149                             throw new ZipException("bug #9950697 [" + thiz
.getName() + "]"); 
 151                         if ((raf
.readShort() & 0x0080) != 0) 
 152                             throw new ZipException("bug #9695860 [" + thiz
.getName() + "]"); 
 155                     return invoke(thiz
, args
); 
 161     private static void fixZipFile$
readCentralDir() { 
 162         final Field ZipFile$entries 
= scanField(ZipFile
.class, "mEntries", "entries"); 
 163         if (ZipFile$entries 
== null) 
 165         ZipFile$entries
.setAccessible(true); 
 167         final Method ZipFile$readCentralDir 
= findMethod(ZipFile
.class, "readCentralDir"); 
 168         if (ZipFile$readCentralDir 
== null) 
 171         MS
.hookMethod(ZipFile
.class, ZipFile$readCentralDir
, 
 172             new MS
.MethodAlteration
<ZipFile
, Void
>() { 
 173                 public Void 
invoked(ZipFile thiz
, Object
... args
) 
 176                     ZipFile$entries
.set(thiz
, new LinkedHashMap
<String
, ZipEntry
>() { 
 177                         public ZipEntry 
put(String key
, ZipEntry value
) { 
 178                             if (super.put(key
, value
) != null) 
 179                                 throw new WrongException(new ZipException("bug #8219321 [" + key 
+ "]")); 
 185                         return invoke(thiz
, args
); 
 186                     } catch (WrongException wrong
) { 
 187                         throw wrong
.getCause(); 
 194     public static void initialize() { 
 196         fixZipFile$
getInputStream(); 
 197         fixZipFile$
readCentralDir();