/* This file is part of VoltDB. * Copyright (C) 2008-2010 VoltDB L.L.C. * * VoltDB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * VoltDB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with VoltDB. If not, see <http://www.gnu.org/licenses/>. */ package org.voltdb.utils; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarInputStream; import java.util.zip.CRC32; /** * Read a text file from within a Jarfile and return the contents as * a string value. This is used by the Catalog deserialization * currently. * */ public class JarReader { protected final JarFile m_jarFile; protected final String m_jarPath; public JarReader(String jarPath) throws IOException { m_jarPath = jarPath; m_jarFile = new JarFile(m_jarPath); } /** * Read filename's contents from m_jarPath's jar file. * @param filename */ public byte[] readFileFromJar(String filename) { return readFileFromJarAtURL(m_jarPath, filename); } /** * Read jar contents from an HTTP URL or a local file. * @param filename The path of the file within the jar to read. * @return An array of bytes representing the contents of the file. */ static public byte[] readFileFromJarAtURL(String jarpath, String filename) { JarInputStream jarIn = JarReader.openJar(jarpath); if (jarIn == null) return (null); byte[] bytes = null; try { JarEntry catEntry = jarIn.getNextJarEntry(); while ((catEntry != null) && (catEntry.getName().equals(filename) == false)) { catEntry = jarIn.getNextJarEntry(); } if (catEntry == null) { return null; } int totalRead = 0; int maxToRead = 4096 << 10; byte buffer[] = new byte[maxToRead]; bytes = new byte[maxToRead * 2]; // Keep reading until we run out of bytes for this entry // We will resize our return value byte array if we run out of space while (jarIn.available() == 1) { int readSize = jarIn.read(buffer, 0, buffer.length); if (readSize > 0) { totalRead += readSize; if (totalRead > bytes.length) { byte temp[] = new byte[bytes.length * 2]; System.arraycopy(bytes, 0, temp, 0, bytes.length); bytes = temp; } System.arraycopy(buffer, 0, bytes, totalRead - readSize, readSize); } } // Trim bytes to proper size byte temp[] = new byte[totalRead]; System.arraycopy(bytes, 0, temp, 0, totalRead); bytes = temp; } catch (IOException e) { e.printStackTrace(); } return bytes; } static public long crcForJar(String jarpath) throws IOException { InputStream fin = openJarFile(jarpath); if (fin == null) throw new FileNotFoundException(); CRC32 crc = new CRC32(); int b = -1; while ((b = fin.read()) != -1) crc.update(b); return crc.getValue(); } /** * * @param jarpath * @return */ static JarInputStream openJar(String jarpath) { InputStream fin = openJarFile(jarpath); if (fin == null) return null; JarInputStream jarIn = null; try { jarIn = new JarInputStream(fin); } catch (IOException ioex) { return null; } return jarIn; } private static InputStream openJarFile(String jarpath) { URL jar_url = null; InputStream fin = null; try { jar_url = new URL(jarpath); fin = jar_url.openStream(); } catch (MalformedURLException ex) { // Invalid URL. Try as a file. try { fin = new FileInputStream(jarpath); } catch (FileNotFoundException e) { return null; } } catch (IOException ioex) { return null; } return fin; } /** * @return The list of paths of files stored in this Jar. */ public List<String> getContentsFromJarfile() { JarInputStream jarIn = JarReader.openJar(m_jarPath); List<String> files = new ArrayList<String>(); try { JarEntry catEntry = null; while ((catEntry = jarIn.getNextJarEntry()) != null) { files.add(catEntry.getName()); } } catch (Exception ex) { return null; } return files; } /** * Read a text file from within a Jarfile and return the contents as * a string value. This is used by the Catalog deserialization * currently. Jarpath can be an HTTP URL or a local filename. * * @param jarpath Path to the jarfile * @param filename Filename within the jarfile * @return A string of the contents of the embedded file or null on failure. */ public static String readFileFromJarfile(String jarpath, String filename) throws IOException { String retval = null; byte[] bytes = JarReader.readFileFromJarAtURL(jarpath, filename); retval = new String(bytes, 0, bytes.length, "UTF-8"); return retval; } /** * Read a file from a jar in the form path/to/jar.jar!/path/to/file.ext */ public static String readFileFromJarfile(String fulljarpath) throws IOException { assert (fulljarpath.contains(".jar!")); String[] paths = fulljarpath.split("!"); if (paths[0].startsWith("file:")) paths[0] = paths[0].substring("file:".length()); paths[1] = paths[1].substring(1); return JarReader.readFileFromJarfile(paths[0], paths[1]); } }