/*
* 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;
}
}
}