/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Imported by CG 20090322 based on Apache Harmony ("enhanced") revision 669414. * Modified to not use java.nio. */ package java.util.jar; import java.io.IOException; import java.util.Map; class InitManifest { private byte[] buf; private int pos; Attributes.Name name; String value; InitManifest(byte[] buf, Attributes main, Attributes.Name ver) throws IOException { this.buf = buf; // check a version attribute if (!readHeader() || (ver != null && !name.equals(ver))) { throw new IOException("Missing version attribute: " + ver); } main.put(name, value); while (readHeader()) { main.put(name, value); } } void initEntries(Map entries, Map chunks) throws IOException { int mark = pos; while (readHeader()) { if (!Attributes.Name.NAME.equals(name)) { throw new IOException("Entry is not named"); } String entryNameValue = value; Attributes entry = (Attributes) entries.get(entryNameValue); if (entry == null) { entry = new Attributes(12); } while (readHeader()) { entry.put(name, value); } if (chunks != null) { if (chunks.get(entryNameValue) != null) { // TODO A bug: there might be several verification chunks for // the same name. I believe they should be used to update // signature in order of appearance; there are two ways to fix // this: either use a list of chunks, or decide on used // signature algorithm in advance and reread the chunks while // updating the signature; for now a defensive error is thrown throw new IOException("A jar verifier does not support more than one entry with the same name"); } chunks.put(entryNameValue, new Manifest.Chunk(mark, pos)); mark = pos; } entries.put(entryNameValue, entry); } } int getPos() { return pos; } /** * Number of subsequent line breaks. */ int linebreak = 0; /** * Read a single line from the manifest buffer. */ private boolean readHeader() throws IOException { if (linebreak > 1) { // break a section on an empty line linebreak = 0; return false; } readName(); linebreak = 0; readValue(); // if the last line break is missed, the line // is ignored by the reference implementation return linebreak > 0; } private byte[] wrap(int mark, int pos) { byte[] buffer = new byte[pos - mark]; System.arraycopy(buf, mark, buffer, 0, pos - mark); return buffer; } private void readName() throws IOException { int i = 0; int mark = pos; while (pos < buf.length) { byte b = buf[pos++]; if (b == ':') { byte[] nameBuffer = wrap(mark, pos - 1); if (buf[pos++] != ' ') { throw new IOException("Invalid attribute " + nameBuffer); } name = new Attributes.Name(nameBuffer); return; } if (!((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || b == '-' || (b >= '0' && b <= '9'))) { throw new IOException("Invalid attribute character code " + b); } } if (i > 0) { throw new IOException("Invalid attribute " + wrap(mark, buf.length)); } } private void readValue() throws IOException { byte next; boolean lastCr = false; int mark = pos; int last = pos; value = ""; while (pos < buf.length) { next = buf[pos++]; switch (next) { case 0: throw new IOException("NUL character in a manifest"); case '\n': if (lastCr) { lastCr = false; } else { linebreak++; } continue; case '\r': lastCr = true; linebreak++; continue; case ' ': if (linebreak == 1) { value += new String(wrap(mark, last), "UTF8"); mark = pos; linebreak = 0; continue; } } if (linebreak >= 1) { pos--; break; } last = pos; } value += new String(wrap(mark, last), "UTF8"); } }