/** @throws IOException java.util.jar.JarFile#getJarEntry(java.lang.String) */ public void test_getEntryLjava_lang_String() throws IOException { try { Support_Resources.copyFile(resources, null, jarName); JarFile jarFile = new JarFile(new File(resources, jarName)); assertEquals("Error in returned entry", 311, jarFile.getEntry(entryName).getSize()); jarFile.close(); } catch (Exception e) { fail("Exception during test: " + e.toString()); } Support_Resources.copyFile(resources, null, jarName); JarFile jarFile = new JarFile(new File(resources, jarName)); Enumeration<JarEntry> enumeration = jarFile.entries(); assertTrue(enumeration.hasMoreElements()); while (enumeration.hasMoreElements()) { JarEntry je = enumeration.nextElement(); jarFile.getEntry(je.getName()); } enumeration = jarFile.entries(); assertTrue(enumeration.hasMoreElements()); JarEntry je = enumeration.nextElement(); try { jarFile.close(); jarFile.getEntry(je.getName()); // fail("IllegalStateException expected."); } catch (IllegalStateException ee) { // Per documentation exception // may be thrown. // expected } }
/** * @return an input stream for the this file in the jar. Closing this stream also closes the jar * file this stream comes from. */ public InputStream getResourceAsStream(String fileName) throws PluginParseException { Validate.notNull(fileName, "The file name must not be null"); final JarFile jar; try { jar = new JarFile(jarFile); } catch (IOException e) { throw new PluginParseException("Cannot open JAR file for reading: " + jarFile, e); } ZipEntry entry = jar.getEntry(fileName); if (entry == null) { return null; } InputStream descriptorStream; try { descriptorStream = new BufferedInputStream(jar.getInputStream(entry)) { // because we do not expose a handle to the jar file this stream is associated with, we // need to make sure // we explicitly close the jar file when we're done with the stream (else we'll have a // file handle leak) public void close() throws IOException { super.close(); jar.close(); } }; } catch (IOException e) { throw new PluginParseException( "Cannot retrieve " + fileName + " from plugin JAR [" + jarFile + "]", e); } return descriptorStream; }
public void connect() throws IOException { if (!connected) { String path = url.getPath(); Matcher matcher = urlPattern.matcher(path); if (matcher.matches()) { path = matcher.group(1); String subPath = matcher.group(2); JarURLConnection jarURLConnection = (JarURLConnection) new URL("jar:" + path).openConnection(); inputStream = jarURLConnection.getInputStream(); if (subPath.isEmpty() == false) { JarFile jar = retrieve(new URL(path), inputStream); String[] nodes = nestingSeparatorPattern.split(subPath); int i; for (i = 0; i < nodes.length - 1; i++) { path += "!/" + nodes[i]; jar = retrieve(new URL(path), inputStream); } ZipEntry entry = jar.getEntry(nodes[i]); entrySize = entry.getSize(); inputStream = jar.getInputStream(entry); } } else { throw new MalformedURLException("Invalid JAP URL path: " + path); } connected = true; } }
protected boolean jarUpToDate(String source, String target, boolean verbose) { JarFile targetJar, sourceJar; try { targetJar = new JarFile(target); } catch (IOException e) { if (verbose) err.println(target + " does not exist yet"); return false; } try { sourceJar = new JarFile(source); } catch (IOException e) { return true; } for (JarEntry entry : Collections.list(sourceJar.entries())) { JarEntry other = (JarEntry) targetJar.getEntry(entry.getName()); if (other == null) { if (verbose) err.println(target + " lacks the file " + entry.getName()); return false; } if (entry.getTime() > other.getTime()) { if (verbose) err.println(target + " is not " + "up-to-date because of " + entry.getName()); return false; } } try { targetJar.close(); sourceJar.close(); } catch (IOException e) { } return true; }
public byte[] read(String path) throws IOException { ZipEntry entry = m_source.getEntry(getInternalPath(path)); if (entry == null) { throw new IOException("Jar Entry is not found for class " + path + "."); } return Streams.readBytes(m_source.getInputStream(entry)); }
@SuppressWarnings("unchecked") private static void loadBots() { logger.info("Loading available bots"); final Collection<File> botJars = FileUtils.listFiles(botsDirecotry, new String[] {"jar"}, false); for (File botJar : botJars) { try { JarFile jar = new JarFile(botJar); ZipEntry entry = jar.getEntry("bot.yml"); if (entry == null) throw new RuntimeException("Bot has no bot.yml file!"); InputStream is = jar.getInputStream(entry); YAMLNode n = new YAMLNode(new Yaml().loadAs(is, Map.class), true); String mainClass = n.getString("mainClass"); String type = n.getString("type"); URLClassLoader loader = new URLClassLoader(new URL[] {botJar.toURI().toURL()}, Chatty.class.getClassLoader()); BOT_INFO.put(type, new BotClassInfo(loader.loadClass(mainClass).asSubclass(Bot.class), n)); logger.info("Loaded bot '{}'", type); } catch (Exception e) { logger.error("Failed to load bot from {}", botJar.getName()); e.printStackTrace(); } } logger.info("Loaded {} bot(s)", BOT_INFO.size()); }
@Test public void getEntryTime() throws Exception { java.util.jar.JarFile jdkJarFile = new java.util.jar.JarFile(this.rootJarFile); assertThat(this.jarFile.getEntry("META-INF/MANIFEST.MF").getTime()) .isEqualTo(jdkJarFile.getEntry("META-INF/MANIFEST.MF").getTime()); jdkJarFile.close(); }
public static boolean isJarDirectory(String path) { if (isJarFile()) { try { JarFile jar = new JarFile(getJarFile()); ZipEntry entry = jar.getEntry(path); return entry != null && entry.isDirectory(); } catch (Exception e) { e.printStackTrace(); } } else { try { URL url = FileUtilities.class.getResource("/" + path); if (url != null) { URI uri = url.toURI(); File classpath = new File(uri); return classpath.isDirectory(); } else { return false; } } catch (Exception e) { e.printStackTrace(); } } return false; }
@SuppressWarnings("unchecked") private static void startPlugins() { logger.info("Loading available plugins"); final Collection<File> botJars = FileUtils.listFiles(pluginsDirecotry, new String[] {"jar"}, false); for (File botJar : botJars) { try { JarFile jar = new JarFile(botJar); ZipEntry ze = jar.getEntry("plugin.yml"); if (ze == null) throw new RuntimeException("Plugin has no plugin.yml file!"); InputStream is = jar.getInputStream(ze); YAMLNode n = new YAMLNode(new Yaml().loadAs(is, Map.class), true); String mainClass = n.getString("mainClass"); String name = n.getString("name"); URLClassLoader loader = new URLClassLoader(new URL[] {botJar.toURI().toURL()}, Chatty.class.getClassLoader()); Plugin plugin = loader.loadClass(mainClass).asSubclass(Plugin.class).newInstance(); plugin.start(); PLUGIN_INFO.put(name, new PluginInfo(name, plugin, n)); logger.info("Loaded plugin '{}'", name); } catch (Exception e) { logger.error("Failed to load plugin from {}", botJar.getName()); e.printStackTrace(); } } logger.info("Loaded {} plugin(s)", PLUGIN_INFO.size()); }
@SuppressWarnings("resource") public InputStream getInputStream() throws IOException { // 注:JarFile与File的设计是不一样的,File相当于C#的FileInfo,只持有信息, // 而JarFile构造时即打开流,所以每次读取数据时,重新new新的实例,而不作为属性字段持有。 JarFile jarFile = new JarFile(file); return jarFile.getInputStream(jarFile.getEntry(getName())); }
private void determineNameMapping(JarFile paramJarFile, Set paramSet, Map paramMap) throws IOException { InputStream localInputStream = paramJarFile.getInputStream(paramJarFile.getEntry("META-INF/INDEX.JD")); if (localInputStream == null) handleException("jardiff.error.noindex", null); LineNumberReader localLineNumberReader = new LineNumberReader(new InputStreamReader(localInputStream, "UTF-8")); String str = localLineNumberReader.readLine(); if ((str == null) || (!str.equals("version 1.0"))) handleException("jardiff.error.badheader", str); while ((str = localLineNumberReader.readLine()) != null) { List localList; if (str.startsWith("remove")) { localList = getSubpaths(str.substring("remove".length())); if (localList.size() != 1) handleException("jardiff.error.badremove", str); paramSet.add(localList.get(0)); continue; } if (str.startsWith("move")) { localList = getSubpaths(str.substring("move".length())); if (localList.size() != 2) handleException("jardiff.error.badmove", str); if (paramMap.put(localList.get(1), localList.get(0)) != null) handleException("jardiff.error.badmove", str); continue; } if (str.length() <= 0) continue; handleException("jardiff.error.badcommand", str); } localLineNumberReader.close(); localInputStream.close(); }
/** * Take the name of a jar file and extract the plugin.xml file, if possible, to a temporary file. * * @param f The jar file to extract from. * @return a temporary file to which the plugin.xml file has been copied. */ public static File unpackPluginXML(File f) { InputStream in = null; OutputStream out = null; try { JarFile jar = new JarFile(f); ZipEntry entry = jar.getEntry(PLUGIN_XML_FILE); if (entry == null) { return null; } File dest = File.createTempFile("jabref_plugin", ".xml"); dest.deleteOnExit(); in = new BufferedInputStream(jar.getInputStream(entry)); out = new BufferedOutputStream(new FileOutputStream(dest)); byte[] buffer = new byte[2048]; for (; ; ) { int nBytes = in.read(buffer); if (nBytes <= 0) break; out.write(buffer, 0, nBytes); } out.flush(); return dest; } catch (IOException ex) { ex.printStackTrace(); return null; } finally { try { if (out != null) out.close(); if (in != null) in.close(); } catch (IOException ex) { ex.printStackTrace(); } } }
/** * This is difficult to implement and close out resources underneath. Delaying until someone * actually requests this. * * <p>If we actually contain the entry throw UnsupportedOperationException, else return null in * case another classloader can handle this. */ @Override public URL getResource(String name) { for (JarFile j : _jars) { ZipEntry entry = j.getEntry(name); if (entry != null) { throw new UnsupportedOperationException( ErrorMessages.GET_RESOURCE_NOT_IMPLEMENTED + name); // $NON-NLS-1$ } } return null; }
public long getLength() { try { JarFile jarFile = new JarFile(file); try { return jarFile.getEntry(getName()).getSize(); } finally { jarFile.close(); } } catch (IOException e) { return super.getLength(); } }
private String getSubsonicBuildNumber() { File war = new File(getWar()); InputStream in = null; try { if (war.isFile()) { JarFile jar = new JarFile(war); ZipEntry entry = jar.getEntry("WEB-INF\\classes\\build_number.txt"); if (entry == null) { entry = jar.getEntry("WEB-INF/classes/build_number.txt"); } in = jar.getInputStream(entry); } else { in = new FileInputStream(war.getPath() + "/WEB-INF/classes/build_number.txt"); } return IOUtils.toString(in); } catch (Exception x) { System.err.println("Failed to resolve build number from WAR " + war + ": " + x); return null; } finally { IOUtils.closeQuietly(in); } }
private Path findJarWithSecureStore(SitePaths sitePaths, String secureStoreClass) throws IOException { List<Path> jars = SiteLibraryLoaderUtil.listJars(sitePaths.lib_dir); String secureStoreClassPath = secureStoreClass.replace('.', '/') + ".class"; for (Path jar : jars) { try (JarFile jarFile = new JarFile(jar.toFile())) { ZipEntry entry = jarFile.getEntry(secureStoreClassPath); if (entry != null) { return jar; } } catch (IOException e) { log.error(e.getMessage(), e); } } return null; }
private boolean testExecutionMode() { executionMode = false; JarFile file = null; try { file = new JarFile(getTangaraPath()); ZipEntry entry = file.getEntry(EXECUTION_PROPERTIES_FILENAME); if (entry != null) { executionMode = true; System.out.println("execution mode detected"); Properties executionProperties = new Properties(); InputStream ips = ClassLoader.getSystemResourceAsStream(EXECUTION_PROPERTIES_FILENAME); executionProperties.load(ips); if (executionProperties.containsKey("main-program")) { String mainTangaraFile = executionProperties.getProperty("main-program"); System.out.println("main tangara file: " + mainTangaraFile); properties.setProperty("main-program", mainTangaraFile); } else { System.err.println("error : main program not specified"); } if (executionProperties.containsKey("language")) { String language = executionProperties.getProperty("language"); properties.setProperty("language", language); System.out.println("language: " + language); } else { System.err.println("error : language not specified"); } if (executionProperties.containsKey("resources")) { String resources = executionProperties.getProperty("resources"); properties.setProperty("program.resources", resources); System.out.println("resources: " + resources); } else { System.err.println("error : resources not specified"); } } } catch (IOException e) { e.printStackTrace(); } finally { if (file != null) { try { file.close(); } catch (IOException e) { System.err.println("error while closing tangara JAR file"); } } } return executionMode; }
private static Properties loadBuildProperties() { Properties properties = new Properties(); Manifest manifest = null; JarFile jar = null; try { URL url = BuildInfo.class.getProtectionDomain().getCodeSource().getLocation(); File file = new File(url.toURI()); jar = new JarFile(file); ZipEntry entry = jar.getEntry("META-INF/build-stamp.properties"); if (entry != null) { try (InputStream stream = jar.getInputStream(entry)) { properties.load(stream); } } manifest = jar.getManifest(); } catch (IllegalArgumentException | IOException | NullPointerException | URISyntaxException ignored) { } finally { if (jar != null) { try { jar.close(); } catch (IOException e) { // ignore } } } if (manifest == null) { return properties; } try { Attributes attributes = manifest.getAttributes("Build-Info"); Set<Entry<Object, Object>> entries = attributes.entrySet(); for (Entry<Object, Object> e : entries) { properties.put(String.valueOf(e.getKey()), String.valueOf(e.getValue())); } } catch (NullPointerException e) { // Fall through } return properties; }
public synchronized void connect() throws IOException { // Call is ignored if already connected. if (connected) return; jar_url = getJarFileURL(); jar_file = JarFileCache.get(jar_url, useCaches); String entry_name = getEntryName(); if (entry_name != null && !entry_name.equals("")) { jar_entry = (JarEntry) jar_file.getEntry(entry_name); if (jar_entry == null) throw new FileNotFoundException("No entry for " + entry_name + " exists."); } connected = true; }
/** * Create a default configuration file from the .jar. * * @param name */ protected void createDefaultConfiguration(String name) { File actual = new File(getDataFolder(), name); if (!actual.exists()) { InputStream input = null; try { JarFile file = new JarFile(getFile()); ZipEntry copy = file.getEntry("defaults/" + name); if (copy == null) throw new FileNotFoundException(); input = file.getInputStream(copy); } catch (IOException e) { getLogger().severe("Unable to read default configuration: " + name); } if (input != null) { FileOutputStream output = null; try { output = new FileOutputStream(actual); byte[] buf = new byte[8192]; int length = 0; while ((length = input.read(buf)) > 0) { output.write(buf, 0, length); } getLogger().info("Default configuration file written: " + name); } catch (IOException e) { e.printStackTrace(); } finally { try { if (input != null) { input.close(); } } catch (IOException e) { } try { if (output != null) { output.close(); } } catch (IOException e) { } } } } }
/** * Jarファイル内から直接 messages_en.yml を読み込み、 defaultMessagesとしてロードする。 * * @param _jar jarファイル * @param _configFolder コンフィグフォルダ * @param lang デフォルト言語 */ protected static void initialize(File _jar, File _configFolder, String lang) { jar = _jar; configFolder = _configFolder; // コンフィグフォルダにメッセージファイルがまだ無いなら、コピーしておく for (String filename : new String[] {"messages_en.yml", "messages_ja.yml"}) { File file = new File(configFolder, filename); if (!file.exists()) { Utility.copyFileFromJar(jar, file, filename, false); } } // デフォルトメッセージを、jarファイル内からロードする defaultMessages = new YamlConfiguration(); JarFile jarFile = null; try { jarFile = new JarFile(jar); ZipEntry zipEntry = jarFile.getEntry(String.format("messages_%s.yml", lang)); InputStream inputStream = jarFile.getInputStream(zipEntry); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); String line; while ((line = reader.readLine()) != null) { if (line.contains(":") && !line.startsWith("#")) { String key = line.substring(0, line.indexOf(":")).trim(); String value = line.substring(line.indexOf(":") + 1).trim(); if (value.startsWith("'") && value.endsWith("'")) value = value.substring(1, value.length() - 1); defaultMessages.set(key, value); } } } catch (IOException e) { e.printStackTrace(); } finally { if (jarFile != null) { try { jarFile.close(); } catch (IOException e) { // do nothing. } } } }
@Override public synchronized InputStream getResourceAsStream(String name) { InputStream input = getParent().getResourceAsStream(name); if (input != null) return input; if (!_open) return null; for (JarFile j : _jars) { try { ZipEntry entry = j.getEntry(name); if (entry != null) { InputStream zipInput = j.getInputStream(entry); return openInputStream(zipInput); } } catch (IOException ioe) { TapestryCore.logError(ErrorMessages.UNABLE_TO_GET_ENTRY_FROM_JAR + j, ioe); // $NON-NLS-1$ } } return null; }
private static void copyFileFromJar(String sourceFileName, File target) { try { JarFile jar = new JarFile(privateInstance.getHome()); ZipEntry entry = jar.getEntry(sourceFileName); InputStream inputStream = new BufferedInputStream(jar.getInputStream(entry)); OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(target)); byte[] buffer = new byte[4096]; for (; ; ) { int nBytes = inputStream.read(buffer); if (nBytes <= 0) break; outputStream.write(buffer, 0, nBytes); } outputStream.flush(); outputStream.close(); inputStream.close(); } catch (FileNotFoundException e) { JOptionPane.showMessageDialog(null, e); } catch (IOException e) { JOptionPane.showMessageDialog(null, e); } }
private static String getStringFromJar(String resourceIdentifier) { StringBuilder result = new StringBuilder(); try { JarFile jar = new JarFile(privateInstance.getHome()); ZipEntry entry = jar.getEntry(resourceIdentifier); BufferedReader inputReader = new BufferedReader(new InputStreamReader(jar.getInputStream(entry))); String newLine; while ((newLine = inputReader.readLine()) != null) { result.append(newLine); } inputReader.close(); } catch (FileNotFoundException e) { JOptionPane.showMessageDialog(null, e); } catch (IOException e) { JOptionPane.showMessageDialog(null, e); } return result.toString(); }
/* * The content of Test.class is modified, jarFile.getInputStream will not * throw security Exception, but it will anytime before the inputStream got * from getInputStream method has been read to end. */ public void test_JarFile_Modified_Class() throws IOException { String modifiedJarName = "Modified_Class.jar"; Support_Resources.copyFile(resources, null, modifiedJarName); JarFile jarFile = new JarFile(new File(resources, modifiedJarName), true); Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { ZipEntry zipEntry = entries.nextElement(); jarFile.getInputStream(zipEntry); } /* The content of Test.class has been tampered. */ ZipEntry zipEntry = jarFile.getEntry("Test.class"); InputStream in = jarFile.getInputStream(zipEntry); byte[] buffer = new byte[1024]; try { while (in.available() > 0) { in.read(buffer); } fail("SecurityException expected"); } catch (SecurityException e) { // desired } }
public Image getImage(String sImage) { Image imReturn = null; try { if (jar == null) { imReturn = this.toolkit.createImage(this.getClass().getClassLoader().getResource(sImage)); } else { // BufferedInputStream bis = new BufferedInputStream(jar.getInputStream(jar.getEntry(sImage))); ByteArrayOutputStream buffer = new ByteArrayOutputStream(4096); int b; while ((b = bis.read()) != -1) { buffer.write(b); } byte[] imageBuffer = buffer.toByteArray(); imReturn = this.toolkit.createImage(imageBuffer); bis.close(); buffer.close(); } } catch (IOException ex) { } return imReturn; }
private void verifyKeystoreFilePresence(JarFile outputWar) { assertNotNull(outputWar.getEntry(WEB_INF_CLASSES + KEYSTORE_FILE_NAMES_PARAM_VALUE)); }
private void verifyPresenceOfInternalKeyStore(JarFile outputWar) { assertNotNull(outputWar.getEntry(SOAP_KEYSTORE_JAR_ENTRY_NAME)); }
public void enhance(@Observes final BeforeDeploymentEvent event) { if (enhancerMethod == null) { LOGGER.debug("OpenJPA is not available so no deploy-time enhancement will be done"); return; } // find persistence.xml final Map<String, List<String>> classesByPXml = new HashMap<String, List<String>>(); final List<URL> usedUrls = new ArrayList<URL>(); // for fake classloader for (URL url : event.getUrls()) { final File file = URLs.toFile(url); if (file.isDirectory()) { final String pXmls = getWarPersistenceXml(url); if (pXmls != null) { feed(classesByPXml, pXmls); } usedUrls.add(url); } else if (file.getName().endsWith(".jar")) { try { final JarFile jar = new JarFile(file); ZipEntry entry = jar.getEntry(META_INF_PERSISTENCE_XML); if (entry != null) { final String path = file.getAbsolutePath(); final File unpacked = new File(path.substring(0, path.length() - 4) + TMP_ENHANCEMENT_SUFFIX); JarExtractor.extract(file, unpacked); // replace jar by folder url since otherwise enhancement doesn't work usedUrls.add(unpacked.toURI().toURL()); feed(classesByPXml, new File(unpacked, META_INF_PERSISTENCE_XML).getAbsolutePath()); } } catch (IOException e) { // ignored } } else { usedUrls.add(url); } } // enhancement final ClassLoader tccl = Thread.currentThread().getContextClassLoader(); final ClassLoader fakeClassLoader = new URLClassLoaderFirst( usedUrls.toArray(new URL[usedUrls.size()]), event.getParentClassLoader()); Thread.currentThread().setContextClassLoader(fakeClassLoader); try { for (Map.Entry<String, List<String>> entry : classesByPXml.entrySet()) { final Properties opts = new Properties(); opts.setProperty(PROPERTIES_FILE_PROP, entry.getKey()); final Object optsArg; try { optsArg = optionsConstructor.newInstance(opts); } catch (Exception e) { LOGGER.debug("can't create options for enhancing"); return; } LOGGER.info("enhancing url(s): " + Arrays.asList(event.getUrls())); try { enhancerMethod.invoke(null, toFilePaths(entry.getValue()), optsArg); } catch (Exception e) { LOGGER.warning("can't enhanced at deploy-time entities", e); } } } finally { Thread.currentThread().setContextClassLoader(tccl); usedUrls.clear(); } // clean up extracted jars and replace jar to keep consistent classloading for (Map.Entry<String, List<String>> entry : classesByPXml.entrySet()) { final List<String> values = entry.getValue(); for (String rawPath : values) { if (rawPath.endsWith(TMP_ENHANCEMENT_SUFFIX + "/") || rawPath.endsWith(TMP_ENHANCEMENT_SUFFIX)) { final File dir = new File(rawPath); final File file = new File( rawPath.substring(0, rawPath.length() - TMP_ENHANCEMENT_SUFFIX.length() - 1) + ".jar"); if (file.exists()) { String name = dir.getName(); name = name.substring(0, name.length() - TMP_ENHANCEMENT_SUFFIX.length()) + ".jar"; final File target = new File(dir.getParentFile(), name); try { // override existing jar otherwise classloading is broken in tomee Files.delete(file); JarCreator.jarDir(dir, target); } catch (final IOException e) { LOGGER.error("can't repackage enhanced jar file " + file.getName()); } Files.delete(dir); } } } values.clear(); } classesByPXml.clear(); }
// Do an update from the given repo. All applications found, and their // APKs, are added to 'apps'. (If 'apps' already contains an app, its // APKs are merged into the existing one). // Returns null if successful, otherwise an error message to be displayed // to the user (if there is an interactive user!) // 'newetag' should be passed empty. On success, it may contain an etag // value for the index that was successfully processed, or it may contain // null if none was available. public static String doUpdate( Context ctx, DB.Repo repo, List<DB.App> apps, StringBuilder newetag, List<Integer> keeprepos, ProgressListener progressListener) { try { int code = 0; if (repo.pubkey != null) { // This is a signed repo - we download the jar file, // check the signature, and extract the index... Log.d( "FDroid", "Getting signed index from " + repo.address + " at " + logDateFormat.format(new Date(System.currentTimeMillis()))); String address = repo.address + "/index.jar"; PackageManager pm = ctx.getPackageManager(); try { PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), 0); address += "?" + pi.versionName; } catch (Exception e) { } Bundle progressData = createProgressData(repo.address); ProgressListener.Event event = new ProgressListener.Event(RepoXMLHandler.PROGRESS_TYPE_DOWNLOAD, progressData); code = getRemoteFile( ctx, address, "tempindex.jar", repo.lastetag, newetag, progressListener, event); if (code == 200) { String jarpath = ctx.getFilesDir() + "/tempindex.jar"; JarFile jar = null; JarEntry je; Certificate[] certs; try { jar = new JarFile(jarpath, true); je = (JarEntry) jar.getEntry("index.xml"); File efile = new File(ctx.getFilesDir(), "/tempindex.xml"); InputStream input = null; OutputStream output = null; try { input = jar.getInputStream(je); output = new FileOutputStream(efile); Utils.copy(input, output); } finally { Utils.closeQuietly(output); Utils.closeQuietly(input); } certs = je.getCertificates(); } catch (SecurityException e) { Log.e("FDroid", "Invalid hash for index file"); return "Invalid hash for index file"; } finally { if (jar != null) { jar.close(); } } if (certs == null) { Log.d("FDroid", "No signature found in index"); return "No signature found in index"; } Log.d( "FDroid", "Index has " + certs.length + " signature" + (certs.length > 1 ? "s." : ".")); boolean match = false; for (Certificate cert : certs) { String certdata = Hasher.hex(cert.getEncoded()); if (repo.pubkey.equals(certdata)) { match = true; break; } } if (!match) { Log.d("FDroid", "Index signature mismatch"); return "Index signature mismatch"; } } } else { // It's an old-fashioned unsigned repo... Log.d("FDroid", "Getting unsigned index from " + repo.address); Bundle eventData = createProgressData(repo.address); ProgressListener.Event event = new ProgressListener.Event(RepoXMLHandler.PROGRESS_TYPE_DOWNLOAD, eventData); code = getRemoteFile( ctx, repo.address + "/index.xml", "tempindex.xml", repo.lastetag, newetag, progressListener, event); } if (code == 200) { // Process the index... SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); XMLReader xr = sp.getXMLReader(); RepoXMLHandler handler = new RepoXMLHandler(repo, apps, progressListener); xr.setContentHandler(handler); File tempIndex = new File(ctx.getFilesDir() + "/tempindex.xml"); BufferedReader r = new BufferedReader(new FileReader(tempIndex)); // A bit of a hack, this might return false positives if an apps description // or some other part of the XML file contains this, but it is a pretty good // estimate and makes the progress counter more informative. // As with asking the server about the size of the index before downloading, // this also has a time tradeoff. It takes about three seconds to iterate // through the file and count 600 apps on a slow emulator (v17), but if it is // taking two minutes to update, the three second wait may be worth it. final String APPLICATION = "<application"; handler.setTotalAppCount(Utils.countSubstringOccurrence(tempIndex, APPLICATION)); InputSource is = new InputSource(r); xr.parse(is); if (handler.pubkey != null && repo.pubkey == null) { // We read an unsigned index, but that indicates that // a signed version is now available... Log.d("FDroid", "Public key found - switching to signed repo for future updates"); repo.pubkey = handler.pubkey; try { DB db = DB.getDB(); db.updateRepoByAddress(repo); } finally { DB.releaseDB(); } } } else if (code == 304) { // The index is unchanged since we last read it. We just mark // everything that came from this repo as being updated. Log.d("FDroid", "Repo index for " + repo.address + " is up to date (by etag)"); keeprepos.add(repo.id); // Make sure we give back the same etag. (The 200 route will // have supplied a new one. newetag.append(repo.lastetag); } else { return "Failed to read index - HTTP response " + Integer.toString(code); } } catch (SSLHandshakeException sslex) { Log.e( "FDroid", "SSLHandShakeException updating from " + repo.address + ":\n" + Log.getStackTraceString(sslex)); return "A problem occurred while establishing an SSL connection. If this problem persists, AND you have a very old device, you could try using http instead of https for the repo URL."; } catch (Exception e) { Log.e( "FDroid", "Exception updating from " + repo.address + ":\n" + Log.getStackTraceString(e)); return "Failed to update - " + e.getMessage(); } finally { ctx.deleteFile("tempindex.xml"); ctx.deleteFile("tempindex.jar"); } return null; }