Subversion Repositories mkgmap

Rev

Rev 4464 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2007 Steve Ratcliffe
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  This program 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.
 *
 *
 * Author: Steve Ratcliffe
 * Create date: Feb 17, 2008
 */

package uk.me.parabola.mkgmap.osmstyle;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import uk.me.parabola.log.Logger;

/**
 * Load a style from a jar file.
 *
 * The style can just be jared up at the top level or it can be
 * contained within a directory in the jar.  You can have more than one
 * style in the jar.  In this case a name will be required to select
 * the one that you want to use.  It looks for a file with a name that
 * ends with 'version' to work out where the style is.  If a name is given
 * then it looks for a file path ending {@code name/version}.
 *
 * @author Steve Ratcliffe
 */

public class JarFileLoader extends StyleFileLoader implements Closeable {
        private static final Logger log = Logger.getLogger(JarFileLoader.class);
        private JarFile jarFile;
        private String prefix;

        public JarFileLoader(URL url) throws FileNotFoundException {
                jarInit(url, null);
        }

        public JarFileLoader(String url, String name) throws FileNotFoundException {
                try {
                        jarInit(new URL(makeJarUrl(url)), name);
                } catch (MalformedURLException e) {
                        throw new FileNotFoundException("Could not open style at " + url);
                }
        }

        private static String makeJarUrl(String url) {
                if (url.toLowerCase().startsWith("jar:"))
                        return url;
                else
                        return "jar:" + url + "!/";
        }

        private void jarInit(URL url, String name) throws FileNotFoundException {
                log.debug("opening", url);
                try {
                        JarURLConnection jurl = (JarURLConnection) url.openConnection();
                        jurl.setUseCaches(false);
                        jarFile = jurl.getJarFile();
                        prefix = jurl.getEntryName();
                        if (prefix == null) {
                                prefix = searchVersion(jarFile, name);
                        }

                        log.debug("jar prefix is", prefix);
                } catch (IOException e) {
                        throw new FileNotFoundException("Could not open style at " + url);
                }
        }

        /**
         * Find path in archive
         * @param file the JarFile instance
         * @param style a style name or null to find any version file
         * @return return prefix of (first) entry that contains file version
         */

        private static String searchVersion(JarFile file, String style) {
                Enumeration<JarEntry> en = file.entries();
                String flatEnd = style==null ? "version" : style + "/version";
                String end = "/" + flatEnd;
                while (en.hasMoreElements()) {
                        JarEntry entry = en.nextElement();
                        String ename = entry.getName();
                        if (ename.endsWith(end) || ename.equals(flatEnd))
                                return ename.substring(0, ename.length() - "version".length());
                }
                return null;
        }

        /**
         * Open the specified file in the style definition.
         *
         * @param filename The name of the file in the style.
         * @return An open file reader for the file.
         * @throws FileNotFoundException When the file can't be opened.
         */

        public Reader open(String filename) throws FileNotFoundException {
                if (jarFile == null)
                        throw new FileNotFoundException("Could not open file " + filename);

                String path = filename;
                if (prefix != null)
                        path = prefix + filename;
               
                JarEntry jarEntry = jarFile.getJarEntry(path);
                if (jarEntry == null)
                        throw new FileNotFoundException("Could not open style file " + filename);

                InputStream stream;
                try {
                        stream = jarFile.getInputStream(jarEntry);
                } catch (IOException e) {
                        throw new FileNotFoundException("Could not open " + filename);
                }
                Reader reader = new InputStreamReader(stream, StandardCharsets.UTF_8);
                return new BufferedReader(reader);
        }

        public void close() {
                try {
                        jarFile.close();
                } catch (IOException e) {
                        log.debug("failed to close jar file");
                }
        }

        public String[] list() {
                Enumeration<JarEntry> en = jarFile.entries();
                List<String> list = new ArrayList<>();
                while (en.hasMoreElements()) {
                        JarEntry entry = en.nextElement();

                        if (!entry.isDirectory()) {
                                String name = entry.getName();
                                if (name.endsWith("version")) {
                                        log.debug("name is", name);
                                        String[] dirs = name.split("/");
                                        if (dirs.length == 1) {
                                                String s = jarFile.getName();
                                                s = s.replaceFirst("\\..*$", "");
                                                s = s.replaceAll(".*/", "");
                                                list.add(s);
                                        }
                                        else
                                                list.add(dirs[dirs.length - 2]);
                                }
                        }
                }

                return list.toArray(new String[list.size()]);
        }

}