Rev 2886 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* Copyright (C) 2011.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 or
* 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.
*/
package uk.me.parabola.mkgmap.main;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import uk.me.parabola.imgfmt.ExitException;
import uk.me.parabola.imgfmt.MapFailedException;
import uk.me.parabola.imgfmt.Utils;
import uk.me.parabola.imgfmt.app.srt.Sort;
import uk.me.parabola.imgfmt.app.typ.TYPFile;
import uk.me.parabola.imgfmt.app.typ.TypData;
import uk.me.parabola.imgfmt.app.typ.TypLabelException;
import uk.me.parabola.imgfmt.app.typ.TypParam;
import uk.me.parabola.imgfmt.sys.FileImgChannel;
import uk.me.parabola.mkgmap.CommandArgs;
import uk.me.parabola.mkgmap.scan.SyntaxException;
import uk.me.parabola.mkgmap.typ.TypTextReader;
/**
* Standalone program to compile a TYP file from the text format.
* Simple main program to demonstrate compiling a typ.txt file.
*
* Usage: TypTextReader [in-file] [out-file]
*
* in-file defaults to 'default.txt'
* out-file defaults to 'OUT.TYP'
*
*/
public class TypCompiler
implements MapProcessor
{
/**
* The integration with mkgmap.
*
* @param args The options that are in force.
* @param filename The input filename.
* @return Returns the name of the file that was written. It depends on the family id.
*/
public String makeMap
(CommandArgs args,
String filename
) {
assert filename.
toLowerCase().
endsWith(".txt");
CharsetProbe probe =
new CharsetProbe
();
String readCharset = probe.
probeCharset(filename
);
TypData data
;
try {
data = compile
(filename, readCharset, args.
getSort());
} catch (SyntaxException e
) {
throw new MapFailedException
("Compiling TYP txt file: " + e.
getMessage());
} catch (FileNotFoundException e
) {
throw new MapFailedException
("Could not open TYP file " + filename +
" to read");
}
TypParam param = data.
getParam();
int family = args.
get("family-id", -
1);
int product = args.
get("product-id", -
1);
int cp = args.
get("code-page", -
1);
if (family
!= -
1)
param.
setFamilyId(family
);
if (product
!= -
1)
param.
setProductId(product
);
if (cp
!= -
1)
param.
setCodePage(cp
);
File outFile =
new File(filename
);
String outName = outFile.
getName();
int last
;
if (outName.
length() > 4 && (last = outName.
lastIndexOf('.')) > 0)
outName = outName.
substring(0, last
);
outName +=
".typ";
outFile =
new File(args.
getOutputDir(), outName
);
try {
writeTyp
(data, outFile
);
} catch (TypLabelException e
) {
throw new MapFailedException
("TYP file cannot be written in code page "
+ data.
getSort().
getCodepage());
} catch (IOException e
) {
throw new MapFailedException
("Error while writing typ file", e
);
}
return outFile.
getPath();
}
/**
* Read and compile a TYP file, returning the compiled form.
*
* @param filename The input filename.
* @param charset The character set to use to read this file. We should have already determined
* that this character set is valid and can be used to read the file.
* @param sort The sort information from command line options, used for the output code page
* only. If null, then the code page set by CodePage in the typ.txt file will be used.
*
* @return The compiled form as a data structure.
* @throws FileNotFoundException If the file doesn't exist.
* @throws SyntaxException All user correctable problems in the input file.
*/
private TypData compile
(String filename,
String charset, Sort sort
)
throws FileNotFoundException, SyntaxException
{
TypTextReader tr =
new TypTextReader
();
TypData data = tr.
getData();
data.
setSort(sort
);
try {
Reader r =
new BufferedReader(new InputStreamReader(new FileInputStream(filename
), charset
));
tr.
read(filename, r
);
} catch (UnsupportedEncodingException e
) {
// Not likely to happen as we should have already used this character set!
throw new MapFailedException
("Unsupported character set", e
);
}
return tr.
getData();
}
/**
* Write the type file out from the compiled form to the given name.
*/
private void writeTyp
(TypData data,
File file
) throws IOException {
RandomAccessFile raf =
new RandomAccessFile(file,
"rw");
FileChannel channel = raf.
getChannel();
channel.
truncate(0);
FileImgChannel w =
new FileImgChannel
(channel
);
TYPFile typ =
new TYPFile
(w
);
typ.
setData(data
);
typ.
write();
typ.
close();
}
/**
* Simple standalone compiler.
*
* Usage: TypCompiler [in-file] [out-file]
* in-file defaults to 'default.txt'
* out-file defaults to OUT.TYP
*/
public static void main
(String[] args
) throws IOException {
String in =
"default.txt";
if (args.
length > 0)
in = args
[0];
String out =
"OUT.TYP";
if (args.
length > 1)
out = args
[1];
new TypCompiler
().
standAloneRun(in, out
);
}
private void standAloneRun
(String in,
String out
) {
CharsetProbe probe =
new CharsetProbe
();
String readCharset = probe.
probeCharset(in
);
TypData data
;
try {
data = compile
(in, readCharset,
null);
} catch (SyntaxException e
) {
System.
out.
println(e.
getMessage());
return;
} catch (FileNotFoundException e
) {
throw new MapFailedException
("Could not open TYP file " + in +
" to read");
}
try {
writeTyp
(data,
new File(out
));
} catch (IOException e
) {
System.
out.
println("Error writing file: " + e.
getMessage());
}
}
class CharsetProbe
{
private String codePage
;
private CharsetEncoder encoder
;
public CharsetProbe
() {
setCodePage
("latin1");
}
private void setCodePage
(String codePage
) {
this.
codePage = codePage
;
this.
encoder =
Charset.
forName(codePage
).
newEncoder();
}
private String probeCharset
(String file
) {
String readingCharset =
"utf-8";
try {
tryCharset
(file, readingCharset
);
return readingCharset
;
} catch (TypLabelException e
) {
try {
readingCharset = e.
getCharsetName();
tryCharset
(file, readingCharset
);
} catch (Exception e1
) {
return "utf-8";
}
}
return readingCharset
;
}
private void tryCharset
(String file,
String readingCharset
) {
InputStream is =
null;
try {
is =
new FileInputStream(file
);
BufferedReader br =
new BufferedReader(new InputStreamReader(is, readingCharset
));
String line
;
while ((line = br.
readLine()) !=
null) {
if (line.
isEmpty())
continue;
// This is a giveaway the file is in utf-something, so ignore anything else
if (line.
charAt(0) == 0xfeff
)
return;
if (line.
startsWith("CodePage")) {
String[] split = line.
split("=");
try {
setCodePage
("cp" +
Integer.
decode(split
[1].
trim()));
} catch (NumberFormatException e
) {
setCodePage
("cp1252");
}
}
if (line.
startsWith("String")) {
CharBuffer cb =
CharBuffer.
wrap(line
);
if (encoder
!=
null)
encoder.
encode(cb
);
}
}
} catch (UnsupportedEncodingException e
) {
throw new TypLabelException
(codePage
);
} catch (CharacterCodingException e
) {
throw new TypLabelException
(codePage
);
} catch (FileNotFoundException e
) {
throw new ExitException
("File not found " + file
);
} catch (IOException e
) {
throw new ExitException
("Could not read file " + file
);
} finally {
Utils.
closeFile(is
);
}
}
}
}