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 20bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughesimport java.io.ByteArrayInputStream; 21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException; 22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream; 23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.OutputStream; 24bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughesimport java.lang.reflect.Field; 2557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilsonimport java.nio.ByteBuffer; 26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.CharBuffer; 2757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilsonimport java.nio.charset.CharsetEncoder; 2856e742806ebb265e77de750cdb4575cff781fdf8Elliott Hughesimport java.nio.charset.Charsets; 2957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilsonimport java.nio.charset.CoderResult; 30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.HashMap; 31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Iterator; 32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Map; 336186821cb13f4ac7ff50950c813394367e021eaeJesse Wilsonimport libcore.io.Streams; 34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The {@code Manifest} class is used to obtain attribute information for a 37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code JarFile} and its entries. 38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class Manifest implements Cloneable { 4057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson static final int LINE_LENGTH_LIMIT = 72; 41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private static final byte[] LINE_SEPARATOR = new byte[] { '\r', '\n' }; 43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 4457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson private static final byte[] VALUE_SEPARATOR = new byte[] { ':', ' ' }; 4557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 46bfdb06dfa90bad70f55ae5c302a699fe28184b81Elliott Hughes private static final Attributes.Name NAME_ATTRIBUTE = new Attributes.Name("Name"); 47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 48bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes private static final Field BAIS_BUF = getByteArrayInputStreamField("buf"); 49bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes private static final Field BAIS_POS = getByteArrayInputStreamField("pos"); 50bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes 51bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes private static Field getByteArrayInputStreamField(String name) { 52bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes try { 53bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes Field f = ByteArrayInputStream.class.getDeclaredField(name); 54bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes f.setAccessible(true); 55bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes return f; 56bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes } catch (Exception ex) { 57bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes throw new AssertionError(ex); 58bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes } 59bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes } 60bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes 61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private Attributes mainAttributes = new Attributes(); 62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 6357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson private HashMap<String, Attributes> entries = new HashMap<String, Attributes>(); 6457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 6557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson static class Chunk { 6657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson int start; 6757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson int end; 6857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 6957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson Chunk(int start, int end) { 7057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson this.start = start; 7157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson this.end = end; 7257995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 7357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 7457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 7557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson private HashMap<String, Chunk> chunks; 76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 7757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson /** 7857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * The end of the main attributes section in the manifest is needed in 79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * verification. 80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 8157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson private int mainEnd; 82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Creates a new {@code Manifest} instance. 85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Manifest() { 87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Creates a new {@code Manifest} instance using the attributes obtained 91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * from the input stream. 9257995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param is 94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code InputStream} to parse for attributes. 95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if an IO error occurs while creating this {@code Manifest} 97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Manifest(InputStream is) throws IOException { 99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project read(is); 100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Creates a new {@code Manifest} instance. The new instance will have the 104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * same attributes as those found in the parameter {@code Manifest}. 10557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param man 107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code Manifest} instance to obtain attributes from. 108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @SuppressWarnings("unchecked") 110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Manifest(Manifest man) { 111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project mainAttributes = (Attributes) man.mainAttributes.clone(); 11257995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson entries = (HashMap<String, Attributes>) ((HashMap<String, Attributes>) man 11357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson .getEntries()).clone(); 114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Manifest(InputStream is, boolean readChunks) throws IOException { 117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (readChunks) { 11857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson chunks = new HashMap<String, Chunk>(); 119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project read(is); 121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Resets the both the main attributes as well as the entry attributes 125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * associated with this {@code Manifest}. 126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void clear() { 12857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson entries.clear(); 129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project mainAttributes.clear(); 130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the {@code Attributes} associated with the parameter entry 134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code name}. 13557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param name 137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the entry to obtain {@code Attributes} from. 138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the Attributes for the entry or {@code null} if the entry does 139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * not exist. 140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Attributes getAttributes(String name) { 142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return getEntries().get(name); 143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns a map containing the {@code Attributes} for each entry in the 147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code Manifest}. 14857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the map of entry attributes. 150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Map<String, Attributes> getEntries() { 15257995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return entries; 15357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 15457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the main {@code Attributes} of the {@code JarFile}. 15757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return main {@code Attributes} associated with the source {@code 159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * JarFile}. 160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Attributes getMainAttributes() { 162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return mainAttributes; 163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Creates a copy of this {@code Manifest}. The returned {@code Manifest} 167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * will equal the {@code Manifest} from which it was cloned. 16857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return a copy of this instance. 170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Object clone() { 173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return new Manifest(this); 174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Writes out the attribute information of the receiver to the specified 178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code OutputStream}. 17957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param os 181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The {@code OutputStream} to write to. 182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * If an error occurs writing the {@code Manifest}. 184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void write(OutputStream os) throws IOException { 186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project write(this, os); 187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 190bfdb06dfa90bad70f55ae5c302a699fe28184b81Elliott Hughes * Merges name/attribute pairs read from the input stream {@code is} into this manifest. 19157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param is 193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The {@code InputStream} to read from. 194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 195bfdb06dfa90bad70f55ae5c302a699fe28184b81Elliott Hughes * If an error occurs reading the manifest. 196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void read(InputStream is) throws IOException { 19857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson byte[] buf; 199bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes if (is instanceof ByteArrayInputStream) { 200bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes buf = exposeByteArrayInputStreamBytes((ByteArrayInputStream) is); 201bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes } else { 202df84cec32f3c1f71ea781e5f851724d84c35e620Jesse Wilson buf = Streams.readFullyNoClose(is); 20357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 20457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 20557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson if (buf.length == 0) { 20657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return; 20757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 20857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 20957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson // a workaround for HARMONY-5662 21057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson // replace EOF and NUL with another new line 21157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson // which does not trigger an error 21257995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson byte b = buf[buf.length - 1]; 213b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes if (b == 0 || b == 26) { 21457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson buf[buf.length - 1] = '\n'; 21557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 21657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 21757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson // Attributes.Name.MANIFEST_VERSION is not used for 21857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson // the second parameter for RI compatibility 219bfdb06dfa90bad70f55ae5c302a699fe28184b81Elliott Hughes InitManifest im = new InitManifest(buf, mainAttributes, null); 22057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson mainEnd = im.getPos(); 22157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson im.initEntries(entries, chunks); 22257995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 22357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 224bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes /** 225bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes * Returns a byte[] containing all the bytes from a ByteArrayInputStream. 226bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes * Where possible, this returns the actual array rather than a copy. 22757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson */ 228bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes private static byte[] exposeByteArrayInputStreamBytes(ByteArrayInputStream bais) { 229bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes byte[] buffer; 230bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes synchronized (bais) { 231bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes byte[] buf; 232bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes int pos; 233bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes try { 234bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes buf = (byte[]) BAIS_BUF.get(bais); 235bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes pos = BAIS_POS.getInt(bais); 236bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes } catch (IllegalAccessException iae) { 237bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes throw new AssertionError(iae); 23857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 239bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes int available = bais.available(); 240bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes if (pos == 0 && buf.length == available) { 241bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes buffer = buf; 242bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes } else { 243bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes buffer = new byte[available]; 244bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes System.arraycopy(buf, pos, buffer, 0, available); 24557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 246bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes bais.skip(available); 24757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 248bbf2c7d0462bb2c612e5a1a28e6d0ce5413d746dElliott Hughes return buffer; 249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the hash code for this instance. 25357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return this {@code Manifest}'s hashCode. 255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public int hashCode() { 25857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return mainAttributes.hashCode() ^ getEntries().hashCode(); 259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Determines if the receiver is equal to the parameter object. Two {@code 263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Manifest}s are equal if they have identical main attributes as well as 264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * identical entry attributes. 26557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param o 267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the object to compare against. 268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return {@code true} if the manifests are equal, {@code false} otherwise 269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public boolean equals(Object o) { 272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (o == null) { 273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return false; 274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (o.getClass() != this.getClass()) { 276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return false; 277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (!mainAttributes.equals(((Manifest) o).mainAttributes)) { 279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return false; 280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 28157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return getEntries().equals(((Manifest) o).getEntries()); 282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 28457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson Chunk getChunk(String name) { 285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return chunks.get(name); 286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project void removeChunks() { 289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project chunks = null; 290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 29257995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson int getMainAttributesEnd() { 29357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return mainEnd; 294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Writes out the attribute information of the specified manifest to the 298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * specified {@code OutputStream} 29957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param manifest 301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the manifest to write out. 302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param out 303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The {@code OutputStream} to write to. 304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * If an error occurs writing the {@code Manifest}. 306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project static void write(Manifest manifest, OutputStream out) throws IOException { 30856e742806ebb265e77de750cdb4575cff781fdf8Elliott Hughes CharsetEncoder encoder = Charsets.UTF_8.newEncoder(); 30956e742806ebb265e77de750cdb4575cff781fdf8Elliott Hughes ByteBuffer buffer = ByteBuffer.allocate(LINE_LENGTH_LIMIT); 31057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 31156e742806ebb265e77de750cdb4575cff781fdf8Elliott Hughes String version = manifest.mainAttributes.getValue(Attributes.Name.MANIFEST_VERSION); 312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (version != null) { 31356e742806ebb265e77de750cdb4575cff781fdf8Elliott Hughes writeEntry(out, Attributes.Name.MANIFEST_VERSION, version, encoder, buffer); 314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Iterator<?> entries = manifest.mainAttributes.keySet().iterator(); 315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project while (entries.hasNext()) { 316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Attributes.Name name = (Attributes.Name) entries.next(); 317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (!name.equals(Attributes.Name.MANIFEST_VERSION)) { 31856e742806ebb265e77de750cdb4575cff781fdf8Elliott Hughes writeEntry(out, name, manifest.mainAttributes.getValue(name), encoder, buffer); 319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project out.write(LINE_SEPARATOR); 32357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson Iterator<String> i = manifest.getEntries().keySet().iterator(); 324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project while (i.hasNext()) { 325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String key = i.next(); 32657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson writeEntry(out, NAME_ATTRIBUTE, key, encoder, buffer); 32757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson Attributes attrib = manifest.entries.get(key); 328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Iterator<?> entries = attrib.keySet().iterator(); 329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project while (entries.hasNext()) { 330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Attributes.Name name = (Attributes.Name) entries.next(); 33157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson writeEntry(out, name, attrib.getValue(name), encoder, buffer); 332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project out.write(LINE_SEPARATOR); 334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 33757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson private static void writeEntry(OutputStream os, Attributes.Name name, 338678e3d534e57c24e3a75a5153cc24714ebdaad8fJesse Wilson String value, CharsetEncoder encoder, ByteBuffer bBuf) throws IOException { 339678e3d534e57c24e3a75a5153cc24714ebdaad8fJesse Wilson String nameString = name.getName(); 340678e3d534e57c24e3a75a5153cc24714ebdaad8fJesse Wilson os.write(nameString.getBytes(Charsets.US_ASCII)); 34157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson os.write(VALUE_SEPARATOR); 34257995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 34357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson encoder.reset(); 344678e3d534e57c24e3a75a5153cc24714ebdaad8fJesse Wilson bBuf.clear().limit(LINE_LENGTH_LIMIT - nameString.length() - 2); 34557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 34657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson CharBuffer cBuf = CharBuffer.wrap(value); 34757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 34857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson while (true) { 349678e3d534e57c24e3a75a5153cc24714ebdaad8fJesse Wilson CoderResult r = encoder.encode(cBuf, bBuf, true); 35057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson if (CoderResult.UNDERFLOW == r) { 35157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson r = encoder.flush(bBuf); 352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 35357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson os.write(bBuf.array(), bBuf.arrayOffset(), bBuf.position()); 354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project os.write(LINE_SEPARATOR); 35557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson if (CoderResult.UNDERFLOW == r) { 35657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson break; 35757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 35857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson os.write(' '); 35957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson bBuf.clear().limit(LINE_LENGTH_LIMIT - 1); 360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 363