commit
						02e5b3e81e
					
				| @ -0,0 +1,102 @@ | ||||
| package me.ag2s.base; | ||||
| 
 | ||||
| import static me.ag2s.base.ThrowableUtils.rethrowAsIOException; | ||||
| 
 | ||||
| import android.os.ParcelFileDescriptor; | ||||
| import android.system.ErrnoException; | ||||
| import android.system.OsConstants; | ||||
| 
 | ||||
| import java.io.EOFException; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| /** | ||||
|  * 读取ParcelFileDescriptor的工具类 | ||||
|  */ | ||||
| @SuppressWarnings("unused") | ||||
| public final class PfdHelper { | ||||
| 
 | ||||
|     /** | ||||
|      * 读取基本类型的buffer | ||||
|      */ | ||||
|     private static final byte[] readBuffer = new byte[8]; | ||||
| 
 | ||||
|     public static void seek(ParcelFileDescriptor pfd, long pos) throws IOException { | ||||
|         try { | ||||
|             android.system.Os.lseek(pfd.getFileDescriptor(), pos, OsConstants.SEEK_SET); | ||||
|         } catch (ErrnoException e) { | ||||
|             throw rethrowAsIOException(e); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public static long getFilePointer(ParcelFileDescriptor pfd) throws IOException { | ||||
|         try { | ||||
|             return android.system.Os.lseek(pfd.getFileDescriptor(), 0, OsConstants.SEEK_CUR); | ||||
|         } catch (ErrnoException e) { | ||||
|             throw rethrowAsIOException(e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static long length(ParcelFileDescriptor pfd) throws IOException { | ||||
|         try { | ||||
|             return android.system.Os.lseek(pfd.getFileDescriptor(), 0, OsConstants.SEEK_END); | ||||
|         } catch (ErrnoException e) { | ||||
|             throw rethrowAsIOException(e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static int readBytes(ParcelFileDescriptor pfd, byte[] b, int off, int len) throws IOException { | ||||
|         try { | ||||
|             return android.system.Os.read(pfd.getFileDescriptor(), b, off, len); | ||||
|         } catch (ErrnoException e) { | ||||
|             throw rethrowAsIOException(e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static int read(ParcelFileDescriptor pfd) throws IOException { | ||||
|         return (read(pfd, readBuffer, 0, 1) != -1) ? readBuffer[0] & 0xff : -1; | ||||
|     } | ||||
| 
 | ||||
|     public static int read(ParcelFileDescriptor pfd, byte[] b, int off, int len) throws IOException { | ||||
|         return readBytes(pfd, b, off, len); | ||||
|     } | ||||
| 
 | ||||
|     public static int read(ParcelFileDescriptor pfd, byte[] b) throws IOException { | ||||
|         return readBytes(pfd, b, 0, b.length); | ||||
|     } | ||||
| 
 | ||||
|     public static void readFully(ParcelFileDescriptor pfd, byte[] b) throws IOException { | ||||
|         readFully(pfd, b, 0, b.length); | ||||
|     } | ||||
| 
 | ||||
|     public static void readFully(ParcelFileDescriptor pfd, byte[] b, int off, int len) throws IOException { | ||||
|         int n = 0; | ||||
|         do { | ||||
|             int count = read(pfd, b, off + n, len - n); | ||||
|             if (count < 0) | ||||
|                 throw new EOFException(); | ||||
|             n += count; | ||||
|         } while (n < len); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public static int skipBytes(ParcelFileDescriptor pfd, int n) throws IOException { | ||||
|         long pos; | ||||
|         long len; | ||||
|         long newpos; | ||||
| 
 | ||||
|         if (n <= 0) { | ||||
|             return 0; | ||||
|         } | ||||
|         pos = getFilePointer(pfd); | ||||
|         len = length(pfd); | ||||
|         newpos = pos + n; | ||||
|         if (newpos > len) { | ||||
|             newpos = len; | ||||
|         } | ||||
|         seek(pfd, newpos); | ||||
| 
 | ||||
|         /* return the actual number of bytes skipped */ | ||||
|         return (int) (newpos - pos); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,16 @@ | ||||
| package me.ag2s.base; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| public class ThrowableUtils { | ||||
| 
 | ||||
| 
 | ||||
|     public static @NonNull | ||||
|     IOException rethrowAsIOException(Throwable throwable) throws IOException { | ||||
|         IOException newException = new IOException(throwable.getMessage()); | ||||
|         newException.initCause(throwable); | ||||
|         throw newException; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,355 @@ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| package me.ag2s.epublib.util.zip; | ||||
| 
 | ||||
| import java.util.Calendar; | ||||
| import java.util.Date; | ||||
| import java.util.zip.ZipOutputStream; | ||||
| 
 | ||||
| /** | ||||
|  * This class represents a member of a zip archive.  ZipFile and | ||||
|  * ZipInputStream will give you instances of this class as information | ||||
|  * about the members in an archive.  On the other hand ZipOutputStream | ||||
|  * needs an instance of this class to create a new member. | ||||
|  * | ||||
|  * @author Jochen Hoenicke | ||||
|  */ | ||||
| public class AndroidZipEntry implements ZipConstants, Cloneable { | ||||
|   private static final int KNOWN_SIZE = 1; | ||||
|   private static final int KNOWN_CSIZE = 2; | ||||
|   private static final int KNOWN_CRC = 4; | ||||
|   private static final int KNOWN_TIME = 8; | ||||
| 
 | ||||
|   private static Calendar cal; | ||||
| 
 | ||||
|   private final String name; | ||||
|   private int size; | ||||
|   private int compressedSize; | ||||
|   private int crc; | ||||
|   private int dostime; | ||||
|   private short known = 0; | ||||
|   private short method = -1; | ||||
|   private byte[] extra = null; | ||||
|   private String comment = null; | ||||
| 
 | ||||
|   int flags;              /* used by ZipOutputStream */ | ||||
|   int offset;             /* used by ZipFile and ZipOutputStream */ | ||||
| 
 | ||||
| 
 | ||||
|   /** | ||||
|    * Compression method.  This method doesn't compress at all. | ||||
|    */ | ||||
|   public final static int STORED = 0; | ||||
|   /** | ||||
|    * Compression method.  This method uses the Deflater. | ||||
|    */ | ||||
|   public final static int DEFLATED = 8; | ||||
| 
 | ||||
|   /** | ||||
|    * Creates a zip entry with the given name. | ||||
|    * | ||||
|    * @param name the name. May include directory components separated | ||||
|    *             by '/'. | ||||
|    * @throws NullPointerException     when name is null. | ||||
|    * @throws IllegalArgumentException when name is bigger then 65535 chars. | ||||
|    */ | ||||
|   public AndroidZipEntry(String name) { | ||||
|     int length = name.length(); | ||||
|     if (length > 65535) | ||||
|       throw new IllegalArgumentException("name length is " + length); | ||||
|     this.name = name; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Creates a copy of the given zip entry. | ||||
|    * | ||||
|    * @param e the entry to copy. | ||||
|    */ | ||||
|   public AndroidZipEntry(AndroidZipEntry e) { | ||||
|     name = e.name; | ||||
|     known = e.known; | ||||
|     size = e.size; | ||||
|     compressedSize = e.compressedSize; | ||||
|     crc = e.crc; | ||||
|     dostime = e.dostime; | ||||
|     method = e.method; | ||||
|     extra = e.extra; | ||||
|     comment = e.comment; | ||||
|   } | ||||
| 
 | ||||
|   final void setDOSTime(int dostime) { | ||||
|     this.dostime = dostime; | ||||
|     known |= KNOWN_TIME; | ||||
|   } | ||||
| 
 | ||||
|   final int getDOSTime() { | ||||
|     if ((known & KNOWN_TIME) == 0) | ||||
|       return 0; | ||||
|     else | ||||
|       return dostime; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Creates a copy of this zip entry. | ||||
|    */ | ||||
|   /** | ||||
|    * Clones the entry. | ||||
|    */ | ||||
|   public Object clone() { | ||||
|     try { | ||||
|       // The JCL says that the `extra' field is also copied.
 | ||||
|       AndroidZipEntry clone = (AndroidZipEntry) super.clone(); | ||||
|       if (extra != null) | ||||
|         clone.extra = (byte[]) extra.clone(); | ||||
|       return clone; | ||||
|     } catch (CloneNotSupportedException ex) { | ||||
|       throw new InternalError(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns the entry name.  The path components in the entry are | ||||
|    * always separated by slashes ('/'). | ||||
|    */ | ||||
|   public String getName() { | ||||
|     return name; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Sets the time of last modification of the entry. | ||||
|    * | ||||
|    * @time the time of last modification of the entry. | ||||
|    */ | ||||
|   public void setTime(long time) { | ||||
|     Calendar cal = getCalendar(); | ||||
|     synchronized (cal) { | ||||
|       cal.setTime(new Date(time * 1000L)); | ||||
|       dostime = (cal.get(Calendar.YEAR) - 1980 & 0x7f) << 25 | ||||
|               | (cal.get(Calendar.MONTH) + 1) << 21 | ||||
|               | (cal.get(Calendar.DAY_OF_MONTH)) << 16 | ||||
|               | (cal.get(Calendar.HOUR_OF_DAY)) << 11 | ||||
|               | (cal.get(Calendar.MINUTE)) << 5 | ||||
|               | (cal.get(Calendar.SECOND)) >> 1; | ||||
|     } | ||||
|     dostime = (int) (dostime / 1000L); | ||||
|     this.known |= KNOWN_TIME; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Gets the time of last modification of the entry. | ||||
|    * | ||||
|    * @return the time of last modification of the entry, or -1 if unknown. | ||||
|    */ | ||||
|   public long getTime() { | ||||
|     if ((known & KNOWN_TIME) == 0) | ||||
|       return -1; | ||||
| 
 | ||||
|     int sec = 2 * (dostime & 0x1f); | ||||
|     int min = (dostime >> 5) & 0x3f; | ||||
|     int hrs = (dostime >> 11) & 0x1f; | ||||
|     int day = (dostime >> 16) & 0x1f; | ||||
|     int mon = ((dostime >> 21) & 0xf) - 1; | ||||
|     int year = ((dostime >> 25) & 0x7f) + 1980; /* since 1900 */ | ||||
| 
 | ||||
|     try { | ||||
|       cal = getCalendar(); | ||||
|       synchronized (cal) { | ||||
|         cal.set(year, mon, day, hrs, min, sec); | ||||
|         return cal.getTime().getTime(); | ||||
|       } | ||||
|     } catch (RuntimeException ex) { | ||||
|       /* Ignore illegal time stamp */ | ||||
|       known &= ~KNOWN_TIME; | ||||
|       return -1; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private static synchronized Calendar getCalendar() { | ||||
|     if (cal == null) | ||||
|       cal = Calendar.getInstance(); | ||||
| 
 | ||||
|     return cal; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Sets the size of the uncompressed data. | ||||
|    * | ||||
|    * @throws IllegalArgumentException if size is not in 0..0xffffffffL | ||||
|    */ | ||||
|   public void setSize(long size) { | ||||
|     if ((size & 0xffffffff00000000L) != 0) | ||||
|       throw new IllegalArgumentException(); | ||||
|     this.size = (int) size; | ||||
|     this.known |= KNOWN_SIZE; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Gets the size of the uncompressed data. | ||||
|    * | ||||
|    * @return the size or -1 if unknown. | ||||
|    */ | ||||
|   public long getSize() { | ||||
|     return (known & KNOWN_SIZE) != 0 ? size & 0xffffffffL : -1L; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Sets the size of the compressed data. | ||||
|    * | ||||
|    * @throws IllegalArgumentException if size is not in 0..0xffffffffL | ||||
|    */ | ||||
|   public void setCompressedSize(long csize) { | ||||
|     if ((csize & 0xffffffff00000000L) != 0) | ||||
|       throw new IllegalArgumentException(); | ||||
|     this.compressedSize = (int) csize; | ||||
|     this.known |= KNOWN_CSIZE; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Gets the size of the compressed data. | ||||
|    * | ||||
|    * @return the size or -1 if unknown. | ||||
|    */ | ||||
|   public long getCompressedSize() { | ||||
|     return (known & KNOWN_CSIZE) != 0 ? compressedSize & 0xffffffffL : -1L; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Sets the crc of the uncompressed data. | ||||
|    * | ||||
|    * @throws IllegalArgumentException if crc is not in 0..0xffffffffL | ||||
|    */ | ||||
|   public void setCrc(long crc) { | ||||
|     if ((crc & 0xffffffff00000000L) != 0) | ||||
|       throw new IllegalArgumentException(); | ||||
|     this.crc = (int) crc; | ||||
|     this.known |= KNOWN_CRC; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Gets the crc of the uncompressed data. | ||||
|    * | ||||
|    * @return the crc or -1 if unknown. | ||||
|    */ | ||||
|   public long getCrc() { | ||||
|     return (known & KNOWN_CRC) != 0 ? crc & 0xffffffffL : -1L; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Sets the compression method.  Only DEFLATED and STORED are | ||||
|    * supported. | ||||
|    * | ||||
|    * @throws IllegalArgumentException if method is not supported. | ||||
|    * @see ZipOutputStream#DEFLATED | ||||
|    * @see ZipOutputStream#STORED | ||||
|    */ | ||||
|   public void setMethod(int method) { | ||||
|     if (method != ZipOutputStream.STORED | ||||
|             && method != ZipOutputStream.DEFLATED) | ||||
|       throw new IllegalArgumentException(); | ||||
|     this.method = (short) method; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Gets the compression method. | ||||
|    * | ||||
|    * @return the compression method or -1 if unknown. | ||||
|    */ | ||||
|   public int getMethod() { | ||||
|     return method; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Sets the extra data. | ||||
|    * | ||||
|    * @throws IllegalArgumentException if extra is longer than 0xffff bytes. | ||||
|    */ | ||||
|   public void setExtra(byte[] extra) { | ||||
|     if (extra == null) { | ||||
|       this.extra = null; | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     if (extra.length > 0xffff) | ||||
|       throw new IllegalArgumentException(); | ||||
|     this.extra = extra; | ||||
|     try { | ||||
|       int pos = 0; | ||||
|       while (pos < extra.length) { | ||||
|         int sig = (extra[pos++] & 0xff) | ||||
|                 | (extra[pos++] & 0xff) << 8; | ||||
|         int len = (extra[pos++] & 0xff) | ||||
|                 | (extra[pos++] & 0xff) << 8; | ||||
|         if (sig == 0x5455) { | ||||
|           /* extended time stamp */ | ||||
|           int flags = extra[pos]; | ||||
|           if ((flags & 1) != 0) { | ||||
|             long time = ((extra[pos + 1] & 0xff) | ||||
|                     | (extra[pos + 2] & 0xff) << 8 | ||||
|                     | (extra[pos + 3] & 0xff) << 16 | ||||
|                     | (extra[pos + 4] & 0xff) << 24); | ||||
|             setTime(time); | ||||
|           } | ||||
|         } | ||||
|         pos += len; | ||||
|       } | ||||
|     } catch (ArrayIndexOutOfBoundsException ex) { | ||||
|       /* be lenient */ | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Gets the extra data. | ||||
|    * | ||||
|    * @return the extra data or null if not set. | ||||
|    */ | ||||
|   public byte[] getExtra() { | ||||
|     return extra; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Sets the entry comment. | ||||
|    * | ||||
|    * @throws IllegalArgumentException if comment is longer than 0xffff. | ||||
|    */ | ||||
|   public void setComment(String comment) { | ||||
|     if (comment != null && comment.length() > 0xffff) | ||||
|       throw new IllegalArgumentException(); | ||||
|     this.comment = comment; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Gets the comment. | ||||
|    * | ||||
|    * @return the comment or null if not set. | ||||
|    */ | ||||
|   public String getComment() { | ||||
|     return comment; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Gets true, if the entry is a directory.  This is solely | ||||
|    * determined by the name, a trailing slash '/' marks a directory. | ||||
|    */ | ||||
|   public boolean isDirectory() { | ||||
|     int nlen = name.length(); | ||||
|     return nlen > 0 && name.charAt(nlen - 1) == '/'; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Gets the string representation of this AndroidZipEntry.  This is just | ||||
|    * the name as returned by getName(). | ||||
|    */ | ||||
|   public String toString() { | ||||
|     return name; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Gets the hashCode of this AndroidZipEntry.  This is just the hashCode | ||||
|    * of the name.  Note that the equals method isn't changed, though. | ||||
|    */ | ||||
|   public int hashCode() { | ||||
|     return name.hashCode(); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,490 @@ | ||||
| 
 | ||||
| 
 | ||||
| package me.ag2s.epublib.util.zip; | ||||
| 
 | ||||
| import static me.ag2s.base.PfdHelper.seek; | ||||
| 
 | ||||
| import android.os.ParcelFileDescriptor; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| import java.io.BufferedInputStream; | ||||
| import java.io.DataInput; | ||||
| import java.io.EOFException; | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.util.Enumeration; | ||||
| import java.util.HashMap; | ||||
| import java.util.Iterator; | ||||
| import java.util.NoSuchElementException; | ||||
| import java.util.zip.Inflater; | ||||
| import java.util.zip.InflaterInputStream; | ||||
| import java.util.zip.ZipOutputStream; | ||||
| 
 | ||||
| import me.ag2s.base.PfdHelper; | ||||
| 
 | ||||
| /** | ||||
|  * This class represents a Zip archive.  You can ask for the contained | ||||
|  * entries, or get an input stream for a file entry.  The entry is | ||||
|  * automatically decompressed. | ||||
|  * <p> | ||||
|  * This class is thread safe:  You can open input streams for arbitrary | ||||
|  * entries in different threads. | ||||
|  * | ||||
|  * @author Jochen Hoenicke | ||||
|  * @author Artur Biesiadowski | ||||
|  */ | ||||
| public class AndroidZipFile implements ZipConstants { | ||||
| 
 | ||||
|     /** | ||||
|      * Mode flag to open a zip file for reading. | ||||
|      */ | ||||
|     public static final int OPEN_READ = 0x1; | ||||
| 
 | ||||
|     /** | ||||
|      * Mode flag to delete a zip file after reading. | ||||
|      */ | ||||
|     public static final int OPEN_DELETE = 0x4; | ||||
| 
 | ||||
|     // Name of this zip file.
 | ||||
|     private final String name; | ||||
| 
 | ||||
|     // File from which zip entries are read.
 | ||||
|     //private final RandomAccessFile raf;
 | ||||
| 
 | ||||
|     private final ParcelFileDescriptor pfd; | ||||
| 
 | ||||
|     // The entries of this zip file when initialized and not yet closed.
 | ||||
|     private HashMap<String, AndroidZipEntry> entries; | ||||
| 
 | ||||
|     private boolean closed = false; | ||||
| 
 | ||||
|     /** | ||||
|      * Opens a Zip file with the given name for reading. | ||||
|      * | ||||
|      * @throws IOException  if a i/o error occured. | ||||
|      * @throws ZipException if the file doesn't contain a valid zip | ||||
|      *                      archive. | ||||
|      */ | ||||
|     public AndroidZipFile(@NonNull ParcelFileDescriptor pfd, String name) throws ZipException, IOException { | ||||
|         this.pfd = pfd; | ||||
|         this.name = name; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Opens a Zip file reading the given File. | ||||
|      * | ||||
|      * @throws IOException  if a i/o error occured. | ||||
|      * @throws ZipException if the file doesn't contain a valid zip | ||||
|      *                      archive. | ||||
|      */ | ||||
|     public AndroidZipFile(File file) throws ZipException, IOException { | ||||
|         this.pfd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); | ||||
|         this.name = file.getPath(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Opens a Zip file reading the given File in the given mode. | ||||
|      * <p> | ||||
|      * If the OPEN_DELETE mode is specified, the zip file will be deleted at | ||||
|      * some time moment after it is opened. It will be deleted before the zip | ||||
|      * file is closed or the Virtual Machine exits. | ||||
|      * <p> | ||||
|      * The contents of the zip file will be accessible until it is closed. | ||||
|      * <p> | ||||
|      * The OPEN_DELETE mode is currently unimplemented in this library | ||||
|      * | ||||
|      * @param mode Must be one of OPEN_READ or OPEN_READ | OPEN_DELETE | ||||
|      * @throws IOException  if a i/o error occured. | ||||
|      * @throws ZipException if the file doesn't contain a valid zip | ||||
|      *                      archive. | ||||
|      * @since JDK1.3 | ||||
|      */ | ||||
| //    public AndroidZipFile(File file, int mode) throws ZipException, IOException {
 | ||||
| //        if ((mode & OPEN_DELETE) != 0) {
 | ||||
| //            throw new IllegalArgumentException
 | ||||
| //                    ("OPEN_DELETE mode not supported yet in net.sf.jazzlib.AndroidZipFile");
 | ||||
| //        }
 | ||||
| //        this.raf = new RandomAccessFile(file, "r");
 | ||||
| //        this.name = file.getPath();
 | ||||
| //    }
 | ||||
| 
 | ||||
|     /** | ||||
|      * Read an unsigned short in little endian byte order from the given | ||||
|      * DataInput stream using the given byte buffer. | ||||
|      * | ||||
|      * @param di DataInput stream to read from. | ||||
|      * @param b  the byte buffer to read in (must be at least 2 bytes long). | ||||
|      * @return The value read. | ||||
|      * @throws IOException  if a i/o error occured. | ||||
|      * @throws EOFException if the file ends prematurely | ||||
|      */ | ||||
|     private final int readLeShort(DataInput di, byte[] b) throws IOException { | ||||
|         di.readFully(b, 0, 2); | ||||
|         return (b[0] & 0xff) | (b[1] & 0xff) << 8; | ||||
|     } | ||||
| 
 | ||||
|     private final int readLeShort(ParcelFileDescriptor pfd, byte[] b) throws IOException { | ||||
|         PfdHelper.readFully(pfd, b, 0, 2);//di.readFully(b, 0, 2);
 | ||||
|         return (b[0] & 0xff) | (b[1] & 0xff) << 8; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Read an int in little endian byte order from the given | ||||
|      * DataInput stream using the given byte buffer. | ||||
|      * | ||||
|      * @param di DataInput stream to read from. | ||||
|      * @param b  the byte buffer to read in (must be at least 4 bytes long). | ||||
|      * @return The value read. | ||||
|      * @throws IOException  if a i/o error occured. | ||||
|      * @throws EOFException if the file ends prematurely | ||||
|      */ | ||||
|     private final int readLeInt(DataInput di, byte[] b) throws IOException { | ||||
|         di.readFully(b, 0, 4); | ||||
|         return ((b[0] & 0xff) | (b[1] & 0xff) << 8) | ||||
|                 | ((b[2] & 0xff) | (b[3] & 0xff) << 8) << 16; | ||||
|     } | ||||
| 
 | ||||
|     private final int readLeInt(ParcelFileDescriptor pfd, byte[] b) throws IOException { | ||||
|         PfdHelper.readFully(pfd, b, 0, 4);//di.readFully(b, 0, 4);
 | ||||
|         return ((b[0] & 0xff) | (b[1] & 0xff) << 8) | ||||
|                 | ((b[2] & 0xff) | (b[3] & 0xff) << 8) << 16; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * Read an unsigned short in little endian byte order from the given | ||||
|      * byte buffer at the given offset. | ||||
|      * | ||||
|      * @param b   the byte array to read from. | ||||
|      * @param off the offset to read from. | ||||
|      * @return The value read. | ||||
|      */ | ||||
|     private final int readLeShort(byte[] b, int off) { | ||||
|         return (b[off] & 0xff) | (b[off + 1] & 0xff) << 8; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Read an int in little endian byte order from the given | ||||
|      * byte buffer at the given offset. | ||||
|      * | ||||
|      * @param b   the byte array to read from. | ||||
|      * @param off the offset to read from. | ||||
|      * @return The value read. | ||||
|      */ | ||||
|     private final int readLeInt(byte[] b, int off) { | ||||
|         return ((b[off] & 0xff) | (b[off + 1] & 0xff) << 8) | ||||
|                 | ((b[off + 2] & 0xff) | (b[off + 3] & 0xff) << 8) << 16; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * Read the central directory of a zip file and fill the entries | ||||
|      * array.  This is called exactly once when first needed. It is called | ||||
|      * while holding the lock on <code>raf</code>. | ||||
|      * | ||||
|      * @throws IOException  if a i/o error occured. | ||||
|      * @throws ZipException if the central directory is malformed | ||||
|      */ | ||||
|     private void readEntries() throws ZipException, IOException { | ||||
|         /* Search for the End Of Central Directory.  When a zip comment is | ||||
|          * present the directory may start earlier. | ||||
|          * FIXME: This searches the whole file in a very slow manner if the | ||||
|          * file isn't a zip file. | ||||
|          */ | ||||
|         //long pos = raf.length() - ENDHDR;
 | ||||
|         long pos = PfdHelper.length(pfd) - ENDHDR; | ||||
|         byte[] ebs = new byte[CENHDR]; | ||||
| 
 | ||||
|         do { | ||||
|             if (pos < 0) | ||||
|                 throw new ZipException | ||||
|                         ("central directory not found, probably not a zip file: " + name); | ||||
|             //raf.seek(pos--);
 | ||||
|             seek(pfd, pos--); | ||||
|         } | ||||
|         //while (readLeInt(raf, ebs) != ENDSIG);
 | ||||
|         while (readLeInt(pfd, ebs) != ENDSIG); | ||||
| 
 | ||||
|         if (PfdHelper.skipBytes(pfd, ENDTOT - ENDNRD) != ENDTOT - ENDNRD) | ||||
|             throw new EOFException(name); | ||||
|         //int count = readLeShort(raf, ebs);
 | ||||
|         int count = readLeShort(pfd, ebs); | ||||
|         if (PfdHelper.skipBytes(pfd, ENDOFF - ENDSIZ) != ENDOFF - ENDSIZ) | ||||
|             throw new EOFException(name); | ||||
|         int centralOffset = readLeInt(pfd, ebs); | ||||
| 
 | ||||
|         entries = new HashMap<>(count + count / 2); | ||||
|         //raf.seek(centralOffset);
 | ||||
|         seek(pfd, centralOffset); | ||||
| 
 | ||||
|         byte[] buffer = new byte[16]; | ||||
|         for (int i = 0; i < count; i++) { | ||||
|             //raf.readFully(ebs);
 | ||||
|             PfdHelper.readFully(pfd, ebs); | ||||
|             if (readLeInt(ebs, 0) != CENSIG) | ||||
|                 throw new ZipException("Wrong Central Directory signature: " + name); | ||||
| 
 | ||||
|             int method = readLeShort(ebs, CENHOW); | ||||
|             int dostime = readLeInt(ebs, CENTIM); | ||||
|             int crc = readLeInt(ebs, CENCRC); | ||||
|             int csize = readLeInt(ebs, CENSIZ); | ||||
|             int size = readLeInt(ebs, CENLEN); | ||||
|             int nameLen = readLeShort(ebs, CENNAM); | ||||
|             int extraLen = readLeShort(ebs, CENEXT); | ||||
|             int commentLen = readLeShort(ebs, CENCOM); | ||||
| 
 | ||||
|             int offset = readLeInt(ebs, CENOFF); | ||||
| 
 | ||||
|             int needBuffer = Math.max(nameLen, commentLen); | ||||
|             if (buffer.length < needBuffer) | ||||
|                 buffer = new byte[needBuffer]; | ||||
| 
 | ||||
|             PfdHelper.readFully(pfd, buffer, 0, nameLen); | ||||
|             String name = new String(buffer, 0, 0, nameLen); | ||||
| 
 | ||||
|             AndroidZipEntry entry = new AndroidZipEntry(name); | ||||
|             entry.setMethod(method); | ||||
|             entry.setCrc(crc & 0xffffffffL); | ||||
|             entry.setSize(size & 0xffffffffL); | ||||
|             entry.setCompressedSize(csize & 0xffffffffL); | ||||
|             entry.setTime(dostime); | ||||
|             if (extraLen > 0) { | ||||
|                 byte[] extra = new byte[extraLen]; | ||||
|                 PfdHelper.readFully(pfd, extra); | ||||
|                 entry.setExtra(extra); | ||||
|             } | ||||
|             if (commentLen > 0) { | ||||
|                 PfdHelper.readFully(pfd, buffer, 0, commentLen); | ||||
|                 entry.setComment(new String(buffer, 0, commentLen)); | ||||
|             } | ||||
|             entry.offset = offset; | ||||
|             //ZipEntryHelper.setOffset(entry,offset);
 | ||||
| 
 | ||||
|             //entry. = offset;
 | ||||
|             entries.put(name, entry); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Closes the AndroidZipFile.  This also closes all input streams given by | ||||
|      * this class.  After this is called, no further method should be | ||||
|      * called. | ||||
|      * | ||||
|      * @throws IOException if a i/o error occured. | ||||
|      */ | ||||
|     public void close() throws IOException { | ||||
|         synchronized (pfd) { | ||||
|             closed = true; | ||||
|             entries = null; | ||||
|             pfd.close(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Calls the <code>close()</code> method when this AndroidZipFile has not yet | ||||
|      * been explicitly closed. | ||||
|      */ | ||||
|     protected void finalize() throws IOException { | ||||
|         if (!closed && pfd != null) close(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns an enumeration of all Zip entries in this Zip file. | ||||
|      */ | ||||
|     public Enumeration<AndroidZipEntry> entries() { | ||||
|         try { | ||||
|             return new ZipEntryEnumeration(getEntries().values().iterator()); | ||||
|         } catch (IOException ioe) { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Checks that the AndroidZipFile is still open and reads entries when necessary. | ||||
|      * | ||||
|      * @throws IllegalStateException when the AndroidZipFile has already been closed. | ||||
|      * @throws java,                 IOEexception          when the entries could not be read. | ||||
|      */ | ||||
|     private HashMap<String, AndroidZipEntry> getEntries() throws IOException { | ||||
|         synchronized (pfd) { | ||||
|             if (closed) | ||||
|                 throw new IllegalStateException("AndroidZipFile has closed: " + name); | ||||
| 
 | ||||
|             if (entries == null) | ||||
|                 readEntries(); | ||||
| 
 | ||||
|             return entries; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Searches for a zip entry in this archive with the given name. | ||||
|      * | ||||
|      * @param name name. May contain directory components separated by | ||||
|      *             slashes ('/'). | ||||
|      * @return the zip entry, or null if no entry with that name exists. | ||||
|      */ | ||||
|     public AndroidZipEntry getEntry(String name) { | ||||
|         try { | ||||
|             HashMap<String, AndroidZipEntry> entries = getEntries(); | ||||
|             AndroidZipEntry entry = entries.get(name); | ||||
|             return entry != null ? (AndroidZipEntry) entry.clone() : null; | ||||
|         } catch (IOException ioe) { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     //access should be protected by synchronized(raf)
 | ||||
|     private final byte[] locBuf = new byte[LOCHDR]; | ||||
| 
 | ||||
|     /** | ||||
|      * Checks, if the local header of the entry at index i matches the | ||||
|      * central directory, and returns the offset to the data. | ||||
|      * | ||||
|      * @param entry to check. | ||||
|      * @return the start offset of the (compressed) data. | ||||
|      * @throws IOException  if a i/o error occured. | ||||
|      * @throws ZipException if the local header doesn't match the | ||||
|      *                      central directory header | ||||
|      */ | ||||
|     private long checkLocalHeader(AndroidZipEntry entry) throws IOException { | ||||
|         synchronized (pfd) { | ||||
|             seek(pfd, entry.offset); | ||||
|             PfdHelper.readFully(pfd, locBuf); | ||||
| 
 | ||||
|             if (readLeInt(locBuf, 0) != LOCSIG) | ||||
|                 throw new ZipException("Wrong Local header signature: " + name); | ||||
| 
 | ||||
|             if (entry.getMethod() != readLeShort(locBuf, LOCHOW)) | ||||
|                 throw new ZipException("Compression method mismatch: " + name); | ||||
| 
 | ||||
|             if (entry.getName().length() != readLeShort(locBuf, LOCNAM)) | ||||
|                 throw new ZipException("file name length mismatch: " + name); | ||||
| 
 | ||||
|             int extraLen = entry.getName().length() + readLeShort(locBuf, LOCEXT); | ||||
|             return entry.offset + LOCHDR + extraLen; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Creates an input stream reading the given zip entry as | ||||
|      * uncompressed data.  Normally zip entry should be an entry | ||||
|      * returned by getEntry() or entries(). | ||||
|      * | ||||
|      * @param entry the entry to create an InputStream for. | ||||
|      * @return the input stream. | ||||
|      * @throws IOException  if a i/o error occured. | ||||
|      * @throws ZipException if the Zip archive is malformed. | ||||
|      */ | ||||
|     public InputStream getInputStream(AndroidZipEntry entry) throws IOException { | ||||
|         HashMap<String, AndroidZipEntry> entries = getEntries(); | ||||
|         String name = entry.getName(); | ||||
|         AndroidZipEntry zipEntry = (AndroidZipEntry) entries.get(name); | ||||
|         if (zipEntry == null) | ||||
|             throw new NoSuchElementException(name); | ||||
| 
 | ||||
|         long start = checkLocalHeader((AndroidZipEntry) zipEntry); | ||||
|         int method = zipEntry.getMethod(); | ||||
|         InputStream is = new BufferedInputStream(new PartialInputStream | ||||
|                 (pfd, start, zipEntry.getCompressedSize())); | ||||
|         switch (method) { | ||||
|             case ZipOutputStream.STORED: | ||||
|                 return is; | ||||
|             case ZipOutputStream.DEFLATED: | ||||
|                 return new InflaterInputStream(is, new Inflater(true)); | ||||
|             default: | ||||
|                 throw new ZipException("Unknown compression method " + method); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the (path) name of this zip file. | ||||
|      */ | ||||
|     public String getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the number of entries in this zip file. | ||||
|      */ | ||||
|     public int size() { | ||||
|         try { | ||||
|             return getEntries().size(); | ||||
|         } catch (IOException ioe) { | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static class ZipEntryEnumeration implements Enumeration<AndroidZipEntry> { | ||||
|         private final Iterator<AndroidZipEntry> elements; | ||||
| 
 | ||||
|         public ZipEntryEnumeration(Iterator<AndroidZipEntry> elements) { | ||||
|             this.elements = elements; | ||||
|         } | ||||
| 
 | ||||
|         public boolean hasMoreElements() { | ||||
|             return elements.hasNext(); | ||||
|         } | ||||
| 
 | ||||
|         public AndroidZipEntry nextElement() { | ||||
|             /* We return a clone, just to be safe that the user doesn't | ||||
|              * change the entry. | ||||
|              */ | ||||
|             return (AndroidZipEntry) (elements.next()).clone(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static class PartialInputStream extends InputStream { | ||||
|         private final ParcelFileDescriptor pfd; | ||||
|         long filepos, end; | ||||
| 
 | ||||
|         public PartialInputStream(ParcelFileDescriptor pfd, long start, long len) { | ||||
|             this.pfd = pfd; | ||||
|             filepos = start; | ||||
|             end = start + len; | ||||
|         } | ||||
| 
 | ||||
|         public int available() { | ||||
|             long amount = end - filepos; | ||||
|             if (amount > Integer.MAX_VALUE) | ||||
|                 return Integer.MAX_VALUE; | ||||
|             return (int) amount; | ||||
|         } | ||||
| 
 | ||||
|         public int read() throws IOException { | ||||
|             if (filepos == end) | ||||
|                 return -1; | ||||
|             synchronized (pfd) { | ||||
|                 seek(pfd, filepos++); | ||||
|                 return PfdHelper.read(pfd); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public int read(byte[] b, int off, int len) throws IOException { | ||||
|             if (len > end - filepos) { | ||||
|                 len = (int) (end - filepos); | ||||
|                 if (len == 0) | ||||
|                     return -1; | ||||
|             } | ||||
|             synchronized (pfd) { | ||||
|                 seek(pfd, filepos); | ||||
|                 int count = PfdHelper.read(pfd, b, off, len); | ||||
|                 if (count > 0) | ||||
|                     filepos += len; | ||||
|                 return count; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public long skip(long amount) { | ||||
|             if (amount < 0) | ||||
|                 throw new IllegalArgumentException(); | ||||
|             if (amount > end - filepos) | ||||
|                 amount = end - filepos; | ||||
|             filepos += amount; | ||||
|             return amount; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,61 @@ | ||||
| 
 | ||||
| 
 | ||||
| package me.ag2s.epublib.util.zip; | ||||
| 
 | ||||
| interface ZipConstants { | ||||
|   /* The local file header */ | ||||
|   int LOCHDR = 30; | ||||
|   int LOCSIG = 'P' | ('K' << 8) | (3 << 16) | (4 << 24); | ||||
| 
 | ||||
|   int LOCVER = 4; | ||||
|   int LOCFLG = 6; | ||||
|   int LOCHOW = 8; | ||||
|   int LOCTIM = 10; | ||||
|   int LOCCRC = 14; | ||||
|   int LOCSIZ = 18; | ||||
|   int LOCLEN = 22; | ||||
|   int LOCNAM = 26; | ||||
|   int LOCEXT = 28; | ||||
| 
 | ||||
|   /* The Data descriptor */ | ||||
|   int EXTSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24); | ||||
|   int EXTHDR = 16; | ||||
| 
 | ||||
|   int EXTCRC = 4; | ||||
|   int EXTSIZ = 8; | ||||
|   int EXTLEN = 12; | ||||
| 
 | ||||
|   /* The central directory file header */ | ||||
|   int CENSIG = 'P' | ('K' << 8) | (1 << 16) | (2 << 24); | ||||
|   int CENHDR = 46; | ||||
| 
 | ||||
|   int CENVEM = 4; | ||||
|   int CENVER = 6; | ||||
|   int CENFLG = 8; | ||||
|   int CENHOW = 10; | ||||
|   int CENTIM = 12; | ||||
|   int CENCRC = 16; | ||||
|   int CENSIZ = 20; | ||||
|   int CENLEN = 24; | ||||
|   int CENNAM = 28; | ||||
|   int CENEXT = 30; | ||||
|   int CENCOM = 32; | ||||
|   int CENDSK = 34; | ||||
|   int CENATT = 36; | ||||
|   int CENATX = 38; | ||||
|   int CENOFF = 42; | ||||
| 
 | ||||
|   /* The entries in the end of central directory */ | ||||
|   int ENDSIG = 'P' | ('K' << 8) | (5 << 16) | (6 << 24); | ||||
|   int ENDHDR = 22; | ||||
| 
 | ||||
|   /* The following two fields are missing in SUN JDK */ | ||||
|   int ENDNRD = 4; | ||||
|   int ENDDCD = 6; | ||||
|   int ENDSUB = 8; | ||||
|   int ENDTOT = 10; | ||||
|   int ENDSIZ = 12; | ||||
|   int ENDOFF = 16; | ||||
|   int ENDCOM = 20; | ||||
| } | ||||
| 
 | ||||
| @ -0,0 +1,75 @@ | ||||
| package me.ag2s.epublib.util.zip; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| import java.util.zip.ZipEntry; | ||||
| 
 | ||||
| public class ZipEntryWrapper { | ||||
|     @NonNull | ||||
|     private final Object zipEntry; | ||||
| 
 | ||||
|     public void checkType() { | ||||
| 
 | ||||
|         if (zipEntry instanceof java.util.zip.ZipEntry || zipEntry instanceof AndroidZipEntry) { | ||||
|         } else { | ||||
|             throw new RuntimeException("使用了不支持的类"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public ZipEntryWrapper(@NonNull ZipEntry zipEntry) { | ||||
|         this.zipEntry = zipEntry; | ||||
|     } | ||||
| 
 | ||||
|     public ZipEntryWrapper(@NonNull AndroidZipEntry zipEntry) { | ||||
|         this.zipEntry = zipEntry; | ||||
|     } | ||||
| 
 | ||||
|     public ZipEntryWrapper(@NonNull Object element) { | ||||
| 
 | ||||
|         this.zipEntry = element; | ||||
|         checkType(); | ||||
|     } | ||||
| 
 | ||||
|     public boolean isDirectory() { | ||||
|         checkType(); | ||||
|         if (zipEntry instanceof ZipEntry) { | ||||
|             return ((ZipEntry) zipEntry).isDirectory(); | ||||
|         } | ||||
|         if (zipEntry instanceof AndroidZipEntry) { | ||||
|             return ((AndroidZipEntry) zipEntry).isDirectory(); | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     public ZipEntry getZipEntry() { | ||||
|         return (ZipEntry) zipEntry; | ||||
|     } | ||||
| 
 | ||||
|     public AndroidZipEntry getAndroidZipEntry() { | ||||
|         return (AndroidZipEntry) zipEntry; | ||||
|     } | ||||
| 
 | ||||
|     public String getName() { | ||||
|         checkType(); | ||||
|         if (zipEntry instanceof ZipEntry) { | ||||
|             return ((ZipEntry) zipEntry).getName(); | ||||
|         } | ||||
|         if (zipEntry instanceof AndroidZipEntry) { | ||||
|             return ((AndroidZipEntry) zipEntry).getName(); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     public long getSize() { | ||||
|         checkType(); | ||||
|         if (zipEntry instanceof ZipEntry) { | ||||
|             return ((ZipEntry) zipEntry).getSize(); | ||||
|         } | ||||
|         if (zipEntry instanceof AndroidZipEntry) { | ||||
|             return ((AndroidZipEntry) zipEntry).getSize(); | ||||
|         } | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,34 @@ | ||||
| 
 | ||||
| 
 | ||||
| package me.ag2s.epublib.util.zip; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| /** | ||||
|  * Thrown during the creation or input of a zip file. | ||||
|  * | ||||
|  * @author Jochen Hoenicke | ||||
|  * @author Per Bothner | ||||
|  * @status updated to 1.4 | ||||
|  */ | ||||
| public class ZipException extends IOException { | ||||
|     /** | ||||
|      * Compatible with JDK 1.0+. | ||||
|      */ | ||||
|     private static final long serialVersionUID = 8000196834066748623L; | ||||
| 
 | ||||
|     /** | ||||
|      * Create an exception without a message. | ||||
|      */ | ||||
|     public ZipException() { | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Create an exception with a message. | ||||
|      * | ||||
|      * @param msg the message | ||||
|      */ | ||||
|     public ZipException(String msg) { | ||||
|         super(msg); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,103 @@ | ||||
| package me.ag2s.epublib.util.zip; | ||||
| 
 | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.util.Enumeration; | ||||
| import java.util.zip.ZipFile; | ||||
| 
 | ||||
| /** | ||||
|  * 对ZipFile的包装 | ||||
|  */ | ||||
| 
 | ||||
| public class ZipFileWrapper { | ||||
|     @NonNull | ||||
|     private final Object zipFile; | ||||
| 
 | ||||
| 
 | ||||
|     public void checkType() { | ||||
|         if (zipFile instanceof java.util.zip.ZipFile || zipFile instanceof AndroidZipFile) { | ||||
|         } else { | ||||
|             throw new RuntimeException("使用了不支持的类"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public ZipFileWrapper(@NonNull ZipFile zipFile) { | ||||
|         this.zipFile = zipFile; | ||||
|         checkType(); | ||||
|     } | ||||
| 
 | ||||
|     public ZipFileWrapper(@NonNull AndroidZipFile zipFile) { | ||||
|         this.zipFile = zipFile; | ||||
|         checkType(); | ||||
|     } | ||||
| 
 | ||||
|     public String getName() { | ||||
|         checkType(); | ||||
|         if (zipFile instanceof java.util.zip.ZipFile) { | ||||
|             return ((ZipFile) zipFile).getName(); | ||||
|         } else if (zipFile instanceof AndroidZipFile) { | ||||
|             return ((AndroidZipFile) zipFile).getName(); | ||||
|         } else { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public String getComment() { | ||||
|         checkType(); | ||||
|         if (zipFile instanceof java.util.zip.ZipFile) { | ||||
|             return ((ZipFile) zipFile).getComment(); | ||||
|         } else if (zipFile instanceof AndroidZipFile) { | ||||
|             return ((AndroidZipFile) zipFile).getName(); | ||||
|         } else { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public ZipEntryWrapper getEntry(String name) { | ||||
|         checkType(); | ||||
|         if (zipFile instanceof java.util.zip.ZipFile) { | ||||
|             return new ZipEntryWrapper(((ZipFile) zipFile).getEntry(name)); | ||||
|         } else if (zipFile instanceof AndroidZipFile) { | ||||
|             return new ZipEntryWrapper(((AndroidZipFile) zipFile).getEntry(name)); | ||||
|         } else { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public Enumeration entries() { | ||||
|         checkType(); | ||||
|         if (zipFile instanceof java.util.zip.ZipFile) { | ||||
|             return ((ZipFile) zipFile).entries(); | ||||
| 
 | ||||
|         } else if (zipFile instanceof AndroidZipFile) { | ||||
|             return ((AndroidZipFile) zipFile).entries(); | ||||
|         } else { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public InputStream getInputStream(ZipEntryWrapper entry) throws IOException { | ||||
|         checkType(); | ||||
|         if (zipFile instanceof java.util.zip.ZipFile) { | ||||
|             return ((ZipFile) zipFile).getInputStream(entry.getZipEntry()); | ||||
|         } else if (zipFile instanceof AndroidZipFile) { | ||||
|             return ((AndroidZipFile) zipFile).getInputStream(entry.getAndroidZipEntry()); | ||||
|         } else { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void close() throws IOException { | ||||
|         checkType(); | ||||
|         if (zipFile instanceof java.util.zip.ZipFile) { | ||||
|             ((ZipFile) zipFile).close(); | ||||
|         } else if (zipFile instanceof AndroidZipFile) { | ||||
|             ((AndroidZipFile) zipFile).close(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue