Subversion Repositories mkgmap

Rev

Rev 3197 | 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: Apr 13, 2008
 */

package uk.me.parabola.mkgmap.osmstyle;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

import uk.me.parabola.imgfmt.Utils;
import uk.me.parabola.log.Logger;

/**
 * Load a style from a single file. All the files that make up the style
 * are held in the same file and delimited by a simple header.
 *
 * <p>Lines before the first header are ignored.  A header looks like this:
 * &lt;&lt;&lt;filename>>>, that is three opening angle brackets, the name
 * of the file and three closing angle brackets.  The opening brackets
 * must be at the beginning of the line, there can be trailing junk after
 * the closing brackets which is ignored.
 *
 * <p>All lines after the header and before the next header or end of file
 * are part of the named file.
 *
 * @author Steve Ratcliffe
 */

public class CombinedStyleFileLoader extends StyleFileLoader {
        private static final Logger log = Logger.getLogger(CombinedStyleFileLoader.class);

        private final Map<String, String> files = new HashMap<>();
        private final String styleName;
        private static final Pattern STYLE_SUFFIX = Pattern.compile("\\.style$");
        private static final Pattern FILENAME_START_MARK = Pattern.compile("<<<");
        private static final Pattern FILENAME_END_MARK = Pattern.compile(">>>.*");

        public CombinedStyleFileLoader(String filename) throws FileNotFoundException {
                styleName = STYLE_SUFFIX.matcher(filename).replaceFirst("");

                Reader in = new FileReader(filename);

                try {
                        loadFiles(in);
                } finally {
                        Utils.closeFile(in);
                }
        }

        private void loadFiles(Reader in) {
                BufferedReader r = new BufferedReader(in);

                StringBuilder currentFile = new StringBuilder();
                try {
                        String line;
                        String currentName = null;
                        while ((line = r.readLine()) != null) {
                                if (line.startsWith("<<<")) {
                                        if (currentName != null) {
                                                // Save previous file if any.
                                                files.put(currentName, currentFile.toString());
                                        }

                                        line = FILENAME_START_MARK.matcher(line).replaceFirst("");
                                        line = FILENAME_END_MARK.matcher(line).replaceFirst("");
                                        log.debug("reading file", line);
                                        currentName = line;
                                        currentFile = new StringBuilder();
                                } else {
                                        currentFile.append(line).append('\n');
                                }
                        }
                        if (currentName == null) {
                                log.error("failed to read style file");
                        } else {
                                files.put(currentName, currentFile.toString());
                        }
                } catch (IOException e) {
                        log.error("failed to read style file");
                }
        }

        /**
         * 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 {
                log.info("opening", filename);
                String contents = files.get(filename);
                if (contents == null)
                        throw new FileNotFoundException(filename);

                log.debug("file", filename, "found");
                return new StringReader(contents);
        }

        /**
         * Close the FileLoader.  This is different from closing individual files that
         * were opened via {@link #open}.  After this call then you shouldn't open any
         * more files.
         */

        public void close() {
                files.clear();
        }

        public String[] list() {
                String basename = styleName.replaceFirst(".*[/\\\\]", "");
                basename = basename.replaceFirst("\\.[^.]+$", "");
                return new String[] {basename};
        }

        /**
         * Covert between the single file simple-archive form and the directory
         * form.  Mostly for fun.
         *
         * @param args Arguments, you supply a directory or a file.  If its a
         * directory then covert into a simple-archive file and if it is a
         * file then expand into separate files.
         */

        public static void main(String[] args) {
                String name = args[0];
                File file = new File(name);

                PrintStream out = System.out;
                try {
                        if (file.isDirectory()) {
                                convertToFile(file, out);
                        } else {
                                String dirname;
                                int ind = name.lastIndexOf('.');
                                if (ind > 0)
                                        dirname = name.substring(0, ind);
                                else
                                        dirname = name + ".d"; // got to do something...
                                convertToDirectory(name, dirname);
                        }
                } catch (FileNotFoundException e) {
                        System.err.println("Could not open file " + e);
                        System.exit(1);
                } catch (IOException e) {
                        System.err.println("Could not read file " + e);
                        System.exit(1);
                }
        }

        private static void convertToDirectory(String name, String dirname) throws IOException {
                try (CombinedStyleFileLoader loader = new CombinedStyleFileLoader(name)) {
                        File dir = new File(dirname);
                        dir.mkdir();
                        for (String s : loader.files.keySet()) {
                                File ent = new File(dir, s);
                                ent.getParentFile().mkdirs();
                                try (FileWriter writer = new FileWriter(ent);
                                                BufferedReader r = new BufferedReader(loader.open(s))) {
                                        String line;
                                        while ((line = r.readLine()) != null) {
                                                writer.write(line);
                                                writer.write('\n');
                                        }
                                }
                        }
                }
        }

        private static void convertToFile(File file, PrintStream out) throws IOException {
                File[] list = file.listFiles(new NoHiddenFilter());
                convertToFile(out, list, null);
        }

        private static void convertToFile(PrintStream out, File[] list, String prefix) throws IOException {
                for (File entry : list) {
                        if (entry.isFile()) {
                                out.print("<<<");
                                if (prefix != null) {
                                        out.print(prefix);
                                        out.print('/');
                                }
                                out.print(entry.getName());
                                out.println(">>>");

                                try (BufferedReader r = new BufferedReader(new FileReader(entry))) {
                                        String line;
                                        while ((line = r.readLine()) != null)
                                                out.println(line);
                                }
                        } else {
                                convertToFile(out, entry.listFiles(new NoHiddenFilter()), entry.getName());
                        }
                }
        }

        private static class NoHiddenFilter implements FilenameFilter {
                public boolean accept(File dir, String name) {
                        return !(name.isEmpty() || name.charAt(0) == '.');
                }
        }
}