jaroslav@672: /* jaroslav@672: * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. jaroslav@672: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jaroslav@672: * jaroslav@672: * This code is free software; you can redistribute it and/or modify it jaroslav@672: * under the terms of the GNU General Public License version 2 only, as jaroslav@672: * published by the Free Software Foundation. Oracle designates this jaroslav@672: * particular file as subject to the "Classpath" exception as provided jaroslav@672: * by Oracle in the LICENSE file that accompanied this code. jaroslav@672: * jaroslav@672: * This code is distributed in the hope that it will be useful, but WITHOUT jaroslav@672: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jaroslav@672: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jaroslav@672: * version 2 for more details (a copy is included in the LICENSE file that jaroslav@672: * accompanied this code). jaroslav@672: * jaroslav@672: * You should have received a copy of the GNU General Public License version jaroslav@672: * 2 along with this work; if not, write to the Free Software Foundation, jaroslav@672: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jaroslav@672: * jaroslav@672: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jaroslav@672: * or visit www.oracle.com if you need additional information or have any jaroslav@672: * questions. jaroslav@672: */ jaroslav@672: package org.apidesign.bck2brwsr.emul.lang; jaroslav@672: jaroslav@672: import java.io.FilterInputStream; jaroslav@672: import java.io.IOException; jaroslav@672: import java.io.InputStream; jaroslav@672: jaroslav@672: /* jaroslav@672: * A fast buffered input stream for parsing manifest files. jaroslav@672: * jaroslav@672: * Taken from java.util.jar.Manifest.FastInputStream and modified to be jaroslav@672: * independent of other Manifest functionality. jaroslav@672: */ jaroslav@672: public abstract class ManifestInputStream extends FilterInputStream { jaroslav@672: private byte[] buf; jaroslav@672: private int count = 0; jaroslav@672: private int pos = 0; jaroslav@672: jaroslav@672: protected ManifestInputStream(InputStream in) { jaroslav@672: this(in, 8192); jaroslav@672: } jaroslav@672: jaroslav@672: protected ManifestInputStream(InputStream in, int size) { jaroslav@672: super(in); jaroslav@672: buf = new byte[size]; jaroslav@672: } jaroslav@672: jaroslav@672: public int read() throws IOException { jaroslav@672: if (pos >= count) { jaroslav@672: fill(); jaroslav@672: if (pos >= count) { jaroslav@672: return -1; jaroslav@672: } jaroslav@672: } jaroslav@672: return buf[pos++] & 0xff; jaroslav@672: } jaroslav@672: jaroslav@672: public int read(byte[] b, int off, int len) throws IOException { jaroslav@672: int avail = count - pos; jaroslav@672: if (avail <= 0) { jaroslav@672: if (len >= buf.length) { jaroslav@672: return in.read(b, off, len); jaroslav@672: } jaroslav@672: fill(); jaroslav@672: avail = count - pos; jaroslav@672: if (avail <= 0) { jaroslav@672: return -1; jaroslav@672: } jaroslav@672: } jaroslav@672: if (len > avail) { jaroslav@672: len = avail; jaroslav@672: } jaroslav@672: System.arraycopy(buf, pos, b, off, len); jaroslav@672: pos += len; jaroslav@672: return len; jaroslav@672: } jaroslav@672: jaroslav@672: /* jaroslav@672: * Reads 'len' bytes from the input stream, or until an end-of-line jaroslav@672: * is reached. Returns the number of bytes read. jaroslav@672: */ jaroslav@672: public int readLine(byte[] b, int off, int len) throws IOException { jaroslav@672: byte[] tbuf = this.buf; jaroslav@672: int total = 0; jaroslav@672: while (total < len) { jaroslav@672: int avail = count - pos; jaroslav@672: if (avail <= 0) { jaroslav@672: fill(); jaroslav@672: avail = count - pos; jaroslav@672: if (avail <= 0) { jaroslav@672: return -1; jaroslav@672: } jaroslav@672: } jaroslav@672: int n = len - total; jaroslav@672: if (n > avail) { jaroslav@672: n = avail; jaroslav@672: } jaroslav@672: int tpos = pos; jaroslav@672: int maxpos = tpos + n; jaroslav@672: while (tpos < maxpos && tbuf[tpos++] != '\n') { jaroslav@672: ; jaroslav@672: } jaroslav@672: n = tpos - pos; jaroslav@672: System.arraycopy(tbuf, pos, b, off, n); jaroslav@672: off += n; jaroslav@672: total += n; jaroslav@672: pos = tpos; jaroslav@672: if (tbuf[tpos - 1] == '\n') { jaroslav@672: break; jaroslav@672: } jaroslav@672: } jaroslav@672: return total; jaroslav@672: } jaroslav@672: jaroslav@672: public byte peek() throws IOException { jaroslav@672: if (pos == count) { jaroslav@672: fill(); jaroslav@672: } jaroslav@672: if (pos == count) { jaroslav@672: return -1; // nothing left in buffer jaroslav@672: } jaroslav@672: return buf[pos]; jaroslav@672: } jaroslav@672: jaroslav@672: public int readLine(byte[] b) throws IOException { jaroslav@672: return readLine(b, 0, b.length); jaroslav@672: } jaroslav@672: jaroslav@672: public long skip(long n) throws IOException { jaroslav@672: if (n <= 0) { jaroslav@672: return 0; jaroslav@672: } jaroslav@672: long avail = count - pos; jaroslav@672: if (avail <= 0) { jaroslav@672: return in.skip(n); jaroslav@672: } jaroslav@672: if (n > avail) { jaroslav@672: n = avail; jaroslav@672: } jaroslav@672: pos += n; jaroslav@672: return n; jaroslav@672: } jaroslav@672: jaroslav@672: public int available() throws IOException { jaroslav@672: return (count - pos) + in.available(); jaroslav@672: } jaroslav@672: jaroslav@672: public void close() throws IOException { jaroslav@672: if (in != null) { jaroslav@672: in.close(); jaroslav@672: in = null; jaroslav@672: buf = null; jaroslav@672: } jaroslav@672: } jaroslav@672: jaroslav@672: private void fill() throws IOException { jaroslav@672: count = pos = 0; jaroslav@672: int n = in.read(buf, 0, buf.length); jaroslav@672: if (n > 0) { jaroslav@672: count = n; jaroslav@672: } jaroslav@672: } jaroslav@672: jaroslav@672: protected abstract String putValue(String key, String value); jaroslav@672: jaroslav@672: public void readAttributes(byte[] lbuf) throws IOException { jaroslav@672: ManifestInputStream is = this; jaroslav@672: jaroslav@672: String name = null; jaroslav@672: String value = null; jaroslav@672: byte[] lastline = null; jaroslav@672: int len; jaroslav@672: while ((len = is.readLine(lbuf)) != -1) { jaroslav@672: boolean lineContinued = false; jaroslav@672: if (lbuf[--len] != '\n') { jaroslav@672: throw new IOException("line too long"); jaroslav@672: } jaroslav@672: if (len > 0 && lbuf[len - 1] == '\r') { jaroslav@672: --len; jaroslav@672: } jaroslav@672: if (len == 0) { jaroslav@672: break; jaroslav@672: } jaroslav@672: int i = 0; jaroslav@672: if (lbuf[0] == ' ') { jaroslav@672: if (name == null) { jaroslav@672: throw new IOException("misplaced continuation line"); jaroslav@672: } jaroslav@672: lineContinued = true; jaroslav@672: byte[] buf = new byte[lastline.length + len - 1]; jaroslav@672: System.arraycopy(lastline, 0, buf, 0, lastline.length); jaroslav@672: System.arraycopy(lbuf, 1, buf, lastline.length, len - 1); jaroslav@672: if (is.peek() == ' ') { jaroslav@672: lastline = buf; jaroslav@672: continue; jaroslav@672: } jaroslav@672: value = new String(buf, 0, buf.length, "UTF8"); jaroslav@672: lastline = null; jaroslav@672: } else { jaroslav@672: while (lbuf[i++] != ':') { jaroslav@672: if (i >= len) { jaroslav@672: throw new IOException("invalid header field"); jaroslav@672: } jaroslav@672: } jaroslav@672: if (lbuf[i++] != ' ') { jaroslav@672: throw new IOException("invalid header field"); jaroslav@672: } jaroslav@672: name = new String(lbuf, 0, 0, i - 2); jaroslav@672: if (is.peek() == ' ') { jaroslav@672: lastline = new byte[len - i]; jaroslav@672: System.arraycopy(lbuf, i, lastline, 0, len - i); jaroslav@672: continue; jaroslav@672: } jaroslav@672: value = new String(lbuf, i, len - i, "UTF8"); jaroslav@672: } jaroslav@672: try { jaroslav@672: if ((putValue(name, value) != null) && (!lineContinued)) { jaroslav@672: throw new IOException("Duplicate name in Manifest: " + name + ".\n" + "Ensure that the manifest does not " + "have duplicate entries, and\n" + "that blank lines separate " + "individual sections in both your\n" + "manifest and in the META-INF/MANIFEST.MF " + "entry in the jar file."); jaroslav@672: } jaroslav@672: } catch (IllegalArgumentException e) { jaroslav@672: throw new IOException("invalid header field name: " + name); jaroslav@672: } jaroslav@672: } jaroslav@672: } jaroslav@672: }