Rev 3389 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* Copyright (C) 2006 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: 16-Dec-2006
*/
package uk.me.parabola.mkgmap.reader.polish;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import uk.me.parabola.imgfmt.FormatException;
import uk.me.parabola.imgfmt.Utils;
import uk.me.parabola.imgfmt.app.Coord;
import uk.me.parabola.imgfmt.app.net.AccessTagsAndBits;
import uk.me.parabola.imgfmt.app.trergn.ExtTypeAttributes;
import uk.me.parabola.log.Logger;
import uk.me.parabola.mkgmap.filters.LineSplitterFilter;
import uk.me.parabola.mkgmap.general.LevelInfo;
import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
import uk.me.parabola.mkgmap.general.MapElement;
import uk.me.parabola.mkgmap.general.MapLine;
import uk.me.parabola.mkgmap.general.MapPoint;
import uk.me.parabola.mkgmap.general.MapShape;
import uk.me.parabola.mkgmap.reader.MapperBasedMapDataSource;
/**
* Read an data file in Polish format. This is the format used by a number
* of other garmin map making programs notably cGPSmapper.
* <p>
* As the input format is designed for garmin maps, it is fairly easy to read
* into mkgmap. Not every feature of the format is read yet, but it shouldn't
* be too difficult to add them in as needed.
* <p>
* Now will place elements at the level specified in the file and not at the
* automatic level that is used in eg. the OSM reader.
*/
public class PolishMapDataSource extends MapperBasedMapDataSource implements LoadableMapDataSource {
private static final Logger log = Logger.getLogger(PolishMapDataSource.class);
private static final String READING_CHARSET = "iso-8859-1";
private static final int S_IMG_ID = 1;
private static final int S_POINT = 2;
private static final int S_POLYLINE = 3;
private static final int S_POLYGON = 4;
private static final int S_RESTRICTION = 5;
private MapPoint point;
private MapLine polyline;
private MapShape shape;
private PolishTurnRestriction restriction;
private List<Coord> points;
private final RoadHelper roadHelper = new RoadHelper();
private final RestrictionHelper restrictionHelper = new RestrictionHelper();
private Map<String, String> extraAttributes;
private String copyright;
private int section;
private LevelInfo[] levels;
private int endLevel;
private char elevUnits;
private static final double METERS_TO_FEET = 3.2808399;
private int lineNo;
private boolean havePolygon4B;
private Boolean driveOnLeft;
// Use to decode labels if they are not in cp1252
private CharsetDecoder dec;
Long2ObjectOpenHashMap<Coord> coordMap = new Long2ObjectOpenHashMap<>();
public boolean isFileSupported(String name) {
// Supported if the extension is .mp
return name.endsWith(".mp") || name.endsWith(".MP") || name.endsWith(".mp.gz");
}
/**
* Load the .osm file and produce the intermediate format.
*
* @param name The filename to read.
* @throws FileNotFoundException If the file does not exist.
*/
public void load(String name) throws FileNotFoundException, FormatException {
Reader reader;
try {
reader = new InputStreamReader(Utils.openFile(name), READING_CHARSET);
} catch (UnsupportedEncodingException e) {
// Java is required to support iso-8859-1 so this is unlikely
throw new FormatException("Unrecognised charset " + READING_CHARSET);
}
// If no code page is given then we read labels in utf-8
dec = Charset.forName("utf-8").newDecoder();
dec.onUnmappableCharacter(CodingErrorAction.REPLACE);
BufferedReader in = new BufferedReader(reader);
try {
String line;
while ((line = in.readLine()) != null) {
++lineNo;
if (line.trim().isEmpty() || line.charAt(0) == ';')
continue;
if (line.startsWith("[END"))
endSection();
else if (line.charAt(0) == '[')
sectionStart(line);
else
processLine(line);
}
// Add all restrictions to the map after reading the full map.
// The reason being, the restrictions section appear in the beginning of the map.
// All the nodes will only be read later on.
// Required to pass the road helper instance as it contains all node data.
restrictionHelper.processAndAddRestrictions(roadHelper, mapper);
} catch (IOException e) {
throw new FormatException("Reading file failed", e);
}
addBackground(havePolygon4B);
coordMap = null;
}
public LevelInfo[] mapLevels() {
if (levels == null) {
// If it has not been set then supply some defaults.
levels = new LevelInfo[] {
new LevelInfo(3, 17),
new LevelInfo(2, 18),
new LevelInfo(1, 22),
new LevelInfo(0, 24),
};
}
levels[0].setTop(true);
return levels;
}
@Override
public LevelInfo[] overviewMapLevels() {
return null;
}
/**
* Get the copyright message. We use whatever was specified inside the
* MPF itself.
*
* @return A string description of the copyright.
*/
public String[] copyrightMessages() {
return new String[] {copyright};
}
/**
* Record that we are starting a new section.
* Section names are enclosed in square brackets. Inside the section there
* are a number of lines with the key=value format.
*
* @param line The raw line from the input file.
*/
private void sectionStart(String line) {
String name = line.substring(1, line.length() - 1);
log.debug("section name", name);
extraAttributes = null;
if (name.equals("IMG ID")) {
section = S_IMG_ID;
} else if (name.equals("POI") || name.equals("RGN10") || name.equals("RGN20")) {
point = new MapPoint();
section = S_POINT;
} else if (name.equals("POLYLINE") || name.equals("RGN40")) {
polyline = new MapLine();
roadHelper.clear();
section = S_POLYLINE;
} else if (name.equals("POLYGON") || name.equals("RGN80")) {
shape = new MapShape();
section = S_POLYGON;
}
else if (name.equals("Restrict")) {
restriction = new PolishTurnRestriction();
section = S_RESTRICTION;
}
else
log.info("Ignoring " + name + " section");
}
/**
* At the end of a section, we add what ever element that we have been
* building to the map.
*/
private void endSection() {
switch (section) {
case S_IMG_ID:
break;
case S_POINT:
if(extraAttributes != null && point.hasExtendedType())
point.setExtTypeAttributes(makeExtTypeAttributes());
mapper.addToBounds(point.getLocation());
mapper.addPoint(point);
break;
case S_POLYLINE:
if (points != null) {
if (roadHelper.isRoad()) {
polyline.setPoints(points);
mapper.addRoad(roadHelper.makeRoad(polyline));
}
else {
if(extraAttributes != null && polyline.hasExtendedType())
polyline.setExtTypeAttributes(makeExtTypeAttributes());
final int maxPointsInLine = LineSplitterFilter.MAX_POINTS_IN_LINE;
if(points.size() > maxPointsInLine) {
List<Coord> segPoints = new ArrayList<>(maxPointsInLine);
for(Coord p : points) {
segPoints.add(p);
if(segPoints.size() == maxPointsInLine) {
MapLine seg = polyline.copy();
seg.setPoints(segPoints);
mapper.addLine(seg);
segPoints = new ArrayList<>(maxPointsInLine);
segPoints.add(p);
}
}
if(!segPoints.isEmpty()) {
polyline.setPoints(segPoints);
mapper.addLine(polyline);
}
}
else {
polyline.setPoints(points);
mapper.addLine(polyline);
}
}
}
break;
case S_POLYGON:
if (points != null) {
if (points.get(0) != points.get(points.size()-1)){
// not closed, close it
points.add(points.get(0));
}
shape.setPoints(points);
if(extraAttributes != null && shape.hasExtendedType())
shape.setExtTypeAttributes(makeExtTypeAttributes());
mapper.addShape(shape);
}
break;
case S_RESTRICTION:
restrictionHelper.addRestriction(restriction);
break;
case 0:
// ignored section
break;
default:
log.warn("unexpected default in switch", section);
break;
}
// Clear the section state.
section = 0;
endLevel = 0;
points = null;
}
/**
* This should be a line that is a key value pair. We switch out to a
* routine that is dependant on the section that we are in.
*
* @param line The raw input line from the file.
*/
private void processLine(String line) {
String[] nameVal = line.split("=", 2);
if (nameVal.length != 2) {
log.warn("short line? " + line);
return;
}
String name = nameVal[0];
String value = nameVal[1];
log.debug("LINE: ", name, "|", value);
switch (section) {
case S_IMG_ID:
imgId(name, value);
break;
case S_POINT:
if (!isCommonValue(point, name, value))
point(name, value);
break;
case S_POLYLINE:
if (!isCommonValue(polyline, name, value))
line(name, value);
break;
case S_POLYGON:
if (!isCommonValue(shape, name, value))
shape(name, value);
break;
case S_RESTRICTION:
restriction(name, value);
break;
default:
log.debug("line ignored");
break;
}
}
/**
* This is called for every line within the POI section. The lines are
* key value pairs that have already been decoded into name and value.
* For each name we recognise we set the appropriate property on
* the <i>point</i>.
*
* @param name Parameter name.
* @param value Its value.
*/
private void point(String name, String value) {
if (name.equals("Type")) {
int type = Integer.decode(value);
point.setType(type);
} else if (name.equals("SubType")) {
int subtype = Integer.decode(value);
int type = point.getType();
if (type <= 0xff)
point.setType((type << 8) | subtype);
} else if (name.startsWith("Data") || name.startsWith("Origin")) {
Coord co = makeCoord(value);
setResolution(point, name);
point.setLocation(co);
}
else {
if(extraAttributes == null)
extraAttributes = new HashMap<>();
extraAttributes.put(name, value);
}
}
/**
* Called for each command in a POLYLINE section. There will be a Data
* line consisting of a number of co-ordinates that must be separated out
* into points.
*
* @param name Command name.
* @param value Command value.
* @see #point
*/
private void line(String name, String value) {
if (name.equals("Type")) {
polyline.setType(Integer.decode(value));
} else if (name.startsWith("Data")) {
List<Coord> newPoints = coordsFromString(value);
// If it is a contour line, then fix the elevation if required.
if ((polyline.getType() == 0x20) ||
(polyline.getType() == 0x21) ||
(polyline.getType() == 0x22)) {
fixElevation();
}
setResolution(polyline, name);
if(points != null) {
log.error("Line " + polyline.getName() + " has multiple Data lines - concatenating the points");
points.addAll(newPoints);
}
else
points = newPoints;
} else if (name.equals("RoadID")) {
roadHelper.setRoadId(Integer.parseInt(value));
} else if (name.startsWith("Nod")) {
roadHelper.addNode(value);
} else if (name.equals("RouteParam") || name.equals("RouteParams")) {
roadHelper.setParam(value);
} else if (name.equals("DirIndicator")) {
polyline.setDirection(Integer.parseInt(value) > 0);
} else if (name.startsWith("Numbers")) {
roadHelper.addNumbers(value);
} else {
if (extraAttributes == null)
extraAttributes = new HashMap<>();
extraAttributes.put(name, value);
}
}
private List<Coord> coordsFromString(String value) {
String[] ords = value.split("\\) *, *\\(");
List<Coord> points = new ArrayList<>();
for (String s : ords) {
Coord co = makeCoord(s);
if (log.isDebugEnabled())
log.debug(" L: ", co);
mapper.addToBounds(co);
points.add(co);
}
log.debug(points.size() + " points from " + value);
return points;
}
/**
* The elevation needs to be in feet. So if it is given in meters then
* convert it.
*/
private void fixElevation() {
if (elevUnits == 'm') {
String h = polyline.getName();
try {
// Convert to feet.
int n = Integer.parseInt(h);
n *= METERS_TO_FEET;
polyline.setName(String.valueOf(n));
} catch (NumberFormatException e) {
// OK it wasn't a number, leave it alone
}
}
}
/**
* Called for each command in a POLYGON section. There will be a Data
* line consisting of a number of co-ordinates that must be separated out
* into points.
*
* @param name Command name.
* @param value Command value.
* @see #line
*/
private void shape(String name, String value) {
if (name.equals("Type")) {
int type = Integer.decode(value);
shape.setType(type);
if(type == 0x4b)
havePolygon4B = true;
} else if (name.startsWith("Data")) {
List<Coord> newPoints = coordsFromString(value);
if(points != null)
points.addAll(newPoints);
else
points = newPoints;
setResolution(shape, name);
}
else {
if(extraAttributes == null)
extraAttributes = new HashMap<>();
extraAttributes.put(name, value);
}
}
private boolean isCommonValue(MapElement elem, String name, String value) {
if (name.equals("Label")) {
elem.setName(unescape(recode(value)));
} else if (name.equals("Label2") || name.equals("Label3")) {
elem.add2Name(unescape(recode(value)));
} else if (name.equals("Levels") || name.equals("EndLevel") || name.equals("LevelsNumber")) {
try {
endLevel = Integer.valueOf(value);
} catch (NumberFormatException e) {
endLevel = 0;
}
} else if (name.equals("ZipCode")) {
elem.setZip(recode(value));
} else if (name.equals("CityName")) {
elem.setCity(recode(value));
} else if (name.equals("StreetDesc")) {
elem.setStreet(recode(value));
} else if (name.equals("HouseNumber")) {
elem.setHouseNumber(recode(value));
} else if (name.equals("is_in")) {
elem.setIsIn(recode(value));
} else if (name.equals("Phone")) {
elem.setPhone(recode(value));
} else if (name.equals("CountryName")) {
elem.setCountry(unescape(recode(value)));
} else if (name.equals("RegionName")) {
//System.out.println("RegionName " + value);
elem.setRegion(recode(value));
} else {
return false;
}
// We dealt with it
return true;
}
/**
* Deal with the polish map escape codes of the form ~[0x##]. These
* stand for a single character and is usually used for highway
* symbols, name separators etc.
*
* The code ~[0x05] stands for the character \005 for example.
*
* @param s The original string that may contain codes.
* @return A string with the escape codes replaced by the single character.
*/
public static String unescape(String s) {
int ind = s.indexOf("~[");
if (ind < 0)
return s;
StringBuilder sb = new StringBuilder();
if (ind > 0)
sb.append(s.substring(0, ind));
char[] buf = s.toCharArray();
while (ind < buf.length) {
if (ind < buf.length-2 && buf[ind] == '~' && buf[ind+1] == '[') {
StringBuffer num = new StringBuffer();
ind += 2; // skip "~["
while (ind < buf.length && buf[ind++] != ']')
num.append(buf[ind - 1]);
try {
int inum = Integer.decode(num.toString());
// Convert any that are in 6-bit format
if (inum == 0x1b2c) inum = 0x1c;
if (inum >= 0x2a)
inum -= 0x29;
sb.append((char) inum);
} catch (NumberFormatException e) {
// Input is malformed so lets just ignore it.
}
} else {
sb.append(buf[ind]);
ind++;
}
}
return sb.toString();
}
/**
* Convert the value of a label into a string based on the declared
* code page in the file.
*
* This makes assumptions about the way that the .mp file is written
* that may not be correct.
*
* @param value The string that has been read with ISO-8859-1.
* @return A possibly different string that is obtained by taking the
* bytes in the input string and decoding them as if they had the
* declared code page.
*/
private String recode(String value) {
if (dec != null) {
try {
// Get the bytes that were actually in the file.
byte[] bytes = value.getBytes(READING_CHARSET);
ByteBuffer buf = ByteBuffer.wrap(bytes);
// Decode from bytes with the correct code page.
CharBuffer out = dec.decode(buf);
return out.toString();
} catch (UnsupportedEncodingException e) {
// Java requires this support, so unlikely to happen
log.warn("no support for " + READING_CHARSET);
} catch (CharacterCodingException e) {
log.error("error decoding label", e);
}
}
return value;
}
private void setResolution(MapElement elem, String name) {
if (endLevel > 0) {
elem.setMinResolution(extractResolution(endLevel));
elem.setMaxResolution(extractResolution(name));
} else {
int res = extractResolution(name);
elem.setMinResolution(res);
elem.setMaxResolution(res);
}
}
/**
* Extract the resolution from the Data label. The name will be something
* like Data2: from that we know it is at level 2 and we can look up
* the resolution.
*
* @param name The name tag DataN, where N is a digit corresponding to the
* level.
*
* @return The resolution that corresponds to the level.
*/
private int extractResolution(String name) {
int level = Integer.valueOf(name.substring(name.charAt(0) == 'O'? 6: 4));
return extractResolution(level);
}
/**
* Extract resolution from the level.
*
* @param level The level (0..)
* @return The resolution.
* @see #extractResolution(String name)
*/
private int extractResolution(int level) {
int nlevels = levels.length;
// Some maps use EndLevel=9 to mean the highest level
if (level >= nlevels)
level = nlevels - 1;
LevelInfo li = levels[nlevels - level - 1];
return li.getBits();
}
/**
* The initial 'IMG ID' section. Contains miscellaneous parameters for
* the map.
*
* @param name Command name.
* @param value Command value.
*/
private void imgId(String name, String value) {
if (name.equals("Copyright")) {
copyright = value;
} else if (name.equals("Levels")) {
int nlev = Integer.valueOf(value);
levels = new LevelInfo[nlev];
} else if (name.startsWith("Level")) {
int level = Integer.valueOf(name.substring(5));
int bits = Integer.valueOf(value);
LevelInfo info = new LevelInfo(level, bits);
int nlevels = levels.length;
if (level >= nlevels)
return;
levels[nlevels - level - 1] = info;
} else if (name.startsWith("Elevation")) {
char fc = value.charAt(0);
if (fc == 'm' || fc == 'M')
elevUnits = 'm';
} else if (name.equals("CodePage")) {
dec = Charset.forName("cp" + value).newDecoder();
dec.onUnmappableCharacter(CodingErrorAction.REPLACE);
} else if (name.endsWith("LeftSideTraffic")){
if ("Y".equals(value)){
setDriveOnLeft(true);
} else if ("N".equals(value)){
setDriveOnLeft(false);
}
}
}
/**
* Create a coordinate from a string. The string will look similar:
* (2.3454,-0.23), but may not have the leading opening parenthesis.
* @param value A string representing a lat,long pair.
* @return The coordinate value.
*/
private Coord makeCoord(String value) {
String[] fields = value.split("[(,)]");
int i = 0;
if (fields[0].isEmpty())
i = 1;
Double f1 = Double.valueOf(fields[i]);
Double f2 = Double.valueOf(fields[i+1]);
Coord co = new Coord(f1, f2);
long key = Utils.coord2Long(co);
Coord co2 = coordMap.get(key);
if (co2 != null)
return co2;
coordMap.put(key, co);
return co;
}
private ExtTypeAttributes makeExtTypeAttributes() {
Map<String, String> eta = new HashMap<>();
int colour = 0;
int style = 0;
for(Map.Entry<String, String> entry : extraAttributes.entrySet()) {
String v = entry.getValue();
if (entry.getKey().equals("Depth")) {
String u = extraAttributes.get("DepthUnit");
if("f".equals(u))
v += "ft";
eta.put("depth", v);
} else if(entry.getKey().equals("Height")) {
String u = extraAttributes.get("HeightUnit");
if("f".equals(u))
v += "ft";
eta.put("height", v);
} else if(entry.getKey().equals("HeightAboveFoundation")) {
String u = extraAttributes.get("HeightAboveFoundationUnit");
if("f".equals(u))
v += "ft";
eta.put("height-above-foundation", v);
} else if(entry.getKey().equals("HeightAboveDatum")) {
String u = extraAttributes.get("HeightAboveDatumUnit");
if("f".equals(u))
v += "ft";
eta.put("height-above-datum", v);
} else if(entry.getKey().equals("Color")) {
colour = Integer.decode(v);
} else if(entry.getKey().equals("Style")) {
style = Integer.decode(v);
} else if(entry.getKey().equals("Position")) {
eta.put("position", v);
} else if(entry.getKey().equals("FoundationColor")) {
eta.put("color", v);
} else if(entry.getKey().equals("Light")) {
eta.put("light", v);
} else if(entry.getKey().equals("LightType")) {
eta.put("type", v);
} else if(entry.getKey().equals("Period")) {
eta.put("period", v);
} else if(entry.getKey().equals("Note")) {
eta.put("note", v);
} else if(entry.getKey().equals("LocalDesignator")) {
eta.put("local-desig", v);
} else if(entry.getKey().equals("InternationalDesignator")) {
eta.put("int-desig", v);
} else if(entry.getKey().equals("FacilityPoint")) {
eta.put("facilities", v);
} else if(entry.getKey().equals("Racon")) {
eta.put("racon", v);
} else if(entry.getKey().equals("LeadingAngle")) {
eta.put("leading-angle", v);
}
}
if(colour != 0 || style != 0)
eta.put("style", "0x" + Integer.toHexString((style << 8) | colour));
return new ExtTypeAttributes(eta, "Line " + lineNo);
}
/**
* Construct the restrictions object.
*/
private void restriction(String name, String value) {
try {
// Proceed only if the restriction is not already marked as invalid.
if (restriction.isValid()) {
if (name.equals("Nod")) {
restriction.setNodId(Long.valueOf(value));
} else if (name.equals("TraffPoints")) {
String[] traffPoints = value.split(",");
// Supported restriction type.
/*
[RESTRICT]
TraffPoints=16968,25008,25009
TraffRoads=520763,532674
[END-RESTRICT]
*/
if (traffPoints.length == 3) {
restriction.setFromNodId(Long.valueOf(traffPoints[0]));
restriction.setToNodId(Long.valueOf(traffPoints[2]));
} else if (traffPoints.length < 3) {
restriction.setValid(false);
log.error("Invalid restriction definition. " + restriction);
} else { // More than 3 nodes are participating in the restriction
// Not supported.
/*
[RESTRICT]
TraffPoints=25009,25008,16968,16967
TraffRoads=532674,520763,520763
[END-RESTRICT]
*/
restriction.setValid(false);
log.info("Restrictions composed from 3 or more roads are not yet supported");
}
} else if (name.equals("TraffRoads")) {
String[] traffRoads = value.split(",");
restriction.setRoadIdA(Long.valueOf(traffRoads[0]));
restriction.setRoadIdB(Long.valueOf(traffRoads[1]));
} else if (name.equals("RestrParam")) {
restriction.setExceptMask(getRestrictionExceptionMask(value));
} else if (name.equals("Time")) {
// Do nothing for now
}
}
} catch (NumberFormatException ex) { // This exception means that this restriction is not properly defined.
restriction.setValid(false); // Mark this as an invalid restriction.
log.error("Invalid restriction definition. " + restriction);
}
}
/**
* Constructs the vehicle exception mask from the restriction params.
* From cGPSMapper manual :-
* <p>
* By default restrictions apply to all kind of vehicles, if
* RestrParam is used, then restriction will be ignored by
* specified types of vehicles.
* </p>
* <p>
* [Emergency],[delivery],[car],[bus],[taxi],[pedestrian],[bicycle],[truck]
* </p>
* <p>
* Example:
* RestrParam=0,1,1,0
* </p>
* Above definition will set the restriction to be applied for
* Emergency, Bus, Taxi, Pedestrian and Bicycle. Restriction
* will NOT apply for Delivery and Car.
*
* @param value Tag value
* @return the exceptMask in mkgmap internal format
*/
private byte getRestrictionExceptionMask(String value) {
String[] params = value.split(",");
byte exceptMask = 0x00;
if (params.length > 0 && params.length <=8) { // Got to have at least one param but not more than 8.
for (int i=0; i<params.length; i++) {
if ("1".equals(params[i])) {
switch(i) {
case 0:
exceptMask |= AccessTagsAndBits.EMERGENCY;
break;
case 1:
exceptMask |= AccessTagsAndBits.DELIVERY;
break;
case 2:
exceptMask |= AccessTagsAndBits.CAR;
break;
case 3:
exceptMask |= AccessTagsAndBits.BUS;
break;
case 4:
exceptMask |= AccessTagsAndBits.TAXI;
break;
case 5:
exceptMask |= AccessTagsAndBits.FOOT;
break;
case 6:
exceptMask |= AccessTagsAndBits.BIKE;
break;
case 7:
exceptMask |= AccessTagsAndBits.TRUCK;
break;
}
}
}
} else {
log.error("Invalid RestrParam definition. -> " + value);
}
return exceptMask;
}
}