/*
* Copyright (c) 2016, Metron, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Metron, Inc. nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL METRON, INC. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.metsci.glimpse.dnc.geosym;
import static com.metsci.glimpse.dnc.geosym.DncGeosymAttributeExpressions.alwaysTrue;
import static com.metsci.glimpse.dnc.geosym.DncGeosymAttributeExpressions.buildAttributeExpression;
import static com.metsci.glimpse.dnc.geosym.DncGeosymLabelLocation.appendToPrevious;
import static com.metsci.glimpse.util.GeneralUtils.newArrayList;
import static com.metsci.glimpse.util.GeneralUtils.newHashMap;
import static com.metsci.glimpse.util.io.StreamOpener.resource;
import static com.metsci.glimpse.util.units.Angle.degreesToRadians;
import static java.lang.Double.parseDouble;
import static java.lang.Float.parseFloat;
import static java.lang.Integer.parseInt;
import static java.lang.Math.cos;
import static java.lang.Math.max;
import static java.lang.Math.sin;
import java.awt.Color;
import java.awt.Font;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import javax.swing.SwingConstants;
import com.metsci.glimpse.support.color.GlimpseColor;
import com.metsci.glimpse.support.font.FontUtils;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
public class DncGeosymIo
{
public static final String geosymAssignmentPath = "geosym/assignments/";
public static final String geosymAttrExprsFile = "attexp.txt";
public static final String geosymCodesFile = "code.txt";
public static final String geosymFullAssignmentsFile = "fullsym.txt";
public static final String geosymSimplifiedAssignmentsFile = "simpsym.txt";
public static final String geosymLabelJoinsFile = "textjoin.txt";
public static final String geosymLabelLocationsFile = "textloc.txt";
public static final String geosymTextAbbreviationsFile = "textabbr.txt";
public static final String geosymTextStylesFile = "textchar.txt";
public static Object2IntMap<String> readSymbolAssignmentHeader(BufferedReader reader) throws IOException
{
// Skip file description line
reader.readLine();
Object2IntMap<String> columnNums = new Object2IntOpenHashMap<String>();
for (int columnNum = 0; true; columnNum++)
{
String line = reader.readLine();
if (line == null) throw new RuntimeException("File header is incomplete");
if (line.equals(";")) break;
// The -1 means: don't discard trailing empty tokens
String[] tokens = line.split("=", -1);
columnNums.put(tokens[0], columnNum);
}
return columnNums;
}
public static BufferedReader resourceReader(String location) throws IOException
{
return new BufferedReader(new InputStreamReader(resource.openForRead(location)));
}
public static BufferedReader geosymReader(String filename) throws IOException
{
return resourceReader(geosymAssignmentPath + filename);
}
public static Map<String,DncGeosymLineAreaStyle> readGeosymLineAreaStyles(String location) throws IOException
{
BufferedReader reader = null;
try
{
reader = resourceReader(location);
return readGeosymLineAreaStyles(reader);
}
finally
{
if (reader != null) reader.close();
}
}
public static Map<String,DncGeosymLineAreaStyle> readGeosymLineAreaStyles(BufferedReader reader) throws IOException
{
Map<String,DncGeosymLineAreaStyle> styles = newHashMap();
while (true)
{
String line = reader.readLine();
if (line == null) break;
if (line.trim().isEmpty()) continue;
if (line.startsWith("#")) continue;
// The -1 means: don't discard trailing empty tokens
String[] tokens = line.split(",", -1);
String symbolId = tokens[0];
String symbolType = tokens[1];
// XXX: Yuck
float lineWidthFactor = 2; // pixels per millimeter
float lineWidth = (tokens[2].isEmpty() ? 1 : max(1, lineWidthFactor*parseFloat(tokens[2])));
float[] lineRgba = (tokens[3].isEmpty() ? GlimpseColor.getBlack() : GlimpseColor.fromColorAwt(Color.decode(tokens[3])));
String lineStipplePattern0 = tokens[4];
String lineStippleFactor0 = tokens[5];
boolean hasLineStipple = (!lineStipplePattern0.isEmpty() && !lineStippleFactor0.isEmpty());
int lineStippleFactor = (hasLineStipple ? parseInt(tokens[5]) : -1);
short lineStipplePattern = (hasLineStipple ? Integer.decode(lineStipplePattern0).shortValue() : 0);
float[] fillRgba = (tokens[6].isEmpty() ? GlimpseColor.getBlack() : GlimpseColor.fromColorAwt(Color.decode(tokens[6])));
styles.put(symbolId, new DncGeosymLineAreaStyle(symbolId, symbolType, lineWidth, lineRgba, hasLineStipple, lineStippleFactor, lineStipplePattern, fillRgba));
}
return styles;
}
public static Int2ObjectMap<DncGeosymAssignment> readDncSymbolAssignments() throws IOException
{
return readDncSymbolAssignments(geosymFullAssignmentsFile);
}
public static Int2ObjectMap<DncGeosymAssignment> readDncSymbolAssignments(String filename) throws IOException
{
BufferedReader attrExprsReader = null;
BufferedReader codesReader = null;
BufferedReader textStylesReader = null;
BufferedReader textAbbrevsReader = null;
BufferedReader labelLocationsReader = null;
BufferedReader labelJoinsReader = null;
BufferedReader assignmentsReader = null;
try
{
codesReader = geosymReader(geosymCodesFile);
List<DncGeosymCode> codes = readGeosymCodes(codesReader);
int productId = findDncProductId(filename, codes);
Int2ObjectMap<String> featureDelinCodes = findFeatureDelineationCodes(filename, codes);
attrExprsReader = geosymReader(geosymAttrExprsFile);
textStylesReader = geosymReader(geosymTextStylesFile);
textAbbrevsReader = geosymReader(geosymTextAbbreviationsFile);
labelLocationsReader = geosymReader(geosymLabelLocationsFile);
labelJoinsReader = geosymReader(geosymLabelJoinsFile);
Int2ObjectMap<String> fontNameCodes = findFontNameCodes(codes);
Int2ObjectMap<String> fontStyleCodes = findFontStyleCodes(codes);
Int2ObjectMap<String> labelJustifyCodes = findLabelJustifyCodes(codes);
Int2ObjectMap<Int2ObjectMap<String>> textAbbrevs = readGeosymTextAbbreviations(textAbbrevsReader);
Int2ObjectMap<DncGeosymTextStyle> textStyles = readGeosymTextStyles(textStylesReader, fontNameCodes, fontStyleCodes, textAbbrevs);
Int2ObjectMap<DncGeosymLabelLocation> labelLocations = readGeosymLabelLocations(labelLocationsReader, labelJustifyCodes);
Int2ObjectMap<DncGeosymLabelJoin> labelJoins = readGeosymLabelJoins(labelJoinsReader, textStyles, labelLocations);
Int2ObjectMap<String> attrComparisonCodes = findAttrComparisonCodes(codes);
Int2ObjectMap<String> attrExprConnectorCodes = findAttrExprConnectorCodes(codes);
Int2ObjectMap<DncGeosymAttributeExpression> attrExprs = readGeosymAttributeExpressions(attrExprsReader, attrComparisonCodes, attrExprConnectorCodes);
assignmentsReader = geosymReader(filename);
return readGeosymAssignments(assignmentsReader, productId, featureDelinCodes, attrExprs, labelJoins);
}
finally
{
if (attrExprsReader != null) attrExprsReader.close();
if (codesReader != null) codesReader.close();
if (textStylesReader != null) textStylesReader.close();
if (textAbbrevsReader != null) textAbbrevsReader.close();
if (labelLocationsReader != null) labelLocationsReader.close();
if (labelJoinsReader != null) labelJoinsReader.close();
if (assignmentsReader != null) assignmentsReader.close();
}
}
public static Int2ObjectMap<DncGeosymAssignment> readGeosymAssignments(BufferedReader reader, int productIdFilter, Int2ObjectMap<String> featureDelinCodes, Int2ObjectMap<DncGeosymAttributeExpression> attrExprs, Int2ObjectMap<DncGeosymLabelJoin> labelJoins) throws IOException
{
Int2ObjectMap<DncGeosymAssignment> assignments = new Int2ObjectOpenHashMap<DncGeosymAssignment>();
Object2IntMap<String> columnNums = readSymbolAssignmentHeader(reader);
while (true)
{
String line = reader.readLine();
if (line == null) break;
// The -1 means: don't discard trailing empty tokens
String[] tokens = line.split("\\|", -1);
String productId = tokens[columnNums.get("pid")];
if (!productId.isEmpty() && parseInt(productId) != productIdFilter) continue;
int assignmentId = parseInt( tokens[columnNums.get("id")] );
String fcode = tokens[columnNums.get("fcode")];
String delineation = featureDelinCodes.get( parseInt( tokens[columnNums.get("delin")] ) );
String coverageType = tokens[columnNums.get("cov")];
DncGeosymAttributeExpression attrExpr = attrExprs.get(assignmentId);
if (attrExpr == null) attrExpr = alwaysTrue;
String pointSymbolId = tokens[columnNums.get("pointsym")];
String lineSymbolId = tokens[columnNums.get("linesym")];
String areaSymbolId = tokens[columnNums.get("areasym")];
int displayPriority = parseInt( tokens[columnNums.get("dispri")] );
String orientationAttr = tokens[columnNums.get("orient")];
String[] labelAttrs = tokens[columnNums.get("labatt")].split(",", -1);
String[] labelJoinIds = tokens[columnNums.get("txrowid")].split(",", -1);
List<DncGeosymLabelMaker> labelMakers = newArrayList();
for (int i = 0; i < labelAttrs.length; i++)
{
String labelAttr = labelAttrs[i];
if (labelAttr.isEmpty()) continue;
DncGeosymLabelJoin labelJoin = labelJoins.get( parseIntOrFallback( labelJoinIds[i], -1 ) );
if (labelJoin.labelLocation == appendToPrevious)
{
DncGeosymLabelMaker previous = labelMakers.remove( labelMakers.size() - 1 );
labelMakers.add( previous.with( labelAttr, labelJoin.textStyle ) );
}
else
{
labelMakers.add( new DncGeosymLabelMaker( labelAttr, labelJoin.textStyle, labelJoin.labelLocation ) );
}
}
DncGeosymAssignment assignment = new DncGeosymAssignment(assignmentId, fcode, delineation, coverageType, attrExpr, pointSymbolId, lineSymbolId, areaSymbolId, displayPriority, orientationAttr, labelMakers);
assignments.put(assignmentId, assignment);
}
return assignments;
}
public static class DncGeosymLabelJoin
{
public final DncGeosymTextStyle textStyle;
public final DncGeosymLabelLocation labelLocation;
public DncGeosymLabelJoin(DncGeosymTextStyle textStyle, DncGeosymLabelLocation labelLocation)
{
this.textStyle = textStyle;
this.labelLocation = labelLocation;
}
}
public static Int2ObjectMap<DncGeosymLabelJoin> readGeosymLabelJoins(BufferedReader reader, Int2ObjectMap<DncGeosymTextStyle> textStyles, Int2ObjectMap<DncGeosymLabelLocation> labelLocations) throws IOException
{
Int2ObjectMap<DncGeosymLabelJoin> joins = new Int2ObjectOpenHashMap<DncGeosymLabelJoin>();
Object2IntMap<String> columnNums = readSymbolAssignmentHeader(reader);
while (true)
{
String line = reader.readLine();
if (line == null) break;
// The -1 means: don't discard trailing empty tokens
String[] tokens = line.split("\\|", -1);
int joinId = parseInt( tokens[columnNums.get("id")] );
DncGeosymTextStyle textStyle = textStyles.get( parseInt( tokens[columnNums.get("textcharid")] ) );
DncGeosymLabelLocation labelLocation = labelLocations.get( parseInt( tokens[columnNums.get("textlocid")] ) );
DncGeosymLabelJoin join = new DncGeosymLabelJoin(textStyle, labelLocation);
joins.put(joinId, join);
}
return joins;
}
public static Int2ObjectMap<Color> readGeosymColors(String location) throws IOException
{
BufferedReader reader = null;
try
{
reader = resourceReader(location);
return readGeosymColors(reader);
}
finally
{
if (reader != null) reader.close();
}
}
public static Int2ObjectMap<Color> readGeosymColors(BufferedReader reader) throws IOException
{
Int2ObjectMap<Color> rgbas = new Int2ObjectOpenHashMap<Color>();
Object2IntMap<String> columnNums = readSymbolAssignmentHeader(reader);
while (true)
{
String line = reader.readLine();
if (line == null) break;
// The -1 means: don't discard trailing empty tokens
String[] tokens = line.split("\\|", -1);
int index = parseInt( tokens[columnNums.get("index")] );
int r = parseInt( tokens[columnNums.get("red")] );
int g = parseInt( tokens[columnNums.get("green")] );
int b = parseInt( tokens[columnNums.get("blue")] );
rgbas.put(index, new Color(r, g, b));
}
return rgbas;
}
public static Int2ObjectMap<DncGeosymTextStyle> readGeosymTextStyles(BufferedReader reader, Int2ObjectMap<String> fontNameCodes, Int2ObjectMap<String> fontStyleCodes, Int2ObjectMap<Int2ObjectMap<String>> textAbbrevs) throws IOException
{
Int2ObjectMap<DncGeosymTextStyle> styles = new Int2ObjectOpenHashMap<DncGeosymTextStyle>();
Object2IntMap<String> columnNums = readSymbolAssignmentHeader(reader);
while (true)
{
String line = reader.readLine();
if (line == null) break;
// The -1 means: don't discard trailing empty tokens
String[] tokens = line.split("\\|", -1);
int styleId = parseInt( tokens[columnNums.get("id")] );
// XXX: Honor fontName and fontStyle
//String fontName = fontNameCodes.get( parseInt( tokens[columnNums.get("tfont")] ) );
//String fontStyle = fontStyleCodes.get( parseInt( tokens[columnNums.get("tstyle")] ) );
float pointSize = parseFloat( tokens[columnNums.get("tsize")] );
Font font = FontUtils.getDefaultPlain(pointSize);
int colorId = parseInt( tokens[columnNums.get("tcolor")] );
String prefix = parseHexCharOrFallback( tokens[columnNums.get("tprepend")], "" );
String suffix = parseHexCharOrFallback( tokens[columnNums.get("tappend")], "" );
Int2ObjectMap<String> abbrevs = textAbbrevs.get( parseIntOrFallback( tokens[columnNums.get("abindexid")], -1 ) );
DncGeosymTextStyle style = new DncGeosymTextStyle(font, colorId, prefix, suffix, abbrevs);
styles.put(styleId, style);
}
return styles;
}
public static Int2ObjectMap<Int2ObjectMap<String>> readGeosymTextAbbreviations(BufferedReader reader) throws IOException
{
while (true)
{
String line = reader.readLine();
if (line == null) break;
if (line.trim().equals(";")) break;
}
Pattern beginBlockPattern = Pattern.compile("^[0-9]+:$");
Int2ObjectMap<Int2ObjectMap<String>> abbrevs = new Int2ObjectOpenHashMap<Int2ObjectMap<String>>();
Int2ObjectMap<String> currentAbbrevs = null;
while (true)
{
String line = reader.readLine();
if (line == null) break;
if (beginBlockPattern.matcher(line).matches())
{
int newBlockNum = parseInt(line.split(":", -1)[0]);
if (!abbrevs.containsKey(newBlockNum)) abbrevs.put(newBlockNum, new Int2ObjectOpenHashMap<String>());
currentAbbrevs = abbrevs.get(newBlockNum);
}
else
{
// The -1 means: don't discard trailing empty tokens
String[] tokens = line.split("\\|", -1);
int id = parseInt(tokens[0]);
String string = tokens[1];
currentAbbrevs.put(id, string);
}
}
return abbrevs;
}
public static Int2ObjectMap<DncGeosymLabelLocation> readGeosymLabelLocations(BufferedReader reader, Int2ObjectMap<String> labelJustifyCodes) throws IOException
{
Int2ObjectMap<DncGeosymLabelLocation> locations = new Int2ObjectOpenHashMap<DncGeosymLabelLocation>();
locations.put(-1, appendToPrevious);
Object2IntMap<String> columnNums = readSymbolAssignmentHeader(reader);
while (true)
{
String line = reader.readLine();
if (line == null) break;
// The -1 means: don't discard trailing empty tokens
String[] tokens = line.split("\\|", -1);
int locationId = parseInt( tokens[columnNums.get("id")] );
String justify = labelJustifyCodes.get( parseInt( tokens[columnNums.get("tjust")] ) );
// XXX: Ugly
int hAlign = SwingConstants.CENTER;
int vAlign = SwingConstants.CENTER;
boolean forSoundings = false;
if (justify.equals("Sounding Text"))
{
forSoundings = true;
}
else
{
if (justify.startsWith("Bottom ")) vAlign = SwingConstants.BOTTOM;
else if (justify.startsWith("Top ")) vAlign = SwingConstants.TOP;
if (justify.endsWith(" Left")) hAlign = SwingConstants.LEFT;
else if (justify.endsWith(" Right")) hAlign = SwingConstants.RIGHT;
}
double offsetDistance_MM = parseDouble( tokens[columnNums.get("tdist")] );
double offsetDirection_RAD = degreesToRadians( parseDouble( tokens[columnNums.get("tdir")] ) );
double xOffset_MM = offsetDistance_MM * sin(offsetDirection_RAD);
double yOffset_MM = offsetDistance_MM * cos(offsetDirection_RAD);
DncGeosymLabelLocation location = new DncGeosymLabelLocation(xOffset_MM, yOffset_MM, hAlign, vAlign, forSoundings);
locations.put(locationId, location);
}
return locations;
}
public static Int2ObjectMap<DncGeosymAttributeExpression> readGeosymAttributeExpressions(BufferedReader reader, Int2ObjectMap<String> comparisonOpCodes, Int2ObjectMap<String> connectorCodes) throws IOException
{
int workingAssignmentId = -1;
int recentSequenceNum = 0;
List<String> workingConnectorOps = newArrayList();
List<DncGeosymAttributeComparison> workingComparisons = newArrayList();
Int2ObjectMap<DncGeosymAttributeExpression> expressions = new Int2ObjectOpenHashMap<DncGeosymAttributeExpression>();
Object2IntMap<String> columnNums = readSymbolAssignmentHeader(reader);
while (true)
{
String line = reader.readLine();
if (line == null) break;
// The -1 means: don't discard trailing empty tokens
String[] tokens = line.split("\\|", -1);
int assignmentId = parseInt( tokens[columnNums.get("cond_index")] );
if (workingAssignmentId != -1 && assignmentId != workingAssignmentId) throw new RuntimeException("Unexpected row id: " + line);
workingAssignmentId = assignmentId;
int sequenceNum = parseInt( tokens[columnNums.get("seq")] );
if (sequenceNum <= recentSequenceNum) throw new RuntimeException("Unexpected sequence number: " + line);
recentSequenceNum = sequenceNum;
String attr = tokens[columnNums.get("att")];
String comparisonOp = comparisonOpCodes.get( parseInt( tokens[columnNums.get("oper")] ) );
String comparisonValue = tokens[columnNums.get("value")];
workingComparisons.add( new DncGeosymAttributeComparison( attr, comparisonOp, comparisonValue ) );
String connectorOp = connectorCodes.get( parseInt( tokens[columnNums.get("connector")] ) );
if (!"None".equals(connectorOp))
{
workingConnectorOps.add(connectorOp);
}
else
{
if (!workingComparisons.isEmpty())
{
expressions.put( assignmentId, buildAttributeExpression(workingConnectorOps, workingComparisons) );
}
workingAssignmentId = -1;
recentSequenceNum = 0;
workingConnectorOps = newArrayList();
workingComparisons = newArrayList();
}
}
if (workingAssignmentId != -1) throw new RuntimeException();
return expressions;
}
public static int findDncProductId(String contextFilename, List<DncGeosymCode> codes)
{
for (DncGeosymCode code : codes)
{
if (code.filename.equals(contextFilename) && code.attribute.equals("pid") && code.description.equals("DNC")) return code.value;
}
throw new RuntimeException("Could not find code for product DNC");
}
public static Int2ObjectMap<String> findFeatureDelineationCodes(String contextFilename, List<DncGeosymCode> codes)
{
Int2ObjectMap<String> delins = new Int2ObjectOpenHashMap<String>();
for (DncGeosymCode code : codes)
{
if (code.filename.equals(contextFilename) && code.attribute.equals("delin"))
{
delins.put(code.value, code.description);
}
}
return delins;
}
public static Int2ObjectMap<String> findFontNameCodes(List<DncGeosymCode> codes)
{
Int2ObjectMap<String> fonts = new Int2ObjectOpenHashMap<String>();
for (DncGeosymCode code : codes)
{
if (code.filename.equals(geosymTextStylesFile) && code.attribute.equals("tfont"))
{
fonts.put(code.value, code.description);
}
}
return fonts;
}
public static Int2ObjectMap<String> findFontStyleCodes(List<DncGeosymCode> codes)
{
Int2ObjectMap<String> styles = new Int2ObjectOpenHashMap<String>();
for (DncGeosymCode code : codes)
{
if (code.filename.equals(geosymTextStylesFile) && code.attribute.equals("tstyle"))
{
styles.put(code.value, code.description);
}
}
return styles;
}
public static Int2ObjectMap<String> findAttrComparisonCodes(List<DncGeosymCode> codes)
{
Int2ObjectMap<String> attrComparisons = new Int2ObjectOpenHashMap<String>();
for (DncGeosymCode code : codes)
{
if (code.filename.equals(geosymAttrExprsFile) && code.attribute.equals("oper"))
{
attrComparisons.put(code.value, code.description);
}
}
return attrComparisons;
}
public static Int2ObjectMap<String> findAttrExprConnectorCodes(List<DncGeosymCode> codes)
{
Int2ObjectMap<String> attrExprConnectors = new Int2ObjectOpenHashMap<String>();
for (DncGeosymCode code : codes)
{
if (code.filename.equals(geosymAttrExprsFile) && code.attribute.equals("connector"))
{
attrExprConnectors.put(code.value, code.description);
}
}
return attrExprConnectors;
}
public static Int2ObjectMap<String> findLabelJustifyCodes(List<DncGeosymCode> codes)
{
Int2ObjectMap<String> justifications = new Int2ObjectOpenHashMap<String>();
for (DncGeosymCode code : codes)
{
if (code.filename.equals(geosymLabelLocationsFile) && code.attribute.equals("tjust"))
{
justifications.put(code.value, code.description);
}
}
return justifications;
}
public static List<DncGeosymCode> readGeosymCodes(BufferedReader reader) throws IOException
{
Object2IntMap<String> columnNums = readSymbolAssignmentHeader(reader);
List<DncGeosymCode> codes = newArrayList();
while (true)
{
String line = reader.readLine();
if (line == null) break;
// The -1 means: don't discard trailing empty tokens
String[] tokens = line.split("\\|", -1);
String filename = tokens[columnNums.get("file")];
String attribute = tokens[columnNums.get("attribute")];
int value = parseInt( tokens[columnNums.get("value")] );
String description = tokens[columnNums.get("description")];
codes.add( new DncGeosymCode(filename, attribute, value, description) );
}
return codes;
}
public static String parseHexCharOrFallback(String string, String fallback)
{
try
{
return String.valueOf((char) parseInt(string, 16));
}
catch (NumberFormatException e)
{
return fallback;
}
}
public static int parseIntOrFallback(String string, int fallback)
{
try
{
return parseInt(string);
}
catch (NumberFormatException e)
{
return fallback;
}
}
}