Subversion Repositories mkgmap

Rev

Rev 4808 | 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: Nov 15, 2007
 */

package uk.me.parabola.mkgmap.combiners;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

import uk.me.parabola.imgfmt.FileSystemParam;
import uk.me.parabola.imgfmt.MapFailedException;
import uk.me.parabola.imgfmt.ReadFailedException;
import uk.me.parabola.imgfmt.Utils;
import uk.me.parabola.imgfmt.app.Area;
import uk.me.parabola.imgfmt.app.BufferedImgFileReader;
import uk.me.parabola.imgfmt.app.lbl.LBLFileReader;
import uk.me.parabola.imgfmt.app.map.MapReader;
import uk.me.parabola.imgfmt.app.srt.Sort;
import uk.me.parabola.imgfmt.app.trergn.TREFileReader;
import uk.me.parabola.imgfmt.app.trergn.TREHeader;
import uk.me.parabola.imgfmt.fs.DirectoryEntry;
import uk.me.parabola.imgfmt.fs.FileSystem;
import uk.me.parabola.imgfmt.fs.ImgChannel;
import uk.me.parabola.imgfmt.sys.FileImgChannel;
import uk.me.parabola.imgfmt.sys.ImgFS;
import uk.me.parabola.log.Logger;
import uk.me.parabola.mkgmap.CommandArgs;
import uk.me.parabola.mkgmap.srt.SrtTextReader;

import static uk.me.parabola.mkgmap.combiners.FileKind.*;

/**
 * Used for holding information about an individual file that will be made into
 * a gmapsupp file.
 *
 * @author Steve Ratcliffe
 */

public class FileInfo {
        private static final Logger log = Logger.getLogger(FileInfo.class);

        private static final List<String> KNOWN_FILE_TYPE_EXT = Arrays.asList(
                        "TRE", "RGN", "LBL", "NET", "NOD",
                        "TYP"
        );

        // The name of the file.
        private final String filename;

        // The kind of file, see *KIND definitions above.
        private FileKind kind;

        private String mapname;
        private int hexname;
        private String innername;
        private String description;

        // If this is an img file, the size of various sections.
        private int rgnsize;
        private int tresize;
        private int lblsize;
        private int netsize;
        private int nodsize;

        private final List<SubFileInfo> subFiles = new ArrayList<>();
        private String[] licenceInfo;
        private CommandArgs args;
        private String mpsName;
        private int codePage;
        private int sortOrderId;
        private int demsize;
        private MapReader mapReader;

        private FileInfo(String filename, FileKind kind) {
                this.filename = filename;
                this.kind = kind;
        }

        // The area covered by the map, if it is a IMG file
        private Area bounds;

        public String getMapname() {
                return mapname;
        }

        protected void setMapname(String mapname) {
                this.mapname = mapname;
        }

        public String getDescription() {
                return description;
        }

        protected void setDescription(String description) {
                this.description = description;
        }

        public int getRgnsize() {
                return rgnsize;
        }

        protected void setRgnsize(int rgnsize) {
                this.rgnsize = rgnsize;
        }

        public int getTresize() {
                return tresize;
        }

        protected void setTresize(int tresize) {
                this.tresize = tresize;
        }

        public int getLblsize() {
                return lblsize;
        }

        protected void setLblsize(int lblsize) {
                this.lblsize = lblsize;
        }

        public Area getBounds() {
                return bounds;
        }

        /**
         * Create a file info the the given file.
         *
         * @param inputName The filename to examine.
         * @return The FileInfo structure giving information about the file.
         * @throws FileNotFoundException If the file doesn't actually exist.
         */

        public static FileInfo getFileInfo(String inputName) throws FileNotFoundException {
                int end = inputName.length();
                File f = new File(inputName);
                if (f.isDirectory() || end < 3)
                        return new FileInfo(inputName, UNKNOWN_KIND);
               
                String ext = end < 3 ? "" : inputName.substring(end - 3).toUpperCase(Locale.ENGLISH);
                FileInfo info;

                try {
                        if (Objects.equals(ext, "IMG")) {
                                info = imgInfo(inputName);
                        } else if ("TYP".equals(ext)) {
                                info = fileInfo(inputName, TYP_KIND);
                        } else if (KNOWN_FILE_TYPE_EXT.contains(ext)) {
                                info = fileInfo(inputName, APP_KIND);
                        } else {
                                info = new FileInfo(inputName, UNKNOWN_KIND);
                        }
                } catch (AssertionError | ReadFailedException e) {
                        throw new MapFailedException("Could not read file " + inputName, e);
                }
                return info;
        }

        /**
         * A TYP file or a component file that goes into a .img (a TRE, LBL etc).
         * The component files are not usually given on the command line like this
         * but you can do.
         *
         * @param inputName The input file name.
         * @param kind The kind of file being added.
         */

        private static FileInfo fileInfo(String inputName, FileKind kind) {
                FileInfo info = new FileInfo(inputName, kind);

                // Get the size of the file.
                File f = new File(inputName);
                info.subFiles.add(new SubFileInfo(inputName, f.length()));

                if (inputName.toLowerCase().endsWith(".lbl")) {
                        lblInfo(inputName, info);
                } else if (inputName.toLowerCase().endsWith(".typ")) {
                        typInfo(inputName, info);
                }

                return info;
        }

        /**
         * Read information from the TYP file that we might need when combining it with other files.
         * @param filename The name of the file.
         * @param info The information will be stored here.
         */

        private static void typInfo(String filename, FileInfo info) {
                try (ImgChannel chan = new FileImgChannel(filename, "r"); BufferedImgFileReader fr = new BufferedImgFileReader(chan))
                {
                        fr.position(0x15);
                        info.setCodePage(fr.get2u());
                } catch (IOException e) {
                        Logger.defaultLogger.error("Unexpected error reading " + filename, e);
                }
        }

        /**
         * An IMG file, this involves real work. We have to read in the file and
         * extract several pieces of information from it.
         *
         * @param inputName The name of the file.
         * @return The information obtained.
         * @throws FileNotFoundException If the file doesn't exist.
         */

        private static FileInfo imgInfo(String inputName) throws FileNotFoundException {

                try (FileSystem imgFs = ImgFS.openFs(inputName)) {
                        FileSystemParam params = imgFs.fsparam();
                        log.info("Desc", params.getMapDescription());
                        log.info("Blocksize", params.getBlockSize());

                        FileInfo info = new FileInfo(inputName, UNKNOWN_KIND);
                        info.setDescription(params.getMapDescription());

                        File f = new File(inputName);
                        String name = f.getName();
                        if (OverviewBuilder.isOverviewImg(name))
                                name = OverviewBuilder.getMapName(name);
                        int dot = name.lastIndexOf('.');
                        if (dot < 0) {
                                name = "0";
                        } else {
                                if (dot > name.length())
                                        dot = name.length();
                                if (dot > 8)
                                        dot = 8;
                                name = name.substring(0, dot);
                        }
                        info.setMapname(name);

                        boolean hasTre = false;
                        DirectoryEntry treEnt = null;

                        List<DirectoryEntry> entries = imgFs.list();
                        for (DirectoryEntry ent : entries) {
                                if (ent.isSpecial())
                                        continue;

                                log.info("file", ent.getFullName());
                                String ext = ent.getExt();

                                if ("TRE".equals(ext)) {
                                        info.setTresize(ent.getSize());
                                        info.setInnername(ent.getName());

                                        hasTre = true;
                                        treEnt = ent;
                                } else if ("RGN".equals(ext)) {
                                        int size = ent.getSize();
                                        info.setRgnsize(size);
                                } else if ("LBL".equals(ext)) {
                                        info.setLblsize(ent.getSize());
                                        lblInfo(imgFs, ent, info);
                                } else if ("NET".equals(ext)) {
                                        info.setNetsize(ent.getSize());
                                } else if ("NOD".equals(ext)) {
                                        info.setNodsize(ent.getSize());
                                } else if ("DEM".equals(ext)) {
                                        info.setDemsize(ent.getSize());
                                } else if ("MDR".equals(ext)) {
                                        // It is not actually a regular img file, so change the kind.
                                        info.setKind(MDR_KIND);
                                } else if ("MPS".equals(ext)) {
                                        // This is a gmapsupp file containing several maps.
                                        info.setKind(GMAPSUPP_KIND);
                                        info.mpsName = ent.getFullName();
                                }

                                info.subFiles.add(new SubFileInfo(ent.getFullName(), ent.getSize()));
                        }

                        if (hasTre)
                                treInfo(imgFs, treEnt, info);

                        if (info.getKind() == UNKNOWN_KIND && hasTre)
                                info.setKind(IMG_KIND);

                        return info;
                }
        }

        /**
         * Obtain the information that we need from the TRE section.
         * @param imgFs The filesystem
         * @param ent The filename within the filesystem of the TRE file.
         * @param info This is where the information will be saved.
         * @throws FileNotFoundException If the file is not found in the filesystem.
         */

        private static void treInfo(FileSystem imgFs, DirectoryEntry ent, FileInfo info) throws FileNotFoundException {
                try (ImgChannel treChan = imgFs.open(ent.getFullName(), "r"); TREFileReader treFile = new TREFileReader(treChan) ) {

                        info.setBounds(treFile.getBounds());

                        info.setLicenceInfo(treFile.getMapInfo(info.getCodePage()));

                        info.setHexname(((TREHeader) treFile.getHeader()).getMapId());
                } catch (FileNotFoundException e) {
                        throw e;
                } catch (IOException e) {
                        throw new FileNotFoundException();
                }
        }

        /**
         * Obtain the information we need from a LBL file.
         */

        private static void lblInfo(FileSystem imgFs, DirectoryEntry ent, FileInfo info) throws FileNotFoundException {
                ImgChannel chan = imgFs.open(ent.getFullName(), "r");
                lblInfo(chan, info);
        }

        private static void lblInfo(String filename, FileInfo info) {
                FileImgChannel r = new FileImgChannel(filename, "r");
                try {
                        lblInfo(r, info);
                } finally {
                        Utils.closeFile(r);
                }
        }

        private static void lblInfo(ImgChannel chan, FileInfo info) {
                try (LBLFileReader lblFile = new LBLFileReader(chan, false, 0)) {
                        info.setCodePage(lblFile.getCodePage());
                        info.setSortOrderId(lblFile.getSortOrderId());
                }
        }

        private void setBounds(Area area) {
                this.bounds = area;
        }

        public String getFilename() {
                return filename;
        }

        public boolean isImg() {
                return kind == IMG_KIND;
        }

        protected void setKind(FileKind kind) {
                this.kind = kind;
        }

        public FileKind getKind() {
                return kind;
        }

        public int getMapnameAsInt() {
                try {
                        return Integer.valueOf(mapname);
                } catch (NumberFormatException e) {
                        return 0;
                }
        }

        public List<SubFileInfo> subFiles() {
                return subFiles;
        }

        private void setLicenceInfo(String[] info) {
                this.licenceInfo = info;
        }

        public String[] getLicenseInfo() {
                return licenceInfo;
        }

        public int getNetsize() {
                return netsize;
        }

        protected void setNetsize(int netsize) {
                this.netsize = netsize;
        }

        public int getNodsize() {
                return nodsize;
        }

        protected void setNodsize(int nodsize) {
                this.nodsize = nodsize;
        }

        public void setArgs(CommandArgs args) {
                this.args = args;
        }

        public String getFamilyName() {
                return args.get("family-name", "OSM map");
        }

        public String getSeriesName() {
                return args.get("series-name", "series name");
        }

        public int getFamilyId() {
                return args.get("family-id", CommandArgs.DEFAULT_FAMILYID);
        }

        public int getProductId() {
                return args.get("product-id", 1);
        }

        public Sort getSort() {
                Sort sort = SrtTextReader.sortForCodepage(codePage);
                if (sort == null)
                        sort = args.getSort();
                sort.setSortOrderId(sortOrderId);
                return sort;
        }

        public String getOutputDir() {
                return args.getOutputDir();
        }

        public String getMpsName() {
                return mpsName;
        }

        public String getInnername() {
                return innername;
        }

        public void setInnername(String name) {
                this.innername = name;
        }

        public void setHexname(int hexname) {
                this.hexname = hexname;
        }

        public int getHexname() {
                return hexname;
        }

        public int getCodePage() {
                return codePage;
        }

        public void setCodePage(int codePage) {
                this.codePage = codePage;
        }

        public void setSortOrderId(int sortOrderId) {
                this.sortOrderId = sortOrderId;
        }

        public boolean hasSortOrder() {
                return sortOrderId != 0;
        }

        public String getOverviewName() {
                return args.get("overview-mapname", "osmmap");
        }

        public int getDemsize() {
                return demsize;
        }

        public void setDemsize(int demsize) {
                this.demsize = demsize;
        }
       
        public MapReader getMapReader() throws FileNotFoundException {
                if (mapReader == null)
                        mapReader = new MapReader(filename);
                return mapReader;
        }
       
        public void closeMapReader() {
                if (mapReader != null) {
                        Utils.closeFile(mapReader);
                        mapReader = null;
                }
        }
}