rt/emul/zip/src/main/java/org/apidesign/bck2brwsr/emul/zip/FastJar.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sun, 11 May 2014 08:10:28 +0200
branchclosure
changeset 1555 71e68f7ed23f
parent 1549 3f4c143ff8f0
child 1569 9eb0eb434c67
permissions -rw-r--r--
Use as little of Java APIs as possible
     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
     5  *
     6  * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
     7  * Other names may be trademarks of their respective owners.
     8  *
     9  * The contents of this file are subject to the terms of either the GNU
    10  * General Public License Version 2 only ("GPL") or the Common
    11  * Development and Distribution License("CDDL") (collectively, the
    12  * "License"). You may not use this file except in compliance with the
    13  * License. You can obtain a copy of the License at
    14  * http://www.netbeans.org/cddl-gplv2.html
    15  * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    16  * specific language governing permissions and limitations under the
    17  * License.  When distributing the software, include this License Header
    18  * Notice in each file and include the License file at
    19  * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    20  * particular file as subject to the "Classpath" exception as provided
    21  * by Oracle in the GPL Version 2 section of the License file that
    22  * accompanied this code. If applicable, add the following below the
    23  * License Header, with the fields enclosed by brackets [] replaced by
    24  * your own identifying information:
    25  * "Portions Copyrighted [year] [name of copyright owner]"
    26  *
    27  * Contributor(s):
    28  *
    29  * Portions Copyrighted 2007 Sun Microsystems, Inc.
    30  */
    31 package org.apidesign.bck2brwsr.emul.zip;
    32 
    33 import java.io.ByteArrayInputStream;
    34 import java.io.IOException;
    35 import java.io.InputStream;
    36 import java.lang.reflect.Method;
    37 import java.util.zip.ZipEntry;
    38 import java.util.zip.ZipInputStream;
    39 import org.apidesign.bck2brwsr.core.JavaScriptBody;
    40 
    41 /**
    42  *
    43  * @author Tomas Zezula
    44  */
    45 public final class FastJar {
    46     private final byte[] arr;
    47 
    48     public FastJar(byte[] arr) {
    49         this.arr = arr;
    50     }
    51     
    52     
    53     private static final int GIVE_UP = 1<<16;
    54 
    55     public static final  class Entry {
    56         
    57         public final String name;
    58         final long offset;
    59         private final long dosTime;
    60         
    61         Entry (String name, long offset, long time) {
    62             assert name != null;
    63             this.name = name;
    64             this.offset = offset;
    65             this.dosTime = time;
    66         }        
    67 /*        
    68         public long getTime () {
    69             Date d = new Date((int)(((dosTime >> 25) & 0x7f) + 80),
    70                     (int)(((dosTime >> 21) & 0x0f) - 1),
    71                     (int)((dosTime >> 16) & 0x1f),
    72                     (int)((dosTime >> 11) & 0x1f),
    73                     (int)((dosTime >> 5) & 0x3f),
    74                     (int)((dosTime << 1) & 0x3e));
    75             return d.getTime();
    76         }
    77         */
    78     }
    79     
    80     public InputStream getInputStream (final Entry e) throws IOException {
    81         return getInputStream(arr, e.offset);
    82     }
    83     
    84     private static InputStream getInputStream (byte[] arr, final long offset) throws IOException {
    85         ByteArrayInputStream is = new ByteArrayInputStream(arr);
    86         is.skip(offset);
    87         ZipInputStream in = new ZipInputStream (is);
    88         ZipEntry e = in.getNextEntry();
    89         if (e != null && e.getCrc() == 0L && e.getMethod() == ZipEntry.STORED) {
    90             int cp = arr.length - is.available();
    91             return new ByteArrayInputStream(arr, cp, (int)e.getSize());
    92         }
    93         return in;
    94     }
    95     
    96     public Entry[] list() throws IOException {
    97         final int size = arr.length;
    98 
    99         int at = size - ZipInputStream.ENDHDR;
   100 
   101         byte[] data = new byte[ZipInputStream.ENDHDR];        
   102         int giveup = 0;
   103 
   104         do {
   105             FastJar.arraycopy(arr, at, data, 0, data.length);
   106             at--;
   107             giveup++;
   108             if (giveup > GIVE_UP) {
   109                 throw new IOException ();
   110             }
   111         } while (getsig(data) != ZipInputStream.ENDSIG);
   112 
   113 
   114         final long censize = endsiz(data);
   115         final long cenoff  = endoff(data);
   116         at = (int) cenoff;                                                     
   117 
   118         Entry[] result = new Entry[0];
   119         int cenread = 0;
   120         data = new byte[ZipInputStream.CENHDR];
   121         while (cenread < censize) {
   122             FastJar.arraycopy(arr, at, data, 0, data.length);
   123             at += data.length;
   124             if (getsig(data) != ZipInputStream.CENSIG) {
   125                 throw new IOException("No central table");          //NOI18N
   126             }
   127             int cennam = cennam(data);
   128             int cenext = cenext(data);
   129             int cencom = cencom(data);
   130             long lhoff = cenoff(data);
   131             long centim = centim(data);
   132             String name = new String(arr, at, cennam, "UTF-8");
   133             at += cennam;
   134             int seekby = cenext+cencom;
   135             int cendatalen = ZipInputStream.CENHDR + cennam + seekby;
   136             cenread+=cendatalen;
   137             result = addEntry(result, new Entry(name,lhoff, centim));
   138             at += seekby;
   139         }
   140         return result;
   141     }
   142 
   143     private Entry[] addEntry(Entry[] result, Entry entry) {
   144         Entry[] e = new Entry[result.length + 1];
   145         e[result.length] = entry;
   146         FastJar.arraycopy(result, 0, e, 0, result.length);
   147         return e;
   148     }
   149 
   150     private static final long getsig(final byte[] b) throws IOException {return get32(b,0);}
   151     private static final long endsiz(final byte[] b) throws IOException {return get32(b,ZipInputStream.ENDSIZ);}
   152     private static final long endoff(final byte[] b) throws IOException {return get32(b,ZipInputStream.ENDOFF);}
   153     private static final long  cenlen(final byte[] b) throws IOException {return get32(b,ZipInputStream.CENLEN);}
   154     private static final long  censiz(final byte[] b) throws IOException {return get32(b,ZipInputStream.CENSIZ);}
   155     private static final long centim(final byte[] b) throws IOException {return get32(b,ZipInputStream.CENTIM);}
   156     private static final int  cennam(final byte[] b) throws IOException {return get16(b,ZipInputStream.CENNAM);}
   157     private static final int  cenext(final byte[] b) throws IOException {return get16(b,ZipInputStream.CENEXT);}
   158     private static final int  cencom(final byte[] b) throws IOException {return get16(b,ZipInputStream.CENCOM);}
   159     private static final long cenoff (final byte[] b) throws IOException {return get32(b,ZipInputStream.CENOFF);}
   160     private static final int lochow(final byte[] b) throws IOException {return get16(b,ZipInputStream.LOCHOW);}
   161     private static final int locname(final byte[] b) throws IOException {return get16(b,ZipInputStream.LOCNAM);}
   162     private static final int locext(final byte[] b) throws IOException {return get16(b,ZipInputStream.LOCEXT);}
   163     private static final long locsiz(final byte[] b) throws IOException {return get32(b,ZipInputStream.LOCSIZ);}
   164     
   165     private static final int get16(final byte[] b, int off) throws IOException {        
   166         final int b1 = b[off];
   167 	final int b2 = b[off+1];
   168         return (b1 & 0xff) | ((b2 & 0xff) << 8);
   169     }
   170 
   171     private static final long get32(final byte[] b, int off) throws IOException {
   172 	final int s1 = get16(b, off);
   173 	final int s2 = get16(b, off+2);
   174         return s1 | ((long)s2 << 16);
   175     }
   176     
   177     @JavaScriptBody(args = {"value", "srcBegin", "dst", "dstBegin", "count"}, body
   178             = "if (srcBegin < dstBegin) {\n"
   179             + "    while (count-- > 0) {\n"
   180             + "        dst[dstBegin + count] = value[srcBegin + count];\n"
   181             + "    }\n"
   182             + "} else {\n"
   183             + "    while (count-- > 0) {\n"
   184             + "        dst[dstBegin++] = value[srcBegin++];\n"
   185             + "    }\n"
   186             + "}"
   187     )
   188     static void arraycopy(Object src, int srcBegin, Object dst, int dstBegin, int count) {
   189         try {
   190             Class<?> system = Class.forName("java.lang.System");
   191             Method m = system.getMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class);
   192             m.invoke(null, src, srcBegin, dst, dstBegin, count);
   193         } catch (Exception ex) {
   194             throw new IllegalStateException(ex);
   195         }
   196     }
   197 
   198 }