1f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson/* 2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one or more 3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * contributor license agreements. See the NOTICE file distributed with 4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this work for additional information regarding copyright ownership. 5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The ASF licenses this file to You under the Apache License, Version 2.0 6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (the "License"); you may not use this file except in compliance with 7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the License. You may obtain a copy of the License at 8f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson * 9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 10f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson * 11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and 15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License. 16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.util.jar; 19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException; 21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream; 22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.OutputStream; 2357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilsonimport java.nio.ByteBuffer; 24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.CharBuffer; 2557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilsonimport java.nio.charset.CharsetEncoder; 2657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilsonimport java.nio.charset.CoderResult; 272a6f23ff8690ac2f025588a360547ce96cde0943Elliott Hughesimport java.nio.charset.StandardCharsets; 28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.HashMap; 29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Iterator; 30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Map; 316186821cb13f4ac7ff50950c813394367e021eaeJesse Wilsonimport libcore.io.Streams; 32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The {@code Manifest} class is used to obtain attribute information for a 35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code JarFile} and its entries. 36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class Manifest implements Cloneable { 3857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson static final int LINE_LENGTH_LIMIT = 72; 39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private static final byte[] LINE_SEPARATOR = new byte[] { '\r', '\n' }; 41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 4257995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson private static final byte[] VALUE_SEPARATOR = new byte[] { ':', ' ' }; 4357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 441222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath private final Attributes mainAttributes; 451222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath private final HashMap<String, Attributes> entries; 46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 471222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath static final class Chunk { 481222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath final int start; 491222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath final int end; 5057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 5157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson Chunk(int start, int end) { 5257995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson this.start = start; 5357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson this.end = end; 5457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 5557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 5657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 5757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson private HashMap<String, Chunk> chunks; 58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 5957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson /** 6057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * The end of the main attributes section in the manifest is needed in 61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * verification. 62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 6357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson private int mainEnd; 64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Creates a new {@code Manifest} instance. 67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Manifest() { 691222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath entries = new HashMap<String, Attributes>(); 701222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath mainAttributes = new Attributes(); 71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Creates a new {@code Manifest} instance using the attributes obtained 75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * from the input stream. 7657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param is 78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code InputStream} to parse for attributes. 79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if an IO error occurs while creating this {@code Manifest} 81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Manifest(InputStream is) throws IOException { 831222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath this(); 841222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath read(Streams.readFully(is)); 85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Creates a new {@code Manifest} instance. The new instance will have the 89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * same attributes as those found in the parameter {@code Manifest}. 9057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param man 92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code Manifest} instance to obtain attributes from. 93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @SuppressWarnings("unchecked") 95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Manifest(Manifest man) { 96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project mainAttributes = (Attributes) man.mainAttributes.clone(); 9757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson entries = (HashMap<String, Attributes>) ((HashMap<String, Attributes>) man 9857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson .getEntries()).clone(); 99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 1011222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath Manifest(byte[] manifestBytes, boolean readChunks) throws IOException { 1021222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath this(); 103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (readChunks) { 10457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson chunks = new HashMap<String, Chunk>(); 105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1061222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath read(manifestBytes); 107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Resets the both the main attributes as well as the entry attributes 111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * associated with this {@code Manifest}. 112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void clear() { 11457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson entries.clear(); 115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project mainAttributes.clear(); 116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the {@code Attributes} associated with the parameter entry 120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code name}. 12157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param name 123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the entry to obtain {@code Attributes} from. 124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the Attributes for the entry or {@code null} if the entry does 125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * not exist. 126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Attributes getAttributes(String name) { 128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return getEntries().get(name); 129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns a map containing the {@code Attributes} for each entry in the 133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code Manifest}. 13457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the map of entry attributes. 136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Map<String, Attributes> getEntries() { 13857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return entries; 13957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 14057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the main {@code Attributes} of the {@code JarFile}. 14357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return main {@code Attributes} associated with the source {@code 145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * JarFile}. 146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Attributes getMainAttributes() { 148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return mainAttributes; 149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Creates a copy of this {@code Manifest}. The returned {@code Manifest} 153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * will equal the {@code Manifest} from which it was cloned. 15457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return a copy of this instance. 156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Object clone() { 159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return new Manifest(this); 160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 1633f52fe84a434dace741ba77de7322ca4d1d12fa7Elliott Hughes * Writes this {@code Manifest}'s name/attributes pairs to the given {@code OutputStream}. 1643f52fe84a434dace741ba77de7322ca4d1d12fa7Elliott Hughes * The {@code MANIFEST_VERSION} or {@code SIGNATURE_VERSION} attribute must be set before 1653f52fe84a434dace741ba77de7322ca4d1d12fa7Elliott Hughes * calling this method, or no attributes will be written. 16657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * If an error occurs writing the {@code Manifest}. 169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void write(OutputStream os) throws IOException { 171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project write(this, os); 172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 175bfdb06dfa90bad70f55ae5c302a699fe28184b81Elliott Hughes * Merges name/attribute pairs read from the input stream {@code is} into this manifest. 17657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param is 178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The {@code InputStream} to read from. 179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 180bfdb06dfa90bad70f55ae5c302a699fe28184b81Elliott Hughes * If an error occurs reading the manifest. 181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void read(InputStream is) throws IOException { 1831222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath read(Streams.readFullyNoClose(is)); 1841222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath } 18557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 1861222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath private void read(byte[] buf) throws IOException { 18757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson if (buf.length == 0) { 18857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return; 18957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 19057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 1913a99bc391e224b8f1d371955c61dd47642e25b53Elliott Hughes ManifestReader im = new ManifestReader(buf, mainAttributes); 1923a99bc391e224b8f1d371955c61dd47642e25b53Elliott Hughes mainEnd = im.getEndOfMainSection(); 1933a99bc391e224b8f1d371955c61dd47642e25b53Elliott Hughes im.readEntries(entries, chunks); 19457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 19557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 196bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes /** 197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the hash code for this instance. 19857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return this {@code Manifest}'s hashCode. 200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public int hashCode() { 20357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return mainAttributes.hashCode() ^ getEntries().hashCode(); 204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Determines if the receiver is equal to the parameter object. Two {@code 208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Manifest}s are equal if they have identical main attributes as well as 209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * identical entry attributes. 21057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param o 212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the object to compare against. 213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return {@code true} if the manifests are equal, {@code false} otherwise 214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public boolean equals(Object o) { 217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (o == null) { 218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return false; 219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (o.getClass() != this.getClass()) { 221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return false; 222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (!mainAttributes.equals(((Manifest) o).mainAttributes)) { 224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return false; 225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 22657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return getEntries().equals(((Manifest) o).getEntries()); 227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 22957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson Chunk getChunk(String name) { 230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return chunks.get(name); 231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project void removeChunks() { 234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project chunks = null; 235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 23757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson int getMainAttributesEnd() { 23857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return mainEnd; 239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Writes out the attribute information of the specified manifest to the 243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * specified {@code OutputStream} 24457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param manifest 246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the manifest to write out. 247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param out 248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The {@code OutputStream} to write to. 249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * If an error occurs writing the {@code Manifest}. 251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project static void write(Manifest manifest, OutputStream out) throws IOException { 2532a6f23ff8690ac2f025588a360547ce96cde0943Elliott Hughes CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder(); 25456e742806ebb265e77de750cdb4575cff781fdf8Elliott Hughes ByteBuffer buffer = ByteBuffer.allocate(LINE_LENGTH_LIMIT); 25557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 2563f52fe84a434dace741ba77de7322ca4d1d12fa7Elliott Hughes Attributes.Name versionName = Attributes.Name.MANIFEST_VERSION; 2573f52fe84a434dace741ba77de7322ca4d1d12fa7Elliott Hughes String version = manifest.mainAttributes.getValue(versionName); 2583f52fe84a434dace741ba77de7322ca4d1d12fa7Elliott Hughes if (version == null) { 2593f52fe84a434dace741ba77de7322ca4d1d12fa7Elliott Hughes versionName = Attributes.Name.SIGNATURE_VERSION; 2603f52fe84a434dace741ba77de7322ca4d1d12fa7Elliott Hughes version = manifest.mainAttributes.getValue(versionName); 2613f52fe84a434dace741ba77de7322ca4d1d12fa7Elliott Hughes } 262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (version != null) { 2633f52fe84a434dace741ba77de7322ca4d1d12fa7Elliott Hughes writeEntry(out, versionName, version, encoder, buffer); 264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Iterator<?> entries = manifest.mainAttributes.keySet().iterator(); 265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project while (entries.hasNext()) { 266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Attributes.Name name = (Attributes.Name) entries.next(); 2673f52fe84a434dace741ba77de7322ca4d1d12fa7Elliott Hughes if (!name.equals(versionName)) { 26856e742806ebb265e77de750cdb4575cff781fdf8Elliott Hughes writeEntry(out, name, manifest.mainAttributes.getValue(name), encoder, buffer); 269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project out.write(LINE_SEPARATOR); 27357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson Iterator<String> i = manifest.getEntries().keySet().iterator(); 274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project while (i.hasNext()) { 275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String key = i.next(); 27659675dbb837c2a92352032e2ef0c8fc3305da9c8Elliott Hughes writeEntry(out, Attributes.Name.NAME, key, encoder, buffer); 2773f52fe84a434dace741ba77de7322ca4d1d12fa7Elliott Hughes Attributes attributes = manifest.entries.get(key); 2783f52fe84a434dace741ba77de7322ca4d1d12fa7Elliott Hughes Iterator<?> entries = attributes.keySet().iterator(); 279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project while (entries.hasNext()) { 280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Attributes.Name name = (Attributes.Name) entries.next(); 2813f52fe84a434dace741ba77de7322ca4d1d12fa7Elliott Hughes writeEntry(out, name, attributes.getValue(name), encoder, buffer); 282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project out.write(LINE_SEPARATOR); 284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 28757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson private static void writeEntry(OutputStream os, Attributes.Name name, 288678e3d534e57c24e3a75a5153cc24714ebdaad8fJesse Wilson String value, CharsetEncoder encoder, ByteBuffer bBuf) throws IOException { 289678e3d534e57c24e3a75a5153cc24714ebdaad8fJesse Wilson String nameString = name.getName(); 2902a6f23ff8690ac2f025588a360547ce96cde0943Elliott Hughes os.write(nameString.getBytes(StandardCharsets.US_ASCII)); 29157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson os.write(VALUE_SEPARATOR); 29257995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 29357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson encoder.reset(); 294678e3d534e57c24e3a75a5153cc24714ebdaad8fJesse Wilson bBuf.clear().limit(LINE_LENGTH_LIMIT - nameString.length() - 2); 29557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 29657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson CharBuffer cBuf = CharBuffer.wrap(value); 29757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 29857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson while (true) { 299678e3d534e57c24e3a75a5153cc24714ebdaad8fJesse Wilson CoderResult r = encoder.encode(cBuf, bBuf, true); 30057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson if (CoderResult.UNDERFLOW == r) { 30157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson r = encoder.flush(bBuf); 302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 30357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson os.write(bBuf.array(), bBuf.arrayOffset(), bBuf.position()); 304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project os.write(LINE_SEPARATOR); 30557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson if (CoderResult.UNDERFLOW == r) { 30657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson break; 30757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 30857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson os.write(' '); 30957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson bBuf.clear().limit(LINE_LENGTH_LIMIT - 1); 310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 313