1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/* 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 8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 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 185aafac4db69e6d087c512cdfa5c7c0e2f1611681Jesse Wilsonpackage libcore.net.url; 19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.File; 21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FileNotFoundException; 22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FileOutputStream; 23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FilterInputStream; 24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException; 25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream; 26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.ContentHandler; 27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.ContentHandlerFactory; 285839b909d9528b7726e678a4b696ed37df15d897Jesse Wilsonimport java.net.JarURLConnection; 29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.MalformedURLException; 30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.URL; 31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.Permission; 32f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonimport java.util.HashMap; 33f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonimport java.util.Iterator; 34f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonimport java.util.Map; 35f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonimport java.util.Set; 36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.jar.JarEntry; 37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.jar.JarFile; 38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.zip.ZipFile; 395aafac4db69e6d087c512cdfa5c7c0e2f1611681Jesse Wilsonimport libcore.net.UriCodec; 40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 425839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * This subclass extends {@code URLConnection}. 43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p> 44f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This class is responsible for connecting and retrieving resources from a Jar 465839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * file which can be anywhere that can be referred to by an URL. 47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 485839b909d9528b7726e678a4b696ed37df15d897Jesse Wilsonpublic class JarURLConnectionImpl extends JarURLConnection { 49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 5059675dbb837c2a92352032e2ef0c8fc3305da9c8Elliott Hughes private static final HashMap<URL, JarFile> jarCache = new HashMap<URL, JarFile>(); 51f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 52f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private URL jarFileURL; 53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 54f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private InputStream jarInput; 55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private JarFile jarFile; 57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private JarEntry jarEntry; 59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 60f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private boolean closed; 61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param url 64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the URL of the JAR 65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws MalformedURLException 66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if the URL is malformed 675839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * @throws IOException 685839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * if there is a problem opening the connection. 69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 7059675dbb837c2a92352032e2ef0c8fc3305da9c8Elliott Hughes public JarURLConnectionImpl(URL url) throws MalformedURLException, IOException { 71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project super(url); 72f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson jarFileURL = getJarFileURL(); 73f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson jarFileURLConnection = jarFileURL.openConnection(); 74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see java.net.URLConnection#connect() 78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void connect() throws IOException { 81f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (!connected) { 82f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson findJarFile(); // ensure the file can be found 83f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson findJarEntry(); // ensure the entry, if any, can be found 84f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson connected = true; 85f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 895839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * Returns the Jar file referred by this {@code URLConnection}. 90f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * thrown if an IO error occurs while connecting to the 93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * resource. 94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public JarFile getJarFile() throws IOException { 97f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson connect(); 98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return jarFile; 99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 1025839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * Returns the Jar file referred by this {@code URLConnection} 103f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if an IO error occurs while connecting to the resource. 106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private void findJarFile() throws IOException { 108f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (getUseCaches()) { 1095839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson synchronized (jarCache) { 110f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson jarFile = jarCache.get(jarFileURL); 111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 112f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (jarFile == null) { 11359675dbb837c2a92352032e2ef0c8fc3305da9c8Elliott Hughes JarFile jar = openJarFile(); 1145839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson synchronized (jarCache) { 115f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson jarFile = jarCache.get(jarFileURL); 1165839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson if (jarFile == null) { 117f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson jarCache.put(jarFileURL, jar); 118f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson jarFile = jar; 1195839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson } else { 120f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson jar.close(); 121f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 122f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1245839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson } else { 125f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson jarFile = openJarFile(); 126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 128f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (jarFile == null) { 129f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson throw new IOException(); 130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 131f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 13359675dbb837c2a92352032e2ef0c8fc3305da9c8Elliott Hughes private JarFile openJarFile() throws IOException { 1345839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson if (jarFileURL.getProtocol().equals("file")) { 13556099d23fcb002b164bff8fb7f14d6ec0453509eJesse Wilson String decodedFile = UriCodec.decode(jarFileURL.getFile()); 13656099d23fcb002b164bff8fb7f14d6ec0453509eJesse Wilson return new JarFile(new File(decodedFile), true, ZipFile.OPEN_READ); 137a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson } else { 138f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson final InputStream is = jarFileURL.openConnection().getInputStream(); 139f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 140ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes FileOutputStream fos = null; 141ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes JarFile result = null; 142ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes try { 143ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes File tempJar = File.createTempFile("hyjar_", ".tmp", null); 144ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes tempJar.deleteOnExit(); 145ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes fos = new FileOutputStream(tempJar); 146ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes byte[] buf = new byte[4096]; 147ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes int nbytes = 0; 148ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes while ((nbytes = is.read(buf)) > -1) { 149ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes fos.write(buf, 0, nbytes); 150ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes } 151ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes fos.close(); 152ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes return new JarFile(tempJar, true, ZipFile.OPEN_READ | ZipFile.OPEN_DELETE); 153ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes } catch (IOException e) { 154ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes return null; 155ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes } finally { 156ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes if (fos != null) { 157ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes try { 158ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes fos.close(); 159ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes } catch (IOException ex) { 160ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes return null; 161ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes } 162ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes } 163ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes } 164f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } finally { 1655839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson if (is != null) { 1665839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson is.close(); 1675839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson } 168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 1735839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * Returns the JarEntry of the entry referenced by this {@code 1745839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * URLConnection}. 175f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 1765839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * @return the JarEntry referenced 177f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if an IO error occurs while getting the entry 180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public JarEntry getJarEntry() throws IOException { 183f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson connect(); 184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return jarEntry; 185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 1895839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * Look up the JarEntry of the entry referenced by this {@code 1905839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * URLConnection}. 191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private void findJarEntry() throws IOException { 193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (getEntryName() == null) { 194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return; 195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project jarEntry = jarFile.getJarEntry(getEntryName()); 197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (jarEntry == null) { 198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project throw new FileNotFoundException(getEntryName()); 199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Creates an input stream for reading from this URL Connection. 204f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the input stream 206f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if an IO error occurs while connecting to the resource. 209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public InputStream getInputStream() throws IOException { 212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (closed) { 213b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes throw new IllegalStateException("JarURLConnection InputStream has been closed"); 214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 215f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson connect(); 216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (jarInput != null) { 217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return jarInput; 218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (jarEntry == null) { 220b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes throw new IOException("Jar entry not specified"); 221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return jarInput = new JarURLConnectionInputStream(jarFile 223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getInputStream(jarEntry), jarFile); 224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 2275839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * Returns the content type of the resource. For jar file itself 2285839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * "x-java/jar" should be returned, for jar entries the content type of the 2295839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * entry should be returned. Returns non-null results ("content/unknown" for 2305839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * unknown types). 231f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the content type 233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public String getContentType() { 236f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (url.getFile().endsWith("!/")) { 237f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // the type for jar file itself is always "x-java/jar" 238f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes return "x-java/jar"; 2395839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson } 2405839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson String cType = null; 2415839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson String entryName = getEntryName(); 242f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 2435839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson if (entryName != null) { 2445839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson // if there is an Jar Entry, get the content type from the name 2455839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson cType = guessContentTypeFromName(entryName); 2465839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson } else { 2475839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson try { 2485839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson connect(); 2495839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson cType = jarFileURLConnection.getContentType(); 2505839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson } catch (IOException ioe) { 2515839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson // Ignore 252f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 2545839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson if (cType == null) { 255f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes cType = "content/unknown"; 2565839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson } 2575839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson return cType; 258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the content length of the resource. Test cases reveal that if the 2625839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * URL is referring to a Jar file, this method answers a content-length 263f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * returned by URLConnection. For jar entry it should return it's size. 264f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * Otherwise, it will return -1. 265f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the content length 267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public int getContentLength() { 270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 271f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson connect(); 272f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (jarEntry == null) { 273f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return jarFileURLConnection.getContentLength(); 274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 2755839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson return (int) getJarEntry().getSize(); 276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } catch (IOException e) { 2775839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson // Ignored 278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return -1; 280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 2835839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * Returns the object pointed by this {@code URL}. If this URLConnection is 2845839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * pointing to a Jar File (no Jar Entry), this method will return a {@code 2855839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * JarFile} If there is a Jar Entry, it will return the object corresponding 2865839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * to the Jar entry content type. 287f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return a non-null object 289f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 2915839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson * if an IO error occurred 292f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see ContentHandler 294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see ContentHandlerFactory 295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see java.io.IOException 296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see #setContentHandlerFactory(ContentHandlerFactory) 297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Object getContent() throws IOException { 300f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson connect(); 301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // if there is no Jar Entry, return a JarFile 302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (jarEntry == null) { 303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return jarFile; 304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return super.getContent(); 306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the permission, in this case the subclass, FilePermission object 310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * which represents the permission necessary for this URLConnection to 311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * establish the connection. 312f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the permission required for this URLConnection. 314f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * thrown when an IO exception occurs while creating the 317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * permission. 318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 319f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Permission getPermission() throws IOException { 322f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return jarFileURLConnection.getPermission(); 323f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 324f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 325f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson @Override 326f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson public boolean getUseCaches() { 327f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return jarFileURLConnection.getUseCaches(); 328f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 329f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 330f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson @Override 331f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson public void setUseCaches(boolean usecaches) { 332f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson jarFileURLConnection.setUseCaches(usecaches); 333f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 334f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 335f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson @Override 336f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson public boolean getDefaultUseCaches() { 337f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return jarFileURLConnection.getDefaultUseCaches(); 338f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 339f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 340f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson @Override 341f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson public void setDefaultUseCaches(boolean defaultusecaches) { 342f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson jarFileURLConnection.setDefaultUseCaches(defaultusecaches); 343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private class JarURLConnectionInputStream extends FilterInputStream { 34680b486724ca19b3c1c3c36334d06856330362f83Jesse Wilson final JarFile jarFile; 347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected JarURLConnectionInputStream(InputStream in, JarFile file) { 349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project super(in); 350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project jarFile = file; 351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void close() throws IOException { 355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project super.close(); 356f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (!getUseCaches()) { 357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project closed = true; 358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project jarFile.close(); 359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 363