18a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak/*
28a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * Licensed to the Apache Software Foundation (ASF) under one or more
38a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * contributor license agreements.  See the NOTICE file distributed with
48a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * this work for additional information regarding copyright ownership.
58a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * The ASF licenses this file to You under the Apache License, Version 2.0
68a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * (the "License"); you may not use this file except in compliance with
78a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * the License.  You may obtain a copy of the License at
88a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak *
98a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak *     http://www.apache.org/licenses/LICENSE-2.0
108a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak *
118a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * Unless required by applicable law or agreed to in writing, software
128a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * distributed under the License is distributed on an "AS IS" BASIS,
138a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
148a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * See the License for the specific language governing permissions and
158a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * limitations under the License.
168a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak */
178a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
188a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakpackage android.util.jar;
198a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
208a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.io.IOException;
218a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.io.InputStream;
228a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.io.OutputStream;
238a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.nio.ByteBuffer;
248a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.nio.CharBuffer;
258a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.nio.charset.CharsetEncoder;
268a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.nio.charset.CoderResult;
278a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.nio.charset.StandardCharsets;
288a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.util.HashMap;
298a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.util.Iterator;
308a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.util.Map;
318a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport java.util.jar.Attributes;
328a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakimport libcore.io.Streams;
338a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
348a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak/**
358a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * The {@code StrictJarManifest} class is used to obtain attribute information for a
368a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * {@code StrictJarFile} and its entries.
378a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak *
388a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak * @hide
398a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak */
408a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniakpublic class StrictJarManifest implements Cloneable {
418a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    static final int LINE_LENGTH_LIMIT = 72;
428a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
438a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    private static final byte[] LINE_SEPARATOR = new byte[] { '\r', '\n' };
448a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
458a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    private static final byte[] VALUE_SEPARATOR = new byte[] { ':', ' ' };
468a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
478a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    private final Attributes mainAttributes;
488a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    private final HashMap<String, Attributes> entries;
498a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
508a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    static final class Chunk {
518a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        final int start;
528a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        final int end;
538a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
548a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        Chunk(int start, int end) {
558a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            this.start = start;
568a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            this.end = end;
578a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        }
588a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
598a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
608a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    private HashMap<String, Chunk> chunks;
618a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
628a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    /**
638a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * The end of the main attributes section in the manifest is needed in
648a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * verification.
658a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     */
668a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    private int mainEnd;
678a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
688a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    /**
698a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * Creates a new {@code StrictJarManifest} instance.
708a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     */
718a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    public StrictJarManifest() {
728a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        entries = new HashMap<String, Attributes>();
738a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        mainAttributes = new Attributes();
748a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
758a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
768a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    /**
778a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * Creates a new {@code StrictJarManifest} instance using the attributes obtained
788a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * from the input stream.
798a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *
808a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @param is
818a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *            {@code InputStream} to parse for attributes.
828a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @throws IOException
838a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *             if an IO error occurs while creating this {@code StrictJarManifest}
848a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     */
858a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    public StrictJarManifest(InputStream is) throws IOException {
868a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        this();
878a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        read(Streams.readFully(is));
888a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
898a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
908a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    /**
918a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * Creates a new {@code StrictJarManifest} instance. The new instance will have the
928a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * same attributes as those found in the parameter {@code StrictJarManifest}.
938a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *
948a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @param man
958a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *            {@code StrictJarManifest} instance to obtain attributes from.
968a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     */
978a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    @SuppressWarnings("unchecked")
988a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    public StrictJarManifest(StrictJarManifest man) {
998a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        mainAttributes = (Attributes) man.mainAttributes.clone();
1008a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        entries = (HashMap<String, Attributes>) ((HashMap<String, Attributes>) man
1018a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak                .getEntries()).clone();
1028a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
1038a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
1048a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    StrictJarManifest(byte[] manifestBytes, boolean readChunks) throws IOException {
1058a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        this();
1068a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        if (readChunks) {
1078a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            chunks = new HashMap<String, Chunk>();
1088a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        }
1098a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        read(manifestBytes);
1108a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
1118a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
1128a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    /**
1138a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * Resets the both the main attributes as well as the entry attributes
1148a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * associated with this {@code StrictJarManifest}.
1158a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     */
1168a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    public void clear() {
1178a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        entries.clear();
1188a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        mainAttributes.clear();
1198a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
1208a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
1218a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    /**
1228a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * Returns the {@code Attributes} associated with the parameter entry
1238a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * {@code name}.
1248a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *
1258a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @param name
1268a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *            the name of the entry to obtain {@code Attributes} from.
1278a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @return the Attributes for the entry or {@code null} if the entry does
1288a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *         not exist.
1298a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     */
1308a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    public Attributes getAttributes(String name) {
1318a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        return getEntries().get(name);
1328a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
1338a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
1348a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    /**
1358a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * Returns a map containing the {@code Attributes} for each entry in the
1368a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * {@code StrictJarManifest}.
1378a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *
1388a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @return the map of entry attributes.
1398a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     */
1408a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    public Map<String, Attributes> getEntries() {
1418a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        return entries;
1428a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
1438a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
1448a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    /**
1458a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * Returns the main {@code Attributes} of the {@code JarFile}.
1468a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *
1478a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @return main {@code Attributes} associated with the source {@code
1488a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *         JarFile}.
1498a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     */
1508a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    public Attributes getMainAttributes() {
1518a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        return mainAttributes;
1528a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
1538a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
1548a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    /**
1558a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * Creates a copy of this {@code StrictJarManifest}. The returned {@code StrictJarManifest}
1568a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * will equal the {@code StrictJarManifest} from which it was cloned.
1578a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *
1588a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @return a copy of this instance.
1598a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     */
1608a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    @Override
1618a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    public Object clone() {
1628a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        return new StrictJarManifest(this);
1638a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
1648a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
1658a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    /**
1668a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * Writes this {@code StrictJarManifest}'s name/attributes pairs to the given {@code OutputStream}.
1678a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * The {@code MANIFEST_VERSION} or {@code SIGNATURE_VERSION} attribute must be set before
1688a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * calling this method, or no attributes will be written.
1698a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *
1708a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @throws IOException
1718a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *             If an error occurs writing the {@code StrictJarManifest}.
1728a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     */
1738a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    public void write(OutputStream os) throws IOException {
1748a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        write(this, os);
1758a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
1768a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
1778a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    /**
1788a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * Merges name/attribute pairs read from the input stream {@code is} into this manifest.
1798a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *
1808a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @param is
1818a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *            The {@code InputStream} to read from.
1828a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @throws IOException
1838a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *             If an error occurs reading the manifest.
1848a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     */
1858a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    public void read(InputStream is) throws IOException {
1868a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        read(Streams.readFullyNoClose(is));
1878a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
1888a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
1898a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    private void read(byte[] buf) throws IOException {
1908a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        if (buf.length == 0) {
1918a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            return;
1928a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        }
1938a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
1948a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        StrictJarManifestReader im = new StrictJarManifestReader(buf, mainAttributes);
1958a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        mainEnd = im.getEndOfMainSection();
1968a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        im.readEntries(entries, chunks);
1978a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
1988a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
1998a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    /**
2008a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * Returns the hash code for this instance.
2018a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *
2028a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @return this {@code StrictJarManifest}'s hashCode.
2038a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     */
2048a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    @Override
2058a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    public int hashCode() {
2068a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        return mainAttributes.hashCode() ^ getEntries().hashCode();
2078a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
2088a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
2098a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    /**
2108a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * Determines if the receiver is equal to the parameter object. Two {@code
2118a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * StrictJarManifest}s are equal if they have identical main attributes as well as
2128a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * identical entry attributes.
2138a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *
2148a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @param o
2158a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *            the object to compare against.
2168a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @return {@code true} if the manifests are equal, {@code false} otherwise
2178a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     */
2188a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    @Override
2198a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    public boolean equals(Object o) {
2208a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        if (o == null) {
2218a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            return false;
2228a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        }
2238a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        if (o.getClass() != this.getClass()) {
2248a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            return false;
2258a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        }
2268a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        if (!mainAttributes.equals(((StrictJarManifest) o).mainAttributes)) {
2278a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            return false;
2288a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        }
2298a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        return getEntries().equals(((StrictJarManifest) o).getEntries());
2308a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
2318a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
2328a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    Chunk getChunk(String name) {
2338a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        return chunks.get(name);
2348a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
2358a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
2368a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    void removeChunks() {
2378a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        chunks = null;
2388a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
2398a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
2408a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    int getMainAttributesEnd() {
2418a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        return mainEnd;
2428a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
2438a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
2448a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    /**
2458a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * Writes out the attribute information of the specified manifest to the
2468a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * specified {@code OutputStream}
2478a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *
2488a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @param manifest
2498a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *            the manifest to write out.
2508a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @param out
2518a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *            The {@code OutputStream} to write to.
2528a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     * @throws IOException
2538a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     *             If an error occurs writing the {@code StrictJarManifest}.
2548a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak     */
2558a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    static void write(StrictJarManifest manifest, OutputStream out) throws IOException {
2568a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder();
2578a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        ByteBuffer buffer = ByteBuffer.allocate(LINE_LENGTH_LIMIT);
2588a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
2598a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        Attributes.Name versionName = Attributes.Name.MANIFEST_VERSION;
2608a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        String version = manifest.mainAttributes.getValue(versionName);
2618a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        if (version == null) {
2628a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            versionName = Attributes.Name.SIGNATURE_VERSION;
2638a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            version = manifest.mainAttributes.getValue(versionName);
2648a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        }
2658a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        if (version != null) {
2668a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            writeEntry(out, versionName, version, encoder, buffer);
2678a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            Iterator<?> entries = manifest.mainAttributes.keySet().iterator();
2688a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            while (entries.hasNext()) {
2698a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak                Attributes.Name name = (Attributes.Name) entries.next();
2708a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak                if (!name.equals(versionName)) {
2718a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak                    writeEntry(out, name, manifest.mainAttributes.getValue(name), encoder, buffer);
2728a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak                }
2738a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            }
2748a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        }
2758a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        out.write(LINE_SEPARATOR);
2768a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        Iterator<String> i = manifest.getEntries().keySet().iterator();
2778a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        while (i.hasNext()) {
2788a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            String key = i.next();
2798a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            writeEntry(out, Attributes.Name.NAME, key, encoder, buffer);
2808a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            Attributes attributes = manifest.entries.get(key);
2818a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            Iterator<?> entries = attributes.keySet().iterator();
2828a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            while (entries.hasNext()) {
2838a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak                Attributes.Name name = (Attributes.Name) entries.next();
2848a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak                writeEntry(out, name, attributes.getValue(name), encoder, buffer);
2858a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            }
2868a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            out.write(LINE_SEPARATOR);
2878a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        }
2888a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
2898a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
2908a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    private static void writeEntry(OutputStream os, Attributes.Name name,
2918a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            String value, CharsetEncoder encoder, ByteBuffer bBuf) throws IOException {
2928a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        String nameString = name.toString();
2938a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        os.write(nameString.getBytes(StandardCharsets.US_ASCII));
2948a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        os.write(VALUE_SEPARATOR);
2958a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
2968a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        encoder.reset();
2978a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        bBuf.clear().limit(LINE_LENGTH_LIMIT - nameString.length() - 2);
2988a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
2998a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        CharBuffer cBuf = CharBuffer.wrap(value);
3008a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak
3018a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        while (true) {
3028a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            CoderResult r = encoder.encode(cBuf, bBuf, true);
3038a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            if (CoderResult.UNDERFLOW == r) {
3048a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak                r = encoder.flush(bBuf);
3058a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            }
3068a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            os.write(bBuf.array(), bBuf.arrayOffset(), bBuf.position());
3078a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            os.write(LINE_SEPARATOR);
3088a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            if (CoderResult.UNDERFLOW == r) {
3098a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak                break;
3108a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            }
3118a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            os.write(' ');
3128a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak            bBuf.clear().limit(LINE_LENGTH_LIMIT - 1);
3138a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak        }
3148a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak    }
3158a7c1606d88873c5a1b5764c16cb046b6f2275b2Przemyslaw Szczepaniak}
316