rt/emul/zip/src/main/java/org/apidesign/bck2brwsr/emul/zip/FastJar.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 13 May 2014 21:14:44 +0200
branchclosure
changeset 1569 9eb0eb434c67
parent 1555 71e68f7ed23f
permissions -rw-r--r--
Used from tests, must be exported
     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.Exported;
    40 import org.apidesign.bck2brwsr.core.JavaScriptBody;
    41 
    42 /**
    43  *
    44  * @author Tomas Zezula
    45  */
    46 public final class FastJar {
    47     private final byte[] arr;
    48 
    49     public FastJar(byte[] arr) {
    50         this.arr = arr;
    51     }
    52     
    53     
    54     private static final int GIVE_UP = 1<<16;
    55 
    56     public static final  class Entry {
    57         
    58         public final String name;
    59         final long offset;
    60         private final long dosTime;
    61         
    62         Entry (String name, long offset, long time) {
    63             assert name != null;
    64             this.name = name;
    65             this.offset = offset;
    66             this.dosTime = time;
    67         }        
    68 /*        
    69         public long getTime () {
    70             Date d = new Date((int)(((dosTime >> 25) & 0x7f) + 80),
    71                     (int)(((dosTime >> 21) & 0x0f) - 1),
    72                     (int)((dosTime >> 16) & 0x1f),
    73                     (int)((dosTime >> 11) & 0x1f),
    74                     (int)((dosTime >> 5) & 0x3f),
    75                     (int)((dosTime << 1) & 0x3e));
    76             return d.getTime();
    77         }
    78         */
    79     }
    80     
    81     public InputStream getInputStream (final Entry e) throws IOException {
    82         return getInputStream(arr, e.offset);
    83     }
    84     
    85     private static InputStream getInputStream (byte[] arr, final long offset) throws IOException {
    86         ByteArrayInputStream is = new ByteArrayInputStream(arr);
    87         is.skip(offset);
    88         ZipInputStream in = new ZipInputStream (is);
    89         ZipEntry e = in.getNextEntry();
    90         if (e != null && e.getCrc() == 0L && e.getMethod() == ZipEntry.STORED) {
    91             int cp = arr.length - is.available();
    92             return new ByteArrayInputStream(arr, cp, (int)e.getSize());
    93         }
    94         return in;
    95     }
    96     
    97     public Entry[] list() throws IOException {
    98         final int size = arr.length;
    99 
   100         int at = size - ZipInputStream.ENDHDR;
   101 
   102         byte[] data = new byte[ZipInputStream.ENDHDR];        
   103         int giveup = 0;
   104 
   105         do {
   106             FastJar.arraycopy(arr, at, data, 0, data.length);
   107             at--;
   108             giveup++;
   109             if (giveup > GIVE_UP) {
   110                 throw new IOException ();
   111             }
   112         } while (getsig(data) != ZipInputStream.ENDSIG);
   113 
   114 
   115         final long censize = endsiz(data);
   116         final long cenoff  = endoff(data);
   117         at = (int) cenoff;                                                     
   118 
   119         Entry[] result = new Entry[0];
   120         int cenread = 0;
   121         data = new byte[ZipInputStream.CENHDR];
   122         while (cenread < censize) {
   123             FastJar.arraycopy(arr, at, data, 0, data.length);
   124             at += data.length;
   125             if (getsig(data) != ZipInputStream.CENSIG) {
   126                 throw new IOException("No central table");          //NOI18N
   127             }
   128             int cennam = cennam(data);
   129             int cenext = cenext(data);
   130             int cencom = cencom(data);
   131             long lhoff = cenoff(data);
   132             long centim = centim(data);
   133             String name = new String(arr, at, cennam, "UTF-8");
   134             at += cennam;
   135             int seekby = cenext+cencom;
   136             int cendatalen = ZipInputStream.CENHDR + cennam + seekby;
   137             cenread+=cendatalen;
   138             result = addEntry(result, new Entry(name,lhoff, centim));
   139             at += seekby;
   140         }
   141         return result;
   142     }
   143 
   144     private Entry[] addEntry(Entry[] result, Entry entry) {
   145         Entry[] e = new Entry[result.length + 1];
   146         e[result.length] = entry;
   147         FastJar.arraycopy(result, 0, e, 0, result.length);
   148         return e;
   149     }
   150 
   151     private static final long getsig(final byte[] b) throws IOException {return get32(b,0);}
   152     private static final long endsiz(final byte[] b) throws IOException {return get32(b,ZipInputStream.ENDSIZ);}
   153     private static final long endoff(final byte[] b) throws IOException {return get32(b,ZipInputStream.ENDOFF);}
   154     private static final long  cenlen(final byte[] b) throws IOException {return get32(b,ZipInputStream.CENLEN);}
   155     private static final long  censiz(final byte[] b) throws IOException {return get32(b,ZipInputStream.CENSIZ);}
   156     private static final long centim(final byte[] b) throws IOException {return get32(b,ZipInputStream.CENTIM);}
   157     private static final int  cennam(final byte[] b) throws IOException {return get16(b,ZipInputStream.CENNAM);}
   158     private static final int  cenext(final byte[] b) throws IOException {return get16(b,ZipInputStream.CENEXT);}
   159     private static final int  cencom(final byte[] b) throws IOException {return get16(b,ZipInputStream.CENCOM);}
   160     private static final long cenoff (final byte[] b) throws IOException {return get32(b,ZipInputStream.CENOFF);}
   161     private static final int lochow(final byte[] b) throws IOException {return get16(b,ZipInputStream.LOCHOW);}
   162     private static final int locname(final byte[] b) throws IOException {return get16(b,ZipInputStream.LOCNAM);}
   163     private static final int locext(final byte[] b) throws IOException {return get16(b,ZipInputStream.LOCEXT);}
   164     private static final long locsiz(final byte[] b) throws IOException {return get32(b,ZipInputStream.LOCSIZ);}
   165     
   166     private static final int get16(final byte[] b, int off) throws IOException {        
   167         final int b1 = b[off];
   168 	final int b2 = b[off+1];
   169         return (b1 & 0xff) | ((b2 & 0xff) << 8);
   170     }
   171 
   172     private static final long get32(final byte[] b, int off) throws IOException {
   173 	final int s1 = get16(b, off);
   174 	final int s2 = get16(b, off+2);
   175         return s1 | ((long)s2 << 16);
   176     }
   177     
   178     @JavaScriptBody(args = {"value", "srcBegin", "dst", "dstBegin", "count"}, body
   179             = "if (srcBegin < dstBegin) {\n"
   180             + "    while (count-- > 0) {\n"
   181             + "        dst[dstBegin + count] = value[srcBegin + count];\n"
   182             + "    }\n"
   183             + "} else {\n"
   184             + "    while (count-- > 0) {\n"
   185             + "        dst[dstBegin++] = value[srcBegin++];\n"
   186             + "    }\n"
   187             + "}"
   188     )
   189     
   190     @Exported
   191     static void arraycopy(Object src, int srcBegin, Object dst, int dstBegin, int count) {
   192         try {
   193             Class<?> system = Class.forName("java.lang.System");
   194             Method m = system.getMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class);
   195             m.invoke(null, src, srcBegin, dst, dstBegin, count);
   196         } catch (Exception ex) {
   197             throw new IllegalStateException(ex);
   198         }
   199     }
   200 
   201 }