[SCM] mkgmap branch, master, updated. a025ad059e22735c2c0701cdc6fa2cc6fb2540b0
Andreas Tille
tille at debian.org
Fri Jan 24 14:55:03 UTC 2014
The following commit has been merged in the master branch:
commit deb0c79831ddb120fb279bd83bb0bab444a66a02
Author: Andreas Tille <tille at debian.org>
Date: Fri Jan 24 15:53:37 2014 +0100
Imported Upstream version 0.0.0+svn2981
diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..cb68169
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="src" path="resources"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="test"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/junit"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/resource"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
+ <classpathentry kind="lib" path="lib/compile/protobuf-java-2.4.1.jar"/>
+ <classpathentry kind="lib" path="lib/compile/osmpbf-1.1.1-754a33af.jar"/>
+ <classpathentry kind="lib" path="lib/compile/fastutil-6.5.2-mkg.1.jar"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f0a3178
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+*.img
+*.tdb
+*.typ
+*~
+bin
+build/classes
+dist
+ivy-distrib/
+lib/
+mkgmap.log.*
diff --git a/.idea/ant.xml b/.idea/ant.xml
new file mode 100644
index 0000000..313b0c0
--- /dev/null
+++ b/.idea/ant.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="AntConfiguration">
+ <buildFile url="file://$PROJECT_DIR$/build.xml" />
+ </component>
+</project>
+
diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml
new file mode 100644
index 0000000..c3eb785
--- /dev/null
+++ b/.idea/codeStyleSettings.xml
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ProjectCodeStyleSettingsManager">
+ <option name="PER_PROJECT_SETTINGS">
+ <value>
+ <option name="JAVA_INDENT_OPTIONS">
+ <value>
+ <option name="INDENT_SIZE" value="4" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="true" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </value>
+ </option>
+ <option name="JSP_INDENT_OPTIONS">
+ <value>
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="4" />
+ <option name="TAB_SIZE" value="2" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </value>
+ </option>
+ <option name="XML_INDENT_OPTIONS">
+ <value>
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="4" />
+ <option name="TAB_SIZE" value="2" />
+ <option name="USE_TAB_CHARACTER" value="true" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </value>
+ </option>
+ <option name="OTHER_INDENT_OPTIONS">
+ <value>
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="2" />
+ <option name="USE_TAB_CHARACTER" value="true" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </value>
+ </option>
+ <option name="LINE_SEPARATOR" value="
" />
+ <option name="USE_FQ_CLASS_NAMES_IN_JAVADOC" value="false" />
+ <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="20" />
+ <option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
+ <value>
+ <package name="java.awt" withSubpackages="false" static="false" />
+ <package name="" withSubpackages="true" static="false" />
+ <package name="javax.swing" withSubpackages="false" static="false" />
+ <package name="org.junit.Assert" withSubpackages="true" static="false" />
+ </value>
+ </option>
+ <option name="IMPORT_LAYOUT_TABLE">
+ <value>
+ <package name="java" withSubpackages="true" static="false" />
+ <emptyLine />
+ <package name="javax" withSubpackages="true" static="false" />
+ <emptyLine />
+ <package name="uk.me.parabola" withSubpackages="true" static="false" />
+ <emptyLine />
+ <package name="" withSubpackages="true" static="false" />
+ <emptyLine />
+ <package name="" withSubpackages="true" static="true" />
+ </value>
+ </option>
+ <option name="RIGHT_MARGIN" value="100" />
+ <option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
+ <option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
+ <option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
+ <option name="JD_P_AT_EMPTY_LINES" value="false" />
+ <option name="HTML_KEEP_LINE_BREAKS_IN_TEXT" value="false" />
+ <option name="HTML_KEEP_BLANK_LINES" value="1" />
+ <option name="HTML_ALIGN_ATTRIBUTES" value="false" />
+ <option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
+ <option name="BLOCK_COMMENT_AT_FIRST_COLUMN" value="false" />
+ <option name="BRACE_STYLE" value="5" />
+ <option name="CLASS_BRACE_STYLE" value="5" />
+ <option name="METHOD_BRACE_STYLE" value="5" />
+ <option name="INDENT_CASE_FROM_SWITCH" value="false" />
+ <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+ <option name="WRAP_COMMENTS" value="true" />
+ <XML>
+ <option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
+ </XML>
+ <ADDITIONAL_INDENT_OPTIONS fileType="haml">
+ <option name="INDENT_SIZE" value="2" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="txt">
+ <option name="INDENT_SIZE" value="2" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <codeStyleSettings language="Groovy">
+ <option name="BRACE_STYLE" value="5" />
+ <option name="CLASS_BRACE_STYLE" value="5" />
+ <option name="METHOD_BRACE_STYLE" value="5" />
+ <option name="INDENT_CASE_FROM_SWITCH" value="false" />
+ <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+ <option name="PARENT_SETTINGS_INSTALLED" value="true" />
+ <indentOptions>
+ <option name="INDENT_SIZE" value="2" />
+ </indentOptions>
+ </codeStyleSettings>
+ <codeStyleSettings language="JAVA">
+ <option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
+ <option name="BLOCK_COMMENT_AT_FIRST_COLUMN" value="false" />
+ <option name="BRACE_STYLE" value="5" />
+ <option name="CLASS_BRACE_STYLE" value="5" />
+ <option name="METHOD_BRACE_STYLE" value="5" />
+ <option name="INDENT_CASE_FROM_SWITCH" value="false" />
+ <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+ <option name="WRAP_COMMENTS" value="true" />
+ <option name="PARENT_SETTINGS_INSTALLED" value="true" />
+ <indentOptions>
+ <option name="USE_TAB_CHARACTER" value="true" />
+ </indentOptions>
+ </codeStyleSettings>
+ <codeStyleSettings language="JSP">
+ <indentOptions>
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="4" />
+ <option name="TAB_SIZE" value="2" />
+ </indentOptions>
+ </codeStyleSettings>
+ <codeStyleSettings language="JavaScript">
+ <option name="BRACE_STYLE" value="5" />
+ <option name="METHOD_BRACE_STYLE" value="5" />
+ <option name="INDENT_CASE_FROM_SWITCH" value="false" />
+ <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+ <option name="PARENT_SETTINGS_INSTALLED" value="true" />
+ <indentOptions>
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="USE_TAB_CHARACTER" value="true" />
+ </indentOptions>
+ </codeStyleSettings>
+ <codeStyleSettings language="PHP">
+ <option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
+ <option name="BLOCK_COMMENT_AT_FIRST_COLUMN" value="false" />
+ <option name="BRACE_STYLE" value="5" />
+ <option name="CLASS_BRACE_STYLE" value="5" />
+ <option name="METHOD_BRACE_STYLE" value="5" />
+ <option name="INDENT_CASE_FROM_SWITCH" value="false" />
+ <option name="WRAP_COMMENTS" value="true" />
+ <option name="PARENT_SETTINGS_INSTALLED" value="true" />
+ </codeStyleSettings>
+ <codeStyleSettings language="Python">
+ <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+ <option name="PARENT_SETTINGS_INSTALLED" value="true" />
+ </codeStyleSettings>
+ <codeStyleSettings language="TypeScript">
+ <option name="BRACE_STYLE" value="5" />
+ <option name="CLASS_BRACE_STYLE" value="5" />
+ <option name="METHOD_BRACE_STYLE" value="5" />
+ <option name="INDENT_CASE_FROM_SWITCH" value="false" />
+ <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+ <option name="PARENT_SETTINGS_INSTALLED" value="true" />
+ </codeStyleSettings>
+ <codeStyleSettings language="XML">
+ <indentOptions>
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="4" />
+ <option name="TAB_SIZE" value="2" />
+ <option name="USE_TAB_CHARACTER" value="true" />
+ </indentOptions>
+ </codeStyleSettings>
+ </value>
+ </option>
+ <option name="USE_PER_PROJECT_SETTINGS" value="true" />
+ </component>
+</project>
+
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..33ad2dc
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="BuildJarProjectSettings">
+ <option name="BUILD_JARS_ON_MAKE" value="false" />
+ </component>
+ <component name="CompilerConfiguration">
+ <option name="DEFAULT_COMPILER" value="Javac" />
+ <excludeFromCompile>
+ <file url="file://$PROJECT_DIR$/src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaSaver.java" />
+ <file url="file://$PROJECT_DIR$/src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaGenerator.java" />
+ </excludeFromCompile>
+ <resourceExtensions>
+ <entry name=".+\.(properties|xml|html|dtd|tld)" />
+ <entry name=".+\.(gif|png|jpeg|jpg)" />
+ </resourceExtensions>
+ <wildcardResourcePatterns>
+ <entry name="?*.properties" />
+ <entry name="?*.xml" />
+ <entry name="?*.gif" />
+ <entry name="?*.png" />
+ <entry name="?*.jpeg" />
+ <entry name="?*.jpg" />
+ <entry name="?*.html" />
+ <entry name="?*.dtd" />
+ <entry name="?*.tld" />
+ <entry name="?*.properties" />
+ <entry name="?*.xml" />
+ <entry name="?*.html" />
+ <entry name="?*.dtd" />
+ <entry name="?*.tld" />
+ <entry name="?*.gif" />
+ <entry name="?*.png" />
+ <entry name="?*.jpeg" />
+ <entry name="?*.jpg" />
+ </wildcardResourcePatterns>
+ <annotationProcessing>
+ <profile default="true" name="Default" enabled="false">
+ <processorPath useClasspath="true" />
+ </profile>
+ </annotationProcessing>
+ </component>
+ <component name="EclipseCompilerSettings">
+ <option name="GENERATE_NO_WARNINGS" value="true" />
+ <option name="DEPRECATION" value="false" />
+ </component>
+</project>
+
diff --git a/.idea/copyright/gpl.xml b/.idea/copyright/gpl.xml
new file mode 100644
index 0000000..b5986d2
--- /dev/null
+++ b/.idea/copyright/gpl.xml
@@ -0,0 +1,9 @@
+<component name="CopyrightManager">
+ <copyright>
+ <option name="notice" value="Copyright (C) $today.year.
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." />
+ <option name="keyword" value="Copyright" />
+ <option name="allowReplaceKeyword" value="" />
+ <option name="myName" value="gpl" />
+ <option name="myLocal" value="true" />
+ </copyright>
+</component>
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..7e2edc5
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,5 @@
+<component name="CopyrightManager">
+ <settings default="gpl">
+ <module2copyright />
+ </settings>
+</component>
\ No newline at end of file
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
new file mode 100644
index 0000000..f6e673a
--- /dev/null
+++ b/.idea/dataSources.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4" />
+
diff --git a/.idea/dictionaries/steve.xml b/.idea/dictionaries/steve.xml
new file mode 100644
index 0000000..09cba22
--- /dev/null
+++ b/.idea/dictionaries/steve.xml
@@ -0,0 +1,110 @@
+<component name="ProjectDictionaryState">
+ <dictionary name="steve">
+ <words>
+ <w>Garmin</w>
+ <w>addr</w>
+ <w>andrzej</w>
+ <w>basename</w>
+ <w>bbox</w>
+ <w>bicubic</w>
+ <w>bitmask</w>
+ <w>bitset</w>
+ <w>bitsets</w>
+ <w>bitstream</w>
+ <w>checksum</w>
+ <w>classname</w>
+ <w>codepage</w>
+ <w>colormode</w>
+ <w>coord</w>
+ <w>coords</w>
+ <w>defs</w>
+ <w>dest</w>
+ <w>discontiguous</w>
+ <w>endian</w>
+ <w>etrex</w>
+ <w>filenames</w>
+ <w>fixme</w>
+ <w>footways</w>
+ <w>fout</w>
+ <w>garmin</w>
+ <w>garmin's</w>
+ <w>gawron</w>
+ <w>geofabrik</w>
+ <w>gmapsupp</w>
+ <w>gpsmapedit</w>
+ <w>gtype</w>
+ <w>gtypes</w>
+ <w>hashlist</w>
+ <w>heibler</w>
+ <w>imgfmt</w>
+ <w>indexable</w>
+ <w>infs</w>
+ <w>intelli</w>
+ <w>interspaced</w>
+ <w>isolines</w>
+ <w>isophase</w>
+ <w>landkarte</w>
+ <w>liboni</w>
+ <w>locator</w>
+ <w>luÃnig</w>
+ <w>mapname</w>
+ <w>mapsource</w>
+ <w>maxspeed</w>
+ <w>moveto</w>
+ <w>multi</w>
+ <w>multimap</w>
+ <w>multipolygon</w>
+ <w>nonspacing</w>
+ <w>occulting</w>
+ <w>oneway</w>
+ <w>oneways</w>
+ <w>outfs</w>
+ <w>outputing</w>
+ <w>pathname</w>
+ <w>peucker</w>
+ <w>pixmaps</w>
+ <w>pois</w>
+ <w>polyline</w>
+ <w>polylines</w>
+ <w>popowsk</w>
+ <w>prepended</w>
+ <w>printf</w>
+ <w>println</w>
+ <w>programmatically</w>
+ <w>racon</w>
+ <w>racons</w>
+ <w>ratcliffe</w>
+ <w>recsize</w>
+ <w>reentrancy</w>
+ <w>resize</w>
+ <w>resized</w>
+ <w>rethrown</w>
+ <w>rgba</w>
+ <w>routable</w>
+ <w>rrggbb</w>
+ <w>seamark</w>
+ <w>slon</w>
+ <w>startup</w>
+ <w>struct</w>
+ <w>subdiv</w>
+ <w>subdivsion</w>
+ <w>subfiles</w>
+ <w>subtree</w>
+ <w>superclass</w>
+ <w>tagname</w>
+ <w>tagval</w>
+ <w>taskdef</w>
+ <w>topo</w>
+ <w>tweeze</w>
+ <w>unshifted</w>
+ <w>usedom</w>
+ <w>vollmert</w>
+ <w>wierd</w>
+ <w>xcharset</w>
+ <w>xcode</w>
+ <w>xmlattr</w>
+ <w>zip'ed</w>
+ <w>zoraster</w>
+ </words>
+ </dictionary>
+</component>
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..8008103
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false">
+ <file url="file://$PROJECT_DIR$/resources/installer/installer_template.nsi" charset="ISO-8859-1" />
+ <file url="file://$PROJECT_DIR$/src/uk/me/parabola/imgfmt/app/srt/package.html" charset="ISO-8859-1" />
+ </component>
+</project>
+
diff --git a/.idea/excludeFromValidation.xml b/.idea/excludeFromValidation.xml
new file mode 100644
index 0000000..f6e673a
--- /dev/null
+++ b/.idea/excludeFromValidation.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4" />
+
diff --git a/.idea/fileColors.xml b/.idea/fileColors.xml
new file mode 100644
index 0000000..f6e673a
--- /dev/null
+++ b/.idea/fileColors.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4" />
+
diff --git a/.idea/inspectionProfiles/Mapping.xml b/.idea/inspectionProfiles/Mapping.xml
new file mode 100644
index 0000000..3de260f
--- /dev/null
+++ b/.idea/inspectionProfiles/Mapping.xml
@@ -0,0 +1,2588 @@
+<component name="InspectionProjectProfileManager">
+ <profile version="1.0" is_locked="true">
+ <option name="myName" value="Mapping" />
+ <option name="myLocal" value="false" />
+ <inspection_tool class="AbsoluteAlignmentInUserInterface" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AbstractBeanReferencesInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AbstractClassExtendsConcreteClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AbstractClassNeverImplemented" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AbstractClassWithOnlyOneDirectInheritor" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AbstractClassWithoutAbstractMethods" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AbstractMethodCallInConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AbstractMethodOverridesAbstractMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AbstractMethodOverridesConcreteMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AbstractMethodWithMissingImplementations" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AccessStaticViaInstance" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AccessToNonThreadSafeStaticFieldFromInstance" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="nonThreadSafeClasses">
+ <value />
+ </option>
+ <option name="nonThreadSafeTypes" value="java.text.DateFormat,java.util.Calendar" />
+ </inspection_tool>
+ <inspection_tool class="AccessToStaticFieldLockedOnInstance" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AmbiguousFieldAccess" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AmbiguousMethodCall" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidDomInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidElementNotAllowed" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintAdapterViewChildren" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintAllowBackup" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintAlwaysShowAction" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintBackButton" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintButtonCase" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintButtonOrder" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintButtonStyle" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintCommitPrefEdits" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintContentDescription" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintCutPasteId" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintDeviceAdmin" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintDisableBaselineAlignment" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintDrawAllocation" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintDuplicateActivity" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintDuplicateDefinition" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintDuplicateIds" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintDuplicateIncludedIds" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintDuplicateUsesFeature" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintEasterEgg" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintEnforceUTF8" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintExportedContentProvider" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintExportedReceiver" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintExportedService" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintExtraText" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintExtraTranslation" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintGifUsage" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintGrantAllUris" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintGridLayout" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintHardcodedDebugMode" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintHardcodedText" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintIconColors" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintIconDensities" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintIconDipSize" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintIconDuplicates" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintIconDuplicatesConfig" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintIconExpectedSize" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintIconExtension" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintIconLauncherShape" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintIconLocation" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintIconMissingDensityFolder" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintIconMixedNinePatch" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintIconNoDpi" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintIconXmlAndPng" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintIllegalResourceRef" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintInOrMmUsage" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintInconsistentArrays" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintInconsistentLayout" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintInefficientWeight" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintInlinedApi" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintInnerclassSeparator" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintInvalidId" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintLabelFor" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintLibraryCustomView" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintLocalSuppress" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintMangledCRLF" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintManifestOrder" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintMenuTitle" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintMergeRootFrame" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintMissingApplicationIcon" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintMissingId" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintMissingPrefix" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintMissingQuantity" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintMissingSuperCall" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintMissingTranslation" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintMissingVersion" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintMockLocation" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintMultipleUsesSdk" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintNestedScrolling" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintNestedWeights" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintNewApi" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintNotSibling" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintObsoleteLayoutParam" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintOldTargetApi" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintOrientation" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintOverdraw" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintOverride" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintPackagedPrivateKey" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintPrivateResource" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintProguard" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintProguardSplit" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintProguardSplitConfig" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintProtectedPermissions" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintPxUsage" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintRegistered" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintRequiredSize" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintResAuto" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintResourceAsColor" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintRtlCompat" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintRtlEnabled" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintRtlHardcoded" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintScrollViewCount" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintScrollViewSize" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintSdCardPath" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintSelectableText" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintServiceCast" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintSetJavaScriptEnabled" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintShowToast" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintSmallSp" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintSpUsage" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintSparseArray" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintStateListReachable" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintStopShip" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintStringFormatCount" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintStringFormatInvalid" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintStringFormatMatches" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintStyleCycle" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintSuspicious0dp" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintSuspiciousImport" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintTextFields" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintTextViewEdits" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintTooDeepLayout" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintTooManyViews" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintTypographyDashes" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintTypographyEllipsis" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintTypographyFractions" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintTypographyOther" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintTypographyQuotes" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintTypos" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintUniquePermission" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintUnknownId" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintUnknownIdInLayout" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintUnlocalizedSms" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintUnusedIds" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintUnusedQuantity" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintUnusedResources" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintUseCheckPermission" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintUseCompoundDrawables" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintUseSparseArrays" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintUseValueOf" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintUselessLeaf" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintUselessParent" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintUsesMinSdkAttributes" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintWorldReadableFiles" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintWorldWriteableFiles" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintWrongCase" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintWrongFolder" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintWrongViewCast" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="AndroidMissingOnClickHandler" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidNonConstantResIdsInSwitch" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="AndroidUnknownAttribute" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="Annotation" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AnnotationClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AnnotationNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*" />
+ <option name="m_minLength" value="8" />
+ <option name="m_maxLength" value="64" />
+ </inspection_tool>
+ <inspection_tool class="Annotator" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="Anonymous2MethodRef" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AnonymousClassComplexity" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="3" />
+ </inspection_tool>
+ <inspection_tool class="AnonymousClassMethodCount" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="1" />
+ </inspection_tool>
+ <inspection_tool class="AnonymousClassVariableHidesContainingMethodVariable" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AnonymousFunctionJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AnonymousInnerClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AnonymousInnerClassMayBeStatic" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AntDuplicateTargetsInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AntMissingPropertiesFileInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AntResolveInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AppEngineDeprecatedRuntimeInspection" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AppEngineForbiddenCode" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="AppEngineThreadsafeCGIHandlerInspection" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AppEngineThreadsafeInspection" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ArchaicSystemPropertyAccess" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ArgNamesErrorsInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="ArgNamesWarningsInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AroundAdviceStyleInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ArrayEquality" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ArrayEquals" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ArrayHashCode" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ArrayLengthInLoopCondition" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ArraysAsListWithZeroOrOneArgument" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AssertAsName" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AssertEqualsBetweenInconvertibleTypes" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AssertEqualsBetweenInconvertibleTypesTestNG" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AssertEqualsCalledOnArray" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AssertEqualsMayBeAssertSame" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AssertStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AssertWithSideEffects" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AssertsWithoutMessages" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AssertsWithoutMessagesTestNG" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AssignmentResultUsedJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AssignmentToCatchBlockParameter" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AssignmentToCollectionFieldFromParameter" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignorePrivateMethods" value="true" />
+ </inspection_tool>
+ <inspection_tool class="AssignmentToDateFieldFromParameter" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignorePrivateMethods" value="true" />
+ </inspection_tool>
+ <inspection_tool class="AssignmentToForLoopParameter" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_checkForeachParameters" value="false" />
+ </inspection_tool>
+ <inspection_tool class="AssignmentToForLoopParameterJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AssignmentToFunctionParameterJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AssignmentToMethodParameter" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreTransformationOfOriginalParameter" value="false" />
+ </inspection_tool>
+ <inspection_tool class="AssignmentToNull" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AssignmentToStaticFieldFromInstanceMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AssignmentToSuperclassField" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AssignmentUsedAsCondition" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AutoBoxing" enabled="false" level="INFO" enabled_by_default="false">
+ <option name="ignoreAddedToCollection" value="false" />
+ </inspection_tool>
+ <inspection_tool class="AutoCloseableResource" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AutoUnboxing" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AutowiredDependenciesInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AwaitNotInLoop" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AwaitWithoutCorrespondingSignal" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BadExceptionCaught" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="exceptionsString" value="java.lang.NullPointerException,java.lang.IllegalMonitorStateException,java.lang.ArrayIndexOutOfBoundsException" />
+ <option name="exceptions">
+ <value />
+ </option>
+ </inspection_tool>
+ <inspection_tool class="BadExceptionDeclared" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="exceptionsString" value="java.lang.Throwable,java.lang.Exception,java.lang.Error,java.lang.RuntimeException,java.lang.NullPointerException,java.lang.ClassCastException,java.lang.ArrayIndexOutOfBoundsException" />
+ <option name="exceptions">
+ <value />
+ </option>
+ <option name="ignoreTestCases" value="false" />
+ <option name="ignoreLibraryOverrides" value="false" />
+ </inspection_tool>
+ <inspection_tool class="BadExceptionThrown" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="exceptionsString" value="java.lang.Throwable,java.lang.Exception,java.lang.Error,java.lang.RuntimeException,java.lang.NullPointerException,java.lang.ClassCastException,java.lang.ArrayIndexOutOfBoundsException" />
+ <option name="exceptions">
+ <value />
+ </option>
+ </inspection_tool>
+ <inspection_tool class="BadExpressionStatementJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="BadOddness" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BatchJobDomInspection" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="BatchXmlDomInspection" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="BeforeClassOrAfterClassIsPublicStaticVoidNoArg" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BeforeOrAfterIsPublicVoidNoArg" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BigDecimalEquals" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BindingAnnotationWithoutInject" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BlockStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BooleanConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="BooleanMethodIsAlwaysInverted" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BooleanMethodNameMustStartWithQuestion" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreBooleanMethods" value="false" />
+ <option name="ignoreInAnnotationInterface" value="true" />
+ <option name="onlyWarnOnBaseMethods" value="true" />
+ <option name="questionString" value="is,can,has,should,could,will,shall,check,contains,equals,add,put,remove,startsWith,endsWith" />
+ </inspection_tool>
+ <inspection_tool class="BooleanParameter" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BooleanVariableAlwaysNegated" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BoundFieldAssignment" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="BoxingBoxedValue" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="BpmnConfigDomInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="BreakStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BreakStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BreakStatementWithLabel" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BreakStatementWithLabelJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BuildoutUnresolvedPartInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="BusyWait" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BvConfigDomInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="BvConstraintMappingsInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CStyleArrayDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CachedNumberConstructorCall" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CallToNativeMethodWhileLocked" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CallToSimpleGetterInClass" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreGetterCallsOnOtherObjects" value="false" />
+ <option name="onlyReportPrivateGetter" value="false" />
+ </inspection_tool>
+ <inspection_tool class="CallToSimpleSetterInClass" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreSetterCallsOnOtherObjects" value="false" />
+ <option name="onlyReportPrivateSetter" value="false" />
+ </inspection_tool>
+ <inspection_tool class="CallToStringConcatCanBeReplacedByOperator" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CallerJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CanBeFinal" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="REPORT_CLASSES" value="false" />
+ <option name="REPORT_METHODS" value="false" />
+ <option name="REPORT_FIELDS" value="true" />
+ </inspection_tool>
+ <inspection_tool class="CastConflictsWithInstanceof" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CastThatLosesPrecision" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreIntegerCharCasts" value="false" />
+ </inspection_tool>
+ <inspection_tool class="CastToConcreteClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CastToIncompatibleInterface" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CatchGenericClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CaughtExceptionImmediatelyRethrown" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CdiAlternativeInspection" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CdiDecoratorInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CdiDisposerMethodInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CdiDomBeans" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CdiInjectInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CdiInjectionPointsInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CdiInterceptorInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CdiManagedBeanInconsistencyInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CdiNormalScopeInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CdiObservesInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CdiSpecializesInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CdiStereotypeInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CdiStereotypeRestrictionsInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CdiTypedAnnotationInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CdiUnproxyableBeanTypesInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CfmlReferenceInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ChainedEquality" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ChainedEqualityJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ChainedFunctionCallJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ChainedMethodCall" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreFieldInitializations" value="true" />
+ <option name="m_ignoreThisSuperCalls" value="true" />
+ </inspection_tool>
+ <inspection_tool class="ChannelResource" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="insideTryAllowed" value="false" />
+ </inspection_tool>
+ <inspection_tool class="CharUsedInArithmeticContext" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CharacterComparison" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CheckDtdRefs" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CheckEmptyScriptTag" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CheckForOutOfMemoryOnLargeArrayAllocation" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="64" />
+ </inspection_tool>
+ <inspection_tool class="CheckImageSize" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CheckNodeTest" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CheckTagEmptyBody" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CheckValidXmlInScriptTagBody" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CheckXmlFileWithXercesValidator" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CheckedExceptionClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ClashingGetters" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ClassComplexity" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="80" />
+ </inspection_tool>
+ <inspection_tool class="ClassCoupling" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_includeJavaClasses" value="false" />
+ <option name="m_includeLibraryClasses" value="false" />
+ <option name="m_limit" value="15" />
+ </inspection_tool>
+ <inspection_tool class="ClassEscapesItsScope" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ClassHasNoToStringMethod" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="excludeClassNames" value="" />
+ <option name="excludeException" value="true" />
+ <option name="excludeDeprecated" value="true" />
+ <option name="excludeEnum" value="false" />
+ <option name="excludeAbstract" value="false" />
+ <option name="excludeTestCode" value="false" />
+ <option name="excludeInnerClasses" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ClassInTopLevelPackage" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ClassIndependentOfModule" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ClassInheritanceDepth" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="2" />
+ </inspection_tool>
+ <inspection_tool class="ClassInitializer" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ClassInitializerMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ClassLoaderInstantiation" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ClassMayBeInterface" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ClassNameDiffersFromFileName" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ClassNamePrefixedWithPackageName" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ClassNameSameAsAncestorName" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ClassNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*" />
+ <option name="m_minLength" value="8" />
+ <option name="m_maxLength" value="64" />
+ </inspection_tool>
+ <inspection_tool class="ClassNestingDepth" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="1" />
+ </inspection_tool>
+ <inspection_tool class="ClassNewInstance" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ClassOnlyUsedInOneModule" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ClassOnlyUsedInOnePackage" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ClassReferencesSubclass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ClassUnconnectedToPackage" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ClassWithMultipleLoggers" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="loggerNamesString" value="java.util.logging.Logger,org.slf4j.Logger,org.apache.commons.logging.Log,org.apache.log4j.Logger" />
+ </inspection_tool>
+ <inspection_tool class="ClassWithTooManyDependencies" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="limit" value="10" />
+ </inspection_tool>
+ <inspection_tool class="ClassWithTooManyDependents" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="limit" value="10" />
+ </inspection_tool>
+ <inspection_tool class="ClassWithTooManyTransitiveDependencies" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="limit" value="35" />
+ </inspection_tool>
+ <inspection_tool class="ClassWithTooManyTransitiveDependents" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="limit" value="35" />
+ </inspection_tool>
+ <inspection_tool class="ClassWithoutConstructor" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ClassWithoutLogger" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="loggerNamesString" value="java.util.logging.Logger,org.slf4j.Logger,org.apache.commons.logging.Log,org.apache.log4j.Logger" />
+ <option name="ignoreSuperLoggers" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ClassWithoutNoArgConstructor" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreClassesWithNoConstructors" value="true" />
+ </inspection_tool>
+ <inspection_tool class="CloneCallsConstructors" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CloneCallsSuperClone" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CloneDeclaresCloneNotSupported" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CloneInNonCloneableClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CloneableClassInSecureContext" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CloneableImplementsClone" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreCloneableDueToInheritance" value="true" />
+ </inspection_tool>
+ <inspection_tool class="CodeBlock2Expr" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CollectionAddedToSelf" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CollectionContainsUrl" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CollectionsFieldAccessReplaceableByMethodCall" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CollectionsMustHaveInitialCapacity" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CommaExpressionJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ComparableImplementedButEqualsNotOverridden" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ComparatorMethodParameterNotUsed" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ComparatorNotSerializable" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CompareToUsesNonFinalVariable" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ComparisonOfShortAndChar" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ComparisonToNaN" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ComponentNotRegistered" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="CHECK_ACTIONS" value="true" />
+ <option name="IGNORE_NON_PUBLIC" value="true" />
+ </inspection_tool>
+ <inspection_tool class="ComponentRegistrationProblems" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="ConditionSignal" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConditionalExpression" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreSimpleAssignmentsAndReturns" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ConditionalExpressionJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConditionalExpressionWithIdenticalBranches" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConditionalExpressionWithIdenticalBranchesJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConflictingAnnotations" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConfusingElse" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="reportWhenNoStatementFollow" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ConfusingFloatingPointLiteral" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConfusingFloatingPointLiteralJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConfusingMainMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConfusingOctalEscape" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConfusingPlusesOrMinusesJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConnectionResource" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConstantAssertCondition" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConstantConditionalExpression" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConstantConditionalExpressionJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConstantConditions" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="SUGGEST_NULLABLE_ANNOTATIONS" value="false" />
+ <option name="DONT_REPORT_TRUE_ASSERT_STATEMENTS" value="true" />
+ </inspection_tool>
+ <inspection_tool class="ConstantDeclaredInAbstractClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConstantDeclaredInInterface" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConstantIfStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConstantIfStatementJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConstantJUnitAssertArgument" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConstantMathCall" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConstantNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="onlyCheckImmutables" value="false" />
+ <option name="m_regex" value="[A-Z_\d]*" />
+ <option name="m_minLength" value="5" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="ConstantOnLHSOfComparison" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConstantOnLHSOfComparisonJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConstantOnRHSOfComparison" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConstantOnRHSOfComparisonJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConstantStringIntern" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConstantValueVariableUse" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConstraintValidatorCreator" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConstructorCount" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreDeprecatedConstructors" value="false" />
+ <option name="m_limit" value="5" />
+ </inspection_tool>
+ <inspection_tool class="ContextComponentScanInconsistencyInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="ContinueOrBreakFromFinallyBlock" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ContinueOrBreakFromFinallyBlockJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ContinueStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ContinueStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ContinueStatementWithLabel" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ContinueStatementWithLabelJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ControlFlowStatementWithoutBraces" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="Convert2Diamond" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="Convert2Lambda" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="Convert2MethodRef" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConvertAnnotations" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConvertJavadoc" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConvertOldAnnotations" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CovariantCompareTo" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CovariantEquals" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CriteriaApiResolveInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="CssConvertColorToHexInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CssConvertColorToRgbInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CssInvalidAtRule" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CssInvalidCharsetRule" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CssInvalidElement" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CssInvalidElementInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CssInvalidHtmlTagReference" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CssInvalidHtmlTagReferenceInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CssInvalidImport" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CssInvalidImportInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CssInvalidPseudoSelector" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CssInvalidShorthandPropertyValue" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CssMissingSemicolon" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CssMissingSemicolonInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CssNegativeValue" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CssNegativeValueInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CssNoGenericFontName" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CssOptimizeSimilarProperties" enabled="false" level="WEAK WARNING" enabled_by_default="true" />
+ <inspection_tool class="CssOptimizeSimilarPropertiesInspection" enabled="true" level="INFO" enabled_by_default="true" />
+ <inspection_tool class="CssOverwrittenProperties" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CssRgbFunction" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CssRgbFunctionInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CssShorthandPropertyValue" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CssUnitlessNumber" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CssUnknownProperty" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="myCustomPropertiesEnabled" value="false" />
+ <option name="myIgnoreVendorSpecificProperties" value="false" />
+ <option name="myCustomPropertiesList">
+ <value>
+ <list size="0" />
+ </value>
+ </option>
+ </inspection_tool>
+ <inspection_tool class="CssUnknownTarget" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CssUnknownTargetInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CssUnusedSymbol" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CssUnusedSymbolInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CucumberExamplesColon" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="CucumberMissedExamples" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="CucumberTableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CucumberUndefinedStep" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CustomClassloader" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CustomSecurityManager" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CyclicClassDependency" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CyclicPackageDependency" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CyclomaticComplexity" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="10" />
+ </inspection_tool>
+ <inspection_tool class="CyclomaticComplexityJS" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="10" />
+ </inspection_tool>
+ <inspection_tool class="DateToString" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DebuggerStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DeclareCollectionAsInterface" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreLocalVariables" value="false" />
+ <option name="ignorePrivateMethodsAndFields" value="false" />
+ </inspection_tool>
+ <inspection_tool class="DeclareParentsInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="DefaultFileTemplate" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="CHECK_FILE_HEADER" value="true" />
+ <option name="CHECK_TRY_CATCH_SECTION" value="true" />
+ <option name="CHECK_METHOD_BODY" value="true" />
+ </inspection_tool>
+ <inspection_tool class="DefaultNotLastCaseInSwitch" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DefaultNotLastCaseInSwitchJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DelegatesTo" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="Dependency" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="DeprecatedClassUsageInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DeprecatedDefenderSyntax" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="Deprecation" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DeserializableClassInSecureContext" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DesignForExtension" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DialogTitleCapitalization" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DisjointPackage" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DivideByZero" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DivideByZeroJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DjangoBrokenLineCommentInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DjangoCloseTagInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DjangoRelationInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DjangoUnresolvedFilterInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DjangoUnresolvedLoadInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DjangoUnresolvedStaticReferenceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DjangoUnresolvedTagInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DjangoUnresolvedTemplateReferenceInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="Django_close_tag" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DocumentWriteJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DollarSignInName" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DoubleCheckedLocking" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreOnVolatileVariables" value="false" />
+ </inspection_tool>
+ <inspection_tool class="DoubleLiteralMayBeFloatLiteral" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DoubleNegation" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DriverManagerGetConnection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DuplicateBooleanBranch" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DuplicateCaseLabelJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DuplicateCondition" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreMethodCalls" value="false" />
+ </inspection_tool>
+ <inspection_tool class="DuplicateConditionJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DuplicateMnemonic" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DuplicatePropertyInspection" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="CURRENT_FILE" value="true" />
+ <option name="MODULE_WITH_DEPENDENCIES" value="false" />
+ <option name="CHECK_DUPLICATE_VALUES" value="true" />
+ <option name="CHECK_DUPLICATE_KEYS" value="true" />
+ <option name="CHECK_DUPLICATE_KEYS_WITH_DIFFERENT_VALUES" value="true" />
+ </inspection_tool>
+ <inspection_tool class="DuplicateStringLiteralInspection" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="MIN_STRING_LENGTH" value="5" />
+ <option name="IGNORE_PROPERTY_KEYS" value="false" />
+ </inspection_tool>
+ <inspection_tool class="DuplicateThrows" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DuplicatedBeanNamesInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="DuplicatedBlockNamesInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DynamicRegexReplaceableByCompiledPattern" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DynamicallyGeneratedCodeJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ELDeferredExpressionsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ELMethodSignatureInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ELSpecValidationInJSP" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ELValidationInJSP" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EjbClassBasicInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="EjbClassWarningsInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EjbDomInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="EjbEntityClassInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="EjbEntityHomeInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="EjbEntityInterfaceInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="EjbEnvironmentInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="EjbInterceptorInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="EjbInterceptorWarningsInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EjbInterfaceMethodInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="EjbInterfaceSignatureInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="EjbProhibitedPackageUsageInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EjbQlInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="EjbRemoteRequirementsInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="EjbSessionHomeInterfaceInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="EjbStaticAccessInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EjbThisExpressionInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ElementOnlyUsedFromTestCode" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EmptyCatchBlock" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_includeComments" value="true" />
+ <option name="m_ignoreTestCases" value="true" />
+ <option name="m_ignoreIgnoreParameter" value="true" />
+ </inspection_tool>
+ <inspection_tool class="EmptyCatchBlockJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EmptyClass" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignorableAnnotations">
+ <value />
+ </option>
+ <option name="ignoreClassWithParameterization" value="false" />
+ <option name="ignoreThrowables" value="true" />
+ </inspection_tool>
+ <inspection_tool class="EmptyDirectory" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EmptyFinallyBlock" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EmptyFinallyBlockJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EmptyInitializer" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EmptyMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EmptyStatementBody" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_reportEmptyBlocks" value="false" />
+ </inspection_tool>
+ <inspection_tool class="EmptyStatementBodyJS" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_reportEmptyBlocks" value="false" />
+ </inspection_tool>
+ <inspection_tool class="EmptySynchronizedStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EmptyTryBlock" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EmptyTryBlockJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EmptyWebServiceClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EndBlockNamesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EnumAsName" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EnumClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EnumSwitchStatementWhichMissesCases" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreSwitchStatementsWithDefault" value="false" />
+ </inspection_tool>
+ <inspection_tool class="EnumeratedClassNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*" />
+ <option name="m_minLength" value="8" />
+ <option name="m_maxLength" value="64" />
+ </inspection_tool>
+ <inspection_tool class="EnumeratedConstantNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*" />
+ <option name="m_minLength" value="5" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="EnumerationCanBeIteration" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EqualityComparisonWithCoercionJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EqualsAndHashcode" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EqualsBetweenInconvertibleTypes" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EqualsCalledOnEnumConstant" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EqualsHashCodeCalledOnUrl" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EqualsUsesNonFinalVariable" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="EqualsWhichDoesntCheckParameterClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ErrorRethrown" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ExceptionCaughtLocallyJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ExceptionFromCatchWhichDoesntWrap" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreGetMessage" value="false" />
+ <option name="ignoreCantWrap" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ExceptionNameDoesntEndWithException" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ExpectedExceptionNeverThrown" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ExpectedExceptionNeverThrownTestNG" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ExtendsAnnotation" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ExtendsConcreteCollection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ExtendsObject" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ExtendsTagPositionInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ExtendsThread" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ExtendsUtilityClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ExtensionPointBeanClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ExternalizableWithSerializationMethods" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ExternalizableWithoutPublicNoArgConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FaceletsDetectingInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FacesModelInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="FallThroughInSwitchStatementJS" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FallthroughInSwitchStatementJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FallthruInSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FeatureEnvy" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreTestCases" value="false" />
+ </inspection_tool>
+ <inspection_tool class="FieldAccessNotGuarded" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FieldAccessedSynchronizedAndUnsynchronized" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="countGettersAndSetters" value="false" />
+ </inspection_tool>
+ <inspection_tool class="FieldCanBeLocal" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FieldCount" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_countConstantFields" value="false" />
+ <option name="m_considerStaticFinalFieldsConstant" value="false" />
+ <option name="myCountEnumConstants" value="false" />
+ <option name="m_limit" value="10" />
+ </inspection_tool>
+ <inspection_tool class="FieldHasSetterButNoGetter" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FieldHidesSuperclassField" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreInvisibleFields" value="true" />
+ </inspection_tool>
+ <inspection_tool class="FieldMayBeFinal" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FieldMayBeStatic" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FieldNameWithMistakes" enabled="false" level="INFO" enabled_by_default="false" />
+ <inspection_tool class="FieldNotUsedInToString" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FieldRepeatedlyAccessed" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreFinalFields" value="false" />
+ </inspection_tool>
+ <inspection_tool class="FileEqualsUsage" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FinalClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FinalMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FinalMethodInFinalClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FinalPrivateMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FinalStaticMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="Finalize" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreTrivialFinalizers" value="true" />
+ </inspection_tool>
+ <inspection_tool class="FinalizeCallsSuperFinalize" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreObjectSubclasses" value="false" />
+ <option name="ignoreTrivialFinalizers" value="true" />
+ </inspection_tool>
+ <inspection_tool class="FinalizeNotProtected" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FinallyBlockCannotCompleteNormally" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FlexUnitClassInProductSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FlexUnitClassVisibilityInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FlexUnitClassWithNoTestsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FlexUnitEmptySuiteInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FlexUnitMethodHasParametersInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FlexUnitMethodInSuiteInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FlexUnitMethodIsPropertyInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FlexUnitMethodIsStaticInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FlexUnitMethodReturnTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FlexUnitMethodVisibilityInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FlexUnitMixedAPIInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FlexUnitSuiteWithNoRunnerInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FloatingPointEquality" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ForCanBeForeach" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="REPORT_INDEXED_LOOP" value="true" />
+ <option name="ignoreUntypedCollections" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ForLoopReplaceableByWhile" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreLoopsWithoutConditions" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ForLoopReplaceableByWhileJS" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreLoopsWithoutConditions" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ForLoopThatDoesntUseLoopVariable" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ForLoopThatDoesntUseLoopVariableJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ForLoopWithMissingComponent" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreCollectionLoops" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ForeachStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FtlCallsInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="FtlDeprecatedBuiltInsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FtlFileReferencesInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="FtlImportCallInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="FtlReferencesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FtlTypesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FtlWellformednessInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="FunctionNamingConventionJS" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[a-z][A-Za-z]*" />
+ <option name="m_minLength" value="4" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="FunctionWithInconsistentReturnsJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FunctionWithMultipleLoopsJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="FunctionWithMultipleReturnPointsJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GWTRemoteServiceAsyncCheck" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="GWTStyleCheck" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="Geronimo" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="GherkinBrokenTableInspection" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="GjsLint" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GlassFish" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="Glassfish" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="GrDeprecatedAPIUsage" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GrFieldAlreadyDefined" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GrFinalVariableAccess" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GrMethodMayBeStatic" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GrPackage" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GrReassignedInClosureLocalVar" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GrUnresolvedAccess" enabled="false" level="WEAK WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyAccessToStaticFieldLockedOnInstance" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyAccessibility" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyAnnotationNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*" />
+ <option name="m_minLength" value="8" />
+ <option name="m_maxLength" value="64" />
+ </inspection_tool>
+ <inspection_tool class="GroovyAssignabilityCheck" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyAssignmentCanBeOperatorAssignment" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreLazyOperators" value="true" />
+ <option name="ignoreObscureOperators" value="false" />
+ </inspection_tool>
+ <inspection_tool class="GroovyAssignmentToForLoopParameter" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyAssignmentToMethodParameter" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyBreak" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyBusyWait" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyClassNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*" />
+ <option name="m_minLength" value="8" />
+ <option name="m_maxLength" value="64" />
+ </inspection_tool>
+ <inspection_tool class="GroovyConditional" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyConditionalCanBeConditionalCall" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyConditionalCanBeElvis" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyConditionalWithIdenticalBranches" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyConstantConditional" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyConstantIfStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyConstantNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[A-Z\d]*" />
+ <option name="m_minLength" value="4" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="GroovyConstructorNamedArguments" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyContinue" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyContinueOrBreakFromFinallyBlock" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyDivideByZero" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyDocCheck" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="GroovyDoubleCheckedLocking" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreOnVolatileVariables" value="false" />
+ </inspection_tool>
+ <inspection_tool class="GroovyDoubleNegation" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyDuplicateSwitchBranch" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyEmptyCatchBlock" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyEmptyFinallyBlock" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyEmptyStatementBody" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyEmptySyncBlock" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyEmptyTryBlock" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyEnumerationNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*" />
+ <option name="m_minLength" value="8" />
+ <option name="m_maxLength" value="64" />
+ </inspection_tool>
+ <inspection_tool class="GroovyFallthrough" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyGetterCallCanBePropertyAccess" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyIfStatementWithIdenticalBranches" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyIfStatementWithTooManyBranches" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="3" />
+ </inspection_tool>
+ <inspection_tool class="GroovyImmutableAnnotation" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyInArgumentCheck" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyInfiniteLoopStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyInfiniteRecursion" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyInstanceMethodNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="4" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="GroovyInstanceVariableNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="m_[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="1" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="GroovyInterfaceNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*" />
+ <option name="m_minLength" value="8" />
+ <option name="m_maxLength" value="64" />
+ </inspection_tool>
+ <inspection_tool class="GroovyLabeledStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyListGetCanBeKeyedAccess" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyListSetCanBeKeyedAccess" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyLocalVariableNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="4" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="GroovyLoopStatementThatDoesntLoop" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyMapGetCanBeKeyedAccess" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyMapPutCanBeKeyedAccess" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyMethodParameterCount" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="5" />
+ </inspection_tool>
+ <inspection_tool class="GroovyMethodWithMoreThanThreeNegations" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyMissingReturnStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyMultipleReturnPointsPerMethod" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="1" />
+ </inspection_tool>
+ <inspection_tool class="GroovyNegatedConditional" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyNegatedIf" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyNestedAssignment" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyNestedConditional" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyNestedSwitch" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyNestedSynchronizedStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyNonShortCircuitBoolean" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyNotifyWhileNotSynchronized" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyOctalInteger" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyOverlyComplexArithmeticExpression" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="3" />
+ </inspection_tool>
+ <inspection_tool class="GroovyOverlyComplexBooleanExpression" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="3" />
+ </inspection_tool>
+ <inspection_tool class="GroovyOverlyComplexMethod" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="10" />
+ </inspection_tool>
+ <inspection_tool class="GroovyOverlyLongMethod" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="30" />
+ </inspection_tool>
+ <inspection_tool class="GroovyOverlyNestedMethod" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="5" />
+ </inspection_tool>
+ <inspection_tool class="GroovyParameterNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="4" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="GroovyPointlessArithmetic" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyPointlessBoolean" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyPublicFieldAccessedInSynchronizedContext" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyRangeTypeCheck" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyResultOfAssignmentUsed" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyResultOfIncrementOrDecrementUsed" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyResultOfObjectAllocationIgnored" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyReturnFromClosureCanBeImplicit" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyReturnFromFinallyBlock" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovySetterCallCanBePropertyAccess" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovySillyAssignment" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovySingletonAnnotation" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyStaticMethodNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="4" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="GroovyStaticVariableNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="s_[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="4" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="GroovySwitchStatementWithNoDefault" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovySynchronizationOnNonFinalField" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovySynchronizationOnThis" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovySynchronizationOnVariableInitializedWithLiteral" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovySynchronizedMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovySystemRunFinalizersOnExit" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyThreadStopSuspendResume" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyThrowFromFinallyBlock" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyTrivialConditional" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyTrivialIf" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyUncheckedAssignmentOfMemberOfRawType" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyUnconditionalWait" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyUnnecessaryContinue" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyUnnecessaryReturn" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyUnreachableStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyUnresolvedAccess" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyUnsynchronizedMethodOverridesSynchronizedMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyUntypedAccess" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyUnusedAssignment" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyUnusedCatchParameter" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyUnusedDeclaration" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyUnusedIncOrDec" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyVariableNotAssigned" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GroovyWaitCallNotInLoop" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyWaitWhileNotSynchronized" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GroovyWhileLoopSpinsOnField" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreNonEmtpyLoops" value="false" />
+ </inspection_tool>
+ <inspection_tool class="GspInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GspPropertiesInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="GtkPreferredJComboBoxRenderer" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="GwtClientClassFromNonInheritedModule" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="GwtCssResourceErrors" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="GwtDefaultPackageNotRegistered" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GwtDeprecatedEventListeners" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GwtDeprecatedPropertyKeyJavadocTag" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GwtInconsistentI18nInterface" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="GwtInconsistentSerializableClass" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="GwtJavaScriptReferences" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="GwtMethodWithParametersInConstantsInterface" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="GwtObsoleteTypeArgsJavadocTag" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GwtServiceNotRegistered" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="GwtSetServiceEntryPointCalls" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GwtToHtmlReferences" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="GwtUiFieldAssignment" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="GwtUiFieldErrors" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="GwtUiHandlerErrors" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="GwtUiXmlReferences" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="HardCodedStringLiteral" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreForAssertStatements" value="true" />
+ <option name="ignoreForExceptionConstructors" value="true" />
+ <option name="ignoreForSpecifiedExceptionConstructors" value="" />
+ <option name="ignoreForJUnitAsserts" value="true" />
+ <option name="ignoreForClassReferences" value="true" />
+ <option name="ignoreForPropertyKeyReferences" value="true" />
+ <option name="ignoreForNonAlpha" value="true" />
+ <option name="ignoreAssignedToConstants" value="false" />
+ <option name="ignoreToString" value="false" />
+ <option name="nonNlsCommentPattern" value="NON-NLS" />
+ </inspection_tool>
+ <inspection_tool class="HardcodedFileSeparators" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_recognizeExampleMediaType" value="false" />
+ </inspection_tool>
+ <inspection_tool class="HardcodedLineSeparators" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="HardwiredNamespacePrefix" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="HashCodeUsesNonFinalVariable" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="HibernateConfigDomFacetInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="HibernateConfigDomInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="HibernateMappingDatasourceDomInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="HibernateMappingDomInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="HibernateResource" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="insideTryAllowed" value="false" />
+ </inspection_tool>
+ <inspection_tool class="HtmlDeprecatedTag" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="HtmlExtraClosingTag" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="HtmlFormInputWithoutLabel" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="HtmlNonExistentInternetResource" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="HtmlPresentationalElement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="HtmlTagCanBeJavadocTag" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="HtmlUnknownAnchorTarget" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="myValues">
+ <value>
+ <list size="0" />
+ </value>
+ </option>
+ <option name="myCustomValuesEnabled" value="true" />
+ </inspection_tool>
+ <inspection_tool class="HtmlUnknownTag" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="myValues">
+ <value>
+ <list size="4">
+ <item index="0" class="java.lang.String" itemvalue="nobr" />
+ <item index="1" class="java.lang.String" itemvalue="noembed" />
+ <item index="2" class="java.lang.String" itemvalue="comment" />
+ <item index="3" class="java.lang.String" itemvalue="noscript" />
+ </list>
+ </value>
+ </option>
+ <option name="myCustomValuesEnabled" value="true" />
+ </inspection_tool>
+ <inspection_tool class="HtmlUnknownTarget" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="IOResource" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoredTypesString" value="java.io.ByteArrayOutputStream,java.io.ByteArrayInputStream,java.io.StringBufferInputStream,java.io.CharArrayWriter,java.io.CharArrayReader,java.io.StringWriter,java.io.StringReader" />
+ <option name="insideTryAllowed" value="false" />
+ </inspection_tool>
+ <inspection_tool class="IfCanBeSwitch" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="minimumBranches" value="3" />
+ <option name="suggestIntSwitches" value="false" />
+ <option name="suggestEnumSwitches" value="false" />
+ </inspection_tool>
+ <inspection_tool class="IfMayBeConditional" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="IfStatementWithIdenticalBranches" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="IfStatementWithIdenticalBranchesJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="IfStatementWithTooManyBranches" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="3" />
+ </inspection_tool>
+ <inspection_tool class="IfStatementWithTooManyBranchesJS" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="3" />
+ </inspection_tool>
+ <inspection_tool class="IgnoreResultOfCall" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_reportAllNonLibraryCalls" value="false" />
+ <option name="callCheckString" value="java.io.InputStream,read,java.io.InputStream,skip,java.lang.StringBuffer,toString,java.lang.StringBuilder,toString,java.lang.String,.*,java.math.BigInteger,.*,java.math.BigDecimal,.*,java.net.InetAddress,.*,java.io.File,.*" />
+ </inspection_tool>
+ <inspection_tool class="IgnoredJUnitTest" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ImplicitArrayToString" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ImplicitCallToSuper" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreForObjectSubclasses" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ImplicitNumericConversion" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreWideningConversions" value="false" />
+ <option name="ignoreCharConversions" value="false" />
+ <option name="ignoreConstantConversions" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ImplicitTypeConversion" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="BITS" value="1720" />
+ <option name="FLAG_EXPLICIT_CONVERSION" value="true" />
+ <option name="IGNORE_NODESET_TO_BOOLEAN_VIA_STRING" value="true" />
+ </inspection_tool>
+ <inspection_tool class="ImplicitlyExposedWebServiceMethods" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
+ <inspection_tool class="IncompatibleMask" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="IncompatibleMaskJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="InconsistentLanguageLevel" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InconsistentLineSeparators" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InconsistentResourceBundle" enabled="false" level="INFO" enabled_by_default="false">
+ <option name="REPORT_MISSING_TRANSLATIONS" value="true" />
+ <option name="REPORT_INCONSISTENT_PROPERTIES" value="true" />
+ <option name="REPORT_DUPLICATED_PROPERTIES" value="true" />
+ </inspection_tool>
+ <inspection_tool class="IncorrectOnMessageMethodsInspection" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="IncrementDecrementResultUsedJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="IncrementDecrementUsedAsExpression" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="IndexOfReplaceableByContains" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="IndexZeroUsage" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="InfiniteLoopJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="InfiniteLoopStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="InfiniteRecursion" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="InfiniteRecursionJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="InjectedReferences" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="InjectionNotApplicable" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="InjectionValueTypeInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="InnerClassMayBeStatic" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InnerClassOnInterface" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreInnerInterfaces" value="false" />
+ </inspection_tool>
+ <inspection_tool class="InnerClassReferencedViaSubclass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InnerClassVariableHidesOuterClassVariable" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreInvisibleFields" value="true" />
+ </inspection_tool>
+ <inspection_tool class="InnerHTMLJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InspectionDescriptionNotFoundInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InspectionMappingConsistency" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="InspectionUsingGrayColors" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InstanceGuardedByStatic" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InstanceMethodNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="4" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="InstanceVariableInitialization" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignorePrimitives" value="false" />
+ </inspection_tool>
+ <inspection_tool class="InstanceVariableNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="m_[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="5" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="InstanceVariableOfConcreteClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InstanceVariableUninitializedUse" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignorePrimitives" value="false" />
+ <option name="annotationNamesString" value="" />
+ </inspection_tool>
+ <inspection_tool class="InstanceofCatchParameter" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InstanceofChain" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreInstanceofOnLibraryClasses" value="false" />
+ </inspection_tool>
+ <inspection_tool class="InstanceofIncompatibleInterface" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InstanceofInterfaces" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InstanceofThis" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InstantiatingObjectToGetClassObject" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="InstantiationOfUtilityClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="IntLiteralMayBeLongLiteral" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="IntegerDivisionInFloatingPointContext" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="IntegerMultiplicationImplicitCastToLong" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreNonOverflowingCompileTimeConstants" value="true" />
+ </inspection_tool>
+ <inspection_tool class="IntentionDescriptionNotFoundInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InterceptionAnnotationWithoutRuntimeRetention" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InterfaceNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*" />
+ <option name="m_minLength" value="8" />
+ <option name="m_maxLength" value="64" />
+ </inspection_tool>
+ <inspection_tool class="InterfaceNeverImplemented" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreInterfacesThatOnlyDeclareConstants" value="false" />
+ </inspection_tool>
+ <inspection_tool class="InterfaceWithOnlyOneDirectInheritor" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InvalidImplementedBy" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InvalidProvidedBy" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InvalidRequestParameters" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="IteratorHasNextCallsIteratorNext" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="IteratorNextDoesNotThrowNoSuchElementException" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JBoss" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="JDBCExecuteWithNonConstantString" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JDBCPrepareStatementWithNonConstantString" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JDBCResource" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="insideTryAllowed" value="false" />
+ </inspection_tool>
+ <inspection_tool class="JNDIResource" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="insideTryAllowed" value="false" />
+ </inspection_tool>
+ <inspection_tool class="JSAccessibilityCheck" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSBitwiseOperatorUsage" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSCheckFunctionSignatures" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSClosureCompilerSyntax" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSCommentMatchesSignature" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSComparisonWithNaN" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSConsecutiveCommasInArrayLiteral" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JSConstructorReturnsPrimitive" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSDeclarationsAtScopeStart" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSDeprecatedSymbols" enabled="true" level="INFO" enabled_by_default="true" />
+ <inspection_tool class="JSDuplicatedDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JSFieldCanBeLocal" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSFieldCanBeLocalInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSHint" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="JSImplicitlyInternalDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JSJQueryEfficiency" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSLastCommaInArrayLiteral" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JSLastCommaInObjectLiteral" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="JSLint" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="JSLintValidation" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="JSLowercasedConstructorCall" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JSMethodCanBeStatic" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSMismatchedCollectionQueryUpdate" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="queries" value="trace,write" />
+ <option name="updates" value="pop,push,shift,splice,unshift" />
+ </inspection_tool>
+ <inspection_tool class="JSMismatchedCollectionQueryUpdateInspection" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="queries" value="trace,write" />
+ <option name="updates" value="pop,push,shift,splice,unshift" />
+ </inspection_tool>
+ <inspection_tool class="JSPotentiallyInvalidConstructorCall" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSPotentiallyInvalidConstructorUsage" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="myConsiderUppercaseFunctionsToBeConstructors" value="true" />
+ </inspection_tool>
+ <inspection_tool class="JSPotentiallyInvalidConstructorUsages" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="myConsiderUppercaseFunctionsToBeConstructors" value="true" />
+ </inspection_tool>
+ <inspection_tool class="JSPotentiallyInvalidTargetOfIndexedPropertyAccess" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSPotentiallyInvalidUsageOfThis" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSPrimitiveTypeWrapperUsage" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSReferencingMutableVariableFromClosure" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSSuspiciousNameCombination" enabled="false" level="WARNING" enabled_by_default="false">
+ <group names="x,width,left,right" />
+ <group names="y,height,top,bottom" />
+ <exclude classes="Math" />
+ </inspection_tool>
+ <inspection_tool class="JSSuspiciousNameCombinationInspection" enabled="true" level="INFO" enabled_by_default="true">
+ <group names="x,width,left,right" />
+ <group names="y,height,top,bottom" />
+ <exclude classes="Math" />
+ </inspection_tool>
+ <inspection_tool class="JSUndeclaredVariable" enabled="true" level="INFO" enabled_by_default="true" />
+ <inspection_tool class="JSUndefinedPropertyAssignment" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSUnfilteredForInLoop" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSUnnecessarySemicolon" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JSUnresolvedFunction" enabled="true" level="INFO" enabled_by_default="true" />
+ <inspection_tool class="JSUnresolvedLibraryURL" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSUnresolvedVariable" enabled="true" level="INFO" enabled_by_default="true" />
+ <inspection_tool class="JSUntypedDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JSUnusedAssignment" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSUnusedGlobalSymbols" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JSUnusedLocalSymbols" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JSValidateJSDoc" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JSValidateJSON" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JSValidateTypes" enabled="true" level="INFO" enabled_by_default="true" />
+ <inspection_tool class="JUnit3StyleTestMethodInJUnit4Class" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JUnit4AnnotatedMethodInJUnit3TestCase" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JUnitAbstractTestClassNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*TestCase" />
+ <option name="m_minLength" value="12" />
+ <option name="m_maxLength" value="64" />
+ </inspection_tool>
+ <inspection_tool class="JUnitDatapoint" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JUnitRule" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JUnitTestClassNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*Test" />
+ <option name="m_minLength" value="8" />
+ <option name="m_maxLength" value="64" />
+ </inspection_tool>
+ <inspection_tool class="JUnitTestNG" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JavaDoc" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="TOP_LEVEL_CLASS_OPTIONS">
+ <value>
+ <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+ <option name="REQUIRED_TAGS" value="" />
+ </value>
+ </option>
+ <option name="INNER_CLASS_OPTIONS">
+ <value>
+ <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+ <option name="REQUIRED_TAGS" value="" />
+ </value>
+ </option>
+ <option name="METHOD_OPTIONS">
+ <value>
+ <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+ <option name="REQUIRED_TAGS" value="" />
+ </value>
+ </option>
+ <option name="FIELD_OPTIONS">
+ <value>
+ <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+ <option name="REQUIRED_TAGS" value="" />
+ </value>
+ </option>
+ <option name="IGNORE_DEPRECATED" value="false" />
+ <option name="IGNORE_JAVADOC_PERIOD" value="true" />
+ <option name="IGNORE_DUPLICATED_THROWS" value="false" />
+ <option name="IGNORE_POINT_TO_ITSELF" value="false" />
+ <option name="myAdditionalJavadocTags" value="" />
+ </inspection_tool>
+ <inspection_tool class="JavaFxDefaultTag" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JavaFxUnresolvedFxIdReference" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JavaFxUnresolvedStyleClassReference" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JavaFxUnusedImports" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JavaLangImport" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JavaLangReflect" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JavaStylePropertiesInvocation" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JavacQuirks" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JavadocReference" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JavaeeApplicationDomInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JdkProxiedBeanTypeInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JpaAttributeMemberSignatureInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JpaAttributeTypeInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JpaConfigDomFacetInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JpaDataSourceORMDomInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JpaDataSourceORMInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JpaDomInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JpaEntityListenerInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JpaEntityListenerWarningsInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JpaMissingIdInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="JpaModelReferenceInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JpaORMDomInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JpaObjectClassSignatureInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JpaQlInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JpaQueryApiInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JpdlModelInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="JsfJamExtendsClassInconsistencyInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JsfManagedBeansInconsistencyInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JspAbsolutePathInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JspDirectiveInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JspPropertiesInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JspUnescapedEl" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="KeySetIterationMayUseEntrySet" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="LabeledStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="LabeledStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="LanguageMismatch" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="CHECK_NON_ANNOTATED_REFERENCES" value="true" />
+ </inspection_tool>
+ <inspection_tool class="LawOfDemeter" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreLibraryCalls" value="true" />
+ </inspection_tool>
+ <inspection_tool class="LengthOneStringInIndexOf" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="LengthOneStringsInConcatenation" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="LessResolvedByNameOnly" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
+ <inspection_tool class="LessUnresolvedImport" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="LessUnresolvedMixin" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="LessUnresolvedVariable" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="LimitedScopeInnerClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ListIndexOfReplaceableByContains" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ListenerMayUseAdapter" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="checkForEmptyMethods" value="true" />
+ </inspection_tool>
+ <inspection_tool class="LiteralAsArgToStringEquals" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="LoadLibraryWithNonConstantString" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="LocalCanBeFinal" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="REPORT_VARIABLES" value="true" />
+ <option name="REPORT_PARAMETERS" value="true" />
+ <option name="REPORT_CATCH_PARAMETERS" value="true" />
+ <option name="REPORT_FOREACH_PARAMETERS" value="true" />
+ </inspection_tool>
+ <inspection_tool class="LocalVariableHidingMemberVariable" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreInvisibleFields" value="true" />
+ <option name="m_ignoreStaticMethods" value="true" />
+ </inspection_tool>
+ <inspection_tool class="LocalVariableNameWithMistakes" enabled="false" level="INFO" enabled_by_default="false" />
+ <inspection_tool class="LocalVariableNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreForLoopParameters" value="false" />
+ <option name="m_ignoreCatchParameters" value="false" />
+ <option name="m_regex" value="[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="1" />
+ <option name="m_maxLength" value="20" />
+ </inspection_tool>
+ <inspection_tool class="LocalVariableNamingConventionJS" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[a-z][A-Za-z]*" />
+ <option name="m_minLength" value="1" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="LocalVariableOfConcreteClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="LogStatementGuardedByLogCondition" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="LoggerInitializedWithForeignClass" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="loggerClassName" value="org.apache.log4j.Logger" />
+ <option name="loggerFactoryMethodName" value="getLogger" />
+ </inspection_tool>
+ <inspection_tool class="LoggingConditionDisagreesWithLogStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="LongLiteralsEndingWithLowercaseL" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="LoopConditionNotUpdatedInsideLoop" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreIterators" value="false" />
+ </inspection_tool>
+ <inspection_tool class="LoopStatementThatDoesntLoopJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="LoopStatementsThatDontLoop" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="LoopWithImplicitTerminationCondition" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="LossyEncoding" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MVCPathVariableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MagicCharacter" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MagicConstant" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MagicNumber" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MagicNumberJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MakoArgumentListInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MalformedFormatString" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MalformedRegex" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MalformedXPath" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ManagedBeanClassInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="ManualArrayCopy" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ManualArrayToCollectionCopy" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MapReplaceableByEnumMap" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MarkerInterface" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MathRandomCastToInt" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MavenDuplicateDependenciesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MavenModelInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="MethodCallInLoopCondition" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MethodCanBeVariableArityMethod" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreByteAndShortArrayParameters" value="true" />
+ <option name="ignoreOverridingMethods" value="false" />
+ </inspection_tool>
+ <inspection_tool class="MethodCount" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="20" />
+ <option name="ignoreGettersAndSetters" value="false" />
+ <option name="ignoreOverridingMethods" value="false" />
+ </inspection_tool>
+ <inspection_tool class="MethodCoupling" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_includeJavaClasses" value="false" />
+ <option name="m_includeLibraryClasses" value="false" />
+ <option name="m_limit" value="10" />
+ </inspection_tool>
+ <inspection_tool class="MethodMayBeStatic" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_onlyPrivateOrFinal" value="false" />
+ <option name="m_ignoreEmptyMethods" value="true" />
+ </inspection_tool>
+ <inspection_tool class="MethodMayBeSynchronized" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MethodNameSameAsClassName" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MethodNameSameAsParentName" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MethodNameWithMistakes" enabled="false" level="INFO" enabled_by_default="false" />
+ <inspection_tool class="MethodNamesDifferOnlyByCase" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MethodOnlyUsedFromInnerClass" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreMethodsAccessedFromAnonymousClass" value="false" />
+ <option name="ignoreStaticMethodsFromNonStaticInnerClass" value="false" />
+ <option name="onlyReportStaticMethods" value="false" />
+ </inspection_tool>
+ <inspection_tool class="MethodOverloadsParentMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MethodOverridesPackageLocalMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MethodOverridesPrivateMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MethodOverridesStaticMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MethodReturnAlwaysConstant" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MethodReturnOfConcreteClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MethodWithMultipleLoops" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MimeType" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="MinMaxValuesInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MismatchedArrayReadWrite" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MismatchedCollectionQueryUpdate" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="queryNames">
+ <value />
+ </option>
+ <option name="updateNames">
+ <value />
+ </option>
+ </inspection_tool>
+ <inspection_tool class="MismatchedStringBuilderQueryUpdate" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MisorderedAssertEqualsArgumentsTestNG" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MisorderedAssertEqualsParameters" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MissedExecutable" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MissingAspectjAutoproxyInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MissingDeprecatedAnnotation" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MissingFinalNewline" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="MissingMnemonic" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MissingOverrideAnnotation" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreObjectMethods" value="true" />
+ <option name="ignoreAnonymousClassMethods" value="false" />
+ </inspection_tool>
+ <inspection_tool class="MissingPackageInfo" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MissortedModifiers" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_requireAnnotationsFirst" value="true" />
+ </inspection_tool>
+ <inspection_tool class="MisspelledCompareTo" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MisspelledEquals" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MisspelledHashcode" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MisspelledHeader" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MisspelledSetUp" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MisspelledTearDown" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MisspelledToString" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ModuleWithTooFewClasses" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="limit" value="10" />
+ </inspection_tool>
+ <inspection_tool class="ModuleWithTooManyClasses" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="limit" value="100" />
+ </inspection_tool>
+ <inspection_tool class="MultipleBindingAnnotations" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MultipleDeclaration" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreForLoopDeclarations" value="true" />
+ </inspection_tool>
+ <inspection_tool class="MultipleExceptionsDeclaredOnTestMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MultipleInjectedConstructorsForClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MultipleMethodDesignatorsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MultipleRepositoryUrls" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MultipleReturnPointsPerMethod" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreGuardClauses" value="false" />
+ <option name="ignoreEqualsMethod" value="false" />
+ <option name="m_limit" value="1" />
+ </inspection_tool>
+ <inspection_tool class="MultipleTopLevelClassesInFile" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MultipleTypedDeclaration" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MultiplyOrDivideByPowerOfTwo" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="checkDivision" value="false" />
+ </inspection_tool>
+ <inspection_tool class="NakedNotify" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NativeMethods" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NegatedConditional" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreNegatedNullComparison" value="true" />
+ </inspection_tool>
+ <inspection_tool class="NegatedConditionalExpression" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NegatedConditionalExpressionJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NegatedEqualityExpression" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NegatedIfElse" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreNegatedNullComparison" value="true" />
+ <option name="m_ignoreNegatedZeroComparison" value="false" />
+ </inspection_tool>
+ <inspection_tool class="NegatedIfStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NegativelyNamedBooleanVariable" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NestedAssignment" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NestedAssignmentJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NestedConditionalExpression" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NestedConditionalExpressionJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NestedFunctionCallJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NestedFunctionJS" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_includeAnonymousFunctions" value="false" />
+ </inspection_tool>
+ <inspection_tool class="NestedMethodCall" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreFieldInitializations" value="true" />
+ </inspection_tool>
+ <inspection_tool class="NestedSwitchStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NestedSwitchStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NestedSynchronizedStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NestedTryStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NestingDepth" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="5" />
+ </inspection_tool>
+ <inspection_tool class="NestingDepthJS" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="5" />
+ </inspection_tool>
+ <inspection_tool class="NewExceptionWithoutArguments" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NewInstanceOfSingleton" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NewStringBufferWithCharArgument" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NoButtonGroup" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NoExplicitFinalizeCalls" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NoLabelFor" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NoScrollPane" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NonAtomicOperationOnVolatileField" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonBlockStatementBodyJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonBooleanMethodNameMayNotStartWithQuestion" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="questionString" value="is,can,has,should,could,will,shall,check,contains,equals,startsWith,endsWith" />
+ <option name="ignoreBooleanMethods" value="false" />
+ <option name="onlyWarnOnBaseMethods" value="true" />
+ </inspection_tool>
+ <inspection_tool class="NonCommentSourceStatements" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="30" />
+ </inspection_tool>
+ <inspection_tool class="NonExceptionNameEndsWithException" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonFinalClone" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonFinalFieldInEnum" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonFinalFieldInImmutable" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonFinalFieldOfException" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonFinalGuard" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonFinalStaticVariableUsedInClassInitialization" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonFinalUtilityClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonJREEmulationClassesInClientCode" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="NonJaxWsWebServices" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonProtectedConstructorInAbstractClass" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreNonPublicClasses" value="false" />
+ </inspection_tool>
+ <inspection_tool class="NonReproducibleMathCall" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonSerializableFieldInSerializableClass" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignorableAnnotations">
+ <value />
+ </option>
+ <option name="ignoreAnonymousInnerClasses" value="false" />
+ <option name="superClassString" value="java.awt.Component" />
+ </inspection_tool>
+ <inspection_tool class="NonSerializableObjectBoundToHttpSession" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonSerializableObjectPassedToObjectStream" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonSerializableServiceParameters" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="NonSerializableWithSerialVersionUIDField" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonSerializableWithSerializationMethods" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonShortCircuitBoolean" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonShortCircuitBooleanExpressionJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonStaticFinalLogger" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="loggerClassName" value="java.util.logging.Logger" />
+ </inspection_tool>
+ <inspection_tool class="NonStaticInnerClassInSecureContext" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonSynchronizedMethodOverridesSynchronizedMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NonThreadSafeLazyInitialization" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NoopMethodInAbstractClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NotifyCalledOnCondition" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NotifyNotInSynchronizedContext" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NotifyWithoutCorrespondingWait" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NullArgumentToVariableArgMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NullThrown" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NullableProblems" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="REPORT_NULLABLE_METHOD_OVERRIDES_NOTNULL" value="true" />
+ <option name="REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL" value="true" />
+ <option name="REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE" value="true" />
+ <option name="REPORT_NOT_ANNOTATED_PARAMETER_OVERRIDES_NOTNULL" value="true" />
+ <option name="REPORT_NOT_ANNOTATED_GETTER" value="true" />
+ <option name="REPORT_NOT_ANNOTATED_SETTER_PARAMETER" value="true" />
+ <option name="REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS" value="true" />
+ <option name="REPORT_NULLS_PASSED_TO_NON_ANNOTATED_METHOD" value="true" />
+ </inspection_tool>
+ <inspection_tool class="NumberEquality" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NumericOverflow" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NumericToString" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ObjectAllocationIgnoredJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ObjectAllocationInLoop" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ObjectEquality" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreEnums" value="true" />
+ <option name="m_ignoreClassObjects" value="false" />
+ <option name="m_ignorePrivateConstructors" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ObjectEqualsNull" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ObjectNotify" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ObjectToString" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ObsoleteCollection" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreRequiredObsoleteCollectionTypes" value="false" />
+ </inspection_tool>
+ <inspection_tool class="OctalAndDecimalIntegersMixed" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="OctalIntegerJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="OctalLiteral" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="OnDemandImport" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="OneButtonGroup" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="OneWayWebMethod" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="OrredNotEqualExpression" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="OverloadedMethodsWithSameNumberOfParameters" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreInconvertibleTypes" value="true" />
+ </inspection_tool>
+ <inspection_tool class="OverloadedVarargsMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="OverlyComplexArithmeticExpression" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="6" />
+ </inspection_tool>
+ <inspection_tool class="OverlyComplexArithmeticExpressionJS" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="6" />
+ </inspection_tool>
+ <inspection_tool class="OverlyComplexBooleanExpression" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="3" />
+ <option name="m_ignorePureConjunctionsDisjunctions" value="true" />
+ </inspection_tool>
+ <inspection_tool class="OverlyComplexBooleanExpressionJS" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="3" />
+ </inspection_tool>
+ <inspection_tool class="OverlyLargePrimitiveArrayInitializer" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="64" />
+ </inspection_tool>
+ <inspection_tool class="OverlyStrongTypeCast" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreInMatchingInstanceof" value="false" />
+ </inspection_tool>
+ <inspection_tool class="OverridableMethodCallDuringObjectConstruction" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="OverriddenMethodCallDuringObjectConstruction" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PackageDotHtmlMayBePackageInfo" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PackageInMultipleModules" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PackageInfoWithoutPackage" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PackageNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[a-z]*" />
+ <option name="m_minLength" value="3" />
+ <option name="m_maxLength" value="16" />
+ </inspection_tool>
+ <inspection_tool class="PackageVisibleField" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PackageVisibleInnerClass" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreEnums" value="false" />
+ <option name="ignoreInterfaces" value="false" />
+ </inspection_tool>
+ <inspection_tool class="PackageWithTooFewClasses" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="limit" value="3" />
+ </inspection_tool>
+ <inspection_tool class="PackageWithTooManyClasses" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="limit" value="10" />
+ </inspection_tool>
+ <inspection_tool class="PageflowModelInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="PagesFileModelInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="PagesModelInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="ParameterCanBeLocal" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ParameterHidingMemberVariable" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreInvisibleFields" value="true" />
+ <option name="m_ignoreStaticMethodParametersHidingInstanceFields" value="false" />
+ <option name="m_ignoreForConstructors" value="false" />
+ <option name="m_ignoreForPropertySetters" value="false" />
+ <option name="m_ignoreForAbstractMethods" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ParameterNameDiffersFromOverriddenParameter" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreSingleCharacterNames" value="false" />
+ <option name="m_ignoreOverridesOfLibraryMethods" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ParameterNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="1" />
+ <option name="m_maxLength" value="20" />
+ </inspection_tool>
+ <inspection_tool class="ParameterNamingConventionJS" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[a-z][A-Za-z]*" />
+ <option name="m_minLength" value="1" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="ParameterOfConcreteClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ParameterizedParametersStaticCollection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ParametersPerConstructor" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ParametersPerFunctionJS" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="5" />
+ </inspection_tool>
+ <inspection_tool class="ParametersPerMethod" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="5" />
+ </inspection_tool>
+ <inspection_tool class="PathAnnotation" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PatternNotApplicable" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="PatternOverriddenByNonAnnotatedMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PatternValidation" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="CHECK_NON_CONSTANT_VALUES" value="true" />
+ </inspection_tool>
+ <inspection_tool class="PhingDomInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="PhpAssignmentInConditionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PhpDeprecationInspection" enabled="true" level="INFO" enabled_by_default="true" />
+ <inspection_tool class="PhpDocMissingReturnTagInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
+ <inspection_tool class="PhpDocSignatureInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
+ <inspection_tool class="PhpDynamicAsStaticMethodCallInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PhpIllegalArrayKeyTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PhpIncludeInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PhpInconsistentReturnPointsInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="PhpMissingDocCommentInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PhpParamsInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PhpSillyAssignmentInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PhpUndefinedClassConstantInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PhpUndefinedClassInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PhpUndefinedConstantInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PhpUndefinedFieldInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PhpUndefinedFunctionInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PhpUndefinedMethodInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PhpUndefinedNamespaceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PhpUndefinedVariableInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PhpUnimplementedMethodsInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="PhpUnreachableStatementInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PhpUnusedLocalVariableInspection" enabled="true" level="INFO" enabled_by_default="true">
+ <option name="DONT_REPORT_FOREACH_VALUE" value="false" />
+ </inspection_tool>
+ <inspection_tool class="PhpUnusedParameterInspection" enabled="true" level="INFO" enabled_by_default="true" />
+ <inspection_tool class="PhpUnusedPrivateFieldInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PhpWrongCatchClausesOrderInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PhpWrongForeachArgumentTypeInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PhpWrongStringConcatenationInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PlaceholderCountMatchesArgumentCount" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PlatformDetectionJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PluginXmlValidity" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="PointcutMethodStyleInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PointlessArithmeticExpression" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreExpressionsContainingConstants" value="false" />
+ </inspection_tool>
+ <inspection_tool class="PointlessArithmeticExpressionJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PointlessBinding" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PointlessBitwiseExpression" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreExpressionsContainingConstants" value="false" />
+ </inspection_tool>
+ <inspection_tool class="PointlessBitwiseExpressionJS" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreExpressionsContainingConstants" value="false" />
+ </inspection_tool>
+ <inspection_tool class="PointlessBooleanExpression" enabled="true" level="WEAK WARNING" enabled_by_default="true">
+ <option name="m_ignoreExpressionsContainingConstants" value="false" />
+ </inspection_tool>
+ <inspection_tool class="PointlessBooleanExpressionJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PointlessIndexOfComparison" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PointlessNullCheck" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PrimitiveArrayArgumentToVariableArgMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PrivateMemberAccessBetweenOuterAndInnerClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ProblematicVarargsMethodOverride" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ProblematicWhitespace" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ProtectedField" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ProtectedInnerClass" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreEnums" value="false" />
+ <option name="ignoreInterfaces" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ProtectedMemberInFinalClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PublicConstructor" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PublicConstructorInNonPublicClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PublicField" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreEnums" value="false" />
+ <option name="ignorableAnnotations">
+ <value />
+ </option>
+ </inspection_tool>
+ <inspection_tool class="PublicFieldAccessedInSynchronizedContext" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PublicInnerClass" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreEnums" value="false" />
+ <option name="ignoreInterfaces" value="false" />
+ </inspection_tool>
+ <inspection_tool class="PublicMethodNotExposedInInterface" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignorableAnnotations">
+ <value />
+ </option>
+ <option name="onlyWarnIfContainingClassImplementsAnInterface" value="false" />
+ </inspection_tool>
+ <inspection_tool class="PublicMethodWithoutLogging" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="loggerClassName" value="java.util.logging.Logger" />
+ </inspection_tool>
+ <inspection_tool class="PublicStaticArrayField" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PublicStaticCollectionField" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyAbstractClassInspection" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyArgumentEqualDefaultInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyArgumentListInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyAttributeOutsideInitInspection" enabled="false" level="WEAK WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyAugmentAssignmentInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyBroadExceptionInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyByteLiteralInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyCallByClassInspection" enabled="true" level="INFO" enabled_by_default="true" />
+ <inspection_tool class="PyCallingNonCallableInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyChainedComparisonsInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyClassHasNoInitInspection" enabled="false" level="WEAK WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyClassicStyleClassInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyComparisonWithNoneInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyCompatibilityInspection" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ourVersions">
+ <value>
+ <list size="0" />
+ </value>
+ </option>
+ </inspection_tool>
+ <inspection_tool class="PyDecoratorInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyDefaultArgumentInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyDeprecatedModulesInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyDeprecationInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyDictCreationInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyDictDuplicateKeysInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyDocstringInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyDocstringTypesInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyExceptClausesOrderInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyExceptionInheritInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyFromFutureImportInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyGlobalUndefinedInspection" enabled="false" level="WEAK WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyInconsistentIndentationInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyInitNewSignatureInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyInterpreterInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyListCreationInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyMandatoryEncodingInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyMethodFirstArgAssignmentInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyMethodMayBeStaticInspection" enabled="false" level="WEAK WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyMethodOverridingInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyMethodParametersInspection" enabled="true" level="INFO" enabled_by_default="true" />
+ <inspection_tool class="PyMissingConstructorInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyNestedDecoratorsInspection" enabled="true" level="INFO" enabled_by_default="true" />
+ <inspection_tool class="PyNonAsciiCharInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyNoneFunctionAssignmentInspection" enabled="false" level="WEAK WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyOldStyleClassesInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyPackageRequirementsInspection" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoredPackages">
+ <value>
+ <list size="0" />
+ </value>
+ </option>
+ </inspection_tool>
+ <inspection_tool class="PyPep8Inspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyPep8NamingInspection" enabled="false" level="WEAK WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyPropertyAccessInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyPropertyDefinitionInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyProtectedMemberInspection" enabled="false" level="WEAK WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyRaisingNewStyleClassInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyRedeclarationInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyRedundantParenthesesInspection" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="myIgnorePercOperator" value="false" />
+ <option name="myIgnoreTupleInReturn" value="false" />
+ </inspection_tool>
+ <inspection_tool class="PyReturnFromInitInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PySetFunctionToLiteralInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyShadowingBuiltinsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyShadowingNamesInspection" enabled="false" level="WEAK WARNING" enabled_by_default="true" />
+ <inspection_tool class="PySimplifyBooleanCheckInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PySingleQuotedDocstringInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyStatementEffectInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyStringExceptionInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyStringFormatInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PySuperArgumentsInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyTrailingSemicolonInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyTupleAssignmentBalanceInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyTupleItemAssignmentInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyTypeCheckerInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyUnboundLocalVariableInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyUnnecessaryBackslashInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PyUnreachableCodeInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PyUnresolvedReferencesInspection" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoredIdentifiers">
+ <value>
+ <list size="0" />
+ </value>
+ </option>
+ </inspection_tool>
+ <inspection_tool class="PyUnusedLocalInspection" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreTupleUnpacking" value="true" />
+ <option name="ignoreLambdaParameters" value="true" />
+ <option name="ignoreLoopIterationVariables" value="true" />
+ </inspection_tool>
+ <inspection_tool class="PyUnusedLocalVariableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="Query_bound_parameters" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="Query_index_required" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="Query_restricted" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="QuestionableName" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="nameString" value="aa,abc,bad,bar,bar2,baz,baz1,baz2,baz3,bb,blah,bogus,bool,cc,dd,defau1t,dummy,dummy2,ee,fa1se,ff,foo,foo1,foo2,foo3,foobar,four,fred,fred1,fred2,gg,hh,hello,hello1,hello2,hello3,ii,nu11,one,silly,silly2,string,two,that,then,three,whi1e,var" />
+ </inspection_tool>
+ <inspection_tool class="QuirksModeInspectionTool" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="IE50" value="false" />
+ <option name="IE55" value="false" />
+ <option name="IE6" value="true" />
+ <option name="IE7" value="true" />
+ <option name="IE_MAC" value="false" />
+ <option name="MOZILLA" value="true" />
+ <option name="OPERA7" value="false" />
+ <option name="OPERA8" value="false" />
+ <option name="OPERA85" value="true" />
+ <option name="OPERA9" value="true" />
+ <option name="SAFARI" value="true" />
+ </inspection_tool>
+ <inspection_tool class="RSReferenceInspection" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RandomDoubleForRandomInteger" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="RawUseOfParameterizedType" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreTypeCasts" value="true" />
+ </inspection_tool>
+ <inspection_tool class="ReadObjectAndWriteObjectPrivate" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ReadObjectInitialization" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ReadResolveAndWriteReplaceProtected" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="RecordStoreResource" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="RedundantArrayCreation" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RedundantCast" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RedundantFieldInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RedundantImplements" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreSerializable" value="false" />
+ <option name="ignoreCloneable" value="false" />
+ </inspection_tool>
+ <inspection_tool class="RedundantImport" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RedundantMethodOverride" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="RedundantScopeBinding" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="RedundantStringFormatCall" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RedundantSuppression" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="RedundantThrows" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RedundantThrowsDeclaration" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="RedundantToBinding" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="RedundantToProviderBinding" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="RedundantTypeArguments" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RedundantTypeConversion" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="CHECK_ANY" value="true" />
+ </inspection_tool>
+ <inspection_tool class="ReferencesToClassesFromDefaultPackagesInJSPFile" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="ReflectionForUnavailableAnnotation" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RefusedBequest" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreEmptySuperMethods" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ReplaceAllDot" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ReplaceAssignmentWithOperatorAssignment" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreLazyOperators" value="true" />
+ <option name="ignoreObscureOperators" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ReplaceAssignmentWithOperatorAssignmentJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="RequiredArtifactTypeInspection" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="RequiredAttributes" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="myAdditionalRequiredHtmlAttributes" value="" />
+ </inspection_tool>
+ <inspection_tool class="RequiredBeanTypeInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="ReservedWordUsedAsNameJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RestRoleInspection" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoredRoles">
+ <value>
+ <list size="0" />
+ </value>
+ </option>
+ </inspection_tool>
+ <inspection_tool class="RestWrongDefaultValueInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="Restricted_Python_calls" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ResultOfObjectAllocationIgnored" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ResultSetIndexZero" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ReturnFromFinallyBlock" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ReturnFromFinallyBlockJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ReturnNull" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_reportObjectMethods" value="true" />
+ <option name="m_reportArrayMethods" value="true" />
+ <option name="m_reportCollectionMethods" value="true" />
+ <option name="m_ignorePrivateMethods" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ReturnOfCollectionField" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignorePrivateMethods" value="true" />
+ </inspection_tool>
+ <inspection_tool class="ReturnOfDateField" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ReturnThis" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ReuseOfLocalVariable" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ReuseOfLocalVariableJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="RuntimeExec" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="RuntimeExecWithNonConstantString" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SSBasedInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SafeLock" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SafeVarargsDetector" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SamePackageImport" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SameParameterValue" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SameReturnValue" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SassScssResolvedByNameOnly" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
+ <inspection_tool class="SassScssUnresolvedFunction" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SassScssUnresolvedMixin" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SassScssUnresolvedPlaceholderSelector" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SassScssUnresolvedVariable" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SassUnresolvedFunction" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SassUnresolvedImport" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SassUnresolvedMixin" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SassUnresolvedPlaceholderSelector" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SassUnresolvedVariable" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SeamAnnotationIncorrectSignatureInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SeamAnnotationsInconsistencyInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SeamBijectionIllegalScopeParameterInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SeamBijectionTypeMismatchInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SeamBijectionUndefinedContextVariableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SeamDomModelInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SeamDuplicateComponentsInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SeamIllegalComponentScopeInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SeamJamComponentInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SecondUnsafeCall" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SelfIncludingJspFiles" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="Semicolon_end_problem" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SerialPersistentFieldsWithWrongSignature" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SerialVersionUIDNotStaticFinal" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SerializableClassInSecureContext" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SerializableHasSerialVersionUIDField" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreAnonymousInnerClasses" value="false" />
+ <option name="superClassString" value="java.awt.Component" />
+ </inspection_tool>
+ <inspection_tool class="SerializableHasSerializationMethods" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreAnonymousInnerClasses" value="false" />
+ <option name="superClassString" value="java.awt.Component" />
+ </inspection_tool>
+ <inspection_tool class="SerializableInnerClassHasSerialVersionUIDField" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreAnonymousInnerClasses" value="false" />
+ <option name="superClassString" value="java.awt.Component" />
+ </inspection_tool>
+ <inspection_tool class="SerializableInnerClassWithNonSerializableOuterClass" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreAnonymousInnerClasses" value="false" />
+ <option name="superClassString" value="java.awt.Component" />
+ </inspection_tool>
+ <inspection_tool class="SerializableWithUnconstructableAncestor" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ServerEndpointInconsistencyInspection" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="ServletWithoutMappingInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SessionScopedInjectsRequestScoped" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SetReplaceableByEnumSet" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SetupCallsSuperSetup" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SetupIsPublicVoidNoArg" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ShiftOutOfRange" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ShiftOutOfRangeJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SignalWithoutCorrespondingAwait" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SillyAssignment" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SillyAssignmentJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SimpleDateFormatWithoutLocale" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SimplifiableAnnotation" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SimplifiableConditionalExpression" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SimplifiableEqualsExpression" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SimplifiableIfStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SimplifiableJUnitAssertion" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="Since15" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SingleCharacterStartsWith" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SingleClassImport" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="Singleton" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SingletonInjectsScoped" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SizeReplaceableByIsEmpty" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SleepWhileHoldingLock" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SocketResource" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="insideTryAllowed" value="false" />
+ </inspection_tool>
+ <inspection_tool class="SpellCheckingInspection" enabled="true" level="TYPO" enabled_by_default="true">
+ <option name="processCode" value="false" />
+ <option name="processLiterals" value="false" />
+ <option name="processComments" value="true" />
+ </inspection_tool>
+ <inspection_tool class="SpringAopErrorsInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringAopWarningsInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SpringBeanAutowiringInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringBeanConstructorArgInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringBeanDepedencyCheckInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringBeanInstantiationInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringBeanLookupMethodInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringBeanNameConventionInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SpringContextConfigurationInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringFacetInspection" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="checkTestFiles" value="false" />
+ </inspection_tool>
+ <inspection_tool class="SpringFactoryMethodInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringIncorrectResourceTypeInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringInjectionValueConsistencyInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringInjectionValueStyleInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SpringIntegrationModelErrorInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SpringIntegrationModelInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SpringJavaAutowiringInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringJavaConfigExternalBeansErrorInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SpringJavaConfigInconsistencyInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringMVCViewInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringMessageDispatcherWebXmlInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringModelInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringOsgiElementsInconsistencyInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SpringOsgiListenerInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SpringOsgiServiceCommonInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SpringPlaceholdersInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SpringPublicFactoryMethodInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SpringReplacedMethodsInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringRequiredAnnotationInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringRequiredPropertyInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringScopesInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringSecurityElementsInconsistencyInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SpringSecurityFiltersConfiguredInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SpringTransactionalComponentInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SpringWebServiceAnnotationsInconsistencyInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SpringWebServicesConfigurationsInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SqlAddNotNullColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SqlAmbiguousColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SqlAutoIncrementDuplicateInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SqlCheckUsingColumnsInspection" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SqlConstantConditionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SqlDeliverTableNameInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SqlDeprecateTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SqlDerivedTableAliasInspection" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SqlDialectInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SqlDropIndexedColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SqlIdentifierInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SqlInsertValuesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SqlPostgresqlSelectFromProcedureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SqlResolveInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SqlShouldBeInGroupByInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SqlTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StandardVariableNames" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StatementsPerFunctionJS" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="30" />
+ </inspection_tool>
+ <inspection_tool class="StaticCallOnSubclass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StaticCollection" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreWeakCollections" value="false" />
+ </inspection_tool>
+ <inspection_tool class="StaticFieldReferenceOnSubclass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StaticGuardedByInstance" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StaticImport" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StaticInheritance" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StaticMethodNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="4" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="StaticMethodOnlyUsedInOneClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StaticNonFinalField" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StaticSuite" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StaticVariableInitialization" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignorePrimitives" value="false" />
+ </inspection_tool>
+ <inspection_tool class="StaticVariableNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="checkMutableFinals" value="false" />
+ <option name="m_regex" value="s_[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="5" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="StaticVariableOfConcreteClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StaticVariableUninitializedUse" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignorePrimitives" value="false" />
+ </inspection_tool>
+ <inspection_tool class="StringBufferField" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StringBufferMustHaveInitialCapacity" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StringBufferReplaceableByString" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StringBufferReplaceableByStringBuilder" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StringBufferToStringInConcatenation" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StringCompareTo" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StringConcatenation" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreAsserts" value="false" />
+ <option name="ignoreSystemOuts" value="false" />
+ <option name="ignoreSystemErrs" value="false" />
+ <option name="ignoreThrowableArguments" value="false" />
+ <option name="ignoreConstantInitializers" value="false" />
+ <option name="ignoreInTestCode" value="false" />
+ <option name="ignoreInToString" value="false" />
+ </inspection_tool>
+ <inspection_tool class="StringConcatenationArgumentToLogCall" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StringConcatenationInFormatCall" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StringConcatenationInLoops" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreUnlessAssigned" value="true" />
+ </inspection_tool>
+ <inspection_tool class="StringConcatenationInMessageFormatCall" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StringConcatenationInsideStringBufferAppend" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StringConcatenationMissingWhitespace" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StringConstructor" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreSubstringArguments" value="false" />
+ </inspection_tool>
+ <inspection_tool class="StringEquality" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StringEquals" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StringEqualsEmptyString" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StringEqualsIgnoreCase" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StringLiteralBreaksHTMLJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StringReplaceableByStringBuffer" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="onlyWarnOnLoop" value="true" />
+ </inspection_tool>
+ <inspection_tool class="StringToString" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StringToUpperWithoutLocale" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StringTokenizer" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="StringWithMistakes" enabled="false" level="INFO" enabled_by_default="false" />
+ <inspection_tool class="Struts2ModelInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="StrutsInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="StrutsTilesInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="StrutsValidatorFormInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="StrutsValidatorInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="SubstringZero" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SubtractionInCompareTo" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SuperClassHasFrequentlyUsedInheritors" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SuppressionAnnotation" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SuspiciousArrayCast" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SuspiciousIndentAfterControlStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SuspiciousMethodCalls" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="REPORT_CONVERTIBLE_METHOD_CALLS" value="true" />
+ </inspection_tool>
+ <inspection_tool class="SuspiciousNameCombination" enabled="true" level="WARNING" enabled_by_default="true">
+ <group names="x,width,left,right" />
+ <group names="y,height,top,bottom" />
+ </inspection_tool>
+ <inspection_tool class="SuspiciousSystemArraycopy" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SuspiciousToArrayCall" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SwitchStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SwitchStatementDensity" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="20" />
+ </inspection_tool>
+ <inspection_tool class="SwitchStatementWithConfusingDeclaration" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SwitchStatementWithNoDefaultBranchJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SwitchStatementWithTooFewBranches" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="2" />
+ </inspection_tool>
+ <inspection_tool class="SwitchStatementWithTooManyBranches" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="10" />
+ </inspection_tool>
+ <inspection_tool class="SwitchStatementsWithoutDefault" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreFullyCoveredEnums" value="true" />
+ </inspection_tool>
+ <inspection_tool class="SynchronizationOnLocalVariableOrMethodParameter" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="reportLocalVariables" value="true" />
+ <option name="reportMethodParameters" value="true" />
+ </inspection_tool>
+ <inspection_tool class="SynchronizationOnStaticField" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SynchronizeOnLock" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SynchronizeOnNonFinalField" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SynchronizeOnThis" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SynchronizedMethod" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_includeNativeMethods" value="true" />
+ <option name="ignoreSynchronizedSuperMethods" value="true" />
+ </inspection_tool>
+ <inspection_tool class="SynchronizedOnLiteralObject" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SyntaxError" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SystemExit" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SystemGC" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SystemGetenv" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SystemOutErr" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SystemProperties" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SystemRunFinalizersOnExit" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SystemSetSecurityManager" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TaglibDomModelInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="TailRecursion" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TailRecursionJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TeardownCallsSuperTeardown" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TeardownIsPublicVoidNoArg" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TelReferencesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TestCaseInProductCode" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TestCaseWithConstructor" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TestCaseWithNoTestMethods" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreSupers" value="false" />
+ </inspection_tool>
+ <inspection_tool class="TestMethodInProductCode" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TestMethodIsPublicVoidNoArg" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TestMethodWithoutAssertion" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="assertionMethods" value="org.junit.Assert,assert.*|fail.*,junit.framework.Assert,assert.*|fail.*,org.mockito.Mockito,verify.*" />
+ <option name="assertKeywordIsAssertion" value="false" />
+ </inspection_tool>
+ <inspection_tool class="TestOnlyProblems" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TextLabelInSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TextLabelInSwitchStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ThisEscapedInConstructor" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ThisExpressionReferencesGlobalObjectJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ThreadDeathRethrown" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ThreadDumpStack" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ThreadLocalNotStaticFinal" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ThreadPriority" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ThreadRun" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ThreadStartInConstruction" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ThreadStopSuspendResume" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ThreadWithDefaultRunMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ThreadYield" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ThreeNegationsPerFunctionJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ThreeNegationsPerMethod" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreInEquals" value="true" />
+ <option name="ignoreInAssert" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ThrowCaughtLocally" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreRethrownExceptions" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ThrowFromFinallyBlock" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ThrowFromFinallyBlockJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ThrowableInstanceNeverThrown" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ThrowablePrintStackTrace" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ThrowablePrintedToSystemOut" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ThrowableResultOfMethodCallIgnored" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ThrownExceptionsPerMethod" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_limit" value="3" />
+ </inspection_tool>
+ <inspection_tool class="ThrowsRuntimeException" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TimeToString" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ToArrayCallWithZeroLengthArrayArgument" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TodoComment" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TooBroadCatch" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TooBroadScope" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_allowConstructorAsInitializer" value="false" />
+ <option name="m_onlyLookAtBlocks" value="false" />
+ </inspection_tool>
+ <inspection_tool class="TooBroadThrows" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TrailingSpacesInProperty" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TransientFieldInNonSerializableClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TransientFieldNotInitialized" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TrivialConditionalJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TrivialIf" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TrivialIfJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TrivialStringConcatenation" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TryFinallyCanBeTryWithResources" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TryWithIdenticalCatches" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TypeCustomizer" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TypeMayBeWeakened" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="useRighthandTypeAsWeakestTypeInAssignments" value="true" />
+ <option name="useParameterizedTypeForCollectionMethods" value="true" />
+ <option name="doNotWeakenToJavaLangObject" value="true" />
+ <option name="onlyWeakentoInterface" value="true" />
+ </inspection_tool>
+ <inspection_tool class="TypeParameterExtendsFinalClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TypeParameterExtendsObject" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TypeParameterHidesVisibleType" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TypeParameterNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*" />
+ <option name="m_minLength" value="1" />
+ <option name="m_maxLength" value="1" />
+ </inspection_tool>
+ <inspection_tool class="UNCHECKED_WARNING" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="IGNORE_UNCHECKED_ASSIGNMENT" value="false" />
+ <option name="IGNORE_UNCHECKED_GENERICS_ARRAY_CREATION" value="true" />
+ <option name="IGNORE_UNCHECKED_CALL" value="false" />
+ <option name="IGNORE_UNCHECKED_CAST" value="false" />
+ <option name="IGNORE_UNCHECKED_OVERRIDING" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UNUSED_IMPORT" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UNUSED_SYMBOL" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="LOCAL_VARIABLE" value="true" />
+ <option name="FIELD" value="true" />
+ <option name="METHOD" value="true" />
+ <option name="CLASS" value="true" />
+ <option name="PARAMETER" value="true" />
+ <option name="REPORT_PARAMETER_FOR_PUBLIC_METHODS" value="true" />
+ </inspection_tool>
+ <inspection_tool class="UnaryPlus" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UncheckedExceptionClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnclearBinaryExpression" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnconditionalWait" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnconstructableTestCase" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UndeclaredTests" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UndesirableClassUsage" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnhandledExceptionInJSP" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UninstantiableBinding" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UninstantiableImplementedByClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UninstantiableProvidedByClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnknownGuard" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnknownLanguage" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="UnnecessarilyQualifiedInnerClassAccess" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreReferencesNeedingImport" value="true" />
+ </inspection_tool>
+ <inspection_tool class="UnnecessarilyQualifiedStaticUsage" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreStaticFieldAccesses" value="false" />
+ <option name="m_ignoreStaticMethodCalls" value="false" />
+ <option name="m_ignoreStaticAccessFromStaticContext" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnnecessarilyQualifiedStaticallyImportedElement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryAnnotationParentheses" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryBlockStatement" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreSwitchBranches" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnnecessaryBoxing" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryCallToStringValueOf" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryConditionalExpression" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryConstantArrayCreationExpression" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryContinue" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryContinueJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryDefault" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnnecessaryEnumModifier" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnnecessaryExplicitNumericCast" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryFinalOnLocalVariable" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnnecessaryFinalOnLocalVariableOrParameter" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnnecessaryFinalOnParameter" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="onlyWarnOnAbstractMethods" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnnecessaryFullyQualifiedName" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreJavadoc" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnnecessaryInheritDoc" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnnecessaryInterfaceModifier" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnnecessaryJavaDocLink" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreInlineLinkToSuper" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnnecessaryLabelJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryLabelOnBreakStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryLabelOnBreakStatementJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryLabelOnContinueStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryLabelOnContinueStatementJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryLocalVariable" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreImmediatelyReturnedVariables" value="false" />
+ <option name="m_ignoreAnnotatedVariables" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnnecessaryLocalVariableJS" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreImmediatelyReturnedVariables" value="false" />
+ <option name="m_ignoreAnnotatedVariables" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnnecessaryModuleDependencyInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryParentheses" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreClarifyingParentheses" value="false" />
+ <option name="ignoreParenthesesOnConditionals" value="false" />
+ <option name="ignoreParenthesesOnLambdaParameter" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnnecessaryQualifiedReference" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryQualifierForThis" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnnecessaryReturn" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryReturnJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessarySemicolon" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryStaticInjection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnnecessarySuperConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessarySuperQualifier" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnnecessaryTemporaryOnConversionFromString" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryTemporaryOnConversionToString" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryThis" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnnecessaryToStringCall" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnnecessaryUnaryMinus" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnnecessaryUnboxing" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryUnicodeEscape" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnparsedCustomBeanInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnpredictableBigDecimalConstructorCall" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreReferences" value="true" />
+ <option name="ignoreComplexLiterals" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnqualifiedFieldAccess" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnqualifiedInnerClassAccess" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreReferencesToLocalInnerClasses" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnqualifiedMethodAccess" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnqualifiedStaticUsage" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreStaticFieldAccesses" value="false" />
+ <option name="m_ignoreStaticMethodCalls" value="false" />
+ <option name="m_ignoreStaticAccessFromStaticContext" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnreachableCodeJS" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnresolvedMessageChannelWarningInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnresolvedPropertyKey" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="UnresolvedReference" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="UnsafeVfsRecursion" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnsecureRandomNumberGeneration" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnterminatedStatementJS" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreSemicolonAtEndOfBlock" value="true" />
+ </inspection_tool>
+ <inspection_tool class="UnusedAssignment" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="REPORT_PREFIX_EXPRESSIONS" value="false" />
+ <option name="REPORT_POSTFIX_EXPRESSIONS" value="true" />
+ <option name="REPORT_REDUNDANT_INITIALIZER" value="true" />
+ </inspection_tool>
+ <inspection_tool class="UnusedCatchParameter" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreCatchBlocksWithComments" value="false" />
+ <option name="m_ignoreTestCases" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnusedCatchParameterJS" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreCatchBlocksWithComments" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnusedDeclaration" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ADD_MAINS_TO_ENTRIES" value="true" />
+ <option name="ADD_APPLET_TO_ENTRIES" value="true" />
+ <option name="ADD_SERVLET_TO_ENTRIES" value="true" />
+ <option name="ADD_NONJAVA_TO_ENTRIES" value="true" />
+ </inspection_tool>
+ <inspection_tool class="UnusedDefine" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnusedImport" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnusedLabel" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnusedLibrary" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnusedMessageFormatParameter" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnusedParameters" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnusedProperty" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnusedReturnValue" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UpperCaseFieldNameNotConstant" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UseJBColor" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UseOfAWTPeerClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UseOfAnotherObjectsPrivateField" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreSameClass" value="false" />
+ <option name="ignoreEquals" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UseOfJDBCDriverClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UseOfObsoleteAssert" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UseOfProcessBuilder" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UseOfPropertiesAsHashtable" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UseOfSunClasses" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UtilSchemaInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="UtilityClass" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignorableAnnotations">
+ <value />
+ </option>
+ </inspection_tool>
+ <inspection_tool class="UtilityClassWithPublicConstructor" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UtilityClassWithoutPrivateConstructor" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignorableAnnotations">
+ <value />
+ </option>
+ <option name="ignoreClassesWithOnlyMain" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ValidExternallyBoundObject" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="ValidatorConfigModelInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="ValidatorModelInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="VarargParameter" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="VariableNotUsedInsideIf" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="VoidExpressionJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="VoidMethodAnnotatedWithGET" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="VolatileArrayField" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="VolatileLongOrDoubleField" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="VtlDirectiveArgsInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="VtlFileReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="VtlInterpolationsInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="VtlReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="VtlTypesInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="W3CssValidation" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="myCssVersion" value="css3" />
+ </inspection_tool>
+ <inspection_tool class="WSReferenceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="WaitCalledOnCondition" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="WaitNotInLoop" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="WaitNotInSynchronizedContext" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="WaitOrAwaitWithoutTimeout" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="WaitWhileHoldingTwoLocks" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="WaitWithoutCorrespondingNotify" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="WeakerAccess" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS" value="false" />
+ <option name="SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES" value="false" />
+ <option name="SUGGEST_PRIVATE_FOR_INNERS" value="false" />
+ </inspection_tool>
+ <inspection_tool class="WebProperties" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="WebWarnings" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="WebflowConfigModelInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="WebflowModelInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="Weblogic" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="WhileCanBeForeach" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="WhileLoopSpinsOnField" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="ignoreNonEmtpyLoops" value="false" />
+ </inspection_tool>
+ <inspection_tool class="WithStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="WrongPackageStatement" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="WsdlHighlightingInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="XHTMLIncompatabilitiesJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="XmlDuplicatedId" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="XmlHighlighting" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="XmlInvalidId" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="XmlPathReference" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="XmlUnboundNsPrefix" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="XmlUnusedNamespaceDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="XmlWithMistakes" enabled="false" level="INFO" enabled_by_default="false" />
+ <inspection_tool class="XmlWrongRootElement" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="XsltDeclarations" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="XsltTemplateInvocation" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="XsltUnusedDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="XsltVariableShadowing" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ZeroLengthArrayInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="dependsOnMethodTestNG" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="groupsTestNG" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="groups">
+ <value>
+ <list size="0" />
+ </value>
+ </option>
+ </inspection_tool>
+ <inspection_tool class="gwtRawAsyncCallback" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="inspection_null_to_primary_type_variable" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="inspection_parametermap_in_statement" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="inspection_resultmap_in_select" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="inspection_select_result_absent" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="inspection_sqlmap_not_in_configuration" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="inspection_symbol_in_sql" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="osmorcClassInDefaultPackage" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="osmorcMissingFinalNewline" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="osmorcMisspelledHeaderName" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="osmorcNonOsgiMavenDependency" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="osmorcUnregisteredActivator" enabled="false" level="ERROR" enabled_by_default="false" />
+ </profile>
+</component>
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..1588227
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,131 @@
+<component name="InspectionProjectProfileManager">
+ <profile version="1.0" is_locked="false">
+ <option name="myName" value="Project Default" />
+ <option name="myLocal" value="false" />
+ <inspection_tool class="AbstractMethodCallInConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AbstractMethodOverridesAbstractMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AssignmentToCatchBlockParameter" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AssignmentToForLoopParameter" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_checkForeachParameters" value="false" />
+ </inspection_tool>
+ <inspection_tool class="AssignmentUsedAsCondition" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AutoBoxing" enabled="false" level="INFO" enabled_by_default="false">
+ <option name="ignoreAddedToCollection" value="false" />
+ </inspection_tool>
+ <inspection_tool class="AutoUnboxing" enabled="false" level="INFO" enabled_by_default="false" />
+ <inspection_tool class="BadExceptionThrown" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="exceptionsString" value="java.lang.Throwable,java.lang.Exception,java.lang.Error,java.lang.RuntimeException,java.lang.NullPointerException,java.lang.ClassCastException,java.lang.ArrayIndexOutOfBoundsException" />
+ <option name="exceptions">
+ <value />
+ </option>
+ </inspection_tool>
+ <inspection_tool class="CStyleArrayDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CatchGenericClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ClassInTopLevelPackage" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ClassMayBeInterface" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CloneInNonCloneableClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CloneableImplementsClone" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreCloneableDueToInheritance" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ComparisonOfShortAndChar" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConfusingOctalEscape" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EmptyClass" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignorableAnnotations">
+ <value />
+ </option>
+ <option name="ignoreClassWithParameterization" value="false" />
+ <option name="ignoreThrowables" value="true" />
+ </inspection_tool>
+ <inspection_tool class="ErrorRethrown" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FallthruInSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ForLoopReplaceableByWhile" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreLoopsWithoutConditions" value="false" />
+ </inspection_tool>
+ <inspection_tool class="IfStatementWithIdenticalBranches" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JavaDoc" enabled="true" level="INFO" enabled_by_default="true">
+ <option name="TOP_LEVEL_CLASS_OPTIONS">
+ <value>
+ <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+ <option name="REQUIRED_TAGS" value="" />
+ </value>
+ </option>
+ <option name="INNER_CLASS_OPTIONS">
+ <value>
+ <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+ <option name="REQUIRED_TAGS" value="" />
+ </value>
+ </option>
+ <option name="METHOD_OPTIONS">
+ <value>
+ <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+ <option name="REQUIRED_TAGS" value="@return at param@throws or @exception" />
+ </value>
+ </option>
+ <option name="FIELD_OPTIONS">
+ <value>
+ <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+ <option name="REQUIRED_TAGS" value="" />
+ </value>
+ </option>
+ <option name="IGNORE_DEPRECATED" value="false" />
+ <option name="IGNORE_JAVADOC_PERIOD" value="true" />
+ <option name="IGNORE_DUPLICATED_THROWS" value="false" />
+ <option name="IGNORE_POINT_TO_ITSELF" value="false" />
+ <option name="myAdditionalJavadocTags" value="" />
+ </inspection_tool>
+ <inspection_tool class="JavaLangImport" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JavadocReference" enabled="true" level="INFO" enabled_by_default="true" />
+ <inspection_tool class="MethodOnlyUsedFromInnerClass" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreMethodsAccessedFromAnonymousClass" value="true" />
+ <option name="ignoreStaticMethodsFromNonStaticInnerClass" value="false" />
+ <option name="onlyReportStaticMethods" value="false" />
+ </inspection_tool>
+ <inspection_tool class="NegatedIfElse" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreNegatedNullComparison" value="true" />
+ <option name="m_ignoreNegatedZeroComparison" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ObsoleteCollection" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreRequiredObsoleteCollectionTypes" value="false" />
+ </inspection_tool>
+ <inspection_tool class="OverridableMethodCallDuringObjectConstruction" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PublicField" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreEnums" value="false" />
+ <option name="ignorableAnnotations">
+ <value />
+ </option>
+ </inspection_tool>
+ <inspection_tool class="RedundantFieldInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RedundantImport" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ReplaceAssignmentWithOperatorAssignment" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreLazyOperators" value="true" />
+ <option name="ignoreObscureOperators" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ResultOfObjectAllocationIgnored" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SamePackageImport" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SameReturnValue" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SizeReplaceableByIsEmpty" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StaticCollection" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreWeakCollections" value="false" />
+ </inspection_tool>
+ <inspection_tool class="StringBufferField" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StringEqualsEmptyString" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SubstringZero" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SubtractionInCompareTo" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SystemGC" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TextLabelInSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TrivialIf" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnnecessaryBoxing" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnnecessaryConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryFullyQualifiedName" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreJavadoc" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnnecessaryLocalVariable" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreImmediatelyReturnedVariables" value="false" />
+ <option name="m_ignoreAnnotatedVariables" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnnecessarySuperConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryUnboxing" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnusedImport" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ZeroLengthArrayInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
+ </profile>
+</component>
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..470e646
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,7 @@
+<component name="InspectionProjectProfileManager">
+ <settings>
+ <option name="PROJECT_PROFILE" value="Mapping" />
+ <option name="USE_PROJECT_PROFILE" value="true" />
+ <version value="1.0" />
+ </settings>
+</component>
\ No newline at end of file
diff --git a/.idea/libraries/resource.xml b/.idea/libraries/resource.xml
new file mode 100644
index 0000000..fff892e
--- /dev/null
+++ b/.idea/libraries/resource.xml
@@ -0,0 +1,9 @@
+<component name="libraryTable">
+ <library name="resource">
+ <CLASSES>
+ <root url="file://$PROJECT_DIR$/test/resources" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+</component>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..d89ecce
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="EntryPointsManager">
+ <entry_points version="2.0" />
+ <list size="5">
+ <item index="0" class="java.lang.String" itemvalue="org.junit.After" />
+ <item index="1" class="java.lang.String" itemvalue="org.junit.AfterClass" />
+ <item index="2" class="java.lang.String" itemvalue="org.junit.Before" />
+ <item index="3" class="java.lang.String" itemvalue="org.junit.BeforeClass" />
+ <item index="4" class="java.lang.String" itemvalue="org.junit.Test" />
+ </list>
+ </component>
+ <component name="ExportToHTMLSettings">
+ <option name="OPEN_IN_BROWSER" value="true" />
+ <option name="OUTPUT_DIRECTORY" value="$USER_HOME$/inspections" />
+ </component>
+ <component name="FacetAutodetectingManager">
+ <autodetection-disabled>
+ <facet-type id="Python">
+ <modules>
+ <module name="mkgmap">
+ <files>
+ <file url="file://$PROJECT_DIR$/scripts/checksum.py" />
+ <file url="file://$PROJECT_DIR$/scripts/gmapi-builder.py" />
+ <file url="file://$PROJECT_DIR$/scripts/imgfile.py" />
+ <file url="file://$PROJECT_DIR$/scripts/mk_map_table.py" />
+ <file url="file://$PROJECT_DIR$/scripts/munger.py" />
+ <file url="file://$PROJECT_DIR$/scripts/namesum.py" />
+ <file url="file://$PROJECT_DIR$/scripts/new_style.py" />
+ </files>
+ </module>
+ </modules>
+ </facet-type>
+ </autodetection-disabled>
+ </component>
+ <component name="IdProvider" IDEtalkID="4895EF755ED348E86177D69FBFDA6A74" />
+ <component name="IvyIDEA.ProjectSettings">
+ <option name="artifactTypeSettings">
+ <ArtifactTypeSettings>
+ <option name="classesTypes" value="jar, mar, sar, war, ear, ejb, bundle, test-jar" />
+ <option name="javadocTypes" value="javadoc, doc, docs, apidoc, apidocs, documentation, documents" />
+ <option name="sourcesTypes" value="source, src, sources, srcs" />
+ </ArtifactTypeSettings>
+ </option>
+ <option name="ivySettingsFile" value="$PROJECT_DIR$/ivysettings.xml" />
+ <option name="propertiesSettings">
+ <PropertiesSettings />
+ </option>
+ </component>
+ <component name="IvyProjectSettings">
+ <dependencies />
+ </component>
+ <component name="JavadocGenerationManager">
+ <option name="OUTPUT_DIRECTORY" />
+ <option name="OPTION_SCOPE" value="protected" />
+ <option name="OPTION_HIERARCHY" value="true" />
+ <option name="OPTION_NAVIGATOR" value="true" />
+ <option name="OPTION_INDEX" value="true" />
+ <option name="OPTION_SEPARATE_INDEX" value="true" />
+ <option name="OPTION_DOCUMENT_TAG_USE" value="false" />
+ <option name="OPTION_DOCUMENT_TAG_AUTHOR" value="false" />
+ <option name="OPTION_DOCUMENT_TAG_VERSION" value="false" />
+ <option name="OPTION_DOCUMENT_TAG_DEPRECATED" value="true" />
+ <option name="OPTION_DEPRECATED_LIST" value="true" />
+ <option name="OTHER_OPTIONS" value="" />
+ <option name="HEAP_SIZE" />
+ <option name="LOCALE" />
+ <option name="OPEN_IN_BROWSER" value="true" />
+ </component>
+ <component name="ProjectDetails">
+ <option name="projectName" value="mkgmap" />
+ </component>
+ <component name="ProjectKey">
+ <option name="state" value="https://svn.parabola.me.uk/svn/mkgmap/trunk/.idea/misc.xml" />
+ </component>
+ <component name="ProjectResources">
+ <default-html-doctype>http://www.w3.org/1999/xhtml</default-html-doctype>
+ </component>
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
+ <output url="file://$PROJECT_DIR$/build/classes" />
+ </component>
+ <component name="SvnBranchConfigurationManager">
+ <option name="myConfigurationMap">
+ <map>
+ <entry key="$PROJECT_DIR$/../display">
+ <value>
+ <SvnBranchConfiguration>
+ <option name="trunkUrl" value="https://svn.parabola.me.uk/svn/display/trunk" />
+ </SvnBranchConfiguration>
+ </value>
+ </entry>
+ <entry key="$PROJECT_DIR$">
+ <value>
+ <SvnBranchConfiguration>
+ <option name="branchUrls">
+ <list>
+ <option value="https://svn.mkgmap.org.uk/svn/mkgmap/branches" />
+ </list>
+ </option>
+ <option name="trunkUrl" value="https://svn.mkgmap.org.uk/svn/mkgmap/trunk" />
+ </SvnBranchConfiguration>
+ </value>
+ </entry>
+ <entry key="$PROJECT_DIR$/.idea">
+ <value>
+ <SvnBranchConfiguration>
+ <option name="branchUrls">
+ <list>
+ <option value="https://svn.mkgmap.org.uk/svn/mkgmap/branches" />
+ <option value="https://svn.mkgmap.org.uk/svn/mkgmap/releases" />
+ <option value="https://svn.mkgmap.org.uk/svn/mkgmap/styles" />
+ <option value="https://svn.mkgmap.org.uk/svn/mkgmap/tags" />
+ </list>
+ </option>
+ <option name="trunkUrl" value="https://svn.mkgmap.org.uk/svn/mkgmap/trunk" />
+ </SvnBranchConfiguration>
+ </value>
+ </entry>
+ </map>
+ </option>
+ <option name="myVersion" value="124" />
+ <option name="mySupportsUserInfoFilter" value="true" />
+ </component>
+ <component name="WebServicesPlugin" addRequiredLibraries="true" />
+</project>
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..59bf28b
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ProjectModuleManager">
+ <modules>
+ <module fileurl="file://$PROJECT_DIR$/mkgmap.iml" filepath="$PROJECT_DIR$/mkgmap.iml" />
+ </modules>
+ </component>
+</project>
+
diff --git a/.idea/projectCodeStyle.xml b/.idea/projectCodeStyle.xml
new file mode 100644
index 0000000..3091564
--- /dev/null
+++ b/.idea/projectCodeStyle.xml
@@ -0,0 +1,423 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="CodeStyleSettingsManager">
+ <option name="PER_PROJECT_SETTINGS">
+ <value>
+ <option name="JAVA_INDENT_OPTIONS">
+ <value>
+ <option name="INDENT_SIZE" value="4" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="true" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </value>
+ </option>
+ <option name="JSP_INDENT_OPTIONS">
+ <value>
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="4" />
+ <option name="TAB_SIZE" value="2" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </value>
+ </option>
+ <option name="XML_INDENT_OPTIONS">
+ <value>
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="4" />
+ <option name="TAB_SIZE" value="2" />
+ <option name="USE_TAB_CHARACTER" value="true" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </value>
+ </option>
+ <option name="OTHER_INDENT_OPTIONS">
+ <value>
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="2" />
+ <option name="USE_TAB_CHARACTER" value="true" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </value>
+ </option>
+ <option name="LINE_SEPARATOR" value="
" />
+ <option name="USE_FQ_CLASS_NAMES_IN_JAVADOC" value="false" />
+ <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="20" />
+ <option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
+ <value>
+ <package name="java.awt" withSubpackages="false" static="false" />
+ <package name="" withSubpackages="true" static="false" />
+ <package name="javax.swing" withSubpackages="false" static="false" />
+ <package name="org.junit.Assert" withSubpackages="true" static="false" />
+ </value>
+ </option>
+ <option name="IMPORT_LAYOUT_TABLE">
+ <value>
+ <package name="java" withSubpackages="true" static="false" />
+ <emptyLine />
+ <package name="javax" withSubpackages="true" static="false" />
+ <emptyLine />
+ <package name="uk.me.parabola" withSubpackages="true" static="false" />
+ <emptyLine />
+ <package name="" withSubpackages="true" static="false" />
+ <emptyLine />
+ <package name="" withSubpackages="true" static="true" />
+ </value>
+ </option>
+ <option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
+ <option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
+ <option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
+ <option name="JD_P_AT_EMPTY_LINES" value="false" />
+ <option name="HTML_KEEP_LINE_BREAKS_IN_TEXT" value="false" />
+ <option name="HTML_KEEP_BLANK_LINES" value="1" />
+ <option name="HTML_ALIGN_ATTRIBUTES" value="false" />
+ <option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
+ <option name="BLOCK_COMMENT_AT_FIRST_COLUMN" value="false" />
+ <option name="BRACE_STYLE" value="5" />
+ <option name="CLASS_BRACE_STYLE" value="5" />
+ <option name="METHOD_BRACE_STYLE" value="5" />
+ <option name="INDENT_CASE_FROM_SWITCH" value="false" />
+ <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+ <option name="WRAP_COMMENTS" value="true" />
+ <ADDITIONAL_INDENT_OPTIONS fileType="css">
+ <option name="INDENT_SIZE" value="4" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="groovy">
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="gsp">
+ <option name="INDENT_SIZE" value="4" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="haml">
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="java">
+ <option name="INDENT_SIZE" value="4" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="true" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="js">
+ <option name="INDENT_SIZE" value="4" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="true" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="jsp">
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="4" />
+ <option name="TAB_SIZE" value="2" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="php">
+ <option name="INDENT_SIZE" value="4" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="py">
+ <option name="INDENT_SIZE" value="4" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="sass">
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="sql">
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="txt">
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="xml">
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="4" />
+ <option name="TAB_SIZE" value="2" />
+ <option name="USE_TAB_CHARACTER" value="true" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="yml">
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ <option name="USE_RELATIVE_INDENTS" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <codeStyleSettings language="ECMA Script Level 4">
+ <option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
+ <option name="BLOCK_COMMENT_AT_FIRST_COLUMN" value="false" />
+ <option name="KEEP_LINE_BREAKS" value="true" />
+ <option name="KEEP_FIRST_COLUMN_COMMENT" value="true" />
+ <option name="INSERT_FIRST_SPACE_IN_LINE" value="true" />
+ <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="true" />
+ <option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="2" />
+ <option name="KEEP_BLANK_LINES_IN_CODE" value="2" />
+ <option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="2" />
+ <option name="BLANK_LINES_BEFORE_PACKAGE" value="0" />
+ <option name="BLANK_LINES_AFTER_PACKAGE" value="1" />
+ <option name="BLANK_LINES_BEFORE_IMPORTS" value="1" />
+ <option name="BLANK_LINES_AFTER_IMPORTS" value="1" />
+ <option name="BLANK_LINES_AROUND_CLASS" value="1" />
+ <option name="BLANK_LINES_AROUND_FIELD" value="0" />
+ <option name="BLANK_LINES_AROUND_METHOD" value="1" />
+ <option name="BLANK_LINES_BEFORE_METHOD_BODY" value="0" />
+ <option name="BLANK_LINES_AROUND_FIELD_IN_INTERFACE" value="0" />
+ <option name="BLANK_LINES_AROUND_METHOD_IN_INTERFACE" value="1" />
+ <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="0" />
+ <option name="BLANK_LINES_AFTER_ANONYMOUS_CLASS_HEADER" value="0" />
+ <option name="BRACE_STYLE" value="5" />
+ <option name="CLASS_BRACE_STYLE" value="5" />
+ <option name="METHOD_BRACE_STYLE" value="5" />
+ <option name="USE_FLYING_GEESE_BRACES" value="false" />
+ <option name="FLYING_GEESE_BRACES_GAP" value="1" />
+ <option name="DO_NOT_INDENT_TOP_LEVEL_CLASS_MEMBERS" value="false" />
+ <option name="ELSE_ON_NEW_LINE" value="false" />
+ <option name="WHILE_ON_NEW_LINE" value="false" />
+ <option name="CATCH_ON_NEW_LINE" value="false" />
+ <option name="FINALLY_ON_NEW_LINE" value="false" />
+ <option name="INDENT_CASE_FROM_SWITCH" value="false" />
+ <option name="SPECIAL_ELSE_IF_TREATMENT" value="true" />
+ <option name="ALIGN_MULTILINE_CHAINED_METHODS" value="false" />
+ <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+ <option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="false" />
+ <option name="ALIGN_MULTILINE_RESOURCES" value="true" />
+ <option name="ALIGN_MULTILINE_FOR" value="true" />
+ <option name="INDENT_WHEN_CASES" value="true" />
+ <option name="ALIGN_MULTILINE_BINARY_OPERATION" value="false" />
+ <option name="ALIGN_MULTILINE_ASSIGNMENT" value="false" />
+ <option name="ALIGN_MULTILINE_TERNARY_OPERATION" value="false" />
+ <option name="ALIGN_MULTILINE_THROWS_LIST" value="false" />
+ <option name="ALIGN_THROWS_KEYWORD" value="false" />
+ <option name="ALIGN_MULTILINE_EXTENDS_LIST" value="false" />
+ <option name="ALIGN_MULTILINE_METHOD_BRACKETS" value="false" />
+ <option name="ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION" value="false" />
+ <option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="false" />
+ <option name="ALIGN_GROUP_FIELD_DECLARATIONS" value="false" />
+ <option name="SPACE_AROUND_ASSIGNMENT_OPERATORS" value="true" />
+ <option name="SPACE_AROUND_LOGICAL_OPERATORS" value="true" />
+ <option name="SPACE_AROUND_EQUALITY_OPERATORS" value="true" />
+ <option name="SPACE_AROUND_RELATIONAL_OPERATORS" value="true" />
+ <option name="SPACE_AROUND_BITWISE_OPERATORS" value="true" />
+ <option name="SPACE_AROUND_ADDITIVE_OPERATORS" value="true" />
+ <option name="SPACE_AROUND_MULTIPLICATIVE_OPERATORS" value="true" />
+ <option name="SPACE_AROUND_SHIFT_OPERATORS" value="true" />
+ <option name="SPACE_AROUND_UNARY_OPERATOR" value="false" />
+ <option name="SPACE_AFTER_COMMA" value="true" />
+ <option name="SPACE_AFTER_COMMA_IN_TYPE_ARGUMENTS" value="true" />
+ <option name="SPACE_BEFORE_COMMA" value="false" />
+ <option name="SPACE_AFTER_SEMICOLON" value="true" />
+ <option name="SPACE_BEFORE_SEMICOLON" value="false" />
+ <option name="SPACE_WITHIN_PARENTHESES" value="false" />
+ <option name="SPACE_WITHIN_METHOD_CALL_PARENTHESES" value="false" />
+ <option name="SPACE_WITHIN_METHOD_PARENTHESES" value="false" />
+ <option name="SPACE_WITHIN_IF_PARENTHESES" value="false" />
+ <option name="SPACE_WITHIN_WHILE_PARENTHESES" value="false" />
+ <option name="SPACE_WITHIN_FOR_PARENTHESES" value="false" />
+ <option name="SPACE_WITHIN_TRY_PARENTHESES" value="false" />
+ <option name="SPACE_WITHIN_CATCH_PARENTHESES" value="false" />
+ <option name="SPACE_WITHIN_SWITCH_PARENTHESES" value="false" />
+ <option name="SPACE_WITHIN_SYNCHRONIZED_PARENTHESES" value="false" />
+ <option name="SPACE_WITHIN_CAST_PARENTHESES" value="false" />
+ <option name="SPACE_WITHIN_BRACKETS" value="false" />
+ <option name="SPACE_WITHIN_BRACES" value="false" />
+ <option name="SPACE_WITHIN_ARRAY_INITIALIZER_BRACES" value="false" />
+ <option name="SPACE_AFTER_TYPE_CAST" value="true" />
+ <option name="SPACE_BEFORE_METHOD_CALL_PARENTHESES" value="false" />
+ <option name="SPACE_BEFORE_METHOD_PARENTHESES" value="false" />
+ <option name="SPACE_BEFORE_IF_PARENTHESES" value="true" />
+ <option name="SPACE_BEFORE_WHILE_PARENTHESES" value="true" />
+ <option name="SPACE_BEFORE_FOR_PARENTHESES" value="true" />
+ <option name="SPACE_BEFORE_TRY_PARENTHESES" value="true" />
+ <option name="SPACE_BEFORE_CATCH_PARENTHESES" value="true" />
+ <option name="SPACE_BEFORE_SWITCH_PARENTHESES" value="true" />
+ <option name="SPACE_BEFORE_SYNCHRONIZED_PARENTHESES" value="true" />
+ <option name="SPACE_BEFORE_CLASS_LBRACE" value="true" />
+ <option name="SPACE_BEFORE_METHOD_LBRACE" value="true" />
+ <option name="SPACE_BEFORE_IF_LBRACE" value="true" />
+ <option name="SPACE_BEFORE_ELSE_LBRACE" value="true" />
+ <option name="SPACE_BEFORE_WHILE_LBRACE" value="true" />
+ <option name="SPACE_BEFORE_FOR_LBRACE" value="true" />
+ <option name="SPACE_BEFORE_DO_LBRACE" value="true" />
+ <option name="SPACE_BEFORE_SWITCH_LBRACE" value="true" />
+ <option name="SPACE_BEFORE_TRY_LBRACE" value="true" />
+ <option name="SPACE_BEFORE_CATCH_LBRACE" value="true" />
+ <option name="SPACE_BEFORE_FINALLY_LBRACE" value="true" />
+ <option name="SPACE_BEFORE_SYNCHRONIZED_LBRACE" value="true" />
+ <option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="false" />
+ <option name="SPACE_BEFORE_ANNOTATION_ARRAY_INITIALIZER_LBRACE" value="false" />
+ <option name="SPACE_BEFORE_ELSE_KEYWORD" value="true" />
+ <option name="SPACE_BEFORE_WHILE_KEYWORD" value="true" />
+ <option name="SPACE_BEFORE_CATCH_KEYWORD" value="true" />
+ <option name="SPACE_BEFORE_FINALLY_KEYWORD" value="true" />
+ <option name="SPACE_BEFORE_QUEST" value="true" />
+ <option name="SPACE_AFTER_QUEST" value="true" />
+ <option name="SPACE_BEFORE_COLON" value="true" />
+ <option name="SPACE_AFTER_COLON" value="true" />
+ <option name="SPACE_BEFORE_TYPE_PARAMETER_LIST" value="false" />
+ <option name="CALL_PARAMETERS_WRAP" value="0" />
+ <option name="PREFER_PARAMETERS_WRAP" value="false" />
+ <option name="CALL_PARAMETERS_LPAREN_ON_NEXT_LINE" value="false" />
+ <option name="CALL_PARAMETERS_RPAREN_ON_NEXT_LINE" value="false" />
+ <option name="METHOD_PARAMETERS_WRAP" value="0" />
+ <option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="false" />
+ <option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="false" />
+ <option name="RESOURCE_LIST_WRAP" value="0" />
+ <option name="RESOURCE_LIST_LPAREN_ON_NEXT_LINE" value="false" />
+ <option name="RESOURCE_LIST_RPAREN_ON_NEXT_LINE" value="false" />
+ <option name="EXTENDS_LIST_WRAP" value="0" />
+ <option name="THROWS_LIST_WRAP" value="0" />
+ <option name="EXTENDS_KEYWORD_WRAP" value="0" />
+ <option name="THROWS_KEYWORD_WRAP" value="0" />
+ <option name="METHOD_CALL_CHAIN_WRAP" value="0" />
+ <option name="PARENTHESES_EXPRESSION_LPAREN_WRAP" value="false" />
+ <option name="PARENTHESES_EXPRESSION_RPAREN_WRAP" value="false" />
+ <option name="BINARY_OPERATION_WRAP" value="0" />
+ <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="false" />
+ <option name="TERNARY_OPERATION_WRAP" value="0" />
+ <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="false" />
+ <option name="MODIFIER_LIST_WRAP" value="false" />
+ <option name="KEEP_SIMPLE_BLOCKS_IN_ONE_LINE" value="false" />
+ <option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="false" />
+ <option name="KEEP_SIMPLE_CLASSES_IN_ONE_LINE" value="false" />
+ <option name="KEEP_MULTIPLE_EXPRESSIONS_IN_ONE_LINE" value="false" />
+ <option name="FOR_STATEMENT_WRAP" value="0" />
+ <option name="FOR_STATEMENT_LPAREN_ON_NEXT_LINE" value="false" />
+ <option name="FOR_STATEMENT_RPAREN_ON_NEXT_LINE" value="false" />
+ <option name="ARRAY_INITIALIZER_WRAP" value="0" />
+ <option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="false" />
+ <option name="ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE" value="false" />
+ <option name="ASSIGNMENT_WRAP" value="0" />
+ <option name="PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE" value="false" />
+ <option name="LABELED_STATEMENT_WRAP" value="2" />
+ <option name="WRAP_COMMENTS" value="true" />
+ <option name="ASSERT_STATEMENT_WRAP" value="0" />
+ <option name="ASSERT_STATEMENT_COLON_ON_NEXT_LINE" value="false" />
+ <option name="IF_BRACE_FORCE" value="0" />
+ <option name="DOWHILE_BRACE_FORCE" value="0" />
+ <option name="WHILE_BRACE_FORCE" value="0" />
+ <option name="FOR_BRACE_FORCE" value="0" />
+ <option name="WRAP_LONG_LINES" value="false" />
+ <option name="METHOD_ANNOTATION_WRAP" value="2" />
+ <option name="CLASS_ANNOTATION_WRAP" value="2" />
+ <option name="FIELD_ANNOTATION_WRAP" value="2" />
+ <option name="PARAMETER_ANNOTATION_WRAP" value="0" />
+ <option name="VARIABLE_ANNOTATION_WRAP" value="0" />
+ <option name="SPACE_BEFORE_ANOTATION_PARAMETER_LIST" value="false" />
+ <option name="SPACE_WITHIN_ANNOTATION_PARENTHESES" value="false" />
+ <option name="ENUM_CONSTANTS_WRAP" value="0" />
+ <option name="PARENT_SETTINGS_INSTALLED" value="true" />
+ </codeStyleSettings>
+ <codeStyleSettings language="JavaScript">
+ <option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
+ <option name="BLOCK_COMMENT_AT_FIRST_COLUMN" value="false" />
+ <option name="BRACE_STYLE" value="5" />
+ <option name="CLASS_BRACE_STYLE" value="5" />
+ <option name="METHOD_BRACE_STYLE" value="5" />
+ <option name="INDENT_CASE_FROM_SWITCH" value="false" />
+ <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+ <option name="WRAP_COMMENTS" value="true" />
+ <option name="PARENT_SETTINGS_INSTALLED" value="true" />
+ </codeStyleSettings>
+ <codeStyleSettings language="PHP">
+ <option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
+ <option name="BLOCK_COMMENT_AT_FIRST_COLUMN" value="false" />
+ <option name="BRACE_STYLE" value="5" />
+ <option name="CLASS_BRACE_STYLE" value="5" />
+ <option name="METHOD_BRACE_STYLE" value="5" />
+ <option name="INDENT_CASE_FROM_SWITCH" value="false" />
+ <option name="WRAP_COMMENTS" value="true" />
+ <option name="PARENT_SETTINGS_INSTALLED" value="true" />
+ </codeStyleSettings>
+ </value>
+ </option>
+ <option name="USE_PER_PROJECT_SETTINGS" value="true" />
+ </component>
+</project>
+
diff --git a/.idea/runConfigurations/Functional.xml b/.idea/runConfigurations/Functional.xml
new file mode 100644
index 0000000..4203719
--- /dev/null
+++ b/.idea/runConfigurations/Functional.xml
@@ -0,0 +1,41 @@
+<component name="ProjectRunConfigurationManager">
+ <configuration default="false" name="Functional" type="JUnit" factoryName="JUnit">
+ <extension name="coverage" enabled="true" merge="false" sample_coverage="true" runner="idea" />
+ <module name="mkgmap" />
+ <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
+ <option name="ALTERNATIVE_JRE_PATH" value="" />
+ <option name="PACKAGE_NAME" value="" />
+ <option name="MAIN_CLASS_NAME" value="" />
+ <option name="METHOD_NAME" value="" />
+ <option name="TEST_OBJECT" value="package" />
+ <option name="VM_PARAMETERS" value="-ea" />
+ <option name="PARAMETERS" value="" />
+ <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
+ <option name="ENV_VARIABLES" />
+ <option name="PASS_PARENT_ENVS" value="true" />
+ <option name="TEST_SEARCH_SCOPE">
+ <value defaultName="singleModule" />
+ </option>
+ <envs />
+ <patterns />
+ <RunnerSettings RunnerId="Cover" />
+ <RunnerSettings RunnerId="Debug">
+ <option name="DEBUG_PORT" value="58506" />
+ <option name="TRANSPORT" value="0" />
+ <option name="LOCAL" value="true" />
+ </RunnerSettings>
+ <RunnerSettings RunnerId="JProfiler">
+ <option name="WINDOW" value="false" />
+ <option name="JVMPI" value="false" />
+ <option name="INTERPRETED" value="false" />
+ </RunnerSettings>
+ <RunnerSettings RunnerId="Profile ">
+ <option name="myExternalizedOptions" value="
additional-options2=onexit\=snapshot
" />
+ </RunnerSettings>
+ <RunnerSettings RunnerId="Run" />
+ <ConfigurationWrapper RunnerId="Cover" />
+ <ConfigurationWrapper RunnerId="Debug" />
+ <ConfigurationWrapper RunnerId="Run" />
+ <method />
+ </configuration>
+</component>
\ No newline at end of file
diff --git a/.idea/runConfigurations/Unit_tests.xml b/.idea/runConfigurations/Unit_tests.xml
new file mode 100644
index 0000000..ad9ef2e
--- /dev/null
+++ b/.idea/runConfigurations/Unit_tests.xml
@@ -0,0 +1,39 @@
+<component name="ProjectRunConfigurationManager">
+ <configuration default="false" name="Unit tests" type="JUnit" factoryName="JUnit">
+ <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
+ <module name="mkgmap" />
+ <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
+ <option name="ALTERNATIVE_JRE_PATH" value="" />
+ <option name="PACKAGE_NAME" value="uk.me.parabola" />
+ <option name="MAIN_CLASS_NAME" value="" />
+ <option name="METHOD_NAME" value="" />
+ <option name="TEST_OBJECT" value="package" />
+ <option name="VM_PARAMETERS" value="-ea" />
+ <option name="PARAMETERS" value="" />
+ <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
+ <option name="ENV_VARIABLES" />
+ <option name="PASS_PARENT_ENVS" value="true" />
+ <option name="TEST_SEARCH_SCOPE">
+ <value defaultName="singleModule" />
+ </option>
+ <envs />
+ <patterns />
+ <RunnerSettings RunnerId="Debug">
+ <option name="DEBUG_PORT" value="42725" />
+ <option name="TRANSPORT" value="0" />
+ <option name="LOCAL" value="true" />
+ </RunnerSettings>
+ <RunnerSettings RunnerId="JProfiler">
+ <option name="WINDOW" value="false" />
+ <option name="JVMPI" value="false" />
+ <option name="INTERPRETED" value="false" />
+ </RunnerSettings>
+ <RunnerSettings RunnerId="Profile ">
+ <option name="myExternalizedOptions" value="
additional-options2=onexit\=snapshot
" />
+ </RunnerSettings>
+ <RunnerSettings RunnerId="Run" />
+ <ConfigurationWrapper RunnerId="Debug" />
+ <ConfigurationWrapper RunnerId="Run" />
+ <method />
+ </configuration>
+</component>
\ No newline at end of file
diff --git a/.idea/runConfigurations/mkgmap.xml b/.idea/runConfigurations/mkgmap.xml
new file mode 100644
index 0000000..5410003
--- /dev/null
+++ b/.idea/runConfigurations/mkgmap.xml
@@ -0,0 +1,31 @@
+<component name="ProjectRunConfigurationManager">
+ <configuration default="false" name="mkgmap" type="Application" factoryName="Application">
+ <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
+ <option name="MAIN_CLASS_NAME" value="uk.me.parabola.mkgmap.main.Main" />
+ <option name="VM_PARAMETERS" value="-ea -Xmx1000m" />
+ <option name="PROGRAM_PARAMETERS" value="--code-page=1251 freizeit.txt" />
+ <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
+ <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
+ <option name="ALTERNATIVE_JRE_PATH" value="" />
+ <option name="ENABLE_SWING_INSPECTOR" value="false" />
+ <option name="ENV_VARIABLES" />
+ <option name="PASS_PARENT_ENVS" value="true" />
+ <module name="mkgmap" />
+ <envs />
+ <RunnerSettings RunnerId="Cover" />
+ <RunnerSettings RunnerId="Debug">
+ <option name="DEBUG_PORT" value="48865" />
+ <option name="TRANSPORT" value="0" />
+ <option name="LOCAL" value="true" />
+ </RunnerSettings>
+ <RunnerSettings RunnerId="Profile ">
+ <option name="myExternalizedOptions" value="
additional-options2=onexit\=snapshot
" />
+ </RunnerSettings>
+ <RunnerSettings RunnerId="Run" />
+ <ConfigurationWrapper RunnerId="Cover" />
+ <ConfigurationWrapper RunnerId="Debug" />
+ <ConfigurationWrapper RunnerId="Profile " />
+ <ConfigurationWrapper RunnerId="Run" />
+ <method />
+ </configuration>
+</component>
\ No newline at end of file
diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml
new file mode 100644
index 0000000..922003b
--- /dev/null
+++ b/.idea/scopes/scope_settings.xml
@@ -0,0 +1,5 @@
+<component name="DependencyValidationManager">
+ <state>
+ <option name="SKIP_IMPORT_STATEMENTS" value="false" />
+ </state>
+</component>
\ No newline at end of file
diff --git a/.idea/spellchecker-settings.xml b/.idea/spellchecker-settings.xml
new file mode 100644
index 0000000..c3b8e21
--- /dev/null
+++ b/.idea/spellchecker-settings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="SpellCheckerSettings" BundledDictionaries="0" Folders="0" Dictionaries="0" />
+</project>
+
diff --git a/.idea/spellchecker.xml b/.idea/spellchecker.xml
new file mode 100644
index 0000000..05a3cf1
--- /dev/null
+++ b/.idea/spellchecker.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project relativePaths="false" version="4" />
+
diff --git a/.idea/sqlDataSources.xml b/.idea/sqlDataSources.xml
new file mode 100644
index 0000000..f6e673a
--- /dev/null
+++ b/.idea/sqlDataSources.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4" />
+
diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml
new file mode 100644
index 0000000..f6e673a
--- /dev/null
+++ b/.idea/sqldialects.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4" />
+
diff --git a/.idea/templateLanguages.xml b/.idea/templateLanguages.xml
new file mode 100644
index 0000000..f6e673a
--- /dev/null
+++ b/.idea/templateLanguages.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4" />
+
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000..3b00020
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="Palette2">
+ <group name="Swing">
+ <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+ </item>
+ <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+ </item>
+ <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
+ <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+ <initial-values>
+ <property name="text" value="Button" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="RadioButton" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="CheckBox" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="Label" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+ <preferred-size width="200" height="200" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+ <preferred-size width="200" height="200" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+ </item>
+ <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+ <preferred-size width="-1" height="20" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+ </item>
+ <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+ </item>
+ </group>
+ </component>
+</project>
+
diff --git a/.idea/validation.xml b/.idea/validation.xml
new file mode 100644
index 0000000..f6e673a
--- /dev/null
+++ b/.idea/validation.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4" />
+
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..9e0c1d4
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ClearCaseSharedConfig">
+ <option name="myUseUcmModel" value="true" />
+ </component>
+ <component name="VcsDirectoryMappings">
+ <mapping directory="" vcs="svn" />
+ </component>
+</project>
+
diff --git a/.idea/webContexts.xml b/.idea/webContexts.xml
new file mode 100644
index 0000000..f6e673a
--- /dev/null
+++ b/.idea/webContexts.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4" />
+
diff --git a/.project b/.project
new file mode 100644
index 0000000..8bf15cf
--- /dev/null
+++ b/.project
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>mkgmap</name>
+ <comment />
+ <projects />
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments />
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..996025a
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,4200 @@
+2008-12-20 steve
+
+ * src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java: Ensure
+ that it is impossible for subdivisions to be too big. They are
+ just limited to the max size if found to be so.
+
+2008-12-16 steve
+
+ * src/uk/me/parabola/mkgmap/Version.java,
+ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java,
+ src/uk/me/parabola/mkgmap/filters/PolygonSizeSplitterFilter.java:
+ Fix the rounding of the map definition areas (I hope).
+
+2008-12-15 steve
+
+ * src/uk/me/parabola/mkgmap/osmstyle/OverlayReader.java,
+ test/uk/me/parabola/mkgmap/osmstyle/StyledConverterTest.java:
+ Points were not copied when overlays were in use.
+
+2008-12-14 steve
+
+ * mkgmap.ipr, src/uk/me/parabola/mkgmap/combiners/OverviewMap.java,
+ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java,
+ src/uk/me/parabola/mkgmap/main/Main.java,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMap.java,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java:
+ Misc: Rearranged overview map classes. Planning to re-work so
+ that it works again.
+
+2008-12-13 steve
+
+ * Makefile, mkgmap.ipr,
+ src/uk/me/parabola/imgfmt/ExitException.java,
+ src/uk/me/parabola/imgfmt/app/BufferedImgFileWriter.java,
+ src/uk/me/parabola/imgfmt/sys/BlockManager.java,
+ src/uk/me/parabola/mkgmap/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/ExitException.java,
+ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java,
+ src/uk/me/parabola/mkgmap/general/AreaClipper.java,
+ src/uk/me/parabola/mkgmap/general/Clipper.java,
+ src/uk/me/parabola/mkgmap/general/LevelInfo.java,
+ src/uk/me/parabola/mkgmap/general/LineAdder.java,
+ src/uk/me/parabola/mkgmap/general/NullClipper.java,
+ src/uk/me/parabola/mkgmap/main/AbstractTestMap.java,
+ src/uk/me/parabola/mkgmap/main/Main.java,
+ src/uk/me/parabola/mkgmap/main/MapMaker.java,
+ src/uk/me/parabola/mkgmap/osmstyle/LineAdder.java,
+ src/uk/me/parabola/mkgmap/osmstyle/OverlayReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/GType.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Style.java,
+ src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5MapDataSource.java:
+ Misc: Reorganise the package structure to remove cycles that were
+ introduced in the style system.
+ * src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/ExpressionReader.java,
+ test/resources/teststyles/derived,
+ test/resources/teststyles/derived/info,
+ test/resources/teststyles/derived/lines,
+ test/resources/teststyles/derived/version,
+ test/resources/teststyles/simple/lines,
+ test/uk/me/parabola/imgfmt/app/typ/TYPFileTest.java,
+ test/uk/me/parabola/mkgmap/osmstyle/ActionReaderTest.java,
+ test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java,
+ test/uk/me/parabola/mkgmap/osmstyle/StyledConverterTest.java:
+ Recognise the match operator, add test for derived styles.
+ * src/uk/me/parabola/mkgmap/osmstyle/eval/Op.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/RegexOp.java: Add regex
+ operation for rules files.
+
+2008-12-10 steve
+
+ * resources/styles/noname/lines: The noname style was mostly
+ invisible when in the night-time scheme. So use a different code
+ for named roads.
+ * src/uk/me/parabola/imgfmt/app/trergn/Point.java,
+ src/uk/me/parabola/mkgmap/build/MapBuilder.java,
+ src/uk/me/parabola/mkgmap/general/AreaClipper.java,
+ src/uk/me/parabola/mkgmap/general/Clipper.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java,
+ src/uk/me/parabola/mkgmap/general/MapPoint.java,
+ src/uk/me/parabola/mkgmap/general/NullClipper.java,
+ src/uk/me/parabola/mkgmap/osmstyle/LineAdder.java,
+ src/uk/me/parabola/mkgmap/osmstyle/OverlayReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/GType.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Style.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Tags.java,
+ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/test/AllElements.java,
+ src/uk/me/parabola/mkgmap/reader/test/TestPoints.java,
+ src/uk/me/parabola/mkgmap/scan/TokenScanner.java,
+ test/resources/teststyles/simple/lines,
+ test/resources/teststyles/simple/overlays,
+ test/uk/me/parabola/mkgmap/osmstyle/ActionReaderTest.java,
+ test/uk/me/parabola/mkgmap/osmstyle/StyledConverterTest.java,
+ test/uk/me/parabola/mkgmap/reader/osm/ElementTest.java,
+ test/uk/me/parabola/mkgmap/reader/osm/TagsTest.java: Implement
+ overlays.
+
+ With this feature you can have a line style that is formed by
+ over laying two lines. By using a TYP file with appropriate
+ definitions, you can create some useful effects.
+
+ To use this create an overlays file in the style. Lines in the
+ file look like this:
+
+ 0x142: 0x12, 0x17, 0x18
+
+ This means that if you have a line of type 0x142, it will be
+ written as three lines with types 0x12, 0x17 and 0x18
+ respectively instead of 0x142.
+
+2008-12-09 steve
+
+ * mkgmap.iml, src/uk/me/parabola/mkgmap/reader/osm/Element.java,
+ src/uk/me/parabola/mkgmap/reader/osm/SimpleMap.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Tags.java,
+ test/uk/me/parabola/mkgmap/reader/osm/TagsTest.java: Rename
+ SimpleMap to Tags to reflect its only use.
+ * src/uk/me/parabola/mkgmap/general/MapElement.java: Bug fix for
+ max resolution.
+
+2008-12-08 steve
+
+ * Makefile, resources/styles/default/lines,
+ resources/styles/default/relations, resources/styles/noname,
+ resources/styles/noname/info, resources/styles/noname/lines,
+ resources/styles/noname/version,
+ src/uk/me/parabola/mkgmap/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/Main.java,
+ src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/SequenceRule.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StylePrinter.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/NotExistsOp.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Element.java,
+ src/uk/me/parabola/mkgmap/reader/osm/GType.java,
+ src/uk/me/parabola/mkgmap/reader/osm/SimpleMap.java,
+ src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5MapDataSource.java,
+ test/resources/teststyles/simple/lines,
+ test/uk/me/parabola/mkgmap/osmstyle/ActionReaderTest.java,
+ test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java,
+ test/uk/me/parabola/mkgmap/osmstyle/StyledConverterTest.java: Add
+ a noname style.
+
+ Can be used with --style=noname
+
+ Major roads that do not have a ref, as well as residential roads
+ that do not have a name are highlighted. You can use the tag
+ noname=yes to show that a road doesn't have and name and
+ therefore shouldn't be highlighted.
+
+ No-name roads show up as a thick line that is visible at higher
+ zooms than is usual for residential roads to help you find areas
+ with poor naming coverage.
+
+2008-12-07 steve
+
+ * resources/styles/default/info, resources/styles/default/lines,
+ resources/styles/default/map-features.csv,
+ resources/styles/default/points,
+ resources/styles/default/polygons,
+ src/uk/me/parabola/mkgmap/osmstyle/SequenceRule.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StylePrinter.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/AddTagAction.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/NameAction.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuilder.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/ValueItem.java,
+ src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java,
+ src/uk/me/parabola/mkgmap/scan/TokenScanner.java,
+ test/resources/teststyles/empty,
+ test/resources/teststyles/empty/points,
+ test/resources/teststyles/empty/relations,
+ test/resources/teststyles/empty/version,
+ test/uk/me/parabola/mkgmap/osmstyle/StyleImplTest.java: Make the
+ default style a rules-based one.
+
+ Fix a bug when a file is empty.
+
+ add to strings to the value action rules.
+ * src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/ConvertFilter.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/ValueItem.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Element.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java,
+ test/uk/me/parabola/mkgmap/osmstyle/actions/AddTagActionTest.java:
+ Remove old hardcoded rules for name and contours but add
+ equivilent rules if you are using an old map-features.csv based
+ style for backward compatibility.
+
+ New styles have to be particular about how to format the name of
+ a road and how to deal with contour lines etc.
+ * ., doc/style-rules.txt, mkgmap.iml, mkgmap.ipr,
+ src/uk/me/parabola/imgfmt/app/typ,
+ src/uk/me/parabola/mkgmap/Options.java,
+ src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyleFileLoader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java,
+ src/uk/me/parabola/mkgmap/osmstyle/TypeReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/Action.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/ActionReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/AddTagAction.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/ConvertFilter.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/DefaultFilter.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/DeleteAction.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/NameAction.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/SubAction.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuilder.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/ValueFilter.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/ValueItem.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/ExpressionReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/Op.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/UnitConversions.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Element.java,
+ src/uk/me/parabola/mkgmap/reader/osm/GType.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Relation.java,
+ src/uk/me/parabola/mkgmap/scan/TokenScanner.java, test/resources,
+ test/resources/teststyles, test/resources/teststyles/simple,
+ test/resources/teststyles/simple/info,
+ test/resources/teststyles/simple/lines,
+ test/resources/teststyles/simple/options,
+ test/resources/teststyles/simple/version, test/uk, test/uk/me,
+ test/uk/me/parabola, test/uk/me/parabola/mkgmap,
+ test/uk/me/parabola/mkgmap/osmstyle/ActionReaderTest.java,
+ test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java,
+ test/uk/me/parabola/mkgmap/osmstyle/StyleImplTest.java,
+ test/uk/me/parabola/mkgmap/osmstyle/StyledConverterTest.java,
+ test/uk/me/parabola/mkgmap/osmstyle/actions/AddTagActionTest.java,
+ test/uk/me/parabola/mkgmap/reader,
+ test/uk/me/parabola/mkgmap/reader/osm,
+ test/uk/me/parabola/mkgmap/reader/osm/ElementTest.java: Merge
+ style branch into trunk.
+
+ The style system is now nearly complete. Will then remove the
+ hardcoded rules for name and contours.
+ * build.xml: Don't include the source in the distributions as we
+ have a separate source one now and have done for a while.
+
+2008-12-06 steve
+
+ * src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java: Make
+ the MPS file name distinctive.
+ * mkgmap.ipr, src/uk/me/parabola/imgfmt/sys/BlockManager.java,
+ src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/mkgmap/combiners/FileInfo.java,
+ src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java:
+ Calculate the block size needed for the gmapsupp correctly. Was
+ ignoring the main constraint while concentrating on a minor
+ one....
+
+ Also there should be a warning now if the directory overflows. If
+ it does that would be a bug.
+
+2008-12-01 steve
+
+ * mkgmap.ipr, src/uk/me/parabola/imgfmt/app/CommonHeader.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/trergn/LinePreparer.java,
+ src/uk/me/parabola/imgfmt/app/typ/BitmapImage.java,
+ src/uk/me/parabola/imgfmt/app/typ/PointInfo.java,
+ src/uk/me/parabola/mkgmap/filters/FilterConfig.java,
+ src/uk/me/parabola/mkgmap/general/LineClipper.java,
+ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java,
+ test/uk/me/parabola/imgfmt/app/typ,
+ test/uk/me/parabola/imgfmt/app/typ/TYPFileTest.java: Misc: code
+ clean up.
+
+2008-11-30 steve
+
+ * src/uk/me/parabola/imgfmt/FormatException.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/Writeable.java,
+ src/uk/me/parabola/imgfmt/app/typ,
+ src/uk/me/parabola/imgfmt/app/typ/BitmapImage.java,
+ src/uk/me/parabola/imgfmt/app/typ/DrawOrder.java,
+ src/uk/me/parabola/imgfmt/app/typ/PointInfo.java,
+ src/uk/me/parabola/imgfmt/app/typ/Rgb.java,
+ src/uk/me/parabola/imgfmt/app/typ/ShapeStacking.java,
+ src/uk/me/parabola/imgfmt/app/typ/TYPFile.java,
+ src/uk/me/parabola/imgfmt/app/typ/TYPHeader.java: Brought in the
+ TYP file implementation from Thomas LuÃnig.
+
+ This is from the typpoi branch, there is still more to be
+ integrated from that branch.
+ * src/uk/me/parabola/mkgmap/osmstyle/Action.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StylePrinter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/GType.java,
+ src/uk/me/parabola/mkgmap/scan/TokenScanner.java: Misc: Code
+ tidy.
+ * ., Makefile, doc/style.txt, mkgmap.ipr,
+ src/uk/me/parabola/mkgmap/build/MapBuilder.java,
+ src/uk/me/parabola/mkgmap/general/Clipper.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/general/PolygonClipper.java,
+ src/uk/me/parabola/mkgmap/main/Main.java,
+ src/uk/me/parabola/mkgmap/osmstyle/Action.java,
+ src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java,
+ src/uk/me/parabola/mkgmap/osmstyle/DefaultFeatureNames.java,
+ src/uk/me/parabola/mkgmap/osmstyle/JarFileLoader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/MapFeatureReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/SequenceRule.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyleFileLoader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StylePrinter.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java,
+ src/uk/me/parabola/mkgmap/osmstyle/TypeReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/Action.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/ActionReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/AddTagAction.java,
+ src/uk/me/parabola/mkgmap/osmstyle/actions/RenameAction.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/EqualsOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/ExpressionReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/GTEOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/GTOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/LTEOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/LTOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/NumericOp.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Element.java,
+ src/uk/me/parabola/mkgmap/reader/osm/GType.java,
+ src/uk/me/parabola/mkgmap/reader/osm/GeneralRelation.java,
+ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Relation.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Style.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyleInfo.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way.java,
+ src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java,
+ src/uk/me/parabola/mkgmap/scan/Token.java,
+ src/uk/me/parabola/mkgmap/scan/TokenScanner.java, test/uk,
+ test/uk/me, test/uk/me/parabola, test/uk/me/parabola/mkgmap,
+ test/uk/me/parabola/mkgmap/osmstyle,
+ test/uk/me/parabola/mkgmap/osmstyle/ActionReaderTest.java,
+ test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java,
+ test/uk/me/parabola/mkgmap/osmstyle/actions,
+ test/uk/me/parabola/mkgmap/osmstyle/actions/AddTagActionTest.java:
+ Merge from style branch.
+ * ., ChangeLog, mkgmap.ipr,
+ src/uk/me/parabola/imgfmt/app/BitReader.java,
+ src/uk/me/parabola/mkgmap/Version.java,
+ test/uk/me/parabola/imgfmt, test/uk/me/parabola/imgfmt/app,
+ test/uk/me/parabola/imgfmt/app/BitReaderTest.java,
+ test/uk/me/parabola/mkgmap/general/LineClipperTest.java: Misc:
+ tests, version and changelog updating.
+
+2008-11-29 steve
+
+ * src/uk/me/parabola/imgfmt/app/BitReader.java: Merge from nod to
+ allow display to compile with trunk
+ * mkgmap.iml, mkgmap.ipr, src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/mkgmap/general/LineClipper.java, test/uk,
+ test/uk/me, test/uk/me/parabola, test/uk/me/parabola/mkgmap,
+ test/uk/me/parabola/mkgmap/general,
+ test/uk/me/parabola/mkgmap/general/LineClipperTest.java: Line
+ clipping was producing zero length lines.
+
+2008-11-28 steve
+
+ * ., mkgmap.ipr,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesHeader.java,
+ src/uk/me/parabola/imgfmt/app/map/Map.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java,
+ src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java,
+ src/uk/me/parabola/imgfmt/sys/FileImgChannel.java,
+ src/uk/me/parabola/imgfmt/sys/ImgFS.java,
+ src/uk/me/parabola/imgfmt/sys/ImgHeader.java,
+ src/uk/me/parabola/mkgmap/combiners/FileInfo.java,
+ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java,
+ src/uk/me/parabola/mkgmap/general/LineClipper.java,
+ src/uk/me/parabola/mkgmap/gui/Main.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestLangMap.java,
+ src/uk/me/parabola/mkgmap/osmstyle/DefaultFeatureNames.java,
+ src/uk/me/parabola/mkgmap/osmstyle/DirectoryFileLoader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/Op.java,
+ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java,
+ src/uk/me/parabola/mkgmap/reader/osm/xml/OsmMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/test/AllElements.java,
+ src/uk/me/parabola/mkgmap/reader/test/TestPoints.java,
+ src/uk/me/parabola/tdbfmt/CopyrightSegment.java,
+ src/uk/me/parabola/tdbfmt/TdbFile.java: Code tidying.
+
+2008-11-27 steve
+
+ * src/uk/me/parabola/imgfmt/Utils.java: Reversing change to the
+ date routines in this file as I suspect they may be causing the
+ recently observed breakage.
+
+ I remember from the beginning that things dont work if the year
+ field has certain values.
+
+2008-11-23 steve
+
+ * ChangeLog, doc/Credits,
+ src/uk/me/parabola/imgfmt/app/map/Map.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java,
+ src/uk/me/parabola/mkgmap/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/scan/TokenScanner.java,
+ src/uk/me/parabola/tdbfmt/OverviewMapBlock.java: Fixed
+ NumberFormatException problems on map names that are not
+ integers.
+
+2008-11-16 steve
+
+ * mkgmap.ipr, mkgmap.iws, src/uk/me/parabola/imgfmt/Utils.java,
+ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java:
+ Code clean up.
+ * mkgmap.ipr, mkgmap.iws,
+ src/uk/me/parabola/imgfmt/app/BitReader.java,
+ src/uk/me/parabola/imgfmt/app/CommonHeader.java,
+ src/uk/me/parabola/imgfmt/app/OffsetWriter.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Latin2Encoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Utf8Decoder.java,
+ src/uk/me/parabola/imgfmt/app/net/RoadDef.java,
+ src/uk/me/parabola/imgfmt/app/net/RoadIndex.java,
+ src/uk/me/parabola/imgfmt/app/trergn/MapValues.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java,
+ src/uk/me/parabola/mkgmap/scan/Token.java,
+ src/uk/me/parabola/mkgmap/scan/TokenScanner.java,
+ src/uk/me/parabola/tdbfmt/RBlock.java: Code clean up.
+ * mkgmap.ipr, mkgmap.iws, src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/imgfmt/app/BitReader.java,
+ src/uk/me/parabola/imgfmt/app/Coord.java,
+ src/uk/me/parabola/imgfmt/app/Section.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java,
+ src/uk/me/parabola/imgfmt/app/map/Map.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Overview.java,
+ src/uk/me/parabola/imgfmt/mps/Block.java,
+ src/uk/me/parabola/imgfmt/sys/ImgFS.java,
+ src/uk/me/parabola/imgfmt/sys/ImgHeader.java,
+ src/uk/me/parabola/io/StructuredInputStream.java,
+ src/uk/me/parabola/mkgmap/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/build/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java,
+ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java,
+ src/uk/me/parabola/mkgmap/filters/FilterConfig.java,
+ src/uk/me/parabola/mkgmap/general/AreaClipper.java,
+ src/uk/me/parabola/mkgmap/main/MapOption.java,
+ src/uk/me/parabola/mkgmap/osmstyle/CombinedStyleFileLoader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java,
+ src/uk/me/parabola/mkgmap/osmstyle/TypeReader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Element.java,
+ src/uk/me/parabola/mkgmap/reader/osm/GType.java,
+ src/uk/me/parabola/mkgmap/reader/osm/xml/OsmMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java,
+ src/uk/me/parabola/tdbfmt/TdbFile.java: Code clean up.
+ * mkgmap.iml, mkgmap.ipr, mkgmap.iws: Add intellij files.
+ * src/uk/me/parabola/mkgmap/general/LineClipper.java: Fix clipping
+ bug where a line runs parallel to the side we are clipping
+ against. Also changed many double values to int's as we only work
+ in ints for the coordinates anyway. Changed some terminology to
+ better match the web page description of the algorithm.
+
+ (Bug reported by beej71)
+
+2008-11-12 steve
+
+ * ., src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/GType.java: Merge change to
+ restore the rule ordering within the file. Rules earlier take
+ priority over rules later.
+
+2008-11-10 steve
+
+ * ., src/uk/me/parabola/mkgmap/general/AreaClipper.java,
+ src/uk/me/parabola/mkgmap/general/Clipper.java,
+ src/uk/me/parabola/mkgmap/general/NullClipper.java,
+ src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java,
+ src/uk/me/parabola/mkgmap/osmstyle/TypeReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/EqualsOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/GTEOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/GTOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/LTEOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/LTOp.java,
+ src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java,
+ src/uk/me/parabola/mkgmap/scan/TokenScanner.java: Merge in
+ important bug fixes from the style branch. Makes all the examples
+ work.
+
+2008-11-09 steve
+
+ * ., Makefile, doc/style-examples.txt, doc/style-rules.txt,
+ doc/style.txt, scripts/new_style.py,
+ src/uk/me/parabola/imgfmt/app/BitWriter.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Latin2Encoder.java,
+ src/uk/me/parabola/imgfmt/app/trergn/LinePreparer.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Point.java,
+ src/uk/me/parabola/imgfmt/app/trergn/RGNFile.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java,
+ src/uk/me/parabola/imgfmt/sys/FileNode.java,
+ src/uk/me/parabola/log/Logger.java,
+ src/uk/me/parabola/mkgmap/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/Option.java,
+ src/uk/me/parabola/mkgmap/OptionProcessor.java,
+ src/uk/me/parabola/mkgmap/Options.java,
+ src/uk/me/parabola/mkgmap/Version.java,
+ src/uk/me/parabola/mkgmap/build/MapBuilder.java,
+ src/uk/me/parabola/mkgmap/general/Clipper.java,
+ src/uk/me/parabola/mkgmap/general/LevelInfo.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/main/AbstractTestMap.java,
+ src/uk/me/parabola/mkgmap/main/Main.java,
+ src/uk/me/parabola/mkgmap/main/MapMaker.java,
+ src/uk/me/parabola/mkgmap/osmstyle,
+ src/uk/me/parabola/mkgmap/osmstyle/CombinedStyleFileLoader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/DefaultFeatureNames.java,
+ src/uk/me/parabola/mkgmap/osmstyle/DirectoryFileLoader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java,
+ src/uk/me/parabola/mkgmap/osmstyle/FixedRule.java,
+ src/uk/me/parabola/mkgmap/osmstyle/JarFileLoader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/MapFeatureReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java,
+ src/uk/me/parabola/mkgmap/osmstyle/SequenceRule.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyleFileLoader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java,
+ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java,
+ src/uk/me/parabola/mkgmap/osmstyle/TypeReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/AndOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/BinaryOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/CloseOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/EqualsOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/ExistsOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/ExpressionReader.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/GTEOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/GTOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/LTEOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/LTOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/NotEqualOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/NotExistsOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/NotOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/Op.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/OpenOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/OrOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/SyntaxException.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/ValueOp.java,
+ src/uk/me/parabola/mkgmap/osmstyle/eval/ValueWithUnit.java,
+ src/uk/me/parabola/mkgmap/osmstyle/package.html,
+ src/uk/me/parabola/mkgmap/reader/osm/CombinedStyleFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/DirectoryFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Element.java,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/GType.java,
+ src/uk/me/parabola/mkgmap/reader/osm/JarFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Node.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5XmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Rule.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Style.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyleFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyleInfo.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyledConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way5.java,
+ src/uk/me/parabola/mkgmap/reader/osm/WordScanner.java,
+ src/uk/me/parabola/mkgmap/reader/osm/package.html,
+ src/uk/me/parabola/mkgmap/reader/osm/xml,
+ src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/xml/OsmMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/plugin/MapReader.java,
+ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java,
+ src/uk/me/parabola/mkgmap/scan,
+ src/uk/me/parabola/mkgmap/scan/TokType.java,
+ src/uk/me/parabola/mkgmap/scan/Token.java,
+ src/uk/me/parabola/mkgmap/scan/TokenScanner.java: Merge the style
+ branch back to the trunk. Next the branch will be recreated for
+ more work.
+ * src/uk/me/parabola/imgfmt/app/BufferedImgFileWriter.java,
+ src/uk/me/parabola/mkgmap/Version.java: Change the message when
+ the RGN region overflows. The previous message was confusing, and
+ I don't expect the new one will be any better, but I will keep
+ changing it until it is. Exit the program as there is not point
+ of going on as the map will not work and it is best not to give
+ hope that it will.
+
+ Bumped the built in version number - thanks Petr for reminding
+ me.
+
+2008-08-31 steve
+
+ * src/uk/me/parabola/imgfmt/app/BitReader.java: Add a signed get
+ method to the bitreader
+
+2008-08-30 steve
+
+ * Makefile, src/uk/me/parabola/imgfmt/app/BitReader.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java: Changes to
+ help display rgn files.
+
+2008-08-28 steve
+
+ * resources/styles/default/map-features.csv: Add highway=path
+ because some people use that. -Markus Barchfeld
+
+2008-08-25 steve
+
+ * src/uk/me/parabola/mkgmap/build/MapBuilder.java,
+ src/uk/me/parabola/mkgmap/general/LevelInfo.java,
+ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java:
+ When a reader plugin already contains an empty top level zoom,
+ then we do not want to create a new one so mark such levels
+ specially and use them for creating the empty level instead of
+ creating our own. Thanks to Pazapas for pointing this out.
+ * src/uk/me/parabola/imgfmt/app/Section.java: Apply fix from the
+ nod branch. When sections are linked then the begining of the
+ second should be the end of the previous one (not the start of
+ the previous).
+
+ Possibly would have caused some weird POI behaviour.
+
+2008-08-24 steve
+
+ * ChangeLog, src/uk/me/parabola/imgfmt/Utils.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/ImgFileReader.java,
+ src/uk/me/parabola/imgfmt/app/ImgFileWriter.java: Some more
+ changes that should have been included in the previous commit.
+
+ Two phase writing of the sections.
+ * src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/map/Map.java,
+ src/uk/me/parabola/imgfmt/app/net/NETFile.java,
+ src/uk/me/parabola/imgfmt/app/trergn/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/typ/TYPFile.java,
+ src/uk/me/parabola/mkgmap/build/MapBuilder.java: The sync method
+ was a bad idea for net and nod.
+
+ We need to separate writing into two phases and control the order
+ that these phases are written in.
+
+ So: 1. Make sync just write the buffers to the disk. 2. Add write
+ and writePost() methods to control the different phases.
+
+ Verified that you get the same result file on trunk.
+
+2008-08-22 elrond
+
+ * src/uk/me/parabola/mkgmap/reader/osm/Osm5XmlHandler.java: Support
+ <bounds> in .osm
+
+ The current OSM api sends a <bounds minlat="..." minlon="..."
+ maxlat="..." maxlon="..."/>. Use it to setup the bounding box.
+
+ (<bound> is another already supported way.)
+ * resources/map-features.csv, resources/osm_garmin_map.csv,
+ resources/styles/default/map-features.csv: Add new features
+ (archaeological_site, school, playground)
+
+ point historic=archaeological_site ->
+ attractions|museum-historical polygon amenity=school ->
+ university (closest match) polygon leisure=playground ->
+ city-park (closest match)
+
+2008-08-03 steve
+
+ * .: Merge tracking for typpoi nod and style branches.
+
+2008-08-02 steve
+
+ * src/uk/me/parabola/mkgmap/filters/SmoothingFilter.java: Initial
+ fix for polygon smoothing, more to do. - Olaf Kähler
+ * src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java:
+ some trivial bugs about converting meters/feet in .mp files...
+ now also all three kinds of contour lines will be processed. -
+ Olaf Kähler
+
+2008-07-28 steve
+
+ * src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5XmlHandler.java: 1: When
+ using files processed by osmcut some ways which were part of the
+ relation were not in the file causing a null-pointer exception.
+ This is now handled in both OSM5XMLHandler and
+ MultipolygonRelation. 2: I changed the calcutation of the
+ distance between points to also take hemisphere changes into
+ account. The code looks not nice to me however. 3: I uncommented
+ the last line of the insertPoints function as the islands looked
+ ok on my venture HC. It appears only mapsource messes things up.
+ Rene Affourtit
+
+2008-07-27 steve
+
+ * Makefile, src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/mkgmap/main/MapMaker.java,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java:
+ Completely empty osm files caused mkgmap to go into a loop and
+ run out of memory. Now we just ignore any empty file. If the file
+ still has a valid bounds element then the output will still be
+ produced. Reported by Christian Ehrlicher.
+
+2008-07-23 steve
+
+ * src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java:
+ When a way is tagged both riverbank and coastline, then prefer
+ the coastline. This gives the best results until there is code to
+ deal with filling in in-complete polygons.
+
+2008-07-18 steve
+
+ * src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java:
+ Add the bodge that allows the contour tag have a height
+ specified, to the contour_ext tags too. Requested by a couple of
+ people for use with Srtm2Osm.
+
+ The mythical new style system will allow this to be configured
+ properly...
+
+2008-07-08 steve
+
+ * src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5XmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Relation.java: Patch to add
+ relation support and in particular for the multi polygon
+ relation.
+
+ known issues: - Areas crossing equator, poles, meridian, dataline
+ will be joined wrong. - connection between inner and outer ways.
+
+ -Rene_A
+
+2008-07-06 steve
+
+ * Makefile,
+ src/uk/me/parabola/imgfmt/app/BufferedReadStrategy.java,
+ src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/ReadStrategy.java,
+ src/uk/me/parabola/imgfmt/app/Section.java,
+ src/uk/me/parabola/imgfmt/app/WriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLHeader.java,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesHeader.java: NetDisplay
+ now looks up the number of cities and so can tell if they need
+ one or 2 bytes.
+ * Makefile,
+ src/uk/me/parabola/imgfmt/app/BufferedImgFileReader.java,
+ src/uk/me/parabola/imgfmt/app/BufferedImgFileWriter.java,
+ src/uk/me/parabola/imgfmt/app/CommonHeader.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/ImgFileReader.java,
+ src/uk/me/parabola/imgfmt/app/ImgFileWriter.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/OffsetWriter.java,
+ src/uk/me/parabola/imgfmt/app/OffsetWriterList.java,
+ src/uk/me/parabola/imgfmt/app/lbl/City.java,
+ src/uk/me/parabola/imgfmt/app/lbl/Country.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLHeader.java,
+ src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesHeader.java,
+ src/uk/me/parabola/imgfmt/app/lbl/Region.java,
+ src/uk/me/parabola/imgfmt/app/lbl/Zip.java,
+ src/uk/me/parabola/imgfmt/app/net/NETFile.java,
+ src/uk/me/parabola/imgfmt/app/net/NETHeader.java,
+ src/uk/me/parabola/imgfmt/app/net/RoadDef.java,
+ src/uk/me/parabola/imgfmt/app/net/RoadIndex.java,
+ src/uk/me/parabola/imgfmt/app/trergn/MapObject.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Overview.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Point.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Polyline.java,
+ src/uk/me/parabola/imgfmt/app/trergn/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/trergn/RGNHeader.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Zoom.java,
+ src/uk/me/parabola/imgfmt/app/typ/TYPFile.java,
+ src/uk/me/parabola/imgfmt/app/typ/TYPHeader.java: Renamed the
+ ReadStrategy and WriteStrategy interfaces and their associated
+ classes to ImgFileReader and ImgFileWriter etc
+ * src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java,
+ src/uk/me/parabola/tdbfmt/HeaderBlock.java: 1. Make overview
+ polygons completely cover the map area. 2. Read family id from
+ tdb header. 3. re-org v4 header writing.
+
+2008-07-05 steve
+
+ * src/uk/me/parabola/mkgmap/main/Main.java: Fixed --help option.
+
+2008-07-03 steve
+
+ * src/uk/me/parabola/tdbfmt/TdbFile.java: Removed unneed imports
+ * src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java,
+ src/uk/me/parabola/mkgmap/filters/PolygonSplitterFilter.java,
+ src/uk/me/parabola/mkgmap/general/LineClipper.java,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java:
+ Removed debugging prints, improved display of bounds.
+ * src/uk/me/parabola/tdbfmt/TBlock.java,
+ src/uk/me/parabola/tdbfmt/TdbFile.java: Add the crc to the T
+ block
+
+2008-07-01 steve
+
+ * Makefile, src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/imgfmt/app/Coord.java,
+ src/uk/me/parabola/mkgmap/general/LineClipper.java,
+ src/uk/me/parabola/mkgmap/general/MapLine.java,
+ src/uk/me/parabola/mkgmap/general/PolygonClipper.java,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5XmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyledConverter.java: If
+ there is a bounding box in the input file, then use that to clip
+ the output to exactly to that box.
+
+2008-06-29 steve
+
+ * src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java,
+ src/uk/me/parabola/tdbfmt/TdbFile.java: Make the family id
+ default to 0 (due to a bug it, the default was really always 0).
+ Remove v4 block from v3 TDB
+ * resources/help/en/options: Add missing options - Michael Vogt
+
+2008-06-28 steve
+
+ * src/uk/me/parabola/io/StructuredOutputStream.java,
+ src/uk/me/parabola/mkgmap/combiners/FileInfo.java,
+ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java,
+ src/uk/me/parabola/tdbfmt/DetailMapBlock.java,
+ src/uk/me/parabola/tdbfmt/HeaderBlock.java,
+ src/uk/me/parabola/tdbfmt/OverviewMapBlock.java,
+ src/uk/me/parabola/tdbfmt/RBlock.java,
+ src/uk/me/parabola/tdbfmt/TBlock.java,
+ src/uk/me/parabola/tdbfmt/TdbFile.java: Adding support for TDB
+ v4. It does not work.
+
+2008-06-23 steve
+
+ * src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java: The part field appears
+ to be just the one byte. - Johann Gail
+
+2008-06-22 steve
+
+ * src/uk/me/parabola/mkgmap/main/Main.java,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java:
+ Remove System.exit's and unused code.
+ * src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java,
+ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java,
+ src/uk/me/parabola/tdbfmt/HeaderBlock.java,
+ src/uk/me/parabola/tdbfmt/TdbFile.java: Set family id more
+ consistantly and read the TRE header more completely (whole
+ header is not needed yet, so we just do part of it).
+
+2008-06-21 steve
+
+ * src/uk/me/parabola/mkgmap/Version.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Segment.java: Segments are
+ long gone.
+ * src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java: Looks like
+ the parent needs to be properly set. (I don't see this crash
+ though) See
+ http://wiki.openstreetmap.org/index.php?title=Talk:Mkgmap&curid=4591&diff=114690&oldid=113277
+ * Makefile, src/uk/me/parabola/imgfmt/app/OffsetWriter.java,
+ src/uk/me/parabola/imgfmt/app/OffsetWriterList.java,
+ src/uk/me/parabola/imgfmt/app/map/Map.java,
+ src/uk/me/parabola/imgfmt/app/net/NETFile.java,
+ src/uk/me/parabola/imgfmt/app/net/RoadDef.java,
+ src/uk/me/parabola/imgfmt/app/net/RoadIndex.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Polyline.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java,
+ src/uk/me/parabola/mkgmap/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/build/MapBuilder.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/main/MapMaker.java: Merge in the net
+ branch. This gives the ability to add the NET section. The work
+ on the net branch was done by Elrond.
+
+2008-06-20 steve
+
+ * src/uk/me/parabola/imgfmt/app/trergn/MapValues.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java: Merge in
+ work to extend the TRE header to the 188 byte version. Somewhat
+ experimental at the moment.
+
+2008-05-24 steve
+
+ * resources/map-features.csv, resources/osm_garmin_map.csv,
+ resources/styles/default/map-features.csv: Added
+ amenity=drinking_water and natural=glacier as suggested by
+ Frédéric Bonifas.
+
+2008-05-15 steve
+
+ * src/uk/me/parabola/mkgmap/reader/osm/Osm5XmlHandler.java: Protect
+ against bad numeric data in the input file.
+
+2008-05-12 steve
+
+ * Makefile,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java: I
+ believe that the garmin is expecting that the contours are in
+ feet, so we need to convert. You can change how it displays them
+ on the Garmin with an option.
+
+2008-05-03 steve
+
+ * src/uk/me/parabola/imgfmt/app/net/NETFile.java,
+ src/uk/me/parabola/imgfmt/app/net/NETHeader.java,
+ src/uk/me/parabola/imgfmt/app/net/RoadDef.java: Little
+ improvement to NET output routines
+
+ This allows to create label-only RoadDefs in the NET file. The
+ created NET file looks good using the display tools.
+
+2008-04-28 steve
+
+ * src/uk/me/parabola/mkgmap/main/Main.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5MapDataSource.java: Make
+ --map-features a synonym for --style-file like it is meant to be.
+
+2008-04-26 steve
+
+ * ChangeLog, Makefile, build.xml, doc/Credits,
+ src/uk/me/parabola/mkgmap/Version.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java: Tidy
+ up for a release.
+ * src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesHeader.java: Add
+ StreetNames to POI
+
+ POIRecords are variable length, have optional flags for the
+ included info and are mostly straight forward. This adds the
+ optional flag writing and one optional field: The StreetName.
+
+ - Elrond
+
+2008-04-22 steve
+
+ * src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesHeader.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Point.java,
+ src/uk/me/parabola/mkgmap/build/MapBuilder.java: Basic POI
+ support
+
+ The LBL file contains a section for detailed information about
+ POIs (street, streetnumber, ZIP, phone number). These entries can
+ be linked from the Point-entries in the map subdivisions.
+
+ For now we only use the Name field in the POIRecord. The user
+ visible change is in MapSource: Most POIs now have a Property
+ context-menu entry, which shows the detailed info.
+
+ The Point-entry flag was found in qlandkarte. The rest is
+ documented in the imgformat pdf.
+
+ - Elrond
+ * src/uk/me/parabola/mkgmap/main/Main.java: Add --version option -
+ suggested by Petr Schönmann.
+
+ Only works properly with packaged versions of mkgmap, not direct
+ from svn.
+
+2008-04-20 steve
+
+ * ChangeLog, doc/mkgmap.1, resources/help/en/copyright,
+ resources/help/en/help, resources/help/en/inputs,
+ resources/help/en/links, resources/help/en/options: Improvements
+ and additional help files.
+ * resources/styles/default/info, resources/styles/test/info,
+ src/uk/me/parabola/mkgmap/gui/MainFileList.java,
+ src/uk/me/parabola/mkgmap/main/Main.java,
+ src/uk/me/parabola/mkgmap/reader/osm/CombinedStyleFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/DirectoryFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/JarFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Style.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyleFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyleInfo.java,
+ src/uk/me/parabola/mkgmap/reader/osm/WordScanner.java: Can now
+ list styles (not that there are any available yet) Added info
+ file so that a style listing can include information about the
+ style
+ * doc/Credits, doc/mkgmap.1: Add man page, written by Andreas Putzo
+ for the Debian project.
+
+2008-04-19 steve
+
+ * build.xml, src/uk/me/parabola/mkgmap/gui,
+ src/uk/me/parabola/mkgmap/gui/AppLayout.form,
+ src/uk/me/parabola/mkgmap/gui/AppLayout.java,
+ src/uk/me/parabola/mkgmap/gui/Buttons.form,
+ src/uk/me/parabola/mkgmap/gui/Buttons.java,
+ src/uk/me/parabola/mkgmap/gui/FileModel.java,
+ src/uk/me/parabola/mkgmap/gui/FileOptions.form,
+ src/uk/me/parabola/mkgmap/gui/FileOptions.java,
+ src/uk/me/parabola/mkgmap/gui/FileOptions.properties,
+ src/uk/me/parabola/mkgmap/gui/InputFile.java,
+ src/uk/me/parabola/mkgmap/gui/Main.java,
+ src/uk/me/parabola/mkgmap/gui/Main.properties,
+ src/uk/me/parabola/mkgmap/gui/MainFileList.form,
+ src/uk/me/parabola/mkgmap/gui/MainFileList.java,
+ src/uk/me/parabola/mkgmap/gui/MainFileList.properties,
+ src/uk/me/parabola/mkgmap/gui/MainFileList_en_US.properties,
+ src/uk/me/parabola/mkgmap/gui/MainFileList_no.properties,
+ src/uk/me/parabola/mkgmap/gui/Main_en_US.properties,
+ src/uk/me/parabola/mkgmap/gui/Main_no.properties,
+ src/uk/me/parabola/mkgmap/gui/package.html: gui
+ * resources/help/en/options, resources/styles/default/options,
+ src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java,
+ src/uk/me/parabola/mkgmap/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/Main.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Style.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyledConverter.java: Make
+ the --levels option available inside the style itself. Clean up
+ the help file.
+
+2008-04-13 steve
+
+ * src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Point.java: Start some
+ POIRecord support. Nothing should change in the created maps yet.
+ - Elrond
+ * src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java:
+ Let polygons get predictable garmin types
+
+ Currently, the order of tags in the input defines the result of
+ the garmin type search for a polygon. Now the type is defined by
+ the order in the map-features.csv.
+
+ This was done for polylines a while back already. - Elrond
+ * src/uk/me/parabola/mkgmap/reader/osm/CombinedStyleFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Style.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyledConverter.java: Apply
+ overrides to options from the command line.
+ * ChangeLog, Makefile, resources/help/en/help,
+ resources/help/en/options,
+ src/uk/me/parabola/mkgmap/main/Main.java: Add possibility of more
+ help files and the --help option
+ * doc/style.txt,
+ src/uk/me/parabola/imgfmt/FileNotWritableException.java,
+ src/uk/me/parabola/imgfmt/app/CommonHeader.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/Section.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/CodeFunctions.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java,
+ src/uk/me/parabola/mkgmap/combiners/FileInfo.java,
+ src/uk/me/parabola/mkgmap/filters/PolygonSizeSplitterFilter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/CombinedStyleFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Style.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyleFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/WordScanner.java: Code tidy
+ up.
+ * build.xml, src/uk/me/parabola/mkgmap/main/Main.java: Actually get
+ the option help into the archive and fix typo in message.
+ * build.xml, resources/help, resources/help/en,
+ resources/help/en/options,
+ src/uk/me/parabola/mkgmap/main/Main.java: Add an options help
+ file.
+ * doc/style.txt, resources/styles/default/map-features.csv,
+ src/uk/me/parabola/mkgmap/reader/osm/CombinedStyleFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyleFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/WordScanner.java: In
+ addition to zip file archives, add a simple single file archive
+ type. This also provides backward compatibility with the single
+ map-features.csv file.
+
+2008-04-12 steve
+
+ * ChangeLog, build.xml, doc/Credits, resources/map-features.csv,
+ resources/styles, resources/styles/default,
+ resources/styles/default/options,
+ resources/styles/default/version, resources/styles/test,
+ resources/styles/test/version,
+ src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java: Add
+ new style directory, tidy up and update. Add Credits file and
+ make build.xml copy it in.
+ * src/uk/me/parabola/mkgmap/reader/osm/Style.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyledConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/WordScanner.java: Remove
+ Scanner which is not available in GNU classpath. Once openjdk
+ becomes available in all the linux distros, then we can consider
+ using again, but it wasn't doing much good anyway.
+ * src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java:
+ Remove the usage of Scanner. It ends up looking simpler anyway.
+
+2008-04-10 steve
+
+ * src/uk/me/parabola/mkgmap/build/MapSplitter.java: Temporary fix
+ for the 'stack-overflow' problem.
+ * src/uk/me/parabola/imgfmt/app/BufferedReadStrategy.java,
+ src/uk/me/parabola/imgfmt/app/ReadStrategy.java,
+ src/uk/me/parabola/imgfmt/app/Section.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java,
+ src/uk/me/parabola/mkgmap/combiners/FileInfo.java,
+ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5MapDataSource.java: Fix
+ insertion of the copyright strings from the individual files into
+ the TDB file, a bit involved since it never worked after the
+ rewrite of the TDB creation from existing files rather than on
+ the fly.
+
+2008-04-08 steve
+
+ * resources/osm_garmin_map.csv: More map features from Elrond
+
+2008-04-07 steve
+
+ * src/uk/me/parabola/imgfmt/sys/ImgHeader.java: Use util routines
+ for string manipulation.
+
+ Clarify set description routine at the same time.
+
+2008-04-06 steve
+
+ * src/uk/me/parabola/imgfmt/sys/ImgHeader.java,
+ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java: Improve tile
+ names in MapSource: - Let ImgHeader read the Description from the
+ .img - Use that description in writing out the .tdb (Elrond)
+ * src/uk/me/parabola/mkgmap/filters/PolygonSizeSplitterFilter.java:
+ Fix to prevent width or height getting too large
+ * src/uk/me/parabola/mkgmap/reader/osm/Style.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyledConverter.java: Add
+ the ability to redifine what is used as the name tag.
+
+2008-03-31 steve
+
+ * resources/map-features.csv, resources/osm_garmin_map.csv: Add
+ living_street.
+ * src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java: Removed duplicate
+ code and made constructor public again as it is used by the
+ display branch. (Elrond)
+
+2008-03-20 steve
+
+ * Makefile,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/JarFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5XmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Style.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyleFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyledConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/package.html: More on named
+ styles.
+
+2008-03-15 steve
+
+ * src/uk/me/parabola/imgfmt/ReadFailedException.java,
+ src/uk/me/parabola/imgfmt/app/CommonHeader.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/BaseEncoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/CodeFunctions.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Format6Decoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Utf8Encoder.java,
+ src/uk/me/parabola/imgfmt/app/lbl/City.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLHeader.java,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/Region.java,
+ src/uk/me/parabola/imgfmt/app/lbl/Zip.java,
+ src/uk/me/parabola/imgfmt/app/net/NETFile.java,
+ src/uk/me/parabola/imgfmt/app/net/NETHeader.java,
+ src/uk/me/parabola/imgfmt/app/net/RoadDef.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java,
+ src/uk/me/parabola/log/Logger.java,
+ src/uk/me/parabola/mkgmap/combiners/FileInfo.java,
+ src/uk/me/parabola/mkgmap/filters/FilterConfig.java,
+ src/uk/me/parabola/mkgmap/filters/LineSizeSplitterFilter.java,
+ src/uk/me/parabola/mkgmap/filters/PolygonSizeSplitterFilter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/JarFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Style.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyleFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyledConverter.java,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java,
+ src/uk/me/parabola/tdbfmt/HeaderBlock.java: Code tidying.
+ * src/uk/me/parabola/mkgmap/reader/osm/JarFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Style.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyleFileLoader.java:
+ Styling development.
+ * resources/map-features.csv, resources/osm_garmin_map.csv:
+ Riverbank is a polygon (strangely).
+
+2008-03-05 steve
+
+ * src/uk/me/parabola/tdbfmt/EndOfFileException.java,
+ src/uk/me/parabola/tdbfmt/StructuredInputStream.java,
+ src/uk/me/parabola/tdbfmt/StructuredOutputStream.java: Files that
+ should have been removed in the last commit
+
+2008-03-04 steve
+
+ * src/uk/me/parabola/imgfmt/mps/Block.java,
+ src/uk/me/parabola/imgfmt/mps/MapBlock.java,
+ src/uk/me/parabola/imgfmt/mps/MapsetBlock.java,
+ src/uk/me/parabola/imgfmt/mps/ProductBlock.java,
+ src/uk/me/parabola/io,
+ src/uk/me/parabola/io/EndOfFileException.java,
+ src/uk/me/parabola/io/StructuredInputStream.java,
+ src/uk/me/parabola/io/StructuredOutputStream.java,
+ src/uk/me/parabola/tdbfmt/Block.java,
+ src/uk/me/parabola/tdbfmt/CopyrightBlock.java,
+ src/uk/me/parabola/tdbfmt/CopyrightSegment.java,
+ src/uk/me/parabola/tdbfmt/DetailMapBlock.java,
+ src/uk/me/parabola/tdbfmt/HeaderBlock.java,
+ src/uk/me/parabola/tdbfmt/OverviewMapBlock.java,
+ src/uk/me/parabola/tdbfmt/TdbFile.java: Fix package cycle.
+ * resources/garmin_feature_list.csv, resources/map-features.csv,
+ resources/osm_garmin_map.csv: Patch by Elrond:
+
+ - Add landuse=scrub and needed garmin feature - Add
+ sport=swimming - Add newer osm names for existing features:
+ shop=supermarket (former: amenity=supermarket) tourism=museum
+ (former: historic=museum)
+
+2008-03-03 steve
+
+ * Makefile, src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java: Fix location of flag
+ and part number in the directory entry.
+
+2008-03-02 steve
+
+ * src/uk/me/parabola/mkgmap/reader/osm/StyledConverter.java: The
+ new styled converter
+ * src/uk/me/parabola/mkgmap/reader/osm/DirectoryFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/JarFileLoader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Style.java,
+ src/uk/me/parabola/mkgmap/reader/osm/StyleFileLoader.java: A new
+ styling system to replace the existing single file one.
+ * Makefile,
+ src/uk/me/parabola/imgfmt/app/labelenc/CodeFunctions.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Utf8Decoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Utf8Encoder.java,
+ src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/mkgmap/CommandArgs.java,
+ src/uk/me/parabola/tdbfmt/OverviewMapBlock.java: work on
+ character encodings. Preparation for none 8 bit encodings.
+
+2008-02-17 steve
+
+ * Makefile,
+ src/uk/me/parabola/mkgmap/reader/osm/CodedConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Element.java,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm4MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5XmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmXmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way4.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way5.java,
+ src/uk/me/parabola/mkgmap/reader/plugin/MapReader.java: Removed
+ osm api version 0.4 code. Moved the setting of the element name
+ into the converter, currently the same code, but will allow ofr
+ more sophisticated treatment of names as required for
+ international use and special purpose maps.
+
+2008-02-16 steve
+
+ * resources/map-features.csv, resources/osm_garmin_map.csv: Applied
+ to wrong branch so merged from bigtre 540,541: --- Patch by
+ Elrond:
+
+ * Added "ground-transportation" for bus-stops, tram-stops, and
+ railway-halts * bakery is better found under grocery than under
+ xxx4 * Add landuse=village_green ---
+
+2008-02-09 steve
+
+ * Makefile,
+ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java:
+ Deal with elevation data on contours that is given in meters.
+
+2008-02-03 steve
+
+ * Makefile, src/uk/me/parabola/imgfmt/app/trergn/Polyline.java,
+ src/uk/me/parabola/mkgmap/Version.java,
+ src/uk/me/parabola/mkgmap/build/MapArea.java,
+ src/uk/me/parabola/mkgmap/combiners/FileInfo.java,
+ src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java,
+ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java,
+ src/uk/me/parabola/mkgmap/filters/RemoveEmpty.java,
+ src/uk/me/parabola/mkgmap/filters/SmoothingFilter.java,
+ src/uk/me/parabola/mkgmap/general/LoadableMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMap.java,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java,
+ test, test/README: Background and sizing fixes. Should fix
+ problem with triangular background areas and areas that don't
+ cover the tile properly.
+
+2008-01-30 steve
+
+ * src/uk/me/parabola/mkgmap/combiners/FileInfo.java,
+ src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java,
+ src/uk/me/parabola/mkgmap/main/Main.java: Fix the file merging
+ code when there is more than one FILE_KIND file with the same or
+ no mapname.
+
+2008-01-27 steve
+
+ * Makefile,
+ src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java: Don't
+ copy the MPS file, if there should be one in the input files.
+ * src/uk/me/parabola/imgfmt/mps/MapBlock.java,
+ src/uk/me/parabola/mkgmap/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java,
+ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java, test: Start
+ to allow configuration of the various parameters in the TDB etc
+ files.
+
+2008-01-26 steve
+
+ * resources/garmin_feature_list.csv, resources/osm_garmin_map.csv:
+ Just adding allotments and hostels. (Elrond)
+
+2008-01-21 steve
+
+ * Makefile,
+ src/uk/me/parabola/imgfmt/app/labelenc/CodeFunctions.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Format6Decoder.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java: Get the format
+ decoder right on reading the LBL file.
+
+2008-01-19 steve
+
+ * src/uk/me/parabola/imgfmt/app/labelenc/Format6Decoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java:
+ Decode the format-6 label format (Robx)
+ * src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java: Factor out
+ writing the section information (patch by Elrond)
+ * Makefile,
+ src/uk/me/parabola/mkgmap/filters/PolygonSizeSplitterFilter.java,
+ src/uk/me/parabola/mkgmap/general/MapCollector.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java,
+ src/uk/me/parabola/mkgmap/general/MapShape.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5XmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmXmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java:
+ Add a background polygon to the map.
+ * src/uk/me/parabola/mkgmap/combiners/FileInfo.java,
+ src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java: Sizing
+ of reserved blocks now works again after allowing for more files.
+ It is still possible for the MPS file to overflow it I guess.
+ * src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java: Wasn't
+ setting the size of the point records correctly, resulting in not
+ all points showing up in find categories. This shows that the
+ garmin devices actually take note of that field - and imgdeocde
+ doesn't.
+
+2008-01-18 steve
+
+ * src/uk/me/parabola/imgfmt/app/BufferedReadStrategy.java: Improve
+ behaviour of read when out of range of the file.
+ * src/uk/me/parabola/imgfmt/sys/FileNode.java,
+ src/uk/me/parabola/mkgmap/combiners/FileInfo.java,
+ src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java:
+ Calculate the size for the gmapsupp file including all files and
+ not just the basic three.
+
+2008-01-17 steve
+
+ * src/uk/me/parabola/imgfmt/app/labelenc/CodeFunctions.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/SimpleDecoder.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLHeader.java,
+ src/uk/me/parabola/imgfmt/app/net/NETHeader.java: net and lbl
+ changes
+ * src/uk/me/parabola/mkgmap/CommandArgs.java: Fix the default code
+ page which was always supposed to be 1252
+
+2008-01-14 steve
+
+ * Makefile,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java:
+ Look up polygons before lines. Therefore if there is a tagging
+ conflict then the one that specifies an area wins.
+
+2008-01-12 steve
+
+ * Makefile: Read files from within the img file where possible.
+
+2008-01-08 steve
+
+ * Makefile,
+ src/uk/me/parabola/imgfmt/app/labelenc/CodeFunctions.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLHeader.java,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesHeader.java,
+ src/uk/me/parabola/imgfmt/app/net/NETHeader.java,
+ src/uk/me/parabola/mkgmap/build/MapArea.java,
+ src/uk/me/parabola/mkgmap/build/MapBuilder.java: More
+ implementation of the city indexed points.
+ * src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java:
+ Allow more than one map feature to match and take the one that is
+ first in the map-features file.
+
+2008-01-06 steve
+
+ * src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/Section.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/CodeFactory.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/CodeFunctions.java,
+ src/uk/me/parabola/imgfmt/app/lbl/City.java,
+ src/uk/me/parabola/imgfmt/app/lbl/Country.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLHeader.java,
+ src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesHeader.java,
+ src/uk/me/parabola/imgfmt/app/lbl/Region.java,
+ src/uk/me/parabola/imgfmt/app/lbl/Zip.java,
+ src/uk/me/parabola/imgfmt/app/net,
+ src/uk/me/parabola/imgfmt/app/net/NETFile.java,
+ src/uk/me/parabola/imgfmt/app/net/NETHeader.java,
+ src/uk/me/parabola/imgfmt/app/net/RoadDef.java,
+ src/uk/me/parabola/imgfmt/app/net/RoadIndex.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java,
+ src/uk/me/parabola/mkgmap/Version.java: A lot of initial code for
+ cities and the NET section.
+
+2008-01-03 steve
+
+ * src/uk/me/parabola/imgfmt/app/labelenc/BaseEncoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Latin1Encoder.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/map/Map.java,
+ src/uk/me/parabola/mkgmap/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestLang10Map.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestLangMap.java,
+ src/uk/me/parabola/mkgmap/main/MapMaker.java: Add a --lower-case
+ option it may be useful for the nuvi etc.
+
+2008-01-02 steve
+
+ * resources/map-features.csv, resources/osm_garmin_map.csv: Patch
+ to add a couple of features. Submitted by Elrond.
+ * ChangeLog, Makefile,
+ src/uk/me/parabola/mkgmap/ArgumentProcessor.java,
+ src/uk/me/parabola/tdbfmt/HeaderBlock.java: Update changelog
+ makefile add javadoc comment, etc
+
+2008-01-01 steve
+
+ * src/uk/me/parabola/imgfmt/app/Section.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/CodeFactory.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/CodeFunctions.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/SimpleDecoder.java,
+ src/uk/me/parabola/imgfmt/app/lbl/City.java,
+ src/uk/me/parabola/imgfmt/app/lbl/Country.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLHeader.java,
+ src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/PlacesHeader.java,
+ src/uk/me/parabola/imgfmt/app/lbl/Region.java,
+ src/uk/me/parabola/imgfmt/app/lbl/Zip.java: Re-wrote the label
+ section to allow the addition of the city,region,country,zip,poi
+ sections.
+
+2007-12-28 steve
+
+ * test: MDX file displayer. I don't really know what this does so
+ don't trust this too much. Appears to be another file containing
+ a list of the maps in a set.
+
+ As the file gets installed at the family level, it could be
+ family wide though.
+ * doc/Zoom, src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLHeader.java: Add a doc file
+ Fix previous merge of label read changes that didn't compile.
+ * test/java: All this has been moved to a separate repo.
+ * src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/CharacterDecoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/SimpleDecoder.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLHeader.java: Changes for
+ reading the LBL file.
+ * src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/ShapeStacking.java,
+ src/uk/me/parabola/imgfmt/app/TYPFile.java,
+ src/uk/me/parabola/imgfmt/app/TYPHeader.java: These should have
+ been removed in the last commit.
+ * src/uk/me/parabola/imgfmt/app/BufferedReadStrategy.java,
+ src/uk/me/parabola/imgfmt/app/CommonHeader.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/InternalFiles.java,
+ src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/LBLHeader.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/LinePreparer.java,
+ src/uk/me/parabola/imgfmt/app/MapObject.java,
+ src/uk/me/parabola/imgfmt/app/Overview.java,
+ src/uk/me/parabola/imgfmt/app/Point.java,
+ src/uk/me/parabola/imgfmt/app/PointOverview.java,
+ src/uk/me/parabola/imgfmt/app/Polygon.java,
+ src/uk/me/parabola/imgfmt/app/PolygonOverview.java,
+ src/uk/me/parabola/imgfmt/app/Polyline.java,
+ src/uk/me/parabola/imgfmt/app/PolylineOverview.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/RGNHeader.java,
+ src/uk/me/parabola/imgfmt/app/Section.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/TREHeader.java,
+ src/uk/me/parabola/imgfmt/app/Zoom.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/AnyCharsetEncoder.java,
+ src/uk/me/parabola/imgfmt/app/lbl,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/lbl/LBLHeader.java,
+ src/uk/me/parabola/imgfmt/app/lbl/package.html,
+ src/uk/me/parabola/imgfmt/app/map,
+ src/uk/me/parabola/imgfmt/app/map/Map.java,
+ src/uk/me/parabola/imgfmt/app/map/package.html,
+ src/uk/me/parabola/imgfmt/app/package.html,
+ src/uk/me/parabola/imgfmt/app/trergn,
+ src/uk/me/parabola/imgfmt/app/trergn/InternalFiles.java,
+ src/uk/me/parabola/imgfmt/app/trergn/LinePreparer.java,
+ src/uk/me/parabola/imgfmt/app/trergn/MapObject.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Overview.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Point.java,
+ src/uk/me/parabola/imgfmt/app/trergn/PointOverview.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Polygon.java,
+ src/uk/me/parabola/imgfmt/app/trergn/PolygonOverview.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Polyline.java,
+ src/uk/me/parabola/imgfmt/app/trergn/PolylineOverview.java,
+ src/uk/me/parabola/imgfmt/app/trergn/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/trergn/RGNHeader.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java,
+ src/uk/me/parabola/imgfmt/app/trergn/Zoom.java,
+ src/uk/me/parabola/imgfmt/app/trergn/package.html,
+ src/uk/me/parabola/imgfmt/app/typ,
+ src/uk/me/parabola/imgfmt/app/typ/ShapeStacking.java,
+ src/uk/me/parabola/imgfmt/app/typ/TYPFile.java,
+ src/uk/me/parabola/imgfmt/app/typ/TYPHeader.java,
+ src/uk/me/parabola/imgfmt/app/typ/package.html,
+ src/uk/me/parabola/imgfmt/mps/Block.java,
+ src/uk/me/parabola/imgfmt/mps/MpsFile.java,
+ src/uk/me/parabola/mkgmap/build/MapArea.java,
+ src/uk/me/parabola/mkgmap/build/MapBuilder.java,
+ src/uk/me/parabola/mkgmap/build/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/combiners/FileInfo.java,
+ src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java,
+ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java,
+ src/uk/me/parabola/mkgmap/general/MapDataSource.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java,
+ src/uk/me/parabola/mkgmap/main/AbstractTestMap.java,
+ src/uk/me/parabola/mkgmap/main/Main.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestLang10Map.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestLangMap.java,
+ src/uk/me/parabola/mkgmap/main/MapMaker.java,
+ src/uk/me/parabola/mkgmap/reader/MapperBasedMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java,
+ test: Complete re-arrangement of files under the app package as
+ it is already quite large and more files will be added here soon.
+
+2007-12-21 steve
+
+ * ., src/uk/me/parabola/imgfmt/app/Section.java,
+ src/uk/me/parabola/imgfmt/app/ShapeStacking.java,
+ src/uk/me/parabola/imgfmt/app/TREHeader.java,
+ src/uk/me/parabola/imgfmt/app/TYPFile.java,
+ src/uk/me/parabola/imgfmt/app/TYPHeader.java,
+ src/uk/me/parabola/imgfmt/sys/FileImgChannel.java,
+ src/uk/me/parabola/mkgmap/reader/test/AllElements.java,
+ test/java/test/TypTest.java, test/java/test/display,
+ test/java/test/display/DisplayItem.java,
+ test/java/test/display/Displayer.java,
+ test/java/test/display/LineSectDisplayer.java,
+ test/java/test/display/MpsDisplay.java,
+ test/java/test/display/PointDisplayer.java,
+ test/java/test/display/PolygonDisplayer.java,
+ test/java/test/display/StackingDisplayer.java,
+ test/java/test/display/TypDisplay.java: Merged revisions
+ 474-480,482-485,487,489-505 via svnmerge from
+ https://svn.parabola.me.uk/svn/mkgmap/branches/typfile
+
+ ........ r474 | steve | 2007-12-15 14:07:00 +0000 (Sat, 15 Dec
+ 2007) | 2 lines Print out the header and the fields we think are
+ pointers and sizes. This should lead to finding the other
+ pointers. ........ r475 | steve | 2007-12-15 14:48:46 +0000 (Sat,
+ 15 Dec 2007) | 1 line analyse the sections found, print gaps
+ between them and size fields found and speculated. ........ r476
+ | steve | 2007-12-15 15:06:16 +0000 (Sat, 15 Dec 2007) | 1 line
+ Appears to be another section, and probably another to be
+ discovered. ........ r477 | steve | 2007-12-15 15:16:54 +0000
+ (Sat, 15 Dec 2007) | 1 line Better printing of body lines.
+ ........ r478 | steve | 2007-12-15 15:49:51 +0000 (Sat, 15 Dec
+ 2007) | 2 lines Fixed bug that was hiding section sizes. Have
+ probably got sect 5 and 6 lengths now. ........ r479 | steve |
+ 2007-12-15 16:05:10 +0000 (Sat, 15 Dec 2007) | 1 line More
+ possible sizes ........ r480 | steve | 2007-12-15 18:54:40 +0000
+ (Sat, 15 Dec 2007) | 2 lines Fixed bug not showing gaps between
+ some known values. Looks like the header is decoded fully as far
+ as sections goes as there is not room for any more. ........ r482
+ | steve | 2007-12-15 20:07:22 +0000 (Sat, 15 Dec 2007) | 2 lines
+ Added sections discovered into the TYP header read/write
+ functions. Verified that what is read is written and can be read
+ again. ........ r483 | steve | 2007-12-15 22:59:55 +0000 (Sat, 15
+ Dec 2007) | 1 line Most of the unknowns are certainly item sizes
+ like in the TRE file, so add them. ........ r484 | steve |
+ 2007-12-16 15:28:12 +0000 (Sun, 16 Dec 2007) | 1 line TYP file
+ displayer ........ r485 | steve | 2007-12-16 15:53:59 +0000 (Sun,
+ 16 Dec 2007) | 1 line Some name changes. ........ r487 | steve |
+ 2007-12-16 18:12:22 +0000 (Sun, 16 Dec 2007) | 1 line Initial
+ printing of the line sections. still lots is unknown. ........
+ r493 | steve | 2007-12-16 21:55:09 +0000 (Sun, 16 Dec 2007) | 2
+ lines Should have been removed in a rename before ........ r494 |
+ steve | 2007-12-16 22:39:01 +0000 (Sun, 16 Dec 2007) | 1 line Add
+ the stacking order section. Fixes and documentation. ........
+ r495 | steve | 2007-12-18 12:28:20 +0000 (Tue, 18 Dec 2007) | 1
+ line Print out the mps file. ........ r496 | steve | 2007-12-18
+ 13:55:59 +0000 (Tue, 18 Dec 2007) | 1 line Better printing of
+ line styles ........ r497 | steve | 2007-12-18 16:33:56 +0000
+ (Tue, 18 Dec 2007) | 1 line Make sense of flags ending with 01
+ ........ r498 | steve | 2007-12-18 16:34:57 +0000 (Tue, 18 Dec
+ 2007) | 1 line write out a copy of each file. ........ r499 |
+ steve | 2007-12-18 16:35:24 +0000 (Tue, 18 Dec 2007) | 1 line
+ make a horizontal component of lines. ........ r500 | steve |
+ 2007-12-19 09:14:27 +0000 (Wed, 19 Dec 2007) | 2 lines Add
+ classes for points and polygons (these may be the wrong way
+ round). ........ r501 | steve | 2007-12-19 09:15:00 +0000 (Wed,
+ 19 Dec 2007) | 1 line reword in comment ........
+
+2007-12-20 steve
+
+ * src/uk/me/parabola/imgfmt/mps/Block.java,
+ src/uk/me/parabola/imgfmt/mps/MapBlock.java,
+ src/uk/me/parabola/imgfmt/mps/MapsetBlock.java,
+ src/uk/me/parabola/imgfmt/mps/MpsFile.java,
+ src/uk/me/parabola/imgfmt/mps/ProductBlock.java,
+ src/uk/me/parabola/mkgmap/combiners/FileInfo.java,
+ src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java,
+ src/uk/me/parabola/tdbfmt/StructuredOutputStream.java: MPS file
+ working at a first glance.
+ * src/uk/me/parabola/imgfmt/mps/Block.java,
+ src/uk/me/parabola/imgfmt/mps/MapBlock.java,
+ src/uk/me/parabola/imgfmt/mps/MapsetBlock.java,
+ src/uk/me/parabola/imgfmt/mps/MpsFile.java,
+ src/uk/me/parabola/imgfmt/mps/ProductBlock.java,
+ src/uk/me/parabola/tdbfmt/StructuredOutputStream.java: Most of
+ the MPS file implemented.
+
+2007-12-19 steve
+
+ * test/java/test/CopyFile.java: Re-instate creating real files from
+ the internal files.
+ * src/uk/me/parabola/imgfmt/mps,
+ src/uk/me/parabola/imgfmt/mps/Block.java,
+ src/uk/me/parabola/imgfmt/mps/MapBlock.java,
+ src/uk/me/parabola/imgfmt/mps/MapsetBlock.java,
+ src/uk/me/parabola/imgfmt/mps/MpsFile.java,
+ src/uk/me/parabola/imgfmt/mps/ProductBlock.java,
+ src/uk/me/parabola/imgfmt/mps/package.html: Add MPS file skeleton
+
+2007-12-16 steve
+
+ * src/uk/me/parabola/mkgmap/CommandArgs.java: Remove redundant
+ initialiser. Forgot to mention in the previous commit that the
+ idea for naming after the input files was requested by
+ Computerteddy.
+ * Makefile, src/uk/me/parabola/mkgmap/CommandArgs.java: If the
+ input file name contains an 8 digit number (in the file name
+ part) then use that as the mapname, unless an explicit name has
+ been specifited.
+
+ If there are a mixture of files that are numbers and not, then it
+ is always possible that you will get conflicts.
+ * ., src/uk/me/parabola/imgfmt/app/BufferedReadStrategy.java,
+ src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/sys/FileImgChannel.java: Merged
+ revisions 481,486,488 via svnmerge from
+ https://svn.parabola.me.uk/svn/mkgmap/branches/typfile
+
+ ........ r481 | steve | 2007-12-15 19:58:34 +0000 (Sat, 15 Dec
+ 2007) | 1 line Reading of ints were being cast to char! ........
+ r486 | steve | 2007-12-16 16:41:10 +0000 (Sun, 16 Dec 2007) | 1
+ line Fix for the file img channel not really seeking. ........
+ r488 | steve | 2007-12-16 18:13:08 +0000 (Sun, 16 Dec 2007) | 1
+ line Make sure there is enough room in the buffer on put3
+ operations ........
+ * .: Initialized merge tracking via "svnmerge" with revisions
+ "1-473" from
+ https://svn.parabola.me.uk/svn/mkgmap/branches/typfile
+
+2007-12-15 steve
+
+ * src/uk/me/parabola/imgfmt/sys/FileImgChannel.java,
+ src/uk/me/parabola/mkgmap/combiners/FileInfo.java,
+ src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java,
+ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java: Allow more
+ than .img files on the command line when combining. Other file
+ types will be treated as appropriate to the operation being
+ performed.
+ * src/uk/me/parabola/imgfmt/app/CommonHeader.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java: General consistency
+ changes.
+ * ChangeLog, Makefile, src/uk/me/parabola/imgfmt/app/TYPFile.java,
+ src/uk/me/parabola/imgfmt/app/TYPHeader.java,
+ test/java/test/TypTest.java: Test decoding program for the TYP
+ file.
+
+2007-12-14 steve
+
+ * .: Removed merge tracking for "svnmerge" for
+ https://svn.parabola.me.uk/svn/mkgmap/branches/imgread
+ * src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/main/FileInfo.java: These should have
+ been removed as part of the change to remove package cycles.
+ * ., Makefile, src/uk/me/parabola/imgfmt/ReadFailedException.java,
+ src/uk/me/parabola/imgfmt/Utils.java,
+ src/uk/me/parabola/imgfmt/app/BufferedReadStrategy.java,
+ src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/CommonHeader.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/LBLHeader.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/MapObject.java,
+ src/uk/me/parabola/imgfmt/app/Overview.java,
+ src/uk/me/parabola/imgfmt/app/Point.java,
+ src/uk/me/parabola/imgfmt/app/Polyline.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/RGNHeader.java,
+ src/uk/me/parabola/imgfmt/app/ReadStrategy.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/TREHeader.java,
+ src/uk/me/parabola/imgfmt/app/TYPFile.java,
+ src/uk/me/parabola/imgfmt/app/TYPHeader.java,
+ src/uk/me/parabola/imgfmt/app/WriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/Zoom.java,
+ src/uk/me/parabola/imgfmt/sys/FileNode.java: Merged revisions
+ 456-465 via svnmerge from
+ https://svn.parabola.me.uk/svn/mkgmap/branches/imgread
+
+ ........ r457 | steve | 2007-12-14 13:43:42 +0000 (Fri, 14 Dec
+ 2007) | 7 lines NON-COMPILING Prepare to factor out the headers
+ from the file definitions. CommonHeader created and the TREHeader
+ that extends from that. ImgFile will not be used for reading and
+ writing directly, but will have reader and writer streams, which
+ will be implemented separately. ........ r458 | steve |
+ 2007-12-14 14:27:32 +0000 (Fri, 14 Dec 2007) | 2 lines Separate
+ out the reader and writer in the ImgFile and add the header
+ there. Compiles, but will not work. ........ r459 | steve |
+ 2007-12-14 15:17:35 +0000 (Fri, 14 Dec 2007) | 1 line Took all
+ the read/write methods off ImgFile and made everything use the
+ reader/writer. ........ r460 | steve | 2007-12-14 15:22:35 +0000
+ (Fri, 14 Dec 2007) | 1 line The RGN file and header now complete
+ and may work. ........ r461 | steve | 2007-12-14 17:52:03 +0000
+ (Fri, 14 Dec 2007) | 1 line Bug fixed and working. Verified same
+ results over a set of UK tiles. ........ r462 | steve |
+ 2007-12-14 18:02:42 +0000 (Fri, 14 Dec 2007) | 1 line Code tidy
+ ........ r464 | steve | 2007-12-14 18:32:55 +0000 (Fri, 14 Dec
+ 2007) | 1 line Made the TRE header a bit neater by reducing the
+ number of separate fields. ........
+ * src/uk/me/parabola/imgfmt/Utils.java,
+ src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/imgfmt/app/MapReader.java,
+ src/uk/me/parabola/mkgmap/ArgumentProcessor.java,
+ src/uk/me/parabola/mkgmap/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/build/MapArea.java,
+ src/uk/me/parabola/mkgmap/build/MapBuilder.java,
+ src/uk/me/parabola/mkgmap/build/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/combiners/Combiner.java,
+ src/uk/me/parabola/mkgmap/combiners/FileInfo.java,
+ src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java,
+ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java,
+ src/uk/me/parabola/mkgmap/main/ArgumentProcessor.java,
+ src/uk/me/parabola/mkgmap/main/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/Main.java,
+ src/uk/me/parabola/mkgmap/main/MapMaker.java,
+ src/uk/me/parabola/mkgmap/main/MapProcessor.java: Move classes
+ around to avoid pakcage cycles. Removed unused class.
+ * src/uk/me/parabola/mkgmap/general/MapDetails.java,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java:
+ Removed unused or duplicate methods.
+ * .: Initialized merge tracking via "svnmerge" with revisions
+ "1-455" from
+ https://svn.parabola.me.uk/svn/mkgmap/branches/imgread
+ * .: Removed merge tracking for "svnmerge" for
+ https://svn.parabola.me.uk/svn/mkgmap/branches/gmapsupp
+ https://svn.parabola.me.uk/svn/mkgmap/branches/filter
+ https://svn.parabola.me.uk/svn/mkgmap/branches/lang
+ * ChangeLog: updated changelog
+
+2007-12-12 steve
+
+ * Makefile, src/uk/me/parabola/imgfmt/sys/ImgHeader.java: Fix for
+ not loading in map source. Increase the number in the header to
+ increase the size of the 'file system'
+ * Makefile, src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java: Moved the line
+ size splitting so that it is nearby the polygon splitting.
+ * Makefile, src/uk/me/parabola/imgfmt/Utils.java,
+ src/uk/me/parabola/mkgmap/main/FileInfo.java,
+ src/uk/me/parabola/mkgmap/main/Main.java: removed debugging
+ statements
+ * ., Makefile, src/uk/me/parabola/imgfmt/Utils.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/MapReader.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/fs/DirectoryEntry.java,
+ src/uk/me/parabola/imgfmt/fs/FileSystem.java,
+ src/uk/me/parabola/imgfmt/sys/ImgFS.java,
+ src/uk/me/parabola/mkgmap/combiners,
+ src/uk/me/parabola/mkgmap/combiners/Combiner.java,
+ src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java,
+ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java,
+ src/uk/me/parabola/mkgmap/main/ArgumentProcessor.java,
+ src/uk/me/parabola/mkgmap/main/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/FileInfo.java,
+ src/uk/me/parabola/mkgmap/main/FilenameProcessor.java,
+ src/uk/me/parabola/mkgmap/main/GmapsuppBuilder.java,
+ src/uk/me/parabola/mkgmap/main/Main.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MapEventListener.java,
+ src/uk/me/parabola/mkgmap/main/MapMaker.java,
+ src/uk/me/parabola/mkgmap/main/MapProcessor.java,
+ src/uk/me/parabola/mkgmap/main/OverviewMapBuilder.java,
+ src/uk/me/parabola/mkgmap/main/package.html,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMap.java,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java:
+ Merged revisions 388-447 via svnmerge from
+ https://svn.parabola.me.uk/svn/mkgmap/branches/gmapsupp
+
+ ................ r410 | steve | 2007-12-03 23:02:33 +0000 (Mon,
+ 03 Dec 2007) | 2 lines Progressing with adding .img files to the
+ gmapsupp. Need to create a structure with just file sizes in I
+ think as that is all we actually use. ................ r411 |
+ steve | 2007-12-04 17:31:28 +0000 (Tue, 04 Dec 2007) | 3 lines
+ Before when we couldn't read .img files, there was a need for a
+ complex system to hook all the summarising functions into the
+ main map making process. We don't need to do this any more. We
+ are just going to reprocess the filenames, including any created
+ files. ................ r412 | steve | 2007-12-04 17:34:49 +0000
+ (Tue, 04 Dec 2007) | 9 lines Merged revisions 404 via svnmerge
+ from https://svn.parabola.me.uk/svn/mkgmap/trunk ........ r404 |
+ steve | 2007-12-03 12:11:46 +0000 (Mon, 03 Dec 2007) | 2 lines
+ Change to be compatible with java-5 ........ ................
+ r413 | steve | 2007-12-04 18:02:01 +0000 (Tue, 04 Dec 2007) | 1
+ line Get the output filenames from the map making process.
+ ................ r414 | steve | 2007-12-04 18:03:10 +0000 (Tue,
+ 04 Dec 2007) | 9 lines Merged revisions 373 via svnmerge from
+ https://svn.parabola.me.uk/svn/mkgmap/trunk ........ r373 | steve
+ | 2007-11-15 00:53:07 +0000 (Thu, 15 Nov 2007) | 1 line Remove
+ call to constructor that is not in 1.5 ........ ................
+ r415 | steve | 2007-12-04 18:06:57 +0000 (Tue, 04 Dec 2007) | 1
+ line Move the overview builders into a new package.
+ ................ r416 | steve | 2007-12-04 20:50:06 +0000 (Tue,
+ 04 Dec 2007) | 2 lines Begin on separate reading of img file to
+ combine them. This is going to be a bigger task than I thought as
+ we need to read more of the files than I thought and we should
+ probably introduce file header classes for TRE etc.
+ ................ r418 | steve | 2007-12-05 21:24:26 +0000 (Wed,
+ 05 Dec 2007) | 1 line got the bounds from the TRE section.
+ ................ r419 | steve | 2007-12-05 21:28:39 +0000 (Wed,
+ 05 Dec 2007) | 1 line Add close method. ................ r420 |
+ steve | 2007-12-05 21:29:16 +0000 (Wed, 05 Dec 2007) | 1 line
+ Renamed formal param. ................ r442 | steve | 2007-12-09
+ 23:40:45 +0000 (Sun, 09 Dec 2007) | 1 line Half way working for
+ the gmapsupp case. Looks like there is an off by one in the
+ header dir space calc. ................ r443 | steve | 2007-12-10
+ 22:45:36 +0000 (Mon, 10 Dec 2007) | 1 line Fixed the off by one
+ error, caused by needing to round up. ................ r444 |
+ steve | 2007-12-10 22:53:16 +0000 (Mon, 10 Dec 2007) | 1 line Add
+ the tdb and overview map combiners. ................ r447 | steve
+ | 2007-12-12 14:33:31 +0000 (Wed, 12 Dec 2007) | 1 line Working
+ TDB and overview map generation. ................
+ * src/uk/me/parabola/mkgmap/Version.java: Get version file from the
+ root directory in the classpath.
+ * Makefile, src/uk/me/parabola/mkgmap/Version.java,
+ src/uk/me/parabola/mkgmap/build/MapBuilder.java: Add version
+ stamping of the resulting maps.
+
+2007-12-09 steve
+
+ * .: ignored files.
+ * Makefile,
+ src/uk/me/parabola/imgfmt/FileNotWritableException.java,
+ src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/AnyCharsetEncoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java,
+ src/uk/me/parabola/imgfmt/sys/ImgFS.java,
+ src/uk/me/parabola/mkgmap/filters/FilterConfig.java,
+ src/uk/me/parabola/mkgmap/filters/MapFilterChain.java,
+ src/uk/me/parabola/mkgmap/filters/PolygonSplitterBase.java,
+ src/uk/me/parabola/mkgmap/filters/SmoothingFilter.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java,
+ src/uk/me/parabola/mkgmap/main/GmapsuppBuilder.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmXmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way5.java,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/test/TestPoints.java,
+ src/uk/me/parabola/tdbfmt/CopyrightBlock.java: Code tidy up.
+ * src/uk/me/parabola/mkgmap/filters/PolygonSplitterBase.java,
+ src/uk/me/parabola/mkgmap/filters/SmoothingFilter.java: Remove
+ unsed code.
+ * src/uk/me/parabola/mkgmap/filters/PolygonSizeSplitterFilter.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java: Polygon splitting
+ code changes.
+ * src/uk/me/parabola/mkgmap/build/MapBuilder.java,
+ src/uk/me/parabola/mkgmap/build/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/filters/FilterConfig.java: Change to
+ use setResolution on filter config.
+ * src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/general/MapLine.java: Make getLocation
+ public
+ * src/uk/me/parabola/imgfmt/app/Area.java: Add contains methods
+ * src/uk/me/parabola/mkgmap/main/MakeMap.java: Narrow scope of a
+ couple of variables
+ * Makefile, src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/mkgmap/build/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java: Moved the polygon
+ size filtering code to where a level is initially created.
+
+2007-12-08 steve
+
+ * src/uk/me/parabola/mkgmap/filters/PolygonSplitterBase.java:
+ Remove name changing code.
+ * Makefile, src/uk/me/parabola/imgfmt/app/LinePreparer.java,
+ src/uk/me/parabola/mkgmap/build/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/filters/PolygonSizeSplitterFilter.java,
+ src/uk/me/parabola/mkgmap/filters/PolygonSplitterBase.java: Bug
+ in determining the number of bits for the deltas. Showed up in
+ the polygon splitting, but nothing to do with that splitting
+ specifically.
+
+2007-12-07 steve
+
+ * src/uk/me/parabola/mkgmap/filters/PolygonSizeSplitterFilter.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java: The polygons
+ were not being split based on the resolution, which meant that
+ the overview map polygons were being split inappropriately.
+
+ Move split to the correct place.
+
+ The line splitting should be moved here too.
+
+2007-12-06 steve
+
+ * src/uk/me/parabola/mkgmap/general/MapDetails.java: Remove println
+ * Makefile,
+ src/uk/me/parabola/mkgmap/filters/PolygonSizeSplitterFilter.java,
+ src/uk/me/parabola/mkgmap/filters/PolygonSplitterBase.java,
+ src/uk/me/parabola/mkgmap/filters/PolygonSplitterFilter.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java: Split polygons
+ for size as well as number of points. The splitting is improved
+ too I think.
+ * ChangeLog: Update changelog
+ * Makefile, src/uk/me/parabola/mkgmap/filters/SmoothingFilter.java:
+ Tone down the smoothing a lot as it was way over the top.
+ * ., src/uk/me/parabola/mkgmap/filters/LineSizeSplitterFilter.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java: Merged
+ revisions 424 via svnmerge from
+ https://svn.parabola.me.uk/svn/mkgmap/branches/filters
+
+ ........ r424 | steve | 2007-12-06 21:09:28 +0000 (Thu, 06 Dec
+ 2007) | 1 line Trivial bug where I was subtracting max-max not
+ max-min ........
+
+2007-12-05 steve
+
+ * ., src/uk/me/parabola/mkgmap/filters/LineSizeSplitterFilter.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java: Merged
+ revisions 417-422 via svnmerge from
+ https://svn.parabola.me.uk/svn/mkgmap/branches/filters
+
+ ........ r421 | steve | 2007-12-05 23:34:24 +0000 (Wed, 05 Dec
+ 2007) | 1 line Split lines that are too big in the sense of size,
+ rather than too many points. ........ r422 | steve | 2007-12-05
+ 23:35:34 +0000 (Wed, 05 Dec 2007) | 1 line remove debugging
+ ........
+
+2007-12-04 steve
+
+ * ., Makefile, src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/mkgmap/build,
+ src/uk/me/parabola/mkgmap/build/LayerFilterChain.java,
+ src/uk/me/parabola/mkgmap/build/MapBuilder.java,
+ src/uk/me/parabola/mkgmap/build/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/build/package.html,
+ src/uk/me/parabola/mkgmap/filters,
+ src/uk/me/parabola/mkgmap/filters/BaseFilter.java,
+ src/uk/me/parabola/mkgmap/filters/FilterConfig.java,
+ src/uk/me/parabola/mkgmap/filters/LineSplitterFilter.java,
+ src/uk/me/parabola/mkgmap/filters/MapFilter.java,
+ src/uk/me/parabola/mkgmap/filters/MapFilterChain.java,
+ src/uk/me/parabola/mkgmap/filters/PolygonSplitterFilter.java,
+ src/uk/me/parabola/mkgmap/filters/RemoveEmpty.java,
+ src/uk/me/parabola/mkgmap/filters/SmoothingFilter.java,
+ src/uk/me/parabola/mkgmap/filters/package.html,
+ src/uk/me/parabola/mkgmap/general/MapBuilder.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/general/MapLine.java,
+ src/uk/me/parabola/mkgmap/general/MapShape.java,
+ src/uk/me/parabola/mkgmap/general/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/OverviewMapBuilder.java: Merged
+ revisions 391-416 via svnmerge from
+ https://svn.parabola.me.uk/svn/mkgmap/branches/filters
+
+ ........ r391 | steve | 2007-12-01 17:22:34 +0000 (Sat, 01 Dec
+ 2007) | 1 line Broke out the splitting of lines a little.
+ ........ r392 | steve | 2007-12-01 17:28:23 +0000 (Sat, 01 Dec
+ 2007) | 1 line Remove the inline line splitting code. ........
+ r393 | steve | 2007-12-01 20:29:03 +0000 (Sat, 01 Dec 2007) | 1
+ line Create filter infrastructure. ........ r394 | steve |
+ 2007-12-02 14:35:27 +0000 (Sun, 02 Dec 2007) | 2 lines A working
+ implementation, although there is more to break out into filters
+ and then we need to add some more functionality. ........ r395 |
+ steve | 2007-12-02 22:12:43 +0000 (Sun, 02 Dec 2007) | 1 line
+ rename filter chain ........ r396 | steve | 2007-12-02 22:13:25
+ +0000 (Sun, 02 Dec 2007) | 1 line rename line splitting filter
+ ........ r397 | steve | 2007-12-03 09:00:24 +0000 (Mon, 03 Dec
+ 2007) | 1 line rename line splitting filter, add polygon splitter
+ ........ r398 | steve | 2007-12-03 10:28:16 +0000 (Mon, 03 Dec
+ 2007) | 1 line Make sure that lines are always copied before
+ changing their points as this would change them for all levels.
+ ........ r399 | steve | 2007-12-03 10:29:17 +0000 (Mon, 03 Dec
+ 2007) | 1 line Add the copy constructors to the MapShape class
+ too. ........ r400 | steve | 2007-12-03 11:03:36 +0000 (Mon, 03
+ Dec 2007) | 1 line Add filtering for polygons and only add the
+ line filter for lines and the polygon filters for polygons...
+ ........ r401 | steve | 2007-12-03 11:22:18 +0000 (Mon, 03 Dec
+ 2007) | 1 line Some tidying ........ r402 | steve | 2007-12-03
+ 12:07:22 +0000 (Mon, 03 Dec 2007) | 1 line Split out files from
+ the general package that do the actual general-->garmin
+ conversion. ........ r405 | steve | 2007-12-03 17:23:48 +0000
+ (Mon, 03 Dec 2007) | 1 line Useful amount of smothing applied.
+ ........ r406 | steve | 2007-12-03 20:58:29 +0000 (Mon, 03 Dec
+ 2007) | 1 line Fix where was not returning after chaining the
+ filter. ........ r407 | steve | 2007-12-03 20:59:07 +0000 (Mon,
+ 03 Dec 2007) | 1 line Now we have a polygon splitter. Polygons
+ that have too many points will be split. ........ r408 | steve |
+ 2007-12-03 21:16:07 +0000 (Mon, 03 Dec 2007) | 2 lines Remove
+ println's ........ r409 | steve | 2007-12-03 21:23:57 +0000 (Mon,
+ 03 Dec 2007) | 1 line Now that the smoothing is in a filter,
+ remove the old code to remove duplicate points. ........
+
+2007-12-03 steve
+
+ * src/uk/me/parabola/imgfmt/app/labelenc/AnyCharsetEncoder.java:
+ Change to be compatible with java-5
+ * .: Initialized merge tracking via "svnmerge" with revisions
+ "1-389" from
+ https://svn.parabola.me.uk/svn/mkgmap/branches/filters
+
+2007-11-24 steve
+
+ * ., Makefile, src/uk/me/parabola/imgfmt/sys/BlockManager.java,
+ src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/imgfmt/sys/package.html,
+ src/uk/me/parabola/mkgmap/main/FileInfo.java,
+ src/uk/me/parabola/mkgmap/main/GmapsuppBuilder.java,
+ src/uk/me/parabola/mkgmap/main/Main.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MapEventListener.java,
+ src/uk/me/parabola/mkgmap/main/MapEvents.java,
+ src/uk/me/parabola/mkgmap/main/MapProcessor.java,
+ src/uk/me/parabola/mkgmap/main/OverviewMapBuilder.java,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java:
+ Merged revisions 371-377,379-384,386-387 via svnmerge from
+ https://svn.parabola.me.uk/svn/mkgmap/branches/gmapsupp
+
+ ........ r371 | steve | 2007-11-15 00:21:24 +0000 (Thu, 15 Nov
+ 2007) | 2 lines Allow several different listeners to be added to
+ the map making processes. One will be the overview map as before,
+ and we need to keep track of input files for the gmapsupp too.
+ ........ r377 | steve | 2007-11-15 10:06:37 +0000 (Thu, 15 Nov
+ 2007) | 2 lines Part of the rename ........ r379 | steve |
+ 2007-11-15 12:36:38 +0000 (Thu, 15 Nov 2007) | 1 line Its clear
+ how the skeleton of the implementation is going to play out now.
+ ........ r380 | steve | 2007-11-15 15:43:36 +0000 (Thu, 15 Nov
+ 2007) | 3 lines The first working gmapsupp.img file produced. It
+ does not have an overview map or an TDB but that doesn't actually
+ seem to matter and it works find on my garmin device. In fact you
+ are probably not supposed to put the TDB and the overview in
+ there? Is it just for mapsource? ........ r381 | steve |
+ 2007-11-15 16:39:17 +0000 (Thu, 15 Nov 2007) | 3 lines Use linked
+ hash map for predictible ordering of the maps in the output.
+ Break up a deeply nested routine a bit. ........ r383 | steve |
+ 2007-11-17 11:45:06 +0000 (Sat, 17 Nov 2007) | 1 line FIx some
+ problems with the header. ........ r384 | steve | 2007-11-17
+ 14:54:26 +0000 (Sat, 17 Nov 2007) | 2 lines Update to new
+ location of tests. ........
+
+2007-11-23 steve
+
+ * ., Makefile,
+ src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java:
+ Merged revisions 385 via svnmerge from
+ https://svn.parabola.me.uk/svn/mkgmap/branches/gmapsupp
+
+ ........ r385 | steve | 2007-11-22 20:59:42 +0000 (Thu, 22 Nov
+ 2007) | 1 line Upper case the strings read in from the
+ translitteration tables. Else if you have Ch for example, then
+ the 'h' does not show up. ........
+ * .: Initialized merge tracking via "svnmerge" with revisions
+ "1-369" from
+ https://svn.parabola.me.uk/svn/mkgmap/branches/gmapsupp
+
+2007-11-15 steve
+
+ * build.xml: Copy the doc to the distribution directory.
+ * src/uk/me/parabola/mkgmap/main/MakeTestLang10Map.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestLangMap.java: Fix calls to
+ PolylineOverview() constructor, note that these files probably
+ don't work any longer anyway.
+ * src/uk/me/parabola/mkgmap/reader/plugin/MapperBasedMapDataSource.java:
+ This should have been removed in the previous commit
+ * src/uk/me/parabola/mkgmap/reader/MapperBasedMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java:
+ Get rid of package dependancy cycle
+ * src/uk/me/parabola/imgfmt/FileNotWritableException.java: Remove
+ call to constructor that is not in 1.5
+ * README: Bring the README file more up to date.
+
+2007-11-14 steve
+
+ * Makefile, src/uk/me/parabola/imgfmt/app/Overview.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java: Fix the
+ overview records.
+ * ., build.xml, resources/chars, resources/chars/ascii,
+ resources/chars/ascii/row00.trans,
+ resources/chars/ascii/row01.trans,
+ resources/chars/ascii/row02.trans,
+ resources/chars/ascii/row03.trans,
+ resources/chars/ascii/row04.trans,
+ src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/AnyCharsetEncoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/BaseEncoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/TableCreator.java: Merged
+ revisions 345-350,352-366 via svnmerge from
+ https://svn.parabola.me.uk/svn/mkgmap/branches/lang
+
+ ........ r345 | steve | 2007-11-02 00:33:22 +0000 (Fri, 02 Nov
+ 2007) | 1 line allow any charset as a target ........ r350 |
+ steve | 2007-11-03 17:45:54 +0000 (Sat, 03 Nov 2007) | 1 line
+ Allow for making upper-casing optional ........ r352 | steve |
+ 2007-11-04 16:49:05 +0000 (Sun, 04 Nov 2007) | 2 lines Make all
+ the transliteration for the acsii-only mode to be table driven.
+ ........ r353 | steve | 2007-11-04 19:03:47 +0000 (Sun, 04 Nov
+ 2007) | 2 lines Added missing (blank) character translit maps.
+ ........ r354 | steve | 2007-11-04 20:00:53 +0000 (Sun, 04 Nov
+ 2007) | 2 lines Build changes needed for character tables.
+ ........ r360 | steve | 2007-11-06 23:02:49 +0000 (Tue, 06 Nov
+ 2007) | 2 lines Russian transliteration provided by User:Liosha
+ ........
+
+2007-11-13 steve
+
+ * src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java:
+ Changed default level definitions.
+ * resources/map-features.csv, resources/osm_garmin_map.csv:
+ Improved set of levels for the map features by Jochen Topf.
+ * src/uk/me/parabola/imgfmt/app/Overview.java,
+ src/uk/me/parabola/imgfmt/app/PointOverview.java,
+ src/uk/me/parabola/imgfmt/app/PolygonOverview.java,
+ src/uk/me/parabola/imgfmt/app/PolylineOverview.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java:
+ Finally made the overview sections actually reflect the levels at
+ which things appear. Calculate the levels for the overview map,
+ so that they do not overlap with any of the inputs, even if they
+ are set to non-default values.
+
+2007-11-10 steve
+
+ * Makefile, src/uk/me/parabola/mkgmap/main/OverviewMapBuilder.java,
+ src/uk/me/parabola/tdbfmt/OverviewMapBlock.java,
+ src/uk/me/parabola/tdbfmt/TdbFile.java: Fix the dimentions in the
+ TDB file. Couple of other fixes for the overview map. Also the
+ name of the overview map now does not have the trailing zeros.
+ * src/uk/me/parabola/imgfmt/sys/Dirent.java: If the name is not
+ eight characters then truncate or left pad with zeros.
+
+2007-11-09 steve
+
+ * src/uk/me/parabola/imgfmt/app/TREFile.java: Back out mistaken
+ checking that broke the map.
+
+2007-11-06 steve
+
+ * src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java:
+ Characters between 1d and 1f can just go through unchanged.
+ * Makefile, src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/tdbfmt/OverviewMapBlock.java: More reliably
+ work with QLandkarte. Calculation of the size of the TRE subdiv
+ region was wrong when the lowest level was not 0, such as happens
+ in the overview map.
+
+2007-11-05 steve
+
+ * ChangeLog, Makefile,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm4MapDataSource.java:
+ Version 0.3 works like 0.4 and recentish files claim to be 0.3 so
+ include them in the 0.4 support
+ * src/uk/me/parabola/tdbfmt/CopyrightBlock.java,
+ src/uk/me/parabola/tdbfmt/CopyrightSegment.java,
+ src/uk/me/parabola/tdbfmt/TestTdb.java: Don't repeat copyright
+ statements.
+
+2007-11-04 steve
+
+ * doc, test: Add some ignores
+
+2007-11-03 steve
+
+ * src/uk/me/parabola/mkgmap/reader/osm/Osm4MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/plugin/MapReader.java: OSM api
+ v0.5 is now the default format. 0.4 is still supported and
+ detected automatically so there is not much difference.
+ * src/uk/me/parabola/mkgmap/reader/osm/Osm4MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/plugin/MapperBasedMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java:
+ Allow reading from zip compressed files. This is done by file
+ extension and not the actual type of file.
+ * .: Initialized merge tracking via "svnmerge" with revisions
+ "1-343" from https://svn.parabola.me.uk/svn/mkgmap/branches/lang
+
+2007-11-02 steve
+
+ * src/uk/me/parabola/imgfmt/app/TYPFile.java: Skeleton code added
+
+2007-10-29 steve
+
+ * Makefile, src/uk/me/parabola/imgfmt/FileSystemParam.java,
+ src/uk/me/parabola/imgfmt/Utils.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/fs/DirectoryEntry.java,
+ src/uk/me/parabola/imgfmt/fs/FileSystem.java,
+ src/uk/me/parabola/imgfmt/fs/ImgChannel.java,
+ src/uk/me/parabola/imgfmt/sys/BlockManager.java,
+ src/uk/me/parabola/imgfmt/sys/BlockTable.java,
+ src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java,
+ src/uk/me/parabola/imgfmt/sys/FileNode.java,
+ src/uk/me/parabola/imgfmt/sys/HeaderDirent.java,
+ src/uk/me/parabola/imgfmt/sys/ImgFS.java,
+ src/uk/me/parabola/imgfmt/sys/ImgHeader.java,
+ src/uk/me/parabola/log/UsefulFormatter.java,
+ src/uk/me/parabola/mkgmap/general/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/main/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/TestAll.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/plugin/MapperBasedMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java,
+ src/uk/me/parabola/tdbfmt/Block.java, test, test/java,
+ test/java/test: Merged in the img file reading support. The
+ underlying img read code (at the imgfmt.sys level) has been
+ heavily changed, so watch out. Appears to give the same result
+ files as before though.
+
+ In addition to read support, you should find that blocksizes
+ other than 512 now actually work.
+
+ Combining .img files into a gmapsupp.img file is now possible,
+ although not implemented just yet.
+
+2007-10-25 steve
+
+ * src/uk/me/parabola/mkgmap/reader/osm/Osm5XmlHandler.java: Add
+ line number and column number on parser errors.
+ * src/uk/me/parabola/mkgmap/main/MakeMap.java: Now that we can have
+ more than one file on the command line, we should deal with
+ errors in induvidual files and then go on to the next. (bug
+ reported by User:Lambertus)
+
+2007-10-21 steve
+
+ * src/uk/me/parabola/mkgmap/general/MapBuilder.java: Was adding one
+ instead of subtracting when making the number of bits for the top
+ invible level.
+
+ Thanks to Petr Schönmann for pointing this out
+
+2007-10-20 steve
+
+ * src/uk/me/parabola/imgfmt/app/TREFile.java: Removed unused
+ statement.
+ * src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java:
+ Add more comments.
+ * src/uk/me/parabola/imgfmt/app/TREFile.java: Account for the size
+ of the final RGN pointer, so that the TRE section size is
+ correct.
+
+2007-10-18 steve
+
+ * ChangeLog, Makefile: Update changelog file.
+ * src/uk/me/parabola/mkgmap/reader/osm/CodedConverter.java: Remove
+ deprecated tag, its more just unused.
+ * src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/mkgmap/general/MapBuilder.java: Fix the
+ markers at the end of a group of subdivisions. I was only putting
+ the end marker on the last divsion in a level. Each set of
+ divisions that has the same parent should have an end marker
+ though.
+
+ This fixes the 'Find' bug, and seems to make the map faster in
+ dense areas.
+ * src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java:
+ Prevent too many levels being used as this leads to maps that
+ cause a crash.
+
+2007-10-15 steve
+
+ * src/uk/me/parabola/mkgmap/general/MapBuilder.java: Split up long
+ lines, this will help with coastlines, contours etc as there
+ appears to be a limit of around 250 points that you can have in a
+ line on the garmin devices.
+ * src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java:
+ Implement the EndLevels (and it varients) and add the old RGN10
+ etc section names.
+
+2007-10-14 steve
+
+ * Makefile, resources/map-features.csv,
+ resources/osm_garmin_map.csv,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java:
+ Hack to display contours with thier heights.
+ * src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java:
+ Add coastlines and cities to the overview. I guess this should be
+ driven by a full map-features file.
+ * src/uk/me/parabola/mkgmap/main/CommandArgs.java: Command argument
+ can now be read from a file, including input files and further
+ files to read options from.
+ * src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/Overview.java,
+ src/uk/me/parabola/mkgmap/general/LevelInfo.java,
+ src/uk/me/parabola/mkgmap/general/MapBuilder.java,
+ src/uk/me/parabola/mkgmap/general/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/main/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/OverviewMapBuilder.java,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way4.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way5.java,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/plugin/MapperBasedMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/test/AllElements.java,
+ src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/test/TestPoints.java,
+ src/uk/me/parabola/tdbfmt/Block.java,
+ src/uk/me/parabola/tdbfmt/CopyrightBlock.java,
+ src/uk/me/parabola/tdbfmt/CopyrightSegment.java,
+ src/uk/me/parabola/tdbfmt/OverviewMapBlock.java: Merged in code
+ cleanup from the gui branch. That branch is now merged up to r299
+
+2007-10-12 steve
+
+ * Makefile,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5XmlHandler.java: If a
+ node that is part of a way is missing, then dont add a null
+ point...
+
+2007-10-07 steve
+
+ * doc/features.txt: Will be list of features.
+
+2007-10-06 steve
+
+ * ., ChangeLog, Makefile, resources/MANIFEST.MF, resources/README,
+ src/uk/me/parabola/imgfmt/app/InternalFiles.java,
+ src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Bit10Encoder.java,
+ src/uk/me/parabola/log/UsefulFormatter.java,
+ src/uk/me/parabola/mkgmap/general/LevelInfo.java,
+ src/uk/me/parabola/mkgmap/general/LoadableMapDataSource.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapBuilder.java,
+ src/uk/me/parabola/mkgmap/general/MapDataSource.java,
+ src/uk/me/parabola/mkgmap/main/ArgumentProcessor.java,
+ src/uk/me/parabola/mkgmap/main/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/FilenameProcessor.java,
+ src/uk/me/parabola/mkgmap/main/Main.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MapEvents.java,
+ src/uk/me/parabola/mkgmap/main/MapOption.java,
+ src/uk/me/parabola/mkgmap/main/MapProcessor.java,
+ src/uk/me/parabola/mkgmap/main/OverviewMapBuilder.java,
+ src/uk/me/parabola/mkgmap/main/TestAll.java,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/overview,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMap.java,
+ src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/overview/package.html,
+ src/uk/me/parabola/mkgmap/reader/plugin/MapperBasedMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java,
+ src/uk/me/parabola/tdbfmt/Block.java,
+ src/uk/me/parabola/tdbfmt/CopyrightBlock.java,
+ src/uk/me/parabola/tdbfmt/CopyrightSegment.java,
+ src/uk/me/parabola/tdbfmt/DetailMapBlock.java,
+ src/uk/me/parabola/tdbfmt/HeaderBlock.java,
+ src/uk/me/parabola/tdbfmt/OverviewMapBlock.java,
+ src/uk/me/parabola/tdbfmt/TdbFile.java: Merged in the
+ overview/tdb branch.
+ * doc/map-features.txt: Customising the map.
+
+2007-10-04 steve
+
+ * doc/map-features.txt, doc/mkgmap-man.txt: First stab at some
+ documentation
+
+2007-10-01 steve
+
+ * ChangeLog: Update the changelog file.
+
+2007-09-25 steve
+
+ * Makefile: makefile changes
+
+2007-09-24 steve
+
+ * src/uk/me/parabola/mkgmap/main/MakeTestMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestPointMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestPolygonMap.java,
+ src/uk/me/parabola/mkgmap/main/TestAll.java,
+ src/uk/me/parabola/mkgmap/main/package.html: Removed test
+ programs that are replaced by the test-map:all-elements map and
+ indeed probably don't even work any more.
+ * src/uk/me/parabola/tdbfmt/Block.java,
+ src/uk/me/parabola/tdbfmt/CopyrightSegment.java,
+ src/uk/me/parabola/tdbfmt/DetailMapBlock.java,
+ src/uk/me/parabola/tdbfmt/TdbFile.java: Code cleanup.
+
+2007-09-23 steve
+
+ * resources/map-features.csv, resources/osm_garmin_map.csv: fix
+ previous change and made the map-features file.
+ * resources/osm_garmin_map.csv: Slight tweek to reduce the number
+ of towns at low res.
+ * src/uk/me/parabola/mkgmap/reader/osm/Osm4MapDataSource.java:
+ Removed imports that are not used any more.
+ * src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java:
+ Not setting the resolution in the default (old) case.
+ * src/uk/me/parabola/tdbfmt/Block.java,
+ src/uk/me/parabola/tdbfmt/CopyrightBlock.java,
+ src/uk/me/parabola/tdbfmt/CopyrightSegment.java,
+ src/uk/me/parabola/tdbfmt/DetailMapBlock.java,
+ src/uk/me/parabola/tdbfmt/HeaderBlock.java,
+ src/uk/me/parabola/tdbfmt/OverviewMapBlock.java,
+ src/uk/me/parabola/tdbfmt/StructuredInputStream.java,
+ src/uk/me/parabola/tdbfmt/StructuredOutputStream.java,
+ src/uk/me/parabola/tdbfmt/TdbFile.java: Javadoc and code tidy up.
+ * src/uk/me/parabola/tdbfmt/Block.java,
+ src/uk/me/parabola/tdbfmt/CopyrightBlock.java,
+ src/uk/me/parabola/tdbfmt/CopyrightSegment.java,
+ src/uk/me/parabola/tdbfmt/DetailMapBlock.java,
+ src/uk/me/parabola/tdbfmt/HeaderBlock.java,
+ src/uk/me/parabola/tdbfmt/OverviewMapBlock.java,
+ src/uk/me/parabola/tdbfmt/StructuredOutputStream.java,
+ src/uk/me/parabola/tdbfmt/TdbFile.java,
+ src/uk/me/parabola/tdbfmt/TestTdb.java: Now can write out the tdb
+ file so it is identical to the file that was read in. Not
+ particularly useful, but shows that all is working.
+ * resources/map-features.csv, resources/osm_garmin_map.csv: Tweeked
+ map features.
+ * src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java: Add
+ warning for when a region is overflowing.
+ * src/uk/me/parabola/mkgmap/reader/test/AllElements.java: wasn't
+ showing all the lines.
+ * src/uk/me/parabola/tdbfmt/TdbFile.java,
+ src/uk/me/parabola/tdbfmt/Test.java,
+ src/uk/me/parabola/tdbfmt/TestTdb.java: Some tidying around tdb
+ test.
+ * src/uk/me/parabola/tdbfmt/CopyrightBlock.java,
+ src/uk/me/parabola/tdbfmt/CopyrightSegment.java,
+ src/uk/me/parabola/tdbfmt/DetailMapBlock.java,
+ src/uk/me/parabola/tdbfmt/EndOfFileException.java,
+ src/uk/me/parabola/tdbfmt/HeaderBlock.java,
+ src/uk/me/parabola/tdbfmt/StructuredInputStream.java,
+ src/uk/me/parabola/tdbfmt/TdbFile.java,
+ src/uk/me/parabola/tdbfmt/TestTdb.java: Javadoc additions
+ * src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/mkgmap/main/TestAll.java: Fuller test
+ coverage.
+ * src/uk/me/parabola/tdbfmt/Block.java,
+ src/uk/me/parabola/tdbfmt/CopyrightBlock.java,
+ src/uk/me/parabola/tdbfmt/CopyrightSegment.java,
+ src/uk/me/parabola/tdbfmt/DetailMapBlock.java,
+ src/uk/me/parabola/tdbfmt/OverviewMapBlock.java,
+ src/uk/me/parabola/tdbfmt/StructuredInputStream.java,
+ src/uk/me/parabola/tdbfmt/TdbFile.java: Full decoding of the TDB
+ file now.
+ * src/uk/me/parabola/tdbfmt/Block.java,
+ src/uk/me/parabola/tdbfmt/CopyrightSegment.java,
+ src/uk/me/parabola/tdbfmt/DetailMapBlock.java,
+ src/uk/me/parabola/tdbfmt/EndOfFileException.java,
+ src/uk/me/parabola/tdbfmt/HeaderBlock.java,
+ src/uk/me/parabola/tdbfmt/OverviewMapBlock.java,
+ src/uk/me/parabola/tdbfmt/StructuredInputStream.java,
+ src/uk/me/parabola/tdbfmt/TdbFile.java,
+ src/uk/me/parabola/tdbfmt/Test.java,
+ src/uk/me/parabola/tdbfmt/package.html: Initial code for the TDB
+ file.
+
+ As there are no programs that simply print the contents out, then
+ the first task is to be able to do this so that we can check that
+ we are producing the correct things.
+ * src/uk/me/parabola/imgfmt/fs/ImgChannel.java: javadoc
+ clarification
+
+2007-09-22 steve
+
+ * src/uk/me/parabola/log/Logger.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestElementMap.java,
+ src/uk/me/parabola/mkgmap/reader/plugin/MapReader.java,
+ src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java:
+ You can now set the level definitions from the command line and
+ choose another map-features file too. --map-features=file
+ --levels=0:24,1:22,2:20 (or you can use 0=24 etc)
+ * src/uk/me/parabola/mkgmap/ConfiguredByProperties.java,
+ src/uk/me/parabola/mkgmap/general/LevelInfo.java,
+ src/uk/me/parabola/mkgmap/main/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/reader/MapReader.java,
+ src/uk/me/parabola/mkgmap/reader/PropertyConfiguredReader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm4MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5XmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmXmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/plugin,
+ src/uk/me/parabola/mkgmap/reader/plugin/MapReader.java,
+ src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java:
+ You can now set the level definitions from the command line and
+ choose another map-features file too. --map-features=file
+ --levels=0:24,1:22,2:20 (or you can use 0=24 etc)
+ * src/uk/me/parabola/mkgmap/reader/osm/Osm5XmlHandler.java:
+ Implement the selective node creation for osm5, the same as for
+ osm4
+ * resources/feature_map.csv, resources/map-features.csv,
+ resources/osm_garmin_map.csv,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java:
+ Now have a new name for the feature map file map-features.csv
+ * resources/feature_map.csv, scripts/mk_map_table.py: Add extra
+ column to the feature map file.
+ * resources/garmin_feature_list.csv, resources/osm_garmin_map.csv,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/reader/osm/CodedConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java:
+ Now read the resolutions from the feature map file.
+
+2007-09-20 steve
+
+ * src/uk/me/parabola/mkgmap/main/CommandArgs.java: typo fix
+
+2007-09-19 steve
+
+ * src/uk/me/parabola/log/Logger.java: Logging routines more
+ consistant.
+
+2007-09-18 steve
+
+ * src/uk/me/parabola/log/Logger.java: Logging routines more
+ consistant.
+ * Makefile,
+ src/uk/me/parabola/mkgmap/reader/osm/OSM5XmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5XmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmXmlHandler.java: Name
+ change for OSM --> Osm
+
+2007-09-15 steve
+
+ * src/uk/me/parabola/log/UsefulFormatter.java: The formatter must
+ be public so that the LogManager can see it.
+ * src/uk/me/parabola/mkgmap/reader/osm/Element.java,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way.java: Better lookup of
+ features by stepping through tags and not by stepping through the
+ list of features.
+
+ Most nodes are just parts of a line. Try to prevent converting
+ nodes that are definitly not stand alone (eg just have a
+ created_by tag).
+
+ Saves about 5%
+ * Makefile, src/uk/me/parabola/mkgmap/main/MakeTestElementMap.java,
+ src/uk/me/parabola/mkgmap/reader/osm/CodedConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/package.html: Documentation
+ and small changes.
+
+2007-09-13 steve
+
+ * Makefile, src/uk/me/parabola/imgfmt/app/BitWriter.java,
+ src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/MapObject.java,
+ src/uk/me/parabola/imgfmt/app/Overview.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Latin2Encoder.java,
+ src/uk/me/parabola/imgfmt/sys/ImgFS.java,
+ src/uk/me/parabola/log/Logger.java,
+ src/uk/me/parabola/log/UsefulFormatter.java,
+ src/uk/me/parabola/mkgmap/general/LevelFilter.java,
+ src/uk/me/parabola/mkgmap/general/LevelInfo.java,
+ src/uk/me/parabola/mkgmap/general/LoadableMapDataSource.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/general/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestElementMap.java,
+ src/uk/me/parabola/mkgmap/reader/MapReader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Node.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OSM5XmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way5.java,
+ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/test/AllElements.java,
+ src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/test/TestPoints.java: Code tidy
+ up.
+ * src/uk/me/parabola/mkgmap/reader/osm/Osm5MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java: Fix
+ spelling. (Bruce Cowan)
+ * src/uk/me/parabola/imgfmt/sys/ImgFS.java,
+ src/uk/me/parabola/mkgmap/general/LevelInfo.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Element.java,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Node.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way.java,
+ src/uk/me/parabola/mkgmap/reader/osm/package.html,
+ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java:
+ Made many classes package local again, now that I've recombined
+ the OSM readers into the one package.
+ * src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/reader/MapReader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OSM5XmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Osm5MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way5.java,
+ src/uk/me/parabola/mkgmap/reader/osm5: Remove osm5 directory and
+ move all to the osm package.
+
+2007-09-12 steve
+
+ * src/uk/me/parabola/mkgmap/reader/osm/Node.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Node4.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm5/Node5.java,
+ src/uk/me/parabola/mkgmap/reader/osm5/OSM5XmlHandler.java: Got
+ rid of Node4 and 5 as they were just the same anyway. The
+ interface went as well.
+ * resources/garmin_feature_list.csv, resources/osm_garmin_map.csv:
+ Extensive work-through of features from going through
+ test-map:all-elements
+
+2007-09-11 steve
+
+ * ChangeLog, Makefile: New changelog checked in.
+ * scripts/mk_map_table.py: Change needed to create map_features
+ * resources/feature_map.csv, resources/garmin_feature_list.csv,
+ resources/osm_garmin_map.csv: A few more features added. Basic
+ city/town support, but can be better and use the indexed point
+ feature of the maps.
+ * resources/logging.properties,
+ src/uk/me/parabola/mkgmap/reader/MapReader.java,
+ src/uk/me/parabola/mkgmap/reader/osm/CodedConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Element.java,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Node.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Node4.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way4.java,
+ src/uk/me/parabola/mkgmap/reader/osm5,
+ src/uk/me/parabola/mkgmap/reader/osm5/Node5.java,
+ src/uk/me/parabola/mkgmap/reader/osm5/OSM5XmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm5/Osm5MapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm5/Way5.java: Added support
+ for api version 0.5. Usage is transparent - it works out the
+ difference between 0.4 and 0.5 automatically and uses the right
+ reader.
+ * src/uk/me/parabola/mkgmap/general/MapSplitter.java: Remove
+ assertion so will compile out of svn
+
+2007-09-09 steve
+
+ * src/uk/me/parabola/log/Logger.java: Make default for static setup
+ SEVERE
+ * src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java: Made a lot of
+ changes to the way that the subdivisions are split. It should now
+ be the case that there are no empty sections within the RGN files
+ ie if there are no points then the flag to say there are points
+ will not be set.
+
+ Doesn't appear to fix the 'find' bug. Does seem to fix the
+ problem shown by imgdecode, where at lower-res levels there are
+ wierd all over the place polygons.
+
+ Not really tested much at all though.
+ * src/uk/me/parabola/mkgmap/general/MapElement.java: Comments to
+ explain min resolution better and the direction it is going in.
+ * src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java:
+ Update the polish input format, so that it places elements at the
+ levels specified in the file and not at the default levels.
+ * src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java:
+ javadoc etc.
+ * src/uk/me/parabola/log/Logger.java: Print warning if log config
+ file could not be opened.
+ * src/uk/me/parabola/imgfmt/app/Subdivision.java: Round the sizes
+ before shifting them.
+ * build.xml, src/uk/me/parabola/log/Logger.java,
+ src/uk/me/parabola/log/UsefulFormatter.java: Convert the logging
+ to use j.u.l underneath. You can still use varargs in the logging
+ calls and the interface is just the same (use debug() instead of
+ fine() etc).
+
+ Was it worth it? Probably not. Should be able to selectively
+ switch on some logging now though.
+
+2007-09-08 steve
+
+ * src/uk/me/parabola/imgfmt/app/RGNFile.java: Cosmetic changes
+ * src/uk/me/parabola/mkgmap/reader/test/ManyPoints.java: Checkin
+ deleted file after re-naming
+ * src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/reader/MapReader.java,
+ src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/test/TestPoints.java: A test map
+ to look into the 'find' bug.
+
+2007-09-03 steve
+
+ * src/uk/me/parabola/mkgmap/main/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/reader/PropertyConfiguredReader.java,
+ src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/test/ManyPoints.java: The test
+ map I am using to debug the 'find' problem and missing points
+ problem.
+ * src/uk/me/parabola/mkgmap/main/CommandArgs.java: Make public
+ * src/uk/me/parabola/mkgmap/main/CommandArgs.java: Remove comment
+ that I don't really believe in.
+ * src/uk/me/parabola/mkgmap/main/MakeMap.java: Fix call to function
+ that is not checked in.
+ * src/uk/me/parabola/mkgmap/general/MapSplitter.java: Comment
+ changed.
+ * src/uk/me/parabola/mkgmap/main/MakeMap.java: Remove adding the
+ dummy overview. It doesn't get added to the end since we now sort
+ them, and the lack of sorting is probably the reason that they
+ were added in the first place(?)
+ * src/uk/me/parabola/mkgmap/reader/test/AllElements.java,
+ src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java:
+ Get the right values for the max number of lines and shapes.
+
+2007-09-02 steve
+
+ * src/uk/me/parabola/imgfmt/app/Overview.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/main/AbstractTestMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestElementMap.java,
+ src/uk/me/parabola/mkgmap/reader/MapReader.java,
+ src/uk/me/parabola/mkgmap/reader/test,
+ src/uk/me/parabola/mkgmap/reader/test/AllElements.java,
+ src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/test/package.html: New test data
+ source. It generates test maps. Try it by using TEST:ALL-ELEMENTS
+ as the input file name.
+ * src/uk/me/parabola/mkgmap/main/AbstractTestMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestLang10Map.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestLangMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestPointMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestPolygonMap.java: Remove
+ writeOverviews from superclass, make a call in the one place it
+ is used and remove all other usages.
+ * src/uk/me/parabola/imgfmt/FileNotWritableException.java: Fix typo
+ in comment
+ * src/uk/me/parabola/imgfmt/app/labelenc/Bit10Encoder.java: The
+ so-called 10-bit encoder, spoils the package dependancies and is
+ probably not even correct. I'd imagine that they would just use
+ unicode for other international character sets.
+ * src/uk/me/parabola/imgfmt/FileNotWritableException.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/sys/ImgFS.java,
+ src/uk/me/parabola/mkgmap/main/AbstractTestMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java: Fix exception
+ handling on unwritable files to be clearer.
+ * src/uk/me/parabola/mkgmap/general/LoadableMapDataSource.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java:
+ The input format interface now has two new methods. One to
+ determine if a given file is supported, and one to return
+ suitable map levels for the map.
+ * resources/README: Added readme file.
+ * src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/reader/MapReader.java: Separate out the
+ code to determine what kind of input file is in use. This will
+ allow a more plugin type approach in the future.
+ * Makefile, src/uk/me/parabola/mkgmap/main/MakeMap.java: 1. Code to
+ simplify the lines before they are written. 2. Change needed for
+ the moving of the reader classes.
+ * src/uk/me/parabola/imgfmt/FileExistsException.java,
+ src/uk/me/parabola/imgfmt/app/package.html,
+ src/uk/me/parabola/imgfmt/fs/DirectoryEntry.java,
+ src/uk/me/parabola/imgfmt/fs/ImgChannel.java,
+ src/uk/me/parabola/imgfmt/package.html,
+ src/uk/me/parabola/mkgmap/general/LevelInfo.java,
+ src/uk/me/parabola/mkgmap/general/package.html,
+ src/uk/me/parabola/mkgmap/main/AbstractTestMap.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Element.java,
+ src/uk/me/parabola/mkgmap/reader/osm/package.html,
+ src/uk/me/parabola/mkgmap/reader/polish/package.html: Many
+ javadoc improvements.
+ * src/uk/me/parabola/mkgmap/general/LevelInfo.java,
+ src/uk/me/parabola/mkgmap/osm, src/uk/me/parabola/mkgmap/polish:
+ Move LevelInfo into the general directory.
+ * src/uk/me/parabola/mkgmap/osm/CodedConverter.java,
+ src/uk/me/parabola/mkgmap/osm/Element.java,
+ src/uk/me/parabola/mkgmap/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/osm/Node.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/osm/OsmConverter.java,
+ src/uk/me/parabola/mkgmap/osm/OsmMapDataSource.java,
+ src/uk/me/parabola/mkgmap/osm/Segment.java,
+ src/uk/me/parabola/mkgmap/osm/Way.java,
+ src/uk/me/parabola/mkgmap/polish/PolishMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader,
+ src/uk/me/parabola/mkgmap/reader/osm,
+ src/uk/me/parabola/mkgmap/reader/osm/CodedConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Element.java,
+ src/uk/me/parabola/mkgmap/reader/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Node.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java,
+ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Segment.java,
+ src/uk/me/parabola/mkgmap/reader/osm/Way.java,
+ src/uk/me/parabola/mkgmap/reader/osm/package.html,
+ src/uk/me/parabola/mkgmap/reader/polish,
+ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java:
+ Move input formats into their own directory. Will make it clearer
+ how to add new input formats, such as shape files.
+
+2007-09-01 steve
+
+ * src/uk/me/parabola/mkgmap/polish,
+ src/uk/me/parabola/mkgmap/polish/PolishMapDataSource.java: Add
+ the polish format as an input choice.
+ * src/uk/me/parabola/mkgmap/osm/FeatureListConverter.java: Re-allow
+ 5 field files again.
+
+2007-08-31 steve
+
+ * src/uk/me/parabola/imgfmt/app/Map.java: Give a message when it is
+ not possible to create the output map file.
+
+2007-08-27 steve
+
+ * src/uk/me/parabola/mkgmap/general/MapDetails.java: Imports
+ re-arranged.
+ * src/uk/me/parabola/mkgmap/general/MapSplitter.java: don't repeat
+ code in the constructors.
+
+2007-08-25 steve
+
+ * Makefile, README,
+ src/uk/me/parabola/imgfmt/app/labelenc/Latin2Encoder.java,
+ src/uk/me/parabola/mkgmap/general/LoadableMapDataSource.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapLine.java,
+ src/uk/me/parabola/mkgmap/main/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/package.html: Small tidy ups for
+ release.
+ * src/uk/me/parabola/mkgmap/general/MapDetails.java: Check for
+ empty areas and lines.
+
+ Fixes bug rendering:
+ http://openstreetmap.gryph.de/germany/germany-070823.osm.bz2
+ * src/uk/me/parabola/imgfmt/app/Area.java: Make sure that areas
+ never have a zero width or height. Avoids the problem below.
+
+ Bearbeite Kachelnummer: 63253506 Exception in thread "main"
+ java.lang.ArithmeticException: / by zero at
+ uk.me.parabola.mkgmap.general.MapArea.pickArea(MapArea.java:361)
+ * src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java: We need to make
+ sure that points are included in the calculation of the size of
+ the area. Otherwise it is posible for the point to be outside the
+ map area altogether. If it happens to outside to the west or
+ south then you get the error below.
+
+ Bearbeite Kachelnummer: 63247525 Exception in thread "main"
+ java.lang.ArrayIndexOutOfBoundsException: -9 at
+ uk.me.parabola.mkgmap.general.MapArea.pickArea(MapArea.java:373)
+ * src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java: Fix
+ ensureSize() properly so that we never run out of space.
+
+ Bearbeite Kachelnummer: 63243936 Exception in thread "main"
+ java.nio.BufferOverflowException at
+ java.nio.HeapByteBuffer.put(HeapByteBuffer.java:165)
+
+2007-08-21 steve
+
+ * src/uk/me/parabola/mkgmap/general/MapArea.java: Re-instated part
+ of the RGN overflow change.
+ * src/uk/me/parabola/mkgmap/general/MapArea.java: Remove println
+ that should have been removed.
+ * ChangeLog, Makefile: Changelog and makefile changes only
+ * src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java:
+ Possible fix for overflow in output buffer.
+ * src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapSplitter.java: Attempted fix
+ for overflowing RGN section.
+
+2007-08-19 steve
+
+ * Makefile: Add note that this is not really used to build
+ * src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java: Allow
+ coastlines to show up at all resolutions.
+ * resources/feature_map.csv, resources/garmin_feature_list.csv,
+ resources/osm_garmin_map.csv: Fix the feature lists which seemed
+ to be populated with all kinds of weird things.
+ * src/uk/me/parabola/imgfmt/app/LBLFile.java: Improve description
+ on javadoc for newLabel (now that it doesn't always return a new
+ lable)
+ * src/uk/me/parabola/imgfmt/app/LBLFile.java: Keep a cache of label
+ names so that we do not create multiple labels for the same piece
+ of text. Greatly reduces the size of the label section.
+ * src/uk/me/parabola/imgfmt/app/Coord.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/general/MapLine.java: Allocate elements
+ to sub-divisions based on the mid-point of the element rather
+ than the first point in the line/polygon. This will create less
+ overlapping of the sub-divisions, which may make the map faster
+ on the Garmin units. To do reduce sub-division overlapping
+ further will require splitting lines. It may not be worth
+ reducing overlap either.
+
+2007-08-15 steve
+
+ * src/uk/me/parabola/mkgmap/main/ExitException.java: This should
+ have been removed by the previous commit.
+ * ChangeLog, src/uk/me/parabola/mkgmap/ExitException.java,
+ src/uk/me/parabola/mkgmap/main/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/FeatureListConverter.java: Move
+ ExitException to remove cycle in the package structure.
+
+2007-06-23 steve
+
+ * src/uk/me/parabola/mkgmap/general/MapArea.java: Getting rid of
+ zero length lines.
+ * src/uk/me/parabola/imgfmt/app/labelenc/package.html,
+ src/uk/me/parabola/imgfmt/fs/package.html,
+ src/uk/me/parabola/imgfmt/package.html,
+ src/uk/me/parabola/mkgmap/main/package.html: Added and fixed
+ package level javadoc.
+
+2007-06-17 steve
+
+ * src/uk/me/parabola/imgfmt/app/Coord.java,
+ src/uk/me/parabola/imgfmt/app/LinePreparer.java: Comments and add
+ a toString method to Coord
+
+2007-06-10 steve
+
+ * Makefile, src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/Zoom.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/general/MapLine.java,
+ src/uk/me/parabola/mkgmap/general/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/osm/Way.java: Tidy up and tweeking of
+ hardwired parameters.
+ * Makefile, src/uk/me/parabola/imgfmt/app/Overview.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/Zoom.java,
+ src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java: Had the wrong mask
+ for the level, so any level above 3 would mess things up.
+
+ Now working with 5 levels. Time to make it configurable...
+ * .: Tidied up the list of ignored files.
+ * Makefile, src/uk/me/parabola/imgfmt/app/Subdivision.java: Merge
+ large file fixes in from stable branch.
+
+2007-06-09 steve
+
+ * src/uk/me/parabola/mkgmap/general/MapElement.java: Add some more
+ hardwired resolutions.
+
+2007-06-07 steve
+
+ * src/uk/me/parabola/imgfmt/sys/Directory.java: Increase number of
+ directory blocks.
+
+2007-05-29 steve
+
+ * src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/mkgmap/osm/ReadOsm.java: Deleted file and
+ remove unused import
+
+2007-05-13 steve
+
+ * Makefile, resources/garmin_feature_list.csv,
+ resources/osm_garmin_map.csv, scripts/mk_map_table.py,
+ src/uk/me/parabola/mkgmap/osm/FeatureListConverter.java: Input
+ files for feature_map.csv and program to create. Moved away from
+ the files in osmgarminmap, but garmin_feature_list.csv is a copy
+ of feature-list.csv from there.
+ * resources/feature_map.csv: New feature map with many more entries
+ and fully sorted. Contributed by Roozbeh Pournader
+
+2007-05-09 steve
+
+ * Makefile, resources/feature_map.csv,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/OsmMapDataSource.java: Zoomability
+ now working for large maps eg London. Still basic, but now just
+ really a matter of tuning it up.
+
+2007-03-29 steve
+
+ * src/uk/me/parabola/imgfmt/app/BitWriter.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/Overview.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/Zoom.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java: Zoomability now
+ working for large maps eg London. Still basic, but now just
+ really a matter of tuning it up.
+
+2007-03-25 steve
+
+ * src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapDataSource.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java: Working 'zoomable'
+ map. Very basic, you see exactly the same things at the lower
+ resolution levels as the higher ones.
+
+ Its now just a simple matter of filtering what is wanted at each
+ level...
+ * src/uk/me/parabola/imgfmt/app/InternalFiles.java,
+ src/uk/me/parabola/imgfmt/app/Polygon.java: Add some javadoc.
+
+2007-03-24 steve
+
+ * src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/Zoom.java,
+ src/uk/me/parabola/mkgmap/general/LoadableMapDataSource.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapDataSource.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/ReadOsm.java: Split MapDataSource
+ to allow it to be implemented by MapArea
+ * src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java: Keep track of
+ how many elements are at each resolution.
+ * src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/general/MapLine.java,
+ src/uk/me/parabola/mkgmap/general/MapPoint.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/FeatureListConverter.java: Pushed
+ bounding box code into line and polyline as it is not needed on
+ points.
+
+2007-03-04 steve
+
+ * src/uk/me/parabola/mkgmap/general/LevelFilter.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java: Level loop in place,
+ although it will not work if more than one level in there.
+ * src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java: Split out
+ making top level subdivision.
+
+2007-03-03 steve
+
+ * ChangeLog, src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/osm/Way.java: Merged back from branch.
+ - Use the ref tag where available - Works for large areas (really
+ this time). Both problems pointed out by Phillip Barnett.
+ * Makefile, src/uk/me/parabola/imgfmt/app/Zoom.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/main/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java: Options added
+ preparation for zoomability.
+
+2007-02-10 steve
+
+ * src/uk/me/parabola/mkgmap/osm/ReadOsm.java: Added space before
+ equals sign.
+
+2007-02-08 steve
+
+ * src/uk/me/parabola/imgfmt/Utils.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/Overview.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java,
+ src/uk/me/parabola/log/Logger.java,
+ src/uk/me/parabola/mkgmap/main/AbstractTestMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/Element.java: Removed a number of
+ the TODO's and removed some dead code.
+ * src/uk/me/parabola/log/Logger.java: May as well remove concurrent
+ hash map it will then run with gcj. Its ten times slower though.
+
+2007-02-07 steve
+
+ * src/uk/me/parabola/imgfmt/FormatException.java,
+ src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/imgfmt/app/BitWriter.java,
+ src/uk/me/parabola/imgfmt/app/Coord.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/main/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/osm/Segment.java: Deleted a lot of
+ unused stuff, even if it would be good for debugging.
+
+2007-02-06 steve
+
+ * build.xml: Build problem
+ * ChangeLog, README, build.xml: Final changes for release.
+ * src/uk/me/parabola/imgfmt/sys/ImgFS.java: Fix annoying problem
+ where overwriting a bigger file leaves the new file unworkable,
+ even if it would be alright otherwise.
+ * src/uk/me/parabola/mkgmap/general/MapArea.java: Keep the full
+ bounds of empty areas.
+ * src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java: Small tidy up.
+
+2007-02-05 steve
+
+ * Makefile: Just a makefile change
+ * src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java: Fixed bug in the write
+ strategy that I'd fixed before, but lost. It looks like the
+ location of the sub-file part is incorrect in the documentation,
+ although correct in the output of imgdecode. I modified Dirent so
+ that the results were good in imgdecode. It looks like the 0x3
+ needs to go *before* the part number in the 'special' dirent.
+
+2007-02-04 steve
+
+ * src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java: Allow
+ extra space, in case the name is just one funny character. Not
+ really sure about this, just happened that there was an error.
+ * src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java: Grow
+ the buffer for any size of file.
+ * src/uk/me/parabola/imgfmt/sys/BlockManager.java,
+ src/uk/me/parabola/imgfmt/sys/BlockTable.java,
+ src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java,
+ src/uk/me/parabola/imgfmt/sys/FileNode.java,
+ src/uk/me/parabola/imgfmt/sys/SysDirEntry.java,
+ src/uk/me/parabola/log/Logger.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java: Code tidy up.
+ * src/uk/me/parabola/log/Logger.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/Way.java: I discovered that debug
+ was really happening when it shouldn't, just not being written to
+ the file. The Coord.toString method was taking considerable time.
+
+ Anyway now whole of london takes 7 seconds, down from 27 seconds.
+ * Makefile,
+ src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/sys/BlockManager.java,
+ src/uk/me/parabola/imgfmt/sys/BlockTable.java,
+ src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java,
+ src/uk/me/parabola/imgfmt/sys/FileNode.java,
+ src/uk/me/parabola/imgfmt/sys/ImgFS.java,
+ src/uk/me/parabola/imgfmt/sys/SysDirEntry.java: Now working on
+ the Garmin for the whole of london.
+
+2007-02-03 steve
+
+ * src/uk/me/parabola/mkgmap/general/MapArea.java: Format long
+ argument list.
+ * src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/general/MapLine.java,
+ src/uk/me/parabola/mkgmap/general/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestPointMap.java,
+ src/uk/me/parabola/mkgmap/main/TestAll.java: Tidy up with added
+ comments too.
+ * src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/general/MapLine.java,
+ src/uk/me/parabola/mkgmap/general/MapPoint.java,
+ src/uk/me/parabola/mkgmap/general/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java: Working fully
+ with large areas.
+
+2007-02-02 steve
+
+ * src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java: Apears to work in
+ QLandkarte anyway on the big file that will not fit into one
+ subdiv.
+
+2007-01-31 steve
+
+ * Makefile, src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/general/MapLine.java,
+ src/uk/me/parabola/mkgmap/general/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/FeatureListConverter.java: The
+ basic area splitter is now done.
+
+2007-01-22 steve
+
+ * src/uk/me/parabola/imgfmt/app/Subdivision.java: May as well
+ uncomment the old methods, rather than create new ones ;)
+ * src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/imgfmt/app/InternalFiles.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/MapObject.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/BaseEncoder.java,
+ src/uk/me/parabola/imgfmt/sys/FileNode.java,
+ src/uk/me/parabola/mkgmap/general/MapArea.java,
+ src/uk/me/parabola/mkgmap/general/MapSplitter.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestLang10Map.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestLangMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestPointMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestPolygonMap.java,
+ src/uk/me/parabola/mkgmap/osm/Element.java,
+ src/uk/me/parabola/mkgmap/osm/Node.java: Massive changes to
+ support multiple subdivisions. Many methods moved around into
+ more logical classes, so the code just looks better anyway.
+
+ Program still works in spite of all the changes.
+
+2007-01-21 steve
+
+ * src/org: Get rid of empty directories.
+
+2007-01-20 steve
+
+ * src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/osm/Way.java: Set the direction flag
+ properly now so that it goes into the map.
+ * src/uk/me/parabola/mkgmap/general/MapDataSource.java,
+ src/uk/me/parabola/mkgmap/general/MapSource.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/ReadOsm.java: Rename MapSource to
+ MapDataSource to avoid confusion with garmin product
+ * src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java,
+ src/uk/me/parabola/mkgmap/general/MapSource.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java: Comments etc while
+ thinking about changes to allow multiple divisions.
+ * build.xml: Set target in build.xml to 1.5 to prevent requiring
+ 1.6.
+
+2007-01-19 steve
+
+ * ChangeLog, README: Final changes for release.
+ * src/uk/me/parabola/imgfmt/sys/Dirent.java: Logging message change
+ * src/uk/me/parabola/mkgmap/main/CommandArgs.java: Added explicit
+ --latin1 option
+ * src/uk/me/parabola/imgfmt/app/LBLFile.java: Make an explicit
+ --latin1 option
+
+2007-01-16 steve
+
+ * src/uk/me/parabola/imgfmt/app/labelenc/BaseEncoder.java: Null
+ terminate string in simple8 format.
+ * Makefile, src/uk/me/parabola/imgfmt/app/Overview.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java: Found problem with
+ polygons not showing up. It would appear that the overview
+ sections have to be sorted by value. So sort them, and points and
+ lines for good measure too, as it may well be the same for them.
+ * src/uk/me/parabola/log/Logger.java: Added a few comments
+
+2007-01-14 steve
+
+ * Makefile, src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/BaseEncoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/EncodedText.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Latin1Encoder.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestLang10Map.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestLangMap.java,
+ src/uk/me/parabola/mkgmap/main/TestAll.java,
+ src/uk/me/parabola/mkgmap/osm/Node.java,
+ src/uk/me/parabola/tdbfmt: Code cleanup
+ * src/uk/me/parabola/imgfmt/app/labelenc,
+ src/uk/me/parabola/imgfmt/app/labelenc/BaseEncoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Bit10Encoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/CharacterEncoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/EncodedText.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Latin1Encoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Latin2Encoder.java,
+ src/uk/me/parabola/imgfmt/app/labelenc/Simple8Encoder.java,
+ src/uk/me/parabola/mkgmap/main/TestAll.java: Basic i18n code
+ done. Now for testing it.
+ * Makefile, src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/Label10.java,
+ src/uk/me/parabola/imgfmt/app/Label6.java,
+ src/uk/me/parabola/imgfmt/app/LabelLatin1.java,
+ src/uk/me/parabola/imgfmt/app/LabelLatin2.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/mkgmap/main/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestLang10Map.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestLangMap.java,
+ src/uk/me/parabola/mkgmap/main/TestAll.java: Major surgury on the
+ label system, now that it is a bit clearer how
+ internationalisation might work.
+
+2007-01-13 steve
+
+ * src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/TestAll.java: Test run through
+ different scenarios. Keeps the code coverage up now that we are
+ adding options.
+
+2007-01-10 steve
+
+ * src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/Label10.java,
+ src/uk/me/parabola/imgfmt/app/Label6.java,
+ src/uk/me/parabola/imgfmt/app/LabelLatin1.java,
+ src/uk/me/parabola/imgfmt/app/LabelLatin2.java: Reorganise label
+ text so that we can deal with different languages.
+
+2007-01-09 steve
+
+ * build.xml: Make feature list get into the built jar.
+
+2007-01-07 steve
+
+ * ChangeLog: Change log updated
+ * src/uk/me/parabola/mkgmap/main/MakeMap.java: ChangeLog updated.
+ * README, resources/feature_map.csv,
+ src/uk/me/parabola/imgfmt/app/MapObject.java,
+ src/uk/me/parabola/mkgmap/main/package.html: Getting ready for a
+ release.
+ * src/uk/me/parabola/mkgmap/osm/FeatureListConverter.java: Fix
+ treatment of points. They now show up again.
+ * src/uk/me/parabola/imgfmt/app/Point.java: Fix so that points are
+ now back on the map, rather than being located way away.
+ * src/uk/me/parabola/imgfmt/app/Label.java: Allow numbers in a name
+ and experiment with 8bit encoding of labels.
+
+2007-01-06 steve
+
+ * src/uk/me/parabola/imgfmt/app/MapObject.java,
+ src/uk/me/parabola/imgfmt/sys/ImgFS.java,
+ src/uk/me/parabola/log/Logger.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java,
+ src/uk/me/parabola/mkgmap/main/AbstractTestMap.java,
+ src/uk/me/parabola/mkgmap/main/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestPointMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestPolygonMap.java,
+ src/uk/me/parabola/mkgmap/osm/Element.java,
+ src/uk/me/parabola/mkgmap/osm/FeatureListConverter.java: Code
+ clean up.
+ * src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/LinePreparer.java,
+ src/uk/me/parabola/imgfmt/app/MapObject.java,
+ src/uk/me/parabola/imgfmt/app/Point.java,
+ src/uk/me/parabola/imgfmt/app/Polyline.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java: Changes to add
+ clarity and fix low zoom rendering.
+
+2007-01-02 steve
+
+ * Makefile, resources/feature_map.csv, scripts/mk_map_table.py,
+ src/uk/me/parabola/mkgmap/main/AbstractTestMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestPointMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestPolygonMap.java,
+ src/uk/me/parabola/mkgmap/osm/Element.java,
+ src/uk/me/parabola/mkgmap/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/osm/Way.java: Code to create artificial
+ maps that shows all different polygon or node types. This will
+ allow us to complete the feature map.
+ * src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/Overview.java,
+ src/uk/me/parabola/imgfmt/app/PointOverview.java,
+ src/uk/me/parabola/imgfmt/app/PolygonOverview.java,
+ src/uk/me/parabola/imgfmt/app/PolylineOverview.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/general/MapPoint.java,
+ src/uk/me/parabola/mkgmap/general/MapSource.java,
+ src/uk/me/parabola/mkgmap/main/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestMap.java,
+ src/uk/me/parabola/mkgmap/osm/ReadOsm.java: The overview section
+ is now generated completely from the elements that are actually
+ present in the map. Not much visible difference, but will mean
+ that all polygons show up once we add them to the features list
+ and all the POI categories will show up and none will be empty.
+
+2007-01-01 steve
+
+ * src/uk/me/parabola/mkgmap/main/MakeMap.java: Remove unused
+ varaibles.
+ * src/uk/me/parabola/mkgmap/main/CommandArgs.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java: We now have a
+ separate class to deal with the arguments. This is getting ready
+ for further changes, doesn't have much effect yet - except you
+ can finally change the mapname.
+ * ChangeLog, Makefile: Group changelog entries by day instead
+ * Makefile: The makefile I've been using for odds and ends.
+ * ChangeLog: Re-paragraphed
+ * src/uk/me/parabola/mkgmap/main/MakeMap.java: Moved adding of the
+ overview sections out of the routine to make the divisisions.
+ Both because it doesn't belong their and in preparation for
+ obtaining the overview from somewhere definitive.
+ * ChangeLog: Added the changelog to the project.
+ * src/uk/me/parabola/log/Logger.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java,
+ src/uk/me/parabola/mkgmap/main/ExitException.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java: Minor cleanups.
+ * build.xml, resources/feature_map.csv, scripts/mk_map_table.py,
+ src/uk/me/parabola/mkgmap/osm/FeatureListConverter.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java: The map featues
+ are now driven by a file. As it turns out though the OSMGarminMap
+ list of features doesn't contain all the features I was already
+ using.
+
+2006-12-31 steve
+
+ * README: Updated readme for release.
+ * src/uk/me/parabola/mkgmap/main/MakeMap.java: If the map info is
+ going to display as the map name, then lets just put the map name
+ there.
+ * src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/MapObject.java,
+ src/uk/me/parabola/imgfmt/app/Polyline.java,
+ src/uk/me/parabola/imgfmt/fs/FileSystem.java,
+ src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/imgfmt/sys/ImgFS.java,
+ src/uk/me/parabola/imgfmt/sys/ImgHeader.java,
+ src/uk/me/parabola/log/Logger.java,
+ src/uk/me/parabola/mkgmap/general/MapLine.java,
+ src/uk/me/parabola/mkgmap/general/MapShape.java,
+ src/uk/me/parabola/mkgmap/main/ExitException.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestMap.java,
+ src/uk/me/parabola/mkgmap/osm/Way.java: Big code clean up.
+ * src/uk/me/parabola/log/Logger.java: Simple logger.
+
+2006-12-30 steve
+
+ * src/uk/me/parabola/imgfmt/app/LinePreparer.java: Fixed bug where
+ base goes over 9. Able to remove a couple of fields as a result.
+ * src/uk/me/parabola/log/Logger.java: Implemented a bit of logging.
+ Will need to be made conditional.
+ * src/uk/me/parabola/mkgmap/osm/Way.java: Fixed the segment
+ ordering bug.
+ * src/uk/me/parabola/mkgmap/osm/Element.java: Check for null on
+ get.
+ * src/uk/me/parabola/mkgmap/osm/Element.java: No tag saved for
+ created_by and don't create the hashmap if it is not needed.
+ * LICENCE.log4j, build.xml, external.properties,
+ resources/MANIFEST.MF, resources/log4j-dist.properties,
+ resources/log4j.properties, src/org, src/org/apache,
+ src/org/apache/log4j,
+ src/uk/me/parabola/imgfmt/app/BitWriter.java,
+ src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/LinePreparer.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/Point.java,
+ src/uk/me/parabola/imgfmt/app/Polyline.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/fs/package.html,
+ src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java,
+ src/uk/me/parabola/imgfmt/sys/FileNode.java,
+ src/uk/me/parabola/imgfmt/sys/ImgFS.java,
+ src/uk/me/parabola/imgfmt/sys/ImgHeader.java,
+ src/uk/me/parabola/log, src/uk/me/parabola/log/Logger.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestMap.java,
+ src/uk/me/parabola/mkgmap/osm/CodedConverter.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/osm/Way.java: Removed log4j dependancy.
+ * src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/LinePreparer.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/Point.java,
+ src/uk/me/parabola/imgfmt/app/Polygon.java,
+ src/uk/me/parabola/imgfmt/app/Polyline.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java,
+ src/uk/me/parabola/imgfmt/sys/FileNode.java,
+ src/uk/me/parabola/mkgmap/general/MapCollector.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/general/MapLine.java,
+ src/uk/me/parabola/mkgmap/general/MapPoint.java,
+ src/uk/me/parabola/mkgmap/general/MapSource.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestMap.java,
+ src/uk/me/parabola/mkgmap/osm/CodedConverter.java,
+ src/uk/me/parabola/mkgmap/osm/Element.java,
+ src/uk/me/parabola/mkgmap/osm/Node.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/osm/OsmConverter.java,
+ src/uk/me/parabola/mkgmap/osm/ReadOsm.java,
+ src/uk/me/parabola/mkgmap/osm/Segment.java,
+ src/uk/me/parabola/mkgmap/osm/Way.java: Mostly a white space
+ change. Have been experimenting with getting the map description
+ to display instead of the map info as the map name.
+ * src/uk/me/parabola/imgfmt/app/Label.java: Added many special
+ characters to the translation.
+ * src/uk/me/parabola/mkgmap/main/MakeMap.java: Fix inconsistant
+ indentation
+
+2006-12-29 steve
+
+ * ., doc, scripts, scripts/checksum.py, scripts/imgfile.py,
+ scripts/munger.py, scripts/namesum.py: added scripts directory
+ for python scripts plus doc base directory. Added more to
+ svn:ignore
+ * src/uk/me/parabola/mkgmap/osm/Segment.java,
+ src/uk/me/parabola/mkgmap/osm/Way.java: Comments toString method.
+ Stuff like that.
+
+2006-12-28 steve
+
+ * src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/CodedConverter.java: adding new
+ features.
+ * src/uk/me/parabola/imgfmt/FormatException.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java,
+ src/uk/me/parabola/mkgmap/FormatException.java,
+ src/uk/me/parabola/mkgmap/general/MapSource.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/ReadOsm.java: Move FormatException
+ to its correct package. Prevents a dependancy loop
+
+2006-12-27 steve
+
+ * README: Update the readme file a bit for the release
+ * README, src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/CodedConverter.java: Added some
+ cool features, rail, woods, water. Made them show up by adding to
+ overview sections where necessary.
+ * src/uk/me/parabola/mkgmap/osm/Way.java: Bug fix to make the
+ spliting into separate lines work better without breaking into
+ all 1 segment lengths.
+
+ This will all be re-written though soon.
+ * src/uk/me/parabola/imgfmt/app/Label.java: fix compilation.
+ * src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/fs/FSOps.java,
+ src/uk/me/parabola/imgfmt/fs/FileSystem.java,
+ src/uk/me/parabola/imgfmt/sys/FileSystem.java,
+ src/uk/me/parabola/imgfmt/sys/ImgFS.java: Changed names of FSOps
+ and FileSystem.
+
+2006-12-26 steve
+
+ * src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/LinePreparer.java,
+ src/uk/me/parabola/imgfmt/app/Point.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/Node.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java: Code tidy up
+ after adding points.
+ * src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/LinePreparer.java,
+ src/uk/me/parabola/imgfmt/app/Point.java,
+ src/uk/me/parabola/mkgmap/general/MapCollector.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java,
+ src/uk/me/parabola/mkgmap/general/MapElement.java,
+ src/uk/me/parabola/mkgmap/general/MapLine.java,
+ src/uk/me/parabola/mkgmap/general/MapPoint.java,
+ src/uk/me/parabola/mkgmap/general/MapSource.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/CodedConverter.java,
+ src/uk/me/parabola/mkgmap/osm/Element.java,
+ src/uk/me/parabola/mkgmap/osm/Node.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/osm/OsmConverter.java,
+ src/uk/me/parabola/mkgmap/osm/ReadOsm.java,
+ src/uk/me/parabola/mkgmap/osm/Segment.java,
+ src/uk/me/parabola/mkgmap/osm/Way.java,
+ src/uk/me/parabola/mkgmap/osm/package.html: Add points to the
+ map. Working.
+
+2006-12-24 steve
+
+ * src/uk/me/parabola/mkgmap/osm/CodedConverter.java: Added a few
+ more feature conversions. Used the osmgarminmap feature list.
+ * src/uk/me/parabola/imgfmt/app/LinePreparer.java,
+ src/uk/me/parabola/imgfmt/app/Polyline.java: Separated out the
+ line preparation code into its own top level class
+
+2006-12-23 steve
+
+ * src/uk/me/parabola/imgfmt/app/Subdivision.java: put shift into
+ constructor and remove unused getters.
+ * src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java: Code tidy
+ * src/uk/me/parabola/imgfmt/app/Polyline.java: Fix for negative
+ number of bits.
+ * .: Ignore more junk in top directory
+ * src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestMap.java: Problem with the
+ devision pointers needed the header size taken off too. Now
+ polygons work.
+ * src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/Point.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/fs/FSOps.java,
+ src/uk/me/parabola/imgfmt/sys/BlockManager.java,
+ src/uk/me/parabola/imgfmt/sys/FileSystem.java,
+ src/uk/me/parabola/mkgmap/osm/CodedConverter.java: Code clean up.
+ * src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/WriteStrategy.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java,
+ src/uk/me/parabola/imgfmt/sys/FileNode.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestMap.java,
+ src/uk/me/parabola/mkgmap/osm/CodedConverter.java: Important fix
+ to get the size of the files correct. Needed as unit reads to the
+ end of the file and we don't want to read a bung of zeros.
+
+ Polygons draw (but no colouring or identification) but cause all
+ the lines to have no information associated with them. When you
+ hover over there is no 'tooltip' or when you click it just says
+ there is nothing there.
+ * src/uk/me/parabola/mkgmap/main/MakeMap.java: Fix imports to not
+ use *
+ * resources/log4j.properties,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/mkgmap/general/MapCollector.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java,
+ src/uk/me/parabola/mkgmap/general/MapShape.java,
+ src/uk/me/parabola/mkgmap/general/MapSource.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestMap.java,
+ src/uk/me/parabola/mkgmap/osm/CodedConverter.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/osm/ReadOsm.java: Code for adding
+ polygons is in. Doesn't work if you enable the polygons but
+ regression test is fine if they are not enabled.
+
+2006-12-22 steve
+
+ * src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/Point.java,
+ src/uk/me/parabola/imgfmt/app/Polygon.java,
+ src/uk/me/parabola/imgfmt/app/Polyline.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestMap.java: restructured
+ ready for adding points and polygons. Now the Map class is the
+ center of all activity. There is no need to leak the TRE,LBL and
+ RGN files outside of the Map class.
+
+2006-12-21 steve
+
+ * LICENCE, build.xml: Add GPL
+ * README, build.xml: Made a half decent README.
+ * build.xml, resources/log4j-dist.properties,
+ resources/log4j.properties: Changed logfile and jar names to be
+ consistant with project name
+ * build.xml: Build a usable dist directory.
+ * src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java,
+ src/uk/me/parabola/imgfmt/sys/FileSystem.java,
+ src/uk/me/parabola/mkgmap/FormatException.java,
+ src/uk/me/parabola/mkgmap/osm/Way.java: Some documentation
+ additions and changed format exception to runtime
+ * src/uk/me/parabola/mkgmap/osm/CodedConverter.java,
+ src/uk/me/parabola/mkgmap/osm/OsmConverter.java: Don't need to be
+ public.
+ * LICENCE.log4j: add licence for log4j.
+ * resources/log4j-dist.properties: added
+
+2006-12-20 steve
+
+ * README, build.xml, resources/MANIFEST.MF,
+ src/uk/me/parabola/imgfmt/app/package.html,
+ src/uk/me/parabola/imgfmt/fs/package.html,
+ src/uk/me/parabola/imgfmt/sys/package.html,
+ src/uk/me/parabola/mkgmap/general/package.html,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/package.html: Fix up build, javadoc
+ etc for release.
+ * src/uk/me/parabola/imgfmt/app/BitWriter.java,
+ src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/Polyline.java: Placed
+ isDebugEnabled around some of the frequent messages.
+ * src/uk/me/parabola/mkgmap/osm/CodedConverter.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/osm/OsmConverter.java: Prepare for a
+ converter that is not hard coded. Plus added a few road types.
+ * src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/osm/OsmConverter.java,
+ src/uk/me/parabola/mkgmap/osm/ReadOsm.java: Separate out the
+ conversion to a separate class.
+ * src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/Point.java,
+ src/uk/me/parabola/imgfmt/app/Polyline.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/fs/FSOps.java,
+ src/uk/me/parabola/imgfmt/sys/FileSystem.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java: Code tidy up.
+ * src/uk/me/parabola/mkgmap/general/MapCollector.java,
+ src/uk/me/parabola/mkgmap/general/MapLine.java,
+ src/uk/me/parabola/mkgmap/general/MapSource.java,
+ src/uk/me/parabola/mkgmap/general/package.html,
+ src/uk/me/parabola/mkgmap/osm/package.html: Documentation and
+ cleanup.
+ * src/uk/me/parabola/mkgmap/osm/ReadOsm.java: Map source is now the
+ source of the copyright message to display.
+ * src/uk/me/parabola/mkgmap/main/MakeTestMap.java: Fix the test
+ program too.
+ * src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/mkgmap/MapCollector.java,
+ src/uk/me/parabola/mkgmap/MapDetails.java,
+ src/uk/me/parabola/mkgmap/MapLine.java,
+ src/uk/me/parabola/mkgmap/MapSource.java,
+ src/uk/me/parabola/mkgmap/general,
+ src/uk/me/parabola/mkgmap/general/MapCollector.java,
+ src/uk/me/parabola/mkgmap/general/MapDetails.java,
+ src/uk/me/parabola/mkgmap/general/MapLine.java,
+ src/uk/me/parabola/mkgmap/general/MapSource.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java: Improved the
+ design by making clear what the collector actually is. It is just
+ part of the generic map handling.
+ * src/uk/me/parabola/mkgmap/main/ExitException.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java: Use exception for
+ errors leading to exit of the progrm
+ * src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/imgfmt/app/BitWriter.java,
+ src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/Coord.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/Overview.java,
+ src/uk/me/parabola/imgfmt/app/Point.java,
+ src/uk/me/parabola/imgfmt/app/Polyline.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/Zoom.java,
+ src/uk/me/parabola/imgfmt/fs/FSOps.java,
+ src/uk/me/parabola/imgfmt/fs/ImgChannel.java,
+ src/uk/me/parabola/imgfmt/sys/BlockManager.java,
+ src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java,
+ src/uk/me/parabola/imgfmt/sys/FileNode.java,
+ src/uk/me/parabola/imgfmt/sys/FileSystem.java,
+ src/uk/me/parabola/imgfmt/sys/ImgHeader.java,
+ src/uk/me/parabola/mkgmap/Filter.java,
+ src/uk/me/parabola/mkgmap/Highway.java,
+ src/uk/me/parabola/mkgmap/MapCallbacks.java,
+ src/uk/me/parabola/mkgmap/MapCollector.java,
+ src/uk/me/parabola/mkgmap/MapData.java,
+ src/uk/me/parabola/mkgmap/MapDetail.java,
+ src/uk/me/parabola/mkgmap/MapDetails.java,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestMap.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/osm/ReadOsm.java,
+ src/uk/me/parabola/mkgmap/osm/Segment.java,
+ src/uk/me/parabola/mkgmap/osm/Way.java: Big cleanup of the code.
+
+2006-12-19 steve
+
+ * src/uk/me/parabola/imgfmt/app/Polyline.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/osm/Segment.java,
+ src/uk/me/parabola/mkgmap/osm/Way.java: Some attempt to fix up
+ mis-ordered segments. Pretty good and usable map results.
+
+ Before the big cleanup.
+ * src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/Coord.java,
+ src/uk/me/parabola/imgfmt/app/Polyline.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/Zoom.java,
+ src/uk/me/parabola/imgfmt/sys/FileNode.java,
+ src/uk/me/parabola/imgfmt/sys/FileSystem.java,
+ src/uk/me/parabola/imgfmt/sys/ImgHeader.java,
+ src/uk/me/parabola/mkgmap/Filter.java,
+ src/uk/me/parabola/mkgmap/FormatException.java,
+ src/uk/me/parabola/mkgmap/Highway.java,
+ src/uk/me/parabola/mkgmap/MakeTestMap.java,
+ src/uk/me/parabola/mkgmap/MapCallbacks.java,
+ src/uk/me/parabola/mkgmap/MapCollector.java,
+ src/uk/me/parabola/mkgmap/MapData.java,
+ src/uk/me/parabola/mkgmap/MapDetail.java,
+ src/uk/me/parabola/mkgmap/MapDetails.java,
+ src/uk/me/parabola/mkgmap/MapLine.java,
+ src/uk/me/parabola/mkgmap/MapSource.java,
+ src/uk/me/parabola/mkgmap/main,
+ src/uk/me/parabola/mkgmap/main/MakeMap.java,
+ src/uk/me/parabola/mkgmap/main/MakeTestMap.java,
+ src/uk/me/parabola/mkgmap/osm/OSMXmlHandler.java,
+ src/uk/me/parabola/mkgmap/osm/ReadOsm.java,
+ src/uk/me/parabola/mkgmap/osm/Segment.java,
+ src/uk/me/parabola/mkgmap/osm/Way.java: Fixed case where all the
+ same sign quantities should be saved as positive and not as twos
+ compliment.
+
+ Map now works. Remaining problems appear to be in unordered
+ segments in the source.
+
+2006-12-18 steve
+
+ * src/uk/me/parabola/imgfmt/app/TREFile.java: Remove hacky, not
+ understood, flags section.
+ * src/uk/me/parabola/mkgmap/MakeTestMap.java: This is part of the
+ working map generating.
+ * src/uk/me/parabola/imgfmt/app/TREFile.java: Finally working with
+ the short TRE header length. We should now be able to use any
+ name.
+ * src/uk/me/parabola/imgfmt/Utils.java: Fix byte ordering and
+ subtrace 1900 from the year in the common header date. If the
+ high bits are set in the date field the map does not load.
+
+2006-12-17 steve
+
+ * .: More ignored directories.
+ * src/uk/me/parabola/imgfmt/app/Polyline.java: Use lon instead of
+ lng
+
+2006-12-16 steve
+
+ * src/uk/me/parabola/mkgmap,
+ src/uk/me/parabola/mkgmap/MakeTestMap.java,
+ src/uk/me/parabola/mkgmap/MapSource.java,
+ src/uk/me/parabola/mkgmap/img, src/uk/me/parabola/mkgmap/osm,
+ src/uk/me/parabola/mkosmgmap: Package moved.
+ * src/uk/me/parabola/mkosmgmap/osm,
+ src/uk/me/parabola/mkosmgmap/osm/ReadOsm.java: Added the osm
+ directory.
+ * src/uk/me/parabola/mkosmgmap/MakeTestMap.java: And indeed lets
+ add the code to make the test map.
+ * src/uk/me/parabola/imgfmt/Utils.java,
+ src/uk/me/parabola/imgfmt/app/BitWriter.java,
+ src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/Polyline.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/fs/ImgChannel.java,
+ src/uk/me/parabola/imgfmt/sys/FileNode.java,
+ src/uk/me/parabola/imgfmt/sys/FileSystem.java,
+ src/uk/me/parabola/mkosmgmap/MapSource.java,
+ src/uk/me/parabola/mkosmgmap/img,
+ src/uk/me/parabola/mkosmgmap/osm: Working test map with streets
+ that test various features of the code.
+
+2006-12-12 steve
+
+ * src/uk/me/parabola/imgfmt/app/Polyline.java: Saving work as this
+ is a complicated bit and may not work on it for a while.
+ * src/uk/me/parabola/imgfmt/Utils.java,
+ src/uk/me/parabola/imgfmt/app/Area.java,
+ src/uk/me/parabola/imgfmt/app/Bounds.java,
+ src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/Coord.java,
+ src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/MapObject.java,
+ src/uk/me/parabola/imgfmt/app/Overview.java,
+ src/uk/me/parabola/imgfmt/app/Point.java,
+ src/uk/me/parabola/imgfmt/app/Polyline.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/Writable.java,
+ src/uk/me/parabola/imgfmt/app/WriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/Zoom.java,
+ src/uk/me/parabola/imgfmt/fs/package.html,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java,
+ src/uk/me/parabola/imgfmt/sys/FileNode.java,
+ src/uk/me/parabola/imgfmt/sys/package.html: Started on polylines.
+ General javadoc rampage.
+
+2006-12-11 steve
+
+ * README, resources/log4j.properties,
+ src/uk/me/parabola/imgfmt/app/Coord.java,
+ src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/Overview.java,
+ src/uk/me/parabola/imgfmt/app/Point.java,
+ src/uk/me/parabola/imgfmt/app/Polyline.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/Zoom.java,
+ src/uk/me/parabola/imgfmt/sys/Directory.java: Working but empty
+ map. worked with points, but I am now going on to lines to get
+ roads.
+ * src/uk/me/parabola/imgfmt/app/Label.java: Fix the end of label
+ marker/length. Before labels that were a multiple of 4 bytes were
+ not ended.
+
+2006-12-10 steve
+
+ * src/uk/me/parabola/imgfmt/app/Bounds.java,
+ src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/Point.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/WriteStrategy.java,
+ src/uk/me/parabola/imgfmt/sys/FileNode.java: Oh well still not
+ recognised. I've padded out the last block to be a full block. No
+ go.
+
+2006-12-09 steve
+
+ * src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/Overview.java,
+ src/uk/me/parabola/imgfmt/app/Subdivion.java,
+ src/uk/me/parabola/imgfmt/app/Subdivision.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/Writable.java,
+ src/uk/me/parabola/imgfmt/app/Zoom.java: Interesting point,
+ getting very close to having a 'complete' map, but still no joy
+ in getting my unit to recognise it.
+ * src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/WriteStrategy.java: Got a label
+ referenced from the copyright section of the TRE header.
+ * src/uk/me/parabola/imgfmt/Utils.java,
+ src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/Label.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/WriteStrategy.java,
+ src/uk/me/parabola/imgfmt/sys/ImgFile.java: Its all a bit neater
+ now.
+
+2006-12-07 steve
+
+ * src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/WriteStrategy.java: Somewhat more
+ works now.
+ * src/uk/me/parabola/imgfmt/app/Bounds.java,
+ src/uk/me/parabola/imgfmt/app/BufferedWriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/Subdivion.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/WriteStrategy.java,
+ src/uk/me/parabola/imgfmt/app/Zoom.java,
+ src/uk/me/parabola/imgfmt/fs/ImgChannel.java: Got some zoom and
+ subdivision classes Working on a write strategy to start with.
+ Not in a working state.
+
+2006-12-05 steve
+
+ * src/uk/me/parabola/imgfmt/Utils.java,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java: Something reasonable
+ is now written into all the headers. No data at all whatsoever.
+
+2006-12-03 steve
+
+ * src/uk/me/parabola/imgfmt/Utils.java,
+ src/uk/me/parabola/imgfmt/app,
+ src/uk/me/parabola/imgfmt/app/ImgFile.java,
+ src/uk/me/parabola/imgfmt/app/LBLFile.java,
+ src/uk/me/parabola/imgfmt/app/Map.java,
+ src/uk/me/parabola/imgfmt/app/RGNFile.java,
+ src/uk/me/parabola/imgfmt/app/TREFile.java,
+ src/uk/me/parabola/imgfmt/app/package.html,
+ src/uk/me/parabola/imgfmt/fs/ImgChannel.java,
+ src/uk/me/parabola/imgfmt/sys/BlockAllocator.java,
+ src/uk/me/parabola/imgfmt/sys/BlockManager.java,
+ src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java,
+ src/uk/me/parabola/imgfmt/sys/FileNode.java,
+ src/uk/me/parabola/imgfmt/sys/FileSystem.java,
+ src/uk/me/parabola/imgfmt/sys/ImgHeader.java: Got some kind of
+ common headers being written out.
+ * src/uk/me/parabola/imgfmt/FileExistsException.java,
+ src/uk/me/parabola/imgfmt/FileSystemParam.java,
+ src/uk/me/parabola/imgfmt/fs/FSOps.java,
+ src/uk/me/parabola/imgfmt/sys/BlockAllocator.java,
+ src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/imgfmt/sys/DirectoryEntryImpl.java,
+ src/uk/me/parabola/imgfmt/sys/Dirent.java,
+ src/uk/me/parabola/imgfmt/sys/FileNode.java,
+ src/uk/me/parabola/imgfmt/sys/FileSystem.java,
+ src/uk/me/parabola/imgfmt/sys/FileSystemParam.java,
+ src/uk/me/parabola/imgfmt/sys/ImgHeader.java: Can create files.
+
+2006-12-02 steve
+
+ * resources/log4j.properties,
+ src/uk/me/parabola/imgfmt/fs/FSOps.java,
+ src/uk/me/parabola/imgfmt/fs/FileChannel.java,
+ src/uk/me/parabola/imgfmt/fs/ImgChannel.java,
+ src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/imgfmt/sys/DirectoryEntryImpl.java,
+ src/uk/me/parabola/imgfmt/sys/FileSystem.java,
+ src/uk/me/parabola/imgfmt/sys/FileSystemParam.java,
+ src/uk/me/parabola/imgfmt/sys/ImgHeader.java: Pretty much the
+ basic structure there for directory entries.
+ * src/uk/me/parabola/imgfmt/fs/DirectoryEntry.java,
+ src/uk/me/parabola/imgfmt/fs/FSOps.java,
+ src/uk/me/parabola/imgfmt/fs/FileChannel.java,
+ src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/imgfmt/sys/DirectoryEntry.java,
+ src/uk/me/parabola/imgfmt/sys/DirectoryEntryImpl.java,
+ src/uk/me/parabola/imgfmt/sys/FileSystem.java,
+ src/uk/me/parabola/imgfmt/sys/ImgFile.java,
+ src/uk/me/parabola/imgfmt/sys/ImgHeader.java: Getting the
+ interface structure better.
+ * src/uk/me/parabola/imgfmt, src/uk/me/parabola/imgfmt/fs,
+ src/uk/me/parabola/imgfmt/sys,
+ src/uk/me/parabola/imgfmt/sys/Directory.java,
+ src/uk/me/parabola/imgfmt/sys/DirectoryEntry.java,
+ src/uk/me/parabola/imgfmt/sys/FileSystem.java,
+ src/uk/me/parabola/imgfmt/sys/ImgFile.java,
+ src/uk/me/parabola/imgfmt/sys/ImgHeader.java: Files really added
+ to new location this time
+ * src/uk/me/parabola/mkosmgmap/img/Directory.java,
+ src/uk/me/parabola/mkosmgmap/img/DirectoryEntry.java,
+ src/uk/me/parabola/mkosmgmap/img/FileSystem.java,
+ src/uk/me/parabola/mkosmgmap/img/ImgFile.java,
+ src/uk/me/parabola/mkosmgmap/img/ImgHeader.java: Files moved to
+ new imgfmt sub-packages.
+
+2006-11-30 steve
+
+ * src/uk/me/parabola/mkosmgmap/img/ImgHeader.java: Corrected
+ 'number of sectors'
+ * src/uk/me/parabola/mkosmgmap/img/Directory.java,
+ src/uk/me/parabola/mkosmgmap/img/DirectoryEntry.java,
+ src/uk/me/parabola/mkosmgmap/img/FileSystem.java,
+ src/uk/me/parabola/mkosmgmap/img/ImgHeader.java: Header finished,
+ starting on the directory.
+
+2006-11-28 steve
+
+ * build.xml, src/uk/me/parabola/mkosmgmap/img/Directory.java,
+ src/uk/me/parabola/mkosmgmap/img/FAT.java,
+ src/uk/me/parabola/mkosmgmap/img/FileSystem.java,
+ src/uk/me/parabola/mkosmgmap/img/ImgHeader.java,
+ src/uk/me/parabola/mkosmgmap/img/PartitionTable.java: progress on
+ the header.
+
+2006-11-26 steve
+
+ * ., README, build.xml, external.properties, resources,
+ resources/log4j.properties, src, src/uk, src/uk/me,
+ src/uk/me/parabola, src/uk/me/parabola/mkosmgmap,
+ src/uk/me/parabola/mkosmgmap/img,
+ src/uk/me/parabola/mkosmgmap/img/FAT.java,
+ src/uk/me/parabola/mkosmgmap/img/FileSystem.java,
+ src/uk/me/parabola/mkosmgmap/img/ImgFile.java,
+ src/uk/me/parabola/mkosmgmap/img/ImgHeader.java,
+ src/uk/me/parabola/mkosmgmap/img/PartitionTable.java,
+ src/uk/me/parabola/mkosmgmap/osm: Initial checkin. Mostly empty
+ files. Structure set up and ant file works.
+ * branches, releases, tags, .: Created mkosmgmap project
+
diff --git a/LICENCE b/LICENCE
new file mode 100644
index 0000000..eeb586b
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..de2ff53
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,137 @@
+
+#
+# This is NOT used to build mkgmap. To build use ant.
+#
+#
+#
+
+#OSMDATA = areas.osm
+#OSMDATA = 63240001.mp
+OSMDATA = localtest/osm5/cricklewood-5.osm
+#OSMDATA = maps/lon.mp
+#OSMDATA = --mapname=90000001 test-map:all-elements
+#OSMDATA = /opt/data/uk-071010-1.osm.gz /opt/data/uk-071010-2.osm.gz
+# takes 31s on trunk-681
+OSMDATA = /opt/data/uk-071010-1.osm.gz
+#OSMDATA = test/osm5/srtm.osm
+#OSMDATA = --latin1 /opt/data/osmworld/*.gz
+#OSMDATA = /opt/data/uk-071114.osm.gz
+#OSMDATA = localtest/osm5/reg40.osm
+#OSMDATA = localtest/osm5/longline.osm
+#OSMDATA = localtest/osm5/reg04.osm
+#OSMDATA = --charset=unicode localtest/osm/czech_test.osm
+#OSMDATA = --tdbfile maps/img/*.img
+#OSMDATA = --tdbfile --gmapsupp /opt/data/uk/63*
+#OSMDATA = test/samples/test.osm
+#OSMDATA = seqld.osm.gz
+#OSMDATA = --net --style=default --name-tag-list='name:en int_name name' test.osm
+#OSMDATA = /opt/data/uk-test-1.osm.gz
+#OSMDATA = /opt/data/uk-lon.osm
+#OSMDATA = other.mp
+
+
+TIME=/usr/bin/time --format 'Real: %E, %S+%U'
+
+OPTS= --tdbfile
+#OPTS= --route --tdbfile --tdb-v4
+OPTS=--tdbfile --family-id=909 --series-name="other map" --description='A test map'
+
+makemap: clean
+ $(TIME) java -XX:+UseCompressedOops -Xmx700m -cp build/classes uk.me.parabola.mkgmap.main.Main $(OPTS) $(OSMDATA)
+ #cp 63240001.img gmapsupp.img
+ #imgdecode gmapsupp.img
+
+t:
+ java -Dlog.config=l -ea -cp build/classes uk.me.parabola.mkgmap.main.Main $(OPTS) $(OSMDATA)
+
+base: clean
+ $(TIME) java -cp build/classes uk.me.parabola.mkgmap.main.Main /opt/data/uk-test-1.osm.gz
+ cp 63240001.img gmapsupp.img
+ imgdecode gmapsupp.img
+
+other: clean
+ java -Dlog.config=l -ea -cp build/classes uk.me.parabola.mkgmap.main.Main \
+ --tdbfile --tdb-v4 --levels=0:24 --route 63240001.mp
+ cp 63240001.img gmapsupp.img
+ imgdecode gmapsupp.img
+
+.PHONY: clean
+clean:
+ rm -f 6324000?/* gmapsupp/* mkgmap.log out.log
+ rm -f gmapsupp.img 632*.img
+ if [ -d 63240001 ]; then rmdir 6324000?; fi
+ rm -f 11112222.img 11112222.tdb
+ rm -f osmmap*
+ rm -f ovm_*.img
+ rm -f g?.img
+ rm -f styletester.style
+ rm -f test.*
+
+load:
+ sleep 2
+ -surun mount /media/disk
+ surun cp gmapsupp.img /media/disk/Garmin/gmapsupp.img
+ surun umount /media/disk
+
+
+map-features map_features:
+ python scripts/mk_map_table.py resources/garmin_feature_list.csv \
+ resources/osm_garmin_map.csv | sort > resources/map-features.csv
+
+test:
+ rm -fr gmapsupp/
+ rm -f 32860003.img
+ java -ea -cp build/classes uk.me.parabola.mkgmap.main.MakeTestMap
+
+# Set values of BASE_LAT and BASE_LONG in your environment to be near your
+# present location.
+test_element:
+ rm -fr gmapsupp/ 32860003
+ rm -f 32860003.img
+ java -ea -cp build/classes uk.me.parabola.mkgmap.main.MakeTestElementMap $$BASE_LAT $$BASE_LONG
+ imgdecode 32860003.img
+
+test_point:
+ rm -fr gmapsupp/ 32860003
+ rm -f 32860003.img
+ java -ea -cp build/classes uk.me.parabola.mkgmap.main.MakeTestPointMap $$BASE_LAT $$BASE_LON
+ imgdecode 32860003.img
+
+test_lang:
+ rm -fr gmapsupp/ 32860003
+ rm -f 32860003.img
+ java -ea -cp build/classes uk.me.parabola.mkgmap.main.MakeTestLangMap $$BASE_LAT $$BASE_LON
+ imgdecode 32860003.img
+
+test_lang10:
+ rm -fr gmapsupp/ 32860003
+ rm -f 32860003.img
+ java -ea -Dlog.filename=out.log -cp build/classes uk.me.parabola.mkgmap.main.MakeTestLang10Map $$BASE_LAT $$BASE_LON
+ imgdecode 32860003.img
+
+tests:
+ java -ea -cp build/classes uk.me.parabola.mkgmap.main.Main localtest/osm/empty.osm
+ java -ea -cp build/classes uk.me.parabola.mkgmap.main.Main localtest/osm/reg40.osm
+ java -ea -cp build/classes uk.me.parabola.mkgmap.main.Main localtest/osm/reg71.osm
+ java -ea -cp build/classes uk.me.parabola.mkgmap.main.Main localtest/osm/cricklewood-5.osm
+ java -ea -cp build/classes uk.me.parabola.mkgmap.main.Main localtest/osm/reg04.osm
+ java -ea -cp build/classes uk.me.parabola.mkgmap.main.Main localtest/osm/reg04b.osm
+ java -ea -cp build/classes uk.me.parabola.mkgmap.main.Main localtest/osm/rus.osm
+ java -ea -cp build/classes uk.me.parabola.mkgmap.main.Main /opt/data/germany-070823.osm.gz
+ java -ea -cp build/classes uk.me.parabola.mkgmap.main.Main /opt/data/uk-070815.osm.gz
+ java -ea -cp build/classes uk.me.parabola.mkgmap.main.Main localtest/osm5/bit-assert-fail.osm
+
+
+tl:
+ -mount /media/disk
+ cp 32860003.img /media/disk/Garmin/gmapsupp.img
+ umount /media/disk
+
+munge:
+ cp pp.bak pp
+ python munger.py
+ cp pp gmapsupp.img
+
+changelog:
+ svn update
+ svn2cl --group-by-day --reparagraph
diff --git a/README b/README
new file mode 100644
index 0000000..0772487
--- /dev/null
+++ b/README
@@ -0,0 +1,85 @@
+
+Making maps for Garmin GPS units
+================================
+
+The goal of the project is to take the map data from
+OpenStreetMap <http://www.openstreetmap.org>
+and to generate a map in the Garmin file format so
+that it can be loaded onto Garmin GPS units.
+
+The original motivation was to help plan mapping sessions,
+but now the maps are becoming useful in their own right.
+
+Using
+=====
+
+This program requires Java 1.6 or above to run.
+
+Producing a map is simple. Save OpenStreetMap data from JOSM
+or by any other method to a file and copy it to the mkgmap
+directory. In the following examples this file is called data.osm.
+
+Run the command:
+
+ java -jar mkgmap.jar data.osm
+
+This will produce a file called 63240001.img.
+
+You can copy the map to your Garmin GPS unit in any way you know how.
+It is best to use a SD card, since then if anything goes wrong you
+can remove it from the unit and all should be well again.
+
+Copy it to the file "Garmin/gmapsupp.img" on the card.
+On many modern Garmin devices, you can use a different
+name so that you can have more than one set of maps.
+
+*NOTE* this will overwrite any other map you have on
+there, make sure that you are not overwriting a valuable map.
+
+Another way would be to use a USB memory card writer and
+for a large map this is quicker as many GPS's have a slow USB
+connection.
+
+There are also various programs that can send a map to the
+device.
+
+You should (depending on the particular Garmin model) see a OSM
+copyright message on starting up, and the map name 'OSM Street map'
+should appear in the map setup section.
+
+For more help see: http://www.mkgmap.org.uk/doc/index.html
+
+
+Invoking mkgmap
+--------------
+
+Most of the default names mentioned in the previous section can be altered
+by suitable options. Run
+
+ java -jar mkgmap.jar --help=options
+
+to obtain an up to date and complete listing of options.
+
+Processing more than one file at a time
+---------------------------------------
+
+The Garmin map format was designed so that a map is made of a number
+of tiles, and if your map has more data than can fit into a single
+tile, you will have to split the map.
+
+See: http://www.mkgmap.org.uk/doc/splitter.html for a program that
+can do this.
+
+You can compile all of the map tiles that are created by splitter
+all at once, by simply listing them all on the command line.
+
+Acknowledgements
+================
+
+This project is almost entirely based on the file format specification
+document written by John Mechalas at the SourceForge project at
+http://sourceforge.net/projects/garmin-img. The 'imgdecode' program
+from the same source was also very important in checking that I was
+on the right lines to producing a good file. Thanks.
+
+Steve
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..5ad2fc9
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,449 @@
+<?xml version="1.0"?>
+<!--
+ File: build.xml
+
+ Copyright (C) 2006, 2012 mkgmap contributors
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 or
+ version 3 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.
+
+ Create date: 26 Nov 2006
+-->
+<project name="mkgmap" default="dist" basedir="."
+ xmlns:ivy="antlib:org.apache.ivy.ant">
+
+ <!-- Set default javac target value -->
+ <property name="ant.build.javac.target" value="1.7"/>
+ <property name="ant.build.javac.source" value="1.7"/>
+
+ <property name="project.name" value="${ant.project.name}"/>
+
+ <!-- Init -->
+ <property name="top" value="."/>
+
+ <!-- Instead of modifying external.properties, you can create a file called
+ local.properties instead. Anything defined in the local.properties file will
+ override properties defined later
+ -->
+ <!--suppress AntResolveInspection,AntMissingPropertiesFileInspection -->
+ <property file="${top}/local.properties"/>
+
+ <property name="build" value="build"/>
+ <property name="dist" value="dist"/>
+
+ <property name="build.classes" value="${build}/classes"/>
+ <property name="build.test" value="${build}/test"/>
+
+ <property name="src" value="src"/>
+ <property name="test" value="test"/>
+
+ <property name="doc" value="doc"/>
+ <property name="javadoc" value="${doc}/api"/>
+ <property name="resources" value="resources"/>
+
+ <property name="project.jar" value="${dist}/${project.name}.jar"/>
+
+ <!-- A place to keep a local copy of the test input data. The test files
+ are large and so are not kept in svn. If you don't set this then they
+ will be downloaded.
+
+ You can set it in the external.properties file too.
+ -->
+ <property name="test.input.cache" value="/opt/data/testinput"/>
+
+ <!-- the project's version number -->
+ <tstamp>
+ <format property="build.timestamp" pattern="yyyy-MM-dd'T'HH:mm:ssZ" />
+ </tstamp>
+
+ <!-- ivy dependency support -->
+ <property name="ivy.version" value="2.2.0"/>
+ <property name="ivy.lib.dir" value="${basedir}/lib" />
+ <property name="ivy.jar.dir" value="${ivy.lib.dir}/build" />
+ <property name="ivy.retrieve.pattern" value="${ivy.lib.dir}/[conf]/[artifact]-[revision].[ext]" />
+ <property name="ivy.distrib.dir" value="ivy-distrib" />
+
+ <!-- For class paths -->
+ <path id="compile.classpath">
+ <fileset dir="${ivy.lib.dir}/compile" />
+ </path>
+ <path id="test.classpath">
+ <fileset dir="${ivy.lib.dir}/test" />
+ </path>
+ <path id="optional.classpath">
+ <fileset dir="${ivy.lib.dir}/optional" />
+ </path>
+
+ <path id="main">
+ <pathelement location="${build.classes}" />
+ <path refid="compile.classpath" />
+ <path refid="optional.classpath" />
+ </path>
+
+ <path id="test">
+ <pathelement location="test/resources"/>
+ <pathelement location="build/test"/>
+ <path refid="test.classpath" />
+ <pathelement location="${build.classes}" />
+ <pathelement location="test"/>
+ </path>
+
+ <!-- ******************** TARGETS ******************** -->
+
+ <!-- targets for downloading and registering ivy -->
+ <target name="ivy-availability" description="Checks if the ivy library is available">
+ <property name="ivy.jar.file" value="${ivy.jar.dir}/ivy-${ivy.version}.jar" />
+ <available property="ivy.available" file="${ivy.jar.file}" />
+ </target>
+
+ <target name="download-ivy" unless="ivy.available" description="Downloads the ivy library from public repositories.">
+ <delete dir="${ivy.jar.dir}"/>
+ <mkdir dir="${ivy.jar.dir}" />
+ <get src="http://repo1.maven.org/maven2/org/apache/ivy/ivy/${ivy.version}/ivy-${ivy.version}.jar"
+ dest="${ivy.jar.file}" usetimestamp="true"/>
+ </target>
+
+ <target name="init-ivy" depends="ivy-availability, download-ivy" description="Registers ivy with ant and initializes it." unless="ivy.initialized">
+ <path id="ivy.lib.path">
+ <fileset dir="${ivy.jar.dir}" includes="*.jar" />
+ </path>
+ <taskdef resource="org/apache/ivy/ant/antlib.xml"
+ uri="antlib:org.apache.ivy.ant"
+ classpathref="ivy.lib.path" />
+ <ivy:configure />
+ <ivy:info />
+ <property name="ivy.initialized" value="true"/>
+ </target>
+
+ <!-- targets for fetching dependencies via ivy -->
+ <target name="resolve-compile" depends="init-ivy" description="Downloads compile dependencies using ivy.">
+ <ivy:retrieve conf="compile" log="download-only" />
+ </target>
+ <target name="resolve-test" depends="init-ivy" description="Downloads test program dependencies using ivy.">
+ <ivy:retrieve conf="test" log="download-only"/>
+ </target>
+ <target name="resolve-macker" depends="init-ivy" description="Downloads macker program dependencies using ivy.">
+ <ivy:retrieve conf="macker" log="download-only"/>
+ </target>
+ <target name="resolve-optional" depends="init-ivy" description="Downloads optional program dependencies using ivy.">
+ <ivy:retrieve conf="optional" log="download-only"/>
+ </target>
+ <target name="resolve" depends="resolve-compile, resolve-test, resolve-macker, resolve-optional"
+ description="Downloads all program dependencies using ivy." />
+
+ <!-- targets for publishing the project (locally) via ivy -->
+ <target name="publish" depends="dist">
+ <copy file="${project.jar}"
+ tofile="${ivy.distrib.dir}/jars/${project.name}-${project.version}.jar"/>
+ <ivy:deliver pubrevision="${project.version}"/>
+ <ivy:publish resolver="local" pubrevision="${project.version}" overwrite="true"/>
+ </target>
+
+ <!-- Prepare - make all the directories -->
+ <target name="prepare">
+ <mkdir dir="${build.classes}" />
+ <mkdir dir="${ivy.lib.dir}/optional"/>
+
+ <property environment="env"/>
+
+ <condition property="have.svn">
+ <and>
+ <available file="${top}/.svn"/>
+ <or>
+ <available file="svnversion" filepath="${env.PATH}"/>
+ <available file="svnversion.exe" filepath="${env.PATH}"/>
+ <available file="svnversion.exe" filepath="${env.Path}"/>
+ </or>
+ </and>
+ </condition>
+ <condition property="have.git">
+ <available file="${top}/.git"/>
+ </condition>
+ </target>
+
+ <target name="svn-version" if="have.svn">
+ <exec executable="svnversion" dir="${top}" logError="false"
+ outputproperty="svn.version.tmp" resultproperty="svnversion.result"
+ failifexecutionfails="false">
+ <arg value="-n" /><arg value="-c" />
+ <redirector><outputfilterchain><tokenfilter>
+ <replaceregex pattern="^([0-9]*:)?" replace="" />
+ <replaceregex pattern="^exported$" replace="" />
+ </tokenfilter></outputfilterchain></redirector>
+ </exec>
+ <condition property="svn.version.build" value="${svn.version.tmp}" else="unknown">
+ <and>
+ <isset property="svn.version.tmp" />
+ <equals arg1="${svnversion.result}" arg2="0" />
+ <not><equals arg1="${svn.version.tmp}" arg2="" /></not>
+ </and>
+ </condition>
+
+ <property name="project.version" value="${svn.version.build}" />
+ </target>
+
+ <target name="git-version" if="have.git">
+ <exec executable="git" dir="${top}" logError="false"
+ outputproperty="git.version.tmp" resultproperty="gitdescribe.result"
+ failifexecutionfails="false">
+ <arg value="describe" /><arg value="--dirty" /><arg value="--tags" /><arg value="--always" />
+ </exec>
+ <condition property="git.version.build" value="${git.version.tmp}">
+ <and>
+ <isset property="git.version.tmp" />
+ <equals arg1="${gitdescribe.result}" arg2="0" />
+ <not><equals arg1="${git.version.tmp}" arg2="" /></not>
+ </and>
+ </condition>
+ <property name="project.version" value="${git.version.build}" />
+ </target>
+
+ <target name="check-version" depends="svn-version, git-version">
+ <property file="${build.classes}/mkgmap-version.properties"/>
+ <condition property="have.version">
+ <or>
+ <and>
+ <isset property="have.svn"/>
+ <equals arg1="${svn.version.build}" arg2="${svn.version}"/>
+ </and>
+ <and>
+ <not><isset property="have.svn"/></not>
+ <available file="${build}/classes/mkgmap-version.properties"/>
+ </and>
+ </or>
+ </condition>
+ </target>
+
+ <target name="version-file" unless="have.version">
+ <property name="project.version" value="${build.timestamp}" />
+ <property name="svn.version.build" value="unknown"/>
+
+ <propertyfile file="${build.classes}/mkgmap-version.properties">
+ <entry key="svn.version" value="${svn.version.build}" />
+ <entry key="build.timestamp" value="${build.timestamp}" />
+ </propertyfile>
+ </target>
+
+ <!-- Compile the product itself (no tests). -->
+ <target name="compile" depends="prepare, resolve-compile"
+ description="main compilation">
+
+ <javac srcdir="${src}" destdir="${build.classes}" encoding="utf-8" debug="true" includeantruntime="false">
+ <include name="**/*.java" />
+ <classpath refid="main"/>
+ <exclude name="**/optional/*.java"/>
+ </javac>
+ </target>
+
+ <!-- Build into the build direcotory. All resource files are copied in. -->
+ <target name="build" depends="compile" description="Build everything into the build direcotory">
+ <copy todir="${build.classes}">
+ <fileset dir="${resources}">
+ <include name="*.csv"/>
+ <include name="*.properties"/>
+ <include name="*.xml"/>
+ <include name="**/*.trans"/>
+ <include name="styles/**"/>
+ <include name="help/**"/>
+ <include name="installer/**"/>
+ <include name="sort/**"/>
+ <exclude name="**/.*"/>
+ </fileset>
+ <fileset dir="src">
+ <include name="**/*.properties"/>
+ </fileset>
+ </copy>
+ </target>
+
+ <!-- Compile the test classes -->
+ <target name="build-test" depends="build, resolve-test">
+ <mkdir dir="${build.test}" />
+ <javac srcdir="${test}" destdir="${build.test}" encoding="utf-8" debug="true" includeantruntime="false">
+ <include name="**/*.java" />
+ <classpath refid="test"/>
+ </javac>
+ </target>
+
+ <target name="test" depends="build-test, obtain-test-input-files" description="Run the junit tests">
+ <mkdir dir="tmp/report"/>
+ <junit printsummary="yes" failureproperty="junit.failure">
+
+ <classpath refid="test"/>
+ <formatter type="xml"/>
+
+ <assertions>
+ <enable/>
+ </assertions>
+
+ <batchtest fork="yes" todir="tmp/report">
+ <fileset dir="test">
+ <include name="**/*Test.java"/>
+
+ <!-- These are standalone tests, not unit tests. -->
+ <exclude name="main/**"/>
+ </fileset>
+ </batchtest>
+ </junit>
+ <junitreport todir="tmp">
+ <fileset dir="tmp/report"/>
+ <report todir="test-reports"/>
+ </junitreport>
+ <fail if="junit.failure" message="Test failed. See test-reports/index.html"/>
+ </target>
+
+ <target name="obtain-test-input-files" description="download the input files for the functional tests">
+ <!-- Local cache, if it doesn't exist then it is not a problem the files
+ will be downloaded in the next step -->
+ <copy todir="test/resources/in" failonerror="false">
+ <fileset dir="${test.input.cache}" includes="**"/>
+ </copy>
+ <mkdir dir="test/resources/in/osm"/>
+ <mkdir dir="test/resources/in/mp"/>
+ <mkdir dir="test/resources/in/img"/>
+ <get src="http://www.mkgmap.org.uk/testinput/osm/lon1.osm.gz"
+ dest="test/resources/in/osm/lon1.osm.gz" usetimestamp="true"
+ ignoreerrors="true"/>
+ <get src="http://www.mkgmap.org.uk/testinput/osm/uk-test-1.osm.gz"
+ dest="test/resources/in/osm/uk-test-1.osm.gz" usetimestamp="true"
+ ignoreerrors="true"/>
+ <get src="http://www.mkgmap.org.uk/testinput/osm/uk-test-2.osm.gz"
+ dest="test/resources/in/osm/uk-test-2.osm.gz" usetimestamp="true"
+ ignoreerrors="true"/>
+ <get src="http://www.mkgmap.org.uk/testinput/mp/test1.mp"
+ dest="test/resources/in/mp/test1.mp" usetimestamp="true"
+ ignoreerrors="true"/>
+ <get src="http://www.mkgmap.org.uk/testinput/img/63240001.img"
+ dest="test/resources/in/img/63240001.img" usetimestamp="true"
+ ignoreerrors="true"/>
+ <get src="http://www.mkgmap.org.uk/testinput/img/63240002.img"
+ dest="test/resources/in/img/63240002.img" usetimestamp="true"
+ ignoreerrors="true"/>
+ <get src="http://www.mkgmap.org.uk/testinput/img/63240003.img"
+ dest="test/resources/in/img/63240003.img" usetimestamp="true"
+ ignoreerrors="true"/>
+ </target>
+
+ <target name="dist" depends="build, check-version, version-file"
+ description="Make the distribution area">
+
+ <mkdir dir="${dist}"/>
+ <mkdir dir="${dist}/lib"/>
+
+ <copy todir="${dist}/lib" flatten="true">
+ <path refid="compile.classpath" />
+ </copy>
+
+ <manifestclasspath property="manifest_cp" jarfile="${project.jar}">
+ <classpath>
+ <fileset dir="${dist}/lib">
+ <include name="**/*.jar" />
+ </fileset>
+ </classpath>
+ </manifestclasspath>
+
+ <!-- Make the jar -->
+ <jar basedir="${build.classes}" jarfile="${project.jar}">
+ <manifest>
+ <attribute name="Main-Class" value="uk.me.parabola.mkgmap.main.Main" />
+ <attribute name="Class-Path" value="${manifest_cp}" />
+ <attribute name="Implementation-Version" value="${project.version}" />
+ </manifest>
+ <include name="**/*.class"/>
+ <include name="*.csv"/>
+ <include name="*.xml"/>
+ <include name="*.properties"/>
+ <include name="**/*.trans"/>
+ <include name="styles/**"/>
+ <include name="sort/**"/>
+ <include name="help/**"/>
+ <include name="installer/**"/>
+ </jar>
+
+ <copy todir="${dist}/doc" >
+ <fileset dir="doc">
+ <include name="README"/>
+ <include name="mkgmap.1"/>
+ </fileset>
+ </copy>
+
+ <!-- misc to be copied to the top level -->
+ <copy todir="${dist}" flatten="true">
+ <fileset dir="${basedir}">
+ <include name="README"/>
+ <include name="LICENCE*"/>
+ </fileset>
+ </copy>
+
+ <mkdir dir="${dist}/examples"/>
+
+ <copy todir="${dist}/examples">
+ <fileset dir="resources">
+ <include name="installer/**"/>
+ <include name="styles/default/**"/>
+ <include name="styles/noname/**"/>
+ <include name="chars/ascii/row02.trans"/>
+ </fileset>
+ </copy>
+
+ </target>
+
+ <target name="javadoc" description="Create the javadoc">
+ <mkdir dir="doc"/>
+ <javadoc destdir="${javadoc}">
+
+ <fileset dir="${src}" includes="**/*.java"/>
+ <classpath refid="main"/>
+ </javadoc>
+ </target>
+
+ <target name="macker" depends="build, resolve-macker">
+ <taskdef name="macker"
+ classname="net.innig.macker.ant.MackerAntTask"
+ classpathref="macker.classpath"/>
+
+ <property name="macker.report.xml" value="macker.out.xml"/>
+ <property name="macker.report.html" value="macker.out.html"/>
+
+ <macker xmlReportFile="${macker.report.xml}" failOnError="false">
+ <rules dir="." includes="macker.xml"/>
+ <classes dir="${build.classes}">
+ <include name="**/*.class"/>
+ </classes>
+ </macker>
+
+ <taskdef name="macker-report"
+ classname="net.innig.macker.ant.MackerReportAntTask"
+ classpathref="macker.classpath"/>
+ <macker-report xmlReportfile="${macker.report.xml}" outputFile="${macker.report.html}" />
+ </target>
+
+ <target name="clean-ivy" description="Clean the ivy installation.">
+ <delete dir="${ivy.jar.dir}"/>
+ </target>
+
+ <!-- Clean everything -->
+ <target name="clean" description="Remove built files">
+ <delete dir="${build}" />
+ <delete dir="tmp"/>
+ </target>
+
+ <!-- Clobber all generated and built files -->
+ <target name="clobber" depends="clean" description="Remove all built files">
+ <delete dir="${dist}" />
+ <delete dir="${ivy.lib.dir}"/>
+ <delete dir="${javadoc}"/>
+ <delete dir="${ivy.distrib.dir}"/>
+ </target>
+
+ <target name="clean-cache" depends="init-ivy" description="Clean the ivy cache.">
+ <ivy:cleancache />
+ </target>
+
+ <target name="rebuild" depends="clean, build" description="Clean existing class files and build from scratch"/>
+</project>
diff --git a/debian/ant.properties b/debian/ant.properties
deleted file mode 100644
index 7385c7f..0000000
--- a/debian/ant.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-ant.build.javac.source=1.5
-ant.build.javac.target=1.5
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644
index 8cb8abc..0000000
--- a/debian/changelog
+++ /dev/null
@@ -1,42 +0,0 @@
-mkgmap (0.0.0+svn2640-1) UNRELEASED; urgency=low
-
- * NOT FINISHED! https://github.com/osmandapp/OsmAnd-tools/blob/master/OsmAndMapCreator/src/crosby/binary/Osmformat.java needs to be packaged first
- * Team upload.
- * New upstream version
- Closes: #580170
- * debian/source/format: 3.0 (quilt)
- * debian/control:
- - Standards-Version: 3.9.4
- - Removed DM-Upload-Allowed
- - Update (Build-)Depends to recent Java standard
- - debhelper 9
- - Add time to Build-Depends which is obviously needed
- - Add Build-Depends libfastutil-java as needed by new upstream version
- * debian/rules: dh $@ --with javahelper
-
- -- Andreas Tille <tille at debian.org> Wed, 05 Jun 2013 11:24:59 +0200
-
-mkgmap (0.0.0+svn1067-1) unstable; urgency=low
-
- [ Andreas Putzo ]
- * New upstream snapshot.
- * Added ${misc:Depends} among dependencies to fix a lintian warning.
- * Bumped debhelper compatibility level to 7.
- * Updated long description.
- * Updated Homepage in debian/control, debian/copyright, debian/watch.
- * Added numerous files from /doc to debian/docs.
- * Mentioned Bernhard Heibler in debian/copyright and updated copyright
- year of software and packaging.
- * Bumped policy to 3.8.2, without changes.
- * Added DM-Upload-Allowed to debian/control.
-
- [ Francesco Paolo Lovergine ]
- * Added me as Uploader to avoid possible inappropriate NMU notices.
-
- -- Francesco Paolo Lovergine <frankie at debian.org> Thu, 16 Jul 2009 11:10:16 +0200
-
-mkgmap (0.0.0+svn630-1) unstable; urgency=low
-
- * Initial release (Closes: #475773)
-
- -- Andreas Putzo <andreas at putzo.net> Mon, 14 Jul 2008 13:38:36 +0000
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index ec63514..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-9
diff --git a/debian/control b/debian/control
deleted file mode 100644
index 9592303..0000000
--- a/debian/control
+++ /dev/null
@@ -1,26 +0,0 @@
-Source: mkgmap
-Section: utils
-Priority: extra
-Maintainer: Debian GIS Project <pkg-grass-devel at lists.alioth.debian.org>
-Uploaders: Andreas Putzo <andreas at putzo.net>,
- Francesco Paolo Lovergine <frankie at debian.org>
-Build-Depends: debhelper (>= 9),
- javahelper (>=0.25),
- ant,
- default-jdk,
- time,
- libfastutil-java
-Standards-Version: 3.9.4
-Homepage: http://www.mkgmap.org.uk
-Vcs-Browser: http://svn.debian.org/viewsvn/pkg-grass/packages/mkgmap/trunk
-Vcs-Svn: svn://svn.debian.org/svn/pkg-grass/packages/mkgmap/trunk
-
-Package: mkgmap
-Architecture: all
-Depends: ${misc:Depends},
- ${java:Depends},
- default-jre | java6-runtime
-Suggests: josm, qlandkarte
-Description: Generate Garmin maps from OpenStreetMap data
- This program converts OpenStreetMap data into a map that
- can be loaded onto compatible Garmin GPS units.
diff --git a/debian/copyright b/debian/copyright
deleted file mode 100644
index e48f54b..0000000
--- a/debian/copyright
+++ /dev/null
@@ -1,43 +0,0 @@
-This package was debianized by Andreas Putzo <andreas at putzo.net> on
-Sun, 13 Apr 2008 19:29:58 +0000.
-
-It was downloaded from http://www.mkgmap.org.uk/snapshots/
-
-Upstream Author:
-
- Steve Ratcliffe <sr at parabola.me.uk>
-
-Copyright:
-
- Copyright (C) 2007-2009 Steve Ratcliffe <sr at parabola.me.uk>
-
-License:
-
- This package 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 package 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.
-
- You should have received a copy of the GNU General Public License
- along with this package; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-On Debian systems, the complete text of the GNU General
-Public License can be found in `/usr/share/common-licenses/GPL-2'.
-
-
-The files:
- src/uk/me/parabola/mkgmap/general/MapPointMultimap.java,
- src/uk/me/parabola/mkgmap/general/MapPointFastFindMap.java,
- src/uk/me/parabola/mkgmap/build/LocatorConfig.java,
- src/uk/me/parabola/mkgmap/build/Locator.java,
-are Copyright (C) 2009 Bernhard Heibler and
-are licensed under the GPL version 2, see above.
-
-
-The Debian packaging is (C) 2008,2009, Andreas Putzo <andreas at putzo.net> and
-is licensed under the GPL version 2, see above.
diff --git a/debian/dirs b/debian/dirs
deleted file mode 100644
index e772481..0000000
--- a/debian/dirs
+++ /dev/null
@@ -1 +0,0 @@
-usr/bin
diff --git a/debian/docs b/debian/docs
deleted file mode 100644
index 65e68cd..0000000
--- a/debian/docs
+++ /dev/null
@@ -1,8 +0,0 @@
-README
-doc/Credits
-doc/Zoom
-doc/map-features.txt
-doc/style-rules.txt
-doc/style-examples.txt
-doc/style.txt
-resources/garmin_feature_list.csv
diff --git a/debian/install b/debian/install
deleted file mode 100644
index 75de0b1..0000000
--- a/debian/install
+++ /dev/null
@@ -1,2 +0,0 @@
-dist/mkgmap.jar usr/share/mkgmap/
-debian/scripts/mkgmap usr/bin/
diff --git a/debian/manpages b/debian/manpages
deleted file mode 100644
index 788b3d6..0000000
--- a/debian/manpages
+++ /dev/null
@@ -1 +0,0 @@
-doc/mkgmap.1
diff --git a/debian/patches/build_xml.patch b/debian/patches/build_xml.patch
deleted file mode 100644
index 85d7e92..0000000
--- a/debian/patches/build_xml.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-Author: Andreas Tille <tille at debian.org>
-LastChanged: Wed, 05 Jun 2013 11:24:59 +0200
-Description: Leave out IVY dependency checker
- Attention: This patch is most probably not yet finished.
- I went until the point when I noticed that mkgmap needs a
- not yet packaged dependency
- http://fastutil.di.unimi.it/
- The packaging of this predependency is finished and was ITPed (#711212)
- When installing libfastutil-java the build as way less error messages.
- It seems the remaining precondition would be at
- https://github.com/osmandapp/OsmAnd-tools/blob/master/OsmAndMapCreator/src/crosby/binary/Osmformat.java
- I need to check this out
-
---- a/build.xml
-+++ b/build.xml
-@@ -19,6 +19,7 @@
- xmlns:ivy="antlib:org.apache.ivy.ant">
-
- <!-- Set default javac target value -->
-+ <property name="deblib" location="/usr/share/java"/>
- <property name="ant.build.javac.target" value="1.6"/>
- <property name="ant.build.javac.source" value="1.6"/>
-
-@@ -71,7 +72,7 @@
-
- <!-- For class paths -->
- <path id="compile.classpath">
-- <fileset dir="${ivy.lib.dir}/compile" />
-+ <fileset dir="${deblib}/" /> <!-- fastutil.jar -->
- </path>
- <path id="test.classpath">
- <fileset dir="${ivy.lib.dir}/test" />
-@@ -231,7 +232,7 @@
- </target>
-
- <!-- Compile the product itself (no tests). -->
-- <target name="compile" depends="prepare, resolve-compile"
-+ <target name="compile" depends="prepare"
- description="main compilation">
-
- <javac srcdir="${src}" destdir="${build.classes}" encoding="utf-8" debug="true" includeantruntime="false">
diff --git a/debian/patches/series b/debian/patches/series
deleted file mode 100644
index 46a7f4e..0000000
--- a/debian/patches/series
+++ /dev/null
@@ -1 +0,0 @@
-build_xml.patch
diff --git a/debian/rules b/debian/rules
deleted file mode 100755
index 05b703b..0000000
--- a/debian/rules
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/make -f
-# -*- makefile -*-
-# debian/rules file for mkgmap
-# Andreas Tille <tille at debian.org>
-# GPL
-
-JAVA_HOME=/usr/lib/jvm/default-java
-
-%:
- dh $@ --with javahelper
-
-override_dh_auto_build:
- ant
diff --git a/debian/scripts/mkgmap b/debian/scripts/mkgmap
deleted file mode 100644
index 00f0870..0000000
--- a/debian/scripts/mkgmap
+++ /dev/null
@@ -1,23 +0,0 @@
-#! /bin/sh
-# Simple wrapper script to execute mkgmap in Debian
-set -e
-
-# First, the users preference as defined by $JAVA_HOME. Next, the
-# other JVMs known to work with mkgmap, with the one working best
-# fist, and the less functional onces after that. Last, use /usr/bin/java.
-# Override to a specific one using JAVACMD
-JAVA_CMDS="$JAVA_HOME/bin/java /usr/lib/jvm/java-6-openjdk/bin/java /usr/lib/jvm/java-6-sun/jre/bin/java /usr/lib/jvm/java-1.5.0-sun/jre/bin/java /usr/bin/java"
-
-for jcmd in $JAVA_CMDS; do
- if [ -x "$jcmd" -a -z "${JAVACMD}" ]; then
- JAVACMD="$jcmd"
- fi
-done
-
-if [ "$JAVACMD" ]; then
- echo "Using $JAVACMD to execute mkgmap."
- exec $JAVACMD -jar /usr/share/mkgmap/mkgmap.jar "$@"
-else
- echo "No valid JVM found to run mkgmap."
- exit 1
-fi
diff --git a/debian/source/format b/debian/source/format
deleted file mode 100644
index 163aaf8..0000000
--- a/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/debian/watch b/debian/watch
deleted file mode 100644
index 7fe5e51..0000000
--- a/debian/watch
+++ /dev/null
@@ -1,3 +0,0 @@
-version=3
-opts="dversionmangle=s/0.0.0.svn//,uversionmangle=s/^r//" \
-http://www.mkgmap.org.uk/snapshots/mkgmap-(.*)-src\.tar\.gz
diff --git a/doc/Credits b/doc/Credits
new file mode 100644
index 0000000..6e69e57
--- /dev/null
+++ b/doc/Credits
@@ -0,0 +1,65 @@
+
+General
+-------
+This project is almost entirely based on the file format specification
+document written by John Mechalas at the SourceForge project at
+http://sourceforge.net/projects/garmin-img. The 'imgdecode' program
+from the same source was also very important in checking that I was
+on the right lines to producing a correct file.
+
+Routing
+-------
+Alexander Atanasov and his libgarmin project
+Robert Vollmert
+Mark Burton: adding .osm support
+Johann Gail, Bernhard Heibler
+
+POI support
+-----------
+Bernhard Heibler: support for filling in address, phone etc information
+into POI based on tags in the .osm file.
+Also automatically finding city information by various means including
+searching for the nearest city to a point. Uses openGeoDB tags if present.
+
+Ben Konrath: Creating POIs for areas.
+
+Code patches
+------------
+Robert Vollmert:
+ - reading and changes to writing of "format-6" labels
+
+Elrond:
+ - put map names into the TDB file
+ - writing out section info
+ - POI support
+
+Rene_A:
+ - Multipolygon relation support
+
+Map features
+------------
+The original map features file was based on the files in OSMGarminMap
+by Jochen Topf. The current file was also created by Jochen Topf.
+
+Additions have been made by a number of people notably by:
+Elrond, Roozbeh, Computerteddy
+
+Documentation
+-------------
+The man page was written by Andreas Putzo
+
+
+Packaging
+---------
+Debian - Andreas Putzo
+
+
+Internationalisation
+--------------------
+Tomi B:
+ - idea for transliteration of non-ascii characters and testing of the Czech letters.
+
+Liosha:
+ - Russian transliteration.
+
+
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000..ee2b45c
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,14 @@
+
+DIRS=styles # tutorial reference
+
+
+all:
+ echo You can only install with this makefile
+
+install: $(DIRS)
+
+$(DIRS):
+ $(MAKE) -C $@ install
+
+
+.PHONY: dirs $(DIRS)
diff --git a/doc/README b/doc/README
new file mode 100644
index 0000000..49d28a3
--- /dev/null
+++ b/doc/README
@@ -0,0 +1,12 @@
+
+
+Documentation
+=============
+
+Most of the documentation is currently on the OSM wiki
+
+ See: http://wiki.openstreetmap.org/wiki/Mkgmap
+ Also: http://www.mkgmap.org.uk/doc/index.html
+
+Documentation is gradually being brought back and written
+so that there will be a complete reference here.
diff --git a/doc/README.INDEX b/doc/README.INDEX
new file mode 100644
index 0000000..5ef2095
--- /dev/null
+++ b/doc/README.INDEX
@@ -0,0 +1,43 @@
+$Id$
+
+README.INDEX for mkgmap
+
+This file describes the various README files for mkgmap. Each file is
+named README.name (where name is lower case) and covers a different
+area of mkgmap usage.
+
+The intent is that everything known about mkgmap will be contained in
+the various README files. Currently, README.INDEX describes a
+proposed organization. Files are listed in an order intended to be
+helpful to new users.
+
+* wiki, web pages
+
+http://wiki.openstreetmap.org/wiki/Mkgmap
+http://www.mkgmap.org.uk/page/main
+
+* README.invoking
+
+This file describes every command-line option for mkgmap. It assumes
+that a .jar already exists and that there are no java issues.
+
+* README.examples
+
+This file describes typical ways to run mkgmap. It is intended to
+cover various normal use cases.
+
+* README.img
+
+This files contains pointers to descriptions of the garmin formats.
+It contains links to other related programs and documents.
+
+* README.installing
+
+This file explains how to get maps from mkgmap into GPS receivers via
+USB Mass Storage, via MapSource (Windows) and RoadTrip (Mac).
+
+* README.java
+
+This file describes how to deal with java, CLASSPATH, which versions
+work, etc. It describes how to build mkgmap from source.
+
diff --git a/doc/README.examples b/doc/README.examples
new file mode 100644
index 0000000..bf5ae22
--- /dev/null
+++ b/doc/README.examples
@@ -0,0 +1,38 @@
+$Id$
+
+README.examples for mkgmap
+
+This file contains a number of examples of how to run mkgmap. It does
+not attempt to label any way correct, but rather to give a number of
+situations and goals and show ways that people think are useful for
+that situation. It is formatted to enable reasonably easy cut and paste.
+
+* OSM maps for use on garmin
+
+This example is for the goal of producing a maximally usable OSM map
+for Garmin, intended for use rather than to assist with mapping.
+
+# Split the Massachusetts osm file (from cloudmade).
+java -Xmx2000m -jar splitter.jar massachusetts.osm > OUT.01.splitter 2>&1
+
+# Create the map. Family-id is arbitrary. Use the areas created by
+# the splitter. Create an overview map and a tdb file.
+java -enableassertions \
+ -Xmx2048m \
+ -jar mkgmap.jar \
+ --tdbfile \
+ --gmapsupp \
+ --family-id=632 \
+ --overview-mapname=40000001 \
+ --country-abbr="US" \
+ --country-name="United States" \
+ --region-abbr="MA" \
+ --region-name="Massachusetts" \
+ --description="OSM gdt" \
+ --route \
+ --add-pois-to-areas \
+ -c template.args > OUT.02.mkgmap 2>&1
+
+# Create a gmapi format map given the above map, overview map, and tdb.
+mkdir -p GMAPI
+gmapi-builder.py -o GMAPI -t 40000001.tdb -b 40000001.img -v
diff --git a/doc/README.img b/doc/README.img
new file mode 100644
index 0000000..d34bb60
--- /dev/null
+++ b/doc/README.img
@@ -0,0 +1,37 @@
+$Id$
+
+README.img for mkgmap
+
+WRITEME
+
+* Format descriptions
+
+See
+
+ http://sourceforge.net/projects/garmin-img
+
+This site also has a program 'imgdecode' which reads a .img file and
+produces a textual representation of it.
+
+mkgmap has support for generating test maps with lines and points of
+possible codepoints. Instead of using an OSM file as input, use the
+special input name "test-map:all-elements":
+ java -jar mkgmap.jar test-map:all-elements
+
+Set BASE_LAT and BASE_LON in the environment to control the location
+of the test elements. See
+http://wiki.openstreetmap.org/wiki/Talk:Mkgmap/dev for more
+information.
+
+* mapid and familyid values
+
+The .img format has an ID for tiles. The splitter recommends
+63240001.img as the name of the first tile.
+
+Maps also have a family id code (set with --family-id) that denotes a
+map family.
+
+If one would like to have multiple versions of OSM data installed at
+once, the compiled maps must appear distinct to MapSource and
+RoadTrip.
+
diff --git a/doc/README.installing b/doc/README.installing
new file mode 100644
index 0000000..59b1834
--- /dev/null
+++ b/doc/README.installing
@@ -0,0 +1,76 @@
+$Id$
+
+README.installing for mkgmap
+
+* Approaches
+
+There are basically three approaches for taking the output of mkgmap
+and installing it on a GPS receiver. One is to directly use the .img
+file, and the other two are to import tha map data to Garmin's
+proprietary programs for Windows (MapSource) and Mac (RoadTrip).
+
+With the direct .img approach, the receiver will have a single map,
+generated by mkgmap, and no way to switch back and forth. With
+MapSource and RoadTrip, the OSM map can be installed along with other
+maps, and one can then use the UI on the GPS receiver to switch maps.
+Also, one can view the maps on a computer.
+
+* Direct .img
+
+mkgmap will normally produce a file called "gmapsupp.img". Place this
+file on the filesystem in the GPS receiver as /Garmin/gmapsupp.img.
+(There is no way to switch among multiple img files from the GPS
+receiver UI.)
+
+* MapSource
+
+[TO BE reviewed: This needs some registry voodoo.]
+There is 3 methods to install maps to MapSource:
+
+1. Create and execute a *.reg file
+ With a text editor create a file and save it as RegFileName.reg
+ with the following content, where HexID is the hex format of the
+ FID, in little-endian order, FID is the FamilyID and PID is the
+ ProductID;
+
+ REGEDIT4
+
+ [HKEY_LOCAL_MACHINE\SOFTWARE\Garmin\MapSource\families\FID]
+ "ID"= hex:HexFID
+ "IDX"="C:\\Garmin\\path\\to\\maps\\OverviewMapName.mdx"
+ "MDR"="C:\\Garmin\\path\\to\\maps\\OverviewMapName_mdr.img"
+
+ [HKEY_LOCAL_MACHINE\SOFTWARE\Garmin\MapSource\families\FID\PID]
+ "LOC"="C:\\Garmin\\path\\to\\maps\\"
+ "BMAP"="C:\\Garmin\\path\\to\\maps\\OverviewMapName.img"
+ "TDB"="C:\\Garmin\\path\\to\\maps\\OverviewMapName.tdb"
+
+2. Edit the registry by hand
+
+3. Using MapSetToolKit (http://cypherman1.googlepages.com/)
+ - Run MapSetToolKit and click Install button placed at the bottom
+ right corner. A dialogue will appear with some blank fields:
+
+ Registry name: introduce any name for your reference.
+ TDB file: browse to the file osmmap.tdb.
+ Overview map: browse to the file osmmap.img.
+ Maps directory: it is filled automatically after giving the path to the files above .
+
+ - Click Install, close the application and you are done. You now have the map in MapSource.
+
+* RoadTrip
+
+TO BE FINISHED:
+
+Garmin provides RoadTrip, a program to view maps, as a no-cost
+download. RoadTrip is bundled with MapInstaller and MapManager.
+
+ http://www8.garmin.com/support/download_details.jsp?id=4332
+
+ Create an overview map with --tdb and -overviewmap.
+
+ Get http://wiki.openstreetmap.org/wiki/Gmapibuilder and run it.
+
+ open the resulting .gmapi. In MapManager, install the map. Then, in
+ RoadTrip the map should be selectable. In MapInstaller, you should
+ be able to choose tiles from the OSM map.
diff --git a/doc/README.invoking b/doc/README.invoking
new file mode 100644
index 0000000..7499fb6
--- /dev/null
+++ b/doc/README.invoking
@@ -0,0 +1,28 @@
+$Id$
+
+BASIC INVOCATION
+
+README.invoking for mkgmap
+
+To run mkgmap, the basic invocation is
+
+ java -jar mkgmap.jar
+
+or
+
+ java -jar /path/to/jar/mkgmap.jar
+
+JAVA OPTIONS
+
+If your computer has 2Gb or less of memory, then you may have to give
+the option "-Xmx900m" to java.
+
+ java -Xmx900m -jar /path/to/jar/mkgmap.jar
+
+BUILTIN HELP
+
+Run
+
+ java -jar mkgmap.jar --help=options
+
+to get a list of options to mkgmap.
diff --git a/doc/README.java b/doc/README.java
new file mode 100644
index 0000000..1436c3a
--- /dev/null
+++ b/doc/README.java
@@ -0,0 +1,48 @@
+
+README.java for mkgmap
+
+* java versions
+
+Version 1.6, or later, of java is required to run mkgmap.
+
+** Mac hints
+
+Mac OS X 10.5 comes with Java 1.5. You can install 1.6 from
+ http://www.apple.com/downloads/macosx/apple/application_updates/javaformacosx105update1.html
+
+After installing, set 1.6 as the default using JAVA preferences, which
+will cause 'java -jar foo.jar' to use the 1.6 JRE. To cause ant to
+use 1.6 to compile, set
+ export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.6/home
+
+* building
+
+To build, you must have a JDK and apache ant installed.
+Then, just run "ant", which will produce dist/mkgmap.jar.
+
+- Installing ant on Windows 95, XP, NT [Barest Basics: PLEASE REVIEW ME]
+Download the latest Apache Ant binaries from http://ant.apache.org
+Unzip the contents to C:\ANT - at least the bin and lib folders must be directly under c:\ANT
+Set the environment variables:
+ Start -> Settings -> Control panel -> System -> Advanced -> Environment Variables
+
+ VARIABLE VALUE (example) EXPLANATION
+
+ Path C:\ANT\bin Add the path to bin to the other paths already there
+ ANT_HOME C:\ANT Create a new variable with the path to your ANT
+ JAVA_HOME C:\Program Files\Java\jdk1.6.0_14 The path to JDK
+ CLASSPATH Should be empty, if it is not run ANT with -noclasspath
+
+Run ANT from the same directory where your build.xml file is located.
+ Open a shell (cmd.exe)- navigate to the directory of build.xml,
+ type "ant" or "ant -noclasspath" if CLASSPATH is not empty
+ press <ENTER>
+If all else fails read the manual (your\path\to\Ant\docs\manual\index.html "Installing Ant" ;-}
+
+- Installing ant on Linux
+ Install via your distribution package manager.
+
+* running
+
+To run, you must have a JRE installed. See README.invoking and
+README.examples. You can use a downloaded jar or one that you built.
diff --git a/doc/Zoom b/doc/Zoom
new file mode 100644
index 0000000..d02261e
--- /dev/null
+++ b/doc/Zoom
@@ -0,0 +1,14 @@
+
+The zoom levels
+===============
+
+This is the range of zooms on my Legend Cx for different number-of-bits.
+I give the range over which it says 'mapsource' and not overzoom or
+basemap.
+
+16 30km-12km
+18 8km-3km
+20 2km-800m
+22 500m-200m
+23 300m-80m
+24 120m-50m
diff --git a/doc/addresses/address.txt b/doc/addresses/address.txt
new file mode 100644
index 0000000..10d28ad
--- /dev/null
+++ b/doc/addresses/address.txt
@@ -0,0 +1,181 @@
+= Address information =
+
+Each POI (in the range 0x?? to 0x??) and street in mkgmap generated maps can have some additional attributes. They can be assigned in the style file by setting mkgmap special tags.
+
+== POIs ==
+Additional attributes for POIs can be used only for POIs with Garmin code 0x?? to 0x??. POIs in the extended range 0x???? to 0x???? do not support these additional attributes.
+
+POIs can have the following attributes:
+[options="header"]
+|=========================================================
+|Attribute |mkgmap tag |Example |Notes
+|Name |name |Pizza Express |Name of the POI
+|Country |mkgmap:country |GBR |Three letter ISO code, e.g. for GBR United Kingdom
+|Region |mkgmap:region |Nottinghamshire |The regions name. Useful if there are multiple cities with the same name.
+|City |mkgmap:city |Nottingham |
+|Street |mkgmap:street |King Street |
+|Housenumber |mkgmap:housenumber |20 |
+|Zipcode |mkgmap:postal_code |NG1 2AS |
+|Phone |mkgmap:phone |+44 115 999999 |Phone number in any format
+|=========================================================
+
+The additional information is displayed if the POI is selected. Only the name, city, region and country information is used for searching.
+
+== Streets ==
+Each street can have the following attributes:
+[options="header"]
+|=========================================================
+|Attribute |mkgmap tag |Example |Notes
+|Name |name |King Street |Street name
+|Country |mkgmap:country |GBR |Three letter ISO code, e.g. for GBR United Kingdom
+|Region |mkgmap:region |Nottinghamshire |The regions name. Useful if there are multiple cities with the same name.
+|City |mkgmap:city |Nottingham |
+|Zipcode |mkgmap:postal_code |NG1 2AS |
+|=========================================================
+
+== LocatorConfig.xml ==
+The +LocatorConfig.xml+ config file contains information about all countries used by mkgmap.
+
+----
+<country name="Schweiz" abr="CHE" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>Switzerland</variant>
+ <variant>Suisse</variant>
+ <variant>CH</variant>
+ <variant>CHE</variant>
+</country>
+----
+
+This includes the +name+ of the country and several of its +variants+. The ISO 3166-1 alpha 3
+(+abr+) code is used by mkgmap internally and in the style file to have a unique naming
+of countries.
+
+TIP: http://en.wikipedia.org/wiki/ISO_3166-1_alpha-3[Wikipedia] has a list of all ISO 3166-1 alpha 3 codes
+
+The two flags +streetBeforeHousenumber+ and +postalcodeBeforeCity+ determines the address order used on the GPS device.
+
+== Assigning the mkgmap tags ==
+The style file can be used to assign the special mkgmap tags listed above.
+
+NOTE: All tags can be assigned without any restrictions but mkgmap performs some special processing for the +mkgmap:country+ tag. See chapter +Country names+ below.
+
+A common set of address rules is located in the +inc/address+ file in the default style of mkgmap.
+
+A common rule set to assign the +mkgmap:city+ tag looks like:
+----
+mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+mkgmap:city!=* & mkgmap:admin_level7=* { set mkgmap:city='${mkgmap:admin_level7}' }
+mkgmap:city!=* & is_in:city=* { set mkgmap:city='${is_in:city}' }
+mkgmap:city!=* & addr:city=* { set mkgmap:city='${addr:city}' }
+----
+
+The first non empty tag of +mkgmap:admin_level8+, +mkgmap:admin_level7+, +is_in:city+ and +addr:city+ is used to assign the +mkgmap:city+ tag and
+therefore the city name of the OSM element.
+
+Usually the +mkgmap:country+ tag should be assigned first. After that it is possible to have country specific rules.
+----
+mkgmap:country=CAN & mkgmap:region!=* & mkgmap:admin_level4=* { set mkgmap:region='${mkgmap:admin_level4}' }
+----
+
+=== Country names ===
+Each country has a long name (United Kingdom) and the ISO 3166-1 alpha 3 code (GBR).
+To avoid a big diversity of combinations for one country (e.g. United Kingdom/GBR, Great Britain/GBR, England/GBR, etc.)
+mkgmap first converts the value of +mkgmap:country+ internally to the ISO code. The country name and all variants
+from the +LocatorConfig.xml+ and country names in all languages from the preprocessed bounds are
+used for this.
+
+.Evaluation of the long name
++mkgmap:country+ is empty::
+ The value of the +country-name+ parameter is used as country name and the value of the +country-abbr+ parameter as three letter ISO code.
+Value of +mkgmap:country+ is unknown::
+ In case the country name cannot be assigned to a known country the given country name is used and the +country-abbr+ parameter is used as three letter ISO code.
+Preprocessed bounds are used::
+ The long name of the country is retrieved by evaluating the +name-tag-list+ option on the country relation that is stored in the preprocessed bounds.
+Preprocessed bounds are not used::
+ The long name is taken from the +name+ attribute of the +LocatorConfig.xml+ entry.
+
+== Preprocessed bounds ==
+In OSM a reasonable number of POIs and streets are not tagged directly with all information required to fill the additional attributes.
+For example it is very uncommon to tag a street with the city and country name the street is located in.
+
+mkgmap uses so called preprocessed bounds files to provide a quick method assign the lies-in relationship for some hard wired tags:
+* admin_level=2..11
+* postal_code
+
+TODO: Parameter, mkgmap tags
+
+=== Creating preprocessed bounds ===
+Preprocessing bounds is a procedure to extract and prepare all boundary and zip code data with from a large
+OSM extract (like europe extract or asia extract). The data is prepared in such a format that mkgmap
+can read and process in a fast way while compiling maps.
+
+Preprocessing consists of two (or three) steps:
+
+. Extracting the required data from the large OSM extract
+. Preprocessing the extract
+. Eventually merge multiple preprocessed extracts
+
+==== Extracting data ====
+The boundary and zip code data must be extracted from a large OSM extract to avoid excessive memory
+requirements in the preprocessing step.
+
+NOTE: This manual describes the usage of the two tools +osmconvert+ and +osmfilter+. The same can be achieved
+with other tools like +osmosis+.
+
+[TIP]
+==========
++osmconvert+ http://wiki.openstreetmap.org/wiki/Osmconvert
+
++osmfilter+ http://wiki.openstreetmap.org/wiki/Osmfilter
+==========
+
+
+.Extract data from europe.osm.pbf
+=================================
+After download the OSM extract (europe.osm.pbf in this example) the extract must be converted
+to o5m format. This o5m file is then filtered.
+
+ osmconvert europe.osm.pbf --out-o5m >europe.o5m
+ osmfilter europe.o5m --keep-nodes= --keep-ways-relations="boundary=administrative =postal_code postal_code=" --out-o5m > europe-boundaries.o5m
+
+=================================
+
+==== Preprocessing data ====
+The tool for preprocessing the boundary and zip code data is contained in the common mkgmap download.
+
+.Preprocessing bounds data
+=================================
+ # The following should be all one line
+ java -cp mkgmap.jar
+ uk.me.parabola.mkgmap.reader.osm.boundary.BoundaryPreprocessor
+ europe-boundaries.o5m
+ europe_bounds
+=================================
+
+This will create a directory called europe_bounds containing multiple files with preprocessed bounds.
+This directory can be used with the bounds option on the mkgmap command line.
+
+
+==== Merging preprocessed data ====
+Preprocessing requires a quite high amount of memory, e.g. north- and south-america requires around 3 GB. So on many systems
+it is not possible to preprocess the whole planet at once. It is possible to divide the planet into several parts where each country
+must be contained completely in one of the parts. Parts should overlap.
+
+Each part is preprocessed in its own directory which are merged as a third step.
+
+.Merging preprocessed data
+=================================
+ # The following should be all one line
+ java -cp mkgmap.jar
+ uk.me.parabola.mkgmap.reader.osm.boundary.BoundaryMerger
+ part1
+ part2
+ merged
+=================================
+
+This command merges the preprocessed bounds from directory +part1+ and +part2+ into the new directory +merged+.
+
+=== index parameter ===
+TODO
+
+=== location-autofill parameter ===
+TODO
\ No newline at end of file
diff --git a/doc/index.txt b/doc/index.txt
new file mode 100644
index 0000000..687a186
--- /dev/null
+++ b/doc/index.txt
@@ -0,0 +1,20 @@
+
+== Documentation ==
+The documentation that is currently available on this site is listed
+below.
+
+[/doc/options '''Command line options''']
+The possible command line options to mkgmap. This list is also available
+using the command:
+ mkgmap --help=options
+
+[/doc/pdf/style-manual.pdf '''Style Manual'''] [pdf]
+This is the complete documentation of the style rules that determine how
+the OSM taged features are converted into the Garmin features.
+
+[/doc/typ-compiler '''TYP compiler manual''']
+This documents the language that is accepted by the TYP compiler that
+is included within mkgmap.
+
+For other documentation go to the Open Street Map wiki for documentation
+[http://wiki.openstreetmap.org/wiki/Mkgmap here]
diff --git a/doc/mkgmap.1 b/doc/mkgmap.1
new file mode 100644
index 0000000..afcdcb3
--- /dev/null
+++ b/doc/mkgmap.1
@@ -0,0 +1,35 @@
+.TH MKGMAP 1 "April 13, 2008"
+.\" Please adjust this date whenever revising the manpage.
+.SH NAME
+mkgmap \- Generate Garmin maps from OpenStreetMap data
+.SH SYNOPSIS
+.B mkgmap
+.RI [ options ] " files.osm " ...
+.SH DESCRIPTION
+This manual page documents briefly the
+.B mkgmap
+command.
+.PP
+\fBmkgmap\fP is a program that converts OpenStreetMap (OSM) data into a map that can be
+loaded onto a Garmin GPS device.
+The mapping between OSM features and the features in the map can be
+completly customized by writing what we term a "style".
+.SH OPTIONS
+.TP
+.B \-\-help <filename>
+Use this option to get alist of the built in help topics.
+In particular calling --help=options will list all the available
+options and is always up to date.
+.SH ACKNOWLEDGEMENTS
+This project is almost entirely based on the file format specification
+document written by John Mechalas at the SourceForge project at
+http://sourceforge.net/projects/garmin-img.
+.SH SEE ALSO
+.BR josm (1),
+.BR qlandkarte (1).
+.SH AUTHOR
+mkgmap was originally written by Steve Ratcliffe <sr at parabola.me.uk>
+and has been improved by many other people since.
+.PP
+This manual page was written by Andreas Putzo <andreas at putzo.net>,
+for the Debian project (but may be used by others).
diff --git a/doc/options.txt b/doc/options.txt
new file mode 100644
index 0000000..b1336fe
--- /dev/null
+++ b/doc/options.txt
@@ -0,0 +1,645 @@
+= List of options =
+Note that option order is significant: An option only applies to
+subsequent input files. (So if you are using splitter, you probably
+want to put most of your options before '-c template.args'.)
+
+=== General options ===
+
+;--help=topic
+: Print help on the given topic. If the topic is omitted then a
+list of all the help topics is printed instead.
+
+;--version
+: Output program version to stderr.
+
+=== File options ===
+;--input-file=filename
+: Read input data from the give file. This option (or just a
+filename) may be given more than once.
+
+;--gmapsupp
+: Create a gmapsupp.img file that can be uploaded to a Garmin or
+placed in "/Garmin" in a microSD card (such as by mounting the
+device in USB mass storage mode). It can be used on ready
+compiled img files, if the input files are not already compiled
+then they are compiled first and then the gmapsupp is created.
+
+;-c filename
+;--read-config=filename
+: The given file is opened and each line is an option setting of
+the form option=value, any option that could be used on the command
+line can be used, however you omit the leading '--'. The short
+option names with a single '-' cannot be used, simply use the
+long name instead.
+
+;--output-dir=filename
+: The directory in which all output files are written. It defaults
+to the current working directory, ie. the directory the command is
+executed from.
+
+;-n name
+;--mapname=name
+: Set the name of the map. Garmin maps are named by 8 digit
+numbersList. The default is 63240001. It is best to use a different
+name if you are going to be making a map for others to use so
+that it is unique and does not clash with others.
+
+;--description=text
+: Sets the descriptive text for the map. This may be displayed in
+QLandkarte, MapSource on on a GPS etc, where it is normally shown
+below the family name. Example: --description="Germany, Denmark"
+Please note: if you use splitter.jar to build a template.args file
+and use -c template.args, then that file may contain a
+"description" that will override this option. Use "--description" in
+splitter.jar to change the description in the template.args file.
+
+;--country-name=name
+: Sets the map's country name. The default is "COUNTRY".
+
+;--country-abbr=abbreviation
+: Sets the map's abbreviated country name. The default is "ABC".
+
+;--region-name=name
+: Sets the map's region name. By default, the map has no region name.
+
+;--region-abbr=abbreviation
+: Sets the map's abbreviated region name. By default, the map has
+no abbreviated region name.
+
+=== Label options ===
+
+;--latin1
+: This is equivalent to --code-page=1252.
+
+;--code-page=number
+: This option enables the use of international characters. Only 8 bit
+character sets are supported and so you have to specify which code page
+you want to use.
+
+: It is entirely dependant on the device firmware which code pages are
+supported.
+
+;--charset=name
+: This option is obsolete. Change the character set with the --code-page
+option.
+
+;--lower-case
+: Allow labels to contain lower case letters. Note that most or all
+Garmin devices are not able to display lower case letters at an angle
+so this option is not generally useful.
+
+=== Address search options ===
+;--index
+: Generate a global address search index. If the --gmapsupp option is
+also given, then the index is generated within the resulting
+gmapsupp.img file so that address search will work on a GPS
+device.
+
+: If instead the --tdbfile option is given then the index consists
+of two files named osmmap.mdx and osmmap_mdr.img which can be used
+with mapsource. (For compatibility, you do not need the tdbfile
+option if gmapsupp is not given).
+
+: If both the --gmapsupp and --tdbfile options are given alongside
+the --index option, then both indexes will be created. Note that
+this will require roughly twice as much memory.
+
+: The --overview-mapname option can be used to change these names. If
+the mapset is sent to the device from MapSource, it will enable
+find by name and address search on the GPS.
+
+: The address fields are assigned by special mkgmap address
+tags using the style file:
+ mkgmap:country
+ mkgmap:region
+ mkgmap:city
+ mkgmap:postal_code
+ mkgmap:street
+ mkgmap:housenumber
+ mkgmap:phone
+ (mkgmap:is_in - used by location-autofill=is_in)
+
+: If the index is created from previously compiled .img files, then the
+same code page and sorting options (eg. --code-page, --latin1 etc) must
+be used as were used to compile the individual map tiles.
+
+;--bounds=directory|zipfile
+: A directory or a zipfile containing the preprocessed bounds files.
+Bounds files in a zipfile must be located in the zipfiles root directory.
+
+: The preprocessed boundaries are used to add special tags to all elements
+(points, lines and polygons) containing the elements location information.
+The style file can be used to assign the address tags mkgmap:country,
+mkgmap:region etc. using these values.
+
+: The following special tags are added:
+ mkgmap:admin_level2 : Name of the admin_level=2 boundary
+ mkgmap:admin_level3 : Name of the admin_level=3 boundary
+ ..
+ mkgmap:admin_level11
+ mkgmap:postcode : the postal_code value
+
+: Preprocessed bounds can be created with the following command:
+ java -cp mkgmap.jar
+ uk.me.parabola.mkgmap.reader.osm.boundary.BoundaryPreprocessor
+ <inputfile> <boundsdir>
+
+: The input file must contain the boundaries that should be preprocessed.
+It can have OSM, PBF or O5M fileformat. It is recommended that it
+contains the boundary data only to avoid very high memory usage.
+The boundsdir gives the directory where the processed files are stored.
+This directory can be used as --bounds parameter with mkgmap.
+
+;--location-autofill=[option1,[option2]]
+: Controls how the address fields for country, region, city and zip info
+are gathered automatically if the fields are not set by using the special
+mkgmap address tags (e.g. mkgmap:city - see option index).
+Warning: automatic assignment of address fields is somehow a best guess.
+:;is_in
+::The is_in tag is analyzed for country and region information.
+
+:;nearest
+::The city/hamlet points that are closest to the element are used
+to assign the missing address fields. Beware that cities located
+in the same tile are used only. So the results close to a tile
+border have less quality.
+
+
+;--housenumbers
+: Enables house number search for OSM input files.
+
+: All nodes and polygons having addr:housenumber and addr:street set are matched
+to streets. A match between a house number element and a street is created if
+the street is located within a radius of 150m and the addr:street tag value of
+the house number element equals the mgkmap:street tag value of the street.
+The mkgmap:street tag must be added to the street in the style file.
+
+: Example:
+:: Node - addr:street=Main Street addr:housenumber=2
+:: Way 1 - name=Main Street
+:: Way 2 - name=Main Street, mkgmap:street=Main Street
+:: Way 3 - mkgmap:street=Mainstreet
+:: Way 4 - name=Main Street [A504]
+: The node matches to way 2. It has mkgmap:street set with a value equal to
+the addr:street tag value of the house number node.
+
+=== Overview map options ===
+;--overview-mapname=name
+: If --tdbfile is enabled, this gives the name of the overview
+.img and .tdb files. The default map name is osmmap.
+
+;--overview-mapnumber=8 digit number
+: If --tdbfile is enabled, this gives the internal 8 digit
+number used in the overview map and tdb file. The default
+number is 63240000.
+
+;--overview-levels
+: like levels, specifies additional levels that are to be written to the
+overview map. Counting of the levels should continue. Up to 8 additional
+levels may be specified, but the lowest usable resolution with MapSource
+seems to be 11. The hard coded default is empty.
+
+;--remove-ovm-work-files
+: If overview-levels is used, mkgmap creates one additional file
+with the prefix ovm_ for each map (*.img) file.
+These files are used to create the overview map.
+With option --remove-ovm-work-files=true the files are removed
+after the overview map was created. The default is to keep the files.
+
+=== Style options ===
+;--style-file=file
+: Specify an external file to obtain the style from. "file" can
+be a directory containing files such as info, lines, options
+(see resources/styles/default for an example). The directory
+path must be absolute or relative to the current working
+directory when mkgmap is invoked.
+
+: The file can be a zip file containing the files instead of a
+directory.
+
+: The files can be at the top level or contained in a folder within
+the zip file. If the zip file contains more than one top level
+folder then each folder is the name of a style that can be selected
+with the --style option.
+
+: The argument can also be a URL that specifies the location of a
+style file.
+
+;--style=name
+: Specify a style name. Must be used if --style-file points to a
+directory or zip file containing multiple styles. If --style-file
+is not used, it selects one of the builtin styles.
+
+;--list-styles
+: List the available styles. If this option is preceeded by a style-file
+option then it lists the styles available within that file.
+
+;--check-styles
+: Perform some checks on the available styles. If this option is
+preceeded by a style-file option then it checks the styles
+available within that file. If it is also preceded by the style
+option it will only check that style.
+
+;--levels=levels code
+: Change the way that the levels on the map correspond to the zoom
+levels in the device. See customisation help. The default is:
+"0:24, 1:22, 2:20, 3:18, 4:16", although each style can have
+its own default. Up to 8 levels may be specified.
+
+;--name-tag-list
+: Get the tag that will be used to supply the name. Useful for
+language variations. You can supply a list and the first one
+will be used. eg. --name-tag-list=name:en,int_name,name
+
+;--map-features=file
+: This option is ignored; use the --style-file option instead.
+
+=== Product description options ===
+
+;--family-id
+: This is an integer that identifies a family of products.
+Range: [1..9999]
+Mkgmap default: 6324
+
+;--family-name
+: If you build several maps, this option describes the
+family name of all of your maps. Garmin will display this
+in the map selection screen.
+
+: Example: --family-name="OpenStreetmap mkgmap XL 2019"
+
+;--product-id
+: This is an integer that identifies a product within a family.
+It is often just 1, which is the default.
+
+;--product-version
+: The version of the product. Default value is 1.
+
+;--series-name
+: This name will be displayed in MapSource in the map selection
+drop-down. The default is "OSM map".
+
+;--area-name
+: Area name is displayed on Garmin units (or at least on eTrex) as the second
+part of the mapname in the list of the individual maps.
+
+;--copyright-message=note
+: Specify a copyright message for files that do not contain one.
+
+;--license-file=file
+: Specify a file which content will be added as license.
+All entrys of all maps will be merged in the overview map.
+
+=== Optimization options ===
+
+;--reduce-point-density=NUM
+: Simplifies the ways with the Douglas Peucker algorithm.
+NUM is the maximal allowed error distance, by which the resulting
+way may differ from the original one.
+This distance gets shifted with lower zoom levels.
+Recommended setting is 4, this should lead to only small differences
+(Default is 2.6, which should lead to invisible changes)
+
+;--reduce-point-density-polygon=NUM
+: Allows to set the maximal allowed error distance for the DP algorythm
+to be applied against polygons. Recommended setting is 8.
+
+;--merge-lines
+: Try to merge lines. This helps the simplify filter to straighten out
+longer chunks at lower zoom levels. Decreases file size more.
+Increases paint speed at low zoom levels.
+Default is enabled, use --no-merge-lines to disable.
+
+;--min-size-polygon=NUM
+: Removes all polygons smaller than NUM from the map.
+This reduces map size and speeds up redrawing of maps.
+Recommended value is 8 to 15, default is 8.
+See also polygon-size-limits.
+
+;--polygon-size-limits=limits code
+: Allows to specify different min-size-polygon values for each resolution.
+Sample:
+--polygon-size-limits="24:12, 18:10, 16:8, 14:4, 12:2, 11:0"
+If a resolution is not given, mkgmap uses the value for the next higher
+one. For the given sample, resolutions 19 to 24 will use value 12,
+resolution 17 and 18 will use 10, and so on.
+Value 0 means to skip the size filter.
+Note that in resolution 24 the filter is not used.
+
+=== Miscellaneous options ===
+
+;--max-jobs[=number]
+: When number is specified, allow that number of maps to be
+processed concurrently. If number is not specified, the limit
+is set equal to the number of CPU cores. If this option is not
+given at all, the limit is 1 (i.e., the maps are processed
+sequentially).
+
+;--keep-going
+: Don't quit whole application if an exception occurs while
+processing a map - continue to process the other maps.
+
+;--block-size=number
+: Changes the block size that is used in the generated map. This
+option is not usually needed, but sometimes an error message
+will ask you to try a value for this option.
+
+;--net
+: Obsolete, use --route instead.
+
+;--route
+: Create maps that support routing.
+
+;--drive-on-left
+;--drive-on-right
+: Explicitly specify which side of the road vehicles are
+expected to drive on. If neither of these options are
+specified, it is assumed that vehicles drive on the right
+unless --check-roundabouts is specified and the first
+roundabout processed is clockwise.
+
+;--check-roundabouts
+: Check that roundabouts have the expected direction (clockwise
+when vehicles drive on the left). Roundabouts that are complete
+loops and have the wrong direction are reversed. Also checks
+that the roundabouts do not fork or overlap other roundabouts.
+
+;--check-roundabout-flares
+: Sanity check roundabout flare roads - warn if they don't point
+in the correct direction or if they are not oneway or if they
+extend too far.
+
+;--max-flare-length-ratio=NUM
+: When checking flare roads, ignore roads whose length is
+greater than NUM (an integer) times the distance between the
+nodes on the roundabout that the flare roads connect to. Using
+this option with a value of at least 5 will cut down the
+number of legitimate roads that are flagged as flare road
+problems. Default value is 0 (disabled) because it's not a
+completely reliable heuristic.
+
+;--ignore-builtin-relations
+: When reading OSM files, skip the built-in processing of
+relations. This speeds up the processing non-routable map
+layers that do not contain multipolygons. This implies
+--ignore-turn-restrictions.
+
+;--ignore-turn-restrictions
+: When reading OSM files, ignore any "restriction" relations.
+
+;--ignore-osm-bounds
+: When reading OSM files, ignore any "bounds" elements.
+With this option selected generate-sea sometimes works better,
+but routing across tiles will not work.
+
+;--preserve-element-order
+: Process the map elements (nodes, ways, relations) in the order
+in which they appear in the OSM input. Without this option,
+the order in which the elements are processed is not defined.
+
+;--remove-short-arcs[=MinLength]
+: Merge nodes to remove short arcs that can cause routing
+problems. If MinLength is specified (in metres), arcs shorter
+than that length will be removed. If a length is not
+specified, only zero-length arcs will be removed.
+
+;--adjust-turn-headings[=BITMASK]
+: Where possible, ensure that turns off to side roads change
+heading sufficiently so that the GPS believes that a turn is
+required rather than a fork. This also avoids spurious
+instructions to "keep right/left" when the road doesn't
+actually fork.
+
+: Optional BITMASK (default value 3) allows you to specify which
+adjustments are to be made (where necessary):
+:* 1 = increase angle between side road and outgoing main road
+:* 2 = increase angle between side road and incoming main road
+
+
+;--report-similar-arcs
+: Issue a warning when more than one arc connects two nodes and
+the ways that the arcs are derived from contain identical
+points. It doesn't make sense to use this option at the same
+time as using the cycleway creating options.
+
+;--report-dead-ends=LEVEL
+: Set the dead end road warning level. The value of LEVEL (which
+defaults to 1 if this option is not specified) determines
+those roads to report:
+:* 0 = none
+:* 1 = multiple oneway roads that join together but go nowhere
+:* 2 = individual oneway roads that go nowhere.
+
+
+;--road-name-pois[=GarminCode]
+: Generate a POI for each named road. By default, the POIs'
+Garmin type code is 0x640a. If desired, a different type code
+can be specified with this option. This s a workaround for not
+being able to search for roads.
+
+: 0x2f15: a blue dot in the middle of the road, and if you select,
+or 'hover' over it, the streetname appears.
+
+;--add-pois-to-lines
+: Generate POIs for lines. For each line (must not be closed) POIs are
+created at several points of the line. Each POI is tagged with the
+same tags like the line and additional tags added by mkgmap:
+mkgmap:line2poi=true and tag mkgmap:line2poitype having
+the following values:
+:* start - The first point of the line
+:* end - The last point of the line
+:* inner - Each point of the line except the first and the last
+:* mid - The middle point
+:
+
+;--add-pois-to-areas
+: Generate a POI for each polygon and multipolygon. The POIs are created
+after the relation style but before the other styles are applied. Each
+POI is tagged with the same tags of
+the area/multipolygon. Additionally the tag mkgmap:area2poi=true is
+set so that it is possible to use that information in the points style
+file. Artifical polygons created by multipolyon processing are not used.
+The POIs are created at the following positions
+:; polygons:
+:: First rule that applies:
+::* the first node tagged with a tag defined by the pois-to-areas-placement option
+::* the center point
+::
+
+:;multipolygons:
+:: First rule that applies:
+::* the node with role=label
+::* the center point of the biggest area
+:
+
+;--pois-to-areas-placement[=taglist]
+: A semicolon separated list of tag=value definitions. A POI is placed at the first
+node of the polygon tagged with the first tag/value pair. If none of the nodes are
+tagged with the first tag-value pair the first node tagged with the second tag-value
+pair is used and so on. If none of the tag-value pairs matches or the taglist is empty
+the center of the polygon is used.
+It is possible to define wildcards for tag values like entrance=*.
+
+: Default: entrance=main;entrance=yes;building=entrance
+
+;--precomp-sea=directory|zipfile
+: Defines the directory or a zip file that contains precompiled sea tiles.
+Sea files in a zipfile must be located in the zipfiles root directory or in
+a sub directory sea. When this option is defined all natural=coastline tags
+from the input OSM tiles are removed and the precompiled data is used instead.
+This option can be combined with the generate-sea options multipolygon, polygons
+and land-tag. The coastlinefile option is ignored if precomp-sea is set.
+
+;--coastlinefile=filename[,filename]
+: Defines a comma separated list of files that contain coastline
+data. The coastline data from the input files is removed if
+this option is set. Files must have OSM or PBF fileformat.
+
+;--generate-sea[=ValueList]
+: Generate sea polygons. ValueList is an optional comma
+separated list of values:
+:;multipolygon
+:: generate the sea using a multipolygon (the default
+behaviour so this really doesn't need to be specified).
+:;polygons | no-mp
+:: don't generate the sea using a multipolygon - instead,
+generate a background sea polygon plus individual land
+polygons with tag natural=land. This requires a
+suitable land polygon type to be defined in the style
+file (suggested type is 0x010100) and the polygon must
+be defined in the TYP file as having a higher drawing
+level than the sea polygon type.
+
+:;no-sea-sectors
+:: disable the generation of "sea sectors" when the
+coastline fails to reach the tile's boundary.
+
+:;extend-sea-sectors
+:: same as no-sea-sectors. Additional adds a point so
+coastline reaches the nearest tile boundary.
+
+:;land-tag=TAG=VAL
+:: tag to use for land polygons (default natural=land).
+
+:;close-gaps=NUM
+:: close gaps in coastline that are less than this distance (metres)
+
+:;floodblocker
+:: enable the flood blocker that prevents a flooding of
+land by checking if the sea polygons contain streets
+(works only with multipolygon processing)
+
+:;fbgap=NUM
+:: flood blocker gap in metre (default 40) points that are closer to the sea polygon do not block
+
+:;fbthres=NUM
+:: at least so many highway points must be contained in
+a sea polygon so that it may be removed by the flood
+blocker (default 20)
+
+:; fbratio=NUM
+:: only sea polygons with a higher ratio
+(highway points * 100000 / polygon size) are removed
+(default 0.5)
+
+:; fbdebug
+:: switches on the debugging of the flood blocker
+generates GPX files for each polygon checked by
+the flood blocker
+:
+
+;--make-poi-index
+: Generate the POI index (not yet useful).
+
+;--nsis
+: Write a .nsi file that can be used with the Nullsoft Scriptable Install System
+(NSIS) to create a Windows Mapsource Installer.
+
+;--make-all-cycleways
+: Turn on all of the options that make cycleways.
+
+;--make-opposite-cycleways
+: Some oneway streets allow bicycle traffic in the reverse
+direction and this option makes a way with the same points as
+the original that allows bicycle traffic (in both directions).
+
+;--make-cycleways
+: Some streets have a separate cycleway track/lane just for
+bicycle traffic and this option makes a way with the same
+points as the original that allows bicycle traffic. Also,
+bicycle traffic is prohibited from using the original way
+(unless that way's bicycle access has been defined).
+
+;--link-pois-to-ways
+: This option copies some specific attributes of a POI to a
+small part of the way the POI is located on. This can be used
+to let barriers block a way or to lower the calculated speed
+around traffic signals.
+POIs with the tags highway=* (e.g. highway=traffic_signals)
+or barrier=* (e.g. barrier=cycle_barrier) are supported.
+The style developer must add at least one of the access tags
+(mkgmap:foot, mkgmap:car etc.), mkgmap:road-speed and/or
+mkgmap:road-class to the POI. These tags are copied to a small
+part of the way around the POI.
+
+;--process-destination
+: Splits all motorway_link and trunk_link ways tagged with
+destination into two or three parts where the second part
+is additionally tagged with mkgmap:dest_hint=true. This
+allows to use any routable Garmin type (except 0x08 and 0x09)
+for that part so that the Garmin device tells the name of
+this part as hint which destination to follow.
+
+;--process-exits
+: Usual Garmin devices do not tell the name of the exit on motorways
+while routing with mkgmap created maps. This option splits the each
+motorway_link and trunk_link into three parts. All parts are tagged
+with the original tags of the link. Additionally the middle part is
+tagged with the following tags:
+ mkgmap:exit_hint=true
+ mkgmap:exit_hint_ref=<ref tag value of the exit>
+ mkgmap:exit_hint_name=<name tag value of the exit>
+ mkgmap:exit_hint_exit_to=<exit_to tag value of the exit>
+
+: Adding a rule checking the mkgmap:exit_hint=true makes it possible
+to use any routable Garmin type (except 0x08 and 0x09) for the middle
+part so that the Garmin device tells the name of this middle part as
+hint where to leave the motorway/trunk.
+
+;--delete-tags-file=FILENAME
+: Names a file that should contain one or more lines of the form
+TAG=VALUE or TAG=*. Blank lines and lines that start with
+a # or ; are ignored. All tag/value pairs in the OSM input are
+compared with these patterns and those that match are deleted.
+
+;--tdbfile
+: Write files that are essential to running with MapSource, a .tdb file and
+an overview map.
+
+;--show-profiles=1
+: Sets a flag in tdb file which marks set mapset as having contour
+lines and allows showing profile in MapSource. Default is 0
+which means disabled.
+
+;--draw-priority=25
+: When two maps cover the same area, this option controls what
+order they are drawn in and therefore which map is on top of
+which. Higher priorities are drawn "on top" of lower
+priorities.
+
+;--transparent
+: Make the map transparent, so that if two maps are loaded that
+cover the same area, you can see through this map and see the
+lower map too. Useful for contour line maps among other
+things.
+
+;--poi-address
+: Enable address / phone information to POIs. Address info is
+read according to the "Karlsruhe" tagging schema. Automatic
+filling of missing information could be enabled using the
+"location-autofill" option.
+
+: Default is enabled, use --no-poi-address to disable.
+
+;--verbose
+: Makes some operations more verbose. Mostly used with --list-styles.
diff --git a/doc/resources/asciidoc/local-docbook45.conf b/doc/resources/asciidoc/local-docbook45.conf
new file mode 100644
index 0000000..661e605
--- /dev/null
+++ b/doc/resources/asciidoc/local-docbook45.conf
@@ -0,0 +1,3 @@
+
+[+docinfo]
+{pubdate#}<pubdate>{pubdate}</pubdate>
diff --git a/doc/resources/asciidoc/local-missing-blockdef.conf b/doc/resources/asciidoc/local-missing-blockdef.conf
new file mode 100644
index 0000000..410b011
--- /dev/null
+++ b/doc/resources/asciidoc/local-missing-blockdef.conf
@@ -0,0 +1,20 @@
+
+#
+# Add definitions that are missing in the 8.6.6 config file (and quite
+# possibly other versions before 8.6.8)
+#
+
+[blockdef-open]
+# A block without opening or closing tags.
+example-style=template="exampleblock",options=("sectionbody",)
+sidebar-style=template="sidebarblock",options=("sectionbody",)
+verse-style=template="verseblock",posattrs=("style","attribution","citetitle")
+quote-style=template="quoteblock",posattrs=("style","attribution","citetitle"),options=("sectionbody",)
+literal-style=template="literalparagraph",subs=("verbatim",)
+listing-style=template="listingparagraph",subs=("verbatim",)
+NOTE-style=template="admonitionblock",name="note",caption="{note-caption}",options=("sectionbody",)
+TIP-style=template="admonitionblock",name="tip",caption="{tip-caption}",options=("sectionbody",)
+IMPORTANT-style=template="admonitionblock",name="important",caption="{important-caption}",options=("sectionbody",)
+WARNING-style=template="admonitionblock",name="warning",caption="{warning-caption}",options=("sectionbody",)
+CAUTION-style=template="admonitionblock",name="caution",caption="{caution-caption}",options=("sectionbody",)
+
diff --git a/doc/resources/common-images/icons/README b/doc/resources/common-images/icons/README
new file mode 100644
index 0000000..f12b2a7
--- /dev/null
+++ b/doc/resources/common-images/icons/README
@@ -0,0 +1,5 @@
+Replaced the plain DocBook XSL admonition icons with Jimmac's DocBook
+icons (http://jimmac.musichall.cz/ikony.php3). I dropped transparency
+from the Jimmac icons to get round MS IE and FOP PNG incompatibilies.
+
+Stuart Rackham
diff --git a/doc/resources/common-images/icons/callouts/1.png b/doc/resources/common-images/icons/callouts/1.png
new file mode 100644
index 0000000..7d47343
Binary files /dev/null and b/doc/resources/common-images/icons/callouts/1.png differ
diff --git a/doc/resources/common-images/icons/callouts/10.png b/doc/resources/common-images/icons/callouts/10.png
new file mode 100644
index 0000000..997bbc8
Binary files /dev/null and b/doc/resources/common-images/icons/callouts/10.png differ
diff --git a/doc/resources/common-images/icons/callouts/11.png b/doc/resources/common-images/icons/callouts/11.png
new file mode 100644
index 0000000..ce47dac
Binary files /dev/null and b/doc/resources/common-images/icons/callouts/11.png differ
diff --git a/doc/resources/common-images/icons/callouts/12.png b/doc/resources/common-images/icons/callouts/12.png
new file mode 100644
index 0000000..31daf4e
Binary files /dev/null and b/doc/resources/common-images/icons/callouts/12.png differ
diff --git a/doc/resources/common-images/icons/callouts/13.png b/doc/resources/common-images/icons/callouts/13.png
new file mode 100644
index 0000000..14021a8
Binary files /dev/null and b/doc/resources/common-images/icons/callouts/13.png differ
diff --git a/doc/resources/common-images/icons/callouts/14.png b/doc/resources/common-images/icons/callouts/14.png
new file mode 100644
index 0000000..64014b7
Binary files /dev/null and b/doc/resources/common-images/icons/callouts/14.png differ
diff --git a/doc/resources/common-images/icons/callouts/15.png b/doc/resources/common-images/icons/callouts/15.png
new file mode 100644
index 0000000..0d65765
Binary files /dev/null and b/doc/resources/common-images/icons/callouts/15.png differ
diff --git a/doc/resources/common-images/icons/callouts/2.png b/doc/resources/common-images/icons/callouts/2.png
new file mode 100644
index 0000000..5d09341
Binary files /dev/null and b/doc/resources/common-images/icons/callouts/2.png differ
diff --git a/doc/resources/common-images/icons/callouts/3.png b/doc/resources/common-images/icons/callouts/3.png
new file mode 100644
index 0000000..ef7b700
Binary files /dev/null and b/doc/resources/common-images/icons/callouts/3.png differ
diff --git a/doc/resources/common-images/icons/callouts/4.png b/doc/resources/common-images/icons/callouts/4.png
new file mode 100644
index 0000000..adb8364
Binary files /dev/null and b/doc/resources/common-images/icons/callouts/4.png differ
diff --git a/doc/resources/common-images/icons/callouts/5.png b/doc/resources/common-images/icons/callouts/5.png
new file mode 100644
index 0000000..4d7eb46
Binary files /dev/null and b/doc/resources/common-images/icons/callouts/5.png differ
diff --git a/doc/resources/common-images/icons/callouts/6.png b/doc/resources/common-images/icons/callouts/6.png
new file mode 100644
index 0000000..0ba694a
Binary files /dev/null and b/doc/resources/common-images/icons/callouts/6.png differ
diff --git a/doc/resources/common-images/icons/callouts/7.png b/doc/resources/common-images/icons/callouts/7.png
new file mode 100644
index 0000000..472e96f
Binary files /dev/null and b/doc/resources/common-images/icons/callouts/7.png differ
diff --git a/doc/resources/common-images/icons/callouts/8.png b/doc/resources/common-images/icons/callouts/8.png
new file mode 100644
index 0000000..5e60973
Binary files /dev/null and b/doc/resources/common-images/icons/callouts/8.png differ
diff --git a/doc/resources/common-images/icons/callouts/9.png b/doc/resources/common-images/icons/callouts/9.png
new file mode 100644
index 0000000..a0676d2
Binary files /dev/null and b/doc/resources/common-images/icons/callouts/9.png differ
diff --git a/doc/resources/common-images/icons/caution.png b/doc/resources/common-images/icons/caution.png
new file mode 100644
index 0000000..9a8c515
Binary files /dev/null and b/doc/resources/common-images/icons/caution.png differ
diff --git a/doc/resources/common-images/icons/example.png b/doc/resources/common-images/icons/example.png
new file mode 100644
index 0000000..1199e86
Binary files /dev/null and b/doc/resources/common-images/icons/example.png differ
diff --git a/doc/resources/common-images/icons/home.png b/doc/resources/common-images/icons/home.png
new file mode 100644
index 0000000..37a5231
Binary files /dev/null and b/doc/resources/common-images/icons/home.png differ
diff --git a/doc/resources/common-images/icons/important.png b/doc/resources/common-images/icons/important.png
new file mode 100644
index 0000000..be685cc
Binary files /dev/null and b/doc/resources/common-images/icons/important.png differ
diff --git a/doc/resources/common-images/icons/next.png b/doc/resources/common-images/icons/next.png
new file mode 100644
index 0000000..64e126b
Binary files /dev/null and b/doc/resources/common-images/icons/next.png differ
diff --git a/doc/resources/common-images/icons/note.png b/doc/resources/common-images/icons/note.png
new file mode 100644
index 0000000..7c1f3e2
Binary files /dev/null and b/doc/resources/common-images/icons/note.png differ
diff --git a/doc/resources/common-images/icons/prev.png b/doc/resources/common-images/icons/prev.png
new file mode 100644
index 0000000..3e8f12f
Binary files /dev/null and b/doc/resources/common-images/icons/prev.png differ
diff --git a/doc/resources/common-images/icons/tip.png b/doc/resources/common-images/icons/tip.png
new file mode 100644
index 0000000..f087c73
Binary files /dev/null and b/doc/resources/common-images/icons/tip.png differ
diff --git a/doc/resources/common-images/icons/up.png b/doc/resources/common-images/icons/up.png
new file mode 100644
index 0000000..2db1ce6
Binary files /dev/null and b/doc/resources/common-images/icons/up.png differ
diff --git a/doc/resources/common-images/icons/warning.png b/doc/resources/common-images/icons/warning.png
new file mode 100644
index 0000000..d41edb9
Binary files /dev/null and b/doc/resources/common-images/icons/warning.png differ
diff --git a/doc/resources/docbook-xsl/common.xsl b/doc/resources/docbook-xsl/common.xsl
new file mode 100644
index 0000000..2e5cbc2
--- /dev/null
+++ b/doc/resources/docbook-xsl/common.xsl
@@ -0,0 +1,106 @@
+<!--
+ Inlcuded in xhtml.xsl, xhtml.chunked.xsl, htmlhelp.xsl.
+ Contains common XSL stylesheets parameters.
+ Output documents styled by docbook.css.
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:param name="html.stylesheet" select="'docbook-xsl.css'"/>
+
+<xsl:param name="htmlhelp.chm" select="'htmlhelp.chm'"/>
+<xsl:param name="htmlhelp.hhc.section.depth" select="5"/>
+
+<xsl:param name="section.autolabel">
+ <xsl:choose>
+ <xsl:when test="/processing-instruction('asciidoc-numbered')">1</xsl:when>
+ <xsl:otherwise>0</xsl:otherwise>
+ </xsl:choose>
+</xsl:param>
+
+<xsl:param name="suppress.navigation" select="0"/>
+<xsl:param name="navig.graphics.extension" select="'.png'"/>
+<xsl:param name="navig.graphics" select="0"/>
+<xsl:param name="navig.graphics.path">images/icons/</xsl:param>
+<xsl:param name="navig.showtitles">0</xsl:param>
+
+<xsl:param name="shade.verbatim" select="0"/>
+<xsl:attribute-set name="shade.verbatim.style">
+ <xsl:attribute name="border">0</xsl:attribute>
+ <xsl:attribute name="background-color">#E0E0E0</xsl:attribute>
+</xsl:attribute-set>
+
+<xsl:param name="admon.graphics" select="1"/>
+<xsl:param name="admon.graphics.path">images/icons/</xsl:param>
+<xsl:param name="admon.graphics.extension" select="'.png'"/>
+<xsl:param name="admon.style">
+ <xsl:text>margin-left: 0; margin-right: 10%;</xsl:text>
+</xsl:param>
+<xsl:param name="admon.textlabel" select="1"/>
+
+<xsl:param name="callout.defaultcolumn" select="'60'"/>
+<xsl:param name="callout.graphics.extension" select="'.png'"/>
+<xsl:param name="callout.graphics" select="'1'"/>
+<xsl:param name="callout.graphics.number.limit" select="'10'"/>
+<xsl:param name="callout.graphics.path" select="'images/icons/callouts/'"/>
+<xsl:param name="callout.list.table" select="'1'"/>
+
+<!-- This does not seem to work. -->
+<xsl:param name="section.autolabel.max.depth" select="2"/>
+
+<xsl:param name="chunk.first.sections" select="1"/>
+<xsl:param name="chunk.section.depth" select="1"/>
+<xsl:param name="chunk.quietly" select="0"/>
+<xsl:param name="chunk.toc" select="''"/>
+<xsl:param name="chunk.tocs.and.lots" select="0"/>
+
+<xsl:param name="html.cellpadding" select="'4px'"/>
+<xsl:param name="html.cellspacing" select="''"/>
+
+<xsl:param name="table.borders.with.css" select="1"/>
+<xsl:param name="table.cell.border.color" select="'#527bbd'"/>
+
+<xsl:param name="table.cell.border.style" select="'solid'"/>
+<xsl:param name="table.cell.border.thickness" select="'1px'"/>
+<xsl:param name="table.footnote.number.format" select="'a'"/>
+<xsl:param name="table.footnote.number.symbols" select="''"/>
+<xsl:param name="table.frame.border.color" select="'#527bbd'"/>
+<xsl:param name="table.frame.border.style" select="'solid'"/>
+<xsl:param name="table.frame.border.thickness" select="'3px'"/>
+<xsl:param name="tablecolumns.extension" select="'1'"/>
+
+<xsl:param name="highlight.source" select="1"/>
+
+<xsl:param name="section.label.includes.component.label" select="1"/>
+
+<!--
+ Table of contents inserted by <?asciidoc-toc?> processing instruction.
+-->
+<xsl:param name="generate.toc">
+ <xsl:choose>
+ <xsl:when test="/processing-instruction('asciidoc-toc')">
+article toc,title
+book toc,title,figure,table,example,equation
+ <!-- The only way I could find that suppressed book chapter TOCs -->
+ <xsl:if test="$generate.section.toc.level != 0">
+chapter toc,title
+part toc,title
+preface toc,title
+qandadiv toc
+qandaset toc
+reference toc,title
+sect1 toc
+sect2 toc
+sect3 toc
+sect4 toc
+sect5 toc
+section toc
+set toc,title
+ </xsl:if>
+ </xsl:when>
+ <xsl:otherwise>
+article nop
+book nop
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:param>
+
+</xsl:stylesheet>
diff --git a/doc/resources/docbook-xsl/fo.xsl b/doc/resources/docbook-xsl/fo.xsl
new file mode 100644
index 0000000..4b2717e
--- /dev/null
+++ b/doc/resources/docbook-xsl/fo.xsl
@@ -0,0 +1,170 @@
+<!--
+ Generates single FO document from DocBook XML source using DocBook XSL
+ stylesheets.
+
+ See xsl-stylesheets/fo/param.xsl for all parameters.
+
+ NOTE: The URL reference to the current DocBook XSL stylesheets is
+ rewritten to point to the copy on the local disk drive by the XML catalog
+ rewrite directives so it doesn't need to go out to the Internet for the
+ stylesheets. This means you don't need to edit the <xsl:import> elements on
+ a machine by machine basis.
+-->
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:fo="http://www.w3.org/1999/XSL/Format">
+<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl"/>
+<xsl:import href="common.xsl"/>
+
+<xsl:param name="fop1.extensions" select="1" />
+<xsl:param name="variablelist.as.blocks" select="1" />
+
+<xsl:param name="paper.type" select="'A4'"/>
+<!--
+<xsl:param name="paper.type" select="'USletter'"/>
+-->
+<xsl:param name="hyphenate">false</xsl:param>
+<!-- justify, left or right -->
+<xsl:param name="alignment">left</xsl:param>
+
+<xsl:param name="body.font.family" select="'serif'"/>
+<xsl:param name="body.font.master">12</xsl:param>
+<xsl:param name="body.font.size">
+ <xsl:value-of select="$body.font.master"/><xsl:text>pt</xsl:text>
+</xsl:param>
+
+<xsl:param name="body.margin.bottom" select="'0.5in'"/>
+<xsl:param name="body.margin.top" select="'0.5in'"/>
+<xsl:param name="bridgehead.in.toc" select="0"/>
+
+<!-- overide setting in common.xsl -->
+<xsl:param name="table.frame.border.thickness" select="'2px'"/>
+
+<!-- Default fetches image from Internet (long timeouts) -->
+<xsl:param name="draft.watermark.image" select="''"/>
+
+<!-- Line break -->
+<xsl:template match="processing-instruction('asciidoc-br')">
+ <fo:block/>
+</xsl:template>
+
+<!-- Horizontal ruler -->
+<xsl:template match="processing-instruction('asciidoc-hr')">
+ <fo:block space-after="1em">
+ <fo:leader leader-pattern="rule" rule-thickness="0.5pt" rule-style="solid" leader-length.minimum="100%"/>
+ </fo:block>
+</xsl:template>
+
+<!-- Hard page break -->
+<xsl:template match="processing-instruction('asciidoc-pagebreak')">
+ <fo:block break-after='page'/>
+</xsl:template>
+
+<!-- Sets title to body text indent -->
+<xsl:param name="body.start.indent">
+ <xsl:choose>
+ <xsl:when test="$fop.extensions != 0">0pt</xsl:when>
+ <xsl:when test="$passivetex.extensions != 0">0pt</xsl:when>
+ <xsl:otherwise>0pt</xsl:otherwise>
+ </xsl:choose>
+</xsl:param>
+<xsl:param name="title.margin.left">
+ <xsl:choose>
+ <xsl:when test="$fop.extensions != 0">-1pc</xsl:when>
+ <xsl:when test="$passivetex.extensions != 0">0pt</xsl:when>
+ <xsl:otherwise>0pt</xsl:otherwise>
+ </xsl:choose>
+</xsl:param>
+<xsl:param name="page.margin.bottom" select="'0.25in'"/>
+<xsl:param name="page.margin.inner">
+ <xsl:choose>
+ <xsl:when test="$double.sided != 0">0.75in</xsl:when>
+ <xsl:otherwise>0.75in</xsl:otherwise>
+ </xsl:choose>
+</xsl:param>
+<xsl:param name="page.margin.outer">
+ <xsl:choose>
+ <xsl:when test="$double.sided != 0">0.5in</xsl:when>
+ <xsl:otherwise>0.5in</xsl:otherwise>
+ </xsl:choose>
+</xsl:param>
+
+<xsl:param name="page.margin.top" select="'0.5in'"/>
+<xsl:param name="page.orientation" select="'portrait'"/>
+<xsl:param name="page.width">
+ <xsl:choose>
+ <xsl:when test="$page.orientation = 'portrait'">
+ <xsl:value-of select="$page.width.portrait"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$page.height.portrait"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:param>
+
+<xsl:attribute-set name="monospace.properties">
+ <xsl:attribute name="font-size">10pt</xsl:attribute>
+</xsl:attribute-set>
+
+<xsl:attribute-set name="admonition.title.properties">
+ <xsl:attribute name="font-size">14pt</xsl:attribute>
+ <xsl:attribute name="font-weight">bold</xsl:attribute>
+ <xsl:attribute name="hyphenate">false</xsl:attribute>
+ <xsl:attribute name="keep-with-next.within-column">always</xsl:attribute>
+</xsl:attribute-set>
+
+<xsl:attribute-set name="sidebar.properties" use-attribute-sets="formal.object.properties">
+ <xsl:attribute name="border-style">solid</xsl:attribute>
+ <xsl:attribute name="border-width">1pt</xsl:attribute>
+ <xsl:attribute name="border-color">silver</xsl:attribute>
+ <xsl:attribute name="background-color">#ffffee</xsl:attribute>
+ <xsl:attribute name="padding-left">12pt</xsl:attribute>
+ <xsl:attribute name="padding-right">12pt</xsl:attribute>
+ <xsl:attribute name="padding-top">6pt</xsl:attribute>
+ <xsl:attribute name="padding-bottom">6pt</xsl:attribute>
+ <xsl:attribute name="margin-left">0pt</xsl:attribute>
+ <xsl:attribute name="margin-right">12pt</xsl:attribute>
+ <xsl:attribute name="margin-top">6pt</xsl:attribute>
+ <xsl:attribute name="margin-bottom">6pt</xsl:attribute>
+</xsl:attribute-set>
+
+<xsl:param name="callout.graphics" select="'1'"/>
+
+<!-- Only shade programlisting and screen verbatim elements -->
+<xsl:param name="shade.verbatim" select="1"/>
+<xsl:attribute-set name="shade.verbatim.style">
+ <xsl:attribute name="background-color">
+ <xsl:choose>
+ <xsl:when test="self::programlisting|self::screen">#E0E0E0</xsl:when>
+ <xsl:otherwise>inherit</xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+</xsl:attribute-set>
+
+<xsl:attribute-set name="component.title.properties">
+ <xsl:attribute name="font-size">16pt</xsl:attribute>
+</xsl:attribute-set>
+<xsl:attribute-set name="section.title.level1.properties">
+ <xsl:attribute name="font-size">14pt</xsl:attribute>
+</xsl:attribute-set>
+<xsl:attribute-set name="section.title.level2.properties">
+ <xsl:attribute name="font-size">13pt</xsl:attribute>
+</xsl:attribute-set>
+<xsl:attribute-set name="section.title.level3.properties">
+ <xsl:attribute name="font-size">12.2pt</xsl:attribute>
+</xsl:attribute-set>
+<xsl:attribute-set name="normal.para.spacing">
+ <xsl:attribute name="space-before.optimum">0.4em</xsl:attribute>
+ <xsl:attribute name="space-before.minimum">0.5em</xsl:attribute>
+ <xsl:attribute name="space-before.maximum">0.6em</xsl:attribute>
+</xsl:attribute-set>
+
+<!--
+ Force XSL Stylesheets 1.72 default table breaks to be the same as the current
+ version (1.74) default which (for tables) is keep-together="auto".
+-->
+<xsl:attribute-set name="table.properties">
+ <xsl:attribute name="keep-together.within-column">auto</xsl:attribute>
+</xsl:attribute-set>
+
+</xsl:stylesheet>
diff --git a/doc/resources/make.param b/doc/resources/make.param
new file mode 100644
index 0000000..d2523f6
--- /dev/null
+++ b/doc/resources/make.param
@@ -0,0 +1,15 @@
+
+ASCIIDOC=asciidoc
+A2X=a2x
+
+DEST=../../dist/doc
+
+RES=../resources
+XSL=$(RES)/docbook-xsl/fo.xsl
+ICONSDIR=$(RES)/common-images/icons
+
+HTML_ATTRS=--conf-file=../resources/asciidoc/local-missing-blockdef.conf -a data-uri
+PDF_OPTS=--icons --icons-dir=$(ICONSDIR) \
+ --asciidoc-opts='--conf-file=../resources/asciidoc/local-docbook45.conf' \
+ -a pubdate="$$(date +'%d %B %Y')"
+
diff --git a/doc/styles/Makefile b/doc/styles/Makefile
new file mode 100644
index 0000000..c2d23be
--- /dev/null
+++ b/doc/styles/Makefile
@@ -0,0 +1,37 @@
+
+include ../resources/make.param
+
+
+SOURCES= about.txt creating.txt design.txt files.txt rules.txt rules-filters.txt \
+ style-manual.txt $(XSL)
+STYLE_MAIN=style-manual.txt
+TARGET_PDF=style-manual.pdf
+
+build: html
+
+all: html pdf epub
+
+html: style-manual.html
+pdf: style-manual.pdf
+epub: style-manual.epub
+
+style-manual.html: $(SOURCES)
+ $(ASCIIDOC) $(HTML_ATTRS) -a icons -a iconsdir=$(ICONSDIR) -b html5 $(STYLE_MAIN)
+
+$(TARGET_PDF): $(SOURCES)
+ $(A2X) --xsl-file=$(XSL) --fop $(PDF_OPTS) $(STYLE_MAIN)
+
+style-manual.epub: $(SOURCES)
+ mkdir -p build
+ cp -ru $(RES)/common-images build
+ $(A2X) --format epub --icons --icons-dir=build/common-images/icons $(STYLE_MAIN)
+
+
+install: $(DEST)/$(TARGET_PDF)
+ cp -u $(TARGET_PDF) $(DEST)
+
+$(DEST)/$(TARGET_PDF): pdf
+
+clean:
+ rm -f style-manual.{pdf,epub,html}
+ rm -rf build
diff --git a/doc/styles/about.txt b/doc/styles/about.txt
new file mode 100644
index 0000000..136cc39
--- /dev/null
+++ b/doc/styles/about.txt
@@ -0,0 +1,46 @@
+
+= About =
+== Licence ==
+This manual is released under the
+link:http://creativecommons.org/licenses/by-sa/2.0/[Creative Commons Attribution-ShareAlike 2.0 license].
+It makes use of some material that was added to the OSM Wiki which is
+release under the same licence.
+
+== Authors and acknowledgments ==
+This manual is created from material that originated from the mkgmap doc
+files and added to OSM wiki. While on the OSM wiki modifications were
+made by many people.
+
+People who have contributed suggestions and corrections to this document
+are:
+Carlos Dávila,
+Geoff Sherlock
+
+
+The list of nicknames of everyone that had modified the wiki pages at the time that
+this manual was created is as follows:
+Brogo,
+Christian Gawron,
+Csdf,
+De muur,
+Derstefan,
+DirkS,
+Extremecarver,
+Gernot,
+!i!,
+Jinx1971,
+Katpatuka,
+MarkS,
+Master,
+Mezzanine,
+Nakor,
+Nop,
+Richard,
+Skela,
+SomeoneElse,
+Tommybgoode,
+Ulfl,
+Walterschloegl,
+WanMil,
+Willem1,
+Yggdrasil
diff --git a/doc/styles/creating.txt b/doc/styles/creating.txt
new file mode 100644
index 0000000..06d687c
--- /dev/null
+++ b/doc/styles/creating.txt
@@ -0,0 +1,197 @@
+
+= Creating a style =
+
+== Testing a style ==
+You can test your style by calling mkgmap with the
+++--style-file=++__path-to-style__ and the `--list-styles` option. If you see your style listed, then your style is recognized by mkgmap.
+Additional tests are performed if you use the `--check-styles` option. The type values are verified to make sure that they are valid. Further checks try to find rules which assign a routable type to a line without making it a road by assigning road_class or road_speed. This is known to cause problems with routing in routable maps.
+Then you can test if your style is valid by using it when creating a map.
+A style can be used just as it was created, but if you want to make it available to others it will be easier if you make a zip file out of it and then you just have the one file to distribute. You just can zip all files of the style. Several different styles can be placed into the same zip archive file.
+
+To use a zipped style, you can use ++--style-file=++__stylename__++.zip++. If
+there is more than one style in the zip file, then you can
+use ++--style-file=++__zipname__`.zip` `--style=`__stylename__.
+
+=== Tests performed by check-styles ===
+The `--check-styles` option verfies that your style uses type values which can processed by mkgmap.
+
+The following rules are verified:
+
+. If a type is ≥ 0x0100 (means it has more than one byte), the rightmost byte
+must be between 0x00 and 0x1f, so e.g. 0x011f is ok, 0x0120 is not.
+. If a type is ≥ 0x010000, it is an extended type, which can be used for points, lines, and polygons.
+. If the type is not extended, it must be ≥ 0x0100 for a point, ≤ 0x3f for a line, and ≤ 0x7f
+for a polygon.
+. The polygon type 0x4a is reserved for the overview map.
+. It is known that the usage of routable types for non-routable lines in resolution 24 can cause
+routing problems (e.g. address search doesn't work). The check will flag rules that assign a routable type for a line in resolution 24 without giving road_class or road_speed. A routable type is between 0x01 and 0x13 or one of: 0x1a, 0x1b, 0x16.
+
+[[style-packaging]]
+== Making a style package ==
+
+A style can be used just as it was created, but if you want to make it
+available to others it will be easier if you
+combine all the individual files into a single archive file.
+
+=== Zip archive
+The first way of doing this is to combine the files into a zip file
+and then you just have the one file to distribute.
+
+To use a zipped style, you can use
+ --style-file=stylename.zip
+
+It does not matter if you include the directory holding the files or not
+in the archive. The style is found by searching for the +version+ file.
+
+You can have more than one style in the zip file, each in their own
+directory. In this case you must include the top level directories of the
+style (and you can include other parent directories as well if you like).
+If there is more than one style in the zip file, then you can use the
++--style+ option alongside the +--style-file+ option.
+ --style-file=zipname.zip --style=stylename.
+
+.Style package layout
+[example]
+--
+----
+.
+`-- mystyles
+ |-- cycle
+ | |-- lines
+ | |-- points
+ | |-- polygons
+ | `-- version
+ `-- hiking
+ |-- lines
+ |-- points
+ |-- polygons
+ `-- version
+----
+
+Here there are two styles named _cycle_ and _hiking_. You can select the `hiking'
+style with the options
+ --style-file=mystyles.zip --style=hiking
+--
+
+=== Simple file archive
+This is formed by appending all of the files of a style into a single
+file separated by lines that contain the file name in triple angled
+brackets.
+
+.Single file archive
+-------
+<<<version>>>
+0
+
+<<<points>>>
+amenity=doctor [0x2a2a level 0]
+# More point definitions here...
+
+<<<lines>>>
+# All the line definitions here...
+------
+
+The file must have a name ending in +.style+ to be recognised.
+
+This file can be easily created in its entirity in a text editor, but you
+can also convert between the files-in-a-directory format and the
+single-file format using the following command:
+
+-----
+ # (to be typed all on one line)
+ java -cp mkgmap.jar uk.me.parabola.mkgmap.osmstyle.StyleImpl
+ mystyle > mystyle.style
+-----
+
+To convert back then supply the file as the argument, rather than the
+directory.
+
+////
+== Examples ==
+
+Examples of mkgmap conversion style rules.
+
+=== Alternatives ===
+Two or more osm tags resolve to the same element in the garmin map.
+----
+highway=footway | highway=path [0x16 level 1]
+----
+
+This is exactly the same as writing the two lines:
+----
+highway=footway [0x16 level 1]
+highway=path [0x16 level 1]
+----
+
+=== White space ===
+Space and new lines don't matter except to separate words that have to be
+separate.
+You can add as much space and as many newlines to the rule to make
+it look good. Or remove them depending on taste. For example the following two rules
+are exactly the same:
+----
+highway = primary
+ | highway=primary_link
+ [
+ 0x2
+ level 3
+ ]
+
+highway=primary|highway=primary_link[0x2 level 3]
+----
+
+=== The Garmin Map ===
+Each Garmin map may contain several separate maps which are prepared at different 'levels' of detail, the most appropriate of these is displayed depending on the zoom selected by the user.
+
+When creating the map, the map maker will choose which of these 'level' maps is displayed according to the 'resolution' (or zoom) selected. For example, a map might contain three levels (0, 1 & 2); On the level 2 map (showing the largest area) a town might just be represented by a named dot; as the user zooms in, the display might switch to the level 1 map showing an outline of the town. Zooming in further might switch to the level 0 map, with the individual streets of the town shown.
+
+''In addition the GPS itself might decide when to show or hide individual features in each of the 'level' maps, especially with POIs. This is also affected by the 'detail' setting in the map config menu.''
+
+=== Resolution ===
+The first is 'resolution' this is a number between 1 and 24 with 24 being the most detailed resolution and each number less is half as detailed. So for example if a road was 12 units long at resolution 24 it would be only 6 at resolution 23 and just 3 at resolution 22.
+
+On a Legend Cx the resolution corresponds the these scales on the device:
+
+.Resolutions
+[width="40%",cols="1,2",frame="topbot",grid="rows"]
+|=====
+| Resolution | Scale on device
+| 16 | 30km-12km
+| 18 | 8km-3km
+| 20 | 2km-800m
+| 22 | 500m-200m
+| 23 | 300m-80m
+| 24 | 120m-50m
+|=====
+
+It may be slightly different on different devices. There is an option
+to increase or decrease the detail and if you change that from 'Normal'
+then it will change the values above too.
+
+=== Level ===
+The next is 'level'. This is a number between 0 and 16 (although perhaps numbers above 10 are not usable), with 0 corresponding to the most detailed view. The map consists of a number of levels starting (usually) with 0. For example 0, 1, 2, 3 and a different amount of detail is added at each level.
+
+The map also contains a table to link the level to the resolution. So you can say that level 0 corresponds to resolution 24.
+
+This mapping is specified in the file 'options' within the style directory in use. You can also specify it on the command line, for example:
+
+ --levels=0:24,1:22,2:20
+
+This means that the map will have three levels. Level 0 in the map will correspond to resolution 24 (the most detailed), level 1 will show at
+resolution 22 (between scales of 500m and 200m) and so on. The lowest level needs to include at least an object, therefore the default lowest level of 16 will create a broken map, if your osm input file has no information at zoom level 16 or lower included.
+
+==== Watch out with levels when building topographical maps ====
+According to the principle that a map is never allowed to have an empty layer, if you have two input files for mkgmap, you have to specify --levels for each input file. This is especially important when one of the input files consists exclusively of contour lines. Take the following command as example on how to create such a map. (Attention the line wrap is only here for the wiki, this has to be one command in cmd.exe or terminal)
+-----
+ java -jar mkgmap.jar --style-file=D:\path\to\mkgmap\resources\styles\style_name\
+ --levels=0:24,1:22,2:20,3:18,4:16,5:14,6:12,7:10 data.osm
+ --levels=0:24,1:22,2:20 srtm.osm
+-----
+This would assume that your contour lines are in layer 24 (minor), 22 (medium) and 20 (major) and your normal osm data spread between 24 and 10. If you don't adhere to proper levels you will get problems with the map not displaying at lower zoom levels, not displaying at higher zoom levels or not displaying at all (you'll only see the background polygon 0x4c).
+
+There are 2 alternatives to circumvent having to assign different levels on compile.
+ a) Introduce dummy objects at the lowest level into your map. A POI in the lowest level per input file is enough.
+ b) Merge your osm files (either by script or in text editor (text editor may crash though on opening huge .osm files), and then use the lowest resulting level.
+Concluding the easiest is to include dummy objects at lowest level. (it should be thought about mkgmap doing this by default). The lower your lowest level the later the basemap will exchange your osm map.
+Your lowest level object is the defined by the object with the lowest level (as defined in your style) actually present in your osm input file.
+////
diff --git a/doc/styles/design.txt b/doc/styles/design.txt
new file mode 100644
index 0000000..5c2d631
--- /dev/null
+++ b/doc/styles/design.txt
@@ -0,0 +1,63 @@
+[[DESIGN]]
+= Designing the map
+You can completely change which features are displayed and at what zoom levels.
+
+First you need to understand a little about the way that the zoom works in Garmin maps. There are two concepts 'resolution' and 'level'.
+
+== The Garmin Map
+
+Each Garmin map may contain several separate maps which are prepared at different 'levels' of detail, the most appropriate of these is displayed depending on the zoom selected by the user.
+
+When creating the map, the map maker will choose which of these 'level' maps is displayed according to the 'resolution' (or zoom) selected. For example, a map might contain three levels (0, 1 & 2); On the level 2 map (showing the largest area) a town might just be represented by a named dot; as the user zooms in, the display might switch to the level 1 map showing an outline of the town. Zooming in further might switch to the level 0 map, with the individual streets of the town shown.
+
+In addition the GPS itself might decide when to show or hide individual features in each of the 'level' maps, especially with POIs. This is also affected by the 'detail' setting in the map config menu.
+
+=== Resolution ===
+The first is 'resolution' this is a number between 1 and 24 with 24 being the most detailed resolution and each number less is half as detailed. So for example if a road was 12 units long at resolution 24 it would be only 6 at resolution 23 and just 3 at resolution 22.
+
+On a Legend Cx the resolution corresponds the these scales on the device:
+
+
+[width="80%",cols="1,4",frame="topbot",grid="rows",options="header"]
+|====
+| Resolution |Scale on device
+| 16 | 30km-12km
+| 18 | 8km-3km
+| 20 | 2km-800m
+| 22 | 500m-200m
+| 23 | 300m-80m
+| 24 | 120m-50m
+|====
+
+It may be slightly different on different devices. There is an option
+to increase or decrease the detail and if you change that from 'Normal'
+then it will change the values above too.
+
+=== Level ===
+The next is 'level'. This is a number between 0 and 16 (although perhaps numbers above 10 are not usable), with 0 corresponding to the most detailed view. The map consists of a number of levels starting (usually) with 0. For example 0, 1, 2, 3 and a different amount of detail is added at each level.
+
+The map also contains a table to link the level to the resolution. So you can say that level 0 corresponds to resolution 24.
+
+This mapping is specified in the file 'options' within the style directory in use. You can also specify it on the command line, for example:
+
+ --levels=0:24,1:22,2:20
+
+This means that the map will have three levels. Level 0 in the map will correspond to resolution 24 (the most detailed), level 1 will show at
+resolution 22 (between scales of 500m and 200m) and so on. The lowest level needs to include at least an object, therefore the default lowest level of 16 will create a broken map, if your osm input file has no information at zoom level 16 or lower included.
+Up to 8 levels are allowed.
+
+=== Overview Level ===
+The next is 'overview-level'. The meaning is the same as in level, but it is used for the creation of the overview map. The overview
+map is used in PC programs like Basecamp or Mapsource, it improves the drawing speed when looking at the whole map.
+
+The GARMIN map contains only one overview map, so it should not contain too many details, else it will reach size limits.
+
+This mapping is specified in the file 'options' within the style directory in use. You can also specify it on the command line, for example:
+
+ --overview-levels=3:18,4:16,5:12
+
+It is recommended to continue the numbers of the levels. Again, up to 8 levels are allowed.
+
+
+
+
diff --git a/doc/styles/files.txt b/doc/styles/files.txt
new file mode 100644
index 0000000..251c6f3
--- /dev/null
+++ b/doc/styles/files.txt
@@ -0,0 +1,171 @@
+
+[[FILES]]
+= The structure of a style =
+
+A style consists of a number of files in a single directory. The best way
+is to start out with an existing style that is close to what you want and
+then work from there.
+
+A style can be packed into a single file using the standard zip utilities
+that are available on every operating system, or it can be written as one
+large text file using the single file style format. These alternatives
+are explained in <<style-packaging,making a style package>>.
+
+== Files ==
+These files are read in the order that they are listed here. In general, files that are read first take priority over files read later.
+The only one of these files that is actually required is the +version+
+file, as that is used to recognise the style.
+At least one of the +points+, +lines+ or +polygons+ files must be present
+or else the resulting maps will be empty.
+
+=== Top level folder ===
+Choose a short name for your style, it should be one word or a couple of words joined by an underscore or hyphen. This is how people will refer to the style when it is finished.
+Create a directory or folder with that name. Then you must create one or
+more files in this directory as detailed below. Only the +version+ file is required.
+
+== The version file
+This file _must_ exist as it is used to recognise a valid style.
+It contains the version number of the style language itself, (not the
+version number of your style, which you can specify in the +info+ file
+if you so wish).
+The current version number of the style language is 1.
+Make sure that there is a new line after the number, place an empty line afterwards to be sure.
+
+== The info file
+This file contains information about your style.
+It is all optional information, and there is only really any point
+adding this information if you are going to distribute your style, or
+you have more than one style that you maintain.
+
+The file consists of key=value pairs in the same syntax as the
+command line option file. To summarise you can use either an equal sign
+'=' or a colon ':' to separate the key from the value. You can also
+surround the value with curly braces '{ }' and this allows you to
+write the value over several lines.
+
+[horizontal]
+version:: The version number of your style.
+
+summary:: A short description of your style in one line.
+
+description:: A longer description of your style.
+
+base-style:: Do not use anymore. This was used to base a style on
+another one. However, it is bug prone and behaves in a way that is not
+intuitive without a good understanding of how things work.
+The preferred way to do this is to use the include mechanism.
+This command will be removed altogether at some point in the future.
+
+.An example info file
+====
+Here is an example based on the +info+ file from the default style.
+You can see it uses both equal and colon as separators, normally you
+would just pick one and use it consistently, but it doesn't make any
+difference which one you use.
+The description is written over several lines surrounded in curly
+brackets.
+Lines beginning with a hash symbol '#' are comments and are ignored.
+----
+#
+# This file contains information about the style.
+#
+
+summary: The default style
+
+version=1.0
+
+description {
+The default style. This is a heavyweight style that is
+designed for use when mapping and especially in lightly covered
+areas.
+}
+----
+====
+
+
+== The options file
+This file contains a number of options that should be set for this style
+as if they were set on the command line.
+Only command line options that affect the style will have any effect.
+The current list is +levels+, +overview-levels+, and +extra-used-tags+.
+
+It is advisable to set up the levels that you want, as the default is not
+suitable for all kinds of maps and may change in the future. Ideally,
+you should set the same levels as are used in your style files. For
+example, if your style files use levels 12,16,20,22,23,24 then it's a
+good idea to make sure your options style file declares these levels
+explicitly.
+
+.An example options file
+====
+ levels = 0:24, 1:22, 2:20, 3:18
+ overview-levels = 4:17, 5:16, 6:15, 7:14, 8:12
+ extra-used-tags=
+====
+
+=== Non command line options
+Most of the options are the same as the command line option of the same
+name and so you should see its description in the option help.
+There are however some options that can only be set in this file
+(just the currently).
+
+extra-used-tags:: A list of tags used by the style. You do not normally
+need to set this, as mkgmap can work out which tags are used by a style
+automatically in most cases. It exists only to work around cases where
+this doesn't work properly.
+
+== The points file
+This files contains a set of rules for converting
+OSM nodes to Garmin POIs (restaurants, bars, ATMs etc).
+It can also contain rules for some kind of OSM nodes that may
+affect routing behavior, for example barriers, traffic_calming, traffic_signals, etc.
+
+If this file is not present or empty then there will be no POI's in the
+final map.
+
+The syntax of the file is described in the <<RULES,style rules section>>.
+Like all other files, a hash symbol '#' introduces a comment.
+
+== The lines file
+This file contains a set of rules for converting OSM ways to Garmin lines (roads, rivers, barriers, etc).
+The syntax of the file is described in the <<RULES,style rules section>>.
+
+== The polygons file
+This file contains a set of rules for converting polygons to Garmin
+areas (fields, buildings, residential areas, etc).
+The syntax of the file is described in the <<RULES,style rules section>>.
+
+== The relations file
+This file contains a set of rules to convert OSM relations.
+Unlike the +points+, +lines+ and +polygons+ files this file does not lead
+directly to a Garmin object.
+Instead it is used to modify the ways or nodes that are contained in the
+relation.
+
+So for example, if the relation represents a route, then you might add one
+or more tags to all the ways that make up the route so that they can be
+processed in the +lines+ file specially.
+
+The syntax of the file is also described in the <<RULES,style rules section>>,
+but the rules can only have an action part, they must not have a type
+description part.
+
+////
+== The overlays file
+The idea of this file
+Used where you want a single way to be converted to two ways in the output map (for example a road might be rendered as normal but an additional line is created if the road is oneway - this then allows you to use a TYP file to add oneway arrows to the road). An example of use might be:
+
+In the lines file:
+-----
+highway=trunk & oneway=yes [0x123 road_class=3 road_speed=5 resolution 16]
+-----
+
+In the overlays file:
+----
+0x123: 0x02, 0x23
+----
+
+Then set the TYP file contain arrows for code 0x23.
+
+Note that only the first way in the overlays file is routable.
+////
diff --git a/doc/styles/img/sym-box.png b/doc/styles/img/sym-box.png
new file mode 100644
index 0000000..4f37269
Binary files /dev/null and b/doc/styles/img/sym-box.png differ
diff --git a/doc/styles/img/sym-hbox.png b/doc/styles/img/sym-hbox.png
new file mode 100644
index 0000000..2f2cb30
Binary files /dev/null and b/doc/styles/img/sym-hbox.png differ
diff --git a/doc/styles/img/sym-interstate.png b/doc/styles/img/sym-interstate.png
new file mode 100644
index 0000000..cbaac5a
Binary files /dev/null and b/doc/styles/img/sym-interstate.png differ
diff --git a/doc/styles/img/sym-oval.png b/doc/styles/img/sym-oval.png
new file mode 100644
index 0000000..87be8ee
Binary files /dev/null and b/doc/styles/img/sym-oval.png differ
diff --git a/doc/styles/img/sym-round.png b/doc/styles/img/sym-round.png
new file mode 100644
index 0000000..8fa3e0b
Binary files /dev/null and b/doc/styles/img/sym-round.png differ
diff --git a/doc/styles/img/sym-shield.png b/doc/styles/img/sym-shield.png
new file mode 100644
index 0000000..5e98dfa
Binary files /dev/null and b/doc/styles/img/sym-shield.png differ
diff --git a/doc/styles/main.txt b/doc/styles/main.txt
new file mode 100644
index 0000000..33ca269
--- /dev/null
+++ b/doc/styles/main.txt
@@ -0,0 +1,52 @@
+
+= Conversion Style manual
+The mkgmap team
+v1.0, December 2012
+:toc:
+:numbered:
+:website: http://www.mkgmap.org.uk
+:email: mkgmap-dev at lists.mkgmap.org.uk
+:description: Describes the style language that converts from OSM tags to Garmin types.
+
+Introduction
+------------
+
+This manual explains how to write a mkgmap style to convert
+between OSM tags and features on a Garmin GPS device.
+
+A style is used to choose which OSM map features appear in the
+Garmin map and which Garmin symbols are used.
+
+There are a few styles built into mkgmap, but
+as there are many different purposes a map may used for, the default
+styles in mkgmap will not be ideal for everyone, so
+you can create and use styles external to mkgmap.
+
+The term _style_ could mean the actual way that the features appear on
+a GPS device, the colour, thickness of the line and so on. This manual
+does not cover that, and if that is what you are looking for, then you
+need the documentation for *TYP files*.
+
+Few people will want to write their own style from scratch, most people
+will use the built in conversion style, or at most make a few changes
+to the default style to add or remove a small number of features.
+For general information about running and using mkgmap see the
+*Tutorial document*.
+
+To be clear this is only needed for converting OSM tags, if you are
+starting with a Polish format file, there is no style involved as the
+garmin types are already fully specified in the input file.
+
+For general information about the Open Street Map project see the
+link:http://wiki.openstreetmap.org[Open Street Map wiki].
+
+
+:leveloffset: 1
+
+include::design.txt[]
+
+include::files.txt[]
+
+include::rules.txt[]
+
+include::creating.txt[]
diff --git a/doc/styles/rules-filters.txt b/doc/styles/rules-filters.txt
new file mode 100644
index 0000000..6703336
--- /dev/null
+++ b/doc/styles/rules-filters.txt
@@ -0,0 +1,136 @@
+//
+// This is the list of variable filters.
+//
+.List of all substitution filters
+[width="100%",grid="rows",cols="<1,<1,3a",options="header"]
+|=======
+| Name | Arguments | Description
+| def | `default` |
+If the variable is not set, then use the argument as a default value.
+This means that the variable will never be `unset' in places where that
+matters.
+
+`${oneway\|def:no}`
+
+| conv | `factor` |
+Use for conversions between units. The only supported version is from meters to feet
+number. It is multiplied by the argument.
+
+`${height\|conv:m=>ft}`
+
+| subst | `from=>to` +
+`from~>to`|
+Substitutes all occurrences of the string +from+ with the string +to+ in
+the tag value. The +`=>`+ operator can be used for an exact matches while +`~>`+ accepts
+regular expressions in the +from+ attribute.
+
++to+ can be empty to remove the +from+ string altogether.
+
+Example, if name ="Queen Street"
+
+`${name\|subst:Queen=>}` returns " Street"
+
+`${name\|subst:Queen=>King}` returns "King Street"
+
+`${name\|subst:.*\s~>}` returns "Street"
+
+| part | `separator operator partnumber` |
+Split a value in parts and returns one or more part(s) of it. If +partnumber+ is negative, the part returned is counted from the end of the split
+
+If not specified, the default separator is ';' and the first part is returned (i.e. `${name\|part:}`=`${name\|part:;:1}`).
+
+If the operator is `:` the part specified by +partnumber+ is returned.
+
+If the operator is `<` or `>` the correspondent number of parts before or after the +partnumber+ are returned
+
+Example: if the value is "Aa#Bb#Cc#Dd#Ee"
+
+`${name\|part:#:1}` returns Aa
+
+`${name\|part:#:-1}` returns Ee
+
+`${name\|part:#:2}` returns Bb
+
+`${name\|part:#:-2}` returns Dd
+
+`${name\|part:#>1}` returns Bb#Cc#Dd#Ee#
+
+`${name\|part:#<5}` returns Aa#Bb#Cc#Dd#
+
+`${name\|part:#<-1}` returns Aa#Bb#Cc#Dd#
+
+This can be especially useful for tags like ref, exit_to and destination or to switch words,
+example if value is "word1 word2 ... wordN-1 wordN"
+
+`${name\|part: :-1}, ${name\|part: <-1}` returns "wordN, word1 word2 ... wordN-1 "
+
+| highway-symbol | `symbol:max-num:max-alpha` |
+Prepares the value as a highway reference such as "A21" "I-80" and so
+on.
+A code is added to the front of the string so that a highway shield is
+displayed, spaces are removed and the text is truncated so as not to overflow the
+symbol.
+
+`${ref\|highway-symbol:box:4:8}`
+
+See below for a list of the +highway-symbol+ values.
+
+The first number is the maximum number of characters to allow for
+references that contain numbers and letters.
+The second is the maximum length of references that do not contain numbers.
+If there is just the one number then it is used in both cases.
+
+| height | `m=>ft` |
+This is the same as the +conv+ filter, except that it prepends a special
+separation character before the value which is intended for elevations.
+As with +conv+ the only supported conversion currently is from meters to feet.
+
+`${ele\|height:m=>ft}`
+
+| not-equal | `tag` |
+Used to check for duplicate tags. If the value of this tag is equal to
+the value of the tag named as the argument to +not-equal+, then value
+of this tag is set to undefined.
+
+....
+place=* {
+ name '${name} (${int_name\|not-equal:name})'
+ \| '${name}'
+ }
+....
+
+In that example, if the international name is different to the name then it will be placed
+in parenthesis after the name. Otherwise there will just be the name as given in the "name" tag.
+
+| substring | `start:end` |
+Extract part of the string. The start and end positions
+are counted starting from zero and the end position is not included.
+
+`${name\|substring:2:5}`
+If the "name" was "Dorset Lane", then the result is "rse". If there is just the one number,
+then the substring starts from that character until the end of the string.
+|=====
+
+=== Symbol codes
+Here is a list of all the symbols that can be created with images to give an
+idea of where they should be used.
+The actual symbol will depend on the device that it is displayed on.
+
+.Highway symbol codes
+[width="60%",cols="1,1,2",options="header"]
+|=====
+| Shield name | Symbol | Description
+| interstate | image:img/sym-interstate.png[] | US Interstate, digits only
+| shield | image:img/sym-shield.png[] | US Highway shield, digits only
+| round | image:img/sym-round.png[] | US Highway round, digits only
+| hbox | image:img/sym-hbox.png[] | Box for major roads
+| box | image:img/sym-box.png[] | Box for medium roads
+| oval | image:img/sym-oval.png[] | Box for smaller roads
+|====
+
+
+////
+| prefix | symbol code |
+hello
+| `${ref\|prefix:box}`
+////
diff --git a/doc/styles/rules.txt b/doc/styles/rules.txt
new file mode 100644
index 0000000..2fcc460
--- /dev/null
+++ b/doc/styles/rules.txt
@@ -0,0 +1,1031 @@
+
+[[RULES]]
+= Style rules =
+
+Rules allow you to take a map feature in the OSM format, which uses a set of tags to describe the feature into the format required by Garmin maps, where features are identified by a number.
+
+The rules for converting points, lines and polygons are held in
+correspondingly named files, as described in <<FILES,the structure of a style>>.
+
+Each file contains a number of rules. Rules test the values of the tags of an OSM node, way or relation.
+They also select a specific Garmin type based on the result of those tests and set mkgmap internal tags (+mkgmap:*+) to assign specific attributes to a map element.
+
+== Introduction ==
+Each rule starts off with an expression to test the value of one or more
+tags.
+
+A rule is made up of two or three parts.
+The three possible parts are:
+
+* The first part is *required*: this is a set of <<Tag_tests,tests>> that are performed on the tags of the item to be converted.
+* The second part is the <<Action_block,action block>> that can be used to do things with the tags of objects that match the tests and is contained in curly brackets `{...}`.
+* The third part is the <<Element_type,element type definition>> and sets
+the Garmin type and sometimes other parameters that will be used if the tests match. This part is contained
+in square brackets `[...]`.
+
+Here is an example of a rule containing all three sections:
+
+----
+natural=cliff { name '${name} cliff' | 'cliff' } [0x10501 resolution 22]
+----
+
+* The tests section is +natural=cliff+
+* The action block is `{ name '${name} cliff' | 'cliff' }`
+* The element type definition is +[0x10501 resolution 22]+
+
+As a general point, space and newlines don't matter. There is no need to
+have rules all on the same line, and you can spread them out over several
+lines and add extra spaces wherever you like if it helps to make them
+easier to read.
+
+.Example with lots of extra space and newlines
+----
+natural=cliff
+ {
+ name '${name} cliff'
+ | 'cliff'
+ }
+
+ [
+ 0x10501
+ resolution 22
+ ]
+----
+
+.Example with all unneeded spaces removed
+----
+natural=cliff{name'${name} cliff'|"cliff"}[0x10501 resolution 22]
+----
+
+=== Tag and text values ===
+Tag names and vales are often single words consisting of letters and
+perhaps digits.
+If however a value (or tag, although that is less common) contains a
+space or punctuation character then the whole value must be enclosed in
+quotation marks. You can use either single quotes (+'+) or
+double quotes (+"+).
+
+If your text contains a quote then you must use the other kind
+of quote around the value.
+
+----
+highway=primary
+"highway"="primary" # quotes not needed, but do no harm
+name='Main Street' # quotes needed to keep 'Main Street' as one thing
+name="Ten O'Clock Tavern" # Double quotes used because text contains single quotes
+----
+
+[[Tag_tests]]
+== Tag tests ==
+The most common test is that a particular OSM tag has a given value.
+So for example if we have
+
+----
+highway=motorway
+----
+
+This means that we look up the highway tag in the OSM input file and if it exists and has the value
+'motorway' then this test has matched.
+
+You can also compare numeric quantities:
+----
+population > 10000
+lanes >= 2
+population < 10000000
+----
+
+Respectively, these mean: a population greater than ten thousand, a road with at least two lanes
+and a population less than one million.
+
+You may also use regular expressions:
+----
+ele ~ '\d*00'
+----
+This checks whether ele is a multiple of 100.
+
+=== Allowed operations
+The following table describes the operations that may be used.
+
+.Full list of operations
+[width="80%",cols="1,4",frame="topbot",grid="rows",options="header"]
+|====
+|Operation | description and examples
+
+| tag=value | This matches when a tag has the given value.
+
+| tag!=value | This is true when the tag does not have the given value,
+or the tag is not present at all.
+
+|tag=* | Matches when the tag exists, regardless of its value.
+
+|tag!=* | Matches when the tag does _not_ exist.
+
+|tag < value |
+Matches when the tag when converted as a number is less than the given value.
+If the value is not numeric then this is always false. This is also the case if
+value contains a unit. Conversion for the maxspeed tag can be done with
+the maxspeedkmh() and maxspeedmph() function (see <<Functions,Functions>>).
+
+|tag \<= value,
+tag > value,
+tag >= value |
+As above, for less than or equal, greater than and greater than or equal.
+
+|tag ~ REGEX| This is true when the value of the tag matches the given
+regular expression.
+The link::http://docs.oracle.com/javase/1.4.2/docs/api/java/util/regex/Pattern.html[Java
+regular expression] syntax is recognised.
+For example `name ~ '.*[Ll]ane'` would match every name that ended in
+'Lane' or 'lane'.
+
+| ! (expr) |
+The 'not' operator ('!') reverses the truth of the expression following.
+That expression must be in brackets.
+
+|====
+
+
+=== Combining tag tests ===
+Although it is possible to convert many OSM nodes and ways just using one
+tag, it is also often necessary to use more than one.
+
+For example, say you want to take roads that are tagged both as
++highway=unclassified+ and +lanes>2+ differently to roads that are
+just +highway=unclassified+. In this type of case, you might create two
+separate rules as follows:
+
+----
+highway=unclassified & lanes>2 [0x06]
+highway=unclassified [0x05]
+----
+
+This means that roads that are unclassified and have more than two lanes
+would use Garmin element type 0x06, whereas unclassified
+roads without a lanes tag, or where it is less or equal than 2
+would use type 0x05.
+
+It is important to note that the order of the rules is important here. The rules are
+matched in the order that they occur in the style file and mkgmap stops trying to apply them after
+the first one that matches.
+If you had the rules above in the reverse order, then the
++highway=unclassified+ rule would match first to any OSM way with that tag/key pair,
+and the second rule would never get applied.
+Therefore, in general you want the most specific rules first and simpler, more
+general rules later on to catch the cases that are not caught by the more
+complex rules.
+
+You can also combine alternatives into the one rule using a logical or, represented
+with a pipe (|) symbol. For example
+----
+highway=footway | highway=path [0x07]
+----
+
+This means if the road has either the *highway=footway* tag or the
+*highway=path* tags (or both), then the condition matches and mkgmap would
+use type 0x07 for the map. This works exactly the same as if you had written
+two separate rules - one for footway and one for path - and indeed is converted
+to two separate rules internally when mkgmap runs.
+
+You are not limited to two tests for a given rule... you can combine and group tests
+in almost whatever way you like.
+So for a slightly forced example the following would be possible:
+----
+place=town & (population > 1000000 | capital=true) | place=city
+----
+
+This would match if there was a +place+ tag which had the value +town+
+and either the population was over a million or it was tagged a capital,
+or there was a +place+ tag with the value +city+.
+
+[NOTE]
+There used to be some restrictions on the kind of expression you could
+use. Now the only restriction is you must have at least one test that
+depends on a tag existing. So you cannot match on everything, regardless
+of tags, or test for an object that does _not_ have a tag.
+
+=== Comparing the values of two tags ===
+Sometimes you may want to compare the values of two tags, rather than
+the value of one tag with a fixed value.
+Use a dollar sign to indicate that you want the tag value.
+
+----
+# If you had the following tags:
+# name=Fford-y-Mor
+# name:en=Terrace Road
+# name:cy=Fford-y-Mor
+
+name = $name:cy {...} # this would match
+name = $name:en {...} # and this would not
+----
+
+This tests if the value of the +name+ tag is the same as the welsh name
+tag (+name:cy+)
+
+It is worth noting that the normal case
+----
+highway=primary
+----
+is exactly the same as
+----
+$highway=primary
+----
+
+
+[[Functions]]
+=== Functions ===
+Functions calculate a specific property of an OSM element.
+
+.Style functions
+[width="100%",cols="2,1,1,1,5",options="header"]
+|=====
+|Function |Node |Way |Relation |Description
+|length() | | x | x |
+Calculates the length in m. For relations its the sum of all member length (including sub relations).
+
+|area_size() | | x | |
+Calculates area size in (garmin units)^2^. A non closed way has an area_size() of 0. In case a polygon is an outer part
+of a multipolygon the whole area size of all outer multipolygon parts is returned.
+
+The size of one (garmin unit)^2^ in m^2^ varies depending on the latitude. Sample values:
+
+5.71 m^2^ at latitude 0°
+
+4.03 m^2^ at (\+-)45°
+
+2.85 m^2^ at (\+-)60°
+
+0.5 m^2^ at (+-)85°
+|is_complete() | | x | |
++true+ if all nodes of a way are contained in the tile. +false+ if some nodes of the way are missing in the tile.
+
+|is_closed() | | x | |
++true+ the way is closed (start and end point are the same). +false+ the way is not closed and cannot be processed as polygon.
+
+|maxspeedkmh() | | x | |
+Retrieves the value of the 'maxspeed' tag converted to km/h.
+
+|maxspeedmph() | | x | |
+Retrieves the value of the 'maxspeed' tag converted to mph.
+
+|type() | x | x | x |
+Retrieves the type of the OSM element: 'node', 'way', 'relation'.
+
+|osmid() | x | x | x |
+Retrieves the id of the OSM element. This can be useful for style debugging purposes. Note that due to internal changes like merging, cutting etc.
+some element ids are changed and some have a faked id > 4611686018427387904.
+
+|====
+
+The following rule matches for all service ways longer than 50m.
+-----
+highway=service & length()>50
+-----
+
+[[Action_block]]
+== Action block ==
+An action block is enclosed in braces +{ ... }+ and contains one or more
+statements that can alter the element being displayed; multiple
+statements are separated by `;' symbol. When there is an action block, the
+<<Element_type,element type definition>> is optional, but if used it must
+come after the action block.
+
+A list of all the command that can be used in the action block follows.
+In the examples you will see notation of the form `${name}`, this is how
+tag values can be substituted into strings, in a similar way to many
+computer languages. For full details see
+the section on <<VARS,variable substitution>>.
+
+=== add ===
+The add command adds a tag if it does not already exist.
+This is often used if you want to set the value of a tag as a default but
+do not want to overwrite any existing tag.
+
+For example, motorways are one way by default so we need to add the
++oneway=yes+ tag in the style so that is treated as one way by the
+device. But there are some stretches of motorway that are one-way and
+these will be tagged as +oneway=no+. If we used +set+ then that tagging
+would be lost, so we use +add+.
+----
+ highway=motorway { add oneway=yes }
+----
+
+The other use is in in relations with the 'apply' command.
+
+All the same you can set any tag you want, it might be useful so you can match
+on it elsewhere in the rules.
+
+You can also use substitutions.
+----
+{add name='${ele}'; add name='${ref}';}
+----
+
+These two commands would set the 'name' tag to the value of the 'ele' tag if it exists, or to the value of the 'ref' tag if that exists.
+
+You can also give a list of alternative expressions separated with a
+vertical bar in the same way as on the name command. The first
+one that is fully defined will be used.
+
+----
+{add key123 = '${name:en}' | '${name}'; }
+----
+
+If 'key123' is not set it will set 'key123' to the value of the 'name:en' tag if it exists and to the 'name' tag if not.
+
+=== set ===
+The 'set' command is just like the 'add' command, except that it sets the
+tag, replacing any existing value it had.
+
+=== delete ===
+The delete command deletes a tag.
+----
+ { delete key123 }
+----
+
+=== deletealltags ===
+The deletealltags command deletes all tags. Usually this stops all further processing of the element.
+----
+ { deletealltags }
+----
+
+=== addlabel ===
+Each item in the Garmin map can have up to four labels. Usually only the first label is displayed.
+On some Garmin units the second label is used for routing instructions. The third
+and fourth label are known to be used for address search only. The four labels can be assigned
+by setting the tags +mkgmap:label:n+ where n is a number between 1 and 4.
+
+The addlabel command assigns the first empty +mkgmap:label:n+ tag with the given value.
+
+----
+ {addlabel '${name} (${ref})' | '${ref}' | '${name}'}
+----
+
+If both the +name+ and +ref+ tags are are set, then the first alternative would be
+completed and the resulting label might be _Main St (A1)_.
+If just +name+ was set, then the first two alternatives can not be fully
+substituted and so are ignored, leaving the last alternative +'${name}'+
+and so the final label might in that case be _Main St_.
+
+Highway shields can be used in the first label only. You can use the notation
++${tagname|highway-symbol:box}+.
+Valid symbols are +interstate+, +shield+, +round+, +hbox+, +box+ and
++oval+. The appropriate kind of highway shield will be added to the value
+of +tagname+. The exact result of the way it looks is dependent on where
+you view the map.
+
+=== name ===
+This sets the first label of the element but only if it is not already set.
+This is a helper action. The same effect can be produced with different notations
+as it is shown in the following example where all three lines have the same effect.
+----
+ {name '${name} (${ref})' | '${ref}' | '${name}'}
+ {add mkgmap:label:1='${name} (${ref})' | '${ref}' | '${name}'}
+ mkgmap:label:1!=* {set mkgmap:label:1='${name} (${ref})' | '${ref}' | '${name}'}
+----
+
+=== addaccess ===
+The "addaccess" action sets all unset mkgmap access restriction tags to the given value.
+This is a helper action to avoid long action blocks.
+
+----
+{ addaccess 'no' }
+----
+is the same as
+----
+{
+ add mkgmap:foot=no;
+ add mkgmap:bicycle=no;
+ add mkgmap:car=no;
+ add mkgmap:taxi=no;
+ add mkgmap:truck=no;
+ add mkgmap:bus=no;
+ add mkgmap:emergency=no;
+ add mkgmap:delivery=no
+}
+----
+
+=== setaccess ===
+The "setaccess" action sets all mkgmap access restriction tags to the given value no matter if
+they already have a value or not. This is a helper action to avoid long action blocks.
+
+----
+{ setaccess 'no' }
+----
+is the same as
+----
+{
+ set mkgmap:foot=no;
+ set mkgmap:bicycle=no;
+ set mkgmap:car=no;
+ set mkgmap:taxi=no;
+ set mkgmap:truck=no;
+ set mkgmap:bus=no;
+ set mkgmap:emergency=no;
+ set mkgmap:delivery=no
+}
+----
+
+=== apply ===
+The "apply" action only makes sense in relations. Say you have a
+relation marking a bus route, but none of the ways that are in the
+relation have any special tags to indicate that they form part of that
+bus route, and you want to be able to tell from looking at the map which
+buses go where. You can write a rule in the *relations file* such as:
+
+----
+type=route & route=bus {
+ apply {
+ set route=bus;
+ set route_ref='${route_ref}';
+ }
+}
+----
+
+
+Then in the *lines file* you will need to write a rule to match _route=bus_.
+All the relation rules are run before any others so that this works.
+
+The substitution `${route_ref}` takes the value of the tag on the *relation* and applies
+it to each of the ways in the relation.
+
+The substitution `$(route_ref)` (with parenthesis, rather than curly
+brackets) can be used for accessing the value of the tag on
+the actually processed *member* of the relation, e.g.
+
+----
+type=route & route=bus {
+ apply {
+ set route=bus;
+ set name='$(name) ${route_ref}';
+ }
+}
+----
+
+The "apply" action can be limited to members with a special role by adding
+_role=rolevalue_ after the _apply_ keyword.
+
+----
+type=route & route=bus {
+ apply role=forward {
+ set route=bus;
+ set name='$(name) ${route_ref}';
+ }
+}
+----
+
+=== apply_once ===
+The apply_once action is like +apply+, but it will apply the action once
+per relation member. A round-trip route relation may include the same
+ways multiple times, unless all member ways have been defined as parallel
+one way streets.
+
+=== echo ===
+The echo action prints the element id plus a text to standard error. This can be
+used for quality checks and debugging purposes.
+----
+highway=motorway_link & oneway!=* { echo "motorway_link without oneway tag" }
+----
+
+=== echotags ===
+The echotags action prints the element id, all tags and values plus a text to standard error.
+This can be used for style debugging purposes.
+----
+highway=living_street { echotags "This is a living_street" }
+----
+
+[[VARS]]
+== Variables
+You can substitute the value of tags within strings in an action.
+A dollar sign (+$+) introduces the substitution followed by the tag name
+surrounded by curly braces like so `${name}`.
+
+The most obvious use for variables is in setting the name of the element.
+You are able to use any combination of tags to make the name from.
+Here we name a fuel station by its brand and the name in brackets following.
+----
+amenity=fuel { name '${brand} (${operator})' } [ 0x2f01 ]
+----
+
+If the operator tag was not set, then the name would not be set because *all*
+substitutions in a string must exist for the result to be valid.
+This is why the "name" command takes a list of possibilities, if operator
+was simply replaced with a blank, then you would have an empty pair of brackets.
+So you would fix the previous rule by adding another name option.
+
+----
+ amenity=fuel
+ { name '${brand} (${operator})' | '${brand}' }
+ [ 0x2f01 ]
+----
+
+If only the brand tag exists, then the first option will be skipped and the second
+will be used.
+
+=== Variable filters
+The value of a variable can be modified by 'filters'.
+The value of the tag can be transformed in various ways before being
+substituted.
+
+A filter is added by adding a vertical bar symbol "|" after the tag name, followed
+by the filter name, then a colon ":" and an argument. If there is more than
+one argument required then they are usually separated by colons too, but
+that is not a rule.
+
+ ${tagname|filter:arg1:arg2}
+
+You can apply as many filter expressions to a substitution as you like.
+
+ ${tagname|filter1:arg|filter2:arg}
+
+include::rules-filters.txt[]
+
+== mkgmap internal tags ==
+There are lots of tags prefixed with +mkgmap:+. Some of them need to be set in the
+style file to set specific attributes of the Garmin map elements, e.g.
+access restrictions, labels, attributes required for address search etc.
+Others are added to the OSM elements by mkgmap so that they can be evaluted in
+the style files to change the processing.
+
+=== Tags evaluated by mkgmap ===
+These tags need to be set within the style file to set specific attributes of
+the Garmin map elements.
+
+----
+ highway=* & (bicycle=no | bicycle=private) { set mkgmap:bicycle='no' }
+----
+This rule defines that the road cannot be used by bicycles.
+
+// see [[Mkgmap/help/Tags]]
+
+.Tags for routable roads
+[options="header"]
+|=========================================================
+| Attribute | mkgmap tag | Example | Notes
+| Labels | +mkgmap:label:1+ +
++mkgmap:label:2+ +
++mkgmap:label:3+ +
++mkgmap:label:4+ | Eastern Avenue +
+A112 | Usually only the first label is displayed. On some units the second label of roads is displayed as routing instruction. All labels are used for address search.
+| Country | +mkgmap:country+ | GBR | Three letter ISO code, e.g. for GBR United Kingdom
+| Region | +mkgmap:region+ | London Borough of Waltham Forest | The regions name. Useful if there are multiple cities with the same name.
+| City | +mkgmap:city+ | London |
+| Street | +mkgmap:street+ | High Road Leyton | This value is used by house number search to match the +addr:street+ tag of an OSM element with house number to the corresponding road. It must be set so that house number search is working.
+| Zipcode | +mkgmap:postal_code+ | E10 5NA |
+| Access restrictions | +mkgmap:foot+ +
++mkgmap:bicycle+ +
++mkgmap:car+ +
++mkgmap:taxi+ +
++mkgmap:truck+ +
++mkgmap:bus+ +
++mkgmap:emergency+ +
++mkgmap:delivery+ | no | These tags are evaluated for routable lines (roads) only. By default access for a specific vehicle type is allowed. Only in case the value of the tag is _no_ access is blocked for the given type.
+| Throughroute | +mkgmap:throughroute+ | no | If this tag is set to _no_ routing is allowed on this road only if the start or end point lies on the road.
+| Carpool lane | +mkgmap:carpool+ | yes | If this tag is set to _yes_ the road is marked to have a carpool lane. This does not seem to work on all units.
+| Toll road | +mkgmap:toll+ | yes | If this tag is set to _yes_ the road can be used only when paying a specific toll.
+| Unpaved | +mkgmap:unpaved+ | yes | If this tag is set to _yes_ the road is marked to be unpaved. Some units can avoid unpaved roads.
+| Ferry | +mkgmap:ferry+ | yes | If this tag is set to _yes_ the line is marked to be a ferry line. Some units can avoid ferry lines.
+| Road speed | +mkgmap:road-speed-class+ | 2 | A value between 0 and 7. Overrides the +road_speed+ definition in the element type definition if this tag is set.
+| Road speed modifier | +mkgmap:road-speed+ | +1 | Modifies the road speed class by the given value. In case the value is prefixed with + or - the road speed class is modified. In case the value does not start with + or - the road speed class value of the element type definition is overriden.
+| Road speed limiters | +mkgmap:road-speed-min+ +
+ +mkgmap:road-speed-max+ | 5 | Defines the minimum/maximum road speed class. This can be used to limit the modification of the road speed class (+mkgmap:road-speed+).
+| Road class | +mkgmap:road-class+ | -1 | Modifies the road class defined in the element type definition. In case the value is prefixed with + or - the road class is modified. In case the value does not start with + or - the road class value of the element type definition is overriden.
+| Road class limiters | +mkgmap:road-class-min+ +
+ +mkgmap:road-class-max+ | 2 | Defines the minimum/maximum road class. This can be used to limit the modification of the road class (+mkgmap:road-class+).
+|=========================================================
+
+.Tags that control the treatment of roads
+[options="header"]
+|=========================================================
+| Tag | Description | Required mkgmap option
+| +mkgmap:way-has-pois+ | +true+ for ways that have at least one point with a tag +access=\*+, +barrier=\*+, or +highway=*+ | 'link-pois-to-ways'
+| +mkgmap:dead-end-check+ | Set to +false+ to disable the dead end check for a specific way | 'report-dead-ends'
+| +mkgmap:flare-check+ | Set to +true+ to force the flare check for a specific way, set to +false+ to disable it | 'check-roundabout-flares'
+| +mkgmap:dir-check+ | Set to +false+ to tell mkgmap to ignore the way when checking roundabouts for clockwise direction | 'check-roundabouts'
+| +mkgmap:no-dir-check+ | Set to +true+ to tell mkgmap to ignore the way when checking roundabouts for clockwise direction | 'check-roundabouts'
+
+|=========================================================
+
+
+.POI address tags
+[options="header"]
+|=========================================================
+| Attribute | mkgmap tag | Example | Notes
+| Name | +mkgmap:label:1+ +
++mkgmap:label:2+ +
++mkgmap:label:3+ +
++mkgmap:label:4+ | Pizza Express | Names of the POI
+| Country | +mkgmap:country+ | GBR | Three letter ISO code, e.g. for GBR United Kingdom
+| Region | +mkgmap:region+ | Nottinghamshire | The regions name. Useful if there are multiple cities with the same name.
+| City | +mkgmap:city+ | Nottingham |
+| Street | +mkgmap:street+ | King Street |
+| Housenumber | +mkgmap:housenumber+ | 20 |
+| Zipcode | +mkgmap:postal_code+ | NG1 2AS |
+| Phone | +mkgmap:phone+ | +44 115 999999 | Phone number in any format
+|=========================================================
+
+TIP: http://en.wikipedia.org/wiki/ISO_3166-1_alpha-3[Wikipedia] has a list of all ISO 3166-1 alpha 3 codes
+
+=== Tags added by mkgmap ===
+Some tags are added by mkgmap to indicate some property calculated by mkgmap.
+
+----
+ mkgmap:admin_level2=* { add mkgmap:country='${mkgmap:admin_level2}' }
+----
+The tag +mkgmap:admin_level2+ is added to each OSM element if the 'bounds' option is set. In the rule above it
+is used to assign the country location.
+
+.Tags added by mkgmap
+[options="header"]
+|=========================================================
+| Tag | Description | Required mkgmap option
+| +mkgmap:admin_level2+ | Name of the +boundary=administrative+ relation/polygon with +admin_level=2+ the element is located in | 'bounds'
+| +mkgmap:admin_level3+ | Name of the +boundary=administrative+ relation/polygon with +admin_level=3+ the element is located in | 'bounds'
+| +mkgmap:admin_level4+ | Name of the +boundary=administrative+ relation/polygon with +admin_level=4+ the element is located in | 'bounds'
+| +mkgmap:admin_level5+ | Name of the +boundary=administrative+ relation/polygon with +admin_level=5+ the element is located in | 'bounds'
+| +mkgmap:admin_level6+ | Name of the +boundary=administrative+ relation/polygon with +admin_level=6+ the element is located in | 'bounds'
+| +mkgmap:admin_level7+ | Name of the +boundary=administrative+ relation/polygon with +admin_level=7+ the element is located in | 'bounds'
+| +mkgmap:admin_level8+ | Name of the +boundary=administrative+ relation/polygon with +admin_level=8+ the element is located in | 'bounds'
+| +mkgmap:admin_level9+ | Name of the +boundary=administrative+ relation/polygon with +admin_level=9+ the element is located in | 'bounds'
+| +mkgmap:admin_level10+ | Name of the +boundary=administrative+ relation/polygon with +admin_level=10+ the element is located in | 'bounds'
+| +mkgmap:admin_level11+ | Name of the +boundary=administrative+ relation/polygon with +admin_level=11+ the element is located in | 'bounds'
+| +mkgmap:postcode+ | Name of the postal code relation/polygon the element is located in | 'bounds'
+| +mkgmap:area2poi+ | The value is +true+ if the POI is derived from a polygon | 'add-poi-to-areas'
+| +mkgmap:line2poi+ | The value is +true+ if the POI is derived from a line | 'add-poi-to-lines'
+| +mkgmap:line2poitype+ | The tag is set for each POI generated from a line. Possible values are: +start+, +end+, +mid+, +inner+. | 'add-poi-to-lines'
+| +mkgmap:exit_hint+ | +true+ for the part on link roads that should contain information about the exit | 'process-exits'
+| +mkgmap:exit_hint_name+ | The +name+ tag value of the links exit node | 'process-exits'
+| +mkgmap:exit_hint_ref+ | The +ref+ tag value of the links exit node | 'process-exits'
+| +mkgmap:exit_hint_exit_to+ | The +exit_to+ tag value of the links exit node | 'process-exits'
+| +mkgmap:dest_hint+ | +true+ for the part on link roads that should contain destination information about the link | 'process-destination'
+| +mkgmap:synthesised+ | The value is +yes+ if the way was added by the make-cycleways option | 'make-cycleways' or 'make-opposite-cycleways'
+| +mkgmap:mp_created+ | The value is +true+ if the way was created by the internal multi-polygon-relation handling | none
+|=========================================================
+
+.Other internal tags
+[options="header"]
+|=========================================================
+| Tag | Description
+| +mkgmap:skipSizeFilter+ | If set to +true+ the line or polygon will pass the size filter, no matter what size it has
+|=========================================================
+
+[[Element_type]]
+== Element type definition ==
+As noted above this is contained in square brackets and if used must be the *last part of the rule*.
+
+The first and only mandatory part of this section is the Garmin type code
+which must always be written in hexadecimal. Following this the element
+type definition rule can contain a number of optional keywords and
+values.
+
+=== level ===
+This is the highest zoom level that this element should appear at (like
+EndLevel in the mp format). The lower the level the detailed the view.
+The most detailed, most zoomed in, level is level 0. A map will usually
+have between three and five levels. If the level for an object is not
+given then it defaults to 0 and so the specified feature will only appear
+at the most detailed level.
+
+In the following example, we set highways to appear from zoom level 4 down to zoom level 0:
+-----
+highway=motorway [0x01 level 4]
+-----
+
+[WARNING]
+--
+You can use +level+ to place elements into the layers of the map that you
+want but you can't force the device to actually display them.
+
+Some pieces of software (such as QLandkarteGT, I believe) will honour
+your selections, but actual GPS devices have their own ideas about
+which POI's can be shown at which resolutions.
+--
+
+.Level ranges
+You can also give a range (e.g. 1-3) and the map will then contain the
+object only between the specified levels.
+
+----
+highway=motorway [0x01 level 3-5]
+-----
+
+In this example, motorways will appear at zoom level 5, which is most
+zoomed out, and continue to be visible until zoom level 3, which is
+moderately zoomed in, and then will not be shown in zoom levels 2, 1 and
+0 (most zoomed-in).
+
+[TIP]
+Of course you are unlikely to want a feature to disappear as you zoom in,
+but this can be used for interesting effects where a different
+representation takes over at the lower zoom levels. For example a
+building may be a point at high levels and then become a polygon at lower
+levels.
+
+=== resolution ===
+
+This is an alternative way of specifying the zoom level at which an
+object appears. It is specified as a number from 1-24, which corresponds
+to one of the zoom levels that Garmin hardware recognises. You should
+not use resolution if you have used level as they achieve the same
+outcome.
+
+In either case, the mapping between level and resolution is given in the
+options style file, where you will see something like this:
+
+-----
+# The levels specification for this style
+#
+levels = 0:24, 1:23, 2:22, 3:20, 4:18, 5:16
+-----
+This sets level zero equal to resolution 24, level 1 to resolution 23 and so on.
+
+Although the default style uses +resolution+ rather than +level+ it is on
+the whole much easier to use +level+ as it is immediately clear where the
+element will end up. If you use a +resolution+ that is `between' two
+levels for example it will only show up in the lower one.
+
+.Resolution ranges
+
+Just as with levels, you can specify a range of resolutions at which an
+object should appear. Here is an example.
+
+----
+highway=residential [0x06 resolution 16-22 continue]
+highway=residential [0x07 resolution 23-24]
+----
+
+This example creates roads of type 0x06 between resolutions 16 and
+22, then roads of type 0x07 between resolutions 23 and 24. This
+example makes use of the continue statement, which is discussed in more
+detail below.
+
+[TIP]
+Since 24 is the default upper bound for a range, that second range could
+just have been written as the single number `23'.
+
+=== default_name ===
+If the element has not already had a name defined elsewhere in the rule,
+it will be given the name specified by +default_name+. This might be
+useful for things that usually don't have names and don't have a
+recognisable separate Garmin symbol. You could give a default name of
+`bus stop' for example and all bus stops that didn't have their own name
+would now be labelled as such.
+
+[TIP]
+Be careful to use this sparingly and not overwhelm the map or the search.
+
+=== road_class ===
+Setting this makes the line a "road" and it will be routable and can be
+part of an address search.
+It gives the class of the road where class 4 is used for major roads that
+connect different parts of the country, class 3 is used for roads that
+connect different regions, down to class 0 which is used for residential
+streets and other roads that you would only use for local travel.
+
+It is important for routing to work well that most roads are class 0 and
+there are fewer and fewer roads in each of the higher classes.
+
+.Road classes
+[width="40%",frame="topbot",grid="rows",cols="<1,<4",options="header"]
+|=====
+| Class | Used as
+| 4 | Major HW/Ramp
+| 3 | Principal HW
+| 2 | Arterial St / Other HW
+| 1 | Roundabout / Collector
+| 0 | Residential Street / Unpaved road / Trail
+|=====
+
+=== road_speed ===
+
+This keyword is used along with +road_class+ to indicate that the line is
+a "road" that can be used for routing and for address searches.
+It is an indication of how fast traffic on the road is. 0 is the slowest and 7 the fastest.
+This is *not* a speed limit and does not activate the maximum speed
+symbol on the newer Garmin car navigation systems.
+The speed limits that Garmin knows are shown in the following table:
+
+.Road Speeds
+[width="40%",frame="topbot",grid="rows",cols="<1,<2",options="header"]
+|======
+| road_speed | highest speed
+| 7 | No speed limit
+| 6 | 70 mph / 110 kmh
+| 5 | 60 mph / 90 kmh
+| 4 | 50 mph / 80 kmh
+| 3 | 35 mph / 60 kmh
+| 2 | 25 mph / 40 kmh
+| 1 | 15 mph / 20 kmh
+| 0 | 3 mph / 5 kmh
+|======
+
+=== continue ===
+
+As discussed above, style rules are matched in the order that they occur
+in the style file. By default, for any given OSM object mkgmap will try
+each rule in turn until one rule wth a _element type definition_ matches;
+it will then stop trying to match further rules against the current OSM
+object. If the rule only has an _action block_ mkgmap will continue to
+find other matches.
+
+However, if you add a _continue_ statement to the definition block of a
+rule, mkgmap will not stop processing the object but will instead carry
+on trying to match subsequent rules until it either runs out of rules or
+finds a matching rule that does not include a _continue_ statement.
+
+This feature is used when you want more than one symbol to result from
+a single OSM element. This could be for clever effects created by
+stacking two lines on top of each other.
+For example if you want to mark a bridge in a distinctive way you
+could match on +bridge=yes+, you would then almost always use +continue+ so
+that the +highway+ tag could be matched later. If you failed to do this
+then there might be a break in the road for routing purposes.
+
+Note that by default when using the _continue_ statement the action block
+of the rule (if there is one) will only be applied _within this rule_ and
+not during any following rule matches. Use the _continue with_actions_
+statement if you want to change this behaviour (see next section).
+
+=== continue with_actions ===
+The with_actions statement modifies the continue behaviour in such a way,
+that the action block of this rule is also applied, when this element is
+checked for additional conversions.
+
+.Example of a full element type definition
+----
+[0x2 road_class=3 road_speed=5 level 2
+default_name 'example street' continue with_actions]
+----
+
+== Including files ==
+Its often convenient to split a file into smaller parts or to use the
+same rules in two different files. In these cases you can include
+one rule file within another.
+
+ include "inc/common";
+
+Here some common rules have been included in a rule file from a directory
+called "inc" within the style. Note that the line ends in a semi-colon
+which is easy to forget.
+
+[NOTE]
+--
+The included files don't have to be located within the style and can be
+anywhere else.
+--
+
+When you include a file, the effect is exactly as if you had replaced the
+include line with the contents of the file. An +include+ directive can
+occur anywhere that a rule could start, and it is possible to include
+another file from with in the file that is included.
+
+.Including from another style
+It is also possible to include a file from another style.
+To do this you simply add +from stylename+ to the end of the include
+statement.
+
+ include "points" from default;
+
+That will include the +points+ file from the default style. This might be
+useful if you want to only change a few things about the default style.
+
+== Finalize section ==
+The points, lines and polygons style files can have a finalize section at the end
+of the style file. It starts with the line +<finalize>+.
+
+The finalize section contains actions only and must not have an element type definition.
+Its rules are executed each time an element type definition in the style file matches.
+The finalize section is often useful to set the mkgmap internal tags.
+
+.Finalize section in the lines file with access handling
+====
+Two elements tagged with
+
+ Way 1: highway=motorway, ref=A1
+ Way 2: highway=service, name=Main Road, access=no, foot=yes, bicycle=yes
+
+using the lines file
+
+ highway=motorway [0x01 road_class=4 road_speed=7 resolution 15]
+ highway=service [0x07 road_class=0 road_speed=1 resolution 24]
+
+ <finalize>
+ highway=* { name '${name} (${ref})' | '${name}' | '${ref}' }
+ highway=motorway { add bicycle=no; add foot=no }
+ bicycle=* { add mkgmap:bicycle='${bicycle}' }
+ foot=* { add mkgmap:foot='${foot}' }
+ access=* { addaccess '${access}' }
+
+will result in
+
+ Way 1: highway=motorway, ref=A1, mkgmap:label:1=A1, mkgmap:foot=no,
+ mkgmap:bicycle=no
+ Road 1 in Garmin map: Type 0x01, Name 'A1', no access for bicycle and foot
+ Way 2: highway=service, name=Main Road, access=no, foot=yes, bicycle=yes,
+ mkgmap:label:1=Main Road, mkgmap:foot=yes, mkgmap:bicycle=yes,
+ mkgmap:car=no, mkgmap:truck=no, mkgmap:bus=no, ...
+ Road 2 in Garmin map: Type 0x07, Name 'Main Road', no access for all vehicle
+ types except bicycle and foot
+====
+
+[NOTE]
+Actions in the finalize section are not persistent in terms of the +continue+ or
++continue with_actions+ statement
+
+== Troubleshooting ==
+
+For each node/way/relation, mkgmap goes through the tags exactly once in
+order from the top of the file downward.
+For each rule that matches, any action block will be run.
+As soon as a rule that ends with a type definition is found then
+processing stops and that is the Garmin symbol that is produced.
+
+The only exception is if the Type Definition contains the
++continue+ statement. In that case _mkgmap_ will continue
+looking for further matches.
+
+* Where possible always have the same tag on the left. This will make things more predictable.
+* Always set made-up tag names if you want to also match on them later, rather than setting tags that might be used already.
+* Use the +echo+ and +echotags+ actions to understand what's going on during style processing.
+
+== Some examples ==
+The following are some examples of style rules, with explanations of what they do.
+
+=== Simple examples ===
+In the majority of cases everything is very simple. Say you want roads that are tagged as *highway=motorway* to have the Garmin type 0x01 ("motorway") and for it to appear up until the zoom level 3.
+
+Then you would write the following rule.
+----
+highway=motorway [0x01 level 3]
+----
+
+Nodes that have an id and a subid are referenced by concatenating both ids.
+----
+amenity=bank [0x2f06 level 3]
+----
+
+This will be explained in more detail in the following sections along
+with how to use more than one tag to make the choice.
+
+=== More involved examples ===
+A few tips and tricks showing how the rules can be used to
+create almost any effect.
+
+.Internet cafes
+====
+ amenity=cafe & internet_access=wlan {name '${name} (wifi)'} [0x2a14 resolution 23]
+====
+Checks to see if an OSM object has both the amenity=cafe and internet_access=wlan key/tag pairs.
+If name=Joe's Coffee Shop, then the Garmin object will be named _Joe's Coffee Shop (wifi)_.
+The Garmin object used will be 0x2a14 and the object will only appear at resolutions 23 and 24
+
+.Guideposts
+====
+ information=guidepost
+ { name '${name} - ${operator} - ${description} '
+ | '${name} - ${description}'
+ | '${name}'
+ | '${description}'
+ | '${operator}'
+ | '${ref}'
+ }
+ [0x4c02 resolution 23 default_name 'Infopost']
+
+Checks to see if an OSM object has the information=guidepost key/tag pair.
+If so then the name will be set depending on the available +name+,
++operator+ and +description+ tags as follows.
+
+1. If for example we have the tags `name="Route 7"`, `operator="Kizomba
+National Parks"` and `description="Trail signpost"`, then the Garmin object will be named
+_Route 7 - Kizomba National Parks - Trail signpost_.
+2. If the OSM object just has the +name+ and +description+ tags set, the Garmin object will be named _Route 7 - Trail signpost_
+3. If just the +name+ tag is available, the Garmin object will be named _Route 7_
+4. If just the +description+ tag is available, the Garmin object will be named _Trail signpost_;
+5. and if just the +operator+ tag is available, the Garmin object will be named _Kizomba National Parks_.
+
+The Garmin object used will be 0x4c02 and will only appear at resolutions 23 and 24
+====
+
+.Car sales rooms
+====
+ shop=car {name '${name} (${operator})' | '${name}' |'${operator}'} [0x2f07 resolution 23]
+
+If name="Alice's Car Salesroom" and operator=Nissan, the Garmin object
+will be named _Alice's Car Salesroom (Nissan)_
+====
+
+.Opening hours in postcode field
+====
+This is a trick to get opening hours to show up in the postcode field of
+a POI. Tricks like this can enhance the map for certain uses, but of
+course may prevent the proper use of the postcode field.
+
+ opening_hours=* {set addr:postcode = '${addr:postcode} open ${opening_hours}'
+ | 'open ${opening_hours}'}
+
+For _any_ OSM object which has the opening_hours key set to a value, this
+sets the postcode to include the opening hours. For example, if
+addr:postcode=90210, addr:street=Alya Street, addr:city=Lagos and
+addr:housenumber=7 and opening_hours=09.00-17.00, the address field of
+the Garmin POI will be _7, Alya Street, Lagos, 90210 open 09.00-17.00_.
+
+====
+
diff --git a/doc/styles/style-manual.txt b/doc/styles/style-manual.txt
new file mode 100644
index 0000000..db4d50f
--- /dev/null
+++ b/doc/styles/style-manual.txt
@@ -0,0 +1,64 @@
+= Conversion Style manual
+The mkgmap team
+:pubdate: January 2013
+:toc:
+:numbered:
+:doctype: book
+:website: http://www.mkgmap.org.uk
+:email: mkgmap-dev at lists.mkgmap.org.uk
+:description: Describes the style language that converts from OSM tags to Garmin types.
+:max-width: 58em
+
+:frame: topbot
+:grid: rows
+
+// Used for conditional compiles for a unix/windows version. Expect to
+// use this more for the tutorial
+:windows: 1
+:linux: 1
+:max: 1
+
+Introduction
+------------
+
+This manual explains how to write a mkgmap style to convert
+between OSM tags and features on a Garmin GPS device.
+
+A style is used to choose which OSM map features appear in the
+Garmin map and which Garmin symbols are used.
+
+There are a few styles built into mkgmap, but
+as there are many different purposes a map may be used for, the default
+styles in mkgmap will not be ideal for everyone, so
+you can create and use styles external to mkgmap.
+
+The term _style_ could mean the actual way that the features appear on
+a GPS device, the colour, thickness of the line and so on. This manual
+does not cover such issues, and if that is what you are looking for, then you
+need the documentation for *TYP files*.
+
+Few people will want to write their own style from scratch, most people
+will use the built in conversion style, or at most make a few changes
+to the default style to add or remove a small number of features.
+For general information about running and using mkgmap see the
+*Tutorial document*.
+
+To be clear this is only needed for converting OSM tags, if you are
+starting with a Polish format file, there is no style involved as the
+garmin types are already fully specified in the input file.
+
+For general information about the OpenStreetMap project see the
+link:http://wiki.openstreetmap.org[OpenStreetMap wiki].
+
+
+:leveloffset: 1
+
+include::design.txt[]
+
+include::files.txt[]
+
+include::rules.txt[]
+
+include::creating.txt[]
+
+include::about.txt[]
diff --git a/doc/tutorial/Makefile b/doc/tutorial/Makefile
new file mode 100644
index 0000000..0d1fe5a
--- /dev/null
+++ b/doc/tutorial/Makefile
@@ -0,0 +1,32 @@
+
+include ../resources/make.param
+
+SOURCE_DEPS= tutorial.txt starting.txt first_map.txt $(XSL)
+TUTORIAL_MAIN=tutorial.txt
+
+build: html
+
+all: html pdf epub
+
+html: tutorial.html
+pdf: tutorial.pdf
+epub: tutorial.epub
+
+tutorial.html: $(SOURCE_DEPS)
+ $(ASCIIDOC) $(HTML_ATTRS) -a icons -a iconsdir=$(ICONSDIR) -b html5 $(TUTORIAL_MAIN)
+
+tutorial.pdf: $(SOURCE_DEPS)
+ $(A2X) --xsl-file=$(XSL) --fop -a doctype=article $(PDF_OPTS) $(TUTORIAL_MAIN)
+
+tutorial.epub: $(SOURCE_DEPS)
+ mkdir -p build
+ cp -ru $(RES)/common-images build
+ $(A2X) --format epub --icons --icons-dir=build/common-images/icons $(TUTORIAL_MAIN)
+
+
+install: pdf
+ cp -u tutorial.pdf $(DEST)
+
+clean:
+ rm -f tutorial.{pdf,epub,html}
+ rm -rf build
diff --git a/doc/tutorial/first_map.txt b/doc/tutorial/first_map.txt
new file mode 100644
index 0000000..6243714
--- /dev/null
+++ b/doc/tutorial/first_map.txt
@@ -0,0 +1,5 @@
+
+Create your first map
+=====================
+TBW
+
diff --git a/doc/tutorial/starting.txt b/doc/tutorial/starting.txt
new file mode 100644
index 0000000..c1e7c79
--- /dev/null
+++ b/doc/tutorial/starting.txt
@@ -0,0 +1,23 @@
+
+Getting started
+===============
+
+== Install java
+To use mkgmap you need a program called Java.
+Download it from http://www.java.com[java.com]
+
+ifdef::linux[]
+=== Linux packages
+If you are running Linux, then you may prefer to install java from you
+systems package manager, instead of from the Java site.
+
+The package is named *java-1.7.0-openjdk* on Fedora and similar
+distributions; on Ubuntu, Debian and similar it is is named
+*openjdk-7-jre*
+
+endif::linux[]
+
+== Download
+Download +mkgmap+ from the
+http://www.mkgmap.org.uk/download/mkgmap.html[mkgmap download site].
+
diff --git a/doc/tutorial/tutorial.txt b/doc/tutorial/tutorial.txt
new file mode 100644
index 0000000..7a9669b
--- /dev/null
+++ b/doc/tutorial/tutorial.txt
@@ -0,0 +1,47 @@
+
+The mkgmap Tutorial
+===================
+The mkgmap team
+:pubdate: January 2013
+:toc:
+:numbered:
+:doctype: book
+:website: http://www.mkgmap.org.uk
+:email: mkgmap-dev at lists.mkgmap.org.uk
+:description: A tutorial that starts with creating your first map and in a series of steps shows how to create a map of a whole country.
+:max-width: 58em
+
+:frame: topbot
+:grid: rows
+
+// Used for conditional compiles for a unix/windows version.
+:windows: 1
+:linux: 1
+:max: 1
+
+
+Introduction
+------------
+This tutorial starts with simple instructions to create a first map of
+you local area and then gradually shows you how to build this into a
+complete map of a country or region that is suitable for distribution to
+others should you wish.
+
+
+:leveloffset: 1
+
+include::starting.txt[]
+
+include::first_map.txt[]
+
+// Some ideas for the sections, order to be decided
+// I'm assuming that this will not be published before the great
+// option defaulting process is complete.
+
+// installing to device, mapsource, basecamp, qlandkartegt etc
+
+// adding sea areas
+
+// using a bounds file to improve addresses
+
+// splitting large area
diff --git a/doc/typ-compiler.txt b/doc/typ-compiler.txt
new file mode 100644
index 0000000..ef86de3
--- /dev/null
+++ b/doc/typ-compiler.txt
@@ -0,0 +1,317 @@
+== The mkgmap TYP file compiler ==
+
+This document describes the format that is understood by the mkgmap TYP compiler.
+It contains everything you need to write a TYP file description that can be compiled, showing exactly how
+you can get the different colour effects that are available.
+
+Although you can edit these files by hand, it is very much more convenient to use one of the graphical editors that are available.
+
+These produce file formats that differ from each other and have variations to the specification that is presented here. These variations will be supported as they are discovered as long as they do not conflict with each other, but are not listed here for clarity. In particular the files produced by [http://www.pinns.co.uk/osm/ostyp.html TYPWiz] and [http://opheliat.free.fr/michel40/ TYPViewer] are supported.
+
+== The [_id] section ==
+
+;FID=#
+: The family id.
+;ProductCode=#
+: The product code within a family, usually just left as one.
+;CodePage=#
+: The code page to use for writing the labels.
+ [_id]
+ FID=1299
+ ProductCode=1
+ CodePage=1252
+ [end]
+
+== The [_drawOrder] section ==
+This is a list of polygon types and level numbers. Polygons with a higher
+level number are drawn on top of those with a lower one.
+
+There is only one tag that is valid in this section.
+
+;Type=object_type,level
+:The object_type is the polygon type such as 0x07 or an extended type such as 0x10208
+:The level is a number starting at 1.
+
+Example:
+<pre>
+[_drawOrder]
+Type=0x032,1
+Type=0x10101,2
+Type=0x002,3
+Type=0x003,3
+Type=0x007,3
+Type=0x009,3
+Type=0x00c,3
+Type=0x00e,3
+Type=0x010,3
+Type=0x012,3
+Type=0x015,3
+Type=0x01b,3
+...
+[end]
+</pre>
+If a polygon type is not listed in this section, then it will not be displayed at all. If it is then it will be styled according to a definition in a [_polygon] section later in this file, or in the default Garmin style if these is no such definition.
+
+== Element sections ==
+The main part of the file consists of descriptions of how elements are to be displayed so that you can change the colours and style of the displayed elements.
+
+Each style definition starts with the name of the section in brackets and ends with the line "[end]". For example:
+ [_polygon]
+ Type=0x02
+ String1=0x04,Residential
+ String2=0x01,Résidentiel
+ String3=0x03,Bebouwde kom
+ ExtendedLabels=Y
+ FontStyle=NoLabel
+ Xpm="0 0 2 0"
+ "! c #DCDCDC"
+ " c none"
+ [end]
+
+ [_line]
+ Type=0x22
+ ; options to style the line
+ [end]
+
+ [_point]
+ Type=0x52
+ ; options to style the POI
+ [end]
+
+You have one of these for each polygon, line of POI you want to change from the built in Garmin style.
+
+== Common options for element sections ==
+
+These options will work in all the element sections [_point], [_line] and [_polygon].
+
+;Type=object_type
+:The object type number - the kind of element that it is. If the number is greater than 0xff then it will be treated as a type and subtype combination. Eg 0x2305 is type 0x23 with subtype 0x5.
+
+;String=#,xxx
+:Defines a label that will be attached to the element. The first part is a language number, the second the actual string. You can use String1, String2 for compatibility, but just String will do for the mkgmap compiler.
+ String=0x04,Parking
+ String=0x03,Parkeerplaats
+
+;FontStyle=xxx
+: xxx can be one of NoLabel, SmallFont, NormalFont, LargeFont.
+
+;DayCustomColor=#colour
+: The colour used for the font when the GPS unit is displaying day colours.
+
+;NightCustomColor=#colour
+: The colour used when the GPS unit is displaying night colours.
+
+== XPM format ==
+The XPM format is used is a somewhat modified form. You can find out more about elsewhere as it is widely used. This is a brief summary of what it all means based on the following example:
+ Xpm="10 5 3 1"
+ "r c #ff0000"
+ "g c #00ff00"
+ "b c #0000ff"
+ "rrrrrrrrrr"
+ "rrrrrrrrrr"
+ "rbbbbbgggr"
+ "rbbbrggggr"
+ "rbbrrrrrrr"
+ "rrrrrrrrrr"
+
+Working from the top, the first line means that the pixmap has a width of 10 and a height of 5. There are 3 different colours and each colour is represented by one character in the lines to follow.
+
+There then follows the three lines giving the colours to use. The first character(s) are a short name for the colour, in this case there is one character (r, g, b) because the last field in the first line was 1. Next is the letter 'c' which can be ignored, and the follows the normal RGB representation of the colour. In this case I have chosen red to be represented by the letter r, g for green and b for blue, but you can use any characters or colours you choose. A space is allowed, and it is traditional to use a space for the background colour.
+
+Then there is the pixmap itself, it is 10 columns wide and 5 lines to match the width and height values in the first line. If the number of characters representing each pixel was 2 say, then there would be 10 groups of 2 characters across. Each letter represents one pixel of the final image, in this example, the top of the icon would be a red line and in the middle there would be some blue and green.
+
+== Polygon elements ==
+A [_polygon] section can have any of the common tags.
+
+It must also contain an Xpm tag. This uses a modified form of the XPM format, see the XPM section for details about the format that are common between all the element types. The following notes only refer to how it is used within the polygon section.
+
+* A single solid colour, that is the same in day and night displays
+ Xpm="0 0 1 0"
+ "a c #778899"
+
+* One solid colour that is used in the day display mode and another that is used in the night display mode.
+ Xpm="0 0 2 0"
+ "a c #778899"
+ "b c #223322"
+
+* A pixmap that has the same solid colours in day and night modes. The pixmap must be 32x32 and have two colours.
+ Xpm="32 32 2 1"
+ "a c #778899"
+ "b c #223322"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaabbbbbbbaaaaaaaaaaaa"
+ "aaaaaaaaaaabbbbbbbbbbbaaaaaaaaaa"
+ ; ... 32 rows in total
+
+* The pixmap can have a transparent background, in which case the second colour will be given as 'none'
+ Xpm="32 32 2 1"
+ "a c #778899"
+ "b c none"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaabbbbbbbaaaaaaaaaaaa"
+ "aaaaaaaaaaabbbbbbbbbbbaaaaaaaaaa"
+ ; ... 32 rows in total
+
+* If you want to have different colours for the day and night modes, then use 4 colours. As before the second and fourth colours can be 'none' to indicate that the background is transparent for the day and/or night colour respectively. In the example the night colour has a transparent background and the day version does not. When you draw the pixmap you only use the day colours, the device will automatically switch to the alternate colours when in night mode. It is traditional to '3' and '4' for the night colour tags in the XPM, but with mkgmap you can use whatever you like.
+ Xpm="32 32 4 1"
+ "a c #778899"
+ "b c #221133"
+ "3 c #112233"
+ "4 c none"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaabbbbbbbaaaaaaaaaaaa"
+ "aaaaaaaaaaabbbbbbbbbbbaaaaaaaaaa"
+ ; ... 32 rows in total
+
+== Line elements ==
+A line section can contain any of the common tags. It can also have the following additional tags
+
+;LineWidth=#
+:The line width in pixels. This is the width, excluding borders if there are any. This is only used if there is not a pixmap.
+;BorderWidth=#
+:The border width. The line will be drawn (on devices that support this) with a border at each edge of the line. It is only used if there is no pixmap. If there should not be a border then it can be omitted or set to zero.
+;UseOrientation=(Y|N)
+:If Y then the pixmap is rotated so that is always following the direction of the road.
+ LineWidth=2
+ BorderWidth=2
+ UseOrientation=Y
+
+As with polygons there is an Xpm tag too and it can specify that solid colours should be used or that there is a bitmap.
+
+If there is a bitmap then it is always has a width of 32, its height will be the width of the line (yes that sound confusing the first time you read it, it just means that the line is written horizontally in the pixmap). The colours work in exactly the same way as they do for polygons, so see the examples there for the different possibilities with day/nitght and transparent colours. An example with a pixmap, which shows a line that will have a thickness of 3.
+ Xpm="32 3 4 1"
+ "a c #550088"
+ ". c #889988"
+ "3 c #889988"
+ "4 c #889955"
+ "aaaaaaaaaaaaaaaaaaaaaaaaa....aaa"
+ "aaaaaa................aaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaa....aaa"
+
+When there is no pixmap then the LineWidth and BorderWidth options come into play. The following combinations are recognised by mkgmap.
+
+* Solid line, no border. Same colour day and night.
+ LineWidth=2
+ Xpm="0 0 1 0"
+ "a c #989898"
+
+* Solid line, no border. Different colour for day and night.
+ LineWidth=2
+ Xpm="0 0 2 0"
+ "a c #989898"
+ "b c #228844"
+
+* Solid line, border width 1, same colour day/night. The second colour is the border colour, the first the main line colour.
+ LineWidth=2
+ BorderWidth=1
+ Xpm="0 0 2 0"
+ "a c #989898"
+ "b c #345544"
+
+* Solid line, border of 1, different day/night colours
+ LineWidth=2
+ BorderWidth=1
+ Xpm="0 0 4 0"
+ "a c #989898"
+ "b c #345544"
+ "3 c #119811"
+ "4 c #3499ee"
+
+== Points (POI) ==
+A point can have any of the common tags and in addition can have the following two tags to specify the icon to be used in day and/or night modes.
+
+;DayXpm
+:The XPM to be used as the only or when the display is showing day-time colours.
+;NightXpm
+:This is optional and if given is an alternative XPM to use when showing night-time colours. It must have the same width and height as the DayXpm, but everything else about it can be different.
+
+Only the DayXpm will be explained, the NightXpm is exactly the same, except that it is constrained to have the same width and height as the DayXpm.
+
+Unlike lines and polygons which are simple two colour bitmaps, points can have many colours and partial transparency.
+There are several colour modes, mkgmap will automatically determine which you need without having to specify it separately. Each POI can have different colours, transparency schemes and sizes.
+* Up to 255 solid pixel colours
+* Up to 254 solid pixel colours with an additional transparent pixel.
+* Up to 255 pixel colours which can each have a different transparency value.
+* Up to 16 million different colours, no transparency
+* Up to 16 million different colours, one transparent pixel.
+
+Here are example of the input and the effect that is achieved.
+* A 10x5 icon with 5 solid colours
+ DayXpm="10 5 5 1"
+ "a c #112211"
+ ". c #1e2291"
+ "/ c #1ef291"
+ "@ c #1eff91"
+ "? c #11ff11"
+ "aaaaaaaaaa"
+ "a...aa//??"
+ "aaaaa@@//a"
+ "aaa.....aa"
+ "aaaaaaaaaa"
+
+* A 10x5 icon with 4 solid colours and a transparent pixel
+ DayXpm="10 5 5 1"
+ ". c #1e2291"
+ "/ c #1ef291"
+ "@ c #1eff91"
+ "? c #11ff11"
+ "a c none"
+ "aaaaaaaaaa"
+ "a...aa//??"
+ "aaaaa@@//a"
+ "aaa.....aa"
+ "aaaaaaaaaa"
+
+* Icon 10x5 with variable transparency on each colour. This is represented in the normal way by adding an extra alpha value to the end of the RGB colour value. The value 00 is completely transparent and FF is completely opaque. Since the TYP format only has 15 different levels of transparency, you should restrict to using the values [11, 22, 33, ... EE, FF]. However you can use any value and it will be rounded to the nearest supported value.
+ DayXpm="10 5 5 1"
+ ". c #1e2291"
+ "/ c #1ef291"
+ "@ c #1eff91dd"
+ "? c #11ff1188"
+ "a c #00000000"
+ "aaaaaaaaaa"
+ "a...aa//??"
+ "aaaaa@@//a"
+ "aaa.....aa"
+ "aaaaaaaaaa"
+the first two colours are completely solid (if the alpha value is omitted it defaults to FF as usual), the third is slightly transparent, down to the last which is completely transparent.
+<p>
+An alternate notation is supported where the transparency value is appended to the line in the form "alpha=13", this is a transparency value that goes from 0 to 15, with 15 being completely transparent. As such it works the opposite way to the alpha value of the normal RGBa values in the previous example. The required conversions are made by mkgmap which ever one you use.
+
+* Image with up to 16 million different colours
+By setting the number of colours in the XPM to zero you can specify a
+different kind of image, where the colour for each pixel is specified
+separately.
+
+Example
+ IconXpm="10 10 0 0"
+ "#990088"
+ "#990088"
+ "#990067"
+ " ... and so on for 100 different values ..."
+
+If you prefer you can place several pixel values on the same line, as
+long as there are the correct number altogether.
+ IconXpm="10 10 0 0"
+ "#990088 #990088 #990067"
+ " ... and so on for 100 different values ..."
+
+The spaces can be ommitted for the most compact representation.
+It is also possible to have a transparent pixel with this format, but there is currently not a way to represent this.
+
+== Icons ==
+An [_icons] section holds a set of images at different resolutions. The images are intended to be of the same logo or icon at a range of different sizes to suit different resolution devices.
+
+Only a few tags are valid in this section.
+
+* The <code>Type</code> tag is required. It identifies the point type that this image set will be used for.
+* The <code>String</code> tag is also allowed, but it does not take a language code at the beginning. Therefore there can only be one of them.
+
+The other tag that can be present is IconXpm.
+There can be several of these tags, each one is a different
+resolution/size. Each one can have a different size, colour mode, and
+number of colours.
+The appropriate version is selected according the capabilities of the
+device it is being displayed on.
+
+The format of the IconXpm tags has the same possibilities as in the _point sections.
diff --git a/extra/README b/extra/README
new file mode 100644
index 0000000..cba5fa6
--- /dev/null
+++ b/extra/README
@@ -0,0 +1,3 @@
+
+This directory contains code that requires external libraries
+to work and so is not part of the core code.
diff --git a/extra/src/uk/me/parabola/mkgmap/ant/MKGMapTask.java b/extra/src/uk/me/parabola/mkgmap/ant/MKGMapTask.java
new file mode 100644
index 0000000..6479e5d
--- /dev/null
+++ b/extra/src/uk/me/parabola/mkgmap/ant/MKGMapTask.java
@@ -0,0 +1,81 @@
+ /*
+ * Copyright (C) 2009 Christian Gawron
+ *
+ * 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: Christian Gawron
+ * Create date: 19-Jun-2009
+ */
+ package uk.me.parabola.mkgmap.ant;
+
+ import java.util.ArrayList;
+ import java.util.List;
+
+ import uk.me.parabola.mkgmap.CommandArgsReader;
+ import uk.me.parabola.mkgmap.main.Main;
+
+ import org.apache.tools.ant.BuildException;
+ import org.apache.tools.ant.Task;
+ import org.apache.tools.ant.types.Path;
+
+/**
+ * This class provides an ant task for mkgmap.
+ * Used like this:
+ * <target name="mkgmap">
+ <taskdef name="mkgmap" classname="uk.me.parabola.mkgmap.ant.MKGMapTask"
+ classpath="dist/mkgmap.jar:."/>
+ <mkgmap options="mkgmap.cfg">
+ <path>
+ <fileset dir="maps" includes="*.osm" />
+ </path>
+ </mkgmap>
+ </target>
+ *
+ */
+ at SuppressWarnings({"UnusedDeclaration"})
+public class MKGMapTask extends Task {
+
+ private final ArrayList<Path> paths = new ArrayList<Path>();
+ private String configFile;
+
+ public void addPath(Path path) {
+ paths.add(path);
+ }
+
+ public void setOptions(String configFile) {
+ this.configFile = configFile;
+ }
+
+ public void execute() {
+ List<String> args = new ArrayList<String>();
+
+ try {
+ CommandArgsReader argsReader = new CommandArgsReader(new Main());
+
+ if (configFile != null)
+ args.add("--read-config=" + configFile);
+
+ for (Path path : paths) {
+ String[] includedFiles = path.list();
+ for (String filename : includedFiles) {
+ log("processing " + filename);
+ args.add("--input-file=" + filename);
+ }
+ }
+
+ argsReader.readArgs(args.toArray(new String[args.size()]));
+ } catch (Exception ex) {
+ //log(ex, 1);
+ throw new BuildException(ex);
+ }
+ }
+}
+
\ No newline at end of file
diff --git a/extra/src/uk/me/parabola/util/TableIcuCreator.java b/extra/src/uk/me/parabola/util/TableIcuCreator.java
new file mode 100644
index 0000000..e252198
--- /dev/null
+++ b/extra/src/uk/me/parabola/util/TableIcuCreator.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.util;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+
+import uk.me.parabola.imgfmt.Utils;
+
+import com.ibm.icu.text.Transliterator;
+
+/**
+ * Call this with a unicode row number and it will produce an empty table
+ * that can be modified.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TableIcuCreator {
+ private static Transliterator trans;
+
+ public static void main(String[] args) {
+ int count = 0;
+ Enumeration<String> targets = Transliterator.getAvailableIDs();
+ while (targets.hasMoreElements()) {
+ String s = targets.nextElement();
+ System.out.println(s);
+ count++;
+ }
+
+ System.out.println("number " + count);
+ //System.exit(0);
+ //trans = Transliterator.getInstance("Any-en_US; nfd; [\u0301\u0302\u0304\u0306\u0307\u0308\u030c\u0328] remove; nfc"); // [:nonspacing mark:] remove; nfc");
+
+ trans = Transliterator.getInstance("Any-Latin"); // [:nonspacing mark:] remove; nfc");
+
+ for (int row = 0; row < 256; row++) {
+ String name = String.format("row%02x.trans", row);
+ PrintWriter out = null;
+ try {
+ out = new PrintWriter(new FileWriter(name));
+ printRow(out, row);
+ } catch (IOException e) {
+ System.out.println("Could not open " + name + " for write");
+ } catch (UselessException e) {
+ //System.out.println("Deleting " + name);
+ File f = new File(name);
+ f.delete();
+ } finally {
+ Utils.closeFile(out);
+ }
+ }
+ }
+
+ private static void printRow(PrintWriter out, int row) throws UselessException {
+ out.println("#");
+ out.println("# This is a table for transliterating characters.");
+ out.println("# It was created using icu4j");
+ out.println("#");
+ out.println("# All resulting strings that contained characters outside the");
+ out.println("# range of iso 8859-1 are commented out");
+ out.println("#");
+ out.println();
+
+ int count = 0;
+ for (int i = 0; i < 256; i++) {
+ char c = (char) ((row << 8) + i);
+ String single = "" + c;
+ String result = trans.transliterate(single);
+
+ if (result.length() == 1 && result.charAt(0) == c)
+ result = "?";
+ else
+ count++;
+
+ boolean inRange = true;
+ for (char rc : result.toCharArray()) {
+ if (rc > 0xff) {
+ //System.out.printf("out of range result %c for row %d\n", rc, row);
+ inRange = false;
+ break;
+ }
+ }
+
+ if (!inRange) {
+ count--;
+ out.print("#");
+ }
+
+ out.format("U+%02x%02x %-12.12s # Character %s", row, i, result, single);
+
+ out.println();
+ }
+
+ if (count == 0)
+ throw new UselessException("count of 0");
+ }
+
+ private static class UselessException extends Exception {
+ private UselessException(String msg) {
+ super(msg);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ivy.xml b/ivy.xml
new file mode 100644
index 0000000..ccf5442
--- /dev/null
+++ b/ivy.xml
@@ -0,0 +1,80 @@
+<ivy-module version="2.0">
+ <info organisation="uk.org.mkgmap" module="mkgmap"/>
+
+ <configurations>
+ <conf name="default" visibility="public" description="runtime dependencies and master artifact can be used with this conf" extends="runtime,master"/>
+ <conf name="master" visibility="public" description="contains only the artifact published by this module itself, with no transitive dependencies"/>
+ <conf name="compile" visibility="public" description="this is the default scope, used if none is specified. Compile dependencies are available in all classpaths."/>
+ <conf name="runtime" visibility="public" description="this scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath." extends="compile"/>
+ <conf name="test" visibility="private" description="this scope indicates that the dependency is not required for normal use of the application, and is only available for the test compilation and execution phases." extends="runtime"/>
+ <conf name="optional" visibility="public" description="contains all optional dependencies"/>
+
+ <conf name="macker" visibility="private" description="to run the macker ant task" />
+ </configurations>
+
+ <publications>
+ <artifact name="mkgmap" conf="master" />
+ </publications>
+ <dependencies>
+ <dependency org="com.google.protobuf" name="protobuf-java"
+ rev="2.4.1"
+ conf="compile->compile(*),master(*)" />
+
+ <dependency org="crosby" name="osmpbf"
+ rev="1.1.1-754a33af"
+ conf="compile->compile(*),master(*)" />
+
+ <dependency org="it.unimi.dsi" name="fastutil"
+ rev="6.5.2-mkg.1"
+ conf="compile->default(*)"
+ />
+
+ <dependency org="junit" name="junit"
+ rev="4.5"
+ conf="test->runtime(*),master(*)" />
+
+ <dependency org="innig" name="macker"
+ rev="0.4.2"
+ conf="macker->compile(*),master(*)" />
+
+ <!-- the following are dependencies of macker, but
+ macker's POM file doesn't list them so they're
+ listed manually here -->
+ <dependency org="commons-lang" name="commons-lang"
+ rev="1.0.1"
+ conf="macker->compile(*),master(*)" />
+ <dependency org="innig" name="innig-util"
+ rev="0.4.2"
+ conf="macker->compile(*),master(*)" />
+ <dependency org="bcel" name="bcel"
+ rev="5.1"
+ conf="macker->compile(*),master(*)" />
+ <dependency org="jdom" name="jdom"
+ rev="b9"
+ conf="macker->compile(*),master(*)" />
+
+ <dependency org="com.ibm.icu" name="icu4j" rev="4.8"
+ conf="optional->master"/>
+
+ <dependency org="org.apache.ant" name="ant" rev="1.8.2"
+ conf="optional->master"/>
+
+ <dependency org="javax.media.jai" name="com.springsource.javax.media.jai.codec" rev="1.1.3"
+ conf="optional->compile"/>
+ <dependency org="javax.media.jai" name="com.springsource.javax.media.jai.core" rev="1.1.3"
+ conf="optional->default(*),compile(*),master(*)"/>
+
+ <dependency org="org.geotools" name="gt-api" rev="2.7.5" conf="optional->default,compile">
+ <!-- A broken version of this is in the main repo which causes problems. Since we already depend on it, just ignore it here -->
+ <exclude module="jai_core"/>
+ </dependency>
+ <dependency org="org.geotools" name="gt-cql" rev="2.7.5" conf="optional->default,compile">
+ <exclude module="jai_core"/>
+ </dependency>
+ <dependency org="org.geotools" name="gt-shapefile" rev="2.7.5" conf="optional->default,compile">
+ <exclude module="jai_core"/>
+ </dependency>
+ <dependency org="org.geotools" name="geotools" rev="2.7.5" conf="optional->default,compile"/>
+
+ </dependencies>
+</ivy-module>
diff --git a/ivysettings.xml b/ivysettings.xml
new file mode 100644
index 0000000..ee4c8ab
--- /dev/null
+++ b/ivysettings.xml
@@ -0,0 +1,38 @@
+<ivysettings>
+ <property name="mkgmap.ivy.repo" value="http://ivy.mkgmap.org.uk/repo" />
+ <settings defaultResolver="custom" />
+
+ <include url="${ivy.default.settings.dir}/ivysettings-public.xml"/>
+ <include url="${ivy.default.settings.dir}/ivysettings-shared.xml"/>
+ <include url="${ivy.default.settings.dir}/ivysettings-local.xml"/>
+ <include url="${ivy.default.settings.dir}/ivysettings-main-chain.xml"/>
+ <include url="${ivy.default.settings.dir}/ivysettings-default-chain.xml"/>
+
+ <resolvers>
+ <chain name="custom" returnFirst="true">
+
+ <resolver ref="default" />
+
+ <url name="mkgmap">
+ <ivy pattern="${mkgmap.ivy.repo}/[organisation]/[module]/[revision]/ivys/ivy.xml" />
+ <artifact pattern="${mkgmap.ivy.repo}/[organisation]/[module]/[revision]/[type]s/[artifact].[ext]" />
+ </url>
+
+ </chain>
+
+ <ibiblio name="geotools-resolver" m2compatible="true" root="http://repo.opengeo.org/" />
+
+ <url name="spring-resolver" >
+ <ivy pattern="http://repository.springsource.com/ivy/bundles/external/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
+ <artifact pattern="http://repository.springsource.com/ivy/bundles/external/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
+ </url>
+
+ </resolvers>
+
+ <modules>
+ <module organisation="org.geotools" resolver="geotools-resolver"/>
+ <module organisation="java3d" resolver="geotools-resolver"/>
+ <module organisation="javax.media.jai" resolver="spring-resolver"/>
+ </modules>
+
+</ivysettings>
diff --git a/mkgmap.iml b/mkgmap.iml
new file mode 100644
index 0000000..07417c8
--- /dev/null
+++ b/mkgmap.iml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module relativePaths="true" type="JAVA_MODULE" version="4">
+ <component name="FacetManager">
+ <facet type="Python" name="Python">
+ <configuration sdkName="" />
+ </facet>
+ <facet type="IvyIDEA" name="IvyIDEA">
+ <configuration ivyFile="$MODULE_DIR$/ivy.xml" useProjectSettings="true" useCustomIvySettings="true" ivySettingsFile="" onlyResolveSelectedConfigs="false">
+ <propertiesSettings>
+ <propertiesFiles includeProjectLevelPropertiesFiles="true" />
+ </propertiesSettings>
+ </configuration>
+ </facet>
+ </component>
+ <component name="NewModuleRootManager" inherit-compiler-output="false">
+ <output url="file://$MODULE_DIR$/build/classes" />
+ <output-test url="file://$MODULE_DIR$/build/test" />
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/extra/src" isTestSource="false" />
+ <excludeFolder url="file://$MODULE_DIR$/63240005" />
+ <excludeFolder url="file://$MODULE_DIR$/dist" />
+ <excludeFolder url="file://$MODULE_DIR$/g" />
+ <excludeFolder url="file://$MODULE_DIR$/gmapsupp" />
+ <excludeFolder url="file://$MODULE_DIR$/localtest" />
+ <excludeFolder url="file://$MODULE_DIR$/maps" />
+ <excludeFolder url="file://$MODULE_DIR$/ref" />
+ <excludeFolder url="file://$MODULE_DIR$/samples" />
+ <excludeFolder url="file://$MODULE_DIR$/test-reports" />
+ <excludeFolder url="file://$MODULE_DIR$/test/resources/in" />
+ <excludeFolder url="file://$MODULE_DIR$/tmp" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="library" name="resource" level="project" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntry type="module-library">
+ <library name="IvyIDEA">
+ <CLASSES>
+ <root url="jar://$USER_HOME$/.ivy2/cache/com.google.protobuf/protobuf-java/jars/protobuf-java-2.4.1.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/crosby/osmpbf/jars/osmpbf-1.1.1-754a33af.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/junit/junit/jars/junit-4.5.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/com.ibm.icu/icu4j/jars/icu4j-4.8.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.apache.ant/ant/jars/ant-1.8.2.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/javax.media.jai/com.springsource.javax.media.jai.codec/jars/com.springsource.javax.media.jai.codec-1.1.3.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/javax.media.jai/com.springsource.javax.media.jai.core/jars/com.springsource.javax.media.jai.core-1.1.3.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.geotools/gt-api/jars/gt-api-2.7.5.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/com.vividsolutions/jts/jars/jts-1.11.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/xerces/xercesImpl/jars/xercesImpl-2.7.1.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.geotools/gt-referencing/jars/gt-referencing-2.7.5.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/java3d/vecmath/jars/vecmath-1.3.2.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/commons-pool/commons-pool/jars/commons-pool-1.5.4.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.geotools/gt-metadata/jars/gt-metadata-2.7.5.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.geotools/gt-opengis/jars/gt-opengis-2.7.5.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/net.java.dev.jsr-275/jsr-275/jars/jsr-275-1.0-beta-2.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.geotools/gt-cql/jars/gt-cql-2.7.5.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.geotools/gt-main/jars/gt-main-2.7.5.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/jdom/jdom/jars/jdom-1.0.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/innig/macker/jars/macker-0.4.2.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/commons-lang/commons-lang/jars/commons-lang-1.0.1.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/innig/innig-util/jars/innig-util-0.4.2.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/bcel/bcel/jars/bcel-5.1.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/regexp/regexp/jars/regexp-1.2.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/jdom/jdom/jars/jdom-b9.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/it.unimi.dsi/fastutil/jars/fastutil-6.5.2-mkg.1.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.geotools/gt-shapefile/jars/gt-shapefile-2.7.5.jar!/" />
+ <root url="jar://$USER_HOME$/.ivy2/cache/org.geotools/gt-data/jars/gt-data-2.7.5.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ </component>
+</module>
+
diff --git a/resources/LocatorConfig.xml b/resources/LocatorConfig.xml
new file mode 100644
index 0000000..ffec3f9
--- /dev/null
+++ b/resources/LocatorConfig.xml
@@ -0,0 +1,1200 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<locator>
+ <country name="Afghanistan" abr="AFG">
+ <variant>AF</variant>
+ <variant>AFG</variant>
+ <variant>âاÙغاÙستاÙâ</variant>
+ </country>
+ <country name="Ã
land Islands" abr="ALA" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>AX</variant>
+ <variant>ALA</variant>
+ <variant>Ã
land</variant>
+ <variant>Ahvenanmaa</variant>
+ </country>
+ <country name="Albania" abr="ALB">
+ <variant>AL</variant>
+ <variant>ALB</variant>
+ <variant>Shqipëria</variant>
+ </country>
+ <country name="Algeria" abr="DZA">
+ <variant>DZ</variant>
+ <variant>DZA</variant>
+ <variant>Algérie</variant>
+ </country>
+ <country name="American Samoa" abr="ASM">
+ <variant>AS</variant>
+ <variant>ASM</variant>
+ </country>
+ <country name="Andorra" abr="AND">
+ <variant>AD</variant>
+ <variant>AND</variant>
+ </country>
+ <country name="Angola" abr="AGO">
+ <variant>AO</variant>
+ <variant>AGO</variant>
+ </country>
+ <country name="Anguilla" abr="AIA">
+ <variant>AI</variant>
+ <variant>AIA</variant>
+ </country>
+ <country name="Antarctica" abr="ATA">
+ <variant>AQ</variant>
+ <variant>ATA</variant>
+ </country>
+ <country name="Antigua and Barbuda" abr="ATG">
+ <variant>AG</variant>
+ <variant>ATG</variant>
+ </country>
+ <country name="Argentina" abr="ARG" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>AR</variant>
+ <variant>ARG</variant>
+ </country>
+ <country name="Armenia" abr="ARM">
+ <variant>AM</variant>
+ <variant>ARM</variant>
+ </country>
+ <country name="Aruba" abr="ABW">
+ <variant>AW</variant>
+ <variant>ABW</variant>
+ </country>
+ <country name="Australia" abr="AUS">
+ <variant>AU</variant>
+ <variant>AUS</variant>
+ </country>
+ <country name="Ãsterreich" abr="AUT" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>Austria</variant>
+ <variant>AT</variant>
+ <variant>AUT</variant>
+ <variant>Oesterreich</variant>
+ <variant>Oestereich</variant>
+ <variant>Ãstereich</variant>
+ </country>
+ <country name="Azerbaijan" abr="AZE">
+ <variant>AZ</variant>
+ <variant>AZE</variant>
+ <variant>AzÉrbaycan</variant>
+ </country>
+ <country name="Bahamas" abr="BHS">
+ <variant>BS</variant>
+ <variant>BHS</variant>
+ <variant>The Bahamas</variant>
+ </country>
+ <country name="Bahrain" abr="BHR">
+ <variant>BH</variant>
+ <variant>BHR</variant>
+ <variant>اÙإسÙاÙ
ÙØ©</variant>
+ </country>
+ <country name="Bangladesh" abr="BGD">
+ <variant>BD</variant>
+ <variant>BGD</variant>
+ <variant>বাà¦à¦²à¦¾à¦¦à§à¦¶</variant>
+ </country>
+ <country name="Barbados" abr="BRB">
+ <variant>BB</variant>
+ <variant>BRB</variant>
+ </country>
+ <country name="Belarus" abr="BLR" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>BY</variant>
+ <variant>BLR</variant>
+ <variant>RéspublÃka Belarus'</variant>
+ <variant>Republic of Belarus</variant>
+ <variant>Ð ÑÑпÑблÑка ÐелаÑÑÑÑ</variant>
+ </country>
+ <country name="België - Belgique" abr="BEL" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>BE</variant>
+ <variant>BEL</variant>
+ <variant>België</variant>
+ <variant>Belgique</variant>
+ <variant>Belgium</variant>
+ <variant>Belgien</variant>
+ <variant>België - Belgique - Belgien</variant>
+ </country>
+ <country name="Belize" abr="BLZ">
+ <variant>BZ</variant>
+ <variant>BLZ</variant>
+ </country>
+ <country name="Benin" abr="BEN">
+ <variant>BJ</variant>
+ <variant>BEN</variant>
+ </country>
+ <country name="Bermuda" abr="BMU">
+ <variant>BM</variant>
+ <variant>BMU</variant>
+ </country>
+ <country name="Bhutan" abr="BTN">
+ <variant>BT</variant>
+ <variant>BTN</variant>
+ </country>
+ <country name="Bolivia" abr="BOL" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>Plurinational State of Bolivia</variant>
+ <variant>BO</variant>
+ <variant>BOL</variant>
+ </country>
+ <country name="Bonaire" abr="BES">
+ <variant>BQ</variant>
+ <variant>BES</variant>
+ </country>
+ <country name="Bosna I Hercegovina" abr="BIH">
+ <variant>BA</variant>
+ <variant>BIH</variant>
+ <variant>Bosnia and Herzegovina</variant>
+ </country>
+ <country name="Botswana" abr="BWA">
+ <variant>BW</variant>
+ <variant>BWA</variant>
+ </country>
+ <country name="Bouvet Island" abr="BVT">
+ <variant>BV</variant>
+ <variant>BVT</variant>
+ </country>
+ <country name="Brazil" abr="BRA" streetBeforeHousenumber="true">
+ <variant>BR</variant>
+ <variant>BRA</variant>
+ </country>
+ <country name="British Indian Ocean Territory" abr="IOT">
+ <variant>IO</variant>
+ <variant>IOT</variant>
+ </country>
+ <country name="Brunei Darussalam" abr="BRN">
+ <variant>BN</variant>
+ <variant>BRN</variant>
+ <variant>برÙ٠داراÙسÙاÙ
â</variant>
+ <variant>Brunei</variant>
+ </country>
+ <country name="Bulgaria" abr="BGR">
+ <variant>BG</variant>
+ <variant>BGR</variant>
+ <variant>ÐÑлгаÑиÑ</variant>
+ </country>
+ <country name="Burkina Faso" abr="BFA">
+ <variant>BF</variant>
+ <variant>BFA</variant>
+ </country>
+ <country name="Burundi" abr="BDI">
+ <variant>BI</variant>
+ <variant>BDI</variant>
+ </country>
+ <country name="Cambodia" abr="KHM">
+ <variant>KH</variant>
+ <variant>KHM</variant>
+ <variant>áááááá¶áá¶áá¶á
áááááááá»áá¶</variant>
+ </country>
+ <country name="Cameroon" abr="CMR">
+ <variant>CM</variant>
+ <variant>CMR</variant>
+ <variant>Cameroun</variant>
+ </country>
+ <country name="Canada" abr="CAN">
+ <variant>CA</variant>
+ <variant>CAN</variant>
+ </country>
+ <country name="Cape Verde" abr="CPV">
+ <variant>CV</variant>
+ <variant>CPV</variant>
+ <variant>Cabo Verde</variant>
+ </country>
+ <country name="Cayman Islands" abr="CYM">
+ <variant>KY</variant>
+ <variant>CYM</variant>
+ </country>
+ <country name="Central African Republic" abr="CAF">
+ <variant>CF</variant>
+ <variant>CAF</variant>
+ <variant>Ködrö tî Bê-Afrika</variant>
+ </country>
+ <country name="Chad" abr="TCD">
+ <variant>TD</variant>
+ <variant>TCD</variant>
+ <variant>جÙ
ÙÙرÙÙØ© تشاد</variant>
+ </country>
+ <country name="Chile" abr="CHL" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>CL</variant>
+ <variant>CHL</variant>
+ </country>
+ <country name="China" abr="CHN">
+ <variant>CN</variant>
+ <variant>CHN</variant>
+ <variant>People's Republic of China</variant>
+ </country>
+ <country name="Christmas Island" abr="CXR">
+ <variant>CX</variant>
+ <variant>CXR</variant>
+ </country>
+ <country name="Cocos (Keeling) Islands" abr="CCK">
+ <variant>CC</variant>
+ <variant>CCK</variant>
+ </country>
+ <country name="Colombia" abr="COL">
+ <variant>CO</variant>
+ <variant>COL</variant>
+ </country>
+ <country name="Comoros" abr="COM">
+ <variant>KM</variant>
+ <variant>COM</variant>
+ <variant>Komori</variant>
+ </country>
+ <country name="Republic of the Congo" abr="COG">
+ <variant>CG</variant>
+ <variant>COG</variant>
+ <variant>Congo-Brazzaville</variant>
+ </country>
+ <country name="Democratic Republic of the Congo" abr="COD">
+ <variant>The Democratic Republic of the Congo</variant>
+ <variant>CD</variant>
+ <variant>COD</variant>
+ <variant>Congo-Kinshasa</variant>
+ </country>
+ <country name="Cook Islands" abr="COK">
+ <variant>CK</variant>
+ <variant>COK</variant>
+ </country>
+ <country name="Costa Rica" abr="CRI">
+ <variant>CR</variant>
+ <variant>CRI</variant>
+ </country>
+ <country name="Côte d'Ivoire" abr="CIV">
+ <variant>CI</variant>
+ <variant>CIV</variant>
+ </country>
+ <country name="Hrvatska" abr="HRV" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>HR</variant>
+ <variant>HRV</variant>
+ <variant>Croatia</variant>
+ </country>
+ <country name="Cuba" abr="CUB">
+ <variant>CU</variant>
+ <variant>CUB</variant>
+ </country>
+ <country name="Curaçao" abr="CUW">
+ <variant>CW</variant>
+ <variant>CUW</variant>
+ </country>
+ <country name="Cyprus" abr="CYP">
+ <variant>CY</variant>
+ <variant>CYP</variant>
+ <variant>ÎÏ
ÏÏιακή ÎημοκÏαÏία</variant>
+ </country>
+ <country name="Ceská Republika" abr="CZE" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>CZ</variant>
+ <variant>CZE</variant>
+ <variant>Czech Republic</variant>
+ <variant>Äeská republika</variant>
+ </country>
+ <country name="Danmark" abr="DNK" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>Denmark</variant>
+ <variant>DK</variant>
+ <variant>DNK</variant>
+ </country>
+ <country name="Djibouti" abr="DJI">
+ <variant>DJ</variant>
+ <variant>DJI</variant>
+ </country>
+ <country name="Dominica" abr="DMA">
+ <variant>DM</variant>
+ <variant>DMA</variant>
+ </country>
+ <country name="Dominican Republic" abr="DOM">
+ <variant>DO</variant>
+ <variant>DOM</variant>
+ <variant>República Dominicana</variant>
+ </country>
+ <country name="Ecuador" abr="ECU">
+ <variant>EC</variant>
+ <variant>ECU</variant>
+ </country>
+ <country name="Egypt" abr="EGY">
+ <variant>EG</variant>
+ <variant>EGY</variant>
+ <variant>جÙ
ÙÙرÙØ© Ù
صر اÙعربÙØ©</variant>
+ </country>
+ <country name="El Salvador" abr="SLV">
+ <variant>SV</variant>
+ <variant>SLV</variant>
+ </country>
+ <country name="Equatorial Guinea" abr="GNQ">
+ <variant>GQ</variant>
+ <variant>GNQ</variant>
+ <variant>Guinea Ecuatorial</variant>
+ </country>
+ <country name="Eritrea" abr="ERI">
+ <variant>ER</variant>
+ <variant>ERI</variant>
+ </country>
+ <country name="Eesti" abr="EST" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>Eesti Vabariik</variant>
+ <variant>Estonia</variant>
+ <variant>EE</variant>
+ <variant>EST</variant>
+ </country>
+ <country name="Ethiopia" abr="ETH">
+ <variant>ET</variant>
+ <variant>ETH</variant>
+ </country>
+ <country name="Falkland Islands (Malvinas)" abr="FLK">
+ <variant>FK</variant>
+ <variant>FLK</variant>
+ </country>
+ <country name="Faroe Islands" abr="FRO">
+ <variant>FO</variant>
+ <variant>FRO</variant>
+ <variant>Føroyar</variant>
+ </country>
+ <country name="Fiji" abr="FJI">
+ <variant>FJ</variant>
+ <variant>FJI</variant>
+ <variant>VITI</variant>
+ </country>
+ <country name="Suomi" abr="FIN" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>Finland</variant>
+ <variant>FI</variant>
+ <variant>FIN</variant>
+ </country>
+ <country name="France" abr="FRA" postalcodeBeforeCity="true">
+ <variant>FR</variant>
+ <variant>FRA</variant>
+ <variant>Metropolitan France</variant>
+ <variant>France métropolitaine</variant>
+ </country>
+ <country name="French Guiana" abr="GUF">
+ <variant>GF</variant>
+ <variant>GUF</variant>
+ </country>
+ <country name="French Polynesia" abr="PYF">
+ <variant>PF</variant>
+ <variant>PYF</variant>
+ </country>
+ <country name="French Southern Territories" abr="ATF">
+ <variant>TF</variant>
+ <variant>ATF</variant>
+ </country>
+ <country name="Gabon" abr="GAB">
+ <variant>GA</variant>
+ <variant>GAB</variant>
+ </country>
+ <country name="Gambia" abr="GMB">
+ <variant>GM</variant>
+ <variant>GMB</variant>
+ <variant>The Gambia</variant>
+ </country>
+ <country name="Georgia" abr="GEO">
+ <variant>GE</variant>
+ <variant>GEO</variant>
+ <variant>á¡áá¥áá ááááá</variant>
+ </country>
+ <country name="Deutschland" abr="DEU" regionOffset="3" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>Bundesrepublik Deutschland</variant>
+ <variant>Germany</variant>
+ <variant>Federal Republic of Germany</variant>
+ <variant>DE</variant>
+ <variant>DEU</variant>
+ </country>
+ <country name="Ghana" abr="GHA">
+ <variant>GH</variant>
+ <variant>GHA</variant>
+ </country>
+ <country name="Gibraltar" abr="GIB">
+ <variant>GI</variant>
+ <variant>GIB</variant>
+ </country>
+ <country name="Greece" abr="GRC" streetBeforeHousenumber="true">
+ <variant>GR</variant>
+ <variant>GRC</variant>
+ <variant>Elláda</variant>
+ <variant>Îλλάδα</variant>
+ </country>
+ <country name="Greenland" abr="GRL">
+ <variant>GL</variant>
+ <variant>GRL</variant>
+ </country>
+ <country name="Grenada" abr="GRD">
+ <variant>GD</variant>
+ <variant>GRD</variant>
+ </country>
+ <country name="Guadeloupe" abr="GLP">
+ <variant>GP</variant>
+ <variant>GLP</variant>
+ <variant>Guadeloupe - Eaux Territoriales</variant>
+ </country>
+ <country name="Guam" abr="GUM">
+ <variant>GU</variant>
+ <variant>GUM</variant>
+ </country>
+ <country name="Guatemala" abr="GTM">
+ <variant>GT</variant>
+ <variant>GTM</variant>
+ </country>
+ <country name="Guernsey" abr="GGY">
+ <variant>GG</variant>
+ <variant>GGY</variant>
+ </country>
+ <country name="Guinea" abr="GIN">
+ <variant>GN</variant>
+ <variant>GIN</variant>
+ </country>
+ <country name="Guinea-Bissau" abr="GNB">
+ <variant>GW</variant>
+ <variant>GNB</variant>
+ <variant>Guiné-Bissau</variant>
+ </country>
+ <country name="Guyana" abr="GUY">
+ <variant>GY</variant>
+ <variant>GUY</variant>
+ </country>
+ <country name="Haiti" abr="HTI">
+ <variant>HT</variant>
+ <variant>HTI</variant>
+ <variant>Ayiti</variant>
+ </country>
+ <country name="Heard Island and McDonald Islands" abr="HMD">
+ <variant>HM</variant>
+ <variant>HMD</variant>
+ </country>
+ <country name="Vatican" abr="VAT">
+ <variant>Holy See</variant>
+ <variant>VA</variant>
+ <variant>VAT</variant>
+ <variant>Vatican City</variant>
+ <variant>Status Civitatis Vaticanæ</variant>
+ </country>
+ <country name="Honduras" abr="HND">
+ <variant>HN</variant>
+ <variant>HND</variant>
+ </country>
+ <country name="Hong Kong" abr="HKG">
+ <variant>HK</variant>
+ <variant>HKG</variant>
+ </country>
+ <country name="Hungary" abr="HUN" streetBeforeHousenumber="true">
+ <variant>HU</variant>
+ <variant>HUN</variant>
+ <variant>Magyarország</variant>
+ </country>
+ <country name="Ãsland" abr="ISL" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>Lýðveldið Ãsland</variant>
+ <variant>Iceland</variant>
+ <variant>IS</variant>
+ <variant>ICE</variant>
+ <variant>ISL</variant>
+ </country>
+ <country name="India" abr="IND">
+ <variant>IN</variant>
+ <variant>IND</variant>
+ </country>
+ <country name="Indonesia" abr="IDN" streetBeforeHousenumber="true">
+ <variant>ID</variant>
+ <variant>IDN</variant>
+ </country>
+ <country name="Iran" abr="IRN">
+ <variant>Islamic Republic of Iran</variant>
+ <variant>IR</variant>
+ <variant>IRN</variant>
+ <variant>âاÙراÙâ</variant>
+ </country>
+ <country name="Iraq" abr="IRQ">
+ <variant>IQ</variant>
+ <variant>IRQ</variant>
+ <variant>جÙ
ÙÙرÙØ© اÙعراÙ</variant>
+ </country>
+ <country name="Ireland" abr="IRL" regionOffset="3">
+ <variant>Republic of Ireland</variant>
+ <variant>Ãire</variant>
+ <variant>IE</variant>
+ <variant>IRL</variant>
+ </country>
+ <country name="Isle of Man" abr="IMN">
+ <variant>IM</variant>
+ <variant>IMN</variant>
+ </country>
+ <country name="Israel" abr="ISR" streetBeforeHousenumber="true">
+ <variant>IL</variant>
+ <variant>ISR</variant>
+ <variant>×××× ×ª ×שר××</variant>
+ </country>
+ <country name="Italia" abr="ITA" regionOffset="2" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>Italy</variant>
+ <variant>IT</variant>
+ <variant>ITA</variant>
+ </country>
+ <country name="Jamaica" abr="JAM">
+ <variant>JM</variant>
+ <variant>JAM</variant>
+ </country>
+ <country name="Japan" abr="JPN">
+ <variant>JP</variant>
+ <variant>JPN</variant>
+ <variant>æ¥æ¬</variant>
+ </country>
+ <country name="Jersey" abr="JEY">
+ <variant>JE</variant>
+ <variant>JEY</variant>
+ </country>
+ <country name="Jordan" abr="JOR">
+ <variant>JO</variant>
+ <variant>JOR</variant>
+ </country>
+ <country name="Kazakhstan" abr="KAZ">
+ <variant>KZ</variant>
+ <variant>KAZ</variant>
+ <variant>ÐазаÑ
ÑÑан</variant>
+ </country>
+ <country name="Kenya" abr="KEN">
+ <variant>KE</variant>
+ <variant>KEN</variant>
+ </country>
+ <country name="Kiribati" abr="KIR">
+ <variant>KI</variant>
+ <variant>KIR</variant>
+ </country>
+ <country name="North Korea" abr="PRK">
+ <variant>Democratic People's Republic of Korea</variant>
+ <variant>KP</variant>
+ <variant>PRK</variant>
+ <variant>ì¡°ì 민주주ìì¸ë¯¼ê³µíêµ</variant>
+ </country>
+ <country name="South Korea" abr="KOR">
+ <variant>Republic of Korea</variant>
+ <variant>KR</variant>
+ <variant>KOR</variant>
+ <variant>ëí민êµ</variant>
+ </country>
+ <country name="Kuwait" abr="KWT">
+ <variant>KW</variant>
+ <variant>KWT</variant>
+ </country>
+ <country name="Kyrgyzstan" abr="KGZ">
+ <variant>KG</variant>
+ <variant>KGZ</variant>
+ <variant>ÐÑÑгÑзÑÑан</variant>
+ </country>
+ <country name="Laos" abr="LAO">
+ <variant>Lao People's Democratic Republic</variant>
+ <variant>LA</variant>
+ <variant>LAO</variant>
+ </country>
+ <country name="Latvija" abr="LVA" streetBeforeHousenumber="true">
+ <variant>LV</variant>
+ <variant>LVA</variant>
+ <variant>Latvia</variant>
+ </country>
+ <country name="Lebanon" abr="LBN">
+ <variant>LB</variant>
+ <variant>LBN</variant>
+ <variant>اÙجÙ
ÙÙرÙØ© اÙÙبÙاÙÙØ©</variant>
+ </country>
+ <country name="Lesotho" abr="LSO">
+ <variant>LS</variant>
+ <variant>LSO</variant>
+ <variant>Kingdom of Lesotho</variant>
+ <variant>Muso oa Lesotho</variant>
+ </country>
+ <country name="Liberia" abr="LBR">
+ <variant>LR</variant>
+ <variant>LBR</variant>
+ </country>
+ <country name="Libya" abr="LBY">
+ <variant>Libyan Arab Jamahiriya</variant>
+ <variant>LY</variant>
+ <variant>LBY</variant>
+ <variant>اÙجÙ
اÙÙرÙØ© اÙÙÙبÙØ©</variant>
+ </country>
+ <country name="Liechtenstein" abr="LIE">
+ <variant>LI</variant>
+ <variant>LIE</variant>
+ </country>
+ <country name="Lietuva" abr="LTU">
+ <variant>LT</variant>
+ <variant>LTU</variant>
+ <variant>Lithuania</variant>
+ </country>
+ <country name="Luxembourg" abr="LUX">
+ <variant>LU</variant>
+ <variant>LUX</variant>
+ <variant>Groussherzogtum Lëtzebuerg</variant>
+ <variant>Grand Duchy of Luxembourg</variant>
+ </country>
+ <country name="Macao" abr="MAC">
+ <variant>MO</variant>
+ <variant>MAC</variant>
+ </country>
+ <country name="Makedonija" abr="MKD">
+ <variant>MK</variant>
+ <variant>MKD</variant>
+ <variant>Macedonia</variant>
+ <variant>ÐакедониÑа</variant>
+ </country>
+ <country name="Madagascar" abr="MDG">
+ <variant>MG</variant>
+ <variant>MDG</variant>
+ <variant>Madagasikara</variant>
+ </country>
+ <country name="Malawi" abr="MWI">
+ <variant>MW</variant>
+ <variant>MWI</variant>
+ <variant>Republic of Malawi</variant>
+ </country>
+ <country name="Malaysia" abr="MYS">
+ <variant>MY</variant>
+ <variant>MYS</variant>
+ </country>
+ <country name="Maldives" abr="MDV">
+ <variant>MV</variant>
+ <variant>MDV</variant>
+ <variant>ÞÞ¨ÞÞ¬ÞÞ¨ÞÞ§ÞÞ°ÞÞÞÞ¬ ÞÞªÞÞªÞÞ«ÞÞ¨ÞÞ°ÞÞ§</variant>
+ </country>
+ <country name="Mali" abr="MLI">
+ <variant>ML</variant>
+ <variant>MLI</variant>
+ </country>
+ <country name="Malta" abr="MLT">
+ <variant>MT</variant>
+ <variant>MLT</variant>
+ </country>
+ <country name="Marshall Islands" abr="MHL">
+ <variant>MH</variant>
+ <variant>MHL</variant>
+ <variant>AolepÄn AorÅkin M̧ajeļ</variant>
+ </country>
+ <country name="Martinique" abr="MTQ">
+ <variant>MQ</variant>
+ <variant>MTQ</variant>
+ </country>
+ <country name="Mauritania" abr="MRT">
+ <variant>MR</variant>
+ <variant>MRT</variant>
+ </country>
+ <country name="Mauritius" abr="MUS">
+ <variant>MU</variant>
+ <variant>MUS</variant>
+ </country>
+ <country name="Mayotte" abr="MYT">
+ <variant>YT</variant>
+ <variant>MYT</variant>
+ <variant>Mayotte - Eaux territoriales</variant>
+ </country>
+ <country name="Mexico" abr="MEX" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>MX</variant>
+ <variant>MEX</variant>
+ <variant>México</variant>
+ </country>
+ <country name="Micronesia" abr="FSM">
+ <variant>Federated States of Micronesia</variant>
+ <variant>FM</variant>
+ <variant>FSM</variant>
+ </country>
+ <country name="Moldova" abr="MDA">
+ <variant>Republic of Moldova</variant>
+ <variant>MD</variant>
+ <variant>MDA</variant>
+ </country>
+ <country name="Monaco" abr="MCO">
+ <variant>MC</variant>
+ <variant>MCO</variant>
+ </country>
+ <country name="Mongolia" abr="MNG">
+ <variant>MN</variant>
+ <variant>MNG</variant>
+ </country>
+ <country name="Montenegro" abr="MNE" streetBeforeHousenumber="true">
+ <variant>ME</variant>
+ <variant>MNE</variant>
+ </country>
+ <country name="Montserrat" abr="MSR">
+ <variant>MS</variant>
+ <variant>MSR</variant>
+ </country>
+ <country name="Morocco" abr="MAR">
+ <variant>MA</variant>
+ <variant>MAR</variant>
+ </country>
+ <country name="Mozambique" abr="MOZ">
+ <variant>MZ</variant>
+ <variant>MOZ</variant>
+ <variant>Moçambique</variant>
+ </country>
+ <country name="Myanmar" abr="MMR">
+ <variant>MM</variant>
+ <variant>MMR</variant>
+ </country>
+ <country name="Namibia" abr="NAM">
+ <variant>NA</variant>
+ <variant>NAM</variant>
+ </country>
+ <country name="Nauru" abr="NRU">
+ <variant>NR</variant>
+ <variant>NRU</variant>
+ <variant>NAOERO</variant>
+ </country>
+ <country name="Nepal" abr="NPL">
+ <variant>NP</variant>
+ <variant>NPL</variant>
+ <variant>नà¥à¤ªà¤¾à¤²</variant>
+ </country>
+ <country name="Nederland" abr="NLD" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>NL</variant>
+ <variant>NLD</variant>
+ <variant>Netherlands</variant>
+ <variant>The Netherlands</variant>
+ </country>
+ <country name="New Caledonia" abr="NCL">
+ <variant>NC</variant>
+ <variant>NCL</variant>
+ </country>
+ <country name="New Zealand" abr="NZL">
+ <variant>NZ</variant>
+ <variant>NZL</variant>
+ <variant>AOTEAROA NEW ZEALAND</variant>
+ </country>
+ <country name="Nicaragua" abr="NIC">
+ <variant>NI</variant>
+ <variant>NIC</variant>
+ </country>
+ <country name="Niger" abr="NER">
+ <variant>NE</variant>
+ <variant>NER</variant>
+ </country>
+ <country name="Nigeria" abr="NGA">
+ <variant>NG</variant>
+ <variant>NGA</variant>
+ </country>
+ <country name="Niue" abr="NIU">
+ <variant>NU</variant>
+ <variant>NIU</variant>
+ </country>
+ <country name="Norfolk Island" abr="NFK">
+ <variant>NF</variant>
+ <variant>NFK</variant>
+ </country>
+ <country name="Northern Mariana Islands" abr="MNP">
+ <variant>MP</variant>
+ <variant>MNP</variant>
+ </country>
+ <country name="Norge" abr="NOR" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>Norway</variant>
+ <variant>Noreg</variant>
+ <variant>NO</variant>
+ <variant>NOR</variant>
+ <variant>Norge/Noreg</variant>
+ </country>
+ <country name="Oman" abr="OMN" streetBeforeHousenumber="true">
+ <variant>OM</variant>
+ <variant>OMN</variant>
+ <variant>âسÙØ·ÙØ© عÙ
اÙâ</variant>
+ </country>
+ <country name="Pakistan" abr="PAK">
+ <variant>PK</variant>
+ <variant>PAK</variant>
+ <variant>âپاکستاÙâ</variant>
+ </country>
+ <country name="Palau" abr="PLW">
+ <variant>PW</variant>
+ <variant>PLW</variant>
+ <variant>BELAU</variant>
+ </country>
+ <country name="Palestinian Territory" abr="PSE">
+ <variant>PS</variant>
+ <variant>PSE</variant>
+ <variant>Palestinian National Authority</variant>
+ </country>
+ <country name="Panama" abr="PAN">
+ <variant>PA</variant>
+ <variant>PAN</variant>
+ <variant>Panamá</variant>
+ </country>
+ <country name="Papua New Guinea" abr="PNG">
+ <variant>PG</variant>
+ <variant>PNG</variant>
+ <variant>PAPUA NIUGINI</variant>
+ </country>
+ <country name="Paraguay" abr="PRY" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>PY</variant>
+ <variant>PRY</variant>
+ </country>
+ <country name="Peru" abr="PER" streetBeforeHousenumber="true">
+ <variant>PE</variant>
+ <variant>PER</variant>
+ </country>
+ <country name="Philippines" abr="PHL">
+ <variant>PH</variant>
+ <variant>PHL</variant>
+ </country>
+ <country name="Pitcairn" abr="PCN">
+ <variant>PN</variant>
+ <variant>PCN</variant>
+ </country>
+ <country name="Polska" abr="POL" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>PL</variant>
+ <variant>POL</variant>
+ <variant>Poland</variant>
+ </country>
+ <country name="Portugal" abr="PRT" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>PT</variant>
+ <variant>PRT</variant>
+ <variant>POR</variant>
+ </country>
+ <country name="Puerto Rico" abr="PRI">
+ <variant>PR</variant>
+ <variant>PRI</variant>
+ </country>
+ <country name="Qatar" abr="QAT">
+ <variant>QA</variant>
+ <variant>QAT</variant>
+ <variant>âÙطرâ</variant>
+ </country>
+ <country name="Réunion" abr="REU">
+ <variant>RE</variant>
+ <variant>REU</variant>
+ </country>
+ <country name="România" abr="ROU" streetBeforeHousenumber="true">
+ <variant>RO</variant>
+ <variant>ROU</variant>
+ <variant>Romania</variant>
+ </country>
+ <country name="Russian Federation" abr="RUS" streetBeforeHousenumber="true">
+ <variant>RU</variant>
+ <variant>RUS</variant>
+ <variant>Russia</variant>
+ <variant>Rossiâ</variant>
+ <variant>Rossijskaâ Federaciâ</variant>
+ <variant>РоÑÑийÑÐºÐ°Ñ Ð¤ÐµÐ´ÐµÑаÑиÑ</variant>
+ </country>
+ <country name="Rwanda" abr="RWA">
+ <variant>RW</variant>
+ <variant>RWA</variant>
+ </country>
+ <country name="Saint Barthélemy" abr="BLM">
+ <variant>BL</variant>
+ <variant>BLM</variant>
+ <variant>Saint-Barthélémy</variant>
+ </country>
+ <country name="Saint Helena" abr="SHN">
+ <variant>Ascension</variant>
+ <variant>Tristan da Cunha</variant>
+ <variant>SH</variant>
+ <variant>SHN</variant>
+ </country>
+ <country name="Saint Kitts and Nevis" abr="KNA">
+ <variant>Saint Kitts</variant>
+ <variant>Nevis</variant>
+ <variant>KN</variant>
+ <variant>KNA</variant>
+ </country>
+ <country name="Saint Lucia" abr="LCA">
+ <variant>LC</variant>
+ <variant>LCA</variant>
+ </country>
+ <country name="Saint Martin" abr="MAF">
+ <variant>MF</variant>
+ <variant>MAF</variant>
+ </country>
+ <country name="Saint Pierre and Miquelon" abr="SPM">
+ <variant>Saint Pierre</variant>
+ <variant>Miquelon</variant>
+ <variant>PM</variant>
+ <variant>SPM</variant>
+ </country>
+ <country name="Saint Vincent and the Grenadines" abr="VCT">
+ <variant>Saint Vincent</variant>
+ <variant>Grenadines</variant>
+ <variant>VC</variant>
+ <variant>VCT</variant>
+ </country>
+ <country name="Samoa" abr="WSM">
+ <variant>WS</variant>
+ <variant>WSM</variant>
+ </country>
+ <country name="San Marino" abr="SMR">
+ <variant>SM</variant>
+ <variant>SMR</variant>
+ </country>
+ <country name="Sao Tome and Principe" abr="STP">
+ <variant>Sao Tome</variant>
+ <variant>Principe</variant>
+ <variant>ST</variant>
+ <variant>STP</variant>
+ <variant>São Tomé and PrÃncipe</variant>
+ <variant>São Tomé e PrÃncipe</variant>
+ </country>
+ <country name="Saudi Arabia" abr="SAU">
+ <variant>SA</variant>
+ <variant>SAU</variant>
+ </country>
+ <country name="Senegal" abr="SEN">
+ <variant>SN</variant>
+ <variant>SEN</variant>
+ </country>
+ <country name="Srbija" abr="SRB">
+ <variant>RS</variant>
+ <variant>SRB</variant>
+ <variant>Serbia</variant>
+ <variant>Republic of Serbia</variant>
+ </country>
+ <country name="Seychelles" abr="SYC">
+ <variant>SC</variant>
+ <variant>SYC</variant>
+ <variant>SESEL</variant>
+ </country>
+ <country name="Sierra Leone" abr="SLE">
+ <variant>SL</variant>
+ <variant>SLE</variant>
+ </country>
+ <country name="Singapore" abr="SGP">
+ <variant>SG</variant>
+ <variant>SGP</variant>
+ <variant>SINGAPURA</variant>
+ </country>
+ <country name="Sint Maarten" abr="SXM">
+ <variant>SX</variant>
+ <variant>SXM</variant>
+ </country>
+ <country name="Slovakia" abr="SVK" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>SK</variant>
+ <variant>SVK</variant>
+ <variant>Slovensko</variant>
+ </country>
+ <country name="Slovenija" abr="SVN" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>SI</variant>
+ <variant>SVN</variant>
+ <variant>Slovenia</variant>
+ </country>
+ <country name="Solomon Islands" abr="SLB">
+ <variant>SB</variant>
+ <variant>SLB</variant>
+ </country>
+ <country name="Somalia" abr="SOM">
+ <variant>SO</variant>
+ <variant>SOM</variant>
+ <variant>Soomaaliya</variant>
+ </country>
+ <country name="South Africa" abr="ZAF">
+ <variant>ZA</variant>
+ <variant>ZAF</variant>
+ </country>
+ <country name="South Georgia and the South Sandwich Islands" abr="SGS">
+ <variant>South Georgia</variant>
+ <variant>South Sandwich Islands</variant>
+ <variant>GS</variant>
+ <variant>SGS</variant>
+ </country>
+ <country name="España" abr="ESP" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>Spain</variant>
+ <variant>ES</variant>
+ <variant>ESP</variant>
+ </country>
+ <country name="Sri Lanka" abr="LKA">
+ <variant>LK</variant>
+ <variant>LKA</variant>
+ <variant>à·à·âර෠ලà¶à¶à·</variant>
+ </country>
+ <country name="South Sudan" abr="SSD">
+ <variant>SS</variant>
+ <variant>SSD</variant>
+ <variant>جÙ
ÙÙرÙØ© اÙسÙداÙ</variant>
+ </country>
+ <country name="Sudan" abr="SDN">
+ <variant>SD</variant>
+ <variant>SDN</variant>
+ <variant>جÙ
ÙÙرÙØ© اÙسÙداÙ</variant>
+ </country>
+ <country name="Suriname" abr="SUR">
+ <variant>SR</variant>
+ <variant>SUR</variant>
+ </country>
+ <country name="Svalbard and Jan Mayen" abr="SJM">
+ <variant>Svalbard</variant>
+ <variant>Jan Mayen</variant>
+ <variant>SJ</variant>
+ <variant>SJM</variant>
+ </country>
+ <country name="Swaziland" abr="SWZ">
+ <variant>SZ</variant>
+ <variant>SWZ</variant>
+ <variant>Swatini</variant>
+ </country>
+ <country name="Sverige" abr="SWE" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>Sweden</variant>
+ <variant>SE</variant>
+ <variant>SWE</variant>
+ </country>
+ <country name="Schweiz" abr="CHE" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>Switzerland</variant>
+ <variant>Suisse</variant>
+ <variant>CH</variant>
+ <variant>CHE</variant>
+ </country>
+ <country name="Syria" abr="SYR">
+ <variant>Syrian Arab Republic</variant>
+ <variant>SY</variant>
+ <variant>SYR</variant>
+ <variant>اÙجÙ
ÙÙرÙØ© اÙعربÙØ© اÙسÙرÙØ©</variant>
+ </country>
+ <country name="Taiwan" abr="TWN">
+ <variant>TW</variant>
+ <variant>TWN</variant>
+ <variant>Republic of China</variant>
+ </country>
+ <country name="Tajikistan" abr="TJK">
+ <variant>TJ</variant>
+ <variant>TJK</variant>
+ <variant>ТоҷикиÑÑон</variant>
+ </country>
+ <country name="Tanzania" abr="TZA">
+ <variant>United Republic of Tanzania</variant>
+ <variant>TZ</variant>
+ <variant>TZA</variant>
+ </country>
+ <country name="Thailand" abr="THA">
+ <variant>TH</variant>
+ <variant>THA</variant>
+ <variant>ราà¸à¸à¸²à¸à¸²à¸à¸±à¸à¸£à¹à¸à¸¢</variant>
+ </country>
+ <country name="Timor-Leste" abr="TLS">
+ <variant>TL</variant>
+ <variant>TLS</variant>
+ <variant>Timór Loro Sa'e</variant>
+ <variant>East Timor</variant>
+ </country>
+ <country name="Togo" abr="TGO">
+ <variant>TG</variant>
+ <variant>TGO</variant>
+ <variant>République Togolaise</variant>
+ </country>
+ <country name="Tokelau" abr="TKL">
+ <variant>TK</variant>
+ <variant>TKL</variant>
+ </country>
+ <country name="Tonga" abr="TON">
+ <variant>TO</variant>
+ <variant>TON</variant>
+ </country>
+ <country name="Trinidad and Tobago" abr="TTO">
+ <variant>Trinidad</variant>
+ <variant>Tobago</variant>
+ <variant>TT</variant>
+ <variant>TTO</variant>
+ </country>
+ <country name="Tunisia" abr="TUN">
+ <variant>TN</variant>
+ <variant>TUN</variant>
+ </country>
+ <country name="Turkey" abr="TUR" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>TR</variant>
+ <variant>TUR</variant>
+ <variant>Türkiye</variant>
+ </country>
+ <country name="Turkmenistan" abr="TKM">
+ <variant>TM</variant>
+ <variant>TKM</variant>
+ <variant>Türkmenistan</variant>
+ </country>
+ <country name="Turks and Caicos Islands" abr="TCA">
+ <variant>TC</variant>
+ <variant>TCA</variant>
+ </country>
+ <country name="Tuvalu" abr="TUV">
+ <variant>TV</variant>
+ <variant>TUV</variant>
+ </country>
+ <country name="Uganda" abr="UGA">
+ <variant>UG</variant>
+ <variant>UGA</variant>
+ </country>
+ <country name="Ukrayina" abr="UKR" streetBeforeHousenumber="true">
+ <variant>UA</variant>
+ <variant>UKR</variant>
+ <variant>Ukraine</variant>
+ <variant>УкÑаÑна</variant>
+ </country>
+ <country name="United Arab Emirates" abr="ARE">
+ <variant>AE</variant>
+ <variant>ARE</variant>
+ <variant>اÙØ¥Ù
ارات اÙعربÙÙØ© اÙÙ
تÙØدة</variant>
+ </country>
+ <country name="United Kingdom" abr="GBR">
+ <variant>England</variant>
+ <variant>Scotland</variant>
+ <variant>Wales</variant>
+ <variant>Northern Ireland</variant>
+ <variant>Great Britain</variant>
+ <variant>Great Britian</variant>
+ <variant>Gibraltar / United Kingdom</variant>
+ <variant>UK</variant>
+ <variant>GB</variant>
+ <variant>GBR</variant>
+ </country>
+ <country name="United States" abr="USA">
+ <variant>US</variant>
+ <variant>USA</variant>
+ <variant>United States of America</variant>
+ </country>
+ <country name="United States Minor Outlying Islands" abr="UMI">
+ <variant>UM</variant>
+ <variant>UMI</variant>
+ </country>
+ <country name="Uruguay" abr="URY" streetBeforeHousenumber="true" postalcodeBeforeCity="true">
+ <variant>UY</variant>
+ <variant>URY</variant>
+ </country>
+ <country name="Uzbekistan" abr="UZB">
+ <variant>UZ</variant>
+ <variant>UZB</variant>
+ <variant>Oʻzbekiston</variant>
+ </country>
+ <country name="Vanuatu" abr="VUT">
+ <variant>VU</variant>
+ <variant>VUT</variant>
+ </country>
+ <country name="Venezuela" abr="VEN">
+ <variant>Bolivarian Republic of Venezuela</variant>
+ <variant>VE</variant>
+ <variant>VEN</variant>
+ </country>
+ <country name="Vietnam" abr="VNM">
+ <variant>VN</variant>
+ <variant>VNM</variant>
+ <variant>Viá»t Nam</variant>
+ </country>
+ <country name="Virgin Islands, British" abr="VGB">
+ <variant>VG</variant>
+ <variant>VGB</variant>
+ <variant>British Virgin Islands</variant>
+ </country>
+ <country name="Virgin Islands, U.S." abr="VIR">
+ <variant>VI</variant>
+ <variant>VIR</variant>
+ </country>
+ <country name="Wallis and Futuna" abr="WLF">
+ <variant>WF</variant>
+ <variant>WLF</variant>
+ </country>
+ <country name="Western Sahara" abr="ESH">
+ <variant>EH</variant>
+ <variant>ESH</variant>
+ <variant>Sahrawi Arab Democratic Republic</variant>
+ <variant>اÙجÙ
ÙÙرÙØ© اÙعربÙØ© اÙصØراÙÙØ© اÙدÙÙ
ÙراطÙØ©</variant>
+ </country>
+ <country name="Yemen" abr="YEM">
+ <variant>YE</variant>
+ <variant>YEM</variant>
+ <variant>âاÙÙÙ
Ùâ</variant>
+ </country>
+ <country name="Zambia" abr="ZMB">
+ <variant>ZM</variant>
+ <variant>ZMB</variant>
+ </country>
+ <country name="Zimbabwe" abr="ZWE">
+ <variant>ZW</variant>
+ <variant>ZWE</variant>
+ </country>
+ <continent name="Europe">
+ </continent>
+ <continent name="Africa">
+ </continent>
+ <continent name="Asia">
+ </continent>
+ <continent name="North America">
+ </continent>
+ <continent name="South America">
+ </continent>
+ <continent name="Oceania">
+ </continent>
+</locator>
diff --git a/resources/chars/ascii/row00.trans b/resources/chars/ascii/row00.trans
new file mode 100644
index 0000000..849e832
--- /dev/null
+++ b/resources/chars/ascii/row00.trans
@@ -0,0 +1,142 @@
+# This is the transliteration table for the latin language into ascii
+# (characters above U+0080).
+#
+# The first column is the unicode character and the second
+# column is the transliteration of that character to ascii characters.
+# One or more characters can be used, for example for a character æ which
+# is a combined a and e you could write 'ae' (without the quotes) as the
+# transliteration.
+#
+# Any line can be deleted and will default to a '?' character
+
+# Created with the Text::Unidecode module of perl
+#
+
+U+0080 ? # Character Â
+U+0081 ? # Character Â
+U+0082 ? # Character Â
+U+0083 ? # Character Â
+U+0084 ? # Character Â
+U+0085 ? # Character Â
+U+0086 ? # Character Â
+U+0087 ? # Character Â
+U+0088 ? # Character Â
+U+0089 ? # Character Â
+U+008a ? # Character Â
+U+008b ? # Character Â
+U+008c ? # Character Â
+U+008d ? # Character Â
+U+008e ? # Character Â
+U+008f ? # Character Â
+U+0090 ? # Character Â
+U+0091 ? # Character Â
+U+0092 ? # Character Â
+U+0093 ? # Character Â
+U+0094 ? # Character Â
+U+0095 ? # Character Â
+U+0096 ? # Character Â
+U+0097 ? # Character Â
+U+0098 ? # Character Â
+U+0099 ? # Character Â
+U+009a ? # Character Â
+U+009b ? # Character Â
+U+009c ? # Character Â
+U+009d ? # Character Â
+U+009e ? # Character Â
+U+009f ? # Character Â
+U+00a0 # Character Â
+U+00a1 ! # Character ¡
+U+00a2 C/ # Character ¢
+U+00a3 PS # Character £
+U+00a4 ? # Character ¤
+U+00a5 Y= # Character ¥
+U+00a6 | # Character ¦
+U+00a7 SS # Character §
+U+00a8 " # Character ¨
+U+00a9 (c) # Character ©
+U+00aa a # Character ª
+U+00ab << # Character «
+U+00ac ! # Character ¬
+U+00ad ? # Character Â
+U+00ae (r) # Character ®
+U+00af - # Character ¯
+U+00b0 deg # Character °
+U+00b1 +- # Character ±
+U+00b2 2 # Character ²
+U+00b3 3 # Character ³
+U+00b4 ' # Character ´
+U+00b5 u # Character µ
+U+00b6 P # Character ¶
+U+00b7 * # Character ·
+U+00b8 , # Character ¸
+U+00b9 1 # Character ¹
+U+00ba o # Character º
+U+00bb >> # Character »
+U+00bc 1/4 # Character ¼
+U+00bd 1/2 # Character ½
+U+00be 3/4 # Character ¾
+U+00bf ? # Character ¿
+U+00c0 A # Character Ã
+U+00c1 A # Character Ã
+U+00c2 A # Character Ã
+U+00c3 A # Character Ã
+U+00c4 A # Character Ã
+U+00c5 A # Character Ã
+U+00c6 AE # Character Ã
+U+00c7 C # Character Ã
+U+00c8 E # Character Ã
+U+00c9 E # Character Ã
+U+00ca E # Character Ã
+U+00cb E # Character Ã
+U+00cc I # Character Ã
+U+00cd I # Character Ã
+U+00ce I # Character Ã
+U+00cf I # Character Ã
+U+00d0 D # Character Ã
+U+00d1 N # Character Ã
+U+00d2 O # Character Ã
+U+00d3 O # Character Ã
+U+00d4 O # Character Ã
+U+00d5 O # Character Ã
+U+00d6 O # Character Ã
+U+00d7 x # Character Ã
+U+00d8 O # Character Ã
+U+00d9 U # Character Ã
+U+00da U # Character Ã
+U+00db U # Character Ã
+U+00dc U # Character Ã
+U+00dd U # Character Ã
+U+00de Th # Character Ã
+U+00df ss # Character Ã
+U+00e0 a # Character Ã
+U+00e1 a # Character á
+U+00e2 a # Character â
+U+00e3 a # Character ã
+U+00e4 a # Character ä
+U+00e5 a # Character å
+U+00e6 ae # Character æ
+U+00e7 c # Character ç
+U+00e8 e # Character è
+U+00e9 e # Character é
+U+00ea e # Character ê
+U+00eb e # Character ë
+U+00ec i # Character ì
+U+00ed i # Character Ã
+U+00ee i # Character î
+U+00ef i # Character ï
+U+00f0 d # Character ð
+U+00f1 n # Character ñ
+U+00f2 o # Character ò
+U+00f3 o # Character ó
+U+00f4 o # Character ô
+U+00f5 o # Character õ
+U+00f6 o # Character ö
+U+00f7 / # Character ÷
+U+00f8 o # Character ø
+U+00f9 u # Character ù
+U+00fa u # Character ú
+U+00fb u # Character û
+U+00fc u # Character ü
+U+00fd y # Character ý
+U+00fe th # Character þ
+U+00ff y # Character ÿ
diff --git a/resources/chars/ascii/row01.trans b/resources/chars/ascii/row01.trans
new file mode 100644
index 0000000..994f642
--- /dev/null
+++ b/resources/chars/ascii/row01.trans
@@ -0,0 +1,262 @@
+#
+# This is the transliteration table for the latin 2 characters
+# that start at unicode U+0100 into ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+0100 A # Character Ä
+U+0101 a # Character Ä
+U+0102 A # Character Ä
+U+0103 a # Character Ä
+U+0104 A # Character Ä
+U+0105 a # Character Ä
+U+0106 C # Character Ä
+U+0107 c # Character Ä
+U+0108 C # Character Ä
+U+0109 c # Character Ä
+U+010a C # Character Ä
+U+010b c # Character Ä
+U+010c C # Character Ä
+U+010d c # Character Ä
+U+010e D # Character Ä
+U+010f d # Character Ä
+U+0110 D # Character Ä
+U+0111 d # Character Ä
+U+0112 E # Character Ä
+U+0113 e # Character Ä
+U+0114 E # Character Ä
+U+0115 e # Character Ä
+U+0116 E # Character Ä
+U+0117 e # Character Ä
+U+0118 E # Character Ä
+U+0119 e # Character Ä
+U+011a E # Character Ä
+U+011b e # Character Ä
+U+011c G # Character Ä
+U+011d g # Character Ä
+U+011e G # Character Ä
+U+011f g # Character Ä
+U+0120 G # Character Ä
+U+0121 g # Character Ä¡
+U+0122 G # Character Ģ
+U+0123 g # Character ģ
+U+0124 H # Character Ĥ
+U+0125 h # Character ĥ
+U+0126 H # Character Ħ
+U+0127 h # Character ħ
+U+0128 I # Character Ĩ
+U+0129 i # Character Ä©
+U+012a I # Character Ī
+U+012b i # Character Ä«
+U+012c I # Character Ĭ
+U+012d i # Character Ä
+U+012e I # Character Ä®
+U+012f i # Character į
+U+0130 I # Character Ä°
+U+0131 i # Character ı
+U+0132 IJ # Character IJ
+U+0133 ? # Character ij
+U+0134 J # Character Ä´
+U+0135 j # Character ĵ
+U+0136 K # Character Ķ
+U+0137 k # Character Ä·
+U+0138 k # Character ĸ
+U+0139 L # Character Ĺ
+U+013a l # Character ĺ
+U+013b L # Character Ä»
+U+013c l # Character ļ
+U+013d L # Character Ľ
+U+013e l # Character ľ
+U+013f L # Character Ä¿
+U+0140 l # Character Å
+U+0141 L # Character Å
+U+0142 l # Character Å
+U+0143 N # Character Å
+U+0144 n # Character Å
+U+0145 N # Character Å
+U+0146 n # Character Å
+U+0147 N # Character Å
+U+0148 n # Character Å
+U+0149 'n # Character Å
+U+014a ng # Character Å
+U+014b NG # Character Å
+U+014c O # Character Å
+U+014d o # Character Å
+U+014e O # Character Å
+U+014f o # Character Å
+U+0150 O # Character Å
+U+0151 o # Character Å
+U+0152 OE # Character Å
+U+0153 oe # Character Å
+U+0154 R # Character Å
+U+0155 r # Character Å
+U+0156 R # Character Å
+U+0157 r # Character Å
+U+0158 R # Character Å
+U+0159 r # Character Å
+U+015a S # Character Å
+U+015b s # Character Å
+U+015c S # Character Å
+U+015d s # Character Å
+U+015e S # Character Å
+U+015f s # Character Å
+U+0160 S # Character Å
+U+0161 s # Character Å¡
+U+0162 T # Character Ţ
+U+0163 t # Character ţ
+U+0164 T # Character Ť
+U+0165 t # Character ť
+U+0166 T # Character Ŧ
+U+0167 t # Character ŧ
+U+0168 U # Character Ũ
+U+0169 u # Character Å©
+U+016a U # Character Ū
+U+016b u # Character Å«
+U+016c U # Character Ŭ
+U+016d u # Character Å
+U+016e U # Character Å®
+U+016f u # Character ů
+U+0170 U # Character Å°
+U+0171 u # Character ű
+U+0172 U # Character Ų
+U+0173 u # Character ų
+U+0174 W # Character Å´
+U+0175 w # Character ŵ
+U+0176 Y # Character Ŷ
+U+0177 y # Character Å·
+U+0178 Y # Character Ÿ
+U+0179 Z # Character Ź
+U+017a z # Character ź
+U+017b Z # Character Å»
+U+017c z # Character ż
+U+017d Z # Character Ž
+U+017e z # Character ž
+U+017f s # Character Å¿
+U+0180 b # Character Æ
+U+0181 B # Character Æ
+U+0182 B # Character Æ
+U+0183 b # Character Æ
+U+0184 6 # Character Æ
+U+0185 6 # Character Æ
+U+0186 O # Character Æ
+U+0187 C # Character Æ
+U+0188 c # Character Æ
+U+0189 D # Character Æ
+U+018a D # Character Æ
+U+018b D # Character Æ
+U+018c d # Character Æ
+U+018d d # Character Æ
+U+018e 3 # Character Æ
+U+018f @ # Character Æ
+U+0190 E # Character Æ
+U+0191 F # Character Æ
+U+0192 f # Character Æ
+U+0193 G # Character Æ
+U+0194 G # Character Æ
+U+0195 hv # Character Æ
+U+0196 I # Character Æ
+U+0197 I # Character Æ
+U+0198 K # Character Æ
+U+0199 k # Character Æ
+U+019a l # Character Æ
+U+019b l # Character Æ
+U+019c W # Character Æ
+U+019d N # Character Æ
+U+019e n # Character Æ
+U+019f O # Character Æ
+U+01a0 O # Character Æ
+U+01a1 o # Character Æ¡
+U+01a2 OI # Character Ƣ
+U+01a3 oi # Character ƣ
+U+01a4 P # Character Ƥ
+U+01a5 p # Character ƥ
+U+01a6 YR # Character Ʀ
+U+01a7 2 # Character Ƨ
+U+01a8 2 # Character ƨ
+U+01a9 SH # Character Æ©
+U+01aa sh # Character ƪ
+U+01ab t # Character Æ«
+U+01ac T # Character Ƭ
+U+01ad t # Character Æ
+U+01ae T # Character Æ®
+U+01af U # Character Ư
+U+01b0 u # Character Æ°
+U+01b1 Y # Character Ʊ
+U+01b2 V # Character Ʋ
+U+01b3 Y # Character Ƴ
+U+01b4 y # Character Æ´
+U+01b5 Z # Character Ƶ
+U+01b6 z # Character ƶ
+U+01b7 ZH # Character Æ·
+U+01b8 ZH # Character Ƹ
+U+01b9 zh # Character ƹ
+U+01ba zh # Character ƺ
+U+01bb 2 # Character Æ»
+U+01bc 5 # Character Ƽ
+U+01bd 5 # Character ƽ
+U+01be ts # Character ƾ
+U+01bf w # Character Æ¿
+U+01c0 | # Character Ç
+U+01c1 || # Character Ç
+U+01c2 |= # Character Ç
+U+01c3 ! # Character Ç
+U+01c4 DZ # Character Ç
+U+01c5 Dz # Character Ç
+U+01c6 dz # Character Ç
+U+01c7 LJ # Character Ç
+U+01c8 Lj # Character Ç
+U+01c9 lj # Character Ç
+U+01ca NJ # Character Ç
+U+01cb Nj # Character Ç
+U+01cc nj # Character Ç
+U+01cd A # Character Ç
+U+01ce a # Character Ç
+U+01cf I # Character Ç
+U+01d0 i # Character Ç
+U+01d1 O # Character Ç
+U+01d2 o # Character Ç
+U+01d3 U # Character Ç
+U+01d4 u # Character Ç
+U+01d5 U # Character Ç
+U+01d6 u # Character Ç
+U+01d7 U # Character Ç
+U+01d8 u # Character Ç
+U+01d9 U # Character Ç
+U+01da u # Character Ç
+U+01db U # Character Ç
+U+01dc u # Character Ç
+U+01dd @ # Character Ç
+U+01de A # Character Ç
+U+01df a # Character Ç
+U+01e0 A # Character Ç
+U+01e1 a # Character Ç¡
+U+01e2 AE # Character Ǣ
+U+01e3 ae # Character ǣ
+U+01e4 G # Character Ǥ
+U+01e5 g # Character ǥ
+U+01e6 G # Character Ǧ
+U+01e7 g # Character ǧ
+U+01e8 K # Character Ǩ
+U+01e9 k # Character Ç©
+U+01ea O # Character Ǫ
+U+01eb o # Character Ç«
+U+01ec O # Character Ǭ
+U+01ed o # Character Ç
+U+01ee ZH # Character Ç®
+U+01ef zh # Character ǯ
+U+01f0 j # Character Ç°
+U+01f1 DZ # Character DZ
+U+01f2 D # Character Dz
+U+01f3 dz # Character dz
+U+01f4 G # Character Ç´
+U+01f5 g # Character ǵ
+U+01f6 HV # Character Ƕ
+U+01f7 W # Character Ç·
+U+01f8 N # Character Ǹ
+U+01f9 n # Character ǹ
+U+01fa A # Character Ǻ
+U+01fb a # Character Ç»
+U+01fc AE # Character Ǽ
+U+01fd ae # Character ǽ
+U+01fe O # Character Ǿ
+U+01ff o # Character Ç¿
diff --git a/resources/chars/ascii/row02.trans b/resources/chars/ascii/row02.trans
new file mode 100644
index 0000000..a7e7af1
--- /dev/null
+++ b/resources/chars/ascii/row02.trans
@@ -0,0 +1,270 @@
+# This is table for transliterating characters in the range
+# from U+0200 to U+02ff
+#
+# The first column is the unicode character and the second
+# column is the transliteration of that character to ascii characters.
+# One or more characters can be used, for example for a character æ which
+# is a combined a and e you could write 'ae' (without the quotes) as the
+# transliteration.
+#
+# Any line can be deleted and will default to a '?' character
+
+# Created with the Text::Unidecode module of perl
+#
+
+U+0200 A # Character È
+U+0201 a # Character È
+U+0202 A # Character È
+U+0203 a # Character È
+U+0204 E # Character È
+U+0205 e # Character È
+U+0206 E # Character È
+U+0207 e # Character È
+U+0208 I # Character È
+U+0209 i # Character È
+U+020a I # Character È
+U+020b i # Character È
+U+020c O # Character È
+U+020d o # Character È
+U+020e O # Character È
+U+020f o # Character È
+U+0210 R # Character È
+U+0211 r # Character È
+U+0212 R # Character È
+U+0213 r # Character È
+U+0214 U # Character È
+U+0215 u # Character È
+U+0216 U # Character È
+U+0217 u # Character È
+U+0218 S # Character È
+U+0219 s # Character È
+U+021a T # Character È
+U+021b t # Character È
+U+021c Y # Character È
+U+021d y # Character È
+U+021e H # Character È
+U+021f h # Character È
+U+0220 ? # Character È
+U+0221 ? # Character È¡
+U+0222 OU # Character Ȣ
+U+0223 ou # Character ȣ
+U+0224 Z # Character Ȥ
+U+0225 z # Character ȥ
+U+0226 A # Character Ȧ
+U+0227 a # Character ȧ
+U+0228 E # Character Ȩ
+U+0229 e # Character È©
+U+022a O # Character Ȫ
+U+022b o # Character È«
+U+022c O # Character Ȭ
+U+022d o # Character È
+U+022e O # Character È®
+U+022f o # Character ȯ
+U+0230 O # Character È°
+U+0231 o # Character ȱ
+U+0232 Y # Character Ȳ
+U+0233 y # Character ȳ
+U+0234 ? # Character È´
+U+0235 ? # Character ȵ
+U+0236 ? # Character ȶ
+U+0237 ? # Character È·
+U+0238 ? # Character ȸ
+U+0239 ? # Character ȹ
+U+023a ? # Character Ⱥ
+U+023b ? # Character È»
+U+023c ? # Character ȼ
+U+023d ? # Character Ƚ
+U+023e ? # Character Ⱦ
+U+023f ? # Character È¿
+U+0240 ? # Character É
+U+0241 ? # Character É
+U+0242 ? # Character É
+U+0243 ? # Character É
+U+0244 ? # Character É
+U+0245 ? # Character É
+U+0246 ? # Character É
+U+0247 ? # Character É
+U+0248 ? # Character É
+U+0249 ? # Character É
+U+024a ? # Character É
+U+024b ? # Character É
+U+024c ? # Character É
+U+024d ? # Character É
+U+024e ? # Character É
+U+024f ? # Character É
+U+0250 a # Character É
+U+0251 a # Character É
+U+0252 a # Character É
+U+0253 b # Character É
+U+0254 o # Character É
+U+0255 c # Character É
+U+0256 d # Character É
+U+0257 d # Character É
+U+0258 e # Character É
+U+0259 @ # Character É
+U+025a @ # Character É
+U+025b e # Character É
+U+025c e # Character É
+U+025d e # Character É
+U+025e e # Character É
+U+025f j # Character É
+U+0260 g # Character É
+U+0261 g # Character É¡
+U+0262 g # Character ɢ
+U+0263 g # Character ɣ
+U+0264 u # Character ɤ
+U+0265 Y # Character ɥ
+U+0266 h # Character ɦ
+U+0267 h # Character ɧ
+U+0268 i # Character ɨ
+U+0269 i # Character É©
+U+026a I # Character ɪ
+U+026b l # Character É«
+U+026c l # Character ɬ
+U+026d l # Character É
+U+026e lZ # Character É®
+U+026f W # Character ɯ
+U+0270 W # Character É°
+U+0271 m # Character ɱ
+U+0272 n # Character ɲ
+U+0273 n # Character ɳ
+U+0274 n # Character É´
+U+0275 o # Character ɵ
+U+0276 OE # Character ɶ
+U+0277 O # Character É·
+U+0278 F # Character ɸ
+U+0279 R # Character ɹ
+U+027a R # Character ɺ
+U+027b R # Character É»
+U+027c R # Character ɼ
+U+027d r # Character ɽ
+U+027e r # Character ɾ
+U+027f R # Character É¿
+U+0280 R # Character Ê
+U+0281 R # Character Ê
+U+0282 s # Character Ê
+U+0283 S # Character Ê
+U+0284 j # Character Ê
+U+0285 S # Character Ê
+U+0286 S # Character Ê
+U+0287 t # Character Ê
+U+0288 t # Character Ê
+U+0289 U # Character Ê
+U+028a U # Character Ê
+U+028b v # Character Ê
+U+028c ^ # Character Ê
+U+028d W # Character Ê
+U+028e Y # Character Ê
+U+028f Y # Character Ê
+U+0290 z # Character Ê
+U+0291 z # Character Ê
+U+0292 Z # Character Ê
+U+0293 Z # Character Ê
+U+0294 ? # Character Ê
+U+0295 ? # Character Ê
+U+0296 ? # Character Ê
+U+0297 C # Character Ê
+U+0298 @ # Character Ê
+U+0299 B # Character Ê
+U+029a E # Character Ê
+U+029b G # Character Ê
+U+029c H # Character Ê
+U+029d j # Character Ê
+U+029e k # Character Ê
+U+029f L # Character Ê
+U+02a0 q # Character Ê
+U+02a1 ? # Character Ê¡
+U+02a2 ? # Character ʢ
+U+02a3 dz # Character ʣ
+U+02a4 dZ # Character ʤ
+U+02a5 dz # Character ʥ
+U+02a6 ts # Character ʦ
+U+02a7 tS # Character ʧ
+U+02a8 tC # Character ʨ
+U+02a9 fN # Character Ê©
+U+02aa ls # Character ʪ
+U+02ab lz # Character Ê«
+U+02ac WW # Character ʬ
+U+02ad ]] # Character Ê
+U+02ae ? # Character Ê®
+U+02af ? # Character ʯ
+U+02b0 k # Character Ê°
+U+02b1 h # Character ʱ
+U+02b2 j # Character ʲ
+U+02b3 r # Character ʳ
+U+02b4 r # Character Ê´
+U+02b5 r # Character ʵ
+U+02b6 r # Character ʶ
+U+02b7 w # Character Ê·
+U+02b8 y # Character ʸ
+U+02b9 ' # Character ʹ
+U+02ba " # Character ʺ
+U+02bb ` # Character Ê»
+U+02bc ' # Character ʼ
+U+02bd ` # Character ʽ
+U+02be ` # Character ʾ
+U+02bf ' # Character Ê¿
+U+02c0 ? # Character Ë
+U+02c1 ? # Character Ë
+U+02c2 < # Character Ë
+U+02c3 > # Character Ë
+U+02c4 ^ # Character Ë
+U+02c5 V # Character Ë
+U+02c6 ^ # Character Ë
+U+02c7 V # Character Ë
+U+02c8 ' # Character Ë
+U+02c9 - # Character Ë
+U+02ca / # Character Ë
+U+02cb \ # Character Ë
+U+02cc , # Character Ë
+U+02cd _ # Character Ë
+U+02ce \ # Character Ë
+U+02cf / # Character Ë
+U+02d0 : # Character Ë
+U+02d1 . # Character Ë
+U+02d2 ` # Character Ë
+U+02d3 ' # Character Ë
+U+02d4 ^ # Character Ë
+U+02d5 V # Character Ë
+U+02d6 + # Character Ë
+U+02d7 - # Character Ë
+U+02d8 V # Character Ë
+U+02d9 . # Character Ë
+U+02da @ # Character Ë
+U+02db , # Character Ë
+U+02dc ~ # Character Ë
+U+02dd " # Character Ë
+U+02de R # Character Ë
+U+02df X # Character Ë
+U+02e0 G # Character Ë
+U+02e1 l # Character Ë¡
+U+02e2 s # Character ˢ
+U+02e3 x # Character ˣ
+U+02e4 ? # Character ˤ
+U+02e5 ? # Character ˥
+U+02e6 ? # Character ˦
+U+02e7 ? # Character ˧
+U+02e8 ? # Character ˨
+U+02e9 ? # Character Ë©
+U+02ea ? # Character ˪
+U+02eb ? # Character Ë«
+U+02ec V # Character ˬ
+U+02ed = # Character Ë
+U+02ee " # Character Ë®
+U+02ef ? # Character ˯
+U+02f0 ? # Character Ë°
+U+02f1 ? # Character ˱
+U+02f2 ? # Character ˲
+U+02f3 ? # Character ˳
+U+02f4 ? # Character Ë´
+U+02f5 ? # Character ˵
+U+02f6 ? # Character ˶
+U+02f7 ? # Character Ë·
+U+02f8 ? # Character ˸
+U+02f9 ? # Character ˹
+U+02fa ? # Character ˺
+U+02fb ? # Character Ë»
+U+02fc ? # Character ˼
+U+02fd ? # Character ˽
+U+02fe ? # Character ˾
+U+02ff ? # Character Ë¿
diff --git a/resources/chars/ascii/row03.trans b/resources/chars/ascii/row03.trans
new file mode 100644
index 0000000..6ef0cdd
--- /dev/null
+++ b/resources/chars/ascii/row03.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+0300 ? # Character Ì
+U+0301 ? # Character Ì
+U+0302 ? # Character Ì
+U+0303 ? # Character Ì
+U+0304 ? # Character Ì
+U+0305 ? # Character Ì
+U+0306 ? # Character Ì
+U+0307 ? # Character Ì
+U+0308 ? # Character Ì
+U+0309 ? # Character Ì
+U+030a ? # Character Ì
+U+030b ? # Character Ì
+U+030c ? # Character Ì
+U+030d ? # Character Ì
+U+030e ? # Character Ì
+U+030f ? # Character Ì
+U+0310 ? # Character Ì
+U+0311 ? # Character Ì
+U+0312 ? # Character Ì
+U+0313 ? # Character Ì
+U+0314 ? # Character Ì
+U+0315 ? # Character Ì
+U+0316 ? # Character Ì
+U+0317 ? # Character Ì
+U+0318 ? # Character Ì
+U+0319 ? # Character Ì
+U+031a ? # Character Ì
+U+031b ? # Character Ì
+U+031c ? # Character Ì
+U+031d ? # Character Ì
+U+031e ? # Character Ì
+U+031f ? # Character Ì
+U+0320 ? # Character Ì
+U+0321 ? # Character Ì¡
+U+0322 ? # Character ̢
+U+0323 ? # Character ̣
+U+0324 ? # Character ̤
+U+0325 ? # Character ̥
+U+0326 ? # Character ̦
+U+0327 ? # Character ̧
+U+0328 ? # Character ̨
+U+0329 ? # Character Ì©
+U+032a ? # Character ̪
+U+032b ? # Character Ì«
+U+032c ? # Character ̬
+U+032d ? # Character Ì
+U+032e ? # Character Ì®
+U+032f ? # Character ̯
+U+0330 ? # Character Ì°
+U+0331 ? # Character ̱
+U+0332 ? # Character ̲
+U+0333 ? # Character ̳
+U+0334 ? # Character Ì´
+U+0335 ? # Character ̵
+U+0336 ? # Character ̶
+U+0337 ? # Character Ì·
+U+0338 ? # Character ̸
+U+0339 ? # Character ̹
+U+033a ? # Character ̺
+U+033b ? # Character Ì»
+U+033c ? # Character ̼
+U+033d ? # Character ̽
+U+033e ? # Character ̾
+U+033f ? # Character Ì¿
+U+0340 ? # Character Í
+U+0341 ? # Character Í
+U+0342 ? # Character Í
+U+0343 ? # Character Í
+U+0344 ? # Character Í
+U+0345 ? # Character Í
+U+0346 ? # Character Í
+U+0347 ? # Character Í
+U+0348 ? # Character Í
+U+0349 ? # Character Í
+U+034a ? # Character Í
+U+034b ? # Character Í
+U+034c ? # Character Í
+U+034d ? # Character Í
+U+034e ? # Character Í
+U+034f ? # Character Í
+U+0350 ? # Character Í
+U+0351 ? # Character Í
+U+0352 ? # Character Í
+U+0353 ? # Character Í
+U+0354 ? # Character Í
+U+0355 ? # Character Í
+U+0356 ? # Character Í
+U+0357 ? # Character Í
+U+0358 ? # Character Í
+U+0359 ? # Character Í
+U+035a ? # Character Í
+U+035b ? # Character Í
+U+035c ? # Character Í
+U+035d ? # Character Í
+U+035e ? # Character Í
+U+035f ? # Character Í
+U+0360 ? # Character Í
+U+0361 ? # Character Í¡
+U+0362 ? # Character ͢
+U+0363 ? # Character ͣ
+U+0364 ? # Character ͤ
+U+0365 ? # Character ͥ
+U+0366 ? # Character ͦ
+U+0367 ? # Character ͧ
+U+0368 ? # Character ͨ
+U+0369 ? # Character Í©
+U+036a ? # Character ͪ
+U+036b ? # Character Í«
+U+036c ? # Character ͬ
+U+036d ? # Character Í
+U+036e ? # Character Í®
+U+036f ? # Character ͯ
+U+0370 ? # Character Í°
+U+0371 ? # Character ͱ
+U+0372 ? # Character Ͳ
+U+0373 ? # Character ͳ
+U+0374 ' # Character Í´
+U+0375 , # Character ͵
+U+0376 ? # Character Ͷ
+U+0377 ? # Character Í·
+U+0378 ? # Character ͸
+U+0379 ? # Character ͹
+U+037a ? # Character ͺ
+U+037b ? # Character Í»
+U+037c ? # Character ͼ
+U+037d ? # Character ͽ
+U+037e ? # Character ;
+U+037f ? # Character Í¿
+U+0380 ? # Character Î
+U+0381 ? # Character Î
+U+0382 ? # Character Î
+U+0383 ? # Character Î
+U+0384 ? # Character Î
+U+0385 ? # Character Î
+U+0386 A # Character Î
+U+0387 ; # Character Î
+U+0388 E # Character Î
+U+0389 E # Character Î
+U+038a I # Character Î
+U+038b ? # Character Î
+U+038c O # Character Î
+U+038d ? # Character Î
+U+038e U # Character Î
+U+038f O # Character Î
+U+0390 I # Character Î
+U+0391 A # Character Î
+U+0392 B # Character Î
+U+0393 G # Character Î
+U+0394 D # Character Î
+U+0395 E # Character Î
+U+0396 Z # Character Î
+U+0397 E # Character Î
+U+0398 Th # Character Î
+U+0399 I # Character Î
+U+039a K # Character Î
+U+039b L # Character Î
+U+039c M # Character Î
+U+039d N # Character Î
+U+039e Ks # Character Î
+U+039f O # Character Î
+U+03a0 P # Character Î
+U+03a1 R # Character Ρ
+U+03a2 ? # Character ΢
+U+03a3 S # Character Σ
+U+03a4 T # Character Τ
+U+03a5 U # Character Υ
+U+03a6 Ph # Character Φ
+U+03a7 Kh # Character Χ
+U+03a8 Ps # Character Ψ
+U+03a9 O # Character Ω
+U+03aa I # Character Ϊ
+U+03ab U # Character Ϋ
+U+03ac a # Character ά
+U+03ad e # Character Î
+U+03ae e # Character ή
+U+03af i # Character ί
+U+03b0 u # Character ΰ
+U+03b1 a # Character α
+U+03b2 b # Character β
+U+03b3 g # Character γ
+U+03b4 d # Character δ
+U+03b5 e # Character ε
+U+03b6 z # Character ζ
+U+03b7 e # Character η
+U+03b8 th # Character θ
+U+03b9 i # Character ι
+U+03ba k # Character κ
+U+03bb l # Character λ
+U+03bc m # Character μ
+U+03bd n # Character ν
+U+03be x # Character ξ
+U+03bf o # Character ο
+U+03c0 p # Character Ï
+U+03c1 r # Character Ï
+U+03c2 s # Character Ï
+U+03c3 s # Character Ï
+U+03c4 t # Character Ï
+U+03c5 u # Character Ï
+U+03c6 ph # Character Ï
+U+03c7 kh # Character Ï
+U+03c8 ps # Character Ï
+U+03c9 o # Character Ï
+U+03ca i # Character Ï
+U+03cb u # Character Ï
+U+03cc o # Character Ï
+U+03cd u # Character Ï
+U+03ce o # Character Ï
+U+03cf ? # Character Ï
+U+03d0 b # Character Ï
+U+03d1 th # Character Ï
+U+03d2 U # Character Ï
+U+03d3 U # Character Ï
+U+03d4 U # Character Ï
+U+03d5 ph # Character Ï
+U+03d6 p # Character Ï
+U+03d7 & # Character Ï
+U+03d8 ? # Character Ï
+U+03d9 ? # Character Ï
+U+03da St # Character Ï
+U+03db st # Character Ï
+U+03dc W # Character Ï
+U+03dd w # Character Ï
+U+03de Q # Character Ï
+U+03df q # Character Ï
+U+03e0 Sp # Character Ï
+U+03e1 sp # Character Ï¡
+U+03e2 Sh # Character Ϣ
+U+03e3 sh # Character ϣ
+U+03e4 F # Character Ϥ
+U+03e5 f # Character ϥ
+U+03e6 Kh # Character Ϧ
+U+03e7 kh # Character ϧ
+U+03e8 H # Character Ϩ
+U+03e9 h # Character Ï©
+U+03ea G # Character Ϫ
+U+03eb g # Character Ï«
+U+03ec CH # Character Ϭ
+U+03ed ch # Character Ï
+U+03ee Ti # Character Ï®
+U+03ef ti # Character ϯ
+U+03f0 k # Character Ï°
+U+03f1 r # Character ϱ
+U+03f2 c # Character ϲ
+U+03f3 j # Character ϳ
+U+03f4 ? # Character Ï´
+U+03f5 ? # Character ϵ
+U+03f6 ? # Character ϶
+U+03f7 ? # Character Ï·
+U+03f8 ? # Character ϸ
+U+03f9 ? # Character Ϲ
+U+03fa ? # Character Ϻ
+U+03fb ? # Character Ï»
+U+03fc ? # Character ϼ
+U+03fd ? # Character Ͻ
+U+03fe ? # Character Ͼ
+U+03ff ? # Character Ï¿
diff --git a/resources/chars/ascii/row04.trans b/resources/chars/ascii/row04.trans
new file mode 100644
index 0000000..263a35b
--- /dev/null
+++ b/resources/chars/ascii/row04.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+0400 Ie # Character Ð
+U+0401 Io # Character Ð
+U+0402 Dj # Character Ð
+U+0403 Gj # Character Ð
+U+0404 Ie # Character Ð
+U+0405 Dz # Character Ð
+U+0406 I # Character Ð
+U+0407 Yi # Character Ð
+U+0408 J # Character Ð
+U+0409 Lj # Character Ð
+U+040a Nj # Character Ð
+U+040b Tsh # Character Ð
+U+040c Kj # Character Ð
+U+040d I # Character Ð
+U+040e U # Character Ð
+U+040f Dzh # Character Ð
+U+0410 A # Character Ð
+U+0411 B # Character Ð
+U+0412 V # Character Ð
+U+0413 G # Character Ð
+U+0414 D # Character Ð
+U+0415 Ie # Character Ð
+U+0416 Zh # Character Ð
+U+0417 Z # Character Ð
+U+0418 I # Character Ð
+U+0419 I # Character Ð
+U+041a K # Character Ð
+U+041b L # Character Ð
+U+041c M # Character Ð
+U+041d N # Character Ð
+U+041e O # Character Ð
+U+041f P # Character Ð
+U+0420 R # Character Ð
+U+0421 S # Character С
+U+0422 T # Character Т
+U+0423 U # Character У
+U+0424 F # Character Ф
+U+0425 Kh # Character Х
+U+0426 Ts # Character Ц
+U+0427 Ch # Character Ч
+U+0428 Sh # Character Ш
+U+0429 Shch # Character Щ
+U+042a ? # Character Ъ
+U+042b Y # Character Ы
+U+042c ' # Character Ь
+U+042d E # Character Ð
+U+042e Iu # Character Ю
+U+042f Ia # Character Я
+U+0430 a # Character а
+U+0431 b # Character б
+U+0432 v # Character в
+U+0433 gh # Character г
+U+0434 d # Character д
+U+0435 ie # Character е
+U+0436 zh # Character ж
+U+0437 z # Character з
+U+0438 i # Character и
+U+0439 i # Character й
+U+043a k # Character к
+U+043b l # Character л
+U+043c m # Character м
+U+043d n # Character н
+U+043e o # Character о
+U+043f p # Character п
+U+0440 r # Character Ñ
+U+0441 s # Character Ñ
+U+0442 t # Character Ñ
+U+0443 u # Character Ñ
+U+0444 f # Character Ñ
+U+0445 kh # Character Ñ
+U+0446 ts # Character Ñ
+U+0447 ch # Character Ñ
+U+0448 sh # Character Ñ
+U+0449 shch # Character Ñ
+U+044a ? # Character Ñ
+U+044b y # Character Ñ
+U+044c ' # Character Ñ
+U+044d e # Character Ñ
+U+044e iu # Character Ñ
+U+044f ia # Character Ñ
+U+0450 ie # Character Ñ
+U+0451 io # Character Ñ
+U+0452 dj # Character Ñ
+U+0453 gj # Character Ñ
+U+0454 ie # Character Ñ
+U+0455 dz # Character Ñ
+U+0456 i # Character Ñ
+U+0457 yi # Character Ñ
+U+0458 j # Character Ñ
+U+0459 lj # Character Ñ
+U+045a nj # Character Ñ
+U+045b tsh # Character Ñ
+U+045c kj # Character Ñ
+U+045d i # Character Ñ
+U+045e u # Character Ñ
+U+045f dzh # Character Ñ
+U+0460 O # Character Ñ
+U+0461 o # Character Ñ¡
+U+0462 E # Character Ѣ
+U+0463 e # Character ѣ
+U+0464 Ie # Character Ѥ
+U+0465 ie # Character ѥ
+U+0466 E # Character Ѧ
+U+0467 e # Character ѧ
+U+0468 Ie # Character Ѩ
+U+0469 ie # Character Ñ©
+U+046a O # Character Ѫ
+U+046b o # Character Ñ«
+U+046c Io # Character Ѭ
+U+046d io # Character Ñ
+U+046e Ks # Character Ñ®
+U+046f ks # Character ѯ
+U+0470 Ps # Character Ñ°
+U+0471 ps # Character ѱ
+U+0472 F # Character Ѳ
+U+0473 f # Character ѳ
+U+0474 Y # Character Ñ´
+U+0475 y # Character ѵ
+U+0476 Y # Character Ѷ
+U+0477 y # Character Ñ·
+U+0478 u # Character Ѹ
+U+0479 u # Character ѹ
+U+047a O # Character Ѻ
+U+047b o # Character Ñ»
+U+047c O # Character Ѽ
+U+047d o # Character ѽ
+U+047e Ot # Character Ѿ
+U+047f ot # Character Ñ¿
+U+0480 Q # Character Ò
+U+0481 q # Character Ò
+U+0482 *1000* # Character Ò
+U+0483 ? # Character Ò
+U+0484 ? # Character Ò
+U+0485 ? # Character Ò
+U+0486 ? # Character Ò
+U+0487 ? # Character Ò
+U+0488 *100.000* # Character Ò
+U+0489 *1.000.000* # Character Ò
+U+048a ? # Character Ò
+U+048b ? # Character Ò
+U+048c " # Character Ò
+U+048d " # Character Ò
+U+048e R' # Character Ò
+U+048f r' # Character Ò
+U+0490 G' # Character Ò
+U+0491 g' # Character Ò
+U+0492 G' # Character Ò
+U+0493 g' # Character Ò
+U+0494 G' # Character Ò
+U+0495 g' # Character Ò
+U+0496 Zh' # Character Ò
+U+0497 zh' # Character Ò
+U+0498 Z' # Character Ò
+U+0499 z' # Character Ò
+U+049a K' # Character Ò
+U+049b k' # Character Ò
+U+049c K' # Character Ò
+U+049d k' # Character Ò
+U+049e K' # Character Ò
+U+049f k' # Character Ò
+U+04a0 K' # Character Ò
+U+04a1 k' # Character Ò¡
+U+04a2 N' # Character Ò¢
+U+04a3 n' # Character Ò£
+U+04a4 Ng # Character Ò¤
+U+04a5 ng # Character Ò¥
+U+04a6 P' # Character Ò¦
+U+04a7 p' # Character Ò§
+U+04a8 Kh # Character Ò¨
+U+04a9 kh # Character Ò©
+U+04aa S' # Character Òª
+U+04ab s' # Character Ò«
+U+04ac T' # Character Ò¬
+U+04ad t' # Character Ò
+U+04ae U # Character Ò®
+U+04af u # Character Ò¯
+U+04b0 U' # Character Ò°
+U+04b1 u' # Character Ò±
+U+04b2 Kh' # Character Ò²
+U+04b3 kh' # Character Ò³
+U+04b4 Tts # Character Ò´
+U+04b5 tts # Character Òµ
+U+04b6 Ch' # Character Ò¶
+U+04b7 ch' # Character Ò·
+U+04b8 Ch' # Character Ò¸
+U+04b9 ch' # Character Ò¹
+U+04ba H # Character Òº
+U+04bb h # Character Ò»
+U+04bc Ch # Character Ò¼
+U+04bd ch # Character Ò½
+U+04be Ch' # Character Ò¾
+U+04bf ch' # Character Ò¿
+U+04c0 ` # Character Ó
+U+04c1 Zh # Character Ó
+U+04c2 zh # Character Ó
+U+04c3 K' # Character Ó
+U+04c4 k' # Character Ó
+U+04c5 ? # Character Ó
+U+04c6 ? # Character Ó
+U+04c7 N' # Character Ó
+U+04c8 n' # Character Ó
+U+04c9 ? # Character Ó
+U+04ca ? # Character Ó
+U+04cb Ch # Character Ó
+U+04cc ch # Character Ó
+U+04cd ? # Character Ó
+U+04ce ? # Character Ó
+U+04cf ? # Character Ó
+U+04d0 a # Character Ó
+U+04d1 a # Character Ó
+U+04d2 A # Character Ó
+U+04d3 a # Character Ó
+U+04d4 Ae # Character Ó
+U+04d5 ae # Character Ó
+U+04d6 Ie # Character Ó
+U+04d7 ie # Character Ó
+U+04d8 @ # Character Ó
+U+04d9 @ # Character Ó
+U+04da @ # Character Ó
+U+04db @ # Character Ó
+U+04dc Zh # Character Ó
+U+04dd zh # Character Ó
+U+04de Z # Character Ó
+U+04df z # Character Ó
+U+04e0 Dz # Character Ó
+U+04e1 dz # Character Ó¡
+U+04e2 I # Character Ó¢
+U+04e3 i # Character Ó£
+U+04e4 I # Character Ó¤
+U+04e5 i # Character Ó¥
+U+04e6 O # Character Ó¦
+U+04e7 o # Character Ó§
+U+04e8 O # Character Ó¨
+U+04e9 o # Character Ó©
+U+04ea O # Character Óª
+U+04eb o # Character Ó«
+U+04ec E # Character Ó¬
+U+04ed e # Character Ó
+U+04ee U # Character Ó®
+U+04ef u # Character Ó¯
+U+04f0 U # Character Ó°
+U+04f1 u # Character Ó±
+U+04f2 U # Character Ó²
+U+04f3 u # Character Ó³
+U+04f4 Ch # Character Ó´
+U+04f5 ch # Character Óµ
+U+04f6 ? # Character Ó¶
+U+04f7 ? # Character Ó·
+U+04f8 Y # Character Ó¸
+U+04f9 y # Character Ó¹
+U+04fa ? # Character Óº
+U+04fb ? # Character Ó»
+U+04fc ? # Character Ó¼
+U+04fd ? # Character Ó½
+U+04fe ? # Character Ó¾
+U+04ff ? # Character Ó¿
diff --git a/resources/chars/ascii/row05.trans b/resources/chars/ascii/row05.trans
new file mode 100644
index 0000000..cc3a40b
--- /dev/null
+++ b/resources/chars/ascii/row05.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+0500 ? # Character Ô
+U+0501 ? # Character Ô
+U+0502 ? # Character Ô
+U+0503 ? # Character Ô
+U+0504 ? # Character Ô
+U+0505 ? # Character Ô
+U+0506 ? # Character Ô
+U+0507 ? # Character Ô
+U+0508 ? # Character Ô
+U+0509 ? # Character Ô
+U+050a ? # Character Ô
+U+050b ? # Character Ô
+U+050c ? # Character Ô
+U+050d ? # Character Ô
+U+050e ? # Character Ô
+U+050f ? # Character Ô
+U+0510 ? # Character Ô
+U+0511 ? # Character Ô
+U+0512 ? # Character Ô
+U+0513 ? # Character Ô
+U+0514 ? # Character Ô
+U+0515 ? # Character Ô
+U+0516 ? # Character Ô
+U+0517 ? # Character Ô
+U+0518 ? # Character Ô
+U+0519 ? # Character Ô
+U+051a ? # Character Ô
+U+051b ? # Character Ô
+U+051c ? # Character Ô
+U+051d ? # Character Ô
+U+051e ? # Character Ô
+U+051f ? # Character Ô
+U+0520 ? # Character Ô
+U+0521 ? # Character Ô¡
+U+0522 ? # Character Ô¢
+U+0523 ? # Character Ô£
+U+0524 ? # Character Ô¤
+U+0525 ? # Character Ô¥
+U+0526 ? # Character Ô¦
+U+0527 ? # Character Ô§
+U+0528 ? # Character Ô¨
+U+0529 ? # Character Ô©
+U+052a ? # Character Ôª
+U+052b ? # Character Ô«
+U+052c ? # Character Ô¬
+U+052d ? # Character Ô
+U+052e ? # Character Ô®
+U+052f ? # Character Ô¯
+U+0530 ? # Character Ô°
+U+0531 A # Character Ô±
+U+0532 B # Character Ô²
+U+0533 G # Character Ô³
+U+0534 D # Character Ô´
+U+0535 E # Character Ôµ
+U+0536 Z # Character Ô¶
+U+0537 E # Character Ô·
+U+0538 E # Character Ô¸
+U+0539 T` # Character Ô¹
+U+053a Zh # Character Ôº
+U+053b I # Character Ô»
+U+053c L # Character Ô¼
+U+053d Kh # Character Ô½
+U+053e Ts # Character Ô¾
+U+053f K # Character Ô¿
+U+0540 H # Character Õ
+U+0541 Dz # Character Õ
+U+0542 Gh # Character Õ
+U+0543 Ch # Character Õ
+U+0544 M # Character Õ
+U+0545 Y # Character Õ
+U+0546 N # Character Õ
+U+0547 Sh # Character Õ
+U+0548 O # Character Õ
+U+0549 Ch` # Character Õ
+U+054a P # Character Õ
+U+054b J # Character Õ
+U+054c Rh # Character Õ
+U+054d S # Character Õ
+U+054e V # Character Õ
+U+054f T # Character Õ
+U+0550 R # Character Õ
+U+0551 Ts` # Character Õ
+U+0552 W # Character Õ
+U+0553 P` # Character Õ
+U+0554 K` # Character Õ
+U+0555 O # Character Õ
+U+0556 F # Character Õ
+U+0557 ? # Character Õ
+U+0558 ? # Character Õ
+U+0559 < # Character Õ
+U+055a ' # Character Õ
+U+055b / # Character Õ
+U+055c ! # Character Õ
+U+055d , # Character Õ
+U+055e ? # Character Õ
+U+055f . # Character Õ
+U+0560 ? # Character Õ
+U+0561 a # Character Õ¡
+U+0562 b # Character Õ¢
+U+0563 g # Character Õ£
+U+0564 d # Character Õ¤
+U+0565 e # Character Õ¥
+U+0566 z # Character Õ¦
+U+0567 e # Character Õ§
+U+0568 e # Character Õ¨
+U+0569 t` # Character Õ©
+U+056a zh # Character Õª
+U+056b i # Character Õ«
+U+056c l # Character Õ¬
+U+056d kh # Character Õ
+U+056e ts # Character Õ®
+U+056f k # Character Õ¯
+U+0570 h # Character Õ°
+U+0571 dz # Character Õ±
+U+0572 gh # Character Õ²
+U+0573 ch # Character Õ³
+U+0574 m # Character Õ´
+U+0575 y # Character Õµ
+U+0576 n # Character Õ¶
+U+0577 sh # Character Õ·
+U+0578 o # Character Õ¸
+U+0579 ch` # Character Õ¹
+U+057a p # Character Õº
+U+057b j # Character Õ»
+U+057c rh # Character Õ¼
+U+057d s # Character Õ½
+U+057e v # Character Õ¾
+U+057f t # Character Õ¿
+U+0580 r # Character Ö
+U+0581 ts` # Character Ö
+U+0582 w # Character Ö
+U+0583 p` # Character Ö
+U+0584 k` # Character Ö
+U+0585 o # Character Ö
+U+0586 f # Character Ö
+U+0587 ew # Character Ö
+U+0588 ? # Character Ö
+U+0589 . # Character Ö
+U+058a - # Character Ö
+U+058b ? # Character Ö
+U+058c ? # Character Ö
+U+058d ? # Character Ö
+U+058e ? # Character Ö
+U+058f ? # Character Ö
+U+0590 ? # Character Ö
+U+0591 ? # Character Ö
+U+0592 ? # Character Ö
+U+0593 ? # Character Ö
+U+0594 ? # Character Ö
+U+0595 ? # Character Ö
+U+0596 ? # Character Ö
+U+0597 ? # Character Ö
+U+0598 ? # Character Ö
+U+0599 ? # Character Ö
+U+059a ? # Character Ö
+U+059b ? # Character Ö
+U+059c ? # Character Ö
+U+059d ? # Character Ö
+U+059e ? # Character Ö
+U+059f ? # Character Ö
+U+05a0 ? # Character Ö
+U+05a1 ? # Character Ö¡
+U+05a2 ? # Character Ö¢
+U+05a3 ? # Character Ö£
+U+05a4 ? # Character Ö¤
+U+05a5 ? # Character Ö¥
+U+05a6 ? # Character Ö¦
+U+05a7 ? # Character Ö§
+U+05a8 ? # Character Ö¨
+U+05a9 ? # Character Ö©
+U+05aa ? # Character Öª
+U+05ab ? # Character Ö«
+U+05ac ? # Character Ö¬
+U+05ad ? # Character Ö
+U+05ae ? # Character Ö®
+U+05af ? # Character Ö¯
+U+05b0 @ # Character Ö°
+U+05b1 e # Character Ö±
+U+05b2 a # Character Ö²
+U+05b3 o # Character Ö³
+U+05b4 i # Character Ö´
+U+05b5 e # Character Öµ
+U+05b6 e # Character Ö¶
+U+05b7 a # Character Ö·
+U+05b8 a # Character Ö¸
+U+05b9 o # Character Ö¹
+U+05ba ? # Character Öº
+U+05bb u # Character Ö»
+U+05bc ' # Character Ö¼
+U+05bd ? # Character Ö½
+U+05be ? # Character Ö¾
+U+05bf ? # Character Ö¿
+U+05c0 ? # Character ×
+U+05c1 ? # Character ×
+U+05c2 ? # Character ×
+U+05c3 : # Character ×
+U+05c4 ? # Character ×
+U+05c5 ? # Character ×
+U+05c6 ? # Character ×
+U+05c7 ? # Character ×
+U+05c8 ? # Character ×
+U+05c9 ? # Character ×
+U+05ca ? # Character ×
+U+05cb ? # Character ×
+U+05cc ? # Character ×
+U+05cd ? # Character ×
+U+05ce ? # Character ×
+U+05cf ? # Character ×
+U+05d0 ? # Character ×
+U+05d1 b # Character ×
+U+05d2 g # Character ×
+U+05d3 d # Character ×
+U+05d4 h # Character ×
+U+05d5 v # Character ×
+U+05d6 z # Character ×
+U+05d7 kh # Character ×
+U+05d8 t # Character ×
+U+05d9 y # Character ×
+U+05da k # Character ×
+U+05db k # Character ×
+U+05dc l # Character ×
+U+05dd m # Character ×
+U+05de m # Character ×
+U+05df n # Character ×
+U+05e0 n # Character ×
+U+05e1 s # Character ס
+U+05e2 ` # Character ×¢
+U+05e3 p # Character ×£
+U+05e4 p # Character פ
+U+05e5 ts # Character ×¥
+U+05e6 ts # Character צ
+U+05e7 q # Character ק
+U+05e8 r # Character ר
+U+05e9 sh # Character ש
+U+05ea t # Character ת
+U+05eb ? # Character ׫
+U+05ec ? # Character ׬
+U+05ed ? # Character ×
+U+05ee ? # Character ×®
+U+05ef ? # Character ׯ
+U+05f0 V # Character ×°
+U+05f1 oy # Character ×±
+U+05f2 i # Character ײ
+U+05f3 ' # Character ׳
+U+05f4 " # Character ×´
+U+05f5 ? # Character ×µ
+U+05f6 ? # Character ׶
+U+05f7 ? # Character ×·
+U+05f8 ? # Character ׸
+U+05f9 ? # Character ×¹
+U+05fa ? # Character ׺
+U+05fb ? # Character ×»
+U+05fc ? # Character ×¼
+U+05fd ? # Character ×½
+U+05fe ? # Character ×¾
+U+05ff ? # Character ׿
diff --git a/resources/chars/ascii/row06.trans b/resources/chars/ascii/row06.trans
new file mode 100644
index 0000000..8add30c
--- /dev/null
+++ b/resources/chars/ascii/row06.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+0600 ? # Character Ø
+U+0601 ? # Character Ø
+U+0602 ? # Character Ø
+U+0603 ? # Character Ø
+U+0604 ? # Character Ø
+U+0605 ? # Character Ø
+U+0606 ? # Character Ø
+U+0607 ? # Character Ø
+U+0608 ? # Character Ø
+U+0609 ? # Character Ø
+U+060a ? # Character Ø
+U+060b ? # Character Ø
+U+060c , # Character Ø
+U+060d ? # Character Ø
+U+060e ? # Character Ø
+U+060f ? # Character Ø
+U+0610 ? # Character Ø
+U+0611 ? # Character Ø
+U+0612 ? # Character Ø
+U+0613 ? # Character Ø
+U+0614 ? # Character Ø
+U+0615 ? # Character Ø
+U+0616 ? # Character Ø
+U+0617 ? # Character Ø
+U+0618 ? # Character Ø
+U+0619 ? # Character Ø
+U+061a ? # Character Ø
+U+061b ; # Character Ø
+U+061c ? # Character Ø
+U+061d ? # Character Ø
+U+061e ? # Character Ø
+U+061f ? # Character Ø
+U+0620 ? # Character Ø
+U+0621 ? # Character Ø¡
+U+0622 a # Character آ
+U+0623 ' # Character أ
+U+0624 w' # Character ؤ
+U+0625 ? # Character إ
+U+0626 y' # Character ئ
+U+0627 ? # Character ا
+U+0628 b # Character ب
+U+0629 @ # Character Ø©
+U+062a t # Character ت
+U+062b th # Character Ø«
+U+062c j # Character ج
+U+062d H # Character Ø
+U+062e kh # Character Ø®
+U+062f d # Character د
+U+0630 dh # Character Ø°
+U+0631 r # Character ر
+U+0632 z # Character ز
+U+0633 s # Character س
+U+0634 sh # Character Ø´
+U+0635 S # Character ص
+U+0636 D # Character ض
+U+0637 T # Character Ø·
+U+0638 Z # Character ظ
+U+0639 ` # Character ع
+U+063a G # Character غ
+U+063b ? # Character Ø»
+U+063c ? # Character ؼ
+U+063d ? # Character ؽ
+U+063e ? # Character ؾ
+U+063f ? # Character Ø¿
+U+0640 ? # Character Ù
+U+0641 f # Character Ù
+U+0642 q # Character Ù
+U+0643 k # Character Ù
+U+0644 l # Character Ù
+U+0645 m # Character Ù
+U+0646 n # Character Ù
+U+0647 h # Character Ù
+U+0648 w # Character Ù
+U+0649 ~ # Character Ù
+U+064a y # Character Ù
+U+064b an # Character Ù
+U+064c un # Character Ù
+U+064d in # Character Ù
+U+064e a # Character Ù
+U+064f u # Character Ù
+U+0650 i # Character Ù
+U+0651 W # Character Ù
+U+0652 ? # Character Ù
+U+0653 ? # Character Ù
+U+0654 ' # Character Ù
+U+0655 ' # Character Ù
+U+0656 ? # Character Ù
+U+0657 ? # Character Ù
+U+0658 ? # Character Ù
+U+0659 ? # Character Ù
+U+065a ? # Character Ù
+U+065b ? # Character Ù
+U+065c ? # Character Ù
+U+065d ? # Character Ù
+U+065e ? # Character Ù
+U+065f ? # Character Ù
+U+0660 ? # Character Ù
+U+0661 1 # Character Ù¡
+U+0662 2 # Character Ù¢
+U+0663 3 # Character Ù£
+U+0664 4 # Character Ù¤
+U+0665 5 # Character Ù¥
+U+0666 6 # Character Ù¦
+U+0667 7 # Character Ù§
+U+0668 8 # Character Ù¨
+U+0669 9 # Character Ù©
+U+066a % # Character Ùª
+U+066b . # Character Ù«
+U+066c , # Character Ù¬
+U+066d * # Character Ù
+U+066e ? # Character Ù®
+U+066f ? # Character Ù¯
+U+0670 ? # Character Ù°
+U+0671 ' # Character Ù±
+U+0672 ' # Character Ù²
+U+0673 ' # Character Ù³
+U+0674 ? # Character Ù´
+U+0675 ' # Character Ùµ
+U+0676 'w # Character Ù¶
+U+0677 'u # Character Ù·
+U+0678 'y # Character Ù¸
+U+0679 tt # Character Ù¹
+U+067a tth # Character Ùº
+U+067b b # Character Ù»
+U+067c t # Character Ù¼
+U+067d T # Character Ù½
+U+067e p # Character Ù¾
+U+067f th # Character Ù¿
+U+0680 bh # Character Ú
+U+0681 'h # Character Ú
+U+0682 H # Character Ú
+U+0683 ny # Character Ú
+U+0684 dy # Character Ú
+U+0685 H # Character Ú
+U+0686 ch # Character Ú
+U+0687 cch # Character Ú
+U+0688 dd # Character Ú
+U+0689 D # Character Ú
+U+068a D # Character Ú
+U+068b Dt # Character Ú
+U+068c dh # Character Ú
+U+068d ddh # Character Ú
+U+068e d # Character Ú
+U+068f D # Character Ú
+U+0690 D # Character Ú
+U+0691 rr # Character Ú
+U+0692 R # Character Ú
+U+0693 R # Character Ú
+U+0694 R # Character Ú
+U+0695 R # Character Ú
+U+0696 R # Character Ú
+U+0697 R # Character Ú
+U+0698 j # Character Ú
+U+0699 R # Character Ú
+U+069a S # Character Ú
+U+069b S # Character Ú
+U+069c S # Character Ú
+U+069d S # Character Ú
+U+069e S # Character Ú
+U+069f T # Character Ú
+U+06a0 GH # Character Ú
+U+06a1 F # Character Ú¡
+U+06a2 F # Character Ú¢
+U+06a3 F # Character Ú£
+U+06a4 v # Character Ú¤
+U+06a5 f # Character Ú¥
+U+06a6 ph # Character Ú¦
+U+06a7 Q # Character Ú§
+U+06a8 Q # Character Ú¨
+U+06a9 kh # Character Ú©
+U+06aa k # Character Úª
+U+06ab K # Character Ú«
+U+06ac K # Character Ú¬
+U+06ad ng # Character Ú
+U+06ae K # Character Ú®
+U+06af g # Character Ú¯
+U+06b0 G # Character Ú°
+U+06b1 N # Character Ú±
+U+06b2 G # Character Ú²
+U+06b3 G # Character Ú³
+U+06b4 G # Character Ú´
+U+06b5 L # Character Úµ
+U+06b6 L # Character Ú¶
+U+06b7 L # Character Ú·
+U+06b8 L # Character Ú¸
+U+06b9 N # Character Ú¹
+U+06ba N # Character Úº
+U+06bb N # Character Ú»
+U+06bc N # Character Ú¼
+U+06bd N # Character Ú½
+U+06be h # Character Ú¾
+U+06bf Ch # Character Ú¿
+U+06c0 hy # Character Û
+U+06c1 h # Character Û
+U+06c2 H # Character Û
+U+06c3 @ # Character Û
+U+06c4 W # Character Û
+U+06c5 oe # Character Û
+U+06c6 oe # Character Û
+U+06c7 u # Character Û
+U+06c8 yu # Character Û
+U+06c9 yu # Character Û
+U+06ca W # Character Û
+U+06cb v # Character Û
+U+06cc y # Character Û
+U+06cd Y # Character Û
+U+06ce Y # Character Û
+U+06cf W # Character Û
+U+06d0 ? # Character Û
+U+06d1 ? # Character Û
+U+06d2 y # Character Û
+U+06d3 y' # Character Û
+U+06d4 . # Character Û
+U+06d5 ae # Character Û
+U+06d6 ? # Character Û
+U+06d7 ? # Character Û
+U+06d8 ? # Character Û
+U+06d9 ? # Character Û
+U+06da ? # Character Û
+U+06db ? # Character Û
+U+06dc ? # Character Û
+U+06dd @ # Character Û
+U+06de # # Character Û
+U+06df ? # Character Û
+U+06e0 ? # Character Û
+U+06e1 ? # Character Û¡
+U+06e2 ? # Character Û¢
+U+06e3 ? # Character Û£
+U+06e4 ? # Character Û¤
+U+06e5 ? # Character Û¥
+U+06e6 ? # Character Û¦
+U+06e7 ? # Character Û§
+U+06e8 ? # Character Û¨
+U+06e9 ^ # Character Û©
+U+06ea ? # Character Ûª
+U+06eb ? # Character Û«
+U+06ec ? # Character Û¬
+U+06ed ? # Character Û
+U+06ee ? # Character Û®
+U+06ef ? # Character Û¯
+U+06f0 ? # Character Û°
+U+06f1 1 # Character Û±
+U+06f2 2 # Character Û²
+U+06f3 3 # Character Û³
+U+06f4 4 # Character Û´
+U+06f5 5 # Character Ûµ
+U+06f6 6 # Character Û¶
+U+06f7 7 # Character Û·
+U+06f8 8 # Character Û¸
+U+06f9 9 # Character Û¹
+U+06fa Sh # Character Ûº
+U+06fb D # Character Û»
+U+06fc Gh # Character Û¼
+U+06fd & # Character Û½
+U+06fe +m # Character Û¾
+U+06ff ? # Character Û¿
diff --git a/resources/chars/ascii/row07.trans b/resources/chars/ascii/row07.trans
new file mode 100644
index 0000000..a32de20
--- /dev/null
+++ b/resources/chars/ascii/row07.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+0700 // # Character Ü
+U+0701 / # Character Ü
+U+0702 , # Character Ü
+U+0703 ! # Character Ü
+U+0704 ! # Character Ü
+U+0705 - # Character Ü
+U+0706 , # Character Ü
+U+0707 , # Character Ü
+U+0708 ; # Character Ü
+U+0709 ? # Character Ü
+U+070a ~ # Character Ü
+U+070b { # Character Ü
+U+070c } # Character Ü
+U+070d * # Character Ü
+U+070e ? # Character Ü
+U+070f ? # Character Ü
+U+0710 ' # Character Ü
+U+0711 ? # Character Ü
+U+0712 b # Character Ü
+U+0713 g # Character Ü
+U+0714 g # Character Ü
+U+0715 d # Character Ü
+U+0716 d # Character Ü
+U+0717 h # Character Ü
+U+0718 w # Character Ü
+U+0719 z # Character Ü
+U+071a H # Character Ü
+U+071b t # Character Ü
+U+071c t # Character Ü
+U+071d y # Character Ü
+U+071e yh # Character Ü
+U+071f k # Character Ü
+U+0720 l # Character Ü
+U+0721 m # Character Ü¡
+U+0722 n # Character ܢ
+U+0723 s # Character ܣ
+U+0724 s # Character ܤ
+U+0725 ` # Character ܥ
+U+0726 p # Character ܦ
+U+0727 p # Character ܧ
+U+0728 S # Character ܨ
+U+0729 q # Character Ü©
+U+072a r # Character ܪ
+U+072b sh # Character Ü«
+U+072c t # Character ܬ
+U+072d ? # Character Ü
+U+072e ? # Character Ü®
+U+072f ? # Character ܯ
+U+0730 a # Character Ü°
+U+0731 a # Character ܱ
+U+0732 a # Character ܲ
+U+0733 A # Character ܳ
+U+0734 A # Character Ü´
+U+0735 A # Character ܵ
+U+0736 e # Character ܶ
+U+0737 e # Character Ü·
+U+0738 e # Character ܸ
+U+0739 E # Character ܹ
+U+073a i # Character ܺ
+U+073b i # Character Ü»
+U+073c u # Character ܼ
+U+073d u # Character ܽ
+U+073e u # Character ܾ
+U+073f o # Character Ü¿
+U+0740 ? # Character Ý
+U+0741 ` # Character Ý
+U+0742 ' # Character Ý
+U+0743 ? # Character Ý
+U+0744 ? # Character Ý
+U+0745 X # Character Ý
+U+0746 Q # Character Ý
+U+0747 @ # Character Ý
+U+0748 @ # Character Ý
+U+0749 | # Character Ý
+U+074a + # Character Ý
+U+074b ? # Character Ý
+U+074c ? # Character Ý
+U+074d ? # Character Ý
+U+074e ? # Character Ý
+U+074f ? # Character Ý
+U+0750 ? # Character Ý
+U+0751 ? # Character Ý
+U+0752 ? # Character Ý
+U+0753 ? # Character Ý
+U+0754 ? # Character Ý
+U+0755 ? # Character Ý
+U+0756 ? # Character Ý
+U+0757 ? # Character Ý
+U+0758 ? # Character Ý
+U+0759 ? # Character Ý
+U+075a ? # Character Ý
+U+075b ? # Character Ý
+U+075c ? # Character Ý
+U+075d ? # Character Ý
+U+075e ? # Character Ý
+U+075f ? # Character Ý
+U+0760 ? # Character Ý
+U+0761 ? # Character Ý¡
+U+0762 ? # Character ݢ
+U+0763 ? # Character ݣ
+U+0764 ? # Character ݤ
+U+0765 ? # Character ݥ
+U+0766 ? # Character ݦ
+U+0767 ? # Character ݧ
+U+0768 ? # Character ݨ
+U+0769 ? # Character Ý©
+U+076a ? # Character ݪ
+U+076b ? # Character Ý«
+U+076c ? # Character ݬ
+U+076d ? # Character Ý
+U+076e ? # Character Ý®
+U+076f ? # Character ݯ
+U+0770 ? # Character Ý°
+U+0771 ? # Character ݱ
+U+0772 ? # Character ݲ
+U+0773 ? # Character ݳ
+U+0774 ? # Character Ý´
+U+0775 ? # Character ݵ
+U+0776 ? # Character ݶ
+U+0777 ? # Character Ý·
+U+0778 ? # Character ݸ
+U+0779 ? # Character ݹ
+U+077a ? # Character ݺ
+U+077b ? # Character Ý»
+U+077c ? # Character ݼ
+U+077d ? # Character ݽ
+U+077e ? # Character ݾ
+U+077f ? # Character Ý¿
+U+0780 h # Character Þ
+U+0781 sh # Character Þ
+U+0782 n # Character Þ
+U+0783 r # Character Þ
+U+0784 b # Character Þ
+U+0785 L # Character Þ
+U+0786 k # Character Þ
+U+0787 ' # Character Þ
+U+0788 v # Character Þ
+U+0789 m # Character Þ
+U+078a f # Character Þ
+U+078b dh # Character Þ
+U+078c th # Character Þ
+U+078d l # Character Þ
+U+078e g # Character Þ
+U+078f ny # Character Þ
+U+0790 s # Character Þ
+U+0791 d # Character Þ
+U+0792 z # Character Þ
+U+0793 t # Character Þ
+U+0794 y # Character Þ
+U+0795 p # Character Þ
+U+0796 j # Character Þ
+U+0797 ch # Character Þ
+U+0798 tt # Character Þ
+U+0799 hh # Character Þ
+U+079a kh # Character Þ
+U+079b th # Character Þ
+U+079c z # Character Þ
+U+079d sh # Character Þ
+U+079e s # Character Þ
+U+079f d # Character Þ
+U+07a0 t # Character Þ
+U+07a1 z # Character Þ¡
+U+07a2 ` # Character Þ¢
+U+07a3 gh # Character Þ£
+U+07a4 q # Character Þ¤
+U+07a5 w # Character Þ¥
+U+07a6 a # Character Þ¦
+U+07a7 aa # Character Þ§
+U+07a8 i # Character Þ¨
+U+07a9 ee # Character Þ©
+U+07aa u # Character Þª
+U+07ab oo # Character Þ«
+U+07ac e # Character Þ¬
+U+07ad ey # Character Þ
+U+07ae o # Character Þ®
+U+07af oa # Character Þ¯
+U+07b0 ? # Character Þ°
+U+07b1 ? # Character Þ±
+U+07b2 ? # Character Þ²
+U+07b3 ? # Character Þ³
+U+07b4 ? # Character Þ´
+U+07b5 ? # Character Þµ
+U+07b6 ? # Character Þ¶
+U+07b7 ? # Character Þ·
+U+07b8 ? # Character Þ¸
+U+07b9 ? # Character Þ¹
+U+07ba ? # Character Þº
+U+07bb ? # Character Þ»
+U+07bc ? # Character Þ¼
+U+07bd ? # Character Þ½
+U+07be ? # Character Þ¾
+U+07bf ? # Character Þ¿
+U+07c0 ? # Character ß
+U+07c1 ? # Character ß
+U+07c2 ? # Character ß
+U+07c3 ? # Character ß
+U+07c4 ? # Character ß
+U+07c5 ? # Character ß
+U+07c6 ? # Character ß
+U+07c7 ? # Character ß
+U+07c8 ? # Character ß
+U+07c9 ? # Character ß
+U+07ca ? # Character ß
+U+07cb ? # Character ß
+U+07cc ? # Character ß
+U+07cd ? # Character ß
+U+07ce ? # Character ß
+U+07cf ? # Character ß
+U+07d0 ? # Character ß
+U+07d1 ? # Character ß
+U+07d2 ? # Character ß
+U+07d3 ? # Character ß
+U+07d4 ? # Character ß
+U+07d5 ? # Character ß
+U+07d6 ? # Character ß
+U+07d7 ? # Character ß
+U+07d8 ? # Character ß
+U+07d9 ? # Character ß
+U+07da ? # Character ß
+U+07db ? # Character ß
+U+07dc ? # Character ß
+U+07dd ? # Character ß
+U+07de ? # Character ß
+U+07df ? # Character ß
+U+07e0 ? # Character ß
+U+07e1 ? # Character ß¡
+U+07e2 ? # Character ߢ
+U+07e3 ? # Character ߣ
+U+07e4 ? # Character ߤ
+U+07e5 ? # Character ߥ
+U+07e6 ? # Character ߦ
+U+07e7 ? # Character ߧ
+U+07e8 ? # Character ߨ
+U+07e9 ? # Character ß©
+U+07ea ? # Character ߪ
+U+07eb ? # Character ß«
+U+07ec ? # Character ߬
+U+07ed ? # Character ß
+U+07ee ? # Character ß®
+U+07ef ? # Character ߯
+U+07f0 ? # Character ß°
+U+07f1 ? # Character ß±
+U+07f2 ? # Character ß²
+U+07f3 ? # Character ß³
+U+07f4 ? # Character ß´
+U+07f5 ? # Character ßµ
+U+07f6 ? # Character ߶
+U+07f7 ? # Character ß·
+U+07f8 ? # Character ߸
+U+07f9 ? # Character ß¹
+U+07fa ? # Character ߺ
+U+07fb ? # Character ß»
+U+07fc ? # Character ß¼
+U+07fd ? # Character ß½
+U+07fe ? # Character ß¾
+U+07ff ? # Character ß¿
diff --git a/resources/chars/ascii/row09.trans b/resources/chars/ascii/row09.trans
new file mode 100644
index 0000000..37940ea
--- /dev/null
+++ b/resources/chars/ascii/row09.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+0900 ? # Character à¤
+U+0901 N # Character à¤
+U+0902 N # Character à¤
+U+0903 H # Character à¤
+U+0904 ? # Character à¤
+U+0905 a # Character à¤
+U+0906 aa # Character à¤
+U+0907 i # Character à¤
+U+0908 ii # Character à¤
+U+0909 u # Character à¤
+U+090a uu # Character à¤
+U+090b R # Character à¤
+U+090c L # Character à¤
+U+090d eN # Character à¤
+U+090e e # Character à¤
+U+090f e # Character à¤
+U+0910 ai # Character à¤
+U+0911 oN # Character à¤
+U+0912 o # Character à¤
+U+0913 o # Character à¤
+U+0914 au # Character à¤
+U+0915 k # Character à¤
+U+0916 kh # Character à¤
+U+0917 g # Character à¤
+U+0918 gh # Character à¤
+U+0919 ng # Character à¤
+U+091a c # Character à¤
+U+091b ch # Character à¤
+U+091c j # Character à¤
+U+091d jh # Character à¤
+U+091e ny # Character à¤
+U+091f tt # Character à¤
+U+0920 tth # Character à¤
+U+0921 dd # Character ड
+U+0922 ddh # Character ढ
+U+0923 nn # Character ण
+U+0924 t # Character त
+U+0925 th # Character थ
+U+0926 d # Character द
+U+0927 dh # Character ध
+U+0928 n # Character न
+U+0929 nnn # Character ऩ
+U+092a p # Character प
+U+092b ph # Character फ
+U+092c b # Character ब
+U+092d bh # Character à¤
+U+092e m # Character म
+U+092f y # Character य
+U+0930 r # Character र
+U+0931 rr # Character ऱ
+U+0932 l # Character ल
+U+0933 l # Character ळ
+U+0934 lll # Character ऴ
+U+0935 v # Character व
+U+0936 sh # Character श
+U+0937 ss # Character ष
+U+0938 s # Character स
+U+0939 h # Character ह
+U+093a ? # Character ऺ
+U+093b ? # Character ऻ
+U+093c ' # Character ़
+U+093d ' # Character ऽ
+U+093e aa # Character ा
+U+093f i # Character ि
+U+0940 ii # Character à¥
+U+0941 u # Character à¥
+U+0942 uu # Character à¥
+U+0943 R # Character à¥
+U+0944 RR # Character à¥
+U+0945 eN # Character à¥
+U+0946 e # Character à¥
+U+0947 e # Character à¥
+U+0948 ai # Character à¥
+U+0949 oN # Character à¥
+U+094a o # Character à¥
+U+094b o # Character à¥
+U+094c au # Character à¥
+U+094d ? # Character à¥
+U+094e ? # Character à¥
+U+094f ? # Character à¥
+U+0950 AUM # Character à¥
+U+0951 ' # Character à¥
+U+0952 ' # Character à¥
+U+0953 ` # Character à¥
+U+0954 ' # Character à¥
+U+0955 ? # Character à¥
+U+0956 ? # Character à¥
+U+0957 ? # Character à¥
+U+0958 q # Character à¥
+U+0959 khh # Character à¥
+U+095a ghh # Character à¥
+U+095b z # Character à¥
+U+095c dddh # Character à¥
+U+095d rh # Character à¥
+U+095e f # Character à¥
+U+095f yy # Character à¥
+U+0960 RR # Character à¥
+U+0961 LL # Character ॡ
+U+0962 L # Character ॢ
+U+0963 LL # Character ॣ
+U+0964 / # Character ।
+U+0965 // # Character ॥
+U+0966 ? # Character ०
+U+0967 1 # Character १
+U+0968 2 # Character २
+U+0969 3 # Character ३
+U+096a 4 # Character ४
+U+096b 5 # Character ५
+U+096c 6 # Character ६
+U+096d 7 # Character à¥
+U+096e 8 # Character ८
+U+096f 9 # Character ९
+U+0970 . # Character ॰
+U+0971 ? # Character ॱ
+U+0972 ? # Character ॲ
+U+0973 ? # Character ॳ
+U+0974 ? # Character ॴ
+U+0975 ? # Character ॵ
+U+0976 ? # Character ॶ
+U+0977 ? # Character ॷ
+U+0978 ? # Character ॸ
+U+0979 ? # Character ॹ
+U+097a ? # Character ॺ
+U+097b ? # Character ॻ
+U+097c ? # Character ॼ
+U+097d ? # Character ॽ
+U+097e ? # Character ॾ
+U+097f ? # Character ॿ
+U+0980 ? # Character à¦
+U+0981 N # Character à¦
+U+0982 N # Character à¦
+U+0983 H # Character à¦
+U+0984 ? # Character à¦
+U+0985 a # Character à¦
+U+0986 aa # Character à¦
+U+0987 i # Character à¦
+U+0988 ii # Character à¦
+U+0989 u # Character à¦
+U+098a uu # Character à¦
+U+098b R # Character à¦
+U+098c RR # Character à¦
+U+098d ? # Character à¦
+U+098e ? # Character à¦
+U+098f e # Character à¦
+U+0990 ai # Character à¦
+U+0991 ? # Character à¦
+U+0992 ? # Character à¦
+U+0993 o # Character à¦
+U+0994 au # Character à¦
+U+0995 k # Character à¦
+U+0996 kh # Character à¦
+U+0997 g # Character à¦
+U+0998 gh # Character à¦
+U+0999 ng # Character à¦
+U+099a c # Character à¦
+U+099b ch # Character à¦
+U+099c j # Character à¦
+U+099d jh # Character à¦
+U+099e ny # Character à¦
+U+099f tt # Character à¦
+U+09a0 tth # Character à¦
+U+09a1 dd # Character ড
+U+09a2 ddh # Character ঢ
+U+09a3 nn # Character ণ
+U+09a4 t # Character ত
+U+09a5 th # Character থ
+U+09a6 d # Character দ
+U+09a7 dh # Character ধ
+U+09a8 n # Character ন
+U+09a9 ? # Character ঩
+U+09aa p # Character প
+U+09ab ph # Character ফ
+U+09ac b # Character ব
+U+09ad bh # Character à¦
+U+09ae m # Character ম
+U+09af y # Character য
+U+09b0 r # Character র
+U+09b1 ? # Character ঱
+U+09b2 l # Character ল
+U+09b3 ? # Character ঳
+U+09b4 ? # Character ঴
+U+09b5 ? # Character ঵
+U+09b6 sh # Character শ
+U+09b7 ss # Character ষ
+U+09b8 s # Character স
+U+09b9 h # Character হ
+U+09ba ? # Character ঺
+U+09bb ? # Character ঻
+U+09bc ' # Character ়
+U+09bd ? # Character ঽ
+U+09be aa # Character া
+U+09bf i # Character ি
+U+09c0 ii # Character à§
+U+09c1 u # Character à§
+U+09c2 uu # Character à§
+U+09c3 R # Character à§
+U+09c4 RR # Character à§
+U+09c5 ? # Character à§
+U+09c6 ? # Character à§
+U+09c7 e # Character à§
+U+09c8 ai # Character à§
+U+09c9 ? # Character à§
+U+09ca ? # Character à§
+U+09cb o # Character à§
+U+09cc au # Character à§
+U+09cd ? # Character à§
+U+09ce ? # Character à§
+U+09cf ? # Character à§
+U+09d0 ? # Character à§
+U+09d1 ? # Character à§
+U+09d2 ? # Character à§
+U+09d3 ? # Character à§
+U+09d4 ? # Character à§
+U+09d5 ? # Character à§
+U+09d6 ? # Character à§
+U+09d7 + # Character à§
+U+09d8 ? # Character à§
+U+09d9 ? # Character à§
+U+09da ? # Character à§
+U+09db ? # Character à§
+U+09dc rr # Character à§
+U+09dd rh # Character à§
+U+09de ? # Character à§
+U+09df yy # Character à§
+U+09e0 RR # Character à§
+U+09e1 LL # Character ৡ
+U+09e2 L # Character ৢ
+U+09e3 LL # Character ৣ
+U+09e4 ? # Character ৤
+U+09e5 ? # Character ৥
+U+09e6 ? # Character ০
+U+09e7 1 # Character ১
+U+09e8 2 # Character ২
+U+09e9 3 # Character ৩
+U+09ea 4 # Character ৪
+U+09eb 5 # Character ৫
+U+09ec 6 # Character ৬
+U+09ed 7 # Character à§
+U+09ee 8 # Character ৮
+U+09ef 9 # Character ৯
+U+09f0 r' # Character ৰ
+U+09f1 r` # Character ৱ
+U+09f2 Rs # Character ৲
+U+09f3 Rs # Character ৳
+U+09f4 1/ # Character ৴
+U+09f5 2/ # Character ৵
+U+09f6 3/ # Character ৶
+U+09f7 4/ # Character ৷
+U+09f8 1 - 1/ # Character ৸
+U+09f9 /16 # Character ৹
+U+09fa ? # Character ৺
+U+09fb ? # Character ৻
+U+09fc ? # Character ৼ
+U+09fd ? # Character ৽
+U+09fe ? # Character ৾
+U+09ff ? # Character ৿
diff --git a/resources/chars/ascii/row0a.trans b/resources/chars/ascii/row0a.trans
new file mode 100644
index 0000000..702646e
--- /dev/null
+++ b/resources/chars/ascii/row0a.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+0a00 ? # Character à¨
+U+0a01 ? # Character à¨
+U+0a02 N # Character à¨
+U+0a03 ? # Character à¨
+U+0a04 ? # Character à¨
+U+0a05 a # Character à¨
+U+0a06 aa # Character à¨
+U+0a07 i # Character à¨
+U+0a08 ii # Character à¨
+U+0a09 u # Character à¨
+U+0a0a uu # Character à¨
+U+0a0b ? # Character à¨
+U+0a0c ? # Character à¨
+U+0a0d ? # Character à¨
+U+0a0e ? # Character à¨
+U+0a0f ee # Character à¨
+U+0a10 ai # Character à¨
+U+0a11 ? # Character à¨
+U+0a12 ? # Character à¨
+U+0a13 oo # Character à¨
+U+0a14 au # Character à¨
+U+0a15 k # Character à¨
+U+0a16 kh # Character à¨
+U+0a17 g # Character à¨
+U+0a18 gh # Character à¨
+U+0a19 ng # Character à¨
+U+0a1a c # Character à¨
+U+0a1b ch # Character à¨
+U+0a1c j # Character à¨
+U+0a1d jh # Character à¨
+U+0a1e ny # Character à¨
+U+0a1f tt # Character à¨
+U+0a20 tth # Character à¨
+U+0a21 dd # Character ਡ
+U+0a22 ddh # Character ਢ
+U+0a23 nn # Character ਣ
+U+0a24 t # Character ਤ
+U+0a25 th # Character ਥ
+U+0a26 d # Character ਦ
+U+0a27 dh # Character ਧ
+U+0a28 n # Character ਨ
+U+0a29 ? # Character ਩
+U+0a2a p # Character ਪ
+U+0a2b ph # Character ਫ
+U+0a2c b # Character ਬ
+U+0a2d bb # Character à¨
+U+0a2e m # Character ਮ
+U+0a2f y # Character ਯ
+U+0a30 r # Character ਰ
+U+0a31 ? # Character ਱
+U+0a32 l # Character ਲ
+U+0a33 ll # Character ਲ਼
+U+0a34 ? # Character ਴
+U+0a35 v # Character ਵ
+U+0a36 sh # Character ਸ਼
+U+0a37 ? # Character ਷
+U+0a38 s # Character ਸ
+U+0a39 h # Character ਹ
+U+0a3a ? # Character ਺
+U+0a3b ? # Character ਻
+U+0a3c ' # Character ਼
+U+0a3d ? # Character ਽
+U+0a3e aa # Character ਾ
+U+0a3f i # Character ਿ
+U+0a40 ii # Character à©
+U+0a41 u # Character à©
+U+0a42 uu # Character à©
+U+0a43 ? # Character à©
+U+0a44 ? # Character à©
+U+0a45 ? # Character à©
+U+0a46 ? # Character à©
+U+0a47 ee # Character à©
+U+0a48 ai # Character à©
+U+0a49 ? # Character à©
+U+0a4a ? # Character à©
+U+0a4b oo # Character à©
+U+0a4c au # Character à©
+U+0a4d ? # Character à©
+U+0a4e ? # Character à©
+U+0a4f ? # Character à©
+U+0a50 ? # Character à©
+U+0a51 ? # Character à©
+U+0a52 ? # Character à©
+U+0a53 ? # Character à©
+U+0a54 ? # Character à©
+U+0a55 ? # Character à©
+U+0a56 ? # Character à©
+U+0a57 ? # Character à©
+U+0a58 ? # Character à©
+U+0a59 khh # Character à©
+U+0a5a ghh # Character à©
+U+0a5b z # Character à©
+U+0a5c rr # Character à©
+U+0a5d ? # Character à©
+U+0a5e f # Character à©
+U+0a5f ? # Character à©
+U+0a60 ? # Character à©
+U+0a61 ? # Character à©¡
+U+0a62 ? # Character à©¢
+U+0a63 ? # Character à©£
+U+0a64 ? # Character ੤
+U+0a65 ? # Character à©¥
+U+0a66 ? # Character ੦
+U+0a67 1 # Character ੧
+U+0a68 2 # Character ੨
+U+0a69 3 # Character à©©
+U+0a6a 4 # Character ੪
+U+0a6b 5 # Character à©«
+U+0a6c 6 # Character ੬
+U+0a6d 7 # Character à©
+U+0a6e 8 # Character à©®
+U+0a6f 9 # Character ੯
+U+0a70 N # Character à©°
+U+0a71 H # Character ੱ
+U+0a72 ? # Character ੲ
+U+0a73 ? # Character ੳ
+U+0a74 G.E.O. # Character à©´
+U+0a75 ? # Character ੵ
+U+0a76 ? # Character ੶
+U+0a77 ? # Character à©·
+U+0a78 ? # Character ੸
+U+0a79 ? # Character ੹
+U+0a7a ? # Character ੺
+U+0a7b ? # Character à©»
+U+0a7c ? # Character ੼
+U+0a7d ? # Character ੽
+U+0a7e ? # Character ੾
+U+0a7f ? # Character à©¿
+U+0a80 ? # Character àª
+U+0a81 N # Character àª
+U+0a82 N # Character àª
+U+0a83 H # Character àª
+U+0a84 ? # Character àª
+U+0a85 a # Character àª
+U+0a86 aa # Character àª
+U+0a87 i # Character àª
+U+0a88 ii # Character àª
+U+0a89 u # Character àª
+U+0a8a uu # Character àª
+U+0a8b R # Character àª
+U+0a8c ? # Character àª
+U+0a8d eN # Character àª
+U+0a8e ? # Character àª
+U+0a8f e # Character àª
+U+0a90 ai # Character àª
+U+0a91 oN # Character àª
+U+0a92 ? # Character àª
+U+0a93 o # Character àª
+U+0a94 au # Character àª
+U+0a95 k # Character àª
+U+0a96 kh # Character àª
+U+0a97 g # Character àª
+U+0a98 gh # Character àª
+U+0a99 ng # Character àª
+U+0a9a c # Character àª
+U+0a9b ch # Character àª
+U+0a9c j # Character àª
+U+0a9d jh # Character àª
+U+0a9e ny # Character àª
+U+0a9f tt # Character àª
+U+0aa0 tth # Character àª
+U+0aa1 dd # Character ડ
+U+0aa2 ddh # Character ઢ
+U+0aa3 nn # Character ણ
+U+0aa4 t # Character ત
+U+0aa5 th # Character થ
+U+0aa6 d # Character દ
+U+0aa7 dh # Character ધ
+U+0aa8 n # Character ન
+U+0aa9 ? # Character ઩
+U+0aaa p # Character પ
+U+0aab ph # Character ફ
+U+0aac b # Character બ
+U+0aad bh # Character àª
+U+0aae m # Character મ
+U+0aaf ya # Character ય
+U+0ab0 r # Character ર
+U+0ab1 ? # Character ઱
+U+0ab2 l # Character લ
+U+0ab3 ll # Character ળ
+U+0ab4 ? # Character ઴
+U+0ab5 v # Character વ
+U+0ab6 sh # Character શ
+U+0ab7 ss # Character ષ
+U+0ab8 s # Character સ
+U+0ab9 h # Character હ
+U+0aba ? # Character ઺
+U+0abb ? # Character ઻
+U+0abc ' # Character ઼
+U+0abd ' # Character ઽ
+U+0abe aa # Character ા
+U+0abf i # Character િ
+U+0ac0 ii # Character à«
+U+0ac1 u # Character à«
+U+0ac2 uu # Character à«
+U+0ac3 R # Character à«
+U+0ac4 RR # Character à«
+U+0ac5 eN # Character à«
+U+0ac6 ? # Character à«
+U+0ac7 e # Character à«
+U+0ac8 ai # Character à«
+U+0ac9 oN # Character à«
+U+0aca ? # Character à«
+U+0acb o # Character à«
+U+0acc au # Character à«
+U+0acd ? # Character à«
+U+0ace ? # Character à«
+U+0acf ? # Character à«
+U+0ad0 AUM # Character à«
+U+0ad1 ? # Character à«
+U+0ad2 ? # Character à«
+U+0ad3 ? # Character à«
+U+0ad4 ? # Character à«
+U+0ad5 ? # Character à«
+U+0ad6 ? # Character à«
+U+0ad7 ? # Character à«
+U+0ad8 ? # Character à«
+U+0ad9 ? # Character à«
+U+0ada ? # Character à«
+U+0adb ? # Character à«
+U+0adc ? # Character à«
+U+0add ? # Character à«
+U+0ade ? # Character à«
+U+0adf ? # Character à«
+U+0ae0 RR # Character à«
+U+0ae1 ? # Character à«¡
+U+0ae2 ? # Character à«¢
+U+0ae3 ? # Character à«£
+U+0ae4 ? # Character ૤
+U+0ae5 ? # Character à«¥
+U+0ae6 ? # Character ૦
+U+0ae7 1 # Character ૧
+U+0ae8 2 # Character ૨
+U+0ae9 3 # Character à«©
+U+0aea 4 # Character ૪
+U+0aeb 5 # Character à««
+U+0aec 6 # Character ૬
+U+0aed 7 # Character à«
+U+0aee 8 # Character à«®
+U+0aef 9 # Character ૯
+U+0af0 ? # Character à«°
+U+0af1 ? # Character ૱
+U+0af2 ? # Character ૲
+U+0af3 ? # Character ૳
+U+0af4 ? # Character à«´
+U+0af5 ? # Character ૵
+U+0af6 ? # Character ૶
+U+0af7 ? # Character à«·
+U+0af8 ? # Character ૸
+U+0af9 ? # Character ૹ
+U+0afa ? # Character ૺ
+U+0afb ? # Character à«»
+U+0afc ? # Character ૼ
+U+0afd ? # Character ૽
+U+0afe ? # Character ૾
+U+0aff ? # Character à«¿
diff --git a/resources/chars/ascii/row0b.trans b/resources/chars/ascii/row0b.trans
new file mode 100644
index 0000000..d22f40d
--- /dev/null
+++ b/resources/chars/ascii/row0b.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+0b00 ? # Character à¬
+U+0b01 N # Character à¬
+U+0b02 N # Character à¬
+U+0b03 H # Character à¬
+U+0b04 ? # Character à¬
+U+0b05 a # Character à¬
+U+0b06 aa # Character à¬
+U+0b07 i # Character à¬
+U+0b08 ii # Character à¬
+U+0b09 u # Character à¬
+U+0b0a uu # Character à¬
+U+0b0b R # Character à¬
+U+0b0c L # Character à¬
+U+0b0d ? # Character à¬
+U+0b0e ? # Character à¬
+U+0b0f e # Character à¬
+U+0b10 ai # Character à¬
+U+0b11 ? # Character à¬
+U+0b12 ? # Character à¬
+U+0b13 o # Character à¬
+U+0b14 au # Character à¬
+U+0b15 k # Character à¬
+U+0b16 kh # Character à¬
+U+0b17 g # Character à¬
+U+0b18 gh # Character à¬
+U+0b19 ng # Character à¬
+U+0b1a c # Character à¬
+U+0b1b ch # Character à¬
+U+0b1c j # Character à¬
+U+0b1d jh # Character à¬
+U+0b1e ny # Character à¬
+U+0b1f tt # Character à¬
+U+0b20 tth # Character à¬
+U+0b21 dd # Character ଡ
+U+0b22 ddh # Character ଢ
+U+0b23 nn # Character ଣ
+U+0b24 t # Character ତ
+U+0b25 th # Character ଥ
+U+0b26 d # Character ଦ
+U+0b27 dh # Character ଧ
+U+0b28 n # Character ନ
+U+0b29 ? # Character ଩
+U+0b2a p # Character ପ
+U+0b2b ph # Character ଫ
+U+0b2c b # Character ବ
+U+0b2d bh # Character à¬
+U+0b2e m # Character ମ
+U+0b2f y # Character ଯ
+U+0b30 r # Character ର
+U+0b31 ? # Character ଱
+U+0b32 l # Character ଲ
+U+0b33 ll # Character ଳ
+U+0b34 ? # Character ଴
+U+0b35 ? # Character ଵ
+U+0b36 sh # Character ଶ
+U+0b37 ss # Character ଷ
+U+0b38 s # Character ସ
+U+0b39 h # Character ହ
+U+0b3a ? # Character ଺
+U+0b3b ? # Character ଻
+U+0b3c ' # Character ଼
+U+0b3d ' # Character ଽ
+U+0b3e aa # Character ା
+U+0b3f i # Character ି
+U+0b40 ii # Character à
+U+0b41 u # Character à
+U+0b42 uu # Character à
+U+0b43 R # Character à
+U+0b44 ? # Character à
+U+0b45 ? # Character à
+U+0b46 ? # Character à
+U+0b47 e # Character à
+U+0b48 ai # Character à
+U+0b49 ? # Character à
+U+0b4a ? # Character à
+U+0b4b o # Character à
+U+0b4c au # Character à
+U+0b4d ? # Character à
+U+0b4e ? # Character à
+U+0b4f ? # Character à
+U+0b50 ? # Character à
+U+0b51 ? # Character à
+U+0b52 ? # Character à
+U+0b53 ? # Character à
+U+0b54 ? # Character à
+U+0b55 ? # Character à
+U+0b56 + # Character à
+U+0b57 + # Character à
+U+0b58 ? # Character à
+U+0b59 ? # Character à
+U+0b5a ? # Character à
+U+0b5b ? # Character à
+U+0b5c rr # Character à
+U+0b5d rh # Character à
+U+0b5e ? # Character à
+U+0b5f yy # Character à
+U+0b60 RR # Character à
+U+0b61 LL # Character à¡
+U+0b62 ? # Character à¢
+U+0b63 ? # Character à£
+U+0b64 ? # Character à¤
+U+0b65 ? # Character à¥
+U+0b66 ? # Character à¦
+U+0b67 1 # Character à§
+U+0b68 2 # Character à¨
+U+0b69 3 # Character à©
+U+0b6a 4 # Character àª
+U+0b6b 5 # Character à«
+U+0b6c 6 # Character à¬
+U+0b6d 7 # Character à
+U+0b6e 8 # Character à®
+U+0b6f 9 # Character à¯
+U+0b70 ? # Character à°
+U+0b71 ? # Character à±
+U+0b72 ? # Character à²
+U+0b73 ? # Character à³
+U+0b74 ? # Character à´
+U+0b75 ? # Character àµ
+U+0b76 ? # Character à¶
+U+0b77 ? # Character à·
+U+0b78 ? # Character à¸
+U+0b79 ? # Character à¹
+U+0b7a ? # Character àº
+U+0b7b ? # Character à»
+U+0b7c ? # Character à¼
+U+0b7d ? # Character à½
+U+0b7e ? # Character à¾
+U+0b7f ? # Character à¿
+U+0b80 ? # Character à®
+U+0b81 ? # Character à®
+U+0b82 N # Character à®
+U+0b83 H # Character à®
+U+0b84 ? # Character à®
+U+0b85 a # Character à®
+U+0b86 aa # Character à®
+U+0b87 i # Character à®
+U+0b88 ii # Character à®
+U+0b89 u # Character à®
+U+0b8a uu # Character à®
+U+0b8b ? # Character à®
+U+0b8c ? # Character à®
+U+0b8d ? # Character à®
+U+0b8e e # Character à®
+U+0b8f ee # Character à®
+U+0b90 ai # Character à®
+U+0b91 ? # Character à®
+U+0b92 o # Character à®
+U+0b93 oo # Character à®
+U+0b94 au # Character à®
+U+0b95 k # Character à®
+U+0b96 ? # Character à®
+U+0b97 ? # Character à®
+U+0b98 ? # Character à®
+U+0b99 ng # Character à®
+U+0b9a c # Character à®
+U+0b9b ? # Character à®
+U+0b9c j # Character à®
+U+0b9d ? # Character à®
+U+0b9e ny # Character à®
+U+0b9f tt # Character à®
+U+0ba0 ? # Character à®
+U+0ba1 ? # Character ஡
+U+0ba2 ? # Character ஢
+U+0ba3 nn # Character ண
+U+0ba4 t # Character த
+U+0ba5 ? # Character ஥
+U+0ba6 ? # Character ஦
+U+0ba7 ? # Character ஧
+U+0ba8 n # Character ந
+U+0ba9 nnn # Character ன
+U+0baa p # Character ப
+U+0bab ? # Character ஫
+U+0bac ? # Character ஬
+U+0bad ? # Character à®
+U+0bae m # Character à®®
+U+0baf y # Character ய
+U+0bb0 r # Character à®°
+U+0bb1 rr # Character à®±
+U+0bb2 l # Character ல
+U+0bb3 ll # Character ள
+U+0bb4 lll # Character à®´
+U+0bb5 v # Character வ
+U+0bb6 ? # Character ஶ
+U+0bb7 ss # Character à®·
+U+0bb8 s # Character ஸ
+U+0bb9 h # Character ஹ
+U+0bba ? # Character ஺
+U+0bbb ? # Character à®»
+U+0bbc ? # Character ஼
+U+0bbd ? # Character ஽
+U+0bbe aa # Character ா
+U+0bbf i # Character ி
+U+0bc0 ii # Character à¯
+U+0bc1 u # Character à¯
+U+0bc2 uu # Character à¯
+U+0bc3 ? # Character à¯
+U+0bc4 ? # Character à¯
+U+0bc5 ? # Character à¯
+U+0bc6 e # Character à¯
+U+0bc7 ee # Character à¯
+U+0bc8 ai # Character à¯
+U+0bc9 ? # Character à¯
+U+0bca o # Character à¯
+U+0bcb oo # Character à¯
+U+0bcc au # Character à¯
+U+0bcd ? # Character à¯
+U+0bce ? # Character à¯
+U+0bcf ? # Character à¯
+U+0bd0 ? # Character à¯
+U+0bd1 ? # Character à¯
+U+0bd2 ? # Character à¯
+U+0bd3 ? # Character à¯
+U+0bd4 ? # Character à¯
+U+0bd5 ? # Character à¯
+U+0bd6 ? # Character à¯
+U+0bd7 + # Character à¯
+U+0bd8 ? # Character à¯
+U+0bd9 ? # Character à¯
+U+0bda ? # Character à¯
+U+0bdb ? # Character à¯
+U+0bdc ? # Character à¯
+U+0bdd ? # Character à¯
+U+0bde ? # Character à¯
+U+0bdf ? # Character à¯
+U+0be0 ? # Character à¯
+U+0be1 ? # Character ௡
+U+0be2 ? # Character ௢
+U+0be3 ? # Character ௣
+U+0be4 ? # Character ௤
+U+0be5 ? # Character ௥
+U+0be6 ? # Character ௦
+U+0be7 1 # Character ௧
+U+0be8 2 # Character ௨
+U+0be9 3 # Character ௩
+U+0bea 4 # Character ௪
+U+0beb 5 # Character ௫
+U+0bec 6 # Character ௬
+U+0bed 7 # Character à¯
+U+0bee 8 # Character ௮
+U+0bef 9 # Character ௯
+U+0bf0 +10+ # Character ௰
+U+0bf1 +100+ # Character ௱
+U+0bf2 +1000+ # Character ௲
+U+0bf3 ? # Character ௳
+U+0bf4 ? # Character ௴
+U+0bf5 ? # Character ௵
+U+0bf6 ? # Character ௶
+U+0bf7 ? # Character ௷
+U+0bf8 ? # Character ௸
+U+0bf9 ? # Character ௹
+U+0bfa ? # Character ௺
+U+0bfb ? # Character ௻
+U+0bfc ? # Character ௼
+U+0bfd ? # Character ௽
+U+0bfe ? # Character ௾
+U+0bff ? # Character ௿
diff --git a/resources/chars/ascii/row0c.trans b/resources/chars/ascii/row0c.trans
new file mode 100644
index 0000000..d06ae96
--- /dev/null
+++ b/resources/chars/ascii/row0c.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+0c00 ? # Character à°
+U+0c01 N # Character à°
+U+0c02 N # Character à°
+U+0c03 H # Character à°
+U+0c04 ? # Character à°
+U+0c05 a # Character à°
+U+0c06 aa # Character à°
+U+0c07 i # Character à°
+U+0c08 ii # Character à°
+U+0c09 u # Character à°
+U+0c0a uu # Character à°
+U+0c0b R # Character à°
+U+0c0c L # Character à°
+U+0c0d ? # Character à°
+U+0c0e e # Character à°
+U+0c0f ee # Character à°
+U+0c10 ai # Character à°
+U+0c11 ? # Character à°
+U+0c12 o # Character à°
+U+0c13 oo # Character à°
+U+0c14 au # Character à°
+U+0c15 k # Character à°
+U+0c16 kh # Character à°
+U+0c17 g # Character à°
+U+0c18 gh # Character à°
+U+0c19 ng # Character à°
+U+0c1a c # Character à°
+U+0c1b ch # Character à°
+U+0c1c j # Character à°
+U+0c1d jh # Character à°
+U+0c1e ny # Character à°
+U+0c1f tt # Character à°
+U+0c20 tth # Character à°
+U+0c21 dd # Character à°¡
+U+0c22 ddh # Character à°¢
+U+0c23 nn # Character à°£
+U+0c24 t # Character à°¤
+U+0c25 th # Character à°¥
+U+0c26 d # Character à°¦
+U+0c27 dh # Character à°§
+U+0c28 n # Character à°¨
+U+0c29 ? # Character à°©
+U+0c2a p # Character à°ª
+U+0c2b ph # Character à°«
+U+0c2c b # Character à°¬
+U+0c2d bh # Character à°
+U+0c2e m # Character à°®
+U+0c2f y # Character à°¯
+U+0c30 r # Character à°°
+U+0c31 rr # Character à°±
+U+0c32 l # Character à°²
+U+0c33 ll # Character à°³
+U+0c34 ? # Character à°´
+U+0c35 v # Character à°µ
+U+0c36 sh # Character à°¶
+U+0c37 ss # Character à°·
+U+0c38 s # Character à°¸
+U+0c39 h # Character à°¹
+U+0c3a ? # Character à°º
+U+0c3b ? # Character à°»
+U+0c3c ? # Character à°¼
+U+0c3d ? # Character à°½
+U+0c3e aa # Character à°¾
+U+0c3f i # Character à°¿
+U+0c40 ii # Character à±
+U+0c41 u # Character à±
+U+0c42 uu # Character à±
+U+0c43 R # Character à±
+U+0c44 RR # Character à±
+U+0c45 ? # Character à±
+U+0c46 e # Character à±
+U+0c47 ee # Character à±
+U+0c48 ai # Character à±
+U+0c49 ? # Character à±
+U+0c4a o # Character à±
+U+0c4b oo # Character à±
+U+0c4c au # Character à±
+U+0c4d ? # Character à±
+U+0c4e ? # Character à±
+U+0c4f ? # Character à±
+U+0c50 ? # Character à±
+U+0c51 ? # Character à±
+U+0c52 ? # Character à±
+U+0c53 ? # Character à±
+U+0c54 ? # Character à±
+U+0c55 + # Character à±
+U+0c56 + # Character à±
+U+0c57 ? # Character à±
+U+0c58 ? # Character à±
+U+0c59 ? # Character à±
+U+0c5a ? # Character à±
+U+0c5b ? # Character à±
+U+0c5c ? # Character à±
+U+0c5d ? # Character à±
+U+0c5e ? # Character à±
+U+0c5f ? # Character à±
+U+0c60 RR # Character à±
+U+0c61 LL # Character ౡ
+U+0c62 ? # Character à±¢
+U+0c63 ? # Character à±£
+U+0c64 ? # Character ౤
+U+0c65 ? # Character à±¥
+U+0c66 ? # Character ౦
+U+0c67 1 # Character ౧
+U+0c68 2 # Character ౨
+U+0c69 3 # Character ౩
+U+0c6a 4 # Character ౪
+U+0c6b 5 # Character ౫
+U+0c6c 6 # Character ౬
+U+0c6d 7 # Character à±
+U+0c6e 8 # Character à±®
+U+0c6f 9 # Character ౯
+U+0c70 ? # Character à±°
+U+0c71 ? # Character à±±
+U+0c72 ? # Character à±²
+U+0c73 ? # Character à±³
+U+0c74 ? # Character à±´
+U+0c75 ? # Character à±µ
+U+0c76 ? # Character ౶
+U+0c77 ? # Character à±·
+U+0c78 ? # Character ౸
+U+0c79 ? # Character à±¹
+U+0c7a ? # Character ౺
+U+0c7b ? # Character à±»
+U+0c7c ? # Character à±¼
+U+0c7d ? # Character à±½
+U+0c7e ? # Character à±¾
+U+0c7f ? # Character ౿
+U+0c80 ? # Character à²
+U+0c81 ? # Character à²
+U+0c82 N # Character à²
+U+0c83 H # Character à²
+U+0c84 ? # Character à²
+U+0c85 a # Character à²
+U+0c86 aa # Character à²
+U+0c87 i # Character à²
+U+0c88 ii # Character à²
+U+0c89 u # Character à²
+U+0c8a uu # Character à²
+U+0c8b R # Character à²
+U+0c8c L # Character à²
+U+0c8d ? # Character à²
+U+0c8e e # Character à²
+U+0c8f ee # Character à²
+U+0c90 ai # Character à²
+U+0c91 ? # Character à²
+U+0c92 o # Character à²
+U+0c93 oo # Character à²
+U+0c94 au # Character à²
+U+0c95 k # Character à²
+U+0c96 kh # Character à²
+U+0c97 g # Character à²
+U+0c98 gh # Character à²
+U+0c99 ng # Character à²
+U+0c9a c # Character à²
+U+0c9b ch # Character à²
+U+0c9c j # Character à²
+U+0c9d jh # Character à²
+U+0c9e ny # Character à²
+U+0c9f tt # Character à²
+U+0ca0 tth # Character à²
+U+0ca1 dd # Character ಡ
+U+0ca2 ddh # Character ಢ
+U+0ca3 nn # Character ಣ
+U+0ca4 t # Character ತ
+U+0ca5 th # Character ಥ
+U+0ca6 d # Character ದ
+U+0ca7 dh # Character ಧ
+U+0ca8 n # Character ನ
+U+0ca9 ? # Character ಩
+U+0caa p # Character ಪ
+U+0cab ph # Character ಫ
+U+0cac b # Character ಬ
+U+0cad bh # Character à²
+U+0cae m # Character ಮ
+U+0caf y # Character ಯ
+U+0cb0 r # Character ರ
+U+0cb1 rr # Character ಱ
+U+0cb2 l # Character ಲ
+U+0cb3 ll # Character ಳ
+U+0cb4 ? # Character ಴
+U+0cb5 v # Character ವ
+U+0cb6 sh # Character ಶ
+U+0cb7 ss # Character ಷ
+U+0cb8 s # Character ಸ
+U+0cb9 h # Character ಹ
+U+0cba ? # Character ಺
+U+0cbb ? # Character ಻
+U+0cbc ? # Character ಼
+U+0cbd ? # Character ಽ
+U+0cbe aa # Character ಾ
+U+0cbf i # Character ಿ
+U+0cc0 ii # Character à³
+U+0cc1 u # Character à³
+U+0cc2 uu # Character à³
+U+0cc3 R # Character à³
+U+0cc4 RR # Character à³
+U+0cc5 ? # Character à³
+U+0cc6 e # Character à³
+U+0cc7 ee # Character à³
+U+0cc8 ai # Character à³
+U+0cc9 ? # Character à³
+U+0cca o # Character à³
+U+0ccb oo # Character à³
+U+0ccc au # Character à³
+U+0ccd ? # Character à³
+U+0cce ? # Character à³
+U+0ccf ? # Character à³
+U+0cd0 ? # Character à³
+U+0cd1 ? # Character à³
+U+0cd2 ? # Character à³
+U+0cd3 ? # Character à³
+U+0cd4 ? # Character à³
+U+0cd5 + # Character à³
+U+0cd6 + # Character à³
+U+0cd7 ? # Character à³
+U+0cd8 ? # Character à³
+U+0cd9 ? # Character à³
+U+0cda ? # Character à³
+U+0cdb ? # Character à³
+U+0cdc ? # Character à³
+U+0cdd ? # Character à³
+U+0cde lll # Character à³
+U+0cdf ? # Character à³
+U+0ce0 RR # Character à³
+U+0ce1 LL # Character ೡ
+U+0ce2 ? # Character à³¢
+U+0ce3 ? # Character à³£
+U+0ce4 ? # Character ೤
+U+0ce5 ? # Character à³¥
+U+0ce6 ? # Character ೦
+U+0ce7 1 # Character ೧
+U+0ce8 2 # Character ೨
+U+0ce9 3 # Character ೩
+U+0cea 4 # Character ೪
+U+0ceb 5 # Character ೫
+U+0cec 6 # Character ೬
+U+0ced 7 # Character à³
+U+0cee 8 # Character à³®
+U+0cef 9 # Character ೯
+U+0cf0 ? # Character à³°
+U+0cf1 ? # Character à³±
+U+0cf2 ? # Character à³²
+U+0cf3 ? # Character à³³
+U+0cf4 ? # Character à³´
+U+0cf5 ? # Character à³µ
+U+0cf6 ? # Character ೶
+U+0cf7 ? # Character à³·
+U+0cf8 ? # Character ೸
+U+0cf9 ? # Character à³¹
+U+0cfa ? # Character ೺
+U+0cfb ? # Character à³»
+U+0cfc ? # Character à³¼
+U+0cfd ? # Character à³½
+U+0cfe ? # Character à³¾
+U+0cff ? # Character ೿
diff --git a/resources/chars/ascii/row0d.trans b/resources/chars/ascii/row0d.trans
new file mode 100644
index 0000000..b2fac4f
--- /dev/null
+++ b/resources/chars/ascii/row0d.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+0d00 ? # Character à´
+U+0d01 ? # Character à´
+U+0d02 N # Character à´
+U+0d03 H # Character à´
+U+0d04 ? # Character à´
+U+0d05 a # Character à´
+U+0d06 aa # Character à´
+U+0d07 i # Character à´
+U+0d08 ii # Character à´
+U+0d09 u # Character à´
+U+0d0a uu # Character à´
+U+0d0b R # Character à´
+U+0d0c L # Character à´
+U+0d0d ? # Character à´
+U+0d0e e # Character à´
+U+0d0f ee # Character à´
+U+0d10 ai # Character à´
+U+0d11 ? # Character à´
+U+0d12 o # Character à´
+U+0d13 oo # Character à´
+U+0d14 au # Character à´
+U+0d15 k # Character à´
+U+0d16 kh # Character à´
+U+0d17 g # Character à´
+U+0d18 gh # Character à´
+U+0d19 ng # Character à´
+U+0d1a c # Character à´
+U+0d1b ch # Character à´
+U+0d1c j # Character à´
+U+0d1d jh # Character à´
+U+0d1e ny # Character à´
+U+0d1f tt # Character à´
+U+0d20 tth # Character à´
+U+0d21 dd # Character à´¡
+U+0d22 ddh # Character à´¢
+U+0d23 nn # Character à´£
+U+0d24 t # Character à´¤
+U+0d25 th # Character à´¥
+U+0d26 d # Character à´¦
+U+0d27 dh # Character à´§
+U+0d28 n # Character à´¨
+U+0d29 ? # Character à´©
+U+0d2a p # Character à´ª
+U+0d2b ph # Character à´«
+U+0d2c b # Character à´¬
+U+0d2d bh # Character à´
+U+0d2e m # Character à´®
+U+0d2f y # Character à´¯
+U+0d30 r # Character à´°
+U+0d31 rr # Character à´±
+U+0d32 l # Character à´²
+U+0d33 ll # Character à´³
+U+0d34 lll # Character à´´
+U+0d35 v # Character à´µ
+U+0d36 sh # Character à´¶
+U+0d37 ss # Character à´·
+U+0d38 s # Character à´¸
+U+0d39 h # Character à´¹
+U+0d3a ? # Character à´º
+U+0d3b ? # Character à´»
+U+0d3c ? # Character à´¼
+U+0d3d ? # Character à´½
+U+0d3e aa # Character à´¾
+U+0d3f i # Character à´¿
+U+0d40 ii # Character àµ
+U+0d41 u # Character àµ
+U+0d42 uu # Character àµ
+U+0d43 R # Character àµ
+U+0d44 ? # Character àµ
+U+0d45 ? # Character àµ
+U+0d46 e # Character àµ
+U+0d47 ee # Character àµ
+U+0d48 ai # Character àµ
+U+0d49 ? # Character àµ
+U+0d4a o # Character àµ
+U+0d4b oo # Character àµ
+U+0d4c au # Character àµ
+U+0d4d ? # Character àµ
+U+0d4e ? # Character àµ
+U+0d4f ? # Character àµ
+U+0d50 ? # Character àµ
+U+0d51 ? # Character àµ
+U+0d52 ? # Character àµ
+U+0d53 ? # Character àµ
+U+0d54 ? # Character àµ
+U+0d55 ? # Character àµ
+U+0d56 ? # Character àµ
+U+0d57 + # Character àµ
+U+0d58 ? # Character àµ
+U+0d59 ? # Character àµ
+U+0d5a ? # Character àµ
+U+0d5b ? # Character àµ
+U+0d5c ? # Character àµ
+U+0d5d ? # Character àµ
+U+0d5e ? # Character àµ
+U+0d5f ? # Character àµ
+U+0d60 RR # Character àµ
+U+0d61 LL # Character ൡ
+U+0d62 ? # Character ൢ
+U+0d63 ? # Character ൣ
+U+0d64 ? # Character ൤
+U+0d65 ? # Character ൥
+U+0d66 ? # Character ൦
+U+0d67 1 # Character ൧
+U+0d68 2 # Character ൨
+U+0d69 3 # Character ൩
+U+0d6a 4 # Character ൪
+U+0d6b 5 # Character ൫
+U+0d6c 6 # Character ൬
+U+0d6d 7 # Character àµ
+U+0d6e 8 # Character ൮
+U+0d6f 9 # Character ൯
+U+0d70 ? # Character ൰
+U+0d71 ? # Character ൱
+U+0d72 ? # Character ൲
+U+0d73 ? # Character ൳
+U+0d74 ? # Character ൴
+U+0d75 ? # Character ൵
+U+0d76 ? # Character ൶
+U+0d77 ? # Character ൷
+U+0d78 ? # Character ൸
+U+0d79 ? # Character ൹
+U+0d7a ? # Character ൺ
+U+0d7b ? # Character ൻ
+U+0d7c ? # Character ർ
+U+0d7d ? # Character ൽ
+U+0d7e ? # Character ൾ
+U+0d7f ? # Character ൿ
+U+0d80 ? # Character à¶
+U+0d81 ? # Character à¶
+U+0d82 N # Character à¶
+U+0d83 H # Character à¶
+U+0d84 ? # Character à¶
+U+0d85 a # Character à¶
+U+0d86 aa # Character à¶
+U+0d87 ae # Character à¶
+U+0d88 aae # Character à¶
+U+0d89 i # Character à¶
+U+0d8a ii # Character à¶
+U+0d8b u # Character à¶
+U+0d8c uu # Character à¶
+U+0d8d R # Character à¶
+U+0d8e RR # Character à¶
+U+0d8f L # Character à¶
+U+0d90 LL # Character à¶
+U+0d91 e # Character à¶
+U+0d92 ee # Character à¶
+U+0d93 ai # Character à¶
+U+0d94 o # Character à¶
+U+0d95 oo # Character à¶
+U+0d96 au # Character à¶
+U+0d97 ? # Character à¶
+U+0d98 ? # Character à¶
+U+0d99 ? # Character à¶
+U+0d9a k # Character à¶
+U+0d9b kh # Character à¶
+U+0d9c g # Character à¶
+U+0d9d gh # Character à¶
+U+0d9e ng # Character à¶
+U+0d9f nng # Character à¶
+U+0da0 c # Character à¶
+U+0da1 ch # Character ඡ
+U+0da2 j # Character ජ
+U+0da3 jh # Character ඣ
+U+0da4 ny # Character ඤ
+U+0da5 jny # Character ඥ
+U+0da6 nyj # Character ඦ
+U+0da7 tt # Character ට
+U+0da8 tth # Character ඨ
+U+0da9 dd # Character ඩ
+U+0daa ddh # Character ඪ
+U+0dab nn # Character ණ
+U+0dac nndd # Character ඬ
+U+0dad t # Character à¶
+U+0dae th # Character ථ
+U+0daf d # Character ද
+U+0db0 dh # Character ධ
+U+0db1 n # Character න
+U+0db2 ? # Character ඲
+U+0db3 nd # Character ඳ
+U+0db4 p # Character ප
+U+0db5 ph # Character ඵ
+U+0db6 b # Character බ
+U+0db7 bh # Character භ
+U+0db8 m # Character ම
+U+0db9 mb # Character ඹ
+U+0dba y # Character ය
+U+0dbb r # Character ර
+U+0dbc ? # Character ඼
+U+0dbd l # Character ල
+U+0dbe ? # Character ඾
+U+0dbf ? # Character ඿
+U+0dc0 v # Character à·
+U+0dc1 sh # Character à·
+U+0dc2 ss # Character à·
+U+0dc3 s # Character à·
+U+0dc4 h # Character à·
+U+0dc5 ll # Character à·
+U+0dc6 f # Character à·
+U+0dc7 ? # Character à·
+U+0dc8 ? # Character à·
+U+0dc9 ? # Character à·
+U+0dca ? # Character à·
+U+0dcb ? # Character à·
+U+0dcc ? # Character à·
+U+0dcd ? # Character à·
+U+0dce ? # Character à·
+U+0dcf aa # Character à·
+U+0dd0 ae # Character à·
+U+0dd1 aae # Character à·
+U+0dd2 i # Character à·
+U+0dd3 ii # Character à·
+U+0dd4 u # Character à·
+U+0dd5 ? # Character à·
+U+0dd6 uu # Character à·
+U+0dd7 ? # Character à·
+U+0dd8 R # Character à·
+U+0dd9 e # Character à·
+U+0dda ee # Character à·
+U+0ddb ai # Character à·
+U+0ddc o # Character à·
+U+0ddd oo # Character à·
+U+0dde au # Character à·
+U+0ddf L # Character à·
+U+0de0 ? # Character à·
+U+0de1 ? # Character à·¡
+U+0de2 ? # Character à·¢
+U+0de3 ? # Character à·£
+U+0de4 ? # Character à·¤
+U+0de5 ? # Character à·¥
+U+0de6 ? # Character à·¦
+U+0de7 ? # Character à·§
+U+0de8 ? # Character à·¨
+U+0de9 ? # Character à·©
+U+0dea ? # Character à·ª
+U+0deb ? # Character à·«
+U+0dec ? # Character à·¬
+U+0ded ? # Character à·
+U+0dee ? # Character à·®
+U+0def ? # Character à·¯
+U+0df0 ? # Character à·°
+U+0df1 ? # Character à·±
+U+0df2 RR # Character à·²
+U+0df3 LL # Character à·³
+U+0df4 . # Character à·´
+U+0df5 ? # Character à·µ
+U+0df6 ? # Character à·¶
+U+0df7 ? # Character à··
+U+0df8 ? # Character à·¸
+U+0df9 ? # Character à·¹
+U+0dfa ? # Character à·º
+U+0dfb ? # Character à·»
+U+0dfc ? # Character à·¼
+U+0dfd ? # Character à·½
+U+0dfe ? # Character à·¾
+U+0dff ? # Character à·¿
diff --git a/resources/chars/ascii/row0e.trans b/resources/chars/ascii/row0e.trans
new file mode 100644
index 0000000..ec3fbf3
--- /dev/null
+++ b/resources/chars/ascii/row0e.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+0e00 ? # Character à¸
+U+0e01 k # Character à¸
+U+0e02 kh # Character à¸
+U+0e03 kh # Character à¸
+U+0e04 kh # Character à¸
+U+0e05 kh # Character à¸
+U+0e06 kh # Character à¸
+U+0e07 ng # Character à¸
+U+0e08 cch # Character à¸
+U+0e09 ch # Character à¸
+U+0e0a ch # Character à¸
+U+0e0b ch # Character à¸
+U+0e0c ch # Character à¸
+U+0e0d y # Character à¸
+U+0e0e d # Character à¸
+U+0e0f t # Character à¸
+U+0e10 th # Character à¸
+U+0e11 th # Character à¸
+U+0e12 th # Character à¸
+U+0e13 n # Character à¸
+U+0e14 d # Character à¸
+U+0e15 t # Character à¸
+U+0e16 th # Character à¸
+U+0e17 th # Character à¸
+U+0e18 th # Character à¸
+U+0e19 n # Character à¸
+U+0e1a b # Character à¸
+U+0e1b p # Character à¸
+U+0e1c ph # Character à¸
+U+0e1d f # Character à¸
+U+0e1e ph # Character à¸
+U+0e1f f # Character à¸
+U+0e20 ph # Character à¸
+U+0e21 m # Character ม
+U+0e22 y # Character ย
+U+0e23 r # Character ร
+U+0e24 R # Character ฤ
+U+0e25 l # Character ล
+U+0e26 L # Character ฦ
+U+0e27 w # Character ว
+U+0e28 s # Character ศ
+U+0e29 s # Character ษ
+U+0e2a s # Character ส
+U+0e2b h # Character ห
+U+0e2c l # Character ฬ
+U+0e2d ` # Character à¸
+U+0e2e h # Character ฮ
+U+0e2f ~ # Character ฯ
+U+0e30 a # Character ะ
+U+0e31 a # Character ั
+U+0e32 aa # Character า
+U+0e33 am # Character ำ
+U+0e34 i # Character ิ
+U+0e35 ii # Character ี
+U+0e36 ue # Character ึ
+U+0e37 uue # Character ื
+U+0e38 u # Character ุ
+U+0e39 uu # Character ู
+U+0e3a ' # Character ฺ
+U+0e3b ? # Character ฻
+U+0e3c ? # Character ฼
+U+0e3d ? # Character ฽
+U+0e3e ? # Character ฾
+U+0e3f Bh. # Character ฿
+U+0e40 e # Character à¹
+U+0e41 ae # Character à¹
+U+0e42 o # Character à¹
+U+0e43 ai # Character à¹
+U+0e44 ai # Character à¹
+U+0e45 ao # Character à¹
+U+0e46 + # Character à¹
+U+0e47 ? # Character à¹
+U+0e48 ? # Character à¹
+U+0e49 ? # Character à¹
+U+0e4a ? # Character à¹
+U+0e4b ? # Character à¹
+U+0e4c ? # Character à¹
+U+0e4d M # Character à¹
+U+0e4e ? # Character à¹
+U+0e4f * # Character à¹
+U+0e50 ? # Character à¹
+U+0e51 1 # Character à¹
+U+0e52 2 # Character à¹
+U+0e53 3 # Character à¹
+U+0e54 4 # Character à¹
+U+0e55 5 # Character à¹
+U+0e56 6 # Character à¹
+U+0e57 7 # Character à¹
+U+0e58 8 # Character à¹
+U+0e59 9 # Character à¹
+U+0e5a // # Character à¹
+U+0e5b /// # Character à¹
+U+0e5c ? # Character à¹
+U+0e5d ? # Character à¹
+U+0e5e ? # Character à¹
+U+0e5f ? # Character à¹
+U+0e60 ? # Character à¹
+U+0e61 ? # Character ๡
+U+0e62 ? # Character ๢
+U+0e63 ? # Character ๣
+U+0e64 ? # Character ๤
+U+0e65 ? # Character ๥
+U+0e66 ? # Character ๦
+U+0e67 ? # Character ๧
+U+0e68 ? # Character ๨
+U+0e69 ? # Character ๩
+U+0e6a ? # Character ๪
+U+0e6b ? # Character ๫
+U+0e6c ? # Character ๬
+U+0e6d ? # Character à¹
+U+0e6e ? # Character ๮
+U+0e6f ? # Character ๯
+U+0e70 ? # Character ๰
+U+0e71 ? # Character ๱
+U+0e72 ? # Character ๲
+U+0e73 ? # Character ๳
+U+0e74 ? # Character ๴
+U+0e75 ? # Character ๵
+U+0e76 ? # Character ๶
+U+0e77 ? # Character ๷
+U+0e78 ? # Character ๸
+U+0e79 ? # Character ๹
+U+0e7a ? # Character ๺
+U+0e7b ? # Character ๻
+U+0e7c ? # Character ๼
+U+0e7d ? # Character ๽
+U+0e7e ? # Character ๾
+U+0e7f ? # Character ๿
+U+0e80 ? # Character àº
+U+0e81 k # Character àº
+U+0e82 kh # Character àº
+U+0e83 ? # Character àº
+U+0e84 kh # Character àº
+U+0e85 ? # Character àº
+U+0e86 ? # Character àº
+U+0e87 ng # Character àº
+U+0e88 ch # Character àº
+U+0e89 ? # Character àº
+U+0e8a s # Character àº
+U+0e8b ? # Character àº
+U+0e8c ? # Character àº
+U+0e8d ny # Character àº
+U+0e8e ? # Character àº
+U+0e8f ? # Character àº
+U+0e90 ? # Character àº
+U+0e91 ? # Character àº
+U+0e92 ? # Character àº
+U+0e93 ? # Character àº
+U+0e94 d # Character àº
+U+0e95 h # Character àº
+U+0e96 th # Character àº
+U+0e97 th # Character àº
+U+0e98 ? # Character àº
+U+0e99 n # Character àº
+U+0e9a b # Character àº
+U+0e9b p # Character àº
+U+0e9c ph # Character àº
+U+0e9d f # Character àº
+U+0e9e ph # Character àº
+U+0e9f f # Character àº
+U+0ea0 ? # Character àº
+U+0ea1 m # Character ມ
+U+0ea2 y # Character ຢ
+U+0ea3 r # Character ຣ
+U+0ea4 ? # Character ຤
+U+0ea5 l # Character ລ
+U+0ea6 ? # Character ຦
+U+0ea7 w # Character ວ
+U+0ea8 ? # Character ຨ
+U+0ea9 ? # Character ຩ
+U+0eaa s # Character ສ
+U+0eab h # Character ຫ
+U+0eac ? # Character ຬ
+U+0ead ` # Character àº
+U+0eae ? # Character ຮ
+U+0eaf ~ # Character ຯ
+U+0eb0 a # Character ະ
+U+0eb1 ? # Character ັ
+U+0eb2 aa # Character າ
+U+0eb3 am # Character ຳ
+U+0eb4 i # Character ິ
+U+0eb5 ii # Character ີ
+U+0eb6 y # Character ຶ
+U+0eb7 yy # Character ື
+U+0eb8 u # Character ຸ
+U+0eb9 uu # Character ູ
+U+0eba ? # Character ຺
+U+0ebb o # Character ົ
+U+0ebc l # Character ຼ
+U+0ebd ny # Character ຽ
+U+0ebe ? # Character ຾
+U+0ebf ? # Character ຿
+U+0ec0 e # Character à»
+U+0ec1 ei # Character à»
+U+0ec2 o # Character à»
+U+0ec3 ay # Character à»
+U+0ec4 ai # Character à»
+U+0ec5 ? # Character à»
+U+0ec6 + # Character à»
+U+0ec7 ? # Character à»
+U+0ec8 ? # Character à»
+U+0ec9 ? # Character à»
+U+0eca ? # Character à»
+U+0ecb ? # Character à»
+U+0ecc ? # Character à»
+U+0ecd M # Character à»
+U+0ece ? # Character à»
+U+0ecf ? # Character à»
+U+0ed0 ? # Character à»
+U+0ed1 1 # Character à»
+U+0ed2 2 # Character à»
+U+0ed3 3 # Character à»
+U+0ed4 4 # Character à»
+U+0ed5 5 # Character à»
+U+0ed6 6 # Character à»
+U+0ed7 7 # Character à»
+U+0ed8 8 # Character à»
+U+0ed9 9 # Character à»
+U+0eda ? # Character à»
+U+0edb ? # Character à»
+U+0edc hn # Character à»
+U+0edd hm # Character à»
+U+0ede ? # Character à»
+U+0edf ? # Character à»
+U+0ee0 ? # Character à»
+U+0ee1 ? # Character ໡
+U+0ee2 ? # Character ໢
+U+0ee3 ? # Character ໣
+U+0ee4 ? # Character ໤
+U+0ee5 ? # Character ໥
+U+0ee6 ? # Character ໦
+U+0ee7 ? # Character ໧
+U+0ee8 ? # Character ໨
+U+0ee9 ? # Character ໩
+U+0eea ? # Character ໪
+U+0eeb ? # Character ໫
+U+0eec ? # Character ໬
+U+0eed ? # Character à»
+U+0eee ? # Character à»®
+U+0eef ? # Character ໯
+U+0ef0 ? # Character à»°
+U+0ef1 ? # Character à»±
+U+0ef2 ? # Character ໲
+U+0ef3 ? # Character ໳
+U+0ef4 ? # Character à»´
+U+0ef5 ? # Character ໵
+U+0ef6 ? # Character ໶
+U+0ef7 ? # Character à»·
+U+0ef8 ? # Character ໸
+U+0ef9 ? # Character ໹
+U+0efa ? # Character ໺
+U+0efb ? # Character à»»
+U+0efc ? # Character ໼
+U+0efd ? # Character ໽
+U+0efe ? # Character ໾
+U+0eff ? # Character ໿
diff --git a/resources/chars/ascii/row0f.trans b/resources/chars/ascii/row0f.trans
new file mode 100644
index 0000000..9beee63
--- /dev/null
+++ b/resources/chars/ascii/row0f.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+0f00 AUM # Character à¼
+U+0f01 ? # Character à¼
+U+0f02 ? # Character à¼
+U+0f03 ? # Character à¼
+U+0f04 ? # Character à¼
+U+0f05 ? # Character à¼
+U+0f06 ? # Character à¼
+U+0f07 ? # Character à¼
+U+0f08 // # Character à¼
+U+0f09 * # Character à¼
+U+0f0a ? # Character à¼
+U+0f0b - # Character à¼
+U+0f0c / # Character à¼
+U+0f0d / # Character à¼
+U+0f0e // # Character à¼
+U+0f0f -/ # Character à¼
+U+0f10 +/ # Character à¼
+U+0f11 X/ # Character à¼
+U+0f12 /XX/ # Character à¼
+U+0f13 /X/ # Character à¼
+U+0f14 , # Character à¼
+U+0f15 ? # Character à¼
+U+0f16 ? # Character à¼
+U+0f17 ? # Character à¼
+U+0f18 ? # Character à¼
+U+0f19 ? # Character à¼
+U+0f1a ? # Character à¼
+U+0f1b ? # Character à¼
+U+0f1c ? # Character à¼
+U+0f1d ? # Character à¼
+U+0f1e ? # Character à¼
+U+0f1f ? # Character à¼
+U+0f20 ? # Character à¼
+U+0f21 1 # Character ༡
+U+0f22 2 # Character ༢
+U+0f23 3 # Character ༣
+U+0f24 4 # Character ༤
+U+0f25 5 # Character ༥
+U+0f26 6 # Character ༦
+U+0f27 7 # Character ༧
+U+0f28 8 # Character ༨
+U+0f29 9 # Character ༩
+U+0f2a .5 # Character ༪
+U+0f2b 1.5 # Character ༫
+U+0f2c 2.5 # Character ༬
+U+0f2d 3.5 # Character à¼
+U+0f2e 4.5 # Character ༮
+U+0f2f 5.5 # Character ༯
+U+0f30 6.5 # Character ༰
+U+0f31 7.5 # Character ༱
+U+0f32 8.5 # Character ༲
+U+0f33 -.5 # Character ༳
+U+0f34 + # Character ༴
+U+0f35 * # Character ༵
+U+0f36 ^ # Character ༶
+U+0f37 _ # Character ༷
+U+0f38 ? # Character ༸
+U+0f39 ~ # Character ༹
+U+0f3a ? # Character ༺
+U+0f3b ] # Character ༻
+U+0f3c [[ # Character ༼
+U+0f3d ]] # Character ༽
+U+0f3e ? # Character ༾
+U+0f3f ? # Character ༿
+U+0f40 k # Character à½
+U+0f41 kh # Character à½
+U+0f42 g # Character à½
+U+0f43 gh # Character à½
+U+0f44 ng # Character à½
+U+0f45 c # Character à½
+U+0f46 ch # Character à½
+U+0f47 j # Character à½
+U+0f48 ? # Character à½
+U+0f49 ny # Character à½
+U+0f4a tt # Character à½
+U+0f4b tth # Character à½
+U+0f4c dd # Character à½
+U+0f4d ddh # Character à½
+U+0f4e nn # Character à½
+U+0f4f t # Character à½
+U+0f50 th # Character à½
+U+0f51 d # Character à½
+U+0f52 dh # Character à½
+U+0f53 n # Character à½
+U+0f54 p # Character à½
+U+0f55 ph # Character à½
+U+0f56 b # Character à½
+U+0f57 bh # Character à½
+U+0f58 m # Character à½
+U+0f59 ts # Character à½
+U+0f5a tsh # Character à½
+U+0f5b dz # Character à½
+U+0f5c dzh # Character à½
+U+0f5d w # Character à½
+U+0f5e zh # Character à½
+U+0f5f z # Character à½
+U+0f60 ' # Character à½
+U+0f61 y # Character ཡ
+U+0f62 r # Character ར
+U+0f63 l # Character ལ
+U+0f64 sh # Character ཤ
+U+0f65 ssh # Character ཥ
+U+0f66 s # Character ས
+U+0f67 h # Character ཧ
+U+0f68 a # Character ཨ
+U+0f69 kss # Character ཀྵ
+U+0f6a r # Character ཪ
+U+0f6b ? # Character ཫ
+U+0f6c ? # Character ཬ
+U+0f6d ? # Character à½
+U+0f6e ? # Character ཮
+U+0f6f ? # Character ཯
+U+0f70 ? # Character ཰
+U+0f71 aa # Character ཱ
+U+0f72 i # Character ི
+U+0f73 ii # Character ཱི
+U+0f74 u # Character ུ
+U+0f75 uu # Character ཱུ
+U+0f76 R # Character ྲྀ
+U+0f77 RR # Character ཷ
+U+0f78 L # Character ླྀ
+U+0f79 LL # Character ཹ
+U+0f7a e # Character ེ
+U+0f7b ee # Character ཻ
+U+0f7c o # Character ོ
+U+0f7d oo # Character ཽ
+U+0f7e M # Character ཾ
+U+0f7f H # Character ཿ
+U+0f80 i # Character à¾
+U+0f81 ii # Character à¾
+U+0f82 ? # Character à¾
+U+0f83 ? # Character à¾
+U+0f84 ? # Character à¾
+U+0f85 ? # Character à¾
+U+0f86 ? # Character à¾
+U+0f87 ? # Character à¾
+U+0f88 ? # Character à¾
+U+0f89 ? # Character à¾
+U+0f8a ? # Character à¾
+U+0f8b ? # Character à¾
+U+0f8c ? # Character à¾
+U+0f8d ? # Character à¾
+U+0f8e ? # Character à¾
+U+0f8f ? # Character à¾
+U+0f90 k # Character à¾
+U+0f91 kh # Character à¾
+U+0f92 g # Character à¾
+U+0f93 gh # Character à¾
+U+0f94 ng # Character à¾
+U+0f95 c # Character à¾
+U+0f96 ch # Character à¾
+U+0f97 j # Character à¾
+U+0f98 ? # Character à¾
+U+0f99 ny # Character à¾
+U+0f9a tt # Character à¾
+U+0f9b tth # Character à¾
+U+0f9c dd # Character à¾
+U+0f9d ddh # Character à¾
+U+0f9e nn # Character à¾
+U+0f9f t # Character à¾
+U+0fa0 th # Character à¾
+U+0fa1 d # Character ྡ
+U+0fa2 dh # Character ྡྷ
+U+0fa3 n # Character ྣ
+U+0fa4 p # Character ྤ
+U+0fa5 ph # Character ྥ
+U+0fa6 b # Character ྦ
+U+0fa7 bh # Character ྦྷ
+U+0fa8 m # Character ྨ
+U+0fa9 ts # Character ྩ
+U+0faa tsh # Character ྪ
+U+0fab dz # Character ྫ
+U+0fac dzh # Character ྫྷ
+U+0fad w # Character à¾
+U+0fae zh # Character ྮ
+U+0faf z # Character ྯ
+U+0fb0 ' # Character ྰ
+U+0fb1 y # Character ྱ
+U+0fb2 r # Character ྲ
+U+0fb3 l # Character ླ
+U+0fb4 sh # Character ྴ
+U+0fb5 ss # Character ྵ
+U+0fb6 s # Character ྶ
+U+0fb7 h # Character ྷ
+U+0fb8 a # Character ྸ
+U+0fb9 kss # Character ྐྵ
+U+0fba w # Character ྺ
+U+0fbb y # Character ྻ
+U+0fbc r # Character ྼ
+U+0fbd ? # Character ྽
+U+0fbe X # Character ྾
+U+0fbf :X: # Character ྿
+U+0fc0 /O/ # Character à¿
+U+0fc1 /o/ # Character à¿
+U+0fc2 \o\ # Character à¿
+U+0fc3 (O) # Character à¿
+U+0fc4 ? # Character à¿
+U+0fc5 ? # Character à¿
+U+0fc6 ? # Character à¿
+U+0fc7 ? # Character à¿
+U+0fc8 ? # Character à¿
+U+0fc9 ? # Character à¿
+U+0fca ? # Character à¿
+U+0fcb ? # Character à¿
+U+0fcc ? # Character à¿
+U+0fcd ? # Character à¿
+U+0fce ? # Character à¿
+U+0fcf ? # Character à¿
+U+0fd0 ? # Character à¿
+U+0fd1 ? # Character à¿
+U+0fd2 ? # Character à¿
+U+0fd3 ? # Character à¿
+U+0fd4 ? # Character à¿
+U+0fd5 ? # Character à¿
+U+0fd6 ? # Character à¿
+U+0fd7 ? # Character à¿
+U+0fd8 ? # Character à¿
+U+0fd9 ? # Character à¿
+U+0fda ? # Character à¿
+U+0fdb ? # Character à¿
+U+0fdc ? # Character à¿
+U+0fdd ? # Character à¿
+U+0fde ? # Character à¿
+U+0fdf ? # Character à¿
+U+0fe0 ? # Character à¿
+U+0fe1 ? # Character à¿¡
+U+0fe2 ? # Character à¿¢
+U+0fe3 ? # Character à¿£
+U+0fe4 ? # Character ࿤
+U+0fe5 ? # Character à¿¥
+U+0fe6 ? # Character ࿦
+U+0fe7 ? # Character ࿧
+U+0fe8 ? # Character ࿨
+U+0fe9 ? # Character à¿©
+U+0fea ? # Character ࿪
+U+0feb ? # Character à¿«
+U+0fec ? # Character ࿬
+U+0fed ? # Character à¿
+U+0fee ? # Character à¿®
+U+0fef ? # Character ࿯
+U+0ff0 ? # Character à¿°
+U+0ff1 ? # Character ࿱
+U+0ff2 ? # Character ࿲
+U+0ff3 ? # Character ࿳
+U+0ff4 ? # Character à¿´
+U+0ff5 ? # Character ࿵
+U+0ff6 ? # Character ࿶
+U+0ff7 ? # Character à¿·
+U+0ff8 ? # Character ࿸
+U+0ff9 ? # Character ࿹
+U+0ffa ? # Character ࿺
+U+0ffb ? # Character à¿»
+U+0ffc ? # Character ࿼
+U+0ffd ? # Character ࿽
+U+0ffe ? # Character ࿾
+U+0fff ? # Character à¿¿
diff --git a/resources/chars/ascii/row10.trans b/resources/chars/ascii/row10.trans
new file mode 100644
index 0000000..882eddf
--- /dev/null
+++ b/resources/chars/ascii/row10.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+1000 k # Character á
+U+1001 kh # Character á
+U+1002 g # Character á
+U+1003 gh # Character á
+U+1004 ng # Character á
+U+1005 c # Character á
+U+1006 ch # Character á
+U+1007 j # Character á
+U+1008 jh # Character á
+U+1009 ny # Character á
+U+100a nny # Character á
+U+100b tt # Character á
+U+100c tth # Character á
+U+100d dd # Character á
+U+100e ddh # Character á
+U+100f nn # Character á
+U+1010 tt # Character á
+U+1011 th # Character á
+U+1012 d # Character á
+U+1013 dh # Character á
+U+1014 n # Character á
+U+1015 p # Character á
+U+1016 ph # Character á
+U+1017 b # Character á
+U+1018 bh # Character á
+U+1019 m # Character á
+U+101a y # Character á
+U+101b r # Character á
+U+101c l # Character á
+U+101d w # Character á
+U+101e s # Character á
+U+101f h # Character á
+U+1020 ll # Character á
+U+1021 a # Character á¡
+U+1022 ? # Character á¢
+U+1023 i # Character á£
+U+1024 ii # Character á¤
+U+1025 u # Character á¥
+U+1026 uu # Character á¦
+U+1027 e # Character á§
+U+1028 ? # Character á¨
+U+1029 o # Character á©
+U+102a au # Character áª
+U+102b ? # Character á«
+U+102c aa # Character á¬
+U+102d i # Character á
+U+102e ii # Character á®
+U+102f u # Character á¯
+U+1030 uu # Character á°
+U+1031 e # Character á±
+U+1032 ai # Character á²
+U+1033 ? # Character á³
+U+1034 ? # Character á´
+U+1035 ? # Character áµ
+U+1036 N # Character á¶
+U+1037 ' # Character á·
+U+1038 : # Character á¸
+U+1039 ? # Character á¹
+U+103a ? # Character áº
+U+103b ? # Character á»
+U+103c ? # Character á¼
+U+103d ? # Character á½
+U+103e ? # Character á¾
+U+103f ? # Character á¿
+U+1040 ? # Character á
+U+1041 1 # Character á
+U+1042 2 # Character á
+U+1043 3 # Character á
+U+1044 4 # Character á
+U+1045 5 # Character á
+U+1046 6 # Character á
+U+1047 7 # Character á
+U+1048 8 # Character á
+U+1049 9 # Character á
+U+104a / # Character á
+U+104b // # Character á
+U+104c n* # Character á
+U+104d r* # Character á
+U+104e l* # Character á
+U+104f e* # Character á
+U+1050 sh # Character á
+U+1051 ss # Character á
+U+1052 R # Character á
+U+1053 RR # Character á
+U+1054 L # Character á
+U+1055 LL # Character á
+U+1056 R # Character á
+U+1057 RR # Character á
+U+1058 L # Character á
+U+1059 LL # Character á
+U+105a ? # Character á
+U+105b ? # Character á
+U+105c ? # Character á
+U+105d ? # Character á
+U+105e ? # Character á
+U+105f ? # Character á
+U+1060 ? # Character á
+U+1061 ? # Character á¡
+U+1062 ? # Character á¢
+U+1063 ? # Character á£
+U+1064 ? # Character á¤
+U+1065 ? # Character á¥
+U+1066 ? # Character á¦
+U+1067 ? # Character á§
+U+1068 ? # Character á¨
+U+1069 ? # Character á©
+U+106a ? # Character áª
+U+106b ? # Character á«
+U+106c ? # Character á¬
+U+106d ? # Character á
+U+106e ? # Character á®
+U+106f ? # Character á¯
+U+1070 ? # Character á°
+U+1071 ? # Character á±
+U+1072 ? # Character á²
+U+1073 ? # Character á³
+U+1074 ? # Character á´
+U+1075 ? # Character áµ
+U+1076 ? # Character á¶
+U+1077 ? # Character á·
+U+1078 ? # Character á¸
+U+1079 ? # Character á¹
+U+107a ? # Character áº
+U+107b ? # Character á»
+U+107c ? # Character á¼
+U+107d ? # Character á½
+U+107e ? # Character á¾
+U+107f ? # Character á¿
+U+1080 ? # Character á
+U+1081 ? # Character á
+U+1082 ? # Character á
+U+1083 ? # Character á
+U+1084 ? # Character á
+U+1085 ? # Character á
+U+1086 ? # Character á
+U+1087 ? # Character á
+U+1088 ? # Character á
+U+1089 ? # Character á
+U+108a ? # Character á
+U+108b ? # Character á
+U+108c ? # Character á
+U+108d ? # Character á
+U+108e ? # Character á
+U+108f ? # Character á
+U+1090 ? # Character á
+U+1091 ? # Character á
+U+1092 ? # Character á
+U+1093 ? # Character á
+U+1094 ? # Character á
+U+1095 ? # Character á
+U+1096 ? # Character á
+U+1097 ? # Character á
+U+1098 ? # Character á
+U+1099 ? # Character á
+U+109a ? # Character á
+U+109b ? # Character á
+U+109c ? # Character á
+U+109d ? # Character á
+U+109e ? # Character á
+U+109f ? # Character á
+U+10a0 A # Character á
+U+10a1 B # Character á¡
+U+10a2 G # Character á¢
+U+10a3 D # Character á£
+U+10a4 E # Character á¤
+U+10a5 V # Character á¥
+U+10a6 Z # Character á¦
+U+10a7 T` # Character á§
+U+10a8 I # Character á¨
+U+10a9 K # Character á©
+U+10aa L # Character áª
+U+10ab M # Character á«
+U+10ac N # Character á¬
+U+10ad O # Character á
+U+10ae P # Character á®
+U+10af Zh # Character á¯
+U+10b0 R # Character á°
+U+10b1 S # Character á±
+U+10b2 T # Character á²
+U+10b3 U # Character á³
+U+10b4 P` # Character á´
+U+10b5 K` # Character áµ
+U+10b6 G' # Character á¶
+U+10b7 Q # Character á·
+U+10b8 Sh # Character á¸
+U+10b9 Ch` # Character á¹
+U+10ba C` # Character áº
+U+10bb Z' # Character á»
+U+10bc C # Character á¼
+U+10bd Ch # Character á½
+U+10be X # Character á¾
+U+10bf J # Character á¿
+U+10c0 H # Character á
+U+10c1 E # Character á
+U+10c2 Y # Character á
+U+10c3 W # Character á
+U+10c4 Xh # Character á
+U+10c5 OE # Character á
+U+10c6 ? # Character á
+U+10c7 ? # Character á
+U+10c8 ? # Character á
+U+10c9 ? # Character á
+U+10ca ? # Character á
+U+10cb ? # Character á
+U+10cc ? # Character á
+U+10cd ? # Character á
+U+10ce ? # Character á
+U+10cf ? # Character á
+U+10d0 a # Character á
+U+10d1 b # Character á
+U+10d2 g # Character á
+U+10d3 d # Character á
+U+10d4 e # Character á
+U+10d5 v # Character á
+U+10d6 z # Character á
+U+10d7 t` # Character á
+U+10d8 i # Character á
+U+10d9 k # Character á
+U+10da l # Character á
+U+10db m # Character á
+U+10dc n # Character á
+U+10dd o # Character á
+U+10de p # Character á
+U+10df zh # Character á
+U+10e0 r # Character á
+U+10e1 s # Character á¡
+U+10e2 t # Character á¢
+U+10e3 u # Character á£
+U+10e4 p` # Character á¤
+U+10e5 k` # Character á¥
+U+10e6 g' # Character á¦
+U+10e7 q # Character á§
+U+10e8 sh # Character á¨
+U+10e9 ch` # Character á©
+U+10ea c` # Character áª
+U+10eb z' # Character á«
+U+10ec c # Character á¬
+U+10ed ch # Character á
+U+10ee x # Character á®
+U+10ef j # Character á¯
+U+10f0 h # Character á°
+U+10f1 e # Character á±
+U+10f2 y # Character á²
+U+10f3 w # Character á³
+U+10f4 xh # Character á´
+U+10f5 oe # Character áµ
+U+10f6 f # Character á¶
+U+10f7 ? # Character á·
+U+10f8 ? # Character á¸
+U+10f9 ? # Character á¹
+U+10fa ? # Character áº
+U+10fb // # Character á»
+U+10fc ? # Character á¼
+U+10fd ? # Character á½
+U+10fe ? # Character á¾
+U+10ff ? # Character á¿
diff --git a/resources/chars/ascii/row11.trans b/resources/chars/ascii/row11.trans
new file mode 100644
index 0000000..14bf5df
--- /dev/null
+++ b/resources/chars/ascii/row11.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+1100 g # Character á
+U+1101 gg # Character á
+U+1102 n # Character á
+U+1103 d # Character á
+U+1104 dd # Character á
+U+1105 r # Character á
+U+1106 m # Character á
+U+1107 b # Character á
+U+1108 bb # Character á
+U+1109 s # Character á
+U+110a ss # Character á
+U+110b ? # Character á
+U+110c j # Character á
+U+110d jj # Character á
+U+110e c # Character á
+U+110f k # Character á
+U+1110 t # Character á
+U+1111 p # Character á
+U+1112 h # Character á
+U+1113 ng # Character á
+U+1114 nn # Character á
+U+1115 nd # Character á
+U+1116 nb # Character á
+U+1117 dg # Character á
+U+1118 rn # Character á
+U+1119 rr # Character á
+U+111a rh # Character á
+U+111b rN # Character á
+U+111c mb # Character á
+U+111d mN # Character á
+U+111e bg # Character á
+U+111f bn # Character á
+U+1120 ? # Character á
+U+1121 bs # Character á¡
+U+1122 bsg # Character á¢
+U+1123 bst # Character á£
+U+1124 bsb # Character á¤
+U+1125 bss # Character á¥
+U+1126 bsj # Character á¦
+U+1127 bj # Character á§
+U+1128 bc # Character á¨
+U+1129 bt # Character á©
+U+112a bp # Character áª
+U+112b bN # Character á«
+U+112c bbN # Character á¬
+U+112d sg # Character á
+U+112e sn # Character á®
+U+112f sd # Character á¯
+U+1130 sr # Character á°
+U+1131 sm # Character á±
+U+1132 sb # Character á²
+U+1133 sbg # Character á³
+U+1134 sss # Character á´
+U+1135 s # Character áµ
+U+1136 sj # Character á¶
+U+1137 sc # Character á·
+U+1138 sk # Character á¸
+U+1139 st # Character á¹
+U+113a sp # Character áº
+U+113b sh # Character á»
+U+113c ? # Character á¼
+U+113d ? # Character á½
+U+113e ? # Character á¾
+U+113f ? # Character á¿
+U+1140 Z # Character á
+U+1141 g # Character á
+U+1142 d # Character á
+U+1143 m # Character á
+U+1144 b # Character á
+U+1145 s # Character á
+U+1146 Z # Character á
+U+1147 ? # Character á
+U+1148 j # Character á
+U+1149 c # Character á
+U+114a t # Character á
+U+114b p # Character á
+U+114c N # Character á
+U+114d j # Character á
+U+114e ? # Character á
+U+114f ? # Character á
+U+1150 ? # Character á
+U+1151 ? # Character á
+U+1152 ck # Character á
+U+1153 ch # Character á
+U+1154 ? # Character á
+U+1155 ? # Character á
+U+1156 pb # Character á
+U+1157 pN # Character á
+U+1158 hh # Character á
+U+1159 Q # Character á
+U+115a ? # Character á
+U+115b ? # Character á
+U+115c ? # Character á
+U+115d ? # Character á
+U+115e ? # Character á
+U+115f ? # Character á
+U+1160 ? # Character á
+U+1161 a # Character á
¡
+U+1162 ae # Character á
¢
+U+1163 ya # Character á
£
+U+1164 yae # Character á
¤
+U+1165 eo # Character á
¥
+U+1166 e # Character á
¦
+U+1167 yeo # Character á
§
+U+1168 ye # Character á
¨
+U+1169 o # Character á
©
+U+116a wa # Character á
ª
+U+116b wae # Character á
«
+U+116c oe # Character á
¬
+U+116d yo # Character á
+U+116e u # Character á
®
+U+116f weo # Character á
¯
+U+1170 we # Character á
°
+U+1171 wi # Character á
±
+U+1172 yu # Character á
²
+U+1173 eu # Character á
³
+U+1174 yi # Character á
´
+U+1175 i # Character á
µ
+U+1176 a-o # Character á
¶
+U+1177 a-u # Character á
·
+U+1178 ya-o # Character á
¸
+U+1179 ya-yo # Character á
¹
+U+117a eo-o # Character á
º
+U+117b eo-u # Character á
»
+U+117c eo-eu # Character á
¼
+U+117d yeo-o # Character á
½
+U+117e yeo-u # Character á
¾
+U+117f o-eo # Character á
¿
+U+1180 o-e # Character á
+U+1181 o-ye # Character á
+U+1182 o-o # Character á
+U+1183 o-u # Character á
+U+1184 yo-ya # Character á
+U+1185 yo-yae # Character á
+U+1186 yo-yeo # Character á
+U+1187 yo-o # Character á
+U+1188 yo-i # Character á
+U+1189 u-a # Character á
+U+118a u-ae # Character á
+U+118b u-eo-eu # Character á
+U+118c u-ye # Character á
+U+118d u-u # Character á
+U+118e yu-a # Character á
+U+118f yu-eo # Character á
+U+1190 yu-e # Character á
+U+1191 yu-yeo # Character á
+U+1192 yu-ye # Character á
+U+1193 yu-u # Character á
+U+1194 yu-i # Character á
+U+1195 eu-u # Character á
+U+1196 eu-eu # Character á
+U+1197 yi-u # Character á
+U+1198 i-a # Character á
+U+1199 i-ya # Character á
+U+119a i-o # Character á
+U+119b i-u # Character á
+U+119c i-eu # Character á
+U+119d i-U # Character á
+U+119e U # Character á
+U+119f U-eo # Character á
+U+11a0 U-u # Character á
+U+11a1 U-i # Character á¡
+U+11a2 UU # Character á¢
+U+11a3 ? # Character á£
+U+11a4 ? # Character á¤
+U+11a5 ? # Character á¥
+U+11a6 ? # Character á¦
+U+11a7 ? # Character á§
+U+11a8 g # Character á¨
+U+11a9 gg # Character á©
+U+11aa gs # Character áª
+U+11ab n # Character á«
+U+11ac nj # Character á¬
+U+11ad nh # Character á
+U+11ae d # Character á®
+U+11af l # Character á¯
+U+11b0 lg # Character á°
+U+11b1 lm # Character á±
+U+11b2 lb # Character á²
+U+11b3 ls # Character á³
+U+11b4 lt # Character á´
+U+11b5 lp # Character áµ
+U+11b6 lh # Character á¶
+U+11b7 m # Character á·
+U+11b8 b # Character á¸
+U+11b9 bs # Character á¹
+U+11ba s # Character áº
+U+11bb ss # Character á»
+U+11bc ng # Character á¼
+U+11bd j # Character á½
+U+11be c # Character á¾
+U+11bf k # Character á¿
+U+11c0 t # Character á
+U+11c1 p # Character á
+U+11c2 h # Character á
+U+11c3 gl # Character á
+U+11c4 gsg # Character á
+U+11c5 ng # Character á
+U+11c6 nd # Character á
+U+11c7 ns # Character á
+U+11c8 nZ # Character á
+U+11c9 nt # Character á
+U+11ca dg # Character á
+U+11cb tl # Character á
+U+11cc lgs # Character á
+U+11cd ln # Character á
+U+11ce ld # Character á
+U+11cf lth # Character á
+U+11d0 ll # Character á
+U+11d1 lmg # Character á
+U+11d2 lms # Character á
+U+11d3 lbs # Character á
+U+11d4 lbh # Character á
+U+11d5 rNp # Character á
+U+11d6 lss # Character á
+U+11d7 lZ # Character á
+U+11d8 lk # Character á
+U+11d9 lQ # Character á
+U+11da mg # Character á
+U+11db ml # Character á
+U+11dc mb # Character á
+U+11dd ms # Character á
+U+11de mss # Character á
+U+11df mZ # Character á
+U+11e0 mc # Character á
+U+11e1 mh # Character á¡
+U+11e2 mN # Character á¢
+U+11e3 bl # Character á£
+U+11e4 bp # Character á¤
+U+11e5 ph # Character á¥
+U+11e6 pN # Character á¦
+U+11e7 sg # Character á§
+U+11e8 sd # Character á¨
+U+11e9 sl # Character á©
+U+11ea sb # Character áª
+U+11eb Z # Character á«
+U+11ec g # Character á¬
+U+11ed ss # Character á
+U+11ee ? # Character á®
+U+11ef kh # Character á¯
+U+11f0 N # Character á°
+U+11f1 Ns # Character á±
+U+11f2 NZ # Character á²
+U+11f3 pb # Character á³
+U+11f4 pN # Character á´
+U+11f5 hn # Character áµ
+U+11f6 hl # Character á¶
+U+11f7 hm # Character á·
+U+11f8 hb # Character á¸
+U+11f9 Q # Character á¹
+U+11fa ? # Character áº
+U+11fb ? # Character á»
+U+11fc ? # Character á¼
+U+11fd ? # Character á½
+U+11fe ? # Character á¾
+U+11ff ? # Character á¿
diff --git a/resources/chars/ascii/row12.trans b/resources/chars/ascii/row12.trans
new file mode 100644
index 0000000..c486116
--- /dev/null
+++ b/resources/chars/ascii/row12.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+1200 ha # Character á
+U+1201 hu # Character á
+U+1202 hi # Character á
+U+1203 haa # Character á
+U+1204 hee # Character á
+U+1205 he # Character á
+U+1206 ho # Character á
+U+1207 ? # Character á
+U+1208 la # Character á
+U+1209 lu # Character á
+U+120a li # Character á
+U+120b laa # Character á
+U+120c lee # Character á
+U+120d le # Character á
+U+120e lo # Character á
+U+120f lwa # Character á
+U+1210 hha # Character á
+U+1211 hhu # Character á
+U+1212 hhi # Character á
+U+1213 hhaa # Character á
+U+1214 hhee # Character á
+U+1215 hhe # Character á
+U+1216 hho # Character á
+U+1217 hhwa # Character á
+U+1218 ma # Character á
+U+1219 mu # Character á
+U+121a mi # Character á
+U+121b maa # Character á
+U+121c mee # Character á
+U+121d me # Character á
+U+121e mo # Character á
+U+121f mwa # Character á
+U+1220 sza # Character á
+U+1221 szu # Character á¡
+U+1222 szi # Character á¢
+U+1223 szaa # Character á£
+U+1224 szee # Character á¤
+U+1225 sze # Character á¥
+U+1226 szo # Character á¦
+U+1227 szwa # Character á§
+U+1228 ra # Character á¨
+U+1229 ru # Character á©
+U+122a ri # Character áª
+U+122b raa # Character á«
+U+122c ree # Character á¬
+U+122d re # Character á
+U+122e ro # Character á®
+U+122f rwa # Character á¯
+U+1230 sa # Character á°
+U+1231 su # Character á±
+U+1232 si # Character á²
+U+1233 saa # Character á³
+U+1234 see # Character á´
+U+1235 se # Character áµ
+U+1236 so # Character á¶
+U+1237 swa # Character á·
+U+1238 sha # Character á¸
+U+1239 shu # Character á¹
+U+123a shi # Character áº
+U+123b shaa # Character á»
+U+123c shee # Character á¼
+U+123d she # Character á½
+U+123e sho # Character á¾
+U+123f shwa # Character á¿
+U+1240 qa # Character á
+U+1241 qu # Character á
+U+1242 qi # Character á
+U+1243 qaa # Character á
+U+1244 qee # Character á
+U+1245 qe # Character á
+U+1246 qo # Character á
+U+1247 ? # Character á
+U+1248 qwa # Character á
+U+1249 ? # Character á
+U+124a qwi # Character á
+U+124b qwaa # Character á
+U+124c qwee # Character á
+U+124d qwe # Character á
+U+124e ? # Character á
+U+124f ? # Character á
+U+1250 qha # Character á
+U+1251 qhu # Character á
+U+1252 qhi # Character á
+U+1253 qhaa # Character á
+U+1254 qhee # Character á
+U+1255 qhe # Character á
+U+1256 qho # Character á
+U+1257 ? # Character á
+U+1258 qhwa # Character á
+U+1259 ? # Character á
+U+125a qhwi # Character á
+U+125b qhwaa # Character á
+U+125c qhwee # Character á
+U+125d qhwe # Character á
+U+125e ? # Character á
+U+125f ? # Character á
+U+1260 ba # Character á
+U+1261 bu # Character á¡
+U+1262 bi # Character á¢
+U+1263 baa # Character á£
+U+1264 bee # Character á¤
+U+1265 be # Character á¥
+U+1266 bo # Character á¦
+U+1267 bwa # Character á§
+U+1268 va # Character á¨
+U+1269 vu # Character á©
+U+126a vi # Character áª
+U+126b vaa # Character á«
+U+126c vee # Character á¬
+U+126d ve # Character á
+U+126e vo # Character á®
+U+126f vwa # Character á¯
+U+1270 ta # Character á°
+U+1271 tu # Character á±
+U+1272 ti # Character á²
+U+1273 taa # Character á³
+U+1274 tee # Character á´
+U+1275 te # Character áµ
+U+1276 to # Character á¶
+U+1277 twa # Character á·
+U+1278 ca # Character á¸
+U+1279 cu # Character á¹
+U+127a ci # Character áº
+U+127b caa # Character á»
+U+127c cee # Character á¼
+U+127d ce # Character á½
+U+127e co # Character á¾
+U+127f cwa # Character á¿
+U+1280 xa # Character á
+U+1281 xu # Character á
+U+1282 xi # Character á
+U+1283 xaa # Character á
+U+1284 xee # Character á
+U+1285 xe # Character á
+U+1286 xo # Character á
+U+1287 ? # Character á
+U+1288 xwa # Character á
+U+1289 ? # Character á
+U+128a xwi # Character á
+U+128b xwaa # Character á
+U+128c xwee # Character á
+U+128d xwe # Character á
+U+128e ? # Character á
+U+128f ? # Character á
+U+1290 na # Character á
+U+1291 nu # Character á
+U+1292 ni # Character á
+U+1293 naa # Character á
+U+1294 nee # Character á
+U+1295 ne # Character á
+U+1296 no # Character á
+U+1297 nwa # Character á
+U+1298 nya # Character á
+U+1299 nyu # Character á
+U+129a nyi # Character á
+U+129b nyaa # Character á
+U+129c nyee # Character á
+U+129d nye # Character á
+U+129e nyo # Character á
+U+129f nywa # Character á
+U+12a0 'a # Character á
+U+12a1 'u # Character á¡
+U+12a2 ? # Character á¢
+U+12a3 'aa # Character á£
+U+12a4 'ee # Character á¤
+U+12a5 'e # Character á¥
+U+12a6 'o # Character á¦
+U+12a7 'wa # Character á§
+U+12a8 ka # Character á¨
+U+12a9 ku # Character á©
+U+12aa ki # Character áª
+U+12ab kaa # Character á«
+U+12ac kee # Character á¬
+U+12ad ke # Character á
+U+12ae ko # Character á®
+U+12af ? # Character á¯
+U+12b0 kwa # Character á°
+U+12b1 ? # Character á±
+U+12b2 kwi # Character á²
+U+12b3 kwaa # Character á³
+U+12b4 kwee # Character á´
+U+12b5 kwe # Character áµ
+U+12b6 ? # Character á¶
+U+12b7 ? # Character á·
+U+12b8 kxa # Character á¸
+U+12b9 kxu # Character á¹
+U+12ba kxi # Character áº
+U+12bb kxaa # Character á»
+U+12bc kxee # Character á¼
+U+12bd kxe # Character á½
+U+12be kxo # Character á¾
+U+12bf ? # Character á¿
+U+12c0 kxwa # Character á
+U+12c1 ? # Character á
+U+12c2 kxwi # Character á
+U+12c3 kxwaa # Character á
+U+12c4 kxwee # Character á
+U+12c5 kxwe # Character á
+U+12c6 ? # Character á
+U+12c7 ? # Character á
+U+12c8 wa # Character á
+U+12c9 wu # Character á
+U+12ca wi # Character á
+U+12cb waa # Character á
+U+12cc wee # Character á
+U+12cd we # Character á
+U+12ce wo # Character á
+U+12cf ? # Character á
+U+12d0 `a # Character á
+U+12d1 `u # Character á
+U+12d2 `i # Character á
+U+12d3 `aa # Character á
+U+12d4 `ee # Character á
+U+12d5 `e # Character á
+U+12d6 `o # Character á
+U+12d7 ? # Character á
+U+12d8 za # Character á
+U+12d9 zu # Character á
+U+12da zi # Character á
+U+12db zaa # Character á
+U+12dc zee # Character á
+U+12dd ze # Character á
+U+12de zo # Character á
+U+12df zwa # Character á
+U+12e0 zha # Character á
+U+12e1 zhu # Character á¡
+U+12e2 zhi # Character á¢
+U+12e3 zhaa # Character á£
+U+12e4 zhee # Character á¤
+U+12e5 zhe # Character á¥
+U+12e6 zho # Character á¦
+U+12e7 zhwa # Character á§
+U+12e8 ya # Character á¨
+U+12e9 yu # Character á©
+U+12ea yi # Character áª
+U+12eb yaa # Character á«
+U+12ec yee # Character á¬
+U+12ed ye # Character á
+U+12ee yo # Character á®
+U+12ef ? # Character á¯
+U+12f0 da # Character á°
+U+12f1 du # Character á±
+U+12f2 di # Character á²
+U+12f3 daa # Character á³
+U+12f4 dee # Character á´
+U+12f5 de # Character áµ
+U+12f6 do # Character á¶
+U+12f7 dwa # Character á·
+U+12f8 dda # Character á¸
+U+12f9 ddu # Character á¹
+U+12fa ddi # Character áº
+U+12fb ddaa # Character á»
+U+12fc ddee # Character á¼
+U+12fd dde # Character á½
+U+12fe ddo # Character á¾
+U+12ff ddwa # Character á¿
diff --git a/resources/chars/ascii/row13.trans b/resources/chars/ascii/row13.trans
new file mode 100644
index 0000000..bd10510
--- /dev/null
+++ b/resources/chars/ascii/row13.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+1300 ja # Character á
+U+1301 ju # Character á
+U+1302 ji # Character á
+U+1303 jaa # Character á
+U+1304 jee # Character á
+U+1305 je # Character á
+U+1306 jo # Character á
+U+1307 jwa # Character á
+U+1308 ga # Character á
+U+1309 gu # Character á
+U+130a gi # Character á
+U+130b gaa # Character á
+U+130c gee # Character á
+U+130d ge # Character á
+U+130e go # Character á
+U+130f ? # Character á
+U+1310 gwa # Character á
+U+1311 ? # Character á
+U+1312 gwi # Character á
+U+1313 gwaa # Character á
+U+1314 gwee # Character á
+U+1315 gwe # Character á
+U+1316 ? # Character á
+U+1317 ? # Character á
+U+1318 gga # Character á
+U+1319 ggu # Character á
+U+131a ggi # Character á
+U+131b ggaa # Character á
+U+131c ggee # Character á
+U+131d gge # Character á
+U+131e ggo # Character á
+U+131f ? # Character á
+U+1320 tha # Character á
+U+1321 thu # Character á¡
+U+1322 thi # Character á¢
+U+1323 thaa # Character á£
+U+1324 thee # Character á¤
+U+1325 the # Character á¥
+U+1326 tho # Character á¦
+U+1327 thwa # Character á§
+U+1328 cha # Character á¨
+U+1329 chu # Character á©
+U+132a chi # Character áª
+U+132b chaa # Character á«
+U+132c chee # Character á¬
+U+132d che # Character á
+U+132e cho # Character á®
+U+132f chwa # Character á¯
+U+1330 pha # Character á°
+U+1331 phu # Character á±
+U+1332 phi # Character á²
+U+1333 phaa # Character á³
+U+1334 phee # Character á´
+U+1335 phe # Character áµ
+U+1336 pho # Character á¶
+U+1337 phwa # Character á·
+U+1338 tsa # Character á¸
+U+1339 tsu # Character á¹
+U+133a tsi # Character áº
+U+133b tsaa # Character á»
+U+133c tsee # Character á¼
+U+133d tse # Character á½
+U+133e tso # Character á¾
+U+133f tswa # Character á¿
+U+1340 tza # Character á
+U+1341 tzu # Character á
+U+1342 tzi # Character á
+U+1343 tzaa # Character á
+U+1344 tzee # Character á
+U+1345 tze # Character á
+U+1346 tzo # Character á
+U+1347 ? # Character á
+U+1348 fa # Character á
+U+1349 fu # Character á
+U+134a fi # Character á
+U+134b faa # Character á
+U+134c fee # Character á
+U+134d fe # Character á
+U+134e fo # Character á
+U+134f fwa # Character á
+U+1350 pa # Character á
+U+1351 pu # Character á
+U+1352 pi # Character á
+U+1353 paa # Character á
+U+1354 pee # Character á
+U+1355 pe # Character á
+U+1356 po # Character á
+U+1357 pwa # Character á
+U+1358 rya # Character á
+U+1359 mya # Character á
+U+135a fya # Character á
+U+135b ? # Character á
+U+135c ? # Character á
+U+135d ? # Character á
+U+135e ? # Character á
+U+135f ? # Character á
+U+1360 ? # Character á
+U+1361 # Character á¡
+U+1362 . # Character á¢
+U+1363 , # Character á£
+U+1364 ; # Character á¤
+U+1365 : # Character á¥
+U+1366 :: # Character á¦
+U+1367 ? # Character á§
+U+1368 // # Character á¨
+U+1369 1 # Character á©
+U+136a 2 # Character áª
+U+136b 3 # Character á«
+U+136c 4 # Character á¬
+U+136d 5 # Character á
+U+136e 6 # Character á®
+U+136f 7 # Character á¯
+U+1370 8 # Character á°
+U+1371 9 # Character á±
+U+1372 10+ # Character á²
+U+1373 20+ # Character á³
+U+1374 30+ # Character á´
+U+1375 40+ # Character áµ
+U+1376 50+ # Character á¶
+U+1377 60+ # Character á·
+U+1378 70+ # Character á¸
+U+1379 80+ # Character á¹
+U+137a 90+ # Character áº
+U+137b 100+ # Character á»
+U+137c 10,000+ # Character á¼
+U+137d ? # Character á½
+U+137e ? # Character á¾
+U+137f ? # Character á¿
+U+1380 ? # Character á
+U+1381 ? # Character á
+U+1382 ? # Character á
+U+1383 ? # Character á
+U+1384 ? # Character á
+U+1385 ? # Character á
+U+1386 ? # Character á
+U+1387 ? # Character á
+U+1388 ? # Character á
+U+1389 ? # Character á
+U+138a ? # Character á
+U+138b ? # Character á
+U+138c ? # Character á
+U+138d ? # Character á
+U+138e ? # Character á
+U+138f ? # Character á
+U+1390 ? # Character á
+U+1391 ? # Character á
+U+1392 ? # Character á
+U+1393 ? # Character á
+U+1394 ? # Character á
+U+1395 ? # Character á
+U+1396 ? # Character á
+U+1397 ? # Character á
+U+1398 ? # Character á
+U+1399 ? # Character á
+U+139a ? # Character á
+U+139b ? # Character á
+U+139c ? # Character á
+U+139d ? # Character á
+U+139e ? # Character á
+U+139f ? # Character á
+U+13a0 a # Character á
+U+13a1 e # Character á¡
+U+13a2 i # Character á¢
+U+13a3 o # Character á£
+U+13a4 u # Character á¤
+U+13a5 v # Character á¥
+U+13a6 ga # Character á¦
+U+13a7 ka # Character á§
+U+13a8 ge # Character á¨
+U+13a9 gi # Character á©
+U+13aa go # Character áª
+U+13ab gu # Character á«
+U+13ac gv # Character á¬
+U+13ad ha # Character á
+U+13ae he # Character á®
+U+13af hi # Character á¯
+U+13b0 ho # Character á°
+U+13b1 hu # Character á±
+U+13b2 hv # Character á²
+U+13b3 la # Character á³
+U+13b4 le # Character á´
+U+13b5 li # Character áµ
+U+13b6 lo # Character á¶
+U+13b7 lu # Character á·
+U+13b8 lv # Character á¸
+U+13b9 ma # Character á¹
+U+13ba me # Character áº
+U+13bb mi # Character á»
+U+13bc mo # Character á¼
+U+13bd mu # Character á½
+U+13be na # Character á¾
+U+13bf hna # Character á¿
+U+13c0 nah # Character á
+U+13c1 ne # Character á
+U+13c2 ni # Character á
+U+13c3 no # Character á
+U+13c4 nu # Character á
+U+13c5 nv # Character á
+U+13c6 qua # Character á
+U+13c7 que # Character á
+U+13c8 qui # Character á
+U+13c9 quo # Character á
+U+13ca quu # Character á
+U+13cb quv # Character á
+U+13cc sa # Character á
+U+13cd s # Character á
+U+13ce se # Character á
+U+13cf si # Character á
+U+13d0 so # Character á
+U+13d1 su # Character á
+U+13d2 sv # Character á
+U+13d3 da # Character á
+U+13d4 ta # Character á
+U+13d5 de # Character á
+U+13d6 te # Character á
+U+13d7 di # Character á
+U+13d8 ti # Character á
+U+13d9 do # Character á
+U+13da du # Character á
+U+13db dv # Character á
+U+13dc dla # Character á
+U+13dd tla # Character á
+U+13de tle # Character á
+U+13df tli # Character á
+U+13e0 tlo # Character á
+U+13e1 tlu # Character á¡
+U+13e2 tlv # Character á¢
+U+13e3 tsa # Character á£
+U+13e4 tse # Character á¤
+U+13e5 tsi # Character á¥
+U+13e6 tso # Character á¦
+U+13e7 tsu # Character á§
+U+13e8 tsv # Character á¨
+U+13e9 wa # Character á©
+U+13ea we # Character áª
+U+13eb wi # Character á«
+U+13ec wo # Character á¬
+U+13ed wu # Character á
+U+13ee wv # Character á®
+U+13ef ya # Character á¯
+U+13f0 ye # Character á°
+U+13f1 yi # Character á±
+U+13f2 yo # Character á²
+U+13f3 yu # Character á³
+U+13f4 yv # Character á´
+U+13f5 ? # Character áµ
+U+13f6 ? # Character á¶
+U+13f7 ? # Character á·
+U+13f8 ? # Character á¸
+U+13f9 ? # Character á¹
+U+13fa ? # Character áº
+U+13fb ? # Character á»
+U+13fc ? # Character á¼
+U+13fd ? # Character á½
+U+13fe ? # Character á¾
+U+13ff ? # Character á¿
diff --git a/resources/chars/ascii/row14.trans b/resources/chars/ascii/row14.trans
new file mode 100644
index 0000000..31648de
--- /dev/null
+++ b/resources/chars/ascii/row14.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+1400 ? # Character á
+U+1401 e # Character á
+U+1402 aai # Character á
+U+1403 i # Character á
+U+1404 ii # Character á
+U+1405 o # Character á
+U+1406 oo # Character á
+U+1407 oo # Character á
+U+1408 ee # Character á
+U+1409 i # Character á
+U+140a a # Character á
+U+140b aa # Character á
+U+140c we # Character á
+U+140d we # Character á
+U+140e wi # Character á
+U+140f wi # Character á
+U+1410 wii # Character á
+U+1411 wii # Character á
+U+1412 wo # Character á
+U+1413 wo # Character á
+U+1414 woo # Character á
+U+1415 woo # Character á
+U+1416 woo # Character á
+U+1417 wa # Character á
+U+1418 wa # Character á
+U+1419 waa # Character á
+U+141a waa # Character á
+U+141b waa # Character á
+U+141c ai # Character á
+U+141d w # Character á
+U+141e ' # Character á
+U+141f t # Character á
+U+1420 k # Character á
+U+1421 sh # Character á¡
+U+1422 s # Character á¢
+U+1423 n # Character á£
+U+1424 w # Character á¤
+U+1425 n # Character á¥
+U+1426 ? # Character á¦
+U+1427 w # Character á§
+U+1428 c # Character á¨
+U+1429 ? # Character á©
+U+142a l # Character áª
+U+142b en # Character á«
+U+142c in # Character á¬
+U+142d on # Character á
+U+142e an # Character á®
+U+142f pe # Character á¯
+U+1430 paai # Character á°
+U+1431 pi # Character á±
+U+1432 pii # Character á²
+U+1433 po # Character á³
+U+1434 poo # Character á´
+U+1435 poo # Character áµ
+U+1436 hee # Character á¶
+U+1437 hi # Character á·
+U+1438 pa # Character á¸
+U+1439 paa # Character á¹
+U+143a pwe # Character áº
+U+143b pwe # Character á»
+U+143c pwi # Character á¼
+U+143d pwi # Character á½
+U+143e pwii # Character á¾
+U+143f pwii # Character á¿
+U+1440 pwo # Character á
+U+1441 pwo # Character á
+U+1442 pwoo # Character á
+U+1443 pwoo # Character á
+U+1444 pwa # Character á
+U+1445 pwa # Character á
+U+1446 pwaa # Character á
+U+1447 pwaa # Character á
+U+1448 pwaa # Character á
+U+1449 p # Character á
+U+144a p # Character á
+U+144b h # Character á
+U+144c te # Character á
+U+144d taai # Character á
+U+144e ti # Character á
+U+144f tii # Character á
+U+1450 to # Character á
+U+1451 too # Character á
+U+1452 too # Character á
+U+1453 dee # Character á
+U+1454 di # Character á
+U+1455 ta # Character á
+U+1456 taa # Character á
+U+1457 twe # Character á
+U+1458 twe # Character á
+U+1459 twi # Character á
+U+145a twi # Character á
+U+145b twii # Character á
+U+145c twii # Character á
+U+145d two # Character á
+U+145e two # Character á
+U+145f twoo # Character á
+U+1460 twoo # Character á
+U+1461 twa # Character á¡
+U+1462 twa # Character á¢
+U+1463 twaa # Character á£
+U+1464 twaa # Character á¤
+U+1465 twaa # Character á¥
+U+1466 t # Character á¦
+U+1467 tte # Character á§
+U+1468 tti # Character á¨
+U+1469 tto # Character á©
+U+146a tta # Character áª
+U+146b ke # Character á«
+U+146c kaai # Character á¬
+U+146d ki # Character á
+U+146e kii # Character á®
+U+146f ko # Character á¯
+U+1470 koo # Character á°
+U+1471 koo # Character á±
+U+1472 ka # Character á²
+U+1473 kaa # Character á³
+U+1474 kwe # Character á´
+U+1475 kwe # Character áµ
+U+1476 kwi # Character á¶
+U+1477 kwi # Character á·
+U+1478 kwii # Character á¸
+U+1479 kwii # Character á¹
+U+147a kwo # Character áº
+U+147b kwo # Character á»
+U+147c kwoo # Character á¼
+U+147d kwoo # Character á½
+U+147e kwa # Character á¾
+U+147f kwa # Character á¿
+U+1480 kwaa # Character á
+U+1481 kwaa # Character á
+U+1482 kwaa # Character á
+U+1483 k # Character á
+U+1484 kw # Character á
+U+1485 keh # Character á
+U+1486 kih # Character á
+U+1487 koh # Character á
+U+1488 kah # Character á
+U+1489 ce # Character á
+U+148a caai # Character á
+U+148b ci # Character á
+U+148c cii # Character á
+U+148d co # Character á
+U+148e coo # Character á
+U+148f coo # Character á
+U+1490 ca # Character á
+U+1491 caa # Character á
+U+1492 cwe # Character á
+U+1493 cwe # Character á
+U+1494 cwi # Character á
+U+1495 cwi # Character á
+U+1496 cwii # Character á
+U+1497 cwii # Character á
+U+1498 cwo # Character á
+U+1499 cwo # Character á
+U+149a cwoo # Character á
+U+149b cwoo # Character á
+U+149c cwa # Character á
+U+149d cwa # Character á
+U+149e cwaa # Character á
+U+149f cwaa # Character á
+U+14a0 cwaa # Character á
+U+14a1 c # Character á¡
+U+14a2 th # Character á¢
+U+14a3 me # Character á£
+U+14a4 maai # Character á¤
+U+14a5 mi # Character á¥
+U+14a6 mii # Character á¦
+U+14a7 mo # Character á§
+U+14a8 moo # Character á¨
+U+14a9 moo # Character á©
+U+14aa ma # Character áª
+U+14ab maa # Character á«
+U+14ac mwe # Character á¬
+U+14ad mwe # Character á
+U+14ae mwi # Character á®
+U+14af mwi # Character á¯
+U+14b0 mwii # Character á°
+U+14b1 mwii # Character á±
+U+14b2 mwo # Character á²
+U+14b3 mwo # Character á³
+U+14b4 mwoo # Character á´
+U+14b5 mwoo # Character áµ
+U+14b6 mwa # Character á¶
+U+14b7 mwa # Character á·
+U+14b8 mwaa # Character á¸
+U+14b9 mwaa # Character á¹
+U+14ba mwaa # Character áº
+U+14bb m # Character á»
+U+14bc m # Character á¼
+U+14bd mh # Character á½
+U+14be m # Character á¾
+U+14bf m # Character á¿
+U+14c0 ne # Character á
+U+14c1 naai # Character á
+U+14c2 ni # Character á
+U+14c3 nii # Character á
+U+14c4 no # Character á
+U+14c5 noo # Character á
+U+14c6 noo # Character á
+U+14c7 na # Character á
+U+14c8 naa # Character á
+U+14c9 nwe # Character á
+U+14ca nwe # Character á
+U+14cb nwa # Character á
+U+14cc nwa # Character á
+U+14cd nwaa # Character á
+U+14ce nwaa # Character á
+U+14cf nwaa # Character á
+U+14d0 n # Character á
+U+14d1 ng # Character á
+U+14d2 nh # Character á
+U+14d3 le # Character á
+U+14d4 laai # Character á
+U+14d5 li # Character á
+U+14d6 lii # Character á
+U+14d7 lo # Character á
+U+14d8 loo # Character á
+U+14d9 loo # Character á
+U+14da la # Character á
+U+14db laa # Character á
+U+14dc lwe # Character á
+U+14dd lwe # Character á
+U+14de lwi # Character á
+U+14df lwi # Character á
+U+14e0 lwii # Character á
+U+14e1 lwii # Character á¡
+U+14e2 lwo # Character á¢
+U+14e3 lwo # Character á£
+U+14e4 lwoo # Character á¤
+U+14e5 lwoo # Character á¥
+U+14e6 lwa # Character á¦
+U+14e7 lwa # Character á§
+U+14e8 lwaa # Character á¨
+U+14e9 lwaa # Character á©
+U+14ea l # Character áª
+U+14eb l # Character á«
+U+14ec l # Character á¬
+U+14ed se # Character á
+U+14ee saai # Character á®
+U+14ef si # Character á¯
+U+14f0 sii # Character á°
+U+14f1 so # Character á±
+U+14f2 soo # Character á²
+U+14f3 soo # Character á³
+U+14f4 sa # Character á´
+U+14f5 saa # Character áµ
+U+14f6 swe # Character á¶
+U+14f7 swe # Character á·
+U+14f8 swi # Character á¸
+U+14f9 swi # Character á¹
+U+14fa swii # Character áº
+U+14fb swii # Character á»
+U+14fc swo # Character á¼
+U+14fd swo # Character á½
+U+14fe swoo # Character á¾
+U+14ff swoo # Character á¿
diff --git a/resources/chars/ascii/row15.trans b/resources/chars/ascii/row15.trans
new file mode 100644
index 0000000..41fffc3
--- /dev/null
+++ b/resources/chars/ascii/row15.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+1500 swa # Character á
+U+1501 swa # Character á
+U+1502 swaa # Character á
+U+1503 swaa # Character á
+U+1504 swaa # Character á
+U+1505 s # Character á
+U+1506 s # Character á
+U+1507 sw # Character á
+U+1508 s # Character á
+U+1509 sk # Character á
+U+150a skw # Character á
+U+150b sW # Character á
+U+150c spwa # Character á
+U+150d stwa # Character á
+U+150e skwa # Character á
+U+150f scwa # Character á
+U+1510 she # Character á
+U+1511 shi # Character á
+U+1512 shii # Character á
+U+1513 sho # Character á
+U+1514 shoo # Character á
+U+1515 sha # Character á
+U+1516 shaa # Character á
+U+1517 shwe # Character á
+U+1518 shwe # Character á
+U+1519 shwi # Character á
+U+151a shwi # Character á
+U+151b shwii # Character á
+U+151c shwii # Character á
+U+151d shwo # Character á
+U+151e shwo # Character á
+U+151f shwoo # Character á
+U+1520 shwoo # Character á
+U+1521 shwa # Character á¡
+U+1522 shwa # Character á¢
+U+1523 shwaa # Character á£
+U+1524 shwaa # Character á¤
+U+1525 sh # Character á¥
+U+1526 ye # Character á¦
+U+1527 yaai # Character á§
+U+1528 yi # Character á¨
+U+1529 yii # Character á©
+U+152a yo # Character áª
+U+152b yoo # Character á«
+U+152c yoo # Character á¬
+U+152d ya # Character á
+U+152e yaa # Character á®
+U+152f ywe # Character á¯
+U+1530 ywe # Character á°
+U+1531 ywi # Character á±
+U+1532 ywi # Character á²
+U+1533 ywii # Character á³
+U+1534 ywii # Character á´
+U+1535 ywo # Character áµ
+U+1536 ywo # Character á¶
+U+1537 ywoo # Character á·
+U+1538 ywoo # Character á¸
+U+1539 ywa # Character á¹
+U+153a ywa # Character áº
+U+153b ywaa # Character á»
+U+153c ywaa # Character á¼
+U+153d ywaa # Character á½
+U+153e y # Character á¾
+U+153f y # Character á¿
+U+1540 y # Character á
+U+1541 yi # Character á
+U+1542 re # Character á
+U+1543 re # Character á
+U+1544 le # Character á
+U+1545 raai # Character á
+U+1546 ri # Character á
+U+1547 rii # Character á
+U+1548 ro # Character á
+U+1549 roo # Character á
+U+154a lo # Character á
+U+154b ra # Character á
+U+154c raa # Character á
+U+154d la # Character á
+U+154e rwaa # Character á
+U+154f rwaa # Character á
+U+1550 r # Character á
+U+1551 r # Character á
+U+1552 r # Character á
+U+1553 fe # Character á
+U+1554 faai # Character á
+U+1555 fi # Character á
+U+1556 fii # Character á
+U+1557 fo # Character á
+U+1558 foo # Character á
+U+1559 fa # Character á
+U+155a faa # Character á
+U+155b fwaa # Character á
+U+155c fwaa # Character á
+U+155d f # Character á
+U+155e the # Character á
+U+155f the # Character á
+U+1560 thi # Character á
+U+1561 thi # Character á¡
+U+1562 thii # Character á¢
+U+1563 thii # Character á£
+U+1564 tho # Character á¤
+U+1565 thoo # Character á¥
+U+1566 tha # Character á¦
+U+1567 thaa # Character á§
+U+1568 thwaa # Character á¨
+U+1569 thwaa # Character á©
+U+156a th # Character áª
+U+156b tthe # Character á«
+U+156c tthi # Character á¬
+U+156d ttho # Character á
+U+156e ttha # Character á®
+U+156f tth # Character á¯
+U+1570 tye # Character á°
+U+1571 tyi # Character á±
+U+1572 tyo # Character á²
+U+1573 tya # Character á³
+U+1574 he # Character á´
+U+1575 hi # Character áµ
+U+1576 hii # Character á¶
+U+1577 ho # Character á·
+U+1578 hoo # Character á¸
+U+1579 ha # Character á¹
+U+157a haa # Character áº
+U+157b h # Character á»
+U+157c h # Character á¼
+U+157d hk # Character á½
+U+157e qaai # Character á¾
+U+157f qi # Character á¿
+U+1580 qii # Character á
+U+1581 qo # Character á
+U+1582 qoo # Character á
+U+1583 qa # Character á
+U+1584 qaa # Character á
+U+1585 q # Character á
+U+1586 tlhe # Character á
+U+1587 tlhi # Character á
+U+1588 tlho # Character á
+U+1589 tlha # Character á
+U+158a re # Character á
+U+158b ri # Character á
+U+158c ro # Character á
+U+158d ra # Character á
+U+158e ngaai # Character á
+U+158f ngi # Character á
+U+1590 ngii # Character á
+U+1591 ngo # Character á
+U+1592 ngoo # Character á
+U+1593 nga # Character á
+U+1594 ngaa # Character á
+U+1595 ng # Character á
+U+1596 nng # Character á
+U+1597 she # Character á
+U+1598 shi # Character á
+U+1599 sho # Character á
+U+159a sha # Character á
+U+159b the # Character á
+U+159c thi # Character á
+U+159d tho # Character á
+U+159e tha # Character á
+U+159f th # Character á
+U+15a0 lhi # Character á
+U+15a1 lhii # Character á¡
+U+15a2 lho # Character á¢
+U+15a3 lhoo # Character á£
+U+15a4 lha # Character á¤
+U+15a5 lhaa # Character á¥
+U+15a6 lh # Character á¦
+U+15a7 the # Character á§
+U+15a8 thi # Character á¨
+U+15a9 thii # Character á©
+U+15aa tho # Character áª
+U+15ab thoo # Character á«
+U+15ac tha # Character á¬
+U+15ad thaa # Character á
+U+15ae th # Character á®
+U+15af b # Character á¯
+U+15b0 e # Character á°
+U+15b1 i # Character á±
+U+15b2 o # Character á²
+U+15b3 a # Character á³
+U+15b4 we # Character á´
+U+15b5 wi # Character áµ
+U+15b6 wo # Character á¶
+U+15b7 wa # Character á·
+U+15b8 ne # Character á¸
+U+15b9 ni # Character á¹
+U+15ba no # Character áº
+U+15bb na # Character á»
+U+15bc ke # Character á¼
+U+15bd ki # Character á½
+U+15be ko # Character á¾
+U+15bf ka # Character á¿
+U+15c0 he # Character á
+U+15c1 hi # Character á
+U+15c2 ho # Character á
+U+15c3 ha # Character á
+U+15c4 ghu # Character á
+U+15c5 gho # Character á
+U+15c6 ghe # Character á
+U+15c7 ghee # Character á
+U+15c8 ghi # Character á
+U+15c9 gha # Character á
+U+15ca ru # Character á
+U+15cb ro # Character á
+U+15cc re # Character á
+U+15cd ree # Character á
+U+15ce ri # Character á
+U+15cf ra # Character á
+U+15d0 wu # Character á
+U+15d1 wo # Character á
+U+15d2 we # Character á
+U+15d3 wee # Character á
+U+15d4 wi # Character á
+U+15d5 wa # Character á
+U+15d6 hwu # Character á
+U+15d7 hwo # Character á
+U+15d8 hwe # Character á
+U+15d9 hwee # Character á
+U+15da hwi # Character á
+U+15db hwa # Character á
+U+15dc thu # Character á
+U+15dd tho # Character á
+U+15de the # Character á
+U+15df thee # Character á
+U+15e0 thi # Character á
+U+15e1 tha # Character á¡
+U+15e2 ttu # Character á¢
+U+15e3 tto # Character á£
+U+15e4 tte # Character á¤
+U+15e5 ttee # Character á¥
+U+15e6 tti # Character á¦
+U+15e7 tta # Character á§
+U+15e8 pu # Character á¨
+U+15e9 po # Character á©
+U+15ea pe # Character áª
+U+15eb pee # Character á«
+U+15ec pi # Character á¬
+U+15ed pa # Character á
+U+15ee p # Character á®
+U+15ef gu # Character á¯
+U+15f0 go # Character á°
+U+15f1 ge # Character á±
+U+15f2 gee # Character á²
+U+15f3 gi # Character á³
+U+15f4 ga # Character á´
+U+15f5 khu # Character áµ
+U+15f6 kho # Character á¶
+U+15f7 khe # Character á·
+U+15f8 khee # Character á¸
+U+15f9 khi # Character á¹
+U+15fa kha # Character áº
+U+15fb kku # Character á»
+U+15fc kko # Character á¼
+U+15fd kke # Character á½
+U+15fe kkee # Character á¾
+U+15ff kki # Character á¿
diff --git a/resources/chars/ascii/row16.trans b/resources/chars/ascii/row16.trans
new file mode 100644
index 0000000..28ccc72
--- /dev/null
+++ b/resources/chars/ascii/row16.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+1600 kka # Character á
+U+1601 kk # Character á
+U+1602 nu # Character á
+U+1603 no # Character á
+U+1604 ne # Character á
+U+1605 nee # Character á
+U+1606 ni # Character á
+U+1607 na # Character á
+U+1608 mu # Character á
+U+1609 mo # Character á
+U+160a me # Character á
+U+160b mee # Character á
+U+160c mi # Character á
+U+160d ma # Character á
+U+160e yu # Character á
+U+160f yo # Character á
+U+1610 ye # Character á
+U+1611 yee # Character á
+U+1612 yi # Character á
+U+1613 ya # Character á
+U+1614 ju # Character á
+U+1615 ju # Character á
+U+1616 jo # Character á
+U+1617 je # Character á
+U+1618 jee # Character á
+U+1619 ji # Character á
+U+161a ji # Character á
+U+161b ja # Character á
+U+161c jju # Character á
+U+161d jjo # Character á
+U+161e jje # Character á
+U+161f jjee # Character á
+U+1620 jji # Character á
+U+1621 jja # Character á¡
+U+1622 lu # Character á¢
+U+1623 lo # Character á£
+U+1624 le # Character á¤
+U+1625 lee # Character á¥
+U+1626 li # Character á¦
+U+1627 la # Character á§
+U+1628 dlu # Character á¨
+U+1629 dlo # Character á©
+U+162a dle # Character áª
+U+162b dlee # Character á«
+U+162c dli # Character á¬
+U+162d dla # Character á
+U+162e lhu # Character á®
+U+162f lho # Character á¯
+U+1630 lhe # Character á°
+U+1631 lhee # Character á±
+U+1632 lhi # Character á²
+U+1633 lha # Character á³
+U+1634 tlhu # Character á´
+U+1635 tlho # Character áµ
+U+1636 tlhe # Character á¶
+U+1637 tlhee # Character á·
+U+1638 tlhi # Character á¸
+U+1639 tlha # Character á¹
+U+163a tlu # Character áº
+U+163b tlo # Character á»
+U+163c tle # Character á¼
+U+163d tlee # Character á½
+U+163e tli # Character á¾
+U+163f tla # Character á¿
+U+1640 zu # Character á
+U+1641 zo # Character á
+U+1642 ze # Character á
+U+1643 zee # Character á
+U+1644 zi # Character á
+U+1645 za # Character á
+U+1646 z # Character á
+U+1647 z # Character á
+U+1648 dzu # Character á
+U+1649 dzo # Character á
+U+164a dze # Character á
+U+164b dzee # Character á
+U+164c dzi # Character á
+U+164d dza # Character á
+U+164e su # Character á
+U+164f so # Character á
+U+1650 se # Character á
+U+1651 see # Character á
+U+1652 si # Character á
+U+1653 sa # Character á
+U+1654 shu # Character á
+U+1655 sho # Character á
+U+1656 she # Character á
+U+1657 shee # Character á
+U+1658 shi # Character á
+U+1659 sha # Character á
+U+165a sh # Character á
+U+165b tsu # Character á
+U+165c tso # Character á
+U+165d tse # Character á
+U+165e tsee # Character á
+U+165f tsi # Character á
+U+1660 tsa # Character á
+U+1661 chu # Character á¡
+U+1662 cho # Character á¢
+U+1663 che # Character á£
+U+1664 chee # Character á¤
+U+1665 chi # Character á¥
+U+1666 cha # Character á¦
+U+1667 ttsu # Character á§
+U+1668 ttso # Character á¨
+U+1669 ttse # Character á©
+U+166a ttsee # Character áª
+U+166b ttsi # Character á«
+U+166c ttsa # Character á¬
+U+166d X # Character á
+U+166e . # Character á®
+U+166f qai # Character á¯
+U+1670 ngai # Character á°
+U+1671 nngi # Character á±
+U+1672 nngii # Character á²
+U+1673 nngo # Character á³
+U+1674 nngoo # Character á´
+U+1675 nnga # Character áµ
+U+1676 nngaa # Character á¶
+U+1677 ? # Character á·
+U+1678 ? # Character á¸
+U+1679 ? # Character á¹
+U+167a ? # Character áº
+U+167b ? # Character á»
+U+167c ? # Character á¼
+U+167d ? # Character á½
+U+167e ? # Character á¾
+U+167f ? # Character á¿
+U+1680 # Character á
+U+1681 b # Character á
+U+1682 l # Character á
+U+1683 f # Character á
+U+1684 s # Character á
+U+1685 n # Character á
+U+1686 h # Character á
+U+1687 d # Character á
+U+1688 t # Character á
+U+1689 c # Character á
+U+168a q # Character á
+U+168b m # Character á
+U+168c g # Character á
+U+168d ng # Character á
+U+168e z # Character á
+U+168f r # Character á
+U+1690 a # Character á
+U+1691 o # Character á
+U+1692 u # Character á
+U+1693 e # Character á
+U+1694 i # Character á
+U+1695 ch # Character á
+U+1696 th # Character á
+U+1697 ph # Character á
+U+1698 p # Character á
+U+1699 x # Character á
+U+169a p # Character á
+U+169b < # Character á
+U+169c > # Character á
+U+169d ? # Character á
+U+169e ? # Character á
+U+169f ? # Character á
+U+16a0 f # Character á
+U+16a1 v # Character á¡
+U+16a2 u # Character á¢
+U+16a3 yr # Character á£
+U+16a4 y # Character á¤
+U+16a5 w # Character á¥
+U+16a6 th # Character á¦
+U+16a7 th # Character á§
+U+16a8 a # Character á¨
+U+16a9 o # Character á©
+U+16aa ac # Character áª
+U+16ab ae # Character á«
+U+16ac o # Character á¬
+U+16ad o # Character á
+U+16ae o # Character á®
+U+16af oe # Character á¯
+U+16b0 on # Character á°
+U+16b1 r # Character á±
+U+16b2 k # Character á²
+U+16b3 c # Character á³
+U+16b4 k # Character á´
+U+16b5 g # Character áµ
+U+16b6 ng # Character á¶
+U+16b7 g # Character á·
+U+16b8 g # Character á¸
+U+16b9 w # Character á¹
+U+16ba h # Character áº
+U+16bb h # Character á»
+U+16bc h # Character á¼
+U+16bd h # Character á½
+U+16be n # Character á¾
+U+16bf n # Character á¿
+U+16c0 n # Character á
+U+16c1 i # Character á
+U+16c2 e # Character á
+U+16c3 j # Character á
+U+16c4 g # Character á
+U+16c5 ae # Character á
+U+16c6 a # Character á
+U+16c7 eo # Character á
+U+16c8 p # Character á
+U+16c9 z # Character á
+U+16ca s # Character á
+U+16cb s # Character á
+U+16cc s # Character á
+U+16cd c # Character á
+U+16ce z # Character á
+U+16cf t # Character á
+U+16d0 t # Character á
+U+16d1 d # Character á
+U+16d2 b # Character á
+U+16d3 b # Character á
+U+16d4 p # Character á
+U+16d5 p # Character á
+U+16d6 e # Character á
+U+16d7 m # Character á
+U+16d8 m # Character á
+U+16d9 m # Character á
+U+16da l # Character á
+U+16db l # Character á
+U+16dc ng # Character á
+U+16dd ng # Character á
+U+16de d # Character á
+U+16df o # Character á
+U+16e0 ear # Character á
+U+16e1 ior # Character á¡
+U+16e2 qu # Character á¢
+U+16e3 qu # Character á£
+U+16e4 qu # Character á¤
+U+16e5 s # Character á¥
+U+16e6 yr # Character á¦
+U+16e7 yr # Character á§
+U+16e8 yr # Character á¨
+U+16e9 q # Character á©
+U+16ea x # Character áª
+U+16eb . # Character á«
+U+16ec : # Character á¬
+U+16ed + # Character á
+U+16ee 17 # Character á®
+U+16ef 18 # Character á¯
+U+16f0 19 # Character á°
+U+16f1 ? # Character á±
+U+16f2 ? # Character á²
+U+16f3 ? # Character á³
+U+16f4 ? # Character á´
+U+16f5 ? # Character áµ
+U+16f6 ? # Character á¶
+U+16f7 ? # Character á·
+U+16f8 ? # Character á¸
+U+16f9 ? # Character á¹
+U+16fa ? # Character áº
+U+16fb ? # Character á»
+U+16fc ? # Character á¼
+U+16fd ? # Character á½
+U+16fe ? # Character á¾
+U+16ff ? # Character á¿
diff --git a/resources/chars/ascii/row17.trans b/resources/chars/ascii/row17.trans
new file mode 100644
index 0000000..e11bdb0
--- /dev/null
+++ b/resources/chars/ascii/row17.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+1700 ? # Character á
+U+1701 ? # Character á
+U+1702 ? # Character á
+U+1703 ? # Character á
+U+1704 ? # Character á
+U+1705 ? # Character á
+U+1706 ? # Character á
+U+1707 ? # Character á
+U+1708 ? # Character á
+U+1709 ? # Character á
+U+170a ? # Character á
+U+170b ? # Character á
+U+170c ? # Character á
+U+170d ? # Character á
+U+170e ? # Character á
+U+170f ? # Character á
+U+1710 ? # Character á
+U+1711 ? # Character á
+U+1712 ? # Character á
+U+1713 ? # Character á
+U+1714 ? # Character á
+U+1715 ? # Character á
+U+1716 ? # Character á
+U+1717 ? # Character á
+U+1718 ? # Character á
+U+1719 ? # Character á
+U+171a ? # Character á
+U+171b ? # Character á
+U+171c ? # Character á
+U+171d ? # Character á
+U+171e ? # Character á
+U+171f ? # Character á
+U+1720 ? # Character á
+U+1721 ? # Character á¡
+U+1722 ? # Character á¢
+U+1723 ? # Character á£
+U+1724 ? # Character á¤
+U+1725 ? # Character á¥
+U+1726 ? # Character á¦
+U+1727 ? # Character á§
+U+1728 ? # Character á¨
+U+1729 ? # Character á©
+U+172a ? # Character áª
+U+172b ? # Character á«
+U+172c ? # Character á¬
+U+172d ? # Character á
+U+172e ? # Character á®
+U+172f ? # Character á¯
+U+1730 ? # Character á°
+U+1731 ? # Character á±
+U+1732 ? # Character á²
+U+1733 ? # Character á³
+U+1734 ? # Character á´
+U+1735 ? # Character áµ
+U+1736 ? # Character á¶
+U+1737 ? # Character á·
+U+1738 ? # Character á¸
+U+1739 ? # Character á¹
+U+173a ? # Character áº
+U+173b ? # Character á»
+U+173c ? # Character á¼
+U+173d ? # Character á½
+U+173e ? # Character á¾
+U+173f ? # Character á¿
+U+1740 ? # Character á
+U+1741 ? # Character á
+U+1742 ? # Character á
+U+1743 ? # Character á
+U+1744 ? # Character á
+U+1745 ? # Character á
+U+1746 ? # Character á
+U+1747 ? # Character á
+U+1748 ? # Character á
+U+1749 ? # Character á
+U+174a ? # Character á
+U+174b ? # Character á
+U+174c ? # Character á
+U+174d ? # Character á
+U+174e ? # Character á
+U+174f ? # Character á
+U+1750 ? # Character á
+U+1751 ? # Character á
+U+1752 ? # Character á
+U+1753 ? # Character á
+U+1754 ? # Character á
+U+1755 ? # Character á
+U+1756 ? # Character á
+U+1757 ? # Character á
+U+1758 ? # Character á
+U+1759 ? # Character á
+U+175a ? # Character á
+U+175b ? # Character á
+U+175c ? # Character á
+U+175d ? # Character á
+U+175e ? # Character á
+U+175f ? # Character á
+U+1760 ? # Character á
+U+1761 ? # Character á¡
+U+1762 ? # Character á¢
+U+1763 ? # Character á£
+U+1764 ? # Character á¤
+U+1765 ? # Character á¥
+U+1766 ? # Character á¦
+U+1767 ? # Character á§
+U+1768 ? # Character á¨
+U+1769 ? # Character á©
+U+176a ? # Character áª
+U+176b ? # Character á«
+U+176c ? # Character á¬
+U+176d ? # Character á
+U+176e ? # Character á®
+U+176f ? # Character á¯
+U+1770 ? # Character á°
+U+1771 ? # Character á±
+U+1772 ? # Character á²
+U+1773 ? # Character á³
+U+1774 ? # Character á´
+U+1775 ? # Character áµ
+U+1776 ? # Character á¶
+U+1777 ? # Character á·
+U+1778 ? # Character á¸
+U+1779 ? # Character á¹
+U+177a ? # Character áº
+U+177b ? # Character á»
+U+177c ? # Character á¼
+U+177d ? # Character á½
+U+177e ? # Character á¾
+U+177f ? # Character á¿
+U+1780 k # Character á
+U+1781 kh # Character á
+U+1782 g # Character á
+U+1783 gh # Character á
+U+1784 ng # Character á
+U+1785 c # Character á
+U+1786 ch # Character á
+U+1787 j # Character á
+U+1788 jh # Character á
+U+1789 ny # Character á
+U+178a t # Character á
+U+178b tth # Character á
+U+178c d # Character á
+U+178d ddh # Character á
+U+178e nn # Character á
+U+178f t # Character á
+U+1790 th # Character á
+U+1791 d # Character á
+U+1792 dh # Character á
+U+1793 n # Character á
+U+1794 p # Character á
+U+1795 ph # Character á
+U+1796 b # Character á
+U+1797 bh # Character á
+U+1798 m # Character á
+U+1799 y # Character á
+U+179a r # Character á
+U+179b l # Character á
+U+179c v # Character á
+U+179d sh # Character á
+U+179e ss # Character á
+U+179f s # Character á
+U+17a0 h # Character á
+U+17a1 l # Character á¡
+U+17a2 q # Character á¢
+U+17a3 a # Character á£
+U+17a4 aa # Character á¤
+U+17a5 i # Character á¥
+U+17a6 ii # Character á¦
+U+17a7 u # Character á§
+U+17a8 uk # Character á¨
+U+17a9 uu # Character á©
+U+17aa uuv # Character áª
+U+17ab ry # Character á«
+U+17ac ryy # Character á¬
+U+17ad ly # Character á
+U+17ae lyy # Character á®
+U+17af e # Character á¯
+U+17b0 ai # Character á°
+U+17b1 oo # Character á±
+U+17b2 oo # Character á²
+U+17b3 au # Character á³
+U+17b4 a # Character á´
+U+17b5 aa # Character áµ
+U+17b6 aa # Character á¶
+U+17b7 i # Character á·
+U+17b8 ii # Character á¸
+U+17b9 y # Character á¹
+U+17ba yy # Character áº
+U+17bb u # Character á»
+U+17bc uu # Character á¼
+U+17bd ua # Character á½
+U+17be oe # Character á¾
+U+17bf ya # Character á¿
+U+17c0 ie # Character á
+U+17c1 e # Character á
+U+17c2 ae # Character á
+U+17c3 ai # Character á
+U+17c4 oo # Character á
+U+17c5 au # Character á
+U+17c6 M # Character á
+U+17c7 H # Character á
+U+17c8 a` # Character á
+U+17c9 ? # Character á
+U+17ca ? # Character á
+U+17cb ? # Character á
+U+17cc r # Character á
+U+17cd ? # Character á
+U+17ce ! # Character á
+U+17cf ? # Character á
+U+17d0 ? # Character á
+U+17d1 ? # Character á
+U+17d2 ? # Character á
+U+17d3 ? # Character á
+U+17d4 . # Character á
+U+17d5 // # Character á
+U+17d6 : # Character á
+U+17d7 + # Character á
+U+17d8 ++ # Character á
+U+17d9 * # Character á
+U+17da /// # Character á
+U+17db KR # Character á
+U+17dc ' # Character á
+U+17dd ? # Character á
+U+17de ? # Character á
+U+17df ? # Character á
+U+17e0 ? # Character á
+U+17e1 1 # Character á¡
+U+17e2 2 # Character á¢
+U+17e3 3 # Character á£
+U+17e4 4 # Character á¤
+U+17e5 5 # Character á¥
+U+17e6 6 # Character á¦
+U+17e7 7 # Character á§
+U+17e8 8 # Character á¨
+U+17e9 9 # Character á©
+U+17ea ? # Character áª
+U+17eb ? # Character á«
+U+17ec ? # Character á¬
+U+17ed ? # Character á
+U+17ee ? # Character á®
+U+17ef ? # Character á¯
+U+17f0 ? # Character á°
+U+17f1 ? # Character á±
+U+17f2 ? # Character á²
+U+17f3 ? # Character á³
+U+17f4 ? # Character á´
+U+17f5 ? # Character áµ
+U+17f6 ? # Character á¶
+U+17f7 ? # Character á·
+U+17f8 ? # Character á¸
+U+17f9 ? # Character á¹
+U+17fa ? # Character áº
+U+17fb ? # Character á»
+U+17fc ? # Character á¼
+U+17fd ? # Character á½
+U+17fe ? # Character á¾
+U+17ff ? # Character á¿
diff --git a/resources/chars/ascii/row18.trans b/resources/chars/ascii/row18.trans
new file mode 100644
index 0000000..e64daca
--- /dev/null
+++ b/resources/chars/ascii/row18.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+1800 @ # Character á
+U+1801 ... # Character á
+U+1802 , # Character á
+U+1803 . # Character á
+U+1804 : # Character á
+U+1805 // # Character á
+U+1806 ? # Character á
+U+1807 - # Character á
+U+1808 , # Character á
+U+1809 . # Character á
+U+180a ? # Character á
+U+180b ? # Character á
+U+180c ? # Character á
+U+180d ? # Character á
+U+180e ? # Character á
+U+180f ? # Character á
+U+1810 ? # Character á
+U+1811 1 # Character á
+U+1812 2 # Character á
+U+1813 3 # Character á
+U+1814 4 # Character á
+U+1815 5 # Character á
+U+1816 6 # Character á
+U+1817 7 # Character á
+U+1818 8 # Character á
+U+1819 9 # Character á
+U+181a ? # Character á
+U+181b ? # Character á
+U+181c ? # Character á
+U+181d ? # Character á
+U+181e ? # Character á
+U+181f ? # Character á
+U+1820 a # Character á
+U+1821 e # Character á ¡
+U+1822 i # Character á ¢
+U+1823 o # Character á £
+U+1824 u # Character á ¤
+U+1825 O # Character á ¥
+U+1826 U # Character á ¦
+U+1827 ee # Character á §
+U+1828 n # Character á ¨
+U+1829 ng # Character á ©
+U+182a b # Character á ª
+U+182b p # Character á «
+U+182c q # Character á ¬
+U+182d g # Character á
+U+182e m # Character á ®
+U+182f l # Character á ¯
+U+1830 s # Character á °
+U+1831 sh # Character á ±
+U+1832 t # Character á ²
+U+1833 d # Character á ³
+U+1834 ch # Character á ´
+U+1835 j # Character á µ
+U+1836 y # Character á ¶
+U+1837 r # Character á ·
+U+1838 w # Character á ¸
+U+1839 f # Character á ¹
+U+183a k # Character á º
+U+183b kha # Character á »
+U+183c ts # Character á ¼
+U+183d z # Character á ½
+U+183e h # Character á ¾
+U+183f zr # Character á ¿
+U+1840 lh # Character á¡
+U+1841 zh # Character á¡
+U+1842 ch # Character á¡
+U+1843 - # Character á¡
+U+1844 e # Character á¡
+U+1845 i # Character á¡
+U+1846 o # Character á¡
+U+1847 u # Character á¡
+U+1848 O # Character á¡
+U+1849 U # Character á¡
+U+184a ng # Character á¡
+U+184b b # Character á¡
+U+184c p # Character á¡
+U+184d q # Character á¡
+U+184e g # Character á¡
+U+184f m # Character á¡
+U+1850 t # Character á¡
+U+1851 d # Character á¡
+U+1852 ch # Character á¡
+U+1853 j # Character á¡
+U+1854 ts # Character á¡
+U+1855 y # Character á¡
+U+1856 w # Character á¡
+U+1857 k # Character á¡
+U+1858 g # Character á¡
+U+1859 h # Character á¡
+U+185a jy # Character á¡
+U+185b ny # Character á¡
+U+185c dz # Character á¡
+U+185d e # Character á¡
+U+185e i # Character á¡
+U+185f iy # Character á¡
+U+1860 U # Character á¡
+U+1861 u # Character á¡¡
+U+1862 ng # Character á¡¢
+U+1863 k # Character á¡£
+U+1864 g # Character ᡤ
+U+1865 h # Character á¡¥
+U+1866 p # Character ᡦ
+U+1867 sh # Character ᡧ
+U+1868 t # Character ᡨ
+U+1869 d # Character á¡©
+U+186a j # Character ᡪ
+U+186b f # Character á¡«
+U+186c g # Character ᡬ
+U+186d h # Character á¡
+U+186e ts # Character á¡®
+U+186f z # Character ᡯ
+U+1870 r # Character á¡°
+U+1871 ch # Character ᡱ
+U+1872 zh # Character ᡲ
+U+1873 i # Character ᡳ
+U+1874 k # Character á¡´
+U+1875 r # Character ᡵ
+U+1876 f # Character ᡶ
+U+1877 zh # Character á¡·
+U+1878 ? # Character ᡸ
+U+1879 ? # Character ᡹
+U+187a ? # Character ᡺
+U+187b ? # Character á¡»
+U+187c ? # Character ᡼
+U+187d ? # Character ᡽
+U+187e ? # Character ᡾
+U+187f ? # Character á¡¿
+U+1880 ? # Character á¢
+U+1881 H # Character á¢
+U+1882 X # Character á¢
+U+1883 W # Character á¢
+U+1884 M # Character á¢
+U+1885 3 # Character á¢
+U+1886 333 # Character á¢
+U+1887 a # Character á¢
+U+1888 i # Character á¢
+U+1889 k # Character á¢
+U+188a ng # Character á¢
+U+188b c # Character á¢
+U+188c tt # Character á¢
+U+188d tth # Character á¢
+U+188e dd # Character á¢
+U+188f nn # Character á¢
+U+1890 t # Character á¢
+U+1891 d # Character á¢
+U+1892 p # Character á¢
+U+1893 ph # Character á¢
+U+1894 ss # Character á¢
+U+1895 zh # Character á¢
+U+1896 z # Character á¢
+U+1897 a # Character á¢
+U+1898 t # Character á¢
+U+1899 zh # Character á¢
+U+189a gh # Character á¢
+U+189b ng # Character á¢
+U+189c c # Character á¢
+U+189d jh # Character á¢
+U+189e tta # Character á¢
+U+189f ddh # Character á¢
+U+18a0 t # Character á¢
+U+18a1 dh # Character ᢡ
+U+18a2 ss # Character ᢢ
+U+18a3 cy # Character ᢣ
+U+18a4 zh # Character ᢤ
+U+18a5 z # Character ᢥ
+U+18a6 u # Character ᢦ
+U+18a7 y # Character ᢧ
+U+18a8 bh # Character ᢨ
+U+18a9 ' # Character ᢩ
+U+18aa ? # Character ᢪ
+U+18ab ? # Character ᢫
+U+18ac ? # Character ᢬
+U+18ad ? # Character á¢
+U+18ae ? # Character ᢮
+U+18af ? # Character ᢯
+U+18b0 ? # Character ᢰ
+U+18b1 ? # Character ᢱ
+U+18b2 ? # Character ᢲ
+U+18b3 ? # Character ᢳ
+U+18b4 ? # Character ᢴ
+U+18b5 ? # Character ᢵ
+U+18b6 ? # Character ᢶ
+U+18b7 ? # Character ᢷ
+U+18b8 ? # Character ᢸ
+U+18b9 ? # Character ᢹ
+U+18ba ? # Character ᢺ
+U+18bb ? # Character ᢻ
+U+18bc ? # Character ᢼ
+U+18bd ? # Character ᢽ
+U+18be ? # Character ᢾ
+U+18bf ? # Character ᢿ
+U+18c0 ? # Character á£
+U+18c1 ? # Character á£
+U+18c2 ? # Character á£
+U+18c3 ? # Character á£
+U+18c4 ? # Character á£
+U+18c5 ? # Character á£
+U+18c6 ? # Character á£
+U+18c7 ? # Character á£
+U+18c8 ? # Character á£
+U+18c9 ? # Character á£
+U+18ca ? # Character á£
+U+18cb ? # Character á£
+U+18cc ? # Character á£
+U+18cd ? # Character á£
+U+18ce ? # Character á£
+U+18cf ? # Character á£
+U+18d0 ? # Character á£
+U+18d1 ? # Character á£
+U+18d2 ? # Character á£
+U+18d3 ? # Character á£
+U+18d4 ? # Character á£
+U+18d5 ? # Character á£
+U+18d6 ? # Character á£
+U+18d7 ? # Character á£
+U+18d8 ? # Character á£
+U+18d9 ? # Character á£
+U+18da ? # Character á£
+U+18db ? # Character á£
+U+18dc ? # Character á£
+U+18dd ? # Character á£
+U+18de ? # Character á£
+U+18df ? # Character á£
+U+18e0 ? # Character á£
+U+18e1 ? # Character ᣡ
+U+18e2 ? # Character ᣢ
+U+18e3 ? # Character ᣣ
+U+18e4 ? # Character ᣤ
+U+18e5 ? # Character ᣥ
+U+18e6 ? # Character ᣦ
+U+18e7 ? # Character ᣧ
+U+18e8 ? # Character ᣨ
+U+18e9 ? # Character ᣩ
+U+18ea ? # Character ᣪ
+U+18eb ? # Character ᣫ
+U+18ec ? # Character ᣬ
+U+18ed ? # Character á£
+U+18ee ? # Character ᣮ
+U+18ef ? # Character ᣯ
+U+18f0 ? # Character ᣰ
+U+18f1 ? # Character ᣱ
+U+18f2 ? # Character ᣲ
+U+18f3 ? # Character ᣳ
+U+18f4 ? # Character ᣴ
+U+18f5 ? # Character ᣵ
+U+18f6 ? # Character ᣶
+U+18f7 ? # Character ᣷
+U+18f8 ? # Character ᣸
+U+18f9 ? # Character ᣹
+U+18fa ? # Character ᣺
+U+18fb ? # Character ᣻
+U+18fc ? # Character ᣼
+U+18fd ? # Character ᣽
+U+18fe ? # Character ᣾
+U+18ff ? # Character ᣿
diff --git a/resources/chars/ascii/row1e.trans b/resources/chars/ascii/row1e.trans
new file mode 100644
index 0000000..4bcdc2c
--- /dev/null
+++ b/resources/chars/ascii/row1e.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+1e00 A # Character á¸
+U+1e01 a # Character á¸
+U+1e02 B # Character á¸
+U+1e03 b # Character á¸
+U+1e04 B # Character á¸
+U+1e05 b # Character á¸
+U+1e06 B # Character á¸
+U+1e07 b # Character á¸
+U+1e08 C # Character á¸
+U+1e09 c # Character á¸
+U+1e0a D # Character á¸
+U+1e0b d # Character á¸
+U+1e0c D # Character á¸
+U+1e0d d # Character á¸
+U+1e0e D # Character á¸
+U+1e0f d # Character á¸
+U+1e10 D # Character á¸
+U+1e11 d # Character á¸
+U+1e12 D # Character á¸
+U+1e13 d # Character á¸
+U+1e14 E # Character á¸
+U+1e15 e # Character á¸
+U+1e16 E # Character á¸
+U+1e17 e # Character á¸
+U+1e18 E # Character á¸
+U+1e19 e # Character á¸
+U+1e1a E # Character á¸
+U+1e1b e # Character á¸
+U+1e1c E # Character á¸
+U+1e1d e # Character á¸
+U+1e1e F # Character á¸
+U+1e1f f # Character á¸
+U+1e20 G # Character á¸
+U+1e21 g # Character ḡ
+U+1e22 H # Character Ḣ
+U+1e23 h # Character ḣ
+U+1e24 H # Character Ḥ
+U+1e25 h # Character ḥ
+U+1e26 H # Character Ḧ
+U+1e27 h # Character ḧ
+U+1e28 H # Character Ḩ
+U+1e29 h # Character ḩ
+U+1e2a H # Character Ḫ
+U+1e2b h # Character ḫ
+U+1e2c I # Character Ḭ
+U+1e2d i # Character á¸
+U+1e2e I # Character Ḯ
+U+1e2f i # Character ḯ
+U+1e30 K # Character Ḱ
+U+1e31 k # Character ḱ
+U+1e32 K # Character Ḳ
+U+1e33 k # Character ḳ
+U+1e34 K # Character Ḵ
+U+1e35 k # Character ḵ
+U+1e36 L # Character Ḷ
+U+1e37 l # Character ḷ
+U+1e38 L # Character Ḹ
+U+1e39 l # Character ḹ
+U+1e3a L # Character Ḻ
+U+1e3b l # Character ḻ
+U+1e3c L # Character Ḽ
+U+1e3d l # Character ḽ
+U+1e3e M # Character Ḿ
+U+1e3f m # Character ḿ
+U+1e40 M # Character á¹
+U+1e41 m # Character á¹
+U+1e42 M # Character á¹
+U+1e43 m # Character á¹
+U+1e44 N # Character á¹
+U+1e45 n # Character á¹
+U+1e46 N # Character á¹
+U+1e47 n # Character á¹
+U+1e48 N # Character á¹
+U+1e49 n # Character á¹
+U+1e4a N # Character á¹
+U+1e4b n # Character á¹
+U+1e4c O # Character á¹
+U+1e4d o # Character á¹
+U+1e4e O # Character á¹
+U+1e4f o # Character á¹
+U+1e50 O # Character á¹
+U+1e51 o # Character á¹
+U+1e52 O # Character á¹
+U+1e53 o # Character á¹
+U+1e54 P # Character á¹
+U+1e55 p # Character á¹
+U+1e56 P # Character á¹
+U+1e57 p # Character á¹
+U+1e58 R # Character á¹
+U+1e59 r # Character á¹
+U+1e5a R # Character á¹
+U+1e5b r # Character á¹
+U+1e5c R # Character á¹
+U+1e5d r # Character á¹
+U+1e5e R # Character á¹
+U+1e5f r # Character á¹
+U+1e60 S # Character á¹
+U+1e61 s # Character ṡ
+U+1e62 S # Character á¹¢
+U+1e63 s # Character á¹£
+U+1e64 S # Character Ṥ
+U+1e65 s # Character á¹¥
+U+1e66 S # Character Ṧ
+U+1e67 s # Character ṧ
+U+1e68 S # Character Ṩ
+U+1e69 s # Character ṩ
+U+1e6a T # Character Ṫ
+U+1e6b t # Character ṫ
+U+1e6c T # Character Ṭ
+U+1e6d t # Character á¹
+U+1e6e T # Character á¹®
+U+1e6f t # Character ṯ
+U+1e70 T # Character á¹°
+U+1e71 t # Character á¹±
+U+1e72 U # Character á¹²
+U+1e73 u # Character á¹³
+U+1e74 U # Character á¹´
+U+1e75 u # Character á¹µ
+U+1e76 U # Character Ṷ
+U+1e77 u # Character á¹·
+U+1e78 U # Character Ṹ
+U+1e79 u # Character á¹¹
+U+1e7a U # Character Ṻ
+U+1e7b u # Character á¹»
+U+1e7c V # Character á¹¼
+U+1e7d v # Character á¹½
+U+1e7e V # Character á¹¾
+U+1e7f v # Character ṿ
+U+1e80 W # Character áº
+U+1e81 w # Character áº
+U+1e82 W # Character áº
+U+1e83 w # Character áº
+U+1e84 W # Character áº
+U+1e85 w # Character áº
+U+1e86 W # Character áº
+U+1e87 w # Character áº
+U+1e88 W # Character áº
+U+1e89 w # Character áº
+U+1e8a X # Character áº
+U+1e8b x # Character áº
+U+1e8c X # Character áº
+U+1e8d x # Character áº
+U+1e8e Y # Character áº
+U+1e8f y # Character áº
+U+1e90 Z # Character áº
+U+1e91 z # Character áº
+U+1e92 Z # Character áº
+U+1e93 z # Character áº
+U+1e94 Z # Character áº
+U+1e95 z # Character áº
+U+1e96 h # Character áº
+U+1e97 t # Character áº
+U+1e98 w # Character áº
+U+1e99 y # Character áº
+U+1e9a a # Character áº
+U+1e9b S # Character áº
+U+1e9c ? # Character áº
+U+1e9d ? # Character áº
+U+1e9e ? # Character áº
+U+1e9f ? # Character áº
+U+1ea0 A # Character áº
+U+1ea1 a # Character ạ
+U+1ea2 A # Character Ả
+U+1ea3 a # Character ả
+U+1ea4 A # Character Ấ
+U+1ea5 a # Character ấ
+U+1ea6 A # Character Ầ
+U+1ea7 a # Character ầ
+U+1ea8 A # Character Ẩ
+U+1ea9 a # Character ẩ
+U+1eaa A # Character Ẫ
+U+1eab a # Character ẫ
+U+1eac A # Character Ậ
+U+1ead a # Character áº
+U+1eae A # Character Ắ
+U+1eaf a # Character ắ
+U+1eb0 A # Character Ằ
+U+1eb1 a # Character ằ
+U+1eb2 A # Character Ẳ
+U+1eb3 a # Character ẳ
+U+1eb4 A # Character Ẵ
+U+1eb5 a # Character ẵ
+U+1eb6 A # Character Ặ
+U+1eb7 a # Character ặ
+U+1eb8 E # Character Ẹ
+U+1eb9 e # Character ẹ
+U+1eba E # Character Ẻ
+U+1ebb e # Character ẻ
+U+1ebc E # Character Ẽ
+U+1ebd e # Character ẽ
+U+1ebe E # Character Ế
+U+1ebf e # Character ế
+U+1ec0 E # Character á»
+U+1ec1 e # Character á»
+U+1ec2 E # Character á»
+U+1ec3 e # Character á»
+U+1ec4 E # Character á»
+U+1ec5 e # Character á»
+U+1ec6 E # Character á»
+U+1ec7 e # Character á»
+U+1ec8 I # Character á»
+U+1ec9 i # Character á»
+U+1eca I # Character á»
+U+1ecb i # Character á»
+U+1ecc O # Character á»
+U+1ecd o # Character á»
+U+1ece O # Character á»
+U+1ecf o # Character á»
+U+1ed0 O # Character á»
+U+1ed1 o # Character á»
+U+1ed2 O # Character á»
+U+1ed3 o # Character á»
+U+1ed4 O # Character á»
+U+1ed5 o # Character á»
+U+1ed6 O # Character á»
+U+1ed7 o # Character á»
+U+1ed8 O # Character á»
+U+1ed9 o # Character á»
+U+1eda O # Character á»
+U+1edb o # Character á»
+U+1edc O # Character á»
+U+1edd o # Character á»
+U+1ede O # Character á»
+U+1edf o # Character á»
+U+1ee0 O # Character á»
+U+1ee1 o # Character ỡ
+U+1ee2 O # Character Ợ
+U+1ee3 o # Character ợ
+U+1ee4 U # Character Ụ
+U+1ee5 u # Character ụ
+U+1ee6 U # Character Ủ
+U+1ee7 u # Character ủ
+U+1ee8 U # Character Ứ
+U+1ee9 u # Character ứ
+U+1eea U # Character Ừ
+U+1eeb u # Character ừ
+U+1eec U # Character Ử
+U+1eed u # Character á»
+U+1eee U # Character á»®
+U+1eef u # Character ữ
+U+1ef0 U # Character á»°
+U+1ef1 u # Character á»±
+U+1ef2 Y # Character Ỳ
+U+1ef3 y # Character ỳ
+U+1ef4 Y # Character á»´
+U+1ef5 y # Character ỵ
+U+1ef6 Y # Character Ỷ
+U+1ef7 y # Character á»·
+U+1ef8 Y # Character Ỹ
+U+1ef9 y # Character ỹ
+U+1efa ? # Character Ỻ
+U+1efb ? # Character á»»
+U+1efc ? # Character Ỽ
+U+1efd ? # Character ỽ
+U+1efe ? # Character Ỿ
+U+1eff ? # Character ỿ
diff --git a/resources/chars/ascii/row1f.trans b/resources/chars/ascii/row1f.trans
new file mode 100644
index 0000000..a4d45b2
--- /dev/null
+++ b/resources/chars/ascii/row1f.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+1f00 a # Character á¼
+U+1f01 a # Character á¼
+U+1f02 a # Character á¼
+U+1f03 a # Character á¼
+U+1f04 a # Character á¼
+U+1f05 a # Character á¼
+U+1f06 a # Character á¼
+U+1f07 a # Character á¼
+U+1f08 A # Character á¼
+U+1f09 A # Character á¼
+U+1f0a A # Character á¼
+U+1f0b A # Character á¼
+U+1f0c A # Character á¼
+U+1f0d A # Character á¼
+U+1f0e A # Character á¼
+U+1f0f A # Character á¼
+U+1f10 e # Character á¼
+U+1f11 e # Character á¼
+U+1f12 e # Character á¼
+U+1f13 e # Character á¼
+U+1f14 e # Character á¼
+U+1f15 e # Character á¼
+U+1f16 ? # Character á¼
+U+1f17 ? # Character á¼
+U+1f18 E # Character á¼
+U+1f19 E # Character á¼
+U+1f1a E # Character á¼
+U+1f1b E # Character á¼
+U+1f1c E # Character á¼
+U+1f1d E # Character á¼
+U+1f1e ? # Character á¼
+U+1f1f ? # Character á¼
+U+1f20 e # Character á¼
+U+1f21 e # Character ἡ
+U+1f22 e # Character á¼¢
+U+1f23 e # Character á¼£
+U+1f24 e # Character ἤ
+U+1f25 e # Character á¼¥
+U+1f26 e # Character ἦ
+U+1f27 e # Character ἧ
+U+1f28 E # Character Ἠ
+U+1f29 E # Character Ἡ
+U+1f2a E # Character Ἢ
+U+1f2b E # Character Ἣ
+U+1f2c E # Character Ἤ
+U+1f2d E # Character á¼
+U+1f2e E # Character á¼®
+U+1f2f E # Character Ἧ
+U+1f30 i # Character á¼°
+U+1f31 i # Character á¼±
+U+1f32 i # Character á¼²
+U+1f33 i # Character á¼³
+U+1f34 i # Character á¼´
+U+1f35 i # Character á¼µ
+U+1f36 i # Character ἶ
+U+1f37 i # Character á¼·
+U+1f38 I # Character Ἰ
+U+1f39 I # Character á¼¹
+U+1f3a I # Character Ἲ
+U+1f3b I # Character á¼»
+U+1f3c I # Character á¼¼
+U+1f3d I # Character á¼½
+U+1f3e I # Character á¼¾
+U+1f3f I # Character Ἷ
+U+1f40 o # Character á½
+U+1f41 o # Character á½
+U+1f42 o # Character á½
+U+1f43 o # Character á½
+U+1f44 o # Character á½
+U+1f45 o # Character á½
+U+1f46 ? # Character á½
+U+1f47 ? # Character á½
+U+1f48 O # Character á½
+U+1f49 O # Character á½
+U+1f4a O # Character á½
+U+1f4b O # Character á½
+U+1f4c O # Character á½
+U+1f4d O # Character á½
+U+1f4e ? # Character á½
+U+1f4f ? # Character á½
+U+1f50 u # Character á½
+U+1f51 u # Character á½
+U+1f52 u # Character á½
+U+1f53 u # Character á½
+U+1f54 u # Character á½
+U+1f55 u # Character á½
+U+1f56 u # Character á½
+U+1f57 u # Character á½
+U+1f58 ? # Character á½
+U+1f59 U # Character á½
+U+1f5a ? # Character á½
+U+1f5b U # Character á½
+U+1f5c ? # Character á½
+U+1f5d U # Character á½
+U+1f5e ? # Character á½
+U+1f5f U # Character á½
+U+1f60 o # Character á½
+U+1f61 o # Character ὡ
+U+1f62 o # Character á½¢
+U+1f63 o # Character á½£
+U+1f64 o # Character ὤ
+U+1f65 o # Character á½¥
+U+1f66 o # Character ὦ
+U+1f67 o # Character ὧ
+U+1f68 O # Character Ὠ
+U+1f69 O # Character Ὡ
+U+1f6a O # Character Ὢ
+U+1f6b O # Character Ὣ
+U+1f6c O # Character Ὤ
+U+1f6d O # Character á½
+U+1f6e O # Character á½®
+U+1f6f O # Character Ὧ
+U+1f70 a # Character á½°
+U+1f71 a # Character á½±
+U+1f72 e # Character á½²
+U+1f73 e # Character á½³
+U+1f74 e # Character á½´
+U+1f75 e # Character á½µ
+U+1f76 i # Character ὶ
+U+1f77 i # Character á½·
+U+1f78 o # Character ὸ
+U+1f79 o # Character á½¹
+U+1f7a u # Character ὺ
+U+1f7b u # Character á½»
+U+1f7c o # Character á½¼
+U+1f7d o # Character á½½
+U+1f7e ? # Character á½¾
+U+1f7f ? # Character ὿
+U+1f80 a # Character á¾
+U+1f81 a # Character á¾
+U+1f82 a # Character á¾
+U+1f83 a # Character á¾
+U+1f84 a # Character á¾
+U+1f85 a # Character á¾
+U+1f86 a # Character á¾
+U+1f87 a # Character á¾
+U+1f88 A # Character á¾
+U+1f89 A # Character á¾
+U+1f8a A # Character á¾
+U+1f8b A # Character á¾
+U+1f8c A # Character á¾
+U+1f8d A # Character á¾
+U+1f8e A # Character á¾
+U+1f8f A # Character á¾
+U+1f90 e # Character á¾
+U+1f91 e # Character á¾
+U+1f92 e # Character á¾
+U+1f93 e # Character á¾
+U+1f94 e # Character á¾
+U+1f95 e # Character á¾
+U+1f96 e # Character á¾
+U+1f97 e # Character á¾
+U+1f98 E # Character á¾
+U+1f99 E # Character á¾
+U+1f9a E # Character á¾
+U+1f9b E # Character á¾
+U+1f9c E # Character á¾
+U+1f9d E # Character á¾
+U+1f9e E # Character á¾
+U+1f9f E # Character á¾
+U+1fa0 o # Character á¾
+U+1fa1 o # Character ᾡ
+U+1fa2 o # Character á¾¢
+U+1fa3 o # Character á¾£
+U+1fa4 o # Character ᾤ
+U+1fa5 o # Character á¾¥
+U+1fa6 o # Character ᾦ
+U+1fa7 o # Character ᾧ
+U+1fa8 O # Character ᾨ
+U+1fa9 O # Character ᾩ
+U+1faa O # Character ᾪ
+U+1fab O # Character ᾫ
+U+1fac O # Character ᾬ
+U+1fad O # Character á¾
+U+1fae O # Character á¾®
+U+1faf O # Character ᾯ
+U+1fb0 a # Character á¾°
+U+1fb1 a # Character á¾±
+U+1fb2 a # Character á¾²
+U+1fb3 a # Character á¾³
+U+1fb4 a # Character á¾´
+U+1fb5 ? # Character á¾µ
+U+1fb6 a # Character ᾶ
+U+1fb7 a # Character á¾·
+U+1fb8 A # Character Ᾰ
+U+1fb9 A # Character á¾¹
+U+1fba A # Character Ὰ
+U+1fbb A # Character á¾»
+U+1fbc A # Character á¾¼
+U+1fbd ' # Character á¾½
+U+1fbe i # Character á¾¾
+U+1fbf ' # Character ᾿
+U+1fc0 ~ # Character á¿
+U+1fc1 "~ # Character á¿
+U+1fc2 e # Character á¿
+U+1fc3 e # Character á¿
+U+1fc4 e # Character á¿
+U+1fc5 ? # Character á¿
+U+1fc6 e # Character á¿
+U+1fc7 e # Character á¿
+U+1fc8 E # Character á¿
+U+1fc9 E # Character á¿
+U+1fca E # Character á¿
+U+1fcb E # Character á¿
+U+1fcc E # Character á¿
+U+1fcd '` # Character á¿
+U+1fce '' # Character á¿
+U+1fcf '~ # Character á¿
+U+1fd0 i # Character á¿
+U+1fd1 i # Character á¿
+U+1fd2 i # Character á¿
+U+1fd3 i # Character á¿
+U+1fd4 ? # Character á¿
+U+1fd5 ? # Character á¿
+U+1fd6 i # Character á¿
+U+1fd7 i # Character á¿
+U+1fd8 I # Character á¿
+U+1fd9 I # Character á¿
+U+1fda I # Character á¿
+U+1fdb I # Character á¿
+U+1fdc ? # Character á¿
+U+1fdd `' # Character á¿
+U+1fde `' # Character á¿
+U+1fdf `~ # Character á¿
+U+1fe0 u # Character á¿
+U+1fe1 u # Character á¿¡
+U+1fe2 u # Character á¿¢
+U+1fe3 u # Character á¿£
+U+1fe4 R # Character ῤ
+U+1fe5 R # Character á¿¥
+U+1fe6 u # Character ῦ
+U+1fe7 u # Character ῧ
+U+1fe8 U # Character Ῠ
+U+1fe9 U # Character á¿©
+U+1fea U # Character Ὺ
+U+1feb U # Character á¿«
+U+1fec R # Character Ῥ
+U+1fed "` # Character á¿
+U+1fee "' # Character á¿®
+U+1fef ` # Character `
+U+1ff0 ? # Character á¿°
+U+1ff1 ? # Character ῱
+U+1ff2 o # Character ῲ
+U+1ff3 o # Character ῳ
+U+1ff4 o # Character á¿´
+U+1ff5 ? # Character ῵
+U+1ff6 o # Character ῶ
+U+1ff7 o # Character á¿·
+U+1ff8 O # Character Ὸ
+U+1ff9 O # Character Ό
+U+1ffa O # Character Ὼ
+U+1ffb O # Character á¿»
+U+1ffc O # Character ῼ
+U+1ffd ' # Character ´
+U+1ffe ` # Character ῾
+U+1fff ? # Character á¿¿
diff --git a/resources/chars/ascii/row20.trans b/resources/chars/ascii/row20.trans
new file mode 100644
index 0000000..f217ff3
--- /dev/null
+++ b/resources/chars/ascii/row20.trans
@@ -0,0 +1,259 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+2000 # Character â
+U+2001 # Character â
+U+2002 # Character â
+U+2003 # Character â
+U+2004 # Character â
+U+2005 # Character â
+U+2006 # Character â
+U+2007 # Character â
+U+2008 # Character â
+U+2009 # Character â
+U+200a # Character â
+U+200b # Character â
+U+200c ? # Character â
+U+200d ? # Character â
+U+200e ? # Character â
+U+200f ? # Character â
+U+2010 - # Character â
+U+2011 - # Character â
+U+2012 - # Character â
+U+2013 - # Character â
+U+2014 -- # Character â
+U+2015 -- # Character â
+U+2016 || # Character â
+U+2017 _ # Character â
+U+2018 ' # Character â
+U+2019 ' # Character â
+U+201a , # Character â
+U+201b ' # Character â
+U+201c " # Character â
+U+201d " # Character â
+U+201e ,, # Character â
+U+201f " # Character â
+U+2020 + # Character â
+U+2021 ++ # Character â¡
+U+2022 * # Character â¢
+U+2023 *> # Character â£
+U+2024 . # Character â¤
+U+2025 .. # Character â¥
+U+2026 ... # Character â¦
+U+2027 . # Character â§
+U+202a ? # Character âª
+U+202b ? # Character â«
+U+202c ? # Character â¬
+U+202d ? # Character â
+U+202e ? # Character â®
+U+202f # Character â¯
+U+2030 %0 # Character â°
+U+2031 %00 # Character â±
+U+2032 ' # Character â²
+U+2033 '' # Character â³
+U+2034 ''' # Character â´
+U+2035 ` # Character âµ
+U+2036 `` # Character â¶
+U+2037 ``` # Character â·
+U+2038 ^ # Character â¸
+U+2039 < # Character â¹
+U+203a > # Character âº
+U+203b * # Character â»
+U+203c !! # Character â¼
+U+203d ? # Character â½
+U+203e - # Character â¾
+U+203f _ # Character â¿
+U+2040 - # Character â
+U+2041 ^ # Character â
+U+2042 *** # Character â
+U+2043 -- # Character â
+U+2044 / # Character â
+U+2045 -[ # Character â
+U+2046 ]- # Character â
+U+2047 ? # Character â
+U+2048 ? # Character â
+U+2049 ? # Character â
+U+204a 7 # Character â
+U+204b PP # Character â
+U+204c (] # Character â
+U+204d [) # Character â
+U+204e ? # Character â
+U+204f ? # Character â
+U+2050 ? # Character â
+U+2051 ? # Character â
+U+2052 ? # Character â
+U+2053 ? # Character â
+U+2054 ? # Character â
+U+2055 ? # Character â
+U+2056 ? # Character â
+U+2057 ? # Character â
+U+2058 ? # Character â
+U+2059 ? # Character â
+U+205a ? # Character â
+U+205b ? # Character â
+U+205c ? # Character â
+U+205d ? # Character â
+U+205e ? # Character â
+U+205f ? # Character â
+U+2060 ? # Character â
+U+2061 ? # Character â¡
+U+2062 ? # Character â¢
+U+2063 ? # Character â£
+U+2064 ? # Character â¤
+U+2065 ? # Character â¥
+U+2066 ? # Character â¦
+U+2067 ? # Character â§
+U+2068 ? # Character â¨
+U+2069 ? # Character â©
+U+206a ? # Character âª
+U+206b ? # Character â«
+U+206c ? # Character â¬
+U+206d ? # Character â
+U+206e ? # Character â®
+U+206f ? # Character â¯
+U+2070 ? # Character â°
+U+2071 ? # Character â±
+U+2072 ? # Character â²
+U+2073 ? # Character â³
+U+2074 4 # Character â´
+U+2075 5 # Character âµ
+U+2076 6 # Character â¶
+U+2077 7 # Character â·
+U+2078 8 # Character â¸
+U+2079 9 # Character â¹
+U+207a + # Character âº
+U+207b - # Character â»
+U+207c = # Character â¼
+U+207d ( # Character â½
+U+207e ) # Character â¾
+U+207f n # Character â¿
+U+2080 ? # Character â
+U+2081 1 # Character â
+U+2082 2 # Character â
+U+2083 3 # Character â
+U+2084 4 # Character â
+U+2085 5 # Character â
+U+2086 6 # Character â
+U+2087 7 # Character â
+U+2088 8 # Character â
+U+2089 9 # Character â
+U+208a + # Character â
+U+208b - # Character â
+U+208c = # Character â
+U+208d ( # Character â
+U+208e ) # Character â
+U+208f ? # Character â
+U+2090 ? # Character â
+U+2091 ? # Character â
+U+2092 ? # Character â
+U+2093 ? # Character â
+U+2094 ? # Character â
+U+2095 ? # Character â
+U+2096 ? # Character â
+U+2097 ? # Character â
+U+2098 ? # Character â
+U+2099 ? # Character â
+U+209a ? # Character â
+U+209b ? # Character â
+U+209c ? # Character â
+U+209d ? # Character â
+U+209e ? # Character â
+U+209f ? # Character â
+U+20a0 ECU # Character â
+U+20a1 CL # Character â¡
+U+20a2 Cr # Character â¢
+U+20a3 FF # Character â£
+U+20a4 L # Character â¤
+U+20a5 mil # Character â¥
+U+20a6 N # Character â¦
+U+20a7 Pts # Character â§
+U+20a8 Rs # Character â¨
+U+20a9 W # Character â©
+U+20aa NS # Character âª
+U+20ab D # Character â«
+U+20ac EU # Character â¬
+U+20ad K # Character â
+U+20ae T # Character â®
+U+20af Dr # Character â¯
+U+20b0 ? # Character â°
+U+20b1 ? # Character â±
+U+20b2 ? # Character â²
+U+20b3 ? # Character â³
+U+20b4 ? # Character â´
+U+20b5 ? # Character âµ
+U+20b6 ? # Character â¶
+U+20b7 ? # Character â·
+U+20b8 ? # Character â¸
+U+20b9 ? # Character â¹
+U+20ba ? # Character âº
+U+20bb ? # Character â»
+U+20bc ? # Character â¼
+U+20bd ? # Character â½
+U+20be ? # Character â¾
+U+20bf ? # Character â¿
+U+20c0 ? # Character â
+U+20c1 ? # Character â
+U+20c2 ? # Character â
+U+20c3 ? # Character â
+U+20c4 ? # Character â
+U+20c5 ? # Character â
+U+20c6 ? # Character â
+U+20c7 ? # Character â
+U+20c8 ? # Character â
+U+20c9 ? # Character â
+U+20ca ? # Character â
+U+20cb ? # Character â
+U+20cc ? # Character â
+U+20cd ? # Character â
+U+20ce ? # Character â
+U+20cf ? # Character â
+U+20d0 ? # Character â
+U+20d1 ? # Character â
+U+20d2 ? # Character â
+U+20d3 ? # Character â
+U+20d4 ? # Character â
+U+20d5 ? # Character â
+U+20d6 ? # Character â
+U+20d7 ? # Character â
+U+20d8 ? # Character â
+U+20d9 ? # Character â
+U+20da ? # Character â
+U+20db ? # Character â
+U+20dc ? # Character â
+U+20dd ? # Character â
+U+20de ? # Character â
+U+20df ? # Character â
+U+20e0 ? # Character â
+U+20e1 ? # Character â¡
+U+20e2 ? # Character â¢
+U+20e3 ? # Character â£
+U+20e4 ? # Character â¤
+U+20e5 ? # Character â¥
+U+20e6 ? # Character â¦
+U+20e7 ? # Character â§
+U+20e8 ? # Character â¨
+U+20e9 ? # Character â©
+U+20ea ? # Character âª
+U+20eb ? # Character â«
+U+20ec ? # Character â¬
+U+20ed ? # Character â
+U+20ee ? # Character â®
+U+20ef ? # Character â¯
+U+20f0 ? # Character â°
+U+20f1 ? # Character â±
+U+20f2 ? # Character â²
+U+20f3 ? # Character â³
+U+20f4 ? # Character â´
+U+20f5 ? # Character âµ
+U+20f6 ? # Character â¶
+U+20f7 ? # Character â·
+U+20f8 ? # Character â¸
+U+20f9 ? # Character â¹
+U+20fa ? # Character âº
+U+20fb ? # Character â»
+U+20fc ? # Character â¼
+U+20fd ? # Character â½
+U+20fe ? # Character â¾
+U+20ff ? # Character â¿
diff --git a/resources/chars/ascii/row21.trans b/resources/chars/ascii/row21.trans
new file mode 100644
index 0000000..eb298c4
--- /dev/null
+++ b/resources/chars/ascii/row21.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+2100 ? # Character â
+U+2101 ? # Character â
+U+2102 ? # Character â
+U+2103 ? # Character â
+U+2104 ? # Character â
+U+2105 ? # Character â
+U+2106 ? # Character â
+U+2107 ? # Character â
+U+2108 ? # Character â
+U+2109 ? # Character â
+U+210a ? # Character â
+U+210b ? # Character â
+U+210c ? # Character â
+U+210d ? # Character â
+U+210e ? # Character â
+U+210f ? # Character â
+U+2110 ? # Character â
+U+2111 ? # Character â
+U+2112 ? # Character â
+U+2113 ? # Character â
+U+2114 ? # Character â
+U+2115 ? # Character â
+U+2116 ? # Character â
+U+2117 ? # Character â
+U+2118 ? # Character â
+U+2119 ? # Character â
+U+211a ? # Character â
+U+211b ? # Character â
+U+211c ? # Character â
+U+211d ? # Character â
+U+211e ? # Character â
+U+211f ? # Character â
+U+2120 ? # Character â
+U+2121 ? # Character â¡
+U+2122 ? # Character â¢
+U+2123 ? # Character â£
+U+2124 ? # Character â¤
+U+2125 ? # Character â¥
+U+2126 ? # Character â¦
+U+2127 ? # Character â§
+U+2128 ? # Character â¨
+U+2129 ? # Character â©
+U+212a ? # Character âª
+U+212b ? # Character â«
+U+212c ? # Character â¬
+U+212d ? # Character â
+U+212e ? # Character â®
+U+212f ? # Character â¯
+U+2130 ? # Character â°
+U+2131 ? # Character â±
+U+2132 ? # Character â²
+U+2133 ? # Character â³
+U+2134 ? # Character â´
+U+2135 ? # Character âµ
+U+2136 ? # Character â¶
+U+2137 ? # Character â·
+U+2138 ? # Character â¸
+U+2139 ? # Character â¹
+U+213a ? # Character âº
+U+213b ? # Character â»
+U+213c ? # Character â¼
+U+213d ? # Character â½
+U+213e ? # Character â¾
+U+213f ? # Character â¿
+U+2140 ? # Character â
+U+2141 ? # Character â
+U+2142 ? # Character â
+U+2143 ? # Character â
+U+2144 ? # Character â
+U+2145 ? # Character â
+U+2146 ? # Character â
+U+2147 ? # Character â
+U+2148 ? # Character â
+U+2149 ? # Character â
+U+214a ? # Character â
+U+214b ? # Character â
+U+214c ? # Character â
+U+214d ? # Character â
+U+214e ? # Character â
+U+214f ? # Character â
+U+2150 ? # Character â
+U+2151 ? # Character â
+U+2152 ? # Character â
+U+2153 1/3 # Character â
+U+2154 2/3 # Character â
+U+2155 1/5 # Character â
+U+2156 2/5 # Character â
+U+2157 3/5 # Character â
+U+2158 4/5 # Character â
+U+2159 1/6 # Character â
+U+215a 5/6 # Character â
+U+215b 1/8 # Character â
+U+215c 3/8 # Character â
+U+215d 5/8 # Character â
+U+215e 7/8 # Character â
+U+215f 1/ # Character â
+U+2160 I # Character â
+U+2161 II # Character â
¡
+U+2162 III # Character â
¢
+U+2163 IV # Character â
£
+U+2164 V # Character â
¤
+U+2165 VI # Character â
¥
+U+2166 VII # Character â
¦
+U+2167 VIII # Character â
§
+U+2168 IX # Character â
¨
+U+2169 X # Character â
©
+U+216a XI # Character â
ª
+U+216b XII # Character â
«
+U+216c L # Character â
¬
+U+216d C # Character â
+U+216e D # Character â
®
+U+216f M # Character â
¯
+U+2170 i # Character â
°
+U+2171 ii # Character â
±
+U+2172 iii # Character â
²
+U+2173 iv # Character â
³
+U+2174 v # Character â
´
+U+2175 vi # Character â
µ
+U+2176 vii # Character â
¶
+U+2177 viii # Character â
·
+U+2178 ix # Character â
¸
+U+2179 x # Character â
¹
+U+217a xi # Character â
º
+U+217b xii # Character â
»
+U+217c l # Character â
¼
+U+217d c # Character â
½
+U+217e d # Character â
¾
+U+217f m # Character â
¿
+U+2180 (D # Character â
+U+2181 D) # Character â
+U+2182 ((|)) # Character â
+U+2183 ) # Character â
+U+2184 ? # Character â
+U+2185 ? # Character â
+U+2186 ? # Character â
+U+2187 ? # Character â
+U+2188 ? # Character â
+U+2189 ? # Character â
+U+218a ? # Character â
+U+218b ? # Character â
+U+218c ? # Character â
+U+218d ? # Character â
+U+218e ? # Character â
+U+218f ? # Character â
+U+2190 - # Character â
+U+2191 | # Character â
+U+2192 - # Character â
+U+2193 | # Character â
+U+2194 - # Character â
+U+2195 | # Character â
+U+2196 \ # Character â
+U+2197 / # Character â
+U+2198 \ # Character â
+U+2199 / # Character â
+U+219a - # Character â
+U+219b - # Character â
+U+219c ~ # Character â
+U+219d ~ # Character â
+U+219e - # Character â
+U+219f | # Character â
+U+21a0 - # Character â
+U+21a1 | # Character â¡
+U+21a2 - # Character â¢
+U+21a3 - # Character â£
+U+21a4 - # Character â¤
+U+21a5 | # Character â¥
+U+21a6 - # Character â¦
+U+21a7 | # Character â§
+U+21a8 | # Character â¨
+U+21a9 - # Character â©
+U+21aa - # Character âª
+U+21ab - # Character â«
+U+21ac - # Character â¬
+U+21ad - # Character â
+U+21ae - # Character â®
+U+21af | # Character â¯
+U+21b0 | # Character â°
+U+21b1 | # Character â±
+U+21b2 | # Character â²
+U+21b3 | # Character â³
+U+21b4 | # Character â´
+U+21b5 | # Character âµ
+U+21b6 ^ # Character â¶
+U+21b7 V # Character â·
+U+21b8 \ # Character â¸
+U+21b9 = # Character â¹
+U+21ba V # Character âº
+U+21bb ^ # Character â»
+U+21bc - # Character â¼
+U+21bd - # Character â½
+U+21be | # Character â¾
+U+21bf | # Character â¿
+U+21c0 - # Character â
+U+21c1 - # Character â
+U+21c2 | # Character â
+U+21c3 | # Character â
+U+21c4 = # Character â
+U+21c5 | # Character â
+U+21c6 = # Character â
+U+21c7 = # Character â
+U+21c8 | # Character â
+U+21c9 = # Character â
+U+21ca | # Character â
+U+21cb = # Character â
+U+21cc = # Character â
+U+21cd = # Character â
+U+21ce = # Character â
+U+21cf = # Character â
+U+21d0 = # Character â
+U+21d1 | # Character â
+U+21d2 = # Character â
+U+21d3 | # Character â
+U+21d4 = # Character â
+U+21d5 | # Character â
+U+21d6 \ # Character â
+U+21d7 / # Character â
+U+21d8 \ # Character â
+U+21d9 / # Character â
+U+21da = # Character â
+U+21db = # Character â
+U+21dc ~ # Character â
+U+21dd ~ # Character â
+U+21de | # Character â
+U+21df | # Character â
+U+21e0 - # Character â
+U+21e1 | # Character â¡
+U+21e2 - # Character â¢
+U+21e3 | # Character â£
+U+21e4 - # Character â¤
+U+21e5 - # Character â¥
+U+21e6 - # Character â¦
+U+21e7 | # Character â§
+U+21e8 - # Character â¨
+U+21e9 | # Character â©
+U+21ea | # Character âª
+U+21eb | # Character â«
+U+21ec | # Character â¬
+U+21ed | # Character â
+U+21ee | # Character â®
+U+21ef | # Character â¯
+U+21f0 - # Character â°
+U+21f1 \ # Character â±
+U+21f2 \ # Character â²
+U+21f3 | # Character â³
+U+21f4 ? # Character â´
+U+21f5 ? # Character âµ
+U+21f6 ? # Character â¶
+U+21f7 ? # Character â·
+U+21f8 ? # Character â¸
+U+21f9 ? # Character â¹
+U+21fa ? # Character âº
+U+21fb ? # Character â»
+U+21fc ? # Character â¼
+U+21fd ? # Character â½
+U+21fe ? # Character â¾
+U+21ff ? # Character â¿
diff --git a/resources/chars/ascii/row25.trans b/resources/chars/ascii/row25.trans
new file mode 100644
index 0000000..e98f38e
--- /dev/null
+++ b/resources/chars/ascii/row25.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+2500 - # Character â
+U+2501 - # Character â
+U+2502 | # Character â
+U+2503 | # Character â
+U+2504 - # Character â
+U+2505 - # Character â
+U+2506 | # Character â
+U+2507 | # Character â
+U+2508 - # Character â
+U+2509 - # Character â
+U+250a | # Character â
+U+250b | # Character â
+U+250c + # Character â
+U+250d + # Character â
+U+250e + # Character â
+U+250f + # Character â
+U+2510 + # Character â
+U+2511 + # Character â
+U+2512 + # Character â
+U+2513 + # Character â
+U+2514 + # Character â
+U+2515 + # Character â
+U+2516 + # Character â
+U+2517 + # Character â
+U+2518 + # Character â
+U+2519 + # Character â
+U+251a + # Character â
+U+251b + # Character â
+U+251c + # Character â
+U+251d + # Character â
+U+251e + # Character â
+U+251f + # Character â
+U+2520 + # Character â
+U+2521 + # Character â¡
+U+2522 + # Character â¢
+U+2523 + # Character â£
+U+2524 + # Character â¤
+U+2525 + # Character â¥
+U+2526 + # Character â¦
+U+2527 + # Character â§
+U+2528 + # Character â¨
+U+2529 + # Character â©
+U+252a + # Character âª
+U+252b + # Character â«
+U+252c + # Character â¬
+U+252d + # Character â
+U+252e + # Character â®
+U+252f + # Character â¯
+U+2530 + # Character â°
+U+2531 + # Character â±
+U+2532 + # Character â²
+U+2533 + # Character â³
+U+2534 + # Character â´
+U+2535 + # Character âµ
+U+2536 + # Character â¶
+U+2537 + # Character â·
+U+2538 + # Character â¸
+U+2539 + # Character â¹
+U+253a + # Character âº
+U+253b + # Character â»
+U+253c + # Character â¼
+U+253d + # Character â½
+U+253e + # Character â¾
+U+253f + # Character â¿
+U+2540 + # Character â
+U+2541 + # Character â
+U+2542 + # Character â
+U+2543 + # Character â
+U+2544 + # Character â
+U+2545 + # Character â
+U+2546 + # Character â
+U+2547 + # Character â
+U+2548 + # Character â
+U+2549 + # Character â
+U+254a + # Character â
+U+254b + # Character â
+U+254c - # Character â
+U+254d - # Character â
+U+254e | # Character â
+U+254f | # Character â
+U+2550 - # Character â
+U+2551 | # Character â
+U+2552 + # Character â
+U+2553 + # Character â
+U+2554 + # Character â
+U+2555 + # Character â
+U+2556 + # Character â
+U+2557 + # Character â
+U+2558 + # Character â
+U+2559 + # Character â
+U+255a + # Character â
+U+255b + # Character â
+U+255c + # Character â
+U+255d + # Character â
+U+255e + # Character â
+U+255f + # Character â
+U+2560 + # Character â
+U+2561 + # Character â¡
+U+2562 + # Character â¢
+U+2563 + # Character â£
+U+2564 + # Character â¤
+U+2565 + # Character â¥
+U+2566 + # Character â¦
+U+2567 + # Character â§
+U+2568 + # Character â¨
+U+2569 + # Character â©
+U+256a + # Character âª
+U+256b + # Character â«
+U+256c + # Character â¬
+U+256d + # Character â
+U+256e + # Character â®
+U+256f + # Character â¯
+U+2570 + # Character â°
+U+2571 / # Character â±
+U+2572 \ # Character â²
+U+2573 X # Character â³
+U+2574 - # Character â´
+U+2575 | # Character âµ
+U+2576 - # Character â¶
+U+2577 | # Character â·
+U+2578 - # Character â¸
+U+2579 | # Character â¹
+U+257a - # Character âº
+U+257b | # Character â»
+U+257c - # Character â¼
+U+257d | # Character â½
+U+257e - # Character â¾
+U+257f | # Character â¿
+U+2580 # # Character â
+U+2581 # # Character â
+U+2582 # # Character â
+U+2583 # # Character â
+U+2584 # # Character â
+U+2585 # # Character â
+U+2586 # # Character â
+U+2587 # # Character â
+U+2588 # # Character â
+U+2589 # # Character â
+U+258a # # Character â
+U+258b # # Character â
+U+258c # # Character â
+U+258d # # Character â
+U+258e # # Character â
+U+258f # # Character â
+U+2590 # # Character â
+U+2591 # # Character â
+U+2592 # # Character â
+U+2593 # # Character â
+U+2594 - # Character â
+U+2595 | # Character â
+U+2596 ? # Character â
+U+2597 ? # Character â
+U+2598 ? # Character â
+U+2599 ? # Character â
+U+259a ? # Character â
+U+259b ? # Character â
+U+259c ? # Character â
+U+259d ? # Character â
+U+259e ? # Character â
+U+259f ? # Character â
+U+25a0 # # Character â
+U+25a1 # # Character â¡
+U+25a2 # # Character â¢
+U+25a3 # # Character â£
+U+25a4 # # Character â¤
+U+25a5 # # Character â¥
+U+25a6 # # Character â¦
+U+25a7 # # Character â§
+U+25a8 # # Character â¨
+U+25a9 # # Character â©
+U+25aa # # Character âª
+U+25ab # # Character â«
+U+25ac # # Character â¬
+U+25ad # # Character â
+U+25ae # # Character â®
+U+25af # # Character â¯
+U+25b0 # # Character â°
+U+25b1 # # Character â±
+U+25b2 ^ # Character â²
+U+25b3 ^ # Character â³
+U+25b4 ^ # Character â´
+U+25b5 ^ # Character âµ
+U+25b6 > # Character â¶
+U+25b7 > # Character â·
+U+25b8 > # Character â¸
+U+25b9 > # Character â¹
+U+25ba > # Character âº
+U+25bb > # Character â»
+U+25bc V # Character â¼
+U+25bd V # Character â½
+U+25be V # Character â¾
+U+25bf V # Character â¿
+U+25c0 < # Character â
+U+25c1 < # Character â
+U+25c2 < # Character â
+U+25c3 < # Character â
+U+25c4 < # Character â
+U+25c5 < # Character â
+U+25c6 * # Character â
+U+25c7 * # Character â
+U+25c8 * # Character â
+U+25c9 * # Character â
+U+25ca * # Character â
+U+25cb * # Character â
+U+25cc * # Character â
+U+25cd * # Character â
+U+25ce * # Character â
+U+25cf * # Character â
+U+25d0 * # Character â
+U+25d1 * # Character â
+U+25d2 * # Character â
+U+25d3 * # Character â
+U+25d4 * # Character â
+U+25d5 * # Character â
+U+25d6 * # Character â
+U+25d7 * # Character â
+U+25d8 * # Character â
+U+25d9 * # Character â
+U+25da * # Character â
+U+25db * # Character â
+U+25dc * # Character â
+U+25dd * # Character â
+U+25de * # Character â
+U+25df * # Character â
+U+25e0 * # Character â
+U+25e1 * # Character â¡
+U+25e2 * # Character â¢
+U+25e3 * # Character â£
+U+25e4 * # Character â¤
+U+25e5 * # Character â¥
+U+25e6 * # Character â¦
+U+25e7 # # Character â§
+U+25e8 # # Character â¨
+U+25e9 # # Character â©
+U+25ea # # Character âª
+U+25eb # # Character â«
+U+25ec ^ # Character â¬
+U+25ed ^ # Character â
+U+25ee ^ # Character â®
+U+25ef O # Character â¯
+U+25f0 # # Character â°
+U+25f1 # # Character â±
+U+25f2 # # Character â²
+U+25f3 # # Character â³
+U+25f4 # # Character â´
+U+25f5 # # Character âµ
+U+25f6 # # Character â¶
+U+25f7 # # Character â·
+U+25f8 ? # Character â¸
+U+25f9 ? # Character â¹
+U+25fa ? # Character âº
+U+25fb ? # Character â»
+U+25fc ? # Character â¼
+U+25fd ? # Character â½
+U+25fe ? # Character â¾
+U+25ff ? # Character â¿
diff --git a/resources/chars/ascii/row28.trans b/resources/chars/ascii/row28.trans
new file mode 100644
index 0000000..fdf5d66
--- /dev/null
+++ b/resources/chars/ascii/row28.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+2800 # Character â
+U+2801 a # Character â
+U+2802 1 # Character â
+U+2803 b # Character â
+U+2804 ' # Character â
+U+2805 k # Character â
+U+2806 2 # Character â
+U+2807 l # Character â
+U+2808 @ # Character â
+U+2809 c # Character â
+U+280a i # Character â
+U+280b f # Character â
+U+280c / # Character â
+U+280d m # Character â
+U+280e s # Character â
+U+280f p # Character â
+U+2810 " # Character â
+U+2811 e # Character â
+U+2812 3 # Character â
+U+2813 h # Character â
+U+2814 9 # Character â
+U+2815 o # Character â
+U+2816 6 # Character â
+U+2817 r # Character â
+U+2818 ^ # Character â
+U+2819 d # Character â
+U+281a j # Character â
+U+281b g # Character â
+U+281c > # Character â
+U+281d n # Character â
+U+281e t # Character â
+U+281f q # Character â
+U+2820 , # Character â
+U+2821 * # Character â ¡
+U+2822 5 # Character â ¢
+U+2823 < # Character â £
+U+2824 - # Character â ¤
+U+2825 u # Character â ¥
+U+2826 8 # Character â ¦
+U+2827 v # Character â §
+U+2828 . # Character â ¨
+U+2829 % # Character â ©
+U+282a [ # Character â ª
+U+282b $ # Character â «
+U+282c + # Character â ¬
+U+282d x # Character â
+U+282e ! # Character â ®
+U+282f & # Character â ¯
+U+2830 ; # Character â °
+U+2831 : # Character â ±
+U+2832 4 # Character â ²
+U+2833 \ # Character â ³
+U+2834 ? # Character â ´
+U+2835 z # Character â µ
+U+2836 7 # Character â ¶
+U+2837 ( # Character â ·
+U+2838 _ # Character â ¸
+U+2839 ? # Character â ¹
+U+283a w # Character â º
+U+283b ] # Character â »
+U+283c # # Character â ¼
+U+283d y # Character â ½
+U+283e ) # Character â ¾
+U+283f = # Character â ¿
+U+2840 [d7] # Character â¡
+U+2841 [d17] # Character â¡
+U+2842 [d27] # Character â¡
+U+2843 [d127] # Character â¡
+U+2844 [d37] # Character â¡
+U+2845 [d137] # Character â¡
+U+2846 [d237] # Character â¡
+U+2847 [d1237] # Character â¡
+U+2848 [d47] # Character â¡
+U+2849 [d147] # Character â¡
+U+284a [d247] # Character â¡
+U+284b [d1247] # Character â¡
+U+284c [d347] # Character â¡
+U+284d [d1347] # Character â¡
+U+284e [d2347] # Character â¡
+U+284f [d12347] # Character â¡
+U+2850 [d57] # Character â¡
+U+2851 [d157] # Character â¡
+U+2852 [d257] # Character â¡
+U+2853 [d1257] # Character â¡
+U+2854 [d357] # Character â¡
+U+2855 [d1357] # Character â¡
+U+2856 [d2357] # Character â¡
+U+2857 [d12357] # Character â¡
+U+2858 [d457] # Character â¡
+U+2859 [d1457] # Character â¡
+U+285a [d2457] # Character â¡
+U+285b [d12457] # Character â¡
+U+285c [d3457] # Character â¡
+U+285d [d13457] # Character â¡
+U+285e [d23457] # Character â¡
+U+285f [d123457] # Character â¡
+U+2860 [d67] # Character â¡
+U+2861 [d167] # Character â¡¡
+U+2862 [d267] # Character â¡¢
+U+2863 [d1267] # Character â¡£
+U+2864 [d367] # Character ⡤
+U+2865 [d1367] # Character â¡¥
+U+2866 [d2367] # Character ⡦
+U+2867 [d12367] # Character ⡧
+U+2868 [d467] # Character ⡨
+U+2869 [d1467] # Character â¡©
+U+286a [d2467] # Character ⡪
+U+286b [d12467] # Character â¡«
+U+286c [d3467] # Character ⡬
+U+286d [d13467] # Character â¡
+U+286e [d23467] # Character â¡®
+U+286f [d123467] # Character ⡯
+U+2870 [d567] # Character â¡°
+U+2871 [d1567] # Character ⡱
+U+2872 [d2567] # Character ⡲
+U+2873 [d12567] # Character ⡳
+U+2874 [d3567] # Character â¡´
+U+2875 [d13567] # Character ⡵
+U+2876 [d23567] # Character ⡶
+U+2877 [d123567] # Character â¡·
+U+2878 [d4567] # Character ⡸
+U+2879 [d14567] # Character ⡹
+U+287a [d24567] # Character ⡺
+U+287b [d124567] # Character â¡»
+U+287c [d34567] # Character ⡼
+U+287d [d134567] # Character ⡽
+U+287e [d234567] # Character ⡾
+U+287f [d1234567] # Character â¡¿
+U+2880 [d8] # Character â¢
+U+2881 [d18] # Character â¢
+U+2882 [d28] # Character â¢
+U+2883 [d128] # Character â¢
+U+2884 [d38] # Character â¢
+U+2885 [d138] # Character â¢
+U+2886 [d238] # Character â¢
+U+2887 [d1238] # Character â¢
+U+2888 [d48] # Character â¢
+U+2889 [d148] # Character â¢
+U+288a [d248] # Character â¢
+U+288b [d1248] # Character â¢
+U+288c [d348] # Character â¢
+U+288d [d1348] # Character â¢
+U+288e [d2348] # Character â¢
+U+288f [d12348] # Character â¢
+U+2890 [d58] # Character â¢
+U+2891 [d158] # Character â¢
+U+2892 [d258] # Character â¢
+U+2893 [d1258] # Character â¢
+U+2894 [d358] # Character â¢
+U+2895 [d1358] # Character â¢
+U+2896 [d2358] # Character â¢
+U+2897 [d12358] # Character â¢
+U+2898 [d458] # Character â¢
+U+2899 [d1458] # Character â¢
+U+289a [d2458] # Character â¢
+U+289b [d12458] # Character â¢
+U+289c [d3458] # Character â¢
+U+289d [d13458] # Character â¢
+U+289e [d23458] # Character â¢
+U+289f [d123458] # Character â¢
+U+28a0 [d68] # Character â¢
+U+28a1 [d168] # Character ⢡
+U+28a2 [d268] # Character ⢢
+U+28a3 [d1268] # Character ⢣
+U+28a4 [d368] # Character ⢤
+U+28a5 [d1368] # Character ⢥
+U+28a6 [d2368] # Character ⢦
+U+28a7 [d12368] # Character ⢧
+U+28a8 [d468] # Character ⢨
+U+28a9 [d1468] # Character ⢩
+U+28aa [d2468] # Character ⢪
+U+28ab [d12468] # Character ⢫
+U+28ac [d3468] # Character ⢬
+U+28ad [d13468] # Character â¢
+U+28ae [d23468] # Character ⢮
+U+28af [d123468] # Character ⢯
+U+28b0 [d568] # Character ⢰
+U+28b1 [d1568] # Character ⢱
+U+28b2 [d2568] # Character ⢲
+U+28b3 [d12568] # Character ⢳
+U+28b4 [d3568] # Character ⢴
+U+28b5 [d13568] # Character ⢵
+U+28b6 [d23568] # Character ⢶
+U+28b7 [d123568] # Character ⢷
+U+28b8 [d4568] # Character ⢸
+U+28b9 [d14568] # Character ⢹
+U+28ba [d24568] # Character ⢺
+U+28bb [d124568] # Character ⢻
+U+28bc [d34568] # Character ⢼
+U+28bd [d134568] # Character ⢽
+U+28be [d234568] # Character ⢾
+U+28bf [d1234568] # Character ⢿
+U+28c0 [d78] # Character â£
+U+28c1 [d178] # Character â£
+U+28c2 [d278] # Character â£
+U+28c3 [d1278] # Character â£
+U+28c4 [d378] # Character â£
+U+28c5 [d1378] # Character â£
+U+28c6 [d2378] # Character â£
+U+28c7 [d12378] # Character â£
+U+28c8 [d478] # Character â£
+U+28c9 [d1478] # Character â£
+U+28ca [d2478] # Character â£
+U+28cb [d12478] # Character â£
+U+28cc [d3478] # Character â£
+U+28cd [d13478] # Character â£
+U+28ce [d23478] # Character â£
+U+28cf [d123478] # Character â£
+U+28d0 [d578] # Character â£
+U+28d1 [d1578] # Character â£
+U+28d2 [d2578] # Character â£
+U+28d3 [d12578] # Character â£
+U+28d4 [d3578] # Character â£
+U+28d5 [d13578] # Character â£
+U+28d6 [d23578] # Character â£
+U+28d7 [d123578] # Character â£
+U+28d8 [d4578] # Character â£
+U+28d9 [d14578] # Character â£
+U+28da [d24578] # Character â£
+U+28db [d124578] # Character â£
+U+28dc [d34578] # Character â£
+U+28dd [d134578] # Character â£
+U+28de [d234578] # Character â£
+U+28df [d1234578] # Character â£
+U+28e0 [d678] # Character â£
+U+28e1 [d1678] # Character ⣡
+U+28e2 [d2678] # Character ⣢
+U+28e3 [d12678] # Character ⣣
+U+28e4 [d3678] # Character ⣤
+U+28e5 [d13678] # Character ⣥
+U+28e6 [d23678] # Character ⣦
+U+28e7 [d123678] # Character ⣧
+U+28e8 [d4678] # Character ⣨
+U+28e9 [d14678] # Character ⣩
+U+28ea [d24678] # Character ⣪
+U+28eb [d124678] # Character ⣫
+U+28ec [d34678] # Character ⣬
+U+28ed [d134678] # Character â£
+U+28ee [d234678] # Character ⣮
+U+28ef [d1234678] # Character ⣯
+U+28f0 [d5678] # Character ⣰
+U+28f1 [d15678] # Character ⣱
+U+28f2 [d25678] # Character ⣲
+U+28f3 [d125678] # Character ⣳
+U+28f4 [d35678] # Character ⣴
+U+28f5 [d135678] # Character ⣵
+U+28f6 [d235678] # Character ⣶
+U+28f7 [d1235678] # Character ⣷
+U+28f8 [d45678] # Character ⣸
+U+28f9 [d145678] # Character ⣹
+U+28fa [d245678] # Character ⣺
+U+28fb [d1245678] # Character ⣻
+U+28fc [d345678] # Character ⣼
+U+28fd [d1345678] # Character ⣽
+U+28fe [d2345678] # Character ⣾
+U+28ff [d12345678] # Character ⣿
diff --git a/resources/chars/ascii/row30.trans b/resources/chars/ascii/row30.trans
new file mode 100644
index 0000000..83f00c9
--- /dev/null
+++ b/resources/chars/ascii/row30.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+3000 # Character ã
+U+3001 , # Character ã
+U+3002 . # Character ã
+U+3003 " # Character ã
+U+3004 [JIS] # Character ã
+U+3005 " # Character ã
+U+3006 / # Character ã
+U+3007 ? # Character ã
+U+3008 < # Character ã
+U+3009 > # Character ã
+U+300a << # Character ã
+U+300b >> # Character ã
+U+300c [ # Character ã
+U+300d ] # Character ã
+U+300e { # Character ã
+U+300f } # Character ã
+U+3010 [( # Character ã
+U+3011 )] # Character ã
+U+3012 @ # Character ã
+U+3013 X # Character ã
+U+3014 [ # Character ã
+U+3015 ] # Character ã
+U+3016 [[ # Character ã
+U+3017 ]] # Character ã
+U+3018 (( # Character ã
+U+3019 )) # Character ã
+U+301a [[ # Character ã
+U+301b ]] # Character ã
+U+301c ~ # Character ã
+U+301d `` # Character ã
+U+301e '' # Character ã
+U+301f ,, # Character ã
+U+3020 @ # Character ã
+U+3021 1 # Character ã¡
+U+3022 2 # Character ã¢
+U+3023 3 # Character ã£
+U+3024 4 # Character ã¤
+U+3025 5 # Character ã¥
+U+3026 6 # Character ã¦
+U+3027 7 # Character ã§
+U+3028 8 # Character ã¨
+U+3029 9 # Character ã©
+U+302a ? # Character ãª
+U+302b ? # Character ã«
+U+302c ? # Character ã¬
+U+302d ? # Character ã
+U+302e ? # Character ã®
+U+302f ? # Character ã¯
+U+3030 ~ # Character ã°
+U+3031 + # Character ã±
+U+3032 + # Character ã²
+U+3033 + # Character ã³
+U+3034 + # Character ã´
+U+3035 ? # Character ãµ
+U+3036 @ # Character ã¶
+U+3037 // # Character ã·
+U+3038 +10+ # Character ã¸
+U+3039 +20+ # Character ã¹
+U+303a +30+ # Character ãº
+U+303b ? # Character ã»
+U+303c ? # Character ã¼
+U+303d ? # Character ã½
+U+303e ? # Character ã¾
+U+303f ? # Character ã¿
+U+3040 ? # Character ã
+U+3041 a # Character ã
+U+3042 a # Character ã
+U+3043 i # Character ã
+U+3044 i # Character ã
+U+3045 u # Character ã
+U+3046 u # Character ã
+U+3047 e # Character ã
+U+3048 e # Character ã
+U+3049 o # Character ã
+U+304a o # Character ã
+U+304b ka # Character ã
+U+304c ga # Character ã
+U+304d ki # Character ã
+U+304e gi # Character ã
+U+304f ku # Character ã
+U+3050 gu # Character ã
+U+3051 ke # Character ã
+U+3052 ge # Character ã
+U+3053 ko # Character ã
+U+3054 go # Character ã
+U+3055 sa # Character ã
+U+3056 za # Character ã
+U+3057 si # Character ã
+U+3058 zi # Character ã
+U+3059 su # Character ã
+U+305a zu # Character ã
+U+305b se # Character ã
+U+305c ze # Character ã
+U+305d so # Character ã
+U+305e zo # Character ã
+U+305f ta # Character ã
+U+3060 da # Character ã
+U+3061 ti # Character ã¡
+U+3062 di # Character ã¢
+U+3063 tu # Character ã£
+U+3064 tu # Character ã¤
+U+3065 du # Character ã¥
+U+3066 te # Character ã¦
+U+3067 de # Character ã§
+U+3068 to # Character ã¨
+U+3069 do # Character ã©
+U+306a na # Character ãª
+U+306b ni # Character ã«
+U+306c nu # Character ã¬
+U+306d ne # Character ã
+U+306e no # Character ã®
+U+306f ha # Character ã¯
+U+3070 ba # Character ã°
+U+3071 pa # Character ã±
+U+3072 hi # Character ã²
+U+3073 bi # Character ã³
+U+3074 pi # Character ã´
+U+3075 hu # Character ãµ
+U+3076 bu # Character ã¶
+U+3077 pu # Character ã·
+U+3078 he # Character ã¸
+U+3079 be # Character ã¹
+U+307a pe # Character ãº
+U+307b ho # Character ã»
+U+307c bo # Character ã¼
+U+307d po # Character ã½
+U+307e ma # Character ã¾
+U+307f mi # Character ã¿
+U+3080 mu # Character ã
+U+3081 me # Character ã
+U+3082 mo # Character ã
+U+3083 ya # Character ã
+U+3084 ya # Character ã
+U+3085 yu # Character ã
+U+3086 yu # Character ã
+U+3087 yo # Character ã
+U+3088 yo # Character ã
+U+3089 ra # Character ã
+U+308a ri # Character ã
+U+308b ru # Character ã
+U+308c re # Character ã
+U+308d ro # Character ã
+U+308e wa # Character ã
+U+308f wa # Character ã
+U+3090 wi # Character ã
+U+3091 we # Character ã
+U+3092 wo # Character ã
+U+3093 n # Character ã
+U+3094 vu # Character ã
+U+3095 ? # Character ã
+U+3096 ? # Character ã
+U+3097 ? # Character ã
+U+3098 ? # Character ã
+U+3099 ? # Character ã
+U+309a ? # Character ã
+U+309b ? # Character ã
+U+309c ? # Character ã
+U+309d " # Character ã
+U+309e " # Character ã
+U+309f ? # Character ã
+U+30a0 ? # Character ã
+U+30a1 a # Character ã¡
+U+30a2 a # Character ã¢
+U+30a3 i # Character ã£
+U+30a4 i # Character ã¤
+U+30a5 u # Character ã¥
+U+30a6 u # Character ã¦
+U+30a7 e # Character ã§
+U+30a8 e # Character ã¨
+U+30a9 o # Character ã©
+U+30aa o # Character ãª
+U+30ab ka # Character ã«
+U+30ac ga # Character ã¬
+U+30ad ki # Character ã
+U+30ae gi # Character ã®
+U+30af ku # Character ã¯
+U+30b0 gu # Character ã°
+U+30b1 ke # Character ã±
+U+30b2 ge # Character ã²
+U+30b3 ko # Character ã³
+U+30b4 go # Character ã´
+U+30b5 sa # Character ãµ
+U+30b6 za # Character ã¶
+U+30b7 si # Character ã·
+U+30b8 zi # Character ã¸
+U+30b9 su # Character ã¹
+U+30ba zu # Character ãº
+U+30bb se # Character ã»
+U+30bc ze # Character ã¼
+U+30bd so # Character ã½
+U+30be zo # Character ã¾
+U+30bf ta # Character ã¿
+U+30c0 da # Character ã
+U+30c1 ti # Character ã
+U+30c2 di # Character ã
+U+30c3 tu # Character ã
+U+30c4 tu # Character ã
+U+30c5 du # Character ã
+U+30c6 te # Character ã
+U+30c7 de # Character ã
+U+30c8 to # Character ã
+U+30c9 do # Character ã
+U+30ca na # Character ã
+U+30cb ni # Character ã
+U+30cc nu # Character ã
+U+30cd ne # Character ã
+U+30ce no # Character ã
+U+30cf ha # Character ã
+U+30d0 ba # Character ã
+U+30d1 pa # Character ã
+U+30d2 hi # Character ã
+U+30d3 bi # Character ã
+U+30d4 pi # Character ã
+U+30d5 hu # Character ã
+U+30d6 bu # Character ã
+U+30d7 pu # Character ã
+U+30d8 he # Character ã
+U+30d9 be # Character ã
+U+30da pe # Character ã
+U+30db ho # Character ã
+U+30dc bo # Character ã
+U+30dd po # Character ã
+U+30de ma # Character ã
+U+30df mi # Character ã
+U+30e0 mu # Character ã
+U+30e1 me # Character ã¡
+U+30e2 mo # Character ã¢
+U+30e3 ya # Character ã£
+U+30e4 ya # Character ã¤
+U+30e5 yu # Character ã¥
+U+30e6 yu # Character ã¦
+U+30e7 yo # Character ã§
+U+30e8 yo # Character ã¨
+U+30e9 ra # Character ã©
+U+30ea ri # Character ãª
+U+30eb ru # Character ã«
+U+30ec re # Character ã¬
+U+30ed ro # Character ã
+U+30ee wa # Character ã®
+U+30ef wa # Character ã¯
+U+30f0 wi # Character ã°
+U+30f1 we # Character ã±
+U+30f2 wo # Character ã²
+U+30f3 n # Character ã³
+U+30f4 vu # Character ã´
+U+30f5 ka # Character ãµ
+U+30f6 ke # Character ã¶
+U+30f7 va # Character ã·
+U+30f8 vi # Character ã¸
+U+30f9 ve # Character ã¹
+U+30fa vo # Character ãº
+U+30fb ? # Character ã»
+U+30fc ? # Character ã¼
+U+30fd " # Character ã½
+U+30fe " # Character ã¾
+U+30ff ? # Character ã¿
diff --git a/resources/chars/ascii/row31.trans b/resources/chars/ascii/row31.trans
new file mode 100644
index 0000000..db6537c
--- /dev/null
+++ b/resources/chars/ascii/row31.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+3100 ? # Character ã
+U+3101 ? # Character ã
+U+3102 ? # Character ã
+U+3103 ? # Character ã
+U+3104 ? # Character ã
+U+3105 B # Character ã
+U+3106 P # Character ã
+U+3107 M # Character ã
+U+3108 F # Character ã
+U+3109 D # Character ã
+U+310a T # Character ã
+U+310b N # Character ã
+U+310c L # Character ã
+U+310d G # Character ã
+U+310e K # Character ã
+U+310f H # Character ã
+U+3110 J # Character ã
+U+3111 Q # Character ã
+U+3112 X # Character ã
+U+3113 ZH # Character ã
+U+3114 CH # Character ã
+U+3115 SH # Character ã
+U+3116 R # Character ã
+U+3117 Z # Character ã
+U+3118 C # Character ã
+U+3119 S # Character ã
+U+311a A # Character ã
+U+311b O # Character ã
+U+311c E # Character ã
+U+311d EH # Character ã
+U+311e AI # Character ã
+U+311f EI # Character ã
+U+3120 AU # Character ã
+U+3121 OU # Character ã¡
+U+3122 AN # Character ã¢
+U+3123 EN # Character ã£
+U+3124 ANG # Character ã¤
+U+3125 ENG # Character ã¥
+U+3126 ER # Character ã¦
+U+3127 I # Character ã§
+U+3128 U # Character ã¨
+U+3129 IU # Character ã©
+U+312a V # Character ãª
+U+312b NG # Character ã«
+U+312c GN # Character ã¬
+U+312d ? # Character ã
+U+312e ? # Character ã®
+U+312f ? # Character ã¯
+U+3130 ? # Character ã°
+U+3131 g # Character ã±
+U+3132 gg # Character ã²
+U+3133 gs # Character ã³
+U+3134 n # Character ã´
+U+3135 nj # Character ãµ
+U+3136 nh # Character ã¶
+U+3137 d # Character ã·
+U+3138 dd # Character ã¸
+U+3139 r # Character ã¹
+U+313a lg # Character ãº
+U+313b lm # Character ã»
+U+313c lb # Character ã¼
+U+313d ls # Character ã½
+U+313e lt # Character ã¾
+U+313f lp # Character ã¿
+U+3140 rh # Character ã
+U+3141 m # Character ã
+U+3142 b # Character ã
+U+3143 bb # Character ã
+U+3144 bs # Character ã
+U+3145 s # Character ã
+U+3146 ss # Character ã
+U+3147 ? # Character ã
+U+3148 j # Character ã
+U+3149 jj # Character ã
+U+314a c # Character ã
+U+314b k # Character ã
+U+314c t # Character ã
+U+314d p # Character ã
+U+314e h # Character ã
+U+314f a # Character ã
+U+3150 ae # Character ã
+U+3151 ya # Character ã
+U+3152 yae # Character ã
+U+3153 eo # Character ã
+U+3154 e # Character ã
+U+3155 yeo # Character ã
+U+3156 ye # Character ã
+U+3157 o # Character ã
+U+3158 wa # Character ã
+U+3159 wae # Character ã
+U+315a oe # Character ã
+U+315b yo # Character ã
+U+315c u # Character ã
+U+315d weo # Character ã
+U+315e we # Character ã
+U+315f wi # Character ã
+U+3160 yu # Character ã
+U+3161 eu # Character ã
¡
+U+3162 yi # Character ã
¢
+U+3163 i # Character ã
£
+U+3164 ? # Character ã
¤
+U+3165 nn # Character ã
¥
+U+3166 nd # Character ã
¦
+U+3167 ns # Character ã
§
+U+3168 nZ # Character ã
¨
+U+3169 lgs # Character ã
©
+U+316a ld # Character ã
ª
+U+316b lbs # Character ã
«
+U+316c lZ # Character ã
¬
+U+316d lQ # Character ã
+U+316e mb # Character ã
®
+U+316f ms # Character ã
¯
+U+3170 mZ # Character ã
°
+U+3171 mN # Character ã
±
+U+3172 bg # Character ã
²
+U+3173 ? # Character ã
³
+U+3174 bsg # Character ã
´
+U+3175 bst # Character ã
µ
+U+3176 bj # Character ã
¶
+U+3177 bt # Character ã
·
+U+3178 bN # Character ã
¸
+U+3179 bbN # Character ã
¹
+U+317a sg # Character ã
º
+U+317b sn # Character ã
»
+U+317c sd # Character ã
¼
+U+317d sb # Character ã
½
+U+317e sj # Character ã
¾
+U+317f Z # Character ã
¿
+U+3180 ? # Character ã
+U+3181 N # Character ã
+U+3182 Ns # Character ã
+U+3183 NZ # Character ã
+U+3184 pN # Character ã
+U+3185 hh # Character ã
+U+3186 Q # Character ã
+U+3187 yo-ya # Character ã
+U+3188 yo-yae # Character ã
+U+3189 yo-i # Character ã
+U+318a yu-yeo # Character ã
+U+318b yu-ye # Character ã
+U+318c yu-i # Character ã
+U+318d U # Character ã
+U+318e U-i # Character ã
+U+318f ? # Character ã
+U+3190 ? # Character ã
+U+3191 ? # Character ã
+U+3192 ? # Character ã
+U+3193 ? # Character ã
+U+3194 ? # Character ã
+U+3195 ? # Character ã
+U+3196 ? # Character ã
+U+3197 ? # Character ã
+U+3198 ? # Character ã
+U+3199 ? # Character ã
+U+319a ? # Character ã
+U+319b ? # Character ã
+U+319c ? # Character ã
+U+319d ? # Character ã
+U+319e ? # Character ã
+U+319f ? # Character ã
+U+31a0 BU # Character ã
+U+31a1 ZI # Character ã¡
+U+31a2 JI # Character ã¢
+U+31a3 GU # Character ã£
+U+31a4 EE # Character ã¤
+U+31a5 ENN # Character ã¥
+U+31a6 OO # Character ã¦
+U+31a7 ONN # Character ã§
+U+31a8 IR # Character ã¨
+U+31a9 ANN # Character ã©
+U+31aa INN # Character ãª
+U+31ab UNN # Character ã«
+U+31ac IM # Character ã¬
+U+31ad NGG # Character ã
+U+31ae AINN # Character ã®
+U+31af AUNN # Character ã¯
+U+31b0 AM # Character ã°
+U+31b1 OM # Character ã±
+U+31b2 ONG # Character ã²
+U+31b3 INNN # Character ã³
+U+31b4 P # Character ã´
+U+31b5 T # Character ãµ
+U+31b6 K # Character ã¶
+U+31b7 H # Character ã·
+U+31b8 ? # Character ã¸
+U+31b9 ? # Character ã¹
+U+31ba ? # Character ãº
+U+31bb ? # Character ã»
+U+31bc ? # Character ã¼
+U+31bd ? # Character ã½
+U+31be ? # Character ã¾
+U+31bf ? # Character ã¿
+U+31c0 ? # Character ã
+U+31c1 ? # Character ã
+U+31c2 ? # Character ã
+U+31c3 ? # Character ã
+U+31c4 ? # Character ã
+U+31c5 ? # Character ã
+U+31c6 ? # Character ã
+U+31c7 ? # Character ã
+U+31c8 ? # Character ã
+U+31c9 ? # Character ã
+U+31ca ? # Character ã
+U+31cb ? # Character ã
+U+31cc ? # Character ã
+U+31cd ? # Character ã
+U+31ce ? # Character ã
+U+31cf ? # Character ã
+U+31d0 ? # Character ã
+U+31d1 ? # Character ã
+U+31d2 ? # Character ã
+U+31d3 ? # Character ã
+U+31d4 ? # Character ã
+U+31d5 ? # Character ã
+U+31d6 ? # Character ã
+U+31d7 ? # Character ã
+U+31d8 ? # Character ã
+U+31d9 ? # Character ã
+U+31da ? # Character ã
+U+31db ? # Character ã
+U+31dc ? # Character ã
+U+31dd ? # Character ã
+U+31de ? # Character ã
+U+31df ? # Character ã
+U+31e0 ? # Character ã
+U+31e1 ? # Character ã¡
+U+31e2 ? # Character ã¢
+U+31e3 ? # Character ã£
+U+31e4 ? # Character ã¤
+U+31e5 ? # Character ã¥
+U+31e6 ? # Character ã¦
+U+31e7 ? # Character ã§
+U+31e8 ? # Character ã¨
+U+31e9 ? # Character ã©
+U+31ea ? # Character ãª
+U+31eb ? # Character ã«
+U+31ec ? # Character ã¬
+U+31ed ? # Character ã
+U+31ee ? # Character ã®
+U+31ef ? # Character ã¯
+U+31f0 ? # Character ã°
+U+31f1 ? # Character ã±
+U+31f2 ? # Character ã²
+U+31f3 ? # Character ã³
+U+31f4 ? # Character ã´
+U+31f5 ? # Character ãµ
+U+31f6 ? # Character ã¶
+U+31f7 ? # Character ã·
+U+31f8 ? # Character ã¸
+U+31f9 ? # Character ã¹
+U+31fa ? # Character ãº
+U+31fb ? # Character ã»
+U+31fc ? # Character ã¼
+U+31fd ? # Character ã½
+U+31fe ? # Character ã¾
+U+31ff ? # Character ã¿
diff --git a/resources/chars/ascii/row32.trans b/resources/chars/ascii/row32.trans
new file mode 100644
index 0000000..f8aa96e
--- /dev/null
+++ b/resources/chars/ascii/row32.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+3200 (g) # Character ã
+U+3201 (n) # Character ã
+U+3202 (d) # Character ã
+U+3203 (r) # Character ã
+U+3204 (m) # Character ã
+U+3205 (b) # Character ã
+U+3206 (s) # Character ã
+U+3207 () # Character ã
+U+3208 (j) # Character ã
+U+3209 (c) # Character ã
+U+320a (k) # Character ã
+U+320b (t) # Character ã
+U+320c (p) # Character ã
+U+320d (h) # Character ã
+U+320e (ga) # Character ã
+U+320f (na) # Character ã
+U+3210 (da) # Character ã
+U+3211 (ra) # Character ã
+U+3212 (ma) # Character ã
+U+3213 (ba) # Character ã
+U+3214 (sa) # Character ã
+U+3215 (a) # Character ã
+U+3216 (ja) # Character ã
+U+3217 (ca) # Character ã
+U+3218 (ka) # Character ã
+U+3219 (ta) # Character ã
+U+321a (pa) # Character ã
+U+321b (ha) # Character ã
+U+321c (ju) # Character ã
+U+321d ? # Character ã
+U+321e ? # Character ã
+U+321f ? # Character ã
+U+3220 (1) # Character ã
+U+3221 (2) # Character ã¡
+U+3222 (3) # Character ã¢
+U+3223 (4) # Character ã£
+U+3224 (5) # Character ã¤
+U+3225 (6) # Character ã¥
+U+3226 (7) # Character ã¦
+U+3227 (8) # Character ã§
+U+3228 (9) # Character ã¨
+U+3229 (10) # Character ã©
+U+322a (Yue) # Character ãª
+U+322b (Huo) # Character ã«
+U+322c (Shui) # Character ã¬
+U+322d (Mu) # Character ã
+U+322e (Jin) # Character ã®
+U+322f (Tu) # Character ã¯
+U+3230 (Ri) # Character ã°
+U+3231 (Zhu) # Character ã±
+U+3232 (You) # Character ã²
+U+3233 (She) # Character ã³
+U+3234 (Ming) # Character ã´
+U+3235 (Te) # Character ãµ
+U+3236 (Cai) # Character ã¶
+U+3237 (Zhu) # Character ã·
+U+3238 (Lao) # Character ã¸
+U+3239 (Dai) # Character ã¹
+U+323a (Hu) # Character ãº
+U+323b (Xue) # Character ã»
+U+323c (Jian) # Character ã¼
+U+323d (Qi) # Character ã½
+U+323e (Zi) # Character ã¾
+U+323f (Xie) # Character ã¿
+U+3240 (Ji) # Character ã
+U+3241 (Xiu) # Character ã
+U+3242 << # Character ã
+U+3243 >> # Character ã
+U+3244 ? # Character ã
+U+3245 ? # Character ã
+U+3246 ? # Character ã
+U+3247 ? # Character ã
+U+3248 ? # Character ã
+U+3249 ? # Character ã
+U+324a ? # Character ã
+U+324b ? # Character ã
+U+324c ? # Character ã
+U+324d ? # Character ã
+U+324e ? # Character ã
+U+324f ? # Character ã
+U+3250 ? # Character ã
+U+3251 ? # Character ã
+U+3252 ? # Character ã
+U+3253 ? # Character ã
+U+3254 ? # Character ã
+U+3255 ? # Character ã
+U+3256 ? # Character ã
+U+3257 ? # Character ã
+U+3258 ? # Character ã
+U+3259 ? # Character ã
+U+325a ? # Character ã
+U+325b ? # Character ã
+U+325c ? # Character ã
+U+325d ? # Character ã
+U+325e ? # Character ã
+U+325f ? # Character ã
+U+3260 (g) # Character ã
+U+3261 (n) # Character ã¡
+U+3262 (d) # Character ã¢
+U+3263 (r) # Character ã£
+U+3264 (m) # Character ã¤
+U+3265 (b) # Character ã¥
+U+3266 (s) # Character ã¦
+U+3267 () # Character ã§
+U+3268 (j) # Character ã¨
+U+3269 (c) # Character ã©
+U+326a (k) # Character ãª
+U+326b (t) # Character ã«
+U+326c (p) # Character ã¬
+U+326d (h) # Character ã
+U+326e (ga) # Character ã®
+U+326f (na) # Character ã¯
+U+3270 (da) # Character ã°
+U+3271 (ra) # Character ã±
+U+3272 (ma) # Character ã²
+U+3273 (ba) # Character ã³
+U+3274 (sa) # Character ã´
+U+3275 (a) # Character ãµ
+U+3276 (ja) # Character ã¶
+U+3277 (ca) # Character ã·
+U+3278 (ka) # Character ã¸
+U+3279 (ta) # Character ã¹
+U+327a (pa) # Character ãº
+U+327b (ha) # Character ã»
+U+327c ? # Character ã¼
+U+327d ? # Character ã½
+U+327e ? # Character ã¾
+U+327f KIS # Character ã¿
+U+3280 (1) # Character ã
+U+3281 (2) # Character ã
+U+3282 (3) # Character ã
+U+3283 (4) # Character ã
+U+3284 (5) # Character ã
+U+3285 (6) # Character ã
+U+3286 (7) # Character ã
+U+3287 (8) # Character ã
+U+3288 (9) # Character ã
+U+3289 (10) # Character ã
+U+328a (Yue) # Character ã
+U+328b (Huo) # Character ã
+U+328c (Shui) # Character ã
+U+328d (Mu) # Character ã
+U+328e (Jin) # Character ã
+U+328f (Tu) # Character ã
+U+3290 (Ri) # Character ã
+U+3291 (Zhu) # Character ã
+U+3292 (You) # Character ã
+U+3293 (She) # Character ã
+U+3294 (Ming) # Character ã
+U+3295 (Te) # Character ã
+U+3296 (Cai) # Character ã
+U+3297 (Zhu) # Character ã
+U+3298 (Lao) # Character ã
+U+3299 (Mi) # Character ã
+U+329a (Nan) # Character ã
+U+329b (Nu) # Character ã
+U+329c (Shi) # Character ã
+U+329d (You) # Character ã
+U+329e (Yin) # Character ã
+U+329f (Zhu) # Character ã
+U+32a0 (Xiang) # Character ã
+U+32a1 (Xiu) # Character ã¡
+U+32a2 (Xie) # Character ã¢
+U+32a3 (Zheng) # Character ã£
+U+32a4 (Shang) # Character ã¤
+U+32a5 (Zhong) # Character ã¥
+U+32a6 (Xia) # Character ã¦
+U+32a7 (Zuo) # Character ã§
+U+32a8 (You) # Character ã¨
+U+32a9 (Yi) # Character ã©
+U+32aa (Zong) # Character ãª
+U+32ab (Xue) # Character ã«
+U+32ac (Jian) # Character ã¬
+U+32ad (Qi) # Character ã
+U+32ae (Zi) # Character ã®
+U+32af (Xie) # Character ã¯
+U+32b0 (Ye) # Character ã°
+U+32b1 ? # Character ã±
+U+32b2 ? # Character ã²
+U+32b3 ? # Character ã³
+U+32b4 ? # Character ã´
+U+32b5 ? # Character ãµ
+U+32b6 ? # Character ã¶
+U+32b7 ? # Character ã·
+U+32b8 ? # Character ã¸
+U+32b9 ? # Character ã¹
+U+32ba ? # Character ãº
+U+32bb ? # Character ã»
+U+32bc ? # Character ã¼
+U+32bd ? # Character ã½
+U+32be ? # Character ã¾
+U+32bf ? # Character ã¿
+U+32c0 1M # Character ã
+U+32c1 2M # Character ã
+U+32c2 3M # Character ã
+U+32c3 4M # Character ã
+U+32c4 5M # Character ã
+U+32c5 6M # Character ã
+U+32c6 7M # Character ã
+U+32c7 8M # Character ã
+U+32c8 9M # Character ã
+U+32c9 10M # Character ã
+U+32ca 11M # Character ã
+U+32cb 12M # Character ã
+U+32cc ? # Character ã
+U+32cd ? # Character ã
+U+32ce ? # Character ã
+U+32cf ? # Character ã
+U+32d0 a # Character ã
+U+32d1 i # Character ã
+U+32d2 u # Character ã
+U+32d3 u # Character ã
+U+32d4 o # Character ã
+U+32d5 ka # Character ã
+U+32d6 ki # Character ã
+U+32d7 ku # Character ã
+U+32d8 ke # Character ã
+U+32d9 ko # Character ã
+U+32da sa # Character ã
+U+32db si # Character ã
+U+32dc su # Character ã
+U+32dd se # Character ã
+U+32de so # Character ã
+U+32df ta # Character ã
+U+32e0 ti # Character ã
+U+32e1 tu # Character ã¡
+U+32e2 te # Character ã¢
+U+32e3 to # Character ã£
+U+32e4 na # Character ã¤
+U+32e5 ni # Character ã¥
+U+32e6 nu # Character ã¦
+U+32e7 ne # Character ã§
+U+32e8 no # Character ã¨
+U+32e9 ha # Character ã©
+U+32ea hi # Character ãª
+U+32eb hu # Character ã«
+U+32ec he # Character ã¬
+U+32ed ho # Character ã
+U+32ee ma # Character ã®
+U+32ef mi # Character ã¯
+U+32f0 mu # Character ã°
+U+32f1 me # Character ã±
+U+32f2 mo # Character ã²
+U+32f3 ya # Character ã³
+U+32f4 yu # Character ã´
+U+32f5 yo # Character ãµ
+U+32f6 ra # Character ã¶
+U+32f7 ri # Character ã·
+U+32f8 ru # Character ã¸
+U+32f9 re # Character ã¹
+U+32fa ro # Character ãº
+U+32fb wa # Character ã»
+U+32fc wi # Character ã¼
+U+32fd we # Character ã½
+U+32fe wo # Character ã¾
+U+32ff ? # Character ã¿
diff --git a/resources/chars/ascii/row33.trans b/resources/chars/ascii/row33.trans
new file mode 100644
index 0000000..9497013
--- /dev/null
+++ b/resources/chars/ascii/row33.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+3300 apartment # Character ã
+U+3301 alpha # Character ã
+U+3302 ampere # Character ã
+U+3303 are # Character ã
+U+3304 inning # Character ã
+U+3305 inch # Character ã
+U+3306 won # Character ã
+U+3307 escudo # Character ã
+U+3308 acre # Character ã
+U+3309 ounce # Character ã
+U+330a ohm # Character ã
+U+330b kai-ri # Character ã
+U+330c carat # Character ã
+U+330d calorie # Character ã
+U+330e gallon # Character ã
+U+330f gamma # Character ã
+U+3310 giga # Character ã
+U+3311 guinea # Character ã
+U+3312 curie # Character ã
+U+3313 guilder # Character ã
+U+3314 kilo # Character ã
+U+3315 kilogram # Character ã
+U+3316 kilometer # Character ã
+U+3317 kilowatt # Character ã
+U+3318 gram # Character ã
+U+3319 gram ton # Character ã
+U+331a cruzeiro # Character ã
+U+331b krone # Character ã
+U+331c case # Character ã
+U+331d koruna # Character ã
+U+331e co-op # Character ã
+U+331f cycle # Character ã
+U+3320 centime # Character ã
+U+3321 shilling # Character ã¡
+U+3322 centi # Character ã¢
+U+3323 cent # Character ã£
+U+3324 dozen # Character ã¤
+U+3325 desi # Character ã¥
+U+3326 dollar # Character ã¦
+U+3327 ton # Character ã§
+U+3328 nano # Character ã¨
+U+3329 knot # Character ã©
+U+332a heights # Character ãª
+U+332b percent # Character ã«
+U+332c parts # Character ã¬
+U+332d barrel # Character ã
+U+332e piaster # Character ã®
+U+332f picul # Character ã¯
+U+3330 pico # Character ã°
+U+3331 building # Character ã±
+U+3332 farad # Character ã²
+U+3333 feet # Character ã³
+U+3334 bushel # Character ã´
+U+3335 franc # Character ãµ
+U+3336 hectare # Character ã¶
+U+3337 peso # Character ã·
+U+3338 pfennig # Character ã¸
+U+3339 hertz # Character ã¹
+U+333a pence # Character ãº
+U+333b page # Character ã»
+U+333c beta # Character ã¼
+U+333d point # Character ã½
+U+333e volt # Character ã¾
+U+333f hon # Character ã¿
+U+3340 pound # Character ã
+U+3341 hall # Character ã
+U+3342 horn # Character ã
+U+3343 micro # Character ã
+U+3344 mile # Character ã
+U+3345 mach # Character ã
+U+3346 mark # Character ã
+U+3347 mansion # Character ã
+U+3348 micron # Character ã
+U+3349 milli # Character ã
+U+334a millibar # Character ã
+U+334b mega # Character ã
+U+334c megaton # Character ã
+U+334d meter # Character ã
+U+334e yard # Character ã
+U+334f yard # Character ã
+U+3350 yuan # Character ã
+U+3351 liter # Character ã
+U+3352 lira # Character ã
+U+3353 rupee # Character ã
+U+3354 ruble # Character ã
+U+3355 rem # Character ã
+U+3356 roentgen # Character ã
+U+3357 watt # Character ã
+U+3358 0h # Character ã
+U+3359 1h # Character ã
+U+335a 2h # Character ã
+U+335b 3h # Character ã
+U+335c 4h # Character ã
+U+335d 5h # Character ã
+U+335e 6h # Character ã
+U+335f 7h # Character ã
+U+3360 8h # Character ã
+U+3361 9h # Character ã¡
+U+3362 10h # Character ã¢
+U+3363 11h # Character ã£
+U+3364 12h # Character ã¤
+U+3365 13h # Character ã¥
+U+3366 14h # Character ã¦
+U+3367 15h # Character ã§
+U+3368 16h # Character ã¨
+U+3369 17h # Character ã©
+U+336a 18h # Character ãª
+U+336b 19h # Character ã«
+U+336c 20h # Character ã¬
+U+336d 21h # Character ã
+U+336e 22h # Character ã®
+U+336f 23h # Character ã¯
+U+3370 24h # Character ã°
+U+3371 HPA # Character ã±
+U+3372 da # Character ã²
+U+3373 AU # Character ã³
+U+3374 bar # Character ã´
+U+3375 oV # Character ãµ
+U+3376 pc # Character ã¶
+U+3377 ? # Character ã·
+U+3378 ? # Character ã¸
+U+3379 ? # Character ã¹
+U+337a ? # Character ãº
+U+337b Heisei # Character ã»
+U+337c Syouwa # Character ã¼
+U+337d Taisyou # Character ã½
+U+337e Meiji # Character ã¾
+U+337f Inc. # Character ã¿
+U+3380 pA # Character ã
+U+3381 nA # Character ã
+U+3382 microamp # Character ã
+U+3383 mA # Character ã
+U+3384 kA # Character ã
+U+3385 kB # Character ã
+U+3386 MB # Character ã
+U+3387 GB # Character ã
+U+3388 cal # Character ã
+U+3389 kcal # Character ã
+U+338a pF # Character ã
+U+338b nF # Character ã
+U+338c microFarad # Character ã
+U+338d microgram # Character ã
+U+338e mg # Character ã
+U+338f kg # Character ã
+U+3390 Hz # Character ã
+U+3391 kHz # Character ã
+U+3392 MHz # Character ã
+U+3393 GHz # Character ã
+U+3394 THz # Character ã
+U+3395 microliter # Character ã
+U+3396 ml # Character ã
+U+3397 dl # Character ã
+U+3398 kl # Character ã
+U+3399 fm # Character ã
+U+339a nm # Character ã
+U+339b micrometer # Character ã
+U+339c mm # Character ã
+U+339d cm # Character ã
+U+339e km # Character ã
+U+339f mm^2 # Character ã
+U+33a0 cm^2 # Character ã
+U+33a1 m^2 # Character ã¡
+U+33a2 km^2 # Character ã¢
+U+33a3 mm^4 # Character ã£
+U+33a4 cm^3 # Character ã¤
+U+33a5 m^3 # Character ã¥
+U+33a6 km^3 # Character ã¦
+U+33a7 m/s # Character ã§
+U+33a8 m/s^2 # Character ã¨
+U+33a9 Pa # Character ã©
+U+33aa kPa # Character ãª
+U+33ab MPa # Character ã«
+U+33ac GPa # Character ã¬
+U+33ad rad # Character ã
+U+33ae rad/s # Character ã®
+U+33af rad/s^2 # Character ã¯
+U+33b0 ps # Character ã°
+U+33b1 ns # Character ã±
+U+33b2 microsecond # Character ã²
+U+33b3 ms # Character ã³
+U+33b4 pV # Character ã´
+U+33b5 nV # Character ãµ
+U+33b6 microvolt # Character ã¶
+U+33b7 mV # Character ã·
+U+33b8 kV # Character ã¸
+U+33b9 MV # Character ã¹
+U+33ba pW # Character ãº
+U+33bb nW # Character ã»
+U+33bc microwatt # Character ã¼
+U+33bd mW # Character ã½
+U+33be kW # Character ã¾
+U+33bf MW # Character ã¿
+U+33c0 kOhm # Character ã
+U+33c1 MOhm # Character ã
+U+33c2 a.m. # Character ã
+U+33c3 Bq # Character ã
+U+33c4 cc # Character ã
+U+33c5 cd # Character ã
+U+33c6 C/kg # Character ã
+U+33c7 Co. # Character ã
+U+33c8 dB # Character ã
+U+33c9 Gy # Character ã
+U+33ca ha # Character ã
+U+33cb HP # Character ã
+U+33cc in # Character ã
+U+33cd K.K. # Character ã
+U+33ce KM # Character ã
+U+33cf kt # Character ã
+U+33d0 lm # Character ã
+U+33d1 ln # Character ã
+U+33d2 log # Character ã
+U+33d3 lx # Character ã
+U+33d4 mb # Character ã
+U+33d5 mil # Character ã
+U+33d6 mol # Character ã
+U+33d7 pH # Character ã
+U+33d8 p.m. # Character ã
+U+33d9 PPM # Character ã
+U+33da PR # Character ã
+U+33db sr # Character ã
+U+33dc Sv # Character ã
+U+33dd Wb # Character ã
+U+33de ? # Character ã
+U+33df ? # Character ã
+U+33e0 1d # Character ã
+U+33e1 2d # Character ã¡
+U+33e2 3d # Character ã¢
+U+33e3 4d # Character ã£
+U+33e4 5d # Character ã¤
+U+33e5 6d # Character ã¥
+U+33e6 7d # Character ã¦
+U+33e7 8d # Character ã§
+U+33e8 9d # Character ã¨
+U+33e9 10d # Character ã©
+U+33ea 11d # Character ãª
+U+33eb 12d # Character ã«
+U+33ec 13d # Character ã¬
+U+33ed 14d # Character ã
+U+33ee 15d # Character ã®
+U+33ef 16d # Character ã¯
+U+33f0 17d # Character ã°
+U+33f1 18d # Character ã±
+U+33f2 19d # Character ã²
+U+33f3 20d # Character ã³
+U+33f4 21d # Character ã´
+U+33f5 22d # Character ãµ
+U+33f6 23d # Character ã¶
+U+33f7 24d # Character ã·
+U+33f8 25d # Character ã¸
+U+33f9 26d # Character ã¹
+U+33fa 27d # Character ãº
+U+33fb 28d # Character ã»
+U+33fc 29d # Character ã¼
+U+33fd 30d # Character ã½
+U+33fe 31d # Character ã¾
+U+33ff ? # Character ã¿
diff --git a/resources/chars/ascii/row4e.trans b/resources/chars/ascii/row4e.trans
new file mode 100644
index 0000000..776c565
--- /dev/null
+++ b/resources/chars/ascii/row4e.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+4e00 ? # Character ä¸
+U+4e01 Ding # Character ä¸
+U+4e02 Kao # Character ä¸
+U+4e03 Qi # Character ä¸
+U+4e04 Shang # Character ä¸
+U+4e05 Xia # Character ä¸
+U+4e06 ? # Character ä¸
+U+4e07 Mo # Character ä¸
+U+4e08 Zhang # Character ä¸
+U+4e09 San # Character ä¸
+U+4e0a Shang # Character ä¸
+U+4e0b Xia # Character ä¸
+U+4e0c Ji # Character ä¸
+U+4e0d Bu # Character ä¸
+U+4e0e Yu # Character ä¸
+U+4e0f Mian # Character ä¸
+U+4e10 Gai # Character ä¸
+U+4e11 Chou # Character ä¸
+U+4e12 Chou # Character ä¸
+U+4e13 Zhuan # Character ä¸
+U+4e14 Qie # Character ä¸
+U+4e15 Pi # Character ä¸
+U+4e16 Shi # Character ä¸
+U+4e17 Shi # Character ä¸
+U+4e18 Qiu # Character ä¸
+U+4e19 Bing # Character ä¸
+U+4e1a Ye # Character ä¸
+U+4e1b Cong # Character ä¸
+U+4e1c Dong # Character ä¸
+U+4e1d Si # Character ä¸
+U+4e1e Cheng # Character ä¸
+U+4e1f Diu # Character ä¸
+U+4e20 Qiu # Character ä¸
+U+4e21 Liang # Character 両
+U+4e22 Diu # Character 丢
+U+4e23 You # Character 丣
+U+4e24 Liang # Character 两
+U+4e25 Yan # Character 严
+U+4e26 Bing # Character 並
+U+4e27 Sang # Character 丧
+U+4e28 Gun # Character 丨
+U+4e29 Jiu # Character 丩
+U+4e2a Ge # Character 个
+U+4e2b Ya # Character 丫
+U+4e2c Qiang # Character 丬
+U+4e2d Zhong # Character ä¸
+U+4e2e Ji # Character 丮
+U+4e2f Jie # Character 丯
+U+4e30 Feng # Character 丰
+U+4e31 Guan # Character 丱
+U+4e32 Chuan # Character 串
+U+4e33 Chan # Character 丳
+U+4e34 Lin # Character 临
+U+4e35 Zhuo # Character 丵
+U+4e36 Zhu # Character 丶
+U+4e37 Ha # Character 丷
+U+4e38 Wan # Character 丸
+U+4e39 Dan # Character 丹
+U+4e3a Wei # Character 为
+U+4e3b Zhu # Character 主
+U+4e3c Jing # Character 丼
+U+4e3d Li # Character 丽
+U+4e3e Ju # Character 举
+U+4e3f Pie # Character 丿
+U+4e40 Fu # Character ä¹
+U+4e41 Yi # Character ä¹
+U+4e42 Yi # Character ä¹
+U+4e43 Nai # Character ä¹
+U+4e44 Shime # Character ä¹
+U+4e45 Jiu # Character ä¹
+U+4e46 Jiu # Character ä¹
+U+4e47 Zhe # Character ä¹
+U+4e48 Yao # Character ä¹
+U+4e49 Yi # Character ä¹
+U+4e4a ? # Character ä¹
+U+4e4b Zhi # Character ä¹
+U+4e4c Wu # Character ä¹
+U+4e4d Zha # Character ä¹
+U+4e4e Hu # Character ä¹
+U+4e4f Fa # Character ä¹
+U+4e50 Le # Character ä¹
+U+4e51 Zhong # Character ä¹
+U+4e52 Ping # Character ä¹
+U+4e53 Pang # Character ä¹
+U+4e54 Qiao # Character ä¹
+U+4e55 Hu # Character ä¹
+U+4e56 Guai # Character ä¹
+U+4e57 Cheng # Character ä¹
+U+4e58 Cheng # Character ä¹
+U+4e59 Yi # Character ä¹
+U+4e5a Yin # Character ä¹
+U+4e5b ? # Character ä¹
+U+4e5c Mie # Character ä¹
+U+4e5d Jiu # Character ä¹
+U+4e5e Qi # Character ä¹
+U+4e5f Ye # Character ä¹
+U+4e60 Xi # Character ä¹
+U+4e61 Xiang # Character 乡
+U+4e62 Gai # Character ä¹¢
+U+4e63 Diu # Character ä¹£
+U+4e64 Hal # Character 乤
+U+4e65 ? # Character ä¹¥
+U+4e66 Shu # Character 书
+U+4e67 Twul # Character 乧
+U+4e68 Shi # Character 乨
+U+4e69 Ji # Character 乩
+U+4e6a Nang # Character 乪
+U+4e6b Jia # Character 乫
+U+4e6c Kel # Character 乬
+U+4e6d Shi # Character ä¹
+U+4e6e ? # Character ä¹®
+U+4e6f Ol # Character 乯
+U+4e70 Mai # Character ä¹°
+U+4e71 Luan # Character ä¹±
+U+4e72 Cal # Character ä¹²
+U+4e73 Ru # Character ä¹³
+U+4e74 Xue # Character ä¹´
+U+4e75 Yan # Character ä¹µ
+U+4e76 Fu # Character 乶
+U+4e77 Sha # Character ä¹·
+U+4e78 Na # Character 乸
+U+4e79 Gan # Character ä¹¹
+U+4e7a Sol # Character 乺
+U+4e7b El # Character ä¹»
+U+4e7c Cwul # Character ä¹¼
+U+4e7d ? # Character ä¹½
+U+4e7e Gan # Character ä¹¾
+U+4e7f Chi # Character 乿
+U+4e80 Gui # Character äº
+U+4e81 Gan # Character äº
+U+4e82 Luan # Character äº
+U+4e83 Lin # Character äº
+U+4e84 Yi # Character äº
+U+4e85 Jue # Character äº
+U+4e86 Liao # Character äº
+U+4e87 Ma # Character äº
+U+4e88 Yu # Character äº
+U+4e89 Zheng # Character äº
+U+4e8a Shi # Character äº
+U+4e8b Shi # Character äº
+U+4e8c Er # Character äº
+U+4e8d Chu # Character äº
+U+4e8e Yu # Character äº
+U+4e8f Yu # Character äº
+U+4e90 Yu # Character äº
+U+4e91 Yun # Character äº
+U+4e92 Hu # Character äº
+U+4e93 Qi # Character äº
+U+4e94 Wu # Character äº
+U+4e95 Jing # Character äº
+U+4e96 Si # Character äº
+U+4e97 Sui # Character äº
+U+4e98 Gen # Character äº
+U+4e99 Gen # Character äº
+U+4e9a Ya # Character äº
+U+4e9b Xie # Character äº
+U+4e9c Ya # Character äº
+U+4e9d Qi # Character äº
+U+4e9e Ya # Character äº
+U+4e9f Ji # Character äº
+U+4ea0 Tou # Character äº
+U+4ea1 Wang # Character 亡
+U+4ea2 Kang # Character 亢
+U+4ea3 Ta # Character 亣
+U+4ea4 Jiao # Character 交
+U+4ea5 Hai # Character 亥
+U+4ea6 Yi # Character 亦
+U+4ea7 Chan # Character 产
+U+4ea8 Heng # Character 亨
+U+4ea9 Mu # Character 亩
+U+4eaa ? # Character 亪
+U+4eab Xiang # Character 享
+U+4eac Jing # Character 京
+U+4ead Ting # Character äº
+U+4eae Liang # Character 亮
+U+4eaf Xiang # Character 亯
+U+4eb0 Jing # Character 亰
+U+4eb1 Ye # Character 亱
+U+4eb2 Qin # Character 亲
+U+4eb3 Bo # Character 亳
+U+4eb4 You # Character 亴
+U+4eb5 Xie # Character 亵
+U+4eb6 Dan # Character 亶
+U+4eb7 Lian # Character 亷
+U+4eb8 Duo # Character 亸
+U+4eb9 Wei # Character 亹
+U+4eba Ren # Character 人
+U+4ebb Ren # Character 亻
+U+4ebc Ji # Character 亼
+U+4ebd La # Character 亽
+U+4ebe Wang # Character 亾
+U+4ebf Yi # Character 亿
+U+4ec0 Shi # Character ä»
+U+4ec1 Ren # Character ä»
+U+4ec2 Le # Character ä»
+U+4ec3 Ding # Character ä»
+U+4ec4 Ze # Character ä»
+U+4ec5 Jin # Character ä»
+U+4ec6 Pu # Character ä»
+U+4ec7 Chou # Character ä»
+U+4ec8 Ba # Character ä»
+U+4ec9 Zhang # Character ä»
+U+4eca Jin # Character ä»
+U+4ecb Jie # Character ä»
+U+4ecc Bing # Character ä»
+U+4ecd Reng # Character ä»
+U+4ece Cong # Character ä»
+U+4ecf Fo # Character ä»
+U+4ed0 San # Character ä»
+U+4ed1 Lun # Character ä»
+U+4ed2 Sya # Character ä»
+U+4ed3 Cang # Character ä»
+U+4ed4 Zi # Character ä»
+U+4ed5 Shi # Character ä»
+U+4ed6 Ta # Character ä»
+U+4ed7 Zhang # Character ä»
+U+4ed8 Fu # Character ä»
+U+4ed9 Xian # Character ä»
+U+4eda Xian # Character ä»
+U+4edb Tuo # Character ä»
+U+4edc Hong # Character ä»
+U+4edd Tong # Character ä»
+U+4ede Ren # Character ä»
+U+4edf Qian # Character ä»
+U+4ee0 Gan # Character ä»
+U+4ee1 Yi # Character 仡
+U+4ee2 Di # Character 仢
+U+4ee3 Dai # Character 代
+U+4ee4 Ling # Character 令
+U+4ee5 Yi # Character 以
+U+4ee6 Chao # Character 仦
+U+4ee7 Chang # Character 仧
+U+4ee8 Sa # Character 仨
+U+4ee9 ? # Character 仩
+U+4eea Yi # Character 仪
+U+4eeb Mu # Character 仫
+U+4eec Men # Character 们
+U+4eed Ren # Character ä»
+U+4eee Jia # Character ä»®
+U+4eef Chao # Character 仯
+U+4ef0 Yang # Character ä»°
+U+4ef1 Qian # Character ä»±
+U+4ef2 Zhong # Character 仲
+U+4ef3 Pi # Character 仳
+U+4ef4 Wan # Character ä»´
+U+4ef5 Wu # Character 仵
+U+4ef6 Jian # Character 件
+U+4ef7 Jie # Character ä»·
+U+4ef8 Yao # Character 仸
+U+4ef9 Feng # Character 仹
+U+4efa Cang # Character 仺
+U+4efb Ren # Character ä»»
+U+4efc Wang # Character 仼
+U+4efd Fen # Character 份
+U+4efe Di # Character 仾
+U+4eff Fang # Character 仿
diff --git a/resources/chars/ascii/row4f.trans b/resources/chars/ascii/row4f.trans
new file mode 100644
index 0000000..3cc26ee
--- /dev/null
+++ b/resources/chars/ascii/row4f.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+4f00 Zhong # Character ä¼
+U+4f01 Qi # Character ä¼
+U+4f02 Pei # Character ä¼
+U+4f03 Yu # Character ä¼
+U+4f04 Diao # Character ä¼
+U+4f05 Dun # Character ä¼
+U+4f06 Wen # Character ä¼
+U+4f07 Yi # Character ä¼
+U+4f08 Xin # Character ä¼
+U+4f09 Kang # Character ä¼
+U+4f0a Yi # Character ä¼
+U+4f0b Ji # Character ä¼
+U+4f0c Ai # Character ä¼
+U+4f0d Wu # Character ä¼
+U+4f0e Ji # Character ä¼
+U+4f0f Fu # Character ä¼
+U+4f10 Fa # Character ä¼
+U+4f11 Xiu # Character ä¼
+U+4f12 Jin # Character ä¼
+U+4f13 Bei # Character ä¼
+U+4f14 Dan # Character ä¼
+U+4f15 Fu # Character ä¼
+U+4f16 Tang # Character ä¼
+U+4f17 Zhong # Character ä¼
+U+4f18 You # Character ä¼
+U+4f19 Huo # Character ä¼
+U+4f1a Hui # Character ä¼
+U+4f1b Yu # Character ä¼
+U+4f1c Cui # Character ä¼
+U+4f1d Chuan # Character ä¼
+U+4f1e San # Character ä¼
+U+4f1f Wei # Character ä¼
+U+4f20 Chuan # Character ä¼
+U+4f21 Che # Character 伡
+U+4f22 Ya # Character ä¼¢
+U+4f23 Xian # Character ä¼£
+U+4f24 Shang # Character 伤
+U+4f25 Chang # Character ä¼¥
+U+4f26 Lun # Character 伦
+U+4f27 Cang # Character 伧
+U+4f28 Xun # Character 伨
+U+4f29 Xin # Character 伩
+U+4f2a Wei # Character 伪
+U+4f2b Zhu # Character 伫
+U+4f2c ? # Character 伬
+U+4f2d Xuan # Character ä¼
+U+4f2e Nu # Character ä¼®
+U+4f2f Bo # Character 伯
+U+4f30 Gu # Character ä¼°
+U+4f31 Ni # Character ä¼±
+U+4f32 Ni # Character ä¼²
+U+4f33 Xie # Character ä¼³
+U+4f34 Ban # Character ä¼´
+U+4f35 Xu # Character ä¼µ
+U+4f36 Ling # Character 伶
+U+4f37 Zhou # Character ä¼·
+U+4f38 Shen # Character 伸
+U+4f39 Qu # Character ä¼¹
+U+4f3a Si # Character 伺
+U+4f3b Beng # Character ä¼»
+U+4f3c Si # Character ä¼¼
+U+4f3d Jia # Character ä¼½
+U+4f3e Pi # Character ä¼¾
+U+4f3f Yi # Character 伿
+U+4f40 Si # Character ä½
+U+4f41 Ai # Character ä½
+U+4f42 Zheng # Character ä½
+U+4f43 Dian # Character ä½
+U+4f44 Han # Character ä½
+U+4f45 Mai # Character ä½
+U+4f46 Dan # Character ä½
+U+4f47 Zhu # Character ä½
+U+4f48 Bu # Character ä½
+U+4f49 Qu # Character ä½
+U+4f4a Bi # Character ä½
+U+4f4b Shao # Character ä½
+U+4f4c Ci # Character ä½
+U+4f4d Wei # Character ä½
+U+4f4e Di # Character ä½
+U+4f4f Zhu # Character ä½
+U+4f50 Zuo # Character ä½
+U+4f51 You # Character ä½
+U+4f52 Yang # Character ä½
+U+4f53 Ti # Character ä½
+U+4f54 Zhan # Character ä½
+U+4f55 He # Character ä½
+U+4f56 Bi # Character ä½
+U+4f57 Tuo # Character ä½
+U+4f58 She # Character ä½
+U+4f59 Yu # Character ä½
+U+4f5a Yi # Character ä½
+U+4f5b Fo # Character ä½
+U+4f5c Zuo # Character ä½
+U+4f5d Kou # Character ä½
+U+4f5e Ning # Character ä½
+U+4f5f Tong # Character ä½
+U+4f60 Ni # Character ä½
+U+4f61 Xuan # Character 佡
+U+4f62 Qu # Character ä½¢
+U+4f63 Yong # Character ä½£
+U+4f64 Wa # Character 佤
+U+4f65 Qian # Character ä½¥
+U+4f66 ? # Character 佦
+U+4f67 Ka # Character 佧
+U+4f68 ? # Character 佨
+U+4f69 Pei # Character 佩
+U+4f6a Huai # Character 佪
+U+4f6b He # Character 佫
+U+4f6c Lao # Character 佬
+U+4f6d Xiang # Character ä½
+U+4f6e Ge # Character ä½®
+U+4f6f Yang # Character 佯
+U+4f70 Bai # Character ä½°
+U+4f71 Fa # Character ä½±
+U+4f72 Ming # Character ä½²
+U+4f73 Jia # Character ä½³
+U+4f74 Er # Character ä½´
+U+4f75 Bing # Character ä½µ
+U+4f76 Ji # Character 佶
+U+4f77 Hen # Character ä½·
+U+4f78 Huo # Character 佸
+U+4f79 Gui # Character ä½¹
+U+4f7a Quan # Character 佺
+U+4f7b Tiao # Character ä½»
+U+4f7c Jiao # Character ä½¼
+U+4f7d Ci # Character ä½½
+U+4f7e Yi # Character ä½¾
+U+4f7f Shi # Character 使
+U+4f80 Xing # Character ä¾
+U+4f81 Shen # Character ä¾
+U+4f82 Tuo # Character ä¾
+U+4f83 Kan # Character ä¾
+U+4f84 Zhi # Character ä¾
+U+4f85 Gai # Character ä¾
+U+4f86 Lai # Character ä¾
+U+4f87 Yi # Character ä¾
+U+4f88 Chi # Character ä¾
+U+4f89 Kua # Character ä¾
+U+4f8a Guang # Character ä¾
+U+4f8b Li # Character ä¾
+U+4f8c Yin # Character ä¾
+U+4f8d Shi # Character ä¾
+U+4f8e Mi # Character ä¾
+U+4f8f Zhu # Character ä¾
+U+4f90 Xu # Character ä¾
+U+4f91 You # Character ä¾
+U+4f92 An # Character ä¾
+U+4f93 Lu # Character ä¾
+U+4f94 Mou # Character ä¾
+U+4f95 Er # Character ä¾
+U+4f96 Lun # Character ä¾
+U+4f97 Tong # Character ä¾
+U+4f98 Cha # Character ä¾
+U+4f99 Chi # Character ä¾
+U+4f9a Xun # Character ä¾
+U+4f9b Gong # Character ä¾
+U+4f9c Zhou # Character ä¾
+U+4f9d Yi # Character ä¾
+U+4f9e Ru # Character ä¾
+U+4f9f Jian # Character ä¾
+U+4fa0 Xia # Character ä¾
+U+4fa1 Jia # Character 価
+U+4fa2 Zai # Character ä¾¢
+U+4fa3 Lu # Character ä¾£
+U+4fa4 Ko # Character 侤
+U+4fa5 Jiao # Character ä¾¥
+U+4fa6 Zhen # Character 侦
+U+4fa7 Ce # Character 侧
+U+4fa8 Qiao # Character 侨
+U+4fa9 Kuai # Character 侩
+U+4faa Chai # Character 侪
+U+4fab Ning # Character 侫
+U+4fac Nong # Character 侬
+U+4fad Jin # Character ä¾
+U+4fae Wu # Character ä¾®
+U+4faf Hou # Character 侯
+U+4fb0 Jiong # Character ä¾°
+U+4fb1 Cheng # Character ä¾±
+U+4fb2 Zhen # Character ä¾²
+U+4fb3 Zuo # Character ä¾³
+U+4fb4 Chou # Character ä¾´
+U+4fb5 Qin # Character ä¾µ
+U+4fb6 Lu # Character 侶
+U+4fb7 Ju # Character ä¾·
+U+4fb8 Shu # Character 侸
+U+4fb9 Ting # Character ä¾¹
+U+4fba Shen # Character 侺
+U+4fbb Tuo # Character ä¾»
+U+4fbc Bo # Character ä¾¼
+U+4fbd Nan # Character ä¾½
+U+4fbe Hao # Character ä¾¾
+U+4fbf Bian # Character 便
+U+4fc0 Tui # Character ä¿
+U+4fc1 Yu # Character ä¿
+U+4fc2 Xi # Character ä¿
+U+4fc3 Cu # Character ä¿
+U+4fc4 E # Character ä¿
+U+4fc5 Qiu # Character ä¿
+U+4fc6 Xu # Character ä¿
+U+4fc7 Kuang # Character ä¿
+U+4fc8 Ku # Character ä¿
+U+4fc9 Wu # Character ä¿
+U+4fca Jun # Character ä¿
+U+4fcb Yi # Character ä¿
+U+4fcc Fu # Character ä¿
+U+4fcd Lang # Character ä¿
+U+4fce Zu # Character ä¿
+U+4fcf Qiao # Character ä¿
+U+4fd0 Li # Character ä¿
+U+4fd1 Yong # Character ä¿
+U+4fd2 Hun # Character ä¿
+U+4fd3 Jing # Character ä¿
+U+4fd4 Xian # Character ä¿
+U+4fd5 San # Character ä¿
+U+4fd6 Pai # Character ä¿
+U+4fd7 Su # Character ä¿
+U+4fd8 Fu # Character ä¿
+U+4fd9 Xi # Character ä¿
+U+4fda Li # Character ä¿
+U+4fdb Fu # Character ä¿
+U+4fdc Ping # Character ä¿
+U+4fdd Bao # Character ä¿
+U+4fde Yu # Character ä¿
+U+4fdf Si # Character ä¿
+U+4fe0 Xia # Character ä¿
+U+4fe1 Xin # Character ä¿¡
+U+4fe2 Xiu # Character ä¿¢
+U+4fe3 Yu # Character ä¿£
+U+4fe4 Ti # Character 俤
+U+4fe5 Che # Character ä¿¥
+U+4fe6 Chou # Character 俦
+U+4fe7 ? # Character 俧
+U+4fe8 Yan # Character 俨
+U+4fe9 Lia # Character ä¿©
+U+4fea Li # Character 俪
+U+4feb Lai # Character ä¿«
+U+4fec ? # Character 俬
+U+4fed Jian # Character ä¿
+U+4fee Xiu # Character ä¿®
+U+4fef Fu # Character 俯
+U+4ff0 He # Character ä¿°
+U+4ff1 Ju # Character 俱
+U+4ff2 Xiao # Character 俲
+U+4ff3 Pai # Character 俳
+U+4ff4 Jian # Character ä¿´
+U+4ff5 Biao # Character 俵
+U+4ff6 Chu # Character 俶
+U+4ff7 Fei # Character ä¿·
+U+4ff8 Feng # Character 俸
+U+4ff9 Ya # Character 俹
+U+4ffa An # Character 俺
+U+4ffb Bei # Character ä¿»
+U+4ffc Yu # Character 俼
+U+4ffd Xin # Character 俽
+U+4ffe Bi # Character 俾
+U+4fff Jian # Character ä¿¿
diff --git a/resources/chars/ascii/row50.trans b/resources/chars/ascii/row50.trans
new file mode 100644
index 0000000..974e795
--- /dev/null
+++ b/resources/chars/ascii/row50.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+5000 Chang # Character å
+U+5001 Chi # Character å
+U+5002 Bing # Character å
+U+5003 Zan # Character å
+U+5004 Yao # Character å
+U+5005 Cui # Character å
+U+5006 Lia # Character å
+U+5007 Wan # Character å
+U+5008 Lai # Character å
+U+5009 Cang # Character å
+U+500a Zong # Character å
+U+500b Ge # Character å
+U+500c Guan # Character å
+U+500d Bei # Character å
+U+500e Tian # Character å
+U+500f Shu # Character å
+U+5010 Shu # Character å
+U+5011 Men # Character å
+U+5012 Dao # Character å
+U+5013 Tan # Character å
+U+5014 Jue # Character å
+U+5015 Chui # Character å
+U+5016 Xing # Character å
+U+5017 Peng # Character å
+U+5018 Tang # Character å
+U+5019 Hou # Character å
+U+501a Yi # Character å
+U+501b Qi # Character å
+U+501c Ti # Character å
+U+501d Gan # Character å
+U+501e Jing # Character å
+U+501f Jie # Character å
+U+5020 Sui # Character å
+U+5021 Chang # Character å¡
+U+5022 Jie # Character å¢
+U+5023 Fang # Character å£
+U+5024 Zhi # Character å¤
+U+5025 Kong # Character å¥
+U+5026 Juan # Character å¦
+U+5027 Zong # Character å§
+U+5028 Ju # Character å¨
+U+5029 Qian # Character å©
+U+502a Ni # Character åª
+U+502b Lun # Character å«
+U+502c Zhuo # Character å¬
+U+502d Wei # Character å
+U+502e Luo # Character å®
+U+502f Song # Character å¯
+U+5030 Leng # Character å°
+U+5031 Hun # Character å±
+U+5032 Dong # Character å²
+U+5033 Zi # Character å³
+U+5034 Ben # Character å´
+U+5035 Wu # Character åµ
+U+5036 Ju # Character å¶
+U+5037 Nai # Character å·
+U+5038 Cai # Character å¸
+U+5039 Jian # Character å¹
+U+503a Zhai # Character åº
+U+503b Ye # Character å»
+U+503c Zhi # Character å¼
+U+503d Sha # Character å½
+U+503e Qing # Character å¾
+U+503f ? # Character å¿
+U+5040 Ying # Character å
+U+5041 Cheng # Character å
+U+5042 Jian # Character å
+U+5043 Yan # Character å
+U+5044 Nuan # Character å
+U+5045 Zhong # Character å
+U+5046 Chun # Character å
+U+5047 Jia # Character å
+U+5048 Jie # Character å
+U+5049 Wei # Character å
+U+504a Yu # Character å
+U+504b Bing # Character å
+U+504c Ruo # Character å
+U+504d Ti # Character å
+U+504e Wei # Character å
+U+504f Pian # Character å
+U+5050 Yan # Character å
+U+5051 Feng # Character å
+U+5052 Tang # Character å
+U+5053 Wo # Character å
+U+5054 E # Character å
+U+5055 Xie # Character å
+U+5056 Che # Character å
+U+5057 Sheng # Character å
+U+5058 Kan # Character å
+U+5059 Di # Character å
+U+505a Zuo # Character å
+U+505b Cha # Character å
+U+505c Ting # Character å
+U+505d Bei # Character å
+U+505e Ye # Character å
+U+505f Huang # Character å
+U+5060 Yao # Character å
+U+5061 Zhan # Character å¡
+U+5062 Chou # Character å¢
+U+5063 Yan # Character å£
+U+5064 You # Character å¤
+U+5065 Jian # Character å¥
+U+5066 Xu # Character å¦
+U+5067 Zha # Character å§
+U+5068 Ci # Character å¨
+U+5069 Fu # Character å©
+U+506a Bi # Character åª
+U+506b Zhi # Character å«
+U+506c Zong # Character å¬
+U+506d Mian # Character å
+U+506e Ji # Character å®
+U+506f Yi # Character å¯
+U+5070 Xie # Character å°
+U+5071 Xun # Character å±
+U+5072 Si # Character å²
+U+5073 Duan # Character å³
+U+5074 Ce # Character å´
+U+5075 Zhen # Character åµ
+U+5076 Ou # Character å¶
+U+5077 Tou # Character å·
+U+5078 Tou # Character å¸
+U+5079 Bei # Character å¹
+U+507a Za # Character åº
+U+507b Lu # Character å»
+U+507c Jie # Character å¼
+U+507d Wei # Character å½
+U+507e Fen # Character å¾
+U+507f Chang # Character å¿
+U+5080 Gui # Character å
+U+5081 Sou # Character å
+U+5082 Zhi # Character å
+U+5083 Su # Character å
+U+5084 Xia # Character å
+U+5085 Fu # Character å
+U+5086 Yuan # Character å
+U+5087 Rong # Character å
+U+5088 Li # Character å
+U+5089 Ru # Character å
+U+508a Yun # Character å
+U+508b Gou # Character å
+U+508c Ma # Character å
+U+508d Bang # Character å
+U+508e Dian # Character å
+U+508f Tang # Character å
+U+5090 Hao # Character å
+U+5091 Jie # Character å
+U+5092 Xi # Character å
+U+5093 Shan # Character å
+U+5094 Qian # Character å
+U+5095 Jue # Character å
+U+5096 Cang # Character å
+U+5097 Chu # Character å
+U+5098 San # Character å
+U+5099 Bei # Character å
+U+509a Xiao # Character å
+U+509b Yong # Character å
+U+509c Yao # Character å
+U+509d Tan # Character å
+U+509e Suo # Character å
+U+509f Yang # Character å
+U+50a0 Fa # Character å
+U+50a1 Bing # Character å¡
+U+50a2 Jia # Character å¢
+U+50a3 Dai # Character å£
+U+50a4 Zai # Character å¤
+U+50a5 Tang # Character å¥
+U+50a6 ? # Character å¦
+U+50a7 Bin # Character å§
+U+50a8 Chu # Character å¨
+U+50a9 Nuo # Character å©
+U+50aa Can # Character åª
+U+50ab Lei # Character å«
+U+50ac Cui # Character å¬
+U+50ad Yong # Character å
+U+50ae Zao # Character å®
+U+50af Zong # Character å¯
+U+50b0 Peng # Character å°
+U+50b1 Song # Character å±
+U+50b2 Ao # Character å²
+U+50b3 Chuan # Character å³
+U+50b4 Yu # Character å´
+U+50b5 Zhai # Character åµ
+U+50b6 Cou # Character å¶
+U+50b7 Shang # Character å·
+U+50b8 Qiang # Character å¸
+U+50b9 Jing # Character å¹
+U+50ba Chi # Character åº
+U+50bb Sha # Character å»
+U+50bc Han # Character å¼
+U+50bd Zhang # Character å½
+U+50be Qing # Character å¾
+U+50bf Yan # Character å¿
+U+50c0 Di # Character å
+U+50c1 Xi # Character å
+U+50c2 Lu # Character å
+U+50c3 Bei # Character å
+U+50c4 Piao # Character å
+U+50c5 Jin # Character å
+U+50c6 Lian # Character å
+U+50c7 Lu # Character å
+U+50c8 Man # Character å
+U+50c9 Qian # Character å
+U+50ca Xian # Character å
+U+50cb Tan # Character å
+U+50cc Ying # Character å
+U+50cd Dong # Character å
+U+50ce Zhuan # Character å
+U+50cf Xiang # Character å
+U+50d0 Shan # Character å
+U+50d1 Qiao # Character å
+U+50d2 Jiong # Character å
+U+50d3 Tui # Character å
+U+50d4 Zun # Character å
+U+50d5 Pu # Character å
+U+50d6 Xi # Character å
+U+50d7 Lao # Character å
+U+50d8 Chang # Character å
+U+50d9 Guang # Character å
+U+50da Liao # Character å
+U+50db Qi # Character å
+U+50dc Deng # Character å
+U+50dd Chan # Character å
+U+50de Wei # Character å
+U+50df Ji # Character å
+U+50e0 Fan # Character å
+U+50e1 Hui # Character å¡
+U+50e2 Chuan # Character å¢
+U+50e3 Jian # Character å£
+U+50e4 Dan # Character å¤
+U+50e5 Jiao # Character å¥
+U+50e6 Jiu # Character å¦
+U+50e7 Seng # Character å§
+U+50e8 Fen # Character å¨
+U+50e9 Xian # Character å©
+U+50ea Jue # Character åª
+U+50eb E # Character å«
+U+50ec Jiao # Character å¬
+U+50ed Jian # Character å
+U+50ee Tong # Character å®
+U+50ef Lin # Character å¯
+U+50f0 Bo # Character å°
+U+50f1 Gu # Character å±
+U+50f2 ? # Character å²
+U+50f3 Su # Character å³
+U+50f4 Xian # Character å´
+U+50f5 Jiang # Character åµ
+U+50f6 Min # Character å¶
+U+50f7 Ye # Character å·
+U+50f8 Jin # Character å¸
+U+50f9 Jia # Character å¹
+U+50fa Qiao # Character åº
+U+50fb Pi # Character å»
+U+50fc Feng # Character å¼
+U+50fd Zhou # Character å½
+U+50fe Ai # Character å¾
+U+50ff Sai # Character å¿
diff --git a/resources/chars/ascii/row51.trans b/resources/chars/ascii/row51.trans
new file mode 100644
index 0000000..10da9d6
--- /dev/null
+++ b/resources/chars/ascii/row51.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+5100 Yi # Character å
+U+5101 Jun # Character å
+U+5102 Nong # Character å
+U+5103 Chan # Character å
+U+5104 Yi # Character å
+U+5105 Dang # Character å
+U+5106 Jing # Character å
+U+5107 Xuan # Character å
+U+5108 Kuai # Character å
+U+5109 Jian # Character å
+U+510a Chu # Character å
+U+510b Dan # Character å
+U+510c Jiao # Character å
+U+510d Sha # Character å
+U+510e Zai # Character å
+U+510f ? # Character å
+U+5110 Bin # Character å
+U+5111 An # Character å
+U+5112 Ru # Character å
+U+5113 Tai # Character å
+U+5114 Chou # Character å
+U+5115 Chai # Character å
+U+5116 Lan # Character å
+U+5117 Ni # Character å
+U+5118 Jin # Character å
+U+5119 Qian # Character å
+U+511a Meng # Character å
+U+511b Wu # Character å
+U+511c Ning # Character å
+U+511d Qiong # Character å
+U+511e Ni # Character å
+U+511f Chang # Character å
+U+5120 Lie # Character å
+U+5121 Lei # Character å¡
+U+5122 Lu # Character å¢
+U+5123 Kuang # Character å£
+U+5124 Bao # Character å¤
+U+5125 Du # Character å¥
+U+5126 Biao # Character å¦
+U+5127 Zan # Character å§
+U+5128 Zhi # Character å¨
+U+5129 Si # Character å©
+U+512a You # Character åª
+U+512b Hao # Character å«
+U+512c Chen # Character å¬
+U+512d Chen # Character å
+U+512e Li # Character å®
+U+512f Teng # Character å¯
+U+5130 Wei # Character å°
+U+5131 Long # Character å±
+U+5132 Chu # Character å²
+U+5133 Chan # Character å³
+U+5134 Rang # Character å´
+U+5135 Shu # Character åµ
+U+5136 Hui # Character å¶
+U+5137 Li # Character å·
+U+5138 Luo # Character å¸
+U+5139 Zan # Character å¹
+U+513a Nuo # Character åº
+U+513b Tang # Character å»
+U+513c Yan # Character å¼
+U+513d Lei # Character å½
+U+513e Nang # Character å¾
+U+513f Er # Character å¿
+U+5140 Wu # Character å
+U+5141 Yun # Character å
+U+5142 Zan # Character å
+U+5143 Yuan # Character å
+U+5144 Xiong # Character å
+U+5145 Chong # Character å
+U+5146 Zhao # Character å
+U+5147 Xiong # Character å
+U+5148 Xian # Character å
+U+5149 Guang # Character å
+U+514a Dui # Character å
+U+514b Ke # Character å
+U+514c Dui # Character å
+U+514d Mian # Character å
+U+514e Tu # Character å
+U+514f Chang # Character å
+U+5150 Er # Character å
+U+5151 Dui # Character å
+U+5152 Er # Character å
+U+5153 Xin # Character å
+U+5154 Tu # Character å
+U+5155 Si # Character å
+U+5156 Yan # Character å
+U+5157 Yan # Character å
+U+5158 Shi # Character å
+U+5159 Shi # Character å
+U+515a Dang # Character å
+U+515b Qian # Character å
+U+515c Dou # Character å
+U+515d Fen # Character å
+U+515e Mao # Character å
+U+515f Shen # Character å
+U+5160 Dou # Character å
+U+5161 Bai # Character å
¡
+U+5162 Jing # Character å
¢
+U+5163 Li # Character å
£
+U+5164 Huang # Character å
¤
+U+5165 Ru # Character å
¥
+U+5166 Wang # Character å
¦
+U+5167 Nei # Character å
§
+U+5168 Quan # Character å
¨
+U+5169 Liang # Character å
©
+U+516a Yu # Character å
ª
+U+516b Ba # Character å
«
+U+516c Gong # Character å
¬
+U+516d Liu # Character å
+U+516e Xi # Character å
®
+U+516f ? # Character å
¯
+U+5170 Lan # Character å
°
+U+5171 Gong # Character å
±
+U+5172 Tian # Character å
²
+U+5173 Guan # Character å
³
+U+5174 Xing # Character å
´
+U+5175 Bing # Character å
µ
+U+5176 Qi # Character å
¶
+U+5177 Ju # Character å
·
+U+5178 Dian # Character å
¸
+U+5179 Zi # Character å
¹
+U+517a Ppwun # Character å
º
+U+517b Yang # Character å
»
+U+517c Jian # Character å
¼
+U+517d Shou # Character å
½
+U+517e Ji # Character å
¾
+U+517f Yi # Character å
¿
+U+5180 Ji # Character å
+U+5181 Chan # Character å
+U+5182 Jiong # Character å
+U+5183 Mao # Character å
+U+5184 Ran # Character å
+U+5185 Nei # Character å
+U+5186 Yuan # Character å
+U+5187 Mao # Character å
+U+5188 Gang # Character å
+U+5189 Ran # Character å
+U+518a Ce # Character å
+U+518b Jiong # Character å
+U+518c Ce # Character å
+U+518d Zai # Character å
+U+518e Gua # Character å
+U+518f Jiong # Character å
+U+5190 Mao # Character å
+U+5191 Zhou # Character å
+U+5192 Mou # Character å
+U+5193 Gou # Character å
+U+5194 Xu # Character å
+U+5195 Mian # Character å
+U+5196 Mi # Character å
+U+5197 Rong # Character å
+U+5198 Yin # Character å
+U+5199 Xie # Character å
+U+519a Kan # Character å
+U+519b Jun # Character å
+U+519c Nong # Character å
+U+519d Yi # Character å
+U+519e Mi # Character å
+U+519f Shi # Character å
+U+51a0 Guan # Character å
+U+51a1 Meng # Character å¡
+U+51a2 Zhong # Character å¢
+U+51a3 Ju # Character å£
+U+51a4 Yuan # Character å¤
+U+51a5 Ming # Character å¥
+U+51a6 Kou # Character å¦
+U+51a7 Lam # Character å§
+U+51a8 Fu # Character å¨
+U+51a9 Xie # Character å©
+U+51aa Mi # Character åª
+U+51ab Bing # Character å«
+U+51ac Dong # Character å¬
+U+51ad Tai # Character å
+U+51ae Gang # Character å®
+U+51af Feng # Character å¯
+U+51b0 Bing # Character å°
+U+51b1 Hu # Character å±
+U+51b2 Chong # Character å²
+U+51b3 Jue # Character å³
+U+51b4 Hu # Character å´
+U+51b5 Kuang # Character åµ
+U+51b6 Ye # Character å¶
+U+51b7 Leng # Character å·
+U+51b8 Pan # Character å¸
+U+51b9 Fu # Character å¹
+U+51ba Min # Character åº
+U+51bb Dong # Character å»
+U+51bc Xian # Character å¼
+U+51bd Lie # Character å½
+U+51be Xia # Character å¾
+U+51bf Jian # Character å¿
+U+51c0 Jing # Character å
+U+51c1 Shu # Character å
+U+51c2 Mei # Character å
+U+51c3 Tu # Character å
+U+51c4 Qi # Character å
+U+51c5 Gu # Character å
+U+51c6 Zhun # Character å
+U+51c7 Song # Character å
+U+51c8 Jing # Character å
+U+51c9 Liang # Character å
+U+51ca Qing # Character å
+U+51cb Diao # Character å
+U+51cc Ling # Character å
+U+51cd Dong # Character å
+U+51ce Gan # Character å
+U+51cf Jian # Character å
+U+51d0 Yin # Character å
+U+51d1 Cou # Character å
+U+51d2 Yi # Character å
+U+51d3 Li # Character å
+U+51d4 Cang # Character å
+U+51d5 Ming # Character å
+U+51d6 Zhuen # Character å
+U+51d7 Cui # Character å
+U+51d8 Si # Character å
+U+51d9 Duo # Character å
+U+51da Jin # Character å
+U+51db Lin # Character å
+U+51dc Lin # Character å
+U+51dd Ning # Character å
+U+51de Xi # Character å
+U+51df Du # Character å
+U+51e0 Ji # Character å
+U+51e1 Fan # Character å¡
+U+51e2 Fan # Character å¢
+U+51e3 Fan # Character å£
+U+51e4 Feng # Character å¤
+U+51e5 Ju # Character å¥
+U+51e6 Chu # Character å¦
+U+51e7 Tako # Character å§
+U+51e8 Feng # Character å¨
+U+51e9 Mok # Character å©
+U+51ea Ci # Character åª
+U+51eb Fu # Character å«
+U+51ec Feng # Character å¬
+U+51ed Ping # Character å
+U+51ee Feng # Character å®
+U+51ef Kai # Character å¯
+U+51f0 Huang # Character å°
+U+51f1 Kai # Character å±
+U+51f2 Gan # Character å²
+U+51f3 Deng # Character å³
+U+51f4 Ping # Character å´
+U+51f5 Qu # Character åµ
+U+51f6 Xiong # Character å¶
+U+51f7 Kuai # Character å·
+U+51f8 Tu # Character å¸
+U+51f9 Ao # Character å¹
+U+51fa Chu # Character åº
+U+51fb Ji # Character å»
+U+51fc Dang # Character å¼
+U+51fd Han # Character å½
+U+51fe Han # Character å¾
+U+51ff Zao # Character å¿
diff --git a/resources/chars/ascii/row52.trans b/resources/chars/ascii/row52.trans
new file mode 100644
index 0000000..79ef9ab
--- /dev/null
+++ b/resources/chars/ascii/row52.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+5200 Dao # Character å
+U+5201 Diao # Character å
+U+5202 Dao # Character å
+U+5203 Ren # Character å
+U+5204 Ren # Character å
+U+5205 Chuang # Character å
+U+5206 Fen # Character å
+U+5207 Qie # Character å
+U+5208 Yi # Character å
+U+5209 Ji # Character å
+U+520a Kan # Character å
+U+520b Qian # Character å
+U+520c Cun # Character å
+U+520d Chu # Character å
+U+520e Wen # Character å
+U+520f Ji # Character å
+U+5210 Dan # Character å
+U+5211 Xing # Character å
+U+5212 Hua # Character å
+U+5213 Wan # Character å
+U+5214 Jue # Character å
+U+5215 Li # Character å
+U+5216 Yue # Character å
+U+5217 Lie # Character å
+U+5218 Liu # Character å
+U+5219 Ze # Character å
+U+521a Gang # Character å
+U+521b Chuang # Character å
+U+521c Fu # Character å
+U+521d Chu # Character å
+U+521e Qu # Character å
+U+521f Ju # Character å
+U+5220 Shan # Character å
+U+5221 Min # Character å¡
+U+5222 Ling # Character å¢
+U+5223 Zhong # Character å£
+U+5224 Pan # Character å¤
+U+5225 Bie # Character å¥
+U+5226 Jie # Character å¦
+U+5227 Jie # Character å§
+U+5228 Bao # Character å¨
+U+5229 Li # Character å©
+U+522a Shan # Character åª
+U+522b Bie # Character å«
+U+522c Chan # Character å¬
+U+522d Jing # Character å
+U+522e Gua # Character å®
+U+522f Gen # Character å¯
+U+5230 Dao # Character å°
+U+5231 Chuang # Character å±
+U+5232 Kui # Character å²
+U+5233 Ku # Character å³
+U+5234 Duo # Character å´
+U+5235 Er # Character åµ
+U+5236 Zhi # Character å¶
+U+5237 Shua # Character å·
+U+5238 Quan # Character å¸
+U+5239 Cha # Character å¹
+U+523a Ci # Character åº
+U+523b Ke # Character å»
+U+523c Jie # Character å¼
+U+523d Gui # Character å½
+U+523e Ci # Character å¾
+U+523f Gui # Character å¿
+U+5240 Kai # Character å
+U+5241 Duo # Character å
+U+5242 Ji # Character å
+U+5243 Ti # Character å
+U+5244 Jing # Character å
+U+5245 Lou # Character å
+U+5246 Gen # Character å
+U+5247 Ze # Character å
+U+5248 Yuan # Character å
+U+5249 Cuo # Character å
+U+524a Xue # Character å
+U+524b Ke # Character å
+U+524c La # Character å
+U+524d Qian # Character å
+U+524e Cha # Character å
+U+524f Chuang # Character å
+U+5250 Gua # Character å
+U+5251 Jian # Character å
+U+5252 Cuo # Character å
+U+5253 Li # Character å
+U+5254 Ti # Character å
+U+5255 Fei # Character å
+U+5256 Pou # Character å
+U+5257 Chan # Character å
+U+5258 Qi # Character å
+U+5259 Chuang # Character å
+U+525a Zi # Character å
+U+525b Gang # Character å
+U+525c Wan # Character å
+U+525d Bo # Character å
+U+525e Ji # Character å
+U+525f Duo # Character å
+U+5260 Qing # Character å
+U+5261 Yan # Character å¡
+U+5262 Zhuo # Character å¢
+U+5263 Jian # Character å£
+U+5264 Ji # Character å¤
+U+5265 Bo # Character å¥
+U+5266 Yan # Character å¦
+U+5267 Ju # Character å§
+U+5268 Huo # Character å¨
+U+5269 Sheng # Character å©
+U+526a Jian # Character åª
+U+526b Duo # Character å«
+U+526c Duan # Character å¬
+U+526d Wu # Character å
+U+526e Gua # Character å®
+U+526f Fu # Character å¯
+U+5270 Sheng # Character å°
+U+5271 Jian # Character å±
+U+5272 Ge # Character å²
+U+5273 Zha # Character å³
+U+5274 Kai # Character å´
+U+5275 Chuang # Character åµ
+U+5276 Juan # Character å¶
+U+5277 Chan # Character å·
+U+5278 Tuan # Character å¸
+U+5279 Lu # Character å¹
+U+527a Li # Character åº
+U+527b Fou # Character å»
+U+527c Shan # Character å¼
+U+527d Piao # Character å½
+U+527e Kou # Character å¾
+U+527f Jiao # Character å¿
+U+5280 Gua # Character å
+U+5281 Qiao # Character å
+U+5282 Jue # Character å
+U+5283 Hua # Character å
+U+5284 Zha # Character å
+U+5285 Zhuo # Character å
+U+5286 Lian # Character å
+U+5287 Ju # Character å
+U+5288 Pi # Character å
+U+5289 Liu # Character å
+U+528a Gui # Character å
+U+528b Jiao # Character å
+U+528c Gui # Character å
+U+528d Jian # Character å
+U+528e Jian # Character å
+U+528f Tang # Character å
+U+5290 Huo # Character å
+U+5291 Ji # Character å
+U+5292 Jian # Character å
+U+5293 Yi # Character å
+U+5294 Jian # Character å
+U+5295 Zhi # Character å
+U+5296 Chan # Character å
+U+5297 Cuan # Character å
+U+5298 Mo # Character å
+U+5299 Li # Character å
+U+529a Zhu # Character å
+U+529b Li # Character å
+U+529c Ya # Character å
+U+529d Quan # Character å
+U+529e Ban # Character å
+U+529f Gong # Character å
+U+52a0 Jia # Character å
+U+52a1 Wu # Character å¡
+U+52a2 Mai # Character å¢
+U+52a3 Lie # Character å£
+U+52a4 Jin # Character å¤
+U+52a5 Keng # Character å¥
+U+52a6 Xie # Character å¦
+U+52a7 Zhi # Character å§
+U+52a8 Dong # Character å¨
+U+52a9 Zhu # Character å©
+U+52aa Nu # Character åª
+U+52ab Jie # Character å«
+U+52ac Qu # Character å¬
+U+52ad Shao # Character å
+U+52ae Yi # Character å®
+U+52af Zhu # Character å¯
+U+52b0 Miao # Character å°
+U+52b1 Li # Character å±
+U+52b2 Jing # Character å²
+U+52b3 Lao # Character å³
+U+52b4 Lao # Character å´
+U+52b5 Juan # Character åµ
+U+52b6 Kou # Character å¶
+U+52b7 Yang # Character å·
+U+52b8 Wa # Character å¸
+U+52b9 Xiao # Character å¹
+U+52ba Mou # Character åº
+U+52bb Kuang # Character å»
+U+52bc Jie # Character å¼
+U+52bd Lie # Character å½
+U+52be He # Character å¾
+U+52bf Shi # Character å¿
+U+52c0 Ke # Character å
+U+52c1 Jing # Character å
+U+52c2 Hao # Character å
+U+52c3 Bo # Character å
+U+52c4 Min # Character å
+U+52c5 Chi # Character å
+U+52c6 Lang # Character å
+U+52c7 Yong # Character å
+U+52c8 Yong # Character å
+U+52c9 Mian # Character å
+U+52ca Ke # Character å
+U+52cb Xun # Character å
+U+52cc Juan # Character å
+U+52cd Qing # Character å
+U+52ce Lu # Character å
+U+52cf Pou # Character å
+U+52d0 Meng # Character å
+U+52d1 Lai # Character å
+U+52d2 Le # Character å
+U+52d3 Kai # Character å
+U+52d4 Mian # Character å
+U+52d5 Dong # Character å
+U+52d6 Xu # Character å
+U+52d7 Xu # Character å
+U+52d8 Kan # Character å
+U+52d9 Wu # Character å
+U+52da Yi # Character å
+U+52db Xun # Character å
+U+52dc Weng # Character å
+U+52dd Sheng # Character å
+U+52de Lao # Character å
+U+52df Mu # Character å
+U+52e0 Lu # Character å
+U+52e1 Piao # Character å¡
+U+52e2 Shi # Character å¢
+U+52e3 Ji # Character å£
+U+52e4 Qin # Character å¤
+U+52e5 Qiang # Character å¥
+U+52e6 Jiao # Character å¦
+U+52e7 Quan # Character å§
+U+52e8 Yang # Character å¨
+U+52e9 Yi # Character å©
+U+52ea Jue # Character åª
+U+52eb Fan # Character å«
+U+52ec Juan # Character å¬
+U+52ed Tong # Character å
+U+52ee Ju # Character å®
+U+52ef Dan # Character å¯
+U+52f0 Xie # Character å°
+U+52f1 Mai # Character å±
+U+52f2 Xun # Character å²
+U+52f3 Xun # Character å³
+U+52f4 Lu # Character å´
+U+52f5 Li # Character åµ
+U+52f6 Che # Character å¶
+U+52f7 Rang # Character å·
+U+52f8 Quan # Character å¸
+U+52f9 Bao # Character å¹
+U+52fa Shao # Character åº
+U+52fb Yun # Character å»
+U+52fc Jiu # Character å¼
+U+52fd Bao # Character å½
+U+52fe Gou # Character å¾
+U+52ff Wu # Character å¿
diff --git a/resources/chars/ascii/row53.trans b/resources/chars/ascii/row53.trans
new file mode 100644
index 0000000..e97ddc4
--- /dev/null
+++ b/resources/chars/ascii/row53.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+5300 Yun # Character å
+U+5301 Mwun # Character å
+U+5302 Nay # Character å
+U+5303 Gai # Character å
+U+5304 Gai # Character å
+U+5305 Bao # Character å
+U+5306 Cong # Character å
+U+5307 ? # Character å
+U+5308 Xiong # Character å
+U+5309 Peng # Character å
+U+530a Ju # Character å
+U+530b Tao # Character å
+U+530c Ge # Character å
+U+530d Pu # Character å
+U+530e An # Character å
+U+530f Pao # Character å
+U+5310 Fu # Character å
+U+5311 Gong # Character å
+U+5312 Da # Character å
+U+5313 Jiu # Character å
+U+5314 Qiong # Character å
+U+5315 Bi # Character å
+U+5316 Hua # Character å
+U+5317 Bei # Character å
+U+5318 Nao # Character å
+U+5319 Chi # Character å
+U+531a Fang # Character å
+U+531b Jiu # Character å
+U+531c Yi # Character å
+U+531d Za # Character å
+U+531e Jiang # Character å
+U+531f Kang # Character å
+U+5320 Jiang # Character å
+U+5321 Kuang # Character å¡
+U+5322 Hu # Character å¢
+U+5323 Xia # Character å£
+U+5324 Qu # Character å¤
+U+5325 Bian # Character å¥
+U+5326 Gui # Character å¦
+U+5327 Qie # Character å§
+U+5328 Zang # Character å¨
+U+5329 Kuang # Character å©
+U+532a Fei # Character åª
+U+532b Hu # Character å«
+U+532c Tou # Character å¬
+U+532d Gui # Character å
+U+532e Gui # Character å®
+U+532f Hui # Character å¯
+U+5330 Dan # Character å°
+U+5331 Gui # Character å±
+U+5332 Lian # Character å²
+U+5333 Lian # Character å³
+U+5334 Suan # Character å´
+U+5335 Du # Character åµ
+U+5336 Jiu # Character å¶
+U+5337 Qu # Character å·
+U+5338 Xi # Character å¸
+U+5339 Pi # Character å¹
+U+533a Qu # Character åº
+U+533b Yi # Character å»
+U+533c Qia # Character å¼
+U+533d Yan # Character å½
+U+533e Bian # Character å¾
+U+533f Ni # Character å¿
+U+5340 Qu # Character å
+U+5341 Shi # Character å
+U+5342 Xin # Character å
+U+5343 Qian # Character å
+U+5344 Nian # Character å
+U+5345 Sa # Character å
+U+5346 Zu # Character å
+U+5347 Sheng # Character å
+U+5348 Wu # Character å
+U+5349 Hui # Character å
+U+534a Ban # Character å
+U+534b Shi # Character å
+U+534c Xi # Character å
+U+534d Wan # Character å
+U+534e Hua # Character å
+U+534f Xie # Character å
+U+5350 Wan # Character å
+U+5351 Bei # Character å
+U+5352 Zu # Character å
+U+5353 Zhuo # Character å
+U+5354 Xie # Character å
+U+5355 Dan # Character å
+U+5356 Mai # Character å
+U+5357 Nan # Character å
+U+5358 Dan # Character å
+U+5359 Ji # Character å
+U+535a Bo # Character å
+U+535b Shuai # Character å
+U+535c Bu # Character å
+U+535d Kuang # Character å
+U+535e Bian # Character å
+U+535f Bu # Character å
+U+5360 Zhan # Character å
+U+5361 Qia # Character å¡
+U+5362 Lu # Character å¢
+U+5363 You # Character å£
+U+5364 Lu # Character å¤
+U+5365 Xi # Character å¥
+U+5366 Gua # Character å¦
+U+5367 Wo # Character å§
+U+5368 Xie # Character å¨
+U+5369 Jie # Character å©
+U+536a Jie # Character åª
+U+536b Wei # Character å«
+U+536c Ang # Character å¬
+U+536d Qiong # Character å
+U+536e Zhi # Character å®
+U+536f Mao # Character å¯
+U+5370 Yin # Character å°
+U+5371 Wei # Character å±
+U+5372 Shao # Character å²
+U+5373 Ji # Character å³
+U+5374 Que # Character å´
+U+5375 Luan # Character åµ
+U+5376 Shi # Character å¶
+U+5377 Juan # Character å·
+U+5378 Xie # Character å¸
+U+5379 Xu # Character å¹
+U+537a Jin # Character åº
+U+537b Que # Character å»
+U+537c Wu # Character å¼
+U+537d Ji # Character å½
+U+537e E # Character å¾
+U+537f Qing # Character å¿
+U+5380 Xi # Character å
+U+5381 ? # Character å
+U+5382 Han # Character å
+U+5383 Zhan # Character å
+U+5384 E # Character å
+U+5385 Ting # Character å
+U+5386 Li # Character å
+U+5387 Zhe # Character å
+U+5388 Han # Character å
+U+5389 Li # Character å
+U+538a Ya # Character å
+U+538b Ya # Character å
+U+538c Yan # Character å
+U+538d She # Character å
+U+538e Zhi # Character å
+U+538f Zha # Character å
+U+5390 Pang # Character å
+U+5391 ? # Character å
+U+5392 He # Character å
+U+5393 Ya # Character å
+U+5394 Zhi # Character å
+U+5395 Ce # Character å
+U+5396 Pang # Character å
+U+5397 Ti # Character å
+U+5398 Li # Character å
+U+5399 She # Character å
+U+539a Hou # Character å
+U+539b Ting # Character å
+U+539c Zui # Character å
+U+539d Cuo # Character å
+U+539e Fei # Character å
+U+539f Yuan # Character å
+U+53a0 Ce # Character å
+U+53a1 Yuan # Character å¡
+U+53a2 Xiang # Character å¢
+U+53a3 Yan # Character å£
+U+53a4 Li # Character å¤
+U+53a5 Jue # Character å¥
+U+53a6 Sha # Character å¦
+U+53a7 Dian # Character å§
+U+53a8 Chu # Character å¨
+U+53a9 Jiu # Character å©
+U+53aa Qin # Character åª
+U+53ab Ao # Character å«
+U+53ac Gui # Character å¬
+U+53ad Yan # Character å
+U+53ae Si # Character å®
+U+53af Li # Character å¯
+U+53b0 Chang # Character å°
+U+53b1 Lan # Character å±
+U+53b2 Li # Character å²
+U+53b3 Yan # Character å³
+U+53b4 Yan # Character å´
+U+53b5 Yuan # Character åµ
+U+53b6 Si # Character å¶
+U+53b7 Gong # Character å·
+U+53b8 Lin # Character å¸
+U+53b9 Qiu # Character å¹
+U+53ba Qu # Character åº
+U+53bb Qu # Character å»
+U+53bc Uk # Character å¼
+U+53bd Lei # Character å½
+U+53be Du # Character å¾
+U+53bf Xian # Character å¿
+U+53c0 Zhuan # Character å
+U+53c1 San # Character å
+U+53c2 Can # Character å
+U+53c3 Can # Character å
+U+53c4 Can # Character å
+U+53c5 Can # Character å
+U+53c6 Ai # Character å
+U+53c7 Dai # Character å
+U+53c8 You # Character å
+U+53c9 Cha # Character å
+U+53ca Ji # Character å
+U+53cb You # Character å
+U+53cc Shuang # Character å
+U+53cd Fan # Character å
+U+53ce Shou # Character å
+U+53cf Guai # Character å
+U+53d0 Ba # Character å
+U+53d1 Fa # Character å
+U+53d2 Ruo # Character å
+U+53d3 Shi # Character å
+U+53d4 Shu # Character å
+U+53d5 Zhuo # Character å
+U+53d6 Qu # Character å
+U+53d7 Shou # Character å
+U+53d8 Bian # Character å
+U+53d9 Xu # Character å
+U+53da Jia # Character å
+U+53db Pan # Character å
+U+53dc Sou # Character å
+U+53dd Gao # Character å
+U+53de Wei # Character å
+U+53df Sou # Character å
+U+53e0 Die # Character å
+U+53e1 Rui # Character å¡
+U+53e2 Cong # Character å¢
+U+53e3 Kou # Character å£
+U+53e4 Gu # Character å¤
+U+53e5 Ju # Character å¥
+U+53e6 Ling # Character å¦
+U+53e7 Gua # Character å§
+U+53e8 Tao # Character å¨
+U+53e9 Kou # Character å©
+U+53ea Zhi # Character åª
+U+53eb Jiao # Character å«
+U+53ec Zhao # Character å¬
+U+53ed Ba # Character å
+U+53ee Ding # Character å®
+U+53ef Ke # Character å¯
+U+53f0 Tai # Character å°
+U+53f1 Chi # Character å±
+U+53f2 Shi # Character å²
+U+53f3 You # Character å³
+U+53f4 Qiu # Character å´
+U+53f5 Po # Character åµ
+U+53f6 Xie # Character å¶
+U+53f7 Hao # Character å·
+U+53f8 Si # Character å¸
+U+53f9 Tan # Character å¹
+U+53fa Chi # Character åº
+U+53fb Le # Character å»
+U+53fc Diao # Character å¼
+U+53fd Ji # Character å½
+U+53fe ? # Character å¾
+U+53ff Hong # Character å¿
diff --git a/resources/chars/ascii/row54.trans b/resources/chars/ascii/row54.trans
new file mode 100644
index 0000000..92ab22b
--- /dev/null
+++ b/resources/chars/ascii/row54.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+5400 Mie # Character å
+U+5401 Xu # Character å
+U+5402 Mang # Character å
+U+5403 Chi # Character å
+U+5404 Ge # Character å
+U+5405 Xuan # Character å
+U+5406 Yao # Character å
+U+5407 Zi # Character å
+U+5408 He # Character å
+U+5409 Ji # Character å
+U+540a Diao # Character å
+U+540b Cun # Character å
+U+540c Tong # Character å
+U+540d Ming # Character å
+U+540e Hou # Character å
+U+540f Li # Character å
+U+5410 Tu # Character å
+U+5411 Xiang # Character å
+U+5412 Zha # Character å
+U+5413 Xia # Character å
+U+5414 Ye # Character å
+U+5415 Lu # Character å
+U+5416 A # Character å
+U+5417 Ma # Character å
+U+5418 Ou # Character å
+U+5419 Xue # Character å
+U+541a Yi # Character å
+U+541b Jun # Character å
+U+541c Chou # Character å
+U+541d Lin # Character å
+U+541e Tun # Character å
+U+541f Yin # Character å
+U+5420 Fei # Character å
+U+5421 Bi # Character å¡
+U+5422 Qin # Character å¢
+U+5423 Qin # Character å£
+U+5424 Jie # Character å¤
+U+5425 Bu # Character å¥
+U+5426 Fou # Character å¦
+U+5427 Ba # Character å§
+U+5428 Dun # Character å¨
+U+5429 Fen # Character å©
+U+542a E # Character åª
+U+542b Han # Character å«
+U+542c Ting # Character å¬
+U+542d Hang # Character å
+U+542e Shun # Character å®
+U+542f Qi # Character å¯
+U+5430 Hong # Character å°
+U+5431 Zhi # Character å±
+U+5432 Shen # Character å²
+U+5433 Wu # Character å³
+U+5434 Wu # Character å´
+U+5435 Chao # Character åµ
+U+5436 Ne # Character å¶
+U+5437 Xue # Character å·
+U+5438 Xi # Character å¸
+U+5439 Chui # Character å¹
+U+543a Dou # Character åº
+U+543b Wen # Character å»
+U+543c Hou # Character å¼
+U+543d Ou # Character å½
+U+543e Wu # Character å¾
+U+543f Gao # Character å¿
+U+5440 Ya # Character å
+U+5441 Jun # Character å
+U+5442 Lu # Character å
+U+5443 E # Character å
+U+5444 Ge # Character å
+U+5445 Mei # Character å
+U+5446 Ai # Character å
+U+5447 Qi # Character å
+U+5448 Cheng # Character å
+U+5449 Wu # Character å
+U+544a Gao # Character å
+U+544b Fu # Character å
+U+544c Jiao # Character å
+U+544d Hong # Character å
+U+544e Chi # Character å
+U+544f Sheng # Character å
+U+5450 Ne # Character å
+U+5451 Tun # Character å
+U+5452 Fu # Character å
+U+5453 Yi # Character å
+U+5454 Dai # Character å
+U+5455 Ou # Character å
+U+5456 Li # Character å
+U+5457 Bai # Character å
+U+5458 Yuan # Character å
+U+5459 Kuai # Character å
+U+545a ? # Character å
+U+545b Qiang # Character å
+U+545c Wu # Character å
+U+545d E # Character å
+U+545e Shi # Character å
+U+545f Quan # Character å
+U+5460 Pen # Character å
+U+5461 Wen # Character å¡
+U+5462 Ni # Character å¢
+U+5463 M # Character å£
+U+5464 Ling # Character å¤
+U+5465 Ran # Character å¥
+U+5466 You # Character å¦
+U+5467 Di # Character å§
+U+5468 Zhou # Character å¨
+U+5469 Shi # Character å©
+U+546a Zhou # Character åª
+U+546b Tie # Character å«
+U+546c Xi # Character å¬
+U+546d Yi # Character å
+U+546e Qi # Character å®
+U+546f Ping # Character å¯
+U+5470 Zi # Character å°
+U+5471 Gu # Character å±
+U+5472 Zi # Character å²
+U+5473 Wei # Character å³
+U+5474 Xu # Character å´
+U+5475 He # Character åµ
+U+5476 Nao # Character å¶
+U+5477 Xia # Character å·
+U+5478 Pei # Character å¸
+U+5479 Yi # Character å¹
+U+547a Xiao # Character åº
+U+547b Shen # Character å»
+U+547c Hu # Character å¼
+U+547d Ming # Character å½
+U+547e Da # Character å¾
+U+547f Qu # Character å¿
+U+5480 Ju # Character å
+U+5481 Gem # Character å
+U+5482 Za # Character å
+U+5483 Tuo # Character å
+U+5484 Duo # Character å
+U+5485 Pou # Character å
+U+5486 Pao # Character å
+U+5487 Bi # Character å
+U+5488 Fu # Character å
+U+5489 Yang # Character å
+U+548a He # Character å
+U+548b Zha # Character å
+U+548c He # Character å
+U+548d Hai # Character å
+U+548e Jiu # Character å
+U+548f Yong # Character å
+U+5490 Fu # Character å
+U+5491 Que # Character å
+U+5492 Zhou # Character å
+U+5493 Wa # Character å
+U+5494 Ka # Character å
+U+5495 Gu # Character å
+U+5496 Ka # Character å
+U+5497 Zuo # Character å
+U+5498 Bu # Character å
+U+5499 Long # Character å
+U+549a Dong # Character å
+U+549b Ning # Character å
+U+549c Tha # Character å
+U+549d Si # Character å
+U+549e Xian # Character å
+U+549f Huo # Character å
+U+54a0 Qi # Character å
+U+54a1 Er # Character å¡
+U+54a2 E # Character å¢
+U+54a3 Guang # Character å£
+U+54a4 Zha # Character å¤
+U+54a5 Xi # Character å¥
+U+54a6 Yi # Character å¦
+U+54a7 Lie # Character å§
+U+54a8 Zi # Character å¨
+U+54a9 Mie # Character å©
+U+54aa Mi # Character åª
+U+54ab Zhi # Character å«
+U+54ac Yao # Character å¬
+U+54ad Ji # Character å
+U+54ae Zhou # Character å®
+U+54af Ge # Character å¯
+U+54b0 Shuai # Character å°
+U+54b1 Zan # Character å±
+U+54b2 Xiao # Character å²
+U+54b3 Ke # Character å³
+U+54b4 Hui # Character å´
+U+54b5 Kua # Character åµ
+U+54b6 Huai # Character å¶
+U+54b7 Tao # Character å·
+U+54b8 Xian # Character å¸
+U+54b9 E # Character å¹
+U+54ba Xuan # Character åº
+U+54bb Xiu # Character å»
+U+54bc Wai # Character å¼
+U+54bd Yan # Character å½
+U+54be Lao # Character å¾
+U+54bf Yi # Character å¿
+U+54c0 Ai # Character å
+U+54c1 Pin # Character å
+U+54c2 Shen # Character å
+U+54c3 Tong # Character å
+U+54c4 Hong # Character å
+U+54c5 Xiong # Character å
+U+54c6 Chi # Character å
+U+54c7 Wa # Character å
+U+54c8 Ha # Character å
+U+54c9 Zai # Character å
+U+54ca Yu # Character å
+U+54cb Di # Character å
+U+54cc Pai # Character å
+U+54cd Xiang # Character å
+U+54ce Ai # Character å
+U+54cf Hen # Character å
+U+54d0 Kuang # Character å
+U+54d1 Ya # Character å
+U+54d2 Da # Character å
+U+54d3 Xiao # Character å
+U+54d4 Bi # Character å
+U+54d5 Yue # Character å
+U+54d6 ? # Character å
+U+54d7 Hua # Character å
+U+54d8 Sasou # Character å
+U+54d9 Kuai # Character å
+U+54da Duo # Character å
+U+54db ? # Character å
+U+54dc Ji # Character å
+U+54dd Nong # Character å
+U+54de Mou # Character å
+U+54df Yo # Character å
+U+54e0 Hao # Character å
+U+54e1 Yuan # Character å¡
+U+54e2 Long # Character å¢
+U+54e3 Pou # Character å£
+U+54e4 Mang # Character å¤
+U+54e5 Ge # Character å¥
+U+54e6 E # Character å¦
+U+54e7 Chi # Character å§
+U+54e8 Shao # Character å¨
+U+54e9 Li # Character å©
+U+54ea Na # Character åª
+U+54eb Zu # Character å«
+U+54ec He # Character å¬
+U+54ed Ku # Character å
+U+54ee Xiao # Character å®
+U+54ef Xian # Character å¯
+U+54f0 Lao # Character å°
+U+54f1 Bo # Character å±
+U+54f2 Zhe # Character å²
+U+54f3 Zha # Character å³
+U+54f4 Liang # Character å´
+U+54f5 Ba # Character åµ
+U+54f6 Mie # Character å¶
+U+54f7 Le # Character å·
+U+54f8 Sui # Character å¸
+U+54f9 Fou # Character å¹
+U+54fa Bu # Character åº
+U+54fb Han # Character å»
+U+54fc Heng # Character å¼
+U+54fd Geng # Character å½
+U+54fe Shuo # Character å¾
+U+54ff Ge # Character å¿
diff --git a/resources/chars/ascii/row55.trans b/resources/chars/ascii/row55.trans
new file mode 100644
index 0000000..4810bea
--- /dev/null
+++ b/resources/chars/ascii/row55.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+5500 You # Character å
+U+5501 Yan # Character å
+U+5502 Gu # Character å
+U+5503 Gu # Character å
+U+5504 Bai # Character å
+U+5505 Han # Character å
+U+5506 Suo # Character å
+U+5507 Chun # Character å
+U+5508 Yi # Character å
+U+5509 Ai # Character å
+U+550a Jia # Character å
+U+550b Tu # Character å
+U+550c Xian # Character å
+U+550d Huan # Character å
+U+550e Li # Character å
+U+550f Xi # Character å
+U+5510 Tang # Character å
+U+5511 Zuo # Character å
+U+5512 Qiu # Character å
+U+5513 Che # Character å
+U+5514 Wu # Character å
+U+5515 Zao # Character å
+U+5516 Ya # Character å
+U+5517 Dou # Character å
+U+5518 Qi # Character å
+U+5519 Di # Character å
+U+551a Qin # Character å
+U+551b Ma # Character å
+U+551c Mal # Character å
+U+551d Hong # Character å
+U+551e Dou # Character å
+U+551f Kes # Character å
+U+5520 Lao # Character å
+U+5521 Liang # Character å¡
+U+5522 Suo # Character å¢
+U+5523 Zao # Character å£
+U+5524 Huan # Character å¤
+U+5525 Lang # Character å¥
+U+5526 Sha # Character å¦
+U+5527 Ji # Character å§
+U+5528 Zuo # Character å¨
+U+5529 Wo # Character å©
+U+552a Feng # Character åª
+U+552b Yin # Character å«
+U+552c Hu # Character å¬
+U+552d Qi # Character å
+U+552e Shou # Character å®
+U+552f Wei # Character å¯
+U+5530 Shua # Character å°
+U+5531 Chang # Character å±
+U+5532 Er # Character å²
+U+5533 Li # Character å³
+U+5534 Qiang # Character å´
+U+5535 An # Character åµ
+U+5536 Jie # Character å¶
+U+5537 Yo # Character å·
+U+5538 Nian # Character å¸
+U+5539 Yu # Character å¹
+U+553a Tian # Character åº
+U+553b Lai # Character å»
+U+553c Sha # Character å¼
+U+553d Xi # Character å½
+U+553e Tuo # Character å¾
+U+553f Hu # Character å¿
+U+5540 Ai # Character å
+U+5541 Zhou # Character å
+U+5542 Nou # Character å
+U+5543 Ken # Character å
+U+5544 Zhuo # Character å
+U+5545 Zhuo # Character å
+U+5546 Shang # Character å
+U+5547 Di # Character å
+U+5548 Heng # Character å
+U+5549 Lan # Character å
+U+554a A # Character å
+U+554b Xiao # Character å
+U+554c Xiang # Character å
+U+554d Tun # Character å
+U+554e Wu # Character å
+U+554f Wen # Character å
+U+5550 Cui # Character å
+U+5551 Sha # Character å
+U+5552 Hu # Character å
+U+5553 Qi # Character å
+U+5554 Qi # Character å
+U+5555 Tao # Character å
+U+5556 Dan # Character å
+U+5557 Dan # Character å
+U+5558 Ye # Character å
+U+5559 Zi # Character å
+U+555a Bi # Character å
+U+555b Cui # Character å
+U+555c Chuo # Character å
+U+555d He # Character å
+U+555e Ya # Character å
+U+555f Qi # Character å
+U+5560 Zhe # Character å
+U+5561 Pei # Character å¡
+U+5562 Liang # Character å¢
+U+5563 Xian # Character å£
+U+5564 Pi # Character å¤
+U+5565 Sha # Character å¥
+U+5566 La # Character å¦
+U+5567 Ze # Character å§
+U+5568 Qing # Character å¨
+U+5569 Gua # Character å©
+U+556a Pa # Character åª
+U+556b Zhe # Character å«
+U+556c Se # Character å¬
+U+556d Zhuan # Character å
+U+556e Nie # Character å®
+U+556f Guo # Character å¯
+U+5570 Luo # Character å°
+U+5571 Yan # Character å±
+U+5572 Di # Character å²
+U+5573 Quan # Character å³
+U+5574 Tan # Character å´
+U+5575 Bo # Character åµ
+U+5576 Ding # Character å¶
+U+5577 Lang # Character å·
+U+5578 Xiao # Character å¸
+U+5579 ? # Character å¹
+U+557a Tang # Character åº
+U+557b Chi # Character å»
+U+557c Ti # Character å¼
+U+557d An # Character å½
+U+557e Jiu # Character å¾
+U+557f Dan # Character å¿
+U+5580 Ke # Character å
+U+5581 Yong # Character å
+U+5582 Wei # Character å
+U+5583 Nan # Character å
+U+5584 Shan # Character å
+U+5585 Yu # Character å
+U+5586 Zhe # Character å
+U+5587 La # Character å
+U+5588 Jie # Character å
+U+5589 Hou # Character å
+U+558a Han # Character å
+U+558b Die # Character å
+U+558c Zhou # Character å
+U+558d Chai # Character å
+U+558e Wai # Character å
+U+558f Re # Character å
+U+5590 Yu # Character å
+U+5591 Yin # Character å
+U+5592 Zan # Character å
+U+5593 Yao # Character å
+U+5594 Wo # Character å
+U+5595 Mian # Character å
+U+5596 Hu # Character å
+U+5597 Yun # Character å
+U+5598 Chuan # Character å
+U+5599 Hui # Character å
+U+559a Huan # Character å
+U+559b Huan # Character å
+U+559c Xi # Character å
+U+559d He # Character å
+U+559e Ji # Character å
+U+559f Kui # Character å
+U+55a0 Zhong # Character å
+U+55a1 Wei # Character å¡
+U+55a2 Sha # Character å¢
+U+55a3 Xu # Character å£
+U+55a4 Huang # Character å¤
+U+55a5 Du # Character å¥
+U+55a6 Nie # Character å¦
+U+55a7 Xuan # Character å§
+U+55a8 Liang # Character å¨
+U+55a9 Yu # Character å©
+U+55aa Sang # Character åª
+U+55ab Chi # Character å«
+U+55ac Qiao # Character å¬
+U+55ad Yan # Character å
+U+55ae Dan # Character å®
+U+55af Pen # Character å¯
+U+55b0 Can # Character å°
+U+55b1 Li # Character å±
+U+55b2 Yo # Character å²
+U+55b3 Zha # Character å³
+U+55b4 Wei # Character å´
+U+55b5 Miao # Character åµ
+U+55b6 Ying # Character å¶
+U+55b7 Pen # Character å·
+U+55b8 Phos # Character å¸
+U+55b9 Kui # Character å¹
+U+55ba Xi # Character åº
+U+55bb Yu # Character å»
+U+55bc Jie # Character å¼
+U+55bd Lou # Character å½
+U+55be Ku # Character å¾
+U+55bf Sao # Character å¿
+U+55c0 Huo # Character å
+U+55c1 Ti # Character å
+U+55c2 Yao # Character å
+U+55c3 He # Character å
+U+55c4 A # Character å
+U+55c5 Xiu # Character å
+U+55c6 Qiang # Character å
+U+55c7 Se # Character å
+U+55c8 Yong # Character å
+U+55c9 Su # Character å
+U+55ca Hong # Character å
+U+55cb Xie # Character å
+U+55cc Yi # Character å
+U+55cd Suo # Character å
+U+55ce Ma # Character å
+U+55cf Cha # Character å
+U+55d0 Hai # Character å
+U+55d1 Ke # Character å
+U+55d2 Ta # Character å
+U+55d3 Sang # Character å
+U+55d4 Tian # Character å
+U+55d5 Ru # Character å
+U+55d6 Sou # Character å
+U+55d7 Wa # Character å
+U+55d8 Ji # Character å
+U+55d9 Pang # Character å
+U+55da Wu # Character å
+U+55db Xian # Character å
+U+55dc Shi # Character å
+U+55dd Ge # Character å
+U+55de Zi # Character å
+U+55df Jie # Character å
+U+55e0 Luo # Character å
+U+55e1 Weng # Character å¡
+U+55e2 Wa # Character å¢
+U+55e3 Si # Character å£
+U+55e4 Chi # Character å¤
+U+55e5 Hao # Character å¥
+U+55e6 Suo # Character å¦
+U+55e7 Jia # Character å§
+U+55e8 Hai # Character å¨
+U+55e9 Suo # Character å©
+U+55ea Qin # Character åª
+U+55eb Nie # Character å«
+U+55ec He # Character å¬
+U+55ed Cis # Character å
+U+55ee Sai # Character å®
+U+55ef Ng # Character å¯
+U+55f0 Ge # Character å°
+U+55f1 Na # Character å±
+U+55f2 Dia # Character å²
+U+55f3 Ai # Character å³
+U+55f4 ? # Character å´
+U+55f5 Tong # Character åµ
+U+55f6 Bi # Character å¶
+U+55f7 Ao # Character å·
+U+55f8 Ao # Character å¸
+U+55f9 Lian # Character å¹
+U+55fa Cui # Character åº
+U+55fb Zhe # Character å»
+U+55fc Mo # Character å¼
+U+55fd Sou # Character å½
+U+55fe Sou # Character å¾
+U+55ff Tan # Character å¿
diff --git a/resources/chars/ascii/row56.trans b/resources/chars/ascii/row56.trans
new file mode 100644
index 0000000..e7fbd10
--- /dev/null
+++ b/resources/chars/ascii/row56.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+5600 Di # Character å
+U+5601 Qi # Character å
+U+5602 Jiao # Character å
+U+5603 Chong # Character å
+U+5604 Jiao # Character å
+U+5605 Kai # Character å
+U+5606 Tan # Character å
+U+5607 San # Character å
+U+5608 Cao # Character å
+U+5609 Jia # Character å
+U+560a Ai # Character å
+U+560b Xiao # Character å
+U+560c Piao # Character å
+U+560d Lou # Character å
+U+560e Ga # Character å
+U+560f Gu # Character å
+U+5610 Xiao # Character å
+U+5611 Hu # Character å
+U+5612 Hui # Character å
+U+5613 Guo # Character å
+U+5614 Ou # Character å
+U+5615 Xian # Character å
+U+5616 Ze # Character å
+U+5617 Chang # Character å
+U+5618 Xu # Character å
+U+5619 Po # Character å
+U+561a De # Character å
+U+561b Ma # Character å
+U+561c Ma # Character å
+U+561d Hu # Character å
+U+561e Lei # Character å
+U+561f Du # Character å
+U+5620 Ga # Character å
+U+5621 Tang # Character å¡
+U+5622 Ye # Character å¢
+U+5623 Beng # Character å£
+U+5624 Ying # Character å¤
+U+5625 Saai # Character å¥
+U+5626 Jiao # Character å¦
+U+5627 Mi # Character å§
+U+5628 Xiao # Character å¨
+U+5629 Hua # Character å©
+U+562a Mai # Character åª
+U+562b Ran # Character å«
+U+562c Zuo # Character å¬
+U+562d Peng # Character å
+U+562e Lao # Character å®
+U+562f Xiao # Character å¯
+U+5630 Ji # Character å°
+U+5631 Zhu # Character å±
+U+5632 Chao # Character å²
+U+5633 Kui # Character å³
+U+5634 Zui # Character å´
+U+5635 Xiao # Character åµ
+U+5636 Si # Character å¶
+U+5637 Hao # Character å·
+U+5638 Fu # Character å¸
+U+5639 Liao # Character å¹
+U+563a Qiao # Character åº
+U+563b Xi # Character å»
+U+563c Xiu # Character å¼
+U+563d Tan # Character å½
+U+563e Tan # Character å¾
+U+563f Mo # Character å¿
+U+5640 Xun # Character å
+U+5641 E # Character å
+U+5642 Zun # Character å
+U+5643 Fan # Character å
+U+5644 Chi # Character å
+U+5645 Hui # Character å
+U+5646 Zan # Character å
+U+5647 Chuang # Character å
+U+5648 Cu # Character å
+U+5649 Dan # Character å
+U+564a Yu # Character å
+U+564b Tun # Character å
+U+564c Cheng # Character å
+U+564d Jiao # Character å
+U+564e Ye # Character å
+U+564f Xi # Character å
+U+5650 Qi # Character å
+U+5651 Hao # Character å
+U+5652 Lian # Character å
+U+5653 Xu # Character å
+U+5654 Deng # Character å
+U+5655 Hui # Character å
+U+5656 Yin # Character å
+U+5657 Pu # Character å
+U+5658 Jue # Character å
+U+5659 Qin # Character å
+U+565a Xun # Character å
+U+565b Nie # Character å
+U+565c Lu # Character å
+U+565d Si # Character å
+U+565e Yan # Character å
+U+565f Ying # Character å
+U+5660 Da # Character å
+U+5661 Dan # Character å¡
+U+5662 Yu # Character å¢
+U+5663 Zhou # Character å£
+U+5664 Jin # Character å¤
+U+5665 Nong # Character å¥
+U+5666 Yue # Character å¦
+U+5667 Hui # Character å§
+U+5668 Qi # Character å¨
+U+5669 E # Character å©
+U+566a Zao # Character åª
+U+566b Yi # Character å«
+U+566c Shi # Character å¬
+U+566d Jiao # Character å
+U+566e Yuan # Character å®
+U+566f Ai # Character å¯
+U+5670 Yong # Character å°
+U+5671 Jue # Character å±
+U+5672 Kuai # Character å²
+U+5673 Yu # Character å³
+U+5674 Pen # Character å´
+U+5675 Dao # Character åµ
+U+5676 Ge # Character å¶
+U+5677 Xin # Character å·
+U+5678 Dun # Character å¸
+U+5679 Dang # Character å¹
+U+567a Sin # Character åº
+U+567b Sai # Character å»
+U+567c Pi # Character å¼
+U+567d Pi # Character å½
+U+567e Yin # Character å¾
+U+567f Zui # Character å¿
+U+5680 Ning # Character å
+U+5681 Di # Character å
+U+5682 Lan # Character å
+U+5683 Ta # Character å
+U+5684 Huo # Character å
+U+5685 Ru # Character å
+U+5686 Hao # Character å
+U+5687 Xia # Character å
+U+5688 Ya # Character å
+U+5689 Duo # Character å
+U+568a Xi # Character å
+U+568b Chou # Character å
+U+568c Ji # Character å
+U+568d Jin # Character å
+U+568e Hao # Character å
+U+568f Ti # Character å
+U+5690 Chang # Character å
+U+5691 ? # Character å
+U+5692 ? # Character å
+U+5693 Ca # Character å
+U+5694 Ti # Character å
+U+5695 Lu # Character å
+U+5696 Hui # Character å
+U+5697 Bo # Character å
+U+5698 You # Character å
+U+5699 Nie # Character å
+U+569a Yin # Character å
+U+569b Hu # Character å
+U+569c Mo # Character å
+U+569d Huang # Character å
+U+569e Zhe # Character å
+U+569f Li # Character å
+U+56a0 Liu # Character å
+U+56a1 Haai # Character å¡
+U+56a2 Nang # Character å¢
+U+56a3 Xiao # Character å£
+U+56a4 Mo # Character å¤
+U+56a5 Yan # Character å¥
+U+56a6 Li # Character å¦
+U+56a7 Lu # Character å§
+U+56a8 Long # Character å¨
+U+56a9 Fu # Character å©
+U+56aa Dan # Character åª
+U+56ab Chen # Character å«
+U+56ac Pin # Character å¬
+U+56ad Pi # Character å
+U+56ae Xiang # Character å®
+U+56af Huo # Character å¯
+U+56b0 Mo # Character å°
+U+56b1 Xi # Character å±
+U+56b2 Duo # Character å²
+U+56b3 Ku # Character å³
+U+56b4 Yan # Character å´
+U+56b5 Chan # Character åµ
+U+56b6 Ying # Character å¶
+U+56b7 Rang # Character å·
+U+56b8 Dian # Character å¸
+U+56b9 La # Character å¹
+U+56ba Ta # Character åº
+U+56bb Xiao # Character å»
+U+56bc Jiao # Character å¼
+U+56bd Chuo # Character å½
+U+56be Huan # Character å¾
+U+56bf Huo # Character å¿
+U+56c0 Zhuan # Character å
+U+56c1 Nie # Character å
+U+56c2 Xiao # Character å
+U+56c3 Ca # Character å
+U+56c4 Li # Character å
+U+56c5 Chan # Character å
+U+56c6 Chai # Character å
+U+56c7 Li # Character å
+U+56c8 Yi # Character å
+U+56c9 Luo # Character å
+U+56ca Nang # Character å
+U+56cb Zan # Character å
+U+56cc Su # Character å
+U+56cd Xi # Character å
+U+56ce So # Character å
+U+56cf Jian # Character å
+U+56d0 Za # Character å
+U+56d1 Zhu # Character å
+U+56d2 Lan # Character å
+U+56d3 Nie # Character å
+U+56d4 Nang # Character å
+U+56d5 ? # Character å
+U+56d6 ? # Character å
+U+56d7 Wei # Character å
+U+56d8 Hui # Character å
+U+56d9 Yin # Character å
+U+56da Qiu # Character å
+U+56db Si # Character å
+U+56dc Nin # Character å
+U+56dd Jian # Character å
+U+56de Hui # Character å
+U+56df Xin # Character å
+U+56e0 Yin # Character å
+U+56e1 Nan # Character å¡
+U+56e2 Tuan # Character å¢
+U+56e3 Tuan # Character å£
+U+56e4 Dun # Character å¤
+U+56e5 Kang # Character å¥
+U+56e6 Yuan # Character å¦
+U+56e7 Jiong # Character å§
+U+56e8 Pian # Character å¨
+U+56e9 Yun # Character å©
+U+56ea Cong # Character åª
+U+56eb Hu # Character å«
+U+56ec Hui # Character å¬
+U+56ed Yuan # Character å
+U+56ee You # Character å®
+U+56ef Guo # Character å¯
+U+56f0 Kun # Character å°
+U+56f1 Cong # Character å±
+U+56f2 Wei # Character å²
+U+56f3 Tu # Character å³
+U+56f4 Wei # Character å´
+U+56f5 Lun # Character åµ
+U+56f6 Guo # Character å¶
+U+56f7 Qun # Character å·
+U+56f8 Ri # Character å¸
+U+56f9 Ling # Character å¹
+U+56fa Gu # Character åº
+U+56fb Guo # Character å»
+U+56fc Tai # Character å¼
+U+56fd Guo # Character å½
+U+56fe Tu # Character å¾
+U+56ff You # Character å¿
diff --git a/resources/chars/ascii/row57.trans b/resources/chars/ascii/row57.trans
new file mode 100644
index 0000000..50abd3c
--- /dev/null
+++ b/resources/chars/ascii/row57.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+5700 Guo # Character å
+U+5701 Yin # Character å
+U+5702 Hun # Character å
+U+5703 Pu # Character å
+U+5704 Yu # Character å
+U+5705 Han # Character å
+U+5706 Yuan # Character å
+U+5707 Lun # Character å
+U+5708 Quan # Character å
+U+5709 Yu # Character å
+U+570a Qing # Character å
+U+570b Guo # Character å
+U+570c Chuan # Character å
+U+570d Wei # Character å
+U+570e Yuan # Character å
+U+570f Quan # Character å
+U+5710 Ku # Character å
+U+5711 Fu # Character å
+U+5712 Yuan # Character å
+U+5713 Yuan # Character å
+U+5714 E # Character å
+U+5715 Tu # Character å
+U+5716 Tu # Character å
+U+5717 Tu # Character å
+U+5718 Tuan # Character å
+U+5719 Lue # Character å
+U+571a Hui # Character å
+U+571b Yi # Character å
+U+571c Yuan # Character å
+U+571d Luan # Character å
+U+571e Luan # Character å
+U+571f Tu # Character å
+U+5720 Ya # Character å
+U+5721 Tu # Character å¡
+U+5722 Ting # Character å¢
+U+5723 Sheng # Character å£
+U+5724 Pu # Character å¤
+U+5725 Lu # Character å¥
+U+5726 Iri # Character å¦
+U+5727 Ya # Character å§
+U+5728 Zai # Character å¨
+U+5729 Wei # Character å©
+U+572a Ge # Character åª
+U+572b Yu # Character å«
+U+572c Wu # Character å¬
+U+572d Gui # Character å
+U+572e Pi # Character å®
+U+572f Yi # Character å¯
+U+5730 Di # Character å°
+U+5731 Qian # Character å±
+U+5732 Qian # Character å²
+U+5733 Zhen # Character å³
+U+5734 Zhuo # Character å´
+U+5735 Dang # Character åµ
+U+5736 Qia # Character å¶
+U+5737 Akutsu # Character å·
+U+5738 Yama # Character å¸
+U+5739 Kuang # Character å¹
+U+573a Chang # Character åº
+U+573b Qi # Character å»
+U+573c Nie # Character å¼
+U+573d Mo # Character å½
+U+573e Ji # Character å¾
+U+573f Jia # Character å¿
+U+5740 Zhi # Character å
+U+5741 Zhi # Character å
+U+5742 Ban # Character å
+U+5743 Xun # Character å
+U+5744 Tou # Character å
+U+5745 Qin # Character å
+U+5746 Fen # Character å
+U+5747 Jun # Character å
+U+5748 Keng # Character å
+U+5749 Tun # Character å
+U+574a Fang # Character å
+U+574b Fen # Character å
+U+574c Ben # Character å
+U+574d Tan # Character å
+U+574e Kan # Character å
+U+574f Pi # Character å
+U+5750 Zuo # Character å
+U+5751 Keng # Character å
+U+5752 Bi # Character å
+U+5753 Xing # Character å
+U+5754 Di # Character å
+U+5755 Jing # Character å
+U+5756 Ji # Character å
+U+5757 Kuai # Character å
+U+5758 Di # Character å
+U+5759 Jing # Character å
+U+575a Jian # Character å
+U+575b Tan # Character å
+U+575c Li # Character å
+U+575d Ba # Character å
+U+575e Wu # Character å
+U+575f Fen # Character å
+U+5760 Zhui # Character å
+U+5761 Po # Character å¡
+U+5762 Pan # Character å¢
+U+5763 Tang # Character å£
+U+5764 Kun # Character å¤
+U+5765 Qu # Character å¥
+U+5766 Tan # Character å¦
+U+5767 Zhi # Character å§
+U+5768 Tuo # Character å¨
+U+5769 Gan # Character å©
+U+576a Ping # Character åª
+U+576b Dian # Character å«
+U+576c Gua # Character å¬
+U+576d Ni # Character å
+U+576e Tai # Character å®
+U+576f Pi # Character å¯
+U+5770 Jiong # Character å°
+U+5771 Yang # Character å±
+U+5772 Fo # Character å²
+U+5773 Ao # Character å³
+U+5774 Liu # Character å´
+U+5775 Qiu # Character åµ
+U+5776 Mu # Character å¶
+U+5777 Ke # Character å·
+U+5778 Gou # Character å¸
+U+5779 Xue # Character å¹
+U+577a Ba # Character åº
+U+577b Chi # Character å»
+U+577c Che # Character å¼
+U+577d Ling # Character å½
+U+577e Zhu # Character å¾
+U+577f Fu # Character å¿
+U+5780 Hu # Character å
+U+5781 Zhi # Character å
+U+5782 Chui # Character å
+U+5783 La # Character å
+U+5784 Long # Character å
+U+5785 Long # Character å
+U+5786 Lu # Character å
+U+5787 Ao # Character å
+U+5788 Tay # Character å
+U+5789 Pao # Character å
+U+578a ? # Character å
+U+578b Xing # Character å
+U+578c Dong # Character å
+U+578d Ji # Character å
+U+578e Ke # Character å
+U+578f Lu # Character å
+U+5790 Ci # Character å
+U+5791 Chi # Character å
+U+5792 Lei # Character å
+U+5793 Gai # Character å
+U+5794 Yin # Character å
+U+5795 Hou # Character å
+U+5796 Dui # Character å
+U+5797 Zhao # Character å
+U+5798 Fu # Character å
+U+5799 Guang # Character å
+U+579a Yao # Character å
+U+579b Duo # Character å
+U+579c Duo # Character å
+U+579d Gui # Character å
+U+579e Cha # Character å
+U+579f Yang # Character å
+U+57a0 Yin # Character å
+U+57a1 Fa # Character å¡
+U+57a2 Gou # Character å¢
+U+57a3 Yuan # Character å£
+U+57a4 Die # Character å¤
+U+57a5 Xie # Character å¥
+U+57a6 Ken # Character å¦
+U+57a7 Jiong # Character å§
+U+57a8 Shou # Character å¨
+U+57a9 E # Character å©
+U+57aa Ha # Character åª
+U+57ab Dian # Character å«
+U+57ac Hong # Character å¬
+U+57ad Wu # Character å
+U+57ae Kua # Character å®
+U+57af ? # Character å¯
+U+57b0 Tao # Character å°
+U+57b1 Dang # Character å±
+U+57b2 Kai # Character å²
+U+57b3 Gake # Character å³
+U+57b4 Nao # Character å´
+U+57b5 An # Character åµ
+U+57b6 Xing # Character å¶
+U+57b7 Xian # Character å·
+U+57b8 Huan # Character å¸
+U+57b9 Bang # Character å¹
+U+57ba Pei # Character åº
+U+57bb Ba # Character å»
+U+57bc Yi # Character å¼
+U+57bd Yin # Character å½
+U+57be Han # Character å¾
+U+57bf Xu # Character å¿
+U+57c0 Chui # Character å
+U+57c1 Cen # Character å
+U+57c2 Geng # Character å
+U+57c3 Ai # Character å
+U+57c4 Peng # Character å
+U+57c5 Fang # Character å
+U+57c6 Que # Character å
+U+57c7 Yong # Character å
+U+57c8 Xun # Character å
+U+57c9 Jia # Character å
+U+57ca Di # Character å
+U+57cb Mai # Character å
+U+57cc Lang # Character å
+U+57cd Xuan # Character å
+U+57ce Cheng # Character å
+U+57cf Yan # Character å
+U+57d0 Jin # Character å
+U+57d1 Zhe # Character å
+U+57d2 Lei # Character å
+U+57d3 Lie # Character å
+U+57d4 Bu # Character å
+U+57d5 Cheng # Character å
+U+57d6 Gomi # Character å
+U+57d7 Bu # Character å
+U+57d8 Shi # Character å
+U+57d9 Xun # Character å
+U+57da Guo # Character å
+U+57db Jiong # Character å
+U+57dc Ye # Character å
+U+57dd Nian # Character å
+U+57de Di # Character å
+U+57df Yu # Character å
+U+57e0 Bu # Character å
+U+57e1 Ya # Character å¡
+U+57e2 Juan # Character å¢
+U+57e3 Sui # Character å£
+U+57e4 Pi # Character å¤
+U+57e5 Cheng # Character å¥
+U+57e6 Wan # Character å¦
+U+57e7 Ju # Character å§
+U+57e8 Lun # Character å¨
+U+57e9 Zheng # Character å©
+U+57ea Kong # Character åª
+U+57eb Chong # Character å«
+U+57ec Dong # Character å¬
+U+57ed Dai # Character å
+U+57ee Tan # Character å®
+U+57ef An # Character å¯
+U+57f0 Cai # Character å°
+U+57f1 Shu # Character å±
+U+57f2 Beng # Character å²
+U+57f3 Kan # Character å³
+U+57f4 Zhi # Character å´
+U+57f5 Duo # Character åµ
+U+57f6 Yi # Character å¶
+U+57f7 Zhi # Character å·
+U+57f8 Yi # Character å¸
+U+57f9 Pei # Character å¹
+U+57fa Ji # Character åº
+U+57fb Zhun # Character å»
+U+57fc Qi # Character å¼
+U+57fd Sao # Character å½
+U+57fe Ju # Character å¾
+U+57ff Ni # Character å¿
diff --git a/resources/chars/ascii/row58.trans b/resources/chars/ascii/row58.trans
new file mode 100644
index 0000000..8ea3a64
--- /dev/null
+++ b/resources/chars/ascii/row58.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+5800 Ku # Character å
+U+5801 Ke # Character å
+U+5802 Tang # Character å
+U+5803 Kun # Character å
+U+5804 Ni # Character å
+U+5805 Jian # Character å
+U+5806 Dui # Character å
+U+5807 Jin # Character å
+U+5808 Gang # Character å
+U+5809 Yu # Character å
+U+580a E # Character å
+U+580b Peng # Character å
+U+580c Gu # Character å
+U+580d Tu # Character å
+U+580e Leng # Character å
+U+580f ? # Character å
+U+5810 Ya # Character å
+U+5811 Qian # Character å
+U+5812 ? # Character å
+U+5813 An # Character å
+U+5814 ? # Character å
+U+5815 Duo # Character å
+U+5816 Nao # Character å
+U+5817 Tu # Character å
+U+5818 Cheng # Character å
+U+5819 Yin # Character å
+U+581a Hun # Character å
+U+581b Bi # Character å
+U+581c Lian # Character å
+U+581d Guo # Character å
+U+581e Die # Character å
+U+581f Zhuan # Character å
+U+5820 Hou # Character å
+U+5821 Bao # Character å ¡
+U+5822 Bao # Character å ¢
+U+5823 Yu # Character å £
+U+5824 Di # Character å ¤
+U+5825 Mao # Character å ¥
+U+5826 Jie # Character å ¦
+U+5827 Ruan # Character å §
+U+5828 E # Character å ¨
+U+5829 Geng # Character å ©
+U+582a Kan # Character å ª
+U+582b Zong # Character å «
+U+582c Yu # Character å ¬
+U+582d Huang # Character å
+U+582e E # Character å ®
+U+582f Yao # Character å ¯
+U+5830 Yan # Character å °
+U+5831 Bao # Character å ±
+U+5832 Ji # Character å ²
+U+5833 Mei # Character å ³
+U+5834 Chang # Character å ´
+U+5835 Du # Character å µ
+U+5836 Tuo # Character å ¶
+U+5837 Yin # Character å ·
+U+5838 Feng # Character å ¸
+U+5839 Zhong # Character å ¹
+U+583a Jie # Character å º
+U+583b Zhen # Character å »
+U+583c Feng # Character å ¼
+U+583d Gang # Character å ½
+U+583e Chuan # Character å ¾
+U+583f Jian # Character å ¿
+U+5840 Pyeng # Character å¡
+U+5841 Toride # Character å¡
+U+5842 Xiang # Character å¡
+U+5843 Huang # Character å¡
+U+5844 Leng # Character å¡
+U+5845 Duan # Character å¡
+U+5846 ? # Character å¡
+U+5847 Xuan # Character å¡
+U+5848 Ji # Character å¡
+U+5849 Ji # Character å¡
+U+584a Kuai # Character å¡
+U+584b Ying # Character å¡
+U+584c Ta # Character å¡
+U+584d Cheng # Character å¡
+U+584e Yong # Character å¡
+U+584f Kai # Character å¡
+U+5850 Su # Character å¡
+U+5851 Su # Character å¡
+U+5852 Shi # Character å¡
+U+5853 Mi # Character å¡
+U+5854 Ta # Character å¡
+U+5855 Weng # Character å¡
+U+5856 Cheng # Character å¡
+U+5857 Tu # Character å¡
+U+5858 Tang # Character å¡
+U+5859 Que # Character å¡
+U+585a Zhong # Character å¡
+U+585b Li # Character å¡
+U+585c Peng # Character å¡
+U+585d Bang # Character å¡
+U+585e Sai # Character å¡
+U+585f Zang # Character å¡
+U+5860 Dui # Character å¡
+U+5861 Tian # Character å¡¡
+U+5862 Wu # Character å¡¢
+U+5863 Cheng # Character å¡£
+U+5864 Xun # Character 塤
+U+5865 Ge # Character å¡¥
+U+5866 Zhen # Character 塦
+U+5867 Ai # Character 塧
+U+5868 Gong # Character 塨
+U+5869 Yan # Character å¡©
+U+586a Kan # Character 塪
+U+586b Tian # Character å¡«
+U+586c Yuan # Character 塬
+U+586d Wen # Character å¡
+U+586e Xie # Character å¡®
+U+586f Liu # Character 塯
+U+5870 Ama # Character å¡°
+U+5871 Lang # Character 塱
+U+5872 Chang # Character 塲
+U+5873 Peng # Character 塳
+U+5874 Beng # Character å¡´
+U+5875 Chen # Character 塵
+U+5876 Cu # Character 塶
+U+5877 Lu # Character å¡·
+U+5878 Ou # Character 塸
+U+5879 Qian # Character 塹
+U+587a Mei # Character 塺
+U+587b Mo # Character å¡»
+U+587c Zhuan # Character 塼
+U+587d Shuang # Character 塽
+U+587e Shu # Character 塾
+U+587f Lou # Character å¡¿
+U+5880 Chi # Character å¢
+U+5881 Man # Character å¢
+U+5882 Biao # Character å¢
+U+5883 Jing # Character å¢
+U+5884 Qi # Character å¢
+U+5885 Shu # Character å¢
+U+5886 Di # Character å¢
+U+5887 Zhang # Character å¢
+U+5888 Kan # Character å¢
+U+5889 Yong # Character å¢
+U+588a Dian # Character å¢
+U+588b Chen # Character å¢
+U+588c Zhi # Character å¢
+U+588d Xi # Character å¢
+U+588e Guo # Character å¢
+U+588f Qiang # Character å¢
+U+5890 Jin # Character å¢
+U+5891 Di # Character å¢
+U+5892 Shang # Character å¢
+U+5893 Mu # Character å¢
+U+5894 Cui # Character å¢
+U+5895 Yan # Character å¢
+U+5896 Ta # Character å¢
+U+5897 Zeng # Character å¢
+U+5898 Qi # Character å¢
+U+5899 Qiang # Character å¢
+U+589a Liang # Character å¢
+U+589b ? # Character å¢
+U+589c Zhui # Character å¢
+U+589d Qiao # Character å¢
+U+589e Zeng # Character å¢
+U+589f Xu # Character å¢
+U+58a0 Shan # Character å¢
+U+58a1 Shan # Character 墡
+U+58a2 Ba # Character 墢
+U+58a3 Pu # Character 墣
+U+58a4 Kuai # Character 墤
+U+58a5 Dong # Character 墥
+U+58a6 Fan # Character 墦
+U+58a7 Que # Character 墧
+U+58a8 Mo # Character 墨
+U+58a9 Dun # Character 墩
+U+58aa Dun # Character 墪
+U+58ab Dun # Character 墫
+U+58ac Di # Character 墬
+U+58ad Sheng # Character å¢
+U+58ae Duo # Character 墮
+U+58af Duo # Character 墯
+U+58b0 Tan # Character 墰
+U+58b1 Deng # Character 墱
+U+58b2 Wu # Character 墲
+U+58b3 Fen # Character 墳
+U+58b4 Huang # Character 墴
+U+58b5 Tan # Character 墵
+U+58b6 Da # Character 墶
+U+58b7 Ye # Character 墷
+U+58b8 Sho # Character 墸
+U+58b9 Mama # Character 墹
+U+58ba Yu # Character 墺
+U+58bb Qiang # Character 墻
+U+58bc Ji # Character 墼
+U+58bd Qiao # Character 墽
+U+58be Ken # Character 墾
+U+58bf Yi # Character 墿
+U+58c0 Pi # Character å£
+U+58c1 Bi # Character å£
+U+58c2 Dian # Character å£
+U+58c3 Jiang # Character å£
+U+58c4 Ye # Character å£
+U+58c5 Yong # Character å£
+U+58c6 Bo # Character å£
+U+58c7 Tan # Character å£
+U+58c8 Lan # Character å£
+U+58c9 Ju # Character å£
+U+58ca Huai # Character å£
+U+58cb Dang # Character å£
+U+58cc Rang # Character å£
+U+58cd Qian # Character å£
+U+58ce Xun # Character å£
+U+58cf Lan # Character å£
+U+58d0 Xi # Character å£
+U+58d1 He # Character å£
+U+58d2 Ai # Character å£
+U+58d3 Ya # Character å£
+U+58d4 Dao # Character å£
+U+58d5 Hao # Character å£
+U+58d6 Ruan # Character å£
+U+58d7 Mama # Character å£
+U+58d8 Lei # Character å£
+U+58d9 Kuang # Character å£
+U+58da Lu # Character å£
+U+58db Yan # Character å£
+U+58dc Tan # Character å£
+U+58dd Wei # Character å£
+U+58de Huai # Character å£
+U+58df Long # Character å£
+U+58e0 Long # Character å£
+U+58e1 Rui # Character 壡
+U+58e2 Li # Character 壢
+U+58e3 Lin # Character 壣
+U+58e4 Rang # Character 壤
+U+58e5 Ten # Character 壥
+U+58e6 Xun # Character 壦
+U+58e7 Yan # Character 壧
+U+58e8 Lei # Character 壨
+U+58e9 Ba # Character 壩
+U+58ea ? # Character 壪
+U+58eb Shi # Character 士
+U+58ec Ren # Character 壬
+U+58ed ? # Character å£
+U+58ee Zhuang # Character 壮
+U+58ef Zhuang # Character 壯
+U+58f0 Sheng # Character 声
+U+58f1 Yi # Character 壱
+U+58f2 Mai # Character 売
+U+58f3 Ke # Character 壳
+U+58f4 Zhu # Character 壴
+U+58f5 Zhuang # Character 壵
+U+58f6 Hu # Character 壶
+U+58f7 Hu # Character 壷
+U+58f8 Kun # Character 壸
+U+58f9 Yi # Character 壹
+U+58fa Hu # Character 壺
+U+58fb Xu # Character 壻
+U+58fc Kun # Character 壼
+U+58fd Shou # Character 壽
+U+58fe Mang # Character 壾
+U+58ff Zun # Character 壿
diff --git a/resources/chars/ascii/row59.trans b/resources/chars/ascii/row59.trans
new file mode 100644
index 0000000..789b412
--- /dev/null
+++ b/resources/chars/ascii/row59.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+5900 Shou # Character å¤
+U+5901 Yi # Character å¤
+U+5902 Zhi # Character å¤
+U+5903 Gu # Character å¤
+U+5904 Chu # Character å¤
+U+5905 Jiang # Character å¤
+U+5906 Feng # Character å¤
+U+5907 Bei # Character å¤
+U+5908 Cay # Character å¤
+U+5909 Bian # Character å¤
+U+590a Sui # Character å¤
+U+590b Qun # Character å¤
+U+590c Ling # Character å¤
+U+590d Fu # Character å¤
+U+590e Zuo # Character å¤
+U+590f Xia # Character å¤
+U+5910 Xiong # Character å¤
+U+5911 ? # Character å¤
+U+5912 Nao # Character å¤
+U+5913 Xia # Character å¤
+U+5914 Kui # Character å¤
+U+5915 Xi # Character å¤
+U+5916 Wai # Character å¤
+U+5917 Yuan # Character å¤
+U+5918 Mao # Character å¤
+U+5919 Su # Character å¤
+U+591a Duo # Character å¤
+U+591b Duo # Character å¤
+U+591c Ye # Character å¤
+U+591d Qing # Character å¤
+U+591e Uys # Character å¤
+U+591f Gou # Character å¤
+U+5920 Gou # Character å¤
+U+5921 Qi # Character 夡
+U+5922 Meng # Character 夢
+U+5923 Meng # Character 夣
+U+5924 Yin # Character 夤
+U+5925 Huo # Character 夥
+U+5926 Chen # Character 夦
+U+5927 Da # Character 大
+U+5928 Ze # Character 夨
+U+5929 Tian # Character 天
+U+592a Tai # Character 太
+U+592b Fu # Character 夫
+U+592c Guai # Character 夬
+U+592d Yao # Character å¤
+U+592e Yang # Character 央
+U+592f Hang # Character 夯
+U+5930 Gao # Character 夰
+U+5931 Shi # Character 失
+U+5932 Ben # Character 夲
+U+5933 Tai # Character 夳
+U+5934 Tou # Character 头
+U+5935 Yan # Character 夵
+U+5936 Bi # Character 夶
+U+5937 Yi # Character 夷
+U+5938 Kua # Character 夸
+U+5939 Jia # Character 夹
+U+593a Duo # Character 夺
+U+593b Kwu # Character 夻
+U+593c Kuang # Character 夼
+U+593d Yun # Character 夽
+U+593e Jia # Character 夾
+U+593f Pa # Character 夿
+U+5940 En # Character å¥
+U+5941 Lian # Character å¥
+U+5942 Huan # Character å¥
+U+5943 Di # Character å¥
+U+5944 Yan # Character å¥
+U+5945 Pao # Character å¥
+U+5946 Quan # Character å¥
+U+5947 Qi # Character å¥
+U+5948 Nai # Character å¥
+U+5949 Feng # Character å¥
+U+594a Xie # Character å¥
+U+594b Fen # Character å¥
+U+594c Dian # Character å¥
+U+594d ? # Character å¥
+U+594e Kui # Character å¥
+U+594f Zou # Character å¥
+U+5950 Huan # Character å¥
+U+5951 Qi # Character å¥
+U+5952 Kai # Character å¥
+U+5953 Zha # Character å¥
+U+5954 Ben # Character å¥
+U+5955 Yi # Character å¥
+U+5956 Jiang # Character å¥
+U+5957 Tao # Character å¥
+U+5958 Zang # Character å¥
+U+5959 Ben # Character å¥
+U+595a Xi # Character å¥
+U+595b Xiang # Character å¥
+U+595c Fei # Character å¥
+U+595d Diao # Character å¥
+U+595e Xun # Character å¥
+U+595f Keng # Character å¥
+U+5960 Dian # Character å¥
+U+5961 Ao # Character 奡
+U+5962 She # Character 奢
+U+5963 Weng # Character 奣
+U+5964 Pan # Character 奤
+U+5965 Ao # Character 奥
+U+5966 Wu # Character 奦
+U+5967 Ao # Character 奧
+U+5968 Jiang # Character 奨
+U+5969 Lian # Character 奩
+U+596a Duo # Character 奪
+U+596b Yun # Character 奫
+U+596c Jiang # Character 奬
+U+596d Shi # Character å¥
+U+596e Fen # Character 奮
+U+596f Huo # Character 奯
+U+5970 Bi # Character 奰
+U+5971 Lian # Character 奱
+U+5972 Duo # Character 奲
+U+5973 Nu # Character 女
+U+5974 Nu # Character 奴
+U+5975 Ding # Character 奵
+U+5976 Nai # Character 奶
+U+5977 Qian # Character 奷
+U+5978 Jian # Character 奸
+U+5979 Ta # Character 她
+U+597a Jiu # Character 奺
+U+597b Nan # Character 奻
+U+597c Cha # Character 奼
+U+597d Hao # Character 好
+U+597e Xian # Character 奾
+U+597f Fan # Character 奿
+U+5980 Ji # Character å¦
+U+5981 Shuo # Character å¦
+U+5982 Ru # Character å¦
+U+5983 Fei # Character å¦
+U+5984 Wang # Character å¦
+U+5985 Hong # Character å¦
+U+5986 Zhuang # Character å¦
+U+5987 Fu # Character å¦
+U+5988 Ma # Character å¦
+U+5989 Dan # Character å¦
+U+598a Ren # Character å¦
+U+598b Fu # Character å¦
+U+598c Jing # Character å¦
+U+598d Yan # Character å¦
+U+598e Xie # Character å¦
+U+598f Wen # Character å¦
+U+5990 Zhong # Character å¦
+U+5991 Pa # Character å¦
+U+5992 Du # Character å¦
+U+5993 Ji # Character å¦
+U+5994 Keng # Character å¦
+U+5995 Zhong # Character å¦
+U+5996 Yao # Character å¦
+U+5997 Jin # Character å¦
+U+5998 Yun # Character å¦
+U+5999 Miao # Character å¦
+U+599a Pei # Character å¦
+U+599b Shi # Character å¦
+U+599c Yue # Character å¦
+U+599d Zhuang # Character å¦
+U+599e Niu # Character å¦
+U+599f Yan # Character å¦
+U+59a0 Na # Character å¦
+U+59a1 Xin # Character 妡
+U+59a2 Fen # Character 妢
+U+59a3 Bi # Character 妣
+U+59a4 Yu # Character 妤
+U+59a5 Tuo # Character 妥
+U+59a6 Feng # Character 妦
+U+59a7 Yuan # Character 妧
+U+59a8 Fang # Character 妨
+U+59a9 Wu # Character 妩
+U+59aa Yu # Character 妪
+U+59ab Gui # Character 妫
+U+59ac Du # Character 妬
+U+59ad Ba # Character å¦
+U+59ae Ni # Character 妮
+U+59af Zhou # Character 妯
+U+59b0 Zhuo # Character 妰
+U+59b1 Zhao # Character 妱
+U+59b2 Da # Character 妲
+U+59b3 Nai # Character 妳
+U+59b4 Yuan # Character 妴
+U+59b5 Tou # Character 妵
+U+59b6 Xuan # Character 妶
+U+59b7 Zhi # Character 妷
+U+59b8 E # Character 妸
+U+59b9 Mei # Character 妹
+U+59ba Mo # Character 妺
+U+59bb Qi # Character 妻
+U+59bc Bi # Character 妼
+U+59bd Shen # Character 妽
+U+59be Qie # Character 妾
+U+59bf E # Character 妿
+U+59c0 He # Character å§
+U+59c1 Xu # Character å§
+U+59c2 Fa # Character å§
+U+59c3 Zheng # Character å§
+U+59c4 Min # Character å§
+U+59c5 Ban # Character å§
+U+59c6 Mu # Character å§
+U+59c7 Fu # Character å§
+U+59c8 Ling # Character å§
+U+59c9 Zi # Character å§
+U+59ca Zi # Character å§
+U+59cb Shi # Character å§
+U+59cc Ran # Character å§
+U+59cd Shan # Character å§
+U+59ce Yang # Character å§
+U+59cf Man # Character å§
+U+59d0 Jie # Character å§
+U+59d1 Gu # Character å§
+U+59d2 Si # Character å§
+U+59d3 Xing # Character å§
+U+59d4 Wei # Character å§
+U+59d5 Zi # Character å§
+U+59d6 Ju # Character å§
+U+59d7 Shan # Character å§
+U+59d8 Pin # Character å§
+U+59d9 Ren # Character å§
+U+59da Yao # Character å§
+U+59db Tong # Character å§
+U+59dc Jiang # Character å§
+U+59dd Shu # Character å§
+U+59de Ji # Character å§
+U+59df Gai # Character å§
+U+59e0 Shang # Character å§
+U+59e1 Kuo # Character 姡
+U+59e2 Juan # Character 姢
+U+59e3 Jiao # Character 姣
+U+59e4 Gou # Character 姤
+U+59e5 Mu # Character 姥
+U+59e6 Jian # Character 姦
+U+59e7 Jian # Character 姧
+U+59e8 Yi # Character 姨
+U+59e9 Nian # Character 姩
+U+59ea Zhi # Character 姪
+U+59eb Ji # Character 姫
+U+59ec Ji # Character 姬
+U+59ed Xian # Character å§
+U+59ee Heng # Character 姮
+U+59ef Guang # Character 姯
+U+59f0 Jun # Character 姰
+U+59f1 Kua # Character 姱
+U+59f2 Yan # Character 姲
+U+59f3 Ming # Character 姳
+U+59f4 Lie # Character 姴
+U+59f5 Pei # Character 姵
+U+59f6 Yan # Character 姶
+U+59f7 You # Character 姷
+U+59f8 Yan # Character 姸
+U+59f9 Cha # Character 姹
+U+59fa Shen # Character 姺
+U+59fb Yin # Character 姻
+U+59fc Chi # Character 姼
+U+59fd Gui # Character 姽
+U+59fe Quan # Character 姾
+U+59ff Zi # Character 姿
diff --git a/resources/chars/ascii/row5a.trans b/resources/chars/ascii/row5a.trans
new file mode 100644
index 0000000..296e42b
--- /dev/null
+++ b/resources/chars/ascii/row5a.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+5a00 Song # Character å¨
+U+5a01 Wei # Character å¨
+U+5a02 Hong # Character å¨
+U+5a03 Wa # Character å¨
+U+5a04 Lou # Character å¨
+U+5a05 Ya # Character å¨
+U+5a06 Rao # Character å¨
+U+5a07 Jiao # Character å¨
+U+5a08 Luan # Character å¨
+U+5a09 Ping # Character å¨
+U+5a0a Xian # Character å¨
+U+5a0b Shao # Character å¨
+U+5a0c Li # Character å¨
+U+5a0d Cheng # Character å¨
+U+5a0e Xiao # Character å¨
+U+5a0f Mang # Character å¨
+U+5a10 Fu # Character å¨
+U+5a11 Suo # Character å¨
+U+5a12 Wu # Character å¨
+U+5a13 Wei # Character å¨
+U+5a14 Ke # Character å¨
+U+5a15 Lai # Character å¨
+U+5a16 Chuo # Character å¨
+U+5a17 Ding # Character å¨
+U+5a18 Niang # Character å¨
+U+5a19 Xing # Character å¨
+U+5a1a Nan # Character å¨
+U+5a1b Yu # Character å¨
+U+5a1c Nuo # Character å¨
+U+5a1d Pei # Character å¨
+U+5a1e Nei # Character å¨
+U+5a1f Juan # Character å¨
+U+5a20 Shen # Character å¨
+U+5a21 Zhi # Character 娡
+U+5a22 Han # Character 娢
+U+5a23 Di # Character 娣
+U+5a24 Zhuang # Character 娤
+U+5a25 E # Character 娥
+U+5a26 Pin # Character 娦
+U+5a27 Tui # Character 娧
+U+5a28 Han # Character 娨
+U+5a29 Mian # Character 娩
+U+5a2a Wu # Character 娪
+U+5a2b Yan # Character 娫
+U+5a2c Wu # Character 娬
+U+5a2d Xi # Character å¨
+U+5a2e Yan # Character 娮
+U+5a2f Yu # Character 娯
+U+5a30 Si # Character 娰
+U+5a31 Yu # Character 娱
+U+5a32 Wa # Character 娲
+U+5a33 ? # Character 娳
+U+5a34 Xian # Character 娴
+U+5a35 Ju # Character 娵
+U+5a36 Qu # Character 娶
+U+5a37 Shui # Character 娷
+U+5a38 Qi # Character 娸
+U+5a39 Xian # Character 娹
+U+5a3a Zhui # Character 娺
+U+5a3b Dong # Character 娻
+U+5a3c Chang # Character 娼
+U+5a3d Lu # Character 娽
+U+5a3e Ai # Character 娾
+U+5a3f E # Character 娿
+U+5a40 E # Character å©
+U+5a41 Lou # Character å©
+U+5a42 Mian # Character å©
+U+5a43 Cong # Character å©
+U+5a44 Pou # Character å©
+U+5a45 Ju # Character å©
+U+5a46 Po # Character å©
+U+5a47 Cai # Character å©
+U+5a48 Ding # Character å©
+U+5a49 Wan # Character å©
+U+5a4a Biao # Character å©
+U+5a4b Xiao # Character å©
+U+5a4c Shu # Character å©
+U+5a4d Qi # Character å©
+U+5a4e Hui # Character å©
+U+5a4f Fu # Character å©
+U+5a50 E # Character å©
+U+5a51 Wo # Character å©
+U+5a52 Tan # Character å©
+U+5a53 Fei # Character å©
+U+5a54 Wei # Character å©
+U+5a55 Jie # Character å©
+U+5a56 Tian # Character å©
+U+5a57 Ni # Character å©
+U+5a58 Quan # Character å©
+U+5a59 Jing # Character å©
+U+5a5a Hun # Character å©
+U+5a5b Jing # Character å©
+U+5a5c Qian # Character å©
+U+5a5d Dian # Character å©
+U+5a5e Xing # Character å©
+U+5a5f Hu # Character å©
+U+5a60 Wa # Character å©
+U+5a61 Lai # Character å©¡
+U+5a62 Bi # Character å©¢
+U+5a63 Yin # Character å©£
+U+5a64 Chou # Character 婤
+U+5a65 Chuo # Character å©¥
+U+5a66 Fu # Character 婦
+U+5a67 Jing # Character 婧
+U+5a68 Lun # Character 婨
+U+5a69 Yan # Character å©©
+U+5a6a Lan # Character 婪
+U+5a6b Kun # Character å©«
+U+5a6c Yin # Character 婬
+U+5a6d Ya # Character å©
+U+5a6e Ju # Character å©®
+U+5a6f Li # Character 婯
+U+5a70 Dian # Character å©°
+U+5a71 Xian # Character 婱
+U+5a72 Hwa # Character 婲
+U+5a73 Hua # Character 婳
+U+5a74 Ying # Character å©´
+U+5a75 Chan # Character 婵
+U+5a76 Shen # Character 婶
+U+5a77 Ting # Character å©·
+U+5a78 Dang # Character 婸
+U+5a79 Yao # Character 婹
+U+5a7a Wu # Character 婺
+U+5a7b Nan # Character å©»
+U+5a7c Ruo # Character 婼
+U+5a7d Jia # Character 婽
+U+5a7e Tou # Character 婾
+U+5a7f Xu # Character å©¿
+U+5a80 Yu # Character åª
+U+5a81 Wei # Character åª
+U+5a82 Ti # Character åª
+U+5a83 Rou # Character åª
+U+5a84 Mei # Character åª
+U+5a85 Dan # Character åª
+U+5a86 Ruan # Character åª
+U+5a87 Qin # Character åª
+U+5a88 Hui # Character åª
+U+5a89 Wu # Character åª
+U+5a8a Qian # Character åª
+U+5a8b Chun # Character åª
+U+5a8c Mao # Character åª
+U+5a8d Fu # Character åª
+U+5a8e Jie # Character åª
+U+5a8f Duan # Character åª
+U+5a90 Xi # Character åª
+U+5a91 Zhong # Character åª
+U+5a92 Mei # Character åª
+U+5a93 Huang # Character åª
+U+5a94 Mian # Character åª
+U+5a95 An # Character åª
+U+5a96 Ying # Character åª
+U+5a97 Xuan # Character åª
+U+5a98 Jie # Character åª
+U+5a99 Wei # Character åª
+U+5a9a Mei # Character åª
+U+5a9b Yuan # Character åª
+U+5a9c Zhen # Character åª
+U+5a9d Qiu # Character åª
+U+5a9e Ti # Character åª
+U+5a9f Xie # Character åª
+U+5aa0 Tuo # Character åª
+U+5aa1 Lian # Character 媡
+U+5aa2 Mao # Character 媢
+U+5aa3 Ran # Character 媣
+U+5aa4 Si # Character 媤
+U+5aa5 Pian # Character 媥
+U+5aa6 Wei # Character 媦
+U+5aa7 Wa # Character 媧
+U+5aa8 Jiu # Character 媨
+U+5aa9 Hu # Character 媩
+U+5aaa Ao # Character 媪
+U+5aab ? # Character 媫
+U+5aac Bou # Character 媬
+U+5aad Xu # Character åª
+U+5aae Tou # Character 媮
+U+5aaf Gui # Character 媯
+U+5ab0 Zou # Character 媰
+U+5ab1 Yao # Character 媱
+U+5ab2 Pi # Character 媲
+U+5ab3 Xi # Character 媳
+U+5ab4 Yuan # Character 媴
+U+5ab5 Ying # Character 媵
+U+5ab6 Rong # Character 媶
+U+5ab7 Ru # Character 媷
+U+5ab8 Chi # Character 媸
+U+5ab9 Liu # Character 媹
+U+5aba Mei # Character 媺
+U+5abb Pan # Character 媻
+U+5abc Ao # Character 媼
+U+5abd Ma # Character 媽
+U+5abe Gou # Character 媾
+U+5abf Kui # Character 媿
+U+5ac0 Qin # Character å«
+U+5ac1 Jia # Character å«
+U+5ac2 Sao # Character å«
+U+5ac3 Zhen # Character å«
+U+5ac4 Yuan # Character å«
+U+5ac5 Cha # Character å«
+U+5ac6 Yong # Character å«
+U+5ac7 Ming # Character å«
+U+5ac8 Ying # Character å«
+U+5ac9 Ji # Character å«
+U+5aca Su # Character å«
+U+5acb Niao # Character å«
+U+5acc Xian # Character å«
+U+5acd Tao # Character å«
+U+5ace Pang # Character å«
+U+5acf Lang # Character å«
+U+5ad0 Nao # Character å«
+U+5ad1 Bao # Character å«
+U+5ad2 Ai # Character å«
+U+5ad3 Pi # Character å«
+U+5ad4 Pin # Character å«
+U+5ad5 Yi # Character å«
+U+5ad6 Piao # Character å«
+U+5ad7 Yu # Character å«
+U+5ad8 Lei # Character å«
+U+5ad9 Xuan # Character å«
+U+5ada Man # Character å«
+U+5adb Yi # Character å«
+U+5adc Zhang # Character å«
+U+5add Kang # Character å«
+U+5ade Yong # Character å«
+U+5adf Ni # Character å«
+U+5ae0 Li # Character å«
+U+5ae1 Di # Character å«¡
+U+5ae2 Gui # Character å«¢
+U+5ae3 Yan # Character å«£
+U+5ae4 Jin # Character 嫤
+U+5ae5 Zhuan # Character å«¥
+U+5ae6 Chang # Character 嫦
+U+5ae7 Ce # Character 嫧
+U+5ae8 Han # Character 嫨
+U+5ae9 Nen # Character å«©
+U+5aea Lao # Character 嫪
+U+5aeb Mo # Character å««
+U+5aec Zhe # Character 嫬
+U+5aed Hu # Character å«
+U+5aee Hu # Character å«®
+U+5aef Ao # Character 嫯
+U+5af0 Nen # Character å«°
+U+5af1 Qiang # Character 嫱
+U+5af2 Ma # Character 嫲
+U+5af3 Pie # Character 嫳
+U+5af4 Gu # Character å«´
+U+5af5 Wu # Character 嫵
+U+5af6 Jiao # Character 嫶
+U+5af7 Tuo # Character å«·
+U+5af8 Zhan # Character 嫸
+U+5af9 Mao # Character 嫹
+U+5afa Xian # Character 嫺
+U+5afb Xian # Character å«»
+U+5afc Mo # Character 嫼
+U+5afd Liao # Character 嫽
+U+5afe Lian # Character 嫾
+U+5aff Hua # Character å«¿
diff --git a/resources/chars/ascii/row5b.trans b/resources/chars/ascii/row5b.trans
new file mode 100644
index 0000000..9cda7c9
--- /dev/null
+++ b/resources/chars/ascii/row5b.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+5b00 Gui # Character å¬
+U+5b01 Deng # Character å¬
+U+5b02 Zhi # Character å¬
+U+5b03 Xu # Character å¬
+U+5b04 Yi # Character å¬
+U+5b05 Hua # Character å¬
+U+5b06 Xi # Character å¬
+U+5b07 Hui # Character å¬
+U+5b08 Rao # Character å¬
+U+5b09 Xi # Character å¬
+U+5b0a Yan # Character å¬
+U+5b0b Chan # Character å¬
+U+5b0c Jiao # Character å¬
+U+5b0d Mei # Character å¬
+U+5b0e Fan # Character å¬
+U+5b0f Fan # Character å¬
+U+5b10 Xian # Character å¬
+U+5b11 Yi # Character å¬
+U+5b12 Wei # Character å¬
+U+5b13 Jiao # Character å¬
+U+5b14 Fu # Character å¬
+U+5b15 Shi # Character å¬
+U+5b16 Bi # Character å¬
+U+5b17 Shan # Character å¬
+U+5b18 Sui # Character å¬
+U+5b19 Qiang # Character å¬
+U+5b1a Lian # Character å¬
+U+5b1b Huan # Character å¬
+U+5b1c Xin # Character å¬
+U+5b1d Niao # Character å¬
+U+5b1e Dong # Character å¬
+U+5b1f Yi # Character å¬
+U+5b20 Can # Character å¬
+U+5b21 Ai # Character 嬡
+U+5b22 Niang # Character 嬢
+U+5b23 Neng # Character 嬣
+U+5b24 Ma # Character 嬤
+U+5b25 Tiao # Character 嬥
+U+5b26 Chou # Character 嬦
+U+5b27 Jin # Character 嬧
+U+5b28 Ci # Character 嬨
+U+5b29 Yu # Character 嬩
+U+5b2a Pin # Character 嬪
+U+5b2b Yong # Character 嬫
+U+5b2c Xu # Character 嬬
+U+5b2d Nai # Character å¬
+U+5b2e Yan # Character 嬮
+U+5b2f Tai # Character 嬯
+U+5b30 Ying # Character 嬰
+U+5b31 Can # Character 嬱
+U+5b32 Niao # Character 嬲
+U+5b33 Wo # Character 嬳
+U+5b34 Ying # Character 嬴
+U+5b35 Mian # Character 嬵
+U+5b36 Kaka # Character 嬶
+U+5b37 Ma # Character 嬷
+U+5b38 Shen # Character 嬸
+U+5b39 Xing # Character 嬹
+U+5b3a Ni # Character 嬺
+U+5b3b Du # Character 嬻
+U+5b3c Liu # Character 嬼
+U+5b3d Yuan # Character 嬽
+U+5b3e Lan # Character 嬾
+U+5b3f Yan # Character 嬿
+U+5b40 Shuang # Character å
+U+5b41 Ling # Character å
+U+5b42 Jiao # Character å
+U+5b43 Niang # Character å
+U+5b44 Lan # Character å
+U+5b45 Xian # Character å
+U+5b46 Ying # Character å
+U+5b47 Shuang # Character å
+U+5b48 Shuai # Character å
+U+5b49 Quan # Character å
+U+5b4a Mi # Character å
+U+5b4b Li # Character å
+U+5b4c Luan # Character å
+U+5b4d Yan # Character å
+U+5b4e Zhu # Character å
+U+5b4f Lan # Character å
+U+5b50 Zi # Character å
+U+5b51 Jie # Character å
+U+5b52 Jue # Character å
+U+5b53 Jue # Character å
+U+5b54 Kong # Character å
+U+5b55 Yun # Character å
+U+5b56 Zi # Character å
+U+5b57 Zi # Character å
+U+5b58 Cun # Character å
+U+5b59 Sun # Character å
+U+5b5a Fu # Character å
+U+5b5b Bei # Character å
+U+5b5c Zi # Character å
+U+5b5d Xiao # Character å
+U+5b5e Xin # Character å
+U+5b5f Meng # Character å
+U+5b60 Si # Character å
+U+5b61 Tai # Character å¡
+U+5b62 Bao # Character å¢
+U+5b63 Ji # Character å£
+U+5b64 Gu # Character å¤
+U+5b65 Nu # Character å¥
+U+5b66 Xue # Character å¦
+U+5b67 ? # Character å§
+U+5b68 Zhuan # Character å¨
+U+5b69 Hai # Character å©
+U+5b6a Luan # Character åª
+U+5b6b Sun # Character å«
+U+5b6c Huai # Character å¬
+U+5b6d Mie # Character å
+U+5b6e Cong # Character å®
+U+5b6f Qian # Character å¯
+U+5b70 Shu # Character å°
+U+5b71 Chan # Character å±
+U+5b72 Ya # Character å²
+U+5b73 Zi # Character å³
+U+5b74 Ni # Character å´
+U+5b75 Fu # Character åµ
+U+5b76 Zi # Character å¶
+U+5b77 Li # Character å·
+U+5b78 Xue # Character å¸
+U+5b79 Bo # Character å¹
+U+5b7a Ru # Character åº
+U+5b7b Lai # Character å»
+U+5b7c Nie # Character å¼
+U+5b7d Nie # Character å½
+U+5b7e Ying # Character å¾
+U+5b7f Luan # Character å¿
+U+5b80 Mian # Character å®
+U+5b81 Zhu # Character å®
+U+5b82 Rong # Character å®
+U+5b83 Ta # Character å®
+U+5b84 Gui # Character å®
+U+5b85 Zhai # Character å®
+U+5b86 Qiong # Character å®
+U+5b87 Yu # Character å®
+U+5b88 Shou # Character å®
+U+5b89 An # Character å®
+U+5b8a Tu # Character å®
+U+5b8b Song # Character å®
+U+5b8c Wan # Character å®
+U+5b8d Rou # Character å®
+U+5b8e Yao # Character å®
+U+5b8f Hong # Character å®
+U+5b90 Yi # Character å®
+U+5b91 Jing # Character å®
+U+5b92 Zhun # Character å®
+U+5b93 Mi # Character å®
+U+5b94 Zhu # Character å®
+U+5b95 Dang # Character å®
+U+5b96 Hong # Character å®
+U+5b97 Zong # Character å®
+U+5b98 Guan # Character å®
+U+5b99 Zhou # Character å®
+U+5b9a Ding # Character å®
+U+5b9b Wan # Character å®
+U+5b9c Yi # Character å®
+U+5b9d Bao # Character å®
+U+5b9e Shi # Character å®
+U+5b9f Shi # Character å®
+U+5ba0 Chong # Character å®
+U+5ba1 Shen # Character 审
+U+5ba2 Ke # Character 客
+U+5ba3 Xuan # Character 宣
+U+5ba4 Shi # Character 室
+U+5ba5 You # Character 宥
+U+5ba6 Huan # Character 宦
+U+5ba7 Yi # Character 宧
+U+5ba8 Tiao # Character 宨
+U+5ba9 Shi # Character 宩
+U+5baa Xian # Character 宪
+U+5bab Gong # Character 宫
+U+5bac Cheng # Character 宬
+U+5bad Qun # Character å®
+U+5bae Gong # Character å®®
+U+5baf Xiao # Character 宯
+U+5bb0 Zai # Character å®°
+U+5bb1 Zha # Character å®±
+U+5bb2 Bao # Character 宲
+U+5bb3 Hai # Character 害
+U+5bb4 Yan # Character å®´
+U+5bb5 Xiao # Character 宵
+U+5bb6 Jia # Character 家
+U+5bb7 Shen # Character å®·
+U+5bb8 Chen # Character 宸
+U+5bb9 Rong # Character 容
+U+5bba Huang # Character 宺
+U+5bbb Mi # Character å®»
+U+5bbc Kou # Character 宼
+U+5bbd Kuan # Character 宽
+U+5bbe Bin # Character 宾
+U+5bbf Su # Character 宿
+U+5bc0 Cai # Character å¯
+U+5bc1 Zan # Character å¯
+U+5bc2 Ji # Character å¯
+U+5bc3 Yuan # Character å¯
+U+5bc4 Ji # Character å¯
+U+5bc5 Yin # Character å¯
+U+5bc6 Mi # Character å¯
+U+5bc7 Kou # Character å¯
+U+5bc8 Qing # Character å¯
+U+5bc9 Que # Character å¯
+U+5bca Zhen # Character å¯
+U+5bcb Jian # Character å¯
+U+5bcc Fu # Character å¯
+U+5bcd Ning # Character å¯
+U+5bce Bing # Character å¯
+U+5bcf Huan # Character å¯
+U+5bd0 Mei # Character å¯
+U+5bd1 Qin # Character å¯
+U+5bd2 Han # Character å¯
+U+5bd3 Yu # Character å¯
+U+5bd4 Shi # Character å¯
+U+5bd5 Ning # Character å¯
+U+5bd6 Qin # Character å¯
+U+5bd7 Ning # Character å¯
+U+5bd8 Zhi # Character å¯
+U+5bd9 Yu # Character å¯
+U+5bda Bao # Character å¯
+U+5bdb Kuan # Character å¯
+U+5bdc Ning # Character å¯
+U+5bdd Qin # Character å¯
+U+5bde Mo # Character å¯
+U+5bdf Cha # Character å¯
+U+5be0 Ju # Character å¯
+U+5be1 Gua # Character 寡
+U+5be2 Qin # Character 寢
+U+5be3 Hu # Character 寣
+U+5be4 Wu # Character 寤
+U+5be5 Liao # Character 寥
+U+5be6 Shi # Character 實
+U+5be7 Zhu # Character 寧
+U+5be8 Zhai # Character 寨
+U+5be9 Shen # Character 審
+U+5bea Wei # Character 寪
+U+5beb Xie # Character 寫
+U+5bec Kuan # Character 寬
+U+5bed Hui # Character å¯
+U+5bee Liao # Character 寮
+U+5bef Jun # Character 寯
+U+5bf0 Huan # Character 寰
+U+5bf1 Yi # Character 寱
+U+5bf2 Yi # Character 寲
+U+5bf3 Bao # Character 寳
+U+5bf4 Qin # Character 寴
+U+5bf5 Chong # Character 寵
+U+5bf6 Bao # Character 寶
+U+5bf7 Feng # Character 寷
+U+5bf8 Cun # Character 寸
+U+5bf9 Dui # Character 对
+U+5bfa Si # Character 寺
+U+5bfb Xun # Character 寻
+U+5bfc Dao # Character 导
+U+5bfd Lu # Character 寽
+U+5bfe Dui # Character 対
+U+5bff Shou # Character 寿
diff --git a/resources/chars/ascii/row5c.trans b/resources/chars/ascii/row5c.trans
new file mode 100644
index 0000000..e1bad8f
--- /dev/null
+++ b/resources/chars/ascii/row5c.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+5c00 Po # Character å°
+U+5c01 Feng # Character å°
+U+5c02 Zhuan # Character å°
+U+5c03 Fu # Character å°
+U+5c04 She # Character å°
+U+5c05 Ke # Character å°
+U+5c06 Jiang # Character å°
+U+5c07 Jiang # Character å°
+U+5c08 Zhuan # Character å°
+U+5c09 Wei # Character å°
+U+5c0a Zun # Character å°
+U+5c0b Xun # Character å°
+U+5c0c Shu # Character å°
+U+5c0d Dui # Character å°
+U+5c0e Dao # Character å°
+U+5c0f Xiao # Character å°
+U+5c10 Ji # Character å°
+U+5c11 Shao # Character å°
+U+5c12 Er # Character å°
+U+5c13 Er # Character å°
+U+5c14 Er # Character å°
+U+5c15 Ga # Character å°
+U+5c16 Jian # Character å°
+U+5c17 Shu # Character å°
+U+5c18 Chen # Character å°
+U+5c19 Shang # Character å°
+U+5c1a Shang # Character å°
+U+5c1b Mo # Character å°
+U+5c1c Ga # Character å°
+U+5c1d Chang # Character å°
+U+5c1e Liao # Character å°
+U+5c1f Xian # Character å°
+U+5c20 Xian # Character å°
+U+5c21 ? # Character å°¡
+U+5c22 Wang # Character å°¢
+U+5c23 Wang # Character å°£
+U+5c24 You # Character å°¤
+U+5c25 Liao # Character å°¥
+U+5c26 Liao # Character å°¦
+U+5c27 Yao # Character å°§
+U+5c28 Mang # Character å°¨
+U+5c29 Wang # Character å°©
+U+5c2a Wang # Character å°ª
+U+5c2b Wang # Character å°«
+U+5c2c Ga # Character å°¬
+U+5c2d Yao # Character å°
+U+5c2e Duo # Character å°®
+U+5c2f Kui # Character å°¯
+U+5c30 Zhong # Character å°°
+U+5c31 Jiu # Character å°±
+U+5c32 Gan # Character å°²
+U+5c33 Gu # Character å°³
+U+5c34 Gan # Character å°´
+U+5c35 Tui # Character å°µ
+U+5c36 Gan # Character å°¶
+U+5c37 Gan # Character å°·
+U+5c38 Shi # Character å°¸
+U+5c39 Yin # Character å°¹
+U+5c3a Chi # Character å°º
+U+5c3b Kao # Character å°»
+U+5c3c Ni # Character å°¼
+U+5c3d Jin # Character å°½
+U+5c3e Wei # Character å°¾
+U+5c3f Niao # Character å°¿
+U+5c40 Ju # Character å±
+U+5c41 Pi # Character å±
+U+5c42 Ceng # Character å±
+U+5c43 Xi # Character å±
+U+5c44 Bi # Character å±
+U+5c45 Ju # Character å±
+U+5c46 Jie # Character å±
+U+5c47 Tian # Character å±
+U+5c48 Qu # Character å±
+U+5c49 Ti # Character å±
+U+5c4a Jie # Character å±
+U+5c4b Wu # Character å±
+U+5c4c Diao # Character å±
+U+5c4d Shi # Character å±
+U+5c4e Shi # Character å±
+U+5c4f Ping # Character å±
+U+5c50 Ji # Character å±
+U+5c51 Xie # Character å±
+U+5c52 Chen # Character å±
+U+5c53 Xi # Character å±
+U+5c54 Ni # Character å±
+U+5c55 Zhan # Character å±
+U+5c56 Xi # Character å±
+U+5c57 ? # Character å±
+U+5c58 Man # Character å±
+U+5c59 E # Character å±
+U+5c5a Lou # Character å±
+U+5c5b Ping # Character å±
+U+5c5c Ti # Character å±
+U+5c5d Fei # Character å±
+U+5c5e Shu # Character å±
+U+5c5f Xie # Character å±
+U+5c60 Tu # Character å±
+U+5c61 Lu # Character 屡
+U+5c62 Lu # Character å±¢
+U+5c63 Xi # Character å±£
+U+5c64 Ceng # Character 層
+U+5c65 Lu # Character å±¥
+U+5c66 Ju # Character 屦
+U+5c67 Xie # Character 屧
+U+5c68 Ju # Character 屨
+U+5c69 Jue # Character 屩
+U+5c6a Liao # Character 屪
+U+5c6b Jue # Character 屫
+U+5c6c Shu # Character 屬
+U+5c6d Xi # Character å±
+U+5c6e Che # Character å±®
+U+5c6f Tun # Character 屯
+U+5c70 Ni # Character å±°
+U+5c71 Shan # Character å±±
+U+5c72 ? # Character å±²
+U+5c73 Xian # Character å±³
+U+5c74 Li # Character å±´
+U+5c75 Xue # Character å±µ
+U+5c76 Nata # Character 屶
+U+5c77 ? # Character å±·
+U+5c78 Long # Character 屸
+U+5c79 Yi # Character å±¹
+U+5c7a Qi # Character 屺
+U+5c7b Ren # Character å±»
+U+5c7c Wu # Character å±¼
+U+5c7d Han # Character å±½
+U+5c7e Shen # Character å±¾
+U+5c7f Yu # Character 屿
+U+5c80 Chu # Character å²
+U+5c81 Sui # Character å²
+U+5c82 Qi # Character å²
+U+5c83 ? # Character å²
+U+5c84 Yue # Character å²
+U+5c85 Ban # Character å²
+U+5c86 Yao # Character å²
+U+5c87 Ang # Character å²
+U+5c88 Ya # Character å²
+U+5c89 Wu # Character å²
+U+5c8a Jie # Character å²
+U+5c8b E # Character å²
+U+5c8c Ji # Character å²
+U+5c8d Qian # Character å²
+U+5c8e Fen # Character å²
+U+5c8f Yuan # Character å²
+U+5c90 Qi # Character å²
+U+5c91 Cen # Character å²
+U+5c92 Qian # Character å²
+U+5c93 Qi # Character å²
+U+5c94 Cha # Character å²
+U+5c95 Jie # Character å²
+U+5c96 Qu # Character å²
+U+5c97 Gang # Character å²
+U+5c98 Xian # Character å²
+U+5c99 Ao # Character å²
+U+5c9a Lan # Character å²
+U+5c9b Dao # Character å²
+U+5c9c Ba # Character å²
+U+5c9d Zuo # Character å²
+U+5c9e Zuo # Character å²
+U+5c9f Yang # Character å²
+U+5ca0 Ju # Character å²
+U+5ca1 Gang # Character 岡
+U+5ca2 Ke # Character å²¢
+U+5ca3 Gou # Character å²£
+U+5ca4 Xue # Character 岤
+U+5ca5 Bei # Character å²¥
+U+5ca6 Li # Character 岦
+U+5ca7 Tiao # Character 岧
+U+5ca8 Ju # Character 岨
+U+5ca9 Yan # Character 岩
+U+5caa Fu # Character 岪
+U+5cab Xiu # Character 岫
+U+5cac Jia # Character 岬
+U+5cad Ling # Character å²
+U+5cae Tuo # Character å²®
+U+5caf Pei # Character 岯
+U+5cb0 You # Character å²°
+U+5cb1 Dai # Character å²±
+U+5cb2 Kuang # Character å²²
+U+5cb3 Yue # Character å²³
+U+5cb4 Qu # Character å²´
+U+5cb5 Hu # Character å²µ
+U+5cb6 Po # Character 岶
+U+5cb7 Min # Character å²·
+U+5cb8 An # Character 岸
+U+5cb9 Tiao # Character å²¹
+U+5cba Ling # Character 岺
+U+5cbb Chi # Character å²»
+U+5cbc Yuri # Character å²¼
+U+5cbd Dong # Character å²½
+U+5cbe Cem # Character å²¾
+U+5cbf Kui # Character 岿
+U+5cc0 Xiu # Character å³
+U+5cc1 Mao # Character å³
+U+5cc2 Tong # Character å³
+U+5cc3 Xue # Character å³
+U+5cc4 Yi # Character å³
+U+5cc5 Kura # Character å³
+U+5cc6 He # Character å³
+U+5cc7 Ke # Character å³
+U+5cc8 Luo # Character å³
+U+5cc9 E # Character å³
+U+5cca Fu # Character å³
+U+5ccb Xun # Character å³
+U+5ccc Die # Character å³
+U+5ccd Lu # Character å³
+U+5cce An # Character å³
+U+5ccf Er # Character å³
+U+5cd0 Gai # Character å³
+U+5cd1 Quan # Character å³
+U+5cd2 Tong # Character å³
+U+5cd3 Yi # Character å³
+U+5cd4 Mu # Character å³
+U+5cd5 Shi # Character å³
+U+5cd6 An # Character å³
+U+5cd7 Wei # Character å³
+U+5cd8 Hu # Character å³
+U+5cd9 Zhi # Character å³
+U+5cda Mi # Character å³
+U+5cdb Li # Character å³
+U+5cdc Ji # Character å³
+U+5cdd Tong # Character å³
+U+5cde Wei # Character å³
+U+5cdf You # Character å³
+U+5ce0 Sang # Character å³
+U+5ce1 Xia # Character 峡
+U+5ce2 Li # Character å³¢
+U+5ce3 Yao # Character å³£
+U+5ce4 Jiao # Character 峤
+U+5ce5 Zheng # Character å³¥
+U+5ce6 Luan # Character 峦
+U+5ce7 Jiao # Character 峧
+U+5ce8 E # Character 峨
+U+5ce9 E # Character 峩
+U+5cea Yu # Character 峪
+U+5ceb Ye # Character 峫
+U+5cec Bu # Character 峬
+U+5ced Qiao # Character å³
+U+5cee Qun # Character å³®
+U+5cef Feng # Character 峯
+U+5cf0 Feng # Character å³°
+U+5cf1 Nao # Character å³±
+U+5cf2 Li # Character å³²
+U+5cf3 You # Character å³³
+U+5cf4 Xian # Character å³´
+U+5cf5 Hong # Character å³µ
+U+5cf6 Dao # Character 島
+U+5cf7 Shen # Character å³·
+U+5cf8 Cheng # Character 峸
+U+5cf9 Tu # Character å³¹
+U+5cfa Geng # Character 峺
+U+5cfb Jun # Character å³»
+U+5cfc Hao # Character å³¼
+U+5cfd Xia # Character å³½
+U+5cfe Yin # Character å³¾
+U+5cff Yu # Character 峿
diff --git a/resources/chars/ascii/row5d.trans b/resources/chars/ascii/row5d.trans
new file mode 100644
index 0000000..8c4855a
--- /dev/null
+++ b/resources/chars/ascii/row5d.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+5d00 Lang # Character å´
+U+5d01 Kan # Character å´
+U+5d02 Lao # Character å´
+U+5d03 Lai # Character å´
+U+5d04 Xian # Character å´
+U+5d05 Que # Character å´
+U+5d06 Kong # Character å´
+U+5d07 Chong # Character å´
+U+5d08 Chong # Character å´
+U+5d09 Ta # Character å´
+U+5d0a Lin # Character å´
+U+5d0b Hua # Character å´
+U+5d0c Ju # Character å´
+U+5d0d Lai # Character å´
+U+5d0e Qi # Character å´
+U+5d0f Min # Character å´
+U+5d10 Kun # Character å´
+U+5d11 Kun # Character å´
+U+5d12 Zu # Character å´
+U+5d13 Gu # Character å´
+U+5d14 Cui # Character å´
+U+5d15 Ya # Character å´
+U+5d16 Ya # Character å´
+U+5d17 Gang # Character å´
+U+5d18 Lun # Character å´
+U+5d19 Lun # Character å´
+U+5d1a Leng # Character å´
+U+5d1b Jue # Character å´
+U+5d1c Duo # Character å´
+U+5d1d Zheng # Character å´
+U+5d1e Guo # Character å´
+U+5d1f Yin # Character å´
+U+5d20 Dong # Character å´
+U+5d21 Han # Character å´¡
+U+5d22 Zheng # Character å´¢
+U+5d23 Wei # Character å´£
+U+5d24 Yao # Character å´¤
+U+5d25 Pi # Character å´¥
+U+5d26 Yan # Character å´¦
+U+5d27 Song # Character å´§
+U+5d28 Jie # Character å´¨
+U+5d29 Beng # Character å´©
+U+5d2a Zu # Character å´ª
+U+5d2b Jue # Character å´«
+U+5d2c Dong # Character å´¬
+U+5d2d Zhan # Character å´
+U+5d2e Gu # Character å´®
+U+5d2f Yin # Character å´¯
+U+5d30 ? # Character å´°
+U+5d31 Ze # Character å´±
+U+5d32 Huang # Character å´²
+U+5d33 Yu # Character å´³
+U+5d34 Wei # Character å´´
+U+5d35 Yang # Character å´µ
+U+5d36 Feng # Character å´¶
+U+5d37 Qiu # Character å´·
+U+5d38 Dun # Character å´¸
+U+5d39 Ti # Character å´¹
+U+5d3a Yi # Character å´º
+U+5d3b Zhi # Character å´»
+U+5d3c Shi # Character å´¼
+U+5d3d Zai # Character å´½
+U+5d3e Yao # Character å´¾
+U+5d3f E # Character å´¿
+U+5d40 Zhu # Character åµ
+U+5d41 Kan # Character åµ
+U+5d42 Lu # Character åµ
+U+5d43 Yan # Character åµ
+U+5d44 Mei # Character åµ
+U+5d45 Gan # Character åµ
+U+5d46 Ji # Character åµ
+U+5d47 Ji # Character åµ
+U+5d48 Huan # Character åµ
+U+5d49 Ting # Character åµ
+U+5d4a Sheng # Character åµ
+U+5d4b Mei # Character åµ
+U+5d4c Qian # Character åµ
+U+5d4d Wu # Character åµ
+U+5d4e Yu # Character åµ
+U+5d4f Zong # Character åµ
+U+5d50 Lan # Character åµ
+U+5d51 Jue # Character åµ
+U+5d52 Yan # Character åµ
+U+5d53 Yan # Character åµ
+U+5d54 Wei # Character åµ
+U+5d55 Zong # Character åµ
+U+5d56 Cha # Character åµ
+U+5d57 Sui # Character åµ
+U+5d58 Rong # Character åµ
+U+5d59 Yamashina # Character åµ
+U+5d5a Qin # Character åµ
+U+5d5b Yu # Character åµ
+U+5d5c Kewashii # Character åµ
+U+5d5d Lou # Character åµ
+U+5d5e Tu # Character åµ
+U+5d5f Dui # Character åµ
+U+5d60 Xi # Character åµ
+U+5d61 Weng # Character 嵡
+U+5d62 Cang # Character åµ¢
+U+5d63 Dang # Character åµ£
+U+5d64 Hong # Character 嵤
+U+5d65 Jie # Character åµ¥
+U+5d66 Ai # Character 嵦
+U+5d67 Liu # Character 嵧
+U+5d68 Wu # Character 嵨
+U+5d69 Song # Character 嵩
+U+5d6a Qiao # Character 嵪
+U+5d6b Zi # Character 嵫
+U+5d6c Wei # Character 嵬
+U+5d6d Beng # Character åµ
+U+5d6e Dian # Character åµ®
+U+5d6f Cuo # Character 嵯
+U+5d70 Qian # Character åµ°
+U+5d71 Yong # Character åµ±
+U+5d72 Nie # Character åµ²
+U+5d73 Cuo # Character åµ³
+U+5d74 Ji # Character åµ´
+U+5d75 ? # Character åµµ
+U+5d76 Tao # Character 嵶
+U+5d77 Song # Character åµ·
+U+5d78 Zong # Character 嵸
+U+5d79 Jiang # Character åµ¹
+U+5d7a Liao # Character 嵺
+U+5d7b Kang # Character åµ»
+U+5d7c Chan # Character åµ¼
+U+5d7d Die # Character åµ½
+U+5d7e Cen # Character åµ¾
+U+5d7f Ding # Character 嵿
+U+5d80 Tu # Character å¶
+U+5d81 Lou # Character å¶
+U+5d82 Zhang # Character å¶
+U+5d83 Zhan # Character å¶
+U+5d84 Zhan # Character å¶
+U+5d85 Ao # Character å¶
+U+5d86 Cao # Character å¶
+U+5d87 Qu # Character å¶
+U+5d88 Qiang # Character å¶
+U+5d89 Zui # Character å¶
+U+5d8a Zui # Character å¶
+U+5d8b Dao # Character å¶
+U+5d8c Dao # Character å¶
+U+5d8d Xi # Character å¶
+U+5d8e Yu # Character å¶
+U+5d8f Bo # Character å¶
+U+5d90 Long # Character å¶
+U+5d91 Xiang # Character å¶
+U+5d92 Ceng # Character å¶
+U+5d93 Bo # Character å¶
+U+5d94 Qin # Character å¶
+U+5d95 Jiao # Character å¶
+U+5d96 Yan # Character å¶
+U+5d97 Lao # Character å¶
+U+5d98 Zhan # Character å¶
+U+5d99 Lin # Character å¶
+U+5d9a Liao # Character å¶
+U+5d9b Liao # Character å¶
+U+5d9c Jin # Character å¶
+U+5d9d Deng # Character å¶
+U+5d9e Duo # Character å¶
+U+5d9f Zun # Character å¶
+U+5da0 Jiao # Character å¶
+U+5da1 Gui # Character 嶡
+U+5da2 Yao # Character 嶢
+U+5da3 Qiao # Character 嶣
+U+5da4 Yao # Character 嶤
+U+5da5 Jue # Character 嶥
+U+5da6 Zhan # Character 嶦
+U+5da7 Yi # Character 嶧
+U+5da8 Xue # Character 嶨
+U+5da9 Nao # Character 嶩
+U+5daa Ye # Character 嶪
+U+5dab Ye # Character 嶫
+U+5dac Yi # Character 嶬
+U+5dad E # Character å¶
+U+5dae Xian # Character 嶮
+U+5daf Ji # Character 嶯
+U+5db0 Xie # Character 嶰
+U+5db1 Ke # Character 嶱
+U+5db2 Xi # Character 嶲
+U+5db3 Di # Character 嶳
+U+5db4 Ao # Character 嶴
+U+5db5 Zui # Character 嶵
+U+5db6 ? # Character 嶶
+U+5db7 Ni # Character 嶷
+U+5db8 Rong # Character 嶸
+U+5db9 Dao # Character 嶹
+U+5dba Ling # Character 嶺
+U+5dbb Za # Character 嶻
+U+5dbc Yu # Character 嶼
+U+5dbd Yue # Character 嶽
+U+5dbe Yin # Character 嶾
+U+5dbf ? # Character 嶿
+U+5dc0 Jie # Character å·
+U+5dc1 Li # Character å·
+U+5dc2 Sui # Character å·
+U+5dc3 Long # Character å·
+U+5dc4 Long # Character å·
+U+5dc5 Dian # Character å·
+U+5dc6 Ying # Character å·
+U+5dc7 Xi # Character å·
+U+5dc8 Ju # Character å·
+U+5dc9 Chan # Character å·
+U+5dca Ying # Character å·
+U+5dcb Kui # Character å·
+U+5dcc Yan # Character å·
+U+5dcd Wei # Character å·
+U+5dce Nao # Character å·
+U+5dcf Quan # Character å·
+U+5dd0 Chao # Character å·
+U+5dd1 Cuan # Character å·
+U+5dd2 Luan # Character å·
+U+5dd3 Dian # Character å·
+U+5dd4 Dian # Character å·
+U+5dd5 ? # Character å·
+U+5dd6 Yan # Character å·
+U+5dd7 Yan # Character å·
+U+5dd8 Yan # Character å·
+U+5dd9 Nao # Character å·
+U+5dda Yan # Character å·
+U+5ddb Chuan # Character å·
+U+5ddc Gui # Character å·
+U+5ddd Chuan # Character å·
+U+5dde Zhou # Character å·
+U+5ddf Huang # Character å·
+U+5de0 Jing # Character å·
+U+5de1 Xun # Character å·¡
+U+5de2 Chao # Character å·¢
+U+5de3 Chao # Character å·£
+U+5de4 Lie # Character å·¤
+U+5de5 Gong # Character å·¥
+U+5de6 Zuo # Character å·¦
+U+5de7 Qiao # Character å·§
+U+5de8 Ju # Character å·¨
+U+5de9 Gong # Character å·©
+U+5dea Kek # Character å·ª
+U+5deb Wu # Character å·«
+U+5dec Pwu # Character å·¬
+U+5ded Pwu # Character å·
+U+5dee Chai # Character å·®
+U+5def Qiu # Character å·¯
+U+5df0 Qiu # Character å·°
+U+5df1 Ji # Character å·±
+U+5df2 Yi # Character å·²
+U+5df3 Si # Character å·³
+U+5df4 Ba # Character å·´
+U+5df5 Zhi # Character å·µ
+U+5df6 Zhao # Character å·¶
+U+5df7 Xiang # Character å··
+U+5df8 Yi # Character å·¸
+U+5df9 Jin # Character å·¹
+U+5dfa Xun # Character å·º
+U+5dfb Juan # Character å·»
+U+5dfc Phas # Character å·¼
+U+5dfd Xun # Character å·½
+U+5dfe Jin # Character å·¾
+U+5dff Fu # Character å·¿
diff --git a/resources/chars/ascii/row5e.trans b/resources/chars/ascii/row5e.trans
new file mode 100644
index 0000000..d94bbda
--- /dev/null
+++ b/resources/chars/ascii/row5e.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+5e00 Za # Character å¸
+U+5e01 Bi # Character å¸
+U+5e02 Shi # Character å¸
+U+5e03 Bu # Character å¸
+U+5e04 Ding # Character å¸
+U+5e05 Shuai # Character å¸
+U+5e06 Fan # Character å¸
+U+5e07 Nie # Character å¸
+U+5e08 Shi # Character å¸
+U+5e09 Fen # Character å¸
+U+5e0a Pa # Character å¸
+U+5e0b Zhi # Character å¸
+U+5e0c Xi # Character å¸
+U+5e0d Hu # Character å¸
+U+5e0e Dan # Character å¸
+U+5e0f Wei # Character å¸
+U+5e10 Zhang # Character å¸
+U+5e11 Tang # Character å¸
+U+5e12 Dai # Character å¸
+U+5e13 Ma # Character å¸
+U+5e14 Pei # Character å¸
+U+5e15 Pa # Character å¸
+U+5e16 Tie # Character å¸
+U+5e17 Fu # Character å¸
+U+5e18 Lian # Character å¸
+U+5e19 Zhi # Character å¸
+U+5e1a Zhou # Character å¸
+U+5e1b Bo # Character å¸
+U+5e1c Zhi # Character å¸
+U+5e1d Di # Character å¸
+U+5e1e Mo # Character å¸
+U+5e1f Yi # Character å¸
+U+5e20 Yi # Character å¸
+U+5e21 Ping # Character 帡
+U+5e22 Qia # Character 帢
+U+5e23 Juan # Character 帣
+U+5e24 Ru # Character 帤
+U+5e25 Shuai # Character 帥
+U+5e26 Dai # Character 带
+U+5e27 Zheng # Character 帧
+U+5e28 Shui # Character 帨
+U+5e29 Qiao # Character 帩
+U+5e2a Zhen # Character 帪
+U+5e2b Shi # Character 師
+U+5e2c Qun # Character 帬
+U+5e2d Xi # Character å¸
+U+5e2e Bang # Character 帮
+U+5e2f Dai # Character 帯
+U+5e30 Gui # Character 帰
+U+5e31 Chou # Character 帱
+U+5e32 Ping # Character 帲
+U+5e33 Zhang # Character 帳
+U+5e34 Sha # Character 帴
+U+5e35 Wan # Character 帵
+U+5e36 Dai # Character 帶
+U+5e37 Wei # Character 帷
+U+5e38 Chang # Character 常
+U+5e39 Sha # Character 帹
+U+5e3a Qi # Character 帺
+U+5e3b Ze # Character 帻
+U+5e3c Guo # Character 帼
+U+5e3d Mao # Character 帽
+U+5e3e Du # Character 帾
+U+5e3f Hou # Character 帿
+U+5e40 Zheng # Character å¹
+U+5e41 Xu # Character å¹
+U+5e42 Mi # Character å¹
+U+5e43 Wei # Character å¹
+U+5e44 Wo # Character å¹
+U+5e45 Fu # Character å¹
+U+5e46 Yi # Character å¹
+U+5e47 Bang # Character å¹
+U+5e48 Ping # Character å¹
+U+5e49 Tazuna # Character å¹
+U+5e4a Gong # Character å¹
+U+5e4b Pan # Character å¹
+U+5e4c Huang # Character å¹
+U+5e4d Dao # Character å¹
+U+5e4e Mi # Character å¹
+U+5e4f Jia # Character å¹
+U+5e50 Teng # Character å¹
+U+5e51 Hui # Character å¹
+U+5e52 Zhong # Character å¹
+U+5e53 Shan # Character å¹
+U+5e54 Man # Character å¹
+U+5e55 Mu # Character å¹
+U+5e56 Biao # Character å¹
+U+5e57 Guo # Character å¹
+U+5e58 Ze # Character å¹
+U+5e59 Mu # Character å¹
+U+5e5a Bang # Character å¹
+U+5e5b Zhang # Character å¹
+U+5e5c Jiong # Character å¹
+U+5e5d Chan # Character å¹
+U+5e5e Fu # Character å¹
+U+5e5f Zhi # Character å¹
+U+5e60 Hu # Character å¹
+U+5e61 Fan # Character 幡
+U+5e62 Chuang # Character å¹¢
+U+5e63 Bi # Character å¹£
+U+5e64 Hei # Character 幤
+U+5e65 ? # Character å¹¥
+U+5e66 Mi # Character 幦
+U+5e67 Qiao # Character 幧
+U+5e68 Chan # Character 幨
+U+5e69 Fen # Character 幩
+U+5e6a Meng # Character 幪
+U+5e6b Bang # Character 幫
+U+5e6c Chou # Character 幬
+U+5e6d Mie # Character å¹
+U+5e6e Chu # Character å¹®
+U+5e6f Jie # Character 幯
+U+5e70 Xian # Character å¹°
+U+5e71 Lan # Character å¹±
+U+5e72 Gan # Character å¹²
+U+5e73 Ping # Character å¹³
+U+5e74 Nian # Character å¹´
+U+5e75 Qian # Character å¹µ
+U+5e76 Bing # Character 并
+U+5e77 Bing # Character å¹·
+U+5e78 Xing # Character 幸
+U+5e79 Gan # Character å¹¹
+U+5e7a Yao # Character 幺
+U+5e7b Huan # Character å¹»
+U+5e7c You # Character å¹¼
+U+5e7d You # Character å¹½
+U+5e7e Ji # Character å¹¾
+U+5e7f Yan # Character 广
+U+5e80 Pi # Character åº
+U+5e81 Ting # Character åº
+U+5e82 Ze # Character åº
+U+5e83 Guang # Character åº
+U+5e84 Zhuang # Character åº
+U+5e85 Mo # Character åº
+U+5e86 Qing # Character åº
+U+5e87 Bi # Character åº
+U+5e88 Qin # Character åº
+U+5e89 Dun # Character åº
+U+5e8a Chuang # Character åº
+U+5e8b Gui # Character åº
+U+5e8c Ya # Character åº
+U+5e8d Bai # Character åº
+U+5e8e Jie # Character åº
+U+5e8f Xu # Character åº
+U+5e90 Lu # Character åº
+U+5e91 Wu # Character åº
+U+5e92 ? # Character åº
+U+5e93 Ku # Character åº
+U+5e94 Ying # Character åº
+U+5e95 Di # Character åº
+U+5e96 Pao # Character åº
+U+5e97 Dian # Character åº
+U+5e98 Ya # Character åº
+U+5e99 Miao # Character åº
+U+5e9a Geng # Character åº
+U+5e9b Ci # Character åº
+U+5e9c Fu # Character åº
+U+5e9d Tong # Character åº
+U+5e9e Pang # Character åº
+U+5e9f Fei # Character åº
+U+5ea0 Xiang # Character åº
+U+5ea1 Yi # Character 庡
+U+5ea2 Zhi # Character 庢
+U+5ea3 Tiao # Character 庣
+U+5ea4 Zhi # Character 庤
+U+5ea5 Xiu # Character 庥
+U+5ea6 Du # Character 度
+U+5ea7 Zuo # Character 座
+U+5ea8 Xiao # Character 庨
+U+5ea9 Tu # Character 庩
+U+5eaa Gui # Character 庪
+U+5eab Ku # Character 庫
+U+5eac Pang # Character 庬
+U+5ead Ting # Character åº
+U+5eae You # Character 庮
+U+5eaf Bu # Character 庯
+U+5eb0 Ding # Character 庰
+U+5eb1 Cheng # Character 庱
+U+5eb2 Lai # Character 庲
+U+5eb3 Bei # Character 庳
+U+5eb4 Ji # Character 庴
+U+5eb5 An # Character 庵
+U+5eb6 Shu # Character 庶
+U+5eb7 Kang # Character 康
+U+5eb8 Yong # Character 庸
+U+5eb9 Tuo # Character 庹
+U+5eba Song # Character 庺
+U+5ebb Shu # Character 庻
+U+5ebc Qing # Character 庼
+U+5ebd Yu # Character 庽
+U+5ebe Yu # Character 庾
+U+5ebf Miao # Character 庿
+U+5ec0 Sou # Character å»
+U+5ec1 Ce # Character å»
+U+5ec2 Xiang # Character å»
+U+5ec3 Fei # Character å»
+U+5ec4 Jiu # Character å»
+U+5ec5 He # Character å»
+U+5ec6 Hui # Character å»
+U+5ec7 Liu # Character å»
+U+5ec8 Sha # Character å»
+U+5ec9 Lian # Character å»
+U+5eca Lang # Character å»
+U+5ecb Sou # Character å»
+U+5ecc Jian # Character å»
+U+5ecd Pou # Character å»
+U+5ece Qing # Character å»
+U+5ecf Jiu # Character å»
+U+5ed0 Jiu # Character å»
+U+5ed1 Qin # Character å»
+U+5ed2 Ao # Character å»
+U+5ed3 Kuo # Character å»
+U+5ed4 Lou # Character å»
+U+5ed5 Yin # Character å»
+U+5ed6 Liao # Character å»
+U+5ed7 Dai # Character å»
+U+5ed8 Lu # Character å»
+U+5ed9 Yi # Character å»
+U+5eda Chu # Character å»
+U+5edb Chan # Character å»
+U+5edc Tu # Character å»
+U+5edd Si # Character å»
+U+5ede Xin # Character å»
+U+5edf Miao # Character å»
+U+5ee0 Chang # Character å»
+U+5ee1 Wu # Character 廡
+U+5ee2 Fei # Character 廢
+U+5ee3 Guang # Character 廣
+U+5ee4 Koc # Character 廤
+U+5ee5 Kuai # Character 廥
+U+5ee6 Bi # Character 廦
+U+5ee7 Qiang # Character 廧
+U+5ee8 Xie # Character 廨
+U+5ee9 Lin # Character 廩
+U+5eea Lin # Character 廪
+U+5eeb Liao # Character 廫
+U+5eec Lu # Character 廬
+U+5eed ? # Character å»
+U+5eee Ying # Character å»®
+U+5eef Xian # Character 廯
+U+5ef0 Ting # Character å»°
+U+5ef1 Yong # Character å»±
+U+5ef2 Li # Character 廲
+U+5ef3 Ting # Character 廳
+U+5ef4 Yin # Character å»´
+U+5ef5 Xun # Character 廵
+U+5ef6 Yan # Character 延
+U+5ef7 Ting # Character å»·
+U+5ef8 Di # Character 廸
+U+5ef9 Po # Character 廹
+U+5efa Jian # Character 建
+U+5efb Hui # Character å»»
+U+5efc Nai # Character 廼
+U+5efd Hui # Character 廽
+U+5efe Gong # Character 廾
+U+5eff Nian # Character 廿
diff --git a/resources/chars/ascii/row5f.trans b/resources/chars/ascii/row5f.trans
new file mode 100644
index 0000000..0d59af0
--- /dev/null
+++ b/resources/chars/ascii/row5f.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+5f00 Kai # Character å¼
+U+5f01 Bian # Character å¼
+U+5f02 Yi # Character å¼
+U+5f03 Qi # Character å¼
+U+5f04 Nong # Character å¼
+U+5f05 Fen # Character å¼
+U+5f06 Ju # Character å¼
+U+5f07 Yan # Character å¼
+U+5f08 Yi # Character å¼
+U+5f09 Zang # Character å¼
+U+5f0a Bi # Character å¼
+U+5f0b Yi # Character å¼
+U+5f0c Yi # Character å¼
+U+5f0d Er # Character å¼
+U+5f0e San # Character å¼
+U+5f0f Shi # Character å¼
+U+5f10 Er # Character å¼
+U+5f11 Shi # Character å¼
+U+5f12 Shi # Character å¼
+U+5f13 Gong # Character å¼
+U+5f14 Diao # Character å¼
+U+5f15 Yin # Character å¼
+U+5f16 Hu # Character å¼
+U+5f17 Fu # Character å¼
+U+5f18 Hong # Character å¼
+U+5f19 Wu # Character å¼
+U+5f1a Tui # Character å¼
+U+5f1b Chi # Character å¼
+U+5f1c Jiang # Character å¼
+U+5f1d Ba # Character å¼
+U+5f1e Shen # Character å¼
+U+5f1f Di # Character å¼
+U+5f20 Zhang # Character å¼
+U+5f21 Jue # Character 弡
+U+5f22 Tao # Character å¼¢
+U+5f23 Fu # Character å¼£
+U+5f24 Di # Character 弤
+U+5f25 Mi # Character å¼¥
+U+5f26 Xian # Character 弦
+U+5f27 Hu # Character 弧
+U+5f28 Chao # Character 弨
+U+5f29 Nu # Character 弩
+U+5f2a Jing # Character 弪
+U+5f2b Zhen # Character 弫
+U+5f2c Yi # Character 弬
+U+5f2d Mi # Character å¼
+U+5f2e Quan # Character å¼®
+U+5f2f Wan # Character 弯
+U+5f30 Shao # Character å¼°
+U+5f31 Ruo # Character å¼±
+U+5f32 Xuan # Character å¼²
+U+5f33 Jing # Character å¼³
+U+5f34 Dun # Character å¼´
+U+5f35 Zhang # Character å¼µ
+U+5f36 Jiang # Character 弶
+U+5f37 Qiang # Character å¼·
+U+5f38 Peng # Character 弸
+U+5f39 Dan # Character å¼¹
+U+5f3a Qiang # Character 强
+U+5f3b Bi # Character å¼»
+U+5f3c Bi # Character å¼¼
+U+5f3d She # Character å¼½
+U+5f3e Dan # Character å¼¾
+U+5f3f Jian # Character 弿
+U+5f40 Gou # Character å½
+U+5f41 Sei # Character å½
+U+5f42 Fa # Character å½
+U+5f43 Bi # Character å½
+U+5f44 Kou # Character å½
+U+5f45 Nagi # Character å½
+U+5f46 Bie # Character å½
+U+5f47 Xiao # Character å½
+U+5f48 Dan # Character å½
+U+5f49 Kuo # Character å½
+U+5f4a Qiang # Character å½
+U+5f4b Hong # Character å½
+U+5f4c Mi # Character å½
+U+5f4d Kuo # Character å½
+U+5f4e Wan # Character å½
+U+5f4f Jue # Character å½
+U+5f50 Ji # Character å½
+U+5f51 Ji # Character å½
+U+5f52 Gui # Character å½
+U+5f53 Dang # Character å½
+U+5f54 Lu # Character å½
+U+5f55 Lu # Character å½
+U+5f56 Tuan # Character å½
+U+5f57 Hui # Character å½
+U+5f58 Zhi # Character å½
+U+5f59 Hui # Character å½
+U+5f5a Hui # Character å½
+U+5f5b Yi # Character å½
+U+5f5c Yi # Character å½
+U+5f5d Yi # Character å½
+U+5f5e Yi # Character å½
+U+5f5f Huo # Character å½
+U+5f60 Huo # Character å½
+U+5f61 Shan # Character 彡
+U+5f62 Xing # Character å½¢
+U+5f63 Wen # Character å½£
+U+5f64 Tong # Character 彤
+U+5f65 Yan # Character å½¥
+U+5f66 Yan # Character 彦
+U+5f67 Yu # Character 彧
+U+5f68 Chi # Character 彨
+U+5f69 Cai # Character 彩
+U+5f6a Biao # Character 彪
+U+5f6b Diao # Character 彫
+U+5f6c Bin # Character 彬
+U+5f6d Peng # Character å½
+U+5f6e Yong # Character å½®
+U+5f6f Piao # Character 彯
+U+5f70 Zhang # Character å½°
+U+5f71 Ying # Character å½±
+U+5f72 Chi # Character å½²
+U+5f73 Chi # Character å½³
+U+5f74 Zhuo # Character å½´
+U+5f75 Tuo # Character å½µ
+U+5f76 Ji # Character 彶
+U+5f77 Pang # Character å½·
+U+5f78 Zhong # Character 彸
+U+5f79 Yi # Character å½¹
+U+5f7a Wang # Character 彺
+U+5f7b Che # Character å½»
+U+5f7c Bi # Character å½¼
+U+5f7d Chi # Character å½½
+U+5f7e Ling # Character å½¾
+U+5f7f Fu # Character 彿
+U+5f80 Wang # Character å¾
+U+5f81 Zheng # Character å¾
+U+5f82 Cu # Character å¾
+U+5f83 Wang # Character å¾
+U+5f84 Jing # Character å¾
+U+5f85 Dai # Character å¾
+U+5f86 Xi # Character å¾
+U+5f87 Xun # Character å¾
+U+5f88 Hen # Character å¾
+U+5f89 Yang # Character å¾
+U+5f8a Huai # Character å¾
+U+5f8b Lu # Character å¾
+U+5f8c Hou # Character å¾
+U+5f8d Wa # Character å¾
+U+5f8e Cheng # Character å¾
+U+5f8f Zhi # Character å¾
+U+5f90 Xu # Character å¾
+U+5f91 Jing # Character å¾
+U+5f92 Tu # Character å¾
+U+5f93 Cong # Character å¾
+U+5f94 ? # Character å¾
+U+5f95 Lai # Character å¾
+U+5f96 Cong # Character å¾
+U+5f97 De # Character å¾
+U+5f98 Pai # Character å¾
+U+5f99 Xi # Character å¾
+U+5f9a ? # Character å¾
+U+5f9b Qi # Character å¾
+U+5f9c Chang # Character å¾
+U+5f9d Zhi # Character å¾
+U+5f9e Cong # Character å¾
+U+5f9f Zhou # Character å¾
+U+5fa0 Lai # Character å¾
+U+5fa1 Yu # Character 御
+U+5fa2 Xie # Character å¾¢
+U+5fa3 Jie # Character å¾£
+U+5fa4 Jian # Character 徤
+U+5fa5 Chi # Character å¾¥
+U+5fa6 Jia # Character 徦
+U+5fa7 Bian # Character 徧
+U+5fa8 Huang # Character 徨
+U+5fa9 Fu # Character 復
+U+5faa Xun # Character 循
+U+5fab Wei # Character 徫
+U+5fac Pang # Character 徬
+U+5fad Yao # Character å¾
+U+5fae Wei # Character å¾®
+U+5faf Xi # Character 徯
+U+5fb0 Zheng # Character å¾°
+U+5fb1 Piao # Character å¾±
+U+5fb2 Chi # Character å¾²
+U+5fb3 De # Character å¾³
+U+5fb4 Zheng # Character å¾´
+U+5fb5 Zheng # Character å¾µ
+U+5fb6 Bie # Character 徶
+U+5fb7 De # Character å¾·
+U+5fb8 Chong # Character 徸
+U+5fb9 Che # Character å¾¹
+U+5fba Jiao # Character 徺
+U+5fbb Wei # Character å¾»
+U+5fbc Jiao # Character å¾¼
+U+5fbd Hui # Character å¾½
+U+5fbe Mei # Character å¾¾
+U+5fbf Long # Character 徿
+U+5fc0 Xiang # Character å¿
+U+5fc1 Bao # Character å¿
+U+5fc2 Qu # Character å¿
+U+5fc3 Xin # Character å¿
+U+5fc4 Shu # Character å¿
+U+5fc5 Bi # Character å¿
+U+5fc6 Yi # Character å¿
+U+5fc7 Le # Character å¿
+U+5fc8 Ren # Character å¿
+U+5fc9 Dao # Character å¿
+U+5fca Ding # Character å¿
+U+5fcb Gai # Character å¿
+U+5fcc Ji # Character å¿
+U+5fcd Ren # Character å¿
+U+5fce Ren # Character å¿
+U+5fcf Chan # Character å¿
+U+5fd0 Tan # Character å¿
+U+5fd1 Te # Character å¿
+U+5fd2 Te # Character å¿
+U+5fd3 Gan # Character å¿
+U+5fd4 Qi # Character å¿
+U+5fd5 Shi # Character å¿
+U+5fd6 Cun # Character å¿
+U+5fd7 Zhi # Character å¿
+U+5fd8 Wang # Character å¿
+U+5fd9 Mang # Character å¿
+U+5fda Xi # Character å¿
+U+5fdb Fan # Character å¿
+U+5fdc Ying # Character å¿
+U+5fdd Tian # Character å¿
+U+5fde Min # Character å¿
+U+5fdf Min # Character å¿
+U+5fe0 Zhong # Character å¿
+U+5fe1 Chong # Character å¿¡
+U+5fe2 Wu # Character å¿¢
+U+5fe3 Ji # Character å¿£
+U+5fe4 Wu # Character 忤
+U+5fe5 Xi # Character å¿¥
+U+5fe6 Ye # Character 忦
+U+5fe7 You # Character 忧
+U+5fe8 Wan # Character 忨
+U+5fe9 Cong # Character å¿©
+U+5fea Zhong # Character 忪
+U+5feb Kuai # Character å¿«
+U+5fec Yu # Character 忬
+U+5fed Bian # Character å¿
+U+5fee Zhi # Character å¿®
+U+5fef Qi # Character 忯
+U+5ff0 Cui # Character å¿°
+U+5ff1 Chen # Character 忱
+U+5ff2 Tai # Character 忲
+U+5ff3 Tun # Character 忳
+U+5ff4 Qian # Character å¿´
+U+5ff5 Nian # Character 念
+U+5ff6 Hun # Character 忶
+U+5ff7 Xiong # Character å¿·
+U+5ff8 Niu # Character 忸
+U+5ff9 Wang # Character 忹
+U+5ffa Xian # Character 忺
+U+5ffb Xin # Character å¿»
+U+5ffc Kang # Character 忼
+U+5ffd Hu # Character 忽
+U+5ffe Kai # Character 忾
+U+5fff Fen # Character å¿¿
diff --git a/resources/chars/ascii/row60.trans b/resources/chars/ascii/row60.trans
new file mode 100644
index 0000000..65a71e4
--- /dev/null
+++ b/resources/chars/ascii/row60.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+6000 Huai # Character æ
+U+6001 Tai # Character æ
+U+6002 Song # Character æ
+U+6003 Wu # Character æ
+U+6004 Ou # Character æ
+U+6005 Chang # Character æ
+U+6006 Chuang # Character æ
+U+6007 Ju # Character æ
+U+6008 Yi # Character æ
+U+6009 Bao # Character æ
+U+600a Chao # Character æ
+U+600b Min # Character æ
+U+600c Pei # Character æ
+U+600d Zuo # Character æ
+U+600e Zen # Character æ
+U+600f Yang # Character æ
+U+6010 Kou # Character æ
+U+6011 Ban # Character æ
+U+6012 Nu # Character æ
+U+6013 Nao # Character æ
+U+6014 Zheng # Character æ
+U+6015 Pa # Character æ
+U+6016 Bu # Character æ
+U+6017 Tie # Character æ
+U+6018 Gu # Character æ
+U+6019 Hu # Character æ
+U+601a Ju # Character æ
+U+601b Da # Character æ
+U+601c Lian # Character æ
+U+601d Si # Character æ
+U+601e Chou # Character æ
+U+601f Di # Character æ
+U+6020 Dai # Character æ
+U+6021 Yi # Character æ¡
+U+6022 Tu # Character æ¢
+U+6023 You # Character æ£
+U+6024 Fu # Character æ¤
+U+6025 Ji # Character æ¥
+U+6026 Peng # Character æ¦
+U+6027 Xing # Character æ§
+U+6028 Yuan # Character æ¨
+U+6029 Ni # Character æ©
+U+602a Guai # Character æª
+U+602b Fu # Character æ«
+U+602c Xi # Character æ¬
+U+602d Bi # Character æ
+U+602e You # Character æ®
+U+602f Qie # Character æ¯
+U+6030 Xuan # Character æ°
+U+6031 Cong # Character æ±
+U+6032 Bing # Character æ²
+U+6033 Huang # Character æ³
+U+6034 Xu # Character æ´
+U+6035 Chu # Character æµ
+U+6036 Pi # Character æ¶
+U+6037 Xi # Character æ·
+U+6038 Xi # Character æ¸
+U+6039 Tan # Character æ¹
+U+603a Koraeru # Character æº
+U+603b Zong # Character æ»
+U+603c Dui # Character æ¼
+U+603d ? # Character æ½
+U+603e Ki # Character æ¾
+U+603f Yi # Character æ¿
+U+6040 Chi # Character æ
+U+6041 Ren # Character æ
+U+6042 Xun # Character æ
+U+6043 Shi # Character æ
+U+6044 Xi # Character æ
+U+6045 Lao # Character æ
+U+6046 Heng # Character æ
+U+6047 Kuang # Character æ
+U+6048 Mu # Character æ
+U+6049 Zhi # Character æ
+U+604a Xie # Character æ
+U+604b Lian # Character æ
+U+604c Tiao # Character æ
+U+604d Huang # Character æ
+U+604e Die # Character æ
+U+604f Hao # Character æ
+U+6050 Kong # Character æ
+U+6051 Gui # Character æ
+U+6052 Heng # Character æ
+U+6053 Xi # Character æ
+U+6054 Xiao # Character æ
+U+6055 Shu # Character æ
+U+6056 S # Character æ
+U+6057 Kua # Character æ
+U+6058 Qiu # Character æ
+U+6059 Yang # Character æ
+U+605a Hui # Character æ
+U+605b Hui # Character æ
+U+605c Chi # Character æ
+U+605d Jia # Character æ
+U+605e Yi # Character æ
+U+605f Xiong # Character æ
+U+6060 Guai # Character æ
+U+6061 Lin # Character æ¡
+U+6062 Hui # Character æ¢
+U+6063 Zi # Character æ£
+U+6064 Xu # Character æ¤
+U+6065 Chi # Character æ¥
+U+6066 Xiang # Character æ¦
+U+6067 Nu # Character æ§
+U+6068 Hen # Character æ¨
+U+6069 En # Character æ©
+U+606a Ke # Character æª
+U+606b Tong # Character æ«
+U+606c Tian # Character æ¬
+U+606d Gong # Character æ
+U+606e Quan # Character æ®
+U+606f Xi # Character æ¯
+U+6070 Qia # Character æ°
+U+6071 Yue # Character æ±
+U+6072 Peng # Character æ²
+U+6073 Ken # Character æ³
+U+6074 De # Character æ´
+U+6075 Hui # Character æµ
+U+6076 E # Character æ¶
+U+6077 Kyuu # Character æ·
+U+6078 Tong # Character æ¸
+U+6079 Yan # Character æ¹
+U+607a Kai # Character æº
+U+607b Ce # Character æ»
+U+607c Nao # Character æ¼
+U+607d Yun # Character æ½
+U+607e Mang # Character æ¾
+U+607f Yong # Character æ¿
+U+6080 Yong # Character æ
+U+6081 Yuan # Character æ
+U+6082 Pi # Character æ
+U+6083 Kun # Character æ
+U+6084 Qiao # Character æ
+U+6085 Yue # Character æ
+U+6086 Yu # Character æ
+U+6087 Yu # Character æ
+U+6088 Jie # Character æ
+U+6089 Xi # Character æ
+U+608a Zhe # Character æ
+U+608b Lin # Character æ
+U+608c Ti # Character æ
+U+608d Han # Character æ
+U+608e Hao # Character æ
+U+608f Qie # Character æ
+U+6090 Ti # Character æ
+U+6091 Bu # Character æ
+U+6092 Yi # Character æ
+U+6093 Qian # Character æ
+U+6094 Hui # Character æ
+U+6095 Xi # Character æ
+U+6096 Bei # Character æ
+U+6097 Man # Character æ
+U+6098 Yi # Character æ
+U+6099 Heng # Character æ
+U+609a Song # Character æ
+U+609b Quan # Character æ
+U+609c Cheng # Character æ
+U+609d Hui # Character æ
+U+609e Wu # Character æ
+U+609f Wu # Character æ
+U+60a0 You # Character æ
+U+60a1 Li # Character æ¡
+U+60a2 Liang # Character æ¢
+U+60a3 Huan # Character æ£
+U+60a4 Cong # Character æ¤
+U+60a5 Yi # Character æ¥
+U+60a6 Yue # Character æ¦
+U+60a7 Li # Character æ§
+U+60a8 Nin # Character æ¨
+U+60a9 Nao # Character æ©
+U+60aa E # Character æª
+U+60ab Que # Character æ«
+U+60ac Xuan # Character æ¬
+U+60ad Qian # Character æ
+U+60ae Wu # Character æ®
+U+60af Min # Character æ¯
+U+60b0 Cong # Character æ°
+U+60b1 Fei # Character æ±
+U+60b2 Bei # Character æ²
+U+60b3 Duo # Character æ³
+U+60b4 Cui # Character æ´
+U+60b5 Chang # Character æµ
+U+60b6 Men # Character æ¶
+U+60b7 Li # Character æ·
+U+60b8 Ji # Character æ¸
+U+60b9 Guan # Character æ¹
+U+60ba Guan # Character æº
+U+60bb Xing # Character æ»
+U+60bc Dao # Character æ¼
+U+60bd Qi # Character æ½
+U+60be Kong # Character æ¾
+U+60bf Tian # Character æ¿
+U+60c0 Lun # Character æ
+U+60c1 Xi # Character æ
+U+60c2 Kan # Character æ
+U+60c3 Kun # Character æ
+U+60c4 Ni # Character æ
+U+60c5 Qing # Character æ
+U+60c6 Chou # Character æ
+U+60c7 Dun # Character æ
+U+60c8 Guo # Character æ
+U+60c9 Chan # Character æ
+U+60ca Liang # Character æ
+U+60cb Wan # Character æ
+U+60cc Yuan # Character æ
+U+60cd Jin # Character æ
+U+60ce Ji # Character æ
+U+60cf Lin # Character æ
+U+60d0 Yu # Character æ
+U+60d1 Huo # Character æ
+U+60d2 He # Character æ
+U+60d3 Quan # Character æ
+U+60d4 Tan # Character æ
+U+60d5 Ti # Character æ
+U+60d6 Ti # Character æ
+U+60d7 Nie # Character æ
+U+60d8 Wang # Character æ
+U+60d9 Chuo # Character æ
+U+60da Bu # Character æ
+U+60db Hun # Character æ
+U+60dc Xi # Character æ
+U+60dd Tang # Character æ
+U+60de Xin # Character æ
+U+60df Wei # Character æ
+U+60e0 Hui # Character æ
+U+60e1 E # Character æ¡
+U+60e2 Rui # Character æ¢
+U+60e3 Zong # Character æ£
+U+60e4 Jian # Character æ¤
+U+60e5 Yong # Character æ¥
+U+60e6 Dian # Character æ¦
+U+60e7 Ju # Character æ§
+U+60e8 Can # Character æ¨
+U+60e9 Cheng # Character æ©
+U+60ea De # Character æª
+U+60eb Bei # Character æ«
+U+60ec Qie # Character æ¬
+U+60ed Can # Character æ
+U+60ee Dan # Character æ®
+U+60ef Guan # Character æ¯
+U+60f0 Duo # Character æ°
+U+60f1 Nao # Character æ±
+U+60f2 Yun # Character æ²
+U+60f3 Xiang # Character æ³
+U+60f4 Zhui # Character æ´
+U+60f5 Die # Character æµ
+U+60f6 Huang # Character æ¶
+U+60f7 Chun # Character æ·
+U+60f8 Qiong # Character æ¸
+U+60f9 Re # Character æ¹
+U+60fa Xing # Character æº
+U+60fb Ce # Character æ»
+U+60fc Bian # Character æ¼
+U+60fd Hun # Character æ½
+U+60fe Zong # Character æ¾
+U+60ff Ti # Character æ¿
diff --git a/resources/chars/ascii/row61.trans b/resources/chars/ascii/row61.trans
new file mode 100644
index 0000000..f17fc9e
--- /dev/null
+++ b/resources/chars/ascii/row61.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+6100 Qiao # Character æ
+U+6101 Chou # Character æ
+U+6102 Bei # Character æ
+U+6103 Xuan # Character æ
+U+6104 Wei # Character æ
+U+6105 Ge # Character æ
+U+6106 Qian # Character æ
+U+6107 Wei # Character æ
+U+6108 Yu # Character æ
+U+6109 Yu # Character æ
+U+610a Bi # Character æ
+U+610b Xuan # Character æ
+U+610c Huan # Character æ
+U+610d Min # Character æ
+U+610e Bi # Character æ
+U+610f Yi # Character æ
+U+6110 Mian # Character æ
+U+6111 Yong # Character æ
+U+6112 Kai # Character æ
+U+6113 Dang # Character æ
+U+6114 Yin # Character æ
+U+6115 E # Character æ
+U+6116 Chen # Character æ
+U+6117 Mou # Character æ
+U+6118 Ke # Character æ
+U+6119 Ke # Character æ
+U+611a Yu # Character æ
+U+611b Ai # Character æ
+U+611c Qie # Character æ
+U+611d Yan # Character æ
+U+611e Nuo # Character æ
+U+611f Gan # Character æ
+U+6120 Yun # Character æ
+U+6121 Zong # Character æ¡
+U+6122 Sai # Character æ¢
+U+6123 Leng # Character æ£
+U+6124 Fen # Character æ¤
+U+6125 ? # Character æ¥
+U+6126 Kui # Character æ¦
+U+6127 Kui # Character æ§
+U+6128 Que # Character æ¨
+U+6129 Gong # Character æ©
+U+612a Yun # Character æª
+U+612b Su # Character æ«
+U+612c Su # Character æ¬
+U+612d Qi # Character æ
+U+612e Yao # Character æ®
+U+612f Song # Character æ¯
+U+6130 Huang # Character æ°
+U+6131 Ji # Character æ±
+U+6132 Gu # Character æ²
+U+6133 Ju # Character æ³
+U+6134 Chuang # Character æ´
+U+6135 Ni # Character æµ
+U+6136 Xie # Character æ¶
+U+6137 Kai # Character æ·
+U+6138 Zheng # Character æ¸
+U+6139 Yong # Character æ¹
+U+613a Cao # Character æº
+U+613b Sun # Character æ»
+U+613c Shen # Character æ¼
+U+613d Bo # Character æ½
+U+613e Kai # Character æ¾
+U+613f Yuan # Character æ¿
+U+6140 Xie # Character æ
+U+6141 Hun # Character æ
+U+6142 Yong # Character æ
+U+6143 Yang # Character æ
+U+6144 Li # Character æ
+U+6145 Sao # Character æ
+U+6146 Tao # Character æ
+U+6147 Yin # Character æ
+U+6148 Ci # Character æ
+U+6149 Xu # Character æ
+U+614a Qian # Character æ
+U+614b Tai # Character æ
+U+614c Huang # Character æ
+U+614d Yun # Character æ
+U+614e Shen # Character æ
+U+614f Ming # Character æ
+U+6150 ? # Character æ
+U+6151 She # Character æ
+U+6152 Cong # Character æ
+U+6153 Piao # Character æ
+U+6154 Mo # Character æ
+U+6155 Mu # Character æ
+U+6156 Guo # Character æ
+U+6157 Chi # Character æ
+U+6158 Can # Character æ
+U+6159 Can # Character æ
+U+615a Can # Character æ
+U+615b Cui # Character æ
+U+615c Min # Character æ
+U+615d Te # Character æ
+U+615e Zhang # Character æ
+U+615f Tong # Character æ
+U+6160 Ao # Character æ
+U+6161 Shuang # Character æ
¡
+U+6162 Man # Character æ
¢
+U+6163 Guan # Character æ
£
+U+6164 Que # Character æ
¤
+U+6165 Zao # Character æ
¥
+U+6166 Jiu # Character æ
¦
+U+6167 Hui # Character æ
§
+U+6168 Kai # Character æ
¨
+U+6169 Lian # Character æ
©
+U+616a Ou # Character æ
ª
+U+616b Song # Character æ
«
+U+616c Jin # Character æ
¬
+U+616d Yin # Character æ
+U+616e Lu # Character æ
®
+U+616f Shang # Character æ
¯
+U+6170 Wei # Character æ
°
+U+6171 Tuan # Character æ
±
+U+6172 Man # Character æ
²
+U+6173 Qian # Character æ
³
+U+6174 She # Character æ
´
+U+6175 Yong # Character æ
µ
+U+6176 Qing # Character æ
¶
+U+6177 Kang # Character æ
·
+U+6178 Di # Character æ
¸
+U+6179 Zhi # Character æ
¹
+U+617a Lou # Character æ
º
+U+617b Juan # Character æ
»
+U+617c Qi # Character æ
¼
+U+617d Qi # Character æ
½
+U+617e Yu # Character æ
¾
+U+617f Ping # Character æ
¿
+U+6180 Liao # Character æ
+U+6181 Cong # Character æ
+U+6182 You # Character æ
+U+6183 Chong # Character æ
+U+6184 Zhi # Character æ
+U+6185 Tong # Character æ
+U+6186 Cheng # Character æ
+U+6187 Qi # Character æ
+U+6188 Qu # Character æ
+U+6189 Peng # Character æ
+U+618a Bei # Character æ
+U+618b Bie # Character æ
+U+618c Chun # Character æ
+U+618d Jiao # Character æ
+U+618e Zeng # Character æ
+U+618f Chi # Character æ
+U+6190 Lian # Character æ
+U+6191 Ping # Character æ
+U+6192 Kui # Character æ
+U+6193 Hui # Character æ
+U+6194 Qiao # Character æ
+U+6195 Cheng # Character æ
+U+6196 Yin # Character æ
+U+6197 Yin # Character æ
+U+6198 Xi # Character æ
+U+6199 Xi # Character æ
+U+619a Dan # Character æ
+U+619b Tan # Character æ
+U+619c Duo # Character æ
+U+619d Dui # Character æ
+U+619e Dui # Character æ
+U+619f Su # Character æ
+U+61a0 Jue # Character æ
+U+61a1 Ce # Character æ¡
+U+61a2 Xiao # Character æ¢
+U+61a3 Fan # Character æ£
+U+61a4 Fen # Character æ¤
+U+61a5 Lao # Character æ¥
+U+61a6 Lao # Character æ¦
+U+61a7 Chong # Character æ§
+U+61a8 Han # Character æ¨
+U+61a9 Qi # Character æ©
+U+61aa Xian # Character æª
+U+61ab Min # Character æ«
+U+61ac Jing # Character æ¬
+U+61ad Liao # Character æ
+U+61ae Wu # Character æ®
+U+61af Can # Character æ¯
+U+61b0 Jue # Character æ°
+U+61b1 Cu # Character æ±
+U+61b2 Xian # Character æ²
+U+61b3 Tan # Character æ³
+U+61b4 Sheng # Character æ´
+U+61b5 Pi # Character æµ
+U+61b6 Yi # Character æ¶
+U+61b7 Chu # Character æ·
+U+61b8 Xian # Character æ¸
+U+61b9 Nao # Character æ¹
+U+61ba Dan # Character æº
+U+61bb Tan # Character æ»
+U+61bc Jing # Character æ¼
+U+61bd Song # Character æ½
+U+61be Han # Character æ¾
+U+61bf Jiao # Character æ¿
+U+61c0 Wai # Character æ
+U+61c1 Huan # Character æ
+U+61c2 Dong # Character æ
+U+61c3 Qin # Character æ
+U+61c4 Qin # Character æ
+U+61c5 Qu # Character æ
+U+61c6 Cao # Character æ
+U+61c7 Ken # Character æ
+U+61c8 Xie # Character æ
+U+61c9 Ying # Character æ
+U+61ca Ao # Character æ
+U+61cb Mao # Character æ
+U+61cc Yi # Character æ
+U+61cd Lin # Character æ
+U+61ce Se # Character æ
+U+61cf Jun # Character æ
+U+61d0 Huai # Character æ
+U+61d1 Men # Character æ
+U+61d2 Lan # Character æ
+U+61d3 Ai # Character æ
+U+61d4 Lin # Character æ
+U+61d5 Yan # Character æ
+U+61d6 Gua # Character æ
+U+61d7 Xia # Character æ
+U+61d8 Chi # Character æ
+U+61d9 Yu # Character æ
+U+61da Yin # Character æ
+U+61db Dai # Character æ
+U+61dc Meng # Character æ
+U+61dd Ai # Character æ
+U+61de Meng # Character æ
+U+61df Dui # Character æ
+U+61e0 Qi # Character æ
+U+61e1 Mo # Character æ¡
+U+61e2 Lan # Character æ¢
+U+61e3 Men # Character æ£
+U+61e4 Chou # Character æ¤
+U+61e5 Zhi # Character æ¥
+U+61e6 Nuo # Character æ¦
+U+61e7 Nuo # Character æ§
+U+61e8 Yan # Character æ¨
+U+61e9 Yang # Character æ©
+U+61ea Bo # Character æª
+U+61eb Zhi # Character æ«
+U+61ec Kuang # Character æ¬
+U+61ed Kuang # Character æ
+U+61ee You # Character æ®
+U+61ef Fu # Character æ¯
+U+61f0 Liu # Character æ°
+U+61f1 Mie # Character æ±
+U+61f2 Cheng # Character æ²
+U+61f3 ? # Character æ³
+U+61f4 Chan # Character æ´
+U+61f5 Meng # Character æµ
+U+61f6 Lan # Character æ¶
+U+61f7 Huai # Character æ·
+U+61f8 Xuan # Character æ¸
+U+61f9 Rang # Character æ¹
+U+61fa Chan # Character æº
+U+61fb Ji # Character æ»
+U+61fc Ju # Character æ¼
+U+61fd Huan # Character æ½
+U+61fe She # Character æ¾
+U+61ff Yi # Character æ¿
diff --git a/resources/chars/ascii/row62.trans b/resources/chars/ascii/row62.trans
new file mode 100644
index 0000000..a2140fd
--- /dev/null
+++ b/resources/chars/ascii/row62.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+6200 Lian # Character æ
+U+6201 Nan # Character æ
+U+6202 Mi # Character æ
+U+6203 Tang # Character æ
+U+6204 Jue # Character æ
+U+6205 Gang # Character æ
+U+6206 Gang # Character æ
+U+6207 Gang # Character æ
+U+6208 Ge # Character æ
+U+6209 Yue # Character æ
+U+620a Wu # Character æ
+U+620b Jian # Character æ
+U+620c Xu # Character æ
+U+620d Shu # Character æ
+U+620e Rong # Character æ
+U+620f Xi # Character æ
+U+6210 Cheng # Character æ
+U+6211 Wo # Character æ
+U+6212 Jie # Character æ
+U+6213 Ge # Character æ
+U+6214 Jian # Character æ
+U+6215 Qiang # Character æ
+U+6216 Huo # Character æ
+U+6217 Qiang # Character æ
+U+6218 Zhan # Character æ
+U+6219 Dong # Character æ
+U+621a Qi # Character æ
+U+621b Jia # Character æ
+U+621c Die # Character æ
+U+621d Zei # Character æ
+U+621e Jia # Character æ
+U+621f Ji # Character æ
+U+6220 Shi # Character æ
+U+6221 Kan # Character æ¡
+U+6222 Ji # Character æ¢
+U+6223 Kui # Character æ£
+U+6224 Gai # Character æ¤
+U+6225 Deng # Character æ¥
+U+6226 Zhan # Character æ¦
+U+6227 Chuang # Character æ§
+U+6228 Ge # Character æ¨
+U+6229 Jian # Character æ©
+U+622a Jie # Character æª
+U+622b Yu # Character æ«
+U+622c Jian # Character æ¬
+U+622d Yan # Character æ
+U+622e Lu # Character æ®
+U+622f Xi # Character æ¯
+U+6230 Zhan # Character æ°
+U+6231 Xi # Character æ±
+U+6232 Xi # Character æ²
+U+6233 Chuo # Character æ³
+U+6234 Dai # Character æ´
+U+6235 Qu # Character æµ
+U+6236 Hu # Character æ¶
+U+6237 Hu # Character æ·
+U+6238 Hu # Character æ¸
+U+6239 E # Character æ¹
+U+623a Shi # Character æº
+U+623b Li # Character æ»
+U+623c Mao # Character æ¼
+U+623d Hu # Character æ½
+U+623e Li # Character æ¾
+U+623f Fang # Character æ¿
+U+6240 Suo # Character æ
+U+6241 Bian # Character æ
+U+6242 Dian # Character æ
+U+6243 Jiong # Character æ
+U+6244 Shang # Character æ
+U+6245 Yi # Character æ
+U+6246 Yi # Character æ
+U+6247 Shan # Character æ
+U+6248 Hu # Character æ
+U+6249 Fei # Character æ
+U+624a Yan # Character æ
+U+624b Shou # Character æ
+U+624c T # Character æ
+U+624d Cai # Character æ
+U+624e Zha # Character æ
+U+624f Qiu # Character æ
+U+6250 Le # Character æ
+U+6251 Bu # Character æ
+U+6252 Ba # Character æ
+U+6253 Da # Character æ
+U+6254 Reng # Character æ
+U+6255 Fu # Character æ
+U+6256 Hameru # Character æ
+U+6257 Zai # Character æ
+U+6258 Tuo # Character æ
+U+6259 Zhang # Character æ
+U+625a Diao # Character æ
+U+625b Kang # Character æ
+U+625c Yu # Character æ
+U+625d Ku # Character æ
+U+625e Han # Character æ
+U+625f Shen # Character æ
+U+6260 Cha # Character æ
+U+6261 Yi # Character æ¡
+U+6262 Gu # Character æ¢
+U+6263 Kou # Character æ£
+U+6264 Wu # Character æ¤
+U+6265 Tuo # Character æ¥
+U+6266 Qian # Character æ¦
+U+6267 Zhi # Character æ§
+U+6268 Ren # Character æ¨
+U+6269 Kuo # Character æ©
+U+626a Men # Character æª
+U+626b Sao # Character æ«
+U+626c Yang # Character æ¬
+U+626d Niu # Character æ
+U+626e Ban # Character æ®
+U+626f Che # Character æ¯
+U+6270 Rao # Character æ°
+U+6271 Xi # Character æ±
+U+6272 Qian # Character æ²
+U+6273 Ban # Character æ³
+U+6274 Jia # Character æ´
+U+6275 Yu # Character æµ
+U+6276 Fu # Character æ¶
+U+6277 Ao # Character æ·
+U+6278 Xi # Character æ¸
+U+6279 Pi # Character æ¹
+U+627a Zhi # Character æº
+U+627b Zi # Character æ»
+U+627c E # Character æ¼
+U+627d Dun # Character æ½
+U+627e Zhao # Character æ¾
+U+627f Cheng # Character æ¿
+U+6280 Ji # Character æ
+U+6281 Yan # Character æ
+U+6282 Kuang # Character æ
+U+6283 Bian # Character æ
+U+6284 Chao # Character æ
+U+6285 Ju # Character æ
+U+6286 Wen # Character æ
+U+6287 Hu # Character æ
+U+6288 Yue # Character æ
+U+6289 Jue # Character æ
+U+628a Ba # Character æ
+U+628b Qin # Character æ
+U+628c Zhen # Character æ
+U+628d Zheng # Character æ
+U+628e Yun # Character æ
+U+628f Wan # Character æ
+U+6290 Nu # Character æ
+U+6291 Yi # Character æ
+U+6292 Shu # Character æ
+U+6293 Zhua # Character æ
+U+6294 Pou # Character æ
+U+6295 Tou # Character æ
+U+6296 Dou # Character æ
+U+6297 Kang # Character æ
+U+6298 Zhe # Character æ
+U+6299 Pou # Character æ
+U+629a Fu # Character æ
+U+629b Pao # Character æ
+U+629c Ba # Character æ
+U+629d Ao # Character æ
+U+629e Ze # Character æ
+U+629f Tuan # Character æ
+U+62a0 Kou # Character æ
+U+62a1 Lun # Character æ¡
+U+62a2 Qiang # Character æ¢
+U+62a3 ? # Character æ£
+U+62a4 Hu # Character æ¤
+U+62a5 Bao # Character æ¥
+U+62a6 Bing # Character æ¦
+U+62a7 Zhi # Character æ§
+U+62a8 Peng # Character æ¨
+U+62a9 Tan # Character æ©
+U+62aa Pu # Character æª
+U+62ab Pi # Character æ«
+U+62ac Tai # Character æ¬
+U+62ad Yao # Character æ
+U+62ae Zhen # Character æ®
+U+62af Zha # Character æ¯
+U+62b0 Yang # Character æ°
+U+62b1 Bao # Character æ±
+U+62b2 He # Character æ²
+U+62b3 Ni # Character æ³
+U+62b4 Yi # Character æ´
+U+62b5 Di # Character æµ
+U+62b6 Chi # Character æ¶
+U+62b7 Pi # Character æ·
+U+62b8 Za # Character æ¸
+U+62b9 Mo # Character æ¹
+U+62ba Mo # Character æº
+U+62bb Shen # Character æ»
+U+62bc Ya # Character æ¼
+U+62bd Chou # Character æ½
+U+62be Qu # Character æ¾
+U+62bf Min # Character æ¿
+U+62c0 Chu # Character æ
+U+62c1 Jia # Character æ
+U+62c2 Fu # Character æ
+U+62c3 Zhan # Character æ
+U+62c4 Zhu # Character æ
+U+62c5 Dan # Character æ
+U+62c6 Chai # Character æ
+U+62c7 Mu # Character æ
+U+62c8 Nian # Character æ
+U+62c9 La # Character æ
+U+62ca Fu # Character æ
+U+62cb Pao # Character æ
+U+62cc Ban # Character æ
+U+62cd Pai # Character æ
+U+62ce Ling # Character æ
+U+62cf Na # Character æ
+U+62d0 Guai # Character æ
+U+62d1 Qian # Character æ
+U+62d2 Ju # Character æ
+U+62d3 Tuo # Character æ
+U+62d4 Ba # Character æ
+U+62d5 Tuo # Character æ
+U+62d6 Tuo # Character æ
+U+62d7 Ao # Character æ
+U+62d8 Ju # Character æ
+U+62d9 Zhuo # Character æ
+U+62da Pan # Character æ
+U+62db Zhao # Character æ
+U+62dc Bai # Character æ
+U+62dd Bai # Character æ
+U+62de Di # Character æ
+U+62df Ni # Character æ
+U+62e0 Ju # Character æ
+U+62e1 Kuo # Character æ¡
+U+62e2 Long # Character æ¢
+U+62e3 Jian # Character æ£
+U+62e4 ? # Character æ¤
+U+62e5 Yong # Character æ¥
+U+62e6 Lan # Character æ¦
+U+62e7 Ning # Character æ§
+U+62e8 Bo # Character æ¨
+U+62e9 Ze # Character æ©
+U+62ea Qian # Character æª
+U+62eb Hen # Character æ«
+U+62ec Gua # Character æ¬
+U+62ed Shi # Character æ
+U+62ee Jie # Character æ®
+U+62ef Zheng # Character æ¯
+U+62f0 Nin # Character æ°
+U+62f1 Gong # Character æ±
+U+62f2 Gong # Character æ²
+U+62f3 Quan # Character æ³
+U+62f4 Shuan # Character æ´
+U+62f5 Cun # Character æµ
+U+62f6 Zan # Character æ¶
+U+62f7 Kao # Character æ·
+U+62f8 Chi # Character æ¸
+U+62f9 Xie # Character æ¹
+U+62fa Ce # Character æº
+U+62fb Hui # Character æ»
+U+62fc Pin # Character æ¼
+U+62fd Zhuai # Character æ½
+U+62fe Shi # Character æ¾
+U+62ff Na # Character æ¿
diff --git a/resources/chars/ascii/row63.trans b/resources/chars/ascii/row63.trans
new file mode 100644
index 0000000..ee82a4a
--- /dev/null
+++ b/resources/chars/ascii/row63.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+6300 Bo # Character æ
+U+6301 Chi # Character æ
+U+6302 Gua # Character æ
+U+6303 Zhi # Character æ
+U+6304 Kuo # Character æ
+U+6305 Duo # Character æ
+U+6306 Duo # Character æ
+U+6307 Zhi # Character æ
+U+6308 Qie # Character æ
+U+6309 An # Character æ
+U+630a Nong # Character æ
+U+630b Zhen # Character æ
+U+630c Ge # Character æ
+U+630d Jiao # Character æ
+U+630e Ku # Character æ
+U+630f Dong # Character æ
+U+6310 Ru # Character æ
+U+6311 Tiao # Character æ
+U+6312 Lie # Character æ
+U+6313 Zha # Character æ
+U+6314 Lu # Character æ
+U+6315 Die # Character æ
+U+6316 Wa # Character æ
+U+6317 Jue # Character æ
+U+6318 Mushiru # Character æ
+U+6319 Ju # Character æ
+U+631a Zhi # Character æ
+U+631b Luan # Character æ
+U+631c Ya # Character æ
+U+631d Zhua # Character æ
+U+631e Ta # Character æ
+U+631f Xie # Character æ
+U+6320 Nao # Character æ
+U+6321 Dang # Character æ¡
+U+6322 Jiao # Character æ¢
+U+6323 Zheng # Character æ£
+U+6324 Ji # Character æ¤
+U+6325 Hui # Character æ¥
+U+6326 Xun # Character æ¦
+U+6327 Ku # Character æ§
+U+6328 Ai # Character æ¨
+U+6329 Tuo # Character æ©
+U+632a Nuo # Character æª
+U+632b Cuo # Character æ«
+U+632c Bo # Character æ¬
+U+632d Geng # Character æ
+U+632e Ti # Character æ®
+U+632f Zhen # Character æ¯
+U+6330 Cheng # Character æ°
+U+6331 Suo # Character æ±
+U+6332 Suo # Character æ²
+U+6333 Keng # Character æ³
+U+6334 Mei # Character æ´
+U+6335 Long # Character æµ
+U+6336 Ju # Character æ¶
+U+6337 Peng # Character æ·
+U+6338 Jian # Character æ¸
+U+6339 Yi # Character æ¹
+U+633a Ting # Character æº
+U+633b Shan # Character æ»
+U+633c Nuo # Character æ¼
+U+633d Wan # Character æ½
+U+633e Xie # Character æ¾
+U+633f Cha # Character æ¿
+U+6340 Feng # Character æ
+U+6341 Jiao # Character æ
+U+6342 Wu # Character æ
+U+6343 Jun # Character æ
+U+6344 Jiu # Character æ
+U+6345 Tong # Character æ
+U+6346 Kun # Character æ
+U+6347 Huo # Character æ
+U+6348 Tu # Character æ
+U+6349 Zhuo # Character æ
+U+634a Pou # Character æ
+U+634b Le # Character æ
+U+634c Ba # Character æ
+U+634d Han # Character æ
+U+634e Shao # Character æ
+U+634f Nie # Character æ
+U+6350 Juan # Character æ
+U+6351 Ze # Character æ
+U+6352 Song # Character æ
+U+6353 Ye # Character æ
+U+6354 Jue # Character æ
+U+6355 Bu # Character æ
+U+6356 Huan # Character æ
+U+6357 Bu # Character æ
+U+6358 Zun # Character æ
+U+6359 Yi # Character æ
+U+635a Zhai # Character æ
+U+635b Lu # Character æ
+U+635c Sou # Character æ
+U+635d Tuo # Character æ
+U+635e Lao # Character æ
+U+635f Sun # Character æ
+U+6360 Bang # Character æ
+U+6361 Jian # Character æ¡
+U+6362 Huan # Character æ¢
+U+6363 Dao # Character æ£
+U+6364 ? # Character æ¤
+U+6365 Wan # Character æ¥
+U+6366 Qin # Character æ¦
+U+6367 Peng # Character æ§
+U+6368 She # Character æ¨
+U+6369 Lie # Character æ©
+U+636a Min # Character æª
+U+636b Men # Character æ«
+U+636c Fu # Character æ¬
+U+636d Bai # Character æ
+U+636e Ju # Character æ®
+U+636f Dao # Character æ¯
+U+6370 Wo # Character æ°
+U+6371 Ai # Character æ±
+U+6372 Juan # Character æ²
+U+6373 Yue # Character æ³
+U+6374 Zong # Character æ´
+U+6375 Chen # Character æµ
+U+6376 Chui # Character æ¶
+U+6377 Jie # Character æ·
+U+6378 Tu # Character æ¸
+U+6379 Ben # Character æ¹
+U+637a Na # Character æº
+U+637b Nian # Character æ»
+U+637c Nuo # Character æ¼
+U+637d Zu # Character æ½
+U+637e Wo # Character æ¾
+U+637f Xi # Character æ¿
+U+6380 Xian # Character æ
+U+6381 Cheng # Character æ
+U+6382 Dian # Character æ
+U+6383 Sao # Character æ
+U+6384 Lun # Character æ
+U+6385 Qing # Character æ
+U+6386 Gang # Character æ
+U+6387 Duo # Character æ
+U+6388 Shou # Character æ
+U+6389 Diao # Character æ
+U+638a Pou # Character æ
+U+638b Di # Character æ
+U+638c Zhang # Character æ
+U+638d Gun # Character æ
+U+638e Ji # Character æ
+U+638f Tao # Character æ
+U+6390 Qia # Character æ
+U+6391 Qi # Character æ
+U+6392 Pai # Character æ
+U+6393 Shu # Character æ
+U+6394 Qian # Character æ
+U+6395 Ling # Character æ
+U+6396 Yi # Character æ
+U+6397 Ya # Character æ
+U+6398 Jue # Character æ
+U+6399 Zheng # Character æ
+U+639a Liang # Character æ
+U+639b Gua # Character æ
+U+639c Yi # Character æ
+U+639d Huo # Character æ
+U+639e Shan # Character æ
+U+639f Zheng # Character æ
+U+63a0 Lue # Character æ
+U+63a1 Cai # Character æ¡
+U+63a2 Tan # Character æ¢
+U+63a3 Che # Character æ£
+U+63a4 Bing # Character æ¤
+U+63a5 Jie # Character æ¥
+U+63a6 Ti # Character æ¦
+U+63a7 Kong # Character æ§
+U+63a8 Tui # Character æ¨
+U+63a9 Yan # Character æ©
+U+63aa Cuo # Character æª
+U+63ab Zou # Character æ«
+U+63ac Ju # Character æ¬
+U+63ad Tian # Character æ
+U+63ae Qian # Character æ®
+U+63af Ken # Character æ¯
+U+63b0 Bai # Character æ°
+U+63b1 Shou # Character æ±
+U+63b2 Jie # Character æ²
+U+63b3 Lu # Character æ³
+U+63b4 Guo # Character æ´
+U+63b5 Haba # Character æµ
+U+63b6 ? # Character æ¶
+U+63b7 Zhi # Character æ·
+U+63b8 Dan # Character æ¸
+U+63b9 Mang # Character æ¹
+U+63ba Xian # Character æº
+U+63bb Sao # Character æ»
+U+63bc Guan # Character æ¼
+U+63bd Peng # Character æ½
+U+63be Yuan # Character æ¾
+U+63bf Nuo # Character æ¿
+U+63c0 Jian # Character æ
+U+63c1 Zhen # Character æ
+U+63c2 Jiu # Character æ
+U+63c3 Jian # Character æ
+U+63c4 Yu # Character æ
+U+63c5 Yan # Character æ
+U+63c6 Kui # Character æ
+U+63c7 Nan # Character æ
+U+63c8 Hong # Character æ
+U+63c9 Rou # Character æ
+U+63ca Pi # Character æ
+U+63cb Wei # Character æ
+U+63cc Sai # Character æ
+U+63cd Zou # Character æ
+U+63ce Xuan # Character æ
+U+63cf Miao # Character æ
+U+63d0 Ti # Character æ
+U+63d1 Nie # Character æ
+U+63d2 Cha # Character æ
+U+63d3 Shi # Character æ
+U+63d4 Zong # Character æ
+U+63d5 Zhen # Character æ
+U+63d6 Yi # Character æ
+U+63d7 Shun # Character æ
+U+63d8 Heng # Character æ
+U+63d9 Bian # Character æ
+U+63da Yang # Character æ
+U+63db Huan # Character æ
+U+63dc Yan # Character æ
+U+63dd Zuan # Character æ
+U+63de An # Character æ
+U+63df Xu # Character æ
+U+63e0 Ya # Character æ
+U+63e1 Wo # Character æ¡
+U+63e2 Ke # Character æ¢
+U+63e3 Chuai # Character æ£
+U+63e4 Ji # Character æ¤
+U+63e5 Ti # Character æ¥
+U+63e6 La # Character æ¦
+U+63e7 La # Character æ§
+U+63e8 Cheng # Character æ¨
+U+63e9 Kai # Character æ©
+U+63ea Jiu # Character æª
+U+63eb Jiu # Character æ«
+U+63ec Tu # Character æ¬
+U+63ed Jie # Character æ
+U+63ee Hui # Character æ®
+U+63ef Geng # Character æ¯
+U+63f0 Chong # Character æ°
+U+63f1 Shuo # Character æ±
+U+63f2 She # Character æ²
+U+63f3 Xie # Character æ³
+U+63f4 Yuan # Character æ´
+U+63f5 Qian # Character æµ
+U+63f6 Ye # Character æ¶
+U+63f7 Cha # Character æ·
+U+63f8 Zha # Character æ¸
+U+63f9 Bei # Character æ¹
+U+63fa Yao # Character æº
+U+63fb ? # Character æ»
+U+63fc ? # Character æ¼
+U+63fd Lan # Character æ½
+U+63fe Wen # Character æ¾
+U+63ff Qin # Character æ¿
diff --git a/resources/chars/ascii/row64.trans b/resources/chars/ascii/row64.trans
new file mode 100644
index 0000000..e6ea61f
--- /dev/null
+++ b/resources/chars/ascii/row64.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+6400 Chan # Character æ
+U+6401 Ge # Character æ
+U+6402 Lou # Character æ
+U+6403 Zong # Character æ
+U+6404 Geng # Character æ
+U+6405 Jiao # Character æ
+U+6406 Gou # Character æ
+U+6407 Qin # Character æ
+U+6408 Yong # Character æ
+U+6409 Que # Character æ
+U+640a Chou # Character æ
+U+640b Chi # Character æ
+U+640c Zhan # Character æ
+U+640d Sun # Character æ
+U+640e Sun # Character æ
+U+640f Bo # Character æ
+U+6410 Chu # Character æ
+U+6411 Rong # Character æ
+U+6412 Beng # Character æ
+U+6413 Cuo # Character æ
+U+6414 Sao # Character æ
+U+6415 Ke # Character æ
+U+6416 Yao # Character æ
+U+6417 Dao # Character æ
+U+6418 Zhi # Character æ
+U+6419 Nu # Character æ
+U+641a Xie # Character æ
+U+641b Jian # Character æ
+U+641c Sou # Character æ
+U+641d Qiu # Character æ
+U+641e Gao # Character æ
+U+641f Xian # Character æ
+U+6420 Shuo # Character æ
+U+6421 Sang # Character æ¡
+U+6422 Jin # Character æ¢
+U+6423 Mie # Character æ£
+U+6424 E # Character æ¤
+U+6425 Chui # Character æ¥
+U+6426 Nuo # Character æ¦
+U+6427 Shan # Character æ§
+U+6428 Ta # Character æ¨
+U+6429 Jie # Character æ©
+U+642a Tang # Character æª
+U+642b Pan # Character æ«
+U+642c Ban # Character æ¬
+U+642d Da # Character æ
+U+642e Li # Character æ®
+U+642f Tao # Character æ¯
+U+6430 Hu # Character æ°
+U+6431 Zhi # Character æ±
+U+6432 Wa # Character æ²
+U+6433 Xia # Character æ³
+U+6434 Qian # Character æ´
+U+6435 Wen # Character æµ
+U+6436 Qiang # Character æ¶
+U+6437 Tian # Character æ·
+U+6438 Zhen # Character æ¸
+U+6439 E # Character æ¹
+U+643a Xi # Character æº
+U+643b Nuo # Character æ»
+U+643c Quan # Character æ¼
+U+643d Cha # Character æ½
+U+643e Zha # Character æ¾
+U+643f Ge # Character æ¿
+U+6440 Wu # Character æ
+U+6441 En # Character æ
+U+6442 She # Character æ
+U+6443 Kang # Character æ
+U+6444 She # Character æ
+U+6445 Shu # Character æ
+U+6446 Bai # Character æ
+U+6447 Yao # Character æ
+U+6448 Bin # Character æ
+U+6449 Sou # Character æ
+U+644a Tan # Character æ
+U+644b Sa # Character æ
+U+644c Chan # Character æ
+U+644d Suo # Character æ
+U+644e Liao # Character æ
+U+644f Chong # Character æ
+U+6450 Chuang # Character æ
+U+6451 Guo # Character æ
+U+6452 Bing # Character æ
+U+6453 Feng # Character æ
+U+6454 Shuai # Character æ
+U+6455 Di # Character æ
+U+6456 Qi # Character æ
+U+6457 Sou # Character æ
+U+6458 Zhai # Character æ
+U+6459 Lian # Character æ
+U+645a Tang # Character æ
+U+645b Chi # Character æ
+U+645c Guan # Character æ
+U+645d Lu # Character æ
+U+645e Luo # Character æ
+U+645f Lou # Character æ
+U+6460 Zong # Character æ
+U+6461 Gai # Character æ¡
+U+6462 Hu # Character æ¢
+U+6463 Zha # Character æ£
+U+6464 Chuang # Character æ¤
+U+6465 Tang # Character æ¥
+U+6466 Hua # Character æ¦
+U+6467 Cui # Character æ§
+U+6468 Nai # Character æ¨
+U+6469 Mo # Character æ©
+U+646a Jiang # Character æª
+U+646b Gui # Character æ«
+U+646c Ying # Character æ¬
+U+646d Zhi # Character æ
+U+646e Ao # Character æ®
+U+646f Zhi # Character æ¯
+U+6470 Nie # Character æ°
+U+6471 Man # Character æ±
+U+6472 Shan # Character æ²
+U+6473 Kou # Character æ³
+U+6474 Shu # Character æ´
+U+6475 Suo # Character æµ
+U+6476 Tuan # Character æ¶
+U+6477 Jiao # Character æ·
+U+6478 Mo # Character æ¸
+U+6479 Mo # Character æ¹
+U+647a Zhe # Character æº
+U+647b Xian # Character æ»
+U+647c Keng # Character æ¼
+U+647d Piao # Character æ½
+U+647e Jiang # Character æ¾
+U+647f Yin # Character æ¿
+U+6480 Gou # Character æ
+U+6481 Qian # Character æ
+U+6482 Lue # Character æ
+U+6483 Ji # Character æ
+U+6484 Ying # Character æ
+U+6485 Jue # Character æ
+U+6486 Pie # Character æ
+U+6487 Pie # Character æ
+U+6488 Lao # Character æ
+U+6489 Dun # Character æ
+U+648a Xian # Character æ
+U+648b Ruan # Character æ
+U+648c Kui # Character æ
+U+648d Zan # Character æ
+U+648e Yi # Character æ
+U+648f Xun # Character æ
+U+6490 Cheng # Character æ
+U+6491 Cheng # Character æ
+U+6492 Sa # Character æ
+U+6493 Nao # Character æ
+U+6494 Heng # Character æ
+U+6495 Si # Character æ
+U+6496 Qian # Character æ
+U+6497 Huang # Character æ
+U+6498 Da # Character æ
+U+6499 Zun # Character æ
+U+649a Nian # Character æ
+U+649b Lin # Character æ
+U+649c Zheng # Character æ
+U+649d Hui # Character æ
+U+649e Zhuang # Character æ
+U+649f Jiao # Character æ
+U+64a0 Ji # Character æ
+U+64a1 Cao # Character æ¡
+U+64a2 Dan # Character æ¢
+U+64a3 Dan # Character æ£
+U+64a4 Che # Character æ¤
+U+64a5 Bo # Character æ¥
+U+64a6 Che # Character æ¦
+U+64a7 Jue # Character æ§
+U+64a8 Xiao # Character æ¨
+U+64a9 Liao # Character æ©
+U+64aa Ben # Character æª
+U+64ab Fu # Character æ«
+U+64ac Qiao # Character æ¬
+U+64ad Bo # Character æ
+U+64ae Cuo # Character æ®
+U+64af Zhuo # Character æ¯
+U+64b0 Zhuan # Character æ°
+U+64b1 Tuo # Character æ±
+U+64b2 Pu # Character æ²
+U+64b3 Qin # Character æ³
+U+64b4 Dun # Character æ´
+U+64b5 Nian # Character æµ
+U+64b6 ? # Character æ¶
+U+64b7 Xie # Character æ·
+U+64b8 Lu # Character æ¸
+U+64b9 Jiao # Character æ¹
+U+64ba Cuan # Character æº
+U+64bb Ta # Character æ»
+U+64bc Han # Character æ¼
+U+64bd Qiao # Character æ½
+U+64be Zhua # Character æ¾
+U+64bf Jian # Character æ¿
+U+64c0 Gan # Character æ
+U+64c1 Yong # Character æ
+U+64c2 Lei # Character æ
+U+64c3 Kuo # Character æ
+U+64c4 Lu # Character æ
+U+64c5 Shan # Character æ
+U+64c6 Zhuo # Character æ
+U+64c7 Ze # Character æ
+U+64c8 Pu # Character æ
+U+64c9 Chuo # Character æ
+U+64ca Ji # Character æ
+U+64cb Dang # Character æ
+U+64cc Suo # Character æ
+U+64cd Cao # Character æ
+U+64ce Qing # Character æ
+U+64cf Jing # Character æ
+U+64d0 Huan # Character æ
+U+64d1 Jie # Character æ
+U+64d2 Qin # Character æ
+U+64d3 Kuai # Character æ
+U+64d4 Dan # Character æ
+U+64d5 Xi # Character æ
+U+64d6 Ge # Character æ
+U+64d7 Pi # Character æ
+U+64d8 Bo # Character æ
+U+64d9 Ao # Character æ
+U+64da Ju # Character æ
+U+64db Ye # Character æ
+U+64dc ? # Character æ
+U+64dd Mang # Character æ
+U+64de Sou # Character æ
+U+64df Mi # Character æ
+U+64e0 Ji # Character æ
+U+64e1 Tai # Character æ¡
+U+64e2 Zhuo # Character æ¢
+U+64e3 Dao # Character æ£
+U+64e4 Xing # Character æ¤
+U+64e5 Lan # Character æ¥
+U+64e6 Ca # Character æ¦
+U+64e7 Ju # Character æ§
+U+64e8 Ye # Character æ¨
+U+64e9 Ru # Character æ©
+U+64ea Ye # Character æª
+U+64eb Ye # Character æ«
+U+64ec Ni # Character æ¬
+U+64ed Hu # Character æ
+U+64ee Ji # Character æ®
+U+64ef Bin # Character æ¯
+U+64f0 Ning # Character æ°
+U+64f1 Ge # Character æ±
+U+64f2 Zhi # Character æ²
+U+64f3 Jie # Character æ³
+U+64f4 Kuo # Character æ´
+U+64f5 Mo # Character æµ
+U+64f6 Jian # Character æ¶
+U+64f7 Xie # Character æ·
+U+64f8 Lie # Character æ¸
+U+64f9 Tan # Character æ¹
+U+64fa Bai # Character æº
+U+64fb Sou # Character æ»
+U+64fc Lu # Character æ¼
+U+64fd Lue # Character æ½
+U+64fe Rao # Character æ¾
+U+64ff Zhi # Character æ¿
diff --git a/resources/chars/ascii/row65.trans b/resources/chars/ascii/row65.trans
new file mode 100644
index 0000000..077cf87
--- /dev/null
+++ b/resources/chars/ascii/row65.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+6500 Pan # Character æ
+U+6501 Yang # Character æ
+U+6502 Lei # Character æ
+U+6503 Sa # Character æ
+U+6504 Shu # Character æ
+U+6505 Zan # Character æ
+U+6506 Nian # Character æ
+U+6507 Xian # Character æ
+U+6508 Jun # Character æ
+U+6509 Huo # Character æ
+U+650a Li # Character æ
+U+650b La # Character æ
+U+650c Han # Character æ
+U+650d Ying # Character æ
+U+650e Lu # Character æ
+U+650f Long # Character æ
+U+6510 Qian # Character æ
+U+6511 Qian # Character æ
+U+6512 Zan # Character æ
+U+6513 Qian # Character æ
+U+6514 Lan # Character æ
+U+6515 San # Character æ
+U+6516 Ying # Character æ
+U+6517 Mei # Character æ
+U+6518 Rang # Character æ
+U+6519 Chan # Character æ
+U+651a ? # Character æ
+U+651b Cuan # Character æ
+U+651c Xi # Character æ
+U+651d She # Character æ
+U+651e Luo # Character æ
+U+651f Jun # Character æ
+U+6520 Mi # Character æ
+U+6521 Li # Character æ¡
+U+6522 Zan # Character æ¢
+U+6523 Luan # Character æ£
+U+6524 Tan # Character æ¤
+U+6525 Zuan # Character æ¥
+U+6526 Li # Character æ¦
+U+6527 Dian # Character æ§
+U+6528 Wa # Character æ¨
+U+6529 Dang # Character æ©
+U+652a Jiao # Character æª
+U+652b Jue # Character æ«
+U+652c Lan # Character æ¬
+U+652d Li # Character æ
+U+652e Nang # Character æ®
+U+652f Zhi # Character æ¯
+U+6530 Gui # Character æ°
+U+6531 Gui # Character æ±
+U+6532 Qi # Character æ²
+U+6533 Xin # Character æ³
+U+6534 Pu # Character æ´
+U+6535 Sui # Character æµ
+U+6536 Shou # Character æ¶
+U+6537 Kao # Character æ·
+U+6538 You # Character æ¸
+U+6539 Gai # Character æ¹
+U+653a Yi # Character æº
+U+653b Gong # Character æ»
+U+653c Gan # Character æ¼
+U+653d Ban # Character æ½
+U+653e Fang # Character æ¾
+U+653f Zheng # Character æ¿
+U+6540 Bo # Character æ
+U+6541 Dian # Character æ
+U+6542 Kou # Character æ
+U+6543 Min # Character æ
+U+6544 Wu # Character æ
+U+6545 Gu # Character æ
+U+6546 He # Character æ
+U+6547 Ce # Character æ
+U+6548 Xiao # Character æ
+U+6549 Mi # Character æ
+U+654a Chu # Character æ
+U+654b Ge # Character æ
+U+654c Di # Character æ
+U+654d Xu # Character æ
+U+654e Jiao # Character æ
+U+654f Min # Character æ
+U+6550 Chen # Character æ
+U+6551 Jiu # Character æ
+U+6552 Zhen # Character æ
+U+6553 Duo # Character æ
+U+6554 Yu # Character æ
+U+6555 Chi # Character æ
+U+6556 Ao # Character æ
+U+6557 Bai # Character æ
+U+6558 Xu # Character æ
+U+6559 Jiao # Character æ
+U+655a Duo # Character æ
+U+655b Lian # Character æ
+U+655c Nie # Character æ
+U+655d Bi # Character æ
+U+655e Chang # Character æ
+U+655f Dian # Character æ
+U+6560 Duo # Character æ
+U+6561 Yi # Character æ¡
+U+6562 Gan # Character æ¢
+U+6563 San # Character æ£
+U+6564 Ke # Character æ¤
+U+6565 Yan # Character æ¥
+U+6566 Dun # Character æ¦
+U+6567 Qi # Character æ§
+U+6568 Dou # Character æ¨
+U+6569 Xiao # Character æ©
+U+656a Duo # Character æª
+U+656b Jiao # Character æ«
+U+656c Jing # Character æ¬
+U+656d Yang # Character æ
+U+656e Xia # Character æ®
+U+656f Min # Character æ¯
+U+6570 Shu # Character æ°
+U+6571 Ai # Character æ±
+U+6572 Qiao # Character æ²
+U+6573 Ai # Character æ³
+U+6574 Zheng # Character æ´
+U+6575 Di # Character æµ
+U+6576 Zhen # Character æ¶
+U+6577 Fu # Character æ·
+U+6578 Shu # Character æ¸
+U+6579 Liao # Character æ¹
+U+657a Qu # Character æº
+U+657b Xiong # Character æ»
+U+657c Xi # Character æ¼
+U+657d Jiao # Character æ½
+U+657e Sen # Character æ¾
+U+657f Jiao # Character æ¿
+U+6580 Zhuo # Character æ
+U+6581 Yi # Character æ
+U+6582 Lian # Character æ
+U+6583 Bi # Character æ
+U+6584 Li # Character æ
+U+6585 Xiao # Character æ
+U+6586 Xiao # Character æ
+U+6587 Wen # Character æ
+U+6588 Xue # Character æ
+U+6589 Qi # Character æ
+U+658a Qi # Character æ
+U+658b Zhai # Character æ
+U+658c Bin # Character æ
+U+658d Jue # Character æ
+U+658e Zhai # Character æ
+U+658f ? # Character æ
+U+6590 Fei # Character æ
+U+6591 Ban # Character æ
+U+6592 Ban # Character æ
+U+6593 Lan # Character æ
+U+6594 Yu # Character æ
+U+6595 Lan # Character æ
+U+6596 Wei # Character æ
+U+6597 Dou # Character æ
+U+6598 Sheng # Character æ
+U+6599 Liao # Character æ
+U+659a Jia # Character æ
+U+659b Hu # Character æ
+U+659c Xie # Character æ
+U+659d Jia # Character æ
+U+659e Yu # Character æ
+U+659f Zhen # Character æ
+U+65a0 Jiao # Character æ
+U+65a1 Wo # Character æ¡
+U+65a2 Tou # Character æ¢
+U+65a3 Chu # Character æ£
+U+65a4 Jin # Character æ¤
+U+65a5 Chi # Character æ¥
+U+65a6 Yin # Character æ¦
+U+65a7 Fu # Character æ§
+U+65a8 Qiang # Character æ¨
+U+65a9 Zhan # Character æ©
+U+65aa Qu # Character æª
+U+65ab Zhuo # Character æ«
+U+65ac Zhan # Character æ¬
+U+65ad Duan # Character æ
+U+65ae Zhuo # Character æ®
+U+65af Si # Character æ¯
+U+65b0 Xin # Character æ°
+U+65b1 Zhuo # Character æ±
+U+65b2 Zhuo # Character æ²
+U+65b3 Qin # Character æ³
+U+65b4 Lin # Character æ´
+U+65b5 Zhuo # Character æµ
+U+65b6 Chu # Character æ¶
+U+65b7 Duan # Character æ·
+U+65b8 Zhu # Character æ¸
+U+65b9 Fang # Character æ¹
+U+65ba Xie # Character æº
+U+65bb Hang # Character æ»
+U+65bc Yu # Character æ¼
+U+65bd Shi # Character æ½
+U+65be Pei # Character æ¾
+U+65bf You # Character æ¿
+U+65c0 Mye # Character æ
+U+65c1 Pang # Character æ
+U+65c2 Qi # Character æ
+U+65c3 Zhan # Character æ
+U+65c4 Mao # Character æ
+U+65c5 Lu # Character æ
+U+65c6 Pei # Character æ
+U+65c7 Pi # Character æ
+U+65c8 Liu # Character æ
+U+65c9 Fu # Character æ
+U+65ca Fang # Character æ
+U+65cb Xuan # Character æ
+U+65cc Jing # Character æ
+U+65cd Jing # Character æ
+U+65ce Ni # Character æ
+U+65cf Zu # Character æ
+U+65d0 Zhao # Character æ
+U+65d1 Yi # Character æ
+U+65d2 Liu # Character æ
+U+65d3 Shao # Character æ
+U+65d4 Jian # Character æ
+U+65d5 Es # Character æ
+U+65d6 Yi # Character æ
+U+65d7 Qi # Character æ
+U+65d8 Zhi # Character æ
+U+65d9 Fan # Character æ
+U+65da Piao # Character æ
+U+65db Fan # Character æ
+U+65dc Zhan # Character æ
+U+65dd Guai # Character æ
+U+65de Sui # Character æ
+U+65df Yu # Character æ
+U+65e0 Wu # Character æ
+U+65e1 Ji # Character æ¡
+U+65e2 Ji # Character æ¢
+U+65e3 Ji # Character æ£
+U+65e4 Huo # Character æ¤
+U+65e5 Ri # Character æ¥
+U+65e6 Dan # Character æ¦
+U+65e7 Jiu # Character æ§
+U+65e8 Zhi # Character æ¨
+U+65e9 Zao # Character æ©
+U+65ea Xie # Character æª
+U+65eb Tiao # Character æ«
+U+65ec Xun # Character æ¬
+U+65ed Xu # Character æ
+U+65ee Xu # Character æ®
+U+65ef Xu # Character æ¯
+U+65f0 Gan # Character æ°
+U+65f1 Han # Character æ±
+U+65f2 Tai # Character æ²
+U+65f3 Di # Character æ³
+U+65f4 Xu # Character æ´
+U+65f5 Chan # Character æµ
+U+65f6 Shi # Character æ¶
+U+65f7 Kuang # Character æ·
+U+65f8 Yang # Character æ¸
+U+65f9 Shi # Character æ¹
+U+65fa Wang # Character æº
+U+65fb Min # Character æ»
+U+65fc Min # Character æ¼
+U+65fd Tun # Character æ½
+U+65fe Chun # Character æ¾
+U+65ff Wu # Character æ¿
diff --git a/resources/chars/ascii/row66.trans b/resources/chars/ascii/row66.trans
new file mode 100644
index 0000000..c841999
--- /dev/null
+++ b/resources/chars/ascii/row66.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+6600 Yun # Character æ
+U+6601 Bei # Character æ
+U+6602 Ang # Character æ
+U+6603 Ze # Character æ
+U+6604 Ban # Character æ
+U+6605 Jie # Character æ
+U+6606 Kun # Character æ
+U+6607 Sheng # Character æ
+U+6608 Hu # Character æ
+U+6609 Fang # Character æ
+U+660a Hao # Character æ
+U+660b Gui # Character æ
+U+660c Chang # Character æ
+U+660d Xuan # Character æ
+U+660e Ming # Character æ
+U+660f Hun # Character æ
+U+6610 Fen # Character æ
+U+6611 Qin # Character æ
+U+6612 Hu # Character æ
+U+6613 Yi # Character æ
+U+6614 Xi # Character æ
+U+6615 Xin # Character æ
+U+6616 Yan # Character æ
+U+6617 Ze # Character æ
+U+6618 Fang # Character æ
+U+6619 Tan # Character æ
+U+661a Shen # Character æ
+U+661b Ju # Character æ
+U+661c Yang # Character æ
+U+661d Zan # Character æ
+U+661e Bing # Character æ
+U+661f Xing # Character æ
+U+6620 Ying # Character æ
+U+6621 Xuan # Character æ¡
+U+6622 Pei # Character æ¢
+U+6623 Zhen # Character æ£
+U+6624 Ling # Character æ¤
+U+6625 Chun # Character æ¥
+U+6626 Hao # Character æ¦
+U+6627 Mei # Character æ§
+U+6628 Zuo # Character æ¨
+U+6629 Mo # Character æ©
+U+662a Bian # Character æª
+U+662b Xu # Character æ«
+U+662c Hun # Character æ¬
+U+662d Zhao # Character æ
+U+662e Zong # Character æ®
+U+662f Shi # Character æ¯
+U+6630 Shi # Character æ°
+U+6631 Yu # Character æ±
+U+6632 Fei # Character æ²
+U+6633 Die # Character æ³
+U+6634 Mao # Character æ´
+U+6635 Ni # Character æµ
+U+6636 Chang # Character æ¶
+U+6637 Wen # Character æ·
+U+6638 Dong # Character æ¸
+U+6639 Ai # Character æ¹
+U+663a Bing # Character æº
+U+663b Ang # Character æ»
+U+663c Zhou # Character æ¼
+U+663d Long # Character æ½
+U+663e Xian # Character æ¾
+U+663f Kuang # Character æ¿
+U+6640 Tiao # Character æ
+U+6641 Chao # Character æ
+U+6642 Shi # Character æ
+U+6643 Huang # Character æ
+U+6644 Huang # Character æ
+U+6645 Xuan # Character æ
+U+6646 Kui # Character æ
+U+6647 Xu # Character æ
+U+6648 Jiao # Character æ
+U+6649 Jin # Character æ
+U+664a Zhi # Character æ
+U+664b Jin # Character æ
+U+664c Shang # Character æ
+U+664d Tong # Character æ
+U+664e Hong # Character æ
+U+664f Yan # Character æ
+U+6650 Gai # Character æ
+U+6651 Xiang # Character æ
+U+6652 Shai # Character æ
+U+6653 Xiao # Character æ
+U+6654 Ye # Character æ
+U+6655 Yun # Character æ
+U+6656 Hui # Character æ
+U+6657 Han # Character æ
+U+6658 Han # Character æ
+U+6659 Jun # Character æ
+U+665a Wan # Character æ
+U+665b Xian # Character æ
+U+665c Kun # Character æ
+U+665d Zhou # Character æ
+U+665e Xi # Character æ
+U+665f Cheng # Character æ
+U+6660 Sheng # Character æ
+U+6661 Bu # Character æ¡
+U+6662 Zhe # Character æ¢
+U+6663 Zhe # Character æ£
+U+6664 Wu # Character æ¤
+U+6665 Han # Character æ¥
+U+6666 Hui # Character æ¦
+U+6667 Hao # Character æ§
+U+6668 Chen # Character æ¨
+U+6669 Wan # Character æ©
+U+666a Tian # Character æª
+U+666b Zhuo # Character æ«
+U+666c Zui # Character æ¬
+U+666d Zhou # Character æ
+U+666e Pu # Character æ®
+U+666f Jing # Character æ¯
+U+6670 Xi # Character æ°
+U+6671 Shan # Character æ±
+U+6672 Yi # Character æ²
+U+6673 Xi # Character æ³
+U+6674 Qing # Character æ´
+U+6675 Qi # Character æµ
+U+6676 Jing # Character æ¶
+U+6677 Gui # Character æ·
+U+6678 Zhen # Character æ¸
+U+6679 Yi # Character æ¹
+U+667a Zhi # Character æº
+U+667b An # Character æ»
+U+667c Wan # Character æ¼
+U+667d Lin # Character æ½
+U+667e Liang # Character æ¾
+U+667f Chang # Character æ¿
+U+6680 Wang # Character æ
+U+6681 Xiao # Character æ
+U+6682 Zan # Character æ
+U+6683 Hi # Character æ
+U+6684 Xuan # Character æ
+U+6685 Xuan # Character æ
+U+6686 Yi # Character æ
+U+6687 Xia # Character æ
+U+6688 Yun # Character æ
+U+6689 Hui # Character æ
+U+668a Fu # Character æ
+U+668b Min # Character æ
+U+668c Kui # Character æ
+U+668d He # Character æ
+U+668e Ying # Character æ
+U+668f Du # Character æ
+U+6690 Wei # Character æ
+U+6691 Shu # Character æ
+U+6692 Qing # Character æ
+U+6693 Mao # Character æ
+U+6694 Nan # Character æ
+U+6695 Jian # Character æ
+U+6696 Nuan # Character æ
+U+6697 An # Character æ
+U+6698 Yang # Character æ
+U+6699 Chun # Character æ
+U+669a Yao # Character æ
+U+669b Suo # Character æ
+U+669c Jin # Character æ
+U+669d Ming # Character æ
+U+669e Jiao # Character æ
+U+669f Kai # Character æ
+U+66a0 Gao # Character æ
+U+66a1 Weng # Character æ¡
+U+66a2 Chang # Character æ¢
+U+66a3 Qi # Character æ£
+U+66a4 Hao # Character æ¤
+U+66a5 Yan # Character æ¥
+U+66a6 Li # Character æ¦
+U+66a7 Ai # Character æ§
+U+66a8 Ji # Character æ¨
+U+66a9 Gui # Character æ©
+U+66aa Men # Character æª
+U+66ab Zan # Character æ«
+U+66ac Xie # Character æ¬
+U+66ad Hao # Character æ
+U+66ae Mu # Character æ®
+U+66af Mo # Character æ¯
+U+66b0 Cong # Character æ°
+U+66b1 Ni # Character æ±
+U+66b2 Zhang # Character æ²
+U+66b3 Hui # Character æ³
+U+66b4 Bao # Character æ´
+U+66b5 Han # Character æµ
+U+66b6 Xuan # Character æ¶
+U+66b7 Chuan # Character æ·
+U+66b8 Liao # Character æ¸
+U+66b9 Xian # Character æ¹
+U+66ba Dan # Character æº
+U+66bb Jing # Character æ»
+U+66bc Pie # Character æ¼
+U+66bd Lin # Character æ½
+U+66be Tun # Character æ¾
+U+66bf Xi # Character æ¿
+U+66c0 Yi # Character æ
+U+66c1 Ji # Character æ
+U+66c2 Huang # Character æ
+U+66c3 Tai # Character æ
+U+66c4 Ye # Character æ
+U+66c5 Ye # Character æ
+U+66c6 Li # Character æ
+U+66c7 Tan # Character æ
+U+66c8 Tong # Character æ
+U+66c9 Xiao # Character æ
+U+66ca Fei # Character æ
+U+66cb Qin # Character æ
+U+66cc Zhao # Character æ
+U+66cd Hao # Character æ
+U+66ce Yi # Character æ
+U+66cf Xiang # Character æ
+U+66d0 Xing # Character æ
+U+66d1 Sen # Character æ
+U+66d2 Jiao # Character æ
+U+66d3 Bao # Character æ
+U+66d4 Jing # Character æ
+U+66d5 Yian # Character æ
+U+66d6 Ai # Character æ
+U+66d7 Ye # Character æ
+U+66d8 Ru # Character æ
+U+66d9 Shu # Character æ
+U+66da Meng # Character æ
+U+66db Xun # Character æ
+U+66dc Yao # Character æ
+U+66dd Pu # Character æ
+U+66de Li # Character æ
+U+66df Chen # Character æ
+U+66e0 Kuang # Character æ
+U+66e1 Die # Character æ¡
+U+66e2 ? # Character æ¢
+U+66e3 Yan # Character æ£
+U+66e4 Huo # Character æ¤
+U+66e5 Lu # Character æ¥
+U+66e6 Xi # Character æ¦
+U+66e7 Rong # Character æ§
+U+66e8 Long # Character æ¨
+U+66e9 Nang # Character æ©
+U+66ea Luo # Character æª
+U+66eb Luan # Character æ«
+U+66ec Shai # Character æ¬
+U+66ed Tang # Character æ
+U+66ee Yan # Character æ®
+U+66ef Chu # Character æ¯
+U+66f0 Yue # Character æ°
+U+66f1 Yue # Character æ±
+U+66f2 Qu # Character æ²
+U+66f3 Yi # Character æ³
+U+66f4 Geng # Character æ´
+U+66f5 Ye # Character æµ
+U+66f6 Hu # Character æ¶
+U+66f7 He # Character æ·
+U+66f8 Shu # Character æ¸
+U+66f9 Cao # Character æ¹
+U+66fa Cao # Character æº
+U+66fb Noboru # Character æ»
+U+66fc Man # Character æ¼
+U+66fd Ceng # Character æ½
+U+66fe Ceng # Character æ¾
+U+66ff Ti # Character æ¿
diff --git a/resources/chars/ascii/row67.trans b/resources/chars/ascii/row67.trans
new file mode 100644
index 0000000..3362211
--- /dev/null
+++ b/resources/chars/ascii/row67.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+6700 Zui # Character æ
+U+6701 Can # Character æ
+U+6702 Xu # Character æ
+U+6703 Hui # Character æ
+U+6704 Yin # Character æ
+U+6705 Qie # Character æ
+U+6706 Fen # Character æ
+U+6707 Pi # Character æ
+U+6708 Yue # Character æ
+U+6709 You # Character æ
+U+670a Ruan # Character æ
+U+670b Peng # Character æ
+U+670c Ban # Character æ
+U+670d Fu # Character æ
+U+670e Ling # Character æ
+U+670f Fei # Character æ
+U+6710 Qu # Character æ
+U+6711 ? # Character æ
+U+6712 Nu # Character æ
+U+6713 Tiao # Character æ
+U+6714 Shuo # Character æ
+U+6715 Zhen # Character æ
+U+6716 Lang # Character æ
+U+6717 Lang # Character æ
+U+6718 Juan # Character æ
+U+6719 Ming # Character æ
+U+671a Huang # Character æ
+U+671b Wang # Character æ
+U+671c Tun # Character æ
+U+671d Zhao # Character æ
+U+671e Ji # Character æ
+U+671f Qi # Character æ
+U+6720 Ying # Character æ
+U+6721 Zong # Character æ¡
+U+6722 Wang # Character æ¢
+U+6723 Tong # Character æ£
+U+6724 Lang # Character æ¤
+U+6725 ? # Character æ¥
+U+6726 Meng # Character æ¦
+U+6727 Long # Character æ§
+U+6728 Mu # Character æ¨
+U+6729 Deng # Character æ©
+U+672a Wei # Character æª
+U+672b Mo # Character æ«
+U+672c Ben # Character æ¬
+U+672d Zha # Character æ
+U+672e Zhu # Character æ®
+U+672f Zhu # Character æ¯
+U+6730 ? # Character æ°
+U+6731 Zhu # Character æ±
+U+6732 Ren # Character æ²
+U+6733 Ba # Character æ³
+U+6734 Po # Character æ´
+U+6735 Duo # Character æµ
+U+6736 Duo # Character æ¶
+U+6737 Dao # Character æ·
+U+6738 Li # Character æ¸
+U+6739 Qiu # Character æ¹
+U+673a Ji # Character æº
+U+673b Jiu # Character æ»
+U+673c Bi # Character æ¼
+U+673d Xiu # Character æ½
+U+673e Ting # Character æ¾
+U+673f Ci # Character æ¿
+U+6740 Sha # Character æ
+U+6741 Eburi # Character æ
+U+6742 Za # Character æ
+U+6743 Quan # Character æ
+U+6744 Qian # Character æ
+U+6745 Yu # Character æ
+U+6746 Gan # Character æ
+U+6747 Wu # Character æ
+U+6748 Cha # Character æ
+U+6749 Shan # Character æ
+U+674a Xun # Character æ
+U+674b Fan # Character æ
+U+674c Wu # Character æ
+U+674d Zi # Character æ
+U+674e Li # Character æ
+U+674f Xing # Character æ
+U+6750 Cai # Character æ
+U+6751 Cun # Character æ
+U+6752 Ren # Character æ
+U+6753 Shao # Character æ
+U+6754 Tuo # Character æ
+U+6755 Di # Character æ
+U+6756 Zhang # Character æ
+U+6757 Mang # Character æ
+U+6758 Chi # Character æ
+U+6759 Yi # Character æ
+U+675a Gu # Character æ
+U+675b Gong # Character æ
+U+675c Du # Character æ
+U+675d Yi # Character æ
+U+675e Qi # Character æ
+U+675f Shu # Character æ
+U+6760 Gang # Character æ
+U+6761 Tiao # Character æ¡
+U+6762 Moku # Character æ¢
+U+6763 Soma # Character æ£
+U+6764 Tochi # Character æ¤
+U+6765 Lai # Character æ¥
+U+6766 Sugi # Character æ¦
+U+6767 Mang # Character æ§
+U+6768 Yang # Character æ¨
+U+6769 Ma # Character æ©
+U+676a Miao # Character æª
+U+676b Si # Character æ«
+U+676c Yuan # Character æ¬
+U+676d Hang # Character æ
+U+676e Fei # Character æ®
+U+676f Bei # Character æ¯
+U+6770 Jie # Character æ°
+U+6771 Dong # Character æ±
+U+6772 Gao # Character æ²
+U+6773 Yao # Character æ³
+U+6774 Xian # Character æ´
+U+6775 Chu # Character æµ
+U+6776 Qun # Character æ¶
+U+6777 Pa # Character æ·
+U+6778 Shu # Character æ¸
+U+6779 Hua # Character æ¹
+U+677a Xin # Character æº
+U+677b Chou # Character æ»
+U+677c Zhu # Character æ¼
+U+677d Chou # Character æ½
+U+677e Song # Character æ¾
+U+677f Ban # Character æ¿
+U+6780 Song # Character æ
+U+6781 Ji # Character æ
+U+6782 Yue # Character æ
+U+6783 Jin # Character æ
+U+6784 Gou # Character æ
+U+6785 Ji # Character æ
+U+6786 Mao # Character æ
+U+6787 Pi # Character æ
+U+6788 Bi # Character æ
+U+6789 Wang # Character æ
+U+678a Ang # Character æ
+U+678b Fang # Character æ
+U+678c Fen # Character æ
+U+678d Yi # Character æ
+U+678e Fu # Character æ
+U+678f Nan # Character æ
+U+6790 Xi # Character æ
+U+6791 Hu # Character æ
+U+6792 Ya # Character æ
+U+6793 Dou # Character æ
+U+6794 Xun # Character æ
+U+6795 Zhen # Character æ
+U+6796 Yao # Character æ
+U+6797 Lin # Character æ
+U+6798 Rui # Character æ
+U+6799 E # Character æ
+U+679a Mei # Character æ
+U+679b Zhao # Character æ
+U+679c Guo # Character æ
+U+679d Zhi # Character æ
+U+679e Cong # Character æ
+U+679f Yun # Character æ
+U+67a0 Waku # Character æ
+U+67a1 Dou # Character æ¡
+U+67a2 Shu # Character æ¢
+U+67a3 Zao # Character æ£
+U+67a4 ? # Character æ¤
+U+67a5 Li # Character æ¥
+U+67a6 Haze # Character æ¦
+U+67a7 Jian # Character æ§
+U+67a8 Cheng # Character æ¨
+U+67a9 Matsu # Character æ©
+U+67aa Qiang # Character æª
+U+67ab Feng # Character æ«
+U+67ac Nan # Character æ¬
+U+67ad Xiao # Character æ
+U+67ae Xian # Character æ®
+U+67af Ku # Character æ¯
+U+67b0 Ping # Character æ°
+U+67b1 Yi # Character æ±
+U+67b2 Xi # Character æ²
+U+67b3 Zhi # Character æ³
+U+67b4 Guai # Character æ´
+U+67b5 Xiao # Character æµ
+U+67b6 Jia # Character æ¶
+U+67b7 Jia # Character æ·
+U+67b8 Gou # Character æ¸
+U+67b9 Fu # Character æ¹
+U+67ba Mo # Character æº
+U+67bb Yi # Character æ»
+U+67bc Ye # Character æ¼
+U+67bd Ye # Character æ½
+U+67be Shi # Character æ¾
+U+67bf Nie # Character æ¿
+U+67c0 Bi # Character æ
+U+67c1 Duo # Character æ
+U+67c2 Yi # Character æ
+U+67c3 Ling # Character æ
+U+67c4 Bing # Character æ
+U+67c5 Ni # Character æ
+U+67c6 La # Character æ
+U+67c7 He # Character æ
+U+67c8 Pan # Character æ
+U+67c9 Fan # Character æ
+U+67ca Zhong # Character æ
+U+67cb Dai # Character æ
+U+67cc Ci # Character æ
+U+67cd Yang # Character æ
+U+67ce Fu # Character æ
+U+67cf Bo # Character æ
+U+67d0 Mou # Character æ
+U+67d1 Gan # Character æ
+U+67d2 Qi # Character æ
+U+67d3 Ran # Character æ
+U+67d4 Rou # Character æ
+U+67d5 Mao # Character æ
+U+67d6 Zhao # Character æ
+U+67d7 Song # Character æ
+U+67d8 Zhe # Character æ
+U+67d9 Xia # Character æ
+U+67da You # Character æ
+U+67db Shen # Character æ
+U+67dc Ju # Character æ
+U+67dd Tuo # Character æ
+U+67de Zuo # Character æ
+U+67df Nan # Character æ
+U+67e0 Ning # Character æ
+U+67e1 Yong # Character æ¡
+U+67e2 Di # Character æ¢
+U+67e3 Zhi # Character æ£
+U+67e4 Zha # Character æ¤
+U+67e5 Cha # Character æ¥
+U+67e6 Dan # Character æ¦
+U+67e7 Gu # Character æ§
+U+67e8 Pu # Character æ¨
+U+67e9 Jiu # Character æ©
+U+67ea Ao # Character æª
+U+67eb Fu # Character æ«
+U+67ec Jian # Character æ¬
+U+67ed Bo # Character æ
+U+67ee Duo # Character æ®
+U+67ef Ke # Character æ¯
+U+67f0 Nai # Character æ°
+U+67f1 Zhu # Character æ±
+U+67f2 Bi # Character æ²
+U+67f3 Liu # Character æ³
+U+67f4 Chai # Character æ´
+U+67f5 Zha # Character æµ
+U+67f6 Si # Character æ¶
+U+67f7 Zhu # Character æ·
+U+67f8 Pei # Character æ¸
+U+67f9 Shi # Character æ¹
+U+67fa Guai # Character æº
+U+67fb Cha # Character æ»
+U+67fc Yao # Character æ¼
+U+67fd Jue # Character æ½
+U+67fe Jiu # Character æ¾
+U+67ff Shi # Character æ¿
diff --git a/resources/chars/ascii/row68.trans b/resources/chars/ascii/row68.trans
new file mode 100644
index 0000000..cf32514
--- /dev/null
+++ b/resources/chars/ascii/row68.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+6800 Zhi # Character æ
+U+6801 Liu # Character æ
+U+6802 Mei # Character æ
+U+6803 Hoy # Character æ
+U+6804 Rong # Character æ
+U+6805 Zha # Character æ
+U+6806 ? # Character æ
+U+6807 Biao # Character æ
+U+6808 Zhan # Character æ
+U+6809 Jie # Character æ
+U+680a Long # Character æ
+U+680b Dong # Character æ
+U+680c Lu # Character æ
+U+680d Sayng # Character æ
+U+680e Li # Character æ
+U+680f Lan # Character æ
+U+6810 Yong # Character æ
+U+6811 Shu # Character æ
+U+6812 Xun # Character æ
+U+6813 Shuan # Character æ
+U+6814 Qi # Character æ
+U+6815 Zhen # Character æ
+U+6816 Qi # Character æ
+U+6817 Li # Character æ
+U+6818 Yi # Character æ
+U+6819 Xiang # Character æ
+U+681a Zhen # Character æ
+U+681b Li # Character æ
+U+681c Su # Character æ
+U+681d Gua # Character æ
+U+681e Kan # Character æ
+U+681f Bing # Character æ
+U+6820 Ren # Character æ
+U+6821 Xiao # Character æ ¡
+U+6822 Bo # Character æ ¢
+U+6823 Ren # Character æ £
+U+6824 Bing # Character æ ¤
+U+6825 Zi # Character æ ¥
+U+6826 Chou # Character æ ¦
+U+6827 Yi # Character æ §
+U+6828 Jie # Character æ ¨
+U+6829 Xu # Character æ ©
+U+682a Zhu # Character æ ª
+U+682b Jian # Character æ «
+U+682c Zui # Character æ ¬
+U+682d Er # Character æ
+U+682e Er # Character æ ®
+U+682f You # Character æ ¯
+U+6830 Fa # Character æ °
+U+6831 Gong # Character æ ±
+U+6832 Kao # Character æ ²
+U+6833 Lao # Character æ ³
+U+6834 Zhan # Character æ ´
+U+6835 Li # Character æ µ
+U+6836 Yin # Character æ ¶
+U+6837 Yang # Character æ ·
+U+6838 He # Character æ ¸
+U+6839 Gen # Character æ ¹
+U+683a Zhi # Character æ º
+U+683b Chi # Character æ »
+U+683c Ge # Character æ ¼
+U+683d Zai # Character æ ½
+U+683e Luan # Character æ ¾
+U+683f Fu # Character æ ¿
+U+6840 Jie # Character æ¡
+U+6841 Hang # Character æ¡
+U+6842 Gui # Character æ¡
+U+6843 Tao # Character æ¡
+U+6844 Guang # Character æ¡
+U+6845 Wei # Character æ¡
+U+6846 Kuang # Character æ¡
+U+6847 Ru # Character æ¡
+U+6848 An # Character æ¡
+U+6849 An # Character æ¡
+U+684a Juan # Character æ¡
+U+684b Yi # Character æ¡
+U+684c Zhuo # Character æ¡
+U+684d Ku # Character æ¡
+U+684e Zhi # Character æ¡
+U+684f Qiong # Character æ¡
+U+6850 Tong # Character æ¡
+U+6851 Sang # Character æ¡
+U+6852 Sang # Character æ¡
+U+6853 Huan # Character æ¡
+U+6854 Jie # Character æ¡
+U+6855 Jiu # Character æ¡
+U+6856 Xue # Character æ¡
+U+6857 Duo # Character æ¡
+U+6858 Zhui # Character æ¡
+U+6859 Yu # Character æ¡
+U+685a Zan # Character æ¡
+U+685b Kasei # Character æ¡
+U+685c Ying # Character æ¡
+U+685d Masu # Character æ¡
+U+685e ? # Character æ¡
+U+685f Zhan # Character æ¡
+U+6860 Ya # Character æ¡
+U+6861 Nao # Character æ¡¡
+U+6862 Zhen # Character æ¡¢
+U+6863 Dang # Character æ¡£
+U+6864 Qi # Character 桤
+U+6865 Qiao # Character æ¡¥
+U+6866 Hua # Character 桦
+U+6867 Kuai # Character 桧
+U+6868 Jiang # Character 桨
+U+6869 Zhuang # Character æ¡©
+U+686a Xun # Character 桪
+U+686b Suo # Character æ¡«
+U+686c Sha # Character 桬
+U+686d Zhen # Character æ¡
+U+686e Bei # Character æ¡®
+U+686f Ting # Character 桯
+U+6870 Gua # Character æ¡°
+U+6871 Jing # Character 桱
+U+6872 Bo # Character 桲
+U+6873 Ben # Character 桳
+U+6874 Fu # Character æ¡´
+U+6875 Rui # Character 桵
+U+6876 Tong # Character 桶
+U+6877 Jue # Character æ¡·
+U+6878 Xi # Character 桸
+U+6879 Lang # Character 桹
+U+687a Liu # Character 桺
+U+687b Feng # Character æ¡»
+U+687c Qi # Character 桼
+U+687d Wen # Character 桽
+U+687e Jun # Character 桾
+U+687f Gan # Character æ¡¿
+U+6880 Cu # Character æ¢
+U+6881 Liang # Character æ¢
+U+6882 Qiu # Character æ¢
+U+6883 Ting # Character æ¢
+U+6884 You # Character æ¢
+U+6885 Mei # Character æ¢
+U+6886 Bang # Character æ¢
+U+6887 Long # Character æ¢
+U+6888 Peng # Character æ¢
+U+6889 Zhuang # Character æ¢
+U+688a Di # Character æ¢
+U+688b Xuan # Character æ¢
+U+688c Tu # Character æ¢
+U+688d Zao # Character æ¢
+U+688e Ao # Character æ¢
+U+688f Gu # Character æ¢
+U+6890 Bi # Character æ¢
+U+6891 Di # Character æ¢
+U+6892 Han # Character æ¢
+U+6893 Zi # Character æ¢
+U+6894 Zhi # Character æ¢
+U+6895 Ren # Character æ¢
+U+6896 Bei # Character æ¢
+U+6897 Geng # Character æ¢
+U+6898 Jian # Character æ¢
+U+6899 Huan # Character æ¢
+U+689a Wan # Character æ¢
+U+689b Nuo # Character æ¢
+U+689c Jia # Character æ¢
+U+689d Tiao # Character æ¢
+U+689e Ji # Character æ¢
+U+689f Xiao # Character æ¢
+U+68a0 Lu # Character æ¢
+U+68a1 Huan # Character 梡
+U+68a2 Shao # Character 梢
+U+68a3 Cen # Character 梣
+U+68a4 Fen # Character 梤
+U+68a5 Song # Character 梥
+U+68a6 Meng # Character 梦
+U+68a7 Wu # Character 梧
+U+68a8 Li # Character 梨
+U+68a9 Li # Character 梩
+U+68aa Dou # Character 梪
+U+68ab Cen # Character 梫
+U+68ac Ying # Character 梬
+U+68ad Suo # Character æ¢
+U+68ae Ju # Character 梮
+U+68af Ti # Character 梯
+U+68b0 Jie # Character 械
+U+68b1 Kun # Character 梱
+U+68b2 Zhuo # Character 梲
+U+68b3 Shu # Character 梳
+U+68b4 Chan # Character 梴
+U+68b5 Fan # Character 梵
+U+68b6 Wei # Character 梶
+U+68b7 Jing # Character 梷
+U+68b8 Li # Character 梸
+U+68b9 Bing # Character 梹
+U+68ba Fumoto # Character 梺
+U+68bb Shikimi # Character 梻
+U+68bc Tao # Character 梼
+U+68bd Zhi # Character 梽
+U+68be Lai # Character 梾
+U+68bf Lian # Character 梿
+U+68c0 Jian # Character æ£
+U+68c1 Zhuo # Character æ£
+U+68c2 Ling # Character æ£
+U+68c3 Li # Character æ£
+U+68c4 Qi # Character æ£
+U+68c5 Bing # Character æ£
+U+68c6 Zhun # Character æ£
+U+68c7 Cong # Character æ£
+U+68c8 Qian # Character æ£
+U+68c9 Mian # Character æ£
+U+68ca Qi # Character æ£
+U+68cb Qi # Character æ£
+U+68cc Cai # Character æ£
+U+68cd Gun # Character æ£
+U+68ce Chan # Character æ£
+U+68cf Te # Character æ£
+U+68d0 Fei # Character æ£
+U+68d1 Pai # Character æ£
+U+68d2 Bang # Character æ£
+U+68d3 Pou # Character æ£
+U+68d4 Hun # Character æ£
+U+68d5 Zong # Character æ£
+U+68d6 Cheng # Character æ£
+U+68d7 Zao # Character æ£
+U+68d8 Ji # Character æ£
+U+68d9 Li # Character æ£
+U+68da Peng # Character æ£
+U+68db Yu # Character æ£
+U+68dc Yu # Character æ£
+U+68dd Gu # Character æ£
+U+68de Hun # Character æ£
+U+68df Dong # Character æ£
+U+68e0 Tang # Character æ£
+U+68e1 Gang # Character 棡
+U+68e2 Wang # Character 棢
+U+68e3 Di # Character 棣
+U+68e4 Xi # Character 棤
+U+68e5 Fan # Character 棥
+U+68e6 Cheng # Character 棦
+U+68e7 Zhan # Character 棧
+U+68e8 Qi # Character 棨
+U+68e9 Yuan # Character 棩
+U+68ea Yan # Character 棪
+U+68eb Yu # Character 棫
+U+68ec Quan # Character 棬
+U+68ed Yi # Character æ£
+U+68ee Sen # Character 森
+U+68ef Ren # Character 棯
+U+68f0 Chui # Character 棰
+U+68f1 Leng # Character 棱
+U+68f2 Qi # Character 棲
+U+68f3 Zhuo # Character 棳
+U+68f4 Fu # Character 棴
+U+68f5 Ke # Character 棵
+U+68f6 Lai # Character 棶
+U+68f7 Zou # Character 棷
+U+68f8 Zou # Character 棸
+U+68f9 Zhuo # Character 棹
+U+68fa Guan # Character 棺
+U+68fb Fen # Character 棻
+U+68fc Fen # Character 棼
+U+68fd Chen # Character 棽
+U+68fe Qiong # Character 棾
+U+68ff Nie # Character 棿
diff --git a/resources/chars/ascii/row69.trans b/resources/chars/ascii/row69.trans
new file mode 100644
index 0000000..1c62ebb
--- /dev/null
+++ b/resources/chars/ascii/row69.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+6900 Wan # Character æ¤
+U+6901 Guo # Character æ¤
+U+6902 Lu # Character æ¤
+U+6903 Hao # Character æ¤
+U+6904 Jie # Character æ¤
+U+6905 Yi # Character æ¤
+U+6906 Chou # Character æ¤
+U+6907 Ju # Character æ¤
+U+6908 Ju # Character æ¤
+U+6909 Cheng # Character æ¤
+U+690a Zuo # Character æ¤
+U+690b Liang # Character æ¤
+U+690c Qiang # Character æ¤
+U+690d Zhi # Character æ¤
+U+690e Zhui # Character æ¤
+U+690f Ya # Character æ¤
+U+6910 Ju # Character æ¤
+U+6911 Bei # Character æ¤
+U+6912 Jiao # Character æ¤
+U+6913 Zhuo # Character æ¤
+U+6914 Zi # Character æ¤
+U+6915 Bin # Character æ¤
+U+6916 Peng # Character æ¤
+U+6917 Ding # Character æ¤
+U+6918 Chu # Character æ¤
+U+6919 Chang # Character æ¤
+U+691a Kunugi # Character æ¤
+U+691b Momiji # Character æ¤
+U+691c Jian # Character æ¤
+U+691d Gui # Character æ¤
+U+691e Xi # Character æ¤
+U+691f Du # Character æ¤
+U+6920 Qian # Character æ¤
+U+6921 Kunugi # Character 椡
+U+6922 Soko # Character 椢
+U+6923 Shide # Character 椣
+U+6924 Luo # Character 椤
+U+6925 Zhi # Character 椥
+U+6926 Ken # Character 椦
+U+6927 Myeng # Character 椧
+U+6928 Tafu # Character 椨
+U+6929 ? # Character 椩
+U+692a Peng # Character 椪
+U+692b Zhan # Character 椫
+U+692c ? # Character 椬
+U+692d Tuo # Character æ¤
+U+692e Sen # Character 椮
+U+692f Duo # Character 椯
+U+6930 Ye # Character 椰
+U+6931 Fou # Character 椱
+U+6932 Wei # Character 椲
+U+6933 Wei # Character 椳
+U+6934 Duan # Character 椴
+U+6935 Jia # Character 椵
+U+6936 Zong # Character 椶
+U+6937 Jian # Character 椷
+U+6938 Yi # Character 椸
+U+6939 Shen # Character 椹
+U+693a Xi # Character 椺
+U+693b Yan # Character 椻
+U+693c Yan # Character 椼
+U+693d Chuan # Character 椽
+U+693e Zhan # Character 椾
+U+693f Chun # Character 椿
+U+6940 Yu # Character æ¥
+U+6941 He # Character æ¥
+U+6942 Zha # Character æ¥
+U+6943 Wo # Character æ¥
+U+6944 Pian # Character æ¥
+U+6945 Bi # Character æ¥
+U+6946 Yao # Character æ¥
+U+6947 Huo # Character æ¥
+U+6948 Xu # Character æ¥
+U+6949 Ruo # Character æ¥
+U+694a Yang # Character æ¥
+U+694b La # Character æ¥
+U+694c Yan # Character æ¥
+U+694d Ben # Character æ¥
+U+694e Hun # Character æ¥
+U+694f Kui # Character æ¥
+U+6950 Jie # Character æ¥
+U+6951 Kui # Character æ¥
+U+6952 Si # Character æ¥
+U+6953 Feng # Character æ¥
+U+6954 Xie # Character æ¥
+U+6955 Tuo # Character æ¥
+U+6956 Zhi # Character æ¥
+U+6957 Jian # Character æ¥
+U+6958 Mu # Character æ¥
+U+6959 Mao # Character æ¥
+U+695a Chu # Character æ¥
+U+695b Hu # Character æ¥
+U+695c Hu # Character æ¥
+U+695d Lian # Character æ¥
+U+695e Leng # Character æ¥
+U+695f Ting # Character æ¥
+U+6960 Nan # Character æ¥
+U+6961 Yu # Character 楡
+U+6962 You # Character 楢
+U+6963 Mei # Character 楣
+U+6964 Song # Character 楤
+U+6965 Xuan # Character 楥
+U+6966 Xuan # Character 楦
+U+6967 Ying # Character 楧
+U+6968 Zhen # Character 楨
+U+6969 Pian # Character 楩
+U+696a Ye # Character 楪
+U+696b Ji # Character 楫
+U+696c Jie # Character 楬
+U+696d Ye # Character æ¥
+U+696e Chu # Character 楮
+U+696f Shun # Character 楯
+U+6970 Yu # Character 楰
+U+6971 Cou # Character 楱
+U+6972 Wei # Character 楲
+U+6973 Mei # Character 楳
+U+6974 Di # Character 楴
+U+6975 Ji # Character 極
+U+6976 Jie # Character 楶
+U+6977 Kai # Character 楷
+U+6978 Qiu # Character 楸
+U+6979 Ying # Character 楹
+U+697a Rou # Character 楺
+U+697b Heng # Character 楻
+U+697c Lou # Character 楼
+U+697d Le # Character 楽
+U+697e Hazou # Character 楾
+U+697f Katsura # Character 楿
+U+6980 Pin # Character æ¦
+U+6981 Muro # Character æ¦
+U+6982 Gai # Character æ¦
+U+6983 Tan # Character æ¦
+U+6984 Lan # Character æ¦
+U+6985 Yun # Character æ¦
+U+6986 Yu # Character æ¦
+U+6987 Chen # Character æ¦
+U+6988 Lu # Character æ¦
+U+6989 Ju # Character æ¦
+U+698a Sakaki # Character æ¦
+U+698b ? # Character æ¦
+U+698c Pi # Character æ¦
+U+698d Xie # Character æ¦
+U+698e Jia # Character æ¦
+U+698f Yi # Character æ¦
+U+6990 Zhan # Character æ¦
+U+6991 Fu # Character æ¦
+U+6992 Nai # Character æ¦
+U+6993 Mi # Character æ¦
+U+6994 Lang # Character æ¦
+U+6995 Rong # Character æ¦
+U+6996 Gu # Character æ¦
+U+6997 Jian # Character æ¦
+U+6998 Ju # Character æ¦
+U+6999 Ta # Character æ¦
+U+699a Yao # Character æ¦
+U+699b Zhen # Character æ¦
+U+699c Bang # Character æ¦
+U+699d Sha # Character æ¦
+U+699e Yuan # Character æ¦
+U+699f Zi # Character æ¦
+U+69a0 Ming # Character æ¦
+U+69a1 Su # Character 榡
+U+69a2 Jia # Character 榢
+U+69a3 Yao # Character 榣
+U+69a4 Jie # Character 榤
+U+69a5 Huang # Character 榥
+U+69a6 Gan # Character 榦
+U+69a7 Fei # Character 榧
+U+69a8 Zha # Character 榨
+U+69a9 Qian # Character 榩
+U+69aa Ma # Character 榪
+U+69ab Sun # Character 榫
+U+69ac Yuan # Character 榬
+U+69ad Xie # Character æ¦
+U+69ae Rong # Character 榮
+U+69af Shi # Character 榯
+U+69b0 Zhi # Character 榰
+U+69b1 Cui # Character 榱
+U+69b2 Yun # Character 榲
+U+69b3 Ting # Character 榳
+U+69b4 Liu # Character 榴
+U+69b5 Rong # Character 榵
+U+69b6 Tang # Character 榶
+U+69b7 Que # Character 榷
+U+69b8 Zhai # Character 榸
+U+69b9 Si # Character 榹
+U+69ba Sheng # Character 榺
+U+69bb Ta # Character 榻
+U+69bc Ke # Character 榼
+U+69bd Xi # Character 榽
+U+69be Gu # Character 榾
+U+69bf Qi # Character 榿
+U+69c0 Kao # Character æ§
+U+69c1 Gao # Character æ§
+U+69c2 Sun # Character æ§
+U+69c3 Pan # Character æ§
+U+69c4 Tao # Character æ§
+U+69c5 Ge # Character æ§
+U+69c6 Xun # Character æ§
+U+69c7 Dian # Character æ§
+U+69c8 Nou # Character æ§
+U+69c9 Ji # Character æ§
+U+69ca Shuo # Character æ§
+U+69cb Gou # Character æ§
+U+69cc Chui # Character æ§
+U+69cd Qiang # Character æ§
+U+69ce Cha # Character æ§
+U+69cf Qian # Character æ§
+U+69d0 Huai # Character æ§
+U+69d1 Mei # Character æ§
+U+69d2 Xu # Character æ§
+U+69d3 Gang # Character æ§
+U+69d4 Gao # Character æ§
+U+69d5 Zhuo # Character æ§
+U+69d6 Tuo # Character æ§
+U+69d7 Hashi # Character æ§
+U+69d8 Yang # Character æ§
+U+69d9 Dian # Character æ§
+U+69da Jia # Character æ§
+U+69db Jian # Character æ§
+U+69dc Zui # Character æ§
+U+69dd Kashi # Character æ§
+U+69de Ori # Character æ§
+U+69df Bin # Character æ§
+U+69e0 Zhu # Character æ§
+U+69e1 ? # Character 槡
+U+69e2 Xi # Character 槢
+U+69e3 Qi # Character 槣
+U+69e4 Lian # Character 槤
+U+69e5 Hui # Character 槥
+U+69e6 Yong # Character 槦
+U+69e7 Qian # Character 槧
+U+69e8 Guo # Character 槨
+U+69e9 Gai # Character 槩
+U+69ea Gai # Character 槪
+U+69eb Tuan # Character 槫
+U+69ec Hua # Character 槬
+U+69ed Cu # Character æ§
+U+69ee Sen # Character 槮
+U+69ef Cui # Character 槯
+U+69f0 Beng # Character 槰
+U+69f1 You # Character 槱
+U+69f2 Hu # Character 槲
+U+69f3 Jiang # Character 槳
+U+69f4 Hu # Character 槴
+U+69f5 Huan # Character 槵
+U+69f6 Kui # Character 槶
+U+69f7 Yi # Character 槷
+U+69f8 Nie # Character 槸
+U+69f9 Gao # Character 槹
+U+69fa Kang # Character 槺
+U+69fb Gui # Character 槻
+U+69fc Gui # Character 槼
+U+69fd Cao # Character 槽
+U+69fe Man # Character 槾
+U+69ff Jin # Character 槿
diff --git a/resources/chars/ascii/row6a.trans b/resources/chars/ascii/row6a.trans
new file mode 100644
index 0000000..af8012f
--- /dev/null
+++ b/resources/chars/ascii/row6a.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+6a00 Di # Character æ¨
+U+6a01 Zhuang # Character æ¨
+U+6a02 Le # Character æ¨
+U+6a03 Lang # Character æ¨
+U+6a04 Chen # Character æ¨
+U+6a05 Cong # Character æ¨
+U+6a06 Li # Character æ¨
+U+6a07 Xiu # Character æ¨
+U+6a08 Qing # Character æ¨
+U+6a09 Shuang # Character æ¨
+U+6a0a Fan # Character æ¨
+U+6a0b Tong # Character æ¨
+U+6a0c Guan # Character æ¨
+U+6a0d Ji # Character æ¨
+U+6a0e Suo # Character æ¨
+U+6a0f Lei # Character æ¨
+U+6a10 Lu # Character æ¨
+U+6a11 Liang # Character æ¨
+U+6a12 Mi # Character æ¨
+U+6a13 Lou # Character æ¨
+U+6a14 Chao # Character æ¨
+U+6a15 Su # Character æ¨
+U+6a16 Ke # Character æ¨
+U+6a17 Shu # Character æ¨
+U+6a18 Tang # Character æ¨
+U+6a19 Biao # Character æ¨
+U+6a1a Lu # Character æ¨
+U+6a1b Jiu # Character æ¨
+U+6a1c Shu # Character æ¨
+U+6a1d Zha # Character æ¨
+U+6a1e Shu # Character æ¨
+U+6a1f Zhang # Character æ¨
+U+6a20 Men # Character æ¨
+U+6a21 Mo # Character 模
+U+6a22 Niao # Character 樢
+U+6a23 Yang # Character 樣
+U+6a24 Tiao # Character 樤
+U+6a25 Peng # Character 樥
+U+6a26 Zhu # Character 樦
+U+6a27 Sha # Character 樧
+U+6a28 Xi # Character 樨
+U+6a29 Quan # Character 権
+U+6a2a Heng # Character 横
+U+6a2b Jian # Character 樫
+U+6a2c Cong # Character 樬
+U+6a2d ? # Character æ¨
+U+6a2e Hokuso # Character 樮
+U+6a2f Qiang # Character 樯
+U+6a30 Tara # Character 樰
+U+6a31 Ying # Character 樱
+U+6a32 Er # Character 樲
+U+6a33 Xin # Character 樳
+U+6a34 Zhi # Character 樴
+U+6a35 Qiao # Character 樵
+U+6a36 Zui # Character 樶
+U+6a37 Cong # Character 樷
+U+6a38 Pu # Character 樸
+U+6a39 Shu # Character 樹
+U+6a3a Hua # Character 樺
+U+6a3b Kui # Character 樻
+U+6a3c Zhen # Character 樼
+U+6a3d Zun # Character 樽
+U+6a3e Yue # Character 樾
+U+6a3f Zhan # Character 樿
+U+6a40 Xi # Character æ©
+U+6a41 Xun # Character æ©
+U+6a42 Dian # Character æ©
+U+6a43 Fa # Character æ©
+U+6a44 Gan # Character æ©
+U+6a45 Mo # Character æ©
+U+6a46 Wu # Character æ©
+U+6a47 Qiao # Character æ©
+U+6a48 Nao # Character æ©
+U+6a49 Lin # Character æ©
+U+6a4a Liu # Character æ©
+U+6a4b Qiao # Character æ©
+U+6a4c Xian # Character æ©
+U+6a4d Run # Character æ©
+U+6a4e Fan # Character æ©
+U+6a4f Zhan # Character æ©
+U+6a50 Tuo # Character æ©
+U+6a51 Lao # Character æ©
+U+6a52 Yun # Character æ©
+U+6a53 Shun # Character æ©
+U+6a54 Tui # Character æ©
+U+6a55 Cheng # Character æ©
+U+6a56 Tang # Character æ©
+U+6a57 Meng # Character æ©
+U+6a58 Ju # Character æ©
+U+6a59 Cheng # Character æ©
+U+6a5a Su # Character æ©
+U+6a5b Jue # Character æ©
+U+6a5c Jue # Character æ©
+U+6a5d Tan # Character æ©
+U+6a5e Hui # Character æ©
+U+6a5f Ji # Character æ©
+U+6a60 Nuo # Character æ©
+U+6a61 Xiang # Character æ©¡
+U+6a62 Tuo # Character æ©¢
+U+6a63 Ning # Character æ©£
+U+6a64 Rui # Character 橤
+U+6a65 Zhu # Character æ©¥
+U+6a66 Chuang # Character 橦
+U+6a67 Zeng # Character 橧
+U+6a68 Fen # Character 橨
+U+6a69 Qiong # Character æ©©
+U+6a6a Ran # Character 橪
+U+6a6b Heng # Character æ©«
+U+6a6c Cen # Character 橬
+U+6a6d Gu # Character æ©
+U+6a6e Liu # Character æ©®
+U+6a6f Lao # Character 橯
+U+6a70 Gao # Character æ©°
+U+6a71 Chu # Character 橱
+U+6a72 Zusa # Character 橲
+U+6a73 Nude # Character 橳
+U+6a74 Ca # Character æ©´
+U+6a75 San # Character 橵
+U+6a76 Ji # Character 橶
+U+6a77 Dou # Character æ©·
+U+6a78 Shou # Character 橸
+U+6a79 Lu # Character 橹
+U+6a7a ? # Character 橺
+U+6a7b ? # Character æ©»
+U+6a7c Yuan # Character 橼
+U+6a7d Ta # Character 橽
+U+6a7e Shu # Character 橾
+U+6a7f Jiang # Character æ©¿
+U+6a80 Tan # Character æª
+U+6a81 Lin # Character æª
+U+6a82 Nong # Character æª
+U+6a83 Yin # Character æª
+U+6a84 Xi # Character æª
+U+6a85 Sui # Character æª
+U+6a86 Shan # Character æª
+U+6a87 Zui # Character æª
+U+6a88 Xuan # Character æª
+U+6a89 Cheng # Character æª
+U+6a8a Gan # Character æª
+U+6a8b Ju # Character æª
+U+6a8c Zui # Character æª
+U+6a8d Yi # Character æª
+U+6a8e Qin # Character æª
+U+6a8f Pu # Character æª
+U+6a90 Yan # Character æª
+U+6a91 Lei # Character æª
+U+6a92 Feng # Character æª
+U+6a93 Hui # Character æª
+U+6a94 Dang # Character æª
+U+6a95 Ji # Character æª
+U+6a96 Sui # Character æª
+U+6a97 Bo # Character æª
+U+6a98 Bi # Character æª
+U+6a99 Ding # Character æª
+U+6a9a Chu # Character æª
+U+6a9b Zhua # Character æª
+U+6a9c Kuai # Character æª
+U+6a9d Ji # Character æª
+U+6a9e Jie # Character æª
+U+6a9f Jia # Character æª
+U+6aa0 Qing # Character æª
+U+6aa1 Zhe # Character 檡
+U+6aa2 Jian # Character 檢
+U+6aa3 Qiang # Character 檣
+U+6aa4 Dao # Character 檤
+U+6aa5 Yi # Character 檥
+U+6aa6 Biao # Character 檦
+U+6aa7 Song # Character 檧
+U+6aa8 She # Character 檨
+U+6aa9 Lin # Character 檩
+U+6aaa Kunugi # Character 檪
+U+6aab Cha # Character 檫
+U+6aac Meng # Character 檬
+U+6aad Yin # Character æª
+U+6aae Tao # Character 檮
+U+6aaf Tai # Character 檯
+U+6ab0 Mian # Character 檰
+U+6ab1 Qi # Character 檱
+U+6ab2 Toan # Character 檲
+U+6ab3 Bin # Character 檳
+U+6ab4 Huo # Character 檴
+U+6ab5 Ji # Character 檵
+U+6ab6 Qian # Character 檶
+U+6ab7 Mi # Character 檷
+U+6ab8 Ning # Character 檸
+U+6ab9 Yi # Character 檹
+U+6aba Gao # Character 檺
+U+6abb Jian # Character 檻
+U+6abc Yin # Character 檼
+U+6abd Er # Character 檽
+U+6abe Qing # Character 檾
+U+6abf Yan # Character 檿
+U+6ac0 Qi # Character æ«
+U+6ac1 Mi # Character æ«
+U+6ac2 Zhao # Character æ«
+U+6ac3 Gui # Character æ«
+U+6ac4 Chun # Character æ«
+U+6ac5 Ji # Character æ«
+U+6ac6 Kui # Character æ«
+U+6ac7 Po # Character æ«
+U+6ac8 Deng # Character æ«
+U+6ac9 Chu # Character æ«
+U+6aca ? # Character æ«
+U+6acb Mian # Character æ«
+U+6acc You # Character æ«
+U+6acd Zhi # Character æ«
+U+6ace Guang # Character æ«
+U+6acf Qian # Character æ«
+U+6ad0 Lei # Character æ«
+U+6ad1 Lei # Character æ«
+U+6ad2 Sa # Character æ«
+U+6ad3 Lu # Character æ«
+U+6ad4 Li # Character æ«
+U+6ad5 Cuan # Character æ«
+U+6ad6 Lu # Character æ«
+U+6ad7 Mie # Character æ«
+U+6ad8 Hui # Character æ«
+U+6ad9 Ou # Character æ«
+U+6ada Lu # Character æ«
+U+6adb Jie # Character æ«
+U+6adc Gao # Character æ«
+U+6add Du # Character æ«
+U+6ade Yuan # Character æ«
+U+6adf Li # Character æ«
+U+6ae0 Fei # Character æ«
+U+6ae1 Zhuo # Character æ«¡
+U+6ae2 Sou # Character æ«¢
+U+6ae3 Lian # Character æ«£
+U+6ae4 Tamo # Character 櫤
+U+6ae5 Chu # Character æ«¥
+U+6ae6 ? # Character 櫦
+U+6ae7 Zhu # Character 櫧
+U+6ae8 Lu # Character 櫨
+U+6ae9 Yan # Character æ«©
+U+6aea Li # Character 櫪
+U+6aeb Zhu # Character æ««
+U+6aec Chen # Character 櫬
+U+6aed Jie # Character æ«
+U+6aee E # Character æ«®
+U+6aef Su # Character 櫯
+U+6af0 Huai # Character æ«°
+U+6af1 Nie # Character 櫱
+U+6af2 Yu # Character 櫲
+U+6af3 Long # Character 櫳
+U+6af4 Lai # Character æ«´
+U+6af5 ? # Character 櫵
+U+6af6 Xian # Character 櫶
+U+6af7 Kwi # Character æ«·
+U+6af8 Ju # Character 櫸
+U+6af9 Xiao # Character 櫹
+U+6afa Ling # Character 櫺
+U+6afb Ying # Character æ«»
+U+6afc Jian # Character 櫼
+U+6afd Yin # Character 櫽
+U+6afe You # Character 櫾
+U+6aff Ying # Character æ«¿
diff --git a/resources/chars/ascii/row6b.trans b/resources/chars/ascii/row6b.trans
new file mode 100644
index 0000000..74b9015
--- /dev/null
+++ b/resources/chars/ascii/row6b.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+6b00 Xiang # Character æ¬
+U+6b01 Nong # Character æ¬
+U+6b02 Bo # Character æ¬
+U+6b03 Chan # Character æ¬
+U+6b04 Lan # Character æ¬
+U+6b05 Ju # Character æ¬
+U+6b06 Shuang # Character æ¬
+U+6b07 She # Character æ¬
+U+6b08 Wei # Character æ¬
+U+6b09 Cong # Character æ¬
+U+6b0a Quan # Character æ¬
+U+6b0b Qu # Character æ¬
+U+6b0c Cang # Character æ¬
+U+6b0d ? # Character æ¬
+U+6b0e Yu # Character æ¬
+U+6b0f Luo # Character æ¬
+U+6b10 Li # Character æ¬
+U+6b11 Zan # Character æ¬
+U+6b12 Luan # Character æ¬
+U+6b13 Dang # Character æ¬
+U+6b14 Jue # Character æ¬
+U+6b15 Em # Character æ¬
+U+6b16 Lan # Character æ¬
+U+6b17 Lan # Character æ¬
+U+6b18 Zhu # Character æ¬
+U+6b19 Lei # Character æ¬
+U+6b1a Li # Character æ¬
+U+6b1b Ba # Character æ¬
+U+6b1c Nang # Character æ¬
+U+6b1d Yu # Character æ¬
+U+6b1e Ling # Character æ¬
+U+6b1f Tsuki # Character æ¬
+U+6b20 Qian # Character æ¬
+U+6b21 Ci # Character 次
+U+6b22 Huan # Character 欢
+U+6b23 Xin # Character 欣
+U+6b24 Yu # Character 欤
+U+6b25 Yu # Character 欥
+U+6b26 Qian # Character 欦
+U+6b27 Ou # Character 欧
+U+6b28 Xu # Character 欨
+U+6b29 Chao # Character 欩
+U+6b2a Chu # Character 欪
+U+6b2b Chi # Character 欫
+U+6b2c Kai # Character 欬
+U+6b2d Yi # Character æ¬
+U+6b2e Jue # Character 欮
+U+6b2f Xi # Character 欯
+U+6b30 Xu # Character 欰
+U+6b31 Xia # Character 欱
+U+6b32 Yu # Character 欲
+U+6b33 Kuai # Character 欳
+U+6b34 Lang # Character 欴
+U+6b35 Kuan # Character 欵
+U+6b36 Shuo # Character 欶
+U+6b37 Xi # Character 欷
+U+6b38 Ai # Character 欸
+U+6b39 Yi # Character 欹
+U+6b3a Qi # Character 欺
+U+6b3b Hu # Character 欻
+U+6b3c Chi # Character 欼
+U+6b3d Qin # Character 欽
+U+6b3e Kuan # Character 款
+U+6b3f Kan # Character 欿
+U+6b40 Kuan # Character æ
+U+6b41 Kan # Character æ
+U+6b42 Chuan # Character æ
+U+6b43 Sha # Character æ
+U+6b44 Gua # Character æ
+U+6b45 Yin # Character æ
+U+6b46 Xin # Character æ
+U+6b47 Xie # Character æ
+U+6b48 Yu # Character æ
+U+6b49 Qian # Character æ
+U+6b4a Xiao # Character æ
+U+6b4b Yi # Character æ
+U+6b4c Ge # Character æ
+U+6b4d Wu # Character æ
+U+6b4e Tan # Character æ
+U+6b4f Jin # Character æ
+U+6b50 Ou # Character æ
+U+6b51 Hu # Character æ
+U+6b52 Ti # Character æ
+U+6b53 Huan # Character æ
+U+6b54 Xu # Character æ
+U+6b55 Pen # Character æ
+U+6b56 Xi # Character æ
+U+6b57 Xiao # Character æ
+U+6b58 Xu # Character æ
+U+6b59 Xi # Character æ
+U+6b5a Sen # Character æ
+U+6b5b Lian # Character æ
+U+6b5c Chu # Character æ
+U+6b5d Yi # Character æ
+U+6b5e Kan # Character æ
+U+6b5f Yu # Character æ
+U+6b60 Chuo # Character æ
+U+6b61 Huan # Character æ¡
+U+6b62 Zhi # Character æ¢
+U+6b63 Zheng # Character æ£
+U+6b64 Ci # Character æ¤
+U+6b65 Bu # Character æ¥
+U+6b66 Wu # Character æ¦
+U+6b67 Qi # Character æ§
+U+6b68 Bu # Character æ¨
+U+6b69 Bu # Character æ©
+U+6b6a Wai # Character æª
+U+6b6b Ju # Character æ«
+U+6b6c Qian # Character æ¬
+U+6b6d Chi # Character æ
+U+6b6e Se # Character æ®
+U+6b6f Chi # Character æ¯
+U+6b70 Se # Character æ°
+U+6b71 Zhong # Character æ±
+U+6b72 Sui # Character æ²
+U+6b73 Sui # Character æ³
+U+6b74 Li # Character æ´
+U+6b75 Cuo # Character æµ
+U+6b76 Yu # Character æ¶
+U+6b77 Li # Character æ·
+U+6b78 Gui # Character æ¸
+U+6b79 Dai # Character æ¹
+U+6b7a Dai # Character æº
+U+6b7b Si # Character æ»
+U+6b7c Jian # Character æ¼
+U+6b7d Zhe # Character æ½
+U+6b7e Mo # Character æ¾
+U+6b7f Mo # Character æ¿
+U+6b80 Yao # Character æ®
+U+6b81 Mo # Character æ®
+U+6b82 Cu # Character æ®
+U+6b83 Yang # Character æ®
+U+6b84 Tian # Character æ®
+U+6b85 Sheng # Character æ®
+U+6b86 Dai # Character æ®
+U+6b87 Shang # Character æ®
+U+6b88 Xu # Character æ®
+U+6b89 Xun # Character æ®
+U+6b8a Shu # Character æ®
+U+6b8b Can # Character æ®
+U+6b8c Jue # Character æ®
+U+6b8d Piao # Character æ®
+U+6b8e Qia # Character æ®
+U+6b8f Qiu # Character æ®
+U+6b90 Su # Character æ®
+U+6b91 Qing # Character æ®
+U+6b92 Yun # Character æ®
+U+6b93 Lian # Character æ®
+U+6b94 Yi # Character æ®
+U+6b95 Fou # Character æ®
+U+6b96 Zhi # Character æ®
+U+6b97 Ye # Character æ®
+U+6b98 Can # Character æ®
+U+6b99 Hun # Character æ®
+U+6b9a Dan # Character æ®
+U+6b9b Ji # Character æ®
+U+6b9c Ye # Character æ®
+U+6b9d Zhen # Character æ®
+U+6b9e Yun # Character æ®
+U+6b9f Wen # Character æ®
+U+6ba0 Chou # Character æ®
+U+6ba1 Bin # Character 殡
+U+6ba2 Ti # Character 殢
+U+6ba3 Jin # Character 殣
+U+6ba4 Shang # Character 殤
+U+6ba5 Yin # Character 殥
+U+6ba6 Diao # Character 殦
+U+6ba7 Cu # Character 殧
+U+6ba8 Hui # Character 殨
+U+6ba9 Cuan # Character 殩
+U+6baa Yi # Character 殪
+U+6bab Dan # Character 殫
+U+6bac Du # Character 殬
+U+6bad Jiang # Character æ®
+U+6bae Lian # Character æ®®
+U+6baf Bin # Character 殯
+U+6bb0 Du # Character æ®°
+U+6bb1 Tsukusu # Character æ®±
+U+6bb2 Jian # Character 殲
+U+6bb3 Shu # Character 殳
+U+6bb4 Ou # Character æ®´
+U+6bb5 Duan # Character 段
+U+6bb6 Zhu # Character 殶
+U+6bb7 Yin # Character æ®·
+U+6bb8 Qing # Character 殸
+U+6bb9 Yi # Character 殹
+U+6bba Sha # Character 殺
+U+6bbb Que # Character æ®»
+U+6bbc Ke # Character 殼
+U+6bbd Yao # Character 殽
+U+6bbe Jun # Character 殾
+U+6bbf Dian # Character 殿
+U+6bc0 Hui # Character æ¯
+U+6bc1 Hui # Character æ¯
+U+6bc2 Gu # Character æ¯
+U+6bc3 Que # Character æ¯
+U+6bc4 Ji # Character æ¯
+U+6bc5 Yi # Character æ¯
+U+6bc6 Ou # Character æ¯
+U+6bc7 Hui # Character æ¯
+U+6bc8 Duan # Character æ¯
+U+6bc9 Yi # Character æ¯
+U+6bca Xiao # Character æ¯
+U+6bcb Wu # Character æ¯
+U+6bcc Guan # Character æ¯
+U+6bcd Mu # Character æ¯
+U+6bce Mei # Character æ¯
+U+6bcf Mei # Character æ¯
+U+6bd0 Ai # Character æ¯
+U+6bd1 Zuo # Character æ¯
+U+6bd2 Du # Character æ¯
+U+6bd3 Yu # Character æ¯
+U+6bd4 Bi # Character æ¯
+U+6bd5 Bi # Character æ¯
+U+6bd6 Bi # Character æ¯
+U+6bd7 Pi # Character æ¯
+U+6bd8 Pi # Character æ¯
+U+6bd9 Bi # Character æ¯
+U+6bda Chan # Character æ¯
+U+6bdb Mao # Character æ¯
+U+6bdc ? # Character æ¯
+U+6bdd ? # Character æ¯
+U+6bde Pu # Character æ¯
+U+6bdf Mushiru # Character æ¯
+U+6be0 Jia # Character æ¯
+U+6be1 Zhan # Character 毡
+U+6be2 Sai # Character 毢
+U+6be3 Mu # Character 毣
+U+6be4 Tuo # Character 毤
+U+6be5 Xun # Character 毥
+U+6be6 Er # Character 毦
+U+6be7 Rong # Character 毧
+U+6be8 Xian # Character 毨
+U+6be9 Ju # Character 毩
+U+6bea Mu # Character 毪
+U+6beb Hao # Character 毫
+U+6bec Qiu # Character 毬
+U+6bed Dou # Character æ¯
+U+6bee Mushiru # Character 毮
+U+6bef Tan # Character 毯
+U+6bf0 Pei # Character 毰
+U+6bf1 Ju # Character 毱
+U+6bf2 Duo # Character 毲
+U+6bf3 Cui # Character 毳
+U+6bf4 Bi # Character 毴
+U+6bf5 San # Character 毵
+U+6bf6 ? # Character 毶
+U+6bf7 Mao # Character 毷
+U+6bf8 Sui # Character 毸
+U+6bf9 Yu # Character 毹
+U+6bfa Yu # Character 毺
+U+6bfb Tuo # Character 毻
+U+6bfc He # Character 毼
+U+6bfd Jian # Character 毽
+U+6bfe Ta # Character 毾
+U+6bff San # Character 毿
diff --git a/resources/chars/ascii/row6c.trans b/resources/chars/ascii/row6c.trans
new file mode 100644
index 0000000..10d099d
--- /dev/null
+++ b/resources/chars/ascii/row6c.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+6c00 Lu # Character æ°
+U+6c01 Mu # Character æ°
+U+6c02 Li # Character æ°
+U+6c03 Tong # Character æ°
+U+6c04 Rong # Character æ°
+U+6c05 Chang # Character æ°
+U+6c06 Pu # Character æ°
+U+6c07 Luo # Character æ°
+U+6c08 Zhan # Character æ°
+U+6c09 Sao # Character æ°
+U+6c0a Zhan # Character æ°
+U+6c0b Meng # Character æ°
+U+6c0c Luo # Character æ°
+U+6c0d Qu # Character æ°
+U+6c0e Die # Character æ°
+U+6c0f Shi # Character æ°
+U+6c10 Di # Character æ°
+U+6c11 Min # Character æ°
+U+6c12 Jue # Character æ°
+U+6c13 Mang # Character æ°
+U+6c14 Qi # Character æ°
+U+6c15 Pie # Character æ°
+U+6c16 Nai # Character æ°
+U+6c17 Qi # Character æ°
+U+6c18 Dao # Character æ°
+U+6c19 Xian # Character æ°
+U+6c1a Chuan # Character æ°
+U+6c1b Fen # Character æ°
+U+6c1c Ri # Character æ°
+U+6c1d Nei # Character æ°
+U+6c1e ? # Character æ°
+U+6c1f Fu # Character æ°
+U+6c20 Shen # Character æ°
+U+6c21 Dong # Character æ°¡
+U+6c22 Qing # Character æ°¢
+U+6c23 Qi # Character æ°£
+U+6c24 Yin # Character æ°¤
+U+6c25 Xi # Character æ°¥
+U+6c26 Hai # Character æ°¦
+U+6c27 Yang # Character æ°§
+U+6c28 An # Character æ°¨
+U+6c29 Ya # Character æ°©
+U+6c2a Ke # Character æ°ª
+U+6c2b Qing # Character æ°«
+U+6c2c Ya # Character æ°¬
+U+6c2d Dong # Character æ°
+U+6c2e Dan # Character æ°®
+U+6c2f Lu # Character æ°¯
+U+6c30 Qing # Character æ°°
+U+6c31 Yang # Character æ°±
+U+6c32 Yun # Character æ°²
+U+6c33 Yun # Character æ°³
+U+6c34 Shui # Character æ°´
+U+6c35 San # Character æ°µ
+U+6c36 Zheng # Character æ°¶
+U+6c37 Bing # Character æ°·
+U+6c38 Yong # Character æ°¸
+U+6c39 Dang # Character æ°¹
+U+6c3a Shitamizu # Character æ°º
+U+6c3b Le # Character æ°»
+U+6c3c Ni # Character æ°¼
+U+6c3d Tun # Character æ°½
+U+6c3e Fan # Character æ°¾
+U+6c3f Gui # Character æ°¿
+U+6c40 Ting # Character æ±
+U+6c41 Zhi # Character æ±
+U+6c42 Qiu # Character æ±
+U+6c43 Bin # Character æ±
+U+6c44 Ze # Character æ±
+U+6c45 Mian # Character æ±
+U+6c46 Cuan # Character æ±
+U+6c47 Hui # Character æ±
+U+6c48 Diao # Character æ±
+U+6c49 Yi # Character æ±
+U+6c4a Cha # Character æ±
+U+6c4b Zhuo # Character æ±
+U+6c4c Chuan # Character æ±
+U+6c4d Wan # Character æ±
+U+6c4e Fan # Character æ±
+U+6c4f Dai # Character æ±
+U+6c50 Xi # Character æ±
+U+6c51 Tuo # Character æ±
+U+6c52 Mang # Character æ±
+U+6c53 Qiu # Character æ±
+U+6c54 Qi # Character æ±
+U+6c55 Shan # Character æ±
+U+6c56 Pai # Character æ±
+U+6c57 Han # Character æ±
+U+6c58 Qian # Character æ±
+U+6c59 Wu # Character æ±
+U+6c5a Wu # Character æ±
+U+6c5b Xun # Character æ±
+U+6c5c Si # Character æ±
+U+6c5d Ru # Character æ±
+U+6c5e Gong # Character æ±
+U+6c5f Jiang # Character æ±
+U+6c60 Chi # Character æ±
+U+6c61 Wu # Character 污
+U+6c62 Tsuchi # Character æ±¢
+U+6c63 ? # Character æ±£
+U+6c64 Tang # Character 汤
+U+6c65 Zhi # Character æ±¥
+U+6c66 Chi # Character 汦
+U+6c67 Qian # Character 汧
+U+6c68 Mi # Character 汨
+U+6c69 Yu # Character 汩
+U+6c6a Wang # Character 汪
+U+6c6b Qing # Character 汫
+U+6c6c Jing # Character 汬
+U+6c6d Rui # Character æ±
+U+6c6e Jun # Character æ±®
+U+6c6f Hong # Character 汯
+U+6c70 Tai # Character æ±°
+U+6c71 Quan # Character æ±±
+U+6c72 Ji # Character æ±²
+U+6c73 Bian # Character æ±³
+U+6c74 Bian # Character æ±´
+U+6c75 Gan # Character æ±µ
+U+6c76 Wen # Character 汶
+U+6c77 Zhong # Character æ±·
+U+6c78 Fang # Character 汸
+U+6c79 Xiong # Character æ±¹
+U+6c7a Jue # Character 決
+U+6c7b Hang # Character æ±»
+U+6c7c Niou # Character æ±¼
+U+6c7d Qi # Character æ±½
+U+6c7e Fen # Character æ±¾
+U+6c7f Xu # Character 汿
+U+6c80 Xu # Character æ²
+U+6c81 Qin # Character æ²
+U+6c82 Yi # Character æ²
+U+6c83 Wo # Character æ²
+U+6c84 Yun # Character æ²
+U+6c85 Yuan # Character æ²
+U+6c86 Hang # Character æ²
+U+6c87 Yan # Character æ²
+U+6c88 Chen # Character æ²
+U+6c89 Chen # Character æ²
+U+6c8a Dan # Character æ²
+U+6c8b You # Character æ²
+U+6c8c Dun # Character æ²
+U+6c8d Hu # Character æ²
+U+6c8e Huo # Character æ²
+U+6c8f Qie # Character æ²
+U+6c90 Mu # Character æ²
+U+6c91 Rou # Character æ²
+U+6c92 Mei # Character æ²
+U+6c93 Ta # Character æ²
+U+6c94 Mian # Character æ²
+U+6c95 Wu # Character æ²
+U+6c96 Chong # Character æ²
+U+6c97 Tian # Character æ²
+U+6c98 Bi # Character æ²
+U+6c99 Sha # Character æ²
+U+6c9a Zhi # Character æ²
+U+6c9b Pei # Character æ²
+U+6c9c Pan # Character æ²
+U+6c9d Zhui # Character æ²
+U+6c9e Za # Character æ²
+U+6c9f Gou # Character æ²
+U+6ca0 Liu # Character æ²
+U+6ca1 Mei # Character 没
+U+6ca2 Ze # Character æ²¢
+U+6ca3 Feng # Character æ²£
+U+6ca4 Ou # Character 沤
+U+6ca5 Li # Character æ²¥
+U+6ca6 Lun # Character 沦
+U+6ca7 Cang # Character 沧
+U+6ca8 Feng # Character 沨
+U+6ca9 Wei # Character 沩
+U+6caa Hu # Character 沪
+U+6cab Mo # Character 沫
+U+6cac Mei # Character 沬
+U+6cad Shu # Character æ²
+U+6cae Ju # Character æ²®
+U+6caf Zan # Character 沯
+U+6cb0 Tuo # Character æ²°
+U+6cb1 Tuo # Character æ²±
+U+6cb2 Tuo # Character æ²²
+U+6cb3 He # Character æ²³
+U+6cb4 Li # Character æ²´
+U+6cb5 Mi # Character æ²µ
+U+6cb6 Yi # Character 沶
+U+6cb7 Fa # Character æ²·
+U+6cb8 Fei # Character 沸
+U+6cb9 You # Character æ²¹
+U+6cba Tian # Character 沺
+U+6cbb Zhi # Character æ²»
+U+6cbc Zhao # Character æ²¼
+U+6cbd Gu # Character æ²½
+U+6cbe Zhan # Character æ²¾
+U+6cbf Yan # Character 沿
+U+6cc0 Si # Character æ³
+U+6cc1 Kuang # Character æ³
+U+6cc2 Jiong # Character æ³
+U+6cc3 Ju # Character æ³
+U+6cc4 Xie # Character æ³
+U+6cc5 Qiu # Character æ³
+U+6cc6 Yi # Character æ³
+U+6cc7 Jia # Character æ³
+U+6cc8 Zhong # Character æ³
+U+6cc9 Quan # Character æ³
+U+6cca Bo # Character æ³
+U+6ccb Hui # Character æ³
+U+6ccc Mi # Character æ³
+U+6ccd Ben # Character æ³
+U+6cce Zhuo # Character æ³
+U+6ccf Chu # Character æ³
+U+6cd0 Le # Character æ³
+U+6cd1 You # Character æ³
+U+6cd2 Gu # Character æ³
+U+6cd3 Hong # Character æ³
+U+6cd4 Gan # Character æ³
+U+6cd5 Fa # Character æ³
+U+6cd6 Mao # Character æ³
+U+6cd7 Si # Character æ³
+U+6cd8 Hu # Character æ³
+U+6cd9 Ping # Character æ³
+U+6cda Ci # Character æ³
+U+6cdb Fan # Character æ³
+U+6cdc Chi # Character æ³
+U+6cdd Su # Character æ³
+U+6cde Ning # Character æ³
+U+6cdf Cheng # Character æ³
+U+6ce0 Ling # Character æ³
+U+6ce1 Pao # Character 泡
+U+6ce2 Bo # Character æ³¢
+U+6ce3 Qi # Character æ³£
+U+6ce4 Si # Character 泤
+U+6ce5 Ni # Character æ³¥
+U+6ce6 Ju # Character 泦
+U+6ce7 Yue # Character 泧
+U+6ce8 Zhu # Character 注
+U+6ce9 Sheng # Character 泩
+U+6cea Lei # Character 泪
+U+6ceb Xuan # Character 泫
+U+6cec Xue # Character 泬
+U+6ced Fu # Character æ³
+U+6cee Pan # Character æ³®
+U+6cef Min # Character 泯
+U+6cf0 Tai # Character æ³°
+U+6cf1 Yang # Character æ³±
+U+6cf2 Ji # Character æ³²
+U+6cf3 Yong # Character æ³³
+U+6cf4 Guan # Character æ³´
+U+6cf5 Beng # Character æ³µ
+U+6cf6 Xue # Character 泶
+U+6cf7 Long # Character æ³·
+U+6cf8 Lu # Character 泸
+U+6cf9 ? # Character æ³¹
+U+6cfa Bo # Character 泺
+U+6cfb Xie # Character æ³»
+U+6cfc Po # Character æ³¼
+U+6cfd Ze # Character æ³½
+U+6cfe Jing # Character æ³¾
+U+6cff Yin # Character 泿
diff --git a/resources/chars/ascii/row6d.trans b/resources/chars/ascii/row6d.trans
new file mode 100644
index 0000000..407b323
--- /dev/null
+++ b/resources/chars/ascii/row6d.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+6d00 Zhou # Character æ´
+U+6d01 Ji # Character æ´
+U+6d02 Yi # Character æ´
+U+6d03 Hui # Character æ´
+U+6d04 Hui # Character æ´
+U+6d05 Zui # Character æ´
+U+6d06 Cheng # Character æ´
+U+6d07 Yin # Character æ´
+U+6d08 Wei # Character æ´
+U+6d09 Hou # Character æ´
+U+6d0a Jian # Character æ´
+U+6d0b Yang # Character æ´
+U+6d0c Lie # Character æ´
+U+6d0d Si # Character æ´
+U+6d0e Ji # Character æ´
+U+6d0f Er # Character æ´
+U+6d10 Xing # Character æ´
+U+6d11 Fu # Character æ´
+U+6d12 Sa # Character æ´
+U+6d13 Suo # Character æ´
+U+6d14 Zhi # Character æ´
+U+6d15 Yin # Character æ´
+U+6d16 Wu # Character æ´
+U+6d17 Xi # Character æ´
+U+6d18 Kao # Character æ´
+U+6d19 Zhu # Character æ´
+U+6d1a Jiang # Character æ´
+U+6d1b Luo # Character æ´
+U+6d1c ? # Character æ´
+U+6d1d An # Character æ´
+U+6d1e Dong # Character æ´
+U+6d1f Yi # Character æ´
+U+6d20 Mou # Character æ´
+U+6d21 Lei # Character æ´¡
+U+6d22 Yi # Character æ´¢
+U+6d23 Mi # Character æ´£
+U+6d24 Quan # Character æ´¤
+U+6d25 Jin # Character æ´¥
+U+6d26 Mo # Character æ´¦
+U+6d27 Wei # Character æ´§
+U+6d28 Xiao # Character æ´¨
+U+6d29 Xie # Character æ´©
+U+6d2a Hong # Character æ´ª
+U+6d2b Xu # Character æ´«
+U+6d2c Shuo # Character æ´¬
+U+6d2d Kuang # Character æ´
+U+6d2e Tao # Character æ´®
+U+6d2f Qie # Character æ´¯
+U+6d30 Ju # Character æ´°
+U+6d31 Er # Character æ´±
+U+6d32 Zhou # Character æ´²
+U+6d33 Ru # Character æ´³
+U+6d34 Ping # Character æ´´
+U+6d35 Xun # Character æ´µ
+U+6d36 Xiong # Character æ´¶
+U+6d37 Zhi # Character æ´·
+U+6d38 Guang # Character æ´¸
+U+6d39 Huan # Character æ´¹
+U+6d3a Ming # Character æ´º
+U+6d3b Huo # Character æ´»
+U+6d3c Wa # Character æ´¼
+U+6d3d Qia # Character æ´½
+U+6d3e Pai # Character æ´¾
+U+6d3f Wu # Character æ´¿
+U+6d40 Qu # Character æµ
+U+6d41 Liu # Character æµ
+U+6d42 Yi # Character æµ
+U+6d43 Jia # Character æµ
+U+6d44 Jing # Character æµ
+U+6d45 Qian # Character æµ
+U+6d46 Jiang # Character æµ
+U+6d47 Jiao # Character æµ
+U+6d48 Cheng # Character æµ
+U+6d49 Shi # Character æµ
+U+6d4a Zhuo # Character æµ
+U+6d4b Ce # Character æµ
+U+6d4c Pal # Character æµ
+U+6d4d Kuai # Character æµ
+U+6d4e Ji # Character æµ
+U+6d4f Liu # Character æµ
+U+6d50 Chan # Character æµ
+U+6d51 Hun # Character æµ
+U+6d52 Hu # Character æµ
+U+6d53 Nong # Character æµ
+U+6d54 Xun # Character æµ
+U+6d55 Jin # Character æµ
+U+6d56 Lie # Character æµ
+U+6d57 Qiu # Character æµ
+U+6d58 Wei # Character æµ
+U+6d59 Zhe # Character æµ
+U+6d5a Jun # Character æµ
+U+6d5b Han # Character æµ
+U+6d5c Bang # Character æµ
+U+6d5d Mang # Character æµ
+U+6d5e Zhuo # Character æµ
+U+6d5f You # Character æµ
+U+6d60 Xi # Character æµ
+U+6d61 Bo # Character 浡
+U+6d62 Dou # Character æµ¢
+U+6d63 Wan # Character æµ£
+U+6d64 Hong # Character 浤
+U+6d65 Yi # Character æµ¥
+U+6d66 Pu # Character 浦
+U+6d67 Ying # Character 浧
+U+6d68 Lan # Character 浨
+U+6d69 Hao # Character 浩
+U+6d6a Lang # Character 浪
+U+6d6b Han # Character 浫
+U+6d6c Li # Character 浬
+U+6d6d Geng # Character æµ
+U+6d6e Fu # Character æµ®
+U+6d6f Wu # Character 浯
+U+6d70 Lian # Character æµ°
+U+6d71 Chun # Character æµ±
+U+6d72 Feng # Character æµ²
+U+6d73 Yi # Character æµ³
+U+6d74 Yu # Character æµ´
+U+6d75 Tong # Character æµµ
+U+6d76 Lao # Character 浶
+U+6d77 Hai # Character æµ·
+U+6d78 Jin # Character 浸
+U+6d79 Jia # Character æµ¹
+U+6d7a Chong # Character 浺
+U+6d7b Weng # Character æµ»
+U+6d7c Mei # Character æµ¼
+U+6d7d Sui # Character æµ½
+U+6d7e Cheng # Character æµ¾
+U+6d7f Pei # Character 浿
+U+6d80 Xian # Character æ¶
+U+6d81 Shen # Character æ¶
+U+6d82 Tu # Character æ¶
+U+6d83 Kun # Character æ¶
+U+6d84 Pin # Character æ¶
+U+6d85 Nie # Character æ¶
+U+6d86 Han # Character æ¶
+U+6d87 Jing # Character æ¶
+U+6d88 Xiao # Character æ¶
+U+6d89 She # Character æ¶
+U+6d8a Nian # Character æ¶
+U+6d8b Tu # Character æ¶
+U+6d8c Yong # Character æ¶
+U+6d8d Xiao # Character æ¶
+U+6d8e Xian # Character æ¶
+U+6d8f Ting # Character æ¶
+U+6d90 E # Character æ¶
+U+6d91 Su # Character æ¶
+U+6d92 Tun # Character æ¶
+U+6d93 Juan # Character æ¶
+U+6d94 Cen # Character æ¶
+U+6d95 Ti # Character æ¶
+U+6d96 Li # Character æ¶
+U+6d97 Shui # Character æ¶
+U+6d98 Si # Character æ¶
+U+6d99 Lei # Character æ¶
+U+6d9a Shui # Character æ¶
+U+6d9b Tao # Character æ¶
+U+6d9c Du # Character æ¶
+U+6d9d Lao # Character æ¶
+U+6d9e Lai # Character æ¶
+U+6d9f Lian # Character æ¶
+U+6da0 Wei # Character æ¶
+U+6da1 Wo # Character 涡
+U+6da2 Yun # Character 涢
+U+6da3 Huan # Character 涣
+U+6da4 Di # Character 涤
+U+6da5 ? # Character 涥
+U+6da6 Run # Character 润
+U+6da7 Jian # Character 涧
+U+6da8 Zhang # Character 涨
+U+6da9 Se # Character 涩
+U+6daa Fu # Character 涪
+U+6dab Guan # Character 涫
+U+6dac Xing # Character 涬
+U+6dad Shou # Character æ¶
+U+6dae Shuan # Character 涮
+U+6daf Ya # Character 涯
+U+6db0 Chuo # Character 涰
+U+6db1 Zhang # Character 涱
+U+6db2 Ye # Character 液
+U+6db3 Kong # Character 涳
+U+6db4 Wo # Character 涴
+U+6db5 Han # Character 涵
+U+6db6 Tuo # Character 涶
+U+6db7 Dong # Character 涷
+U+6db8 He # Character 涸
+U+6db9 Wo # Character 涹
+U+6dba Ju # Character 涺
+U+6dbb Gan # Character 涻
+U+6dbc Liang # Character 涼
+U+6dbd Hun # Character 涽
+U+6dbe Ta # Character 涾
+U+6dbf Zhuo # Character 涿
+U+6dc0 Dian # Character æ·
+U+6dc1 Qie # Character æ·
+U+6dc2 De # Character æ·
+U+6dc3 Juan # Character æ·
+U+6dc4 Zi # Character æ·
+U+6dc5 Xi # Character æ·
+U+6dc6 Yao # Character æ·
+U+6dc7 Qi # Character æ·
+U+6dc8 Gu # Character æ·
+U+6dc9 Guo # Character æ·
+U+6dca Han # Character æ·
+U+6dcb Lin # Character æ·
+U+6dcc Tang # Character æ·
+U+6dcd Zhou # Character æ·
+U+6dce Peng # Character æ·
+U+6dcf Hao # Character æ·
+U+6dd0 Chang # Character æ·
+U+6dd1 Shu # Character æ·
+U+6dd2 Qi # Character æ·
+U+6dd3 Fang # Character æ·
+U+6dd4 Chi # Character æ·
+U+6dd5 Lu # Character æ·
+U+6dd6 Nao # Character æ·
+U+6dd7 Ju # Character æ·
+U+6dd8 Tao # Character æ·
+U+6dd9 Cong # Character æ·
+U+6dda Lei # Character æ·
+U+6ddb Zhi # Character æ·
+U+6ddc Peng # Character æ·
+U+6ddd Fei # Character æ·
+U+6dde Song # Character æ·
+U+6ddf Tian # Character æ·
+U+6de0 Pi # Character æ·
+U+6de1 Dan # Character æ·¡
+U+6de2 Yu # Character æ·¢
+U+6de3 Ni # Character æ·£
+U+6de4 Yu # Character æ·¤
+U+6de5 Lu # Character æ·¥
+U+6de6 Gan # Character æ·¦
+U+6de7 Mi # Character æ·§
+U+6de8 Jing # Character æ·¨
+U+6de9 Ling # Character æ·©
+U+6dea Lun # Character æ·ª
+U+6deb Yin # Character æ·«
+U+6dec Cui # Character æ·¬
+U+6ded Qu # Character æ·
+U+6dee Huai # Character æ·®
+U+6def Yu # Character æ·¯
+U+6df0 Nian # Character æ·°
+U+6df1 Shen # Character æ·±
+U+6df2 Piao # Character æ·²
+U+6df3 Chun # Character æ·³
+U+6df4 Wa # Character æ·´
+U+6df5 Yuan # Character æ·µ
+U+6df6 Lai # Character æ·¶
+U+6df7 Hun # Character æ··
+U+6df8 Qing # Character æ·¸
+U+6df9 Yan # Character æ·¹
+U+6dfa Qian # Character æ·º
+U+6dfb Tian # Character æ·»
+U+6dfc Miao # Character æ·¼
+U+6dfd Zhi # Character æ·½
+U+6dfe Yin # Character æ·¾
+U+6dff Mi # Character æ·¿
diff --git a/resources/chars/ascii/row6e.trans b/resources/chars/ascii/row6e.trans
new file mode 100644
index 0000000..e9fe6e8
--- /dev/null
+++ b/resources/chars/ascii/row6e.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+6e00 Ben # Character æ¸
+U+6e01 Yuan # Character æ¸
+U+6e02 Wen # Character æ¸
+U+6e03 Re # Character æ¸
+U+6e04 Fei # Character æ¸
+U+6e05 Qing # Character æ¸
+U+6e06 Yuan # Character æ¸
+U+6e07 Ke # Character æ¸
+U+6e08 Ji # Character æ¸
+U+6e09 She # Character æ¸
+U+6e0a Yuan # Character æ¸
+U+6e0b Shibui # Character æ¸
+U+6e0c Lu # Character æ¸
+U+6e0d Zi # Character æ¸
+U+6e0e Du # Character æ¸
+U+6e0f ? # Character æ¸
+U+6e10 Jian # Character æ¸
+U+6e11 Min # Character æ¸
+U+6e12 Pi # Character æ¸
+U+6e13 Tani # Character æ¸
+U+6e14 Yu # Character æ¸
+U+6e15 Yuan # Character æ¸
+U+6e16 Shen # Character æ¸
+U+6e17 Shen # Character æ¸
+U+6e18 Rou # Character æ¸
+U+6e19 Huan # Character æ¸
+U+6e1a Zhu # Character æ¸
+U+6e1b Jian # Character æ¸
+U+6e1c Nuan # Character æ¸
+U+6e1d Yu # Character æ¸
+U+6e1e Qiu # Character æ¸
+U+6e1f Ting # Character æ¸
+U+6e20 Qu # Character æ¸
+U+6e21 Du # Character 渡
+U+6e22 Feng # Character 渢
+U+6e23 Zha # Character 渣
+U+6e24 Bo # Character 渤
+U+6e25 Wo # Character 渥
+U+6e26 Wo # Character 渦
+U+6e27 Di # Character 渧
+U+6e28 Wei # Character 渨
+U+6e29 Wen # Character 温
+U+6e2a Ru # Character 渪
+U+6e2b Xie # Character 渫
+U+6e2c Ce # Character 測
+U+6e2d Wei # Character æ¸
+U+6e2e Ge # Character 渮
+U+6e2f Gang # Character 港
+U+6e30 Yan # Character 渰
+U+6e31 Hong # Character 渱
+U+6e32 Xuan # Character 渲
+U+6e33 Mi # Character 渳
+U+6e34 Ke # Character 渴
+U+6e35 Mao # Character 渵
+U+6e36 Ying # Character 渶
+U+6e37 Yan # Character 渷
+U+6e38 You # Character 游
+U+6e39 Hong # Character 渹
+U+6e3a Miao # Character 渺
+U+6e3b Xing # Character 渻
+U+6e3c Mei # Character 渼
+U+6e3d Zai # Character 渽
+U+6e3e Hun # Character 渾
+U+6e3f Nai # Character 渿
+U+6e40 Kui # Character æ¹
+U+6e41 Shi # Character æ¹
+U+6e42 E # Character æ¹
+U+6e43 Pai # Character æ¹
+U+6e44 Mei # Character æ¹
+U+6e45 Lian # Character æ¹
+U+6e46 Qi # Character æ¹
+U+6e47 Qi # Character æ¹
+U+6e48 Mei # Character æ¹
+U+6e49 Tian # Character æ¹
+U+6e4a Cou # Character æ¹
+U+6e4b Wei # Character æ¹
+U+6e4c Can # Character æ¹
+U+6e4d Tuan # Character æ¹
+U+6e4e Mian # Character æ¹
+U+6e4f Hui # Character æ¹
+U+6e50 Mo # Character æ¹
+U+6e51 Xu # Character æ¹
+U+6e52 Ji # Character æ¹
+U+6e53 Pen # Character æ¹
+U+6e54 Jian # Character æ¹
+U+6e55 Jian # Character æ¹
+U+6e56 Hu # Character æ¹
+U+6e57 Feng # Character æ¹
+U+6e58 Xiang # Character æ¹
+U+6e59 Yi # Character æ¹
+U+6e5a Yin # Character æ¹
+U+6e5b Zhan # Character æ¹
+U+6e5c Shi # Character æ¹
+U+6e5d Jie # Character æ¹
+U+6e5e Cheng # Character æ¹
+U+6e5f Huang # Character æ¹
+U+6e60 Tan # Character æ¹
+U+6e61 Yu # Character 湡
+U+6e62 Bi # Character æ¹¢
+U+6e63 Min # Character æ¹£
+U+6e64 Shi # Character 湤
+U+6e65 Tu # Character æ¹¥
+U+6e66 Sheng # Character 湦
+U+6e67 Yong # Character 湧
+U+6e68 Qu # Character 湨
+U+6e69 Zhong # Character 湩
+U+6e6a Suei # Character 湪
+U+6e6b Jiu # Character 湫
+U+6e6c Jiao # Character 湬
+U+6e6d Qiou # Character æ¹
+U+6e6e Yin # Character æ¹®
+U+6e6f Tang # Character 湯
+U+6e70 Long # Character æ¹°
+U+6e71 Huo # Character æ¹±
+U+6e72 Yuan # Character æ¹²
+U+6e73 Nan # Character æ¹³
+U+6e74 Ban # Character æ¹´
+U+6e75 You # Character æ¹µ
+U+6e76 Quan # Character 湶
+U+6e77 Chui # Character æ¹·
+U+6e78 Liang # Character 湸
+U+6e79 Chan # Character æ¹¹
+U+6e7a Yan # Character 湺
+U+6e7b Chun # Character æ¹»
+U+6e7c Nie # Character æ¹¼
+U+6e7d Zi # Character æ¹½
+U+6e7e Wan # Character æ¹¾
+U+6e7f Shi # Character 湿
+U+6e80 Man # Character æº
+U+6e81 Ying # Character æº
+U+6e82 Ratsu # Character æº
+U+6e83 Kui # Character æº
+U+6e84 ? # Character æº
+U+6e85 Jian # Character æº
+U+6e86 Xu # Character æº
+U+6e87 Lu # Character æº
+U+6e88 Gui # Character æº
+U+6e89 Gai # Character æº
+U+6e8a ? # Character æº
+U+6e8b ? # Character æº
+U+6e8c Po # Character æº
+U+6e8d Jin # Character æº
+U+6e8e Gui # Character æº
+U+6e8f Tang # Character æº
+U+6e90 Yuan # Character æº
+U+6e91 Suo # Character æº
+U+6e92 Yuan # Character æº
+U+6e93 Lian # Character æº
+U+6e94 Yao # Character æº
+U+6e95 Meng # Character æº
+U+6e96 Zhun # Character æº
+U+6e97 Sheng # Character æº
+U+6e98 Ke # Character æº
+U+6e99 Tai # Character æº
+U+6e9a Da # Character æº
+U+6e9b Wa # Character æº
+U+6e9c Liu # Character æº
+U+6e9d Gou # Character æº
+U+6e9e Sao # Character æº
+U+6e9f Ming # Character æº
+U+6ea0 Zha # Character æº
+U+6ea1 Shi # Character 溡
+U+6ea2 Yi # Character 溢
+U+6ea3 Lun # Character 溣
+U+6ea4 Ma # Character 溤
+U+6ea5 Pu # Character 溥
+U+6ea6 Wei # Character 溦
+U+6ea7 Li # Character 溧
+U+6ea8 Cai # Character 溨
+U+6ea9 Wu # Character 溩
+U+6eaa Xi # Character 溪
+U+6eab Wen # Character 溫
+U+6eac Qiang # Character 溬
+U+6ead Ze # Character æº
+U+6eae Shi # Character 溮
+U+6eaf Su # Character 溯
+U+6eb0 Yi # Character 溰
+U+6eb1 Zhen # Character 溱
+U+6eb2 Sou # Character 溲
+U+6eb3 Yun # Character 溳
+U+6eb4 Xiu # Character 溴
+U+6eb5 Yin # Character 溵
+U+6eb6 Rong # Character 溶
+U+6eb7 Hun # Character 溷
+U+6eb8 Su # Character 溸
+U+6eb9 Su # Character 溹
+U+6eba Ni # Character 溺
+U+6ebb Ta # Character 溻
+U+6ebc Shi # Character 溼
+U+6ebd Ru # Character 溽
+U+6ebe Wei # Character 溾
+U+6ebf Pan # Character 溿
+U+6ec0 Chu # Character æ»
+U+6ec1 Chu # Character æ»
+U+6ec2 Pang # Character æ»
+U+6ec3 Weng # Character æ»
+U+6ec4 Cang # Character æ»
+U+6ec5 Mie # Character æ»
+U+6ec6 He # Character æ»
+U+6ec7 Dian # Character æ»
+U+6ec8 Hao # Character æ»
+U+6ec9 Huang # Character æ»
+U+6eca Xi # Character æ»
+U+6ecb Zi # Character æ»
+U+6ecc Di # Character æ»
+U+6ecd Zhi # Character æ»
+U+6ece Ying # Character æ»
+U+6ecf Fu # Character æ»
+U+6ed0 Jie # Character æ»
+U+6ed1 Hua # Character æ»
+U+6ed2 Ge # Character æ»
+U+6ed3 Zi # Character æ»
+U+6ed4 Tao # Character æ»
+U+6ed5 Teng # Character æ»
+U+6ed6 Sui # Character æ»
+U+6ed7 Bi # Character æ»
+U+6ed8 Jiao # Character æ»
+U+6ed9 Hui # Character æ»
+U+6eda Gun # Character æ»
+U+6edb Yin # Character æ»
+U+6edc Gao # Character æ»
+U+6edd Long # Character æ»
+U+6ede Zhi # Character æ»
+U+6edf Yan # Character æ»
+U+6ee0 She # Character æ»
+U+6ee1 Man # Character 满
+U+6ee2 Ying # Character 滢
+U+6ee3 Chun # Character 滣
+U+6ee4 Lu # Character 滤
+U+6ee5 Lan # Character 滥
+U+6ee6 Luan # Character 滦
+U+6ee7 ? # Character 滧
+U+6ee8 Bin # Character 滨
+U+6ee9 Tan # Character 滩
+U+6eea Yu # Character 滪
+U+6eeb Sou # Character 滫
+U+6eec Hu # Character 滬
+U+6eed Bi # Character æ»
+U+6eee Biao # Character æ»®
+U+6eef Zhi # Character 滯
+U+6ef0 Jiang # Character æ»°
+U+6ef1 Kou # Character æ»±
+U+6ef2 Shen # Character 滲
+U+6ef3 Shang # Character 滳
+U+6ef4 Di # Character æ»´
+U+6ef5 Mi # Character 滵
+U+6ef6 Ao # Character 滶
+U+6ef7 Lu # Character æ»·
+U+6ef8 Hu # Character 滸
+U+6ef9 Hu # Character 滹
+U+6efa You # Character 滺
+U+6efb Chan # Character æ»»
+U+6efc Fan # Character 滼
+U+6efd Yong # Character 滽
+U+6efe Gun # Character 滾
+U+6eff Man # Character 滿
diff --git a/resources/chars/ascii/row6f.trans b/resources/chars/ascii/row6f.trans
new file mode 100644
index 0000000..00101af
--- /dev/null
+++ b/resources/chars/ascii/row6f.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+6f00 Qing # Character æ¼
+U+6f01 Yu # Character æ¼
+U+6f02 Piao # Character æ¼
+U+6f03 Ji # Character æ¼
+U+6f04 Ya # Character æ¼
+U+6f05 Jiao # Character æ¼
+U+6f06 Qi # Character æ¼
+U+6f07 Xi # Character æ¼
+U+6f08 Ji # Character æ¼
+U+6f09 Lu # Character æ¼
+U+6f0a Lu # Character æ¼
+U+6f0b Long # Character æ¼
+U+6f0c Jin # Character æ¼
+U+6f0d Guo # Character æ¼
+U+6f0e Cong # Character æ¼
+U+6f0f Lou # Character æ¼
+U+6f10 Zhi # Character æ¼
+U+6f11 Gai # Character æ¼
+U+6f12 Qiang # Character æ¼
+U+6f13 Li # Character æ¼
+U+6f14 Yan # Character æ¼
+U+6f15 Cao # Character æ¼
+U+6f16 Jiao # Character æ¼
+U+6f17 Cong # Character æ¼
+U+6f18 Qun # Character æ¼
+U+6f19 Tuan # Character æ¼
+U+6f1a Ou # Character æ¼
+U+6f1b Teng # Character æ¼
+U+6f1c Ye # Character æ¼
+U+6f1d Xi # Character æ¼
+U+6f1e Mi # Character æ¼
+U+6f1f Tang # Character æ¼
+U+6f20 Mo # Character æ¼
+U+6f21 Shang # Character 漡
+U+6f22 Han # Character æ¼¢
+U+6f23 Lian # Character æ¼£
+U+6f24 Lan # Character 漤
+U+6f25 Wa # Character æ¼¥
+U+6f26 Li # Character 漦
+U+6f27 Qian # Character 漧
+U+6f28 Feng # Character 漨
+U+6f29 Xuan # Character 漩
+U+6f2a Yi # Character 漪
+U+6f2b Man # Character 漫
+U+6f2c Zi # Character 漬
+U+6f2d Mang # Character æ¼
+U+6f2e Kang # Character æ¼®
+U+6f2f Lei # Character 漯
+U+6f30 Peng # Character æ¼°
+U+6f31 Shu # Character æ¼±
+U+6f32 Zhang # Character æ¼²
+U+6f33 Zhang # Character æ¼³
+U+6f34 Chong # Character æ¼´
+U+6f35 Xu # Character æ¼µ
+U+6f36 Huan # Character 漶
+U+6f37 Kuo # Character æ¼·
+U+6f38 Jian # Character 漸
+U+6f39 Yan # Character æ¼¹
+U+6f3a Chuang # Character 漺
+U+6f3b Liao # Character æ¼»
+U+6f3c Cui # Character æ¼¼
+U+6f3d Ti # Character æ¼½
+U+6f3e Yang # Character æ¼¾
+U+6f3f Jiang # Character 漿
+U+6f40 Cong # Character æ½
+U+6f41 Ying # Character æ½
+U+6f42 Hong # Character æ½
+U+6f43 Xun # Character æ½
+U+6f44 Shu # Character æ½
+U+6f45 Guan # Character æ½
+U+6f46 Ying # Character æ½
+U+6f47 Xiao # Character æ½
+U+6f48 ? # Character æ½
+U+6f49 ? # Character æ½
+U+6f4a Xu # Character æ½
+U+6f4b Lian # Character æ½
+U+6f4c Zhi # Character æ½
+U+6f4d Wei # Character æ½
+U+6f4e Pi # Character æ½
+U+6f4f Jue # Character æ½
+U+6f50 Jiao # Character æ½
+U+6f51 Po # Character æ½
+U+6f52 Dang # Character æ½
+U+6f53 Hui # Character æ½
+U+6f54 Jie # Character æ½
+U+6f55 Wu # Character æ½
+U+6f56 Pa # Character æ½
+U+6f57 Ji # Character æ½
+U+6f58 Pan # Character æ½
+U+6f59 Gui # Character æ½
+U+6f5a Xiao # Character æ½
+U+6f5b Qian # Character æ½
+U+6f5c Qian # Character æ½
+U+6f5d Xi # Character æ½
+U+6f5e Lu # Character æ½
+U+6f5f Xi # Character æ½
+U+6f60 Xuan # Character æ½
+U+6f61 Dun # Character 潡
+U+6f62 Huang # Character æ½¢
+U+6f63 Min # Character æ½£
+U+6f64 Run # Character 潤
+U+6f65 Su # Character æ½¥
+U+6f66 Liao # Character 潦
+U+6f67 Zhen # Character 潧
+U+6f68 Zhong # Character 潨
+U+6f69 Yi # Character 潩
+U+6f6a Di # Character 潪
+U+6f6b Wan # Character 潫
+U+6f6c Dan # Character 潬
+U+6f6d Tan # Character æ½
+U+6f6e Chao # Character æ½®
+U+6f6f Xun # Character 潯
+U+6f70 Kui # Character æ½°
+U+6f71 Yie # Character æ½±
+U+6f72 Shao # Character æ½²
+U+6f73 Tu # Character æ½³
+U+6f74 Zhu # Character æ½´
+U+6f75 San # Character æ½µ
+U+6f76 Hei # Character 潶
+U+6f77 Bi # Character æ½·
+U+6f78 Shan # Character 潸
+U+6f79 Chan # Character æ½¹
+U+6f7a Chan # Character 潺
+U+6f7b Shu # Character æ½»
+U+6f7c Tong # Character æ½¼
+U+6f7d Pu # Character æ½½
+U+6f7e Lin # Character æ½¾
+U+6f7f Wei # Character 潿
+U+6f80 Se # Character æ¾
+U+6f81 Se # Character æ¾
+U+6f82 Cheng # Character æ¾
+U+6f83 Jiong # Character æ¾
+U+6f84 Cheng # Character æ¾
+U+6f85 Hua # Character æ¾
+U+6f86 Jiao # Character æ¾
+U+6f87 Lao # Character æ¾
+U+6f88 Che # Character æ¾
+U+6f89 Gan # Character æ¾
+U+6f8a Cun # Character æ¾
+U+6f8b Heng # Character æ¾
+U+6f8c Si # Character æ¾
+U+6f8d Shu # Character æ¾
+U+6f8e Peng # Character æ¾
+U+6f8f Han # Character æ¾
+U+6f90 Yun # Character æ¾
+U+6f91 Liu # Character æ¾
+U+6f92 Hong # Character æ¾
+U+6f93 Fu # Character æ¾
+U+6f94 Hao # Character æ¾
+U+6f95 He # Character æ¾
+U+6f96 Xian # Character æ¾
+U+6f97 Jian # Character æ¾
+U+6f98 Shan # Character æ¾
+U+6f99 Xi # Character æ¾
+U+6f9a Oki # Character æ¾
+U+6f9b ? # Character æ¾
+U+6f9c Lan # Character æ¾
+U+6f9d ? # Character æ¾
+U+6f9e Yu # Character æ¾
+U+6f9f Lin # Character æ¾
+U+6fa0 Min # Character æ¾
+U+6fa1 Zao # Character 澡
+U+6fa2 Dang # Character æ¾¢
+U+6fa3 Wan # Character æ¾£
+U+6fa4 Ze # Character 澤
+U+6fa5 Xie # Character æ¾¥
+U+6fa6 Yu # Character 澦
+U+6fa7 Li # Character 澧
+U+6fa8 Shi # Character 澨
+U+6fa9 Xue # Character 澩
+U+6faa Ling # Character 澪
+U+6fab Man # Character 澫
+U+6fac Zi # Character 澬
+U+6fad Yong # Character æ¾
+U+6fae Kuai # Character æ¾®
+U+6faf Can # Character 澯
+U+6fb0 Lian # Character æ¾°
+U+6fb1 Dian # Character æ¾±
+U+6fb2 Ye # Character æ¾²
+U+6fb3 Ao # Character æ¾³
+U+6fb4 Huan # Character æ¾´
+U+6fb5 Zhen # Character æ¾µ
+U+6fb6 Chan # Character 澶
+U+6fb7 Man # Character æ¾·
+U+6fb8 Dan # Character 澸
+U+6fb9 Dan # Character æ¾¹
+U+6fba Yi # Character 澺
+U+6fbb Sui # Character æ¾»
+U+6fbc Pi # Character æ¾¼
+U+6fbd Ju # Character æ¾½
+U+6fbe Ta # Character æ¾¾
+U+6fbf Qin # Character 澿
+U+6fc0 Ji # Character æ¿
+U+6fc1 Zhuo # Character æ¿
+U+6fc2 Lian # Character æ¿
+U+6fc3 Nong # Character æ¿
+U+6fc4 Guo # Character æ¿
+U+6fc5 Jin # Character æ¿
+U+6fc6 Fen # Character æ¿
+U+6fc7 Se # Character æ¿
+U+6fc8 Ji # Character æ¿
+U+6fc9 Sui # Character æ¿
+U+6fca Hui # Character æ¿
+U+6fcb Chu # Character æ¿
+U+6fcc Ta # Character æ¿
+U+6fcd Song # Character æ¿
+U+6fce Ding # Character æ¿
+U+6fcf ? # Character æ¿
+U+6fd0 Zhu # Character æ¿
+U+6fd1 Lai # Character æ¿
+U+6fd2 Bin # Character æ¿
+U+6fd3 Lian # Character æ¿
+U+6fd4 Mi # Character æ¿
+U+6fd5 Shi # Character æ¿
+U+6fd6 Shu # Character æ¿
+U+6fd7 Mi # Character æ¿
+U+6fd8 Ning # Character æ¿
+U+6fd9 Ying # Character æ¿
+U+6fda Ying # Character æ¿
+U+6fdb Meng # Character æ¿
+U+6fdc Jin # Character æ¿
+U+6fdd Qi # Character æ¿
+U+6fde Pi # Character æ¿
+U+6fdf Ji # Character æ¿
+U+6fe0 Hao # Character æ¿
+U+6fe1 Ru # Character æ¿¡
+U+6fe2 Zui # Character æ¿¢
+U+6fe3 Wo # Character æ¿£
+U+6fe4 Tao # Character 濤
+U+6fe5 Yin # Character æ¿¥
+U+6fe6 Yin # Character 濦
+U+6fe7 Dui # Character 濧
+U+6fe8 Ci # Character 濨
+U+6fe9 Huo # Character æ¿©
+U+6fea Jing # Character 濪
+U+6feb Lan # Character æ¿«
+U+6fec Jun # Character 濬
+U+6fed Ai # Character æ¿
+U+6fee Pu # Character æ¿®
+U+6fef Zhuo # Character 濯
+U+6ff0 Wei # Character æ¿°
+U+6ff1 Bin # Character 濱
+U+6ff2 Gu # Character 濲
+U+6ff3 Qian # Character 濳
+U+6ff4 Xing # Character æ¿´
+U+6ff5 Hama # Character 濵
+U+6ff6 Kuo # Character 濶
+U+6ff7 Fei # Character æ¿·
+U+6ff8 ? # Character 濸
+U+6ff9 Boku # Character 濹
+U+6ffa Jian # Character 濺
+U+6ffb Wei # Character æ¿»
+U+6ffc Luo # Character 濼
+U+6ffd Zan # Character 濽
+U+6ffe Lu # Character 濾
+U+6fff Li # Character æ¿¿
diff --git a/resources/chars/ascii/row70.trans b/resources/chars/ascii/row70.trans
new file mode 100644
index 0000000..f03e419
--- /dev/null
+++ b/resources/chars/ascii/row70.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+7000 You # Character ç
+U+7001 Yang # Character ç
+U+7002 Lu # Character ç
+U+7003 Si # Character ç
+U+7004 Jie # Character ç
+U+7005 Ying # Character ç
+U+7006 Du # Character ç
+U+7007 Wang # Character ç
+U+7008 Hui # Character ç
+U+7009 Xie # Character ç
+U+700a Pan # Character ç
+U+700b Shen # Character ç
+U+700c Biao # Character ç
+U+700d Chan # Character ç
+U+700e Mo # Character ç
+U+700f Liu # Character ç
+U+7010 Jian # Character ç
+U+7011 Pu # Character ç
+U+7012 Se # Character ç
+U+7013 Cheng # Character ç
+U+7014 Gu # Character ç
+U+7015 Bin # Character ç
+U+7016 Huo # Character ç
+U+7017 Xian # Character ç
+U+7018 Lu # Character ç
+U+7019 Qin # Character ç
+U+701a Han # Character ç
+U+701b Ying # Character ç
+U+701c Yong # Character ç
+U+701d Li # Character ç
+U+701e Jing # Character ç
+U+701f Xiao # Character ç
+U+7020 Ying # Character ç
+U+7021 Sui # Character ç¡
+U+7022 Wei # Character ç¢
+U+7023 Xie # Character ç£
+U+7024 Huai # Character ç¤
+U+7025 Hao # Character ç¥
+U+7026 Zhu # Character ç¦
+U+7027 Long # Character ç§
+U+7028 Lai # Character ç¨
+U+7029 Dui # Character ç©
+U+702a Fan # Character çª
+U+702b Hu # Character ç«
+U+702c Lai # Character ç¬
+U+702d ? # Character ç
+U+702e ? # Character ç®
+U+702f Ying # Character ç¯
+U+7030 Mi # Character ç°
+U+7031 Ji # Character ç±
+U+7032 Lian # Character ç²
+U+7033 Jian # Character ç³
+U+7034 Ying # Character ç´
+U+7035 Fen # Character çµ
+U+7036 Lin # Character ç¶
+U+7037 Yi # Character ç·
+U+7038 Jian # Character ç¸
+U+7039 Yue # Character ç¹
+U+703a Chan # Character çº
+U+703b Dai # Character ç»
+U+703c Rang # Character ç¼
+U+703d Jian # Character ç½
+U+703e Lan # Character ç¾
+U+703f Fan # Character ç¿
+U+7040 Shuang # Character ç
+U+7041 Yuan # Character ç
+U+7042 Zhuo # Character ç
+U+7043 Feng # Character ç
+U+7044 She # Character ç
+U+7045 Lei # Character ç
+U+7046 Lan # Character ç
+U+7047 Cong # Character ç
+U+7048 Qu # Character ç
+U+7049 Yong # Character ç
+U+704a Qian # Character ç
+U+704b Fa # Character ç
+U+704c Guan # Character ç
+U+704d Que # Character ç
+U+704e Yan # Character ç
+U+704f Hao # Character ç
+U+7050 Hyeng # Character ç
+U+7051 Sa # Character ç
+U+7052 Zan # Character ç
+U+7053 Luan # Character ç
+U+7054 Yan # Character ç
+U+7055 Li # Character ç
+U+7056 Mi # Character ç
+U+7057 Shan # Character ç
+U+7058 Tan # Character ç
+U+7059 Dang # Character ç
+U+705a Jiao # Character ç
+U+705b Chan # Character ç
+U+705c ? # Character ç
+U+705d Hao # Character ç
+U+705e Ba # Character ç
+U+705f Zhu # Character ç
+U+7060 Lan # Character ç
+U+7061 Lan # Character ç¡
+U+7062 Nang # Character ç¢
+U+7063 Wan # Character ç£
+U+7064 Luan # Character ç¤
+U+7065 Xun # Character ç¥
+U+7066 Xian # Character ç¦
+U+7067 Yan # Character ç§
+U+7068 Gan # Character ç¨
+U+7069 Yan # Character ç©
+U+706a Yu # Character çª
+U+706b Huo # Character ç«
+U+706c Si # Character ç¬
+U+706d Mie # Character ç
+U+706e Guang # Character ç®
+U+706f Deng # Character ç¯
+U+7070 Hui # Character ç°
+U+7071 Xiao # Character ç±
+U+7072 Xiao # Character ç²
+U+7073 Hu # Character ç³
+U+7074 Hong # Character ç´
+U+7075 Ling # Character çµ
+U+7076 Zao # Character ç¶
+U+7077 Zhuan # Character ç·
+U+7078 Jiu # Character ç¸
+U+7079 Zha # Character ç¹
+U+707a Xie # Character çº
+U+707b Chi # Character ç»
+U+707c Zhuo # Character ç¼
+U+707d Zai # Character ç½
+U+707e Zai # Character ç¾
+U+707f Can # Character ç¿
+U+7080 Yang # Character ç
+U+7081 Qi # Character ç
+U+7082 Zhong # Character ç
+U+7083 Fen # Character ç
+U+7084 Niu # Character ç
+U+7085 Jiong # Character ç
+U+7086 Wen # Character ç
+U+7087 Po # Character ç
+U+7088 Yi # Character ç
+U+7089 Lu # Character ç
+U+708a Chui # Character ç
+U+708b Pi # Character ç
+U+708c Kai # Character ç
+U+708d Pan # Character ç
+U+708e Yan # Character ç
+U+708f Kai # Character ç
+U+7090 Pang # Character ç
+U+7091 Mu # Character ç
+U+7092 Chao # Character ç
+U+7093 Liao # Character ç
+U+7094 Gui # Character ç
+U+7095 Kang # Character ç
+U+7096 Tun # Character ç
+U+7097 Guang # Character ç
+U+7098 Xin # Character ç
+U+7099 Zhi # Character ç
+U+709a Guang # Character ç
+U+709b Guang # Character ç
+U+709c Wei # Character ç
+U+709d Qiang # Character ç
+U+709e ? # Character ç
+U+709f Da # Character ç
+U+70a0 Xia # Character ç
+U+70a1 Zheng # Character ç¡
+U+70a2 Zhu # Character ç¢
+U+70a3 Ke # Character ç£
+U+70a4 Zhao # Character ç¤
+U+70a5 Fu # Character ç¥
+U+70a6 Ba # Character ç¦
+U+70a7 Duo # Character ç§
+U+70a8 Duo # Character ç¨
+U+70a9 Ling # Character ç©
+U+70aa Zhuo # Character çª
+U+70ab Xuan # Character ç«
+U+70ac Ju # Character ç¬
+U+70ad Tan # Character ç
+U+70ae Pao # Character ç®
+U+70af Jiong # Character ç¯
+U+70b0 Pao # Character ç°
+U+70b1 Tai # Character ç±
+U+70b2 Tai # Character ç²
+U+70b3 Bing # Character ç³
+U+70b4 Yang # Character ç´
+U+70b5 Tong # Character çµ
+U+70b6 Han # Character ç¶
+U+70b7 Zhu # Character ç·
+U+70b8 Zha # Character ç¸
+U+70b9 Dian # Character ç¹
+U+70ba Wei # Character çº
+U+70bb Shi # Character ç»
+U+70bc Lian # Character ç¼
+U+70bd Chi # Character ç½
+U+70be Huang # Character ç¾
+U+70bf ? # Character ç¿
+U+70c0 Hu # Character ç
+U+70c1 Shuo # Character ç
+U+70c2 Lan # Character ç
+U+70c3 Jing # Character ç
+U+70c4 Jiao # Character ç
+U+70c5 Xu # Character ç
+U+70c6 Xing # Character ç
+U+70c7 Quan # Character ç
+U+70c8 Lie # Character ç
+U+70c9 Huan # Character ç
+U+70ca Yang # Character ç
+U+70cb Xiao # Character ç
+U+70cc Xiu # Character ç
+U+70cd Xian # Character ç
+U+70ce Yin # Character ç
+U+70cf Wu # Character ç
+U+70d0 Zhou # Character ç
+U+70d1 Yao # Character ç
+U+70d2 Shi # Character ç
+U+70d3 Wei # Character ç
+U+70d4 Tong # Character ç
+U+70d5 Xue # Character ç
+U+70d6 Zai # Character ç
+U+70d7 Kai # Character ç
+U+70d8 Hong # Character ç
+U+70d9 Luo # Character ç
+U+70da Xia # Character ç
+U+70db Zhu # Character ç
+U+70dc Xuan # Character ç
+U+70dd Zheng # Character ç
+U+70de Po # Character ç
+U+70df Yan # Character ç
+U+70e0 Hui # Character ç
+U+70e1 Guang # Character ç¡
+U+70e2 Zhe # Character ç¢
+U+70e3 Hui # Character ç£
+U+70e4 Kao # Character ç¤
+U+70e5 ? # Character ç¥
+U+70e6 Fan # Character ç¦
+U+70e7 Shao # Character ç§
+U+70e8 Ye # Character ç¨
+U+70e9 Hui # Character ç©
+U+70ea ? # Character çª
+U+70eb Tang # Character ç«
+U+70ec Jin # Character ç¬
+U+70ed Re # Character ç
+U+70ee ? # Character ç®
+U+70ef Xi # Character ç¯
+U+70f0 Fu # Character ç°
+U+70f1 Jiong # Character ç±
+U+70f2 Che # Character ç²
+U+70f3 Pu # Character ç³
+U+70f4 Jing # Character ç´
+U+70f5 Zhuo # Character çµ
+U+70f6 Ting # Character ç¶
+U+70f7 Wan # Character ç·
+U+70f8 Hai # Character ç¸
+U+70f9 Peng # Character ç¹
+U+70fa Lang # Character çº
+U+70fb Shan # Character ç»
+U+70fc Hu # Character ç¼
+U+70fd Feng # Character ç½
+U+70fe Chi # Character ç¾
+U+70ff Rong # Character ç¿
diff --git a/resources/chars/ascii/row71.trans b/resources/chars/ascii/row71.trans
new file mode 100644
index 0000000..e7cb6be
--- /dev/null
+++ b/resources/chars/ascii/row71.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+7100 Hu # Character ç
+U+7101 Xi # Character ç
+U+7102 Shu # Character ç
+U+7103 He # Character ç
+U+7104 Xun # Character ç
+U+7105 Ku # Character ç
+U+7106 Jue # Character ç
+U+7107 Xiao # Character ç
+U+7108 Xi # Character ç
+U+7109 Yan # Character ç
+U+710a Han # Character ç
+U+710b Zhuang # Character ç
+U+710c Jun # Character ç
+U+710d Di # Character ç
+U+710e Xie # Character ç
+U+710f Ji # Character ç
+U+7110 Wu # Character ç
+U+7111 ? # Character ç
+U+7112 ? # Character ç
+U+7113 Han # Character ç
+U+7114 Yan # Character ç
+U+7115 Huan # Character ç
+U+7116 Men # Character ç
+U+7117 Ju # Character ç
+U+7118 Chou # Character ç
+U+7119 Bei # Character ç
+U+711a Fen # Character ç
+U+711b Lin # Character ç
+U+711c Kun # Character ç
+U+711d Hun # Character ç
+U+711e Tun # Character ç
+U+711f Xi # Character ç
+U+7120 Cui # Character ç
+U+7121 Wu # Character ç¡
+U+7122 Hong # Character ç¢
+U+7123 Ju # Character ç£
+U+7124 Fu # Character ç¤
+U+7125 Wo # Character ç¥
+U+7126 Jiao # Character ç¦
+U+7127 Cong # Character ç§
+U+7128 Feng # Character ç¨
+U+7129 Ping # Character ç©
+U+712a Qiong # Character çª
+U+712b Ruo # Character ç«
+U+712c Xi # Character ç¬
+U+712d Qiong # Character ç
+U+712e Xin # Character ç®
+U+712f Zhuo # Character ç¯
+U+7130 Yan # Character ç°
+U+7131 Yan # Character ç±
+U+7132 Yi # Character ç²
+U+7133 Jue # Character ç³
+U+7134 Yu # Character ç´
+U+7135 Gang # Character çµ
+U+7136 Ran # Character ç¶
+U+7137 Pi # Character ç·
+U+7138 Gu # Character ç¸
+U+7139 ? # Character ç¹
+U+713a Sheng # Character çº
+U+713b Chang # Character ç»
+U+713c Shao # Character ç¼
+U+713d ? # Character ç½
+U+713e ? # Character ç¾
+U+713f ? # Character ç¿
+U+7140 ? # Character ç
+U+7141 Chen # Character ç
+U+7142 He # Character ç
+U+7143 Kui # Character ç
+U+7144 Zhong # Character ç
+U+7145 Duan # Character ç
+U+7146 Xia # Character ç
+U+7147 Hui # Character ç
+U+7148 Feng # Character ç
+U+7149 Lian # Character ç
+U+714a Xuan # Character ç
+U+714b Xing # Character ç
+U+714c Huang # Character ç
+U+714d Jiao # Character ç
+U+714e Jian # Character ç
+U+714f Bi # Character ç
+U+7150 Ying # Character ç
+U+7151 Zhu # Character ç
+U+7152 Wei # Character ç
+U+7153 Tuan # Character ç
+U+7154 Tian # Character ç
+U+7155 Xi # Character ç
+U+7156 Nuan # Character ç
+U+7157 Nuan # Character ç
+U+7158 Chan # Character ç
+U+7159 Yan # Character ç
+U+715a Jiong # Character ç
+U+715b Jiong # Character ç
+U+715c Yu # Character ç
+U+715d Mei # Character ç
+U+715e Sha # Character ç
+U+715f Wei # Character ç
+U+7160 Ye # Character ç
+U+7161 Xin # Character ç
¡
+U+7162 Qiong # Character ç
¢
+U+7163 Rou # Character ç
£
+U+7164 Mei # Character ç
¤
+U+7165 Huan # Character ç
¥
+U+7166 Xu # Character ç
¦
+U+7167 Zhao # Character ç
§
+U+7168 Wei # Character ç
¨
+U+7169 Fan # Character ç
©
+U+716a Qiu # Character ç
ª
+U+716b Sui # Character ç
«
+U+716c Yang # Character ç
¬
+U+716d Lie # Character ç
+U+716e Zhu # Character ç
®
+U+716f Jie # Character ç
¯
+U+7170 Gao # Character ç
°
+U+7171 Gua # Character ç
±
+U+7172 Bao # Character ç
²
+U+7173 Hu # Character ç
³
+U+7174 Yun # Character ç
´
+U+7175 Xia # Character ç
µ
+U+7176 ? # Character ç
¶
+U+7177 ? # Character ç
·
+U+7178 Bian # Character ç
¸
+U+7179 Gou # Character ç
¹
+U+717a Tui # Character ç
º
+U+717b Tang # Character ç
»
+U+717c Chao # Character ç
¼
+U+717d Shan # Character ç
½
+U+717e N # Character ç
¾
+U+717f Bo # Character ç
¿
+U+7180 Huang # Character ç
+U+7181 Xie # Character ç
+U+7182 Xi # Character ç
+U+7183 Wu # Character ç
+U+7184 Xi # Character ç
+U+7185 Yun # Character ç
+U+7186 He # Character ç
+U+7187 He # Character ç
+U+7188 Xi # Character ç
+U+7189 Yun # Character ç
+U+718a Xiong # Character ç
+U+718b Nai # Character ç
+U+718c Shan # Character ç
+U+718d Qiong # Character ç
+U+718e Yao # Character ç
+U+718f Xun # Character ç
+U+7190 Mi # Character ç
+U+7191 Lian # Character ç
+U+7192 Ying # Character ç
+U+7193 Wen # Character ç
+U+7194 Rong # Character ç
+U+7195 Oozutsu # Character ç
+U+7196 ? # Character ç
+U+7197 Qiang # Character ç
+U+7198 Liu # Character ç
+U+7199 Xi # Character ç
+U+719a Bi # Character ç
+U+719b Biao # Character ç
+U+719c Zong # Character ç
+U+719d Lu # Character ç
+U+719e Jian # Character ç
+U+719f Shou # Character ç
+U+71a0 Yi # Character ç
+U+71a1 Lou # Character ç¡
+U+71a2 Feng # Character ç¢
+U+71a3 Sui # Character ç£
+U+71a4 Yi # Character ç¤
+U+71a5 Tong # Character ç¥
+U+71a6 Jue # Character ç¦
+U+71a7 Zong # Character ç§
+U+71a8 Yun # Character ç¨
+U+71a9 Hu # Character ç©
+U+71aa Yi # Character çª
+U+71ab Zhi # Character ç«
+U+71ac Ao # Character ç¬
+U+71ad Wei # Character ç
+U+71ae Liao # Character ç®
+U+71af Han # Character ç¯
+U+71b0 Ou # Character ç°
+U+71b1 Re # Character ç±
+U+71b2 Jiong # Character ç²
+U+71b3 Man # Character ç³
+U+71b4 ? # Character ç´
+U+71b5 Shang # Character çµ
+U+71b6 Cuan # Character ç¶
+U+71b7 Zeng # Character ç·
+U+71b8 Jian # Character ç¸
+U+71b9 Xi # Character ç¹
+U+71ba Xi # Character çº
+U+71bb Xi # Character ç»
+U+71bc Yi # Character ç¼
+U+71bd Xiao # Character ç½
+U+71be Chi # Character ç¾
+U+71bf Huang # Character ç¿
+U+71c0 Chan # Character ç
+U+71c1 Ye # Character ç
+U+71c2 Qian # Character ç
+U+71c3 Ran # Character ç
+U+71c4 Yan # Character ç
+U+71c5 Xian # Character ç
+U+71c6 Qiao # Character ç
+U+71c7 Zun # Character ç
+U+71c8 Deng # Character ç
+U+71c9 Dun # Character ç
+U+71ca Shen # Character ç
+U+71cb Jiao # Character ç
+U+71cc Fen # Character ç
+U+71cd Si # Character ç
+U+71ce Liao # Character ç
+U+71cf Yu # Character ç
+U+71d0 Lin # Character ç
+U+71d1 Tong # Character ç
+U+71d2 Shao # Character ç
+U+71d3 Fen # Character ç
+U+71d4 Fan # Character ç
+U+71d5 Yan # Character ç
+U+71d6 Xun # Character ç
+U+71d7 Lan # Character ç
+U+71d8 Mei # Character ç
+U+71d9 Tang # Character ç
+U+71da Yi # Character ç
+U+71db Jing # Character ç
+U+71dc Men # Character ç
+U+71dd ? # Character ç
+U+71de ? # Character ç
+U+71df Ying # Character ç
+U+71e0 Yu # Character ç
+U+71e1 Yi # Character ç¡
+U+71e2 Xue # Character ç¢
+U+71e3 Lan # Character ç£
+U+71e4 Tai # Character ç¤
+U+71e5 Zao # Character ç¥
+U+71e6 Can # Character ç¦
+U+71e7 Sui # Character ç§
+U+71e8 Xi # Character ç¨
+U+71e9 Que # Character ç©
+U+71ea Cong # Character çª
+U+71eb Lian # Character ç«
+U+71ec Hui # Character ç¬
+U+71ed Zhu # Character ç
+U+71ee Xie # Character ç®
+U+71ef Ling # Character ç¯
+U+71f0 Wei # Character ç°
+U+71f1 Yi # Character ç±
+U+71f2 Xie # Character ç²
+U+71f3 Zhao # Character ç³
+U+71f4 Hui # Character ç´
+U+71f5 Tatsu # Character çµ
+U+71f6 Nung # Character ç¶
+U+71f7 Lan # Character ç·
+U+71f8 Ru # Character ç¸
+U+71f9 Xian # Character ç¹
+U+71fa Kao # Character çº
+U+71fb Xun # Character ç»
+U+71fc Jin # Character ç¼
+U+71fd Chou # Character ç½
+U+71fe Chou # Character ç¾
+U+71ff Yao # Character ç¿
diff --git a/resources/chars/ascii/row72.trans b/resources/chars/ascii/row72.trans
new file mode 100644
index 0000000..25949bb
--- /dev/null
+++ b/resources/chars/ascii/row72.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+7200 He # Character ç
+U+7201 Lan # Character ç
+U+7202 Biao # Character ç
+U+7203 Rong # Character ç
+U+7204 Li # Character ç
+U+7205 Mo # Character ç
+U+7206 Bao # Character ç
+U+7207 Ruo # Character ç
+U+7208 Lu # Character ç
+U+7209 La # Character ç
+U+720a Ao # Character ç
+U+720b Xun # Character ç
+U+720c Kuang # Character ç
+U+720d Shuo # Character ç
+U+720e ? # Character ç
+U+720f Li # Character ç
+U+7210 Lu # Character ç
+U+7211 Jue # Character ç
+U+7212 Liao # Character ç
+U+7213 Yan # Character ç
+U+7214 Xi # Character ç
+U+7215 Xie # Character ç
+U+7216 Long # Character ç
+U+7217 Ye # Character ç
+U+7218 ? # Character ç
+U+7219 Rang # Character ç
+U+721a Yue # Character ç
+U+721b Lan # Character ç
+U+721c Cong # Character ç
+U+721d Jue # Character ç
+U+721e Tong # Character ç
+U+721f Guan # Character ç
+U+7220 ? # Character ç
+U+7221 Che # Character ç¡
+U+7222 Mi # Character ç¢
+U+7223 Tang # Character ç£
+U+7224 Lan # Character ç¤
+U+7225 Zhu # Character ç¥
+U+7226 ? # Character ç¦
+U+7227 Ling # Character ç§
+U+7228 Cuan # Character ç¨
+U+7229 Yu # Character ç©
+U+722a Zhua # Character çª
+U+722b Tsumekanmuri # Character ç«
+U+722c Pa # Character ç¬
+U+722d Zheng # Character ç
+U+722e Pao # Character ç®
+U+722f Cheng # Character ç¯
+U+7230 Yuan # Character ç°
+U+7231 Ai # Character ç±
+U+7232 Wei # Character ç²
+U+7233 ? # Character ç³
+U+7234 Jue # Character ç´
+U+7235 Jue # Character çµ
+U+7236 Fu # Character ç¶
+U+7237 Ye # Character ç·
+U+7238 Ba # Character ç¸
+U+7239 Die # Character ç¹
+U+723a Ye # Character çº
+U+723b Yao # Character ç»
+U+723c Zu # Character ç¼
+U+723d Shuang # Character ç½
+U+723e Er # Character ç¾
+U+723f Qiang # Character ç¿
+U+7240 Chuang # Character ç
+U+7241 Ge # Character ç
+U+7242 Zang # Character ç
+U+7243 Die # Character ç
+U+7244 Qiang # Character ç
+U+7245 Yong # Character ç
+U+7246 Qiang # Character ç
+U+7247 Pian # Character ç
+U+7248 Ban # Character ç
+U+7249 Pan # Character ç
+U+724a Shao # Character ç
+U+724b Jian # Character ç
+U+724c Pai # Character ç
+U+724d Du # Character ç
+U+724e Chuang # Character ç
+U+724f Tou # Character ç
+U+7250 Zha # Character ç
+U+7251 Bian # Character ç
+U+7252 Die # Character ç
+U+7253 Bang # Character ç
+U+7254 Bo # Character ç
+U+7255 Chuang # Character ç
+U+7256 You # Character ç
+U+7257 ? # Character ç
+U+7258 Du # Character ç
+U+7259 Ya # Character ç
+U+725a Cheng # Character ç
+U+725b Niu # Character ç
+U+725c Ushihen # Character ç
+U+725d Pin # Character ç
+U+725e Jiu # Character ç
+U+725f Mou # Character ç
+U+7260 Tuo # Character ç
+U+7261 Mu # Character ç¡
+U+7262 Lao # Character ç¢
+U+7263 Ren # Character ç£
+U+7264 Mang # Character ç¤
+U+7265 Fang # Character ç¥
+U+7266 Mao # Character ç¦
+U+7267 Mu # Character ç§
+U+7268 Gang # Character ç¨
+U+7269 Wu # Character ç©
+U+726a Yan # Character çª
+U+726b Ge # Character ç«
+U+726c Bei # Character ç¬
+U+726d Si # Character ç
+U+726e Jian # Character ç®
+U+726f Gu # Character ç¯
+U+7270 You # Character ç°
+U+7271 Ge # Character ç±
+U+7272 Sheng # Character ç²
+U+7273 Mu # Character ç³
+U+7274 Di # Character ç´
+U+7275 Qian # Character çµ
+U+7276 Quan # Character ç¶
+U+7277 Quan # Character ç·
+U+7278 Zi # Character ç¸
+U+7279 Te # Character ç¹
+U+727a Xi # Character çº
+U+727b Mang # Character ç»
+U+727c Keng # Character ç¼
+U+727d Qian # Character ç½
+U+727e Wu # Character ç¾
+U+727f Gu # Character ç¿
+U+7280 Xi # Character ç
+U+7281 Li # Character ç
+U+7282 Li # Character ç
+U+7283 Pou # Character ç
+U+7284 Ji # Character ç
+U+7285 Gang # Character ç
+U+7286 Zhi # Character ç
+U+7287 Ben # Character ç
+U+7288 Quan # Character ç
+U+7289 Run # Character ç
+U+728a Du # Character ç
+U+728b Ju # Character ç
+U+728c Jia # Character ç
+U+728d Jian # Character ç
+U+728e Feng # Character ç
+U+728f Pian # Character ç
+U+7290 Ke # Character ç
+U+7291 Ju # Character ç
+U+7292 Kao # Character ç
+U+7293 Chu # Character ç
+U+7294 Xi # Character ç
+U+7295 Bei # Character ç
+U+7296 Luo # Character ç
+U+7297 Jie # Character ç
+U+7298 Ma # Character ç
+U+7299 San # Character ç
+U+729a Wei # Character ç
+U+729b Li # Character ç
+U+729c Dun # Character ç
+U+729d Tong # Character ç
+U+729e ? # Character ç
+U+729f Jiang # Character ç
+U+72a0 Ikenie # Character ç
+U+72a1 Li # Character ç¡
+U+72a2 Du # Character ç¢
+U+72a3 Lie # Character ç£
+U+72a4 Pi # Character ç¤
+U+72a5 Piao # Character ç¥
+U+72a6 Bao # Character ç¦
+U+72a7 Xi # Character ç§
+U+72a8 Chou # Character ç¨
+U+72a9 Wei # Character ç©
+U+72aa Kui # Character çª
+U+72ab Chou # Character ç«
+U+72ac Quan # Character ç¬
+U+72ad Fan # Character ç
+U+72ae Ba # Character ç®
+U+72af Fan # Character ç¯
+U+72b0 Qiu # Character ç°
+U+72b1 Ji # Character ç±
+U+72b2 Cai # Character ç²
+U+72b3 Chuo # Character ç³
+U+72b4 An # Character ç´
+U+72b5 Jie # Character çµ
+U+72b6 Zhuang # Character ç¶
+U+72b7 Guang # Character ç·
+U+72b8 Ma # Character ç¸
+U+72b9 You # Character ç¹
+U+72ba Kang # Character çº
+U+72bb Bo # Character ç»
+U+72bc Hou # Character ç¼
+U+72bd Ya # Character ç½
+U+72be Yin # Character ç¾
+U+72bf Huan # Character ç¿
+U+72c0 Zhuang # Character ç
+U+72c1 Yun # Character ç
+U+72c2 Kuang # Character ç
+U+72c3 Niu # Character ç
+U+72c4 Di # Character ç
+U+72c5 Qing # Character ç
+U+72c6 Zhong # Character ç
+U+72c7 Mu # Character ç
+U+72c8 Bei # Character ç
+U+72c9 Pi # Character ç
+U+72ca Ju # Character ç
+U+72cb Ni # Character ç
+U+72cc Sheng # Character ç
+U+72cd Pao # Character ç
+U+72ce Xia # Character ç
+U+72cf Tuo # Character ç
+U+72d0 Hu # Character ç
+U+72d1 Ling # Character ç
+U+72d2 Fei # Character ç
+U+72d3 Pi # Character ç
+U+72d4 Ni # Character ç
+U+72d5 Ao # Character ç
+U+72d6 You # Character ç
+U+72d7 Gou # Character ç
+U+72d8 Yue # Character ç
+U+72d9 Ju # Character ç
+U+72da Dan # Character ç
+U+72db Po # Character ç
+U+72dc Gu # Character ç
+U+72dd Xian # Character ç
+U+72de Ning # Character ç
+U+72df Huan # Character ç
+U+72e0 Hen # Character ç
+U+72e1 Jiao # Character ç¡
+U+72e2 He # Character ç¢
+U+72e3 Zhao # Character ç£
+U+72e4 Ji # Character ç¤
+U+72e5 Xun # Character ç¥
+U+72e6 Shan # Character ç¦
+U+72e7 Ta # Character ç§
+U+72e8 Rong # Character ç¨
+U+72e9 Shou # Character ç©
+U+72ea Tong # Character çª
+U+72eb Lao # Character ç«
+U+72ec Du # Character ç¬
+U+72ed Xia # Character ç
+U+72ee Shi # Character ç®
+U+72ef Hua # Character ç¯
+U+72f0 Zheng # Character ç°
+U+72f1 Yu # Character ç±
+U+72f2 Sun # Character ç²
+U+72f3 Yu # Character ç³
+U+72f4 Bi # Character ç´
+U+72f5 Mang # Character çµ
+U+72f6 Xi # Character ç¶
+U+72f7 Juan # Character ç·
+U+72f8 Li # Character ç¸
+U+72f9 Xia # Character ç¹
+U+72fa Yin # Character çº
+U+72fb Suan # Character ç»
+U+72fc Lang # Character ç¼
+U+72fd Bei # Character ç½
+U+72fe Zhi # Character ç¾
+U+72ff Yan # Character ç¿
diff --git a/resources/chars/ascii/row73.trans b/resources/chars/ascii/row73.trans
new file mode 100644
index 0000000..0f151f9
--- /dev/null
+++ b/resources/chars/ascii/row73.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+7300 Sha # Character ç
+U+7301 Li # Character ç
+U+7302 Han # Character ç
+U+7303 Xian # Character ç
+U+7304 Jing # Character ç
+U+7305 Pai # Character ç
+U+7306 Fei # Character ç
+U+7307 Yao # Character ç
+U+7308 Ba # Character ç
+U+7309 Qi # Character ç
+U+730a Ni # Character ç
+U+730b Biao # Character ç
+U+730c Yin # Character ç
+U+730d Lai # Character ç
+U+730e Xi # Character ç
+U+730f Jian # Character ç
+U+7310 Qiang # Character ç
+U+7311 Kun # Character ç
+U+7312 Yan # Character ç
+U+7313 Guo # Character ç
+U+7314 Zong # Character ç
+U+7315 Mi # Character ç
+U+7316 Chang # Character ç
+U+7317 Yi # Character ç
+U+7318 Zhi # Character ç
+U+7319 Zheng # Character ç
+U+731a Ya # Character ç
+U+731b Meng # Character ç
+U+731c Cai # Character ç
+U+731d Cu # Character ç
+U+731e She # Character ç
+U+731f Kari # Character ç
+U+7320 Cen # Character ç
+U+7321 Luo # Character ç¡
+U+7322 Hu # Character ç¢
+U+7323 Zong # Character ç£
+U+7324 Ji # Character ç¤
+U+7325 Wei # Character ç¥
+U+7326 Feng # Character ç¦
+U+7327 Wo # Character ç§
+U+7328 Yuan # Character ç¨
+U+7329 Xing # Character ç©
+U+732a Zhu # Character çª
+U+732b Mao # Character ç«
+U+732c Wei # Character ç¬
+U+732d Yuan # Character ç
+U+732e Xian # Character ç®
+U+732f Tuan # Character ç¯
+U+7330 Ya # Character ç°
+U+7331 Nao # Character ç±
+U+7332 Xie # Character ç²
+U+7333 Jia # Character ç³
+U+7334 Hou # Character ç´
+U+7335 Bian # Character çµ
+U+7336 You # Character ç¶
+U+7337 You # Character ç·
+U+7338 Mei # Character ç¸
+U+7339 Zha # Character ç¹
+U+733a Yao # Character çº
+U+733b Sun # Character ç»
+U+733c Bo # Character ç¼
+U+733d Ming # Character ç½
+U+733e Hua # Character ç¾
+U+733f Yuan # Character ç¿
+U+7340 Sou # Character ç
+U+7341 Ma # Character ç
+U+7342 Yuan # Character ç
+U+7343 Dai # Character ç
+U+7344 Yu # Character ç
+U+7345 Shi # Character ç
+U+7346 Hao # Character ç
+U+7347 ? # Character ç
+U+7348 Yi # Character ç
+U+7349 Zhen # Character ç
+U+734a Chuang # Character ç
+U+734b Hao # Character ç
+U+734c Man # Character ç
+U+734d Jing # Character ç
+U+734e Jiang # Character ç
+U+734f Mu # Character ç
+U+7350 Zhang # Character ç
+U+7351 Chan # Character ç
+U+7352 Ao # Character ç
+U+7353 Ao # Character ç
+U+7354 Hao # Character ç
+U+7355 Cui # Character ç
+U+7356 Fen # Character ç
+U+7357 Jue # Character ç
+U+7358 Bi # Character ç
+U+7359 Bi # Character ç
+U+735a Huang # Character ç
+U+735b Pu # Character ç
+U+735c Lin # Character ç
+U+735d Yu # Character ç
+U+735e Tong # Character ç
+U+735f Yao # Character ç
+U+7360 Liao # Character ç
+U+7361 Shuo # Character ç¡
+U+7362 Xiao # Character ç¢
+U+7363 Swu # Character ç£
+U+7364 Ton # Character ç¤
+U+7365 Xi # Character ç¥
+U+7366 Ge # Character ç¦
+U+7367 Juan # Character ç§
+U+7368 Du # Character ç¨
+U+7369 Hui # Character ç©
+U+736a Kuai # Character çª
+U+736b Xian # Character ç«
+U+736c Xie # Character ç¬
+U+736d Ta # Character ç
+U+736e Xian # Character ç®
+U+736f Xun # Character ç¯
+U+7370 Ning # Character ç°
+U+7371 Pin # Character ç±
+U+7372 Huo # Character ç²
+U+7373 Nou # Character ç³
+U+7374 Meng # Character ç´
+U+7375 Lie # Character çµ
+U+7376 Nao # Character ç¶
+U+7377 Guang # Character ç·
+U+7378 Shou # Character ç¸
+U+7379 Lu # Character ç¹
+U+737a Ta # Character çº
+U+737b Xian # Character ç»
+U+737c Mi # Character ç¼
+U+737d Rang # Character ç½
+U+737e Huan # Character ç¾
+U+737f Nao # Character ç¿
+U+7380 Luo # Character ç
+U+7381 Xian # Character ç
+U+7382 Qi # Character ç
+U+7383 Jue # Character ç
+U+7384 Xuan # Character ç
+U+7385 Miao # Character ç
+U+7386 Zi # Character ç
+U+7387 Lu # Character ç
+U+7388 Lu # Character ç
+U+7389 Yu # Character ç
+U+738a Su # Character ç
+U+738b Wang # Character ç
+U+738c Qiu # Character ç
+U+738d Ga # Character ç
+U+738e Ding # Character ç
+U+738f Le # Character ç
+U+7390 Ba # Character ç
+U+7391 Ji # Character ç
+U+7392 Hong # Character ç
+U+7393 Di # Character ç
+U+7394 Quan # Character ç
+U+7395 Gan # Character ç
+U+7396 Jiu # Character ç
+U+7397 Yu # Character ç
+U+7398 Ji # Character ç
+U+7399 Yu # Character ç
+U+739a Yang # Character ç
+U+739b Ma # Character ç
+U+739c Gong # Character ç
+U+739d Wu # Character ç
+U+739e Fu # Character ç
+U+739f Wen # Character ç
+U+73a0 Jie # Character ç
+U+73a1 Ya # Character ç¡
+U+73a2 Fen # Character ç¢
+U+73a3 Bian # Character ç£
+U+73a4 Beng # Character ç¤
+U+73a5 Yue # Character ç¥
+U+73a6 Jue # Character ç¦
+U+73a7 Yun # Character ç§
+U+73a8 Jue # Character ç¨
+U+73a9 Wan # Character ç©
+U+73aa Jian # Character çª
+U+73ab Mei # Character ç«
+U+73ac Dan # Character ç¬
+U+73ad Pi # Character ç
+U+73ae Wei # Character ç®
+U+73af Huan # Character ç¯
+U+73b0 Xian # Character ç°
+U+73b1 Qiang # Character ç±
+U+73b2 Ling # Character ç²
+U+73b3 Dai # Character ç³
+U+73b4 Yi # Character ç´
+U+73b5 An # Character çµ
+U+73b6 Ping # Character ç¶
+U+73b7 Dian # Character ç·
+U+73b8 Fu # Character ç¸
+U+73b9 Xuan # Character ç¹
+U+73ba Xi # Character çº
+U+73bb Bo # Character ç»
+U+73bc Ci # Character ç¼
+U+73bd Gou # Character ç½
+U+73be Jia # Character ç¾
+U+73bf Shao # Character ç¿
+U+73c0 Po # Character ç
+U+73c1 Ci # Character ç
+U+73c2 Ke # Character ç
+U+73c3 Ran # Character ç
+U+73c4 Sheng # Character ç
+U+73c5 Shen # Character ç
+U+73c6 Yi # Character ç
+U+73c7 Zu # Character ç
+U+73c8 Jia # Character ç
+U+73c9 Min # Character ç
+U+73ca Shan # Character ç
+U+73cb Liu # Character ç
+U+73cc Bi # Character ç
+U+73cd Zhen # Character ç
+U+73ce Zhen # Character ç
+U+73cf Jue # Character ç
+U+73d0 Fa # Character ç
+U+73d1 Long # Character ç
+U+73d2 Jin # Character ç
+U+73d3 Jiao # Character ç
+U+73d4 Jian # Character ç
+U+73d5 Li # Character ç
+U+73d6 Guang # Character ç
+U+73d7 Xian # Character ç
+U+73d8 Zhou # Character ç
+U+73d9 Gong # Character ç
+U+73da Yan # Character ç
+U+73db Xiu # Character ç
+U+73dc Yang # Character ç
+U+73dd Xu # Character ç
+U+73de Luo # Character ç
+U+73df Su # Character ç
+U+73e0 Zhu # Character ç
+U+73e1 Qin # Character ç¡
+U+73e2 Ken # Character ç¢
+U+73e3 Xun # Character ç£
+U+73e4 Bao # Character ç¤
+U+73e5 Er # Character ç¥
+U+73e6 Xiang # Character ç¦
+U+73e7 Yao # Character ç§
+U+73e8 Xia # Character ç¨
+U+73e9 Heng # Character ç©
+U+73ea Gui # Character çª
+U+73eb Chong # Character ç«
+U+73ec Xu # Character ç¬
+U+73ed Ban # Character ç
+U+73ee Pei # Character ç®
+U+73ef ? # Character ç¯
+U+73f0 Dang # Character ç°
+U+73f1 Ei # Character ç±
+U+73f2 Hun # Character ç²
+U+73f3 Wen # Character ç³
+U+73f4 E # Character ç´
+U+73f5 Cheng # Character çµ
+U+73f6 Ti # Character ç¶
+U+73f7 Wu # Character ç·
+U+73f8 Wu # Character ç¸
+U+73f9 Cheng # Character ç¹
+U+73fa Jun # Character çº
+U+73fb Mei # Character ç»
+U+73fc Bei # Character ç¼
+U+73fd Ting # Character ç½
+U+73fe Xian # Character ç¾
+U+73ff Chuo # Character ç¿
diff --git a/resources/chars/ascii/row74.trans b/resources/chars/ascii/row74.trans
new file mode 100644
index 0000000..dbcd208
--- /dev/null
+++ b/resources/chars/ascii/row74.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+7400 Han # Character ç
+U+7401 Xuan # Character ç
+U+7402 Yan # Character ç
+U+7403 Qiu # Character ç
+U+7404 Quan # Character ç
+U+7405 Lang # Character ç
+U+7406 Li # Character ç
+U+7407 Xiu # Character ç
+U+7408 Fu # Character ç
+U+7409 Liu # Character ç
+U+740a Ye # Character ç
+U+740b Xi # Character ç
+U+740c Ling # Character ç
+U+740d Li # Character ç
+U+740e Jin # Character ç
+U+740f Lian # Character ç
+U+7410 Suo # Character ç
+U+7411 Chiisai # Character ç
+U+7412 ? # Character ç
+U+7413 Wan # Character ç
+U+7414 Dian # Character ç
+U+7415 Pin # Character ç
+U+7416 Zhan # Character ç
+U+7417 Cui # Character ç
+U+7418 Min # Character ç
+U+7419 Yu # Character ç
+U+741a Ju # Character ç
+U+741b Chen # Character ç
+U+741c Lai # Character ç
+U+741d Wen # Character ç
+U+741e Sheng # Character ç
+U+741f Wei # Character ç
+U+7420 Dian # Character ç
+U+7421 Chu # Character ç¡
+U+7422 Zhuo # Character ç¢
+U+7423 Pei # Character ç£
+U+7424 Cheng # Character ç¤
+U+7425 Hu # Character ç¥
+U+7426 Qi # Character ç¦
+U+7427 E # Character ç§
+U+7428 Kun # Character ç¨
+U+7429 Chang # Character ç©
+U+742a Qi # Character çª
+U+742b Beng # Character ç«
+U+742c Wan # Character ç¬
+U+742d Lu # Character ç
+U+742e Cong # Character ç®
+U+742f Guan # Character ç¯
+U+7430 Yan # Character ç°
+U+7431 Diao # Character ç±
+U+7432 Bei # Character ç²
+U+7433 Lin # Character ç³
+U+7434 Qin # Character ç´
+U+7435 Pi # Character çµ
+U+7436 Pa # Character ç¶
+U+7437 Que # Character ç·
+U+7438 Zhuo # Character ç¸
+U+7439 Qin # Character ç¹
+U+743a Fa # Character çº
+U+743b ? # Character ç»
+U+743c Qiong # Character ç¼
+U+743d Du # Character ç½
+U+743e Jie # Character ç¾
+U+743f Hun # Character ç¿
+U+7440 Yu # Character ç
+U+7441 Mao # Character ç
+U+7442 Mei # Character ç
+U+7443 Chun # Character ç
+U+7444 Xuan # Character ç
+U+7445 Ti # Character ç
+U+7446 Xing # Character ç
+U+7447 Dai # Character ç
+U+7448 Rou # Character ç
+U+7449 Min # Character ç
+U+744a Zhen # Character ç
+U+744b Wei # Character ç
+U+744c Ruan # Character ç
+U+744d Huan # Character ç
+U+744e Jie # Character ç
+U+744f Chuan # Character ç
+U+7450 Jian # Character ç
+U+7451 Zhuan # Character ç
+U+7452 Yang # Character ç
+U+7453 Lian # Character ç
+U+7454 Quan # Character ç
+U+7455 Xia # Character ç
+U+7456 Duan # Character ç
+U+7457 Yuan # Character ç
+U+7458 Ye # Character ç
+U+7459 Nao # Character ç
+U+745a Hu # Character ç
+U+745b Ying # Character ç
+U+745c Yu # Character ç
+U+745d Huang # Character ç
+U+745e Rui # Character ç
+U+745f Se # Character ç
+U+7460 Liu # Character ç
+U+7461 Shi # Character ç¡
+U+7462 Rong # Character ç¢
+U+7463 Suo # Character ç£
+U+7464 Yao # Character ç¤
+U+7465 Wen # Character ç¥
+U+7466 Wu # Character ç¦
+U+7467 Jin # Character ç§
+U+7468 Jin # Character ç¨
+U+7469 Ying # Character ç©
+U+746a Ma # Character çª
+U+746b Tao # Character ç«
+U+746c Liu # Character ç¬
+U+746d Tang # Character ç
+U+746e Li # Character ç®
+U+746f Lang # Character ç¯
+U+7470 Gui # Character ç°
+U+7471 Zhen # Character ç±
+U+7472 Qiang # Character ç²
+U+7473 Cuo # Character ç³
+U+7474 Jue # Character ç´
+U+7475 Zhao # Character çµ
+U+7476 Yao # Character ç¶
+U+7477 Ai # Character ç·
+U+7478 Bin # Character ç¸
+U+7479 Tu # Character ç¹
+U+747a Chang # Character çº
+U+747b Kun # Character ç»
+U+747c Zhuan # Character ç¼
+U+747d Cong # Character ç½
+U+747e Jin # Character ç¾
+U+747f Yi # Character ç¿
+U+7480 Cui # Character ç
+U+7481 Cong # Character ç
+U+7482 Qi # Character ç
+U+7483 Li # Character ç
+U+7484 Ying # Character ç
+U+7485 Suo # Character ç
+U+7486 Qiu # Character ç
+U+7487 Xuan # Character ç
+U+7488 Ao # Character ç
+U+7489 Lian # Character ç
+U+748a Man # Character ç
+U+748b Zhang # Character ç
+U+748c Yin # Character ç
+U+748d ? # Character ç
+U+748e Ying # Character ç
+U+748f Zhi # Character ç
+U+7490 Lu # Character ç
+U+7491 Wu # Character ç
+U+7492 Deng # Character ç
+U+7493 Xiou # Character ç
+U+7494 Zeng # Character ç
+U+7495 Xun # Character ç
+U+7496 Qu # Character ç
+U+7497 Dang # Character ç
+U+7498 Lin # Character ç
+U+7499 Liao # Character ç
+U+749a Qiong # Character ç
+U+749b Su # Character ç
+U+749c Huang # Character ç
+U+749d Gui # Character ç
+U+749e Pu # Character ç
+U+749f Jing # Character ç
+U+74a0 Fan # Character ç
+U+74a1 Jin # Character ç¡
+U+74a2 Liu # Character ç¢
+U+74a3 Ji # Character ç£
+U+74a4 ? # Character ç¤
+U+74a5 Jing # Character ç¥
+U+74a6 Ai # Character ç¦
+U+74a7 Bi # Character ç§
+U+74a8 Can # Character ç¨
+U+74a9 Qu # Character ç©
+U+74aa Zao # Character çª
+U+74ab Dang # Character ç«
+U+74ac Jiao # Character ç¬
+U+74ad Gun # Character ç
+U+74ae Tan # Character ç®
+U+74af Hui # Character ç¯
+U+74b0 Huan # Character ç°
+U+74b1 Se # Character ç±
+U+74b2 Sui # Character ç²
+U+74b3 Tian # Character ç³
+U+74b4 ? # Character ç´
+U+74b5 Yu # Character çµ
+U+74b6 Jin # Character ç¶
+U+74b7 Lu # Character ç·
+U+74b8 Bin # Character ç¸
+U+74b9 Shou # Character ç¹
+U+74ba Wen # Character çº
+U+74bb Zui # Character ç»
+U+74bc Lan # Character ç¼
+U+74bd Xi # Character ç½
+U+74be Ji # Character ç¾
+U+74bf Xuan # Character ç¿
+U+74c0 Ruan # Character ç
+U+74c1 Huo # Character ç
+U+74c2 Gai # Character ç
+U+74c3 Lei # Character ç
+U+74c4 Du # Character ç
+U+74c5 Li # Character ç
+U+74c6 Zhi # Character ç
+U+74c7 Rou # Character ç
+U+74c8 Li # Character ç
+U+74c9 Zan # Character ç
+U+74ca Qiong # Character ç
+U+74cb Zhe # Character ç
+U+74cc Gui # Character ç
+U+74cd Sui # Character ç
+U+74ce La # Character ç
+U+74cf Long # Character ç
+U+74d0 Lu # Character ç
+U+74d1 Li # Character ç
+U+74d2 Zan # Character ç
+U+74d3 Lan # Character ç
+U+74d4 Ying # Character ç
+U+74d5 Mi # Character ç
+U+74d6 Xiang # Character ç
+U+74d7 Xi # Character ç
+U+74d8 Guan # Character ç
+U+74d9 Dao # Character ç
+U+74da Zan # Character ç
+U+74db Huan # Character ç
+U+74dc Gua # Character ç
+U+74dd Bo # Character ç
+U+74de Die # Character ç
+U+74df Bao # Character ç
+U+74e0 Hu # Character ç
+U+74e1 Zhi # Character ç¡
+U+74e2 Piao # Character ç¢
+U+74e3 Ban # Character ç£
+U+74e4 Rang # Character ç¤
+U+74e5 Li # Character ç¥
+U+74e6 Wa # Character ç¦
+U+74e7 Dekaguramu # Character ç§
+U+74e8 Jiang # Character ç¨
+U+74e9 Qian # Character ç©
+U+74ea Fan # Character çª
+U+74eb Pen # Character ç«
+U+74ec Fang # Character ç¬
+U+74ed Dan # Character ç
+U+74ee Weng # Character ç®
+U+74ef Ou # Character ç¯
+U+74f0 Deshiguramu # Character ç°
+U+74f1 Miriguramu # Character ç±
+U+74f2 Thon # Character ç²
+U+74f3 Hu # Character ç³
+U+74f4 Ling # Character ç´
+U+74f5 Yi # Character çµ
+U+74f6 Ping # Character ç¶
+U+74f7 Ci # Character ç·
+U+74f8 Hekutogura # Character ç¸
+U+74f9 Juan # Character ç¹
+U+74fa Chang # Character çº
+U+74fb Chi # Character ç»
+U+74fc Sarake # Character ç¼
+U+74fd Dang # Character ç½
+U+74fe Meng # Character ç¾
+U+74ff Pou # Character ç¿
diff --git a/resources/chars/ascii/row75.trans b/resources/chars/ascii/row75.trans
new file mode 100644
index 0000000..1d8056b
--- /dev/null
+++ b/resources/chars/ascii/row75.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+7500 Zhui # Character ç
+U+7501 Ping # Character ç
+U+7502 Bian # Character ç
+U+7503 Zhou # Character ç
+U+7504 Zhen # Character ç
+U+7505 Senchigura # Character ç
+U+7506 Ci # Character ç
+U+7507 Ying # Character ç
+U+7508 Qi # Character ç
+U+7509 Xian # Character ç
+U+750a Lou # Character ç
+U+750b Di # Character ç
+U+750c Ou # Character ç
+U+750d Meng # Character ç
+U+750e Zhuan # Character ç
+U+750f Peng # Character ç
+U+7510 Lin # Character ç
+U+7511 Zeng # Character ç
+U+7512 Wu # Character ç
+U+7513 Pi # Character ç
+U+7514 Dan # Character ç
+U+7515 Weng # Character ç
+U+7516 Ying # Character ç
+U+7517 Yan # Character ç
+U+7518 Gan # Character ç
+U+7519 Dai # Character ç
+U+751a Shen # Character ç
+U+751b Tian # Character ç
+U+751c Tian # Character ç
+U+751d Han # Character ç
+U+751e Chang # Character ç
+U+751f Sheng # Character ç
+U+7520 Qing # Character ç
+U+7521 Sheng # Character ç¡
+U+7522 Chan # Character ç¢
+U+7523 Chan # Character ç£
+U+7524 Rui # Character ç¤
+U+7525 Sheng # Character ç¥
+U+7526 Su # Character ç¦
+U+7527 Sen # Character ç§
+U+7528 Yong # Character ç¨
+U+7529 Shuai # Character ç©
+U+752a Lu # Character çª
+U+752b Fu # Character ç«
+U+752c Yong # Character ç¬
+U+752d Beng # Character ç
+U+752e Feng # Character ç®
+U+752f Ning # Character ç¯
+U+7530 Tian # Character ç°
+U+7531 You # Character ç±
+U+7532 Jia # Character ç²
+U+7533 Shen # Character ç³
+U+7534 Zha # Character ç´
+U+7535 Dian # Character çµ
+U+7536 Fu # Character ç¶
+U+7537 Nan # Character ç·
+U+7538 Dian # Character ç¸
+U+7539 Ping # Character ç¹
+U+753a Ting # Character çº
+U+753b Hua # Character ç»
+U+753c Ting # Character ç¼
+U+753d Quan # Character ç½
+U+753e Zi # Character ç¾
+U+753f Meng # Character ç¿
+U+7540 Bi # Character ç
+U+7541 Qi # Character ç
+U+7542 Liu # Character ç
+U+7543 Xun # Character ç
+U+7544 Liu # Character ç
+U+7545 Chang # Character ç
+U+7546 Mu # Character ç
+U+7547 Yun # Character ç
+U+7548 Fan # Character ç
+U+7549 Fu # Character ç
+U+754a Geng # Character ç
+U+754b Tian # Character ç
+U+754c Jie # Character ç
+U+754d Jie # Character ç
+U+754e Quan # Character ç
+U+754f Wei # Character ç
+U+7550 Fu # Character ç
+U+7551 Tian # Character ç
+U+7552 Mu # Character ç
+U+7553 Tap # Character ç
+U+7554 Pan # Character ç
+U+7555 Jiang # Character ç
+U+7556 Wa # Character ç
+U+7557 Da # Character ç
+U+7558 Nan # Character ç
+U+7559 Liu # Character ç
+U+755a Ben # Character ç
+U+755b Zhen # Character ç
+U+755c Chu # Character ç
+U+755d Mu # Character ç
+U+755e Mu # Character ç
+U+755f Ce # Character ç
+U+7560 Cen # Character ç
+U+7561 Gai # Character ç¡
+U+7562 Bi # Character ç¢
+U+7563 Da # Character ç£
+U+7564 Zhi # Character ç¤
+U+7565 Lue # Character ç¥
+U+7566 Qi # Character ç¦
+U+7567 Lue # Character ç§
+U+7568 Pan # Character ç¨
+U+7569 Kesa # Character ç©
+U+756a Fan # Character çª
+U+756b Hua # Character ç«
+U+756c Yu # Character ç¬
+U+756d Yu # Character ç
+U+756e Mu # Character ç®
+U+756f Jun # Character ç¯
+U+7570 Yi # Character ç°
+U+7571 Liu # Character ç±
+U+7572 Yu # Character ç²
+U+7573 Die # Character ç³
+U+7574 Chou # Character ç´
+U+7575 Hua # Character çµ
+U+7576 Dang # Character ç¶
+U+7577 Chuo # Character ç·
+U+7578 Ji # Character ç¸
+U+7579 Wan # Character ç¹
+U+757a Jiang # Character çº
+U+757b Sheng # Character ç»
+U+757c Chang # Character ç¼
+U+757d Tuan # Character ç½
+U+757e Lei # Character ç¾
+U+757f Ji # Character ç¿
+U+7580 Cha # Character ç
+U+7581 Liu # Character ç
+U+7582 Tatamu # Character ç
+U+7583 Tuan # Character ç
+U+7584 Lin # Character ç
+U+7585 Jiang # Character ç
+U+7586 Jiang # Character ç
+U+7587 Chou # Character ç
+U+7588 Bo # Character ç
+U+7589 Die # Character ç
+U+758a Die # Character ç
+U+758b Pi # Character ç
+U+758c Nie # Character ç
+U+758d Dan # Character ç
+U+758e Shu # Character ç
+U+758f Shu # Character ç
+U+7590 Zhi # Character ç
+U+7591 Yi # Character ç
+U+7592 Chuang # Character ç
+U+7593 Nai # Character ç
+U+7594 Ding # Character ç
+U+7595 Bi # Character ç
+U+7596 Jie # Character ç
+U+7597 Liao # Character ç
+U+7598 Gong # Character ç
+U+7599 Ge # Character ç
+U+759a Jiu # Character ç
+U+759b Zhou # Character ç
+U+759c Xia # Character ç
+U+759d Shan # Character ç
+U+759e Xu # Character ç
+U+759f Nue # Character ç
+U+75a0 Li # Character ç
+U+75a1 Yang # Character ç¡
+U+75a2 Chen # Character ç¢
+U+75a3 You # Character ç£
+U+75a4 Ba # Character ç¤
+U+75a5 Jie # Character ç¥
+U+75a6 Jue # Character ç¦
+U+75a7 Zhi # Character ç§
+U+75a8 Xia # Character ç¨
+U+75a9 Cui # Character ç©
+U+75aa Bi # Character çª
+U+75ab Yi # Character ç«
+U+75ac Li # Character ç¬
+U+75ad Zong # Character ç
+U+75ae Chuang # Character ç®
+U+75af Feng # Character ç¯
+U+75b0 Zhu # Character ç°
+U+75b1 Pao # Character ç±
+U+75b2 Pi # Character ç²
+U+75b3 Gan # Character ç³
+U+75b4 Ke # Character ç´
+U+75b5 Ci # Character çµ
+U+75b6 Xie # Character ç¶
+U+75b7 Qi # Character ç·
+U+75b8 Dan # Character ç¸
+U+75b9 Zhen # Character ç¹
+U+75ba Fa # Character çº
+U+75bb Zhi # Character ç»
+U+75bc Teng # Character ç¼
+U+75bd Ju # Character ç½
+U+75be Ji # Character ç¾
+U+75bf Fei # Character ç¿
+U+75c0 Qu # Character ç
+U+75c1 Dian # Character ç
+U+75c2 Jia # Character ç
+U+75c3 Xian # Character ç
+U+75c4 Cha # Character ç
+U+75c5 Bing # Character ç
+U+75c6 Ni # Character ç
+U+75c7 Zheng # Character ç
+U+75c8 Yong # Character ç
+U+75c9 Jing # Character ç
+U+75ca Quan # Character ç
+U+75cb Chong # Character ç
+U+75cc Tong # Character ç
+U+75cd Yi # Character ç
+U+75ce Kai # Character ç
+U+75cf Wei # Character ç
+U+75d0 Hui # Character ç
+U+75d1 Duo # Character ç
+U+75d2 Yang # Character ç
+U+75d3 Chi # Character ç
+U+75d4 Zhi # Character ç
+U+75d5 Hen # Character ç
+U+75d6 Ya # Character ç
+U+75d7 Mei # Character ç
+U+75d8 Dou # Character ç
+U+75d9 Jing # Character ç
+U+75da Xiao # Character ç
+U+75db Tong # Character ç
+U+75dc Tu # Character ç
+U+75dd Mang # Character ç
+U+75de Pi # Character ç
+U+75df Xiao # Character ç
+U+75e0 Suan # Character ç
+U+75e1 Pu # Character ç¡
+U+75e2 Li # Character ç¢
+U+75e3 Zhi # Character ç£
+U+75e4 Cuo # Character ç¤
+U+75e5 Duo # Character ç¥
+U+75e6 Wu # Character ç¦
+U+75e7 Sha # Character ç§
+U+75e8 Lao # Character ç¨
+U+75e9 Shou # Character ç©
+U+75ea Huan # Character çª
+U+75eb Xian # Character ç«
+U+75ec Yi # Character ç¬
+U+75ed Peng # Character ç
+U+75ee Zhang # Character ç®
+U+75ef Guan # Character ç¯
+U+75f0 Tan # Character ç°
+U+75f1 Fei # Character ç±
+U+75f2 Ma # Character ç²
+U+75f3 Lin # Character ç³
+U+75f4 Chi # Character ç´
+U+75f5 Ji # Character çµ
+U+75f6 Dian # Character ç¶
+U+75f7 An # Character ç·
+U+75f8 Chi # Character ç¸
+U+75f9 Bi # Character ç¹
+U+75fa Bei # Character çº
+U+75fb Min # Character ç»
+U+75fc Gu # Character ç¼
+U+75fd Dui # Character ç½
+U+75fe E # Character ç¾
+U+75ff Wei # Character ç¿
diff --git a/resources/chars/ascii/row76.trans b/resources/chars/ascii/row76.trans
new file mode 100644
index 0000000..07678d3
--- /dev/null
+++ b/resources/chars/ascii/row76.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+7600 Yu # Character ç
+U+7601 Cui # Character ç
+U+7602 Ya # Character ç
+U+7603 Zhu # Character ç
+U+7604 Cu # Character ç
+U+7605 Dan # Character ç
+U+7606 Shen # Character ç
+U+7607 Zhung # Character ç
+U+7608 Ji # Character ç
+U+7609 Yu # Character ç
+U+760a Hou # Character ç
+U+760b Feng # Character ç
+U+760c La # Character ç
+U+760d Yang # Character ç
+U+760e Shen # Character ç
+U+760f Tu # Character ç
+U+7610 Yu # Character ç
+U+7611 Gua # Character ç
+U+7612 Wen # Character ç
+U+7613 Huan # Character ç
+U+7614 Ku # Character ç
+U+7615 Jia # Character ç
+U+7616 Yin # Character ç
+U+7617 Yi # Character ç
+U+7618 Lu # Character ç
+U+7619 Sao # Character ç
+U+761a Jue # Character ç
+U+761b Chi # Character ç
+U+761c Xi # Character ç
+U+761d Guan # Character ç
+U+761e Yi # Character ç
+U+761f Wen # Character ç
+U+7620 Ji # Character ç
+U+7621 Chuang # Character ç¡
+U+7622 Ban # Character ç¢
+U+7623 Lei # Character ç£
+U+7624 Liu # Character ç¤
+U+7625 Chai # Character ç¥
+U+7626 Shou # Character ç¦
+U+7627 Nue # Character ç§
+U+7628 Dian # Character ç¨
+U+7629 Da # Character ç©
+U+762a Pie # Character çª
+U+762b Tan # Character ç«
+U+762c Zhang # Character ç¬
+U+762d Biao # Character ç
+U+762e Shen # Character ç®
+U+762f Cu # Character ç¯
+U+7630 Luo # Character ç°
+U+7631 Yi # Character ç±
+U+7632 Zong # Character ç²
+U+7633 Chou # Character ç³
+U+7634 Zhang # Character ç´
+U+7635 Zhai # Character çµ
+U+7636 Sou # Character ç¶
+U+7637 Suo # Character ç·
+U+7638 Que # Character ç¸
+U+7639 Diao # Character ç¹
+U+763a Lou # Character çº
+U+763b Lu # Character ç»
+U+763c Mo # Character ç¼
+U+763d Jin # Character ç½
+U+763e Yin # Character ç¾
+U+763f Ying # Character ç¿
+U+7640 Huang # Character ç
+U+7641 Fu # Character ç
+U+7642 Liao # Character ç
+U+7643 Long # Character ç
+U+7644 Qiao # Character ç
+U+7645 Liu # Character ç
+U+7646 Lao # Character ç
+U+7647 Xian # Character ç
+U+7648 Fei # Character ç
+U+7649 Dan # Character ç
+U+764a Yin # Character ç
+U+764b He # Character ç
+U+764c Yan # Character ç
+U+764d Ban # Character ç
+U+764e Xian # Character ç
+U+764f Guan # Character ç
+U+7650 Guai # Character ç
+U+7651 Nong # Character ç
+U+7652 Yu # Character ç
+U+7653 Wei # Character ç
+U+7654 Yi # Character ç
+U+7655 Yong # Character ç
+U+7656 Pi # Character ç
+U+7657 Lei # Character ç
+U+7658 Li # Character ç
+U+7659 Shu # Character ç
+U+765a Dan # Character ç
+U+765b Lin # Character ç
+U+765c Dian # Character ç
+U+765d Lin # Character ç
+U+765e Lai # Character ç
+U+765f Pie # Character ç
+U+7660 Ji # Character ç
+U+7661 Chi # Character ç¡
+U+7662 Yang # Character ç¢
+U+7663 Xian # Character ç£
+U+7664 Jie # Character ç¤
+U+7665 Zheng # Character ç¥
+U+7666 ? # Character ç¦
+U+7667 Li # Character ç§
+U+7668 Huo # Character ç¨
+U+7669 Lai # Character ç©
+U+766a Shaku # Character çª
+U+766b Dian # Character ç«
+U+766c Xian # Character ç¬
+U+766d Ying # Character ç
+U+766e Yin # Character ç®
+U+766f Qu # Character ç¯
+U+7670 Yong # Character ç°
+U+7671 Tan # Character ç±
+U+7672 Dian # Character ç²
+U+7673 Luo # Character ç³
+U+7674 Luan # Character ç´
+U+7675 Luan # Character çµ
+U+7676 Bo # Character ç¶
+U+7677 ? # Character ç·
+U+7678 Gui # Character ç¸
+U+7679 Po # Character ç¹
+U+767a Fa # Character çº
+U+767b Deng # Character ç»
+U+767c Fa # Character ç¼
+U+767d Bai # Character ç½
+U+767e Bai # Character ç¾
+U+767f Qie # Character ç¿
+U+7680 Bi # Character ç
+U+7681 Zao # Character ç
+U+7682 Zao # Character ç
+U+7683 Mao # Character ç
+U+7684 De # Character ç
+U+7685 Pa # Character ç
+U+7686 Jie # Character ç
+U+7687 Huang # Character ç
+U+7688 Gui # Character ç
+U+7689 Ci # Character ç
+U+768a Ling # Character ç
+U+768b Gao # Character ç
+U+768c Mo # Character ç
+U+768d Ji # Character ç
+U+768e Jiao # Character ç
+U+768f Peng # Character ç
+U+7690 Gao # Character ç
+U+7691 Ai # Character ç
+U+7692 E # Character ç
+U+7693 Hao # Character ç
+U+7694 Han # Character ç
+U+7695 Bi # Character ç
+U+7696 Wan # Character ç
+U+7697 Chou # Character ç
+U+7698 Qian # Character ç
+U+7699 Xi # Character ç
+U+769a Ai # Character ç
+U+769b Jiong # Character ç
+U+769c Hao # Character ç
+U+769d Huang # Character ç
+U+769e Hao # Character ç
+U+769f Ze # Character ç
+U+76a0 Cui # Character ç
+U+76a1 Hao # Character ç¡
+U+76a2 Xiao # Character ç¢
+U+76a3 Ye # Character ç£
+U+76a4 Po # Character ç¤
+U+76a5 Hao # Character ç¥
+U+76a6 Jiao # Character ç¦
+U+76a7 Ai # Character ç§
+U+76a8 Xing # Character ç¨
+U+76a9 Huang # Character ç©
+U+76aa Li # Character çª
+U+76ab Piao # Character ç«
+U+76ac He # Character ç¬
+U+76ad Jiao # Character ç
+U+76ae Pi # Character ç®
+U+76af Gan # Character ç¯
+U+76b0 Pao # Character ç°
+U+76b1 Zhou # Character ç±
+U+76b2 Jun # Character ç²
+U+76b3 Qiu # Character ç³
+U+76b4 Cun # Character ç´
+U+76b5 Que # Character çµ
+U+76b6 Zha # Character ç¶
+U+76b7 Gu # Character ç·
+U+76b8 Jun # Character ç¸
+U+76b9 Jun # Character ç¹
+U+76ba Zhou # Character çº
+U+76bb Zha # Character ç»
+U+76bc Gu # Character ç¼
+U+76bd Zhan # Character ç½
+U+76be Du # Character ç¾
+U+76bf Min # Character ç¿
+U+76c0 Qi # Character ç
+U+76c1 Ying # Character ç
+U+76c2 Yu # Character ç
+U+76c3 Bei # Character ç
+U+76c4 Zhao # Character ç
+U+76c5 Zhong # Character ç
+U+76c6 Pen # Character ç
+U+76c7 He # Character ç
+U+76c8 Ying # Character ç
+U+76c9 He # Character ç
+U+76ca Yi # Character ç
+U+76cb Bo # Character ç
+U+76cc Wan # Character ç
+U+76cd He # Character ç
+U+76ce Ang # Character ç
+U+76cf Zhan # Character ç
+U+76d0 Yan # Character ç
+U+76d1 Jian # Character ç
+U+76d2 He # Character ç
+U+76d3 Yu # Character ç
+U+76d4 Kui # Character ç
+U+76d5 Fan # Character ç
+U+76d6 Gai # Character ç
+U+76d7 Dao # Character ç
+U+76d8 Pan # Character ç
+U+76d9 Fu # Character ç
+U+76da Qiu # Character ç
+U+76db Sheng # Character ç
+U+76dc Dao # Character ç
+U+76dd Lu # Character ç
+U+76de Zhan # Character ç
+U+76df Meng # Character ç
+U+76e0 Li # Character ç
+U+76e1 Jin # Character ç¡
+U+76e2 Xu # Character ç¢
+U+76e3 Jian # Character ç£
+U+76e4 Pan # Character ç¤
+U+76e5 Guan # Character ç¥
+U+76e6 An # Character ç¦
+U+76e7 Lu # Character ç§
+U+76e8 Shu # Character ç¨
+U+76e9 Zhou # Character ç©
+U+76ea Dang # Character çª
+U+76eb An # Character ç«
+U+76ec Gu # Character ç¬
+U+76ed Li # Character ç
+U+76ee Mu # Character ç®
+U+76ef Cheng # Character ç¯
+U+76f0 Gan # Character ç°
+U+76f1 Xu # Character ç±
+U+76f2 Mang # Character ç²
+U+76f3 Mang # Character ç³
+U+76f4 Zhi # Character ç´
+U+76f5 Qi # Character çµ
+U+76f6 Ruan # Character ç¶
+U+76f7 Tian # Character ç·
+U+76f8 Xiang # Character ç¸
+U+76f9 Dun # Character ç¹
+U+76fa Xin # Character çº
+U+76fb Xi # Character ç»
+U+76fc Pan # Character ç¼
+U+76fd Feng # Character ç½
+U+76fe Dun # Character ç¾
+U+76ff Min # Character ç¿
diff --git a/resources/chars/ascii/row77.trans b/resources/chars/ascii/row77.trans
new file mode 100644
index 0000000..4b687fb
--- /dev/null
+++ b/resources/chars/ascii/row77.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+7700 Ming # Character ç
+U+7701 Sheng # Character ç
+U+7702 Shi # Character ç
+U+7703 Yun # Character ç
+U+7704 Mian # Character ç
+U+7705 Pan # Character ç
+U+7706 Fang # Character ç
+U+7707 Miao # Character ç
+U+7708 Dan # Character ç
+U+7709 Mei # Character ç
+U+770a Mao # Character ç
+U+770b Kan # Character ç
+U+770c Xian # Character ç
+U+770d Ou # Character ç
+U+770e Shi # Character ç
+U+770f Yang # Character ç
+U+7710 Zheng # Character ç
+U+7711 Yao # Character ç
+U+7712 Shen # Character ç
+U+7713 Huo # Character ç
+U+7714 Da # Character ç
+U+7715 Zhen # Character ç
+U+7716 Kuang # Character ç
+U+7717 Ju # Character ç
+U+7718 Shen # Character ç
+U+7719 Chi # Character ç
+U+771a Sheng # Character ç
+U+771b Mei # Character ç
+U+771c Mo # Character ç
+U+771d Zhu # Character ç
+U+771e Zhen # Character ç
+U+771f Zhen # Character ç
+U+7720 Mian # Character ç
+U+7721 Di # Character ç¡
+U+7722 Yuan # Character ç¢
+U+7723 Die # Character ç£
+U+7724 Yi # Character ç¤
+U+7725 Zi # Character ç¥
+U+7726 Zi # Character ç¦
+U+7727 Chao # Character ç§
+U+7728 Zha # Character ç¨
+U+7729 Xuan # Character ç©
+U+772a Bing # Character çª
+U+772b Mi # Character ç«
+U+772c Long # Character ç¬
+U+772d Sui # Character ç
+U+772e Dong # Character ç®
+U+772f Mi # Character ç¯
+U+7730 Die # Character ç°
+U+7731 Yi # Character ç±
+U+7732 Er # Character ç²
+U+7733 Ming # Character ç³
+U+7734 Xuan # Character ç´
+U+7735 Chi # Character çµ
+U+7736 Kuang # Character ç¶
+U+7737 Juan # Character ç·
+U+7738 Mou # Character ç¸
+U+7739 Zhen # Character ç¹
+U+773a Tiao # Character çº
+U+773b Yang # Character ç»
+U+773c Yan # Character ç¼
+U+773d Mo # Character ç½
+U+773e Zhong # Character ç¾
+U+773f Mai # Character ç¿
+U+7740 Zhao # Character ç
+U+7741 Zheng # Character ç
+U+7742 Mei # Character ç
+U+7743 Jun # Character ç
+U+7744 Shao # Character ç
+U+7745 Han # Character ç
+U+7746 Huan # Character ç
+U+7747 Di # Character ç
+U+7748 Cheng # Character ç
+U+7749 Cuo # Character ç
+U+774a Juan # Character ç
+U+774b E # Character ç
+U+774c Wan # Character ç
+U+774d Xian # Character ç
+U+774e Xi # Character ç
+U+774f Kun # Character ç
+U+7750 Lai # Character ç
+U+7751 Jian # Character ç
+U+7752 Shan # Character ç
+U+7753 Tian # Character ç
+U+7754 Hun # Character ç
+U+7755 Wan # Character ç
+U+7756 Ling # Character ç
+U+7757 Shi # Character ç
+U+7758 Qiong # Character ç
+U+7759 Lie # Character ç
+U+775a Yai # Character ç
+U+775b Jing # Character ç
+U+775c Zheng # Character ç
+U+775d Li # Character ç
+U+775e Lai # Character ç
+U+775f Sui # Character ç
+U+7760 Juan # Character ç
+U+7761 Shui # Character ç¡
+U+7762 Sui # Character ç¢
+U+7763 Du # Character ç£
+U+7764 Bi # Character ç¤
+U+7765 Bi # Character ç¥
+U+7766 Mu # Character ç¦
+U+7767 Hun # Character ç§
+U+7768 Ni # Character ç¨
+U+7769 Lu # Character ç©
+U+776a Yi # Character çª
+U+776b Jie # Character ç«
+U+776c Cai # Character ç¬
+U+776d Zhou # Character ç
+U+776e Yu # Character ç®
+U+776f Hun # Character ç¯
+U+7770 Ma # Character ç°
+U+7771 Xia # Character ç±
+U+7772 Xing # Character ç²
+U+7773 Xi # Character ç³
+U+7774 Gun # Character ç´
+U+7775 Cai # Character çµ
+U+7776 Chun # Character ç¶
+U+7777 Jian # Character ç·
+U+7778 Mei # Character ç¸
+U+7779 Du # Character ç¹
+U+777a Hou # Character çº
+U+777b Xuan # Character ç»
+U+777c Ti # Character ç¼
+U+777d Kui # Character ç½
+U+777e Gao # Character ç¾
+U+777f Rui # Character ç¿
+U+7780 Mou # Character ç
+U+7781 Xu # Character ç
+U+7782 Fa # Character ç
+U+7783 Wen # Character ç
+U+7784 Miao # Character ç
+U+7785 Chou # Character ç
+U+7786 Kui # Character ç
+U+7787 Mi # Character ç
+U+7788 Weng # Character ç
+U+7789 Kou # Character ç
+U+778a Dang # Character ç
+U+778b Chen # Character ç
+U+778c Ke # Character ç
+U+778d Sou # Character ç
+U+778e Xia # Character ç
+U+778f Qiong # Character ç
+U+7790 Mao # Character ç
+U+7791 Ming # Character ç
+U+7792 Man # Character ç
+U+7793 Shui # Character ç
+U+7794 Ze # Character ç
+U+7795 Zhang # Character ç
+U+7796 Yi # Character ç
+U+7797 Diao # Character ç
+U+7798 Ou # Character ç
+U+7799 Mo # Character ç
+U+779a Shun # Character ç
+U+779b Cong # Character ç
+U+779c Lou # Character ç
+U+779d Chi # Character ç
+U+779e Man # Character ç
+U+779f Piao # Character ç
+U+77a0 Cheng # Character ç
+U+77a1 Ji # Character ç¡
+U+77a2 Meng # Character ç¢
+U+77a3 ? # Character ç£
+U+77a4 Run # Character ç¤
+U+77a5 Pie # Character ç¥
+U+77a6 Xi # Character ç¦
+U+77a7 Qiao # Character ç§
+U+77a8 Pu # Character ç¨
+U+77a9 Zhu # Character ç©
+U+77aa Deng # Character çª
+U+77ab Shen # Character ç«
+U+77ac Shun # Character ç¬
+U+77ad Liao # Character ç
+U+77ae Che # Character ç®
+U+77af Xian # Character ç¯
+U+77b0 Kan # Character ç°
+U+77b1 Ye # Character ç±
+U+77b2 Xu # Character ç²
+U+77b3 Tong # Character ç³
+U+77b4 Mou # Character ç´
+U+77b5 Lin # Character çµ
+U+77b6 Kui # Character ç¶
+U+77b7 Xian # Character ç·
+U+77b8 Ye # Character ç¸
+U+77b9 Ai # Character ç¹
+U+77ba Hui # Character çº
+U+77bb Zhan # Character ç»
+U+77bc Jian # Character ç¼
+U+77bd Gu # Character ç½
+U+77be Zhao # Character ç¾
+U+77bf Qu # Character ç¿
+U+77c0 Wei # Character ç
+U+77c1 Chou # Character ç
+U+77c2 Sao # Character ç
+U+77c3 Ning # Character ç
+U+77c4 Xun # Character ç
+U+77c5 Yao # Character ç
+U+77c6 Huo # Character ç
+U+77c7 Meng # Character ç
+U+77c8 Mian # Character ç
+U+77c9 Bin # Character ç
+U+77ca Mian # Character ç
+U+77cb Li # Character ç
+U+77cc Kuang # Character ç
+U+77cd Jue # Character ç
+U+77ce Xuan # Character ç
+U+77cf Mian # Character ç
+U+77d0 Huo # Character ç
+U+77d1 Lu # Character ç
+U+77d2 Meng # Character ç
+U+77d3 Long # Character ç
+U+77d4 Guan # Character ç
+U+77d5 Man # Character ç
+U+77d6 Xi # Character ç
+U+77d7 Chu # Character ç
+U+77d8 Tang # Character ç
+U+77d9 Kan # Character ç
+U+77da Zhu # Character ç
+U+77db Mao # Character ç
+U+77dc Jin # Character ç
+U+77dd Lin # Character ç
+U+77de Yu # Character ç
+U+77df Shuo # Character ç
+U+77e0 Ce # Character ç
+U+77e1 Jue # Character ç¡
+U+77e2 Shi # Character ç¢
+U+77e3 Yi # Character ç£
+U+77e4 Shen # Character ç¤
+U+77e5 Zhi # Character ç¥
+U+77e6 Hou # Character ç¦
+U+77e7 Shen # Character ç§
+U+77e8 Ying # Character ç¨
+U+77e9 Ju # Character ç©
+U+77ea Zhou # Character çª
+U+77eb Jiao # Character ç«
+U+77ec Cuo # Character ç¬
+U+77ed Duan # Character ç
+U+77ee Ai # Character ç®
+U+77ef Jiao # Character ç¯
+U+77f0 Zeng # Character ç°
+U+77f1 Huo # Character ç±
+U+77f2 Bai # Character ç²
+U+77f3 Shi # Character ç³
+U+77f4 Ding # Character ç´
+U+77f5 Qi # Character çµ
+U+77f6 Ji # Character ç¶
+U+77f7 Zi # Character ç·
+U+77f8 Gan # Character ç¸
+U+77f9 Wu # Character ç¹
+U+77fa Tuo # Character çº
+U+77fb Ku # Character ç»
+U+77fc Qiang # Character ç¼
+U+77fd Xi # Character ç½
+U+77fe Fan # Character ç¾
+U+77ff Kuang # Character ç¿
diff --git a/resources/chars/ascii/row78.trans b/resources/chars/ascii/row78.trans
new file mode 100644
index 0000000..13828b2
--- /dev/null
+++ b/resources/chars/ascii/row78.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+7800 Dang # Character ç
+U+7801 Ma # Character ç
+U+7802 Sha # Character ç
+U+7803 Dan # Character ç
+U+7804 Jue # Character ç
+U+7805 Li # Character ç
+U+7806 Fu # Character ç
+U+7807 Min # Character ç
+U+7808 Nuo # Character ç
+U+7809 Huo # Character ç
+U+780a Kang # Character ç
+U+780b Zhi # Character ç
+U+780c Qi # Character ç
+U+780d Kan # Character ç
+U+780e Jie # Character ç
+U+780f Fen # Character ç
+U+7810 E # Character ç
+U+7811 Ya # Character ç
+U+7812 Pi # Character ç
+U+7813 Zhe # Character ç
+U+7814 Yan # Character ç
+U+7815 Sui # Character ç
+U+7816 Zhuan # Character ç
+U+7817 Che # Character ç
+U+7818 Dun # Character ç
+U+7819 Pan # Character ç
+U+781a Yan # Character ç
+U+781b ? # Character ç
+U+781c Feng # Character ç
+U+781d Fa # Character ç
+U+781e Mo # Character ç
+U+781f Zha # Character ç
+U+7820 Qu # Character ç
+U+7821 Yu # Character ç ¡
+U+7822 Luo # Character ç ¢
+U+7823 Tuo # Character ç £
+U+7824 Tuo # Character ç ¤
+U+7825 Di # Character ç ¥
+U+7826 Zhai # Character ç ¦
+U+7827 Zhen # Character ç §
+U+7828 Ai # Character ç ¨
+U+7829 Fei # Character ç ©
+U+782a Mu # Character ç ª
+U+782b Zhu # Character ç «
+U+782c Li # Character ç ¬
+U+782d Bian # Character ç
+U+782e Nu # Character ç ®
+U+782f Ping # Character ç ¯
+U+7830 Peng # Character ç °
+U+7831 Ling # Character ç ±
+U+7832 Pao # Character ç ²
+U+7833 Le # Character ç ³
+U+7834 Po # Character ç ´
+U+7835 Bo # Character ç µ
+U+7836 Po # Character ç ¶
+U+7837 Shen # Character ç ·
+U+7838 Za # Character ç ¸
+U+7839 Nuo # Character ç ¹
+U+783a Li # Character ç º
+U+783b Long # Character ç »
+U+783c Tong # Character ç ¼
+U+783d ? # Character ç ½
+U+783e Li # Character ç ¾
+U+783f Aragane # Character ç ¿
+U+7840 Chu # Character ç¡
+U+7841 Keng # Character ç¡
+U+7842 Quan # Character ç¡
+U+7843 Zhu # Character ç¡
+U+7844 Kuang # Character ç¡
+U+7845 Huo # Character ç¡
+U+7846 E # Character ç¡
+U+7847 Nao # Character ç¡
+U+7848 Jia # Character ç¡
+U+7849 Lu # Character ç¡
+U+784a Wei # Character ç¡
+U+784b Ai # Character ç¡
+U+784c Luo # Character ç¡
+U+784d Ken # Character ç¡
+U+784e Xing # Character ç¡
+U+784f Yan # Character ç¡
+U+7850 Tong # Character ç¡
+U+7851 Peng # Character ç¡
+U+7852 Xi # Character ç¡
+U+7853 ? # Character ç¡
+U+7854 Hong # Character ç¡
+U+7855 Shuo # Character ç¡
+U+7856 Xia # Character ç¡
+U+7857 Qiao # Character ç¡
+U+7858 ? # Character ç¡
+U+7859 Wei # Character ç¡
+U+785a Qiao # Character ç¡
+U+785b ? # Character ç¡
+U+785c Keng # Character ç¡
+U+785d Xiao # Character ç¡
+U+785e Que # Character ç¡
+U+785f Chan # Character ç¡
+U+7860 Lang # Character ç¡
+U+7861 Hong # Character ç¡¡
+U+7862 Yu # Character ç¡¢
+U+7863 Xiao # Character ç¡£
+U+7864 Xia # Character 硤
+U+7865 Mang # Character ç¡¥
+U+7866 Long # Character 硦
+U+7867 Iong # Character 硧
+U+7868 Che # Character 硨
+U+7869 Che # Character ç¡©
+U+786a E # Character 硪
+U+786b Liu # Character ç¡«
+U+786c Ying # Character 硬
+U+786d Mang # Character ç¡
+U+786e Que # Character ç¡®
+U+786f Yan # Character 硯
+U+7870 Sha # Character ç¡°
+U+7871 Kun # Character 硱
+U+7872 Yu # Character 硲
+U+7873 ? # Character 硳
+U+7874 Kaki # Character ç¡´
+U+7875 Lu # Character 硵
+U+7876 Chen # Character 硶
+U+7877 Jian # Character ç¡·
+U+7878 Nue # Character 硸
+U+7879 Song # Character 硹
+U+787a Zhuo # Character 硺
+U+787b Keng # Character ç¡»
+U+787c Peng # Character 硼
+U+787d Yan # Character 硽
+U+787e Zhui # Character 硾
+U+787f Kong # Character ç¡¿
+U+7880 Ceng # Character ç¢
+U+7881 Qi # Character ç¢
+U+7882 Zong # Character ç¢
+U+7883 Qing # Character ç¢
+U+7884 Lin # Character ç¢
+U+7885 Jun # Character ç¢
+U+7886 Bo # Character ç¢
+U+7887 Ding # Character ç¢
+U+7888 Min # Character ç¢
+U+7889 Diao # Character ç¢
+U+788a Jian # Character ç¢
+U+788b He # Character ç¢
+U+788c Lu # Character ç¢
+U+788d Ai # Character ç¢
+U+788e Sui # Character ç¢
+U+788f Que # Character ç¢
+U+7890 Ling # Character ç¢
+U+7891 Bei # Character ç¢
+U+7892 Yin # Character ç¢
+U+7893 Dui # Character ç¢
+U+7894 Wu # Character ç¢
+U+7895 Qi # Character ç¢
+U+7896 Lun # Character ç¢
+U+7897 Wan # Character ç¢
+U+7898 Dian # Character ç¢
+U+7899 Gang # Character ç¢
+U+789a Pei # Character ç¢
+U+789b Qi # Character ç¢
+U+789c Chen # Character ç¢
+U+789d Ruan # Character ç¢
+U+789e Yan # Character ç¢
+U+789f Die # Character ç¢
+U+78a0 Ding # Character ç¢
+U+78a1 Du # Character 碡
+U+78a2 Tuo # Character 碢
+U+78a3 Jie # Character 碣
+U+78a4 Ying # Character 碤
+U+78a5 Bian # Character 碥
+U+78a6 Ke # Character 碦
+U+78a7 Bi # Character 碧
+U+78a8 Wei # Character 碨
+U+78a9 Shuo # Character 碩
+U+78aa Zhen # Character 碪
+U+78ab Duan # Character 碫
+U+78ac Xia # Character 碬
+U+78ad Dang # Character ç¢
+U+78ae Ti # Character 碮
+U+78af Nao # Character 碯
+U+78b0 Peng # Character 碰
+U+78b1 Jian # Character 碱
+U+78b2 Di # Character 碲
+U+78b3 Tan # Character 碳
+U+78b4 Cha # Character 碴
+U+78b5 Seki # Character 碵
+U+78b6 Qi # Character 碶
+U+78b7 ? # Character 碷
+U+78b8 Feng # Character 碸
+U+78b9 Xuan # Character 碹
+U+78ba Que # Character 確
+U+78bb Que # Character 碻
+U+78bc Ma # Character 碼
+U+78bd Gong # Character 碽
+U+78be Nian # Character 碾
+U+78bf Su # Character 碿
+U+78c0 E # Character ç£
+U+78c1 Ci # Character ç£
+U+78c2 Liu # Character ç£
+U+78c3 Si # Character ç£
+U+78c4 Tang # Character ç£
+U+78c5 Bang # Character ç£
+U+78c6 Hua # Character ç£
+U+78c7 Pi # Character ç£
+U+78c8 Wei # Character ç£
+U+78c9 Sang # Character ç£
+U+78ca Lei # Character ç£
+U+78cb Cuo # Character ç£
+U+78cc Zhen # Character ç£
+U+78cd Xia # Character ç£
+U+78ce Qi # Character ç£
+U+78cf Lian # Character ç£
+U+78d0 Pan # Character ç£
+U+78d1 Wei # Character ç£
+U+78d2 Yun # Character ç£
+U+78d3 Dui # Character ç£
+U+78d4 Zhe # Character ç£
+U+78d5 Ke # Character ç£
+U+78d6 La # Character ç£
+U+78d7 ? # Character ç£
+U+78d8 Qing # Character ç£
+U+78d9 Gun # Character ç£
+U+78da Zhuan # Character ç£
+U+78db Chan # Character ç£
+U+78dc Qi # Character ç£
+U+78dd Ao # Character ç£
+U+78de Peng # Character ç£
+U+78df Lu # Character ç£
+U+78e0 Lu # Character ç£
+U+78e1 Kan # Character 磡
+U+78e2 Qiang # Character 磢
+U+78e3 Chen # Character 磣
+U+78e4 Yin # Character 磤
+U+78e5 Lei # Character 磥
+U+78e6 Biao # Character 磦
+U+78e7 Qi # Character 磧
+U+78e8 Mo # Character 磨
+U+78e9 Qi # Character 磩
+U+78ea Cui # Character 磪
+U+78eb Zong # Character 磫
+U+78ec Qing # Character 磬
+U+78ed Chuo # Character ç£
+U+78ee ? # Character 磮
+U+78ef Ji # Character 磯
+U+78f0 Shan # Character 磰
+U+78f1 Lao # Character 磱
+U+78f2 Qu # Character 磲
+U+78f3 Zeng # Character 磳
+U+78f4 Deng # Character 磴
+U+78f5 Jian # Character 磵
+U+78f6 Xi # Character 磶
+U+78f7 Lin # Character 磷
+U+78f8 Ding # Character 磸
+U+78f9 Dian # Character 磹
+U+78fa Huang # Character 磺
+U+78fb Pan # Character 磻
+U+78fc Za # Character 磼
+U+78fd Qiao # Character 磽
+U+78fe Di # Character 磾
+U+78ff Li # Character 磿
diff --git a/resources/chars/ascii/row79.trans b/resources/chars/ascii/row79.trans
new file mode 100644
index 0000000..14fae05
--- /dev/null
+++ b/resources/chars/ascii/row79.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+7900 Tani # Character ç¤
+U+7901 Jiao # Character ç¤
+U+7902 ? # Character ç¤
+U+7903 Zhang # Character ç¤
+U+7904 Qiao # Character ç¤
+U+7905 Dun # Character ç¤
+U+7906 Xian # Character ç¤
+U+7907 Yu # Character ç¤
+U+7908 Zhui # Character ç¤
+U+7909 He # Character ç¤
+U+790a Huo # Character ç¤
+U+790b Zhai # Character ç¤
+U+790c Lei # Character ç¤
+U+790d Ke # Character ç¤
+U+790e Chu # Character ç¤
+U+790f Ji # Character ç¤
+U+7910 Que # Character ç¤
+U+7911 Dang # Character ç¤
+U+7912 Yi # Character ç¤
+U+7913 Jiang # Character ç¤
+U+7914 Pi # Character ç¤
+U+7915 Pi # Character ç¤
+U+7916 Yu # Character ç¤
+U+7917 Pin # Character ç¤
+U+7918 Qi # Character ç¤
+U+7919 Ai # Character ç¤
+U+791a Kai # Character ç¤
+U+791b Jian # Character ç¤
+U+791c Yu # Character ç¤
+U+791d Ruan # Character ç¤
+U+791e Meng # Character ç¤
+U+791f Pao # Character ç¤
+U+7920 Ci # Character ç¤
+U+7921 ? # Character 礡
+U+7922 ? # Character 礢
+U+7923 Mie # Character 礣
+U+7924 Ca # Character 礤
+U+7925 Xian # Character 礥
+U+7926 Kuang # Character 礦
+U+7927 Lei # Character 礧
+U+7928 Lei # Character 礨
+U+7929 Zhi # Character 礩
+U+792a Li # Character 礪
+U+792b Li # Character 礫
+U+792c Fan # Character 礬
+U+792d Que # Character ç¤
+U+792e Pao # Character 礮
+U+792f Ying # Character 礯
+U+7930 Li # Character 礰
+U+7931 Long # Character 礱
+U+7932 Long # Character 礲
+U+7933 Mo # Character 礳
+U+7934 Bo # Character 礴
+U+7935 Shuang # Character 礵
+U+7936 Guan # Character 礶
+U+7937 Lan # Character 礷
+U+7938 Zan # Character 礸
+U+7939 Yan # Character 礹
+U+793a Shi # Character 示
+U+793b Shi # Character 礻
+U+793c Li # Character 礼
+U+793d Reng # Character 礽
+U+793e She # Character 社
+U+793f Yue # Character 礿
+U+7940 Si # Character ç¥
+U+7941 Qi # Character ç¥
+U+7942 Ta # Character ç¥
+U+7943 Ma # Character ç¥
+U+7944 Xie # Character ç¥
+U+7945 Xian # Character ç¥
+U+7946 Xian # Character ç¥
+U+7947 Zhi # Character ç¥
+U+7948 Qi # Character ç¥
+U+7949 Zhi # Character ç¥
+U+794a Beng # Character ç¥
+U+794b Dui # Character ç¥
+U+794c Zhong # Character ç¥
+U+794d ? # Character ç¥
+U+794e Yi # Character ç¥
+U+794f Shi # Character ç¥
+U+7950 You # Character ç¥
+U+7951 Zhi # Character ç¥
+U+7952 Tiao # Character ç¥
+U+7953 Fu # Character ç¥
+U+7954 Fu # Character ç¥
+U+7955 Mi # Character ç¥
+U+7956 Zu # Character ç¥
+U+7957 Zhi # Character ç¥
+U+7958 Suan # Character ç¥
+U+7959 Mei # Character ç¥
+U+795a Zuo # Character ç¥
+U+795b Qu # Character ç¥
+U+795c Hu # Character ç¥
+U+795d Zhu # Character ç¥
+U+795e Shen # Character ç¥
+U+795f Sui # Character ç¥
+U+7960 Ci # Character ç¥
+U+7961 Chai # Character 祡
+U+7962 Mi # Character 祢
+U+7963 Lu # Character 祣
+U+7964 Yu # Character 祤
+U+7965 Xiang # Character 祥
+U+7966 Wu # Character 祦
+U+7967 Tiao # Character 祧
+U+7968 Piao # Character 票
+U+7969 Zhu # Character 祩
+U+796a Gui # Character 祪
+U+796b Xia # Character 祫
+U+796c Zhi # Character 祬
+U+796d Ji # Character ç¥
+U+796e Gao # Character 祮
+U+796f Zhen # Character 祯
+U+7970 Gao # Character 祰
+U+7971 Shui # Character 祱
+U+7972 Jin # Character 祲
+U+7973 Chen # Character 祳
+U+7974 Gai # Character 祴
+U+7975 Kun # Character 祵
+U+7976 Di # Character 祶
+U+7977 Dao # Character 祷
+U+7978 Huo # Character 祸
+U+7979 Tao # Character 祹
+U+797a Qi # Character 祺
+U+797b Gu # Character 祻
+U+797c Guan # Character 祼
+U+797d Zui # Character 祽
+U+797e Ling # Character 祾
+U+797f Lu # Character 祿
+U+7980 Bing # Character ç¦
+U+7981 Jin # Character ç¦
+U+7982 Dao # Character ç¦
+U+7983 Zhi # Character ç¦
+U+7984 Lu # Character ç¦
+U+7985 Shan # Character ç¦
+U+7986 Bei # Character ç¦
+U+7987 Zhe # Character ç¦
+U+7988 Hui # Character ç¦
+U+7989 You # Character ç¦
+U+798a Xi # Character ç¦
+U+798b Yin # Character ç¦
+U+798c Zi # Character ç¦
+U+798d Huo # Character ç¦
+U+798e Zhen # Character ç¦
+U+798f Fu # Character ç¦
+U+7990 Yuan # Character ç¦
+U+7991 Wu # Character ç¦
+U+7992 Xian # Character ç¦
+U+7993 Yang # Character ç¦
+U+7994 Ti # Character ç¦
+U+7995 Yi # Character ç¦
+U+7996 Mei # Character ç¦
+U+7997 Si # Character ç¦
+U+7998 Di # Character ç¦
+U+7999 ? # Character ç¦
+U+799a Zhuo # Character ç¦
+U+799b Zhen # Character ç¦
+U+799c Yong # Character ç¦
+U+799d Ji # Character ç¦
+U+799e Gao # Character ç¦
+U+799f Tang # Character ç¦
+U+79a0 Si # Character ç¦
+U+79a1 Ma # Character 禡
+U+79a2 Ta # Character 禢
+U+79a3 ? # Character 禣
+U+79a4 Xuan # Character 禤
+U+79a5 Qi # Character 禥
+U+79a6 Yu # Character 禦
+U+79a7 Xi # Character 禧
+U+79a8 Ji # Character 禨
+U+79a9 Si # Character 禩
+U+79aa Chan # Character 禪
+U+79ab Tan # Character 禫
+U+79ac Kuai # Character 禬
+U+79ad Sui # Character ç¦
+U+79ae Li # Character 禮
+U+79af Nong # Character 禯
+U+79b0 Ni # Character 禰
+U+79b1 Dao # Character 禱
+U+79b2 Li # Character 禲
+U+79b3 Rang # Character 禳
+U+79b4 Yue # Character 禴
+U+79b5 Ti # Character 禵
+U+79b6 Zan # Character 禶
+U+79b7 Lei # Character 禷
+U+79b8 Rou # Character 禸
+U+79b9 Yu # Character 禹
+U+79ba Yu # Character 禺
+U+79bb Chi # Character 离
+U+79bc Xie # Character 禼
+U+79bd Qin # Character 禽
+U+79be He # Character 禾
+U+79bf Tu # Character 禿
+U+79c0 Xiu # Character ç§
+U+79c1 Si # Character ç§
+U+79c2 Ren # Character ç§
+U+79c3 Tu # Character ç§
+U+79c4 Zi # Character ç§
+U+79c5 Cha # Character ç§
+U+79c6 Gan # Character ç§
+U+79c7 Yi # Character ç§
+U+79c8 Xian # Character ç§
+U+79c9 Bing # Character ç§
+U+79ca Nian # Character ç§
+U+79cb Qiu # Character ç§
+U+79cc Qiu # Character ç§
+U+79cd Chong # Character ç§
+U+79ce Fen # Character ç§
+U+79cf Hao # Character ç§
+U+79d0 Yun # Character ç§
+U+79d1 Ke # Character ç§
+U+79d2 Miao # Character ç§
+U+79d3 Zhi # Character ç§
+U+79d4 Geng # Character ç§
+U+79d5 Bi # Character ç§
+U+79d6 Zhi # Character ç§
+U+79d7 Yu # Character ç§
+U+79d8 Mi # Character ç§
+U+79d9 Ku # Character ç§
+U+79da Ban # Character ç§
+U+79db Pi # Character ç§
+U+79dc Ni # Character ç§
+U+79dd Li # Character ç§
+U+79de You # Character ç§
+U+79df Zu # Character ç§
+U+79e0 Pi # Character ç§
+U+79e1 Ba # Character 秡
+U+79e2 Ling # Character 秢
+U+79e3 Mo # Character 秣
+U+79e4 Cheng # Character 秤
+U+79e5 Nian # Character 秥
+U+79e6 Qin # Character 秦
+U+79e7 Yang # Character 秧
+U+79e8 Zuo # Character 秨
+U+79e9 Zhi # Character 秩
+U+79ea Zhi # Character 秪
+U+79eb Shu # Character 秫
+U+79ec Ju # Character 秬
+U+79ed Zi # Character ç§
+U+79ee Huo # Character 秮
+U+79ef Ji # Character 积
+U+79f0 Cheng # Character 称
+U+79f1 Tong # Character 秱
+U+79f2 Zhi # Character 秲
+U+79f3 Huo # Character 秳
+U+79f4 He # Character 秴
+U+79f5 Yin # Character 秵
+U+79f6 Zi # Character 秶
+U+79f7 Zhi # Character 秷
+U+79f8 Jie # Character 秸
+U+79f9 Ren # Character 秹
+U+79fa Du # Character 秺
+U+79fb Yi # Character 移
+U+79fc Zhu # Character 秼
+U+79fd Hui # Character 秽
+U+79fe Nong # Character 秾
+U+79ff Fu # Character 秿
diff --git a/resources/chars/ascii/row7a.trans b/resources/chars/ascii/row7a.trans
new file mode 100644
index 0000000..80a5cbb
--- /dev/null
+++ b/resources/chars/ascii/row7a.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+7a00 Xi # Character ç¨
+U+7a01 Kao # Character ç¨
+U+7a02 Lang # Character ç¨
+U+7a03 Fu # Character ç¨
+U+7a04 Ze # Character ç¨
+U+7a05 Shui # Character ç¨
+U+7a06 Lu # Character ç¨
+U+7a07 Kun # Character ç¨
+U+7a08 Gan # Character ç¨
+U+7a09 Geng # Character ç¨
+U+7a0a Ti # Character ç¨
+U+7a0b Cheng # Character ç¨
+U+7a0c Tu # Character ç¨
+U+7a0d Shao # Character ç¨
+U+7a0e Shui # Character ç¨
+U+7a0f Ya # Character ç¨
+U+7a10 Lun # Character ç¨
+U+7a11 Lu # Character ç¨
+U+7a12 Gu # Character ç¨
+U+7a13 Zuo # Character ç¨
+U+7a14 Ren # Character ç¨
+U+7a15 Zhun # Character ç¨
+U+7a16 Bang # Character ç¨
+U+7a17 Bai # Character ç¨
+U+7a18 Ji # Character ç¨
+U+7a19 Zhi # Character ç¨
+U+7a1a Zhi # Character ç¨
+U+7a1b Kun # Character ç¨
+U+7a1c Leng # Character ç¨
+U+7a1d Peng # Character ç¨
+U+7a1e Ke # Character ç¨
+U+7a1f Bing # Character ç¨
+U+7a20 Chou # Character ç¨
+U+7a21 Zu # Character 稡
+U+7a22 Yu # Character 稢
+U+7a23 Su # Character 稣
+U+7a24 Lue # Character 稤
+U+7a25 ? # Character 稥
+U+7a26 Yi # Character 稦
+U+7a27 Xi # Character 稧
+U+7a28 Bian # Character 稨
+U+7a29 Ji # Character 稩
+U+7a2a Fu # Character 稪
+U+7a2b Bi # Character 稫
+U+7a2c Nuo # Character 稬
+U+7a2d Jie # Character ç¨
+U+7a2e Zhong # Character 種
+U+7a2f Zong # Character 稯
+U+7a30 Xu # Character 稰
+U+7a31 Cheng # Character 稱
+U+7a32 Dao # Character 稲
+U+7a33 Wen # Character 稳
+U+7a34 Lian # Character 稴
+U+7a35 Zi # Character 稵
+U+7a36 Yu # Character 稶
+U+7a37 Ji # Character 稷
+U+7a38 Xu # Character 稸
+U+7a39 Zhen # Character 稹
+U+7a3a Zhi # Character 稺
+U+7a3b Dao # Character 稻
+U+7a3c Jia # Character 稼
+U+7a3d Ji # Character 稽
+U+7a3e Gao # Character 稾
+U+7a3f Gao # Character 稿
+U+7a40 Gu # Character ç©
+U+7a41 Rong # Character ç©
+U+7a42 Sui # Character ç©
+U+7a43 You # Character ç©
+U+7a44 Ji # Character ç©
+U+7a45 Kang # Character ç©
+U+7a46 Mu # Character ç©
+U+7a47 Shan # Character ç©
+U+7a48 Men # Character ç©
+U+7a49 Zhi # Character ç©
+U+7a4a Ji # Character ç©
+U+7a4b Lu # Character ç©
+U+7a4c Su # Character ç©
+U+7a4d Ji # Character ç©
+U+7a4e Ying # Character ç©
+U+7a4f Wen # Character ç©
+U+7a50 Qiu # Character ç©
+U+7a51 Se # Character ç©
+U+7a52 ? # Character ç©
+U+7a53 Yi # Character ç©
+U+7a54 Huang # Character ç©
+U+7a55 Qie # Character ç©
+U+7a56 Ji # Character ç©
+U+7a57 Sui # Character ç©
+U+7a58 Xiao # Character ç©
+U+7a59 Pu # Character ç©
+U+7a5a Jiao # Character ç©
+U+7a5b Zhuo # Character ç©
+U+7a5c Tong # Character ç©
+U+7a5d Sai # Character ç©
+U+7a5e Lu # Character ç©
+U+7a5f Sui # Character ç©
+U+7a60 Nong # Character ç©
+U+7a61 Se # Character ç©¡
+U+7a62 Hui # Character ç©¢
+U+7a63 Rang # Character ç©£
+U+7a64 Nuo # Character 穤
+U+7a65 Yu # Character ç©¥
+U+7a66 Bin # Character 穦
+U+7a67 Ji # Character 穧
+U+7a68 Tui # Character 穨
+U+7a69 Wen # Character ç©©
+U+7a6a Cheng # Character 穪
+U+7a6b Huo # Character ç©«
+U+7a6c Gong # Character 穬
+U+7a6d Lu # Character ç©
+U+7a6e Biao # Character ç©®
+U+7a6f ? # Character 穯
+U+7a70 Rang # Character ç©°
+U+7a71 Zhuo # Character 穱
+U+7a72 Li # Character 穲
+U+7a73 Zan # Character 穳
+U+7a74 Xue # Character ç©´
+U+7a75 Wa # Character 穵
+U+7a76 Jiu # Character 究
+U+7a77 Qiong # Character ç©·
+U+7a78 Xi # Character 穸
+U+7a79 Qiong # Character 穹
+U+7a7a Kong # Character 空
+U+7a7b Yu # Character ç©»
+U+7a7c Sen # Character 穼
+U+7a7d Jing # Character 穽
+U+7a7e Yao # Character 穾
+U+7a7f Chuan # Character ç©¿
+U+7a80 Zhun # Character çª
+U+7a81 Tu # Character çª
+U+7a82 Lao # Character çª
+U+7a83 Qie # Character çª
+U+7a84 Zhai # Character çª
+U+7a85 Yao # Character çª
+U+7a86 Bian # Character çª
+U+7a87 Bao # Character çª
+U+7a88 Yao # Character çª
+U+7a89 Bing # Character çª
+U+7a8a Wa # Character çª
+U+7a8b Zhu # Character çª
+U+7a8c Jiao # Character çª
+U+7a8d Qiao # Character çª
+U+7a8e Diao # Character çª
+U+7a8f Wu # Character çª
+U+7a90 Gui # Character çª
+U+7a91 Yao # Character çª
+U+7a92 Zhi # Character çª
+U+7a93 Chuang # Character çª
+U+7a94 Yao # Character çª
+U+7a95 Tiao # Character çª
+U+7a96 Jiao # Character çª
+U+7a97 Chuang # Character çª
+U+7a98 Jiong # Character çª
+U+7a99 Xiao # Character çª
+U+7a9a Cheng # Character çª
+U+7a9b Kou # Character çª
+U+7a9c Cuan # Character çª
+U+7a9d Wo # Character çª
+U+7a9e Dan # Character çª
+U+7a9f Ku # Character çª
+U+7aa0 Ke # Character çª
+U+7aa1 Zhui # Character 窡
+U+7aa2 Xu # Character 窢
+U+7aa3 Su # Character 窣
+U+7aa4 Guan # Character 窤
+U+7aa5 Kui # Character 窥
+U+7aa6 Dou # Character 窦
+U+7aa7 ? # Character 窧
+U+7aa8 Yin # Character 窨
+U+7aa9 Wo # Character 窩
+U+7aaa Wa # Character 窪
+U+7aab Ya # Character 窫
+U+7aac Yu # Character 窬
+U+7aad Ju # Character çª
+U+7aae Qiong # Character 窮
+U+7aaf Yao # Character 窯
+U+7ab0 Yao # Character 窰
+U+7ab1 Tiao # Character 窱
+U+7ab2 Chao # Character 窲
+U+7ab3 Yu # Character 窳
+U+7ab4 Tian # Character 窴
+U+7ab5 Diao # Character 窵
+U+7ab6 Ju # Character 窶
+U+7ab7 Liao # Character 窷
+U+7ab8 Xi # Character 窸
+U+7ab9 Wu # Character 窹
+U+7aba Kui # Character 窺
+U+7abb Chuang # Character 窻
+U+7abc Zhao # Character 窼
+U+7abd ? # Character 窽
+U+7abe Kuan # Character 窾
+U+7abf Long # Character 窿
+U+7ac0 Cheng # Character ç«
+U+7ac1 Cui # Character ç«
+U+7ac2 Piao # Character ç«
+U+7ac3 Zao # Character ç«
+U+7ac4 Cuan # Character ç«
+U+7ac5 Qiao # Character ç«
+U+7ac6 Qiong # Character ç«
+U+7ac7 Dou # Character ç«
+U+7ac8 Zao # Character ç«
+U+7ac9 Long # Character ç«
+U+7aca Qie # Character ç«
+U+7acb Li # Character ç«
+U+7acc Chu # Character ç«
+U+7acd Shi # Character ç«
+U+7ace Fou # Character ç«
+U+7acf Qian # Character ç«
+U+7ad0 Chu # Character ç«
+U+7ad1 Hong # Character ç«
+U+7ad2 Qi # Character ç«
+U+7ad3 Qian # Character ç«
+U+7ad4 Gong # Character ç«
+U+7ad5 Shi # Character ç«
+U+7ad6 Shu # Character ç«
+U+7ad7 Miao # Character ç«
+U+7ad8 Ju # Character ç«
+U+7ad9 Zhan # Character ç«
+U+7ada Zhu # Character ç«
+U+7adb Ling # Character ç«
+U+7adc Long # Character ç«
+U+7add Bing # Character ç«
+U+7ade Jing # Character ç«
+U+7adf Jing # Character ç«
+U+7ae0 Zhang # Character ç«
+U+7ae1 Yi # Character ç«¡
+U+7ae2 Si # Character ç«¢
+U+7ae3 Jun # Character ç«£
+U+7ae4 Hong # Character 竤
+U+7ae5 Tong # Character ç«¥
+U+7ae6 Song # Character 竦
+U+7ae7 Jing # Character 竧
+U+7ae8 Diao # Character 竨
+U+7ae9 Yi # Character ç«©
+U+7aea Shu # Character 竪
+U+7aeb Jing # Character ç««
+U+7aec Qu # Character 竬
+U+7aed Jie # Character ç«
+U+7aee Ping # Character ç«®
+U+7aef Duan # Character 端
+U+7af0 Shao # Character ç«°
+U+7af1 Zhuan # Character 竱
+U+7af2 Ceng # Character 竲
+U+7af3 Deng # Character 竳
+U+7af4 Cui # Character ç«´
+U+7af5 Huai # Character 竵
+U+7af6 Jing # Character 競
+U+7af7 Kan # Character ç«·
+U+7af8 Jing # Character 竸
+U+7af9 Zhu # Character 竹
+U+7afa Zhu # Character 竺
+U+7afb Le # Character ç«»
+U+7afc Peng # Character 竼
+U+7afd Yu # Character 竽
+U+7afe Chi # Character 竾
+U+7aff Gan # Character ç«¿
diff --git a/resources/chars/ascii/row7b.trans b/resources/chars/ascii/row7b.trans
new file mode 100644
index 0000000..c573b9b
--- /dev/null
+++ b/resources/chars/ascii/row7b.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+7b00 Mang # Character ç¬
+U+7b01 Zhu # Character ç¬
+U+7b02 Utsubo # Character ç¬
+U+7b03 Du # Character ç¬
+U+7b04 Ji # Character ç¬
+U+7b05 Xiao # Character ç¬
+U+7b06 Ba # Character ç¬
+U+7b07 Suan # Character ç¬
+U+7b08 Ji # Character ç¬
+U+7b09 Zhen # Character ç¬
+U+7b0a Zhao # Character ç¬
+U+7b0b Sun # Character ç¬
+U+7b0c Ya # Character ç¬
+U+7b0d Zhui # Character ç¬
+U+7b0e Yuan # Character ç¬
+U+7b0f Hu # Character ç¬
+U+7b10 Gang # Character ç¬
+U+7b11 Xiao # Character ç¬
+U+7b12 Cen # Character ç¬
+U+7b13 Pi # Character ç¬
+U+7b14 Bi # Character ç¬
+U+7b15 Jian # Character ç¬
+U+7b16 Yi # Character ç¬
+U+7b17 Dong # Character ç¬
+U+7b18 Shan # Character ç¬
+U+7b19 Sheng # Character ç¬
+U+7b1a Xia # Character ç¬
+U+7b1b Di # Character ç¬
+U+7b1c Zhu # Character ç¬
+U+7b1d Na # Character ç¬
+U+7b1e Chi # Character ç¬
+U+7b1f Gu # Character ç¬
+U+7b20 Li # Character ç¬
+U+7b21 Qie # Character 笡
+U+7b22 Min # Character 笢
+U+7b23 Bao # Character 笣
+U+7b24 Tiao # Character 笤
+U+7b25 Si # Character 笥
+U+7b26 Fu # Character 符
+U+7b27 Ce # Character 笧
+U+7b28 Ben # Character 笨
+U+7b29 Pei # Character 笩
+U+7b2a Da # Character 笪
+U+7b2b Zi # Character 笫
+U+7b2c Di # Character 第
+U+7b2d Ling # Character ç¬
+U+7b2e Ze # Character 笮
+U+7b2f Nu # Character 笯
+U+7b30 Fu # Character 笰
+U+7b31 Gou # Character 笱
+U+7b32 Fan # Character 笲
+U+7b33 Jia # Character 笳
+U+7b34 Ge # Character 笴
+U+7b35 Fan # Character 笵
+U+7b36 Shi # Character 笶
+U+7b37 Mao # Character 笷
+U+7b38 Po # Character 笸
+U+7b39 Sey # Character 笹
+U+7b3a Jian # Character 笺
+U+7b3b Qiong # Character 笻
+U+7b3c Long # Character 笼
+U+7b3d Souke # Character 笽
+U+7b3e Bian # Character 笾
+U+7b3f Luo # Character 笿
+U+7b40 Gui # Character ç
+U+7b41 Qu # Character ç
+U+7b42 Chi # Character ç
+U+7b43 Yin # Character ç
+U+7b44 Yao # Character ç
+U+7b45 Xian # Character ç
+U+7b46 Bi # Character ç
+U+7b47 Qiong # Character ç
+U+7b48 Gua # Character ç
+U+7b49 Deng # Character ç
+U+7b4a Jiao # Character ç
+U+7b4b Jin # Character ç
+U+7b4c Quan # Character ç
+U+7b4d Sun # Character ç
+U+7b4e Ru # Character ç
+U+7b4f Fa # Character ç
+U+7b50 Kuang # Character ç
+U+7b51 Zhu # Character ç
+U+7b52 Tong # Character ç
+U+7b53 Ji # Character ç
+U+7b54 Da # Character ç
+U+7b55 Xing # Character ç
+U+7b56 Ce # Character ç
+U+7b57 Zhong # Character ç
+U+7b58 Kou # Character ç
+U+7b59 Lai # Character ç
+U+7b5a Bi # Character ç
+U+7b5b Shai # Character ç
+U+7b5c Dang # Character ç
+U+7b5d Zheng # Character ç
+U+7b5e Ce # Character ç
+U+7b5f Fu # Character ç
+U+7b60 Yun # Character ç
+U+7b61 Tu # Character ç¡
+U+7b62 Pa # Character ç¢
+U+7b63 Li # Character ç£
+U+7b64 Lang # Character ç¤
+U+7b65 Ju # Character ç¥
+U+7b66 Guan # Character ç¦
+U+7b67 Jian # Character ç§
+U+7b68 Han # Character ç¨
+U+7b69 Tong # Character ç©
+U+7b6a Xia # Character çª
+U+7b6b Zhi # Character ç«
+U+7b6c Cheng # Character ç¬
+U+7b6d Suan # Character ç
+U+7b6e Shi # Character ç®
+U+7b6f Zhu # Character ç¯
+U+7b70 Zuo # Character ç°
+U+7b71 Xiao # Character ç±
+U+7b72 Shao # Character ç²
+U+7b73 Ting # Character ç³
+U+7b74 Ce # Character ç´
+U+7b75 Yan # Character çµ
+U+7b76 Gao # Character ç¶
+U+7b77 Kuai # Character ç·
+U+7b78 Gan # Character ç¸
+U+7b79 Chou # Character ç¹
+U+7b7a Kago # Character çº
+U+7b7b Gang # Character ç»
+U+7b7c Yun # Character ç¼
+U+7b7d O # Character ç½
+U+7b7e Qian # Character ç¾
+U+7b7f Xiao # Character ç¿
+U+7b80 Jian # Character ç®
+U+7b81 Pu # Character ç®
+U+7b82 Lai # Character ç®
+U+7b83 Zou # Character ç®
+U+7b84 Bi # Character ç®
+U+7b85 Bi # Character ç®
+U+7b86 Bi # Character ç®
+U+7b87 Ge # Character ç®
+U+7b88 Chi # Character ç®
+U+7b89 Guai # Character ç®
+U+7b8a Yu # Character ç®
+U+7b8b Jian # Character ç®
+U+7b8c Zhao # Character ç®
+U+7b8d Gu # Character ç®
+U+7b8e Chi # Character ç®
+U+7b8f Zheng # Character ç®
+U+7b90 Jing # Character ç®
+U+7b91 Sha # Character ç®
+U+7b92 Zhou # Character ç®
+U+7b93 Lu # Character ç®
+U+7b94 Bo # Character ç®
+U+7b95 Ji # Character ç®
+U+7b96 Lin # Character ç®
+U+7b97 Suan # Character ç®
+U+7b98 Jun # Character ç®
+U+7b99 Fu # Character ç®
+U+7b9a Zha # Character ç®
+U+7b9b Gu # Character ç®
+U+7b9c Kong # Character ç®
+U+7b9d Qian # Character ç®
+U+7b9e Quan # Character ç®
+U+7b9f Jun # Character ç®
+U+7ba0 Chui # Character ç®
+U+7ba1 Guan # Character 管
+U+7ba2 Yuan # Character 箢
+U+7ba3 Ce # Character 箣
+U+7ba4 Ju # Character 箤
+U+7ba5 Bo # Character 箥
+U+7ba6 Ze # Character 箦
+U+7ba7 Qie # Character 箧
+U+7ba8 Tuo # Character 箨
+U+7ba9 Luo # Character 箩
+U+7baa Dan # Character 箪
+U+7bab Xiao # Character 箫
+U+7bac Ruo # Character 箬
+U+7bad Jian # Character ç®
+U+7bae Xuan # Character ç®®
+U+7baf Bian # Character 箯
+U+7bb0 Sun # Character ç®°
+U+7bb1 Xiang # Character ç®±
+U+7bb2 Xian # Character 箲
+U+7bb3 Ping # Character 箳
+U+7bb4 Zhen # Character ç®´
+U+7bb5 Sheng # Character 箵
+U+7bb6 Hu # Character 箶
+U+7bb7 Shi # Character ç®·
+U+7bb8 Zhu # Character 箸
+U+7bb9 Yue # Character 箹
+U+7bba Chun # Character 箺
+U+7bbb Lu # Character ç®»
+U+7bbc Wu # Character 箼
+U+7bbd Dong # Character 箽
+U+7bbe Xiao # Character 箾
+U+7bbf Ji # Character 箿
+U+7bc0 Jie # Character ç¯
+U+7bc1 Huang # Character ç¯
+U+7bc2 Xing # Character ç¯
+U+7bc3 Mei # Character ç¯
+U+7bc4 Fan # Character ç¯
+U+7bc5 Chui # Character ç¯
+U+7bc6 Zhuan # Character ç¯
+U+7bc7 Pian # Character ç¯
+U+7bc8 Feng # Character ç¯
+U+7bc9 Zhu # Character ç¯
+U+7bca Hong # Character ç¯
+U+7bcb Qie # Character ç¯
+U+7bcc Hou # Character ç¯
+U+7bcd Qiu # Character ç¯
+U+7bce Miao # Character ç¯
+U+7bcf Qian # Character ç¯
+U+7bd0 ? # Character ç¯
+U+7bd1 Kui # Character ç¯
+U+7bd2 Sik # Character ç¯
+U+7bd3 Lou # Character ç¯
+U+7bd4 Yun # Character ç¯
+U+7bd5 He # Character ç¯
+U+7bd6 Tang # Character ç¯
+U+7bd7 Yue # Character ç¯
+U+7bd8 Chou # Character ç¯
+U+7bd9 Gao # Character ç¯
+U+7bda Fei # Character ç¯
+U+7bdb Ruo # Character ç¯
+U+7bdc Zheng # Character ç¯
+U+7bdd Gou # Character ç¯
+U+7bde Nie # Character ç¯
+U+7bdf Qian # Character ç¯
+U+7be0 Xiao # Character ç¯
+U+7be1 Cuan # Character 篡
+U+7be2 Gong # Character 篢
+U+7be3 Pang # Character 篣
+U+7be4 Du # Character 篤
+U+7be5 Li # Character 篥
+U+7be6 Bi # Character 篦
+U+7be7 Zhuo # Character 篧
+U+7be8 Chu # Character 篨
+U+7be9 Shai # Character 篩
+U+7bea Chi # Character 篪
+U+7beb Zhu # Character 篫
+U+7bec Qiang # Character 篬
+U+7bed Long # Character ç¯
+U+7bee Lan # Character 篮
+U+7bef Jian # Character 篯
+U+7bf0 Bu # Character 篰
+U+7bf1 Li # Character 篱
+U+7bf2 Hui # Character 篲
+U+7bf3 Bi # Character 篳
+U+7bf4 Di # Character 篴
+U+7bf5 Cong # Character 篵
+U+7bf6 Yan # Character 篶
+U+7bf7 Peng # Character 篷
+U+7bf8 Sen # Character 篸
+U+7bf9 Zhuan # Character 篹
+U+7bfa Pai # Character 篺
+U+7bfb Piao # Character 篻
+U+7bfc Dou # Character 篼
+U+7bfd Yu # Character 篽
+U+7bfe Mie # Character 篾
+U+7bff Zhuan # Character 篿
diff --git a/resources/chars/ascii/row7c.trans b/resources/chars/ascii/row7c.trans
new file mode 100644
index 0000000..8ec2204
--- /dev/null
+++ b/resources/chars/ascii/row7c.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+7c00 Ze # Character ç°
+U+7c01 Xi # Character ç°
+U+7c02 Guo # Character ç°
+U+7c03 Yi # Character ç°
+U+7c04 Hu # Character ç°
+U+7c05 Chan # Character ç°
+U+7c06 Kou # Character ç°
+U+7c07 Cu # Character ç°
+U+7c08 Ping # Character ç°
+U+7c09 Chou # Character ç°
+U+7c0a Ji # Character ç°
+U+7c0b Gui # Character ç°
+U+7c0c Su # Character ç°
+U+7c0d Lou # Character ç°
+U+7c0e Zha # Character ç°
+U+7c0f Lu # Character ç°
+U+7c10 Nian # Character ç°
+U+7c11 Suo # Character ç°
+U+7c12 Cuan # Character ç°
+U+7c13 Sasara # Character ç°
+U+7c14 Suo # Character ç°
+U+7c15 Le # Character ç°
+U+7c16 Duan # Character ç°
+U+7c17 Yana # Character ç°
+U+7c18 Xiao # Character ç°
+U+7c19 Bo # Character ç°
+U+7c1a Mi # Character ç°
+U+7c1b Si # Character ç°
+U+7c1c Dang # Character ç°
+U+7c1d Liao # Character ç°
+U+7c1e Dan # Character ç°
+U+7c1f Dian # Character ç°
+U+7c20 Fu # Character ç°
+U+7c21 Jian # Character ç°¡
+U+7c22 Min # Character ç°¢
+U+7c23 Kui # Character ç°£
+U+7c24 Dai # Character ç°¤
+U+7c25 Qiao # Character ç°¥
+U+7c26 Deng # Character ç°¦
+U+7c27 Huang # Character ç°§
+U+7c28 Sun # Character ç°¨
+U+7c29 Lao # Character ç°©
+U+7c2a Zan # Character ç°ª
+U+7c2b Xiao # Character ç°«
+U+7c2c Du # Character ç°¬
+U+7c2d Shi # Character ç°
+U+7c2e Zan # Character ç°®
+U+7c2f ? # Character ç°¯
+U+7c30 Pai # Character ç°°
+U+7c31 Hata # Character ç°±
+U+7c32 Pai # Character ç°²
+U+7c33 Gan # Character ç°³
+U+7c34 Ju # Character ç°´
+U+7c35 Du # Character ç°µ
+U+7c36 Lu # Character ç°¶
+U+7c37 Yan # Character ç°·
+U+7c38 Bo # Character ç°¸
+U+7c39 Dang # Character ç°¹
+U+7c3a Sai # Character ç°º
+U+7c3b Ke # Character ç°»
+U+7c3c Long # Character ç°¼
+U+7c3d Qian # Character ç°½
+U+7c3e Lian # Character ç°¾
+U+7c3f Bo # Character ç°¿
+U+7c40 Zhou # Character ç±
+U+7c41 Lai # Character ç±
+U+7c42 ? # Character ç±
+U+7c43 Lan # Character ç±
+U+7c44 Kui # Character ç±
+U+7c45 Yu # Character ç±
+U+7c46 Yue # Character ç±
+U+7c47 Hao # Character ç±
+U+7c48 Zhen # Character ç±
+U+7c49 Tai # Character ç±
+U+7c4a Ti # Character ç±
+U+7c4b Mi # Character ç±
+U+7c4c Chou # Character ç±
+U+7c4d Ji # Character ç±
+U+7c4e ? # Character ç±
+U+7c4f Hata # Character ç±
+U+7c50 Teng # Character ç±
+U+7c51 Zhuan # Character ç±
+U+7c52 Zhou # Character ç±
+U+7c53 Fan # Character ç±
+U+7c54 Sou # Character ç±
+U+7c55 Zhou # Character ç±
+U+7c56 Kuji # Character ç±
+U+7c57 Zhuo # Character ç±
+U+7c58 Teng # Character ç±
+U+7c59 Lu # Character ç±
+U+7c5a Lu # Character ç±
+U+7c5b Jian # Character ç±
+U+7c5c Tuo # Character ç±
+U+7c5d Ying # Character ç±
+U+7c5e Yu # Character ç±
+U+7c5f Lai # Character ç±
+U+7c60 Long # Character ç±
+U+7c61 Shinshi # Character 籡
+U+7c62 Lian # Character ç±¢
+U+7c63 Lan # Character ç±£
+U+7c64 Qian # Character 籤
+U+7c65 Yue # Character ç±¥
+U+7c66 Zhong # Character 籦
+U+7c67 Qu # Character 籧
+U+7c68 Lian # Character 籨
+U+7c69 Bian # Character 籩
+U+7c6a Duan # Character 籪
+U+7c6b Zuan # Character 籫
+U+7c6c Li # Character 籬
+U+7c6d Si # Character ç±
+U+7c6e Luo # Character ç±®
+U+7c6f Ying # Character 籯
+U+7c70 Yue # Character ç±°
+U+7c71 Zhuo # Character ç±±
+U+7c72 Xu # Character ç±²
+U+7c73 Mi # Character ç±³
+U+7c74 Di # Character ç±´
+U+7c75 Fan # Character ç±µ
+U+7c76 Shen # Character 籶
+U+7c77 Zhe # Character ç±·
+U+7c78 Shen # Character 籸
+U+7c79 Nu # Character ç±¹
+U+7c7a Xie # Character 籺
+U+7c7b Lei # Character ç±»
+U+7c7c Xian # Character ç±¼
+U+7c7d Zi # Character ç±½
+U+7c7e Ni # Character ç±¾
+U+7c7f Cun # Character 籿
+U+7c80 ? # Character ç²
+U+7c81 Qian # Character ç²
+U+7c82 Kume # Character ç²
+U+7c83 Bi # Character ç²
+U+7c84 Ban # Character ç²
+U+7c85 Wu # Character ç²
+U+7c86 Sha # Character ç²
+U+7c87 Kang # Character ç²
+U+7c88 Rou # Character ç²
+U+7c89 Fen # Character ç²
+U+7c8a Bi # Character ç²
+U+7c8b Cui # Character ç²
+U+7c8c ? # Character ç²
+U+7c8d Li # Character ç²
+U+7c8e Chi # Character ç²
+U+7c8f Nukamiso # Character ç²
+U+7c90 Ro # Character ç²
+U+7c91 Ba # Character ç²
+U+7c92 Li # Character ç²
+U+7c93 Gan # Character ç²
+U+7c94 Ju # Character ç²
+U+7c95 Po # Character ç²
+U+7c96 Mo # Character ç²
+U+7c97 Cu # Character ç²
+U+7c98 Nian # Character ç²
+U+7c99 Zhou # Character ç²
+U+7c9a Li # Character ç²
+U+7c9b Su # Character ç²
+U+7c9c Tiao # Character ç²
+U+7c9d Li # Character ç²
+U+7c9e Qi # Character ç²
+U+7c9f Su # Character ç²
+U+7ca0 Hong # Character ç²
+U+7ca1 Tong # Character 粡
+U+7ca2 Zi # Character ç²¢
+U+7ca3 Ce # Character ç²£
+U+7ca4 Yue # Character 粤
+U+7ca5 Zhou # Character ç²¥
+U+7ca6 Lin # Character 粦
+U+7ca7 Zhuang # Character 粧
+U+7ca8 Bai # Character 粨
+U+7ca9 ? # Character 粩
+U+7caa Fen # Character 粪
+U+7cab Ji # Character 粫
+U+7cac ? # Character 粬
+U+7cad Sukumo # Character ç²
+U+7cae Liang # Character ç²®
+U+7caf Xian # Character 粯
+U+7cb0 Fu # Character ç²°
+U+7cb1 Liang # Character ç²±
+U+7cb2 Can # Character ç²²
+U+7cb3 Geng # Character ç²³
+U+7cb4 Li # Character ç²´
+U+7cb5 Yue # Character ç²µ
+U+7cb6 Lu # Character 粶
+U+7cb7 Ju # Character ç²·
+U+7cb8 Qi # Character 粸
+U+7cb9 Cui # Character ç²¹
+U+7cba Bai # Character 粺
+U+7cbb Zhang # Character ç²»
+U+7cbc Lin # Character ç²¼
+U+7cbd Zong # Character ç²½
+U+7cbe Jing # Character ç²¾
+U+7cbf Guo # Character 粿
+U+7cc0 Kouji # Character ç³
+U+7cc1 San # Character ç³
+U+7cc2 San # Character ç³
+U+7cc3 Tang # Character ç³
+U+7cc4 Bian # Character ç³
+U+7cc5 Rou # Character ç³
+U+7cc6 Mian # Character ç³
+U+7cc7 Hou # Character ç³
+U+7cc8 Xu # Character ç³
+U+7cc9 Zong # Character ç³
+U+7cca Hu # Character ç³
+U+7ccb Jian # Character ç³
+U+7ccc Zan # Character ç³
+U+7ccd Ci # Character ç³
+U+7cce Li # Character ç³
+U+7ccf Xie # Character ç³
+U+7cd0 Fu # Character ç³
+U+7cd1 Ni # Character ç³
+U+7cd2 Bei # Character ç³
+U+7cd3 Gu # Character ç³
+U+7cd4 Xiu # Character ç³
+U+7cd5 Gao # Character ç³
+U+7cd6 Tang # Character ç³
+U+7cd7 Qiu # Character ç³
+U+7cd8 Sukumo # Character ç³
+U+7cd9 Cao # Character ç³
+U+7cda Zhuang # Character ç³
+U+7cdb Tang # Character ç³
+U+7cdc Mi # Character ç³
+U+7cdd San # Character ç³
+U+7cde Fen # Character ç³
+U+7cdf Zao # Character ç³
+U+7ce0 Kang # Character ç³
+U+7ce1 Jiang # Character 糡
+U+7ce2 Mo # Character ç³¢
+U+7ce3 San # Character ç³£
+U+7ce4 San # Character 糤
+U+7ce5 Nuo # Character ç³¥
+U+7ce6 Xi # Character 糦
+U+7ce7 Liang # Character 糧
+U+7ce8 Jiang # Character 糨
+U+7ce9 Kuai # Character 糩
+U+7cea Bo # Character 糪
+U+7ceb Huan # Character 糫
+U+7cec ? # Character 糬
+U+7ced Zong # Character ç³
+U+7cee Xian # Character ç³®
+U+7cef Nuo # Character 糯
+U+7cf0 Tuan # Character ç³°
+U+7cf1 Nie # Character ç³±
+U+7cf2 Li # Character ç³²
+U+7cf3 Zuo # Character ç³³
+U+7cf4 Di # Character ç³´
+U+7cf5 Nie # Character ç³µ
+U+7cf6 Tiao # Character 糶
+U+7cf7 Lan # Character ç³·
+U+7cf8 Mi # Character 糸
+U+7cf9 Jiao # Character ç³¹
+U+7cfa Jiu # Character 糺
+U+7cfb Xi # Character ç³»
+U+7cfc Gong # Character ç³¼
+U+7cfd Zheng # Character ç³½
+U+7cfe Jiu # Character ç³¾
+U+7cff You # Character 糿
diff --git a/resources/chars/ascii/row7d.trans b/resources/chars/ascii/row7d.trans
new file mode 100644
index 0000000..2e494bf
--- /dev/null
+++ b/resources/chars/ascii/row7d.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+7d00 Ji # Character ç´
+U+7d01 Cha # Character ç´
+U+7d02 Zhou # Character ç´
+U+7d03 Xun # Character ç´
+U+7d04 Yue # Character ç´
+U+7d05 Hong # Character ç´
+U+7d06 Yu # Character ç´
+U+7d07 He # Character ç´
+U+7d08 Wan # Character ç´
+U+7d09 Ren # Character ç´
+U+7d0a Wen # Character ç´
+U+7d0b Wen # Character ç´
+U+7d0c Qiu # Character ç´
+U+7d0d Na # Character ç´
+U+7d0e Zi # Character ç´
+U+7d0f Tou # Character ç´
+U+7d10 Niu # Character ç´
+U+7d11 Fou # Character ç´
+U+7d12 Jie # Character ç´
+U+7d13 Shu # Character ç´
+U+7d14 Chun # Character ç´
+U+7d15 Pi # Character ç´
+U+7d16 Yin # Character ç´
+U+7d17 Sha # Character ç´
+U+7d18 Hong # Character ç´
+U+7d19 Zhi # Character ç´
+U+7d1a Ji # Character ç´
+U+7d1b Fen # Character ç´
+U+7d1c Yun # Character ç´
+U+7d1d Ren # Character ç´
+U+7d1e Dan # Character ç´
+U+7d1f Jin # Character ç´
+U+7d20 Su # Character ç´
+U+7d21 Fang # Character ç´¡
+U+7d22 Suo # Character ç´¢
+U+7d23 Cui # Character ç´£
+U+7d24 Jiu # Character ç´¤
+U+7d25 Zha # Character ç´¥
+U+7d26 Kinu # Character ç´¦
+U+7d27 Jin # Character ç´§
+U+7d28 Fu # Character ç´¨
+U+7d29 Zhi # Character ç´©
+U+7d2a Ci # Character ç´ª
+U+7d2b Zi # Character ç´«
+U+7d2c Chou # Character ç´¬
+U+7d2d Hong # Character ç´
+U+7d2e Zha # Character ç´®
+U+7d2f Lei # Character ç´¯
+U+7d30 Xi # Character ç´°
+U+7d31 Fu # Character ç´±
+U+7d32 Xie # Character ç´²
+U+7d33 Shen # Character ç´³
+U+7d34 Bei # Character ç´´
+U+7d35 Zhu # Character ç´µ
+U+7d36 Qu # Character ç´¶
+U+7d37 Ling # Character ç´·
+U+7d38 Zhu # Character ç´¸
+U+7d39 Shao # Character ç´¹
+U+7d3a Gan # Character ç´º
+U+7d3b Yang # Character ç´»
+U+7d3c Fu # Character ç´¼
+U+7d3d Tuo # Character ç´½
+U+7d3e Zhen # Character ç´¾
+U+7d3f Dai # Character ç´¿
+U+7d40 Zhuo # Character çµ
+U+7d41 Shi # Character çµ
+U+7d42 Zhong # Character çµ
+U+7d43 Xian # Character çµ
+U+7d44 Zu # Character çµ
+U+7d45 Jiong # Character çµ
+U+7d46 Ban # Character çµ
+U+7d47 Ju # Character çµ
+U+7d48 Mo # Character çµ
+U+7d49 Shu # Character çµ
+U+7d4a Zui # Character çµ
+U+7d4b Wata # Character çµ
+U+7d4c Jing # Character çµ
+U+7d4d Ren # Character çµ
+U+7d4e Heng # Character çµ
+U+7d4f Xie # Character çµ
+U+7d50 Jie # Character çµ
+U+7d51 Zhu # Character çµ
+U+7d52 Chou # Character çµ
+U+7d53 Gua # Character çµ
+U+7d54 Bai # Character çµ
+U+7d55 Jue # Character çµ
+U+7d56 Kuang # Character çµ
+U+7d57 Hu # Character çµ
+U+7d58 Ci # Character çµ
+U+7d59 Geng # Character çµ
+U+7d5a Geng # Character çµ
+U+7d5b Tao # Character çµ
+U+7d5c Xie # Character çµ
+U+7d5d Ku # Character çµ
+U+7d5e Jiao # Character çµ
+U+7d5f Quan # Character çµ
+U+7d60 Gai # Character çµ
+U+7d61 Luo # Character 絡
+U+7d62 Xuan # Character çµ¢
+U+7d63 Bing # Character çµ£
+U+7d64 Xian # Character 絤
+U+7d65 Fu # Character çµ¥
+U+7d66 Gei # Character 給
+U+7d67 Tong # Character 絧
+U+7d68 Rong # Character 絨
+U+7d69 Tiao # Character 絩
+U+7d6a Yin # Character 絪
+U+7d6b Lei # Character 絫
+U+7d6c Xie # Character 絬
+U+7d6d Quan # Character çµ
+U+7d6e Xu # Character çµ®
+U+7d6f Lun # Character 絯
+U+7d70 Die # Character çµ°
+U+7d71 Tong # Character çµ±
+U+7d72 Si # Character çµ²
+U+7d73 Jiang # Character çµ³
+U+7d74 Xiang # Character çµ´
+U+7d75 Hui # Character çµµ
+U+7d76 Jue # Character 絶
+U+7d77 Zhi # Character çµ·
+U+7d78 Jian # Character 絸
+U+7d79 Juan # Character çµ¹
+U+7d7a Chi # Character 絺
+U+7d7b Mian # Character çµ»
+U+7d7c Zhen # Character çµ¼
+U+7d7d Lu # Character çµ½
+U+7d7e Cheng # Character çµ¾
+U+7d7f Qiu # Character 絿
+U+7d80 Shu # Character ç¶
+U+7d81 Bang # Character ç¶
+U+7d82 Tong # Character ç¶
+U+7d83 Xiao # Character ç¶
+U+7d84 Wan # Character ç¶
+U+7d85 Qin # Character ç¶
+U+7d86 Geng # Character ç¶
+U+7d87 Xiu # Character ç¶
+U+7d88 Ti # Character ç¶
+U+7d89 Xiu # Character ç¶
+U+7d8a Xie # Character ç¶
+U+7d8b Hong # Character ç¶
+U+7d8c Xi # Character ç¶
+U+7d8d Fu # Character ç¶
+U+7d8e Ting # Character ç¶
+U+7d8f Sui # Character ç¶
+U+7d90 Dui # Character ç¶
+U+7d91 Kun # Character ç¶
+U+7d92 Fu # Character ç¶
+U+7d93 Jing # Character ç¶
+U+7d94 Hu # Character ç¶
+U+7d95 Zhi # Character ç¶
+U+7d96 Yan # Character ç¶
+U+7d97 Jiong # Character ç¶
+U+7d98 Feng # Character ç¶
+U+7d99 Ji # Character ç¶
+U+7d9a Sok # Character ç¶
+U+7d9b Kase # Character ç¶
+U+7d9c Zong # Character ç¶
+U+7d9d Lin # Character ç¶
+U+7d9e Duo # Character ç¶
+U+7d9f Li # Character ç¶
+U+7da0 Lu # Character ç¶
+U+7da1 Liang # Character 綡
+U+7da2 Chou # Character 綢
+U+7da3 Quan # Character 綣
+U+7da4 Shao # Character 綤
+U+7da5 Qi # Character 綥
+U+7da6 Qi # Character 綦
+U+7da7 Zhun # Character 綧
+U+7da8 Qi # Character 綨
+U+7da9 Wan # Character 綩
+U+7daa Qian # Character 綪
+U+7dab Xian # Character 綫
+U+7dac Shou # Character 綬
+U+7dad Wei # Character ç¶
+U+7dae Qi # Character 綮
+U+7daf Tao # Character 綯
+U+7db0 Wan # Character 綰
+U+7db1 Gang # Character 綱
+U+7db2 Wang # Character 網
+U+7db3 Beng # Character 綳
+U+7db4 Zhui # Character 綴
+U+7db5 Cai # Character 綵
+U+7db6 Guo # Character 綶
+U+7db7 Cui # Character 綷
+U+7db8 Lun # Character 綸
+U+7db9 Liu # Character 綹
+U+7dba Qi # Character 綺
+U+7dbb Zhan # Character 綻
+U+7dbc Bei # Character 綼
+U+7dbd Chuo # Character 綽
+U+7dbe Ling # Character 綾
+U+7dbf Mian # Character 綿
+U+7dc0 Qi # Character ç·
+U+7dc1 Qie # Character ç·
+U+7dc2 Tan # Character ç·
+U+7dc3 Zong # Character ç·
+U+7dc4 Gun # Character ç·
+U+7dc5 Zou # Character ç·
+U+7dc6 Yi # Character ç·
+U+7dc7 Zi # Character ç·
+U+7dc8 Xing # Character ç·
+U+7dc9 Liang # Character ç·
+U+7dca Jin # Character ç·
+U+7dcb Fei # Character ç·
+U+7dcc Rui # Character ç·
+U+7dcd Min # Character ç·
+U+7dce Yu # Character ç·
+U+7dcf Zong # Character ç·
+U+7dd0 Fan # Character ç·
+U+7dd1 Lu # Character ç·
+U+7dd2 Xu # Character ç·
+U+7dd3 Yingl # Character ç·
+U+7dd4 Zhang # Character ç·
+U+7dd5 Kasuri # Character ç·
+U+7dd6 Xu # Character ç·
+U+7dd7 Xiang # Character ç·
+U+7dd8 Jian # Character ç·
+U+7dd9 Ke # Character ç·
+U+7dda Xian # Character ç·
+U+7ddb Ruan # Character ç·
+U+7ddc Mian # Character ç·
+U+7ddd Qi # Character ç·
+U+7dde Duan # Character ç·
+U+7ddf Zhong # Character ç·
+U+7de0 Di # Character ç·
+U+7de1 Min # Character ç·¡
+U+7de2 Miao # Character ç·¢
+U+7de3 Yuan # Character ç·£
+U+7de4 Xie # Character ç·¤
+U+7de5 Bao # Character ç·¥
+U+7de6 Si # Character ç·¦
+U+7de7 Qiu # Character ç·§
+U+7de8 Bian # Character ç·¨
+U+7de9 Huan # Character ç·©
+U+7dea Geng # Character ç·ª
+U+7deb Cong # Character ç·«
+U+7dec Mian # Character ç·¬
+U+7ded Wei # Character ç·
+U+7dee Fu # Character ç·®
+U+7def Wei # Character ç·¯
+U+7df0 Yu # Character ç·°
+U+7df1 Gou # Character ç·±
+U+7df2 Miao # Character ç·²
+U+7df3 Xie # Character ç·³
+U+7df4 Lian # Character ç·´
+U+7df5 Zong # Character ç·µ
+U+7df6 Bian # Character ç·¶
+U+7df7 Yun # Character ç··
+U+7df8 Yin # Character ç·¸
+U+7df9 Ti # Character ç·¹
+U+7dfa Gua # Character ç·º
+U+7dfb Zhi # Character ç·»
+U+7dfc Yun # Character ç·¼
+U+7dfd Cheng # Character ç·½
+U+7dfe Chan # Character ç·¾
+U+7dff Dai # Character ç·¿
diff --git a/resources/chars/ascii/row7e.trans b/resources/chars/ascii/row7e.trans
new file mode 100644
index 0000000..3cf945e
--- /dev/null
+++ b/resources/chars/ascii/row7e.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+7e00 Xia # Character ç¸
+U+7e01 Yuan # Character ç¸
+U+7e02 Zong # Character ç¸
+U+7e03 Xu # Character ç¸
+U+7e04 Nawa # Character ç¸
+U+7e05 Odoshi # Character ç¸
+U+7e06 Geng # Character ç¸
+U+7e07 Sen # Character ç¸
+U+7e08 Ying # Character ç¸
+U+7e09 Jin # Character ç¸
+U+7e0a Yi # Character ç¸
+U+7e0b Zhui # Character ç¸
+U+7e0c Ni # Character ç¸
+U+7e0d Bang # Character ç¸
+U+7e0e Gu # Character ç¸
+U+7e0f Pan # Character ç¸
+U+7e10 Zhou # Character ç¸
+U+7e11 Jian # Character ç¸
+U+7e12 Cuo # Character ç¸
+U+7e13 Quan # Character ç¸
+U+7e14 Shuang # Character ç¸
+U+7e15 Yun # Character ç¸
+U+7e16 Xia # Character ç¸
+U+7e17 Shuai # Character ç¸
+U+7e18 Xi # Character ç¸
+U+7e19 Rong # Character ç¸
+U+7e1a Tao # Character ç¸
+U+7e1b Fu # Character ç¸
+U+7e1c Yun # Character ç¸
+U+7e1d Zhen # Character ç¸
+U+7e1e Gao # Character ç¸
+U+7e1f Ru # Character ç¸
+U+7e20 Hu # Character ç¸
+U+7e21 Zai # Character 縡
+U+7e22 Teng # Character 縢
+U+7e23 Xian # Character 縣
+U+7e24 Su # Character 縤
+U+7e25 Zhen # Character 縥
+U+7e26 Zong # Character 縦
+U+7e27 Tao # Character 縧
+U+7e28 Horo # Character 縨
+U+7e29 Cai # Character 縩
+U+7e2a Bi # Character 縪
+U+7e2b Feng # Character 縫
+U+7e2c Cu # Character 縬
+U+7e2d Li # Character ç¸
+U+7e2e Suo # Character 縮
+U+7e2f Yin # Character 縯
+U+7e30 Xi # Character 縰
+U+7e31 Zong # Character 縱
+U+7e32 Lei # Character 縲
+U+7e33 Zhuan # Character 縳
+U+7e34 Qian # Character 縴
+U+7e35 Man # Character 縵
+U+7e36 Zhi # Character 縶
+U+7e37 Lu # Character 縷
+U+7e38 Mo # Character 縸
+U+7e39 Piao # Character 縹
+U+7e3a Lian # Character 縺
+U+7e3b Mi # Character 縻
+U+7e3c Xuan # Character 縼
+U+7e3d Zong # Character 總
+U+7e3e Ji # Character 績
+U+7e3f Shan # Character 縿
+U+7e40 Sui # Character ç¹
+U+7e41 Fan # Character ç¹
+U+7e42 Shuai # Character ç¹
+U+7e43 Beng # Character ç¹
+U+7e44 Yi # Character ç¹
+U+7e45 Sao # Character ç¹
+U+7e46 Mou # Character ç¹
+U+7e47 Zhou # Character ç¹
+U+7e48 Qiang # Character ç¹
+U+7e49 Hun # Character ç¹
+U+7e4a Sem # Character ç¹
+U+7e4b Xi # Character ç¹
+U+7e4c Jung # Character ç¹
+U+7e4d Xiu # Character ç¹
+U+7e4e Ran # Character ç¹
+U+7e4f Xuan # Character ç¹
+U+7e50 Hui # Character ç¹
+U+7e51 Qiao # Character ç¹
+U+7e52 Zeng # Character ç¹
+U+7e53 Zuo # Character ç¹
+U+7e54 Zhi # Character ç¹
+U+7e55 Shan # Character ç¹
+U+7e56 San # Character ç¹
+U+7e57 Lin # Character ç¹
+U+7e58 Yu # Character ç¹
+U+7e59 Fan # Character ç¹
+U+7e5a Liao # Character ç¹
+U+7e5b Chuo # Character ç¹
+U+7e5c Zun # Character ç¹
+U+7e5d Jian # Character ç¹
+U+7e5e Rao # Character ç¹
+U+7e5f Chan # Character ç¹
+U+7e60 Rui # Character ç¹
+U+7e61 Xiu # Character 繡
+U+7e62 Hui # Character ç¹¢
+U+7e63 Hua # Character ç¹£
+U+7e64 Zuan # Character 繤
+U+7e65 Xi # Character ç¹¥
+U+7e66 Qiang # Character 繦
+U+7e67 Un # Character 繧
+U+7e68 Da # Character 繨
+U+7e69 Sheng # Character 繩
+U+7e6a Hui # Character 繪
+U+7e6b Xi # Character 繫
+U+7e6c Se # Character 繬
+U+7e6d Jian # Character ç¹
+U+7e6e Jiang # Character ç¹®
+U+7e6f Huan # Character 繯
+U+7e70 Zao # Character ç¹°
+U+7e71 Cong # Character ç¹±
+U+7e72 Jie # Character ç¹²
+U+7e73 Jiao # Character ç¹³
+U+7e74 Bo # Character ç¹´
+U+7e75 Chan # Character ç¹µ
+U+7e76 Yi # Character 繶
+U+7e77 Nao # Character ç¹·
+U+7e78 Sui # Character 繸
+U+7e79 Yi # Character ç¹¹
+U+7e7a Shai # Character 繺
+U+7e7b Xu # Character ç¹»
+U+7e7c Ji # Character ç¹¼
+U+7e7d Bin # Character ç¹½
+U+7e7e Qian # Character ç¹¾
+U+7e7f Lan # Character 繿
+U+7e80 Pu # Character çº
+U+7e81 Xun # Character çº
+U+7e82 Zuan # Character çº
+U+7e83 Qi # Character çº
+U+7e84 Peng # Character çº
+U+7e85 Li # Character çº
+U+7e86 Mo # Character çº
+U+7e87 Lei # Character çº
+U+7e88 Xie # Character çº
+U+7e89 Zuan # Character çº
+U+7e8a Kuang # Character çº
+U+7e8b You # Character çº
+U+7e8c Xu # Character çº
+U+7e8d Lei # Character çº
+U+7e8e Xian # Character çº
+U+7e8f Chan # Character çº
+U+7e90 Kou # Character çº
+U+7e91 Lu # Character çº
+U+7e92 Chan # Character çº
+U+7e93 Ying # Character çº
+U+7e94 Cai # Character çº
+U+7e95 Xiang # Character çº
+U+7e96 Xian # Character çº
+U+7e97 Zui # Character çº
+U+7e98 Zuan # Character çº
+U+7e99 Luo # Character çº
+U+7e9a Xi # Character çº
+U+7e9b Dao # Character çº
+U+7e9c Lan # Character çº
+U+7e9d Lei # Character çº
+U+7e9e Lian # Character çº
+U+7e9f Si # Character çº
+U+7ea0 Jiu # Character çº
+U+7ea1 Yu # Character 纡
+U+7ea2 Hong # Character 红
+U+7ea3 Zhou # Character 纣
+U+7ea4 Xian # Character 纤
+U+7ea5 He # Character 纥
+U+7ea6 Yue # Character 约
+U+7ea7 Ji # Character 级
+U+7ea8 Wan # Character 纨
+U+7ea9 Kuang # Character 纩
+U+7eaa Ji # Character 纪
+U+7eab Ren # Character 纫
+U+7eac Wei # Character 纬
+U+7ead Yun # Character çº
+U+7eae Hong # Character 纮
+U+7eaf Chun # Character 纯
+U+7eb0 Pi # Character 纰
+U+7eb1 Sha # Character 纱
+U+7eb2 Gang # Character 纲
+U+7eb3 Na # Character 纳
+U+7eb4 Ren # Character 纴
+U+7eb5 Zong # Character 纵
+U+7eb6 Lun # Character 纶
+U+7eb7 Fen # Character 纷
+U+7eb8 Zhi # Character 纸
+U+7eb9 Wen # Character 纹
+U+7eba Fang # Character 纺
+U+7ebb Zhu # Character 纻
+U+7ebc Yin # Character 纼
+U+7ebd Niu # Character 纽
+U+7ebe Shu # Character 纾
+U+7ebf Xian # Character 线
+U+7ec0 Gan # Character ç»
+U+7ec1 Xie # Character ç»
+U+7ec2 Fu # Character ç»
+U+7ec3 Lian # Character ç»
+U+7ec4 Zu # Character ç»
+U+7ec5 Shen # Character ç»
+U+7ec6 Xi # Character ç»
+U+7ec7 Zhi # Character ç»
+U+7ec8 Zhong # Character ç»
+U+7ec9 Zhou # Character ç»
+U+7eca Ban # Character ç»
+U+7ecb Fu # Character ç»
+U+7ecc Zhuo # Character ç»
+U+7ecd Shao # Character ç»
+U+7ece Yi # Character ç»
+U+7ecf Jing # Character ç»
+U+7ed0 Dai # Character ç»
+U+7ed1 Bang # Character ç»
+U+7ed2 Rong # Character ç»
+U+7ed3 Jie # Character ç»
+U+7ed4 Ku # Character ç»
+U+7ed5 Rao # Character ç»
+U+7ed6 Die # Character ç»
+U+7ed7 Heng # Character ç»
+U+7ed8 Hui # Character ç»
+U+7ed9 Gei # Character ç»
+U+7eda Xuan # Character ç»
+U+7edb Jiang # Character ç»
+U+7edc Luo # Character ç»
+U+7edd Jue # Character ç»
+U+7ede Jiao # Character ç»
+U+7edf Tong # Character ç»
+U+7ee0 Geng # Character ç»
+U+7ee1 Xiao # Character 绡
+U+7ee2 Juan # Character 绢
+U+7ee3 Xiu # Character 绣
+U+7ee4 Xi # Character 绤
+U+7ee5 Sui # Character 绥
+U+7ee6 Tao # Character 绦
+U+7ee7 Ji # Character 继
+U+7ee8 Ti # Character 绨
+U+7ee9 Ji # Character 绩
+U+7eea Xu # Character 绪
+U+7eeb Ling # Character 绫
+U+7eec ? # Character 绬
+U+7eed Xu # Character ç»
+U+7eee Qi # Character ç»®
+U+7eef Fei # Character 绯
+U+7ef0 Chuo # Character ç»°
+U+7ef1 Zhang # Character ç»±
+U+7ef2 Gun # Character 绲
+U+7ef3 Sheng # Character 绳
+U+7ef4 Wei # Character ç»´
+U+7ef5 Mian # Character 绵
+U+7ef6 Shou # Character 绶
+U+7ef7 Beng # Character ç»·
+U+7ef8 Chou # Character 绸
+U+7ef9 Tao # Character 绹
+U+7efa Liu # Character 绺
+U+7efb Quan # Character ç»»
+U+7efc Zong # Character 综
+U+7efd Zhan # Character 绽
+U+7efe Wan # Character 绾
+U+7eff Lu # Character 绿
diff --git a/resources/chars/ascii/row7f.trans b/resources/chars/ascii/row7f.trans
new file mode 100644
index 0000000..d299d7f
--- /dev/null
+++ b/resources/chars/ascii/row7f.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+7f00 Zhui # Character ç¼
+U+7f01 Zi # Character ç¼
+U+7f02 Ke # Character ç¼
+U+7f03 Xiang # Character ç¼
+U+7f04 Jian # Character ç¼
+U+7f05 Mian # Character ç¼
+U+7f06 Lan # Character ç¼
+U+7f07 Ti # Character ç¼
+U+7f08 Miao # Character ç¼
+U+7f09 Qi # Character ç¼
+U+7f0a Yun # Character ç¼
+U+7f0b Hui # Character ç¼
+U+7f0c Si # Character ç¼
+U+7f0d Duo # Character ç¼
+U+7f0e Duan # Character ç¼
+U+7f0f Bian # Character ç¼
+U+7f10 Xian # Character ç¼
+U+7f11 Gou # Character ç¼
+U+7f12 Zhui # Character ç¼
+U+7f13 Huan # Character ç¼
+U+7f14 Di # Character ç¼
+U+7f15 Lu # Character ç¼
+U+7f16 Bian # Character ç¼
+U+7f17 Min # Character ç¼
+U+7f18 Yuan # Character ç¼
+U+7f19 Jin # Character ç¼
+U+7f1a Fu # Character ç¼
+U+7f1b Ru # Character ç¼
+U+7f1c Zhen # Character ç¼
+U+7f1d Feng # Character ç¼
+U+7f1e Shuai # Character ç¼
+U+7f1f Gao # Character ç¼
+U+7f20 Chan # Character ç¼
+U+7f21 Li # Character 缡
+U+7f22 Yi # Character ç¼¢
+U+7f23 Jian # Character ç¼£
+U+7f24 Bin # Character 缤
+U+7f25 Piao # Character ç¼¥
+U+7f26 Man # Character 缦
+U+7f27 Lei # Character 缧
+U+7f28 Ying # Character 缨
+U+7f29 Suo # Character 缩
+U+7f2a Mou # Character 缪
+U+7f2b Sao # Character 缫
+U+7f2c Xie # Character 缬
+U+7f2d Liao # Character ç¼
+U+7f2e Shan # Character ç¼®
+U+7f2f Zeng # Character 缯
+U+7f30 Jiang # Character ç¼°
+U+7f31 Qian # Character ç¼±
+U+7f32 Zao # Character ç¼²
+U+7f33 Huan # Character ç¼³
+U+7f34 Jiao # Character ç¼´
+U+7f35 Zuan # Character ç¼µ
+U+7f36 Fou # Character 缶
+U+7f37 Xie # Character ç¼·
+U+7f38 Gang # Character 缸
+U+7f39 Fou # Character ç¼¹
+U+7f3a Que # Character 缺
+U+7f3b Fou # Character ç¼»
+U+7f3c Kaakeru # Character ç¼¼
+U+7f3d Bo # Character ç¼½
+U+7f3e Ping # Character ç¼¾
+U+7f3f Hou # Character 缿
+U+7f40 ? # Character ç½
+U+7f41 Gang # Character ç½
+U+7f42 Ying # Character ç½
+U+7f43 Ying # Character ç½
+U+7f44 Qing # Character ç½
+U+7f45 Xia # Character ç½
+U+7f46 Guan # Character ç½
+U+7f47 Zun # Character ç½
+U+7f48 Tan # Character ç½
+U+7f49 Chang # Character ç½
+U+7f4a Qi # Character ç½
+U+7f4b Weng # Character ç½
+U+7f4c Ying # Character ç½
+U+7f4d Lei # Character ç½
+U+7f4e Tan # Character ç½
+U+7f4f Lu # Character ç½
+U+7f50 Guan # Character ç½
+U+7f51 Wang # Character ç½
+U+7f52 Wang # Character ç½
+U+7f53 Gang # Character ç½
+U+7f54 Wang # Character ç½
+U+7f55 Han # Character ç½
+U+7f56 ? # Character ç½
+U+7f57 Luo # Character ç½
+U+7f58 Fu # Character ç½
+U+7f59 Mi # Character ç½
+U+7f5a Fa # Character ç½
+U+7f5b Gu # Character ç½
+U+7f5c Zhu # Character ç½
+U+7f5d Ju # Character ç½
+U+7f5e Mao # Character ç½
+U+7f5f Gu # Character ç½
+U+7f60 Min # Character ç½
+U+7f61 Gang # Character 罡
+U+7f62 Ba # Character ç½¢
+U+7f63 Gua # Character ç½£
+U+7f64 Ti # Character 罤
+U+7f65 Juan # Character ç½¥
+U+7f66 Fu # Character 罦
+U+7f67 Lin # Character 罧
+U+7f68 Yan # Character 罨
+U+7f69 Zhao # Character 罩
+U+7f6a Zui # Character 罪
+U+7f6b Gua # Character 罫
+U+7f6c Zhuo # Character 罬
+U+7f6d Yu # Character ç½
+U+7f6e Zhi # Character ç½®
+U+7f6f An # Character 罯
+U+7f70 Fa # Character ç½°
+U+7f71 Nan # Character ç½±
+U+7f72 Shu # Character ç½²
+U+7f73 Si # Character ç½³
+U+7f74 Pi # Character ç½´
+U+7f75 Ma # Character ç½µ
+U+7f76 Liu # Character 罶
+U+7f77 Ba # Character ç½·
+U+7f78 Fa # Character 罸
+U+7f79 Li # Character ç½¹
+U+7f7a Chao # Character 罺
+U+7f7b Wei # Character ç½»
+U+7f7c Bi # Character ç½¼
+U+7f7d Ji # Character ç½½
+U+7f7e Zeng # Character ç½¾
+U+7f7f Tong # Character 罿
+U+7f80 Liu # Character ç¾
+U+7f81 Ji # Character ç¾
+U+7f82 Juan # Character ç¾
+U+7f83 Mi # Character ç¾
+U+7f84 Zhao # Character ç¾
+U+7f85 Luo # Character ç¾
+U+7f86 Pi # Character ç¾
+U+7f87 Ji # Character ç¾
+U+7f88 Ji # Character ç¾
+U+7f89 Luan # Character ç¾
+U+7f8a Yang # Character ç¾
+U+7f8b Mie # Character ç¾
+U+7f8c Qiang # Character ç¾
+U+7f8d Ta # Character ç¾
+U+7f8e Mei # Character ç¾
+U+7f8f Yang # Character ç¾
+U+7f90 You # Character ç¾
+U+7f91 You # Character ç¾
+U+7f92 Fen # Character ç¾
+U+7f93 Ba # Character ç¾
+U+7f94 Gao # Character ç¾
+U+7f95 Yang # Character ç¾
+U+7f96 Gu # Character ç¾
+U+7f97 Qiang # Character ç¾
+U+7f98 Zang # Character ç¾
+U+7f99 Gao # Character ç¾
+U+7f9a Ling # Character ç¾
+U+7f9b Yi # Character ç¾
+U+7f9c Zhu # Character ç¾
+U+7f9d Di # Character ç¾
+U+7f9e Xiu # Character ç¾
+U+7f9f Qian # Character ç¾
+U+7fa0 Yi # Character ç¾
+U+7fa1 Xian # Character 羡
+U+7fa2 Rong # Character ç¾¢
+U+7fa3 Qun # Character ç¾£
+U+7fa4 Qun # Character 群
+U+7fa5 Qian # Character ç¾¥
+U+7fa6 Huan # Character 羦
+U+7fa7 Zui # Character 羧
+U+7fa8 Xian # Character 羨
+U+7fa9 Yi # Character 義
+U+7faa Yashinau # Character 羪
+U+7fab Qiang # Character 羫
+U+7fac Xian # Character 羬
+U+7fad Yu # Character ç¾
+U+7fae Geng # Character ç¾®
+U+7faf Jie # Character 羯
+U+7fb0 Tang # Character ç¾°
+U+7fb1 Yuan # Character ç¾±
+U+7fb2 Xi # Character ç¾²
+U+7fb3 Fan # Character ç¾³
+U+7fb4 Shan # Character ç¾´
+U+7fb5 Fen # Character ç¾µ
+U+7fb6 Shan # Character 羶
+U+7fb7 Lian # Character ç¾·
+U+7fb8 Lei # Character 羸
+U+7fb9 Geng # Character ç¾¹
+U+7fba Nou # Character 羺
+U+7fbb Qiang # Character ç¾»
+U+7fbc Chan # Character ç¾¼
+U+7fbd Yu # Character ç¾½
+U+7fbe Gong # Character ç¾¾
+U+7fbf Yi # Character 羿
+U+7fc0 Chong # Character ç¿
+U+7fc1 Weng # Character ç¿
+U+7fc2 Fen # Character ç¿
+U+7fc3 Hong # Character ç¿
+U+7fc4 Chi # Character ç¿
+U+7fc5 Chi # Character ç¿
+U+7fc6 Cui # Character ç¿
+U+7fc7 Fu # Character ç¿
+U+7fc8 Xia # Character ç¿
+U+7fc9 Pen # Character ç¿
+U+7fca Yi # Character ç¿
+U+7fcb La # Character ç¿
+U+7fcc Yi # Character ç¿
+U+7fcd Pi # Character ç¿
+U+7fce Ling # Character ç¿
+U+7fcf Liu # Character ç¿
+U+7fd0 Zhi # Character ç¿
+U+7fd1 Qu # Character ç¿
+U+7fd2 Xi # Character ç¿
+U+7fd3 Xie # Character ç¿
+U+7fd4 Xiang # Character ç¿
+U+7fd5 Xi # Character ç¿
+U+7fd6 Xi # Character ç¿
+U+7fd7 Qi # Character ç¿
+U+7fd8 Qiao # Character ç¿
+U+7fd9 Hui # Character ç¿
+U+7fda Hui # Character ç¿
+U+7fdb Xiao # Character ç¿
+U+7fdc Se # Character ç¿
+U+7fdd Hong # Character ç¿
+U+7fde Jiang # Character ç¿
+U+7fdf Di # Character ç¿
+U+7fe0 Cui # Character ç¿
+U+7fe1 Fei # Character ç¿¡
+U+7fe2 Tao # Character ç¿¢
+U+7fe3 Sha # Character ç¿£
+U+7fe4 Chi # Character 翤
+U+7fe5 Zhu # Character ç¿¥
+U+7fe6 Jian # Character 翦
+U+7fe7 Xuan # Character 翧
+U+7fe8 Shi # Character 翨
+U+7fe9 Pian # Character ç¿©
+U+7fea Zong # Character 翪
+U+7feb Wan # Character ç¿«
+U+7fec Hui # Character 翬
+U+7fed Hou # Character ç¿
+U+7fee He # Character ç¿®
+U+7fef He # Character 翯
+U+7ff0 Han # Character ç¿°
+U+7ff1 Ao # Character 翱
+U+7ff2 Piao # Character 翲
+U+7ff3 Yi # Character 翳
+U+7ff4 Lian # Character ç¿´
+U+7ff5 Qu # Character 翵
+U+7ff6 ? # Character 翶
+U+7ff7 Lin # Character ç¿·
+U+7ff8 Pen # Character 翸
+U+7ff9 Qiao # Character 翹
+U+7ffa Ao # Character 翺
+U+7ffb Fan # Character ç¿»
+U+7ffc Yi # Character 翼
+U+7ffd Hui # Character 翽
+U+7ffe Xuan # Character 翾
+U+7fff Dao # Character ç¿¿
diff --git a/resources/chars/ascii/row80.trans b/resources/chars/ascii/row80.trans
new file mode 100644
index 0000000..41db483
--- /dev/null
+++ b/resources/chars/ascii/row80.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+8000 Yao # Character è
+U+8001 Lao # Character è
+U+8002 ? # Character è
+U+8003 Kao # Character è
+U+8004 Mao # Character è
+U+8005 Zhe # Character è
+U+8006 Qi # Character è
+U+8007 Gou # Character è
+U+8008 Gou # Character è
+U+8009 Gou # Character è
+U+800a Die # Character è
+U+800b Die # Character è
+U+800c Er # Character è
+U+800d Shua # Character è
+U+800e Ruan # Character è
+U+800f Er # Character è
+U+8010 Nai # Character è
+U+8011 Zhuan # Character è
+U+8012 Lei # Character è
+U+8013 Ting # Character è
+U+8014 Zi # Character è
+U+8015 Geng # Character è
+U+8016 Chao # Character è
+U+8017 Hao # Character è
+U+8018 Yun # Character è
+U+8019 Pa # Character è
+U+801a Pi # Character è
+U+801b Chi # Character è
+U+801c Si # Character è
+U+801d Chu # Character è
+U+801e Jia # Character è
+U+801f Ju # Character è
+U+8020 He # Character è
+U+8021 Chu # Character è¡
+U+8022 Lao # Character è¢
+U+8023 Lun # Character è£
+U+8024 Ji # Character è¤
+U+8025 Tang # Character è¥
+U+8026 Ou # Character è¦
+U+8027 Lou # Character è§
+U+8028 Nou # Character è¨
+U+8029 Gou # Character è©
+U+802a Pang # Character èª
+U+802b Ze # Character è«
+U+802c Lou # Character è¬
+U+802d Ji # Character è
+U+802e Lao # Character è®
+U+802f Huo # Character è¯
+U+8030 You # Character è°
+U+8031 Mo # Character è±
+U+8032 Huai # Character è²
+U+8033 Er # Character è³
+U+8034 Zhe # Character è´
+U+8035 Ting # Character èµ
+U+8036 Ye # Character è¶
+U+8037 Da # Character è·
+U+8038 Song # Character è¸
+U+8039 Qin # Character è¹
+U+803a Yun # Character èº
+U+803b Chi # Character è»
+U+803c Dan # Character è¼
+U+803d Dan # Character è½
+U+803e Hong # Character è¾
+U+803f Geng # Character è¿
+U+8040 Zhi # Character è
+U+8041 ? # Character è
+U+8042 Nie # Character è
+U+8043 Dan # Character è
+U+8044 Zhen # Character è
+U+8045 Che # Character è
+U+8046 Ling # Character è
+U+8047 Zheng # Character è
+U+8048 You # Character è
+U+8049 Wa # Character è
+U+804a Liao # Character è
+U+804b Long # Character è
+U+804c Zhi # Character è
+U+804d Ning # Character è
+U+804e Tiao # Character è
+U+804f Er # Character è
+U+8050 Ya # Character è
+U+8051 Die # Character è
+U+8052 Gua # Character è
+U+8053 ? # Character è
+U+8054 Lian # Character è
+U+8055 Hao # Character è
+U+8056 Sheng # Character è
+U+8057 Lie # Character è
+U+8058 Pin # Character è
+U+8059 Jing # Character è
+U+805a Ju # Character è
+U+805b Bi # Character è
+U+805c Di # Character è
+U+805d Guo # Character è
+U+805e Wen # Character è
+U+805f Xu # Character è
+U+8060 Ping # Character è
+U+8061 Cong # Character è¡
+U+8062 Shikato # Character è¢
+U+8063 ? # Character è£
+U+8064 Ting # Character è¤
+U+8065 Yu # Character è¥
+U+8066 Cong # Character è¦
+U+8067 Kui # Character è§
+U+8068 Tsuraneru # Character è¨
+U+8069 Kui # Character è©
+U+806a Cong # Character èª
+U+806b Lian # Character è«
+U+806c Weng # Character è¬
+U+806d Kui # Character è
+U+806e Lian # Character è®
+U+806f Lian # Character è¯
+U+8070 Cong # Character è°
+U+8071 Ao # Character è±
+U+8072 Sheng # Character è²
+U+8073 Song # Character è³
+U+8074 Ting # Character è´
+U+8075 Kui # Character èµ
+U+8076 Nie # Character è¶
+U+8077 Zhi # Character è·
+U+8078 Dan # Character è¸
+U+8079 Ning # Character è¹
+U+807a Qie # Character èº
+U+807b Ji # Character è»
+U+807c Ting # Character è¼
+U+807d Ting # Character è½
+U+807e Long # Character è¾
+U+807f Yu # Character è¿
+U+8080 Yu # Character è
+U+8081 Zhao # Character è
+U+8082 Si # Character è
+U+8083 Su # Character è
+U+8084 Yi # Character è
+U+8085 Su # Character è
+U+8086 Si # Character è
+U+8087 Zhao # Character è
+U+8088 Zhao # Character è
+U+8089 Rou # Character è
+U+808a Yi # Character è
+U+808b Le # Character è
+U+808c Ji # Character è
+U+808d Qiu # Character è
+U+808e Ken # Character è
+U+808f Cao # Character è
+U+8090 Ge # Character è
+U+8091 Di # Character è
+U+8092 Huan # Character è
+U+8093 Huang # Character è
+U+8094 Yi # Character è
+U+8095 Ren # Character è
+U+8096 Xiao # Character è
+U+8097 Ru # Character è
+U+8098 Zhou # Character è
+U+8099 Yuan # Character è
+U+809a Du # Character è
+U+809b Gang # Character è
+U+809c Rong # Character è
+U+809d Gan # Character è
+U+809e Cha # Character è
+U+809f Wo # Character è
+U+80a0 Chang # Character è
+U+80a1 Gu # Character è¡
+U+80a2 Zhi # Character è¢
+U+80a3 Han # Character è£
+U+80a4 Fu # Character è¤
+U+80a5 Fei # Character è¥
+U+80a6 Fen # Character è¦
+U+80a7 Pei # Character è§
+U+80a8 Pang # Character è¨
+U+80a9 Jian # Character è©
+U+80aa Fang # Character èª
+U+80ab Zhun # Character è«
+U+80ac You # Character è¬
+U+80ad Na # Character è
+U+80ae Hang # Character è®
+U+80af Ken # Character è¯
+U+80b0 Ran # Character è°
+U+80b1 Gong # Character è±
+U+80b2 Yu # Character è²
+U+80b3 Wen # Character è³
+U+80b4 Yao # Character è´
+U+80b5 Jin # Character èµ
+U+80b6 Pi # Character è¶
+U+80b7 Qian # Character è·
+U+80b8 Xi # Character è¸
+U+80b9 Xi # Character è¹
+U+80ba Fei # Character èº
+U+80bb Ken # Character è»
+U+80bc Jing # Character è¼
+U+80bd Tai # Character è½
+U+80be Shen # Character è¾
+U+80bf Zhong # Character è¿
+U+80c0 Zhang # Character è
+U+80c1 Xie # Character è
+U+80c2 Shen # Character è
+U+80c3 Wei # Character è
+U+80c4 Zhou # Character è
+U+80c5 Die # Character è
+U+80c6 Dan # Character è
+U+80c7 Fei # Character è
+U+80c8 Ba # Character è
+U+80c9 Bo # Character è
+U+80ca Qu # Character è
+U+80cb Tian # Character è
+U+80cc Bei # Character è
+U+80cd Gua # Character è
+U+80ce Tai # Character è
+U+80cf Zi # Character è
+U+80d0 Ku # Character è
+U+80d1 Zhi # Character è
+U+80d2 Ni # Character è
+U+80d3 Ping # Character è
+U+80d4 Zi # Character è
+U+80d5 Fu # Character è
+U+80d6 Pang # Character è
+U+80d7 Zhen # Character è
+U+80d8 Xian # Character è
+U+80d9 Zuo # Character è
+U+80da Pei # Character è
+U+80db Jia # Character è
+U+80dc Sheng # Character è
+U+80dd Zhi # Character è
+U+80de Bao # Character è
+U+80df Mu # Character è
+U+80e0 Qu # Character è
+U+80e1 Hu # Character è¡
+U+80e2 Ke # Character è¢
+U+80e3 Yi # Character è£
+U+80e4 Yin # Character è¤
+U+80e5 Xu # Character è¥
+U+80e6 Yang # Character è¦
+U+80e7 Long # Character è§
+U+80e8 Dong # Character è¨
+U+80e9 Ka # Character è©
+U+80ea Lu # Character èª
+U+80eb Jing # Character è«
+U+80ec Nu # Character è¬
+U+80ed Yan # Character è
+U+80ee Pang # Character è®
+U+80ef Kua # Character è¯
+U+80f0 Yi # Character è°
+U+80f1 Guang # Character è±
+U+80f2 Gai # Character è²
+U+80f3 Ge # Character è³
+U+80f4 Dong # Character è´
+U+80f5 Zhi # Character èµ
+U+80f6 Xiao # Character è¶
+U+80f7 Xiong # Character è·
+U+80f8 Xiong # Character è¸
+U+80f9 Er # Character è¹
+U+80fa E # Character èº
+U+80fb Xing # Character è»
+U+80fc Pian # Character è¼
+U+80fd Neng # Character è½
+U+80fe Zi # Character è¾
+U+80ff Gui # Character è¿
diff --git a/resources/chars/ascii/row81.trans b/resources/chars/ascii/row81.trans
new file mode 100644
index 0000000..514e394
--- /dev/null
+++ b/resources/chars/ascii/row81.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+8100 Cheng # Character è
+U+8101 Tiao # Character è
+U+8102 Zhi # Character è
+U+8103 Cui # Character è
+U+8104 Mei # Character è
+U+8105 Xie # Character è
+U+8106 Cui # Character è
+U+8107 Xie # Character è
+U+8108 Mo # Character è
+U+8109 Mai # Character è
+U+810a Ji # Character è
+U+810b Obiyaakasu # Character è
+U+810c ? # Character è
+U+810d Kuai # Character è
+U+810e Sa # Character è
+U+810f Zang # Character è
+U+8110 Qi # Character è
+U+8111 Nao # Character è
+U+8112 Mi # Character è
+U+8113 Nong # Character è
+U+8114 Luan # Character è
+U+8115 Wan # Character è
+U+8116 Bo # Character è
+U+8117 Wen # Character è
+U+8118 Guan # Character è
+U+8119 Qiu # Character è
+U+811a Jiao # Character è
+U+811b Jing # Character è
+U+811c Rou # Character è
+U+811d Heng # Character è
+U+811e Cuo # Character è
+U+811f Lie # Character è
+U+8120 Shan # Character è
+U+8121 Ting # Character è¡
+U+8122 Mei # Character è¢
+U+8123 Chun # Character è£
+U+8124 Shen # Character è¤
+U+8125 Xie # Character è¥
+U+8126 De # Character è¦
+U+8127 Zui # Character è§
+U+8128 Cu # Character è¨
+U+8129 Xiu # Character è©
+U+812a Xin # Character èª
+U+812b Tuo # Character è«
+U+812c Pao # Character è¬
+U+812d Cheng # Character è
+U+812e Nei # Character è®
+U+812f Fu # Character è¯
+U+8130 Dou # Character è°
+U+8131 Tuo # Character è±
+U+8132 Niao # Character è²
+U+8133 Noy # Character è³
+U+8134 Pi # Character è´
+U+8135 Gu # Character èµ
+U+8136 Gua # Character è¶
+U+8137 Li # Character è·
+U+8138 Lian # Character è¸
+U+8139 Zhang # Character è¹
+U+813a Cui # Character èº
+U+813b Jie # Character è»
+U+813c Liang # Character è¼
+U+813d Zhou # Character è½
+U+813e Pi # Character è¾
+U+813f Biao # Character è¿
+U+8140 Lun # Character è
+U+8141 Pian # Character è
+U+8142 Guo # Character è
+U+8143 Kui # Character è
+U+8144 Chui # Character è
+U+8145 Dan # Character è
+U+8146 Tian # Character è
+U+8147 Nei # Character è
+U+8148 Jing # Character è
+U+8149 Jie # Character è
+U+814a La # Character è
+U+814b Yi # Character è
+U+814c An # Character è
+U+814d Ren # Character è
+U+814e Shen # Character è
+U+814f Chuo # Character è
+U+8150 Fu # Character è
+U+8151 Fu # Character è
+U+8152 Ju # Character è
+U+8153 Fei # Character è
+U+8154 Qiang # Character è
+U+8155 Wan # Character è
+U+8156 Dong # Character è
+U+8157 Pi # Character è
+U+8158 Guo # Character è
+U+8159 Zong # Character è
+U+815a Ding # Character è
+U+815b Wu # Character è
+U+815c Mei # Character è
+U+815d Ruan # Character è
+U+815e Zhuan # Character è
+U+815f Zhi # Character è
+U+8160 Cou # Character è
+U+8161 Gua # Character è
¡
+U+8162 Ou # Character è
¢
+U+8163 Di # Character è
£
+U+8164 An # Character è
¤
+U+8165 Xing # Character è
¥
+U+8166 Nao # Character è
¦
+U+8167 Yu # Character è
§
+U+8168 Chuan # Character è
¨
+U+8169 Nan # Character è
©
+U+816a Yun # Character è
ª
+U+816b Zhong # Character è
«
+U+816c Rou # Character è
¬
+U+816d E # Character è
+U+816e Sai # Character è
®
+U+816f Tu # Character è
¯
+U+8170 Yao # Character è
°
+U+8171 Jian # Character è
±
+U+8172 Wei # Character è
²
+U+8173 Jiao # Character è
³
+U+8174 Yu # Character è
´
+U+8175 Jia # Character è
µ
+U+8176 Duan # Character è
¶
+U+8177 Bi # Character è
·
+U+8178 Chang # Character è
¸
+U+8179 Fu # Character è
¹
+U+817a Xian # Character è
º
+U+817b Ni # Character è
»
+U+817c Mian # Character è
¼
+U+817d Wa # Character è
½
+U+817e Teng # Character è
¾
+U+817f Tui # Character è
¿
+U+8180 Bang # Character è
+U+8181 Qian # Character è
+U+8182 Lu # Character è
+U+8183 Wa # Character è
+U+8184 Sou # Character è
+U+8185 Tang # Character è
+U+8186 Su # Character è
+U+8187 Zhui # Character è
+U+8188 Ge # Character è
+U+8189 Yi # Character è
+U+818a Bo # Character è
+U+818b Liao # Character è
+U+818c Ji # Character è
+U+818d Pi # Character è
+U+818e Xie # Character è
+U+818f Gao # Character è
+U+8190 Lu # Character è
+U+8191 Bin # Character è
+U+8192 Ou # Character è
+U+8193 Chang # Character è
+U+8194 Lu # Character è
+U+8195 Guo # Character è
+U+8196 Pang # Character è
+U+8197 Chuai # Character è
+U+8198 Piao # Character è
+U+8199 Jiang # Character è
+U+819a Fu # Character è
+U+819b Tang # Character è
+U+819c Mo # Character è
+U+819d Xi # Character è
+U+819e Zhuan # Character è
+U+819f Lu # Character è
+U+81a0 Jiao # Character è
+U+81a1 Ying # Character è¡
+U+81a2 Lu # Character è¢
+U+81a3 Zhi # Character è£
+U+81a4 Tara # Character è¤
+U+81a5 Chun # Character è¥
+U+81a6 Lian # Character è¦
+U+81a7 Tong # Character è§
+U+81a8 Peng # Character è¨
+U+81a9 Ni # Character è©
+U+81aa Zha # Character èª
+U+81ab Liao # Character è«
+U+81ac Cui # Character è¬
+U+81ad Gui # Character è
+U+81ae Xiao # Character è®
+U+81af Teng # Character è¯
+U+81b0 Fan # Character è°
+U+81b1 Zhi # Character è±
+U+81b2 Jiao # Character è²
+U+81b3 Shan # Character è³
+U+81b4 Wu # Character è´
+U+81b5 Cui # Character èµ
+U+81b6 Run # Character è¶
+U+81b7 Xiang # Character è·
+U+81b8 Sui # Character è¸
+U+81b9 Fen # Character è¹
+U+81ba Ying # Character èº
+U+81bb Tan # Character è»
+U+81bc Zhua # Character è¼
+U+81bd Dan # Character è½
+U+81be Kuai # Character è¾
+U+81bf Nong # Character è¿
+U+81c0 Tun # Character è
+U+81c1 Lian # Character è
+U+81c2 Bi # Character è
+U+81c3 Yong # Character è
+U+81c4 Jue # Character è
+U+81c5 Chu # Character è
+U+81c6 Yi # Character è
+U+81c7 Juan # Character è
+U+81c8 La # Character è
+U+81c9 Lian # Character è
+U+81ca Sao # Character è
+U+81cb Tun # Character è
+U+81cc Gu # Character è
+U+81cd Qi # Character è
+U+81ce Cui # Character è
+U+81cf Bin # Character è
+U+81d0 Xun # Character è
+U+81d1 Ru # Character è
+U+81d2 Huo # Character è
+U+81d3 Zang # Character è
+U+81d4 Xian # Character è
+U+81d5 Biao # Character è
+U+81d6 Xing # Character è
+U+81d7 Kuan # Character è
+U+81d8 La # Character è
+U+81d9 Yan # Character è
+U+81da Lu # Character è
+U+81db Huo # Character è
+U+81dc Zang # Character è
+U+81dd Luo # Character è
+U+81de Qu # Character è
+U+81df Zang # Character è
+U+81e0 Luan # Character è
+U+81e1 Ni # Character è¡
+U+81e2 Zang # Character è¢
+U+81e3 Chen # Character è£
+U+81e4 Qian # Character è¤
+U+81e5 Wo # Character è¥
+U+81e6 Guang # Character è¦
+U+81e7 Zang # Character è§
+U+81e8 Lin # Character è¨
+U+81e9 Guang # Character è©
+U+81ea Zi # Character èª
+U+81eb Jiao # Character è«
+U+81ec Nie # Character è¬
+U+81ed Chou # Character è
+U+81ee Ji # Character è®
+U+81ef Gao # Character è¯
+U+81f0 Chou # Character è°
+U+81f1 Mian # Character è±
+U+81f2 Nie # Character è²
+U+81f3 Zhi # Character è³
+U+81f4 Zhi # Character è´
+U+81f5 Ge # Character èµ
+U+81f6 Jian # Character è¶
+U+81f7 Die # Character è·
+U+81f8 Zhi # Character è¸
+U+81f9 Xiu # Character è¹
+U+81fa Tai # Character èº
+U+81fb Zhen # Character è»
+U+81fc Jiu # Character è¼
+U+81fd Xian # Character è½
+U+81fe Yu # Character è¾
+U+81ff Cha # Character è¿
diff --git a/resources/chars/ascii/row82.trans b/resources/chars/ascii/row82.trans
new file mode 100644
index 0000000..67de9b8
--- /dev/null
+++ b/resources/chars/ascii/row82.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+8200 Yao # Character è
+U+8201 Yu # Character è
+U+8202 Chong # Character è
+U+8203 Xi # Character è
+U+8204 Xi # Character è
+U+8205 Jiu # Character è
+U+8206 Yu # Character è
+U+8207 Yu # Character è
+U+8208 Xing # Character è
+U+8209 Ju # Character è
+U+820a Jiu # Character è
+U+820b Xin # Character è
+U+820c She # Character è
+U+820d She # Character è
+U+820e Yadoru # Character è
+U+820f Jiu # Character è
+U+8210 Shi # Character è
+U+8211 Tan # Character è
+U+8212 Shu # Character è
+U+8213 Shi # Character è
+U+8214 Tian # Character è
+U+8215 Dan # Character è
+U+8216 Pu # Character è
+U+8217 Pu # Character è
+U+8218 Guan # Character è
+U+8219 Hua # Character è
+U+821a Tan # Character è
+U+821b Chuan # Character è
+U+821c Shun # Character è
+U+821d Xia # Character è
+U+821e Wu # Character è
+U+821f Zhou # Character è
+U+8220 Dao # Character è
+U+8221 Gang # Character è¡
+U+8222 Shan # Character è¢
+U+8223 Yi # Character è£
+U+8224 ? # Character è¤
+U+8225 Pa # Character è¥
+U+8226 Tai # Character è¦
+U+8227 Fan # Character è§
+U+8228 Ban # Character è¨
+U+8229 Chuan # Character è©
+U+822a Hang # Character èª
+U+822b Fang # Character è«
+U+822c Ban # Character è¬
+U+822d Que # Character è
+U+822e Hesaki # Character è®
+U+822f Zhong # Character è¯
+U+8230 Jian # Character è°
+U+8231 Cang # Character è±
+U+8232 Ling # Character è²
+U+8233 Zhu # Character è³
+U+8234 Ze # Character è´
+U+8235 Duo # Character èµ
+U+8236 Bo # Character è¶
+U+8237 Xian # Character è·
+U+8238 Ge # Character è¸
+U+8239 Chuan # Character è¹
+U+823a Jia # Character èº
+U+823b Lu # Character è»
+U+823c Hong # Character è¼
+U+823d Pang # Character è½
+U+823e Xi # Character è¾
+U+823f ? # Character è¿
+U+8240 Fu # Character è
+U+8241 Zao # Character è
+U+8242 Feng # Character è
+U+8243 Li # Character è
+U+8244 Shao # Character è
+U+8245 Yu # Character è
+U+8246 Lang # Character è
+U+8247 Ting # Character è
+U+8248 ? # Character è
+U+8249 Wei # Character è
+U+824a Bo # Character è
+U+824b Meng # Character è
+U+824c Nian # Character è
+U+824d Ju # Character è
+U+824e Huang # Character è
+U+824f Shou # Character è
+U+8250 Zong # Character è
+U+8251 Bian # Character è
+U+8252 Mao # Character è
+U+8253 Die # Character è
+U+8254 ? # Character è
+U+8255 Bang # Character è
+U+8256 Cha # Character è
+U+8257 Yi # Character è
+U+8258 Sao # Character è
+U+8259 Cang # Character è
+U+825a Cao # Character è
+U+825b Lou # Character è
+U+825c Dai # Character è
+U+825d Sori # Character è
+U+825e Yao # Character è
+U+825f Tong # Character è
+U+8260 Yofune # Character è
+U+8261 Dang # Character è¡
+U+8262 Tan # Character è¢
+U+8263 Lu # Character è£
+U+8264 Yi # Character è¤
+U+8265 Jie # Character è¥
+U+8266 Jian # Character è¦
+U+8267 Huo # Character è§
+U+8268 Meng # Character è¨
+U+8269 Qi # Character è©
+U+826a Lu # Character èª
+U+826b Lu # Character è«
+U+826c Chan # Character è¬
+U+826d Shuang # Character è
+U+826e Gen # Character è®
+U+826f Liang # Character è¯
+U+8270 Jian # Character è°
+U+8271 Jian # Character è±
+U+8272 Se # Character è²
+U+8273 Yan # Character è³
+U+8274 Fu # Character è´
+U+8275 Ping # Character èµ
+U+8276 Yan # Character è¶
+U+8277 Yan # Character è·
+U+8278 Cao # Character è¸
+U+8279 Cao # Character è¹
+U+827a Yi # Character èº
+U+827b Le # Character è»
+U+827c Ting # Character è¼
+U+827d Qiu # Character è½
+U+827e Ai # Character è¾
+U+827f Nai # Character è¿
+U+8280 Tiao # Character è
+U+8281 Jiao # Character è
+U+8282 Jie # Character è
+U+8283 Peng # Character è
+U+8284 Wan # Character è
+U+8285 Yi # Character è
+U+8286 Chai # Character è
+U+8287 Mian # Character è
+U+8288 Mie # Character è
+U+8289 Gan # Character è
+U+828a Qian # Character è
+U+828b Yu # Character è
+U+828c Yu # Character è
+U+828d Shuo # Character è
+U+828e Qiong # Character è
+U+828f Tu # Character è
+U+8290 Xia # Character è
+U+8291 Qi # Character è
+U+8292 Mang # Character è
+U+8293 Zi # Character è
+U+8294 Hui # Character è
+U+8295 Sui # Character è
+U+8296 Zhi # Character è
+U+8297 Xiang # Character è
+U+8298 Bi # Character è
+U+8299 Fu # Character è
+U+829a Tun # Character è
+U+829b Wei # Character è
+U+829c Wu # Character è
+U+829d Zhi # Character è
+U+829e Qi # Character è
+U+829f Shan # Character è
+U+82a0 Wen # Character è
+U+82a1 Qian # Character è¡
+U+82a2 Ren # Character è¢
+U+82a3 Fou # Character è£
+U+82a4 Kou # Character è¤
+U+82a5 Jie # Character è¥
+U+82a6 Lu # Character è¦
+U+82a7 Xu # Character è§
+U+82a8 Ji # Character è¨
+U+82a9 Qin # Character è©
+U+82aa Qi # Character èª
+U+82ab Yuan # Character è«
+U+82ac Fen # Character è¬
+U+82ad Ba # Character è
+U+82ae Rui # Character è®
+U+82af Xin # Character è¯
+U+82b0 Ji # Character è°
+U+82b1 Hua # Character è±
+U+82b2 Hua # Character è²
+U+82b3 Fang # Character è³
+U+82b4 Wu # Character è´
+U+82b5 Jue # Character èµ
+U+82b6 Gou # Character è¶
+U+82b7 Zhi # Character è·
+U+82b8 Yun # Character è¸
+U+82b9 Qin # Character è¹
+U+82ba Ao # Character èº
+U+82bb Chu # Character è»
+U+82bc Mao # Character è¼
+U+82bd Ya # Character è½
+U+82be Fei # Character è¾
+U+82bf Reng # Character è¿
+U+82c0 Hang # Character è
+U+82c1 Cong # Character è
+U+82c2 Yin # Character è
+U+82c3 You # Character è
+U+82c4 Bian # Character è
+U+82c5 Yi # Character è
+U+82c6 Susa # Character è
+U+82c7 Wei # Character è
+U+82c8 Li # Character è
+U+82c9 Pi # Character è
+U+82ca E # Character è
+U+82cb Xian # Character è
+U+82cc Chang # Character è
+U+82cd Cang # Character è
+U+82ce Meng # Character è
+U+82cf Su # Character è
+U+82d0 Yi # Character è
+U+82d1 Yuan # Character è
+U+82d2 Ran # Character è
+U+82d3 Ling # Character è
+U+82d4 Tai # Character è
+U+82d5 Tiao # Character è
+U+82d6 Di # Character è
+U+82d7 Miao # Character è
+U+82d8 Qiong # Character è
+U+82d9 Li # Character è
+U+82da Yong # Character è
+U+82db Ke # Character è
+U+82dc Mu # Character è
+U+82dd Pei # Character è
+U+82de Bao # Character è
+U+82df Gou # Character è
+U+82e0 Min # Character è
+U+82e1 Yi # Character è¡
+U+82e2 Yi # Character è¢
+U+82e3 Ju # Character è£
+U+82e4 Pi # Character è¤
+U+82e5 Ruo # Character è¥
+U+82e6 Ku # Character è¦
+U+82e7 Zhu # Character è§
+U+82e8 Ni # Character è¨
+U+82e9 Bo # Character è©
+U+82ea Bing # Character èª
+U+82eb Shan # Character è«
+U+82ec Qiu # Character è¬
+U+82ed Yao # Character è
+U+82ee Xian # Character è®
+U+82ef Ben # Character è¯
+U+82f0 Hong # Character è°
+U+82f1 Ying # Character è±
+U+82f2 Zha # Character è²
+U+82f3 Dong # Character è³
+U+82f4 Ju # Character è´
+U+82f5 Die # Character èµ
+U+82f6 Nie # Character è¶
+U+82f7 Gan # Character è·
+U+82f8 Hu # Character è¸
+U+82f9 Ping # Character è¹
+U+82fa Mei # Character èº
+U+82fb Fu # Character è»
+U+82fc Sheng # Character è¼
+U+82fd Gu # Character è½
+U+82fe Bi # Character è¾
+U+82ff Wei # Character è¿
diff --git a/resources/chars/ascii/row83.trans b/resources/chars/ascii/row83.trans
new file mode 100644
index 0000000..307ef21
--- /dev/null
+++ b/resources/chars/ascii/row83.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+8300 Fu # Character è
+U+8301 Zhuo # Character è
+U+8302 Mao # Character è
+U+8303 Fan # Character è
+U+8304 Qie # Character è
+U+8305 Mao # Character è
+U+8306 Mao # Character è
+U+8307 Ba # Character è
+U+8308 Zi # Character è
+U+8309 Mo # Character è
+U+830a Zi # Character è
+U+830b Di # Character è
+U+830c Chi # Character è
+U+830d Ji # Character è
+U+830e Jing # Character è
+U+830f Long # Character è
+U+8310 ? # Character è
+U+8311 Niao # Character è
+U+8312 ? # Character è
+U+8313 Xue # Character è
+U+8314 Ying # Character è
+U+8315 Qiong # Character è
+U+8316 Ge # Character è
+U+8317 Ming # Character è
+U+8318 Li # Character è
+U+8319 Rong # Character è
+U+831a Yin # Character è
+U+831b Gen # Character è
+U+831c Qian # Character è
+U+831d Chai # Character è
+U+831e Chen # Character è
+U+831f Yu # Character è
+U+8320 Xiu # Character è
+U+8321 Zi # Character è¡
+U+8322 Lie # Character è¢
+U+8323 Wu # Character è£
+U+8324 Ji # Character è¤
+U+8325 Kui # Character è¥
+U+8326 Ce # Character è¦
+U+8327 Chong # Character è§
+U+8328 Ci # Character è¨
+U+8329 Gou # Character è©
+U+832a Guang # Character èª
+U+832b Mang # Character è«
+U+832c Chi # Character è¬
+U+832d Jiao # Character è
+U+832e Jiao # Character è®
+U+832f Fu # Character è¯
+U+8330 Yu # Character è°
+U+8331 Zhu # Character è±
+U+8332 Zi # Character è²
+U+8333 Jiang # Character è³
+U+8334 Hui # Character è´
+U+8335 Yin # Character èµ
+U+8336 Cha # Character è¶
+U+8337 Fa # Character è·
+U+8338 Rong # Character è¸
+U+8339 Ru # Character è¹
+U+833a Chong # Character èº
+U+833b Mang # Character è»
+U+833c Tong # Character è¼
+U+833d Zhong # Character è½
+U+833e ? # Character è¾
+U+833f Zhu # Character è¿
+U+8340 Xun # Character è
+U+8341 Huan # Character è
+U+8342 Kua # Character è
+U+8343 Quan # Character è
+U+8344 Gai # Character è
+U+8345 Da # Character è
+U+8346 Jing # Character è
+U+8347 Xing # Character è
+U+8348 Quan # Character è
+U+8349 Cao # Character è
+U+834a Jing # Character è
+U+834b Er # Character è
+U+834c An # Character è
+U+834d Shou # Character è
+U+834e Chi # Character è
+U+834f Ren # Character è
+U+8350 Jian # Character è
+U+8351 Ti # Character è
+U+8352 Huang # Character è
+U+8353 Ping # Character è
+U+8354 Li # Character è
+U+8355 Jin # Character è
+U+8356 Lao # Character è
+U+8357 Shu # Character è
+U+8358 Zhuang # Character è
+U+8359 Da # Character è
+U+835a Jia # Character è
+U+835b Rao # Character è
+U+835c Bi # Character è
+U+835d Ze # Character è
+U+835e Qiao # Character è
+U+835f Hui # Character è
+U+8360 Qi # Character è
+U+8361 Dang # Character è¡
+U+8362 ? # Character è¢
+U+8363 Rong # Character è£
+U+8364 Hun # Character è¤
+U+8365 Ying # Character è¥
+U+8366 Luo # Character è¦
+U+8367 Ying # Character è§
+U+8368 Xun # Character è¨
+U+8369 Jin # Character è©
+U+836a Sun # Character èª
+U+836b Yin # Character è«
+U+836c Mai # Character è¬
+U+836d Hong # Character è
+U+836e Zhou # Character è®
+U+836f Yao # Character è¯
+U+8370 Du # Character è°
+U+8371 Wei # Character è±
+U+8372 Chu # Character è²
+U+8373 Dou # Character è³
+U+8374 Fu # Character è´
+U+8375 Ren # Character èµ
+U+8376 Yin # Character è¶
+U+8377 He # Character è·
+U+8378 Bi # Character è¸
+U+8379 Bu # Character è¹
+U+837a Yun # Character èº
+U+837b Di # Character è»
+U+837c Tu # Character è¼
+U+837d Sui # Character è½
+U+837e Sui # Character è¾
+U+837f Cheng # Character è¿
+U+8380 Chen # Character è
+U+8381 Wu # Character è
+U+8382 Bie # Character è
+U+8383 Xi # Character è
+U+8384 Geng # Character è
+U+8385 Li # Character è
+U+8386 Fu # Character è
+U+8387 Zhu # Character è
+U+8388 Mo # Character è
+U+8389 Li # Character è
+U+838a Zhuang # Character è
+U+838b Ji # Character è
+U+838c Duo # Character è
+U+838d Qiu # Character è
+U+838e Sha # Character è
+U+838f Suo # Character è
+U+8390 Chen # Character è
+U+8391 Feng # Character è
+U+8392 Ju # Character è
+U+8393 Mei # Character è
+U+8394 Meng # Character è
+U+8395 Xing # Character è
+U+8396 Jing # Character è
+U+8397 Che # Character è
+U+8398 Xin # Character è
+U+8399 Jun # Character è
+U+839a Yan # Character è
+U+839b Ting # Character è
+U+839c Diao # Character è
+U+839d Cuo # Character è
+U+839e Wan # Character è
+U+839f Han # Character è
+U+83a0 You # Character è
+U+83a1 Cuo # Character è¡
+U+83a2 Jia # Character è¢
+U+83a3 Wang # Character è£
+U+83a4 You # Character è¤
+U+83a5 Niu # Character è¥
+U+83a6 Shao # Character è¦
+U+83a7 Xian # Character è§
+U+83a8 Lang # Character è¨
+U+83a9 Fu # Character è©
+U+83aa E # Character èª
+U+83ab Mo # Character è«
+U+83ac Wen # Character è¬
+U+83ad Jie # Character è
+U+83ae Nan # Character è®
+U+83af Mu # Character è¯
+U+83b0 Kan # Character è°
+U+83b1 Lai # Character è±
+U+83b2 Lian # Character è²
+U+83b3 Shi # Character è³
+U+83b4 Wo # Character è´
+U+83b5 Usagi # Character èµ
+U+83b6 Lian # Character è¶
+U+83b7 Huo # Character è·
+U+83b8 You # Character è¸
+U+83b9 Ying # Character è¹
+U+83ba Ying # Character èº
+U+83bb Nuc # Character è»
+U+83bc Chun # Character è¼
+U+83bd Mang # Character è½
+U+83be Mang # Character è¾
+U+83bf Ci # Character è¿
+U+83c0 Wan # Character è
+U+83c1 Jing # Character è
+U+83c2 Di # Character è
+U+83c3 Qu # Character è
+U+83c4 Dong # Character è
+U+83c5 Jian # Character è
+U+83c6 Zou # Character è
+U+83c7 Gu # Character è
+U+83c8 La # Character è
+U+83c9 Lu # Character è
+U+83ca Ju # Character è
+U+83cb Wei # Character è
+U+83cc Jun # Character è
+U+83cd Nie # Character è
+U+83ce Kun # Character è
+U+83cf He # Character è
+U+83d0 Pu # Character è
+U+83d1 Zi # Character è
+U+83d2 Gao # Character è
+U+83d3 Guo # Character è
+U+83d4 Fu # Character è
+U+83d5 Lun # Character è
+U+83d6 Chang # Character è
+U+83d7 Chou # Character è
+U+83d8 Song # Character è
+U+83d9 Chui # Character è
+U+83da Zhan # Character è
+U+83db Men # Character è
+U+83dc Cai # Character è
+U+83dd Ba # Character è
+U+83de Li # Character è
+U+83df Tu # Character è
+U+83e0 Bo # Character è
+U+83e1 Han # Character è¡
+U+83e2 Bao # Character è¢
+U+83e3 Qin # Character è£
+U+83e4 Juan # Character è¤
+U+83e5 Xi # Character è¥
+U+83e6 Qin # Character è¦
+U+83e7 Di # Character è§
+U+83e8 Jie # Character è¨
+U+83e9 Pu # Character è©
+U+83ea Dang # Character èª
+U+83eb Jin # Character è«
+U+83ec Zhao # Character è¬
+U+83ed Tai # Character è
+U+83ee Geng # Character è®
+U+83ef Hua # Character è¯
+U+83f0 Gu # Character è°
+U+83f1 Ling # Character è±
+U+83f2 Fei # Character è²
+U+83f3 Jin # Character è³
+U+83f4 An # Character è´
+U+83f5 Wang # Character èµ
+U+83f6 Beng # Character è¶
+U+83f7 Zhou # Character è·
+U+83f8 Yan # Character è¸
+U+83f9 Ju # Character è¹
+U+83fa Jian # Character èº
+U+83fb Lin # Character è»
+U+83fc Tan # Character è¼
+U+83fd Shu # Character è½
+U+83fe Tian # Character è¾
+U+83ff Dao # Character è¿
diff --git a/resources/chars/ascii/row84.trans b/resources/chars/ascii/row84.trans
new file mode 100644
index 0000000..da744d5
--- /dev/null
+++ b/resources/chars/ascii/row84.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+8400 Hu # Character è
+U+8401 Qi # Character è
+U+8402 He # Character è
+U+8403 Cui # Character è
+U+8404 Tao # Character è
+U+8405 Chun # Character è
+U+8406 Bei # Character è
+U+8407 Chang # Character è
+U+8408 Huan # Character è
+U+8409 Fei # Character è
+U+840a Lai # Character è
+U+840b Qi # Character è
+U+840c Meng # Character è
+U+840d Ping # Character è
+U+840e Wei # Character è
+U+840f Dan # Character è
+U+8410 Sha # Character è
+U+8411 Huan # Character è
+U+8412 Yan # Character è
+U+8413 Yi # Character è
+U+8414 Tiao # Character è
+U+8415 Qi # Character è
+U+8416 Wan # Character è
+U+8417 Ce # Character è
+U+8418 Nai # Character è
+U+8419 Kutabireru # Character è
+U+841a Tuo # Character è
+U+841b Jiu # Character è
+U+841c Tie # Character è
+U+841d Luo # Character è
+U+841e ? # Character è
+U+841f ? # Character è
+U+8420 Meng # Character è
+U+8421 ? # Character è¡
+U+8422 Yaji # Character è¢
+U+8423 ? # Character è£
+U+8424 Ying # Character è¤
+U+8425 Ying # Character è¥
+U+8426 Ying # Character è¦
+U+8427 Xiao # Character è§
+U+8428 Sa # Character è¨
+U+8429 Qiu # Character è©
+U+842a Ke # Character èª
+U+842b Xiang # Character è«
+U+842c Wan # Character è¬
+U+842d Yu # Character è
+U+842e Yu # Character è®
+U+842f Fu # Character è¯
+U+8430 Lian # Character è°
+U+8431 Xuan # Character è±
+U+8432 Yuan # Character è²
+U+8433 Nan # Character è³
+U+8434 Ze # Character è´
+U+8435 Wo # Character èµ
+U+8436 Chun # Character è¶
+U+8437 Xiao # Character è·
+U+8438 Yu # Character è¸
+U+8439 Pian # Character è¹
+U+843a Mao # Character èº
+U+843b An # Character è»
+U+843c E # Character è¼
+U+843d Luo # Character è½
+U+843e Ying # Character è¾
+U+843f Huo # Character è¿
+U+8440 Gua # Character è
+U+8441 Jiang # Character è
+U+8442 Mian # Character è
+U+8443 Zuo # Character è
+U+8444 Zuo # Character è
+U+8445 Ju # Character è
+U+8446 Bao # Character è
+U+8447 Rou # Character è
+U+8448 Xi # Character è
+U+8449 Xie # Character è
+U+844a An # Character è
+U+844b Qu # Character è
+U+844c Jian # Character è
+U+844d Fu # Character è
+U+844e Lu # Character è
+U+844f Jing # Character è
+U+8450 Pen # Character è
+U+8451 Feng # Character è
+U+8452 Hong # Character è
+U+8453 Hong # Character è
+U+8454 Hou # Character è
+U+8455 Yan # Character è
+U+8456 Tu # Character è
+U+8457 Zhu # Character è
+U+8458 Zi # Character è
+U+8459 Xiang # Character è
+U+845a Shen # Character è
+U+845b Ge # Character è
+U+845c Jie # Character è
+U+845d Jing # Character è
+U+845e Mi # Character è
+U+845f Huang # Character è
+U+8460 Shen # Character è
+U+8461 Pu # Character è¡
+U+8462 Gai # Character è¢
+U+8463 Dong # Character è£
+U+8464 Zhou # Character è¤
+U+8465 Qian # Character è¥
+U+8466 Wei # Character è¦
+U+8467 Bo # Character è§
+U+8468 Wei # Character è¨
+U+8469 Pa # Character è©
+U+846a Ji # Character èª
+U+846b Hu # Character è«
+U+846c Zang # Character è¬
+U+846d Jia # Character è
+U+846e Duan # Character è®
+U+846f Yao # Character è¯
+U+8470 Jun # Character è°
+U+8471 Cong # Character è±
+U+8472 Quan # Character è²
+U+8473 Wei # Character è³
+U+8474 Xian # Character è´
+U+8475 Kui # Character èµ
+U+8476 Ting # Character è¶
+U+8477 Hun # Character è·
+U+8478 Xi # Character è¸
+U+8479 Shi # Character è¹
+U+847a Qi # Character èº
+U+847b Lan # Character è»
+U+847c Zong # Character è¼
+U+847d Yao # Character è½
+U+847e Yuan # Character è¾
+U+847f Mei # Character è¿
+U+8480 Yun # Character è
+U+8481 Shu # Character è
+U+8482 Di # Character è
+U+8483 Zhuan # Character è
+U+8484 Guan # Character è
+U+8485 Sukumo # Character è
+U+8486 Xue # Character è
+U+8487 Chan # Character è
+U+8488 Kai # Character è
+U+8489 Kui # Character è
+U+848a ? # Character è
+U+848b Jiang # Character è
+U+848c Lou # Character è
+U+848d Wei # Character è
+U+848e Pai # Character è
+U+848f ? # Character è
+U+8490 Sou # Character è
+U+8491 Yin # Character è
+U+8492 Shi # Character è
+U+8493 Chun # Character è
+U+8494 Shi # Character è
+U+8495 Yun # Character è
+U+8496 Zhen # Character è
+U+8497 Lang # Character è
+U+8498 Nu # Character è
+U+8499 Meng # Character è
+U+849a He # Character è
+U+849b Que # Character è
+U+849c Suan # Character è
+U+849d Yuan # Character è
+U+849e Li # Character è
+U+849f Ju # Character è
+U+84a0 Xi # Character è
+U+84a1 Pang # Character è¡
+U+84a2 Chu # Character è¢
+U+84a3 Xu # Character è£
+U+84a4 Tu # Character è¤
+U+84a5 Liu # Character è¥
+U+84a6 Wo # Character è¦
+U+84a7 Zhen # Character è§
+U+84a8 Qian # Character è¨
+U+84a9 Zu # Character è©
+U+84aa Po # Character èª
+U+84ab Cuo # Character è«
+U+84ac Yuan # Character è¬
+U+84ad Chu # Character è
+U+84ae Yu # Character è®
+U+84af Kuai # Character è¯
+U+84b0 Pan # Character è°
+U+84b1 Pu # Character è±
+U+84b2 Pu # Character è²
+U+84b3 Na # Character è³
+U+84b4 Shuo # Character è´
+U+84b5 Xi # Character èµ
+U+84b6 Fen # Character è¶
+U+84b7 Yun # Character è·
+U+84b8 Zheng # Character è¸
+U+84b9 Jian # Character è¹
+U+84ba Ji # Character èº
+U+84bb Ruo # Character è»
+U+84bc Cang # Character è¼
+U+84bd En # Character è½
+U+84be Mi # Character è¾
+U+84bf Hao # Character è¿
+U+84c0 Sun # Character è
+U+84c1 Zhen # Character è
+U+84c2 Ming # Character è
+U+84c3 Sou # Character è
+U+84c4 Xu # Character è
+U+84c5 Liu # Character è
+U+84c6 Xi # Character è
+U+84c7 Gu # Character è
+U+84c8 Lang # Character è
+U+84c9 Rong # Character è
+U+84ca Weng # Character è
+U+84cb Gai # Character è
+U+84cc Cuo # Character è
+U+84cd Shi # Character è
+U+84ce Tang # Character è
+U+84cf Luo # Character è
+U+84d0 Ru # Character è
+U+84d1 Suo # Character è
+U+84d2 Xian # Character è
+U+84d3 Bei # Character è
+U+84d4 Yao # Character è
+U+84d5 Gui # Character è
+U+84d6 Bi # Character è
+U+84d7 Zong # Character è
+U+84d8 Gun # Character è
+U+84d9 Za # Character è
+U+84da Xiu # Character è
+U+84db Ce # Character è
+U+84dc Hai # Character è
+U+84dd Lan # Character è
+U+84de ? # Character è
+U+84df Ji # Character è
+U+84e0 Li # Character è
+U+84e1 Can # Character è¡
+U+84e2 Lang # Character è¢
+U+84e3 Yu # Character è£
+U+84e4 ? # Character è¤
+U+84e5 Ying # Character è¥
+U+84e6 Mo # Character è¦
+U+84e7 Diao # Character è§
+U+84e8 Tiao # Character è¨
+U+84e9 Mao # Character è©
+U+84ea Tong # Character èª
+U+84eb Zhu # Character è«
+U+84ec Peng # Character è¬
+U+84ed An # Character è
+U+84ee Lian # Character è®
+U+84ef Cong # Character è¯
+U+84f0 Xi # Character è°
+U+84f1 Ping # Character è±
+U+84f2 Qiu # Character è²
+U+84f3 Jin # Character è³
+U+84f4 Chun # Character è´
+U+84f5 Jie # Character èµ
+U+84f6 Wei # Character è¶
+U+84f7 Tui # Character è·
+U+84f8 Cao # Character è¸
+U+84f9 Yu # Character è¹
+U+84fa Yi # Character èº
+U+84fb Ji # Character è»
+U+84fc Liao # Character è¼
+U+84fd Bi # Character è½
+U+84fe Lu # Character è¾
+U+84ff Su # Character è¿
diff --git a/resources/chars/ascii/row85.trans b/resources/chars/ascii/row85.trans
new file mode 100644
index 0000000..9cb79e3
--- /dev/null
+++ b/resources/chars/ascii/row85.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+8500 Bu # Character è
+U+8501 Zhang # Character è
+U+8502 Luo # Character è
+U+8503 Jiang # Character è
+U+8504 Man # Character è
+U+8505 Yan # Character è
+U+8506 Ling # Character è
+U+8507 Ji # Character è
+U+8508 Piao # Character è
+U+8509 Gun # Character è
+U+850a Han # Character è
+U+850b Di # Character è
+U+850c Su # Character è
+U+850d Lu # Character è
+U+850e She # Character è
+U+850f Shang # Character è
+U+8510 Di # Character è
+U+8511 Mie # Character è
+U+8512 Xun # Character è
+U+8513 Man # Character è
+U+8514 Bo # Character è
+U+8515 Di # Character è
+U+8516 Cuo # Character è
+U+8517 Zhe # Character è
+U+8518 Sen # Character è
+U+8519 Xuan # Character è
+U+851a Wei # Character è
+U+851b Hu # Character è
+U+851c Ao # Character è
+U+851d Mi # Character è
+U+851e Lou # Character è
+U+851f Cu # Character è
+U+8520 Zhong # Character è
+U+8521 Cai # Character è¡
+U+8522 Po # Character è¢
+U+8523 Jiang # Character è£
+U+8524 Mi # Character è¤
+U+8525 Cong # Character è¥
+U+8526 Niao # Character è¦
+U+8527 Hui # Character è§
+U+8528 Jun # Character è¨
+U+8529 Yin # Character è©
+U+852a Jian # Character èª
+U+852b Yan # Character è«
+U+852c Shu # Character è¬
+U+852d Yin # Character è
+U+852e Kui # Character è®
+U+852f Chen # Character è¯
+U+8530 Hu # Character è°
+U+8531 Sha # Character è±
+U+8532 Kou # Character è²
+U+8533 Qian # Character è³
+U+8534 Ma # Character è´
+U+8535 Zang # Character èµ
+U+8536 Sonoko # Character è¶
+U+8537 Qiang # Character è·
+U+8538 Dou # Character è¸
+U+8539 Lian # Character è¹
+U+853a Lin # Character èº
+U+853b Kou # Character è»
+U+853c Ai # Character è¼
+U+853d Bi # Character è½
+U+853e Li # Character è¾
+U+853f Wei # Character è¿
+U+8540 Ji # Character è
+U+8541 Xun # Character è
+U+8542 Sheng # Character è
+U+8543 Fan # Character è
+U+8544 Meng # Character è
+U+8545 Ou # Character è
+U+8546 Chan # Character è
+U+8547 Dian # Character è
+U+8548 Xun # Character è
+U+8549 Jiao # Character è
+U+854a Rui # Character è
+U+854b Rui # Character è
+U+854c Lei # Character è
+U+854d Yu # Character è
+U+854e Qiao # Character è
+U+854f Chu # Character è
+U+8550 Hua # Character è
+U+8551 Jian # Character è
+U+8552 Mai # Character è
+U+8553 Yun # Character è
+U+8554 Bao # Character è
+U+8555 You # Character è
+U+8556 Qu # Character è
+U+8557 Lu # Character è
+U+8558 Rao # Character è
+U+8559 Hui # Character è
+U+855a E # Character è
+U+855b Teng # Character è
+U+855c Fei # Character è
+U+855d Jue # Character è
+U+855e Zui # Character è
+U+855f Fa # Character è
+U+8560 Ru # Character è
+U+8561 Fen # Character è¡
+U+8562 Kui # Character è¢
+U+8563 Shun # Character è£
+U+8564 Rui # Character è¤
+U+8565 Ya # Character è¥
+U+8566 Xu # Character è¦
+U+8567 Fu # Character è§
+U+8568 Jue # Character è¨
+U+8569 Dang # Character è©
+U+856a Wu # Character èª
+U+856b Tong # Character è«
+U+856c Si # Character è¬
+U+856d Xiao # Character è
+U+856e Xi # Character è®
+U+856f Long # Character è¯
+U+8570 Yun # Character è°
+U+8571 ? # Character è±
+U+8572 Qi # Character è²
+U+8573 Jian # Character è³
+U+8574 Yun # Character è´
+U+8575 Sun # Character èµ
+U+8576 Ling # Character è¶
+U+8577 Yu # Character è·
+U+8578 Xia # Character è¸
+U+8579 Yong # Character è¹
+U+857a Ji # Character èº
+U+857b Hong # Character è»
+U+857c Si # Character è¼
+U+857d Nong # Character è½
+U+857e Lei # Character è¾
+U+857f Xuan # Character è¿
+U+8580 Yun # Character è
+U+8581 Yu # Character è
+U+8582 Xi # Character è
+U+8583 Hao # Character è
+U+8584 Bo # Character è
+U+8585 Hao # Character è
+U+8586 Ai # Character è
+U+8587 Wei # Character è
+U+8588 Hui # Character è
+U+8589 Wei # Character è
+U+858a Ji # Character è
+U+858b Ci # Character è
+U+858c Xiang # Character è
+U+858d Luan # Character è
+U+858e Mie # Character è
+U+858f Yi # Character è
+U+8590 Leng # Character è
+U+8591 Jiang # Character è
+U+8592 Can # Character è
+U+8593 Shen # Character è
+U+8594 Qiang # Character è
+U+8595 Lian # Character è
+U+8596 Ke # Character è
+U+8597 Yuan # Character è
+U+8598 Da # Character è
+U+8599 Ti # Character è
+U+859a Tang # Character è
+U+859b Xie # Character è
+U+859c Bi # Character è
+U+859d Zhan # Character è
+U+859e Sun # Character è
+U+859f Lian # Character è
+U+85a0 Fan # Character è
+U+85a1 Ding # Character è¡
+U+85a2 Jie # Character è¢
+U+85a3 Gu # Character è£
+U+85a4 Xie # Character è¤
+U+85a5 Shu # Character è¥
+U+85a6 Jian # Character è¦
+U+85a7 Kao # Character è§
+U+85a8 Hong # Character è¨
+U+85a9 Sa # Character è©
+U+85aa Xin # Character èª
+U+85ab Xun # Character è«
+U+85ac Yao # Character è¬
+U+85ad Hie # Character è
+U+85ae Sou # Character è®
+U+85af Shu # Character è¯
+U+85b0 Xun # Character è°
+U+85b1 Dui # Character è±
+U+85b2 Pin # Character è²
+U+85b3 Wei # Character è³
+U+85b4 Neng # Character è´
+U+85b5 Chou # Character èµ
+U+85b6 Mai # Character è¶
+U+85b7 Ru # Character è·
+U+85b8 Piao # Character è¸
+U+85b9 Tai # Character è¹
+U+85ba Qi # Character èº
+U+85bb Zao # Character è»
+U+85bc Chen # Character è¼
+U+85bd Zhen # Character è½
+U+85be Er # Character è¾
+U+85bf Ni # Character è¿
+U+85c0 Ying # Character è
+U+85c1 Gao # Character è
+U+85c2 Cong # Character è
+U+85c3 Xiao # Character è
+U+85c4 Qi # Character è
+U+85c5 Fa # Character è
+U+85c6 Jian # Character è
+U+85c7 Xu # Character è
+U+85c8 Kui # Character è
+U+85c9 Jie # Character è
+U+85ca Bian # Character è
+U+85cb Diao # Character è
+U+85cc Mi # Character è
+U+85cd Lan # Character è
+U+85ce Jin # Character è
+U+85cf Cang # Character è
+U+85d0 Miao # Character è
+U+85d1 Qiong # Character è
+U+85d2 Qie # Character è
+U+85d3 Xian # Character è
+U+85d4 ? # Character è
+U+85d5 Ou # Character è
+U+85d6 Xian # Character è
+U+85d7 Su # Character è
+U+85d8 Lu # Character è
+U+85d9 Yi # Character è
+U+85da Xu # Character è
+U+85db Xie # Character è
+U+85dc Li # Character è
+U+85dd Yi # Character è
+U+85de La # Character è
+U+85df Lei # Character è
+U+85e0 Xiao # Character è
+U+85e1 Di # Character è¡
+U+85e2 Zhi # Character è¢
+U+85e3 Bei # Character è£
+U+85e4 Teng # Character è¤
+U+85e5 Yao # Character è¥
+U+85e6 Mo # Character è¦
+U+85e7 Huan # Character è§
+U+85e8 Piao # Character è¨
+U+85e9 Fan # Character è©
+U+85ea Sou # Character èª
+U+85eb Tan # Character è«
+U+85ec Tui # Character è¬
+U+85ed Qiong # Character è
+U+85ee Qiao # Character è®
+U+85ef Wei # Character è¯
+U+85f0 Liu # Character è°
+U+85f1 Hui # Character è±
+U+85f2 ? # Character è²
+U+85f3 Gao # Character è³
+U+85f4 Yun # Character è´
+U+85f5 ? # Character èµ
+U+85f6 Li # Character è¶
+U+85f7 Shu # Character è·
+U+85f8 Chu # Character è¸
+U+85f9 Ai # Character è¹
+U+85fa Lin # Character èº
+U+85fb Zao # Character è»
+U+85fc Xuan # Character è¼
+U+85fd Chen # Character è½
+U+85fe Lai # Character è¾
+U+85ff Huo # Character è¿
diff --git a/resources/chars/ascii/row86.trans b/resources/chars/ascii/row86.trans
new file mode 100644
index 0000000..2fd38dd
--- /dev/null
+++ b/resources/chars/ascii/row86.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+8600 Tuo # Character è
+U+8601 Wu # Character è
+U+8602 Rui # Character è
+U+8603 Rui # Character è
+U+8604 Qi # Character è
+U+8605 Heng # Character è
+U+8606 Lu # Character è
+U+8607 Su # Character è
+U+8608 Tui # Character è
+U+8609 Mang # Character è
+U+860a Yun # Character è
+U+860b Pin # Character è
+U+860c Yu # Character è
+U+860d Xun # Character è
+U+860e Ji # Character è
+U+860f Jiong # Character è
+U+8610 Xian # Character è
+U+8611 Mo # Character è
+U+8612 Hagi # Character è
+U+8613 Su # Character è
+U+8614 Jiong # Character è
+U+8615 ? # Character è
+U+8616 Nie # Character è
+U+8617 Bo # Character è
+U+8618 Rang # Character è
+U+8619 Yi # Character è
+U+861a Xian # Character è
+U+861b Yu # Character è
+U+861c Ju # Character è
+U+861d Lian # Character è
+U+861e Lian # Character è
+U+861f Yin # Character è
+U+8620 Qiang # Character è
+U+8621 Ying # Character è¡
+U+8622 Long # Character è¢
+U+8623 Tong # Character è£
+U+8624 Wei # Character è¤
+U+8625 Yue # Character è¥
+U+8626 Ling # Character è¦
+U+8627 Qu # Character è§
+U+8628 Yao # Character è¨
+U+8629 Fan # Character è©
+U+862a Mi # Character èª
+U+862b Lan # Character è«
+U+862c Kui # Character è¬
+U+862d Lan # Character è
+U+862e Ji # Character è®
+U+862f Dang # Character è¯
+U+8630 Katsura # Character è°
+U+8631 Lei # Character è±
+U+8632 Lei # Character è²
+U+8633 Hua # Character è³
+U+8634 Feng # Character è´
+U+8635 Zhi # Character èµ
+U+8636 Wei # Character è¶
+U+8637 Kui # Character è·
+U+8638 Zhan # Character è¸
+U+8639 Huai # Character è¹
+U+863a Li # Character èº
+U+863b Ji # Character è»
+U+863c Mi # Character è¼
+U+863d Lei # Character è½
+U+863e Huai # Character è¾
+U+863f Luo # Character è¿
+U+8640 Ji # Character è
+U+8641 Kui # Character è
+U+8642 Lu # Character è
+U+8643 Jian # Character è
+U+8644 San # Character è
+U+8645 ? # Character è
+U+8646 Lei # Character è
+U+8647 Quan # Character è
+U+8648 Xiao # Character è
+U+8649 Yi # Character è
+U+864a Luan # Character è
+U+864b Men # Character è
+U+864c Bie # Character è
+U+864d Hu # Character è
+U+864e Hu # Character è
+U+864f Lu # Character è
+U+8650 Nue # Character è
+U+8651 Lu # Character è
+U+8652 Si # Character è
+U+8653 Xiao # Character è
+U+8654 Qian # Character è
+U+8655 Chu # Character è
+U+8656 Hu # Character è
+U+8657 Xu # Character è
+U+8658 Cuo # Character è
+U+8659 Fu # Character è
+U+865a Xu # Character è
+U+865b Xu # Character è
+U+865c Lu # Character è
+U+865d Hu # Character è
+U+865e Yu # Character è
+U+865f Hao # Character è
+U+8660 Jiao # Character è
+U+8661 Ju # Character è¡
+U+8662 Guo # Character è¢
+U+8663 Bao # Character è£
+U+8664 Yan # Character è¤
+U+8665 Zhan # Character è¥
+U+8666 Zhan # Character è¦
+U+8667 Kui # Character è§
+U+8668 Ban # Character è¨
+U+8669 Xi # Character è©
+U+866a Shu # Character èª
+U+866b Chong # Character è«
+U+866c Qiu # Character è¬
+U+866d Diao # Character è
+U+866e Ji # Character è®
+U+866f Qiu # Character è¯
+U+8670 Cheng # Character è°
+U+8671 Shi # Character è±
+U+8672 ? # Character è²
+U+8673 Di # Character è³
+U+8674 Zhe # Character è´
+U+8675 She # Character èµ
+U+8676 Yu # Character è¶
+U+8677 Gan # Character è·
+U+8678 Zi # Character è¸
+U+8679 Hong # Character è¹
+U+867a Hui # Character èº
+U+867b Meng # Character è»
+U+867c Ge # Character è¼
+U+867d Sui # Character è½
+U+867e Xia # Character è¾
+U+867f Chai # Character è¿
+U+8680 Shi # Character è
+U+8681 Yi # Character è
+U+8682 Ma # Character è
+U+8683 Xiang # Character è
+U+8684 Fang # Character è
+U+8685 E # Character è
+U+8686 Pa # Character è
+U+8687 Chi # Character è
+U+8688 Qian # Character è
+U+8689 Wen # Character è
+U+868a Wen # Character è
+U+868b Rui # Character è
+U+868c Bang # Character è
+U+868d Bi # Character è
+U+868e Yue # Character è
+U+868f Yue # Character è
+U+8690 Jun # Character è
+U+8691 Qi # Character è
+U+8692 Ran # Character è
+U+8693 Yin # Character è
+U+8694 Qi # Character è
+U+8695 Tian # Character è
+U+8696 Yuan # Character è
+U+8697 Jue # Character è
+U+8698 Hui # Character è
+U+8699 Qin # Character è
+U+869a Qi # Character è
+U+869b Zhong # Character è
+U+869c Ya # Character è
+U+869d Ci # Character è
+U+869e Mu # Character è
+U+869f Wang # Character è
+U+86a0 Fen # Character è
+U+86a1 Fen # Character è¡
+U+86a2 Hang # Character è¢
+U+86a3 Gong # Character è£
+U+86a4 Zao # Character è¤
+U+86a5 Fu # Character è¥
+U+86a6 Ran # Character è¦
+U+86a7 Jie # Character è§
+U+86a8 Fu # Character è¨
+U+86a9 Chi # Character è©
+U+86aa Dou # Character èª
+U+86ab Piao # Character è«
+U+86ac Xian # Character è¬
+U+86ad Ni # Character è
+U+86ae Te # Character è®
+U+86af Qiu # Character è¯
+U+86b0 You # Character è°
+U+86b1 Zha # Character è±
+U+86b2 Ping # Character è²
+U+86b3 Chi # Character è³
+U+86b4 You # Character è´
+U+86b5 He # Character èµ
+U+86b6 Han # Character è¶
+U+86b7 Ju # Character è·
+U+86b8 Li # Character è¸
+U+86b9 Fu # Character è¹
+U+86ba Ran # Character èº
+U+86bb Zha # Character è»
+U+86bc Gou # Character è¼
+U+86bd Pi # Character è½
+U+86be Bo # Character è¾
+U+86bf Xian # Character è¿
+U+86c0 Zhu # Character è
+U+86c1 Diao # Character è
+U+86c2 Bie # Character è
+U+86c3 Bing # Character è
+U+86c4 Gu # Character è
+U+86c5 Ran # Character è
+U+86c6 Qu # Character è
+U+86c7 She # Character è
+U+86c8 Tie # Character è
+U+86c9 Ling # Character è
+U+86ca Gu # Character è
+U+86cb Dan # Character è
+U+86cc Gu # Character è
+U+86cd Ying # Character è
+U+86ce Li # Character è
+U+86cf Cheng # Character è
+U+86d0 Qu # Character è
+U+86d1 Mou # Character è
+U+86d2 Ge # Character è
+U+86d3 Ci # Character è
+U+86d4 Hui # Character è
+U+86d5 Hui # Character è
+U+86d6 Mang # Character è
+U+86d7 Fu # Character è
+U+86d8 Yang # Character è
+U+86d9 Wa # Character è
+U+86da Lie # Character è
+U+86db Zhu # Character è
+U+86dc Yi # Character è
+U+86dd Xian # Character è
+U+86de Kuo # Character è
+U+86df Jiao # Character è
+U+86e0 Li # Character è
+U+86e1 Yi # Character è¡
+U+86e2 Ping # Character è¢
+U+86e3 Ji # Character è£
+U+86e4 Ha # Character è¤
+U+86e5 She # Character è¥
+U+86e6 Yi # Character è¦
+U+86e7 Wang # Character è§
+U+86e8 Mo # Character è¨
+U+86e9 Qiong # Character è©
+U+86ea Qie # Character èª
+U+86eb Gui # Character è«
+U+86ec Gong # Character è¬
+U+86ed Zhi # Character è
+U+86ee Man # Character è®
+U+86ef Ebi # Character è¯
+U+86f0 Zhi # Character è°
+U+86f1 Jia # Character è±
+U+86f2 Rao # Character è²
+U+86f3 Si # Character è³
+U+86f4 Qi # Character è´
+U+86f5 Xing # Character èµ
+U+86f6 Lie # Character è¶
+U+86f7 Qiu # Character è·
+U+86f8 Shao # Character è¸
+U+86f9 Yong # Character è¹
+U+86fa Jia # Character èº
+U+86fb Shui # Character è»
+U+86fc Che # Character è¼
+U+86fd Bai # Character è½
+U+86fe E # Character è¾
+U+86ff Han # Character è¿
diff --git a/resources/chars/ascii/row87.trans b/resources/chars/ascii/row87.trans
new file mode 100644
index 0000000..19eba5b
--- /dev/null
+++ b/resources/chars/ascii/row87.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+8700 Shu # Character è
+U+8701 Xuan # Character è
+U+8702 Feng # Character è
+U+8703 Shen # Character è
+U+8704 Zhen # Character è
+U+8705 Fu # Character è
+U+8706 Xian # Character è
+U+8707 Zhe # Character è
+U+8708 Wu # Character è
+U+8709 Fu # Character è
+U+870a Li # Character è
+U+870b Lang # Character è
+U+870c Bi # Character è
+U+870d Chu # Character è
+U+870e Yuan # Character è
+U+870f You # Character è
+U+8710 Jie # Character è
+U+8711 Dan # Character è
+U+8712 Yan # Character è
+U+8713 Ting # Character è
+U+8714 Dian # Character è
+U+8715 Shui # Character è
+U+8716 Hui # Character è
+U+8717 Gua # Character è
+U+8718 Zhi # Character è
+U+8719 Song # Character è
+U+871a Fei # Character è
+U+871b Ju # Character è
+U+871c Mi # Character è
+U+871d Qi # Character è
+U+871e Qi # Character è
+U+871f Yu # Character è
+U+8720 Jun # Character è
+U+8721 Zha # Character è¡
+U+8722 Meng # Character è¢
+U+8723 Qiang # Character è£
+U+8724 Si # Character è¤
+U+8725 Xi # Character è¥
+U+8726 Lun # Character è¦
+U+8727 Li # Character è§
+U+8728 Die # Character è¨
+U+8729 Tiao # Character è©
+U+872a Tao # Character èª
+U+872b Kun # Character è«
+U+872c Gan # Character è¬
+U+872d Han # Character è
+U+872e Yu # Character è®
+U+872f Bang # Character è¯
+U+8730 Fei # Character è°
+U+8731 Pi # Character è±
+U+8732 Wei # Character è²
+U+8733 Dun # Character è³
+U+8734 Yi # Character è´
+U+8735 Yuan # Character èµ
+U+8736 Su # Character è¶
+U+8737 Quan # Character è·
+U+8738 Qian # Character è¸
+U+8739 Rui # Character è¹
+U+873a Ni # Character èº
+U+873b Qing # Character è»
+U+873c Wei # Character è¼
+U+873d Liang # Character è½
+U+873e Guo # Character è¾
+U+873f Wan # Character è¿
+U+8740 Dong # Character è
+U+8741 E # Character è
+U+8742 Ban # Character è
+U+8743 Di # Character è
+U+8744 Wang # Character è
+U+8745 Can # Character è
+U+8746 Yang # Character è
+U+8747 Ying # Character è
+U+8748 Guo # Character è
+U+8749 Chan # Character è
+U+874a ? # Character è
+U+874b La # Character è
+U+874c Ke # Character è
+U+874d Ji # Character è
+U+874e He # Character è
+U+874f Ting # Character è
+U+8750 Mai # Character è
+U+8751 Xu # Character è
+U+8752 Mian # Character è
+U+8753 Yu # Character è
+U+8754 Jie # Character è
+U+8755 Shi # Character è
+U+8756 Xuan # Character è
+U+8757 Huang # Character è
+U+8758 Yan # Character è
+U+8759 Bian # Character è
+U+875a Rou # Character è
+U+875b Wei # Character è
+U+875c Fu # Character è
+U+875d Yuan # Character è
+U+875e Mei # Character è
+U+875f Wei # Character è
+U+8760 Fu # Character è
+U+8761 Ruan # Character è¡
+U+8762 Xie # Character è¢
+U+8763 You # Character è£
+U+8764 Qiu # Character è¤
+U+8765 Mao # Character è¥
+U+8766 Xia # Character è¦
+U+8767 Ying # Character è§
+U+8768 Shi # Character è¨
+U+8769 Chong # Character è©
+U+876a Tang # Character èª
+U+876b Zhu # Character è«
+U+876c Zong # Character è¬
+U+876d Ti # Character è
+U+876e Fu # Character è®
+U+876f Yuan # Character è¯
+U+8770 Hui # Character è°
+U+8771 Meng # Character è±
+U+8772 La # Character è²
+U+8773 Du # Character è³
+U+8774 Hu # Character è´
+U+8775 Qiu # Character èµ
+U+8776 Die # Character è¶
+U+8777 Li # Character è·
+U+8778 Gua # Character è¸
+U+8779 Yun # Character è¹
+U+877a Ju # Character èº
+U+877b Nan # Character è»
+U+877c Lou # Character è¼
+U+877d Qun # Character è½
+U+877e Rong # Character è¾
+U+877f Ying # Character è¿
+U+8780 Jiang # Character è
+U+8781 ? # Character è
+U+8782 Lang # Character è
+U+8783 Pang # Character è
+U+8784 Si # Character è
+U+8785 Xi # Character è
+U+8786 Ci # Character è
+U+8787 Xi # Character è
+U+8788 Yuan # Character è
+U+8789 Weng # Character è
+U+878a Lian # Character è
+U+878b Sou # Character è
+U+878c Ban # Character è
+U+878d Rong # Character è
+U+878e Rong # Character è
+U+878f Ji # Character è
+U+8790 Wu # Character è
+U+8791 Qiu # Character è
+U+8792 Han # Character è
+U+8793 Qin # Character è
+U+8794 Yi # Character è
+U+8795 Bi # Character è
+U+8796 Hua # Character è
+U+8797 Tang # Character è
+U+8798 Yi # Character è
+U+8799 Du # Character è
+U+879a Nai # Character è
+U+879b He # Character è
+U+879c Hu # Character è
+U+879d Hui # Character è
+U+879e Ma # Character è
+U+879f Ming # Character è
+U+87a0 Yi # Character è
+U+87a1 Wen # Character è¡
+U+87a2 Ying # Character è¢
+U+87a3 Teng # Character è£
+U+87a4 Yu # Character è¤
+U+87a5 Cang # Character è¥
+U+87a6 So # Character è¦
+U+87a7 Ebi # Character è§
+U+87a8 Man # Character è¨
+U+87a9 ? # Character è©
+U+87aa Shang # Character èª
+U+87ab Zhe # Character è«
+U+87ac Cao # Character è¬
+U+87ad Chi # Character è
+U+87ae Di # Character è®
+U+87af Ao # Character è¯
+U+87b0 Lu # Character è°
+U+87b1 Wei # Character è±
+U+87b2 Zhi # Character è²
+U+87b3 Tang # Character è³
+U+87b4 Chen # Character è´
+U+87b5 Piao # Character èµ
+U+87b6 Qu # Character è¶
+U+87b7 Pi # Character è·
+U+87b8 Yu # Character è¸
+U+87b9 Jian # Character è¹
+U+87ba Luo # Character èº
+U+87bb Lou # Character è»
+U+87bc Qin # Character è¼
+U+87bd Zhong # Character è½
+U+87be Yin # Character è¾
+U+87bf Jiang # Character è¿
+U+87c0 Shuai # Character è
+U+87c1 Wen # Character è
+U+87c2 Jiao # Character è
+U+87c3 Wan # Character è
+U+87c4 Zhi # Character è
+U+87c5 Zhe # Character è
+U+87c6 Ma # Character è
+U+87c7 Ma # Character è
+U+87c8 Guo # Character è
+U+87c9 Liu # Character è
+U+87ca Mao # Character è
+U+87cb Xi # Character è
+U+87cc Cong # Character è
+U+87cd Li # Character è
+U+87ce Man # Character è
+U+87cf Xiao # Character è
+U+87d0 Kamakiri # Character è
+U+87d1 Zhang # Character è
+U+87d2 Mang # Character è
+U+87d3 Xiang # Character è
+U+87d4 Mo # Character è
+U+87d5 Zui # Character è
+U+87d6 Si # Character è
+U+87d7 Qiu # Character è
+U+87d8 Te # Character è
+U+87d9 Zhi # Character è
+U+87da Peng # Character è
+U+87db Peng # Character è
+U+87dc Jiao # Character è
+U+87dd Qu # Character è
+U+87de Bie # Character è
+U+87df Liao # Character è
+U+87e0 Pan # Character è
+U+87e1 Gui # Character è¡
+U+87e2 Xi # Character è¢
+U+87e3 Ji # Character è£
+U+87e4 Zhuan # Character è¤
+U+87e5 Huang # Character è¥
+U+87e6 Fei # Character è¦
+U+87e7 Lao # Character è§
+U+87e8 Jue # Character è¨
+U+87e9 Jue # Character è©
+U+87ea Hui # Character èª
+U+87eb Yin # Character è«
+U+87ec Chan # Character è¬
+U+87ed Jiao # Character è
+U+87ee Shan # Character è®
+U+87ef Rao # Character è¯
+U+87f0 Xiao # Character è°
+U+87f1 Mou # Character è±
+U+87f2 Chong # Character è²
+U+87f3 Xun # Character è³
+U+87f4 Si # Character è´
+U+87f5 ? # Character èµ
+U+87f6 Cheng # Character è¶
+U+87f7 Dang # Character è·
+U+87f8 Li # Character è¸
+U+87f9 Xie # Character è¹
+U+87fa Shan # Character èº
+U+87fb Yi # Character è»
+U+87fc Jing # Character è¼
+U+87fd Da # Character è½
+U+87fe Chan # Character è¾
+U+87ff Qi # Character è¿
diff --git a/resources/chars/ascii/row88.trans b/resources/chars/ascii/row88.trans
new file mode 100644
index 0000000..b3f824f
--- /dev/null
+++ b/resources/chars/ascii/row88.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+8800 Ci # Character è
+U+8801 Xiang # Character è
+U+8802 She # Character è
+U+8803 Luo # Character è
+U+8804 Qin # Character è
+U+8805 Ying # Character è
+U+8806 Chai # Character è
+U+8807 Li # Character è
+U+8808 Ze # Character è
+U+8809 Xuan # Character è
+U+880a Lian # Character è
+U+880b Zhu # Character è
+U+880c Ze # Character è
+U+880d Xie # Character è
+U+880e Mang # Character è
+U+880f Xie # Character è
+U+8810 Qi # Character è
+U+8811 Rong # Character è
+U+8812 Jian # Character è
+U+8813 Meng # Character è
+U+8814 Hao # Character è
+U+8815 Ruan # Character è
+U+8816 Huo # Character è
+U+8817 Zhuo # Character è
+U+8818 Jie # Character è
+U+8819 Bin # Character è
+U+881a He # Character è
+U+881b Mie # Character è
+U+881c Fan # Character è
+U+881d Lei # Character è
+U+881e Jie # Character è
+U+881f La # Character è
+U+8820 Mi # Character è
+U+8821 Li # Character è ¡
+U+8822 Chun # Character è ¢
+U+8823 Li # Character è £
+U+8824 Qiu # Character è ¤
+U+8825 Nie # Character è ¥
+U+8826 Lu # Character è ¦
+U+8827 Du # Character è §
+U+8828 Xiao # Character è ¨
+U+8829 Zhu # Character è ©
+U+882a Long # Character è ª
+U+882b Li # Character è «
+U+882c Long # Character è ¬
+U+882d Feng # Character è
+U+882e Ye # Character è ®
+U+882f Beng # Character è ¯
+U+8830 Shang # Character è °
+U+8831 Gu # Character è ±
+U+8832 Juan # Character è ²
+U+8833 Ying # Character è ³
+U+8834 ? # Character è ´
+U+8835 Xi # Character è µ
+U+8836 Can # Character è ¶
+U+8837 Qu # Character è ·
+U+8838 Quan # Character è ¸
+U+8839 Du # Character è ¹
+U+883a Can # Character è º
+U+883b Man # Character è »
+U+883c Jue # Character è ¼
+U+883d Jie # Character è ½
+U+883e Zhu # Character è ¾
+U+883f Zha # Character è ¿
+U+8840 Xie # Character è¡
+U+8841 Huang # Character è¡
+U+8842 Niu # Character è¡
+U+8843 Pei # Character è¡
+U+8844 Nu # Character è¡
+U+8845 Xin # Character è¡
+U+8846 Zhong # Character è¡
+U+8847 Mo # Character è¡
+U+8848 Er # Character è¡
+U+8849 Ke # Character è¡
+U+884a Mie # Character è¡
+U+884b Xi # Character è¡
+U+884c Xing # Character è¡
+U+884d Yan # Character è¡
+U+884e Kan # Character è¡
+U+884f Yuan # Character è¡
+U+8850 ? # Character è¡
+U+8851 Ling # Character è¡
+U+8852 Xuan # Character è¡
+U+8853 Shu # Character è¡
+U+8854 Xian # Character è¡
+U+8855 Tong # Character è¡
+U+8856 Long # Character è¡
+U+8857 Jie # Character è¡
+U+8858 Xian # Character è¡
+U+8859 Ya # Character è¡
+U+885a Hu # Character è¡
+U+885b Wei # Character è¡
+U+885c Dao # Character è¡
+U+885d Chong # Character è¡
+U+885e Wei # Character è¡
+U+885f Dao # Character è¡
+U+8860 Zhun # Character è¡
+U+8861 Heng # Character è¡¡
+U+8862 Qu # Character è¡¢
+U+8863 Yi # Character è¡£
+U+8864 Yi # Character 衤
+U+8865 Bu # Character è¡¥
+U+8866 Gan # Character 衦
+U+8867 Yu # Character 衧
+U+8868 Biao # Character 表
+U+8869 Cha # Character è¡©
+U+886a Yi # Character 衪
+U+886b Shan # Character è¡«
+U+886c Chen # Character 衬
+U+886d Fu # Character è¡
+U+886e Gun # Character è¡®
+U+886f Fen # Character 衯
+U+8870 Shuai # Character è¡°
+U+8871 Jie # Character 衱
+U+8872 Na # Character 衲
+U+8873 Zhong # Character 衳
+U+8874 Dan # Character è¡´
+U+8875 Ri # Character 衵
+U+8876 Zhong # Character 衶
+U+8877 Zhong # Character è¡·
+U+8878 Xie # Character 衸
+U+8879 Qi # Character 衹
+U+887a Xie # Character 衺
+U+887b Ran # Character è¡»
+U+887c Zhi # Character 衼
+U+887d Ren # Character 衽
+U+887e Qin # Character 衾
+U+887f Jin # Character è¡¿
+U+8880 Jun # Character è¢
+U+8881 Yuan # Character è¢
+U+8882 Mei # Character è¢
+U+8883 Chai # Character è¢
+U+8884 Ao # Character è¢
+U+8885 Niao # Character è¢
+U+8886 Hui # Character è¢
+U+8887 Ran # Character è¢
+U+8888 Jia # Character è¢
+U+8889 Tuo # Character è¢
+U+888a Ling # Character è¢
+U+888b Dai # Character è¢
+U+888c Bao # Character è¢
+U+888d Pao # Character è¢
+U+888e Yao # Character è¢
+U+888f Zuo # Character è¢
+U+8890 Bi # Character è¢
+U+8891 Shao # Character è¢
+U+8892 Tan # Character è¢
+U+8893 Ju # Character è¢
+U+8894 He # Character è¢
+U+8895 Shu # Character è¢
+U+8896 Xiu # Character è¢
+U+8897 Zhen # Character è¢
+U+8898 Yi # Character è¢
+U+8899 Pa # Character è¢
+U+889a Bo # Character è¢
+U+889b Di # Character è¢
+U+889c Wa # Character è¢
+U+889d Fu # Character è¢
+U+889e Gun # Character è¢
+U+889f Zhi # Character è¢
+U+88a0 Zhi # Character è¢
+U+88a1 Ran # Character 袡
+U+88a2 Pan # Character 袢
+U+88a3 Yi # Character 袣
+U+88a4 Mao # Character 袤
+U+88a5 Tuo # Character 袥
+U+88a6 Na # Character 袦
+U+88a7 Kou # Character 袧
+U+88a8 Xian # Character 袨
+U+88a9 Chan # Character 袩
+U+88aa Qu # Character 袪
+U+88ab Bei # Character 被
+U+88ac Gun # Character 袬
+U+88ad Xi # Character è¢
+U+88ae Ne # Character 袮
+U+88af Bo # Character 袯
+U+88b0 Horo # Character 袰
+U+88b1 Fu # Character 袱
+U+88b2 Yi # Character 袲
+U+88b3 Chi # Character 袳
+U+88b4 Ku # Character 袴
+U+88b5 Ren # Character 袵
+U+88b6 Jiang # Character 袶
+U+88b7 Jia # Character 袷
+U+88b8 Cun # Character 袸
+U+88b9 Mo # Character 袹
+U+88ba Jie # Character 袺
+U+88bb Er # Character 袻
+U+88bc Luo # Character 袼
+U+88bd Ru # Character 袽
+U+88be Zhu # Character 袾
+U+88bf Gui # Character 袿
+U+88c0 Yin # Character è£
+U+88c1 Cai # Character è£
+U+88c2 Lie # Character è£
+U+88c3 Kamishimo # Character è£
+U+88c4 Yuki # Character è£
+U+88c5 Zhuang # Character è£
+U+88c6 Dang # Character è£
+U+88c7 ? # Character è£
+U+88c8 Kun # Character è£
+U+88c9 Ken # Character è£
+U+88ca Niao # Character è£
+U+88cb Shu # Character è£
+U+88cc Jia # Character è£
+U+88cd Kun # Character è£
+U+88ce Cheng # Character è£
+U+88cf Li # Character è£
+U+88d0 Juan # Character è£
+U+88d1 Shen # Character è£
+U+88d2 Pou # Character è£
+U+88d3 Ge # Character è£
+U+88d4 Yi # Character è£
+U+88d5 Yu # Character è£
+U+88d6 Zhen # Character è£
+U+88d7 Liu # Character è£
+U+88d8 Qiu # Character è£
+U+88d9 Qun # Character è£
+U+88da Ji # Character è£
+U+88db Yi # Character è£
+U+88dc Bu # Character è£
+U+88dd Zhuang # Character è£
+U+88de Shui # Character è£
+U+88df Sha # Character è£
+U+88e0 Qun # Character è£
+U+88e1 Li # Character 裡
+U+88e2 Lian # Character 裢
+U+88e3 Lian # Character 裣
+U+88e4 Ku # Character 裤
+U+88e5 Jian # Character 裥
+U+88e6 Fou # Character 裦
+U+88e7 Chan # Character 裧
+U+88e8 Bi # Character 裨
+U+88e9 Gun # Character 裩
+U+88ea Tao # Character 裪
+U+88eb Yuan # Character 裫
+U+88ec Ling # Character 裬
+U+88ed Chi # Character è£
+U+88ee Chang # Character 裮
+U+88ef Chou # Character 裯
+U+88f0 Duo # Character 裰
+U+88f1 Biao # Character 裱
+U+88f2 Liang # Character 裲
+U+88f3 Chang # Character 裳
+U+88f4 Pei # Character 裴
+U+88f5 Pei # Character 裵
+U+88f6 Fei # Character 裶
+U+88f7 Yuan # Character 裷
+U+88f8 Luo # Character 裸
+U+88f9 Guo # Character 裹
+U+88fa Yan # Character 裺
+U+88fb Du # Character 裻
+U+88fc Xi # Character 裼
+U+88fd Zhi # Character 製
+U+88fe Ju # Character 裾
+U+88ff Qi # Character 裿
diff --git a/resources/chars/ascii/row89.trans b/resources/chars/ascii/row89.trans
new file mode 100644
index 0000000..ae3e840
--- /dev/null
+++ b/resources/chars/ascii/row89.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+8900 Ji # Character è¤
+U+8901 Zhi # Character è¤
+U+8902 Gua # Character è¤
+U+8903 Ken # Character è¤
+U+8904 Che # Character è¤
+U+8905 Ti # Character è¤
+U+8906 Ti # Character è¤
+U+8907 Fu # Character è¤
+U+8908 Chong # Character è¤
+U+8909 Xie # Character è¤
+U+890a Bian # Character è¤
+U+890b Die # Character è¤
+U+890c Kun # Character è¤
+U+890d Duan # Character è¤
+U+890e Xiu # Character è¤
+U+890f Xiu # Character è¤
+U+8910 He # Character è¤
+U+8911 Yuan # Character è¤
+U+8912 Bao # Character è¤
+U+8913 Bao # Character è¤
+U+8914 Fu # Character è¤
+U+8915 Yu # Character è¤
+U+8916 Tuan # Character è¤
+U+8917 Yan # Character è¤
+U+8918 Hui # Character è¤
+U+8919 Bei # Character è¤
+U+891a Chu # Character è¤
+U+891b Lu # Character è¤
+U+891c Ena # Character è¤
+U+891d Hitoe # Character è¤
+U+891e Yun # Character è¤
+U+891f Da # Character è¤
+U+8920 Gou # Character è¤
+U+8921 Da # Character 褡
+U+8922 Huai # Character 褢
+U+8923 Rong # Character 褣
+U+8924 Yuan # Character 褤
+U+8925 Ru # Character 褥
+U+8926 Nai # Character 褦
+U+8927 Jiong # Character 褧
+U+8928 Suo # Character 褨
+U+8929 Ban # Character 褩
+U+892a Tun # Character 褪
+U+892b Chi # Character 褫
+U+892c Sang # Character 褬
+U+892d Niao # Character è¤
+U+892e Ying # Character 褮
+U+892f Jie # Character 褯
+U+8930 Qian # Character 褰
+U+8931 Huai # Character 褱
+U+8932 Ku # Character 褲
+U+8933 Lian # Character 褳
+U+8934 Bao # Character 褴
+U+8935 Li # Character 褵
+U+8936 Zhe # Character 褶
+U+8937 Shi # Character 褷
+U+8938 Lu # Character 褸
+U+8939 Yi # Character 褹
+U+893a Die # Character 褺
+U+893b Xie # Character 褻
+U+893c Xian # Character 褼
+U+893d Wei # Character 褽
+U+893e Biao # Character 褾
+U+893f Cao # Character 褿
+U+8940 Ji # Character è¥
+U+8941 Jiang # Character è¥
+U+8942 Sen # Character è¥
+U+8943 Bao # Character è¥
+U+8944 Xiang # Character è¥
+U+8945 Chihaya # Character è¥
+U+8946 Pu # Character è¥
+U+8947 Jian # Character è¥
+U+8948 Zhuan # Character è¥
+U+8949 Jian # Character è¥
+U+894a Zui # Character è¥
+U+894b Ji # Character è¥
+U+894c Dan # Character è¥
+U+894d Za # Character è¥
+U+894e Fan # Character è¥
+U+894f Bo # Character è¥
+U+8950 Xiang # Character è¥
+U+8951 Xin # Character è¥
+U+8952 Bie # Character è¥
+U+8953 Rao # Character è¥
+U+8954 Man # Character è¥
+U+8955 Lan # Character è¥
+U+8956 Ao # Character è¥
+U+8957 Duo # Character è¥
+U+8958 Gui # Character è¥
+U+8959 Cao # Character è¥
+U+895a Sui # Character è¥
+U+895b Nong # Character è¥
+U+895c Chan # Character è¥
+U+895d Lian # Character è¥
+U+895e Bi # Character è¥
+U+895f Jin # Character è¥
+U+8960 Dang # Character è¥
+U+8961 Shu # Character 襡
+U+8962 Tan # Character 襢
+U+8963 Bi # Character 襣
+U+8964 Lan # Character 襤
+U+8965 Pu # Character 襥
+U+8966 Ru # Character 襦
+U+8967 Zhi # Character 襧
+U+8968 ? # Character 襨
+U+8969 Shu # Character 襩
+U+896a Wa # Character 襪
+U+896b Shi # Character 襫
+U+896c Bai # Character 襬
+U+896d Xie # Character è¥
+U+896e Bo # Character 襮
+U+896f Chen # Character 襯
+U+8970 Lai # Character 襰
+U+8971 Long # Character 襱
+U+8972 Xi # Character 襲
+U+8973 Xian # Character 襳
+U+8974 Lan # Character 襴
+U+8975 Zhe # Character 襵
+U+8976 Dai # Character 襶
+U+8977 Tasuki # Character 襷
+U+8978 Zan # Character 襸
+U+8979 Shi # Character 襹
+U+897a Jian # Character 襺
+U+897b Pan # Character 襻
+U+897c Yi # Character 襼
+U+897d Ran # Character 襽
+U+897e Ya # Character 襾
+U+897f Xi # Character 西
+U+8980 Xi # Character è¦
+U+8981 Yao # Character è¦
+U+8982 Feng # Character è¦
+U+8983 Tan # Character è¦
+U+8984 ? # Character è¦
+U+8985 Biao # Character è¦
+U+8986 Fu # Character è¦
+U+8987 Ba # Character è¦
+U+8988 He # Character è¦
+U+8989 Ji # Character è¦
+U+898a Ji # Character è¦
+U+898b Jian # Character è¦
+U+898c Guan # Character è¦
+U+898d Bian # Character è¦
+U+898e Yan # Character è¦
+U+898f Gui # Character è¦
+U+8990 Jue # Character è¦
+U+8991 Pian # Character è¦
+U+8992 Mao # Character è¦
+U+8993 Mi # Character è¦
+U+8994 Mi # Character è¦
+U+8995 Mie # Character è¦
+U+8996 Shi # Character è¦
+U+8997 Si # Character è¦
+U+8998 Zhan # Character è¦
+U+8999 Luo # Character è¦
+U+899a Jue # Character è¦
+U+899b Mi # Character è¦
+U+899c Tiao # Character è¦
+U+899d Lian # Character è¦
+U+899e Yao # Character è¦
+U+899f Zhi # Character è¦
+U+89a0 Jun # Character è¦
+U+89a1 Xi # Character 覡
+U+89a2 Shan # Character 覢
+U+89a3 Wei # Character 覣
+U+89a4 Xi # Character 覤
+U+89a5 Tian # Character 覥
+U+89a6 Yu # Character 覦
+U+89a7 Lan # Character 覧
+U+89a8 E # Character 覨
+U+89a9 Du # Character 覩
+U+89aa Qin # Character 親
+U+89ab Pang # Character 覫
+U+89ac Ji # Character 覬
+U+89ad Ming # Character è¦
+U+89ae Ying # Character 覮
+U+89af Gou # Character 覯
+U+89b0 Qu # Character 覰
+U+89b1 Zhan # Character 覱
+U+89b2 Jin # Character 覲
+U+89b3 Guan # Character 観
+U+89b4 Deng # Character 覴
+U+89b5 Jian # Character 覵
+U+89b6 Luo # Character 覶
+U+89b7 Qu # Character 覷
+U+89b8 Jian # Character 覸
+U+89b9 Wei # Character 覹
+U+89ba Jue # Character 覺
+U+89bb Qu # Character 覻
+U+89bc Luo # Character 覼
+U+89bd Lan # Character 覽
+U+89be Shen # Character 覾
+U+89bf Di # Character 覿
+U+89c0 Guan # Character è§
+U+89c1 Jian # Character è§
+U+89c2 Guan # Character è§
+U+89c3 Yan # Character è§
+U+89c4 Gui # Character è§
+U+89c5 Mi # Character è§
+U+89c6 Shi # Character è§
+U+89c7 Zhan # Character è§
+U+89c8 Lan # Character è§
+U+89c9 Jue # Character è§
+U+89ca Ji # Character è§
+U+89cb Xi # Character è§
+U+89cc Di # Character è§
+U+89cd Tian # Character è§
+U+89ce Yu # Character è§
+U+89cf Gou # Character è§
+U+89d0 Jin # Character è§
+U+89d1 Qu # Character è§
+U+89d2 Jiao # Character è§
+U+89d3 Jiu # Character è§
+U+89d4 Jin # Character è§
+U+89d5 Cu # Character è§
+U+89d6 Jue # Character è§
+U+89d7 Zhi # Character è§
+U+89d8 Chao # Character è§
+U+89d9 Ji # Character è§
+U+89da Gu # Character è§
+U+89db Dan # Character è§
+U+89dc Zui # Character è§
+U+89dd Di # Character è§
+U+89de Shang # Character è§
+U+89df Hua # Character è§
+U+89e0 Quan # Character è§
+U+89e1 Ge # Character 觡
+U+89e2 Chi # Character 觢
+U+89e3 Jie # Character 解
+U+89e4 Gui # Character 觤
+U+89e5 Gong # Character 觥
+U+89e6 Hong # Character 触
+U+89e7 Jie # Character 觧
+U+89e8 Hun # Character 觨
+U+89e9 Qiu # Character 觩
+U+89ea Xing # Character 觪
+U+89eb Su # Character 觫
+U+89ec Ni # Character 觬
+U+89ed Ji # Character è§
+U+89ee Lu # Character 觮
+U+89ef Zhi # Character 觯
+U+89f0 Zha # Character 觰
+U+89f1 Bi # Character 觱
+U+89f2 Xing # Character 觲
+U+89f3 Hu # Character 觳
+U+89f4 Shang # Character 觴
+U+89f5 Gong # Character 觵
+U+89f6 Zhi # Character 觶
+U+89f7 Xue # Character 觷
+U+89f8 Chu # Character 觸
+U+89f9 Xi # Character 觹
+U+89fa Yi # Character 觺
+U+89fb Lu # Character 觻
+U+89fc Jue # Character 觼
+U+89fd Xi # Character 觽
+U+89fe Yan # Character 觾
+U+89ff Xi # Character 觿
diff --git a/resources/chars/ascii/row8a.trans b/resources/chars/ascii/row8a.trans
new file mode 100644
index 0000000..fafceea
--- /dev/null
+++ b/resources/chars/ascii/row8a.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+8a00 Yan # Character è¨
+U+8a01 Yan # Character è¨
+U+8a02 Ding # Character è¨
+U+8a03 Fu # Character è¨
+U+8a04 Qiu # Character è¨
+U+8a05 Qiu # Character è¨
+U+8a06 Jiao # Character è¨
+U+8a07 Hong # Character è¨
+U+8a08 Ji # Character è¨
+U+8a09 Fan # Character è¨
+U+8a0a Xun # Character è¨
+U+8a0b Diao # Character è¨
+U+8a0c Hong # Character è¨
+U+8a0d Cha # Character è¨
+U+8a0e Tao # Character è¨
+U+8a0f Xu # Character è¨
+U+8a10 Jie # Character è¨
+U+8a11 Yi # Character è¨
+U+8a12 Ren # Character è¨
+U+8a13 Xun # Character è¨
+U+8a14 Yin # Character è¨
+U+8a15 Shan # Character è¨
+U+8a16 Qi # Character è¨
+U+8a17 Tuo # Character è¨
+U+8a18 Ji # Character è¨
+U+8a19 Xun # Character è¨
+U+8a1a Yin # Character è¨
+U+8a1b E # Character è¨
+U+8a1c Fen # Character è¨
+U+8a1d Ya # Character è¨
+U+8a1e Yao # Character è¨
+U+8a1f Song # Character è¨
+U+8a20 Shen # Character è¨
+U+8a21 Yin # Character 訡
+U+8a22 Xin # Character 訢
+U+8a23 Jue # Character 訣
+U+8a24 Xiao # Character 訤
+U+8a25 Ne # Character 訥
+U+8a26 Chen # Character 訦
+U+8a27 You # Character 訧
+U+8a28 Zhi # Character 訨
+U+8a29 Xiong # Character 訩
+U+8a2a Fang # Character 訪
+U+8a2b Xin # Character 訫
+U+8a2c Chao # Character 訬
+U+8a2d She # Character è¨
+U+8a2e Xian # Character 訮
+U+8a2f Sha # Character 訯
+U+8a30 Tun # Character 訰
+U+8a31 Xu # Character 許
+U+8a32 Yi # Character 訲
+U+8a33 Yi # Character 訳
+U+8a34 Su # Character 訴
+U+8a35 Chi # Character 訵
+U+8a36 He # Character 訶
+U+8a37 Shen # Character 訷
+U+8a38 He # Character 訸
+U+8a39 Xu # Character 訹
+U+8a3a Zhen # Character 診
+U+8a3b Zhu # Character 註
+U+8a3c Zheng # Character 証
+U+8a3d Gou # Character 訽
+U+8a3e Zi # Character 訾
+U+8a3f Zi # Character 訿
+U+8a40 Zhan # Character è©
+U+8a41 Gu # Character è©
+U+8a42 Fu # Character è©
+U+8a43 Quan # Character è©
+U+8a44 Die # Character è©
+U+8a45 Ling # Character è©
+U+8a46 Di # Character è©
+U+8a47 Yang # Character è©
+U+8a48 Li # Character è©
+U+8a49 Nao # Character è©
+U+8a4a Pan # Character è©
+U+8a4b Zhou # Character è©
+U+8a4c Gan # Character è©
+U+8a4d Yi # Character è©
+U+8a4e Ju # Character è©
+U+8a4f Ao # Character è©
+U+8a50 Zha # Character è©
+U+8a51 Tuo # Character è©
+U+8a52 Yi # Character è©
+U+8a53 Qu # Character è©
+U+8a54 Zhao # Character è©
+U+8a55 Ping # Character è©
+U+8a56 Bi # Character è©
+U+8a57 Xiong # Character è©
+U+8a58 Qu # Character è©
+U+8a59 Ba # Character è©
+U+8a5a Da # Character è©
+U+8a5b Zu # Character è©
+U+8a5c Tao # Character è©
+U+8a5d Zhu # Character è©
+U+8a5e Ci # Character è©
+U+8a5f Zhe # Character è©
+U+8a60 Yong # Character è©
+U+8a61 Xu # Character è©¡
+U+8a62 Xun # Character è©¢
+U+8a63 Yi # Character è©£
+U+8a64 Huang # Character 詤
+U+8a65 He # Character è©¥
+U+8a66 Shi # Character 試
+U+8a67 Cha # Character 詧
+U+8a68 Jiao # Character 詨
+U+8a69 Shi # Character è©©
+U+8a6a Hen # Character 詪
+U+8a6b Cha # Character è©«
+U+8a6c Gou # Character 詬
+U+8a6d Gui # Character è©
+U+8a6e Quan # Character è©®
+U+8a6f Hui # Character 詯
+U+8a70 Jie # Character è©°
+U+8a71 Hua # Character 話
+U+8a72 Gai # Character 該
+U+8a73 Xiang # Character 詳
+U+8a74 Wei # Character è©´
+U+8a75 Shen # Character 詵
+U+8a76 Chou # Character 詶
+U+8a77 Tong # Character è©·
+U+8a78 Mi # Character 詸
+U+8a79 Zhan # Character 詹
+U+8a7a Ming # Character 詺
+U+8a7b E # Character è©»
+U+8a7c Hui # Character 詼
+U+8a7d Yan # Character 詽
+U+8a7e Xiong # Character 詾
+U+8a7f Gua # Character è©¿
+U+8a80 Er # Character èª
+U+8a81 Beng # Character èª
+U+8a82 Tiao # Character èª
+U+8a83 Chi # Character èª
+U+8a84 Lei # Character èª
+U+8a85 Zhu # Character èª
+U+8a86 Kuang # Character èª
+U+8a87 Kua # Character èª
+U+8a88 Wu # Character èª
+U+8a89 Yu # Character èª
+U+8a8a Teng # Character èª
+U+8a8b Ji # Character èª
+U+8a8c Zhi # Character èª
+U+8a8d Ren # Character èª
+U+8a8e Su # Character èª
+U+8a8f Lang # Character èª
+U+8a90 E # Character èª
+U+8a91 Kuang # Character èª
+U+8a92 E # Character èª
+U+8a93 Shi # Character èª
+U+8a94 Ting # Character èª
+U+8a95 Dan # Character èª
+U+8a96 Bo # Character èª
+U+8a97 Chan # Character èª
+U+8a98 You # Character èª
+U+8a99 Heng # Character èª
+U+8a9a Qiao # Character èª
+U+8a9b Qin # Character èª
+U+8a9c Shua # Character èª
+U+8a9d An # Character èª
+U+8a9e Yu # Character èª
+U+8a9f Xiao # Character èª
+U+8aa0 Cheng # Character èª
+U+8aa1 Jie # Character 誡
+U+8aa2 Xian # Character 誢
+U+8aa3 Wu # Character 誣
+U+8aa4 Wu # Character 誤
+U+8aa5 Gao # Character 誥
+U+8aa6 Song # Character 誦
+U+8aa7 Pu # Character 誧
+U+8aa8 Hui # Character 誨
+U+8aa9 Jing # Character 誩
+U+8aaa Shuo # Character 說
+U+8aab Zhen # Character 誫
+U+8aac Shuo # Character 説
+U+8aad Du # Character èª
+U+8aae Yasashi # Character 誮
+U+8aaf Chang # Character 誯
+U+8ab0 Shui # Character 誰
+U+8ab1 Jie # Character 誱
+U+8ab2 Ke # Character 課
+U+8ab3 Qu # Character 誳
+U+8ab4 Cong # Character 誴
+U+8ab5 Xiao # Character 誵
+U+8ab6 Sui # Character 誶
+U+8ab7 Wang # Character 誷
+U+8ab8 Xuan # Character 誸
+U+8ab9 Fei # Character 誹
+U+8aba Chi # Character 誺
+U+8abb Ta # Character 誻
+U+8abc Yi # Character 誼
+U+8abd Na # Character 誽
+U+8abe Yin # Character 誾
+U+8abf Diao # Character 調
+U+8ac0 Pi # Character è«
+U+8ac1 Chuo # Character è«
+U+8ac2 Chan # Character è«
+U+8ac3 Chen # Character è«
+U+8ac4 Zhun # Character è«
+U+8ac5 Ji # Character è«
+U+8ac6 Qi # Character è«
+U+8ac7 Tan # Character è«
+U+8ac8 Zhui # Character è«
+U+8ac9 Wei # Character è«
+U+8aca Ju # Character è«
+U+8acb Qing # Character è«
+U+8acc Jian # Character è«
+U+8acd Zheng # Character è«
+U+8ace Ze # Character è«
+U+8acf Zou # Character è«
+U+8ad0 Qian # Character è«
+U+8ad1 Zhuo # Character è«
+U+8ad2 Liang # Character è«
+U+8ad3 Jian # Character è«
+U+8ad4 Zhu # Character è«
+U+8ad5 Hao # Character è«
+U+8ad6 Lun # Character è«
+U+8ad7 Shen # Character è«
+U+8ad8 Biao # Character è«
+U+8ad9 Huai # Character è«
+U+8ada Pian # Character è«
+U+8adb Yu # Character è«
+U+8adc Die # Character è«
+U+8add Xu # Character è«
+U+8ade Pian # Character è«
+U+8adf Shi # Character è«
+U+8ae0 Xuan # Character è«
+U+8ae1 Shi # Character è«¡
+U+8ae2 Hun # Character è«¢
+U+8ae3 Hua # Character è«£
+U+8ae4 E # Character 諤
+U+8ae5 Zhong # Character è«¥
+U+8ae6 Di # Character 諦
+U+8ae7 Xie # Character 諧
+U+8ae8 Fu # Character 諨
+U+8ae9 Pu # Character è«©
+U+8aea Ting # Character 諪
+U+8aeb Jian # Character è««
+U+8aec Qi # Character 諬
+U+8aed Yu # Character è«
+U+8aee Zi # Character è«®
+U+8aef Chuan # Character 諯
+U+8af0 Xi # Character è«°
+U+8af1 Hui # Character 諱
+U+8af2 Yin # Character 諲
+U+8af3 An # Character 諳
+U+8af4 Xian # Character è«´
+U+8af5 Nan # Character 諵
+U+8af6 Chen # Character 諶
+U+8af7 Feng # Character è«·
+U+8af8 Zhu # Character 諸
+U+8af9 Yang # Character 諹
+U+8afa Yan # Character 諺
+U+8afb Heng # Character è«»
+U+8afc Xuan # Character 諼
+U+8afd Ge # Character 諽
+U+8afe Nuo # Character 諾
+U+8aff Qi # Character è«¿
diff --git a/resources/chars/ascii/row8b.trans b/resources/chars/ascii/row8b.trans
new file mode 100644
index 0000000..1d1eb88
--- /dev/null
+++ b/resources/chars/ascii/row8b.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+8b00 Mou # Character è¬
+U+8b01 Ye # Character è¬
+U+8b02 Wei # Character è¬
+U+8b03 ? # Character è¬
+U+8b04 Teng # Character è¬
+U+8b05 Zou # Character è¬
+U+8b06 Shan # Character è¬
+U+8b07 Jian # Character è¬
+U+8b08 Bo # Character è¬
+U+8b09 Ku # Character è¬
+U+8b0a Huang # Character è¬
+U+8b0b Huo # Character è¬
+U+8b0c Ge # Character è¬
+U+8b0d Ying # Character è¬
+U+8b0e Mi # Character è¬
+U+8b0f Xiao # Character è¬
+U+8b10 Mi # Character è¬
+U+8b11 Xi # Character è¬
+U+8b12 Qiang # Character è¬
+U+8b13 Chen # Character è¬
+U+8b14 Nue # Character è¬
+U+8b15 Ti # Character è¬
+U+8b16 Su # Character è¬
+U+8b17 Bang # Character è¬
+U+8b18 Chi # Character è¬
+U+8b19 Qian # Character è¬
+U+8b1a Shi # Character è¬
+U+8b1b Jiang # Character è¬
+U+8b1c Yuan # Character è¬
+U+8b1d Xie # Character è¬
+U+8b1e Xue # Character è¬
+U+8b1f Tao # Character è¬
+U+8b20 Yao # Character è¬
+U+8b21 Yao # Character 謡
+U+8b22 ? # Character 謢
+U+8b23 Yu # Character 謣
+U+8b24 Biao # Character 謤
+U+8b25 Cong # Character 謥
+U+8b26 Qing # Character 謦
+U+8b27 Li # Character 謧
+U+8b28 Mo # Character 謨
+U+8b29 Mo # Character 謩
+U+8b2a Shang # Character 謪
+U+8b2b Zhe # Character 謫
+U+8b2c Miu # Character 謬
+U+8b2d Jian # Character è¬
+U+8b2e Ze # Character 謮
+U+8b2f Jie # Character 謯
+U+8b30 Lian # Character 謰
+U+8b31 Lou # Character 謱
+U+8b32 Can # Character 謲
+U+8b33 Ou # Character 謳
+U+8b34 Guan # Character 謴
+U+8b35 Xi # Character 謵
+U+8b36 Zhuo # Character 謶
+U+8b37 Ao # Character 謷
+U+8b38 Ao # Character 謸
+U+8b39 Jin # Character 謹
+U+8b3a Zhe # Character 謺
+U+8b3b Yi # Character 謻
+U+8b3c Hu # Character 謼
+U+8b3d Jiang # Character 謽
+U+8b3e Man # Character 謾
+U+8b3f Chao # Character 謿
+U+8b40 Han # Character è
+U+8b41 Hua # Character è
+U+8b42 Chan # Character è
+U+8b43 Xu # Character è
+U+8b44 Zeng # Character è
+U+8b45 Se # Character è
+U+8b46 Xi # Character è
+U+8b47 She # Character è
+U+8b48 Dui # Character è
+U+8b49 Zheng # Character è
+U+8b4a Nao # Character è
+U+8b4b Lan # Character è
+U+8b4c E # Character è
+U+8b4d Ying # Character è
+U+8b4e Jue # Character è
+U+8b4f Ji # Character è
+U+8b50 Zun # Character è
+U+8b51 Jiao # Character è
+U+8b52 Bo # Character è
+U+8b53 Hui # Character è
+U+8b54 Zhuan # Character è
+U+8b55 Mu # Character è
+U+8b56 Zen # Character è
+U+8b57 Zha # Character è
+U+8b58 Shi # Character è
+U+8b59 Qiao # Character è
+U+8b5a Tan # Character è
+U+8b5b Zen # Character è
+U+8b5c Pu # Character è
+U+8b5d Sheng # Character è
+U+8b5e Xuan # Character è
+U+8b5f Zao # Character è
+U+8b60 Tan # Character è
+U+8b61 Dang # Character è¡
+U+8b62 Sui # Character è¢
+U+8b63 Qian # Character è£
+U+8b64 Ji # Character è¤
+U+8b65 Jiao # Character è¥
+U+8b66 Jing # Character è¦
+U+8b67 Lian # Character è§
+U+8b68 Nou # Character è¨
+U+8b69 Yi # Character è©
+U+8b6a Ai # Character èª
+U+8b6b Zhan # Character è«
+U+8b6c Pi # Character è¬
+U+8b6d Hui # Character è
+U+8b6e Hua # Character è®
+U+8b6f Yi # Character è¯
+U+8b70 Yi # Character è°
+U+8b71 Shan # Character è±
+U+8b72 Rang # Character è²
+U+8b73 Nou # Character è³
+U+8b74 Qian # Character è´
+U+8b75 Zhui # Character èµ
+U+8b76 Ta # Character è¶
+U+8b77 Hu # Character è·
+U+8b78 Zhou # Character è¸
+U+8b79 Hao # Character è¹
+U+8b7a Ye # Character èº
+U+8b7b Ying # Character è»
+U+8b7c Jian # Character è¼
+U+8b7d Yu # Character è½
+U+8b7e Jian # Character è¾
+U+8b7f Hui # Character è¿
+U+8b80 Du # Character è®
+U+8b81 Zhe # Character è®
+U+8b82 Xuan # Character è®
+U+8b83 Zan # Character è®
+U+8b84 Lei # Character è®
+U+8b85 Shen # Character è®
+U+8b86 Wei # Character è®
+U+8b87 Chan # Character è®
+U+8b88 Li # Character è®
+U+8b89 Yi # Character è®
+U+8b8a Bian # Character è®
+U+8b8b Zhe # Character è®
+U+8b8c Yan # Character è®
+U+8b8d E # Character è®
+U+8b8e Chou # Character è®
+U+8b8f Wei # Character è®
+U+8b90 Chou # Character è®
+U+8b91 Yao # Character è®
+U+8b92 Chan # Character è®
+U+8b93 Rang # Character è®
+U+8b94 Yin # Character è®
+U+8b95 Lan # Character è®
+U+8b96 Chen # Character è®
+U+8b97 Huo # Character è®
+U+8b98 Zhe # Character è®
+U+8b99 Huan # Character è®
+U+8b9a Zan # Character è®
+U+8b9b Yi # Character è®
+U+8b9c Dang # Character è®
+U+8b9d Zhan # Character è®
+U+8b9e Yan # Character è®
+U+8b9f Du # Character è®
+U+8ba0 Yan # Character è®
+U+8ba1 Ji # Character 计
+U+8ba2 Ding # Character 订
+U+8ba3 Fu # Character 讣
+U+8ba4 Ren # Character 认
+U+8ba5 Ji # Character 讥
+U+8ba6 Jie # Character 讦
+U+8ba7 Hong # Character 讧
+U+8ba8 Tao # Character 讨
+U+8ba9 Rang # Character 让
+U+8baa Shan # Character 讪
+U+8bab Qi # Character 讫
+U+8bac Tuo # Character 讬
+U+8bad Xun # Character è®
+U+8bae Yi # Character è®®
+U+8baf Xun # Character 讯
+U+8bb0 Ji # Character è®°
+U+8bb1 Ren # Character è®±
+U+8bb2 Jiang # Character 讲
+U+8bb3 Hui # Character 讳
+U+8bb4 Ou # Character è®´
+U+8bb5 Ju # Character 讵
+U+8bb6 Ya # Character 讶
+U+8bb7 Ne # Character è®·
+U+8bb8 Xu # Character 许
+U+8bb9 E # Character 讹
+U+8bba Lun # Character 论
+U+8bbb Xiong # Character è®»
+U+8bbc Song # Character 讼
+U+8bbd Feng # Character 讽
+U+8bbe She # Character 设
+U+8bbf Fang # Character 访
+U+8bc0 Jue # Character è¯
+U+8bc1 Zheng # Character è¯
+U+8bc2 Gu # Character è¯
+U+8bc3 He # Character è¯
+U+8bc4 Ping # Character è¯
+U+8bc5 Zu # Character è¯
+U+8bc6 Shi # Character è¯
+U+8bc7 Xiong # Character è¯
+U+8bc8 Zha # Character è¯
+U+8bc9 Su # Character è¯
+U+8bca Zhen # Character è¯
+U+8bcb Di # Character è¯
+U+8bcc Zou # Character è¯
+U+8bcd Ci # Character è¯
+U+8bce Qu # Character è¯
+U+8bcf Zhao # Character è¯
+U+8bd0 Bi # Character è¯
+U+8bd1 Yi # Character è¯
+U+8bd2 Yi # Character è¯
+U+8bd3 Kuang # Character è¯
+U+8bd4 Lei # Character è¯
+U+8bd5 Shi # Character è¯
+U+8bd6 Gua # Character è¯
+U+8bd7 Shi # Character è¯
+U+8bd8 Jie # Character è¯
+U+8bd9 Hui # Character è¯
+U+8bda Cheng # Character è¯
+U+8bdb Zhu # Character è¯
+U+8bdc Shen # Character è¯
+U+8bdd Hua # Character è¯
+U+8bde Dan # Character è¯
+U+8bdf Gou # Character è¯
+U+8be0 Quan # Character è¯
+U+8be1 Gui # Character 诡
+U+8be2 Xun # Character 询
+U+8be3 Yi # Character 诣
+U+8be4 Zheng # Character 诤
+U+8be5 Gai # Character 该
+U+8be6 Xiang # Character 详
+U+8be7 Cha # Character 诧
+U+8be8 Hun # Character 诨
+U+8be9 Xu # Character 诩
+U+8bea Zhou # Character 诪
+U+8beb Jie # Character 诫
+U+8bec Wu # Character 诬
+U+8bed Yu # Character è¯
+U+8bee Qiao # Character 诮
+U+8bef Wu # Character 误
+U+8bf0 Gao # Character 诰
+U+8bf1 You # Character 诱
+U+8bf2 Hui # Character 诲
+U+8bf3 Kuang # Character 诳
+U+8bf4 Shuo # Character 说
+U+8bf5 Song # Character 诵
+U+8bf6 Ai # Character 诶
+U+8bf7 Qing # Character 请
+U+8bf8 Zhu # Character 诸
+U+8bf9 Zou # Character 诹
+U+8bfa Nuo # Character 诺
+U+8bfb Du # Character 读
+U+8bfc Zhuo # Character 诼
+U+8bfd Fei # Character 诽
+U+8bfe Ke # Character 课
+U+8bff Wei # Character 诿
diff --git a/resources/chars/ascii/row8c.trans b/resources/chars/ascii/row8c.trans
new file mode 100644
index 0000000..80070b1
--- /dev/null
+++ b/resources/chars/ascii/row8c.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+8c00 Yu # Character è°
+U+8c01 Shui # Character è°
+U+8c02 Shen # Character è°
+U+8c03 Diao # Character è°
+U+8c04 Chan # Character è°
+U+8c05 Liang # Character è°
+U+8c06 Zhun # Character è°
+U+8c07 Sui # Character è°
+U+8c08 Tan # Character è°
+U+8c09 Shen # Character è°
+U+8c0a Yi # Character è°
+U+8c0b Mou # Character è°
+U+8c0c Chen # Character è°
+U+8c0d Die # Character è°
+U+8c0e Huang # Character è°
+U+8c0f Jian # Character è°
+U+8c10 Xie # Character è°
+U+8c11 Nue # Character è°
+U+8c12 Ye # Character è°
+U+8c13 Wei # Character è°
+U+8c14 E # Character è°
+U+8c15 Yu # Character è°
+U+8c16 Xuan # Character è°
+U+8c17 Chan # Character è°
+U+8c18 Zi # Character è°
+U+8c19 An # Character è°
+U+8c1a Yan # Character è°
+U+8c1b Di # Character è°
+U+8c1c Mi # Character è°
+U+8c1d Pian # Character è°
+U+8c1e Xu # Character è°
+U+8c1f Mo # Character è°
+U+8c20 Dang # Character è°
+U+8c21 Su # Character è°¡
+U+8c22 Xie # Character è°¢
+U+8c23 Yao # Character è°£
+U+8c24 Bang # Character è°¤
+U+8c25 Shi # Character è°¥
+U+8c26 Qian # Character è°¦
+U+8c27 Mi # Character è°§
+U+8c28 Jin # Character è°¨
+U+8c29 Man # Character è°©
+U+8c2a Zhe # Character è°ª
+U+8c2b Jian # Character è°«
+U+8c2c Miu # Character è°¬
+U+8c2d Tan # Character è°
+U+8c2e Zen # Character è°®
+U+8c2f Qiao # Character è°¯
+U+8c30 Lan # Character è°°
+U+8c31 Pu # Character è°±
+U+8c32 Jue # Character è°²
+U+8c33 Yan # Character è°³
+U+8c34 Qian # Character è°´
+U+8c35 Zhan # Character è°µ
+U+8c36 Chen # Character è°¶
+U+8c37 Gu # Character è°·
+U+8c38 Qian # Character è°¸
+U+8c39 Hong # Character è°¹
+U+8c3a Xia # Character è°º
+U+8c3b Jue # Character è°»
+U+8c3c Hong # Character è°¼
+U+8c3d Han # Character è°½
+U+8c3e Hong # Character è°¾
+U+8c3f Xi # Character è°¿
+U+8c40 Xi # Character è±
+U+8c41 Huo # Character è±
+U+8c42 Liao # Character è±
+U+8c43 Han # Character è±
+U+8c44 Du # Character è±
+U+8c45 Long # Character è±
+U+8c46 Dou # Character è±
+U+8c47 Jiang # Character è±
+U+8c48 Qi # Character è±
+U+8c49 Shi # Character è±
+U+8c4a Li # Character è±
+U+8c4b Deng # Character è±
+U+8c4c Wan # Character è±
+U+8c4d Bi # Character è±
+U+8c4e Shu # Character è±
+U+8c4f Xian # Character è±
+U+8c50 Feng # Character è±
+U+8c51 Zhi # Character è±
+U+8c52 Zhi # Character è±
+U+8c53 Yan # Character è±
+U+8c54 Yan # Character è±
+U+8c55 Shi # Character è±
+U+8c56 Chu # Character è±
+U+8c57 Hui # Character è±
+U+8c58 Tun # Character è±
+U+8c59 Yi # Character è±
+U+8c5a Tun # Character è±
+U+8c5b Yi # Character è±
+U+8c5c Jian # Character è±
+U+8c5d Ba # Character è±
+U+8c5e Hou # Character è±
+U+8c5f E # Character è±
+U+8c60 Cu # Character è±
+U+8c61 Xiang # Character 象
+U+8c62 Huan # Character è±¢
+U+8c63 Jian # Character è±£
+U+8c64 Ken # Character 豤
+U+8c65 Gai # Character è±¥
+U+8c66 Qu # Character 豦
+U+8c67 Fu # Character 豧
+U+8c68 Xi # Character 豨
+U+8c69 Bin # Character 豩
+U+8c6a Hao # Character 豪
+U+8c6b Yu # Character 豫
+U+8c6c Zhu # Character 豬
+U+8c6d Jia # Character è±
+U+8c6e ? # Character è±®
+U+8c6f Xi # Character 豯
+U+8c70 Bo # Character è±°
+U+8c71 Wen # Character è±±
+U+8c72 Huan # Character è±²
+U+8c73 Bin # Character è±³
+U+8c74 Di # Character è±´
+U+8c75 Zong # Character è±µ
+U+8c76 Fen # Character 豶
+U+8c77 Yi # Character è±·
+U+8c78 Zhi # Character 豸
+U+8c79 Bao # Character è±¹
+U+8c7a Chai # Character 豺
+U+8c7b Han # Character è±»
+U+8c7c Pi # Character è±¼
+U+8c7d Na # Character è±½
+U+8c7e Pi # Character è±¾
+U+8c7f Gou # Character 豿
+U+8c80 Na # Character è²
+U+8c81 You # Character è²
+U+8c82 Diao # Character è²
+U+8c83 Mo # Character è²
+U+8c84 Si # Character è²
+U+8c85 Xiu # Character è²
+U+8c86 Huan # Character è²
+U+8c87 Kun # Character è²
+U+8c88 He # Character è²
+U+8c89 He # Character è²
+U+8c8a Mo # Character è²
+U+8c8b Han # Character è²
+U+8c8c Mao # Character è²
+U+8c8d Li # Character è²
+U+8c8e Ni # Character è²
+U+8c8f Bi # Character è²
+U+8c90 Yu # Character è²
+U+8c91 Jia # Character è²
+U+8c92 Tuan # Character è²
+U+8c93 Mao # Character è²
+U+8c94 Pi # Character è²
+U+8c95 Xi # Character è²
+U+8c96 E # Character è²
+U+8c97 Ju # Character è²
+U+8c98 Mo # Character è²
+U+8c99 Chu # Character è²
+U+8c9a Tan # Character è²
+U+8c9b Huan # Character è²
+U+8c9c Jue # Character è²
+U+8c9d Bei # Character è²
+U+8c9e Zhen # Character è²
+U+8c9f Yuan # Character è²
+U+8ca0 Fu # Character è²
+U+8ca1 Cai # Character 財
+U+8ca2 Gong # Character è²¢
+U+8ca3 Te # Character è²£
+U+8ca4 Yi # Character 貤
+U+8ca5 Hang # Character è²¥
+U+8ca6 Wan # Character 貦
+U+8ca7 Pin # Character 貧
+U+8ca8 Huo # Character 貨
+U+8ca9 Fan # Character 販
+U+8caa Tan # Character 貪
+U+8cab Guan # Character 貫
+U+8cac Ze # Character 責
+U+8cad Zhi # Character è²
+U+8cae Er # Character è²®
+U+8caf Zhu # Character 貯
+U+8cb0 Shi # Character è²°
+U+8cb1 Bi # Character è²±
+U+8cb2 Zi # Character è²²
+U+8cb3 Er # Character è²³
+U+8cb4 Gui # Character è²´
+U+8cb5 Pian # Character è²µ
+U+8cb6 Bian # Character 貶
+U+8cb7 Mai # Character è²·
+U+8cb8 Dai # Character 貸
+U+8cb9 Sheng # Character è²¹
+U+8cba Kuang # Character 貺
+U+8cbb Fei # Character è²»
+U+8cbc Tie # Character è²¼
+U+8cbd Yi # Character è²½
+U+8cbe Chi # Character è²¾
+U+8cbf Mao # Character 貿
+U+8cc0 He # Character è³
+U+8cc1 Bi # Character è³
+U+8cc2 Lu # Character è³
+U+8cc3 Ren # Character è³
+U+8cc4 Hui # Character è³
+U+8cc5 Gai # Character è³
+U+8cc6 Pian # Character è³
+U+8cc7 Zi # Character è³
+U+8cc8 Jia # Character è³
+U+8cc9 Xu # Character è³
+U+8cca Zei # Character è³
+U+8ccb Jiao # Character è³
+U+8ccc Gai # Character è³
+U+8ccd Zang # Character è³
+U+8cce Jian # Character è³
+U+8ccf Ying # Character è³
+U+8cd0 Xun # Character è³
+U+8cd1 Zhen # Character è³
+U+8cd2 She # Character è³
+U+8cd3 Bin # Character è³
+U+8cd4 Bin # Character è³
+U+8cd5 Qiu # Character è³
+U+8cd6 She # Character è³
+U+8cd7 Chuan # Character è³
+U+8cd8 Zang # Character è³
+U+8cd9 Zhou # Character è³
+U+8cda Lai # Character è³
+U+8cdb Zan # Character è³
+U+8cdc Si # Character è³
+U+8cdd Chen # Character è³
+U+8cde Shang # Character è³
+U+8cdf Tian # Character è³
+U+8ce0 Pei # Character è³
+U+8ce1 Geng # Character 賡
+U+8ce2 Xian # Character è³¢
+U+8ce3 Mai # Character è³£
+U+8ce4 Jian # Character 賤
+U+8ce5 Sui # Character è³¥
+U+8ce6 Fu # Character 賦
+U+8ce7 Tan # Character 賧
+U+8ce8 Cong # Character 賨
+U+8ce9 Cong # Character 賩
+U+8cea Zhi # Character 質
+U+8ceb Ji # Character 賫
+U+8cec Zhang # Character 賬
+U+8ced Du # Character è³
+U+8cee Jin # Character è³®
+U+8cef Xiong # Character 賯
+U+8cf0 Shun # Character è³°
+U+8cf1 Yun # Character è³±
+U+8cf2 Bao # Character è³²
+U+8cf3 Zai # Character è³³
+U+8cf4 Lai # Character è³´
+U+8cf5 Feng # Character è³µ
+U+8cf6 Cang # Character 賶
+U+8cf7 Ji # Character è³·
+U+8cf8 Sheng # Character 賸
+U+8cf9 Ai # Character è³¹
+U+8cfa Zhuan # Character 賺
+U+8cfb Fu # Character è³»
+U+8cfc Gou # Character è³¼
+U+8cfd Sai # Character è³½
+U+8cfe Ze # Character è³¾
+U+8cff Liao # Character 賿
diff --git a/resources/chars/ascii/row8d.trans b/resources/chars/ascii/row8d.trans
new file mode 100644
index 0000000..197b323
--- /dev/null
+++ b/resources/chars/ascii/row8d.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+8d00 Wei # Character è´
+U+8d01 Bai # Character è´
+U+8d02 Chen # Character è´
+U+8d03 Zhuan # Character è´
+U+8d04 Zhi # Character è´
+U+8d05 Zhui # Character è´
+U+8d06 Biao # Character è´
+U+8d07 Yun # Character è´
+U+8d08 Zeng # Character è´
+U+8d09 Tan # Character è´
+U+8d0a Zan # Character è´
+U+8d0b Yan # Character è´
+U+8d0c ? # Character è´
+U+8d0d Shan # Character è´
+U+8d0e Wan # Character è´
+U+8d0f Ying # Character è´
+U+8d10 Jin # Character è´
+U+8d11 Gan # Character è´
+U+8d12 Xian # Character è´
+U+8d13 Zang # Character è´
+U+8d14 Bi # Character è´
+U+8d15 Du # Character è´
+U+8d16 Shu # Character è´
+U+8d17 Yan # Character è´
+U+8d18 ? # Character è´
+U+8d19 Xuan # Character è´
+U+8d1a Long # Character è´
+U+8d1b Gan # Character è´
+U+8d1c Zang # Character è´
+U+8d1d Bei # Character è´
+U+8d1e Zhen # Character è´
+U+8d1f Fu # Character è´
+U+8d20 Yuan # Character è´
+U+8d21 Gong # Character è´¡
+U+8d22 Cai # Character è´¢
+U+8d23 Ze # Character è´£
+U+8d24 Xian # Character è´¤
+U+8d25 Bai # Character è´¥
+U+8d26 Zhang # Character è´¦
+U+8d27 Huo # Character è´§
+U+8d28 Zhi # Character è´¨
+U+8d29 Fan # Character è´©
+U+8d2a Tan # Character è´ª
+U+8d2b Pin # Character è´«
+U+8d2c Bian # Character è´¬
+U+8d2d Gou # Character è´
+U+8d2e Zhu # Character è´®
+U+8d2f Guan # Character è´¯
+U+8d30 Er # Character è´°
+U+8d31 Jian # Character è´±
+U+8d32 Bi # Character è´²
+U+8d33 Shi # Character è´³
+U+8d34 Tie # Character è´´
+U+8d35 Gui # Character è´µ
+U+8d36 Kuang # Character è´¶
+U+8d37 Dai # Character è´·
+U+8d38 Mao # Character è´¸
+U+8d39 Fei # Character è´¹
+U+8d3a He # Character è´º
+U+8d3b Yi # Character è´»
+U+8d3c Zei # Character è´¼
+U+8d3d Zhi # Character è´½
+U+8d3e Jia # Character è´¾
+U+8d3f Hui # Character è´¿
+U+8d40 Zi # Character èµ
+U+8d41 Ren # Character èµ
+U+8d42 Lu # Character èµ
+U+8d43 Zang # Character èµ
+U+8d44 Zi # Character èµ
+U+8d45 Gai # Character èµ
+U+8d46 Jin # Character èµ
+U+8d47 Qiu # Character èµ
+U+8d48 Zhen # Character èµ
+U+8d49 Lai # Character èµ
+U+8d4a She # Character èµ
+U+8d4b Fu # Character èµ
+U+8d4c Du # Character èµ
+U+8d4d Ji # Character èµ
+U+8d4e Shu # Character èµ
+U+8d4f Shang # Character èµ
+U+8d50 Si # Character èµ
+U+8d51 Bi # Character èµ
+U+8d52 Zhou # Character èµ
+U+8d53 Geng # Character èµ
+U+8d54 Pei # Character èµ
+U+8d55 Tan # Character èµ
+U+8d56 Lai # Character èµ
+U+8d57 Feng # Character èµ
+U+8d58 Zhui # Character èµ
+U+8d59 Fu # Character èµ
+U+8d5a Zhuan # Character èµ
+U+8d5b Sai # Character èµ
+U+8d5c Ze # Character èµ
+U+8d5d Yan # Character èµ
+U+8d5e Zan # Character èµ
+U+8d5f Yun # Character èµ
+U+8d60 Zeng # Character èµ
+U+8d61 Shan # Character 赡
+U+8d62 Ying # Character èµ¢
+U+8d63 Gan # Character èµ£
+U+8d64 Chi # Character 赤
+U+8d65 Xi # Character èµ¥
+U+8d66 She # Character 赦
+U+8d67 Nan # Character 赧
+U+8d68 Xiong # Character 赨
+U+8d69 Xi # Character 赩
+U+8d6a Cheng # Character 赪
+U+8d6b He # Character 赫
+U+8d6c Cheng # Character 赬
+U+8d6d Zhe # Character èµ
+U+8d6e Xia # Character èµ®
+U+8d6f Tang # Character 赯
+U+8d70 Zou # Character èµ°
+U+8d71 Zou # Character èµ±
+U+8d72 Li # Character èµ²
+U+8d73 Jiu # Character èµ³
+U+8d74 Fu # Character èµ´
+U+8d75 Zhao # Character èµµ
+U+8d76 Gan # Character 赶
+U+8d77 Qi # Character èµ·
+U+8d78 Shan # Character 赸
+U+8d79 Qiong # Character èµ¹
+U+8d7a Qin # Character 赺
+U+8d7b Xian # Character èµ»
+U+8d7c Ci # Character èµ¼
+U+8d7d Jue # Character èµ½
+U+8d7e Qin # Character èµ¾
+U+8d7f Chi # Character 赿
+U+8d80 Ci # Character è¶
+U+8d81 Chen # Character è¶
+U+8d82 Chen # Character è¶
+U+8d83 Die # Character è¶
+U+8d84 Ju # Character è¶
+U+8d85 Chao # Character è¶
+U+8d86 Di # Character è¶
+U+8d87 Se # Character è¶
+U+8d88 Zhan # Character è¶
+U+8d89 Zhu # Character è¶
+U+8d8a Yue # Character è¶
+U+8d8b Qu # Character è¶
+U+8d8c Jie # Character è¶
+U+8d8d Chi # Character è¶
+U+8d8e Chu # Character è¶
+U+8d8f Gua # Character è¶
+U+8d90 Xue # Character è¶
+U+8d91 Ci # Character è¶
+U+8d92 Tiao # Character è¶
+U+8d93 Duo # Character è¶
+U+8d94 Lie # Character è¶
+U+8d95 Gan # Character è¶
+U+8d96 Suo # Character è¶
+U+8d97 Cu # Character è¶
+U+8d98 Xi # Character è¶
+U+8d99 Zhao # Character è¶
+U+8d9a Su # Character è¶
+U+8d9b Yin # Character è¶
+U+8d9c Ju # Character è¶
+U+8d9d Jian # Character è¶
+U+8d9e Que # Character è¶
+U+8d9f Tang # Character è¶
+U+8da0 Chuo # Character è¶
+U+8da1 Cui # Character 趡
+U+8da2 Lu # Character 趢
+U+8da3 Qu # Character 趣
+U+8da4 Dang # Character 趤
+U+8da5 Qiu # Character 趥
+U+8da6 Zi # Character 趦
+U+8da7 Ti # Character 趧
+U+8da8 Qu # Character 趨
+U+8da9 Chi # Character 趩
+U+8daa Huang # Character 趪
+U+8dab Qiao # Character 趫
+U+8dac Qiao # Character 趬
+U+8dad Yao # Character è¶
+U+8dae Zao # Character 趮
+U+8daf Ti # Character 趯
+U+8db0 ? # Character 趰
+U+8db1 Zan # Character 趱
+U+8db2 Zan # Character 趲
+U+8db3 Zu # Character 足
+U+8db4 Pa # Character 趴
+U+8db5 Bao # Character 趵
+U+8db6 Ku # Character 趶
+U+8db7 Ke # Character 趷
+U+8db8 Dun # Character 趸
+U+8db9 Jue # Character 趹
+U+8dba Fu # Character 趺
+U+8dbb Chen # Character 趻
+U+8dbc Jian # Character 趼
+U+8dbd Fang # Character 趽
+U+8dbe Zhi # Character 趾
+U+8dbf Sa # Character 趿
+U+8dc0 Yue # Character è·
+U+8dc1 Pa # Character è·
+U+8dc2 Qi # Character è·
+U+8dc3 Yue # Character è·
+U+8dc4 Qiang # Character è·
+U+8dc5 Tuo # Character è·
+U+8dc6 Tai # Character è·
+U+8dc7 Yi # Character è·
+U+8dc8 Nian # Character è·
+U+8dc9 Ling # Character è·
+U+8dca Mei # Character è·
+U+8dcb Ba # Character è·
+U+8dcc Die # Character è·
+U+8dcd Ku # Character è·
+U+8dce Tuo # Character è·
+U+8dcf Jia # Character è·
+U+8dd0 Ci # Character è·
+U+8dd1 Pao # Character è·
+U+8dd2 Qia # Character è·
+U+8dd3 Zhu # Character è·
+U+8dd4 Ju # Character è·
+U+8dd5 Die # Character è·
+U+8dd6 Zhi # Character è·
+U+8dd7 Fu # Character è·
+U+8dd8 Pan # Character è·
+U+8dd9 Ju # Character è·
+U+8dda Shan # Character è·
+U+8ddb Bo # Character è·
+U+8ddc Ni # Character è·
+U+8ddd Ju # Character è·
+U+8dde Li # Character è·
+U+8ddf Gen # Character è·
+U+8de0 Yi # Character è·
+U+8de1 Ji # Character è·¡
+U+8de2 Dai # Character è·¢
+U+8de3 Xian # Character è·£
+U+8de4 Jiao # Character è·¤
+U+8de5 Duo # Character è·¥
+U+8de6 Zhu # Character è·¦
+U+8de7 Zhuan # Character è·§
+U+8de8 Kua # Character è·¨
+U+8de9 Zhuai # Character è·©
+U+8dea Gui # Character è·ª
+U+8deb Qiong # Character è·«
+U+8dec Kui # Character è·¬
+U+8ded Xiang # Character è·
+U+8dee Chi # Character è·®
+U+8def Lu # Character è·¯
+U+8df0 Beng # Character è·°
+U+8df1 Zhi # Character è·±
+U+8df2 Jia # Character è·²
+U+8df3 Tiao # Character è·³
+U+8df4 Cai # Character è·´
+U+8df5 Jian # Character è·µ
+U+8df6 Ta # Character è·¶
+U+8df7 Qiao # Character è··
+U+8df8 Bi # Character è·¸
+U+8df9 Xian # Character è·¹
+U+8dfa Duo # Character è·º
+U+8dfb Ji # Character è·»
+U+8dfc Ju # Character è·¼
+U+8dfd Ji # Character è·½
+U+8dfe Shu # Character è·¾
+U+8dff Tu # Character è·¿
diff --git a/resources/chars/ascii/row8e.trans b/resources/chars/ascii/row8e.trans
new file mode 100644
index 0000000..fbd0f49
--- /dev/null
+++ b/resources/chars/ascii/row8e.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+8e00 Chu # Character è¸
+U+8e01 Jing # Character è¸
+U+8e02 Nie # Character è¸
+U+8e03 Xiao # Character è¸
+U+8e04 Bo # Character è¸
+U+8e05 Chi # Character è¸
+U+8e06 Qun # Character è¸
+U+8e07 Mou # Character è¸
+U+8e08 Shu # Character è¸
+U+8e09 Lang # Character è¸
+U+8e0a Yong # Character è¸
+U+8e0b Jiao # Character è¸
+U+8e0c Chou # Character è¸
+U+8e0d Qiao # Character è¸
+U+8e0e ? # Character è¸
+U+8e0f Ta # Character è¸
+U+8e10 Jian # Character è¸
+U+8e11 Qi # Character è¸
+U+8e12 Wo # Character è¸
+U+8e13 Wei # Character è¸
+U+8e14 Zhuo # Character è¸
+U+8e15 Jie # Character è¸
+U+8e16 Ji # Character è¸
+U+8e17 Nie # Character è¸
+U+8e18 Ju # Character è¸
+U+8e19 Ju # Character è¸
+U+8e1a Lun # Character è¸
+U+8e1b Lu # Character è¸
+U+8e1c Leng # Character è¸
+U+8e1d Huai # Character è¸
+U+8e1e Ju # Character è¸
+U+8e1f Chi # Character è¸
+U+8e20 Wan # Character è¸
+U+8e21 Quan # Character 踡
+U+8e22 Ti # Character 踢
+U+8e23 Bo # Character 踣
+U+8e24 Zu # Character 踤
+U+8e25 Qie # Character 踥
+U+8e26 Ji # Character 踦
+U+8e27 Cu # Character 踧
+U+8e28 Zong # Character 踨
+U+8e29 Cai # Character 踩
+U+8e2a Zong # Character 踪
+U+8e2b Peng # Character 踫
+U+8e2c Zhi # Character 踬
+U+8e2d Zheng # Character è¸
+U+8e2e Dian # Character 踮
+U+8e2f Zhi # Character 踯
+U+8e30 Yu # Character 踰
+U+8e31 Duo # Character 踱
+U+8e32 Dun # Character 踲
+U+8e33 Chun # Character 踳
+U+8e34 Yong # Character 踴
+U+8e35 Zhong # Character 踵
+U+8e36 Di # Character 踶
+U+8e37 Zhe # Character 踷
+U+8e38 Chen # Character 踸
+U+8e39 Chuai # Character 踹
+U+8e3a Jian # Character 踺
+U+8e3b Gua # Character 踻
+U+8e3c Tang # Character 踼
+U+8e3d Ju # Character 踽
+U+8e3e Fu # Character 踾
+U+8e3f Zu # Character 踿
+U+8e40 Die # Character è¹
+U+8e41 Pian # Character è¹
+U+8e42 Rou # Character è¹
+U+8e43 Nuo # Character è¹
+U+8e44 Ti # Character è¹
+U+8e45 Cha # Character è¹
+U+8e46 Tui # Character è¹
+U+8e47 Jian # Character è¹
+U+8e48 Dao # Character è¹
+U+8e49 Cuo # Character è¹
+U+8e4a Xi # Character è¹
+U+8e4b Ta # Character è¹
+U+8e4c Qiang # Character è¹
+U+8e4d Zhan # Character è¹
+U+8e4e Dian # Character è¹
+U+8e4f Ti # Character è¹
+U+8e50 Ji # Character è¹
+U+8e51 Nie # Character è¹
+U+8e52 Man # Character è¹
+U+8e53 Liu # Character è¹
+U+8e54 Zhan # Character è¹
+U+8e55 Bi # Character è¹
+U+8e56 Chong # Character è¹
+U+8e57 Lu # Character è¹
+U+8e58 Liao # Character è¹
+U+8e59 Cu # Character è¹
+U+8e5a Tang # Character è¹
+U+8e5b Dai # Character è¹
+U+8e5c Suo # Character è¹
+U+8e5d Xi # Character è¹
+U+8e5e Kui # Character è¹
+U+8e5f Ji # Character è¹
+U+8e60 Zhi # Character è¹
+U+8e61 Qiang # Character 蹡
+U+8e62 Di # Character è¹¢
+U+8e63 Man # Character è¹£
+U+8e64 Zong # Character 蹤
+U+8e65 Lian # Character è¹¥
+U+8e66 Beng # Character 蹦
+U+8e67 Zao # Character 蹧
+U+8e68 Nian # Character 蹨
+U+8e69 Bie # Character 蹩
+U+8e6a Tui # Character 蹪
+U+8e6b Ju # Character 蹫
+U+8e6c Deng # Character 蹬
+U+8e6d Ceng # Character è¹
+U+8e6e Xian # Character è¹®
+U+8e6f Fan # Character 蹯
+U+8e70 Chu # Character è¹°
+U+8e71 Zhong # Character è¹±
+U+8e72 Dun # Character è¹²
+U+8e73 Bo # Character è¹³
+U+8e74 Cu # Character è¹´
+U+8e75 Zu # Character è¹µ
+U+8e76 Jue # Character 蹶
+U+8e77 Jue # Character è¹·
+U+8e78 Lin # Character 蹸
+U+8e79 Ta # Character è¹¹
+U+8e7a Qiao # Character 蹺
+U+8e7b Qiao # Character è¹»
+U+8e7c Pu # Character è¹¼
+U+8e7d Liao # Character è¹½
+U+8e7e Dun # Character è¹¾
+U+8e7f Cuan # Character 蹿
+U+8e80 Kuang # Character èº
+U+8e81 Zao # Character èº
+U+8e82 Ta # Character èº
+U+8e83 Bi # Character èº
+U+8e84 Bi # Character èº
+U+8e85 Zhu # Character èº
+U+8e86 Ju # Character èº
+U+8e87 Chu # Character èº
+U+8e88 Qiao # Character èº
+U+8e89 Dun # Character èº
+U+8e8a Chou # Character èº
+U+8e8b Ji # Character èº
+U+8e8c Wu # Character èº
+U+8e8d Yue # Character èº
+U+8e8e Nian # Character èº
+U+8e8f Lin # Character èº
+U+8e90 Lie # Character èº
+U+8e91 Zhi # Character èº
+U+8e92 Li # Character èº
+U+8e93 Zhi # Character èº
+U+8e94 Chan # Character èº
+U+8e95 Chu # Character èº
+U+8e96 Duan # Character èº
+U+8e97 Wei # Character èº
+U+8e98 Long # Character èº
+U+8e99 Lin # Character èº
+U+8e9a Xian # Character èº
+U+8e9b Wei # Character èº
+U+8e9c Zuan # Character èº
+U+8e9d Lan # Character èº
+U+8e9e Xie # Character èº
+U+8e9f Rang # Character èº
+U+8ea0 Xie # Character èº
+U+8ea1 Nie # Character 躡
+U+8ea2 Ta # Character 躢
+U+8ea3 Qu # Character 躣
+U+8ea4 Jie # Character 躤
+U+8ea5 Cuan # Character 躥
+U+8ea6 Zuan # Character 躦
+U+8ea7 Xi # Character 躧
+U+8ea8 Kui # Character 躨
+U+8ea9 Jue # Character 躩
+U+8eaa Lin # Character 躪
+U+8eab Shen # Character 身
+U+8eac Gong # Character 躬
+U+8ead Dan # Character èº
+U+8eae Segare # Character 躮
+U+8eaf Qu # Character 躯
+U+8eb0 Ti # Character 躰
+U+8eb1 Duo # Character 躱
+U+8eb2 Duo # Character 躲
+U+8eb3 Gong # Character 躳
+U+8eb4 Lang # Character 躴
+U+8eb5 Nerau # Character 躵
+U+8eb6 Luo # Character 躶
+U+8eb7 Ai # Character 躷
+U+8eb8 Ji # Character 躸
+U+8eb9 Ju # Character 躹
+U+8eba Tang # Character 躺
+U+8ebb Utsuke # Character 躻
+U+8ebc ? # Character 躼
+U+8ebd Yan # Character 躽
+U+8ebe Shitsuke # Character 躾
+U+8ebf Kang # Character 躿
+U+8ec0 Qu # Character è»
+U+8ec1 Lou # Character è»
+U+8ec2 Lao # Character è»
+U+8ec3 Tuo # Character è»
+U+8ec4 Zhi # Character è»
+U+8ec5 Yagate # Character è»
+U+8ec6 Ti # Character è»
+U+8ec7 Dao # Character è»
+U+8ec8 Yagate # Character è»
+U+8ec9 Yu # Character è»
+U+8eca Che # Character è»
+U+8ecb Ya # Character è»
+U+8ecc Gui # Character è»
+U+8ecd Jun # Character è»
+U+8ece Wei # Character è»
+U+8ecf Yue # Character è»
+U+8ed0 Xin # Character è»
+U+8ed1 Di # Character è»
+U+8ed2 Xuan # Character è»
+U+8ed3 Fan # Character è»
+U+8ed4 Ren # Character è»
+U+8ed5 Shan # Character è»
+U+8ed6 Qiang # Character è»
+U+8ed7 Shu # Character è»
+U+8ed8 Tun # Character è»
+U+8ed9 Chen # Character è»
+U+8eda Dai # Character è»
+U+8edb E # Character è»
+U+8edc Na # Character è»
+U+8edd Qi # Character è»
+U+8ede Mao # Character è»
+U+8edf Ruan # Character è»
+U+8ee0 Ren # Character è»
+U+8ee1 Fan # Character 軡
+U+8ee2 Zhuan # Character 転
+U+8ee3 Hong # Character 軣
+U+8ee4 Hu # Character 軤
+U+8ee5 Qu # Character 軥
+U+8ee6 Huang # Character 軦
+U+8ee7 Di # Character 軧
+U+8ee8 Ling # Character 軨
+U+8ee9 Dai # Character 軩
+U+8eea Ao # Character 軪
+U+8eeb Zhen # Character 軫
+U+8eec Fan # Character 軬
+U+8eed Kuang # Character è»
+U+8eee Ang # Character è»®
+U+8eef Peng # Character 軯
+U+8ef0 Bei # Character è»°
+U+8ef1 Gu # Character è»±
+U+8ef2 Ku # Character 軲
+U+8ef3 Pao # Character 軳
+U+8ef4 Zhu # Character è»´
+U+8ef5 Rong # Character 軵
+U+8ef6 E # Character 軶
+U+8ef7 Ba # Character è»·
+U+8ef8 Zhou # Character 軸
+U+8ef9 Zhi # Character 軹
+U+8efa Yao # Character 軺
+U+8efb Ke # Character è»»
+U+8efc Yi # Character 軼
+U+8efd Qing # Character 軽
+U+8efe Shi # Character 軾
+U+8eff Ping # Character 軿
diff --git a/resources/chars/ascii/row8f.trans b/resources/chars/ascii/row8f.trans
new file mode 100644
index 0000000..2dab0ce
--- /dev/null
+++ b/resources/chars/ascii/row8f.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+8f00 Er # Character è¼
+U+8f01 Qiong # Character è¼
+U+8f02 Ju # Character è¼
+U+8f03 Jiao # Character è¼
+U+8f04 Guang # Character è¼
+U+8f05 Lu # Character è¼
+U+8f06 Kai # Character è¼
+U+8f07 Quan # Character è¼
+U+8f08 Zhou # Character è¼
+U+8f09 Zai # Character è¼
+U+8f0a Zhi # Character è¼
+U+8f0b She # Character è¼
+U+8f0c Liang # Character è¼
+U+8f0d Yu # Character è¼
+U+8f0e Shao # Character è¼
+U+8f0f You # Character è¼
+U+8f10 Huan # Character è¼
+U+8f11 Yun # Character è¼
+U+8f12 Zhe # Character è¼
+U+8f13 Wan # Character è¼
+U+8f14 Fu # Character è¼
+U+8f15 Qing # Character è¼
+U+8f16 Zhou # Character è¼
+U+8f17 Ni # Character è¼
+U+8f18 Ling # Character è¼
+U+8f19 Zhe # Character è¼
+U+8f1a Zhan # Character è¼
+U+8f1b Liang # Character è¼
+U+8f1c Zi # Character è¼
+U+8f1d Hui # Character è¼
+U+8f1e Wang # Character è¼
+U+8f1f Chuo # Character è¼
+U+8f20 Guo # Character è¼
+U+8f21 Kan # Character 輡
+U+8f22 Yi # Character è¼¢
+U+8f23 Peng # Character è¼£
+U+8f24 Qian # Character 輤
+U+8f25 Gun # Character è¼¥
+U+8f26 Nian # Character 輦
+U+8f27 Pian # Character 輧
+U+8f28 Guan # Character 輨
+U+8f29 Bei # Character 輩
+U+8f2a Lun # Character 輪
+U+8f2b Pai # Character 輫
+U+8f2c Liang # Character 輬
+U+8f2d Ruan # Character è¼
+U+8f2e Rou # Character è¼®
+U+8f2f Ji # Character 輯
+U+8f30 Yang # Character è¼°
+U+8f31 Xian # Character è¼±
+U+8f32 Chuan # Character è¼²
+U+8f33 Cou # Character è¼³
+U+8f34 Qun # Character è¼´
+U+8f35 Ge # Character è¼µ
+U+8f36 You # Character 輶
+U+8f37 Hong # Character è¼·
+U+8f38 Shu # Character 輸
+U+8f39 Fu # Character è¼¹
+U+8f3a Zi # Character 輺
+U+8f3b Fu # Character è¼»
+U+8f3c Wen # Character è¼¼
+U+8f3d Ben # Character è¼½
+U+8f3e Zhan # Character è¼¾
+U+8f3f Yu # Character 輿
+U+8f40 Wen # Character è½
+U+8f41 Tao # Character è½
+U+8f42 Gu # Character è½
+U+8f43 Zhen # Character è½
+U+8f44 Xia # Character è½
+U+8f45 Yuan # Character è½
+U+8f46 Lu # Character è½
+U+8f47 Jiu # Character è½
+U+8f48 Chao # Character è½
+U+8f49 Zhuan # Character è½
+U+8f4a Wei # Character è½
+U+8f4b Hun # Character è½
+U+8f4c Sori # Character è½
+U+8f4d Che # Character è½
+U+8f4e Jiao # Character è½
+U+8f4f Zhan # Character è½
+U+8f50 Pu # Character è½
+U+8f51 Lao # Character è½
+U+8f52 Fen # Character è½
+U+8f53 Fan # Character è½
+U+8f54 Lin # Character è½
+U+8f55 Ge # Character è½
+U+8f56 Se # Character è½
+U+8f57 Kan # Character è½
+U+8f58 Huan # Character è½
+U+8f59 Yi # Character è½
+U+8f5a Ji # Character è½
+U+8f5b Dui # Character è½
+U+8f5c Er # Character è½
+U+8f5d Yu # Character è½
+U+8f5e Xian # Character è½
+U+8f5f Hong # Character è½
+U+8f60 Lei # Character è½
+U+8f61 Pei # Character 轡
+U+8f62 Li # Character è½¢
+U+8f63 Li # Character è½£
+U+8f64 Lu # Character 轤
+U+8f65 Lin # Character è½¥
+U+8f66 Che # Character 车
+U+8f67 Ya # Character 轧
+U+8f68 Gui # Character 轨
+U+8f69 Xuan # Character 轩
+U+8f6a Di # Character 轪
+U+8f6b Ren # Character 轫
+U+8f6c Zhuan # Character 转
+U+8f6d E # Character è½
+U+8f6e Lun # Character è½®
+U+8f6f Ruan # Character 软
+U+8f70 Hong # Character è½°
+U+8f71 Ku # Character è½±
+U+8f72 Ke # Character è½²
+U+8f73 Lu # Character è½³
+U+8f74 Zhou # Character è½´
+U+8f75 Zhi # Character è½µ
+U+8f76 Yi # Character 轶
+U+8f77 Hu # Character è½·
+U+8f78 Zhen # Character 轸
+U+8f79 Li # Character è½¹
+U+8f7a Yao # Character 轺
+U+8f7b Qing # Character è½»
+U+8f7c Shi # Character è½¼
+U+8f7d Zai # Character è½½
+U+8f7e Zhi # Character è½¾
+U+8f7f Jiao # Character 轿
+U+8f80 Zhou # Character è¾
+U+8f81 Quan # Character è¾
+U+8f82 Lu # Character è¾
+U+8f83 Jiao # Character è¾
+U+8f84 Zhe # Character è¾
+U+8f85 Fu # Character è¾
+U+8f86 Liang # Character è¾
+U+8f87 Nian # Character è¾
+U+8f88 Bei # Character è¾
+U+8f89 Hui # Character è¾
+U+8f8a Gun # Character è¾
+U+8f8b Wang # Character è¾
+U+8f8c Liang # Character è¾
+U+8f8d Chuo # Character è¾
+U+8f8e Zi # Character è¾
+U+8f8f Cou # Character è¾
+U+8f90 Fu # Character è¾
+U+8f91 Ji # Character è¾
+U+8f92 Wen # Character è¾
+U+8f93 Shu # Character è¾
+U+8f94 Pei # Character è¾
+U+8f95 Yuan # Character è¾
+U+8f96 Xia # Character è¾
+U+8f97 Zhan # Character è¾
+U+8f98 Lu # Character è¾
+U+8f99 Che # Character è¾
+U+8f9a Lin # Character è¾
+U+8f9b Xin # Character è¾
+U+8f9c Gu # Character è¾
+U+8f9d Ci # Character è¾
+U+8f9e Ci # Character è¾
+U+8f9f Pi # Character è¾
+U+8fa0 Zui # Character è¾
+U+8fa1 Bian # Character 辡
+U+8fa2 La # Character è¾¢
+U+8fa3 La # Character è¾£
+U+8fa4 Ci # Character 辤
+U+8fa5 Xue # Character è¾¥
+U+8fa6 Ban # Character 辦
+U+8fa7 Bian # Character 辧
+U+8fa8 Bian # Character 辨
+U+8fa9 Bian # Character 辩
+U+8faa ? # Character 辪
+U+8fab Bian # Character 辫
+U+8fac Ban # Character 辬
+U+8fad Ci # Character è¾
+U+8fae Bian # Character è¾®
+U+8faf Bian # Character 辯
+U+8fb0 Chen # Character è¾°
+U+8fb1 Ru # Character è¾±
+U+8fb2 Nong # Character è¾²
+U+8fb3 Nong # Character è¾³
+U+8fb4 Zhen # Character è¾´
+U+8fb5 Chuo # Character è¾µ
+U+8fb6 Chuo # Character 辶
+U+8fb7 Suberu # Character è¾·
+U+8fb8 Reng # Character 辸
+U+8fb9 Bian # Character è¾¹
+U+8fba Bian # Character 辺
+U+8fbb Sip # Character è¾»
+U+8fbc Ip # Character è¾¼
+U+8fbd Liao # Character è¾½
+U+8fbe Da # Character è¾¾
+U+8fbf Chan # Character 辿
+U+8fc0 Gan # Character è¿
+U+8fc1 Qian # Character è¿
+U+8fc2 Yu # Character è¿
+U+8fc3 Yu # Character è¿
+U+8fc4 Qi # Character è¿
+U+8fc5 Xun # Character è¿
+U+8fc6 Yi # Character è¿
+U+8fc7 Guo # Character è¿
+U+8fc8 Mai # Character è¿
+U+8fc9 Qi # Character è¿
+U+8fca Za # Character è¿
+U+8fcb Wang # Character è¿
+U+8fcc Jia # Character è¿
+U+8fcd Zhun # Character è¿
+U+8fce Ying # Character è¿
+U+8fcf Ti # Character è¿
+U+8fd0 Yun # Character è¿
+U+8fd1 Jin # Character è¿
+U+8fd2 Hang # Character è¿
+U+8fd3 Ya # Character è¿
+U+8fd4 Fan # Character è¿
+U+8fd5 Wu # Character è¿
+U+8fd6 Da # Character è¿
+U+8fd7 E # Character è¿
+U+8fd8 Huan # Character è¿
+U+8fd9 Zhe # Character è¿
+U+8fda Totemo # Character è¿
+U+8fdb Jin # Character è¿
+U+8fdc Yuan # Character è¿
+U+8fdd Wei # Character è¿
+U+8fde Lian # Character è¿
+U+8fdf Chi # Character è¿
+U+8fe0 Che # Character è¿
+U+8fe1 Ni # Character è¿¡
+U+8fe2 Tiao # Character è¿¢
+U+8fe3 Zhi # Character è¿£
+U+8fe4 Yi # Character 迤
+U+8fe5 Jiong # Character è¿¥
+U+8fe6 Jia # Character 迦
+U+8fe7 Chen # Character 迧
+U+8fe8 Dai # Character 迨
+U+8fe9 Er # Character è¿©
+U+8fea Di # Character 迪
+U+8feb Po # Character è¿«
+U+8fec Wang # Character 迬
+U+8fed Die # Character è¿
+U+8fee Ze # Character è¿®
+U+8fef Tao # Character 迯
+U+8ff0 Shu # Character è¿°
+U+8ff1 Tuo # Character 迱
+U+8ff2 Kep # Character 迲
+U+8ff3 Jing # Character 迳
+U+8ff4 Hui # Character è¿´
+U+8ff5 Tong # Character 迵
+U+8ff6 You # Character 迶
+U+8ff7 Mi # Character è¿·
+U+8ff8 Beng # Character 迸
+U+8ff9 Ji # Character 迹
+U+8ffa Nai # Character 迺
+U+8ffb Yi # Character è¿»
+U+8ffc Jie # Character 迼
+U+8ffd Zhui # Character 追
+U+8ffe Lie # Character 迾
+U+8fff Xun # Character è¿¿
diff --git a/resources/chars/ascii/row90.trans b/resources/chars/ascii/row90.trans
new file mode 100644
index 0000000..b9c01c2
--- /dev/null
+++ b/resources/chars/ascii/row90.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+9000 Tui # Character é
+U+9001 Song # Character é
+U+9002 Gua # Character é
+U+9003 Tao # Character é
+U+9004 Pang # Character é
+U+9005 Hou # Character é
+U+9006 Ni # Character é
+U+9007 Dun # Character é
+U+9008 Jiong # Character é
+U+9009 Xuan # Character é
+U+900a Xun # Character é
+U+900b Bu # Character é
+U+900c You # Character é
+U+900d Xiao # Character é
+U+900e Qiu # Character é
+U+900f Tou # Character é
+U+9010 Zhu # Character é
+U+9011 Qiu # Character é
+U+9012 Di # Character é
+U+9013 Di # Character é
+U+9014 Tu # Character é
+U+9015 Jing # Character é
+U+9016 Ti # Character é
+U+9017 Dou # Character é
+U+9018 Yi # Character é
+U+9019 Zhe # Character é
+U+901a Tong # Character é
+U+901b Guang # Character é
+U+901c Wu # Character é
+U+901d Shi # Character é
+U+901e Cheng # Character é
+U+901f Su # Character é
+U+9020 Zao # Character é
+U+9021 Qun # Character é¡
+U+9022 Feng # Character é¢
+U+9023 Lian # Character é£
+U+9024 Suo # Character é¤
+U+9025 Hui # Character é¥
+U+9026 Li # Character é¦
+U+9027 Sako # Character é§
+U+9028 Lai # Character é¨
+U+9029 Ben # Character é©
+U+902a Cuo # Character éª
+U+902b Jue # Character é«
+U+902c Beng # Character é¬
+U+902d Huan # Character é
+U+902e Dai # Character é®
+U+902f Lu # Character é¯
+U+9030 You # Character é°
+U+9031 Zhou # Character é±
+U+9032 Jin # Character é²
+U+9033 Yu # Character é³
+U+9034 Chuo # Character é´
+U+9035 Kui # Character éµ
+U+9036 Wei # Character é¶
+U+9037 Ti # Character é·
+U+9038 Yi # Character é¸
+U+9039 Da # Character é¹
+U+903a Yuan # Character éº
+U+903b Luo # Character é»
+U+903c Bi # Character é¼
+U+903d Nuo # Character é½
+U+903e Yu # Character é¾
+U+903f Dang # Character é¿
+U+9040 Sui # Character é
+U+9041 Dun # Character é
+U+9042 Sui # Character é
+U+9043 Yan # Character é
+U+9044 Chuan # Character é
+U+9045 Chi # Character é
+U+9046 Ti # Character é
+U+9047 Yu # Character é
+U+9048 Shi # Character é
+U+9049 Zhen # Character é
+U+904a You # Character é
+U+904b Yun # Character é
+U+904c E # Character é
+U+904d Bian # Character é
+U+904e Guo # Character é
+U+904f E # Character é
+U+9050 Xia # Character é
+U+9051 Huang # Character é
+U+9052 Qiu # Character é
+U+9053 Dao # Character é
+U+9054 Da # Character é
+U+9055 Wei # Character é
+U+9056 Appare # Character é
+U+9057 Yi # Character é
+U+9058 Gou # Character é
+U+9059 Yao # Character é
+U+905a Chu # Character é
+U+905b Liu # Character é
+U+905c Xun # Character é
+U+905d Ta # Character é
+U+905e Di # Character é
+U+905f Chi # Character é
+U+9060 Yuan # Character é
+U+9061 Su # Character é¡
+U+9062 Ta # Character é¢
+U+9063 Qian # Character é£
+U+9064 ? # Character é¤
+U+9065 Yao # Character é¥
+U+9066 Guan # Character é¦
+U+9067 Zhang # Character é§
+U+9068 Ao # Character é¨
+U+9069 Shi # Character é©
+U+906a Ce # Character éª
+U+906b Chi # Character é«
+U+906c Su # Character é¬
+U+906d Zao # Character é
+U+906e Zhe # Character é®
+U+906f Dun # Character é¯
+U+9070 Di # Character é°
+U+9071 Lou # Character é±
+U+9072 Chi # Character é²
+U+9073 Cuo # Character é³
+U+9074 Lin # Character é´
+U+9075 Zun # Character éµ
+U+9076 Rao # Character é¶
+U+9077 Qian # Character é·
+U+9078 Xuan # Character é¸
+U+9079 Yu # Character é¹
+U+907a Yi # Character éº
+U+907b Wu # Character é»
+U+907c Liao # Character é¼
+U+907d Ju # Character é½
+U+907e Shi # Character é¾
+U+907f Bi # Character é¿
+U+9080 Yao # Character é
+U+9081 Mai # Character é
+U+9082 Xie # Character é
+U+9083 Sui # Character é
+U+9084 Huan # Character é
+U+9085 Zhan # Character é
+U+9086 Teng # Character é
+U+9087 Er # Character é
+U+9088 Miao # Character é
+U+9089 Bian # Character é
+U+908a Bian # Character é
+U+908b La # Character é
+U+908c Li # Character é
+U+908d Yuan # Character é
+U+908e Yao # Character é
+U+908f Luo # Character é
+U+9090 Li # Character é
+U+9091 Yi # Character é
+U+9092 Ting # Character é
+U+9093 Deng # Character é
+U+9094 Qi # Character é
+U+9095 Yong # Character é
+U+9096 Shan # Character é
+U+9097 Han # Character é
+U+9098 Yu # Character é
+U+9099 Mang # Character é
+U+909a Ru # Character é
+U+909b Qiong # Character é
+U+909c ? # Character é
+U+909d Kuang # Character é
+U+909e Fu # Character é
+U+909f Kang # Character é
+U+90a0 Bin # Character é
+U+90a1 Fang # Character é¡
+U+90a2 Xing # Character é¢
+U+90a3 Na # Character é£
+U+90a4 Xin # Character é¤
+U+90a5 Shen # Character é¥
+U+90a6 Bang # Character é¦
+U+90a7 Yuan # Character é§
+U+90a8 Cun # Character é¨
+U+90a9 Huo # Character é©
+U+90aa Xie # Character éª
+U+90ab Bang # Character é«
+U+90ac Wu # Character é¬
+U+90ad Ju # Character é
+U+90ae You # Character é®
+U+90af Han # Character é¯
+U+90b0 Tai # Character é°
+U+90b1 Qiu # Character é±
+U+90b2 Bi # Character é²
+U+90b3 Pei # Character é³
+U+90b4 Bing # Character é´
+U+90b5 Shao # Character éµ
+U+90b6 Bei # Character é¶
+U+90b7 Wa # Character é·
+U+90b8 Di # Character é¸
+U+90b9 Zou # Character é¹
+U+90ba Ye # Character éº
+U+90bb Lin # Character é»
+U+90bc Kuang # Character é¼
+U+90bd Gui # Character é½
+U+90be Zhu # Character é¾
+U+90bf Shi # Character é¿
+U+90c0 Ku # Character é
+U+90c1 Yu # Character é
+U+90c2 Gai # Character é
+U+90c3 Ge # Character é
+U+90c4 Xi # Character é
+U+90c5 Zhi # Character é
+U+90c6 Ji # Character é
+U+90c7 Xun # Character é
+U+90c8 Hou # Character é
+U+90c9 Xing # Character é
+U+90ca Jiao # Character é
+U+90cb Xi # Character é
+U+90cc Gui # Character é
+U+90cd Nuo # Character é
+U+90ce Lang # Character é
+U+90cf Jia # Character é
+U+90d0 Kuai # Character é
+U+90d1 Zheng # Character é
+U+90d2 Otoko # Character é
+U+90d3 Yun # Character é
+U+90d4 Yan # Character é
+U+90d5 Cheng # Character é
+U+90d6 Dou # Character é
+U+90d7 Chi # Character é
+U+90d8 Lu # Character é
+U+90d9 Fu # Character é
+U+90da Wu # Character é
+U+90db Fu # Character é
+U+90dc Gao # Character é
+U+90dd Hao # Character é
+U+90de Lang # Character é
+U+90df Jia # Character é
+U+90e0 Geng # Character é
+U+90e1 Jun # Character é¡
+U+90e2 Ying # Character é¢
+U+90e3 Bo # Character é£
+U+90e4 Xi # Character é¤
+U+90e5 Bei # Character é¥
+U+90e6 Li # Character é¦
+U+90e7 Yun # Character é§
+U+90e8 Bu # Character é¨
+U+90e9 Xiao # Character é©
+U+90ea Qi # Character éª
+U+90eb Pi # Character é«
+U+90ec Qing # Character é¬
+U+90ed Guo # Character é
+U+90ee Zhou # Character é®
+U+90ef Tan # Character é¯
+U+90f0 Zou # Character é°
+U+90f1 Ping # Character é±
+U+90f2 Lai # Character é²
+U+90f3 Ni # Character é³
+U+90f4 Chen # Character é´
+U+90f5 You # Character éµ
+U+90f6 Bu # Character é¶
+U+90f7 Xiang # Character é·
+U+90f8 Dan # Character é¸
+U+90f9 Ju # Character é¹
+U+90fa Yong # Character éº
+U+90fb Qiao # Character é»
+U+90fc Yi # Character é¼
+U+90fd Du # Character é½
+U+90fe Yan # Character é¾
+U+90ff Mei # Character é¿
diff --git a/resources/chars/ascii/row91.trans b/resources/chars/ascii/row91.trans
new file mode 100644
index 0000000..519f9ef
--- /dev/null
+++ b/resources/chars/ascii/row91.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+9100 Ruo # Character é
+U+9101 Bei # Character é
+U+9102 E # Character é
+U+9103 Yu # Character é
+U+9104 Juan # Character é
+U+9105 Yu # Character é
+U+9106 Yun # Character é
+U+9107 Hou # Character é
+U+9108 Kui # Character é
+U+9109 Xiang # Character é
+U+910a Xiang # Character é
+U+910b Sou # Character é
+U+910c Tang # Character é
+U+910d Ming # Character é
+U+910e Xi # Character é
+U+910f Ru # Character é
+U+9110 Chu # Character é
+U+9111 Zi # Character é
+U+9112 Zou # Character é
+U+9113 Ju # Character é
+U+9114 Wu # Character é
+U+9115 Xiang # Character é
+U+9116 Yun # Character é
+U+9117 Hao # Character é
+U+9118 Yong # Character é
+U+9119 Bi # Character é
+U+911a Mo # Character é
+U+911b Chao # Character é
+U+911c Fu # Character é
+U+911d Liao # Character é
+U+911e Yin # Character é
+U+911f Zhuan # Character é
+U+9120 Hu # Character é
+U+9121 Qiao # Character é¡
+U+9122 Yan # Character é¢
+U+9123 Zhang # Character é£
+U+9124 Fan # Character é¤
+U+9125 Qiao # Character é¥
+U+9126 Xu # Character é¦
+U+9127 Deng # Character é§
+U+9128 Bi # Character é¨
+U+9129 Xin # Character é©
+U+912a Bi # Character éª
+U+912b Ceng # Character é«
+U+912c Wei # Character é¬
+U+912d Zheng # Character é
+U+912e Mao # Character é®
+U+912f Shan # Character é¯
+U+9130 Lin # Character é°
+U+9131 Po # Character é±
+U+9132 Dan # Character é²
+U+9133 Meng # Character é³
+U+9134 Ye # Character é´
+U+9135 Cao # Character éµ
+U+9136 Kuai # Character é¶
+U+9137 Feng # Character é·
+U+9138 Meng # Character é¸
+U+9139 Zou # Character é¹
+U+913a Kuang # Character éº
+U+913b Lian # Character é»
+U+913c Zan # Character é¼
+U+913d Chan # Character é½
+U+913e You # Character é¾
+U+913f Qi # Character é¿
+U+9140 Yan # Character é
+U+9141 Chan # Character é
+U+9142 Zan # Character é
+U+9143 Ling # Character é
+U+9144 Huan # Character é
+U+9145 Xi # Character é
+U+9146 Feng # Character é
+U+9147 Zan # Character é
+U+9148 Li # Character é
+U+9149 You # Character é
+U+914a Ding # Character é
+U+914b Qiu # Character é
+U+914c Zhuo # Character é
+U+914d Pei # Character é
+U+914e Zhou # Character é
+U+914f Yi # Character é
+U+9150 Hang # Character é
+U+9151 Yu # Character é
+U+9152 Jiu # Character é
+U+9153 Yan # Character é
+U+9154 Zui # Character é
+U+9155 Mao # Character é
+U+9156 Dan # Character é
+U+9157 Xu # Character é
+U+9158 Tou # Character é
+U+9159 Zhen # Character é
+U+915a Fen # Character é
+U+915b Sakenomoto # Character é
+U+915c ? # Character é
+U+915d Yun # Character é
+U+915e Tai # Character é
+U+915f Tian # Character é
+U+9160 Qia # Character é
+U+9161 Tuo # Character é
¡
+U+9162 Zuo # Character é
¢
+U+9163 Han # Character é
£
+U+9164 Gu # Character é
¤
+U+9165 Su # Character é
¥
+U+9166 Po # Character é
¦
+U+9167 Chou # Character é
§
+U+9168 Zai # Character é
¨
+U+9169 Ming # Character é
©
+U+916a Luo # Character é
ª
+U+916b Chuo # Character é
«
+U+916c Chou # Character é
¬
+U+916d You # Character é
+U+916e Tong # Character é
®
+U+916f Zhi # Character é
¯
+U+9170 Xian # Character é
°
+U+9171 Jiang # Character é
±
+U+9172 Cheng # Character é
²
+U+9173 Yin # Character é
³
+U+9174 Tu # Character é
´
+U+9175 Xiao # Character é
µ
+U+9176 Mei # Character é
¶
+U+9177 Ku # Character é
·
+U+9178 Suan # Character é
¸
+U+9179 Lei # Character é
¹
+U+917a Pu # Character é
º
+U+917b Zui # Character é
»
+U+917c Hai # Character é
¼
+U+917d Yan # Character é
½
+U+917e Xi # Character é
¾
+U+917f Niang # Character é
¿
+U+9180 Wei # Character é
+U+9181 Lu # Character é
+U+9182 Lan # Character é
+U+9183 Yan # Character é
+U+9184 Tao # Character é
+U+9185 Pei # Character é
+U+9186 Zhan # Character é
+U+9187 Chun # Character é
+U+9188 Tan # Character é
+U+9189 Zui # Character é
+U+918a Chuo # Character é
+U+918b Cu # Character é
+U+918c Kun # Character é
+U+918d Ti # Character é
+U+918e Mian # Character é
+U+918f Du # Character é
+U+9190 Hu # Character é
+U+9191 Xu # Character é
+U+9192 Xing # Character é
+U+9193 Tan # Character é
+U+9194 Jiu # Character é
+U+9195 Chun # Character é
+U+9196 Yun # Character é
+U+9197 Po # Character é
+U+9198 Ke # Character é
+U+9199 Sou # Character é
+U+919a Mi # Character é
+U+919b Quan # Character é
+U+919c Chou # Character é
+U+919d Cuo # Character é
+U+919e Yun # Character é
+U+919f Yong # Character é
+U+91a0 Ang # Character é
+U+91a1 Zha # Character é¡
+U+91a2 Hai # Character é¢
+U+91a3 Tang # Character é£
+U+91a4 Jiang # Character é¤
+U+91a5 Piao # Character é¥
+U+91a6 Shan # Character é¦
+U+91a7 Yu # Character é§
+U+91a8 Li # Character é¨
+U+91a9 Zao # Character é©
+U+91aa Lao # Character éª
+U+91ab Yi # Character é«
+U+91ac Jiang # Character é¬
+U+91ad Pu # Character é
+U+91ae Jiao # Character é®
+U+91af Xi # Character é¯
+U+91b0 Tan # Character é°
+U+91b1 Po # Character é±
+U+91b2 Nong # Character é²
+U+91b3 Yi # Character é³
+U+91b4 Li # Character é´
+U+91b5 Ju # Character éµ
+U+91b6 Jiao # Character é¶
+U+91b7 Yi # Character é·
+U+91b8 Niang # Character é¸
+U+91b9 Ru # Character é¹
+U+91ba Xun # Character éº
+U+91bb Chou # Character é»
+U+91bc Yan # Character é¼
+U+91bd Ling # Character é½
+U+91be Mi # Character é¾
+U+91bf Mi # Character é¿
+U+91c0 Niang # Character é
+U+91c1 Xin # Character é
+U+91c2 Jiao # Character é
+U+91c3 Xi # Character é
+U+91c4 Mi # Character é
+U+91c5 Yan # Character é
+U+91c6 Bian # Character é
+U+91c7 Cai # Character é
+U+91c8 Shi # Character é
+U+91c9 You # Character é
+U+91ca Shi # Character é
+U+91cb Shi # Character é
+U+91cc Li # Character é
+U+91cd Zhong # Character é
+U+91ce Ye # Character é
+U+91cf Liang # Character é
+U+91d0 Li # Character é
+U+91d1 Jin # Character é
+U+91d2 Jin # Character é
+U+91d3 Qiu # Character é
+U+91d4 Yi # Character é
+U+91d5 Diao # Character é
+U+91d6 Dao # Character é
+U+91d7 Zhao # Character é
+U+91d8 Ding # Character é
+U+91d9 Po # Character é
+U+91da Qiu # Character é
+U+91db He # Character é
+U+91dc Fu # Character é
+U+91dd Zhen # Character é
+U+91de Zhi # Character é
+U+91df Ba # Character é
+U+91e0 Luan # Character é
+U+91e1 Fu # Character é¡
+U+91e2 Nai # Character é¢
+U+91e3 Diao # Character é£
+U+91e4 Shan # Character é¤
+U+91e5 Qiao # Character é¥
+U+91e6 Kou # Character é¦
+U+91e7 Chuan # Character é§
+U+91e8 Zi # Character é¨
+U+91e9 Fan # Character é©
+U+91ea Yu # Character éª
+U+91eb Hua # Character é«
+U+91ec Han # Character é¬
+U+91ed Gong # Character é
+U+91ee Qi # Character é®
+U+91ef Mang # Character é¯
+U+91f0 Ri # Character é°
+U+91f1 Di # Character é±
+U+91f2 Si # Character é²
+U+91f3 Xi # Character é³
+U+91f4 Yi # Character é´
+U+91f5 Chai # Character éµ
+U+91f6 Shi # Character é¶
+U+91f7 Tu # Character é·
+U+91f8 Xi # Character é¸
+U+91f9 Nu # Character é¹
+U+91fa Qian # Character éº
+U+91fb Ishiyumi # Character é»
+U+91fc Jian # Character é¼
+U+91fd Pi # Character é½
+U+91fe Ye # Character é¾
+U+91ff Yin # Character é¿
diff --git a/resources/chars/ascii/row92.trans b/resources/chars/ascii/row92.trans
new file mode 100644
index 0000000..ab8fde0
--- /dev/null
+++ b/resources/chars/ascii/row92.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+9200 Ba # Character é
+U+9201 Fang # Character é
+U+9202 Chen # Character é
+U+9203 Xing # Character é
+U+9204 Tou # Character é
+U+9205 Yue # Character é
+U+9206 Yan # Character é
+U+9207 Fu # Character é
+U+9208 Pi # Character é
+U+9209 Na # Character é
+U+920a Xin # Character é
+U+920b E # Character é
+U+920c Jue # Character é
+U+920d Dun # Character é
+U+920e Gou # Character é
+U+920f Yin # Character é
+U+9210 Qian # Character é
+U+9211 Ban # Character é
+U+9212 Ji # Character é
+U+9213 Ren # Character é
+U+9214 Chao # Character é
+U+9215 Niu # Character é
+U+9216 Fen # Character é
+U+9217 Yun # Character é
+U+9218 Ji # Character é
+U+9219 Qin # Character é
+U+921a Pi # Character é
+U+921b Guo # Character é
+U+921c Hong # Character é
+U+921d Yin # Character é
+U+921e Jun # Character é
+U+921f Shi # Character é
+U+9220 Yi # Character é
+U+9221 Zhong # Character é¡
+U+9222 Nie # Character é¢
+U+9223 Gai # Character é£
+U+9224 Ri # Character é¤
+U+9225 Huo # Character é¥
+U+9226 Tai # Character é¦
+U+9227 Kang # Character é§
+U+9228 Habaki # Character é¨
+U+9229 Irori # Character é©
+U+922a Ngaak # Character éª
+U+922b ? # Character é«
+U+922c Duo # Character é¬
+U+922d Zi # Character é
+U+922e Ni # Character é®
+U+922f Tu # Character é¯
+U+9230 Shi # Character é°
+U+9231 Min # Character é±
+U+9232 Gu # Character é²
+U+9233 E # Character é³
+U+9234 Ling # Character é´
+U+9235 Bing # Character éµ
+U+9236 Yi # Character é¶
+U+9237 Gu # Character é·
+U+9238 Ba # Character é¸
+U+9239 Pi # Character é¹
+U+923a Yu # Character éº
+U+923b Si # Character é»
+U+923c Zuo # Character é¼
+U+923d Bu # Character é½
+U+923e You # Character é¾
+U+923f Dian # Character é¿
+U+9240 Jia # Character é
+U+9241 Zhen # Character é
+U+9242 Shi # Character é
+U+9243 Shi # Character é
+U+9244 Tie # Character é
+U+9245 Ju # Character é
+U+9246 Zhan # Character é
+U+9247 Shi # Character é
+U+9248 She # Character é
+U+9249 Xuan # Character é
+U+924a Zhao # Character é
+U+924b Bao # Character é
+U+924c He # Character é
+U+924d Bi # Character é
+U+924e Sheng # Character é
+U+924f Chu # Character é
+U+9250 Shi # Character é
+U+9251 Bo # Character é
+U+9252 Zhu # Character é
+U+9253 Chi # Character é
+U+9254 Za # Character é
+U+9255 Po # Character é
+U+9256 Tong # Character é
+U+9257 Qian # Character é
+U+9258 Fu # Character é
+U+9259 Zhai # Character é
+U+925a Liu # Character é
+U+925b Qian # Character é
+U+925c Fu # Character é
+U+925d Li # Character é
+U+925e Yue # Character é
+U+925f Pi # Character é
+U+9260 Yang # Character é
+U+9261 Ban # Character é¡
+U+9262 Bo # Character é¢
+U+9263 Jie # Character é£
+U+9264 Gou # Character é¤
+U+9265 Shu # Character é¥
+U+9266 Zheng # Character é¦
+U+9267 Mu # Character é§
+U+9268 Ni # Character é¨
+U+9269 Nie # Character é©
+U+926a Di # Character éª
+U+926b Jia # Character é«
+U+926c Mu # Character é¬
+U+926d Dan # Character é
+U+926e Shen # Character é®
+U+926f Yi # Character é¯
+U+9270 Si # Character é°
+U+9271 Kuang # Character é±
+U+9272 Ka # Character é²
+U+9273 Bei # Character é³
+U+9274 Jian # Character é´
+U+9275 Tong # Character éµ
+U+9276 Xing # Character é¶
+U+9277 Hong # Character é·
+U+9278 Jiao # Character é¸
+U+9279 Chi # Character é¹
+U+927a Er # Character éº
+U+927b Ge # Character é»
+U+927c Bing # Character é¼
+U+927d Shi # Character é½
+U+927e Mou # Character é¾
+U+927f Jia # Character é¿
+U+9280 Yin # Character é
+U+9281 Jun # Character é
+U+9282 Zhou # Character é
+U+9283 Chong # Character é
+U+9284 Shang # Character é
+U+9285 Tong # Character é
+U+9286 Mo # Character é
+U+9287 Lei # Character é
+U+9288 Ji # Character é
+U+9289 Yu # Character é
+U+928a Xu # Character é
+U+928b Ren # Character é
+U+928c Zun # Character é
+U+928d Zhi # Character é
+U+928e Qiong # Character é
+U+928f Shan # Character é
+U+9290 Chi # Character é
+U+9291 Xian # Character é
+U+9292 Xing # Character é
+U+9293 Quan # Character é
+U+9294 Pi # Character é
+U+9295 Tie # Character é
+U+9296 Zhu # Character é
+U+9297 Hou # Character é
+U+9298 Ming # Character é
+U+9299 Kua # Character é
+U+929a Yao # Character é
+U+929b Xian # Character é
+U+929c Xian # Character é
+U+929d Xiu # Character é
+U+929e Jun # Character é
+U+929f Cha # Character é
+U+92a0 Lao # Character é
+U+92a1 Ji # Character é¡
+U+92a2 Pi # Character é¢
+U+92a3 Ru # Character é£
+U+92a4 Mi # Character é¤
+U+92a5 Yi # Character é¥
+U+92a6 Yin # Character é¦
+U+92a7 Guang # Character é§
+U+92a8 An # Character é¨
+U+92a9 Diou # Character é©
+U+92aa You # Character éª
+U+92ab Se # Character é«
+U+92ac Kao # Character é¬
+U+92ad Qian # Character é
+U+92ae Luan # Character é®
+U+92af Kasugai # Character é¯
+U+92b0 Ai # Character é°
+U+92b1 Diao # Character é±
+U+92b2 Han # Character é²
+U+92b3 Rui # Character é³
+U+92b4 Shi # Character é´
+U+92b5 Keng # Character éµ
+U+92b6 Qiu # Character é¶
+U+92b7 Xiao # Character é·
+U+92b8 Zhe # Character é¸
+U+92b9 Xiu # Character é¹
+U+92ba Zang # Character éº
+U+92bb Ti # Character é»
+U+92bc Cuo # Character é¼
+U+92bd Gua # Character é½
+U+92be Gong # Character é¾
+U+92bf Zhong # Character é¿
+U+92c0 Dou # Character é
+U+92c1 Lu # Character é
+U+92c2 Mei # Character é
+U+92c3 Lang # Character é
+U+92c4 Wan # Character é
+U+92c5 Xin # Character é
+U+92c6 Yun # Character é
+U+92c7 Bei # Character é
+U+92c8 Wu # Character é
+U+92c9 Su # Character é
+U+92ca Yu # Character é
+U+92cb Chan # Character é
+U+92cc Ting # Character é
+U+92cd Bo # Character é
+U+92ce Han # Character é
+U+92cf Jia # Character é
+U+92d0 Hong # Character é
+U+92d1 Cuan # Character é
+U+92d2 Feng # Character é
+U+92d3 Chan # Character é
+U+92d4 Wan # Character é
+U+92d5 Zhi # Character é
+U+92d6 Si # Character é
+U+92d7 Xuan # Character é
+U+92d8 Wu # Character é
+U+92d9 Wu # Character é
+U+92da Tiao # Character é
+U+92db Gong # Character é
+U+92dc Zhuo # Character é
+U+92dd Lue # Character é
+U+92de Xing # Character é
+U+92df Qian # Character é
+U+92e0 Shen # Character é
+U+92e1 Han # Character é¡
+U+92e2 Lue # Character é¢
+U+92e3 Xie # Character é£
+U+92e4 Chu # Character é¤
+U+92e5 Zheng # Character é¥
+U+92e6 Ju # Character é¦
+U+92e7 Xian # Character é§
+U+92e8 Tie # Character é¨
+U+92e9 Mang # Character é©
+U+92ea Pu # Character éª
+U+92eb Li # Character é«
+U+92ec Pan # Character é¬
+U+92ed Rui # Character é
+U+92ee Cheng # Character é®
+U+92ef Gao # Character é¯
+U+92f0 Li # Character é°
+U+92f1 Te # Character é±
+U+92f2 Pyeng # Character é²
+U+92f3 Zhu # Character é³
+U+92f4 ? # Character é´
+U+92f5 Tu # Character éµ
+U+92f6 Liu # Character é¶
+U+92f7 Zui # Character é·
+U+92f8 Ju # Character é¸
+U+92f9 Chang # Character é¹
+U+92fa Yuan # Character éº
+U+92fb Jian # Character é»
+U+92fc Gang # Character é¼
+U+92fd Diao # Character é½
+U+92fe Tao # Character é¾
+U+92ff Chang # Character é¿
diff --git a/resources/chars/ascii/row93.trans b/resources/chars/ascii/row93.trans
new file mode 100644
index 0000000..5268af6
--- /dev/null
+++ b/resources/chars/ascii/row93.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+9300 Lun # Character é
+U+9301 Kua # Character é
+U+9302 Ling # Character é
+U+9303 Bei # Character é
+U+9304 Lu # Character é
+U+9305 Li # Character é
+U+9306 Qiang # Character é
+U+9307 Pou # Character é
+U+9308 Juan # Character é
+U+9309 Min # Character é
+U+930a Zui # Character é
+U+930b Peng # Character é
+U+930c An # Character é
+U+930d Pi # Character é
+U+930e Xian # Character é
+U+930f Ya # Character é
+U+9310 Zhui # Character é
+U+9311 Lei # Character é
+U+9312 A # Character é
+U+9313 Kong # Character é
+U+9314 Ta # Character é
+U+9315 Kun # Character é
+U+9316 Du # Character é
+U+9317 Wei # Character é
+U+9318 Chui # Character é
+U+9319 Zi # Character é
+U+931a Zheng # Character é
+U+931b Ben # Character é
+U+931c Nie # Character é
+U+931d Cong # Character é
+U+931e Qun # Character é
+U+931f Tan # Character é
+U+9320 Ding # Character é
+U+9321 Qi # Character é¡
+U+9322 Qian # Character é¢
+U+9323 Zhuo # Character é£
+U+9324 Qi # Character é¤
+U+9325 Yu # Character é¥
+U+9326 Jin # Character é¦
+U+9327 Guan # Character é§
+U+9328 Mao # Character é¨
+U+9329 Chang # Character é©
+U+932a Tian # Character éª
+U+932b Xi # Character é«
+U+932c Lian # Character é¬
+U+932d Tao # Character é
+U+932e Gu # Character é®
+U+932f Cuo # Character é¯
+U+9330 Shu # Character é°
+U+9331 Zhen # Character é±
+U+9332 Lu # Character é²
+U+9333 Meng # Character é³
+U+9334 Lu # Character é´
+U+9335 Hua # Character éµ
+U+9336 Biao # Character é¶
+U+9337 Ga # Character é·
+U+9338 Lai # Character é¸
+U+9339 Ken # Character é¹
+U+933a Kazari # Character éº
+U+933b Bu # Character é»
+U+933c Nai # Character é¼
+U+933d Wan # Character é½
+U+933e Zan # Character é¾
+U+933f ? # Character é¿
+U+9340 De # Character é
+U+9341 Xian # Character é
+U+9342 ? # Character é
+U+9343 Huo # Character é
+U+9344 Liang # Character é
+U+9345 ? # Character é
+U+9346 Men # Character é
+U+9347 Kai # Character é
+U+9348 Ying # Character é
+U+9349 Di # Character é
+U+934a Lian # Character é
+U+934b Guo # Character é
+U+934c Xian # Character é
+U+934d Du # Character é
+U+934e Tu # Character é
+U+934f Wei # Character é
+U+9350 Cong # Character é
+U+9351 Fu # Character é
+U+9352 Rou # Character é
+U+9353 Ji # Character é
+U+9354 E # Character é
+U+9355 Rou # Character é
+U+9356 Chen # Character é
+U+9357 Ti # Character é
+U+9358 Zha # Character é
+U+9359 Hong # Character é
+U+935a Yang # Character é
+U+935b Duan # Character é
+U+935c Xia # Character é
+U+935d Yu # Character é
+U+935e Keng # Character é
+U+935f Xing # Character é
+U+9360 Huang # Character é
+U+9361 Wei # Character é¡
+U+9362 Fu # Character é¢
+U+9363 Zhao # Character é£
+U+9364 Cha # Character é¤
+U+9365 Qie # Character é¥
+U+9366 She # Character é¦
+U+9367 Hong # Character é§
+U+9368 Kui # Character é¨
+U+9369 Tian # Character é©
+U+936a Mou # Character éª
+U+936b Qiao # Character é«
+U+936c Qiao # Character é¬
+U+936d Hou # Character é
+U+936e Tou # Character é®
+U+936f Cong # Character é¯
+U+9370 Huan # Character é°
+U+9371 Ye # Character é±
+U+9372 Min # Character é²
+U+9373 Jian # Character é³
+U+9374 Duan # Character é´
+U+9375 Jian # Character éµ
+U+9376 Song # Character é¶
+U+9377 Kui # Character é·
+U+9378 Hu # Character é¸
+U+9379 Xuan # Character é¹
+U+937a Duo # Character éº
+U+937b Jie # Character é»
+U+937c Zhen # Character é¼
+U+937d Bian # Character é½
+U+937e Zhong # Character é¾
+U+937f Zi # Character é¿
+U+9380 Xiu # Character é
+U+9381 Ye # Character é
+U+9382 Mei # Character é
+U+9383 Pai # Character é
+U+9384 Ai # Character é
+U+9385 Jie # Character é
+U+9386 ? # Character é
+U+9387 Mei # Character é
+U+9388 Chuo # Character é
+U+9389 Ta # Character é
+U+938a Bang # Character é
+U+938b Xia # Character é
+U+938c Lian # Character é
+U+938d Suo # Character é
+U+938e Xi # Character é
+U+938f Liu # Character é
+U+9390 Zu # Character é
+U+9391 Ye # Character é
+U+9392 Nou # Character é
+U+9393 Weng # Character é
+U+9394 Rong # Character é
+U+9395 Tang # Character é
+U+9396 Suo # Character é
+U+9397 Qiang # Character é
+U+9398 Ge # Character é
+U+9399 Shuo # Character é
+U+939a Chui # Character é
+U+939b Bo # Character é
+U+939c Pan # Character é
+U+939d Sa # Character é
+U+939e Bi # Character é
+U+939f Sang # Character é
+U+93a0 Gang # Character é
+U+93a1 Zi # Character é¡
+U+93a2 Wu # Character é¢
+U+93a3 Ying # Character é£
+U+93a4 Huang # Character é¤
+U+93a5 Tiao # Character é¥
+U+93a6 Liu # Character é¦
+U+93a7 Kai # Character é§
+U+93a8 Sun # Character é¨
+U+93a9 Sha # Character é©
+U+93aa Sou # Character éª
+U+93ab Wan # Character é«
+U+93ac Hao # Character é¬
+U+93ad Zhen # Character é
+U+93ae Zhen # Character é®
+U+93af Luo # Character é¯
+U+93b0 Yi # Character é°
+U+93b1 Yuan # Character é±
+U+93b2 Tang # Character é²
+U+93b3 Nie # Character é³
+U+93b4 Xi # Character é´
+U+93b5 Jia # Character éµ
+U+93b6 Ge # Character é¶
+U+93b7 Ma # Character é·
+U+93b8 Juan # Character é¸
+U+93b9 Kasugai # Character é¹
+U+93ba Habaki # Character éº
+U+93bb Suo # Character é»
+U+93bc ? # Character é¼
+U+93bd ? # Character é½
+U+93be ? # Character é¾
+U+93bf Na # Character é¿
+U+93c0 Lu # Character é
+U+93c1 Suo # Character é
+U+93c2 Ou # Character é
+U+93c3 Zu # Character é
+U+93c4 Tuan # Character é
+U+93c5 Xiu # Character é
+U+93c6 Guan # Character é
+U+93c7 Xuan # Character é
+U+93c8 Lian # Character é
+U+93c9 Shou # Character é
+U+93ca Ao # Character é
+U+93cb Man # Character é
+U+93cc Mo # Character é
+U+93cd Luo # Character é
+U+93ce Bi # Character é
+U+93cf Wei # Character é
+U+93d0 Liu # Character é
+U+93d1 Di # Character é
+U+93d2 Qiao # Character é
+U+93d3 Cong # Character é
+U+93d4 Yi # Character é
+U+93d5 Lu # Character é
+U+93d6 Ao # Character é
+U+93d7 Keng # Character é
+U+93d8 Qiang # Character é
+U+93d9 Cui # Character é
+U+93da Qi # Character é
+U+93db Chang # Character é
+U+93dc Tang # Character é
+U+93dd Man # Character é
+U+93de Yong # Character é
+U+93df Chan # Character é
+U+93e0 Feng # Character é
+U+93e1 Jing # Character é¡
+U+93e2 Biao # Character é¢
+U+93e3 Shu # Character é£
+U+93e4 Lou # Character é¤
+U+93e5 Xiu # Character é¥
+U+93e6 Cong # Character é¦
+U+93e7 Long # Character é§
+U+93e8 Zan # Character é¨
+U+93e9 Jian # Character é©
+U+93ea Cao # Character éª
+U+93eb Li # Character é«
+U+93ec Xia # Character é¬
+U+93ed Xi # Character é
+U+93ee Kang # Character é®
+U+93ef ? # Character é¯
+U+93f0 Beng # Character é°
+U+93f1 ? # Character é±
+U+93f2 ? # Character é²
+U+93f3 Zheng # Character é³
+U+93f4 Lu # Character é´
+U+93f5 Hua # Character éµ
+U+93f6 Ji # Character é¶
+U+93f7 Pu # Character é·
+U+93f8 Hui # Character é¸
+U+93f9 Qiang # Character é¹
+U+93fa Po # Character éº
+U+93fb Lin # Character é»
+U+93fc Suo # Character é¼
+U+93fd Xiu # Character é½
+U+93fe San # Character é¾
+U+93ff Cheng # Character é¿
diff --git a/resources/chars/ascii/row94.trans b/resources/chars/ascii/row94.trans
new file mode 100644
index 0000000..605178c
--- /dev/null
+++ b/resources/chars/ascii/row94.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+9400 Kui # Character é
+U+9401 Si # Character é
+U+9402 Liu # Character é
+U+9403 Nao # Character é
+U+9404 Heng # Character é
+U+9405 Pie # Character é
+U+9406 Sui # Character é
+U+9407 Fan # Character é
+U+9408 Qiao # Character é
+U+9409 Quan # Character é
+U+940a Yang # Character é
+U+940b Tang # Character é
+U+940c Xiang # Character é
+U+940d Jue # Character é
+U+940e Jiao # Character é
+U+940f Zun # Character é
+U+9410 Liao # Character é
+U+9411 Jie # Character é
+U+9412 Lao # Character é
+U+9413 Dui # Character é
+U+9414 Tan # Character é
+U+9415 Zan # Character é
+U+9416 Ji # Character é
+U+9417 Jian # Character é
+U+9418 Zhong # Character é
+U+9419 Deng # Character é
+U+941a Ya # Character é
+U+941b Ying # Character é
+U+941c Dui # Character é
+U+941d Jue # Character é
+U+941e Nou # Character é
+U+941f Ti # Character é
+U+9420 Pu # Character é
+U+9421 Tie # Character é¡
+U+9422 ? # Character é¢
+U+9423 ? # Character é£
+U+9424 Ding # Character é¤
+U+9425 Shan # Character é¥
+U+9426 Kai # Character é¦
+U+9427 Jian # Character é§
+U+9428 Fei # Character é¨
+U+9429 Sui # Character é©
+U+942a Lu # Character éª
+U+942b Juan # Character é«
+U+942c Hui # Character é¬
+U+942d Yu # Character é
+U+942e Lian # Character é®
+U+942f Zhuo # Character é¯
+U+9430 Qiao # Character é°
+U+9431 Qian # Character é±
+U+9432 Zhuo # Character é²
+U+9433 Lei # Character é³
+U+9434 Bi # Character é´
+U+9435 Tie # Character éµ
+U+9436 Huan # Character é¶
+U+9437 Ye # Character é·
+U+9438 Duo # Character é¸
+U+9439 Guo # Character é¹
+U+943a Dang # Character éº
+U+943b Ju # Character é»
+U+943c Fen # Character é¼
+U+943d Da # Character é½
+U+943e Bei # Character é¾
+U+943f Yi # Character é¿
+U+9440 Ai # Character é
+U+9441 Zong # Character é
+U+9442 Xun # Character é
+U+9443 Diao # Character é
+U+9444 Zhu # Character é
+U+9445 Heng # Character é
+U+9446 Zhui # Character é
+U+9447 Ji # Character é
+U+9448 Nie # Character é
+U+9449 Ta # Character é
+U+944a Huo # Character é
+U+944b Qing # Character é
+U+944c Bin # Character é
+U+944d Ying # Character é
+U+944e Kui # Character é
+U+944f Ning # Character é
+U+9450 Xu # Character é
+U+9451 Jian # Character é
+U+9452 Jian # Character é
+U+9453 Yari # Character é
+U+9454 Cha # Character é
+U+9455 Zhi # Character é
+U+9456 Mie # Character é
+U+9457 Li # Character é
+U+9458 Lei # Character é
+U+9459 Ji # Character é
+U+945a Zuan # Character é
+U+945b Kuang # Character é
+U+945c Shang # Character é
+U+945d Peng # Character é
+U+945e La # Character é
+U+945f Du # Character é
+U+9460 Shuo # Character é
+U+9461 Chuo # Character é¡
+U+9462 Lu # Character é¢
+U+9463 Biao # Character é£
+U+9464 Bao # Character é¤
+U+9465 Lu # Character é¥
+U+9466 ? # Character é¦
+U+9467 ? # Character é§
+U+9468 Long # Character é¨
+U+9469 E # Character é©
+U+946a Lu # Character éª
+U+946b Xin # Character é«
+U+946c Jian # Character é¬
+U+946d Lan # Character é
+U+946e Bo # Character é®
+U+946f Jian # Character é¯
+U+9470 Yao # Character é°
+U+9471 Chan # Character é±
+U+9472 Xiang # Character é²
+U+9473 Jian # Character é³
+U+9474 Xi # Character é´
+U+9475 Guan # Character éµ
+U+9476 Cang # Character é¶
+U+9477 Nie # Character é·
+U+9478 Lei # Character é¸
+U+9479 Cuan # Character é¹
+U+947a Qu # Character éº
+U+947b Pan # Character é»
+U+947c Luo # Character é¼
+U+947d Zuan # Character é½
+U+947e Luan # Character é¾
+U+947f Zao # Character é¿
+U+9480 Nie # Character é
+U+9481 Jue # Character é
+U+9482 Tang # Character é
+U+9483 Shu # Character é
+U+9484 Lan # Character é
+U+9485 Jin # Character é
+U+9486 Qiu # Character é
+U+9487 Yi # Character é
+U+9488 Zhen # Character é
+U+9489 Ding # Character é
+U+948a Zhao # Character é
+U+948b Po # Character é
+U+948c Diao # Character é
+U+948d Tu # Character é
+U+948e Qian # Character é
+U+948f Chuan # Character é
+U+9490 Shan # Character é
+U+9491 Ji # Character é
+U+9492 Fan # Character é
+U+9493 Diao # Character é
+U+9494 Men # Character é
+U+9495 Nu # Character é
+U+9496 Xi # Character é
+U+9497 Chai # Character é
+U+9498 Xing # Character é
+U+9499 Gai # Character é
+U+949a Bu # Character é
+U+949b Tai # Character é
+U+949c Ju # Character é
+U+949d Dun # Character é
+U+949e Chao # Character é
+U+949f Zhong # Character é
+U+94a0 Na # Character é
+U+94a1 Bei # Character é¡
+U+94a2 Gang # Character é¢
+U+94a3 Ban # Character é£
+U+94a4 Qian # Character é¤
+U+94a5 Yao # Character é¥
+U+94a6 Qin # Character é¦
+U+94a7 Jun # Character é§
+U+94a8 Wu # Character é¨
+U+94a9 Gou # Character é©
+U+94aa Kang # Character éª
+U+94ab Fang # Character é«
+U+94ac Huo # Character é¬
+U+94ad Tou # Character é
+U+94ae Niu # Character é®
+U+94af Ba # Character é¯
+U+94b0 Yu # Character é°
+U+94b1 Qian # Character é±
+U+94b2 Zheng # Character é²
+U+94b3 Qian # Character é³
+U+94b4 Gu # Character é´
+U+94b5 Bo # Character éµ
+U+94b6 E # Character é¶
+U+94b7 Po # Character é·
+U+94b8 Bu # Character é¸
+U+94b9 Ba # Character é¹
+U+94ba Yue # Character éº
+U+94bb Zuan # Character é»
+U+94bc Mu # Character é¼
+U+94bd Dan # Character é½
+U+94be Jia # Character é¾
+U+94bf Dian # Character é¿
+U+94c0 You # Character é
+U+94c1 Tie # Character é
+U+94c2 Bo # Character é
+U+94c3 Ling # Character é
+U+94c4 Shuo # Character é
+U+94c5 Qian # Character é
+U+94c6 Liu # Character é
+U+94c7 Bao # Character é
+U+94c8 Shi # Character é
+U+94c9 Xuan # Character é
+U+94ca She # Character é
+U+94cb Bi # Character é
+U+94cc Ni # Character é
+U+94cd Pi # Character é
+U+94ce Duo # Character é
+U+94cf Xing # Character é
+U+94d0 Kao # Character é
+U+94d1 Lao # Character é
+U+94d2 Er # Character é
+U+94d3 Mang # Character é
+U+94d4 Ya # Character é
+U+94d5 You # Character é
+U+94d6 Cheng # Character é
+U+94d7 Jia # Character é
+U+94d8 Ye # Character é
+U+94d9 Nao # Character é
+U+94da Zhi # Character é
+U+94db Dang # Character é
+U+94dc Tong # Character é
+U+94dd Lu # Character é
+U+94de Diao # Character é
+U+94df Yin # Character é
+U+94e0 Kai # Character é
+U+94e1 Zha # Character é¡
+U+94e2 Zhu # Character é¢
+U+94e3 Xian # Character é£
+U+94e4 Ting # Character é¤
+U+94e5 Diu # Character é¥
+U+94e6 Xian # Character é¦
+U+94e7 Hua # Character é§
+U+94e8 Quan # Character é¨
+U+94e9 Sha # Character é©
+U+94ea Jia # Character éª
+U+94eb Yao # Character é«
+U+94ec Ge # Character é¬
+U+94ed Ming # Character é
+U+94ee Zheng # Character é®
+U+94ef Se # Character é¯
+U+94f0 Jiao # Character é°
+U+94f1 Yi # Character é±
+U+94f2 Chan # Character é²
+U+94f3 Chong # Character é³
+U+94f4 Tang # Character é´
+U+94f5 An # Character éµ
+U+94f6 Yin # Character é¶
+U+94f7 Ru # Character é·
+U+94f8 Zhu # Character é¸
+U+94f9 Lao # Character é¹
+U+94fa Pu # Character éº
+U+94fb Wu # Character é»
+U+94fc Lai # Character é¼
+U+94fd Te # Character é½
+U+94fe Lian # Character é¾
+U+94ff Keng # Character é¿
diff --git a/resources/chars/ascii/row95.trans b/resources/chars/ascii/row95.trans
new file mode 100644
index 0000000..fc5e778
--- /dev/null
+++ b/resources/chars/ascii/row95.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+9500 Xiao # Character é
+U+9501 Suo # Character é
+U+9502 Li # Character é
+U+9503 Zheng # Character é
+U+9504 Chu # Character é
+U+9505 Guo # Character é
+U+9506 Gao # Character é
+U+9507 Tie # Character é
+U+9508 Xiu # Character é
+U+9509 Cuo # Character é
+U+950a Lue # Character é
+U+950b Feng # Character é
+U+950c Xin # Character é
+U+950d Liu # Character é
+U+950e Kai # Character é
+U+950f Jian # Character é
+U+9510 Rui # Character é
+U+9511 Ti # Character é
+U+9512 Lang # Character é
+U+9513 Qian # Character é
+U+9514 Ju # Character é
+U+9515 A # Character é
+U+9516 Qiang # Character é
+U+9517 Duo # Character é
+U+9518 Tian # Character é
+U+9519 Cuo # Character é
+U+951a Mao # Character é
+U+951b Ben # Character é
+U+951c Qi # Character é
+U+951d De # Character é
+U+951e Kua # Character é
+U+951f Kun # Character é
+U+9520 Chang # Character é
+U+9521 Xi # Character é¡
+U+9522 Gu # Character é¢
+U+9523 Luo # Character é£
+U+9524 Chui # Character é¤
+U+9525 Zhui # Character é¥
+U+9526 Jin # Character é¦
+U+9527 Zhi # Character é§
+U+9528 Xian # Character é¨
+U+9529 Juan # Character é©
+U+952a Huo # Character éª
+U+952b Pou # Character é«
+U+952c Tan # Character é¬
+U+952d Ding # Character é
+U+952e Jian # Character é®
+U+952f Ju # Character é¯
+U+9530 Meng # Character é°
+U+9531 Zi # Character é±
+U+9532 Qie # Character é²
+U+9533 Ying # Character é³
+U+9534 Kai # Character é´
+U+9535 Qiang # Character éµ
+U+9536 Song # Character é¶
+U+9537 E # Character é·
+U+9538 Cha # Character é¸
+U+9539 Qiao # Character é¹
+U+953a Zhong # Character éº
+U+953b Duan # Character é»
+U+953c Sou # Character é¼
+U+953d Huang # Character é½
+U+953e Huan # Character é¾
+U+953f Ai # Character é¿
+U+9540 Du # Character é
+U+9541 Mei # Character é
+U+9542 Lou # Character é
+U+9543 Zi # Character é
+U+9544 Fei # Character é
+U+9545 Mei # Character é
+U+9546 Mo # Character é
+U+9547 Zhen # Character é
+U+9548 Bo # Character é
+U+9549 Ge # Character é
+U+954a Nie # Character é
+U+954b Tang # Character é
+U+954c Juan # Character é
+U+954d Nie # Character é
+U+954e Na # Character é
+U+954f Liu # Character é
+U+9550 Hao # Character é
+U+9551 Bang # Character é
+U+9552 Yi # Character é
+U+9553 Jia # Character é
+U+9554 Bin # Character é
+U+9555 Rong # Character é
+U+9556 Biao # Character é
+U+9557 Tang # Character é
+U+9558 Man # Character é
+U+9559 Luo # Character é
+U+955a Beng # Character é
+U+955b Yong # Character é
+U+955c Jing # Character é
+U+955d Di # Character é
+U+955e Zu # Character é
+U+955f Xuan # Character é
+U+9560 Liu # Character é
+U+9561 Tan # Character é¡
+U+9562 Jue # Character é¢
+U+9563 Liao # Character é£
+U+9564 Pu # Character é¤
+U+9565 Lu # Character é¥
+U+9566 Dui # Character é¦
+U+9567 Lan # Character é§
+U+9568 Pu # Character é¨
+U+9569 Cuan # Character é©
+U+956a Qiang # Character éª
+U+956b Deng # Character é«
+U+956c Huo # Character é¬
+U+956d Lei # Character é
+U+956e Huan # Character é®
+U+956f Zhuo # Character é¯
+U+9570 Lian # Character é°
+U+9571 Yi # Character é±
+U+9572 Cha # Character é²
+U+9573 Biao # Character é³
+U+9574 La # Character é´
+U+9575 Chan # Character éµ
+U+9576 Xiang # Character é¶
+U+9577 Chang # Character é·
+U+9578 Chang # Character é¸
+U+9579 Jiu # Character é¹
+U+957a Ao # Character éº
+U+957b Die # Character é»
+U+957c Qu # Character é¼
+U+957d Liao # Character é½
+U+957e Mi # Character é¾
+U+957f Chang # Character é¿
+U+9580 Men # Character é
+U+9581 Ma # Character é
+U+9582 Shuan # Character é
+U+9583 Shan # Character é
+U+9584 Huo # Character é
+U+9585 Men # Character é
+U+9586 Yan # Character é
+U+9587 Bi # Character é
+U+9588 Han # Character é
+U+9589 Bi # Character é
+U+958a San # Character é
+U+958b Kai # Character é
+U+958c Kang # Character é
+U+958d Beng # Character é
+U+958e Hong # Character é
+U+958f Run # Character é
+U+9590 San # Character é
+U+9591 Xian # Character é
+U+9592 Xian # Character é
+U+9593 Jian # Character é
+U+9594 Min # Character é
+U+9595 Xia # Character é
+U+9596 Yuru # Character é
+U+9597 Dou # Character é
+U+9598 Zha # Character é
+U+9599 Nao # Character é
+U+959a Jian # Character é
+U+959b Peng # Character é
+U+959c Xia # Character é
+U+959d Ling # Character é
+U+959e Bian # Character é
+U+959f Bi # Character é
+U+95a0 Run # Character é
+U+95a1 He # Character é¡
+U+95a2 Guan # Character é¢
+U+95a3 Ge # Character é£
+U+95a4 Ge # Character é¤
+U+95a5 Fa # Character é¥
+U+95a6 Chu # Character é¦
+U+95a7 Hong # Character é§
+U+95a8 Gui # Character é¨
+U+95a9 Min # Character é©
+U+95aa Se # Character éª
+U+95ab Kun # Character é«
+U+95ac Lang # Character é¬
+U+95ad Lu # Character é
+U+95ae Ting # Character é®
+U+95af Sha # Character é¯
+U+95b0 Ju # Character é°
+U+95b1 Yue # Character é±
+U+95b2 Yue # Character é²
+U+95b3 Chan # Character é³
+U+95b4 Qu # Character é´
+U+95b5 Lin # Character éµ
+U+95b6 Chang # Character é¶
+U+95b7 Shai # Character é·
+U+95b8 Kun # Character é¸
+U+95b9 Yan # Character é¹
+U+95ba Min # Character éº
+U+95bb Yan # Character é»
+U+95bc E # Character é¼
+U+95bd Hun # Character é½
+U+95be Yu # Character é¾
+U+95bf Wen # Character é¿
+U+95c0 Xiang # Character é
+U+95c1 Bao # Character é
+U+95c2 Xiang # Character é
+U+95c3 Qu # Character é
+U+95c4 Yao # Character é
+U+95c5 Wen # Character é
+U+95c6 Ban # Character é
+U+95c7 An # Character é
+U+95c8 Wei # Character é
+U+95c9 Yin # Character é
+U+95ca Kuo # Character é
+U+95cb Que # Character é
+U+95cc Lan # Character é
+U+95cd Du # Character é
+U+95ce ? # Character é
+U+95cf Phwung # Character é
+U+95d0 Tian # Character é
+U+95d1 Nie # Character é
+U+95d2 Ta # Character é
+U+95d3 Kai # Character é
+U+95d4 He # Character é
+U+95d5 Que # Character é
+U+95d6 Chuang # Character é
+U+95d7 Guan # Character é
+U+95d8 Dou # Character é
+U+95d9 Qi # Character é
+U+95da Kui # Character é
+U+95db Tang # Character é
+U+95dc Guan # Character é
+U+95dd Piao # Character é
+U+95de Kan # Character é
+U+95df Xi # Character é
+U+95e0 Hui # Character é
+U+95e1 Chan # Character é¡
+U+95e2 Pi # Character é¢
+U+95e3 Dang # Character é£
+U+95e4 Huan # Character é¤
+U+95e5 Ta # Character é¥
+U+95e6 Wen # Character é¦
+U+95e7 ? # Character é§
+U+95e8 Men # Character é¨
+U+95e9 Shuan # Character é©
+U+95ea Shan # Character éª
+U+95eb Yan # Character é«
+U+95ec Han # Character é¬
+U+95ed Bi # Character é
+U+95ee Wen # Character é®
+U+95ef Chuang # Character é¯
+U+95f0 Run # Character é°
+U+95f1 Wei # Character é±
+U+95f2 Xian # Character é²
+U+95f3 Hong # Character é³
+U+95f4 Jian # Character é´
+U+95f5 Min # Character éµ
+U+95f6 Kang # Character é¶
+U+95f7 Men # Character é·
+U+95f8 Zha # Character é¸
+U+95f9 Nao # Character é¹
+U+95fa Gui # Character éº
+U+95fb Wen # Character é»
+U+95fc Ta # Character é¼
+U+95fd Min # Character é½
+U+95fe Lu # Character é¾
+U+95ff Kai # Character é¿
diff --git a/resources/chars/ascii/row96.trans b/resources/chars/ascii/row96.trans
new file mode 100644
index 0000000..b81f419
--- /dev/null
+++ b/resources/chars/ascii/row96.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+9600 Fa # Character é
+U+9601 Ge # Character é
+U+9602 He # Character é
+U+9603 Kun # Character é
+U+9604 Jiu # Character é
+U+9605 Yue # Character é
+U+9606 Lang # Character é
+U+9607 Du # Character é
+U+9608 Yu # Character é
+U+9609 Yan # Character é
+U+960a Chang # Character é
+U+960b Xi # Character é
+U+960c Wen # Character é
+U+960d Hun # Character é
+U+960e Yan # Character é
+U+960f E # Character é
+U+9610 Chan # Character é
+U+9611 Lan # Character é
+U+9612 Qu # Character é
+U+9613 Hui # Character é
+U+9614 Kuo # Character é
+U+9615 Que # Character é
+U+9616 Ge # Character é
+U+9617 Tian # Character é
+U+9618 Ta # Character é
+U+9619 Que # Character é
+U+961a Kan # Character é
+U+961b Huan # Character é
+U+961c Fu # Character é
+U+961d Fu # Character é
+U+961e Le # Character é
+U+961f Dui # Character é
+U+9620 Xin # Character é
+U+9621 Qian # Character é¡
+U+9622 Wu # Character é¢
+U+9623 Yi # Character é£
+U+9624 Tuo # Character é¤
+U+9625 Yin # Character é¥
+U+9626 Yang # Character é¦
+U+9627 Dou # Character é§
+U+9628 E # Character é¨
+U+9629 Sheng # Character é©
+U+962a Ban # Character éª
+U+962b Pei # Character é«
+U+962c Keng # Character é¬
+U+962d Yun # Character é
+U+962e Ruan # Character é®
+U+962f Zhi # Character é¯
+U+9630 Pi # Character é°
+U+9631 Jing # Character é±
+U+9632 Fang # Character é²
+U+9633 Yang # Character é³
+U+9634 Yin # Character é´
+U+9635 Zhen # Character éµ
+U+9636 Jie # Character é¶
+U+9637 Cheng # Character é·
+U+9638 E # Character é¸
+U+9639 Qu # Character é¹
+U+963a Di # Character éº
+U+963b Zu # Character é»
+U+963c Zuo # Character é¼
+U+963d Dian # Character é½
+U+963e Ling # Character é¾
+U+963f A # Character é¿
+U+9640 Tuo # Character é
+U+9641 Tuo # Character é
+U+9642 Po # Character é
+U+9643 Bing # Character é
+U+9644 Fu # Character é
+U+9645 Ji # Character é
+U+9646 Lu # Character é
+U+9647 Long # Character é
+U+9648 Chen # Character é
+U+9649 Xing # Character é
+U+964a Duo # Character é
+U+964b Lou # Character é
+U+964c Mo # Character é
+U+964d Jiang # Character é
+U+964e Shu # Character é
+U+964f Duo # Character é
+U+9650 Xian # Character é
+U+9651 Er # Character é
+U+9652 Gui # Character é
+U+9653 Yu # Character é
+U+9654 Gai # Character é
+U+9655 Shan # Character é
+U+9656 Xun # Character é
+U+9657 Qiao # Character é
+U+9658 Xing # Character é
+U+9659 Chun # Character é
+U+965a Fu # Character é
+U+965b Bi # Character é
+U+965c Xia # Character é
+U+965d Shan # Character é
+U+965e Sheng # Character é
+U+965f Zhi # Character é
+U+9660 Pu # Character é
+U+9661 Dou # Character é¡
+U+9662 Yuan # Character é¢
+U+9663 Zhen # Character é£
+U+9664 Chu # Character é¤
+U+9665 Xian # Character é¥
+U+9666 Tou # Character é¦
+U+9667 Nie # Character é§
+U+9668 Yun # Character é¨
+U+9669 Xian # Character é©
+U+966a Pei # Character éª
+U+966b Pei # Character é«
+U+966c Zou # Character é¬
+U+966d Yi # Character é
+U+966e Dui # Character é®
+U+966f Lun # Character é¯
+U+9670 Yin # Character é°
+U+9671 Ju # Character é±
+U+9672 Chui # Character é²
+U+9673 Chen # Character é³
+U+9674 Pi # Character é´
+U+9675 Ling # Character éµ
+U+9676 Tao # Character é¶
+U+9677 Xian # Character é·
+U+9678 Lu # Character é¸
+U+9679 Sheng # Character é¹
+U+967a Xian # Character éº
+U+967b Yin # Character é»
+U+967c Zhu # Character é¼
+U+967d Yang # Character é½
+U+967e Reng # Character é¾
+U+967f Shan # Character é¿
+U+9680 Chong # Character é
+U+9681 Yan # Character é
+U+9682 Yin # Character é
+U+9683 Yu # Character é
+U+9684 Ti # Character é
+U+9685 Yu # Character é
+U+9686 Long # Character é
+U+9687 Wei # Character é
+U+9688 Wei # Character é
+U+9689 Nie # Character é
+U+968a Dui # Character é
+U+968b Sui # Character é
+U+968c An # Character é
+U+968d Huang # Character é
+U+968e Jie # Character é
+U+968f Sui # Character é
+U+9690 Yin # Character é
+U+9691 Gai # Character é
+U+9692 Yan # Character é
+U+9693 Hui # Character é
+U+9694 Ge # Character é
+U+9695 Yun # Character é
+U+9696 Wu # Character é
+U+9697 Wei # Character é
+U+9698 Ai # Character é
+U+9699 Xi # Character é
+U+969a Tang # Character é
+U+969b Ji # Character é
+U+969c Zhang # Character é
+U+969d Dao # Character é
+U+969e Ao # Character é
+U+969f Xi # Character é
+U+96a0 Yin # Character é
+U+96a1 ? # Character é¡
+U+96a2 Rao # Character é¢
+U+96a3 Lin # Character é£
+U+96a4 Tui # Character é¤
+U+96a5 Deng # Character é¥
+U+96a6 Pi # Character é¦
+U+96a7 Sui # Character é§
+U+96a8 Sui # Character é¨
+U+96a9 Yu # Character é©
+U+96aa Xian # Character éª
+U+96ab Fen # Character é«
+U+96ac Ni # Character é¬
+U+96ad Er # Character é
+U+96ae Ji # Character é®
+U+96af Dao # Character é¯
+U+96b0 Xi # Character é°
+U+96b1 Yin # Character é±
+U+96b2 E # Character é²
+U+96b3 Hui # Character é³
+U+96b4 Long # Character é´
+U+96b5 Xi # Character éµ
+U+96b6 Li # Character é¶
+U+96b7 Li # Character é·
+U+96b8 Li # Character é¸
+U+96b9 Zhui # Character é¹
+U+96ba He # Character éº
+U+96bb Zhi # Character é»
+U+96bc Zhun # Character é¼
+U+96bd Jun # Character é½
+U+96be Nan # Character é¾
+U+96bf Yi # Character é¿
+U+96c0 Que # Character é
+U+96c1 Yan # Character é
+U+96c2 Qian # Character é
+U+96c3 Ya # Character é
+U+96c4 Xiong # Character é
+U+96c5 Ya # Character é
+U+96c6 Ji # Character é
+U+96c7 Gu # Character é
+U+96c8 Huan # Character é
+U+96c9 Zhi # Character é
+U+96ca Gou # Character é
+U+96cb Jun # Character é
+U+96cc Ci # Character é
+U+96cd Yong # Character é
+U+96ce Ju # Character é
+U+96cf Chu # Character é
+U+96d0 Hu # Character é
+U+96d1 Za # Character é
+U+96d2 Luo # Character é
+U+96d3 Yu # Character é
+U+96d4 Chou # Character é
+U+96d5 Diao # Character é
+U+96d6 Sui # Character é
+U+96d7 Han # Character é
+U+96d8 Huo # Character é
+U+96d9 Shuang # Character é
+U+96da Guan # Character é
+U+96db Chu # Character é
+U+96dc Za # Character é
+U+96dd Yong # Character é
+U+96de Ji # Character é
+U+96df Xi # Character é
+U+96e0 Chou # Character é
+U+96e1 Liu # Character é¡
+U+96e2 Li # Character é¢
+U+96e3 Nan # Character é£
+U+96e4 Xue # Character é¤
+U+96e5 Za # Character é¥
+U+96e6 Ji # Character é¦
+U+96e7 Ji # Character é§
+U+96e8 Yu # Character é¨
+U+96e9 Yu # Character é©
+U+96ea Xue # Character éª
+U+96eb Na # Character é«
+U+96ec Fou # Character é¬
+U+96ed Se # Character é
+U+96ee Mu # Character é®
+U+96ef Wen # Character é¯
+U+96f0 Fen # Character é°
+U+96f1 Pang # Character é±
+U+96f2 Yun # Character é²
+U+96f3 Li # Character é³
+U+96f4 Li # Character é´
+U+96f5 Ang # Character éµ
+U+96f6 Ling # Character é¶
+U+96f7 Lei # Character é·
+U+96f8 An # Character é¸
+U+96f9 Bao # Character é¹
+U+96fa Meng # Character éº
+U+96fb Dian # Character é»
+U+96fc Dang # Character é¼
+U+96fd Xing # Character é½
+U+96fe Wu # Character é¾
+U+96ff Zhao # Character é¿
diff --git a/resources/chars/ascii/row97.trans b/resources/chars/ascii/row97.trans
new file mode 100644
index 0000000..c13c394
--- /dev/null
+++ b/resources/chars/ascii/row97.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+9700 Xu # Character é
+U+9701 Ji # Character é
+U+9702 Mu # Character é
+U+9703 Chen # Character é
+U+9704 Xiao # Character é
+U+9705 Zha # Character é
+U+9706 Ting # Character é
+U+9707 Zhen # Character é
+U+9708 Pei # Character é
+U+9709 Mei # Character é
+U+970a Ling # Character é
+U+970b Qi # Character é
+U+970c Chou # Character é
+U+970d Huo # Character é
+U+970e Sha # Character é
+U+970f Fei # Character é
+U+9710 Weng # Character é
+U+9711 Zhan # Character é
+U+9712 Yin # Character é
+U+9713 Ni # Character é
+U+9714 Chou # Character é
+U+9715 Tun # Character é
+U+9716 Lin # Character é
+U+9717 ? # Character é
+U+9718 Dong # Character é
+U+9719 Ying # Character é
+U+971a Wu # Character é
+U+971b Ling # Character é
+U+971c Shuang # Character é
+U+971d Ling # Character é
+U+971e Xia # Character é
+U+971f Hong # Character é
+U+9720 Yin # Character é
+U+9721 Mo # Character é¡
+U+9722 Mai # Character é¢
+U+9723 Yun # Character é£
+U+9724 Liu # Character é¤
+U+9725 Meng # Character é¥
+U+9726 Bin # Character é¦
+U+9727 Wu # Character é§
+U+9728 Wei # Character é¨
+U+9729 Huo # Character é©
+U+972a Yin # Character éª
+U+972b Xi # Character é«
+U+972c Yi # Character é¬
+U+972d Ai # Character é
+U+972e Dan # Character é®
+U+972f Deng # Character é¯
+U+9730 Xian # Character é°
+U+9731 Yu # Character é±
+U+9732 Lu # Character é²
+U+9733 Long # Character é³
+U+9734 Dai # Character é´
+U+9735 Ji # Character éµ
+U+9736 Pang # Character é¶
+U+9737 Yang # Character é·
+U+9738 Ba # Character é¸
+U+9739 Pi # Character é¹
+U+973a Wei # Character éº
+U+973b ? # Character é»
+U+973c Xi # Character é¼
+U+973d Ji # Character é½
+U+973e Mai # Character é¾
+U+973f Meng # Character é¿
+U+9740 Meng # Character é
+U+9741 Lei # Character é
+U+9742 Li # Character é
+U+9743 Huo # Character é
+U+9744 Ai # Character é
+U+9745 Fei # Character é
+U+9746 Dai # Character é
+U+9747 Long # Character é
+U+9748 Ling # Character é
+U+9749 Ai # Character é
+U+974a Feng # Character é
+U+974b Li # Character é
+U+974c Bao # Character é
+U+974d ? # Character é
+U+974e He # Character é
+U+974f He # Character é
+U+9750 Bing # Character é
+U+9751 Qing # Character é
+U+9752 Qing # Character é
+U+9753 Jing # Character é
+U+9754 Tian # Character é
+U+9755 Zhen # Character é
+U+9756 Jing # Character é
+U+9757 Cheng # Character é
+U+9758 Qing # Character é
+U+9759 Jing # Character é
+U+975a Jing # Character é
+U+975b Dian # Character é
+U+975c Jing # Character é
+U+975d Tian # Character é
+U+975e Fei # Character é
+U+975f Fei # Character é
+U+9760 Kao # Character é
+U+9761 Mi # Character é¡
+U+9762 Mian # Character é¢
+U+9763 Mian # Character é£
+U+9764 Pao # Character é¤
+U+9765 Ye # Character é¥
+U+9766 Tian # Character é¦
+U+9767 Hui # Character é§
+U+9768 Ye # Character é¨
+U+9769 Ge # Character é©
+U+976a Ding # Character éª
+U+976b Cha # Character é«
+U+976c Jian # Character é¬
+U+976d Ren # Character é
+U+976e Di # Character é®
+U+976f Du # Character é¯
+U+9770 Wu # Character é°
+U+9771 Ren # Character é±
+U+9772 Qin # Character é²
+U+9773 Jin # Character é³
+U+9774 Xue # Character é´
+U+9775 Niu # Character éµ
+U+9776 Ba # Character é¶
+U+9777 Yin # Character é·
+U+9778 Sa # Character é¸
+U+9779 Na # Character é¹
+U+977a Mo # Character éº
+U+977b Zu # Character é»
+U+977c Da # Character é¼
+U+977d Ban # Character é½
+U+977e Yi # Character é¾
+U+977f Yao # Character é¿
+U+9780 Tao # Character é
+U+9781 Tuo # Character é
+U+9782 Jia # Character é
+U+9783 Hong # Character é
+U+9784 Pao # Character é
+U+9785 Yang # Character é
+U+9786 Tomo # Character é
+U+9787 Yin # Character é
+U+9788 Jia # Character é
+U+9789 Tao # Character é
+U+978a Ji # Character é
+U+978b Xie # Character é
+U+978c An # Character é
+U+978d An # Character é
+U+978e Hen # Character é
+U+978f Gong # Character é
+U+9790 Kohaze # Character é
+U+9791 Da # Character é
+U+9792 Qiao # Character é
+U+9793 Ting # Character é
+U+9794 Wan # Character é
+U+9795 Ying # Character é
+U+9796 Sui # Character é
+U+9797 Tiao # Character é
+U+9798 Qiao # Character é
+U+9799 Xuan # Character é
+U+979a Kong # Character é
+U+979b Beng # Character é
+U+979c Ta # Character é
+U+979d Zhang # Character é
+U+979e Bing # Character é
+U+979f Kuo # Character é
+U+97a0 Ju # Character é
+U+97a1 La # Character é¡
+U+97a2 Xie # Character é¢
+U+97a3 Rou # Character é£
+U+97a4 Bang # Character é¤
+U+97a5 Yi # Character é¥
+U+97a6 Qiu # Character é¦
+U+97a7 Qiu # Character é§
+U+97a8 He # Character é¨
+U+97a9 Xiao # Character é©
+U+97aa Mu # Character éª
+U+97ab Ju # Character é«
+U+97ac Jian # Character é¬
+U+97ad Bian # Character é
+U+97ae Di # Character é®
+U+97af Jian # Character é¯
+U+97b0 On # Character é°
+U+97b1 Tao # Character é±
+U+97b2 Gou # Character é²
+U+97b3 Ta # Character é³
+U+97b4 Bei # Character é´
+U+97b5 Xie # Character éµ
+U+97b6 Pan # Character é¶
+U+97b7 Ge # Character é·
+U+97b8 Bi # Character é¸
+U+97b9 Kuo # Character é¹
+U+97ba Tang # Character éº
+U+97bb Lou # Character é»
+U+97bc Gui # Character é¼
+U+97bd Qiao # Character é½
+U+97be Xue # Character é¾
+U+97bf Ji # Character é¿
+U+97c0 Jian # Character é
+U+97c1 Jiang # Character é
+U+97c2 Chan # Character é
+U+97c3 Da # Character é
+U+97c4 Huo # Character é
+U+97c5 Xian # Character é
+U+97c6 Qian # Character é
+U+97c7 Du # Character é
+U+97c8 Wa # Character é
+U+97c9 Jian # Character é
+U+97ca Lan # Character é
+U+97cb Wei # Character é
+U+97cc Ren # Character é
+U+97cd Fu # Character é
+U+97ce Mei # Character é
+U+97cf Juan # Character é
+U+97d0 Ge # Character é
+U+97d1 Wei # Character é
+U+97d2 Qiao # Character é
+U+97d3 Han # Character é
+U+97d4 Chang # Character é
+U+97d5 ? # Character é
+U+97d6 Rou # Character é
+U+97d7 Xun # Character é
+U+97d8 She # Character é
+U+97d9 Wei # Character é
+U+97da Ge # Character é
+U+97db Bei # Character é
+U+97dc Tao # Character é
+U+97dd Gou # Character é
+U+97de Yun # Character é
+U+97df ? # Character é
+U+97e0 Bi # Character é
+U+97e1 Wei # Character é¡
+U+97e2 Hui # Character é¢
+U+97e3 Du # Character é£
+U+97e4 Wa # Character é¤
+U+97e5 Du # Character é¥
+U+97e6 Wei # Character é¦
+U+97e7 Ren # Character é§
+U+97e8 Fu # Character é¨
+U+97e9 Han # Character é©
+U+97ea Wei # Character éª
+U+97eb Yun # Character é«
+U+97ec Tao # Character é¬
+U+97ed Jiu # Character é
+U+97ee Jiu # Character é®
+U+97ef Xian # Character é¯
+U+97f0 Xie # Character é°
+U+97f1 Xian # Character é±
+U+97f2 Ji # Character é²
+U+97f3 Yin # Character é³
+U+97f4 Za # Character é´
+U+97f5 Yun # Character éµ
+U+97f6 Shao # Character é¶
+U+97f7 Le # Character é·
+U+97f8 Peng # Character é¸
+U+97f9 Heng # Character é¹
+U+97fa Ying # Character éº
+U+97fb Yun # Character é»
+U+97fc Peng # Character é¼
+U+97fd Yin # Character é½
+U+97fe Yin # Character é¾
+U+97ff Xiang # Character é¿
diff --git a/resources/chars/ascii/row98.trans b/resources/chars/ascii/row98.trans
new file mode 100644
index 0000000..1bd9763
--- /dev/null
+++ b/resources/chars/ascii/row98.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+9800 Hu # Character é
+U+9801 Ye # Character é
+U+9802 Ding # Character é
+U+9803 Qing # Character é
+U+9804 Pan # Character é
+U+9805 Xiang # Character é
+U+9806 Shun # Character é
+U+9807 Han # Character é
+U+9808 Xu # Character é
+U+9809 Yi # Character é
+U+980a Xu # Character é
+U+980b Gu # Character é
+U+980c Song # Character é
+U+980d Kui # Character é
+U+980e Qi # Character é
+U+980f Hang # Character é
+U+9810 Yu # Character é
+U+9811 Wan # Character é
+U+9812 Ban # Character é
+U+9813 Dun # Character é
+U+9814 Di # Character é
+U+9815 Dan # Character é
+U+9816 Pan # Character é
+U+9817 Po # Character é
+U+9818 Ling # Character é
+U+9819 Ce # Character é
+U+981a Jing # Character é
+U+981b Lei # Character é
+U+981c He # Character é
+U+981d Qiao # Character é
+U+981e E # Character é
+U+981f E # Character é
+U+9820 Wei # Character é
+U+9821 Jie # Character é ¡
+U+9822 Gua # Character é ¢
+U+9823 Shen # Character é £
+U+9824 Yi # Character é ¤
+U+9825 Shen # Character é ¥
+U+9826 Hai # Character é ¦
+U+9827 Dui # Character é §
+U+9828 Pian # Character é ¨
+U+9829 Ping # Character é ©
+U+982a Lei # Character é ª
+U+982b Fu # Character é «
+U+982c Jia # Character é ¬
+U+982d Tou # Character é
+U+982e Hui # Character é ®
+U+982f Kui # Character é ¯
+U+9830 Jia # Character é °
+U+9831 Le # Character é ±
+U+9832 Tian # Character é ²
+U+9833 Cheng # Character é ³
+U+9834 Ying # Character é ´
+U+9835 Jun # Character é µ
+U+9836 Hu # Character é ¶
+U+9837 Han # Character é ·
+U+9838 Jing # Character é ¸
+U+9839 Tui # Character é ¹
+U+983a Tui # Character é º
+U+983b Pin # Character é »
+U+983c Lai # Character é ¼
+U+983d Tui # Character é ½
+U+983e Zi # Character é ¾
+U+983f Zi # Character é ¿
+U+9840 Chui # Character é¡
+U+9841 Ding # Character é¡
+U+9842 Lai # Character é¡
+U+9843 Yan # Character é¡
+U+9844 Han # Character é¡
+U+9845 Jian # Character é¡
+U+9846 Ke # Character é¡
+U+9847 Cui # Character é¡
+U+9848 Jiong # Character é¡
+U+9849 Qin # Character é¡
+U+984a Yi # Character é¡
+U+984b Sai # Character é¡
+U+984c Ti # Character é¡
+U+984d E # Character é¡
+U+984e E # Character é¡
+U+984f Yan # Character é¡
+U+9850 Hun # Character é¡
+U+9851 Kan # Character é¡
+U+9852 Yong # Character é¡
+U+9853 Zhuan # Character é¡
+U+9854 Yan # Character é¡
+U+9855 Xian # Character é¡
+U+9856 Xin # Character é¡
+U+9857 Yi # Character é¡
+U+9858 Yuan # Character é¡
+U+9859 Sang # Character é¡
+U+985a Dian # Character é¡
+U+985b Dian # Character é¡
+U+985c Jiang # Character é¡
+U+985d Ku # Character é¡
+U+985e Lei # Character é¡
+U+985f Liao # Character é¡
+U+9860 Piao # Character é¡
+U+9861 Yi # Character é¡¡
+U+9862 Man # Character é¡¢
+U+9863 Qi # Character é¡£
+U+9864 Rao # Character 顤
+U+9865 Hao # Character é¡¥
+U+9866 Qiao # Character 顦
+U+9867 Gu # Character 顧
+U+9868 Xun # Character 顨
+U+9869 Qian # Character é¡©
+U+986a Hui # Character 顪
+U+986b Zhan # Character é¡«
+U+986c Ru # Character 顬
+U+986d Hong # Character é¡
+U+986e Bin # Character é¡®
+U+986f Xian # Character 顯
+U+9870 Pin # Character é¡°
+U+9871 Lu # Character 顱
+U+9872 Lan # Character 顲
+U+9873 Nie # Character 顳
+U+9874 Quan # Character é¡´
+U+9875 Ye # Character 页
+U+9876 Ding # Character 顶
+U+9877 Qing # Character é¡·
+U+9878 Han # Character 顸
+U+9879 Xiang # Character 项
+U+987a Shun # Character 顺
+U+987b Xu # Character é¡»
+U+987c Xu # Character 顼
+U+987d Wan # Character 顽
+U+987e Gu # Character 顾
+U+987f Dun # Character é¡¿
+U+9880 Qi # Character é¢
+U+9881 Ban # Character é¢
+U+9882 Song # Character é¢
+U+9883 Hang # Character é¢
+U+9884 Yu # Character é¢
+U+9885 Lu # Character é¢
+U+9886 Ling # Character é¢
+U+9887 Po # Character é¢
+U+9888 Jing # Character é¢
+U+9889 Jie # Character é¢
+U+988a Jia # Character é¢
+U+988b Tian # Character é¢
+U+988c Han # Character é¢
+U+988d Ying # Character é¢
+U+988e Jiong # Character é¢
+U+988f Hai # Character é¢
+U+9890 Yi # Character é¢
+U+9891 Pin # Character é¢
+U+9892 Hui # Character é¢
+U+9893 Tui # Character é¢
+U+9894 Han # Character é¢
+U+9895 Ying # Character é¢
+U+9896 Ying # Character é¢
+U+9897 Ke # Character é¢
+U+9898 Ti # Character é¢
+U+9899 Yong # Character é¢
+U+989a E # Character é¢
+U+989b Zhuan # Character é¢
+U+989c Yan # Character é¢
+U+989d E # Character é¢
+U+989e Nie # Character é¢
+U+989f Man # Character é¢
+U+98a0 Dian # Character é¢
+U+98a1 Sang # Character 颡
+U+98a2 Hao # Character 颢
+U+98a3 Lei # Character 颣
+U+98a4 Zhan # Character 颤
+U+98a5 Ru # Character 颥
+U+98a6 Pin # Character 颦
+U+98a7 Quan # Character 颧
+U+98a8 Feng # Character 風
+U+98a9 Biao # Character 颩
+U+98aa Oroshi # Character 颪
+U+98ab Fu # Character 颫
+U+98ac Xia # Character 颬
+U+98ad Zhan # Character é¢
+U+98ae Biao # Character 颮
+U+98af Sa # Character 颯
+U+98b0 Ba # Character 颰
+U+98b1 Tai # Character 颱
+U+98b2 Lie # Character 颲
+U+98b3 Gua # Character 颳
+U+98b4 Xuan # Character 颴
+U+98b5 Shao # Character 颵
+U+98b6 Ju # Character 颶
+U+98b7 Bi # Character 颷
+U+98b8 Si # Character 颸
+U+98b9 Wei # Character 颹
+U+98ba Yang # Character 颺
+U+98bb Yao # Character 颻
+U+98bc Sou # Character 颼
+U+98bd Kai # Character 颽
+U+98be Sao # Character 颾
+U+98bf Fan # Character 颿
+U+98c0 Liu # Character é£
+U+98c1 Xi # Character é£
+U+98c2 Liao # Character é£
+U+98c3 Piao # Character é£
+U+98c4 Piao # Character é£
+U+98c5 Liu # Character é£
+U+98c6 Biao # Character é£
+U+98c7 Biao # Character é£
+U+98c8 Biao # Character é£
+U+98c9 Liao # Character é£
+U+98ca ? # Character é£
+U+98cb Se # Character é£
+U+98cc Feng # Character é£
+U+98cd Biao # Character é£
+U+98ce Feng # Character é£
+U+98cf Yang # Character é£
+U+98d0 Zhan # Character é£
+U+98d1 Biao # Character é£
+U+98d2 Sa # Character é£
+U+98d3 Ju # Character é£
+U+98d4 Si # Character é£
+U+98d5 Sou # Character é£
+U+98d6 Yao # Character é£
+U+98d7 Liu # Character é£
+U+98d8 Piao # Character é£
+U+98d9 Biao # Character é£
+U+98da Biao # Character é£
+U+98db Fei # Character é£
+U+98dc Fan # Character é£
+U+98dd Fei # Character é£
+U+98de Fei # Character é£
+U+98df Shi # Character é£
+U+98e0 Shi # Character é£
+U+98e1 Can # Character 飡
+U+98e2 Ji # Character 飢
+U+98e3 Ding # Character 飣
+U+98e4 Si # Character 飤
+U+98e5 Tuo # Character 飥
+U+98e6 Zhan # Character 飦
+U+98e7 Sun # Character 飧
+U+98e8 Xiang # Character 飨
+U+98e9 Tun # Character 飩
+U+98ea Ren # Character 飪
+U+98eb Yu # Character 飫
+U+98ec Juan # Character 飬
+U+98ed Chi # Character é£
+U+98ee Yin # Character 飮
+U+98ef Fan # Character 飯
+U+98f0 Fan # Character 飰
+U+98f1 Sun # Character 飱
+U+98f2 Yin # Character 飲
+U+98f3 Zhu # Character 飳
+U+98f4 Yi # Character 飴
+U+98f5 Zhai # Character 飵
+U+98f6 Bi # Character 飶
+U+98f7 Jie # Character 飷
+U+98f8 Tao # Character 飸
+U+98f9 Liu # Character 飹
+U+98fa Ci # Character 飺
+U+98fb Tie # Character 飻
+U+98fc Si # Character 飼
+U+98fd Bao # Character 飽
+U+98fe Shi # Character 飾
+U+98ff Duo # Character 飿
diff --git a/resources/chars/ascii/row99.trans b/resources/chars/ascii/row99.trans
new file mode 100644
index 0000000..9f114fc
--- /dev/null
+++ b/resources/chars/ascii/row99.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+9900 Hai # Character é¤
+U+9901 Ren # Character é¤
+U+9902 Tian # Character é¤
+U+9903 Jiao # Character é¤
+U+9904 Jia # Character é¤
+U+9905 Bing # Character é¤
+U+9906 Yao # Character é¤
+U+9907 Tong # Character é¤
+U+9908 Ci # Character é¤
+U+9909 Xiang # Character é¤
+U+990a Yang # Character é¤
+U+990b Yang # Character é¤
+U+990c Er # Character é¤
+U+990d Yan # Character é¤
+U+990e Le # Character é¤
+U+990f Yi # Character é¤
+U+9910 Can # Character é¤
+U+9911 Bo # Character é¤
+U+9912 Nei # Character é¤
+U+9913 E # Character é¤
+U+9914 Bu # Character é¤
+U+9915 Jun # Character é¤
+U+9916 Dou # Character é¤
+U+9917 Su # Character é¤
+U+9918 Yu # Character é¤
+U+9919 Shi # Character é¤
+U+991a Yao # Character é¤
+U+991b Hun # Character é¤
+U+991c Guo # Character é¤
+U+991d Shi # Character é¤
+U+991e Jian # Character é¤
+U+991f Zhui # Character é¤
+U+9920 Bing # Character é¤
+U+9921 Xian # Character 餡
+U+9922 Bu # Character 餢
+U+9923 Ye # Character 餣
+U+9924 Tan # Character 餤
+U+9925 Fei # Character 餥
+U+9926 Zhang # Character 餦
+U+9927 Wei # Character 餧
+U+9928 Guan # Character 館
+U+9929 E # Character 餩
+U+992a Nuan # Character 餪
+U+992b Hun # Character 餫
+U+992c Hu # Character 餬
+U+992d Huang # Character é¤
+U+992e Tie # Character 餮
+U+992f Hui # Character 餯
+U+9930 Jian # Character 餰
+U+9931 Hou # Character 餱
+U+9932 He # Character 餲
+U+9933 Xing # Character 餳
+U+9934 Fen # Character 餴
+U+9935 Wei # Character 餵
+U+9936 Gu # Character 餶
+U+9937 Cha # Character 餷
+U+9938 Song # Character 餸
+U+9939 Tang # Character 餹
+U+993a Bo # Character 餺
+U+993b Gao # Character 餻
+U+993c Xi # Character 餼
+U+993d Kui # Character 餽
+U+993e Liu # Character 餾
+U+993f Sou # Character 餿
+U+9940 Tao # Character é¥
+U+9941 Ye # Character é¥
+U+9942 Yun # Character é¥
+U+9943 Mo # Character é¥
+U+9944 Tang # Character é¥
+U+9945 Man # Character é¥
+U+9946 Bi # Character é¥
+U+9947 Yu # Character é¥
+U+9948 Xiu # Character é¥
+U+9949 Jin # Character é¥
+U+994a San # Character é¥
+U+994b Kui # Character é¥
+U+994c Zhuan # Character é¥
+U+994d Shan # Character é¥
+U+994e Chi # Character é¥
+U+994f Dan # Character é¥
+U+9950 Yi # Character é¥
+U+9951 Ji # Character é¥
+U+9952 Rao # Character é¥
+U+9953 Cheng # Character é¥
+U+9954 Yong # Character é¥
+U+9955 Tao # Character é¥
+U+9956 Hui # Character é¥
+U+9957 Xiang # Character é¥
+U+9958 Zhan # Character é¥
+U+9959 Fen # Character é¥
+U+995a Hai # Character é¥
+U+995b Meng # Character é¥
+U+995c Yan # Character é¥
+U+995d Mo # Character é¥
+U+995e Chan # Character é¥
+U+995f Xiang # Character é¥
+U+9960 Luo # Character é¥
+U+9961 Zuan # Character 饡
+U+9962 Nang # Character 饢
+U+9963 Shi # Character 饣
+U+9964 Ding # Character 饤
+U+9965 Ji # Character 饥
+U+9966 Tuo # Character 饦
+U+9967 Xing # Character 饧
+U+9968 Tun # Character 饨
+U+9969 Xi # Character 饩
+U+996a Ren # Character 饪
+U+996b Yu # Character 饫
+U+996c Chi # Character 饬
+U+996d Fan # Character é¥
+U+996e Yin # Character 饮
+U+996f Jian # Character 饯
+U+9970 Shi # Character 饰
+U+9971 Bao # Character 饱
+U+9972 Si # Character 饲
+U+9973 Duo # Character 饳
+U+9974 Yi # Character 饴
+U+9975 Er # Character 饵
+U+9976 Rao # Character 饶
+U+9977 Xiang # Character 饷
+U+9978 Jia # Character 饸
+U+9979 Le # Character 饹
+U+997a Jiao # Character 饺
+U+997b Yi # Character 饻
+U+997c Bing # Character 饼
+U+997d Bo # Character 饽
+U+997e Dou # Character 饾
+U+997f E # Character 饿
+U+9980 Yu # Character é¦
+U+9981 Nei # Character é¦
+U+9982 Jun # Character é¦
+U+9983 Guo # Character é¦
+U+9984 Hun # Character é¦
+U+9985 Xian # Character é¦
+U+9986 Guan # Character é¦
+U+9987 Cha # Character é¦
+U+9988 Kui # Character é¦
+U+9989 Gu # Character é¦
+U+998a Sou # Character é¦
+U+998b Chan # Character é¦
+U+998c Ye # Character é¦
+U+998d Mo # Character é¦
+U+998e Bo # Character é¦
+U+998f Liu # Character é¦
+U+9990 Xiu # Character é¦
+U+9991 Jin # Character é¦
+U+9992 Man # Character é¦
+U+9993 San # Character é¦
+U+9994 Zhuan # Character é¦
+U+9995 Nang # Character é¦
+U+9996 Shou # Character é¦
+U+9997 Kui # Character é¦
+U+9998 Guo # Character é¦
+U+9999 Xiang # Character é¦
+U+999a Fen # Character é¦
+U+999b Ba # Character é¦
+U+999c Ni # Character é¦
+U+999d Bi # Character é¦
+U+999e Bo # Character é¦
+U+999f Tu # Character é¦
+U+99a0 Han # Character é¦
+U+99a1 Fei # Character 馡
+U+99a2 Jian # Character 馢
+U+99a3 An # Character 馣
+U+99a4 Ai # Character 馤
+U+99a5 Fu # Character 馥
+U+99a6 Xian # Character 馦
+U+99a7 Wen # Character 馧
+U+99a8 Xin # Character 馨
+U+99a9 Fen # Character 馩
+U+99aa Bin # Character 馪
+U+99ab Xing # Character 馫
+U+99ac Ma # Character 馬
+U+99ad Yu # Character é¦
+U+99ae Feng # Character 馮
+U+99af Han # Character 馯
+U+99b0 Di # Character 馰
+U+99b1 Tuo # Character 馱
+U+99b2 Tuo # Character 馲
+U+99b3 Chi # Character 馳
+U+99b4 Xun # Character 馴
+U+99b5 Zhu # Character 馵
+U+99b6 Zhi # Character 馶
+U+99b7 Pei # Character 馷
+U+99b8 Xin # Character 馸
+U+99b9 Ri # Character 馹
+U+99ba Sa # Character 馺
+U+99bb Yin # Character 馻
+U+99bc Wen # Character 馼
+U+99bd Zhi # Character 馽
+U+99be Dan # Character 馾
+U+99bf Lu # Character 馿
+U+99c0 You # Character é§
+U+99c1 Bo # Character é§
+U+99c2 Bao # Character é§
+U+99c3 Kuai # Character é§
+U+99c4 Tuo # Character é§
+U+99c5 Yi # Character é§
+U+99c6 Qu # Character é§
+U+99c7 ? # Character é§
+U+99c8 Qu # Character é§
+U+99c9 Jiong # Character é§
+U+99ca Bo # Character é§
+U+99cb Zhao # Character é§
+U+99cc Yuan # Character é§
+U+99cd Peng # Character é§
+U+99ce Zhou # Character é§
+U+99cf Ju # Character é§
+U+99d0 Zhu # Character é§
+U+99d1 Nu # Character é§
+U+99d2 Ju # Character é§
+U+99d3 Pi # Character é§
+U+99d4 Zang # Character é§
+U+99d5 Jia # Character é§
+U+99d6 Ling # Character é§
+U+99d7 Zhen # Character é§
+U+99d8 Tai # Character é§
+U+99d9 Fu # Character é§
+U+99da Yang # Character é§
+U+99db Shi # Character é§
+U+99dc Bi # Character é§
+U+99dd Tuo # Character é§
+U+99de Tuo # Character é§
+U+99df Si # Character é§
+U+99e0 Liu # Character é§
+U+99e1 Ma # Character 駡
+U+99e2 Pian # Character 駢
+U+99e3 Tao # Character 駣
+U+99e4 Zhi # Character 駤
+U+99e5 Rong # Character 駥
+U+99e6 Teng # Character 駦
+U+99e7 Dong # Character 駧
+U+99e8 Xun # Character 駨
+U+99e9 Quan # Character 駩
+U+99ea Shen # Character 駪
+U+99eb Jiong # Character 駫
+U+99ec Er # Character 駬
+U+99ed Hai # Character é§
+U+99ee Bo # Character 駮
+U+99ef Zhu # Character 駯
+U+99f0 Yin # Character 駰
+U+99f1 Luo # Character 駱
+U+99f2 Shuu # Character 駲
+U+99f3 Dan # Character 駳
+U+99f4 Xie # Character 駴
+U+99f5 Liu # Character 駵
+U+99f6 Ju # Character 駶
+U+99f7 Song # Character 駷
+U+99f8 Qin # Character 駸
+U+99f9 Mang # Character 駹
+U+99fa Liang # Character 駺
+U+99fb Han # Character 駻
+U+99fc Tu # Character 駼
+U+99fd Xuan # Character 駽
+U+99fe Tui # Character 駾
+U+99ff Jun # Character 駿
diff --git a/resources/chars/ascii/row9a.trans b/resources/chars/ascii/row9a.trans
new file mode 100644
index 0000000..351da33
--- /dev/null
+++ b/resources/chars/ascii/row9a.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+9a00 E # Character é¨
+U+9a01 Cheng # Character é¨
+U+9a02 Xin # Character é¨
+U+9a03 Ai # Character é¨
+U+9a04 Lu # Character é¨
+U+9a05 Zhui # Character é¨
+U+9a06 Zhou # Character é¨
+U+9a07 She # Character é¨
+U+9a08 Pian # Character é¨
+U+9a09 Kun # Character é¨
+U+9a0a Tao # Character é¨
+U+9a0b Lai # Character é¨
+U+9a0c Zong # Character é¨
+U+9a0d Ke # Character é¨
+U+9a0e Qi # Character é¨
+U+9a0f Qi # Character é¨
+U+9a10 Yan # Character é¨
+U+9a11 Fei # Character é¨
+U+9a12 Sao # Character é¨
+U+9a13 Yan # Character é¨
+U+9a14 Jie # Character é¨
+U+9a15 Yao # Character é¨
+U+9a16 Wu # Character é¨
+U+9a17 Pian # Character é¨
+U+9a18 Cong # Character é¨
+U+9a19 Pian # Character é¨
+U+9a1a Qian # Character é¨
+U+9a1b Fei # Character é¨
+U+9a1c Huang # Character é¨
+U+9a1d Jian # Character é¨
+U+9a1e Huo # Character é¨
+U+9a1f Yu # Character é¨
+U+9a20 Ti # Character é¨
+U+9a21 Quan # Character 騡
+U+9a22 Xia # Character 騢
+U+9a23 Zong # Character 騣
+U+9a24 Kui # Character 騤
+U+9a25 Rou # Character 騥
+U+9a26 Si # Character 騦
+U+9a27 Gua # Character 騧
+U+9a28 Tuo # Character 騨
+U+9a29 Kui # Character 騩
+U+9a2a Sou # Character 騪
+U+9a2b Qian # Character 騫
+U+9a2c Cheng # Character 騬
+U+9a2d Zhi # Character é¨
+U+9a2e Liu # Character 騮
+U+9a2f Pang # Character 騯
+U+9a30 Teng # Character 騰
+U+9a31 Xi # Character 騱
+U+9a32 Cao # Character 騲
+U+9a33 Du # Character 騳
+U+9a34 Yan # Character 騴
+U+9a35 Yuan # Character 騵
+U+9a36 Zou # Character 騶
+U+9a37 Sao # Character 騷
+U+9a38 Shan # Character 騸
+U+9a39 Li # Character 騹
+U+9a3a Zhi # Character 騺
+U+9a3b Shuang # Character 騻
+U+9a3c Lu # Character 騼
+U+9a3d Xi # Character 騽
+U+9a3e Luo # Character 騾
+U+9a3f Zhang # Character 騿
+U+9a40 Mo # Character é©
+U+9a41 Ao # Character é©
+U+9a42 Can # Character é©
+U+9a43 Piao # Character é©
+U+9a44 Cong # Character é©
+U+9a45 Qu # Character é©
+U+9a46 Bi # Character é©
+U+9a47 Zhi # Character é©
+U+9a48 Yu # Character é©
+U+9a49 Xu # Character é©
+U+9a4a Hua # Character é©
+U+9a4b Bo # Character é©
+U+9a4c Su # Character é©
+U+9a4d Xiao # Character é©
+U+9a4e Lin # Character é©
+U+9a4f Chan # Character é©
+U+9a50 Dun # Character é©
+U+9a51 Liu # Character é©
+U+9a52 Tuo # Character é©
+U+9a53 Zeng # Character é©
+U+9a54 Tan # Character é©
+U+9a55 Jiao # Character é©
+U+9a56 Tie # Character é©
+U+9a57 Yan # Character é©
+U+9a58 Luo # Character é©
+U+9a59 Zhan # Character é©
+U+9a5a Jing # Character é©
+U+9a5b Yi # Character é©
+U+9a5c Ye # Character é©
+U+9a5d Tuo # Character é©
+U+9a5e Bin # Character é©
+U+9a5f Zou # Character é©
+U+9a60 Yan # Character é©
+U+9a61 Peng # Character é©¡
+U+9a62 Lu # Character é©¢
+U+9a63 Teng # Character é©£
+U+9a64 Xiang # Character 驤
+U+9a65 Ji # Character é©¥
+U+9a66 Shuang # Character 驦
+U+9a67 Ju # Character 驧
+U+9a68 Xi # Character 驨
+U+9a69 Huan # Character é©©
+U+9a6a Li # Character 驪
+U+9a6b Biao # Character é©«
+U+9a6c Ma # Character 马
+U+9a6d Yu # Character é©
+U+9a6e Tuo # Character é©®
+U+9a6f Xun # Character 驯
+U+9a70 Chi # Character é©°
+U+9a71 Qu # Character 驱
+U+9a72 Ri # Character 驲
+U+9a73 Bo # Character 驳
+U+9a74 Lu # Character é©´
+U+9a75 Zang # Character 驵
+U+9a76 Shi # Character 驶
+U+9a77 Si # Character é©·
+U+9a78 Fu # Character 驸
+U+9a79 Ju # Character 驹
+U+9a7a Zou # Character 驺
+U+9a7b Zhu # Character é©»
+U+9a7c Tuo # Character 驼
+U+9a7d Nu # Character 驽
+U+9a7e Jia # Character 驾
+U+9a7f Yi # Character é©¿
+U+9a80 Tai # Character éª
+U+9a81 Xiao # Character éª
+U+9a82 Ma # Character éª
+U+9a83 Yin # Character éª
+U+9a84 Jiao # Character éª
+U+9a85 Hua # Character éª
+U+9a86 Luo # Character éª
+U+9a87 Hai # Character éª
+U+9a88 Pian # Character éª
+U+9a89 Biao # Character éª
+U+9a8a Li # Character éª
+U+9a8b Cheng # Character éª
+U+9a8c Yan # Character éª
+U+9a8d Xin # Character éª
+U+9a8e Qin # Character éª
+U+9a8f Jun # Character éª
+U+9a90 Qi # Character éª
+U+9a91 Qi # Character éª
+U+9a92 Ke # Character éª
+U+9a93 Zhui # Character éª
+U+9a94 Zong # Character éª
+U+9a95 Su # Character éª
+U+9a96 Can # Character éª
+U+9a97 Pian # Character éª
+U+9a98 Zhi # Character éª
+U+9a99 Kui # Character éª
+U+9a9a Sao # Character éª
+U+9a9b Wu # Character éª
+U+9a9c Ao # Character éª
+U+9a9d Liu # Character éª
+U+9a9e Qian # Character éª
+U+9a9f Shan # Character éª
+U+9aa0 Piao # Character éª
+U+9aa1 Luo # Character 骡
+U+9aa2 Cong # Character 骢
+U+9aa3 Chan # Character 骣
+U+9aa4 Zou # Character 骤
+U+9aa5 Ji # Character 骥
+U+9aa6 Shuang # Character 骦
+U+9aa7 Xiang # Character 骧
+U+9aa8 Gu # Character 骨
+U+9aa9 Wei # Character 骩
+U+9aaa Wei # Character 骪
+U+9aab Wei # Character 骫
+U+9aac Yu # Character 骬
+U+9aad Gan # Character éª
+U+9aae Yi # Character 骮
+U+9aaf Ang # Character 骯
+U+9ab0 Tou # Character 骰
+U+9ab1 Xie # Character 骱
+U+9ab2 Bao # Character 骲
+U+9ab3 Bi # Character 骳
+U+9ab4 Chi # Character 骴
+U+9ab5 Ti # Character 骵
+U+9ab6 Di # Character 骶
+U+9ab7 Ku # Character 骷
+U+9ab8 Hai # Character 骸
+U+9ab9 Qiao # Character 骹
+U+9aba Gou # Character 骺
+U+9abb Kua # Character 骻
+U+9abc Ge # Character 骼
+U+9abd Tui # Character 骽
+U+9abe Geng # Character 骾
+U+9abf Pian # Character 骿
+U+9ac0 Bi # Character é«
+U+9ac1 Ke # Character é«
+U+9ac2 Ka # Character é«
+U+9ac3 Yu # Character é«
+U+9ac4 Sui # Character é«
+U+9ac5 Lou # Character é«
+U+9ac6 Bo # Character é«
+U+9ac7 Xiao # Character é«
+U+9ac8 Pang # Character é«
+U+9ac9 Bo # Character é«
+U+9aca Ci # Character é«
+U+9acb Kuan # Character é«
+U+9acc Bin # Character é«
+U+9acd Mo # Character é«
+U+9ace Liao # Character é«
+U+9acf Lou # Character é«
+U+9ad0 Nao # Character é«
+U+9ad1 Du # Character é«
+U+9ad2 Zang # Character é«
+U+9ad3 Sui # Character é«
+U+9ad4 Ti # Character é«
+U+9ad5 Bin # Character é«
+U+9ad6 Kuan # Character é«
+U+9ad7 Lu # Character é«
+U+9ad8 Gao # Character é«
+U+9ad9 Gao # Character é«
+U+9ada Qiao # Character é«
+U+9adb Kao # Character é«
+U+9adc Qiao # Character é«
+U+9add Lao # Character é«
+U+9ade Zao # Character é«
+U+9adf Biao # Character é«
+U+9ae0 Kun # Character é«
+U+9ae1 Kun # Character é«¡
+U+9ae2 Ti # Character é«¢
+U+9ae3 Fang # Character é«£
+U+9ae4 Xiu # Character 髤
+U+9ae5 Ran # Character é«¥
+U+9ae6 Mao # Character 髦
+U+9ae7 Dan # Character 髧
+U+9ae8 Kun # Character 髨
+U+9ae9 Bin # Character é«©
+U+9aea Fa # Character 髪
+U+9aeb Tiao # Character é««
+U+9aec Peng # Character 髬
+U+9aed Zi # Character é«
+U+9aee Fa # Character é«®
+U+9aef Ran # Character 髯
+U+9af0 Ti # Character é«°
+U+9af1 Pao # Character 髱
+U+9af2 Pi # Character 髲
+U+9af3 Mao # Character 髳
+U+9af4 Fu # Character é«´
+U+9af5 Er # Character 髵
+U+9af6 Rong # Character 髶
+U+9af7 Qu # Character é«·
+U+9af8 Gong # Character 髸
+U+9af9 Xiu # Character 髹
+U+9afa Gua # Character 髺
+U+9afb Ji # Character é«»
+U+9afc Peng # Character 髼
+U+9afd Zhua # Character 髽
+U+9afe Shao # Character 髾
+U+9aff Sha # Character é«¿
diff --git a/resources/chars/ascii/row9b.trans b/resources/chars/ascii/row9b.trans
new file mode 100644
index 0000000..b6b1bf1
--- /dev/null
+++ b/resources/chars/ascii/row9b.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+9b00 Ti # Character é¬
+U+9b01 Li # Character é¬
+U+9b02 Bin # Character é¬
+U+9b03 Zong # Character é¬
+U+9b04 Ti # Character é¬
+U+9b05 Peng # Character é¬
+U+9b06 Song # Character é¬
+U+9b07 Zheng # Character é¬
+U+9b08 Quan # Character é¬
+U+9b09 Zong # Character é¬
+U+9b0a Shun # Character é¬
+U+9b0b Jian # Character é¬
+U+9b0c Duo # Character é¬
+U+9b0d Hu # Character é¬
+U+9b0e La # Character é¬
+U+9b0f Jiu # Character é¬
+U+9b10 Qi # Character é¬
+U+9b11 Lian # Character é¬
+U+9b12 Zhen # Character é¬
+U+9b13 Bin # Character é¬
+U+9b14 Peng # Character é¬
+U+9b15 Mo # Character é¬
+U+9b16 San # Character é¬
+U+9b17 Man # Character é¬
+U+9b18 Man # Character é¬
+U+9b19 Seng # Character é¬
+U+9b1a Xu # Character é¬
+U+9b1b Lie # Character é¬
+U+9b1c Qian # Character é¬
+U+9b1d Qian # Character é¬
+U+9b1e Nong # Character é¬
+U+9b1f Huan # Character é¬
+U+9b20 Kuai # Character é¬
+U+9b21 Ning # Character 鬡
+U+9b22 Bin # Character 鬢
+U+9b23 Lie # Character 鬣
+U+9b24 Rang # Character 鬤
+U+9b25 Dou # Character 鬥
+U+9b26 Dou # Character 鬦
+U+9b27 Nao # Character 鬧
+U+9b28 Hong # Character 鬨
+U+9b29 Xi # Character 鬩
+U+9b2a Dou # Character 鬪
+U+9b2b Han # Character 鬫
+U+9b2c Dou # Character 鬬
+U+9b2d Dou # Character é¬
+U+9b2e Jiu # Character 鬮
+U+9b2f Chang # Character 鬯
+U+9b30 Yu # Character 鬰
+U+9b31 Yu # Character 鬱
+U+9b32 Li # Character 鬲
+U+9b33 Juan # Character 鬳
+U+9b34 Fu # Character 鬴
+U+9b35 Qian # Character 鬵
+U+9b36 Gui # Character 鬶
+U+9b37 Zong # Character 鬷
+U+9b38 Liu # Character 鬸
+U+9b39 Gui # Character 鬹
+U+9b3a Shang # Character 鬺
+U+9b3b Yu # Character 鬻
+U+9b3c Gui # Character 鬼
+U+9b3d Mei # Character 鬽
+U+9b3e Ji # Character 鬾
+U+9b3f Qi # Character 鬿
+U+9b40 Jie # Character é
+U+9b41 Kui # Character é
+U+9b42 Hun # Character é
+U+9b43 Ba # Character é
+U+9b44 Po # Character é
+U+9b45 Mei # Character é
+U+9b46 Xu # Character é
+U+9b47 Yan # Character é
+U+9b48 Xiao # Character é
+U+9b49 Liang # Character é
+U+9b4a Yu # Character é
+U+9b4b Tui # Character é
+U+9b4c Qi # Character é
+U+9b4d Wang # Character é
+U+9b4e Liang # Character é
+U+9b4f Wei # Character é
+U+9b50 Jian # Character é
+U+9b51 Chi # Character é
+U+9b52 Piao # Character é
+U+9b53 Bi # Character é
+U+9b54 Mo # Character é
+U+9b55 Ji # Character é
+U+9b56 Xu # Character é
+U+9b57 Chou # Character é
+U+9b58 Yan # Character é
+U+9b59 Zhan # Character é
+U+9b5a Yu # Character é
+U+9b5b Dao # Character é
+U+9b5c Ren # Character é
+U+9b5d Ji # Character é
+U+9b5e Eri # Character é
+U+9b5f Gong # Character é
+U+9b60 Tuo # Character é
+U+9b61 Diao # Character é¡
+U+9b62 Ji # Character é¢
+U+9b63 Xu # Character é£
+U+9b64 E # Character é¤
+U+9b65 E # Character é¥
+U+9b66 Sha # Character é¦
+U+9b67 Hang # Character é§
+U+9b68 Tun # Character é¨
+U+9b69 Mo # Character é©
+U+9b6a Jie # Character éª
+U+9b6b Shen # Character é«
+U+9b6c Fan # Character é¬
+U+9b6d Yuan # Character é
+U+9b6e Bi # Character é®
+U+9b6f Lu # Character é¯
+U+9b70 Wen # Character é°
+U+9b71 Hu # Character é±
+U+9b72 Lu # Character é²
+U+9b73 Za # Character é³
+U+9b74 Fang # Character é´
+U+9b75 Fen # Character éµ
+U+9b76 Na # Character é¶
+U+9b77 You # Character é·
+U+9b78 Namazu # Character é¸
+U+9b79 Todo # Character é¹
+U+9b7a He # Character éº
+U+9b7b Xia # Character é»
+U+9b7c Qu # Character é¼
+U+9b7d Han # Character é½
+U+9b7e Pi # Character é¾
+U+9b7f Ling # Character é¿
+U+9b80 Tuo # Character é®
+U+9b81 Bo # Character é®
+U+9b82 Qiu # Character é®
+U+9b83 Ping # Character é®
+U+9b84 Fu # Character é®
+U+9b85 Bi # Character é®
+U+9b86 Ji # Character é®
+U+9b87 Wei # Character é®
+U+9b88 Ju # Character é®
+U+9b89 Diao # Character é®
+U+9b8a Bo # Character é®
+U+9b8b You # Character é®
+U+9b8c Gun # Character é®
+U+9b8d Pi # Character é®
+U+9b8e Nian # Character é®
+U+9b8f Xing # Character é®
+U+9b90 Tai # Character é®
+U+9b91 Bao # Character é®
+U+9b92 Fu # Character é®
+U+9b93 Zha # Character é®
+U+9b94 Ju # Character é®
+U+9b95 Gu # Character é®
+U+9b96 Kajika # Character é®
+U+9b97 Tong # Character é®
+U+9b98 ? # Character é®
+U+9b99 Ta # Character é®
+U+9b9a Jie # Character é®
+U+9b9b Shu # Character é®
+U+9b9c Hou # Character é®
+U+9b9d Xiang # Character é®
+U+9b9e Er # Character é®
+U+9b9f An # Character é®
+U+9ba0 Wei # Character é®
+U+9ba1 Tiao # Character 鮡
+U+9ba2 Zhu # Character 鮢
+U+9ba3 Yin # Character 鮣
+U+9ba4 Lie # Character 鮤
+U+9ba5 Luo # Character 鮥
+U+9ba6 Tong # Character 鮦
+U+9ba7 Yi # Character 鮧
+U+9ba8 Qi # Character 鮨
+U+9ba9 Bing # Character 鮩
+U+9baa Wei # Character 鮪
+U+9bab Jiao # Character 鮫
+U+9bac Bu # Character 鮬
+U+9bad Gui # Character é®
+U+9bae Xian # Character é®®
+U+9baf Ge # Character 鮯
+U+9bb0 Hui # Character é®°
+U+9bb1 Bora # Character é®±
+U+9bb2 Mate # Character 鮲
+U+9bb3 Kao # Character 鮳
+U+9bb4 Gori # Character é®´
+U+9bb5 Duo # Character 鮵
+U+9bb6 Jun # Character 鮶
+U+9bb7 Ti # Character é®·
+U+9bb8 Man # Character 鮸
+U+9bb9 Xiao # Character 鮹
+U+9bba Za # Character 鮺
+U+9bbb Sha # Character é®»
+U+9bbc Qin # Character 鮼
+U+9bbd Yu # Character 鮽
+U+9bbe Nei # Character 鮾
+U+9bbf Zhe # Character 鮿
+U+9bc0 Gun # Character é¯
+U+9bc1 Geng # Character é¯
+U+9bc2 Su # Character é¯
+U+9bc3 Wu # Character é¯
+U+9bc4 Qiu # Character é¯
+U+9bc5 Ting # Character é¯
+U+9bc6 Fu # Character é¯
+U+9bc7 Wan # Character é¯
+U+9bc8 You # Character é¯
+U+9bc9 Li # Character é¯
+U+9bca Sha # Character é¯
+U+9bcb Sha # Character é¯
+U+9bcc Gao # Character é¯
+U+9bcd Meng # Character é¯
+U+9bce Ugui # Character é¯
+U+9bcf Asari # Character é¯
+U+9bd0 Subashiri # Character é¯
+U+9bd1 Kazunoko # Character é¯
+U+9bd2 Yong # Character é¯
+U+9bd3 Ni # Character é¯
+U+9bd4 Zi # Character é¯
+U+9bd5 Qi # Character é¯
+U+9bd6 Qing # Character é¯
+U+9bd7 Xiang # Character é¯
+U+9bd8 Nei # Character é¯
+U+9bd9 Chun # Character é¯
+U+9bda Ji # Character é¯
+U+9bdb Diao # Character é¯
+U+9bdc Qie # Character é¯
+U+9bdd Gu # Character é¯
+U+9bde Zhou # Character é¯
+U+9bdf Dong # Character é¯
+U+9be0 Lai # Character é¯
+U+9be1 Fei # Character 鯡
+U+9be2 Ni # Character 鯢
+U+9be3 Yi # Character 鯣
+U+9be4 Kun # Character 鯤
+U+9be5 Lu # Character 鯥
+U+9be6 Jiu # Character 鯦
+U+9be7 Chang # Character 鯧
+U+9be8 Jing # Character 鯨
+U+9be9 Lun # Character 鯩
+U+9bea Ling # Character 鯪
+U+9beb Zou # Character 鯫
+U+9bec Li # Character 鯬
+U+9bed Meng # Character é¯
+U+9bee Zong # Character 鯮
+U+9bef Zhi # Character 鯯
+U+9bf0 Nian # Character 鯰
+U+9bf1 Shachi # Character 鯱
+U+9bf2 Dojou # Character 鯲
+U+9bf3 Sukesou # Character 鯳
+U+9bf4 Shi # Character 鯴
+U+9bf5 Shen # Character 鯵
+U+9bf6 Hun # Character 鯶
+U+9bf7 Shi # Character 鯷
+U+9bf8 Hou # Character 鯸
+U+9bf9 Xing # Character 鯹
+U+9bfa Zhu # Character 鯺
+U+9bfb La # Character 鯻
+U+9bfc Zong # Character 鯼
+U+9bfd Ji # Character 鯽
+U+9bfe Bian # Character 鯾
+U+9bff Bian # Character 鯿
diff --git a/resources/chars/ascii/row9c.trans b/resources/chars/ascii/row9c.trans
new file mode 100644
index 0000000..319fb6e
--- /dev/null
+++ b/resources/chars/ascii/row9c.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+9c00 Huan # Character é°
+U+9c01 Quan # Character é°
+U+9c02 Ze # Character é°
+U+9c03 Wei # Character é°
+U+9c04 Wei # Character é°
+U+9c05 Yu # Character é°
+U+9c06 Qun # Character é°
+U+9c07 Rou # Character é°
+U+9c08 Die # Character é°
+U+9c09 Huang # Character é°
+U+9c0a Lian # Character é°
+U+9c0b Yan # Character é°
+U+9c0c Qiu # Character é°
+U+9c0d Qiu # Character é°
+U+9c0e Jian # Character é°
+U+9c0f Bi # Character é°
+U+9c10 E # Character é°
+U+9c11 Yang # Character é°
+U+9c12 Fu # Character é°
+U+9c13 Sai # Character é°
+U+9c14 Jian # Character é°
+U+9c15 Xia # Character é°
+U+9c16 Tuo # Character é°
+U+9c17 Hu # Character é°
+U+9c18 Muroaji # Character é°
+U+9c19 Ruo # Character é°
+U+9c1a Haraka # Character é°
+U+9c1b Wen # Character é°
+U+9c1c Jian # Character é°
+U+9c1d Hao # Character é°
+U+9c1e Wu # Character é°
+U+9c1f Fang # Character é°
+U+9c20 Sao # Character é°
+U+9c21 Liu # Character é°¡
+U+9c22 Ma # Character é°¢
+U+9c23 Shi # Character é°£
+U+9c24 Shi # Character é°¤
+U+9c25 Yin # Character é°¥
+U+9c26 Z # Character é°¦
+U+9c27 Teng # Character é°§
+U+9c28 Ta # Character é°¨
+U+9c29 Yao # Character é°©
+U+9c2a Ge # Character é°ª
+U+9c2b Rong # Character é°«
+U+9c2c Qian # Character é°¬
+U+9c2d Qi # Character é°
+U+9c2e Wen # Character é°®
+U+9c2f Ruo # Character é°¯
+U+9c30 Hatahata # Character é°°
+U+9c31 Lian # Character é°±
+U+9c32 Ao # Character é°²
+U+9c33 Le # Character é°³
+U+9c34 Hui # Character é°´
+U+9c35 Min # Character é°µ
+U+9c36 Ji # Character é°¶
+U+9c37 Tiao # Character é°·
+U+9c38 Qu # Character é°¸
+U+9c39 Jian # Character é°¹
+U+9c3a Sao # Character é°º
+U+9c3b Man # Character é°»
+U+9c3c Xi # Character é°¼
+U+9c3d Qiu # Character é°½
+U+9c3e Biao # Character é°¾
+U+9c3f Ji # Character é°¿
+U+9c40 Ji # Character é±
+U+9c41 Zhu # Character é±
+U+9c42 Jiang # Character é±
+U+9c43 Qiu # Character é±
+U+9c44 Zhuan # Character é±
+U+9c45 Yong # Character é±
+U+9c46 Zhang # Character é±
+U+9c47 Kang # Character é±
+U+9c48 Xue # Character é±
+U+9c49 Bie # Character é±
+U+9c4a Jue # Character é±
+U+9c4b Qu # Character é±
+U+9c4c Xiang # Character é±
+U+9c4d Bo # Character é±
+U+9c4e Jiao # Character é±
+U+9c4f Xun # Character é±
+U+9c50 Su # Character é±
+U+9c51 Huang # Character é±
+U+9c52 Zun # Character é±
+U+9c53 Shan # Character é±
+U+9c54 Shan # Character é±
+U+9c55 Fan # Character é±
+U+9c56 Jue # Character é±
+U+9c57 Lin # Character é±
+U+9c58 Xun # Character é±
+U+9c59 Miao # Character é±
+U+9c5a Xi # Character é±
+U+9c5b Eso # Character é±
+U+9c5c Kyou # Character é±
+U+9c5d Fen # Character é±
+U+9c5e Guan # Character é±
+U+9c5f Hou # Character é±
+U+9c60 Kuai # Character é±
+U+9c61 Zei # Character 鱡
+U+9c62 Sao # Character é±¢
+U+9c63 Zhan # Character é±£
+U+9c64 Gan # Character 鱤
+U+9c65 Gui # Character é±¥
+U+9c66 Sheng # Character 鱦
+U+9c67 Li # Character 鱧
+U+9c68 Chang # Character 鱨
+U+9c69 Hatahata # Character 鱩
+U+9c6a Shiira # Character 鱪
+U+9c6b Mutsu # Character 鱫
+U+9c6c Ru # Character 鱬
+U+9c6d Ji # Character é±
+U+9c6e Xu # Character é±®
+U+9c6f Huo # Character 鱯
+U+9c70 Shiira # Character é±°
+U+9c71 Li # Character é±±
+U+9c72 Lie # Character é±²
+U+9c73 Li # Character é±³
+U+9c74 Mie # Character é±´
+U+9c75 Zhen # Character é±µ
+U+9c76 Xiang # Character 鱶
+U+9c77 E # Character é±·
+U+9c78 Lu # Character 鱸
+U+9c79 Guan # Character é±¹
+U+9c7a Li # Character 鱺
+U+9c7b Xian # Character é±»
+U+9c7c Yu # Character é±¼
+U+9c7d Dao # Character é±½
+U+9c7e Ji # Character é±¾
+U+9c7f You # Character 鱿
+U+9c80 Tun # Character é²
+U+9c81 Lu # Character é²
+U+9c82 Fang # Character é²
+U+9c83 Ba # Character é²
+U+9c84 He # Character é²
+U+9c85 Bo # Character é²
+U+9c86 Ping # Character é²
+U+9c87 Nian # Character é²
+U+9c88 Lu # Character é²
+U+9c89 You # Character é²
+U+9c8a Zha # Character é²
+U+9c8b Fu # Character é²
+U+9c8c Bo # Character é²
+U+9c8d Bao # Character é²
+U+9c8e Hou # Character é²
+U+9c8f Pi # Character é²
+U+9c90 Tai # Character é²
+U+9c91 Gui # Character é²
+U+9c92 Jie # Character é²
+U+9c93 Kao # Character é²
+U+9c94 Wei # Character é²
+U+9c95 Er # Character é²
+U+9c96 Tong # Character é²
+U+9c97 Ze # Character é²
+U+9c98 Hou # Character é²
+U+9c99 Kuai # Character é²
+U+9c9a Ji # Character é²
+U+9c9b Jiao # Character é²
+U+9c9c Xian # Character é²
+U+9c9d Za # Character é²
+U+9c9e Xiang # Character é²
+U+9c9f Xun # Character é²
+U+9ca0 Geng # Character é²
+U+9ca1 Li # Character 鲡
+U+9ca2 Lian # Character é²¢
+U+9ca3 Jian # Character é²£
+U+9ca4 Li # Character 鲤
+U+9ca5 Shi # Character é²¥
+U+9ca6 Tiao # Character 鲦
+U+9ca7 Gun # Character 鲧
+U+9ca8 Sha # Character 鲨
+U+9ca9 Wan # Character 鲩
+U+9caa Jun # Character 鲪
+U+9cab Ji # Character 鲫
+U+9cac Yong # Character 鲬
+U+9cad Qing # Character é²
+U+9cae Ling # Character é²®
+U+9caf Qi # Character 鲯
+U+9cb0 Zou # Character é²°
+U+9cb1 Fei # Character é²±
+U+9cb2 Kun # Character é²²
+U+9cb3 Chang # Character é²³
+U+9cb4 Gu # Character é²´
+U+9cb5 Ni # Character é²µ
+U+9cb6 Nian # Character 鲶
+U+9cb7 Diao # Character é²·
+U+9cb8 Jing # Character 鲸
+U+9cb9 Shen # Character é²¹
+U+9cba Shi # Character 鲺
+U+9cbb Zi # Character é²»
+U+9cbc Fen # Character é²¼
+U+9cbd Die # Character é²½
+U+9cbe Bi # Character é²¾
+U+9cbf Chang # Character 鲿
+U+9cc0 Shi # Character é³
+U+9cc1 Wen # Character é³
+U+9cc2 Wei # Character é³
+U+9cc3 Sai # Character é³
+U+9cc4 E # Character é³
+U+9cc5 Qiu # Character é³
+U+9cc6 Fu # Character é³
+U+9cc7 Huang # Character é³
+U+9cc8 Quan # Character é³
+U+9cc9 Jiang # Character é³
+U+9cca Bian # Character é³
+U+9ccb Sao # Character é³
+U+9ccc Ao # Character é³
+U+9ccd Qi # Character é³
+U+9cce Ta # Character é³
+U+9ccf Yin # Character é³
+U+9cd0 Yao # Character é³
+U+9cd1 Fang # Character é³
+U+9cd2 Jian # Character é³
+U+9cd3 Le # Character é³
+U+9cd4 Biao # Character é³
+U+9cd5 Xue # Character é³
+U+9cd6 Bie # Character é³
+U+9cd7 Man # Character é³
+U+9cd8 Min # Character é³
+U+9cd9 Yong # Character é³
+U+9cda Wei # Character é³
+U+9cdb Xi # Character é³
+U+9cdc Jue # Character é³
+U+9cdd Shan # Character é³
+U+9cde Lin # Character é³
+U+9cdf Zun # Character é³
+U+9ce0 Huo # Character é³
+U+9ce1 Gan # Character 鳡
+U+9ce2 Li # Character é³¢
+U+9ce3 Zhan # Character é³£
+U+9ce4 Guan # Character 鳤
+U+9ce5 Niao # Character é³¥
+U+9ce6 Yi # Character 鳦
+U+9ce7 Fu # Character 鳧
+U+9ce8 Li # Character 鳨
+U+9ce9 Jiu # Character 鳩
+U+9cea Bu # Character 鳪
+U+9ceb Yan # Character 鳫
+U+9cec Fu # Character 鳬
+U+9ced Diao # Character é³
+U+9cee Ji # Character é³®
+U+9cef Feng # Character 鳯
+U+9cf0 Nio # Character é³°
+U+9cf1 Gan # Character é³±
+U+9cf2 Shi # Character é³²
+U+9cf3 Feng # Character é³³
+U+9cf4 Ming # Character é³´
+U+9cf5 Bao # Character é³µ
+U+9cf6 Yuan # Character 鳶
+U+9cf7 Zhi # Character é³·
+U+9cf8 Hu # Character 鳸
+U+9cf9 Qin # Character é³¹
+U+9cfa Fu # Character 鳺
+U+9cfb Fen # Character é³»
+U+9cfc Wen # Character é³¼
+U+9cfd Jian # Character é³½
+U+9cfe Shi # Character é³¾
+U+9cff Yu # Character 鳿
diff --git a/resources/chars/ascii/row9d.trans b/resources/chars/ascii/row9d.trans
new file mode 100644
index 0000000..2dfb1fd
--- /dev/null
+++ b/resources/chars/ascii/row9d.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+9d00 Fou # Character é´
+U+9d01 Yiao # Character é´
+U+9d02 Jue # Character é´
+U+9d03 Jue # Character é´
+U+9d04 Pi # Character é´
+U+9d05 Huan # Character é´
+U+9d06 Zhen # Character é´
+U+9d07 Bao # Character é´
+U+9d08 Yan # Character é´
+U+9d09 Ya # Character é´
+U+9d0a Zheng # Character é´
+U+9d0b Fang # Character é´
+U+9d0c Feng # Character é´
+U+9d0d Wen # Character é´
+U+9d0e Ou # Character é´
+U+9d0f Te # Character é´
+U+9d10 Jia # Character é´
+U+9d11 Nu # Character é´
+U+9d12 Ling # Character é´
+U+9d13 Mie # Character é´
+U+9d14 Fu # Character é´
+U+9d15 Tuo # Character é´
+U+9d16 Wen # Character é´
+U+9d17 Li # Character é´
+U+9d18 Bian # Character é´
+U+9d19 Zhi # Character é´
+U+9d1a Ge # Character é´
+U+9d1b Yuan # Character é´
+U+9d1c Zi # Character é´
+U+9d1d Qu # Character é´
+U+9d1e Xiao # Character é´
+U+9d1f Zhi # Character é´
+U+9d20 Dan # Character é´
+U+9d21 Ju # Character é´¡
+U+9d22 You # Character é´¢
+U+9d23 Gu # Character é´£
+U+9d24 Zhong # Character é´¤
+U+9d25 Yu # Character é´¥
+U+9d26 Yang # Character é´¦
+U+9d27 Rong # Character é´§
+U+9d28 Ya # Character é´¨
+U+9d29 Tie # Character é´©
+U+9d2a Yu # Character é´ª
+U+9d2b Shigi # Character é´«
+U+9d2c Ying # Character é´¬
+U+9d2d Zhui # Character é´
+U+9d2e Wu # Character é´®
+U+9d2f Er # Character é´¯
+U+9d30 Gua # Character é´°
+U+9d31 Ai # Character é´±
+U+9d32 Zhi # Character é´²
+U+9d33 Yan # Character é´³
+U+9d34 Heng # Character é´´
+U+9d35 Jiao # Character é´µ
+U+9d36 Ji # Character é´¶
+U+9d37 Lie # Character é´·
+U+9d38 Zhu # Character é´¸
+U+9d39 Ren # Character é´¹
+U+9d3a Yi # Character é´º
+U+9d3b Hong # Character é´»
+U+9d3c Luo # Character é´¼
+U+9d3d Ru # Character é´½
+U+9d3e Mou # Character é´¾
+U+9d3f Ge # Character é´¿
+U+9d40 Ren # Character éµ
+U+9d41 Jiao # Character éµ
+U+9d42 Xiu # Character éµ
+U+9d43 Zhou # Character éµ
+U+9d44 Zhi # Character éµ
+U+9d45 Luo # Character éµ
+U+9d46 Chidori # Character éµ
+U+9d47 Toki # Character éµ
+U+9d48 Ten # Character éµ
+U+9d49 Luan # Character éµ
+U+9d4a Jia # Character éµ
+U+9d4b Ji # Character éµ
+U+9d4c Yu # Character éµ
+U+9d4d Huan # Character éµ
+U+9d4e Tuo # Character éµ
+U+9d4f Bu # Character éµ
+U+9d50 Wu # Character éµ
+U+9d51 Juan # Character éµ
+U+9d52 Yu # Character éµ
+U+9d53 Bo # Character éµ
+U+9d54 Xun # Character éµ
+U+9d55 Xun # Character éµ
+U+9d56 Bi # Character éµ
+U+9d57 Xi # Character éµ
+U+9d58 Jun # Character éµ
+U+9d59 Ju # Character éµ
+U+9d5a Tu # Character éµ
+U+9d5b Jing # Character éµ
+U+9d5c Ti # Character éµ
+U+9d5d E # Character éµ
+U+9d5e E # Character éµ
+U+9d5f Kuang # Character éµ
+U+9d60 Hu # Character éµ
+U+9d61 Wu # Character 鵡
+U+9d62 Shen # Character éµ¢
+U+9d63 Lai # Character éµ£
+U+9d64 Ikaruga # Character 鵤
+U+9d65 Kakesu # Character éµ¥
+U+9d66 Lu # Character 鵦
+U+9d67 Ping # Character 鵧
+U+9d68 Shu # Character 鵨
+U+9d69 Fu # Character 鵩
+U+9d6a An # Character 鵪
+U+9d6b Zhao # Character 鵫
+U+9d6c Peng # Character 鵬
+U+9d6d Qin # Character éµ
+U+9d6e Qian # Character éµ®
+U+9d6f Bei # Character 鵯
+U+9d70 Diao # Character éµ°
+U+9d71 Lu # Character éµ±
+U+9d72 Que # Character éµ²
+U+9d73 Jian # Character éµ³
+U+9d74 Ju # Character éµ´
+U+9d75 Tu # Character éµµ
+U+9d76 Ya # Character 鵶
+U+9d77 Yuan # Character éµ·
+U+9d78 Qi # Character 鵸
+U+9d79 Li # Character éµ¹
+U+9d7a Ye # Character 鵺
+U+9d7b Zhui # Character éµ»
+U+9d7c Kong # Character éµ¼
+U+9d7d Zhui # Character éµ½
+U+9d7e Kun # Character éµ¾
+U+9d7f Sheng # Character 鵿
+U+9d80 Qi # Character é¶
+U+9d81 Jing # Character é¶
+U+9d82 Yi # Character é¶
+U+9d83 Yi # Character é¶
+U+9d84 Jing # Character é¶
+U+9d85 Zi # Character é¶
+U+9d86 Lai # Character é¶
+U+9d87 Dong # Character é¶
+U+9d88 Qi # Character é¶
+U+9d89 Chun # Character é¶
+U+9d8a Geng # Character é¶
+U+9d8b Ju # Character é¶
+U+9d8c Qu # Character é¶
+U+9d8d Isuka # Character é¶
+U+9d8e Kikuitadaki # Character é¶
+U+9d8f Ji # Character é¶
+U+9d90 Shu # Character é¶
+U+9d91 ? # Character é¶
+U+9d92 Chi # Character é¶
+U+9d93 Miao # Character é¶
+U+9d94 Rou # Character é¶
+U+9d95 An # Character é¶
+U+9d96 Qiu # Character é¶
+U+9d97 Ti # Character é¶
+U+9d98 Hu # Character é¶
+U+9d99 Ti # Character é¶
+U+9d9a E # Character é¶
+U+9d9b Jie # Character é¶
+U+9d9c Mao # Character é¶
+U+9d9d Fu # Character é¶
+U+9d9e Chun # Character é¶
+U+9d9f Tu # Character é¶
+U+9da0 Yan # Character é¶
+U+9da1 He # Character 鶡
+U+9da2 Yuan # Character 鶢
+U+9da3 Pian # Character 鶣
+U+9da4 Yun # Character 鶤
+U+9da5 Mei # Character 鶥
+U+9da6 Hu # Character 鶦
+U+9da7 Ying # Character 鶧
+U+9da8 Dun # Character 鶨
+U+9da9 Mu # Character 鶩
+U+9daa Ju # Character 鶪
+U+9dab Tsugumi # Character 鶫
+U+9dac Cang # Character 鶬
+U+9dad Fang # Character é¶
+U+9dae Gu # Character 鶮
+U+9daf Ying # Character 鶯
+U+9db0 Yuan # Character 鶰
+U+9db1 Xuan # Character 鶱
+U+9db2 Weng # Character 鶲
+U+9db3 Shi # Character 鶳
+U+9db4 He # Character 鶴
+U+9db5 Chu # Character 鶵
+U+9db6 Tang # Character 鶶
+U+9db7 Xia # Character 鶷
+U+9db8 Ruo # Character 鶸
+U+9db9 Liu # Character 鶹
+U+9dba Ji # Character 鶺
+U+9dbb Gu # Character 鶻
+U+9dbc Jian # Character 鶼
+U+9dbd Zhun # Character 鶽
+U+9dbe Han # Character 鶾
+U+9dbf Zi # Character 鶿
+U+9dc0 Zi # Character é·
+U+9dc1 Ni # Character é·
+U+9dc2 Yao # Character é·
+U+9dc3 Yan # Character é·
+U+9dc4 Ji # Character é·
+U+9dc5 Li # Character é·
+U+9dc6 Tian # Character é·
+U+9dc7 Kou # Character é·
+U+9dc8 Ti # Character é·
+U+9dc9 Ti # Character é·
+U+9dca Ni # Character é·
+U+9dcb Tu # Character é·
+U+9dcc Ma # Character é·
+U+9dcd Jiao # Character é·
+U+9dce Gao # Character é·
+U+9dcf Tian # Character é·
+U+9dd0 Chen # Character é·
+U+9dd1 Li # Character é·
+U+9dd2 Zhuan # Character é·
+U+9dd3 Zhe # Character é·
+U+9dd4 Ao # Character é·
+U+9dd5 Yao # Character é·
+U+9dd6 Yi # Character é·
+U+9dd7 Ou # Character é·
+U+9dd8 Chi # Character é·
+U+9dd9 Zhi # Character é·
+U+9dda Liao # Character é·
+U+9ddb Rong # Character é·
+U+9ddc Lou # Character é·
+U+9ddd Bi # Character é·
+U+9dde Shuang # Character é·
+U+9ddf Zhuo # Character é·
+U+9de0 Yu # Character é·
+U+9de1 Wu # Character é·¡
+U+9de2 Jue # Character é·¢
+U+9de3 Yin # Character é·£
+U+9de4 Quan # Character é·¤
+U+9de5 Si # Character é·¥
+U+9de6 Jiao # Character é·¦
+U+9de7 Yi # Character é·§
+U+9de8 Hua # Character é·¨
+U+9de9 Bi # Character é·©
+U+9dea Ying # Character é·ª
+U+9deb Su # Character é·«
+U+9dec Huang # Character é·¬
+U+9ded Fan # Character é·
+U+9dee Jiao # Character é·®
+U+9def Liao # Character é·¯
+U+9df0 Yan # Character é·°
+U+9df1 Kao # Character é·±
+U+9df2 Jiu # Character é·²
+U+9df3 Xian # Character é·³
+U+9df4 Xian # Character é·´
+U+9df5 Tu # Character é·µ
+U+9df6 Mai # Character é·¶
+U+9df7 Zun # Character é··
+U+9df8 Yu # Character é·¸
+U+9df9 Ying # Character é·¹
+U+9dfa Lu # Character é·º
+U+9dfb Tuan # Character é·»
+U+9dfc Xian # Character é·¼
+U+9dfd Xue # Character é·½
+U+9dfe Yi # Character é·¾
+U+9dff Pi # Character é·¿
diff --git a/resources/chars/ascii/row9e.trans b/resources/chars/ascii/row9e.trans
new file mode 100644
index 0000000..3d05783
--- /dev/null
+++ b/resources/chars/ascii/row9e.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+9e00 Shu # Character é¸
+U+9e01 Luo # Character é¸
+U+9e02 Qi # Character é¸
+U+9e03 Yi # Character é¸
+U+9e04 Ji # Character é¸
+U+9e05 Zhe # Character é¸
+U+9e06 Yu # Character é¸
+U+9e07 Zhan # Character é¸
+U+9e08 Ye # Character é¸
+U+9e09 Yang # Character é¸
+U+9e0a Pi # Character é¸
+U+9e0b Ning # Character é¸
+U+9e0c Huo # Character é¸
+U+9e0d Mi # Character é¸
+U+9e0e Ying # Character é¸
+U+9e0f Meng # Character é¸
+U+9e10 Di # Character é¸
+U+9e11 Yue # Character é¸
+U+9e12 Yu # Character é¸
+U+9e13 Lei # Character é¸
+U+9e14 Bao # Character é¸
+U+9e15 Lu # Character é¸
+U+9e16 He # Character é¸
+U+9e17 Long # Character é¸
+U+9e18 Shuang # Character é¸
+U+9e19 Yue # Character é¸
+U+9e1a Ying # Character é¸
+U+9e1b Guan # Character é¸
+U+9e1c Qu # Character é¸
+U+9e1d Li # Character é¸
+U+9e1e Luan # Character é¸
+U+9e1f Niao # Character é¸
+U+9e20 Jiu # Character é¸
+U+9e21 Ji # Character 鸡
+U+9e22 Yuan # Character 鸢
+U+9e23 Ming # Character 鸣
+U+9e24 Shi # Character 鸤
+U+9e25 Ou # Character 鸥
+U+9e26 Ya # Character 鸦
+U+9e27 Cang # Character 鸧
+U+9e28 Bao # Character 鸨
+U+9e29 Zhen # Character 鸩
+U+9e2a Gu # Character 鸪
+U+9e2b Dong # Character 鸫
+U+9e2c Lu # Character 鸬
+U+9e2d Ya # Character é¸
+U+9e2e Xiao # Character 鸮
+U+9e2f Yang # Character 鸯
+U+9e30 Ling # Character 鸰
+U+9e31 Zhi # Character 鸱
+U+9e32 Qu # Character 鸲
+U+9e33 Yuan # Character 鸳
+U+9e34 Xue # Character 鸴
+U+9e35 Tuo # Character 鸵
+U+9e36 Si # Character 鸶
+U+9e37 Zhi # Character 鸷
+U+9e38 Er # Character 鸸
+U+9e39 Gua # Character 鸹
+U+9e3a Xiu # Character 鸺
+U+9e3b Heng # Character 鸻
+U+9e3c Zhou # Character 鸼
+U+9e3d Ge # Character 鸽
+U+9e3e Luan # Character 鸾
+U+9e3f Hong # Character 鸿
+U+9e40 Wu # Character é¹
+U+9e41 Bo # Character é¹
+U+9e42 Li # Character é¹
+U+9e43 Juan # Character é¹
+U+9e44 Hu # Character é¹
+U+9e45 E # Character é¹
+U+9e46 Yu # Character é¹
+U+9e47 Xian # Character é¹
+U+9e48 Ti # Character é¹
+U+9e49 Wu # Character é¹
+U+9e4a Que # Character é¹
+U+9e4b Miao # Character é¹
+U+9e4c An # Character é¹
+U+9e4d Kun # Character é¹
+U+9e4e Bei # Character é¹
+U+9e4f Peng # Character é¹
+U+9e50 Qian # Character é¹
+U+9e51 Chun # Character é¹
+U+9e52 Geng # Character é¹
+U+9e53 Yuan # Character é¹
+U+9e54 Su # Character é¹
+U+9e55 Hu # Character é¹
+U+9e56 He # Character é¹
+U+9e57 E # Character é¹
+U+9e58 Gu # Character é¹
+U+9e59 Qiu # Character é¹
+U+9e5a Zi # Character é¹
+U+9e5b Mei # Character é¹
+U+9e5c Mu # Character é¹
+U+9e5d Ni # Character é¹
+U+9e5e Yao # Character é¹
+U+9e5f Weng # Character é¹
+U+9e60 Liu # Character é¹
+U+9e61 Ji # Character 鹡
+U+9e62 Ni # Character é¹¢
+U+9e63 Jian # Character é¹£
+U+9e64 He # Character 鹤
+U+9e65 Yi # Character é¹¥
+U+9e66 Ying # Character 鹦
+U+9e67 Zhe # Character 鹧
+U+9e68 Liao # Character 鹨
+U+9e69 Liao # Character 鹩
+U+9e6a Jiao # Character 鹪
+U+9e6b Jiu # Character 鹫
+U+9e6c Yu # Character 鹬
+U+9e6d Lu # Character é¹
+U+9e6e Xuan # Character é¹®
+U+9e6f Zhan # Character 鹯
+U+9e70 Ying # Character é¹°
+U+9e71 Huo # Character é¹±
+U+9e72 Meng # Character é¹²
+U+9e73 Guan # Character é¹³
+U+9e74 Shuang # Character é¹´
+U+9e75 Lu # Character é¹µ
+U+9e76 Jin # Character 鹶
+U+9e77 Ling # Character é¹·
+U+9e78 Jian # Character 鹸
+U+9e79 Xian # Character é¹¹
+U+9e7a Cuo # Character 鹺
+U+9e7b Jian # Character é¹»
+U+9e7c Jian # Character é¹¼
+U+9e7d Yan # Character é¹½
+U+9e7e Cuo # Character é¹¾
+U+9e7f Lu # Character 鹿
+U+9e80 You # Character éº
+U+9e81 Cu # Character éº
+U+9e82 Ji # Character éº
+U+9e83 Biao # Character éº
+U+9e84 Cu # Character éº
+U+9e85 Biao # Character éº
+U+9e86 Zhu # Character éº
+U+9e87 Jun # Character éº
+U+9e88 Zhu # Character éº
+U+9e89 Jian # Character éº
+U+9e8a Mi # Character éº
+U+9e8b Mi # Character éº
+U+9e8c Wu # Character éº
+U+9e8d Liu # Character éº
+U+9e8e Chen # Character éº
+U+9e8f Jun # Character éº
+U+9e90 Lin # Character éº
+U+9e91 Ni # Character éº
+U+9e92 Qi # Character éº
+U+9e93 Lu # Character éº
+U+9e94 Jiu # Character éº
+U+9e95 Jun # Character éº
+U+9e96 Jing # Character éº
+U+9e97 Li # Character éº
+U+9e98 Xiang # Character éº
+U+9e99 Yan # Character éº
+U+9e9a Jia # Character éº
+U+9e9b Mi # Character éº
+U+9e9c Li # Character éº
+U+9e9d She # Character éº
+U+9e9e Zhang # Character éº
+U+9e9f Lin # Character éº
+U+9ea0 Jing # Character éº
+U+9ea1 Ji # Character 麡
+U+9ea2 Ling # Character 麢
+U+9ea3 Yan # Character 麣
+U+9ea4 Cu # Character 麤
+U+9ea5 Mai # Character 麥
+U+9ea6 Mai # Character 麦
+U+9ea7 Ge # Character 麧
+U+9ea8 Chao # Character 麨
+U+9ea9 Fu # Character 麩
+U+9eaa Mian # Character 麪
+U+9eab Mian # Character 麫
+U+9eac Fu # Character 麬
+U+9ead Pao # Character éº
+U+9eae Qu # Character 麮
+U+9eaf Qu # Character 麯
+U+9eb0 Mou # Character 麰
+U+9eb1 Fu # Character 麱
+U+9eb2 Xian # Character 麲
+U+9eb3 Lai # Character 麳
+U+9eb4 Qu # Character 麴
+U+9eb5 Mian # Character 麵
+U+9eb6 ? # Character 麶
+U+9eb7 Feng # Character 麷
+U+9eb8 Fu # Character 麸
+U+9eb9 Qu # Character 麹
+U+9eba Mian # Character 麺
+U+9ebb Ma # Character 麻
+U+9ebc Mo # Character 麼
+U+9ebd Mo # Character 麽
+U+9ebe Hui # Character 麾
+U+9ebf Ma # Character 麿
+U+9ec0 Zou # Character é»
+U+9ec1 Nen # Character é»
+U+9ec2 Fen # Character é»
+U+9ec3 Huang # Character é»
+U+9ec4 Huang # Character é»
+U+9ec5 Jin # Character é»
+U+9ec6 Guang # Character é»
+U+9ec7 Tian # Character é»
+U+9ec8 Tou # Character é»
+U+9ec9 Heng # Character é»
+U+9eca Xi # Character é»
+U+9ecb Kuang # Character é»
+U+9ecc Heng # Character é»
+U+9ecd Shu # Character é»
+U+9ece Li # Character é»
+U+9ecf Nian # Character é»
+U+9ed0 Chi # Character é»
+U+9ed1 Hei # Character é»
+U+9ed2 Hei # Character é»
+U+9ed3 Yi # Character é»
+U+9ed4 Qian # Character é»
+U+9ed5 Dan # Character é»
+U+9ed6 Xi # Character é»
+U+9ed7 Tuan # Character é»
+U+9ed8 Mo # Character é»
+U+9ed9 Mo # Character é»
+U+9eda Qian # Character é»
+U+9edb Dai # Character é»
+U+9edc Chu # Character é»
+U+9edd You # Character é»
+U+9ede Dian # Character é»
+U+9edf Yi # Character é»
+U+9ee0 Xia # Character é»
+U+9ee1 Yan # Character 黡
+U+9ee2 Qu # Character 黢
+U+9ee3 Mei # Character 黣
+U+9ee4 Yan # Character 黤
+U+9ee5 Jing # Character 黥
+U+9ee6 Yu # Character 黦
+U+9ee7 Li # Character 黧
+U+9ee8 Dang # Character 黨
+U+9ee9 Du # Character 黩
+U+9eea Can # Character 黪
+U+9eeb Yin # Character 黫
+U+9eec An # Character 黬
+U+9eed Yan # Character é»
+U+9eee Tan # Character é»®
+U+9eef An # Character 黯
+U+9ef0 Zhen # Character é»°
+U+9ef1 Dai # Character é»±
+U+9ef2 Can # Character 黲
+U+9ef3 Yi # Character 黳
+U+9ef4 Mei # Character é»´
+U+9ef5 Dan # Character 黵
+U+9ef6 Yan # Character 黶
+U+9ef7 Du # Character é»·
+U+9ef8 Lu # Character 黸
+U+9ef9 Zhi # Character 黹
+U+9efa Fen # Character 黺
+U+9efb Fu # Character é»»
+U+9efc Fu # Character 黼
+U+9efd Min # Character 黽
+U+9efe Min # Character 黾
+U+9eff Yuan # Character 黿
diff --git a/resources/chars/ascii/row9f.trans b/resources/chars/ascii/row9f.trans
new file mode 100644
index 0000000..ff05fef
--- /dev/null
+++ b/resources/chars/ascii/row9f.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+9f00 Cu # Character é¼
+U+9f01 Qu # Character é¼
+U+9f02 Chao # Character é¼
+U+9f03 Wa # Character é¼
+U+9f04 Zhu # Character é¼
+U+9f05 Zhi # Character é¼
+U+9f06 Mang # Character é¼
+U+9f07 Ao # Character é¼
+U+9f08 Bie # Character é¼
+U+9f09 Tuo # Character é¼
+U+9f0a Bi # Character é¼
+U+9f0b Yuan # Character é¼
+U+9f0c Chao # Character é¼
+U+9f0d Tuo # Character é¼
+U+9f0e Ding # Character é¼
+U+9f0f Mi # Character é¼
+U+9f10 Nai # Character é¼
+U+9f11 Ding # Character é¼
+U+9f12 Zi # Character é¼
+U+9f13 Gu # Character é¼
+U+9f14 Gu # Character é¼
+U+9f15 Dong # Character é¼
+U+9f16 Fen # Character é¼
+U+9f17 Tao # Character é¼
+U+9f18 Yuan # Character é¼
+U+9f19 Pi # Character é¼
+U+9f1a Chang # Character é¼
+U+9f1b Gao # Character é¼
+U+9f1c Qi # Character é¼
+U+9f1d Yuan # Character é¼
+U+9f1e Tang # Character é¼
+U+9f1f Teng # Character é¼
+U+9f20 Shu # Character é¼
+U+9f21 Shu # Character 鼡
+U+9f22 Fen # Character é¼¢
+U+9f23 Fei # Character é¼£
+U+9f24 Wen # Character 鼤
+U+9f25 Ba # Character é¼¥
+U+9f26 Diao # Character 鼦
+U+9f27 Tuo # Character 鼧
+U+9f28 Tong # Character 鼨
+U+9f29 Qu # Character 鼩
+U+9f2a Sheng # Character 鼪
+U+9f2b Shi # Character 鼫
+U+9f2c You # Character 鼬
+U+9f2d Shi # Character é¼
+U+9f2e Ting # Character é¼®
+U+9f2f Wu # Character 鼯
+U+9f30 Nian # Character é¼°
+U+9f31 Jing # Character é¼±
+U+9f32 Hun # Character é¼²
+U+9f33 Ju # Character é¼³
+U+9f34 Yan # Character é¼´
+U+9f35 Tu # Character é¼µ
+U+9f36 Ti # Character 鼶
+U+9f37 Xi # Character é¼·
+U+9f38 Xian # Character 鼸
+U+9f39 Yan # Character é¼¹
+U+9f3a Lei # Character 鼺
+U+9f3b Bi # Character é¼»
+U+9f3c Yao # Character é¼¼
+U+9f3d Qiu # Character é¼½
+U+9f3e Han # Character é¼¾
+U+9f3f Wu # Character 鼿
+U+9f40 Wu # Character é½
+U+9f41 Hou # Character é½
+U+9f42 Xi # Character é½
+U+9f43 Ge # Character é½
+U+9f44 Zha # Character é½
+U+9f45 Xiu # Character é½
+U+9f46 Weng # Character é½
+U+9f47 Zha # Character é½
+U+9f48 Nong # Character é½
+U+9f49 Nang # Character é½
+U+9f4a Qi # Character é½
+U+9f4b Zhai # Character é½
+U+9f4c Ji # Character é½
+U+9f4d Zi # Character é½
+U+9f4e Ji # Character é½
+U+9f4f Ji # Character é½
+U+9f50 Qi # Character é½
+U+9f51 Ji # Character é½
+U+9f52 Chi # Character é½
+U+9f53 Chen # Character é½
+U+9f54 Chen # Character é½
+U+9f55 He # Character é½
+U+9f56 Ya # Character é½
+U+9f57 Ken # Character é½
+U+9f58 Xie # Character é½
+U+9f59 Pao # Character é½
+U+9f5a Cuo # Character é½
+U+9f5b Shi # Character é½
+U+9f5c Zi # Character é½
+U+9f5d Chi # Character é½
+U+9f5e Nian # Character é½
+U+9f5f Ju # Character é½
+U+9f60 Tiao # Character é½
+U+9f61 Ling # Character 齡
+U+9f62 Ling # Character é½¢
+U+9f63 Chu # Character é½£
+U+9f64 Quan # Character 齤
+U+9f65 Xie # Character é½¥
+U+9f66 Ken # Character 齦
+U+9f67 Nie # Character 齧
+U+9f68 Jiu # Character 齨
+U+9f69 Yao # Character 齩
+U+9f6a Chuo # Character 齪
+U+9f6b Kun # Character 齫
+U+9f6c Yu # Character 齬
+U+9f6d Chu # Character é½
+U+9f6e Yi # Character é½®
+U+9f6f Ni # Character 齯
+U+9f70 Cuo # Character é½°
+U+9f71 Zou # Character é½±
+U+9f72 Qu # Character é½²
+U+9f73 Nen # Character é½³
+U+9f74 Xian # Character é½´
+U+9f75 Ou # Character é½µ
+U+9f76 E # Character 齶
+U+9f77 Wo # Character é½·
+U+9f78 Yi # Character 齸
+U+9f79 Chuo # Character é½¹
+U+9f7a Zou # Character 齺
+U+9f7b Dian # Character é½»
+U+9f7c Chu # Character é½¼
+U+9f7d Jin # Character é½½
+U+9f7e Ya # Character é½¾
+U+9f7f Chi # Character 齿
+U+9f80 Chen # Character é¾
+U+9f81 He # Character é¾
+U+9f82 Ken # Character é¾
+U+9f83 Ju # Character é¾
+U+9f84 Ling # Character é¾
+U+9f85 Pao # Character é¾
+U+9f86 Tiao # Character é¾
+U+9f87 Zi # Character é¾
+U+9f88 Ken # Character é¾
+U+9f89 Yu # Character é¾
+U+9f8a Chuo # Character é¾
+U+9f8b Qu # Character é¾
+U+9f8c Wo # Character é¾
+U+9f8d Long # Character é¾
+U+9f8e Pang # Character é¾
+U+9f8f Gong # Character é¾
+U+9f90 Pang # Character é¾
+U+9f91 Yan # Character é¾
+U+9f92 Long # Character é¾
+U+9f93 Long # Character é¾
+U+9f94 Gong # Character é¾
+U+9f95 Kan # Character é¾
+U+9f96 Ta # Character é¾
+U+9f97 Ling # Character é¾
+U+9f98 Ta # Character é¾
+U+9f99 Long # Character é¾
+U+9f9a Gong # Character é¾
+U+9f9b Kan # Character é¾
+U+9f9c Gui # Character é¾
+U+9f9d Qiu # Character é¾
+U+9f9e Bie # Character é¾
+U+9f9f Gui # Character é¾
+U+9fa0 Yue # Character é¾
+U+9fa1 Chui # Character 龡
+U+9fa2 He # Character é¾¢
+U+9fa3 Jue # Character é¾£
+U+9fa4 Xie # Character 龤
+U+9fa5 Yu # Character é¾¥
+U+9fa6 ? # Character 龦
+U+9fa7 ? # Character 龧
+U+9fa8 ? # Character 龨
+U+9fa9 ? # Character 龩
+U+9faa ? # Character 龪
+U+9fab ? # Character 龫
+U+9fac ? # Character 龬
+U+9fad ? # Character é¾
+U+9fae ? # Character é¾®
+U+9faf ? # Character 龯
+U+9fb0 ? # Character é¾°
+U+9fb1 ? # Character é¾±
+U+9fb2 ? # Character é¾²
+U+9fb3 ? # Character é¾³
+U+9fb4 ? # Character é¾´
+U+9fb5 ? # Character é¾µ
+U+9fb6 ? # Character 龶
+U+9fb7 ? # Character é¾·
+U+9fb8 ? # Character 龸
+U+9fb9 ? # Character é¾¹
+U+9fba ? # Character 龺
+U+9fbb ? # Character é¾»
+U+9fbc ? # Character é¾¼
+U+9fbd ? # Character é¾½
+U+9fbe ? # Character é¾¾
+U+9fbf ? # Character 龿
+U+9fc0 ? # Character é¿
+U+9fc1 ? # Character é¿
+U+9fc2 ? # Character é¿
+U+9fc3 ? # Character é¿
+U+9fc4 ? # Character é¿
+U+9fc5 ? # Character é¿
+U+9fc6 ? # Character é¿
+U+9fc7 ? # Character é¿
+U+9fc8 ? # Character é¿
+U+9fc9 ? # Character é¿
+U+9fca ? # Character é¿
+U+9fcb ? # Character é¿
+U+9fcc ? # Character é¿
+U+9fcd ? # Character é¿
+U+9fce ? # Character é¿
+U+9fcf ? # Character é¿
+U+9fd0 ? # Character é¿
+U+9fd1 ? # Character é¿
+U+9fd2 ? # Character é¿
+U+9fd3 ? # Character é¿
+U+9fd4 ? # Character é¿
+U+9fd5 ? # Character é¿
+U+9fd6 ? # Character é¿
+U+9fd7 ? # Character é¿
+U+9fd8 ? # Character é¿
+U+9fd9 ? # Character é¿
+U+9fda ? # Character é¿
+U+9fdb ? # Character é¿
+U+9fdc ? # Character é¿
+U+9fdd ? # Character é¿
+U+9fde ? # Character é¿
+U+9fdf ? # Character é¿
+U+9fe0 ? # Character é¿
+U+9fe1 ? # Character é¿¡
+U+9fe2 ? # Character é¿¢
+U+9fe3 ? # Character é¿£
+U+9fe4 ? # Character 鿤
+U+9fe5 ? # Character é¿¥
+U+9fe6 ? # Character 鿦
+U+9fe7 ? # Character 鿧
+U+9fe8 ? # Character 鿨
+U+9fe9 ? # Character é¿©
+U+9fea ? # Character 鿪
+U+9feb ? # Character é¿«
+U+9fec ? # Character 鿬
+U+9fed ? # Character é¿
+U+9fee ? # Character é¿®
+U+9fef ? # Character 鿯
+U+9ff0 ? # Character é¿°
+U+9ff1 ? # Character 鿱
+U+9ff2 ? # Character 鿲
+U+9ff3 ? # Character 鿳
+U+9ff4 ? # Character é¿´
+U+9ff5 ? # Character 鿵
+U+9ff6 ? # Character 鿶
+U+9ff7 ? # Character é¿·
+U+9ff8 ? # Character 鿸
+U+9ff9 ? # Character 鿹
+U+9ffa ? # Character 鿺
+U+9ffb ? # Character é¿»
+U+9ffc ? # Character 鿼
+U+9ffd ? # Character 鿽
+U+9ffe ? # Character 鿾
+U+9fff ? # Character é¿¿
diff --git a/resources/chars/ascii/rowa0.trans b/resources/chars/ascii/rowa0.trans
new file mode 100644
index 0000000..11c7c18
--- /dev/null
+++ b/resources/chars/ascii/rowa0.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+a000 it # Character ê
+U+a001 ix # Character ê
+U+a002 i # Character ê
+U+a003 ip # Character ê
+U+a004 iet # Character ê
+U+a005 iex # Character ê
+U+a006 ie # Character ê
+U+a007 iep # Character ê
+U+a008 at # Character ê
+U+a009 ax # Character ê
+U+a00a a # Character ê
+U+a00b ap # Character ê
+U+a00c uox # Character ê
+U+a00d uo # Character ê
+U+a00e uop # Character ê
+U+a00f ot # Character ê
+U+a010 ox # Character ê
+U+a011 o # Character ê
+U+a012 op # Character ê
+U+a013 ex # Character ê
+U+a014 e # Character ê
+U+a015 wu # Character ê
+U+a016 bit # Character ê
+U+a017 bix # Character ê
+U+a018 bi # Character ê
+U+a019 bip # Character ê
+U+a01a biet # Character ê
+U+a01b biex # Character ê
+U+a01c bie # Character ê
+U+a01d biep # Character ê
+U+a01e bat # Character ê
+U+a01f bax # Character ê
+U+a020 ba # Character ê
+U+a021 bap # Character ê¡
+U+a022 buox # Character ê¢
+U+a023 buo # Character ê£
+U+a024 buop # Character ê¤
+U+a025 bot # Character ê¥
+U+a026 box # Character ê¦
+U+a027 bo # Character ê§
+U+a028 bop # Character ê¨
+U+a029 bex # Character ê©
+U+a02a be # Character êª
+U+a02b bep # Character ê«
+U+a02c but # Character ê¬
+U+a02d bux # Character ê
+U+a02e bu # Character ê®
+U+a02f bup # Character ê¯
+U+a030 burx # Character ê°
+U+a031 bur # Character ê±
+U+a032 byt # Character ê²
+U+a033 byx # Character ê³
+U+a034 by # Character ê´
+U+a035 byp # Character êµ
+U+a036 byrx # Character ê¶
+U+a037 byr # Character ê·
+U+a038 pit # Character ê¸
+U+a039 pix # Character ê¹
+U+a03a pi # Character êº
+U+a03b pip # Character ê»
+U+a03c piex # Character ê¼
+U+a03d pie # Character ê½
+U+a03e piep # Character ê¾
+U+a03f pat # Character ê¿
+U+a040 pax # Character ê
+U+a041 pa # Character ê
+U+a042 pap # Character ê
+U+a043 puox # Character ê
+U+a044 puo # Character ê
+U+a045 puop # Character ê
+U+a046 pot # Character ê
+U+a047 pox # Character ê
+U+a048 po # Character ê
+U+a049 pop # Character ê
+U+a04a put # Character ê
+U+a04b pux # Character ê
+U+a04c pu # Character ê
+U+a04d pup # Character ê
+U+a04e purx # Character ê
+U+a04f pur # Character ê
+U+a050 pyt # Character ê
+U+a051 pyx # Character ê
+U+a052 py # Character ê
+U+a053 pyp # Character ê
+U+a054 pyrx # Character ê
+U+a055 pyr # Character ê
+U+a056 bbit # Character ê
+U+a057 bbix # Character ê
+U+a058 bbi # Character ê
+U+a059 bbip # Character ê
+U+a05a bbiet # Character ê
+U+a05b bbiex # Character ê
+U+a05c bbie # Character ê
+U+a05d bbiep # Character ê
+U+a05e bbat # Character ê
+U+a05f bbax # Character ê
+U+a060 bba # Character ê
+U+a061 bbap # Character ê¡
+U+a062 bbuox # Character ê¢
+U+a063 bbuo # Character ê£
+U+a064 bbuop # Character ê¤
+U+a065 bbot # Character ê¥
+U+a066 bbox # Character ê¦
+U+a067 bbo # Character ê§
+U+a068 bbop # Character ê¨
+U+a069 bbex # Character ê©
+U+a06a bbe # Character êª
+U+a06b bbep # Character ê«
+U+a06c bbut # Character ê¬
+U+a06d bbux # Character ê
+U+a06e bbu # Character ê®
+U+a06f bbup # Character ê¯
+U+a070 bburx # Character ê°
+U+a071 bbur # Character ê±
+U+a072 bbyt # Character ê²
+U+a073 bbyx # Character ê³
+U+a074 bby # Character ê´
+U+a075 bbyp # Character êµ
+U+a076 nbit # Character ê¶
+U+a077 nbix # Character ê·
+U+a078 nbi # Character ê¸
+U+a079 nbip # Character ê¹
+U+a07a nbiex # Character êº
+U+a07b nbie # Character ê»
+U+a07c nbiep # Character ê¼
+U+a07d nbat # Character ê½
+U+a07e nbax # Character ê¾
+U+a07f nba # Character ê¿
+U+a080 nbap # Character ê
+U+a081 nbot # Character ê
+U+a082 nbox # Character ê
+U+a083 nbo # Character ê
+U+a084 nbop # Character ê
+U+a085 nbut # Character ê
+U+a086 nbux # Character ê
+U+a087 nbu # Character ê
+U+a088 nbup # Character ê
+U+a089 nburx # Character ê
+U+a08a nbur # Character ê
+U+a08b nbyt # Character ê
+U+a08c nbyx # Character ê
+U+a08d nby # Character ê
+U+a08e nbyp # Character ê
+U+a08f nbyrx # Character ê
+U+a090 nbyr # Character ê
+U+a091 hmit # Character ê
+U+a092 hmix # Character ê
+U+a093 hmi # Character ê
+U+a094 hmip # Character ê
+U+a095 hmiex # Character ê
+U+a096 hmie # Character ê
+U+a097 hmiep # Character ê
+U+a098 hmat # Character ê
+U+a099 hmax # Character ê
+U+a09a hma # Character ê
+U+a09b hmap # Character ê
+U+a09c hmuox # Character ê
+U+a09d hmuo # Character ê
+U+a09e hmuop # Character ê
+U+a09f hmot # Character ê
+U+a0a0 hmox # Character ê
+U+a0a1 hmo # Character ê¡
+U+a0a2 hmop # Character ê¢
+U+a0a3 hmut # Character ê£
+U+a0a4 hmux # Character ê¤
+U+a0a5 hmu # Character ê¥
+U+a0a6 hmup # Character ê¦
+U+a0a7 hmurx # Character ê§
+U+a0a8 hmur # Character ê¨
+U+a0a9 hmyx # Character ê©
+U+a0aa hmy # Character êª
+U+a0ab hmyp # Character ê«
+U+a0ac hmyrx # Character ê¬
+U+a0ad hmyr # Character ê
+U+a0ae mit # Character ê®
+U+a0af mix # Character ê¯
+U+a0b0 mi # Character ê°
+U+a0b1 mip # Character ê±
+U+a0b2 miex # Character ê²
+U+a0b3 mie # Character ê³
+U+a0b4 miep # Character ê´
+U+a0b5 mat # Character êµ
+U+a0b6 max # Character ê¶
+U+a0b7 ma # Character ê·
+U+a0b8 map # Character ê¸
+U+a0b9 muot # Character ê¹
+U+a0ba muox # Character êº
+U+a0bb muo # Character ê»
+U+a0bc muop # Character ê¼
+U+a0bd mot # Character ê½
+U+a0be mox # Character ê¾
+U+a0bf mo # Character ê¿
+U+a0c0 mop # Character ê
+U+a0c1 mex # Character ê
+U+a0c2 me # Character ê
+U+a0c3 mut # Character ê
+U+a0c4 mux # Character ê
+U+a0c5 mu # Character ê
+U+a0c6 mup # Character ê
+U+a0c7 murx # Character ê
+U+a0c8 mur # Character ê
+U+a0c9 myt # Character ê
+U+a0ca myx # Character ê
+U+a0cb my # Character ê
+U+a0cc myp # Character ê
+U+a0cd fit # Character ê
+U+a0ce fix # Character ê
+U+a0cf fi # Character ê
+U+a0d0 fip # Character ê
+U+a0d1 fat # Character ê
+U+a0d2 fax # Character ê
+U+a0d3 fa # Character ê
+U+a0d4 fap # Character ê
+U+a0d5 fox # Character ê
+U+a0d6 fo # Character ê
+U+a0d7 fop # Character ê
+U+a0d8 fut # Character ê
+U+a0d9 fux # Character ê
+U+a0da fu # Character ê
+U+a0db fup # Character ê
+U+a0dc furx # Character ê
+U+a0dd fur # Character ê
+U+a0de fyt # Character ê
+U+a0df fyx # Character ê
+U+a0e0 fy # Character ê
+U+a0e1 fyp # Character ê¡
+U+a0e2 vit # Character ê¢
+U+a0e3 vix # Character ê£
+U+a0e4 vi # Character ê¤
+U+a0e5 vip # Character ê¥
+U+a0e6 viet # Character ê¦
+U+a0e7 viex # Character ê§
+U+a0e8 vie # Character ê¨
+U+a0e9 viep # Character ê©
+U+a0ea vat # Character êª
+U+a0eb vax # Character ê«
+U+a0ec va # Character ê¬
+U+a0ed vap # Character ê
+U+a0ee vot # Character ê®
+U+a0ef vox # Character ê¯
+U+a0f0 vo # Character ê°
+U+a0f1 vop # Character ê±
+U+a0f2 vex # Character ê²
+U+a0f3 vep # Character ê³
+U+a0f4 vut # Character ê´
+U+a0f5 vux # Character êµ
+U+a0f6 vu # Character ê¶
+U+a0f7 vup # Character ê·
+U+a0f8 vurx # Character ê¸
+U+a0f9 vur # Character ê¹
+U+a0fa vyt # Character êº
+U+a0fb vyx # Character ê»
+U+a0fc vy # Character ê¼
+U+a0fd vyp # Character ê½
+U+a0fe vyrx # Character ê¾
+U+a0ff vyr # Character ê¿
diff --git a/resources/chars/ascii/rowa1.trans b/resources/chars/ascii/rowa1.trans
new file mode 100644
index 0000000..1a74e78
--- /dev/null
+++ b/resources/chars/ascii/rowa1.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+a100 dit # Character ê
+U+a101 dix # Character ê
+U+a102 di # Character ê
+U+a103 dip # Character ê
+U+a104 diex # Character ê
+U+a105 die # Character ê
+U+a106 diep # Character ê
+U+a107 dat # Character ê
+U+a108 dax # Character ê
+U+a109 da # Character ê
+U+a10a dap # Character ê
+U+a10b duox # Character ê
+U+a10c duo # Character ê
+U+a10d dot # Character ê
+U+a10e dox # Character ê
+U+a10f do # Character ê
+U+a110 dop # Character ê
+U+a111 dex # Character ê
+U+a112 de # Character ê
+U+a113 dep # Character ê
+U+a114 dut # Character ê
+U+a115 dux # Character ê
+U+a116 du # Character ê
+U+a117 dup # Character ê
+U+a118 durx # Character ê
+U+a119 dur # Character ê
+U+a11a tit # Character ê
+U+a11b tix # Character ê
+U+a11c ti # Character ê
+U+a11d tip # Character ê
+U+a11e tiex # Character ê
+U+a11f tie # Character ê
+U+a120 tiep # Character ê
+U+a121 tat # Character ê¡
+U+a122 tax # Character ê¢
+U+a123 ta # Character ê£
+U+a124 tap # Character ê¤
+U+a125 tuot # Character ê¥
+U+a126 tuox # Character ê¦
+U+a127 tuo # Character ê§
+U+a128 tuop # Character ê¨
+U+a129 tot # Character ê©
+U+a12a tox # Character êª
+U+a12b to # Character ê«
+U+a12c top # Character ê¬
+U+a12d tex # Character ê
+U+a12e te # Character ê®
+U+a12f tep # Character ê¯
+U+a130 tut # Character ê°
+U+a131 tux # Character ê±
+U+a132 tu # Character ê²
+U+a133 tup # Character ê³
+U+a134 turx # Character ê´
+U+a135 tur # Character êµ
+U+a136 ddit # Character ê¶
+U+a137 ddix # Character ê·
+U+a138 ddi # Character ê¸
+U+a139 ddip # Character ê¹
+U+a13a ddiex # Character êº
+U+a13b ddie # Character ê»
+U+a13c ddiep # Character ê¼
+U+a13d ddat # Character ê½
+U+a13e ddax # Character ê¾
+U+a13f dda # Character ê¿
+U+a140 ddap # Character ê
+U+a141 dduox # Character ê
+U+a142 dduo # Character ê
+U+a143 dduop # Character ê
+U+a144 ddot # Character ê
+U+a145 ddox # Character ê
+U+a146 ddo # Character ê
+U+a147 ddop # Character ê
+U+a148 ddex # Character ê
+U+a149 dde # Character ê
+U+a14a ddep # Character ê
+U+a14b ddut # Character ê
+U+a14c ddux # Character ê
+U+a14d ddu # Character ê
+U+a14e ddup # Character ê
+U+a14f ddurx # Character ê
+U+a150 ddur # Character ê
+U+a151 ndit # Character ê
+U+a152 ndix # Character ê
+U+a153 ndi # Character ê
+U+a154 ndip # Character ê
+U+a155 ndiex # Character ê
+U+a156 ndie # Character ê
+U+a157 ndat # Character ê
+U+a158 ndax # Character ê
+U+a159 nda # Character ê
+U+a15a ndap # Character ê
+U+a15b ndot # Character ê
+U+a15c ndox # Character ê
+U+a15d ndo # Character ê
+U+a15e ndop # Character ê
+U+a15f ndex # Character ê
+U+a160 nde # Character ê
+U+a161 ndep # Character ê
¡
+U+a162 ndut # Character ê
¢
+U+a163 ndux # Character ê
£
+U+a164 ndu # Character ê
¤
+U+a165 ndup # Character ê
¥
+U+a166 ndurx # Character ê
¦
+U+a167 ndur # Character ê
§
+U+a168 hnit # Character ê
¨
+U+a169 hnix # Character ê
©
+U+a16a hni # Character ê
ª
+U+a16b hnip # Character ê
«
+U+a16c hniet # Character ê
¬
+U+a16d hniex # Character ê
+U+a16e hnie # Character ê
®
+U+a16f hniep # Character ê
¯
+U+a170 hnat # Character ê
°
+U+a171 hnax # Character ê
±
+U+a172 hna # Character ê
²
+U+a173 hnap # Character ê
³
+U+a174 hnuox # Character ê
´
+U+a175 hnuo # Character ê
µ
+U+a176 hnot # Character ê
¶
+U+a177 hnox # Character ê
·
+U+a178 hnop # Character ê
¸
+U+a179 hnex # Character ê
¹
+U+a17a hne # Character ê
º
+U+a17b hnep # Character ê
»
+U+a17c hnut # Character ê
¼
+U+a17d nit # Character ê
½
+U+a17e nix # Character ê
¾
+U+a17f ni # Character ê
¿
+U+a180 nip # Character ê
+U+a181 niex # Character ê
+U+a182 nie # Character ê
+U+a183 niep # Character ê
+U+a184 nax # Character ê
+U+a185 na # Character ê
+U+a186 nap # Character ê
+U+a187 nuox # Character ê
+U+a188 nuo # Character ê
+U+a189 nuop # Character ê
+U+a18a not # Character ê
+U+a18b nox # Character ê
+U+a18c no # Character ê
+U+a18d nop # Character ê
+U+a18e nex # Character ê
+U+a18f ne # Character ê
+U+a190 nep # Character ê
+U+a191 nut # Character ê
+U+a192 nux # Character ê
+U+a193 nu # Character ê
+U+a194 nup # Character ê
+U+a195 nurx # Character ê
+U+a196 nur # Character ê
+U+a197 hlit # Character ê
+U+a198 hlix # Character ê
+U+a199 hli # Character ê
+U+a19a hlip # Character ê
+U+a19b hliex # Character ê
+U+a19c hlie # Character ê
+U+a19d hliep # Character ê
+U+a19e hlat # Character ê
+U+a19f hlax # Character ê
+U+a1a0 hla # Character ê
+U+a1a1 hlap # Character ê¡
+U+a1a2 hluox # Character ê¢
+U+a1a3 hluo # Character ê£
+U+a1a4 hluop # Character ê¤
+U+a1a5 hlox # Character ê¥
+U+a1a6 hlo # Character ê¦
+U+a1a7 hlop # Character ê§
+U+a1a8 hlex # Character ê¨
+U+a1a9 hle # Character ê©
+U+a1aa hlep # Character êª
+U+a1ab hlut # Character ê«
+U+a1ac hlux # Character ê¬
+U+a1ad hlu # Character ê
+U+a1ae hlup # Character ê®
+U+a1af hlurx # Character ê¯
+U+a1b0 hlur # Character ê°
+U+a1b1 hlyt # Character ê±
+U+a1b2 hlyx # Character ê²
+U+a1b3 hly # Character ê³
+U+a1b4 hlyp # Character ê´
+U+a1b5 hlyrx # Character êµ
+U+a1b6 hlyr # Character ê¶
+U+a1b7 lit # Character ê·
+U+a1b8 lix # Character ê¸
+U+a1b9 li # Character ê¹
+U+a1ba lip # Character êº
+U+a1bb liet # Character ê»
+U+a1bc liex # Character ê¼
+U+a1bd lie # Character ê½
+U+a1be liep # Character ê¾
+U+a1bf lat # Character ê¿
+U+a1c0 lax # Character ê
+U+a1c1 la # Character ê
+U+a1c2 lap # Character ê
+U+a1c3 luot # Character ê
+U+a1c4 luox # Character ê
+U+a1c5 luo # Character ê
+U+a1c6 luop # Character ê
+U+a1c7 lot # Character ê
+U+a1c8 lox # Character ê
+U+a1c9 lo # Character ê
+U+a1ca lop # Character ê
+U+a1cb lex # Character ê
+U+a1cc le # Character ê
+U+a1cd lep # Character ê
+U+a1ce lut # Character ê
+U+a1cf lux # Character ê
+U+a1d0 lu # Character ê
+U+a1d1 lup # Character ê
+U+a1d2 lurx # Character ê
+U+a1d3 lur # Character ê
+U+a1d4 lyt # Character ê
+U+a1d5 lyx # Character ê
+U+a1d6 ly # Character ê
+U+a1d7 lyp # Character ê
+U+a1d8 lyrx # Character ê
+U+a1d9 lyr # Character ê
+U+a1da git # Character ê
+U+a1db gix # Character ê
+U+a1dc gi # Character ê
+U+a1dd gip # Character ê
+U+a1de giet # Character ê
+U+a1df giex # Character ê
+U+a1e0 gie # Character ê
+U+a1e1 giep # Character ê¡
+U+a1e2 gat # Character ê¢
+U+a1e3 gax # Character ê£
+U+a1e4 ga # Character ê¤
+U+a1e5 gap # Character ê¥
+U+a1e6 guot # Character ê¦
+U+a1e7 guox # Character ê§
+U+a1e8 guo # Character ê¨
+U+a1e9 guop # Character ê©
+U+a1ea got # Character êª
+U+a1eb gox # Character ê«
+U+a1ec go # Character ê¬
+U+a1ed gop # Character ê
+U+a1ee get # Character ê®
+U+a1ef gex # Character ê¯
+U+a1f0 ge # Character ê°
+U+a1f1 gep # Character ê±
+U+a1f2 gut # Character ê²
+U+a1f3 gux # Character ê³
+U+a1f4 gu # Character ê´
+U+a1f5 gup # Character êµ
+U+a1f6 gurx # Character ê¶
+U+a1f7 gur # Character ê·
+U+a1f8 kit # Character ê¸
+U+a1f9 kix # Character ê¹
+U+a1fa ki # Character êº
+U+a1fb kip # Character ê»
+U+a1fc kiex # Character ê¼
+U+a1fd kie # Character ê½
+U+a1fe kiep # Character ê¾
+U+a1ff kat # Character ê¿
diff --git a/resources/chars/ascii/rowa2.trans b/resources/chars/ascii/rowa2.trans
new file mode 100644
index 0000000..6ade385
--- /dev/null
+++ b/resources/chars/ascii/rowa2.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+a200 kax # Character ê
+U+a201 ka # Character ê
+U+a202 kap # Character ê
+U+a203 kuox # Character ê
+U+a204 kuo # Character ê
+U+a205 kuop # Character ê
+U+a206 kot # Character ê
+U+a207 kox # Character ê
+U+a208 ko # Character ê
+U+a209 kop # Character ê
+U+a20a ket # Character ê
+U+a20b kex # Character ê
+U+a20c ke # Character ê
+U+a20d kep # Character ê
+U+a20e kut # Character ê
+U+a20f kux # Character ê
+U+a210 ku # Character ê
+U+a211 kup # Character ê
+U+a212 kurx # Character ê
+U+a213 kur # Character ê
+U+a214 ggit # Character ê
+U+a215 ggix # Character ê
+U+a216 ggi # Character ê
+U+a217 ggiex # Character ê
+U+a218 ggie # Character ê
+U+a219 ggiep # Character ê
+U+a21a ggat # Character ê
+U+a21b ggax # Character ê
+U+a21c gga # Character ê
+U+a21d ggap # Character ê
+U+a21e gguot # Character ê
+U+a21f gguox # Character ê
+U+a220 gguo # Character ê
+U+a221 gguop # Character ê¡
+U+a222 ggot # Character ê¢
+U+a223 ggox # Character ê£
+U+a224 ggo # Character ê¤
+U+a225 ggop # Character ê¥
+U+a226 gget # Character ê¦
+U+a227 ggex # Character ê§
+U+a228 gge # Character ê¨
+U+a229 ggep # Character ê©
+U+a22a ggut # Character êª
+U+a22b ggux # Character ê«
+U+a22c ggu # Character ê¬
+U+a22d ggup # Character ê
+U+a22e ggurx # Character ê®
+U+a22f ggur # Character ê¯
+U+a230 mgiex # Character ê°
+U+a231 mgie # Character ê±
+U+a232 mgat # Character ê²
+U+a233 mgax # Character ê³
+U+a234 mga # Character ê´
+U+a235 mgap # Character êµ
+U+a236 mguox # Character ê¶
+U+a237 mguo # Character ê·
+U+a238 mguop # Character ê¸
+U+a239 mgot # Character ê¹
+U+a23a mgox # Character êº
+U+a23b mgo # Character ê»
+U+a23c mgop # Character ê¼
+U+a23d mgex # Character ê½
+U+a23e mge # Character ê¾
+U+a23f mgep # Character ê¿
+U+a240 mgut # Character ê
+U+a241 mgux # Character ê
+U+a242 mgu # Character ê
+U+a243 mgup # Character ê
+U+a244 mgurx # Character ê
+U+a245 mgur # Character ê
+U+a246 hxit # Character ê
+U+a247 hxix # Character ê
+U+a248 hxi # Character ê
+U+a249 hxip # Character ê
+U+a24a hxiet # Character ê
+U+a24b hxiex # Character ê
+U+a24c hxie # Character ê
+U+a24d hxiep # Character ê
+U+a24e hxat # Character ê
+U+a24f hxax # Character ê
+U+a250 hxa # Character ê
+U+a251 hxap # Character ê
+U+a252 hxuot # Character ê
+U+a253 hxuox # Character ê
+U+a254 hxuo # Character ê
+U+a255 hxuop # Character ê
+U+a256 hxot # Character ê
+U+a257 hxox # Character ê
+U+a258 hxo # Character ê
+U+a259 hxop # Character ê
+U+a25a hxex # Character ê
+U+a25b hxe # Character ê
+U+a25c hxep # Character ê
+U+a25d ngiex # Character ê
+U+a25e ngie # Character ê
+U+a25f ngiep # Character ê
+U+a260 ngat # Character ê
+U+a261 ngax # Character ê¡
+U+a262 nga # Character ê¢
+U+a263 ngap # Character ê£
+U+a264 nguot # Character ê¤
+U+a265 nguox # Character ê¥
+U+a266 nguo # Character ê¦
+U+a267 ngot # Character ê§
+U+a268 ngox # Character ê¨
+U+a269 ngo # Character ê©
+U+a26a ngop # Character êª
+U+a26b ngex # Character ê«
+U+a26c nge # Character ê¬
+U+a26d ngep # Character ê
+U+a26e hit # Character ê®
+U+a26f hiex # Character ê¯
+U+a270 hie # Character ê°
+U+a271 hat # Character ê±
+U+a272 hax # Character ê²
+U+a273 ha # Character ê³
+U+a274 hap # Character ê´
+U+a275 huot # Character êµ
+U+a276 huox # Character ê¶
+U+a277 huo # Character ê·
+U+a278 huop # Character ê¸
+U+a279 hot # Character ê¹
+U+a27a hox # Character êº
+U+a27b ho # Character ê»
+U+a27c hop # Character ê¼
+U+a27d hex # Character ê½
+U+a27e he # Character ê¾
+U+a27f hep # Character ê¿
+U+a280 wat # Character ê
+U+a281 wax # Character ê
+U+a282 wa # Character ê
+U+a283 wap # Character ê
+U+a284 wuox # Character ê
+U+a285 wuo # Character ê
+U+a286 wuop # Character ê
+U+a287 wox # Character ê
+U+a288 wo # Character ê
+U+a289 wop # Character ê
+U+a28a wex # Character ê
+U+a28b we # Character ê
+U+a28c wep # Character ê
+U+a28d zit # Character ê
+U+a28e zix # Character ê
+U+a28f zi # Character ê
+U+a290 zip # Character ê
+U+a291 ziex # Character ê
+U+a292 zie # Character ê
+U+a293 ziep # Character ê
+U+a294 zat # Character ê
+U+a295 zax # Character ê
+U+a296 za # Character ê
+U+a297 zap # Character ê
+U+a298 zuox # Character ê
+U+a299 zuo # Character ê
+U+a29a zuop # Character ê
+U+a29b zot # Character ê
+U+a29c zox # Character ê
+U+a29d zo # Character ê
+U+a29e zop # Character ê
+U+a29f zex # Character ê
+U+a2a0 ze # Character ê
+U+a2a1 zep # Character ê¡
+U+a2a2 zut # Character ê¢
+U+a2a3 zux # Character ê£
+U+a2a4 zu # Character ê¤
+U+a2a5 zup # Character ê¥
+U+a2a6 zurx # Character ê¦
+U+a2a7 zur # Character ê§
+U+a2a8 zyt # Character ê¨
+U+a2a9 zyx # Character ê©
+U+a2aa zy # Character êª
+U+a2ab zyp # Character ê«
+U+a2ac zyrx # Character ê¬
+U+a2ad zyr # Character ê
+U+a2ae cit # Character ê®
+U+a2af cix # Character ê¯
+U+a2b0 ci # Character ê°
+U+a2b1 cip # Character ê±
+U+a2b2 ciet # Character ê²
+U+a2b3 ciex # Character ê³
+U+a2b4 cie # Character ê´
+U+a2b5 ciep # Character êµ
+U+a2b6 cat # Character ê¶
+U+a2b7 cax # Character ê·
+U+a2b8 ca # Character ê¸
+U+a2b9 cap # Character ê¹
+U+a2ba cuox # Character êº
+U+a2bb cuo # Character ê»
+U+a2bc cuop # Character ê¼
+U+a2bd cot # Character ê½
+U+a2be cox # Character ê¾
+U+a2bf co # Character ê¿
+U+a2c0 cop # Character ê
+U+a2c1 cex # Character ê
+U+a2c2 ce # Character ê
+U+a2c3 cep # Character ê
+U+a2c4 cut # Character ê
+U+a2c5 cux # Character ê
+U+a2c6 cu # Character ê
+U+a2c7 cup # Character ê
+U+a2c8 curx # Character ê
+U+a2c9 cur # Character ê
+U+a2ca cyt # Character ê
+U+a2cb cyx # Character ê
+U+a2cc cy # Character ê
+U+a2cd cyp # Character ê
+U+a2ce cyrx # Character ê
+U+a2cf cyr # Character ê
+U+a2d0 zzit # Character ê
+U+a2d1 zzix # Character ê
+U+a2d2 zzi # Character ê
+U+a2d3 zzip # Character ê
+U+a2d4 zziet # Character ê
+U+a2d5 zziex # Character ê
+U+a2d6 zzie # Character ê
+U+a2d7 zziep # Character ê
+U+a2d8 zzat # Character ê
+U+a2d9 zzax # Character ê
+U+a2da zza # Character ê
+U+a2db zzap # Character ê
+U+a2dc zzox # Character ê
+U+a2dd zzo # Character ê
+U+a2de zzop # Character ê
+U+a2df zzex # Character ê
+U+a2e0 zze # Character ê
+U+a2e1 zzep # Character ê¡
+U+a2e2 zzux # Character ê¢
+U+a2e3 zzu # Character ê£
+U+a2e4 zzup # Character ê¤
+U+a2e5 zzurx # Character ê¥
+U+a2e6 zzur # Character ê¦
+U+a2e7 zzyt # Character ê§
+U+a2e8 zzyx # Character ê¨
+U+a2e9 zzy # Character ê©
+U+a2ea zzyp # Character êª
+U+a2eb zzyrx # Character ê«
+U+a2ec zzyr # Character ê¬
+U+a2ed nzit # Character ê
+U+a2ee nzix # Character ê®
+U+a2ef nzi # Character ê¯
+U+a2f0 nzip # Character ê°
+U+a2f1 nziex # Character ê±
+U+a2f2 nzie # Character ê²
+U+a2f3 nziep # Character ê³
+U+a2f4 nzat # Character ê´
+U+a2f5 nzax # Character êµ
+U+a2f6 nza # Character ê¶
+U+a2f7 nzap # Character ê·
+U+a2f8 nzuox # Character ê¸
+U+a2f9 nzuo # Character ê¹
+U+a2fa nzox # Character êº
+U+a2fb nzop # Character ê»
+U+a2fc nzex # Character ê¼
+U+a2fd nze # Character ê½
+U+a2fe nzux # Character ê¾
+U+a2ff nzu # Character ê¿
diff --git a/resources/chars/ascii/rowa3.trans b/resources/chars/ascii/rowa3.trans
new file mode 100644
index 0000000..647b0c8
--- /dev/null
+++ b/resources/chars/ascii/rowa3.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+a300 nzup # Character ê
+U+a301 nzurx # Character ê
+U+a302 nzur # Character ê
+U+a303 nzyt # Character ê
+U+a304 nzyx # Character ê
+U+a305 nzy # Character ê
+U+a306 nzyp # Character ê
+U+a307 nzyrx # Character ê
+U+a308 nzyr # Character ê
+U+a309 sit # Character ê
+U+a30a six # Character ê
+U+a30b si # Character ê
+U+a30c sip # Character ê
+U+a30d siex # Character ê
+U+a30e sie # Character ê
+U+a30f siep # Character ê
+U+a310 sat # Character ê
+U+a311 sax # Character ê
+U+a312 sa # Character ê
+U+a313 sap # Character ê
+U+a314 suox # Character ê
+U+a315 suo # Character ê
+U+a316 suop # Character ê
+U+a317 sot # Character ê
+U+a318 sox # Character ê
+U+a319 so # Character ê
+U+a31a sop # Character ê
+U+a31b sex # Character ê
+U+a31c se # Character ê
+U+a31d sep # Character ê
+U+a31e sut # Character ê
+U+a31f sux # Character ê
+U+a320 su # Character ê
+U+a321 sup # Character ê¡
+U+a322 surx # Character ê¢
+U+a323 sur # Character ê£
+U+a324 syt # Character ê¤
+U+a325 syx # Character ê¥
+U+a326 sy # Character ê¦
+U+a327 syp # Character ê§
+U+a328 syrx # Character ê¨
+U+a329 syr # Character ê©
+U+a32a ssit # Character êª
+U+a32b ssix # Character ê«
+U+a32c ssi # Character ê¬
+U+a32d ssip # Character ê
+U+a32e ssiex # Character ê®
+U+a32f ssie # Character ê¯
+U+a330 ssiep # Character ê°
+U+a331 ssat # Character ê±
+U+a332 ssax # Character ê²
+U+a333 ssa # Character ê³
+U+a334 ssap # Character ê´
+U+a335 ssot # Character êµ
+U+a336 ssox # Character ê¶
+U+a337 sso # Character ê·
+U+a338 ssop # Character ê¸
+U+a339 ssex # Character ê¹
+U+a33a sse # Character êº
+U+a33b ssep # Character ê»
+U+a33c ssut # Character ê¼
+U+a33d ssux # Character ê½
+U+a33e ssu # Character ê¾
+U+a33f ssup # Character ê¿
+U+a340 ssyt # Character ê
+U+a341 ssyx # Character ê
+U+a342 ssy # Character ê
+U+a343 ssyp # Character ê
+U+a344 ssyrx # Character ê
+U+a345 ssyr # Character ê
+U+a346 zhat # Character ê
+U+a347 zhax # Character ê
+U+a348 zha # Character ê
+U+a349 zhap # Character ê
+U+a34a zhuox # Character ê
+U+a34b zhuo # Character ê
+U+a34c zhuop # Character ê
+U+a34d zhot # Character ê
+U+a34e zhox # Character ê
+U+a34f zho # Character ê
+U+a350 zhop # Character ê
+U+a351 zhet # Character ê
+U+a352 zhex # Character ê
+U+a353 zhe # Character ê
+U+a354 zhep # Character ê
+U+a355 zhut # Character ê
+U+a356 zhux # Character ê
+U+a357 zhu # Character ê
+U+a358 zhup # Character ê
+U+a359 zhurx # Character ê
+U+a35a zhur # Character ê
+U+a35b zhyt # Character ê
+U+a35c zhyx # Character ê
+U+a35d zhy # Character ê
+U+a35e zhyp # Character ê
+U+a35f zhyrx # Character ê
+U+a360 zhyr # Character ê
+U+a361 chat # Character ê¡
+U+a362 chax # Character ê¢
+U+a363 cha # Character ê£
+U+a364 chap # Character ê¤
+U+a365 chuot # Character ê¥
+U+a366 chuox # Character ê¦
+U+a367 chuo # Character ê§
+U+a368 chuop # Character ê¨
+U+a369 chot # Character ê©
+U+a36a chox # Character êª
+U+a36b cho # Character ê«
+U+a36c chop # Character ê¬
+U+a36d chet # Character ê
+U+a36e chex # Character ê®
+U+a36f che # Character ê¯
+U+a370 chep # Character ê°
+U+a371 chux # Character ê±
+U+a372 chu # Character ê²
+U+a373 chup # Character ê³
+U+a374 churx # Character ê´
+U+a375 chur # Character êµ
+U+a376 chyt # Character ê¶
+U+a377 chyx # Character ê·
+U+a378 chy # Character ê¸
+U+a379 chyp # Character ê¹
+U+a37a chyrx # Character êº
+U+a37b chyr # Character ê»
+U+a37c rrax # Character ê¼
+U+a37d rra # Character ê½
+U+a37e rruox # Character ê¾
+U+a37f rruo # Character ê¿
+U+a380 rrot # Character ê
+U+a381 rrox # Character ê
+U+a382 rro # Character ê
+U+a383 rrop # Character ê
+U+a384 rret # Character ê
+U+a385 rrex # Character ê
+U+a386 rre # Character ê
+U+a387 rrep # Character ê
+U+a388 rrut # Character ê
+U+a389 rrux # Character ê
+U+a38a rru # Character ê
+U+a38b rrup # Character ê
+U+a38c rrurx # Character ê
+U+a38d rrur # Character ê
+U+a38e rryt # Character ê
+U+a38f rryx # Character ê
+U+a390 rry # Character ê
+U+a391 rryp # Character ê
+U+a392 rryrx # Character ê
+U+a393 rryr # Character ê
+U+a394 nrat # Character ê
+U+a395 nrax # Character ê
+U+a396 nra # Character ê
+U+a397 nrap # Character ê
+U+a398 nrox # Character ê
+U+a399 nro # Character ê
+U+a39a nrop # Character ê
+U+a39b nret # Character ê
+U+a39c nrex # Character ê
+U+a39d nre # Character ê
+U+a39e nrep # Character ê
+U+a39f nrut # Character ê
+U+a3a0 nrux # Character ê
+U+a3a1 nru # Character ê¡
+U+a3a2 nrup # Character ê¢
+U+a3a3 nrurx # Character ê£
+U+a3a4 nrur # Character ê¤
+U+a3a5 nryt # Character ê¥
+U+a3a6 nryx # Character ê¦
+U+a3a7 nry # Character ê§
+U+a3a8 nryp # Character ê¨
+U+a3a9 nryrx # Character ê©
+U+a3aa nryr # Character êª
+U+a3ab shat # Character ê«
+U+a3ac shax # Character ê¬
+U+a3ad sha # Character ê
+U+a3ae shap # Character ê®
+U+a3af shuox # Character ê¯
+U+a3b0 shuo # Character ê°
+U+a3b1 shuop # Character ê±
+U+a3b2 shot # Character ê²
+U+a3b3 shox # Character ê³
+U+a3b4 sho # Character ê´
+U+a3b5 shop # Character êµ
+U+a3b6 shet # Character ê¶
+U+a3b7 shex # Character ê·
+U+a3b8 she # Character ê¸
+U+a3b9 shep # Character ê¹
+U+a3ba shut # Character êº
+U+a3bb shux # Character ê»
+U+a3bc shu # Character ê¼
+U+a3bd shup # Character ê½
+U+a3be shurx # Character ê¾
+U+a3bf shur # Character ê¿
+U+a3c0 shyt # Character ê
+U+a3c1 shyx # Character ê
+U+a3c2 shy # Character ê
+U+a3c3 shyp # Character ê
+U+a3c4 shyrx # Character ê
+U+a3c5 shyr # Character ê
+U+a3c6 rat # Character ê
+U+a3c7 rax # Character ê
+U+a3c8 ra # Character ê
+U+a3c9 rap # Character ê
+U+a3ca ruox # Character ê
+U+a3cb ruo # Character ê
+U+a3cc ruop # Character ê
+U+a3cd rot # Character ê
+U+a3ce rox # Character ê
+U+a3cf ro # Character ê
+U+a3d0 rop # Character ê
+U+a3d1 rex # Character ê
+U+a3d2 re # Character ê
+U+a3d3 rep # Character ê
+U+a3d4 rut # Character ê
+U+a3d5 rux # Character ê
+U+a3d6 ru # Character ê
+U+a3d7 rup # Character ê
+U+a3d8 rurx # Character ê
+U+a3d9 rur # Character ê
+U+a3da ryt # Character ê
+U+a3db ryx # Character ê
+U+a3dc ry # Character ê
+U+a3dd ryp # Character ê
+U+a3de ryrx # Character ê
+U+a3df ryr # Character ê
+U+a3e0 jit # Character ê
+U+a3e1 jix # Character ê¡
+U+a3e2 ji # Character ê¢
+U+a3e3 jip # Character ê£
+U+a3e4 jiet # Character ê¤
+U+a3e5 jiex # Character ê¥
+U+a3e6 jie # Character ê¦
+U+a3e7 jiep # Character ê§
+U+a3e8 juot # Character ê¨
+U+a3e9 juox # Character ê©
+U+a3ea juo # Character êª
+U+a3eb juop # Character ê«
+U+a3ec jot # Character ê¬
+U+a3ed jox # Character ê
+U+a3ee jo # Character ê®
+U+a3ef jop # Character ê¯
+U+a3f0 jut # Character ê°
+U+a3f1 jux # Character ê±
+U+a3f2 ju # Character ê²
+U+a3f3 jup # Character ê³
+U+a3f4 jurx # Character ê´
+U+a3f5 jur # Character êµ
+U+a3f6 jyt # Character ê¶
+U+a3f7 jyx # Character ê·
+U+a3f8 jy # Character ê¸
+U+a3f9 jyp # Character ê¹
+U+a3fa jyrx # Character êº
+U+a3fb jyr # Character ê»
+U+a3fc qit # Character ê¼
+U+a3fd qix # Character ê½
+U+a3fe qi # Character ê¾
+U+a3ff qip # Character ê¿
diff --git a/resources/chars/ascii/rowa4.trans b/resources/chars/ascii/rowa4.trans
new file mode 100644
index 0000000..8ddeae8
--- /dev/null
+++ b/resources/chars/ascii/rowa4.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+a400 qiet # Character ê
+U+a401 qiex # Character ê
+U+a402 qie # Character ê
+U+a403 qiep # Character ê
+U+a404 quot # Character ê
+U+a405 quox # Character ê
+U+a406 quo # Character ê
+U+a407 quop # Character ê
+U+a408 qot # Character ê
+U+a409 qox # Character ê
+U+a40a qo # Character ê
+U+a40b qop # Character ê
+U+a40c qut # Character ê
+U+a40d qux # Character ê
+U+a40e qu # Character ê
+U+a40f qup # Character ê
+U+a410 qurx # Character ê
+U+a411 qur # Character ê
+U+a412 qyt # Character ê
+U+a413 qyx # Character ê
+U+a414 qy # Character ê
+U+a415 qyp # Character ê
+U+a416 qyrx # Character ê
+U+a417 qyr # Character ê
+U+a418 jjit # Character ê
+U+a419 jjix # Character ê
+U+a41a jji # Character ê
+U+a41b jjip # Character ê
+U+a41c jjiet # Character ê
+U+a41d jjiex # Character ê
+U+a41e jjie # Character ê
+U+a41f jjiep # Character ê
+U+a420 jjuox # Character ê
+U+a421 jjuo # Character ê¡
+U+a422 jjuop # Character ê¢
+U+a423 jjot # Character ê£
+U+a424 jjox # Character ê¤
+U+a425 jjo # Character ê¥
+U+a426 jjop # Character ê¦
+U+a427 jjut # Character ê§
+U+a428 jjux # Character ê¨
+U+a429 jju # Character ê©
+U+a42a jjup # Character êª
+U+a42b jjurx # Character ê«
+U+a42c jjur # Character ê¬
+U+a42d jjyt # Character ê
+U+a42e jjyx # Character ê®
+U+a42f jjy # Character ê¯
+U+a430 jjyp # Character ê°
+U+a431 njit # Character ê±
+U+a432 njix # Character ê²
+U+a433 nji # Character ê³
+U+a434 njip # Character ê´
+U+a435 njiet # Character êµ
+U+a436 njiex # Character ê¶
+U+a437 njie # Character ê·
+U+a438 njiep # Character ê¸
+U+a439 njuox # Character ê¹
+U+a43a njuo # Character êº
+U+a43b njot # Character ê»
+U+a43c njox # Character ê¼
+U+a43d njo # Character ê½
+U+a43e njop # Character ê¾
+U+a43f njux # Character ê¿
+U+a440 nju # Character ê
+U+a441 njup # Character ê
+U+a442 njurx # Character ê
+U+a443 njur # Character ê
+U+a444 njyt # Character ê
+U+a445 njyx # Character ê
+U+a446 njy # Character ê
+U+a447 njyp # Character ê
+U+a448 njyrx # Character ê
+U+a449 njyr # Character ê
+U+a44a nyit # Character ê
+U+a44b nyix # Character ê
+U+a44c nyi # Character ê
+U+a44d nyip # Character ê
+U+a44e nyiet # Character ê
+U+a44f nyiex # Character ê
+U+a450 nyie # Character ê
+U+a451 nyiep # Character ê
+U+a452 nyuox # Character ê
+U+a453 nyuo # Character ê
+U+a454 nyuop # Character ê
+U+a455 nyot # Character ê
+U+a456 nyox # Character ê
+U+a457 nyo # Character ê
+U+a458 nyop # Character ê
+U+a459 nyut # Character ê
+U+a45a nyux # Character ê
+U+a45b nyu # Character ê
+U+a45c nyup # Character ê
+U+a45d xit # Character ê
+U+a45e xix # Character ê
+U+a45f xi # Character ê
+U+a460 xip # Character ê
+U+a461 xiet # Character ê¡
+U+a462 xiex # Character ê¢
+U+a463 xie # Character ê£
+U+a464 xiep # Character ê¤
+U+a465 xuox # Character ê¥
+U+a466 xuo # Character ê¦
+U+a467 xot # Character ê§
+U+a468 xox # Character ê¨
+U+a469 xo # Character ê©
+U+a46a xop # Character êª
+U+a46b xyt # Character ê«
+U+a46c xyx # Character ê¬
+U+a46d xy # Character ê
+U+a46e xyp # Character ê®
+U+a46f xyrx # Character ê¯
+U+a470 xyr # Character ê°
+U+a471 yit # Character ê±
+U+a472 yix # Character ê²
+U+a473 yi # Character ê³
+U+a474 yip # Character ê´
+U+a475 yiet # Character êµ
+U+a476 yiex # Character ê¶
+U+a477 yie # Character ê·
+U+a478 yiep # Character ê¸
+U+a479 yuot # Character ê¹
+U+a47a yuox # Character êº
+U+a47b yuo # Character ê»
+U+a47c yuop # Character ê¼
+U+a47d yot # Character ê½
+U+a47e yox # Character ê¾
+U+a47f yo # Character ê¿
+U+a480 yop # Character ê
+U+a481 yut # Character ê
+U+a482 yux # Character ê
+U+a483 yu # Character ê
+U+a484 yup # Character ê
+U+a485 yurx # Character ê
+U+a486 yur # Character ê
+U+a487 yyt # Character ê
+U+a488 yyx # Character ê
+U+a489 yy # Character ê
+U+a48a yyp # Character ê
+U+a48b yyrx # Character ê
+U+a48c yyr # Character ê
+U+a48d ? # Character ê
+U+a48e ? # Character ê
+U+a48f ? # Character ê
+U+a490 Qot # Character ê
+U+a491 Li # Character ê
+U+a492 Kit # Character ê
+U+a493 Nyip # Character ê
+U+a494 Cyp # Character ê
+U+a495 Ssi # Character ê
+U+a496 Ggop # Character ê
+U+a497 Gep # Character ê
+U+a498 Mi # Character ê
+U+a499 Hxit # Character ê
+U+a49a Lyr # Character ê
+U+a49b Bbut # Character ê
+U+a49c Mop # Character ê
+U+a49d Yo # Character ê
+U+a49e Put # Character ê
+U+a49f Hxuo # Character ê
+U+a4a0 Tat # Character ê
+U+a4a1 Ga # Character ê¡
+U+a4a2 ? # Character ê¢
+U+a4a3 ? # Character ê£
+U+a4a4 Ddur # Character ê¤
+U+a4a5 Bur # Character ê¥
+U+a4a6 Gguo # Character ê¦
+U+a4a7 Nyop # Character ê§
+U+a4a8 Tu # Character ê¨
+U+a4a9 Op # Character ê©
+U+a4aa Jjut # Character êª
+U+a4ab Zot # Character ê«
+U+a4ac Pyt # Character ê¬
+U+a4ad Hmo # Character ê
+U+a4ae Yit # Character ê®
+U+a4af Vur # Character ê¯
+U+a4b0 Shy # Character ê°
+U+a4b1 Vep # Character ê±
+U+a4b2 Za # Character ê²
+U+a4b3 Jo # Character ê³
+U+a4b4 ? # Character ê´
+U+a4b5 Jjy # Character êµ
+U+a4b6 Got # Character ê¶
+U+a4b7 Jjie # Character ê·
+U+a4b8 Wo # Character ê¸
+U+a4b9 Du # Character ê¹
+U+a4ba Shur # Character êº
+U+a4bb Lie # Character ê»
+U+a4bc Cy # Character ê¼
+U+a4bd Cuop # Character ê½
+U+a4be Cip # Character ê¾
+U+a4bf Hxop # Character ê¿
+U+a4c0 Shat # Character ê
+U+a4c1 ? # Character ê
+U+a4c2 Shop # Character ê
+U+a4c3 Che # Character ê
+U+a4c4 Zziet # Character ê
+U+a4c5 ? # Character ê
+U+a4c6 Ke # Character ê
+U+a4c7 ? # Character ê
+U+a4c8 ? # Character ê
+U+a4c9 ? # Character ê
+U+a4ca ? # Character ê
+U+a4cb ? # Character ê
+U+a4cc ? # Character ê
+U+a4cd ? # Character ê
+U+a4ce ? # Character ê
+U+a4cf ? # Character ê
+U+a4d0 ? # Character ê
+U+a4d1 ? # Character ê
+U+a4d2 ? # Character ê
+U+a4d3 ? # Character ê
+U+a4d4 ? # Character ê
+U+a4d5 ? # Character ê
+U+a4d6 ? # Character ê
+U+a4d7 ? # Character ê
+U+a4d8 ? # Character ê
+U+a4d9 ? # Character ê
+U+a4da ? # Character ê
+U+a4db ? # Character ê
+U+a4dc ? # Character ê
+U+a4dd ? # Character ê
+U+a4de ? # Character ê
+U+a4df ? # Character ê
+U+a4e0 ? # Character ê
+U+a4e1 ? # Character ê¡
+U+a4e2 ? # Character ê¢
+U+a4e3 ? # Character ê£
+U+a4e4 ? # Character ê¤
+U+a4e5 ? # Character ê¥
+U+a4e6 ? # Character ê¦
+U+a4e7 ? # Character ê§
+U+a4e8 ? # Character ê¨
+U+a4e9 ? # Character ê©
+U+a4ea ? # Character êª
+U+a4eb ? # Character ê«
+U+a4ec ? # Character ê¬
+U+a4ed ? # Character ê
+U+a4ee ? # Character ê®
+U+a4ef ? # Character ê¯
+U+a4f0 ? # Character ê°
+U+a4f1 ? # Character ê±
+U+a4f2 ? # Character ê²
+U+a4f3 ? # Character ê³
+U+a4f4 ? # Character ê´
+U+a4f5 ? # Character êµ
+U+a4f6 ? # Character ê¶
+U+a4f7 ? # Character ê·
+U+a4f8 ? # Character ê¸
+U+a4f9 ? # Character ê¹
+U+a4fa ? # Character êº
+U+a4fb ? # Character ê»
+U+a4fc ? # Character ê¼
+U+a4fd ? # Character ê½
+U+a4fe ? # Character ê¾
+U+a4ff ? # Character ê¿
diff --git a/resources/chars/ascii/rowac.trans b/resources/chars/ascii/rowac.trans
new file mode 100644
index 0000000..250e6ba
--- /dev/null
+++ b/resources/chars/ascii/rowac.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+ac00 ga # Character ê°
+U+ac01 gag # Character ê°
+U+ac02 gagg # Character ê°
+U+ac03 gags # Character ê°
+U+ac04 gan # Character ê°
+U+ac05 ganj # Character ê°
+U+ac06 ganh # Character ê°
+U+ac07 gad # Character ê°
+U+ac08 gal # Character ê°
+U+ac09 galg # Character ê°
+U+ac0a galm # Character ê°
+U+ac0b galb # Character ê°
+U+ac0c gals # Character ê°
+U+ac0d galt # Character ê°
+U+ac0e galp # Character ê°
+U+ac0f galh # Character ê°
+U+ac10 gam # Character ê°
+U+ac11 gab # Character ê°
+U+ac12 gabs # Character ê°
+U+ac13 gas # Character ê°
+U+ac14 gass # Character ê°
+U+ac15 gang # Character ê°
+U+ac16 gaj # Character ê°
+U+ac17 gac # Character ê°
+U+ac18 gak # Character ê°
+U+ac19 gat # Character ê°
+U+ac1a gap # Character ê°
+U+ac1b gah # Character ê°
+U+ac1c gae # Character ê°
+U+ac1d gaeg # Character ê°
+U+ac1e gaegg # Character ê°
+U+ac1f gaegs # Character ê°
+U+ac20 gaen # Character ê°
+U+ac21 gaenj # Character ê°¡
+U+ac22 gaenh # Character ê°¢
+U+ac23 gaed # Character ê°£
+U+ac24 gael # Character ê°¤
+U+ac25 gaelg # Character ê°¥
+U+ac26 gaelm # Character ê°¦
+U+ac27 gaelb # Character ê°§
+U+ac28 gaels # Character ê°¨
+U+ac29 gaelt # Character ê°©
+U+ac2a gaelp # Character ê°ª
+U+ac2b gaelh # Character ê°«
+U+ac2c gaem # Character ê°¬
+U+ac2d gaeb # Character ê°
+U+ac2e gaebs # Character ê°®
+U+ac2f gaes # Character ê°¯
+U+ac30 gaess # Character ê°°
+U+ac31 gaeng # Character ê°±
+U+ac32 gaej # Character ê°²
+U+ac33 gaec # Character ê°³
+U+ac34 gaek # Character ê°´
+U+ac35 gaet # Character ê°µ
+U+ac36 gaep # Character ê°¶
+U+ac37 gaeh # Character ê°·
+U+ac38 gya # Character ê°¸
+U+ac39 gyag # Character ê°¹
+U+ac3a gyagg # Character ê°º
+U+ac3b gyags # Character ê°»
+U+ac3c gyan # Character ê°¼
+U+ac3d gyanj # Character ê°½
+U+ac3e gyanh # Character ê°¾
+U+ac3f gyad # Character ê°¿
+U+ac40 gyal # Character ê±
+U+ac41 gyalg # Character ê±
+U+ac42 gyalm # Character ê±
+U+ac43 gyalb # Character ê±
+U+ac44 gyals # Character ê±
+U+ac45 gyalt # Character ê±
+U+ac46 gyalp # Character ê±
+U+ac47 gyalh # Character ê±
+U+ac48 gyam # Character ê±
+U+ac49 gyab # Character ê±
+U+ac4a gyabs # Character ê±
+U+ac4b gyas # Character ê±
+U+ac4c gyass # Character ê±
+U+ac4d gyang # Character ê±
+U+ac4e gyaj # Character ê±
+U+ac4f gyac # Character ê±
+U+ac50 gyak # Character ê±
+U+ac51 gyat # Character ê±
+U+ac52 gyap # Character ê±
+U+ac53 gyah # Character ê±
+U+ac54 gyae # Character ê±
+U+ac55 gyaeg # Character ê±
+U+ac56 gyaegg # Character ê±
+U+ac57 gyaegs # Character ê±
+U+ac58 gyaen # Character ê±
+U+ac59 gyaenj # Character ê±
+U+ac5a gyaenh # Character ê±
+U+ac5b gyaed # Character ê±
+U+ac5c gyael # Character ê±
+U+ac5d gyaelg # Character ê±
+U+ac5e gyaelm # Character ê±
+U+ac5f gyaelb # Character ê±
+U+ac60 gyaels # Character ê±
+U+ac61 gyaelt # Character 걡
+U+ac62 gyaelp # Character ê±¢
+U+ac63 gyaelh # Character ê±£
+U+ac64 gyaem # Character 걤
+U+ac65 gyaeb # Character ê±¥
+U+ac66 gyaebs # Character 걦
+U+ac67 gyaes # Character 걧
+U+ac68 gyaess # Character 걨
+U+ac69 gyaeng # Character 걩
+U+ac6a gyaej # Character 걪
+U+ac6b gyaec # Character 걫
+U+ac6c gyaek # Character 걬
+U+ac6d gyaet # Character ê±
+U+ac6e gyaep # Character ê±®
+U+ac6f gyaeh # Character 걯
+U+ac70 geo # Character ê±°
+U+ac71 geog # Character ê±±
+U+ac72 geogg # Character ê±²
+U+ac73 geogs # Character ê±³
+U+ac74 geon # Character ê±´
+U+ac75 geonj # Character ê±µ
+U+ac76 geonh # Character 걶
+U+ac77 geod # Character ê±·
+U+ac78 geol # Character 걸
+U+ac79 geolg # Character ê±¹
+U+ac7a geolm # Character 걺
+U+ac7b geolb # Character ê±»
+U+ac7c geols # Character ê±¼
+U+ac7d geolt # Character ê±½
+U+ac7e geolp # Character ê±¾
+U+ac7f geolh # Character 걿
+U+ac80 geom # Character ê²
+U+ac81 geob # Character ê²
+U+ac82 geobs # Character ê²
+U+ac83 geos # Character ê²
+U+ac84 geoss # Character ê²
+U+ac85 geong # Character ê²
+U+ac86 geoj # Character ê²
+U+ac87 geoc # Character ê²
+U+ac88 geok # Character ê²
+U+ac89 geot # Character ê²
+U+ac8a geop # Character ê²
+U+ac8b geoh # Character ê²
+U+ac8c ge # Character ê²
+U+ac8d geg # Character ê²
+U+ac8e gegg # Character ê²
+U+ac8f gegs # Character ê²
+U+ac90 gen # Character ê²
+U+ac91 genj # Character ê²
+U+ac92 genh # Character ê²
+U+ac93 ged # Character ê²
+U+ac94 gel # Character ê²
+U+ac95 gelg # Character ê²
+U+ac96 gelm # Character ê²
+U+ac97 gelb # Character ê²
+U+ac98 gels # Character ê²
+U+ac99 gelt # Character ê²
+U+ac9a gelp # Character ê²
+U+ac9b gelh # Character ê²
+U+ac9c gem # Character ê²
+U+ac9d geb # Character ê²
+U+ac9e gebs # Character ê²
+U+ac9f ges # Character ê²
+U+aca0 gess # Character ê²
+U+aca1 geng # Character 겡
+U+aca2 gej # Character ê²¢
+U+aca3 gec # Character ê²£
+U+aca4 gek # Character 겤
+U+aca5 get # Character ê²¥
+U+aca6 gep # Character 겦
+U+aca7 geh # Character 겧
+U+aca8 gyeo # Character 겨
+U+aca9 gyeog # Character 격
+U+acaa gyeogg # Character 겪
+U+acab gyeogs # Character 겫
+U+acac gyeon # Character 견
+U+acad gyeonj # Character ê²
+U+acae gyeonh # Character ê²®
+U+acaf gyeod # Character 겯
+U+acb0 gyeol # Character ê²°
+U+acb1 gyeolg # Character ê²±
+U+acb2 gyeolm # Character ê²²
+U+acb3 gyeolb # Character ê²³
+U+acb4 gyeols # Character ê²´
+U+acb5 gyeolt # Character ê²µ
+U+acb6 gyeolp # Character 겶
+U+acb7 gyeolh # Character ê²·
+U+acb8 gyeom # Character 겸
+U+acb9 gyeob # Character ê²¹
+U+acba gyeobs # Character 겺
+U+acbb gyeos # Character ê²»
+U+acbc gyeoss # Character ê²¼
+U+acbd gyeong # Character ê²½
+U+acbe gyeoj # Character ê²¾
+U+acbf gyeoc # Character 겿
+U+acc0 gyeok # Character ê³
+U+acc1 gyeot # Character ê³
+U+acc2 gyeop # Character ê³
+U+acc3 gyeoh # Character ê³
+U+acc4 gye # Character ê³
+U+acc5 gyeg # Character ê³
+U+acc6 gyegg # Character ê³
+U+acc7 gyegs # Character ê³
+U+acc8 gyen # Character ê³
+U+acc9 gyenj # Character ê³
+U+acca gyenh # Character ê³
+U+accb gyed # Character ê³
+U+accc gyel # Character ê³
+U+accd gyelg # Character ê³
+U+acce gyelm # Character ê³
+U+accf gyelb # Character ê³
+U+acd0 gyels # Character ê³
+U+acd1 gyelt # Character ê³
+U+acd2 gyelp # Character ê³
+U+acd3 gyelh # Character ê³
+U+acd4 gyem # Character ê³
+U+acd5 gyeb # Character ê³
+U+acd6 gyebs # Character ê³
+U+acd7 gyes # Character ê³
+U+acd8 gyess # Character ê³
+U+acd9 gyeng # Character ê³
+U+acda gyej # Character ê³
+U+acdb gyec # Character ê³
+U+acdc gyek # Character ê³
+U+acdd gyet # Character ê³
+U+acde gyep # Character ê³
+U+acdf gyeh # Character ê³
+U+ace0 go # Character ê³
+U+ace1 gog # Character 곡
+U+ace2 gogg # Character ê³¢
+U+ace3 gogs # Character ê³£
+U+ace4 gon # Character 곤
+U+ace5 gonj # Character ê³¥
+U+ace6 gonh # Character 곦
+U+ace7 god # Character 곧
+U+ace8 gol # Character 골
+U+ace9 golg # Character 곩
+U+acea golm # Character 곪
+U+aceb golb # Character 곫
+U+acec gols # Character 곬
+U+aced golt # Character ê³
+U+acee golp # Character ê³®
+U+acef golh # Character 곯
+U+acf0 gom # Character ê³°
+U+acf1 gob # Character ê³±
+U+acf2 gobs # Character ê³²
+U+acf3 gos # Character ê³³
+U+acf4 goss # Character ê³´
+U+acf5 gong # Character ê³µ
+U+acf6 goj # Character 곶
+U+acf7 goc # Character ê³·
+U+acf8 gok # Character 곸
+U+acf9 got # Character ê³¹
+U+acfa gop # Character 곺
+U+acfb goh # Character ê³»
+U+acfc gwa # Character ê³¼
+U+acfd gwag # Character ê³½
+U+acfe gwagg # Character ê³¾
+U+acff gwags # Character 곿
diff --git a/resources/chars/ascii/rowad.trans b/resources/chars/ascii/rowad.trans
new file mode 100644
index 0000000..310ae6a
--- /dev/null
+++ b/resources/chars/ascii/rowad.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+ad00 gwan # Character ê´
+U+ad01 gwanj # Character ê´
+U+ad02 gwanh # Character ê´
+U+ad03 gwad # Character ê´
+U+ad04 gwal # Character ê´
+U+ad05 gwalg # Character ê´
+U+ad06 gwalm # Character ê´
+U+ad07 gwalb # Character ê´
+U+ad08 gwals # Character ê´
+U+ad09 gwalt # Character ê´
+U+ad0a gwalp # Character ê´
+U+ad0b gwalh # Character ê´
+U+ad0c gwam # Character ê´
+U+ad0d gwab # Character ê´
+U+ad0e gwabs # Character ê´
+U+ad0f gwas # Character ê´
+U+ad10 gwass # Character ê´
+U+ad11 gwang # Character ê´
+U+ad12 gwaj # Character ê´
+U+ad13 gwac # Character ê´
+U+ad14 gwak # Character ê´
+U+ad15 gwat # Character ê´
+U+ad16 gwap # Character ê´
+U+ad17 gwah # Character ê´
+U+ad18 gwae # Character ê´
+U+ad19 gwaeg # Character ê´
+U+ad1a gwaegg # Character ê´
+U+ad1b gwaegs # Character ê´
+U+ad1c gwaen # Character ê´
+U+ad1d gwaenj # Character ê´
+U+ad1e gwaenh # Character ê´
+U+ad1f gwaed # Character ê´
+U+ad20 gwael # Character ê´
+U+ad21 gwaelg # Character ê´¡
+U+ad22 gwaelm # Character ê´¢
+U+ad23 gwaelb # Character ê´£
+U+ad24 gwaels # Character ê´¤
+U+ad25 gwaelt # Character ê´¥
+U+ad26 gwaelp # Character ê´¦
+U+ad27 gwaelh # Character ê´§
+U+ad28 gwaem # Character ê´¨
+U+ad29 gwaeb # Character ê´©
+U+ad2a gwaebs # Character ê´ª
+U+ad2b gwaes # Character ê´«
+U+ad2c gwaess # Character ê´¬
+U+ad2d gwaeng # Character ê´
+U+ad2e gwaej # Character ê´®
+U+ad2f gwaec # Character ê´¯
+U+ad30 gwaek # Character ê´°
+U+ad31 gwaet # Character ê´±
+U+ad32 gwaep # Character ê´²
+U+ad33 gwaeh # Character ê´³
+U+ad34 goe # Character ê´´
+U+ad35 goeg # Character ê´µ
+U+ad36 goegg # Character ê´¶
+U+ad37 goegs # Character ê´·
+U+ad38 goen # Character ê´¸
+U+ad39 goenj # Character ê´¹
+U+ad3a goenh # Character ê´º
+U+ad3b goed # Character ê´»
+U+ad3c goel # Character ê´¼
+U+ad3d goelg # Character ê´½
+U+ad3e goelm # Character ê´¾
+U+ad3f goelb # Character ê´¿
+U+ad40 goels # Character êµ
+U+ad41 goelt # Character êµ
+U+ad42 goelp # Character êµ
+U+ad43 goelh # Character êµ
+U+ad44 goem # Character êµ
+U+ad45 goeb # Character êµ
+U+ad46 goebs # Character êµ
+U+ad47 goes # Character êµ
+U+ad48 goess # Character êµ
+U+ad49 goeng # Character êµ
+U+ad4a goej # Character êµ
+U+ad4b goec # Character êµ
+U+ad4c goek # Character êµ
+U+ad4d goet # Character êµ
+U+ad4e goep # Character êµ
+U+ad4f goeh # Character êµ
+U+ad50 gyo # Character êµ
+U+ad51 gyog # Character êµ
+U+ad52 gyogg # Character êµ
+U+ad53 gyogs # Character êµ
+U+ad54 gyon # Character êµ
+U+ad55 gyonj # Character êµ
+U+ad56 gyonh # Character êµ
+U+ad57 gyod # Character êµ
+U+ad58 gyol # Character êµ
+U+ad59 gyolg # Character êµ
+U+ad5a gyolm # Character êµ
+U+ad5b gyolb # Character êµ
+U+ad5c gyols # Character êµ
+U+ad5d gyolt # Character êµ
+U+ad5e gyolp # Character êµ
+U+ad5f gyolh # Character êµ
+U+ad60 gyom # Character êµ
+U+ad61 gyob # Character 굡
+U+ad62 gyobs # Character êµ¢
+U+ad63 gyos # Character êµ£
+U+ad64 gyoss # Character 굤
+U+ad65 gyong # Character êµ¥
+U+ad66 gyoj # Character 굦
+U+ad67 gyoc # Character 굧
+U+ad68 gyok # Character 굨
+U+ad69 gyot # Character 굩
+U+ad6a gyop # Character 굪
+U+ad6b gyoh # Character 굫
+U+ad6c gu # Character 구
+U+ad6d gug # Character êµ
+U+ad6e gugg # Character êµ®
+U+ad6f gugs # Character 굯
+U+ad70 gun # Character êµ°
+U+ad71 gunj # Character êµ±
+U+ad72 gunh # Character êµ²
+U+ad73 gud # Character êµ³
+U+ad74 gul # Character êµ´
+U+ad75 gulg # Character êµµ
+U+ad76 gulm # Character 굶
+U+ad77 gulb # Character êµ·
+U+ad78 guls # Character 굸
+U+ad79 gult # Character êµ¹
+U+ad7a gulp # Character 굺
+U+ad7b gulh # Character êµ»
+U+ad7c gum # Character êµ¼
+U+ad7d gub # Character êµ½
+U+ad7e gubs # Character êµ¾
+U+ad7f gus # Character 굿
+U+ad80 guss # Character ê¶
+U+ad81 gung # Character ê¶
+U+ad82 guj # Character ê¶
+U+ad83 guc # Character ê¶
+U+ad84 guk # Character ê¶
+U+ad85 gut # Character ê¶
+U+ad86 gup # Character ê¶
+U+ad87 guh # Character ê¶
+U+ad88 gweo # Character ê¶
+U+ad89 gweog # Character ê¶
+U+ad8a gweogg # Character ê¶
+U+ad8b gweogs # Character ê¶
+U+ad8c gweon # Character ê¶
+U+ad8d gweonj # Character ê¶
+U+ad8e gweonh # Character ê¶
+U+ad8f gweod # Character ê¶
+U+ad90 gweol # Character ê¶
+U+ad91 gweolg # Character ê¶
+U+ad92 gweolm # Character ê¶
+U+ad93 gweolb # Character ê¶
+U+ad94 gweols # Character ê¶
+U+ad95 gweolt # Character ê¶
+U+ad96 gweolp # Character ê¶
+U+ad97 gweolh # Character ê¶
+U+ad98 gweom # Character ê¶
+U+ad99 gweob # Character ê¶
+U+ad9a gweobs # Character ê¶
+U+ad9b gweos # Character ê¶
+U+ad9c gweoss # Character ê¶
+U+ad9d gweong # Character ê¶
+U+ad9e gweoj # Character ê¶
+U+ad9f gweoc # Character ê¶
+U+ada0 gweok # Character ê¶
+U+ada1 gweot # Character 궡
+U+ada2 gweop # Character 궢
+U+ada3 gweoh # Character 궣
+U+ada4 gwe # Character 궤
+U+ada5 gweg # Character 궥
+U+ada6 gwegg # Character 궦
+U+ada7 gwegs # Character 궧
+U+ada8 gwen # Character 궨
+U+ada9 gwenj # Character 궩
+U+adaa gwenh # Character 궪
+U+adab gwed # Character 궫
+U+adac gwel # Character 궬
+U+adad gwelg # Character ê¶
+U+adae gwelm # Character 궮
+U+adaf gwelb # Character 궯
+U+adb0 gwels # Character 궰
+U+adb1 gwelt # Character 궱
+U+adb2 gwelp # Character 궲
+U+adb3 gwelh # Character 궳
+U+adb4 gwem # Character 궴
+U+adb5 gweb # Character 궵
+U+adb6 gwebs # Character 궶
+U+adb7 gwes # Character 궷
+U+adb8 gwess # Character 궸
+U+adb9 gweng # Character 궹
+U+adba gwej # Character 궺
+U+adbb gwec # Character 궻
+U+adbc gwek # Character 궼
+U+adbd gwet # Character 궽
+U+adbe gwep # Character 궾
+U+adbf gweh # Character 궿
+U+adc0 gwi # Character ê·
+U+adc1 gwig # Character ê·
+U+adc2 gwigg # Character ê·
+U+adc3 gwigs # Character ê·
+U+adc4 gwin # Character ê·
+U+adc5 gwinj # Character ê·
+U+adc6 gwinh # Character ê·
+U+adc7 gwid # Character ê·
+U+adc8 gwil # Character ê·
+U+adc9 gwilg # Character ê·
+U+adca gwilm # Character ê·
+U+adcb gwilb # Character ê·
+U+adcc gwils # Character ê·
+U+adcd gwilt # Character ê·
+U+adce gwilp # Character ê·
+U+adcf gwilh # Character ê·
+U+add0 gwim # Character ê·
+U+add1 gwib # Character ê·
+U+add2 gwibs # Character ê·
+U+add3 gwis # Character ê·
+U+add4 gwiss # Character ê·
+U+add5 gwing # Character ê·
+U+add6 gwij # Character ê·
+U+add7 gwic # Character ê·
+U+add8 gwik # Character ê·
+U+add9 gwit # Character ê·
+U+adda gwip # Character ê·
+U+addb gwih # Character ê·
+U+addc gyu # Character ê·
+U+addd gyug # Character ê·
+U+adde gyugg # Character ê·
+U+addf gyugs # Character ê·
+U+ade0 gyun # Character ê·
+U+ade1 gyunj # Character ê·¡
+U+ade2 gyunh # Character ê·¢
+U+ade3 gyud # Character ê·£
+U+ade4 gyul # Character ê·¤
+U+ade5 gyulg # Character ê·¥
+U+ade6 gyulm # Character ê·¦
+U+ade7 gyulb # Character ê·§
+U+ade8 gyuls # Character ê·¨
+U+ade9 gyult # Character ê·©
+U+adea gyulp # Character ê·ª
+U+adeb gyulh # Character ê·«
+U+adec gyum # Character ê·¬
+U+aded gyub # Character ê·
+U+adee gyubs # Character ê·®
+U+adef gyus # Character ê·¯
+U+adf0 gyuss # Character ê·°
+U+adf1 gyung # Character ê·±
+U+adf2 gyuj # Character ê·²
+U+adf3 gyuc # Character ê·³
+U+adf4 gyuk # Character ê·´
+U+adf5 gyut # Character ê·µ
+U+adf6 gyup # Character ê·¶
+U+adf7 gyuh # Character ê··
+U+adf8 geu # Character ê·¸
+U+adf9 geug # Character ê·¹
+U+adfa geugg # Character ê·º
+U+adfb geugs # Character ê·»
+U+adfc geun # Character ê·¼
+U+adfd geunj # Character ê·½
+U+adfe geunh # Character ê·¾
+U+adff geud # Character ê·¿
diff --git a/resources/chars/ascii/rowae.trans b/resources/chars/ascii/rowae.trans
new file mode 100644
index 0000000..d82a806
--- /dev/null
+++ b/resources/chars/ascii/rowae.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+ae00 geul # Character ê¸
+U+ae01 geulg # Character ê¸
+U+ae02 geulm # Character ê¸
+U+ae03 geulb # Character ê¸
+U+ae04 geuls # Character ê¸
+U+ae05 geult # Character ê¸
+U+ae06 geulp # Character ê¸
+U+ae07 geulh # Character ê¸
+U+ae08 geum # Character ê¸
+U+ae09 geub # Character ê¸
+U+ae0a geubs # Character ê¸
+U+ae0b geus # Character ê¸
+U+ae0c geuss # Character ê¸
+U+ae0d geung # Character ê¸
+U+ae0e geuj # Character ê¸
+U+ae0f geuc # Character ê¸
+U+ae10 geuk # Character ê¸
+U+ae11 geut # Character ê¸
+U+ae12 geup # Character ê¸
+U+ae13 geuh # Character ê¸
+U+ae14 gyi # Character ê¸
+U+ae15 gyig # Character ê¸
+U+ae16 gyigg # Character ê¸
+U+ae17 gyigs # Character ê¸
+U+ae18 gyin # Character ê¸
+U+ae19 gyinj # Character ê¸
+U+ae1a gyinh # Character ê¸
+U+ae1b gyid # Character ê¸
+U+ae1c gyil # Character ê¸
+U+ae1d gyilg # Character ê¸
+U+ae1e gyilm # Character ê¸
+U+ae1f gyilb # Character ê¸
+U+ae20 gyils # Character ê¸
+U+ae21 gyilt # Character 긡
+U+ae22 gyilp # Character 긢
+U+ae23 gyilh # Character 긣
+U+ae24 gyim # Character 긤
+U+ae25 gyib # Character 긥
+U+ae26 gyibs # Character 긦
+U+ae27 gyis # Character 긧
+U+ae28 gyiss # Character 긨
+U+ae29 gying # Character 긩
+U+ae2a gyij # Character 긪
+U+ae2b gyic # Character 긫
+U+ae2c gyik # Character 긬
+U+ae2d gyit # Character ê¸
+U+ae2e gyip # Character 긮
+U+ae2f gyih # Character 긯
+U+ae30 gi # Character 기
+U+ae31 gig # Character 긱
+U+ae32 gigg # Character 긲
+U+ae33 gigs # Character 긳
+U+ae34 gin # Character 긴
+U+ae35 ginj # Character 긵
+U+ae36 ginh # Character 긶
+U+ae37 gid # Character 긷
+U+ae38 gil # Character 길
+U+ae39 gilg # Character 긹
+U+ae3a gilm # Character 긺
+U+ae3b gilb # Character 긻
+U+ae3c gils # Character 긼
+U+ae3d gilt # Character 긽
+U+ae3e gilp # Character 긾
+U+ae3f gilh # Character 긿
+U+ae40 gim # Character ê¹
+U+ae41 gib # Character ê¹
+U+ae42 gibs # Character ê¹
+U+ae43 gis # Character ê¹
+U+ae44 giss # Character ê¹
+U+ae45 ging # Character ê¹
+U+ae46 gij # Character ê¹
+U+ae47 gic # Character ê¹
+U+ae48 gik # Character ê¹
+U+ae49 git # Character ê¹
+U+ae4a gip # Character ê¹
+U+ae4b gih # Character ê¹
+U+ae4c gga # Character ê¹
+U+ae4d ggag # Character ê¹
+U+ae4e ggagg # Character ê¹
+U+ae4f ggags # Character ê¹
+U+ae50 ggan # Character ê¹
+U+ae51 gganj # Character ê¹
+U+ae52 gganh # Character ê¹
+U+ae53 ggad # Character ê¹
+U+ae54 ggal # Character ê¹
+U+ae55 ggalg # Character ê¹
+U+ae56 ggalm # Character ê¹
+U+ae57 ggalb # Character ê¹
+U+ae58 ggals # Character ê¹
+U+ae59 ggalt # Character ê¹
+U+ae5a ggalp # Character ê¹
+U+ae5b ggalh # Character ê¹
+U+ae5c ggam # Character ê¹
+U+ae5d ggab # Character ê¹
+U+ae5e ggabs # Character ê¹
+U+ae5f ggas # Character ê¹
+U+ae60 ggass # Character ê¹
+U+ae61 ggang # Character 깡
+U+ae62 ggaj # Character ê¹¢
+U+ae63 ggac # Character ê¹£
+U+ae64 ggak # Character 깤
+U+ae65 ggat # Character ê¹¥
+U+ae66 ggap # Character 깦
+U+ae67 ggah # Character 깧
+U+ae68 ggae # Character 깨
+U+ae69 ggaeg # Character 깩
+U+ae6a ggaegg # Character 깪
+U+ae6b ggaegs # Character 깫
+U+ae6c ggaen # Character 깬
+U+ae6d ggaenj # Character ê¹
+U+ae6e ggaenh # Character ê¹®
+U+ae6f ggaed # Character 깯
+U+ae70 ggael # Character ê¹°
+U+ae71 ggaelg # Character ê¹±
+U+ae72 ggaelm # Character ê¹²
+U+ae73 ggaelb # Character ê¹³
+U+ae74 ggaels # Character ê¹´
+U+ae75 ggaelt # Character ê¹µ
+U+ae76 ggaelp # Character 깶
+U+ae77 ggaelh # Character ê¹·
+U+ae78 ggaem # Character 깸
+U+ae79 ggaeb # Character ê¹¹
+U+ae7a ggaebs # Character 깺
+U+ae7b ggaes # Character ê¹»
+U+ae7c ggaess # Character ê¹¼
+U+ae7d ggaeng # Character ê¹½
+U+ae7e ggaej # Character ê¹¾
+U+ae7f ggaec # Character 깿
+U+ae80 ggaek # Character êº
+U+ae81 ggaet # Character êº
+U+ae82 ggaep # Character êº
+U+ae83 ggaeh # Character êº
+U+ae84 ggya # Character êº
+U+ae85 ggyag # Character êº
+U+ae86 ggyagg # Character êº
+U+ae87 ggyags # Character êº
+U+ae88 ggyan # Character êº
+U+ae89 ggyanj # Character êº
+U+ae8a ggyanh # Character êº
+U+ae8b ggyad # Character êº
+U+ae8c ggyal # Character êº
+U+ae8d ggyalg # Character êº
+U+ae8e ggyalm # Character êº
+U+ae8f ggyalb # Character êº
+U+ae90 ggyals # Character êº
+U+ae91 ggyalt # Character êº
+U+ae92 ggyalp # Character êº
+U+ae93 ggyalh # Character êº
+U+ae94 ggyam # Character êº
+U+ae95 ggyab # Character êº
+U+ae96 ggyabs # Character êº
+U+ae97 ggyas # Character êº
+U+ae98 ggyass # Character êº
+U+ae99 ggyang # Character êº
+U+ae9a ggyaj # Character êº
+U+ae9b ggyac # Character êº
+U+ae9c ggyak # Character êº
+U+ae9d ggyat # Character êº
+U+ae9e ggyap # Character êº
+U+ae9f ggyah # Character êº
+U+aea0 ggyae # Character êº
+U+aea1 ggyaeg # Character 꺡
+U+aea2 ggyaegg # Character 꺢
+U+aea3 ggyaegs # Character 꺣
+U+aea4 ggyaen # Character 꺤
+U+aea5 ggyaenj # Character 꺥
+U+aea6 ggyaenh # Character 꺦
+U+aea7 ggyaed # Character 꺧
+U+aea8 ggyael # Character 꺨
+U+aea9 ggyaelg # Character 꺩
+U+aeaa ggyaelm # Character 꺪
+U+aeab ggyaelb # Character 꺫
+U+aeac ggyaels # Character 꺬
+U+aead ggyaelt # Character êº
+U+aeae ggyaelp # Character 꺮
+U+aeaf ggyaelh # Character 꺯
+U+aeb0 ggyaem # Character 꺰
+U+aeb1 ggyaeb # Character 꺱
+U+aeb2 ggyaebs # Character 꺲
+U+aeb3 ggyaes # Character 꺳
+U+aeb4 ggyaess # Character 꺴
+U+aeb5 ggyaeng # Character 꺵
+U+aeb6 ggyaej # Character 꺶
+U+aeb7 ggyaec # Character 꺷
+U+aeb8 ggyaek # Character 꺸
+U+aeb9 ggyaet # Character 꺹
+U+aeba ggyaep # Character 꺺
+U+aebb ggyaeh # Character 꺻
+U+aebc ggeo # Character 꺼
+U+aebd ggeog # Character 꺽
+U+aebe ggeogg # Character 꺾
+U+aebf ggeogs # Character 꺿
+U+aec0 ggeon # Character ê»
+U+aec1 ggeonj # Character ê»
+U+aec2 ggeonh # Character ê»
+U+aec3 ggeod # Character ê»
+U+aec4 ggeol # Character ê»
+U+aec5 ggeolg # Character ê»
+U+aec6 ggeolm # Character ê»
+U+aec7 ggeolb # Character ê»
+U+aec8 ggeols # Character ê»
+U+aec9 ggeolt # Character ê»
+U+aeca ggeolp # Character ê»
+U+aecb ggeolh # Character ê»
+U+aecc ggeom # Character ê»
+U+aecd ggeob # Character ê»
+U+aece ggeobs # Character ê»
+U+aecf ggeos # Character ê»
+U+aed0 ggeoss # Character ê»
+U+aed1 ggeong # Character ê»
+U+aed2 ggeoj # Character ê»
+U+aed3 ggeoc # Character ê»
+U+aed4 ggeok # Character ê»
+U+aed5 ggeot # Character ê»
+U+aed6 ggeop # Character ê»
+U+aed7 ggeoh # Character ê»
+U+aed8 gge # Character ê»
+U+aed9 ggeg # Character ê»
+U+aeda ggegg # Character ê»
+U+aedb ggegs # Character ê»
+U+aedc ggen # Character ê»
+U+aedd ggenj # Character ê»
+U+aede ggenh # Character ê»
+U+aedf gged # Character ê»
+U+aee0 ggel # Character ê»
+U+aee1 ggelg # Character 껡
+U+aee2 ggelm # Character 껢
+U+aee3 ggelb # Character 껣
+U+aee4 ggels # Character 껤
+U+aee5 ggelt # Character 껥
+U+aee6 ggelp # Character 껦
+U+aee7 ggelh # Character 껧
+U+aee8 ggem # Character 껨
+U+aee9 ggeb # Character 껩
+U+aeea ggebs # Character 껪
+U+aeeb gges # Character 껫
+U+aeec ggess # Character 껬
+U+aeed ggeng # Character ê»
+U+aeee ggej # Character ê»®
+U+aeef ggec # Character 껯
+U+aef0 ggek # Character ê»°
+U+aef1 gget # Character ê»±
+U+aef2 ggep # Character 껲
+U+aef3 ggeh # Character 껳
+U+aef4 ggyeo # Character ê»´
+U+aef5 ggyeog # Character 껵
+U+aef6 ggyeogg # Character 껶
+U+aef7 ggyeogs # Character ê»·
+U+aef8 ggyeon # Character 껸
+U+aef9 ggyeonj # Character 껹
+U+aefa ggyeonh # Character 껺
+U+aefb ggyeod # Character ê»»
+U+aefc ggyeol # Character 껼
+U+aefd ggyeolg # Character 껽
+U+aefe ggyeolm # Character 껾
+U+aeff ggyeolb # Character 껿
diff --git a/resources/chars/ascii/rowaf.trans b/resources/chars/ascii/rowaf.trans
new file mode 100644
index 0000000..ae2e057
--- /dev/null
+++ b/resources/chars/ascii/rowaf.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+af00 ggyeols # Character ê¼
+U+af01 ggyeolt # Character ê¼
+U+af02 ggyeolp # Character ê¼
+U+af03 ggyeolh # Character ê¼
+U+af04 ggyeom # Character ê¼
+U+af05 ggyeob # Character ê¼
+U+af06 ggyeobs # Character ê¼
+U+af07 ggyeos # Character ê¼
+U+af08 ggyeoss # Character ê¼
+U+af09 ggyeong # Character ê¼
+U+af0a ggyeoj # Character ê¼
+U+af0b ggyeoc # Character ê¼
+U+af0c ggyeok # Character ê¼
+U+af0d ggyeot # Character ê¼
+U+af0e ggyeop # Character ê¼
+U+af0f ggyeoh # Character ê¼
+U+af10 ggye # Character ê¼
+U+af11 ggyeg # Character ê¼
+U+af12 ggyegg # Character ê¼
+U+af13 ggyegs # Character ê¼
+U+af14 ggyen # Character ê¼
+U+af15 ggyenj # Character ê¼
+U+af16 ggyenh # Character ê¼
+U+af17 ggyed # Character ê¼
+U+af18 ggyel # Character ê¼
+U+af19 ggyelg # Character ê¼
+U+af1a ggyelm # Character ê¼
+U+af1b ggyelb # Character ê¼
+U+af1c ggyels # Character ê¼
+U+af1d ggyelt # Character ê¼
+U+af1e ggyelp # Character ê¼
+U+af1f ggyelh # Character ê¼
+U+af20 ggyem # Character ê¼
+U+af21 ggyeb # Character 꼡
+U+af22 ggyebs # Character ê¼¢
+U+af23 ggyes # Character ê¼£
+U+af24 ggyess # Character 꼤
+U+af25 ggyeng # Character ê¼¥
+U+af26 ggyej # Character 꼦
+U+af27 ggyec # Character 꼧
+U+af28 ggyek # Character 꼨
+U+af29 ggyet # Character 꼩
+U+af2a ggyep # Character 꼪
+U+af2b ggyeh # Character 꼫
+U+af2c ggo # Character 꼬
+U+af2d ggog # Character ê¼
+U+af2e ggogg # Character ê¼®
+U+af2f ggogs # Character 꼯
+U+af30 ggon # Character ê¼°
+U+af31 ggonj # Character ê¼±
+U+af32 ggonh # Character ê¼²
+U+af33 ggod # Character ê¼³
+U+af34 ggol # Character ê¼´
+U+af35 ggolg # Character ê¼µ
+U+af36 ggolm # Character 꼶
+U+af37 ggolb # Character ê¼·
+U+af38 ggols # Character 꼸
+U+af39 ggolt # Character ê¼¹
+U+af3a ggolp # Character 꼺
+U+af3b ggolh # Character ê¼»
+U+af3c ggom # Character ê¼¼
+U+af3d ggob # Character ê¼½
+U+af3e ggobs # Character ê¼¾
+U+af3f ggos # Character 꼿
+U+af40 ggoss # Character ê½
+U+af41 ggong # Character ê½
+U+af42 ggoj # Character ê½
+U+af43 ggoc # Character ê½
+U+af44 ggok # Character ê½
+U+af45 ggot # Character ê½
+U+af46 ggop # Character ê½
+U+af47 ggoh # Character ê½
+U+af48 ggwa # Character ê½
+U+af49 ggwag # Character ê½
+U+af4a ggwagg # Character ê½
+U+af4b ggwags # Character ê½
+U+af4c ggwan # Character ê½
+U+af4d ggwanj # Character ê½
+U+af4e ggwanh # Character ê½
+U+af4f ggwad # Character ê½
+U+af50 ggwal # Character ê½
+U+af51 ggwalg # Character ê½
+U+af52 ggwalm # Character ê½
+U+af53 ggwalb # Character ê½
+U+af54 ggwals # Character ê½
+U+af55 ggwalt # Character ê½
+U+af56 ggwalp # Character ê½
+U+af57 ggwalh # Character ê½
+U+af58 ggwam # Character ê½
+U+af59 ggwab # Character ê½
+U+af5a ggwabs # Character ê½
+U+af5b ggwas # Character ê½
+U+af5c ggwass # Character ê½
+U+af5d ggwang # Character ê½
+U+af5e ggwaj # Character ê½
+U+af5f ggwac # Character ê½
+U+af60 ggwak # Character ê½
+U+af61 ggwat # Character 꽡
+U+af62 ggwap # Character ê½¢
+U+af63 ggwah # Character ê½£
+U+af64 ggwae # Character 꽤
+U+af65 ggwaeg # Character ê½¥
+U+af66 ggwaegg # Character 꽦
+U+af67 ggwaegs # Character 꽧
+U+af68 ggwaen # Character 꽨
+U+af69 ggwaenj # Character 꽩
+U+af6a ggwaenh # Character 꽪
+U+af6b ggwaed # Character 꽫
+U+af6c ggwael # Character 꽬
+U+af6d ggwaelg # Character ê½
+U+af6e ggwaelm # Character ê½®
+U+af6f ggwaelb # Character 꽯
+U+af70 ggwaels # Character ê½°
+U+af71 ggwaelt # Character ê½±
+U+af72 ggwaelp # Character ê½²
+U+af73 ggwaelh # Character ê½³
+U+af74 ggwaem # Character ê½´
+U+af75 ggwaeb # Character ê½µ
+U+af76 ggwaebs # Character 꽶
+U+af77 ggwaes # Character ê½·
+U+af78 ggwaess # Character 꽸
+U+af79 ggwaeng # Character ê½¹
+U+af7a ggwaej # Character 꽺
+U+af7b ggwaec # Character ê½»
+U+af7c ggwaek # Character ê½¼
+U+af7d ggwaet # Character ê½½
+U+af7e ggwaep # Character ê½¾
+U+af7f ggwaeh # Character 꽿
+U+af80 ggoe # Character ê¾
+U+af81 ggoeg # Character ê¾
+U+af82 ggoegg # Character ê¾
+U+af83 ggoegs # Character ê¾
+U+af84 ggoen # Character ê¾
+U+af85 ggoenj # Character ê¾
+U+af86 ggoenh # Character ê¾
+U+af87 ggoed # Character ê¾
+U+af88 ggoel # Character ê¾
+U+af89 ggoelg # Character ê¾
+U+af8a ggoelm # Character ê¾
+U+af8b ggoelb # Character ê¾
+U+af8c ggoels # Character ê¾
+U+af8d ggoelt # Character ê¾
+U+af8e ggoelp # Character ê¾
+U+af8f ggoelh # Character ê¾
+U+af90 ggoem # Character ê¾
+U+af91 ggoeb # Character ê¾
+U+af92 ggoebs # Character ê¾
+U+af93 ggoes # Character ê¾
+U+af94 ggoess # Character ê¾
+U+af95 ggoeng # Character ê¾
+U+af96 ggoej # Character ê¾
+U+af97 ggoec # Character ê¾
+U+af98 ggoek # Character ê¾
+U+af99 ggoet # Character ê¾
+U+af9a ggoep # Character ê¾
+U+af9b ggoeh # Character ê¾
+U+af9c ggyo # Character ê¾
+U+af9d ggyog # Character ê¾
+U+af9e ggyogg # Character ê¾
+U+af9f ggyogs # Character ê¾
+U+afa0 ggyon # Character ê¾
+U+afa1 ggyonj # Character 꾡
+U+afa2 ggyonh # Character ê¾¢
+U+afa3 ggyod # Character ê¾£
+U+afa4 ggyol # Character 꾤
+U+afa5 ggyolg # Character ê¾¥
+U+afa6 ggyolm # Character 꾦
+U+afa7 ggyolb # Character 꾧
+U+afa8 ggyols # Character 꾨
+U+afa9 ggyolt # Character 꾩
+U+afaa ggyolp # Character 꾪
+U+afab ggyolh # Character 꾫
+U+afac ggyom # Character 꾬
+U+afad ggyob # Character ê¾
+U+afae ggyobs # Character ê¾®
+U+afaf ggyos # Character 꾯
+U+afb0 ggyoss # Character ê¾°
+U+afb1 ggyong # Character ê¾±
+U+afb2 ggyoj # Character ê¾²
+U+afb3 ggyoc # Character ê¾³
+U+afb4 ggyok # Character ê¾´
+U+afb5 ggyot # Character ê¾µ
+U+afb6 ggyop # Character 꾶
+U+afb7 ggyoh # Character ê¾·
+U+afb8 ggu # Character 꾸
+U+afb9 ggug # Character ê¾¹
+U+afba ggugg # Character 꾺
+U+afbb ggugs # Character ê¾»
+U+afbc ggun # Character ê¾¼
+U+afbd ggunj # Character ê¾½
+U+afbe ggunh # Character ê¾¾
+U+afbf ggud # Character 꾿
+U+afc0 ggul # Character ê¿
+U+afc1 ggulg # Character ê¿
+U+afc2 ggulm # Character ê¿
+U+afc3 ggulb # Character ê¿
+U+afc4 gguls # Character ê¿
+U+afc5 ggult # Character ê¿
+U+afc6 ggulp # Character ê¿
+U+afc7 ggulh # Character ê¿
+U+afc8 ggum # Character ê¿
+U+afc9 ggub # Character ê¿
+U+afca ggubs # Character ê¿
+U+afcb ggus # Character ê¿
+U+afcc gguss # Character ê¿
+U+afcd ggung # Character ê¿
+U+afce gguj # Character ê¿
+U+afcf gguc # Character ê¿
+U+afd0 gguk # Character ê¿
+U+afd1 ggut # Character ê¿
+U+afd2 ggup # Character ê¿
+U+afd3 gguh # Character ê¿
+U+afd4 ggweo # Character ê¿
+U+afd5 ggweog # Character ê¿
+U+afd6 ggweogg # Character ê¿
+U+afd7 ggweogs # Character ê¿
+U+afd8 ggweon # Character ê¿
+U+afd9 ggweonj # Character ê¿
+U+afda ggweonh # Character ê¿
+U+afdb ggweod # Character ê¿
+U+afdc ggweol # Character ê¿
+U+afdd ggweolg # Character ê¿
+U+afde ggweolm # Character ê¿
+U+afdf ggweolb # Character ê¿
+U+afe0 ggweols # Character ê¿
+U+afe1 ggweolt # Character ê¿¡
+U+afe2 ggweolp # Character ê¿¢
+U+afe3 ggweolh # Character ê¿£
+U+afe4 ggweom # Character 꿤
+U+afe5 ggweob # Character ê¿¥
+U+afe6 ggweobs # Character 꿦
+U+afe7 ggweos # Character 꿧
+U+afe8 ggweoss # Character 꿨
+U+afe9 ggweong # Character ê¿©
+U+afea ggweoj # Character 꿪
+U+afeb ggweoc # Character ê¿«
+U+afec ggweok # Character 꿬
+U+afed ggweot # Character ê¿
+U+afee ggweop # Character ê¿®
+U+afef ggweoh # Character 꿯
+U+aff0 ggwe # Character ê¿°
+U+aff1 ggweg # Character 꿱
+U+aff2 ggwegg # Character 꿲
+U+aff3 ggwegs # Character 꿳
+U+aff4 ggwen # Character ê¿´
+U+aff5 ggwenj # Character 꿵
+U+aff6 ggwenh # Character 꿶
+U+aff7 ggwed # Character ê¿·
+U+aff8 ggwel # Character 꿸
+U+aff9 ggwelg # Character 꿹
+U+affa ggwelm # Character 꿺
+U+affb ggwelb # Character ê¿»
+U+affc ggwels # Character 꿼
+U+affd ggwelt # Character 꿽
+U+affe ggwelp # Character 꿾
+U+afff ggwelh # Character ê¿¿
diff --git a/resources/chars/ascii/rowb0.trans b/resources/chars/ascii/rowb0.trans
new file mode 100644
index 0000000..868333e
--- /dev/null
+++ b/resources/chars/ascii/rowb0.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+b000 ggwem # Character ë
+U+b001 ggweb # Character ë
+U+b002 ggwebs # Character ë
+U+b003 ggwes # Character ë
+U+b004 ggwess # Character ë
+U+b005 ggweng # Character ë
+U+b006 ggwej # Character ë
+U+b007 ggwec # Character ë
+U+b008 ggwek # Character ë
+U+b009 ggwet # Character ë
+U+b00a ggwep # Character ë
+U+b00b ggweh # Character ë
+U+b00c ggwi # Character ë
+U+b00d ggwig # Character ë
+U+b00e ggwigg # Character ë
+U+b00f ggwigs # Character ë
+U+b010 ggwin # Character ë
+U+b011 ggwinj # Character ë
+U+b012 ggwinh # Character ë
+U+b013 ggwid # Character ë
+U+b014 ggwil # Character ë
+U+b015 ggwilg # Character ë
+U+b016 ggwilm # Character ë
+U+b017 ggwilb # Character ë
+U+b018 ggwils # Character ë
+U+b019 ggwilt # Character ë
+U+b01a ggwilp # Character ë
+U+b01b ggwilh # Character ë
+U+b01c ggwim # Character ë
+U+b01d ggwib # Character ë
+U+b01e ggwibs # Character ë
+U+b01f ggwis # Character ë
+U+b020 ggwiss # Character ë
+U+b021 ggwing # Character ë¡
+U+b022 ggwij # Character ë¢
+U+b023 ggwic # Character ë£
+U+b024 ggwik # Character ë¤
+U+b025 ggwit # Character ë¥
+U+b026 ggwip # Character ë¦
+U+b027 ggwih # Character ë§
+U+b028 ggyu # Character ë¨
+U+b029 ggyug # Character ë©
+U+b02a ggyugg # Character ëª
+U+b02b ggyugs # Character ë«
+U+b02c ggyun # Character ë¬
+U+b02d ggyunj # Character ë
+U+b02e ggyunh # Character ë®
+U+b02f ggyud # Character ë¯
+U+b030 ggyul # Character ë°
+U+b031 ggyulg # Character ë±
+U+b032 ggyulm # Character ë²
+U+b033 ggyulb # Character ë³
+U+b034 ggyuls # Character ë´
+U+b035 ggyult # Character ëµ
+U+b036 ggyulp # Character ë¶
+U+b037 ggyulh # Character ë·
+U+b038 ggyum # Character ë¸
+U+b039 ggyub # Character ë¹
+U+b03a ggyubs # Character ëº
+U+b03b ggyus # Character ë»
+U+b03c ggyuss # Character ë¼
+U+b03d ggyung # Character ë½
+U+b03e ggyuj # Character ë¾
+U+b03f ggyuc # Character ë¿
+U+b040 ggyuk # Character ë
+U+b041 ggyut # Character ë
+U+b042 ggyup # Character ë
+U+b043 ggyuh # Character ë
+U+b044 ggeu # Character ë
+U+b045 ggeug # Character ë
+U+b046 ggeugg # Character ë
+U+b047 ggeugs # Character ë
+U+b048 ggeun # Character ë
+U+b049 ggeunj # Character ë
+U+b04a ggeunh # Character ë
+U+b04b ggeud # Character ë
+U+b04c ggeul # Character ë
+U+b04d ggeulg # Character ë
+U+b04e ggeulm # Character ë
+U+b04f ggeulb # Character ë
+U+b050 ggeuls # Character ë
+U+b051 ggeult # Character ë
+U+b052 ggeulp # Character ë
+U+b053 ggeulh # Character ë
+U+b054 ggeum # Character ë
+U+b055 ggeub # Character ë
+U+b056 ggeubs # Character ë
+U+b057 ggeus # Character ë
+U+b058 ggeuss # Character ë
+U+b059 ggeung # Character ë
+U+b05a ggeuj # Character ë
+U+b05b ggeuc # Character ë
+U+b05c ggeuk # Character ë
+U+b05d ggeut # Character ë
+U+b05e ggeup # Character ë
+U+b05f ggeuh # Character ë
+U+b060 ggyi # Character ë
+U+b061 ggyig # Character ë¡
+U+b062 ggyigg # Character ë¢
+U+b063 ggyigs # Character ë£
+U+b064 ggyin # Character ë¤
+U+b065 ggyinj # Character ë¥
+U+b066 ggyinh # Character ë¦
+U+b067 ggyid # Character ë§
+U+b068 ggyil # Character ë¨
+U+b069 ggyilg # Character ë©
+U+b06a ggyilm # Character ëª
+U+b06b ggyilb # Character ë«
+U+b06c ggyils # Character ë¬
+U+b06d ggyilt # Character ë
+U+b06e ggyilp # Character ë®
+U+b06f ggyilh # Character ë¯
+U+b070 ggyim # Character ë°
+U+b071 ggyib # Character ë±
+U+b072 ggyibs # Character ë²
+U+b073 ggyis # Character ë³
+U+b074 ggyiss # Character ë´
+U+b075 ggying # Character ëµ
+U+b076 ggyij # Character ë¶
+U+b077 ggyic # Character ë·
+U+b078 ggyik # Character ë¸
+U+b079 ggyit # Character ë¹
+U+b07a ggyip # Character ëº
+U+b07b ggyih # Character ë»
+U+b07c ggi # Character ë¼
+U+b07d ggig # Character ë½
+U+b07e ggigg # Character ë¾
+U+b07f ggigs # Character ë¿
+U+b080 ggin # Character ë
+U+b081 gginj # Character ë
+U+b082 gginh # Character ë
+U+b083 ggid # Character ë
+U+b084 ggil # Character ë
+U+b085 ggilg # Character ë
+U+b086 ggilm # Character ë
+U+b087 ggilb # Character ë
+U+b088 ggils # Character ë
+U+b089 ggilt # Character ë
+U+b08a ggilp # Character ë
+U+b08b ggilh # Character ë
+U+b08c ggim # Character ë
+U+b08d ggib # Character ë
+U+b08e ggibs # Character ë
+U+b08f ggis # Character ë
+U+b090 ggiss # Character ë
+U+b091 gging # Character ë
+U+b092 ggij # Character ë
+U+b093 ggic # Character ë
+U+b094 ggik # Character ë
+U+b095 ggit # Character ë
+U+b096 ggip # Character ë
+U+b097 ggih # Character ë
+U+b098 na # Character ë
+U+b099 nag # Character ë
+U+b09a nagg # Character ë
+U+b09b nags # Character ë
+U+b09c nan # Character ë
+U+b09d nanj # Character ë
+U+b09e nanh # Character ë
+U+b09f nad # Character ë
+U+b0a0 nal # Character ë
+U+b0a1 nalg # Character ë¡
+U+b0a2 nalm # Character ë¢
+U+b0a3 nalb # Character ë£
+U+b0a4 nals # Character ë¤
+U+b0a5 nalt # Character ë¥
+U+b0a6 nalp # Character ë¦
+U+b0a7 nalh # Character ë§
+U+b0a8 nam # Character ë¨
+U+b0a9 nab # Character ë©
+U+b0aa nabs # Character ëª
+U+b0ab nas # Character ë«
+U+b0ac nass # Character ë¬
+U+b0ad nang # Character ë
+U+b0ae naj # Character ë®
+U+b0af nac # Character ë¯
+U+b0b0 nak # Character ë°
+U+b0b1 nat # Character ë±
+U+b0b2 nap # Character ë²
+U+b0b3 nah # Character ë³
+U+b0b4 nae # Character ë´
+U+b0b5 naeg # Character ëµ
+U+b0b6 naegg # Character ë¶
+U+b0b7 naegs # Character ë·
+U+b0b8 naen # Character ë¸
+U+b0b9 naenj # Character ë¹
+U+b0ba naenh # Character ëº
+U+b0bb naed # Character ë»
+U+b0bc nael # Character ë¼
+U+b0bd naelg # Character ë½
+U+b0be naelm # Character ë¾
+U+b0bf naelb # Character ë¿
+U+b0c0 naels # Character ë
+U+b0c1 naelt # Character ë
+U+b0c2 naelp # Character ë
+U+b0c3 naelh # Character ë
+U+b0c4 naem # Character ë
+U+b0c5 naeb # Character ë
+U+b0c6 naebs # Character ë
+U+b0c7 naes # Character ë
+U+b0c8 naess # Character ë
+U+b0c9 naeng # Character ë
+U+b0ca naej # Character ë
+U+b0cb naec # Character ë
+U+b0cc naek # Character ë
+U+b0cd naet # Character ë
+U+b0ce naep # Character ë
+U+b0cf naeh # Character ë
+U+b0d0 nya # Character ë
+U+b0d1 nyag # Character ë
+U+b0d2 nyagg # Character ë
+U+b0d3 nyags # Character ë
+U+b0d4 nyan # Character ë
+U+b0d5 nyanj # Character ë
+U+b0d6 nyanh # Character ë
+U+b0d7 nyad # Character ë
+U+b0d8 nyal # Character ë
+U+b0d9 nyalg # Character ë
+U+b0da nyalm # Character ë
+U+b0db nyalb # Character ë
+U+b0dc nyals # Character ë
+U+b0dd nyalt # Character ë
+U+b0de nyalp # Character ë
+U+b0df nyalh # Character ë
+U+b0e0 nyam # Character ë
+U+b0e1 nyab # Character ë¡
+U+b0e2 nyabs # Character ë¢
+U+b0e3 nyas # Character ë£
+U+b0e4 nyass # Character ë¤
+U+b0e5 nyang # Character ë¥
+U+b0e6 nyaj # Character ë¦
+U+b0e7 nyac # Character ë§
+U+b0e8 nyak # Character ë¨
+U+b0e9 nyat # Character ë©
+U+b0ea nyap # Character ëª
+U+b0eb nyah # Character ë«
+U+b0ec nyae # Character ë¬
+U+b0ed nyaeg # Character ë
+U+b0ee nyaegg # Character ë®
+U+b0ef nyaegs # Character ë¯
+U+b0f0 nyaen # Character ë°
+U+b0f1 nyaenj # Character ë±
+U+b0f2 nyaenh # Character ë²
+U+b0f3 nyaed # Character ë³
+U+b0f4 nyael # Character ë´
+U+b0f5 nyaelg # Character ëµ
+U+b0f6 nyaelm # Character ë¶
+U+b0f7 nyaelb # Character ë·
+U+b0f8 nyaels # Character ë¸
+U+b0f9 nyaelt # Character ë¹
+U+b0fa nyaelp # Character ëº
+U+b0fb nyaelh # Character ë»
+U+b0fc nyaem # Character ë¼
+U+b0fd nyaeb # Character ë½
+U+b0fe nyaebs # Character ë¾
+U+b0ff nyaes # Character ë¿
diff --git a/resources/chars/ascii/rowb1.trans b/resources/chars/ascii/rowb1.trans
new file mode 100644
index 0000000..67c2a3c
--- /dev/null
+++ b/resources/chars/ascii/rowb1.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+b100 nyaess # Character ë
+U+b101 nyaeng # Character ë
+U+b102 nyaej # Character ë
+U+b103 nyaec # Character ë
+U+b104 nyaek # Character ë
+U+b105 nyaet # Character ë
+U+b106 nyaep # Character ë
+U+b107 nyaeh # Character ë
+U+b108 neo # Character ë
+U+b109 neog # Character ë
+U+b10a neogg # Character ë
+U+b10b neogs # Character ë
+U+b10c neon # Character ë
+U+b10d neonj # Character ë
+U+b10e neonh # Character ë
+U+b10f neod # Character ë
+U+b110 neol # Character ë
+U+b111 neolg # Character ë
+U+b112 neolm # Character ë
+U+b113 neolb # Character ë
+U+b114 neols # Character ë
+U+b115 neolt # Character ë
+U+b116 neolp # Character ë
+U+b117 neolh # Character ë
+U+b118 neom # Character ë
+U+b119 neob # Character ë
+U+b11a neobs # Character ë
+U+b11b neos # Character ë
+U+b11c neoss # Character ë
+U+b11d neong # Character ë
+U+b11e neoj # Character ë
+U+b11f neoc # Character ë
+U+b120 neok # Character ë
+U+b121 neot # Character ë¡
+U+b122 neop # Character ë¢
+U+b123 neoh # Character ë£
+U+b124 ne # Character ë¤
+U+b125 neg # Character ë¥
+U+b126 negg # Character ë¦
+U+b127 negs # Character ë§
+U+b128 nen # Character ë¨
+U+b129 nenj # Character ë©
+U+b12a nenh # Character ëª
+U+b12b ned # Character ë«
+U+b12c nel # Character ë¬
+U+b12d nelg # Character ë
+U+b12e nelm # Character ë®
+U+b12f nelb # Character ë¯
+U+b130 nels # Character ë°
+U+b131 nelt # Character ë±
+U+b132 nelp # Character ë²
+U+b133 nelh # Character ë³
+U+b134 nem # Character ë´
+U+b135 neb # Character ëµ
+U+b136 nebs # Character ë¶
+U+b137 nes # Character ë·
+U+b138 ness # Character ë¸
+U+b139 neng # Character ë¹
+U+b13a nej # Character ëº
+U+b13b nec # Character ë»
+U+b13c nek # Character ë¼
+U+b13d net # Character ë½
+U+b13e nep # Character ë¾
+U+b13f neh # Character ë¿
+U+b140 nyeo # Character ë
+U+b141 nyeog # Character ë
+U+b142 nyeogg # Character ë
+U+b143 nyeogs # Character ë
+U+b144 nyeon # Character ë
+U+b145 nyeonj # Character ë
+U+b146 nyeonh # Character ë
+U+b147 nyeod # Character ë
+U+b148 nyeol # Character ë
+U+b149 nyeolg # Character ë
+U+b14a nyeolm # Character ë
+U+b14b nyeolb # Character ë
+U+b14c nyeols # Character ë
+U+b14d nyeolt # Character ë
+U+b14e nyeolp # Character ë
+U+b14f nyeolh # Character ë
+U+b150 nyeom # Character ë
+U+b151 nyeob # Character ë
+U+b152 nyeobs # Character ë
+U+b153 nyeos # Character ë
+U+b154 nyeoss # Character ë
+U+b155 nyeong # Character ë
+U+b156 nyeoj # Character ë
+U+b157 nyeoc # Character ë
+U+b158 nyeok # Character ë
+U+b159 nyeot # Character ë
+U+b15a nyeop # Character ë
+U+b15b nyeoh # Character ë
+U+b15c nye # Character ë
+U+b15d nyeg # Character ë
+U+b15e nyegg # Character ë
+U+b15f nyegs # Character ë
+U+b160 nyen # Character ë
+U+b161 nyenj # Character ë
¡
+U+b162 nyenh # Character ë
¢
+U+b163 nyed # Character ë
£
+U+b164 nyel # Character ë
¤
+U+b165 nyelg # Character ë
¥
+U+b166 nyelm # Character ë
¦
+U+b167 nyelb # Character ë
§
+U+b168 nyels # Character ë
¨
+U+b169 nyelt # Character ë
©
+U+b16a nyelp # Character ë
ª
+U+b16b nyelh # Character ë
«
+U+b16c nyem # Character ë
¬
+U+b16d nyeb # Character ë
+U+b16e nyebs # Character ë
®
+U+b16f nyes # Character ë
¯
+U+b170 nyess # Character ë
°
+U+b171 nyeng # Character ë
±
+U+b172 nyej # Character ë
²
+U+b173 nyec # Character ë
³
+U+b174 nyek # Character ë
´
+U+b175 nyet # Character ë
µ
+U+b176 nyep # Character ë
¶
+U+b177 nyeh # Character ë
·
+U+b178 no # Character ë
¸
+U+b179 nog # Character ë
¹
+U+b17a nogg # Character ë
º
+U+b17b nogs # Character ë
»
+U+b17c non # Character ë
¼
+U+b17d nonj # Character ë
½
+U+b17e nonh # Character ë
¾
+U+b17f nod # Character ë
¿
+U+b180 nol # Character ë
+U+b181 nolg # Character ë
+U+b182 nolm # Character ë
+U+b183 nolb # Character ë
+U+b184 nols # Character ë
+U+b185 nolt # Character ë
+U+b186 nolp # Character ë
+U+b187 nolh # Character ë
+U+b188 nom # Character ë
+U+b189 nob # Character ë
+U+b18a nobs # Character ë
+U+b18b nos # Character ë
+U+b18c noss # Character ë
+U+b18d nong # Character ë
+U+b18e noj # Character ë
+U+b18f noc # Character ë
+U+b190 nok # Character ë
+U+b191 not # Character ë
+U+b192 nop # Character ë
+U+b193 noh # Character ë
+U+b194 nwa # Character ë
+U+b195 nwag # Character ë
+U+b196 nwagg # Character ë
+U+b197 nwags # Character ë
+U+b198 nwan # Character ë
+U+b199 nwanj # Character ë
+U+b19a nwanh # Character ë
+U+b19b nwad # Character ë
+U+b19c nwal # Character ë
+U+b19d nwalg # Character ë
+U+b19e nwalm # Character ë
+U+b19f nwalb # Character ë
+U+b1a0 nwals # Character ë
+U+b1a1 nwalt # Character ë¡
+U+b1a2 nwalp # Character ë¢
+U+b1a3 nwalh # Character ë£
+U+b1a4 nwam # Character ë¤
+U+b1a5 nwab # Character ë¥
+U+b1a6 nwabs # Character ë¦
+U+b1a7 nwas # Character ë§
+U+b1a8 nwass # Character ë¨
+U+b1a9 nwang # Character ë©
+U+b1aa nwaj # Character ëª
+U+b1ab nwac # Character ë«
+U+b1ac nwak # Character ë¬
+U+b1ad nwat # Character ë
+U+b1ae nwap # Character ë®
+U+b1af nwah # Character ë¯
+U+b1b0 nwae # Character ë°
+U+b1b1 nwaeg # Character ë±
+U+b1b2 nwaegg # Character ë²
+U+b1b3 nwaegs # Character ë³
+U+b1b4 nwaen # Character ë´
+U+b1b5 nwaenj # Character ëµ
+U+b1b6 nwaenh # Character ë¶
+U+b1b7 nwaed # Character ë·
+U+b1b8 nwael # Character ë¸
+U+b1b9 nwaelg # Character ë¹
+U+b1ba nwaelm # Character ëº
+U+b1bb nwaelb # Character ë»
+U+b1bc nwaels # Character ë¼
+U+b1bd nwaelt # Character ë½
+U+b1be nwaelp # Character ë¾
+U+b1bf nwaelh # Character ë¿
+U+b1c0 nwaem # Character ë
+U+b1c1 nwaeb # Character ë
+U+b1c2 nwaebs # Character ë
+U+b1c3 nwaes # Character ë
+U+b1c4 nwaess # Character ë
+U+b1c5 nwaeng # Character ë
+U+b1c6 nwaej # Character ë
+U+b1c7 nwaec # Character ë
+U+b1c8 nwaek # Character ë
+U+b1c9 nwaet # Character ë
+U+b1ca nwaep # Character ë
+U+b1cb nwaeh # Character ë
+U+b1cc noe # Character ë
+U+b1cd noeg # Character ë
+U+b1ce noegg # Character ë
+U+b1cf noegs # Character ë
+U+b1d0 noen # Character ë
+U+b1d1 noenj # Character ë
+U+b1d2 noenh # Character ë
+U+b1d3 noed # Character ë
+U+b1d4 noel # Character ë
+U+b1d5 noelg # Character ë
+U+b1d6 noelm # Character ë
+U+b1d7 noelb # Character ë
+U+b1d8 noels # Character ë
+U+b1d9 noelt # Character ë
+U+b1da noelp # Character ë
+U+b1db noelh # Character ë
+U+b1dc noem # Character ë
+U+b1dd noeb # Character ë
+U+b1de noebs # Character ë
+U+b1df noes # Character ë
+U+b1e0 noess # Character ë
+U+b1e1 noeng # Character ë¡
+U+b1e2 noej # Character ë¢
+U+b1e3 noec # Character ë£
+U+b1e4 noek # Character ë¤
+U+b1e5 noet # Character ë¥
+U+b1e6 noep # Character ë¦
+U+b1e7 noeh # Character ë§
+U+b1e8 nyo # Character ë¨
+U+b1e9 nyog # Character ë©
+U+b1ea nyogg # Character ëª
+U+b1eb nyogs # Character ë«
+U+b1ec nyon # Character ë¬
+U+b1ed nyonj # Character ë
+U+b1ee nyonh # Character ë®
+U+b1ef nyod # Character ë¯
+U+b1f0 nyol # Character ë°
+U+b1f1 nyolg # Character ë±
+U+b1f2 nyolm # Character ë²
+U+b1f3 nyolb # Character ë³
+U+b1f4 nyols # Character ë´
+U+b1f5 nyolt # Character ëµ
+U+b1f6 nyolp # Character ë¶
+U+b1f7 nyolh # Character ë·
+U+b1f8 nyom # Character ë¸
+U+b1f9 nyob # Character ë¹
+U+b1fa nyobs # Character ëº
+U+b1fb nyos # Character ë»
+U+b1fc nyoss # Character ë¼
+U+b1fd nyong # Character ë½
+U+b1fe nyoj # Character ë¾
+U+b1ff nyoc # Character ë¿
diff --git a/resources/chars/ascii/rowb2.trans b/resources/chars/ascii/rowb2.trans
new file mode 100644
index 0000000..d58fc60
--- /dev/null
+++ b/resources/chars/ascii/rowb2.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+b200 nyok # Character ë
+U+b201 nyot # Character ë
+U+b202 nyop # Character ë
+U+b203 nyoh # Character ë
+U+b204 nu # Character ë
+U+b205 nug # Character ë
+U+b206 nugg # Character ë
+U+b207 nugs # Character ë
+U+b208 nun # Character ë
+U+b209 nunj # Character ë
+U+b20a nunh # Character ë
+U+b20b nud # Character ë
+U+b20c nul # Character ë
+U+b20d nulg # Character ë
+U+b20e nulm # Character ë
+U+b20f nulb # Character ë
+U+b210 nuls # Character ë
+U+b211 nult # Character ë
+U+b212 nulp # Character ë
+U+b213 nulh # Character ë
+U+b214 num # Character ë
+U+b215 nub # Character ë
+U+b216 nubs # Character ë
+U+b217 nus # Character ë
+U+b218 nuss # Character ë
+U+b219 nung # Character ë
+U+b21a nuj # Character ë
+U+b21b nuc # Character ë
+U+b21c nuk # Character ë
+U+b21d nut # Character ë
+U+b21e nup # Character ë
+U+b21f nuh # Character ë
+U+b220 nweo # Character ë
+U+b221 nweog # Character ë¡
+U+b222 nweogg # Character ë¢
+U+b223 nweogs # Character ë£
+U+b224 nweon # Character ë¤
+U+b225 nweonj # Character ë¥
+U+b226 nweonh # Character ë¦
+U+b227 nweod # Character ë§
+U+b228 nweol # Character ë¨
+U+b229 nweolg # Character ë©
+U+b22a nweolm # Character ëª
+U+b22b nweolb # Character ë«
+U+b22c nweols # Character ë¬
+U+b22d nweolt # Character ë
+U+b22e nweolp # Character ë®
+U+b22f nweolh # Character ë¯
+U+b230 nweom # Character ë°
+U+b231 nweob # Character ë±
+U+b232 nweobs # Character ë²
+U+b233 nweos # Character ë³
+U+b234 nweoss # Character ë´
+U+b235 nweong # Character ëµ
+U+b236 nweoj # Character ë¶
+U+b237 nweoc # Character ë·
+U+b238 nweok # Character ë¸
+U+b239 nweot # Character ë¹
+U+b23a nweop # Character ëº
+U+b23b nweoh # Character ë»
+U+b23c nwe # Character ë¼
+U+b23d nweg # Character ë½
+U+b23e nwegg # Character ë¾
+U+b23f nwegs # Character ë¿
+U+b240 nwen # Character ë
+U+b241 nwenj # Character ë
+U+b242 nwenh # Character ë
+U+b243 nwed # Character ë
+U+b244 nwel # Character ë
+U+b245 nwelg # Character ë
+U+b246 nwelm # Character ë
+U+b247 nwelb # Character ë
+U+b248 nwels # Character ë
+U+b249 nwelt # Character ë
+U+b24a nwelp # Character ë
+U+b24b nwelh # Character ë
+U+b24c nwem # Character ë
+U+b24d nweb # Character ë
+U+b24e nwebs # Character ë
+U+b24f nwes # Character ë
+U+b250 nwess # Character ë
+U+b251 nweng # Character ë
+U+b252 nwej # Character ë
+U+b253 nwec # Character ë
+U+b254 nwek # Character ë
+U+b255 nwet # Character ë
+U+b256 nwep # Character ë
+U+b257 nweh # Character ë
+U+b258 nwi # Character ë
+U+b259 nwig # Character ë
+U+b25a nwigg # Character ë
+U+b25b nwigs # Character ë
+U+b25c nwin # Character ë
+U+b25d nwinj # Character ë
+U+b25e nwinh # Character ë
+U+b25f nwid # Character ë
+U+b260 nwil # Character ë
+U+b261 nwilg # Character ë¡
+U+b262 nwilm # Character ë¢
+U+b263 nwilb # Character ë£
+U+b264 nwils # Character ë¤
+U+b265 nwilt # Character ë¥
+U+b266 nwilp # Character ë¦
+U+b267 nwilh # Character ë§
+U+b268 nwim # Character ë¨
+U+b269 nwib # Character ë©
+U+b26a nwibs # Character ëª
+U+b26b nwis # Character ë«
+U+b26c nwiss # Character ë¬
+U+b26d nwing # Character ë
+U+b26e nwij # Character ë®
+U+b26f nwic # Character ë¯
+U+b270 nwik # Character ë°
+U+b271 nwit # Character ë±
+U+b272 nwip # Character ë²
+U+b273 nwih # Character ë³
+U+b274 nyu # Character ë´
+U+b275 nyug # Character ëµ
+U+b276 nyugg # Character ë¶
+U+b277 nyugs # Character ë·
+U+b278 nyun # Character ë¸
+U+b279 nyunj # Character ë¹
+U+b27a nyunh # Character ëº
+U+b27b nyud # Character ë»
+U+b27c nyul # Character ë¼
+U+b27d nyulg # Character ë½
+U+b27e nyulm # Character ë¾
+U+b27f nyulb # Character ë¿
+U+b280 nyuls # Character ë
+U+b281 nyult # Character ë
+U+b282 nyulp # Character ë
+U+b283 nyulh # Character ë
+U+b284 nyum # Character ë
+U+b285 nyub # Character ë
+U+b286 nyubs # Character ë
+U+b287 nyus # Character ë
+U+b288 nyuss # Character ë
+U+b289 nyung # Character ë
+U+b28a nyuj # Character ë
+U+b28b nyuc # Character ë
+U+b28c nyuk # Character ë
+U+b28d nyut # Character ë
+U+b28e nyup # Character ë
+U+b28f nyuh # Character ë
+U+b290 neu # Character ë
+U+b291 neug # Character ë
+U+b292 neugg # Character ë
+U+b293 neugs # Character ë
+U+b294 neun # Character ë
+U+b295 neunj # Character ë
+U+b296 neunh # Character ë
+U+b297 neud # Character ë
+U+b298 neul # Character ë
+U+b299 neulg # Character ë
+U+b29a neulm # Character ë
+U+b29b neulb # Character ë
+U+b29c neuls # Character ë
+U+b29d neult # Character ë
+U+b29e neulp # Character ë
+U+b29f neulh # Character ë
+U+b2a0 neum # Character ë
+U+b2a1 neub # Character ë¡
+U+b2a2 neubs # Character ë¢
+U+b2a3 neus # Character ë£
+U+b2a4 neuss # Character ë¤
+U+b2a5 neung # Character ë¥
+U+b2a6 neuj # Character ë¦
+U+b2a7 neuc # Character ë§
+U+b2a8 neuk # Character ë¨
+U+b2a9 neut # Character ë©
+U+b2aa neup # Character ëª
+U+b2ab neuh # Character ë«
+U+b2ac nyi # Character ë¬
+U+b2ad nyig # Character ë
+U+b2ae nyigg # Character ë®
+U+b2af nyigs # Character ë¯
+U+b2b0 nyin # Character ë°
+U+b2b1 nyinj # Character ë±
+U+b2b2 nyinh # Character ë²
+U+b2b3 nyid # Character ë³
+U+b2b4 nyil # Character ë´
+U+b2b5 nyilg # Character ëµ
+U+b2b6 nyilm # Character ë¶
+U+b2b7 nyilb # Character ë·
+U+b2b8 nyils # Character ë¸
+U+b2b9 nyilt # Character ë¹
+U+b2ba nyilp # Character ëº
+U+b2bb nyilh # Character ë»
+U+b2bc nyim # Character ë¼
+U+b2bd nyib # Character ë½
+U+b2be nyibs # Character ë¾
+U+b2bf nyis # Character ë¿
+U+b2c0 nyiss # Character ë
+U+b2c1 nying # Character ë
+U+b2c2 nyij # Character ë
+U+b2c3 nyic # Character ë
+U+b2c4 nyik # Character ë
+U+b2c5 nyit # Character ë
+U+b2c6 nyip # Character ë
+U+b2c7 nyih # Character ë
+U+b2c8 ni # Character ë
+U+b2c9 nig # Character ë
+U+b2ca nigg # Character ë
+U+b2cb nigs # Character ë
+U+b2cc nin # Character ë
+U+b2cd ninj # Character ë
+U+b2ce ninh # Character ë
+U+b2cf nid # Character ë
+U+b2d0 nil # Character ë
+U+b2d1 nilg # Character ë
+U+b2d2 nilm # Character ë
+U+b2d3 nilb # Character ë
+U+b2d4 nils # Character ë
+U+b2d5 nilt # Character ë
+U+b2d6 nilp # Character ë
+U+b2d7 nilh # Character ë
+U+b2d8 nim # Character ë
+U+b2d9 nib # Character ë
+U+b2da nibs # Character ë
+U+b2db nis # Character ë
+U+b2dc niss # Character ë
+U+b2dd ning # Character ë
+U+b2de nij # Character ë
+U+b2df nic # Character ë
+U+b2e0 nik # Character ë
+U+b2e1 nit # Character ë¡
+U+b2e2 nip # Character ë¢
+U+b2e3 nih # Character ë£
+U+b2e4 da # Character ë¤
+U+b2e5 dag # Character ë¥
+U+b2e6 dagg # Character ë¦
+U+b2e7 dags # Character ë§
+U+b2e8 dan # Character ë¨
+U+b2e9 danj # Character ë©
+U+b2ea danh # Character ëª
+U+b2eb dad # Character ë«
+U+b2ec dal # Character ë¬
+U+b2ed dalg # Character ë
+U+b2ee dalm # Character ë®
+U+b2ef dalb # Character ë¯
+U+b2f0 dals # Character ë°
+U+b2f1 dalt # Character ë±
+U+b2f2 dalp # Character ë²
+U+b2f3 dalh # Character ë³
+U+b2f4 dam # Character ë´
+U+b2f5 dab # Character ëµ
+U+b2f6 dabs # Character ë¶
+U+b2f7 das # Character ë·
+U+b2f8 dass # Character ë¸
+U+b2f9 dang # Character ë¹
+U+b2fa daj # Character ëº
+U+b2fb dac # Character ë»
+U+b2fc dak # Character ë¼
+U+b2fd dat # Character ë½
+U+b2fe dap # Character ë¾
+U+b2ff dah # Character ë¿
diff --git a/resources/chars/ascii/rowb3.trans b/resources/chars/ascii/rowb3.trans
new file mode 100644
index 0000000..5e1d6a7
--- /dev/null
+++ b/resources/chars/ascii/rowb3.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+b300 dae # Character ë
+U+b301 daeg # Character ë
+U+b302 daegg # Character ë
+U+b303 daegs # Character ë
+U+b304 daen # Character ë
+U+b305 daenj # Character ë
+U+b306 daenh # Character ë
+U+b307 daed # Character ë
+U+b308 dael # Character ë
+U+b309 daelg # Character ë
+U+b30a daelm # Character ë
+U+b30b daelb # Character ë
+U+b30c daels # Character ë
+U+b30d daelt # Character ë
+U+b30e daelp # Character ë
+U+b30f daelh # Character ë
+U+b310 daem # Character ë
+U+b311 daeb # Character ë
+U+b312 daebs # Character ë
+U+b313 daes # Character ë
+U+b314 daess # Character ë
+U+b315 daeng # Character ë
+U+b316 daej # Character ë
+U+b317 daec # Character ë
+U+b318 daek # Character ë
+U+b319 daet # Character ë
+U+b31a daep # Character ë
+U+b31b daeh # Character ë
+U+b31c dya # Character ë
+U+b31d dyag # Character ë
+U+b31e dyagg # Character ë
+U+b31f dyags # Character ë
+U+b320 dyan # Character ë
+U+b321 dyanj # Character ë¡
+U+b322 dyanh # Character ë¢
+U+b323 dyad # Character ë£
+U+b324 dyal # Character ë¤
+U+b325 dyalg # Character ë¥
+U+b326 dyalm # Character ë¦
+U+b327 dyalb # Character ë§
+U+b328 dyals # Character ë¨
+U+b329 dyalt # Character ë©
+U+b32a dyalp # Character ëª
+U+b32b dyalh # Character ë«
+U+b32c dyam # Character ë¬
+U+b32d dyab # Character ë
+U+b32e dyabs # Character ë®
+U+b32f dyas # Character ë¯
+U+b330 dyass # Character ë°
+U+b331 dyang # Character ë±
+U+b332 dyaj # Character ë²
+U+b333 dyac # Character ë³
+U+b334 dyak # Character ë´
+U+b335 dyat # Character ëµ
+U+b336 dyap # Character ë¶
+U+b337 dyah # Character ë·
+U+b338 dyae # Character ë¸
+U+b339 dyaeg # Character ë¹
+U+b33a dyaegg # Character ëº
+U+b33b dyaegs # Character ë»
+U+b33c dyaen # Character ë¼
+U+b33d dyaenj # Character ë½
+U+b33e dyaenh # Character ë¾
+U+b33f dyaed # Character ë¿
+U+b340 dyael # Character ë
+U+b341 dyaelg # Character ë
+U+b342 dyaelm # Character ë
+U+b343 dyaelb # Character ë
+U+b344 dyaels # Character ë
+U+b345 dyaelt # Character ë
+U+b346 dyaelp # Character ë
+U+b347 dyaelh # Character ë
+U+b348 dyaem # Character ë
+U+b349 dyaeb # Character ë
+U+b34a dyaebs # Character ë
+U+b34b dyaes # Character ë
+U+b34c dyaess # Character ë
+U+b34d dyaeng # Character ë
+U+b34e dyaej # Character ë
+U+b34f dyaec # Character ë
+U+b350 dyaek # Character ë
+U+b351 dyaet # Character ë
+U+b352 dyaep # Character ë
+U+b353 dyaeh # Character ë
+U+b354 deo # Character ë
+U+b355 deog # Character ë
+U+b356 deogg # Character ë
+U+b357 deogs # Character ë
+U+b358 deon # Character ë
+U+b359 deonj # Character ë
+U+b35a deonh # Character ë
+U+b35b deod # Character ë
+U+b35c deol # Character ë
+U+b35d deolg # Character ë
+U+b35e deolm # Character ë
+U+b35f deolb # Character ë
+U+b360 deols # Character ë
+U+b361 deolt # Character ë¡
+U+b362 deolp # Character ë¢
+U+b363 deolh # Character ë£
+U+b364 deom # Character ë¤
+U+b365 deob # Character ë¥
+U+b366 deobs # Character ë¦
+U+b367 deos # Character ë§
+U+b368 deoss # Character ë¨
+U+b369 deong # Character ë©
+U+b36a deoj # Character ëª
+U+b36b deoc # Character ë«
+U+b36c deok # Character ë¬
+U+b36d deot # Character ë
+U+b36e deop # Character ë®
+U+b36f deoh # Character ë¯
+U+b370 de # Character ë°
+U+b371 deg # Character ë±
+U+b372 degg # Character ë²
+U+b373 degs # Character ë³
+U+b374 den # Character ë´
+U+b375 denj # Character ëµ
+U+b376 denh # Character ë¶
+U+b377 ded # Character ë·
+U+b378 del # Character ë¸
+U+b379 delg # Character ë¹
+U+b37a delm # Character ëº
+U+b37b delb # Character ë»
+U+b37c dels # Character ë¼
+U+b37d delt # Character ë½
+U+b37e delp # Character ë¾
+U+b37f delh # Character ë¿
+U+b380 dem # Character ë
+U+b381 deb # Character ë
+U+b382 debs # Character ë
+U+b383 des # Character ë
+U+b384 dess # Character ë
+U+b385 deng # Character ë
+U+b386 dej # Character ë
+U+b387 dec # Character ë
+U+b388 dek # Character ë
+U+b389 det # Character ë
+U+b38a dep # Character ë
+U+b38b deh # Character ë
+U+b38c dyeo # Character ë
+U+b38d dyeog # Character ë
+U+b38e dyeogg # Character ë
+U+b38f dyeogs # Character ë
+U+b390 dyeon # Character ë
+U+b391 dyeonj # Character ë
+U+b392 dyeonh # Character ë
+U+b393 dyeod # Character ë
+U+b394 dyeol # Character ë
+U+b395 dyeolg # Character ë
+U+b396 dyeolm # Character ë
+U+b397 dyeolb # Character ë
+U+b398 dyeols # Character ë
+U+b399 dyeolt # Character ë
+U+b39a dyeolp # Character ë
+U+b39b dyeolh # Character ë
+U+b39c dyeom # Character ë
+U+b39d dyeob # Character ë
+U+b39e dyeobs # Character ë
+U+b39f dyeos # Character ë
+U+b3a0 dyeoss # Character ë
+U+b3a1 dyeong # Character ë¡
+U+b3a2 dyeoj # Character ë¢
+U+b3a3 dyeoc # Character ë£
+U+b3a4 dyeok # Character ë¤
+U+b3a5 dyeot # Character ë¥
+U+b3a6 dyeop # Character ë¦
+U+b3a7 dyeoh # Character ë§
+U+b3a8 dye # Character ë¨
+U+b3a9 dyeg # Character ë©
+U+b3aa dyegg # Character ëª
+U+b3ab dyegs # Character ë«
+U+b3ac dyen # Character ë¬
+U+b3ad dyenj # Character ë
+U+b3ae dyenh # Character ë®
+U+b3af dyed # Character ë¯
+U+b3b0 dyel # Character ë°
+U+b3b1 dyelg # Character ë±
+U+b3b2 dyelm # Character ë²
+U+b3b3 dyelb # Character ë³
+U+b3b4 dyels # Character ë´
+U+b3b5 dyelt # Character ëµ
+U+b3b6 dyelp # Character ë¶
+U+b3b7 dyelh # Character ë·
+U+b3b8 dyem # Character ë¸
+U+b3b9 dyeb # Character ë¹
+U+b3ba dyebs # Character ëº
+U+b3bb dyes # Character ë»
+U+b3bc dyess # Character ë¼
+U+b3bd dyeng # Character ë½
+U+b3be dyej # Character ë¾
+U+b3bf dyec # Character ë¿
+U+b3c0 dyek # Character ë
+U+b3c1 dyet # Character ë
+U+b3c2 dyep # Character ë
+U+b3c3 dyeh # Character ë
+U+b3c4 do # Character ë
+U+b3c5 dog # Character ë
+U+b3c6 dogg # Character ë
+U+b3c7 dogs # Character ë
+U+b3c8 don # Character ë
+U+b3c9 donj # Character ë
+U+b3ca donh # Character ë
+U+b3cb dod # Character ë
+U+b3cc dol # Character ë
+U+b3cd dolg # Character ë
+U+b3ce dolm # Character ë
+U+b3cf dolb # Character ë
+U+b3d0 dols # Character ë
+U+b3d1 dolt # Character ë
+U+b3d2 dolp # Character ë
+U+b3d3 dolh # Character ë
+U+b3d4 dom # Character ë
+U+b3d5 dob # Character ë
+U+b3d6 dobs # Character ë
+U+b3d7 dos # Character ë
+U+b3d8 doss # Character ë
+U+b3d9 dong # Character ë
+U+b3da doj # Character ë
+U+b3db doc # Character ë
+U+b3dc dok # Character ë
+U+b3dd dot # Character ë
+U+b3de dop # Character ë
+U+b3df doh # Character ë
+U+b3e0 dwa # Character ë
+U+b3e1 dwag # Character ë¡
+U+b3e2 dwagg # Character ë¢
+U+b3e3 dwags # Character ë£
+U+b3e4 dwan # Character ë¤
+U+b3e5 dwanj # Character ë¥
+U+b3e6 dwanh # Character ë¦
+U+b3e7 dwad # Character ë§
+U+b3e8 dwal # Character ë¨
+U+b3e9 dwalg # Character ë©
+U+b3ea dwalm # Character ëª
+U+b3eb dwalb # Character ë«
+U+b3ec dwals # Character ë¬
+U+b3ed dwalt # Character ë
+U+b3ee dwalp # Character ë®
+U+b3ef dwalh # Character ë¯
+U+b3f0 dwam # Character ë°
+U+b3f1 dwab # Character ë±
+U+b3f2 dwabs # Character ë²
+U+b3f3 dwas # Character ë³
+U+b3f4 dwass # Character ë´
+U+b3f5 dwang # Character ëµ
+U+b3f6 dwaj # Character ë¶
+U+b3f7 dwac # Character ë·
+U+b3f8 dwak # Character ë¸
+U+b3f9 dwat # Character ë¹
+U+b3fa dwap # Character ëº
+U+b3fb dwah # Character ë»
+U+b3fc dwae # Character ë¼
+U+b3fd dwaeg # Character ë½
+U+b3fe dwaegg # Character ë¾
+U+b3ff dwaegs # Character ë¿
diff --git a/resources/chars/ascii/rowb4.trans b/resources/chars/ascii/rowb4.trans
new file mode 100644
index 0000000..b693368
--- /dev/null
+++ b/resources/chars/ascii/rowb4.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+b400 dwaen # Character ë
+U+b401 dwaenj # Character ë
+U+b402 dwaenh # Character ë
+U+b403 dwaed # Character ë
+U+b404 dwael # Character ë
+U+b405 dwaelg # Character ë
+U+b406 dwaelm # Character ë
+U+b407 dwaelb # Character ë
+U+b408 dwaels # Character ë
+U+b409 dwaelt # Character ë
+U+b40a dwaelp # Character ë
+U+b40b dwaelh # Character ë
+U+b40c dwaem # Character ë
+U+b40d dwaeb # Character ë
+U+b40e dwaebs # Character ë
+U+b40f dwaes # Character ë
+U+b410 dwaess # Character ë
+U+b411 dwaeng # Character ë
+U+b412 dwaej # Character ë
+U+b413 dwaec # Character ë
+U+b414 dwaek # Character ë
+U+b415 dwaet # Character ë
+U+b416 dwaep # Character ë
+U+b417 dwaeh # Character ë
+U+b418 doe # Character ë
+U+b419 doeg # Character ë
+U+b41a doegg # Character ë
+U+b41b doegs # Character ë
+U+b41c doen # Character ë
+U+b41d doenj # Character ë
+U+b41e doenh # Character ë
+U+b41f doed # Character ë
+U+b420 doel # Character ë
+U+b421 doelg # Character ë¡
+U+b422 doelm # Character ë¢
+U+b423 doelb # Character ë£
+U+b424 doels # Character ë¤
+U+b425 doelt # Character ë¥
+U+b426 doelp # Character ë¦
+U+b427 doelh # Character ë§
+U+b428 doem # Character ë¨
+U+b429 doeb # Character ë©
+U+b42a doebs # Character ëª
+U+b42b does # Character ë«
+U+b42c doess # Character ë¬
+U+b42d doeng # Character ë
+U+b42e doej # Character ë®
+U+b42f doec # Character ë¯
+U+b430 doek # Character ë°
+U+b431 doet # Character ë±
+U+b432 doep # Character ë²
+U+b433 doeh # Character ë³
+U+b434 dyo # Character ë´
+U+b435 dyog # Character ëµ
+U+b436 dyogg # Character ë¶
+U+b437 dyogs # Character ë·
+U+b438 dyon # Character ë¸
+U+b439 dyonj # Character ë¹
+U+b43a dyonh # Character ëº
+U+b43b dyod # Character ë»
+U+b43c dyol # Character ë¼
+U+b43d dyolg # Character ë½
+U+b43e dyolm # Character ë¾
+U+b43f dyolb # Character ë¿
+U+b440 dyols # Character ë
+U+b441 dyolt # Character ë
+U+b442 dyolp # Character ë
+U+b443 dyolh # Character ë
+U+b444 dyom # Character ë
+U+b445 dyob # Character ë
+U+b446 dyobs # Character ë
+U+b447 dyos # Character ë
+U+b448 dyoss # Character ë
+U+b449 dyong # Character ë
+U+b44a dyoj # Character ë
+U+b44b dyoc # Character ë
+U+b44c dyok # Character ë
+U+b44d dyot # Character ë
+U+b44e dyop # Character ë
+U+b44f dyoh # Character ë
+U+b450 du # Character ë
+U+b451 dug # Character ë
+U+b452 dugg # Character ë
+U+b453 dugs # Character ë
+U+b454 dun # Character ë
+U+b455 dunj # Character ë
+U+b456 dunh # Character ë
+U+b457 dud # Character ë
+U+b458 dul # Character ë
+U+b459 dulg # Character ë
+U+b45a dulm # Character ë
+U+b45b dulb # Character ë
+U+b45c duls # Character ë
+U+b45d dult # Character ë
+U+b45e dulp # Character ë
+U+b45f dulh # Character ë
+U+b460 dum # Character ë
+U+b461 dub # Character ë¡
+U+b462 dubs # Character ë¢
+U+b463 dus # Character ë£
+U+b464 duss # Character ë¤
+U+b465 dung # Character ë¥
+U+b466 duj # Character ë¦
+U+b467 duc # Character ë§
+U+b468 duk # Character ë¨
+U+b469 dut # Character ë©
+U+b46a dup # Character ëª
+U+b46b duh # Character ë«
+U+b46c dweo # Character ë¬
+U+b46d dweog # Character ë
+U+b46e dweogg # Character ë®
+U+b46f dweogs # Character ë¯
+U+b470 dweon # Character ë°
+U+b471 dweonj # Character ë±
+U+b472 dweonh # Character ë²
+U+b473 dweod # Character ë³
+U+b474 dweol # Character ë´
+U+b475 dweolg # Character ëµ
+U+b476 dweolm # Character ë¶
+U+b477 dweolb # Character ë·
+U+b478 dweols # Character ë¸
+U+b479 dweolt # Character ë¹
+U+b47a dweolp # Character ëº
+U+b47b dweolh # Character ë»
+U+b47c dweom # Character ë¼
+U+b47d dweob # Character ë½
+U+b47e dweobs # Character ë¾
+U+b47f dweos # Character ë¿
+U+b480 dweoss # Character ë
+U+b481 dweong # Character ë
+U+b482 dweoj # Character ë
+U+b483 dweoc # Character ë
+U+b484 dweok # Character ë
+U+b485 dweot # Character ë
+U+b486 dweop # Character ë
+U+b487 dweoh # Character ë
+U+b488 dwe # Character ë
+U+b489 dweg # Character ë
+U+b48a dwegg # Character ë
+U+b48b dwegs # Character ë
+U+b48c dwen # Character ë
+U+b48d dwenj # Character ë
+U+b48e dwenh # Character ë
+U+b48f dwed # Character ë
+U+b490 dwel # Character ë
+U+b491 dwelg # Character ë
+U+b492 dwelm # Character ë
+U+b493 dwelb # Character ë
+U+b494 dwels # Character ë
+U+b495 dwelt # Character ë
+U+b496 dwelp # Character ë
+U+b497 dwelh # Character ë
+U+b498 dwem # Character ë
+U+b499 dweb # Character ë
+U+b49a dwebs # Character ë
+U+b49b dwes # Character ë
+U+b49c dwess # Character ë
+U+b49d dweng # Character ë
+U+b49e dwej # Character ë
+U+b49f dwec # Character ë
+U+b4a0 dwek # Character ë
+U+b4a1 dwet # Character ë¡
+U+b4a2 dwep # Character ë¢
+U+b4a3 dweh # Character ë£
+U+b4a4 dwi # Character ë¤
+U+b4a5 dwig # Character ë¥
+U+b4a6 dwigg # Character ë¦
+U+b4a7 dwigs # Character ë§
+U+b4a8 dwin # Character ë¨
+U+b4a9 dwinj # Character ë©
+U+b4aa dwinh # Character ëª
+U+b4ab dwid # Character ë«
+U+b4ac dwil # Character ë¬
+U+b4ad dwilg # Character ë
+U+b4ae dwilm # Character ë®
+U+b4af dwilb # Character ë¯
+U+b4b0 dwils # Character ë°
+U+b4b1 dwilt # Character ë±
+U+b4b2 dwilp # Character ë²
+U+b4b3 dwilh # Character ë³
+U+b4b4 dwim # Character ë´
+U+b4b5 dwib # Character ëµ
+U+b4b6 dwibs # Character ë¶
+U+b4b7 dwis # Character ë·
+U+b4b8 dwiss # Character ë¸
+U+b4b9 dwing # Character ë¹
+U+b4ba dwij # Character ëº
+U+b4bb dwic # Character ë»
+U+b4bc dwik # Character ë¼
+U+b4bd dwit # Character ë½
+U+b4be dwip # Character ë¾
+U+b4bf dwih # Character ë¿
+U+b4c0 dyu # Character ë
+U+b4c1 dyug # Character ë
+U+b4c2 dyugg # Character ë
+U+b4c3 dyugs # Character ë
+U+b4c4 dyun # Character ë
+U+b4c5 dyunj # Character ë
+U+b4c6 dyunh # Character ë
+U+b4c7 dyud # Character ë
+U+b4c8 dyul # Character ë
+U+b4c9 dyulg # Character ë
+U+b4ca dyulm # Character ë
+U+b4cb dyulb # Character ë
+U+b4cc dyuls # Character ë
+U+b4cd dyult # Character ë
+U+b4ce dyulp # Character ë
+U+b4cf dyulh # Character ë
+U+b4d0 dyum # Character ë
+U+b4d1 dyub # Character ë
+U+b4d2 dyubs # Character ë
+U+b4d3 dyus # Character ë
+U+b4d4 dyuss # Character ë
+U+b4d5 dyung # Character ë
+U+b4d6 dyuj # Character ë
+U+b4d7 dyuc # Character ë
+U+b4d8 dyuk # Character ë
+U+b4d9 dyut # Character ë
+U+b4da dyup # Character ë
+U+b4db dyuh # Character ë
+U+b4dc deu # Character ë
+U+b4dd deug # Character ë
+U+b4de deugg # Character ë
+U+b4df deugs # Character ë
+U+b4e0 deun # Character ë
+U+b4e1 deunj # Character ë¡
+U+b4e2 deunh # Character ë¢
+U+b4e3 deud # Character ë£
+U+b4e4 deul # Character ë¤
+U+b4e5 deulg # Character ë¥
+U+b4e6 deulm # Character ë¦
+U+b4e7 deulb # Character ë§
+U+b4e8 deuls # Character ë¨
+U+b4e9 deult # Character ë©
+U+b4ea deulp # Character ëª
+U+b4eb deulh # Character ë«
+U+b4ec deum # Character ë¬
+U+b4ed deub # Character ë
+U+b4ee deubs # Character ë®
+U+b4ef deus # Character ë¯
+U+b4f0 deuss # Character ë°
+U+b4f1 deung # Character ë±
+U+b4f2 deuj # Character ë²
+U+b4f3 deuc # Character ë³
+U+b4f4 deuk # Character ë´
+U+b4f5 deut # Character ëµ
+U+b4f6 deup # Character ë¶
+U+b4f7 deuh # Character ë·
+U+b4f8 dyi # Character ë¸
+U+b4f9 dyig # Character ë¹
+U+b4fa dyigg # Character ëº
+U+b4fb dyigs # Character ë»
+U+b4fc dyin # Character ë¼
+U+b4fd dyinj # Character ë½
+U+b4fe dyinh # Character ë¾
+U+b4ff dyid # Character ë¿
diff --git a/resources/chars/ascii/rowb5.trans b/resources/chars/ascii/rowb5.trans
new file mode 100644
index 0000000..eb582af
--- /dev/null
+++ b/resources/chars/ascii/rowb5.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+b500 dyil # Character ë
+U+b501 dyilg # Character ë
+U+b502 dyilm # Character ë
+U+b503 dyilb # Character ë
+U+b504 dyils # Character ë
+U+b505 dyilt # Character ë
+U+b506 dyilp # Character ë
+U+b507 dyilh # Character ë
+U+b508 dyim # Character ë
+U+b509 dyib # Character ë
+U+b50a dyibs # Character ë
+U+b50b dyis # Character ë
+U+b50c dyiss # Character ë
+U+b50d dying # Character ë
+U+b50e dyij # Character ë
+U+b50f dyic # Character ë
+U+b510 dyik # Character ë
+U+b511 dyit # Character ë
+U+b512 dyip # Character ë
+U+b513 dyih # Character ë
+U+b514 di # Character ë
+U+b515 dig # Character ë
+U+b516 digg # Character ë
+U+b517 digs # Character ë
+U+b518 din # Character ë
+U+b519 dinj # Character ë
+U+b51a dinh # Character ë
+U+b51b did # Character ë
+U+b51c dil # Character ë
+U+b51d dilg # Character ë
+U+b51e dilm # Character ë
+U+b51f dilb # Character ë
+U+b520 dils # Character ë
+U+b521 dilt # Character ë¡
+U+b522 dilp # Character ë¢
+U+b523 dilh # Character ë£
+U+b524 dim # Character ë¤
+U+b525 dib # Character ë¥
+U+b526 dibs # Character ë¦
+U+b527 dis # Character ë§
+U+b528 diss # Character ë¨
+U+b529 ding # Character ë©
+U+b52a dij # Character ëª
+U+b52b dic # Character ë«
+U+b52c dik # Character ë¬
+U+b52d dit # Character ë
+U+b52e dip # Character ë®
+U+b52f dih # Character ë¯
+U+b530 dda # Character ë°
+U+b531 ddag # Character ë±
+U+b532 ddagg # Character ë²
+U+b533 ddags # Character ë³
+U+b534 ddan # Character ë´
+U+b535 ddanj # Character ëµ
+U+b536 ddanh # Character ë¶
+U+b537 ddad # Character ë·
+U+b538 ddal # Character ë¸
+U+b539 ddalg # Character ë¹
+U+b53a ddalm # Character ëº
+U+b53b ddalb # Character ë»
+U+b53c ddals # Character ë¼
+U+b53d ddalt # Character ë½
+U+b53e ddalp # Character ë¾
+U+b53f ddalh # Character ë¿
+U+b540 ddam # Character ë
+U+b541 ddab # Character ë
+U+b542 ddabs # Character ë
+U+b543 ddas # Character ë
+U+b544 ddass # Character ë
+U+b545 ddang # Character ë
+U+b546 ddaj # Character ë
+U+b547 ddac # Character ë
+U+b548 ddak # Character ë
+U+b549 ddat # Character ë
+U+b54a ddap # Character ë
+U+b54b ddah # Character ë
+U+b54c ddae # Character ë
+U+b54d ddaeg # Character ë
+U+b54e ddaegg # Character ë
+U+b54f ddaegs # Character ë
+U+b550 ddaen # Character ë
+U+b551 ddaenj # Character ë
+U+b552 ddaenh # Character ë
+U+b553 ddaed # Character ë
+U+b554 ddael # Character ë
+U+b555 ddaelg # Character ë
+U+b556 ddaelm # Character ë
+U+b557 ddaelb # Character ë
+U+b558 ddaels # Character ë
+U+b559 ddaelt # Character ë
+U+b55a ddaelp # Character ë
+U+b55b ddaelh # Character ë
+U+b55c ddaem # Character ë
+U+b55d ddaeb # Character ë
+U+b55e ddaebs # Character ë
+U+b55f ddaes # Character ë
+U+b560 ddaess # Character ë
+U+b561 ddaeng # Character ë¡
+U+b562 ddaej # Character ë¢
+U+b563 ddaec # Character ë£
+U+b564 ddaek # Character ë¤
+U+b565 ddaet # Character ë¥
+U+b566 ddaep # Character ë¦
+U+b567 ddaeh # Character ë§
+U+b568 ddya # Character ë¨
+U+b569 ddyag # Character ë©
+U+b56a ddyagg # Character ëª
+U+b56b ddyags # Character ë«
+U+b56c ddyan # Character ë¬
+U+b56d ddyanj # Character ë
+U+b56e ddyanh # Character ë®
+U+b56f ddyad # Character ë¯
+U+b570 ddyal # Character ë°
+U+b571 ddyalg # Character ë±
+U+b572 ddyalm # Character ë²
+U+b573 ddyalb # Character ë³
+U+b574 ddyals # Character ë´
+U+b575 ddyalt # Character ëµ
+U+b576 ddyalp # Character ë¶
+U+b577 ddyalh # Character ë·
+U+b578 ddyam # Character ë¸
+U+b579 ddyab # Character ë¹
+U+b57a ddyabs # Character ëº
+U+b57b ddyas # Character ë»
+U+b57c ddyass # Character ë¼
+U+b57d ddyang # Character ë½
+U+b57e ddyaj # Character ë¾
+U+b57f ddyac # Character ë¿
+U+b580 ddyak # Character ë
+U+b581 ddyat # Character ë
+U+b582 ddyap # Character ë
+U+b583 ddyah # Character ë
+U+b584 ddyae # Character ë
+U+b585 ddyaeg # Character ë
+U+b586 ddyaegg # Character ë
+U+b587 ddyaegs # Character ë
+U+b588 ddyaen # Character ë
+U+b589 ddyaenj # Character ë
+U+b58a ddyaenh # Character ë
+U+b58b ddyaed # Character ë
+U+b58c ddyael # Character ë
+U+b58d ddyaelg # Character ë
+U+b58e ddyaelm # Character ë
+U+b58f ddyaelb # Character ë
+U+b590 ddyaels # Character ë
+U+b591 ddyaelt # Character ë
+U+b592 ddyaelp # Character ë
+U+b593 ddyaelh # Character ë
+U+b594 ddyaem # Character ë
+U+b595 ddyaeb # Character ë
+U+b596 ddyaebs # Character ë
+U+b597 ddyaes # Character ë
+U+b598 ddyaess # Character ë
+U+b599 ddyaeng # Character ë
+U+b59a ddyaej # Character ë
+U+b59b ddyaec # Character ë
+U+b59c ddyaek # Character ë
+U+b59d ddyaet # Character ë
+U+b59e ddyaep # Character ë
+U+b59f ddyaeh # Character ë
+U+b5a0 ddeo # Character ë
+U+b5a1 ddeog # Character ë¡
+U+b5a2 ddeogg # Character ë¢
+U+b5a3 ddeogs # Character ë£
+U+b5a4 ddeon # Character ë¤
+U+b5a5 ddeonj # Character ë¥
+U+b5a6 ddeonh # Character ë¦
+U+b5a7 ddeod # Character ë§
+U+b5a8 ddeol # Character ë¨
+U+b5a9 ddeolg # Character ë©
+U+b5aa ddeolm # Character ëª
+U+b5ab ddeolb # Character ë«
+U+b5ac ddeols # Character ë¬
+U+b5ad ddeolt # Character ë
+U+b5ae ddeolp # Character ë®
+U+b5af ddeolh # Character ë¯
+U+b5b0 ddeom # Character ë°
+U+b5b1 ddeob # Character ë±
+U+b5b2 ddeobs # Character ë²
+U+b5b3 ddeos # Character ë³
+U+b5b4 ddeoss # Character ë´
+U+b5b5 ddeong # Character ëµ
+U+b5b6 ddeoj # Character ë¶
+U+b5b7 ddeoc # Character ë·
+U+b5b8 ddeok # Character ë¸
+U+b5b9 ddeot # Character ë¹
+U+b5ba ddeop # Character ëº
+U+b5bb ddeoh # Character ë»
+U+b5bc dde # Character ë¼
+U+b5bd ddeg # Character ë½
+U+b5be ddegg # Character ë¾
+U+b5bf ddegs # Character ë¿
+U+b5c0 dden # Character ë
+U+b5c1 ddenj # Character ë
+U+b5c2 ddenh # Character ë
+U+b5c3 dded # Character ë
+U+b5c4 ddel # Character ë
+U+b5c5 ddelg # Character ë
+U+b5c6 ddelm # Character ë
+U+b5c7 ddelb # Character ë
+U+b5c8 ddels # Character ë
+U+b5c9 ddelt # Character ë
+U+b5ca ddelp # Character ë
+U+b5cb ddelh # Character ë
+U+b5cc ddem # Character ë
+U+b5cd ddeb # Character ë
+U+b5ce ddebs # Character ë
+U+b5cf ddes # Character ë
+U+b5d0 ddess # Character ë
+U+b5d1 ddeng # Character ë
+U+b5d2 ddej # Character ë
+U+b5d3 ddec # Character ë
+U+b5d4 ddek # Character ë
+U+b5d5 ddet # Character ë
+U+b5d6 ddep # Character ë
+U+b5d7 ddeh # Character ë
+U+b5d8 ddyeo # Character ë
+U+b5d9 ddyeog # Character ë
+U+b5da ddyeogg # Character ë
+U+b5db ddyeogs # Character ë
+U+b5dc ddyeon # Character ë
+U+b5dd ddyeonj # Character ë
+U+b5de ddyeonh # Character ë
+U+b5df ddyeod # Character ë
+U+b5e0 ddyeol # Character ë
+U+b5e1 ddyeolg # Character ë¡
+U+b5e2 ddyeolm # Character ë¢
+U+b5e3 ddyeolb # Character ë£
+U+b5e4 ddyeols # Character ë¤
+U+b5e5 ddyeolt # Character ë¥
+U+b5e6 ddyeolp # Character ë¦
+U+b5e7 ddyeolh # Character ë§
+U+b5e8 ddyeom # Character ë¨
+U+b5e9 ddyeob # Character ë©
+U+b5ea ddyeobs # Character ëª
+U+b5eb ddyeos # Character ë«
+U+b5ec ddyeoss # Character ë¬
+U+b5ed ddyeong # Character ë
+U+b5ee ddyeoj # Character ë®
+U+b5ef ddyeoc # Character ë¯
+U+b5f0 ddyeok # Character ë°
+U+b5f1 ddyeot # Character ë±
+U+b5f2 ddyeop # Character ë²
+U+b5f3 ddyeoh # Character ë³
+U+b5f4 ddye # Character ë´
+U+b5f5 ddyeg # Character ëµ
+U+b5f6 ddyegg # Character ë¶
+U+b5f7 ddyegs # Character ë·
+U+b5f8 ddyen # Character ë¸
+U+b5f9 ddyenj # Character ë¹
+U+b5fa ddyenh # Character ëº
+U+b5fb ddyed # Character ë»
+U+b5fc ddyel # Character ë¼
+U+b5fd ddyelg # Character ë½
+U+b5fe ddyelm # Character ë¾
+U+b5ff ddyelb # Character ë¿
diff --git a/resources/chars/ascii/rowb6.trans b/resources/chars/ascii/rowb6.trans
new file mode 100644
index 0000000..75c724e
--- /dev/null
+++ b/resources/chars/ascii/rowb6.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+b600 ddyels # Character ë
+U+b601 ddyelt # Character ë
+U+b602 ddyelp # Character ë
+U+b603 ddyelh # Character ë
+U+b604 ddyem # Character ë
+U+b605 ddyeb # Character ë
+U+b606 ddyebs # Character ë
+U+b607 ddyes # Character ë
+U+b608 ddyess # Character ë
+U+b609 ddyeng # Character ë
+U+b60a ddyej # Character ë
+U+b60b ddyec # Character ë
+U+b60c ddyek # Character ë
+U+b60d ddyet # Character ë
+U+b60e ddyep # Character ë
+U+b60f ddyeh # Character ë
+U+b610 ddo # Character ë
+U+b611 ddog # Character ë
+U+b612 ddogg # Character ë
+U+b613 ddogs # Character ë
+U+b614 ddon # Character ë
+U+b615 ddonj # Character ë
+U+b616 ddonh # Character ë
+U+b617 ddod # Character ë
+U+b618 ddol # Character ë
+U+b619 ddolg # Character ë
+U+b61a ddolm # Character ë
+U+b61b ddolb # Character ë
+U+b61c ddols # Character ë
+U+b61d ddolt # Character ë
+U+b61e ddolp # Character ë
+U+b61f ddolh # Character ë
+U+b620 ddom # Character ë
+U+b621 ddob # Character ë¡
+U+b622 ddobs # Character ë¢
+U+b623 ddos # Character ë£
+U+b624 ddoss # Character ë¤
+U+b625 ddong # Character ë¥
+U+b626 ddoj # Character ë¦
+U+b627 ddoc # Character ë§
+U+b628 ddok # Character ë¨
+U+b629 ddot # Character ë©
+U+b62a ddop # Character ëª
+U+b62b ddoh # Character ë«
+U+b62c ddwa # Character ë¬
+U+b62d ddwag # Character ë
+U+b62e ddwagg # Character ë®
+U+b62f ddwags # Character ë¯
+U+b630 ddwan # Character ë°
+U+b631 ddwanj # Character ë±
+U+b632 ddwanh # Character ë²
+U+b633 ddwad # Character ë³
+U+b634 ddwal # Character ë´
+U+b635 ddwalg # Character ëµ
+U+b636 ddwalm # Character ë¶
+U+b637 ddwalb # Character ë·
+U+b638 ddwals # Character ë¸
+U+b639 ddwalt # Character ë¹
+U+b63a ddwalp # Character ëº
+U+b63b ddwalh # Character ë»
+U+b63c ddwam # Character ë¼
+U+b63d ddwab # Character ë½
+U+b63e ddwabs # Character ë¾
+U+b63f ddwas # Character ë¿
+U+b640 ddwass # Character ë
+U+b641 ddwang # Character ë
+U+b642 ddwaj # Character ë
+U+b643 ddwac # Character ë
+U+b644 ddwak # Character ë
+U+b645 ddwat # Character ë
+U+b646 ddwap # Character ë
+U+b647 ddwah # Character ë
+U+b648 ddwae # Character ë
+U+b649 ddwaeg # Character ë
+U+b64a ddwaegg # Character ë
+U+b64b ddwaegs # Character ë
+U+b64c ddwaen # Character ë
+U+b64d ddwaenj # Character ë
+U+b64e ddwaenh # Character ë
+U+b64f ddwaed # Character ë
+U+b650 ddwael # Character ë
+U+b651 ddwaelg # Character ë
+U+b652 ddwaelm # Character ë
+U+b653 ddwaelb # Character ë
+U+b654 ddwaels # Character ë
+U+b655 ddwaelt # Character ë
+U+b656 ddwaelp # Character ë
+U+b657 ddwaelh # Character ë
+U+b658 ddwaem # Character ë
+U+b659 ddwaeb # Character ë
+U+b65a ddwaebs # Character ë
+U+b65b ddwaes # Character ë
+U+b65c ddwaess # Character ë
+U+b65d ddwaeng # Character ë
+U+b65e ddwaej # Character ë
+U+b65f ddwaec # Character ë
+U+b660 ddwaek # Character ë
+U+b661 ddwaet # Character ë¡
+U+b662 ddwaep # Character ë¢
+U+b663 ddwaeh # Character ë£
+U+b664 ddoe # Character ë¤
+U+b665 ddoeg # Character ë¥
+U+b666 ddoegg # Character ë¦
+U+b667 ddoegs # Character ë§
+U+b668 ddoen # Character ë¨
+U+b669 ddoenj # Character ë©
+U+b66a ddoenh # Character ëª
+U+b66b ddoed # Character ë«
+U+b66c ddoel # Character ë¬
+U+b66d ddoelg # Character ë
+U+b66e ddoelm # Character ë®
+U+b66f ddoelb # Character ë¯
+U+b670 ddoels # Character ë°
+U+b671 ddoelt # Character ë±
+U+b672 ddoelp # Character ë²
+U+b673 ddoelh # Character ë³
+U+b674 ddoem # Character ë´
+U+b675 ddoeb # Character ëµ
+U+b676 ddoebs # Character ë¶
+U+b677 ddoes # Character ë·
+U+b678 ddoess # Character ë¸
+U+b679 ddoeng # Character ë¹
+U+b67a ddoej # Character ëº
+U+b67b ddoec # Character ë»
+U+b67c ddoek # Character ë¼
+U+b67d ddoet # Character ë½
+U+b67e ddoep # Character ë¾
+U+b67f ddoeh # Character ë¿
+U+b680 ddyo # Character ë
+U+b681 ddyog # Character ë
+U+b682 ddyogg # Character ë
+U+b683 ddyogs # Character ë
+U+b684 ddyon # Character ë
+U+b685 ddyonj # Character ë
+U+b686 ddyonh # Character ë
+U+b687 ddyod # Character ë
+U+b688 ddyol # Character ë
+U+b689 ddyolg # Character ë
+U+b68a ddyolm # Character ë
+U+b68b ddyolb # Character ë
+U+b68c ddyols # Character ë
+U+b68d ddyolt # Character ë
+U+b68e ddyolp # Character ë
+U+b68f ddyolh # Character ë
+U+b690 ddyom # Character ë
+U+b691 ddyob # Character ë
+U+b692 ddyobs # Character ë
+U+b693 ddyos # Character ë
+U+b694 ddyoss # Character ë
+U+b695 ddyong # Character ë
+U+b696 ddyoj # Character ë
+U+b697 ddyoc # Character ë
+U+b698 ddyok # Character ë
+U+b699 ddyot # Character ë
+U+b69a ddyop # Character ë
+U+b69b ddyoh # Character ë
+U+b69c ddu # Character ë
+U+b69d ddug # Character ë
+U+b69e ddugg # Character ë
+U+b69f ddugs # Character ë
+U+b6a0 ddun # Character ë
+U+b6a1 ddunj # Character ë¡
+U+b6a2 ddunh # Character ë¢
+U+b6a3 ddud # Character ë£
+U+b6a4 ddul # Character ë¤
+U+b6a5 ddulg # Character ë¥
+U+b6a6 ddulm # Character ë¦
+U+b6a7 ddulb # Character ë§
+U+b6a8 dduls # Character ë¨
+U+b6a9 ddult # Character ë©
+U+b6aa ddulp # Character ëª
+U+b6ab ddulh # Character ë«
+U+b6ac ddum # Character ë¬
+U+b6ad ddub # Character ë
+U+b6ae ddubs # Character ë®
+U+b6af ddus # Character ë¯
+U+b6b0 dduss # Character ë°
+U+b6b1 ddung # Character ë±
+U+b6b2 dduj # Character ë²
+U+b6b3 dduc # Character ë³
+U+b6b4 dduk # Character ë´
+U+b6b5 ddut # Character ëµ
+U+b6b6 ddup # Character ë¶
+U+b6b7 dduh # Character ë·
+U+b6b8 ddweo # Character ë¸
+U+b6b9 ddweog # Character ë¹
+U+b6ba ddweogg # Character ëº
+U+b6bb ddweogs # Character ë»
+U+b6bc ddweon # Character ë¼
+U+b6bd ddweonj # Character ë½
+U+b6be ddweonh # Character ë¾
+U+b6bf ddweod # Character ë¿
+U+b6c0 ddweol # Character ë
+U+b6c1 ddweolg # Character ë
+U+b6c2 ddweolm # Character ë
+U+b6c3 ddweolb # Character ë
+U+b6c4 ddweols # Character ë
+U+b6c5 ddweolt # Character ë
+U+b6c6 ddweolp # Character ë
+U+b6c7 ddweolh # Character ë
+U+b6c8 ddweom # Character ë
+U+b6c9 ddweob # Character ë
+U+b6ca ddweobs # Character ë
+U+b6cb ddweos # Character ë
+U+b6cc ddweoss # Character ë
+U+b6cd ddweong # Character ë
+U+b6ce ddweoj # Character ë
+U+b6cf ddweoc # Character ë
+U+b6d0 ddweok # Character ë
+U+b6d1 ddweot # Character ë
+U+b6d2 ddweop # Character ë
+U+b6d3 ddweoh # Character ë
+U+b6d4 ddwe # Character ë
+U+b6d5 ddweg # Character ë
+U+b6d6 ddwegg # Character ë
+U+b6d7 ddwegs # Character ë
+U+b6d8 ddwen # Character ë
+U+b6d9 ddwenj # Character ë
+U+b6da ddwenh # Character ë
+U+b6db ddwed # Character ë
+U+b6dc ddwel # Character ë
+U+b6dd ddwelg # Character ë
+U+b6de ddwelm # Character ë
+U+b6df ddwelb # Character ë
+U+b6e0 ddwels # Character ë
+U+b6e1 ddwelt # Character ë¡
+U+b6e2 ddwelp # Character ë¢
+U+b6e3 ddwelh # Character ë£
+U+b6e4 ddwem # Character ë¤
+U+b6e5 ddweb # Character ë¥
+U+b6e6 ddwebs # Character ë¦
+U+b6e7 ddwes # Character ë§
+U+b6e8 ddwess # Character ë¨
+U+b6e9 ddweng # Character ë©
+U+b6ea ddwej # Character ëª
+U+b6eb ddwec # Character ë«
+U+b6ec ddwek # Character ë¬
+U+b6ed ddwet # Character ë
+U+b6ee ddwep # Character ë®
+U+b6ef ddweh # Character ë¯
+U+b6f0 ddwi # Character ë°
+U+b6f1 ddwig # Character ë±
+U+b6f2 ddwigg # Character ë²
+U+b6f3 ddwigs # Character ë³
+U+b6f4 ddwin # Character ë´
+U+b6f5 ddwinj # Character ëµ
+U+b6f6 ddwinh # Character ë¶
+U+b6f7 ddwid # Character ë·
+U+b6f8 ddwil # Character ë¸
+U+b6f9 ddwilg # Character ë¹
+U+b6fa ddwilm # Character ëº
+U+b6fb ddwilb # Character ë»
+U+b6fc ddwils # Character ë¼
+U+b6fd ddwilt # Character ë½
+U+b6fe ddwilp # Character ë¾
+U+b6ff ddwilh # Character ë¿
diff --git a/resources/chars/ascii/rowb7.trans b/resources/chars/ascii/rowb7.trans
new file mode 100644
index 0000000..e189096
--- /dev/null
+++ b/resources/chars/ascii/rowb7.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+b700 ddwim # Character ë
+U+b701 ddwib # Character ë
+U+b702 ddwibs # Character ë
+U+b703 ddwis # Character ë
+U+b704 ddwiss # Character ë
+U+b705 ddwing # Character ë
+U+b706 ddwij # Character ë
+U+b707 ddwic # Character ë
+U+b708 ddwik # Character ë
+U+b709 ddwit # Character ë
+U+b70a ddwip # Character ë
+U+b70b ddwih # Character ë
+U+b70c ddyu # Character ë
+U+b70d ddyug # Character ë
+U+b70e ddyugg # Character ë
+U+b70f ddyugs # Character ë
+U+b710 ddyun # Character ë
+U+b711 ddyunj # Character ë
+U+b712 ddyunh # Character ë
+U+b713 ddyud # Character ë
+U+b714 ddyul # Character ë
+U+b715 ddyulg # Character ë
+U+b716 ddyulm # Character ë
+U+b717 ddyulb # Character ë
+U+b718 ddyuls # Character ë
+U+b719 ddyult # Character ë
+U+b71a ddyulp # Character ë
+U+b71b ddyulh # Character ë
+U+b71c ddyum # Character ë
+U+b71d ddyub # Character ë
+U+b71e ddyubs # Character ë
+U+b71f ddyus # Character ë
+U+b720 ddyuss # Character ë
+U+b721 ddyung # Character ë¡
+U+b722 ddyuj # Character ë¢
+U+b723 ddyuc # Character ë£
+U+b724 ddyuk # Character ë¤
+U+b725 ddyut # Character ë¥
+U+b726 ddyup # Character ë¦
+U+b727 ddyuh # Character ë§
+U+b728 ddeu # Character ë¨
+U+b729 ddeug # Character ë©
+U+b72a ddeugg # Character ëª
+U+b72b ddeugs # Character ë«
+U+b72c ddeun # Character ë¬
+U+b72d ddeunj # Character ë
+U+b72e ddeunh # Character ë®
+U+b72f ddeud # Character ë¯
+U+b730 ddeul # Character ë°
+U+b731 ddeulg # Character ë±
+U+b732 ddeulm # Character ë²
+U+b733 ddeulb # Character ë³
+U+b734 ddeuls # Character ë´
+U+b735 ddeult # Character ëµ
+U+b736 ddeulp # Character ë¶
+U+b737 ddeulh # Character ë·
+U+b738 ddeum # Character ë¸
+U+b739 ddeub # Character ë¹
+U+b73a ddeubs # Character ëº
+U+b73b ddeus # Character ë»
+U+b73c ddeuss # Character ë¼
+U+b73d ddeung # Character ë½
+U+b73e ddeuj # Character ë¾
+U+b73f ddeuc # Character ë¿
+U+b740 ddeuk # Character ë
+U+b741 ddeut # Character ë
+U+b742 ddeup # Character ë
+U+b743 ddeuh # Character ë
+U+b744 ddyi # Character ë
+U+b745 ddyig # Character ë
+U+b746 ddyigg # Character ë
+U+b747 ddyigs # Character ë
+U+b748 ddyin # Character ë
+U+b749 ddyinj # Character ë
+U+b74a ddyinh # Character ë
+U+b74b ddyid # Character ë
+U+b74c ddyil # Character ë
+U+b74d ddyilg # Character ë
+U+b74e ddyilm # Character ë
+U+b74f ddyilb # Character ë
+U+b750 ddyils # Character ë
+U+b751 ddyilt # Character ë
+U+b752 ddyilp # Character ë
+U+b753 ddyilh # Character ë
+U+b754 ddyim # Character ë
+U+b755 ddyib # Character ë
+U+b756 ddyibs # Character ë
+U+b757 ddyis # Character ë
+U+b758 ddyiss # Character ë
+U+b759 ddying # Character ë
+U+b75a ddyij # Character ë
+U+b75b ddyic # Character ë
+U+b75c ddyik # Character ë
+U+b75d ddyit # Character ë
+U+b75e ddyip # Character ë
+U+b75f ddyih # Character ë
+U+b760 ddi # Character ë
+U+b761 ddig # Character ë¡
+U+b762 ddigg # Character ë¢
+U+b763 ddigs # Character ë£
+U+b764 ddin # Character ë¤
+U+b765 ddinj # Character ë¥
+U+b766 ddinh # Character ë¦
+U+b767 ddid # Character ë§
+U+b768 ddil # Character ë¨
+U+b769 ddilg # Character ë©
+U+b76a ddilm # Character ëª
+U+b76b ddilb # Character ë«
+U+b76c ddils # Character ë¬
+U+b76d ddilt # Character ë
+U+b76e ddilp # Character ë®
+U+b76f ddilh # Character ë¯
+U+b770 ddim # Character ë°
+U+b771 ddib # Character ë±
+U+b772 ddibs # Character ë²
+U+b773 ddis # Character ë³
+U+b774 ddiss # Character ë´
+U+b775 dding # Character ëµ
+U+b776 ddij # Character ë¶
+U+b777 ddic # Character ë·
+U+b778 ddik # Character ë¸
+U+b779 ddit # Character ë¹
+U+b77a ddip # Character ëº
+U+b77b ddih # Character ë»
+U+b77c ra # Character ë¼
+U+b77d rag # Character ë½
+U+b77e ragg # Character ë¾
+U+b77f rags # Character ë¿
+U+b780 ran # Character ë
+U+b781 ranj # Character ë
+U+b782 ranh # Character ë
+U+b783 rad # Character ë
+U+b784 ral # Character ë
+U+b785 ralg # Character ë
+U+b786 ralm # Character ë
+U+b787 ralb # Character ë
+U+b788 rals # Character ë
+U+b789 ralt # Character ë
+U+b78a ralp # Character ë
+U+b78b ralh # Character ë
+U+b78c ram # Character ë
+U+b78d rab # Character ë
+U+b78e rabs # Character ë
+U+b78f ras # Character ë
+U+b790 rass # Character ë
+U+b791 rang # Character ë
+U+b792 raj # Character ë
+U+b793 rac # Character ë
+U+b794 rak # Character ë
+U+b795 rat # Character ë
+U+b796 rap # Character ë
+U+b797 rah # Character ë
+U+b798 rae # Character ë
+U+b799 raeg # Character ë
+U+b79a raegg # Character ë
+U+b79b raegs # Character ë
+U+b79c raen # Character ë
+U+b79d raenj # Character ë
+U+b79e raenh # Character ë
+U+b79f raed # Character ë
+U+b7a0 rael # Character ë
+U+b7a1 raelg # Character ë¡
+U+b7a2 raelm # Character ë¢
+U+b7a3 raelb # Character ë£
+U+b7a4 raels # Character ë¤
+U+b7a5 raelt # Character ë¥
+U+b7a6 raelp # Character ë¦
+U+b7a7 raelh # Character ë§
+U+b7a8 raem # Character ë¨
+U+b7a9 raeb # Character ë©
+U+b7aa raebs # Character ëª
+U+b7ab raes # Character ë«
+U+b7ac raess # Character ë¬
+U+b7ad raeng # Character ë
+U+b7ae raej # Character ë®
+U+b7af raec # Character ë¯
+U+b7b0 raek # Character ë°
+U+b7b1 raet # Character ë±
+U+b7b2 raep # Character ë²
+U+b7b3 raeh # Character ë³
+U+b7b4 rya # Character ë´
+U+b7b5 ryag # Character ëµ
+U+b7b6 ryagg # Character ë¶
+U+b7b7 ryags # Character ë·
+U+b7b8 ryan # Character ë¸
+U+b7b9 ryanj # Character ë¹
+U+b7ba ryanh # Character ëº
+U+b7bb ryad # Character ë»
+U+b7bc ryal # Character ë¼
+U+b7bd ryalg # Character ë½
+U+b7be ryalm # Character ë¾
+U+b7bf ryalb # Character ë¿
+U+b7c0 ryals # Character ë
+U+b7c1 ryalt # Character ë
+U+b7c2 ryalp # Character ë
+U+b7c3 ryalh # Character ë
+U+b7c4 ryam # Character ë
+U+b7c5 ryab # Character ë
+U+b7c6 ryabs # Character ë
+U+b7c7 ryas # Character ë
+U+b7c8 ryass # Character ë
+U+b7c9 ryang # Character ë
+U+b7ca ryaj # Character ë
+U+b7cb ryac # Character ë
+U+b7cc ryak # Character ë
+U+b7cd ryat # Character ë
+U+b7ce ryap # Character ë
+U+b7cf ryah # Character ë
+U+b7d0 ryae # Character ë
+U+b7d1 ryaeg # Character ë
+U+b7d2 ryaegg # Character ë
+U+b7d3 ryaegs # Character ë
+U+b7d4 ryaen # Character ë
+U+b7d5 ryaenj # Character ë
+U+b7d6 ryaenh # Character ë
+U+b7d7 ryaed # Character ë
+U+b7d8 ryael # Character ë
+U+b7d9 ryaelg # Character ë
+U+b7da ryaelm # Character ë
+U+b7db ryaelb # Character ë
+U+b7dc ryaels # Character ë
+U+b7dd ryaelt # Character ë
+U+b7de ryaelp # Character ë
+U+b7df ryaelh # Character ë
+U+b7e0 ryaem # Character ë
+U+b7e1 ryaeb # Character ë¡
+U+b7e2 ryaebs # Character ë¢
+U+b7e3 ryaes # Character ë£
+U+b7e4 ryaess # Character ë¤
+U+b7e5 ryaeng # Character ë¥
+U+b7e6 ryaej # Character ë¦
+U+b7e7 ryaec # Character ë§
+U+b7e8 ryaek # Character ë¨
+U+b7e9 ryaet # Character ë©
+U+b7ea ryaep # Character ëª
+U+b7eb ryaeh # Character ë«
+U+b7ec reo # Character ë¬
+U+b7ed reog # Character ë
+U+b7ee reogg # Character ë®
+U+b7ef reogs # Character ë¯
+U+b7f0 reon # Character ë°
+U+b7f1 reonj # Character ë±
+U+b7f2 reonh # Character ë²
+U+b7f3 reod # Character ë³
+U+b7f4 reol # Character ë´
+U+b7f5 reolg # Character ëµ
+U+b7f6 reolm # Character ë¶
+U+b7f7 reolb # Character ë·
+U+b7f8 reols # Character ë¸
+U+b7f9 reolt # Character ë¹
+U+b7fa reolp # Character ëº
+U+b7fb reolh # Character ë»
+U+b7fc reom # Character ë¼
+U+b7fd reob # Character ë½
+U+b7fe reobs # Character ë¾
+U+b7ff reos # Character ë¿
diff --git a/resources/chars/ascii/rowb8.trans b/resources/chars/ascii/rowb8.trans
new file mode 100644
index 0000000..98bc6e0
--- /dev/null
+++ b/resources/chars/ascii/rowb8.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+b800 reoss # Character ë
+U+b801 reong # Character ë
+U+b802 reoj # Character ë
+U+b803 reoc # Character ë
+U+b804 reok # Character ë
+U+b805 reot # Character ë
+U+b806 reop # Character ë
+U+b807 reoh # Character ë
+U+b808 re # Character ë
+U+b809 reg # Character ë
+U+b80a regg # Character ë
+U+b80b regs # Character ë
+U+b80c ren # Character ë
+U+b80d renj # Character ë
+U+b80e renh # Character ë
+U+b80f red # Character ë
+U+b810 rel # Character ë
+U+b811 relg # Character ë
+U+b812 relm # Character ë
+U+b813 relb # Character ë
+U+b814 rels # Character ë
+U+b815 relt # Character ë
+U+b816 relp # Character ë
+U+b817 relh # Character ë
+U+b818 rem # Character ë
+U+b819 reb # Character ë
+U+b81a rebs # Character ë
+U+b81b res # Character ë
+U+b81c ress # Character ë
+U+b81d reng # Character ë
+U+b81e rej # Character ë
+U+b81f rec # Character ë
+U+b820 rek # Character ë
+U+b821 ret # Character ë ¡
+U+b822 rep # Character ë ¢
+U+b823 reh # Character ë £
+U+b824 ryeo # Character ë ¤
+U+b825 ryeog # Character ë ¥
+U+b826 ryeogg # Character ë ¦
+U+b827 ryeogs # Character ë §
+U+b828 ryeon # Character ë ¨
+U+b829 ryeonj # Character ë ©
+U+b82a ryeonh # Character ë ª
+U+b82b ryeod # Character ë «
+U+b82c ryeol # Character ë ¬
+U+b82d ryeolg # Character ë
+U+b82e ryeolm # Character ë ®
+U+b82f ryeolb # Character ë ¯
+U+b830 ryeols # Character ë °
+U+b831 ryeolt # Character ë ±
+U+b832 ryeolp # Character ë ²
+U+b833 ryeolh # Character ë ³
+U+b834 ryeom # Character ë ´
+U+b835 ryeob # Character ë µ
+U+b836 ryeobs # Character ë ¶
+U+b837 ryeos # Character ë ·
+U+b838 ryeoss # Character ë ¸
+U+b839 ryeong # Character ë ¹
+U+b83a ryeoj # Character ë º
+U+b83b ryeoc # Character ë »
+U+b83c ryeok # Character ë ¼
+U+b83d ryeot # Character ë ½
+U+b83e ryeop # Character ë ¾
+U+b83f ryeoh # Character ë ¿
+U+b840 rye # Character ë¡
+U+b841 ryeg # Character ë¡
+U+b842 ryegg # Character ë¡
+U+b843 ryegs # Character ë¡
+U+b844 ryen # Character ë¡
+U+b845 ryenj # Character ë¡
+U+b846 ryenh # Character ë¡
+U+b847 ryed # Character ë¡
+U+b848 ryel # Character ë¡
+U+b849 ryelg # Character ë¡
+U+b84a ryelm # Character ë¡
+U+b84b ryelb # Character ë¡
+U+b84c ryels # Character ë¡
+U+b84d ryelt # Character ë¡
+U+b84e ryelp # Character ë¡
+U+b84f ryelh # Character ë¡
+U+b850 ryem # Character ë¡
+U+b851 ryeb # Character ë¡
+U+b852 ryebs # Character ë¡
+U+b853 ryes # Character ë¡
+U+b854 ryess # Character ë¡
+U+b855 ryeng # Character ë¡
+U+b856 ryej # Character ë¡
+U+b857 ryec # Character ë¡
+U+b858 ryek # Character ë¡
+U+b859 ryet # Character ë¡
+U+b85a ryep # Character ë¡
+U+b85b ryeh # Character ë¡
+U+b85c ro # Character ë¡
+U+b85d rog # Character ë¡
+U+b85e rogg # Character ë¡
+U+b85f rogs # Character ë¡
+U+b860 ron # Character ë¡
+U+b861 ronj # Character ë¡¡
+U+b862 ronh # Character ë¡¢
+U+b863 rod # Character ë¡£
+U+b864 rol # Character 롤
+U+b865 rolg # Character ë¡¥
+U+b866 rolm # Character 롦
+U+b867 rolb # Character 롧
+U+b868 rols # Character 롨
+U+b869 rolt # Character ë¡©
+U+b86a rolp # Character 롪
+U+b86b rolh # Character ë¡«
+U+b86c rom # Character 롬
+U+b86d rob # Character ë¡
+U+b86e robs # Character ë¡®
+U+b86f ros # Character 롯
+U+b870 ross # Character ë¡°
+U+b871 rong # Character 롱
+U+b872 roj # Character 롲
+U+b873 roc # Character 롳
+U+b874 rok # Character ë¡´
+U+b875 rot # Character 롵
+U+b876 rop # Character 롶
+U+b877 roh # Character ë¡·
+U+b878 rwa # Character 롸
+U+b879 rwag # Character 롹
+U+b87a rwagg # Character 롺
+U+b87b rwags # Character ë¡»
+U+b87c rwan # Character 롼
+U+b87d rwanj # Character 롽
+U+b87e rwanh # Character 롾
+U+b87f rwad # Character ë¡¿
+U+b880 rwal # Character ë¢
+U+b881 rwalg # Character ë¢
+U+b882 rwalm # Character ë¢
+U+b883 rwalb # Character ë¢
+U+b884 rwals # Character ë¢
+U+b885 rwalt # Character ë¢
+U+b886 rwalp # Character ë¢
+U+b887 rwalh # Character ë¢
+U+b888 rwam # Character ë¢
+U+b889 rwab # Character ë¢
+U+b88a rwabs # Character ë¢
+U+b88b rwas # Character ë¢
+U+b88c rwass # Character ë¢
+U+b88d rwang # Character ë¢
+U+b88e rwaj # Character ë¢
+U+b88f rwac # Character ë¢
+U+b890 rwak # Character ë¢
+U+b891 rwat # Character ë¢
+U+b892 rwap # Character ë¢
+U+b893 rwah # Character ë¢
+U+b894 rwae # Character ë¢
+U+b895 rwaeg # Character ë¢
+U+b896 rwaegg # Character ë¢
+U+b897 rwaegs # Character ë¢
+U+b898 rwaen # Character ë¢
+U+b899 rwaenj # Character ë¢
+U+b89a rwaenh # Character ë¢
+U+b89b rwaed # Character ë¢
+U+b89c rwael # Character ë¢
+U+b89d rwaelg # Character ë¢
+U+b89e rwaelm # Character ë¢
+U+b89f rwaelb # Character ë¢
+U+b8a0 rwaels # Character ë¢
+U+b8a1 rwaelt # Character 뢡
+U+b8a2 rwaelp # Character 뢢
+U+b8a3 rwaelh # Character 뢣
+U+b8a4 rwaem # Character 뢤
+U+b8a5 rwaeb # Character 뢥
+U+b8a6 rwaebs # Character 뢦
+U+b8a7 rwaes # Character 뢧
+U+b8a8 rwaess # Character 뢨
+U+b8a9 rwaeng # Character 뢩
+U+b8aa rwaej # Character 뢪
+U+b8ab rwaec # Character 뢫
+U+b8ac rwaek # Character 뢬
+U+b8ad rwaet # Character ë¢
+U+b8ae rwaep # Character 뢮
+U+b8af rwaeh # Character 뢯
+U+b8b0 roe # Character 뢰
+U+b8b1 roeg # Character 뢱
+U+b8b2 roegg # Character 뢲
+U+b8b3 roegs # Character 뢳
+U+b8b4 roen # Character 뢴
+U+b8b5 roenj # Character 뢵
+U+b8b6 roenh # Character 뢶
+U+b8b7 roed # Character 뢷
+U+b8b8 roel # Character 뢸
+U+b8b9 roelg # Character 뢹
+U+b8ba roelm # Character 뢺
+U+b8bb roelb # Character 뢻
+U+b8bc roels # Character 뢼
+U+b8bd roelt # Character 뢽
+U+b8be roelp # Character 뢾
+U+b8bf roelh # Character 뢿
+U+b8c0 roem # Character ë£
+U+b8c1 roeb # Character ë£
+U+b8c2 roebs # Character ë£
+U+b8c3 roes # Character ë£
+U+b8c4 roess # Character ë£
+U+b8c5 roeng # Character ë£
+U+b8c6 roej # Character ë£
+U+b8c7 roec # Character ë£
+U+b8c8 roek # Character ë£
+U+b8c9 roet # Character ë£
+U+b8ca roep # Character ë£
+U+b8cb roeh # Character ë£
+U+b8cc ryo # Character ë£
+U+b8cd ryog # Character ë£
+U+b8ce ryogg # Character ë£
+U+b8cf ryogs # Character ë£
+U+b8d0 ryon # Character ë£
+U+b8d1 ryonj # Character ë£
+U+b8d2 ryonh # Character ë£
+U+b8d3 ryod # Character ë£
+U+b8d4 ryol # Character ë£
+U+b8d5 ryolg # Character ë£
+U+b8d6 ryolm # Character ë£
+U+b8d7 ryolb # Character ë£
+U+b8d8 ryols # Character ë£
+U+b8d9 ryolt # Character ë£
+U+b8da ryolp # Character ë£
+U+b8db ryolh # Character ë£
+U+b8dc ryom # Character ë£
+U+b8dd ryob # Character ë£
+U+b8de ryobs # Character ë£
+U+b8df ryos # Character ë£
+U+b8e0 ryoss # Character ë£
+U+b8e1 ryong # Character 룡
+U+b8e2 ryoj # Character 룢
+U+b8e3 ryoc # Character 룣
+U+b8e4 ryok # Character 룤
+U+b8e5 ryot # Character 룥
+U+b8e6 ryop # Character 룦
+U+b8e7 ryoh # Character 룧
+U+b8e8 ru # Character 루
+U+b8e9 rug # Character 룩
+U+b8ea rugg # Character 룪
+U+b8eb rugs # Character 룫
+U+b8ec run # Character 룬
+U+b8ed runj # Character ë£
+U+b8ee runh # Character 룮
+U+b8ef rud # Character 룯
+U+b8f0 rul # Character 룰
+U+b8f1 rulg # Character 룱
+U+b8f2 rulm # Character 룲
+U+b8f3 rulb # Character 룳
+U+b8f4 ruls # Character 룴
+U+b8f5 rult # Character 룵
+U+b8f6 rulp # Character 룶
+U+b8f7 rulh # Character 룷
+U+b8f8 rum # Character 룸
+U+b8f9 rub # Character 룹
+U+b8fa rubs # Character 룺
+U+b8fb rus # Character 룻
+U+b8fc russ # Character 룼
+U+b8fd rung # Character 룽
+U+b8fe ruj # Character 룾
+U+b8ff ruc # Character 룿
diff --git a/resources/chars/ascii/rowb9.trans b/resources/chars/ascii/rowb9.trans
new file mode 100644
index 0000000..1b5aab7
--- /dev/null
+++ b/resources/chars/ascii/rowb9.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+b900 ruk # Character ë¤
+U+b901 rut # Character ë¤
+U+b902 rup # Character ë¤
+U+b903 ruh # Character ë¤
+U+b904 rweo # Character ë¤
+U+b905 rweog # Character ë¤
+U+b906 rweogg # Character ë¤
+U+b907 rweogs # Character ë¤
+U+b908 rweon # Character ë¤
+U+b909 rweonj # Character ë¤
+U+b90a rweonh # Character ë¤
+U+b90b rweod # Character ë¤
+U+b90c rweol # Character ë¤
+U+b90d rweolg # Character ë¤
+U+b90e rweolm # Character ë¤
+U+b90f rweolb # Character ë¤
+U+b910 rweols # Character ë¤
+U+b911 rweolt # Character ë¤
+U+b912 rweolp # Character ë¤
+U+b913 rweolh # Character ë¤
+U+b914 rweom # Character ë¤
+U+b915 rweob # Character ë¤
+U+b916 rweobs # Character ë¤
+U+b917 rweos # Character ë¤
+U+b918 rweoss # Character ë¤
+U+b919 rweong # Character ë¤
+U+b91a rweoj # Character ë¤
+U+b91b rweoc # Character ë¤
+U+b91c rweok # Character ë¤
+U+b91d rweot # Character ë¤
+U+b91e rweop # Character ë¤
+U+b91f rweoh # Character ë¤
+U+b920 rwe # Character ë¤
+U+b921 rweg # Character 뤡
+U+b922 rwegg # Character 뤢
+U+b923 rwegs # Character 뤣
+U+b924 rwen # Character 뤤
+U+b925 rwenj # Character 뤥
+U+b926 rwenh # Character 뤦
+U+b927 rwed # Character 뤧
+U+b928 rwel # Character 뤨
+U+b929 rwelg # Character 뤩
+U+b92a rwelm # Character 뤪
+U+b92b rwelb # Character 뤫
+U+b92c rwels # Character 뤬
+U+b92d rwelt # Character ë¤
+U+b92e rwelp # Character 뤮
+U+b92f rwelh # Character 뤯
+U+b930 rwem # Character 뤰
+U+b931 rweb # Character 뤱
+U+b932 rwebs # Character 뤲
+U+b933 rwes # Character 뤳
+U+b934 rwess # Character 뤴
+U+b935 rweng # Character 뤵
+U+b936 rwej # Character 뤶
+U+b937 rwec # Character 뤷
+U+b938 rwek # Character 뤸
+U+b939 rwet # Character 뤹
+U+b93a rwep # Character 뤺
+U+b93b rweh # Character 뤻
+U+b93c rwi # Character 뤼
+U+b93d rwig # Character 뤽
+U+b93e rwigg # Character 뤾
+U+b93f rwigs # Character 뤿
+U+b940 rwin # Character ë¥
+U+b941 rwinj # Character ë¥
+U+b942 rwinh # Character ë¥
+U+b943 rwid # Character ë¥
+U+b944 rwil # Character ë¥
+U+b945 rwilg # Character ë¥
+U+b946 rwilm # Character ë¥
+U+b947 rwilb # Character ë¥
+U+b948 rwils # Character ë¥
+U+b949 rwilt # Character ë¥
+U+b94a rwilp # Character ë¥
+U+b94b rwilh # Character ë¥
+U+b94c rwim # Character ë¥
+U+b94d rwib # Character ë¥
+U+b94e rwibs # Character ë¥
+U+b94f rwis # Character ë¥
+U+b950 rwiss # Character ë¥
+U+b951 rwing # Character ë¥
+U+b952 rwij # Character ë¥
+U+b953 rwic # Character ë¥
+U+b954 rwik # Character ë¥
+U+b955 rwit # Character ë¥
+U+b956 rwip # Character ë¥
+U+b957 rwih # Character ë¥
+U+b958 ryu # Character ë¥
+U+b959 ryug # Character ë¥
+U+b95a ryugg # Character ë¥
+U+b95b ryugs # Character ë¥
+U+b95c ryun # Character ë¥
+U+b95d ryunj # Character ë¥
+U+b95e ryunh # Character ë¥
+U+b95f ryud # Character ë¥
+U+b960 ryul # Character ë¥
+U+b961 ryulg # Character 륡
+U+b962 ryulm # Character 륢
+U+b963 ryulb # Character 륣
+U+b964 ryuls # Character 륤
+U+b965 ryult # Character 륥
+U+b966 ryulp # Character 륦
+U+b967 ryulh # Character 륧
+U+b968 ryum # Character 륨
+U+b969 ryub # Character 륩
+U+b96a ryubs # Character 륪
+U+b96b ryus # Character 륫
+U+b96c ryuss # Character 륬
+U+b96d ryung # Character ë¥
+U+b96e ryuj # Character 륮
+U+b96f ryuc # Character 륯
+U+b970 ryuk # Character 륰
+U+b971 ryut # Character 륱
+U+b972 ryup # Character 륲
+U+b973 ryuh # Character 륳
+U+b974 reu # Character 르
+U+b975 reug # Character 륵
+U+b976 reugg # Character 륶
+U+b977 reugs # Character 륷
+U+b978 reun # Character 른
+U+b979 reunj # Character 륹
+U+b97a reunh # Character 륺
+U+b97b reud # Character 륻
+U+b97c reul # Character 를
+U+b97d reulg # Character 륽
+U+b97e reulm # Character 륾
+U+b97f reulb # Character 륿
+U+b980 reuls # Character ë¦
+U+b981 reult # Character ë¦
+U+b982 reulp # Character ë¦
+U+b983 reulh # Character ë¦
+U+b984 reum # Character ë¦
+U+b985 reub # Character ë¦
+U+b986 reubs # Character ë¦
+U+b987 reus # Character ë¦
+U+b988 reuss # Character ë¦
+U+b989 reung # Character ë¦
+U+b98a reuj # Character ë¦
+U+b98b reuc # Character ë¦
+U+b98c reuk # Character ë¦
+U+b98d reut # Character ë¦
+U+b98e reup # Character ë¦
+U+b98f reuh # Character ë¦
+U+b990 ryi # Character ë¦
+U+b991 ryig # Character ë¦
+U+b992 ryigg # Character ë¦
+U+b993 ryigs # Character ë¦
+U+b994 ryin # Character ë¦
+U+b995 ryinj # Character ë¦
+U+b996 ryinh # Character ë¦
+U+b997 ryid # Character ë¦
+U+b998 ryil # Character ë¦
+U+b999 ryilg # Character ë¦
+U+b99a ryilm # Character ë¦
+U+b99b ryilb # Character ë¦
+U+b99c ryils # Character ë¦
+U+b99d ryilt # Character ë¦
+U+b99e ryilp # Character ë¦
+U+b99f ryilh # Character ë¦
+U+b9a0 ryim # Character ë¦
+U+b9a1 ryib # Character 릡
+U+b9a2 ryibs # Character 릢
+U+b9a3 ryis # Character 릣
+U+b9a4 ryiss # Character 릤
+U+b9a5 rying # Character 릥
+U+b9a6 ryij # Character 릦
+U+b9a7 ryic # Character 릧
+U+b9a8 ryik # Character 릨
+U+b9a9 ryit # Character 릩
+U+b9aa ryip # Character 릪
+U+b9ab ryih # Character 릫
+U+b9ac ri # Character 리
+U+b9ad rig # Character ë¦
+U+b9ae rigg # Character 릮
+U+b9af rigs # Character 릯
+U+b9b0 rin # Character 린
+U+b9b1 rinj # Character 릱
+U+b9b2 rinh # Character 릲
+U+b9b3 rid # Character 릳
+U+b9b4 ril # Character 릴
+U+b9b5 rilg # Character 릵
+U+b9b6 rilm # Character 릶
+U+b9b7 rilb # Character 릷
+U+b9b8 rils # Character 릸
+U+b9b9 rilt # Character 릹
+U+b9ba rilp # Character 릺
+U+b9bb rilh # Character 릻
+U+b9bc rim # Character 림
+U+b9bd rib # Character 립
+U+b9be ribs # Character 릾
+U+b9bf ris # Character 릿
+U+b9c0 riss # Character ë§
+U+b9c1 ring # Character ë§
+U+b9c2 rij # Character ë§
+U+b9c3 ric # Character ë§
+U+b9c4 rik # Character ë§
+U+b9c5 rit # Character ë§
+U+b9c6 rip # Character ë§
+U+b9c7 rih # Character ë§
+U+b9c8 ma # Character ë§
+U+b9c9 mag # Character ë§
+U+b9ca magg # Character ë§
+U+b9cb mags # Character ë§
+U+b9cc man # Character ë§
+U+b9cd manj # Character ë§
+U+b9ce manh # Character ë§
+U+b9cf mad # Character ë§
+U+b9d0 mal # Character ë§
+U+b9d1 malg # Character ë§
+U+b9d2 malm # Character ë§
+U+b9d3 malb # Character ë§
+U+b9d4 mals # Character ë§
+U+b9d5 malt # Character ë§
+U+b9d6 malp # Character ë§
+U+b9d7 malh # Character ë§
+U+b9d8 mam # Character ë§
+U+b9d9 mab # Character ë§
+U+b9da mabs # Character ë§
+U+b9db mas # Character ë§
+U+b9dc mass # Character ë§
+U+b9dd mang # Character ë§
+U+b9de maj # Character ë§
+U+b9df mac # Character ë§
+U+b9e0 mak # Character ë§
+U+b9e1 mat # Character 맡
+U+b9e2 map # Character 맢
+U+b9e3 mah # Character 맣
+U+b9e4 mae # Character 매
+U+b9e5 maeg # Character 맥
+U+b9e6 maegg # Character 맦
+U+b9e7 maegs # Character 맧
+U+b9e8 maen # Character 맨
+U+b9e9 maenj # Character 맩
+U+b9ea maenh # Character 맪
+U+b9eb maed # Character 맫
+U+b9ec mael # Character 맬
+U+b9ed maelg # Character ë§
+U+b9ee maelm # Character 맮
+U+b9ef maelb # Character 맯
+U+b9f0 maels # Character 맰
+U+b9f1 maelt # Character 맱
+U+b9f2 maelp # Character 맲
+U+b9f3 maelh # Character 맳
+U+b9f4 maem # Character 맴
+U+b9f5 maeb # Character 맵
+U+b9f6 maebs # Character 맶
+U+b9f7 maes # Character 맷
+U+b9f8 maess # Character 맸
+U+b9f9 maeng # Character 맹
+U+b9fa maej # Character 맺
+U+b9fb maec # Character 맻
+U+b9fc maek # Character 맼
+U+b9fd maet # Character 맽
+U+b9fe maep # Character 맾
+U+b9ff maeh # Character 맿
diff --git a/resources/chars/ascii/rowba.trans b/resources/chars/ascii/rowba.trans
new file mode 100644
index 0000000..9836a3b
--- /dev/null
+++ b/resources/chars/ascii/rowba.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+ba00 mya # Character ë¨
+U+ba01 myag # Character ë¨
+U+ba02 myagg # Character ë¨
+U+ba03 myags # Character ë¨
+U+ba04 myan # Character ë¨
+U+ba05 myanj # Character ë¨
+U+ba06 myanh # Character ë¨
+U+ba07 myad # Character ë¨
+U+ba08 myal # Character ë¨
+U+ba09 myalg # Character ë¨
+U+ba0a myalm # Character ë¨
+U+ba0b myalb # Character ë¨
+U+ba0c myals # Character ë¨
+U+ba0d myalt # Character ë¨
+U+ba0e myalp # Character ë¨
+U+ba0f myalh # Character ë¨
+U+ba10 myam # Character ë¨
+U+ba11 myab # Character ë¨
+U+ba12 myabs # Character ë¨
+U+ba13 myas # Character ë¨
+U+ba14 myass # Character ë¨
+U+ba15 myang # Character ë¨
+U+ba16 myaj # Character ë¨
+U+ba17 myac # Character ë¨
+U+ba18 myak # Character ë¨
+U+ba19 myat # Character ë¨
+U+ba1a myap # Character ë¨
+U+ba1b myah # Character ë¨
+U+ba1c myae # Character ë¨
+U+ba1d myaeg # Character ë¨
+U+ba1e myaegg # Character ë¨
+U+ba1f myaegs # Character ë¨
+U+ba20 myaen # Character ë¨
+U+ba21 myaenj # Character 먡
+U+ba22 myaenh # Character 먢
+U+ba23 myaed # Character 먣
+U+ba24 myael # Character 먤
+U+ba25 myaelg # Character 먥
+U+ba26 myaelm # Character 먦
+U+ba27 myaelb # Character 먧
+U+ba28 myaels # Character 먨
+U+ba29 myaelt # Character 먩
+U+ba2a myaelp # Character 먪
+U+ba2b myaelh # Character 먫
+U+ba2c myaem # Character 먬
+U+ba2d myaeb # Character ë¨
+U+ba2e myaebs # Character 먮
+U+ba2f myaes # Character 먯
+U+ba30 myaess # Character 먰
+U+ba31 myaeng # Character 먱
+U+ba32 myaej # Character 먲
+U+ba33 myaec # Character 먳
+U+ba34 myaek # Character 먴
+U+ba35 myaet # Character 먵
+U+ba36 myaep # Character 먶
+U+ba37 myaeh # Character 먷
+U+ba38 meo # Character 머
+U+ba39 meog # Character 먹
+U+ba3a meogg # Character 먺
+U+ba3b meogs # Character 먻
+U+ba3c meon # Character 먼
+U+ba3d meonj # Character 먽
+U+ba3e meonh # Character 먾
+U+ba3f meod # Character 먿
+U+ba40 meol # Character ë©
+U+ba41 meolg # Character ë©
+U+ba42 meolm # Character ë©
+U+ba43 meolb # Character ë©
+U+ba44 meols # Character ë©
+U+ba45 meolt # Character ë©
+U+ba46 meolp # Character ë©
+U+ba47 meolh # Character ë©
+U+ba48 meom # Character ë©
+U+ba49 meob # Character ë©
+U+ba4a meobs # Character ë©
+U+ba4b meos # Character ë©
+U+ba4c meoss # Character ë©
+U+ba4d meong # Character ë©
+U+ba4e meoj # Character ë©
+U+ba4f meoc # Character ë©
+U+ba50 meok # Character ë©
+U+ba51 meot # Character ë©
+U+ba52 meop # Character ë©
+U+ba53 meoh # Character ë©
+U+ba54 me # Character ë©
+U+ba55 meg # Character ë©
+U+ba56 megg # Character ë©
+U+ba57 megs # Character ë©
+U+ba58 men # Character ë©
+U+ba59 menj # Character ë©
+U+ba5a menh # Character ë©
+U+ba5b med # Character ë©
+U+ba5c mel # Character ë©
+U+ba5d melg # Character ë©
+U+ba5e melm # Character ë©
+U+ba5f melb # Character ë©
+U+ba60 mels # Character ë©
+U+ba61 melt # Character ë©¡
+U+ba62 melp # Character ë©¢
+U+ba63 melh # Character ë©£
+U+ba64 mem # Character 멤
+U+ba65 meb # Character ë©¥
+U+ba66 mebs # Character 멦
+U+ba67 mes # Character 멧
+U+ba68 mess # Character 멨
+U+ba69 meng # Character ë©©
+U+ba6a mej # Character 멪
+U+ba6b mec # Character ë©«
+U+ba6c mek # Character 멬
+U+ba6d met # Character ë©
+U+ba6e mep # Character ë©®
+U+ba6f meh # Character 멯
+U+ba70 myeo # Character ë©°
+U+ba71 myeog # Character 멱
+U+ba72 myeogg # Character 멲
+U+ba73 myeogs # Character 멳
+U+ba74 myeon # Character ë©´
+U+ba75 myeonj # Character 멵
+U+ba76 myeonh # Character 멶
+U+ba77 myeod # Character ë©·
+U+ba78 myeol # Character 멸
+U+ba79 myeolg # Character 멹
+U+ba7a myeolm # Character 멺
+U+ba7b myeolb # Character ë©»
+U+ba7c myeols # Character 멼
+U+ba7d myeolt # Character 멽
+U+ba7e myeolp # Character 멾
+U+ba7f myeolh # Character ë©¿
+U+ba80 myeom # Character ëª
+U+ba81 myeob # Character ëª
+U+ba82 myeobs # Character ëª
+U+ba83 myeos # Character ëª
+U+ba84 myeoss # Character ëª
+U+ba85 myeong # Character ëª
+U+ba86 myeoj # Character ëª
+U+ba87 myeoc # Character ëª
+U+ba88 myeok # Character ëª
+U+ba89 myeot # Character ëª
+U+ba8a myeop # Character ëª
+U+ba8b myeoh # Character ëª
+U+ba8c mye # Character ëª
+U+ba8d myeg # Character ëª
+U+ba8e myegg # Character ëª
+U+ba8f myegs # Character ëª
+U+ba90 myen # Character ëª
+U+ba91 myenj # Character ëª
+U+ba92 myenh # Character ëª
+U+ba93 myed # Character ëª
+U+ba94 myel # Character ëª
+U+ba95 myelg # Character ëª
+U+ba96 myelm # Character ëª
+U+ba97 myelb # Character ëª
+U+ba98 myels # Character ëª
+U+ba99 myelt # Character ëª
+U+ba9a myelp # Character ëª
+U+ba9b myelh # Character ëª
+U+ba9c myem # Character ëª
+U+ba9d myeb # Character ëª
+U+ba9e myebs # Character ëª
+U+ba9f myes # Character ëª
+U+baa0 myess # Character ëª
+U+baa1 myeng # Character 몡
+U+baa2 myej # Character 몢
+U+baa3 myec # Character 몣
+U+baa4 myek # Character 몤
+U+baa5 myet # Character 몥
+U+baa6 myep # Character 몦
+U+baa7 myeh # Character 몧
+U+baa8 mo # Character 모
+U+baa9 mog # Character 목
+U+baaa mogg # Character 몪
+U+baab mogs # Character 몫
+U+baac mon # Character 몬
+U+baad monj # Character ëª
+U+baae monh # Character 몮
+U+baaf mod # Character 몯
+U+bab0 mol # Character 몰
+U+bab1 molg # Character 몱
+U+bab2 molm # Character 몲
+U+bab3 molb # Character 몳
+U+bab4 mols # Character 몴
+U+bab5 molt # Character 몵
+U+bab6 molp # Character 몶
+U+bab7 molh # Character 몷
+U+bab8 mom # Character 몸
+U+bab9 mob # Character 몹
+U+baba mobs # Character 몺
+U+babb mos # Character 못
+U+babc moss # Character 몼
+U+babd mong # Character 몽
+U+babe moj # Character 몾
+U+babf moc # Character 몿
+U+bac0 mok # Character ë«
+U+bac1 mot # Character ë«
+U+bac2 mop # Character ë«
+U+bac3 moh # Character ë«
+U+bac4 mwa # Character ë«
+U+bac5 mwag # Character ë«
+U+bac6 mwagg # Character ë«
+U+bac7 mwags # Character ë«
+U+bac8 mwan # Character ë«
+U+bac9 mwanj # Character ë«
+U+baca mwanh # Character ë«
+U+bacb mwad # Character ë«
+U+bacc mwal # Character ë«
+U+bacd mwalg # Character ë«
+U+bace mwalm # Character ë«
+U+bacf mwalb # Character ë«
+U+bad0 mwals # Character ë«
+U+bad1 mwalt # Character ë«
+U+bad2 mwalp # Character ë«
+U+bad3 mwalh # Character ë«
+U+bad4 mwam # Character ë«
+U+bad5 mwab # Character ë«
+U+bad6 mwabs # Character ë«
+U+bad7 mwas # Character ë«
+U+bad8 mwass # Character ë«
+U+bad9 mwang # Character ë«
+U+bada mwaj # Character ë«
+U+badb mwac # Character ë«
+U+badc mwak # Character ë«
+U+badd mwat # Character ë«
+U+bade mwap # Character ë«
+U+badf mwah # Character ë«
+U+bae0 mwae # Character ë«
+U+bae1 mwaeg # Character ë«¡
+U+bae2 mwaegg # Character ë«¢
+U+bae3 mwaegs # Character ë«£
+U+bae4 mwaen # Character 뫤
+U+bae5 mwaenj # Character ë«¥
+U+bae6 mwaenh # Character 뫦
+U+bae7 mwaed # Character 뫧
+U+bae8 mwael # Character 뫨
+U+bae9 mwaelg # Character ë«©
+U+baea mwaelm # Character 뫪
+U+baeb mwaelb # Character ë««
+U+baec mwaels # Character 뫬
+U+baed mwaelt # Character ë«
+U+baee mwaelp # Character ë«®
+U+baef mwaelh # Character 뫯
+U+baf0 mwaem # Character ë«°
+U+baf1 mwaeb # Character 뫱
+U+baf2 mwaebs # Character 뫲
+U+baf3 mwaes # Character 뫳
+U+baf4 mwaess # Character ë«´
+U+baf5 mwaeng # Character 뫵
+U+baf6 mwaej # Character 뫶
+U+baf7 mwaec # Character ë«·
+U+baf8 mwaek # Character 뫸
+U+baf9 mwaet # Character 뫹
+U+bafa mwaep # Character 뫺
+U+bafb mwaeh # Character ë«»
+U+bafc moe # Character 뫼
+U+bafd moeg # Character 뫽
+U+bafe moegg # Character 뫾
+U+baff moegs # Character ë«¿
diff --git a/resources/chars/ascii/rowbb.trans b/resources/chars/ascii/rowbb.trans
new file mode 100644
index 0000000..2d4208e
--- /dev/null
+++ b/resources/chars/ascii/rowbb.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+bb00 moen # Character ë¬
+U+bb01 moenj # Character ë¬
+U+bb02 moenh # Character ë¬
+U+bb03 moed # Character ë¬
+U+bb04 moel # Character ë¬
+U+bb05 moelg # Character ë¬
+U+bb06 moelm # Character ë¬
+U+bb07 moelb # Character ë¬
+U+bb08 moels # Character ë¬
+U+bb09 moelt # Character ë¬
+U+bb0a moelp # Character ë¬
+U+bb0b moelh # Character ë¬
+U+bb0c moem # Character ë¬
+U+bb0d moeb # Character ë¬
+U+bb0e moebs # Character ë¬
+U+bb0f moes # Character ë¬
+U+bb10 moess # Character ë¬
+U+bb11 moeng # Character ë¬
+U+bb12 moej # Character ë¬
+U+bb13 moec # Character ë¬
+U+bb14 moek # Character ë¬
+U+bb15 moet # Character ë¬
+U+bb16 moep # Character ë¬
+U+bb17 moeh # Character ë¬
+U+bb18 myo # Character ë¬
+U+bb19 myog # Character ë¬
+U+bb1a myogg # Character ë¬
+U+bb1b myogs # Character ë¬
+U+bb1c myon # Character ë¬
+U+bb1d myonj # Character ë¬
+U+bb1e myonh # Character ë¬
+U+bb1f myod # Character ë¬
+U+bb20 myol # Character ë¬
+U+bb21 myolg # Character 묡
+U+bb22 myolm # Character 묢
+U+bb23 myolb # Character 묣
+U+bb24 myols # Character 묤
+U+bb25 myolt # Character 묥
+U+bb26 myolp # Character 묦
+U+bb27 myolh # Character 묧
+U+bb28 myom # Character 묨
+U+bb29 myob # Character 묩
+U+bb2a myobs # Character 묪
+U+bb2b myos # Character 묫
+U+bb2c myoss # Character 묬
+U+bb2d myong # Character ë¬
+U+bb2e myoj # Character 묮
+U+bb2f myoc # Character 묯
+U+bb30 myok # Character 묰
+U+bb31 myot # Character 묱
+U+bb32 myop # Character 묲
+U+bb33 myoh # Character 묳
+U+bb34 mu # Character 무
+U+bb35 mug # Character 묵
+U+bb36 mugg # Character 묶
+U+bb37 mugs # Character 묷
+U+bb38 mun # Character 문
+U+bb39 munj # Character 묹
+U+bb3a munh # Character 묺
+U+bb3b mud # Character 묻
+U+bb3c mul # Character 물
+U+bb3d mulg # Character 묽
+U+bb3e mulm # Character 묾
+U+bb3f mulb # Character 묿
+U+bb40 muls # Character ë
+U+bb41 mult # Character ë
+U+bb42 mulp # Character ë
+U+bb43 mulh # Character ë
+U+bb44 mum # Character ë
+U+bb45 mub # Character ë
+U+bb46 mubs # Character ë
+U+bb47 mus # Character ë
+U+bb48 muss # Character ë
+U+bb49 mung # Character ë
+U+bb4a muj # Character ë
+U+bb4b muc # Character ë
+U+bb4c muk # Character ë
+U+bb4d mut # Character ë
+U+bb4e mup # Character ë
+U+bb4f muh # Character ë
+U+bb50 mweo # Character ë
+U+bb51 mweog # Character ë
+U+bb52 mweogg # Character ë
+U+bb53 mweogs # Character ë
+U+bb54 mweon # Character ë
+U+bb55 mweonj # Character ë
+U+bb56 mweonh # Character ë
+U+bb57 mweod # Character ë
+U+bb58 mweol # Character ë
+U+bb59 mweolg # Character ë
+U+bb5a mweolm # Character ë
+U+bb5b mweolb # Character ë
+U+bb5c mweols # Character ë
+U+bb5d mweolt # Character ë
+U+bb5e mweolp # Character ë
+U+bb5f mweolh # Character ë
+U+bb60 mweom # Character ë
+U+bb61 mweob # Character ë¡
+U+bb62 mweobs # Character ë¢
+U+bb63 mweos # Character ë£
+U+bb64 mweoss # Character ë¤
+U+bb65 mweong # Character ë¥
+U+bb66 mweoj # Character ë¦
+U+bb67 mweoc # Character ë§
+U+bb68 mweok # Character ë¨
+U+bb69 mweot # Character ë©
+U+bb6a mweop # Character ëª
+U+bb6b mweoh # Character ë«
+U+bb6c mwe # Character ë¬
+U+bb6d mweg # Character ë
+U+bb6e mwegg # Character ë®
+U+bb6f mwegs # Character ë¯
+U+bb70 mwen # Character ë°
+U+bb71 mwenj # Character ë±
+U+bb72 mwenh # Character ë²
+U+bb73 mwed # Character ë³
+U+bb74 mwel # Character ë´
+U+bb75 mwelg # Character ëµ
+U+bb76 mwelm # Character ë¶
+U+bb77 mwelb # Character ë·
+U+bb78 mwels # Character ë¸
+U+bb79 mwelt # Character ë¹
+U+bb7a mwelp # Character ëº
+U+bb7b mwelh # Character ë»
+U+bb7c mwem # Character ë¼
+U+bb7d mweb # Character ë½
+U+bb7e mwebs # Character ë¾
+U+bb7f mwes # Character ë¿
+U+bb80 mwess # Character ë®
+U+bb81 mweng # Character ë®
+U+bb82 mwej # Character ë®
+U+bb83 mwec # Character ë®
+U+bb84 mwek # Character ë®
+U+bb85 mwet # Character ë®
+U+bb86 mwep # Character ë®
+U+bb87 mweh # Character ë®
+U+bb88 mwi # Character ë®
+U+bb89 mwig # Character ë®
+U+bb8a mwigg # Character ë®
+U+bb8b mwigs # Character ë®
+U+bb8c mwin # Character ë®
+U+bb8d mwinj # Character ë®
+U+bb8e mwinh # Character ë®
+U+bb8f mwid # Character ë®
+U+bb90 mwil # Character ë®
+U+bb91 mwilg # Character ë®
+U+bb92 mwilm # Character ë®
+U+bb93 mwilb # Character ë®
+U+bb94 mwils # Character ë®
+U+bb95 mwilt # Character ë®
+U+bb96 mwilp # Character ë®
+U+bb97 mwilh # Character ë®
+U+bb98 mwim # Character ë®
+U+bb99 mwib # Character ë®
+U+bb9a mwibs # Character ë®
+U+bb9b mwis # Character ë®
+U+bb9c mwiss # Character ë®
+U+bb9d mwing # Character ë®
+U+bb9e mwij # Character ë®
+U+bb9f mwic # Character ë®
+U+bba0 mwik # Character ë®
+U+bba1 mwit # Character 뮡
+U+bba2 mwip # Character 뮢
+U+bba3 mwih # Character 뮣
+U+bba4 myu # Character 뮤
+U+bba5 myug # Character 뮥
+U+bba6 myugg # Character 뮦
+U+bba7 myugs # Character 뮧
+U+bba8 myun # Character 뮨
+U+bba9 myunj # Character 뮩
+U+bbaa myunh # Character 뮪
+U+bbab myud # Character 뮫
+U+bbac myul # Character 뮬
+U+bbad myulg # Character ë®
+U+bbae myulm # Character ë®®
+U+bbaf myulb # Character 뮯
+U+bbb0 myuls # Character ë®°
+U+bbb1 myult # Character ë®±
+U+bbb2 myulp # Character 뮲
+U+bbb3 myulh # Character 뮳
+U+bbb4 myum # Character ë®´
+U+bbb5 myub # Character 뮵
+U+bbb6 myubs # Character 뮶
+U+bbb7 myus # Character ë®·
+U+bbb8 myuss # Character 뮸
+U+bbb9 myung # Character 뮹
+U+bbba myuj # Character 뮺
+U+bbbb myuc # Character ë®»
+U+bbbc myuk # Character 뮼
+U+bbbd myut # Character 뮽
+U+bbbe myup # Character 뮾
+U+bbbf myuh # Character 뮿
+U+bbc0 meu # Character ë¯
+U+bbc1 meug # Character ë¯
+U+bbc2 meugg # Character ë¯
+U+bbc3 meugs # Character ë¯
+U+bbc4 meun # Character ë¯
+U+bbc5 meunj # Character ë¯
+U+bbc6 meunh # Character ë¯
+U+bbc7 meud # Character ë¯
+U+bbc8 meul # Character ë¯
+U+bbc9 meulg # Character ë¯
+U+bbca meulm # Character ë¯
+U+bbcb meulb # Character ë¯
+U+bbcc meuls # Character ë¯
+U+bbcd meult # Character ë¯
+U+bbce meulp # Character ë¯
+U+bbcf meulh # Character ë¯
+U+bbd0 meum # Character ë¯
+U+bbd1 meub # Character ë¯
+U+bbd2 meubs # Character ë¯
+U+bbd3 meus # Character ë¯
+U+bbd4 meuss # Character ë¯
+U+bbd5 meung # Character ë¯
+U+bbd6 meuj # Character ë¯
+U+bbd7 meuc # Character ë¯
+U+bbd8 meuk # Character ë¯
+U+bbd9 meut # Character ë¯
+U+bbda meup # Character ë¯
+U+bbdb meuh # Character ë¯
+U+bbdc myi # Character ë¯
+U+bbdd myig # Character ë¯
+U+bbde myigg # Character ë¯
+U+bbdf myigs # Character ë¯
+U+bbe0 myin # Character ë¯
+U+bbe1 myinj # Character 믡
+U+bbe2 myinh # Character 믢
+U+bbe3 myid # Character 믣
+U+bbe4 myil # Character 믤
+U+bbe5 myilg # Character 믥
+U+bbe6 myilm # Character 믦
+U+bbe7 myilb # Character 믧
+U+bbe8 myils # Character 믨
+U+bbe9 myilt # Character 믩
+U+bbea myilp # Character 믪
+U+bbeb myilh # Character 믫
+U+bbec myim # Character 믬
+U+bbed myib # Character ë¯
+U+bbee myibs # Character 믮
+U+bbef myis # Character 믯
+U+bbf0 myiss # Character 믰
+U+bbf1 mying # Character 믱
+U+bbf2 myij # Character 믲
+U+bbf3 myic # Character 믳
+U+bbf4 myik # Character 믴
+U+bbf5 myit # Character 믵
+U+bbf6 myip # Character 믶
+U+bbf7 myih # Character 믷
+U+bbf8 mi # Character 미
+U+bbf9 mig # Character 믹
+U+bbfa migg # Character 믺
+U+bbfb migs # Character 믻
+U+bbfc min # Character 민
+U+bbfd minj # Character 믽
+U+bbfe minh # Character 믾
+U+bbff mid # Character 믿
diff --git a/resources/chars/ascii/rowbc.trans b/resources/chars/ascii/rowbc.trans
new file mode 100644
index 0000000..1d83fa4
--- /dev/null
+++ b/resources/chars/ascii/rowbc.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+bc00 mil # Character ë°
+U+bc01 milg # Character ë°
+U+bc02 milm # Character ë°
+U+bc03 milb # Character ë°
+U+bc04 mils # Character ë°
+U+bc05 milt # Character ë°
+U+bc06 milp # Character ë°
+U+bc07 milh # Character ë°
+U+bc08 mim # Character ë°
+U+bc09 mib # Character ë°
+U+bc0a mibs # Character ë°
+U+bc0b mis # Character ë°
+U+bc0c miss # Character ë°
+U+bc0d ming # Character ë°
+U+bc0e mij # Character ë°
+U+bc0f mic # Character ë°
+U+bc10 mik # Character ë°
+U+bc11 mit # Character ë°
+U+bc12 mip # Character ë°
+U+bc13 mih # Character ë°
+U+bc14 ba # Character ë°
+U+bc15 bag # Character ë°
+U+bc16 bagg # Character ë°
+U+bc17 bags # Character ë°
+U+bc18 ban # Character ë°
+U+bc19 banj # Character ë°
+U+bc1a banh # Character ë°
+U+bc1b bad # Character ë°
+U+bc1c bal # Character ë°
+U+bc1d balg # Character ë°
+U+bc1e balm # Character ë°
+U+bc1f balb # Character ë°
+U+bc20 bals # Character ë°
+U+bc21 balt # Character ë°¡
+U+bc22 balp # Character ë°¢
+U+bc23 balh # Character ë°£
+U+bc24 bam # Character ë°¤
+U+bc25 bab # Character ë°¥
+U+bc26 babs # Character ë°¦
+U+bc27 bas # Character ë°§
+U+bc28 bass # Character ë°¨
+U+bc29 bang # Character ë°©
+U+bc2a baj # Character ë°ª
+U+bc2b bac # Character ë°«
+U+bc2c bak # Character ë°¬
+U+bc2d bat # Character ë°
+U+bc2e bap # Character ë°®
+U+bc2f bah # Character ë°¯
+U+bc30 bae # Character ë°°
+U+bc31 baeg # Character ë°±
+U+bc32 baegg # Character ë°²
+U+bc33 baegs # Character ë°³
+U+bc34 baen # Character ë°´
+U+bc35 baenj # Character ë°µ
+U+bc36 baenh # Character ë°¶
+U+bc37 baed # Character ë°·
+U+bc38 bael # Character ë°¸
+U+bc39 baelg # Character ë°¹
+U+bc3a baelm # Character ë°º
+U+bc3b baelb # Character ë°»
+U+bc3c baels # Character ë°¼
+U+bc3d baelt # Character ë°½
+U+bc3e baelp # Character ë°¾
+U+bc3f baelh # Character ë°¿
+U+bc40 baem # Character ë±
+U+bc41 baeb # Character ë±
+U+bc42 baebs # Character ë±
+U+bc43 baes # Character ë±
+U+bc44 baess # Character ë±
+U+bc45 baeng # Character ë±
+U+bc46 baej # Character ë±
+U+bc47 baec # Character ë±
+U+bc48 baek # Character ë±
+U+bc49 baet # Character ë±
+U+bc4a baep # Character ë±
+U+bc4b baeh # Character ë±
+U+bc4c bya # Character ë±
+U+bc4d byag # Character ë±
+U+bc4e byagg # Character ë±
+U+bc4f byags # Character ë±
+U+bc50 byan # Character ë±
+U+bc51 byanj # Character ë±
+U+bc52 byanh # Character ë±
+U+bc53 byad # Character ë±
+U+bc54 byal # Character ë±
+U+bc55 byalg # Character ë±
+U+bc56 byalm # Character ë±
+U+bc57 byalb # Character ë±
+U+bc58 byals # Character ë±
+U+bc59 byalt # Character ë±
+U+bc5a byalp # Character ë±
+U+bc5b byalh # Character ë±
+U+bc5c byam # Character ë±
+U+bc5d byab # Character ë±
+U+bc5e byabs # Character ë±
+U+bc5f byas # Character ë±
+U+bc60 byass # Character ë±
+U+bc61 byang # Character 뱡
+U+bc62 byaj # Character ë±¢
+U+bc63 byac # Character ë±£
+U+bc64 byak # Character 뱤
+U+bc65 byat # Character ë±¥
+U+bc66 byap # Character 뱦
+U+bc67 byah # Character 뱧
+U+bc68 byae # Character 뱨
+U+bc69 byaeg # Character 뱩
+U+bc6a byaegg # Character 뱪
+U+bc6b byaegs # Character 뱫
+U+bc6c byaen # Character 뱬
+U+bc6d byaenj # Character ë±
+U+bc6e byaenh # Character ë±®
+U+bc6f byaed # Character 뱯
+U+bc70 byael # Character ë±°
+U+bc71 byaelg # Character ë±±
+U+bc72 byaelm # Character ë±²
+U+bc73 byaelb # Character ë±³
+U+bc74 byaels # Character ë±´
+U+bc75 byaelt # Character ë±µ
+U+bc76 byaelp # Character 뱶
+U+bc77 byaelh # Character ë±·
+U+bc78 byaem # Character 뱸
+U+bc79 byaeb # Character ë±¹
+U+bc7a byaebs # Character 뱺
+U+bc7b byaes # Character ë±»
+U+bc7c byaess # Character ë±¼
+U+bc7d byaeng # Character ë±½
+U+bc7e byaej # Character ë±¾
+U+bc7f byaec # Character 뱿
+U+bc80 byaek # Character ë²
+U+bc81 byaet # Character ë²
+U+bc82 byaep # Character ë²
+U+bc83 byaeh # Character ë²
+U+bc84 beo # Character ë²
+U+bc85 beog # Character ë²
+U+bc86 beogg # Character ë²
+U+bc87 beogs # Character ë²
+U+bc88 beon # Character ë²
+U+bc89 beonj # Character ë²
+U+bc8a beonh # Character ë²
+U+bc8b beod # Character ë²
+U+bc8c beol # Character ë²
+U+bc8d beolg # Character ë²
+U+bc8e beolm # Character ë²
+U+bc8f beolb # Character ë²
+U+bc90 beols # Character ë²
+U+bc91 beolt # Character ë²
+U+bc92 beolp # Character ë²
+U+bc93 beolh # Character ë²
+U+bc94 beom # Character ë²
+U+bc95 beob # Character ë²
+U+bc96 beobs # Character ë²
+U+bc97 beos # Character ë²
+U+bc98 beoss # Character ë²
+U+bc99 beong # Character ë²
+U+bc9a beoj # Character ë²
+U+bc9b beoc # Character ë²
+U+bc9c beok # Character ë²
+U+bc9d beot # Character ë²
+U+bc9e beop # Character ë²
+U+bc9f beoh # Character ë²
+U+bca0 be # Character ë²
+U+bca1 beg # Character 벡
+U+bca2 begg # Character ë²¢
+U+bca3 begs # Character ë²£
+U+bca4 ben # Character 벤
+U+bca5 benj # Character ë²¥
+U+bca6 benh # Character 벦
+U+bca7 bed # Character 벧
+U+bca8 bel # Character 벨
+U+bca9 belg # Character 벩
+U+bcaa belm # Character 벪
+U+bcab belb # Character 벫
+U+bcac bels # Character 벬
+U+bcad belt # Character ë²
+U+bcae belp # Character ë²®
+U+bcaf belh # Character 벯
+U+bcb0 bem # Character ë²°
+U+bcb1 beb # Character ë²±
+U+bcb2 bebs # Character ë²²
+U+bcb3 bes # Character ë²³
+U+bcb4 bess # Character ë²´
+U+bcb5 beng # Character ë²µ
+U+bcb6 bej # Character 벶
+U+bcb7 bec # Character ë²·
+U+bcb8 bek # Character 벸
+U+bcb9 bet # Character ë²¹
+U+bcba bep # Character 벺
+U+bcbb beh # Character ë²»
+U+bcbc byeo # Character ë²¼
+U+bcbd byeog # Character ë²½
+U+bcbe byeogg # Character ë²¾
+U+bcbf byeogs # Character 벿
+U+bcc0 byeon # Character ë³
+U+bcc1 byeonj # Character ë³
+U+bcc2 byeonh # Character ë³
+U+bcc3 byeod # Character ë³
+U+bcc4 byeol # Character ë³
+U+bcc5 byeolg # Character ë³
+U+bcc6 byeolm # Character ë³
+U+bcc7 byeolb # Character ë³
+U+bcc8 byeols # Character ë³
+U+bcc9 byeolt # Character ë³
+U+bcca byeolp # Character ë³
+U+bccb byeolh # Character ë³
+U+bccc byeom # Character ë³
+U+bccd byeob # Character ë³
+U+bcce byeobs # Character ë³
+U+bccf byeos # Character ë³
+U+bcd0 byeoss # Character ë³
+U+bcd1 byeong # Character ë³
+U+bcd2 byeoj # Character ë³
+U+bcd3 byeoc # Character ë³
+U+bcd4 byeok # Character ë³
+U+bcd5 byeot # Character ë³
+U+bcd6 byeop # Character ë³
+U+bcd7 byeoh # Character ë³
+U+bcd8 bye # Character ë³
+U+bcd9 byeg # Character ë³
+U+bcda byegg # Character ë³
+U+bcdb byegs # Character ë³
+U+bcdc byen # Character ë³
+U+bcdd byenj # Character ë³
+U+bcde byenh # Character ë³
+U+bcdf byed # Character ë³
+U+bce0 byel # Character ë³
+U+bce1 byelg # Character 볡
+U+bce2 byelm # Character ë³¢
+U+bce3 byelb # Character ë³£
+U+bce4 byels # Character 볤
+U+bce5 byelt # Character ë³¥
+U+bce6 byelp # Character 볦
+U+bce7 byelh # Character 볧
+U+bce8 byem # Character 볨
+U+bce9 byeb # Character 볩
+U+bcea byebs # Character 볪
+U+bceb byes # Character 볫
+U+bcec byess # Character 볬
+U+bced byeng # Character ë³
+U+bcee byej # Character ë³®
+U+bcef byec # Character 볯
+U+bcf0 byek # Character ë³°
+U+bcf1 byet # Character ë³±
+U+bcf2 byep # Character ë³²
+U+bcf3 byeh # Character ë³³
+U+bcf4 bo # Character ë³´
+U+bcf5 bog # Character ë³µ
+U+bcf6 bogg # Character 볶
+U+bcf7 bogs # Character ë³·
+U+bcf8 bon # Character 본
+U+bcf9 bonj # Character ë³¹
+U+bcfa bonh # Character 볺
+U+bcfb bod # Character ë³»
+U+bcfc bol # Character ë³¼
+U+bcfd bolg # Character ë³½
+U+bcfe bolm # Character ë³¾
+U+bcff bolb # Character 볿
diff --git a/resources/chars/ascii/rowbd.trans b/resources/chars/ascii/rowbd.trans
new file mode 100644
index 0000000..3fb066e
--- /dev/null
+++ b/resources/chars/ascii/rowbd.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+bd00 bols # Character ë´
+U+bd01 bolt # Character ë´
+U+bd02 bolp # Character ë´
+U+bd03 bolh # Character ë´
+U+bd04 bom # Character ë´
+U+bd05 bob # Character ë´
+U+bd06 bobs # Character ë´
+U+bd07 bos # Character ë´
+U+bd08 boss # Character ë´
+U+bd09 bong # Character ë´
+U+bd0a boj # Character ë´
+U+bd0b boc # Character ë´
+U+bd0c bok # Character ë´
+U+bd0d bot # Character ë´
+U+bd0e bop # Character ë´
+U+bd0f boh # Character ë´
+U+bd10 bwa # Character ë´
+U+bd11 bwag # Character ë´
+U+bd12 bwagg # Character ë´
+U+bd13 bwags # Character ë´
+U+bd14 bwan # Character ë´
+U+bd15 bwanj # Character ë´
+U+bd16 bwanh # Character ë´
+U+bd17 bwad # Character ë´
+U+bd18 bwal # Character ë´
+U+bd19 bwalg # Character ë´
+U+bd1a bwalm # Character ë´
+U+bd1b bwalb # Character ë´
+U+bd1c bwals # Character ë´
+U+bd1d bwalt # Character ë´
+U+bd1e bwalp # Character ë´
+U+bd1f bwalh # Character ë´
+U+bd20 bwam # Character ë´
+U+bd21 bwab # Character ë´¡
+U+bd22 bwabs # Character ë´¢
+U+bd23 bwas # Character ë´£
+U+bd24 bwass # Character ë´¤
+U+bd25 bwang # Character ë´¥
+U+bd26 bwaj # Character ë´¦
+U+bd27 bwac # Character ë´§
+U+bd28 bwak # Character ë´¨
+U+bd29 bwat # Character ë´©
+U+bd2a bwap # Character ë´ª
+U+bd2b bwah # Character ë´«
+U+bd2c bwae # Character ë´¬
+U+bd2d bwaeg # Character ë´
+U+bd2e bwaegg # Character ë´®
+U+bd2f bwaegs # Character ë´¯
+U+bd30 bwaen # Character ë´°
+U+bd31 bwaenj # Character ë´±
+U+bd32 bwaenh # Character ë´²
+U+bd33 bwaed # Character ë´³
+U+bd34 bwael # Character ë´´
+U+bd35 bwaelg # Character ë´µ
+U+bd36 bwaelm # Character ë´¶
+U+bd37 bwaelb # Character ë´·
+U+bd38 bwaels # Character ë´¸
+U+bd39 bwaelt # Character ë´¹
+U+bd3a bwaelp # Character ë´º
+U+bd3b bwaelh # Character ë´»
+U+bd3c bwaem # Character ë´¼
+U+bd3d bwaeb # Character ë´½
+U+bd3e bwaebs # Character ë´¾
+U+bd3f bwaes # Character ë´¿
+U+bd40 bwaess # Character ëµ
+U+bd41 bwaeng # Character ëµ
+U+bd42 bwaej # Character ëµ
+U+bd43 bwaec # Character ëµ
+U+bd44 bwaek # Character ëµ
+U+bd45 bwaet # Character ëµ
+U+bd46 bwaep # Character ëµ
+U+bd47 bwaeh # Character ëµ
+U+bd48 boe # Character ëµ
+U+bd49 boeg # Character ëµ
+U+bd4a boegg # Character ëµ
+U+bd4b boegs # Character ëµ
+U+bd4c boen # Character ëµ
+U+bd4d boenj # Character ëµ
+U+bd4e boenh # Character ëµ
+U+bd4f boed # Character ëµ
+U+bd50 boel # Character ëµ
+U+bd51 boelg # Character ëµ
+U+bd52 boelm # Character ëµ
+U+bd53 boelb # Character ëµ
+U+bd54 boels # Character ëµ
+U+bd55 boelt # Character ëµ
+U+bd56 boelp # Character ëµ
+U+bd57 boelh # Character ëµ
+U+bd58 boem # Character ëµ
+U+bd59 boeb # Character ëµ
+U+bd5a boebs # Character ëµ
+U+bd5b boes # Character ëµ
+U+bd5c boess # Character ëµ
+U+bd5d boeng # Character ëµ
+U+bd5e boej # Character ëµ
+U+bd5f boec # Character ëµ
+U+bd60 boek # Character ëµ
+U+bd61 boet # Character 뵡
+U+bd62 boep # Character ëµ¢
+U+bd63 boeh # Character ëµ£
+U+bd64 byo # Character 뵤
+U+bd65 byog # Character ëµ¥
+U+bd66 byogg # Character 뵦
+U+bd67 byogs # Character 뵧
+U+bd68 byon # Character 뵨
+U+bd69 byonj # Character 뵩
+U+bd6a byonh # Character 뵪
+U+bd6b byod # Character 뵫
+U+bd6c byol # Character 뵬
+U+bd6d byolg # Character ëµ
+U+bd6e byolm # Character ëµ®
+U+bd6f byolb # Character 뵯
+U+bd70 byols # Character ëµ°
+U+bd71 byolt # Character ëµ±
+U+bd72 byolp # Character ëµ²
+U+bd73 byolh # Character ëµ³
+U+bd74 byom # Character ëµ´
+U+bd75 byob # Character ëµµ
+U+bd76 byobs # Character 뵶
+U+bd77 byos # Character ëµ·
+U+bd78 byoss # Character 뵸
+U+bd79 byong # Character ëµ¹
+U+bd7a byoj # Character 뵺
+U+bd7b byoc # Character ëµ»
+U+bd7c byok # Character ëµ¼
+U+bd7d byot # Character ëµ½
+U+bd7e byop # Character ëµ¾
+U+bd7f byoh # Character 뵿
+U+bd80 bu # Character ë¶
+U+bd81 bug # Character ë¶
+U+bd82 bugg # Character ë¶
+U+bd83 bugs # Character ë¶
+U+bd84 bun # Character ë¶
+U+bd85 bunj # Character ë¶
+U+bd86 bunh # Character ë¶
+U+bd87 bud # Character ë¶
+U+bd88 bul # Character ë¶
+U+bd89 bulg # Character ë¶
+U+bd8a bulm # Character ë¶
+U+bd8b bulb # Character ë¶
+U+bd8c buls # Character ë¶
+U+bd8d bult # Character ë¶
+U+bd8e bulp # Character ë¶
+U+bd8f bulh # Character ë¶
+U+bd90 bum # Character ë¶
+U+bd91 bub # Character ë¶
+U+bd92 bubs # Character ë¶
+U+bd93 bus # Character ë¶
+U+bd94 buss # Character ë¶
+U+bd95 bung # Character ë¶
+U+bd96 buj # Character ë¶
+U+bd97 buc # Character ë¶
+U+bd98 buk # Character ë¶
+U+bd99 but # Character ë¶
+U+bd9a bup # Character ë¶
+U+bd9b buh # Character ë¶
+U+bd9c bweo # Character ë¶
+U+bd9d bweog # Character ë¶
+U+bd9e bweogg # Character ë¶
+U+bd9f bweogs # Character ë¶
+U+bda0 bweon # Character ë¶
+U+bda1 bweonj # Character 붡
+U+bda2 bweonh # Character 붢
+U+bda3 bweod # Character 붣
+U+bda4 bweol # Character 붤
+U+bda5 bweolg # Character 붥
+U+bda6 bweolm # Character 붦
+U+bda7 bweolb # Character 붧
+U+bda8 bweols # Character 붨
+U+bda9 bweolt # Character 붩
+U+bdaa bweolp # Character 붪
+U+bdab bweolh # Character 붫
+U+bdac bweom # Character 붬
+U+bdad bweob # Character ë¶
+U+bdae bweobs # Character 붮
+U+bdaf bweos # Character 붯
+U+bdb0 bweoss # Character 붰
+U+bdb1 bweong # Character 붱
+U+bdb2 bweoj # Character 붲
+U+bdb3 bweoc # Character 붳
+U+bdb4 bweok # Character 붴
+U+bdb5 bweot # Character 붵
+U+bdb6 bweop # Character 붶
+U+bdb7 bweoh # Character 붷
+U+bdb8 bwe # Character 붸
+U+bdb9 bweg # Character 붹
+U+bdba bwegg # Character 붺
+U+bdbb bwegs # Character 붻
+U+bdbc bwen # Character 붼
+U+bdbd bwenj # Character 붽
+U+bdbe bwenh # Character 붾
+U+bdbf bwed # Character 붿
+U+bdc0 bwel # Character ë·
+U+bdc1 bwelg # Character ë·
+U+bdc2 bwelm # Character ë·
+U+bdc3 bwelb # Character ë·
+U+bdc4 bwels # Character ë·
+U+bdc5 bwelt # Character ë·
+U+bdc6 bwelp # Character ë·
+U+bdc7 bwelh # Character ë·
+U+bdc8 bwem # Character ë·
+U+bdc9 bweb # Character ë·
+U+bdca bwebs # Character ë·
+U+bdcb bwes # Character ë·
+U+bdcc bwess # Character ë·
+U+bdcd bweng # Character ë·
+U+bdce bwej # Character ë·
+U+bdcf bwec # Character ë·
+U+bdd0 bwek # Character ë·
+U+bdd1 bwet # Character ë·
+U+bdd2 bwep # Character ë·
+U+bdd3 bweh # Character ë·
+U+bdd4 bwi # Character ë·
+U+bdd5 bwig # Character ë·
+U+bdd6 bwigg # Character ë·
+U+bdd7 bwigs # Character ë·
+U+bdd8 bwin # Character ë·
+U+bdd9 bwinj # Character ë·
+U+bdda bwinh # Character ë·
+U+bddb bwid # Character ë·
+U+bddc bwil # Character ë·
+U+bddd bwilg # Character ë·
+U+bdde bwilm # Character ë·
+U+bddf bwilb # Character ë·
+U+bde0 bwils # Character ë·
+U+bde1 bwilt # Character ë·¡
+U+bde2 bwilp # Character ë·¢
+U+bde3 bwilh # Character ë·£
+U+bde4 bwim # Character ë·¤
+U+bde5 bwib # Character ë·¥
+U+bde6 bwibs # Character ë·¦
+U+bde7 bwis # Character ë·§
+U+bde8 bwiss # Character ë·¨
+U+bde9 bwing # Character ë·©
+U+bdea bwij # Character ë·ª
+U+bdeb bwic # Character ë·«
+U+bdec bwik # Character ë·¬
+U+bded bwit # Character ë·
+U+bdee bwip # Character ë·®
+U+bdef bwih # Character ë·¯
+U+bdf0 byu # Character ë·°
+U+bdf1 byug # Character ë·±
+U+bdf2 byugg # Character ë·²
+U+bdf3 byugs # Character ë·³
+U+bdf4 byun # Character ë·´
+U+bdf5 byunj # Character ë·µ
+U+bdf6 byunh # Character ë·¶
+U+bdf7 byud # Character ë··
+U+bdf8 byul # Character ë·¸
+U+bdf9 byulg # Character ë·¹
+U+bdfa byulm # Character ë·º
+U+bdfb byulb # Character ë·»
+U+bdfc byuls # Character ë·¼
+U+bdfd byult # Character ë·½
+U+bdfe byulp # Character ë·¾
+U+bdff byulh # Character ë·¿
diff --git a/resources/chars/ascii/rowbe.trans b/resources/chars/ascii/rowbe.trans
new file mode 100644
index 0000000..cbd7dda
--- /dev/null
+++ b/resources/chars/ascii/rowbe.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+be00 byum # Character ë¸
+U+be01 byub # Character ë¸
+U+be02 byubs # Character ë¸
+U+be03 byus # Character ë¸
+U+be04 byuss # Character ë¸
+U+be05 byung # Character ë¸
+U+be06 byuj # Character ë¸
+U+be07 byuc # Character ë¸
+U+be08 byuk # Character ë¸
+U+be09 byut # Character ë¸
+U+be0a byup # Character ë¸
+U+be0b byuh # Character ë¸
+U+be0c beu # Character ë¸
+U+be0d beug # Character ë¸
+U+be0e beugg # Character ë¸
+U+be0f beugs # Character ë¸
+U+be10 beun # Character ë¸
+U+be11 beunj # Character ë¸
+U+be12 beunh # Character ë¸
+U+be13 beud # Character ë¸
+U+be14 beul # Character ë¸
+U+be15 beulg # Character ë¸
+U+be16 beulm # Character ë¸
+U+be17 beulb # Character ë¸
+U+be18 beuls # Character ë¸
+U+be19 beult # Character ë¸
+U+be1a beulp # Character ë¸
+U+be1b beulh # Character ë¸
+U+be1c beum # Character ë¸
+U+be1d beub # Character ë¸
+U+be1e beubs # Character ë¸
+U+be1f beus # Character ë¸
+U+be20 beuss # Character ë¸
+U+be21 beung # Character 븡
+U+be22 beuj # Character 븢
+U+be23 beuc # Character 븣
+U+be24 beuk # Character 븤
+U+be25 beut # Character 븥
+U+be26 beup # Character 븦
+U+be27 beuh # Character 븧
+U+be28 byi # Character 븨
+U+be29 byig # Character 븩
+U+be2a byigg # Character 븪
+U+be2b byigs # Character 븫
+U+be2c byin # Character 븬
+U+be2d byinj # Character ë¸
+U+be2e byinh # Character 븮
+U+be2f byid # Character 븯
+U+be30 byil # Character 븰
+U+be31 byilg # Character 븱
+U+be32 byilm # Character 븲
+U+be33 byilb # Character 븳
+U+be34 byils # Character 븴
+U+be35 byilt # Character 븵
+U+be36 byilp # Character 븶
+U+be37 byilh # Character 븷
+U+be38 byim # Character 븸
+U+be39 byib # Character 븹
+U+be3a byibs # Character 븺
+U+be3b byis # Character 븻
+U+be3c byiss # Character 븼
+U+be3d bying # Character 븽
+U+be3e byij # Character 븾
+U+be3f byic # Character 븿
+U+be40 byik # Character ë¹
+U+be41 byit # Character ë¹
+U+be42 byip # Character ë¹
+U+be43 byih # Character ë¹
+U+be44 bi # Character ë¹
+U+be45 big # Character ë¹
+U+be46 bigg # Character ë¹
+U+be47 bigs # Character ë¹
+U+be48 bin # Character ë¹
+U+be49 binj # Character ë¹
+U+be4a binh # Character ë¹
+U+be4b bid # Character ë¹
+U+be4c bil # Character ë¹
+U+be4d bilg # Character ë¹
+U+be4e bilm # Character ë¹
+U+be4f bilb # Character ë¹
+U+be50 bils # Character ë¹
+U+be51 bilt # Character ë¹
+U+be52 bilp # Character ë¹
+U+be53 bilh # Character ë¹
+U+be54 bim # Character ë¹
+U+be55 bib # Character ë¹
+U+be56 bibs # Character ë¹
+U+be57 bis # Character ë¹
+U+be58 biss # Character ë¹
+U+be59 bing # Character ë¹
+U+be5a bij # Character ë¹
+U+be5b bic # Character ë¹
+U+be5c bik # Character ë¹
+U+be5d bit # Character ë¹
+U+be5e bip # Character ë¹
+U+be5f bih # Character ë¹
+U+be60 bba # Character ë¹
+U+be61 bbag # Character 빡
+U+be62 bbagg # Character ë¹¢
+U+be63 bbags # Character ë¹£
+U+be64 bban # Character 빤
+U+be65 bbanj # Character ë¹¥
+U+be66 bbanh # Character 빦
+U+be67 bbad # Character 빧
+U+be68 bbal # Character 빨
+U+be69 bbalg # Character 빩
+U+be6a bbalm # Character 빪
+U+be6b bbalb # Character 빫
+U+be6c bbals # Character 빬
+U+be6d bbalt # Character ë¹
+U+be6e bbalp # Character ë¹®
+U+be6f bbalh # Character 빯
+U+be70 bbam # Character ë¹°
+U+be71 bbab # Character ë¹±
+U+be72 bbabs # Character ë¹²
+U+be73 bbas # Character ë¹³
+U+be74 bbass # Character ë¹´
+U+be75 bbang # Character ë¹µ
+U+be76 bbaj # Character 빶
+U+be77 bbac # Character ë¹·
+U+be78 bbak # Character 빸
+U+be79 bbat # Character ë¹¹
+U+be7a bbap # Character 빺
+U+be7b bbah # Character ë¹»
+U+be7c bbae # Character ë¹¼
+U+be7d bbaeg # Character ë¹½
+U+be7e bbaegg # Character ë¹¾
+U+be7f bbaegs # Character 빿
+U+be80 bbaen # Character ëº
+U+be81 bbaenj # Character ëº
+U+be82 bbaenh # Character ëº
+U+be83 bbaed # Character ëº
+U+be84 bbael # Character ëº
+U+be85 bbaelg # Character ëº
+U+be86 bbaelm # Character ëº
+U+be87 bbaelb # Character ëº
+U+be88 bbaels # Character ëº
+U+be89 bbaelt # Character ëº
+U+be8a bbaelp # Character ëº
+U+be8b bbaelh # Character ëº
+U+be8c bbaem # Character ëº
+U+be8d bbaeb # Character ëº
+U+be8e bbaebs # Character ëº
+U+be8f bbaes # Character ëº
+U+be90 bbaess # Character ëº
+U+be91 bbaeng # Character ëº
+U+be92 bbaej # Character ëº
+U+be93 bbaec # Character ëº
+U+be94 bbaek # Character ëº
+U+be95 bbaet # Character ëº
+U+be96 bbaep # Character ëº
+U+be97 bbaeh # Character ëº
+U+be98 bbya # Character ëº
+U+be99 bbyag # Character ëº
+U+be9a bbyagg # Character ëº
+U+be9b bbyags # Character ëº
+U+be9c bbyan # Character ëº
+U+be9d bbyanj # Character ëº
+U+be9e bbyanh # Character ëº
+U+be9f bbyad # Character ëº
+U+bea0 bbyal # Character ëº
+U+bea1 bbyalg # Character 뺡
+U+bea2 bbyalm # Character 뺢
+U+bea3 bbyalb # Character 뺣
+U+bea4 bbyals # Character 뺤
+U+bea5 bbyalt # Character 뺥
+U+bea6 bbyalp # Character 뺦
+U+bea7 bbyalh # Character 뺧
+U+bea8 bbyam # Character 뺨
+U+bea9 bbyab # Character 뺩
+U+beaa bbyabs # Character 뺪
+U+beab bbyas # Character 뺫
+U+beac bbyass # Character 뺬
+U+bead bbyang # Character ëº
+U+beae bbyaj # Character 뺮
+U+beaf bbyac # Character 뺯
+U+beb0 bbyak # Character 뺰
+U+beb1 bbyat # Character 뺱
+U+beb2 bbyap # Character 뺲
+U+beb3 bbyah # Character 뺳
+U+beb4 bbyae # Character 뺴
+U+beb5 bbyaeg # Character 뺵
+U+beb6 bbyaegg # Character 뺶
+U+beb7 bbyaegs # Character 뺷
+U+beb8 bbyaen # Character 뺸
+U+beb9 bbyaenj # Character 뺹
+U+beba bbyaenh # Character 뺺
+U+bebb bbyaed # Character 뺻
+U+bebc bbyael # Character 뺼
+U+bebd bbyaelg # Character 뺽
+U+bebe bbyaelm # Character 뺾
+U+bebf bbyaelb # Character 뺿
+U+bec0 bbyaels # Character ë»
+U+bec1 bbyaelt # Character ë»
+U+bec2 bbyaelp # Character ë»
+U+bec3 bbyaelh # Character ë»
+U+bec4 bbyaem # Character ë»
+U+bec5 bbyaeb # Character ë»
+U+bec6 bbyaebs # Character ë»
+U+bec7 bbyaes # Character ë»
+U+bec8 bbyaess # Character ë»
+U+bec9 bbyaeng # Character ë»
+U+beca bbyaej # Character ë»
+U+becb bbyaec # Character ë»
+U+becc bbyaek # Character ë»
+U+becd bbyaet # Character ë»
+U+bece bbyaep # Character ë»
+U+becf bbyaeh # Character ë»
+U+bed0 bbeo # Character ë»
+U+bed1 bbeog # Character ë»
+U+bed2 bbeogg # Character ë»
+U+bed3 bbeogs # Character ë»
+U+bed4 bbeon # Character ë»
+U+bed5 bbeonj # Character ë»
+U+bed6 bbeonh # Character ë»
+U+bed7 bbeod # Character ë»
+U+bed8 bbeol # Character ë»
+U+bed9 bbeolg # Character ë»
+U+beda bbeolm # Character ë»
+U+bedb bbeolb # Character ë»
+U+bedc bbeols # Character ë»
+U+bedd bbeolt # Character ë»
+U+bede bbeolp # Character ë»
+U+bedf bbeolh # Character ë»
+U+bee0 bbeom # Character ë»
+U+bee1 bbeob # Character 뻡
+U+bee2 bbeobs # Character 뻢
+U+bee3 bbeos # Character 뻣
+U+bee4 bbeoss # Character 뻤
+U+bee5 bbeong # Character 뻥
+U+bee6 bbeoj # Character 뻦
+U+bee7 bbeoc # Character 뻧
+U+bee8 bbeok # Character 뻨
+U+bee9 bbeot # Character 뻩
+U+beea bbeop # Character 뻪
+U+beeb bbeoh # Character 뻫
+U+beec bbe # Character 뻬
+U+beed bbeg # Character ë»
+U+beee bbegg # Character ë»®
+U+beef bbegs # Character 뻯
+U+bef0 bben # Character ë»°
+U+bef1 bbenj # Character ë»±
+U+bef2 bbenh # Character 뻲
+U+bef3 bbed # Character 뻳
+U+bef4 bbel # Character ë»´
+U+bef5 bbelg # Character 뻵
+U+bef6 bbelm # Character 뻶
+U+bef7 bbelb # Character ë»·
+U+bef8 bbels # Character 뻸
+U+bef9 bbelt # Character 뻹
+U+befa bbelp # Character 뻺
+U+befb bbelh # Character ë»»
+U+befc bbem # Character 뻼
+U+befd bbeb # Character 뻽
+U+befe bbebs # Character 뻾
+U+beff bbes # Character 뻿
diff --git a/resources/chars/ascii/rowbf.trans b/resources/chars/ascii/rowbf.trans
new file mode 100644
index 0000000..a7c1254
--- /dev/null
+++ b/resources/chars/ascii/rowbf.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+bf00 bbess # Character ë¼
+U+bf01 bbeng # Character ë¼
+U+bf02 bbej # Character ë¼
+U+bf03 bbec # Character ë¼
+U+bf04 bbek # Character ë¼
+U+bf05 bbet # Character ë¼
+U+bf06 bbep # Character ë¼
+U+bf07 bbeh # Character ë¼
+U+bf08 bbyeo # Character ë¼
+U+bf09 bbyeog # Character ë¼
+U+bf0a bbyeogg # Character ë¼
+U+bf0b bbyeogs # Character ë¼
+U+bf0c bbyeon # Character ë¼
+U+bf0d bbyeonj # Character ë¼
+U+bf0e bbyeonh # Character ë¼
+U+bf0f bbyeod # Character ë¼
+U+bf10 bbyeol # Character ë¼
+U+bf11 bbyeolg # Character ë¼
+U+bf12 bbyeolm # Character ë¼
+U+bf13 bbyeolb # Character ë¼
+U+bf14 bbyeols # Character ë¼
+U+bf15 bbyeolt # Character ë¼
+U+bf16 bbyeolp # Character ë¼
+U+bf17 bbyeolh # Character ë¼
+U+bf18 bbyeom # Character ë¼
+U+bf19 bbyeob # Character ë¼
+U+bf1a bbyeobs # Character ë¼
+U+bf1b bbyeos # Character ë¼
+U+bf1c bbyeoss # Character ë¼
+U+bf1d bbyeong # Character ë¼
+U+bf1e bbyeoj # Character ë¼
+U+bf1f bbyeoc # Character ë¼
+U+bf20 bbyeok # Character ë¼
+U+bf21 bbyeot # Character 뼡
+U+bf22 bbyeop # Character ë¼¢
+U+bf23 bbyeoh # Character ë¼£
+U+bf24 bbye # Character 뼤
+U+bf25 bbyeg # Character ë¼¥
+U+bf26 bbyegg # Character 뼦
+U+bf27 bbyegs # Character 뼧
+U+bf28 bbyen # Character 뼨
+U+bf29 bbyenj # Character 뼩
+U+bf2a bbyenh # Character 뼪
+U+bf2b bbyed # Character 뼫
+U+bf2c bbyel # Character 뼬
+U+bf2d bbyelg # Character ë¼
+U+bf2e bbyelm # Character ë¼®
+U+bf2f bbyelb # Character 뼯
+U+bf30 bbyels # Character ë¼°
+U+bf31 bbyelt # Character ë¼±
+U+bf32 bbyelp # Character ë¼²
+U+bf33 bbyelh # Character ë¼³
+U+bf34 bbyem # Character ë¼´
+U+bf35 bbyeb # Character ë¼µ
+U+bf36 bbyebs # Character 뼶
+U+bf37 bbyes # Character ë¼·
+U+bf38 bbyess # Character 뼸
+U+bf39 bbyeng # Character ë¼¹
+U+bf3a bbyej # Character 뼺
+U+bf3b bbyec # Character ë¼»
+U+bf3c bbyek # Character ë¼¼
+U+bf3d bbyet # Character ë¼½
+U+bf3e bbyep # Character ë¼¾
+U+bf3f bbyeh # Character 뼿
+U+bf40 bbo # Character ë½
+U+bf41 bbog # Character ë½
+U+bf42 bbogg # Character ë½
+U+bf43 bbogs # Character ë½
+U+bf44 bbon # Character ë½
+U+bf45 bbonj # Character ë½
+U+bf46 bbonh # Character ë½
+U+bf47 bbod # Character ë½
+U+bf48 bbol # Character ë½
+U+bf49 bbolg # Character ë½
+U+bf4a bbolm # Character ë½
+U+bf4b bbolb # Character ë½
+U+bf4c bbols # Character ë½
+U+bf4d bbolt # Character ë½
+U+bf4e bbolp # Character ë½
+U+bf4f bbolh # Character ë½
+U+bf50 bbom # Character ë½
+U+bf51 bbob # Character ë½
+U+bf52 bbobs # Character ë½
+U+bf53 bbos # Character ë½
+U+bf54 bboss # Character ë½
+U+bf55 bbong # Character ë½
+U+bf56 bboj # Character ë½
+U+bf57 bboc # Character ë½
+U+bf58 bbok # Character ë½
+U+bf59 bbot # Character ë½
+U+bf5a bbop # Character ë½
+U+bf5b bboh # Character ë½
+U+bf5c bbwa # Character ë½
+U+bf5d bbwag # Character ë½
+U+bf5e bbwagg # Character ë½
+U+bf5f bbwags # Character ë½
+U+bf60 bbwan # Character ë½
+U+bf61 bbwanj # Character 뽡
+U+bf62 bbwanh # Character ë½¢
+U+bf63 bbwad # Character ë½£
+U+bf64 bbwal # Character 뽤
+U+bf65 bbwalg # Character ë½¥
+U+bf66 bbwalm # Character 뽦
+U+bf67 bbwalb # Character 뽧
+U+bf68 bbwals # Character 뽨
+U+bf69 bbwalt # Character 뽩
+U+bf6a bbwalp # Character 뽪
+U+bf6b bbwalh # Character 뽫
+U+bf6c bbwam # Character 뽬
+U+bf6d bbwab # Character ë½
+U+bf6e bbwabs # Character ë½®
+U+bf6f bbwas # Character 뽯
+U+bf70 bbwass # Character ë½°
+U+bf71 bbwang # Character ë½±
+U+bf72 bbwaj # Character ë½²
+U+bf73 bbwac # Character ë½³
+U+bf74 bbwak # Character ë½´
+U+bf75 bbwat # Character ë½µ
+U+bf76 bbwap # Character 뽶
+U+bf77 bbwah # Character ë½·
+U+bf78 bbwae # Character 뽸
+U+bf79 bbwaeg # Character ë½¹
+U+bf7a bbwaegg # Character 뽺
+U+bf7b bbwaegs # Character ë½»
+U+bf7c bbwaen # Character ë½¼
+U+bf7d bbwaenj # Character ë½½
+U+bf7e bbwaenh # Character ë½¾
+U+bf7f bbwaed # Character 뽿
+U+bf80 bbwael # Character ë¾
+U+bf81 bbwaelg # Character ë¾
+U+bf82 bbwaelm # Character ë¾
+U+bf83 bbwaelb # Character ë¾
+U+bf84 bbwaels # Character ë¾
+U+bf85 bbwaelt # Character ë¾
+U+bf86 bbwaelp # Character ë¾
+U+bf87 bbwaelh # Character ë¾
+U+bf88 bbwaem # Character ë¾
+U+bf89 bbwaeb # Character ë¾
+U+bf8a bbwaebs # Character ë¾
+U+bf8b bbwaes # Character ë¾
+U+bf8c bbwaess # Character ë¾
+U+bf8d bbwaeng # Character ë¾
+U+bf8e bbwaej # Character ë¾
+U+bf8f bbwaec # Character ë¾
+U+bf90 bbwaek # Character ë¾
+U+bf91 bbwaet # Character ë¾
+U+bf92 bbwaep # Character ë¾
+U+bf93 bbwaeh # Character ë¾
+U+bf94 bboe # Character ë¾
+U+bf95 bboeg # Character ë¾
+U+bf96 bboegg # Character ë¾
+U+bf97 bboegs # Character ë¾
+U+bf98 bboen # Character ë¾
+U+bf99 bboenj # Character ë¾
+U+bf9a bboenh # Character ë¾
+U+bf9b bboed # Character ë¾
+U+bf9c bboel # Character ë¾
+U+bf9d bboelg # Character ë¾
+U+bf9e bboelm # Character ë¾
+U+bf9f bboelb # Character ë¾
+U+bfa0 bboels # Character ë¾
+U+bfa1 bboelt # Character 뾡
+U+bfa2 bboelp # Character ë¾¢
+U+bfa3 bboelh # Character ë¾£
+U+bfa4 bboem # Character 뾤
+U+bfa5 bboeb # Character ë¾¥
+U+bfa6 bboebs # Character 뾦
+U+bfa7 bboes # Character 뾧
+U+bfa8 bboess # Character 뾨
+U+bfa9 bboeng # Character 뾩
+U+bfaa bboej # Character 뾪
+U+bfab bboec # Character 뾫
+U+bfac bboek # Character 뾬
+U+bfad bboet # Character ë¾
+U+bfae bboep # Character ë¾®
+U+bfaf bboeh # Character 뾯
+U+bfb0 bbyo # Character ë¾°
+U+bfb1 bbyog # Character ë¾±
+U+bfb2 bbyogg # Character ë¾²
+U+bfb3 bbyogs # Character ë¾³
+U+bfb4 bbyon # Character ë¾´
+U+bfb5 bbyonj # Character ë¾µ
+U+bfb6 bbyonh # Character 뾶
+U+bfb7 bbyod # Character ë¾·
+U+bfb8 bbyol # Character 뾸
+U+bfb9 bbyolg # Character ë¾¹
+U+bfba bbyolm # Character 뾺
+U+bfbb bbyolb # Character ë¾»
+U+bfbc bbyols # Character ë¾¼
+U+bfbd bbyolt # Character ë¾½
+U+bfbe bbyolp # Character ë¾¾
+U+bfbf bbyolh # Character 뾿
+U+bfc0 bbyom # Character ë¿
+U+bfc1 bbyob # Character ë¿
+U+bfc2 bbyobs # Character ë¿
+U+bfc3 bbyos # Character ë¿
+U+bfc4 bbyoss # Character ë¿
+U+bfc5 bbyong # Character ë¿
+U+bfc6 bbyoj # Character ë¿
+U+bfc7 bbyoc # Character ë¿
+U+bfc8 bbyok # Character ë¿
+U+bfc9 bbyot # Character ë¿
+U+bfca bbyop # Character ë¿
+U+bfcb bbyoh # Character ë¿
+U+bfcc bbu # Character ë¿
+U+bfcd bbug # Character ë¿
+U+bfce bbugg # Character ë¿
+U+bfcf bbugs # Character ë¿
+U+bfd0 bbun # Character ë¿
+U+bfd1 bbunj # Character ë¿
+U+bfd2 bbunh # Character ë¿
+U+bfd3 bbud # Character ë¿
+U+bfd4 bbul # Character ë¿
+U+bfd5 bbulg # Character ë¿
+U+bfd6 bbulm # Character ë¿
+U+bfd7 bbulb # Character ë¿
+U+bfd8 bbuls # Character ë¿
+U+bfd9 bbult # Character ë¿
+U+bfda bbulp # Character ë¿
+U+bfdb bbulh # Character ë¿
+U+bfdc bbum # Character ë¿
+U+bfdd bbub # Character ë¿
+U+bfde bbubs # Character ë¿
+U+bfdf bbus # Character ë¿
+U+bfe0 bbuss # Character ë¿
+U+bfe1 bbung # Character ë¿¡
+U+bfe2 bbuj # Character ë¿¢
+U+bfe3 bbuc # Character ë¿£
+U+bfe4 bbuk # Character 뿤
+U+bfe5 bbut # Character ë¿¥
+U+bfe6 bbup # Character 뿦
+U+bfe7 bbuh # Character 뿧
+U+bfe8 bbweo # Character 뿨
+U+bfe9 bbweog # Character ë¿©
+U+bfea bbweogg # Character 뿪
+U+bfeb bbweogs # Character ë¿«
+U+bfec bbweon # Character 뿬
+U+bfed bbweonj # Character ë¿
+U+bfee bbweonh # Character ë¿®
+U+bfef bbweod # Character 뿯
+U+bff0 bbweol # Character ë¿°
+U+bff1 bbweolg # Character 뿱
+U+bff2 bbweolm # Character 뿲
+U+bff3 bbweolb # Character 뿳
+U+bff4 bbweols # Character ë¿´
+U+bff5 bbweolt # Character 뿵
+U+bff6 bbweolp # Character 뿶
+U+bff7 bbweolh # Character ë¿·
+U+bff8 bbweom # Character 뿸
+U+bff9 bbweob # Character 뿹
+U+bffa bbweobs # Character 뿺
+U+bffb bbweos # Character ë¿»
+U+bffc bbweoss # Character 뿼
+U+bffd bbweong # Character 뿽
+U+bffe bbweoj # Character 뿾
+U+bfff bbweoc # Character ë¿¿
diff --git a/resources/chars/ascii/rowc0.trans b/resources/chars/ascii/rowc0.trans
new file mode 100644
index 0000000..75d8c85
--- /dev/null
+++ b/resources/chars/ascii/rowc0.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+c000 bbweok # Character ì
+U+c001 bbweot # Character ì
+U+c002 bbweop # Character ì
+U+c003 bbweoh # Character ì
+U+c004 bbwe # Character ì
+U+c005 bbweg # Character ì
+U+c006 bbwegg # Character ì
+U+c007 bbwegs # Character ì
+U+c008 bbwen # Character ì
+U+c009 bbwenj # Character ì
+U+c00a bbwenh # Character ì
+U+c00b bbwed # Character ì
+U+c00c bbwel # Character ì
+U+c00d bbwelg # Character ì
+U+c00e bbwelm # Character ì
+U+c00f bbwelb # Character ì
+U+c010 bbwels # Character ì
+U+c011 bbwelt # Character ì
+U+c012 bbwelp # Character ì
+U+c013 bbwelh # Character ì
+U+c014 bbwem # Character ì
+U+c015 bbweb # Character ì
+U+c016 bbwebs # Character ì
+U+c017 bbwes # Character ì
+U+c018 bbwess # Character ì
+U+c019 bbweng # Character ì
+U+c01a bbwej # Character ì
+U+c01b bbwec # Character ì
+U+c01c bbwek # Character ì
+U+c01d bbwet # Character ì
+U+c01e bbwep # Character ì
+U+c01f bbweh # Character ì
+U+c020 bbwi # Character ì
+U+c021 bbwig # Character ì¡
+U+c022 bbwigg # Character ì¢
+U+c023 bbwigs # Character ì£
+U+c024 bbwin # Character ì¤
+U+c025 bbwinj # Character ì¥
+U+c026 bbwinh # Character ì¦
+U+c027 bbwid # Character ì§
+U+c028 bbwil # Character ì¨
+U+c029 bbwilg # Character ì©
+U+c02a bbwilm # Character ìª
+U+c02b bbwilb # Character ì«
+U+c02c bbwils # Character ì¬
+U+c02d bbwilt # Character ì
+U+c02e bbwilp # Character ì®
+U+c02f bbwilh # Character ì¯
+U+c030 bbwim # Character ì°
+U+c031 bbwib # Character ì±
+U+c032 bbwibs # Character ì²
+U+c033 bbwis # Character ì³
+U+c034 bbwiss # Character ì´
+U+c035 bbwing # Character ìµ
+U+c036 bbwij # Character ì¶
+U+c037 bbwic # Character ì·
+U+c038 bbwik # Character ì¸
+U+c039 bbwit # Character ì¹
+U+c03a bbwip # Character ìº
+U+c03b bbwih # Character ì»
+U+c03c bbyu # Character ì¼
+U+c03d bbyug # Character ì½
+U+c03e bbyugg # Character ì¾
+U+c03f bbyugs # Character ì¿
+U+c040 bbyun # Character ì
+U+c041 bbyunj # Character ì
+U+c042 bbyunh # Character ì
+U+c043 bbyud # Character ì
+U+c044 bbyul # Character ì
+U+c045 bbyulg # Character ì
+U+c046 bbyulm # Character ì
+U+c047 bbyulb # Character ì
+U+c048 bbyuls # Character ì
+U+c049 bbyult # Character ì
+U+c04a bbyulp # Character ì
+U+c04b bbyulh # Character ì
+U+c04c bbyum # Character ì
+U+c04d bbyub # Character ì
+U+c04e bbyubs # Character ì
+U+c04f bbyus # Character ì
+U+c050 bbyuss # Character ì
+U+c051 bbyung # Character ì
+U+c052 bbyuj # Character ì
+U+c053 bbyuc # Character ì
+U+c054 bbyuk # Character ì
+U+c055 bbyut # Character ì
+U+c056 bbyup # Character ì
+U+c057 bbyuh # Character ì
+U+c058 bbeu # Character ì
+U+c059 bbeug # Character ì
+U+c05a bbeugg # Character ì
+U+c05b bbeugs # Character ì
+U+c05c bbeun # Character ì
+U+c05d bbeunj # Character ì
+U+c05e bbeunh # Character ì
+U+c05f bbeud # Character ì
+U+c060 bbeul # Character ì
+U+c061 bbeulg # Character ì¡
+U+c062 bbeulm # Character ì¢
+U+c063 bbeulb # Character ì£
+U+c064 bbeuls # Character ì¤
+U+c065 bbeult # Character ì¥
+U+c066 bbeulp # Character ì¦
+U+c067 bbeulh # Character ì§
+U+c068 bbeum # Character ì¨
+U+c069 bbeub # Character ì©
+U+c06a bbeubs # Character ìª
+U+c06b bbeus # Character ì«
+U+c06c bbeuss # Character ì¬
+U+c06d bbeung # Character ì
+U+c06e bbeuj # Character ì®
+U+c06f bbeuc # Character ì¯
+U+c070 bbeuk # Character ì°
+U+c071 bbeut # Character ì±
+U+c072 bbeup # Character ì²
+U+c073 bbeuh # Character ì³
+U+c074 bbyi # Character ì´
+U+c075 bbyig # Character ìµ
+U+c076 bbyigg # Character ì¶
+U+c077 bbyigs # Character ì·
+U+c078 bbyin # Character ì¸
+U+c079 bbyinj # Character ì¹
+U+c07a bbyinh # Character ìº
+U+c07b bbyid # Character ì»
+U+c07c bbyil # Character ì¼
+U+c07d bbyilg # Character ì½
+U+c07e bbyilm # Character ì¾
+U+c07f bbyilb # Character ì¿
+U+c080 bbyils # Character ì
+U+c081 bbyilt # Character ì
+U+c082 bbyilp # Character ì
+U+c083 bbyilh # Character ì
+U+c084 bbyim # Character ì
+U+c085 bbyib # Character ì
+U+c086 bbyibs # Character ì
+U+c087 bbyis # Character ì
+U+c088 bbyiss # Character ì
+U+c089 bbying # Character ì
+U+c08a bbyij # Character ì
+U+c08b bbyic # Character ì
+U+c08c bbyik # Character ì
+U+c08d bbyit # Character ì
+U+c08e bbyip # Character ì
+U+c08f bbyih # Character ì
+U+c090 bbi # Character ì
+U+c091 bbig # Character ì
+U+c092 bbigg # Character ì
+U+c093 bbigs # Character ì
+U+c094 bbin # Character ì
+U+c095 bbinj # Character ì
+U+c096 bbinh # Character ì
+U+c097 bbid # Character ì
+U+c098 bbil # Character ì
+U+c099 bbilg # Character ì
+U+c09a bbilm # Character ì
+U+c09b bbilb # Character ì
+U+c09c bbils # Character ì
+U+c09d bbilt # Character ì
+U+c09e bbilp # Character ì
+U+c09f bbilh # Character ì
+U+c0a0 bbim # Character ì
+U+c0a1 bbib # Character ì¡
+U+c0a2 bbibs # Character ì¢
+U+c0a3 bbis # Character ì£
+U+c0a4 bbiss # Character ì¤
+U+c0a5 bbing # Character ì¥
+U+c0a6 bbij # Character ì¦
+U+c0a7 bbic # Character ì§
+U+c0a8 bbik # Character ì¨
+U+c0a9 bbit # Character ì©
+U+c0aa bbip # Character ìª
+U+c0ab bbih # Character ì«
+U+c0ac sa # Character ì¬
+U+c0ad sag # Character ì
+U+c0ae sagg # Character ì®
+U+c0af sags # Character ì¯
+U+c0b0 san # Character ì°
+U+c0b1 sanj # Character ì±
+U+c0b2 sanh # Character ì²
+U+c0b3 sad # Character ì³
+U+c0b4 sal # Character ì´
+U+c0b5 salg # Character ìµ
+U+c0b6 salm # Character ì¶
+U+c0b7 salb # Character ì·
+U+c0b8 sals # Character ì¸
+U+c0b9 salt # Character ì¹
+U+c0ba salp # Character ìº
+U+c0bb salh # Character ì»
+U+c0bc sam # Character ì¼
+U+c0bd sab # Character ì½
+U+c0be sabs # Character ì¾
+U+c0bf sas # Character ì¿
+U+c0c0 sass # Character ì
+U+c0c1 sang # Character ì
+U+c0c2 saj # Character ì
+U+c0c3 sac # Character ì
+U+c0c4 sak # Character ì
+U+c0c5 sat # Character ì
+U+c0c6 sap # Character ì
+U+c0c7 sah # Character ì
+U+c0c8 sae # Character ì
+U+c0c9 saeg # Character ì
+U+c0ca saegg # Character ì
+U+c0cb saegs # Character ì
+U+c0cc saen # Character ì
+U+c0cd saenj # Character ì
+U+c0ce saenh # Character ì
+U+c0cf saed # Character ì
+U+c0d0 sael # Character ì
+U+c0d1 saelg # Character ì
+U+c0d2 saelm # Character ì
+U+c0d3 saelb # Character ì
+U+c0d4 saels # Character ì
+U+c0d5 saelt # Character ì
+U+c0d6 saelp # Character ì
+U+c0d7 saelh # Character ì
+U+c0d8 saem # Character ì
+U+c0d9 saeb # Character ì
+U+c0da saebs # Character ì
+U+c0db saes # Character ì
+U+c0dc saess # Character ì
+U+c0dd saeng # Character ì
+U+c0de saej # Character ì
+U+c0df saec # Character ì
+U+c0e0 saek # Character ì
+U+c0e1 saet # Character ì¡
+U+c0e2 saep # Character ì¢
+U+c0e3 saeh # Character ì£
+U+c0e4 sya # Character ì¤
+U+c0e5 syag # Character ì¥
+U+c0e6 syagg # Character ì¦
+U+c0e7 syags # Character ì§
+U+c0e8 syan # Character ì¨
+U+c0e9 syanj # Character ì©
+U+c0ea syanh # Character ìª
+U+c0eb syad # Character ì«
+U+c0ec syal # Character ì¬
+U+c0ed syalg # Character ì
+U+c0ee syalm # Character ì®
+U+c0ef syalb # Character ì¯
+U+c0f0 syals # Character ì°
+U+c0f1 syalt # Character ì±
+U+c0f2 syalp # Character ì²
+U+c0f3 syalh # Character ì³
+U+c0f4 syam # Character ì´
+U+c0f5 syab # Character ìµ
+U+c0f6 syabs # Character ì¶
+U+c0f7 syas # Character ì·
+U+c0f8 syass # Character ì¸
+U+c0f9 syang # Character ì¹
+U+c0fa syaj # Character ìº
+U+c0fb syac # Character ì»
+U+c0fc syak # Character ì¼
+U+c0fd syat # Character ì½
+U+c0fe syap # Character ì¾
+U+c0ff syah # Character ì¿
diff --git a/resources/chars/ascii/rowc1.trans b/resources/chars/ascii/rowc1.trans
new file mode 100644
index 0000000..6d77372
--- /dev/null
+++ b/resources/chars/ascii/rowc1.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+c100 syae # Character ì
+U+c101 syaeg # Character ì
+U+c102 syaegg # Character ì
+U+c103 syaegs # Character ì
+U+c104 syaen # Character ì
+U+c105 syaenj # Character ì
+U+c106 syaenh # Character ì
+U+c107 syaed # Character ì
+U+c108 syael # Character ì
+U+c109 syaelg # Character ì
+U+c10a syaelm # Character ì
+U+c10b syaelb # Character ì
+U+c10c syaels # Character ì
+U+c10d syaelt # Character ì
+U+c10e syaelp # Character ì
+U+c10f syaelh # Character ì
+U+c110 syaem # Character ì
+U+c111 syaeb # Character ì
+U+c112 syaebs # Character ì
+U+c113 syaes # Character ì
+U+c114 syaess # Character ì
+U+c115 syaeng # Character ì
+U+c116 syaej # Character ì
+U+c117 syaec # Character ì
+U+c118 syaek # Character ì
+U+c119 syaet # Character ì
+U+c11a syaep # Character ì
+U+c11b syaeh # Character ì
+U+c11c seo # Character ì
+U+c11d seog # Character ì
+U+c11e seogg # Character ì
+U+c11f seogs # Character ì
+U+c120 seon # Character ì
+U+c121 seonj # Character ì¡
+U+c122 seonh # Character ì¢
+U+c123 seod # Character ì£
+U+c124 seol # Character ì¤
+U+c125 seolg # Character ì¥
+U+c126 seolm # Character ì¦
+U+c127 seolb # Character ì§
+U+c128 seols # Character ì¨
+U+c129 seolt # Character ì©
+U+c12a seolp # Character ìª
+U+c12b seolh # Character ì«
+U+c12c seom # Character ì¬
+U+c12d seob # Character ì
+U+c12e seobs # Character ì®
+U+c12f seos # Character ì¯
+U+c130 seoss # Character ì°
+U+c131 seong # Character ì±
+U+c132 seoj # Character ì²
+U+c133 seoc # Character ì³
+U+c134 seok # Character ì´
+U+c135 seot # Character ìµ
+U+c136 seop # Character ì¶
+U+c137 seoh # Character ì·
+U+c138 se # Character ì¸
+U+c139 seg # Character ì¹
+U+c13a segg # Character ìº
+U+c13b segs # Character ì»
+U+c13c sen # Character ì¼
+U+c13d senj # Character ì½
+U+c13e senh # Character ì¾
+U+c13f sed # Character ì¿
+U+c140 sel # Character ì
+U+c141 selg # Character ì
+U+c142 selm # Character ì
+U+c143 selb # Character ì
+U+c144 sels # Character ì
+U+c145 selt # Character ì
+U+c146 selp # Character ì
+U+c147 selh # Character ì
+U+c148 sem # Character ì
+U+c149 seb # Character ì
+U+c14a sebs # Character ì
+U+c14b ses # Character ì
+U+c14c sess # Character ì
+U+c14d seng # Character ì
+U+c14e sej # Character ì
+U+c14f sec # Character ì
+U+c150 sek # Character ì
+U+c151 set # Character ì
+U+c152 sep # Character ì
+U+c153 seh # Character ì
+U+c154 syeo # Character ì
+U+c155 syeog # Character ì
+U+c156 syeogg # Character ì
+U+c157 syeogs # Character ì
+U+c158 syeon # Character ì
+U+c159 syeonj # Character ì
+U+c15a syeonh # Character ì
+U+c15b syeod # Character ì
+U+c15c syeol # Character ì
+U+c15d syeolg # Character ì
+U+c15e syeolm # Character ì
+U+c15f syeolb # Character ì
+U+c160 syeols # Character ì
+U+c161 syeolt # Character ì
¡
+U+c162 syeolp # Character ì
¢
+U+c163 syeolh # Character ì
£
+U+c164 syeom # Character ì
¤
+U+c165 syeob # Character ì
¥
+U+c166 syeobs # Character ì
¦
+U+c167 syeos # Character ì
§
+U+c168 syeoss # Character ì
¨
+U+c169 syeong # Character ì
©
+U+c16a syeoj # Character ì
ª
+U+c16b syeoc # Character ì
«
+U+c16c syeok # Character ì
¬
+U+c16d syeot # Character ì
+U+c16e syeop # Character ì
®
+U+c16f syeoh # Character ì
¯
+U+c170 sye # Character ì
°
+U+c171 syeg # Character ì
±
+U+c172 syegg # Character ì
²
+U+c173 syegs # Character ì
³
+U+c174 syen # Character ì
´
+U+c175 syenj # Character ì
µ
+U+c176 syenh # Character ì
¶
+U+c177 syed # Character ì
·
+U+c178 syel # Character ì
¸
+U+c179 syelg # Character ì
¹
+U+c17a syelm # Character ì
º
+U+c17b syelb # Character ì
»
+U+c17c syels # Character ì
¼
+U+c17d syelt # Character ì
½
+U+c17e syelp # Character ì
¾
+U+c17f syelh # Character ì
¿
+U+c180 syem # Character ì
+U+c181 syeb # Character ì
+U+c182 syebs # Character ì
+U+c183 syes # Character ì
+U+c184 syess # Character ì
+U+c185 syeng # Character ì
+U+c186 syej # Character ì
+U+c187 syec # Character ì
+U+c188 syek # Character ì
+U+c189 syet # Character ì
+U+c18a syep # Character ì
+U+c18b syeh # Character ì
+U+c18c so # Character ì
+U+c18d sog # Character ì
+U+c18e sogg # Character ì
+U+c18f sogs # Character ì
+U+c190 son # Character ì
+U+c191 sonj # Character ì
+U+c192 sonh # Character ì
+U+c193 sod # Character ì
+U+c194 sol # Character ì
+U+c195 solg # Character ì
+U+c196 solm # Character ì
+U+c197 solb # Character ì
+U+c198 sols # Character ì
+U+c199 solt # Character ì
+U+c19a solp # Character ì
+U+c19b solh # Character ì
+U+c19c som # Character ì
+U+c19d sob # Character ì
+U+c19e sobs # Character ì
+U+c19f sos # Character ì
+U+c1a0 soss # Character ì
+U+c1a1 song # Character ì¡
+U+c1a2 soj # Character ì¢
+U+c1a3 soc # Character ì£
+U+c1a4 sok # Character ì¤
+U+c1a5 sot # Character ì¥
+U+c1a6 sop # Character ì¦
+U+c1a7 soh # Character ì§
+U+c1a8 swa # Character ì¨
+U+c1a9 swag # Character ì©
+U+c1aa swagg # Character ìª
+U+c1ab swags # Character ì«
+U+c1ac swan # Character ì¬
+U+c1ad swanj # Character ì
+U+c1ae swanh # Character ì®
+U+c1af swad # Character ì¯
+U+c1b0 swal # Character ì°
+U+c1b1 swalg # Character ì±
+U+c1b2 swalm # Character ì²
+U+c1b3 swalb # Character ì³
+U+c1b4 swals # Character ì´
+U+c1b5 swalt # Character ìµ
+U+c1b6 swalp # Character ì¶
+U+c1b7 swalh # Character ì·
+U+c1b8 swam # Character ì¸
+U+c1b9 swab # Character ì¹
+U+c1ba swabs # Character ìº
+U+c1bb swas # Character ì»
+U+c1bc swass # Character ì¼
+U+c1bd swang # Character ì½
+U+c1be swaj # Character ì¾
+U+c1bf swac # Character ì¿
+U+c1c0 swak # Character ì
+U+c1c1 swat # Character ì
+U+c1c2 swap # Character ì
+U+c1c3 swah # Character ì
+U+c1c4 swae # Character ì
+U+c1c5 swaeg # Character ì
+U+c1c6 swaegg # Character ì
+U+c1c7 swaegs # Character ì
+U+c1c8 swaen # Character ì
+U+c1c9 swaenj # Character ì
+U+c1ca swaenh # Character ì
+U+c1cb swaed # Character ì
+U+c1cc swael # Character ì
+U+c1cd swaelg # Character ì
+U+c1ce swaelm # Character ì
+U+c1cf swaelb # Character ì
+U+c1d0 swaels # Character ì
+U+c1d1 swaelt # Character ì
+U+c1d2 swaelp # Character ì
+U+c1d3 swaelh # Character ì
+U+c1d4 swaem # Character ì
+U+c1d5 swaeb # Character ì
+U+c1d6 swaebs # Character ì
+U+c1d7 swaes # Character ì
+U+c1d8 swaess # Character ì
+U+c1d9 swaeng # Character ì
+U+c1da swaej # Character ì
+U+c1db swaec # Character ì
+U+c1dc swaek # Character ì
+U+c1dd swaet # Character ì
+U+c1de swaep # Character ì
+U+c1df swaeh # Character ì
+U+c1e0 soe # Character ì
+U+c1e1 soeg # Character ì¡
+U+c1e2 soegg # Character ì¢
+U+c1e3 soegs # Character ì£
+U+c1e4 soen # Character ì¤
+U+c1e5 soenj # Character ì¥
+U+c1e6 soenh # Character ì¦
+U+c1e7 soed # Character ì§
+U+c1e8 soel # Character ì¨
+U+c1e9 soelg # Character ì©
+U+c1ea soelm # Character ìª
+U+c1eb soelb # Character ì«
+U+c1ec soels # Character ì¬
+U+c1ed soelt # Character ì
+U+c1ee soelp # Character ì®
+U+c1ef soelh # Character ì¯
+U+c1f0 soem # Character ì°
+U+c1f1 soeb # Character ì±
+U+c1f2 soebs # Character ì²
+U+c1f3 soes # Character ì³
+U+c1f4 soess # Character ì´
+U+c1f5 soeng # Character ìµ
+U+c1f6 soej # Character ì¶
+U+c1f7 soec # Character ì·
+U+c1f8 soek # Character ì¸
+U+c1f9 soet # Character ì¹
+U+c1fa soep # Character ìº
+U+c1fb soeh # Character ì»
+U+c1fc syo # Character ì¼
+U+c1fd syog # Character ì½
+U+c1fe syogg # Character ì¾
+U+c1ff syogs # Character ì¿
diff --git a/resources/chars/ascii/rowc2.trans b/resources/chars/ascii/rowc2.trans
new file mode 100644
index 0000000..42efa9f
--- /dev/null
+++ b/resources/chars/ascii/rowc2.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+c200 syon # Character ì
+U+c201 syonj # Character ì
+U+c202 syonh # Character ì
+U+c203 syod # Character ì
+U+c204 syol # Character ì
+U+c205 syolg # Character ì
+U+c206 syolm # Character ì
+U+c207 syolb # Character ì
+U+c208 syols # Character ì
+U+c209 syolt # Character ì
+U+c20a syolp # Character ì
+U+c20b syolh # Character ì
+U+c20c syom # Character ì
+U+c20d syob # Character ì
+U+c20e syobs # Character ì
+U+c20f syos # Character ì
+U+c210 syoss # Character ì
+U+c211 syong # Character ì
+U+c212 syoj # Character ì
+U+c213 syoc # Character ì
+U+c214 syok # Character ì
+U+c215 syot # Character ì
+U+c216 syop # Character ì
+U+c217 syoh # Character ì
+U+c218 su # Character ì
+U+c219 sug # Character ì
+U+c21a sugg # Character ì
+U+c21b sugs # Character ì
+U+c21c sun # Character ì
+U+c21d sunj # Character ì
+U+c21e sunh # Character ì
+U+c21f sud # Character ì
+U+c220 sul # Character ì
+U+c221 sulg # Character ì¡
+U+c222 sulm # Character ì¢
+U+c223 sulb # Character ì£
+U+c224 suls # Character ì¤
+U+c225 sult # Character ì¥
+U+c226 sulp # Character ì¦
+U+c227 sulh # Character ì§
+U+c228 sum # Character ì¨
+U+c229 sub # Character ì©
+U+c22a subs # Character ìª
+U+c22b sus # Character ì«
+U+c22c suss # Character ì¬
+U+c22d sung # Character ì
+U+c22e suj # Character ì®
+U+c22f suc # Character ì¯
+U+c230 suk # Character ì°
+U+c231 sut # Character ì±
+U+c232 sup # Character ì²
+U+c233 suh # Character ì³
+U+c234 sweo # Character ì´
+U+c235 sweog # Character ìµ
+U+c236 sweogg # Character ì¶
+U+c237 sweogs # Character ì·
+U+c238 sweon # Character ì¸
+U+c239 sweonj # Character ì¹
+U+c23a sweonh # Character ìº
+U+c23b sweod # Character ì»
+U+c23c sweol # Character ì¼
+U+c23d sweolg # Character ì½
+U+c23e sweolm # Character ì¾
+U+c23f sweolb # Character ì¿
+U+c240 sweols # Character ì
+U+c241 sweolt # Character ì
+U+c242 sweolp # Character ì
+U+c243 sweolh # Character ì
+U+c244 sweom # Character ì
+U+c245 sweob # Character ì
+U+c246 sweobs # Character ì
+U+c247 sweos # Character ì
+U+c248 sweoss # Character ì
+U+c249 sweong # Character ì
+U+c24a sweoj # Character ì
+U+c24b sweoc # Character ì
+U+c24c sweok # Character ì
+U+c24d sweot # Character ì
+U+c24e sweop # Character ì
+U+c24f sweoh # Character ì
+U+c250 swe # Character ì
+U+c251 sweg # Character ì
+U+c252 swegg # Character ì
+U+c253 swegs # Character ì
+U+c254 swen # Character ì
+U+c255 swenj # Character ì
+U+c256 swenh # Character ì
+U+c257 swed # Character ì
+U+c258 swel # Character ì
+U+c259 swelg # Character ì
+U+c25a swelm # Character ì
+U+c25b swelb # Character ì
+U+c25c swels # Character ì
+U+c25d swelt # Character ì
+U+c25e swelp # Character ì
+U+c25f swelh # Character ì
+U+c260 swem # Character ì
+U+c261 sweb # Character ì¡
+U+c262 swebs # Character ì¢
+U+c263 swes # Character ì£
+U+c264 swess # Character ì¤
+U+c265 sweng # Character ì¥
+U+c266 swej # Character ì¦
+U+c267 swec # Character ì§
+U+c268 swek # Character ì¨
+U+c269 swet # Character ì©
+U+c26a swep # Character ìª
+U+c26b sweh # Character ì«
+U+c26c swi # Character ì¬
+U+c26d swig # Character ì
+U+c26e swigg # Character ì®
+U+c26f swigs # Character ì¯
+U+c270 swin # Character ì°
+U+c271 swinj # Character ì±
+U+c272 swinh # Character ì²
+U+c273 swid # Character ì³
+U+c274 swil # Character ì´
+U+c275 swilg # Character ìµ
+U+c276 swilm # Character ì¶
+U+c277 swilb # Character ì·
+U+c278 swils # Character ì¸
+U+c279 swilt # Character ì¹
+U+c27a swilp # Character ìº
+U+c27b swilh # Character ì»
+U+c27c swim # Character ì¼
+U+c27d swib # Character ì½
+U+c27e swibs # Character ì¾
+U+c27f swis # Character ì¿
+U+c280 swiss # Character ì
+U+c281 swing # Character ì
+U+c282 swij # Character ì
+U+c283 swic # Character ì
+U+c284 swik # Character ì
+U+c285 swit # Character ì
+U+c286 swip # Character ì
+U+c287 swih # Character ì
+U+c288 syu # Character ì
+U+c289 syug # Character ì
+U+c28a syugg # Character ì
+U+c28b syugs # Character ì
+U+c28c syun # Character ì
+U+c28d syunj # Character ì
+U+c28e syunh # Character ì
+U+c28f syud # Character ì
+U+c290 syul # Character ì
+U+c291 syulg # Character ì
+U+c292 syulm # Character ì
+U+c293 syulb # Character ì
+U+c294 syuls # Character ì
+U+c295 syult # Character ì
+U+c296 syulp # Character ì
+U+c297 syulh # Character ì
+U+c298 syum # Character ì
+U+c299 syub # Character ì
+U+c29a syubs # Character ì
+U+c29b syus # Character ì
+U+c29c syuss # Character ì
+U+c29d syung # Character ì
+U+c29e syuj # Character ì
+U+c29f syuc # Character ì
+U+c2a0 syuk # Character ì
+U+c2a1 syut # Character ì¡
+U+c2a2 syup # Character ì¢
+U+c2a3 syuh # Character ì£
+U+c2a4 seu # Character ì¤
+U+c2a5 seug # Character ì¥
+U+c2a6 seugg # Character ì¦
+U+c2a7 seugs # Character ì§
+U+c2a8 seun # Character ì¨
+U+c2a9 seunj # Character ì©
+U+c2aa seunh # Character ìª
+U+c2ab seud # Character ì«
+U+c2ac seul # Character ì¬
+U+c2ad seulg # Character ì
+U+c2ae seulm # Character ì®
+U+c2af seulb # Character ì¯
+U+c2b0 seuls # Character ì°
+U+c2b1 seult # Character ì±
+U+c2b2 seulp # Character ì²
+U+c2b3 seulh # Character ì³
+U+c2b4 seum # Character ì´
+U+c2b5 seub # Character ìµ
+U+c2b6 seubs # Character ì¶
+U+c2b7 seus # Character ì·
+U+c2b8 seuss # Character ì¸
+U+c2b9 seung # Character ì¹
+U+c2ba seuj # Character ìº
+U+c2bb seuc # Character ì»
+U+c2bc seuk # Character ì¼
+U+c2bd seut # Character ì½
+U+c2be seup # Character ì¾
+U+c2bf seuh # Character ì¿
+U+c2c0 syi # Character ì
+U+c2c1 syig # Character ì
+U+c2c2 syigg # Character ì
+U+c2c3 syigs # Character ì
+U+c2c4 syin # Character ì
+U+c2c5 syinj # Character ì
+U+c2c6 syinh # Character ì
+U+c2c7 syid # Character ì
+U+c2c8 syil # Character ì
+U+c2c9 syilg # Character ì
+U+c2ca syilm # Character ì
+U+c2cb syilb # Character ì
+U+c2cc syils # Character ì
+U+c2cd syilt # Character ì
+U+c2ce syilp # Character ì
+U+c2cf syilh # Character ì
+U+c2d0 syim # Character ì
+U+c2d1 syib # Character ì
+U+c2d2 syibs # Character ì
+U+c2d3 syis # Character ì
+U+c2d4 syiss # Character ì
+U+c2d5 sying # Character ì
+U+c2d6 syij # Character ì
+U+c2d7 syic # Character ì
+U+c2d8 syik # Character ì
+U+c2d9 syit # Character ì
+U+c2da syip # Character ì
+U+c2db syih # Character ì
+U+c2dc si # Character ì
+U+c2dd sig # Character ì
+U+c2de sigg # Character ì
+U+c2df sigs # Character ì
+U+c2e0 sin # Character ì
+U+c2e1 sinj # Character ì¡
+U+c2e2 sinh # Character ì¢
+U+c2e3 sid # Character ì£
+U+c2e4 sil # Character ì¤
+U+c2e5 silg # Character ì¥
+U+c2e6 silm # Character ì¦
+U+c2e7 silb # Character ì§
+U+c2e8 sils # Character ì¨
+U+c2e9 silt # Character ì©
+U+c2ea silp # Character ìª
+U+c2eb silh # Character ì«
+U+c2ec sim # Character ì¬
+U+c2ed sib # Character ì
+U+c2ee sibs # Character ì®
+U+c2ef sis # Character ì¯
+U+c2f0 siss # Character ì°
+U+c2f1 sing # Character ì±
+U+c2f2 sij # Character ì²
+U+c2f3 sic # Character ì³
+U+c2f4 sik # Character ì´
+U+c2f5 sit # Character ìµ
+U+c2f6 sip # Character ì¶
+U+c2f7 sih # Character ì·
+U+c2f8 ssa # Character ì¸
+U+c2f9 ssag # Character ì¹
+U+c2fa ssagg # Character ìº
+U+c2fb ssags # Character ì»
+U+c2fc ssan # Character ì¼
+U+c2fd ssanj # Character ì½
+U+c2fe ssanh # Character ì¾
+U+c2ff ssad # Character ì¿
diff --git a/resources/chars/ascii/rowc3.trans b/resources/chars/ascii/rowc3.trans
new file mode 100644
index 0000000..f4ff23d
--- /dev/null
+++ b/resources/chars/ascii/rowc3.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+c300 ssal # Character ì
+U+c301 ssalg # Character ì
+U+c302 ssalm # Character ì
+U+c303 ssalb # Character ì
+U+c304 ssals # Character ì
+U+c305 ssalt # Character ì
+U+c306 ssalp # Character ì
+U+c307 ssalh # Character ì
+U+c308 ssam # Character ì
+U+c309 ssab # Character ì
+U+c30a ssabs # Character ì
+U+c30b ssas # Character ì
+U+c30c ssass # Character ì
+U+c30d ssang # Character ì
+U+c30e ssaj # Character ì
+U+c30f ssac # Character ì
+U+c310 ssak # Character ì
+U+c311 ssat # Character ì
+U+c312 ssap # Character ì
+U+c313 ssah # Character ì
+U+c314 ssae # Character ì
+U+c315 ssaeg # Character ì
+U+c316 ssaegg # Character ì
+U+c317 ssaegs # Character ì
+U+c318 ssaen # Character ì
+U+c319 ssaenj # Character ì
+U+c31a ssaenh # Character ì
+U+c31b ssaed # Character ì
+U+c31c ssael # Character ì
+U+c31d ssaelg # Character ì
+U+c31e ssaelm # Character ì
+U+c31f ssaelb # Character ì
+U+c320 ssaels # Character ì
+U+c321 ssaelt # Character ì¡
+U+c322 ssaelp # Character ì¢
+U+c323 ssaelh # Character ì£
+U+c324 ssaem # Character ì¤
+U+c325 ssaeb # Character ì¥
+U+c326 ssaebs # Character ì¦
+U+c327 ssaes # Character ì§
+U+c328 ssaess # Character ì¨
+U+c329 ssaeng # Character ì©
+U+c32a ssaej # Character ìª
+U+c32b ssaec # Character ì«
+U+c32c ssaek # Character ì¬
+U+c32d ssaet # Character ì
+U+c32e ssaep # Character ì®
+U+c32f ssaeh # Character ì¯
+U+c330 ssya # Character ì°
+U+c331 ssyag # Character ì±
+U+c332 ssyagg # Character ì²
+U+c333 ssyags # Character ì³
+U+c334 ssyan # Character ì´
+U+c335 ssyanj # Character ìµ
+U+c336 ssyanh # Character ì¶
+U+c337 ssyad # Character ì·
+U+c338 ssyal # Character ì¸
+U+c339 ssyalg # Character ì¹
+U+c33a ssyalm # Character ìº
+U+c33b ssyalb # Character ì»
+U+c33c ssyals # Character ì¼
+U+c33d ssyalt # Character ì½
+U+c33e ssyalp # Character ì¾
+U+c33f ssyalh # Character ì¿
+U+c340 ssyam # Character ì
+U+c341 ssyab # Character ì
+U+c342 ssyabs # Character ì
+U+c343 ssyas # Character ì
+U+c344 ssyass # Character ì
+U+c345 ssyang # Character ì
+U+c346 ssyaj # Character ì
+U+c347 ssyac # Character ì
+U+c348 ssyak # Character ì
+U+c349 ssyat # Character ì
+U+c34a ssyap # Character ì
+U+c34b ssyah # Character ì
+U+c34c ssyae # Character ì
+U+c34d ssyaeg # Character ì
+U+c34e ssyaegg # Character ì
+U+c34f ssyaegs # Character ì
+U+c350 ssyaen # Character ì
+U+c351 ssyaenj # Character ì
+U+c352 ssyaenh # Character ì
+U+c353 ssyaed # Character ì
+U+c354 ssyael # Character ì
+U+c355 ssyaelg # Character ì
+U+c356 ssyaelm # Character ì
+U+c357 ssyaelb # Character ì
+U+c358 ssyaels # Character ì
+U+c359 ssyaelt # Character ì
+U+c35a ssyaelp # Character ì
+U+c35b ssyaelh # Character ì
+U+c35c ssyaem # Character ì
+U+c35d ssyaeb # Character ì
+U+c35e ssyaebs # Character ì
+U+c35f ssyaes # Character ì
+U+c360 ssyaess # Character ì
+U+c361 ssyaeng # Character ì¡
+U+c362 ssyaej # Character ì¢
+U+c363 ssyaec # Character ì£
+U+c364 ssyaek # Character ì¤
+U+c365 ssyaet # Character ì¥
+U+c366 ssyaep # Character ì¦
+U+c367 ssyaeh # Character ì§
+U+c368 sseo # Character ì¨
+U+c369 sseog # Character ì©
+U+c36a sseogg # Character ìª
+U+c36b sseogs # Character ì«
+U+c36c sseon # Character ì¬
+U+c36d sseonj # Character ì
+U+c36e sseonh # Character ì®
+U+c36f sseod # Character ì¯
+U+c370 sseol # Character ì°
+U+c371 sseolg # Character ì±
+U+c372 sseolm # Character ì²
+U+c373 sseolb # Character ì³
+U+c374 sseols # Character ì´
+U+c375 sseolt # Character ìµ
+U+c376 sseolp # Character ì¶
+U+c377 sseolh # Character ì·
+U+c378 sseom # Character ì¸
+U+c379 sseob # Character ì¹
+U+c37a sseobs # Character ìº
+U+c37b sseos # Character ì»
+U+c37c sseoss # Character ì¼
+U+c37d sseong # Character ì½
+U+c37e sseoj # Character ì¾
+U+c37f sseoc # Character ì¿
+U+c380 sseok # Character ì
+U+c381 sseot # Character ì
+U+c382 sseop # Character ì
+U+c383 sseoh # Character ì
+U+c384 sse # Character ì
+U+c385 sseg # Character ì
+U+c386 ssegg # Character ì
+U+c387 ssegs # Character ì
+U+c388 ssen # Character ì
+U+c389 ssenj # Character ì
+U+c38a ssenh # Character ì
+U+c38b ssed # Character ì
+U+c38c ssel # Character ì
+U+c38d sselg # Character ì
+U+c38e sselm # Character ì
+U+c38f sselb # Character ì
+U+c390 ssels # Character ì
+U+c391 sselt # Character ì
+U+c392 sselp # Character ì
+U+c393 sselh # Character ì
+U+c394 ssem # Character ì
+U+c395 sseb # Character ì
+U+c396 ssebs # Character ì
+U+c397 sses # Character ì
+U+c398 ssess # Character ì
+U+c399 sseng # Character ì
+U+c39a ssej # Character ì
+U+c39b ssec # Character ì
+U+c39c ssek # Character ì
+U+c39d sset # Character ì
+U+c39e ssep # Character ì
+U+c39f sseh # Character ì
+U+c3a0 ssyeo # Character ì
+U+c3a1 ssyeog # Character ì¡
+U+c3a2 ssyeogg # Character ì¢
+U+c3a3 ssyeogs # Character ì£
+U+c3a4 ssyeon # Character ì¤
+U+c3a5 ssyeonj # Character ì¥
+U+c3a6 ssyeonh # Character ì¦
+U+c3a7 ssyeod # Character ì§
+U+c3a8 ssyeol # Character ì¨
+U+c3a9 ssyeolg # Character ì©
+U+c3aa ssyeolm # Character ìª
+U+c3ab ssyeolb # Character ì«
+U+c3ac ssyeols # Character ì¬
+U+c3ad ssyeolt # Character ì
+U+c3ae ssyeolp # Character ì®
+U+c3af ssyeolh # Character ì¯
+U+c3b0 ssyeom # Character ì°
+U+c3b1 ssyeob # Character ì±
+U+c3b2 ssyeobs # Character ì²
+U+c3b3 ssyeos # Character ì³
+U+c3b4 ssyeoss # Character ì´
+U+c3b5 ssyeong # Character ìµ
+U+c3b6 ssyeoj # Character ì¶
+U+c3b7 ssyeoc # Character ì·
+U+c3b8 ssyeok # Character ì¸
+U+c3b9 ssyeot # Character ì¹
+U+c3ba ssyeop # Character ìº
+U+c3bb ssyeoh # Character ì»
+U+c3bc ssye # Character ì¼
+U+c3bd ssyeg # Character ì½
+U+c3be ssyegg # Character ì¾
+U+c3bf ssyegs # Character ì¿
+U+c3c0 ssyen # Character ì
+U+c3c1 ssyenj # Character ì
+U+c3c2 ssyenh # Character ì
+U+c3c3 ssyed # Character ì
+U+c3c4 ssyel # Character ì
+U+c3c5 ssyelg # Character ì
+U+c3c6 ssyelm # Character ì
+U+c3c7 ssyelb # Character ì
+U+c3c8 ssyels # Character ì
+U+c3c9 ssyelt # Character ì
+U+c3ca ssyelp # Character ì
+U+c3cb ssyelh # Character ì
+U+c3cc ssyem # Character ì
+U+c3cd ssyeb # Character ì
+U+c3ce ssyebs # Character ì
+U+c3cf ssyes # Character ì
+U+c3d0 ssyess # Character ì
+U+c3d1 ssyeng # Character ì
+U+c3d2 ssyej # Character ì
+U+c3d3 ssyec # Character ì
+U+c3d4 ssyek # Character ì
+U+c3d5 ssyet # Character ì
+U+c3d6 ssyep # Character ì
+U+c3d7 ssyeh # Character ì
+U+c3d8 sso # Character ì
+U+c3d9 ssog # Character ì
+U+c3da ssogg # Character ì
+U+c3db ssogs # Character ì
+U+c3dc sson # Character ì
+U+c3dd ssonj # Character ì
+U+c3de ssonh # Character ì
+U+c3df ssod # Character ì
+U+c3e0 ssol # Character ì
+U+c3e1 ssolg # Character ì¡
+U+c3e2 ssolm # Character ì¢
+U+c3e3 ssolb # Character ì£
+U+c3e4 ssols # Character ì¤
+U+c3e5 ssolt # Character ì¥
+U+c3e6 ssolp # Character ì¦
+U+c3e7 ssolh # Character ì§
+U+c3e8 ssom # Character ì¨
+U+c3e9 ssob # Character ì©
+U+c3ea ssobs # Character ìª
+U+c3eb ssos # Character ì«
+U+c3ec ssoss # Character ì¬
+U+c3ed ssong # Character ì
+U+c3ee ssoj # Character ì®
+U+c3ef ssoc # Character ì¯
+U+c3f0 ssok # Character ì°
+U+c3f1 ssot # Character ì±
+U+c3f2 ssop # Character ì²
+U+c3f3 ssoh # Character ì³
+U+c3f4 sswa # Character ì´
+U+c3f5 sswag # Character ìµ
+U+c3f6 sswagg # Character ì¶
+U+c3f7 sswags # Character ì·
+U+c3f8 sswan # Character ì¸
+U+c3f9 sswanj # Character ì¹
+U+c3fa sswanh # Character ìº
+U+c3fb sswad # Character ì»
+U+c3fc sswal # Character ì¼
+U+c3fd sswalg # Character ì½
+U+c3fe sswalm # Character ì¾
+U+c3ff sswalb # Character ì¿
diff --git a/resources/chars/ascii/rowc4.trans b/resources/chars/ascii/rowc4.trans
new file mode 100644
index 0000000..b7c7d31
--- /dev/null
+++ b/resources/chars/ascii/rowc4.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+c400 sswals # Character ì
+U+c401 sswalt # Character ì
+U+c402 sswalp # Character ì
+U+c403 sswalh # Character ì
+U+c404 sswam # Character ì
+U+c405 sswab # Character ì
+U+c406 sswabs # Character ì
+U+c407 sswas # Character ì
+U+c408 sswass # Character ì
+U+c409 sswang # Character ì
+U+c40a sswaj # Character ì
+U+c40b sswac # Character ì
+U+c40c sswak # Character ì
+U+c40d sswat # Character ì
+U+c40e sswap # Character ì
+U+c40f sswah # Character ì
+U+c410 sswae # Character ì
+U+c411 sswaeg # Character ì
+U+c412 sswaegg # Character ì
+U+c413 sswaegs # Character ì
+U+c414 sswaen # Character ì
+U+c415 sswaenj # Character ì
+U+c416 sswaenh # Character ì
+U+c417 sswaed # Character ì
+U+c418 sswael # Character ì
+U+c419 sswaelg # Character ì
+U+c41a sswaelm # Character ì
+U+c41b sswaelb # Character ì
+U+c41c sswaels # Character ì
+U+c41d sswaelt # Character ì
+U+c41e sswaelp # Character ì
+U+c41f sswaelh # Character ì
+U+c420 sswaem # Character ì
+U+c421 sswaeb # Character ì¡
+U+c422 sswaebs # Character ì¢
+U+c423 sswaes # Character ì£
+U+c424 sswaess # Character ì¤
+U+c425 sswaeng # Character ì¥
+U+c426 sswaej # Character ì¦
+U+c427 sswaec # Character ì§
+U+c428 sswaek # Character ì¨
+U+c429 sswaet # Character ì©
+U+c42a sswaep # Character ìª
+U+c42b sswaeh # Character ì«
+U+c42c ssoe # Character ì¬
+U+c42d ssoeg # Character ì
+U+c42e ssoegg # Character ì®
+U+c42f ssoegs # Character ì¯
+U+c430 ssoen # Character ì°
+U+c431 ssoenj # Character ì±
+U+c432 ssoenh # Character ì²
+U+c433 ssoed # Character ì³
+U+c434 ssoel # Character ì´
+U+c435 ssoelg # Character ìµ
+U+c436 ssoelm # Character ì¶
+U+c437 ssoelb # Character ì·
+U+c438 ssoels # Character ì¸
+U+c439 ssoelt # Character ì¹
+U+c43a ssoelp # Character ìº
+U+c43b ssoelh # Character ì»
+U+c43c ssoem # Character ì¼
+U+c43d ssoeb # Character ì½
+U+c43e ssoebs # Character ì¾
+U+c43f ssoes # Character ì¿
+U+c440 ssoess # Character ì
+U+c441 ssoeng # Character ì
+U+c442 ssoej # Character ì
+U+c443 ssoec # Character ì
+U+c444 ssoek # Character ì
+U+c445 ssoet # Character ì
+U+c446 ssoep # Character ì
+U+c447 ssoeh # Character ì
+U+c448 ssyo # Character ì
+U+c449 ssyog # Character ì
+U+c44a ssyogg # Character ì
+U+c44b ssyogs # Character ì
+U+c44c ssyon # Character ì
+U+c44d ssyonj # Character ì
+U+c44e ssyonh # Character ì
+U+c44f ssyod # Character ì
+U+c450 ssyol # Character ì
+U+c451 ssyolg # Character ì
+U+c452 ssyolm # Character ì
+U+c453 ssyolb # Character ì
+U+c454 ssyols # Character ì
+U+c455 ssyolt # Character ì
+U+c456 ssyolp # Character ì
+U+c457 ssyolh # Character ì
+U+c458 ssyom # Character ì
+U+c459 ssyob # Character ì
+U+c45a ssyobs # Character ì
+U+c45b ssyos # Character ì
+U+c45c ssyoss # Character ì
+U+c45d ssyong # Character ì
+U+c45e ssyoj # Character ì
+U+c45f ssyoc # Character ì
+U+c460 ssyok # Character ì
+U+c461 ssyot # Character ì¡
+U+c462 ssyop # Character ì¢
+U+c463 ssyoh # Character ì£
+U+c464 ssu # Character ì¤
+U+c465 ssug # Character ì¥
+U+c466 ssugg # Character ì¦
+U+c467 ssugs # Character ì§
+U+c468 ssun # Character ì¨
+U+c469 ssunj # Character ì©
+U+c46a ssunh # Character ìª
+U+c46b ssud # Character ì«
+U+c46c ssul # Character ì¬
+U+c46d ssulg # Character ì
+U+c46e ssulm # Character ì®
+U+c46f ssulb # Character ì¯
+U+c470 ssuls # Character ì°
+U+c471 ssult # Character ì±
+U+c472 ssulp # Character ì²
+U+c473 ssulh # Character ì³
+U+c474 ssum # Character ì´
+U+c475 ssub # Character ìµ
+U+c476 ssubs # Character ì¶
+U+c477 ssus # Character ì·
+U+c478 ssuss # Character ì¸
+U+c479 ssung # Character ì¹
+U+c47a ssuj # Character ìº
+U+c47b ssuc # Character ì»
+U+c47c ssuk # Character ì¼
+U+c47d ssut # Character ì½
+U+c47e ssup # Character ì¾
+U+c47f ssuh # Character ì¿
+U+c480 ssweo # Character ì
+U+c481 ssweog # Character ì
+U+c482 ssweogg # Character ì
+U+c483 ssweogs # Character ì
+U+c484 ssweon # Character ì
+U+c485 ssweonj # Character ì
+U+c486 ssweonh # Character ì
+U+c487 ssweod # Character ì
+U+c488 ssweol # Character ì
+U+c489 ssweolg # Character ì
+U+c48a ssweolm # Character ì
+U+c48b ssweolb # Character ì
+U+c48c ssweols # Character ì
+U+c48d ssweolt # Character ì
+U+c48e ssweolp # Character ì
+U+c48f ssweolh # Character ì
+U+c490 ssweom # Character ì
+U+c491 ssweob # Character ì
+U+c492 ssweobs # Character ì
+U+c493 ssweos # Character ì
+U+c494 ssweoss # Character ì
+U+c495 ssweong # Character ì
+U+c496 ssweoj # Character ì
+U+c497 ssweoc # Character ì
+U+c498 ssweok # Character ì
+U+c499 ssweot # Character ì
+U+c49a ssweop # Character ì
+U+c49b ssweoh # Character ì
+U+c49c sswe # Character ì
+U+c49d ssweg # Character ì
+U+c49e sswegg # Character ì
+U+c49f sswegs # Character ì
+U+c4a0 sswen # Character ì
+U+c4a1 sswenj # Character ì¡
+U+c4a2 sswenh # Character ì¢
+U+c4a3 sswed # Character ì£
+U+c4a4 sswel # Character ì¤
+U+c4a5 sswelg # Character ì¥
+U+c4a6 sswelm # Character ì¦
+U+c4a7 sswelb # Character ì§
+U+c4a8 sswels # Character ì¨
+U+c4a9 sswelt # Character ì©
+U+c4aa sswelp # Character ìª
+U+c4ab sswelh # Character ì«
+U+c4ac sswem # Character ì¬
+U+c4ad ssweb # Character ì
+U+c4ae sswebs # Character ì®
+U+c4af sswes # Character ì¯
+U+c4b0 sswess # Character ì°
+U+c4b1 ssweng # Character ì±
+U+c4b2 sswej # Character ì²
+U+c4b3 sswec # Character ì³
+U+c4b4 sswek # Character ì´
+U+c4b5 sswet # Character ìµ
+U+c4b6 sswep # Character ì¶
+U+c4b7 ssweh # Character ì·
+U+c4b8 sswi # Character ì¸
+U+c4b9 sswig # Character ì¹
+U+c4ba sswigg # Character ìº
+U+c4bb sswigs # Character ì»
+U+c4bc sswin # Character ì¼
+U+c4bd sswinj # Character ì½
+U+c4be sswinh # Character ì¾
+U+c4bf sswid # Character ì¿
+U+c4c0 sswil # Character ì
+U+c4c1 sswilg # Character ì
+U+c4c2 sswilm # Character ì
+U+c4c3 sswilb # Character ì
+U+c4c4 sswils # Character ì
+U+c4c5 sswilt # Character ì
+U+c4c6 sswilp # Character ì
+U+c4c7 sswilh # Character ì
+U+c4c8 sswim # Character ì
+U+c4c9 sswib # Character ì
+U+c4ca sswibs # Character ì
+U+c4cb sswis # Character ì
+U+c4cc sswiss # Character ì
+U+c4cd sswing # Character ì
+U+c4ce sswij # Character ì
+U+c4cf sswic # Character ì
+U+c4d0 sswik # Character ì
+U+c4d1 sswit # Character ì
+U+c4d2 sswip # Character ì
+U+c4d3 sswih # Character ì
+U+c4d4 ssyu # Character ì
+U+c4d5 ssyug # Character ì
+U+c4d6 ssyugg # Character ì
+U+c4d7 ssyugs # Character ì
+U+c4d8 ssyun # Character ì
+U+c4d9 ssyunj # Character ì
+U+c4da ssyunh # Character ì
+U+c4db ssyud # Character ì
+U+c4dc ssyul # Character ì
+U+c4dd ssyulg # Character ì
+U+c4de ssyulm # Character ì
+U+c4df ssyulb # Character ì
+U+c4e0 ssyuls # Character ì
+U+c4e1 ssyult # Character ì¡
+U+c4e2 ssyulp # Character ì¢
+U+c4e3 ssyulh # Character ì£
+U+c4e4 ssyum # Character ì¤
+U+c4e5 ssyub # Character ì¥
+U+c4e6 ssyubs # Character ì¦
+U+c4e7 ssyus # Character ì§
+U+c4e8 ssyuss # Character ì¨
+U+c4e9 ssyung # Character ì©
+U+c4ea ssyuj # Character ìª
+U+c4eb ssyuc # Character ì«
+U+c4ec ssyuk # Character ì¬
+U+c4ed ssyut # Character ì
+U+c4ee ssyup # Character ì®
+U+c4ef ssyuh # Character ì¯
+U+c4f0 sseu # Character ì°
+U+c4f1 sseug # Character ì±
+U+c4f2 sseugg # Character ì²
+U+c4f3 sseugs # Character ì³
+U+c4f4 sseun # Character ì´
+U+c4f5 sseunj # Character ìµ
+U+c4f6 sseunh # Character ì¶
+U+c4f7 sseud # Character ì·
+U+c4f8 sseul # Character ì¸
+U+c4f9 sseulg # Character ì¹
+U+c4fa sseulm # Character ìº
+U+c4fb sseulb # Character ì»
+U+c4fc sseuls # Character ì¼
+U+c4fd sseult # Character ì½
+U+c4fe sseulp # Character ì¾
+U+c4ff sseulh # Character ì¿
diff --git a/resources/chars/ascii/rowc5.trans b/resources/chars/ascii/rowc5.trans
new file mode 100644
index 0000000..d8c2912
--- /dev/null
+++ b/resources/chars/ascii/rowc5.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+c500 sseum # Character ì
+U+c501 sseub # Character ì
+U+c502 sseubs # Character ì
+U+c503 sseus # Character ì
+U+c504 sseuss # Character ì
+U+c505 sseung # Character ì
+U+c506 sseuj # Character ì
+U+c507 sseuc # Character ì
+U+c508 sseuk # Character ì
+U+c509 sseut # Character ì
+U+c50a sseup # Character ì
+U+c50b sseuh # Character ì
+U+c50c ssyi # Character ì
+U+c50d ssyig # Character ì
+U+c50e ssyigg # Character ì
+U+c50f ssyigs # Character ì
+U+c510 ssyin # Character ì
+U+c511 ssyinj # Character ì
+U+c512 ssyinh # Character ì
+U+c513 ssyid # Character ì
+U+c514 ssyil # Character ì
+U+c515 ssyilg # Character ì
+U+c516 ssyilm # Character ì
+U+c517 ssyilb # Character ì
+U+c518 ssyils # Character ì
+U+c519 ssyilt # Character ì
+U+c51a ssyilp # Character ì
+U+c51b ssyilh # Character ì
+U+c51c ssyim # Character ì
+U+c51d ssyib # Character ì
+U+c51e ssyibs # Character ì
+U+c51f ssyis # Character ì
+U+c520 ssyiss # Character ì
+U+c521 ssying # Character ì¡
+U+c522 ssyij # Character ì¢
+U+c523 ssyic # Character ì£
+U+c524 ssyik # Character ì¤
+U+c525 ssyit # Character ì¥
+U+c526 ssyip # Character ì¦
+U+c527 ssyih # Character ì§
+U+c528 ssi # Character ì¨
+U+c529 ssig # Character ì©
+U+c52a ssigg # Character ìª
+U+c52b ssigs # Character ì«
+U+c52c ssin # Character ì¬
+U+c52d ssinj # Character ì
+U+c52e ssinh # Character ì®
+U+c52f ssid # Character ì¯
+U+c530 ssil # Character ì°
+U+c531 ssilg # Character ì±
+U+c532 ssilm # Character ì²
+U+c533 ssilb # Character ì³
+U+c534 ssils # Character ì´
+U+c535 ssilt # Character ìµ
+U+c536 ssilp # Character ì¶
+U+c537 ssilh # Character ì·
+U+c538 ssim # Character ì¸
+U+c539 ssib # Character ì¹
+U+c53a ssibs # Character ìº
+U+c53b ssis # Character ì»
+U+c53c ssiss # Character ì¼
+U+c53d ssing # Character ì½
+U+c53e ssij # Character ì¾
+U+c53f ssic # Character ì¿
+U+c540 ssik # Character ì
+U+c541 ssit # Character ì
+U+c542 ssip # Character ì
+U+c543 ssih # Character ì
+U+c544 a # Character ì
+U+c545 ag # Character ì
+U+c546 agg # Character ì
+U+c547 ags # Character ì
+U+c548 an # Character ì
+U+c549 anj # Character ì
+U+c54a anh # Character ì
+U+c54b ad # Character ì
+U+c54c al # Character ì
+U+c54d alg # Character ì
+U+c54e alm # Character ì
+U+c54f alb # Character ì
+U+c550 als # Character ì
+U+c551 alt # Character ì
+U+c552 alp # Character ì
+U+c553 alh # Character ì
+U+c554 am # Character ì
+U+c555 ab # Character ì
+U+c556 abs # Character ì
+U+c557 as # Character ì
+U+c558 ass # Character ì
+U+c559 ang # Character ì
+U+c55a aj # Character ì
+U+c55b ac # Character ì
+U+c55c ak # Character ì
+U+c55d at # Character ì
+U+c55e ap # Character ì
+U+c55f ah # Character ì
+U+c560 ae # Character ì
+U+c561 aeg # Character ì¡
+U+c562 aegg # Character ì¢
+U+c563 aegs # Character ì£
+U+c564 aen # Character ì¤
+U+c565 aenj # Character ì¥
+U+c566 aenh # Character ì¦
+U+c567 aed # Character ì§
+U+c568 ael # Character ì¨
+U+c569 aelg # Character ì©
+U+c56a aelm # Character ìª
+U+c56b aelb # Character ì«
+U+c56c aels # Character ì¬
+U+c56d aelt # Character ì
+U+c56e aelp # Character ì®
+U+c56f aelh # Character ì¯
+U+c570 aem # Character ì°
+U+c571 aeb # Character ì±
+U+c572 aebs # Character ì²
+U+c573 aes # Character ì³
+U+c574 aess # Character ì´
+U+c575 aeng # Character ìµ
+U+c576 aej # Character ì¶
+U+c577 aec # Character ì·
+U+c578 aek # Character ì¸
+U+c579 aet # Character ì¹
+U+c57a aep # Character ìº
+U+c57b aeh # Character ì»
+U+c57c ya # Character ì¼
+U+c57d yag # Character ì½
+U+c57e yagg # Character ì¾
+U+c57f yags # Character ì¿
+U+c580 yan # Character ì
+U+c581 yanj # Character ì
+U+c582 yanh # Character ì
+U+c583 yad # Character ì
+U+c584 yal # Character ì
+U+c585 yalg # Character ì
+U+c586 yalm # Character ì
+U+c587 yalb # Character ì
+U+c588 yals # Character ì
+U+c589 yalt # Character ì
+U+c58a yalp # Character ì
+U+c58b yalh # Character ì
+U+c58c yam # Character ì
+U+c58d yab # Character ì
+U+c58e yabs # Character ì
+U+c58f yas # Character ì
+U+c590 yass # Character ì
+U+c591 yang # Character ì
+U+c592 yaj # Character ì
+U+c593 yac # Character ì
+U+c594 yak # Character ì
+U+c595 yat # Character ì
+U+c596 yap # Character ì
+U+c597 yah # Character ì
+U+c598 yae # Character ì
+U+c599 yaeg # Character ì
+U+c59a yaegg # Character ì
+U+c59b yaegs # Character ì
+U+c59c yaen # Character ì
+U+c59d yaenj # Character ì
+U+c59e yaenh # Character ì
+U+c59f yaed # Character ì
+U+c5a0 yael # Character ì
+U+c5a1 yaelg # Character ì¡
+U+c5a2 yaelm # Character ì¢
+U+c5a3 yaelb # Character ì£
+U+c5a4 yaels # Character ì¤
+U+c5a5 yaelt # Character ì¥
+U+c5a6 yaelp # Character ì¦
+U+c5a7 yaelh # Character ì§
+U+c5a8 yaem # Character ì¨
+U+c5a9 yaeb # Character ì©
+U+c5aa yaebs # Character ìª
+U+c5ab yaes # Character ì«
+U+c5ac yaess # Character ì¬
+U+c5ad yaeng # Character ì
+U+c5ae yaej # Character ì®
+U+c5af yaec # Character ì¯
+U+c5b0 yaek # Character ì°
+U+c5b1 yaet # Character ì±
+U+c5b2 yaep # Character ì²
+U+c5b3 yaeh # Character ì³
+U+c5b4 eo # Character ì´
+U+c5b5 eog # Character ìµ
+U+c5b6 eogg # Character ì¶
+U+c5b7 eogs # Character ì·
+U+c5b8 eon # Character ì¸
+U+c5b9 eonj # Character ì¹
+U+c5ba eonh # Character ìº
+U+c5bb eod # Character ì»
+U+c5bc eol # Character ì¼
+U+c5bd eolg # Character ì½
+U+c5be eolm # Character ì¾
+U+c5bf eolb # Character ì¿
+U+c5c0 eols # Character ì
+U+c5c1 eolt # Character ì
+U+c5c2 eolp # Character ì
+U+c5c3 eolh # Character ì
+U+c5c4 eom # Character ì
+U+c5c5 eob # Character ì
+U+c5c6 eobs # Character ì
+U+c5c7 eos # Character ì
+U+c5c8 eoss # Character ì
+U+c5c9 eong # Character ì
+U+c5ca eoj # Character ì
+U+c5cb eoc # Character ì
+U+c5cc eok # Character ì
+U+c5cd eot # Character ì
+U+c5ce eop # Character ì
+U+c5cf eoh # Character ì
+U+c5d0 e # Character ì
+U+c5d1 eg # Character ì
+U+c5d2 egg # Character ì
+U+c5d3 egs # Character ì
+U+c5d4 en # Character ì
+U+c5d5 enj # Character ì
+U+c5d6 enh # Character ì
+U+c5d7 ed # Character ì
+U+c5d8 el # Character ì
+U+c5d9 elg # Character ì
+U+c5da elm # Character ì
+U+c5db elb # Character ì
+U+c5dc els # Character ì
+U+c5dd elt # Character ì
+U+c5de elp # Character ì
+U+c5df elh # Character ì
+U+c5e0 em # Character ì
+U+c5e1 eb # Character ì¡
+U+c5e2 ebs # Character ì¢
+U+c5e3 es # Character ì£
+U+c5e4 ess # Character ì¤
+U+c5e5 eng # Character ì¥
+U+c5e6 ej # Character ì¦
+U+c5e7 ec # Character ì§
+U+c5e8 ek # Character ì¨
+U+c5e9 et # Character ì©
+U+c5ea ep # Character ìª
+U+c5eb eh # Character ì«
+U+c5ec yeo # Character ì¬
+U+c5ed yeog # Character ì
+U+c5ee yeogg # Character ì®
+U+c5ef yeogs # Character ì¯
+U+c5f0 yeon # Character ì°
+U+c5f1 yeonj # Character ì±
+U+c5f2 yeonh # Character ì²
+U+c5f3 yeod # Character ì³
+U+c5f4 yeol # Character ì´
+U+c5f5 yeolg # Character ìµ
+U+c5f6 yeolm # Character ì¶
+U+c5f7 yeolb # Character ì·
+U+c5f8 yeols # Character ì¸
+U+c5f9 yeolt # Character ì¹
+U+c5fa yeolp # Character ìº
+U+c5fb yeolh # Character ì»
+U+c5fc yeom # Character ì¼
+U+c5fd yeob # Character ì½
+U+c5fe yeobs # Character ì¾
+U+c5ff yeos # Character ì¿
diff --git a/resources/chars/ascii/rowc6.trans b/resources/chars/ascii/rowc6.trans
new file mode 100644
index 0000000..a753029
--- /dev/null
+++ b/resources/chars/ascii/rowc6.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+c600 yeoss # Character ì
+U+c601 yeong # Character ì
+U+c602 yeoj # Character ì
+U+c603 yeoc # Character ì
+U+c604 yeok # Character ì
+U+c605 yeot # Character ì
+U+c606 yeop # Character ì
+U+c607 yeoh # Character ì
+U+c608 ye # Character ì
+U+c609 yeg # Character ì
+U+c60a yegg # Character ì
+U+c60b yegs # Character ì
+U+c60c yen # Character ì
+U+c60d yenj # Character ì
+U+c60e yenh # Character ì
+U+c60f yed # Character ì
+U+c610 yel # Character ì
+U+c611 yelg # Character ì
+U+c612 yelm # Character ì
+U+c613 yelb # Character ì
+U+c614 yels # Character ì
+U+c615 yelt # Character ì
+U+c616 yelp # Character ì
+U+c617 yelh # Character ì
+U+c618 yem # Character ì
+U+c619 yeb # Character ì
+U+c61a yebs # Character ì
+U+c61b yes # Character ì
+U+c61c yess # Character ì
+U+c61d yeng # Character ì
+U+c61e yej # Character ì
+U+c61f yec # Character ì
+U+c620 yek # Character ì
+U+c621 yet # Character ì¡
+U+c622 yep # Character ì¢
+U+c623 yeh # Character ì£
+U+c624 o # Character ì¤
+U+c625 og # Character ì¥
+U+c626 ogg # Character ì¦
+U+c627 ogs # Character ì§
+U+c628 on # Character ì¨
+U+c629 onj # Character ì©
+U+c62a onh # Character ìª
+U+c62b od # Character ì«
+U+c62c ol # Character ì¬
+U+c62d olg # Character ì
+U+c62e olm # Character ì®
+U+c62f olb # Character ì¯
+U+c630 ols # Character ì°
+U+c631 olt # Character ì±
+U+c632 olp # Character ì²
+U+c633 olh # Character ì³
+U+c634 om # Character ì´
+U+c635 ob # Character ìµ
+U+c636 obs # Character ì¶
+U+c637 os # Character ì·
+U+c638 oss # Character ì¸
+U+c639 ong # Character ì¹
+U+c63a oj # Character ìº
+U+c63b oc # Character ì»
+U+c63c ok # Character ì¼
+U+c63d ot # Character ì½
+U+c63e op # Character ì¾
+U+c63f oh # Character ì¿
+U+c640 wa # Character ì
+U+c641 wag # Character ì
+U+c642 wagg # Character ì
+U+c643 wags # Character ì
+U+c644 wan # Character ì
+U+c645 wanj # Character ì
+U+c646 wanh # Character ì
+U+c647 wad # Character ì
+U+c648 wal # Character ì
+U+c649 walg # Character ì
+U+c64a walm # Character ì
+U+c64b walb # Character ì
+U+c64c wals # Character ì
+U+c64d walt # Character ì
+U+c64e walp # Character ì
+U+c64f walh # Character ì
+U+c650 wam # Character ì
+U+c651 wab # Character ì
+U+c652 wabs # Character ì
+U+c653 was # Character ì
+U+c654 wass # Character ì
+U+c655 wang # Character ì
+U+c656 waj # Character ì
+U+c657 wac # Character ì
+U+c658 wak # Character ì
+U+c659 wat # Character ì
+U+c65a wap # Character ì
+U+c65b wah # Character ì
+U+c65c wae # Character ì
+U+c65d waeg # Character ì
+U+c65e waegg # Character ì
+U+c65f waegs # Character ì
+U+c660 waen # Character ì
+U+c661 waenj # Character ì¡
+U+c662 waenh # Character ì¢
+U+c663 waed # Character ì£
+U+c664 wael # Character ì¤
+U+c665 waelg # Character ì¥
+U+c666 waelm # Character ì¦
+U+c667 waelb # Character ì§
+U+c668 waels # Character ì¨
+U+c669 waelt # Character ì©
+U+c66a waelp # Character ìª
+U+c66b waelh # Character ì«
+U+c66c waem # Character ì¬
+U+c66d waeb # Character ì
+U+c66e waebs # Character ì®
+U+c66f waes # Character ì¯
+U+c670 waess # Character ì°
+U+c671 waeng # Character ì±
+U+c672 waej # Character ì²
+U+c673 waec # Character ì³
+U+c674 waek # Character ì´
+U+c675 waet # Character ìµ
+U+c676 waep # Character ì¶
+U+c677 waeh # Character ì·
+U+c678 oe # Character ì¸
+U+c679 oeg # Character ì¹
+U+c67a oegg # Character ìº
+U+c67b oegs # Character ì»
+U+c67c oen # Character ì¼
+U+c67d oenj # Character ì½
+U+c67e oenh # Character ì¾
+U+c67f oed # Character ì¿
+U+c680 oel # Character ì
+U+c681 oelg # Character ì
+U+c682 oelm # Character ì
+U+c683 oelb # Character ì
+U+c684 oels # Character ì
+U+c685 oelt # Character ì
+U+c686 oelp # Character ì
+U+c687 oelh # Character ì
+U+c688 oem # Character ì
+U+c689 oeb # Character ì
+U+c68a oebs # Character ì
+U+c68b oes # Character ì
+U+c68c oess # Character ì
+U+c68d oeng # Character ì
+U+c68e oej # Character ì
+U+c68f oec # Character ì
+U+c690 oek # Character ì
+U+c691 oet # Character ì
+U+c692 oep # Character ì
+U+c693 oeh # Character ì
+U+c694 yo # Character ì
+U+c695 yog # Character ì
+U+c696 yogg # Character ì
+U+c697 yogs # Character ì
+U+c698 yon # Character ì
+U+c699 yonj # Character ì
+U+c69a yonh # Character ì
+U+c69b yod # Character ì
+U+c69c yol # Character ì
+U+c69d yolg # Character ì
+U+c69e yolm # Character ì
+U+c69f yolb # Character ì
+U+c6a0 yols # Character ì
+U+c6a1 yolt # Character ì¡
+U+c6a2 yolp # Character ì¢
+U+c6a3 yolh # Character ì£
+U+c6a4 yom # Character ì¤
+U+c6a5 yob # Character ì¥
+U+c6a6 yobs # Character ì¦
+U+c6a7 yos # Character ì§
+U+c6a8 yoss # Character ì¨
+U+c6a9 yong # Character ì©
+U+c6aa yoj # Character ìª
+U+c6ab yoc # Character ì«
+U+c6ac yok # Character ì¬
+U+c6ad yot # Character ì
+U+c6ae yop # Character ì®
+U+c6af yoh # Character ì¯
+U+c6b0 u # Character ì°
+U+c6b1 ug # Character ì±
+U+c6b2 ugg # Character ì²
+U+c6b3 ugs # Character ì³
+U+c6b4 un # Character ì´
+U+c6b5 unj # Character ìµ
+U+c6b6 unh # Character ì¶
+U+c6b7 ud # Character ì·
+U+c6b8 ul # Character ì¸
+U+c6b9 ulg # Character ì¹
+U+c6ba ulm # Character ìº
+U+c6bb ulb # Character ì»
+U+c6bc uls # Character ì¼
+U+c6bd ult # Character ì½
+U+c6be ulp # Character ì¾
+U+c6bf ulh # Character ì¿
+U+c6c0 um # Character ì
+U+c6c1 ub # Character ì
+U+c6c2 ubs # Character ì
+U+c6c3 us # Character ì
+U+c6c4 uss # Character ì
+U+c6c5 ung # Character ì
+U+c6c6 uj # Character ì
+U+c6c7 uc # Character ì
+U+c6c8 uk # Character ì
+U+c6c9 ut # Character ì
+U+c6ca up # Character ì
+U+c6cb uh # Character ì
+U+c6cc weo # Character ì
+U+c6cd weog # Character ì
+U+c6ce weogg # Character ì
+U+c6cf weogs # Character ì
+U+c6d0 weon # Character ì
+U+c6d1 weonj # Character ì
+U+c6d2 weonh # Character ì
+U+c6d3 weod # Character ì
+U+c6d4 weol # Character ì
+U+c6d5 weolg # Character ì
+U+c6d6 weolm # Character ì
+U+c6d7 weolb # Character ì
+U+c6d8 weols # Character ì
+U+c6d9 weolt # Character ì
+U+c6da weolp # Character ì
+U+c6db weolh # Character ì
+U+c6dc weom # Character ì
+U+c6dd weob # Character ì
+U+c6de weobs # Character ì
+U+c6df weos # Character ì
+U+c6e0 weoss # Character ì
+U+c6e1 weong # Character ì¡
+U+c6e2 weoj # Character ì¢
+U+c6e3 weoc # Character ì£
+U+c6e4 weok # Character ì¤
+U+c6e5 weot # Character ì¥
+U+c6e6 weop # Character ì¦
+U+c6e7 weoh # Character ì§
+U+c6e8 we # Character ì¨
+U+c6e9 weg # Character ì©
+U+c6ea wegg # Character ìª
+U+c6eb wegs # Character ì«
+U+c6ec wen # Character ì¬
+U+c6ed wenj # Character ì
+U+c6ee wenh # Character ì®
+U+c6ef wed # Character ì¯
+U+c6f0 wel # Character ì°
+U+c6f1 welg # Character ì±
+U+c6f2 welm # Character ì²
+U+c6f3 welb # Character ì³
+U+c6f4 wels # Character ì´
+U+c6f5 welt # Character ìµ
+U+c6f6 welp # Character ì¶
+U+c6f7 welh # Character ì·
+U+c6f8 wem # Character ì¸
+U+c6f9 web # Character ì¹
+U+c6fa webs # Character ìº
+U+c6fb wes # Character ì»
+U+c6fc wess # Character ì¼
+U+c6fd weng # Character ì½
+U+c6fe wej # Character ì¾
+U+c6ff wec # Character ì¿
diff --git a/resources/chars/ascii/rowc7.trans b/resources/chars/ascii/rowc7.trans
new file mode 100644
index 0000000..85f1b26
--- /dev/null
+++ b/resources/chars/ascii/rowc7.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+c700 wek # Character ì
+U+c701 wet # Character ì
+U+c702 wep # Character ì
+U+c703 weh # Character ì
+U+c704 wi # Character ì
+U+c705 wig # Character ì
+U+c706 wigg # Character ì
+U+c707 wigs # Character ì
+U+c708 win # Character ì
+U+c709 winj # Character ì
+U+c70a winh # Character ì
+U+c70b wid # Character ì
+U+c70c wil # Character ì
+U+c70d wilg # Character ì
+U+c70e wilm # Character ì
+U+c70f wilb # Character ì
+U+c710 wils # Character ì
+U+c711 wilt # Character ì
+U+c712 wilp # Character ì
+U+c713 wilh # Character ì
+U+c714 wim # Character ì
+U+c715 wib # Character ì
+U+c716 wibs # Character ì
+U+c717 wis # Character ì
+U+c718 wiss # Character ì
+U+c719 wing # Character ì
+U+c71a wij # Character ì
+U+c71b wic # Character ì
+U+c71c wik # Character ì
+U+c71d wit # Character ì
+U+c71e wip # Character ì
+U+c71f wih # Character ì
+U+c720 yu # Character ì
+U+c721 yug # Character ì¡
+U+c722 yugg # Character ì¢
+U+c723 yugs # Character ì£
+U+c724 yun # Character ì¤
+U+c725 yunj # Character ì¥
+U+c726 yunh # Character ì¦
+U+c727 yud # Character ì§
+U+c728 yul # Character ì¨
+U+c729 yulg # Character ì©
+U+c72a yulm # Character ìª
+U+c72b yulb # Character ì«
+U+c72c yuls # Character ì¬
+U+c72d yult # Character ì
+U+c72e yulp # Character ì®
+U+c72f yulh # Character ì¯
+U+c730 yum # Character ì°
+U+c731 yub # Character ì±
+U+c732 yubs # Character ì²
+U+c733 yus # Character ì³
+U+c734 yuss # Character ì´
+U+c735 yung # Character ìµ
+U+c736 yuj # Character ì¶
+U+c737 yuc # Character ì·
+U+c738 yuk # Character ì¸
+U+c739 yut # Character ì¹
+U+c73a yup # Character ìº
+U+c73b yuh # Character ì»
+U+c73c eu # Character ì¼
+U+c73d eug # Character ì½
+U+c73e eugg # Character ì¾
+U+c73f eugs # Character ì¿
+U+c740 eun # Character ì
+U+c741 eunj # Character ì
+U+c742 eunh # Character ì
+U+c743 eud # Character ì
+U+c744 eul # Character ì
+U+c745 eulg # Character ì
+U+c746 eulm # Character ì
+U+c747 eulb # Character ì
+U+c748 euls # Character ì
+U+c749 eult # Character ì
+U+c74a eulp # Character ì
+U+c74b eulh # Character ì
+U+c74c eum # Character ì
+U+c74d eub # Character ì
+U+c74e eubs # Character ì
+U+c74f eus # Character ì
+U+c750 euss # Character ì
+U+c751 eung # Character ì
+U+c752 euj # Character ì
+U+c753 euc # Character ì
+U+c754 euk # Character ì
+U+c755 eut # Character ì
+U+c756 eup # Character ì
+U+c757 euh # Character ì
+U+c758 yi # Character ì
+U+c759 yig # Character ì
+U+c75a yigg # Character ì
+U+c75b yigs # Character ì
+U+c75c yin # Character ì
+U+c75d yinj # Character ì
+U+c75e yinh # Character ì
+U+c75f yid # Character ì
+U+c760 yil # Character ì
+U+c761 yilg # Character ì¡
+U+c762 yilm # Character ì¢
+U+c763 yilb # Character ì£
+U+c764 yils # Character ì¤
+U+c765 yilt # Character ì¥
+U+c766 yilp # Character ì¦
+U+c767 yilh # Character ì§
+U+c768 yim # Character ì¨
+U+c769 yib # Character ì©
+U+c76a yibs # Character ìª
+U+c76b yis # Character ì«
+U+c76c yiss # Character ì¬
+U+c76d ying # Character ì
+U+c76e yij # Character ì®
+U+c76f yic # Character ì¯
+U+c770 yik # Character ì°
+U+c771 yit # Character ì±
+U+c772 yip # Character ì²
+U+c773 yih # Character ì³
+U+c774 i # Character ì´
+U+c775 ig # Character ìµ
+U+c776 igg # Character ì¶
+U+c777 igs # Character ì·
+U+c778 in # Character ì¸
+U+c779 inj # Character ì¹
+U+c77a inh # Character ìº
+U+c77b id # Character ì»
+U+c77c il # Character ì¼
+U+c77d ilg # Character ì½
+U+c77e ilm # Character ì¾
+U+c77f ilb # Character ì¿
+U+c780 ils # Character ì
+U+c781 ilt # Character ì
+U+c782 ilp # Character ì
+U+c783 ilh # Character ì
+U+c784 im # Character ì
+U+c785 ib # Character ì
+U+c786 ibs # Character ì
+U+c787 is # Character ì
+U+c788 iss # Character ì
+U+c789 ing # Character ì
+U+c78a ij # Character ì
+U+c78b ic # Character ì
+U+c78c ik # Character ì
+U+c78d it # Character ì
+U+c78e ip # Character ì
+U+c78f ih # Character ì
+U+c790 ja # Character ì
+U+c791 jag # Character ì
+U+c792 jagg # Character ì
+U+c793 jags # Character ì
+U+c794 jan # Character ì
+U+c795 janj # Character ì
+U+c796 janh # Character ì
+U+c797 jad # Character ì
+U+c798 jal # Character ì
+U+c799 jalg # Character ì
+U+c79a jalm # Character ì
+U+c79b jalb # Character ì
+U+c79c jals # Character ì
+U+c79d jalt # Character ì
+U+c79e jalp # Character ì
+U+c79f jalh # Character ì
+U+c7a0 jam # Character ì
+U+c7a1 jab # Character ì¡
+U+c7a2 jabs # Character ì¢
+U+c7a3 jas # Character ì£
+U+c7a4 jass # Character ì¤
+U+c7a5 jang # Character ì¥
+U+c7a6 jaj # Character ì¦
+U+c7a7 jac # Character ì§
+U+c7a8 jak # Character ì¨
+U+c7a9 jat # Character ì©
+U+c7aa jap # Character ìª
+U+c7ab jah # Character ì«
+U+c7ac jae # Character ì¬
+U+c7ad jaeg # Character ì
+U+c7ae jaegg # Character ì®
+U+c7af jaegs # Character ì¯
+U+c7b0 jaen # Character ì°
+U+c7b1 jaenj # Character ì±
+U+c7b2 jaenh # Character ì²
+U+c7b3 jaed # Character ì³
+U+c7b4 jael # Character ì´
+U+c7b5 jaelg # Character ìµ
+U+c7b6 jaelm # Character ì¶
+U+c7b7 jaelb # Character ì·
+U+c7b8 jaels # Character ì¸
+U+c7b9 jaelt # Character ì¹
+U+c7ba jaelp # Character ìº
+U+c7bb jaelh # Character ì»
+U+c7bc jaem # Character ì¼
+U+c7bd jaeb # Character ì½
+U+c7be jaebs # Character ì¾
+U+c7bf jaes # Character ì¿
+U+c7c0 jaess # Character ì
+U+c7c1 jaeng # Character ì
+U+c7c2 jaej # Character ì
+U+c7c3 jaec # Character ì
+U+c7c4 jaek # Character ì
+U+c7c5 jaet # Character ì
+U+c7c6 jaep # Character ì
+U+c7c7 jaeh # Character ì
+U+c7c8 jya # Character ì
+U+c7c9 jyag # Character ì
+U+c7ca jyagg # Character ì
+U+c7cb jyags # Character ì
+U+c7cc jyan # Character ì
+U+c7cd jyanj # Character ì
+U+c7ce jyanh # Character ì
+U+c7cf jyad # Character ì
+U+c7d0 jyal # Character ì
+U+c7d1 jyalg # Character ì
+U+c7d2 jyalm # Character ì
+U+c7d3 jyalb # Character ì
+U+c7d4 jyals # Character ì
+U+c7d5 jyalt # Character ì
+U+c7d6 jyalp # Character ì
+U+c7d7 jyalh # Character ì
+U+c7d8 jyam # Character ì
+U+c7d9 jyab # Character ì
+U+c7da jyabs # Character ì
+U+c7db jyas # Character ì
+U+c7dc jyass # Character ì
+U+c7dd jyang # Character ì
+U+c7de jyaj # Character ì
+U+c7df jyac # Character ì
+U+c7e0 jyak # Character ì
+U+c7e1 jyat # Character ì¡
+U+c7e2 jyap # Character ì¢
+U+c7e3 jyah # Character ì£
+U+c7e4 jyae # Character ì¤
+U+c7e5 jyaeg # Character ì¥
+U+c7e6 jyaegg # Character ì¦
+U+c7e7 jyaegs # Character ì§
+U+c7e8 jyaen # Character ì¨
+U+c7e9 jyaenj # Character ì©
+U+c7ea jyaenh # Character ìª
+U+c7eb jyaed # Character ì«
+U+c7ec jyael # Character ì¬
+U+c7ed jyaelg # Character ì
+U+c7ee jyaelm # Character ì®
+U+c7ef jyaelb # Character ì¯
+U+c7f0 jyaels # Character ì°
+U+c7f1 jyaelt # Character ì±
+U+c7f2 jyaelp # Character ì²
+U+c7f3 jyaelh # Character ì³
+U+c7f4 jyaem # Character ì´
+U+c7f5 jyaeb # Character ìµ
+U+c7f6 jyaebs # Character ì¶
+U+c7f7 jyaes # Character ì·
+U+c7f8 jyaess # Character ì¸
+U+c7f9 jyaeng # Character ì¹
+U+c7fa jyaej # Character ìº
+U+c7fb jyaec # Character ì»
+U+c7fc jyaek # Character ì¼
+U+c7fd jyaet # Character ì½
+U+c7fe jyaep # Character ì¾
+U+c7ff jyaeh # Character ì¿
diff --git a/resources/chars/ascii/rowc8.trans b/resources/chars/ascii/rowc8.trans
new file mode 100644
index 0000000..da58f1e
--- /dev/null
+++ b/resources/chars/ascii/rowc8.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+c800 jeo # Character ì
+U+c801 jeog # Character ì
+U+c802 jeogg # Character ì
+U+c803 jeogs # Character ì
+U+c804 jeon # Character ì
+U+c805 jeonj # Character ì
+U+c806 jeonh # Character ì
+U+c807 jeod # Character ì
+U+c808 jeol # Character ì
+U+c809 jeolg # Character ì
+U+c80a jeolm # Character ì
+U+c80b jeolb # Character ì
+U+c80c jeols # Character ì
+U+c80d jeolt # Character ì
+U+c80e jeolp # Character ì
+U+c80f jeolh # Character ì
+U+c810 jeom # Character ì
+U+c811 jeob # Character ì
+U+c812 jeobs # Character ì
+U+c813 jeos # Character ì
+U+c814 jeoss # Character ì
+U+c815 jeong # Character ì
+U+c816 jeoj # Character ì
+U+c817 jeoc # Character ì
+U+c818 jeok # Character ì
+U+c819 jeot # Character ì
+U+c81a jeop # Character ì
+U+c81b jeoh # Character ì
+U+c81c je # Character ì
+U+c81d jeg # Character ì
+U+c81e jegg # Character ì
+U+c81f jegs # Character ì
+U+c820 jen # Character ì
+U+c821 jenj # Character ì ¡
+U+c822 jenh # Character ì ¢
+U+c823 jed # Character ì £
+U+c824 jel # Character ì ¤
+U+c825 jelg # Character ì ¥
+U+c826 jelm # Character ì ¦
+U+c827 jelb # Character ì §
+U+c828 jels # Character ì ¨
+U+c829 jelt # Character ì ©
+U+c82a jelp # Character ì ª
+U+c82b jelh # Character ì «
+U+c82c jem # Character ì ¬
+U+c82d jeb # Character ì
+U+c82e jebs # Character ì ®
+U+c82f jes # Character ì ¯
+U+c830 jess # Character ì °
+U+c831 jeng # Character ì ±
+U+c832 jej # Character ì ²
+U+c833 jec # Character ì ³
+U+c834 jek # Character ì ´
+U+c835 jet # Character ì µ
+U+c836 jep # Character ì ¶
+U+c837 jeh # Character ì ·
+U+c838 jyeo # Character ì ¸
+U+c839 jyeog # Character ì ¹
+U+c83a jyeogg # Character ì º
+U+c83b jyeogs # Character ì »
+U+c83c jyeon # Character ì ¼
+U+c83d jyeonj # Character ì ½
+U+c83e jyeonh # Character ì ¾
+U+c83f jyeod # Character ì ¿
+U+c840 jyeol # Character ì¡
+U+c841 jyeolg # Character ì¡
+U+c842 jyeolm # Character ì¡
+U+c843 jyeolb # Character ì¡
+U+c844 jyeols # Character ì¡
+U+c845 jyeolt # Character ì¡
+U+c846 jyeolp # Character ì¡
+U+c847 jyeolh # Character ì¡
+U+c848 jyeom # Character ì¡
+U+c849 jyeob # Character ì¡
+U+c84a jyeobs # Character ì¡
+U+c84b jyeos # Character ì¡
+U+c84c jyeoss # Character ì¡
+U+c84d jyeong # Character ì¡
+U+c84e jyeoj # Character ì¡
+U+c84f jyeoc # Character ì¡
+U+c850 jyeok # Character ì¡
+U+c851 jyeot # Character ì¡
+U+c852 jyeop # Character ì¡
+U+c853 jyeoh # Character ì¡
+U+c854 jye # Character ì¡
+U+c855 jyeg # Character ì¡
+U+c856 jyegg # Character ì¡
+U+c857 jyegs # Character ì¡
+U+c858 jyen # Character ì¡
+U+c859 jyenj # Character ì¡
+U+c85a jyenh # Character ì¡
+U+c85b jyed # Character ì¡
+U+c85c jyel # Character ì¡
+U+c85d jyelg # Character ì¡
+U+c85e jyelm # Character ì¡
+U+c85f jyelb # Character ì¡
+U+c860 jyels # Character ì¡
+U+c861 jyelt # Character ì¡¡
+U+c862 jyelp # Character ì¡¢
+U+c863 jyelh # Character ì¡£
+U+c864 jyem # Character 졤
+U+c865 jyeb # Character ì¡¥
+U+c866 jyebs # Character 졦
+U+c867 jyes # Character 졧
+U+c868 jyess # Character 졨
+U+c869 jyeng # Character ì¡©
+U+c86a jyej # Character 졪
+U+c86b jyec # Character ì¡«
+U+c86c jyek # Character 졬
+U+c86d jyet # Character ì¡
+U+c86e jyep # Character ì¡®
+U+c86f jyeh # Character 졯
+U+c870 jo # Character ì¡°
+U+c871 jog # Character 족
+U+c872 jogg # Character 졲
+U+c873 jogs # Character 졳
+U+c874 jon # Character ì¡´
+U+c875 jonj # Character 졵
+U+c876 jonh # Character 졶
+U+c877 jod # Character ì¡·
+U+c878 jol # Character 졸
+U+c879 jolg # Character 졹
+U+c87a jolm # Character 졺
+U+c87b jolb # Character ì¡»
+U+c87c jols # Character 졼
+U+c87d jolt # Character 졽
+U+c87e jolp # Character 졾
+U+c87f jolh # Character ì¡¿
+U+c880 jom # Character ì¢
+U+c881 job # Character ì¢
+U+c882 jobs # Character ì¢
+U+c883 jos # Character ì¢
+U+c884 joss # Character ì¢
+U+c885 jong # Character ì¢
+U+c886 joj # Character ì¢
+U+c887 joc # Character ì¢
+U+c888 jok # Character ì¢
+U+c889 jot # Character ì¢
+U+c88a jop # Character ì¢
+U+c88b joh # Character ì¢
+U+c88c jwa # Character ì¢
+U+c88d jwag # Character ì¢
+U+c88e jwagg # Character ì¢
+U+c88f jwags # Character ì¢
+U+c890 jwan # Character ì¢
+U+c891 jwanj # Character ì¢
+U+c892 jwanh # Character ì¢
+U+c893 jwad # Character ì¢
+U+c894 jwal # Character ì¢
+U+c895 jwalg # Character ì¢
+U+c896 jwalm # Character ì¢
+U+c897 jwalb # Character ì¢
+U+c898 jwals # Character ì¢
+U+c899 jwalt # Character ì¢
+U+c89a jwalp # Character ì¢
+U+c89b jwalh # Character ì¢
+U+c89c jwam # Character ì¢
+U+c89d jwab # Character ì¢
+U+c89e jwabs # Character ì¢
+U+c89f jwas # Character ì¢
+U+c8a0 jwass # Character ì¢
+U+c8a1 jwang # Character 좡
+U+c8a2 jwaj # Character 좢
+U+c8a3 jwac # Character 좣
+U+c8a4 jwak # Character 좤
+U+c8a5 jwat # Character 좥
+U+c8a6 jwap # Character 좦
+U+c8a7 jwah # Character 좧
+U+c8a8 jwae # Character 좨
+U+c8a9 jwaeg # Character 좩
+U+c8aa jwaegg # Character 좪
+U+c8ab jwaegs # Character 좫
+U+c8ac jwaen # Character 좬
+U+c8ad jwaenj # Character ì¢
+U+c8ae jwaenh # Character 좮
+U+c8af jwaed # Character 좯
+U+c8b0 jwael # Character 좰
+U+c8b1 jwaelg # Character 좱
+U+c8b2 jwaelm # Character 좲
+U+c8b3 jwaelb # Character 좳
+U+c8b4 jwaels # Character 좴
+U+c8b5 jwaelt # Character 좵
+U+c8b6 jwaelp # Character 좶
+U+c8b7 jwaelh # Character 좷
+U+c8b8 jwaem # Character 좸
+U+c8b9 jwaeb # Character 좹
+U+c8ba jwaebs # Character 좺
+U+c8bb jwaes # Character 좻
+U+c8bc jwaess # Character 좼
+U+c8bd jwaeng # Character 좽
+U+c8be jwaej # Character 좾
+U+c8bf jwaec # Character 좿
+U+c8c0 jwaek # Character ì£
+U+c8c1 jwaet # Character ì£
+U+c8c2 jwaep # Character ì£
+U+c8c3 jwaeh # Character ì£
+U+c8c4 joe # Character ì£
+U+c8c5 joeg # Character ì£
+U+c8c6 joegg # Character ì£
+U+c8c7 joegs # Character ì£
+U+c8c8 joen # Character ì£
+U+c8c9 joenj # Character ì£
+U+c8ca joenh # Character ì£
+U+c8cb joed # Character ì£
+U+c8cc joel # Character ì£
+U+c8cd joelg # Character ì£
+U+c8ce joelm # Character ì£
+U+c8cf joelb # Character ì£
+U+c8d0 joels # Character ì£
+U+c8d1 joelt # Character ì£
+U+c8d2 joelp # Character ì£
+U+c8d3 joelh # Character ì£
+U+c8d4 joem # Character ì£
+U+c8d5 joeb # Character ì£
+U+c8d6 joebs # Character ì£
+U+c8d7 joes # Character ì£
+U+c8d8 joess # Character ì£
+U+c8d9 joeng # Character ì£
+U+c8da joej # Character ì£
+U+c8db joec # Character ì£
+U+c8dc joek # Character ì£
+U+c8dd joet # Character ì£
+U+c8de joep # Character ì£
+U+c8df joeh # Character ì£
+U+c8e0 jyo # Character ì£
+U+c8e1 jyog # Character 죡
+U+c8e2 jyogg # Character 죢
+U+c8e3 jyogs # Character 죣
+U+c8e4 jyon # Character 죤
+U+c8e5 jyonj # Character 죥
+U+c8e6 jyonh # Character 죦
+U+c8e7 jyod # Character 죧
+U+c8e8 jyol # Character 죨
+U+c8e9 jyolg # Character 죩
+U+c8ea jyolm # Character 죪
+U+c8eb jyolb # Character 죫
+U+c8ec jyols # Character 죬
+U+c8ed jyolt # Character ì£
+U+c8ee jyolp # Character 죮
+U+c8ef jyolh # Character 죯
+U+c8f0 jyom # Character 죰
+U+c8f1 jyob # Character 죱
+U+c8f2 jyobs # Character 죲
+U+c8f3 jyos # Character 죳
+U+c8f4 jyoss # Character 죴
+U+c8f5 jyong # Character 죵
+U+c8f6 jyoj # Character 죶
+U+c8f7 jyoc # Character 죷
+U+c8f8 jyok # Character 죸
+U+c8f9 jyot # Character 죹
+U+c8fa jyop # Character 죺
+U+c8fb jyoh # Character 죻
+U+c8fc ju # Character 주
+U+c8fd jug # Character 죽
+U+c8fe jugg # Character 죾
+U+c8ff jugs # Character 죿
diff --git a/resources/chars/ascii/rowc9.trans b/resources/chars/ascii/rowc9.trans
new file mode 100644
index 0000000..2c1f4d7
--- /dev/null
+++ b/resources/chars/ascii/rowc9.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+c900 jun # Character ì¤
+U+c901 junj # Character ì¤
+U+c902 junh # Character ì¤
+U+c903 jud # Character ì¤
+U+c904 jul # Character ì¤
+U+c905 julg # Character ì¤
+U+c906 julm # Character ì¤
+U+c907 julb # Character ì¤
+U+c908 juls # Character ì¤
+U+c909 jult # Character ì¤
+U+c90a julp # Character ì¤
+U+c90b julh # Character ì¤
+U+c90c jum # Character ì¤
+U+c90d jub # Character ì¤
+U+c90e jubs # Character ì¤
+U+c90f jus # Character ì¤
+U+c910 juss # Character ì¤
+U+c911 jung # Character ì¤
+U+c912 juj # Character ì¤
+U+c913 juc # Character ì¤
+U+c914 juk # Character ì¤
+U+c915 jut # Character ì¤
+U+c916 jup # Character ì¤
+U+c917 juh # Character ì¤
+U+c918 jweo # Character ì¤
+U+c919 jweog # Character ì¤
+U+c91a jweogg # Character ì¤
+U+c91b jweogs # Character ì¤
+U+c91c jweon # Character ì¤
+U+c91d jweonj # Character ì¤
+U+c91e jweonh # Character ì¤
+U+c91f jweod # Character ì¤
+U+c920 jweol # Character ì¤
+U+c921 jweolg # Character 줡
+U+c922 jweolm # Character 줢
+U+c923 jweolb # Character 줣
+U+c924 jweols # Character 줤
+U+c925 jweolt # Character 줥
+U+c926 jweolp # Character 줦
+U+c927 jweolh # Character 줧
+U+c928 jweom # Character 줨
+U+c929 jweob # Character 줩
+U+c92a jweobs # Character 줪
+U+c92b jweos # Character 줫
+U+c92c jweoss # Character 줬
+U+c92d jweong # Character ì¤
+U+c92e jweoj # Character 줮
+U+c92f jweoc # Character 줯
+U+c930 jweok # Character 줰
+U+c931 jweot # Character 줱
+U+c932 jweop # Character 줲
+U+c933 jweoh # Character 줳
+U+c934 jwe # Character 줴
+U+c935 jweg # Character 줵
+U+c936 jwegg # Character 줶
+U+c937 jwegs # Character 줷
+U+c938 jwen # Character 줸
+U+c939 jwenj # Character 줹
+U+c93a jwenh # Character 줺
+U+c93b jwed # Character 줻
+U+c93c jwel # Character 줼
+U+c93d jwelg # Character 줽
+U+c93e jwelm # Character 줾
+U+c93f jwelb # Character 줿
+U+c940 jwels # Character ì¥
+U+c941 jwelt # Character ì¥
+U+c942 jwelp # Character ì¥
+U+c943 jwelh # Character ì¥
+U+c944 jwem # Character ì¥
+U+c945 jweb # Character ì¥
+U+c946 jwebs # Character ì¥
+U+c947 jwes # Character ì¥
+U+c948 jwess # Character ì¥
+U+c949 jweng # Character ì¥
+U+c94a jwej # Character ì¥
+U+c94b jwec # Character ì¥
+U+c94c jwek # Character ì¥
+U+c94d jwet # Character ì¥
+U+c94e jwep # Character ì¥
+U+c94f jweh # Character ì¥
+U+c950 jwi # Character ì¥
+U+c951 jwig # Character ì¥
+U+c952 jwigg # Character ì¥
+U+c953 jwigs # Character ì¥
+U+c954 jwin # Character ì¥
+U+c955 jwinj # Character ì¥
+U+c956 jwinh # Character ì¥
+U+c957 jwid # Character ì¥
+U+c958 jwil # Character ì¥
+U+c959 jwilg # Character ì¥
+U+c95a jwilm # Character ì¥
+U+c95b jwilb # Character ì¥
+U+c95c jwils # Character ì¥
+U+c95d jwilt # Character ì¥
+U+c95e jwilp # Character ì¥
+U+c95f jwilh # Character ì¥
+U+c960 jwim # Character ì¥
+U+c961 jwib # Character 쥡
+U+c962 jwibs # Character 쥢
+U+c963 jwis # Character 쥣
+U+c964 jwiss # Character 쥤
+U+c965 jwing # Character 쥥
+U+c966 jwij # Character 쥦
+U+c967 jwic # Character 쥧
+U+c968 jwik # Character 쥨
+U+c969 jwit # Character 쥩
+U+c96a jwip # Character 쥪
+U+c96b jwih # Character 쥫
+U+c96c jyu # Character 쥬
+U+c96d jyug # Character ì¥
+U+c96e jyugg # Character 쥮
+U+c96f jyugs # Character 쥯
+U+c970 jyun # Character 쥰
+U+c971 jyunj # Character 쥱
+U+c972 jyunh # Character 쥲
+U+c973 jyud # Character 쥳
+U+c974 jyul # Character 쥴
+U+c975 jyulg # Character 쥵
+U+c976 jyulm # Character 쥶
+U+c977 jyulb # Character 쥷
+U+c978 jyuls # Character 쥸
+U+c979 jyult # Character 쥹
+U+c97a jyulp # Character 쥺
+U+c97b jyulh # Character 쥻
+U+c97c jyum # Character 쥼
+U+c97d jyub # Character 쥽
+U+c97e jyubs # Character 쥾
+U+c97f jyus # Character 쥿
+U+c980 jyuss # Character ì¦
+U+c981 jyung # Character ì¦
+U+c982 jyuj # Character ì¦
+U+c983 jyuc # Character ì¦
+U+c984 jyuk # Character ì¦
+U+c985 jyut # Character ì¦
+U+c986 jyup # Character ì¦
+U+c987 jyuh # Character ì¦
+U+c988 jeu # Character ì¦
+U+c989 jeug # Character ì¦
+U+c98a jeugg # Character ì¦
+U+c98b jeugs # Character ì¦
+U+c98c jeun # Character ì¦
+U+c98d jeunj # Character ì¦
+U+c98e jeunh # Character ì¦
+U+c98f jeud # Character ì¦
+U+c990 jeul # Character ì¦
+U+c991 jeulg # Character ì¦
+U+c992 jeulm # Character ì¦
+U+c993 jeulb # Character ì¦
+U+c994 jeuls # Character ì¦
+U+c995 jeult # Character ì¦
+U+c996 jeulp # Character ì¦
+U+c997 jeulh # Character ì¦
+U+c998 jeum # Character ì¦
+U+c999 jeub # Character ì¦
+U+c99a jeubs # Character ì¦
+U+c99b jeus # Character ì¦
+U+c99c jeuss # Character ì¦
+U+c99d jeung # Character ì¦
+U+c99e jeuj # Character ì¦
+U+c99f jeuc # Character ì¦
+U+c9a0 jeuk # Character ì¦
+U+c9a1 jeut # Character 즡
+U+c9a2 jeup # Character 즢
+U+c9a3 jeuh # Character 즣
+U+c9a4 jyi # Character 즤
+U+c9a5 jyig # Character 즥
+U+c9a6 jyigg # Character 즦
+U+c9a7 jyigs # Character 즧
+U+c9a8 jyin # Character 즨
+U+c9a9 jyinj # Character 즩
+U+c9aa jyinh # Character 즪
+U+c9ab jyid # Character 즫
+U+c9ac jyil # Character 즬
+U+c9ad jyilg # Character ì¦
+U+c9ae jyilm # Character 즮
+U+c9af jyilb # Character 즯
+U+c9b0 jyils # Character 즰
+U+c9b1 jyilt # Character 즱
+U+c9b2 jyilp # Character 즲
+U+c9b3 jyilh # Character 즳
+U+c9b4 jyim # Character 즴
+U+c9b5 jyib # Character 즵
+U+c9b6 jyibs # Character 즶
+U+c9b7 jyis # Character 즷
+U+c9b8 jyiss # Character 즸
+U+c9b9 jying # Character 즹
+U+c9ba jyij # Character 즺
+U+c9bb jyic # Character 즻
+U+c9bc jyik # Character 즼
+U+c9bd jyit # Character 즽
+U+c9be jyip # Character 즾
+U+c9bf jyih # Character 즿
+U+c9c0 ji # Character ì§
+U+c9c1 jig # Character ì§
+U+c9c2 jigg # Character ì§
+U+c9c3 jigs # Character ì§
+U+c9c4 jin # Character ì§
+U+c9c5 jinj # Character ì§
+U+c9c6 jinh # Character ì§
+U+c9c7 jid # Character ì§
+U+c9c8 jil # Character ì§
+U+c9c9 jilg # Character ì§
+U+c9ca jilm # Character ì§
+U+c9cb jilb # Character ì§
+U+c9cc jils # Character ì§
+U+c9cd jilt # Character ì§
+U+c9ce jilp # Character ì§
+U+c9cf jilh # Character ì§
+U+c9d0 jim # Character ì§
+U+c9d1 jib # Character ì§
+U+c9d2 jibs # Character ì§
+U+c9d3 jis # Character ì§
+U+c9d4 jiss # Character ì§
+U+c9d5 jing # Character ì§
+U+c9d6 jij # Character ì§
+U+c9d7 jic # Character ì§
+U+c9d8 jik # Character ì§
+U+c9d9 jit # Character ì§
+U+c9da jip # Character ì§
+U+c9db jih # Character ì§
+U+c9dc jja # Character ì§
+U+c9dd jjag # Character ì§
+U+c9de jjagg # Character ì§
+U+c9df jjags # Character ì§
+U+c9e0 jjan # Character ì§
+U+c9e1 jjanj # Character 짡
+U+c9e2 jjanh # Character 짢
+U+c9e3 jjad # Character 짣
+U+c9e4 jjal # Character 짤
+U+c9e5 jjalg # Character 짥
+U+c9e6 jjalm # Character 짦
+U+c9e7 jjalb # Character 짧
+U+c9e8 jjals # Character 짨
+U+c9e9 jjalt # Character 짩
+U+c9ea jjalp # Character 짪
+U+c9eb jjalh # Character 짫
+U+c9ec jjam # Character 짬
+U+c9ed jjab # Character ì§
+U+c9ee jjabs # Character 짮
+U+c9ef jjas # Character 짯
+U+c9f0 jjass # Character 짰
+U+c9f1 jjang # Character 짱
+U+c9f2 jjaj # Character 짲
+U+c9f3 jjac # Character 짳
+U+c9f4 jjak # Character 짴
+U+c9f5 jjat # Character 짵
+U+c9f6 jjap # Character 짶
+U+c9f7 jjah # Character 짷
+U+c9f8 jjae # Character 째
+U+c9f9 jjaeg # Character 짹
+U+c9fa jjaegg # Character 짺
+U+c9fb jjaegs # Character 짻
+U+c9fc jjaen # Character 짼
+U+c9fd jjaenj # Character 짽
+U+c9fe jjaenh # Character 짾
+U+c9ff jjaed # Character 짿
diff --git a/resources/chars/ascii/rowca.trans b/resources/chars/ascii/rowca.trans
new file mode 100644
index 0000000..ed12d45
--- /dev/null
+++ b/resources/chars/ascii/rowca.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+ca00 jjael # Character ì¨
+U+ca01 jjaelg # Character ì¨
+U+ca02 jjaelm # Character ì¨
+U+ca03 jjaelb # Character ì¨
+U+ca04 jjaels # Character ì¨
+U+ca05 jjaelt # Character ì¨
+U+ca06 jjaelp # Character ì¨
+U+ca07 jjaelh # Character ì¨
+U+ca08 jjaem # Character ì¨
+U+ca09 jjaeb # Character ì¨
+U+ca0a jjaebs # Character ì¨
+U+ca0b jjaes # Character ì¨
+U+ca0c jjaess # Character ì¨
+U+ca0d jjaeng # Character ì¨
+U+ca0e jjaej # Character ì¨
+U+ca0f jjaec # Character ì¨
+U+ca10 jjaek # Character ì¨
+U+ca11 jjaet # Character ì¨
+U+ca12 jjaep # Character ì¨
+U+ca13 jjaeh # Character ì¨
+U+ca14 jjya # Character ì¨
+U+ca15 jjyag # Character ì¨
+U+ca16 jjyagg # Character ì¨
+U+ca17 jjyags # Character ì¨
+U+ca18 jjyan # Character ì¨
+U+ca19 jjyanj # Character ì¨
+U+ca1a jjyanh # Character ì¨
+U+ca1b jjyad # Character ì¨
+U+ca1c jjyal # Character ì¨
+U+ca1d jjyalg # Character ì¨
+U+ca1e jjyalm # Character ì¨
+U+ca1f jjyalb # Character ì¨
+U+ca20 jjyals # Character ì¨
+U+ca21 jjyalt # Character 쨡
+U+ca22 jjyalp # Character 쨢
+U+ca23 jjyalh # Character 쨣
+U+ca24 jjyam # Character 쨤
+U+ca25 jjyab # Character 쨥
+U+ca26 jjyabs # Character 쨦
+U+ca27 jjyas # Character 쨧
+U+ca28 jjyass # Character 쨨
+U+ca29 jjyang # Character 쨩
+U+ca2a jjyaj # Character 쨪
+U+ca2b jjyac # Character 쨫
+U+ca2c jjyak # Character 쨬
+U+ca2d jjyat # Character ì¨
+U+ca2e jjyap # Character 쨮
+U+ca2f jjyah # Character 쨯
+U+ca30 jjyae # Character 쨰
+U+ca31 jjyaeg # Character 쨱
+U+ca32 jjyaegg # Character 쨲
+U+ca33 jjyaegs # Character 쨳
+U+ca34 jjyaen # Character 쨴
+U+ca35 jjyaenj # Character 쨵
+U+ca36 jjyaenh # Character 쨶
+U+ca37 jjyaed # Character 쨷
+U+ca38 jjyael # Character 쨸
+U+ca39 jjyaelg # Character 쨹
+U+ca3a jjyaelm # Character 쨺
+U+ca3b jjyaelb # Character 쨻
+U+ca3c jjyaels # Character 쨼
+U+ca3d jjyaelt # Character 쨽
+U+ca3e jjyaelp # Character 쨾
+U+ca3f jjyaelh # Character 쨿
+U+ca40 jjyaem # Character ì©
+U+ca41 jjyaeb # Character ì©
+U+ca42 jjyaebs # Character ì©
+U+ca43 jjyaes # Character ì©
+U+ca44 jjyaess # Character ì©
+U+ca45 jjyaeng # Character ì©
+U+ca46 jjyaej # Character ì©
+U+ca47 jjyaec # Character ì©
+U+ca48 jjyaek # Character ì©
+U+ca49 jjyaet # Character ì©
+U+ca4a jjyaep # Character ì©
+U+ca4b jjyaeh # Character ì©
+U+ca4c jjeo # Character ì©
+U+ca4d jjeog # Character ì©
+U+ca4e jjeogg # Character ì©
+U+ca4f jjeogs # Character ì©
+U+ca50 jjeon # Character ì©
+U+ca51 jjeonj # Character ì©
+U+ca52 jjeonh # Character ì©
+U+ca53 jjeod # Character ì©
+U+ca54 jjeol # Character ì©
+U+ca55 jjeolg # Character ì©
+U+ca56 jjeolm # Character ì©
+U+ca57 jjeolb # Character ì©
+U+ca58 jjeols # Character ì©
+U+ca59 jjeolt # Character ì©
+U+ca5a jjeolp # Character ì©
+U+ca5b jjeolh # Character ì©
+U+ca5c jjeom # Character ì©
+U+ca5d jjeob # Character ì©
+U+ca5e jjeobs # Character ì©
+U+ca5f jjeos # Character ì©
+U+ca60 jjeoss # Character ì©
+U+ca61 jjeong # Character ì©¡
+U+ca62 jjeoj # Character ì©¢
+U+ca63 jjeoc # Character ì©£
+U+ca64 jjeok # Character 쩤
+U+ca65 jjeot # Character ì©¥
+U+ca66 jjeop # Character 쩦
+U+ca67 jjeoh # Character 쩧
+U+ca68 jje # Character 쩨
+U+ca69 jjeg # Character ì©©
+U+ca6a jjegg # Character 쩪
+U+ca6b jjegs # Character ì©«
+U+ca6c jjen # Character 쩬
+U+ca6d jjenj # Character ì©
+U+ca6e jjenh # Character ì©®
+U+ca6f jjed # Character 쩯
+U+ca70 jjel # Character ì©°
+U+ca71 jjelg # Character 쩱
+U+ca72 jjelm # Character 쩲
+U+ca73 jjelb # Character 쩳
+U+ca74 jjels # Character ì©´
+U+ca75 jjelt # Character 쩵
+U+ca76 jjelp # Character 쩶
+U+ca77 jjelh # Character ì©·
+U+ca78 jjem # Character 쩸
+U+ca79 jjeb # Character 쩹
+U+ca7a jjebs # Character 쩺
+U+ca7b jjes # Character ì©»
+U+ca7c jjess # Character 쩼
+U+ca7d jjeng # Character 쩽
+U+ca7e jjej # Character 쩾
+U+ca7f jjec # Character ì©¿
+U+ca80 jjek # Character ìª
+U+ca81 jjet # Character ìª
+U+ca82 jjep # Character ìª
+U+ca83 jjeh # Character ìª
+U+ca84 jjyeo # Character ìª
+U+ca85 jjyeog # Character ìª
+U+ca86 jjyeogg # Character ìª
+U+ca87 jjyeogs # Character ìª
+U+ca88 jjyeon # Character ìª
+U+ca89 jjyeonj # Character ìª
+U+ca8a jjyeonh # Character ìª
+U+ca8b jjyeod # Character ìª
+U+ca8c jjyeol # Character ìª
+U+ca8d jjyeolg # Character ìª
+U+ca8e jjyeolm # Character ìª
+U+ca8f jjyeolb # Character ìª
+U+ca90 jjyeols # Character ìª
+U+ca91 jjyeolt # Character ìª
+U+ca92 jjyeolp # Character ìª
+U+ca93 jjyeolh # Character ìª
+U+ca94 jjyeom # Character ìª
+U+ca95 jjyeob # Character ìª
+U+ca96 jjyeobs # Character ìª
+U+ca97 jjyeos # Character ìª
+U+ca98 jjyeoss # Character ìª
+U+ca99 jjyeong # Character ìª
+U+ca9a jjyeoj # Character ìª
+U+ca9b jjyeoc # Character ìª
+U+ca9c jjyeok # Character ìª
+U+ca9d jjyeot # Character ìª
+U+ca9e jjyeop # Character ìª
+U+ca9f jjyeoh # Character ìª
+U+caa0 jjye # Character ìª
+U+caa1 jjyeg # Character 쪡
+U+caa2 jjyegg # Character 쪢
+U+caa3 jjyegs # Character 쪣
+U+caa4 jjyen # Character 쪤
+U+caa5 jjyenj # Character 쪥
+U+caa6 jjyenh # Character 쪦
+U+caa7 jjyed # Character 쪧
+U+caa8 jjyel # Character 쪨
+U+caa9 jjyelg # Character 쪩
+U+caaa jjyelm # Character 쪪
+U+caab jjyelb # Character 쪫
+U+caac jjyels # Character 쪬
+U+caad jjyelt # Character ìª
+U+caae jjyelp # Character 쪮
+U+caaf jjyelh # Character 쪯
+U+cab0 jjyem # Character 쪰
+U+cab1 jjyeb # Character 쪱
+U+cab2 jjyebs # Character 쪲
+U+cab3 jjyes # Character 쪳
+U+cab4 jjyess # Character 쪴
+U+cab5 jjyeng # Character 쪵
+U+cab6 jjyej # Character 쪶
+U+cab7 jjyec # Character 쪷
+U+cab8 jjyek # Character 쪸
+U+cab9 jjyet # Character 쪹
+U+caba jjyep # Character 쪺
+U+cabb jjyeh # Character 쪻
+U+cabc jjo # Character 쪼
+U+cabd jjog # Character 쪽
+U+cabe jjogg # Character 쪾
+U+cabf jjogs # Character 쪿
+U+cac0 jjon # Character ì«
+U+cac1 jjonj # Character ì«
+U+cac2 jjonh # Character ì«
+U+cac3 jjod # Character ì«
+U+cac4 jjol # Character ì«
+U+cac5 jjolg # Character ì«
+U+cac6 jjolm # Character ì«
+U+cac7 jjolb # Character ì«
+U+cac8 jjols # Character ì«
+U+cac9 jjolt # Character ì«
+U+caca jjolp # Character ì«
+U+cacb jjolh # Character ì«
+U+cacc jjom # Character ì«
+U+cacd jjob # Character ì«
+U+cace jjobs # Character ì«
+U+cacf jjos # Character ì«
+U+cad0 jjoss # Character ì«
+U+cad1 jjong # Character ì«
+U+cad2 jjoj # Character ì«
+U+cad3 jjoc # Character ì«
+U+cad4 jjok # Character ì«
+U+cad5 jjot # Character ì«
+U+cad6 jjop # Character ì«
+U+cad7 jjoh # Character ì«
+U+cad8 jjwa # Character ì«
+U+cad9 jjwag # Character ì«
+U+cada jjwagg # Character ì«
+U+cadb jjwags # Character ì«
+U+cadc jjwan # Character ì«
+U+cadd jjwanj # Character ì«
+U+cade jjwanh # Character ì«
+U+cadf jjwad # Character ì«
+U+cae0 jjwal # Character ì«
+U+cae1 jjwalg # Character ì«¡
+U+cae2 jjwalm # Character ì«¢
+U+cae3 jjwalb # Character ì«£
+U+cae4 jjwals # Character 쫤
+U+cae5 jjwalt # Character ì«¥
+U+cae6 jjwalp # Character 쫦
+U+cae7 jjwalh # Character 쫧
+U+cae8 jjwam # Character 쫨
+U+cae9 jjwab # Character ì«©
+U+caea jjwabs # Character 쫪
+U+caeb jjwas # Character ì««
+U+caec jjwass # Character 쫬
+U+caed jjwang # Character ì«
+U+caee jjwaj # Character ì«®
+U+caef jjwac # Character 쫯
+U+caf0 jjwak # Character ì«°
+U+caf1 jjwat # Character 쫱
+U+caf2 jjwap # Character 쫲
+U+caf3 jjwah # Character 쫳
+U+caf4 jjwae # Character ì«´
+U+caf5 jjwaeg # Character 쫵
+U+caf6 jjwaegg # Character 쫶
+U+caf7 jjwaegs # Character ì«·
+U+caf8 jjwaen # Character 쫸
+U+caf9 jjwaenj # Character 쫹
+U+cafa jjwaenh # Character 쫺
+U+cafb jjwaed # Character ì«»
+U+cafc jjwael # Character 쫼
+U+cafd jjwaelg # Character 쫽
+U+cafe jjwaelm # Character 쫾
+U+caff jjwaelb # Character ì«¿
diff --git a/resources/chars/ascii/rowcb.trans b/resources/chars/ascii/rowcb.trans
new file mode 100644
index 0000000..f8e1523
--- /dev/null
+++ b/resources/chars/ascii/rowcb.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+cb00 jjwaels # Character ì¬
+U+cb01 jjwaelt # Character ì¬
+U+cb02 jjwaelp # Character ì¬
+U+cb03 jjwaelh # Character ì¬
+U+cb04 jjwaem # Character ì¬
+U+cb05 jjwaeb # Character ì¬
+U+cb06 jjwaebs # Character ì¬
+U+cb07 jjwaes # Character ì¬
+U+cb08 jjwaess # Character ì¬
+U+cb09 jjwaeng # Character ì¬
+U+cb0a jjwaej # Character ì¬
+U+cb0b jjwaec # Character ì¬
+U+cb0c jjwaek # Character ì¬
+U+cb0d jjwaet # Character ì¬
+U+cb0e jjwaep # Character ì¬
+U+cb0f jjwaeh # Character ì¬
+U+cb10 jjoe # Character ì¬
+U+cb11 jjoeg # Character ì¬
+U+cb12 jjoegg # Character ì¬
+U+cb13 jjoegs # Character ì¬
+U+cb14 jjoen # Character ì¬
+U+cb15 jjoenj # Character ì¬
+U+cb16 jjoenh # Character ì¬
+U+cb17 jjoed # Character ì¬
+U+cb18 jjoel # Character ì¬
+U+cb19 jjoelg # Character ì¬
+U+cb1a jjoelm # Character ì¬
+U+cb1b jjoelb # Character ì¬
+U+cb1c jjoels # Character ì¬
+U+cb1d jjoelt # Character ì¬
+U+cb1e jjoelp # Character ì¬
+U+cb1f jjoelh # Character ì¬
+U+cb20 jjoem # Character ì¬
+U+cb21 jjoeb # Character 쬡
+U+cb22 jjoebs # Character 쬢
+U+cb23 jjoes # Character 쬣
+U+cb24 jjoess # Character 쬤
+U+cb25 jjoeng # Character 쬥
+U+cb26 jjoej # Character 쬦
+U+cb27 jjoec # Character 쬧
+U+cb28 jjoek # Character 쬨
+U+cb29 jjoet # Character 쬩
+U+cb2a jjoep # Character 쬪
+U+cb2b jjoeh # Character 쬫
+U+cb2c jjyo # Character 쬬
+U+cb2d jjyog # Character ì¬
+U+cb2e jjyogg # Character 쬮
+U+cb2f jjyogs # Character 쬯
+U+cb30 jjyon # Character 쬰
+U+cb31 jjyonj # Character 쬱
+U+cb32 jjyonh # Character 쬲
+U+cb33 jjyod # Character 쬳
+U+cb34 jjyol # Character 쬴
+U+cb35 jjyolg # Character 쬵
+U+cb36 jjyolm # Character 쬶
+U+cb37 jjyolb # Character 쬷
+U+cb38 jjyols # Character 쬸
+U+cb39 jjyolt # Character 쬹
+U+cb3a jjyolp # Character 쬺
+U+cb3b jjyolh # Character 쬻
+U+cb3c jjyom # Character 쬼
+U+cb3d jjyob # Character 쬽
+U+cb3e jjyobs # Character 쬾
+U+cb3f jjyos # Character 쬿
+U+cb40 jjyoss # Character ì
+U+cb41 jjyong # Character ì
+U+cb42 jjyoj # Character ì
+U+cb43 jjyoc # Character ì
+U+cb44 jjyok # Character ì
+U+cb45 jjyot # Character ì
+U+cb46 jjyop # Character ì
+U+cb47 jjyoh # Character ì
+U+cb48 jju # Character ì
+U+cb49 jjug # Character ì
+U+cb4a jjugg # Character ì
+U+cb4b jjugs # Character ì
+U+cb4c jjun # Character ì
+U+cb4d jjunj # Character ì
+U+cb4e jjunh # Character ì
+U+cb4f jjud # Character ì
+U+cb50 jjul # Character ì
+U+cb51 jjulg # Character ì
+U+cb52 jjulm # Character ì
+U+cb53 jjulb # Character ì
+U+cb54 jjuls # Character ì
+U+cb55 jjult # Character ì
+U+cb56 jjulp # Character ì
+U+cb57 jjulh # Character ì
+U+cb58 jjum # Character ì
+U+cb59 jjub # Character ì
+U+cb5a jjubs # Character ì
+U+cb5b jjus # Character ì
+U+cb5c jjuss # Character ì
+U+cb5d jjung # Character ì
+U+cb5e jjuj # Character ì
+U+cb5f jjuc # Character ì
+U+cb60 jjuk # Character ì
+U+cb61 jjut # Character ì¡
+U+cb62 jjup # Character ì¢
+U+cb63 jjuh # Character ì£
+U+cb64 jjweo # Character ì¤
+U+cb65 jjweog # Character ì¥
+U+cb66 jjweogg # Character ì¦
+U+cb67 jjweogs # Character ì§
+U+cb68 jjweon # Character ì¨
+U+cb69 jjweonj # Character ì©
+U+cb6a jjweonh # Character ìª
+U+cb6b jjweod # Character ì«
+U+cb6c jjweol # Character ì¬
+U+cb6d jjweolg # Character ì
+U+cb6e jjweolm # Character ì®
+U+cb6f jjweolb # Character ì¯
+U+cb70 jjweols # Character ì°
+U+cb71 jjweolt # Character ì±
+U+cb72 jjweolp # Character ì²
+U+cb73 jjweolh # Character ì³
+U+cb74 jjweom # Character ì´
+U+cb75 jjweob # Character ìµ
+U+cb76 jjweobs # Character ì¶
+U+cb77 jjweos # Character ì·
+U+cb78 jjweoss # Character ì¸
+U+cb79 jjweong # Character ì¹
+U+cb7a jjweoj # Character ìº
+U+cb7b jjweoc # Character ì»
+U+cb7c jjweok # Character ì¼
+U+cb7d jjweot # Character ì½
+U+cb7e jjweop # Character ì¾
+U+cb7f jjweoh # Character ì¿
+U+cb80 jjwe # Character ì®
+U+cb81 jjweg # Character ì®
+U+cb82 jjwegg # Character ì®
+U+cb83 jjwegs # Character ì®
+U+cb84 jjwen # Character ì®
+U+cb85 jjwenj # Character ì®
+U+cb86 jjwenh # Character ì®
+U+cb87 jjwed # Character ì®
+U+cb88 jjwel # Character ì®
+U+cb89 jjwelg # Character ì®
+U+cb8a jjwelm # Character ì®
+U+cb8b jjwelb # Character ì®
+U+cb8c jjwels # Character ì®
+U+cb8d jjwelt # Character ì®
+U+cb8e jjwelp # Character ì®
+U+cb8f jjwelh # Character ì®
+U+cb90 jjwem # Character ì®
+U+cb91 jjweb # Character ì®
+U+cb92 jjwebs # Character ì®
+U+cb93 jjwes # Character ì®
+U+cb94 jjwess # Character ì®
+U+cb95 jjweng # Character ì®
+U+cb96 jjwej # Character ì®
+U+cb97 jjwec # Character ì®
+U+cb98 jjwek # Character ì®
+U+cb99 jjwet # Character ì®
+U+cb9a jjwep # Character ì®
+U+cb9b jjweh # Character ì®
+U+cb9c jjwi # Character ì®
+U+cb9d jjwig # Character ì®
+U+cb9e jjwigg # Character ì®
+U+cb9f jjwigs # Character ì®
+U+cba0 jjwin # Character ì®
+U+cba1 jjwinj # Character 쮡
+U+cba2 jjwinh # Character 쮢
+U+cba3 jjwid # Character 쮣
+U+cba4 jjwil # Character 쮤
+U+cba5 jjwilg # Character 쮥
+U+cba6 jjwilm # Character 쮦
+U+cba7 jjwilb # Character 쮧
+U+cba8 jjwils # Character 쮨
+U+cba9 jjwilt # Character 쮩
+U+cbaa jjwilp # Character 쮪
+U+cbab jjwilh # Character 쮫
+U+cbac jjwim # Character 쮬
+U+cbad jjwib # Character ì®
+U+cbae jjwibs # Character ì®®
+U+cbaf jjwis # Character 쮯
+U+cbb0 jjwiss # Character ì®°
+U+cbb1 jjwing # Character ì®±
+U+cbb2 jjwij # Character 쮲
+U+cbb3 jjwic # Character 쮳
+U+cbb4 jjwik # Character ì®´
+U+cbb5 jjwit # Character 쮵
+U+cbb6 jjwip # Character 쮶
+U+cbb7 jjwih # Character ì®·
+U+cbb8 jjyu # Character 쮸
+U+cbb9 jjyug # Character 쮹
+U+cbba jjyugg # Character 쮺
+U+cbbb jjyugs # Character ì®»
+U+cbbc jjyun # Character 쮼
+U+cbbd jjyunj # Character 쮽
+U+cbbe jjyunh # Character 쮾
+U+cbbf jjyud # Character 쮿
+U+cbc0 jjyul # Character ì¯
+U+cbc1 jjyulg # Character ì¯
+U+cbc2 jjyulm # Character ì¯
+U+cbc3 jjyulb # Character ì¯
+U+cbc4 jjyuls # Character ì¯
+U+cbc5 jjyult # Character ì¯
+U+cbc6 jjyulp # Character ì¯
+U+cbc7 jjyulh # Character ì¯
+U+cbc8 jjyum # Character ì¯
+U+cbc9 jjyub # Character ì¯
+U+cbca jjyubs # Character ì¯
+U+cbcb jjyus # Character ì¯
+U+cbcc jjyuss # Character ì¯
+U+cbcd jjyung # Character ì¯
+U+cbce jjyuj # Character ì¯
+U+cbcf jjyuc # Character ì¯
+U+cbd0 jjyuk # Character ì¯
+U+cbd1 jjyut # Character ì¯
+U+cbd2 jjyup # Character ì¯
+U+cbd3 jjyuh # Character ì¯
+U+cbd4 jjeu # Character ì¯
+U+cbd5 jjeug # Character ì¯
+U+cbd6 jjeugg # Character ì¯
+U+cbd7 jjeugs # Character ì¯
+U+cbd8 jjeun # Character ì¯
+U+cbd9 jjeunj # Character ì¯
+U+cbda jjeunh # Character ì¯
+U+cbdb jjeud # Character ì¯
+U+cbdc jjeul # Character ì¯
+U+cbdd jjeulg # Character ì¯
+U+cbde jjeulm # Character ì¯
+U+cbdf jjeulb # Character ì¯
+U+cbe0 jjeuls # Character ì¯
+U+cbe1 jjeult # Character 쯡
+U+cbe2 jjeulp # Character 쯢
+U+cbe3 jjeulh # Character 쯣
+U+cbe4 jjeum # Character 쯤
+U+cbe5 jjeub # Character 쯥
+U+cbe6 jjeubs # Character 쯦
+U+cbe7 jjeus # Character 쯧
+U+cbe8 jjeuss # Character 쯨
+U+cbe9 jjeung # Character 쯩
+U+cbea jjeuj # Character 쯪
+U+cbeb jjeuc # Character 쯫
+U+cbec jjeuk # Character 쯬
+U+cbed jjeut # Character ì¯
+U+cbee jjeup # Character 쯮
+U+cbef jjeuh # Character 쯯
+U+cbf0 jjyi # Character 쯰
+U+cbf1 jjyig # Character 쯱
+U+cbf2 jjyigg # Character 쯲
+U+cbf3 jjyigs # Character 쯳
+U+cbf4 jjyin # Character 쯴
+U+cbf5 jjyinj # Character 쯵
+U+cbf6 jjyinh # Character 쯶
+U+cbf7 jjyid # Character 쯷
+U+cbf8 jjyil # Character 쯸
+U+cbf9 jjyilg # Character 쯹
+U+cbfa jjyilm # Character 쯺
+U+cbfb jjyilb # Character 쯻
+U+cbfc jjyils # Character 쯼
+U+cbfd jjyilt # Character 쯽
+U+cbfe jjyilp # Character 쯾
+U+cbff jjyilh # Character 쯿
diff --git a/resources/chars/ascii/rowcc.trans b/resources/chars/ascii/rowcc.trans
new file mode 100644
index 0000000..748e84e
--- /dev/null
+++ b/resources/chars/ascii/rowcc.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+cc00 jjyim # Character ì°
+U+cc01 jjyib # Character ì°
+U+cc02 jjyibs # Character ì°
+U+cc03 jjyis # Character ì°
+U+cc04 jjyiss # Character ì°
+U+cc05 jjying # Character ì°
+U+cc06 jjyij # Character ì°
+U+cc07 jjyic # Character ì°
+U+cc08 jjyik # Character ì°
+U+cc09 jjyit # Character ì°
+U+cc0a jjyip # Character ì°
+U+cc0b jjyih # Character ì°
+U+cc0c jji # Character ì°
+U+cc0d jjig # Character ì°
+U+cc0e jjigg # Character ì°
+U+cc0f jjigs # Character ì°
+U+cc10 jjin # Character ì°
+U+cc11 jjinj # Character ì°
+U+cc12 jjinh # Character ì°
+U+cc13 jjid # Character ì°
+U+cc14 jjil # Character ì°
+U+cc15 jjilg # Character ì°
+U+cc16 jjilm # Character ì°
+U+cc17 jjilb # Character ì°
+U+cc18 jjils # Character ì°
+U+cc19 jjilt # Character ì°
+U+cc1a jjilp # Character ì°
+U+cc1b jjilh # Character ì°
+U+cc1c jjim # Character ì°
+U+cc1d jjib # Character ì°
+U+cc1e jjibs # Character ì°
+U+cc1f jjis # Character ì°
+U+cc20 jjiss # Character ì°
+U+cc21 jjing # Character ì°¡
+U+cc22 jjij # Character ì°¢
+U+cc23 jjic # Character ì°£
+U+cc24 jjik # Character ì°¤
+U+cc25 jjit # Character ì°¥
+U+cc26 jjip # Character ì°¦
+U+cc27 jjih # Character ì°§
+U+cc28 ca # Character ì°¨
+U+cc29 cag # Character ì°©
+U+cc2a cagg # Character ì°ª
+U+cc2b cags # Character ì°«
+U+cc2c can # Character ì°¬
+U+cc2d canj # Character ì°
+U+cc2e canh # Character ì°®
+U+cc2f cad # Character ì°¯
+U+cc30 cal # Character ì°°
+U+cc31 calg # Character ì°±
+U+cc32 calm # Character ì°²
+U+cc33 calb # Character ì°³
+U+cc34 cals # Character ì°´
+U+cc35 calt # Character ì°µ
+U+cc36 calp # Character ì°¶
+U+cc37 calh # Character ì°·
+U+cc38 cam # Character ì°¸
+U+cc39 cab # Character ì°¹
+U+cc3a cabs # Character ì°º
+U+cc3b cas # Character ì°»
+U+cc3c cass # Character ì°¼
+U+cc3d cang # Character ì°½
+U+cc3e caj # Character ì°¾
+U+cc3f cac # Character ì°¿
+U+cc40 cak # Character ì±
+U+cc41 cat # Character ì±
+U+cc42 cap # Character ì±
+U+cc43 cah # Character ì±
+U+cc44 cae # Character ì±
+U+cc45 caeg # Character ì±
+U+cc46 caegg # Character ì±
+U+cc47 caegs # Character ì±
+U+cc48 caen # Character ì±
+U+cc49 caenj # Character ì±
+U+cc4a caenh # Character ì±
+U+cc4b caed # Character ì±
+U+cc4c cael # Character ì±
+U+cc4d caelg # Character ì±
+U+cc4e caelm # Character ì±
+U+cc4f caelb # Character ì±
+U+cc50 caels # Character ì±
+U+cc51 caelt # Character ì±
+U+cc52 caelp # Character ì±
+U+cc53 caelh # Character ì±
+U+cc54 caem # Character ì±
+U+cc55 caeb # Character ì±
+U+cc56 caebs # Character ì±
+U+cc57 caes # Character ì±
+U+cc58 caess # Character ì±
+U+cc59 caeng # Character ì±
+U+cc5a caej # Character ì±
+U+cc5b caec # Character ì±
+U+cc5c caek # Character ì±
+U+cc5d caet # Character ì±
+U+cc5e caep # Character ì±
+U+cc5f caeh # Character ì±
+U+cc60 cya # Character ì±
+U+cc61 cyag # Character 챡
+U+cc62 cyagg # Character ì±¢
+U+cc63 cyags # Character ì±£
+U+cc64 cyan # Character 챤
+U+cc65 cyanj # Character ì±¥
+U+cc66 cyanh # Character 챦
+U+cc67 cyad # Character 챧
+U+cc68 cyal # Character 챨
+U+cc69 cyalg # Character 챩
+U+cc6a cyalm # Character 챪
+U+cc6b cyalb # Character 챫
+U+cc6c cyals # Character 챬
+U+cc6d cyalt # Character ì±
+U+cc6e cyalp # Character ì±®
+U+cc6f cyalh # Character 챯
+U+cc70 cyam # Character ì±°
+U+cc71 cyab # Character ì±±
+U+cc72 cyabs # Character ì±²
+U+cc73 cyas # Character ì±³
+U+cc74 cyass # Character ì±´
+U+cc75 cyang # Character ì±µ
+U+cc76 cyaj # Character 챶
+U+cc77 cyac # Character ì±·
+U+cc78 cyak # Character 챸
+U+cc79 cyat # Character ì±¹
+U+cc7a cyap # Character 챺
+U+cc7b cyah # Character ì±»
+U+cc7c cyae # Character ì±¼
+U+cc7d cyaeg # Character ì±½
+U+cc7e cyaegg # Character ì±¾
+U+cc7f cyaegs # Character 챿
+U+cc80 cyaen # Character ì²
+U+cc81 cyaenj # Character ì²
+U+cc82 cyaenh # Character ì²
+U+cc83 cyaed # Character ì²
+U+cc84 cyael # Character ì²
+U+cc85 cyaelg # Character ì²
+U+cc86 cyaelm # Character ì²
+U+cc87 cyaelb # Character ì²
+U+cc88 cyaels # Character ì²
+U+cc89 cyaelt # Character ì²
+U+cc8a cyaelp # Character ì²
+U+cc8b cyaelh # Character ì²
+U+cc8c cyaem # Character ì²
+U+cc8d cyaeb # Character ì²
+U+cc8e cyaebs # Character ì²
+U+cc8f cyaes # Character ì²
+U+cc90 cyaess # Character ì²
+U+cc91 cyaeng # Character ì²
+U+cc92 cyaej # Character ì²
+U+cc93 cyaec # Character ì²
+U+cc94 cyaek # Character ì²
+U+cc95 cyaet # Character ì²
+U+cc96 cyaep # Character ì²
+U+cc97 cyaeh # Character ì²
+U+cc98 ceo # Character ì²
+U+cc99 ceog # Character ì²
+U+cc9a ceogg # Character ì²
+U+cc9b ceogs # Character ì²
+U+cc9c ceon # Character ì²
+U+cc9d ceonj # Character ì²
+U+cc9e ceonh # Character ì²
+U+cc9f ceod # Character ì²
+U+cca0 ceol # Character ì²
+U+cca1 ceolg # Character 첡
+U+cca2 ceolm # Character ì²¢
+U+cca3 ceolb # Character ì²£
+U+cca4 ceols # Character 첤
+U+cca5 ceolt # Character ì²¥
+U+cca6 ceolp # Character 첦
+U+cca7 ceolh # Character 첧
+U+cca8 ceom # Character 첨
+U+cca9 ceob # Character 첩
+U+ccaa ceobs # Character 첪
+U+ccab ceos # Character 첫
+U+ccac ceoss # Character 첬
+U+ccad ceong # Character ì²
+U+ccae ceoj # Character ì²®
+U+ccaf ceoc # Character 첯
+U+ccb0 ceok # Character ì²°
+U+ccb1 ceot # Character ì²±
+U+ccb2 ceop # Character ì²²
+U+ccb3 ceoh # Character ì²³
+U+ccb4 ce # Character ì²´
+U+ccb5 ceg # Character ì²µ
+U+ccb6 cegg # Character 첶
+U+ccb7 cegs # Character ì²·
+U+ccb8 cen # Character 첸
+U+ccb9 cenj # Character ì²¹
+U+ccba cenh # Character 첺
+U+ccbb ced # Character ì²»
+U+ccbc cel # Character ì²¼
+U+ccbd celg # Character ì²½
+U+ccbe celm # Character ì²¾
+U+ccbf celb # Character 첿
+U+ccc0 cels # Character ì³
+U+ccc1 celt # Character ì³
+U+ccc2 celp # Character ì³
+U+ccc3 celh # Character ì³
+U+ccc4 cem # Character ì³
+U+ccc5 ceb # Character ì³
+U+ccc6 cebs # Character ì³
+U+ccc7 ces # Character ì³
+U+ccc8 cess # Character ì³
+U+ccc9 ceng # Character ì³
+U+ccca cej # Character ì³
+U+cccb cec # Character ì³
+U+cccc cek # Character ì³
+U+cccd cet # Character ì³
+U+ccce cep # Character ì³
+U+cccf ceh # Character ì³
+U+ccd0 cyeo # Character ì³
+U+ccd1 cyeog # Character ì³
+U+ccd2 cyeogg # Character ì³
+U+ccd3 cyeogs # Character ì³
+U+ccd4 cyeon # Character ì³
+U+ccd5 cyeonj # Character ì³
+U+ccd6 cyeonh # Character ì³
+U+ccd7 cyeod # Character ì³
+U+ccd8 cyeol # Character ì³
+U+ccd9 cyeolg # Character ì³
+U+ccda cyeolm # Character ì³
+U+ccdb cyeolb # Character ì³
+U+ccdc cyeols # Character ì³
+U+ccdd cyeolt # Character ì³
+U+ccde cyeolp # Character ì³
+U+ccdf cyeolh # Character ì³
+U+cce0 cyeom # Character ì³
+U+cce1 cyeob # Character 쳡
+U+cce2 cyeobs # Character ì³¢
+U+cce3 cyeos # Character ì³£
+U+cce4 cyeoss # Character 쳤
+U+cce5 cyeong # Character ì³¥
+U+cce6 cyeoj # Character 쳦
+U+cce7 cyeoc # Character 쳧
+U+cce8 cyeok # Character 쳨
+U+cce9 cyeot # Character 쳩
+U+ccea cyeop # Character 쳪
+U+cceb cyeoh # Character 쳫
+U+ccec cye # Character 쳬
+U+cced cyeg # Character ì³
+U+ccee cyegg # Character ì³®
+U+ccef cyegs # Character 쳯
+U+ccf0 cyen # Character ì³°
+U+ccf1 cyenj # Character ì³±
+U+ccf2 cyenh # Character ì³²
+U+ccf3 cyed # Character ì³³
+U+ccf4 cyel # Character ì³´
+U+ccf5 cyelg # Character ì³µ
+U+ccf6 cyelm # Character 쳶
+U+ccf7 cyelb # Character ì³·
+U+ccf8 cyels # Character 쳸
+U+ccf9 cyelt # Character ì³¹
+U+ccfa cyelp # Character 쳺
+U+ccfb cyelh # Character ì³»
+U+ccfc cyem # Character ì³¼
+U+ccfd cyeb # Character ì³½
+U+ccfe cyebs # Character ì³¾
+U+ccff cyes # Character 쳿
diff --git a/resources/chars/ascii/rowcd.trans b/resources/chars/ascii/rowcd.trans
new file mode 100644
index 0000000..59eec1d
--- /dev/null
+++ b/resources/chars/ascii/rowcd.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+cd00 cyess # Character ì´
+U+cd01 cyeng # Character ì´
+U+cd02 cyej # Character ì´
+U+cd03 cyec # Character ì´
+U+cd04 cyek # Character ì´
+U+cd05 cyet # Character ì´
+U+cd06 cyep # Character ì´
+U+cd07 cyeh # Character ì´
+U+cd08 co # Character ì´
+U+cd09 cog # Character ì´
+U+cd0a cogg # Character ì´
+U+cd0b cogs # Character ì´
+U+cd0c con # Character ì´
+U+cd0d conj # Character ì´
+U+cd0e conh # Character ì´
+U+cd0f cod # Character ì´
+U+cd10 col # Character ì´
+U+cd11 colg # Character ì´
+U+cd12 colm # Character ì´
+U+cd13 colb # Character ì´
+U+cd14 cols # Character ì´
+U+cd15 colt # Character ì´
+U+cd16 colp # Character ì´
+U+cd17 colh # Character ì´
+U+cd18 com # Character ì´
+U+cd19 cob # Character ì´
+U+cd1a cobs # Character ì´
+U+cd1b cos # Character ì´
+U+cd1c coss # Character ì´
+U+cd1d cong # Character ì´
+U+cd1e coj # Character ì´
+U+cd1f coc # Character ì´
+U+cd20 cok # Character ì´
+U+cd21 cot # Character ì´¡
+U+cd22 cop # Character ì´¢
+U+cd23 coh # Character ì´£
+U+cd24 cwa # Character ì´¤
+U+cd25 cwag # Character ì´¥
+U+cd26 cwagg # Character ì´¦
+U+cd27 cwags # Character ì´§
+U+cd28 cwan # Character ì´¨
+U+cd29 cwanj # Character ì´©
+U+cd2a cwanh # Character ì´ª
+U+cd2b cwad # Character ì´«
+U+cd2c cwal # Character ì´¬
+U+cd2d cwalg # Character ì´
+U+cd2e cwalm # Character ì´®
+U+cd2f cwalb # Character ì´¯
+U+cd30 cwals # Character ì´°
+U+cd31 cwalt # Character ì´±
+U+cd32 cwalp # Character ì´²
+U+cd33 cwalh # Character ì´³
+U+cd34 cwam # Character ì´´
+U+cd35 cwab # Character ì´µ
+U+cd36 cwabs # Character ì´¶
+U+cd37 cwas # Character ì´·
+U+cd38 cwass # Character ì´¸
+U+cd39 cwang # Character ì´¹
+U+cd3a cwaj # Character ì´º
+U+cd3b cwac # Character ì´»
+U+cd3c cwak # Character ì´¼
+U+cd3d cwat # Character ì´½
+U+cd3e cwap # Character ì´¾
+U+cd3f cwah # Character ì´¿
+U+cd40 cwae # Character ìµ
+U+cd41 cwaeg # Character ìµ
+U+cd42 cwaegg # Character ìµ
+U+cd43 cwaegs # Character ìµ
+U+cd44 cwaen # Character ìµ
+U+cd45 cwaenj # Character ìµ
+U+cd46 cwaenh # Character ìµ
+U+cd47 cwaed # Character ìµ
+U+cd48 cwael # Character ìµ
+U+cd49 cwaelg # Character ìµ
+U+cd4a cwaelm # Character ìµ
+U+cd4b cwaelb # Character ìµ
+U+cd4c cwaels # Character ìµ
+U+cd4d cwaelt # Character ìµ
+U+cd4e cwaelp # Character ìµ
+U+cd4f cwaelh # Character ìµ
+U+cd50 cwaem # Character ìµ
+U+cd51 cwaeb # Character ìµ
+U+cd52 cwaebs # Character ìµ
+U+cd53 cwaes # Character ìµ
+U+cd54 cwaess # Character ìµ
+U+cd55 cwaeng # Character ìµ
+U+cd56 cwaej # Character ìµ
+U+cd57 cwaec # Character ìµ
+U+cd58 cwaek # Character ìµ
+U+cd59 cwaet # Character ìµ
+U+cd5a cwaep # Character ìµ
+U+cd5b cwaeh # Character ìµ
+U+cd5c coe # Character ìµ
+U+cd5d coeg # Character ìµ
+U+cd5e coegg # Character ìµ
+U+cd5f coegs # Character ìµ
+U+cd60 coen # Character ìµ
+U+cd61 coenj # Character 쵡
+U+cd62 coenh # Character ìµ¢
+U+cd63 coed # Character ìµ£
+U+cd64 coel # Character 쵤
+U+cd65 coelg # Character ìµ¥
+U+cd66 coelm # Character 쵦
+U+cd67 coelb # Character 쵧
+U+cd68 coels # Character 쵨
+U+cd69 coelt # Character 쵩
+U+cd6a coelp # Character 쵪
+U+cd6b coelh # Character 쵫
+U+cd6c coem # Character 쵬
+U+cd6d coeb # Character ìµ
+U+cd6e coebs # Character ìµ®
+U+cd6f coes # Character 쵯
+U+cd70 coess # Character ìµ°
+U+cd71 coeng # Character ìµ±
+U+cd72 coej # Character ìµ²
+U+cd73 coec # Character ìµ³
+U+cd74 coek # Character ìµ´
+U+cd75 coet # Character ìµµ
+U+cd76 coep # Character 쵶
+U+cd77 coeh # Character ìµ·
+U+cd78 cyo # Character 쵸
+U+cd79 cyog # Character ìµ¹
+U+cd7a cyogg # Character 쵺
+U+cd7b cyogs # Character ìµ»
+U+cd7c cyon # Character ìµ¼
+U+cd7d cyonj # Character ìµ½
+U+cd7e cyonh # Character ìµ¾
+U+cd7f cyod # Character 쵿
+U+cd80 cyol # Character ì¶
+U+cd81 cyolg # Character ì¶
+U+cd82 cyolm # Character ì¶
+U+cd83 cyolb # Character ì¶
+U+cd84 cyols # Character ì¶
+U+cd85 cyolt # Character ì¶
+U+cd86 cyolp # Character ì¶
+U+cd87 cyolh # Character ì¶
+U+cd88 cyom # Character ì¶
+U+cd89 cyob # Character ì¶
+U+cd8a cyobs # Character ì¶
+U+cd8b cyos # Character ì¶
+U+cd8c cyoss # Character ì¶
+U+cd8d cyong # Character ì¶
+U+cd8e cyoj # Character ì¶
+U+cd8f cyoc # Character ì¶
+U+cd90 cyok # Character ì¶
+U+cd91 cyot # Character ì¶
+U+cd92 cyop # Character ì¶
+U+cd93 cyoh # Character ì¶
+U+cd94 cu # Character ì¶
+U+cd95 cug # Character ì¶
+U+cd96 cugg # Character ì¶
+U+cd97 cugs # Character ì¶
+U+cd98 cun # Character ì¶
+U+cd99 cunj # Character ì¶
+U+cd9a cunh # Character ì¶
+U+cd9b cud # Character ì¶
+U+cd9c cul # Character ì¶
+U+cd9d culg # Character ì¶
+U+cd9e culm # Character ì¶
+U+cd9f culb # Character ì¶
+U+cda0 culs # Character ì¶
+U+cda1 cult # Character 춡
+U+cda2 culp # Character 춢
+U+cda3 culh # Character 춣
+U+cda4 cum # Character 춤
+U+cda5 cub # Character 춥
+U+cda6 cubs # Character 춦
+U+cda7 cus # Character 춧
+U+cda8 cuss # Character 춨
+U+cda9 cung # Character 충
+U+cdaa cuj # Character 춪
+U+cdab cuc # Character 춫
+U+cdac cuk # Character 춬
+U+cdad cut # Character ì¶
+U+cdae cup # Character 춮
+U+cdaf cuh # Character 춯
+U+cdb0 cweo # Character 춰
+U+cdb1 cweog # Character 춱
+U+cdb2 cweogg # Character 춲
+U+cdb3 cweogs # Character 춳
+U+cdb4 cweon # Character 춴
+U+cdb5 cweonj # Character 춵
+U+cdb6 cweonh # Character 춶
+U+cdb7 cweod # Character 춷
+U+cdb8 cweol # Character 춸
+U+cdb9 cweolg # Character 춹
+U+cdba cweolm # Character 춺
+U+cdbb cweolb # Character 춻
+U+cdbc cweols # Character 춼
+U+cdbd cweolt # Character 춽
+U+cdbe cweolp # Character 춾
+U+cdbf cweolh # Character 춿
+U+cdc0 cweom # Character ì·
+U+cdc1 cweob # Character ì·
+U+cdc2 cweobs # Character ì·
+U+cdc3 cweos # Character ì·
+U+cdc4 cweoss # Character ì·
+U+cdc5 cweong # Character ì·
+U+cdc6 cweoj # Character ì·
+U+cdc7 cweoc # Character ì·
+U+cdc8 cweok # Character ì·
+U+cdc9 cweot # Character ì·
+U+cdca cweop # Character ì·
+U+cdcb cweoh # Character ì·
+U+cdcc cwe # Character ì·
+U+cdcd cweg # Character ì·
+U+cdce cwegg # Character ì·
+U+cdcf cwegs # Character ì·
+U+cdd0 cwen # Character ì·
+U+cdd1 cwenj # Character ì·
+U+cdd2 cwenh # Character ì·
+U+cdd3 cwed # Character ì·
+U+cdd4 cwel # Character ì·
+U+cdd5 cwelg # Character ì·
+U+cdd6 cwelm # Character ì·
+U+cdd7 cwelb # Character ì·
+U+cdd8 cwels # Character ì·
+U+cdd9 cwelt # Character ì·
+U+cdda cwelp # Character ì·
+U+cddb cwelh # Character ì·
+U+cddc cwem # Character ì·
+U+cddd cweb # Character ì·
+U+cdde cwebs # Character ì·
+U+cddf cwes # Character ì·
+U+cde0 cwess # Character ì·
+U+cde1 cweng # Character ì·¡
+U+cde2 cwej # Character ì·¢
+U+cde3 cwec # Character ì·£
+U+cde4 cwek # Character ì·¤
+U+cde5 cwet # Character ì·¥
+U+cde6 cwep # Character ì·¦
+U+cde7 cweh # Character ì·§
+U+cde8 cwi # Character ì·¨
+U+cde9 cwig # Character ì·©
+U+cdea cwigg # Character ì·ª
+U+cdeb cwigs # Character ì·«
+U+cdec cwin # Character ì·¬
+U+cded cwinj # Character ì·
+U+cdee cwinh # Character ì·®
+U+cdef cwid # Character ì·¯
+U+cdf0 cwil # Character ì·°
+U+cdf1 cwilg # Character ì·±
+U+cdf2 cwilm # Character ì·²
+U+cdf3 cwilb # Character ì·³
+U+cdf4 cwils # Character ì·´
+U+cdf5 cwilt # Character ì·µ
+U+cdf6 cwilp # Character ì·¶
+U+cdf7 cwilh # Character ì··
+U+cdf8 cwim # Character ì·¸
+U+cdf9 cwib # Character ì·¹
+U+cdfa cwibs # Character ì·º
+U+cdfb cwis # Character ì·»
+U+cdfc cwiss # Character ì·¼
+U+cdfd cwing # Character ì·½
+U+cdfe cwij # Character ì·¾
+U+cdff cwic # Character ì·¿
diff --git a/resources/chars/ascii/rowce.trans b/resources/chars/ascii/rowce.trans
new file mode 100644
index 0000000..cd31e9e
--- /dev/null
+++ b/resources/chars/ascii/rowce.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+ce00 cwik # Character ì¸
+U+ce01 cwit # Character ì¸
+U+ce02 cwip # Character ì¸
+U+ce03 cwih # Character ì¸
+U+ce04 cyu # Character ì¸
+U+ce05 cyug # Character ì¸
+U+ce06 cyugg # Character ì¸
+U+ce07 cyugs # Character ì¸
+U+ce08 cyun # Character ì¸
+U+ce09 cyunj # Character ì¸
+U+ce0a cyunh # Character ì¸
+U+ce0b cyud # Character ì¸
+U+ce0c cyul # Character ì¸
+U+ce0d cyulg # Character ì¸
+U+ce0e cyulm # Character ì¸
+U+ce0f cyulb # Character ì¸
+U+ce10 cyuls # Character ì¸
+U+ce11 cyult # Character ì¸
+U+ce12 cyulp # Character ì¸
+U+ce13 cyulh # Character ì¸
+U+ce14 cyum # Character ì¸
+U+ce15 cyub # Character ì¸
+U+ce16 cyubs # Character ì¸
+U+ce17 cyus # Character ì¸
+U+ce18 cyuss # Character ì¸
+U+ce19 cyung # Character ì¸
+U+ce1a cyuj # Character ì¸
+U+ce1b cyuc # Character ì¸
+U+ce1c cyuk # Character ì¸
+U+ce1d cyut # Character ì¸
+U+ce1e cyup # Character ì¸
+U+ce1f cyuh # Character ì¸
+U+ce20 ceu # Character ì¸
+U+ce21 ceug # Character 측
+U+ce22 ceugg # Character 츢
+U+ce23 ceugs # Character 츣
+U+ce24 ceun # Character 츤
+U+ce25 ceunj # Character 츥
+U+ce26 ceunh # Character 츦
+U+ce27 ceud # Character 츧
+U+ce28 ceul # Character 츨
+U+ce29 ceulg # Character 츩
+U+ce2a ceulm # Character 츪
+U+ce2b ceulb # Character 츫
+U+ce2c ceuls # Character 츬
+U+ce2d ceult # Character ì¸
+U+ce2e ceulp # Character 츮
+U+ce2f ceulh # Character 츯
+U+ce30 ceum # Character 츰
+U+ce31 ceub # Character 츱
+U+ce32 ceubs # Character 츲
+U+ce33 ceus # Character 츳
+U+ce34 ceuss # Character 츴
+U+ce35 ceung # Character 층
+U+ce36 ceuj # Character 츶
+U+ce37 ceuc # Character 츷
+U+ce38 ceuk # Character 츸
+U+ce39 ceut # Character 츹
+U+ce3a ceup # Character 츺
+U+ce3b ceuh # Character 츻
+U+ce3c cyi # Character 츼
+U+ce3d cyig # Character 츽
+U+ce3e cyigg # Character 츾
+U+ce3f cyigs # Character 츿
+U+ce40 cyin # Character ì¹
+U+ce41 cyinj # Character ì¹
+U+ce42 cyinh # Character ì¹
+U+ce43 cyid # Character ì¹
+U+ce44 cyil # Character ì¹
+U+ce45 cyilg # Character ì¹
+U+ce46 cyilm # Character ì¹
+U+ce47 cyilb # Character ì¹
+U+ce48 cyils # Character ì¹
+U+ce49 cyilt # Character ì¹
+U+ce4a cyilp # Character ì¹
+U+ce4b cyilh # Character ì¹
+U+ce4c cyim # Character ì¹
+U+ce4d cyib # Character ì¹
+U+ce4e cyibs # Character ì¹
+U+ce4f cyis # Character ì¹
+U+ce50 cyiss # Character ì¹
+U+ce51 cying # Character ì¹
+U+ce52 cyij # Character ì¹
+U+ce53 cyic # Character ì¹
+U+ce54 cyik # Character ì¹
+U+ce55 cyit # Character ì¹
+U+ce56 cyip # Character ì¹
+U+ce57 cyih # Character ì¹
+U+ce58 ci # Character ì¹
+U+ce59 cig # Character ì¹
+U+ce5a cigg # Character ì¹
+U+ce5b cigs # Character ì¹
+U+ce5c cin # Character ì¹
+U+ce5d cinj # Character ì¹
+U+ce5e cinh # Character ì¹
+U+ce5f cid # Character ì¹
+U+ce60 cil # Character ì¹
+U+ce61 cilg # Character 칡
+U+ce62 cilm # Character ì¹¢
+U+ce63 cilb # Character ì¹£
+U+ce64 cils # Character 칤
+U+ce65 cilt # Character ì¹¥
+U+ce66 cilp # Character 칦
+U+ce67 cilh # Character 칧
+U+ce68 cim # Character 침
+U+ce69 cib # Character 칩
+U+ce6a cibs # Character 칪
+U+ce6b cis # Character 칫
+U+ce6c ciss # Character 칬
+U+ce6d cing # Character ì¹
+U+ce6e cij # Character ì¹®
+U+ce6f cic # Character 칯
+U+ce70 cik # Character ì¹°
+U+ce71 cit # Character ì¹±
+U+ce72 cip # Character ì¹²
+U+ce73 cih # Character ì¹³
+U+ce74 ka # Character ì¹´
+U+ce75 kag # Character ì¹µ
+U+ce76 kagg # Character 칶
+U+ce77 kags # Character ì¹·
+U+ce78 kan # Character 칸
+U+ce79 kanj # Character ì¹¹
+U+ce7a kanh # Character 칺
+U+ce7b kad # Character ì¹»
+U+ce7c kal # Character ì¹¼
+U+ce7d kalg # Character ì¹½
+U+ce7e kalm # Character ì¹¾
+U+ce7f kalb # Character 칿
+U+ce80 kals # Character ìº
+U+ce81 kalt # Character ìº
+U+ce82 kalp # Character ìº
+U+ce83 kalh # Character ìº
+U+ce84 kam # Character ìº
+U+ce85 kab # Character ìº
+U+ce86 kabs # Character ìº
+U+ce87 kas # Character ìº
+U+ce88 kass # Character ìº
+U+ce89 kang # Character ìº
+U+ce8a kaj # Character ìº
+U+ce8b kac # Character ìº
+U+ce8c kak # Character ìº
+U+ce8d kat # Character ìº
+U+ce8e kap # Character ìº
+U+ce8f kah # Character ìº
+U+ce90 kae # Character ìº
+U+ce91 kaeg # Character ìº
+U+ce92 kaegg # Character ìº
+U+ce93 kaegs # Character ìº
+U+ce94 kaen # Character ìº
+U+ce95 kaenj # Character ìº
+U+ce96 kaenh # Character ìº
+U+ce97 kaed # Character ìº
+U+ce98 kael # Character ìº
+U+ce99 kaelg # Character ìº
+U+ce9a kaelm # Character ìº
+U+ce9b kaelb # Character ìº
+U+ce9c kaels # Character ìº
+U+ce9d kaelt # Character ìº
+U+ce9e kaelp # Character ìº
+U+ce9f kaelh # Character ìº
+U+cea0 kaem # Character ìº
+U+cea1 kaeb # Character 캡
+U+cea2 kaebs # Character 캢
+U+cea3 kaes # Character 캣
+U+cea4 kaess # Character 캤
+U+cea5 kaeng # Character 캥
+U+cea6 kaej # Character 캦
+U+cea7 kaec # Character 캧
+U+cea8 kaek # Character 캨
+U+cea9 kaet # Character 캩
+U+ceaa kaep # Character 캪
+U+ceab kaeh # Character 캫
+U+ceac kya # Character 캬
+U+cead kyag # Character ìº
+U+ceae kyagg # Character 캮
+U+ceaf kyags # Character 캯
+U+ceb0 kyan # Character 캰
+U+ceb1 kyanj # Character 캱
+U+ceb2 kyanh # Character 캲
+U+ceb3 kyad # Character 캳
+U+ceb4 kyal # Character 캴
+U+ceb5 kyalg # Character 캵
+U+ceb6 kyalm # Character 캶
+U+ceb7 kyalb # Character 캷
+U+ceb8 kyals # Character 캸
+U+ceb9 kyalt # Character 캹
+U+ceba kyalp # Character 캺
+U+cebb kyalh # Character 캻
+U+cebc kyam # Character 캼
+U+cebd kyab # Character 캽
+U+cebe kyabs # Character 캾
+U+cebf kyas # Character 캿
+U+cec0 kyass # Character ì»
+U+cec1 kyang # Character ì»
+U+cec2 kyaj # Character ì»
+U+cec3 kyac # Character ì»
+U+cec4 kyak # Character ì»
+U+cec5 kyat # Character ì»
+U+cec6 kyap # Character ì»
+U+cec7 kyah # Character ì»
+U+cec8 kyae # Character ì»
+U+cec9 kyaeg # Character ì»
+U+ceca kyaegg # Character ì»
+U+cecb kyaegs # Character ì»
+U+cecc kyaen # Character ì»
+U+cecd kyaenj # Character ì»
+U+cece kyaenh # Character ì»
+U+cecf kyaed # Character ì»
+U+ced0 kyael # Character ì»
+U+ced1 kyaelg # Character ì»
+U+ced2 kyaelm # Character ì»
+U+ced3 kyaelb # Character ì»
+U+ced4 kyaels # Character ì»
+U+ced5 kyaelt # Character ì»
+U+ced6 kyaelp # Character ì»
+U+ced7 kyaelh # Character ì»
+U+ced8 kyaem # Character ì»
+U+ced9 kyaeb # Character ì»
+U+ceda kyaebs # Character ì»
+U+cedb kyaes # Character ì»
+U+cedc kyaess # Character ì»
+U+cedd kyaeng # Character ì»
+U+cede kyaej # Character ì»
+U+cedf kyaec # Character ì»
+U+cee0 kyaek # Character ì»
+U+cee1 kyaet # Character 컡
+U+cee2 kyaep # Character 컢
+U+cee3 kyaeh # Character 컣
+U+cee4 keo # Character 커
+U+cee5 keog # Character 컥
+U+cee6 keogg # Character 컦
+U+cee7 keogs # Character 컧
+U+cee8 keon # Character 컨
+U+cee9 keonj # Character 컩
+U+ceea keonh # Character 컪
+U+ceeb keod # Character 컫
+U+ceec keol # Character 컬
+U+ceed keolg # Character ì»
+U+ceee keolm # Character ì»®
+U+ceef keolb # Character 컯
+U+cef0 keols # Character ì»°
+U+cef1 keolt # Character ì»±
+U+cef2 keolp # Character 컲
+U+cef3 keolh # Character 컳
+U+cef4 keom # Character ì»´
+U+cef5 keob # Character 컵
+U+cef6 keobs # Character 컶
+U+cef7 keos # Character ì»·
+U+cef8 keoss # Character 컸
+U+cef9 keong # Character 컹
+U+cefa keoj # Character 컺
+U+cefb keoc # Character ì»»
+U+cefc keok # Character 컼
+U+cefd keot # Character 컽
+U+cefe keop # Character 컾
+U+ceff keoh # Character 컿
diff --git a/resources/chars/ascii/rowcf.trans b/resources/chars/ascii/rowcf.trans
new file mode 100644
index 0000000..e8513ec
--- /dev/null
+++ b/resources/chars/ascii/rowcf.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+cf00 ke # Character ì¼
+U+cf01 keg # Character ì¼
+U+cf02 kegg # Character ì¼
+U+cf03 kegs # Character ì¼
+U+cf04 ken # Character ì¼
+U+cf05 kenj # Character ì¼
+U+cf06 kenh # Character ì¼
+U+cf07 ked # Character ì¼
+U+cf08 kel # Character ì¼
+U+cf09 kelg # Character ì¼
+U+cf0a kelm # Character ì¼
+U+cf0b kelb # Character ì¼
+U+cf0c kels # Character ì¼
+U+cf0d kelt # Character ì¼
+U+cf0e kelp # Character ì¼
+U+cf0f kelh # Character ì¼
+U+cf10 kem # Character ì¼
+U+cf11 keb # Character ì¼
+U+cf12 kebs # Character ì¼
+U+cf13 kes # Character ì¼
+U+cf14 kess # Character ì¼
+U+cf15 keng # Character ì¼
+U+cf16 kej # Character ì¼
+U+cf17 kec # Character ì¼
+U+cf18 kek # Character ì¼
+U+cf19 ket # Character ì¼
+U+cf1a kep # Character ì¼
+U+cf1b keh # Character ì¼
+U+cf1c kyeo # Character ì¼
+U+cf1d kyeog # Character ì¼
+U+cf1e kyeogg # Character ì¼
+U+cf1f kyeogs # Character ì¼
+U+cf20 kyeon # Character ì¼
+U+cf21 kyeonj # Character 켡
+U+cf22 kyeonh # Character ì¼¢
+U+cf23 kyeod # Character ì¼£
+U+cf24 kyeol # Character 켤
+U+cf25 kyeolg # Character ì¼¥
+U+cf26 kyeolm # Character 켦
+U+cf27 kyeolb # Character 켧
+U+cf28 kyeols # Character 켨
+U+cf29 kyeolt # Character 켩
+U+cf2a kyeolp # Character 켪
+U+cf2b kyeolh # Character 켫
+U+cf2c kyeom # Character 켬
+U+cf2d kyeob # Character ì¼
+U+cf2e kyeobs # Character ì¼®
+U+cf2f kyeos # Character 켯
+U+cf30 kyeoss # Character ì¼°
+U+cf31 kyeong # Character ì¼±
+U+cf32 kyeoj # Character ì¼²
+U+cf33 kyeoc # Character ì¼³
+U+cf34 kyeok # Character ì¼´
+U+cf35 kyeot # Character ì¼µ
+U+cf36 kyeop # Character 켶
+U+cf37 kyeoh # Character ì¼·
+U+cf38 kye # Character 켸
+U+cf39 kyeg # Character ì¼¹
+U+cf3a kyegg # Character 켺
+U+cf3b kyegs # Character ì¼»
+U+cf3c kyen # Character ì¼¼
+U+cf3d kyenj # Character ì¼½
+U+cf3e kyenh # Character ì¼¾
+U+cf3f kyed # Character 켿
+U+cf40 kyel # Character ì½
+U+cf41 kyelg # Character ì½
+U+cf42 kyelm # Character ì½
+U+cf43 kyelb # Character ì½
+U+cf44 kyels # Character ì½
+U+cf45 kyelt # Character ì½
+U+cf46 kyelp # Character ì½
+U+cf47 kyelh # Character ì½
+U+cf48 kyem # Character ì½
+U+cf49 kyeb # Character ì½
+U+cf4a kyebs # Character ì½
+U+cf4b kyes # Character ì½
+U+cf4c kyess # Character ì½
+U+cf4d kyeng # Character ì½
+U+cf4e kyej # Character ì½
+U+cf4f kyec # Character ì½
+U+cf50 kyek # Character ì½
+U+cf51 kyet # Character ì½
+U+cf52 kyep # Character ì½
+U+cf53 kyeh # Character ì½
+U+cf54 ko # Character ì½
+U+cf55 kog # Character ì½
+U+cf56 kogg # Character ì½
+U+cf57 kogs # Character ì½
+U+cf58 kon # Character ì½
+U+cf59 konj # Character ì½
+U+cf5a konh # Character ì½
+U+cf5b kod # Character ì½
+U+cf5c kol # Character ì½
+U+cf5d kolg # Character ì½
+U+cf5e kolm # Character ì½
+U+cf5f kolb # Character ì½
+U+cf60 kols # Character ì½
+U+cf61 kolt # Character 콡
+U+cf62 kolp # Character ì½¢
+U+cf63 kolh # Character ì½£
+U+cf64 kom # Character 콤
+U+cf65 kob # Character ì½¥
+U+cf66 kobs # Character 콦
+U+cf67 kos # Character 콧
+U+cf68 koss # Character 콨
+U+cf69 kong # Character 콩
+U+cf6a koj # Character 콪
+U+cf6b koc # Character 콫
+U+cf6c kok # Character 콬
+U+cf6d kot # Character ì½
+U+cf6e kop # Character ì½®
+U+cf6f koh # Character 콯
+U+cf70 kwa # Character ì½°
+U+cf71 kwag # Character ì½±
+U+cf72 kwagg # Character ì½²
+U+cf73 kwags # Character ì½³
+U+cf74 kwan # Character ì½´
+U+cf75 kwanj # Character ì½µ
+U+cf76 kwanh # Character 콶
+U+cf77 kwad # Character ì½·
+U+cf78 kwal # Character 콸
+U+cf79 kwalg # Character ì½¹
+U+cf7a kwalm # Character 콺
+U+cf7b kwalb # Character ì½»
+U+cf7c kwals # Character ì½¼
+U+cf7d kwalt # Character ì½½
+U+cf7e kwalp # Character ì½¾
+U+cf7f kwalh # Character 콿
+U+cf80 kwam # Character ì¾
+U+cf81 kwab # Character ì¾
+U+cf82 kwabs # Character ì¾
+U+cf83 kwas # Character ì¾
+U+cf84 kwass # Character ì¾
+U+cf85 kwang # Character ì¾
+U+cf86 kwaj # Character ì¾
+U+cf87 kwac # Character ì¾
+U+cf88 kwak # Character ì¾
+U+cf89 kwat # Character ì¾
+U+cf8a kwap # Character ì¾
+U+cf8b kwah # Character ì¾
+U+cf8c kwae # Character ì¾
+U+cf8d kwaeg # Character ì¾
+U+cf8e kwaegg # Character ì¾
+U+cf8f kwaegs # Character ì¾
+U+cf90 kwaen # Character ì¾
+U+cf91 kwaenj # Character ì¾
+U+cf92 kwaenh # Character ì¾
+U+cf93 kwaed # Character ì¾
+U+cf94 kwael # Character ì¾
+U+cf95 kwaelg # Character ì¾
+U+cf96 kwaelm # Character ì¾
+U+cf97 kwaelb # Character ì¾
+U+cf98 kwaels # Character ì¾
+U+cf99 kwaelt # Character ì¾
+U+cf9a kwaelp # Character ì¾
+U+cf9b kwaelh # Character ì¾
+U+cf9c kwaem # Character ì¾
+U+cf9d kwaeb # Character ì¾
+U+cf9e kwaebs # Character ì¾
+U+cf9f kwaes # Character ì¾
+U+cfa0 kwaess # Character ì¾
+U+cfa1 kwaeng # Character 쾡
+U+cfa2 kwaej # Character ì¾¢
+U+cfa3 kwaec # Character ì¾£
+U+cfa4 kwaek # Character 쾤
+U+cfa5 kwaet # Character ì¾¥
+U+cfa6 kwaep # Character 쾦
+U+cfa7 kwaeh # Character 쾧
+U+cfa8 koe # Character 쾨
+U+cfa9 koeg # Character 쾩
+U+cfaa koegg # Character 쾪
+U+cfab koegs # Character 쾫
+U+cfac koen # Character 쾬
+U+cfad koenj # Character ì¾
+U+cfae koenh # Character ì¾®
+U+cfaf koed # Character 쾯
+U+cfb0 koel # Character ì¾°
+U+cfb1 koelg # Character ì¾±
+U+cfb2 koelm # Character ì¾²
+U+cfb3 koelb # Character ì¾³
+U+cfb4 koels # Character ì¾´
+U+cfb5 koelt # Character ì¾µ
+U+cfb6 koelp # Character 쾶
+U+cfb7 koelh # Character ì¾·
+U+cfb8 koem # Character 쾸
+U+cfb9 koeb # Character ì¾¹
+U+cfba koebs # Character 쾺
+U+cfbb koes # Character ì¾»
+U+cfbc koess # Character ì¾¼
+U+cfbd koeng # Character ì¾½
+U+cfbe koej # Character ì¾¾
+U+cfbf koec # Character 쾿
+U+cfc0 koek # Character ì¿
+U+cfc1 koet # Character ì¿
+U+cfc2 koep # Character ì¿
+U+cfc3 koeh # Character ì¿
+U+cfc4 kyo # Character ì¿
+U+cfc5 kyog # Character ì¿
+U+cfc6 kyogg # Character ì¿
+U+cfc7 kyogs # Character ì¿
+U+cfc8 kyon # Character ì¿
+U+cfc9 kyonj # Character ì¿
+U+cfca kyonh # Character ì¿
+U+cfcb kyod # Character ì¿
+U+cfcc kyol # Character ì¿
+U+cfcd kyolg # Character ì¿
+U+cfce kyolm # Character ì¿
+U+cfcf kyolb # Character ì¿
+U+cfd0 kyols # Character ì¿
+U+cfd1 kyolt # Character ì¿
+U+cfd2 kyolp # Character ì¿
+U+cfd3 kyolh # Character ì¿
+U+cfd4 kyom # Character ì¿
+U+cfd5 kyob # Character ì¿
+U+cfd6 kyobs # Character ì¿
+U+cfd7 kyos # Character ì¿
+U+cfd8 kyoss # Character ì¿
+U+cfd9 kyong # Character ì¿
+U+cfda kyoj # Character ì¿
+U+cfdb kyoc # Character ì¿
+U+cfdc kyok # Character ì¿
+U+cfdd kyot # Character ì¿
+U+cfde kyop # Character ì¿
+U+cfdf kyoh # Character ì¿
+U+cfe0 ku # Character ì¿
+U+cfe1 kug # Character ì¿¡
+U+cfe2 kugg # Character ì¿¢
+U+cfe3 kugs # Character ì¿£
+U+cfe4 kun # Character 쿤
+U+cfe5 kunj # Character ì¿¥
+U+cfe6 kunh # Character 쿦
+U+cfe7 kud # Character 쿧
+U+cfe8 kul # Character 쿨
+U+cfe9 kulg # Character ì¿©
+U+cfea kulm # Character 쿪
+U+cfeb kulb # Character ì¿«
+U+cfec kuls # Character 쿬
+U+cfed kult # Character ì¿
+U+cfee kulp # Character ì¿®
+U+cfef kulh # Character 쿯
+U+cff0 kum # Character ì¿°
+U+cff1 kub # Character 쿱
+U+cff2 kubs # Character 쿲
+U+cff3 kus # Character 쿳
+U+cff4 kuss # Character ì¿´
+U+cff5 kung # Character 쿵
+U+cff6 kuj # Character 쿶
+U+cff7 kuc # Character ì¿·
+U+cff8 kuk # Character 쿸
+U+cff9 kut # Character 쿹
+U+cffa kup # Character 쿺
+U+cffb kuh # Character ì¿»
+U+cffc kweo # Character 쿼
+U+cffd kweog # Character 쿽
+U+cffe kweogg # Character 쿾
+U+cfff kweogs # Character ì¿¿
diff --git a/resources/chars/ascii/rowd0.trans b/resources/chars/ascii/rowd0.trans
new file mode 100644
index 0000000..f3b7410
--- /dev/null
+++ b/resources/chars/ascii/rowd0.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+d000 kweon # Character í
+U+d001 kweonj # Character í
+U+d002 kweonh # Character í
+U+d003 kweod # Character í
+U+d004 kweol # Character í
+U+d005 kweolg # Character í
+U+d006 kweolm # Character í
+U+d007 kweolb # Character í
+U+d008 kweols # Character í
+U+d009 kweolt # Character í
+U+d00a kweolp # Character í
+U+d00b kweolh # Character í
+U+d00c kweom # Character í
+U+d00d kweob # Character í
+U+d00e kweobs # Character í
+U+d00f kweos # Character í
+U+d010 kweoss # Character í
+U+d011 kweong # Character í
+U+d012 kweoj # Character í
+U+d013 kweoc # Character í
+U+d014 kweok # Character í
+U+d015 kweot # Character í
+U+d016 kweop # Character í
+U+d017 kweoh # Character í
+U+d018 kwe # Character í
+U+d019 kweg # Character í
+U+d01a kwegg # Character í
+U+d01b kwegs # Character í
+U+d01c kwen # Character í
+U+d01d kwenj # Character í
+U+d01e kwenh # Character í
+U+d01f kwed # Character í
+U+d020 kwel # Character í
+U+d021 kwelg # Character í¡
+U+d022 kwelm # Character í¢
+U+d023 kwelb # Character í£
+U+d024 kwels # Character í¤
+U+d025 kwelt # Character í¥
+U+d026 kwelp # Character í¦
+U+d027 kwelh # Character í§
+U+d028 kwem # Character í¨
+U+d029 kweb # Character í©
+U+d02a kwebs # Character íª
+U+d02b kwes # Character í«
+U+d02c kwess # Character í¬
+U+d02d kweng # Character í
+U+d02e kwej # Character í®
+U+d02f kwec # Character í¯
+U+d030 kwek # Character í°
+U+d031 kwet # Character í±
+U+d032 kwep # Character í²
+U+d033 kweh # Character í³
+U+d034 kwi # Character í´
+U+d035 kwig # Character íµ
+U+d036 kwigg # Character í¶
+U+d037 kwigs # Character í·
+U+d038 kwin # Character í¸
+U+d039 kwinj # Character í¹
+U+d03a kwinh # Character íº
+U+d03b kwid # Character í»
+U+d03c kwil # Character í¼
+U+d03d kwilg # Character í½
+U+d03e kwilm # Character í¾
+U+d03f kwilb # Character í¿
+U+d040 kwils # Character í
+U+d041 kwilt # Character í
+U+d042 kwilp # Character í
+U+d043 kwilh # Character í
+U+d044 kwim # Character í
+U+d045 kwib # Character í
+U+d046 kwibs # Character í
+U+d047 kwis # Character í
+U+d048 kwiss # Character í
+U+d049 kwing # Character í
+U+d04a kwij # Character í
+U+d04b kwic # Character í
+U+d04c kwik # Character í
+U+d04d kwit # Character í
+U+d04e kwip # Character í
+U+d04f kwih # Character í
+U+d050 kyu # Character í
+U+d051 kyug # Character í
+U+d052 kyugg # Character í
+U+d053 kyugs # Character í
+U+d054 kyun # Character í
+U+d055 kyunj # Character í
+U+d056 kyunh # Character í
+U+d057 kyud # Character í
+U+d058 kyul # Character í
+U+d059 kyulg # Character í
+U+d05a kyulm # Character í
+U+d05b kyulb # Character í
+U+d05c kyuls # Character í
+U+d05d kyult # Character í
+U+d05e kyulp # Character í
+U+d05f kyulh # Character í
+U+d060 kyum # Character í
+U+d061 kyub # Character í¡
+U+d062 kyubs # Character í¢
+U+d063 kyus # Character í£
+U+d064 kyuss # Character í¤
+U+d065 kyung # Character í¥
+U+d066 kyuj # Character í¦
+U+d067 kyuc # Character í§
+U+d068 kyuk # Character í¨
+U+d069 kyut # Character í©
+U+d06a kyup # Character íª
+U+d06b kyuh # Character í«
+U+d06c keu # Character í¬
+U+d06d keug # Character í
+U+d06e keugg # Character í®
+U+d06f keugs # Character í¯
+U+d070 keun # Character í°
+U+d071 keunj # Character í±
+U+d072 keunh # Character í²
+U+d073 keud # Character í³
+U+d074 keul # Character í´
+U+d075 keulg # Character íµ
+U+d076 keulm # Character í¶
+U+d077 keulb # Character í·
+U+d078 keuls # Character í¸
+U+d079 keult # Character í¹
+U+d07a keulp # Character íº
+U+d07b keulh # Character í»
+U+d07c keum # Character í¼
+U+d07d keub # Character í½
+U+d07e keubs # Character í¾
+U+d07f keus # Character í¿
+U+d080 keuss # Character í
+U+d081 keung # Character í
+U+d082 keuj # Character í
+U+d083 keuc # Character í
+U+d084 keuk # Character í
+U+d085 keut # Character í
+U+d086 keup # Character í
+U+d087 keuh # Character í
+U+d088 kyi # Character í
+U+d089 kyig # Character í
+U+d08a kyigg # Character í
+U+d08b kyigs # Character í
+U+d08c kyin # Character í
+U+d08d kyinj # Character í
+U+d08e kyinh # Character í
+U+d08f kyid # Character í
+U+d090 kyil # Character í
+U+d091 kyilg # Character í
+U+d092 kyilm # Character í
+U+d093 kyilb # Character í
+U+d094 kyils # Character í
+U+d095 kyilt # Character í
+U+d096 kyilp # Character í
+U+d097 kyilh # Character í
+U+d098 kyim # Character í
+U+d099 kyib # Character í
+U+d09a kyibs # Character í
+U+d09b kyis # Character í
+U+d09c kyiss # Character í
+U+d09d kying # Character í
+U+d09e kyij # Character í
+U+d09f kyic # Character í
+U+d0a0 kyik # Character í
+U+d0a1 kyit # Character í¡
+U+d0a2 kyip # Character í¢
+U+d0a3 kyih # Character í£
+U+d0a4 ki # Character í¤
+U+d0a5 kig # Character í¥
+U+d0a6 kigg # Character í¦
+U+d0a7 kigs # Character í§
+U+d0a8 kin # Character í¨
+U+d0a9 kinj # Character í©
+U+d0aa kinh # Character íª
+U+d0ab kid # Character í«
+U+d0ac kil # Character í¬
+U+d0ad kilg # Character í
+U+d0ae kilm # Character í®
+U+d0af kilb # Character í¯
+U+d0b0 kils # Character í°
+U+d0b1 kilt # Character í±
+U+d0b2 kilp # Character í²
+U+d0b3 kilh # Character í³
+U+d0b4 kim # Character í´
+U+d0b5 kib # Character íµ
+U+d0b6 kibs # Character í¶
+U+d0b7 kis # Character í·
+U+d0b8 kiss # Character í¸
+U+d0b9 king # Character í¹
+U+d0ba kij # Character íº
+U+d0bb kic # Character í»
+U+d0bc kik # Character í¼
+U+d0bd kit # Character í½
+U+d0be kip # Character í¾
+U+d0bf kih # Character í¿
+U+d0c0 ta # Character í
+U+d0c1 tag # Character í
+U+d0c2 tagg # Character í
+U+d0c3 tags # Character í
+U+d0c4 tan # Character í
+U+d0c5 tanj # Character í
+U+d0c6 tanh # Character í
+U+d0c7 tad # Character í
+U+d0c8 tal # Character í
+U+d0c9 talg # Character í
+U+d0ca talm # Character í
+U+d0cb talb # Character í
+U+d0cc tals # Character í
+U+d0cd talt # Character í
+U+d0ce talp # Character í
+U+d0cf talh # Character í
+U+d0d0 tam # Character í
+U+d0d1 tab # Character í
+U+d0d2 tabs # Character í
+U+d0d3 tas # Character í
+U+d0d4 tass # Character í
+U+d0d5 tang # Character í
+U+d0d6 taj # Character í
+U+d0d7 tac # Character í
+U+d0d8 tak # Character í
+U+d0d9 tat # Character í
+U+d0da tap # Character í
+U+d0db tah # Character í
+U+d0dc tae # Character í
+U+d0dd taeg # Character í
+U+d0de taegg # Character í
+U+d0df taegs # Character í
+U+d0e0 taen # Character í
+U+d0e1 taenj # Character í¡
+U+d0e2 taenh # Character í¢
+U+d0e3 taed # Character í£
+U+d0e4 tael # Character í¤
+U+d0e5 taelg # Character í¥
+U+d0e6 taelm # Character í¦
+U+d0e7 taelb # Character í§
+U+d0e8 taels # Character í¨
+U+d0e9 taelt # Character í©
+U+d0ea taelp # Character íª
+U+d0eb taelh # Character í«
+U+d0ec taem # Character í¬
+U+d0ed taeb # Character í
+U+d0ee taebs # Character í®
+U+d0ef taes # Character í¯
+U+d0f0 taess # Character í°
+U+d0f1 taeng # Character í±
+U+d0f2 taej # Character í²
+U+d0f3 taec # Character í³
+U+d0f4 taek # Character í´
+U+d0f5 taet # Character íµ
+U+d0f6 taep # Character í¶
+U+d0f7 taeh # Character í·
+U+d0f8 tya # Character í¸
+U+d0f9 tyag # Character í¹
+U+d0fa tyagg # Character íº
+U+d0fb tyags # Character í»
+U+d0fc tyan # Character í¼
+U+d0fd tyanj # Character í½
+U+d0fe tyanh # Character í¾
+U+d0ff tyad # Character í¿
diff --git a/resources/chars/ascii/rowd1.trans b/resources/chars/ascii/rowd1.trans
new file mode 100644
index 0000000..33a125e
--- /dev/null
+++ b/resources/chars/ascii/rowd1.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+d100 tyal # Character í
+U+d101 tyalg # Character í
+U+d102 tyalm # Character í
+U+d103 tyalb # Character í
+U+d104 tyals # Character í
+U+d105 tyalt # Character í
+U+d106 tyalp # Character í
+U+d107 tyalh # Character í
+U+d108 tyam # Character í
+U+d109 tyab # Character í
+U+d10a tyabs # Character í
+U+d10b tyas # Character í
+U+d10c tyass # Character í
+U+d10d tyang # Character í
+U+d10e tyaj # Character í
+U+d10f tyac # Character í
+U+d110 tyak # Character í
+U+d111 tyat # Character í
+U+d112 tyap # Character í
+U+d113 tyah # Character í
+U+d114 tyae # Character í
+U+d115 tyaeg # Character í
+U+d116 tyaegg # Character í
+U+d117 tyaegs # Character í
+U+d118 tyaen # Character í
+U+d119 tyaenj # Character í
+U+d11a tyaenh # Character í
+U+d11b tyaed # Character í
+U+d11c tyael # Character í
+U+d11d tyaelg # Character í
+U+d11e tyaelm # Character í
+U+d11f tyaelb # Character í
+U+d120 tyaels # Character í
+U+d121 tyaelt # Character í¡
+U+d122 tyaelp # Character í¢
+U+d123 tyaelh # Character í£
+U+d124 tyaem # Character í¤
+U+d125 tyaeb # Character í¥
+U+d126 tyaebs # Character í¦
+U+d127 tyaes # Character í§
+U+d128 tyaess # Character í¨
+U+d129 tyaeng # Character í©
+U+d12a tyaej # Character íª
+U+d12b tyaec # Character í«
+U+d12c tyaek # Character í¬
+U+d12d tyaet # Character í
+U+d12e tyaep # Character í®
+U+d12f tyaeh # Character í¯
+U+d130 teo # Character í°
+U+d131 teog # Character í±
+U+d132 teogg # Character í²
+U+d133 teogs # Character í³
+U+d134 teon # Character í´
+U+d135 teonj # Character íµ
+U+d136 teonh # Character í¶
+U+d137 teod # Character í·
+U+d138 teol # Character í¸
+U+d139 teolg # Character í¹
+U+d13a teolm # Character íº
+U+d13b teolb # Character í»
+U+d13c teols # Character í¼
+U+d13d teolt # Character í½
+U+d13e teolp # Character í¾
+U+d13f teolh # Character í¿
+U+d140 teom # Character í
+U+d141 teob # Character í
+U+d142 teobs # Character í
+U+d143 teos # Character í
+U+d144 teoss # Character í
+U+d145 teong # Character í
+U+d146 teoj # Character í
+U+d147 teoc # Character í
+U+d148 teok # Character í
+U+d149 teot # Character í
+U+d14a teop # Character í
+U+d14b teoh # Character í
+U+d14c te # Character í
+U+d14d teg # Character í
+U+d14e tegg # Character í
+U+d14f tegs # Character í
+U+d150 ten # Character í
+U+d151 tenj # Character í
+U+d152 tenh # Character í
+U+d153 ted # Character í
+U+d154 tel # Character í
+U+d155 telg # Character í
+U+d156 telm # Character í
+U+d157 telb # Character í
+U+d158 tels # Character í
+U+d159 telt # Character í
+U+d15a telp # Character í
+U+d15b telh # Character í
+U+d15c tem # Character í
+U+d15d teb # Character í
+U+d15e tebs # Character í
+U+d15f tes # Character í
+U+d160 tess # Character í
+U+d161 teng # Character í
¡
+U+d162 tej # Character í
¢
+U+d163 tec # Character í
£
+U+d164 tek # Character í
¤
+U+d165 tet # Character í
¥
+U+d166 tep # Character í
¦
+U+d167 teh # Character í
§
+U+d168 tyeo # Character í
¨
+U+d169 tyeog # Character í
©
+U+d16a tyeogg # Character í
ª
+U+d16b tyeogs # Character í
«
+U+d16c tyeon # Character í
¬
+U+d16d tyeonj # Character í
+U+d16e tyeonh # Character í
®
+U+d16f tyeod # Character í
¯
+U+d170 tyeol # Character í
°
+U+d171 tyeolg # Character í
±
+U+d172 tyeolm # Character í
²
+U+d173 tyeolb # Character í
³
+U+d174 tyeols # Character í
´
+U+d175 tyeolt # Character í
µ
+U+d176 tyeolp # Character í
¶
+U+d177 tyeolh # Character í
·
+U+d178 tyeom # Character í
¸
+U+d179 tyeob # Character í
¹
+U+d17a tyeobs # Character í
º
+U+d17b tyeos # Character í
»
+U+d17c tyeoss # Character í
¼
+U+d17d tyeong # Character í
½
+U+d17e tyeoj # Character í
¾
+U+d17f tyeoc # Character í
¿
+U+d180 tyeok # Character í
+U+d181 tyeot # Character í
+U+d182 tyeop # Character í
+U+d183 tyeoh # Character í
+U+d184 tye # Character í
+U+d185 tyeg # Character í
+U+d186 tyegg # Character í
+U+d187 tyegs # Character í
+U+d188 tyen # Character í
+U+d189 tyenj # Character í
+U+d18a tyenh # Character í
+U+d18b tyed # Character í
+U+d18c tyel # Character í
+U+d18d tyelg # Character í
+U+d18e tyelm # Character í
+U+d18f tyelb # Character í
+U+d190 tyels # Character í
+U+d191 tyelt # Character í
+U+d192 tyelp # Character í
+U+d193 tyelh # Character í
+U+d194 tyem # Character í
+U+d195 tyeb # Character í
+U+d196 tyebs # Character í
+U+d197 tyes # Character í
+U+d198 tyess # Character í
+U+d199 tyeng # Character í
+U+d19a tyej # Character í
+U+d19b tyec # Character í
+U+d19c tyek # Character í
+U+d19d tyet # Character í
+U+d19e tyep # Character í
+U+d19f tyeh # Character í
+U+d1a0 to # Character í
+U+d1a1 tog # Character í¡
+U+d1a2 togg # Character í¢
+U+d1a3 togs # Character í£
+U+d1a4 ton # Character í¤
+U+d1a5 tonj # Character í¥
+U+d1a6 tonh # Character í¦
+U+d1a7 tod # Character í§
+U+d1a8 tol # Character í¨
+U+d1a9 tolg # Character í©
+U+d1aa tolm # Character íª
+U+d1ab tolb # Character í«
+U+d1ac tols # Character í¬
+U+d1ad tolt # Character í
+U+d1ae tolp # Character í®
+U+d1af tolh # Character í¯
+U+d1b0 tom # Character í°
+U+d1b1 tob # Character í±
+U+d1b2 tobs # Character í²
+U+d1b3 tos # Character í³
+U+d1b4 toss # Character í´
+U+d1b5 tong # Character íµ
+U+d1b6 toj # Character í¶
+U+d1b7 toc # Character í·
+U+d1b8 tok # Character í¸
+U+d1b9 tot # Character í¹
+U+d1ba top # Character íº
+U+d1bb toh # Character í»
+U+d1bc twa # Character í¼
+U+d1bd twag # Character í½
+U+d1be twagg # Character í¾
+U+d1bf twags # Character í¿
+U+d1c0 twan # Character í
+U+d1c1 twanj # Character í
+U+d1c2 twanh # Character í
+U+d1c3 twad # Character í
+U+d1c4 twal # Character í
+U+d1c5 twalg # Character í
+U+d1c6 twalm # Character í
+U+d1c7 twalb # Character í
+U+d1c8 twals # Character í
+U+d1c9 twalt # Character í
+U+d1ca twalp # Character í
+U+d1cb twalh # Character í
+U+d1cc twam # Character í
+U+d1cd twab # Character í
+U+d1ce twabs # Character í
+U+d1cf twas # Character í
+U+d1d0 twass # Character í
+U+d1d1 twang # Character í
+U+d1d2 twaj # Character í
+U+d1d3 twac # Character í
+U+d1d4 twak # Character í
+U+d1d5 twat # Character í
+U+d1d6 twap # Character í
+U+d1d7 twah # Character í
+U+d1d8 twae # Character í
+U+d1d9 twaeg # Character í
+U+d1da twaegg # Character í
+U+d1db twaegs # Character í
+U+d1dc twaen # Character í
+U+d1dd twaenj # Character í
+U+d1de twaenh # Character í
+U+d1df twaed # Character í
+U+d1e0 twael # Character í
+U+d1e1 twaelg # Character í¡
+U+d1e2 twaelm # Character í¢
+U+d1e3 twaelb # Character í£
+U+d1e4 twaels # Character í¤
+U+d1e5 twaelt # Character í¥
+U+d1e6 twaelp # Character í¦
+U+d1e7 twaelh # Character í§
+U+d1e8 twaem # Character í¨
+U+d1e9 twaeb # Character í©
+U+d1ea twaebs # Character íª
+U+d1eb twaes # Character í«
+U+d1ec twaess # Character í¬
+U+d1ed twaeng # Character í
+U+d1ee twaej # Character í®
+U+d1ef twaec # Character í¯
+U+d1f0 twaek # Character í°
+U+d1f1 twaet # Character í±
+U+d1f2 twaep # Character í²
+U+d1f3 twaeh # Character í³
+U+d1f4 toe # Character í´
+U+d1f5 toeg # Character íµ
+U+d1f6 toegg # Character í¶
+U+d1f7 toegs # Character í·
+U+d1f8 toen # Character í¸
+U+d1f9 toenj # Character í¹
+U+d1fa toenh # Character íº
+U+d1fb toed # Character í»
+U+d1fc toel # Character í¼
+U+d1fd toelg # Character í½
+U+d1fe toelm # Character í¾
+U+d1ff toelb # Character í¿
diff --git a/resources/chars/ascii/rowd2.trans b/resources/chars/ascii/rowd2.trans
new file mode 100644
index 0000000..47966e8
--- /dev/null
+++ b/resources/chars/ascii/rowd2.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+d200 toels # Character í
+U+d201 toelt # Character í
+U+d202 toelp # Character í
+U+d203 toelh # Character í
+U+d204 toem # Character í
+U+d205 toeb # Character í
+U+d206 toebs # Character í
+U+d207 toes # Character í
+U+d208 toess # Character í
+U+d209 toeng # Character í
+U+d20a toej # Character í
+U+d20b toec # Character í
+U+d20c toek # Character í
+U+d20d toet # Character í
+U+d20e toep # Character í
+U+d20f toeh # Character í
+U+d210 tyo # Character í
+U+d211 tyog # Character í
+U+d212 tyogg # Character í
+U+d213 tyogs # Character í
+U+d214 tyon # Character í
+U+d215 tyonj # Character í
+U+d216 tyonh # Character í
+U+d217 tyod # Character í
+U+d218 tyol # Character í
+U+d219 tyolg # Character í
+U+d21a tyolm # Character í
+U+d21b tyolb # Character í
+U+d21c tyols # Character í
+U+d21d tyolt # Character í
+U+d21e tyolp # Character í
+U+d21f tyolh # Character í
+U+d220 tyom # Character í
+U+d221 tyob # Character í¡
+U+d222 tyobs # Character í¢
+U+d223 tyos # Character í£
+U+d224 tyoss # Character í¤
+U+d225 tyong # Character í¥
+U+d226 tyoj # Character í¦
+U+d227 tyoc # Character í§
+U+d228 tyok # Character í¨
+U+d229 tyot # Character í©
+U+d22a tyop # Character íª
+U+d22b tyoh # Character í«
+U+d22c tu # Character í¬
+U+d22d tug # Character í
+U+d22e tugg # Character í®
+U+d22f tugs # Character í¯
+U+d230 tun # Character í°
+U+d231 tunj # Character í±
+U+d232 tunh # Character í²
+U+d233 tud # Character í³
+U+d234 tul # Character í´
+U+d235 tulg # Character íµ
+U+d236 tulm # Character í¶
+U+d237 tulb # Character í·
+U+d238 tuls # Character í¸
+U+d239 tult # Character í¹
+U+d23a tulp # Character íº
+U+d23b tulh # Character í»
+U+d23c tum # Character í¼
+U+d23d tub # Character í½
+U+d23e tubs # Character í¾
+U+d23f tus # Character í¿
+U+d240 tuss # Character í
+U+d241 tung # Character í
+U+d242 tuj # Character í
+U+d243 tuc # Character í
+U+d244 tuk # Character í
+U+d245 tut # Character í
+U+d246 tup # Character í
+U+d247 tuh # Character í
+U+d248 tweo # Character í
+U+d249 tweog # Character í
+U+d24a tweogg # Character í
+U+d24b tweogs # Character í
+U+d24c tweon # Character í
+U+d24d tweonj # Character í
+U+d24e tweonh # Character í
+U+d24f tweod # Character í
+U+d250 tweol # Character í
+U+d251 tweolg # Character í
+U+d252 tweolm # Character í
+U+d253 tweolb # Character í
+U+d254 tweols # Character í
+U+d255 tweolt # Character í
+U+d256 tweolp # Character í
+U+d257 tweolh # Character í
+U+d258 tweom # Character í
+U+d259 tweob # Character í
+U+d25a tweobs # Character í
+U+d25b tweos # Character í
+U+d25c tweoss # Character í
+U+d25d tweong # Character í
+U+d25e tweoj # Character í
+U+d25f tweoc # Character í
+U+d260 tweok # Character í
+U+d261 tweot # Character í¡
+U+d262 tweop # Character í¢
+U+d263 tweoh # Character í£
+U+d264 twe # Character í¤
+U+d265 tweg # Character í¥
+U+d266 twegg # Character í¦
+U+d267 twegs # Character í§
+U+d268 twen # Character í¨
+U+d269 twenj # Character í©
+U+d26a twenh # Character íª
+U+d26b twed # Character í«
+U+d26c twel # Character í¬
+U+d26d twelg # Character í
+U+d26e twelm # Character í®
+U+d26f twelb # Character í¯
+U+d270 twels # Character í°
+U+d271 twelt # Character í±
+U+d272 twelp # Character í²
+U+d273 twelh # Character í³
+U+d274 twem # Character í´
+U+d275 tweb # Character íµ
+U+d276 twebs # Character í¶
+U+d277 twes # Character í·
+U+d278 twess # Character í¸
+U+d279 tweng # Character í¹
+U+d27a twej # Character íº
+U+d27b twec # Character í»
+U+d27c twek # Character í¼
+U+d27d twet # Character í½
+U+d27e twep # Character í¾
+U+d27f tweh # Character í¿
+U+d280 twi # Character í
+U+d281 twig # Character í
+U+d282 twigg # Character í
+U+d283 twigs # Character í
+U+d284 twin # Character í
+U+d285 twinj # Character í
+U+d286 twinh # Character í
+U+d287 twid # Character í
+U+d288 twil # Character í
+U+d289 twilg # Character í
+U+d28a twilm # Character í
+U+d28b twilb # Character í
+U+d28c twils # Character í
+U+d28d twilt # Character í
+U+d28e twilp # Character í
+U+d28f twilh # Character í
+U+d290 twim # Character í
+U+d291 twib # Character í
+U+d292 twibs # Character í
+U+d293 twis # Character í
+U+d294 twiss # Character í
+U+d295 twing # Character í
+U+d296 twij # Character í
+U+d297 twic # Character í
+U+d298 twik # Character í
+U+d299 twit # Character í
+U+d29a twip # Character í
+U+d29b twih # Character í
+U+d29c tyu # Character í
+U+d29d tyug # Character í
+U+d29e tyugg # Character í
+U+d29f tyugs # Character í
+U+d2a0 tyun # Character í
+U+d2a1 tyunj # Character í¡
+U+d2a2 tyunh # Character í¢
+U+d2a3 tyud # Character í£
+U+d2a4 tyul # Character í¤
+U+d2a5 tyulg # Character í¥
+U+d2a6 tyulm # Character í¦
+U+d2a7 tyulb # Character í§
+U+d2a8 tyuls # Character í¨
+U+d2a9 tyult # Character í©
+U+d2aa tyulp # Character íª
+U+d2ab tyulh # Character í«
+U+d2ac tyum # Character í¬
+U+d2ad tyub # Character í
+U+d2ae tyubs # Character í®
+U+d2af tyus # Character í¯
+U+d2b0 tyuss # Character í°
+U+d2b1 tyung # Character í±
+U+d2b2 tyuj # Character í²
+U+d2b3 tyuc # Character í³
+U+d2b4 tyuk # Character í´
+U+d2b5 tyut # Character íµ
+U+d2b6 tyup # Character í¶
+U+d2b7 tyuh # Character í·
+U+d2b8 teu # Character í¸
+U+d2b9 teug # Character í¹
+U+d2ba teugg # Character íº
+U+d2bb teugs # Character í»
+U+d2bc teun # Character í¼
+U+d2bd teunj # Character í½
+U+d2be teunh # Character í¾
+U+d2bf teud # Character í¿
+U+d2c0 teul # Character í
+U+d2c1 teulg # Character í
+U+d2c2 teulm # Character í
+U+d2c3 teulb # Character í
+U+d2c4 teuls # Character í
+U+d2c5 teult # Character í
+U+d2c6 teulp # Character í
+U+d2c7 teulh # Character í
+U+d2c8 teum # Character í
+U+d2c9 teub # Character í
+U+d2ca teubs # Character í
+U+d2cb teus # Character í
+U+d2cc teuss # Character í
+U+d2cd teung # Character í
+U+d2ce teuj # Character í
+U+d2cf teuc # Character í
+U+d2d0 teuk # Character í
+U+d2d1 teut # Character í
+U+d2d2 teup # Character í
+U+d2d3 teuh # Character í
+U+d2d4 tyi # Character í
+U+d2d5 tyig # Character í
+U+d2d6 tyigg # Character í
+U+d2d7 tyigs # Character í
+U+d2d8 tyin # Character í
+U+d2d9 tyinj # Character í
+U+d2da tyinh # Character í
+U+d2db tyid # Character í
+U+d2dc tyil # Character í
+U+d2dd tyilg # Character í
+U+d2de tyilm # Character í
+U+d2df tyilb # Character í
+U+d2e0 tyils # Character í
+U+d2e1 tyilt # Character í¡
+U+d2e2 tyilp # Character í¢
+U+d2e3 tyilh # Character í£
+U+d2e4 tyim # Character í¤
+U+d2e5 tyib # Character í¥
+U+d2e6 tyibs # Character í¦
+U+d2e7 tyis # Character í§
+U+d2e8 tyiss # Character í¨
+U+d2e9 tying # Character í©
+U+d2ea tyij # Character íª
+U+d2eb tyic # Character í«
+U+d2ec tyik # Character í¬
+U+d2ed tyit # Character í
+U+d2ee tyip # Character í®
+U+d2ef tyih # Character í¯
+U+d2f0 ti # Character í°
+U+d2f1 tig # Character í±
+U+d2f2 tigg # Character í²
+U+d2f3 tigs # Character í³
+U+d2f4 tin # Character í´
+U+d2f5 tinj # Character íµ
+U+d2f6 tinh # Character í¶
+U+d2f7 tid # Character í·
+U+d2f8 til # Character í¸
+U+d2f9 tilg # Character í¹
+U+d2fa tilm # Character íº
+U+d2fb tilb # Character í»
+U+d2fc tils # Character í¼
+U+d2fd tilt # Character í½
+U+d2fe tilp # Character í¾
+U+d2ff tilh # Character í¿
diff --git a/resources/chars/ascii/rowd3.trans b/resources/chars/ascii/rowd3.trans
new file mode 100644
index 0000000..d5f0ac0
--- /dev/null
+++ b/resources/chars/ascii/rowd3.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+d300 tim # Character í
+U+d301 tib # Character í
+U+d302 tibs # Character í
+U+d303 tis # Character í
+U+d304 tiss # Character í
+U+d305 ting # Character í
+U+d306 tij # Character í
+U+d307 tic # Character í
+U+d308 tik # Character í
+U+d309 tit # Character í
+U+d30a tip # Character í
+U+d30b tih # Character í
+U+d30c pa # Character í
+U+d30d pag # Character í
+U+d30e pagg # Character í
+U+d30f pags # Character í
+U+d310 pan # Character í
+U+d311 panj # Character í
+U+d312 panh # Character í
+U+d313 pad # Character í
+U+d314 pal # Character í
+U+d315 palg # Character í
+U+d316 palm # Character í
+U+d317 palb # Character í
+U+d318 pals # Character í
+U+d319 palt # Character í
+U+d31a palp # Character í
+U+d31b palh # Character í
+U+d31c pam # Character í
+U+d31d pab # Character í
+U+d31e pabs # Character í
+U+d31f pas # Character í
+U+d320 pass # Character í
+U+d321 pang # Character í¡
+U+d322 paj # Character í¢
+U+d323 pac # Character í£
+U+d324 pak # Character í¤
+U+d325 pat # Character í¥
+U+d326 pap # Character í¦
+U+d327 pah # Character í§
+U+d328 pae # Character í¨
+U+d329 paeg # Character í©
+U+d32a paegg # Character íª
+U+d32b paegs # Character í«
+U+d32c paen # Character í¬
+U+d32d paenj # Character í
+U+d32e paenh # Character í®
+U+d32f paed # Character í¯
+U+d330 pael # Character í°
+U+d331 paelg # Character í±
+U+d332 paelm # Character í²
+U+d333 paelb # Character í³
+U+d334 paels # Character í´
+U+d335 paelt # Character íµ
+U+d336 paelp # Character í¶
+U+d337 paelh # Character í·
+U+d338 paem # Character í¸
+U+d339 paeb # Character í¹
+U+d33a paebs # Character íº
+U+d33b paes # Character í»
+U+d33c paess # Character í¼
+U+d33d paeng # Character í½
+U+d33e paej # Character í¾
+U+d33f paec # Character í¿
+U+d340 paek # Character í
+U+d341 paet # Character í
+U+d342 paep # Character í
+U+d343 paeh # Character í
+U+d344 pya # Character í
+U+d345 pyag # Character í
+U+d346 pyagg # Character í
+U+d347 pyags # Character í
+U+d348 pyan # Character í
+U+d349 pyanj # Character í
+U+d34a pyanh # Character í
+U+d34b pyad # Character í
+U+d34c pyal # Character í
+U+d34d pyalg # Character í
+U+d34e pyalm # Character í
+U+d34f pyalb # Character í
+U+d350 pyals # Character í
+U+d351 pyalt # Character í
+U+d352 pyalp # Character í
+U+d353 pyalh # Character í
+U+d354 pyam # Character í
+U+d355 pyab # Character í
+U+d356 pyabs # Character í
+U+d357 pyas # Character í
+U+d358 pyass # Character í
+U+d359 pyang # Character í
+U+d35a pyaj # Character í
+U+d35b pyac # Character í
+U+d35c pyak # Character í
+U+d35d pyat # Character í
+U+d35e pyap # Character í
+U+d35f pyah # Character í
+U+d360 pyae # Character í
+U+d361 pyaeg # Character í¡
+U+d362 pyaegg # Character í¢
+U+d363 pyaegs # Character í£
+U+d364 pyaen # Character í¤
+U+d365 pyaenj # Character í¥
+U+d366 pyaenh # Character í¦
+U+d367 pyaed # Character í§
+U+d368 pyael # Character í¨
+U+d369 pyaelg # Character í©
+U+d36a pyaelm # Character íª
+U+d36b pyaelb # Character í«
+U+d36c pyaels # Character í¬
+U+d36d pyaelt # Character í
+U+d36e pyaelp # Character í®
+U+d36f pyaelh # Character í¯
+U+d370 pyaem # Character í°
+U+d371 pyaeb # Character í±
+U+d372 pyaebs # Character í²
+U+d373 pyaes # Character í³
+U+d374 pyaess # Character í´
+U+d375 pyaeng # Character íµ
+U+d376 pyaej # Character í¶
+U+d377 pyaec # Character í·
+U+d378 pyaek # Character í¸
+U+d379 pyaet # Character í¹
+U+d37a pyaep # Character íº
+U+d37b pyaeh # Character í»
+U+d37c peo # Character í¼
+U+d37d peog # Character í½
+U+d37e peogg # Character í¾
+U+d37f peogs # Character í¿
+U+d380 peon # Character í
+U+d381 peonj # Character í
+U+d382 peonh # Character í
+U+d383 peod # Character í
+U+d384 peol # Character í
+U+d385 peolg # Character í
+U+d386 peolm # Character í
+U+d387 peolb # Character í
+U+d388 peols # Character í
+U+d389 peolt # Character í
+U+d38a peolp # Character í
+U+d38b peolh # Character í
+U+d38c peom # Character í
+U+d38d peob # Character í
+U+d38e peobs # Character í
+U+d38f peos # Character í
+U+d390 peoss # Character í
+U+d391 peong # Character í
+U+d392 peoj # Character í
+U+d393 peoc # Character í
+U+d394 peok # Character í
+U+d395 peot # Character í
+U+d396 peop # Character í
+U+d397 peoh # Character í
+U+d398 pe # Character í
+U+d399 peg # Character í
+U+d39a pegg # Character í
+U+d39b pegs # Character í
+U+d39c pen # Character í
+U+d39d penj # Character í
+U+d39e penh # Character í
+U+d39f ped # Character í
+U+d3a0 pel # Character í
+U+d3a1 pelg # Character í¡
+U+d3a2 pelm # Character í¢
+U+d3a3 pelb # Character í£
+U+d3a4 pels # Character í¤
+U+d3a5 pelt # Character í¥
+U+d3a6 pelp # Character í¦
+U+d3a7 pelh # Character í§
+U+d3a8 pem # Character í¨
+U+d3a9 peb # Character í©
+U+d3aa pebs # Character íª
+U+d3ab pes # Character í«
+U+d3ac pess # Character í¬
+U+d3ad peng # Character í
+U+d3ae pej # Character í®
+U+d3af pec # Character í¯
+U+d3b0 pek # Character í°
+U+d3b1 pet # Character í±
+U+d3b2 pep # Character í²
+U+d3b3 peh # Character í³
+U+d3b4 pyeo # Character í´
+U+d3b5 pyeog # Character íµ
+U+d3b6 pyeogg # Character í¶
+U+d3b7 pyeogs # Character í·
+U+d3b8 pyeon # Character í¸
+U+d3b9 pyeonj # Character í¹
+U+d3ba pyeonh # Character íº
+U+d3bb pyeod # Character í»
+U+d3bc pyeol # Character í¼
+U+d3bd pyeolg # Character í½
+U+d3be pyeolm # Character í¾
+U+d3bf pyeolb # Character í¿
+U+d3c0 pyeols # Character í
+U+d3c1 pyeolt # Character í
+U+d3c2 pyeolp # Character í
+U+d3c3 pyeolh # Character í
+U+d3c4 pyeom # Character í
+U+d3c5 pyeob # Character í
+U+d3c6 pyeobs # Character í
+U+d3c7 pyeos # Character í
+U+d3c8 pyeoss # Character í
+U+d3c9 pyeong # Character í
+U+d3ca pyeoj # Character í
+U+d3cb pyeoc # Character í
+U+d3cc pyeok # Character í
+U+d3cd pyeot # Character í
+U+d3ce pyeop # Character í
+U+d3cf pyeoh # Character í
+U+d3d0 pye # Character í
+U+d3d1 pyeg # Character í
+U+d3d2 pyegg # Character í
+U+d3d3 pyegs # Character í
+U+d3d4 pyen # Character í
+U+d3d5 pyenj # Character í
+U+d3d6 pyenh # Character í
+U+d3d7 pyed # Character í
+U+d3d8 pyel # Character í
+U+d3d9 pyelg # Character í
+U+d3da pyelm # Character í
+U+d3db pyelb # Character í
+U+d3dc pyels # Character í
+U+d3dd pyelt # Character í
+U+d3de pyelp # Character í
+U+d3df pyelh # Character í
+U+d3e0 pyem # Character í
+U+d3e1 pyeb # Character í¡
+U+d3e2 pyebs # Character í¢
+U+d3e3 pyes # Character í£
+U+d3e4 pyess # Character í¤
+U+d3e5 pyeng # Character í¥
+U+d3e6 pyej # Character í¦
+U+d3e7 pyec # Character í§
+U+d3e8 pyek # Character í¨
+U+d3e9 pyet # Character í©
+U+d3ea pyep # Character íª
+U+d3eb pyeh # Character í«
+U+d3ec po # Character í¬
+U+d3ed pog # Character í
+U+d3ee pogg # Character í®
+U+d3ef pogs # Character í¯
+U+d3f0 pon # Character í°
+U+d3f1 ponj # Character í±
+U+d3f2 ponh # Character í²
+U+d3f3 pod # Character í³
+U+d3f4 pol # Character í´
+U+d3f5 polg # Character íµ
+U+d3f6 polm # Character í¶
+U+d3f7 polb # Character í·
+U+d3f8 pols # Character í¸
+U+d3f9 polt # Character í¹
+U+d3fa polp # Character íº
+U+d3fb polh # Character í»
+U+d3fc pom # Character í¼
+U+d3fd pob # Character í½
+U+d3fe pobs # Character í¾
+U+d3ff pos # Character í¿
diff --git a/resources/chars/ascii/rowd4.trans b/resources/chars/ascii/rowd4.trans
new file mode 100644
index 0000000..c28d51a
--- /dev/null
+++ b/resources/chars/ascii/rowd4.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+d400 poss # Character í
+U+d401 pong # Character í
+U+d402 poj # Character í
+U+d403 poc # Character í
+U+d404 pok # Character í
+U+d405 pot # Character í
+U+d406 pop # Character í
+U+d407 poh # Character í
+U+d408 pwa # Character í
+U+d409 pwag # Character í
+U+d40a pwagg # Character í
+U+d40b pwags # Character í
+U+d40c pwan # Character í
+U+d40d pwanj # Character í
+U+d40e pwanh # Character í
+U+d40f pwad # Character í
+U+d410 pwal # Character í
+U+d411 pwalg # Character í
+U+d412 pwalm # Character í
+U+d413 pwalb # Character í
+U+d414 pwals # Character í
+U+d415 pwalt # Character í
+U+d416 pwalp # Character í
+U+d417 pwalh # Character í
+U+d418 pwam # Character í
+U+d419 pwab # Character í
+U+d41a pwabs # Character í
+U+d41b pwas # Character í
+U+d41c pwass # Character í
+U+d41d pwang # Character í
+U+d41e pwaj # Character í
+U+d41f pwac # Character í
+U+d420 pwak # Character í
+U+d421 pwat # Character í¡
+U+d422 pwap # Character í¢
+U+d423 pwah # Character í£
+U+d424 pwae # Character í¤
+U+d425 pwaeg # Character í¥
+U+d426 pwaegg # Character í¦
+U+d427 pwaegs # Character í§
+U+d428 pwaen # Character í¨
+U+d429 pwaenj # Character í©
+U+d42a pwaenh # Character íª
+U+d42b pwaed # Character í«
+U+d42c pwael # Character í¬
+U+d42d pwaelg # Character í
+U+d42e pwaelm # Character í®
+U+d42f pwaelb # Character í¯
+U+d430 pwaels # Character í°
+U+d431 pwaelt # Character í±
+U+d432 pwaelp # Character í²
+U+d433 pwaelh # Character í³
+U+d434 pwaem # Character í´
+U+d435 pwaeb # Character íµ
+U+d436 pwaebs # Character í¶
+U+d437 pwaes # Character í·
+U+d438 pwaess # Character í¸
+U+d439 pwaeng # Character í¹
+U+d43a pwaej # Character íº
+U+d43b pwaec # Character í»
+U+d43c pwaek # Character í¼
+U+d43d pwaet # Character í½
+U+d43e pwaep # Character í¾
+U+d43f pwaeh # Character í¿
+U+d440 poe # Character í
+U+d441 poeg # Character í
+U+d442 poegg # Character í
+U+d443 poegs # Character í
+U+d444 poen # Character í
+U+d445 poenj # Character í
+U+d446 poenh # Character í
+U+d447 poed # Character í
+U+d448 poel # Character í
+U+d449 poelg # Character í
+U+d44a poelm # Character í
+U+d44b poelb # Character í
+U+d44c poels # Character í
+U+d44d poelt # Character í
+U+d44e poelp # Character í
+U+d44f poelh # Character í
+U+d450 poem # Character í
+U+d451 poeb # Character í
+U+d452 poebs # Character í
+U+d453 poes # Character í
+U+d454 poess # Character í
+U+d455 poeng # Character í
+U+d456 poej # Character í
+U+d457 poec # Character í
+U+d458 poek # Character í
+U+d459 poet # Character í
+U+d45a poep # Character í
+U+d45b poeh # Character í
+U+d45c pyo # Character í
+U+d45d pyog # Character í
+U+d45e pyogg # Character í
+U+d45f pyogs # Character í
+U+d460 pyon # Character í
+U+d461 pyonj # Character í¡
+U+d462 pyonh # Character í¢
+U+d463 pyod # Character í£
+U+d464 pyol # Character í¤
+U+d465 pyolg # Character í¥
+U+d466 pyolm # Character í¦
+U+d467 pyolb # Character í§
+U+d468 pyols # Character í¨
+U+d469 pyolt # Character í©
+U+d46a pyolp # Character íª
+U+d46b pyolh # Character í«
+U+d46c pyom # Character í¬
+U+d46d pyob # Character í
+U+d46e pyobs # Character í®
+U+d46f pyos # Character í¯
+U+d470 pyoss # Character í°
+U+d471 pyong # Character í±
+U+d472 pyoj # Character í²
+U+d473 pyoc # Character í³
+U+d474 pyok # Character í´
+U+d475 pyot # Character íµ
+U+d476 pyop # Character í¶
+U+d477 pyoh # Character í·
+U+d478 pu # Character í¸
+U+d479 pug # Character í¹
+U+d47a pugg # Character íº
+U+d47b pugs # Character í»
+U+d47c pun # Character í¼
+U+d47d punj # Character í½
+U+d47e punh # Character í¾
+U+d47f pud # Character í¿
+U+d480 pul # Character í
+U+d481 pulg # Character í
+U+d482 pulm # Character í
+U+d483 pulb # Character í
+U+d484 puls # Character í
+U+d485 pult # Character í
+U+d486 pulp # Character í
+U+d487 pulh # Character í
+U+d488 pum # Character í
+U+d489 pub # Character í
+U+d48a pubs # Character í
+U+d48b pus # Character í
+U+d48c puss # Character í
+U+d48d pung # Character í
+U+d48e puj # Character í
+U+d48f puc # Character í
+U+d490 puk # Character í
+U+d491 put # Character í
+U+d492 pup # Character í
+U+d493 puh # Character í
+U+d494 pweo # Character í
+U+d495 pweog # Character í
+U+d496 pweogg # Character í
+U+d497 pweogs # Character í
+U+d498 pweon # Character í
+U+d499 pweonj # Character í
+U+d49a pweonh # Character í
+U+d49b pweod # Character í
+U+d49c pweol # Character í
+U+d49d pweolg # Character í
+U+d49e pweolm # Character í
+U+d49f pweolb # Character í
+U+d4a0 pweols # Character í
+U+d4a1 pweolt # Character í¡
+U+d4a2 pweolp # Character í¢
+U+d4a3 pweolh # Character í£
+U+d4a4 pweom # Character í¤
+U+d4a5 pweob # Character í¥
+U+d4a6 pweobs # Character í¦
+U+d4a7 pweos # Character í§
+U+d4a8 pweoss # Character í¨
+U+d4a9 pweong # Character í©
+U+d4aa pweoj # Character íª
+U+d4ab pweoc # Character í«
+U+d4ac pweok # Character í¬
+U+d4ad pweot # Character í
+U+d4ae pweop # Character í®
+U+d4af pweoh # Character í¯
+U+d4b0 pwe # Character í°
+U+d4b1 pweg # Character í±
+U+d4b2 pwegg # Character í²
+U+d4b3 pwegs # Character í³
+U+d4b4 pwen # Character í´
+U+d4b5 pwenj # Character íµ
+U+d4b6 pwenh # Character í¶
+U+d4b7 pwed # Character í·
+U+d4b8 pwel # Character í¸
+U+d4b9 pwelg # Character í¹
+U+d4ba pwelm # Character íº
+U+d4bb pwelb # Character í»
+U+d4bc pwels # Character í¼
+U+d4bd pwelt # Character í½
+U+d4be pwelp # Character í¾
+U+d4bf pwelh # Character í¿
+U+d4c0 pwem # Character í
+U+d4c1 pweb # Character í
+U+d4c2 pwebs # Character í
+U+d4c3 pwes # Character í
+U+d4c4 pwess # Character í
+U+d4c5 pweng # Character í
+U+d4c6 pwej # Character í
+U+d4c7 pwec # Character í
+U+d4c8 pwek # Character í
+U+d4c9 pwet # Character í
+U+d4ca pwep # Character í
+U+d4cb pweh # Character í
+U+d4cc pwi # Character í
+U+d4cd pwig # Character í
+U+d4ce pwigg # Character í
+U+d4cf pwigs # Character í
+U+d4d0 pwin # Character í
+U+d4d1 pwinj # Character í
+U+d4d2 pwinh # Character í
+U+d4d3 pwid # Character í
+U+d4d4 pwil # Character í
+U+d4d5 pwilg # Character í
+U+d4d6 pwilm # Character í
+U+d4d7 pwilb # Character í
+U+d4d8 pwils # Character í
+U+d4d9 pwilt # Character í
+U+d4da pwilp # Character í
+U+d4db pwilh # Character í
+U+d4dc pwim # Character í
+U+d4dd pwib # Character í
+U+d4de pwibs # Character í
+U+d4df pwis # Character í
+U+d4e0 pwiss # Character í
+U+d4e1 pwing # Character í¡
+U+d4e2 pwij # Character í¢
+U+d4e3 pwic # Character í£
+U+d4e4 pwik # Character í¤
+U+d4e5 pwit # Character í¥
+U+d4e6 pwip # Character í¦
+U+d4e7 pwih # Character í§
+U+d4e8 pyu # Character í¨
+U+d4e9 pyug # Character í©
+U+d4ea pyugg # Character íª
+U+d4eb pyugs # Character í«
+U+d4ec pyun # Character í¬
+U+d4ed pyunj # Character í
+U+d4ee pyunh # Character í®
+U+d4ef pyud # Character í¯
+U+d4f0 pyul # Character í°
+U+d4f1 pyulg # Character í±
+U+d4f2 pyulm # Character í²
+U+d4f3 pyulb # Character í³
+U+d4f4 pyuls # Character í´
+U+d4f5 pyult # Character íµ
+U+d4f6 pyulp # Character í¶
+U+d4f7 pyulh # Character í·
+U+d4f8 pyum # Character í¸
+U+d4f9 pyub # Character í¹
+U+d4fa pyubs # Character íº
+U+d4fb pyus # Character í»
+U+d4fc pyuss # Character í¼
+U+d4fd pyung # Character í½
+U+d4fe pyuj # Character í¾
+U+d4ff pyuc # Character í¿
diff --git a/resources/chars/ascii/rowd5.trans b/resources/chars/ascii/rowd5.trans
new file mode 100644
index 0000000..490567b
--- /dev/null
+++ b/resources/chars/ascii/rowd5.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+d500 pyuk # Character í
+U+d501 pyut # Character í
+U+d502 pyup # Character í
+U+d503 pyuh # Character í
+U+d504 peu # Character í
+U+d505 peug # Character í
+U+d506 peugg # Character í
+U+d507 peugs # Character í
+U+d508 peun # Character í
+U+d509 peunj # Character í
+U+d50a peunh # Character í
+U+d50b peud # Character í
+U+d50c peul # Character í
+U+d50d peulg # Character í
+U+d50e peulm # Character í
+U+d50f peulb # Character í
+U+d510 peuls # Character í
+U+d511 peult # Character í
+U+d512 peulp # Character í
+U+d513 peulh # Character í
+U+d514 peum # Character í
+U+d515 peub # Character í
+U+d516 peubs # Character í
+U+d517 peus # Character í
+U+d518 peuss # Character í
+U+d519 peung # Character í
+U+d51a peuj # Character í
+U+d51b peuc # Character í
+U+d51c peuk # Character í
+U+d51d peut # Character í
+U+d51e peup # Character í
+U+d51f peuh # Character í
+U+d520 pyi # Character í
+U+d521 pyig # Character í¡
+U+d522 pyigg # Character í¢
+U+d523 pyigs # Character í£
+U+d524 pyin # Character í¤
+U+d525 pyinj # Character í¥
+U+d526 pyinh # Character í¦
+U+d527 pyid # Character í§
+U+d528 pyil # Character í¨
+U+d529 pyilg # Character í©
+U+d52a pyilm # Character íª
+U+d52b pyilb # Character í«
+U+d52c pyils # Character í¬
+U+d52d pyilt # Character í
+U+d52e pyilp # Character í®
+U+d52f pyilh # Character í¯
+U+d530 pyim # Character í°
+U+d531 pyib # Character í±
+U+d532 pyibs # Character í²
+U+d533 pyis # Character í³
+U+d534 pyiss # Character í´
+U+d535 pying # Character íµ
+U+d536 pyij # Character í¶
+U+d537 pyic # Character í·
+U+d538 pyik # Character í¸
+U+d539 pyit # Character í¹
+U+d53a pyip # Character íº
+U+d53b pyih # Character í»
+U+d53c pi # Character í¼
+U+d53d pig # Character í½
+U+d53e pigg # Character í¾
+U+d53f pigs # Character í¿
+U+d540 pin # Character í
+U+d541 pinj # Character í
+U+d542 pinh # Character í
+U+d543 pid # Character í
+U+d544 pil # Character í
+U+d545 pilg # Character í
+U+d546 pilm # Character í
+U+d547 pilb # Character í
+U+d548 pils # Character í
+U+d549 pilt # Character í
+U+d54a pilp # Character í
+U+d54b pilh # Character í
+U+d54c pim # Character í
+U+d54d pib # Character í
+U+d54e pibs # Character í
+U+d54f pis # Character í
+U+d550 piss # Character í
+U+d551 ping # Character í
+U+d552 pij # Character í
+U+d553 pic # Character í
+U+d554 pik # Character í
+U+d555 pit # Character í
+U+d556 pip # Character í
+U+d557 pih # Character í
+U+d558 ha # Character í
+U+d559 hag # Character í
+U+d55a hagg # Character í
+U+d55b hags # Character í
+U+d55c han # Character í
+U+d55d hanj # Character í
+U+d55e hanh # Character í
+U+d55f had # Character í
+U+d560 hal # Character í
+U+d561 halg # Character í¡
+U+d562 halm # Character í¢
+U+d563 halb # Character í£
+U+d564 hals # Character í¤
+U+d565 halt # Character í¥
+U+d566 halp # Character í¦
+U+d567 halh # Character í§
+U+d568 ham # Character í¨
+U+d569 hab # Character í©
+U+d56a habs # Character íª
+U+d56b has # Character í«
+U+d56c hass # Character í¬
+U+d56d hang # Character í
+U+d56e haj # Character í®
+U+d56f hac # Character í¯
+U+d570 hak # Character í°
+U+d571 hat # Character í±
+U+d572 hap # Character í²
+U+d573 hah # Character í³
+U+d574 hae # Character í´
+U+d575 haeg # Character íµ
+U+d576 haegg # Character í¶
+U+d577 haegs # Character í·
+U+d578 haen # Character í¸
+U+d579 haenj # Character í¹
+U+d57a haenh # Character íº
+U+d57b haed # Character í»
+U+d57c hael # Character í¼
+U+d57d haelg # Character í½
+U+d57e haelm # Character í¾
+U+d57f haelb # Character í¿
+U+d580 haels # Character í
+U+d581 haelt # Character í
+U+d582 haelp # Character í
+U+d583 haelh # Character í
+U+d584 haem # Character í
+U+d585 haeb # Character í
+U+d586 haebs # Character í
+U+d587 haes # Character í
+U+d588 haess # Character í
+U+d589 haeng # Character í
+U+d58a haej # Character í
+U+d58b haec # Character í
+U+d58c haek # Character í
+U+d58d haet # Character í
+U+d58e haep # Character í
+U+d58f haeh # Character í
+U+d590 hya # Character í
+U+d591 hyag # Character í
+U+d592 hyagg # Character í
+U+d593 hyags # Character í
+U+d594 hyan # Character í
+U+d595 hyanj # Character í
+U+d596 hyanh # Character í
+U+d597 hyad # Character í
+U+d598 hyal # Character í
+U+d599 hyalg # Character í
+U+d59a hyalm # Character í
+U+d59b hyalb # Character í
+U+d59c hyals # Character í
+U+d59d hyalt # Character í
+U+d59e hyalp # Character í
+U+d59f hyalh # Character í
+U+d5a0 hyam # Character í
+U+d5a1 hyab # Character í¡
+U+d5a2 hyabs # Character í¢
+U+d5a3 hyas # Character í£
+U+d5a4 hyass # Character í¤
+U+d5a5 hyang # Character í¥
+U+d5a6 hyaj # Character í¦
+U+d5a7 hyac # Character í§
+U+d5a8 hyak # Character í¨
+U+d5a9 hyat # Character í©
+U+d5aa hyap # Character íª
+U+d5ab hyah # Character í«
+U+d5ac hyae # Character í¬
+U+d5ad hyaeg # Character í
+U+d5ae hyaegg # Character í®
+U+d5af hyaegs # Character í¯
+U+d5b0 hyaen # Character í°
+U+d5b1 hyaenj # Character í±
+U+d5b2 hyaenh # Character í²
+U+d5b3 hyaed # Character í³
+U+d5b4 hyael # Character í´
+U+d5b5 hyaelg # Character íµ
+U+d5b6 hyaelm # Character í¶
+U+d5b7 hyaelb # Character í·
+U+d5b8 hyaels # Character í¸
+U+d5b9 hyaelt # Character í¹
+U+d5ba hyaelp # Character íº
+U+d5bb hyaelh # Character í»
+U+d5bc hyaem # Character í¼
+U+d5bd hyaeb # Character í½
+U+d5be hyaebs # Character í¾
+U+d5bf hyaes # Character í¿
+U+d5c0 hyaess # Character í
+U+d5c1 hyaeng # Character í
+U+d5c2 hyaej # Character í
+U+d5c3 hyaec # Character í
+U+d5c4 hyaek # Character í
+U+d5c5 hyaet # Character í
+U+d5c6 hyaep # Character í
+U+d5c7 hyaeh # Character í
+U+d5c8 heo # Character í
+U+d5c9 heog # Character í
+U+d5ca heogg # Character í
+U+d5cb heogs # Character í
+U+d5cc heon # Character í
+U+d5cd heonj # Character í
+U+d5ce heonh # Character í
+U+d5cf heod # Character í
+U+d5d0 heol # Character í
+U+d5d1 heolg # Character í
+U+d5d2 heolm # Character í
+U+d5d3 heolb # Character í
+U+d5d4 heols # Character í
+U+d5d5 heolt # Character í
+U+d5d6 heolp # Character í
+U+d5d7 heolh # Character í
+U+d5d8 heom # Character í
+U+d5d9 heob # Character í
+U+d5da heobs # Character í
+U+d5db heos # Character í
+U+d5dc heoss # Character í
+U+d5dd heong # Character í
+U+d5de heoj # Character í
+U+d5df heoc # Character í
+U+d5e0 heok # Character í
+U+d5e1 heot # Character í¡
+U+d5e2 heop # Character í¢
+U+d5e3 heoh # Character í£
+U+d5e4 he # Character í¤
+U+d5e5 heg # Character í¥
+U+d5e6 hegg # Character í¦
+U+d5e7 hegs # Character í§
+U+d5e8 hen # Character í¨
+U+d5e9 henj # Character í©
+U+d5ea henh # Character íª
+U+d5eb hed # Character í«
+U+d5ec hel # Character í¬
+U+d5ed helg # Character í
+U+d5ee helm # Character í®
+U+d5ef helb # Character í¯
+U+d5f0 hels # Character í°
+U+d5f1 helt # Character í±
+U+d5f2 help # Character í²
+U+d5f3 helh # Character í³
+U+d5f4 hem # Character í´
+U+d5f5 heb # Character íµ
+U+d5f6 hebs # Character í¶
+U+d5f7 hes # Character í·
+U+d5f8 hess # Character í¸
+U+d5f9 heng # Character í¹
+U+d5fa hej # Character íº
+U+d5fb hec # Character í»
+U+d5fc hek # Character í¼
+U+d5fd het # Character í½
+U+d5fe hep # Character í¾
+U+d5ff heh # Character í¿
diff --git a/resources/chars/ascii/rowd6.trans b/resources/chars/ascii/rowd6.trans
new file mode 100644
index 0000000..b1368e4
--- /dev/null
+++ b/resources/chars/ascii/rowd6.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+d600 hyeo # Character í
+U+d601 hyeog # Character í
+U+d602 hyeogg # Character í
+U+d603 hyeogs # Character í
+U+d604 hyeon # Character í
+U+d605 hyeonj # Character í
+U+d606 hyeonh # Character í
+U+d607 hyeod # Character í
+U+d608 hyeol # Character í
+U+d609 hyeolg # Character í
+U+d60a hyeolm # Character í
+U+d60b hyeolb # Character í
+U+d60c hyeols # Character í
+U+d60d hyeolt # Character í
+U+d60e hyeolp # Character í
+U+d60f hyeolh # Character í
+U+d610 hyeom # Character í
+U+d611 hyeob # Character í
+U+d612 hyeobs # Character í
+U+d613 hyeos # Character í
+U+d614 hyeoss # Character í
+U+d615 hyeong # Character í
+U+d616 hyeoj # Character í
+U+d617 hyeoc # Character í
+U+d618 hyeok # Character í
+U+d619 hyeot # Character í
+U+d61a hyeop # Character í
+U+d61b hyeoh # Character í
+U+d61c hye # Character í
+U+d61d hyeg # Character í
+U+d61e hyegg # Character í
+U+d61f hyegs # Character í
+U+d620 hyen # Character í
+U+d621 hyenj # Character í¡
+U+d622 hyenh # Character í¢
+U+d623 hyed # Character í£
+U+d624 hyel # Character í¤
+U+d625 hyelg # Character í¥
+U+d626 hyelm # Character í¦
+U+d627 hyelb # Character í§
+U+d628 hyels # Character í¨
+U+d629 hyelt # Character í©
+U+d62a hyelp # Character íª
+U+d62b hyelh # Character í«
+U+d62c hyem # Character í¬
+U+d62d hyeb # Character í
+U+d62e hyebs # Character í®
+U+d62f hyes # Character í¯
+U+d630 hyess # Character í°
+U+d631 hyeng # Character í±
+U+d632 hyej # Character í²
+U+d633 hyec # Character í³
+U+d634 hyek # Character í´
+U+d635 hyet # Character íµ
+U+d636 hyep # Character í¶
+U+d637 hyeh # Character í·
+U+d638 ho # Character í¸
+U+d639 hog # Character í¹
+U+d63a hogg # Character íº
+U+d63b hogs # Character í»
+U+d63c hon # Character í¼
+U+d63d honj # Character í½
+U+d63e honh # Character í¾
+U+d63f hod # Character í¿
+U+d640 hol # Character í
+U+d641 holg # Character í
+U+d642 holm # Character í
+U+d643 holb # Character í
+U+d644 hols # Character í
+U+d645 holt # Character í
+U+d646 holp # Character í
+U+d647 holh # Character í
+U+d648 hom # Character í
+U+d649 hob # Character í
+U+d64a hobs # Character í
+U+d64b hos # Character í
+U+d64c hoss # Character í
+U+d64d hong # Character í
+U+d64e hoj # Character í
+U+d64f hoc # Character í
+U+d650 hok # Character í
+U+d651 hot # Character í
+U+d652 hop # Character í
+U+d653 hoh # Character í
+U+d654 hwa # Character í
+U+d655 hwag # Character í
+U+d656 hwagg # Character í
+U+d657 hwags # Character í
+U+d658 hwan # Character í
+U+d659 hwanj # Character í
+U+d65a hwanh # Character í
+U+d65b hwad # Character í
+U+d65c hwal # Character í
+U+d65d hwalg # Character í
+U+d65e hwalm # Character í
+U+d65f hwalb # Character í
+U+d660 hwals # Character í
+U+d661 hwalt # Character í¡
+U+d662 hwalp # Character í¢
+U+d663 hwalh # Character í£
+U+d664 hwam # Character í¤
+U+d665 hwab # Character í¥
+U+d666 hwabs # Character í¦
+U+d667 hwas # Character í§
+U+d668 hwass # Character í¨
+U+d669 hwang # Character í©
+U+d66a hwaj # Character íª
+U+d66b hwac # Character í«
+U+d66c hwak # Character í¬
+U+d66d hwat # Character í
+U+d66e hwap # Character í®
+U+d66f hwah # Character í¯
+U+d670 hwae # Character í°
+U+d671 hwaeg # Character í±
+U+d672 hwaegg # Character í²
+U+d673 hwaegs # Character í³
+U+d674 hwaen # Character í´
+U+d675 hwaenj # Character íµ
+U+d676 hwaenh # Character í¶
+U+d677 hwaed # Character í·
+U+d678 hwael # Character í¸
+U+d679 hwaelg # Character í¹
+U+d67a hwaelm # Character íº
+U+d67b hwaelb # Character í»
+U+d67c hwaels # Character í¼
+U+d67d hwaelt # Character í½
+U+d67e hwaelp # Character í¾
+U+d67f hwaelh # Character í¿
+U+d680 hwaem # Character í
+U+d681 hwaeb # Character í
+U+d682 hwaebs # Character í
+U+d683 hwaes # Character í
+U+d684 hwaess # Character í
+U+d685 hwaeng # Character í
+U+d686 hwaej # Character í
+U+d687 hwaec # Character í
+U+d688 hwaek # Character í
+U+d689 hwaet # Character í
+U+d68a hwaep # Character í
+U+d68b hwaeh # Character í
+U+d68c hoe # Character í
+U+d68d hoeg # Character í
+U+d68e hoegg # Character í
+U+d68f hoegs # Character í
+U+d690 hoen # Character í
+U+d691 hoenj # Character í
+U+d692 hoenh # Character í
+U+d693 hoed # Character í
+U+d694 hoel # Character í
+U+d695 hoelg # Character í
+U+d696 hoelm # Character í
+U+d697 hoelb # Character í
+U+d698 hoels # Character í
+U+d699 hoelt # Character í
+U+d69a hoelp # Character í
+U+d69b hoelh # Character í
+U+d69c hoem # Character í
+U+d69d hoeb # Character í
+U+d69e hoebs # Character í
+U+d69f hoes # Character í
+U+d6a0 hoess # Character í
+U+d6a1 hoeng # Character í¡
+U+d6a2 hoej # Character í¢
+U+d6a3 hoec # Character í£
+U+d6a4 hoek # Character í¤
+U+d6a5 hoet # Character í¥
+U+d6a6 hoep # Character í¦
+U+d6a7 hoeh # Character í§
+U+d6a8 hyo # Character í¨
+U+d6a9 hyog # Character í©
+U+d6aa hyogg # Character íª
+U+d6ab hyogs # Character í«
+U+d6ac hyon # Character í¬
+U+d6ad hyonj # Character í
+U+d6ae hyonh # Character í®
+U+d6af hyod # Character í¯
+U+d6b0 hyol # Character í°
+U+d6b1 hyolg # Character í±
+U+d6b2 hyolm # Character í²
+U+d6b3 hyolb # Character í³
+U+d6b4 hyols # Character í´
+U+d6b5 hyolt # Character íµ
+U+d6b6 hyolp # Character í¶
+U+d6b7 hyolh # Character í·
+U+d6b8 hyom # Character í¸
+U+d6b9 hyob # Character í¹
+U+d6ba hyobs # Character íº
+U+d6bb hyos # Character í»
+U+d6bc hyoss # Character í¼
+U+d6bd hyong # Character í½
+U+d6be hyoj # Character í¾
+U+d6bf hyoc # Character í¿
+U+d6c0 hyok # Character í
+U+d6c1 hyot # Character í
+U+d6c2 hyop # Character í
+U+d6c3 hyoh # Character í
+U+d6c4 hu # Character í
+U+d6c5 hug # Character í
+U+d6c6 hugg # Character í
+U+d6c7 hugs # Character í
+U+d6c8 hun # Character í
+U+d6c9 hunj # Character í
+U+d6ca hunh # Character í
+U+d6cb hud # Character í
+U+d6cc hul # Character í
+U+d6cd hulg # Character í
+U+d6ce hulm # Character í
+U+d6cf hulb # Character í
+U+d6d0 huls # Character í
+U+d6d1 hult # Character í
+U+d6d2 hulp # Character í
+U+d6d3 hulh # Character í
+U+d6d4 hum # Character í
+U+d6d5 hub # Character í
+U+d6d6 hubs # Character í
+U+d6d7 hus # Character í
+U+d6d8 huss # Character í
+U+d6d9 hung # Character í
+U+d6da huj # Character í
+U+d6db huc # Character í
+U+d6dc huk # Character í
+U+d6dd hut # Character í
+U+d6de hup # Character í
+U+d6df huh # Character í
+U+d6e0 hweo # Character í
+U+d6e1 hweog # Character í¡
+U+d6e2 hweogg # Character í¢
+U+d6e3 hweogs # Character í£
+U+d6e4 hweon # Character í¤
+U+d6e5 hweonj # Character í¥
+U+d6e6 hweonh # Character í¦
+U+d6e7 hweod # Character í§
+U+d6e8 hweol # Character í¨
+U+d6e9 hweolg # Character í©
+U+d6ea hweolm # Character íª
+U+d6eb hweolb # Character í«
+U+d6ec hweols # Character í¬
+U+d6ed hweolt # Character í
+U+d6ee hweolp # Character í®
+U+d6ef hweolh # Character í¯
+U+d6f0 hweom # Character í°
+U+d6f1 hweob # Character í±
+U+d6f2 hweobs # Character í²
+U+d6f3 hweos # Character í³
+U+d6f4 hweoss # Character í´
+U+d6f5 hweong # Character íµ
+U+d6f6 hweoj # Character í¶
+U+d6f7 hweoc # Character í·
+U+d6f8 hweok # Character í¸
+U+d6f9 hweot # Character í¹
+U+d6fa hweop # Character íº
+U+d6fb hweoh # Character í»
+U+d6fc hwe # Character í¼
+U+d6fd hweg # Character í½
+U+d6fe hwegg # Character í¾
+U+d6ff hwegs # Character í¿
diff --git a/resources/chars/ascii/rowd7.trans b/resources/chars/ascii/rowd7.trans
new file mode 100644
index 0000000..8340e16
--- /dev/null
+++ b/resources/chars/ascii/rowd7.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+d700 hwen # Character í
+U+d701 hwenj # Character í
+U+d702 hwenh # Character í
+U+d703 hwed # Character í
+U+d704 hwel # Character í
+U+d705 hwelg # Character í
+U+d706 hwelm # Character í
+U+d707 hwelb # Character í
+U+d708 hwels # Character í
+U+d709 hwelt # Character í
+U+d70a hwelp # Character í
+U+d70b hwelh # Character í
+U+d70c hwem # Character í
+U+d70d hweb # Character í
+U+d70e hwebs # Character í
+U+d70f hwes # Character í
+U+d710 hwess # Character í
+U+d711 hweng # Character í
+U+d712 hwej # Character í
+U+d713 hwec # Character í
+U+d714 hwek # Character í
+U+d715 hwet # Character í
+U+d716 hwep # Character í
+U+d717 hweh # Character í
+U+d718 hwi # Character í
+U+d719 hwig # Character í
+U+d71a hwigg # Character í
+U+d71b hwigs # Character í
+U+d71c hwin # Character í
+U+d71d hwinj # Character í
+U+d71e hwinh # Character í
+U+d71f hwid # Character í
+U+d720 hwil # Character í
+U+d721 hwilg # Character í¡
+U+d722 hwilm # Character í¢
+U+d723 hwilb # Character í£
+U+d724 hwils # Character í¤
+U+d725 hwilt # Character í¥
+U+d726 hwilp # Character í¦
+U+d727 hwilh # Character í§
+U+d728 hwim # Character í¨
+U+d729 hwib # Character í©
+U+d72a hwibs # Character íª
+U+d72b hwis # Character í«
+U+d72c hwiss # Character í¬
+U+d72d hwing # Character í
+U+d72e hwij # Character í®
+U+d72f hwic # Character í¯
+U+d730 hwik # Character í°
+U+d731 hwit # Character í±
+U+d732 hwip # Character í²
+U+d733 hwih # Character í³
+U+d734 hyu # Character í´
+U+d735 hyug # Character íµ
+U+d736 hyugg # Character í¶
+U+d737 hyugs # Character í·
+U+d738 hyun # Character í¸
+U+d739 hyunj # Character í¹
+U+d73a hyunh # Character íº
+U+d73b hyud # Character í»
+U+d73c hyul # Character í¼
+U+d73d hyulg # Character í½
+U+d73e hyulm # Character í¾
+U+d73f hyulb # Character í¿
+U+d740 hyuls # Character í
+U+d741 hyult # Character í
+U+d742 hyulp # Character í
+U+d743 hyulh # Character í
+U+d744 hyum # Character í
+U+d745 hyub # Character í
+U+d746 hyubs # Character í
+U+d747 hyus # Character í
+U+d748 hyuss # Character í
+U+d749 hyung # Character í
+U+d74a hyuj # Character í
+U+d74b hyuc # Character í
+U+d74c hyuk # Character í
+U+d74d hyut # Character í
+U+d74e hyup # Character í
+U+d74f hyuh # Character í
+U+d750 heu # Character í
+U+d751 heug # Character í
+U+d752 heugg # Character í
+U+d753 heugs # Character í
+U+d754 heun # Character í
+U+d755 heunj # Character í
+U+d756 heunh # Character í
+U+d757 heud # Character í
+U+d758 heul # Character í
+U+d759 heulg # Character í
+U+d75a heulm # Character í
+U+d75b heulb # Character í
+U+d75c heuls # Character í
+U+d75d heult # Character í
+U+d75e heulp # Character í
+U+d75f heulh # Character í
+U+d760 heum # Character í
+U+d761 heub # Character í¡
+U+d762 heubs # Character í¢
+U+d763 heus # Character í£
+U+d764 heuss # Character í¤
+U+d765 heung # Character í¥
+U+d766 heuj # Character í¦
+U+d767 heuc # Character í§
+U+d768 heuk # Character í¨
+U+d769 heut # Character í©
+U+d76a heup # Character íª
+U+d76b heuh # Character í«
+U+d76c hyi # Character í¬
+U+d76d hyig # Character í
+U+d76e hyigg # Character í®
+U+d76f hyigs # Character í¯
+U+d770 hyin # Character í°
+U+d771 hyinj # Character í±
+U+d772 hyinh # Character í²
+U+d773 hyid # Character í³
+U+d774 hyil # Character í´
+U+d775 hyilg # Character íµ
+U+d776 hyilm # Character í¶
+U+d777 hyilb # Character í·
+U+d778 hyils # Character í¸
+U+d779 hyilt # Character í¹
+U+d77a hyilp # Character íº
+U+d77b hyilh # Character í»
+U+d77c hyim # Character í¼
+U+d77d hyib # Character í½
+U+d77e hyibs # Character í¾
+U+d77f hyis # Character í¿
+U+d780 hyiss # Character í
+U+d781 hying # Character í
+U+d782 hyij # Character í
+U+d783 hyic # Character í
+U+d784 hyik # Character í
+U+d785 hyit # Character í
+U+d786 hyip # Character í
+U+d787 hyih # Character í
+U+d788 hi # Character í
+U+d789 hig # Character í
+U+d78a higg # Character í
+U+d78b higs # Character í
+U+d78c hin # Character í
+U+d78d hinj # Character í
+U+d78e hinh # Character í
+U+d78f hid # Character í
+U+d790 hil # Character í
+U+d791 hilg # Character í
+U+d792 hilm # Character í
+U+d793 hilb # Character í
+U+d794 hils # Character í
+U+d795 hilt # Character í
+U+d796 hilp # Character í
+U+d797 hilh # Character í
+U+d798 him # Character í
+U+d799 hib # Character í
+U+d79a hibs # Character í
+U+d79b his # Character í
+U+d79c hiss # Character í
+U+d79d hing # Character í
+U+d79e hij # Character í
+U+d79f hic # Character í
+U+d7a0 hik # Character í
+U+d7a1 hit # Character í¡
+U+d7a2 hip # Character í¢
+U+d7a3 hih # Character í£
+U+d7a4 ? # Character í¤
+U+d7a5 ? # Character í¥
+U+d7a6 ? # Character í¦
+U+d7a7 ? # Character í§
+U+d7a8 ? # Character í¨
+U+d7a9 ? # Character í©
+U+d7aa ? # Character íª
+U+d7ab ? # Character í«
+U+d7ac ? # Character í¬
+U+d7ad ? # Character í
+U+d7ae ? # Character í®
+U+d7af ? # Character í¯
+U+d7b0 ? # Character í°
+U+d7b1 ? # Character í±
+U+d7b2 ? # Character í²
+U+d7b3 ? # Character í³
+U+d7b4 ? # Character í´
+U+d7b5 ? # Character íµ
+U+d7b6 ? # Character í¶
+U+d7b7 ? # Character í·
+U+d7b8 ? # Character í¸
+U+d7b9 ? # Character í¹
+U+d7ba ? # Character íº
+U+d7bb ? # Character í»
+U+d7bc ? # Character í¼
+U+d7bd ? # Character í½
+U+d7be ? # Character í¾
+U+d7bf ? # Character í¿
+U+d7c0 ? # Character í
+U+d7c1 ? # Character í
+U+d7c2 ? # Character í
+U+d7c3 ? # Character í
+U+d7c4 ? # Character í
+U+d7c5 ? # Character í
+U+d7c6 ? # Character í
+U+d7c7 ? # Character í
+U+d7c8 ? # Character í
+U+d7c9 ? # Character í
+U+d7ca ? # Character í
+U+d7cb ? # Character í
+U+d7cc ? # Character í
+U+d7cd ? # Character í
+U+d7ce ? # Character í
+U+d7cf ? # Character í
+U+d7d0 ? # Character í
+U+d7d1 ? # Character í
+U+d7d2 ? # Character í
+U+d7d3 ? # Character í
+U+d7d4 ? # Character í
+U+d7d5 ? # Character í
+U+d7d6 ? # Character í
+U+d7d7 ? # Character í
+U+d7d8 ? # Character í
+U+d7d9 ? # Character í
+U+d7da ? # Character í
+U+d7db ? # Character í
+U+d7dc ? # Character í
+U+d7dd ? # Character í
+U+d7de ? # Character í
+U+d7df ? # Character í
+U+d7e0 ? # Character í
+U+d7e1 ? # Character í¡
+U+d7e2 ? # Character í¢
+U+d7e3 ? # Character í£
+U+d7e4 ? # Character í¤
+U+d7e5 ? # Character í¥
+U+d7e6 ? # Character í¦
+U+d7e7 ? # Character í§
+U+d7e8 ? # Character í¨
+U+d7e9 ? # Character í©
+U+d7ea ? # Character íª
+U+d7eb ? # Character í«
+U+d7ec ? # Character í¬
+U+d7ed ? # Character í
+U+d7ee ? # Character í®
+U+d7ef ? # Character í¯
+U+d7f0 ? # Character í°
+U+d7f1 ? # Character í±
+U+d7f2 ? # Character í²
+U+d7f3 ? # Character í³
+U+d7f4 ? # Character í´
+U+d7f5 ? # Character íµ
+U+d7f6 ? # Character í¶
+U+d7f7 ? # Character í·
+U+d7f8 ? # Character í¸
+U+d7f9 ? # Character í¹
+U+d7fa ? # Character íº
+U+d7fb ? # Character í»
+U+d7fc ? # Character í¼
+U+d7fd ? # Character í½
+U+d7fe ? # Character í¾
+U+d7ff ? # Character í¿
diff --git a/resources/chars/ascii/rowf9.trans b/resources/chars/ascii/rowf9.trans
new file mode 100644
index 0000000..1b0068e
--- /dev/null
+++ b/resources/chars/ascii/rowf9.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+f900 Kay # Character ï¤
+U+f901 Kayng # Character ï¤
+U+f902 Ke # Character ï¤
+U+f903 Ko # Character ï¤
+U+f904 Kol # Character ï¤
+U+f905 Koc # Character ï¤
+U+f906 Kwi # Character ï¤
+U+f907 Kwi # Character ï¤
+U+f908 Kyun # Character ï¤
+U+f909 Kul # Character ï¤
+U+f90a Kum # Character ï¤
+U+f90b Na # Character ï¤
+U+f90c Na # Character ï¤
+U+f90d Na # Character ï¤
+U+f90e La # Character ï¤
+U+f90f Na # Character ï¤
+U+f910 Na # Character ï¤
+U+f911 Na # Character ï¤
+U+f912 Na # Character ï¤
+U+f913 Na # Character ï¤
+U+f914 Nak # Character ï¤
+U+f915 Nak # Character ï¤
+U+f916 Nak # Character ï¤
+U+f917 Nak # Character ï¤
+U+f918 Nak # Character ï¤
+U+f919 Nak # Character ï¤
+U+f91a Nak # Character ï¤
+U+f91b Nan # Character ï¤
+U+f91c Nan # Character ï¤
+U+f91d Nan # Character ï¤
+U+f91e Nan # Character ï¤
+U+f91f Nan # Character ï¤
+U+f920 Nan # Character ï¤
+U+f921 Nam # Character 嵐
+U+f922 Nam # Character 濫
+U+f923 Nam # Character 藍
+U+f924 Nam # Character 襤
+U+f925 Nap # Character 拉
+U+f926 Nap # Character 臘
+U+f927 Nap # Character 蠟
+U+f928 Nang # Character 廊
+U+f929 Nang # Character 朗
+U+f92a Nang # Character 浪
+U+f92b Nang # Character 狼
+U+f92c Nang # Character 郎
+U+f92d Nay # Character ï¤
+U+f92e Nayng # Character 冷
+U+f92f No # Character 勞
+U+f930 No # Character 擄
+U+f931 No # Character 櫓
+U+f932 No # Character 爐
+U+f933 No # Character 盧
+U+f934 No # Character 老
+U+f935 No # Character 蘆
+U+f936 No # Character 虜
+U+f937 No # Character 路
+U+f938 No # Character 露
+U+f939 No # Character 魯
+U+f93a No # Character 鷺
+U+f93b Nok # Character 碌
+U+f93c Nok # Character 祿
+U+f93d Nok # Character 綠
+U+f93e Nok # Character 菉
+U+f93f Nok # Character 錄
+U+f940 Nok # Character ï¥
+U+f941 Non # Character ï¥
+U+f942 Nong # Character ï¥
+U+f943 Nong # Character ï¥
+U+f944 Nong # Character ï¥
+U+f945 Nong # Character ï¥
+U+f946 Noy # Character ï¥
+U+f947 Noy # Character ï¥
+U+f948 Noy # Character ï¥
+U+f949 Noy # Character ï¥
+U+f94a Nwu # Character ï¥
+U+f94b Nwu # Character ï¥
+U+f94c Nwu # Character ï¥
+U+f94d Nwu # Character ï¥
+U+f94e Nwu # Character ï¥
+U+f94f Nwu # Character ï¥
+U+f950 Nwu # Character ï¥
+U+f951 Nwu # Character ï¥
+U+f952 Nuk # Character ï¥
+U+f953 Nuk # Character ï¥
+U+f954 Num # Character ï¥
+U+f955 Nung # Character ï¥
+U+f956 Nung # Character ï¥
+U+f957 Nung # Character ï¥
+U+f958 Nung # Character ï¥
+U+f959 Nung # Character ï¥
+U+f95a Twu # Character ï¥
+U+f95b La # Character ï¥
+U+f95c Lak # Character ï¥
+U+f95d Lak # Character ï¥
+U+f95e Lan # Character ï¥
+U+f95f Lyeng # Character ï¥
+U+f960 Lo # Character ï¥
+U+f961 Lyul # Character 率
+U+f962 Li # Character 異
+U+f963 Pey # Character 北
+U+f964 Pen # Character 磻
+U+f965 Pyen # Character 便
+U+f966 Pwu # Character 復
+U+f967 Pwul # Character 不
+U+f968 Pi # Character 泌
+U+f969 Sak # Character 數
+U+f96a Sak # Character 索
+U+f96b Sam # Character 參
+U+f96c Sayk # Character 塞
+U+f96d Sayng # Character ï¥
+U+f96e Sep # Character 葉
+U+f96f Sey # Character 說
+U+f970 Sway # Character 殺
+U+f971 Sin # Character 辰
+U+f972 Sim # Character 沈
+U+f973 Sip # Character 拾
+U+f974 Ya # Character 若
+U+f975 Yak # Character 掠
+U+f976 Yak # Character 略
+U+f977 Yang # Character 亮
+U+f978 Yang # Character 兩
+U+f979 Yang # Character 凉
+U+f97a Yang # Character 梁
+U+f97b Yang # Character 糧
+U+f97c Yang # Character 良
+U+f97d Yang # Character 諒
+U+f97e Yang # Character 量
+U+f97f Ye # Character 勵
+U+f980 Ye # Character ï¦
+U+f981 Ye # Character ï¦
+U+f982 Ye # Character ï¦
+U+f983 Ye # Character ï¦
+U+f984 Ye # Character ï¦
+U+f985 Ye # Character ï¦
+U+f986 Ye # Character ï¦
+U+f987 Ye # Character ï¦
+U+f988 Ye # Character ï¦
+U+f989 Ye # Character ï¦
+U+f98a Yek # Character ï¦
+U+f98b Yek # Character ï¦
+U+f98c Yek # Character ï¦
+U+f98d Yek # Character ï¦
+U+f98e Yen # Character ï¦
+U+f98f Yen # Character ï¦
+U+f990 Yen # Character ï¦
+U+f991 Yen # Character ï¦
+U+f992 Yen # Character ï¦
+U+f993 Yen # Character ï¦
+U+f994 Yen # Character ï¦
+U+f995 Yen # Character ï¦
+U+f996 Yen # Character ï¦
+U+f997 Yen # Character ï¦
+U+f998 Yen # Character ï¦
+U+f999 Yen # Character ï¦
+U+f99a Yen # Character ï¦
+U+f99b Yen # Character ï¦
+U+f99c Yel # Character ï¦
+U+f99d Yel # Character ï¦
+U+f99e Yel # Character ï¦
+U+f99f Yel # Character ï¦
+U+f9a0 Yel # Character ï¦
+U+f9a1 Yel # Character 說
+U+f9a2 Yem # Character 廉
+U+f9a3 Yem # Character 念
+U+f9a4 Yem # Character 捻
+U+f9a5 Yem # Character 殮
+U+f9a6 Yem # Character 簾
+U+f9a7 Yep # Character 獵
+U+f9a8 Yeng # Character 令
+U+f9a9 Yeng # Character 囹
+U+f9aa Yeng # Character 寧
+U+f9ab Yeng # Character 嶺
+U+f9ac Yeng # Character 怜
+U+f9ad Yeng # Character ï¦
+U+f9ae Yeng # Character 瑩
+U+f9af Yeng # Character 羚
+U+f9b0 Yeng # Character 聆
+U+f9b1 Yeng # Character 鈴
+U+f9b2 Yeng # Character 零
+U+f9b3 Yeng # Character 靈
+U+f9b4 Yeng # Character 領
+U+f9b5 Yey # Character 例
+U+f9b6 Yey # Character 禮
+U+f9b7 Yey # Character 醴
+U+f9b8 Yey # Character 隸
+U+f9b9 O # Character 惡
+U+f9ba Yo # Character 了
+U+f9bb Yo # Character 僚
+U+f9bc Yo # Character 寮
+U+f9bd Yo # Character 尿
+U+f9be Yo # Character 料
+U+f9bf Yo # Character 樂
+U+f9c0 Yo # Character ï§
+U+f9c1 Yo # Character ï§
+U+f9c2 Yo # Character ï§
+U+f9c3 Yo # Character ï§
+U+f9c4 Yong # Character ï§
+U+f9c5 Wun # Character ï§
+U+f9c6 Wen # Character ï§
+U+f9c7 Yu # Character ï§
+U+f9c8 Yu # Character ï§
+U+f9c9 Yu # Character ï§
+U+f9ca Yu # Character ï§
+U+f9cb Yu # Character ï§
+U+f9cc Yu # Character ï§
+U+f9cd Yu # Character ï§
+U+f9ce Yu # Character ï§
+U+f9cf Yu # Character ï§
+U+f9d0 Yu # Character ï§
+U+f9d1 Yuk # Character ï§
+U+f9d2 Yuk # Character ï§
+U+f9d3 Yuk # Character ï§
+U+f9d4 Yun # Character ï§
+U+f9d5 Yun # Character ï§
+U+f9d6 Yun # Character ï§
+U+f9d7 Yun # Character ï§
+U+f9d8 Yul # Character ï§
+U+f9d9 Yul # Character ï§
+U+f9da Yul # Character ï§
+U+f9db Yul # Character ï§
+U+f9dc Yung # Character ï§
+U+f9dd I # Character ï§
+U+f9de I # Character ï§
+U+f9df I # Character ï§
+U+f9e0 I # Character ï§
+U+f9e1 I # Character 李
+U+f9e2 I # Character 梨
+U+f9e3 I # Character 泥
+U+f9e4 I # Character 理
+U+f9e5 I # Character 痢
+U+f9e6 I # Character 罹
+U+f9e7 I # Character 裏
+U+f9e8 I # Character 裡
+U+f9e9 I # Character 里
+U+f9ea I # Character 離
+U+f9eb Ik # Character 匿
+U+f9ec Ik # Character 溺
+U+f9ed In # Character ï§
+U+f9ee In # Character 燐
+U+f9ef In # Character 璘
+U+f9f0 In # Character 藺
+U+f9f1 In # Character 隣
+U+f9f2 In # Character 鱗
+U+f9f3 In # Character 麟
+U+f9f4 Im # Character 林
+U+f9f5 Im # Character 淋
+U+f9f6 Im # Character 臨
+U+f9f7 Ip # Character 立
+U+f9f8 Ip # Character 笠
+U+f9f9 Ip # Character 粒
+U+f9fa Cang # Character 狀
+U+f9fb Cek # Character 炙
+U+f9fc Ci # Character 識
+U+f9fd Cip # Character 什
+U+f9fe Cha # Character 茶
+U+f9ff Chek # Character 刺
diff --git a/resources/chars/ascii/rowfa.trans b/resources/chars/ascii/rowfa.trans
new file mode 100644
index 0000000..5b48bde
--- /dev/null
+++ b/resources/chars/ascii/rowfa.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+fa00 Chey # Character ï¨
+U+fa01 Thak # Character ï¨
+U+fa02 Thak # Character ï¨
+U+fa03 Thang # Character ï¨
+U+fa04 Thayk # Character ï¨
+U+fa05 Thong # Character ï¨
+U+fa06 Pho # Character ï¨
+U+fa07 Phok # Character ï¨
+U+fa08 Hang # Character ï¨
+U+fa09 Hang # Character ï¨
+U+fa0a Hyen # Character ï¨
+U+fa0b Hwak # Character ï¨
+U+fa0c Wu # Character ï¨
+U+fa0d Huo # Character ï¨
+U+fa0e ? # Character ï¨
+U+fa0f ? # Character ï¨
+U+fa10 Zhong # Character ï¨
+U+fa11 ? # Character ï¨
+U+fa12 Qing # Character ï¨
+U+fa13 ? # Character ï¨
+U+fa14 ? # Character ï¨
+U+fa15 Xi # Character ï¨
+U+fa16 Zhu # Character ï¨
+U+fa17 Yi # Character ï¨
+U+fa18 Li # Character ï¨
+U+fa19 Shen # Character ï¨
+U+fa1a Xiang # Character ï¨
+U+fa1b Fu # Character ï¨
+U+fa1c Jing # Character ï¨
+U+fa1d Jing # Character ï¨
+U+fa1e Yu # Character ï¨
+U+fa1f ? # Character ï¨
+U+fa20 Hagi # Character ï¨
+U+fa21 ? # Character 﨡
+U+fa22 Zhu # Character 諸
+U+fa23 ? # Character 﨣
+U+fa24 ? # Character 﨤
+U+fa25 Yi # Character 逸
+U+fa26 Du # Character 都
+U+fa27 ? # Character 﨧
+U+fa28 ? # Character 﨨
+U+fa29 ? # Character 﨩
+U+fa2a Fan # Character 飯
+U+fa2b Si # Character 飼
+U+fa2c Guan # Character 館
+U+fa2d ? # Character ï¨
+U+fa2e ? # Character 郞
+U+fa2f ? # Character 隷
+U+fa30 ? # Character 侮
+U+fa31 ? # Character 僧
+U+fa32 ? # Character 免
+U+fa33 ? # Character 勉
+U+fa34 ? # Character 勤
+U+fa35 ? # Character 卑
+U+fa36 ? # Character 喝
+U+fa37 ? # Character 嘆
+U+fa38 ? # Character 器
+U+fa39 ? # Character 塀
+U+fa3a ? # Character 墨
+U+fa3b ? # Character 層
+U+fa3c ? # Character 屮
+U+fa3d ? # Character 悔
+U+fa3e ? # Character 慨
+U+fa3f ? # Character 憎
+U+fa40 ? # Character ï©
+U+fa41 ? # Character ï©
+U+fa42 ? # Character ï©
+U+fa43 ? # Character ï©
+U+fa44 ? # Character ï©
+U+fa45 ? # Character ï©
+U+fa46 ? # Character ï©
+U+fa47 ? # Character ï©
+U+fa48 ? # Character ï©
+U+fa49 ? # Character ï©
+U+fa4a ? # Character ï©
+U+fa4b ? # Character ï©
+U+fa4c ? # Character ï©
+U+fa4d ? # Character ï©
+U+fa4e ? # Character ï©
+U+fa4f ? # Character ï©
+U+fa50 ? # Character ï©
+U+fa51 ? # Character ï©
+U+fa52 ? # Character ï©
+U+fa53 ? # Character ï©
+U+fa54 ? # Character ï©
+U+fa55 ? # Character ï©
+U+fa56 ? # Character ï©
+U+fa57 ? # Character ï©
+U+fa58 ? # Character ï©
+U+fa59 ? # Character ï©
+U+fa5a ? # Character ï©
+U+fa5b ? # Character ï©
+U+fa5c ? # Character ï©
+U+fa5d ? # Character ï©
+U+fa5e ? # Character ï©
+U+fa5f ? # Character ï©
+U+fa60 ? # Character ï©
+U+fa61 ? # Character ï©¡
+U+fa62 ? # Character ï©¢
+U+fa63 ? # Character ï©£
+U+fa64 ? # Character 賓
+U+fa65 ? # Character ï©¥
+U+fa66 ? # Character 辶
+U+fa67 ? # Character 逸
+U+fa68 ? # Character 難
+U+fa69 ? # Character ï©©
+U+fa6a ? # Character 頻
+U+fa6b ? # Character ï©«
+U+fa6c ? # Character 𤋮
+U+fa6d ? # Character ï©
+U+fa6e ? # Character ï©®
+U+fa6f ? # Character 﩯
+U+fa70 ? # Character ï©°
+U+fa71 ? # Character 况
+U+fa72 ? # Character 全
+U+fa73 ? # Character 侀
+U+fa74 ? # Character ï©´
+U+fa75 ? # Character 冀
+U+fa76 ? # Character 勇
+U+fa77 ? # Character ï©·
+U+fa78 ? # Character 喝
+U+fa79 ? # Character 啕
+U+fa7a ? # Character 喙
+U+fa7b ? # Character ï©»
+U+fa7c ? # Character 塚
+U+fa7d ? # Character 墳
+U+fa7e ? # Character 奄
+U+fa7f ? # Character ï©¿
+U+fa80 ? # Character ïª
+U+fa81 ? # Character ïª
+U+fa82 ? # Character ïª
+U+fa83 ? # Character ïª
+U+fa84 ? # Character ïª
+U+fa85 ? # Character ïª
+U+fa86 ? # Character ïª
+U+fa87 ? # Character ïª
+U+fa88 ? # Character ïª
+U+fa89 ? # Character ïª
+U+fa8a ? # Character ïª
+U+fa8b ? # Character ïª
+U+fa8c ? # Character ïª
+U+fa8d ? # Character ïª
+U+fa8e ? # Character ïª
+U+fa8f ? # Character ïª
+U+fa90 ? # Character ïª
+U+fa91 ? # Character ïª
+U+fa92 ? # Character ïª
+U+fa93 ? # Character ïª
+U+fa94 ? # Character ïª
+U+fa95 ? # Character ïª
+U+fa96 ? # Character ïª
+U+fa97 ? # Character ïª
+U+fa98 ? # Character ïª
+U+fa99 ? # Character ïª
+U+fa9a ? # Character ïª
+U+fa9b ? # Character ïª
+U+fa9c ? # Character ïª
+U+fa9d ? # Character ïª
+U+fa9e ? # Character ïª
+U+fa9f ? # Character ïª
+U+faa0 ? # Character ïª
+U+faa1 ? # Character 瑱
+U+faa2 ? # Character 甆
+U+faa3 ? # Character 画
+U+faa4 ? # Character 瘝
+U+faa5 ? # Character 瘟
+U+faa6 ? # Character 益
+U+faa7 ? # Character 盛
+U+faa8 ? # Character 直
+U+faa9 ? # Character 睊
+U+faaa ? # Character 着
+U+faab ? # Character 磌
+U+faac ? # Character 窱
+U+faad ? # Character ïª
+U+faae ? # Character 类
+U+faaf ? # Character 絛
+U+fab0 ? # Character 練
+U+fab1 ? # Character 缾
+U+fab2 ? # Character 者
+U+fab3 ? # Character 荒
+U+fab4 ? # Character 華
+U+fab5 ? # Character 蝹
+U+fab6 ? # Character 襁
+U+fab7 ? # Character 覆
+U+fab8 ? # Character 視
+U+fab9 ? # Character 調
+U+faba ? # Character 諸
+U+fabb ? # Character 請
+U+fabc ? # Character 謁
+U+fabd ? # Character 諾
+U+fabe ? # Character 諭
+U+fabf ? # Character 謹
+U+fac0 ? # Character ï«
+U+fac1 ? # Character ï«
+U+fac2 ? # Character ï«
+U+fac3 ? # Character ï«
+U+fac4 ? # Character ï«
+U+fac5 ? # Character ï«
+U+fac6 ? # Character ï«
+U+fac7 ? # Character ï«
+U+fac8 ? # Character ï«
+U+fac9 ? # Character ï«
+U+faca ? # Character ï«
+U+facb ? # Character ï«
+U+facc ? # Character ï«
+U+facd ? # Character ï«
+U+face ? # Character ï«
+U+facf ? # Character ï«
+U+fad0 ? # Character ï«
+U+fad1 ? # Character ï«
+U+fad2 ? # Character ï«
+U+fad3 ? # Character ï«
+U+fad4 ? # Character ï«
+U+fad5 ? # Character ï«
+U+fad6 ? # Character ï«
+U+fad7 ? # Character ï«
+U+fad8 ? # Character ï«
+U+fad9 ? # Character ï«
+U+fada ? # Character ï«
+U+fadb ? # Character ï«
+U+fadc ? # Character ï«
+U+fadd ? # Character ï«
+U+fade ? # Character ï«
+U+fadf ? # Character ï«
+U+fae0 ? # Character ï«
+U+fae1 ? # Character ï«¡
+U+fae2 ? # Character ï«¢
+U+fae3 ? # Character ï«£
+U+fae4 ? # Character 﫤
+U+fae5 ? # Character ï«¥
+U+fae6 ? # Character 﫦
+U+fae7 ? # Character 﫧
+U+fae8 ? # Character 﫨
+U+fae9 ? # Character ï«©
+U+faea ? # Character 﫪
+U+faeb ? # Character ï««
+U+faec ? # Character 﫬
+U+faed ? # Character ï«
+U+faee ? # Character ï«®
+U+faef ? # Character 﫯
+U+faf0 ? # Character ï«°
+U+faf1 ? # Character 﫱
+U+faf2 ? # Character 﫲
+U+faf3 ? # Character 﫳
+U+faf4 ? # Character ï«´
+U+faf5 ? # Character 﫵
+U+faf6 ? # Character 﫶
+U+faf7 ? # Character ï«·
+U+faf8 ? # Character 﫸
+U+faf9 ? # Character 﫹
+U+fafa ? # Character 﫺
+U+fafb ? # Character ï«»
+U+fafc ? # Character 﫼
+U+fafd ? # Character 﫽
+U+fafe ? # Character 﫾
+U+faff ? # Character ï«¿
diff --git a/resources/chars/ascii/rowfb.trans b/resources/chars/ascii/rowfb.trans
new file mode 100644
index 0000000..fffa2be
--- /dev/null
+++ b/resources/chars/ascii/rowfb.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+fb00 ff # Character ï¬
+U+fb01 fi # Character ï¬
+U+fb02 fl # Character ï¬
+U+fb03 ffi # Character ï¬
+U+fb04 ffl # Character ï¬
+U+fb05 st # Character ï¬
+U+fb06 st # Character ï¬
+U+fb07 ? # Character ï¬
+U+fb08 ? # Character ï¬
+U+fb09 ? # Character ï¬
+U+fb0a ? # Character ï¬
+U+fb0b ? # Character ï¬
+U+fb0c ? # Character ï¬
+U+fb0d ? # Character ï¬
+U+fb0e ? # Character ï¬
+U+fb0f ? # Character ï¬
+U+fb10 ? # Character ï¬
+U+fb11 ? # Character ï¬
+U+fb12 ? # Character ï¬
+U+fb13 mn # Character ï¬
+U+fb14 me # Character ï¬
+U+fb15 mi # Character ï¬
+U+fb16 vn # Character ï¬
+U+fb17 mkh # Character ï¬
+U+fb18 ? # Character ï¬
+U+fb19 ? # Character ï¬
+U+fb1a ? # Character ï¬
+U+fb1b ? # Character ï¬
+U+fb1c ? # Character ï¬
+U+fb1d yi # Character ï¬
+U+fb1e ? # Character ï¬
+U+fb1f ay # Character ï¬
+U+fb20 ` # Character ï¬
+U+fb21 ? # Character ﬡ
+U+fb22 d # Character ﬢ
+U+fb23 h # Character ﬣ
+U+fb24 k # Character ﬤ
+U+fb25 l # Character ﬥ
+U+fb26 m # Character ﬦ
+U+fb27 m # Character ﬧ
+U+fb28 t # Character ﬨ
+U+fb29 + # Character ﬩
+U+fb2a sh # Character שׁ
+U+fb2b s # Character שׂ
+U+fb2c sh # Character שּׁ
+U+fb2d s # Character ï¬
+U+fb2e a # Character אַ
+U+fb2f a # Character אָ
+U+fb30 ? # Character אּ
+U+fb31 b # Character בּ
+U+fb32 g # Character גּ
+U+fb33 d # Character דּ
+U+fb34 h # Character הּ
+U+fb35 v # Character וּ
+U+fb36 z # Character זּ
+U+fb37 ? # Character ﬷
+U+fb38 t # Character טּ
+U+fb39 y # Character יּ
+U+fb3a k # Character ךּ
+U+fb3b k # Character כּ
+U+fb3c l # Character לּ
+U+fb3d ? # Character ﬽
+U+fb3e l # Character מּ
+U+fb3f ? # Character ﬿
+U+fb40 n # Character ï
+U+fb41 n # Character ï
+U+fb42 ? # Character ï
+U+fb43 p # Character ï
+U+fb44 p # Character ï
+U+fb45 ? # Character ï
+U+fb46 ts # Character ï
+U+fb47 ts # Character ï
+U+fb48 r # Character ï
+U+fb49 sh # Character ï
+U+fb4a t # Character ï
+U+fb4b vo # Character ï
+U+fb4c b # Character ï
+U+fb4d k # Character ï
+U+fb4e p # Character ï
+U+fb4f l # Character ï
+U+fb50 ? # Character ï
+U+fb51 ? # Character ï
+U+fb52 ? # Character ï
+U+fb53 ? # Character ï
+U+fb54 ? # Character ï
+U+fb55 ? # Character ï
+U+fb56 ? # Character ï
+U+fb57 ? # Character ï
+U+fb58 ? # Character ï
+U+fb59 ? # Character ï
+U+fb5a ? # Character ï
+U+fb5b ? # Character ï
+U+fb5c ? # Character ï
+U+fb5d ? # Character ï
+U+fb5e ? # Character ï
+U+fb5f ? # Character ï
+U+fb60 ? # Character ï
+U+fb61 ? # Character ï¡
+U+fb62 ? # Character ï¢
+U+fb63 ? # Character ï£
+U+fb64 ? # Character ï¤
+U+fb65 ? # Character ï¥
+U+fb66 ? # Character ï¦
+U+fb67 ? # Character ï§
+U+fb68 ? # Character ï¨
+U+fb69 ? # Character ï©
+U+fb6a ? # Character ïª
+U+fb6b ? # Character ï«
+U+fb6c ? # Character ï¬
+U+fb6d ? # Character ï
+U+fb6e ? # Character ï®
+U+fb6f ? # Character ï¯
+U+fb70 ? # Character ï°
+U+fb71 ? # Character ï±
+U+fb72 ? # Character ï²
+U+fb73 ? # Character ï³
+U+fb74 ? # Character ï´
+U+fb75 ? # Character ïµ
+U+fb76 ? # Character ï¶
+U+fb77 ? # Character ï·
+U+fb78 ? # Character ï¸
+U+fb79 ? # Character ï¹
+U+fb7a ? # Character ïº
+U+fb7b ? # Character ï»
+U+fb7c ? # Character ï¼
+U+fb7d ? # Character ï½
+U+fb7e ? # Character ï¾
+U+fb7f ? # Character ï¿
+U+fb80 ? # Character ï®
+U+fb81 ? # Character ï®
+U+fb82 ? # Character ï®
+U+fb83 ? # Character ï®
+U+fb84 ? # Character ï®
+U+fb85 ? # Character ï®
+U+fb86 ? # Character ï®
+U+fb87 ? # Character ï®
+U+fb88 ? # Character ï®
+U+fb89 ? # Character ï®
+U+fb8a ? # Character ï®
+U+fb8b ? # Character ï®
+U+fb8c ? # Character ï®
+U+fb8d ? # Character ï®
+U+fb8e ? # Character ï®
+U+fb8f ? # Character ï®
+U+fb90 ? # Character ï®
+U+fb91 ? # Character ï®
+U+fb92 ? # Character ï®
+U+fb93 ? # Character ï®
+U+fb94 ? # Character ï®
+U+fb95 ? # Character ï®
+U+fb96 ? # Character ï®
+U+fb97 ? # Character ï®
+U+fb98 ? # Character ï®
+U+fb99 ? # Character ï®
+U+fb9a ? # Character ï®
+U+fb9b ? # Character ï®
+U+fb9c ? # Character ï®
+U+fb9d ? # Character ï®
+U+fb9e ? # Character ï®
+U+fb9f ? # Character ï®
+U+fba0 ? # Character ï®
+U+fba1 ? # Character ﮡ
+U+fba2 ? # Character ﮢ
+U+fba3 ? # Character ﮣ
+U+fba4 ? # Character ﮤ
+U+fba5 ? # Character ﮥ
+U+fba6 ? # Character ﮦ
+U+fba7 ? # Character ﮧ
+U+fba8 ? # Character ﮨ
+U+fba9 ? # Character ﮩ
+U+fbaa ? # Character ﮪ
+U+fbab ? # Character ﮫ
+U+fbac ? # Character ﮬ
+U+fbad ? # Character ï®
+U+fbae ? # Character ï®®
+U+fbaf ? # Character ﮯ
+U+fbb0 ? # Character ï®°
+U+fbb1 ? # Character ï®±
+U+fbb2 ? # Character ﮲
+U+fbb3 ? # Character ﮳
+U+fbb4 ? # Character ï®´
+U+fbb5 ? # Character ﮵
+U+fbb6 ? # Character ﮶
+U+fbb7 ? # Character ï®·
+U+fbb8 ? # Character ﮸
+U+fbb9 ? # Character ﮹
+U+fbba ? # Character ﮺
+U+fbbb ? # Character ï®»
+U+fbbc ? # Character ﮼
+U+fbbd ? # Character ﮽
+U+fbbe ? # Character ﮾
+U+fbbf ? # Character ﮿
+U+fbc0 ? # Character ï¯
+U+fbc1 ? # Character ï¯
+U+fbc2 ? # Character ï¯
+U+fbc3 ? # Character ï¯
+U+fbc4 ? # Character ï¯
+U+fbc5 ? # Character ï¯
+U+fbc6 ? # Character ï¯
+U+fbc7 ? # Character ï¯
+U+fbc8 ? # Character ï¯
+U+fbc9 ? # Character ï¯
+U+fbca ? # Character ï¯
+U+fbcb ? # Character ï¯
+U+fbcc ? # Character ï¯
+U+fbcd ? # Character ï¯
+U+fbce ? # Character ï¯
+U+fbcf ? # Character ï¯
+U+fbd0 ? # Character ï¯
+U+fbd1 ? # Character ï¯
+U+fbd2 ? # Character ï¯
+U+fbd3 ? # Character ï¯
+U+fbd4 ? # Character ï¯
+U+fbd5 ? # Character ï¯
+U+fbd6 ? # Character ï¯
+U+fbd7 ? # Character ï¯
+U+fbd8 ? # Character ï¯
+U+fbd9 ? # Character ï¯
+U+fbda ? # Character ï¯
+U+fbdb ? # Character ï¯
+U+fbdc ? # Character ï¯
+U+fbdd ? # Character ï¯
+U+fbde ? # Character ï¯
+U+fbdf ? # Character ï¯
+U+fbe0 ? # Character ï¯
+U+fbe1 ? # Character ﯡ
+U+fbe2 ? # Character ﯢ
+U+fbe3 ? # Character ﯣ
+U+fbe4 ? # Character ﯤ
+U+fbe5 ? # Character ﯥ
+U+fbe6 ? # Character ﯦ
+U+fbe7 ? # Character ﯧ
+U+fbe8 ? # Character ﯨ
+U+fbe9 ? # Character ﯩ
+U+fbea ? # Character ﯪ
+U+fbeb ? # Character ﯫ
+U+fbec ? # Character ﯬ
+U+fbed ? # Character ï¯
+U+fbee ? # Character ﯮ
+U+fbef ? # Character ﯯ
+U+fbf0 ? # Character ﯰ
+U+fbf1 ? # Character ﯱ
+U+fbf2 ? # Character ﯲ
+U+fbf3 ? # Character ﯳ
+U+fbf4 ? # Character ﯴ
+U+fbf5 ? # Character ﯵ
+U+fbf6 ? # Character ﯶ
+U+fbf7 ? # Character ﯷ
+U+fbf8 ? # Character ﯸ
+U+fbf9 ? # Character ﯹ
+U+fbfa ? # Character ﯺ
+U+fbfb ? # Character ﯻ
+U+fbfc ? # Character ﯼ
+U+fbfd ? # Character ﯽ
+U+fbfe ? # Character ﯾ
+U+fbff ? # Character ﯿ
diff --git a/resources/chars/ascii/rowfe.trans b/resources/chars/ascii/rowfe.trans
new file mode 100644
index 0000000..122a149
--- /dev/null
+++ b/resources/chars/ascii/rowfe.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+fe00 ? # Character ï¸
+U+fe01 ? # Character ï¸
+U+fe02 ? # Character ï¸
+U+fe03 ? # Character ï¸
+U+fe04 ? # Character ï¸
+U+fe05 ? # Character ï¸
+U+fe06 ? # Character ï¸
+U+fe07 ? # Character ï¸
+U+fe08 ? # Character ï¸
+U+fe09 ? # Character ï¸
+U+fe0a ? # Character ï¸
+U+fe0b ? # Character ï¸
+U+fe0c ? # Character ï¸
+U+fe0d ? # Character ï¸
+U+fe0e ? # Character ï¸
+U+fe0f ? # Character ï¸
+U+fe10 ? # Character ï¸
+U+fe11 ? # Character ï¸
+U+fe12 ? # Character ï¸
+U+fe13 ? # Character ï¸
+U+fe14 ? # Character ï¸
+U+fe15 ? # Character ï¸
+U+fe16 ? # Character ï¸
+U+fe17 ? # Character ï¸
+U+fe18 ? # Character ï¸
+U+fe19 ? # Character ï¸
+U+fe1a ? # Character ï¸
+U+fe1b ? # Character ï¸
+U+fe1c ? # Character ï¸
+U+fe1d ? # Character ï¸
+U+fe1e ? # Character ï¸
+U+fe1f ? # Character ï¸
+U+fe20 ? # Character ï¸
+U+fe21 ? # Character ︡
+U+fe22 ? # Character ︢
+U+fe23 ~ # Character ︣
+U+fe24 ? # Character ︤
+U+fe25 ? # Character ︥
+U+fe26 ? # Character ︦
+U+fe27 ? # Character ︧
+U+fe28 ? # Character ︨
+U+fe29 ? # Character ︩
+U+fe2a ? # Character ︪
+U+fe2b ? # Character ︫
+U+fe2c ? # Character ︬
+U+fe2d ? # Character ï¸
+U+fe2e ? # Character ︮
+U+fe2f ? # Character ︯
+U+fe30 .. # Character ︰
+U+fe31 -- # Character ︱
+U+fe32 - # Character ︲
+U+fe33 _ # Character ︳
+U+fe34 _ # Character ︴
+U+fe35 ( # Character ︵
+U+fe36 ) # Character ︶
+U+fe37 { # Character ︷
+U+fe38 } # Character ︸
+U+fe39 [ # Character ︹
+U+fe3a ] # Character ︺
+U+fe3b [( # Character ︻
+U+fe3c )] # Character ︼
+U+fe3d << # Character ︽
+U+fe3e >> # Character ︾
+U+fe3f < # Character ︿
+U+fe40 > # Character ï¹
+U+fe41 [ # Character ï¹
+U+fe42 ] # Character ï¹
+U+fe43 { # Character ï¹
+U+fe44 } # Character ï¹
+U+fe45 ? # Character ï¹
+U+fe46 ? # Character ï¹
+U+fe47 ? # Character ï¹
+U+fe48 ? # Character ï¹
+U+fe49 ? # Character ï¹
+U+fe4a ? # Character ï¹
+U+fe4b ? # Character ï¹
+U+fe4c ? # Character ï¹
+U+fe4d ? # Character ï¹
+U+fe4e ? # Character ï¹
+U+fe4f ? # Character ï¹
+U+fe50 , # Character ï¹
+U+fe51 , # Character ï¹
+U+fe52 . # Character ï¹
+U+fe53 ? # Character ï¹
+U+fe54 ; # Character ï¹
+U+fe55 : # Character ï¹
+U+fe56 ? # Character ï¹
+U+fe57 ! # Character ï¹
+U+fe58 - # Character ï¹
+U+fe59 ( # Character ï¹
+U+fe5a ) # Character ï¹
+U+fe5b { # Character ï¹
+U+fe5c } # Character ï¹
+U+fe5d { # Character ï¹
+U+fe5e } # Character ï¹
+U+fe5f # # Character ï¹
+U+fe60 & # Character ï¹
+U+fe61 * # Character ﹡
+U+fe62 + # Character ï¹¢
+U+fe63 - # Character ï¹£
+U+fe64 < # Character ﹤
+U+fe65 > # Character ï¹¥
+U+fe66 = # Character ﹦
+U+fe67 ? # Character ﹧
+U+fe68 \ # Character ﹨
+U+fe69 $ # Character ﹩
+U+fe6a % # Character ﹪
+U+fe6b @ # Character ﹫
+U+fe6c ? # Character ﹬
+U+fe6d ? # Character ï¹
+U+fe6e ? # Character ï¹®
+U+fe6f ? # Character ﹯
+U+fe70 ? # Character ï¹°
+U+fe71 ? # Character ï¹±
+U+fe72 ? # Character ï¹²
+U+fe73 ? # Character ï¹³
+U+fe74 ? # Character ï¹´
+U+fe75 ? # Character ï¹µ
+U+fe76 ? # Character ﹶ
+U+fe77 ? # Character ï¹·
+U+fe78 ? # Character ﹸ
+U+fe79 ? # Character ï¹¹
+U+fe7a ? # Character ﹺ
+U+fe7b ? # Character ï¹»
+U+fe7c ? # Character ï¹¼
+U+fe7d ? # Character ï¹½
+U+fe7e ? # Character ï¹¾
+U+fe7f ? # Character ﹿ
+U+fe80 ? # Character ïº
+U+fe81 ? # Character ïº
+U+fe82 ? # Character ïº
+U+fe83 ? # Character ïº
+U+fe84 ? # Character ïº
+U+fe85 ? # Character ïº
+U+fe86 ? # Character ïº
+U+fe87 ? # Character ïº
+U+fe88 ? # Character ïº
+U+fe89 ? # Character ïº
+U+fe8a ? # Character ïº
+U+fe8b ? # Character ïº
+U+fe8c ? # Character ïº
+U+fe8d ? # Character ïº
+U+fe8e ? # Character ïº
+U+fe8f ? # Character ïº
+U+fe90 ? # Character ïº
+U+fe91 ? # Character ïº
+U+fe92 ? # Character ïº
+U+fe93 ? # Character ïº
+U+fe94 ? # Character ïº
+U+fe95 ? # Character ïº
+U+fe96 ? # Character ïº
+U+fe97 ? # Character ïº
+U+fe98 ? # Character ïº
+U+fe99 ? # Character ïº
+U+fe9a ? # Character ïº
+U+fe9b ? # Character ïº
+U+fe9c ? # Character ïº
+U+fe9d ? # Character ïº
+U+fe9e ? # Character ïº
+U+fe9f ? # Character ïº
+U+fea0 ? # Character ïº
+U+fea1 ? # Character ﺡ
+U+fea2 ? # Character ﺢ
+U+fea3 ? # Character ﺣ
+U+fea4 ? # Character ﺤ
+U+fea5 ? # Character ﺥ
+U+fea6 ? # Character ﺦ
+U+fea7 ? # Character ﺧ
+U+fea8 ? # Character ﺨ
+U+fea9 ? # Character ﺩ
+U+feaa ? # Character ﺪ
+U+feab ? # Character ﺫ
+U+feac ? # Character ﺬ
+U+fead ? # Character ïº
+U+feae ? # Character ﺮ
+U+feaf ? # Character ﺯ
+U+feb0 ? # Character ﺰ
+U+feb1 ? # Character ﺱ
+U+feb2 ? # Character ﺲ
+U+feb3 ? # Character ﺳ
+U+feb4 ? # Character ﺴ
+U+feb5 ? # Character ﺵ
+U+feb6 ? # Character ﺶ
+U+feb7 ? # Character ﺷ
+U+feb8 ? # Character ﺸ
+U+feb9 ? # Character ﺹ
+U+feba ? # Character ﺺ
+U+febb ? # Character ﺻ
+U+febc ? # Character ﺼ
+U+febd ? # Character ﺽ
+U+febe ? # Character ﺾ
+U+febf ? # Character ﺿ
+U+fec0 ? # Character ï»
+U+fec1 ? # Character ï»
+U+fec2 ? # Character ï»
+U+fec3 ? # Character ï»
+U+fec4 ? # Character ï»
+U+fec5 ? # Character ï»
+U+fec6 ? # Character ï»
+U+fec7 ? # Character ï»
+U+fec8 ? # Character ï»
+U+fec9 ? # Character ï»
+U+feca ? # Character ï»
+U+fecb ? # Character ï»
+U+fecc ? # Character ï»
+U+fecd ? # Character ï»
+U+fece ? # Character ï»
+U+fecf ? # Character ï»
+U+fed0 ? # Character ï»
+U+fed1 ? # Character ï»
+U+fed2 ? # Character ï»
+U+fed3 ? # Character ï»
+U+fed4 ? # Character ï»
+U+fed5 ? # Character ï»
+U+fed6 ? # Character ï»
+U+fed7 ? # Character ï»
+U+fed8 ? # Character ï»
+U+fed9 ? # Character ï»
+U+feda ? # Character ï»
+U+fedb ? # Character ï»
+U+fedc ? # Character ï»
+U+fedd ? # Character ï»
+U+fede ? # Character ï»
+U+fedf ? # Character ï»
+U+fee0 ? # Character ï»
+U+fee1 ? # Character ﻡ
+U+fee2 ? # Character ﻢ
+U+fee3 ? # Character ﻣ
+U+fee4 ? # Character ﻤ
+U+fee5 ? # Character ﻥ
+U+fee6 ? # Character ﻦ
+U+fee7 ? # Character ﻧ
+U+fee8 ? # Character ﻨ
+U+fee9 ? # Character ﻩ
+U+feea ? # Character ﻪ
+U+feeb ? # Character ﻫ
+U+feec ? # Character ﻬ
+U+feed ? # Character ï»
+U+feee ? # Character ï»®
+U+feef ? # Character ﻯ
+U+fef0 ? # Character ï»°
+U+fef1 ? # Character ï»±
+U+fef2 ? # Character ﻲ
+U+fef3 ? # Character ﻳ
+U+fef4 ? # Character ï»´
+U+fef5 ? # Character ﻵ
+U+fef6 ? # Character ﻶ
+U+fef7 ? # Character ï»·
+U+fef8 ? # Character ﻸ
+U+fef9 ? # Character ﻹ
+U+fefa ? # Character ﻺ
+U+fefb ? # Character ï»»
+U+fefc ? # Character ﻼ
+U+fefd ? # Character ﻽
+U+fefe ? # Character ﻾
+U+feff ? # Character 
diff --git a/resources/chars/ascii/rowff.trans b/resources/chars/ascii/rowff.trans
new file mode 100644
index 0000000..6c87bc4
--- /dev/null
+++ b/resources/chars/ascii/rowff.trans
@@ -0,0 +1,261 @@
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+
+U+ff00 ? # Character ï¼
+U+ff01 ! # Character ï¼
+U+ff02 " # Character ï¼
+U+ff03 # # Character ï¼
+U+ff04 $ # Character ï¼
+U+ff05 % # Character ï¼
+U+ff06 & # Character ï¼
+U+ff07 ' # Character ï¼
+U+ff08 ( # Character ï¼
+U+ff09 ) # Character ï¼
+U+ff0a * # Character ï¼
+U+ff0b + # Character ï¼
+U+ff0c , # Character ï¼
+U+ff0d - # Character ï¼
+U+ff0e . # Character ï¼
+U+ff0f / # Character ï¼
+U+ff10 ? # Character ï¼
+U+ff11 1 # Character ï¼
+U+ff12 2 # Character ï¼
+U+ff13 3 # Character ï¼
+U+ff14 4 # Character ï¼
+U+ff15 5 # Character ï¼
+U+ff16 6 # Character ï¼
+U+ff17 7 # Character ï¼
+U+ff18 8 # Character ï¼
+U+ff19 9 # Character ï¼
+U+ff1a : # Character ï¼
+U+ff1b ; # Character ï¼
+U+ff1c < # Character ï¼
+U+ff1d = # Character ï¼
+U+ff1e > # Character ï¼
+U+ff1f ? # Character ï¼
+U+ff20 @ # Character ï¼
+U+ff21 A # Character A
+U+ff22 B # Character ï¼¢
+U+ff23 C # Character ï¼£
+U+ff24 D # Character D
+U+ff25 E # Character ï¼¥
+U+ff26 F # Character F
+U+ff27 G # Character G
+U+ff28 H # Character H
+U+ff29 I # Character I
+U+ff2a J # Character J
+U+ff2b K # Character K
+U+ff2c L # Character L
+U+ff2d M # Character ï¼
+U+ff2e N # Character ï¼®
+U+ff2f O # Character O
+U+ff30 P # Character ï¼°
+U+ff31 Q # Character ï¼±
+U+ff32 R # Character ï¼²
+U+ff33 S # Character ï¼³
+U+ff34 T # Character ï¼´
+U+ff35 U # Character ï¼µ
+U+ff36 V # Character V
+U+ff37 W # Character ï¼·
+U+ff38 X # Character X
+U+ff39 Y # Character ï¼¹
+U+ff3a Z # Character Z
+U+ff3b [ # Character ï¼»
+U+ff3c \ # Character ï¼¼
+U+ff3d ] # Character ï¼½
+U+ff3e ^ # Character ï¼¾
+U+ff3f _ # Character _
+U+ff40 ` # Character ï½
+U+ff41 a # Character ï½
+U+ff42 b # Character ï½
+U+ff43 c # Character ï½
+U+ff44 d # Character ï½
+U+ff45 e # Character ï½
+U+ff46 f # Character ï½
+U+ff47 g # Character ï½
+U+ff48 h # Character ï½
+U+ff49 i # Character ï½
+U+ff4a j # Character ï½
+U+ff4b k # Character ï½
+U+ff4c l # Character ï½
+U+ff4d m # Character ï½
+U+ff4e n # Character ï½
+U+ff4f o # Character ï½
+U+ff50 p # Character ï½
+U+ff51 q # Character ï½
+U+ff52 r # Character ï½
+U+ff53 s # Character ï½
+U+ff54 t # Character ï½
+U+ff55 u # Character ï½
+U+ff56 v # Character ï½
+U+ff57 w # Character ï½
+U+ff58 x # Character ï½
+U+ff59 y # Character ï½
+U+ff5a z # Character ï½
+U+ff5b { # Character ï½
+U+ff5c | # Character ï½
+U+ff5d } # Character ï½
+U+ff5e ~ # Character ï½
+U+ff5f ? # Character ï½
+U+ff60 ? # Character ï½
+U+ff61 . # Character 。
+U+ff62 [ # Character ï½¢
+U+ff63 ] # Character ï½£
+U+ff64 , # Character 、
+U+ff65 * # Character ï½¥
+U+ff66 wo # Character ヲ
+U+ff67 a # Character ァ
+U+ff68 i # Character ィ
+U+ff69 u # Character ゥ
+U+ff6a e # Character ェ
+U+ff6b o # Character ォ
+U+ff6c ya # Character ャ
+U+ff6d yu # Character ï½
+U+ff6e yo # Character ï½®
+U+ff6f tu # Character ッ
+U+ff70 + # Character ï½°
+U+ff71 a # Character ï½±
+U+ff72 i # Character ï½²
+U+ff73 u # Character ï½³
+U+ff74 e # Character ï½´
+U+ff75 o # Character ï½µ
+U+ff76 ka # Character カ
+U+ff77 ki # Character ï½·
+U+ff78 ku # Character ク
+U+ff79 ke # Character ï½¹
+U+ff7a ko # Character コ
+U+ff7b sa # Character ï½»
+U+ff7c si # Character ï½¼
+U+ff7d su # Character ï½½
+U+ff7e se # Character ï½¾
+U+ff7f so # Character ソ
+U+ff80 ta # Character ï¾
+U+ff81 ti # Character ï¾
+U+ff82 tu # Character ï¾
+U+ff83 te # Character ï¾
+U+ff84 to # Character ï¾
+U+ff85 na # Character ï¾
+U+ff86 ni # Character ï¾
+U+ff87 nu # Character ï¾
+U+ff88 ne # Character ï¾
+U+ff89 no # Character ï¾
+U+ff8a ha # Character ï¾
+U+ff8b hi # Character ï¾
+U+ff8c hu # Character ï¾
+U+ff8d he # Character ï¾
+U+ff8e ho # Character ï¾
+U+ff8f ma # Character ï¾
+U+ff90 mi # Character ï¾
+U+ff91 mu # Character ï¾
+U+ff92 me # Character ï¾
+U+ff93 mo # Character ï¾
+U+ff94 ya # Character ï¾
+U+ff95 yu # Character ï¾
+U+ff96 yo # Character ï¾
+U+ff97 ra # Character ï¾
+U+ff98 ri # Character ï¾
+U+ff99 ru # Character ï¾
+U+ff9a re # Character ï¾
+U+ff9b ro # Character ï¾
+U+ff9c wa # Character ï¾
+U+ff9d n # Character ï¾
+U+ff9e : # Character ï¾
+U+ff9f ; # Character ï¾
+U+ffa0 ? # Character ï¾
+U+ffa1 g # Character ᄀ
+U+ffa2 gg # Character ï¾¢
+U+ffa3 gs # Character ï¾£
+U+ffa4 n # Character ᄂ
+U+ffa5 nj # Character ï¾¥
+U+ffa6 nh # Character ᆭ
+U+ffa7 d # Character ᄃ
+U+ffa8 dd # Character ᄄ
+U+ffa9 r # Character ᄅ
+U+ffaa lg # Character ᆰ
+U+ffab lm # Character ᆱ
+U+ffac lb # Character ᆲ
+U+ffad ls # Character ï¾
+U+ffae lt # Character ï¾®
+U+ffaf lp # Character ᆵ
+U+ffb0 rh # Character ï¾°
+U+ffb1 m # Character ï¾±
+U+ffb2 b # Character ï¾²
+U+ffb3 bb # Character ï¾³
+U+ffb4 bs # Character ï¾´
+U+ffb5 s # Character ï¾µ
+U+ffb6 ss # Character ᄊ
+U+ffb7 ? # Character ï¾·
+U+ffb8 j # Character ᄌ
+U+ffb9 jj # Character ï¾¹
+U+ffba c # Character ᄎ
+U+ffbb k # Character ï¾»
+U+ffbc t # Character ï¾¼
+U+ffbd p # Character ï¾½
+U+ffbe h # Character ï¾¾
+U+ffbf ? # Character ﾿
+U+ffc0 ? # Character ï¿
+U+ffc1 ? # Character ï¿
+U+ffc2 a # Character ï¿
+U+ffc3 ae # Character ï¿
+U+ffc4 ya # Character ï¿
+U+ffc5 yae # Character ï¿
+U+ffc6 eo # Character ï¿
+U+ffc7 e # Character ï¿
+U+ffc8 ? # Character ï¿
+U+ffc9 ? # Character ï¿
+U+ffca yeo # Character ï¿
+U+ffcb ye # Character ï¿
+U+ffcc o # Character ï¿
+U+ffcd wa # Character ï¿
+U+ffce wae # Character ï¿
+U+ffcf oe # Character ï¿
+U+ffd0 ? # Character ï¿
+U+ffd1 ? # Character ï¿
+U+ffd2 yo # Character ï¿
+U+ffd3 u # Character ï¿
+U+ffd4 weo # Character ï¿
+U+ffd5 we # Character ï¿
+U+ffd6 wi # Character ï¿
+U+ffd7 yu # Character ï¿
+U+ffd8 ? # Character ï¿
+U+ffd9 ? # Character ï¿
+U+ffda eu # Character ï¿
+U+ffdb yi # Character ï¿
+U+ffdc i # Character ï¿
+U+ffdd ? # Character ï¿
+U+ffde ? # Character ï¿
+U+ffdf ? # Character ï¿
+U+ffe0 /C # Character ï¿
+U+ffe1 PS # Character ï¿¡
+U+ffe2 ! # Character ï¿¢
+U+ffe3 - # Character ï¿£
+U+ffe4 | # Character ¦
+U+ffe5 Y= # Character ï¿¥
+U+ffe6 W= # Character ₩
+U+ffe7 ? # Character ￧
+U+ffe8 | # Character │
+U+ffe9 - # Character ï¿©
+U+ffea | # Character ↑
+U+ffeb - # Character ï¿«
+U+ffec | # Character ↓
+U+ffed # # Character ï¿
+U+ffee O # Character ï¿®
+U+ffef ? # Character ￯
+U+fff0 ? # Character ï¿°
+U+fff1 ? # Character ￱
+U+fff2 ? # Character ￲
+U+fff3 ? # Character ￳
+U+fff4 ? # Character ï¿´
+U+fff5 ? # Character ￵
+U+fff6 ? # Character ￶
+U+fff7 ? # Character ï¿·
+U+fff8 ? # Character ￸
+U+fff9 { # Character 
+U+fffa | # Character 
+U+fffb } # Character ï¿»
+U+fffc ? # Character 
+U+fffd ? # Character �
+U+fffe ? # Character ￾
+U+ffff ? # Character ï¿¿
diff --git a/resources/chars/latin1/row03.trans b/resources/chars/latin1/row03.trans
new file mode 100644
index 0000000..881b619
--- /dev/null
+++ b/resources/chars/latin1/row03.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+0300 ? # Character Ì
+U+0301 ? # Character Ì
+U+0302 ? # Character Ì
+U+0303 ? # Character Ì
+U+0304 ? # Character Ì
+U+0305 ? # Character Ì
+U+0306 ? # Character Ì
+U+0307 ? # Character Ì
+U+0308 ? # Character Ì
+U+0309 ? # Character Ì
+U+030a ? # Character Ì
+U+030b ? # Character Ì
+U+030c ? # Character Ì
+U+030d ? # Character Ì
+U+030e ? # Character Ì
+U+030f ? # Character Ì
+U+0310 ? # Character Ì
+U+0311 ? # Character Ì
+U+0312 ? # Character Ì
+U+0313 ? # Character Ì
+U+0314 ? # Character Ì
+U+0315 ? # Character Ì
+U+0316 ? # Character Ì
+U+0317 ? # Character Ì
+U+0318 ? # Character Ì
+U+0319 ? # Character Ì
+U+031a ? # Character Ì
+U+031b ? # Character Ì
+U+031c ? # Character Ì
+U+031d ? # Character Ì
+U+031e ? # Character Ì
+U+031f ? # Character Ì
+U+0320 ? # Character Ì
+U+0321 ? # Character Ì¡
+U+0322 ? # Character ̢
+U+0323 ? # Character ̣
+U+0324 ? # Character ̤
+U+0325 ? # Character ̥
+U+0326 ? # Character ̦
+U+0327 ? # Character ̧
+U+0328 ? # Character ̨
+U+0329 ? # Character Ì©
+U+032a ? # Character ̪
+U+032b ? # Character Ì«
+U+032c ? # Character ̬
+U+032d ? # Character Ì
+U+032e ? # Character Ì®
+U+032f ? # Character ̯
+U+0330 ? # Character Ì°
+U+0331 ? # Character ̱
+U+0332 ? # Character ̲
+U+0333 ? # Character ̳
+U+0334 ? # Character Ì´
+U+0335 ? # Character ̵
+U+0336 ? # Character ̶
+U+0337 ? # Character Ì·
+U+0338 ? # Character ̸
+U+0339 ? # Character ̹
+U+033a ? # Character ̺
+U+033b ? # Character Ì»
+U+033c ? # Character ̼
+U+033d ? # Character ̽
+U+033e ? # Character ̾
+U+033f ? # Character Ì¿
+U+0340 ? # Character Í
+U+0341 ? # Character Í
+U+0342 ? # Character Í
+U+0343 ? # Character Í
+U+0344 ? # Character Í
+U+0345 ? # Character Í
+U+0346 ? # Character Í
+U+0347 ? # Character Í
+U+0348 ? # Character Í
+U+0349 ? # Character Í
+U+034a ? # Character Í
+U+034b ? # Character Í
+U+034c ? # Character Í
+U+034d ? # Character Í
+U+034e ? # Character Í
+U+034f ? # Character Í
+U+0350 ? # Character Í
+U+0351 ? # Character Í
+U+0352 ? # Character Í
+U+0353 ? # Character Í
+U+0354 ? # Character Í
+U+0355 ? # Character Í
+U+0356 ? # Character Í
+U+0357 ? # Character Í
+U+0358 ? # Character Í
+U+0359 ? # Character Í
+U+035a ? # Character Í
+U+035b ? # Character Í
+U+035c ? # Character Í
+U+035d ? # Character Í
+U+035e ? # Character Í
+U+035f ? # Character Í
+U+0360 ? # Character Í
+U+0361 ? # Character Í¡
+U+0362 ? # Character ͢
+U+0363 ? # Character ͣ
+U+0364 ? # Character ͤ
+U+0365 ? # Character ͥ
+U+0366 ? # Character ͦ
+U+0367 ? # Character ͧ
+U+0368 ? # Character ͨ
+U+0369 ? # Character Í©
+U+036a ? # Character ͪ
+U+036b ? # Character Í«
+U+036c ? # Character ͬ
+U+036d ? # Character Í
+U+036e ? # Character Í®
+U+036f ? # Character ͯ
+U+0370 ? # Character Í°
+U+0371 ? # Character ͱ
+U+0372 ? # Character Ͳ
+U+0373 ? # Character ͳ
+U+0374 ? # Character Í´
+U+0375 ? # Character ͵
+U+0376 ? # Character Ͷ
+U+0377 ? # Character Í·
+U+0378 ? # Character ͸
+U+0379 ? # Character ͹
+U+037a i # Character ͺ
+U+037b ? # Character Í»
+U+037c ? # Character ͼ
+U+037d ? # Character ͽ
+U+037e ? # Character ;
+U+037f ? # Character Í¿
+U+0380 ? # Character Î
+U+0381 ? # Character Î
+U+0382 ? # Character Î
+U+0383 ? # Character Î
+U+0384 ? # Character Î
+U+0385 ? # Character Î
+U+0386 Ã # Character Î
+U+0387 ? # Character Î
+U+0388 Ã # Character Î
+#U+0389 Ḡ# Character Î
+U+038a à # Character Î
+U+038b ? # Character Î
+U+038c à # Character Î
+U+038d ? # Character Î
+U+038e à # Character Î
+#U+038f á¹ # Character Î
+#U+0390 ḯ # Character Î
+U+0391 A # Character Î
+U+0392 B # Character Î
+U+0393 G # Character Î
+U+0394 D # Character Î
+U+0395 E # Character Î
+U+0396 Z # Character Î
+#U+0397 Ä # Character Î
+U+0398 TH # Character Î
+U+0399 I # Character Î
+U+039a K # Character Î
+U+039b L # Character Î
+U+039c M # Character Î
+U+039d N # Character Î
+U+039e X # Character Î
+U+039f O # Character Î
+U+03a0 P # Character Î
+U+03a1 R # Character Ρ
+U+03a2 ? # Character ΢
+U+03a3 S # Character Σ
+U+03a4 T # Character Τ
+U+03a5 Y # Character Υ
+U+03a6 PH # Character Φ
+U+03a7 CH # Character Χ
+U+03a8 PS # Character Ψ
+#U+03a9 Š# Character Ω
+U+03aa à # Character Ϊ
+#U+03ab Ÿ # Character Ϋ
+U+03ac á # Character ά
+U+03ad é # Character Î
+#U+03ae Ḡ# Character ή
+U+03af à # Character ί
+#U+03b0 Ã¿Ì # Character ΰ
+U+03b1 a # Character α
+U+03b2 b # Character β
+U+03b3 g # Character γ
+U+03b4 d # Character δ
+U+03b5 e # Character ε
+U+03b6 z # Character ζ
+#U+03b7 Ä # Character η
+U+03b8 th # Character θ
+U+03b9 i # Character ι
+U+03ba k # Character κ
+U+03bb l # Character λ
+U+03bc m # Character μ
+U+03bd n # Character ν
+U+03be x # Character ξ
+U+03bf o # Character ο
+U+03c0 p # Character Ï
+U+03c1 r # Character Ï
+#U+03c2 s̱ # Character Ï
+U+03c3 s # Character Ï
+U+03c4 t # Character Ï
+U+03c5 y # Character Ï
+U+03c6 ph # Character Ï
+U+03c7 ch # Character Ï
+U+03c8 ps # Character Ï
+#U+03c9 Å # Character Ï
+U+03ca ï # Character Ï
+U+03cb ÿ # Character Ï
+U+03cc ó # Character Ï
+U+03cd ý # Character Ï
+#U+03ce á¹ # Character Ï
+U+03cf ? # Character Ï
+U+03d0 b # Character Ï
+U+03d1 th # Character Ï
+U+03d2 Y # Character Ï
+U+03d3 Ã # Character Ï
+#U+03d4 Ÿ # Character Ï
+U+03d5 ph # Character Ï
+U+03d6 p # Character Ï
+U+03d7 ? # Character Ï
+U+03d8 ? # Character Ï
+U+03d9 ? # Character Ï
+U+03da ? # Character Ï
+U+03db ? # Character Ï
+U+03dc ? # Character Ï
+U+03dd ? # Character Ï
+U+03de ? # Character Ï
+U+03df ? # Character Ï
+U+03e0 ? # Character Ï
+U+03e1 ? # Character Ï¡
+U+03e2 ? # Character Ϣ
+U+03e3 ? # Character ϣ
+U+03e4 ? # Character Ϥ
+U+03e5 ? # Character ϥ
+U+03e6 ? # Character Ϧ
+U+03e7 ? # Character ϧ
+U+03e8 ? # Character Ϩ
+U+03e9 ? # Character Ï©
+U+03ea ? # Character Ϫ
+U+03eb ? # Character Ï«
+U+03ec ? # Character Ϭ
+U+03ed ? # Character Ï
+U+03ee ? # Character Ï®
+U+03ef ? # Character ϯ
+U+03f0 k # Character Ï°
+U+03f1 r # Character ϱ
+U+03f2 s # Character ϲ
+U+03f3 j # Character ϳ
+U+03f4 TH # Character Ï´
+U+03f5 e # Character ϵ
+U+03f6 ? # Character ϶
+#U+03f7 Å # Character Ï·
+#U+03f8 š # Character ϸ
+U+03f9 S # Character Ϲ
+#U+03fa Š# Character Ϻ
+#U+03fb Å # Character Ï»
+U+03fc ? # Character ϼ
+U+03fd ? # Character Ͻ
+U+03fe ? # Character Ͼ
+U+03ff ? # Character Ï¿
diff --git a/resources/chars/latin1/row04.trans b/resources/chars/latin1/row04.trans
new file mode 100644
index 0000000..49b0890
--- /dev/null
+++ b/resources/chars/latin1/row04.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+0400 Ã # Character Ð
+U+0401 Ã # Character Ð
+#U+0402 Ä # Character Ð
+#U+0403 Ç´ # Character Ð
+U+0404 Ã # Character Ð
+#U+0405 Ạ# Character Ð
+U+0406 Ã # Character Ð
+#U+0407 ÃÌ # Character Ð
+#U+0408 JÌ # Character Ð
+#U+0409 LÌ # Character Ð
+#U+040a NÌ # Character Ð
+#U+040b Ä # Character Ð
+#U+040c Ḱ # Character Ð
+U+040d à # Character Ð
+#U+040e Ŭ # Character Ð
+#U+040f DÌ # Character Ð
+U+0410 A # Character Ð
+U+0411 B # Character Ð
+U+0412 V # Character Ð
+U+0413 G # Character Ð
+U+0414 D # Character Ð
+U+0415 E # Character Ð
+#U+0416 Ž # Character Ð
+U+0417 Z # Character Ð
+U+0418 I # Character Ð
+U+0419 J # Character Ð
+U+041a K # Character Ð
+U+041b L # Character Ð
+U+041c M # Character Ð
+U+041d N # Character Ð
+U+041e O # Character Ð
+U+041f P # Character Ð
+U+0420 R # Character Ð
+U+0421 S # Character С
+U+0422 T # Character Т
+U+0423 U # Character У
+U+0424 F # Character Ф
+U+0425 H # Character Х
+U+0426 C # Character Ц
+#U+0427 Ä # Character Ч
+#U+0428 Š# Character Ш
+#U+0429 Š# Character Щ
+#U+042a ʺ̱ # Character Ъ
+U+042b Y # Character Ы
+#U+042c ʹ̱ # Character Ь
+U+042d à # Character Ð
+U+042e à # Character Ю
+U+042f à # Character Я
+U+0430 a # Character а
+U+0431 b # Character б
+U+0432 v # Character в
+U+0433 g # Character г
+U+0434 d # Character д
+U+0435 e # Character е
+#U+0436 ž # Character ж
+U+0437 z # Character з
+U+0438 i # Character и
+U+0439 j # Character й
+U+043a k # Character к
+U+043b l # Character л
+U+043c m # Character м
+U+043d n # Character н
+U+043e o # Character о
+U+043f p # Character п
+U+0440 r # Character Ñ
+U+0441 s # Character Ñ
+U+0442 t # Character Ñ
+U+0443 u # Character Ñ
+U+0444 f # Character Ñ
+U+0445 h # Character Ñ
+U+0446 c # Character Ñ
+#U+0447 Ä # Character Ñ
+#U+0448 Å¡ # Character Ñ
+#U+0449 Å # Character Ñ
+#U+044a ʺ # Character Ñ
+U+044b y # Character Ñ
+#U+044c ʹ # Character Ñ
+U+044d é # Character Ñ
+U+044e û # Character Ñ
+U+044f â # Character Ñ
+U+0450 è # Character Ñ
+U+0451 ë # Character Ñ
+#U+0452 Ä # Character Ñ
+#U+0453 ǵ # Character Ñ
+U+0454 ê # Character Ñ
+#U+0455 Ạ# Character Ñ
+U+0456 Ã # Character Ñ
+#U+0457 ÃÌ # Character Ñ
+#U+0458 Ç° # Character Ñ
+#U+0459 lÌ # Character Ñ
+#U+045a nÌ # Character Ñ
+#U+045b Ä # Character Ñ
+#U+045c ḱ # Character Ñ
+U+045d ì # Character Ñ
+#U+045e Å # Character Ñ
+#U+045f dÌ # Character Ñ
+U+0460 ? # Character Ñ
+U+0461 ? # Character Ñ¡
+U+0462 ? # Character Ѣ
+U+0463 ? # Character ѣ
+U+0464 ? # Character Ѥ
+U+0465 ? # Character ѥ
+U+0466 ? # Character Ѧ
+U+0467 ? # Character ѧ
+U+0468 ? # Character Ѩ
+U+0469 ? # Character Ñ©
+U+046a ? # Character Ѫ
+U+046b ? # Character Ñ«
+U+046c ? # Character Ѭ
+U+046d ? # Character Ñ
+U+046e ? # Character Ñ®
+U+046f ? # Character ѯ
+U+0470 ? # Character Ñ°
+U+0471 ? # Character ѱ
+U+0472 ? # Character Ѳ
+U+0473 ? # Character ѳ
+U+0474 ? # Character Ñ´
+U+0475 ? # Character ѵ
+U+0476 ? # Character Ѷ
+U+0477 ? # Character Ñ·
+U+0478 ? # Character Ѹ
+U+0479 ? # Character ѹ
+U+047a ? # Character Ѻ
+U+047b ? # Character Ñ»
+U+047c ? # Character Ѽ
+U+047d ? # Character ѽ
+U+047e ? # Character Ѿ
+U+047f ? # Character Ñ¿
+U+0480 ? # Character Ò
+U+0481 ? # Character Ò
+U+0482 ? # Character Ò
+U+0483 ? # Character Ò
+U+0484 ? # Character Ò
+U+0485 ? # Character Ò
+U+0486 ? # Character Ò
+U+0487 ? # Character Ò
+U+0488 ? # Character Ò
+U+0489 ? # Character Ò
+U+048a ? # Character Ò
+U+048b ? # Character Ò
+U+048c ? # Character Ò
+U+048d ? # Character Ò
+U+048e ? # Character Ò
+U+048f ? # Character Ò
+#U+0490 GÌ # Character Ò
+#U+0491 gÌ # Character Ò
+#U+0492 Ä # Character Ò
+#U+0493 Ä¡ # Character Ò
+#U+0494 Ä # Character Ò
+#U+0495 Ä # Character Ò
+U+0496 ? # Character Ò
+U+0497 ? # Character Ò
+#U+0498 Z̦ # Character Ò
+#U+0499 z̦ # Character Ò
+#U+049a KË # Character Ò
+#U+049b kË # Character Ò
+U+049c ? # Character Ò
+U+049d ? # Character Ò
+U+049e ? # Character Ò
+U+049f ? # Character Ò
+U+04a0 ? # Character Ò
+U+04a1 ? # Character Ò¡
+U+04a2 ? # Character Ò¢
+U+04a3 ? # Character Ò£
+U+04a4 ? # Character Ò¤
+U+04a5 ? # Character Ò¥
+U+04a6 ? # Character Ò¦
+U+04a7 ? # Character Ò§
+U+04a8 ? # Character Ò¨
+U+04a9 ? # Character Ò©
+U+04aa ? # Character Òª
+U+04ab ? # Character Ò«
+U+04ac ? # Character Ò¬
+U+04ad ? # Character Ò
+U+04ae ? # Character Ò®
+U+04af ? # Character Ò¯
+U+04b0 ? # Character Ò°
+U+04b1 ? # Character Ò±
+U+04b2 ? # Character Ò²
+U+04b3 ? # Character Ò³
+U+04b4 ? # Character Ò´
+U+04b5 ? # Character Òµ
+U+04b6 ? # Character Ò¶
+U+04b7 ? # Character Ò·
+U+04b8 ? # Character Ò¸
+U+04b9 ? # Character Ò¹
+U+04ba ? # Character Òº
+U+04bb ? # Character Ò»
+U+04bc ? # Character Ò¼
+U+04bd ? # Character Ò½
+U+04be ? # Character Ò¾
+U+04bf ? # Character Ò¿
+U+04c0 ? # Character Ó
+#U+04c1 Å½Ì # Character Ó
+#U+04c2 Å¾Ì # Character Ó
+U+04c3 ? # Character Ó
+U+04c4 ? # Character Ó
+U+04c5 ? # Character Ó
+U+04c6 ? # Character Ó
+U+04c7 ? # Character Ó
+U+04c8 ? # Character Ó
+U+04c9 ? # Character Ó
+U+04ca ? # Character Ó
+U+04cb ? # Character Ó
+U+04cc ? # Character Ó
+U+04cd ? # Character Ó
+U+04ce ? # Character Ó
+U+04cf ? # Character Ó
+#U+04d0 Ä # Character Ó
+#U+04d1 Ä # Character Ó
+U+04d2 Ã # Character Ó
+U+04d3 ä # Character Ó
+U+04d4 Ã # Character Ó
+U+04d5 æ # Character Ó
+#U+04d6 Ä # Character Ó
+#U+04d7 Ä # Character Ó
+#U+04d8 Æ # Character Ó
+#U+04d9 É # Character Ó
+#U+04da ÆÌ # Character Ó
+#U+04db ÉÌ # Character Ó
+#U+04dc Å½Ì # Character Ó
+#U+04dd Å¾Ì # Character Ó
+#U+04de ZÌ # Character Ó
+#U+04df zÌ # Character Ó
+U+04e0 ? # Character Ó
+U+04e1 ? # Character Ó¡
+#U+04e2 Ī # Character Ӣ
+#U+04e3 Ä« # Character Ó£
+U+04e4 Ã # Character Ó¤
+U+04e5 ï # Character ӥ
+U+04e6 Ã # Character Ó¦
+U+04e7 ö # Character ӧ
+U+04e8 ? # Character Ó¨
+U+04e9 ? # Character Ó©
+U+04ea ? # Character Óª
+U+04eb ? # Character Ó«
+#U+04ec ÃÌ # Character Ó¬
+#U+04ed Ã©Ì # Character Ó
+#U+04ee Ū # Character Ӯ
+#U+04ef Å« # Character Ó¯
+U+04f0 Ã # Character Ó°
+U+04f1 ü # Character ӱ
+#U+04f2 Å° # Character Ó²
+#U+04f3 ű # Character ӳ
+#U+04f4 ÄÌ # Character Ó´
+#U+04f5 ÄÌ # Character Óµ
+U+04f6 ? # Character Ó¶
+U+04f7 ? # Character Ó·
+#U+04f8 Ÿ # Character Ӹ
+U+04f9 ÿ # Character ӹ
+U+04fa ? # Character Óº
+U+04fb ? # Character Ó»
+U+04fc ? # Character Ó¼
+U+04fd ? # Character Ó½
+U+04fe ? # Character Ó¾
+U+04ff ? # Character Ó¿
diff --git a/resources/chars/latin1/row05.trans b/resources/chars/latin1/row05.trans
new file mode 100644
index 0000000..f8bf131
--- /dev/null
+++ b/resources/chars/latin1/row05.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+0500 ? # Character Ô
+U+0501 ? # Character Ô
+U+0502 ? # Character Ô
+U+0503 ? # Character Ô
+U+0504 ? # Character Ô
+U+0505 ? # Character Ô
+U+0506 ? # Character Ô
+U+0507 ? # Character Ô
+U+0508 ? # Character Ô
+U+0509 ? # Character Ô
+U+050a ? # Character Ô
+U+050b ? # Character Ô
+U+050c ? # Character Ô
+U+050d ? # Character Ô
+U+050e ? # Character Ô
+U+050f ? # Character Ô
+U+0510 ? # Character Ô
+U+0511 ? # Character Ô
+U+0512 ? # Character Ô
+U+0513 ? # Character Ô
+U+0514 ? # Character Ô
+U+0515 ? # Character Ô
+U+0516 ? # Character Ô
+U+0517 ? # Character Ô
+U+0518 ? # Character Ô
+U+0519 ? # Character Ô
+U+051a ? # Character Ô
+U+051b ? # Character Ô
+U+051c ? # Character Ô
+U+051d ? # Character Ô
+U+051e ? # Character Ô
+U+051f ? # Character Ô
+U+0520 ? # Character Ô
+U+0521 ? # Character Ô¡
+U+0522 ? # Character Ô¢
+U+0523 ? # Character Ô£
+U+0524 ? # Character Ô¤
+U+0525 ? # Character Ô¥
+U+0526 ? # Character Ô¦
+U+0527 ? # Character Ô§
+U+0528 ? # Character Ô¨
+U+0529 ? # Character Ô©
+U+052a ? # Character Ôª
+U+052b ? # Character Ô«
+U+052c ? # Character Ô¬
+U+052d ? # Character Ô
+U+052e ? # Character Ô®
+U+052f ? # Character Ô¯
+U+0530 ? # Character Ô°
+U+0531 A # Character Ô±
+U+0532 B # Character Ô²
+U+0533 G # Character Ô³
+U+0534 D # Character Ô´
+U+0535 E # Character Ôµ
+U+0536 Z # Character Ô¶
+#U+0537 Ä # Character Ô·
+#U+0538 Æ # Character Ô¸
+#U+0539 TÊ» # Character Ô¹
+#U+053a Ž # Character Ժ
+U+053b I # Character Ô»
+U+053c L # Character Ô¼
+U+053d X # Character Ô½
+U+053e C # Character Ô¾
+U+053f K # Character Ô¿
+U+0540 H # Character Õ
+U+0541 J # Character Õ
+#U+0542 Ä # Character Õ
+#U+0543 Ä # Character Õ
+U+0544 M # Character Õ
+U+0545 Y # Character Õ
+U+0546 N # Character Õ
+#U+0547 Å # Character Õ
+U+0548 O # Character Õ
+#U+0549 ÄÊ» # Character Õ
+U+054a P # Character Õ
+#U+054b JÌ # Character Õ
+#U+054c á¹ # Character Õ
+U+054d S # Character Õ
+U+054e V # Character Õ
+U+054f T # Character Õ
+U+0550 R # Character Õ
+#U+0551 CÊ» # Character Õ
+U+0552 W # Character Õ
+#U+0553 PÊ» # Character Õ
+#U+0554 KÊ» # Character Õ
+#U+0555 Å # Character Õ
+U+0556 F # Character Õ
+U+0557 ? # Character Õ
+U+0558 ? # Character Õ
+U+0559 ? # Character Õ
+U+055a ? # Character Õ
+U+055b ? # Character Õ
+U+055c ? # Character Õ
+U+055d ? # Character Õ
+U+055e ? # Character Õ
+U+055f ? # Character Õ
+U+0560 ? # Character Õ
+U+0561 a # Character Õ¡
+U+0562 b # Character Õ¢
+U+0563 g # Character Õ£
+U+0564 d # Character Õ¤
+U+0565 e # Character Õ¥
+U+0566 z # Character Õ¦
+#U+0567 Ä # Character Õ§
+#U+0568 É # Character Õ¨
+#U+0569 tÊ» # Character Õ©
+#U+056a ž # Character ժ
+U+056b i # Character Õ«
+U+056c l # Character Õ¬
+U+056d x # Character Õ
+U+056e c # Character Õ®
+U+056f k # Character Õ¯
+U+0570 h # Character Õ°
+U+0571 j # Character Õ±
+#U+0572 Ä¡ # Character Õ²
+#U+0573 Ä # Character Õ³
+U+0574 m # Character Õ´
+U+0575 y # Character Õµ
+U+0576 n # Character Õ¶
+#U+0577 Å¡ # Character Õ·
+U+0578 o # Character Õ¸
+#U+0579 ÄÊ» # Character Õ¹
+U+057a p # Character Õº
+#U+057b Ç° # Character Õ»
+#U+057c á¹ # Character Õ¼
+U+057d s # Character Õ½
+U+057e v # Character Õ¾
+U+057f t # Character Õ¿
+U+0580 r # Character Ö
+#U+0581 cÊ» # Character Ö
+U+0582 w # Character Ö
+#U+0583 pÊ» # Character Ö
+#U+0584 kÊ» # Character Ö
+#U+0585 Å # Character Ö
+U+0586 f # Character Ö
+U+0587 ev # Character Ö
+U+0588 ? # Character Ö
+U+0589 ? # Character Ö
+U+058a ? # Character Ö
+U+058b ? # Character Ö
+U+058c ? # Character Ö
+U+058d ? # Character Ö
+U+058e ? # Character Ö
+U+058f ? # Character Ö
+U+0590 ? # Character Ö
+U+0591 ? # Character Ö
+U+0592 ? # Character Ö
+U+0593 ? # Character Ö
+U+0594 ? # Character Ö
+U+0595 ? # Character Ö
+U+0596 ? # Character Ö
+U+0597 ? # Character Ö
+U+0598 ? # Character Ö
+U+0599 ? # Character Ö
+U+059a ? # Character Ö
+U+059b ? # Character Ö
+U+059c ? # Character Ö
+U+059d ? # Character Ö
+U+059e ? # Character Ö
+U+059f ? # Character Ö
+U+05a0 ? # Character Ö
+U+05a1 ? # Character Ö¡
+U+05a2 ? # Character Ö¢
+U+05a3 ? # Character Ö£
+U+05a4 ? # Character Ö¤
+U+05a5 ? # Character Ö¥
+U+05a6 ? # Character Ö¦
+U+05a7 ? # Character Ö§
+U+05a8 ? # Character Ö¨
+U+05a9 ? # Character Ö©
+U+05aa ? # Character Öª
+U+05ab ? # Character Ö«
+U+05ac ? # Character Ö¬
+U+05ad ? # Character Ö
+U+05ae ? # Character Ö®
+U+05af ? # Character Ö¯
+#U+05b0 Ä # Character Ö°
+U+05b1 è # Character ֱ
+U+05b2 Ã # Character Ö²
+U+05b3 o # Character Ö³
+U+05b4 i # Character Ö´
+U+05b5 é # Character ֵ
+U+05b6 e # Character Ö¶
+U+05b7 a # Character Ö·
+U+05b8 á # Character ָ
+U+05b9 ò # Character ֹ
+U+05ba ? # Character Öº
+U+05bb u # Character Ö»
+#U+05bc Ì # Character Ö¼
+U+05bd ? # Character Ö½
+U+05be ? # Character Ö¾
+#U+05bf Ì # Character Ö¿
+U+05c0 ? # Character ×
+#U+05c1 Ì # Character ×
+#U+05c2 Ì # Character ×
+U+05c3 ? # Character ×
+U+05c4 ? # Character ×
+U+05c5 ? # Character ×
+U+05c6 ? # Character ×
+U+05c7 ? # Character ×
+U+05c8 ? # Character ×
+U+05c9 ? # Character ×
+U+05ca ? # Character ×
+U+05cb ? # Character ×
+U+05cc ? # Character ×
+U+05cd ? # Character ×
+U+05ce ? # Character ×
+U+05cf ? # Character ×
+#U+05d0 ʼ # Character ×
+U+05d1 b # Character ×
+U+05d2 g # Character ×
+U+05d3 d # Character ×
+U+05d4 h # Character ×
+U+05d5 w # Character ×
+U+05d6 z # Character ×
+#U+05d7 Ạ# Character ×
+U+05d8 t # Character ×
+U+05d9 y # Character ×
+U+05da k # Character ×
+U+05db k # Character ×
+U+05dc l # Character ×
+U+05dd m # Character ×
+U+05de m # Character ×
+U+05df n # Character ×
+U+05e0 n # Character ×
+U+05e1 s # Character ס
+#U+05e2 Ê» # Character ×¢
+U+05e3 p # Character ×£
+U+05e4 p # Character פ
+#U+05e5 Ạ# Character ץ
+#U+05e6 Ạ# Character צ
+U+05e7 q # Character ק
+U+05e8 r # Character ר
+#U+05e9 Š# Character ש
+#U+05ea ţ # Character ת
+U+05eb ? # Character ׫
+U+05ec ? # Character ׬
+U+05ed ? # Character ×
+U+05ee ? # Character ×®
+U+05ef ? # Character ׯ
+U+05f0 ww # Character ×°
+U+05f1 wy # Character ×±
+U+05f2 yy # Character ײ
+U+05f3 ? # Character ׳
+U+05f4 ? # Character ×´
+U+05f5 ? # Character ×µ
+U+05f6 ? # Character ׶
+U+05f7 ? # Character ×·
+U+05f8 ? # Character ׸
+U+05f9 ? # Character ×¹
+U+05fa ? # Character ׺
+U+05fb ? # Character ×»
+U+05fc ? # Character ×¼
+U+05fd ? # Character ×½
+U+05fe ? # Character ×¾
+U+05ff ? # Character ׿
diff --git a/resources/chars/latin1/row06.trans b/resources/chars/latin1/row06.trans
new file mode 100644
index 0000000..d18b899
--- /dev/null
+++ b/resources/chars/latin1/row06.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+0600 ? # Character Ø
+U+0601 ? # Character Ø
+U+0602 ? # Character Ø
+U+0603 ? # Character Ø
+U+0604 ? # Character Ø
+U+0605 ? # Character Ø
+U+0606 ? # Character Ø
+U+0607 ? # Character Ø
+U+0608 ? # Character Ø
+U+0609 ? # Character Ø
+U+060a ? # Character Ø
+U+060b ? # Character Ø
+U+060c ? # Character Ø
+U+060d ? # Character Ø
+U+060e ? # Character Ø
+U+060f ? # Character Ø
+U+0610 ? # Character Ø
+U+0611 ? # Character Ø
+U+0612 ? # Character Ø
+U+0613 ? # Character Ø
+U+0614 ? # Character Ø
+U+0615 ? # Character Ø
+U+0616 ? # Character Ø
+U+0617 ? # Character Ø
+U+0618 ? # Character Ø
+U+0619 ? # Character Ø
+U+061a ? # Character Ø
+U+061b ? # Character Ø
+U+061c ? # Character Ø
+U+061d ? # Character Ø
+U+061e ? # Character Ø
+U+061f ? # Character Ø
+U+0620 ? # Character Ø
+#U+0621 ʾ # Character ء
+#U+0622 Ạ# Character آ
+#U+0623 áº¡Ì # Character Ø£
+#U+0624 wÌ # Character ؤ
+#U+0625 ạ̹ # Character إ
+#U+0626 ỷ # Character ئ
+#U+0627 ạ # Character ا
+U+0628 b # Character ب
+#U+0629 Ạ# Character ة
+U+062a t # Character ت
+#U+062b tẠ# Character ث
+U+062c j # Character ج
+#U+062d ḥ # Character Ø
+#U+062e kẠ# Character خ
+U+062f d # Character د
+#U+0630 dẠ# Character ذ
+U+0631 r # Character ر
+U+0632 z # Character ز
+U+0633 s # Character س
+#U+0634 sẠ# Character ش
+#U+0635 ṣ # Character ص
+#U+0636 Ḡ# Character ض
+#U+0637 á¹ # Character Ø·
+#U+0638 Ạ# Character ظ
+#U+0639 ʿ # Character ع
+#U+063a gẠ# Character غ
+U+063b ? # Character Ø»
+U+063c ? # Character ؼ
+U+063d ? # Character ؽ
+U+063e ? # Character ؾ
+U+063f ? # Character Ø¿
+U+0640 ? # Character Ù
+U+0641 f # Character Ù
+U+0642 q # Character Ù
+U+0643 k # Character Ù
+U+0644 l # Character Ù
+U+0645 m # Character Ù
+U+0646 n # Character Ù
+U+0647 h # Character Ù
+U+0648 w # Character Ù
+#U+0649 y̱ # Character Ù
+U+064a y # Character Ù
+U+064b ? # Character Ù
+U+064c ? # Character Ù
+U+064d ? # Character Ù
+U+064e ? # Character Ù
+U+064f ? # Character Ù
+U+0650 ? # Character Ù
+U+0651 ? # Character Ù
+U+0652 ? # Character Ù
+U+0653 ? # Character Ù
+U+0654 ? # Character Ù
+U+0655 ? # Character Ù
+U+0656 ? # Character Ù
+U+0657 ? # Character Ù
+U+0658 ? # Character Ù
+U+0659 ? # Character Ù
+U+065a ? # Character Ù
+U+065b ? # Character Ù
+U+065c ? # Character Ù
+U+065d ? # Character Ù
+U+065e ? # Character Ù
+U+065f ? # Character Ù
+U+0660 ? # Character Ù
+U+0661 ? # Character Ù¡
+U+0662 ? # Character Ù¢
+U+0663 ? # Character Ù£
+U+0664 ? # Character Ù¤
+U+0665 ? # Character Ù¥
+U+0666 ? # Character Ù¦
+U+0667 ? # Character Ù§
+U+0668 ? # Character Ù¨
+U+0669 ? # Character Ù©
+U+066a % # Character Ùª
+#U+066b ,̱ # Character ٫
+#U+066c .̱ # Character ٬
+U+066d ? # Character Ù
+U+066e ? # Character Ù®
+U+066f ? # Character Ù¯
+U+0670 ? # Character Ù°
+U+0671 ? # Character Ù±
+U+0672 ? # Character Ù²
+U+0673 ? # Character Ù³
+U+0674 ? # Character Ù´
+#U+0675 ạٴ # Character ٵ
+#U+0676 wÙ´ # Character Ù¶
+#U+0677 ÛÙ´ # Character Ù·
+#U+0678 yÙ´ # Character Ù¸
+U+0679 ? # Character Ù¹
+U+067a ? # Character Ùº
+U+067b ? # Character Ù»
+U+067c ? # Character Ù¼
+U+067d ? # Character Ù½
+U+067e p # Character Ù¾
+U+067f ? # Character Ù¿
+U+0680 ? # Character Ú
+U+0681 ? # Character Ú
+U+0682 ? # Character Ú
+U+0683 ? # Character Ú
+U+0684 ? # Character Ú
+U+0685 ? # Character Ú
+#U+0686 cẠ# Character Ú
+U+0687 ? # Character Ú
+U+0688 ? # Character Ú
+U+0689 ? # Character Ú
+U+068a ? # Character Ú
+U+068b ? # Character Ú
+U+068c ? # Character Ú
+U+068d ? # Character Ú
+U+068e ? # Character Ú
+U+068f ? # Character Ú
+U+0690 ? # Character Ú
+U+0691 ? # Character Ú
+U+0692 ? # Character Ú
+U+0693 ? # Character Ú
+U+0694 ? # Character Ú
+U+0695 ? # Character Ú
+U+0696 ? # Character Ú
+U+0697 ? # Character Ú
+#U+0698 zẠ# Character Ú
+U+0699 ? # Character Ú
+#U+069a sË # Character Ú
+U+069b ? # Character Ú
+U+069c ? # Character Ú
+U+069d ? # Character Ú
+U+069e ? # Character Ú
+U+069f ? # Character Ú
+U+06a0 ? # Character Ú
+U+06a1 ? # Character Ú¡
+U+06a2 ? # Character Ú¢
+U+06a3 ? # Character Ú£
+U+06a4 v # Character Ú¤
+U+06a5 ? # Character Ú¥
+U+06a6 ? # Character Ú¦
+U+06a7 ? # Character Ú§
+U+06a8 ? # Character Ú¨
+#U+06a9 ḵ # Character ک
+U+06aa ? # Character Úª
+U+06ab ? # Character Ú«
+U+06ac ? # Character Ú¬
+#U+06ad á¹g # Character Ú
+U+06ae ? # Character Ú®
+U+06af g # Character Ú¯
+U+06b0 ? # Character Ú°
+U+06b1 ? # Character Ú±
+U+06b2 ? # Character Ú²
+U+06b3 ? # Character Ú³
+U+06b4 ? # Character Ú´
+U+06b5 ? # Character Úµ
+U+06b6 ? # Character Ú¶
+U+06b7 ? # Character Ú·
+U+06b8 ? # Character Ú¸
+U+06b9 ? # Character Ú¹
+U+06ba ? # Character Úº
+U+06bb ? # Character Ú»
+U+06bc ? # Character Ú¼
+U+06bd ? # Character Ú½
+U+06be ? # Character Ú¾
+U+06bf ? # Character Ú¿
+#U+06c0 ÛÌ # Character Û
+U+06c1 ? # Character Û
+#U+06c2 ÛÌ # Character Û
+U+06c3 ? # Character Û
+U+06c4 ? # Character Û
+U+06c5 ? # Character Û
+U+06c6 ? # Character Û
+U+06c7 ? # Character Û
+U+06c8 ? # Character Û
+U+06c9 ? # Character Û
+U+06ca ? # Character Û
+#U+06cb v̱ # Character Û
+#U+06cc yÌ° # Character Û
+U+06cd ? # Character Û
+U+06ce ? # Character Û
+U+06cf ? # Character Û
+U+06d0 ? # Character Û
+U+06d1 ? # Character Û
+U+06d2 ? # Character Û
+#U+06d3 ÛÌ # Character Û
+U+06d4 ? # Character Û
+U+06d5 ? # Character Û
+U+06d6 ? # Character Û
+U+06d7 ? # Character Û
+U+06d8 ? # Character Û
+U+06d9 ? # Character Û
+U+06da ? # Character Û
+U+06db ? # Character Û
+U+06dc ? # Character Û
+U+06dd ? # Character Û
+U+06de ? # Character Û
+U+06df ? # Character Û
+U+06e0 ? # Character Û
+U+06e1 ? # Character Û¡
+U+06e2 ? # Character Û¢
+U+06e3 ? # Character Û£
+U+06e4 ? # Character Û¤
+U+06e5 ? # Character Û¥
+U+06e6 ? # Character Û¦
+U+06e7 ? # Character Û§
+U+06e8 ? # Character Û¨
+U+06e9 ? # Character Û©
+U+06ea ? # Character Ûª
+U+06eb ? # Character Û«
+U+06ec ? # Character Û¬
+U+06ed ? # Character Û
+U+06ee ? # Character Û®
+U+06ef ? # Character Û¯
+#U+06f0 0̱ # Character ۰
+#U+06f1 1̱ # Character ۱
+#U+06f2 2̱ # Character ۲
+#U+06f3 3̱ # Character ۳
+#U+06f4 4̱ # Character ۴
+#U+06f5 5̱ # Character ۵
+#U+06f6 6̱ # Character ۶
+#U+06f7 7̱ # Character ۷
+#U+06f8 8̱ # Character ۸
+#U+06f9 9̱ # Character ۹
+U+06fa ? # Character Ûº
+U+06fb ? # Character Û»
+U+06fc ? # Character Û¼
+U+06fd ? # Character Û½
+U+06fe ? # Character Û¾
+U+06ff ? # Character Û¿
diff --git a/resources/chars/latin1/row07.trans b/resources/chars/latin1/row07.trans
new file mode 100644
index 0000000..c41c69f
--- /dev/null
+++ b/resources/chars/latin1/row07.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+0700 ? # Character Ü
+U+0701 ? # Character Ü
+U+0702 ? # Character Ü
+U+0703 ? # Character Ü
+U+0704 ? # Character Ü
+U+0705 ? # Character Ü
+U+0706 ? # Character Ü
+U+0707 ? # Character Ü
+U+0708 ? # Character Ü
+U+0709 ? # Character Ü
+U+070a ? # Character Ü
+U+070b ? # Character Ü
+U+070c ? # Character Ü
+U+070d * # Character Ü
+U+070e ? # Character Ü
+U+070f ? # Character Ü
+#U+0710 ʾ # Character Ü
+#U+0711 ʾ # Character Ü
+U+0712 b # Character Ü
+U+0713 g # Character Ü
+U+0714 g # Character Ü
+U+0715 d # Character Ü
+U+0716 dr # Character Ü
+U+0717 h # Character Ü
+U+0718 w # Character Ü
+U+0719 z # Character Ü
+#U+071a ḥ # Character Ü
+#U+071b tÌ£ # Character Ü
+#U+071c tÌ£ # Character Ü
+U+071d y # Character Ü
+U+071e yh # Character Ü
+U+071f k # Character Ü
+U+0720 l # Character Ü
+U+0721 m # Character Ü¡
+U+0722 n # Character ܢ
+U+0723 s # Character ܣ
+U+0724 s # Character ܤ
+#U+0725 ʿ # Character ܥ
+U+0726 p # Character ܦ
+U+0727 p # Character ܧ
+#U+0728 ṣ # Character ܨ
+U+0729 q # Character Ü©
+U+072a r # Character ܪ
+U+072b sh # Character Ü«
+U+072c t # Character ܬ
+U+072d ? # Character Ü
+U+072e ? # Character Ü®
+U+072f ? # Character ܯ
+U+0730 a # Character Ü°
+U+0731 a # Character ܱ
+U+0732 a # Character ܲ
+U+0733 o # Character ܳ
+U+0734 o # Character Ü´
+U+0735 a # Character ܵ
+U+0736 e # Character ܶ
+U+0737 e # Character Ü·
+U+0738 e # Character ܸ
+#U+0739 Ä # Character ܹ
+U+073a i # Character ܺ
+U+073b i # Character Ü»
+U+073c u # Character ܼ
+U+073d u # Character ܽ
+U+073e u # Character ܾ
+U+073f o # Character Ü¿
+U+0740 ? # Character Ý
+U+0741 ? # Character Ý
+U+0742 i # Character Ý
+U+0743 ? # Character Ý
+U+0744 ? # Character Ý
+U+0745 ? # Character Ý
+U+0746 ? # Character Ý
+U+0747 ? # Character Ý
+U+0748 ? # Character Ý
+U+0749 ? # Character Ý
+U+074a ? # Character Ý
+U+074b ? # Character Ý
+U+074c ? # Character Ý
+U+074d ? # Character Ý
+U+074e ? # Character Ý
+U+074f ? # Character Ý
+U+0750 ? # Character Ý
+U+0751 ? # Character Ý
+U+0752 ? # Character Ý
+U+0753 ? # Character Ý
+U+0754 ? # Character Ý
+U+0755 ? # Character Ý
+U+0756 ? # Character Ý
+U+0757 ? # Character Ý
+U+0758 ? # Character Ý
+U+0759 ? # Character Ý
+U+075a ? # Character Ý
+U+075b ? # Character Ý
+U+075c ? # Character Ý
+U+075d ? # Character Ý
+U+075e ? # Character Ý
+U+075f ? # Character Ý
+U+0760 ? # Character Ý
+U+0761 ? # Character Ý¡
+U+0762 ? # Character ݢ
+U+0763 ? # Character ݣ
+U+0764 ? # Character ݤ
+U+0765 ? # Character ݥ
+U+0766 ? # Character ݦ
+U+0767 ? # Character ݧ
+U+0768 ? # Character ݨ
+U+0769 ? # Character Ý©
+U+076a ? # Character ݪ
+U+076b ? # Character Ý«
+U+076c ? # Character ݬ
+U+076d ? # Character Ý
+U+076e ? # Character Ý®
+U+076f ? # Character ݯ
+U+0770 ? # Character Ý°
+U+0771 ? # Character ݱ
+U+0772 ? # Character ݲ
+U+0773 ? # Character ݳ
+U+0774 ? # Character Ý´
+U+0775 ? # Character ݵ
+U+0776 ? # Character ݶ
+U+0777 ? # Character Ý·
+U+0778 ? # Character ݸ
+U+0779 ? # Character ݹ
+U+077a ? # Character ݺ
+U+077b ? # Character Ý»
+U+077c ? # Character ݼ
+U+077d ? # Character ݽ
+U+077e ? # Character ݾ
+U+077f ? # Character Ý¿
+U+0780 h # Character Þ
+#U+0781 Å¡ # Character Þ
+U+0782 n # Character Þ
+U+0783 r # Character Þ
+U+0784 b # Character Þ
+#U+0785 ḷ # Character Þ
+U+0786 k # Character Þ
+#U+0787 â # Character Þ
+U+0788 v # Character Þ
+U+0789 m # Character Þ
+U+078a f # Character Þ
+U+078b d # Character Þ
+U+078c t # Character Þ
+U+078d l # Character Þ
+U+078e g # Character Þ
+U+078f ñ # Character Þ
+U+0790 s # Character Þ
+#U+0791 Ḡ# Character Þ
+U+0792 z # Character Þ
+#U+0793 á¹ # Character Þ
+U+0794 y # Character Þ
+U+0795 p # Character Þ
+U+0796 j # Character Þ
+#U+0797 Ä # Character Þ
+U+0798 tt # Character Þ
+#U+0799 ḥ # Character Þ
+U+079a kh # Character Þ
+U+079b dh # Character Þ
+U+079c ? # Character Þ
+#U+079d Å¡ # Character Þ
+#U+079e á¹£ # Character Þ
+#U+079f Ḡ# Character Þ
+#U+07a0 t̤ # Character Þ
+U+07a1 ? # Character Þ¡
+#U+07a2 Ê¿ # Character Þ¢
+#U+07a3 ǧ # Character ޣ
+U+07a4 q # Character Þ¤
+U+07a5 ? # Character Þ¥
+U+07a6 a # Character Þ¦
+#U+07a7 Ä # Character Þ§
+U+07a8 i # Character Þ¨
+#U+07a9 Ä« # Character Þ©
+U+07aa u # Character Þª
+#U+07ab Å« # Character Þ«
+U+07ac e # Character Þ¬
+#U+07ad Ä # Character Þ
+U+07ae o # Character Þ®
+#U+07af Å # Character Þ¯
+U+07b0 # Character Þ°
+U+07b1 ? # Character Þ±
+U+07b2 ? # Character Þ²
+U+07b3 ? # Character Þ³
+U+07b4 ? # Character Þ´
+U+07b5 ? # Character Þµ
+U+07b6 ? # Character Þ¶
+U+07b7 ? # Character Þ·
+U+07b8 ? # Character Þ¸
+U+07b9 ? # Character Þ¹
+U+07ba ? # Character Þº
+U+07bb ? # Character Þ»
+U+07bc ? # Character Þ¼
+U+07bd ? # Character Þ½
+U+07be ? # Character Þ¾
+U+07bf ? # Character Þ¿
+U+07c0 ? # Character ß
+U+07c1 ? # Character ß
+U+07c2 ? # Character ß
+U+07c3 ? # Character ß
+U+07c4 ? # Character ß
+U+07c5 ? # Character ß
+U+07c6 ? # Character ß
+U+07c7 ? # Character ß
+U+07c8 ? # Character ß
+U+07c9 ? # Character ß
+U+07ca ? # Character ß
+U+07cb ? # Character ß
+U+07cc ? # Character ß
+U+07cd ? # Character ß
+U+07ce ? # Character ß
+U+07cf ? # Character ß
+U+07d0 ? # Character ß
+U+07d1 ? # Character ß
+U+07d2 ? # Character ß
+U+07d3 ? # Character ß
+U+07d4 ? # Character ß
+U+07d5 ? # Character ß
+U+07d6 ? # Character ß
+U+07d7 ? # Character ß
+U+07d8 ? # Character ß
+U+07d9 ? # Character ß
+U+07da ? # Character ß
+U+07db ? # Character ß
+U+07dc ? # Character ß
+U+07dd ? # Character ß
+U+07de ? # Character ß
+U+07df ? # Character ß
+U+07e0 ? # Character ß
+U+07e1 ? # Character ß¡
+U+07e2 ? # Character ߢ
+U+07e3 ? # Character ߣ
+U+07e4 ? # Character ߤ
+U+07e5 ? # Character ߥ
+U+07e6 ? # Character ߦ
+U+07e7 ? # Character ߧ
+U+07e8 ? # Character ߨ
+U+07e9 ? # Character ß©
+U+07ea ? # Character ߪ
+U+07eb ? # Character ß«
+U+07ec ? # Character ߬
+U+07ed ? # Character ß
+U+07ee ? # Character ß®
+U+07ef ? # Character ߯
+U+07f0 ? # Character ß°
+U+07f1 ? # Character ß±
+U+07f2 ? # Character ß²
+U+07f3 ? # Character ß³
+U+07f4 ? # Character ß´
+U+07f5 ? # Character ßµ
+U+07f6 ? # Character ߶
+U+07f7 ? # Character ß·
+U+07f8 ? # Character ߸
+U+07f9 ? # Character ß¹
+U+07fa ? # Character ߺ
+U+07fb ? # Character ß»
+U+07fc ? # Character ß¼
+U+07fd ? # Character ß½
+U+07fe ? # Character ß¾
+U+07ff ? # Character ß¿
diff --git a/resources/chars/latin1/row09.trans b/resources/chars/latin1/row09.trans
new file mode 100644
index 0000000..3a861d1
--- /dev/null
+++ b/resources/chars/latin1/row09.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+0900 ? # Character à¤
+#U+0901 mÌ # Character à¤
+#U+0902 á¹ # Character à¤
+#U+0903 ḥ # Character à¤
+U+0904 # Character à¤
+U+0905 a # Character à¤
+#U+0906 Ä # Character à¤
+U+0907 i # Character à¤
+#U+0908 Ä« # Character à¤
+U+0909 u # Character à¤
+#U+090a Å« # Character à¤
+#U+090b rÌ¥ # Character à¤
+#U+090c lÌ¥ # Character à¤
+#U+090d Ä # Character à¤
+U+090e e # Character à¤
+#U+090f Ä # Character à¤
+U+0910 ai # Character à¤
+#U+0911 Å # Character à¤
+U+0912 o # Character à¤
+#U+0913 Å # Character à¤
+U+0914 au # Character à¤
+U+0915 ka # Character à¤
+U+0916 kha # Character à¤
+U+0917 ga # Character à¤
+U+0918 gha # Character à¤
+#U+0919 á¹
a # Character à¤
+U+091a ca # Character à¤
+U+091b cha # Character à¤
+U+091c ja # Character à¤
+U+091d jha # Character à¤
+U+091e ña # Character à¤
+#U+091f á¹a # Character à¤
+#U+0920 á¹ha # Character à¤
+#U+0921 á¸a # Character ड
+#U+0922 á¸ha # Character ढ
+#U+0923 á¹a # Character ण
+U+0924 ta # Character त
+U+0925 tha # Character थ
+U+0926 da # Character द
+U+0927 dha # Character ध
+U+0928 na # Character न
+#U+0929 á¹a # Character ऩ
+U+092a pa # Character प
+U+092b pha # Character फ
+U+092c ba # Character ब
+U+092d bha # Character à¤
+U+092e ma # Character म
+U+092f ya # Character य
+U+0930 ra # Character र
+#U+0931 á¹a # Character ऱ
+U+0932 la # Character ल
+#U+0933 ḷa # Character ळ
+#U+0934 ḻa # Character ऴ
+U+0935 va # Character व
+#U+0936 Åa # Character श
+#U+0937 ṣa # Character ष
+U+0938 sa # Character स
+U+0939 ha # Character ह
+U+093a ? # Character ऺ
+U+093b ? # Character ऻ
+U+093c # Character ़
+#U+093d Ì # Character ऽ
+#U+093e ÌÄ # Character ा
+#U+093f Ìi # Character ि
+#U+0940 ÌÄ« # Character à¥
+#U+0941 Ìu # Character à¥
+#U+0942 ÌÅ« # Character à¥
+#U+0943 ÌrÌ¥ # Character à¥
+#U+0944 ÌlÌ¥ # Character à¥
+#U+0945 ÌÄ # Character à¥
+#U+0946 Ìe # Character à¥
+#U+0947 ÌÄ # Character à¥
+#U+0948 Ìai # Character à¥
+#U+0949 ÌÅ # Character à¥
+#U+094a Ìo # Character à¥
+#U+094b ÌÅ # Character à¥
+#U+094c Ìau # Character à¥
+U+094d # Character à¥
+U+094e ? # Character à¥
+U+094f ? # Character à¥
+U+0950 'om # Character à¥
+U+0951 ? # Character à¥
+U+0952 ? # Character à¥
+U+0953 # Character à¥
+U+0954 # Character à¥
+U+0955 ? # Character à¥
+U+0956 ? # Character à¥
+U+0957 ? # Character à¥
+U+0958 qa # Character à¥
+#U+0959 ḵáºa # Character à¥
+#U+095a Ä¡a # Character à¥
+U+095b za # Character à¥
+#U+095c á¹a # Character à¥
+#U+095d á¹ha # Character à¥
+U+095e fa # Character à¥
+#U+095f áºa # Character à¥
+#U+0960 rÌ¥Ì # Character à¥
+#U+0961 lÌ¥Ì # Character ॡ
+#U+0962 ÌrÌ¥Ì # Character ॢ
+#U+0963 ÌlÌ¥Ì # Character ॣ
+U+0964 ? # Character ।
+U+0965 ? # Character ॥
+U+0966 0 # Character ०
+U+0967 1 # Character १
+U+0968 2 # Character २
+U+0969 3 # Character ३
+U+096a 4 # Character ४
+U+096b 5 # Character ५
+U+096c 6 # Character ६
+U+096d 7 # Character à¥
+U+096e 8 # Character ८
+U+096f 9 # Character ९
+U+0970 ? # Character ॰
+U+0971 ? # Character ॱ
+U+0972 ? # Character ॲ
+U+0973 ? # Character ॳ
+U+0974 ? # Character ॴ
+U+0975 ? # Character ॵ
+U+0976 ? # Character ॶ
+U+0977 ? # Character ॷ
+U+0978 ? # Character ॸ
+U+0979 ? # Character ॹ
+U+097a ? # Character ॺ
+U+097b ? # Character ॻ
+U+097c ? # Character ॼ
+#U+097d Ê # Character ॽ
+U+097e ? # Character ॾ
+U+097f ? # Character ॿ
+U+0980 ? # Character à¦
+#U+0981 mÌ # Character à¦
+#U+0982 á¹ # Character à¦
+#U+0983 ḥ # Character à¦
+U+0984 ? # Character à¦
+U+0985 a # Character à¦
+#U+0986 Ä # Character à¦
+U+0987 i # Character à¦
+#U+0988 Ä« # Character à¦
+U+0989 u # Character à¦
+#U+098a Å« # Character à¦
+#U+098b rÌ¥ # Character à¦
+#U+098c lÌ¥ # Character à¦
+U+098d ? # Character à¦
+U+098e ? # Character à¦
+#U+098f Ä # Character à¦
+U+0990 ai # Character à¦
+U+0991 ? # Character à¦
+U+0992 ? # Character à¦
+#U+0993 Å # Character à¦
+U+0994 au # Character à¦
+U+0995 ka # Character à¦
+U+0996 kha # Character à¦
+U+0997 ga # Character à¦
+U+0998 gha # Character à¦
+#U+0999 á¹
a # Character à¦
+U+099a ca # Character à¦
+U+099b cha # Character à¦
+U+099c ja # Character à¦
+U+099d jha # Character à¦
+U+099e ña # Character à¦
+#U+099f á¹a # Character à¦
+#U+09a0 á¹ha # Character à¦
+#U+09a1 á¸a # Character ড
+#U+09a2 á¸ha # Character ঢ
+#U+09a3 á¹a # Character ণ
+U+09a4 ta # Character ত
+U+09a5 tha # Character থ
+U+09a6 da # Character দ
+U+09a7 dha # Character ধ
+U+09a8 na # Character ন
+U+09a9 ? # Character ঩
+U+09aa pa # Character প
+U+09ab pha # Character ফ
+U+09ac ba # Character ব
+U+09ad bha # Character à¦
+U+09ae ma # Character ম
+U+09af ya # Character য
+U+09b0 ra # Character র
+U+09b1 ? # Character ঱
+U+09b2 la # Character ল
+U+09b3 ? # Character ঳
+U+09b4 ? # Character ঴
+U+09b5 ? # Character ঵
+#U+09b6 Åa # Character শ
+#U+09b7 ṣa # Character ষ
+U+09b8 sa # Character স
+U+09b9 ha # Character হ
+U+09ba ? # Character ঺
+U+09bb ? # Character ঻
+U+09bc # Character ়
+#U+09bd Ì # Character ঽ
+#U+09be ÌÄ # Character া
+#U+09bf Ìi # Character ি
+#U+09c0 ÌÄ« # Character à§
+#U+09c1 Ìu # Character à§
+#U+09c2 ÌÅ« # Character à§
+#U+09c3 ÌrÌ¥ # Character à§
+#U+09c4 ÌlÌ¥ # Character à§
+U+09c5 ? # Character à§
+U+09c6 ? # Character à§
+#U+09c7 ÌÄ # Character à§
+#U+09c8 Ìai # Character à§
+U+09c9 ? # Character à§
+U+09ca ? # Character à§
+#U+09cb ÌÅ # Character à§
+#U+09cc Ìau # Character à§
+U+09cd # Character à§
+#U+09ce ṯ # Character à§
+U+09cf ? # Character à§
+U+09d0 ? # Character à§
+U+09d1 ? # Character à§
+U+09d2 ? # Character à§
+U+09d3 ? # Character à§
+U+09d4 ? # Character à§
+U+09d5 ? # Character à§
+U+09d6 ? # Character à§
+U+09d7 # Character à§
+U+09d8 ? # Character à§
+U+09d9 ? # Character à§
+U+09da ? # Character à§
+U+09db ? # Character à§
+#U+09dc á¹a # Character à§
+#U+09dd á¹ha # Character à§
+U+09de ? # Character à§
+#U+09df áºa # Character à§
+#U+09e0 rÌ¥Ì # Character à§
+#U+09e1 lÌ¥Ì # Character ৡ
+#U+09e2 ÌrÌ¥Ì # Character ৢ
+#U+09e3 ÌlÌ¥Ì # Character ৣ
+U+09e4 ? # Character ৤
+U+09e5 ? # Character ৥
+U+09e6 0 # Character ০
+U+09e7 1 # Character ১
+U+09e8 2 # Character ২
+U+09e9 3 # Character ৩
+U+09ea 4 # Character ৪
+U+09eb 5 # Character ৫
+U+09ec 6 # Character ৬
+U+09ed 7 # Character à§
+U+09ee 8 # Character ৮
+U+09ef 9 # Character ৯
+U+09f0 ra # Character ৰ
+U+09f1 ra # Character ৱ
+U+09f2 # Character ৲
+U+09f3 # Character ৳
+U+09f4 # Character ৴
+U+09f5 # Character ৵
+U+09f6 # Character ৶
+U+09f7 # Character ৷
+U+09f8 # Character ৸
+U+09f9 # Character ৹
+U+09fa # Character ৺
+U+09fb ? # Character ৻
+U+09fc ? # Character ৼ
+U+09fd ? # Character ৽
+U+09fe ? # Character ৾
+U+09ff ? # Character ৿
diff --git a/resources/chars/latin1/row0a.trans b/resources/chars/latin1/row0a.trans
new file mode 100644
index 0000000..0a2d31d
--- /dev/null
+++ b/resources/chars/latin1/row0a.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+0a00 ? # Character à¨
+#U+0a01 mÌ # Character à¨
+#U+0a02 á¹ # Character à¨
+U+0a03 ? # Character à¨
+U+0a04 ? # Character à¨
+U+0a05 a # Character à¨
+#U+0a06 Ä # Character à¨
+U+0a07 i # Character à¨
+#U+0a08 Ä« # Character à¨
+U+0a09 u # Character à¨
+#U+0a0a Å« # Character à¨
+U+0a0b ? # Character à¨
+U+0a0c ? # Character à¨
+U+0a0d ? # Character à¨
+U+0a0e ? # Character à¨
+#U+0a0f Ä # Character à¨
+U+0a10 ai # Character à¨
+U+0a11 ? # Character à¨
+U+0a12 ? # Character à¨
+#U+0a13 Å # Character à¨
+U+0a14 au # Character à¨
+U+0a15 ka # Character à¨
+U+0a16 kha # Character à¨
+U+0a17 ga # Character à¨
+U+0a18 gha # Character à¨
+#U+0a19 á¹
a # Character à¨
+U+0a1a ca # Character à¨
+U+0a1b cha # Character à¨
+U+0a1c ja # Character à¨
+U+0a1d jha # Character à¨
+U+0a1e ña # Character à¨
+#U+0a1f á¹a # Character à¨
+#U+0a20 á¹ha # Character à¨
+#U+0a21 á¸a # Character ਡ
+#U+0a22 á¸ha # Character ਢ
+#U+0a23 á¹a # Character ਣ
+U+0a24 ta # Character ਤ
+U+0a25 tha # Character ਥ
+U+0a26 da # Character ਦ
+U+0a27 dha # Character ਧ
+U+0a28 na # Character ਨ
+U+0a29 ? # Character ਩
+U+0a2a pa # Character ਪ
+U+0a2b pha # Character ਫ
+U+0a2c ba # Character ਬ
+U+0a2d bha # Character à¨
+U+0a2e ma # Character ਮ
+U+0a2f ya # Character ਯ
+U+0a30 ra # Character ਰ
+U+0a31 ? # Character ਱
+U+0a32 la # Character ਲ
+#U+0a33 ḻa # Character ਲ਼
+U+0a34 ? # Character ਴
+U+0a35 va # Character ਵ
+#U+0a36 Åa # Character ਸ਼
+U+0a37 ? # Character ਷
+U+0a38 sa # Character ਸ
+U+0a39 ha # Character ਹ
+U+0a3a ? # Character ਺
+U+0a3b ? # Character ਻
+U+0a3c # Character ਼
+U+0a3d ? # Character ਽
+#U+0a3e ÌÄ # Character ਾ
+#U+0a3f Ìi # Character ਿ
+#U+0a40 ÌÄ« # Character à©
+#U+0a41 Ìu # Character à©
+#U+0a42 ÌÅ« # Character à©
+U+0a43 ? # Character à©
+U+0a44 ? # Character à©
+U+0a45 ? # Character à©
+U+0a46 ? # Character à©
+#U+0a47 ÌÄ # Character à©
+#U+0a48 Ìai # Character à©
+U+0a49 ? # Character à©
+U+0a4a ? # Character à©
+#U+0a4b ÌÅ # Character à©
+#U+0a4c Ìau # Character à©
+U+0a4d # Character à©
+U+0a4e ? # Character à©
+U+0a4f ? # Character à©
+U+0a50 ? # Character à©
+U+0a51 ? # Character à©
+U+0a52 ? # Character à©
+U+0a53 ? # Character à©
+U+0a54 ? # Character à©
+U+0a55 ? # Character à©
+U+0a56 ? # Character à©
+U+0a57 ? # Character à©
+U+0a58 ? # Character à©
+#U+0a59 ḵáºa # Character à©
+#U+0a5a Ä¡a # Character à©
+U+0a5b za # Character à©
+#U+0a5c á¹a # Character à©
+U+0a5d ? # Character à©
+U+0a5e fa # Character à©
+U+0a5f ? # Character à©
+U+0a60 ? # Character à©
+U+0a61 ? # Character à©¡
+U+0a62 ? # Character à©¢
+U+0a63 ? # Character à©£
+U+0a64 ? # Character ੤
+U+0a65 ? # Character à©¥
+U+0a66 0 # Character ੦
+U+0a67 1 # Character ੧
+U+0a68 2 # Character ੨
+U+0a69 3 # Character à©©
+U+0a6a 4 # Character ੪
+U+0a6b 5 # Character à©«
+U+0a6c 6 # Character ੬
+U+0a6d 7 # Character à©
+U+0a6e 8 # Character à©®
+U+0a6f 9 # Character ੯
+U+0a70 # Character à©°
+U+0a71 # Character ੱ
+U+0a72 # Character ੲ
+U+0a73 # Character ੳ
+U+0a74 # Character à©´
+U+0a75 ? # Character ੵ
+U+0a76 ? # Character ੶
+U+0a77 ? # Character à©·
+U+0a78 ? # Character ੸
+U+0a79 ? # Character ੹
+U+0a7a ? # Character ੺
+U+0a7b ? # Character à©»
+U+0a7c ? # Character ੼
+U+0a7d ? # Character ੽
+U+0a7e ? # Character ੾
+U+0a7f ? # Character à©¿
+U+0a80 ? # Character àª
+#U+0a81 mÌ # Character àª
+#U+0a82 á¹ # Character àª
+#U+0a83 ḥ # Character àª
+U+0a84 ? # Character àª
+U+0a85 a # Character àª
+#U+0a86 Ä # Character àª
+U+0a87 i # Character àª
+#U+0a88 Ä« # Character àª
+U+0a89 u # Character àª
+#U+0a8a Å« # Character àª
+#U+0a8b rÌ¥ # Character àª
+#U+0a8c lÌ¥ # Character àª
+#U+0a8d Ä # Character àª
+U+0a8e ? # Character àª
+#U+0a8f Ä # Character àª
+U+0a90 ai # Character àª
+#U+0a91 Å # Character àª
+U+0a92 ? # Character àª
+#U+0a93 Å # Character àª
+U+0a94 au # Character àª
+U+0a95 ka # Character àª
+U+0a96 kha # Character àª
+U+0a97 ga # Character àª
+U+0a98 gha # Character àª
+#U+0a99 á¹
a # Character àª
+U+0a9a ca # Character àª
+U+0a9b cha # Character àª
+U+0a9c ja # Character àª
+U+0a9d jha # Character àª
+U+0a9e ña # Character àª
+#U+0a9f á¹a # Character àª
+#U+0aa0 á¹ha # Character àª
+#U+0aa1 á¸a # Character ડ
+#U+0aa2 á¸ha # Character ઢ
+#U+0aa3 á¹a # Character ણ
+U+0aa4 ta # Character ત
+U+0aa5 tha # Character થ
+U+0aa6 da # Character દ
+U+0aa7 dha # Character ધ
+U+0aa8 na # Character ન
+U+0aa9 ? # Character ઩
+U+0aaa pa # Character પ
+U+0aab pha # Character ફ
+U+0aac ba # Character બ
+U+0aad bha # Character àª
+U+0aae ma # Character મ
+U+0aaf ya # Character ય
+U+0ab0 ra # Character ર
+U+0ab1 ? # Character ઱
+U+0ab2 la # Character લ
+#U+0ab3 ḷa # Character ળ
+U+0ab4 ? # Character ઴
+U+0ab5 va # Character વ
+#U+0ab6 Åa # Character શ
+#U+0ab7 ṣa # Character ષ
+U+0ab8 sa # Character સ
+U+0ab9 ha # Character હ
+U+0aba ? # Character ઺
+U+0abb ? # Character ઻
+U+0abc # Character ઼
+#U+0abd Ì # Character ઽ
+#U+0abe ÌÄ # Character ા
+#U+0abf Ìi # Character િ
+#U+0ac0 ÌÄ« # Character à«
+#U+0ac1 Ìu # Character à«
+#U+0ac2 ÌÅ« # Character à«
+#U+0ac3 ÌrÌ¥ # Character à«
+#U+0ac4 ÌlÌ¥ # Character à«
+#U+0ac5 ÌÄ # Character à«
+U+0ac6 ? # Character à«
+#U+0ac7 ÌÄ # Character à«
+#U+0ac8 Ìai # Character à«
+#U+0ac9 ÌÅ # Character à«
+U+0aca ? # Character à«
+#U+0acb ÌÅ # Character à«
+#U+0acc Ìau # Character à«
+U+0acd # Character à«
+U+0ace ? # Character à«
+U+0acf ? # Character à«
+U+0ad0 'om # Character à«
+U+0ad1 ? # Character à«
+U+0ad2 ? # Character à«
+U+0ad3 ? # Character à«
+U+0ad4 ? # Character à«
+U+0ad5 ? # Character à«
+U+0ad6 ? # Character à«
+U+0ad7 ? # Character à«
+U+0ad8 ? # Character à«
+U+0ad9 ? # Character à«
+U+0ada ? # Character à«
+U+0adb ? # Character à«
+U+0adc ? # Character à«
+U+0add ? # Character à«
+U+0ade ? # Character à«
+U+0adf ? # Character à«
+#U+0ae0 rÌ¥Ì # Character à«
+#U+0ae1 lÌ¥Ì # Character à«¡
+U+0ae2 ? # Character à«¢
+U+0ae3 ? # Character à«£
+U+0ae4 ? # Character ૤
+U+0ae5 ? # Character à«¥
+U+0ae6 0 # Character ૦
+U+0ae7 1 # Character ૧
+U+0ae8 2 # Character ૨
+U+0ae9 3 # Character à«©
+U+0aea 4 # Character ૪
+U+0aeb 5 # Character à««
+U+0aec 6 # Character ૬
+U+0aed 7 # Character à«
+U+0aee 8 # Character à«®
+U+0aef 9 # Character ૯
+U+0af0 ? # Character à«°
+U+0af1 ? # Character ૱
+U+0af2 ? # Character ૲
+U+0af3 ? # Character ૳
+U+0af4 ? # Character à«´
+U+0af5 ? # Character ૵
+U+0af6 ? # Character ૶
+U+0af7 ? # Character à«·
+U+0af8 ? # Character ૸
+U+0af9 ? # Character ૹ
+U+0afa ? # Character ૺ
+U+0afb ? # Character à«»
+U+0afc ? # Character ૼ
+U+0afd ? # Character ૽
+U+0afe ? # Character ૾
+U+0aff ? # Character à«¿
diff --git a/resources/chars/latin1/row0b.trans b/resources/chars/latin1/row0b.trans
new file mode 100644
index 0000000..b4feb35
--- /dev/null
+++ b/resources/chars/latin1/row0b.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+0b00 ? # Character à¬
+#U+0b01 mÌ # Character à¬
+#U+0b02 á¹ # Character à¬
+#U+0b03 ḥ # Character à¬
+U+0b04 ? # Character à¬
+U+0b05 a # Character à¬
+#U+0b06 Ä # Character à¬
+U+0b07 i # Character à¬
+#U+0b08 Ä« # Character à¬
+U+0b09 u # Character à¬
+#U+0b0a Å« # Character à¬
+#U+0b0b rÌ¥ # Character à¬
+#U+0b0c lÌ¥ # Character à¬
+U+0b0d ? # Character à¬
+U+0b0e ? # Character à¬
+#U+0b0f Ä # Character à¬
+U+0b10 ai # Character à¬
+U+0b11 ? # Character à¬
+U+0b12 ? # Character à¬
+#U+0b13 Å # Character à¬
+U+0b14 au # Character à¬
+U+0b15 ka # Character à¬
+U+0b16 kha # Character à¬
+U+0b17 ga # Character à¬
+U+0b18 gha # Character à¬
+#U+0b19 á¹
a # Character à¬
+U+0b1a ca # Character à¬
+U+0b1b cha # Character à¬
+U+0b1c ja # Character à¬
+U+0b1d jha # Character à¬
+U+0b1e ña # Character à¬
+#U+0b1f á¹a # Character à¬
+#U+0b20 á¹ha # Character à¬
+#U+0b21 á¸a # Character ଡ
+#U+0b22 á¸ha # Character ଢ
+#U+0b23 á¹a # Character ଣ
+U+0b24 ta # Character ତ
+U+0b25 tha # Character ଥ
+U+0b26 da # Character ଦ
+U+0b27 dha # Character ଧ
+U+0b28 na # Character ନ
+U+0b29 ? # Character ଩
+U+0b2a pa # Character ପ
+U+0b2b pha # Character ଫ
+U+0b2c ba # Character ବ
+U+0b2d bha # Character à¬
+U+0b2e ma # Character ମ
+U+0b2f ya # Character ଯ
+U+0b30 ra # Character ର
+U+0b31 ? # Character ଱
+U+0b32 la # Character ଲ
+#U+0b33 ḷa # Character ଳ
+U+0b34 ? # Character ଴
+U+0b35 va # Character ଵ
+#U+0b36 Åa # Character ଶ
+#U+0b37 ṣa # Character ଷ
+U+0b38 sa # Character ସ
+U+0b39 ha # Character ହ
+U+0b3a ? # Character ଺
+U+0b3b ? # Character ଻
+U+0b3c # Character ଼
+#U+0b3d Ì # Character ଽ
+#U+0b3e ÌÄ # Character ା
+#U+0b3f Ìi # Character ି
+#U+0b40 ÌÄ« # Character à
+#U+0b41 Ìu # Character à
+#U+0b42 ÌÅ« # Character à
+#U+0b43 ÌrÌ¥ # Character à
+U+0b44 ? # Character à
+U+0b45 ? # Character à
+U+0b46 ? # Character à
+#U+0b47 ÌÄ # Character à
+#U+0b48 Ìai # Character à
+U+0b49 ? # Character à
+U+0b4a ? # Character à
+#U+0b4b ÌÅ # Character à
+#U+0b4c Ìau # Character à
+U+0b4d # Character à
+U+0b4e ? # Character à
+U+0b4f ? # Character à
+U+0b50 ? # Character à
+U+0b51 ? # Character à
+U+0b52 ? # Character à
+U+0b53 ? # Character à
+U+0b54 ? # Character à
+U+0b55 ? # Character à
+U+0b56 # Character à
+U+0b57 # Character à
+U+0b58 ? # Character à
+U+0b59 ? # Character à
+U+0b5a ? # Character à
+U+0b5b ? # Character à
+#U+0b5c á¹a # Character à
+#U+0b5d á¹ha # Character à
+U+0b5e ? # Character à
+#U+0b5f áºa # Character à
+#U+0b60 rÌ¥Ì # Character à
+#U+0b61 lÌ¥Ì # Character à¡
+U+0b62 ? # Character à¢
+U+0b63 ? # Character à£
+U+0b64 ? # Character à¤
+U+0b65 ? # Character à¥
+U+0b66 0 # Character à¦
+U+0b67 1 # Character à§
+U+0b68 2 # Character à¨
+U+0b69 3 # Character à©
+U+0b6a 4 # Character àª
+U+0b6b 5 # Character à«
+U+0b6c 6 # Character à¬
+U+0b6d 7 # Character à
+U+0b6e 8 # Character à®
+U+0b6f 9 # Character à¯
+U+0b70 # Character à°
+#U+0b71 áºa # Character à±
+U+0b72 ? # Character à²
+U+0b73 ? # Character à³
+U+0b74 ? # Character à´
+U+0b75 ? # Character àµ
+U+0b76 ? # Character à¶
+U+0b77 ? # Character à·
+U+0b78 ? # Character à¸
+U+0b79 ? # Character à¹
+U+0b7a ? # Character àº
+U+0b7b ? # Character à»
+U+0b7c ? # Character à¼
+U+0b7d ? # Character à½
+U+0b7e ? # Character à¾
+U+0b7f ? # Character à¿
+U+0b80 ? # Character à®
+U+0b81 ? # Character à®
+#U+0b82 á¹ # Character à®
+#U+0b83 ḥ # Character à®
+U+0b84 ? # Character à®
+U+0b85 a # Character à®
+#U+0b86 Ä # Character à®
+U+0b87 i # Character à®
+#U+0b88 Ä« # Character à®
+U+0b89 u # Character à®
+#U+0b8a Å« # Character à®
+U+0b8b ? # Character à®
+U+0b8c ? # Character à®
+U+0b8d ? # Character à®
+U+0b8e e # Character à®
+#U+0b8f Ä # Character à®
+U+0b90 ai # Character à®
+U+0b91 ? # Character à®
+U+0b92 o # Character à®
+#U+0b93 Å # Character à®
+U+0b94 au # Character à®
+U+0b95 ka # Character à®
+U+0b96 ? # Character à®
+U+0b97 ? # Character à®
+U+0b98 ? # Character à®
+#U+0b99 á¹
a # Character à®
+U+0b9a ca # Character à®
+U+0b9b ? # Character à®
+U+0b9c ja # Character à®
+U+0b9d ? # Character à®
+U+0b9e ña # Character à®
+#U+0b9f á¹a # Character à®
+U+0ba0 ? # Character à®
+U+0ba1 ? # Character ஡
+U+0ba2 ? # Character ஢
+#U+0ba3 á¹a # Character ண
+U+0ba4 ta # Character த
+U+0ba5 ? # Character ஥
+U+0ba6 ? # Character ஦
+U+0ba7 ? # Character ஧
+U+0ba8 na # Character ந
+#U+0ba9 á¹a # Character ன
+U+0baa pa # Character ப
+U+0bab ? # Character ஫
+U+0bac ? # Character ஬
+U+0bad ? # Character à®
+U+0bae ma # Character à®®
+U+0baf ya # Character ய
+U+0bb0 ra # Character à®°
+#U+0bb1 á¹a # Character à®±
+U+0bb2 la # Character ல
+#U+0bb3 ḷa # Character ள
+#U+0bb4 ḻa # Character ழ
+U+0bb5 va # Character வ
+#U+0bb6 Åa # Character ஶ
+#U+0bb7 á¹£a # Character à®·
+U+0bb8 sa # Character ஸ
+U+0bb9 ha # Character ஹ
+U+0bba ? # Character ஺
+U+0bbb ? # Character à®»
+U+0bbc ? # Character ஼
+U+0bbd ? # Character ஽
+#U+0bbe ÌÄ # Character ா
+#U+0bbf Ìi # Character ி
+#U+0bc0 ÌÄ« # Character à¯
+#U+0bc1 Ìu # Character à¯
+#U+0bc2 ÌÅ« # Character à¯
+U+0bc3 ? # Character à¯
+U+0bc4 ? # Character à¯
+U+0bc5 ? # Character à¯
+#U+0bc6 Ìe # Character à¯
+#U+0bc7 ÌÄ # Character à¯
+#U+0bc8 Ìai # Character à¯
+U+0bc9 ? # Character à¯
+#U+0bca Ìo # Character à¯
+#U+0bcb ÌÅ # Character à¯
+#U+0bcc Ìau # Character à¯
+U+0bcd # Character à¯
+U+0bce ? # Character à¯
+U+0bcf ? # Character à¯
+U+0bd0 ? # Character à¯
+U+0bd1 ? # Character à¯
+U+0bd2 ? # Character à¯
+U+0bd3 ? # Character à¯
+U+0bd4 ? # Character à¯
+U+0bd5 ? # Character à¯
+U+0bd6 ? # Character à¯
+U+0bd7 # Character à¯
+U+0bd8 ? # Character à¯
+U+0bd9 ? # Character à¯
+U+0bda ? # Character à¯
+U+0bdb ? # Character à¯
+U+0bdc ? # Character à¯
+U+0bdd ? # Character à¯
+U+0bde ? # Character à¯
+U+0bdf ? # Character à¯
+U+0be0 ? # Character à¯
+U+0be1 ? # Character ௡
+U+0be2 ? # Character ௢
+U+0be3 ? # Character ௣
+U+0be4 ? # Character ௤
+U+0be5 ? # Character ௥
+U+0be6 0 # Character ௦
+U+0be7 1 # Character ௧
+U+0be8 2 # Character ௨
+U+0be9 3 # Character ௩
+U+0bea 4 # Character ௪
+U+0beb 5 # Character ௫
+U+0bec 6 # Character ௬
+U+0bed 7 # Character à¯
+U+0bee 8 # Character ௮
+U+0bef 9 # Character ௯
+U+0bf0 10 # Character ௰
+U+0bf1 100 # Character ௱
+U+0bf2 1000 # Character ௲
+U+0bf3 ? # Character ௳
+U+0bf4 ? # Character ௴
+U+0bf5 ? # Character ௵
+U+0bf6 ? # Character ௶
+U+0bf7 ? # Character ௷
+U+0bf8 ? # Character ௸
+U+0bf9 ? # Character ௹
+U+0bfa ? # Character ௺
+U+0bfb ? # Character ௻
+U+0bfc ? # Character ௼
+U+0bfd ? # Character ௽
+U+0bfe ? # Character ௾
+U+0bff ? # Character ௿
diff --git a/resources/chars/latin1/row0c.trans b/resources/chars/latin1/row0c.trans
new file mode 100644
index 0000000..b9a5e59
--- /dev/null
+++ b/resources/chars/latin1/row0c.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+0c00 ? # Character à°
+#U+0c01 mÌ # Character à°
+#U+0c02 á¹ # Character à°
+#U+0c03 ḥ # Character à°
+U+0c04 ? # Character à°
+U+0c05 a # Character à°
+#U+0c06 Ä # Character à°
+U+0c07 i # Character à°
+#U+0c08 Ä« # Character à°
+U+0c09 u # Character à°
+#U+0c0a Å« # Character à°
+#U+0c0b rÌ¥ # Character à°
+#U+0c0c lÌ¥ # Character à°
+U+0c0d ? # Character à°
+U+0c0e e # Character à°
+#U+0c0f Ä # Character à°
+U+0c10 ai # Character à°
+U+0c11 ? # Character à°
+U+0c12 o # Character à°
+#U+0c13 Å # Character à°
+U+0c14 au # Character à°
+U+0c15 ka # Character à°
+U+0c16 kha # Character à°
+U+0c17 ga # Character à°
+U+0c18 gha # Character à°
+#U+0c19 á¹
a # Character à°
+U+0c1a ca # Character à°
+U+0c1b cha # Character à°
+U+0c1c ja # Character à°
+U+0c1d jha # Character à°
+U+0c1e ña # Character à°
+#U+0c1f á¹a # Character à°
+#U+0c20 á¹ha # Character à°
+#U+0c21 á¸a # Character à°¡
+#U+0c22 á¸ha # Character à°¢
+#U+0c23 á¹a # Character à°£
+U+0c24 ta # Character à°¤
+U+0c25 tha # Character à°¥
+U+0c26 da # Character à°¦
+U+0c27 dha # Character à°§
+U+0c28 na # Character à°¨
+U+0c29 ? # Character à°©
+U+0c2a pa # Character à°ª
+U+0c2b pha # Character à°«
+U+0c2c ba # Character à°¬
+U+0c2d bha # Character à°
+U+0c2e ma # Character à°®
+U+0c2f ya # Character à°¯
+U+0c30 ra # Character à°°
+#U+0c31 á¹a # Character à°±
+U+0c32 la # Character à°²
+#U+0c33 ḷa # Character ళ
+U+0c34 ? # Character à°´
+U+0c35 va # Character à°µ
+#U+0c36 Åa # Character à°¶
+#U+0c37 á¹£a # Character à°·
+U+0c38 sa # Character à°¸
+U+0c39 ha # Character à°¹
+U+0c3a ? # Character à°º
+U+0c3b ? # Character à°»
+U+0c3c ? # Character à°¼
+U+0c3d ? # Character à°½
+#U+0c3e ÌÄ # Character à°¾
+#U+0c3f Ìi # Character à°¿
+#U+0c40 ÌÄ« # Character à±
+#U+0c41 Ìu # Character à±
+#U+0c42 ÌÅ« # Character à±
+#U+0c43 ÌrÌ¥ # Character à±
+#U+0c44 ÌlÌ¥ # Character à±
+U+0c45 ? # Character à±
+#U+0c46 Ìe # Character à±
+#U+0c47 ÌÄ # Character à±
+#U+0c48 Ìai # Character à±
+U+0c49 ? # Character à±
+#U+0c4a Ìo # Character à±
+#U+0c4b ÌÅ # Character à±
+#U+0c4c Ìau # Character à±
+U+0c4d # Character à±
+U+0c4e ? # Character à±
+U+0c4f ? # Character à±
+U+0c50 ? # Character à±
+U+0c51 ? # Character à±
+U+0c52 ? # Character à±
+U+0c53 ? # Character à±
+U+0c54 ? # Character à±
+U+0c55 # Character à±
+U+0c56 # Character à±
+U+0c57 ? # Character à±
+U+0c58 ? # Character à±
+U+0c59 ? # Character à±
+U+0c5a ? # Character à±
+U+0c5b ? # Character à±
+U+0c5c ? # Character à±
+U+0c5d ? # Character à±
+U+0c5e ? # Character à±
+U+0c5f ? # Character à±
+#U+0c60 rÌ¥Ì # Character à±
+#U+0c61 lÌ¥Ì # Character ౡ
+U+0c62 ? # Character à±¢
+U+0c63 ? # Character à±£
+U+0c64 ? # Character ౤
+U+0c65 ? # Character à±¥
+U+0c66 0 # Character ౦
+U+0c67 1 # Character ౧
+U+0c68 2 # Character ౨
+U+0c69 3 # Character ౩
+U+0c6a 4 # Character ౪
+U+0c6b 5 # Character ౫
+U+0c6c 6 # Character ౬
+U+0c6d 7 # Character à±
+U+0c6e 8 # Character à±®
+U+0c6f 9 # Character ౯
+U+0c70 ? # Character à±°
+U+0c71 ? # Character à±±
+U+0c72 ? # Character à±²
+U+0c73 ? # Character à±³
+U+0c74 ? # Character à±´
+U+0c75 ? # Character à±µ
+U+0c76 ? # Character ౶
+U+0c77 ? # Character à±·
+U+0c78 ? # Character ౸
+U+0c79 ? # Character à±¹
+U+0c7a ? # Character ౺
+U+0c7b ? # Character à±»
+U+0c7c ? # Character à±¼
+U+0c7d ? # Character à±½
+U+0c7e ? # Character à±¾
+U+0c7f ? # Character ౿
+U+0c80 ? # Character à²
+U+0c81 ? # Character à²
+#U+0c82 á¹ # Character à²
+#U+0c83 ḥ # Character à²
+U+0c84 ? # Character à²
+U+0c85 a # Character à²
+#U+0c86 Ä # Character à²
+U+0c87 i # Character à²
+#U+0c88 Ä« # Character à²
+U+0c89 u # Character à²
+#U+0c8a Å« # Character à²
+#U+0c8b rÌ¥ # Character à²
+#U+0c8c lÌ¥ # Character à²
+U+0c8d ? # Character à²
+U+0c8e e # Character à²
+#U+0c8f Ä # Character à²
+U+0c90 ai # Character à²
+U+0c91 ? # Character à²
+U+0c92 o # Character à²
+#U+0c93 Å # Character à²
+U+0c94 au # Character à²
+U+0c95 ka # Character à²
+U+0c96 kha # Character à²
+U+0c97 ga # Character à²
+U+0c98 gha # Character à²
+#U+0c99 á¹
a # Character à²
+U+0c9a ca # Character à²
+U+0c9b cha # Character à²
+U+0c9c ja # Character à²
+U+0c9d jha # Character à²
+U+0c9e ña # Character à²
+#U+0c9f á¹a # Character à²
+#U+0ca0 á¹ha # Character à²
+#U+0ca1 á¸a # Character ಡ
+#U+0ca2 á¸ha # Character ಢ
+#U+0ca3 á¹a # Character ಣ
+U+0ca4 ta # Character ತ
+U+0ca5 tha # Character ಥ
+U+0ca6 da # Character ದ
+U+0ca7 dha # Character ಧ
+U+0ca8 na # Character ನ
+U+0ca9 ? # Character ಩
+U+0caa pa # Character ಪ
+U+0cab pha # Character ಫ
+U+0cac ba # Character ಬ
+U+0cad bha # Character à²
+U+0cae ma # Character ಮ
+U+0caf ya # Character ಯ
+U+0cb0 ra # Character ರ
+#U+0cb1 á¹a # Character ಱ
+U+0cb2 la # Character ಲ
+#U+0cb3 ḷa # Character ಳ
+U+0cb4 ? # Character ಴
+U+0cb5 va # Character ವ
+#U+0cb6 Åa # Character ಶ
+#U+0cb7 ṣa # Character ಷ
+U+0cb8 sa # Character ಸ
+U+0cb9 ha # Character ಹ
+U+0cba ? # Character ಺
+U+0cbb ? # Character ಻
+U+0cbc # Character ಼
+#U+0cbd Ì # Character ಽ
+#U+0cbe ÌÄ # Character ಾ
+#U+0cbf Ìi # Character ಿ
+#U+0cc0 ÌÄ« # Character à³
+#U+0cc1 Ìu # Character à³
+#U+0cc2 ÌÅ« # Character à³
+#U+0cc3 ÌrÌ¥ # Character à³
+#U+0cc4 ÌlÌ¥ # Character à³
+U+0cc5 ? # Character à³
+#U+0cc6 Ìe # Character à³
+#U+0cc7 ÌÄ # Character à³
+#U+0cc8 Ìai # Character à³
+U+0cc9 ? # Character à³
+#U+0cca Ìo # Character à³
+#U+0ccb ÌÅ # Character à³
+#U+0ccc Ìau # Character à³
+U+0ccd # Character à³
+U+0cce ? # Character à³
+U+0ccf ? # Character à³
+U+0cd0 ? # Character à³
+U+0cd1 ? # Character à³
+U+0cd2 ? # Character à³
+U+0cd3 ? # Character à³
+U+0cd4 ? # Character à³
+U+0cd5 # Character à³
+U+0cd6 # Character à³
+U+0cd7 ? # Character à³
+U+0cd8 ? # Character à³
+U+0cd9 ? # Character à³
+U+0cda ? # Character à³
+U+0cdb ? # Character à³
+U+0cdc ? # Character à³
+U+0cdd ? # Character à³
+#U+0cde ḻa # Character à³
+U+0cdf ? # Character à³
+#U+0ce0 rÌ¥Ì # Character à³
+#U+0ce1 lÌ¥Ì # Character ೡ
+U+0ce2 ? # Character à³¢
+U+0ce3 ? # Character à³£
+U+0ce4 ? # Character ೤
+U+0ce5 ? # Character à³¥
+U+0ce6 0 # Character ೦
+U+0ce7 1 # Character ೧
+U+0ce8 2 # Character ೨
+U+0ce9 3 # Character ೩
+U+0cea 4 # Character ೪
+U+0ceb 5 # Character ೫
+U+0cec 6 # Character ೬
+U+0ced 7 # Character à³
+U+0cee 8 # Character à³®
+U+0cef 9 # Character ೯
+U+0cf0 ? # Character à³°
+U+0cf1 ? # Character à³±
+U+0cf2 ? # Character à³²
+U+0cf3 ? # Character à³³
+U+0cf4 ? # Character à³´
+U+0cf5 ? # Character à³µ
+U+0cf6 ? # Character ೶
+U+0cf7 ? # Character à³·
+U+0cf8 ? # Character ೸
+U+0cf9 ? # Character à³¹
+U+0cfa ? # Character ೺
+U+0cfb ? # Character à³»
+U+0cfc ? # Character à³¼
+U+0cfd ? # Character à³½
+U+0cfe ? # Character à³¾
+U+0cff ? # Character ೿
diff --git a/resources/chars/latin1/row0d.trans b/resources/chars/latin1/row0d.trans
new file mode 100644
index 0000000..57e79ad
--- /dev/null
+++ b/resources/chars/latin1/row0d.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+0d00 ? # Character à´
+U+0d01 ? # Character à´
+#U+0d02 á¹ # Character à´
+#U+0d03 ḥ # Character à´
+U+0d04 ? # Character à´
+U+0d05 a # Character à´
+#U+0d06 Ä # Character à´
+U+0d07 i # Character à´
+#U+0d08 Ä« # Character à´
+U+0d09 u # Character à´
+#U+0d0a Å« # Character à´
+#U+0d0b rÌ¥ # Character à´
+#U+0d0c lÌ¥ # Character à´
+U+0d0d ? # Character à´
+U+0d0e e # Character à´
+#U+0d0f Ä # Character à´
+U+0d10 ai # Character à´
+U+0d11 ? # Character à´
+U+0d12 o # Character à´
+#U+0d13 Å # Character à´
+U+0d14 au # Character à´
+U+0d15 ka # Character à´
+U+0d16 kha # Character à´
+U+0d17 ga # Character à´
+U+0d18 gha # Character à´
+#U+0d19 á¹
a # Character à´
+U+0d1a ca # Character à´
+U+0d1b cha # Character à´
+U+0d1c ja # Character à´
+U+0d1d jha # Character à´
+U+0d1e ña # Character à´
+#U+0d1f á¹a # Character à´
+#U+0d20 á¹ha # Character à´
+#U+0d21 á¸a # Character à´¡
+#U+0d22 á¸ha # Character à´¢
+#U+0d23 á¹a # Character à´£
+U+0d24 ta # Character à´¤
+U+0d25 tha # Character à´¥
+U+0d26 da # Character à´¦
+U+0d27 dha # Character à´§
+U+0d28 na # Character à´¨
+U+0d29 ? # Character à´©
+U+0d2a pa # Character à´ª
+U+0d2b pha # Character à´«
+U+0d2c ba # Character à´¬
+U+0d2d bha # Character à´
+U+0d2e ma # Character à´®
+U+0d2f ya # Character à´¯
+U+0d30 ra # Character à´°
+#U+0d31 á¹a # Character à´±
+U+0d32 la # Character à´²
+#U+0d33 ḷa # Character ള
+#U+0d34 ḻa # Character ഴ
+U+0d35 va # Character à´µ
+#U+0d36 Åa # Character à´¶
+#U+0d37 á¹£a # Character à´·
+U+0d38 sa # Character à´¸
+U+0d39 ha # Character à´¹
+U+0d3a ? # Character à´º
+U+0d3b ? # Character à´»
+U+0d3c ? # Character à´¼
+U+0d3d ? # Character à´½
+#U+0d3e ÌÄ # Character à´¾
+#U+0d3f Ìi # Character à´¿
+#U+0d40 ÌÄ« # Character àµ
+#U+0d41 Ìu # Character àµ
+#U+0d42 ÌÅ« # Character àµ
+#U+0d43 ÌrÌ¥ # Character àµ
+U+0d44 ? # Character àµ
+U+0d45 ? # Character àµ
+#U+0d46 Ìe # Character àµ
+#U+0d47 ÌÄ # Character àµ
+#U+0d48 Ìai # Character àµ
+U+0d49 ? # Character àµ
+#U+0d4a ÌeÄ # Character àµ
+#U+0d4b ÌÄÄ # Character àµ
+#U+0d4c Ìe # Character àµ
+U+0d4d # Character àµ
+U+0d4e ? # Character àµ
+U+0d4f ? # Character àµ
+U+0d50 ? # Character àµ
+U+0d51 ? # Character àµ
+U+0d52 ? # Character àµ
+U+0d53 ? # Character àµ
+U+0d54 ? # Character àµ
+U+0d55 ? # Character àµ
+U+0d56 ? # Character àµ
+U+0d57 # Character àµ
+U+0d58 ? # Character àµ
+U+0d59 ? # Character àµ
+U+0d5a ? # Character àµ
+U+0d5b ? # Character àµ
+U+0d5c ? # Character àµ
+U+0d5d ? # Character àµ
+U+0d5e ? # Character àµ
+U+0d5f ? # Character àµ
+#U+0d60 rÌ¥Ì # Character àµ
+#U+0d61 lÌ¥Ì # Character ൡ
+U+0d62 ? # Character ൢ
+U+0d63 ? # Character ൣ
+U+0d64 ? # Character ൤
+U+0d65 ? # Character ൥
+U+0d66 0 # Character ൦
+U+0d67 1 # Character ൧
+U+0d68 2 # Character ൨
+U+0d69 3 # Character ൩
+U+0d6a 4 # Character ൪
+U+0d6b 5 # Character ൫
+U+0d6c 6 # Character ൬
+U+0d6d 7 # Character àµ
+U+0d6e 8 # Character ൮
+U+0d6f 9 # Character ൯
+U+0d70 ? # Character ൰
+U+0d71 ? # Character ൱
+U+0d72 ? # Character ൲
+U+0d73 ? # Character ൳
+U+0d74 ? # Character ൴
+U+0d75 ? # Character ൵
+U+0d76 ? # Character ൶
+U+0d77 ? # Character ൷
+U+0d78 ? # Character ൸
+U+0d79 ? # Character ൹
+U+0d7a ? # Character ൺ
+U+0d7b ? # Character ൻ
+U+0d7c ? # Character ർ
+U+0d7d ? # Character ൽ
+U+0d7e ? # Character ൾ
+U+0d7f ? # Character ൿ
+U+0d80 ? # Character à¶
+U+0d81 ? # Character à¶
+U+0d82 ? # Character à¶
+U+0d83 ? # Character à¶
+U+0d84 ? # Character à¶
+U+0d85 ? # Character à¶
+U+0d86 ? # Character à¶
+U+0d87 ? # Character à¶
+U+0d88 ? # Character à¶
+U+0d89 ? # Character à¶
+U+0d8a ? # Character à¶
+U+0d8b ? # Character à¶
+U+0d8c ? # Character à¶
+U+0d8d ? # Character à¶
+U+0d8e ? # Character à¶
+U+0d8f ? # Character à¶
+U+0d90 ? # Character à¶
+U+0d91 ? # Character à¶
+U+0d92 ? # Character à¶
+U+0d93 ? # Character à¶
+U+0d94 ? # Character à¶
+U+0d95 ? # Character à¶
+U+0d96 ? # Character à¶
+U+0d97 ? # Character à¶
+U+0d98 ? # Character à¶
+U+0d99 ? # Character à¶
+U+0d9a ? # Character à¶
+U+0d9b ? # Character à¶
+U+0d9c ? # Character à¶
+U+0d9d ? # Character à¶
+U+0d9e ? # Character à¶
+U+0d9f ? # Character à¶
+U+0da0 ? # Character à¶
+U+0da1 ? # Character ඡ
+U+0da2 ? # Character ජ
+U+0da3 ? # Character ඣ
+U+0da4 ? # Character ඤ
+U+0da5 ? # Character ඥ
+U+0da6 ? # Character ඦ
+U+0da7 ? # Character ට
+U+0da8 ? # Character ඨ
+U+0da9 ? # Character ඩ
+U+0daa ? # Character ඪ
+U+0dab ? # Character ණ
+U+0dac ? # Character ඬ
+U+0dad ? # Character à¶
+U+0dae ? # Character ථ
+U+0daf ? # Character ද
+U+0db0 ? # Character ධ
+U+0db1 ? # Character න
+U+0db2 ? # Character ඲
+U+0db3 ? # Character ඳ
+U+0db4 ? # Character ප
+U+0db5 ? # Character ඵ
+U+0db6 ? # Character බ
+U+0db7 ? # Character භ
+U+0db8 ? # Character ම
+U+0db9 ? # Character ඹ
+U+0dba ? # Character ය
+U+0dbb ? # Character ර
+U+0dbc ? # Character ඼
+U+0dbd ? # Character ල
+U+0dbe ? # Character ඾
+U+0dbf ? # Character ඿
+U+0dc0 ? # Character à·
+U+0dc1 ? # Character à·
+U+0dc2 ? # Character à·
+U+0dc3 ? # Character à·
+U+0dc4 ? # Character à·
+U+0dc5 ? # Character à·
+U+0dc6 ? # Character à·
+U+0dc7 ? # Character à·
+U+0dc8 ? # Character à·
+U+0dc9 ? # Character à·
+U+0dca ? # Character à·
+U+0dcb ? # Character à·
+U+0dcc ? # Character à·
+U+0dcd ? # Character à·
+U+0dce ? # Character à·
+U+0dcf ? # Character à·
+U+0dd0 ? # Character à·
+U+0dd1 ? # Character à·
+U+0dd2 ? # Character à·
+U+0dd3 ? # Character à·
+U+0dd4 ? # Character à·
+U+0dd5 ? # Character à·
+U+0dd6 ? # Character à·
+U+0dd7 ? # Character à·
+U+0dd8 ? # Character à·
+U+0dd9 ? # Character à·
+U+0dda ? # Character à·
+U+0ddb ? # Character à·
+U+0ddc ? # Character à·
+U+0ddd ? # Character à·
+U+0dde ? # Character à·
+U+0ddf ? # Character à·
+U+0de0 ? # Character à·
+U+0de1 ? # Character à·¡
+U+0de2 ? # Character à·¢
+U+0de3 ? # Character à·£
+U+0de4 ? # Character à·¤
+U+0de5 ? # Character à·¥
+U+0de6 ? # Character à·¦
+U+0de7 ? # Character à·§
+U+0de8 ? # Character à·¨
+U+0de9 ? # Character à·©
+U+0dea ? # Character à·ª
+U+0deb ? # Character à·«
+U+0dec ? # Character à·¬
+U+0ded ? # Character à·
+U+0dee ? # Character à·®
+U+0def ? # Character à·¯
+U+0df0 ? # Character à·°
+U+0df1 ? # Character à·±
+U+0df2 ? # Character à·²
+U+0df3 ? # Character à·³
+U+0df4 ? # Character à·´
+U+0df5 ? # Character à·µ
+U+0df6 ? # Character à·¶
+U+0df7 ? # Character à··
+U+0df8 ? # Character à·¸
+U+0df9 ? # Character à·¹
+U+0dfa ? # Character à·º
+U+0dfb ? # Character à·»
+U+0dfc ? # Character à·¼
+U+0dfd ? # Character à·½
+U+0dfe ? # Character à·¾
+U+0dff ? # Character à·¿
diff --git a/resources/chars/latin1/row0e.trans b/resources/chars/latin1/row0e.trans
new file mode 100644
index 0000000..c796db0
--- /dev/null
+++ b/resources/chars/latin1/row0e.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+0e00 ? # Character à¸
+U+0e01 k # Character à¸
+#U+0e02 kÌh # Character à¸
+#U+0e03 ḳÌh # Character à¸
+U+0e04 kh # Character à¸
+#U+0e05 kʹh # Character à¸
+#U+0e06 ḳh # Character à¸
+U+0e07 ng # Character à¸
+U+0e08 c # Character à¸
+#U+0e09 cÌh # Character à¸
+U+0e0a ch # Character à¸
+U+0e0b s # Character à¸
+#U+0e0c cÌ£h # Character à¸
+#U+0e0d ỵ # Character à¸
+#U+0e0e Ḡ# Character à¸
+#U+0e0f tÌ© # Character à¸
+#U+0e10 á¹Ìh # Character à¸
+#U+0e11 ṯh # Character à¸
+#U+0e12 tʹh # Character à¸
+#U+0e13 á¹ # Character à¸
+U+0e14 d # Character à¸
+U+0e15 t # Character à¸
+#U+0e16 tÌh # Character à¸
+U+0e17 th # Character à¸
+#U+0e18 á¹h # Character à¸
+U+0e19 n # Character à¸
+U+0e1a b # Character à¸
+U+0e1b p # Character à¸
+#U+0e1c pÌh # Character à¸
+#U+0e1d fÌ # Character à¸
+U+0e1e ph # Character à¸
+U+0e1f f # Character à¸
+#U+0e20 pÌ£h # Character à¸
+U+0e21 m # Character ม
+U+0e22 y # Character ย
+U+0e23 r # Character ร
+U+0e24 v # Character ฤ
+U+0e25 l # Character ล
+#U+0e26 Š# Character ฦ
+U+0e27 w # Character ว
+#U+0e28 á¹£Ì # Character ศ
+#U+0e29 sÌʹ # Character ษ
+#U+0e2a sÌ # Character ส
+#U+0e2b hÌ # Character ห
+#U+0e2c ḷ # Character ฬ
+U+0e2d x # Character à¸
+#U+0e2e ḥ # Character ฮ
+#U+0e2f ⡠# Character ฯ
+U+0e30 a # Character ะ
+#U+0e31 ạ # Character ั
+#U+0e32 Ä # Character า
+#U+0e33 ả # Character ำ
+U+0e34 i # Character ิ
+#U+0e35 ī # Character ี
+#U+0e36 ụ # Character ึ
+#U+0e37 á»¥Ì # Character ื
+U+0e38 u # Character ุ
+#U+0e39 ū # Character ู
+#U+0e3a Ë # Character ฺ
+U+0e3b ? # Character ฻
+U+0e3c ? # Character ฼
+U+0e3d ? # Character ฽
+U+0e3e ? # Character ฾
+U+0e3f ? # Character ฿
+U+0e40 e # Character à¹
+U+0e41 æ # Character à¹
+U+0e42 o # Character à¹
+#U+0e43 ı # Character à¹
+#U+0e44 á» # Character à¹
+#U+0e45 ɨ # Character à¹
+U+0e46 « # Character à¹
+#U+0e47 Ì # Character à¹
+#U+0e48 Ì # Character à¹
+#U+0e49 Ì # Character à¹
+#U+0e4a Ì # Character à¹
+#U+0e4b Ì # Character à¹
+#U+0e4c Ì # Character à¹
+#U+0e4d Ì # Character à¹
+U+0e4e ~ # Character à¹
+U+0e4f § # Character à¹
+U+0e50 0 # Character à¹
+U+0e51 1 # Character à¹
+U+0e52 2 # Character à¹
+U+0e53 3 # Character à¹
+U+0e54 4 # Character à¹
+U+0e55 5 # Character à¹
+U+0e56 6 # Character à¹
+U+0e57 7 # Character à¹
+U+0e58 8 # Character à¹
+U+0e59 9 # Character à¹
+U+0e5a || # Character à¹
+U+0e5b » # Character à¹
+U+0e5c ? # Character à¹
+U+0e5d ? # Character à¹
+U+0e5e ? # Character à¹
+U+0e5f ? # Character à¹
+U+0e60 ? # Character à¹
+U+0e61 ? # Character ๡
+U+0e62 ? # Character ๢
+U+0e63 ? # Character ๣
+U+0e64 ? # Character ๤
+U+0e65 ? # Character ๥
+U+0e66 ? # Character ๦
+U+0e67 ? # Character ๧
+U+0e68 ? # Character ๨
+U+0e69 ? # Character ๩
+U+0e6a ? # Character ๪
+U+0e6b ? # Character ๫
+U+0e6c ? # Character ๬
+U+0e6d ? # Character à¹
+U+0e6e ? # Character ๮
+U+0e6f ? # Character ๯
+U+0e70 ? # Character ๰
+U+0e71 ? # Character ๱
+U+0e72 ? # Character ๲
+U+0e73 ? # Character ๳
+U+0e74 ? # Character ๴
+U+0e75 ? # Character ๵
+U+0e76 ? # Character ๶
+U+0e77 ? # Character ๷
+U+0e78 ? # Character ๸
+U+0e79 ? # Character ๹
+U+0e7a ? # Character ๺
+U+0e7b ? # Character ๻
+U+0e7c ? # Character ๼
+U+0e7d ? # Character ๽
+U+0e7e ? # Character ๾
+U+0e7f ? # Character ๿
+U+0e80 ? # Character àº
+U+0e81 ? # Character àº
+U+0e82 ? # Character àº
+U+0e83 ? # Character àº
+U+0e84 ? # Character àº
+U+0e85 ? # Character àº
+U+0e86 ? # Character àº
+U+0e87 ? # Character àº
+U+0e88 ? # Character àº
+U+0e89 ? # Character àº
+U+0e8a ? # Character àº
+U+0e8b ? # Character àº
+U+0e8c ? # Character àº
+U+0e8d ? # Character àº
+U+0e8e ? # Character àº
+U+0e8f ? # Character àº
+U+0e90 ? # Character àº
+U+0e91 ? # Character àº
+U+0e92 ? # Character àº
+U+0e93 ? # Character àº
+U+0e94 ? # Character àº
+U+0e95 ? # Character àº
+U+0e96 ? # Character àº
+U+0e97 ? # Character àº
+U+0e98 ? # Character àº
+U+0e99 ? # Character àº
+U+0e9a ? # Character àº
+U+0e9b ? # Character àº
+U+0e9c ? # Character àº
+U+0e9d ? # Character àº
+U+0e9e ? # Character àº
+U+0e9f ? # Character àº
+U+0ea0 ? # Character àº
+U+0ea1 ? # Character ມ
+U+0ea2 ? # Character ຢ
+U+0ea3 ? # Character ຣ
+U+0ea4 ? # Character ຤
+U+0ea5 ? # Character ລ
+U+0ea6 ? # Character ຦
+U+0ea7 ? # Character ວ
+U+0ea8 ? # Character ຨ
+U+0ea9 ? # Character ຩ
+U+0eaa ? # Character ສ
+U+0eab ? # Character ຫ
+U+0eac ? # Character ຬ
+U+0ead ? # Character àº
+U+0eae ? # Character ຮ
+U+0eaf ? # Character ຯ
+U+0eb0 ? # Character ະ
+U+0eb1 ? # Character ັ
+U+0eb2 ? # Character າ
+U+0eb3 ? # Character ຳ
+U+0eb4 ? # Character ິ
+U+0eb5 ? # Character ີ
+U+0eb6 ? # Character ຶ
+U+0eb7 ? # Character ື
+U+0eb8 ? # Character ຸ
+U+0eb9 ? # Character ູ
+U+0eba ? # Character ຺
+U+0ebb ? # Character ົ
+U+0ebc ? # Character ຼ
+U+0ebd ? # Character ຽ
+U+0ebe ? # Character ຾
+U+0ebf ? # Character ຿
+U+0ec0 ? # Character à»
+U+0ec1 ? # Character à»
+U+0ec2 ? # Character à»
+U+0ec3 ? # Character à»
+U+0ec4 ? # Character à»
+U+0ec5 ? # Character à»
+U+0ec6 ? # Character à»
+U+0ec7 ? # Character à»
+U+0ec8 ? # Character à»
+U+0ec9 ? # Character à»
+U+0eca ? # Character à»
+U+0ecb ? # Character à»
+U+0ecc ? # Character à»
+U+0ecd ? # Character à»
+U+0ece ? # Character à»
+U+0ecf ? # Character à»
+U+0ed0 ? # Character à»
+U+0ed1 ? # Character à»
+U+0ed2 ? # Character à»
+U+0ed3 ? # Character à»
+U+0ed4 ? # Character à»
+U+0ed5 ? # Character à»
+U+0ed6 ? # Character à»
+U+0ed7 ? # Character à»
+U+0ed8 ? # Character à»
+U+0ed9 ? # Character à»
+U+0eda ? # Character à»
+U+0edb ? # Character à»
+U+0edc ? # Character à»
+U+0edd ? # Character à»
+U+0ede ? # Character à»
+U+0edf ? # Character à»
+U+0ee0 ? # Character à»
+U+0ee1 ? # Character ໡
+U+0ee2 ? # Character ໢
+U+0ee3 ? # Character ໣
+U+0ee4 ? # Character ໤
+U+0ee5 ? # Character ໥
+U+0ee6 ? # Character ໦
+U+0ee7 ? # Character ໧
+U+0ee8 ? # Character ໨
+U+0ee9 ? # Character ໩
+U+0eea ? # Character ໪
+U+0eeb ? # Character ໫
+U+0eec ? # Character ໬
+U+0eed ? # Character à»
+U+0eee ? # Character à»®
+U+0eef ? # Character ໯
+U+0ef0 ? # Character à»°
+U+0ef1 ? # Character à»±
+U+0ef2 ? # Character ໲
+U+0ef3 ? # Character ໳
+U+0ef4 ? # Character à»´
+U+0ef5 ? # Character ໵
+U+0ef6 ? # Character ໶
+U+0ef7 ? # Character à»·
+U+0ef8 ? # Character ໸
+U+0ef9 ? # Character ໹
+U+0efa ? # Character ໺
+U+0efb ? # Character à»»
+U+0efc ? # Character ໼
+U+0efd ? # Character ໽
+U+0efe ? # Character ໾
+U+0eff ? # Character ໿
diff --git a/resources/chars/latin1/row10.trans b/resources/chars/latin1/row10.trans
new file mode 100644
index 0000000..db557eb
--- /dev/null
+++ b/resources/chars/latin1/row10.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+1000 ? # Character á
+U+1001 ? # Character á
+U+1002 ? # Character á
+U+1003 ? # Character á
+U+1004 ? # Character á
+U+1005 ? # Character á
+U+1006 ? # Character á
+U+1007 ? # Character á
+U+1008 ? # Character á
+U+1009 ? # Character á
+U+100a ? # Character á
+U+100b ? # Character á
+U+100c ? # Character á
+U+100d ? # Character á
+U+100e ? # Character á
+U+100f ? # Character á
+U+1010 ? # Character á
+U+1011 ? # Character á
+U+1012 ? # Character á
+U+1013 ? # Character á
+U+1014 ? # Character á
+U+1015 ? # Character á
+U+1016 ? # Character á
+U+1017 ? # Character á
+U+1018 ? # Character á
+U+1019 ? # Character á
+U+101a ? # Character á
+U+101b ? # Character á
+U+101c ? # Character á
+U+101d ? # Character á
+U+101e ? # Character á
+U+101f ? # Character á
+U+1020 ? # Character á
+U+1021 ? # Character á¡
+U+1022 ? # Character á¢
+U+1023 ? # Character á£
+U+1024 ? # Character á¤
+U+1025 ? # Character á¥
+U+1026 ? # Character á¦
+U+1027 ? # Character á§
+U+1028 ? # Character á¨
+U+1029 ? # Character á©
+U+102a ? # Character áª
+U+102b ? # Character á«
+U+102c ? # Character á¬
+U+102d ? # Character á
+U+102e ? # Character á®
+U+102f ? # Character á¯
+U+1030 ? # Character á°
+U+1031 ? # Character á±
+U+1032 ? # Character á²
+U+1033 ? # Character á³
+U+1034 ? # Character á´
+U+1035 ? # Character áµ
+U+1036 ? # Character á¶
+U+1037 ? # Character á·
+U+1038 ? # Character á¸
+U+1039 ? # Character á¹
+U+103a ? # Character áº
+U+103b ? # Character á»
+U+103c ? # Character á¼
+U+103d ? # Character á½
+U+103e ? # Character á¾
+U+103f ? # Character á¿
+U+1040 ? # Character á
+U+1041 ? # Character á
+U+1042 ? # Character á
+U+1043 ? # Character á
+U+1044 ? # Character á
+U+1045 ? # Character á
+U+1046 ? # Character á
+U+1047 ? # Character á
+U+1048 ? # Character á
+U+1049 ? # Character á
+U+104a ? # Character á
+U+104b ? # Character á
+U+104c ? # Character á
+U+104d ? # Character á
+U+104e ? # Character á
+U+104f ? # Character á
+U+1050 ? # Character á
+U+1051 ? # Character á
+U+1052 ? # Character á
+U+1053 ? # Character á
+U+1054 ? # Character á
+U+1055 ? # Character á
+U+1056 ? # Character á
+U+1057 ? # Character á
+U+1058 ? # Character á
+U+1059 ? # Character á
+U+105a ? # Character á
+U+105b ? # Character á
+U+105c ? # Character á
+U+105d ? # Character á
+U+105e ? # Character á
+U+105f ? # Character á
+U+1060 ? # Character á
+U+1061 ? # Character á¡
+U+1062 ? # Character á¢
+U+1063 ? # Character á£
+U+1064 ? # Character á¤
+U+1065 ? # Character á¥
+U+1066 ? # Character á¦
+U+1067 ? # Character á§
+U+1068 ? # Character á¨
+U+1069 ? # Character á©
+U+106a ? # Character áª
+U+106b ? # Character á«
+U+106c ? # Character á¬
+U+106d ? # Character á
+U+106e ? # Character á®
+U+106f ? # Character á¯
+U+1070 ? # Character á°
+U+1071 ? # Character á±
+U+1072 ? # Character á²
+U+1073 ? # Character á³
+U+1074 ? # Character á´
+U+1075 ? # Character áµ
+U+1076 ? # Character á¶
+U+1077 ? # Character á·
+U+1078 ? # Character á¸
+U+1079 ? # Character á¹
+U+107a ? # Character áº
+U+107b ? # Character á»
+U+107c ? # Character á¼
+U+107d ? # Character á½
+U+107e ? # Character á¾
+U+107f ? # Character á¿
+U+1080 ? # Character á
+U+1081 ? # Character á
+U+1082 ? # Character á
+U+1083 ? # Character á
+U+1084 ? # Character á
+U+1085 ? # Character á
+U+1086 ? # Character á
+U+1087 ? # Character á
+U+1088 ? # Character á
+U+1089 ? # Character á
+U+108a ? # Character á
+U+108b ? # Character á
+U+108c ? # Character á
+U+108d ? # Character á
+U+108e ? # Character á
+U+108f ? # Character á
+U+1090 ? # Character á
+U+1091 ? # Character á
+U+1092 ? # Character á
+U+1093 ? # Character á
+U+1094 ? # Character á
+U+1095 ? # Character á
+U+1096 ? # Character á
+U+1097 ? # Character á
+U+1098 ? # Character á
+U+1099 ? # Character á
+U+109a ? # Character á
+U+109b ? # Character á
+U+109c ? # Character á
+U+109d ? # Character á
+U+109e ? # Character á
+U+109f ? # Character á
+U+10a0 ? # Character á
+U+10a1 ? # Character á¡
+U+10a2 ? # Character á¢
+U+10a3 ? # Character á£
+U+10a4 ? # Character á¤
+U+10a5 ? # Character á¥
+U+10a6 ? # Character á¦
+U+10a7 ? # Character á§
+U+10a8 ? # Character á¨
+U+10a9 ? # Character á©
+U+10aa ? # Character áª
+U+10ab ? # Character á«
+U+10ac ? # Character á¬
+U+10ad ? # Character á
+U+10ae ? # Character á®
+U+10af ? # Character á¯
+U+10b0 ? # Character á°
+U+10b1 ? # Character á±
+U+10b2 ? # Character á²
+U+10b3 ? # Character á³
+U+10b4 ? # Character á´
+U+10b5 ? # Character áµ
+U+10b6 ? # Character á¶
+U+10b7 ? # Character á·
+U+10b8 ? # Character á¸
+U+10b9 ? # Character á¹
+U+10ba ? # Character áº
+U+10bb ? # Character á»
+U+10bc ? # Character á¼
+U+10bd ? # Character á½
+U+10be ? # Character á¾
+U+10bf ? # Character á¿
+U+10c0 ? # Character á
+U+10c1 ? # Character á
+U+10c2 ? # Character á
+U+10c3 ? # Character á
+U+10c4 ? # Character á
+U+10c5 ? # Character á
+U+10c6 ? # Character á
+U+10c7 ? # Character á
+U+10c8 ? # Character á
+U+10c9 ? # Character á
+U+10ca ? # Character á
+U+10cb ? # Character á
+U+10cc ? # Character á
+U+10cd ? # Character á
+U+10ce ? # Character á
+U+10cf ? # Character á
+U+10d0 a # Character á
+U+10d1 b # Character á
+U+10d2 g # Character á
+U+10d3 d # Character á
+U+10d4 e # Character á
+U+10d5 v # Character á
+U+10d6 z # Character á
+U+10d7 t # Character á
+U+10d8 i # Character á
+#U+10d9 kʼ # Character á
+U+10da l # Character á
+U+10db m # Character á
+U+10dc n # Character á
+U+10dd o # Character á
+#U+10de pʼ # Character á
+U+10df zh # Character á
+U+10e0 r # Character á
+U+10e1 s # Character á¡
+#U+10e2 tʼ # Character á¢
+U+10e3 u # Character á£
+U+10e4 p # Character á¤
+U+10e5 k # Character á¥
+U+10e6 gh # Character á¦
+#U+10e7 qʼ # Character á§
+U+10e8 sh # Character á¨
+U+10e9 ch # Character á©
+U+10ea ts # Character áª
+U+10eb dz # Character á«
+#U+10ec tsʼ # Character á¬
+#U+10ed chʼ # Character á
+U+10ee kh # Character á®
+U+10ef j # Character á¯
+U+10f0 h # Character á°
+U+10f1 ? # Character á±
+U+10f2 ? # Character á²
+#U+10f3 Åi # Character á³
+U+10f4 q # Character á´
+U+10f5 ? # Character áµ
+U+10f6 ? # Character á¶
+U+10f7 ? # Character á·
+U+10f8 ? # Character á¸
+U+10f9 ? # Character á¹
+U+10fa ? # Character áº
+U+10fb ? # Character á»
+U+10fc ? # Character á¼
+U+10fd ? # Character á½
+U+10fe ? # Character á¾
+U+10ff ? # Character á¿
diff --git a/resources/chars/latin1/row11.trans b/resources/chars/latin1/row11.trans
new file mode 100644
index 0000000..a8be137
--- /dev/null
+++ b/resources/chars/latin1/row11.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+1100 g # Character á
+U+1101 kk # Character á
+U+1102 n # Character á
+U+1103 d # Character á
+U+1104 tt # Character á
+U+1105 l # Character á
+U+1106 m # Character á
+U+1107 b # Character á
+U+1108 pp # Character á
+U+1109 s # Character á
+U+110a ss # Character á
+U+110b # Character á
+U+110c j # Character á
+U+110d jj # Character á
+U+110e ch # Character á
+U+110f k # Character á
+U+1110 t # Character á
+U+1111 p # Character á
+U+1112 h # Character á
+U+1113 ? # Character á
+U+1114 ? # Character á
+U+1115 ? # Character á
+U+1116 ? # Character á
+U+1117 ? # Character á
+U+1118 ? # Character á
+U+1119 ? # Character á
+U+111a ? # Character á
+U+111b ? # Character á
+U+111c ? # Character á
+U+111d ? # Character á
+U+111e ? # Character á
+U+111f ? # Character á
+U+1120 ? # Character á
+U+1121 ? # Character á¡
+U+1122 ? # Character á¢
+U+1123 ? # Character á£
+U+1124 ? # Character á¤
+U+1125 ? # Character á¥
+U+1126 ? # Character á¦
+U+1127 ? # Character á§
+U+1128 ? # Character á¨
+U+1129 ? # Character á©
+U+112a ? # Character áª
+U+112b ? # Character á«
+U+112c ? # Character á¬
+U+112d ? # Character á
+U+112e ? # Character á®
+U+112f ? # Character á¯
+U+1130 ? # Character á°
+U+1131 ? # Character á±
+U+1132 ? # Character á²
+U+1133 ? # Character á³
+U+1134 ? # Character á´
+U+1135 ? # Character áµ
+U+1136 ? # Character á¶
+U+1137 ? # Character á·
+U+1138 ? # Character á¸
+U+1139 ? # Character á¹
+U+113a ? # Character áº
+U+113b ? # Character á»
+U+113c ? # Character á¼
+U+113d ? # Character á½
+U+113e ? # Character á¾
+U+113f ? # Character á¿
+U+1140 ? # Character á
+U+1141 ? # Character á
+U+1142 ? # Character á
+U+1143 ? # Character á
+U+1144 ? # Character á
+U+1145 ? # Character á
+U+1146 ? # Character á
+U+1147 ? # Character á
+U+1148 ? # Character á
+U+1149 ? # Character á
+U+114a ? # Character á
+U+114b ? # Character á
+U+114c ? # Character á
+U+114d ? # Character á
+U+114e ? # Character á
+U+114f ? # Character á
+U+1150 ? # Character á
+U+1151 ? # Character á
+U+1152 ? # Character á
+U+1153 ? # Character á
+U+1154 ? # Character á
+U+1155 ? # Character á
+U+1156 ? # Character á
+U+1157 ? # Character á
+U+1158 ? # Character á
+U+1159 ? # Character á
+U+115a ? # Character á
+U+115b ? # Character á
+U+115c ? # Character á
+U+115d ? # Character á
+U+115e ? # Character á
+U+115f ? # Character á
+U+1160 ? # Character á
+U+1161 a # Character á
¡
+U+1162 ae # Character á
¢
+U+1163 ya # Character á
£
+U+1164 yae # Character á
¤
+U+1165 eo # Character á
¥
+U+1166 e # Character á
¦
+U+1167 yeo # Character á
§
+U+1168 ye # Character á
¨
+U+1169 o # Character á
©
+U+116a wa # Character á
ª
+U+116b wae # Character á
«
+U+116c oe # Character á
¬
+U+116d yo # Character á
+U+116e u # Character á
®
+U+116f wo # Character á
¯
+U+1170 we # Character á
°
+U+1171 wi # Character á
±
+U+1172 yu # Character á
²
+U+1173 eu # Character á
³
+U+1174 ui # Character á
´
+U+1175 i # Character á
µ
+U+1176 ? # Character á
¶
+U+1177 ? # Character á
·
+U+1178 ? # Character á
¸
+U+1179 ? # Character á
¹
+U+117a ? # Character á
º
+U+117b ? # Character á
»
+U+117c ? # Character á
¼
+U+117d ? # Character á
½
+U+117e ? # Character á
¾
+U+117f ? # Character á
¿
+U+1180 ? # Character á
+U+1181 ? # Character á
+U+1182 ? # Character á
+U+1183 ? # Character á
+U+1184 ? # Character á
+U+1185 ? # Character á
+U+1186 ? # Character á
+U+1187 ? # Character á
+U+1188 ? # Character á
+U+1189 ? # Character á
+U+118a ? # Character á
+U+118b ? # Character á
+U+118c ? # Character á
+U+118d ? # Character á
+U+118e ? # Character á
+U+118f ? # Character á
+U+1190 ? # Character á
+U+1191 ? # Character á
+U+1192 ? # Character á
+U+1193 ? # Character á
+U+1194 ? # Character á
+U+1195 ? # Character á
+U+1196 ? # Character á
+U+1197 ? # Character á
+U+1198 ? # Character á
+U+1199 ? # Character á
+U+119a ? # Character á
+U+119b ? # Character á
+U+119c ? # Character á
+U+119d ? # Character á
+U+119e ? # Character á
+U+119f ? # Character á
+U+11a0 ? # Character á
+U+11a1 ? # Character á¡
+U+11a2 ? # Character á¢
+U+11a3 ? # Character á£
+U+11a4 ? # Character á¤
+U+11a5 ? # Character á¥
+U+11a6 ? # Character á¦
+U+11a7 ? # Character á§
+U+11a8 g # Character á¨
+U+11a9 kk # Character á©
+U+11aa gs # Character áª
+U+11ab n # Character á«
+U+11ac nj # Character á¬
+U+11ad nh # Character á
+U+11ae d # Character á®
+U+11af l # Character á¯
+U+11b0 lg # Character á°
+U+11b1 lm # Character á±
+U+11b2 lb # Character á²
+U+11b3 ls # Character á³
+U+11b4 lt # Character á´
+U+11b5 lp # Character áµ
+U+11b6 lh # Character á¶
+U+11b7 m # Character á·
+U+11b8 b # Character á¸
+U+11b9 bs # Character á¹
+U+11ba s # Character áº
+U+11bb ss # Character á»
+U+11bc ng # Character á¼
+U+11bd j # Character á½
+U+11be ch # Character á¾
+U+11bf k # Character á¿
+U+11c0 t # Character á
+U+11c1 p # Character á
+U+11c2 h # Character á
+U+11c3 ? # Character á
+U+11c4 ? # Character á
+U+11c5 ? # Character á
+U+11c6 ? # Character á
+U+11c7 ? # Character á
+U+11c8 ? # Character á
+U+11c9 ? # Character á
+U+11ca ? # Character á
+U+11cb ? # Character á
+U+11cc ? # Character á
+U+11cd ? # Character á
+U+11ce ? # Character á
+U+11cf ? # Character á
+U+11d0 ? # Character á
+U+11d1 ? # Character á
+U+11d2 ? # Character á
+U+11d3 ? # Character á
+U+11d4 ? # Character á
+U+11d5 ? # Character á
+U+11d6 ? # Character á
+U+11d7 ? # Character á
+U+11d8 ? # Character á
+U+11d9 ? # Character á
+U+11da ? # Character á
+U+11db ? # Character á
+U+11dc ? # Character á
+U+11dd ? # Character á
+U+11de ? # Character á
+U+11df ? # Character á
+U+11e0 ? # Character á
+U+11e1 ? # Character á¡
+U+11e2 ? # Character á¢
+U+11e3 ? # Character á£
+U+11e4 ? # Character á¤
+U+11e5 ? # Character á¥
+U+11e6 ? # Character á¦
+U+11e7 ? # Character á§
+U+11e8 ? # Character á¨
+U+11e9 ? # Character á©
+U+11ea ? # Character áª
+U+11eb ? # Character á«
+U+11ec ? # Character á¬
+U+11ed ? # Character á
+U+11ee ? # Character á®
+U+11ef ? # Character á¯
+U+11f0 ? # Character á°
+U+11f1 ? # Character á±
+U+11f2 ? # Character á²
+U+11f3 ? # Character á³
+U+11f4 ? # Character á´
+U+11f5 ? # Character áµ
+U+11f6 ? # Character á¶
+U+11f7 ? # Character á·
+U+11f8 ? # Character á¸
+U+11f9 ? # Character á¹
+U+11fa ? # Character áº
+U+11fb ? # Character á»
+U+11fc ? # Character á¼
+U+11fd ? # Character á½
+U+11fe ? # Character á¾
+U+11ff ? # Character á¿
diff --git a/resources/chars/latin1/row1f.trans b/resources/chars/latin1/row1f.trans
new file mode 100644
index 0000000..621540f
--- /dev/null
+++ b/resources/chars/latin1/row1f.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+1f00 a # Character á¼
+U+1f01 ha # Character á¼
+U+1f02 Ã # Character á¼
+U+1f03 hà # Character á¼
+U+1f04 á # Character á¼
+U+1f05 há # Character á¼
+U+1f06 â # Character á¼
+U+1f07 hâ # Character á¼
+U+1f08 A # Character á¼
+U+1f09 HA # Character á¼
+U+1f0a à # Character á¼
+U+1f0b HÃ # Character á¼
+U+1f0c à # Character á¼
+U+1f0d HÃ # Character á¼
+U+1f0e à # Character á¼
+U+1f0f HÃ # Character á¼
+U+1f10 e # Character á¼
+U+1f11 he # Character á¼
+U+1f12 è # Character á¼
+U+1f13 hè # Character á¼
+U+1f14 é # Character á¼
+U+1f15 hé # Character á¼
+U+1f16 ? # Character á¼
+U+1f17 ? # Character á¼
+U+1f18 E # Character á¼
+U+1f19 HE # Character á¼
+U+1f1a à # Character á¼
+U+1f1b HÃ # Character á¼
+U+1f1c à # Character á¼
+U+1f1d HÃ # Character á¼
+U+1f1e ? # Character á¼
+U+1f1f ? # Character á¼
+#U+1f20 Ä # Character á¼
+#U+1f21 hÄ # Character ἡ
+#U+1f22 Ḡ# Character ἢ
+#U+1f23 hḠ# Character ἣ
+#U+1f24 Ḡ# Character ἤ
+#U+1f25 hḠ# Character ἥ
+#U+1f26 ÄÌ # Character ἦ
+#U+1f27 hÄÌ # Character ἧ
+#U+1f28 Ä # Character Ἠ
+#U+1f29 HÄ # Character Ἡ
+#U+1f2a Ḡ# Character Ἢ
+#U+1f2b HḠ# Character Ἣ
+#U+1f2c Ḡ# Character Ἤ
+#U+1f2d HḠ# Character á¼
+#U+1f2e ÄÌ # Character á¼®
+#U+1f2f HÄÌ # Character Ἧ
+U+1f30 i # Character á¼°
+U+1f31 hi # Character á¼±
+U+1f32 ì # Character ἲ
+U+1f33 hì # Character ἳ
+U+1f34 Ã # Character á¼´
+U+1f35 hà # Character ἵ
+U+1f36 î # Character ἶ
+U+1f37 hî # Character ἷ
+U+1f38 I # Character Ἰ
+U+1f39 HI # Character á¼¹
+U+1f3a à # Character Ἲ
+U+1f3b HÃ # Character á¼»
+U+1f3c à # Character Ἴ
+U+1f3d HÃ # Character á¼½
+U+1f3e à # Character Ἶ
+U+1f3f Hà # Character Ἷ
+U+1f40 o # Character á½
+U+1f41 ho # Character á½
+U+1f42 ò # Character á½
+U+1f43 hò # Character á½
+U+1f44 ó # Character á½
+U+1f45 hó # Character á½
+U+1f46 ? # Character á½
+U+1f47 ? # Character á½
+U+1f48 O # Character á½
+U+1f49 HO # Character á½
+U+1f4a à # Character á½
+U+1f4b HÃ # Character á½
+U+1f4c à # Character á½
+U+1f4d HÃ # Character á½
+U+1f4e ? # Character á½
+U+1f4f ? # Character á½
+U+1f50 y # Character á½
+U+1f51 hy # Character á½
+#U+1f52 ỳ # Character á½
+#U+1f53 hỳ # Character á½
+U+1f54 ý # Character á½
+U+1f55 hý # Character á½
+#U+1f56 Å· # Character á½
+#U+1f57 hÅ· # Character á½
+U+1f58 ? # Character á½
+U+1f59 HY # Character á½
+U+1f5a ? # Character á½
+#U+1f5b HỲ # Character á½
+U+1f5c ? # Character á½
+U+1f5d HÃ # Character á½
+U+1f5e ? # Character á½
+#U+1f5f HŶ # Character á½
+#U+1f60 Å # Character á½
+#U+1f61 hŠ# Character ὡ
+#U+1f62 á¹ # Character á½¢
+#U+1f63 há¹ # Character á½£
+#U+1f64 Ṡ# Character ὤ
+#U+1f65 há¹ # Character á½¥
+#U+1f66 ÅÌ # Character ὦ
+#U+1f67 hÅÌ # Character ὧ
+#U+1f68 Š# Character Ὠ
+#U+1f69 HŠ# Character Ὡ
+#U+1f6a Ṡ# Character Ὢ
+#U+1f6b HṠ# Character Ὣ
+#U+1f6c Ṡ# Character Ὤ
+#U+1f6d Há¹ # Character á½
+#U+1f6e ÅÌ # Character á½®
+#U+1f6f HÅÌ # Character Ὧ
+U+1f70 Ã # Character á½°
+U+1f71 á # Character ά
+U+1f72 è # Character ὲ
+U+1f73 é # Character έ
+#U+1f74 Ḡ# Character ὴ
+#U+1f75 Ḡ# Character ή
+U+1f76 ì # Character ὶ
+U+1f77 Ã # Character á½·
+U+1f78 ò # Character ὸ
+U+1f79 ó # Character ό
+#U+1f7a ỳ # Character ὺ
+U+1f7b ý # Character ύ
+#U+1f7c á¹ # Character á½¼
+#U+1f7d á¹ # Character á½½
+U+1f7e ? # Character á½¾
+U+1f7f ? # Character ὿
+#U+1f80 Äi # Character á¾
+#U+1f81 hÄi # Character á¾
+#U+1f82 ÄÌi # Character á¾
+#U+1f83 hÄÌi # Character á¾
+#U+1f84 ÄÌi # Character á¾
+#U+1f85 hÄÌi # Character á¾
+#U+1f86 ÄÌi # Character á¾
+#U+1f87 hÄÌi # Character á¾
+#U+1f88 ÄI # Character á¾
+#U+1f89 HÄI # Character á¾
+#U+1f8a ÄÌI # Character á¾
+#U+1f8b HÄÌI # Character á¾
+#U+1f8c ÄÌI # Character á¾
+#U+1f8d HÄÌI # Character á¾
+#U+1f8e ÄÌI # Character á¾
+#U+1f8f HÄÌI # Character á¾
+#U+1f90 Äi # Character á¾
+#U+1f91 hÄi # Character á¾
+#U+1f92 á¸i # Character á¾
+#U+1f93 há¸i # Character á¾
+#U+1f94 á¸i # Character á¾
+#U+1f95 há¸i # Character á¾
+#U+1f96 ÄÌi # Character á¾
+#U+1f97 hÄÌi # Character á¾
+#U+1f98 ÄI # Character á¾
+#U+1f99 HÄI # Character á¾
+#U+1f9a á¸I # Character á¾
+#U+1f9b Há¸I # Character á¾
+#U+1f9c á¸I # Character á¾
+#U+1f9d Há¸I # Character á¾
+#U+1f9e ÄÌI # Character á¾
+#U+1f9f HÄÌI # Character á¾
+#U+1fa0 Åi # Character á¾
+#U+1fa1 hÅi # Character ᾡ
+#U+1fa2 á¹i # Character á¾¢
+#U+1fa3 há¹i # Character á¾£
+#U+1fa4 á¹i # Character ᾤ
+#U+1fa5 há¹i # Character á¾¥
+#U+1fa6 ÅÌi # Character ᾦ
+#U+1fa7 hÅÌi # Character ᾧ
+#U+1fa8 ÅI # Character ᾨ
+#U+1fa9 HÅI # Character ᾩ
+#U+1faa á¹I # Character ᾪ
+#U+1fab Há¹I # Character ᾫ
+#U+1fac á¹I # Character ᾬ
+#U+1fad Há¹I # Character á¾
+#U+1fae ÅÌI # Character á¾®
+#U+1faf HÅÌI # Character ᾯ
+#U+1fb0 Ä # Character á¾°
+#U+1fb1 Ä # Character á¾±
+#U+1fb2 ÄÌi # Character á¾²
+#U+1fb3 Äi # Character á¾³
+#U+1fb4 ÄÌi # Character á¾´
+U+1fb5 ? # Character á¾µ
+U+1fb6 â # Character ᾶ
+#U+1fb7 ÄÌi # Character á¾·
+#U+1fb8 Ä # Character Ᾰ
+#U+1fb9 Ä # Character á¾¹
+U+1fba à # Character Ὰ
+U+1fbb à # Character Ά
+#U+1fbc ÄI # Character á¾¼
+U+1fbd ? # Character á¾½
+U+1fbe i # Character á¾¾
+U+1fbf ? # Character ᾿
+U+1fc0 ? # Character á¿
+#U+1fc1 Â¨Ì # Character á¿
+#U+1fc2 á¸i # Character á¿
+#U+1fc3 Äi # Character á¿
+#U+1fc4 á¸i # Character á¿
+U+1fc5 ? # Character á¿
+#U+1fc6 ÄÌ # Character á¿
+#U+1fc7 ÄÌi # Character á¿
+U+1fc8 Ã # Character á¿
+U+1fc9 Ã # Character á¿
+#U+1fca Ḡ# Character á¿
+#U+1fcb Ḡ# Character á¿
+#U+1fcc ÄI # Character á¿
+U+1fcd ? # Character á¿
+U+1fce ? # Character á¿
+#U+1fcf á¾¿Ì # Character á¿
+#U+1fd0 Ä # Character á¿
+#U+1fd1 Ä« # Character á¿
+#U+1fd2 Ã¯Ì # Character á¿
+#U+1fd3 ḯ # Character á¿
+U+1fd4 ? # Character á¿
+U+1fd5 ? # Character á¿
+U+1fd6 î # Character á¿
+#U+1fd7 Ã¯Ì # Character á¿
+#U+1fd8 Ĭ # Character á¿
+#U+1fd9 Ī # Character á¿
+U+1fda à # Character á¿
+U+1fdb à # Character á¿
+U+1fdc ? # Character á¿
+U+1fdd ? # Character á¿
+U+1fde ? # Character á¿
+#U+1fdf á¿¾Ì # Character á¿
+#U+1fe0 yÌ # Character á¿
+#U+1fe1 ȳ # Character ῡ
+#U+1fe2 Ã¿Ì # Character á¿¢
+#U+1fe3 Ã¿Ì # Character á¿£
+U+1fe4 r # Character ῤ
+U+1fe5 rh # Character á¿¥
+#U+1fe6 ŷ # Character ῦ
+#U+1fe7 Ã¿Ì # Character ῧ
+#U+1fe8 YÌ # Character Ῠ
+#U+1fe9 Ȳ # Character Ῡ
+#U+1fea Ỳ # Character Ὺ
+U+1feb à # Character Ύ
+U+1fec RH # Character Ῥ
+U+1fed ? # Character á¿
+U+1fee ? # Character á¿®
+U+1fef ? # Character `
+U+1ff0 ? # Character á¿°
+U+1ff1 ? # Character ῱
+#U+1ff2 á¹i # Character ῲ
+#U+1ff3 Åi # Character ῳ
+#U+1ff4 á¹i # Character á¿´
+U+1ff5 ? # Character ῵
+#U+1ff6 ÅÌ # Character ῶ
+#U+1ff7 ÅÌi # Character á¿·
+U+1ff8 à # Character Ὸ
+U+1ff9 à # Character Ό
+#U+1ffa Ṡ# Character Ὼ
+#U+1ffb á¹ # Character á¿»
+#U+1ffc ÅI # Character ῼ
+U+1ffd ? # Character ´
+U+1ffe ? # Character ῾
+U+1fff ? # Character á¿¿
diff --git a/resources/chars/latin1/row30.trans b/resources/chars/latin1/row30.trans
new file mode 100644
index 0000000..82e5199
--- /dev/null
+++ b/resources/chars/latin1/row30.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+3000 # Character ã
+U+3001 ? # Character ã
+U+3002 ? # Character ã
+U+3003 ? # Character ã
+U+3004 ? # Character ã
+U+3005 ? # Character ã
+U+3006 ? # Character ã
+U+3007 ? # Character ã
+U+3008 ? # Character ã
+U+3009 ? # Character ã
+U+300a ? # Character ã
+U+300b ? # Character ã
+U+300c ? # Character ã
+U+300d ? # Character ã
+U+300e ? # Character ã
+U+300f ? # Character ã
+U+3010 ? # Character ã
+U+3011 ? # Character ã
+U+3012 ? # Character ã
+U+3013 ? # Character ã
+U+3014 ? # Character ã
+U+3015 ? # Character ã
+U+3016 ? # Character ã
+U+3017 ? # Character ã
+U+3018 ? # Character ã
+U+3019 ? # Character ã
+U+301a ? # Character ã
+U+301b ? # Character ã
+U+301c ? # Character ã
+U+301d ? # Character ã
+U+301e ? # Character ã
+U+301f ? # Character ã
+U+3020 ? # Character ã
+U+3021 ? # Character ã¡
+U+3022 ? # Character ã¢
+U+3023 ? # Character ã£
+U+3024 ? # Character ã¤
+U+3025 ? # Character ã¥
+U+3026 ? # Character ã¦
+U+3027 ? # Character ã§
+U+3028 ? # Character ã¨
+U+3029 ? # Character ã©
+U+302a ? # Character ãª
+U+302b ? # Character ã«
+U+302c ? # Character ã¬
+U+302d ? # Character ã
+U+302e ? # Character ã®
+U+302f ? # Character ã¯
+U+3030 ? # Character ã°
+U+3031 ? # Character ã±
+U+3032 ? # Character ã²
+U+3033 ? # Character ã³
+U+3034 ? # Character ã´
+U+3035 ? # Character ãµ
+U+3036 ? # Character ã¶
+U+3037 ? # Character ã·
+U+3038 ? # Character ã¸
+U+3039 ? # Character ã¹
+U+303a ? # Character ãº
+U+303b ? # Character ã»
+U+303c ? # Character ã¼
+U+303d ? # Character ã½
+U+303e ? # Character ã¾
+U+303f ? # Character ã¿
+U+3040 ? # Character ã
+U+3041 ~a # Character ã
+U+3042 a # Character ã
+U+3043 ~i # Character ã
+U+3044 i # Character ã
+U+3045 ~u # Character ã
+U+3046 u # Character ã
+U+3047 ~e # Character ã
+U+3048 e # Character ã
+U+3049 ~o # Character ã
+U+304a o # Character ã
+U+304b ka # Character ã
+U+304c ga # Character ã
+U+304d ki # Character ã
+U+304e gi # Character ã
+U+304f ku # Character ã
+U+3050 gu # Character ã
+U+3051 ke # Character ã
+U+3052 ge # Character ã
+U+3053 ko # Character ã
+U+3054 go # Character ã
+U+3055 sa # Character ã
+U+3056 za # Character ã
+U+3057 shi # Character ã
+U+3058 ji # Character ã
+U+3059 su # Character ã
+U+305a zu # Character ã
+U+305b se # Character ã
+U+305c ze # Character ã
+U+305d so # Character ã
+U+305e zo # Character ã
+U+305f ta # Character ã
+U+3060 da # Character ã
+U+3061 chi # Character ã¡
+U+3062 dji # Character ã¢
+U+3063 ~tsu # Character ã£
+U+3064 tsu # Character ã¤
+U+3065 dzu # Character ã¥
+U+3066 te # Character ã¦
+U+3067 de # Character ã§
+U+3068 to # Character ã¨
+U+3069 do # Character ã©
+U+306a na # Character ãª
+U+306b ni # Character ã«
+U+306c nu # Character ã¬
+U+306d ne # Character ã
+U+306e no # Character ã®
+U+306f ha # Character ã¯
+U+3070 ba # Character ã°
+U+3071 pa # Character ã±
+U+3072 hi # Character ã²
+U+3073 bi # Character ã³
+U+3074 pi # Character ã´
+U+3075 fu # Character ãµ
+U+3076 bu # Character ã¶
+U+3077 pu # Character ã·
+U+3078 he # Character ã¸
+U+3079 be # Character ã¹
+U+307a pe # Character ãº
+U+307b ho # Character ã»
+U+307c bo # Character ã¼
+U+307d po # Character ã½
+U+307e ma # Character ã¾
+U+307f mi # Character ã¿
+U+3080 mu # Character ã
+U+3081 me # Character ã
+U+3082 mo # Character ã
+U+3083 ~ya # Character ã
+U+3084 ya # Character ã
+U+3085 ~yu # Character ã
+U+3086 yu # Character ã
+U+3087 ~yo # Character ã
+U+3088 yo # Character ã
+U+3089 ra # Character ã
+U+308a ri # Character ã
+U+308b ru # Character ã
+U+308c re # Character ã
+U+308d ro # Character ã
+U+308e ~wa # Character ã
+U+308f wa # Character ã
+U+3090 wi # Character ã
+U+3091 we # Character ã
+U+3092 wo # Character ã
+U+3093 n # Character ã
+U+3094 vu # Character ã
+U+3095 ? # Character ã
+U+3096 ? # Character ã
+U+3097 ? # Character ã
+U+3098 ? # Character ã
+U+3099 ? # Character ã
+U+309a ? # Character ã
+U+309b ? # Character ã
+U+309c ? # Character ã
+U+309d # Character ã
+U+309e # Character ã
+U+309f ? # Character ã
+U+30a0 ? # Character ã
+U+30a1 ~a # Character ã¡
+U+30a2 a # Character ã¢
+U+30a3 ~i # Character ã£
+U+30a4 i # Character ã¤
+U+30a5 ~u # Character ã¥
+U+30a6 u # Character ã¦
+U+30a7 ~e # Character ã§
+U+30a8 e # Character ã¨
+U+30a9 ~o # Character ã©
+U+30aa o # Character ãª
+U+30ab ka # Character ã«
+U+30ac ga # Character ã¬
+U+30ad ki # Character ã
+U+30ae gi # Character ã®
+U+30af ku # Character ã¯
+U+30b0 gu # Character ã°
+U+30b1 ke # Character ã±
+U+30b2 ge # Character ã²
+U+30b3 ko # Character ã³
+U+30b4 go # Character ã´
+U+30b5 sa # Character ãµ
+U+30b6 za # Character ã¶
+U+30b7 shi # Character ã·
+U+30b8 ji # Character ã¸
+U+30b9 su # Character ã¹
+U+30ba zu # Character ãº
+U+30bb se # Character ã»
+U+30bc ze # Character ã¼
+U+30bd so # Character ã½
+U+30be zo # Character ã¾
+U+30bf ta # Character ã¿
+U+30c0 da # Character ã
+U+30c1 chi # Character ã
+U+30c2 dji # Character ã
+U+30c3 ~tsu # Character ã
+U+30c4 tsu # Character ã
+U+30c5 dzu # Character ã
+U+30c6 te # Character ã
+U+30c7 de # Character ã
+U+30c8 to # Character ã
+U+30c9 do # Character ã
+U+30ca na # Character ã
+U+30cb ni # Character ã
+U+30cc nu # Character ã
+U+30cd ne # Character ã
+U+30ce no # Character ã
+U+30cf ha # Character ã
+U+30d0 ba # Character ã
+U+30d1 pa # Character ã
+U+30d2 hi # Character ã
+U+30d3 bi # Character ã
+U+30d4 pi # Character ã
+U+30d5 fu # Character ã
+U+30d6 bu # Character ã
+U+30d7 pu # Character ã
+U+30d8 he # Character ã
+U+30d9 be # Character ã
+U+30da pe # Character ã
+U+30db ho # Character ã
+U+30dc bo # Character ã
+U+30dd po # Character ã
+U+30de ma # Character ã
+U+30df mi # Character ã
+U+30e0 mu # Character ã
+U+30e1 me # Character ã¡
+U+30e2 mo # Character ã¢
+U+30e3 ~ya # Character ã£
+U+30e4 ya # Character ã¤
+U+30e5 ~yu # Character ã¥
+U+30e6 yu # Character ã¦
+U+30e7 ~yo # Character ã§
+U+30e8 yo # Character ã¨
+U+30e9 ra # Character ã©
+U+30ea ri # Character ãª
+U+30eb ru # Character ã«
+U+30ec re # Character ã¬
+U+30ed ro # Character ã
+U+30ee ~wa # Character ã®
+U+30ef wa # Character ã¯
+U+30f0 wi # Character ã°
+U+30f1 we # Character ã±
+U+30f2 wo # Character ã²
+U+30f3 n # Character ã³
+U+30f4 vu # Character ã´
+U+30f5 ~ka # Character ãµ
+U+30f6 ~ke # Character ã¶
+U+30f7 va # Character ã·
+U+30f8 vi # Character ã¸
+U+30f9 ve # Character ã¹
+U+30fa vo # Character ãº
+U+30fb ? # Character ã»
+U+30fc ? # Character ã¼
+U+30fd # Character ã½
+U+30fe # Character ã¾
+U+30ff ? # Character ã¿
diff --git a/resources/chars/latin1/row31.trans b/resources/chars/latin1/row31.trans
new file mode 100644
index 0000000..6a7c04a
--- /dev/null
+++ b/resources/chars/latin1/row31.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+3100 ? # Character ã
+U+3101 ? # Character ã
+U+3102 ? # Character ã
+U+3103 ? # Character ã
+U+3104 ? # Character ã
+U+3105 ? # Character ã
+U+3106 ? # Character ã
+U+3107 ? # Character ã
+U+3108 ? # Character ã
+U+3109 ? # Character ã
+U+310a ? # Character ã
+U+310b ? # Character ã
+U+310c ? # Character ã
+U+310d ? # Character ã
+U+310e ? # Character ã
+U+310f ? # Character ã
+U+3110 ? # Character ã
+U+3111 ? # Character ã
+U+3112 ? # Character ã
+U+3113 ? # Character ã
+U+3114 ? # Character ã
+U+3115 ? # Character ã
+U+3116 ? # Character ã
+U+3117 ? # Character ã
+U+3118 ? # Character ã
+U+3119 ? # Character ã
+U+311a ? # Character ã
+U+311b ? # Character ã
+U+311c ? # Character ã
+U+311d ? # Character ã
+U+311e ? # Character ã
+U+311f ? # Character ã
+U+3120 ? # Character ã
+U+3121 ? # Character ã¡
+U+3122 ? # Character ã¢
+U+3123 ? # Character ã£
+U+3124 ? # Character ã¤
+U+3125 ? # Character ã¥
+U+3126 ? # Character ã¦
+U+3127 ? # Character ã§
+U+3128 ? # Character ã¨
+U+3129 ? # Character ã©
+U+312a ? # Character ãª
+U+312b ? # Character ã«
+U+312c ? # Character ã¬
+U+312d ? # Character ã
+U+312e ? # Character ã®
+U+312f ? # Character ã¯
+U+3130 ? # Character ã°
+U+3131 g # Character ã±
+U+3132 kk # Character ã²
+U+3133 gs # Character ã³
+U+3134 n # Character ã´
+U+3135 nj # Character ãµ
+U+3136 nh # Character ã¶
+U+3137 d # Character ã·
+U+3138 tt # Character ã¸
+U+3139 l # Character ã¹
+U+313a lg # Character ãº
+U+313b lm # Character ã»
+U+313c lb # Character ã¼
+U+313d ls # Character ã½
+U+313e lt # Character ã¾
+U+313f lp # Character ã¿
+U+3140 ? # Character ã
+U+3141 m # Character ã
+U+3142 b # Character ã
+U+3143 pp # Character ã
+U+3144 ? # Character ã
+U+3145 s # Character ã
+U+3146 ss # Character ã
+U+3147 # Character ã
+U+3148 j # Character ã
+U+3149 jj # Character ã
+U+314a ch # Character ã
+U+314b k # Character ã
+U+314c t # Character ã
+U+314d p # Character ã
+U+314e h # Character ã
+U+314f a # Character ã
+U+3150 ae # Character ã
+U+3151 ya # Character ã
+U+3152 yae # Character ã
+U+3153 eo # Character ã
+U+3154 e # Character ã
+U+3155 yeo # Character ã
+U+3156 ye # Character ã
+U+3157 o # Character ã
+U+3158 wa # Character ã
+U+3159 wae # Character ã
+U+315a oe # Character ã
+U+315b yo # Character ã
+U+315c u # Character ã
+U+315d wo # Character ã
+U+315e we # Character ã
+U+315f wi # Character ã
+U+3160 yu # Character ã
+U+3161 eu # Character ã
¡
+U+3162 ui # Character ã
¢
+U+3163 i # Character ã
£
+U+3164 ? # Character ã
¤
+U+3165 ? # Character ã
¥
+U+3166 ? # Character ã
¦
+U+3167 ? # Character ã
§
+U+3168 ? # Character ã
¨
+U+3169 ? # Character ã
©
+U+316a ? # Character ã
ª
+U+316b ? # Character ã
«
+U+316c ? # Character ã
¬
+U+316d ? # Character ã
+U+316e ? # Character ã
®
+U+316f ? # Character ã
¯
+U+3170 ? # Character ã
°
+U+3171 ? # Character ã
±
+U+3172 ? # Character ã
²
+U+3173 ? # Character ã
³
+U+3174 ? # Character ã
´
+U+3175 ? # Character ã
µ
+U+3176 ? # Character ã
¶
+U+3177 ? # Character ã
·
+U+3178 ? # Character ã
¸
+U+3179 ? # Character ã
¹
+U+317a ? # Character ã
º
+U+317b ? # Character ã
»
+U+317c ? # Character ã
¼
+U+317d ? # Character ã
½
+U+317e ? # Character ã
¾
+U+317f ? # Character ã
¿
+U+3180 ? # Character ã
+U+3181 ? # Character ã
+U+3182 ? # Character ã
+U+3183 ? # Character ã
+U+3184 ? # Character ã
+U+3185 ? # Character ã
+U+3186 ? # Character ã
+U+3187 ? # Character ã
+U+3188 ? # Character ã
+U+3189 ? # Character ã
+U+318a ? # Character ã
+U+318b ? # Character ã
+U+318c ? # Character ã
+U+318d ? # Character ã
+U+318e ? # Character ã
+U+318f ? # Character ã
+U+3190 ? # Character ã
+U+3191 ? # Character ã
+U+3192 ? # Character ã
+U+3193 ? # Character ã
+U+3194 ? # Character ã
+U+3195 ? # Character ã
+U+3196 ? # Character ã
+U+3197 ? # Character ã
+U+3198 ? # Character ã
+U+3199 ? # Character ã
+U+319a ? # Character ã
+U+319b ? # Character ã
+U+319c ? # Character ã
+U+319d ? # Character ã
+U+319e ? # Character ã
+U+319f ? # Character ã
+U+31a0 ? # Character ã
+U+31a1 ? # Character ã¡
+U+31a2 ? # Character ã¢
+U+31a3 ? # Character ã£
+U+31a4 ? # Character ã¤
+U+31a5 ? # Character ã¥
+U+31a6 ? # Character ã¦
+U+31a7 ? # Character ã§
+U+31a8 ? # Character ã¨
+U+31a9 ? # Character ã©
+U+31aa ? # Character ãª
+U+31ab ? # Character ã«
+U+31ac ? # Character ã¬
+U+31ad ? # Character ã
+U+31ae ? # Character ã®
+U+31af ? # Character ã¯
+U+31b0 ? # Character ã°
+U+31b1 ? # Character ã±
+U+31b2 ? # Character ã²
+U+31b3 ? # Character ã³
+U+31b4 ? # Character ã´
+U+31b5 ? # Character ãµ
+U+31b6 ? # Character ã¶
+U+31b7 ? # Character ã·
+U+31b8 ? # Character ã¸
+U+31b9 ? # Character ã¹
+U+31ba ? # Character ãº
+U+31bb ? # Character ã»
+U+31bc ? # Character ã¼
+U+31bd ? # Character ã½
+U+31be ? # Character ã¾
+U+31bf ? # Character ã¿
+U+31c0 ? # Character ã
+U+31c1 ? # Character ã
+U+31c2 ? # Character ã
+U+31c3 ? # Character ã
+U+31c4 ? # Character ã
+U+31c5 ? # Character ã
+U+31c6 ? # Character ã
+U+31c7 ? # Character ã
+U+31c8 ? # Character ã
+U+31c9 ? # Character ã
+U+31ca ? # Character ã
+U+31cb ? # Character ã
+U+31cc ? # Character ã
+U+31cd ? # Character ã
+U+31ce ? # Character ã
+U+31cf ? # Character ã
+U+31d0 ? # Character ã
+U+31d1 ? # Character ã
+U+31d2 ? # Character ã
+U+31d3 ? # Character ã
+U+31d4 ? # Character ã
+U+31d5 ? # Character ã
+U+31d6 ? # Character ã
+U+31d7 ? # Character ã
+U+31d8 ? # Character ã
+U+31d9 ? # Character ã
+U+31da ? # Character ã
+U+31db ? # Character ã
+U+31dc ? # Character ã
+U+31dd ? # Character ã
+U+31de ? # Character ã
+U+31df ? # Character ã
+U+31e0 ? # Character ã
+U+31e1 ? # Character ã¡
+U+31e2 ? # Character ã¢
+U+31e3 ? # Character ã£
+U+31e4 ? # Character ã¤
+U+31e5 ? # Character ã¥
+U+31e6 ? # Character ã¦
+U+31e7 ? # Character ã§
+U+31e8 ? # Character ã¨
+U+31e9 ? # Character ã©
+U+31ea ? # Character ãª
+U+31eb ? # Character ã«
+U+31ec ? # Character ã¬
+U+31ed ? # Character ã
+U+31ee ? # Character ã®
+U+31ef ? # Character ã¯
+U+31f0 ? # Character ã°
+U+31f1 ? # Character ã±
+U+31f2 ? # Character ã²
+U+31f3 ? # Character ã³
+U+31f4 ? # Character ã´
+U+31f5 ? # Character ãµ
+U+31f6 ? # Character ã¶
+U+31f7 ? # Character ã·
+U+31f8 ? # Character ã¸
+U+31f9 ? # Character ã¹
+U+31fa ? # Character ãº
+U+31fb ? # Character ã»
+U+31fc ? # Character ã¼
+U+31fd ? # Character ã½
+U+31fe ? # Character ã¾
+U+31ff ? # Character ã¿
diff --git a/resources/chars/latin1/row32.trans b/resources/chars/latin1/row32.trans
new file mode 100644
index 0000000..b7d060a
--- /dev/null
+++ b/resources/chars/latin1/row32.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+3200 (g) # Character ã
+U+3201 (n) # Character ã
+U+3202 (d) # Character ã
+U+3203 (l) # Character ã
+U+3204 (m) # Character ã
+U+3205 (b) # Character ã
+U+3206 (s) # Character ã
+U+3207 () # Character ã
+U+3208 (j) # Character ã
+U+3209 (ch) # Character ã
+U+320a (k) # Character ã
+U+320b (t) # Character ã
+U+320c (p) # Character ã
+U+320d (h) # Character ã
+U+320e (ga) # Character ã
+U+320f (na) # Character ã
+U+3210 (da) # Character ã
+U+3211 (la) # Character ã
+U+3212 (ma) # Character ã
+U+3213 (ba) # Character ã
+U+3214 (sa) # Character ã
+U+3215 (a) # Character ã
+U+3216 (ja) # Character ã
+U+3217 (cha) # Character ã
+U+3218 (ka) # Character ã
+U+3219 (ta) # Character ã
+U+321a (pa) # Character ã
+U+321b (ha) # Character ã
+U+321c (ju) # Character ã
+U+321d ? # Character ã
+U+321e ? # Character ã
+U+321f ? # Character ã
+U+3220 ? # Character ã
+U+3221 ? # Character ã¡
+U+3222 ? # Character ã¢
+U+3223 ? # Character ã£
+U+3224 ? # Character ã¤
+U+3225 ? # Character ã¥
+U+3226 ? # Character ã¦
+U+3227 ? # Character ã§
+U+3228 ? # Character ã¨
+U+3229 ? # Character ã©
+U+322a ? # Character ãª
+U+322b ? # Character ã«
+U+322c ? # Character ã¬
+U+322d ? # Character ã
+U+322e ? # Character ã®
+U+322f ? # Character ã¯
+U+3230 ? # Character ã°
+U+3231 ? # Character ã±
+U+3232 ? # Character ã²
+U+3233 ? # Character ã³
+U+3234 ? # Character ã´
+U+3235 ? # Character ãµ
+U+3236 ? # Character ã¶
+U+3237 ? # Character ã·
+U+3238 ? # Character ã¸
+U+3239 ? # Character ã¹
+U+323a ? # Character ãº
+U+323b ? # Character ã»
+U+323c ? # Character ã¼
+U+323d ? # Character ã½
+U+323e ? # Character ã¾
+U+323f ? # Character ã¿
+U+3240 ? # Character ã
+U+3241 ? # Character ã
+U+3242 ? # Character ã
+U+3243 ? # Character ã
+U+3244 ? # Character ã
+U+3245 ? # Character ã
+U+3246 ? # Character ã
+U+3247 ? # Character ã
+U+3248 ? # Character ã
+U+3249 ? # Character ã
+U+324a ? # Character ã
+U+324b ? # Character ã
+U+324c ? # Character ã
+U+324d ? # Character ã
+U+324e ? # Character ã
+U+324f ? # Character ã
+U+3250 ? # Character ã
+U+3251 ? # Character ã
+U+3252 ? # Character ã
+U+3253 ? # Character ã
+U+3254 ? # Character ã
+U+3255 ? # Character ã
+U+3256 ? # Character ã
+U+3257 ? # Character ã
+U+3258 ? # Character ã
+U+3259 ? # Character ã
+U+325a ? # Character ã
+U+325b ? # Character ã
+U+325c ? # Character ã
+U+325d ? # Character ã
+U+325e ? # Character ã
+U+325f ? # Character ã
+U+3260 g # Character ã
+U+3261 n # Character ã¡
+U+3262 d # Character ã¢
+U+3263 l # Character ã£
+U+3264 m # Character ã¤
+U+3265 b # Character ã¥
+U+3266 s # Character ã¦
+U+3267 # Character ã§
+U+3268 j # Character ã¨
+U+3269 ch # Character ã©
+U+326a k # Character ãª
+U+326b t # Character ã«
+U+326c p # Character ã¬
+U+326d h # Character ã
+U+326e ga # Character ã®
+U+326f na # Character ã¯
+U+3270 da # Character ã°
+U+3271 la # Character ã±
+U+3272 ma # Character ã²
+U+3273 ba # Character ã³
+U+3274 sa # Character ã´
+U+3275 a # Character ãµ
+U+3276 ja # Character ã¶
+U+3277 cha # Character ã·
+U+3278 ka # Character ã¸
+U+3279 ta # Character ã¹
+U+327a pa # Character ãº
+U+327b ha # Character ã»
+U+327c ? # Character ã¼
+U+327d ? # Character ã½
+U+327e ? # Character ã¾
+U+327f ? # Character ã¿
+U+3280 ? # Character ã
+U+3281 ? # Character ã
+U+3282 ? # Character ã
+U+3283 ? # Character ã
+U+3284 ? # Character ã
+U+3285 ? # Character ã
+U+3286 ? # Character ã
+U+3287 ? # Character ã
+U+3288 ? # Character ã
+U+3289 ? # Character ã
+U+328a ? # Character ã
+U+328b ? # Character ã
+U+328c ? # Character ã
+U+328d ? # Character ã
+U+328e ? # Character ã
+U+328f ? # Character ã
+U+3290 ? # Character ã
+U+3291 ? # Character ã
+U+3292 ? # Character ã
+U+3293 ? # Character ã
+U+3294 ? # Character ã
+U+3295 ? # Character ã
+U+3296 ? # Character ã
+U+3297 ? # Character ã
+U+3298 ? # Character ã
+U+3299 ? # Character ã
+U+329a ? # Character ã
+U+329b ? # Character ã
+U+329c ? # Character ã
+U+329d ? # Character ã
+U+329e ? # Character ã
+U+329f ? # Character ã
+U+32a0 ? # Character ã
+U+32a1 ? # Character ã¡
+U+32a2 ? # Character ã¢
+U+32a3 ? # Character ã£
+U+32a4 ? # Character ã¤
+U+32a5 ? # Character ã¥
+U+32a6 ? # Character ã¦
+U+32a7 ? # Character ã§
+U+32a8 ? # Character ã¨
+U+32a9 ? # Character ã©
+U+32aa ? # Character ãª
+U+32ab ? # Character ã«
+U+32ac ? # Character ã¬
+U+32ad ? # Character ã
+U+32ae ? # Character ã®
+U+32af ? # Character ã¯
+U+32b0 ? # Character ã°
+U+32b1 ? # Character ã±
+U+32b2 ? # Character ã²
+U+32b3 ? # Character ã³
+U+32b4 ? # Character ã´
+U+32b5 ? # Character ãµ
+U+32b6 ? # Character ã¶
+U+32b7 ? # Character ã·
+U+32b8 ? # Character ã¸
+U+32b9 ? # Character ã¹
+U+32ba ? # Character ãº
+U+32bb ? # Character ã»
+U+32bc ? # Character ã¼
+U+32bd ? # Character ã½
+U+32be ? # Character ã¾
+U+32bf ? # Character ã¿
+U+32c0 ? # Character ã
+U+32c1 ? # Character ã
+U+32c2 ? # Character ã
+U+32c3 ? # Character ã
+U+32c4 ? # Character ã
+U+32c5 ? # Character ã
+U+32c6 ? # Character ã
+U+32c7 ? # Character ã
+U+32c8 ? # Character ã
+U+32c9 ? # Character ã
+U+32ca ? # Character ã
+U+32cb ? # Character ã
+U+32cc ? # Character ã
+U+32cd ? # Character ã
+U+32ce ? # Character ã
+U+32cf ? # Character ã
+U+32d0 ? # Character ã
+U+32d1 ? # Character ã
+U+32d2 ? # Character ã
+U+32d3 ? # Character ã
+U+32d4 ? # Character ã
+U+32d5 ? # Character ã
+U+32d6 ? # Character ã
+U+32d7 ? # Character ã
+U+32d8 ? # Character ã
+U+32d9 ? # Character ã
+U+32da ? # Character ã
+U+32db ? # Character ã
+U+32dc ? # Character ã
+U+32dd ? # Character ã
+U+32de ? # Character ã
+U+32df ? # Character ã
+U+32e0 ? # Character ã
+U+32e1 ? # Character ã¡
+U+32e2 ? # Character ã¢
+U+32e3 ? # Character ã£
+U+32e4 ? # Character ã¤
+U+32e5 ? # Character ã¥
+U+32e6 ? # Character ã¦
+U+32e7 ? # Character ã§
+U+32e8 ? # Character ã¨
+U+32e9 ? # Character ã©
+U+32ea ? # Character ãª
+U+32eb ? # Character ã«
+U+32ec ? # Character ã¬
+U+32ed ? # Character ã
+U+32ee ? # Character ã®
+U+32ef ? # Character ã¯
+U+32f0 ? # Character ã°
+U+32f1 ? # Character ã±
+U+32f2 ? # Character ã²
+U+32f3 ? # Character ã³
+U+32f4 ? # Character ã´
+U+32f5 ? # Character ãµ
+U+32f6 ? # Character ã¶
+U+32f7 ? # Character ã·
+U+32f8 ? # Character ã¸
+U+32f9 ? # Character ã¹
+U+32fa ? # Character ãº
+U+32fb ? # Character ã»
+U+32fc ? # Character ã¼
+U+32fd ? # Character ã½
+U+32fe ? # Character ã¾
+U+32ff ? # Character ã¿
diff --git a/resources/chars/latin1/row34.trans b/resources/chars/latin1/row34.trans
new file mode 100644
index 0000000..a49ed09
--- /dev/null
+++ b/resources/chars/latin1/row34.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+3400 qiÅ« # Character ã
+#U+3401 tiÇn # Character ã
+U+3402 ? # Character ã
+U+3403 ? # Character ã
+U+3404 kuà # Character ã
+#U+3405 wÇ # Character ã
+#U+3406 yÇn # Character ã
+U+3407 ? # Character ã
+U+3408 ? # Character ã
+U+3409 ? # Character ã
+U+340a ? # Character ã
+U+340b ? # Character ã
+U+340c sì # Character ã
+U+340d ? # Character ã
+U+340e ? # Character ã
+U+340f ? # Character ã
+U+3410 ? # Character ã
+U+3411 ? # Character ã
+U+3412 ? # Character ã
+U+3413 ? # Character ã
+U+3414 ? # Character ã
+U+3415 ? # Character ã
+U+3416 yè # Character ã
+U+3417 ? # Character ã
+U+3418 ? # Character ã
+U+3419 ? # Character ã
+U+341a ? # Character ã
+U+341b ? # Character ã
+U+341c chóu # Character ã
+U+341d ? # Character ã
+U+341e ? # Character ã
+U+341f ? # Character ã
+U+3420 ? # Character ã
+U+3421 nuò # Character ã¡
+U+3422 ? # Character ã¢
+U+3423 ? # Character ã£
+U+3424 qiú # Character ã¤
+U+3425 ? # Character ã¥
+U+3426 ? # Character ã¦
+U+3427 ? # Character ã§
+U+3428 xù # Character ã¨
+U+3429 xÃng # Character ã©
+U+342a ? # Character ãª
+#U+342b xiÅng # Character ã«
+U+342c liú # Character ã¬
+#U+342d lÇn # Character ã
+#U+342e xiÄng # Character ã®
+#U+342f yÅng # Character ã¯
+U+3430 xìn # Character ã°
+#U+3431 zhÄn # Character ã±
+U+3432 dà i # Character ã²
+U+3433 wù # Character ã³
+#U+3434 pÄn # Character ã´
+U+3435 ? # Character ãµ
+U+3436 ? # Character ã¶
+#U+3437 mÇ # Character ã·
+U+3438 qià n # Character ã¸
+U+3439 yì # Character ã¹
+U+343a zhòng # Character ãº
+#U+343b Å # Character ã»
+U+343c chèng # Character ã¼
+U+343d ? # Character ã½
+U+343e ? # Character ã¾
+U+343f ? # Character ã¿
+U+3440 ? # Character ã
+#U+3441 zhuÅ # Character ã
+#U+3442 fÇng # Character ã
+#U+3443 Ço # Character ã
+#U+3444 wÇ # Character ã
+U+3445 zuò # Character ã
+U+3446 ? # Character ã
+U+3447 zhòu # Character ã
+U+3448 dòng # Character ã
+U+3449 sù # Character ã
+U+344a yì # Character ã
+U+344b jiòng # Character ã
+#U+344c wÄng # Character ã
+#U+344d lÄi # Character ã
+#U+344e nÇo # Character ã
+U+344f zhù # Character ã
+U+3450 ? # Character ã
+U+3451 ? # Character ã
+U+3452 ? # Character ã
+U+3453 ? # Character ã
+#U+3454 xÇ # Character ã
+U+3455 ? # Character ã
+U+3456 ? # Character ã
+U+3457 ? # Character ã
+U+3458 jiè # Character ã
+U+3459 dié # Character ã
+U+345a nuó # Character ã
+U+345b sù # Character ã
+U+345c yì # Character ã
+U+345d lòng # Character ã
+U+345e yìng # Character ã
+#U+345f bÄng # Character ã
+U+3460 ? # Character ã
+U+3461 ? # Character ã¡
+U+3462 ? # Character ã¢
+U+3463 lán # Character ã£
+U+3464 miáo # Character ã¤
+U+3465 yì # Character ã¥
+U+3466 lì # Character ã¦
+U+3467 jì # Character ã§
+#U+3468 yÇ # Character ã¨
+U+3469 luó # Character ã©
+U+346a chái # Character ãª
+U+346b ? # Character ã«
+U+346c ? # Character ã¬
+U+346d ? # Character ã
+U+346e hún # Character ã®
+#U+346f xÇ # Character ã¯
+U+3470 huì # Character ã°
+#U+3471 rÇo # Character ã±
+U+3472 ? # Character ã²
+U+3473 zhòu # Character ã³
+U+3474 ? # Character ã´
+U+3475 hà n # Character ãµ
+U+3476 xì # Character ã¶
+U+3477 tà i # Character ã·
+#U+3478 Çi # Character ã¸
+U+3479 huì # Character ã¹
+U+347a jùn # Character ãº
+U+347b mà # Character ã»
+U+347c lüè # Character ã¼
+U+347d táng # Character ã½
+U+347e xiáo # Character ã¾
+U+347f tiáo # Character ã¿
+#U+3480 zhÇ # Character ã
+#U+3481 yÇ # Character ã
+U+3482 kù # Character ã
+U+3483 èr # Character ã
+U+3484 nà ng # Character ã
+#U+3485 qÇ # Character ã
+U+3486 chì # Character ã
+U+3487 mù # Character ã
+U+3488 hà n # Character ã
+#U+3489 tÇng # Character ã
+U+348a sè # Character ã
+U+348b ? # Character ã
+U+348c qióng # Character ã
+U+348d léi # Character ã
+#U+348e sÇ # Character ã
+U+348f ? # Character ã
+U+3490 ? # Character ã
+U+3491 huì # Character ã
+U+3492 pú # Character ã
+U+3493 tà # Character ã
+#U+3494 shÇ # Character ã
+U+3495 ? # Character ã
+#U+3496 Çu # Character ã
+U+3497 tái # Character ã
+U+3498 ? # Character ã
+U+3499 mián # Character ã
+#U+349a wÄn # Character ã
+U+349b dià o # Character ã
+U+349c yú # Character ã
+U+349d miè # Character ã
+U+349e jùn # Character ã
+#U+349f niÇo # Character ã
+U+34a0 xiè # Character ã
+U+34a1 yóu # Character ã¡
+U+34a2 ? # Character ã¢
+U+34a3 ? # Character ã£
+U+34a4 shè # Character ã¤
+U+34a5 ? # Character ã¥
+#U+34a6 lÄi # Character ã¦
+U+34a7 lì # Character ã§
+U+34a8 ? # Character ã¨
+#U+34a9 luÇ # Character ã©
+U+34aa ? # Character ãª
+U+34ab jì # Character ã«
+U+34ac ? # Character ã¬
+U+34ad ? # Character ã
+U+34ae ? # Character ã®
+U+34af ? # Character ã¯
+U+34b0 quán # Character ã°
+U+34b1 ? # Character ã±
+U+34b2 cái # Character ã²
+#U+34b3 liÇng # Character ã³
+#U+34b4 gÇ # Character ã´
+U+34b5 mà o # Character ãµ
+U+34b6 ? # Character ã¶
+#U+34b7 guÇ # Character ã·
+U+34b8 suì # Character ã¸
+U+34b9 ? # Character ã¹
+U+34ba ? # Character ãº
+U+34bb mà o # Character ã»
+U+34bc mán # Character ã¼
+U+34bd ? # Character ã½
+U+34be shì # Character ã¾
+U+34bf là # Character ã¿
+U+34c0 ? # Character ã
+#U+34c1 wÇng # Character ã
+U+34c2 kòu # Character ã
+U+34c3 chuà # Character ã
+U+34c4 zhèn # Character ã
+U+34c5 ? # Character ã
+U+34c6 ? # Character ã
+U+34c7 ? # Character ã
+U+34c8 bèi # Character ã
+U+34c9 huà n # Character ã
+U+34ca dòng # Character ã
+U+34cb gòng # Character ã
+U+34cc ? # Character ã
+U+34cd ? # Character ã
+U+34ce lián # Character ã
+#U+34cf jiÇng # Character ã
+U+34d0 lù # Character ã
+U+34d1 xìng # Character ã
+U+34d2 ? # Character ã
+U+34d3 nán # Character ã
+U+34d4 xiè # Character ã
+U+34d5 ? # Character ã
+U+34d6 bì # Character ã
+U+34d7 jié # Character ã
+U+34d8 sù # Character ã
+U+34d9 ? # Character ã
+U+34da ? # Character ã
+U+34db ? # Character ã
+U+34dc yòu # Character ã
+U+34dd xÃng # Character ã
+U+34de qì # Character ã
+U+34df ? # Character ã
+U+34e0 dià n # Character ã
+#U+34e1 fÇ # Character ã¡
+U+34e2 luò # Character ã¢
+U+34e3 qià # Character ã£
+U+34e4 jié # Character ã¤
+U+34e5 ? # Character ã¥
+U+34e6 ? # Character ã¦
+#U+34e7 yÇn # Character ã§
+U+34e8 cà # Character ã¨
+U+34e9 ? # Character ã©
+#U+34ea lÇng # Character ãª
+U+34eb ? # Character ã«
+U+34ec ? # Character ã¬
+U+34ed hé # Character ã
+U+34ee ? # Character ã®
+U+34ef là # Character ã¯
+U+34f0 huà # Character ã°
+U+34f1 tóu # Character ã±
+U+34f2 pià n # Character ã²
+U+34f3 ? # Character ã³
+U+34f4 jùn # Character ã´
+U+34f5 è # Character ãµ
+U+34f6 qiè # Character ã¶
+U+34f7 yì # Character ã·
+U+34f8 jué # Character ã¸
+U+34f9 ruì # Character ã¹
+U+34fa jià n # Character ãº
+U+34fb ? # Character ã»
+U+34fc chì # Character ã¼
+U+34fd chóng # Character ã½
+U+34fe chà # Character ã¾
+U+34ff ? # Character ã¿
diff --git a/resources/chars/latin1/row35.trans b/resources/chars/latin1/row35.trans
new file mode 100644
index 0000000..e67cb2e
--- /dev/null
+++ b/resources/chars/latin1/row35.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+3500 lüè # Character ã
+U+3501 ? # Character ã
+U+3502 lÃn # Character ã
+U+3503 jué # Character ã
+U+3504 sù # Character ã
+U+3505 xià o # Character ã
+U+3506 chán # Character ã
+U+3507 ? # Character ã
+U+3508 ? # Character ã
+U+3509 zhú # Character ã
+#U+350a dÇn # Character ã
+U+350b jià n # Character ã
+U+350c zhòu # Character ã
+#U+350d duÇ # Character ã
+U+350e xiè # Character ã
+U+350f lì # Character ã
+U+3510 ? # Character ã
+U+3511 chì # Character ã
+U+3512 xà # Character ã
+#U+3513 jiÇn # Character ã
+U+3514 ? # Character ã
+U+3515 jà # Character ã
+U+3516 ? # Character ã
+U+3517 fèi # Character ã
+U+3518 chù # Character ã
+#U+3519 bÇng # Character ã
+#U+351a kÇu # Character ã
+U+351b ? # Character ã
+U+351c bá # Character ã
+#U+351d liÇng # Character ã
+U+351e kuà i # Character ã
+U+351f ? # Character ã
+U+3520 hé # Character ã
+U+3521 ? # Character ã¡
+U+3522 jué # Character ã¢
+U+3523 léi # Character ã£
+#U+3524 shÄn # Character ã¤
+U+3525 pà # Character ã¥
+#U+3526 yÇng # Character ã¦
+#U+3527 lÇ # Character ã§
+U+3528 bèi # Character ã¨
+U+3529 è # Character ã©
+#U+352a lÇ # Character ãª
+U+352b ? # Character ã«
+U+352c ? # Character ã¬
+U+352d chè # Character ã
+U+352e nuó # Character ã®
+#U+352f suÇn # Character ã¯
+U+3530 héng # Character ã°
+#U+3531 yÇ # Character ã±
+U+3532 ? # Character ã²
+#U+3533 guÇ # Character ã³
+U+3534 yì # Character ã´
+U+3535 xià n # Character ãµ
+U+3536 gòng # Character ã¶
+U+3537 lòu # Character ã·
+U+3538 ? # Character ã¸
+U+3539 lè # Character ã¹
+U+353a shì # Character ãº
+U+353b ? # Character ã»
+#U+353c sÇn # Character ã¼
+U+353d yà o # Character ã½
+U+353e jié # Character ã¾
+U+353f zòu # Character ã¿
+U+3540 ? # Character ã
+U+3541 què # Character ã
+U+3542 yÃn # Character ã
+U+3543 ? # Character ã
+U+3544 zhì # Character ã
+#U+3545 jiÇ # Character ã
+U+3546 hù # Character ã
+U+3547 lá # Character ã
+U+3548 hòu # Character ã
+U+3549 kè # Character ã
+U+354a ? # Character ã
+U+354b jìng # Character ã
+U+354c à i # Character ã
+U+354d ? # Character ã
+U+354e è # Character ã
+U+354f chú # Character ã
+#U+3550 xiÄ # Character ã
+U+3551 chú # Character ã
+U+3552 wéi # Character ã
+U+3553 ? # Character ã
+U+3554 ? # Character ã
+U+3555 huà n # Character ã
+U+3556 sù # Character ã
+U+3557 yòu # Character ã
+U+3558 ? # Character ã
+U+3559 jùn # Character ã
+#U+355a zhÇo # Character ã
+U+355b xù # Character ã
+#U+355c shÇ # Character ã
+U+355d ? # Character ã
+U+355e ? # Character ã
+U+355f kuì # Character ã
+U+3560 ? # Character ã
+U+3561 hé # Character ã¡
+U+3562 gà i # Character ã¢
+#U+3563 yÇn # Character ã£
+U+3564 qiú # Character ã¤
+#U+3565 yÇ # Character ã¥
+U+3566 huà # Character ã¦
+U+3567 ? # Character ã§
+U+3568 fà n # Character ã¨
+U+3569 zhà ng # Character ã©
+#U+356a dÇn # Character ãª
+#U+356b fÇng # Character ã«
+U+356c sòng # Character ã¬
+U+356d à o # Character ã
+#U+356e fÇ # Character ã®
+U+356f nèi # Character ã¯
+U+3570 hè # Character ã°
+U+3571 yóu # Character ã±
+U+3572 huá # Character ã²
+U+3573 ? # Character ã³
+U+3574 chén # Character ã´
+U+3575 guó # Character ãµ
+#U+3576 ngÌ # Character ã¶
+U+3577 huà # Character ã·
+U+3578 lì # Character ã¸
+U+3579 fá # Character ã¹
+U+357a háo # Character ãº
+#U+357b pÇu # Character ã»
+U+357c ? # Character ã¼
+U+357d sì # Character ã½
+U+357e ? # Character ã¾
+U+357f ? # Character ã¿
+U+3580 lè # Character ã
+U+3581 lìn # Character ã
+U+3582 yì # Character ã
+#U+3583 hÇu # Character ã
+U+3584 ? # Character ã
+U+3585 xù # Character ã
+U+3586 qú # Character ã
+U+3587 ér # Character ã
+U+3588 ? # Character ã
+U+3589 ? # Character ã
+U+358a ? # Character ã
+U+358b ? # Character ã
+U+358c ? # Character ã
+U+358d ? # Character ã
+U+358e ? # Character ã
+U+358f nèi # Character ã
+#U+3590 wÄi # Character ã
+U+3591 xiè # Character ã
+U+3592 tà # Character ã
+U+3593 hóng # Character ã
+#U+3594 tÇn # Character ã
+U+3595 bò # Character ã
+U+3596 niè # Character ã
+U+3597 yÃn # Character ã
+U+3598 ? # Character ã
+U+3599 ? # Character ã
+U+359a ? # Character ã
+U+359b ? # Character ã
+U+359c ? # Character ã
+U+359d ? # Character ã
+#U+359e wÄi # Character ã
+U+359f shòu # Character ã
+U+35a0 bà # Character ã
+U+35a1 yè # Character ã¡
+U+35a2 jà # Character ã¢
+U+35a3 tòu # Character ã£
+U+35a4 hán # Character ã¤
+#U+35a5 jiÇng # Character ã¥
+#U+35a6 dÇng # Character ã¦
+#U+35a7 wÄn # Character ã§
+U+35a8 lù # Character ã¨
+#U+35a9 sÇu # Character ã©
+U+35aa guó # Character ãª
+U+35ab lÃng # Character ã«
+U+35ac ? # Character ã¬
+#U+35ad tiÇn # Character ã
+U+35ae lún # Character ã®
+U+35af ? # Character ã¯
+U+35b0 ? # Character ã°
+U+35b1 ? # Character ã±
+U+35b2 ? # Character ã²
+U+35b3 ? # Character ã³
+U+35b4 ? # Character ã´
+U+35b5 ? # Character ãµ
+U+35b6 yè # Character ã¶
+U+35b7 shà # Character ã·
+U+35b8 xué # Character ã¸
+U+35b9 fèn # Character ã¹
+#U+35ba chÇn # Character ãº
+U+35bb róu # Character ã»
+#U+35bc duÇ # Character ã¼
+U+35bd zé # Character ã½
+U+35be è # Character ã¾
+U+35bf xié # Character ã¿
+U+35c0 ? # Character ã
+U+35c1 è # Character ã
+#U+35c2 shÄng # Character ã
+#U+35c3 wÄn # Character ã
+U+35c4 mán # Character ã
+U+35c5 hú # Character ã
+U+35c6 gé # Character ã
+U+35c7 xiá # Character ã
+U+35c8 mà n # Character ã
+U+35c9 bì # Character ã
+U+35ca jà # Character ã
+U+35cb hóu # Character ã
+U+35cc zhì # Character ã
+U+35cd ? # Character ã
+U+35ce ? # Character ã
+U+35cf ? # Character ã
+U+35d0 ? # Character ã
+U+35d1 bà i # Character ã
+U+35d2 Ã i # Character ã
+U+35d3 ? # Character ã
+U+35d4 ? # Character ã
+U+35d5 gòu # Character ã
+U+35d6 dà n # Character ã
+#U+35d7 bÇi # Character ã
+U+35d8 bó # Character ã
+U+35d9 nà # Character ã
+U+35da lì # Character ã
+U+35db xià o # Character ã
+U+35dc xiù # Character ã
+U+35dd ? # Character ã
+U+35de ? # Character ã
+U+35df ? # Character ã
+U+35e0 ? # Character ã
+U+35e1 ? # Character ã¡
+U+35e2 dòng # Character ã¢
+U+35e3 tì # Character ã£
+U+35e4 cù # Character ã¤
+U+35e5 kuò # Character ã¥
+U+35e6 láo # Character ã¦
+U+35e7 zhì # Character ã§
+#U+35e8 Çi # Character ã¨
+U+35e9 ? # Character ã©
+U+35ea ? # Character ãª
+U+35eb qiè # Character ã«
+U+35ec ? # Character ã¬
+U+35ed ? # Character ã
+U+35ee ? # Character ã®
+U+35ef ? # Character ã¯
+U+35f0 chù # Character ã°
+U+35f1 jà # Character ã±
+U+35f2 huò # Character ã²
+#U+35f3 tÇ # Character ã³
+U+35f4 yán # Character ã´
+U+35f5 xù # Character ãµ
+U+35f6 ? # Character ã¶
+#U+35f7 sÇi # Character ã·
+U+35f8 ? # Character ã¸
+U+35f9 ? # Character ã¹
+U+35fa ? # Character ãº
+U+35fb ? # Character ã»
+U+35fc yè # Character ã¼
+#U+35fd xiÇng # Character ã½
+U+35fe ? # Character ã¾
+U+35ff xià # Character ã¿
diff --git a/resources/chars/latin1/row36.trans b/resources/chars/latin1/row36.trans
new file mode 100644
index 0000000..3b12e19
--- /dev/null
+++ b/resources/chars/latin1/row36.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+3600 zuò # Character ã
+U+3601 yì # Character ã
+U+3602 cà # Character ã
+U+3603 ? # Character ã
+U+3604 ? # Character ã
+U+3605 xián # Character ã
+U+3606 tái # Character ã
+U+3607 róng # Character ã
+#U+3608 yÄ« # Character ã
+U+3609 zhì # Character ã
+U+360a yì # Character ã
+U+360b xián # Character ã
+U+360c jù # Character ã
+U+360d jà # Character ã
+#U+360e hÇn # Character ã
+U+360f ? # Character ã
+U+3610 pà o # Character ã
+U+3611 lì # Character ã
+U+3612 ? # Character ã
+U+3613 lán # Character ã
+#U+3614 cÇn # Character ã
+#U+3615 hÇn # Character ã
+U+3616 yán # Character ã
+U+3617 ? # Character ã
+U+3618 ? # Character ã
+U+3619 yán # Character ã
+#U+361a hÇn # Character ã
+U+361b ? # Character ã
+#U+361c chÇ # Character ã
+#U+361d niÇn # Character ã
+U+361e huò # Character ã
+U+361f ? # Character ã
+U+3620 bì # Character ã
+U+3621 xiá # Character ã¡
+#U+3622 wÄng # Character ã¢
+U+3623 xuán # Character ã£
+U+3624 ? # Character ã¤
+U+3625 yóu # Character ã¥
+U+3626 qÃn # Character ã¦
+U+3627 xù # Character ã§
+U+3628 nèi # Character ã¨
+U+3629 bì # Character ã©
+U+362a hà o # Character ãª
+#U+362b jÇng # Character ã«
+U+362c à o # Character ã¬
+U+362d à o # Character ã
+U+362e ? # Character ã®
+U+362f ? # Character ã¯
+U+3630 ? # Character ã°
+U+3631 ? # Character ã±
+U+3632 jú # Character ã²
+U+3633 ? # Character ã³
+U+3634 zuò # Character ã´
+U+3635 bù # Character ãµ
+U+3636 jié # Character ã¶
+U+3637 Ã i # Character ã·
+U+3638 zà ng # Character ã¸
+U+3639 cà # Character ã¹
+U+363a fá # Character ãº
+U+363b ? # Character ã»
+U+363c ? # Character ã¼
+U+363d ? # Character ã½
+U+363e ? # Character ã¾
+U+363f niè # Character ã¿
+U+3640 liù # Character ã
+#U+3641 mÇng # Character ã
+U+3642 duì # Character ã
+U+3643 ? # Character ã
+U+3644 bì # Character ã
+#U+3645 bÇo # Character ã
+U+3646 ? # Character ã
+U+3647 chù # Character ã
+U+3648 hán # Character ã
+#U+3649 tiÇn # Character ã
+U+364a cháng # Character ã
+U+364b ? # Character ã
+U+364c ? # Character ã
+U+364d ? # Character ã
+U+364e ? # Character ã
+U+364f fù # Character ã
+#U+3650 duÇ # Character ã
+#U+3651 yÇ # Character ã
+#U+3652 yÄ # Character ã
+U+3653 kuà # Character ã
+U+3654 hán # Character ã
+U+3655 kuà i # Character ã
+U+3656 ? # Character ã
+U+3657 kuà i # Character ã
+U+3658 ? # Character ã
+#U+3659 lÇng # Character ã
+U+365a ? # Character ã
+#U+365b bÇ # Character ã
+U+365c chà # Character ã
+U+365d xié # Character ã
+U+365e niè # Character ã
+#U+365f lÇng # Character ã
+U+3660 yì # Character ã
+U+3661 ? # Character ã¡
+U+3662 mán # Character ã¢
+U+3663 zhà ng # Character ã£
+U+3664 xià # Character ã¤
+#U+3665 gÇn # Character ã¥
+U+3666 ? # Character ã¦
+U+3667 ? # Character ã§
+U+3668 jì # Character ã¨
+U+3669 liáo # Character ã©
+U+366a yè # Character ãª
+U+366b jà # Character ã«
+U+366c yÃn # Character ã¬
+U+366d ? # Character ã
+U+366e ? # Character ã®
+U+366f yì # Character ã¯
+U+3670 xiè # Character ã°
+U+3671 hà o # Character ã±
+#U+3672 yÇng # Character ã²
+#U+3673 hÇn # Character ã³
+U+3674 chà n # Character ã´
+U+3675 tái # Character ãµ
+U+3676 táng # Character ã¶
+U+3677 zhà # Character ã·
+U+3678 bà o # Character ã¸
+U+3679 méng # Character ã¹
+U+367a guì # Character ãº
+U+367b chán # Character ã»
+#U+367c lÄi # Character ã¼
+U+367d ? # Character ã½
+U+367e xì # Character ã¾
+U+367f ? # Character ã¿
+U+3680 ? # Character ã
+U+3681 qiáo # Character ã
+U+3682 ráng # Character ã
+U+3683 yún # Character ã
+U+3684 ? # Character ã
+U+3685 lóng # Character ã
+U+3686 fù # Character ã
+U+3687 ? # Character ã
+U+3688 ? # Character ã
+#U+3689 gÇ # Character ã
+U+368a ? # Character ã
+U+368b ? # Character ã
+U+368c huà # Character ã
+U+368d guó # Character ã
+U+368e ? # Character ã
+#U+368f gÇo # Character ã
+U+3690 tà o # Character ã
+U+3691 ? # Character ã
+#U+3692 shÇn # Character ã
+U+3693 lái # Character ã
+U+3694 niè # Character ã
+U+3695 fú # Character ã
+#U+3696 gÇo # Character ã
+U+3697 qié # Character ã
+U+3698 bà n # Character ã
+U+3699 ? # Character ã
+U+369a ? # Character ã
+U+369b xì # Character ã
+U+369c xù # Character ã
+U+369d kuà # Character ã
+#U+369e mÄng # Character ã
+U+369f chuò # Character ã
+U+36a0 ? # Character ã
+#U+36a1 jÇ # Character ã¡
+U+36a2 nú # Character ã¢
+U+36a3 xiáo # Character ã£
+U+36a4 yì # Character ã¤
+U+36a5 yú # Character ã¥
+U+36a6 yà # Character ã¦
+#U+36a7 yÇn # Character ã§
+U+36a8 ? # Character ã¨
+#U+36a9 rÇn # Character ã©
+U+36aa hà o # Character ãª
+U+36ab shà # Character ã«
+U+36ac ? # Character ã¬
+U+36ad yóu # Character ã
+U+36ae ? # Character ã®
+U+36af xÃn # Character ã¯
+#U+36b0 bÇ # Character ã°
+U+36b1 ? # Character ã±
+#U+36b2 diÇn # Character ã²
+U+36b3 ? # Character ã³
+U+36b4 bù # Character ã´
+U+36b5 ? # Character ãµ
+U+36b6 sì # Character ã¶
+#U+36b7 Är # Character ã·
+U+36b8 ? # Character ã¸
+#U+36b9 mÇo # Character ã¹
+U+36ba yùn # Character ãº
+U+36bb ? # Character ã»
+U+36bc ? # Character ã¼
+#U+36bd qiÇo # Character ã½
+U+36be ? # Character ã¾
+U+36bf páo # Character ã¿
+U+36c0 ? # Character ã
+U+36c1 ? # Character ã
+#U+36c2 nuÇ # Character ã
+U+36c3 jié # Character ã
+U+36c4 ? # Character ã
+U+36c5 èr # Character ã
+#U+36c6 duÇ # Character ã
+U+36c7 ? # Character ã
+U+36c8 ? # Character ã
+U+36c9 ? # Character ã
+#U+36ca duÇ # Character ã
+U+36cb ? # Character ã
+U+36cc ? # Character ã
+U+36cd qiè # Character ã
+U+36ce ? # Character ã
+U+36cf òu # Character ã
+#U+36d0 sÇu # Character ã
+U+36d1 cà n # Character ã
+U+36d2 dòu # Character ã
+U+36d3 ? # Character ã
+U+36d4 péng # Character ã
+U+36d5 yì # Character ã
+U+36d6 ? # Character ã
+U+36d7 zuò # Character ã
+U+36d8 pò # Character ã
+U+36d9 qiè # Character ã
+#U+36da tÇng # Character ã
+U+36db xìn # Character ã
+U+36dc yóu # Character ã
+U+36dd bèi # Character ã
+U+36de lòng # Character ã
+U+36df ? # Character ã
+U+36e0 ? # Character ã
+U+36e1 ? # Character ã¡
+U+36e2 ? # Character ã¢
+U+36e3 ? # Character ã£
+U+36e4 ? # Character ã¤
+U+36e5 tà # Character ã¥
+#U+36e6 lÇn # Character ã¦
+#U+36e7 mÇn # Character ã§
+#U+36e8 qiÇng # Character ã¨
+U+36e9 zhóu # Character ã©
+U+36ea yà n # Character ãª
+U+36eb ? # Character ã«
+U+36ec lù # Character ã¬
+U+36ed ? # Character ã
+#U+36ee sÇo # Character ã®
+#U+36ef miÇn # Character ã¯
+U+36f0 ? # Character ã°
+U+36f1 ruì # Character ã±
+U+36f2 fà # Character ã²
+U+36f3 chà # Character ã³
+#U+36f4 nÇo # Character ã´
+U+36f5 ? # Character ãµ
+U+36f6 chóu # Character ã¶
+U+36f7 ? # Character ã·
+U+36f8 shù # Character ã¸
+U+36f9 pián # Character ã¹
+U+36fa ? # Character ãº
+#U+36fb kuÇ # Character ã»
+U+36fc shà # Character ã¼
+U+36fd ? # Character ã½
+U+36fe xián # Character ã¾
+U+36ff zhì # Character ã¿
diff --git a/resources/chars/latin1/row37.trans b/resources/chars/latin1/row37.trans
new file mode 100644
index 0000000..dfb3ce4
--- /dev/null
+++ b/resources/chars/latin1/row37.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+3700 ? # Character ã
+U+3701 ? # Character ã
+U+3702 ? # Character ã
+U+3703 lià n # Character ã
+U+3704 xún # Character ã
+U+3705 xù # Character ã
+U+3706 mì # Character ã
+U+3707 huì # Character ã
+U+3708 mù # Character ã
+U+3709 ? # Character ã
+U+370a pà ng # Character ã
+U+370b yì # Character ã
+U+370c gòu # Character ã
+U+370d táng # Character ã
+U+370e qà # Character ã
+U+370f yún # Character ã
+U+3710 shù # Character ã
+U+3711 fú # Character ã
+U+3712 yì # Character ã
+U+3713 dá # Character ã
+U+3714 ? # Character ã
+U+3715 lián # Character ã
+U+3716 cáo # Character ã
+#U+3717 cÇn # Character ã
+U+3718 jù # Character ã
+U+3719 lù # Character ã
+U+371a sù # Character ã
+U+371b nèn # Character ã
+U+371c à o # Character ã
+#U+371d Çn # Character ã
+U+371e qià n # Character ã
+U+371f ? # Character ã
+U+3720 ? # Character ã
+U+3721 ? # Character ã¡
+U+3722 ? # Character ã¢
+U+3723 rán # Character ã£
+#U+3724 shÄn # Character ã¤
+U+3725 mái # Character ã¥
+U+3726 hà n # Character ã¦
+U+3727 yuè # Character ã§
+U+3728 ér # Character ã¨
+U+3729 Ã o # Character ã©
+#U+372a xiÇn # Character ãª
+U+372b mà # Character ã«
+U+372c ? # Character ã¬
+U+372d ? # Character ã
+U+372e là n # Character ã®
+U+372f ? # Character ã¯
+U+3730 yuè # Character ã°
+U+3731 dòng # Character ã±
+#U+3732 wÄng # Character ã²
+U+3733 huái # Character ã³
+U+3734 mèng # Character ã´
+#U+3735 niÇo # Character ãµ
+#U+3736 wÇn # Character ã¶
+U+3737 mà # Character ã·
+U+3738 niè # Character ã¸
+U+3739 qú # Character ã¹
+U+373a zà n # Character ãº
+U+373b lià n # Character ã»
+U+373c zhà # Character ã¼
+#U+373d zÇ # Character ã½
+U+373e hái # Character ã¾
+U+373f xù # Character ã¿
+U+3740 hà o # Character ã
+U+3741 xún # Character ã
+U+3742 zhì # Character ã
+U+3743 fà n # Character ã
+U+3744 chún # Character ã
+U+3745 gòu # Character ã
+U+3746 ? # Character ã
+U+3747 chún # Character ã
+U+3748 luán # Character ã
+U+3749 zhù # Character ã
+#U+374a shÇu # Character ã
+U+374b liáo # Character ã
+U+374c jié # Character ã
+#U+374d xiÄ # Character ã
+U+374e dìng # Character ã
+U+374f jiè # Character ã
+U+3750 róng # Character ã
+U+3751 máng # Character ã
+U+3752 ? # Character ã
+U+3753 gé # Character ã
+U+3754 yà o # Character ã
+U+3755 nÃng # Character ã
+U+3756 yà # Character ã
+U+3757 láng # Character ã
+U+3758 yóng # Character ã
+U+3759 yÃn # Character ã
+U+375a ? # Character ã
+U+375b sù # Character ã
+U+375c ? # Character ã
+U+375d lÃn # Character ã
+U+375e yà # Character ã
+U+375f máo # Character ã
+U+3760 mÃng # Character ã
+U+3761 zuì # Character ã¡
+#U+3762 yÇ # Character ã¢
+U+3763 yè # Character ã£
+U+3764 gòu # Character ã¤
+#U+3765 mÇ # Character ã¥
+U+3766 jùn # Character ã¦
+#U+3767 wÄn # Character ã§
+U+3768 ? # Character ã¨
+U+3769 ? # Character ã©
+U+376a dià n # Character ãª
+U+376b lóng # Character ã«
+U+376c ? # Character ã¬
+#U+376d xÇng # Character ã
+U+376e cuì # Character ã®
+U+376f qiáo # Character ã¯
+U+3770 mián # Character ã°
+U+3771 mèng # Character ã±
+#U+3772 qÇn # Character ã²
+U+3773 ? # Character ã³
+U+3774 wán # Character ã´
+U+3775 dé # Character ãµ
+U+3776 à i # Character ã¶
+U+3777 ? # Character ã·
+U+3778 bià n # Character ã¸
+U+3779 nóu # Character ã¹
+U+377a lián # Character ãº
+#U+377b jÇn # Character ã»
+U+377c ? # Character ã¼
+U+377d chuà # Character ã½
+#U+377e zuÇ # Character ã¾
+U+377f bó # Character ã¿
+U+3780 ? # Character ã
+U+3781 yà o # Character ã
+#U+3782 tuÇ # Character ã
+U+3783 jà # Character ã
+U+3784 ? # Character ã
+#U+3785 guÇ # Character ã
+#U+3786 jÇ # Character ã
+#U+3787 wÄi # Character ã
+U+3788 ? # Character ã
+U+3789 ? # Character ã
+U+378a xù # Character ã
+#U+378b niÇn # Character ã
+U+378c yùn # Character ã
+U+378d ? # Character ã
+#U+378e bÇ # Character ã
+U+378f zhé # Character ã
+#U+3790 jÅ« # Character ã
+#U+3791 wÄi # Character ã
+U+3792 xì # Character ã
+#U+3793 qÇ # Character ã
+U+3794 yà # Character ã
+U+3795 xiè # Character ã
+U+3796 cì # Character ã
+U+3797 qiú # Character ã
+U+3798 tún # Character ã
+U+3799 nià o # Character ã
+U+379a qì # Character ã
+#U+379b jÇ # Character ã
+U+379c ? # Character ã
+U+379d ? # Character ã
+U+379e ? # Character ã
+U+379f dià n # Character ã
+U+37a0 láo # Character ã
+#U+37a1 zhÇn # Character ã¡
+U+37a2 ? # Character ã¢
+U+37a3 ? # Character ã£
+U+37a4 yÃn # Character ã¤
+U+37a5 cén # Character ã¥
+#U+37a6 jÇ # Character ã¦
+U+37a7 huì # Character ã§
+#U+37a8 zÇi # Character ã¨
+U+37a9 lán # Character ã©
+U+37aa náo # Character ãª
+U+37ab jù # Character ã«
+U+37ac qìn # Character ã¬
+U+37ad dà i # Character ã
+U+37ae ? # Character ã®
+U+37af jié # Character ã¯
+#U+37b0 xÇ # Character ã°
+U+37b1 ? # Character ã±
+U+37b2 yòng # Character ã²
+#U+37b3 dÇu # Character ã³
+U+37b4 chà # Character ã´
+U+37b5 ? # Character ãµ
+#U+37b6 mÇn # Character ã¶
+U+37b7 huáng # Character ã·
+U+37b8 suì # Character ã¸
+#U+37b9 kÄ # Character ã¹
+U+37ba zú # Character ãº
+U+37bb hà o # Character ã»
+U+37bc chéng # Character ã¼
+U+37bd xuè # Character ã½
+U+37be nà # Character ã¾
+U+37bf chì # Character ã¿
+U+37c0 lián # Character ã
+U+37c1 Ã n # Character ã
+#U+37c2 chÇ # Character ã
+U+37c3 ? # Character ã
+U+37c4 xiáng # Character ã
+U+37c5 yáng # Character ã
+U+37c6 huá # Character ã
+U+37c7 cuó # Character ã
+U+37c8 qiú # Character ã
+U+37c9 láo # Character ã
+U+37ca fú # Character ã
+U+37cb duì # Character ã
+U+37cc máng # Character ã
+U+37cd láng # Character ã
+#U+37ce tuÇ # Character ã
+U+37cf hán # Character ã
+#U+37d0 mÇng # Character ã
+U+37d1 bó # Character ã
+U+37d2 ? # Character ã
+U+37d3 qà # Character ã
+U+37d4 hán # Character ã
+U+37d5 ? # Character ã
+U+37d6 lòng # Character ã
+U+37d7 ? # Character ã
+U+37d8 tiáo # Character ã
+#U+37d9 lÇo # Character ã
+U+37da qà # Character ã
+U+37db zà n # Character ã
+U+37dc mà # Character ã
+U+37dd péi # Character ã
+U+37de zhà n # Character ã
+U+37df xià ng # Character ã
+#U+37e0 gÇng # Character ã
+U+37e1 ? # Character ã¡
+U+37e2 qà # Character ã¢
+U+37e3 ? # Character ã£
+U+37e4 lù # Character ã¤
+U+37e5 ? # Character ã¥
+U+37e6 yùn # Character ã¦
+U+37e7 è # Character ã§
+U+37e8 quán # Character ã¨
+U+37e9 mÃn # Character ã©
+#U+37ea wÄi # Character ãª
+U+37eb quán # Character ã«
+#U+37ec shÇ # Character ã¬
+U+37ed mÃn # Character ã
+U+37ee ? # Character ã®
+U+37ef ? # Character ã¯
+#U+37f0 mÇng # Character ã°
+#U+37f1 yÇo # Character ã±
+U+37f2 jué # Character ã²
+U+37f3 lì # Character ã³
+U+37f4 kuà i # Character ã´
+#U+37f5 gÇng # Character ãµ
+U+37f6 yuán # Character ã¶
+U+37f7 da # Character ã·
+U+37f8 ? # Character ã¸
+U+37f9 láo # Character ã¹
+U+37fa lóu # Character ãº
+U+37fb qià n # Character ã»
+U+37fc áo # Character ã¼
+#U+37fd biÇo # Character ã½
+U+37fe ? # Character ã¾
+U+37ff máng # Character ã¿
diff --git a/resources/chars/latin1/row38.trans b/resources/chars/latin1/row38.trans
new file mode 100644
index 0000000..6685c4a
--- /dev/null
+++ b/resources/chars/latin1/row38.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+3800 dÇo # Character ã
+U+3801 ? # Character ã
+U+3802 áo # Character ã
+U+3803 ? # Character ã
+U+3804 xà # Character ã
+U+3805 fú # Character ã
+U+3806 ? # Character ã
+U+3807 jiù # Character ã
+U+3808 rùn # Character ã
+U+3809 tóng # Character ã
+#U+380a qÅ« # Character ã
+U+380b è # Character ã
+U+380c ? # Character ã
+U+380d jà # Character ã
+U+380e jà # Character ã
+U+380f huá # Character ã
+U+3810 jià o # Character ã
+U+3811 zuì # Character ã
+#U+3812 biÇo # Character ã
+U+3813 méng # Character ã
+U+3814 bà i # Character ã
+#U+3815 wÄi # Character ã
+U+3816 jì # Character ã
+U+3817 Ã o # Character ã
+#U+3818 yÇ # Character ã
+U+3819 háo # Character ã
+U+381a duì # Character ã
+U+381b wò # Character ã
+U+381c nì # Character ã
+U+381d cuán # Character ã
+U+381e ? # Character ã
+U+381f là # Character ã
+U+3820 lú # Character ã
+#U+3821 niÇo # Character ã ¡
+U+3822 huà # Character 㠢
+U+3823 là i # Character 㠣
+U+3824 ? # Character ã ¤
+#U+3825 lÇ # Character ã ¥
+U+3826 ? # Character ã ¦
+U+3827 mà # Character 㠧
+U+3828 yù # Character 㠨
+U+3829 ? # Character ã ©
+U+382a jù # Character 㠪
+U+382b ? # Character ã «
+U+382c ? # Character ã ¬
+#U+382d zhÇn # Character ã
+U+382e ? # Character ã ®
+#U+382f yÇ # Character ã ¯
+U+3830 ? # Character ã °
+U+3831 jì # Character 㠱
+#U+3832 bÇ # Character ã ²
+U+3833 ? # Character ã ³
+U+3834 rèn # Character 㠴
+U+3835 ? # Character ã µ
+U+3836 fán # Character 㠶
+U+3837 gé # Character 㠷
+U+3838 kù # Character 㠸
+U+3839 jiè # Character 㠹
+U+383a miáo # Character 㠺
+U+383b ? # Character ã »
+U+383c ? # Character ã ¼
+U+383d tóng # Character 㠽
+U+383e ? # Character ã ¾
+#U+383f cÇ # Character ã ¿
+U+3840 bì # Character ã¡
+#U+3841 kÇi # Character ã¡
+U+3842 lì # Character ã¡
+U+3843 ? # Character ã¡
+#U+3844 sÇn # Character ã¡
+#U+3845 nuÇ # Character ã¡
+U+3846 ? # Character ã¡
+U+3847 jà # Character ã¡
+U+3848 mén # Character ã¡
+U+3849 xián # Character ã¡
+U+384a qià # Character ã¡
+U+384b è # Character ã¡
+U+384c mà o # Character ã¡
+U+384d ? # Character ã¡
+U+384e ? # Character ã¡
+U+384f tóu # Character ã¡
+U+3850 ? # Character ã¡
+#U+3851 qiÇo # Character ã¡
+U+3852 ? # Character ã¡
+U+3853 ? # Character ã¡
+U+3854 wù # Character ã¡
+U+3855 ? # Character ã¡
+U+3856 chuáng # Character ã¡
+U+3857 tà # Character ã¡
+U+3858 lián # Character ã¡
+U+3859 bì # Character ã¡
+U+385a ? # Character ã¡
+U+385b máng # Character ã¡
+#U+385c xuÄ # Character ã¡
+U+385d fèng # Character ã¡
+#U+385e lÄi # Character ã¡
+U+385f ? # Character ã¡
+U+3860 zhèng # Character ã¡
+U+3861 chú # Character 㡡
+U+3862 mà n # Character 㡢
+U+3863 lóng # Character 㡣
+U+3864 ? # Character 㡤
+#U+3865 yÇn # Character ã¡¥
+U+3866 ? # Character 㡦
+U+3867 zhèng # Character 㡧
+#U+3868 qiÄn # Character 㡨
+U+3869 luán # Character 㡩
+U+386a nié # Character 㡪
+U+386b yì # Character 㡫
+U+386c ? # Character 㡬
+U+386d jì # Character ã¡
+U+386e jà # Character 㡮
+U+386f zhái # Character 㡯
+#U+3870 yÇ # Character ã¡°
+#U+3871 jiÇ # Character 㡱
+U+3872 huán # Character 㡲
+#U+3873 dÇ # Character 㡳
+U+3874 ? # Character ã¡´
+U+3875 lÃng # Character 㡵
+U+3876 jì # Character 㡶
+#U+3877 bÄn # Character ã¡·
+#U+3878 zhÇ # Character 㡸
+U+3879 cì # Character 㡹
+U+387a dà n # Character 㡺
+U+387b lià o # Character 㡻
+U+387c yì # Character 㡼
+U+387d zhà o # Character 㡽
+U+387e xià n # Character 㡾
+U+387f chì # Character 㡿
+U+3880 cì # Character ã¢
+#U+3881 chÇ # Character ã¢
+#U+3882 yÇn # Character ã¢
+U+3883 láng # Character ã¢
+U+3884 dòu # Character ã¢
+U+3885 lòng # Character ã¢
+U+3886 chán # Character ã¢
+U+3887 ? # Character ã¢
+U+3888 tuà # Character ã¢
+U+3889 chá # Character ã¢
+#U+388a Çi # Character ã¢
+#U+388b chÇ # Character ã¢
+U+388c ? # Character ã¢
+U+388d yÃng # Character ã¢
+U+388e chà # Character ã¢
+U+388f tóu # Character ã¢
+U+3890 ? # Character ã¢
+U+3891 tuà # Character ã¢
+U+3892 chá # Character ã¢
+#U+3893 yÇo # Character ã¢
+#U+3894 zÇng # Character ã¢
+U+3895 ? # Character ã¢
+U+3896 ? # Character ã¢
+U+3897 qià o # Character ã¢
+U+3898 lián # Character ã¢
+U+3899 qÃn # Character ã¢
+#U+389a lÇ # Character ã¢
+U+389b yà n # Character ã¢
+U+389c ? # Character ã¢
+U+389d ? # Character ã¢
+U+389e yì # Character ã¢
+#U+389f chÇn # Character ã¢
+#U+38a0 jiÇng # Character ã¢
+#U+38a1 jiÇng # Character 㢡
+U+38a2 ? # Character 㢢
+U+38a3 jìng # Character 㢣
+U+38a4 ? # Character 㢤
+U+38a5 dòng # Character 㢥
+U+38a6 ? # Character 㢦
+U+38a7 juà n # Character 㢧
+U+38a8 hà n # Character 㢨
+U+38a9 dì # Character 㢩
+U+38aa ? # Character 㢪
+U+38ab ? # Character 㢫
+U+38ac hóng # Character 㢬
+U+38ad ? # Character ã¢
+U+38ae chà # Character 㢮
+U+38af mÃn # Character 㢯
+U+38b0 bì # Character 㢰
+U+38b1 ? # Character 㢱
+U+38b2 xùn # Character 㢲
+U+38b3 lú # Character 㢳
+U+38b4 ? # Character 㢴
+U+38b5 shè # Character 㢵
+U+38b6 bì # Character 㢶
+U+38b7 ? # Character 㢷
+U+38b8 bì # Character 㢸
+U+38b9 ? # Character 㢹
+U+38ba xián # Character 㢺
+#U+38bb wÄi # Character 㢻
+U+38bc biè # Character 㢼
+#U+38bd Är # Character 㢽
+U+38be juà n # Character 㢾
+U+38bf ? # Character 㢿
+U+38c0 zhèn # Character ã£
+U+38c1 bèi # Character ã£
+U+38c2 yì # Character ã£
+#U+38c3 yÇ # Character ã£
+U+38c4 qú # Character ã£
+U+38c5 zà n # Character ã£
+U+38c6 mà # Character ã£
+#U+38c7 nÇ # Character ã£
+U+38c8 sì # Character ã£
+U+38c9 ? # Character ã£
+U+38ca ? # Character ã£
+U+38cb ? # Character ã£
+U+38cc shà n # Character ã£
+U+38cd tái # Character ã£
+U+38ce mù # Character ã£
+U+38cf jìng # Character ã£
+U+38d0 bià n # Character ã£
+U+38d1 róng # Character ã£
+U+38d2 cèng # Character ã£
+U+38d3 cà n # Character ã£
+U+38d4 ? # Character ã£
+U+38d5 ? # Character ã£
+U+38d6 ? # Character ã£
+U+38d7 ? # Character ã£
+U+38d8 ? # Character ã£
+U+38d9 dà # Character ã£
+U+38da tóng # Character ã£
+U+38db tà # Character ã£
+U+38dc xÃng # Character ã£
+U+38dd ? # Character ã£
+U+38de duó # Character ã£
+U+38df xì # Character ã£
+U+38e0 tóng # Character ã£
+U+38e1 ? # Character 㣡
+U+38e2 tà # Character 㣢
+#U+38e3 shÇn # Character 㣣
+U+38e4 jià n # Character 㣤
+U+38e5 zhì # Character 㣥
+U+38e6 ? # Character 㣦
+U+38e7 yìn # Character 㣧
+U+38e8 ? # Character 㣨
+U+38e9 ? # Character 㣩
+#U+38ea huÇn # Character 㣪
+#U+38eb zhÇng # Character 㣫
+U+38ec qì # Character 㣬
+U+38ed ? # Character ã£
+U+38ee ? # Character 㣮
+U+38ef xiè # Character 㣯
+U+38f0 xiè # Character 㣰
+U+38f1 zé # Character 㣱
+U+38f2 wéi # Character 㣲
+U+38f3 ? # Character 㣳
+U+38f4 ? # Character 㣴
+U+38f5 tà # Character 㣵
+U+38f6 ? # Character 㣶
+U+38f7 nìng # Character 㣷
+U+38f8 ? # Character 㣸
+U+38f9 ? # Character 㣹
+U+38fa ? # Character 㣺
+U+38fb yì # Character 㣻
+#U+38fc rÄn # Character 㣼
+U+38fd shù # Character 㣽
+U+38fe chà # Character 㣾
+U+38ff zhuó # Character 㣿
diff --git a/resources/chars/latin1/row39.trans b/resources/chars/latin1/row39.trans
new file mode 100644
index 0000000..3f52348
--- /dev/null
+++ b/resources/chars/latin1/row39.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+3900 ? # Character ã¤
+#U+3901 miÇn # Character ã¤
+U+3902 jà # Character ã¤
+U+3903 fáng # Character ã¤
+U+3904 pèi # Character ã¤
+U+3905 à i # Character ã¤
+U+3906 fà n # Character ã¤
+#U+3907 Ço # Character ã¤
+U+3908 qìn # Character ã¤
+U+3909 qià # Character ã¤
+U+390a xià o # Character ã¤
+U+390b ? # Character ã¤
+U+390c ? # Character ã¤
+#U+390d qiÇo # Character ã¤
+U+390e ? # Character ã¤
+U+390f tóng # Character ã¤
+U+3910 ? # Character ã¤
+U+3911 yòu # Character ã¤
+U+3912 ? # Character ã¤
+U+3913 bèn # Character ã¤
+U+3914 fú # Character ã¤
+U+3915 chù # Character ã¤
+U+3916 zhù # Character ã¤
+U+3917 ? # Character ã¤
+U+3918 chù # Character ã¤
+U+3919 ? # Character ã¤
+U+391a háng # Character ã¤
+U+391b nÃn # Character ã¤
+U+391c jué # Character ã¤
+U+391d ? # Character ã¤
+U+391e chà # Character ã¤
+#U+391f kÇng # Character ã¤
+U+3920 liè # Character ã¤
+U+3921 lì # Character 㤡
+U+3922 xù # Character 㤢
+U+3923 ? # Character 㤣
+U+3924 yú # Character 㤤
+U+3925 hà i # Character 㤥
+U+3926 lì # Character 㤦
+U+3927 hóu # Character 㤧
+#U+3928 gÇng # Character 㤨
+U+3929 kè # Character 㤩
+U+392a yuà n # Character 㤪
+U+392b dé # Character 㤫
+U+392c huì # Character 㤬
+U+392d ? # Character ã¤
+U+392e kuáng # Character 㤮
+#U+392f jiÇng # Character 㤯
+#U+3930 zÇn # Character 㤰
+U+3931 fù # Character 㤱
+U+3932 qiè # Character 㤲
+#U+3933 bÄi # Character 㤳
+U+3934 xà # Character 㤴
+U+3935 cà # Character 㤵
+U+3936 páng # Character 㤶
+U+3937 ? # Character 㤷
+U+3938 xì # Character 㤸
+U+3939 qiú # Character 㤹
+#U+393a huÇng # Character 㤺
+U+393b ? # Character 㤻
+U+393c ? # Character 㤼
+U+393d chóu # Character 㤽
+U+393e sà n # Character 㤾
+U+393f ? # Character 㤿
+U+3940 dé # Character ã¥
+U+3941 dé # Character ã¥
+U+3942 tè # Character ã¥
+U+3943 mèn # Character ã¥
+U+3944 lÃng # Character ã¥
+U+3945 shòu # Character ã¥
+U+3946 dià n # Character ã¥
+U+3947 cán # Character ã¥
+U+3948 dié # Character ã¥
+U+3949 chè # Character ã¥
+U+394a péng # Character ã¥
+U+394b ? # Character ã¥
+U+394c jú # Character ã¥
+U+394d jì # Character ã¥
+U+394e lái # Character ã¥
+#U+394f tiÇn # Character ã¥
+U+3950 yuà n # Character ã¥
+U+3951 ? # Character ã¥
+#U+3952 cÇi # Character ã¥
+#U+3953 qÇ # Character ã¥
+U+3954 yú # Character ã¥
+U+3955 lián # Character ã¥
+U+3956 ? # Character ã¥
+U+3957 ? # Character ã¥
+U+3958 ? # Character ã¥
+U+3959 ? # Character ã¥
+U+395a yú # Character ã¥
+U+395b jà # Character ã¥
+U+395c wèi # Character ã¥
+#U+395d mÇ # Character ã¥
+U+395e cuì # Character ã¥
+U+395f xié # Character ã¥
+#U+3960 xÇ # Character ã¥
+U+3961 xì # Character 㥡
+U+3962 qiú # Character 㥢
+U+3963 huì # Character 㥣
+U+3964 ? # Character 㥤
+U+3965 yú # Character 㥥
+U+3966 qiè # Character 㥦
+U+3967 shùn # Character 㥧
+U+3968 chuà # Character 㥨
+#U+3969 duÇ # Character 㥩
+U+396a lóu # Character 㥪
+U+396b ? # Character 㥫
+U+396c páng # Character 㥬
+U+396d tà i # Character ã¥
+U+396e zhòu # Character 㥮
+#U+396f yÇn # Character 㥯
+U+3970 ? # Character 㥰
+#U+3971 fÄi # Character 㥱
+U+3972 shèn # Character 㥲
+U+3973 yuán # Character 㥳
+U+3974 yà # Character 㥴
+U+3975 hùn # Character 㥵
+U+3976 sè # Character 㥶
+U+3977 yè # Character 㥷
+#U+3978 mÇn # Character 㥸
+#U+3979 fÄn # Character 㥹
+U+397a hé # Character 㥺
+U+397b ? # Character 㥻
+#U+397c yÇn # Character 㥼
+U+397d cè # Character 㥽
+U+397e nì # Character 㥾
+U+397f à o # Character 㥿
+U+3980 féng # Character ã¦
+U+3981 lián # Character ã¦
+U+3982 cháng # Character ã¦
+#U+3983 chÇn # Character ã¦
+U+3984 má # Character ã¦
+U+3985 dì # Character ã¦
+U+3986 ? # Character ã¦
+U+3987 lù # Character ã¦
+U+3988 ? # Character ã¦
+U+3989 yì # Character ã¦
+U+398a huá # Character ã¦
+U+398b ? # Character ã¦
+U+398c tuì # Character ã¦
+U+398d è # Character ã¦
+U+398e huà # Character ã¦
+#U+398f sÇn # Character ã¦
+U+3990 nì # Character ã¦
+#U+3991 liÇn # Character ã¦
+U+3992 là # Character ã¦
+U+3993 xià n # Character ã¦
+U+3994 yà n # Character ã¦
+U+3995 lóng # Character ã¦
+U+3996 mèn # Character ã¦
+U+3997 jià n # Character ã¦
+U+3998 ? # Character ã¦
+U+3999 ? # Character ã¦
+#U+399a biÇn # Character ã¦
+U+399b yú # Character ã¦
+U+399c huò # Character ã¦
+#U+399d miÇo # Character ã¦
+U+399e chóu # Character ã¦
+U+399f hà i # Character ã¦
+U+39a0 ? # Character ã¦
+U+39a1 lè # Character 㦡
+U+39a2 jié # Character 㦢
+U+39a3 wèi # Character 㦣
+U+39a4 yì # Character 㦤
+U+39a5 huán # Character 㦥
+U+39a6 hè # Character 㦦
+#U+39a7 cÇn # Character 㦧
+U+39a8 lán # Character 㦨
+#U+39a9 yÇn # Character 㦩
+U+39aa xiè # Character 㦪
+U+39ab ? # Character 㦫
+#U+39ac luÇ # Character 㦬
+U+39ad lÃng # Character ã¦
+U+39ae qián # Character 㦮
+U+39af huò # Character 㦯
+U+39b0 ? # Character 㦰
+#U+39b1 wÇ # Character 㦱
+U+39b2 ? # Character 㦲
+U+39b3 ? # Character 㦳
+U+39b4 gé # Character 㦴
+U+39b5 ? # Character 㦵
+U+39b6 dié # Character 㦶
+#U+39b7 yÇng # Character 㦷
+#U+39b8 jÇ # Character 㦸
+U+39b9 à ng # Character 㦹
+#U+39ba rÇ # Character 㦺
+U+39bb xà # Character 㦻
+U+39bc shuà ng # Character 㦼
+U+39bd xù # Character 㦽
+U+39be yà # Character 㦾
+U+39bf hù # Character 㦿
+U+39c0 jà # Character ã§
+U+39c1 qù # Character ã§
+U+39c2 tián # Character ã§
+U+39c3 ? # Character ã§
+#U+39c4 qiÇn # Character ã§
+U+39c5 mù # Character ã§
+U+39c6 ? # Character ã§
+#U+39c7 mÇo # Character ã§
+#U+39c8 yÇn # Character ã§
+U+39c9 gà i # Character ã§
+U+39ca bá # Character ã§
+#U+39cb xiÇn # Character ã§
+U+39cc mà o # Character ã§
+#U+39cd fÇng # Character ã§
+U+39ce yá # Character ã§
+U+39cf ? # Character ã§
+#U+39d0 sÇng # Character ã§
+U+39d1 wéi # Character ã§
+U+39d2 xué # Character ã§
+U+39d3 ? # Character ã§
+U+39d4 guà i # Character ã§
+U+39d5 jiù # Character ã§
+U+39d6 è # Character ã§
+#U+39d7 zÇ # Character ã§
+U+39d8 cuì # Character ã§
+U+39d9 bì # Character ã§
+#U+39da wÇ # Character ã§
+U+39db ? # Character ã§
+U+39dc liè # Character ã§
+U+39dd ? # Character ã§
+U+39de ? # Character ã§
+#U+39df kuÇi # Character ã§
+U+39e0 ? # Character ã§
+U+39e1 hà i # Character 㧡
+U+39e2 ? # Character 㧢
+U+39e3 zhù # Character 㧣
+U+39e4 chòng # Character 㧤
+#U+39e5 xiÇn # Character 㧥
+U+39e6 xuà n # Character 㧦
+U+39e7 ? # Character 㧧
+U+39e8 qiú # Character 㧨
+U+39e9 pèi # Character 㧩
+#U+39ea guÇ # Character 㧪
+U+39eb ér # Character 㧫
+#U+39ec gÇng # Character 㧬
+U+39ed qióng # Character ã§
+U+39ee ? # Character 㧮
+#U+39ef lÇo # Character 㧯
+U+39f0 lì # Character 㧰
+U+39f1 chèn # Character 㧱
+#U+39f2 sÇn # Character 㧲
+U+39f3 bó # Character 㧳
+#U+39f4 wÇ # Character 㧴
+U+39f5 póu # Character 㧵
+U+39f6 ? # Character 㧶
+U+39f7 duò # Character 㧷
+U+39f8 ? # Character 㧸
+U+39f9 tè # Character 㧹
+U+39fa tà # Character 㧺
+#U+39fb zhÇ # Character 㧻
+U+39fc bià o # Character 㧼
+U+39fd gù # Character 㧽
+U+39fe ? # Character 㧾
+U+39ff ? # Character 㧿
diff --git a/resources/chars/latin1/row3a.trans b/resources/chars/latin1/row3a.trans
new file mode 100644
index 0000000..26ccd46
--- /dev/null
+++ b/resources/chars/latin1/row3a.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+3a00 bÇng # Character ã¨
+U+3a01 zhà # Character ã¨
+#U+3a02 dÇng # Character ã¨
+U+3a03 chéng # Character ã¨
+U+3a04 zhà o # Character ã¨
+U+3a05 nèi # Character ã¨
+#U+3a06 lÇn # Character ã¨
+U+3a07 pó # Character ã¨
+#U+3a08 jÇ # Character ã¨
+#U+3a09 mÇn # Character ã¨
+#U+3a0a wÄi # Character ã¨
+#U+3a0b chÄ # Character ã¨
+U+3a0c gòu # Character ã¨
+U+3a0d ? # Character ã¨
+U+3a0e rú # Character ã¨
+U+3a0f ? # Character ã¨
+#U+3a10 bÇ # Character ã¨
+U+3a11 ? # Character ã¨
+U+3a12 kuà # Character ã¨
+U+3a13 láo # Character ã¨
+U+3a14 hà n # Character ã¨
+U+3a15 yÃng # Character ã¨
+U+3a16 zhì # Character ã¨
+U+3a17 jié # Character ã¨
+#U+3a18 xÇng # Character ã¨
+U+3a19 xié # Character ã¨
+U+3a1a xún # Character ã¨
+#U+3a1b shÇn # Character ã¨
+U+3a1c qián # Character ã¨
+U+3a1d xiè # Character ã¨
+U+3a1e sù # Character ã¨
+U+3a1f hái # Character ã¨
+U+3a20 mì # Character ã¨
+U+3a21 hún # Character 㨡
+U+3a22 ? # Character 㨢
+U+3a23 ? # Character 㨣
+U+3a24 huì # Character 㨤
+U+3a25 nà # Character 㨥
+#U+3a26 sÇng # Character 㨦
+U+3a27 bèn # Character 㨧
+U+3a28 liù # Character 㨨
+U+3a29 jié # Character 㨩
+U+3a2a huà ng # Character 㨪
+#U+3a2b lÇn # Character 㨫
+U+3a2c ? # Character 㨬
+U+3a2d hù # Character ã¨
+U+3a2e ? # Character 㨮
+U+3a2f huò # Character 㨯
+U+3a30 gé # Character 㨰
+U+3a31 yáo # Character 㨱
+U+3a32 cè # Character 㨲
+#U+3a33 guÇ # Character 㨳
+U+3a34 jià n # Character 㨴
+#U+3a35 jiÇn # Character 㨵
+U+3a36 chóu # Character 㨶
+U+3a37 jìn # Character 㨷
+U+3a38 mà # Character 㨸
+U+3a39 huì # Character 㨹
+U+3a3a mén # Character 㨺
+U+3a3b cán # Character 㨻
+U+3a3c luè # Character 㨼
+#U+3a3d pÇ # Character 㨽
+U+3a3e yà ng # Character 㨾
+U+3a3f jù # Character 㨿
+U+3a40 jù # Character ã©
+U+3a41 què # Character ã©
+U+3a42 ? # Character ã©
+U+3a43 ? # Character ã©
+U+3a44 ? # Character ã©
+U+3a45 ? # Character ã©
+U+3a46 jiù # Character ã©
+U+3a47 huà # Character ã©
+U+3a48 xià n # Character ã©
+U+3a49 xié # Character ã©
+U+3a4a ? # Character ã©
+U+3a4b sù # Character ã©
+U+3a4c fèi # Character ã©
+U+3a4d cè # Character ã©
+U+3a4e yè # Character ã©
+U+3a4f ? # Character ã©
+U+3a50 ? # Character ã©
+U+3a51 ? # Character ã©
+U+3a52 qÃn # Character ã©
+#U+3a53 huÇ # Character ã©
+U+3a54 tún # Character ã©
+U+3a55 ? # Character ã©
+U+3a56 qiáng # Character ã©
+U+3a57 xà # Character ã©
+#U+3a58 yÇ # Character ã©
+U+3a59 ? # Character ã©
+U+3a5a méng # Character ã©
+U+3a5b tuán # Character ã©
+#U+3a5c lÇn # Character ã©
+U+3a5d háo # Character ã©
+U+3a5e cì # Character ã©
+U+3a5f zhà i # Character ã©
+#U+3a60 piÇo # Character ã©
+#U+3a61 luÇ # Character ã©¡
+U+3a62 mà # Character 㩢
+U+3a63 ? # Character ã©£
+U+3a64 ? # Character 㩤
+U+3a65 ? # Character ã©¥
+U+3a66 xié # Character 㩦
+U+3a67 bó # Character 㩧
+U+3a68 huì # Character 㩨
+#U+3a69 qÇ # Character ã©©
+U+3a6a xié # Character 㩪
+U+3a6b ? # Character ã©«
+U+3a6c ? # Character 㩬
+U+3a6d bó # Character ã©
+U+3a6e qián # Character 㩮
+#U+3a6f bÇn # Character 㩯
+#U+3a70 jiÇo # Character ã©°
+U+3a71 jué # Character 㩱
+#U+3a72 kÇn # Character 㩲
+#U+3a73 sÇng # Character 㩳
+U+3a74 jú # Character 㩴
+U+3a75 è # Character 㩵
+U+3a76 niè # Character 㩶
+U+3a77 ? # Character ã©·
+U+3a78 dié # Character 㩸
+U+3a79 dié # Character 㩹
+U+3a7a ? # Character 㩺
+#U+3a7b guÇ # Character ã©»
+U+3a7c ? # Character 㩼
+U+3a7d qà # Character 㩽
+U+3a7e chuà # Character 㩾
+U+3a7f ? # Character ã©¿
+U+3a80 yú # Character ãª
+U+3a81 qÃn # Character ãª
+U+3a82 ? # Character ãª
+#U+3a83 kÄ # Character ãª
+U+3a84 fú # Character ãª
+U+3a85 ? # Character ãª
+#U+3a86 dÇ # Character ãª
+U+3a87 xià n # Character ãª
+U+3a88 guì # Character ãª
+U+3a89 hé # Character ãª
+U+3a8a qún # Character ãª
+U+3a8b hà n # Character ãª
+#U+3a8c tÇng # Character ãª
+U+3a8d bó # Character ãª
+#U+3a8e shÇn # Character ãª
+#U+3a8f bÇ # Character ãª
+U+3a90 lù # Character ãª
+U+3a91 yè # Character ãª
+U+3a92 nà # Character ãª
+U+3a93 chuái # Character ãª
+U+3a94 sà n # Character ãª
+U+3a95 dià o # Character ãª
+U+3a96 lù # Character ãª
+#U+3a97 tÇu # Character ãª
+#U+3a98 liÇn # Character ãª
+#U+3a99 kÄ # Character ãª
+U+3a9a sà n # Character ãª
+#U+3a9b zhÄn # Character ãª
+#U+3a9c chuÇi # Character ãª
+U+3a9d lià n # Character ãª
+U+3a9e mà o # Character ãª
+U+3a9f ? # Character ãª
+U+3aa0 qià n # Character ãª
+#U+3aa1 kÄ # Character 㪡
+#U+3aa2 shÇo # Character 㪢
+U+3aa3 qià o # Character 㪣
+U+3aa4 bì # Character 㪤
+U+3aa5 ? # Character 㪥
+U+3aa6 yìn # Character 㪦
+U+3aa7 ? # Character 㪧
+U+3aa8 shà n # Character 㪨
+U+3aa9 sù # Character 㪩
+U+3aaa sà # Character 㪪
+U+3aab ruì # Character 㪫
+U+3aac zhuó # Character 㪬
+U+3aad lú # Character ãª
+U+3aae lÃng # Character 㪮
+U+3aaf chá # Character 㪯
+U+3ab0 ? # Character 㪰
+U+3ab1 huà n # Character 㪱
+U+3ab2 ? # Character 㪲
+U+3ab3 ? # Character 㪳
+U+3ab4 jiá # Character 㪴
+U+3ab5 bà n # Character 㪵
+U+3ab6 hú # Character 㪶
+#U+3ab7 dÇu # Character 㪷
+U+3ab8 ? # Character 㪸
+#U+3ab9 lÇu # Character 㪹
+U+3aba ? # Character 㪺
+U+3abb juà n # Character 㪻
+#U+3abc kÄ # Character 㪼
+#U+3abd suÇ # Character 㪽
+U+3abe gé # Character 㪾
+U+3abf zhé # Character 㪿
+#U+3ac0 dÇng # Character ã«
+U+3ac1 duà n # Character ã«
+U+3ac2 zhù # Character ã«
+#U+3ac3 yÇn # Character ã«
+U+3ac4 páng # Character ã«
+U+3ac5 chá # Character ã«
+U+3ac6 ? # Character ã«
+U+3ac7 ? # Character ã«
+U+3ac8 ? # Character ã«
+U+3ac9 ? # Character ã«
+#U+3aca yÇ # Character ã«
+U+3acb ? # Character ã«
+U+3acc ? # Character ã«
+U+3acd yóu # Character ã«
+#U+3ace gÇn # Character ã«
+#U+3acf yÇo # Character ã«
+#U+3ad0 yÇo # Character ã«
+U+3ad1 shà # Character ã«
+#U+3ad2 gÇng # Character ã«
+#U+3ad3 qÇ # Character ã«
+U+3ad4 gèn # Character ã«
+U+3ad5 ? # Character ã«
+U+3ad6 ? # Character ã«
+U+3ad7 hòu # Character ã«
+U+3ad8 mì # Character ã«
+U+3ad9 fú # Character ã«
+U+3ada ? # Character ã«
+U+3adb guà ng # Character ã«
+U+3adc dà n # Character ã«
+U+3add ? # Character ã«
+U+3ade ? # Character ã«
+U+3adf yán # Character ã«
+U+3ae0 ? # Character ã«
+U+3ae1 ? # Character ã«¡
+U+3ae2 qù # Character 㫢
+U+3ae3 ? # Character ã«£
+#U+3ae4 chÇng # Character 㫤
+#U+3ae5 mÇng # Character ã«¥
+U+3ae6 ? # Character 㫦
+U+3ae7 bà o # Character 㫧
+U+3ae8 ? # Character 㫨
+U+3ae9 ? # Character ã«©
+U+3aea ? # Character 㫪
+#U+3aeb xiÇn # Character ã««
+U+3aec ? # Character 㫬
+U+3aed ? # Character ã«
+U+3aee ? # Character ã«®
+U+3aef mà o # Character 㫯
+#U+3af0 lÇng # Character ã«°
+#U+3af1 nÇn # Character 㫱
+U+3af2 pèi # Character 㫲
+U+3af3 chén # Character 㫳
+U+3af4 ? # Character ã«´
+U+3af5 ? # Character 㫵
+#U+3af6 cÇu # Character 㫶
+U+3af7 ? # Character ã«·
+U+3af8 qiè # Character 㫸
+U+3af9 dà i # Character 㫹
+U+3afa ? # Character 㫺
+U+3afb kùn # Character 㫻
+U+3afc dié # Character 㫼
+U+3afd lù # Character 㫽
+U+3afe ? # Character 㫾
+U+3aff ? # Character ã«¿
diff --git a/resources/chars/latin1/row3b.trans b/resources/chars/latin1/row3b.trans
new file mode 100644
index 0000000..bbc8086
--- /dev/null
+++ b/resources/chars/latin1/row3b.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+3b00 ? # Character ã¬
+U+3b01 ? # Character ã¬
+U+3b02 yú # Character ã¬
+U+3b03 tái # Character ã¬
+U+3b04 chà n # Character ã¬
+U+3b05 mà n # Character ã¬
+U+3b06 mián # Character ã¬
+U+3b07 huà n # Character ã¬
+U+3b08 ? # Character ã¬
+#U+3b09 nuÇn # Character ã¬
+#U+3b0a huÇn # Character ã¬
+U+3b0b hóu # Character ã¬
+U+3b0c jìng # Character ã¬
+U+3b0d bó # Character ã¬
+#U+3b0e xiÇn # Character ã¬
+U+3b0f lì # Character ã¬
+#U+3b10 jÇn # Character ã¬
+U+3b11 ? # Character ã¬
+#U+3b12 mÇng # Character ã¬
+U+3b13 pià o # Character ã¬
+U+3b14 háo # Character ã¬
+U+3b15 yáng # Character ã¬
+U+3b16 ? # Character ã¬
+U+3b17 xià n # Character ã¬
+U+3b18 sù # Character ã¬
+#U+3b19 wÄi # Character ã¬
+U+3b1a chè # Character ã¬
+U+3b1b ? # Character ã¬
+U+3b1c jìn # Character ã¬
+U+3b1d céng # Character ã¬
+U+3b1e hè # Character ã¬
+U+3b1f ? # Character ã¬
+U+3b20 shà i # Character ã¬
+U+3b21 lÃng # Character 㬡
+U+3b22 ? # Character 㬢
+U+3b23 duì # Character 㬣
+U+3b24 ? # Character 㬤
+U+3b25 pù # Character 㬥
+U+3b26 yuè # Character 㬦
+U+3b27 bó # Character 㬧
+U+3b28 ? # Character 㬨
+U+3b29 huì # Character 㬩
+U+3b2a dié # Character 㬪
+U+3b2b yà n # Character 㬫
+U+3b2c jù # Character 㬬
+U+3b2d jià o # Character ã¬
+U+3b2e kuà i # Character 㬮
+U+3b2f liè # Character 㬯
+U+3b30 yú # Character 㬰
+U+3b31 tì # Character 㬱
+U+3b32 ? # Character 㬲
+#U+3b33 wÇ # Character 㬳
+#U+3b34 hÇng # Character 㬴
+U+3b35 xiáo # Character 㬵
+U+3b36 hà o # Character 㬶
+U+3b37 ? # Character 㬷
+U+3b38 ? # Character 㬸
+U+3b39 ? # Character 㬹
+U+3b3a ? # Character 㬺
+#U+3b3b huÇng # Character 㬻
+U+3b3c fù # Character 㬼
+U+3b3d ? # Character 㬽
+U+3b3e ? # Character 㬾
+U+3b3f dùn # Character 㬿
+U+3b40 ? # Character ã
+U+3b41 réng # Character ã
+#U+3b42 jiÇo # Character ã
+U+3b43 ? # Character ã
+U+3b44 xìn # Character ã
+U+3b45 ? # Character ã
+U+3b46 ? # Character ã
+U+3b47 yuà n # Character ã
+U+3b48 jué # Character ã
+U+3b49 huá # Character ã
+U+3b4a ? # Character ã
+U+3b4b bà ng # Character ã
+U+3b4c móu # Character ã
+U+3b4d ? # Character ã
+U+3b4e ? # Character ã
+#U+3b4f wÄi # Character ã
+U+3b50 ? # Character ã
+U+3b51 mèi # Character ã
+U+3b52 sì # Character ã
+U+3b53 bià n # Character ã
+U+3b54 lú # Character ã
+U+3b55 ? # Character ã
+U+3b56 ? # Character ã
+U+3b57 ? # Character ã
+U+3b58 hé # Character ã
+U+3b59 shé # Character ã
+#U+3b5a lÇ # Character ã
+U+3b5b pà i # Character ã
+U+3b5c róng # Character ã
+U+3b5d qiú # Character ã
+U+3b5e liè # Character ã
+#U+3b5f gÇng # Character ã
+#U+3b60 xiÇn # Character ã
+U+3b61 xì # Character ã¡
+U+3b62 ? # Character ã¢
+U+3b63 ? # Character ã£
+#U+3b64 niÇo # Character ã¤
+U+3b65 ? # Character ã¥
+U+3b66 ? # Character ã¦
+U+3b67 ? # Character ã§
+U+3b68 xié # Character ã¨
+U+3b69 lèi # Character ã©
+U+3b6a ? # Character ãª
+U+3b6b cuán # Character ã«
+U+3b6c zhuó # Character ã¬
+U+3b6d fèi # Character ã
+U+3b6e zuò # Character ã®
+U+3b6f dié # Character ã¯
+U+3b70 jì # Character ã°
+U+3b71 hé # Character ã±
+U+3b72 jà # Character ã²
+U+3b73 ? # Character ã³
+U+3b74 ? # Character ã´
+U+3b75 ? # Character ãµ
+U+3b76 ? # Character ã¶
+U+3b77 ? # Character ã·
+U+3b78 tú # Character ã¸
+U+3b79 xián # Character ã¹
+#U+3b7a yÇn # Character ãº
+U+3b7b táng # Character ã»
+U+3b7c tà # Character ã¼
+#U+3b7d dÇ # Character ã½
+U+3b7e jué # Character ã¾
+U+3b7f áng # Character ã¿
+U+3b80 hán # Character ã®
+U+3b81 yáo # Character ã®
+U+3b82 jú # Character ã®
+U+3b83 ruà # Character ã®
+#U+3b84 bÇng # Character ã®
+U+3b85 ? # Character ã®
+U+3b86 niè # Character ã®
+U+3b87 tià n # Character ã®
+U+3b88 nà i # Character ã®
+U+3b89 ? # Character ã®
+U+3b8a ? # Character ã®
+#U+3b8b yÇu # Character ã®
+U+3b8c mián # Character ã®
+U+3b8d ? # Character ã®
+U+3b8e ? # Character ã®
+U+3b8f nà i # Character ã®
+#U+3b90 xÇng # Character ã®
+U+3b91 qì # Character ã®
+U+3b92 ? # Character ã®
+U+3b93 gèn # Character ã®
+U+3b94 tóng # Character ã®
+U+3b95 ér # Character ã®
+U+3b96 jiá # Character ã®
+U+3b97 qÃn # Character ã®
+U+3b98 mà o # Character ã®
+U+3b99 è # Character ã®
+U+3b9a lì # Character ã®
+U+3b9b chà # Character ã®
+U+3b9c ? # Character ã®
+U+3b9d hé # Character ã®
+U+3b9e jié # Character ã®
+U+3b9f jà # Character ã®
+U+3ba0 ? # Character ã®
+U+3ba1 guà n # Character 㮡
+U+3ba2 hóu # Character 㮢
+U+3ba3 gà i # Character 㮣
+U+3ba4 ? # Character 㮤
+U+3ba5 fèn # Character 㮥
+U+3ba6 sè # Character 㮦
+U+3ba7 ? # Character 㮧
+U+3ba8 jà # Character 㮨
+U+3ba9 ? # Character 㮩
+U+3baa qióng # Character 㮪
+U+3bab hé # Character 㮫
+U+3bac ? # Character 㮬
+U+3bad xián # Character ã®
+U+3bae jié # Character 㮮
+U+3baf huá # Character 㮯
+U+3bb0 bà # Character 㮰
+U+3bb1 ? # Character ã®±
+U+3bb2 ? # Character 㮲
+U+3bb3 zhèn # Character 㮳
+U+3bb4 ? # Character ã®´
+U+3bb5 ? # Character 㮵
+U+3bb6 shì # Character 㮶
+U+3bb7 ? # Character ã®·
+U+3bb8 sòng # Character 㮸
+#U+3bb9 zhÇ # Character 㮹
+#U+3bba bÄn # Character 㮺
+U+3bbb ? # Character ã®»
+U+3bbc ? # Character 㮼
+U+3bbd ? # Character 㮽
+#U+3bbe lÇng # Character 㮾
+U+3bbf bì # Character 㮿
+#U+3bc0 xiÇn # Character ã¯
+U+3bc1 bà ng # Character ã¯
+U+3bc2 dà i # Character ã¯
+U+3bc3 ? # Character ã¯
+U+3bc4 ? # Character ã¯
+U+3bc5 pà # Character ã¯
+#U+3bc6 chÇn # Character ã¯
+U+3bc7 bì # Character ã¯
+U+3bc8 sù # Character ã¯
+U+3bc9 huò # Character ã¯
+U+3bca hén # Character ã¯
+#U+3bcb yÇng # Character ã¯
+U+3bcc chuán # Character ã¯
+#U+3bcd jiÇng # Character ã¯
+U+3bce nèn # Character ã¯
+#U+3bcf gÇ # Character ã¯
+#U+3bd0 fÇng # Character ã¯
+U+3bd1 ? # Character ã¯
+U+3bd2 ? # Character ã¯
+U+3bd3 tà # Character ã¯
+U+3bd4 cuì # Character ã¯
+U+3bd5 ? # Character ã¯
+U+3bd6 dé # Character ã¯
+#U+3bd7 rÇn # Character ã¯
+#U+3bd8 kuÇn # Character ã¯
+U+3bd9 chè # Character ã¯
+U+3bda dá # Character ã¯
+U+3bdb hú # Character ã¯
+U+3bdc cuì # Character ã¯
+U+3bdd lù # Character ã¯
+U+3bde juà n # Character ã¯
+U+3bdf lù # Character ã¯
+U+3be0 qià n # Character ã¯
+U+3be1 pà o # Character 㯡
+U+3be2 zhèn # Character 㯢
+U+3be3 ? # Character 㯣
+U+3be4 lì # Character 㯤
+U+3be5 cáo # Character 㯥
+U+3be6 qà # Character 㯦
+U+3be7 ? # Character 㯧
+U+3be8 ? # Character 㯨
+U+3be9 tì # Character 㯩
+U+3bea lÃng # Character 㯪
+U+3beb qú # Character 㯫
+#U+3bec liÇn # Character 㯬
+#U+3bed lÇ # Character ã¯
+#U+3bee shÇ # Character 㯮
+U+3bef gòng # Character 㯯
+U+3bf0 zhé # Character 㯰
+#U+3bf1 biÇo # Character 㯱
+U+3bf2 jìn # Character 㯲
+U+3bf3 qÃng # Character 㯳
+U+3bf4 ? # Character 㯴
+U+3bf5 ? # Character 㯵
+U+3bf6 ? # Character 㯶
+U+3bf7 pú # Character 㯷
+#U+3bf8 jÇn # Character 㯸
+#U+3bf9 biÇo # Character 㯹
+U+3bfa jià n # Character 㯺
+#U+3bfb gÇn # Character 㯻
+U+3bfc ? # Character 㯼
+U+3bfd ? # Character 㯽
+U+3bfe ? # Character 㯾
+U+3bff liè # Character 㯿
diff --git a/resources/chars/latin1/row3c.trans b/resources/chars/latin1/row3c.trans
new file mode 100644
index 0000000..f65ca1d
--- /dev/null
+++ b/resources/chars/latin1/row3c.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+3c00 là # Character ã°
+#U+3c01 luÇ # Character ã°
+#U+3c02 shÄn # Character ã°
+U+3c03 mián # Character ã°
+U+3c04 jià n # Character ã°
+U+3c05 dà # Character ã°
+U+3c06 bèi # Character ã°
+U+3c07 ? # Character ã°
+#U+3c08 liÇn # Character ã°
+U+3c09 ? # Character ã°
+U+3c0a xún # Character ã°
+U+3c0b pÃn # Character ã°
+U+3c0c què # Character ã°
+U+3c0d lóng # Character ã°
+U+3c0e zuì # Character ã°
+U+3c0f ? # Character ã°
+U+3c10 jué # Character ã°
+U+3c11 ? # Character ã°
+U+3c12 shé # Character ã°
+U+3c13 ? # Character ã°
+U+3c14 xiè # Character ã°
+U+3c15 ? # Character ã°
+#U+3c16 lÇn # Character ã°
+U+3c17 cù # Character ã°
+U+3c18 yà # Character ã°
+U+3c19 nuó # Character ã°
+U+3c1a là # Character ã°
+U+3c1b yuè # Character ã°
+U+3c1c ? # Character ã°
+#U+3c1d yÇ # Character ã°
+U+3c1e ? # Character ã°
+U+3c1f jì # Character ã°
+U+3c20 kà ng # Character ã°
+U+3c21 xiè # Character 㰡
+U+3c22 ? # Character ã°¢
+U+3c23 zì # Character 㰣
+#U+3c24 kÄ # Character ã°¤
+U+3c25 huì # Character 㰥
+U+3c26 qù # Character 㰦
+U+3c27 ? # Character ã°§
+U+3c28 ? # Character ã°¨
+U+3c29 ? # Character ã°©
+U+3c2a wá # Character 㰪
+U+3c2b ? # Character ã°«
+U+3c2c xún # Character 㰬
+U+3c2d ? # Character ã°
+U+3c2e shèn # Character 㰮
+U+3c2f kòu # Character 㰯
+U+3c30 qiè # Character 㰰
+U+3c31 shà # Character 㰱
+U+3c32 xù # Character 㰲
+U+3c33 yà # Character 㰳
+U+3c34 pó # Character 㰴
+U+3c35 zú # Character 㰵
+#U+3c36 yÇu # Character ã°¶
+U+3c37 zì # Character 㰷
+#U+3c38 liÇn # Character ã°¸
+U+3c39 jìn # Character 㰹
+U+3c3a xiá # Character 㰺
+#U+3c3b yÇ # Character ã°»
+U+3c3c qiè # Character 㰼
+#U+3c3d mÇ # Character ã°½
+U+3c3e jià o # Character 㰾
+U+3c3f ? # Character ã°¿
+#U+3c40 chÇ # Character ã±
+U+3c41 shì # Character ã±
+U+3c42 ? # Character ã±
+#U+3c43 yÇn # Character ã±
+U+3c44 mò # Character ã±
+U+3c45 yì # Character ã±
+U+3c46 ? # Character ã±
+U+3c47 sè # Character ã±
+U+3c48 jìn # Character ã±
+U+3c49 yè # Character ã±
+U+3c4a ? # Character ã±
+U+3c4b què # Character ã±
+U+3c4c chè # Character ã±
+U+3c4d luán # Character ã±
+U+3c4e ? # Character ã±
+U+3c4f zhèng # Character ã±
+U+3c50 ? # Character ã±
+U+3c51 ? # Character ã±
+U+3c52 ? # Character ã±
+U+3c53 ? # Character ã±
+U+3c54 ? # Character ã±
+U+3c55 ? # Character ã±
+U+3c56 cuì # Character ã±
+U+3c57 ? # Character ã±
+U+3c58 Ã n # Character ã±
+#U+3c59 xiÇ # Character ã±
+U+3c5a cán # Character ã±
+#U+3c5b chuÇn # Character ã±
+U+3c5c zhá # Character ã±
+U+3c5d ? # Character ã±
+U+3c5e jà # Character ã±
+U+3c5f bó # Character ã±
+U+3c60 ? # Character ã±
+U+3c61 ? # Character 㱡
+U+3c62 láng # Character 㱢
+#U+3c63 tuÇ # Character ã±£
+U+3c64 ? # Character 㱤
+U+3c65 lÃng # Character ã±¥
+U+3c66 è # Character 㱦
+U+3c67 wò # Character 㱧
+U+3c68 lià n # Character 㱨
+U+3c69 dú # Character 㱩
+U+3c6a mèn # Character 㱪
+U+3c6b là n # Character 㱫
+#U+3c6c wÄi # Character 㱬
+U+3c6d duà n # Character ã±
+U+3c6e kuà i # Character 㱮
+U+3c6f ái # Character 㱯
+#U+3c70 zÇi # Character ã±°
+U+3c71 huì # Character 㱱
+U+3c72 yì # Character 㱲
+U+3c73 mò # Character 㱳
+U+3c74 zì # Character 㱴
+U+3c75 bèn # Character 㱵
+U+3c76 bèng # Character 㱶
+U+3c77 ? # Character ã±·
+U+3c78 bì # Character 㱸
+U+3c79 lì # Character 㱹
+U+3c7a lú # Character 㱺
+#U+3c7b luÇ # Character ã±»
+U+3c7c ? # Character ã±¼
+U+3c7d dà n # Character 㱽
+U+3c7e ? # Character ã±¾
+U+3c7f què # Character 㱿
+U+3c80 chén # Character ã²
+U+3c81 ? # Character ã²
+U+3c82 chéng # Character ã²
+U+3c83 jiù # Character ã²
+U+3c84 kòu # Character ã²
+U+3c85 jì # Character ã²
+U+3c86 lÃng # Character ã²
+U+3c87 ? # Character ã²
+U+3c88 sháo # Character ã²
+U+3c89 kà i # Character ã²
+U+3c8a ruì # Character ã²
+U+3c8b chuò # Character ã²
+U+3c8c nèng # Character ã²
+U+3c8d ? # Character ã²
+U+3c8e lóu # Character ã²
+#U+3c8f bÇo # Character ã²
+U+3c90 ? # Character ã²
+U+3c91 ? # Character ã²
+U+3c92 bà o # Character ã²
+U+3c93 róng # Character ã²
+U+3c94 ? # Character ã²
+U+3c95 lèi # Character ã²
+U+3c96 ? # Character ã²
+U+3c97 ? # Character ã²
+U+3c98 qú # Character ã²
+U+3c99 ? # Character ã²
+U+3c9a ? # Character ã²
+#U+3c9b zhÇ # Character ã²
+U+3c9c tán # Character ã²
+#U+3c9d rÇng # Character ã²
+U+3c9e zú # Character ã²
+#U+3c9f yÇng # Character ã²
+U+3ca0 máo # Character ã²
+U+3ca1 nà i # Character 㲡
+U+3ca2 bià n # Character 㲢
+U+3ca3 ? # Character ã²£
+U+3ca4 ? # Character 㲤
+U+3ca5 táng # Character 㲥
+U+3ca6 hà n # Character 㲦
+U+3ca7 zà o # Character 㲧
+U+3ca8 róng # Character 㲨
+U+3ca9 ? # Character 㲩
+U+3caa ? # Character 㲪
+U+3cab pú # Character 㲫
+U+3cac ? # Character 㲬
+#U+3cad tÇn # Character ã²
+U+3cae ? # Character ã²®
+U+3caf rán # Character 㲯
+U+3cb0 nÃng # Character ã²°
+U+3cb1 liè # Character 㲱
+U+3cb2 dié # Character 㲲
+U+3cb3 dié # Character 㲳
+U+3cb4 zhòng # Character 㲴
+U+3cb5 ? # Character ã²µ
+#U+3cb6 lÇ # Character 㲶
+U+3cb7 dà n # Character 㲷
+U+3cb8 ? # Character 㲸
+#U+3cb9 guÇ # Character ã²¹
+U+3cba jà # Character 㲺
+U+3cbb nì # Character 㲻
+U+3cbc yì # Character 㲼
+U+3cbd nià n # Character 㲽
+#U+3cbe yÇ # Character ã²¾
+#U+3cbf wÇng # Character 㲿
+U+3cc0 guò # Character ã³
+U+3cc1 zè # Character ã³
+U+3cc2 yán # Character ã³
+U+3cc3 cuì # Character ã³
+U+3cc4 xián # Character ã³
+#U+3cc5 jiÇo # Character ã³
+#U+3cc6 shÇ # Character ã³
+U+3cc7 fù # Character ã³
+U+3cc8 pèi # Character ã³
+U+3cc9 ? # Character ã³
+U+3cca ? # Character ã³
+U+3ccb ? # Character ã³
+U+3ccc ? # Character ã³
+U+3ccd bù # Character ã³
+U+3cce bià n # Character ã³
+#U+3ccf chÇ # Character ã³
+U+3cd0 sà # Character ã³
+U+3cd1 yì # Character ã³
+U+3cd2 bià n # Character ã³
+U+3cd3 ? # Character ã³
+U+3cd4 duì # Character ã³
+U+3cd5 lán # Character ã³
+U+3cd6 ? # Character ã³
+U+3cd7 chà i # Character ã³
+U+3cd8 ? # Character ã³
+U+3cd9 xuà n # Character ã³
+U+3cda yù # Character ã³
+U+3cdb yú # Character ã³
+U+3cdc ? # Character ã³
+U+3cdd ? # Character ã³
+U+3cde ? # Character ã³
+U+3cdf ? # Character ã³
+U+3ce0 tà # Character ã³
+U+3ce1 ? # Character 㳡
+U+3ce2 ? # Character ã³¢
+U+3ce3 ? # Character ã³£
+U+3ce4 ? # Character 㳤
+U+3ce5 jù # Character 㳥
+U+3ce6 xiè # Character 㳦
+U+3ce7 xà # Character 㳧
+#U+3ce8 jiÇn # Character 㳨
+U+3ce9 ? # Character 㳩
+U+3cea pà n # Character 㳪
+U+3ceb tà # Character 㳫
+U+3cec xuán # Character 㳬
+U+3ced xián # Character ã³
+U+3cee nià o # Character 㳮
+U+3cef ? # Character 㳯
+U+3cf0 ? # Character ã³°
+U+3cf1 ? # Character ã³±
+U+3cf2 ? # Character ã³²
+U+3cf3 ? # Character ã³³
+U+3cf4 mì # Character 㳴
+U+3cf5 jì # Character 㳵
+U+3cf6 gòu # Character 㳶
+#U+3cf7 wÄn # Character ã³·
+U+3cf8 ? # Character 㳸
+#U+3cf9 wÇng # Character ã³¹
+U+3cfa yóu # Character 㳺
+U+3cfb zé # Character 㳻
+U+3cfc bì # Character 㳼
+#U+3cfd mÇ # Character ã³½
+U+3cfe ? # Character ã³¾
+U+3cff xiè # Character 㳿
diff --git a/resources/chars/latin1/row3d.trans b/resources/chars/latin1/row3d.trans
new file mode 100644
index 0000000..6b43889
--- /dev/null
+++ b/resources/chars/latin1/row3d.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+3d00 fà n # Character ã´
+U+3d01 yì # Character ã´
+U+3d02 ? # Character ã´
+U+3d03 lèi # Character ã´
+U+3d04 yÃng # Character ã´
+U+3d05 ? # Character ã´
+U+3d06 jìn # Character ã´
+U+3d07 shè # Character ã´
+U+3d08 yìn # Character ã´
+#U+3d09 jÇ # Character ã´
+U+3d0a ? # Character ã´
+U+3d0b sù # Character ã´
+U+3d0c ? # Character ã´
+U+3d0d ? # Character ã´
+U+3d0e ? # Character ã´
+#U+3d0f wÇng # Character ã´
+U+3d10 mià n # Character ã´
+U+3d11 sù # Character ã´
+U+3d12 yì # Character ã´
+#U+3d13 zÇi # Character ã´
+U+3d14 sè # Character ã´
+U+3d15 jà # Character ã´
+U+3d16 luò # Character ã´
+U+3d17 ? # Character ã´
+U+3d18 mà o # Character ã´
+U+3d19 zhá # Character ã´
+U+3d1a suì # Character ã´
+U+3d1b zhì # Character ã´
+U+3d1c bià n # Character ã´
+U+3d1d là # Character ã´
+U+3d1e ? # Character ã´
+U+3d1f ? # Character ã´
+U+3d20 ? # Character ã´
+U+3d21 ? # Character ã´¡
+U+3d22 ? # Character ã´¢
+U+3d23 ? # Character ã´£
+U+3d24 ? # Character ã´¤
+U+3d25 qià o # Character 㴥
+U+3d26 guà n # Character 㴦
+U+3d27 ? # Character ã´§
+U+3d28 zhèn # Character 㴨
+U+3d29 ? # Character ã´©
+U+3d2a niè # Character 㴪
+U+3d2b jùn # Character 㴫
+U+3d2c xiè # Character 㴬
+#U+3d2d yÇo # Character ã´
+U+3d2e xiè # Character 㴮
+U+3d2f ? # Character ã´¯
+U+3d30 néng # Character 㴰
+U+3d31 ? # Character ã´±
+U+3d32 ? # Character ã´²
+#U+3d33 lÇng # Character ã´³
+U+3d34 chén # Character 㴴
+U+3d35 mì # Character 㴵
+U+3d36 què # Character 㴶
+U+3d37 ? # Character ã´·
+U+3d38 nà # Character 㴸
+U+3d39 ? # Character ã´¹
+U+3d3a ? # Character ã´º
+U+3d3b ? # Character ã´»
+U+3d3c sù # Character 㴼
+U+3d3d xiè # Character 㴽
+U+3d3e bó # Character 㴾
+#U+3d3f dÇng # Character ã´¿
+U+3d40 cuà n # Character ãµ
+U+3d41 ? # Character ãµ
+#U+3d42 chuÇng # Character ãµ
+U+3d43 chè # Character ãµ
+U+3d44 hà n # Character ãµ
+U+3d45 dà n # Character ãµ
+U+3d46 hà o # Character ãµ
+U+3d47 ? # Character ãµ
+U+3d48 ? # Character ãµ
+U+3d49 ? # Character ãµ
+#U+3d4a shÄn # Character ãµ
+U+3d4b mì # Character ãµ
+U+3d4c chà n # Character ãµ
+U+3d4d mèn # Character ãµ
+#U+3d4e hÇn # Character ãµ
+#U+3d4f cuÇ # Character ãµ
+U+3d50 jué # Character ãµ
+U+3d51 hè # Character ãµ
+U+3d52 fèi # Character ãµ
+U+3d53 shà # Character ãµ
+#U+3d54 chÄ # Character ãµ
+U+3d55 shèn # Character ãµ
+#U+3d56 nÇ # Character ãµ
+U+3d57 fù # Character ãµ
+U+3d58 mà n # Character ãµ
+U+3d59 ? # Character ãµ
+U+3d5a ? # Character ãµ
+U+3d5b ? # Character ãµ
+U+3d5c ? # Character ãµ
+U+3d5d yì # Character ãµ
+U+3d5e chóu # Character ãµ
+U+3d5f ? # Character ãµ
+U+3d60 ? # Character ãµ
+U+3d61 báo # Character 㵡
+U+3d62 léi # Character 㵢
+#U+3d63 kÄ # Character ãµ£
+U+3d64 dià n # Character 㵤
+U+3d65 bì # Character 㵥
+U+3d66 suà # Character 㵦
+U+3d67 gé # Character 㵧
+U+3d68 bì # Character 㵨
+U+3d69 yì # Character 㵩
+U+3d6a xián # Character 㵪
+#U+3d6b nÇ # Character 㵫
+U+3d6c yÃng # Character 㵬
+#U+3d6d zhÇ # Character ãµ
+U+3d6e chún # Character 㵮
+U+3d6f féng # Character 㵯
+U+3d70 xù # Character 㵰
+#U+3d71 piÇo # Character ãµ±
+#U+3d72 wÇ # Character ãµ²
+U+3d73 liáo # Character 㵳
+U+3d74 cáng # Character 㵴
+U+3d75 zòu # Character 㵵
+U+3d76 ? # Character 㵶
+U+3d77 bià n # Character 㵷
+U+3d78 yà o # Character 㵸
+U+3d79 huán # Character 㵹
+U+3d7a pái # Character 㵺
+U+3d7b sòu # Character 㵻
+U+3d7c ? # Character ãµ¼
+U+3d7d duì # Character 㵽
+U+3d7e jìng # Character 㵾
+U+3d7f xà # Character 㵿
+U+3d80 ? # Character ã¶
+U+3d81 guó # Character ã¶
+U+3d82 ? # Character ã¶
+U+3d83 ? # Character ã¶
+U+3d84 yán # Character ã¶
+U+3d85 xué # Character ã¶
+U+3d86 chú # Character ã¶
+U+3d87 héng # Character ã¶
+#U+3d88 liÇng # Character ã¶
+U+3d89 ? # Character ã¶
+U+3d8a ? # Character ã¶
+U+3d8b ? # Character ã¶
+U+3d8c lián # Character ã¶
+#U+3d8d xiÇn # Character ã¶
+U+3d8e huán # Character ã¶
+U+3d8f ? # Character ã¶
+U+3d90 ? # Character ã¶
+U+3d91 lià n # Character ã¶
+#U+3d92 shÇn # Character ã¶
+U+3d93 cáng # Character ã¶
+U+3d94 bèi # Character ã¶
+#U+3d95 jiÇn # Character ã¶
+U+3d96 shù # Character ã¶
+U+3d97 fà n # Character ã¶
+U+3d98 dià n # Character ã¶
+U+3d99 ? # Character ã¶
+U+3d9a bà # Character ã¶
+U+3d9b yú # Character ã¶
+U+3d9c ? # Character ã¶
+U+3d9d ? # Character ã¶
+#U+3d9e nÇng # Character ã¶
+#U+3d9f lÄi # Character ã¶
+U+3da0 yì # Character ã¶
+U+3da1 dà i # Character 㶡
+U+3da2 ? # Character 㶢
+U+3da3 chán # Character 㶣
+#U+3da4 chÇo # Character 㶤
+U+3da5 ? # Character 㶥
+U+3da6 jìn # Character 㶦
+U+3da7 nèn # Character 㶧
+U+3da8 ? # Character 㶨
+U+3da9 ? # Character 㶩
+U+3daa ? # Character 㶪
+#U+3dab liÇo # Character 㶫
+U+3dac méi # Character 㶬
+U+3dad jiù # Character ã¶
+U+3dae ? # Character 㶮
+U+3daf liù # Character 㶯
+U+3db0 hán # Character 㶰
+U+3db1 ? # Character 㶱
+U+3db2 yòng # Character 㶲
+U+3db3 jìn # Character 㶳
+#U+3db4 chÇ # Character 㶴
+U+3db5 rèn # Character 㶵
+U+3db6 nóng # Character 㶶
+U+3db7 ? # Character 㶷
+U+3db8 ? # Character 㶸
+U+3db9 hòng # Character 㶹
+U+3dba tià n # Character 㶺
+U+3dbb ? # Character 㶻
+U+3dbc ? # Character 㶼
+U+3dbd ? # Character 㶽
+U+3dbe ? # Character 㶾
+U+3dbf bó # Character 㶿
+U+3dc0 qióng # Character ã·
+U+3dc1 ? # Character ã·
+U+3dc2 shù # Character ã·
+#U+3dc3 cuÇ # Character ã·
+U+3dc4 huì # Character ã·
+#U+3dc5 chÇo # Character ã·
+U+3dc6 dòu # Character ã·
+U+3dc7 guà i # Character ã·
+U+3dc8 è # Character ã·
+U+3dc9 wèi # Character ã·
+U+3dca fén # Character ã·
+U+3dcb tán # Character ã·
+U+3dcc ? # Character ã·
+U+3dcd lún # Character ã·
+U+3dce hè # Character ã·
+#U+3dcf yÇng # Character ã·
+#U+3dd0 huÇ # Character ã·
+U+3dd1 ? # Character ã·
+U+3dd2 yú # Character ã·
+#U+3dd3 zÇng # Character ã·
+U+3dd4 yà n # Character ã·
+U+3dd5 qiú # Character ã·
+U+3dd6 zhà o # Character ã·
+#U+3dd7 jiÇng # Character ã·
+U+3dd8 tái # Character ã·
+U+3dd9 ? # Character ã·
+U+3dda ? # Character ã·
+U+3ddb ? # Character ã·
+U+3ddc ? # Character ã·
+U+3ddd ? # Character ã·
+U+3dde ? # Character ã·
+U+3ddf tuì # Character ã·
+U+3de0 lÃn # Character ã·
+#U+3de1 jiÇng # Character ã·¡
+#U+3de2 zhÇ # Character ã·¢
+U+3de3 ? # Character ã·£
+U+3de4 hè # Character 㷤
+U+3de5 ? # Character ã·¥
+U+3de6 xù # Character 㷦
+U+3de7 ? # Character ã·§
+U+3de8 ? # Character ã·¨
+U+3de9 ? # Character ã·©
+U+3dea cuì # Character 㷪
+#U+3deb qÇng # Character ã·«
+U+3dec mò # Character 㷬
+U+3ded ? # Character ã·
+U+3dee ? # Character ã·®
+U+3def bèng # Character 㷯
+U+3df0 là # Character 㷰
+U+3df1 ? # Character ã·±
+U+3df2 ? # Character ã·²
+U+3df3 yà n # Character 㷳
+U+3df4 gé # Character 㷴
+U+3df5 mò # Character 㷵
+U+3df6 bèi # Character 㷶
+#U+3df7 juÇn # Character ã··
+U+3df8 dié # Character 㷸
+U+3df9 shà o # Character 㷹
+U+3dfa ? # Character ã·º
+U+3dfb wú # Character 㷻
+U+3dfc yà n # Character 㷼
+U+3dfd ? # Character ã·½
+U+3dfe jué # Character 㷾
+U+3dff ? # Character ã·¿
diff --git a/resources/chars/latin1/row3e.trans b/resources/chars/latin1/row3e.trans
new file mode 100644
index 0000000..b04692d
--- /dev/null
+++ b/resources/chars/latin1/row3e.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+3e00 tái # Character ã¸
+#U+3e01 hÇn # Character ã¸
+U+3e02 ? # Character ã¸
+#U+3e03 diÇn # Character ã¸
+U+3e04 jì # Character ã¸
+U+3e05 jié # Character ã¸
+U+3e06 ? # Character ã¸
+U+3e07 ? # Character ã¸
+U+3e08 ? # Character ã¸
+U+3e09 xiè # Character ã¸
+U+3e0a là # Character ã¸
+U+3e0b fán # Character ã¸
+U+3e0c huò # Character ã¸
+U+3e0d xì # Character ã¸
+U+3e0e niè # Character ã¸
+U+3e0f mà # Character ã¸
+U+3e10 rán # Character ã¸
+U+3e11 cuà n # Character ã¸
+U+3e12 yÃn # Character ã¸
+U+3e13 mì # Character ã¸
+U+3e14 ? # Character ã¸
+U+3e15 jué # Character ã¸
+U+3e16 ? # Character ã¸
+U+3e17 tóng # Character ã¸
+U+3e18 wà n # Character ã¸
+U+3e19 ? # Character ã¸
+#U+3e1a lÇ # Character ã¸
+U+3e1b sháo # Character ã¸
+U+3e1c kòng # Character ã¸
+#U+3e1d kÇn # Character ã¸
+#U+3e1e bÇn # Character ã¸
+U+3e1f ? # Character ã¸
+#U+3e20 tiÇo # Character ã¸
+U+3e21 ? # Character 㸡
+U+3e22 bèi # Character 㸢
+U+3e23 yè # Character 㸣
+U+3e24 pià n # Character 㸤
+U+3e25 chán # Character 㸥
+U+3e26 hù # Character 㸦
+U+3e27 kèn # Character 㸧
+U+3e28 ? # Character 㸨
+U+3e29 à n # Character 㸩
+U+3e2a chún # Character 㸪
+U+3e2b qián # Character 㸫
+U+3e2c bèi # Character 㸬
+U+3e2d ? # Character ã¸
+U+3e2e fén # Character 㸮
+U+3e2f ? # Character 㸯
+U+3e30 tuó # Character 㸰
+U+3e31 tuó # Character 㸱
+U+3e32 zuó # Character 㸲
+U+3e33 lÃng # Character 㸳
+U+3e34 ? # Character 㸴
+#U+3e35 guÇ # Character 㸵
+U+3e36 ? # Character 㸶
+U+3e37 shì # Character 㸷
+#U+3e38 hÇu # Character 㸸
+U+3e39 liè # Character 㸹
+U+3e3a ? # Character 㸺
+U+3e3b sì # Character 㸻
+U+3e3c ? # Character 㸼
+U+3e3d bèi # Character 㸽
+U+3e3e rèn # Character 㸾
+U+3e3f dú # Character 㸿
+U+3e40 bó # Character ã¹
+U+3e41 liáng # Character ã¹
+U+3e42 cì # Character ã¹
+U+3e43 bì # Character ã¹
+U+3e44 jì # Character ã¹
+#U+3e45 zÇng # Character ã¹
+U+3e46 ? # Character ã¹
+U+3e47 hé # Character ã¹
+U+3e48 là # Character ã¹
+U+3e49 yuán # Character ã¹
+U+3e4a yuè # Character ã¹
+U+3e4b ? # Character ã¹
+#U+3e4c chÇn # Character ã¹
+U+3e4d dà # Character ã¹
+U+3e4e léi # Character ã¹
+#U+3e4f jÇn # Character ã¹
+U+3e50 chóng # Character ã¹
+U+3e51 sì # Character ã¹
+#U+3e52 pÇ # Character ã¹
+U+3e53 yì # Character ã¹
+U+3e54 ? # Character ã¹
+U+3e55 ? # Character ã¹
+U+3e56 huà n # Character ã¹
+U+3e57 táo # Character ã¹
+U+3e58 rú # Character ã¹
+U+3e59 yÃng # Character ã¹
+U+3e5a yÃng # Character ã¹
+U+3e5b ráo # Character ã¹
+U+3e5c yÃn # Character ã¹
+U+3e5d shì # Character ã¹
+U+3e5e yÃn # Character ã¹
+U+3e5f jué # Character ã¹
+U+3e60 tún # Character ã¹
+U+3e61 xuán # Character 㹡
+U+3e62 ? # Character ã¹¢
+U+3e63 ? # Character ã¹£
+U+3e64 qiè # Character 㹤
+U+3e65 zhù # Character 㹥
+U+3e66 ? # Character 㹦
+U+3e67 ? # Character 㹧
+U+3e68 yòu # Character 㹨
+U+3e69 ? # Character 㹩
+U+3e6a ? # Character 㹪
+U+3e6b xì # Character 㹫
+#U+3e6c shÇ # Character 㹬
+U+3e6d yì # Character ã¹
+U+3e6e mò # Character 㹮
+U+3e6f ? # Character 㹯
+U+3e70 ? # Character ã¹°
+U+3e71 hú # Character 㹱
+U+3e72 xià o # Character 㹲
+U+3e73 wú # Character 㹳
+U+3e74 ? # Character ã¹´
+U+3e75 jìng # Character 㹵
+U+3e76 tÃng # Character 㹶
+#U+3e77 shÇ # Character ã¹·
+U+3e78 nà # Character 㹸
+U+3e79 ? # Character ã¹¹
+U+3e7a tà # Character 㹺
+U+3e7b ? # Character ã¹»
+#U+3e7c chÇ # Character ã¹¼
+#U+3e7d chÇn # Character ã¹½
+#U+3e7e piÇo # Character ã¹¾
+#U+3e7f diÇo # Character 㹿
+U+3e80 náo # Character ãº
+#U+3e81 nÇo # Character ãº
+#U+3e82 gÇn # Character ãº
+#U+3e83 gÇu # Character ãº
+#U+3e84 yÇ # Character ãº
+U+3e85 hóu # Character ãº
+U+3e86 ? # Character ãº
+U+3e87 ? # Character ãº
+U+3e88 ? # Character ãº
+U+3e89 hù # Character ãº
+U+3e8a yà ng # Character ãº
+U+3e8b ? # Character ãº
+U+3e8c xià n # Character ãº
+U+3e8d ? # Character ãº
+U+3e8e róng # Character ãº
+U+3e8f lóu # Character ãº
+#U+3e90 zhÇo # Character ãº
+U+3e91 cán # Character ãº
+U+3e92 lià o # Character ãº
+U+3e93 pià o # Character ãº
+U+3e94 hà i # Character ãº
+U+3e95 fán # Character ãº
+#U+3e96 hÇn # Character ãº
+U+3e97 dà n # Character ãº
+U+3e98 zhà n # Character ãº
+U+3e99 ? # Character ãº
+#U+3e9a tÇ # Character ãº
+U+3e9b zhù # Character ãº
+#U+3e9c bÇn # Character ãº
+U+3e9d jià n # Character ãº
+U+3e9e yú # Character ãº
+U+3e9f zhuó # Character ãº
+U+3ea0 yòu # Character ãº
+U+3ea1 lì # Character 㺡
+U+3ea2 ? # Character 㺢
+U+3ea3 ? # Character 㺣
+U+3ea4 ? # Character 㺤
+U+3ea5 chán # Character 㺥
+U+3ea6 lián # Character 㺦
+U+3ea7 ? # Character 㺧
+U+3ea8 ? # Character 㺨
+U+3ea9 jiù # Character 㺩
+U+3eaa pú # Character 㺪
+U+3eab qiú # Character 㺫
+#U+3eac gÇng # Character 㺬
+#U+3ead zÇ # Character ãº
+U+3eae yú # Character 㺮
+U+3eaf ? # Character 㺯
+U+3eb0 ? # Character 㺰
+U+3eb1 réng # Character 㺱
+#U+3eb2 niÇ # Character 㺲
+U+3eb3 méi # Character 㺳
+U+3eb4 ? # Character 㺴
+U+3eb5 jiú # Character 㺵
+U+3eb6 ? # Character 㺶
+U+3eb7 xù # Character 㺷
+U+3eb8 pÃng # Character 㺸
+U+3eb9 bià n # Character 㺹
+U+3eba mà o # Character 㺺
+U+3ebb ? # Character 㺻
+U+3ebc ? # Character 㺼
+U+3ebd ? # Character 㺽
+U+3ebe ? # Character 㺾
+U+3ebf yà # Character 㺿
+U+3ec0 yóu # Character ã»
+U+3ec1 ? # Character ã»
+U+3ec2 pÃng # Character ã»
+U+3ec3 ? # Character ã»
+#U+3ec4 bÇo # Character ã»
+U+3ec5 huì # Character ã»
+U+3ec6 ? # Character ã»
+U+3ec7 ? # Character ã»
+U+3ec8 ? # Character ã»
+U+3ec9 bù # Character ã»
+U+3eca máng # Character ã»
+U+3ecb là # Character ã»
+U+3ecc tú # Character ã»
+U+3ecd wú # Character ã»
+U+3ece lì # Character ã»
+U+3ecf lÃng # Character ã»
+U+3ed0 ? # Character ã»
+U+3ed1 jì # Character ã»
+U+3ed2 jùn # Character ã»
+U+3ed3 ? # Character ã»
+#U+3ed4 duÇ # Character ã»
+U+3ed5 jué # Character ã»
+U+3ed6 dà i # Character ã»
+U+3ed7 bèi # Character ã»
+U+3ed8 ? # Character ã»
+U+3ed9 ? # Character ã»
+U+3eda ? # Character ã»
+U+3edb ? # Character ã»
+U+3edc ? # Character ã»
+U+3edd là # Character ã»
+U+3ede bià n # Character ã»
+U+3edf suà # Character ã»
+U+3ee0 tú # Character ã»
+U+3ee1 dié # Character 㻡
+U+3ee2 ? # Character 㻢
+U+3ee3 ? # Character 㻣
+U+3ee4 ? # Character 㻤
+U+3ee5 ? # Character 㻥
+U+3ee6 ? # Character 㻦
+U+3ee7 duò # Character 㻧
+U+3ee8 ? # Character 㻨
+U+3ee9 ? # Character 㻩
+U+3eea suì # Character 㻪
+U+3eeb bì # Character 㻫
+U+3eec tú # Character 㻬
+U+3eed sè # Character ã»
+U+3eee cà n # Character 㻮
+U+3eef tú # Character 㻯
+#U+3ef0 miÇn # Character ã»°
+U+3ef1 ? # Character ã»±
+#U+3ef2 lÇ # Character 㻲
+U+3ef3 ? # Character 㻳
+U+3ef4 ? # Character ã»´
+U+3ef5 zhà n # Character 㻵
+#U+3ef6 bÇ # Character 㻶
+U+3ef7 jà # Character 㻷
+U+3ef8 cén # Character 㻸
+U+3ef9 ? # Character 㻹
+U+3efa lì # Character 㻺
+U+3efb ? # Character ã»»
+U+3efc ? # Character 㻼
+U+3efd suì # Character 㻽
+U+3efe ? # Character 㻾
+#U+3eff shÇ # Character 㻿
diff --git a/resources/chars/latin1/row3f.trans b/resources/chars/latin1/row3f.trans
new file mode 100644
index 0000000..f2e0571
--- /dev/null
+++ b/resources/chars/latin1/row3f.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+3f00 ? # Character ã¼
+U+3f01 ? # Character ã¼
+U+3f02 é # Character ã¼
+U+3f03 ? # Character ã¼
+U+3f04 ? # Character ã¼
+U+3f05 ? # Character ã¼
+U+3f06 ? # Character ã¼
+U+3f07 qióng # Character ã¼
+U+3f08 luó # Character ã¼
+U+3f09 yìn # Character ã¼
+U+3f0a tún # Character ã¼
+#U+3f0b gÇ # Character ã¼
+#U+3f0c yÇ # Character ã¼
+#U+3f0d lÄi # Character ã¼
+U+3f0e bèi # Character ã¼
+#U+3f0f nÄi # Character ã¼
+U+3f10 pián # Character ã¼
+U+3f11 lià n # Character ã¼
+#U+3f12 qiÇ # Character ã¼
+U+3f13 lián # Character ã¼
+U+3f14 ? # Character ã¼
+U+3f15 ? # Character ã¼
+U+3f16 lì # Character ã¼
+#U+3f17 dÇng # Character ã¼
+#U+3f18 wÇ # Character ã¼
+U+3f19 zhòu # Character ã¼
+U+3f1a ? # Character ã¼
+U+3f1b xÃng # Character ã¼
+U+3f1c à ng # Character ã¼
+U+3f1d fà n # Character ã¼
+U+3f1e pèng # Character ã¼
+U+3f1f bái # Character ã¼
+U+3f20 tuó # Character ã¼
+U+3f21 ? # Character 㼡
+#U+3f22 Ä # Character ã¼¢
+#U+3f23 bÇi # Character ã¼£
+U+3f24 qì # Character 㼤
+U+3f25 chú # Character 㼥
+#U+3f26 gÇng # Character 㼦
+U+3f27 tóng # Character 㼧
+U+3f28 hán # Character 㼨
+U+3f29 chéng # Character 㼩
+U+3f2a jiá # Character 㼪
+U+3f2b huà n # Character 㼫
+U+3f2c xìng # Character 㼬
+U+3f2d dià n # Character ã¼
+U+3f2e mái # Character 㼮
+U+3f2f dòng # Character 㼯
+U+3f30 é # Character 㼰
+#U+3f31 ruÇn # Character ã¼±
+U+3f32 liè # Character 㼲
+#U+3f33 shÄng # Character ã¼³
+#U+3f34 Çu # Character ã¼´
+U+3f35 dì # Character 㼵
+U+3f36 yú # Character 㼶
+U+3f37 chuán # Character 㼷
+U+3f38 róng # Character 㼸
+U+3f39 ? # Character ã¼¹
+U+3f3a táng # Character 㼺
+U+3f3b cóng # Character 㼻
+U+3f3c piáo # Character 㼼
+#U+3f3d shuÇng # Character ã¼½
+U+3f3e lù # Character 㼾
+U+3f3f tóng # Character 㼿
+U+3f40 zhèng # Character ã½
+U+3f41 lì # Character ã½
+U+3f42 sà # Character ã½
+U+3f43 ? # Character ã½
+U+3f44 ? # Character ã½
+U+3f45 ? # Character ã½
+U+3f46 ? # Character ã½
+U+3f47 guà i # Character ã½
+U+3f48 yì # Character ã½
+#U+3f49 hÇn # Character ã½
+U+3f4a xiè # Character ã½
+U+3f4b luó # Character ã½
+U+3f4c liù # Character ã½
+U+3f4d ? # Character ã½
+#U+3f4e dÇn # Character ã½
+U+3f4f ? # Character ã½
+U+3f50 ? # Character ã½
+U+3f51 tán # Character ã½
+U+3f52 ? # Character ã½
+U+3f53 ? # Character ã½
+U+3f54 ? # Character ã½
+U+3f55 yóu # Character ã½
+U+3f56 nán # Character ã½
+U+3f57 ? # Character ã½
+#U+3f58 gÇng # Character ã½
+U+3f59 jùn # Character ã½
+U+3f5a chì # Character ã½
+U+3f5b kòu # Character ã½
+#U+3f5c wÇn # Character ã½
+U+3f5d lì # Character ã½
+U+3f5e liú # Character ã½
+U+3f5f liè # Character ã½
+U+3f60 xiá # Character ã½
+U+3f61 ? # Character 㽡
+#U+3f62 Çn # Character ã½¢
+U+3f63 yù # Character 㽣
+U+3f64 jú # Character 㽤
+U+3f65 róu # Character 㽥
+U+3f66 xún # Character 㽦
+U+3f67 ? # Character 㽧
+U+3f68 cuó # Character 㽨
+U+3f69 cà n # Character 㽩
+#U+3f6a zÄng # Character 㽪
+#U+3f6b yÇng # Character 㽫
+U+3f6c fù # Character 㽬
+#U+3f6d ruÇn # Character ã½
+U+3f6e ? # Character ã½®
+U+3f6f xà # Character 㽯
+U+3f70 shù # Character 㽰
+#U+3f71 jiÇo # Character ã½±
+#U+3f72 jiÇo # Character ã½²
+U+3f73 hà n # Character 㽳
+U+3f74 zhà ng # Character 㽴
+U+3f75 ? # Character ã½µ
+U+3f76 ? # Character 㽶
+U+3f77 shuì # Character 㽷
+U+3f78 chén # Character 㽸
+U+3f79 fà n # Character 㽹
+U+3f7a jà # Character 㽺
+U+3f7b ? # Character ã½»
+U+3f7c ? # Character ã½¼
+U+3f7d gù # Character 㽽
+U+3f7e wù # Character 㽾
+U+3f7f ? # Character 㽿
+U+3f80 qiè # Character ã¾
+U+3f81 shù # Character ã¾
+U+3f82 ? # Character ã¾
+U+3f83 tuó # Character ã¾
+U+3f84 dú # Character ã¾
+U+3f85 sì # Character ã¾
+U+3f86 rán # Character ã¾
+U+3f87 mù # Character ã¾
+U+3f88 fù # Character ã¾
+U+3f89 lÃng # Character ã¾
+U+3f8a jà # Character ã¾
+U+3f8b xiù # Character ã¾
+#U+3f8c xuÇn # Character ã¾
+U+3f8d nái # Character ã¾
+U+3f8e ? # Character ã¾
+U+3f8f jiè # Character ã¾
+U+3f90 lì # Character ã¾
+U+3f91 dá # Character ã¾
+U+3f92 jì # Character ã¾
+U+3f93 ? # Character ã¾
+#U+3f94 lÇ # Character ã¾
+#U+3f95 shÄn # Character ã¾
+#U+3f96 lÇ # Character ã¾
+#U+3f97 lÇng # Character ã¾
+#U+3f98 gÄng # Character ã¾
+#U+3f99 yÇn # Character ã¾
+U+3f9a ? # Character ã¾
+#U+3f9b qÇn # Character ã¾
+U+3f9c qiè # Character ã¾
+U+3f9d chè # Character ã¾
+#U+3f9e yÇu # Character ã¾
+U+3f9f bù # Character ã¾
+U+3fa0 huáng # Character ã¾
+U+3fa1 què # Character 㾡
+U+3fa2 là i # Character 㾢
+U+3fa3 ? # Character ã¾£
+U+3fa4 ? # Character 㾤
+U+3fa5 xù # Character 㾥
+U+3fa6 bà ng # Character 㾦
+U+3fa7 kè # Character 㾧
+#U+3fa8 qÇ # Character 㾨
+U+3fa9 ? # Character 㾩
+#U+3faa shÄng # Character 㾪
+U+3fab ? # Character 㾫
+U+3fac ? # Character 㾬
+U+3fad zhòu # Character ã¾
+U+3fae huáng # Character 㾮
+U+3faf tuà # Character 㾯
+U+3fb0 hú # Character 㾰
+U+3fb1 bèi # Character 㾱
+U+3fb2 ? # Character ã¾²
+U+3fb3 ? # Character ã¾³
+U+3fb4 ? # Character ã¾´
+U+3fb5 jì # Character 㾵
+#U+3fb6 gÇ # Character 㾶
+U+3fb7 ? # Character ã¾·
+#U+3fb8 gÇo # Character 㾸
+U+3fb9 chái # Character 㾹
+U+3fba mà # Character 㾺
+U+3fbb zhù # Character 㾻
+#U+3fbc tuÇ # Character ã¾¼
+U+3fbd tuà # Character 㾽
+U+3fbe lián # Character 㾾
+U+3fbf láng # Character 㾿
+U+3fc0 ? # Character ã¿
+U+3fc1 ? # Character ã¿
+U+3fc2 ? # Character ã¿
+U+3fc3 dà i # Character ã¿
+U+3fc4 Ã i # Character ã¿
+#U+3fc5 xiÇn # Character ã¿
+U+3fc6 ? # Character ã¿
+U+3fc7 xà # Character ã¿
+U+3fc8 ? # Character ã¿
+U+3fc9 tuà # Character ã¿
+#U+3fca cÇn # Character ã¿
+U+3fcb sà o # Character ã¿
+U+3fcc ? # Character ã¿
+U+3fcd jiè # Character ã¿
+U+3fce fèn # Character ã¿
+U+3fcf qún # Character ã¿
+U+3fd0 ? # Character ã¿
+U+3fd1 yà o # Character ã¿
+#U+3fd2 dÇo # Character ã¿
+U+3fd3 jiá # Character ã¿
+#U+3fd4 lÄi # Character ã¿
+U+3fd5 yán # Character ã¿
+U+3fd6 lú # Character ã¿
+U+3fd7 tuà # Character ã¿
+U+3fd8 yÃng # Character ã¿
+U+3fd9 pì # Character ã¿
+U+3fda luò # Character ã¿
+U+3fdb là # Character ã¿
+#U+3fdc biÄ # Character ã¿
+U+3fdd ? # Character ã¿
+U+3fde mà o # Character ã¿
+U+3fdf bái # Character ã¿
+U+3fe0 ? # Character ã¿
+U+3fe1 ? # Character ã¿¡
+U+3fe2 yà o # Character 㿢
+U+3fe3 hé # Character 㿣
+#U+3fe4 chÇn # Character 㿤
+U+3fe5 hú # Character 㿥
+U+3fe6 nìng # Character 㿦
+U+3fe7 chóu # Character 㿧
+U+3fe8 lì # Character 㿨
+#U+3fe9 tÇng # Character ã¿©
+U+3fea huán # Character 㿪
+U+3feb bì # Character 㿫
+U+3fec ? # Character 㿬
+U+3fed chè # Character ã¿
+U+3fee yà ng # Character 㿮
+U+3fef dá # Character 㿯
+U+3ff0 áo # Character 㿰
+U+3ff1 xué # Character 㿱
+U+3ff2 ? # Character 㿲
+U+3ff3 ? # Character 㿳
+U+3ff4 ? # Character ã¿´
+#U+3ff5 rÇn # Character 㿵
+U+3ff6 ? # Character 㿶
+U+3ff7 zà o # Character 㿷
+#U+3ff8 wÇn # Character 㿸
+U+3ff9 tà # Character 㿹
+U+3ffa báo # Character 㿺
+U+3ffb ? # Character ã¿»
+U+3ffc yán # Character 㿼
+U+3ffd ? # Character 㿽
+U+3ffe zhù # Character 㿾
+#U+3fff yÇ # Character ã¿¿
diff --git a/resources/chars/latin1/row40.trans b/resources/chars/latin1/row40.trans
new file mode 100644
index 0000000..1310a8c
--- /dev/null
+++ b/resources/chars/latin1/row40.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+4000 fán # Character ä
+U+4001 yòu # Character ä
+U+4002 ? # Character ä
+U+4003 tuà # Character ä
+U+4004 méng # Character ä
+U+4005 shè # Character ä
+U+4006 jìn # Character ä
+#U+4007 gÇ # Character ä
+U+4008 qì # Character ä
+U+4009 qiáo # Character ä
+#U+400a jiÇo # Character ä
+U+400b yán # Character ä
+U+400c ? # Character ä
+U+400d kà n # Character ä
+#U+400e miÇn # Character ä
+U+400f xià n # Character ä
+#U+4010 sÇn # Character ä
+U+4011 nà # Character ä
+U+4012 ? # Character ä
+U+4013 huà n # Character ä
+U+4014 niú # Character ä
+U+4015 chèng # Character ä
+U+4016 ? # Character ä
+U+4017 jué # Character ä
+U+4018 xà # Character ä
+U+4019 qì # Character ä
+U+401a áng # Character ä
+U+401b mèi # Character ä
+#U+401c gÇ # Character ä
+U+401d ? # Character ä
+U+401e ? # Character ä
+U+401f fán # Character ä
+U+4020 qú # Character ä
+U+4021 chà n # Character ä¡
+U+4022 shùn # Character ä¢
+U+4023 bì # Character ä£
+U+4024 mà o # Character ä¤
+U+4025 shuò # Character ä¥
+#U+4026 gÇ # Character ä¦
+#U+4027 hÇng # Character ä§
+U+4028 huà n # Character ä¨
+U+4029 luò # Character ä©
+U+402a háng # Character äª
+U+402b jiá # Character ä«
+U+402c quán # Character ä¬
+U+402d ? # Character ä
+U+402e máng # Character ä®
+#U+402f bÇ # Character ä¯
+#U+4030 gÇ # Character ä°
+U+4031 ? # Character ä±
+U+4032 mù # Character ä²
+U+4033 Ã i # Character ä³
+#U+4034 yÇng # Character ä´
+U+4035 shùn # Character äµ
+#U+4036 lÇng # Character ä¶
+U+4037 jié # Character ä·
+U+4038 dì # Character ä¸
+U+4039 jiá # Character ä¹
+U+403a ? # Character äº
+U+403b pìn # Character ä»
+U+403c rèn # Character ä¼
+U+403d yán # Character ä½
+#U+403e dÇ # Character ä¾
+U+403f dì # Character ä¿
+U+4040 ? # Character ä
+#U+4041 lÇng # Character ä
+U+4042 xià n # Character ä
+U+4043 ? # Character ä
+U+4044 xìng # Character ä
+U+4045 bèi # Character ä
+#U+4046 Çn # Character ä
+U+4047 mì # Character ä
+U+4048 qì # Character ä
+U+4049 qì # Character ä
+U+404a wò # Character ä
+U+404b shé # Character ä
+U+404c yù # Character ä
+U+404d jià # Character ä
+U+404e chéng # Character ä
+#U+404f yÇo # Character ä
+U+4050 yìng # Character ä
+U+4051 yáng # Character ä
+U+4052 jà # Character ä
+U+4053 jiè # Character ä
+U+4054 hà n # Character ä
+U+4055 mÃn # Character ä
+#U+4056 lÅu # Character ä
+#U+4057 kÇi # Character ä
+#U+4058 yÇo # Character ä
+#U+4059 yÇn # Character ä
+#U+405a sÇn # Character ä
+#U+405b guÇ # Character ä
+#U+405c huÇng # Character ä
+U+405d yÃng # Character ä
+#U+405e shÄng # Character ä
+U+405f chá # Character ä
+U+4060 lián # Character ä
+U+4061 ? # Character ä¡
+U+4062 xuán # Character ä¢
+U+4063 chuán # Character ä£
+U+4064 chè # Character ä¤
+U+4065 nì # Character ä¥
+U+4066 qù # Character ä¦
+U+4067 miáo # Character ä§
+U+4068 huò # Character ä¨
+U+4069 yú # Character ä©
+#U+406a nÇn # Character äª
+U+406b hú # Character ä«
+U+406c céng # Character ä¬
+U+406d ? # Character ä
+U+406e qián # Character ä®
+U+406f shè # Character ä¯
+#U+4070 jiÇng # Character ä°
+U+4071 Ã o # Character ä±
+U+4072 mái # Character ä²
+#U+4073 mÇng # Character ä³
+#U+4074 zhÇn # Character ä´
+#U+4075 biÇn # Character äµ
+#U+4076 jiÇo # Character ä¶
+U+4077 jué # Character ä·
+U+4078 nóng # Character ä¸
+U+4079 bì # Character ä¹
+U+407a shì # Character äº
+U+407b lì # Character ä»
+U+407c mò # Character ä¼
+U+407d liè # Character ä½
+U+407e miè # Character ä¾
+U+407f mò # Character ä¿
+#U+4080 xÄ« # Character ä
+U+4081 chán # Character ä
+U+4082 qú # Character ä
+U+4083 jià o # Character ä
+U+4084 huò # Character ä
+U+4085 ? # Character ä
+U+4086 xù # Character ä
+U+4087 náng # Character ä
+U+4088 tóng # Character ä
+U+4089 hóu # Character ä
+U+408a yù # Character ä
+U+408b ? # Character ä
+U+408c ? # Character ä
+U+408d bó # Character ä
+#U+408e zuÇn # Character ä
+U+408f ? # Character ä
+U+4090 chuò # Character ä
+U+4091 ? # Character ä
+U+4092 jié # Character ä
+U+4093 ? # Character ä
+U+4094 xìng # Character ä
+U+4095 huì # Character ä
+U+4096 shà # Character ä
+U+4097 ? # Character ä
+U+4098 ? # Character ä
+U+4099 ? # Character ä
+U+409a yáo # Character ä
+U+409b yú # Character ä
+U+409c bà ng # Character ä
+U+409d jié # Character ä
+U+409e zhè # Character ä
+U+409f ? # Character ä
+U+40a0 shé # Character ä
+#U+40a1 dÇ # Character ä¡
+#U+40a2 dÇng # Character ä¢
+U+40a3 cà # Character ä£
+U+40a4 fù # Character ä¤
+U+40a5 mÃn # Character ä¥
+#U+40a6 zhÄn # Character ä¦
+#U+40a7 zhÄn # Character ä§
+U+40a8 ? # Character ä¨
+U+40a9 yà n # Character ä©
+U+40aa dià o # Character äª
+U+40ab hóng # Character ä«
+#U+40ac gÇng # Character ä¬
+U+40ad ? # Character ä
+U+40ae lüè # Character ä®
+U+40af guà i # Character ä¯
+U+40b0 là # Character ä°
+U+40b1 cuì # Character ä±
+#U+40b2 fÇ # Character ä²
+#U+40b3 cuÇ # Character ä³
+U+40b4 yán # Character ä´
+U+40b5 ? # Character äµ
+U+40b6 jié # Character ä¶
+U+40b7 ? # Character ä·
+U+40b8 guó # Character ä¸
+#U+40b9 suÇ # Character ä¹
+#U+40ba wÇn # Character äº
+U+40bb zhèng # Character ä»
+U+40bc niè # Character ä¼
+U+40bd dià o # Character ä½
+#U+40be lÇi # Character ä¾
+U+40bf tà # Character ä¿
+U+40c0 cuì # Character ä
+U+40c1 ? # Character ä
+#U+40c2 gÇn # Character ä
+U+40c3 ? # Character ä
+U+40c4 ? # Character ä
+U+40c5 ? # Character ä
+U+40c6 ? # Character ä
+U+40c7 mián # Character ä
+U+40c8 ? # Character ä
+U+40c9 mÃn # Character ä
+#U+40ca jÇ # Character ä
+U+40cb yú # Character ä
+U+40cc ? # Character ä
+U+40cd zhà o # Character ä
+U+40ce zé # Character ä
+U+40cf ? # Character ä
+U+40d0 ? # Character ä
+U+40d1 pán # Character ä
+U+40d2 hé # Character ä
+U+40d3 gòu # Character ä
+U+40d4 hóng # Character ä
+U+40d5 láo # Character ä
+U+40d6 wù # Character ä
+U+40d7 chuò # Character ä
+U+40d8 ? # Character ä
+U+40d9 lù # Character ä
+U+40da cù # Character ä
+U+40db lián # Character ä
+U+40dc ? # Character ä
+U+40dd qià o # Character ä
+U+40de shú # Character ä
+U+40df ? # Character ä
+U+40e0 ? # Character ä
+U+40e1 cén # Character ä¡
+U+40e2 ? # Character ä¢
+#U+40e3 huÇ # Character ä£
+U+40e4 sù # Character ä¤
+U+40e5 chuáng # Character ä¥
+U+40e6 ? # Character ä¦
+U+40e7 lóng # Character ä§
+U+40e8 ? # Character ä¨
+U+40e9 náo # Character ä©
+U+40ea tán # Character äª
+#U+40eb dÇn # Character ä«
+#U+40ec wÄi # Character ä¬
+#U+40ed gÇn # Character ä
+U+40ee dá # Character ä®
+U+40ef lì # Character ä¯
+U+40f0 ? # Character ä°
+U+40f1 xià n # Character ä±
+U+40f2 pán # Character ä²
+U+40f3 là # Character ä³
+U+40f4 ? # Character ä´
+#U+40f5 niÇo # Character äµ
+U+40f6 huái # Character ä¶
+U+40f7 yÃng # Character ä·
+U+40f8 xià n # Character ä¸
+U+40f9 là n # Character ä¹
+U+40fa mó # Character äº
+U+40fb bà # Character ä»
+U+40fc ? # Character ä¼
+U+40fd fú # Character ä½
+#U+40fe bÇ # Character ä¾
+U+40ff ? # Character ä¿
diff --git a/resources/chars/latin1/row41.trans b/resources/chars/latin1/row41.trans
new file mode 100644
index 0000000..61f5d0a
--- /dev/null
+++ b/resources/chars/latin1/row41.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+4100 huò # Character ä
+U+4101 yì # Character ä
+U+4102 liù # Character ä
+U+4103 ? # Character ä
+U+4104 ? # Character ä
+U+4105 juà n # Character ä
+U+4106 huó # Character ä
+U+4107 chéng # Character ä
+U+4108 dòu # Character ä
+U+4109 é # Character ä
+U+410a ? # Character ä
+#U+410b yÇn # Character ä
+U+410c zhuì # Character ä
+U+410d dù # Character ä
+#U+410e qÇ # Character ä
+U+410f yú # Character ä
+U+4110 quà n # Character ä
+U+4111 huó # Character ä
+U+4112 niè # Character ä
+U+4113 héng # Character ä
+#U+4114 jÇ # Character ä
+U+4115 shè # Character ä
+U+4116 ? # Character ä
+U+4117 ? # Character ä
+U+4118 péng # Character ä
+U+4119 mÃng # Character ä
+U+411a cáo # Character ä
+U+411b lóu # Character ä
+U+411c là # Character ä
+#U+411d chÇn # Character ä
+U+411e ? # Character ä
+U+411f cuì # Character ä
+U+4120 shà n # Character ä
+U+4121 ? # Character ä¡
+U+4122 qà # Character ä¢
+U+4123 ? # Character ä£
+U+4124 là i # Character ä¤
+U+4125 lÃng # Character ä¥
+#U+4126 liÇo # Character ä¦
+U+4127 réng # Character ä§
+U+4128 yú # Character ä¨
+U+4129 náo # Character ä©
+U+412a chuò # Character äª
+#U+412b qÇ # Character ä«
+U+412c yà # Character ä¬
+U+412d nián # Character ä
+U+412e ? # Character ä®
+#U+412f jiÇn # Character ä¯
+U+4130 yá # Character ä°
+U+4131 ? # Character ä±
+U+4132 chuà # Character ä²
+U+4133 ? # Character ä³
+U+4134 ? # Character ä´
+U+4135 ? # Character äµ
+U+4136 bì # Character ä¶
+U+4137 dà n # Character ä·
+U+4138 pò # Character ä¸
+U+4139 nián # Character ä¹
+U+413a zhì # Character äº
+U+413b cháo # Character ä»
+#U+413c tiÇn # Character ä¼
+#U+413d tiÇn # Character ä½
+U+413e ròu # Character ä¾
+U+413f yì # Character ä¿
+U+4140 liè # Character ä
+U+4141 Ã n # Character ä
+U+4142 hé # Character ä
+U+4143 qióng # Character ä
+U+4144 lì # Character ä
+U+4145 ? # Character ä
+U+4146 zì # Character ä
+U+4147 sù # Character ä
+U+4148 yuà n # Character ä
+U+4149 yà # Character ä
+U+414a dù # Character ä
+#U+414b wÇn # Character ä
+U+414c ? # Character ä
+U+414d dòng # Character ä
+#U+414e yÇu # Character ä
+U+414f huì # Character ä
+#U+4150 jiÇn # Character ä
+U+4151 ruà # Character ä
+U+4152 máng # Character ä
+#U+4153 jÇ # Character ä
+U+4154 ? # Character ä
+U+4155 ? # Character ä
+#U+4156 Çn # Character ä
+U+4157 suì # Character ä
+U+4158 lái # Character ä
+U+4159 hùn # Character ä
+#U+415a qiÇng # Character ä
+U+415b ? # Character ä
+U+415c duò # Character ä
+U+415d ? # Character ä
+U+415e nà # Character ä
+#U+415f cÇn # Character ä
+U+4160 tà # Character ä
+#U+4161 xÇ # Character ä
¡
+U+4162 jiù # Character ä
¢
+U+4163 huáng # Character ä
£
+U+4164 qì # Character ä
¤
+U+4165 jié # Character ä
¥
+U+4166 máo # Character ä
¦
+U+4167 yà n # Character ä
§
+U+4168 ? # Character ä
¨
+#U+4169 zhÇ # Character ä
©
+U+416a tuà # Character ä
ª
+U+416b ? # Character ä
«
+U+416c à i # Character ä
¬
+U+416d páng # Character ä
+U+416e cà ng # Character ä
®
+U+416f táng # Character ä
¯
+#U+4170 Än # Character ä
°
+U+4171 hùn # Character ä
±
+U+4172 qà # Character ä
²
+U+4173 chú # Character ä
³
+#U+4174 suÇ # Character ä
´
+U+4175 zhuó # Character ä
µ
+U+4176 nòu # Character ä
¶
+U+4177 tú # Character ä
·
+U+4178 zú # Character ä
¸
+U+4179 lóu # Character ä
¹
+#U+417a miÇo # Character ä
º
+U+417b là # Character ä
»
+U+417c mán # Character ä
¼
+#U+417d gÇ # Character ä
½
+U+417e cén # Character ä
¾
+U+417f huá # Character ä
¿
+#U+4180 mÄi # Character ä
+U+4181 ? # Character ä
+U+4182 lián # Character ä
+#U+4183 dÇo # Character ä
+U+4184 shà n # Character ä
+U+4185 cà # Character ä
+U+4186 ? # Character ä
+U+4187 ? # Character ä
+U+4188 zhì # Character ä
+U+4189 bà # Character ä
+U+418a cuì # Character ä
+#U+418b qiÅ« # Character ä
+U+418c ? # Character ä
+U+418d lóng # Character ä
+U+418e ? # Character ä
+U+418f fèi # Character ä
+U+4190 guó # Character ä
+U+4191 chéng # Character ä
+U+4192 jiù # Character ä
+U+4193 è # Character ä
+U+4194 ? # Character ä
+U+4195 jué # Character ä
+U+4196 hóng # Character ä
+U+4197 jià o # Character ä
+U+4198 cuán # Character ä
+U+4199 yáo # Character ä
+U+419a tóng # Character ä
+U+419b chá # Character ä
+U+419c yòu # Character ä
+U+419d shù # Character ä
+#U+419e yÇo # Character ä
+U+419f gé # Character ä
+U+41a0 huà n # Character ä
+U+41a1 láng # Character ä¡
+U+41a2 jué # Character ä¢
+U+41a3 chén # Character ä£
+U+41a4 ? # Character ä¤
+U+41a5 ? # Character ä¥
+U+41a6 shèn # Character ä¦
+U+41a7 ? # Character ä§
+U+41a8 mÃng # Character ä¨
+U+41a9 mÃng # Character ä©
+U+41aa ? # Character äª
+#U+41ab chuÄng # Character ä«
+#U+41ac yÇn # Character ä¬
+U+41ad ? # Character ä
+U+41ae jìn # Character ä®
+U+41af chuò # Character ä¯
+U+41b0 ? # Character ä°
+#U+41b1 tÇn # Character ä±
+U+41b2 ? # Character ä²
+U+41b3 qióng # Character ä³
+U+41b4 ? # Character ä´
+U+41b5 chéng # Character äµ
+U+41b6 ? # Character ä¶
+U+41b7 yù # Character ä·
+U+41b8 chéng # Character ä¸
+#U+41b9 tÇng # Character ä¹
+U+41ba ? # Character äº
+U+41bb qià o # Character ä»
+U+41bc ? # Character ä¼
+U+41bd jù # Character ä½
+U+41be lán # Character ä¾
+U+41bf yì # Character ä¿
+U+41c0 róng # Character ä
+U+41c1 ? # Character ä
+U+41c2 ? # Character ä
+U+41c3 sì # Character ä
+U+41c4 ? # Character ä
+U+41c5 fá # Character ä
+U+41c6 ? # Character ä
+U+41c7 méng # Character ä
+U+41c8 guì # Character ä
+U+41c9 ? # Character ä
+U+41ca ? # Character ä
+U+41cb hà i # Character ä
+U+41cc qià o # Character ä
+U+41cd chuò # Character ä
+U+41ce què # Character ä
+U+41cf duì # Character ä
+U+41d0 lì # Character ä
+U+41d1 bà # Character ä
+U+41d2 jiè # Character ä
+U+41d3 ? # Character ä
+U+41d4 luò # Character ä
+U+41d5 ? # Character ä
+#U+41d6 yÇn # Character ä
+U+41d7 ? # Character ä
+U+41d8 hù # Character ä
+#U+41d9 yÇn # Character ä
+U+41da ? # Character ä
+#U+41db zhÇ # Character ä
+#U+41dc liÇn # Character ä
+U+41dd ? # Character ä
+#U+41de gÇn # Character ä
+U+41df jià n # Character ä
+U+41e0 zhòu # Character ä
+U+41e1 zhù # Character ä¡
+#U+41e2 kÇ # Character ä¢
+U+41e3 nà # Character ä£
+U+41e4 duì # Character ä¤
+U+41e5 zé # Character ä¥
+#U+41e6 yÇng # Character ä¦
+U+41e7 zhù # Character ä§
+U+41e8 gòng # Character ä¨
+U+41e9 yì # Character ä©
+U+41ea ? # Character äª
+U+41eb ? # Character ä«
+#U+41ec chuÇng # Character ä¬
+#U+41ed lÇo # Character ä
+U+41ee rèn # Character ä®
+U+41ef róng # Character ä¯
+U+41f0 ? # Character ä°
+U+41f1 nà # Character ä±
+U+41f2 cè # Character ä²
+U+41f3 ? # Character ä³
+U+41f4 ? # Character ä´
+U+41f5 yà # Character äµ
+U+41f6 jué # Character ä¶
+#U+41f7 bÇ # Character ä·
+U+41f8 chéng # Character ä¸
+U+41f9 jùn # Character ä¹
+U+41fa chóu # Character äº
+U+41fb huì # Character ä»
+U+41fc chì # Character ä¼
+U+41fd zhì # Character ä½
+U+41fe yán # Character ä¾
+U+41ff ? # Character ä¿
diff --git a/resources/chars/latin1/row42.trans b/resources/chars/latin1/row42.trans
new file mode 100644
index 0000000..f40b3f8
--- /dev/null
+++ b/resources/chars/latin1/row42.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+4200 ? # Character ä
+U+4201 lún # Character ä
+U+4202 bìng # Character ä
+#U+4203 zhÇo # Character ä
+U+4204 hán # Character ä
+U+4205 yù # Character ä
+U+4206 dà i # Character ä
+U+4207 zhà o # Character ä
+U+4208 féi # Character ä
+U+4209 shà # Character ä
+U+420a lÃng # Character ä
+U+420b tà # Character ä
+U+420c ? # Character ä
+U+420d máng # Character ä
+U+420e yè # Character ä
+U+420f báo # Character ä
+U+4210 kuì # Character ä
+#U+4211 guÇ # Character ä
+#U+4212 nÇn # Character ä
+U+4213 gé # Character ä
+U+4214 ? # Character ä
+U+4215 chà # Character ä
+U+4216 ? # Character ä
+#U+4217 suÇ # Character ä
+U+4218 cà # Character ä
+U+4219 zhòu # Character ä
+U+421a tái # Character ä
+U+421b kuà i # Character ä
+U+421c qìn # Character ä
+U+421d ? # Character ä
+#U+421e dÇ # Character ä
+U+421f cè # Character ä
+#U+4220 huÇn # Character ä
+U+4221 ? # Character ä¡
+#U+4222 sÇi # Character ä¢
+U+4223 zhèng # Character ä£
+U+4224 qián # Character ä¤
+U+4225 ? # Character ä¥
+U+4226 ? # Character ä¦
+#U+4227 wÄi # Character ä§
+U+4228 ? # Character ä¨
+U+4229 ? # Character ä©
+U+422a xì # Character äª
+U+422b nà # Character ä«
+U+422c pú # Character ä¬
+U+422d huái # Character ä
+#U+422e jÇ # Character ä®
+U+422f ? # Character ä¯
+U+4230 ? # Character ä°
+U+4231 ? # Character ä±
+U+4232 pán # Character ä²
+U+4233 tà # Character ä³
+U+4234 qià n # Character ä´
+U+4235 ? # Character äµ
+U+4236 róng # Character ä¶
+U+4237 luò # Character ä·
+U+4238 hú # Character ä¸
+#U+4239 sÇu # Character ä¹
+U+423a ? # Character äº
+U+423b pú # Character ä»
+U+423c miè # Character ä¼
+U+423d ? # Character ä½
+U+423e shuò # Character ä¾
+U+423f mà i # Character ä¿
+U+4240 shù # Character ä
+U+4241 lÃng # Character ä
+#U+4242 lÄi # Character ä
+#U+4243 jiÇng # Character ä
+U+4244 léng # Character ä
+U+4245 zhì # Character ä
+#U+4246 diÇo # Character ä
+U+4247 ? # Character ä
+#U+4248 sÇn # Character ä
+U+4249 hú # Character ä
+U+424a fà n # Character ä
+U+424b mèi # Character ä
+U+424c suì # Character ä
+#U+424d jiÇn # Character ä
+U+424e táng # Character ä
+U+424f xiè # Character ä
+U+4250 ? # Character ä
+U+4251 mó # Character ä
+U+4252 fán # Character ä
+U+4253 léi # Character ä
+U+4254 ? # Character ä
+U+4255 céng # Character ä
+U+4256 lÃng # Character ä
+U+4257 ? # Character ä
+U+4258 cóng # Character ä
+U+4259 yún # Character ä
+U+425a méng # Character ä
+U+425b yù # Character ä
+U+425c zhì # Character ä
+#U+425d qÇ # Character ä
+#U+425e dÇn # Character ä
+U+425f huò # Character ä
+U+4260 wéi # Character ä
+U+4261 tán # Character ä¡
+U+4262 sè # Character ä¢
+U+4263 xiè # Character ä£
+#U+4264 sÇu # Character ä¤
+#U+4265 sÇng # Character ä¥
+U+4266 ? # Character ä¦
+U+4267 liú # Character ä§
+U+4268 yì # Character ä¨
+U+4269 ? # Character ä©
+U+426a lèi # Character äª
+U+426b là # Character ä«
+U+426c fèi # Character ä¬
+U+426d liè # Character ä
+U+426e lìn # Character ä®
+U+426f xià n # Character ä¯
+U+4270 yáo # Character ä°
+U+4271 ? # Character ä±
+U+4272 biè # Character ä²
+#U+4273 xiÇn # Character ä³
+U+4274 ráng # Character ä´
+U+4275 zhuà n # Character äµ
+U+4276 ? # Character ä¶
+U+4277 dà n # Character ä·
+U+4278 bià n # Character ä¸
+U+4279 lÃng # Character ä¹
+U+427a hóng # Character äº
+U+427b qà # Character ä»
+U+427c lià o # Character ä¼
+#U+427d bÇn # Character ä½
+U+427e mì # Character ä¾
+U+427f hú # Character ä¿
+U+4280 hú # Character ä
+U+4281 ? # Character ä
+U+4282 cè # Character ä
+U+4283 pèi # Character ä
+U+4284 qióng # Character ä
+U+4285 mÃng # Character ä
+U+4286 jiù # Character ä
+U+4287 bù # Character ä
+U+4288 méi # Character ä
+#U+4289 sÇn # Character ä
+U+428a mèi # Character ä
+U+428b ? # Character ä
+U+428c ? # Character ä
+U+428d là # Character ä
+#U+428e quÇn # Character ä
+U+428f ? # Character ä
+U+4290 èn # Character ä
+#U+4291 xiÇng # Character ä
+U+4292 ? # Character ä
+U+4293 shì # Character ä
+U+4294 ? # Character ä
+U+4295 ? # Character ä
+#U+4296 lÇn # Character ä
+U+4297 huáng # Character ä
+U+4298 jiù # Character ä
+U+4299 yán # Character ä
+U+429a ? # Character ä
+#U+429b sÇ # Character ä
+U+429c tuán # Character ä
+U+429d xiè # Character ä
+U+429e zhé # Character ä
+U+429f mén # Character ä
+U+42a0 xì # Character ä
+U+42a1 mán # Character ä¡
+U+42a2 ? # Character ä¢
+U+42a3 huáng # Character ä£
+U+42a4 tán # Character ä¤
+U+42a5 xià o # Character ä¥
+U+42a6 yá # Character ä¦
+U+42a7 bì # Character ä§
+U+42a8 luó # Character ä¨
+U+42a9 fán # Character ä©
+U+42aa lì # Character äª
+#U+42ab cuÇ # Character ä«
+U+42ac chà # Character ä¬
+U+42ad chóu # Character ä
+U+42ae dà # Character ä®
+U+42af kuà ng # Character ä¯
+#U+42b0 chÇ # Character ä°
+U+42b1 ? # Character ä±
+#U+42b2 chÇn # Character ä²
+U+42b3 mà # Character ä³
+U+42b4 qià n # Character ä´
+U+42b5 qiú # Character äµ
+U+42b6 zhèn # Character ä¶
+U+42b7 ? # Character ä·
+U+42b8 ? # Character ä¸
+U+42b9 ? # Character ä¹
+#U+42ba gÇ # Character äº
+#U+42bb yÇn # Character ä»
+#U+42bc chÇ # Character ä¼
+U+42bd guà i # Character ä½
+U+42be mù # Character ä¾
+U+42bf bó # Character ä¿
+U+42c0 kuà # Character ä
+#U+42c1 gÄng # Character ä
+U+42c2 yáo # Character ä
+U+42c3 mà o # Character ä
+#U+42c4 wÇng # Character ä
+U+42c5 ? # Character ä
+U+42c6 ? # Character ä
+U+42c7 ? # Character ä
+U+42c8 rú # Character ä
+U+42c9 jué # Character ä
+U+42ca ? # Character ä
+U+42cb mÃn # Character ä
+#U+42cc jiÇng # Character ä
+U+42cd ? # Character ä
+U+42ce zhà n # Character ä
+U+42cf zuò # Character ä
+U+42d0 yuè # Character ä
+#U+42d1 bÇng # Character ä
+U+42d2 ? # Character ä
+U+42d3 zhòu # Character ä
+U+42d4 bì # Character ä
+U+42d5 rèn # Character ä
+U+42d6 yù # Character ä
+U+42d7 ? # Character ä
+U+42d8 chuò # Character ä
+#U+42d9 Är # Character ä
+U+42da yì # Character ä
+U+42db mà # Character ä
+U+42dc qìng # Character ä
+U+42dd ? # Character ä
+#U+42de wÇng # Character ä
+U+42df jì # Character ä
+#U+42e0 bÇ # Character ä
+U+42e1 ? # Character ä¡
+U+42e2 biè # Character ä¢
+U+42e3 fán # Character ä£
+U+42e4 yà o # Character ä¤
+U+42e5 là # Character ä¥
+U+42e6 fán # Character ä¦
+U+42e7 qú # Character ä§
+#U+42e8 fÇ # Character ä¨
+U+42e9 ér # Character ä©
+U+42ea ? # Character äª
+U+42eb ? # Character ä«
+U+42ec ? # Character ä¬
+U+42ed huò # Character ä
+U+42ee jìn # Character ä®
+#U+42ef qÇ # Character ä¯
+U+42f0 jú # Character ä°
+U+42f1 lái # Character ä±
+#U+42f2 chÄ # Character ä²
+U+42f3 bèi # Character ä³
+U+42f4 niù # Character ä´
+U+42f5 yì # Character äµ
+U+42f6 xù # Character ä¶
+U+42f7 liú # Character ä·
+U+42f8 xún # Character ä¸
+U+42f9 fú # Character ä¹
+U+42fa ? # Character äº
+U+42fb nÃn # Character ä»
+#U+42fc tÇng # Character ä¼
+#U+42fd bÄng # Character ä½
+#U+42fe zhÇ # Character ä¾
+U+42ff ? # Character ä¿
diff --git a/resources/chars/latin1/row43.trans b/resources/chars/latin1/row43.trans
new file mode 100644
index 0000000..59d076a
--- /dev/null
+++ b/resources/chars/latin1/row43.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+4300 ? # Character ä
+U+4301 ? # Character ä
+U+4302 òu # Character ä
+U+4303 shuò # Character ä
+#U+4304 gÄng # Character ä
+U+4305 táng # Character ä
+U+4306 guì # Character ä
+U+4307 huì # Character ä
+U+4308 tà # Character ä
+U+4309 ? # Character ä
+U+430a yáo # Character ä
+U+430b ? # Character ä
+U+430c qì # Character ä
+U+430d hà n # Character ä
+U+430e lüè # Character ä
+U+430f mì # Character ä
+U+4310 mì # Character ä
+U+4311 ? # Character ä
+U+4312 lù # Character ä
+U+4313 fán # Character ä
+U+4314 òu # Character ä
+U+4315 mà # Character ä
+U+4316 jié # Character ä
+#U+4317 fÇ # Character ä
+U+4318 mà # Character ä
+#U+4319 huÇng # Character ä
+U+431a sù # Character ä
+U+431b yáo # Character ä
+U+431c niè # Character ä
+U+431d jìn # Character ä
+#U+431e liÇn # Character ä
+U+431f bì # Character ä
+U+4320 qìng # Character ä
+#U+4321 tÇ # Character ä¡
+U+4322 lÃng # Character ä¢
+#U+4323 zuÇn # Character ä£
+#U+4324 zhÇ # Character ä¤
+#U+4325 yÇn # Character ä¥
+#U+4326 dÇo # Character ä¦
+U+4327 chóu # Character ä§
+U+4328 cà i # Character ä¨
+U+4329 mì # Character ä©
+U+432a yán # Character äª
+#U+432b lÇn # Character ä«
+U+432c chóng # Character ä¬
+U+432d ? # Character ä
+U+432e ? # Character ä®
+U+432f guà n # Character ä¯
+U+4330 shè # Character ä°
+U+4331 luò # Character ä±
+U+4332 ? # Character ä²
+U+4333 ? # Character ä³
+U+4334 luò # Character ä´
+U+4335 zhú # Character äµ
+U+4336 ? # Character ä¶
+U+4337 chóu # Character ä·
+U+4338 juà n # Character ä¸
+#U+4339 jiÇng # Character ä¹
+#U+433a Är # Character äº
+U+433b yì # Character ä»
+U+433c ruì # Character ä¼
+#U+433d cÇi # Character ä½
+U+433e rén # Character ä¾
+U+433f fú # Character ä¿
+U+4340 lán # Character ä
+U+4341 suì # Character ä
+U+4342 yú # Character ä
+U+4343 yáo # Character ä
+#U+4344 diÇn # Character ä
+U+4345 lÃng # Character ä
+U+4346 zhù # Character ä
+U+4347 tà # Character ä
+U+4348 pÃng # Character ä
+U+4349 qián # Character ä
+U+434a jué # Character ä
+U+434b chuà # Character ä
+U+434c bù # Character ä
+#U+434d gÇ # Character ä
+U+434e cùn # Character ä
+U+434f ? # Character ä
+#U+4350 hÇn # Character ä
+#U+4351 hÇn # Character ä
+#U+4352 mÇu # Character ä
+U+4353 hù # Character ä
+U+4354 hóng # Character ä
+#U+4355 dÇ # Character ä
+U+4356 fú # Character ä
+U+4357 xuà n # Character ä
+U+4358 mà # Character ä
+U+4359 méi # Character ä
+U+435a là ng # Character ä
+U+435b gù # Character ä
+U+435c zhà o # Character ä
+U+435d tà # Character ä
+U+435e yù # Character ä
+U+435f zòng # Character ä
+U+4360 là # Character ä
+U+4361 lià o # Character ä¡
+U+4362 wú # Character ä¢
+U+4363 léi # Character ä£
+#U+4364 jÇ # Character ä¤
+U+4365 lèi # Character ä¥
+U+4366 là # Character ä¦
+U+4367 ? # Character ä§
+U+4368 bó # Character ä¨
+#U+4369 Çng # Character ä©
+U+436a kuì # Character äª
+U+436b tuó # Character ä«
+U+436c ? # Character ä¬
+U+436d ? # Character ä
+U+436e zhà o # Character ä®
+#U+436f guÇ # Character ä¯
+U+4370 ? # Character ä°
+U+4371 xú # Character ä±
+U+4372 nái # Character ä²
+U+4373 chuò # Character ä³
+U+4374 duò # Character ä´
+U+4375 ? # Character äµ
+U+4376 dòng # Character ä¶
+U+4377 guì # Character ä·
+U+4378 bó # Character ä¸
+U+4379 ? # Character ä¹
+U+437a huán # Character äº
+#U+437b xuÇn # Character ä»
+U+437c cán # Character ä¼
+U+437d lì # Character ä½
+U+437e tuà # Character ä¾
+U+437f huáng # Character ä¿
+U+4380 xuè # Character ä
+U+4381 hú # Character ä
+#U+4382 bÇo # Character ä
+#U+4383 rÇn # Character ä
+U+4384 tiáo # Character ä
+U+4385 fù # Character ä
+U+4386 lià o # Character ä
+U+4387 ? # Character ä
+U+4388 yì # Character ä
+U+4389 shù # Character ä
+U+438a pò # Character ä
+U+438b hè # Character ä
+U+438c cù # Character ä
+U+438d ? # Character ä
+U+438e nà # Character ä
+U+438f à n # Character ä
+#U+4390 chÇo # Character ä
+U+4391 lù # Character ä
+#U+4392 zhÇn # Character ä
+U+4393 tà # Character ä
+U+4394 ? # Character ä
+U+4395 ? # Character ä
+U+4396 ? # Character ä
+U+4397 qiáo # Character ä
+U+4398 sù # Character ä
+U+4399 ? # Character ä
+U+439a guà n # Character ä
+U+439b ? # Character ä
+U+439c ? # Character ä
+U+439d chú # Character ä
+U+439e ? # Character ä
+U+439f ér # Character ä
+U+43a0 ér # Character ä
+#U+43a1 nuÇn # Character ä¡
+#U+43a2 qÇ # Character ä¢
+U+43a3 sì # Character ä£
+U+43a4 chú # Character ä¤
+U+43a5 ? # Character ä¥
+#U+43a6 yÇn # Character ä¦
+U+43a7 bà ng # Character ä§
+U+43a8 à n # Character ä¨
+U+43a9 ? # Character ä©
+U+43aa nè # Character äª
+U+43ab chuà ng # Character ä«
+U+43ac bà # Character ä¬
+U+43ad ? # Character ä
+U+43ae tì # Character ä®
+U+43af hà n # Character ä¯
+U+43b0 zuó # Character ä°
+U+43b1 bà # Character ä±
+U+43b2 zhé # Character ä²
+U+43b3 wà # Character ä³
+U+43b4 shèng # Character ä´
+U+43b5 bì # Character äµ
+U+43b6 èr # Character ä¶
+U+43b7 zhù # Character ä·
+U+43b8 wù # Character ä¸
+U+43b9 wén # Character ä¹
+#U+43ba zhÇ # Character äº
+#U+43bb zhÇu # Character ä»
+U+43bc lù # Character ä¼
+U+43bd wén # Character ä½
+#U+43be gÇn # Character ä¾
+U+43bf qiú # Character ä¿
+U+43c0 là # Character ä
+#U+43c1 zÇi # Character ä
+#U+43c2 sÇu # Character ä
+U+43c3 mián # Character ä
+U+43c4 zhì # Character ä
+U+43c5 qì # Character ä
+U+43c6 cáo # Character ä
+U+43c7 pià o # Character ä
+U+43c8 lián # Character ä
+U+43c9 ? # Character ä
+U+43ca lóng # Character ä
+U+43cb sù # Character ä
+U+43cc qì # Character ä
+U+43cd yuà n # Character ä
+U+43ce féng # Character ä
+U+43cf ? # Character ä
+U+43d0 jué # Character ä
+U+43d1 dì # Character ä
+U+43d2 pià n # Character ä
+#U+43d3 guÇn # Character ä
+#U+43d4 niÇ # Character ä
+#U+43d5 rÄn # Character ä
+U+43d6 zhèn # Character ä
+U+43d7 gà i # Character ä
+#U+43d8 pÇ # Character ä
+#U+43d9 tÇn # Character ä
+#U+43da chÇo # Character ä
+#U+43db chÇn # Character ä
+U+43dc ? # Character ä
+U+43dd chún # Character ä
+U+43de mò # Character ä
+U+43df biè # Character ä
+U+43e0 qì # Character ä
+U+43e1 shì # Character ä¡
+#U+43e2 bÇ # Character ä¢
+U+43e3 jué # Character ä£
+U+43e4 sì # Character ä¤
+U+43e5 ? # Character ä¥
+U+43e6 huá # Character ä¦
+U+43e7 ná # Character ä§
+#U+43e8 huÇ # Character ä¨
+U+43e9 ? # Character ä©
+U+43ea èr # Character äª
+U+43eb ? # Character ä«
+U+43ec móu # Character ä¬
+U+43ed ? # Character ä
+U+43ee xà # Character ä®
+U+43ef zhì # Character ä¯
+#U+43f0 rÄn # Character ä°
+U+43f1 jú # Character ä±
+U+43f2 dié # Character ä²
+U+43f3 zhè # Character ä³
+U+43f4 shà o # Character ä´
+#U+43f5 mÄng # Character äµ
+U+43f6 bì # Character ä¶
+U+43f7 hà n # Character ä·
+U+43f8 yú # Character ä¸
+U+43f9 xià n # Character ä¹
+U+43fa ? # Character äº
+U+43fb néng # Character ä»
+U+43fc cán # Character ä¼
+U+43fd bù # Character ä½
+U+43fe ? # Character ä¾
+#U+43ff qÇ # Character ä¿
diff --git a/resources/chars/latin1/row44.trans b/resources/chars/latin1/row44.trans
new file mode 100644
index 0000000..67b537e
--- /dev/null
+++ b/resources/chars/latin1/row44.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+4400 jì # Character ä
+#U+4401 niÇo # Character ä
+U+4402 lù # Character ä
+#U+4403 jiÇng # Character ä
+U+4404 hà n # Character ä
+U+4405 yà # Character ä
+#U+4406 cÇi # Character ä
+U+4407 chún # Character ä
+U+4408 zhà # Character ä
+U+4409 zì # Character ä
+U+440a dá # Character ä
+U+440b ? # Character ä
+#U+440c tiÇn # Character ä
+U+440d zhòu # Character ä
+U+440e ? # Character ä
+#U+440f chÇn # Character ä
+U+4410 ? # Character ä
+U+4411 zhé # Character ä
+U+4412 ? # Character ä
+U+4413 róu # Character ä
+U+4414 bìn # Character ä
+U+4415 jà # Character ä
+U+4416 yà # Character ä
+#U+4417 dÇ # Character ä
+U+4418 jué # Character ä
+U+4419 gé # Character ä
+U+441a jà # Character ä
+U+441b ? # Character ä
+U+441c ? # Character ä
+#U+441d suÇ # Character ä
+U+441e ruò # Character ä
+U+441f xià ng # Character ä
+#U+4420 huÇng # Character ä
+U+4421 qà # Character ä¡
+U+4422 zhù # Character ä¢
+U+4423 cuò # Character ä£
+U+4424 chà # Character ä¤
+#U+4425 wÄng # Character ä¥
+U+4426 ? # Character ä¦
+U+4427 kà o # Character ä§
+#U+4428 gÇ # Character ä¨
+#U+4429 kÇi # Character ä©
+U+442a fà n # Character äª
+U+442b ? # Character ä«
+U+442c cáo # Character ä¬
+U+442d zhì # Character ä
+#U+442e chÇn # Character ä®
+U+442f léi # Character ä¯
+U+4430 ? # Character ä°
+U+4431 ? # Character ä±
+U+4432 zhé # Character ä²
+U+4433 yú # Character ä³
+U+4434 guì # Character ä´
+U+4435 huáng # Character äµ
+#U+4436 jÇn # Character ä¶
+U+4437 ? # Character ä·
+U+4438 guó # Character ä¸
+U+4439 sà o # Character ä¹
+U+443a tà n # Character äº
+U+443b ? # Character ä»
+U+443c xì # Character ä¼
+U+443d mán # Character ä½
+U+443e duó # Character ä¾
+U+443f áo # Character ä¿
+U+4440 pì # Character ä
+U+4441 wù # Character ä
+#U+4442 Çi # Character ä
+U+4443 méng # Character ä
+U+4444 pì # Character ä
+U+4445 méng # Character ä
+#U+4446 yÇng # Character ä
+U+4447 zhì # Character ä
+U+4448 bó # Character ä
+U+4449 yÃng # Character ä
+U+444a wéi # Character ä
+U+444b náo # Character ä
+U+444c lán # Character ä
+U+444d yà n # Character ä
+#U+444e chÇn # Character ä
+U+444f quán # Character ä
+#U+4450 zhÄn # Character ä
+U+4451 pú # Character ä
+U+4452 ? # Character ä
+U+4453 tái # Character ä
+U+4454 fèi # Character ä
+#U+4455 shÇ # Character ä
+U+4456 ? # Character ä
+U+4457 dà ng # Character ä
+U+4458 chá # Character ä
+U+4459 rán # Character ä
+U+445a tián # Character ä
+#U+445b chÇ # Character ä
+U+445c tà # Character ä
+#U+445d jiÇ # Character ä
+U+445e shùn # Character ä
+U+445f huáng # Character ä
+#U+4460 liÇo # Character ä
+U+4461 ? # Character ä¡
+U+4462 ? # Character ä¢
+U+4463 ? # Character ä£
+U+4464 jìn # Character ä¤
+U+4465 è # Character ä¥
+U+4466 ? # Character ä¦
+U+4467 fú # Character ä§
+U+4468 duò # Character ä¨
+U+4469 ? # Character ä©
+U+446a è # Character äª
+U+446b ? # Character ä«
+U+446c yà o # Character ä¬
+U+446d dì # Character ä
+U+446e ? # Character ä®
+U+446f dì # Character ä¯
+U+4470 bù # Character ä°
+U+4471 mán # Character ä±
+U+4472 chè # Character ä²
+U+4473 lún # Character ä³
+U+4474 qà # Character ä´
+U+4475 mù # Character äµ
+U+4476 cán # Character ä¶
+U+4477 ? # Character ä·
+U+4478 ? # Character ä¸
+U+4479 ? # Character ä¹
+U+447a ? # Character äº
+U+447b yóu # Character ä»
+U+447c ? # Character ä¼
+U+447d dá # Character ä½
+U+447e ? # Character ä¾
+U+447f sù # Character ä¿
+U+4480 fú # Character ä
+U+4481 jì # Character ä
+#U+4482 jiÇng # Character ä
+U+4483 cà o # Character ä
+U+4484 bó # Character ä
+U+4485 téng # Character ä
+U+4486 chè # Character ä
+U+4487 fù # Character ä
+#U+4488 bÇ # Character ä
+#U+4489 wÇ # Character ä
+U+448a ? # Character ä
+#U+448b yÇng # Character ä
+U+448c mìng # Character ä
+#U+448d pÇng # Character ä
+#U+448e mÇng # Character ä
+U+448f ? # Character ä
+U+4490 méng # Character ä
+#U+4491 cÇo # Character ä
+U+4492 tiáo # Character ä
+#U+4493 kÇi # Character ä
+U+4494 bà i # Character ä
+#U+4495 xiÇo # Character ä
+U+4496 xìn # Character ä
+U+4497 qì # Character ä
+U+4498 ? # Character ä
+U+4499 ? # Character ä
+#U+449a shÇo # Character ä
+U+449b héng # Character ä
+U+449c niú # Character ä
+U+449d xiáo # Character ä
+U+449e chén # Character ä
+U+449f ? # Character ä
+#U+44a0 fÇn # Character ä
+#U+44a1 yÇn # Character ä¡
+U+44a2 áng # Character ä¢
+#U+44a3 rÇn # Character ä£
+U+44a4 rì # Character ä¤
+U+44a5 fà # Character ä¥
+U+44a6 fà n # Character ä¦
+U+44a7 qù # Character ä§
+#U+44a8 shÇ # Character ä¨
+U+44a9 hé # Character ä©
+U+44aa bià n # Character äª
+U+44ab dà i # Character ä«
+U+44ac mò # Character ä¬
+#U+44ad dÄng # Character ä
+U+44ae ? # Character ä®
+U+44af ? # Character ä¯
+U+44b0 ? # Character ä°
+U+44b1 ? # Character ä±
+U+44b2 chà # Character ä²
+#U+44b3 duÇ # Character ä³
+#U+44b4 yÇu # Character ä´
+U+44b5 hà o # Character äµ
+U+44b6 ? # Character ä¶
+U+44b7 ? # Character ä·
+U+44b8 xián # Character ä¸
+U+44b9 lèi # Character ä¹
+#U+44ba jÇn # Character äº
+#U+44bb qÇ # Character ä»
+U+44bc ? # Character ä¼
+U+44bd méi # Character ä½
+U+44be ? # Character ä¾
+U+44bf ? # Character ä¿
+U+44c0 ? # Character ä
+U+44c1 ? # Character ä
+U+44c2 yán # Character ä
+U+44c3 yì # Character ä
+U+44c4 yÃn # Character ä
+U+44c5 qà # Character ä
+U+44c6 zhé # Character ä
+U+44c7 xì # Character ä
+U+44c8 yì # Character ä
+U+44c9 yé # Character ä
+U+44ca è # Character ä
+U+44cb ? # Character ä
+U+44cc zhì # Character ä
+#U+44cd hÇn # Character ä
+U+44ce chuò # Character ä
+U+44cf ? # Character ä
+U+44d0 chún # Character ä
+#U+44d1 bÇng # Character ä
+#U+44d2 kuÇi # Character ä
+U+44d3 chóu # Character ä
+U+44d4 ? # Character ä
+#U+44d5 tuÇ # Character ä
+U+44d6 qióng # Character ä
+U+44d7 ? # Character ä
+U+44d8 jiù # Character ä
+U+44d9 ? # Character ä
+U+44da cú # Character ä
+#U+44db fÇ # Character ä
+U+44dc ? # Character ä
+U+44dd méng # Character ä
+U+44de lì # Character ä
+U+44df liè # Character ä
+U+44e0 tà # Character ä
+U+44e1 ? # Character ä¡
+U+44e2 gù # Character ä¢
+#U+44e3 liÇng # Character ä£
+U+44e4 ? # Character ä¤
+U+44e5 là # Character ä¥
+#U+44e6 diÇn # Character ä¦
+U+44e7 cì # Character ä§
+U+44e8 ? # Character ä¨
+U+44e9 ? # Character ä©
+U+44ea ? # Character äª
+U+44eb jì # Character ä«
+U+44ec ? # Character ä¬
+U+44ed chà # Character ä
+U+44ee mà o # Character ä®
+U+44ef dú # Character ä¯
+U+44f0 ? # Character ä°
+U+44f1 chái # Character ä±
+U+44f2 ruì # Character ä²
+#U+44f3 hÄn # Character ä³
+U+44f4 ruán # Character ä´
+U+44f5 ? # Character äµ
+U+44f6 là i # Character ä¶
+U+44f7 xìng # Character ä·
+U+44f8 ? # Character ä¸
+U+44f9 yì # Character ä¹
+#U+44fa mÄi # Character äº
+U+44fb ? # Character ä»
+U+44fc hè # Character ä¼
+U+44fd jì # Character ä½
+U+44fe ? # Character ä¾
+#U+44ff hÇn # Character ä¿
diff --git a/resources/chars/latin1/row45.trans b/resources/chars/latin1/row45.trans
new file mode 100644
index 0000000..92218d3
--- /dev/null
+++ b/resources/chars/latin1/row45.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+4500 ? # Character ä
+U+4501 lì # Character ä
+#U+4502 zÇ # Character ä
+#U+4503 zÇ # Character ä
+U+4504 yáo # Character ä
+U+4505 ? # Character ä
+U+4506 là # Character ä
+#U+4507 qÇ # Character ä
+#U+4508 gÇn # Character ä
+U+4509 lì # Character ä
+U+450a ? # Character ä
+U+450b ? # Character ä
+U+450c ? # Character ä
+U+450d ? # Character ä
+U+450e sù # Character ä
+U+450f chòu # Character ä
+U+4510 ? # Character ä
+U+4511 xié # Character ä
+U+4512 bèi # Character ä
+#U+4513 xÇ # Character ä
+U+4514 jìng # Character ä
+U+4515 pú # Character ä
+U+4516 lÃng # Character ä
+U+4517 xiáng # Character ä
+U+4518 zuò # Character ä
+U+4519 dià o # Character ä
+U+451a chún # Character ä
+#U+451b qÇng # Character ä
+U+451c nán # Character ä
+U+451d ? # Character ä
+#U+451e lÇ # Character ä
+U+451f chà # Character ä
+#U+4520 shÇo # Character ä
+U+4521 yú # Character ä¡
+U+4522 huá # Character ä¢
+U+4523 là # Character ä£
+U+4524 ? # Character ä¤
+U+4525 ? # Character ä¥
+U+4526 ? # Character ä¦
+U+4527 là # Character ä§
+U+4528 ? # Character ä¨
+U+4529 ? # Character ä©
+U+452a duì # Character äª
+U+452b ? # Character ä«
+U+452c yì # Character ä¬
+U+452d nìng # Character ä
+U+452e ? # Character ä®
+U+452f hú # Character ä¯
+U+4530 fú # Character ä°
+U+4531 ? # Character ä±
+U+4532 chéng # Character ä²
+#U+4533 nÇn # Character ä³
+U+4534 cè # Character ä´
+U+4535 ? # Character äµ
+U+4536 tà # Character ä¶
+U+4537 qÃn # Character ä·
+#U+4538 biÇo # Character ä¸
+U+4539 suì # Character ä¹
+U+453a wéi # Character äº
+U+453b ? # Character ä»
+U+453c sè # Character ä¼
+U+453d à i # Character ä½
+U+453e è # Character ä¾
+U+453f jiè # Character ä¿
+#U+4540 kuÇn # Character ä
+#U+4541 fÄi # Character ä
+U+4542 ? # Character ä
+U+4543 yìn # Character ä
+U+4544 ? # Character ä
+#U+4545 sÇo # Character ä
+U+4546 dòu # Character ä
+U+4547 huì # Character ä
+U+4548 xiè # Character ä
+U+4549 zé # Character ä
+U+454a tán # Character ä
+#U+454b chÇng # Character ä
+U+454c zhì # Character ä
+U+454d yì # Character ä
+U+454e fú # Character ä
+U+454f é # Character ä
+U+4550 ? # Character ä
+U+4551 jùn # Character ä
+U+4552 ? # Character ä
+U+4553 chá # Character ä
+U+4554 xián # Character ä
+U+4555 mà n # Character ä
+U+4556 ? # Character ä
+U+4557 bì # Character ä
+U+4558 lÃng # Character ä
+U+4559 jié # Character ä
+U+455a kuì # Character ä
+U+455b jiá # Character ä
+U+455c ? # Character ä
+U+455d ? # Character ä
+U+455e là ng # Character ä
+U+455f ? # Character ä
+U+4560 fèi # Character ä
+#U+4561 lÇ # Character ä¡
+#U+4562 zhÇ # Character ä¢
+U+4563 hé # Character ä£
+U+4564 ? # Character ä¤
+#U+4565 nÇ # Character ä¥
+U+4566 yÃng # Character ä¦
+U+4567 xià o # Character ä§
+U+4568 téng # Character ä¨
+#U+4569 lÇo # Character ä©
+U+456a zé # Character äª
+U+456b kuà # Character ä«
+U+456c ? # Character ä¬
+U+456d qián # Character ä
+U+456e jú # Character ä®
+U+456f piáo # Character ä¯
+U+4570 bà n # Character ä°
+#U+4571 dÇu # Character ä±
+#U+4572 lÇn # Character ä²
+U+4573 mà # Character ä³
+U+4574 zhuó # Character ä´
+U+4575 xié # Character äµ
+U+4576 hù # Character ä¶
+U+4577 mà # Character ä·
+U+4578 ? # Character ä¸
+U+4579 zá # Character ä¹
+U+457a cóng # Character äº
+U+457b gé # Character ä»
+U+457c nán # Character ä¼
+U+457d zhú # Character ä½
+U+457e yán # Character ä¾
+U+457f hà n # Character ä¿
+U+4580 ? # Character ä
+U+4581 yì # Character ä
+U+4582 luán # Character ä
+U+4583 yuè # Character ä
+U+4584 rán # Character ä
+U+4585 lÃng # Character ä
+U+4586 nià ng # Character ä
+U+4587 yù # Character ä
+U+4588 nuè # Character ä
+U+4589 ? # Character ä
+U+458a yà # Character ä
+U+458b nuè # Character ä
+U+458c qÃn # Character ä
+U+458d qián # Character ä
+U+458e xiá # Character ä
+#U+458f chÇ # Character ä
+U+4590 jìn # Character ä
+U+4591 mì # Character ä
+U+4592 ? # Character ä
+U+4593 nà # Character ä
+U+4594 hà n # Character ä
+#U+4595 zÇ # Character ä
+U+4596 xiá # Character ä
+U+4597 yán # Character ä
+U+4598 tú # Character ä
+U+4599 ? # Character ä
+U+459a ? # Character ä
+#U+459b suÇ # Character ä
+U+459c yÃn # Character ä
+U+459d chóng # Character ä
+#U+459e zhÇu # Character ä
+#U+459f mÇng # Character ä
+U+45a0 yuán # Character ä
+#U+45a1 nÇ # Character ä¡
+U+45a2 miáo # Character ä¢
+U+45a3 sà o # Character ä£
+#U+45a4 wÇn # Character ä¤
+U+45a5 là # Character ä¥
+U+45a6 ? # Character ä¦
+U+45a7 nà # Character ä§
+U+45a8 shà # Character ä¨
+U+45a9 bì # Character ä©
+U+45aa cà # Character äª
+U+45ab bà ng # Character ä«
+U+45ac ? # Character ä¬
+U+45ad juà n # Character ä
+#U+45ae xiÇng # Character ä®
+U+45af guì # Character ä¯
+U+45b0 pà i # Character ä°
+U+45b1 ? # Character ä±
+U+45b2 xún # Character ä²
+U+45b3 zhà # Character ä³
+U+45b4 yáo # Character ä´
+U+45b5 ? # Character äµ
+U+45b6 ? # Character ä¶
+U+45b7 ? # Character ä·
+U+45b8 é # Character ä¸
+U+45b9 yáng # Character ä¹
+U+45ba tiáo # Character äº
+U+45bb yóu # Character ä»
+U+45bc jué # Character ä¼
+U+45bd là # Character ä½
+U+45be ? # Character ä¾
+U+45bf là # Character ä¿
+U+45c0 ? # Character ä
+U+45c1 jì # Character ä
+#U+45c2 hÇ # Character ä
+U+45c3 zhà n # Character ä
+#U+45c4 fÇ # Character ä
+U+45c5 cháng # Character ä
+#U+45c6 guÇn # Character ä
+U+45c7 jú # Character ä
+U+45c8 méng # Character ä
+U+45c9 ? # Character ä
+U+45ca chéng # Character ä
+U+45cb móu # Character ä
+U+45cc ? # Character ä
+#U+45cd lÇ # Character ä
+U+45ce ? # Character ä
+U+45cf ? # Character ä
+U+45d0 ? # Character ä
+U+45d1 yì # Character ä
+U+45d2 bìng # Character ä
+U+45d3 ? # Character ä
+U+45d4 hóu # Character ä
+#U+45d5 wÇn # Character ä
+U+45d6 chì # Character ä
+U+45d7 ? # Character ä
+U+45d8 gé # Character ä
+U+45d9 hán # Character ä
+U+45da bó # Character ä
+U+45db ? # Character ä
+U+45dc liú # Character ä
+U+45dd cán # Character ä
+U+45de cán # Character ä
+U+45df yì # Character ä
+U+45e0 xuán # Character ä
+U+45e1 yán # Character ä¡
+#U+45e2 suÇ # Character ä¢
+#U+45e3 gÇo # Character ä£
+U+45e4 yóng # Character ä¤
+U+45e5 ? # Character ä¥
+U+45e6 ? # Character ä¦
+U+45e7 ? # Character ä§
+U+45e8 yú # Character ä¨
+U+45e9 ? # Character ä©
+U+45ea zhè # Character äª
+U+45eb má # Character ä«
+U+45ec ? # Character ä¬
+U+45ed ? # Character ä
+#U+45ee shuÇng # Character ä®
+U+45ef jìn # Character ä¯
+U+45f0 guà n # Character ä°
+U+45f1 pú # Character ä±
+U+45f2 lìn # Character ä²
+U+45f3 ? # Character ä³
+U+45f4 tÃng # Character ä´
+U+45f5 ? # Character äµ
+U+45f6 là # Character ä¶
+U+45f7 yì # Character ä·
+U+45f8 ? # Character ä¸
+U+45f9 cì # Character ä¹
+#U+45fa yÇn # Character äº
+U+45fb jié # Character ä»
+U+45fc ? # Character ä¼
+U+45fd wèi # Character ä½
+#U+45fe xiÇn # Character ä¾
+U+45ff nÃng # Character ä¿
diff --git a/resources/chars/latin1/row46.trans b/resources/chars/latin1/row46.trans
new file mode 100644
index 0000000..a2ec7c7
--- /dev/null
+++ b/resources/chars/latin1/row46.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+4600 fù # Character ä
+U+4601 gé # Character ä
+U+4602 ? # Character ä
+U+4603 mò # Character ä
+U+4604 fù # Character ä
+U+4605 nái # Character ä
+#U+4606 xiÇn # Character ä
+U+4607 wén # Character ä
+U+4608 lì # Character ä
+U+4609 cán # Character ä
+U+460a miè # Character ä
+U+460b ? # Character ä
+U+460c nì # Character ä
+U+460d chà i # Character ä
+U+460e ? # Character ä
+U+460f xù # Character ä
+#U+4610 nÇ # Character ä
+U+4611 mà i # Character ä
+U+4612 ? # Character ä
+U+4613 kà n # Character ä
+U+4614 ? # Character ä
+U+4615 háng # Character ä
+U+4616 ? # Character ä
+U+4617 ? # Character ä
+U+4618 yù # Character ä
+U+4619 wèi # Character ä
+U+461a zhú # Character ä
+U+461b ? # Character ä
+U+461c ? # Character ä
+U+461d yì # Character ä
+U+461e ? # Character ä
+U+461f ? # Character ä
+U+4620 fú # Character ä
+#U+4621 bÇ # Character ä¡
+#U+4622 zhÇ # Character ä¢
+#U+4623 zÇ # Character ä£
+U+4624 shù # Character ä¤
+U+4625 xiá # Character ä¥
+U+4626 nà # Character ä¦
+U+4627 ? # Character ä§
+#U+4628 jiÇo # Character ä¨
+U+4629 xuà n # Character ä©
+U+462a ? # Character äª
+U+462b nòu # Character ä«
+U+462c róng # Character ä¬
+U+462d dié # Character ä
+U+462e sà # Character ä®
+U+462f ? # Character ä¯
+U+4630 ? # Character ä°
+U+4631 yù # Character ä±
+U+4632 ? # Character ä²
+U+4633 ? # Character ä³
+U+4634 ? # Character ä´
+U+4635 lù # Character äµ
+U+4636 hà n # Character ä¶
+U+4637 ? # Character ä·
+U+4638 yì # Character ä¸
+U+4639 zuì # Character ä¹
+U+463a zhà n # Character äº
+U+463b sù # Character ä»
+#U+463c wÇn # Character ä¼
+U+463d nà # Character ä½
+#U+463e guÇn # Character ä¾
+U+463f jué # Character ä¿
+#U+4640 bÄng # Character ä
+U+4641 cán # Character ä
+U+4642 ? # Character ä
+U+4643 duò # Character ä
+U+4644 qì # Character ä
+U+4645 yà o # Character ä
+U+4646 guì # Character ä
+#U+4647 nuÇn # Character ä
+U+4648 hóu # Character ä
+U+4649 xún # Character ä
+U+464a xiè # Character ä
+U+464b ? # Character ä
+U+464c huì # Character ä
+U+464d ? # Character ä
+U+464e xié # Character ä
+U+464f bó # Character ä
+U+4650 kè # Character ä
+U+4651 ? # Character ä
+U+4652 xù # Character ä
+#U+4653 bÇi # Character ä
+U+4654 ? # Character ä
+U+4655 chù # Character ä
+U+4656 ? # Character ä
+U+4657 tì # Character ä
+#U+4658 chÇ # Character ä
+U+4659 chà # Character ä
+#U+465a niÇo # Character ä
+U+465b guà n # Character ä
+U+465c féng # Character ä
+U+465d xiè # Character ä
+U+465e ? # Character ä
+U+465f duò # Character ä
+U+4660 jué # Character ä
+U+4661 huì # Character ä¡
+U+4662 zèng # Character ä¢
+U+4663 sà # Character ä£
+#U+4664 duÇ # Character ä¤
+U+4665 lÃng # Character ä¥
+U+4666 méng # Character ä¦
+U+4667 ? # Character ä§
+#U+4668 guÇ # Character ä¨
+U+4669 méng # Character ä©
+U+466a lóng # Character äª
+U+466b ? # Character ä«
+U+466c yìng # Character ä¬
+U+466d ? # Character ä
+U+466e guà n # Character ä®
+U+466f cù # Character ä¯
+U+4670 là # Character ä°
+U+4671 dú # Character ä±
+U+4672 ? # Character ä²
+U+4673 è # Character ä³
+U+4674 ? # Character ä´
+U+4675 ? # Character äµ
+U+4676 ? # Character ä¶
+U+4677 dé # Character ä·
+U+4678 dé # Character ä¸
+#U+4679 jiÇng # Character ä¹
+U+467a lián # Character äº
+U+467b ? # Character ä»
+U+467c shà o # Character ä¼
+U+467d xì # Character ä½
+U+467e ? # Character ä¾
+U+467f wèi # Character ä¿
+U+4680 ? # Character ä
+U+4681 ? # Character ä
+U+4682 hè # Character ä
+U+4683 yóu # Character ä
+U+4684 lù # Character ä
+U+4685 lái # Character ä
+#U+4686 Çu # Character ä
+#U+4687 shÄng # Character ä
+U+4688 juà n # Character ä
+U+4689 qì # Character ä
+U+468a ? # Character ä
+U+468b yùn # Character ä
+U+468c ? # Character ä
+U+468d qì # Character ä
+U+468e ? # Character ä
+U+468f lèng # Character ä
+U+4690 jà # Character ä
+U+4691 mái # Character ä
+U+4692 chuáng # Character ä
+#U+4693 niÇn # Character ä
+U+4694 ? # Character ä
+U+4695 lì # Character ä
+U+4696 lÃng # Character ä
+U+4697 ? # Character ä
+U+4698 chén # Character ä
+U+4699 ? # Character ä
+#U+469a xiÇn # Character ä
+U+469b hú # Character ä
+U+469c ? # Character ä
+U+469d zú # Character ä
+#U+469e dÇi # Character ä
+#U+469f dÇi # Character ä
+U+46a0 hùn # Character ä
+U+46a1 ? # Character ä¡
+U+46a2 chè # Character ä¢
+U+46a3 tà # Character ä£
+U+46a4 ? # Character ä¤
+U+46a5 nuò # Character ä¥
+U+46a6 zhì # Character ä¦
+U+46a7 liú # Character ä§
+U+46a8 fèi # Character ä¨
+#U+46a9 jiÇo # Character ä©
+U+46aa ? # Character äª
+U+46ab áo # Character ä«
+U+46ac lÃn # Character ä¬
+U+46ad ? # Character ä
+U+46ae réng # Character ä®
+#U+46af tÇo # Character ä¯
+#U+46b0 pÇ # Character ä°
+U+46b1 xìn # Character ä±
+U+46b2 shà n # Character ä²
+U+46b3 xiè # Character ä³
+U+46b4 wà # Character ä´
+#U+46b5 tÇo # Character äµ
+U+46b6 ? # Character ä¶
+U+46b7 xì # Character ä·
+U+46b8 xiè # Character ä¸
+#U+46b9 pÇ # Character ä¹
+U+46ba yáo # Character äº
+U+46bb yáo # Character ä»
+#U+46bc nÇ # Character ä¼
+U+46bd hà o # Character ä½
+U+46be nÃn # Character ä¾
+U+46bf yìn # Character ä¿
+#U+46c0 fÇn # Character ä
+U+46c1 nán # Character ä
+U+46c2 chà # Character ä
+U+46c3 wà ng # Character ä
+#U+46c4 yuÇn # Character ä
+U+46c5 xiá # Character ä
+U+46c6 zhòu # Character ä
+#U+46c7 yuÇn # Character ä
+U+46c8 shì # Character ä
+U+46c9 mì # Character ä
+U+46ca ? # Character ä
+U+46cb gé # Character ä
+U+46cc páo # Character ä
+U+46cd fèi # Character ä
+U+46ce hù # Character ä
+U+46cf nà # Character ä
+U+46d0 cà # Character ä
+U+46d1 mì # Character ä
+U+46d2 bià n # Character ä
+U+46d3 ? # Character ä
+U+46d4 ná # Character ä
+U+46d5 yù # Character ä
+U+46d6 è # Character ä
+#U+46d7 zhÇ # Character ä
+U+46d8 nÃn # Character ä
+U+46d9 xù # Character ä
+U+46da lüè # Character ä
+U+46db huì # Character ä
+U+46dc xùn # Character ä
+U+46dd náo # Character ä
+#U+46de hÇn # Character ä
+U+46df jiá # Character ä
+U+46e0 dòu # Character ä
+U+46e1 huà # Character ä¡
+U+46e2 ? # Character ä¢
+U+46e3 ? # Character ä£
+U+46e4 cù # Character ä¤
+U+46e5 xì # Character ä¥
+U+46e6 sòng # Character ä¦
+U+46e7 mà # Character ä§
+U+46e8 xìn # Character ä¨
+U+46e9 wù # Character ä©
+U+46ea qióng # Character äª
+U+46eb zhèng # Character ä«
+U+46ec chóu # Character ä¬
+U+46ed xìng # Character ä
+U+46ee jiù # Character ä®
+U+46ef jù # Character ä¯
+U+46f0 hún # Character ä°
+U+46f1 tà # Character ä±
+U+46f2 mán # Character ä²
+#U+46f3 jiÇn # Character ä³
+#U+46f4 qÇ # Character ä´
+U+46f5 shòu # Character äµ
+#U+46f6 lÄi # Character ä¶
+#U+46f7 wÇn # Character ä·
+U+46f8 chè # Character ä¸
+U+46f9 cà n # Character ä¹
+U+46fa jiè # Character äº
+U+46fb yòu # Character ä»
+#U+46fc huÇ # Character ä¼
+#U+46fd zhÇ # Character ä½
+U+46fe sù # Character ä¾
+U+46ff gé # Character ä¿
diff --git a/resources/chars/latin1/row47.trans b/resources/chars/latin1/row47.trans
new file mode 100644
index 0000000..bc7ca48
--- /dev/null
+++ b/resources/chars/latin1/row47.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+4700 nÇo # Character ä
+U+4701 xì # Character ä
+U+4702 ? # Character ä
+U+4703 ? # Character ä
+U+4704 chà # Character ä
+U+4705 wéi # Character ä
+U+4706 mò # Character ä
+#U+4707 gÇn # Character ä
+U+4708 ? # Character ä
+U+4709 ? # Character ä
+U+470a zà o # Character ä
+U+470b huì # Character ä
+U+470c luán # Character ä
+U+470d liáo # Character ä
+U+470e láo # Character ä
+U+470f ? # Character ä
+U+4710 ? # Character ä
+U+4711 qià # Character ä
+U+4712 Ã o # Character ä
+U+4713 niè # Character ä
+U+4714 suà # Character ä
+U+4715 mà i # Character ä
+U+4716 tà n # Character ä
+U+4717 xìn # Character ä
+#U+4718 jÇng # Character ä
+U+4719 án # Character ä
+U+471a tà # Character ä
+U+471b chán # Character ä
+U+471c wèi # Character ä
+#U+471d tuÇn # Character ä
+U+471e jì # Character ä
+U+471f chén # Character ä
+U+4720 chè # Character ä
+U+4721 xù # Character ä¡
+#U+4722 xiÇn # Character ä¢
+#U+4723 xÄ«n # Character ä£
+U+4724 ? # Character ä¤
+U+4725 ? # Character ä¥
+U+4726 ? # Character ä¦
+#U+4727 nÇo # Character ä§
+U+4728 ? # Character ä¨
+U+4729 yà n # Character ä©
+U+472a qiú # Character äª
+U+472b hóng # Character ä«
+#U+472c sÇng # Character ä¬
+U+472d jùn # Character ä
+U+472e liáo # Character ä®
+U+472f jú # Character ä¯
+U+4730 ? # Character ä°
+#U+4731 mÇn # Character ä±
+U+4732 liè # Character ä²
+U+4733 ? # Character ä³
+U+4734 chù # Character ä´
+#U+4735 chÇ # Character äµ
+U+4736 xiáng # Character ä¶
+U+4737 ? # Character ä·
+#U+4738 mÄi # Character ä¸
+U+4739 shù # Character ä¹
+U+473a cè # Character äº
+#U+473b chÇ # Character ä»
+U+473c gú # Character ä¼
+U+473d yú # Character ä½
+U+473e ? # Character ä¾
+U+473f ? # Character ä¿
+U+4740 liáo # Character ä
+U+4741 láo # Character ä
+U+4742 shù # Character ä
+U+4743 zhé # Character ä
+U+4744 ? # Character ä
+U+4745 ? # Character ä
+U+4746 ? # Character ä
+U+4747 ? # Character ä
+U+4748 è # Character ä
+U+4749 ? # Character ä
+U+474a shà # Character ä
+U+474b zòng # Character ä
+U+474c jué # Character ä
+U+474d jùn # Character ä
+U+474e ? # Character ä
+U+474f lóu # Character ä
+U+4750 wéi # Character ä
+U+4751 ? # Character ä
+U+4752 zhù # Character ä
+U+4753 là # Character ä
+U+4754 ? # Character ä
+U+4755 zhé # Character ä
+#U+4756 zhÇo # Character ä
+U+4757 ? # Character ä
+U+4758 yì # Character ä
+U+4759 ? # Character ä
+U+475a nà # Character ä
+U+475b ? # Character ä
+U+475c ? # Character ä
+#U+475d yÇ # Character ä
+U+475e hà o # Character ä
+U+475f yà # Character ä
+U+4760 huán # Character ä
+U+4761 mà n # Character ä¡
+U+4762 mà n # Character ä¢
+U+4763 qú # Character ä£
+#U+4764 lÇo # Character ä¤
+U+4765 háo # Character ä¥
+U+4766 ? # Character ä¦
+U+4767 mén # Character ä§
+U+4768 xián # Character ä¨
+U+4769 zhèn # Character ä©
+U+476a shú # Character äª
+U+476b zuó # Character ä«
+U+476c zhù # Character ä¬
+U+476d gòu # Character ä
+U+476e xuà n # Character ä®
+U+476f yì # Character ä¯
+U+4770 tà # Character ä°
+U+4771 ? # Character ä±
+U+4772 jìn # Character ä²
+U+4773 cán # Character ä³
+U+4774 ? # Character ä´
+U+4775 bù # Character äµ
+U+4776 liáng # Character ä¶
+U+4777 zhì # Character ä·
+U+4778 jì # Character ä¸
+#U+4779 wÇn # Character ä¹
+U+477a guà n # Character äº
+U+477b ? # Character ä»
+U+477c qÃng # Character ä¼
+U+477d à i # Character ä½
+U+477e fù # Character ä¾
+U+477f guì # Character ä¿
+U+4780 gòu # Character ä
+U+4781 xià n # Character ä
+#U+4782 ruÇn # Character ä
+U+4783 zhì # Character ä
+U+4784 bià o # Character ä
+U+4785 yà # Character ä
+#U+4786 suÇ # Character ä
+U+4787 dié # Character ä
+#U+4788 guÇ # Character ä
+U+4789 shèng # Character ä
+U+478a xùn # Character ä
+U+478b chèn # Character ä
+U+478c shé # Character ä
+U+478d qÃng # Character ä
+U+478e ? # Character ä
+U+478f ? # Character ä
+#U+4790 chÇn # Character ä
+U+4791 hóng # Character ä
+U+4792 dòng # Character ä
+#U+4793 chÄng # Character ä
+#U+4794 wÄi # Character ä
+U+4795 dié # Character ä
+#U+4796 shÇ # Character ä
+U+4797 ? # Character ä
+U+4798 jà # Character ä
+U+4799 zá # Character ä
+U+479a qà # Character ä
+U+479b ? # Character ä
+U+479c fù # Character ä
+#U+479d Ço # Character ä
+U+479e fú # Character ä
+U+479f pò # Character ä
+U+47a0 ? # Character ä
+#U+47a1 tÇn # Character ä¡
+U+47a2 zhà # Character ä¢
+#U+47a3 chÄ # Character ä£
+U+47a4 qú # Character ä¤
+U+47a5 yòu # Character ä¥
+U+47a6 hé # Character ä¦
+U+47a7 hòu # Character ä§
+#U+47a8 guÇ # Character ä¨
+U+47a9 è # Character ä©
+U+47aa jià ng # Character äª
+#U+47ab yÇn # Character ä«
+U+47ac tòu # Character ä¬
+#U+47ad qiÇ # Character ä
+U+47ae ? # Character ä®
+U+47af fù # Character ä¯
+U+47b0 zuó # Character ä°
+U+47b1 hú # Character ä±
+U+47b2 ? # Character ä²
+U+47b3 bó # Character ä³
+U+47b4 ? # Character ä´
+#U+47b5 juÄ # Character äµ
+U+47b6 dì # Character ä¶
+U+47b7 jué # Character ä·
+U+47b8 fù # Character ä¸
+U+47b9 huáng # Character ä¹
+U+47ba ? # Character äº
+#U+47bb yÇng # Character ä»
+#U+47bc chuÇ # Character ä¼
+#U+47bd suÇ # Character ä½
+U+47be chà # Character ä¾
+U+47bf ? # Character ä¿
+U+47c0 ? # Character ä
+U+47c1 ? # Character ä
+U+47c2 mán # Character ä
+U+47c3 cà # Character ä
+U+47c4 qì # Character ä
+U+47c5 jià n # Character ä
+U+47c6 bì # Character ä
+U+47c7 ? # Character ä
+U+47c8 zhà # Character ä
+U+47c9 zhú # Character ä
+U+47ca qú # Character ä
+#U+47cb zhÇn # Character ä
+U+47cc jà # Character ä
+U+47cd dián # Character ä
+U+47ce ? # Character ä
+U+47cf lì # Character ä
+U+47d0 lì # Character ä
+#U+47d1 lÇ # Character ä
+U+47d2 quán # Character ä
+U+47d3 ? # Character ä
+U+47d4 fù # Character ä
+U+47d5 chà # Character ä
+U+47d6 tà ng # Character ä
+U+47d7 shì # Character ä
+U+47d8 hà ng # Character ä
+U+47d9 qiè # Character ä
+U+47da qà # Character ä
+U+47db bó # Character ä
+U+47dc nà # Character ä
+U+47dd tòu # Character ä
+U+47de chú # Character ä
+U+47df cù # Character ä
+U+47e0 yuè # Character ä
+U+47e1 dì # Character ä¡
+U+47e2 chén # Character ä¢
+U+47e3 chù # Character ä£
+U+47e4 bì # Character ä¤
+U+47e5 máng # Character ä¥
+U+47e6 bá # Character ä¦
+U+47e7 tián # Character ä§
+U+47e8 mÃn # Character ä¨
+#U+47e9 liÄ # Character ä©
+#U+47ea fÄng # Character äª
+U+47eb ? # Character ä«
+U+47ec qiù # Character ä¬
+U+47ed tiáo # Character ä
+U+47ee fú # Character ä®
+U+47ef kuò # Character ä¯
+#U+47f0 jiÇn # Character ä°
+U+47f1 ? # Character ä±
+U+47f2 ? # Character ä²
+U+47f3 ? # Character ä³
+U+47f4 zhèn # Character ä´
+U+47f5 qiú # Character äµ
+U+47f6 cuò # Character ä¶
+U+47f7 chì # Character ä·
+U+47f8 kuà # Character ä¸
+U+47f9 liè # Character ä¹
+#U+47fa bÇng # Character äº
+U+47fb dù # Character ä»
+#U+47fc wÇ # Character ä¼
+U+47fd ? # Character ä½
+#U+47fe juÄ # Character ä¾
+U+47ff lù # Character ä¿
diff --git a/resources/chars/latin1/row48.trans b/resources/chars/latin1/row48.trans
new file mode 100644
index 0000000..60d5a59
--- /dev/null
+++ b/resources/chars/latin1/row48.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+4800 chÇng # Character ä
+U+4801 ? # Character ä
+U+4802 chú # Character ä
+#U+4803 liÇng # Character ä
+#U+4804 tiÇn # Character ä
+#U+4805 kÇn # Character ä
+U+4806 cháng # Character ä
+U+4807 jué # Character ä
+U+4808 tú # Character ä
+U+4809 huà # Character ä
+U+480a fèi # Character ä
+#U+480b bÇ # Character ä
+U+480c ? # Character ä
+U+480d qiá # Character ä
+U+480e wò # Character ä
+U+480f jì # Character ä
+U+4810 qù # Character ä
+#U+4811 kuÇ # Character ä
+U+4812 hú # Character ä
+U+4813 cù # Character ä
+U+4814 suì # Character ä
+U+4815 ? # Character ä
+U+4816 ? # Character ä
+U+4817 qiù # Character ä
+U+4818 pì # Character ä
+U+4819 bèi # Character ä
+U+481a wà # Character ä
+#U+481b jiÇo # Character ä
+U+481c róng # Character ä
+U+481d ? # Character ä
+U+481e cù # Character ä
+U+481f dié # Character ä
+U+4820 chì # Character ä
+U+4821 cuó # Character ä ¡
+U+4822 mèng # Character ä ¢
+#U+4823 xuÇn # Character ä £
+#U+4824 duÇ # Character ä ¤
+U+4825 bié # Character ä ¥
+U+4826 zhè # Character ä ¦
+U+4827 chú # Character ä §
+U+4828 chà n # Character ä ¨
+U+4829 guì # Character ä ©
+U+482a duà n # Character ä ª
+U+482b zòu # Character ä «
+U+482c dèng # Character ä ¬
+U+482d lái # Character ä
+U+482e téng # Character ä ®
+U+482f yuè # Character ä ¯
+U+4830 quán # Character ä °
+#U+4831 shÇ # Character ä ±
+U+4832 lÃng # Character ä ²
+U+4833 ? # Character ä ³
+#U+4834 qÇn # Character ä ´
+U+4835 fù # Character ä µ
+U+4836 shè # Character ä ¶
+#U+4837 tiÇo # Character ä ·
+U+4838 ? # Character ä ¸
+U+4839 ái # Character ä ¹
+U+483a ? # Character ä º
+U+483b qióng # Character ä »
+U+483c dià o # Character ä ¼
+U+483d hái # Character ä ½
+#U+483e shÇn # Character ä ¾
+U+483f wà i # Character ä ¿
+#U+4840 zhÇn # Character ä¡
+#U+4841 lÇng # Character ä¡
+U+4842 jiù # Character ä¡
+U+4843 lì # Character ä¡
+U+4844 ? # Character ä¡
+#U+4845 mÇn # Character ä¡
+U+4846 róng # Character ä¡
+U+4847 yuè # Character ä¡
+U+4848 jué # Character ä¡
+#U+4849 kÇng # Character ä¡
+U+484a fán # Character ä¡
+U+484b qà # Character ä¡
+U+484c hóng # Character ä¡
+U+484d fú # Character ä¡
+U+484e lú # Character ä¡
+U+484f hóng # Character ä¡
+U+4850 tuó # Character ä¡
+U+4851 mÃn # Character ä¡
+U+4852 tián # Character ä¡
+U+4853 juà n # Character ä¡
+#U+4854 qÇ # Character ä¡
+#U+4855 zhÄng # Character ä¡
+U+4856 jìng # Character ä¡
+#U+4857 gÇng # Character ä¡
+U+4858 tián # Character ä¡
+U+4859 láng # Character ä¡
+U+485a mà o # Character ä¡
+U+485b yìn # Character ä¡
+U+485c lù # Character ä¡
+#U+485d yÇn # Character ä¡
+U+485e jú # Character ä¡
+U+485f pì # Character ä¡
+U+4860 ? # Character ä¡
+U+4861 xié # Character 䡡
+U+4862 bià n # Character 䡢
+U+4863 ? # Character ä¡£
+U+4864 ? # Character 䡤
+U+4865 róng # Character 䡥
+#U+4866 sÇng # Character 䡦
+#U+4867 wÇ # Character 䡧
+U+4868 chà # Character 䡨
+#U+4869 gÇ # Character ä¡©
+U+486a chán # Character 䡪
+U+486b péng # Character 䡫
+U+486c mà n # Character 䡬
+U+486d ? # Character ä¡
+U+486e ? # Character ä¡®
+U+486f shuà ng # Character 䡯
+#U+4870 kÄng # Character ä¡°
+#U+4871 zhuÇn # Character 䡱
+U+4872 chán # Character 䡲
+U+4873 ? # Character 䡳
+U+4874 chuáng # Character 䡴
+U+4875 suì # Character 䡵
+U+4876 bèi # Character 䡶
+U+4877 kà i # Character 䡷
+U+4878 ? # Character 䡸
+U+4879 zhì # Character 䡹
+U+487a wèi # Character 䡺
+U+487b mÃn # Character ä¡»
+U+487c lÃng # Character 䡼
+U+487d ? # Character 䡽
+U+487e nèi # Character 䡾
+U+487f lÃng # Character ä¡¿
+U+4880 qì # Character ä¢
+U+4881 yuè # Character ä¢
+U+4882 ? # Character ä¢
+U+4883 yì # Character ä¢
+#U+4884 xÇ # Character ä¢
+U+4885 chén # Character ä¢
+U+4886 ? # Character ä¢
+#U+4887 rÇng # Character ä¢
+U+4888 chén # Character ä¢
+U+4889 nóng # Character ä¢
+U+488a yóu # Character ä¢
+U+488b jì # Character ä¢
+U+488c bó # Character ä¢
+#U+488d fÇng # Character ä¢
+U+488e ? # Character ä¢
+U+488f ? # Character ä¢
+U+4890 cú # Character ä¢
+#U+4891 dÇ # Character ä¢
+U+4892 ? # Character ä¢
+U+4893 yú # Character ä¢
+U+4894 gé # Character ä¢
+U+4895 xù # Character ä¢
+#U+4896 lÇ # Character ä¢
+U+4897 hé # Character ä¢
+U+4898 ? # Character ä¢
+U+4899 bà i # Character ä¢
+U+489a gòng # Character ä¢
+#U+489b jiÇng # Character ä¢
+U+489c ? # Character ä¢
+U+489d yà # Character ä¢
+U+489e nù # Character ä¢
+U+489f yóu # Character ä¢
+U+48a0 sòng # Character ä¢
+U+48a1 xiè # Character 䢡
+U+48a2 cà ng # Character 䢢
+U+48a3 yáo # Character 䢣
+U+48a4 shù # Character 䢤
+U+48a5 yán # Character 䢥
+U+48a6 shuà i # Character 䢦
+U+48a7 lià o # Character 䢧
+U+48a8 ? # Character 䢨
+U+48a9 yù # Character 䢩
+U+48aa bó # Character 䢪
+U+48ab suà # Character 䢫
+U+48ac ? # Character 䢬
+U+48ad yà n # Character ä¢
+U+48ae lèi # Character 䢮
+U+48af lÃn # Character 䢯
+U+48b0 tái # Character 䢰
+U+48b1 dú # Character 䢱
+U+48b2 yuè # Character 䢲
+#U+48b3 jÇ # Character 䢳
+U+48b4 ? # Character 䢴
+U+48b5 yún # Character 䢵
+U+48b6 ? # Character 䢶
+U+48b7 ? # Character 䢷
+U+48b8 ? # Character 䢸
+#U+48b9 jÇ # Character 䢹
+U+48ba ? # Character 䢺
+U+48bb chén # Character 䢻
+U+48bc ? # Character 䢼
+U+48bd xià ng # Character 䢽
+#U+48be xiÇn # Character 䢾
+U+48bf ? # Character 䢿
+#U+48c0 guÇ # Character ä£
+#U+48c1 yÇ # Character ä£
+#U+48c2 lÄi # Character ä£
+U+48c3 ? # Character ä£
+U+48c4 tú # Character ä£
+U+48c5 chén # Character ä£
+U+48c6 xÃng # Character ä£
+U+48c7 qiú # Character ä£
+U+48c8 hà ng # Character ä£
+U+48c9 ? # Character ä£
+#U+48ca dÇng # Character ä£
+#U+48cb cÇi # Character ä£
+#U+48cc dÇ # Character ä£
+#U+48cd yÇn # Character ä£
+U+48ce ? # Character ä£
+U+48cf ? # Character ä£
+U+48d0 ? # Character ä£
+U+48d1 chán # Character ä£
+U+48d2 ? # Character ä£
+U+48d3 là # Character ä£
+#U+48d4 suÇ # Character ä£
+#U+48d5 mÇ # Character ä£
+#U+48d6 mÇ # Character ä£
+U+48d7 ? # Character ä£
+U+48d8 táng # Character ä£
+U+48d9 péi # Character ä£
+U+48da lóu # Character ä£
+U+48db ? # Character ä£
+U+48dc cuó # Character ä£
+U+48dd tú # Character ä£
+U+48de è # Character ä£
+U+48df cán # Character ä£
+U+48e0 jié # Character ä£
+U+48e1 tà # Character 䣡
+U+48e2 jà # Character 䣢
+#U+48e3 dÇng # Character 䣣
+U+48e4 jià o # Character 䣤
+#U+48e5 bÇ # Character 䣥
+U+48e6 lèi # Character 䣦
+U+48e7 yì # Character 䣧
+U+48e8 chún # Character 䣨
+U+48e9 chún # Character 䣩
+U+48ea pò # Character 䣪
+U+48eb là # Character 䣫
+#U+48ec zÇi # Character 䣬
+U+48ed tà i # Character ä£
+U+48ee pò # Character 䣮
+#U+48ef tiÇn # Character 䣯
+U+48f0 jù # Character 䣰
+U+48f1 xù # Character 䣱
+U+48f2 fà n # Character 䣲
+U+48f3 ? # Character 䣳
+U+48f4 xù # Character 䣴
+U+48f5 èr # Character 䣵
+U+48f6 huó # Character 䣶
+U+48f7 ? # Character 䣷
+#U+48f8 rÇn # Character 䣸
+U+48f9 fá # Character 䣹
+U+48fa ? # Character 䣺
+U+48fb ? # Character 䣻
+U+48fc liáng # Character 䣼
+#U+48fd tÇ # Character 䣽
+U+48fe mì # Character 䣾
+U+48ff ? # Character 䣿
diff --git a/resources/chars/latin1/row49.trans b/resources/chars/latin1/row49.trans
new file mode 100644
index 0000000..dc906ee
--- /dev/null
+++ b/resources/chars/latin1/row49.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+4900 ? # Character ä¤
+U+4901 cén # Character ä¤
+U+4902 méi # Character ä¤
+U+4903 yìn # Character ä¤
+#U+4904 miÇn # Character ä¤
+U+4905 tú # Character ä¤
+U+4906 kuà # Character ä¤
+U+4907 ? # Character ä¤
+U+4908 ? # Character ä¤
+U+4909 mì # Character ä¤
+U+490a róng # Character ä¤
+U+490b guó # Character ä¤
+U+490c ? # Character ä¤
+U+490d mà # Character ä¤
+U+490e jú # Character ä¤
+#U+490f pÇ # Character ä¤
+#U+4910 jÇn # Character ä¤
+U+4911 wà ng # Character ä¤
+#U+4912 jÇ # Character ä¤
+U+4913 méng # Character ä¤
+U+4914 jià n # Character ä¤
+U+4915 xuè # Character ä¤
+U+4916 bà o # Character ä¤
+#U+4917 gÇn # Character ä¤
+#U+4918 chÇn # Character ä¤
+U+4919 lì # Character ä¤
+#U+491a lÇ # Character ä¤
+U+491b qiú # Character ä¤
+U+491c dùn # Character ä¤
+U+491d yìng # Character ä¤
+#U+491e yÇn # Character ä¤
+U+491f chén # Character ä¤
+#U+4920 jÄ« # Character ä¤
+#U+4921 rÇn # Character 䤡
+U+4922 ? # Character 䤢
+U+4923 lüè # Character 䤣
+U+4924 ? # Character 䤤
+#U+4925 guÇ # Character 䤥
+U+4926 yuè # Character 䤦
+U+4927 huì # Character 䤧
+U+4928 pì # Character 䤨
+U+4929 chá # Character 䤩
+#U+492a duÇ # Character 䤪
+U+492b chán # Character 䤫
+U+492c ? # Character 䤬
+U+492d kuà n # Character ä¤
+U+492e shè # Character 䤮
+U+492f xÃng # Character 䤯
+#U+4930 wÄng # Character 䤰
+U+4931 shì # Character 䤱
+U+4932 chì # Character 䤲
+U+4933 yè # Character 䤳
+U+4934 hán # Character 䤴
+U+4935 fèi # Character 䤵
+U+4936 yè # Character 䤶
+U+4937 yán # Character 䤷
+U+4938 zuà n # Character 䤸
+U+4939 ? # Character 䤹
+#U+493a yÇn # Character 䤺
+U+493b duò # Character 䤻
+U+493c xià n # Character 䤼
+U+493d ? # Character 䤽
+U+493e ? # Character 䤾
+U+493f qiè # Character 䤿
+#U+4940 chÇn # Character ä¥
+U+4941 hán # Character ä¥
+U+4942 mèng # Character ä¥
+U+4943 yuè # Character ä¥
+U+4944 cù # Character ä¥
+U+4945 qià n # Character ä¥
+#U+4946 jÇn # Character ä¥
+U+4947 shà n # Character ä¥
+#U+4948 mÇ # Character ä¥
+U+4949 ? # Character ä¥
+U+494a ? # Character ä¥
+U+494b ? # Character ä¥
+U+494c zhèng # Character ä¥
+U+494d zhì # Character ä¥
+U+494e chún # Character ä¥
+#U+494f yÇ # Character ä¥
+U+4950 móu # Character ä¥
+U+4951 wà n # Character ä¥
+U+4952 chóu # Character ä¥
+U+4953 ? # Character ä¥
+U+4954 sù # Character ä¥
+#U+4955 piÄ # Character ä¥
+U+4956 tián # Character ä¥
+#U+4957 kuÇn # Character ä¥
+U+4958 cù # Character ä¥
+U+4959 suì # Character ä¥
+U+495a ? # Character ä¥
+U+495b jié # Character ä¥
+U+495c jià n # Character ä¥
+U+495d áo # Character ä¥
+#U+495e jiÇo # Character ä¥
+U+495f yè # Character ä¥
+U+4960 ? # Character ä¥
+U+4961 yè # Character 䥡
+U+4962 lóng # Character 䥢
+U+4963 záo # Character 䥣
+U+4964 báo # Character 䥤
+U+4965 lián # Character 䥥
+U+4966 ? # Character 䥦
+U+4967 huán # Character 䥧
+#U+4968 lÇ # Character 䥨
+U+4969 wéi # Character 䥩
+#U+496a xiÇn # Character 䥪
+#U+496b tiÄ # Character 䥫
+U+496c bó # Character 䥬
+U+496d zhèng # Character ä¥
+U+496e zhú # Character 䥮
+U+496f bà # Character 䥯
+U+4970 mèng # Character 䥰
+#U+4971 xiÄ # Character 䥱
+U+4972 ? # Character 䥲
+U+4973 ? # Character 䥳
+U+4974 ? # Character 䥴
+#U+4975 xiÇo # Character 䥵
+U+4976 lì # Character 䥶
+U+4977 zhá # Character 䥷
+U+4978 mà # Character 䥸
+U+4979 ? # Character 䥹
+U+497a yé # Character 䥺
+U+497b ? # Character 䥻
+U+497c ? # Character 䥼
+U+497d ? # Character 䥽
+#U+497e xiÄ # Character 䥾
+U+497f ? # Character 䥿
+U+4980 ? # Character ä¦
+U+4981 ? # Character ä¦
+U+4982 shà n # Character ä¦
+U+4983 ? # Character ä¦
+U+4984 ? # Character ä¦
+U+4985 shà n # Character ä¦
+U+4986 jué # Character ä¦
+U+4987 jì # Character ä¦
+#U+4988 fÇng # Character ä¦
+U+4989 ? # Character ä¦
+#U+498a niÇo # Character ä¦
+U+498b áo # Character ä¦
+U+498c chù # Character ä¦
+U+498d wù # Character ä¦
+#U+498e guÇn # Character ä¦
+U+498f xiè # Character ä¦
+#U+4990 tÇng # Character ä¦
+U+4991 xiè # Character ä¦
+U+4992 dà ng # Character ä¦
+U+4993 ? # Character ä¦
+#U+4994 tÇn # Character ä¦
+U+4995 ? # Character ä¦
+U+4996 xiá # Character ä¦
+U+4997 xù # Character ä¦
+U+4998 bì # Character ä¦
+U+4999 sì # Character ä¦
+U+499a huò # Character ä¦
+U+499b zhèng # Character ä¦
+U+499c wú # Character ä¦
+U+499d ? # Character ä¦
+U+499e rùn # Character ä¦
+U+499f chuà i # Character ä¦
+#U+49a0 shÇ # Character ä¦
+U+49a1 huán # Character 䦡
+U+49a2 kuò # Character 䦢
+U+49a3 fù # Character 䦣
+U+49a4 chuà i # Character 䦤
+U+49a5 xián # Character 䦥
+U+49a6 qÃn # Character 䦦
+U+49a7 qié # Character 䦧
+U+49a8 lán # Character 䦨
+U+49a9 ? # Character 䦩
+U+49aa yà # Character 䦪
+U+49ab ? # Character 䦫
+U+49ac què # Character 䦬
+U+49ad ? # Character ä¦
+#U+49ae chÇn # Character 䦮
+U+49af zhì # Character 䦯
+U+49b0 ? # Character 䦰
+#U+49b1 kuÇ # Character 䦱
+U+49b2 qià n # Character 䦲
+U+49b3 hà ng # Character 䦳
+U+49b4 yì # Character 䦴
+#U+49b5 nÇ # Character 䦵
+U+49b6 zhèng # Character 䦶
+U+49b7 chuà i # Character 䦷
+U+49b8 ? # Character 䦸
+U+49b9 shà # Character 䦹
+U+49ba ? # Character 䦺
+U+49bb cì # Character 䦻
+U+49bc jué # Character 䦼
+U+49bd xù # Character 䦽
+#U+49be yÇn # Character 䦾
+U+49bf ? # Character 䦿
+U+49c0 ? # Character ä§
+U+49c1 chù # Character ä§
+U+49c2 dà o # Character ä§
+U+49c3 dià n # Character ä§
+U+49c4 gè # Character ä§
+U+49c5 tì # Character ä§
+U+49c6 hóng # Character ä§
+#U+49c7 nÇ # Character ä§
+U+49c8 ? # Character ä§
+#U+49c9 lÇ # Character ä§
+U+49ca ? # Character ä§
+#U+49cb xiÇn # Character ä§
+U+49cc ? # Character ä§
+U+49cd xì # Character ä§
+U+49ce xuà n # Character ä§
+U+49cf ? # Character ä§
+U+49d0 ? # Character ä§
+U+49d1 ? # Character ä§
+U+49d2 lái # Character ä§
+U+49d3 ? # Character ä§
+U+49d4 mù # Character ä§
+U+49d5 chéng # Character ä§
+U+49d6 jià n # Character ä§
+U+49d7 bì # Character ä§
+U+49d8 qà # Character ä§
+U+49d9 lÃng # Character ä§
+U+49da hà o # Character ä§
+U+49db bà ng # Character ä§
+U+49dc táng # Character ä§
+U+49dd dì # Character ä§
+U+49de fù # Character ä§
+U+49df xià n # Character ä§
+U+49e0 shuà n # Character ä§
+U+49e1 ? # Character 䧡
+U+49e2 ? # Character 䧢
+U+49e3 ? # Character 䧣
+U+49e4 pú # Character 䧤
+U+49e5 huì # Character 䧥
+U+49e6 wéi # Character 䧦
+#U+49e7 yÇ # Character 䧧
+U+49e8 yè # Character 䧨
+U+49e9 ? # Character 䧩
+U+49ea chè # Character 䧪
+U+49eb háo # Character 䧫
+U+49ec ? # Character 䧬
+U+49ed ? # Character ä§
+#U+49ee xiÇn # Character 䧮
+U+49ef chán # Character 䧯
+U+49f0 hùn # Character 䧰
+U+49f1 ? # Character 䧱
+U+49f2 hà n # Character 䧲
+U+49f3 cà # Character 䧳
+U+49f4 ? # Character 䧴
+U+49f5 qà # Character 䧵
+U+49f6 kuà # Character 䧶
+U+49f7 róu # Character 䧷
+U+49f8 ? # Character 䧸
+U+49f9 ? # Character 䧹
+U+49fa xióng # Character 䧺
+U+49fb ? # Character 䧻
+U+49fc hú # Character 䧼
+#U+49fd cuÇ # Character 䧽
+U+49fe ? # Character 䧾
+U+49ff què # Character 䧿
diff --git a/resources/chars/latin1/row4a.trans b/resources/chars/latin1/row4a.trans
new file mode 100644
index 0000000..e868bc8
--- /dev/null
+++ b/resources/chars/latin1/row4a.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+4a00 dà # Character ä¨
+U+4a01 chè # Character ä¨
+U+4a02 ? # Character ä¨
+U+4a03 ? # Character ä¨
+U+4a04 yà n # Character ä¨
+U+4a05 liáo # Character ä¨
+U+4a06 bà # Character ä¨
+U+4a07 ? # Character ä¨
+U+4a08 ? # Character ä¨
+U+4a09 ? # Character ä¨
+U+4a0a ? # Character ä¨
+U+4a0b nüè # Character ä¨
+U+4a0c báo # Character ä¨
+#U+4a0d yÇng # Character ä¨
+U+4a0e hóng # Character ä¨
+U+4a0f cà # Character ä¨
+U+4a10 qià # Character ä¨
+U+4a11 tà # Character ä¨
+U+4a12 yù # Character ä¨
+U+4a13 léi # Character ä¨
+U+4a14 báo # Character ä¨
+U+4a15 ? # Character ä¨
+U+4a16 jì # Character ä¨
+U+4a17 fú # Character ä¨
+U+4a18 xià n # Character ä¨
+U+4a19 cén # Character ä¨
+U+4a1a ? # Character ä¨
+U+4a1b sè # Character ä¨
+U+4a1c ? # Character ä¨
+U+4a1d ? # Character ä¨
+#U+4a1e yÇ # Character ä¨
+U+4a1f ? # Character ä¨
+#U+4a20 Çi # Character ä¨
+U+4a21 hán # Character 䨡
+U+4a22 dà n # Character 䨢
+U+4a23 gé # Character 䨣
+U+4a24 dà # Character 䨤
+U+4a25 hù # Character 䨥
+U+4a26 páng # Character 䨦
+U+4a27 ? # Character 䨧
+U+4a28 ? # Character 䨨
+U+4a29 lÃng # Character 䨩
+U+4a2a mái # Character 䨪
+U+4a2b mà i # Character 䨫
+U+4a2c lián # Character 䨬
+U+4a2d ? # Character ä¨
+#U+4a2e xuÄ # Character 䨮
+U+4a2f zhèn # Character 䨯
+U+4a30 pò # Character 䨰
+U+4a31 fù # Character 䨱
+U+4a32 nóu # Character 䨲
+U+4a33 xì # Character 䨳
+U+4a34 duì # Character 䨴
+U+4a35 dà n # Character 䨵
+#U+4a36 yÇn # Character 䨶
+U+4a37 xià n # Character 䨷
+#U+4a38 yÇn # Character 䨸
+U+4a39 ? # Character 䨹
+U+4a3a duì # Character 䨺
+U+4a3b bèng # Character 䨻
+U+4a3c hù # Character 䨼
+#U+4a3d fÄi # Character 䨽
+#U+4a3e fÄi # Character 䨾
+U+4a3f qián # Character 䨿
+U+4a40 bèi # Character ä©
+U+4a41 ? # Character ä©
+U+4a42 ? # Character ä©
+U+4a43 shì # Character ä©
+#U+4a44 tiÇn # Character ä©
+#U+4a45 zhÇn # Character ä©
+#U+4a46 jiÇn # Character ä©
+U+4a47 ? # Character ä©
+U+4a48 huì # Character ä©
+#U+4a49 fÇ # Character ä©
+#U+4a4a wÇn # Character ä©
+#U+4a4b mÇ # Character ä©
+U+4a4c qiáo # Character ä©
+#U+4a4d liÇo # Character ä©
+U+4a4e ? # Character ä©
+U+4a4f miè # Character ä©
+U+4a50 gé # Character ä©
+U+4a51 hóng # Character ä©
+U+4a52 yú # Character ä©
+U+4a53 qà # Character ä©
+U+4a54 duò # Character ä©
+U+4a55 áng # Character ä©
+U+4a56 ? # Character ä©
+U+4a57 bà # Character ä©
+U+4a58 dì # Character ä©
+U+4a59 xuà n # Character ä©
+U+4a5a dì # Character ä©
+U+4a5b bì # Character ä©
+U+4a5c zhòu # Character ä©
+U+4a5d páo # Character ä©
+U+4a5e nián # Character ä©
+U+4a5f yà # Character ä©
+U+4a60 ? # Character ä©
+U+4a61 jiá # Character 䩡
+U+4a62 dá # Character 䩢
+#U+4a63 duÇ # Character ä©£
+U+4a64 xì # Character 䩤
+U+4a65 dà n # Character 䩥
+U+4a66 tiáo # Character 䩦
+U+4a67 xiè # Character 䩧
+U+4a68 chà ng # Character 䩨
+#U+4a69 yuÇn # Character ä©©
+#U+4a6a guÇn # Character 䩪
+#U+4a6b liÇng # Character ä©«
+#U+4a6c bÄng # Character 䩬
+U+4a6d ? # Character ä©
+U+4a6e lù # Character 䩮
+U+4a6f jà # Character 䩯
+U+4a70 xuà n # Character 䩰
+U+4a71 shù # Character 䩱
+U+4a72 ? # Character 䩲
+#U+4a73 shÇ # Character 䩳
+U+4a74 hú # Character 䩴
+U+4a75 yùn # Character 䩵
+#U+4a76 chÇn # Character 䩶
+U+4a77 ? # Character ä©·
+U+4a78 róng # Character 䩸
+U+4a79 é # Character 䩹
+U+4a7a ? # Character 䩺
+U+4a7b bà # Character 䩻
+U+4a7c féng # Character 䩼
+U+4a7d ? # Character 䩽
+U+4a7e zhè # Character 䩾
+U+4a7f fén # Character 䩿
+#U+4a80 guÇn # Character äª
+#U+4a81 bÇ # Character äª
+U+4a82 gé # Character äª
+U+4a83 ? # Character äª
+U+4a84 huáng # Character äª
+U+4a85 dú # Character äª
+#U+4a86 tÇ # Character äª
+U+4a87 bó # Character äª
+#U+4a88 qiÇn # Character äª
+U+4a89 là # Character äª
+U+4a8a lóng # Character äª
+U+4a8b wèi # Character äª
+U+4a8c zhà n # Character äª
+U+4a8d lán # Character äª
+U+4a8e ? # Character äª
+U+4a8f nà # Character äª
+U+4a90 bì # Character äª
+U+4a91 tuó # Character äª
+U+4a92 jià o # Character äª
+U+4a93 ? # Character äª
+#U+4a94 bÇ # Character äª
+U+4a95 jú # Character äª
+U+4a96 pò # Character äª
+U+4a97 xiá # Character äª
+#U+4a98 wÄi # Character äª
+U+4a99 fú # Character äª
+U+4a9a hè # Character äª
+U+4a9b fán # Character äª
+U+4a9c chà n # Character äª
+U+4a9d hù # Character äª
+U+4a9e zá # Character äª
+U+4a9f ? # Character äª
+U+4aa0 ? # Character äª
+U+4aa1 ? # Character 䪡
+U+4aa2 ? # Character 䪢
+U+4aa3 ? # Character 䪣
+U+4aa4 fán # Character 䪤
+U+4aa5 dié # Character 䪥
+U+4aa6 hóng # Character 䪦
+U+4aa7 chà # Character 䪧
+U+4aa8 báo # Character 䪨
+U+4aa9 yÃn # Character 䪩
+U+4aaa ? # Character 䪪
+U+4aab ? # Character 䪫
+U+4aac bó # Character 䪬
+#U+4aad ruÇn # Character äª
+#U+4aae chÇu # Character 䪮
+U+4aaf yÃng # Character 䪯
+U+4ab0 ? # Character 䪰
+#U+4ab1 gÇi # Character 䪱
+U+4ab2 ? # Character 䪲
+#U+4ab3 yÇn # Character 䪳
+#U+4ab4 zhÄn # Character 䪴
+#U+4ab5 yÇ # Character 䪵
+U+4ab6 ? # Character 䪶
+U+4ab7 hòu # Character 䪷
+U+4ab8 mÃn # Character 䪸
+U+4ab9 péi # Character 䪹
+U+4aba gé # Character 䪺
+U+4abb bià n # Character 䪻
+U+4abc ? # Character 䪼
+U+4abd hà o # Character 䪽
+U+4abe mà # Character 䪾
+#U+4abf shÄng # Character 䪿
+#U+4ac0 gÄn # Character ä«
+U+4ac1 bì # Character ä«
+#U+4ac2 duÇ # Character ä«
+U+4ac3 chún # Character ä«
+U+4ac4 chuà # Character ä«
+U+4ac5 sà n # Character ä«
+U+4ac6 chéng # Character ä«
+U+4ac7 rán # Character ä«
+U+4ac8 zèn # Character ä«
+U+4ac9 mà o # Character ä«
+U+4aca bó # Character ä«
+U+4acb tuà # Character ä«
+#U+4acc pÇ # Character ä«
+#U+4acd fÇ # Character ä«
+U+4ace ? # Character ä«
+U+4acf ? # Character ä«
+U+4ad0 lÃn # Character ä«
+U+4ad1 ? # Character ä«
+U+4ad2 mén # Character ä«
+U+4ad3 wú # Character ä«
+U+4ad4 qì # Character ä«
+U+4ad5 zhì # Character ä«
+#U+4ad6 chÄn # Character ä«
+U+4ad7 xiá # Character ä«
+U+4ad8 hé # Character ä«
+#U+4ad9 sÇng # Character ä«
+U+4ada ? # Character ä«
+U+4adb hóu # Character ä«
+U+4adc ? # Character ä«
+#U+4add fÇ # Character ä«
+U+4ade ráo # Character ä«
+U+4adf hún # Character ä«
+U+4ae0 péi # Character ä«
+U+4ae1 qià n # Character 䫡
+U+4ae2 ? # Character ä«¢
+U+4ae3 xà # Character 䫣
+U+4ae4 mÃng # Character 䫤
+#U+4ae5 kuÇ # Character ä«¥
+U+4ae6 gé # Character 䫦
+U+4ae7 ? # Character 䫧
+U+4ae8 à o # Character 䫨
+#U+4ae9 sÇn # Character ä«©
+#U+4aea shuÇng # Character 䫪
+U+4aeb lóu # Character 䫫
+#U+4aec zhÄn # Character 䫬
+U+4aed huì # Character ä«
+U+4aee cán # Character 䫮
+U+4aef ? # Character 䫯
+U+4af0 lìn # Character 䫰
+U+4af1 ná # Character 䫱
+U+4af2 hà n # Character 䫲
+U+4af3 dú # Character 䫳
+U+4af4 jìn # Character 䫴
+U+4af5 mián # Character 䫵
+U+4af6 fán # Character 䫶
+U+4af7 è # Character 䫷
+U+4af8 náo # Character 䫸
+U+4af9 hóng # Character 䫹
+U+4afa hóng # Character 䫺
+U+4afb xué # Character 䫻
+U+4afc xuè # Character 䫼
+U+4afd ? # Character 䫽
+U+4afe bì # Character 䫾
+U+4aff ? # Character ä«¿
diff --git a/resources/chars/latin1/row4b.trans b/resources/chars/latin1/row4b.trans
new file mode 100644
index 0000000..0c927b4
--- /dev/null
+++ b/resources/chars/latin1/row4b.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+4b00 yÇu # Character ä¬
+U+4b01 yà # Character ä¬
+U+4b02 xuè # Character ä¬
+U+4b03 sà # Character ä¬
+U+4b04 yù # Character ä¬
+U+4b05 lì # Character ä¬
+U+4b06 lì # Character ä¬
+U+4b07 yuà n # Character ä¬
+U+4b08 duì # Character ä¬
+U+4b09 hà o # Character ä¬
+U+4b0a qiè # Character ä¬
+U+4b0b léng # Character ä¬
+U+4b0c ? # Character ä¬
+U+4b0d ? # Character ä¬
+U+4b0e guó # Character ä¬
+U+4b0f bù # Character ä¬
+#U+4b10 wÄi # Character ä¬
+U+4b11 wèi # Character ä¬
+U+4b12 ? # Character ä¬
+U+4b13 à n # Character ä¬
+U+4b14 xù # Character ä¬
+#U+4b15 shÇng # Character ä¬
+U+4b16 héng # Character ä¬
+U+4b17 yáng # Character ä¬
+U+4b18 ? # Character ä¬
+U+4b19 yáo # Character ä¬
+U+4b1a ? # Character ä¬
+U+4b1b bì # Character ä¬
+U+4b1c ? # Character ä¬
+U+4b1d héng # Character ä¬
+U+4b1e táo # Character ä¬
+U+4b1f liú # Character ä¬
+U+4b20 ? # Character ä¬
+U+4b21 zhù # Character 䬡
+U+4b22 ? # Character 䬢
+U+4b23 qì # Character 䬣
+U+4b24 cháo # Character 䬤
+U+4b25 yì # Character 䬥
+U+4b26 dòu # Character 䬦
+U+4b27 yuán # Character 䬧
+U+4b28 cù # Character 䬨
+U+4b29 ? # Character 䬩
+U+4b2a bó # Character 䬪
+#U+4b2b cÇn # Character 䬫
+#U+4b2c yÇng # Character 䬬
+U+4b2d ? # Character ä¬
+U+4b2e yà # Character 䬮
+U+4b2f nián # Character 䬯
+U+4b30 shà o # Character 䬰
+U+4b31 bèn # Character 䬱
+U+4b32 ? # Character 䬲
+#U+4b33 bÇn # Character 䬳
+U+4b34 mò # Character 䬴
+U+4b35 à i # Character 䬵
+U+4b36 èn # Character 䬶
+#U+4b37 shÄ # Character 䬷
+U+4b38 ? # Character 䬸
+U+4b39 zhì # Character 䬹
+U+4b3a yà ng # Character 䬺
+U+4b3b jià n # Character 䬻
+U+4b3c yuà n # Character 䬼
+U+4b3d duì # Character 䬽
+U+4b3e tà # Character 䬾
+#U+4b3f wÄi # Character 䬿
+U+4b40 xùn # Character ä
+U+4b41 zhì # Character ä
+U+4b42 yì # Character ä
+#U+4b43 rÄn # Character ä
+U+4b44 shì # Character ä
+U+4b45 hú # Character ä
+U+4b46 nè # Character ä
+U+4b47 yì # Character ä
+U+4b48 jià n # Character ä
+#U+4b49 suÇ # Character ä
+#U+4b4a yÇng # Character ä
+#U+4b4b bÇo # Character ä
+U+4b4c hú # Character ä
+U+4b4d hú # Character ä
+U+4b4e xié # Character ä
+U+4b4f ? # Character ä
+U+4b50 yà ng # Character ä
+U+4b51 lián # Character ä
+U+4b52 ? # Character ä
+U+4b53 èn # Character ä
+U+4b54 ? # Character ä
+U+4b55 jià n # Character ä
+U+4b56 zhù # Character ä
+#U+4b57 yÇng # Character ä
+U+4b58 yà n # Character ä
+#U+4b59 jÇn # Character ä
+U+4b5a chuáng # Character ä
+U+4b5b dà n # Character ä
+U+4b5c ? # Character ä
+U+4b5d kuà i # Character ä
+U+4b5e yì # Character ä
+U+4b5f yè # Character ä
+#U+4b60 jiÇn # Character ä
+U+4b61 èn # Character ä¡
+U+4b62 nÃng # Character ä¢
+U+4b63 cà # Character ä£
+#U+4b64 qiÇn # Character ä¤
+U+4b65 xuè # Character ä¥
+U+4b66 bó # Character ä¦
+#U+4b67 mÇ # Character ä§
+U+4b68 shuì # Character ä¨
+U+4b69 mì # Character ä©
+U+4b6a liáng # Character äª
+#U+4b6b qÇ # Character ä«
+#U+4b6c qÇ # Character ä¬
+#U+4b6d shÇu # Character ä
+U+4b6e bì # Character ä®
+U+4b6f bó # Character ä¯
+#U+4b70 bÄng # Character ä°
+U+4b71 bié # Character ä±
+#U+4b72 nÇ # Character ä²
+U+4b73 wèi # Character ä³
+U+4b74 huán # Character ä´
+U+4b75 fán # Character äµ
+U+4b76 qà # Character ä¶
+U+4b77 liú # Character ä·
+U+4b78 fù # Character ä¸
+U+4b79 áng # Character ä¹
+U+4b7a áng # Character äº
+U+4b7b ? # Character ä»
+U+4b7c qà # Character ä¼
+U+4b7d qún # Character ä½
+U+4b7e tuó # Character ä¾
+U+4b7f yì # Character ä¿
+U+4b80 bó # Character ä®
+U+4b81 pián # Character ä®
+U+4b82 bó # Character ä®
+U+4b83 ? # Character ä®
+U+4b84 xuán # Character ä®
+U+4b85 ? # Character ä®
+U+4b86 ? # Character ä®
+U+4b87 yù # Character ä®
+U+4b88 chà # Character ä®
+U+4b89 lú # Character ä®
+U+4b8a yà # Character ä®
+U+4b8b lì # Character ä®
+U+4b8c ? # Character ä®
+#U+4b8d niÇo # Character ä®
+U+4b8e xì # Character ä®
+U+4b8f wú # Character ä®
+U+4b90 ? # Character ä®
+U+4b91 lèi # Character ä®
+U+4b92 ? # Character ä®
+U+4b93 zhà o # Character ä®
+#U+4b94 zuÇ # Character ä®
+U+4b95 chuò # Character ä®
+U+4b96 ? # Character ä®
+U+4b97 Ã n # Character ä®
+U+4b98 ér # Character ä®
+U+4b99 yù # Character ä®
+U+4b9a lèng # Character ä®
+U+4b9b fù # Character ä®
+U+4b9c shà # Character ä®
+U+4b9d huán # Character ä®
+U+4b9e chù # Character ä®
+#U+4b9f sÇu # Character ä®
+U+4ba0 ? # Character ä®
+U+4ba1 bì # Character 䮡
+U+4ba2 dié # Character 䮢
+U+4ba3 ? # Character 䮣
+U+4ba4 dà # Character 䮤
+U+4ba5 lì # Character 䮥
+U+4ba6 ? # Character 䮦
+U+4ba7 hán # Character 䮧
+#U+4ba8 zÇi # Character 䮨
+U+4ba9 gú # Character 䮩
+U+4baa chéng # Character 䮪
+U+4bab lóu # Character 䮫
+U+4bac mò # Character 䮬
+U+4bad mì # Character ä®
+U+4bae mà i # Character 䮮
+U+4baf à o # Character 䮯
+#U+4bb0 dÇn # Character ä®°
+U+4bb1 zhú # Character 䮱
+U+4bb2 huáng # Character 䮲
+U+4bb3 fán # Character 䮳
+U+4bb4 dèng # Character 䮴
+U+4bb5 tóng # Character 䮵
+U+4bb6 ? # Character 䮶
+U+4bb7 dú # Character 䮷
+U+4bb8 hú # Character 䮸
+U+4bb9 wèi # Character 䮹
+U+4bba jì # Character 䮺
+U+4bbb chì # Character 䮻
+U+4bbc lÃn # Character 䮼
+U+4bbd ? # Character 䮽
+U+4bbe páng # Character 䮾
+#U+4bbf jiÇn # Character 䮿
+U+4bc0 niè # Character ä¯
+U+4bc1 luó # Character ä¯
+U+4bc2 jà # Character ä¯
+U+4bc3 ? # Character ä¯
+U+4bc4 ? # Character ä¯
+U+4bc5 niè # Character ä¯
+U+4bc6 yì # Character ä¯
+U+4bc7 ? # Character ä¯
+U+4bc8 wán # Character ä¯
+U+4bc9 yà # Character ä¯
+U+4bca qià # Character ä¯
+U+4bcb bó # Character ä¯
+U+4bcc ? # Character ä¯
+U+4bcd lÃng # Character ä¯
+U+4bce gà n # Character ä¯
+U+4bcf huó # Character ä¯
+U+4bd0 hái # Character ä¯
+U+4bd1 ? # Character ä¯
+U+4bd2 héng # Character ä¯
+U+4bd3 kuà # Character ä¯
+U+4bd4 cén # Character ä¯
+U+4bd5 ? # Character ä¯
+U+4bd6 láng # Character ä¯
+U+4bd7 bì # Character ä¯
+U+4bd8 huà n # Character ä¯
+U+4bd9 pò # Character ä¯
+#U+4bda Çu # Character ä¯
+#U+4bdb jiÇn # Character ä¯
+U+4bdc tì # Character ä¯
+#U+4bdd suÇ # Character ä¯
+U+4bde ? # Character ä¯
+U+4bdf duì # Character ä¯
+#U+4be0 Ço # Character ä¯
+#U+4be1 jiÇn # Character 䯡
+U+4be2 mó # Character 䯢
+U+4be3 guì # Character 䯣
+U+4be4 kuà i # Character 䯤
+U+4be5 à n # Character 䯥
+U+4be6 mà # Character 䯦
+#U+4be7 qÇng # Character 䯧
+U+4be8 fén # Character 䯨
+U+4be9 ? # Character 䯩
+#U+4bea kÇo # Character 䯪
+U+4beb hà o # Character 䯫
+#U+4bec duÇ # Character 䯬
+U+4bed ? # Character ä¯
+U+4bee nái # Character 䯮
+U+4bef ? # Character 䯯
+U+4bf0 jiè # Character 䯰
+U+4bf1 fù # Character 䯱
+U+4bf2 pá # Character 䯲
+U+4bf3 ? # Character 䯳
+U+4bf4 cháng # Character 䯴
+U+4bf5 niè # Character 䯵
+U+4bf6 mán # Character 䯶
+U+4bf7 ? # Character 䯷
+U+4bf8 cì # Character 䯸
+U+4bf9 ? # Character 䯹
+U+4bfa kuò # Character 䯺
+U+4bfb ? # Character 䯻
+U+4bfc dà # Character 䯼
+#U+4bfd fÇ # Character 䯽
+U+4bfe tiáo # Character 䯾
+U+4bff zú # Character 䯿
diff --git a/resources/chars/latin1/row4c.trans b/resources/chars/latin1/row4c.trans
new file mode 100644
index 0000000..0ac9020
--- /dev/null
+++ b/resources/chars/latin1/row4c.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+4c00 wÇ # Character ä°
+U+4c01 fèi # Character ä°
+U+4c02 cà i # Character ä°
+U+4c03 péng # Character ä°
+U+4c04 shì # Character ä°
+U+4c05 ? # Character ä°
+U+4c06 róu # Character ä°
+U+4c07 qà # Character ä°
+#U+4c08 chÇ # Character ä°
+U+4c09 pán # Character ä°
+U+4c0a bó # Character ä°
+U+4c0b mán # Character ä°
+#U+4c0c zÇng # Character ä°
+U+4c0d cì # Character ä°
+U+4c0e guì # Character ä°
+U+4c0f jì # Character ä°
+U+4c10 lán # Character ä°
+U+4c11 ? # Character ä°
+U+4c12 méng # Character ä°
+U+4c13 mián # Character ä°
+U+4c14 pán # Character ä°
+U+4c15 lú # Character ä°
+U+4c16 cuán # Character ä°
+U+4c17 ? # Character ä°
+U+4c18 liú # Character ä°
+#U+4c19 yÇ # Character ä°
+U+4c1a wén # Character ä°
+U+4c1b lì # Character ä°
+U+4c1c lì # Character ä°
+U+4c1d zèng # Character ä°
+#U+4c1e zhÇ # Character ä°
+U+4c1f hún # Character ä°
+U+4c20 shén # Character ä°
+U+4c21 chì # Character 䰡
+U+4c22 xìng # Character 䰢
+#U+4c23 wÇng # Character ä°£
+U+4c24 ? # Character ä°¤
+U+4c25 huò # Character 䰥
+#U+4c26 pÇ # Character ä°¦
+U+4c27 ? # Character ä°§
+U+4c28 mèi # Character 䰨
+#U+4c29 chÄ # Character ä°©
+U+4c2a mèi # Character 䰪
+U+4c2b cháo # Character 䰫
+U+4c2c jú # Character 䰬
+U+4c2d nòu # Character ä°
+U+4c2e ? # Character ä°®
+#U+4c2f nÇ # Character ä°¯
+U+4c30 rú # Character 䰰
+U+4c31 lÃng # Character ä°±
+U+4c32 yà # Character 䰲
+U+4c33 ? # Character ä°³
+U+4c34 qì # Character 䰴
+U+4c35 ? # Character ä°µ
+U+4c36 ? # Character ä°¶
+U+4c37 bà ng # Character 䰷
+U+4c38 ? # Character ä°¸
+U+4c39 zé # Character 䰹
+U+4c3a jiè # Character 䰺
+U+4c3b yú # Character 䰻
+U+4c3c xÃn # Character ä°¼
+U+4c3d bèi # Character 䰽
+U+4c3e bà # Character 䰾
+U+4c3f tuó # Character 䰿
+U+4c40 ? # Character ä±
+U+4c41 qiáo # Character ä±
+#U+4c42 yÇu # Character ä±
+#U+4c43 dÇ # Character ä±
+U+4c44 jiè # Character ä±
+U+4c45 mò # Character ä±
+U+4c46 shéng # Character ä±
+U+4c47 shà n # Character ä±
+U+4c48 qà # Character ä±
+U+4c49 shà n # Character ä±
+#U+4c4a mÇ # Character ä±
+#U+4c4b dÇn # Character ä±
+U+4c4c yà # Character ä±
+U+4c4d gèng # Character ä±
+U+4c4e gèng # Character ä±
+#U+4c4f tÇu # Character ä±
+U+4c50 ? # Character ä±
+U+4c51 xué # Character ä±
+U+4c52 yì # Character ä±
+U+4c53 tÃng # Character ä±
+U+4c54 tiáo # Character ä±
+U+4c55 móu # Character ä±
+U+4c56 liú # Character ä±
+U+4c57 ? # Character ä±
+U+4c58 là # Character ä±
+U+4c59 ? # Character ä±
+U+4c5a lù # Character ä±
+U+4c5b xù # Character ä±
+U+4c5c cuò # Character ä±
+U+4c5d bà # Character ä±
+U+4c5e liú # Character ä±
+U+4c5f jù # Character ä±
+U+4c60 zhà n # Character ä±
+U+4c61 jú # Character 䱡
+U+4c62 ? # Character ä±¢
+U+4c63 zú # Character 䱣
+U+4c64 xià n # Character 䱤
+U+4c65 zhà # Character 䱥
+U+4c66 ? # Character 䱦
+U+4c67 ? # Character 䱧
+U+4c68 zhì # Character 䱨
+U+4c69 ? # Character 䱩
+U+4c6a ? # Character 䱪
+U+4c6b là # Character 䱫
+U+4c6c ? # Character 䱬
+U+4c6d gèng # Character ä±
+U+4c6e é # Character 䱮
+U+4c6f mú # Character 䱯
+U+4c70 zhòng # Character 䱰
+U+4c71 dì # Character 䱱
+U+4c72 yán # Character 䱲
+U+4c73 ? # Character ä±³
+U+4c74 gèng # Character 䱴
+U+4c75 ? # Character ä±µ
+U+4c76 láng # Character 䱶
+U+4c77 yú # Character 䱷
+U+4c78 ? # Character 䱸
+U+4c79 nà # Character 䱹
+U+4c7a hái # Character 䱺
+U+4c7b huá # Character 䱻
+#U+4c7c zhÇn # Character ä±¼
+U+4c7d ? # Character ä±½
+U+4c7e lóu # Character 䱾
+U+4c7f chà n # Character 䱿
+U+4c80 dié # Character ä²
+U+4c81 wèi # Character ä²
+U+4c82 xuán # Character ä²
+#U+4c83 zÇo # Character ä²
+U+4c84 mÃn # Character ä²
+U+4c85 ? # Character ä²
+U+4c86 ? # Character ä²
+U+4c87 ? # Character ä²
+U+4c88 ? # Character ä²
+U+4c89 ? # Character ä²
+#U+4c8a tuÇ # Character ä²
+U+4c8b cén # Character ä²
+#U+4c8c kuÇn # Character ä²
+U+4c8d téng # Character ä²
+#U+4c8e nÄi # Character ä²
+U+4c8f láo # Character ä²
+#U+4c90 lÇ # Character ä²
+U+4c91 yà # Character ä²
+U+4c92 xiè # Character ä²
+#U+4c93 yÇn # Character ä²
+U+4c94 qÃng # Character ä²
+#U+4c95 pÇ # Character ä²
+U+4c96 chóu # Character ä²
+U+4c97 xián # Character ä²
+#U+4c98 guÇn # Character ä²
+U+4c99 jié # Character ä²
+U+4c9a là i # Character ä²
+U+4c9b méng # Character ä²
+U+4c9c yè # Character ä²
+U+4c9d ? # Character ä²
+U+4c9e lì # Character ä²
+U+4c9f yìn # Character ä²
+U+4ca0 ? # Character ä²
+U+4ca1 ? # Character 䲡
+U+4ca2 téng # Character 䲢
+U+4ca3 yú # Character 䲣
+U+4ca4 ? # Character 䲤
+U+4ca5 ? # Character ä²¥
+U+4ca6 chá # Character 䲦
+U+4ca7 dù # Character 䲧
+U+4ca8 hóng # Character 䲨
+U+4ca9 ? # Character 䲩
+U+4caa xì # Character 䲪
+U+4cab ? # Character 䲫
+U+4cac qà # Character 䲬
+U+4cad ? # Character ä²
+U+4cae yuán # Character 䲮
+U+4caf jà # Character 䲯
+U+4cb0 yùn # Character 䲰
+#U+4cb1 fÇng # Character ä²±
+U+4cb2 ? # Character ä²²
+U+4cb3 háng # Character 䲳
+U+4cb4 zhèn # Character 䲴
+U+4cb5 hù # Character 䲵
+U+4cb6 ? # Character 䲶
+U+4cb7 ? # Character ä²·
+U+4cb8 jiè # Character 䲸
+U+4cb9 péi # Character 䲹
+U+4cba gà n # Character 䲺
+U+4cbb xuán # Character 䲻
+U+4cbc ? # Character ä²¼
+#U+4cbd dÇo # Character ä²½
+#U+4cbe qiÇo # Character ä²¾
+U+4cbf cà # Character 䲿
+U+4cc0 dié # Character ä³
+U+4cc1 bá # Character ä³
+U+4cc2 tiáo # Character ä³
+#U+4cc3 wÇn # Character ä³
+U+4cc4 cà # Character ä³
+#U+4cc5 zhÇ # Character ä³
+U+4cc6 bái # Character ä³
+#U+4cc7 wÇ # Character ä³
+#U+4cc8 bÇo # Character ä³
+U+4cc9 dà n # Character ä³
+U+4cca bá # Character ä³
+U+4ccb tóng # Character ä³
+U+4ccc ? # Character ä³
+U+4ccd ? # Character ä³
+U+4cce jiù # Character ä³
+U+4ccf guì # Character ä³
+U+4cd0 cì # Character ä³
+#U+4cd1 yÇu # Character ä³
+U+4cd2 yuán # Character ä³
+#U+4cd3 lÇo # Character ä³
+U+4cd4 jiù # Character ä³
+U+4cd5 fóu # Character ä³
+U+4cd6 nèi # Character ä³
+U+4cd7 é # Character ä³
+U+4cd8 é # Character ä³
+#U+4cd9 xÇng # Character ä³
+U+4cda hé # Character ä³
+U+4cdb yà n # Character ä³
+U+4cdc tú # Character ä³
+U+4cdd bù # Character ä³
+#U+4cde bÄng # Character ä³
+U+4cdf kòu # Character ä³
+U+4ce0 chuà # Character ä³
+U+4ce1 ? # Character 䳡
+U+4ce2 qà # Character 䳢
+U+4ce3 yuán # Character 䳣
+U+4ce4 ? # Character 䳤
+U+4ce5 ? # Character ä³¥
+U+4ce6 ? # Character 䳦
+U+4ce7 hóu # Character 䳧
+U+4ce8 huáng # Character 䳨
+U+4ce9 ? # Character 䳩
+U+4cea juà n # Character 䳪
+U+4ceb kuà # Character 䳫
+U+4cec è # Character 䳬
+U+4ced jà # Character ä³
+U+4cee mò # Character 䳮
+U+4cef chóng # Character 䳯
+#U+4cf0 bÇo # Character ä³°
+U+4cf1 wù # Character 䳱
+U+4cf2 zhèn # Character 䳲
+U+4cf3 xù # Character 䳳
+U+4cf4 dá # Character 䳴
+U+4cf5 chì # Character 䳵
+U+4cf6 ? # Character 䳶
+U+4cf7 cóng # Character 䳷
+U+4cf8 má # Character 䳸
+U+4cf9 kòu # Character 䳹
+U+4cfa yà n # Character 䳺
+U+4cfb cán # Character 䳻
+U+4cfc ? # Character ä³¼
+U+4cfd hè # Character 䳽
+U+4cfe ? # Character ä³¾
+U+4cff lán # Character 䳿
diff --git a/resources/chars/latin1/row4d.trans b/resources/chars/latin1/row4d.trans
new file mode 100644
index 0000000..0c14e21
--- /dev/null
+++ b/resources/chars/latin1/row4d.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+4d00 tóng # Character ä´
+U+4d01 yù # Character ä´
+U+4d02 hà ng # Character ä´
+U+4d03 náo # Character ä´
+U+4d04 lì # Character ä´
+U+4d05 fén # Character ä´
+U+4d06 pú # Character ä´
+U+4d07 lÃng # Character ä´
+#U+4d08 Ço # Character ä´
+U+4d09 xuán # Character ä´
+U+4d0a yà # Character ä´
+U+4d0b xuán # Character ä´
+U+4d0c méng # Character ä´
+U+4d0d ? # Character ä´
+#U+4d0e lÄi # Character ä´
+U+4d0f yà n # Character ä´
+#U+4d10 bÇo # Character ä´
+U+4d11 dié # Character ä´
+U+4d12 lÃng # Character ä´
+#U+4d13 shÄ« # Character ä´
+#U+4d14 jiÄo # Character ä´
+U+4d15 liè # Character ä´
+#U+4d16 jÄ«ng # Character ä´
+U+4d17 jú # Character ä´
+#U+4d18 tÄ« # Character ä´
+U+4d19 pì # Character ä´
+#U+4d1a gÇng # Character ä´
+#U+4d1b jiÇo # Character ä´
+U+4d1c huái # Character ä´
+U+4d1d bù # Character ä´
+U+4d1e dà # Character ä´
+U+4d1f huán # Character ä´
+#U+4d20 yÇo # Character ä´
+U+4d21 lì # Character 䴡
+U+4d22 mà # Character 䴢
+U+4d23 ? # Character ä´£
+U+4d24 ? # Character ä´¤
+U+4d25 ? # Character ä´¥
+U+4d26 rén # Character 䴦
+U+4d27 ? # Character ä´§
+U+4d28 ? # Character ä´¨
+U+4d29 piáo # Character 䴩
+U+4d2a lù # Character 䴪
+U+4d2b lÃng # Character ä´«
+U+4d2c yì # Character 䴬
+U+4d2d cái # Character ä´
+U+4d2e shà n # Character 䴮
+U+4d2f ? # Character ä´¯
+U+4d30 shú # Character 䴰
+U+4d31 tuó # Character 䴱
+U+4d32 mò # Character 䴲
+U+4d33 hè # Character 䴳
+U+4d34 tiè # Character 䴴
+#U+4d35 bÇng # Character ä´µ
+U+4d36 péng # Character 䴶
+U+4d37 hún # Character 䴷
+U+4d38 ? # Character ä´¸
+#U+4d39 guÇ # Character ä´¹
+U+4d3a bù # Character 䴺
+U+4d3b là # Character 䴻
+#U+4d3c chÇn # Character ä´¼
+U+4d3d bà i # Character 䴽
+U+4d3e cuó # Character 䴾
+U+4d3f méng # Character 䴿
+#U+4d40 suÇ # Character äµ
+U+4d41 qià ng # Character äµ
+U+4d42 zhà # Character äµ
+U+4d43 kuà ng # Character äµ
+U+4d44 bà # Character äµ
+U+4d45 áo # Character äµ
+U+4d46 méng # Character äµ
+U+4d47 xià n # Character äµ
+U+4d48 ? # Character äµ
+U+4d49 tóu # Character äµ
+U+4d4a ? # Character äµ
+#U+4d4b wÄi # Character äµ
+U+4d4c ? # Character äµ
+U+4d4d ? # Character äµ
+U+4d4e ? # Character äµ
+#U+4d4f lÇo # Character äµ
+#U+4d50 chÇn # Character äµ
+U+4d51 nì # Character äµ
+U+4d52 nì # Character äµ
+U+4d53 là # Character äµ
+#U+4d54 dÇng # Character äµ
+U+4d55 jù # Character äµ
+U+4d56 jià n # Character äµ
+U+4d57 fú # Character äµ
+U+4d58 shà # Character äµ
+#U+4d59 zhÇ # Character äµ
+#U+4d5a tÇo # Character äµ
+U+4d5b jià n # Character äµ
+#U+4d5c nÇng # Character äµ
+U+4d5d yà # Character äµ
+U+4d5e jìng # Character äµ
+#U+4d5f gÇn # Character äµ
+U+4d60 dà # Character äµ
+#U+4d61 jiÇn # Character 䵡
+U+4d62 mèi # Character 䵢
+U+4d63 dá # Character 䵣
+#U+4d64 jiÇn # Character 䵤
+U+4d65 shè # Character 䵥
+U+4d66 xiè # Character 䵦
+U+4d67 zà i # Character 䵧
+U+4d68 máng # Character 䵨
+U+4d69 là # Character 䵩
+U+4d6a gùn # Character 䵪
+U+4d6b yù # Character 䵫
+U+4d6c tà # Character 䵬
+U+4d6d zhè # Character äµ
+U+4d6e yà ng # Character 䵮
+#U+4d6f tuÇn # Character 䵯
+U+4d70 ? # Character äµ°
+U+4d71 hè # Character 䵱
+U+4d72 dià o # Character 䵲
+U+4d73 wèi # Character 䵳
+U+4d74 yùn # Character 䵴
+U+4d75 zhá # Character 䵵
+U+4d76 qú # Character 䵶
+U+4d77 ? # Character äµ·
+U+4d78 ? # Character 䵸
+U+4d79 ? # Character äµ¹
+#U+4d7a tÇng # Character 䵺
+#U+4d7b gÇ # Character äµ»
+U+4d7c ? # Character äµ¼
+U+4d7d cà # Character 䵽
+U+4d7e fú # Character 䵾
+U+4d7f tiè # Character 䵿
+U+4d80 tà # Character ä¶
+U+4d81 tà # Character ä¶
+U+4d82 zhuó # Character ä¶
+U+4d83 hán # Character ä¶
+U+4d84 pÃng # Character ä¶
+U+4d85 hé # Character ä¶
+U+4d86 ? # Character ä¶
+U+4d87 zhòu # Character ä¶
+U+4d88 bó # Character ä¶
+U+4d89 liú # Character ä¶
+#U+4d8a nÇ # Character ä¶
+U+4d8b ? # Character ä¶
+U+4d8c pà o # Character ä¶
+U+4d8d dì # Character ä¶
+U+4d8e shà # Character ä¶
+#U+4d8f tÇ # Character ä¶
+U+4d90 kuà i # Character ä¶
+U+4d91 tì # Character ä¶
+U+4d92 qà # Character ä¶
+U+4d93 jì # Character ä¶
+U+4d94 chà # Character ä¶
+U+4d95 pá # Character ä¶
+U+4d96 jìn # Character ä¶
+U+4d97 kè # Character ä¶
+U+4d98 lì # Character ä¶
+U+4d99 jù # Character ä¶
+#U+4d9a qÇ # Character ä¶
+U+4d9b là # Character ä¶
+U+4d9c gù # Character ä¶
+U+4d9d qià # Character ä¶
+U+4d9e qà # Character ä¶
+U+4d9f xià n # Character ä¶
+#U+4da0 jiÇn # Character ä¶
+U+4da1 shà # Character 䶡
+U+4da2 xián # Character 䶢
+U+4da3 ái # Character 䶣
+U+4da4 huá # Character 䶤
+#U+4da5 jÇ # Character 䶥
+U+4da6 zé # Character 䶦
+#U+4da7 yÇo # Character 䶧
+U+4da8 ? # Character 䶨
+U+4da9 jì # Character 䶩
+U+4daa chá # Character 䶪
+#U+4dab kÇn # Character 䶫
+U+4dac ? # Character 䶬
+U+4dad ? # Character ä¶
+U+4dae yán # Character 䶮
+U+4daf ? # Character 䶯
+U+4db0 ? # Character 䶰
+U+4db1 tóng # Character 䶱
+U+4db2 nán # Character 䶲
+U+4db3 yuè # Character 䶳
+U+4db4 ? # Character 䶴
+U+4db5 chà # Character 䶵
+U+4db6 ? # Character 䶶
+U+4db7 ? # Character 䶷
+U+4db8 ? # Character 䶸
+U+4db9 ? # Character 䶹
+U+4dba ? # Character 䶺
+U+4dbb ? # Character 䶻
+U+4dbc ? # Character 䶼
+U+4dbd ? # Character 䶽
+U+4dbe ? # Character 䶾
+U+4dbf ? # Character 䶿
+U+4dc0 ? # Character ä·
+U+4dc1 ? # Character ä·
+U+4dc2 ? # Character ä·
+U+4dc3 ? # Character ä·
+U+4dc4 ? # Character ä·
+U+4dc5 ? # Character ä·
+U+4dc6 ? # Character ä·
+U+4dc7 ? # Character ä·
+U+4dc8 ? # Character ä·
+U+4dc9 ? # Character ä·
+U+4dca ? # Character ä·
+U+4dcb ? # Character ä·
+U+4dcc ? # Character ä·
+U+4dcd ? # Character ä·
+U+4dce ? # Character ä·
+U+4dcf ? # Character ä·
+U+4dd0 ? # Character ä·
+U+4dd1 ? # Character ä·
+U+4dd2 ? # Character ä·
+U+4dd3 ? # Character ä·
+U+4dd4 ? # Character ä·
+U+4dd5 ? # Character ä·
+U+4dd6 ? # Character ä·
+U+4dd7 ? # Character ä·
+U+4dd8 ? # Character ä·
+U+4dd9 ? # Character ä·
+U+4dda ? # Character ä·
+U+4ddb ? # Character ä·
+U+4ddc ? # Character ä·
+U+4ddd ? # Character ä·
+U+4dde ? # Character ä·
+U+4ddf ? # Character ä·
+U+4de0 ? # Character ä·
+U+4de1 ? # Character ä·¡
+U+4de2 ? # Character ä·¢
+U+4de3 ? # Character ä·£
+U+4de4 ? # Character ä·¤
+U+4de5 ? # Character ä·¥
+U+4de6 ? # Character ä·¦
+U+4de7 ? # Character ä·§
+U+4de8 ? # Character ä·¨
+U+4de9 ? # Character ä·©
+U+4dea ? # Character ä·ª
+U+4deb ? # Character ä·«
+U+4dec ? # Character ä·¬
+U+4ded ? # Character ä·
+U+4dee ? # Character ä·®
+U+4def ? # Character ä·¯
+U+4df0 ? # Character ä·°
+U+4df1 ? # Character ä·±
+U+4df2 ? # Character ä·²
+U+4df3 ? # Character ä·³
+U+4df4 ? # Character ä·´
+U+4df5 ? # Character ä·µ
+U+4df6 ? # Character ä·¶
+U+4df7 ? # Character ä··
+U+4df8 ? # Character ä·¸
+U+4df9 ? # Character ä·¹
+U+4dfa ? # Character ä·º
+U+4dfb ? # Character ä·»
+U+4dfc ? # Character ä·¼
+U+4dfd ? # Character ä·½
+U+4dfe ? # Character ä·¾
+U+4dff ? # Character ä·¿
diff --git a/resources/chars/latin1/row4e.trans b/resources/chars/latin1/row4e.trans
new file mode 100644
index 0000000..e9c8d64
--- /dev/null
+++ b/resources/chars/latin1/row4e.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+4e00 yÄ« # Character ä¸
+#U+4e01 dÄ«ng # Character ä¸
+#U+4e02 kÇo # Character ä¸
+#U+4e03 qÄ« # Character ä¸
+U+4e04 shà ng # Character ä¸
+U+4e05 xià # Character ä¸
+U+4e06 ? # Character ä¸
+U+4e07 wà n # Character ä¸
+U+4e08 zhà ng # Character ä¸
+#U+4e09 sÄn # Character ä¸
+U+4e0a shà ng # Character ä¸
+U+4e0b xià # Character ä¸
+#U+4e0c jÄ« # Character ä¸
+U+4e0d bù # Character ä¸
+#U+4e0e yÇ # Character ä¸
+#U+4e0f miÇn # Character ä¸
+U+4e10 gà i # Character ä¸
+#U+4e11 chÇu # Character ä¸
+#U+4e12 chÇu # Character ä¸
+#U+4e13 zhuÄn # Character ä¸
+#U+4e14 qiÄ # Character ä¸
+#U+4e15 pÄ« # Character ä¸
+U+4e16 shì # Character ä¸
+U+4e17 shì # Character ä¸
+#U+4e18 qiÅ« # Character ä¸
+#U+4e19 bÇng # Character ä¸
+U+4e1a yè # Character ä¸
+U+4e1b cóng # Character ä¸
+#U+4e1c dÅng # Character ä¸
+#U+4e1d sÄ« # Character ä¸
+U+4e1e chéng # Character ä¸
+#U+4e1f diÅ« # Character ä¸
+#U+4e20 qiÅ« # Character ä¸
+#U+4e21 liÇng # Character 両
+#U+4e22 diū # Character 丢
+#U+4e23 yÇu # Character 丣
+#U+4e24 liÇng # Character 两
+U+4e25 yán # Character 严
+U+4e26 bìng # Character 並
+U+4e27 sà ng # Character 丧
+#U+4e28 gÇn # Character 丨
+#U+4e29 jiū # Character 丩
+U+4e2a gè # Character 个
+#U+4e2b yÄ # Character 丫
+U+4e2c qiáng # Character 丬
+#U+4e2d zhÅng # Character ä¸
+#U+4e2e jÇ # Character 丮
+U+4e2f jiè # Character 丯
+#U+4e30 fÄng # Character 丰
+U+4e31 guà n # Character 丱
+U+4e32 chuà n # Character 串
+#U+4e33 chÇn # Character 丳
+U+4e34 lÃn # Character 临
+#U+4e35 zhuÇ # Character 丵
+#U+4e36 zhÇ # Character 丶
+U+4e37 ? # Character 丷
+U+4e38 wán # Character 丸
+#U+4e39 dÄn # Character 丹
+U+4e3a wèi # Character 为
+#U+4e3b zhÇ # Character 主
+#U+4e3c jÇng # Character 丼
+U+4e3d lì # Character 丽
+#U+4e3e jÇ # Character 举
+#U+4e3f piÄ # Character 丿
+U+4e40 fú # Character ä¹
+U+4e41 yà # Character ä¹
+U+4e42 yì # Character ä¹
+#U+4e43 nÇi # Character ä¹
+U+4e44 ? # Character ä¹
+#U+4e45 jiÇ # Character ä¹
+#U+4e46 jiÇ # Character ä¹
+U+4e47 zhé # Character ä¹
+U+4e48 me # Character ä¹
+U+4e49 yì # Character ä¹
+U+4e4a ? # Character ä¹
+#U+4e4b zhÄ« # Character ä¹
+#U+4e4c wÅ« # Character ä¹
+U+4e4d zhà # Character ä¹
+U+4e4e hu # Character ä¹
+U+4e4f fá # Character ä¹
+U+4e50 lè # Character ä¹
+U+4e51 zhòng # Character ä¹
+#U+4e52 pÄ«ng # Character ä¹
+#U+4e53 pÄng # Character ä¹
+U+4e54 qiáo # Character ä¹
+#U+4e55 hÇ # Character ä¹
+#U+4e56 guÄi # Character ä¹
+U+4e57 chéng # Character ä¹
+U+4e58 chéng # Character ä¹
+#U+4e59 yÇ # Character ä¹
+#U+4e5a yÇn # Character ä¹
+U+4e5b ? # Character ä¹
+#U+4e5c miÄ # Character ä¹
+#U+4e5d jiÇ # Character ä¹
+#U+4e5e qÇ # Character ä¹
+#U+4e5f yÄ # Character ä¹
+U+4e60 xà # Character ä¹
+#U+4e61 xiÄng # Character 乡
+U+4e62 gà i # Character 乢
+#U+4e63 diū # Character 乣
+U+4e64 ? # Character 乤
+U+4e65 ? # Character ä¹¥
+#U+4e66 shū # Character 书
+U+4e67 ? # Character 乧
+#U+4e68 shÇ # Character 乨
+#U+4e69 jī # Character 乩
+#U+4e6a nÄng # Character 乪
+#U+4e6b jiÄ # Character 乫
+U+4e6c ? # Character 乬
+U+4e6d shà # Character ä¹
+U+4e6e ? # Character ä¹®
+U+4e6f ? # Character 乯
+#U+4e70 mÇi # Character ä¹°
+U+4e71 luà n # Character 乱
+U+4e72 ? # Character ä¹²
+#U+4e73 rÇ # Character ä¹³
+U+4e74 xué # Character 乴
+#U+4e75 yÇn # Character ä¹µ
+#U+4e76 fÇ # Character 乶
+#U+4e77 shÄ # Character ä¹·
+#U+4e78 nÇ # Character 乸
+#U+4e79 gÄn # Character ä¹¹
+U+4e7a ? # Character 乺
+U+4e7b ? # Character ä¹»
+U+4e7c ? # Character ä¹¼
+U+4e7d ? # Character ä¹½
+#U+4e7e gÄn # Character ä¹¾
+U+4e7f chì # Character 乿
+#U+4e80 guÄ« # Character äº
+#U+4e81 gÄn # Character äº
+U+4e82 luà n # Character äº
+U+4e83 lÃn # Character äº
+U+4e84 yì # Character äº
+U+4e85 jué # Character äº
+U+4e86 le # Character äº
+U+4e87 ? # Character äº
+#U+4e88 yÇ # Character äº
+#U+4e89 zhÄng # Character äº
+U+4e8a shì # Character äº
+U+4e8b shì # Character äº
+U+4e8c èr # Character äº
+U+4e8d chù # Character äº
+U+4e8e yú # Character äº
+#U+4e8f kuÄ« # Character äº
+U+4e90 yú # Character äº
+U+4e91 yún # Character äº
+U+4e92 hù # Character äº
+U+4e93 qà # Character äº
+#U+4e94 wÇ # Character äº
+#U+4e95 jÇng # Character äº
+U+4e96 sì # Character äº
+U+4e97 suì # Character äº
+U+4e98 gèn # Character äº
+U+4e99 gèn # Character äº
+U+4e9a yà # Character äº
+#U+4e9b xiÄ # Character äº
+U+4e9c yà # Character äº
+U+4e9d qà # Character äº
+U+4e9e yà # Character äº
+U+4e9f jà # Character äº
+U+4ea0 tóu # Character äº
+U+4ea1 wáng # Character 亡
+U+4ea2 kà ng # Character 亢
+U+4ea3 tà # Character 亣
+#U+4ea4 jiÄo # Character 交
+U+4ea5 hà i # Character 亥
+U+4ea6 yì # Character 亦
+#U+4ea7 chÇn # Character 产
+#U+4ea8 hÄng # Character 亨
+#U+4ea9 mÇ # Character 亩
+U+4eaa ? # Character 亪
+#U+4eab xiÇng # Character 享
+#U+4eac jīng # Character 京
+U+4ead tÃng # Character äº
+U+4eae lià ng # Character 亮
+#U+4eaf xiÇng # Character 亯
+#U+4eb0 jīng # Character 亰
+U+4eb1 yè # Character 亱
+#U+4eb2 qīn # Character 亲
+U+4eb3 bó # Character 亳
+U+4eb4 yòu # Character 亴
+U+4eb5 xiè # Character 亵
+#U+4eb6 dÇn # Character 亶
+U+4eb7 lián # Character 亷
+#U+4eb8 duÇ # Character 亸
+#U+4eb9 wÄi # Character 亹
+U+4eba rén # Character 人
+U+4ebb rén # Character 亻
+U+4ebc jà # Character 亼
+U+4ebd ? # Character 亽
+U+4ebe wáng # Character 亾
+U+4ebf yì # Character 亿
+U+4ec0 shén # Character ä»
+U+4ec1 rén # Character ä»
+U+4ec2 lè # Character ä»
+#U+4ec3 dÄ«ng # Character ä»
+U+4ec4 zè # Character ä»
+#U+4ec5 jÇn # Character ä»
+#U+4ec6 pÅ« # Character ä»
+U+4ec7 chóu # Character ä»
+#U+4ec8 bÄ # Character ä»
+#U+4ec9 zhÇng # Character ä»
+#U+4eca jÄ«n # Character ä»
+U+4ecb jiè # Character ä»
+#U+4ecc bÄ«ng # Character ä»
+U+4ecd réng # Character ä»
+U+4ece cóng # Character ä»
+U+4ecf fó # Character ä»
+#U+4ed0 sÇn # Character ä»
+U+4ed1 lún # Character ä»
+U+4ed2 ? # Character ä»
+#U+4ed3 cÄng # Character ä»
+#U+4ed4 zÇ # Character ä»
+U+4ed5 shì # Character ä»
+#U+4ed6 tÄ # Character ä»
+U+4ed7 zhà ng # Character ä»
+U+4ed8 fù # Character ä»
+U+4ed9 xian # Character ä»
+#U+4eda xiÄn # Character ä»
+#U+4edb tuÅ # Character ä»
+U+4edc hóng # Character ä»
+U+4edd tóng # Character ä»
+U+4ede rèn # Character ä»
+#U+4edf qiÄn # Character ä»
+U+4ee0 gán # Character ä»
+U+4ee1 yì # Character 仡
+U+4ee2 dà # Character 仢
+U+4ee3 dà i # Character 代
+U+4ee4 lìng # Character 令
+#U+4ee5 yÇ # Character 以
+U+4ee6 chà o # Character 仦
+U+4ee7 cháng # Character 仧
+#U+4ee8 sÄ # Character 仨
+U+4ee9 ? # Character 仩
+U+4eea yà # Character 仪
+U+4eeb mù # Character 仫
+U+4eec men # Character 们
+U+4eed rèn # Character ä»
+#U+4eee jiÇ # Character ä»®
+U+4eef chà o # Character 仯
+#U+4ef0 yÇng # Character ä»°
+U+4ef1 qián # Character 仱
+U+4ef2 zhòng # Character 仲
+#U+4ef3 pÇ # Character 仳
+U+4ef4 wà n # Character 仴
+#U+4ef5 wÇ # Character 仵
+U+4ef6 jià n # Character 件
+U+4ef7 jià # Character 价
+#U+4ef8 yÇo # Character 仸
+#U+4ef9 fÄng # Character 仹
+#U+4efa cÄng # Character 仺
+U+4efb rèn # Character 任
+U+4efc wáng # Character 仼
+U+4efd fèn # Character 份
+#U+4efe dī # Character 仾
+#U+4eff fÇng # Character 仿
diff --git a/resources/chars/latin1/row4f.trans b/resources/chars/latin1/row4f.trans
new file mode 100644
index 0000000..ff4b2fd
--- /dev/null
+++ b/resources/chars/latin1/row4f.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+4f00 zhÅng # Character ä¼
+#U+4f01 qÇ # Character ä¼
+U+4f02 pèi # Character ä¼
+U+4f03 yú # Character ä¼
+U+4f04 dià o # Character ä¼
+U+4f05 dùn # Character ä¼
+U+4f06 wèn # Character ä¼
+U+4f07 yì # Character ä¼
+#U+4f08 xÇn # Character ä¼
+U+4f09 kà ng # Character ä¼
+#U+4f0a yÄ« # Character ä¼
+U+4f0b jà # Character ä¼
+U+4f0c à i # Character ä¼
+U+4f0d wu # Character ä¼
+U+4f0e jì # Character ä¼
+U+4f0f fú # Character ä¼
+U+4f10 fá # Character ä¼
+#U+4f11 xiÅ« # Character ä¼
+U+4f12 jìn # Character ä¼
+#U+4f13 bÄi # Character ä¼
+#U+4f14 dÇn # Character ä¼
+#U+4f15 fÅ« # Character ä¼
+#U+4f16 tÇng # Character ä¼
+U+4f17 zhòng # Character ä¼
+#U+4f18 yÅu # Character ä¼
+#U+4f19 huÇ # Character ä¼
+U+4f1a huì # Character ä¼
+#U+4f1b yÇ # Character ä¼
+U+4f1c cuì # Character ä¼
+U+4f1d chuán # Character ä¼
+#U+4f1e sÇn # Character ä¼
+#U+4f1f wÄi # Character ä¼
+U+4f20 chuán # Character ä¼
+#U+4f21 chÄ # Character 伡
+U+4f22 yá # Character 伢
+U+4f23 xià n # Character 伣
+#U+4f24 shÄng # Character 伤
+#U+4f25 chÄng # Character ä¼¥
+U+4f26 lún # Character 伦
+#U+4f27 cÄng # Character 伧
+U+4f28 xùn # Character 伨
+U+4f29 xìn # Character 伩
+#U+4f2a wÄi # Character 伪
+U+4f2b zhù # Character 伫
+U+4f2c ? # Character 伬
+U+4f2d xuán # Character ä¼
+U+4f2e nú # Character 伮
+U+4f2f bó # Character 伯
+#U+4f30 gū # Character 估
+#U+4f31 nÇ # Character ä¼±
+#U+4f32 nÇ # Character ä¼²
+U+4f33 xiè # Character 伳
+U+4f34 bà n # Character 伴
+U+4f35 xù # Character 伵
+U+4f36 ling # Character 伶
+U+4f37 zhòu # Character 伷
+#U+4f38 shÄn # Character 伸
+#U+4f39 qū # Character 伹
+U+4f3a cì # Character 伺
+#U+4f3b bÄng # Character ä¼»
+U+4f3c shì # Character 似
+#U+4f3d jiÄ # Character ä¼½
+#U+4f3e pī # Character 伾
+U+4f3f yì # Character 伿
+U+4f40 sì # Character ä½
+#U+4f41 Çi # Character ä½
+#U+4f42 zhÄng # Character ä½
+U+4f43 dià n # Character ä½
+U+4f44 hán # Character ä½
+U+4f45 mà i # Character ä½
+U+4f46 dà n # Character ä½
+U+4f47 zhù # Character ä½
+U+4f48 bù # Character ä½
+#U+4f49 qÅ« # Character ä½
+#U+4f4a bÇ # Character ä½
+U+4f4b shà o # Character ä½
+#U+4f4c cÇ # Character ä½
+U+4f4d wèi # Character ä½
+#U+4f4e dÄ« # Character ä½
+U+4f4f zhù # Character ä½
+#U+4f50 zuÇ # Character ä½
+U+4f51 yòu # Character ä½
+#U+4f52 yÄng # Character ä½
+#U+4f53 tÇ # Character ä½
+U+4f54 zhà n # Character ä½
+U+4f55 hé # Character ä½
+U+4f56 bì # Character ä½
+#U+4f57 tuÅ # Character ä½
+U+4f58 shé # Character ä½
+U+4f59 yú # Character ä½
+U+4f5a yì # Character ä½
+U+4f5b fú # Character ä½
+U+4f5c zuò # Character ä½
+U+4f5d kòu # Character ä½
+U+4f5e nìng # Character ä½
+U+4f5f tóng # Character ä½
+#U+4f60 nÇ # Character ä½
+#U+4f61 xuÄn # Character 佡
+U+4f62 qú # Character 佢
+U+4f63 yòng # Character 佣
+#U+4f64 wÇ # Character 佤
+#U+4f65 qiÄn # Character ä½¥
+U+4f66 ? # Character 佦
+#U+4f67 kÇ # Character 佧
+U+4f68 ? # Character 佨
+U+4f69 pèi # Character 佩
+U+4f6a huái # Character 佪
+U+4f6b hè # Character 佫
+#U+4f6c lÇo # Character 佬
+U+4f6d xiáng # Character ä½
+U+4f6e gé # Character 佮
+U+4f6f yáng # Character 佯
+#U+4f70 bÇi # Character ä½°
+#U+4f71 fÇ # Character ä½±
+U+4f72 mÃng # Character ä½²
+#U+4f73 jiÄ # Character ä½³
+U+4f74 èr # Character 佴
+U+4f75 bìng # Character 併
+U+4f76 jà # Character 佶
+#U+4f77 hÄn # Character ä½·
+U+4f78 huó # Character 佸
+#U+4f79 guÇ # Character ä½¹
+U+4f7a quán # Character 佺
+#U+4f7b tiÄo # Character ä½»
+#U+4f7c jiÇo # Character ä½¼
+U+4f7d cì # Character 佽
+U+4f7e yì # Character 佾
+#U+4f7f shÇ # Character 使
+U+4f80 xÃng # Character ä¾
+#U+4f81 shÄn # Character ä¾
+#U+4f82 tuÅ # Character ä¾
+#U+4f83 kÇn # Character ä¾
+U+4f84 zhà # Character ä¾
+#U+4f85 gÄi # Character ä¾
+U+4f86 lái # Character ä¾
+U+4f87 yà # Character ä¾
+#U+4f88 chÇ # Character ä¾
+#U+4f89 kuÄ # Character ä¾
+#U+4f8a guÄng # Character ä¾
+U+4f8b lì # Character ä¾
+#U+4f8c yÄ«n # Character ä¾
+U+4f8d shì # Character ä¾
+#U+4f8e mÇ # Character ä¾
+#U+4f8f zhÅ« # Character ä¾
+U+4f90 xù # Character ä¾
+U+4f91 yòu # Character ä¾
+#U+4f92 Än # Character ä¾
+U+4f93 lù # Character ä¾
+U+4f94 móu # Character ä¾
+U+4f95 ér # Character ä¾
+U+4f96 lún # Character ä¾
+U+4f97 tóng # Character ä¾
+U+4f98 chà # Character ä¾
+U+4f99 chì # Character ä¾
+U+4f9a xùn # Character ä¾
+#U+4f9b gÅng # Character ä¾
+#U+4f9c zhÅu # Character ä¾
+#U+4f9d yÄ« # Character ä¾
+#U+4f9e rÇ # Character ä¾
+U+4f9f jià n # Character ä¾
+U+4fa0 xiá # Character ä¾
+U+4fa1 jià # Character 価
+U+4fa2 zà i # Character 侢
+#U+4fa3 lÇ # Character ä¾£
+U+4fa4 ? # Character 侤
+#U+4fa5 jiÇo # Character ä¾¥
+#U+4fa6 zhÄn # Character 侦
+U+4fa7 cè # Character 侧
+U+4fa8 qiáo # Character 侨
+U+4fa9 kuà i # Character 侩
+U+4faa chái # Character 侪
+U+4fab nìng # Character 侫
+U+4fac nóng # Character 侬
+#U+4fad jÇn # Character ä¾
+#U+4fae wÇ # Character ä¾®
+U+4faf hóu # Character 侯
+#U+4fb0 jiÇng # Character ä¾°
+#U+4fb1 chÄng # Character ä¾±
+U+4fb2 zhèn # Character 侲
+U+4fb3 zuò # Character 侳
+#U+4fb4 chÇu # Character ä¾´
+#U+4fb5 qīn # Character 侵
+#U+4fb6 lÇ # Character 侶
+U+4fb7 jú # Character 侷
+U+4fb8 shù # Character 侸
+#U+4fb9 tÇng # Character ä¾¹
+U+4fba shèn # Character 侺
+#U+4fbb tuÅ # Character ä¾»
+U+4fbc bó # Character 侼
+U+4fbd nán # Character 侽
+#U+4fbe hÄo # Character ä¾¾
+U+4fbf bià n # Character 便
+#U+4fc0 tuÇ # Character ä¿
+#U+4fc1 yÇ # Character ä¿
+U+4fc2 xì # Character ä¿
+U+4fc3 cù # Character ä¿
+U+4fc4 é # Character ä¿
+U+4fc5 qiú # Character ä¿
+U+4fc6 xú # Character ä¿
+#U+4fc7 kuÇng # Character ä¿
+U+4fc8 kù # Character ä¿
+U+4fc9 wù # Character ä¿
+U+4fca jùn # Character ä¿
+U+4fcb yì # Character ä¿
+#U+4fcc fÇ # Character ä¿
+U+4fcd láng # Character ä¿
+#U+4fce zÇ # Character ä¿
+U+4fcf qià o # Character ä¿
+U+4fd0 lì # Character ä¿
+#U+4fd1 yÇng # Character ä¿
+U+4fd2 hùn # Character ä¿
+U+4fd3 jìng # Character ä¿
+U+4fd4 xià n # Character ä¿
+U+4fd5 sà n # Character ä¿
+#U+4fd6 pÇi # Character ä¿
+U+4fd7 sú # Character ä¿
+U+4fd8 fú # Character ä¿
+#U+4fd9 xÄ« # Character ä¿
+#U+4fda lÇ # Character ä¿
+#U+4fdb fÇ # Character ä¿
+#U+4fdc pÄ«ng # Character ä¿
+#U+4fdd bÇo # Character ä¿
+U+4fde yú # Character ä¿
+U+4fdf sì # Character ä¿
+U+4fe0 xiá # Character ä¿
+U+4fe1 xìn # Character 信
+#U+4fe2 xiū # Character 俢
+#U+4fe3 yÇ # Character ä¿£
+U+4fe4 tì # Character 俤
+#U+4fe5 chÄ # Character ä¿¥
+U+4fe6 chóu # Character 俦
+U+4fe7 ? # Character 俧
+#U+4fe8 yÇn # Character 俨
+#U+4fe9 liÇ # Character ä¿©
+U+4fea lì # Character 俪
+U+4feb lái # Character 俫
+U+4fec ? # Character 俬
+#U+4fed jiÇn # Character ä¿
+#U+4fee xiū # Character 修
+#U+4fef fÇ # Character 俯
+U+4ff0 hè # Character 俰
+U+4ff1 jù # Character 俱
+U+4ff2 xià o # Character 俲
+U+4ff3 pái # Character 俳
+U+4ff4 jià n # Character 俴
+U+4ff5 bià o # Character 俵
+U+4ff6 chù # Character 俶
+U+4ff7 fèi # Character 俷
+U+4ff8 fèng # Character 俸
+U+4ff9 yà # Character 俹
+#U+4ffa Çn # Character 俺
+U+4ffb bèi # Character 俻
+U+4ffc yù # Character 俼
+#U+4ffd xīn # Character 俽
+#U+4ffe bÇ # Character 俾
+U+4fff jià n # Character 俿
diff --git a/resources/chars/latin1/row50.trans b/resources/chars/latin1/row50.trans
new file mode 100644
index 0000000..87a68b2
--- /dev/null
+++ b/resources/chars/latin1/row50.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+5000 chÄng # Character å
+U+5001 chà # Character å
+U+5002 bìng # Character å
+U+5003 zán # Character å
+U+5004 yáo # Character å
+U+5005 cuì # Character å
+#U+5006 liÇ # Character å
+#U+5007 wÇn # Character å
+U+5008 lái # Character å
+#U+5009 cÄng # Character å
+U+500a zòng # Character å
+U+500b gè # Character å
+#U+500c guÄn # Character å
+U+500d bèi # Character å
+#U+500e tiÄn # Character å
+#U+500f shÅ« # Character å
+#U+5010 shÅ« # Character å
+U+5011 men # Character å
+U+5012 dà o # Character å
+U+5013 tán # Character å
+U+5014 jué # Character å
+U+5015 chuà # Character å
+U+5016 xìng # Character å
+U+5017 péng # Character å
+#U+5018 tÇng # Character å
+U+5019 hou # Character å
+#U+501a yÇ # Character å
+#U+501b qÄ« # Character å
+U+501c tì # Character å
+U+501d gà n # Character å
+U+501e jìng # Character å
+U+501f jiè # Character å
+#U+5020 suÄ« # Character å
+U+5021 chà ng # Character å¡
+U+5022 jié # Character å¢
+#U+5023 fÇng # Character å£
+U+5024 zhà # Character å¤
+#U+5025 kÅng # Character å¥
+U+5026 juà n # Character å¦
+#U+5027 zÅng # Character å§
+U+5028 jù # Character å¨
+U+5029 qià n # Character å©
+U+502a nà # Character åª
+U+502b lún # Character å«
+#U+502c zhuÅ # Character å¬
+#U+502d wÄi # Character å
+#U+502e luÇ # Character å®
+#U+502f sÅng # Character å¯
+U+5030 léng # Character å°
+U+5031 hùn # Character å±
+#U+5032 dÅng # Character å²
+U+5033 zì # Character å³
+U+5034 bèn # Character å´
+#U+5035 wÇ # Character åµ
+U+5036 jù # Character å¶
+U+5037 nà i # Character å·
+#U+5038 cÇi # Character å¸
+#U+5039 jiÇn # Character å¹
+U+503a zhà i # Character åº
+#U+503b yÄ # Character å»
+U+503c zhà # Character å¼
+U+503d shà # Character å½
+#U+503e qÄ«ng # Character å¾
+U+503f ? # Character å¿
+#U+5040 yÄ«ng # Character å
+#U+5041 chÄng # Character å
+#U+5042 jiÄn # Character å
+#U+5043 yÇn # Character å
+U+5044 nuà n # Character å
+U+5045 zhòng # Character å
+#U+5046 chÇn # Character å
+#U+5047 jiÇ # Character å
+U+5048 jié # Character å
+#U+5049 wÄi # Character å
+#U+504a yÇ # Character å
+#U+504b bÇng # Character å
+U+504c ruò # Character å
+U+504d tà # Character å
+#U+504e wÄi # Character å
+#U+504f piÄn # Character å
+U+5050 yà n # Character å
+#U+5051 fÄng # Character å
+#U+5052 tÇng # Character å
+U+5053 wò # Character å
+U+5054 è # Character å
+U+5055 xié # Character å
+#U+5056 chÄ # Character å
+#U+5057 shÄng # Character å
+#U+5058 kÇn # Character å
+U+5059 dì # Character å
+U+505a zuò # Character å
+#U+505b chÄ # Character å
+U+505c tÃng # Character å
+U+505d bèi # Character å
+U+505e yè # Character å
+U+505f huáng # Character å
+#U+5060 yÇo # Character å
+U+5061 zhà n # Character å¡
+#U+5062 chÇu # Character å¢
+#U+5063 yÄn # Character å£
+#U+5064 yÇu # Character å¤
+U+5065 jià n # Character å¥
+#U+5066 xÅ« # Character å¦
+#U+5067 zhÄ # Character å§
+#U+5068 cÄ« # Character å¨
+U+5069 fù # Character å©
+#U+506a bÄ« # Character åª
+U+506b zhì # Character å«
+#U+506c zÇng # Character å¬
+#U+506d miÇn # Character å
+U+506e jà # Character å®
+#U+506f yÇ # Character å¯
+U+5070 xiè # Character å°
+U+5071 xún # Character å±
+#U+5072 sÄ« # Character å²
+#U+5073 duÄn # Character å³
+U+5074 cè # Character å´
+#U+5075 zhÄn # Character åµ
+#U+5076 Çu # Character å¶
+#U+5077 tÅu # Character å·
+#U+5078 tÅu # Character å¸
+U+5079 bèi # Character å¹
+U+507a zá # Character åº
+#U+507b lÇ # Character å»
+U+507c jié # Character å¼
+#U+507d wÄi # Character å½
+U+507e fèn # Character å¾
+U+507f cháng # Character å¿
+#U+5080 guÄ« # Character å
+#U+5081 sÇu # Character å
+U+5082 zhì # Character å
+U+5083 sù # Character å
+#U+5084 xiÄ # Character å
+U+5085 fu # Character å
+U+5086 yuà n # Character å
+#U+5087 rÇng # Character å
+U+5088 lì # Character å
+U+5089 rù # Character å
+#U+508a yÇn # Character å
+U+508b gòu # Character å
+U+508c mà # Character å
+U+508d bà ng # Character å
+#U+508e diÄn # Character å
+U+508f táng # Character å
+U+5090 hà o # Character å
+U+5091 jié # Character å
+#U+5092 xÄ« # Character å
+U+5093 shà n # Character å
+U+5094 qià n # Character å
+U+5095 jué # Character å
+#U+5096 cÄng # Character å
+U+5097 chù # Character å
+#U+5098 sÇn # Character å
+U+5099 bèi # Character å
+U+509a xià o # Character å
+#U+509b yÇng # Character å
+U+509c yáo # Character å
+U+509d tà n # Character å
+#U+509e suÅ # Character å
+#U+509f yÇng # Character å
+#U+50a0 fÄ # Character å
+U+50a1 bìng # Character å¡
+#U+50a2 jiÄ # Character å¢
+#U+50a3 dÇi # Character å£
+U+50a4 zà i # Character å¤
+#U+50a5 tÇng # Character å¥
+U+50a6 ? # Character å¦
+U+50a7 bìn # Character å§
+#U+50a8 chÇ # Character å¨
+U+50a9 nuó # Character å©
+#U+50aa cÄn # Character åª
+#U+50ab lÄi # Character å«
+#U+50ac cuÄ« # Character å¬
+#U+50ad yÅng # Character å
+#U+50ae zÄo # Character å®
+#U+50af zÇng # Character å¯
+U+50b0 péng # Character å°
+#U+50b1 sÇng # Character å±
+U+50b2 Ã o # Character å²
+U+50b3 chuán # Character å³
+#U+50b4 yÇ # Character å´
+U+50b5 zhà i # Character åµ
+U+50b6 còu # Character å¶
+#U+50b7 shÄng # Character å·
+#U+50b8 qiÇng # Character å¸
+U+50b9 jìng # Character å¹
+U+50ba chì # Character åº
+#U+50bb shÇ # Character å»
+U+50bc hà n # Character å¼
+#U+50bd zhÄng # Character å½
+#U+50be qÄ«ng # Character å¾
+U+50bf yà n # Character å¿
+U+50c0 dì # Character å
+#U+50c1 xÄ« # Character å
+#U+50c2 lÇ # Character å
+U+50c3 bèi # Character å
+U+50c4 pià o # Character å
+#U+50c5 jÇn # Character å
+U+50c6 lián # Character å
+U+50c7 lù # Character å
+U+50c8 mà n # Character å
+#U+50c9 qiÄn # Character å
+#U+50ca xiÄn # Character å
+U+50cb tà n # Character å
+U+50cc yÃng # Character å
+U+50cd dòng # Character å
+U+50ce zhuà n # Character å
+U+50cf xià ng # Character å
+U+50d0 shà n # Character å
+U+50d1 qiáo # Character å
+#U+50d2 jiÇng # Character å
+#U+50d3 tuÇ # Character å
+#U+50d4 zÇn # Character å
+U+50d5 pú # Character å
+#U+50d6 xÄ« # Character å
+U+50d7 láo # Character å
+#U+50d8 chÇng # Character å
+#U+50d9 guÄng # Character å
+U+50da liáo # Character å
+#U+50db qÄ« # Character å
+U+50dc dèng # Character å
+U+50dd chán # Character å
+#U+50de wÄi # Character å
+#U+50df jÄ« # Character å
+#U+50e0 fÄn # Character å
+U+50e1 huì # Character å¡
+#U+50e2 chuÇn # Character å¢
+U+50e3 jià n # Character å£
+U+50e4 dà n # Character å¤
+#U+50e5 jiÇo # Character å¥
+U+50e6 jiù # Character å¦
+#U+50e7 sÄng # Character å§
+U+50e8 fèn # Character å¨
+U+50e9 xià n # Character å©
+U+50ea jué # Character åª
+U+50eb è # Character å«
+#U+50ec jiÄo # Character å¬
+U+50ed jià n # Character å
+U+50ee tóng # Character å®
+#U+50ef lÇn # Character å¯
+U+50f0 bó # Character å°
+U+50f1 gù # Character å±
+U+50f2 ? # Character å²
+U+50f3 sù # Character å³
+U+50f4 xià n # Character å´
+#U+50f5 jiÄng # Character åµ
+#U+50f6 mÇn # Character å¶
+U+50f7 yè # Character å·
+U+50f8 jìn # Character å¸
+U+50f9 jià # Character å¹
+U+50fa qià o # Character åº
+U+50fb pì # Character å»
+#U+50fc fÄng # Character å¼
+U+50fd zhòu # Character å½
+U+50fe à i # Character å¾
+U+50ff sà i # Character å¿
diff --git a/resources/chars/latin1/row51.trans b/resources/chars/latin1/row51.trans
new file mode 100644
index 0000000..17ec759
--- /dev/null
+++ b/resources/chars/latin1/row51.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+5100 yà # Character å
+U+5101 jùn # Character å
+U+5102 nóng # Character å
+U+5103 chán # Character å
+U+5104 yì # Character å
+#U+5105 dÄng # Character å
+#U+5106 jÇng # Character å
+#U+5107 xuÄn # Character å
+U+5108 kuà i # Character å
+#U+5109 jiÇn # Character å
+U+510a chù # Character å
+#U+510b dÄn # Character å
+#U+510c jiÇo # Character å
+#U+510d shÇ # Character å
+U+510e zà i # Character å
+U+510f ? # Character å
+U+5110 bìn # Character å
+U+5111 Ã n # Character å
+U+5112 rú # Character å
+U+5113 tái # Character å
+U+5114 chóu # Character å
+U+5115 chái # Character å
+U+5116 lán # Character å
+#U+5117 nÇ # Character å
+#U+5118 jÇn # Character å
+U+5119 qià n # Character å
+U+511a méng # Character å
+#U+511b wÇ # Character å
+U+511c nÃng # Character å
+U+511d qióng # Character å
+#U+511e nÇ # Character å
+U+511f cháng # Character å
+U+5120 liè # Character å
+#U+5121 lÄi # Character å¡
+#U+5122 lÇ # Character å¢
+U+5123 kuà ng # Character å£
+U+5124 bà o # Character å¤
+U+5125 dú # Character å¥
+#U+5126 biÄo # Character å¦
+#U+5127 zÇn # Character å§
+U+5128 zhà # Character å¨
+U+5129 sì # Character å©
+#U+512a yÅu # Character åª
+U+512b háo # Character å«
+U+512c chèn # Character å¬
+U+512d chèn # Character å
+U+512e lì # Character å®
+U+512f téng # Character å¯
+#U+5130 wÄi # Character å°
+#U+5131 lÇng # Character å±
+#U+5132 chÇ # Character å²
+U+5133 chà n # Character å³
+U+5134 ráng # Character å´
+#U+5135 shÅ« # Character åµ
+U+5136 huì # Character å¶
+U+5137 lì # Character å·
+U+5138 luó # Character å¸
+#U+5139 zÇn # Character å¹
+U+513a nuó # Character åº
+#U+513b tÇng # Character å»
+#U+513c yÇn # Character å¼
+#U+513d lÄi # Character å½
+U+513e nà ng # Character å¾
+U+513f r # Character å¿
+U+5140 wù # Character å
+#U+5141 yÇn # Character å
+#U+5142 zÄn # Character å
+U+5143 yuán # Character å
+#U+5144 xiÅng # Character å
+#U+5145 chÅng # Character å
+U+5146 zhà o # Character å
+#U+5147 xiÅng # Character å
+#U+5148 xiÄn # Character å
+#U+5149 guÄng # Character å
+U+514a duì # Character å
+U+514b kè # Character å
+U+514c duì # Character å
+#U+514d miÇn # Character å
+U+514e tù # Character å
+U+514f cháng # Character å
+U+5150 ér # Character å
+U+5151 duì # Character å
+U+5152 r # Character å
+#U+5153 xÄ«n # Character å
+U+5154 tù # Character å
+U+5155 sì # Character å
+#U+5156 yÇn # Character å
+#U+5157 yÇn # Character å
+#U+5158 shÇ # Character å
+U+5159 ? # Character å
+#U+515a dÇng # Character å
+#U+515b qiÄn # Character å
+#U+515c dÅu # Character å
+#U+515d fÄn # Character å
+U+515e máo # Character å
+#U+515f shÄn # Character å
+#U+5160 dÅu # Character å
+U+5161 ? # Character å
¡
+#U+5162 jÄ«ng # Character å
¢
+#U+5163 lÇ # Character å
£
+U+5164 huáng # Character å
¤
+U+5165 rù # Character å
¥
+U+5166 wáng # Character å
¦
+U+5167 nèi # Character å
§
+U+5168 quán # Character å
¨
+#U+5169 liÇng # Character å
©
+U+516a yú # Character å
ª
+#U+516b bÄ # Character å
«
+#U+516c gÅng # Character å
¬
+U+516d liù # Character å
+#U+516e xÄ« # Character å
®
+U+516f ? # Character å
¯
+U+5170 lán # Character å
°
+U+5171 gòng # Character å
±
+#U+5172 tiÄn # Character å
²
+#U+5173 guÄn # Character å
³
+U+5174 xìng # Character å
´
+#U+5175 bÄ«ng # Character å
µ
+U+5176 qà # Character å
¶
+U+5177 jù # Character å
·
+#U+5178 diÇn # Character å
¸
+#U+5179 zÄ« # Character å
¹
+U+517a ? # Character å
º
+#U+517b yÇng # Character å
»
+#U+517c jiÄn # Character å
¼
+U+517d shòu # Character å
½
+U+517e jì # Character å
¾
+U+517f yì # Character å
¿
+U+5180 jì # Character å
+#U+5181 chÇn # Character å
+#U+5182 jiÅng # Character å
+U+5183 ? # Character å
+#U+5184 rÇn # Character å
+U+5185 nèi # Character å
+U+5186 ? # Character å
+#U+5187 mÇo # Character å
+#U+5188 gÄng # Character å
+#U+5189 rÇn # Character å
+U+518a cè # Character å
+#U+518b jiÅng # Character å
+U+518c cè # Character å
+U+518d zà i # Character å
+#U+518e guÇ # Character å
+#U+518f jiÇng # Character å
+U+5190 mà o # Character å
+U+5191 zhòu # Character å
+U+5192 mà o # Character å
+U+5193 gòu # Character å
+#U+5194 xÇ # Character å
+#U+5195 miÇn # Character å
+U+5196 mì # Character å
+#U+5197 rÇng # Character å
+U+5198 yÃn # Character å
+#U+5199 xiÄ # Character å
+#U+519a kÇn # Character å
+#U+519b jÅ«n # Character å
+U+519c nóng # Character å
+U+519d yà # Character å
+U+519e mà # Character å
+U+519f shì # Character å
+#U+51a0 guÄn # Character å
+U+51a1 méng # Character å¡
+#U+51a2 zhÇng # Character å¢
+U+51a3 jù # Character å£
+#U+51a4 yuÄn # Character å¤
+U+51a5 mÃng # Character å¥
+U+51a6 kòu # Character å¦
+U+51a7 ? # Character å§
+U+51a8 fù # Character å¨
+#U+51a9 xiÄ # Character å©
+U+51aa mì # Character åª
+#U+51ab bÄ«ng # Character å«
+#U+51ac dÅng # Character å¬
+U+51ad tái # Character å
+#U+51ae gÄng # Character å®
+U+51af féng # Character å¯
+#U+51b0 bÄ«ng # Character å°
+U+51b1 hù # Character å±
+#U+51b2 chÅng # Character å²
+U+51b3 jué # Character å³
+U+51b4 hù # Character å´
+U+51b5 kuà ng # Character åµ
+#U+51b6 yÄ # Character å¶
+#U+51b7 lÄng # Character å·
+U+51b8 pà n # Character å¸
+U+51b9 fú # Character å¹
+#U+51ba mÇn # Character åº
+U+51bb dòng # Character å»
+#U+51bc xiÇn # Character å¼
+U+51bd liè # Character å½
+U+51be xiá # Character å¾
+#U+51bf jiÄn # Character å¿
+U+51c0 jìng # Character å
+U+51c1 shù # Character å
+#U+51c2 mÄi # Character å
+U+51c3 tú # Character å
+#U+51c4 qÄ« # Character å
+U+51c5 gù # Character å
+#U+51c6 zhÇn # Character å
+#U+51c7 sÅng # Character å
+U+51c8 jìng # Character å
+U+51c9 liáng # Character å
+U+51ca qìng # Character å
+#U+51cb diÄo # Character å
+U+51cc lÃng # Character å
+U+51cd dòng # Character å
+U+51ce gà n # Character å
+#U+51cf jiÇn # Character å
+#U+51d0 yÄ«n # Character å
+U+51d1 còu # Character å
+U+51d2 yà # Character å
+U+51d3 lì # Character å
+#U+51d4 cÄng # Character å
+#U+51d5 mÇng # Character å
+U+51d6 ? # Character å
+U+51d7 cuà # Character å
+#U+51d8 sÄ« # Character å
+U+51d9 duó # Character å
+U+51da jìn # Character å
+#U+51db lÇn # Character å
+#U+51dc lÇn # Character å
+U+51dd nÃng # Character å
+#U+51de xÄ« # Character å
+U+51df dú # Character å
+#U+51e0 jÇ # Character å
+U+51e1 fán # Character å¡
+U+51e2 fán # Character å¢
+U+51e3 fán # Character å£
+U+51e4 fèng # Character å¤
+#U+51e5 jÅ« # Character å¥
+#U+51e6 chÇ # Character å¦
+U+51e7 ? # Character å§
+#U+51e8 fÄng # Character å¨
+U+51e9 ? # Character å©
+U+51ea ? # Character åª
+U+51eb fú # Character å«
+#U+51ec fÄng # Character å¬
+U+51ed pÃng # Character å
+#U+51ee fÄng # Character å®
+#U+51ef kÇi # Character å¯
+U+51f0 huáng # Character å°
+#U+51f1 kÇi # Character å±
+#U+51f2 gÄn # Character å²
+U+51f3 dèng # Character å³
+U+51f4 pÃng # Character å´
+#U+51f5 qÅ« # Character åµ
+#U+51f6 xiÅng # Character å¶
+U+51f7 kuà i # Character å·
+#U+51f8 tÅ« # Character å¸
+#U+51f9 Äo # Character å¹
+#U+51fa chÅ« # Character åº
+#U+51fb jÄ« # Character å»
+U+51fc dà ng # Character å¼
+U+51fd hán # Character å½
+U+51fe hán # Character å¾
+U+51ff záo # Character å¿
diff --git a/resources/chars/latin1/row52.trans b/resources/chars/latin1/row52.trans
new file mode 100644
index 0000000..e72ba2f
--- /dev/null
+++ b/resources/chars/latin1/row52.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+5200 dÄo # Character å
+#U+5201 diÄo # Character å
+#U+5202 dÄo # Character å
+U+5203 rèn # Character å
+U+5204 rèn # Character å
+#U+5205 chuÄng # Character å
+#U+5206 fÄn # Character å
+U+5207 qiè # Character å
+U+5208 yì # Character å
+#U+5209 jÄ« # Character å
+#U+520a kÄn # Character å
+U+520b qià n # Character å
+#U+520c cÇn # Character å
+U+520d chú # Character å
+#U+520e wÄn # Character å
+#U+520f jÄ« # Character å
+#U+5210 dÇn # Character å
+U+5211 xÃng # Character å
+U+5212 huà # Character å
+U+5213 wán # Character å
+U+5214 jué # Character å
+U+5215 là # Character å
+U+5216 yuè # Character å
+U+5217 liè # Character å
+U+5218 liú # Character å
+U+5219 zé # Character å
+#U+521a gÄng # Character å
+U+521b chuà ng # Character å
+U+521c fú # Character å
+#U+521d chÅ« # Character å
+U+521e qù # Character å
+#U+521f jÅ« # Character å
+#U+5220 shÄn # Character å
+#U+5221 mÇn # Character å¡
+U+5222 lÃng # Character å¢
+#U+5223 zhÅng # Character å£
+U+5224 pà n # Character å¤
+U+5225 bié # Character å¥
+U+5226 jié # Character å¦
+U+5227 jié # Character å§
+U+5228 páo # Character å¨
+U+5229 lì # Character å©
+#U+522a shÄn # Character åª
+U+522b bié # Character å«
+#U+522c chÇn # Character å¬
+#U+522d jÇng # Character å
+#U+522e guÄ # Character å®
+#U+522f gÄn # Character å¯
+U+5230 dà o # Character å°
+U+5231 chuà ng # Character å±
+#U+5232 kuÄ« # Character å²
+#U+5233 kÅ« # Character å³
+U+5234 duò # Character å´
+U+5235 èr # Character åµ
+U+5236 zhì # Character å¶
+#U+5237 shuÄ # Character å·
+U+5238 quà n # Character å¸
+#U+5239 shÄ # Character å¹
+U+523a cì # Character åº
+U+523b kè # Character å»
+U+523c jié # Character å¼
+U+523d guì # Character å½
+U+523e cì # Character å¾
+U+523f guì # Character å¿
+#U+5240 kÇi # Character å
+U+5241 duò # Character å
+U+5242 jì # Character å
+U+5243 tì # Character å
+#U+5244 jÇng # Character å
+U+5245 lóu # Character å
+#U+5246 gÄn # Character å
+U+5247 zé # Character å
+#U+5248 yuÄn # Character å
+U+5249 cuò # Character å
+#U+524a xuÄ # Character å
+U+524b kè # Character å
+U+524c là # Character å
+U+524d qián # Character å
+#U+524e shÄ # Character å
+U+524f chuà ng # Character å
+#U+5250 guÇ # Character å
+U+5251 jià n # Character å
+U+5252 cuò # Character å
+U+5253 là # Character å
+#U+5254 tÄ« # Character å
+U+5255 fèi # Character å
+#U+5256 pÅu # Character å
+#U+5257 chÇn # Character å
+U+5258 qà # Character å
+U+5259 chuà ng # Character å
+U+525a zì # Character å
+#U+525b gÄng # Character å
+#U+525c wÄn # Character å
+#U+525d bÅ # Character å
+#U+525e jÄ« # Character å
+#U+525f duÅ # Character å
+U+5260 qÃng # Character å
+#U+5261 yÇn # Character å¡
+U+5262 zhuó # Character å¢
+U+5263 jià n # Character å£
+U+5264 jì # Character å¤
+#U+5265 bÅ # Character å¥
+#U+5266 yÄn # Character å¦
+U+5267 jù # Character å§
+U+5268 huò # Character å¨
+U+5269 shèng # Character å©
+#U+526a jiÇn # Character åª
+U+526b duó # Character å«
+#U+526c duÄn # Character å¬
+#U+526d wÅ« # Character å
+#U+526e guÇ # Character å®
+U+526f fù # Character å¯
+U+5270 shèng # Character å°
+U+5271 jià n # Character å±
+#U+5272 gÄ # Character å²
+#U+5273 zhÄ # Character å³
+#U+5274 kÇi # Character å´
+U+5275 chuà ng # Character åµ
+#U+5276 juÄn # Character å¶
+#U+5277 chÇn # Character å·
+U+5278 tuán # Character å¸
+U+5279 lù # Character å¹
+U+527a là # Character åº
+U+527b fóu # Character å»
+#U+527c shÄn # Character å¼
+U+527d pià o # Character å½
+#U+527e kÅu # Character å¾
+#U+527f jiÇo # Character å¿
+#U+5280 guÄ # Character å
+#U+5281 qiÄo # Character å
+U+5282 jué # Character å
+U+5283 huà # Character å
+U+5284 zhá # Character å
+U+5285 zhuò # Character å
+U+5286 lián # Character å
+U+5287 jù # Character å
+#U+5288 pÄ« # Character å
+U+5289 liú # Character å
+U+528a guì # Character å
+#U+528b jiÇo # Character å
+U+528c guì # Character å
+U+528d jià n # Character å
+U+528e jià n # Character å
+#U+528f tÄng # Character å
+#U+5290 huÅ # Character å
+U+5291 jì # Character å
+U+5292 jià n # Character å
+U+5293 yì # Character å
+U+5294 jià n # Character å
+U+5295 zhà # Character å
+U+5296 chán # Character å
+U+5297 cuán # Character å
+U+5298 mó # Character å
+U+5299 là # Character å
+U+529a zhú # Character å
+U+529b lì # Character å
+#U+529c yÄ # Character å
+U+529d quà n # Character å
+U+529e bà n # Character å
+#U+529f gÅng # Character å
+#U+52a0 jiÄ # Character å
+U+52a1 wu # Character å¡
+U+52a2 mà i # Character å¢
+U+52a3 liè # Character å£
+U+52a4 jìn # Character å¤
+#U+52a5 kÄng # Character å¥
+U+52a6 xié # Character å¦
+#U+52a7 zhÇ # Character å§
+U+52a8 dòng # Character å¨
+U+52a9 zhù # Character å©
+#U+52aa nÇ # Character åª
+U+52ab jié # Character å«
+U+52ac qú # Character å¬
+U+52ad shà o # Character å
+U+52ae yì # Character å®
+#U+52af zhÅ« # Character å¯
+#U+52b0 miÇo # Character å°
+U+52b1 lì # Character å±
+U+52b2 jìn # Character å²
+U+52b3 láo # Character å³
+U+52b4 láo # Character å´
+U+52b5 juà n # Character åµ
+#U+52b6 kÇu # Character å¶
+U+52b7 yáng # Character å·
+#U+52b8 wÄ # Character å¸
+U+52b9 xià o # Character å¹
+U+52ba móu # Character åº
+#U+52bb kuÄng # Character å»
+U+52bc jié # Character å¼
+U+52bd liè # Character å½
+U+52be hé # Character å¾
+U+52bf shì # Character å¿
+U+52c0 kè # Character å
+U+52c1 jìn # Character å
+U+52c2 háo # Character å
+U+52c3 bó # Character å
+#U+52c4 mÇn # Character å
+U+52c5 chì # Character å
+U+52c6 láng # Character å
+#U+52c7 yÇng # Character å
+#U+52c8 yÇng # Character å
+#U+52c9 miÇn # Character å
+U+52ca kè # Character å
+#U+52cb xÅ«n # Character å
+U+52cc juà n # Character å
+U+52cd qÃng # Character å
+U+52ce lù # Character å
+#U+52cf pÇu # Character å
+#U+52d0 mÄng # Character å
+U+52d1 là i # Character å
+#U+52d2 lÄi # Character å
+U+52d3 kà i # Character å
+#U+52d4 miÇn # Character å
+U+52d5 dòng # Character å
+U+52d6 xù # Character å
+U+52d7 xù # Character å
+#U+52d8 kÄn # Character å
+U+52d9 wu # Character å
+U+52da yì # Character å
+#U+52db xÅ«n # Character å
+#U+52dc wÄng # Character å
+U+52dd shèng # Character å
+U+52de láo # Character å
+U+52df mù # Character å
+U+52e0 lù # Character å
+U+52e1 pià o # Character å¡
+U+52e2 shì # Character å¢
+#U+52e3 jÄ« # Character å£
+U+52e4 qÃn # Character å¤
+#U+52e5 qiÇng # Character å¥
+#U+52e6 jiÇo # Character å¦
+U+52e7 quà n # Character å§
+#U+52e8 yÇng # Character å¨
+U+52e9 yì # Character å©
+U+52ea jué # Character åª
+U+52eb fán # Character å«
+U+52ec juà n # Character å¬
+U+52ed tóng # Character å
+U+52ee jù # Character å®
+#U+52ef dÄn # Character å¯
+U+52f0 xié # Character å°
+U+52f1 mà i # Character å±
+#U+52f2 xÅ«n # Character å²
+#U+52f3 xÅ«n # Character å³
+#U+52f4 lÇ # Character å´
+U+52f5 lì # Character åµ
+U+52f6 chè # Character å¶
+U+52f7 ráng # Character å·
+U+52f8 quà n # Character å¸
+#U+52f9 bÄo # Character å¹
+U+52fa sháo # Character åº
+U+52fb yún # Character å»
+#U+52fc jiÅ« # Character å¼
+U+52fd bà o # Character å½
+#U+52fe gÅu # Character å¾
+U+52ff wù # Character å¿
diff --git a/resources/chars/latin1/row53.trans b/resources/chars/latin1/row53.trans
new file mode 100644
index 0000000..550b938
--- /dev/null
+++ b/resources/chars/latin1/row53.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+5300 yún # Character å
+U+5301 ? # Character å
+U+5302 ? # Character å
+U+5303 gà i # Character å
+U+5304 gà i # Character å
+#U+5305 bÄo # Character å
+#U+5306 cÅng # Character å
+U+5307 ? # Character å
+#U+5308 xiÅng # Character å
+#U+5309 pÄng # Character å
+U+530a jú # Character å
+U+530b táo # Character å
+U+530c gé # Character å
+U+530d pú # Character å
+U+530e à n # Character å
+U+530f páo # Character å
+U+5310 fú # Character å
+#U+5311 gÅng # Character å
+U+5312 dá # Character å
+U+5313 jiù # Character å
+#U+5314 qiÅng # Character å
+#U+5315 bÇ # Character å
+U+5316 huà # Character å
+#U+5317 bÄi # Character å
+#U+5318 nÇo # Character å
+U+5319 shi # Character å
+#U+531a fÄng # Character å
+U+531b jiù # Character å
+U+531c yà # Character å
+#U+531d zÄ # Character å
+U+531e jià ng # Character å
+U+531f kà ng # Character å
+U+5320 jiang # Character å
+#U+5321 kuÄng # Character å¡
+#U+5322 hÅ« # Character å¢
+U+5323 xiá # Character å£
+#U+5324 qÅ« # Character å¤
+U+5325 bià n # Character å¥
+#U+5326 guÇ # Character å¦
+U+5327 qiè # Character å§
+#U+5328 zÄng # Character å¨
+#U+5329 kuÄng # Character å©
+#U+532a fÄi # Character åª
+#U+532b hÅ« # Character å«
+U+532c tóu # Character å¬
+#U+532d guÇ # Character å
+U+532e guì # Character å®
+U+532f huì # Character å¯
+#U+5330 dÄn # Character å°
+U+5331 guì # Character å±
+U+5332 lián # Character å²
+U+5333 lián # Character å³
+#U+5334 suÇn # Character å´
+U+5335 dú # Character åµ
+U+5336 jiù # Character å¶
+U+5337 qú # Character å·
+#U+5338 xÇ # Character å¸
+#U+5339 pÇ # Character å¹
+#U+533a qÅ« # Character åº
+#U+533b yÄ« # Character å»
+U+533c qià # Character å¼
+#U+533d yÇn # Character å½
+#U+533e biÇn # Character å¾
+U+533f nì # Character å¿
+#U+5340 qÅ« # Character å
+U+5341 shà # Character å
+U+5342 xìn # Character å
+#U+5343 qiÄn # Character å
+U+5344 nià n # Character å
+U+5345 sà # Character å
+U+5346 zú # Character å
+#U+5347 shÄng # Character å
+#U+5348 wÇ # Character å
+U+5349 huì # Character å
+U+534a bà n # Character å
+U+534b shì # Character å
+U+534c xì # Character å
+U+534d wà n # Character å
+U+534e huá # Character å
+U+534f xié # Character å
+U+5350 wà n # Character å
+#U+5351 bÄi # Character å
+U+5352 zú # Character å
+#U+5353 zhuÅ # Character å
+U+5354 xié # Character å
+#U+5355 dÄn # Character å
+U+5356 mà i # Character å
+U+5357 nán # Character å
+#U+5358 dÄn # Character å
+U+5359 jà # Character å
+U+535a bó # Character å
+U+535b shuà i # Character å
+U+535c bo # Character å
+U+535d kuà ng # Character å
+U+535e bià n # Character å
+#U+535f bÇ # Character å
+U+5360 zhà n # Character å
+#U+5361 kÇ # Character å¡
+U+5362 lú # Character å¢
+#U+5363 yÇu # Character å£
+#U+5364 lÇ # Character å¤
+#U+5365 xÄ« # Character å¥
+U+5366 guà # Character å¦
+U+5367 wò # Character å§
+U+5368 xiè # Character å¨
+U+5369 jié # Character å©
+U+536a jié # Character åª
+U+536b wèi # Character å«
+U+536c áng # Character å¬
+U+536d qióng # Character å
+#U+536e zhÄ« # Character å®
+#U+536f mÇo # Character å¯
+U+5370 yìn # Character å°
+#U+5371 wÄi # Character å±
+U+5372 shà o # Character å²
+U+5373 jà # Character å³
+U+5374 què # Character å´
+#U+5375 luÇn # Character åµ
+U+5376 shì # Character å¶
+#U+5377 juÇn # Character å·
+U+5378 xiè # Character å¸
+U+5379 xù # Character å¹
+#U+537a jÇn # Character åº
+U+537b què # Character å»
+U+537c wù # Character å¼
+U+537d jà # Character å½
+U+537e è # Character å¾
+#U+537f qÄ«ng # Character å¿
+#U+5380 xÄ« # Character å
+U+5381 ? # Character å
+#U+5382 chÇng # Character å
+#U+5383 zhÄn # Character å
+U+5384 è # Character å
+#U+5385 tÄ«ng # Character å
+U+5386 lì # Character å
+U+5387 zhé # Character å
+#U+5388 hÇn # Character å
+U+5389 lì # Character å
+#U+538a yÇ # Character å
+#U+538b yÄ # Character å
+U+538c yà n # Character å
+U+538d shè # Character å
+#U+538e zhÇ # Character å
+#U+538f zhÇ # Character å
+U+5390 páng # Character å
+U+5391 ? # Character å
+U+5392 hé # Character å
+U+5393 yá # Character å
+U+5394 zhì # Character å
+U+5395 cè # Character å
+U+5396 páng # Character å
+U+5397 tà # Character å
+U+5398 là # Character å
+U+5399 shè # Character å
+U+539a hòu # Character å
+#U+539b tÄ«ng # Character å
+#U+539c zuÄ« # Character å
+U+539d cuò # Character å
+U+539e fèi # Character å
+U+539f yuán # Character å
+U+53a0 cè # Character å
+U+53a1 yuán # Character å¡
+#U+53a2 xiÄng # Character å¢
+#U+53a3 yÇn # Character å£
+U+53a4 lì # Character å¤
+U+53a5 jué # Character å¥
+U+53a6 shà # Character å¦
+#U+53a7 diÄn # Character å§
+U+53a8 chú # Character å¨
+U+53a9 jiù # Character å©
+U+53aa qÃn # Character åª
+U+53ab áo # Character å«
+#U+53ac guÇ # Character å¬
+U+53ad yà n # Character å
+#U+53ae sÄ« # Character å®
+U+53af lì # Character å¯
+#U+53b0 chÇng # Character å°
+U+53b1 lán # Character å±
+U+53b2 lì # Character å²
+U+53b3 yán # Character å³
+#U+53b4 yÇn # Character å´
+U+53b5 yuán # Character åµ
+#U+53b6 sÄ« # Character å¶
+#U+53b7 gÅng # Character å·
+U+53b8 lÃn # Character å¸
+U+53b9 qiú # Character å¹
+U+53ba qù # Character åº
+U+53bb qù # Character å»
+U+53bc ? # Character å¼
+#U+53bd lÄi # Character å½
+#U+53be dÅ« # Character å¾
+U+53bf xià n # Character å¿
+#U+53c0 zhuÄn # Character å
+#U+53c1 sÄn # Character å
+#U+53c2 cÄn # Character å
+#U+53c3 cÄn # Character å
+#U+53c4 cÄn # Character å
+#U+53c5 cÄn # Character å
+U+53c6 Ã i # Character å
+U+53c7 dà i # Character å
+U+53c8 yòu # Character å
+U+53c9 cha # Character å
+U+53ca jà # Character å
+U+53cb you # Character å
+#U+53cc shuÄng # Character å
+#U+53cd fÇn # Character å
+#U+53ce shÅu # Character å
+U+53cf guà i # Character å
+U+53d0 bá # Character å
+#U+53d1 fÄ # Character å
+U+53d2 ruò # Character å
+U+53d3 shì # Character å
+#U+53d4 shÅ« # Character å
+U+53d5 zhuó # Character å
+#U+53d6 qÇ # Character å
+U+53d7 shòu # Character å
+U+53d8 bià n # Character å
+U+53d9 xù # Character å
+#U+53da jiÇ # Character å
+U+53db pà n # Character å
+#U+53dc sÇu # Character å
+U+53dd gà o # Character å
+U+53de wèi # Character å
+#U+53df sÇu # Character å
+U+53e0 dié # Character å
+U+53e1 ruì # Character å¡
+U+53e2 cóng # Character å¢
+#U+53e3 kÇu # Character å£
+#U+53e4 gÇ # Character å¤
+U+53e5 jù # Character å¥
+U+53e6 lìng # Character å¦
+#U+53e7 guÇ # Character å§
+#U+53e8 tÄo # Character å¨
+U+53e9 kòu # Character å©
+#U+53ea zhÇ # Character åª
+U+53eb jià o # Character å«
+U+53ec zhà o # Character å¬
+U+53ed ba # Character å
+#U+53ee dÄ«ng # Character å®
+#U+53ef kÄ # Character å¯
+U+53f0 tái # Character å°
+U+53f1 chì # Character å±
+#U+53f2 shÇ # Character å²
+U+53f3 yòu # Character å³
+U+53f4 qiú # Character å´
+#U+53f5 pÇ # Character åµ
+U+53f6 yè # Character å¶
+U+53f7 hà o # Character å·
+#U+53f8 sÄ« # Character å¸
+U+53f9 tà n # Character å¹
+#U+53fa chÇ # Character åº
+U+53fb lè # Character å»
+#U+53fc diÄo # Character å¼
+#U+53fd jÄ« # Character å½
+U+53fe ? # Character å¾
+#U+53ff hÅng # Character å¿
diff --git a/resources/chars/latin1/row54.trans b/resources/chars/latin1/row54.trans
new file mode 100644
index 0000000..97434be
--- /dev/null
+++ b/resources/chars/latin1/row54.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+5400 miÄ # Character å
+#U+5401 xÅ« # Character å
+U+5402 máng # Character å
+#U+5403 chÄ« # Character å
+U+5404 gè # Character å
+#U+5405 xuÄn # Character å
+#U+5406 yÄo # Character å
+#U+5407 zÇ # Character å
+U+5408 hé # Character å
+U+5409 jà # Character å
+U+540a dià o # Character å
+U+540b cùn # Character å
+U+540c tóng # Character å
+U+540d mÃng # Character å
+U+540e hòu # Character å
+U+540f lì # Character å
+#U+5410 tÇ # Character å
+U+5411 xià ng # Character å
+U+5412 zhà # Character å
+U+5413 xià # Character å
+#U+5414 yÄ # Character å
+#U+5415 lÇ # Character å
+#U+5416 Ä # Character å
+U+5417 ma # Character å
+#U+5418 Çu # Character å
+#U+5419 xuÄ # Character å
+#U+541a yÄ« # Character å
+#U+541b jÅ«n # Character å
+#U+541c chÇu # Character å
+U+541d lìn # Character å
+#U+541e tÅ«n # Character å
+U+541f yÃn # Character å
+U+5420 fèi # Character å
+#U+5421 bÇ # Character å¡
+U+5422 qìn # Character å¢
+U+5423 qìn # Character å£
+U+5424 jiè # Character å¤
+U+5425 bù # Character å¥
+#U+5426 fÇu # Character å¦
+U+5427 ba # Character å§
+#U+5428 dÅ«n # Character å¨
+#U+5429 fÄn # Character å©
+U+542a é # Character åª
+U+542b hán # Character å«
+#U+542c tÄ«ng # Character å¬
+#U+542d kÄng # Character å
+#U+542e shÇn # Character å®
+#U+542f qÇ # Character å¯
+U+5430 hóng # Character å°
+#U+5431 zhÄ« # Character å±
+#U+5432 shÄn # Character å²
+U+5433 wú # Character å³
+U+5434 wú # Character å´
+#U+5435 chÇo # Character åµ
+U+5436 ne # Character å¶
+U+5437 xuè # Character å·
+#U+5438 xÄ« # Character å¸
+#U+5439 chuÄ« # Character å¹
+#U+543a dÅu # Character åº
+#U+543b wÄn # Character å»
+#U+543c hÇu # Character å¼
+U+543d óu # Character å½
+U+543e wú # Character å¾
+U+543f gà o # Character å¿
+U+5440 ya # Character å
+U+5441 jùn # Character å
+#U+5442 lÇ # Character å
+U+5443 è # Character å
+U+5444 gé # Character å
+U+5445 méi # Character å
+#U+5446 dÄi # Character å
+#U+5447 qÇ # Character å
+U+5448 chéng # Character å
+U+5449 wú # Character å
+U+544a gà o # Character å
+#U+544b fÅ« # Character å
+U+544c jià o # Character å
+#U+544d hÅng # Character å
+#U+544e chÇ # Character å
+#U+544f shÄng # Character å
+U+5450 ne # Character å
+#U+5451 tÅ«n # Character å
+#U+5452 fÇ # Character å
+U+5453 yì # Character å
+#U+5454 dÄi # Character å
+#U+5455 Åu # Character å
+U+5456 lì # Character å
+U+5457 bei # Character å
+U+5458 yuán # Character å
+#U+5459 kuÄi # Character å
+U+545a ? # Character å
+#U+545b qiÄng # Character å
+#U+545c wÅ« # Character å
+U+545d è # Character å
+#U+545e shÄ« # Character å
+#U+545f quÇn # Character å
+#U+5460 pÄn # Character å
+#U+5461 wÄn # Character å¡
+U+5462 ne # Character å¢
+U+5463 ? # Character å£
+#U+5464 lÇng # Character å¤
+#U+5465 rÇn # Character å¥
+#U+5466 yÅu # Character å¦
+#U+5467 dÇ # Character å§
+#U+5468 zhÅu # Character å¨
+U+5469 shì # Character å©
+U+546a zhòu # Character åª
+#U+546b tiÄ # Character å«
+U+546c xì # Character å¬
+U+546d yì # Character å
+U+546e qì # Character å®
+U+546f pÃng # Character å¯
+#U+5470 zÇ # Character å°
+#U+5471 gÅ« # Character å±
+#U+5472 zÄ« # Character å²
+U+5473 wèi # Character å³
+#U+5474 xÅ« # Character å´
+#U+5475 Ä # Character åµ
+U+5476 náo # Character å¶
+#U+5477 xiÄ # Character å·
+#U+5478 pÄi # Character å¸
+U+5479 yì # Character å¹
+#U+547a xiÄo # Character åº
+#U+547b shÄn # Character å»
+#U+547c hÅ« # Character å¼
+U+547d mìng # Character å½
+U+547e dá # Character å¾
+#U+547f qÅ« # Character å¿
+#U+5480 jÇ # Character å
+U+5481 ? # Character å
+#U+5482 zÄ # Character å
+#U+5483 tuÅ # Character å
+#U+5484 duÅ # Character å
+U+5485 pòu # Character å
+U+5486 páo # Character å
+U+5487 bì # Character å
+U+5488 fú # Character å
+#U+5489 yÄng # Character å
+U+548a hé # Character å
+#U+548b zÇ # Character å
+U+548c hé # Character å
+#U+548d hÄi # Character å
+U+548e jiù # Character å
+#U+548f yÇng # Character å
+U+5490 fu # Character å
+U+5491 què # Character å
+U+5492 zhòu # Character å
+#U+5493 wÇ # Character å
+#U+5494 kÇ # Character å
+U+5495 gu # Character å
+#U+5496 kÄ # Character å
+#U+5497 zuÇ # Character å
+U+5498 bù # Character å
+U+5499 lóng # Character å
+#U+549a dÅng # Character å
+U+549b nÃng # Character å
+U+549c ? # Character å
+#U+549d sÄ« # Character å
+U+549e xià n # Character å
+U+549f huò # Character å
+U+54a0 qì # Character å
+U+54a1 èr # Character å¡
+U+54a2 è # Character å¢
+#U+54a3 guÄng # Character å£
+U+54a4 zhà # Character å¤
+U+54a5 xì # Character å¥
+U+54a6 yà # Character å¦
+U+54a7 lie # Character å§
+#U+54a8 zÄ« # Character å¨
+#U+54a9 miÄ # Character å©
+#U+54aa mÄ« # Character åª
+#U+54ab zhÇ # Character å«
+#U+54ac yÇo # Character å¬
+#U+54ad jÄ« # Character å
+U+54ae zhòu # Character å®
+#U+54af gÄ # Character å¯
+U+54b0 shuà i # Character å°
+U+54b1 zán # Character å±
+U+54b2 xià o # Character å²
+#U+54b3 hÄi # Character å³
+#U+54b4 huÄ« # Character å´
+#U+54b5 kuÄ # Character åµ
+U+54b6 huà i # Character å¶
+U+54b7 táo # Character å·
+U+54b8 xián # Character å¸
+U+54b9 è # Character å¹
+#U+54ba xuÄn # Character åº
+#U+54bb xiÅ« # Character å»
+#U+54bc wÄi # Character å¼
+U+54bd yà n # Character å½
+#U+54be lÇo # Character å¾
+#U+54bf yÄ« # Character å¿
+#U+54c0 Äi # Character å
+#U+54c1 pÇn # Character å
+#U+54c2 shÄn # Character å
+U+54c3 tóng # Character å
+#U+54c4 hÅng # Character å
+#U+54c5 xiÅng # Character å
+#U+54c6 duÅ # Character å
+U+54c7 wa # Character å
+#U+54c8 hÄ # Character å
+#U+54c9 zÄi # Character å
+U+54ca yù # Character å
+U+54cb dì # Character å
+U+54cc pà i # Character å
+#U+54cd xiÇng # Character å
+#U+54ce Äi # Character å
+U+54cf gén # Character å
+#U+54d0 kuÄng # Character å
+#U+54d1 yÇ # Character å
+#U+54d2 dÄ # Character å
+#U+54d3 xiÄo # Character å
+U+54d4 bì # Character å
+#U+54d5 yuÄ # Character å
+U+54d6 ? # Character å
+#U+54d7 huÄ # Character å
+U+54d8 ? # Character å
+U+54d9 kuà i # Character å
+#U+54da duÇ # Character å
+U+54db ? # Character å
+U+54dc jì # Character å
+U+54dd nóng # Character å
+#U+54de mÅu # Character å
+#U+54df yÅ # Character å
+U+54e0 hà o # Character å
+U+54e1 yuán # Character å¡
+U+54e2 lòng # Character å¢
+#U+54e3 pÇu # Character å£
+U+54e4 máng # Character å¤
+#U+54e5 gÄ # Character å¥
+U+54e6 ó # Character å¦
+#U+54e7 chÄ« # Character å§
+U+54e8 shà o # Character å¨
+U+54e9 li # Character å©
+#U+54ea nÇ # Character åª
+U+54eb zú # Character å«
+U+54ec hé # Character å¬
+#U+54ed kÅ« # Character å
+#U+54ee xiÄo # Character å®
+U+54ef xià n # Character å¯
+U+54f0 láo # Character å°
+#U+54f1 bÅ # Character å±
+U+54f2 zhé # Character å²
+#U+54f3 zhÄ # Character å³
+U+54f4 lià ng # Character å´
+#U+54f5 bÄ # Character åµ
+#U+54f6 miÄ # Character å¶
+U+54f7 lè # Character å·
+#U+54f8 suÄ« # Character å¸
+U+54f9 fóu # Character å¹
+#U+54fa bÇ # Character åº
+U+54fb hà n # Character å»
+#U+54fc hÄng # Character å¼
+#U+54fd gÄng # Character å½
+#U+54fe shuÅ # Character å¾
+#U+54ff gÄ # Character å¿
diff --git a/resources/chars/latin1/row55.trans b/resources/chars/latin1/row55.trans
new file mode 100644
index 0000000..6f0f370
--- /dev/null
+++ b/resources/chars/latin1/row55.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+5500 yÇu # Character å
+U+5501 yà n # Character å
+#U+5502 gÇ # Character å
+#U+5503 gÇ # Character å
+U+5504 bei # Character å
+#U+5505 hÄn # Character å
+#U+5506 suÅ # Character å
+U+5507 chún # Character å
+U+5508 yì # Character å
+#U+5509 Äi # Character å
+U+550a jiá # Character å
+#U+550b tÇ # Character å
+U+550c xián # Character å
+#U+550d huÇn # Character å
+#U+550e lÄ« # Character å
+#U+550f xÄ« # Character å
+U+5510 táng # Character å
+U+5511 zuò # Character å
+U+5512 qiú # Character å
+#U+5513 chÄ # Character å
+U+5514 wú # Character å
+U+5515 zà o # Character å
+#U+5516 yÇ # Character å
+#U+5517 dÅu # Character å
+#U+5518 qÇ # Character å
+U+5519 dà # Character å
+U+551a qìn # Character å
+U+551b mà # Character å
+U+551c ? # Character å
+#U+551d hÇng # Character å
+#U+551e dÇu # Character å
+U+551f ? # Character å
+U+5520 láo # Character å
+#U+5521 liÇng # Character å¡
+#U+5522 suÇ # Character å¢
+U+5523 zà o # Character å£
+U+5524 huà n # Character å¤
+U+5525 ? # Character å¥
+#U+5526 shÄ # Character å¦
+#U+5527 jÄ« # Character å§
+#U+5528 zuÇ # Character å¨
+#U+5529 wÅ # Character å©
+#U+552a fÄng # Character åª
+U+552b yÃn # Character å«
+U+552c hu # Character å¬
+#U+552d qÄ« # Character å
+U+552e shòu # Character å®
+U+552f wéi # Character å¯
+#U+5530 shuÄ # Character å°
+U+5531 chà ng # Character å±
+U+5532 ér # Character å²
+U+5533 lì # Character å³
+U+5534 qià ng # Character å´
+#U+5535 Çn # Character åµ
+U+5536 jiè # Character å¶
+#U+5537 yÅ # Character å·
+U+5538 nià n # Character å¸
+#U+5539 yÅ« # Character å¹
+#U+553a tiÇn # Character åº
+#U+553b lÇi # Character å»
+U+553c shà # Character å¼
+#U+553d xÄ« # Character å½
+U+553e tuò # Character å¾
+#U+553f hÅ« # Character å¿
+U+5540 ái # Character å
+#U+5541 zhÅu # Character å
+U+5542 nòu # Character å
+#U+5543 kÄn # Character å
+U+5544 zhuó # Character å
+U+5545 zhuó # Character å
+#U+5546 shÄng # Character å
+U+5547 dà # Character å
+U+5548 hèng # Character å
+U+5549 lán # Character å
+U+554a a # Character å
+#U+554b xiÄo # Character å
+#U+554c xiÄng # Character å
+#U+554d tÅ«n # Character å
+#U+554e wÇ # Character å
+U+554f wèn # Character å
+U+5550 cuì # Character å
+U+5551 shà # Character å
+#U+5552 hÅ« # Character å
+#U+5553 qÇ # Character å
+#U+5554 qÇ # Character å
+U+5555 táo # Character å
+U+5556 dà n # Character å
+U+5557 dà n # Character å
+U+5558 yè # Character å
+#U+5559 zÇ # Character å
+#U+555a bÇ # Character å
+U+555b cuì # Character å
+U+555c chuò # Character å
+U+555d hé # Character å
+#U+555e yÇ # Character å
+#U+555f qÇ # Character å
+U+5560 zhé # Character å
+#U+5561 fÄi # Character å¡
+#U+5562 liÇng # Character å¢
+U+5563 xián # Character å£
+U+5564 pà # Character å¤
+U+5565 shà # Character å¥
+U+5566 la # Character å¦
+U+5567 zé # Character å§
+#U+5568 qÄ«ng # Character å¨
+U+5569 guà # Character å©
+#U+556a pÄ # Character åª
+#U+556b zhÄ # Character å«
+U+556c sè # Character å¬
+U+556d zhuà n # Character å
+U+556e niè # Character å®
+U+556f guo # Character å¯
+#U+5570 luÅ # Character å°
+#U+5571 yÄn # Character å±
+U+5572 dì # Character å²
+U+5573 quán # Character å³
+#U+5574 tÄn # Character å´
+U+5575 bo # Character åµ
+U+5576 dìng # Character å¶
+#U+5577 lÄng # Character å·
+U+5578 xià o # Character å¸
+U+5579 ? # Character å¹
+U+557a táng # Character åº
+U+557b chì # Character å»
+U+557c tà # Character å¼
+U+557d án # Character å½
+#U+557e jiÅ« # Character å¾
+U+557f dà n # Character å¿
+U+5580 kè # Character å
+U+5581 yóng # Character å
+U+5582 wèi # Character å
+U+5583 nán # Character å
+U+5584 shà n # Character å
+U+5585 yù # Character å
+U+5586 zhé # Character å
+#U+5587 lÇ # Character å
+#U+5588 jiÄ # Character å
+U+5589 hóu # Character å
+#U+558a hÇn # Character å
+U+558b dié # Character å
+#U+558c zhÅu # Character å
+U+558d chái # Character å
+#U+558e wÄi # Character å
+#U+558f rÄ # Character å
+U+5590 yù # Character å
+#U+5591 yÄ«n # Character å
+U+5592 zán # Character å
+#U+5593 yÄo # Character å
+#U+5594 Å # Character å
+#U+5595 miÇn # Character å
+U+5596 hú # Character å
+#U+5597 yÇn # Character å
+#U+5598 chuÇn # Character å
+U+5599 huì # Character å
+U+559a huà n # Character å
+U+559b huà n # Character å
+#U+559c xÇ # Character å
+#U+559d hÄ # Character å
+#U+559e jÄ« # Character å
+U+559f kuì # Character å
+#U+55a0 zhÇng # Character å
+#U+55a1 wÄi # Character å¡
+U+55a2 shà # Character å¢
+#U+55a3 xÇ # Character å£
+U+55a4 huáng # Character å¤
+U+55a5 dù # Character å¥
+U+55a6 niè # Character å¦
+#U+55a7 xuÇn # Character å§
+U+55a8 lià ng # Character å¨
+U+55a9 yù # Character å©
+U+55aa sà ng # Character åª
+#U+55ab chÄ« # Character å«
+U+55ac qiáo # Character å¬
+U+55ad yà n # Character å
+#U+55ae dÄn # Character å®
+#U+55af pÄn # Character å¯
+#U+55b0 cÄn # Character å°
+U+55b1 là # Character å±
+#U+55b2 yÅ # Character å²
+#U+55b3 zhÄ # Character å³
+#U+55b4 wÄi # Character å´
+#U+55b5 miÄo # Character åµ
+U+55b6 yÃng # Character å¶
+#U+55b7 pÄn # Character å·
+U+55b8 ? # Character å¸
+U+55b9 kuà # Character å¹
+U+55ba xì # Character åº
+U+55bb yù # Character å»
+U+55bc jié # Character å¼
+U+55bd lou # Character å½
+U+55be kù # Character å¾
+U+55bf sà o # Character å¿
+U+55c0 huò # Character å
+U+55c1 tà # Character å
+U+55c2 yáo # Character å
+U+55c3 hè # Character å
+U+55c4 á # Character å
+U+55c5 xiù # Character å
+#U+55c6 qiÄng # Character å
+U+55c7 sè # Character å
+#U+55c8 yÅng # Character å
+U+55c9 sù # Character å
+#U+55ca hÇng # Character å
+U+55cb xié # Character å
+U+55cc yì # Character å
+#U+55cd suÅ # Character å
+U+55ce ma # Character å
+#U+55cf chÄ # Character å
+U+55d0 hà i # Character å
+U+55d1 kè # Character å
+U+55d2 tà # Character å
+#U+55d3 sÇng # Character å
+U+55d4 tián # Character å
+U+55d5 rù # Character å
+#U+55d6 sÅu # Character å
+#U+55d7 wÄ # Character å
+#U+55d8 jÄ« # Character å
+#U+55d9 pÇng # Character å
+#U+55da wÅ« # Character å
+U+55db xián # Character å
+U+55dc shì # Character å
+U+55dd gé # Character å
+#U+55de zÄ« # Character å
+#U+55df jiÄ # Character å
+U+55e0 luò # Character å
+#U+55e1 wÄng # Character å¡
+U+55e2 wà # Character å¢
+U+55e3 sì # Character å£
+#U+55e4 chÄ« # Character å¤
+U+55e5 háo # Character å¥
+U+55e6 suo # Character å¦
+U+55e7 ? # Character å§
+#U+55e8 hÄi # Character å¨
+#U+55e9 suÇ # Character å©
+U+55ea qÃn # Character åª
+U+55eb niè # Character å«
+#U+55ec hÄ # Character å¬
+U+55ed ? # Character å
+U+55ee sà i # Character å®
+#U+55ef Å # Character å¯
+U+55f0 gè # Character å°
+U+55f1 ná # Character å±
+#U+55f2 diÇ # Character å²
+U+55f3 Ã i # Character å³
+U+55f4 ? # Character å´
+#U+55f5 tÅng # Character åµ
+U+55f6 bì # Character å¶
+U+55f7 áo # Character å·
+U+55f8 áo # Character å¸
+U+55f9 lián # Character å¹
+#U+55fa cuÄ« # Character åº
+#U+55fb zhÄ # Character å»
+U+55fc mò # Character å¼
+U+55fd sou # Character å½
+#U+55fe sÇu # Character å¾
+#U+55ff tÇn # Character å¿
diff --git a/resources/chars/latin1/row56.trans b/resources/chars/latin1/row56.trans
new file mode 100644
index 0000000..8a8a9d2
--- /dev/null
+++ b/resources/chars/latin1/row56.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+5600 dà # Character å
+#U+5601 qÄ« # Character å
+U+5602 jià o # Character å
+#U+5603 chÅng # Character å
+#U+5604 jiÄo # Character å
+#U+5605 kÇi # Character å
+U+5606 tà n # Character å
+#U+5607 sÄn # Character å
+U+5608 cáo # Character å
+#U+5609 jiÄ # Character å
+U+560a ái # Character å
+#U+560b xiÄo # Character å
+#U+560c piÄo # Character å
+U+560d lou # Character å
+#U+560e gÄ # Character å
+#U+560f gÇ # Character å
+#U+5610 xiÄo # Character å
+#U+5611 hÅ« # Character å
+U+5612 huì # Character å
+U+5613 guo # Character å
+#U+5614 Åu # Character å
+#U+5615 xiÄn # Character å
+U+5616 zé # Character å
+U+5617 cháng # Character å
+#U+5618 xÅ« # Character å
+U+5619 pó # Character å
+U+561a dé # Character å
+U+561b ma # Character å
+U+561c mà # Character å
+U+561d hú # Character å
+U+561e lei # Character å
+#U+561f dÅ« # Character å
+#U+5620 gÄ # Character å
+#U+5621 tÄng # Character å¡
+#U+5622 yÄ # Character å¢
+#U+5623 bÄng # Character å£
+#U+5624 yÄ«ng # Character å¤
+U+5625 ? # Character å¥
+U+5626 jià o # Character å¦
+#U+5627 mÄ« # Character å§
+U+5628 xià o # Character å¨
+#U+5629 huÄ # Character å©
+#U+562a mÇi # Character åª
+U+562b rán # Character å«
+#U+562c zuÅ # Character å¬
+#U+562d pÄng # Character å
+U+562e láo # Character å®
+U+562f xià o # Character å¯
+#U+5630 jÄ« # Character å°
+#U+5631 zhÇ # Character å±
+U+5632 cháo # Character å²
+U+5633 kuì # Character å³
+#U+5634 zuÇ # Character å´
+#U+5635 xiÄo # Character åµ
+#U+5636 sÄ« # Character å¶
+U+5637 háo # Character å·
+#U+5638 fÇ # Character å¸
+U+5639 liáo # Character å¹
+U+563a qiáo # Character åº
+#U+563b xÄ« # Character å»
+U+563c xiù # Character å¼
+#U+563d tÄn # Character å½
+U+563e tán # Character å¾
+#U+563f hÄi # Character å¿
+U+5640 xùn # Character å
+#U+5641 Ä # Character å
+#U+5642 zÇn # Character å
+#U+5643 fÄn # Character å
+#U+5644 chÄ« # Character å
+#U+5645 huÄ« # Character å
+#U+5646 zÇn # Character å
+U+5647 chuáng # Character å
+U+5648 cù # Character å
+U+5649 dà n # Character å
+U+564a yù # Character å
+#U+564b tÅ«n # Character å
+#U+564c chÄng # Character å
+U+564d jià o # Character å
+#U+564e yÄ # Character å
+#U+564f xÄ« # Character å
+U+5650 qì # Character å
+U+5651 háo # Character å
+U+5652 lián # Character å
+#U+5653 xÅ« # Character å
+#U+5654 dÄng # Character å
+#U+5655 huÄ« # Character å
+U+5656 yÃn # Character å
+#U+5657 pÅ« # Character å
+#U+5658 juÄ # Character å
+U+5659 qÃn # Character å
+U+565a xún # Character å
+U+565b niè # Character å
+#U+565c lÅ« # Character å
+#U+565d sÄ« # Character å
+#U+565e yÇn # Character å
+U+565f yìng # Character å
+#U+5660 dÄ # Character å
+#U+5661 dÄn # Character å¡
+#U+5662 Å # Character å¢
+U+5663 zhòu # Character å£
+U+5664 jìn # Character å¤
+U+5665 nóng # Character å¥
+#U+5666 yuÄ # Character å¦
+U+5667 huì # Character å§
+U+5668 qì # Character å¨
+U+5669 è # Character å©
+U+566a zà o # Character åª
+#U+566b yÄ« # Character å«
+U+566c shì # Character å¬
+U+566d jià o # Character å
+#U+566e yuÄn # Character å®
+U+566f à i # Character å¯
+#U+5670 yÅng # Character å°
+U+5671 jué # Character å±
+U+5672 kuà i # Character å²
+#U+5673 yÇ # Character å³
+#U+5674 pÄn # Character å´
+U+5675 dà o # Character åµ
+U+5676 gé # Character å¶
+#U+5677 xÄ«n # Character å·
+#U+5678 dÅ«n # Character å¸
+#U+5679 dÄng # Character å¹
+U+567a ? # Character åº
+U+567b sai # Character å»
+#U+567c pÄ« # Character å¼
+#U+567d pÇ # Character å½
+#U+567e yÄ«n # Character å¾
+#U+567f zuÇ # Character å¿
+U+5680 nÃng # Character å
+U+5681 dà # Character å
+U+5682 là n # Character å
+#U+5683 tÄ # Character å
+U+5684 huò # Character å
+U+5685 rú # Character å
+#U+5686 hÄo # Character å
+U+5687 xià # Character å
+U+5688 yà # Character å
+#U+5689 duÅ # Character å
+U+568a xì # Character å
+U+568b chóu # Character å
+U+568c jì # Character å
+U+568d jìn # Character å
+U+568e háo # Character å
+U+568f tì # Character å
+U+5690 cháng # Character å
+U+5691 ? # Character å
+U+5692 ? # Character å
+#U+5693 cÄ # Character å
+U+5694 tì # Character å
+#U+5695 lÅ« # Character å
+U+5696 huì # Character å
+U+5697 bó # Character å
+#U+5698 yÅu # Character å
+U+5699 niè # Character å
+U+569a yÃn # Character å
+U+569b hù # Character å
+U+569c mò # Character å
+#U+569d huÄng # Character å
+U+569e zhé # Character å
+U+569f là # Character å
+U+56a0 liú # Character å
+U+56a1 ? # Character å¡
+U+56a2 náng # Character å¢
+#U+56a3 xiÄo # Character å£
+U+56a4 mó # Character å¤
+U+56a5 yà n # Character å¥
+U+56a6 lì # Character å¦
+U+56a7 lú # Character å§
+U+56a8 lóng # Character å¨
+U+56a9 fú # Character å©
+U+56aa dà n # Character åª
+U+56ab chèn # Character å«
+U+56ac pÃn # Character å¬
+#U+56ad pÇ # Character å
+U+56ae xià ng # Character å®
+U+56af huò # Character å¯
+U+56b0 mó # Character å°
+U+56b1 xì # Character å±
+#U+56b2 duÇ # Character å²
+U+56b3 kù # Character å³
+U+56b4 yán # Character å´
+U+56b5 chán # Character åµ
+#U+56b6 yÄ«ng # Character å¶
+#U+56b7 rÇng # Character å·
+#U+56b8 diÇn # Character å¸
+#U+56b9 lÄ # Character å¹
+U+56ba tà # Character åº
+#U+56bb xiÄo # Character å»
+U+56bc jué # Character å¼
+U+56bd chuò # Character å½
+#U+56be huÄn # Character å¾
+U+56bf huò # Character å¿
+U+56c0 zhuà n # Character å
+U+56c1 niè # Character å
+#U+56c2 xiÄo # Character å
+U+56c3 cà # Character å
+U+56c4 là # Character å
+#U+56c5 chÇn # Character å
+U+56c6 chà i # Character å
+U+56c7 lì # Character å
+U+56c8 yì # Character å
+#U+56c9 luÅ # Character å
+U+56ca náng # Character å
+U+56cb zà n # Character å
+#U+56cc sÅ« # Character å
+#U+56cd xÇ # Character å
+U+56ce ? # Character å
+#U+56cf jiÄn # Character å
+U+56d0 zá # Character å
+#U+56d1 zhÇ # Character å
+U+56d2 lán # Character å
+U+56d3 niè # Character å
+#U+56d4 nÄng # Character å
+U+56d5 ? # Character å
+U+56d6 ? # Character å
+U+56d7 wéi # Character å
+U+56d8 huà # Character å
+#U+56d9 yÄ«n # Character å
+U+56da qiú # Character å
+U+56db sì # Character å
+U+56dc nÃn # Character å
+#U+56dd jiÇn # Character å
+U+56de huà # Character å
+U+56df xìn # Character å
+#U+56e0 yÄ«n # Character å
+#U+56e1 nÄn # Character å¡
+U+56e2 tuán # Character å¢
+U+56e3 tuán # Character å£
+U+56e4 dùn # Character å¤
+U+56e5 kà ng # Character å¥
+#U+56e6 yuÄn # Character å¦
+#U+56e7 jiÇng # Character å§
+#U+56e8 piÄn # Character å¨
+U+56e9 yùn # Character å©
+#U+56ea cÅng # Character åª
+U+56eb hú # Character å«
+U+56ec huà # Character å¬
+U+56ed yuán # Character å
+U+56ee yóu # Character å®
+U+56ef guó # Character å¯
+U+56f0 kùn # Character å°
+#U+56f1 cÅng # Character å±
+U+56f2 wéi # Character å²
+U+56f3 tú # Character å³
+U+56f4 wéi # Character å´
+U+56f5 lún # Character åµ
+U+56f6 guó # Character å¶
+#U+56f7 qÅ«n # Character å·
+U+56f8 rì # Character å¸
+U+56f9 lÃng # Character å¹
+U+56fa gù # Character åº
+U+56fb guó # Character å»
+#U+56fc tÄi # Character å¼
+U+56fd guó # Character å½
+U+56fe tú # Character å¾
+U+56ff yòu # Character å¿
diff --git a/resources/chars/latin1/row57.trans b/resources/chars/latin1/row57.trans
new file mode 100644
index 0000000..e9875c3
--- /dev/null
+++ b/resources/chars/latin1/row57.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+5700 guó # Character å
+U+5701 yÃn # Character å
+U+5702 hùn # Character å
+#U+5703 pÇ # Character å
+#U+5704 yÇ # Character å
+U+5705 hán # Character å
+U+5706 yuán # Character å
+U+5707 lún # Character å
+#U+5708 quÄn # Character å
+#U+5709 yÇ # Character å
+#U+570a qÄ«ng # Character å
+U+570b guó # Character å
+U+570c chuán # Character å
+U+570d wéi # Character å
+U+570e yuán # Character å
+#U+570f quÄn # Character å
+#U+5710 kÅ« # Character å
+U+5711 fù # Character å
+U+5712 yuán # Character å
+U+5713 yuán # Character å
+U+5714 è # Character å
+U+5715 ? # Character å
+U+5716 tú # Character å
+U+5717 tú # Character å
+U+5718 tuán # Character å
+U+5719 lüè # Character å
+U+571a huì # Character å
+U+571b yì # Character å
+U+571c yuán # Character å
+U+571d luán # Character å
+U+571e luán # Character å
+#U+571f tÇ # Character å
+U+5720 yà # Character å
+#U+5721 tÇ # Character å¡
+#U+5722 tÄ«ng # Character å¢
+U+5723 shèng # Character å£
+#U+5724 pÇ # Character å¤
+U+5725 lù # Character å¥
+U+5726 ? # Character å¦
+#U+5727 yÄ # Character å§
+U+5728 zà i # Character å¨
+U+5729 wéi # Character å©
+#U+572a gÄ # Character åª
+U+572b yù # Character å«
+#U+572c wÅ« # Character å¬
+#U+572d guÄ« # Character å
+#U+572e pÇ # Character å®
+U+572f yà # Character å¯
+U+5730 de # Character å°
+#U+5731 qiÄn # Character å±
+#U+5732 qiÄn # Character å²
+U+5733 zhèn # Character å³
+U+5734 zhuó # Character å´
+U+5735 dà ng # Character åµ
+U+5736 qià # Character å¶
+U+5737 ? # Character å·
+U+5738 ? # Character å¸
+U+5739 kuà ng # Character å¹
+#U+573a chÇng # Character åº
+U+573b qà # Character å»
+U+573c niè # Character å¼
+U+573d mò # Character å½
+#U+573e jÄ« # Character å¾
+U+573f jiá # Character å¿
+#U+5740 zhÇ # Character å
+#U+5741 zhÇ # Character å
+#U+5742 bÇn # Character å
+#U+5743 xÅ«n # Character å
+U+5744 tóu # Character å
+#U+5745 qÇn # Character å
+U+5746 fén # Character å
+#U+5747 jÅ«n # Character å
+#U+5748 kÄng # Character å
+U+5749 tún # Character å
+U+574a fang # Character å
+U+574b fèn # Character å
+U+574c bèn # Character å
+#U+574d tÄn # Character å
+#U+574e kÇn # Character å
+U+574f huà i # Character å
+U+5750 zuò # Character å
+#U+5751 kÄng # Character å
+U+5752 bì # Character å
+U+5753 xÃng # Character å
+U+5754 dì # Character å
+#U+5755 jÄ«ng # Character å
+U+5756 jì # Character å
+U+5757 kuà i # Character å
+#U+5758 dÇ # Character å
+#U+5759 jÄ«ng # Character å
+#U+575a jiÄn # Character å
+U+575b tán # Character å
+U+575c lì # Character å
+U+575d bà # Character å
+U+575e wù # Character å
+U+575f fén # Character å
+U+5760 zhuì # Character å
+#U+5761 pÅ # Character å¡
+#U+5762 pÇn # Character å¢
+#U+5763 tÄng # Character å£
+#U+5764 kÅ«n # Character å¤
+#U+5765 qÅ« # Character å¥
+#U+5766 tÇn # Character å¦
+#U+5767 zhÄ« # Character å§
+U+5768 tuó # Character å¨
+#U+5769 gÄn # Character å©
+U+576a pÃng # Character åª
+U+576b dià n # Character å«
+U+576c guà # Character å¬
+U+576d nà # Character å
+U+576e tái # Character å®
+#U+576f pÄ« # Character å¯
+#U+5770 jiÅng # Character å°
+#U+5771 yÇng # Character å±
+U+5772 fó # Character å²
+U+5773 Ã o # Character å³
+U+5774 liù # Character å´
+#U+5775 qiÅ« # Character åµ
+U+5776 mù # Character å¶
+#U+5777 kÄ # Character å·
+U+5778 gòu # Character å¸
+U+5779 xuè # Character å¹
+U+577a bá # Character åº
+U+577b chà # Character å»
+U+577c chè # Character å¼
+U+577d lÃng # Character å½
+U+577e zhù # Character å¾
+U+577f fù # Character å¿
+#U+5780 hÅ« # Character å
+U+5781 zhì # Character å
+U+5782 chuà # Character å
+#U+5783 lÄ # Character å
+#U+5784 lÇng # Character å
+#U+5785 lÇng # Character å
+U+5786 lú # Character å
+U+5787 Ã o # Character å
+U+5788 ? # Character å
+U+5789 páo # Character å
+U+578a ? # Character å
+U+578b xÃng # Character å
+U+578c dòng # Character å
+U+578d jì # Character å
+U+578e kè # Character å
+U+578f lù # Character å
+U+5790 cà # Character å
+#U+5791 chÇ # Character å
+#U+5792 lÄi # Character å
+#U+5793 gÄi # Character å
+#U+5794 yÄ«n # Character å
+U+5795 hòu # Character å
+#U+5796 duÄ« # Character å
+U+5797 zhà o # Character å
+U+5798 fú # Character å
+#U+5799 guÄng # Character å
+U+579a yáo # Character å
+#U+579b duÇ # Character å
+#U+579c duÇ # Character å
+#U+579d guÇ # Character å
+U+579e chá # Character å
+U+579f yáng # Character å
+U+57a0 yÃn # Character å
+U+57a1 fá # Character å¡
+U+57a2 gòu # Character å¢
+U+57a3 yuán # Character å£
+U+57a4 dié # Character å¤
+U+57a5 xié # Character å¥
+#U+57a6 kÄn # Character å¦
+#U+57a7 jiÅng # Character å§
+#U+57a8 shÇu # Character å¨
+U+57a9 è # Character å©
+U+57aa ? # Character åª
+U+57ab dià n # Character å«
+U+57ac hóng # Character å¬
+U+57ad wù # Character å
+#U+57ae kuÇ # Character å®
+U+57af ? # Character å¯
+U+57b0 ? # Character å°
+U+57b1 dà ng # Character å±
+#U+57b2 kÇi # Character å²
+U+57b3 ? # Character å³
+#U+57b4 nÇo # Character å´
+#U+57b5 Çn # Character åµ
+#U+57b6 xÄ«ng # Character å¶
+U+57b7 xià n # Character å·
+U+57b8 huà n # Character å¸
+#U+57b9 bÄng # Character å¹
+#U+57ba pÄi # Character åº
+U+57bb bà # Character å»
+U+57bc yì # Character å¼
+U+57bd yìn # Character å½
+U+57be hà n # Character å¾
+U+57bf xù # Character å¿
+U+57c0 chuà # Character å
+U+57c1 cén # Character å
+#U+57c2 gÄng # Character å
+#U+57c3 Äi # Character å
+U+57c4 péng # Character å
+U+57c5 fáng # Character å
+U+57c6 què # Character å
+#U+57c7 yÇng # Character å
+U+57c8 xùn # Character å
+U+57c9 jiá # Character å
+U+57ca dì # Character å
+U+57cb mái # Character å
+U+57cc là ng # Character å
+U+57cd xuà n # Character å
+U+57ce chéng # Character å
+U+57cf yán # Character å
+#U+57d0 jÄ«n # Character å
+U+57d1 zhé # Character å
+U+57d2 lèi # Character å
+U+57d3 liè # Character å
+U+57d4 bù # Character å
+U+57d5 chéng # Character å
+U+57d6 ? # Character å
+U+57d7 bù # Character å
+U+57d8 shà # Character å
+#U+57d9 xÅ«n # Character å
+#U+57da guÅ # Character å
+#U+57db jiÅng # Character å
+#U+57dc yÄ # Character å
+U+57dd nià n # Character å
+#U+57de dÇ # Character å
+U+57df yù # Character å
+U+57e0 bù # Character å
+U+57e1 yà # Character å¡
+#U+57e2 juÇn # Character å¢
+U+57e3 suì # Character å£
+U+57e4 pà # Character å¤
+#U+57e5 chÄng # Character å¥
+#U+57e6 wÇn # Character å¦
+U+57e7 jù # Character å§
+#U+57e8 lÇn # Character å¨
+#U+57e9 zhÄng # Character å©
+#U+57ea kÅng # Character åª
+#U+57eb chÇng # Character å«
+#U+57ec dÅng # Character å¬
+U+57ed dà i # Character å
+U+57ee tà n # Character å®
+#U+57ef Çn # Character å¯
+U+57f0 cà i # Character å°
+U+57f1 shú # Character å±
+#U+57f2 bÄng # Character å²
+#U+57f3 kÇn # Character å³
+U+57f4 zhà # Character å´
+#U+57f5 duÇ # Character åµ
+U+57f6 yì # Character å¶
+U+57f7 zhà # Character å·
+U+57f8 yì # Character å¸
+U+57f9 péi # Character å¹
+#U+57fa jÄ« # Character åº
+#U+57fb zhÇn # Character å»
+U+57fc qà # Character å¼
+U+57fd sà o # Character å½
+U+57fe jù # Character å¾
+U+57ff nà # Character å¿
diff --git a/resources/chars/latin1/row58.trans b/resources/chars/latin1/row58.trans
new file mode 100644
index 0000000..c006112
--- /dev/null
+++ b/resources/chars/latin1/row58.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+5800 kÅ« # Character å
+U+5801 kè # Character å
+U+5802 táng # Character å
+#U+5803 kÅ«n # Character å
+U+5804 nì # Character å
+#U+5805 jiÄn # Character å
+#U+5806 duÄ« # Character å
+#U+5807 jÇn # Character å
+#U+5808 gÄng # Character å
+U+5809 yù # Character å
+U+580a è # Character å
+U+580b péng # Character å
+U+580c gù # Character å
+U+580d tù # Character å
+U+580e lèng # Character å
+U+580f ? # Character å
+U+5810 yá # Character å
+U+5811 qià n # Character å
+U+5812 ? # Character å
+U+5813 Ã n # Character å
+U+5814 ? # Character å
+U+5815 duò # Character å
+#U+5816 nÇo # Character å
+#U+5817 tÅ« # Character å
+U+5818 chéng # Character å
+#U+5819 yÄ«n # Character å
+U+581a hún # Character å
+U+581b bì # Character å
+U+581c lià n # Character å
+#U+581d guÅ # Character å
+U+581e dié # Character å
+U+581f zhuà n # Character å
+U+5820 hòu # Character å
+#U+5821 bÇo # Character å ¡
+#U+5822 bÇo # Character å ¢
+U+5823 yú # Character å £
+#U+5824 dÄ« # Character å ¤
+U+5825 máo # Character å ¥
+#U+5826 jiÄ # Character å ¦
+U+5827 ruán # Character å §
+U+5828 è # Character å ¨
+U+5829 gèng # Character å ©
+#U+582a kÄn # Character å ª
+#U+582b zÅng # Character å «
+U+582c yú # Character å ¬
+U+582d huáng # Character å
+U+582e è # Character å ®
+U+582f yáo # Character å ¯
+U+5830 yà n # Character å °
+U+5831 bà o # Character å ±
+U+5832 jà # Character å ²
+U+5833 méi # Character å ³
+#U+5834 chÇng # Character å ´
+#U+5835 dÇ # Character å µ
+U+5836 tuó # Character å ¶
+U+5837 yìn # Character å ·
+U+5838 féng # Character å ¸
+U+5839 zhòng # Character å ¹
+U+583a jiè # Character å º
+#U+583b zhÄn # Character å »
+#U+583c fÄng # Character å ¼
+#U+583d gÄng # Character å ½
+#U+583e chuÇn # Character å ¾
+#U+583f jiÇn # Character å ¿
+U+5840 ? # Character å¡
+U+5841 ? # Character å¡
+U+5842 xià ng # Character å¡
+#U+5843 huÄng # Character å¡
+U+5844 léng # Character å¡
+U+5845 duà n # Character å¡
+U+5846 ? # Character å¡
+#U+5847 xuÄn # Character å¡
+U+5848 jì # Character å¡
+U+5849 jà # Character å¡
+U+584a kuà i # Character å¡
+U+584b yÃng # Character å¡
+#U+584c tÄ # Character å¡
+U+584d chéng # Character å¡
+#U+584e yÇng # Character å¡
+#U+584f kÇi # Character å¡
+U+5850 sù # Character å¡
+U+5851 sù # Character å¡
+U+5852 shà # Character å¡
+U+5853 mì # Character å¡
+#U+5854 tÇ # Character å¡
+#U+5855 wÄng # Character å¡
+U+5856 chéng # Character å¡
+U+5857 tú # Character å¡
+U+5858 táng # Character å¡
+U+5859 què # Character å¡
+#U+585a zhÇng # Character å¡
+U+585b lì # Character å¡
+U+585c péng # Character å¡
+U+585d bà ng # Character å¡
+#U+585e sÄi # Character å¡
+U+585f zà ng # Character å¡
+#U+5860 duÄ« # Character å¡
+U+5861 tián # Character 塡
+U+5862 wù # Character 塢
+#U+5863 chÄng # Character å¡£
+#U+5864 xūn # Character 塤
+U+5865 gé # Character 塥
+U+5866 zhèn # Character 塦
+U+5867 à i # Character 塧
+#U+5868 gÅng # Character 塨
+U+5869 yán # Character 塩
+#U+586a kÇn # Character 塪
+U+586b tián # Character 填
+U+586c yuán # Character 塬
+#U+586d wÄn # Character å¡
+U+586e xiè # Character 塮
+U+586f liù # Character 塯
+U+5870 ? # Character å¡°
+#U+5871 lÇng # Character 塱
+U+5872 cháng # Character 塲
+U+5873 péng # Character 塳
+U+5874 bèng # Character 塴
+U+5875 chén # Character 塵
+U+5876 cù # Character 塶
+#U+5877 lÇ # Character å¡·
+#U+5878 Çu # Character 塸
+U+5879 qià n # Character 塹
+U+587a méi # Character 塺
+U+587b mò # Character 塻
+#U+587c zhuÄn # Character 塼
+#U+587d shuÇng # Character 塽
+U+587e shú # Character 塾
+#U+587f lÇu # Character å¡¿
+U+5880 chà # Character å¢
+U+5881 mà n # Character å¢
+#U+5882 biÄo # Character å¢
+U+5883 jìng # Character å¢
+#U+5884 qÄ« # Character å¢
+U+5885 shù # Character å¢
+U+5886 dì # Character å¢
+#U+5887 zhÄng # Character å¢
+U+5888 kà n # Character å¢
+#U+5889 yÅng # Character å¢
+U+588a dià n # Character å¢
+#U+588b chÄn # Character å¢
+#U+588c zhÄ« # Character å¢
+U+588d xì # Character å¢
+#U+588e guÅ # Character å¢
+#U+588f qiÇng # Character å¢
+U+5890 jìn # Character å¢
+#U+5891 dÄ« # Character å¢
+#U+5892 shÄng # Character å¢
+U+5893 mù # Character å¢
+#U+5894 cuÄ« # Character å¢
+U+5895 yà n # Character å¢
+#U+5896 tÇ # Character å¢
+#U+5897 zÄng # Character å¢
+U+5898 qà # Character å¢
+U+5899 qiáng # Character å¢
+U+589a liáng # Character å¢
+U+589b ? # Character å¢
+U+589c zhuì # Character å¢
+#U+589d qiÄo # Character å¢
+#U+589e zÄng # Character å¢
+#U+589f xÅ« # Character å¢
+U+58a0 shà n # Character å¢
+U+58a1 shà n # Character 墡
+U+58a2 bá # Character 墢
+#U+58a3 pū # Character 墣
+U+58a4 kuà i # Character 墤
+#U+58a5 dÇng # Character 墥
+U+58a6 fán # Character 墦
+U+58a7 què # Character 墧
+U+58a8 mò # Character 墨
+#U+58a9 dūn # Character 墩
+#U+58aa dūn # Character 墪
+#U+58ab dūn # Character 墫
+U+58ac dì # Character 墬
+U+58ad shèng # Character å¢
+U+58ae duò # Character 墮
+U+58af duò # Character 墯
+U+58b0 tán # Character 墰
+U+58b1 dèng # Character 墱
+#U+58b2 wÇ # Character 墲
+U+58b3 fén # Character 墳
+U+58b4 huáng # Character 墴
+U+58b5 tán # Character 墵
+#U+58b6 dÄ # Character 墶
+U+58b7 yè # Character 墷
+U+58b8 ? # Character 墸
+U+58b9 ? # Character 墹
+U+58ba yù # Character 墺
+U+58bb qiáng # Character 墻
+#U+58bc jī # Character 墼
+#U+58bd qiÄo # Character 墽
+#U+58be kÄn # Character 墾
+U+58bf yì # Character 墿
+U+58c0 pà # Character å£
+U+58c1 bì # Character å£
+U+58c2 dià n # Character å£
+#U+58c3 jiÄng # Character å£
+#U+58c4 yÄ # Character å£
+#U+58c5 yÅng # Character å£
+U+58c6 bó # Character å£
+U+58c7 tán # Character å£
+#U+58c8 lÇn # Character å£
+U+58c9 jù # Character å£
+U+58ca huà i # Character å£
+U+58cb dà ng # Character å£
+#U+58cc rÇng # Character å£
+U+58cd qià n # Character å£
+#U+58ce xÅ«n # Character å£
+U+58cf là n # Character å£
+#U+58d0 xÇ # Character å£
+U+58d1 hè # Character å£
+U+58d2 à i # Character å£
+#U+58d3 yÄ # Character å£
+#U+58d4 dÇo # Character å£
+U+58d5 háo # Character å£
+U+58d6 ruán # Character å£
+U+58d7 ? # Character å£
+#U+58d8 lÄi # Character å£
+U+58d9 kuà ng # Character å£
+U+58da lú # Character å£
+U+58db yán # Character å£
+U+58dc tán # Character å£
+U+58dd wéi # Character å£
+U+58de huà i # Character å£
+#U+58df lÇng # Character å£
+#U+58e0 lÇng # Character å£
+U+58e1 ruì # Character 壡
+U+58e2 lì # Character 壢
+U+58e3 lÃn # Character 壣
+#U+58e4 rÇng # Character 壤
+U+58e5 ? # Character 壥
+#U+58e6 xūn # Character 壦
+U+58e7 yán # Character 壧
+U+58e8 léi # Character 壨
+U+58e9 bà # Character 壩
+U+58ea ? # Character 壪
+U+58eb shì # Character 士
+U+58ec rén # Character 壬
+U+58ed ? # Character å£
+U+58ee zhuà ng # Character 壮
+U+58ef zhuà ng # Character 壯
+#U+58f0 shÄng # Character 声
+#U+58f1 yī # Character 壱
+U+58f2 mà i # Character 売
+U+58f3 ké # Character 壳
+#U+58f4 zhÇ # Character 壴
+U+58f5 zhuà ng # Character 壵
+U+58f6 hú # Character 壶
+U+58f7 hú # Character 壷
+#U+58f8 kÇn # Character 壸
+#U+58f9 yī # Character 壹
+U+58fa hú # Character 壺
+U+58fb xù # Character 壻
+#U+58fc kÇn # Character 壼
+U+58fd shòu # Character 壽
+#U+58fe mÇng # Character 壾
+#U+58ff zÇn # Character 壿
diff --git a/resources/chars/latin1/row59.trans b/resources/chars/latin1/row59.trans
new file mode 100644
index 0000000..01ad1ee
--- /dev/null
+++ b/resources/chars/latin1/row59.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+5900 shòu # Character å¤
+#U+5901 yÄ« # Character å¤
+#U+5902 zhÇ # Character å¤
+#U+5903 gÅ« # Character å¤
+U+5904 chù # Character å¤
+U+5905 jià ng # Character å¤
+#U+5906 fÄng # Character å¤
+U+5907 bèi # Character å¤
+U+5908 ? # Character å¤
+U+5909 bià n # Character å¤
+#U+590a suÄ« # Character å¤
+#U+590b qÅ«n # Character å¤
+U+590c lÃng # Character å¤
+U+590d fù # Character å¤
+U+590e zuò # Character å¤
+U+590f xià # Character å¤
+U+5910 xiòng # Character å¤
+U+5911 ? # Character å¤
+U+5912 náo # Character å¤
+U+5913 xià # Character å¤
+U+5914 kuà # Character å¤
+#U+5915 xÄ« # Character å¤
+U+5916 wà i # Character å¤
+U+5917 yuà n # Character å¤
+#U+5918 mÇo # Character å¤
+U+5919 sù # Character å¤
+#U+591a duÅ # Character å¤
+#U+591b duÅ # Character å¤
+U+591c yè # Character å¤
+U+591d qÃng # Character å¤
+U+591e ? # Character å¤
+U+591f gòu # Character å¤
+U+5920 gòu # Character å¤
+U+5921 qì # Character 夡
+U+5922 mèng # Character 夢
+U+5923 mèng # Character 夣
+U+5924 yÃn # Character 夤
+#U+5925 huÇ # Character 夥
+U+5926 chèn # Character 夦
+U+5927 dà # Character 大
+U+5928 zè # Character 夨
+#U+5929 tiÄn # Character 天
+U+592a tà i # Character 太
+U+592b fu # Character 夫
+U+592c guà i # Character 夬
+#U+592d yÇo # Character å¤
+#U+592e yÄng # Character 央
+#U+592f hÄng # Character 夯
+#U+5930 gÇo # Character 夰
+#U+5931 shī # Character 失
+#U+5932 bÄn # Character 夲
+U+5933 tà i # Character 夳
+U+5934 tóu # Character 头
+#U+5935 yÇn # Character 夵
+#U+5936 bÇ # Character 夶
+U+5937 yà # Character 夷
+#U+5938 kuÄ # Character 夸
+#U+5939 jiÄ # Character 夹
+U+593a duó # Character 夺
+U+593b ? # Character 夻
+#U+593c kuÇng # Character 夼
+U+593d yùn # Character 夽
+#U+593e jiÄ # Character 夾
+#U+593f pÄ # Character 夿
+#U+5940 Än # Character å¥
+U+5941 lián # Character å¥
+U+5942 huà n # Character å¥
+U+5943 dì # Character å¥
+#U+5944 yÇn # Character å¥
+U+5945 pà o # Character å¥
+#U+5946 quÇn # Character å¥
+U+5947 qà # Character å¥
+U+5948 nà i # Character å¥
+U+5949 fèng # Character å¥
+U+594a xié # Character å¥
+U+594b fèn # Character å¥
+#U+594c diÇn # Character å¥
+U+594d ? # Character å¥
+U+594e kuà # Character å¥
+U+594f zòu # Character å¥
+U+5950 huà n # Character å¥
+U+5951 qì # Character å¥
+#U+5952 kÄi # Character å¥
+U+5953 zhà # Character å¥
+#U+5954 bÄn # Character å¥
+U+5955 yì # Character å¥
+#U+5956 jiÇng # Character å¥
+U+5957 tà o # Character å¥
+U+5958 zà ng # Character å¥
+#U+5959 bÄn # Character å¥
+#U+595a xÄ« # Character å¥
+#U+595b xiÇng # Character å¥
+#U+595c fÄi # Character å¥
+#U+595d diÄo # Character å¥
+U+595e xùn # Character å¥
+#U+595f kÄng # Character å¥
+U+5960 dià n # Character å¥
+U+5961 à o # Character 奡
+#U+5962 shÄ # Character 奢
+#U+5963 wÄng # Character 奣
+#U+5964 pÇn # Character 奤
+U+5965 à o # Character 奥
+U+5966 wù # Character 奦
+U+5967 à o # Character 奧
+#U+5968 jiÇng # Character 奨
+U+5969 lián # Character 奩
+U+596a duó # Character 奪
+#U+596b yūn # Character 奫
+#U+596c jiÇng # Character 奬
+U+596d shì # Character å¥
+U+596e fèn # Character 奮
+U+596f huò # Character 奯
+U+5970 bì # Character 奰
+U+5971 lián # Character 奱
+#U+5972 duÇ # Character 奲
+#U+5973 nÇ # Character 女
+U+5974 nú # Character 奴
+#U+5975 dīng # Character 奵
+#U+5976 nÇi # Character 奶
+#U+5977 qiÄn # Character 奷
+#U+5978 jiÄn # Character 奸
+#U+5979 tÄ # Character 她
+#U+597a jiÇ # Character 奺
+U+597b nán # Character 奻
+U+597c chà # Character 奼
+#U+597d hÇo # Character 好
+#U+597e xiÄn # Character 奾
+U+597f fà n # Character 奿
+#U+5980 jÇ # Character å¦
+U+5981 shuò # Character å¦
+U+5982 rú # Character å¦
+#U+5983 fÄi # Character å¦
+U+5984 wà ng # Character å¦
+U+5985 hóng # Character å¦
+#U+5986 zhuÄng # Character å¦
+U+5987 fù # Character å¦
+#U+5988 mÄ # Character å¦
+#U+5989 dÄn # Character å¦
+U+598a rèn # Character å¦
+#U+598b fÅ« # Character å¦
+U+598c jìng # Character å¦
+U+598d yán # Character å¦
+U+598e xiè # Character å¦
+U+598f wèn # Character å¦
+#U+5990 zhÅng # Character å¦
+#U+5991 pÄ # Character å¦
+U+5992 dù # Character å¦
+U+5993 jì # Character å¦
+#U+5994 kÄng # Character å¦
+U+5995 zhòng # Character å¦
+#U+5996 yÄo # Character å¦
+U+5997 jìn # Character å¦
+U+5998 yún # Character å¦
+U+5999 mià o # Character å¦
+#U+599a pÄi # Character å¦
+U+599b ? # Character å¦
+U+599c yuè # Character å¦
+#U+599d zhuÄng # Character å¦
+#U+599e niÅ« # Character å¦
+U+599f yà n # Character å¦
+U+59a0 nà # Character å¦
+#U+59a1 xīn # Character 妡
+U+59a2 fén # Character 妢
+#U+59a3 bÇ # Character 妣
+U+59a4 yú # Character 妤
+#U+59a5 tuÇ # Character 妥
+#U+59a6 fÄng # Character 妦
+U+59a7 yuán # Character 妧
+U+59a8 fáng # Character 妨
+#U+59a9 wÇ # Character 妩
+U+59aa yù # Character 妪
+#U+59ab guī # Character 妫
+U+59ac dù # Character 妬
+U+59ad bá # Character å¦
+#U+59ae nī # Character 妮
+U+59af zhóu # Character 妯
+U+59b0 zhuó # Character 妰
+#U+59b1 zhÄo # Character 妱
+U+59b2 dá # Character 妲
+#U+59b3 nÇi # Character 妳
+#U+59b4 yuÇn # Character 妴
+#U+59b5 tÇu # Character 妵
+U+59b6 xuán # Character 妶
+U+59b7 zhà # Character 妷
+#U+59b8 Ä # Character 妸
+U+59b9 mèi # Character 妹
+U+59ba mò # Character 妺
+#U+59bb qī # Character 妻
+U+59bc bì # Character 妼
+#U+59bd shÄn # Character 妽
+U+59be qiè # Character 妾
+#U+59bf Ä # Character 妿
+U+59c0 hé # Character å§
+#U+59c1 xÇ # Character å§
+U+59c2 fá # Character å§
+#U+59c3 zhÄng # Character å§
+U+59c4 mÃn # Character å§
+U+59c5 bà n # Character å§
+#U+59c6 mÇ # Character å§
+#U+59c7 fÅ« # Character å§
+U+59c8 lÃng # Character å§
+#U+59c9 zÇ # Character å§
+#U+59ca zÇ # Character å§
+#U+59cb shÇ # Character å§
+#U+59cc rÇn # Character å§
+#U+59cd shÄn # Character å§
+#U+59ce yÄng # Character å§
+U+59cf mán # Character å§
+U+59d0 jie # Character å§
+#U+59d1 gÅ« # Character å§
+U+59d2 sì # Character å§
+U+59d3 xìng # Character å§
+#U+59d4 wÄi # Character å§
+#U+59d5 zÄ« # Character å§
+U+59d6 jù # Character å§
+#U+59d7 shÄn # Character å§
+#U+59d8 pÄ«n # Character å§
+U+59d9 rèn # Character å§
+U+59da yáo # Character å§
+#U+59db tÇng # Character å§
+#U+59dc jiÄng # Character å§
+#U+59dd shÅ« # Character å§
+U+59de jà # Character å§
+#U+59df gÄi # Character å§
+U+59e0 shà ng # Character å§
+U+59e1 kuò # Character 姡
+#U+59e2 juÄn # Character 姢
+#U+59e3 jiÄo # Character 姣
+U+59e4 gòu # Character 姤
+#U+59e5 mÇ # Character 姥
+#U+59e6 jiÄn # Character 姦
+#U+59e7 jiÄn # Character 姧
+U+59e8 yà # Character 姨
+U+59e9 nià n # Character 姩
+U+59ea zhà # Character 姪
+#U+59eb jī # Character 姫
+#U+59ec jī # Character 姬
+U+59ed xià n # Character å§
+U+59ee héng # Character 姮
+#U+59ef guÄng # Character 姯
+#U+59f0 jūn # Character 姰
+#U+59f1 kuÄ # Character 姱
+U+59f2 yà n # Character 姲
+#U+59f3 mÇng # Character 姳
+U+59f4 liè # Character 姴
+U+59f5 pèi # Character 姵
+#U+59f6 yÇn # Character 姶
+U+59f7 yòu # Character 姷
+U+59f8 yán # Character 姸
+U+59f9 chà # Character 姹
+#U+59fa shÄn # Character 姺
+#U+59fb yīn # Character 姻
+#U+59fc chÇ # Character 姼
+#U+59fd guÇ # Character 姽
+#U+59fe quÄn # Character 姾
+#U+59ff zī # Character 姿
diff --git a/resources/chars/latin1/row5a.trans b/resources/chars/latin1/row5a.trans
new file mode 100644
index 0000000..726bb24
--- /dev/null
+++ b/resources/chars/latin1/row5a.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+5a00 sÅng # Character å¨
+#U+5a01 wÄi # Character å¨
+U+5a02 hóng # Character å¨
+U+5a03 wá # Character å¨
+U+5a04 lóu # Character å¨
+U+5a05 yà # Character å¨
+#U+5a06 rÇo # Character å¨
+#U+5a07 jiÄo # Character å¨
+U+5a08 luán # Character å¨
+#U+5a09 pÄ«ng # Character å¨
+U+5a0a xià n # Character å¨
+U+5a0b shà o # Character å¨
+#U+5a0c lÇ # Character å¨
+U+5a0d chéng # Character å¨
+U+5a0e xià o # Character å¨
+U+5a0f máng # Character å¨
+U+5a10 ? # Character å¨
+#U+5a11 suÅ # Character å¨
+#U+5a12 wÇ # Character å¨
+#U+5a13 wÄi # Character å¨
+U+5a14 kè # Character å¨
+U+5a15 là i # Character å¨
+U+5a16 chuò # Character å¨
+U+5a17 dìng # Character å¨
+U+5a18 niang # Character å¨
+U+5a19 xÃng # Character å¨
+U+5a1a nán # Character å¨
+U+5a1b yú # Character å¨
+U+5a1c nuó # Character å¨
+#U+5a1d pÄi # Character å¨
+#U+5a1e nÄi # Character å¨
+#U+5a1f juÄn # Character å¨
+#U+5a20 shÄn # Character å¨
+U+5a21 zhì # Character 娡
+U+5a22 hán # Character 娢
+U+5a23 dì # Character 娣
+#U+5a24 zhuÄng # Character 娤
+U+5a25 é # Character 娥
+U+5a26 pÃn # Character 娦
+U+5a27 tuì # Character 娧
+U+5a28 hà n # Character 娨
+#U+5a29 miÇn # Character 娩
+U+5a2a wú # Character 娪
+U+5a2b yán # Character 娫
+#U+5a2c wÇ # Character 娬
+#U+5a2d xÄ« # Character å¨
+U+5a2e yán # Character 娮
+U+5a2f yú # Character 娯
+U+5a30 sì # Character 娰
+U+5a31 yú # Character 娱
+#U+5a32 wÄ # Character 娲
+U+5a33 ? # Character 娳
+U+5a34 xián # Character 娴
+#U+5a35 jū # Character 娵
+#U+5a36 qÇ # Character 娶
+U+5a37 shuì # Character 娷
+#U+5a38 qī # Character 娸
+U+5a39 xián # Character 娹
+#U+5a3a zhuī # Character 娺
+#U+5a3b dÅng # Character 娻
+#U+5a3c chÄng # Character 娼
+U+5a3d lù # Character 娽
+#U+5a3e Çi # Character 娾
+#U+5a3f Ä # Character 娿
+#U+5a40 Ä # Character å©
+U+5a41 lóu # Character å©
+U+5a42 mián # Character å©
+U+5a43 cóng # Character å©
+#U+5a44 pÇu # Character å©
+U+5a45 jú # Character å©
+U+5a46 pó # Character å©
+#U+5a47 cÇi # Character å©
+U+5a48 dÃng # Character å©
+#U+5a49 wÇn # Character å©
+#U+5a4a biÇo # Character å©
+#U+5a4b xiÄo # Character å©
+#U+5a4c shÇ # Character å©
+#U+5a4d qÇ # Character å©
+#U+5a4e huÄ« # Character å©
+U+5a4f fù # Character å©
+#U+5a50 Ä # Character å©
+#U+5a51 wÇ # Character å©
+U+5a52 tán # Character å©
+#U+5a53 fÄi # Character å©
+U+5a54 ? # Character å©
+U+5a55 jié # Character å©
+#U+5a56 tiÄn # Character å©
+U+5a57 nà # Character å©
+U+5a58 quán # Character å©
+U+5a59 jìng # Character å©
+#U+5a5a hÅ«n # Character å©
+#U+5a5b jÄ«ng # Character å©
+#U+5a5c qiÄn # Character å©
+U+5a5d dià n # Character å©
+U+5a5e xìng # Character å©
+U+5a5f hù # Character å©
+U+5a60 wà # Character å©
+U+5a61 lái # Character 婡
+U+5a62 bì # Character 婢
+#U+5a63 yīn # Character 婣
+#U+5a64 chÅu # Character 婤
+U+5a65 chuò # Character 婥
+U+5a66 fù # Character 婦
+U+5a67 jìng # Character 婧
+U+5a68 lún # Character 婨
+U+5a69 yà n # Character 婩
+U+5a6a lán # Character 婪
+#U+5a6b kūn # Character 婫
+U+5a6c yÃn # Character 婬
+U+5a6d yà # Character å©
+U+5a6e ? # Character å©®
+U+5a6f lì # Character 婯
+#U+5a70 diÇn # Character å©°
+U+5a71 xián # Character 婱
+U+5a72 ? # Character 婲
+U+5a73 huà # Character 婳
+#U+5a74 yīng # Character 婴
+U+5a75 chán # Character 婵
+#U+5a76 shÄn # Character 婶
+U+5a77 tÃng # Character å©·
+U+5a78 dà ng # Character 婸
+#U+5a79 yÇo # Character 婹
+U+5a7a wù # Character 婺
+U+5a7b nà n # Character 婻
+U+5a7c ruò # Character 婼
+#U+5a7d jiÇ # Character 婽
+#U+5a7e tÅu # Character 婾
+U+5a7f xù # Character 婿
+U+5a80 yú # Character åª
+#U+5a81 wÄi # Character åª
+U+5a82 tà # Character åª
+U+5a83 róu # Character åª
+#U+5a84 mÄi # Character åª
+#U+5a85 dÄn # Character åª
+#U+5a86 ruÇn # Character åª
+#U+5a87 qÄ«n # Character åª
+U+5a88 ? # Character åª
+#U+5a89 wÅ« # Character åª
+U+5a8a qián # Character åª
+#U+5a8b chÅ«n # Character åª
+U+5a8c máo # Character åª
+U+5a8d fù # Character åª
+#U+5a8e jiÄ # Character åª
+#U+5a8f duÄn # Character åª
+#U+5a90 xÄ« # Character åª
+U+5a91 zhòng # Character åª
+U+5a92 méi # Character åª
+U+5a93 huáng # Character åª
+U+5a94 mián # Character åª
+#U+5a95 Än # Character åª
+#U+5a96 yÄ«ng # Character åª
+#U+5a97 xuÄn # Character åª
+U+5a98 ? # Character åª
+#U+5a99 wÄi # Character åª
+U+5a9a mèi # Character åª
+U+5a9b yuà n # Character åª
+#U+5a9c zhÄn # Character åª
+#U+5a9d qiÅ« # Character åª
+U+5a9e tà # Character åª
+U+5a9f xiè # Character åª
+#U+5aa0 tuÇ # Character åª
+U+5aa1 lià n # Character 媡
+U+5aa2 mà o # Character 媢
+#U+5aa3 rÇn # Character 媣
+#U+5aa4 sī # Character 媤
+#U+5aa5 piÄn # Character 媥
+U+5aa6 wèi # Character 媦
+#U+5aa7 wÄ # Character 媧
+U+5aa8 jiù # Character 媨
+U+5aa9 hú # Character 媩
+#U+5aaa Ço # Character 媪
+U+5aab ? # Character 媫
+U+5aac ? # Character 媬
+#U+5aad xÅ« # Character åª
+#U+5aae tÅu # Character 媮
+#U+5aaf guī # Character 媯
+#U+5ab0 zÅu # Character 媰
+U+5ab1 yáo # Character 媱
+U+5ab2 pì # Character 媲
+U+5ab3 xà # Character 媳
+U+5ab4 yuán # Character 媴
+U+5ab5 yìng # Character 媵
+U+5ab6 róng # Character 媶
+U+5ab7 rù # Character 媷
+#U+5ab8 chī # Character 媸
+U+5ab9 liú # Character 媹
+#U+5aba mÄi # Character 媺
+U+5abb pán # Character 媻
+#U+5abc Ço # Character 媼
+#U+5abd mÄ # Character 媽
+U+5abe gòu # Character 媾
+U+5abf kuì # Character 媿
+U+5ac0 qÃn # Character å«
+U+5ac1 jià # Character å«
+#U+5ac2 sÇo # Character å«
+#U+5ac3 zhÄn # Character å«
+U+5ac4 yuán # Character å«
+#U+5ac5 chÄ # Character å«
+U+5ac6 yóng # Character å«
+U+5ac7 mÃng # Character å«
+#U+5ac8 yÄ«ng # Character å«
+U+5ac9 jà # Character å«
+U+5aca sù # Character å«
+#U+5acb niÇo # Character å«
+U+5acc xián # Character å«
+#U+5acd tÄo # Character å«
+U+5ace páng # Character å«
+U+5acf láng # Character å«
+#U+5ad0 nÇo # Character å«
+U+5ad1 báo # Character å«
+U+5ad2 Ã i # Character å«
+U+5ad3 pì # Character å«
+U+5ad4 pÃn # Character å«
+U+5ad5 yì # Character å«
+U+5ad6 pià o # Character å«
+U+5ad7 yù # Character å«
+U+5ad8 léi # Character å«
+U+5ad9 xuán # Character å«
+U+5ada mà n # Character å«
+#U+5adb yÄ« # Character å«
+#U+5adc zhÄng # Character å«
+#U+5add kÄng # Character å«
+U+5ade yóng # Character å«
+U+5adf nì # Character å«
+U+5ae0 là # Character å«
+U+5ae1 dà # Character 嫡
+#U+5ae2 guī # Character 嫢
+#U+5ae3 yÄn # Character å«£
+U+5ae4 jìn # Character 嫤
+#U+5ae5 zhuÄn # Character å«¥
+U+5ae6 cháng # Character 嫦
+U+5ae7 cè # Character 嫧
+#U+5ae8 hÄn # Character 嫨
+U+5ae9 nèn # Character 嫩
+U+5aea là o # Character 嫪
+U+5aeb mó # Character 嫫
+#U+5aec zhÄ # Character 嫬
+U+5aed hù # Character å«
+U+5aee hù # Character 嫮
+U+5aef à o # Character 嫯
+U+5af0 nèn # Character 嫰
+U+5af1 qiáng # Character 嫱
+U+5af2 ? # Character 嫲
+U+5af3 piè # Character 嫳
+#U+5af4 gū # Character 嫴
+#U+5af5 wÇ # Character 嫵
+U+5af6 jiáo # Character 嫶
+#U+5af7 tuÇ # Character å«·
+#U+5af8 zhÇn # Character 嫸
+U+5af9 máo # Character 嫹
+U+5afa xián # Character 嫺
+U+5afb xián # Character 嫻
+U+5afc mò # Character 嫼
+U+5afd liáo # Character 嫽
+U+5afe lián # Character 嫾
+U+5aff huà # Character 嫿
diff --git a/resources/chars/latin1/row5b.trans b/resources/chars/latin1/row5b.trans
new file mode 100644
index 0000000..7eead29
--- /dev/null
+++ b/resources/chars/latin1/row5b.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+5b00 guÄ« # Character å¬
+#U+5b01 dÄng # Character å¬
+#U+5b02 zhÄ« # Character å¬
+#U+5b03 xÅ« # Character å¬
+U+5b04 ? # Character å¬
+U+5b05 huá # Character å¬
+#U+5b06 xÄ« # Character å¬
+U+5b07 huì # Character å¬
+#U+5b08 rÇo # Character å¬
+#U+5b09 xÄ« # Character å¬
+U+5b0a yà n # Character å¬
+U+5b0b chán # Character å¬
+#U+5b0c jiÄo # Character å¬
+#U+5b0d mÄi # Character å¬
+U+5b0e fà n # Character å¬
+#U+5b0f fÄn # Character å¬
+#U+5b10 xiÄn # Character å¬
+U+5b11 yì # Character å¬
+U+5b12 wèi # Character å¬
+U+5b13 jià o # Character å¬
+U+5b14 fù # Character å¬
+U+5b15 shì # Character å¬
+U+5b16 bì # Character å¬
+U+5b17 shà n # Character å¬
+U+5b18 suì # Character å¬
+U+5b19 qiáng # Character å¬
+#U+5b1a liÇn # Character å¬
+U+5b1b huán # Character å¬
+U+5b1c ? # Character å¬
+#U+5b1d niÇo # Character å¬
+#U+5b1e dÇng # Character å¬
+U+5b1f yì # Character å¬
+U+5b20 cán # Character å¬
+U+5b21 à i # Character 嬡
+U+5b22 niáng # Character 嬢
+U+5b23 néng # Character 嬣
+#U+5b24 mÄ # Character 嬤
+#U+5b25 tiÇo # Character 嬥
+U+5b26 chóu # Character 嬦
+U+5b27 jìn # Character 嬧
+U+5b28 cà # Character 嬨
+U+5b29 yú # Character 嬩
+U+5b2a pÃn # Character 嬪
+U+5b2b ? # Character 嬫
+#U+5b2c xū # Character 嬬
+#U+5b2d nÇi # Character å¬
+#U+5b2e yÄn # Character 嬮
+U+5b2f tái # Character 嬯
+#U+5b30 yīng # Character 嬰
+U+5b31 cán # Character 嬱
+#U+5b32 niÇo # Character 嬲
+U+5b33 ? # Character 嬳
+U+5b34 yÃng # Character 嬴
+U+5b35 mián # Character 嬵
+U+5b36 ? # Character 嬶
+#U+5b37 mÄ # Character 嬷
+#U+5b38 shÄn # Character 嬸
+U+5b39 xìng # Character 嬹
+U+5b3a nì # Character 嬺
+U+5b3b dú # Character 嬻
+#U+5b3c liÇ # Character 嬼
+#U+5b3d yuÄn # Character 嬽
+#U+5b3e lÇn # Character 嬾
+U+5b3f yà n # Character 嬿
+#U+5b40 shuÄng # Character å
+U+5b41 lÃng # Character å
+#U+5b42 jiÇo # Character å
+U+5b43 niáng # Character å
+#U+5b44 lÇn # Character å
+#U+5b45 xiÄn # Character å
+#U+5b46 yÄ«ng # Character å
+#U+5b47 shuÄng # Character å
+#U+5b48 shuÄi # Character å
+U+5b49 quán # Character å
+#U+5b4a mÇ # Character å
+U+5b4b là # Character å
+U+5b4c luán # Character å
+U+5b4d yán # Character å
+#U+5b4e zhÇ # Character å
+#U+5b4f lÇn # Character å
+U+5b50 zi # Character å
+U+5b51 jié # Character å
+U+5b52 jué # Character å
+U+5b53 jué # Character å
+#U+5b54 kÇng # Character å
+U+5b55 yùn # Character å
+#U+5b56 zÄ« # Character å
+U+5b57 zì # Character å
+U+5b58 cún # Character å
+#U+5b59 sÅ«n # Character å
+U+5b5a fú # Character å
+U+5b5b bèi # Character å
+#U+5b5c zÄ« # Character å
+U+5b5d xià o # Character å
+U+5b5e xìn # Character å
+U+5b5f mèng # Character å
+U+5b60 sì # Character å
+#U+5b61 tÄi # Character å¡
+#U+5b62 bÄo # Character å¢
+U+5b63 jì # Character å£
+#U+5b64 gÅ« # Character å¤
+U+5b65 nú # Character å¥
+U+5b66 xué # Character å¦
+U+5b67 ? # Character å§
+#U+5b68 zhuÇn # Character å¨
+U+5b69 hái # Character å©
+U+5b6a luán # Character åª
+#U+5b6b sÅ«n # Character å«
+U+5b6c huà i # Character å¬
+#U+5b6d miÄ # Character å
+U+5b6e cóng # Character å®
+#U+5b6f qiÄn # Character å¯
+U+5b70 shú # Character å°
+U+5b71 chán # Character å±
+#U+5b72 yÄ # Character å²
+#U+5b73 zÄ« # Character å³
+#U+5b74 nÇ # Character å´
+#U+5b75 fÅ« # Character åµ
+#U+5b76 zÄ« # Character å¶
+U+5b77 là # Character å·
+U+5b78 xué # Character å¸
+U+5b79 bò # Character å¹
+U+5b7a rú # Character åº
+U+5b7b lái # Character å»
+U+5b7c niè # Character å¼
+U+5b7d niè # Character å½
+#U+5b7e yÄ«ng # Character å¾
+U+5b7f luán # Character å¿
+U+5b80 mián # Character å®
+U+5b81 nÃng # Character å®
+#U+5b82 rÇng # Character å®
+#U+5b83 tÄ # Character å®
+#U+5b84 guÇ # Character å®
+U+5b85 zhái # Character å®
+U+5b86 qióng # Character å®
+#U+5b87 yÇ # Character å®
+#U+5b88 shÇu # Character å®
+#U+5b89 Än # Character å®
+U+5b8a tú # Character å®
+U+5b8b sòng # Character å®
+U+5b8c wán # Character å®
+U+5b8d ròu # Character å®
+#U+5b8e yÇo # Character å®
+U+5b8f hóng # Character å®
+U+5b90 yà # Character å®
+#U+5b91 jÇng # Character å®
+#U+5b92 zhÅ«n # Character å®
+U+5b93 mì # Character å®
+#U+5b94 zhÇ # Character å®
+U+5b95 dà ng # Character å®
+U+5b96 hóng # Character å®
+#U+5b97 zÅng # Character å®
+#U+5b98 guÄn # Character å®
+U+5b99 zhòu # Character å®
+U+5b9a dìng # Character å®
+#U+5b9b wÇn # Character å®
+U+5b9c yi # Character å®
+#U+5b9d bÇo # Character å®
+U+5b9e shà # Character å®
+U+5b9f shà # Character å®
+#U+5ba0 chÇng # Character å®
+#U+5ba1 shÄn # Character 审
+U+5ba2 kè # Character 客
+#U+5ba3 xuÄn # Character 宣
+U+5ba4 shì # Character 室
+U+5ba5 yòu # Character 宥
+U+5ba6 huà n # Character 宦
+U+5ba7 yà # Character 宧
+#U+5ba8 tiÇo # Character 宨
+#U+5ba9 shÇ # Character 宩
+U+5baa xià n # Character 宪
+#U+5bab gÅng # Character 宫
+U+5bac chéng # Character 宬
+U+5bad qún # Character å®
+#U+5bae gÅng # Character å®®
+#U+5baf xiÄo # Character 宯
+#U+5bb0 zÇi # Character å®°
+U+5bb1 zhà # Character 宱
+#U+5bb2 bÇo # Character 宲
+U+5bb3 hà i # Character 害
+U+5bb4 yà n # Character 宴
+#U+5bb5 xiÄo # Character 宵
+#U+5bb6 jiÄ # Character 家
+#U+5bb7 shÄn # Character å®·
+U+5bb8 chén # Character 宸
+U+5bb9 róng # Character 容
+#U+5bba huÇng # Character 宺
+U+5bbb mì # Character 宻
+U+5bbc kòu # Character 宼
+#U+5bbd kuÄn # Character 宽
+#U+5bbe bīn # Character 宾
+U+5bbf sù # Character 宿
+U+5bc0 cà i # Character å¯
+#U+5bc1 zÇn # Character å¯
+U+5bc2 jì # Character å¯
+#U+5bc3 yuÄn # Character å¯
+U+5bc4 jì # Character å¯
+U+5bc5 yÃn # Character å¯
+U+5bc6 mì # Character å¯
+U+5bc7 kòu # Character å¯
+#U+5bc8 qÄ«ng # Character å¯
+U+5bc9 què # Character å¯
+#U+5bca zhÄn # Character å¯
+#U+5bcb jiÇn # Character å¯
+U+5bcc fù # Character å¯
+U+5bcd nÃng # Character å¯
+U+5bce bìng # Character å¯
+U+5bcf huán # Character å¯
+U+5bd0 mèi # Character å¯
+#U+5bd1 qÇn # Character å¯
+U+5bd2 hán # Character å¯
+U+5bd3 yù # Character å¯
+U+5bd4 shà # Character å¯
+U+5bd5 nÃng # Character å¯
+U+5bd6 qìn # Character å¯
+U+5bd7 nÃng # Character å¯
+U+5bd8 zhì # Character å¯
+#U+5bd9 yÇ # Character å¯
+#U+5bda bÇo # Character å¯
+#U+5bdb kuÄn # Character å¯
+U+5bdc nÃng # Character å¯
+#U+5bdd qÇn # Character å¯
+U+5bde mò # Character å¯
+U+5bdf chá # Character å¯
+U+5be0 jù # Character å¯
+#U+5be1 guÇ # Character 寡
+#U+5be2 qÇn # Character 寢
+#U+5be3 hū # Character 寣
+U+5be4 wù # Character 寤
+U+5be5 liáo # Character 寥
+U+5be6 shà # Character 實
+U+5be7 nÃng # Character 寧
+U+5be8 zhà i # Character 寨
+#U+5be9 shÄn # Character 審
+#U+5bea wÄi # Character 寪
+#U+5beb xiÄ # Character 寫
+#U+5bec kuÄn # Character 寬
+U+5bed huì # Character å¯
+U+5bee liáo # Character 寮
+U+5bef jùn # Character 寯
+U+5bf0 huán # Character 寰
+U+5bf1 yì # Character 寱
+U+5bf2 yà # Character 寲
+#U+5bf3 bÇo # Character 寳
+U+5bf4 qìn # Character 寴
+#U+5bf5 chÇng # Character 寵
+#U+5bf6 bÇo # Character 寶
+#U+5bf7 fÄng # Character 寷
+U+5bf8 cùn # Character 寸
+U+5bf9 duì # Character 对
+U+5bfa sì # Character 寺
+U+5bfb xún # Character 寻
+#U+5bfc dÇo # Character 导
+#U+5bfd lÇ # Character 寽
+U+5bfe duì # Character 対
+U+5bff shòu # Character 寿
diff --git a/resources/chars/latin1/row5c.trans b/resources/chars/latin1/row5c.trans
new file mode 100644
index 0000000..f5eb4eb
--- /dev/null
+++ b/resources/chars/latin1/row5c.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+5c00 pÇ # Character å°
+#U+5c01 fÄng # Character å°
+#U+5c02 zhuÄn # Character å°
+#U+5c03 fÅ« # Character å°
+U+5c04 shè # Character å°
+U+5c05 kè # Character å°
+#U+5c06 jiÄng # Character å°
+#U+5c07 jiÄng # Character å°
+#U+5c08 zhuÄn # Character å°
+U+5c09 wèi # Character å°
+#U+5c0a zÅ«n # Character å°
+U+5c0b xún # Character å°
+U+5c0c shù # Character å°
+U+5c0d duì # Character å°
+#U+5c0e dÇo # Character å°
+#U+5c0f xiÇo # Character å°
+#U+5c10 jÄ« # Character å°
+#U+5c11 shÇo # Character å°
+#U+5c12 Är # Character å°
+#U+5c13 Är # Character å°
+#U+5c14 Är # Character å°
+#U+5c15 gÇ # Character å°
+#U+5c16 jiÄn # Character å°
+U+5c17 shú # Character å°
+U+5c18 chén # Character å°
+U+5c19 shà ng # Character å°
+U+5c1a shà ng # Character å°
+U+5c1b ? # Character å°
+U+5c1c gá # Character å°
+U+5c1d cháng # Character å°
+U+5c1e lià o # Character å°
+#U+5c1f xiÇn # Character å°
+#U+5c20 xiÇn # Character å°
+U+5c21 ? # Character å°¡
+#U+5c22 wÄng # Character å°¢
+#U+5c23 wÄng # Character å°£
+U+5c24 yóu # Character 尤
+U+5c25 lià o # Character 尥
+U+5c26 lià o # Character 尦
+U+5c27 yáo # Character 尧
+U+5c28 máng # Character 尨
+#U+5c29 wÄng # Character å°©
+#U+5c2a wÄng # Character å°ª
+#U+5c2b wÄng # Character å°«
+U+5c2c gà # Character 尬
+U+5c2d yáo # Character å°
+U+5c2e duò # Character 尮
+U+5c2f kuì # Character 尯
+#U+5c30 zhÇng # Character å°°
+U+5c31 jiù # Character 就
+#U+5c32 gÄn # Character å°²
+#U+5c33 gÇ # Character å°³
+#U+5c34 gÄn # Character å°´
+U+5c35 tuà # Character 尵
+#U+5c36 gÄn # Character å°¶
+#U+5c37 gÄn # Character å°·
+#U+5c38 shī # Character 尸
+#U+5c39 yÇn # Character å°¹
+#U+5c3a chÇ # Character å°º
+#U+5c3b kÄo # Character å°»
+U+5c3c nà # Character 尼
+#U+5c3d jÇn # Character å°½
+#U+5c3e wÄi # Character å°¾
+U+5c3f nià o # Character 尿
+U+5c40 jú # Character å±
+U+5c41 pì # Character å±
+U+5c42 céng # Character å±
+U+5c43 xì # Character å±
+#U+5c44 bÄ« # Character å±
+#U+5c45 jÅ« # Character å±
+U+5c46 jiè # Character å±
+U+5c47 tián # Character å±
+#U+5c48 qÅ« # Character å±
+U+5c49 ti # Character å±
+U+5c4a jiè # Character å±
+#U+5c4b wÅ« # Character å±
+#U+5c4c diÇo # Character å±
+#U+5c4d shÄ« # Character å±
+#U+5c4e shÇ # Character å±
+U+5c4f pÃng # Character å±
+#U+5c50 jÄ« # Character å±
+U+5c51 xiè # Character å±
+U+5c52 chén # Character å±
+U+5c53 xì # Character å±
+U+5c54 nà # Character å±
+#U+5c55 zhÇn # Character å±
+#U+5c56 xÄ« # Character å±
+U+5c57 ? # Character å±
+#U+5c58 mÇn # Character å±
+#U+5c59 Ä # Character å±
+U+5c5a lòu # Character å±
+U+5c5b pÃng # Character å±
+U+5c5c ti # Character å±
+U+5c5d fèi # Character å±
+#U+5c5e shÇ # Character å±
+U+5c5f xiè # Character å±
+U+5c60 tú # Character å±
+#U+5c61 lÇ # Character 屡
+#U+5c62 lÇ # Character å±¢
+#U+5c63 xÇ # Character å±£
+U+5c64 céng # Character 層
+#U+5c65 lÇ # Character å±¥
+U+5c66 jù # Character 屦
+U+5c67 xiè # Character 屧
+U+5c68 jù # Character 屨
+#U+5c69 juÄ # Character 屩
+U+5c6a liáo # Character 屪
+U+5c6b jué # Character 屫
+#U+5c6c shÇ # Character 屬
+U+5c6d xì # Character å±
+U+5c6e chè # Character 屮
+U+5c6f tún # Character 屯
+U+5c70 nì # Character 屰
+#U+5c71 shÄn # Character å±±
+U+5c72 ? # Character å±²
+#U+5c73 xiÄn # Character å±³
+U+5c74 lì # Character 屴
+#U+5c75 xuÄ # Character å±µ
+U+5c76 ? # Character 屶
+U+5c77 ? # Character å±·
+U+5c78 lóng # Character 屸
+U+5c79 yì # Character 屹
+#U+5c7a qÇ # Character 屺
+U+5c7b rèn # Character 屻
+U+5c7c wù # Character 屼
+U+5c7d hà n # Character 屽
+#U+5c7e shÄn # Character å±¾
+#U+5c7f yÇ # Character 屿
+#U+5c80 chÅ« # Character å²
+U+5c81 suì # Character å²
+#U+5c82 qÇ # Character å²
+U+5c83 ? # Character å²
+U+5c84 yuè # Character å²
+#U+5c85 bÇn # Character å²
+#U+5c86 yÇo # Character å²
+U+5c87 áng # Character å²
+U+5c88 yá # Character å²
+U+5c89 wù # Character å²
+U+5c8a jié # Character å²
+U+5c8b è # Character å²
+U+5c8c jà # Character å²
+#U+5c8d qiÄn # Character å²
+#U+5c8e fÄn # Character å²
+U+5c8f yuán # Character å²
+U+5c90 qà # Character å²
+U+5c91 cén # Character å²
+U+5c92 qián # Character å²
+U+5c93 qà # Character å²
+U+5c94 chà # Character å²
+U+5c95 jiè # Character å²
+#U+5c96 qÅ« # Character å²
+#U+5c97 gÇng # Character å²
+U+5c98 xià n # Character å²
+U+5c99 Ã o # Character å²
+U+5c9a lán # Character å²
+#U+5c9b dÇo # Character å²
+#U+5c9c bÄ # Character å²
+U+5c9d zuò # Character å²
+U+5c9e zuò # Character å²
+#U+5c9f yÇng # Character å²
+U+5ca0 jù # Character å²
+#U+5ca1 gÄng # Character 岡
+#U+5ca2 kÄ # Character å²¢
+#U+5ca3 gÇu # Character å²£
+U+5ca4 xuè # Character 岤
+#U+5ca5 bÄi # Character å²¥
+U+5ca6 lì # Character 岦
+U+5ca7 tiáo # Character 岧
+#U+5ca8 jū # Character 岨
+U+5ca9 yán # Character 岩
+U+5caa fú # Character 岪
+U+5cab xiù # Character 岫
+#U+5cac jiÇ # Character 岬
+#U+5cad lÇng # Character å²
+U+5cae tuó # Character 岮
+#U+5caf pÄi # Character 岯
+#U+5cb0 yÇu # Character å²°
+U+5cb1 dà i # Character 岱
+U+5cb2 kuà ng # Character 岲
+U+5cb3 yuè # Character 岳
+#U+5cb4 qū # Character 岴
+U+5cb5 hù # Character 岵
+U+5cb6 pò # Character 岶
+U+5cb7 mÃn # Character å²·
+U+5cb8 à n # Character 岸
+U+5cb9 tiáo # Character 岹
+U+5cba lÃng # Character 岺
+U+5cbb chà # Character 岻
+U+5cbc ? # Character å²¼
+#U+5cbd dÅng # Character å²½
+U+5cbe ? # Character å²¾
+#U+5cbf kuī # Character 岿
+U+5cc0 xiù # Character å³
+#U+5cc1 mÇo # Character å³
+U+5cc2 tóng # Character å³
+U+5cc3 xué # Character å³
+U+5cc4 yì # Character å³
+U+5cc5 ? # Character å³
+#U+5cc6 hÄ # Character å³
+#U+5cc7 kÄ # Character å³
+U+5cc8 luò # Character å³
+#U+5cc9 Ä # Character å³
+U+5cca fù # Character å³
+U+5ccb xún # Character å³
+U+5ccc dié # Character å³
+U+5ccd lù # Character å³
+#U+5cce Än # Character å³
+#U+5ccf Är # Character å³
+#U+5cd0 gÄi # Character å³
+U+5cd1 quán # Character å³
+U+5cd2 tóng # Character å³
+U+5cd3 yà # Character å³
+#U+5cd4 mÇ # Character å³
+U+5cd5 shà # Character å³
+#U+5cd6 Än # Character å³
+U+5cd7 wéi # Character å³
+#U+5cd8 hÅ« # Character å³
+U+5cd9 zhì # Character å³
+U+5cda mì # Character å³
+#U+5cdb lÇ # Character å³
+#U+5cdc jÄ« # Character å³
+U+5cdd tóng # Character å³
+U+5cde wéi # Character å³
+U+5cdf yòu # Character å³
+U+5ce0 ? # Character å³
+U+5ce1 xiá # Character 峡
+#U+5ce2 lÇ # Character å³¢
+U+5ce3 yáo # Character 峣
+U+5ce4 jià o # Character 峤
+#U+5ce5 zhÄng # Character å³¥
+U+5ce6 luán # Character 峦
+#U+5ce7 jiÄo # Character 峧
+U+5ce8 é # Character 峨
+U+5ce9 é # Character 峩
+U+5cea yù # Character 峪
+U+5ceb yé # Character 峫
+#U+5cec bū # Character 峬
+U+5ced qià o # Character å³
+#U+5cee qūn # Character 峮
+#U+5cef fÄng # Character 峯
+#U+5cf0 fÄng # Character å³°
+U+5cf1 náo # Character 峱
+#U+5cf2 lÇ # Character å³²
+U+5cf3 yóu # Character 峳
+U+5cf4 xià n # Character 峴
+U+5cf5 hóng # Character 峵
+#U+5cf6 dÇo # Character 島
+#U+5cf7 shÄn # Character å³·
+U+5cf8 chéng # Character 峸
+U+5cf9 tú # Character 峹
+#U+5cfa gÄng # Character 峺
+U+5cfb jùn # Character 峻
+U+5cfc hà o # Character 峼
+U+5cfd xiá # Character 峽
+#U+5cfe yīn # Character 峾
+#U+5cff yÇ # Character 峿
diff --git a/resources/chars/latin1/row5d.trans b/resources/chars/latin1/row5d.trans
new file mode 100644
index 0000000..157d35f
--- /dev/null
+++ b/resources/chars/latin1/row5d.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+5d00 là ng # Character å´
+#U+5d01 kÇn # Character å´
+U+5d02 láo # Character å´
+U+5d03 lái # Character å´
+#U+5d04 xiÇn # Character å´
+U+5d05 què # Character å´
+#U+5d06 kÅng # Character å´
+U+5d07 chóng # Character å´
+U+5d08 chóng # Character å´
+U+5d09 tà # Character å´
+U+5d0a ? # Character å´
+U+5d0b huá # Character å´
+#U+5d0c jÅ« # Character å´
+U+5d0d lái # Character å´
+U+5d0e qà # Character å´
+U+5d0f mÃn # Character å´
+#U+5d10 kÅ«n # Character å´
+#U+5d11 kÅ«n # Character å´
+U+5d12 zú # Character å´
+U+5d13 gù # Character å´
+#U+5d14 cuÄ« # Character å´
+U+5d15 yá # Character å´
+U+5d16 yá # Character å´
+#U+5d17 gÇng # Character å´
+U+5d18 lún # Character å´
+U+5d19 lún # Character å´
+U+5d1a léng # Character å´
+U+5d1b jué # Character å´
+#U+5d1c duÅ # Character å´
+#U+5d1d zhÄng # Character å´
+#U+5d1e guÅ # Character å´
+U+5d1f yÃn # Character å´
+#U+5d20 dÅng # Character å´
+U+5d21 hán # Character 崡
+#U+5d22 zhÄng # Character å´¢
+#U+5d23 wÄi # Character å´£
+U+5d24 yáo # Character 崤
+#U+5d25 pÇ # Character å´¥
+#U+5d26 yÄn # Character å´¦
+#U+5d27 sÅng # Character å´§
+U+5d28 jié # Character 崨
+#U+5d29 bÄng # Character å´©
+U+5d2a zú # Character 崪
+U+5d2b jué # Character 崫
+#U+5d2c dÅng # Character å´¬
+#U+5d2d zhÇn # Character å´
+U+5d2e gù # Character 崮
+U+5d2f yÃn # Character å´¯
+U+5d30 ? # Character å´°
+U+5d31 zé # Character 崱
+U+5d32 huáng # Character 崲
+U+5d33 yú # Character 崳
+#U+5d34 wÄi # Character å´´
+U+5d35 yáng # Character 崵
+#U+5d36 fÄng # Character å´¶
+U+5d37 qiú # Character 崷
+U+5d38 dùn # Character 崸
+U+5d39 tà # Character 崹
+#U+5d3a yÇ # Character å´º
+U+5d3b zhì # Character 崻
+U+5d3c shì # Character 崼
+#U+5d3d zÇi # Character å´½
+#U+5d3e yÇo # Character å´¾
+U+5d3f è # Character 崿
+U+5d40 zhù # Character åµ
+#U+5d41 kÄn # Character åµ
+#U+5d42 lÇ # Character åµ
+#U+5d43 yÇn # Character åµ
+#U+5d44 mÄi # Character åµ
+#U+5d45 gÄn # Character åµ
+#U+5d46 jÄ« # Character åµ
+#U+5d47 jÄ« # Character åµ
+#U+5d48 huÇn # Character åµ
+U+5d49 tÃng # Character åµ
+U+5d4a shèng # Character åµ
+U+5d4b méi # Character åµ
+U+5d4c qià n # Character åµ
+U+5d4d wù # Character åµ
+U+5d4e yú # Character åµ
+#U+5d4f zÅng # Character åµ
+U+5d50 lán # Character åµ
+U+5d51 jué # Character åµ
+U+5d52 yán # Character åµ
+U+5d53 yán # Character åµ
+#U+5d54 wÄi # Character åµ
+#U+5d55 zÅng # Character åµ
+U+5d56 chá # Character åµ
+U+5d57 suì # Character åµ
+U+5d58 róng # Character åµ
+U+5d59 ? # Character åµ
+#U+5d5a qÄ«n # Character åµ
+U+5d5b yú # Character åµ
+U+5d5c ? # Character åµ
+#U+5d5d lÇu # Character åµ
+U+5d5e tú # Character åµ
+#U+5d5f duÄ« # Character åµ
+#U+5d60 xÄ« # Character åµ
+#U+5d61 wÄng # Character 嵡
+#U+5d62 cÄng # Character åµ¢
+#U+5d63 dÄng # Character åµ£
+U+5d64 hóng # Character 嵤
+U+5d65 jié # Character 嵥
+U+5d66 ái # Character 嵦
+U+5d67 liú # Character 嵧
+#U+5d68 wÇ # Character 嵨
+#U+5d69 sÅng # Character 嵩
+#U+5d6a qiÄo # Character 嵪
+#U+5d6b zī # Character 嵫
+U+5d6c wéi # Character 嵬
+#U+5d6d bÄng # Character åµ
+#U+5d6e diÄn # Character åµ®
+U+5d6f cuó # Character 嵯
+#U+5d70 qiÇn # Character åµ°
+#U+5d71 yÇng # Character åµ±
+U+5d72 niè # Character 嵲
+U+5d73 cuó # Character 嵳
+U+5d74 jà # Character 嵴
+U+5d75 ? # Character åµµ
+U+5d76 ? # Character 嵶
+#U+5d77 sÇng # Character åµ·
+#U+5d78 zÅng # Character 嵸
+U+5d79 jià ng # Character 嵹
+U+5d7a liáo # Character 嵺
+U+5d7b ? # Character åµ»
+#U+5d7c chÇn # Character åµ¼
+U+5d7d dié # Character 嵽
+#U+5d7e cÄn # Character åµ¾
+#U+5d7f dÇng # Character 嵿
+#U+5d80 tÅ« # Character å¶
+#U+5d81 lÇu # Character å¶
+U+5d82 zhà ng # Character å¶
+#U+5d83 zhÇn # Character å¶
+#U+5d84 zhÇn # Character å¶
+U+5d85 áo # Character å¶
+U+5d86 cáo # Character å¶
+#U+5d87 qÅ« # Character å¶
+#U+5d88 qiÄng # Character å¶
+#U+5d89 zuÄ« # Character å¶
+#U+5d8a zuÇ # Character å¶
+#U+5d8b dÇo # Character å¶
+#U+5d8c dÇo # Character å¶
+U+5d8d xà # Character å¶
+U+5d8e yù # Character å¶
+U+5d8f bó # Character å¶
+U+5d90 lóng # Character å¶
+#U+5d91 xiÇng # Character å¶
+U+5d92 céng # Character å¶
+#U+5d93 bÅ # Character å¶
+#U+5d94 qÄ«n # Character å¶
+#U+5d95 jiÄo # Character å¶
+#U+5d96 yÇn # Character å¶
+U+5d97 láo # Character å¶
+U+5d98 zhà n # Character å¶
+U+5d99 lÃn # Character å¶
+U+5d9a liáo # Character å¶
+U+5d9b liáo # Character å¶
+#U+5d9c jÄ«n # Character å¶
+U+5d9d dèng # Character å¶
+U+5d9e duò # Character å¶
+#U+5d9f zÅ«n # Character å¶
+U+5da0 jià o # Character å¶
+U+5da1 guì # Character 嶡
+U+5da2 yáo # Character 嶢
+U+5da3 qiáo # Character 嶣
+U+5da4 yáo # Character 嶤
+U+5da5 jué # Character 嶥
+#U+5da6 zhÄn # Character 嶦
+U+5da7 yì # Character 嶧
+U+5da8 xué # Character 嶨
+U+5da9 náo # Character 嶩
+U+5daa yè # Character 嶪
+U+5dab yè # Character 嶫
+U+5dac yà # Character 嶬
+U+5dad è # Character å¶
+#U+5dae xiÇn # Character 嶮
+U+5daf jà # Character 嶯
+U+5db0 xiè # Character 嶰
+#U+5db1 kÄ # Character 嶱
+#U+5db2 xī # Character 嶲
+U+5db3 dì # Character 嶳
+U+5db4 à o # Character 嶴
+#U+5db5 zuÇ # Character 嶵
+U+5db6 ? # Character 嶶
+U+5db7 nì # Character 嶷
+U+5db8 róng # Character 嶸
+#U+5db9 dÇo # Character 嶹
+#U+5dba lÇng # Character 嶺
+U+5dbb zá # Character 嶻
+#U+5dbc yÇ # Character 嶼
+U+5dbd yuè # Character 嶽
+#U+5dbe yÇn # Character 嶾
+U+5dbf ? # Character 嶿
+#U+5dc0 jiÄ # Character å·
+U+5dc1 lì # Character å·
+#U+5dc2 suÇ # Character å·
+U+5dc3 lóng # Character å·
+U+5dc4 lóng # Character å·
+#U+5dc5 diÄn # Character å·
+U+5dc6 yÃng # Character å·
+#U+5dc7 xÄ« # Character å·
+U+5dc8 jú # Character å·
+U+5dc9 chán # Character å·
+#U+5dca yÇng # Character å·
+#U+5dcb kuÄ« # Character å·
+U+5dcc yán # Character å·
+#U+5dcd wÄi # Character å·
+U+5dce náo # Character å·
+U+5dcf quán # Character å·
+#U+5dd0 chÇo # Character å·
+U+5dd1 cuán # Character å·
+U+5dd2 luán # Character å·
+#U+5dd3 diÄn # Character å·
+#U+5dd4 diÄn # Character å·
+U+5dd5 ? # Character å·
+U+5dd6 yán # Character å·
+U+5dd7 yán # Character å·
+#U+5dd8 yÇn # Character å·
+U+5dd9 náo # Character å·
+#U+5dda yÇn # Character å·
+#U+5ddb chuÄn # Character å·
+U+5ddc guì # Character å·
+#U+5ddd chuÄn # Character å·
+#U+5dde zhÅu # Character å·
+#U+5ddf huÄng # Character å·
+#U+5de0 jÄ«ng # Character å·
+U+5de1 xún # Character 巡
+U+5de2 cháo # Character 巢
+U+5de3 cháo # Character 巣
+#U+5de4 liÄ # Character å·¤
+#U+5de5 gÅng # Character å·¥
+#U+5de6 zuÇ # Character å·¦
+#U+5de7 qiÇo # Character å·§
+U+5de8 jù # Character 巨
+#U+5de9 gÇng # Character å·©
+U+5dea ? # Character å·ª
+#U+5deb wū # Character 巫
+U+5dec ? # Character å·¬
+U+5ded ? # Character å·
+U+5dee chà # Character 差
+U+5def qiú # Character 巯
+U+5df0 qiú # Character 巰
+#U+5df1 jÇ # Character å·±
+#U+5df2 yÇ # Character å·²
+U+5df3 sì # Character 巳
+U+5df4 ba # Character å·´
+#U+5df5 zhī # Character 巵
+#U+5df6 zhÄo # Character å·¶
+U+5df7 xià ng # Character 巷
+U+5df8 yà # Character 巸
+#U+5df9 jÇn # Character å·¹
+U+5dfa xùn # Character 巺
+U+5dfb juà n # Character 巻
+U+5dfc ? # Character å·¼
+U+5dfd xùn # Character 巽
+#U+5dfe jīn # Character 巾
+U+5dff fú # Character 巿
diff --git a/resources/chars/latin1/row5e.trans b/resources/chars/latin1/row5e.trans
new file mode 100644
index 0000000..7c04947
--- /dev/null
+++ b/resources/chars/latin1/row5e.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+5e00 zÄ # Character å¸
+U+5e01 bì # Character å¸
+U+5e02 shì # Character å¸
+U+5e03 bù # Character å¸
+#U+5e04 dÄ«ng # Character å¸
+U+5e05 shuà i # Character å¸
+#U+5e06 fÄn # Character å¸
+U+5e07 niè # Character å¸
+#U+5e08 shÄ« # Character å¸
+#U+5e09 fÄn # Character å¸
+U+5e0a pà # Character å¸
+#U+5e0b zhÇ # Character å¸
+#U+5e0c xÄ« # Character å¸
+U+5e0d hù # Character å¸
+U+5e0e dà n # Character å¸
+U+5e0f wéi # Character å¸
+U+5e10 zhà ng # Character å¸
+#U+5e11 tÇng # Character å¸
+U+5e12 dà i # Character å¸
+U+5e13 mà # Character å¸
+U+5e14 pèi # Character å¸
+U+5e15 pà # Character å¸
+#U+5e16 tiÄ # Character å¸
+U+5e17 fú # Character å¸
+U+5e18 lián # Character å¸
+U+5e19 zhì # Character å¸
+U+5e1a zhou # Character å¸
+U+5e1b bó # Character å¸
+U+5e1c zhì # Character å¸
+U+5e1d dì # Character å¸
+U+5e1e mò # Character å¸
+U+5e1f yì # Character å¸
+U+5e20 yì # Character å¸
+U+5e21 pÃng # Character 帡
+U+5e22 qià # Character 帢
+U+5e23 juà n # Character 帣
+U+5e24 rú # Character 帤
+U+5e25 shuà i # Character 帥
+U+5e26 dà i # Character 带
+U+5e27 zhèng # Character 帧
+U+5e28 shuì # Character 帨
+U+5e29 qià o # Character 帩
+#U+5e2a zhÄn # Character 帪
+#U+5e2b shī # Character 師
+U+5e2c qún # Character 帬
+U+5e2d xà # Character å¸
+#U+5e2e bÄng # Character 帮
+U+5e2f dà i # Character 帯
+#U+5e30 guī # Character 帰
+U+5e31 chóu # Character 帱
+U+5e32 pÃng # Character 帲
+U+5e33 zhà ng # Character 帳
+#U+5e34 shÄ # Character 帴
+#U+5e35 wÄn # Character 帵
+U+5e36 dà i # Character 帶
+U+5e37 wéi # Character 帷
+U+5e38 cháng # Character 常
+U+5e39 shà # Character 帹
+U+5e3a qà # Character 帺
+U+5e3b zé # Character 帻
+U+5e3c guó # Character 帼
+U+5e3d mà o # Character 帽
+#U+5e3e dÇ # Character 帾
+U+5e3f hóu # Character 帿
+U+5e40 zhèng # Character å¹
+#U+5e41 xÅ« # Character å¹
+U+5e42 mì # Character å¹
+U+5e43 wéi # Character å¹
+U+5e44 wò # Character å¹
+U+5e45 fú # Character å¹
+U+5e46 yì # Character å¹
+#U+5e47 bÄng # Character å¹
+U+5e48 pÃng # Character å¹
+U+5e49 ? # Character å¹
+#U+5e4a gÅng # Character å¹
+U+5e4b pán # Character å¹
+#U+5e4c huÇng # Character å¹
+#U+5e4d dÄo # Character å¹
+U+5e4e mì # Character å¹
+#U+5e4f jiÄ # Character å¹
+U+5e50 téng # Character å¹
+#U+5e51 huÄ« # Character å¹
+#U+5e52 zhÅng # Character å¹
+#U+5e53 shÄn # Character å¹
+U+5e54 mà n # Character å¹
+U+5e55 mù # Character å¹
+#U+5e56 biÄo # Character å¹
+U+5e57 guó # Character å¹
+U+5e58 zé # Character å¹
+U+5e59 mù # Character å¹
+#U+5e5a bÄng # Character å¹
+U+5e5b zhà ng # Character å¹
+#U+5e5c jiÇng # Character å¹
+#U+5e5d chÇn # Character å¹
+U+5e5e fú # Character å¹
+U+5e5f zhì # Character å¹
+#U+5e60 hÅ« # Character å¹
+#U+5e61 fÄn # Character 幡
+U+5e62 chuáng # Character 幢
+U+5e63 bì # Character 幣
+U+5e64 ? # Character 幤
+U+5e65 ? # Character å¹¥
+U+5e66 mì # Character 幦
+#U+5e67 qiÄo # Character 幧
+#U+5e68 chÄn # Character 幨
+U+5e69 fén # Character 幩
+U+5e6a méng # Character 幪
+#U+5e6b bÄng # Character 幫
+U+5e6c chóu # Character 幬
+U+5e6d miè # Character å¹
+U+5e6e chú # Character 幮
+U+5e6f jié # Character 幯
+#U+5e70 xiÇn # Character å¹°
+U+5e71 lán # Character 幱
+U+5e72 gà n # Character 干
+U+5e73 pÃng # Character å¹³
+U+5e74 nián # Character 年
+#U+5e75 qiÄn # Character å¹µ
+U+5e76 bìng # Character 并
+U+5e77 bìng # Character 幷
+U+5e78 xìng # Character 幸
+U+5e79 gà n # Character 幹
+#U+5e7a yÄo # Character 幺
+U+5e7b huà n # Character 幻
+U+5e7c yòu # Character 幼
+#U+5e7d yÅu # Character å¹½
+#U+5e7e jÇ # Character å¹¾
+#U+5e7f guÇng # Character 广
+#U+5e80 pÇ # Character åº
+#U+5e81 tÄ«ng # Character åº
+U+5e82 zè # Character åº
+#U+5e83 guÇng # Character åº
+#U+5e84 zhuÄng # Character åº
+U+5e85 mo # Character åº
+U+5e86 qìng # Character åº
+U+5e87 bì # Character åº
+U+5e88 qÃn # Character åº
+U+5e89 dùn # Character åº
+U+5e8a chuáng # Character åº
+#U+5e8b guÇ # Character åº
+#U+5e8c yÇ # Character åº
+U+5e8d bà i # Character åº
+U+5e8e jiè # Character åº
+U+5e8f xù # Character åº
+U+5e90 lú # Character åº
+#U+5e91 wÇ # Character åº
+U+5e92 ? # Character åº
+U+5e93 kù # Character åº
+#U+5e94 yÄ«ng # Character åº
+#U+5e95 dÇ # Character åº
+U+5e96 páo # Character åº
+U+5e97 dià n # Character åº
+#U+5e98 yÄ # Character åº
+U+5e99 mià o # Character åº
+#U+5e9a gÄng # Character åº
+#U+5e9b cÄ« # Character åº
+#U+5e9c fÇ # Character åº
+U+5e9d tóng # Character åº
+U+5e9e páng # Character åº
+U+5e9f fèi # Character åº
+U+5ea0 xiáng # Character åº
+#U+5ea1 yÇ # Character 庡
+U+5ea2 zhì # Character 庢
+#U+5ea3 tiÄo # Character 庣
+U+5ea4 zhì # Character 庤
+#U+5ea5 xiū # Character 庥
+U+5ea6 dù # Character 度
+U+5ea7 zuò # Character 座
+#U+5ea8 xiÄo # Character 庨
+U+5ea9 tú # Character 庩
+#U+5eaa guÇ # Character 庪
+U+5eab kù # Character 庫
+U+5eac páng # Character 庬
+U+5ead tÃng # Character åº
+#U+5eae yÇu # Character 庮
+#U+5eaf bū # Character 庯
+#U+5eb0 dīng # Character 庰
+#U+5eb1 chÄng # Character 庱
+U+5eb2 lái # Character 庲
+#U+5eb3 bÄi # Character 庳
+U+5eb4 jà # Character 庴
+#U+5eb5 Än # Character 庵
+U+5eb6 shù # Character 庶
+#U+5eb7 kÄng # Character 康
+#U+5eb8 yÅng # Character 庸
+#U+5eb9 tuÇ # Character 庹
+#U+5eba sÅng # Character 庺
+U+5ebb shù # Character 庻
+#U+5ebc qÇng # Character 庼
+U+5ebd yù # Character 庽
+#U+5ebe yÇ # Character 庾
+U+5ebf mià o # Character 庿
+#U+5ec0 sÅu # Character å»
+U+5ec1 cè # Character å»
+#U+5ec2 xiÄng # Character å»
+U+5ec3 fèi # Character å»
+U+5ec4 jiù # Character å»
+U+5ec5 hé # Character å»
+U+5ec6 huì # Character å»
+U+5ec7 liù # Character å»
+U+5ec8 shà # Character å»
+U+5ec9 lián # Character å»
+U+5eca láng # Character å»
+#U+5ecb sÅu # Character å»
+U+5ecc zhì # Character å»
+#U+5ecd pÇu # Character å»
+#U+5ece qÇng # Character å»
+U+5ecf jiù # Character å»
+U+5ed0 jiù # Character å»
+U+5ed1 qÃn # Character å»
+U+5ed2 áo # Character å»
+U+5ed3 kuò # Character å»
+U+5ed4 lóu # Character å»
+#U+5ed5 yÄ«n # Character å»
+U+5ed6 lià o # Character å»
+U+5ed7 dà i # Character å»
+U+5ed8 lù # Character å»
+U+5ed9 yì # Character å»
+U+5eda chú # Character å»
+U+5edb chán # Character å»
+#U+5edc tÅ« # Character å»
+#U+5edd sÄ« # Character å»
+#U+5ede xÄ«n # Character å»
+U+5edf mià o # Character å»
+#U+5ee0 chÇng # Character å»
+#U+5ee1 wÇ # Character 廡
+U+5ee2 fèi # Character 廢
+#U+5ee3 guÇng # Character 廣
+U+5ee4 ? # Character 廤
+U+5ee5 kuà i # Character 廥
+U+5ee6 bì # Character 廦
+U+5ee7 qiáng # Character 廧
+U+5ee8 xiè # Character 廨
+#U+5ee9 lÇn # Character 廩
+#U+5eea lÇn # Character 廪
+U+5eeb liáo # Character 廫
+U+5eec lú # Character 廬
+U+5eed ? # Character å»
+U+5eee yÃng # Character å»®
+#U+5eef xiÄn # Character 廯
+#U+5ef0 tīng # Character 廰
+#U+5ef1 yÅng # Character å»±
+U+5ef2 là # Character 廲
+#U+5ef3 tīng # Character 廳
+#U+5ef4 yÇn # Character å»´
+U+5ef5 xún # Character 廵
+U+5ef6 yán # Character 延
+U+5ef7 tÃng # Character å»·
+U+5ef8 dà # Character 廸
+U+5ef9 pò # Character 廹
+U+5efa jià n # Character 建
+U+5efb huà # Character 廻
+#U+5efc nÇi # Character 廼
+U+5efd huà # Character 廽
+U+5efe gòng # Character 廾
+U+5eff nià n # Character 廿
diff --git a/resources/chars/latin1/row5f.trans b/resources/chars/latin1/row5f.trans
new file mode 100644
index 0000000..f34975e
--- /dev/null
+++ b/resources/chars/latin1/row5f.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+5f00 kÄi # Character å¼
+U+5f01 bià n # Character å¼
+U+5f02 yì # Character å¼
+U+5f03 qì # Character å¼
+U+5f04 nòng # Character å¼
+U+5f05 fén # Character å¼
+#U+5f06 jÇ # Character å¼
+#U+5f07 yÇn # Character å¼
+U+5f08 yì # Character å¼
+U+5f09 zà ng # Character å¼
+U+5f0a bì # Character å¼
+U+5f0b yì # Character å¼
+#U+5f0c yÄ« # Character å¼
+U+5f0d èr # Character å¼
+#U+5f0e sÄn # Character å¼
+U+5f0f shì # Character å¼
+U+5f10 èr # Character å¼
+U+5f11 shì # Character å¼
+U+5f12 shì # Character å¼
+#U+5f13 gÅng # Character å¼
+U+5f14 dià o # Character å¼
+#U+5f15 yÇn # Character å¼
+U+5f16 hù # Character å¼
+U+5f17 fú # Character å¼
+U+5f18 hóng # Character å¼
+#U+5f19 wÅ« # Character å¼
+U+5f1a tuà # Character å¼
+U+5f1b chà # Character å¼
+U+5f1c jià ng # Character å¼
+U+5f1d bà # Character å¼
+#U+5f1e shÄn # Character å¼
+U+5f1f dì # Character å¼
+#U+5f20 zhÄng # Character å¼
+U+5f21 jué # Character 弡
+#U+5f22 tÄo # Character å¼¢
+#U+5f23 fÇ # Character å¼£
+#U+5f24 dÇ # Character 弤
+U+5f25 mà # Character 弥
+U+5f26 xián # Character 弦
+U+5f27 hú # Character 弧
+#U+5f28 chÄo # Character 弨
+#U+5f29 nÇ # Character 弩
+U+5f2a jìng # Character 弪
+#U+5f2b zhÄn # Character 弫
+U+5f2c yà # Character 弬
+#U+5f2d mÇ # Character å¼
+#U+5f2e quÄn # Character å¼®
+#U+5f2f wÄn # Character 弯
+#U+5f30 shÄo # Character å¼°
+U+5f31 ruò # Character 弱
+#U+5f32 xuÄn # Character å¼²
+U+5f33 jìng # Character 弳
+#U+5f34 dūn # Character 弴
+#U+5f35 zhÄng # Character å¼µ
+U+5f36 jià ng # Character 弶
+U+5f37 qiáng # Character 強
+U+5f38 péng # Character 弸
+U+5f39 dà n # Character 弹
+U+5f3a qiáng # Character 强
+U+5f3b bì # Character 弻
+U+5f3c bì # Character 弼
+U+5f3d shè # Character 弽
+U+5f3e dà n # Character 弾
+#U+5f3f jiÇn # Character 弿
+U+5f40 gòu # Character å½
+U+5f41 ? # Character å½
+#U+5f42 fÄ # Character å½
+U+5f43 bì # Character å½
+#U+5f44 kÅu # Character å½
+U+5f45 ? # Character å½
+U+5f46 biè # Character å½
+#U+5f47 xiÄo # Character å½
+U+5f48 dà n # Character å½
+U+5f49 kuò # Character å½
+U+5f4a qiáng # Character å½
+U+5f4b hóng # Character å½
+U+5f4c mà # Character å½
+U+5f4d kuò # Character å½
+#U+5f4e wÄn # Character å½
+U+5f4f jué # Character å½
+U+5f50 jì # Character å½
+U+5f51 jì # Character å½
+#U+5f52 guÄ« # Character å½
+#U+5f53 dÄng # Character å½
+U+5f54 lù # Character å½
+U+5f55 lù # Character å½
+U+5f56 tuà n # Character å½
+U+5f57 huì # Character å½
+U+5f58 zhì # Character å½
+U+5f59 huì # Character å½
+U+5f5a huì # Character å½
+U+5f5b yà # Character å½
+U+5f5c yà # Character å½
+U+5f5d yà # Character å½
+U+5f5e yà # Character å½
+U+5f5f huò # Character å½
+U+5f60 huò # Character å½
+#U+5f61 shÄn # Character 彡
+U+5f62 xÃng # Character å½¢
+U+5f63 wén # Character 彣
+U+5f64 tóng # Character 彤
+U+5f65 yà n # Character 彥
+U+5f66 yà n # Character 彦
+U+5f67 yù # Character 彧
+#U+5f68 chī # Character 彨
+#U+5f69 cÇi # Character 彩
+#U+5f6a biÄo # Character 彪
+#U+5f6b diÄo # Character 彫
+#U+5f6c bīn # Character 彬
+U+5f6d péng # Character å½
+#U+5f6e yÇng # Character å½®
+#U+5f6f piÄo # Character 彯
+#U+5f70 zhÄng # Character å½°
+#U+5f71 yÇng # Character å½±
+#U+5f72 chī # Character 彲
+U+5f73 chì # Character 彳
+U+5f74 zhuó # Character 彴
+#U+5f75 tuÇ # Character å½µ
+U+5f76 jà # Character 彶
+U+5f77 páng # Character 彷
+#U+5f78 zhÅng # Character 彸
+U+5f79 yì # Character 役
+U+5f7a wáng # Character 彺
+U+5f7b chè # Character 彻
+#U+5f7c bÇ # Character å½¼
+U+5f7d chà # Character 彽
+#U+5f7e lÇng # Character å½¾
+U+5f7f fú # Character 彿
+#U+5f80 wÇng # Character å¾
+#U+5f81 zhÄng # Character å¾
+U+5f82 cú # Character å¾
+#U+5f83 wÇng # Character å¾
+U+5f84 jìng # Character å¾
+U+5f85 dà i # Character å¾
+#U+5f86 xÄ« # Character å¾
+U+5f87 xùn # Character å¾
+#U+5f88 hÄn # Character å¾
+U+5f89 yáng # Character å¾
+U+5f8a huái # Character å¾
+#U+5f8b lÇ # Character å¾
+U+5f8c hòu # Character å¾
+#U+5f8d wÄ # Character å¾
+#U+5f8e chÄng # Character å¾
+U+5f8f zhì # Character å¾
+U+5f90 xú # Character å¾
+U+5f91 jìng # Character å¾
+U+5f92 tú # Character å¾
+U+5f93 cóng # Character å¾
+U+5f94 ? # Character å¾
+U+5f95 lái # Character å¾
+U+5f96 cóng # Character å¾
+U+5f97 de # Character å¾
+U+5f98 pái # Character å¾
+#U+5f99 xÇ # Character å¾
+U+5f9a ? # Character å¾
+U+5f9b qì # Character å¾
+U+5f9c cháng # Character å¾
+U+5f9d zhì # Character å¾
+U+5f9e cóng # Character å¾
+#U+5f9f zhÅu # Character å¾
+U+5fa0 lái # Character å¾
+U+5fa1 yù # Character 御
+U+5fa2 xiè # Character 徢
+U+5fa3 jiè # Character 徣
+U+5fa4 jià n # Character 徤
+U+5fa5 chà # Character 徥
+#U+5fa6 jiÇ # Character 徦
+U+5fa7 bià n # Character 徧
+U+5fa8 huáng # Character 徨
+U+5fa9 fù # Character 復
+U+5faa xún # Character 循
+#U+5fab wÄi # Character 徫
+U+5fac páng # Character 徬
+U+5fad yáo # Character å¾
+#U+5fae wÄi # Character å¾®
+#U+5faf xī # Character 徯
+#U+5fb0 zhÄng # Character å¾°
+U+5fb1 pià o # Character 徱
+U+5fb2 chà # Character 徲
+U+5fb3 dé # Character 徳
+#U+5fb4 zhÄng # Character å¾´
+#U+5fb5 zhÄng # Character å¾µ
+U+5fb6 biè # Character 徶
+U+5fb7 dé # Character 德
+#U+5fb8 chÅng # Character 徸
+U+5fb9 chè # Character 徹
+#U+5fba jiÇo # Character 徺
+U+5fbb wèi # Character 徻
+U+5fbc jià o # Character 徼
+#U+5fbd huī # Character 徽
+U+5fbe méi # Character 徾
+U+5fbf lòng # Character 徿
+#U+5fc0 xiÄng # Character å¿
+U+5fc1 bà o # Character å¿
+U+5fc2 qú # Character å¿
+#U+5fc3 xÄ«n # Character å¿
+U+5fc4 ? # Character å¿
+U+5fc5 bì # Character å¿
+U+5fc6 yì # Character å¿
+U+5fc7 lè # Character å¿
+U+5fc8 rén # Character å¿
+#U+5fc9 dÄo # Character å¿
+U+5fca dìng # Character å¿
+#U+5fcb gÇi # Character å¿
+U+5fcc jì # Character å¿
+#U+5fcd rÄn # Character å¿
+U+5fce rén # Character å¿
+U+5fcf chà n # Character å¿
+#U+5fd0 tÇn # Character å¿
+U+5fd1 tè # Character å¿
+U+5fd2 tè # Character å¿
+#U+5fd3 gÄn # Character å¿
+U+5fd4 qì # Character å¿
+U+5fd5 shì # Character å¿
+#U+5fd6 cÇn # Character å¿
+U+5fd7 zhì # Character å¿
+U+5fd8 wà ng # Character å¿
+U+5fd9 máng # Character å¿
+#U+5fda xÄ« # Character å¿
+U+5fdb fán # Character å¿
+#U+5fdc yÄ«ng # Character å¿
+#U+5fdd tiÇn # Character å¿
+U+5fde mÃn # Character å¿
+U+5fdf mÃn # Character å¿
+#U+5fe0 zhÅng # Character å¿
+#U+5fe1 chÅng # Character å¿¡
+U+5fe2 wù # Character 忢
+U+5fe3 jà # Character 忣
+#U+5fe4 wÇ # Character 忤
+U+5fe5 xì # Character 忥
+U+5fe6 yè # Character 忦
+#U+5fe7 yÅu # Character 忧
+U+5fe8 wà n # Character 忨
+#U+5fe9 cÅng # Character å¿©
+#U+5fea zhÅng # Character 忪
+U+5feb kuà i # Character 快
+U+5fec yù # Character 忬
+U+5fed bià n # Character å¿
+U+5fee zhì # Character 忮
+U+5fef qà # Character 忯
+U+5ff0 cuì # Character 忰
+U+5ff1 chén # Character 忱
+U+5ff2 tà i # Character 忲
+U+5ff3 tún # Character 忳
+U+5ff4 qián # Character 忴
+U+5ff5 nià n # Character 念
+U+5ff6 hún # Character 忶
+#U+5ff7 xiÅng # Character å¿·
+#U+5ff8 niÇ # Character 忸
+#U+5ff9 wÇng # Character 忹
+#U+5ffa xiÄn # Character 忺
+#U+5ffb xīn # Character 忻
+#U+5ffc kÄng # Character 忼
+#U+5ffd hū # Character 忽
+U+5ffe kà i # Character 忾
+U+5fff fèn # Character 忿
diff --git a/resources/chars/latin1/row60.trans b/resources/chars/latin1/row60.trans
new file mode 100644
index 0000000..f8da915
--- /dev/null
+++ b/resources/chars/latin1/row60.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+6000 huái # Character æ
+U+6001 tà i # Character æ
+#U+6002 sÇng # Character æ
+#U+6003 wÇ # Character æ
+U+6004 òu # Character æ
+U+6005 chà ng # Character æ
+U+6006 chuà ng # Character æ
+U+6007 jù # Character æ
+U+6008 yì # Character æ
+#U+6009 bÇo # Character æ
+#U+600a chÄo # Character æ
+U+600b mÃn # Character æ
+#U+600c pÄi # Character æ
+U+600d zuò # Character æ
+#U+600e zÄn # Character æ
+U+600f yà ng # Character æ
+U+6010 kòu # Character æ
+U+6011 bà n # Character æ
+U+6012 nù # Character æ
+U+6013 náo # Character æ
+#U+6014 zhÄng # Character æ
+U+6015 pà # Character æ
+U+6016 bù # Character æ
+#U+6017 tiÄ # Character æ
+U+6018 gù # Character æ
+U+6019 hù # Character æ
+U+601a jù # Character æ
+U+601b dá # Character æ
+U+601c lián # Character æ
+#U+601d sÄ« # Character æ
+#U+601e chÅu # Character æ
+U+601f dì # Character æ
+U+6020 dà i # Character æ
+U+6021 yà # Character æ¡
+U+6022 tú # Character æ¢
+U+6023 yóu # Character æ£
+#U+6024 fÅ« # Character æ¤
+U+6025 jà # Character æ¥
+#U+6026 pÄng # Character æ¦
+U+6027 xìng # Character æ§
+U+6028 yuà n # Character æ¨
+U+6029 nà # Character æ©
+U+602a guà i # Character æª
+U+602b fú # Character æ«
+U+602c xì # Character æ¬
+U+602d bì # Character æ
+#U+602e yÅu # Character æ®
+U+602f qiè # Character æ¯
+U+6030 xuà n # Character æ°
+#U+6031 cÅng # Character æ±
+#U+6032 bÇng # Character æ²
+#U+6033 huÇng # Character æ³
+U+6034 xù # Character æ´
+U+6035 chù # Character æµ
+#U+6036 pÄ« # Character æ¶
+#U+6037 xÄ« # Character æ·
+#U+6038 xÄ« # Character æ¸
+#U+6039 tÄn # Character æ¹
+U+603a ? # Character æº
+#U+603b zÇng # Character æ»
+U+603c duì # Character æ¼
+U+603d ? # Character æ½
+U+603e ? # Character æ¾
+U+603f yì # Character æ¿
+#U+6040 chÇ # Character æ
+U+6041 rèn # Character æ
+U+6042 xún # Character æ
+U+6043 shì # Character æ
+U+6044 xì # Character æ
+#U+6045 lÇo # Character æ
+U+6046 héng # Character æ
+#U+6047 kuÄng # Character æ
+U+6048 mú # Character æ
+#U+6049 zhÇ # Character æ
+U+604a xié # Character æ
+U+604b lià n # Character æ
+#U+604c tiÄo # Character æ
+#U+604d huÇng # Character æ
+U+604e dié # Character æ
+#U+604f hÇo # Character æ
+#U+6050 kÇng # Character æ
+#U+6051 guÇ # Character æ
+U+6052 héng # Character æ
+#U+6053 xÄ« # Character æ
+U+6054 xià o # Character æ
+U+6055 shù # Character æ
+U+6056 ? # Character æ
+#U+6057 kuÇ # Character æ
+#U+6058 qiÅ« # Character æ
+U+6059 yà ng # Character æ
+U+605a huì # Character æ
+U+605b huà # Character æ
+U+605c chì # Character æ
+U+605d jiá # Character æ
+U+605e yà # Character æ
+#U+605f xiÅng # Character æ
+U+6060 guà i # Character æ
+U+6061 lìn # Character æ¡
+#U+6062 huÄ« # Character æ¢
+U+6063 zì # Character æ£
+U+6064 xù # Character æ¤
+#U+6065 chÇ # Character æ¥
+U+6066 xià ng # Character æ¦
+#U+6067 nÇ # Character æ§
+U+6068 hèn # Character æ¨
+#U+6069 Än # Character æ©
+U+606a kè # Character æª
+#U+606b tÅng # Character æ«
+U+606c tián # Character æ¬
+#U+606d gÅng # Character æ
+U+606e quán # Character æ®
+U+606f xi # Character æ¯
+U+6070 qià # Character æ°
+U+6071 yuè # Character æ±
+#U+6072 pÄng # Character æ²
+#U+6073 kÄn # Character æ³
+U+6074 dé # Character æ´
+U+6075 huì # Character æµ
+U+6076 è # Character æ¶
+U+6077 ? # Character æ·
+U+6078 tòng # Character æ¸
+U+6079 yà n # Character æ¹
+#U+607a kÇi # Character æº
+U+607b cè # Character æ»
+#U+607c nÇo # Character æ¼
+U+607d yùn # Character æ½
+U+607e máng # Character æ¾
+#U+607f yÇng # Character æ¿
+#U+6080 yÇng # Character æ
+#U+6081 yuÄn # Character æ
+#U+6082 pÄ« # Character æ
+#U+6083 kÇn # Character æ
+#U+6084 qiÄo # Character æ
+U+6085 yuè # Character æ
+U+6086 yù # Character æ
+U+6087 yù # Character æ
+U+6088 jiè # Character æ
+#U+6089 xÄ« # Character æ
+U+608a zhé # Character æ
+U+608b lìn # Character æ
+U+608c tì # Character æ
+U+608d hà n # Character æ
+U+608e hà o # Character æ
+U+608f qiè # Character æ
+U+6090 tì # Character æ
+U+6091 bù # Character æ
+U+6092 yì # Character æ
+U+6093 qià n # Character æ
+#U+6094 huÇ # Character æ
+#U+6095 xÄ« # Character æ
+U+6096 bèi # Character æ
+U+6097 mán # Character æ
+#U+6098 yÄ« # Character æ
+#U+6099 hÄng # Character æ
+#U+609a sÇng # Character æ
+#U+609b quÄn # Character æ
+#U+609c chÄng # Character æ
+#U+609d huÄ« # Character æ
+U+609e wù # Character æ
+U+609f wù # Character æ
+#U+60a0 yÅu # Character æ
+U+60a1 là # Character æ¡
+U+60a2 lià ng # Character æ¢
+U+60a3 huà n # Character æ£
+#U+60a4 cÅng # Character æ¤
+U+60a5 yì # Character æ¥
+U+60a6 yuè # Character æ¦
+U+60a7 lì # Character æ§
+U+60a8 nÃn # Character æ¨
+#U+60a9 nÇo # Character æ©
+U+60aa è # Character æª
+U+60ab què # Character æ«
+U+60ac xuán # Character æ¬
+#U+60ad qiÄn # Character æ
+U+60ae wù # Character æ®
+#U+60af mÇn # Character æ¯
+U+60b0 cóng # Character æ°
+#U+60b1 fÄi # Character æ±
+#U+60b2 bÄi # Character æ²
+U+60b3 duó # Character æ³
+U+60b4 cuì # Character æ´
+U+60b5 chà ng # Character æµ
+U+60b6 mèn # Character æ¶
+U+60b7 lì # Character æ·
+U+60b8 jì # Character æ¸
+U+60b9 guà n # Character æ¹
+U+60ba guà n # Character æº
+U+60bb xìng # Character æ»
+U+60bc dà o # Character æ¼
+#U+60bd qÄ« # Character æ½
+#U+60be kÅng # Character æ¾
+#U+60bf tiÇn # Character æ¿
+U+60c0 lún # Character æ
+#U+60c1 xÄ« # Character æ
+#U+60c2 kÇn # Character æ
+#U+60c3 kÅ«n # Character æ
+U+60c4 nì # Character æ
+U+60c5 qÃng # Character æ
+U+60c6 chóu # Character æ
+#U+60c7 dÅ«n # Character æ
+#U+60c8 guÇ # Character æ
+#U+60c9 chÄn # Character æ
+#U+60ca jÄ«ng # Character æ
+#U+60cb wÇn # Character æ
+#U+60cc yuÄn # Character æ
+#U+60cd jÄ«n # Character æ
+U+60ce jì # Character æ
+U+60cf lÃn # Character æ
+U+60d0 yù # Character æ
+U+60d1 huò # Character æ
+U+60d2 hé # Character æ
+U+60d3 quán # Character æ
+U+60d4 tán # Character æ
+U+60d5 tì # Character æ
+U+60d6 tì # Character æ
+#U+60d7 niÄ # Character æ
+#U+60d8 wÇng # Character æ
+U+60d9 chuò # Character æ
+#U+60da hÅ« # Character æ
+#U+60db hÅ«n # Character æ
+#U+60dc xÄ« # Character æ
+#U+60dd tÇng # Character æ
+#U+60de xÄ«n # Character æ
+U+60df wéi # Character æ
+U+60e0 huì # Character æ
+U+60e1 è # Character æ¡
+#U+60e2 ruÇ # Character æ¢
+#U+60e3 zÇng # Character æ£
+#U+60e4 jiÄn # Character æ¤
+#U+60e5 yÇng # Character æ¥
+U+60e6 dià n # Character æ¦
+U+60e7 jù # Character æ§
+#U+60e8 cÇn # Character æ¨
+U+60e9 chéng # Character æ©
+U+60ea dé # Character æª
+U+60eb bèi # Character æ«
+U+60ec qiè # Character æ¬
+U+60ed cán # Character æ
+U+60ee dà n # Character æ®
+U+60ef guà n # Character æ¯
+U+60f0 duò # Character æ°
+#U+60f1 nÇo # Character æ±
+U+60f2 yùn # Character æ²
+#U+60f3 xiÇng # Character æ³
+U+60f4 zhuì # Character æ´
+U+60f5 diè # Character æµ
+U+60f6 huáng # Character æ¶
+#U+60f7 chÇn # Character æ·
+U+60f8 qióng # Character æ¸
+#U+60f9 rÄ # Character æ¹
+#U+60fa xÄ«ng # Character æº
+U+60fb cè # Character æ»
+#U+60fc biÇn # Character æ¼
+#U+60fd hÅ«n # Character æ½
+#U+60fe zÅng # Character æ¾
+U+60ff tà # Character æ¿
diff --git a/resources/chars/latin1/row61.trans b/resources/chars/latin1/row61.trans
new file mode 100644
index 0000000..7b80de0
--- /dev/null
+++ b/resources/chars/latin1/row61.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+6100 qiÇo # Character æ
+U+6101 chóu # Character æ
+U+6102 bèi # Character æ
+#U+6103 xuÄn # Character æ
+#U+6104 wÄi # Character æ
+U+6105 gé # Character æ
+#U+6106 qiÄn # Character æ
+#U+6107 wÄi # Character æ
+U+6108 yù # Character æ
+U+6109 yú # Character æ
+U+610a bì # Character æ
+#U+610b xuÄn # Character æ
+U+610c huà n # Character æ
+#U+610d mÇn # Character æ
+U+610e bì # Character æ
+U+610f yì # Character æ
+#U+6110 miÇn # Character æ
+#U+6111 yÇng # Character æ
+U+6112 kà i # Character æ
+U+6113 dà ng # Character æ
+#U+6114 yÄ«n # Character æ
+U+6115 è # Character æ
+U+6116 chén # Character æ
+U+6117 mòu # Character æ
+U+6118 kè # Character æ
+U+6119 kè # Character æ
+U+611a yú # Character æ
+U+611b à i # Character æ
+U+611c qiè # Character æ
+#U+611d yÇn # Character æ
+U+611e nuò # Character æ
+#U+611f gÇn # Character æ
+U+6120 yùn # Character æ
+#U+6121 zÇng # Character æ¡
+#U+6122 sÄi # Character æ¢
+U+6123 lèng # Character æ£
+U+6124 fèn # Character æ¤
+U+6125 ? # Character æ¥
+U+6126 kuì # Character æ¦
+U+6127 kuì # Character æ§
+U+6128 què # Character æ¨
+#U+6129 gÅng # Character æ©
+U+612a yún # Character æª
+U+612b sù # Character æ«
+U+612c sù # Character æ¬
+U+612d qà # Character æ
+U+612e yáo # Character æ®
+#U+612f sÇng # Character æ¯
+#U+6130 huÇng # Character æ°
+U+6131 jà # Character æ±
+#U+6132 gÇ # Character æ²
+U+6133 jù # Character æ³
+U+6134 chuà ng # Character æ´
+U+6135 nì # Character æµ
+U+6136 xié # Character æ¶
+#U+6137 kÇi # Character æ·
+#U+6138 zhÄng # Character æ¸
+#U+6139 yÇng # Character æ¹
+#U+613a cÇo # Character æº
+U+613b sùn # Character æ»
+U+613c shèn # Character æ¼
+U+613d bó # Character æ½
+U+613e kà i # Character æ¾
+U+613f yuà n # Character æ¿
+U+6140 xié # Character æ
+U+6141 hùn # Character æ
+#U+6142 yÇng # Character æ
+#U+6143 yÇng # Character æ
+U+6144 lì # Character æ
+#U+6145 sÄo # Character æ
+#U+6146 tÄo # Character æ
+#U+6147 yÄ«n # Character æ
+U+6148 cà # Character æ
+U+6149 xù # Character æ
+U+614a qià n # Character æ
+U+614b tà i # Character æ
+#U+614c huÄng # Character æ
+U+614d yùn # Character æ
+U+614e shèn # Character æ
+#U+614f mÇng # Character æ
+U+6150 ? # Character æ
+U+6151 shè # Character æ
+U+6152 cóng # Character æ
+U+6153 pià o # Character æ
+U+6154 mò # Character æ
+U+6155 mù # Character æ
+U+6156 guó # Character æ
+U+6157 chì # Character æ
+#U+6158 cÇn # Character æ
+U+6159 cán # Character æ
+U+615a cán # Character æ
+U+615b cuà # Character æ
+#U+615c mÇn # Character æ
+U+615d tè # Character æ
+#U+615e zhÄng # Character æ
+U+615f tòng # Character æ
+U+6160 Ã o # Character æ
+#U+6161 shuÇng # Character æ
¡
+U+6162 mà n # Character æ
¢
+U+6163 guà n # Character æ
£
+U+6164 què # Character æ
¤
+U+6165 zà o # Character æ
¥
+U+6166 jiù # Character æ
¦
+U+6167 huì # Character æ
§
+#U+6168 kÇi # Character æ
¨
+U+6169 lián # Character æ
©
+U+616a òu # Character æ
ª
+#U+616b sÇng # Character æ
«
+#U+616c jÇn # Character æ
¬
+U+616d yìn # Character æ
+#U+616e lÇ # Character æ
®
+#U+616f shÄng # Character æ
¯
+U+6170 wèi # Character æ
°
+U+6171 tuán # Character æ
±
+U+6172 mán # Character æ
²
+#U+6173 qiÄn # Character æ
³
+U+6174 shè # Character æ
´
+#U+6175 yÅng # Character æ
µ
+U+6176 qìng # Character æ
¶
+#U+6177 kÄng # Character æ
·
+U+6178 dì # Character æ
¸
+U+6179 zhà # Character æ
¹
+U+617a lóu # Character æ
º
+U+617b juà n # Character æ
»
+#U+617c qÄ« # Character æ
¼
+#U+617d qÄ« # Character æ
½
+U+617e yù # Character æ
¾
+U+617f pÃng # Character æ
¿
+U+6180 liáo # Character æ
+#U+6181 cÅng # Character æ
+#U+6182 yÅu # Character æ
+#U+6183 chÅng # Character æ
+U+6184 zhì # Character æ
+U+6185 tòng # Character æ
+#U+6186 chÄng # Character æ
+U+6187 qì # Character æ
+#U+6188 qÅ« # Character æ
+U+6189 péng # Character æ
+U+618a bèi # Character æ
+#U+618b biÄ # Character æ
+U+618c chún # Character æ
+#U+618d jiÄo # Character æ
+#U+618e zÄng # Character æ
+U+618f chì # Character æ
+U+6190 lián # Character æ
+U+6191 pÃng # Character æ
+U+6192 kuì # Character æ
+U+6193 huì # Character æ
+U+6194 qiáo # Character æ
+U+6195 chéng # Character æ
+U+6196 yìn # Character æ
+U+6197 yìn # Character æ
+#U+6198 xÇ # Character æ
+#U+6199 xÇ # Character æ
+U+619a dà n # Character æ
+U+619b tán # Character æ
+#U+619c duÇ # Character æ
+U+619d duì # Character æ
+U+619e duì # Character æ
+U+619f sù # Character æ
+U+61a0 jué # Character æ
+U+61a1 cè # Character æ¡
+#U+61a2 xiÄo # Character æ¢
+U+61a3 fán # Character æ£
+U+61a4 fèn # Character æ¤
+U+61a5 láo # Character æ¥
+U+61a6 là o # Character æ¦
+#U+61a7 chÅng # Character æ§
+#U+61a8 hÄn # Character æ¨
+U+61a9 qì # Character æ©
+U+61aa xián # Character æª
+#U+61ab mÇn # Character æ«
+#U+61ac jÇng # Character æ¬
+#U+61ad liÇo # Character æ
+#U+61ae wÇ # Character æ®
+#U+61af cÇn # Character æ¯
+U+61b0 jué # Character æ°
+U+61b1 cù # Character æ±
+U+61b2 xià n # Character æ²
+#U+61b3 tÇn # Character æ³
+U+61b4 shéng # Character æ´
+#U+61b5 pÄ« # Character æµ
+U+61b6 yì # Character æ¶
+#U+61b7 chÇ # Character æ·
+#U+61b8 xiÄn # Character æ¸
+U+61b9 náo # Character æ¹
+U+61ba dà n # Character æº
+#U+61bb tÇn # Character æ»
+#U+61bc jÇng # Character æ¼
+#U+61bd sÅng # Character æ½
+U+61be hà n # Character æ¾
+#U+61bf jiÄo # Character æ¿
+U+61c0 wà i # Character æ
+U+61c1 huán # Character æ
+#U+61c2 dÇng # Character æ
+U+61c3 qÃn # Character æ
+U+61c4 qÃn # Character æ
+U+61c5 qú # Character æ
+#U+61c6 cÇo # Character æ
+#U+61c7 kÄn # Character æ
+U+61c8 xiè # Character æ
+#U+61c9 yÄ«ng # Character æ
+U+61ca à o # Character æ
+U+61cb mà o # Character æ
+U+61cc yì # Character æ
+#U+61cd lÇn # Character æ
+U+61ce sè # Character æ
+U+61cf jùn # Character æ
+U+61d0 huái # Character æ
+U+61d1 mèn # Character æ
+#U+61d2 lÇn # Character æ
+U+61d3 Ã i # Character æ
+#U+61d4 lÇn # Character æ
+#U+61d5 yÄn # Character æ
+#U+61d6 guÄ # Character æ
+U+61d7 xià # Character æ
+U+61d8 chì # Character æ
+#U+61d9 yÇ # Character æ
+U+61da yìn # Character æ
+#U+61db dÄi # Character æ
+U+61dc mèng # Character æ
+U+61dd à i # Character æ
+U+61de méng # Character æ
+U+61df duì # Character æ
+U+61e0 qà # Character æ
+#U+61e1 mÇ # Character æ¡
+U+61e2 lán # Character æ¢
+U+61e3 mèn # Character æ£
+U+61e4 chóu # Character æ¤
+U+61e5 zhì # Character æ¥
+U+61e6 nuò # Character æ¦
+U+61e7 nuò # Character æ§
+#U+61e8 yÄn # Character æ¨
+#U+61e9 yÇng # Character æ©
+U+61ea bó # Character æª
+U+61eb zhà # Character æ«
+U+61ec kuà ng # Character æ¬
+U+61ed kuà ng # Character æ
+#U+61ee yÇu # Character æ®
+#U+61ef fÅ« # Character æ¯
+U+61f0 liú # Character æ°
+U+61f1 miè # Character æ±
+U+61f2 chéng # Character æ²
+U+61f3 ? # Character æ³
+U+61f4 chà n # Character æ´
+U+61f5 méng # Character æµ
+#U+61f6 lÇn # Character æ¶
+U+61f7 huái # Character æ·
+U+61f8 xuán # Character æ¸
+U+61f9 rà ng # Character æ¹
+U+61fa chà n # Character æº
+U+61fb jì # Character æ»
+U+61fc jù # Character æ¼
+#U+61fd huÄn # Character æ½
+U+61fe shè # Character æ¾
+U+61ff yì # Character æ¿
diff --git a/resources/chars/latin1/row62.trans b/resources/chars/latin1/row62.trans
new file mode 100644
index 0000000..daae480
--- /dev/null
+++ b/resources/chars/latin1/row62.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+6200 lià n # Character æ
+#U+6201 nÇn # Character æ
+U+6202 mà # Character æ
+#U+6203 tÇng # Character æ
+U+6204 jué # Character æ
+U+6205 gà ng # Character æ
+U+6206 gà ng # Character æ
+U+6207 gà ng # Character æ
+#U+6208 gÄ # Character æ
+U+6209 yuè # Character æ
+U+620a wù # Character æ
+#U+620b jiÄn # Character æ
+#U+620c xÅ« # Character æ
+U+620d shù # Character æ
+U+620e róng # Character æ
+U+620f xì # Character æ
+U+6210 chéng # Character æ
+#U+6211 wÇ # Character æ
+U+6212 jiè # Character æ
+#U+6213 gÄ # Character æ
+#U+6214 jiÄn # Character æ
+#U+6215 qiÄng # Character æ
+U+6216 huò # Character æ
+#U+6217 qiÄng # Character æ
+U+6218 zhà n # Character æ
+U+6219 dòng # Character æ
+U+621a qi # Character æ
+U+621b jiá # Character æ
+U+621c dié # Character æ
+U+621d zéi # Character æ
+U+621e jiá # Character æ
+#U+621f jÇ # Character æ
+U+6220 shì # Character æ
+#U+6221 kÄn # Character æ¡
+U+6222 jà # Character æ¢
+U+6223 kuà # Character æ£
+U+6224 gà i # Character æ¤
+#U+6225 dÄng # Character æ¥
+U+6226 zhà n # Character æ¦
+#U+6227 chuÄng # Character æ§
+#U+6228 gÄ # Character æ¨
+#U+6229 jiÇn # Character æ©
+U+622a jié # Character æª
+U+622b yù # Character æ«
+#U+622c jiÇn # Character æ¬
+#U+622d yÇn # Character æ
+U+622e lù # Character æ®
+U+622f xì # Character æ¯
+U+6230 zhà n # Character æ°
+U+6231 xì # Character æ±
+U+6232 xì # Character æ²
+#U+6233 chuÅ # Character æ³
+U+6234 dà i # Character æ´
+U+6235 qú # Character æµ
+U+6236 hù # Character æ¶
+U+6237 hù # Character æ·
+U+6238 hù # Character æ¸
+U+6239 è # Character æ¹
+U+623a shì # Character æº
+U+623b lì # Character æ»
+#U+623c mÇo # Character æ¼
+U+623d hù # Character æ½
+U+623e lì # Character æ¾
+U+623f fáng # Character æ¿
+#U+6240 suÇ # Character æ
+#U+6241 biÇn # Character æ
+U+6242 dià n # Character æ
+#U+6243 jiÅng # Character æ
+#U+6244 shÇng # Character æ
+U+6245 yà # Character æ
+#U+6246 yÇ # Character æ
+U+6247 shà n # Character æ
+U+6248 hù # Character æ
+#U+6249 fÄi # Character æ
+#U+624a yÇn # Character æ
+#U+624b shÇu # Character æ
+U+624c ? # Character æ
+U+624d cái # Character æ
+#U+624e zhÄ # Character æ
+U+624f qiú # Character æ
+U+6250 lè # Character æ
+#U+6251 pÅ« # Character æ
+#U+6252 bÄ # Character æ
+#U+6253 dÇ # Character æ
+#U+6254 rÄng # Character æ
+U+6255 fú # Character æ
+U+6256 ? # Character æ
+U+6257 zà i # Character æ
+#U+6258 tuÅ # Character æ
+U+6259 zhà ng # Character æ
+#U+625a diÄo # Character æ
+U+625b káng # Character æ
+#U+625c yÅ« # Character æ
+#U+625d kÅ« # Character æ
+U+625e hà n # Character æ
+#U+625f shÄn # Character æ
+#U+6260 chÄ # Character æ
+#U+6261 yÇ # Character æ¡
+#U+6262 gÇ # Character æ¢
+U+6263 kòu # Character æ£
+U+6264 wù # Character æ¤
+#U+6265 tuÅ # Character æ¥
+#U+6266 qiÄn # Character æ¦
+U+6267 zhà # Character æ§
+U+6268 rèn # Character æ¨
+U+6269 kuò # Character æ©
+U+626a mén # Character æª
+#U+626b sÇo # Character æ«
+U+626c yáng # Character æ¬
+#U+626d niÇ # Character æ
+U+626e ban # Character æ®
+#U+626f chÄ # Character æ¯
+#U+6270 rÇo # Character æ°
+#U+6271 xÄ« # Character æ±
+U+6272 qián # Character æ²
+#U+6273 bÄn # Character æ³
+U+6274 jiá # Character æ´
+U+6275 yú # Character æµ
+U+6276 fú # Character æ¶
+U+6277 Ã o # Character æ·
+#U+6278 xÄ« # Character æ¸
+#U+6279 pÄ« # Character æ¹
+#U+627a zhÇ # Character æº
+U+627b zì # Character æ»
+U+627c è # Character æ¼
+U+627d dùn # Character æ½
+#U+627e zhÇo # Character æ¾
+U+627f chéng # Character æ¿
+U+6280 jì # Character æ
+#U+6281 yÇn # Character æ
+U+6282 kuáng # Character æ
+U+6283 bià n # Character æ
+#U+6284 chÄo # Character æ
+#U+6285 jÅ« # Character æ
+U+6286 wèn # Character æ
+U+6287 hú # Character æ
+U+6288 yuè # Character æ
+U+6289 jué # Character æ
+#U+628a bÇ # Character æ
+U+628b qìn # Character æ
+#U+628c zhÄn # Character æ
+#U+628d zhÄng # Character æ
+#U+628e yÇn # Character æ
+U+628f wán # Character æ
+U+6290 nù # Character æ
+U+6291 yì # Character æ
+#U+6292 shÅ« # Character æ
+#U+6293 zhuÄ # Character æ
+U+6294 póu # Character æ
+U+6295 tóu # Character æ
+#U+6296 dÇu # Character æ
+U+6297 kà ng # Character æ
+U+6298 zhé # Character æ
+U+6299 póu # Character æ
+#U+629a fÇ # Character æ
+#U+629b pÄo # Character æ
+U+629c bá # Character æ
+#U+629d Ço # Character æ
+U+629e zé # Character æ
+U+629f tuán # Character æ
+#U+62a0 kÅu # Character æ
+#U+62a1 lÅ«n # Character æ¡
+#U+62a2 qiÇng # Character æ¢
+U+62a3 ? # Character æ£
+U+62a4 hù # Character æ¤
+U+62a5 bà o # Character æ¥
+#U+62a6 bÇng # Character æ¦
+#U+62a7 zhÇ # Character æ§
+#U+62a8 pÄng # Character æ¨
+#U+62a9 tÄn # Character æ©
+#U+62aa pÅ« # Character æª
+#U+62ab pÄ« # Character æ«
+U+62ac tái # Character æ¬
+#U+62ad yÇo # Character æ
+#U+62ae zhÄn # Character æ®
+#U+62af zhÄ # Character æ¯
+#U+62b0 yÇng # Character æ°
+U+62b1 bà o # Character æ±
+#U+62b2 hÄ # Character æ²
+#U+62b3 nÇ # Character æ³
+U+62b4 yì # Character æ´
+#U+62b5 dÇ # Character æµ
+U+62b6 chì # Character æ¶
+#U+62b7 pÄ« # Character æ·
+#U+62b8 zÄ # Character æ¸
+#U+62b9 mÇ # Character æ¹
+U+62ba mèi # Character æº
+U+62bb shèn # Character æ»
+#U+62bc yÄ # Character æ¼
+#U+62bd chÅu # Character æ½
+#U+62be qÅ« # Character æ¾
+#U+62bf mÇn # Character æ¿
+U+62c0 chù # Character æ
+#U+62c1 jiÄ # Character æ
+U+62c2 fú # Character æ
+#U+62c3 zhÇn # Character æ
+#U+62c4 zhÇ # Character æ
+#U+62c5 dÄn # Character æ
+#U+62c6 chÄi # Character æ
+U+62c7 mu # Character æ
+U+62c8 nián # Character æ
+#U+62c9 lÄ # Character æ
+#U+62ca fÇ # Character æ
+#U+62cb pÄo # Character æ
+U+62cc bà n # Character æ
+#U+62cd pÄi # Character æ
+#U+62ce lÄ«ng # Character æ
+U+62cf ná # Character æ
+#U+62d0 guÇi # Character æ
+U+62d1 qián # Character æ
+U+62d2 jù # Character æ
+U+62d3 tuò # Character æ
+U+62d4 bá # Character æ
+#U+62d5 tuÅ # Character æ
+#U+62d6 tuÅ # Character æ
+#U+62d7 Ço # Character æ
+#U+62d8 jÅ« # Character æ
+U+62d9 zhuó # Character æ
+U+62da pà n # Character æ
+#U+62db zhÄo # Character æ
+U+62dc bà i # Character æ
+U+62dd bà i # Character æ
+#U+62de dÇ # Character æ
+#U+62df nÇ # Character æ
+U+62e0 jù # Character æ
+U+62e1 kuò # Character æ¡
+#U+62e2 lÇng # Character æ¢
+#U+62e3 jiÇn # Character æ£
+U+62e4 ? # Character æ¤
+#U+62e5 yÅng # Character æ¥
+U+62e6 lán # Character æ¦
+U+62e7 nÃng # Character æ§
+#U+62e8 bÅ # Character æ¨
+U+62e9 zé # Character æ©
+#U+62ea qiÄn # Character æª
+U+62eb hén # Character æ«
+U+62ec kuò # Character æ¬
+U+62ed shì # Character æ
+U+62ee jié # Character æ®
+#U+62ef zhÄng # Character æ¯
+#U+62f0 nÇn # Character æ°
+#U+62f1 gÇng # Character æ±
+#U+62f2 gÇng # Character æ²
+U+62f3 quán # Character æ³
+#U+62f4 shuÄn # Character æ´
+U+62f5 cún # Character æµ
+#U+62f6 zÇn # Character æ¶
+#U+62f7 kÇo # Character æ·
+#U+62f8 chÇ # Character æ¸
+U+62f9 xié # Character æ¹
+U+62fa cè # Character æº
+#U+62fb huÄ« # Character æ»
+#U+62fc pÄ«n # Character æ¼
+#U+62fd zhuÄi # Character æ½
+U+62fe shi # Character æ¾
+U+62ff ná # Character æ¿
diff --git a/resources/chars/latin1/row63.trans b/resources/chars/latin1/row63.trans
new file mode 100644
index 0000000..01bc74e
--- /dev/null
+++ b/resources/chars/latin1/row63.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+6300 bò # Character æ
+U+6301 chà # Character æ
+U+6302 guà # Character æ
+U+6303 zhì # Character æ
+U+6304 kuò # Character æ
+#U+6305 duÇ # Character æ
+#U+6306 duÇ # Character æ
+#U+6307 zhÇ # Character æ
+U+6308 qiè # Character æ
+U+6309 Ã n # Character æ
+U+630a nòng # Character æ
+U+630b zhèn # Character æ
+U+630c gé # Character æ
+U+630d jià o # Character æ
+U+630e kuà # Character æ
+U+630f dòng # Character æ
+U+6310 rú # Character æ
+#U+6311 tiÄo # Character æ
+U+6312 liè # Character æ
+#U+6313 zhÄ # Character æ
+#U+6314 lÇ # Character æ
+U+6315 dié # Character æ
+#U+6316 wÄ # Character æ
+U+6317 jué # Character æ
+U+6318 ? # Character æ
+#U+6319 jÇ # Character æ
+U+631a zhì # Character æ
+U+631b luán # Character æ
+U+631c yà # Character æ
+#U+631d zhuÄ # Character æ
+U+631e tà # Character æ
+U+631f xié # Character æ
+U+6320 náo # Character æ
+#U+6321 dÇng # Character æ¡
+#U+6322 jiÇo # Character æ¢
+#U+6323 zhÄng # Character æ£
+#U+6324 jÇ # Character æ¤
+#U+6325 huÄ« # Character æ¥
+U+6326 xún # Character æ¦
+U+6327 ? # Character æ§
+#U+6328 Äi # Character æ¨
+#U+6329 tuÅ # Character æ©
+U+632a nuó # Character æª
+U+632b cuò # Character æ«
+U+632c bó # Character æ¬
+#U+632d gÄng # Character æ
+#U+632e tÇ # Character æ®
+U+632f zhèn # Character æ¯
+U+6330 chéng # Character æ°
+#U+6331 suÅ # Character æ±
+#U+6332 suÅ # Character æ²
+#U+6333 kÄng # Character æ³
+#U+6334 mÄi # Character æ´
+U+6335 lòng # Character æµ
+U+6336 jú # Character æ¶
+U+6337 péng # Character æ·
+#U+6338 jiÇn # Character æ¸
+U+6339 yì # Character æ¹
+#U+633a tÇng # Character æº
+#U+633b shÄn # Character æ»
+U+633c nuò # Character æ¼
+#U+633d wÇn # Character æ½
+U+633e xié # Character æ¾
+#U+633f chÄ # Character æ¿
+#U+6340 fÄng # Character æ
+#U+6341 jiÇo # Character æ
+#U+6342 wÇ # Character æ
+U+6343 jùn # Character æ
+U+6344 jiù # Character æ
+#U+6345 tÇng # Character æ
+#U+6346 kÇn # Character æ
+U+6347 huò # Character æ
+U+6348 tú # Character æ
+#U+6349 zhuÅ # Character æ
+U+634a póu # Character æ
+U+634b lè # Character æ
+#U+634c bÄ # Character æ
+U+634d hà n # Character æ
+#U+634e shÄo # Character æ
+#U+634f niÄ # Character æ
+#U+6350 juÄn # Character æ
+U+6351 zé # Character æ
+#U+6352 sÇng # Character æ
+U+6353 yé # Character æ
+U+6354 jué # Character æ
+#U+6355 bÇ # Character æ
+U+6356 huán # Character æ
+U+6357 bù # Character æ
+U+6358 zùn # Character æ
+U+6359 yì # Character æ
+#U+635a zhÄi # Character æ
+#U+635b lÇ # Character æ
+#U+635c sÅu # Character æ
+#U+635d tuÅ # Character æ
+#U+635e lÄo # Character æ
+#U+635f sÇn # Character æ
+#U+6360 bÄng # Character æ
+#U+6361 jiÇn # Character æ¡
+U+6362 huà n # Character æ¢
+#U+6363 dÇo # Character æ£
+U+6364 ? # Character æ¤
+U+6365 wà n # Character æ¥
+U+6366 qÃn # Character æ¦
+#U+6367 pÄng # Character æ§
+#U+6368 shÄ # Character æ¨
+U+6369 liè # Character æ©
+U+636a mÃn # Character æª
+U+636b mén # Character æ«
+#U+636c fÇ # Character æ¬
+#U+636d bÇi # Character æ
+U+636e jù # Character æ®
+#U+636f dÇo # Character æ¯
+#U+6370 wÇ # Character æ°
+U+6371 ái # Character æ±
+#U+6372 juÇn # Character æ²
+U+6373 yuè # Character æ³
+#U+6374 zÇng # Character æ´
+#U+6375 chÄn # Character æµ
+U+6376 chuà # Character æ¶
+U+6377 jié # Character æ·
+#U+6378 tÅ« # Character æ¸
+U+6379 bèn # Character æ¹
+U+637a nà # Character æº
+#U+637b niÇn # Character æ»
+U+637c nuó # Character æ¼
+U+637d zú # Character æ½
+U+637e wò # Character æ¾
+#U+637f xÄ« # Character æ¿
+#U+6380 xiÄn # Character æ
+U+6381 chéng # Character æ
+#U+6382 diÄn # Character æ
+#U+6383 sÇo # Character æ
+#U+6384 lÅ«n # Character æ
+U+6385 qìng # Character æ
+#U+6386 gÄng # Character æ
+U+6387 duó # Character æ
+U+6388 shòu # Character æ
+U+6389 dià o # Character æ
+U+638a póu # Character æ
+#U+638b dÇ # Character æ
+#U+638c zhÇng # Character æ
+#U+638d gÇn # Character æ
+#U+638e jÇ # Character æ
+#U+638f tÄo # Character æ
+#U+6390 qiÄ # Character æ
+U+6391 qà # Character æ
+U+6392 pái # Character æ
+U+6393 shú # Character æ
+#U+6394 qiÄn # Character æ
+U+6395 lìng # Character æ
+U+6396 yì # Character æ
+U+6397 yà # Character æ
+U+6398 jué # Character æ
+#U+6399 zhÄng # Character æ
+#U+639a liÇng # Character æ
+U+639b guà # Character æ
+#U+639c yÇ # Character æ
+U+639d huò # Character æ
+U+639e shà n # Character æ
+#U+639f zhÄng # Character æ
+U+63a0 è # Character æ
+#U+63a1 cÇi # Character æ¡
+U+63a2 tà n # Character æ¢
+U+63a3 chè # Character æ£
+#U+63a4 bÄ«ng # Character æ¤
+#U+63a5 jiÄ # Character æ¥
+U+63a6 tì # Character æ¦
+U+63a7 kòng # Character æ§
+#U+63a8 tuÄ« # Character æ¨
+#U+63a9 yÇn # Character æ©
+U+63aa cuò # Character æª
+#U+63ab zÅu # Character æ«
+U+63ac jú # Character æ¬
+U+63ad tià n # Character æ
+U+63ae qián # Character æ®
+U+63af kèn # Character æ¯
+#U+63b0 bÄi # Character æ°
+#U+63b1 shÇu # Character æ±
+#U+63b2 jiÄ # Character æ²
+#U+63b3 lÇ # Character æ³
+U+63b4 guó # Character æ´
+U+63b5 ? # Character æµ
+U+63b6 ? # Character æ¶
+U+63b7 zhì # Character æ·
+#U+63b8 dÇn # Character æ¸
+U+63b9 ? # Character æ¹
+#U+63ba xiÄn # Character æº
+#U+63bb sÄo # Character æ»
+U+63bc guà n # Character æ¼
+U+63bd pèng # Character æ½
+U+63be yuà n # Character æ¾
+U+63bf nuò # Character æ¿
+#U+63c0 jiÇn # Character æ
+#U+63c1 zhÄn # Character æ
+#U+63c2 jiÅ« # Character æ
+#U+63c3 jiÄn # Character æ
+U+63c4 yú # Character æ
+U+63c5 yán # Character æ
+U+63c6 kuà # Character æ
+#U+63c7 nÇn # Character æ
+#U+63c8 hÅng # Character æ
+U+63c9 róu # Character æ
+U+63ca pì # Character æ
+#U+63cb wÄi # Character æ
+#U+63cc sÄi # Character æ
+U+63cd zòu # Character æ
+#U+63ce xuÄn # Character æ
+U+63cf miáo # Character æ
+U+63d0 tà # Character æ
+#U+63d1 niÄ # Character æ
+#U+63d2 chÄ # Character æ
+U+63d3 shì # Character æ
+#U+63d4 zÇng # Character æ
+U+63d5 zhèn # Character æ
+#U+63d6 yÄ« # Character æ
+#U+63d7 shÇn # Character æ
+U+63d8 héng # Character æ
+U+63d9 bià n # Character æ
+U+63da yáng # Character æ
+U+63db huà n # Character æ
+#U+63dc yÇn # Character æ
+U+63dd zuà n # Character æ
+#U+63de Çn # Character æ
+#U+63df xÅ« # Character æ
+U+63e0 yà # Character æ
+U+63e1 wò # Character æ¡
+U+63e2 kè # Character æ¢
+#U+63e3 chuÄi # Character æ£
+U+63e4 jà # Character æ¤
+U+63e5 tì # Character æ¥
+U+63e6 lá # Character æ¦
+U+63e7 là # Character æ§
+U+63e8 chéng # Character æ¨
+#U+63e9 kÄi # Character æ©
+#U+63ea jiÅ« # Character æª
+#U+63eb jiÅ« # Character æ«
+U+63ec tú # Character æ¬
+#U+63ed jiÄ # Character æ
+#U+63ee huÄ« # Character æ®
+#U+63ef gÄng # Character æ¯
+U+63f0 chòng # Character æ°
+U+63f1 shuò # Character æ±
+U+63f2 shé # Character æ²
+U+63f3 xiè # Character æ³
+U+63f4 yuán # Character æ´
+U+63f5 qián # Character æµ
+U+63f6 yé # Character æ¶
+#U+63f7 chÄ # Character æ·
+#U+63f8 zhÄ # Character æ¸
+#U+63f9 bÄi # Character æ¹
+U+63fa yáo # Character æº
+U+63fb ? # Character æ»
+U+63fc ? # Character æ¼
+#U+63fd lÇn # Character æ½
+U+63fe wèn # Character æ¾
+U+63ff qìn # Character æ¿
diff --git a/resources/chars/latin1/row64.trans b/resources/chars/latin1/row64.trans
new file mode 100644
index 0000000..a23e631
--- /dev/null
+++ b/resources/chars/latin1/row64.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+6400 chÄn # Character æ
+#U+6401 gÄ # Character æ
+#U+6402 lÇu # Character æ
+#U+6403 zÇng # Character æ
+#U+6404 gÄng # Character æ
+#U+6405 jiÇo # Character æ
+U+6406 gòu # Character æ
+U+6407 qìn # Character æ
+#U+6408 yÇng # Character æ
+U+6409 què # Character æ
+#U+640a chÅu # Character æ
+#U+640b chÇ # Character æ
+#U+640c zhÇn # Character æ
+#U+640d sÇn # Character æ
+#U+640e sÅ«n # Character æ
+U+640f bó # Character æ
+U+6410 chù # Character æ
+#U+6411 rÇng # Character æ
+U+6412 bèng # Character æ
+#U+6413 cuÅ # Character æ
+#U+6414 sÄo # Character æ
+U+6415 kè # Character æ
+U+6416 yáo # Character æ
+#U+6417 dÇo # Character æ
+#U+6418 zhÄ« # Character æ
+U+6419 nù # Character æ
+U+641a xié # Character æ
+#U+641b jiÄn # Character æ
+#U+641c sÅu # Character æ
+#U+641d qiÇ # Character æ
+#U+641e gÇo # Character æ
+#U+641f xiÇn # Character æ
+U+6420 shuò # Character æ
+#U+6421 sÇng # Character æ¡
+U+6422 jìn # Character æ¢
+U+6423 miè # Character æ£
+U+6424 è # Character æ¤
+U+6425 chuà # Character æ¥
+U+6426 nuò # Character æ¦
+#U+6427 shÄn # Character æ§
+U+6428 tà # Character æ¨
+U+6429 jié # Character æ©
+U+642a táng # Character æª
+U+642b pán # Character æ«
+#U+642c bÄn # Character æ¬
+#U+642d dÄ # Character æ
+U+642e lì # Character æ®
+#U+642f tÄo # Character æ¯
+U+6430 hú # Character æ°
+U+6431 zhì # Character æ±
+#U+6432 wÄ # Character æ²
+U+6433 xiá # Character æ³
+#U+6434 qiÄn # Character æ´
+U+6435 wèn # Character æµ
+#U+6436 qiÇng # Character æ¶
+U+6437 tián # Character æ·
+#U+6438 zhÄn # Character æ¸
+U+6439 è # Character æ¹
+U+643a xié # Character æº
+U+643b nuò # Character æ»
+U+643c quán # Character æ¼
+U+643d chá # Character æ½
+U+643e zhà # Character æ¾
+U+643f gé # Character æ¿
+#U+6440 wÇ # Character æ
+U+6441 èn # Character æ
+U+6442 shè # Character æ
+U+6443 káng # Character æ
+U+6444 shè # Character æ
+#U+6445 shÅ« # Character æ
+#U+6446 bÇi # Character æ
+U+6447 yáo # Character æ
+U+6448 bìn # Character æ
+#U+6449 sÅu # Character æ
+#U+644a tÄn # Character æ
+U+644b sà # Character æ
+#U+644c chÇn # Character æ
+#U+644d suÅ # Character æ
+U+644e liáo # Character æ
+#U+644f chÅng # Character æ
+#U+6450 chuÄng # Character æ
+U+6451 guó # Character æ
+U+6452 bìng # Character æ
+U+6453 féng # Character æ
+#U+6454 shuÄi # Character æ
+U+6455 dì # Character æ
+U+6456 qì # Character æ
+U+6457 ? # Character æ
+#U+6458 zhÄi # Character æ
+#U+6459 liÇn # Character æ
+U+645a táng # Character æ
+#U+645b chÄ« # Character æ
+U+645c guà n # Character æ
+U+645d lù # Character æ
+U+645e luó # Character æ
+#U+645f lÇu # Character æ
+#U+6460 zÇng # Character æ
+U+6461 gà i # Character æ¡
+U+6462 hù # Character æ¢
+#U+6463 zhÄ # Character æ£
+#U+6464 chuÇng # Character æ¤
+U+6465 tà ng # Character æ¥
+U+6466 huà # Character æ¦
+#U+6467 cuÄ« # Character æ§
+U+6468 nái # Character æ¨
+U+6469 mó # Character æ©
+#U+646a jiÄng # Character æª
+#U+646b guÄ« # Character æ«
+U+646c yìng # Character æ¬
+U+646d zhà # Character æ
+U+646e áo # Character æ®
+U+646f zhì # Character æ¯
+U+6470 niè # Character æ°
+U+6471 mán # Character æ±
+U+6472 shà n # Character æ²
+#U+6473 kÅu # Character æ³
+#U+6474 shÅ« # Character æ´
+#U+6475 suÇ # Character æµ
+U+6476 tuán # Character æ¶
+#U+6477 jiÇo # Character æ·
+#U+6478 mÅ # Character æ¸
+U+6479 mó # Character æ¹
+U+647a zhé # Character æº
+#U+647b xiÄn # Character æ»
+#U+647c kÄng # Character æ¼
+#U+647d piÇo # Character æ½
+U+647e jià ng # Character æ¾
+#U+647f yÄ«n # Character æ¿
+U+6480 gòu # Character æ
+#U+6481 qiÄn # Character æ
+U+6482 lià o # Character æ
+U+6483 jà # Character æ
+#U+6484 yÄ«ng # Character æ
+#U+6485 juÄ # Character æ
+#U+6486 piÄ # Character æ
+#U+6487 piÄ # Character æ
+#U+6488 lÄo # Character æ
+#U+6489 dÅ«n # Character æ
+U+648a xià n # Character æ
+U+648b ruán # Character æ
+U+648c kuì # Character æ
+#U+648d zÇn # Character æ
+U+648e yì # Character æ
+U+648f xún # Character æ
+#U+6490 chÄng # Character æ
+#U+6491 chÄng # Character æ
+#U+6492 sÄ # Character æ
+U+6493 náo # Character æ
+U+6494 hèng # Character æ
+#U+6495 sÄ« # Character æ
+#U+6496 qiÇn # Character æ
+U+6497 huáng # Character æ
+#U+6498 dÄ # Character æ
+#U+6499 zÇn # Character æ
+#U+649a niÇn # Character æ
+#U+649b lÇn # Character æ
+#U+649c zhÄng # Character æ
+#U+649d huÄ« # Character æ
+U+649e zhuà ng # Character æ
+#U+649f jiÇo # Character æ
+#U+64a0 jÇ # Character æ
+#U+64a1 cÄo # Character æ¡
+#U+64a2 dÇn # Character æ¢
+#U+64a3 dÇn # Character æ£
+U+64a4 chè # Character æ¤
+#U+64a5 bÅ # Character æ¥
+#U+64a6 chÄ # Character æ¦
+U+64a7 jué # Character æ§
+#U+64a8 xiÄo # Character æ¨
+#U+64a9 liÄo # Character æ©
+U+64aa bèn # Character æª
+#U+64ab fÇ # Character æ«
+U+64ac qià o # Character æ¬
+#U+64ad bÅ # Character æ
+#U+64ae cuÅ # Character æ®
+U+64af zhuó # Character æ¯
+U+64b0 zhuà n # Character æ°
+#U+64b1 tuÇ # Character æ±
+#U+64b2 pÅ« # Character æ²
+U+64b3 qìn # Character æ³
+#U+64b4 dÅ«n # Character æ´
+#U+64b5 niÇn # Character æµ
+U+64b6 ? # Character æ¶
+U+64b7 xié # Character æ·
+#U+64b8 lÇ # Character æ¸
+#U+64b9 jiÇo # Character æ¹
+#U+64ba cuÄn # Character æº
+U+64bb tà # Character æ»
+U+64bc hà n # Character æ¼
+U+64bd qià o # Character æ½
+#U+64be zhuÄ # Character æ¾
+#U+64bf jiÇn # Character æ¿
+#U+64c0 gÇn # Character æ
+#U+64c1 yÅng # Character æ
+U+64c2 léi # Character æ
+#U+64c3 kuÇ # Character æ
+#U+64c4 lÇ # Character æ
+U+64c5 shà n # Character æ
+U+64c6 zhuó # Character æ
+U+64c7 zé # Character æ
+#U+64c8 pÅ« # Character æ
+U+64c9 chuò # Character æ
+#U+64ca jÄ« # Character æ
+#U+64cb dÇng # Character æ
+#U+64cc suÇ # Character æ
+#U+64cd cÄo # Character æ
+U+64ce qÃng # Character æ
+U+64cf jìng # Character æ
+U+64d0 huà n # Character æ
+#U+64d1 jiÄ # Character æ
+U+64d2 qÃn # Character æ
+#U+64d3 kuÇi # Character æ
+#U+64d4 dÄn # Character æ
+#U+64d5 xÄ« # Character æ
+#U+64d6 gÄ # Character æ
+U+64d7 pì # Character æ
+U+64d8 bò # Character æ
+U+64d9 Ã o # Character æ
+U+64da jù # Character æ
+U+64db yè # Character æ
+U+64dc ? # Character æ
+U+64dd ? # Character æ
+#U+64de sÇu # Character æ
+U+64df mà # Character æ
+#U+64e0 jÇ # Character æ
+U+64e1 tái # Character æ¡
+U+64e2 zhuó # Character æ¢
+#U+64e3 dÇo # Character æ£
+#U+64e4 xÇng # Character æ¤
+#U+64e5 lÇn # Character æ¥
+#U+64e6 cÄ # Character æ¦
+#U+64e7 jÇ # Character æ§
+U+64e8 yé # Character æ¨
+#U+64e9 rÇ # Character æ©
+U+64ea yè # Character æª
+U+64eb yè # Character æ«
+#U+64ec nÇ # Character æ¬
+U+64ed hù # Character æ
+U+64ee jà # Character æ®
+U+64ef bìn # Character æ¯
+U+64f0 nÃng # Character æ°
+#U+64f1 gÄ # Character æ±
+U+64f2 zhì # Character æ²
+U+64f3 jié # Character æ³
+U+64f4 kuò # Character æ´
+U+64f5 mó # Character æµ
+U+64f6 jià n # Character æ¶
+U+64f7 xié # Character æ·
+U+64f8 liè # Character æ¸
+#U+64f9 tÄn # Character æ¹
+#U+64fa bÇi # Character æº
+#U+64fb sÇu # Character æ»
+#U+64fc lÇ # Character æ¼
+U+64fd lüè # Character æ½
+#U+64fe rÇo # Character æ¾
+U+64ff zhà # Character æ¿
diff --git a/resources/chars/latin1/row65.trans b/resources/chars/latin1/row65.trans
new file mode 100644
index 0000000..0183099
--- /dev/null
+++ b/resources/chars/latin1/row65.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+6500 pÄn # Character æ
+#U+6501 yÇng # Character æ
+U+6502 lèi # Character æ
+U+6503 sà # Character æ
+#U+6504 shÅ« # Character æ
+#U+6505 zÇn # Character æ
+#U+6506 niÇn # Character æ
+#U+6507 xiÇn # Character æ
+U+6508 jùn # Character æ
+U+6509 huò # Character æ
+U+650a lì # Character æ
+U+650b là # Character æ
+U+650c hà n # Character æ
+U+650d yÃng # Character æ
+U+650e lú # Character æ
+#U+650f lÇng # Character æ
+#U+6510 qiÄn # Character æ
+#U+6511 qiÄn # Character æ
+#U+6512 zÇn # Character æ
+#U+6513 qiÄn # Character æ
+U+6514 lán # Character æ
+#U+6515 sÄn # Character æ
+#U+6516 yÄ«ng # Character æ
+U+6517 méi # Character æ
+U+6518 ráng # Character æ
+#U+6519 chÄn # Character æ
+U+651a ? # Character æ
+#U+651b cuÄn # Character æ
+U+651c xié # Character æ
+U+651d shè # Character æ
+#U+651e luÇ # Character æ
+U+651f jùn # Character æ
+U+6520 mà # Character æ
+U+6521 là # Character æ¡
+#U+6522 zÇn # Character æ¢
+U+6523 lüán # Character æ£
+#U+6524 tÄn # Character æ¤
+U+6525 zuà n # Character æ¥
+U+6526 lì # Character æ¦
+#U+6527 diÄn # Character æ§
+#U+6528 wÄ # Character æ¨
+#U+6529 dÇng # Character æ©
+#U+652a jiÇo # Character æª
+U+652b jué # Character æ«
+#U+652c lÇn # Character æ¬
+U+652d lì # Character æ
+#U+652e nÇng # Character æ®
+#U+652f zhÄ« # Character æ¯
+U+6530 guì # Character æ°
+#U+6531 guÇ # Character æ±
+#U+6532 qÄ« # Character æ²
+U+6533 xÃn # Character æ³
+#U+6534 pÅ« # Character æ´
+#U+6535 suÄ« # Character æµ
+#U+6536 shÅu # Character æ¶
+U+6537 káo # Character æ·
+#U+6538 yÅu # Character æ¸
+#U+6539 gÇi # Character æ¹
+#U+653a yÇ # Character æº
+#U+653b gÅng # Character æ»
+#U+653c gÄn # Character æ¼
+#U+653d bÄn # Character æ½
+U+653e fà ng # Character æ¾
+U+653f zhèng # Character æ¿
+U+6540 bó # Character æ
+#U+6541 diÄn # Character æ
+U+6542 kòu # Character æ
+#U+6543 mÇn # Character æ
+U+6544 wù # Character æ
+U+6545 gù # Character æ
+U+6546 hé # Character æ
+U+6547 cè # Character æ
+U+6548 xià o # Character æ
+#U+6549 mÇ # Character æ
+U+654a chù # Character æ
+U+654b gé # Character æ
+U+654c dà # Character æ
+U+654d xù # Character æ
+U+654e jià o # Character æ
+#U+654f mÇn # Character æ
+U+6550 chén # Character æ
+U+6551 jiù # Character æ
+U+6552 zhèn # Character æ
+U+6553 duó # Character æ
+#U+6554 yÇ # Character æ
+U+6555 chì # Character æ
+U+6556 áo # Character æ
+U+6557 bà i # Character æ
+U+6558 xù # Character æ
+U+6559 jià o # Character æ
+U+655a duó # Character æ
+U+655b lià n # Character æ
+U+655c niè # Character æ
+U+655d bì # Character æ
+U+655e chang # Character æ
+#U+655f diÇn # Character æ
+U+6560 duó # Character æ
+U+6561 yì # Character æ¡
+#U+6562 gÇn # Character æ¢
+U+6563 sà n # Character æ£
+#U+6564 kÄ # Character æ¤
+U+6565 yà n # Character æ¥
+#U+6566 dÅ«n # Character æ¦
+#U+6567 qÇ # Character æ§
+#U+6568 dÇu # Character æ¨
+U+6569 xià o # Character æ©
+U+656a duó # Character æª
+U+656b jià o # Character æ«
+U+656c jìng # Character æ¬
+U+656d yáng # Character æ
+U+656e xiá # Character æ®
+U+656f mÃn # Character æ¯
+U+6570 shù # Character æ°
+U+6571 ái # Character æ±
+#U+6572 qiÄo # Character æ²
+U+6573 ái # Character æ³
+#U+6574 zhÄng # Character æ´
+U+6575 dà # Character æµ
+U+6576 zhèn # Character æ¶
+#U+6577 fÅ« # Character æ·
+U+6578 shù # Character æ¸
+U+6579 liáo # Character æ¹
+#U+657a qÅ« # Character æº
+U+657b xiòng # Character æ»
+#U+657c xÇ # Character æ¼
+#U+657d jiÇo # Character æ½
+U+657e ? # Character æ¾
+#U+657f jiÇo # Character æ¿
+U+6580 zhuó # Character æ
+U+6581 yì # Character æ
+U+6582 lià n # Character æ
+U+6583 bì # Character æ
+U+6584 lì # Character æ
+U+6585 xià o # Character æ
+U+6586 xià o # Character æ
+U+6587 wén # Character æ
+U+6588 xué # Character æ
+U+6589 qà # Character æ
+U+658a qà # Character æ
+#U+658b zhÄi # Character æ
+#U+658c bÄ«n # Character æ
+U+658d jué # Character æ
+#U+658e zhÄi # Character æ
+U+658f ? # Character æ
+#U+6590 fÄi # Character æ
+#U+6591 bÄn # Character æ
+#U+6592 bÄn # Character æ
+U+6593 lán # Character æ
+#U+6594 yÇ # Character æ
+U+6595 lán # Character æ
+#U+6596 wÄi # Character æ
+U+6597 dòu # Character æ
+#U+6598 shÄng # Character æ
+U+6599 lià o # Character æ
+#U+659a jiÇ # Character æ
+U+659b hú # Character æ
+U+659c xié # Character æ
+#U+659d jiÇ # Character æ
+#U+659e yÇ # Character æ
+#U+659f zhÄn # Character æ
+U+65a0 jià o # Character æ
+U+65a1 wò # Character æ¡
+#U+65a2 tÇu # Character æ¢
+U+65a3 chù # Character æ£
+#U+65a4 jÄ«n # Character æ¤
+U+65a5 chì # Character æ¥
+U+65a6 yÃn # Character æ¦
+#U+65a7 fÇ # Character æ§
+#U+65a8 qiÄng # Character æ¨
+#U+65a9 zhÇn # Character æ©
+U+65aa qú # Character æª
+U+65ab zhuó # Character æ«
+#U+65ac zhÇn # Character æ¬
+U+65ad duà n # Character æ
+U+65ae zhuó # Character æ®
+#U+65af sÄ« # Character æ¯
+#U+65b0 xÄ«n # Character æ°
+U+65b1 zhuó # Character æ±
+U+65b2 zhuó # Character æ²
+U+65b3 qÃn # Character æ³
+U+65b4 lÃn # Character æ´
+U+65b5 zhuó # Character æµ
+U+65b6 chù # Character æ¶
+U+65b7 duà n # Character æ·
+#U+65b8 zhÇ # Character æ¸
+#U+65b9 fÄng # Character æ¹
+U+65ba xiè # Character æº
+U+65bb háng # Character æ»
+U+65bc yú # Character æ¼
+#U+65bd shÄ« # Character æ½
+U+65be pèi # Character æ¾
+U+65bf yóu # Character æ¿
+U+65c0 ? # Character æ
+U+65c1 páng # Character æ
+U+65c2 qà # Character æ
+#U+65c3 zhÄn # Character æ
+U+65c4 máo # Character æ
+#U+65c5 lÇ # Character æ
+U+65c6 pèi # Character æ
+#U+65c7 pÄ« # Character æ
+U+65c8 liú # Character æ
+#U+65c9 fÅ« # Character æ
+#U+65ca fÇng # Character æ
+U+65cb xuán # Character æ
+#U+65cc jÄ«ng # Character æ
+#U+65cd jÄ«ng # Character æ
+#U+65ce nÇ # Character æ
+U+65cf zú # Character æ
+U+65d0 zhà o # Character æ
+#U+65d1 yÇ # Character æ
+U+65d2 liú # Character æ
+#U+65d3 shÄo # Character æ
+U+65d4 jià n # Character æ
+U+65d5 ? # Character æ
+#U+65d6 yÇ # Character æ
+U+65d7 qà # Character æ
+U+65d8 zhì # Character æ
+#U+65d9 fÄn # Character æ
+#U+65da piÄo # Character æ
+#U+65db fÄn # Character æ
+#U+65dc zhÄn # Character æ
+U+65dd guà i # Character æ
+U+65de suì # Character æ
+U+65df yú # Character æ
+U+65e0 wú # Character æ
+U+65e1 jì # Character æ¡
+U+65e2 jì # Character æ¢
+U+65e3 jì # Character æ£
+U+65e4 huò # Character æ¤
+U+65e5 rì # Character æ¥
+U+65e6 dà n # Character æ¦
+U+65e7 jiù # Character æ§
+#U+65e8 zhÇ # Character æ¨
+#U+65e9 zÇo # Character æ©
+U+65ea xié # Character æª
+#U+65eb tiÄo # Character æ«
+U+65ec xún # Character æ¬
+U+65ed xù # Character æ
+U+65ee xù # Character æ®
+U+65ef xù # Character æ¯
+U+65f0 gà n # Character æ°
+U+65f1 hà n # Character æ±
+U+65f2 tái # Character æ²
+U+65f3 dì # Character æ³
+#U+65f4 xÅ« # Character æ´
+#U+65f5 chÇn # Character æµ
+U+65f6 shà # Character æ¶
+U+65f7 kuà ng # Character æ·
+U+65f8 yáng # Character æ¸
+U+65f9 shà # Character æ¹
+U+65fa wà ng # Character æº
+U+65fb mÃn # Character æ»
+U+65fc mÃn # Character æ¼
+#U+65fd tÅ«n # Character æ½
+#U+65fe chÅ«n # Character æ¾
+#U+65ff wÇ # Character æ¿
diff --git a/resources/chars/latin1/row66.trans b/resources/chars/latin1/row66.trans
new file mode 100644
index 0000000..288b1b7
--- /dev/null
+++ b/resources/chars/latin1/row66.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+6600 yún # Character æ
+U+6601 bèi # Character æ
+U+6602 áng # Character æ
+U+6603 zè # Character æ
+#U+6604 bÇn # Character æ
+U+6605 jié # Character æ
+#U+6606 kÅ«n # Character æ
+#U+6607 shÄng # Character æ
+U+6608 hù # Character æ
+#U+6609 fÇng # Character æ
+U+660a hà o # Character æ
+U+660b guì # Character æ
+#U+660c chÄng # Character æ
+#U+660d xuÄn # Character æ
+U+660e mÃng # Character æ
+#U+660f hÅ«n # Character æ
+#U+6610 fÄn # Character æ
+#U+6611 qÇn # Character æ
+#U+6612 hÅ« # Character æ
+U+6613 yì # Character æ
+U+6614 xà # Character æ
+#U+6615 xÄ«n # Character æ
+U+6616 yán # Character æ
+U+6617 zè # Character æ
+#U+6618 fÇng # Character æ
+U+6619 tán # Character æ
+U+661a shèn # Character æ
+U+661b jù # Character æ
+U+661c yáng # Character æ
+#U+661d zÇn # Character æ
+#U+661e bÇng # Character æ
+#U+661f xÄ«ng # Character æ
+U+6620 yìng # Character æ
+U+6621 xuà n # Character æ¡
+#U+6622 pÄi # Character æ¢
+#U+6623 zhÄn # Character æ£
+#U+6624 lÄ«ng # Character æ¤
+#U+6625 chÅ«n # Character æ¥
+U+6626 hà o # Character æ¦
+U+6627 mèi # Character æ§
+U+6628 zuó # Character æ¨
+U+6629 mò # Character æ©
+U+662a bià n # Character æª
+#U+662b xÇ # Character æ«
+#U+662c hÅ«n # Character æ¬
+#U+662d zhÄo # Character æ
+U+662e zòng # Character æ®
+U+662f shì # Character æ¯
+U+6630 shì # Character æ°
+U+6631 yù # Character æ±
+U+6632 fèi # Character æ²
+U+6633 dié # Character æ³
+#U+6634 mÇo # Character æ´
+U+6635 nì # Character æµ
+#U+6636 chÇng # Character æ¶
+#U+6637 wÄn # Character æ·
+#U+6638 dÅng # Character æ¸
+#U+6639 Çi # Character æ¹
+#U+663a bÇng # Character æº
+U+663b áng # Character æ»
+U+663c zhòu # Character æ¼
+U+663d lóng # Character æ½
+#U+663e xiÇn # Character æ¾
+U+663f kuà ng # Character æ¿
+#U+6640 tiÇo # Character æ
+U+6641 cháo # Character æ
+U+6642 shà # Character æ
+U+6643 huang # Character æ
+#U+6644 huÇng # Character æ
+#U+6645 xuÄn # Character æ
+U+6646 kuà # Character æ
+#U+6647 xÅ« # Character æ
+#U+6648 jiÇo # Character æ
+U+6649 jìn # Character æ
+#U+664a zhÇ # Character æ
+U+664b jìn # Character æ
+#U+664c shÇng # Character æ
+U+664d tóng # Character æ
+#U+664e hÇng # Character æ
+U+664f yà n # Character æ
+#U+6650 gÄi # Character æ
+#U+6651 xiÇng # Character æ
+U+6652 shà i # Character æ
+#U+6653 xiÇo # Character æ
+#U+6654 yÄ # Character æ
+#U+6655 yÅ«n # Character æ
+#U+6656 huÄ« # Character æ
+U+6657 hán # Character æ
+U+6658 hà n # Character æ
+U+6659 jùn # Character æ
+#U+665a wÇn # Character æ
+U+665b xià n # Character æ
+#U+665c kÅ«n # Character æ
+U+665d zhòu # Character æ
+#U+665e xÄ« # Character æ
+U+665f chéng # Character æ
+U+6660 shéng # Character æ
+#U+6661 bÅ« # Character æ¡
+#U+6662 zhÄ # Character æ¢
+#U+6663 zhÄ # Character æ£
+U+6664 wù # Character æ¤
+U+6665 hà n # Character æ¥
+U+6666 huì # Character æ¦
+U+6667 hà o # Character æ§
+U+6668 chen # Character æ¨
+#U+6669 wÇn # Character æ©
+#U+666a tiÇn # Character æª
+U+666b zhuó # Character æ«
+U+666c zuì # Character æ¬
+#U+666d zhÇu # Character æ
+#U+666e pÇ # Character æ®
+#U+666f jÇng # Character æ¯
+#U+6670 xÄ« # Character æ°
+#U+6671 shÇn # Character æ±
+#U+6672 yÇ # Character æ²
+U+6673 xì # Character æ³
+U+6674 qÃng # Character æ´
+#U+6675 qÇ # Character æµ
+#U+6676 jÄ«ng # Character æ¶
+#U+6677 guÇ # Character æ·
+#U+6678 zhÄn # Character æ¸
+U+6679 yì # Character æ¹
+U+667a zhì # Character æº
+#U+667b Çn # Character æ»
+#U+667c wÇn # Character æ¼
+U+667d lÃn # Character æ½
+U+667e lià ng # Character æ¾
+#U+667f chÄng # Character æ¿
+#U+6680 wÇng # Character æ
+#U+6681 xiÇo # Character æ
+U+6682 zà n # Character æ
+U+6683 ? # Character æ
+#U+6684 xuÄn # Character æ
+#U+6685 xuÇn # Character æ
+U+6686 yà # Character æ
+U+6687 xiá # Character æ
+#U+6688 yÅ«n # Character æ
+#U+6689 huÄ« # Character æ
+#U+668a fÇ # Character æ
+#U+668b mÇn # Character æ
+U+668c kuà # Character æ
+U+668d hè # Character æ
+U+668e yìng # Character æ
+#U+668f dÇ # Character æ
+#U+6690 wÄi # Character æ
+#U+6691 shÇ # Character æ
+U+6692 qÃng # Character æ
+U+6693 mà o # Character æ
+U+6694 nán # Character æ
+#U+6695 jiÇn # Character æ
+#U+6696 nuÇn # Character æ
+U+6697 Ã n # Character æ
+U+6698 yáng # Character æ
+#U+6699 chÅ«n # Character æ
+U+669a yáo # Character æ
+#U+669b suÇ # Character æ
+U+669c jìn # Character æ
+U+669d mÃng # Character æ
+#U+669e jiÇo # Character æ
+#U+669f kÇi # Character æ
+#U+66a0 gÇo # Character æ
+#U+66a1 wÄng # Character æ¡
+U+66a2 chà ng # Character æ¢
+U+66a3 qì # Character æ£
+U+66a4 hà o # Character æ¤
+U+66a5 yà n # Character æ¥
+U+66a6 lì # Character æ¦
+U+66a7 à i # Character æ§
+U+66a8 jì # Character æ¨
+U+66a9 guì # Character æ©
+#U+66aa mÄn # Character æª
+U+66ab zà n # Character æ«
+U+66ac xiè # Character æ¬
+U+66ad hà o # Character æ
+U+66ae mù # Character æ®
+U+66af mò # Character æ¯
+#U+66b0 cÅng # Character æ°
+U+66b1 nì # Character æ±
+#U+66b2 zhÄng # Character æ²
+U+66b3 huì # Character æ³
+U+66b4 bà o # Character æ´
+U+66b5 hà n # Character æµ
+U+66b6 xuán # Character æ¶
+U+66b7 chuán # Character æ·
+U+66b8 liáo # Character æ¸
+#U+66b9 xiÄn # Character æ¹
+U+66ba dà n # Character æº
+#U+66bb jÇng # Character æ»
+#U+66bc piÄ # Character æ¼
+U+66bd lÃn # Character æ½
+#U+66be tÅ«n # Character æ¾
+#U+66bf xÇ # Character æ¿
+U+66c0 yì # Character æ
+U+66c1 jì # Character æ
+U+66c2 huà ng # Character æ
+U+66c3 tà i # Character æ
+U+66c4 yè # Character æ
+U+66c5 yè # Character æ
+U+66c6 lì # Character æ
+U+66c7 tán # Character æ
+U+66c8 tóng # Character æ
+#U+66c9 xiÇo # Character æ
+U+66ca fèi # Character æ
+#U+66cb qÇn # Character æ
+U+66cc zhà o # Character æ
+U+66cd hà o # Character æ
+U+66ce yì # Character æ
+U+66cf xià ng # Character æ
+#U+66d0 xÄ«ng # Character æ
+#U+66d1 sÄn # Character æ
+#U+66d2 jiÇo # Character æ
+U+66d3 bà o # Character æ
+U+66d4 jìng # Character æ
+U+66d5 yià n # Character æ
+U+66d6 Ã i # Character æ
+U+66d7 yè # Character æ
+U+66d8 rú # Character æ
+U+66d9 shù # Character æ
+U+66da méng # Character æ
+#U+66db xÅ«n # Character æ
+U+66dc yà o # Character æ
+U+66dd pù # Character æ
+U+66de lì # Character æ
+U+66df chén # Character æ
+U+66e0 kuà ng # Character æ
+U+66e1 dié # Character æ¡
+U+66e2 ? # Character æ¢
+U+66e3 yà n # Character æ£
+U+66e4 huò # Character æ¤
+U+66e5 lú # Character æ¥
+#U+66e6 xÄ« # Character æ¦
+U+66e7 róng # Character æ§
+U+66e8 lóng # Character æ¨
+#U+66e9 nÇng # Character æ©
+#U+66ea luÇ # Character æª
+U+66eb luán # Character æ«
+U+66ec shà i # Character æ¬
+#U+66ed tÇng # Character æ
+#U+66ee yÇn # Character æ®
+U+66ef chú # Character æ¯
+#U+66f0 yuÄ # Character æ°
+#U+66f1 yuÄ # Character æ±
+#U+66f2 qÅ« # Character æ²
+U+66f3 yì # Character æ³
+U+66f4 gèng # Character æ´
+U+66f5 yè # Character æµ
+#U+66f6 hÅ« # Character æ¶
+U+66f7 hé # Character æ·
+#U+66f8 shÅ« # Character æ¸
+U+66f9 cáo # Character æ¹
+U+66fa cáo # Character æº
+U+66fb ? # Character æ»
+U+66fc mà n # Character æ¼
+#U+66fd cÄng # Character æ½
+U+66fe céng # Character æ¾
+U+66ff tì # Character æ¿
diff --git a/resources/chars/latin1/row67.trans b/resources/chars/latin1/row67.trans
new file mode 100644
index 0000000..2104425
--- /dev/null
+++ b/resources/chars/latin1/row67.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+6700 zuì # Character æ
+#U+6701 cÇn # Character æ
+U+6702 xù # Character æ
+U+6703 huì # Character æ
+U+6704 yìn # Character æ
+U+6705 qiè # Character æ
+#U+6706 fÄn # Character æ
+U+6707 pà # Character æ
+U+6708 yuè # Character æ
+#U+6709 yÇu # Character æ
+#U+670a ruÇn # Character æ
+U+670b péng # Character æ
+#U+670c bÄn # Character æ
+U+670d fú # Character æ
+U+670e lÃng # Character æ
+#U+670f fÄi # Character æ
+U+6710 qú # Character æ
+U+6711 ? # Character æ
+#U+6712 nÇ # Character æ
+U+6713 tià o # Character æ
+U+6714 shuò # Character æ
+U+6715 zhèn # Character æ
+#U+6716 lÇng # Character æ
+#U+6717 lÇng # Character æ
+#U+6718 juÄn # Character æ
+U+6719 mÃng # Character æ
+#U+671a huÄng # Character æ
+U+671b wà ng # Character æ
+#U+671c tÅ«n # Character æ
+U+671d cháo # Character æ
+#U+671e jÄ« # Character æ
+#U+671f qÄ« # Character æ
+#U+6720 yÄ«ng # Character æ
+#U+6721 zÅng # Character æ¡
+U+6722 wà ng # Character æ¢
+U+6723 tóng # Character æ£
+#U+6724 lÇng # Character æ¤
+U+6725 ? # Character æ¥
+U+6726 méng # Character æ¦
+U+6727 lóng # Character æ§
+U+6728 mù # Character æ¨
+#U+6729 dÄng # Character æ©
+U+672a wèi # Character æª
+U+672b mò # Character æ«
+#U+672c bÄn # Character æ¬
+U+672d zhá # Character æ
+U+672e shù # Character æ®
+U+672f shù # Character æ¯
+U+6730 ? # Character æ°
+#U+6731 zhÅ« # Character æ±
+U+6732 rén # Character æ²
+#U+6733 bÄ # Character æ³
+#U+6734 pÇ # Character æ´
+U+6735 duo # Character æµ
+#U+6736 duÇ # Character æ¶
+#U+6737 dÄo # Character æ·
+U+6738 lì # Character æ¸
+U+6739 qiú # Character æ¹
+#U+673a jÄ« # Character æº
+#U+673b jiÅ« # Character æ»
+#U+673c bÇ # Character æ¼
+#U+673d xiÇ # Character æ½
+U+673e tÃng # Character æ¾
+U+673f cì # Character æ¿
+#U+6740 shÄ # Character æ
+U+6741 ? # Character æ
+U+6742 zá # Character æ
+U+6743 quán # Character æ
+#U+6744 qiÄn # Character æ
+U+6745 yú # Character æ
+#U+6746 gÄn # Character æ
+#U+6747 wÅ« # Character æ
+#U+6748 chÄ # Character æ
+#U+6749 shÄn # Character æ
+U+674a xún # Character æ
+#U+674b fÄn # Character æ
+U+674c wù # Character æ
+#U+674d zÇ # Character æ
+U+674e li # Character æ
+U+674f xìng # Character æ
+U+6750 cái # Character æ
+#U+6751 cÅ«n # Character æ
+U+6752 rèn # Character æ
+U+6753 sháo # Character æ
+#U+6754 tuÅ # Character æ
+U+6755 dì # Character æ
+U+6756 zhà ng # Character æ
+U+6757 máng # Character æ
+U+6758 chì # Character æ
+U+6759 yì # Character æ
+#U+675a gÇ # Character æ
+#U+675b gÅng # Character æ
+U+675c dù # Character æ
+U+675d yà # Character æ
+#U+675e qÇ # Character æ
+U+675f shù # Character æ
+#U+6760 gÄng # Character æ
+U+6761 tiáo # Character æ¡
+U+6762 ? # Character æ¢
+U+6763 ? # Character æ£
+U+6764 ? # Character æ¤
+U+6765 lái # Character æ¥
+U+6766 ? # Character æ¦
+U+6767 máng # Character æ§
+U+6768 yáng # Character æ¨
+U+6769 mà # Character æ©
+#U+676a miÇo # Character æª
+U+676b sì # Character æ«
+U+676c yuán # Character æ¬
+U+676d háng # Character æ
+U+676e fèi # Character æ®
+#U+676f bÄi # Character æ¯
+U+6770 jié # Character æ°
+#U+6771 dÅng # Character æ±
+#U+6772 gÇo # Character æ²
+#U+6773 yÇo # Character æ³
+#U+6774 xiÄn # Character æ´
+#U+6775 chÇ # Character æµ
+#U+6776 qÅ«n # Character æ¶
+U+6777 pá # Character æ·
+#U+6778 shÅ« # Character æ¸
+U+6779 huà # Character æ¹
+#U+677a xÄ«n # Character æº
+#U+677b chÇu # Character æ»
+U+677c zhù # Character æ¼
+#U+677d chÇu # Character æ½
+#U+677e sÅng # Character æ¾
+#U+677f bÇn # Character æ¿
+#U+6780 sÅng # Character æ
+U+6781 jà # Character æ
+U+6782 yuè # Character æ
+U+6783 jìn # Character æ
+U+6784 gòu # Character æ
+#U+6785 jÄ« # Character æ
+U+6786 máo # Character æ
+U+6787 pà # Character æ
+U+6788 bì # Character æ
+U+6789 wang # Character æ
+U+678a à ng # Character æ
+#U+678b fÄng # Character æ
+U+678c fén # Character æ
+U+678d yì # Character æ
+U+678e fú # Character æ
+U+678f nán # Character æ
+#U+6790 xÄ« # Character æ
+U+6791 hù # Character æ
+U+6792 yá # Character æ
+#U+6793 dÇu # Character æ
+U+6794 xún # Character æ
+#U+6795 zhÄn # Character æ
+#U+6796 yÄo # Character æ
+U+6797 lÃn # Character æ
+U+6798 ruì # Character æ
+U+6799 é # Character æ
+U+679a méi # Character æ
+U+679b zhà o # Character æ
+#U+679c guÇ # Character æ
+#U+679d zhÄ« # Character æ
+#U+679e cÅng # Character æ
+U+679f yùn # Character æ
+U+67a0 ? # Character æ
+#U+67a1 dÇu # Character æ¡
+#U+67a2 shÅ« # Character æ¢
+#U+67a3 zÇo # Character æ£
+U+67a4 ? # Character æ¤
+U+67a5 lì # Character æ¥
+U+67a6 ? # Character æ¦
+U+67a7 jià n # Character æ§
+U+67a8 chéng # Character æ¨
+U+67a9 ? # Character æ©
+#U+67aa qiÄng # Character æª
+#U+67ab fÄng # Character æ«
+U+67ac nán # Character æ¬
+#U+67ad xiÄo # Character æ
+#U+67ae xiÄn # Character æ®
+#U+67af kÅ« # Character æ¯
+U+67b0 pÃng # Character æ°
+U+67b1 yà # Character æ±
+#U+67b2 xÇ # Character æ²
+#U+67b3 zhÄ« # Character æ³
+#U+67b4 guÇi # Character æ´
+#U+67b5 xiÄo # Character æµ
+U+67b6 jià # Character æ¶
+#U+67b7 jiÄ # Character æ·
+#U+67b8 gÇu # Character æ¸
+#U+67b9 fÅ« # Character æ¹
+U+67ba mò # Character æº
+U+67bb yì # Character æ»
+U+67bc yè # Character æ¼
+U+67bd yè # Character æ½
+U+67be shì # Character æ¾
+U+67bf niè # Character æ¿
+#U+67c0 bÇ # Character æ
+U+67c1 duò # Character æ
+U+67c2 yà # Character æ
+U+67c3 lÃng # Character æ
+#U+67c4 bÇng # Character æ
+#U+67c5 nÇ # Character æ
+#U+67c6 lÄ # Character æ
+U+67c7 hé # Character æ
+U+67c8 pán # Character æ
+U+67c9 fán # Character æ
+#U+67ca zhÅng # Character æ
+U+67cb dà i # Character æ
+U+67cc cà # Character æ
+#U+67cd yÄng # Character æ
+#U+67ce fÅ« # Character æ
+#U+67cf bÇi # Character æ
+#U+67d0 mÇu # Character æ
+#U+67d1 gÄn # Character æ
+#U+67d2 qÄ« # Character æ
+#U+67d3 rÇn # Character æ
+U+67d4 róu # Character æ
+U+67d5 mà o # Character æ
+#U+67d6 zhÄo # Character æ
+#U+67d7 sÅng # Character æ
+U+67d8 zhè # Character æ
+U+67d9 xiá # Character æ
+U+67da yòu # Character æ
+#U+67db shÄn # Character æ
+U+67dc guì # Character æ
+U+67dd tuò # Character æ
+U+67de zuò # Character æ
+U+67df nán # Character æ
+U+67e0 nÃng # Character æ
+#U+67e1 yÇng # Character æ¡
+#U+67e2 dÇ # Character æ¢
+U+67e3 zhà # Character æ£
+#U+67e4 zhÄ # Character æ¤
+U+67e5 chá # Character æ¥
+U+67e6 dà n # Character æ¦
+#U+67e7 gÅ« # Character æ§
+U+67e8 ? # Character æ¨
+U+67e9 jiù # Character æ©
+#U+67ea Äo # Character æª
+U+67eb fú # Character æ«
+#U+67ec jiÇn # Character æ¬
+#U+67ed bÅ # Character æ
+U+67ee duò # Character æ®
+#U+67ef kÄ # Character æ¯
+U+67f0 nà i # Character æ°
+U+67f1 zhù # Character æ±
+U+67f2 bì # Character æ²
+#U+67f3 liÇ # Character æ³
+U+67f4 chái # Character æ´
+U+67f5 zhà # Character æµ
+U+67f6 sì # Character æ¶
+U+67f7 zhù # Character æ·
+#U+67f8 pÄi # Character æ¸
+U+67f9 shì # Character æ¹
+#U+67fa guÇi # Character æº
+U+67fb chá # Character æ»
+#U+67fc yÇo # Character æ¼
+U+67fd jué # Character æ½
+U+67fe jiù # Character æ¾
+U+67ff shì # Character æ¿
diff --git a/resources/chars/latin1/row68.trans b/resources/chars/latin1/row68.trans
new file mode 100644
index 0000000..a5108ed
--- /dev/null
+++ b/resources/chars/latin1/row68.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+6800 zhÄ« # Character æ
+#U+6801 liÇ # Character æ
+U+6802 méi # Character æ
+U+6803 ? # Character æ
+U+6804 róng # Character æ
+U+6805 zhà # Character æ
+U+6806 ? # Character æ
+#U+6807 biÄo # Character æ
+U+6808 zhà n # Character æ
+U+6809 jié # Character æ
+U+680a lóng # Character æ
+U+680b dòng # Character æ
+U+680c lú # Character æ
+U+680d ? # Character æ
+U+680e lì # Character æ
+U+680f lán # Character æ
+#U+6810 yÇng # Character æ
+U+6811 shù # Character æ
+U+6812 xún # Character æ
+#U+6813 shuÄn # Character æ
+U+6814 qì # Character æ
+#U+6815 zhÄn # Character æ
+#U+6816 qÄ« # Character æ
+U+6817 lì # Character æ
+#U+6818 yÇ # Character æ
+U+6819 xiáng # Character æ
+U+681a zhèn # Character æ
+U+681b lì # Character æ
+U+681c sù # Character æ
+#U+681d guÄ # Character æ
+#U+681e kÄn # Character æ
+#U+681f bÄ«ng # Character æ
+#U+6820 rÄn # Character æ
+U+6821 xià o # Character æ ¡
+U+6822 bó # Character æ ¢
+#U+6823 rÄn # Character æ £
+U+6824 bìng # Character æ ¤
+#U+6825 zÄ« # Character æ ¥
+U+6826 chóu # Character æ ¦
+U+6827 yì # Character æ §
+U+6828 jié # Character æ ¨
+#U+6829 xÇ # Character æ ©
+#U+682a zhÅ« # Character æ ª
+U+682b jià n # Character æ «
+U+682c zuì # Character æ ¬
+U+682d ér # Character æ
+#U+682e Är # Character æ ®
+#U+682f yÇu # Character æ ¯
+U+6830 fá # Character æ °
+#U+6831 gÇng # Character æ ±
+#U+6832 kÇo # Character æ ²
+#U+6833 lÇo # Character æ ³
+#U+6834 zhÄn # Character æ ´
+U+6835 lì # Character æ µ
+U+6836 ? # Character æ ¶
+U+6837 yà ng # Character æ ·
+U+6838 hé # Character æ ¸
+#U+6839 gÄn # Character æ ¹
+#U+683a zhÇ # Character æ º
+U+683b chì # Character æ »
+U+683c gé # Character æ ¼
+#U+683d zÄi # Character æ ½
+U+683e luán # Character æ ¾
+U+683f fú # Character æ ¿
+U+6840 jié # Character æ¡
+U+6841 háng # Character æ¡
+U+6842 guì # Character æ¡
+U+6843 táo # Character æ¡
+U+6844 guà ng # Character æ¡
+U+6845 wéi # Character æ¡
+#U+6846 kuÄng # Character æ¡
+U+6847 rú # Character æ¡
+U+6848 Ã n # Character æ¡
+U+6849 Ã n # Character æ¡
+U+684a juà n # Character æ¡
+U+684b yà # Character æ¡
+#U+684c zhuÅ # Character æ¡
+#U+684d kÅ« # Character æ¡
+U+684e zhà # Character æ¡
+U+684f qióng # Character æ¡
+U+6850 tóng # Character æ¡
+#U+6851 sÄng # Character æ¡
+#U+6852 sÄng # Character æ¡
+U+6853 huán # Character æ¡
+U+6854 jú # Character æ¡
+U+6855 jiù # Character æ¡
+U+6856 xuè # Character æ¡
+U+6857 duò # Character æ¡
+U+6858 zhuì # Character æ¡
+U+6859 yú # Character æ¡
+#U+685a zÇn # Character æ¡
+U+685b ? # Character æ¡
+#U+685c yÄ«ng # Character æ¡
+U+685d ? # Character æ¡
+U+685e ? # Character æ¡
+U+685f zhà n # Character æ¡
+U+6860 yá # Character æ¡
+U+6861 náo # Character 桡
+#U+6862 zhÄn # Character æ¡¢
+U+6863 dà ng # Character 档
+#U+6864 qī # Character 桤
+U+6865 qiáo # Character 桥
+U+6866 huà # Character 桦
+U+6867 kuà i # Character 桧
+#U+6868 jiÇng # Character 桨
+#U+6869 zhuÄng # Character æ¡©
+U+686a xún # Character 桪
+#U+686b suÅ # Character æ¡«
+#U+686c shÄ # Character 桬
+#U+686d zhÄn # Character æ¡
+#U+686e bÄi # Character æ¡®
+#U+686f tīng # Character 桯
+#U+6870 guÄ # Character æ¡°
+U+6871 jìng # Character 桱
+U+6872 bó # Character 桲
+U+6873 bèn # Character 桳
+U+6874 fú # Character 桴
+#U+6875 ruÇ # Character 桵
+#U+6876 tÇng # Character 桶
+U+6877 jué # Character 桷
+#U+6878 xī # Character 桸
+U+6879 láng # Character 桹
+#U+687a liÇ # Character 桺
+#U+687b fÄng # Character æ¡»
+#U+687c qī # Character 桼
+#U+687d wÄn # Character 桽
+#U+687e jūn # Character 桾
+#U+687f gÇn # Character æ¡¿
+U+6880 cù # Character æ¢
+U+6881 liáng # Character æ¢
+U+6882 qiú # Character æ¢
+#U+6883 tÇng # Character æ¢
+#U+6884 yÇu # Character æ¢
+U+6885 méi # Character æ¢
+#U+6886 bÄng # Character æ¢
+U+6887 lòng # Character æ¢
+#U+6888 pÄng # Character æ¢
+#U+6889 zhuÄng # Character æ¢
+U+688a dì # Character æ¢
+#U+688b xuÄn # Character æ¢
+U+688c tú # Character æ¢
+U+688d zà o # Character æ¢
+#U+688e Äo # Character æ¢
+U+688f gù # Character æ¢
+U+6890 bì # Character æ¢
+U+6891 dà # Character æ¢
+U+6892 hán # Character æ¢
+#U+6893 zÇ # Character æ¢
+#U+6894 zhÄ« # Character æ¢
+U+6895 rèn # Character æ¢
+U+6896 bèi # Character æ¢
+#U+6897 gÄng # Character æ¢
+U+6898 jià n # Character æ¢
+U+6899 huà n # Character æ¢
+#U+689a wÇn # Character æ¢
+U+689b nuó # Character æ¢
+U+689c jiá # Character æ¢
+U+689d tiáo # Character æ¢
+U+689e jì # Character æ¢
+#U+689f xiÄo # Character æ¢
+#U+68a0 lÇ # Character æ¢
+U+68a1 huán # Character 梡
+#U+68a2 shÄo # Character 梢
+U+68a3 cén # Character 梣
+U+68a4 fén # Character 梤
+#U+68a5 sÅng # Character 梥
+U+68a6 mèng # Character 梦
+U+68a7 wú # Character 梧
+U+68a8 là # Character 梨
+U+68a9 là # Character 梩
+U+68aa dòu # Character 梪
+#U+68ab cÄn # Character 梫
+#U+68ac yÇng # Character 梬
+#U+68ad suÅ # Character æ¢
+U+68ae jú # Character 梮
+#U+68af tī # Character 梯
+U+68b0 xiè # Character 械
+#U+68b1 kÇn # Character 梱
+U+68b2 zhuó # Character 梲
+#U+68b3 shū # Character 梳
+#U+68b4 chÄn # Character 梴
+U+68b5 fà n # Character 梵
+#U+68b6 wÄi # Character 梶
+U+68b7 jìng # Character 梷
+U+68b8 là # Character 梸
+#U+68b9 bīng # Character 梹
+U+68ba ? # Character 梺
+U+68bb ? # Character 梻
+U+68bc táo # Character 梼
+U+68bd zhì # Character 梽
+U+68be lái # Character 梾
+U+68bf lián # Character 梿
+#U+68c0 jiÇn # Character æ£
+U+68c1 zhuó # Character æ£
+U+68c2 lÃng # Character æ£
+U+68c3 là # Character æ£
+U+68c4 qì # Character æ£
+U+68c5 bìng # Character æ£
+#U+68c6 zhÅ«n # Character æ£
+#U+68c7 cÅng # Character æ£
+U+68c8 qià n # Character æ£
+U+68c9 mián # Character æ£
+U+68ca qà # Character æ£
+U+68cb qà # Character æ£
+#U+68cc cÇi # Character æ£
+U+68cd gùn # Character æ£
+U+68ce chán # Character æ£
+U+68cf tè # Character æ£
+#U+68d0 fÄi # Character æ£
+U+68d1 pái # Character æ£
+U+68d2 bà ng # Character æ£
+#U+68d3 pÇu # Character æ£
+#U+68d4 hÅ«n # Character æ£
+#U+68d5 zÅng # Character æ£
+U+68d6 chéng # Character æ£
+#U+68d7 zÇo # Character æ£
+U+68d8 jà # Character æ£
+U+68d9 lì # Character æ£
+U+68da péng # Character æ£
+U+68db yù # Character æ£
+U+68dc yù # Character æ£
+U+68dd gù # Character æ£
+U+68de hún # Character æ£
+U+68df dòng # Character æ£
+U+68e0 táng # Character æ£
+#U+68e1 gÄng # Character 棡
+#U+68e2 wÇng # Character 棢
+U+68e3 dì # Character 棣
+U+68e4 xà # Character 棤
+U+68e5 fán # Character 棥
+#U+68e6 chÄng # Character 棦
+U+68e7 zhà n # Character 棧
+#U+68e8 qÇ # Character 棨
+#U+68e9 yuÄn # Character 棩
+#U+68ea yÇn # Character 棪
+U+68eb yù # Character 棫
+#U+68ec quÄn # Character 棬
+U+68ed yì # Character æ£
+#U+68ee sÄn # Character 森
+#U+68ef rÄn # Character 棯
+U+68f0 chuà # Character 棰
+U+68f1 léng # Character 棱
+#U+68f2 qī # Character 棲
+U+68f3 zhuó # Character 棳
+U+68f4 fú # Character 棴
+#U+68f5 kÄ # Character 棵
+U+68f6 lái # Character 棶
+#U+68f7 zÅu # Character 棷
+#U+68f8 zÅu # Character 棸
+#U+68f9 zhuŠ# Character 棹
+#U+68fa guÄn # Character 棺
+U+68fb fén # Character 棻
+U+68fc fén # Character 棼
+#U+68fd chÄn # Character 棽
+U+68fe qióng # Character 棾
+U+68ff niè # Character 棿
diff --git a/resources/chars/latin1/row69.trans b/resources/chars/latin1/row69.trans
new file mode 100644
index 0000000..9ae67b0
--- /dev/null
+++ b/resources/chars/latin1/row69.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+6900 wÇn # Character æ¤
+#U+6901 guÇ # Character æ¤
+U+6902 lù # Character æ¤
+U+6903 háo # Character æ¤
+#U+6904 jiÄ # Character æ¤
+#U+6905 yÇ # Character æ¤
+U+6906 chóu # Character æ¤
+#U+6907 jÇ # Character æ¤
+U+6908 jú # Character æ¤
+U+6909 chéng # Character æ¤
+U+690a zuó # Character æ¤
+U+690b liáng # Character æ¤
+#U+690c qiÄng # Character æ¤
+U+690d zhà # Character æ¤
+#U+690e zhuÄ« # Character æ¤
+#U+690f yÄ # Character æ¤
+#U+6910 jÅ« # Character æ¤
+#U+6911 bÄi # Character æ¤
+#U+6912 jiÄo # Character æ¤
+U+6913 zhuó # Character æ¤
+#U+6914 zÄ« # Character æ¤
+#U+6915 bÄ«n # Character æ¤
+U+6916 péng # Character æ¤
+U+6917 dìng # Character æ¤
+#U+6918 chÇ # Character æ¤
+U+6919 ? # Character æ¤
+U+691a ? # Character æ¤
+U+691b ? # Character æ¤
+#U+691c jiÇn # Character æ¤
+#U+691d guÄ« # Character æ¤
+U+691e xì # Character æ¤
+U+691f dú # Character æ¤
+U+6920 qià n # Character æ¤
+U+6921 ? # Character 椡
+U+6922 ? # Character 椢
+U+6923 ? # Character 椣
+U+6924 luó # Character 椤
+#U+6925 zhī # Character 椥
+U+6926 ? # Character 椦
+U+6927 ? # Character 椧
+U+6928 ? # Character 椨
+U+6929 ? # Character 椩
+U+692a pèng # Character 椪
+#U+692b zhÇn # Character 椫
+U+692c ? # Character 椬
+#U+692d tuÇ # Character æ¤
+#U+692e sÄn # Character 椮
+U+692f duó # Character 椯
+U+6930 yé # Character 椰
+U+6931 fòu # Character 椱
+#U+6932 wÄi # Character 椲
+#U+6933 wÄi # Character 椳
+U+6934 duà n # Character 椴
+#U+6935 jiÇ # Character 椵
+#U+6936 zÅng # Character 椶
+#U+6937 jiÄn # Character 椷
+U+6938 yà # Character 椸
+U+6939 shèn # Character 椹
+U+693a xà # Character 椺
+U+693b yà n # Character 椻
+#U+693c yÇn # Character 椼
+U+693d chuán # Character 椽
+U+693e zhà n # Character 椾
+#U+693f chūn # Character 椿
+#U+6940 yÇ # Character æ¥
+U+6941 hé # Character æ¥
+#U+6942 zhÄ # Character æ¥
+U+6943 wò # Character æ¥
+U+6944 pián # Character æ¥
+U+6945 bì # Character æ¥
+#U+6946 yÄo # Character æ¥
+U+6947 huò # Character æ¥
+#U+6948 xÅ« # Character æ¥
+U+6949 ruò # Character æ¥
+U+694a yáng # Character æ¥
+U+694b là # Character æ¥
+U+694c yán # Character æ¥
+#U+694d bÄn # Character æ¥
+U+694e hún # Character æ¥
+U+694f kuà # Character æ¥
+U+6950 jiè # Character æ¥
+U+6951 kuà # Character æ¥
+#U+6952 sÄ« # Character æ¥
+#U+6953 fÄng # Character æ¥
+U+6954 xiè # Character æ¥
+#U+6955 tuÇ # Character æ¥
+U+6956 zhì # Character æ¥
+U+6957 jià n # Character æ¥
+U+6958 mù # Character æ¥
+U+6959 mà o # Character æ¥
+U+695a chu # Character æ¥
+U+695b hù # Character æ¥
+U+695c hú # Character æ¥
+U+695d lià n # Character æ¥
+U+695e léng # Character æ¥
+U+695f tÃng # Character æ¥
+U+6960 nán # Character æ¥
+U+6961 yú # Character 楡
+U+6962 yóu # Character 楢
+U+6963 méi # Character 楣
+#U+6964 sÇng # Character 楤
+U+6965 xuà n # Character 楥
+U+6966 xuà n # Character 楦
+#U+6967 yīng # Character 楧
+#U+6968 zhÄn # Character 楨
+U+6969 pián # Character 楩
+U+696a yè # Character 楪
+U+696b jà # Character 楫
+U+696c jié # Character 楬
+U+696d yè # Character æ¥
+#U+696e chÇ # Character 楮
+#U+696f shÇn # Character 楯
+U+6970 yú # Character 楰
+U+6971 còu # Character 楱
+#U+6972 wÄi # Character 楲
+U+6973 méi # Character 楳
+U+6974 dì # Character 楴
+U+6975 jà # Character 極
+U+6976 jié # Character 楶
+#U+6977 kÇi # Character 楷
+#U+6978 qiū # Character 楸
+U+6979 yÃng # Character 楹
+U+697a róu # Character 楺
+U+697b héng # Character 楻
+U+697c lóu # Character 楼
+U+697d lè # Character 楽
+U+697e ? # Character 楾
+U+697f ? # Character 楿
+#U+6980 pÇn # Character æ¦
+U+6981 ? # Character æ¦
+U+6982 gà i # Character æ¦
+U+6983 tán # Character æ¦
+#U+6984 lÇn # Character æ¦
+U+6985 yún # Character æ¦
+U+6986 yú # Character æ¦
+U+6987 chèn # Character æ¦
+#U+6988 lÇ # Character æ¦
+#U+6989 jÇ # Character æ¦
+U+698a ? # Character æ¦
+U+698b ? # Character æ¦
+U+698c ? # Character æ¦
+U+698d xiè # Character æ¦
+#U+698e jiÇ # Character æ¦
+U+698f yì # Character æ¦
+#U+6990 zhÇn # Character æ¦
+U+6991 fù # Character æ¦
+U+6992 nà i # Character æ¦
+U+6993 mì # Character æ¦
+U+6994 láng # Character æ¦
+U+6995 róng # Character æ¦
+#U+6996 gÇ # Character æ¦
+U+6997 jià n # Character æ¦
+#U+6998 jÇ # Character æ¦
+#U+6999 tÇ # Character æ¦
+#U+699a yÇo # Character æ¦
+#U+699b zhÄn # Character æ¦
+#U+699c bÇng # Character æ¦
+#U+699d shÄ # Character æ¦
+U+699e yuán # Character æ¦
+#U+699f zÇ # Character æ¦
+#U+69a0 mÄ«ng # Character æ¦
+U+69a1 sù # Character 榡
+U+69a2 jià # Character 榢
+U+69a3 yáo # Character 榣
+U+69a4 jié # Character 榤
+#U+69a5 huÇng # Character 榥
+U+69a6 gà n # Character 榦
+#U+69a7 fÄi # Character 榧
+U+69a8 zhà # Character 榨
+U+69a9 qián # Character 榩
+U+69aa mà # Character 榪
+#U+69ab sÇn # Character 榫
+U+69ac yuán # Character 榬
+U+69ad xiè # Character æ¦
+U+69ae róng # Character 榮
+U+69af shà # Character 榯
+#U+69b0 zhī # Character 榰
+#U+69b1 cuī # Character 榱
+U+69b2 yún # Character 榲
+U+69b3 tÃng # Character 榳
+U+69b4 liú # Character 榴
+U+69b5 róng # Character 榵
+U+69b6 táng # Character 榶
+U+69b7 què # Character 榷
+#U+69b8 zhÄi # Character 榸
+#U+69b9 sī # Character 榹
+U+69ba shèng # Character 榺
+U+69bb tà # Character 榻
+U+69bc kè # Character 榼
+#U+69bd xī # Character 榽
+U+69be gù # Character 榾
+#U+69bf qī # Character 榿
+#U+69c0 kÇo # Character æ§
+#U+69c1 gÇo # Character æ§
+#U+69c2 sÅ«n # Character æ§
+U+69c3 pán # Character æ§
+#U+69c4 tÄo # Character æ§
+U+69c5 gé # Character æ§
+U+69c6 xún # Character æ§
+#U+69c7 diÄn # Character æ§
+U+69c8 nòu # Character æ§
+U+69c9 jà # Character æ§
+U+69ca shuò # Character æ§
+U+69cb gòu # Character æ§
+U+69cc chuà # Character æ§
+#U+69cd qiÄng # Character æ§
+#U+69ce chÄ # Character æ§
+#U+69cf qiÇn # Character æ§
+U+69d0 huái # Character æ§
+U+69d1 méi # Character æ§
+U+69d2 xù # Character æ§
+U+69d3 gà ng # Character æ§
+#U+69d4 gÄo # Character æ§
+U+69d5 zhuó # Character æ§
+U+69d6 tuò # Character æ§
+U+69d7 ? # Character æ§
+U+69d8 yà ng # Character æ§
+#U+69d9 diÄn # Character æ§
+#U+69da jiÇ # Character æ§
+#U+69db kÇn # Character æ§
+U+69dc zuì # Character æ§
+U+69dd ? # Character æ§
+U+69de ? # Character æ§
+#U+69df bÄ«n # Character æ§
+#U+69e0 zhÅ« # Character æ§
+U+69e1 ? # Character 槡
+U+69e2 xà # Character 槢
+#U+69e3 qÇ # Character 槣
+U+69e4 lián # Character 槤
+U+69e5 huì # Character 槥
+U+69e6 yóng # Character 槦
+U+69e7 qià n # Character 槧
+#U+69e8 guÇ # Character 槨
+U+69e9 gà i # Character 槩
+U+69ea gà i # Character 槪
+U+69eb tuán # Character 槫
+U+69ec huà # Character 槬
+U+69ed cù # Character æ§
+#U+69ee sÄn # Character 槮
+#U+69ef cuī # Character 槯
+U+69f0 bèng # Character 槰
+#U+69f1 yÇu # Character 槱
+U+69f2 hú # Character 槲
+#U+69f3 jiÇng # Character 槳
+U+69f4 hù # Character 槴
+U+69f5 huà n # Character 槵
+U+69f6 kuì # Character 槶
+U+69f7 yì # Character 槷
+U+69f8 niè # Character 槸
+#U+69f9 gÄo # Character 槹
+#U+69fa kÄng # Character 槺
+#U+69fb guī # Character 槻
+#U+69fc guī # Character 槼
+U+69fd cáo # Character 槽
+U+69fe mán # Character 槾
+#U+69ff jÇn # Character 槿
diff --git a/resources/chars/latin1/row6a.trans b/resources/chars/latin1/row6a.trans
new file mode 100644
index 0000000..874cbe7
--- /dev/null
+++ b/resources/chars/latin1/row6a.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+6a00 dì # Character æ¨
+#U+6a01 zhuÄng # Character æ¨
+U+6a02 lè # Character æ¨
+U+6a03 láng # Character æ¨
+U+6a04 chén # Character æ¨
+#U+6a05 cÅng # Character æ¨
+U+6a06 là # Character æ¨
+#U+6a07 xiÅ« # Character æ¨
+U+6a08 qÃng # Character æ¨
+#U+6a09 shuÇng # Character æ¨
+U+6a0a fán # Character æ¨
+#U+6a0b tÅng # Character æ¨
+U+6a0c guà n # Character æ¨
+#U+6a0d jÄ« # Character æ¨
+#U+6a0e suÅ # Character æ¨
+#U+6a0f lÄi # Character æ¨
+#U+6a10 lÇ # Character æ¨
+U+6a11 liáng # Character æ¨
+U+6a12 mì # Character æ¨
+U+6a13 lóu # Character æ¨
+U+6a14 cháo # Character æ¨
+U+6a15 sù # Character æ¨
+#U+6a16 kÄ # Character æ¨
+#U+6a17 shÅ« # Character æ¨
+U+6a18 táng # Character æ¨
+#U+6a19 biÄo # Character æ¨
+U+6a1a lù # Character æ¨
+#U+6a1b jiÅ« # Character æ¨
+U+6a1c shù # Character æ¨
+#U+6a1d zhÄ # Character æ¨
+#U+6a1e shÅ« # Character æ¨
+#U+6a1f zhÄng # Character æ¨
+U+6a20 mén # Character æ¨
+U+6a21 mó # Character 模
+#U+6a22 niÇo # Character 樢
+U+6a23 yà ng # Character 樣
+U+6a24 tiáo # Character 樤
+U+6a25 péng # Character 樥
+U+6a26 zhù # Character 樦
+#U+6a27 shÄ # Character 樧
+#U+6a28 xī # Character 樨
+U+6a29 quán # Character 権
+U+6a2a héng # Character 横
+#U+6a2b jiÄn # Character 樫
+#U+6a2c cÅng # Character 樬
+U+6a2d ? # Character æ¨
+U+6a2e ? # Character 樮
+U+6a2f qiáng # Character 樯
+U+6a30 ? # Character 樰
+#U+6a31 yīng # Character 樱
+U+6a32 èr # Character 樲
+U+6a33 xÃn # Character 樳
+U+6a34 zhà # Character 樴
+U+6a35 qiáo # Character 樵
+#U+6a36 zuī # Character 樶
+#U+6a37 cÅng # Character 樷
+U+6a38 pú # Character 樸
+U+6a39 shù # Character 樹
+U+6a3a huà # Character 樺
+U+6a3b kuì # Character 樻
+#U+6a3c zhÄn # Character 樼
+#U+6a3d zūn # Character 樽
+U+6a3e yuè # Character 樾
+#U+6a3f zhÇn # Character 樿
+#U+6a40 xÄ« # Character æ©
+U+6a41 xún # Character æ©
+U+6a42 dià n # Character æ©
+#U+6a43 fÄ # Character æ©
+#U+6a44 gÇn # Character æ©
+U+6a45 mó # Character æ©
+#U+6a46 wÇ # Character æ©
+#U+6a47 qiÄo # Character æ©
+U+6a48 náo # Character æ©
+U+6a49 lìn # Character æ©
+U+6a4a liú # Character æ©
+U+6a4b qiáo # Character æ©
+U+6a4c xià n # Character æ©
+U+6a4d rùn # Character æ©
+U+6a4e fán # Character æ©
+#U+6a4f zhÇn # Character æ©
+U+6a50 tuò # Character æ©
+#U+6a51 lÇo # Character æ©
+U+6a52 yún # Character æ©
+U+6a53 shùn # Character æ©
+U+6a54 tuà # Character æ©
+#U+6a55 chÄng # Character æ©
+U+6a56 táng # Character æ©
+U+6a57 méng # Character æ©
+U+6a58 jú # Character æ©
+U+6a59 chéng # Character æ©
+U+6a5a sù # Character æ©
+U+6a5b jué # Character æ©
+U+6a5c jué # Character æ©
+#U+6a5d tÄn # Character æ©
+U+6a5e huì # Character æ©
+#U+6a5f jÄ« # Character æ©
+#U+6a60 nuÇ # Character æ©
+U+6a61 xià ng # Character 橡
+#U+6a62 tuÇ # Character æ©¢
+#U+6a63 nÇng # Character æ©£
+#U+6a64 ruÇ # Character 橤
+#U+6a65 zhū # Character 橥
+U+6a66 chuáng # Character 橦
+#U+6a67 zÄng # Character 橧
+U+6a68 fén # Character 橨
+U+6a69 qióng # Character 橩
+#U+6a6a rÇn # Character 橪
+U+6a6b héng # Character 橫
+U+6a6c cén # Character 橬
+#U+6a6d gÅ« # Character æ©
+#U+6a6e liÇ # Character æ©®
+U+6a6f là o # Character 橯
+#U+6a70 gÄo # Character æ©°
+U+6a71 chú # Character 橱
+U+6a72 ? # Character 橲
+U+6a73 ? # Character 橳
+U+6a74 ? # Character æ©´
+U+6a75 ? # Character 橵
+U+6a76 jà # Character 橶
+#U+6a77 dÅu # Character æ©·
+U+6a78 ? # Character 橸
+#U+6a79 lÇ # Character 橹
+U+6a7a ? # Character 橺
+U+6a7b ? # Character æ©»
+U+6a7c yuán # Character 橼
+U+6a7d tà # Character 橽
+#U+6a7e shū # Character 橾
+#U+6a7f jiÄng # Character æ©¿
+U+6a80 tán # Character æª
+#U+6a81 lÇn # Character æª
+U+6a82 nóng # Character æª
+#U+6a83 yÇn # Character æª
+U+6a84 xà # Character æª
+U+6a85 suì # Character æª
+#U+6a86 shÄn # Character æª
+U+6a87 zuì # Character æª
+U+6a88 xuán # Character æª
+#U+6a89 chÄng # Character æª
+U+6a8a gà n # Character æª
+#U+6a8b jÅ« # Character æª
+U+6a8c zuì # Character æª
+U+6a8d yì # Character æª
+U+6a8e qÃn # Character æª
+#U+6a8f pÇ # Character æª
+U+6a90 yán # Character æª
+U+6a91 léi # Character æª
+#U+6a92 fÄng # Character æª
+#U+6a93 huÇ # Character æª
+U+6a94 dà ng # Character æª
+U+6a95 jì # Character æª
+U+6a96 suì # Character æª
+U+6a97 bò # Character æª
+U+6a98 bì # Character æª
+#U+6a99 dÇng # Character æª
+#U+6a9a chÇ # Character æª
+#U+6a9b zhuÄ # Character æª
+U+6a9c kuà i # Character æª
+U+6a9d jà # Character æª
+#U+6a9e jiÄ # Character æª
+#U+6a9f jiÇ # Character æª
+U+6aa0 qÃng # Character æª
+U+6aa1 zhè # Character 檡
+#U+6aa2 jiÇn # Character 檢
+U+6aa3 qiáng # Character 檣
+U+6aa4 dà o # Character 檤
+#U+6aa5 yÇ # Character 檥
+#U+6aa6 biÇo # Character 檦
+#U+6aa7 sÅng # Character 檧
+#U+6aa8 shÄ # Character 檨
+#U+6aa9 lÇn # Character 檩
+U+6aaa ? # Character 檪
+U+6aab chá # Character 檫
+U+6aac méng # Character 檬
+U+6aad yÃn # Character æª
+U+6aae táo # Character 檮
+U+6aaf tái # Character 檯
+U+6ab0 mián # Character 檰
+U+6ab1 qà # Character 檱
+U+6ab2 ? # Character 檲
+#U+6ab3 bīn # Character 檳
+U+6ab4 huò # Character 檴
+U+6ab5 jì # Character 檵
+#U+6ab6 qiÄn # Character 檶
+U+6ab7 mà # Character 檷
+U+6ab8 nÃng # Character 檸
+#U+6ab9 yī # Character 檹
+#U+6aba gÇo # Character 檺
+#U+6abb kÇn # Character 檻
+U+6abc yìn # Character 檼
+U+6abd ér # Character 檽
+#U+6abe qÇng # Character 檾
+#U+6abf yÇn # Character 檿
+U+6ac0 qà # Character æ«
+U+6ac1 mì # Character æ«
+U+6ac2 zhà o # Character æ«
+U+6ac3 guì # Character æ«
+#U+6ac4 chÅ«n # Character æ«
+#U+6ac5 jÄ« # Character æ«
+U+6ac6 kuà # Character æ«
+U+6ac7 pó # Character æ«
+U+6ac8 dèng # Character æ«
+U+6ac9 chú # Character æ«
+U+6aca ? # Character æ«
+U+6acb mián # Character æ«
+#U+6acc yÅu # Character æ«
+U+6acd zhì # Character æ«
+U+6ace guà ng # Character æ«
+#U+6acf qiÄn # Character æ«
+#U+6ad0 lÄi # Character æ«
+#U+6ad1 lÄi # Character æ«
+U+6ad2 sà # Character æ«
+#U+6ad3 lÇ # Character æ«
+U+6ad4 lì # Character æ«
+U+6ad5 cuán # Character æ«
+#U+6ad6 lÇ # Character æ«
+U+6ad7 miè # Character æ«
+U+6ad8 huì # Character æ«
+#U+6ad9 Åu # Character æ«
+#U+6ada lÇ # Character æ«
+U+6adb jié # Character æ«
+#U+6adc gÄo # Character æ«
+U+6add dú # Character æ«
+U+6ade yuán # Character æ«
+U+6adf lì # Character æ«
+U+6ae0 fèi # Character æ«
+U+6ae1 zhuó # Character 櫡
+#U+6ae2 sÇu # Character æ«¢
+U+6ae3 lián # Character 櫣
+U+6ae4 ? # Character 櫤
+U+6ae5 chú # Character 櫥
+U+6ae6 ? # Character 櫦
+#U+6ae7 zhū # Character 櫧
+U+6ae8 lú # Character 櫨
+U+6ae9 yán # Character 櫩
+U+6aea lì # Character 櫪
+#U+6aeb zhū # Character 櫫
+U+6aec chèn # Character 櫬
+U+6aed jié # Character æ«
+U+6aee è # Character 櫮
+#U+6aef sū # Character 櫯
+U+6af0 huái # Character 櫰
+U+6af1 niè # Character 櫱
+U+6af2 yù # Character 櫲
+U+6af3 lóng # Character 櫳
+U+6af4 là i # Character 櫴
+U+6af5 ? # Character 櫵
+#U+6af6 xiÇn # Character 櫶
+U+6af7 ? # Character æ«·
+#U+6af8 jÇ # Character 櫸
+#U+6af9 xiÄo # Character 櫹
+U+6afa lÃng # Character 櫺
+#U+6afb yīng # Character 櫻
+#U+6afc jiÄn # Character 櫼
+#U+6afd yÇn # Character 櫽
+U+6afe yóu # Character 櫾
+U+6aff yÃng # Character æ«¿
diff --git a/resources/chars/latin1/row6b.trans b/resources/chars/latin1/row6b.trans
new file mode 100644
index 0000000..c16c5f1
--- /dev/null
+++ b/resources/chars/latin1/row6b.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+6b00 xiÄng # Character æ¬
+U+6b01 nóng # Character æ¬
+U+6b02 bó # Character æ¬
+U+6b03 chán # Character æ¬
+U+6b04 lán # Character æ¬
+#U+6b05 jÇ # Character æ¬
+#U+6b06 shuÄng # Character æ¬
+U+6b07 shè # Character æ¬
+U+6b08 wéi # Character æ¬
+U+6b09 còng # Character æ¬
+U+6b0a quán # Character æ¬
+U+6b0b qú # Character æ¬
+U+6b0c ? # Character æ¬
+U+6b0d ? # Character æ¬
+U+6b0e yù # Character æ¬
+U+6b0f luó # Character æ¬
+#U+6b10 lÇ # Character æ¬
+U+6b11 zà n # Character æ¬
+U+6b12 luán # Character æ¬
+#U+6b13 dÇng # Character æ¬
+U+6b14 jué # Character æ¬
+U+6b15 ? # Character æ¬
+#U+6b16 lÇn # Character æ¬
+U+6b17 lán # Character æ¬
+#U+6b18 zhÇ # Character æ¬
+U+6b19 léi # Character æ¬
+#U+6b1a lÇ # Character æ¬
+U+6b1b bà # Character æ¬
+U+6b1c náng # Character æ¬
+U+6b1d yù # Character æ¬
+U+6b1e lÃng # Character æ¬
+U+6b1f ? # Character æ¬
+U+6b20 qià n # Character æ¬
+U+6b21 cì # Character 次
+U+6b22 huan # Character 欢
+#U+6b23 xīn # Character 欣
+U+6b24 yú # Character 欤
+U+6b25 yù # Character 欥
+#U+6b26 qiÄn # Character 欦
+#U+6b27 Åu # Character 欧
+#U+6b28 xū # Character 欨
+#U+6b29 chÄo # Character 欩
+U+6b2a chù # Character 欪
+#U+6b2b chī # Character 欫
+U+6b2c kà i # Character 欬
+U+6b2d yì # Character æ¬
+U+6b2e jué # Character 欮
+U+6b2f xà # Character 欯
+#U+6b30 xū # Character 欰
+U+6b31 xià # Character 欱
+U+6b32 yù # Character 欲
+U+6b33 kuà i # Character 欳
+U+6b34 láng # Character 欴
+#U+6b35 kuÇn # Character 欵
+U+6b36 shuò # Character 欶
+#U+6b37 xī # Character 欷
+#U+6b38 Çi # Character 欸
+#U+6b39 yī # Character 欹
+#U+6b3a qī # Character 欺
+#U+6b3b hū # Character 欻
+#U+6b3c chÇ # Character 欼
+#U+6b3d qīn # Character 欽
+#U+6b3e kuÇn # Character 款
+#U+6b3f kÇn # Character 欿
+#U+6b40 kuÇn # Character æ
+#U+6b41 kÇn # Character æ
+U+6b42 chuán # Character æ
+U+6b43 shà # Character æ
+U+6b44 ? # Character æ
+#U+6b45 yÄ«n # Character æ
+#U+6b46 xÄ«n # Character æ
+#U+6b47 xiÄ # Character æ
+U+6b48 yú # Character æ
+U+6b49 qià n # Character æ
+#U+6b4a xiÄo # Character æ
+U+6b4b yà # Character æ
+#U+6b4c gÄ # Character æ
+#U+6b4d wÅ« # Character æ
+U+6b4e tà n # Character æ
+U+6b4f jìn # Character æ
+#U+6b50 Åu # Character æ
+#U+6b51 hÅ« # Character æ
+U+6b52 tì # Character æ
+#U+6b53 huÄn # Character æ
+#U+6b54 xÅ« # Character æ
+U+6b55 pèn # Character æ
+#U+6b56 xÄ« # Character æ
+U+6b57 xià o # Character æ
+#U+6b58 xÅ« # Character æ
+U+6b59 xì # Character æ
+U+6b5a ? # Character æ
+U+6b5b lià n # Character æ
+U+6b5c chù # Character æ
+U+6b5d yì # Character æ
+#U+6b5e kÇn # Character æ
+U+6b5f yú # Character æ
+U+6b60 chuò # Character æ
+U+6b61 huan # Character æ¡
+#U+6b62 zhÇ # Character æ¢
+U+6b63 zhèng # Character æ£
+#U+6b64 cÇ # Character æ¤
+U+6b65 bù # Character æ¥
+#U+6b66 wÇ # Character æ¦
+U+6b67 qà # Character æ§
+U+6b68 bù # Character æ¨
+U+6b69 bù # Character æ©
+#U+6b6a wÄi # Character æª
+U+6b6b jù # Character æ«
+U+6b6c qián # Character æ¬
+U+6b6d chà # Character æ
+U+6b6e sè # Character æ®
+#U+6b6f chÇ # Character æ¯
+U+6b70 sè # Character æ°
+#U+6b71 zhÇng # Character æ±
+U+6b72 suì # Character æ²
+U+6b73 suì # Character æ³
+U+6b74 lì # Character æ´
+U+6b75 cuò # Character æµ
+U+6b76 yú # Character æ¶
+U+6b77 lì # Character æ·
+#U+6b78 guÄ« # Character æ¸
+#U+6b79 dÇi # Character æ¹
+#U+6b7a dÇi # Character æº
+#U+6b7b sÇ # Character æ»
+#U+6b7c jiÄn # Character æ¼
+U+6b7d zhé # Character æ½
+U+6b7e mò # Character æ¾
+U+6b7f mò # Character æ¿
+#U+6b80 yÇo # Character æ®
+U+6b81 mò # Character æ®
+U+6b82 cú # Character æ®
+#U+6b83 yÄng # Character æ®
+#U+6b84 tiÇn # Character æ®
+#U+6b85 shÄng # Character æ®
+U+6b86 dà i # Character æ®
+#U+6b87 shÄng # Character æ®
+U+6b88 xù # Character æ®
+U+6b89 xùn # Character æ®
+#U+6b8a shÅ« # Character æ®
+U+6b8b cán # Character æ®
+U+6b8c jué # Character æ®
+#U+6b8d piÇo # Character æ®
+U+6b8e qià # Character æ®
+U+6b8f qiù # Character æ®
+U+6b90 sù # Character æ®
+U+6b91 qÃng # Character æ®
+#U+6b92 yÇn # Character æ®
+U+6b93 lià n # Character æ®
+U+6b94 yì # Character æ®
+#U+6b95 fÇu # Character æ®
+U+6b96 zhà # Character æ®
+U+6b97 yè # Character æ®
+U+6b98 cán # Character æ®
+#U+6b99 hÅ«n # Character æ®
+#U+6b9a dÄn # Character æ®
+U+6b9b jà # Character æ®
+U+6b9c yè # Character æ®
+U+6b9d ? # Character æ®
+#U+6b9e yÇn # Character æ®
+#U+6b9f wÄn # Character æ®
+U+6ba0 chòu # Character æ®
+U+6ba1 bìn # Character 殡
+U+6ba2 tì # Character 殢
+#U+6ba3 jÇn # Character 殣
+#U+6ba4 shÄng # Character 殤
+U+6ba5 yÃn # Character 殥
+#U+6ba6 diÄo # Character 殦
+U+6ba7 cù # Character 殧
+U+6ba8 huì # Character 殨
+U+6ba9 cuà n # Character 殩
+U+6baa yì # Character 殪
+#U+6bab dÄn # Character 殫
+U+6bac dù # Character 殬
+#U+6bad jiÄng # Character æ®
+U+6bae lià n # Character 殮
+U+6baf bìn # Character 殯
+U+6bb0 dú # Character 殰
+U+6bb1 ? # Character æ®±
+#U+6bb2 jiÄn # Character 殲
+#U+6bb3 shū # Character 殳
+#U+6bb4 Åu # Character æ®´
+U+6bb5 duà n # Character 段
+U+6bb6 zhù # Character 殶
+#U+6bb7 yīn # Character 殷
+U+6bb8 qìng # Character 殸
+U+6bb9 yì # Character 殹
+#U+6bba shÄ # Character 殺
+U+6bbb què # Character 殻
+U+6bbc ké # Character 殼
+U+6bbd yáo # Character 殽
+U+6bbe jùn # Character 殾
+U+6bbf dià n # Character 殿
+#U+6bc0 huÇ # Character æ¯
+#U+6bc1 huÇ # Character æ¯
+#U+6bc2 gÇ # Character æ¯
+U+6bc3 què # Character æ¯
+#U+6bc4 jÄ« # Character æ¯
+U+6bc5 yì # Character æ¯
+#U+6bc6 Åu # Character æ¯
+#U+6bc7 huÇ # Character æ¯
+U+6bc8 duà n # Character æ¯
+#U+6bc9 yÄ« # Character æ¯
+#U+6bca xiÄo # Character æ¯
+U+6bcb wú # Character æ¯
+U+6bcc guà n # Character æ¯
+#U+6bcd mÇ # Character æ¯
+#U+6bce mÄi # Character æ¯
+#U+6bcf mÄi # Character æ¯
+#U+6bd0 Çi # Character æ¯
+#U+6bd1 zuÇ # Character æ¯
+U+6bd2 dú # Character æ¯
+U+6bd3 yù # Character æ¯
+#U+6bd4 bÇ # Character æ¯
+U+6bd5 bì # Character æ¯
+U+6bd6 bì # Character æ¯
+U+6bd7 pà # Character æ¯
+U+6bd8 pà # Character æ¯
+U+6bd9 bì # Character æ¯
+U+6bda chán # Character æ¯
+U+6bdb máo # Character æ¯
+U+6bdc ? # Character æ¯
+U+6bdd ? # Character æ¯
+U+6bde pú # Character æ¯
+U+6bdf ? # Character æ¯
+#U+6be0 jiÄ # Character æ¯
+#U+6be1 zhÄn # Character 毡
+#U+6be2 sÄi # Character 毢
+U+6be3 mù # Character 毣
+U+6be4 tuò # Character 毤
+U+6be5 xún # Character 毥
+U+6be6 èr # Character 毦
+U+6be7 róng # Character 毧
+#U+6be8 xiÇn # Character 毨
+U+6be9 jú # Character 毩
+U+6bea mú # Character 毪
+U+6beb háo # Character 毫
+U+6bec qiú # Character 毬
+U+6bed dòu # Character æ¯
+U+6bee ? # Character 毮
+#U+6bef tÇn # Character 毯
+U+6bf0 péi # Character 毰
+U+6bf1 jú # Character 毱
+U+6bf2 duó # Character 毲
+U+6bf3 cuì # Character 毳
+#U+6bf4 bī # Character 毴
+#U+6bf5 sÄn # Character 毵
+U+6bf6 ? # Character 毶
+U+6bf7 mà o # Character 毷
+#U+6bf8 suī # Character 毸
+#U+6bf9 yū # Character 毹
+#U+6bfa yū # Character 毺
+U+6bfb tuò # Character 毻
+U+6bfc hé # Character 毼
+U+6bfd jià n # Character 毽
+U+6bfe tà # Character 毾
+#U+6bff sÄn # Character 毿
diff --git a/resources/chars/latin1/row6c.trans b/resources/chars/latin1/row6c.trans
new file mode 100644
index 0000000..4a05d93
--- /dev/null
+++ b/resources/chars/latin1/row6c.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+6c00 lÇ # Character æ°
+U+6c01 mú # Character æ°
+U+6c02 là # Character æ°
+U+6c03 tóng # Character æ°
+#U+6c04 rÇng # Character æ°
+#U+6c05 chÇng # Character æ°
+#U+6c06 pÇ # Character æ°
+U+6c07 luó # Character æ°
+#U+6c08 zhÄn # Character æ°
+U+6c09 sà o # Character æ°
+#U+6c0a zhÄn # Character æ°
+U+6c0b méng # Character æ°
+U+6c0c luó # Character æ°
+U+6c0d qú # Character æ°
+U+6c0e dié # Character æ°
+U+6c0f shì # Character æ°
+#U+6c10 dÇ # Character æ°
+U+6c11 mÃn # Character æ°
+U+6c12 jué # Character æ°
+U+6c13 máng # Character æ°
+U+6c14 qì # Character æ°
+#U+6c15 piÄ # Character æ°
+#U+6c16 nÇi # Character æ°
+U+6c17 qì # Character æ°
+#U+6c18 dÄo # Character æ°
+#U+6c19 xiÄn # Character æ°
+#U+6c1a chuÄn # Character æ°
+#U+6c1b fÄn # Character æ°
+U+6c1c rì # Character æ°
+U+6c1d nèi # Character æ°
+U+6c1e ? # Character æ°
+U+6c1f fú # Character æ°
+#U+6c20 shÄn # Character æ°
+#U+6c21 dÅng # Character æ°¡
+#U+6c22 qīng # Character 氢
+U+6c23 qì # Character 氣
+#U+6c24 yīn # Character 氤
+#U+6c25 xī # Character 氥
+U+6c26 hà i # Character 氦
+#U+6c27 yÇng # Character æ°§
+#U+6c28 Än # Character æ°¨
+U+6c29 yà # Character 氩
+U+6c2a kè # Character 氪
+#U+6c2b qīng # Character 氫
+U+6c2c yà # Character 氬
+#U+6c2d dÅng # Character æ°
+U+6c2e dà n # Character 氮
+#U+6c2f lÇ # Character æ°¯
+#U+6c30 qīng # Character 氰
+#U+6c31 yÇng # Character æ°±
+#U+6c32 yūn # Character 氲
+#U+6c33 yūn # Character 氳
+#U+6c34 shuÇ # Character æ°´
+U+6c35 ? # Character æ°µ
+#U+6c36 zhÄng # Character æ°¶
+#U+6c37 bīng # Character 氷
+#U+6c38 yÇng # Character æ°¸
+U+6c39 dà ng # Character 氹
+U+6c3a ? # Character æ°º
+U+6c3b lè # Character 氻
+U+6c3c nì # Character 氼
+#U+6c3d tÇn # Character æ°½
+U+6c3e fà n # Character 氾
+#U+6c3f guÇ # Character æ°¿
+#U+6c40 tÄ«ng # Character æ±
+#U+6c41 zhÄ« # Character æ±
+U+6c42 qiú # Character æ±
+#U+6c43 bÄ«n # Character æ±
+U+6c44 zè # Character æ±
+#U+6c45 miÇn # Character æ±
+#U+6c46 cuÄn # Character æ±
+U+6c47 huì # Character æ±
+#U+6c48 diÄo # Character æ±
+U+6c49 hà n # Character æ±
+U+6c4a chà # Character æ±
+U+6c4b zhuó # Character æ±
+U+6c4c chuà n # Character æ±
+U+6c4d wán # Character æ±
+U+6c4e fà n # Character æ±
+U+6c4f dà i # Character æ±
+U+6c50 xì # Character æ±
+#U+6c51 tuÅ # Character æ±
+U+6c52 máng # Character æ±
+U+6c53 qiú # Character æ±
+U+6c54 qì # Character æ±
+U+6c55 shà n # Character æ±
+U+6c56 pà i # Character æ±
+U+6c57 hà n # Character æ±
+#U+6c58 qiÄn # Character æ±
+#U+6c59 wÅ« # Character æ±
+#U+6c5a wÅ« # Character æ±
+U+6c5b xùn # Character æ±
+U+6c5c sì # Character æ±
+#U+6c5d rÇ # Character æ±
+#U+6c5e gÇng # Character æ±
+#U+6c5f jiÄng # Character æ±
+U+6c60 chà # Character æ±
+#U+6c61 wū # Character 污
+U+6c62 ? # Character æ±¢
+U+6c63 ? # Character æ±£
+#U+6c64 tÄng # Character 汤
+#U+6c65 zhī # Character 汥
+U+6c66 chà # Character 汦
+#U+6c67 qiÄn # Character 汧
+U+6c68 mì # Character 汨
+U+6c69 yù # Character 汩
+#U+6c6a wÄng # Character 汪
+U+6c6b qìng # Character 汫
+#U+6c6c jÇng # Character 汬
+U+6c6d ruì # Character æ±
+#U+6c6e jūn # Character 汮
+U+6c6f hóng # Character 汯
+U+6c70 tà i # Character 汰
+#U+6c71 quÇn # Character æ±±
+U+6c72 jà # Character 汲
+U+6c73 bià n # Character 汳
+U+6c74 bià n # Character 汴
+U+6c75 gà n # Character 汵
+U+6c76 wèn # Character 汶
+#U+6c77 zhÅng # Character æ±·
+#U+6c78 fÄng # Character 汸
+#U+6c79 xiÅng # Character æ±¹
+U+6c7a jué # Character 決
+#U+6c7b hÇng # Character æ±»
+U+6c7c ? # Character æ±¼
+U+6c7d qì # Character 汽
+U+6c7e fén # Character 汾
+U+6c7f xù # Character 汿
+U+6c80 xù # Character æ²
+U+6c81 qìn # Character æ²
+U+6c82 yà # Character æ²
+U+6c83 wò # Character æ²
+U+6c84 yún # Character æ²
+U+6c85 yuán # Character æ²
+U+6c86 háng # Character æ²
+#U+6c87 yÇn # Character æ²
+U+6c88 chén # Character æ²
+U+6c89 chén # Character æ²
+U+6c8a dà n # Character æ²
+U+6c8b yóu # Character æ²
+U+6c8c dùn # Character æ²
+U+6c8d hù # Character æ²
+U+6c8e huò # Character æ²
+#U+6c8f qÄ« # Character æ²
+U+6c90 mù # Character æ²
+U+6c91 róu # Character æ²
+U+6c92 méi # Character æ²
+U+6c93 tà # Character æ²
+#U+6c94 miÇn # Character æ²
+U+6c95 wù # Character æ²
+#U+6c96 chÅng # Character æ²
+#U+6c97 tiÄn # Character æ²
+#U+6c98 bÇ # Character æ²
+#U+6c99 shÄ # Character æ²
+#U+6c9a zhÇ # Character æ²
+U+6c9b pèi # Character æ²
+U+6c9c pà n # Character æ²
+#U+6c9d zhuÇ # Character æ²
+#U+6c9e zÄ # Character æ²
+#U+6c9f gÅu # Character æ²
+U+6ca0 liú # Character æ²
+U+6ca1 méi # Character 没
+U+6ca2 zé # Character 沢
+#U+6ca3 fÄng # Character æ²£
+U+6ca4 òu # Character 沤
+U+6ca5 lì # Character 沥
+U+6ca6 lún # Character 沦
+#U+6ca7 cÄng # Character 沧
+U+6ca8 féng # Character 沨
+U+6ca9 wéi # Character 沩
+U+6caa hù # Character 沪
+U+6cab mò # Character 沫
+U+6cac mèi # Character 沬
+U+6cad shù # Character æ²
+#U+6cae jū # Character 沮
+#U+6caf zÇn # Character 沯
+#U+6cb0 tuÅ # Character æ²°
+U+6cb1 tuó # Character 沱
+U+6cb2 tuó # Character 沲
+U+6cb3 hé # Character 河
+U+6cb4 lì # Character 沴
+#U+6cb5 mÇ # Character æ²µ
+U+6cb6 yà # Character 沶
+#U+6cb7 fÄ # Character æ²·
+U+6cb8 fèi # Character 沸
+U+6cb9 yóu # Character 油
+U+6cba tián # Character 沺
+U+6cbb zhì # Character 治
+#U+6cbc zhÇo # Character æ²¼
+#U+6cbd gū # Character 沽
+#U+6cbe zhÄn # Character æ²¾
+U+6cbf yán # Character 沿
+#U+6cc0 sÄ« # Character æ³
+U+6cc1 kuà ng # Character æ³
+#U+6cc2 jiÇng # Character æ³
+U+6cc3 jù # Character æ³
+U+6cc4 xiè # Character æ³
+U+6cc5 qiú # Character æ³
+#U+6cc6 yÄ« # Character æ³
+#U+6cc7 jiÄ # Character æ³
+#U+6cc8 zhÅng # Character æ³
+U+6cc9 quán # Character æ³
+#U+6cca pÅ # Character æ³
+U+6ccb huì # Character æ³
+U+6ccc mì # Character æ³
+#U+6ccd bÄn # Character æ³
+U+6cce zhuó # Character æ³
+U+6ccf chù # Character æ³
+U+6cd0 lè # Character æ³
+#U+6cd1 yÇu # Character æ³
+#U+6cd2 gÅ« # Character æ³
+U+6cd3 hóng # Character æ³
+#U+6cd4 gÄn # Character æ³
+#U+6cd5 fÇ # Character æ³
+#U+6cd6 mÇo # Character æ³
+U+6cd7 sì # Character æ³
+#U+6cd8 hÅ« # Character æ³
+U+6cd9 pÃng # Character æ³
+#U+6cda cÇ # Character æ³
+U+6cdb fà n # Character æ³
+U+6cdc chà # Character æ³
+U+6cdd sù # Character æ³
+U+6cde nìng # Character æ³
+#U+6cdf chÄng # Character æ³
+U+6ce0 lÃng # Character æ³
+U+6ce1 pà o # Character 泡
+#U+6ce2 bÅ # Character æ³¢
+U+6ce3 qì # Character 泣
+U+6ce4 sì # Character 泤
+U+6ce5 nà # Character 泥
+U+6ce6 jú # Character 泦
+U+6ce7 yuè # Character 泧
+U+6ce8 zhù # Character 注
+#U+6ce9 shÄng # Character 泩
+U+6cea lèi # Character 泪
+U+6ceb xuà n # Character 泫
+U+6cec xuè # Character 泬
+#U+6ced fÅ« # Character æ³
+U+6cee pà n # Character 泮
+#U+6cef mÇn # Character 泯
+U+6cf0 tà i # Character 泰
+#U+6cf1 yÄng # Character æ³±
+#U+6cf2 jÇ # Character æ³²
+#U+6cf3 yÇng # Character æ³³
+U+6cf4 guà n # Character 泴
+U+6cf5 bèng # Character 泵
+U+6cf6 xué # Character 泶
+U+6cf7 lóng # Character 泷
+U+6cf8 lú # Character 泸
+U+6cf9 ? # Character æ³¹
+U+6cfa bó # Character 泺
+U+6cfb xiè # Character 泻
+U+6cfc po # Character æ³¼
+U+6cfd zé # Character 泽
+#U+6cfe jīng # Character 泾
+U+6cff yÃn # Character 泿
diff --git a/resources/chars/latin1/row6d.trans b/resources/chars/latin1/row6d.trans
new file mode 100644
index 0000000..a83ab99
--- /dev/null
+++ b/resources/chars/latin1/row6d.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+6d00 zhÅu # Character æ´
+U+6d01 jié # Character æ´
+U+6d02 yì # Character æ´
+#U+6d03 huÄ« # Character æ´
+U+6d04 huà # Character æ´
+#U+6d05 zuÇ # Character æ´
+U+6d06 chéng # Character æ´
+#U+6d07 yÄ«n # Character æ´
+U+6d08 wéi # Character æ´
+U+6d09 hòu # Character æ´
+U+6d0a jià n # Character æ´
+U+6d0b yáng # Character æ´
+U+6d0c liè # Character æ´
+U+6d0d sì # Character æ´
+U+6d0e jì # Character æ´
+U+6d0f ér # Character æ´
+U+6d10 xÃng # Character æ´
+U+6d11 fú # Character æ´
+#U+6d12 sÇ # Character æ´
+#U+6d13 suÇ # Character æ´
+#U+6d14 zhÇ # Character æ´
+#U+6d15 yÄ«n # Character æ´
+U+6d16 wú # Character æ´
+#U+6d17 xÇ # Character æ´
+#U+6d18 kÇo # Character æ´
+#U+6d19 zhÅ« # Character æ´
+U+6d1a jià ng # Character æ´
+U+6d1b luò # Character æ´
+U+6d1c ? # Character æ´
+U+6d1d à n # Character æ´
+U+6d1e dòng # Character æ´
+U+6d1f yà # Character æ´
+U+6d20 móu # Character æ´
+#U+6d21 lÄi # Character æ´¡
+#U+6d22 yī # Character 洢
+#U+6d23 mÇ # Character æ´£
+U+6d24 quán # Character 洤
+#U+6d25 jīn # Character 津
+U+6d26 mò # Character 洦
+#U+6d27 wÄi # Character æ´§
+U+6d28 xiáo # Character 洨
+U+6d29 xiè # Character 洩
+U+6d2a hóng # Character 洪
+U+6d2b xù # Character 洫
+U+6d2c shuò # Character 洬
+#U+6d2d kuÄng # Character æ´
+#U+6d2e tÄo # Character æ´®
+U+6d2f qiè # Character 洯
+U+6d30 jù # Character 洰
+#U+6d31 Är # Character æ´±
+#U+6d32 zhÅu # Character æ´²
+U+6d33 rù # Character 洳
+U+6d34 pÃng # Character æ´´
+U+6d35 xún # Character 洵
+#U+6d36 xiÅng # Character æ´¶
+U+6d37 zhì # Character 洷
+#U+6d38 guÄng # Character æ´¸
+U+6d39 huán # Character 洹
+U+6d3a mÃng # Character æ´º
+U+6d3b huó # Character 活
+#U+6d3c wÄ # Character æ´¼
+U+6d3d qià # Character 洽
+U+6d3e pà i # Character 派
+#U+6d3f wū # Character 洿
+#U+6d40 qÇ # Character æµ
+U+6d41 liú # Character æµ
+U+6d42 yì # Character æµ
+U+6d43 jiá # Character æµ
+U+6d44 jìng # Character æµ
+#U+6d45 qiÇn # Character æµ
+#U+6d46 jiÄng # Character æµ
+#U+6d47 jiÄo # Character æµ
+U+6d48 chéng # Character æµ
+#U+6d49 shÄ« # Character æµ
+U+6d4a zhuó # Character æµ
+U+6d4b cè # Character æµ
+U+6d4c ? # Character æµ
+U+6d4d kuà i # Character æµ
+U+6d4e jì # Character æµ
+U+6d4f liú # Character æµ
+#U+6d50 chÇn # Character æµ
+U+6d51 hún # Character æµ
+#U+6d52 hÇ # Character æµ
+U+6d53 nóng # Character æµ
+U+6d54 xún # Character æµ
+U+6d55 jìn # Character æµ
+U+6d56 liè # Character æµ
+U+6d57 qiú # Character æµ
+#U+6d58 wÄi # Character æµ
+U+6d59 zhè # Character æµ
+U+6d5a jùn # Character æµ
+U+6d5b hà n # Character æµ
+#U+6d5c bÄng # Character æµ
+U+6d5d máng # Character æµ
+U+6d5e zhuó # Character æµ
+U+6d5f yóu # Character æµ
+#U+6d60 xÄ« # Character æµ
+U+6d61 bó # Character 浡
+U+6d62 dòu # Character 浢
+#U+6d63 wÇn # Character æµ£
+U+6d64 hóng # Character 浤
+U+6d65 yì # Character 浥
+#U+6d66 pÇ # Character 浦
+#U+6d67 yÇng # Character 浧
+#U+6d68 lÇn # Character 浨
+U+6d69 hà o # Character 浩
+U+6d6a là ng # Character 浪
+#U+6d6b hÇn # Character 浫
+#U+6d6c lÇ # Character 浬
+#U+6d6d gÄng # Character æµ
+U+6d6e fú # Character 浮
+U+6d6f wú # Character 浯
+U+6d70 lià n # Character 浰
+U+6d71 chún # Character 浱
+U+6d72 féng # Character 浲
+U+6d73 yì # Character 浳
+U+6d74 yù # Character 浴
+U+6d75 tóng # Character 浵
+U+6d76 láo # Character 浶
+#U+6d77 hÇi # Character æµ·
+U+6d78 jìn # Character 浸
+U+6d79 jiá # Character 浹
+#U+6d7a chÅng # Character 浺
+#U+6d7b wÄng # Character æµ»
+#U+6d7c mÄi # Character æµ¼
+#U+6d7d suī # Character 浽
+#U+6d7e chÄng # Character æµ¾
+U+6d7f pèi # Character 浿
+U+6d80 xià n # Character æ¶
+U+6d81 shèn # Character æ¶
+U+6d82 tu # Character æ¶
+U+6d83 kùn # Character æ¶
+#U+6d84 pÄ«n # Character æ¶
+U+6d85 niè # Character æ¶
+U+6d86 hà n # Character æ¶
+#U+6d87 jÄ«ng # Character æ¶
+#U+6d88 xiÄo # Character æ¶
+U+6d89 shè # Character æ¶
+U+6d8a nià n # Character æ¶
+#U+6d8b tÅ« # Character æ¶
+#U+6d8c yÇng # Character æ¶
+U+6d8d xià o # Character æ¶
+U+6d8e xián # Character æ¶
+#U+6d8f tÇng # Character æ¶
+U+6d90 é # Character æ¶
+U+6d91 sù # Character æ¶
+#U+6d92 tÅ«n # Character æ¶
+#U+6d93 juÄn # Character æ¶
+U+6d94 cén # Character æ¶
+U+6d95 tì # Character æ¶
+U+6d96 lì # Character æ¶
+U+6d97 shuì # Character æ¶
+U+6d98 sì # Character æ¶
+U+6d99 lèi # Character æ¶
+U+6d9a shuì # Character æ¶
+#U+6d9b tÄo # Character æ¶
+U+6d9c dú # Character æ¶
+U+6d9d là o # Character æ¶
+U+6d9e lái # Character æ¶
+U+6d9f lián # Character æ¶
+U+6da0 wéi # Character æ¶
+#U+6da1 wŠ# Character 涡
+U+6da2 yún # Character 涢
+U+6da3 huà n # Character 涣
+U+6da4 dà # Character 涤
+U+6da5 ? # Character 涥
+U+6da6 rùn # Character 润
+U+6da7 jià n # Character 涧
+#U+6da8 zhÇng # Character 涨
+U+6da9 sè # Character 涩
+U+6daa fú # Character 涪
+U+6dab guà n # Character 涫
+U+6dac xìng # Character 涬
+U+6dad shòu # Character æ¶
+U+6dae shuà n # Character 涮
+U+6daf yá # Character 涯
+U+6db0 chuò # Character 涰
+U+6db1 zhà ng # Character 涱
+U+6db2 yè # Character 液
+#U+6db3 kÅng # Character 涳
+U+6db4 wò # Character 涴
+U+6db5 hán # Character 涵
+#U+6db6 tuŠ# Character 涶
+#U+6db7 dÅng # Character 涷
+U+6db8 hé # Character 涸
+#U+6db9 wŠ# Character 涹
+#U+6dba jū # Character 涺
+U+6dbb gà n # Character 涻
+U+6dbc liáng # Character 涼
+#U+6dbd hūn # Character 涽
+U+6dbe tà # Character 涾
+U+6dbf zhuó # Character 涿
+U+6dc0 dià n # Character æ·
+U+6dc1 qiè # Character æ·
+U+6dc2 dé # Character æ·
+U+6dc3 juà n # Character æ·
+#U+6dc4 zÄ« # Character æ·
+#U+6dc5 xÄ« # Character æ·
+U+6dc6 yáo # Character æ·
+U+6dc7 qà # Character æ·
+#U+6dc8 gÇ # Character æ·
+#U+6dc9 guÇ # Character æ·
+U+6dca hà n # Character æ·
+U+6dcb lÃn # Character æ·
+#U+6dcc tÇng # Character æ·
+#U+6dcd zhÅu # Character æ·
+#U+6dce pÄng # Character æ·
+U+6dcf hà o # Character æ·
+#U+6dd0 chÄng # Character æ·
+U+6dd1 shú # Character æ·
+#U+6dd2 qÄ« # Character æ·
+#U+6dd3 fÄng # Character æ·
+U+6dd4 chì # Character æ·
+U+6dd5 lù # Character æ·
+U+6dd6 nà o # Character æ·
+U+6dd7 jú # Character æ·
+U+6dd8 táo # Character æ·
+U+6dd9 cóng # Character æ·
+U+6dda lèi # Character æ·
+U+6ddb zhì # Character æ·
+U+6ddc péng # Character æ·
+U+6ddd féi # Character æ·
+#U+6dde sÅng # Character æ·
+#U+6ddf tiÇn # Character æ·
+U+6de0 pì # Character æ·
+U+6de1 dà n # Character 淡
+U+6de2 yù # Character 淢
+U+6de3 nà # Character 淣
+#U+6de4 yū # Character 淤
+U+6de5 lù # Character 淥
+U+6de6 gà n # Character 淦
+U+6de7 mì # Character 淧
+U+6de8 jìng # Character 淨
+U+6de9 lÃng # Character æ·©
+U+6dea lún # Character 淪
+U+6deb yÃn # Character æ·«
+U+6dec cuì # Character 淬
+U+6ded qú # Character æ·
+U+6dee huái # Character 淮
+U+6def yù # Character 淯
+U+6df0 nià n # Character 淰
+#U+6df1 shÄn # Character æ·±
+U+6df2 piáo # Character 淲
+U+6df3 chún # Character 淳
+U+6df4 wà # Character 淴
+#U+6df5 yuÄn # Character æ·µ
+U+6df6 lái # Character 淶
+U+6df7 hùn # Character 混
+#U+6df8 qīng # Character 淸
+#U+6df9 yÄn # Character æ·¹
+#U+6dfa qiÇn # Character æ·º
+#U+6dfb tiÄn # Character æ·»
+#U+6dfc miÇo # Character æ·¼
+#U+6dfd zhÇ # Character æ·½
+#U+6dfe yÇn # Character æ·¾
+U+6dff mì # Character 淿
diff --git a/resources/chars/latin1/row6e.trans b/resources/chars/latin1/row6e.trans
new file mode 100644
index 0000000..2ef5834
--- /dev/null
+++ b/resources/chars/latin1/row6e.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+6e00 bÄn # Character æ¸
+#U+6e01 yuÄn # Character æ¸
+U+6e02 wèn # Character æ¸
+U+6e03 rè # Character æ¸
+#U+6e04 fÄi # Character æ¸
+#U+6e05 qÄ«ng # Character æ¸
+#U+6e06 yuÄn # Character æ¸
+#U+6e07 kÄ # Character æ¸
+U+6e08 jì # Character æ¸
+U+6e09 shè # Character æ¸
+#U+6e0a yuÄn # Character æ¸
+U+6e0b ? # Character æ¸
+U+6e0c lù # Character æ¸
+U+6e0d zì # Character æ¸
+U+6e0e dú # Character æ¸
+U+6e0f ? # Character æ¸
+U+6e10 jià n # Character æ¸
+#U+6e11 mÇn # Character æ¸
+U+6e12 pì # Character æ¸
+U+6e13 ? # Character æ¸
+U+6e14 yú # Character æ¸
+#U+6e15 yuÄn # Character æ¸
+#U+6e16 shÄn # Character æ¸
+U+6e17 shèn # Character æ¸
+U+6e18 róu # Character æ¸
+U+6e19 huà n # Character æ¸
+#U+6e1a zhÇ # Character æ¸
+#U+6e1b jiÇn # Character æ¸
+#U+6e1c nuÇn # Character æ¸
+U+6e1d yú # Character æ¸
+U+6e1e qiú # Character æ¸
+U+6e1f tÃng # Character æ¸
+U+6e20 qú # Character æ¸
+U+6e21 dù # Character 渡
+U+6e22 féng # Character 渢
+#U+6e23 zhÄ # Character 渣
+U+6e24 bó # Character 渤
+U+6e25 wò # Character 渥
+#U+6e26 wŠ# Character 渦
+U+6e27 dì # Character 渧
+#U+6e28 wÄi # Character 渨
+#U+6e29 wÄn # Character 温
+U+6e2a rú # Character 渪
+U+6e2b xiè # Character 渫
+U+6e2c cè # Character 測
+U+6e2d wèi # Character æ¸
+#U+6e2e gÄ # Character 渮
+#U+6e2f gÇng # Character 港
+#U+6e30 yÇn # Character 渰
+U+6e31 hóng # Character 渱
+U+6e32 xuà n # Character 渲
+#U+6e33 mÇ # Character 渳
+#U+6e34 kÄ # Character 渴
+U+6e35 máo # Character 渵
+#U+6e36 yīng # Character 渶
+#U+6e37 yÇn # Character 渷
+U+6e38 yóu # Character 游
+#U+6e39 hÅng # Character 渹
+#U+6e3a miÇo # Character 渺
+#U+6e3b xÇng # Character 渻
+#U+6e3c mÄi # Character 渼
+#U+6e3d zÄi # Character 渽
+U+6e3e hún # Character 渾
+U+6e3f nà i # Character 渿
+U+6e40 kuà # Character æ¹
+U+6e41 shà # Character æ¹
+U+6e42 è # Character æ¹
+U+6e43 pà i # Character æ¹
+U+6e44 méi # Character æ¹
+U+6e45 lià n # Character æ¹
+U+6e46 qì # Character æ¹
+U+6e47 qì # Character æ¹
+U+6e48 méi # Character æ¹
+U+6e49 tián # Character æ¹
+U+6e4a còu # Character æ¹
+U+6e4b wéi # Character æ¹
+#U+6e4c cÄn # Character æ¹
+#U+6e4d tuÄn # Character æ¹
+#U+6e4e miÇn # Character æ¹
+U+6e4f huì # Character æ¹
+U+6e50 mò # Character æ¹
+#U+6e51 xÇ # Character æ¹
+U+6e52 jà # Character æ¹
+U+6e53 pén # Character æ¹
+#U+6e54 jiÄn # Character æ¹
+#U+6e55 jiÇn # Character æ¹
+U+6e56 hú # Character æ¹
+U+6e57 fèng # Character æ¹
+#U+6e58 xiÄng # Character æ¹
+U+6e59 yì # Character æ¹
+U+6e5a yìn # Character æ¹
+U+6e5b zhà n # Character æ¹
+U+6e5c shà # Character æ¹
+#U+6e5d jiÄ # Character æ¹
+U+6e5e chéng # Character æ¹
+U+6e5f huáng # Character æ¹
+U+6e60 tà n # Character æ¹
+U+6e61 yú # Character 湡
+U+6e62 bì # Character 湢
+#U+6e63 mÇn # Character æ¹£
+#U+6e64 shī # Character 湤
+U+6e65 tú # Character 湥
+#U+6e66 shÄng # Character 湦
+#U+6e67 yÇng # Character 湧
+U+6e68 qù # Character 湨
+U+6e69 zhòng # Character 湩
+U+6e6a ? # Character 湪
+#U+6e6b jiū # Character 湫
+#U+6e6c jiÇo # Character 湬
+U+6e6d ? # Character æ¹
+#U+6e6e yīn # Character 湮
+#U+6e6f tÄng # Character 湯
+U+6e70 lóng # Character 湰
+U+6e71 huò # Character 湱
+U+6e72 yuán # Character 湲
+#U+6e73 nÇn # Character æ¹³
+U+6e74 bà n # Character 湴
+#U+6e75 yÇu # Character æ¹µ
+U+6e76 quán # Character 湶
+U+6e77 chuà # Character 湷
+U+6e78 lià ng # Character 湸
+U+6e79 chán # Character 湹
+U+6e7a yán # Character 湺
+U+6e7b chún # Character 湻
+U+6e7c niè # Character 湼
+#U+6e7d zī # Character 湽
+#U+6e7e wÄn # Character æ¹¾
+#U+6e7f shī # Character 湿
+#U+6e80 mÇn # Character æº
+U+6e81 yÃng # Character æº
+U+6e82 ? # Character æº
+U+6e83 kuì # Character æº
+U+6e84 ? # Character æº
+U+6e85 jià n # Character æº
+U+6e86 xù # Character æº
+#U+6e87 lÇ # Character æº
+#U+6e88 guÄ« # Character æº
+U+6e89 gà i # Character æº
+U+6e8a ? # Character æº
+U+6e8b ? # Character æº
+#U+6e8c pÅ # Character æº
+U+6e8d jìn # Character æº
+U+6e8e guì # Character æº
+U+6e8f táng # Character æº
+U+6e90 yuán # Character æº
+#U+6e91 suÇ # Character æº
+U+6e92 yuán # Character æº
+U+6e93 lián # Character æº
+#U+6e94 yÇo # Character æº
+U+6e95 mèng # Character æº
+#U+6e96 zhÇn # Character æº
+U+6e97 shéng # Character æº
+U+6e98 kè # Character æº
+U+6e99 tà i # Character æº
+U+6e9a dá # Character æº
+#U+6e9b wÄ # Character æº
+#U+6e9c liÅ« # Character æº
+#U+6e9d gÅu # Character æº
+#U+6e9e sÄo # Character æº
+U+6e9f mÃng # Character æº
+U+6ea0 zhà # Character æº
+U+6ea1 shà # Character 溡
+U+6ea2 yì # Character 溢
+U+6ea3 lún # Character 溣
+#U+6ea4 mÇ # Character 溤
+#U+6ea5 pÇ # Character 溥
+U+6ea6 wéi # Character 溦
+U+6ea7 lì # Character 溧
+U+6ea8 cái # Character 溨
+U+6ea9 wù # Character 溩
+#U+6eaa xī # Character 溪
+#U+6eab wÄn # Character 溫
+#U+6eac qiÄng # Character 溬
+U+6ead zé # Character æº
+#U+6eae shī # Character 溮
+U+6eaf sù # Character 溯
+#U+6eb0 yī # Character 溰
+#U+6eb1 zhÄn # Character 溱
+#U+6eb2 sÅu # Character 溲
+U+6eb3 yún # Character 溳
+U+6eb4 xiù # Character 溴
+#U+6eb5 yīn # Character 溵
+U+6eb6 róng # Character 溶
+U+6eb7 hùn # Character 溷
+U+6eb8 sù # Character 溸
+U+6eb9 sù # Character 溹
+U+6eba nì # Character 溺
+U+6ebb tà # Character 溻
+#U+6ebc shī # Character 溼
+U+6ebd rù # Character 溽
+#U+6ebe wÄi # Character 溾
+U+6ebf pà n # Character 溿
+U+6ec0 chù # Character æ»
+U+6ec1 chú # Character æ»
+#U+6ec2 pÄng # Character æ»
+#U+6ec3 wÄng # Character æ»
+#U+6ec4 cÄng # Character æ»
+U+6ec5 miè # Character æ»
+U+6ec6 hé # Character æ»
+#U+6ec7 diÄn # Character æ»
+U+6ec8 hà o # Character æ»
+#U+6ec9 huÇng # Character æ»
+U+6eca xì # Character æ»
+#U+6ecb zÄ« # Character æ»
+U+6ecc dà # Character æ»
+#U+6ecd zhÇ # Character æ»
+U+6ece yÃng # Character æ»
+#U+6ecf fÇ # Character æ»
+U+6ed0 jié # Character æ»
+U+6ed1 huá # Character æ»
+#U+6ed2 gÄ # Character æ»
+#U+6ed3 zÇ # Character æ»
+#U+6ed4 tÄo # Character æ»
+U+6ed5 téng # Character æ»
+#U+6ed6 suÄ« # Character æ»
+#U+6ed7 bÇ # Character æ»
+U+6ed8 jià o # Character æ»
+U+6ed9 huì # Character æ»
+#U+6eda gÇn # Character æ»
+U+6edb yÃn # Character æ»
+#U+6edc gÄo # Character æ»
+U+6edd lóng # Character æ»
+U+6ede zhì # Character æ»
+U+6edf yà n # Character æ»
+U+6ee0 shè # Character æ»
+#U+6ee1 mÇn # Character 满
+U+6ee2 yìng # Character 滢
+U+6ee3 chún # Character 滣
+#U+6ee4 lÇ # Character 滤
+U+6ee5 là n # Character 滥
+U+6ee6 luán # Character 滦
+U+6ee7 ? # Character 滧
+#U+6ee8 bīn # Character 滨
+#U+6ee9 tÄn # Character 滩
+U+6eea yù # Character 滪
+#U+6eeb sÇu # Character 滫
+U+6eec hù # Character 滬
+U+6eed bì # Character æ»
+#U+6eee biÄo # Character æ»®
+U+6eef zhì # Character 滯
+#U+6ef0 jiÇng # Character æ»°
+U+6ef1 kòu # Character 滱
+U+6ef2 shèn # Character 滲
+#U+6ef3 shÄng # Character 滳
+#U+6ef4 dī # Character 滴
+U+6ef5 mì # Character 滵
+U+6ef6 áo # Character 滶
+#U+6ef7 lÇ # Character æ»·
+#U+6ef8 hÇ # Character 滸
+#U+6ef9 hū # Character 滹
+U+6efa yóu # Character 滺
+#U+6efb chÇn # Character æ»»
+U+6efc fà n # Character 滼
+U+6efd yóng # Character 滽
+#U+6efe gÇn # Character 滾
+#U+6eff mÇn # Character 滿
diff --git a/resources/chars/latin1/row6f.trans b/resources/chars/latin1/row6f.trans
new file mode 100644
index 0000000..89af787
--- /dev/null
+++ b/resources/chars/latin1/row6f.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+6f00 qìng # Character æ¼
+U+6f01 yú # Character æ¼
+U+6f02 pià o # Character æ¼
+U+6f03 jà # Character æ¼
+U+6f04 yá # Character æ¼
+#U+6f05 jiÇo # Character æ¼
+#U+6f06 qÄ« # Character æ¼
+#U+6f07 xÇ # Character æ¼
+U+6f08 jì # Character æ¼
+U+6f09 lù # Character æ¼
+#U+6f0a lÇ # Character æ¼
+U+6f0b lóng # Character æ¼
+#U+6f0c jÇn # Character æ¼
+U+6f0d guó # Character æ¼
+U+6f0e cóng # Character æ¼
+U+6f0f lòu # Character æ¼
+U+6f10 zhà # Character æ¼
+U+6f11 gà i # Character æ¼
+U+6f12 qiáng # Character æ¼
+U+6f13 là # Character æ¼
+#U+6f14 yÇn # Character æ¼
+U+6f15 cáo # Character æ¼
+U+6f16 jià o # Character æ¼
+#U+6f17 cÅng # Character æ¼
+U+6f18 qún # Character æ¼
+U+6f19 tuán # Character æ¼
+U+6f1a òu # Character æ¼
+U+6f1b téng # Character æ¼
+#U+6f1c yÄ # Character æ¼
+U+6f1d xà # Character æ¼
+U+6f1e mì # Character æ¼
+U+6f1f táng # Character æ¼
+U+6f20 mò # Character æ¼
+#U+6f21 shÄng # Character 漡
+U+6f22 hà n # Character 漢
+U+6f23 lián # Character 漣
+#U+6f24 lÇn # Character 漤
+#U+6f25 wÄ # Character æ¼¥
+U+6f26 là # Character 漦
+U+6f27 qián # Character 漧
+U+6f28 féng # Character 漨
+U+6f29 xuán # Character 漩
+#U+6f2a yī # Character 漪
+U+6f2b mà n # Character 漫
+U+6f2c zì # Character 漬
+#U+6f2d mÇng # Character æ¼
+#U+6f2e kÄng # Character æ¼®
+#U+6f2f lÄi # Character 漯
+#U+6f30 pÄng # Character æ¼°
+U+6f31 shù # Character 漱
+#U+6f32 zhÇng # Character æ¼²
+#U+6f33 zhÄng # Character æ¼³
+U+6f34 chóng # Character 漴
+U+6f35 xù # Character 漵
+U+6f36 huà n # Character 漶
+U+6f37 kuò # Character 漷
+U+6f38 jià n # Character 漸
+#U+6f39 yÄn # Character æ¼¹
+#U+6f3a chuÇng # Character 漺
+U+6f3b liáo # Character 漻
+#U+6f3c cuÇ # Character æ¼¼
+U+6f3d tà # Character 漽
+U+6f3e yà ng # Character 漾
+#U+6f3f jiÄng # Character 漿
+U+6f40 cóng # Character æ½
+#U+6f41 yÇng # Character æ½
+U+6f42 hóng # Character æ½
+U+6f43 xún # Character æ½
+U+6f44 shù # Character æ½
+U+6f45 guà n # Character æ½
+U+6f46 yÃng # Character æ½
+#U+6f47 xiÄo # Character æ½
+U+6f48 ? # Character æ½
+U+6f49 ? # Character æ½
+U+6f4a xù # Character æ½
+U+6f4b lià n # Character æ½
+U+6f4c zhì # Character æ½
+U+6f4d wéi # Character æ½
+U+6f4e pì # Character æ½
+U+6f4f jué # Character æ½
+U+6f50 jià o # Character æ½
+U+6f51 po # Character æ½
+U+6f52 dà ng # Character æ½
+U+6f53 huì # Character æ½
+U+6f54 jié # Character æ½
+#U+6f55 wÇ # Character æ½
+U+6f56 pá # Character æ½
+U+6f57 jà # Character æ½
+#U+6f58 pÄn # Character æ½
+U+6f59 guà # Character æ½
+#U+6f5a xiÄo # Character æ½
+U+6f5b qián # Character æ½
+U+6f5c qián # Character æ½
+#U+6f5d xÄ« # Character æ½
+U+6f5e lù # Character æ½
+U+6f5f xì # Character æ½
+U+6f60 xuà n # Character æ½
+U+6f61 dùn # Character 潡
+U+6f62 huáng # Character 潢
+#U+6f63 mÇn # Character æ½£
+U+6f64 rùn # Character 潤
+U+6f65 sù # Character 潥
+U+6f66 liáo # Character 潦
+#U+6f67 zhÄn # Character 潧
+#U+6f68 zhÅng # Character 潨
+U+6f69 yì # Character 潩
+U+6f6a dà # Character 潪
+#U+6f6b wÄn # Character 潫
+U+6f6c dà n # Character 潬
+U+6f6d tán # Character æ½
+U+6f6e cháo # Character 潮
+U+6f6f xún # Character 潯
+U+6f70 kuì # Character 潰
+U+6f71 ? # Character æ½±
+U+6f72 shà o # Character 潲
+U+6f73 tú # Character 潳
+#U+6f74 zhū # Character 潴
+U+6f75 sà n # Character 潵
+#U+6f76 hÄi # Character 潶
+#U+6f77 bÇ # Character æ½·
+#U+6f78 shÄn # Character 潸
+U+6f79 chán # Character 潹
+U+6f7a chán # Character 潺
+#U+6f7b shÇ # Character æ½»
+U+6f7c tóng # Character 潼
+#U+6f7d pÇ # Character æ½½
+U+6f7e lÃn # Character æ½¾
+U+6f7f wéi # Character 潿
+U+6f80 sè # Character æ¾
+U+6f81 sè # Character æ¾
+U+6f82 chéng # Character æ¾
+U+6f83 jiòng # Character æ¾
+U+6f84 chéng # Character æ¾
+U+6f85 huà # Character æ¾
+#U+6f86 jiÄo # Character æ¾
+U+6f87 là o # Character æ¾
+U+6f88 chè # Character æ¾
+#U+6f89 gÇn # Character æ¾
+#U+6f8a cÅ«n # Character æ¾
+U+6f8b hèng # Character æ¾
+#U+6f8c sÄ« # Character æ¾
+U+6f8d shù # Character æ¾
+#U+6f8e pÄng # Character æ¾
+U+6f8f hà n # Character æ¾
+U+6f90 yún # Character æ¾
+U+6f91 liù # Character æ¾
+U+6f92 hòng # Character æ¾
+U+6f93 fú # Character æ¾
+U+6f94 hà o # Character æ¾
+U+6f95 hé # Character æ¾
+#U+6f96 xiÄn # Character æ¾
+U+6f97 jià n # Character æ¾
+#U+6f98 shÄn # Character æ¾
+U+6f99 xì # Character æ¾
+U+6f9a ? # Character æ¾
+U+6f9b ? # Character æ¾
+U+6f9c lán # Character æ¾
+U+6f9d ? # Character æ¾
+U+6f9e yú # Character æ¾
+#U+6f9f lÇn # Character æ¾
+#U+6fa0 mÇn # Character æ¾
+#U+6fa1 zÇo # Character 澡
+#U+6fa2 dÄng # Character æ¾¢
+#U+6fa3 wÇn # Character æ¾£
+U+6fa4 zé # Character 澤
+U+6fa5 xiè # Character 澥
+U+6fa6 yù # Character 澦
+#U+6fa7 lÇ # Character 澧
+U+6fa8 shì # Character 澨
+U+6fa9 xué # Character 澩
+U+6faa lÃng # Character 澪
+U+6fab mà n # Character 澫
+#U+6fac zī # Character 澬
+#U+6fad yÅng # Character æ¾
+U+6fae kuà i # Character 澮
+U+6faf cà n # Character 澯
+U+6fb0 lià n # Character 澰
+U+6fb1 dià n # Character 澱
+U+6fb2 yè # Character 澲
+U+6fb3 Ã o # Character æ¾³
+U+6fb4 huán # Character 澴
+#U+6fb5 zhÄn # Character æ¾µ
+U+6fb6 chán # Character 澶
+U+6fb7 mà n # Character 澷
+#U+6fb8 dÇn # Character 澸
+U+6fb9 dà n # Character 澹
+U+6fba yì # Character 澺
+U+6fbb suì # Character 澻
+U+6fbc pì # Character 澼
+U+6fbd jù # Character 澽
+U+6fbe tà # Character 澾
+U+6fbf qÃn # Character 澿
+#U+6fc0 jÄ« # Character æ¿
+U+6fc1 zhuó # Character æ¿
+U+6fc2 lián # Character æ¿
+U+6fc3 nóng # Character æ¿
+#U+6fc4 guÅ # Character æ¿
+U+6fc5 jìn # Character æ¿
+U+6fc6 fén # Character æ¿
+U+6fc7 sè # Character æ¿
+U+6fc8 jà # Character æ¿
+#U+6fc9 suÄ« # Character æ¿
+U+6fca huì # Character æ¿
+#U+6fcb chÇ # Character æ¿
+U+6fcc tà # Character æ¿
+#U+6fcd sÅng # Character æ¿
+#U+6fce dÇng # Character æ¿
+U+6fcf ? # Character æ¿
+#U+6fd0 zhÇ # Character æ¿
+U+6fd1 là i # Character æ¿
+#U+6fd2 bÄ«n # Character æ¿
+U+6fd3 lián # Character æ¿
+#U+6fd4 mÇ # Character æ¿
+#U+6fd5 shÄ« # Character æ¿
+U+6fd6 shù # Character æ¿
+U+6fd7 mì # Character æ¿
+U+6fd8 nìng # Character æ¿
+U+6fd9 yÃng # Character æ¿
+U+6fda yÃng # Character æ¿
+U+6fdb méng # Character æ¿
+U+6fdc jìn # Character æ¿
+U+6fdd qà # Character æ¿
+U+6fde pì # Character æ¿
+U+6fdf jì # Character æ¿
+U+6fe0 háo # Character æ¿
+U+6fe1 rú # Character 濡
+#U+6fe2 zuÇ # Character æ¿¢
+U+6fe3 wò # Character 濣
+#U+6fe4 tÄo # Character 濤
+U+6fe5 yìn # Character 濥
+#U+6fe6 yÇn # Character 濦
+U+6fe7 duì # Character 濧
+U+6fe8 cà # Character 濨
+U+6fe9 huò # Character 濩
+U+6fea jìng # Character 濪
+U+6feb là n # Character 濫
+U+6fec jùn # Character 濬
+U+6fed à i # Character æ¿
+#U+6fee pū # Character 濮
+U+6fef zhuó # Character 濯
+U+6ff0 wéi # Character 濰
+#U+6ff1 bīn # Character 濱
+#U+6ff2 gÇ # Character 濲
+U+6ff3 qián # Character 濳
+U+6ff4 xÃng # Character æ¿´
+U+6ff5 ? # Character 濵
+U+6ff6 kuò # Character 濶
+U+6ff7 fèi # Character 濷
+U+6ff8 ? # Character 濸
+U+6ff9 ? # Character 濹
+U+6ffa jià n # Character 濺
+#U+6ffb wÄi # Character æ¿»
+U+6ffc luò # Character 濼
+U+6ffd zà n # Character 濽
+#U+6ffe lÇ # Character 濾
+U+6fff lì # Character 濿
diff --git a/resources/chars/latin1/row70.trans b/resources/chars/latin1/row70.trans
new file mode 100644
index 0000000..fe367d6
--- /dev/null
+++ b/resources/chars/latin1/row70.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+7000 yÅu # Character ç
+U+7001 yà ng # Character ç
+#U+7002 lÇ # Character ç
+U+7003 sì # Character ç
+U+7004 jié # Character ç
+U+7005 yìng # Character ç
+U+7006 dú # Character ç
+#U+7007 wÇng # Character ç
+#U+7008 huÄ« # Character ç
+U+7009 xiè # Character ç
+U+700a pán # Character ç
+#U+700b shÄn # Character ç
+#U+700c biÄo # Character ç
+U+700d chán # Character ç
+U+700e mò # Character ç
+U+700f liú # Character ç
+#U+7010 jiÄn # Character ç
+U+7011 pù # Character ç
+U+7012 sè # Character ç
+U+7013 chéng # Character ç
+#U+7014 gÇ # Character ç
+#U+7015 bÄ«n # Character ç
+U+7016 huò # Character ç
+U+7017 xià n # Character ç
+U+7018 lú # Character ç
+#U+7019 qÄ«n # Character ç
+U+701a hà n # Character ç
+U+701b yÃng # Character ç
+#U+701c yÅng # Character ç
+U+701d lì # Character ç
+U+701e jìng # Character ç
+#U+701f xiÄo # Character ç
+U+7020 yÃng # Character ç
+#U+7021 suÇ # Character ç¡
+U+7022 wéi # Character ç¢
+U+7023 xiè # Character ç£
+U+7024 huái # Character ç¤
+U+7025 hà o # Character ç¥
+#U+7026 zhÅ« # Character ç¦
+U+7027 lóng # Character ç§
+U+7028 là i # Character ç¨
+U+7029 duì # Character ç©
+U+702a fán # Character çª
+U+702b hú # Character ç«
+U+702c là i # Character ç¬
+U+702d ? # Character ç
+U+702e ? # Character ç®
+U+702f yÃng # Character ç¯
+U+7030 mà # Character ç°
+U+7031 jì # Character ç±
+U+7032 lià n # Character ç²
+U+7033 jià n # Character ç³
+#U+7034 yÇng # Character ç´
+U+7035 fèn # Character çµ
+U+7036 lÃn # Character ç¶
+U+7037 yì # Character ç·
+#U+7038 jiÄn # Character ç¸
+U+7039 yuè # Character ç¹
+U+703a chán # Character çº
+U+703b dà i # Character ç»
+U+703c ráng # Character ç¼
+#U+703d jiÇn # Character ç½
+U+703e lán # Character ç¾
+U+703f fán # Character ç¿
+U+7040 shuà ng # Character ç
+#U+7041 yuÄn # Character ç
+U+7042 zhuó # Character ç
+#U+7043 fÄng # Character ç
+U+7044 shè # Character ç
+#U+7045 lÄi # Character ç
+U+7046 lán # Character ç
+U+7047 cóng # Character ç
+U+7048 qú # Character ç
+#U+7049 yÅng # Character ç
+U+704a qián # Character ç
+#U+704b fÇ # Character ç
+U+704c guà n # Character ç
+U+704d què # Character ç
+U+704e yà n # Character ç
+U+704f hà o # Character ç
+U+7050 ? # Character ç
+#U+7051 sÇ # Character ç
+U+7052 zà n # Character ç
+U+7053 luán # Character ç
+U+7054 yà n # Character ç
+U+7055 là # Character ç
+#U+7056 mÇ # Character ç
+U+7057 shà n # Character ç
+#U+7058 tÄn # Character ç
+#U+7059 dÇng # Character ç
+#U+705a jiÇo # Character ç
+#U+705b chÇn # Character ç
+U+705c ? # Character ç
+U+705d hà o # Character ç
+U+705e bà # Character ç
+U+705f zhú # Character ç
+#U+7060 lÇn # Character ç
+U+7061 lán # Character ç¡
+#U+7062 nÇng # Character ç¢
+#U+7063 wÄn # Character ç£
+U+7064 luán # Character ç¤
+U+7065 xún # Character ç¥
+#U+7066 xiÇn # Character ç¦
+U+7067 yà n # Character ç§
+#U+7068 gÇn # Character ç¨
+U+7069 yà n # Character ç©
+U+706a yù # Character çª
+#U+706b huÇ # Character ç«
+#U+706c biÄo # Character ç¬
+U+706d miè # Character ç
+#U+706e guÄng # Character ç®
+#U+706f dÄng # Character ç¯
+#U+7070 huÄ« # Character ç°
+#U+7071 xiÄo # Character ç±
+#U+7072 xiÄo # Character ç²
+U+7073 ? # Character ç³
+U+7074 hóng # Character ç´
+U+7075 lÃng # Character çµ
+U+7076 zà o # Character ç¶
+U+7077 zhuà n # Character ç·
+#U+7078 jiÇ # Character ç¸
+U+7079 zhà # Character ç¹
+U+707a xiè # Character çº
+U+707b chì # Character ç»
+U+707c zhuó # Character ç¼
+#U+707d zÄi # Character ç½
+#U+707e zÄi # Character ç¾
+U+707f cà n # Character ç¿
+U+7080 yáng # Character ç
+U+7081 qì # Character ç
+#U+7082 zhÅng # Character ç
+U+7083 fén # Character ç
+#U+7084 niÇ # Character ç
+#U+7085 jiÇng # Character ç
+U+7086 wén # Character ç
+U+7087 pò # Character ç
+U+7088 yì # Character ç
+U+7089 lú # Character ç
+#U+708a chuÄ« # Character ç
+#U+708b pÄ« # Character ç
+U+708c kà i # Character ç
+U+708d pà n # Character ç
+U+708e yán # Character ç
+U+708f kà i # Character ç
+U+7090 pà ng # Character ç
+U+7091 mù # Character ç
+#U+7092 chÇo # Character ç
+U+7093 lià o # Character ç
+U+7094 guì # Character ç
+U+7095 kà ng # Character ç
+#U+7096 tÅ«n # Character ç
+#U+7097 guÄng # Character ç
+#U+7098 xÄ«n # Character ç
+U+7099 zhì # Character ç
+U+709a ? # Character ç
+#U+709b guÄng # Character ç
+#U+709c wÄi # Character ç
+U+709d qià ng # Character ç
+U+709e ? # Character ç
+U+709f dá # Character ç
+U+70a0 xiá # Character ç
+#U+70a1 zhÄng # Character ç¡
+U+70a2 zhú # Character ç¢
+#U+70a3 kÄ # Character ç£
+U+70a4 zhà o # Character ç¤
+U+70a5 fú # Character ç¥
+U+70a6 bá # Character ç¦
+U+70a7 duò # Character ç§
+U+70a8 duò # Character ç¨
+U+70a9 lìng # Character ç©
+U+70aa zhuó # Character çª
+U+70ab xuà n # Character ç«
+U+70ac jù # Character ç¬
+U+70ad tà n # Character ç
+U+70ae pà o # Character ç®
+#U+70af jiÇng # Character ç¯
+U+70b0 páo # Character ç°
+U+70b1 tái # Character ç±
+U+70b2 tái # Character ç²
+#U+70b3 bÇng # Character ç³
+#U+70b4 yÇng # Character ç´
+#U+70b5 tÅng # Character çµ
+#U+70b6 hÄn # Character ç¶
+U+70b7 zhù # Character ç·
+U+70b8 zhà # Character ç¸
+#U+70b9 diÇn # Character ç¹
+U+70ba wèi # Character çº
+U+70bb shà # Character ç»
+U+70bc lià n # Character ç¼
+U+70bd chì # Character ç½
+#U+70be huÇng # Character ç¾
+U+70bf ? # Character ç¿
+#U+70c0 hÅ« # Character ç
+U+70c1 shuò # Character ç
+U+70c2 là n # Character ç
+#U+70c3 jÇng # Character ç
+#U+70c4 jiÇo # Character ç
+U+70c5 xù # Character ç
+U+70c6 xÃng # Character ç
+U+70c7 quà n # Character ç
+U+70c8 liè # Character ç
+U+70c9 huà n # Character ç
+U+70ca yáng # Character ç
+#U+70cb xiÄo # Character ç
+#U+70cc xiÅ« # Character ç
+#U+70cd xiÇn # Character ç
+U+70ce yÃn # Character ç
+#U+70cf wÅ« # Character ç
+#U+70d0 zhÅu # Character ç
+U+70d1 yáo # Character ç
+U+70d2 shì # Character ç
+#U+70d3 wÄi # Character ç
+U+70d4 tóng # Character ç
+U+70d5 xuè # Character ç
+#U+70d6 zÄi # Character ç
+U+70d7 kà i # Character ç
+#U+70d8 hÅng # Character ç
+U+70d9 luò # Character ç
+U+70da xiá # Character ç
+U+70db zhú # Character ç
+#U+70dc xuÇn # Character ç
+#U+70dd zhÄng # Character ç
+U+70de pò # Character ç
+#U+70df yÄn # Character ç
+#U+70e0 huÇ # Character ç
+#U+70e1 guÄng # Character ç¡
+U+70e2 zhè # Character ç¢
+#U+70e3 huÄ« # Character ç£
+#U+70e4 kÇo # Character ç¤
+U+70e5 ? # Character ç¥
+U+70e6 fán # Character ç¦
+#U+70e7 shÄo # Character ç§
+U+70e8 yè # Character ç¨
+U+70e9 huì # Character ç©
+U+70ea ? # Character çª
+U+70eb tà ng # Character ç«
+U+70ec jìn # Character ç¬
+U+70ed rè # Character ç
+U+70ee ? # Character ç®
+#U+70ef xÄ« # Character ç¯
+U+70f0 fú # Character ç°
+#U+70f1 jiÇng # Character ç±
+U+70f2 chè # Character ç²
+#U+70f3 pÇ # Character ç³
+#U+70f4 jÇng # Character ç´
+U+70f5 zhuó # Character çµ
+#U+70f6 tÇng # Character ç¶
+U+70f7 wán # Character ç·
+#U+70f8 hÇi # Character ç¸
+#U+70f9 pÄng # Character ç¹
+#U+70fa lÇng # Character çº
+#U+70fb shÄn # Character ç»
+#U+70fc hÅ« # Character ç¼
+#U+70fd fÄng # Character ç½
+U+70fe chì # Character ç¾
+U+70ff róng # Character ç¿
diff --git a/resources/chars/latin1/row71.trans b/resources/chars/latin1/row71.trans
new file mode 100644
index 0000000..d97899e
--- /dev/null
+++ b/resources/chars/latin1/row71.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+7100 hú # Character ç
+U+7101 ? # Character ç
+U+7102 shú # Character ç
+U+7103 hè # Character ç
+#U+7104 xÅ«n # Character ç
+U+7105 kù # Character ç
+U+7106 jué # Character ç
+#U+7107 xiÄo # Character ç
+#U+7108 xÄ« # Character ç
+#U+7109 yÄn # Character ç
+U+710a hà n # Character ç
+U+710b zhuà ng # Character ç
+U+710c jùn # Character ç
+U+710d dì # Character ç
+U+710e xiè # Character ç
+U+710f jà # Character ç
+U+7110 wù # Character ç
+U+7111 ? # Character ç
+U+7112 ? # Character ç
+U+7113 hán # Character ç
+U+7114 yà n # Character ç
+U+7115 huà n # Character ç
+U+7116 mèn # Character ç
+U+7117 jú # Character ç
+U+7118 chóu # Character ç
+U+7119 bèi # Character ç
+U+711a fén # Character ç
+U+711b lìn # Character ç
+#U+711c kÅ«n # Character ç
+U+711d hùn # Character ç
+#U+711e tÅ«n # Character ç
+U+711f xà # Character ç
+U+7120 cuì # Character ç
+U+7121 wú # Character ç¡
+#U+7122 hÅng # Character ç¢
+U+7123 jù # Character ç£
+#U+7124 fÇ # Character ç¤
+U+7125 wò # Character ç¥
+#U+7126 jiÄo # Character ç¦
+#U+7127 cÅng # Character ç§
+U+7128 fèng # Character ç¨
+#U+7129 pÄ«ng # Character ç©
+#U+712a qiÅng # Character çª
+U+712b ruò # Character ç«
+U+712c xà # Character ç¬
+U+712d qióng # Character ç
+U+712e xìn # Character ç®
+U+712f zhuó # Character ç¯
+U+7130 yà n # Character ç°
+U+7131 yà n # Character ç±
+U+7132 yì # Character ç²
+U+7133 jué # Character ç³
+U+7134 yù # Character ç´
+U+7135 gà ng # Character çµ
+U+7136 rán # Character ç¶
+U+7137 pà # Character ç·
+#U+7138 gÇ # Character ç¸
+U+7139 ? # Character ç¹
+#U+713a shÄng # Character çº
+U+713b chà ng # Character ç»
+#U+713c shÄo # Character ç¼
+U+713d ? # Character ç½
+U+713e ? # Character ç¾
+U+713f ? # Character ç¿
+U+7140 ? # Character ç
+U+7141 chén # Character ç
+U+7142 hè # Character ç
+#U+7143 kuÇ # Character ç
+#U+7144 zhÅng # Character ç
+U+7145 duà n # Character ç
+#U+7146 xiÄ # Character ç
+#U+7147 huÄ« # Character ç
+U+7148 fèng # Character ç
+U+7149 lià n # Character ç
+#U+714a xuÄn # Character ç
+#U+714b xÄ«ng # Character ç
+U+714c huáng # Character ç
+#U+714d jiÇo # Character ç
+#U+714e jiÄn # Character ç
+U+714f bì # Character ç
+#U+7150 yÄ«ng # Character ç
+#U+7151 zhÇ # Character ç
+#U+7152 wÄi # Character ç
+#U+7153 tuÄn # Character ç
+U+7154 tià n # Character ç
+#U+7155 xÄ« # Character ç
+#U+7156 nuÇn # Character ç
+#U+7157 nuÇn # Character ç
+U+7158 chán # Character ç
+#U+7159 yÄn # Character ç
+#U+715a jiÇng # Character ç
+#U+715b jiÇng # Character ç
+U+715c yù # Character ç
+U+715d mèi # Character ç
+#U+715e shÄ # Character ç
+U+715f wèi # Character ç
+U+7160 yè # Character ç
+U+7161 xìn # Character ç
¡
+U+7162 qióng # Character ç
¢
+#U+7163 rÇu # Character ç
£
+U+7164 méi # Character ç
¤
+U+7165 huà n # Character ç
¥
+#U+7166 xÇ # Character ç
¦
+U+7167 zhà o # Character ç
§
+#U+7168 wÄi # Character ç
¨
+U+7169 fán # Character ç
©
+U+716a qiú # Character ç
ª
+U+716b suì # Character ç
«
+U+716c yáng # Character ç
¬
+U+716d liè # Character ç
+#U+716e zhÇ # Character ç
®
+U+716f ? # Character ç
¯
+U+7170 gà o # Character ç
°
+#U+7171 guÄ # Character ç
±
+U+7172 bà o # Character ç
²
+U+7173 hú # Character ç
³
+#U+7174 yÅ«n # Character ç
´
+#U+7175 xiÄ # Character ç
µ
+U+7176 ? # Character ç
¶
+U+7177 ? # Character ç
·
+#U+7178 biÄn # Character ç
¸
+U+7179 gòu # Character ç
¹
+U+717a tuì # Character ç
º
+U+717b táng # Character ç
»
+#U+717c chÇo # Character ç
¼
+#U+717d shÄn # Character ç
½
+#U+717e Än # Character ç
¾
+U+717f bó # Character ç
¿
+#U+7180 huÇng # Character ç
+U+7181 xié # Character ç
+U+7182 xì # Character ç
+U+7183 wù # Character ç
+#U+7184 xÄ« # Character ç
+U+7185 yún # Character ç
+U+7186 hé # Character ç
+U+7187 hè # Character ç
+#U+7188 xÄ« # Character ç
+U+7189 yún # Character ç
+U+718a xióng # Character ç
+U+718b nái # Character ç
+U+718c shà n # Character ç
+U+718d ? # Character ç
+U+718e yà o # Character ç
+#U+718f xÅ«n # Character ç
+U+7190 mì # Character ç
+U+7191 lián # Character ç
+U+7192 yÃng # Character ç
+U+7193 wèn # Character ç
+U+7194 róng # Character ç
+U+7195 ? # Character ç
+U+7196 ? # Character ç
+U+7197 qià ng # Character ç
+#U+7198 liÅ« # Character ç
+#U+7199 xÄ« # Character ç
+U+719a bì # Character ç
+#U+719b biÄo # Character ç
+#U+719c zÇng # Character ç
+U+719d lù # Character ç
+#U+719e jiÄn # Character ç
+U+719f shú # Character ç
+U+71a0 yì # Character ç
+U+71a1 lóu # Character ç¡
+#U+71a2 fÄng # Character ç¢
+#U+71a3 suÄ« # Character ç£
+U+71a4 yì # Character ç¤
+#U+71a5 tÅng # Character ç¥
+U+71a6 jué # Character ç¦
+#U+71a7 zÅng # Character ç§
+U+71a8 yùn # Character ç¨
+U+71a9 hù # Character ç©
+U+71aa yà # Character çª
+U+71ab zhì # Character ç«
+U+71ac áo # Character ç¬
+U+71ad wèi # Character ç
+U+71ae liáo # Character ç®
+U+71af hà n # Character ç¯
+#U+71b0 Åu # Character ç°
+U+71b1 rè # Character ç±
+#U+71b2 jiÇng # Character ç²
+U+71b3 mà n # Character ç³
+U+71b4 ? # Character ç´
+#U+71b5 shÄng # Character çµ
+U+71b6 cuà n # Character ç¶
+#U+71b7 zÄng # Character ç·
+#U+71b8 jiÄn # Character ç¸
+#U+71b9 xÄ« # Character ç¹
+#U+71ba xÄ« # Character çº
+#U+71bb xÄ« # Character ç»
+U+71bc yì # Character ç¼
+U+71bd xià o # Character ç½
+U+71be chì # Character ç¾
+U+71bf huáng # Character ç¿
+#U+71c0 chÇn # Character ç
+U+71c1 yè # Character ç
+U+71c2 qián # Character ç
+U+71c3 rán # Character ç
+U+71c4 yà n # Character ç
+U+71c5 xián # Character ç
+U+71c6 qiáo # Character ç
+U+71c7 zùn # Character ç
+#U+71c8 dÄng # Character ç
+U+71c9 dùn # Character ç
+#U+71ca shÄn # Character ç
+#U+71cb jiÄo # Character ç
+U+71cc fén # Character ç
+#U+71cd sÄ« # Character ç
+U+71ce lià o # Character ç
+U+71cf yù # Character ç
+U+71d0 lÃn # Character ç
+U+71d1 tóng # Character ç
+#U+71d2 shÄo # Character ç
+#U+71d3 fÄn # Character ç
+U+71d4 fán # Character ç
+U+71d5 yà n # Character ç
+U+71d6 xún # Character ç
+U+71d7 là n # Character ç
+#U+71d8 mÄi # Character ç
+U+71d9 tà ng # Character ç
+#U+71da yÄ« # Character ç
+#U+71db jÇng # Character ç
+U+71dc mèn # Character ç
+U+71dd ? # Character ç
+U+71de ? # Character ç
+U+71df yÃng # Character ç
+U+71e0 yù # Character ç
+U+71e1 yì # Character ç¡
+U+71e2 xué # Character ç¢
+U+71e3 lán # Character ç£
+U+71e4 tà i # Character ç¤
+U+71e5 zà o # Character ç¥
+U+71e6 cà n # Character ç¦
+U+71e7 suì # Character ç§
+#U+71e8 xÄ« # Character ç¨
+U+71e9 què # Character ç©
+#U+71ea cÅng # Character çª
+U+71eb lián # Character ç«
+#U+71ec huÇ # Character ç¬
+U+71ed zhú # Character ç
+U+71ee xiè # Character ç®
+U+71ef lÃng # Character ç¯
+#U+71f0 wÄi # Character ç°
+U+71f1 yì # Character ç±
+U+71f2 xié # Character ç²
+U+71f3 zhà o # Character ç³
+U+71f4 huì # Character ç´
+U+71f5 ? # Character çµ
+U+71f6 ? # Character ç¶
+U+71f7 lán # Character ç·
+U+71f8 rú # Character ç¸
+#U+71f9 xiÇn # Character ç¹
+#U+71fa kÇo # Character çº
+#U+71fb xÅ«n # Character ç»
+U+71fc jìn # Character ç¼
+U+71fd chóu # Character ç½
+U+71fe chóu # Character ç¾
+U+71ff yà o # Character ç¿
diff --git a/resources/chars/latin1/row72.trans b/resources/chars/latin1/row72.trans
new file mode 100644
index 0000000..2aecf18
--- /dev/null
+++ b/resources/chars/latin1/row72.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+7200 hè # Character ç
+U+7201 là n # Character ç
+#U+7202 biÄo # Character ç
+U+7203 róng # Character ç
+U+7204 lì # Character ç
+U+7205 mò # Character ç
+U+7206 bà o # Character ç
+U+7207 ruò # Character ç
+#U+7208 lÇ # Character ç
+U+7209 là # Character ç
+U+720a áo # Character ç
+U+720b xùn # Character ç
+U+720c kuà ng # Character ç
+U+720d shuò # Character ç
+U+720e ? # Character ç
+U+720f lì # Character ç
+U+7210 lú # Character ç
+U+7211 jué # Character ç
+U+7212 lià o # Character ç
+U+7213 yà n # Character ç
+#U+7214 xÄ« # Character ç
+U+7215 xiè # Character ç
+U+7216 lóng # Character ç
+U+7217 yè # Character ç
+U+7218 ? # Character ç
+#U+7219 rÇng # Character ç
+U+721a yuè # Character ç
+U+721b là n # Character ç
+U+721c cóng # Character ç
+U+721d jué # Character ç
+U+721e tóng # Character ç
+U+721f guà n # Character ç
+U+7220 ? # Character ç
+U+7221 chè # Character ç¡
+U+7222 mà # Character ç¢
+#U+7223 tÇng # Character ç£
+U+7224 là n # Character ç¤
+U+7225 zhú # Character ç¥
+U+7226 ? # Character ç¦
+U+7227 lÃng # Character ç§
+U+7228 cuà n # Character ç¨
+U+7229 yù # Character ç©
+#U+722a zhÇo # Character çª
+U+722b ? # Character ç«
+U+722c pá # Character ç¬
+#U+722d zhÄng # Character ç
+U+722e páo # Character ç®
+#U+722f chÄng # Character ç¯
+U+7230 yuán # Character ç°
+U+7231 Ã i # Character ç±
+U+7232 wèi # Character ç²
+U+7233 ? # Character ç³
+U+7234 jué # Character ç´
+U+7235 jué # Character çµ
+U+7236 fù # Character ç¶
+U+7237 ye # Character ç·
+U+7238 bà # Character ç¸
+#U+7239 diÄ # Character ç¹
+U+723a ye # Character çº
+U+723b yáo # Character ç»
+#U+723c zÇ # Character ç¼
+#U+723d shuÇng # Character ç½
+#U+723e Är # Character ç¾
+U+723f qiáng # Character ç¿
+U+7240 chuáng # Character ç
+#U+7241 gÄ # Character ç
+#U+7242 zÄng # Character ç
+U+7243 dié # Character ç
+#U+7244 qiÄng # Character ç
+U+7245 yóng # Character ç
+U+7246 qiáng # Character ç
+U+7247 pià n # Character ç
+#U+7248 bÇn # Character ç
+U+7249 pà n # Character ç
+U+724a sháo # Character ç
+#U+724b jiÄn # Character ç
+U+724c pái # Character ç
+U+724d dú # Character ç
+#U+724e chuÄng # Character ç
+U+724f tóu # Character ç
+U+7250 zhá # Character ç
+#U+7251 biÄn # Character ç
+U+7252 dié # Character ç
+#U+7253 bÇng # Character ç
+U+7254 bó # Character ç
+#U+7255 chuÄng # Character ç
+#U+7256 yÇu # Character ç
+U+7257 ? # Character ç
+U+7258 dú # Character ç
+U+7259 yá # Character ç
+U+725a chèng # Character ç
+U+725b niú # Character ç
+U+725c ? # Character ç
+U+725d pìn # Character ç
+#U+725e jiÅ« # Character ç
+U+725f móu # Character ç
+#U+7260 tuÅ # Character ç
+#U+7261 mÇ # Character ç¡
+U+7262 láo # Character ç¢
+U+7263 rèn # Character ç£
+U+7264 máng # Character ç¤
+#U+7265 fÄng # Character ç¥
+U+7266 máo # Character ç¦
+U+7267 mù # Character ç§
+#U+7268 gÄng # Character ç¨
+U+7269 wù # Character ç©
+U+726a yà n # Character çª
+#U+726b gÄ # Character ç«
+U+726c bèi # Character ç¬
+U+726d sì # Character ç
+U+726e jià n # Character ç®
+#U+726f gÇ # Character ç¯
+U+7270 yòu # Character ç°
+#U+7271 gÄ # Character ç±
+#U+7272 shÄng # Character ç²
+#U+7273 mÇ # Character ç³
+#U+7274 dÇ # Character ç´
+#U+7275 qiÄn # Character çµ
+U+7276 quà n # Character ç¶
+U+7277 quán # Character ç·
+U+7278 zì # Character ç¸
+U+7279 tè # Character ç¹
+#U+727a xÄ« # Character çº
+U+727b máng # Character ç»
+#U+727c kÄng # Character ç¼
+#U+727d qiÄn # Character ç½
+U+727e wú # Character ç¾
+U+727f gù # Character ç¿
+#U+7280 xÄ« # Character ç
+U+7281 là # Character ç
+U+7282 là # Character ç
+#U+7283 pÇu # Character ç
+#U+7284 jÄ« # Character ç
+#U+7285 gÄng # Character ç
+U+7286 zhà # Character ç
+#U+7287 bÄn # Character ç
+U+7288 quán # Character ç
+U+7289 rún # Character ç
+U+728a dú # Character ç
+U+728b jù # Character ç
+#U+728c jiÄ # Character ç
+#U+728d jiÄn # Character ç
+#U+728e fÄng # Character ç
+#U+728f piÄn # Character ç
+#U+7290 kÄ # Character ç
+U+7291 jú # Character ç
+U+7292 kà o # Character ç
+U+7293 chú # Character ç
+U+7294 xì # Character ç
+U+7295 bèi # Character ç
+U+7296 luò # Character ç
+U+7297 jiè # Character ç
+U+7298 má # Character ç
+#U+7299 sÄn # Character ç
+U+729a wèi # Character ç
+U+729b máo # Character ç
+#U+729c dÅ«n # Character ç
+U+729d tóng # Character ç
+U+729e ? # Character ç
+U+729f jià ng # Character ç
+U+72a0 ? # Character ç
+U+72a1 lì # Character ç¡
+U+72a2 dú # Character ç¢
+U+72a3 liè # Character ç£
+U+72a4 pà # Character ç¤
+#U+72a5 piÇo # Character ç¥
+U+72a6 bà o # Character ç¦
+#U+72a7 xÄ« # Character ç§
+#U+72a8 chÅu # Character ç¨
+U+72a9 wèi # Character ç©
+U+72aa kuà # Character çª
+#U+72ab chÅu # Character ç«
+#U+72ac quÇn # Character ç¬
+U+72ad ? # Character ç
+U+72ae bá # Character ç®
+U+72af fà n # Character ç¯
+U+72b0 qiú # Character ç°
+#U+72b1 jÇ # Character ç±
+U+72b2 cái # Character ç²
+U+72b3 chuó # Character ç³
+U+72b4 Ã n # Character ç´
+U+72b5 jié # Character çµ
+U+72b6 zhuà ng # Character ç¶
+#U+72b7 guÇng # Character ç·
+U+72b8 mà # Character ç¸
+U+72b9 yóu # Character ç¹
+U+72ba kà ng # Character çº
+U+72bb bó # Character ç»
+#U+72bc hÇu # Character ç¼
+U+72bd yá # Character ç½
+U+72be yÃn # Character ç¾
+#U+72bf huÄn # Character ç¿
+U+72c0 zhuà ng # Character ç
+#U+72c1 yÇn # Character ç
+U+72c2 kuáng # Character ç
+#U+72c3 niÇ # Character ç
+U+72c4 dà # Character ç
+#U+72c5 qÄ«ng # Character ç
+U+72c6 zhòng # Character ç
+U+72c7 mù # Character ç
+U+72c8 bèi # Character ç
+#U+72c9 pÄ« # Character ç
+U+72ca jú # Character ç
+U+72cb nà # Character ç
+#U+72cc shÄng # Character ç
+U+72cd páo # Character ç
+U+72ce xiá # Character ç
+U+72cf tuó # Character ç
+U+72d0 hú # Character ç
+U+72d1 lÃng # Character ç
+U+72d2 fèi # Character ç
+#U+72d3 pÄ« # Character ç
+#U+72d4 nÇ # Character ç
+#U+72d5 Ço # Character ç
+U+72d6 yòu # Character ç
+#U+72d7 gÇu # Character ç
+U+72d8 yuè # Character ç
+#U+72d9 jÅ« # Character ç
+U+72da dà n # Character ç
+U+72db pò # Character ç
+#U+72dc gÇ # Character ç
+#U+72dd xiÇn # Character ç
+U+72de nÃng # Character ç
+U+72df huán # Character ç
+#U+72e0 hÄn # Character ç
+#U+72e1 jiÇo # Character ç¡
+U+72e2 hé # Character ç¢
+U+72e3 zhà o # Character ç£
+U+72e4 jà # Character ç¤
+U+72e5 xùn # Character ç¥
+#U+72e6 shÄn # Character ç¦
+U+72e7 tà # Character ç§
+U+72e8 róng # Character ç¨
+U+72e9 shòu # Character ç©
+#U+72ea tÅng # Character çª
+#U+72eb lÇo # Character ç«
+U+72ec dú # Character ç¬
+U+72ed xiá # Character ç
+#U+72ee shÄ« # Character ç®
+U+72ef huá # Character ç¯
+#U+72f0 zhÄng # Character ç°
+U+72f1 yù # Character ç±
+#U+72f2 sÅ«n # Character ç²
+U+72f3 yú # Character ç³
+U+72f4 bì # Character ç´
+U+72f5 máng # Character çµ
+#U+72f6 xÇ # Character ç¶
+U+72f7 juà n # Character ç·
+U+72f8 li # Character ç¸
+U+72f9 xiá # Character ç¹
+U+72fa yÃn # Character çº
+#U+72fb suÄn # Character ç»
+U+72fc láng # Character ç¼
+U+72fd bèi # Character ç½
+U+72fe zhì # Character ç¾
+U+72ff yán # Character ç¿
diff --git a/resources/chars/latin1/row73.trans b/resources/chars/latin1/row73.trans
new file mode 100644
index 0000000..57ef4af
--- /dev/null
+++ b/resources/chars/latin1/row73.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+7300 shÄ # Character ç
+U+7301 lì # Character ç
+U+7302 hà n # Character ç
+#U+7303 xiÇn # Character ç
+#U+7304 jÄ«ng # Character ç
+U+7305 pái # Character ç
+#U+7306 fÄi # Character ç
+U+7307 yáo # Character ç
+U+7308 bà # Character ç
+U+7309 qà # Character ç
+U+730a nà # Character ç
+#U+730b biÄo # Character ç
+U+730c yìn # Character ç
+U+730d lái # Character ç
+U+730e liè # Character ç
+#U+730f jiÄn # Character ç
+#U+7310 qiÄng # Character ç
+#U+7311 kÅ«n # Character ç
+#U+7312 yÄn # Character ç
+#U+7313 guÇ # Character ç
+U+7314 zòng # Character ç
+U+7315 mà # Character ç
+#U+7316 chÄng # Character ç
+#U+7317 yÄ« # Character ç
+U+7318 zhì # Character ç
+#U+7319 zhÄng # Character ç
+U+731a yá # Character ç
+#U+731b mÄng # Character ç
+#U+731c cÄi # Character ç
+U+731d cù # Character ç
+U+731e shè # Character ç
+U+731f ? # Character ç
+U+7320 ? # Character ç
+U+7321 luó # Character ç¡
+U+7322 hú # Character ç¢
+#U+7323 zÅng # Character ç£
+U+7324 jì # Character ç¤
+#U+7325 wÄi # Character ç¥
+#U+7326 fÄng # Character ç¦
+#U+7327 wÅ # Character ç§
+U+7328 yuán # Character ç¨
+#U+7329 xÄ«ng # Character ç©
+#U+732a zhÅ« # Character çª
+#U+732b mÄo # Character ç«
+U+732c wei # Character ç¬
+U+732d yuán # Character ç
+U+732e xià n # Character ç®
+#U+732f tuÄn # Character ç¯
+U+7330 yà # Character ç°
+U+7331 náo # Character ç±
+#U+7332 xiÄ # Character ç²
+#U+7333 jiÄ # Character ç³
+U+7334 hóu # Character ç´
+#U+7335 biÄn # Character çµ
+U+7336 yóu # Character ç¶
+U+7337 yóu # Character ç·
+U+7338 méi # Character ç¸
+#U+7339 zhÄ # Character ç¹
+U+733a yáo # Character çº
+#U+733b sÅ«n # Character ç»
+U+733c bó # Character ç¼
+U+733d mÃng # Character ç½
+U+733e huá # Character ç¾
+U+733f yuán # Character ç¿
+#U+7340 sÅu # Character ç
+U+7341 mà # Character ç
+U+7342 yuán # Character ç
+#U+7343 dÄi # Character ç
+U+7344 yù # Character ç
+#U+7345 shÄ« # Character ç
+U+7346 háo # Character ç
+U+7347 ? # Character ç
+U+7348 yì # Character ç
+#U+7349 zhÄn # Character ç
+U+734a chuà ng # Character ç
+U+734b háo # Character ç
+U+734c mà n # Character ç
+U+734d jìng # Character ç
+#U+734e jiÇng # Character ç
+U+734f mú # Character ç
+#U+7350 zhÄng # Character ç
+U+7351 chán # Character ç
+U+7352 áo # Character ç
+U+7353 áo # Character ç
+U+7354 háo # Character ç
+#U+7355 cuÄ« # Character ç
+U+7356 fén # Character ç
+U+7357 jué # Character ç
+U+7358 bì # Character ç
+U+7359 bì # Character ç
+U+735a huáng # Character ç
+U+735b pú # Character ç
+U+735c lÃn # Character ç
+U+735d yù # Character ç
+U+735e tóng # Character ç
+U+735f yà o # Character ç
+U+7360 liáo # Character ç
+U+7361 shuò # Character ç¡
+#U+7362 xiÄo # Character ç¢
+U+7363 ? # Character ç£
+U+7364 ? # Character ç¤
+U+7365 xà # Character ç¥
+U+7366 gé # Character ç¦
+U+7367 juà n # Character ç§
+U+7368 dú # Character ç¨
+U+7369 huì # Character ç©
+U+736a kuà i # Character çª
+#U+736b xiÇn # Character ç«
+U+736c xiè # Character ç¬
+U+736d tà # Character ç
+#U+736e xiÇn # Character ç®
+#U+736f xÅ«n # Character ç¯
+U+7370 nÃng # Character ç°
+U+7371 pÃn # Character ç±
+U+7372 huò # Character ç²
+U+7373 nòu # Character ç³
+U+7374 méng # Character ç´
+U+7375 liè # Character çµ
+U+7376 náo # Character ç¶
+#U+7377 guÇng # Character ç·
+U+7378 shòu # Character ç¸
+U+7379 lú # Character ç¹
+U+737a tà # Character çº
+U+737b xià n # Character ç»
+U+737c mà # Character ç¼
+U+737d ráng # Character ç½
+#U+737e huÄn # Character ç¾
+U+737f náo # Character ç¿
+U+7380 luó # Character ç
+#U+7381 xiÇn # Character ç
+U+7382 qà # Character ç
+U+7383 jué # Character ç
+U+7384 xuán # Character ç
+U+7385 mià o # Character ç
+#U+7386 zÄ« # Character ç
+#U+7387 lÇ # Character ç
+U+7388 lú # Character ç
+U+7389 yù # Character ç
+U+738a sù # Character ç
+U+738b wáng # Character ç
+U+738c qiú # Character ç
+#U+738d gÇ # Character ç
+#U+738e dÄ«ng # Character ç
+U+738f lè # Character ç
+#U+7390 bÄ # Character ç
+#U+7391 jÄ« # Character ç
+U+7392 hóng # Character ç
+U+7393 dì # Character ç
+U+7394 quà n # Character ç
+#U+7395 gÄn # Character ç
+#U+7396 jiÇ # Character ç
+U+7397 yú # Character ç
+#U+7398 jÇ # Character ç
+U+7399 yú # Character ç
+U+739a yáng # Character ç
+#U+739b mÇ # Character ç
+#U+739c gÅng # Character ç
+#U+739d wÇ # Character ç
+#U+739e fÅ« # Character ç
+U+739f wén # Character ç
+U+73a0 jiè # Character ç
+U+73a1 yà # Character ç¡
+U+73a2 fén # Character ç¢
+U+73a3 bià n # Character ç£
+#U+73a4 bÄng # Character ç¤
+U+73a5 yuè # Character ç¥
+U+73a6 jué # Character ç¦
+#U+73a7 yÇn # Character ç§
+U+73a8 jué # Character ç¨
+U+73a9 wán # Character ç©
+#U+73aa jiÄn # Character çª
+U+73ab méi # Character ç«
+#U+73ac dÇn # Character ç¬
+U+73ad pà # Character ç
+#U+73ae wÄi # Character ç®
+U+73af huán # Character ç¯
+U+73b0 xià n # Character ç°
+#U+73b1 qiÄng # Character ç±
+U+73b2 lÃng # Character ç²
+U+73b3 dà i # Character ç³
+U+73b4 yì # Character ç´
+U+73b5 án # Character çµ
+U+73b6 pÃng # Character ç¶
+U+73b7 dià n # Character ç·
+U+73b8 fú # Character ç¸
+U+73b9 xuán # Character ç¹
+#U+73ba xÇ # Character çº
+#U+73bb bÅ # Character ç»
+#U+73bc cÇ # Character ç¼
+#U+73bd gÇu # Character ç½
+#U+73be jiÇ # Character ç¾
+U+73bf sháo # Character ç¿
+U+73c0 pò # Character ç
+U+73c1 cà # Character ç
+#U+73c2 kÄ # Character ç
+#U+73c3 rÇn # Character ç
+#U+73c4 shÄng # Character ç
+#U+73c5 shÄn # Character ç
+U+73c6 yà # Character ç
+#U+73c7 zÇ # Character ç
+#U+73c8 jiÄ # Character ç
+U+73c9 mÃn # Character ç
+#U+73ca shÄn # Character ç
+#U+73cb liÇ # Character ç
+U+73cc bì # Character ç
+#U+73cd zhÄn # Character ç
+#U+73ce zhÄn # Character ç
+U+73cf jué # Character ç
+U+73d0 fà # Character ç
+U+73d1 lóng # Character ç
+#U+73d2 jÄ«n # Character ç
+U+73d3 jià o # Character ç
+U+73d4 jià n # Character ç
+U+73d5 lì # Character ç
+#U+73d6 guÄng # Character ç
+#U+73d7 xiÄn # Character ç
+#U+73d8 zhÅu # Character ç
+#U+73d9 gÇng # Character ç
+#U+73da yÄn # Character ç
+U+73db xiù # Character ç
+U+73dc yáng # Character ç
+#U+73dd xÇ # Character ç
+U+73de luò # Character ç
+U+73df sù # Character ç
+#U+73e0 zhÅ« # Character ç
+U+73e1 qÃn # Character ç¡
+U+73e2 kèn # Character ç¢
+U+73e3 xún # Character ç£
+#U+73e4 bÇo # Character ç¤
+#U+73e5 Är # Character ç¥
+U+73e6 xià ng # Character ç¦
+U+73e7 yáo # Character ç§
+U+73e8 xiá # Character ç¨
+U+73e9 héng # Character ç©
+#U+73ea guÄ« # Character çª
+#U+73eb chÅng # Character ç«
+U+73ec xù # Character ç¬
+#U+73ed bÄn # Character ç
+U+73ee pèi # Character ç®
+U+73ef ? # Character ç¯
+#U+73f0 dÄng # Character ç°
+U+73f1 ? # Character ç±
+U+73f2 hún # Character ç²
+U+73f3 wén # Character ç³
+U+73f4 é # Character ç´
+U+73f5 chéng # Character çµ
+U+73f6 tà # Character ç¶
+#U+73f7 wÇ # Character ç·
+U+73f8 wú # Character ç¸
+U+73f9 chéng # Character ç¹
+U+73fa jùn # Character çº
+U+73fb méi # Character ç»
+U+73fc bèi # Character ç¼
+#U+73fd tÇng # Character ç½
+U+73fe xià n # Character ç¾
+U+73ff chuò # Character ç¿
diff --git a/resources/chars/latin1/row74.trans b/resources/chars/latin1/row74.trans
new file mode 100644
index 0000000..7a15c15
--- /dev/null
+++ b/resources/chars/latin1/row74.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+7400 hán # Character ç
+U+7401 xuán # Character ç
+U+7402 yán # Character ç
+U+7403 qiú # Character ç
+#U+7404 quÇn # Character ç
+U+7405 láng # Character ç
+#U+7406 lÇ # Character ç
+U+7407 xiù # Character ç
+U+7408 fú # Character ç
+U+7409 liú # Character ç
+U+740a yé # Character ç
+#U+740b xÄ« # Character ç
+U+740c lÃng # Character ç
+U+740d lì # Character ç
+U+740e jìn # Character ç
+U+740f lián # Character ç
+#U+7410 suÇ # Character ç
+U+7411 ? # Character ç
+U+7412 ? # Character ç
+U+7413 wán # Character ç
+U+7414 dià n # Character ç
+U+7415 pÃn # Character ç
+#U+7416 zhÇn # Character ç
+U+7417 cuì # Character ç
+U+7418 mÃn # Character ç
+U+7419 yù # Character ç
+#U+741a jÅ« # Character ç
+#U+741b chÄn # Character ç
+U+741c lái # Character ç
+U+741d wén # Character ç
+U+741e shèng # Character ç
+U+741f wéi # Character ç
+#U+7420 diÇn # Character ç
+U+7421 chù # Character ç¡
+U+7422 zuó # Character ç¢
+#U+7423 pÄi # Character ç£
+#U+7424 chÄng # Character ç¤
+#U+7425 hÇ # Character ç¥
+U+7426 qà # Character ç¦
+U+7427 è # Character ç§
+#U+7428 kÅ«n # Character ç¨
+#U+7429 chÄng # Character ç©
+U+742a qà # Character çª
+#U+742b bÄng # Character ç«
+#U+742c wÇn # Character ç¬
+U+742d lù # Character ç
+U+742e cóng # Character ç®
+#U+742f guÇn # Character ç¯
+#U+7430 yÇn # Character ç°
+#U+7431 diÄo # Character ç±
+U+7432 bèi # Character ç²
+U+7433 lÃn # Character ç³
+U+7434 qÃn # Character ç´
+U+7435 pà # Character çµ
+U+7436 pá # Character ç¶
+U+7437 què # Character ç·
+U+7438 zhuó # Character ç¸
+U+7439 qÃn # Character ç¹
+U+743a fà # Character çº
+U+743b ? # Character ç»
+U+743c qióng # Character ç¼
+#U+743d dÇ # Character ç½
+U+743e jiè # Character ç¾
+U+743f hún # Character ç¿
+#U+7440 yÇ # Character ç
+U+7441 mà o # Character ç
+U+7442 méi # Character ç
+U+7443 ? # Character ç
+#U+7444 xuÄn # Character ç
+U+7445 tà # Character ç
+#U+7446 xÄ«ng # Character ç
+U+7447 dà i # Character ç
+U+7448 róu # Character ç
+U+7449 mÃn # Character ç
+#U+744a zhÄn # Character ç
+#U+744b wÄi # Character ç
+#U+744c ruÇn # Character ç
+U+744d huà n # Character ç
+#U+744e jiÄ # Character ç
+#U+744f chuÄn # Character ç
+#U+7450 jiÇn # Character ç
+U+7451 zhuà n # Character ç
+U+7452 yáng # Character ç
+U+7453 lià n # Character ç
+U+7454 quán # Character ç
+U+7455 xiá # Character ç
+U+7456 duà n # Character ç
+U+7457 yuà n # Character ç
+U+7458 yé # Character ç
+#U+7459 nÇo # Character ç
+U+745a hú # Character ç
+#U+745b yÄ«ng # Character ç
+U+745c yú # Character ç
+U+745d huáng # Character ç
+U+745e ruì # Character ç
+U+745f sè # Character ç
+U+7460 liú # Character ç
+U+7461 ? # Character ç¡
+U+7462 róng # Character ç¢
+#U+7463 suÇ # Character ç£
+U+7464 yáo # Character ç¤
+#U+7465 wÄn # Character ç¥
+#U+7466 wÅ« # Character ç¦
+#U+7467 jÄ«n # Character ç§
+U+7468 jìn # Character ç¨
+U+7469 yÃng # Character ç©
+#U+746a mÇ # Character çª
+#U+746b tÄo # Character ç«
+U+746c liú # Character ç¬
+U+746d táng # Character ç
+U+746e lì # Character ç®
+U+746f láng # Character ç¯
+#U+7470 guÄ« # Character ç°
+U+7471 zhèn # Character ç±
+#U+7472 qiÄng # Character ç²
+#U+7473 cuÇ # Character ç³
+U+7474 jué # Character ç´
+#U+7475 zhÇo # Character çµ
+U+7476 yáo # Character ç¶
+U+7477 Ã i # Character ç·
+#U+7478 bÄ«n # Character ç¸
+U+7479 tú # Character ç¹
+U+747a cháng # Character çº
+#U+747b kÅ«n # Character ç»
+#U+747c zhuÄn # Character ç¼
+#U+747d cÅng # Character ç½
+#U+747e jÇn # Character ç¾
+#U+747f yÄ« # Character ç¿
+#U+7480 cuÇ # Character ç
+#U+7481 cÅng # Character ç
+U+7482 qà # Character ç
+U+7483 là # Character ç
+#U+7484 yÇng # Character ç
+#U+7485 suÇ # Character ç
+U+7486 qiú # Character ç
+U+7487 xuán # Character ç
+U+7488 áo # Character ç
+U+7489 lián # Character ç
+U+748a mán # Character ç
+#U+748b zhÄng # Character ç
+U+748c yÃn # Character ç
+U+748d ? # Character ç
+#U+748e yÄ«ng # Character ç
+U+748f zhì # Character ç
+U+7490 lù # Character ç
+U+7491 wú # Character ç
+#U+7492 dÄng # Character ç
+U+7493 ? # Character ç
+#U+7494 zÄng # Character ç
+U+7495 xún # Character ç
+U+7496 qú # Character ç
+U+7497 dà ng # Character ç
+U+7498 lÃn # Character ç
+U+7499 liáo # Character ç
+U+749a qióng # Character ç
+U+749b sù # Character ç
+U+749c huáng # Character ç
+#U+749d guÄ« # Character ç
+U+749e pú # Character ç
+#U+749f jÇng # Character ç
+U+74a0 fán # Character ç
+U+74a1 jìn # Character ç¡
+U+74a2 liú # Character ç¢
+#U+74a3 jÄ« # Character ç£
+U+74a4 ? # Character ç¤
+#U+74a5 jÇng # Character ç¥
+U+74a6 à i # Character ç¦
+U+74a7 bì # Character ç§
+U+74a8 cà n # Character ç¨
+U+74a9 qú # Character ç©
+#U+74aa zÇo # Character çª
+#U+74ab dÄng # Character ç«
+#U+74ac jiÇo # Character ç¬
+U+74ad gùn # Character ç
+#U+74ae tÇn # Character ç®
+U+74af huì # Character ç¯
+U+74b0 huán # Character ç°
+U+74b1 sè # Character ç±
+U+74b2 suì # Character ç²
+U+74b3 tián # Character ç³
+U+74b4 ? # Character ç´
+U+74b5 yú # Character çµ
+U+74b6 jìn # Character ç¶
+U+74b7 lú # Character ç·
+#U+74b8 bÄ«n # Character ç¸
+U+74b9 shòu # Character ç¹
+U+74ba wèn # Character çº
+#U+74bb zuÇ # Character ç»
+U+74bc lán # Character ç¼
+#U+74bd xÇ # Character ç½
+U+74be jì # Character ç¾
+U+74bf xuán # Character ç¿
+#U+74c0 ruÇn # Character ç
+U+74c1 huò # Character ç
+U+74c2 gà i # Character ç
+U+74c3 léi # Character ç
+U+74c4 dú # Character ç
+U+74c5 lì # Character ç
+U+74c6 zhà # Character ç
+U+74c7 róu # Character ç
+U+74c8 là # Character ç
+U+74c9 zà n # Character ç
+U+74ca qióng # Character ç
+U+74cb zhé # Character ç
+#U+74cc guÄ« # Character ç
+U+74cd suì # Character ç
+U+74ce là # Character ç
+U+74cf lóng # Character ç
+U+74d0 lú # Character ç
+U+74d1 lì # Character ç
+U+74d2 zà n # Character ç
+U+74d3 là n # Character ç
+#U+74d4 yÄ«ng # Character ç
+U+74d5 mà # Character ç
+#U+74d6 xiÄng # Character ç
+#U+74d7 xÄ« # Character ç
+U+74d8 guà n # Character ç
+U+74d9 dà o # Character ç
+U+74da zà n # Character ç
+U+74db huán # Character ç
+#U+74dc guÄ # Character ç
+U+74dd bó # Character ç
+U+74de dié # Character ç
+U+74df báo # Character ç
+U+74e0 hù # Character ç
+U+74e1 zhà # Character ç¡
+U+74e2 piáo # Character ç¢
+U+74e3 bà n # Character ç£
+U+74e4 ráng # Character ç¤
+U+74e5 lì # Character ç¥
+#U+74e6 wÇ # Character ç¦
+U+74e7 ? # Character ç§
+#U+74e8 jiÄng # Character ç¨
+U+74e9 ? # Character ç©
+#U+74ea fÇn # Character çª
+U+74eb pén # Character ç«
+#U+74ec fÇng # Character ç¬
+#U+74ed dÇn # Character ç
+U+74ee wèng # Character ç®
+#U+74ef Åu # Character ç¯
+U+74f0 ? # Character ç°
+U+74f1 ? # Character ç±
+U+74f2 ? # Character ç²
+U+74f3 hú # Character ç³
+U+74f4 lÃng # Character ç´
+U+74f5 yà # Character çµ
+U+74f6 pÃng # Character ç¶
+U+74f7 cà # Character ç·
+U+74f8 ? # Character ç¸
+U+74f9 juà n # Character ç¹
+U+74fa cháng # Character çº
+#U+74fb chÄ« # Character ç»
+U+74fc ? # Character ç¼
+U+74fd dà ng # Character ç½
+#U+74fe mÄng # Character ç¾
+#U+74ff pÇu # Character ç¿
diff --git a/resources/chars/latin1/row75.trans b/resources/chars/latin1/row75.trans
new file mode 100644
index 0000000..663b2e5
--- /dev/null
+++ b/resources/chars/latin1/row75.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+7500 zhuì # Character ç
+U+7501 pÃng # Character ç
+#U+7502 biÄn # Character ç
+U+7503 zhòu # Character ç
+#U+7504 zhÄn # Character ç
+U+7505 ? # Character ç
+U+7506 cà # Character ç
+#U+7507 yÄ«ng # Character ç
+U+7508 qì # Character ç
+U+7509 xián # Character ç
+#U+750a lÇu # Character ç
+U+750b dì # Character ç
+#U+750c Åu # Character ç
+U+750d méng # Character ç
+#U+750e zhuÄn # Character ç
+U+750f pèng # Character ç
+U+7510 lÃn # Character ç
+U+7511 zèng # Character ç
+#U+7512 wÇ # Character ç
+U+7513 pì # Character ç
+#U+7514 dÄn # Character ç
+U+7515 wèng # Character ç
+#U+7516 yÄ«ng # Character ç
+#U+7517 yÇn # Character ç
+#U+7518 gÄn # Character ç
+U+7519 dà i # Character ç
+U+751a shén # Character ç
+U+751b tián # Character ç
+U+751c tián # Character ç
+#U+751d hÄn # Character ç
+U+751e cháng # Character ç
+#U+751f shÄng # Character ç
+U+7520 qÃng # Character ç
+#U+7521 shÄng # Character ç¡
+#U+7522 chÇn # Character ç¢
+#U+7523 chÇn # Character ç£
+U+7524 ruà # Character ç¤
+#U+7525 shÄng # Character ç¥
+#U+7526 sÅ« # Character ç¦
+#U+7527 sÄn # Character ç§
+U+7528 yòng # Character ç¨
+#U+7529 shuÇi # Character ç©
+U+752a lù # Character çª
+U+752b fu # Character ç«
+#U+752c yÇng # Character ç¬
+U+752d béng # Character ç
+U+752e fèng # Character ç®
+U+752f nÃng # Character ç¯
+U+7530 tián # Character ç°
+U+7531 yóu # Character ç±
+#U+7532 jiÇ # Character ç²
+#U+7533 shÄn # Character ç³
+U+7534 zhá # Character ç´
+U+7535 dià n # Character çµ
+U+7536 fú # Character ç¶
+U+7537 nán # Character ç·
+#U+7538 diÄn # Character ç¸
+U+7539 pÃng # Character ç¹
+#U+753a tÇng # Character çº
+U+753b huà # Character ç»
+#U+753c tÇng # Character ç¼
+#U+753d quÇn # Character ç½
+#U+753e zÄ« # Character ç¾
+U+753f méng # Character ç¿
+U+7540 bì # Character ç
+U+7541 qà # Character ç
+U+7542 liù # Character ç
+U+7543 xún # Character ç
+U+7544 liú # Character ç
+U+7545 chà ng # Character ç
+#U+7546 mÇ # Character ç
+U+7547 yún # Character ç
+U+7548 fà n # Character ç
+U+7549 fú # Character ç
+#U+754a gÄng # Character ç
+U+754b tián # Character ç
+U+754c jiè # Character ç
+U+754d jiè # Character ç
+#U+754e quÇn # Character ç
+U+754f wèi # Character ç
+U+7550 fú # Character ç
+U+7551 tián # Character ç
+#U+7552 mÇ # Character ç
+U+7553 ? # Character ç
+U+7554 pà n # Character ç
+#U+7555 jiÄng # Character ç
+#U+7556 wÄ # Character ç
+U+7557 dá # Character ç
+U+7558 nán # Character ç
+U+7559 liú # Character ç
+#U+755a bÄn # Character ç
+#U+755b zhÄn # Character ç
+U+755c chù # Character ç
+#U+755d mÇ # Character ç
+#U+755e mÇ # Character ç
+U+755f cè # Character ç
+U+7560 ? # Character ç
+#U+7561 gÄi # Character ç¡
+U+7562 bì # Character ç¢
+U+7563 dá # Character ç£
+U+7564 zhì # Character ç¤
+U+7565 è # Character ç¥
+U+7566 qà # Character ç¦
+U+7567 lüè # Character ç§
+#U+7568 pÄn # Character ç¨
+U+7569 ? # Character ç©
+#U+756a fÄn # Character çª
+U+756b huà # Character ç«
+U+756c yú # Character ç¬
+U+756d yú # Character ç
+#U+756e mÇ # Character ç®
+U+756f jùn # Character ç¯
+U+7570 yì # Character ç°
+U+7571 liú # Character ç±
+U+7572 yú # Character ç²
+U+7573 dié # Character ç³
+U+7574 chóu # Character ç´
+U+7575 huà # Character çµ
+#U+7576 dÄng # Character ç¶
+U+7577 chuò # Character ç·
+#U+7578 jÄ« # Character ç¸
+#U+7579 wÇn # Character ç¹
+#U+757a jiÄng # Character çº
+U+757b shéng # Character ç»
+U+757c chà ng # Character ç¼
+#U+757d tuÇn # Character ç½
+U+757e léi # Character ç¾
+#U+757f jÄ« # Character ç¿
+#U+7580 chÄ # Character ç
+U+7581 liú # Character ç
+U+7582 ? # Character ç
+#U+7583 tuÇn # Character ç
+U+7584 lÃn # Character ç
+#U+7585 jiÄng # Character ç
+#U+7586 jiÄng # Character ç
+U+7587 chóu # Character ç
+U+7588 bò # Character ç
+U+7589 dié # Character ç
+U+758a dié # Character ç
+#U+758b pÇ # Character ç
+U+758c niè # Character ç
+U+758d dà n # Character ç
+#U+758e shÅ« # Character ç
+#U+758f shÅ« # Character ç
+U+7590 zhì # Character ç
+U+7591 yà # Character ç
+U+7592 chuáng # Character ç
+#U+7593 nÇi # Character ç
+#U+7594 dÄ«ng # Character ç
+#U+7595 bÇ # Character ç
+U+7596 jié # Character ç
+U+7597 liáo # Character ç
+#U+7598 gÅng # Character ç
+#U+7599 gÄ # Character ç
+U+759a jiù # Character ç
+#U+759b zhÇu # Character ç
+U+759c xià # Character ç
+U+759d shà n # Character ç
+#U+759e xÅ« # Character ç
+U+759f nüè # Character ç
+U+75a0 lì # Character ç
+U+75a1 yáng # Character ç¡
+U+75a2 chèn # Character ç¢
+U+75a3 yóu # Character ç£
+#U+75a4 bÄ # Character ç¤
+U+75a5 jiè # Character ç¥
+U+75a6 jué # Character ç¦
+#U+75a7 zhÄ« # Character ç§
+#U+75a8 xiÄ # Character ç¨
+U+75a9 cuì # Character ç©
+U+75aa bì # Character çª
+U+75ab yì # Character ç«
+U+75ac lì # Character ç¬
+U+75ad zòng # Character ç
+#U+75ae chuÄng # Character ç®
+#U+75af fÄng # Character ç¯
+U+75b0 zhù # Character ç°
+U+75b1 pà o # Character ç±
+U+75b2 pà # Character ç²
+#U+75b3 gÄn # Character ç³
+#U+75b4 kÄ # Character ç´
+#U+75b5 cÄ« # Character çµ
+U+75b6 xiè # Character ç¶
+U+75b7 qà # Character ç·
+#U+75b8 dÇn # Character ç¸
+#U+75b9 zhÄn # Character ç¹
+U+75ba fá # Character çº
+#U+75bb zhÇ # Character ç»
+U+75bc téng # Character ç¼
+#U+75bd jÅ« # Character ç½
+U+75be jà # Character ç¾
+U+75bf fèi # Character ç¿
+U+75c0 qú # Character ç
+U+75c1 dià n # Character ç
+#U+75c2 jiÄ # Character ç
+U+75c3 xián # Character ç
+U+75c4 chá # Character ç
+U+75c5 bìng # Character ç
+U+75c6 nì # Character ç
+U+75c7 zhèng # Character ç
+#U+75c8 yÅng # Character ç
+U+75c9 jìng # Character ç
+U+75ca quán # Character ç
+U+75cb chóng # Character ç
+#U+75cc tÅng # Character ç
+U+75cd yà # Character ç
+#U+75ce kÄi # Character ç
+#U+75cf wÄi # Character ç
+U+75d0 huà # Character ç
+#U+75d1 duÇ # Character ç
+#U+75d2 yÇng # Character ç
+U+75d3 chì # Character ç
+U+75d4 zhì # Character ç
+U+75d5 hén # Character ç
+#U+75d6 yÇ # Character ç
+U+75d7 mèi # Character ç
+U+75d8 dòu # Character ç
+U+75d9 jìng # Character ç
+#U+75da xiÄo # Character ç
+U+75db tòng # Character ç
+#U+75dc tÅ« # Character ç
+U+75dd máng # Character ç
+#U+75de pÇ # Character ç
+#U+75df xiÄo # Character ç
+#U+75e0 suÄn # Character ç
+#U+75e1 pÅ« # Character ç¡
+U+75e2 lì # Character ç¢
+U+75e3 zhì # Character ç£
+U+75e4 cuó # Character ç¤
+U+75e5 duó # Character ç¥
+U+75e6 wù # Character ç¦
+#U+75e7 shÄ # Character ç§
+U+75e8 láo # Character ç¨
+U+75e9 shòu # Character ç©
+U+75ea huà n # Character çª
+U+75eb xián # Character ç«
+U+75ec yì # Character ç¬
+U+75ed péng # Character ç
+U+75ee zhà ng # Character ç®
+#U+75ef guÇn # Character ç¯
+U+75f0 tán # Character ç°
+U+75f1 fèi # Character ç±
+U+75f2 má # Character ç²
+U+75f3 lÃn # Character ç³
+#U+75f4 chÄ« # Character ç´
+U+75f5 jì # Character çµ
+#U+75f6 diÇn # Character ç¶
+#U+75f7 Än # Character ç·
+U+75f8 chì # Character ç¸
+U+75f9 bì # Character ç¹
+U+75fa bì # Character çº
+U+75fb mÃn # Character ç»
+#U+75fc gÅ« # Character ç¼
+#U+75fd duÄ« # Character ç½
+#U+75fe Ä # Character ç¾
+#U+75ff wÄi # Character ç¿
diff --git a/resources/chars/latin1/row76.trans b/resources/chars/latin1/row76.trans
new file mode 100644
index 0000000..3597f05
--- /dev/null
+++ b/resources/chars/latin1/row76.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+7600 yÅ« # Character ç
+U+7601 cuì # Character ç
+#U+7602 yÇ # Character ç
+#U+7603 zhÇ # Character ç
+U+7604 cù # Character ç
+U+7605 dà n # Character ç
+U+7606 shèn # Character ç
+#U+7607 zhÇng # Character ç
+U+7608 jì # Character ç
+U+7609 yù # Character ç
+U+760a hóu # Character ç
+#U+760b fÄng # Character ç
+U+760c là # Character ç
+U+760d yáng # Character ç
+U+760e shèn # Character ç
+U+760f tú # Character ç
+#U+7610 yÇ # Character ç
+#U+7611 guÄ # Character ç
+U+7612 wén # Character ç
+U+7613 huà n # Character ç
+U+7614 kù # Character ç
+#U+7615 jiÇ # Character ç
+#U+7616 yÄ«n # Character ç
+U+7617 yì # Character ç
+#U+7618 lÇ # Character ç
+#U+7619 sÄo # Character ç
+U+761a jué # Character ç
+U+761b chì # Character ç
+U+761c xà # Character ç
+#U+761d guÄn # Character ç
+U+761e yì # Character ç
+#U+761f wÄn # Character ç
+U+7620 jà # Character ç
+#U+7621 chuÄng # Character ç¡
+#U+7622 bÄn # Character ç¢
+#U+7623 lÄi # Character ç£
+U+7624 liú # Character ç¤
+U+7625 chà i # Character ç¥
+U+7626 shòu # Character ç¦
+U+7627 nüè # Character ç§
+#U+7628 diÄn # Character ç¨
+U+7629 da # Character ç©
+#U+762a biÄ # Character çª
+#U+762b tÄn # Character ç«
+U+762c zhà ng # Character ç¬
+#U+762d biÄo # Character ç
+U+762e shèn # Character ç®
+U+762f cù # Character ç¯
+#U+7630 luÇ # Character ç°
+U+7631 yì # Character ç±
+U+7632 zòng # Character ç²
+#U+7633 chÅu # Character ç³
+U+7634 zhà ng # Character ç´
+U+7635 zhà i # Character çµ
+U+7636 sòu # Character ç¶
+#U+7637 suÇ # Character ç·
+U+7638 qué # Character ç¸
+U+7639 dià o # Character ç¹
+U+763a lòu # Character çº
+#U+763b lÇ # Character ç»
+U+763c mò # Character ç¼
+U+763d jìn # Character ç½
+#U+763e yÇn # Character ç¾
+#U+763f yÇng # Character ç¿
+U+7640 huáng # Character ç
+U+7641 fú # Character ç
+U+7642 liáo # Character ç
+U+7643 lóng # Character ç
+U+7644 qiáo # Character ç
+U+7645 liú # Character ç
+U+7646 láo # Character ç
+U+7647 xián # Character ç
+U+7648 fèi # Character ç
+U+7649 dà n # Character ç
+U+764a yìn # Character ç
+U+764b hè # Character ç
+U+764c ái # Character ç
+#U+764d bÄn # Character ç
+U+764e xián # Character ç
+#U+764f guÄn # Character ç
+U+7650 guà i # Character ç
+U+7651 nóng # Character ç
+U+7652 yù # Character ç
+U+7653 wéi # Character ç
+U+7654 yì # Character ç
+#U+7655 yÅng # Character ç
+#U+7656 pÇ # Character ç
+#U+7657 lÄi # Character ç
+U+7658 lì # Character ç
+#U+7659 shÇ # Character ç
+U+765a dà n # Character ç
+#U+765b lÇn # Character ç
+U+765c dià n # Character ç
+#U+765d lÇn # Character ç
+U+765e là i # Character ç
+#U+765f biÄ # Character ç
+U+7660 jì # Character ç
+#U+7661 chÄ« # Character ç¡
+#U+7662 yÇng # Character ç¢
+#U+7663 xiÇn # Character ç£
+U+7664 jié # Character ç¤
+#U+7665 zhÄng # Character ç¥
+U+7666 ? # Character ç¦
+U+7667 lì # Character ç§
+U+7668 huò # Character ç¨
+U+7669 là i # Character ç©
+U+766a ? # Character çª
+#U+766b diÄn # Character ç«
+#U+766c xiÇn # Character ç¬
+#U+766d yÇng # Character ç
+#U+766e yÇn # Character ç®
+U+766f qú # Character ç¯
+#U+7670 yÅng # Character ç°
+#U+7671 tÄn # Character ç±
+#U+7672 diÄn # Character ç²
+#U+7673 luÇ # Character ç³
+U+7674 lüán # Character ç´
+U+7675 luán # Character çµ
+#U+7676 bÅ # Character ç¶
+U+7677 ? # Character ç·
+#U+7678 guÇ # Character ç¸
+#U+7679 pÅ # Character ç¹
+#U+767a fÄ # Character çº
+#U+767b dÄng # Character ç»
+#U+767c fÄ # Character ç¼
+U+767d bái # Character ç½
+#U+767e bÇi # Character ç¾
+U+767f qié # Character ç¿
+#U+7680 bÄ« # Character ç
+U+7681 zà o # Character ç
+U+7682 zà o # Character ç
+U+7683 mà o # Character ç
+U+7684 de # Character ç
+#U+7685 pÄ # Character ç
+#U+7686 jiÄ # Character ç
+U+7687 huáng # Character ç
+#U+7688 guÄ« # Character ç
+#U+7689 cÇ # Character ç
+U+768a lÃng # Character ç
+#U+768b gÄo # Character ç
+U+768c mò # Character ç
+U+768d jà # Character ç
+#U+768e jiÇo # Character ç
+#U+768f pÄng # Character ç
+#U+7690 gÄo # Character ç
+U+7691 ái # Character ç
+U+7692 é # Character ç
+U+7693 hà o # Character ç
+U+7694 hà n # Character ç
+#U+7695 bÄ« # Character ç
+#U+7696 wÇn # Character ç
+U+7697 chóu # Character ç
+U+7698 qià n # Character ç
+#U+7699 xÄ« # Character ç
+U+769a ái # Character ç
+#U+769b jiÇng # Character ç
+U+769c hà o # Character ç
+#U+769d huÇng # Character ç
+U+769e hà o # Character ç
+U+769f zé # Character ç
+#U+76a0 cuÇ # Character ç
+U+76a1 hà o # Character ç¡
+#U+76a2 xiÇo # Character ç¢
+U+76a3 yè # Character ç£
+U+76a4 pó # Character ç¤
+U+76a5 hà o # Character ç¥
+#U+76a6 jiÇo # Character ç¦
+U+76a7 à i # Character ç§
+#U+76a8 xÄ«ng # Character ç¨
+U+76a9 huà ng # Character ç©
+U+76aa lì # Character çª
+#U+76ab piÇo # Character ç«
+U+76ac hè # Character ç¬
+U+76ad jià o # Character ç
+U+76ae pà # Character ç®
+#U+76af gÇn # Character ç¯
+U+76b0 pà o # Character ç°
+U+76b1 zhòu # Character ç±
+#U+76b2 jÅ«n # Character ç²
+U+76b3 qiú # Character ç³
+#U+76b4 cÅ«n # Character ç´
+U+76b5 què # Character çµ
+#U+76b6 zhÄ # Character ç¶
+#U+76b7 gÇ # Character ç·
+#U+76b8 jÅ«n # Character ç¸
+#U+76b9 jÅ«n # Character ç¹
+U+76ba zhòu # Character çº
+#U+76bb zhÄ # Character ç»
+#U+76bc gÇ # Character ç¼
+#U+76bd zhÇn # Character ç½
+U+76be dú # Character ç¾
+#U+76bf mÇn # Character ç¿
+#U+76c0 qÇ # Character ç
+U+76c1 yÃng # Character ç
+U+76c2 yú # Character ç
+#U+76c3 bÄi # Character ç
+#U+76c4 zhÄo # Character ç
+#U+76c5 zhÅng # Character ç
+U+76c6 pén # Character ç
+U+76c7 hé # Character ç
+U+76c8 yÃng # Character ç
+U+76c9 hé # Character ç
+U+76ca yì # Character ç
+#U+76cb bÅ # Character ç
+#U+76cc wÇn # Character ç
+U+76cd hé # Character ç
+U+76ce à ng # Character ç
+#U+76cf zhÇn # Character ç
+U+76d0 yán # Character ç
+#U+76d1 jiÄn # Character ç
+U+76d2 hé # Character ç
+#U+76d3 yÅ« # Character ç
+#U+76d4 kuÄ« # Character ç
+U+76d5 fà n # Character ç
+U+76d6 gà i # Character ç
+U+76d7 dà o # Character ç
+U+76d8 pán # Character ç
+#U+76d9 fÇ # Character ç
+U+76da qiú # Character ç
+U+76db shèng # Character ç
+U+76dc dà o # Character ç
+U+76dd lù # Character ç
+#U+76de zhÇn # Character ç
+U+76df méng # Character ç
+#U+76e0 lÇ # Character ç
+#U+76e1 jÇn # Character ç¡
+U+76e2 xù # Character ç¢
+#U+76e3 jiÄn # Character ç£
+U+76e4 pán # Character ç¤
+U+76e5 guà n # Character ç¥
+#U+76e6 Än # Character ç¦
+U+76e7 lú # Character ç§
+#U+76e8 shÇ # Character ç¨
+#U+76e9 zhÅu # Character ç©
+U+76ea dà ng # Character çª
+#U+76eb Än # Character ç«
+#U+76ec gÇ # Character ç¬
+U+76ed lì # Character ç
+U+76ee mù # Character ç®
+#U+76ef dÄ«ng # Character ç¯
+#U+76f0 gÇn # Character ç°
+#U+76f1 xÅ« # Character ç±
+U+76f2 máng # Character ç²
+U+76f3 máng # Character ç³
+U+76f4 zhà # Character ç´
+U+76f5 qì # Character çµ
+#U+76f6 ruÇn # Character ç¶
+U+76f7 tián # Character ç·
+#U+76f8 xiÄng # Character ç¸
+U+76f9 dùn # Character ç¹
+#U+76fa xÄ«n # Character çº
+U+76fb xì # Character ç»
+U+76fc pà n # Character ç¼
+#U+76fd fÄng # Character ç½
+U+76fe dùn # Character ç¾
+U+76ff mÃn # Character ç¿
diff --git a/resources/chars/latin1/row77.trans b/resources/chars/latin1/row77.trans
new file mode 100644
index 0000000..2114bf5
--- /dev/null
+++ b/resources/chars/latin1/row77.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+7700 mÃng # Character ç
+#U+7701 shÄng # Character ç
+U+7702 shì # Character ç
+U+7703 yún # Character ç
+#U+7704 miÇn # Character ç
+#U+7705 pÄn # Character ç
+#U+7706 fÇng # Character ç
+#U+7707 miÇo # Character ç
+#U+7708 dÄn # Character ç
+U+7709 méi # Character ç
+U+770a mà o # Character ç
+U+770b kà n # Character ç
+U+770c xià n # Character ç
+#U+770d Åu # Character ç
+U+770e shì # Character ç
+#U+770f yÄng # Character ç
+#U+7710 zhÄng # Character ç
+#U+7711 yÇo # Character ç
+U+7712 shèn # Character ç
+U+7713 huò # Character ç
+U+7714 dà # Character ç
+#U+7715 zhÄn # Character ç
+U+7716 kuà ng # Character ç
+#U+7717 jÅ« # Character ç
+U+7718 shèn # Character ç
+U+7719 chì # Character ç
+#U+771a shÄng # Character ç
+U+771b mèi # Character ç
+U+771c mò # Character ç
+U+771d zhù # Character ç
+#U+771e zhÄn # Character ç
+#U+771f zhÄn # Character ç
+U+7720 mián # Character ç
+#U+7721 dÄ« # Character ç¡
+#U+7722 yuÄn # Character ç¢
+U+7723 dié # Character ç£
+U+7724 yà # Character ç¤
+U+7725 zì # Character ç¥
+U+7726 zì # Character ç¦
+#U+7727 chÇo # Character ç§
+#U+7728 zhÇ # Character ç¨
+U+7729 xuà n # Character ç©
+#U+772a bÇng # Character çª
+#U+772b mÇ # Character ç«
+U+772c lóng # Character ç¬
+#U+772d suÄ« # Character ç
+U+772e dòng # Character ç®
+#U+772f mÄ« # Character ç¯
+U+7730 dié # Character ç°
+U+7731 yà # Character ç±
+U+7732 èr # Character ç²
+#U+7733 mÇng # Character ç³
+U+7734 xuà n # Character ç´
+#U+7735 chÄ« # Character çµ
+U+7736 kuà ng # Character ç¶
+U+7737 juà n # Character ç·
+U+7738 móu # Character ç¸
+U+7739 zhèn # Character ç¹
+U+773a tià o # Character çº
+U+773b yáng # Character ç»
+#U+773c yÇn # Character ç¼
+U+773d mò # Character ç½
+U+773e zhòng # Character ç¾
+U+773f mà i # Character ç¿
+U+7740 zhe # Character ç
+#U+7741 zhÄng # Character ç
+U+7742 méi # Character ç
+U+7743 jùn # Character ç
+U+7744 shà o # Character ç
+U+7745 hà n # Character ç
+#U+7746 huÇn # Character ç
+U+7747 dì # Character ç
+#U+7748 chÄng # Character ç
+#U+7749 cuÅ # Character ç
+U+774a juà n # Character ç
+U+774b é # Character ç
+#U+774c wÇn # Character ç
+U+774d xià n # Character ç
+#U+774e xÄ« # Character ç
+U+774f kùn # Character ç
+U+7750 là i # Character ç
+#U+7751 jiÇn # Character ç
+#U+7752 shÇn # Character ç
+#U+7753 tiÇn # Character ç
+#U+7754 hÇn # Character ç
+#U+7755 wÇn # Character ç
+U+7756 lÃng # Character ç
+U+7757 shì # Character ç
+U+7758 qióng # Character ç
+U+7759 liè # Character ç
+U+775a yái # Character ç
+U+775b jing # Character ç
+#U+775c zhÄng # Character ç
+U+775d là # Character ç
+U+775e là i # Character ç
+U+775f suì # Character ç
+U+7760 juà n # Character ç
+U+7761 shuì # Character ç¡
+#U+7762 suÄ« # Character ç¢
+#U+7763 dÅ« # Character ç£
+U+7764 bì # Character ç¤
+U+7765 bì # Character ç¥
+U+7766 mù # Character ç¦
+#U+7767 hÅ«n # Character ç§
+U+7768 nì # Character ç¨
+U+7769 lù # Character ç©
+U+776a yì # Character çª
+U+776b jié # Character ç«
+#U+776c cÇi # Character ç¬
+#U+776d zhÇu # Character ç
+U+776e yú # Character ç®
+#U+776f hÅ«n # Character ç¯
+U+7770 mà # Character ç°
+U+7771 xià # Character ç±
+#U+7772 xÇng # Character ç²
+#U+7773 xÄ« # Character ç³
+U+7774 gùn # Character ç´
+U+7775 ? # Character çµ
+#U+7776 chÇn # Character ç¶
+#U+7777 jiÄn # Character ç·
+U+7778 mèi # Character ç¸
+#U+7779 dÇ # Character ç¹
+U+777a hóu # Character çº
+#U+777b xuÄn # Character ç»
+U+777c tì # Character ç¼
+U+777d kuà # Character ç½
+#U+777e gÄo # Character ç¾
+U+777f ruì # Character ç¿
+U+7780 mòu # Character ç
+U+7781 xù # Character ç
+#U+7782 fÄ # Character ç
+#U+7783 wÄn # Character ç
+U+7784 miáo # Character ç
+#U+7785 chÇu # Character ç
+U+7786 kuì # Character ç
+#U+7787 mÄ« # Character ç
+#U+7788 wÄng # Character ç
+U+7789 kòu # Character ç
+U+778a dà ng # Character ç
+#U+778b chÄn # Character ç
+#U+778c kÄ # Character ç
+#U+778d sÇu # Character ç
+#U+778e xiÄ # Character ç
+U+778f qióng # Character ç
+U+7790 mà o # Character ç
+U+7791 mÃng # Character ç
+U+7792 mán # Character ç
+U+7793 shuì # Character ç
+U+7794 zé # Character ç
+U+7795 zhà ng # Character ç
+U+7796 yì # Character ç
+#U+7797 diÄo # Character ç
+#U+7798 Åu # Character ç
+U+7799 mò # Character ç
+U+779a shùn # Character ç
+#U+779b cÅng # Character ç
+#U+779c lÅu # Character ç
+#U+779d chÄ« # Character ç
+U+779e mán # Character ç
+#U+779f piÇo # Character ç
+#U+77a0 chÄng # Character ç
+U+77a1 jì # Character ç¡
+U+77a2 méng # Character ç¢
+U+77a3 ? # Character ç£
+U+77a4 rún # Character ç¤
+#U+77a5 piÄ # Character ç¥
+#U+77a6 xÄ« # Character ç¦
+U+77a7 qiáo # Character ç§
+U+77a8 pú # Character ç¨
+#U+77a9 zhÇ # Character ç©
+U+77aa dèng # Character çª
+#U+77ab shÄn # Character ç«
+U+77ac shùn # Character ç¬
+#U+77ad liÇo # Character ç
+U+77ae chè # Character ç®
+U+77af xián # Character ç¯
+U+77b0 kà n # Character ç°
+U+77b1 yè # Character ç±
+U+77b2 xù # Character ç²
+U+77b3 tóng # Character ç³
+U+77b4 móu # Character ç´
+U+77b5 lÃn # Character çµ
+U+77b6 kuì # Character ç¶
+U+77b7 xián # Character ç·
+U+77b8 yè # Character ç¸
+U+77b9 Ã i # Character ç¹
+U+77ba huì # Character çº
+#U+77bb zhÄn # Character ç»
+#U+77bc jiÇn # Character ç¼
+#U+77bd gÇ # Character ç½
+U+77be zhà o # Character ç¾
+#U+77bf qÅ« # Character ç¿
+U+77c0 wéi # Character ç
+#U+77c1 chÇu # Character ç
+U+77c2 sà o # Character ç
+#U+77c3 nÇng # Character ç
+#U+77c4 xÅ«n # Character ç
+U+77c5 yà o # Character ç
+U+77c6 huò # Character ç
+U+77c7 méng # Character ç
+U+77c8 mián # Character ç
+#U+77c9 bÄ«n # Character ç
+U+77ca mián # Character ç
+U+77cb lì # Character ç
+U+77cc kuà ng # Character ç
+U+77cd jué # Character ç
+#U+77ce xuÄn # Character ç
+U+77cf mián # Character ç
+U+77d0 huò # Character ç
+U+77d1 lú # Character ç
+U+77d2 méng # Character ç
+U+77d3 lóng # Character ç
+U+77d4 guà n # Character ç
+#U+77d5 mÇn # Character ç
+#U+77d6 xÇ # Character ç
+U+77d7 chù # Character ç
+#U+77d8 tÇng # Character ç
+U+77d9 kà n # Character ç
+#U+77da zhÇ # Character ç
+U+77db máo # Character ç
+#U+77dc jÄ«n # Character ç
+U+77dd lÃn # Character ç
+U+77de yù # Character ç
+U+77df shuò # Character ç
+U+77e0 cè # Character ç
+U+77e1 jué # Character ç¡
+#U+77e2 shÇ # Character ç¢
+#U+77e3 yÇ # Character ç£
+#U+77e4 shÄn # Character ç¤
+#U+77e5 zhÄ« # Character ç¥
+U+77e6 hóu # Character ç¦
+#U+77e7 shÄn # Character ç§
+#U+77e8 yÇng # Character ç¨
+U+77e9 ju # Character ç©
+#U+77ea zhÅu # Character çª
+#U+77eb jiÇo # Character ç«
+U+77ec cuó # Character ç¬
+#U+77ed duÇn # Character ç
+#U+77ee Çi # Character ç®
+#U+77ef jiÇo # Character ç¯
+#U+77f0 zÄng # Character ç°
+U+77f1 huò # Character ç±
+#U+77f2 bÇi # Character ç²
+U+77f3 shà # Character ç³
+U+77f4 dìng # Character ç´
+U+77f5 qì # Character çµ
+#U+77f6 jÄ« # Character ç¶
+#U+77f7 zÇ # Character ç·
+#U+77f8 gÄn # Character ç¸
+U+77f9 wù # Character ç¹
+#U+77fa tuÅ # Character çº
+U+77fb kù # Character ç»
+#U+77fc qiÄng # Character ç¼
+U+77fd xì # Character ç½
+U+77fe fán # Character ç¾
+U+77ff kuà ng # Character ç¿
diff --git a/resources/chars/latin1/row78.trans b/resources/chars/latin1/row78.trans
new file mode 100644
index 0000000..fbbb4fa
--- /dev/null
+++ b/resources/chars/latin1/row78.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+7800 dà ng # Character ç
+#U+7801 mÇ # Character ç
+#U+7802 shÄ # Character ç
+#U+7803 dÄn # Character ç
+U+7804 jué # Character ç
+U+7805 lì # Character ç
+#U+7806 fÅ« # Character ç
+U+7807 mÃn # Character ç
+#U+7808 nuÇ # Character ç
+U+7809 huò # Character ç
+U+780a kà ng # Character ç
+#U+780b zhÇ # Character ç
+U+780c qì # Character ç
+#U+780d kÇn # Character ç
+U+780e jiè # Character ç
+#U+780f fÄn # Character ç
+U+7810 è # Character ç
+U+7811 yà # Character ç
+#U+7812 pÄ« # Character ç
+U+7813 zhé # Character ç
+U+7814 yán # Character ç
+U+7815 suì # Character ç
+#U+7816 zhuÄn # Character ç
+#U+7817 chÄ # Character ç
+U+7818 dùn # Character ç
+#U+7819 pÄn # Character ç
+U+781a yà n # Character ç
+U+781b ? # Character ç
+#U+781c fÄng # Character ç
+U+781d fá # Character ç
+U+781e mò # Character ç
+U+781f zhà # Character ç
+#U+7820 qÅ« # Character ç
+U+7821 yù # Character ç ¡
+#U+7822 luÇ # Character ç ¢
+U+7823 tuó # Character ç £
+U+7824 tuó # Character ç ¤
+#U+7825 dÇ # Character ç ¥
+U+7826 zhà i # Character ç ¦
+#U+7827 zhÄn # Character ç §
+U+7828 Ã i # Character ç ¨
+U+7829 fèi # Character ç ©
+#U+782a mÇ # Character ç ª
+#U+782b zhÇ # Character ç «
+U+782c lì # Character ç ¬
+#U+782d biÄn # Character ç
+#U+782e nÇ # Character ç ®
+#U+782f pÄ«ng # Character ç ¯
+#U+7830 pÄng # Character ç °
+U+7831 lÃng # Character ç ±
+U+7832 pà o # Character ç ²
+U+7833 lè # Character ç ³
+U+7834 pò # Character ç ´
+#U+7835 bÅ # Character ç µ
+U+7836 pò # Character ç ¶
+#U+7837 shÄn # Character ç ·
+U+7838 zá # Character ç ¸
+#U+7839 nuÇ # Character ç ¹
+U+783a lì # Character ç º
+U+783b lóng # Character ç »
+U+783c tóng # Character ç ¼
+U+783d ? # Character ç ½
+U+783e lì # Character ç ¾
+U+783f ? # Character ç ¿
+#U+7840 chÇ # Character ç¡
+#U+7841 kÄng # Character ç¡
+U+7842 quán # Character ç¡
+#U+7843 zhÅ« # Character ç¡
+#U+7844 kuÄng # Character ç¡
+#U+7845 guÄ« # Character ç¡
+U+7846 è # Character ç¡
+U+7847 náo # Character ç¡
+U+7848 jiá # Character ç¡
+U+7849 lù # Character ç¡
+#U+784a wÄi # Character ç¡
+U+784b à i # Character ç¡
+U+784c luò # Character ç¡
+U+784d kèn # Character ç¡
+U+784e xÃng # Character ç¡
+U+784f yán # Character ç¡
+U+7850 tóng # Character ç¡
+#U+7851 pÄng # Character ç¡
+#U+7852 xÄ« # Character ç¡
+U+7853 ? # Character ç¡
+U+7854 hóng # Character ç¡
+U+7855 shuò # Character ç¡
+U+7856 xiá # Character ç¡
+#U+7857 qiÄo # Character ç¡
+U+7858 ? # Character ç¡
+U+7859 wèi # Character ç¡
+U+785a qiáo # Character ç¡
+U+785b ? # Character ç¡
+#U+785c kÄng # Character ç¡
+#U+785d xiÄo # Character ç¡
+U+785e què # Character ç¡
+U+785f chà n # Character ç¡
+#U+7860 lÇng # Character ç¡
+U+7861 hóng # Character 硡
+U+7862 yú # Character 硢
+#U+7863 xiÄo # Character ç¡£
+U+7864 xiá # Character 硤
+#U+7865 mÇng # Character ç¡¥
+U+7866 lòng # Character 硦
+#U+7867 iÇng # Character 硧
+#U+7868 chÄ # Character 硨
+U+7869 chè # Character 硩
+U+786a é # Character 硪
+U+786b liú # Character 硫
+U+786c yìng # Character 硬
+U+786d máng # Character ç¡
+U+786e què # Character 确
+U+786f yà n # Character 硯
+#U+7870 shÄ # Character ç¡°
+#U+7871 kÇn # Character 硱
+U+7872 yù # Character 硲
+U+7873 ? # Character 硳
+U+7874 ? # Character ç¡´
+#U+7875 lÇ # Character 硵
+#U+7876 chÄn # Character 硶
+#U+7877 jiÇn # Character ç¡·
+U+7878 nuè # Character 硸
+#U+7879 sÅng # Character 硹
+U+787a zhuó # Character 硺
+#U+787b kÄng # Character ç¡»
+U+787c péng # Character 硼
+#U+787d yÇn # Character 硽
+U+787e zhuì # Character 硾
+#U+787f kÅng # Character ç¡¿
+U+7880 céng # Character ç¢
+U+7881 qà # Character ç¢
+U+7882 zòng # Character ç¢
+U+7883 qìng # Character ç¢
+U+7884 lÃn # Character ç¢
+#U+7885 jÅ«n # Character ç¢
+#U+7886 bÅ # Character ç¢
+U+7887 dìng # Character ç¢
+U+7888 mÃn # Character ç¢
+#U+7889 diÄo # Character ç¢
+#U+788a jiÄn # Character ç¢
+U+788b hè # Character ç¢
+U+788c lù # Character ç¢
+U+788d à i # Character ç¢
+U+788e suì # Character ç¢
+U+788f què # Character ç¢
+U+7890 lÃng # Character ç¢
+#U+7891 bÄi # Character ç¢
+U+7892 yÃn # Character ç¢
+U+7893 duì # Character ç¢
+#U+7894 wÇ # Character ç¢
+U+7895 qà # Character ç¢
+U+7896 lùn # Character ç¢
+#U+7897 wÇn # Character ç¢
+#U+7898 diÇn # Character ç¢
+#U+7899 gÄng # Character ç¢
+U+789a péi # Character ç¢
+U+789b qì # Character ç¢
+#U+789c chÄn # Character ç¢
+#U+789d ruÇn # Character ç¢
+U+789e yán # Character ç¢
+U+789f dié # Character ç¢
+U+78a0 dìng # Character ç¢
+U+78a1 dú # Character 碡
+U+78a2 tuó # Character 碢
+U+78a3 jié # Character 碣
+#U+78a4 yīng # Character 碤
+#U+78a5 biÇn # Character 碥
+U+78a6 kè # Character 碦
+U+78a7 bì # Character 碧
+#U+78a8 wÄi # Character 碨
+U+78a9 shuò # Character 碩
+#U+78aa zhÄn # Character 碪
+U+78ab duà n # Character 碫
+U+78ac xiá # Character 碬
+U+78ad dà ng # Character ç¢
+U+78ae tà # Character 碮
+#U+78af nÇo # Character 碯
+U+78b0 pèng # Character 碰
+#U+78b1 jiÇn # Character 碱
+U+78b2 dì # Character 碲
+U+78b3 tà n # Character 碳
+U+78b4 chá # Character 碴
+U+78b5 ? # Character 碵
+U+78b6 qì # Character 碶
+U+78b7 ? # Character 碷
+#U+78b8 fÄng # Character 碸
+U+78b9 xuà n # Character 碹
+U+78ba què # Character 確
+U+78bb què # Character 碻
+#U+78bc mÇ # Character 碼
+#U+78bd gÅng # Character 碽
+#U+78be niÇn # Character 碾
+U+78bf sù # Character 碿
+U+78c0 é # Character ç£
+U+78c1 cà # Character ç£
+U+78c2 liù # Character ç£
+#U+78c3 sÄ« # Character ç£
+U+78c4 táng # Character ç£
+U+78c5 bà ng # Character ç£
+U+78c6 huá # Character ç£
+#U+78c7 pÄ« # Character ç£
+#U+78c8 wÄi # Character ç£
+#U+78c9 sÇng # Character ç£
+#U+78ca lÄi # Character ç£
+#U+78cb cuÅ # Character ç£
+#U+78cc zhÄn # Character ç£
+U+78cd xiá # Character ç£
+#U+78ce qÄ« # Character ç£
+U+78cf lián # Character ç£
+U+78d0 pán # Character ç£
+U+78d1 wèi # Character ç£
+#U+78d2 yÇn # Character ç£
+#U+78d3 duÄ« # Character ç£
+U+78d4 zhé # Character ç£
+#U+78d5 kÄ # Character ç£
+#U+78d6 lÄ # Character ç£
+U+78d7 ? # Character ç£
+U+78d8 qìng # Character ç£
+#U+78d9 gÇn # Character ç£
+#U+78da zhuÄn # Character ç£
+U+78db chán # Character ç£
+U+78dc qì # Character ç£
+U+78dd áo # Character ç£
+#U+78de pÄng # Character ç£
+U+78df lù # Character ç£
+#U+78e0 lÇ # Character ç£
+U+78e1 kà n # Character 磡
+#U+78e2 qiÇng # Character 磢
+#U+78e3 chÄn # Character 磣
+#U+78e4 yÇn # Character 磤
+#U+78e5 lÄi # Character 磥
+#U+78e6 biÄo # Character 磦
+U+78e7 qì # Character 磧
+U+78e8 mó # Character 磨
+#U+78e9 qī # Character 磩
+#U+78ea cuī # Character 磪
+#U+78eb zÅng # Character 磫
+U+78ec qìng # Character 磬
+U+78ed chuò # Character ç£
+U+78ee ? # Character 磮
+#U+78ef jī # Character 磯
+U+78f0 shà n # Character 磰
+U+78f1 láo # Character 磱
+U+78f2 qú # Character 磲
+#U+78f3 zÄng # Character 磳
+U+78f4 dèng # Character 磴
+U+78f5 jià n # Character 磵
+U+78f6 xì # Character 磶
+U+78f7 lÃn # Character 磷
+U+78f8 dìng # Character 磸
+U+78f9 dià n # Character 磹
+U+78fa huáng # Character 磺
+U+78fb pán # Character 磻
+U+78fc zá # Character 磼
+#U+78fd qiÄo # Character 磽
+#U+78fe dī # Character 磾
+U+78ff lì # Character 磿
diff --git a/resources/chars/latin1/row79.trans b/resources/chars/latin1/row79.trans
new file mode 100644
index 0000000..2a33aab
--- /dev/null
+++ b/resources/chars/latin1/row79.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+7900 ? # Character ç¤
+#U+7901 jiÄo # Character ç¤
+U+7902 ? # Character ç¤
+#U+7903 zhÇng # Character ç¤
+U+7904 qiáo # Character ç¤
+#U+7905 dÅ«n # Character ç¤
+#U+7906 xiÇn # Character ç¤
+U+7907 yù # Character ç¤
+U+7908 zhuì # Character ç¤
+U+7909 hé # Character ç¤
+U+790a huò # Character ç¤
+U+790b zhái # Character ç¤
+U+790c lèi # Character ç¤
+#U+790d kÄ # Character ç¤
+#U+790e chÇ # Character ç¤
+U+790f jà # Character ç¤
+U+7910 què # Character ç¤
+U+7911 dà ng # Character ç¤
+#U+7912 yÇ # Character ç¤
+#U+7913 jiÄng # Character ç¤
+U+7914 pì # Character ç¤
+#U+7915 pÄ« # Character ç¤
+U+7916 yù # Character ç¤
+#U+7917 pÄ«n # Character ç¤
+U+7918 qì # Character ç¤
+U+7919 à i # Character ç¤
+U+791a kà i # Character ç¤
+#U+791b jiÄn # Character ç¤
+U+791c yù # Character ç¤
+#U+791d ruÇn # Character ç¤
+U+791e méng # Character ç¤
+U+791f pà o # Character ç¤
+U+7920 cà # Character ç¤
+U+7921 bó # Character 礡
+U+7922 ? # Character 礢
+U+7923 miè # Character 礣
+#U+7924 cÇ # Character 礤
+U+7925 xián # Character 礥
+U+7926 kuà ng # Character 礦
+U+7927 lèi # Character 礧
+#U+7928 lÄi # Character 礨
+U+7929 zhì # Character 礩
+U+792a lì # Character 礪
+U+792b lì # Character 礫
+U+792c fán # Character 礬
+U+792d què # Character ç¤
+U+792e pà o # Character 礮
+#U+792f yīng # Character 礯
+U+7930 lì # Character 礰
+U+7931 lóng # Character 礱
+U+7932 lóng # Character 礲
+U+7933 mò # Character 礳
+U+7934 bó # Character 礴
+#U+7935 shuÄng # Character 礵
+U+7936 guà n # Character 礶
+U+7937 lán # Character 礷
+#U+7938 zÇn # Character 礸
+U+7939 yán # Character 礹
+U+793a shì # Character 示
+U+793b ? # Character 礻
+#U+793c lÇ # Character 礼
+U+793d réng # Character 礽
+U+793e shè # Character 社
+U+793f yuè # Character 礿
+U+7940 sì # Character ç¥
+U+7941 qà # Character ç¥
+#U+7942 tÄ # Character ç¥
+U+7943 mà # Character ç¥
+U+7944 xiè # Character ç¥
+#U+7945 xiÄn # Character ç¥
+#U+7946 xiÄn # Character ç¥
+#U+7947 zhÄ« # Character ç¥
+U+7948 qà # Character ç¥
+#U+7949 zhÇ # Character ç¥
+#U+794a bÄng # Character ç¥
+U+794b duì # Character ç¥
+U+794c zhòng # Character ç¥
+U+794d ? # Character ç¥
+#U+794e yÄ« # Character ç¥
+U+794f shà # Character ç¥
+U+7950 yòu # Character ç¥
+U+7951 zhì # Character ç¥
+U+7952 tiáo # Character ç¥
+U+7953 fú # Character ç¥
+U+7954 fù # Character ç¥
+U+7955 mì # Character ç¥
+#U+7956 zÇ # Character ç¥
+#U+7957 zhÄ« # Character ç¥
+U+7958 suà n # Character ç¥
+U+7959 mèi # Character ç¥
+U+795a zuò # Character ç¥
+#U+795b qÅ« # Character ç¥
+U+795c hù # Character ç¥
+U+795d zhù # Character ç¥
+U+795e shén # Character ç¥
+U+795f suì # Character ç¥
+U+7960 cà # Character ç¥
+U+7961 chái # Character 祡
+U+7962 mà # Character 祢
+#U+7963 lÇ # Character 祣
+#U+7964 yÇ # Character 祤
+U+7965 xiáng # Character 祥
+U+7966 wú # Character 祦
+#U+7967 tiÄo # Character 祧
+U+7968 pià o # Character 票
+#U+7969 zhū # Character 祩
+#U+796a guÇ # Character 祪
+U+796b xiá # Character 祫
+#U+796c zhī # Character 祬
+U+796d jì # Character ç¥
+U+796e gà o # Character 祮
+#U+796f zhÄn # Character 祯
+U+7970 gà o # Character 祰
+U+7971 shuì # Character 祱
+#U+7972 jīn # Character 祲
+#U+7973 chÄn # Character 祳
+#U+7974 gÄi # Character 祴
+#U+7975 kÇn # Character 祵
+U+7976 dì # Character 祶
+#U+7977 dÇo # Character 祷
+U+7978 huò # Character 祸
+U+7979 táo # Character 祹
+U+797a qà # Character 祺
+U+797b gù # Character 祻
+U+797c guà n # Character 祼
+U+797d zuì # Character 祽
+U+797e lÃng # Character 祾
+U+797f lù # Character 祿
+#U+7980 bÇng # Character ç¦
+U+7981 jìn # Character ç¦
+#U+7982 dÇo # Character ç¦
+U+7983 zhà # Character ç¦
+U+7984 lù # Character ç¦
+U+7985 shà n # Character ç¦
+#U+7986 bÄi # Character ç¦
+#U+7987 zhÄ # Character ç¦
+#U+7988 huÄ« # Character ç¦
+#U+7989 yÇu # Character ç¦
+U+798a xì # Character ç¦
+#U+798b yÄ«n # Character ç¦
+#U+798c zÄ« # Character ç¦
+U+798d huò # Character ç¦
+#U+798e zhÄn # Character ç¦
+U+798f fú # Character ç¦
+U+7990 yuà n # Character ç¦
+U+7991 wú # Character ç¦
+#U+7992 xiÇn # Character ç¦
+U+7993 yáng # Character ç¦
+U+7994 tà # Character ç¦
+#U+7995 yÄ« # Character ç¦
+U+7996 méi # Character ç¦
+#U+7997 sÄ« # Character ç¦
+U+7998 dì # Character ç¦
+U+7999 ? # Character ç¦
+U+799a zhuó # Character ç¦
+#U+799b zhÄn # Character ç¦
+#U+799c yÇng # Character ç¦
+U+799d jà # Character ç¦
+U+799e gà o # Character ç¦
+U+799f táng # Character ç¦
+#U+79a0 sÄ« # Character ç¦
+U+79a1 mà # Character 禡
+#U+79a2 tÄ # Character 禢
+U+79a3 ? # Character 禣
+#U+79a4 xuÄn # Character 禤
+U+79a5 qà # Character 禥
+U+79a6 yù # Character 禦
+#U+79a7 xī # Character 禧
+#U+79a8 jī # Character 禨
+U+79a9 sì # Character 禩
+U+79aa chán # Character 禪
+#U+79ab tÇn # Character 禫
+U+79ac kuà i # Character 禬
+U+79ad suì # Character ç¦
+#U+79ae lÇ # Character 禮
+U+79af nóng # Character 禯
+#U+79b0 nÇ # Character 禰
+#U+79b1 dÇo # Character 禱
+U+79b2 lì # Character 禲
+U+79b3 ráng # Character 禳
+U+79b4 yuè # Character 禴
+U+79b5 tà # Character 禵
+#U+79b6 zÇn # Character 禶
+U+79b7 lèi # Character 禷
+U+79b8 róu # Character 禸
+#U+79b9 yÇ # Character 禹
+U+79ba yú # Character 禺
+U+79bb là # Character 离
+U+79bc xiè # Character 禼
+U+79bd qÃn # Character 禽
+U+79be hé # Character 禾
+#U+79bf tū # Character 禿
+U+79c0 xiù # Character ç§
+#U+79c1 sÄ« # Character ç§
+U+79c2 rén # Character ç§
+#U+79c3 tÅ« # Character ç§
+#U+79c4 zÇ # Character ç§
+U+79c5 chá # Character ç§
+#U+79c6 gÇn # Character ç§
+U+79c7 yì # Character ç§
+#U+79c8 xiÄn # Character ç§
+#U+79c9 bÇng # Character ç§
+U+79ca nián # Character ç§
+#U+79cb qiÅ« # Character ç§
+#U+79cc qiÅ« # Character ç§
+#U+79cd zhÇng # Character ç§
+U+79ce fén # Character ç§
+U+79cf hà o # Character ç§
+U+79d0 yún # Character ç§
+#U+79d1 kÄ # Character ç§
+#U+79d2 miÇo # Character ç§
+#U+79d3 zhÄ« # Character ç§
+#U+79d4 gÄng # Character ç§
+#U+79d5 bÇ # Character ç§
+#U+79d6 zhÄ« # Character ç§
+U+79d7 yù # Character ç§
+U+79d8 mì # Character ç§
+U+79d9 kù # Character ç§
+U+79da bà n # Character ç§
+#U+79db pÄ« # Character ç§
+U+79dc nà # Character ç§
+U+79dd lì # Character ç§
+U+79de yóu # Character ç§
+#U+79df zÅ« # Character ç§
+#U+79e0 pÄ« # Character ç§
+U+79e1 bá # Character 秡
+U+79e2 lÃng # Character 秢
+U+79e3 mò # Character 秣
+U+79e4 chèng # Character 秤
+U+79e5 nián # Character 秥
+U+79e6 qÃn # Character 秦
+#U+79e7 yÄng # Character 秧
+U+79e8 zuó # Character 秨
+U+79e9 zhì # Character 秩
+#U+79ea zhī # Character 秪
+U+79eb shú # Character 秫
+U+79ec jù # Character 秬
+#U+79ed zÇ # Character ç§
+U+79ee huó # Character 秮
+#U+79ef jī # Character 积
+#U+79f0 chÄng # Character 称
+U+79f1 tóng # Character 秱
+U+79f2 zhì # Character 秲
+U+79f3 huó # Character 秳
+U+79f4 hé # Character 秴
+#U+79f5 yīn # Character 秵
+#U+79f6 zī # Character 秶
+U+79f7 zhà # Character 秷
+#U+79f8 jiÄ # Character 秸
+#U+79f9 rÄn # Character 秹
+U+79fa dù # Character 秺
+U+79fb yà # Character 移
+#U+79fc zhū # Character 秼
+U+79fd huì # Character 秽
+U+79fe nóng # Character 秾
+#U+79ff fÇ # Character 秿
diff --git a/resources/chars/latin1/row7a.trans b/resources/chars/latin1/row7a.trans
new file mode 100644
index 0000000..ba2b905
--- /dev/null
+++ b/resources/chars/latin1/row7a.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+7a00 xÄ« # Character ç¨
+#U+7a01 kÇo # Character ç¨
+U+7a02 láng # Character ç¨
+#U+7a03 fÅ« # Character ç¨
+U+7a04 zè # Character ç¨
+U+7a05 shuì # Character ç¨
+#U+7a06 lÇ # Character ç¨
+#U+7a07 kÇn # Character ç¨
+#U+7a08 gÇn # Character ç¨
+#U+7a09 gÄng # Character ç¨
+U+7a0a tà # Character ç¨
+U+7a0b chéng # Character ç¨
+U+7a0c tú # Character ç¨
+#U+7a0d shÄo # Character ç¨
+U+7a0e shuì # Character ç¨
+U+7a0f yà # Character ç¨
+#U+7a10 lÇn # Character ç¨
+U+7a11 lù # Character ç¨
+U+7a12 gù # Character ç¨
+U+7a13 zuó # Character ç¨
+#U+7a14 rÄn # Character ç¨
+U+7a15 zhùn # Character ç¨
+U+7a16 bà ng # Character ç¨
+U+7a17 bà i # Character ç¨
+#U+7a18 jÄ« # Character ç¨
+U+7a19 zhà # Character ç¨
+U+7a1a zhì # Character ç¨
+#U+7a1b kÇn # Character ç¨
+U+7a1c léng # Character ç¨
+U+7a1d péng # Character ç¨
+#U+7a1e kÄ # Character ç¨
+#U+7a1f bÇng # Character ç¨
+U+7a20 chóu # Character ç¨
+U+7a21 zú # Character 稡
+U+7a22 yù # Character 稢
+#U+7a23 sū # Character 稣
+U+7a24 lüè # Character 稤
+U+7a25 ? # Character 稥
+#U+7a26 yī # Character 稦
+U+7a27 xì # Character 稧
+#U+7a28 biÄn # Character 稨
+U+7a29 jì # Character 稩
+U+7a2a fù # Character 稪
+#U+7a2b bī # Character 稫
+U+7a2c nuò # Character 稬
+#U+7a2d jiÄ # Character ç¨
+#U+7a2e zhÇng # Character 種
+#U+7a2f zÅng # Character 稯
+#U+7a30 xū # Character 稰
+#U+7a31 chÄng # Character 稱
+U+7a32 dà o # Character 稲
+#U+7a33 wÄn # Character 稳
+U+7a34 lián # Character 稴
+#U+7a35 zī # Character 稵
+U+7a36 yù # Character 稶
+U+7a37 jì # Character 稷
+U+7a38 xù # Character 稸
+#U+7a39 zhÄn # Character 稹
+U+7a3a zhì # Character 稺
+U+7a3b dà o # Character 稻
+U+7a3c jia # Character 稼
+#U+7a3d jī # Character 稽
+#U+7a3e gÇo # Character 稾
+#U+7a3f gÇo # Character 稿
+#U+7a40 gÇ # Character ç©
+U+7a41 róng # Character ç©
+U+7a42 suì # Character ç©
+U+7a43 ? # Character ç©
+U+7a44 jì # Character ç©
+#U+7a45 kÄng # Character ç©
+U+7a46 mù # Character ç©
+#U+7a47 shÄn # Character ç©
+U+7a48 mén # Character ç©
+U+7a49 zhì # Character ç©
+U+7a4a jì # Character ç©
+U+7a4b lù # Character ç©
+#U+7a4c sÅ« # Character ç©
+#U+7a4d jÄ« # Character ç©
+#U+7a4e yÇng # Character ç©
+#U+7a4f wÄn # Character ç©
+#U+7a50 qiÅ« # Character ç©
+U+7a51 sè # Character ç©
+U+7a52 ? # Character ç©
+U+7a53 yì # Character ç©
+U+7a54 huáng # Character ç©
+U+7a55 qiè # Character ç©
+#U+7a56 jÇ # Character ç©
+U+7a57 suì # Character ç©
+#U+7a58 xiÄo # Character ç©
+U+7a59 pú # Character ç©
+#U+7a5a jiÄo # Character ç©
+#U+7a5b zhuÅ # Character ç©
+U+7a5c tóng # Character ç©
+U+7a5d ? # Character ç©
+#U+7a5e lÇ # Character ç©
+U+7a5f suì # Character ç©
+U+7a60 nóng # Character ç©
+U+7a61 sè # Character 穡
+U+7a62 huì # Character 穢
+U+7a63 ráng # Character 穣
+U+7a64 nuò # Character 穤
+U+7a65 yù # Character 穥
+U+7a66 ? # Character 穦
+U+7a67 jì # Character 穧
+U+7a68 tuà # Character 穨
+#U+7a69 wÄn # Character ç©©
+#U+7a6a chÄng # Character 穪
+U+7a6b huò # Character 穫
+#U+7a6c gÇng # Character 穬
+#U+7a6d lÇ # Character ç©
+#U+7a6e biÄo # Character ç©®
+U+7a6f ? # Character 穯
+U+7a70 ráng # Character 穰
+#U+7a71 zhuŠ# Character 穱
+U+7a72 là # Character 穲
+U+7a73 zà n # Character 穳
+U+7a74 xuè # Character 穴
+#U+7a75 wÄ # Character 穵
+#U+7a76 jiū # Character 究
+U+7a77 qióng # Character 穷
+U+7a78 xì # Character 穸
+#U+7a79 qiÅng # Character 穹
+#U+7a7a kÅng # Character 空
+#U+7a7b yū # Character 穻
+#U+7a7c sÄn # Character 穼
+#U+7a7d jÇng # Character 穽
+U+7a7e yà o # Character 穾
+#U+7a7f chuÄn # Character ç©¿
+#U+7a80 zhÅ«n # Character çª
+#U+7a81 tÅ« # Character çª
+U+7a82 láo # Character çª
+U+7a83 qiè # Character çª
+#U+7a84 zhÇi # Character çª
+#U+7a85 yÇo # Character çª
+#U+7a86 biÇn # Character çª
+U+7a87 báo # Character çª
+#U+7a88 yÇo # Character çª
+#U+7a89 bÇng # Character çª
+#U+7a8a wÄ # Character çª
+U+7a8b zhú # Character çª
+U+7a8c jià o # Character çª
+U+7a8d qià o # Character çª
+U+7a8e dià o # Character çª
+#U+7a8f wÅ« # Character çª
+#U+7a90 guÄ« # Character çª
+U+7a91 yáo # Character çª
+U+7a92 zhì # Character çª
+#U+7a93 chuÄng # Character çª
+#U+7a94 yÇo # Character çª
+#U+7a95 tiÇo # Character çª
+U+7a96 jià o # Character çª
+#U+7a97 chuÄng # Character çª
+#U+7a98 jiÇng # Character çª
+#U+7a99 xiÄo # Character çª
+U+7a9a chéng # Character çª
+U+7a9b kòu # Character çª
+U+7a9c cuà n # Character çª
+#U+7a9d wÅ # Character çª
+U+7a9e dà n # Character çª
+#U+7a9f kÅ« # Character çª
+#U+7aa0 kÄ # Character çª
+U+7aa1 zhuì # Character 窡
+U+7aa2 xù # Character 窢
+U+7aa3 sù # Character 窣
+U+7aa4 ? # Character 窤
+#U+7aa5 kuī # Character 窥
+U+7aa6 dòu # Character 窦
+U+7aa7 ? # Character 窧
+U+7aa8 yìn # Character 窨
+#U+7aa9 wŠ# Character 窩
+#U+7aaa wÄ # Character 窪
+U+7aab yà # Character 窫
+U+7aac yú # Character 窬
+U+7aad jù # Character çª
+U+7aae qióng # Character 窮
+U+7aaf yáo # Character 窯
+U+7ab0 yáo # Character 窰
+U+7ab1 tià o # Character 窱
+U+7ab2 cháo # Character 窲
+#U+7ab3 yÇ # Character 窳
+U+7ab4 tián # Character 窴
+U+7ab5 dià o # Character 窵
+U+7ab6 jù # Character 窶
+U+7ab7 liáo # Character 窷
+#U+7ab8 xī # Character 窸
+U+7ab9 wù # Character 窹
+#U+7aba kuī # Character 窺
+#U+7abb chuÄng # Character 窻
+#U+7abc zhÄo # Character 窼
+U+7abd ? # Character 窽
+#U+7abe kuÇn # Character 窾
+U+7abf long # Character 窿
+#U+7ac0 chÄng # Character ç«
+U+7ac1 cuì # Character ç«
+U+7ac2 piáo # Character ç«
+U+7ac3 zà o # Character ç«
+U+7ac4 cuà n # Character ç«
+U+7ac5 qià o # Character ç«
+U+7ac6 qióng # Character ç«
+U+7ac7 dòu # Character ç«
+U+7ac8 zà o # Character ç«
+#U+7ac9 lÇng # Character ç«
+U+7aca qiè # Character ç«
+U+7acb lì # Character ç«
+U+7acc chù # Character ç«
+U+7acd ? # Character ç«
+U+7ace fòu # Character ç«
+U+7acf ? # Character ç«
+U+7ad0 chù # Character ç«
+U+7ad1 hóng # Character ç«
+U+7ad2 qà # Character ç«
+U+7ad3 ? # Character ç«
+U+7ad4 ? # Character ç«
+U+7ad5 ? # Character ç«
+U+7ad6 shù # Character ç«
+U+7ad7 mià o # Character ç«
+#U+7ad8 jÇ # Character ç«
+U+7ad9 zhà n # Character ç«
+U+7ada zhù # Character ç«
+U+7adb lÃng # Character ç«
+U+7adc lóng # Character ç«
+U+7add bìng # Character ç«
+U+7ade jìng # Character ç«
+U+7adf jìng # Character ç«
+#U+7ae0 zhÄng # Character ç«
+U+7ae1 ? # Character ç«¡
+U+7ae2 sì # Character 竢
+U+7ae3 jùn # Character 竣
+U+7ae4 hóng # Character 竤
+U+7ae5 tóng # Character 童
+#U+7ae6 sÇng # Character 竦
+U+7ae7 jìng # Character 竧
+U+7ae8 dià o # Character 竨
+U+7ae9 yì # Character 竩
+U+7aea shù # Character 竪
+U+7aeb jìng # Character 竫
+#U+7aec qÇ # Character 竬
+U+7aed jié # Character ç«
+U+7aee pÃng # Character ç«®
+#U+7aef duÄn # Character 端
+U+7af0 sháo # Character 竰
+#U+7af1 zhuÇn # Character 竱
+U+7af2 céng # Character 竲
+#U+7af3 dÄng # Character 竳
+#U+7af4 cuī # Character 竴
+#U+7af5 huÄi # Character 竵
+U+7af6 jìng # Character 競
+U+7af7 kà n # Character 竷
+U+7af8 jìng # Character 竸
+U+7af9 zhú # Character 竹
+U+7afa zhú # Character 竺
+U+7afb lè # Character 竻
+U+7afc péng # Character 竼
+U+7afd yú # Character 竽
+U+7afe chà # Character 竾
+#U+7aff gÄn # Character ç«¿
diff --git a/resources/chars/latin1/row7b.trans b/resources/chars/latin1/row7b.trans
new file mode 100644
index 0000000..ee60b6a
--- /dev/null
+++ b/resources/chars/latin1/row7b.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+7b00 máng # Character ç¬
+U+7b01 zhú # Character ç¬
+U+7b02 ? # Character ç¬
+#U+7b03 dÇ # Character ç¬
+#U+7b04 jÄ« # Character ç¬
+U+7b05 xiáo # Character ç¬
+U+7b06 ba # Character ç¬
+U+7b07 suà n # Character ç¬
+U+7b08 jà # Character ç¬
+#U+7b09 zhÄn # Character ç¬
+U+7b0a zhà o # Character ç¬
+#U+7b0b sÇn # Character ç¬
+U+7b0c yá # Character ç¬
+U+7b0d zhuì # Character ç¬
+U+7b0e yuán # Character ç¬
+U+7b0f hù # Character ç¬
+#U+7b10 gÄng # Character ç¬
+U+7b11 xià o # Character ç¬
+U+7b12 cén # Character ç¬
+U+7b13 pà # Character ç¬
+#U+7b14 bÇ # Character ç¬
+#U+7b15 jiÇn # Character ç¬
+#U+7b16 yÇ # Character ç¬
+#U+7b17 dÅng # Character ç¬
+#U+7b18 shÄn # Character ç¬
+#U+7b19 shÄng # Character ç¬
+U+7b1a xiá # Character ç¬
+U+7b1b dà # Character ç¬
+U+7b1c zhú # Character ç¬
+U+7b1d nà # Character ç¬
+#U+7b1e chÄ« # Character ç¬
+#U+7b1f gÅ« # Character ç¬
+U+7b20 lì # Character ç¬
+U+7b21 qiè # Character 笡
+#U+7b22 mÇn # Character 笢
+#U+7b23 bÄo # Character 笣
+U+7b24 tiáo # Character 笤
+U+7b25 sì # Character 笥
+U+7b26 fú # Character 符
+U+7b27 cè # Character 笧
+U+7b28 bèn # Character 笨
+U+7b29 pèi # Character 笩
+U+7b2a dá # Character 笪
+#U+7b2b zÇ # Character 笫
+U+7b2c dì # Character 第
+U+7b2d lÃng # Character ç¬
+U+7b2e zé # Character 笮
+U+7b2f nú # Character 笯
+U+7b30 fú # Character 笰
+#U+7b31 gÇu # Character 笱
+#U+7b32 fÄn # Character 笲
+#U+7b33 jiÄ # Character 笳
+#U+7b34 gÄ # Character 笴
+U+7b35 fà n # Character 笵
+#U+7b36 shÇ # Character 笶
+#U+7b37 mÇo # Character 笷
+#U+7b38 pÇ # Character 笸
+U+7b39 ? # Character 笹
+#U+7b3a jiÄn # Character 笺
+U+7b3b qióng # Character 笻
+U+7b3c lóng # Character 笼
+U+7b3d ? # Character 笽
+#U+7b3e biÄn # Character 笾
+U+7b3f luò # Character 笿
+U+7b40 guì # Character ç
+#U+7b41 qÇ # Character ç
+U+7b42 chà # Character ç
+#U+7b43 yÄ«n # Character ç
+U+7b44 yà o # Character ç
+#U+7b45 xiÇn # Character ç
+#U+7b46 bÇ # Character ç
+U+7b47 qióng # Character ç
+#U+7b48 guÄ # Character ç
+#U+7b49 dÄng # Character ç
+#U+7b4a jiÇo # Character ç
+#U+7b4b jÄ«n # Character ç
+U+7b4c quán # Character ç
+#U+7b4d sÇn # Character ç
+U+7b4e rú # Character ç
+U+7b4f fá # Character ç
+#U+7b50 kuÄng # Character ç
+U+7b51 zhù # Character ç
+#U+7b52 tÇng # Character ç
+#U+7b53 jÄ« # Character ç
+U+7b54 dá # Character ç
+U+7b55 xÃng # Character ç
+U+7b56 cè # Character ç
+U+7b57 zhòng # Character ç
+U+7b58 kòu # Character ç
+U+7b59 lái # Character ç
+U+7b5a bì # Character ç
+#U+7b5b shÄi # Character ç
+#U+7b5c dÄng # Character ç
+#U+7b5d zhÄng # Character ç
+U+7b5e cè # Character ç
+#U+7b5f fÅ« # Character ç
+U+7b60 yún # Character ç
+U+7b61 tú # Character ç¡
+U+7b62 pá # Character ç¢
+U+7b63 lì # Character ç£
+U+7b64 láng # Character ç¤
+#U+7b65 jÇ # Character ç¥
+#U+7b66 guÇn # Character ç¦
+#U+7b67 jiÇn # Character ç§
+U+7b68 hán # Character ç¨
+U+7b69 tóng # Character ç©
+U+7b6a xiá # Character çª
+U+7b6b zhì # Character ç«
+U+7b6c chéng # Character ç¬
+U+7b6d suà n # Character ç
+U+7b6e shì # Character ç®
+U+7b6f zhù # Character ç¯
+U+7b70 zuó # Character ç°
+#U+7b71 xiÇo # Character ç±
+#U+7b72 shÄo # Character ç²
+U+7b73 tÃng # Character ç³
+U+7b74 cè # Character ç´
+U+7b75 yán # Character çµ
+#U+7b76 gÇo # Character ç¶
+U+7b77 kuà i # Character ç·
+#U+7b78 gÄn # Character ç¸
+U+7b79 chóu # Character ç¹
+U+7b7a ? # Character çº
+U+7b7b gà ng # Character ç»
+U+7b7c yún # Character ç¼
+U+7b7d ? # Character ç½
+#U+7b7e qiÄn # Character ç¾
+#U+7b7f xiÇo # Character ç¿
+#U+7b80 jiÇn # Character ç®
+U+7b81 pú # Character ç®
+U+7b82 lái # Character ç®
+#U+7b83 zÅu # Character ç®
+U+7b84 bì # Character ç®
+U+7b85 bì # Character ç®
+U+7b86 bì # Character ç®
+U+7b87 gè # Character ç®
+U+7b88 chà # Character ç®
+#U+7b89 guÇi # Character ç®
+#U+7b8a yÅ« # Character ç®
+#U+7b8b jiÄn # Character ç®
+U+7b8c zhà o # Character ç®
+#U+7b8d gÅ« # Character ç®
+U+7b8e chà # Character ç®
+#U+7b8f zhÄng # Character ç®
+#U+7b90 jÄ«ng # Character ç®
+U+7b91 shà # Character ç®
+#U+7b92 zhÇu # Character ç®
+U+7b93 lù # Character ç®
+U+7b94 bó # Character ç®
+#U+7b95 jÄ« # Character ç®
+U+7b96 lÃn # Character ç®
+U+7b97 suà n # Character ç®
+U+7b98 jùn # Character ç®
+U+7b99 fú # Character ç®
+U+7b9a zhá # Character ç®
+#U+7b9b gÅ« # Character ç®
+#U+7b9c kÅng # Character ç®
+U+7b9d qián # Character ç®
+#U+7b9e quÄn # Character ç®
+U+7b9f jùn # Character ç®
+U+7ba0 chuà # Character ç®
+#U+7ba1 guÇn # Character 管
+#U+7ba2 yuÄn # Character 箢
+U+7ba3 cè # Character 箣
+U+7ba4 jú # Character 箤
+#U+7ba5 bÇ # Character 箥
+U+7ba6 zé # Character 箦
+U+7ba7 qiè # Character 箧
+U+7ba8 tuò # Character 箨
+U+7ba9 luó # Character 箩
+#U+7baa dÄn # Character 箪
+#U+7bab xiÄo # Character 箫
+U+7bac ruò # Character 箬
+U+7bad jià n # Character ç®
+U+7bae ? # Character ç®®
+#U+7baf biÄn # Character 箯
+#U+7bb0 sÇn # Character ç®°
+#U+7bb1 xiÄng # Character ç®±
+#U+7bb2 xiÇn # Character 箲
+U+7bb3 pÃng # Character 箳
+#U+7bb4 zhÄn # Character ç®´
+#U+7bb5 shÄng # Character 箵
+U+7bb6 hú # Character 箶
+#U+7bb7 shī # Character 箷
+U+7bb8 zhù # Character 箸
+#U+7bb9 yuÄ # Character 箹
+#U+7bba chÇn # Character 箺
+#U+7bbb lÇ # Character ç®»
+#U+7bbc wū # Character 箼
+#U+7bbd dÇng # Character 箽
+#U+7bbe xiÄo # Character 箾
+U+7bbf jà # Character 箿
+U+7bc0 jié # Character ç¯
+U+7bc1 huáng # Character ç¯
+#U+7bc2 xÄ«ng # Character ç¯
+U+7bc3 méi # Character ç¯
+U+7bc4 fà n # Character ç¯
+U+7bc5 chuà # Character ç¯
+U+7bc6 zhuà n # Character ç¯
+#U+7bc7 piÄn # Character ç¯
+#U+7bc8 fÄng # Character ç¯
+U+7bc9 zhú # Character ç¯
+U+7bca hóng # Character ç¯
+U+7bcb qiè # Character ç¯
+U+7bcc hóu # Character ç¯
+#U+7bcd qiÅ« # Character ç¯
+#U+7bce miÇo # Character ç¯
+U+7bcf qià n # Character ç¯
+U+7bd0 ? # Character ç¯
+U+7bd1 kuì # Character ç¯
+U+7bd2 ? # Character ç¯
+#U+7bd3 lÇu # Character ç¯
+U+7bd4 yún # Character ç¯
+U+7bd5 hé # Character ç¯
+U+7bd6 táng # Character ç¯
+U+7bd7 yuè # Character ç¯
+#U+7bd8 chÅu # Character ç¯
+#U+7bd9 gÄo # Character ç¯
+#U+7bda fÄi # Character ç¯
+U+7bdb ruò # Character ç¯
+#U+7bdc zhÄng # Character ç¯
+#U+7bdd gÅu # Character ç¯
+U+7bde niè # Character ç¯
+U+7bdf qià n # Character ç¯
+#U+7be0 xiÇo # Character ç¯
+U+7be1 cuà n # Character 篡
+#U+7be2 gÅng # Character 篢
+U+7be3 páng # Character 篣
+#U+7be4 dÇ # Character 篤
+U+7be5 lì # Character 篥
+U+7be6 bì # Character 篦
+U+7be7 zhuó # Character 篧
+U+7be8 chú # Character 篨
+#U+7be9 shÄi # Character 篩
+U+7bea chà # Character 篪
+U+7beb zhú # Character 篫
+#U+7bec qiÄng # Character 篬
+U+7bed lóng # Character ç¯
+U+7bee lán # Character 篮
+#U+7bef jiÄn # Character 篯
+U+7bf0 bù # Character 篰
+U+7bf1 là # Character 篱
+U+7bf2 huì # Character 篲
+U+7bf3 bì # Character 篳
+U+7bf4 dà # Character 篴
+#U+7bf5 cÅng # Character 篵
+#U+7bf6 yÄn # Character 篶
+U+7bf7 peng # Character 篷
+#U+7bf8 sÄn # Character 篸
+U+7bf9 zhuà n # Character 篹
+U+7bfa pái # Character 篺
+U+7bfb pià o # Character 篻
+#U+7bfc dÅu # Character 篼
+#U+7bfd yÇ # Character 篽
+U+7bfe miè # Character 篾
+#U+7bff zhuÄn # Character 篿
diff --git a/resources/chars/latin1/row7c.trans b/resources/chars/latin1/row7c.trans
new file mode 100644
index 0000000..acdf57e
--- /dev/null
+++ b/resources/chars/latin1/row7c.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+7c00 zé # Character ç°
+#U+7c01 xÇ # Character ç°
+U+7c02 guó # Character ç°
+U+7c03 yà # Character ç°
+U+7c04 hù # Character ç°
+#U+7c05 chÇn # Character ç°
+U+7c06 kòu # Character ç°
+U+7c07 cù # Character ç°
+U+7c08 pÃng # Character ç°
+U+7c09 chòu # Character ç°
+#U+7c0a jÄ« # Character ç°
+#U+7c0b guÇ # Character ç°
+U+7c0c sù # Character ç°
+#U+7c0d lÇu # Character ç°
+U+7c0e zhà # Character ç°
+U+7c0f lù # Character ç°
+#U+7c10 niÇn # Character ç°
+#U+7c11 suÅ # Character ç°
+U+7c12 cuà n # Character ç°
+U+7c13 ? # Character ç°
+#U+7c14 suÅ # Character ç°
+U+7c15 lè # Character ç°
+U+7c16 duà n # Character ç°
+U+7c17 ? # Character ç°
+#U+7c18 xiÄo # Character ç°
+U+7c19 bó # Character ç°
+U+7c1a mì # Character ç°
+#U+7c1b sÄ« # Character ç°
+U+7c1c dà ng # Character ç°
+U+7c1d liáo # Character ç°
+#U+7c1e dÄn # Character ç°
+U+7c1f dià n # Character ç°
+#U+7c20 fÇ # Character ç°
+#U+7c21 jiÇn # Character ç°¡
+#U+7c22 mÇn # Character ç°¢
+U+7c23 kuì # Character 簣
+U+7c24 dà i # Character 簤
+U+7c25 qiáo # Character 簥
+#U+7c26 dÄng # Character ç°¦
+U+7c27 huáng # Character 簧
+#U+7c28 sÇn # Character ç°¨
+U+7c29 láo # Character 簩
+#U+7c2a zÄn # Character ç°ª
+#U+7c2b xiÄo # Character ç°«
+U+7c2c dù # Character 簬
+U+7c2d shì # Character ç°
+#U+7c2e zÄn # Character ç°®
+U+7c2f ? # Character ç°¯
+U+7c30 pái # Character 簰
+U+7c31 ? # Character ç°±
+U+7c32 pái # Character 簲
+U+7c33 gà n # Character 簳
+U+7c34 jù # Character 簴
+U+7c35 dù # Character 簵
+U+7c36 lù # Character 簶
+U+7c37 yán # Character 簷
+#U+7c38 bÇ # Character ç°¸
+#U+7c39 dÄng # Character ç°¹
+U+7c3a sà i # Character 簺
+#U+7c3b kÄ # Character ç°»
+U+7c3c lóng # Character 簼
+#U+7c3d qiÄn # Character ç°½
+U+7c3e lián # Character 簾
+U+7c3f bó # Character 簿
+U+7c40 zhòu # Character ç±
+U+7c41 là i # Character ç±
+U+7c42 ? # Character ç±
+U+7c43 lán # Character ç±
+U+7c44 kuì # Character ç±
+U+7c45 yú # Character ç±
+U+7c46 yuè # Character ç±
+U+7c47 háo # Character ç±
+#U+7c48 zhÄn # Character ç±
+U+7c49 tái # Character ç±
+U+7c4a tì # Character ç±
+U+7c4b mà # Character ç±
+U+7c4c chóu # Character ç±
+U+7c4d jà # Character ç±
+U+7c4e ? # Character ç±
+U+7c4f ? # Character ç±
+U+7c50 téng # Character ç±
+U+7c51 zhuà n # Character ç±
+U+7c52 zhòu # Character ç±
+#U+7c53 fÄn # Character ç±
+#U+7c54 sÇu # Character ç±
+U+7c55 zhòu # Character ç±
+U+7c56 ? # Character ç±
+U+7c57 zhuó # Character ç±
+U+7c58 téng # Character ç±
+U+7c59 lù # Character ç±
+U+7c5a lú # Character ç±
+#U+7c5b jiÄn # Character ç±
+U+7c5c tuò # Character ç±
+U+7c5d yÃng # Character ç±
+U+7c5e yù # Character ç±
+U+7c5f là i # Character ç±
+U+7c60 lóng # Character ç±
+U+7c61 ? # Character 籡
+U+7c62 lián # Character 籢
+U+7c63 lán # Character 籣
+#U+7c64 qiÄn # Character 籤
+U+7c65 yuè # Character 籥
+#U+7c66 zhÅng # Character 籦
+U+7c67 qú # Character 籧
+U+7c68 lián # Character 籨
+#U+7c69 biÄn # Character 籩
+U+7c6a duà n # Character 籪
+#U+7c6b zuÇn # Character 籫
+U+7c6c là # Character 籬
+#U+7c6d sÄ« # Character ç±
+U+7c6e luó # Character 籮
+U+7c6f yÃng # Character 籯
+U+7c70 yuè # Character 籰
+U+7c71 zhuó # Character 籱
+#U+7c72 xū # Character 籲
+#U+7c73 mÇ # Character ç±³
+U+7c74 dà # Character 籴
+U+7c75 fán # Character 籵
+#U+7c76 shÄn # Character 籶
+U+7c77 zhé # Character 籷
+#U+7c78 shÄn # Character 籸
+#U+7c79 nÇ # Character ç±¹
+U+7c7a xié # Character 籺
+U+7c7b lèi # Character 类
+#U+7c7c xiÄn # Character ç±¼
+#U+7c7d zÇ # Character ç±½
+U+7c7e nà # Character 籾
+U+7c7f cùn # Character 籿
+U+7c80 ? # Character ç²
+#U+7c81 qiÄn # Character ç²
+U+7c82 ? # Character ç²
+#U+7c83 bÇ # Character ç²
+#U+7c84 bÇn # Character ç²
+U+7c85 wù # Character ç²
+#U+7c86 shÄ # Character ç²
+#U+7c87 kÄng # Character ç²
+#U+7c88 rÇu # Character ç²
+#U+7c89 fÄn # Character ç²
+U+7c8a bì # Character ç²
+U+7c8b cuì # Character ç²
+U+7c8c ? # Character ç²
+U+7c8d là # Character ç²
+#U+7c8e chÇ # Character ç²
+U+7c8f ? # Character ç²
+U+7c90 ? # Character ç²
+#U+7c91 bÄ # Character ç²
+U+7c92 lì # Character ç²
+#U+7c93 gÄn # Character ç²
+U+7c94 jù # Character ç²
+U+7c95 pò # Character ç²
+U+7c96 mò # Character ç²
+#U+7c97 cÅ« # Character ç²
+#U+7c98 zhÄn # Character ç²
+U+7c99 zhòu # Character ç²
+U+7c9a là # Character ç²
+U+7c9b sù # Character ç²
+U+7c9c tià o # Character ç²
+U+7c9d lì # Character ç²
+#U+7c9e qÄ« # Character ç²
+U+7c9f sù # Character ç²
+U+7ca0 hóng # Character ç²
+U+7ca1 tóng # Character 粡
+#U+7ca2 zī # Character 粢
+U+7ca3 cè # Character 粣
+U+7ca4 yuè # Character 粤
+#U+7ca5 zhÅu # Character ç²¥
+U+7ca6 lìn # Character 粦
+#U+7ca7 zhuÄng # Character 粧
+#U+7ca8 bÇi # Character 粨
+U+7ca9 ? # Character 粩
+U+7caa fèn # Character 粪
+U+7cab ? # Character 粫
+U+7cac ? # Character 粬
+U+7cad ? # Character ç²
+U+7cae liáng # Character 粮
+U+7caf xià n # Character 粯
+U+7cb0 fú # Character 粰
+U+7cb1 liáng # Character 粱
+U+7cb2 cà n # Character 粲
+#U+7cb3 gÄng # Character ç²³
+#U+7cb4 lÇ # Character ç²´
+U+7cb5 yuè # Character 粵
+U+7cb6 lù # Character 粶
+U+7cb7 jú # Character 粷
+U+7cb8 qà # Character 粸
+U+7cb9 cuì # Character 粹
+U+7cba bà i # Character 粺
+#U+7cbb zhÄng # Character ç²»
+U+7cbc lÃn # Character ç²¼
+U+7cbd zòng # Character 粽
+#U+7cbe jīng # Character 精
+#U+7cbf guÇ # Character 粿
+U+7cc0 ? # Character ç³
+#U+7cc1 sÄn # Character ç³
+#U+7cc2 sÇn # Character ç³
+U+7cc3 táng # Character ç³
+#U+7cc4 biÄn # Character ç³
+#U+7cc5 rÇu # Character ç³
+U+7cc6 mià n # Character ç³
+U+7cc7 hóu # Character ç³
+#U+7cc8 xÇ # Character ç³
+U+7cc9 zòng # Character ç³
+U+7cca hu # Character ç³
+U+7ccb jià n # Character ç³
+U+7ccc zán # Character ç³
+U+7ccd cà # Character ç³
+U+7cce là # Character ç³
+U+7ccf xiè # Character ç³
+#U+7cd0 fÅ« # Character ç³
+U+7cd1 nì # Character ç³
+U+7cd2 bèi # Character ç³
+#U+7cd3 gÇ # Character ç³
+#U+7cd4 xiÇ # Character ç³
+#U+7cd5 gÄo # Character ç³
+U+7cd6 táng # Character ç³
+#U+7cd7 qiÇ # Character ç³
+U+7cd8 ? # Character ç³
+#U+7cd9 cÄo # Character ç³
+#U+7cda zhuÄng # Character ç³
+U+7cdb táng # Character ç³
+U+7cdc mà # Character ç³
+#U+7cdd sÄn # Character ç³
+U+7cde fèn # Character ç³
+#U+7cdf zÄo # Character ç³
+#U+7ce0 kÄng # Character ç³
+U+7ce1 jià ng # Character 糡
+U+7ce2 mó # Character 糢
+#U+7ce3 sÇn # Character ç³£
+#U+7ce4 sÇn # Character 糤
+U+7ce5 nuò # Character 糥
+#U+7ce6 xī # Character 糦
+U+7ce7 liáng # Character 糧
+U+7ce8 jià ng # Character 糨
+U+7ce9 kuà i # Character 糩
+U+7cea bó # Character 糪
+U+7ceb huán # Character 糫
+U+7cec ? # Character 糬
+U+7ced zòng # Character ç³
+U+7cee xià n # Character 糮
+U+7cef nuò # Character 糯
+U+7cf0 tuán # Character 糰
+U+7cf1 niè # Character 糱
+U+7cf2 lì # Character 糲
+U+7cf3 zuò # Character 糳
+U+7cf4 dà # Character 糴
+U+7cf5 niè # Character 糵
+U+7cf6 tià o # Character 糶
+U+7cf7 lán # Character 糷
+U+7cf8 mì # Character 糸
+#U+7cf9 sī # Character 糹
+#U+7cfa jiū # Character 糺
+U+7cfb xì # Character 系
+#U+7cfc gÅng # Character ç³¼
+#U+7cfd zhÄng # Character ç³½
+#U+7cfe jiū # Character 糾
+U+7cff yòu # Character 糿
diff --git a/resources/chars/latin1/row7d.trans b/resources/chars/latin1/row7d.trans
new file mode 100644
index 0000000..dba6373
--- /dev/null
+++ b/resources/chars/latin1/row7d.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+7d00 jì # Character ç´
+U+7d01 chà # Character ç´
+U+7d02 zhòu # Character ç´
+U+7d03 xún # Character ç´
+#U+7d04 yuÄ # Character ç´
+U+7d05 hóng # Character ç´
+#U+7d06 yÅ« # Character ç´
+U+7d07 hé # Character ç´
+U+7d08 wán # Character ç´
+U+7d09 rèn # Character ç´
+U+7d0a wèn # Character ç´
+U+7d0b wén # Character ç´
+U+7d0c qiú # Character ç´
+U+7d0d nà # Character ç´
+#U+7d0e zÄ« # Character ç´
+#U+7d0f tÇu # Character ç´
+#U+7d10 niÇ # Character ç´
+U+7d11 fóu # Character ç´
+U+7d12 jiè # Character ç´
+#U+7d13 shÅ« # Character ç´
+U+7d14 chún # Character ç´
+U+7d15 pà # Character ç´
+#U+7d16 yÇn # Character ç´
+#U+7d17 shÄ # Character ç´
+U+7d18 hóng # Character ç´
+#U+7d19 zhÇ # Character ç´
+U+7d1a jà # Character ç´
+#U+7d1b fÄn # Character ç´
+U+7d1c yún # Character ç´
+U+7d1d rén # Character ç´
+#U+7d1e dÇn # Character ç´
+#U+7d1f jÄ«n # Character ç´
+U+7d20 sù # Character ç´
+#U+7d21 fÇng # Character ç´¡
+#U+7d22 suÇ # Character ç´¢
+U+7d23 cuì # Character 紣
+#U+7d24 jiÇ # Character ç´¤
+U+7d25 zhá # Character 紥
+U+7d26 ? # Character ç´¦
+#U+7d27 jÇn # Character ç´§
+U+7d28 fù # Character 紨
+U+7d29 zhì # Character 紩
+#U+7d2a cÇ # Character ç´ª
+#U+7d2b zÇ # Character ç´«
+U+7d2c chóu # Character 紬
+U+7d2d hóng # Character ç´
+U+7d2e zhá # Character 紮
+U+7d2f lèi # Character 累
+U+7d30 xì # Character 細
+U+7d31 fú # Character 紱
+U+7d32 xiè # Character 紲
+#U+7d33 shÄn # Character ç´³
+U+7d34 bèi # Character 紴
+U+7d35 zhù # Character 紵
+#U+7d36 qÇ # Character ç´¶
+U+7d37 lÃng # Character ç´·
+U+7d38 zhù # Character 紸
+U+7d39 shà o # Character 紹
+U+7d3a gà n # Character 紺
+#U+7d3b yÄng # Character ç´»
+U+7d3c fú # Character 紼
+U+7d3d tuó # Character 紽
+#U+7d3e zhÄn # Character ç´¾
+U+7d3f dà i # Character 紿
+U+7d40 zhuó # Character çµ
+#U+7d41 shÄ« # Character çµ
+#U+7d42 zhÅng # Character çµ
+U+7d43 xián # Character çµ
+#U+7d44 zÇ # Character çµ
+#U+7d45 jiÇng # Character çµ
+U+7d46 bà n # Character çµ
+U+7d47 jù # Character çµ
+U+7d48 mò # Character çµ
+U+7d49 shù # Character çµ
+U+7d4a zuì # Character çµ
+U+7d4b ? # Character çµ
+#U+7d4c jÄ«ng # Character çµ
+U+7d4d rén # Character çµ
+U+7d4e hèng # Character çµ
+U+7d4f xiè # Character çµ
+U+7d50 jié # Character çµ
+#U+7d51 zhÅ« # Character çµ
+U+7d52 chóu # Character çµ
+U+7d53 guà # Character çµ
+#U+7d54 bÇi # Character çµ
+U+7d55 jué # Character çµ
+U+7d56 kuà ng # Character çµ
+U+7d57 hú # Character çµ
+U+7d58 cì # Character çµ
+#U+7d59 gÄng # Character çµ
+#U+7d5a gÄng # Character çµ
+#U+7d5b tÄo # Character çµ
+U+7d5c xié # Character çµ
+U+7d5d kù # Character çµ
+#U+7d5e jiÇo # Character çµ
+#U+7d5f quÄn # Character çµ
+#U+7d60 gÇi # Character çµ
+U+7d61 luò # Character 絡
+U+7d62 xuà n # Character 絢
+#U+7d63 bīng # Character 絣
+U+7d64 xià n # Character 絤
+U+7d65 fú # Character 絥
+#U+7d66 gÄi # Character 給
+U+7d67 tóng # Character 絧
+U+7d68 róng # Character 絨
+U+7d69 tià o # Character 絩
+#U+7d6a yīn # Character 絪
+#U+7d6b lÄi # Character 絫
+U+7d6c xiè # Character 絬
+U+7d6d quà n # Character çµ
+U+7d6e xù # Character 絮
+#U+7d6f lÇn # Character 絯
+U+7d70 dié # Character 絰
+#U+7d71 tÇng # Character çµ±
+#U+7d72 sī # Character 絲
+U+7d73 jià ng # Character 絳
+U+7d74 xiáng # Character 絴
+U+7d75 huì # Character 絵
+U+7d76 jué # Character 絶
+U+7d77 zhà # Character 絷
+#U+7d78 jiÇn # Character 絸
+U+7d79 juà n # Character 絹
+#U+7d7a chī # Character 絺
+#U+7d7b miÇn # Character çµ»
+#U+7d7c zhÄn # Character çµ¼
+#U+7d7d lÇ # Character çµ½
+U+7d7e chéng # Character 絾
+U+7d7f qiú # Character 絿
+#U+7d80 shÅ« # Character ç¶
+#U+7d81 bÇng # Character ç¶
+#U+7d82 tÇng # Character ç¶
+#U+7d83 xiÄo # Character ç¶
+U+7d84 wà n # Character ç¶
+#U+7d85 qÄ«n # Character ç¶
+#U+7d86 gÄng # Character ç¶
+#U+7d87 xiÇ # Character ç¶
+U+7d88 tà # Character ç¶
+U+7d89 xiù # Character ç¶
+U+7d8a xié # Character ç¶
+U+7d8b hóng # Character ç¶
+U+7d8c xì # Character ç¶
+U+7d8d fú # Character ç¶
+#U+7d8e tÄ«ng # Character ç¶
+#U+7d8f suÄ« # Character ç¶
+U+7d90 duì # Character ç¶
+#U+7d91 kÇn # Character ç¶
+#U+7d92 fÅ« # Character ç¶
+#U+7d93 jÄ«ng # Character ç¶
+U+7d94 hù # Character ç¶
+#U+7d95 zhÄ« # Character ç¶
+U+7d96 yán # Character ç¶
+#U+7d97 jiÇng # Character ç¶
+U+7d98 féng # Character ç¶
+U+7d99 jì # Character ç¶
+U+7d9a ? # Character ç¶
+U+7d9b ? # Character ç¶
+#U+7d9c zÅng # Character ç¶
+U+7d9d lÃn # Character ç¶
+#U+7d9e duÇ # Character ç¶
+U+7d9f lì # Character ç¶
+#U+7da0 lÇ # Character ç¶
+U+7da1 liáng # Character 綡
+U+7da2 chóu # Character 綢
+#U+7da3 quÇn # Character 綣
+U+7da4 shà o # Character 綤
+U+7da5 qì # Character 綥
+U+7da6 qà # Character 綦
+#U+7da7 zhÇn # Character 綧
+U+7da8 qà # Character 綨
+#U+7da9 wÇn # Character 綩
+U+7daa qià n # Character 綪
+U+7dab xià n # Character 綫
+U+7dac shòu # Character 綬
+U+7dad wéi # Character ç¶
+#U+7dae qÇ # Character 綮
+U+7daf táo # Character 綯
+#U+7db0 wÇn # Character 綰
+#U+7db1 gÄng # Character 綱
+#U+7db2 wÇng # Character 網
+#U+7db3 bÄng # Character 綳
+U+7db4 zhui # Character 綴
+#U+7db5 cÇi # Character 綵
+#U+7db6 guÇ # Character 綶
+U+7db7 cuì # Character 綷
+U+7db8 lún # Character 綸
+#U+7db9 liÇ # Character 綹
+#U+7dba qÇ # Character 綺
+U+7dbb zhà n # Character 綻
+#U+7dbc bÄi # Character 綼
+U+7dbd chuò # Character 綽
+U+7dbe lÃng # Character 綾
+U+7dbf mián # Character 綿
+#U+7dc0 qÄ« # Character ç·
+U+7dc1 qiè # Character ç·
+#U+7dc2 tÄn # Character ç·
+#U+7dc3 zÅng # Character ç·
+#U+7dc4 gÇn # Character ç·
+#U+7dc5 zÅu # Character ç·
+U+7dc6 yì # Character ç·
+#U+7dc7 zÄ« # Character ç·
+U+7dc8 xìng # Character ç·
+#U+7dc9 liÇng # Character ç·
+#U+7dca jÇn # Character ç·
+#U+7dcb fÄi # Character ç·
+U+7dcc ruà # Character ç·
+U+7dcd mÃn # Character ç·
+U+7dce yù # Character ç·
+#U+7dcf zÇng # Character ç·
+U+7dd0 fán # Character ç·
+#U+7dd1 lÇ # Character ç·
+U+7dd2 xù # Character ç·
+#U+7dd3 yÄ«ng # Character ç·
+U+7dd4 zhà ng # Character ç·
+U+7dd5 ? # Character ç·
+U+7dd6 xù # Character ç·
+#U+7dd7 xiÄng # Character ç·
+#U+7dd8 jiÄn # Character ç·
+U+7dd9 kè # Character ç·
+U+7dda xià n # Character ç·
+#U+7ddb ruÇn # Character ç·
+U+7ddc mián # Character ç·
+U+7ddd qì # Character ç·
+U+7dde duà n # Character ç·
+U+7ddf zhòng # Character ç·
+U+7de0 dì # Character ç·
+U+7de1 mÃn # Character ç·¡
+U+7de2 miáo # Character 緢
+U+7de3 yuán # Character 緣
+U+7de4 xiè # Character 緤
+#U+7de5 bÇo # Character ç·¥
+#U+7de6 sī # Character 緦
+#U+7de7 qiū # Character 緧
+#U+7de8 biÄn # Character ç·¨
+#U+7de9 huÇn # Character ç·©
+#U+7dea gÄng # Character ç·ª
+#U+7deb cÅng # Character ç·«
+#U+7dec miÇn # Character ç·¬
+U+7ded wèi # Character ç·
+U+7dee fù # Character 緮
+#U+7def wÄi # Character ç·¯
+U+7df0 yú # Character 緰
+#U+7df1 gÅu # Character ç·±
+#U+7df2 miÇo # Character ç·²
+U+7df3 xié # Character 緳
+U+7df4 lià n # Character 練
+#U+7df5 zÅng # Character ç·µ
+U+7df6 bià n # Character 緶
+U+7df7 yùn # Character 緷
+#U+7df8 yīn # Character 緸
+U+7df9 tà # Character 緹
+#U+7dfa guÄ # Character ç·º
+U+7dfb zhì # Character 緻
+#U+7dfc yūn # Character 緼
+#U+7dfd chÄng # Character ç·½
+U+7dfe chán # Character 緾
+U+7dff dà i # Character 緿
diff --git a/resources/chars/latin1/row7e.trans b/resources/chars/latin1/row7e.trans
new file mode 100644
index 0000000..62f3621
--- /dev/null
+++ b/resources/chars/latin1/row7e.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+7e00 xiá # Character ç¸
+U+7e01 yuán # Character ç¸
+#U+7e02 zÇng # Character ç¸
+#U+7e03 xÅ« # Character ç¸
+U+7e04 ? # Character ç¸
+U+7e05 ? # Character ç¸
+#U+7e06 gÄng # Character ç¸
+U+7e07 ? # Character ç¸
+U+7e08 yÃng # Character ç¸
+U+7e09 jìn # Character ç¸
+U+7e0a yì # Character ç¸
+U+7e0b zhuì # Character ç¸
+U+7e0c nì # Character ç¸
+#U+7e0d bÄng # Character ç¸
+#U+7e0e gÇ # Character ç¸
+U+7e0f pán # Character ç¸
+U+7e10 zhòu # Character ç¸
+#U+7e11 jiÄn # Character ç¸
+#U+7e12 cuÇ # Character ç¸
+#U+7e13 quÇn # Character ç¸
+#U+7e14 shuÇng # Character ç¸
+#U+7e15 yÅ«n # Character ç¸
+U+7e16 xiá # Character ç¸
+#U+7e17 shuÄi # Character ç¸
+#U+7e18 xÄ« # Character ç¸
+U+7e19 róng # Character ç¸
+#U+7e1a tÄo # Character ç¸
+U+7e1b fù # Character ç¸
+U+7e1c yún # Character ç¸
+#U+7e1d zhÄn # Character ç¸
+#U+7e1e gÇo # Character ç¸
+U+7e1f rù # Character ç¸
+U+7e20 hú # Character ç¸
+#U+7e21 zÇi # Character 縡
+U+7e22 téng # Character 縢
+U+7e23 xià n # Character 縣
+U+7e24 sù # Character 縤
+#U+7e25 zhÄn # Character 縥
+U+7e26 zòng # Character 縦
+#U+7e27 tÄo # Character 縧
+U+7e28 ? # Character 縨
+U+7e29 cà i # Character 縩
+U+7e2a bì # Character 縪
+U+7e2b fèng # Character 縫
+U+7e2c cù # Character 縬
+U+7e2d là # Character ç¸
+#U+7e2e suŠ# Character 縮
+#U+7e2f yÇn # Character 縯
+#U+7e30 xÇ # Character 縰
+U+7e31 zòng # Character 縱
+U+7e32 léi # Character 縲
+U+7e33 zhuà n # Character 縳
+#U+7e34 qiÄn # Character 縴
+U+7e35 mà n # Character 縵
+U+7e36 zhà # Character 縶
+#U+7e37 lÇ # Character 縷
+U+7e38 mò # Character 縸
+#U+7e39 piÇo # Character 縹
+U+7e3a lián # Character 縺
+U+7e3b mà # Character 縻
+U+7e3c xuà n # Character 縼
+#U+7e3d zÇng # Character 總
+#U+7e3e jī # Character 績
+#U+7e3f shÄn # Character 縿
+U+7e40 suì # Character ç¹
+U+7e41 fán # Character ç¹
+U+7e42 shuà i # Character ç¹
+#U+7e43 bÄng # Character ç¹
+#U+7e44 yÄ« # Character ç¹
+#U+7e45 sÄo # Character ç¹
+U+7e46 móu # Character ç¹
+U+7e47 zhòu # Character ç¹
+#U+7e48 qiÇng # Character ç¹
+U+7e49 hún # Character ç¹
+U+7e4a ? # Character ç¹
+U+7e4b xì # Character ç¹
+U+7e4c ? # Character ç¹
+U+7e4d xiù # Character ç¹
+U+7e4e rán # Character ç¹
+U+7e4f xuà n # Character ç¹
+U+7e50 huì # Character ç¹
+#U+7e51 qiÄo # Character ç¹
+#U+7e52 zÄng # Character ç¹
+#U+7e53 zuÇ # Character ç¹
+#U+7e54 zhÄ« # Character ç¹
+U+7e55 shà n # Character ç¹
+#U+7e56 sÇn # Character ç¹
+U+7e57 lÃn # Character ç¹
+U+7e58 yù # Character ç¹
+#U+7e59 fÄn # Character ç¹
+U+7e5a liáo # Character ç¹
+U+7e5b chuò # Character ç¹
+#U+7e5c zÅ«n # Character ç¹
+U+7e5d jià n # Character ç¹
+U+7e5e rà o # Character ç¹
+#U+7e5f chÇn # Character ç¹
+#U+7e60 ruÇ # Character ç¹
+U+7e61 xiù # Character 繡
+U+7e62 huì # Character 繢
+U+7e63 huà # Character 繣
+#U+7e64 zuÇn # Character 繤
+#U+7e65 xī # Character 繥
+#U+7e66 qiÇng # Character 繦
+U+7e67 ? # Character 繧
+U+7e68 dá # Character 繨
+U+7e69 shéng # Character 繩
+U+7e6a huì # Character 繪
+U+7e6b xì # Character 繫
+U+7e6c sè # Character 繬
+#U+7e6d jiÇn # Character ç¹
+#U+7e6e jiÄng # Character ç¹®
+U+7e6f huán # Character 繯
+#U+7e70 zÇo # Character ç¹°
+#U+7e71 cÅng # Character ç¹±
+U+7e72 jiè # Character 繲
+#U+7e73 jiÇo # Character ç¹³
+U+7e74 bò # Character 繴
+U+7e75 chán # Character 繵
+U+7e76 yì # Character 繶
+U+7e77 náo # Character 繷
+U+7e78 suì # Character 繸
+U+7e79 yì # Character 繹
+#U+7e7a shÇi # Character 繺
+#U+7e7b xū # Character 繻
+U+7e7c jì # Character 繼
+#U+7e7d bīn # Character 繽
+#U+7e7e qiÇn # Character ç¹¾
+U+7e7f lán # Character 繿
+U+7e80 pú # Character çº
+#U+7e81 xÅ«n # Character çº
+#U+7e82 zuÇn # Character çº
+U+7e83 qà # Character çº
+U+7e84 péng # Character çº
+U+7e85 lì # Character çº
+U+7e86 mò # Character çº
+U+7e87 lèi # Character çº
+U+7e88 xié # Character çº
+#U+7e89 zuÇn # Character çº
+U+7e8a kuà ng # Character çº
+#U+7e8b yÅu # Character çº
+U+7e8c xù # Character çº
+U+7e8d léi # Character çº
+#U+7e8e xiÄn # Character çº
+U+7e8f chán # Character çº
+U+7e90 ? # Character çº
+U+7e91 lú # Character çº
+U+7e92 chán # Character çº
+#U+7e93 yÄ«ng # Character çº
+U+7e94 cái # Character çº
+#U+7e95 xiÄng # Character çº
+#U+7e96 xiÄn # Character çº
+#U+7e97 zuÄ« # Character çº
+#U+7e98 zuÇn # Character çº
+U+7e99 luò # Character çº
+#U+7e9a xÇ # Character çº
+U+7e9b dà o # Character çº
+U+7e9c là n # Character çº
+U+7e9d léi # Character çº
+U+7e9e lià n # Character çº
+#U+7e9f sÄ« # Character çº
+#U+7ea0 jiÅ« # Character çº
+#U+7ea1 yū # Character 纡
+U+7ea2 hóng # Character 红
+U+7ea3 zhòu # Character 纣
+#U+7ea4 xiÄn # Character 纤
+U+7ea5 hé # Character 纥
+#U+7ea6 yuÄ # Character 约
+U+7ea7 jà # Character 级
+U+7ea8 wán # Character 纨
+U+7ea9 kuà ng # Character 纩
+U+7eaa jì # Character 纪
+U+7eab rèn # Character 纫
+#U+7eac wÄi # Character 纬
+U+7ead yún # Character çº
+U+7eae hóng # Character 纮
+U+7eaf chún # Character 纯
+U+7eb0 pà # Character 纰
+#U+7eb1 shÄ # Character 纱
+#U+7eb2 gÄng # Character 纲
+U+7eb3 nà # Character 纳
+U+7eb4 rén # Character 纴
+U+7eb5 zòng # Character 纵
+U+7eb6 lún # Character 纶
+#U+7eb7 fÄn # Character 纷
+#U+7eb8 zhÇ # Character 纸
+U+7eb9 wén # Character 纹
+#U+7eba fÇng # Character 纺
+U+7ebb zhù # Character 纻
+#U+7ebc yÇn # Character 纼
+#U+7ebd niÇ # Character 纽
+#U+7ebe shū # Character 纾
+U+7ebf xià n # Character 线
+U+7ec0 gà n # Character ç»
+U+7ec1 xiè # Character ç»
+U+7ec2 fú # Character ç»
+U+7ec3 lià n # Character ç»
+#U+7ec4 zÇ # Character ç»
+#U+7ec5 shÄn # Character ç»
+U+7ec6 xì # Character ç»
+#U+7ec7 zhÄ« # Character ç»
+#U+7ec8 zhÅng # Character ç»
+U+7ec9 zhòu # Character ç»
+U+7eca bà n # Character ç»
+U+7ecb fú # Character ç»
+U+7ecc zhuó # Character ç»
+U+7ecd shà o # Character ç»
+U+7ece yì # Character ç»
+#U+7ecf jÄ«ng # Character ç»
+U+7ed0 dà i # Character ç»
+#U+7ed1 bÇng # Character ç»
+U+7ed2 róng # Character ç»
+U+7ed3 jié # Character ç»
+U+7ed4 kù # Character ç»
+U+7ed5 rà o # Character ç»
+U+7ed6 dié # Character ç»
+U+7ed7 hèng # Character ç»
+U+7ed8 huì # Character ç»
+#U+7ed9 gÄi # Character ç»
+U+7eda xuà n # Character ç»
+U+7edb jià ng # Character ç»
+U+7edc luò # Character ç»
+U+7edd jué # Character ç»
+#U+7ede jiÇo # Character ç»
+#U+7edf tÇng # Character ç»
+#U+7ee0 gÄng # Character ç»
+#U+7ee1 xiÄo # Character 绡
+U+7ee2 juà n # Character 绢
+U+7ee3 xiù # Character 绣
+U+7ee4 xì # Character 绤
+#U+7ee5 suī # Character 绥
+#U+7ee6 tÄo # Character 绦
+U+7ee7 jì # Character 继
+U+7ee8 tà # Character 绨
+#U+7ee9 jī # Character 绩
+U+7eea xù # Character 绪
+U+7eeb lÃng # Character 绫
+#U+7eec yīng # Character 绬
+U+7eed xù # Character ç»
+#U+7eee qÇ # Character ç»®
+#U+7eef fÄi # Character 绯
+U+7ef0 chuò # Character 绰
+#U+7ef1 zhÇng # Character ç»±
+#U+7ef2 gÇn # Character 绲
+U+7ef3 shéng # Character 绳
+U+7ef4 wéi # Character 维
+U+7ef5 mián # Character 绵
+U+7ef6 shòu # Character 绶
+#U+7ef7 bÄng # Character ç»·
+U+7ef8 chóu # Character 绸
+U+7ef9 táo # Character 绹
+#U+7efa liÇ # Character 绺
+#U+7efb quÇn # Character ç»»
+#U+7efc zÅng # Character 综
+U+7efd zhà n # Character 绽
+#U+7efe wÇn # Character 绾
+#U+7eff lÇ # Character 绿
diff --git a/resources/chars/latin1/row7f.trans b/resources/chars/latin1/row7f.trans
new file mode 100644
index 0000000..16b21a7
--- /dev/null
+++ b/resources/chars/latin1/row7f.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+7f00 zhui # Character ç¼
+#U+7f01 zÄ« # Character ç¼
+U+7f02 kè # Character ç¼
+#U+7f03 xiÄng # Character ç¼
+#U+7f04 jiÄn # Character ç¼
+#U+7f05 miÇn # Character ç¼
+U+7f06 là n # Character ç¼
+U+7f07 tà # Character ç¼
+#U+7f08 miÇo # Character ç¼
+U+7f09 qì # Character ç¼
+#U+7f0a yÅ«n # Character ç¼
+U+7f0b huì # Character ç¼
+#U+7f0c sÄ« # Character ç¼
+#U+7f0d duÇ # Character ç¼
+U+7f0e duà n # Character ç¼
+U+7f0f bià n # Character ç¼
+U+7f10 xià n # Character ç¼
+#U+7f11 gÅu # Character ç¼
+U+7f12 zhuì # Character ç¼
+#U+7f13 huÇn # Character ç¼
+U+7f14 dì # Character ç¼
+#U+7f15 lÇ # Character ç¼
+#U+7f16 biÄn # Character ç¼
+U+7f17 mÃn # Character ç¼
+U+7f18 yuán # Character ç¼
+U+7f19 jìn # Character ç¼
+U+7f1a fù # Character ç¼
+U+7f1b rù # Character ç¼
+#U+7f1c zhÄn # Character ç¼
+U+7f1d fèng # Character ç¼
+#U+7f1e shuÄi # Character ç¼
+#U+7f1f gÇo # Character ç¼
+U+7f20 chán # Character ç¼
+U+7f21 là # Character 缡
+U+7f22 yì # Character 缢
+#U+7f23 jiÄn # Character ç¼£
+#U+7f24 bīn # Character 缤
+#U+7f25 piÇo # Character ç¼¥
+U+7f26 mà n # Character 缦
+U+7f27 léi # Character 缧
+#U+7f28 yīng # Character 缨
+#U+7f29 suŠ# Character 缩
+U+7f2a móu # Character 缪
+#U+7f2b sÄo # Character 缫
+U+7f2c xié # Character 缬
+U+7f2d liáo # Character ç¼
+U+7f2e shà n # Character 缮
+#U+7f2f zÄng # Character 缯
+#U+7f30 jiÄng # Character ç¼°
+#U+7f31 qiÇn # Character ç¼±
+#U+7f32 zÇo # Character ç¼²
+U+7f33 huán # Character 缳
+#U+7f34 jiÇo # Character ç¼´
+#U+7f35 zuÇn # Character ç¼µ
+#U+7f36 fÇu # Character 缶
+U+7f37 xiè # Character 缷
+#U+7f38 gÄng # Character 缸
+#U+7f39 fÇu # Character ç¼¹
+#U+7f3a quÄ # Character 缺
+#U+7f3b fÇu # Character ç¼»
+U+7f3c ? # Character ç¼¼
+#U+7f3d bÅ # Character ç¼½
+U+7f3e pÃng # Character ç¼¾
+U+7f3f hòu # Character 缿
+U+7f40 ? # Character ç½
+#U+7f41 gÄng # Character ç½
+#U+7f42 yÄ«ng # Character ç½
+#U+7f43 yÄ«ng # Character ç½
+U+7f44 qìng # Character ç½
+U+7f45 xià # Character ç½
+U+7f46 guà n # Character ç½
+#U+7f47 zÅ«n # Character ç½
+U+7f48 tán # Character ç½
+U+7f49 ? # Character ç½
+U+7f4a qì # Character ç½
+U+7f4b wèng # Character ç½
+#U+7f4c yÄ«ng # Character ç½
+U+7f4d léi # Character ç½
+U+7f4e tán # Character ç½
+U+7f4f lú # Character ç½
+U+7f50 guà n # Character ç½
+#U+7f51 wÇng # Character ç½
+#U+7f52 wÇng # Character ç½
+#U+7f53 gÄng # Character ç½
+#U+7f54 wÇng # Character ç½
+#U+7f55 hÇn # Character ç½
+U+7f56 ? # Character ç½
+#U+7f57 luÅ # Character ç½
+U+7f58 fú # Character ç½
+U+7f59 mà # Character ç½
+U+7f5a fá # Character ç½
+#U+7f5b gÅ« # Character ç½
+#U+7f5c zhÇ # Character ç½
+#U+7f5d jÅ« # Character ç½
+U+7f5e máo # Character ç½
+#U+7f5f gÇ # Character ç½
+U+7f60 mÃn # Character ç½
+#U+7f61 gÄng # Character 罡
+U+7f62 ba # Character ç½¢
+U+7f63 guà # Character 罣
+U+7f64 tà # Character 罤
+U+7f65 juà n # Character 罥
+#U+7f66 fū # Character 罦
+U+7f67 lÃn # Character 罧
+#U+7f68 yÇn # Character 罨
+U+7f69 zhà o # Character 罩
+U+7f6a zuì # Character 罪
+U+7f6b guà # Character 罫
+U+7f6c zhuó # Character 罬
+U+7f6d yù # Character ç½
+U+7f6e zhì # Character 置
+#U+7f6f Çn # Character 罯
+U+7f70 fá # Character 罰
+#U+7f71 nÇn # Character ç½±
+#U+7f72 shÇ # Character ç½²
+#U+7f73 sī # Character 罳
+U+7f74 pà # Character 罴
+U+7f75 mà # Character 罵
+#U+7f76 liÇ # Character 罶
+U+7f77 ba # Character ç½·
+U+7f78 fá # Character 罸
+U+7f79 là # Character 罹
+#U+7f7a chÄo # Character 罺
+U+7f7b wèi # Character 罻
+U+7f7c bì # Character 罼
+U+7f7d jì # Character 罽
+#U+7f7e zÄng # Character ç½¾
+U+7f7f tóng # Character 罿
+#U+7f80 liÇ # Character ç¾
+#U+7f81 jÄ« # Character ç¾
+U+7f82 juà n # Character ç¾
+U+7f83 mì # Character ç¾
+U+7f84 zhà o # Character ç¾
+U+7f85 luó # Character ç¾
+U+7f86 pà # Character ç¾
+#U+7f87 jÄ« # Character ç¾
+#U+7f88 jÄ« # Character ç¾
+U+7f89 luán # Character ç¾
+U+7f8a yáng # Character ç¾
+#U+7f8b miÄ # Character ç¾
+#U+7f8c qiÄng # Character ç¾
+U+7f8d tà # Character ç¾
+#U+7f8e mÄi # Character ç¾
+U+7f8f yáng # Character ç¾
+#U+7f90 yÇu # Character ç¾
+#U+7f91 yÇu # Character ç¾
+U+7f92 fén # Character ç¾
+#U+7f93 bÄ # Character ç¾
+#U+7f94 gÄo # Character ç¾
+U+7f95 yà ng # Character ç¾
+#U+7f96 gÇ # Character ç¾
+#U+7f97 qiÄng # Character ç¾
+#U+7f98 zÄng # Character ç¾
+#U+7f99 gÄo # Character ç¾
+U+7f9a lÃng # Character ç¾
+U+7f9b yì # Character ç¾
+U+7f9c zhù # Character ç¾
+#U+7f9d dÄ« # Character ç¾
+#U+7f9e xiÅ« # Character ç¾
+#U+7f9f qiÄn # Character ç¾
+U+7fa0 yà # Character ç¾
+U+7fa1 xià n # Character 羡
+U+7fa2 róng # Character 羢
+U+7fa3 qún # Character 羣
+U+7fa4 qún # Character 群
+#U+7fa5 qiÄn # Character ç¾¥
+U+7fa6 huán # Character 羦
+#U+7fa7 zuī # Character 羧
+U+7fa8 xià n # Character 羨
+U+7fa9 yì # Character 義
+U+7faa ? # Character 羪
+#U+7fab qiÄng # Character 羫
+U+7fac xián # Character 羬
+U+7fad yú # Character ç¾
+#U+7fae gÄng # Character ç¾®
+U+7faf jié # Character 羯
+#U+7fb0 tÄng # Character ç¾°
+U+7fb1 yuán # Character 羱
+#U+7fb2 xī # Character 羲
+U+7fb3 fán # Character 羳
+#U+7fb4 shÄn # Character ç¾´
+#U+7fb5 fÄn # Character ç¾µ
+#U+7fb6 shÄn # Character 羶
+#U+7fb7 liÇn # Character ç¾·
+U+7fb8 léi # Character 羸
+#U+7fb9 gÄng # Character ç¾¹
+U+7fba nóu # Character 羺
+U+7fbb qià ng # Character 羻
+U+7fbc chà n # Character 羼
+#U+7fbd yÇ # Character ç¾½
+U+7fbe gòng # Character 羾
+U+7fbf yì # Character 羿
+U+7fc0 chóng # Character ç¿
+#U+7fc1 wÄng # Character ç¿
+#U+7fc2 fÄn # Character ç¿
+U+7fc3 hóng # Character ç¿
+U+7fc4 chì # Character ç¿
+U+7fc5 chì # Character ç¿
+U+7fc6 cuì # Character ç¿
+U+7fc7 fú # Character ç¿
+U+7fc8 xiá # Character ç¿
+#U+7fc9 pÄn # Character ç¿
+U+7fca yì # Character ç¿
+#U+7fcb lÄ # Character ç¿
+U+7fcc yì # Character ç¿
+#U+7fcd pÄ« # Character ç¿
+U+7fce lÃng # Character ç¿
+U+7fcf liù # Character ç¿
+U+7fd0 zhì # Character ç¿
+U+7fd1 qú # Character ç¿
+U+7fd2 xà # Character ç¿
+U+7fd3 xié # Character ç¿
+U+7fd4 xiáng # Character ç¿
+U+7fd5 xì # Character ç¿
+U+7fd6 xì # Character ç¿
+U+7fd7 qà # Character ç¿
+U+7fd8 qià o # Character ç¿
+U+7fd9 huì # Character ç¿
+#U+7fda huÄ« # Character ç¿
+#U+7fdb xiÄo # Character ç¿
+U+7fdc sè # Character ç¿
+U+7fdd hóng # Character ç¿
+#U+7fde jiÄng # Character ç¿
+U+7fdf dà # Character ç¿
+U+7fe0 cuì # Character ç¿
+#U+7fe1 fÄi # Character ç¿¡
+#U+7fe2 tÄo # Character ç¿¢
+U+7fe3 shà # Character 翣
+U+7fe4 chì # Character 翤
+U+7fe5 zhù # Character 翥
+#U+7fe6 jiÇn # Character 翦
+#U+7fe7 xuÄn # Character 翧
+U+7fe8 shì # Character 翨
+#U+7fe9 piÄn # Character ç¿©
+#U+7fea zÅng # Character 翪
+U+7feb wà n # Character 翫
+#U+7fec huī # Character 翬
+U+7fed hóu # Character ç¿
+U+7fee hé # Character 翮
+U+7fef hè # Character 翯
+U+7ff0 hà n # Character 翰
+U+7ff1 áo # Character 翱
+#U+7ff2 piÄo # Character 翲
+U+7ff3 yì # Character 翳
+U+7ff4 lián # Character 翴
+U+7ff5 qú # Character 翵
+U+7ff6 ? # Character 翶
+U+7ff7 lÃn # Character ç¿·
+#U+7ff8 pÄn # Character 翸
+U+7ff9 qià o # Character 翹
+U+7ffa áo # Character 翺
+#U+7ffb fÄn # Character ç¿»
+U+7ffc yì # Character 翼
+U+7ffd huì # Character 翽
+#U+7ffe xuÄn # Character 翾
+U+7fff dà o # Character 翿
diff --git a/resources/chars/latin1/row80.trans b/resources/chars/latin1/row80.trans
new file mode 100644
index 0000000..8e5f948
--- /dev/null
+++ b/resources/chars/latin1/row80.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+8000 yà o # Character è
+#U+8001 lÇo # Character è
+U+8002 ? # Character è
+#U+8003 kÇo # Character è
+U+8004 mà o # Character è
+#U+8005 zhÄ # Character è
+U+8006 qà # Character è
+#U+8007 gÇu # Character è
+#U+8008 gÇu # Character è
+#U+8009 gÇu # Character è
+U+800a diè # Character è
+U+800b diè # Character è
+U+800c ér # Character è
+#U+800d shuÇ # Character è
+#U+800e ruÇn # Character è
+U+800f ér # Character è
+U+8010 nà i # Character è
+#U+8011 zhuÄn # Character è
+#U+8012 lÄi # Character è
+#U+8013 tÄ«ng # Character è
+#U+8014 zÇ # Character è
+#U+8015 gÄng # Character è
+U+8016 chà o # Character è
+U+8017 hà o # Character è
+U+8018 yún # Character è
+U+8019 pá # Character è
+#U+801a pÄ« # Character è
+U+801b chà # Character è
+U+801c sì # Character è
+U+801d chú # Character è
+#U+801e jiÄ # Character è
+U+801f jù # Character è
+U+8020 hé # Character è
+U+8021 chú # Character è¡
+U+8022 là o # Character è¢
+#U+8023 lÇn # Character è£
+U+8024 jà # Character è¤
+#U+8025 tÇng # Character è¥
+#U+8026 Çu # Character è¦
+U+8027 lóu # Character è§
+U+8028 nòu # Character è¨
+#U+8029 gÅu # Character è©
+#U+802a pÇng # Character èª
+U+802b zé # Character è«
+U+802c lóu # Character è¬
+#U+802d jÄ« # Character è
+U+802e là o # Character è®
+U+802f huò # Character è¯
+#U+8030 yÅu # Character è°
+U+8031 mò # Character è±
+U+8032 huái # Character è²
+#U+8033 Är # Character è³
+U+8034 zhé # Character è´
+#U+8035 tÄ«ng # Character èµ
+U+8036 yé # Character è¶
+#U+8037 dÄ # Character è·
+#U+8038 sÇng # Character è¸
+U+8039 qÃn # Character è¹
+U+803a yún # Character èº
+#U+803b chÇ # Character è»
+#U+803c dÄn # Character è¼
+#U+803d dÄn # Character è½
+U+803e hóng # Character è¾
+#U+803f gÄng # Character è¿
+U+8040 zhà # Character è
+U+8041 ? # Character è
+U+8042 niè # Character è
+#U+8043 dÄn # Character è
+#U+8044 zhÄn # Character è
+U+8045 chè # Character è
+U+8046 lÃng # Character è
+#U+8047 zhÄng # Character è
+#U+8048 yÇu # Character è
+#U+8049 wÄ # Character è
+U+804a liáo # Character è
+U+804b lóng # Character è
+U+804c zhà # Character è
+U+804d nÃng # Character è
+#U+804e tiÄo # Character è
+U+804f ér # Character è
+U+8050 yà # Character è
+U+8051 dié # Character è
+#U+8052 guÄ # Character è
+U+8053 ? # Character è
+U+8054 lián # Character è
+U+8055 hà o # Character è
+U+8056 shèng # Character è
+U+8057 liè # Character è
+U+8058 pìn # Character è
+#U+8059 jÄ«ng # Character è
+U+805a jù # Character è
+U+805b bì # Character è
+#U+805c dÇ # Character è
+U+805d guó # Character è
+U+805e wén # Character è
+U+805f xù # Character è
+U+8060 pÃng # Character è
+#U+8061 cÅng # Character è¡
+U+8062 ? # Character è¢
+U+8063 ? # Character è£
+U+8064 tÃng # Character è¤
+#U+8065 yÇ # Character è¥
+#U+8066 cÅng # Character è¦
+U+8067 kuà # Character è§
+U+8068 ? # Character è¨
+U+8069 kuì # Character è©
+#U+806a cÅng # Character èª
+U+806b lián # Character è«
+#U+806c wÄng # Character è¬
+U+806d kuì # Character è
+U+806e lián # Character è®
+U+806f lián # Character è¯
+#U+8070 cÅng # Character è°
+U+8071 áo # Character è±
+#U+8072 shÄng # Character è²
+#U+8073 sÇng # Character è³
+#U+8074 tÄ«ng # Character è´
+U+8075 kuì # Character èµ
+U+8076 niè # Character è¶
+U+8077 zhà # Character è·
+#U+8078 dÄn # Character è¸
+U+8079 nÃng # Character è¹
+U+807a ? # Character èº
+#U+807b jÄ« # Character è»
+#U+807c tÄ«ng # Character è¼
+#U+807d tÄ«ng # Character è½
+U+807e lóng # Character è¾
+U+807f yù # Character è¿
+U+8080 yù # Character è
+U+8081 zhà o # Character è
+U+8082 sì # Character è
+U+8083 sù # Character è
+U+8084 yì # Character è
+U+8085 sù # Character è
+U+8086 sì # Character è
+U+8087 zhà o # Character è
+U+8088 zhà o # Character è
+U+8089 ròu # Character è
+U+808a yì # Character è
+U+808b lè # Character è
+#U+808c jÄ« # Character è
+U+808d qiú # Character è
+#U+808e kÄn # Character è
+U+808f cà o # Character è
+#U+8090 gÄ # Character è
+U+8091 dì # Character è
+U+8092 huán # Character è
+#U+8093 huÄng # Character è
+#U+8094 yÇ # Character è
+U+8095 rèn # Character è
+U+8096 xià o # Character è
+#U+8097 rÇ # Character è
+#U+8098 zhÇu # Character è
+#U+8099 yuÄn # Character è
+U+809a dù # Character è
+#U+809b gÄng # Character è
+U+809c róng # Character è
+#U+809d gÄn # Character è
+#U+809e chÄ # Character è
+U+809f wò # Character è
+U+80a0 cháng # Character è
+#U+80a1 gÇ # Character è¡
+#U+80a2 zhÄ« # Character è¢
+U+80a3 hán # Character è£
+#U+80a4 fÅ« # Character è¤
+U+80a5 féi # Character è¥
+U+80a6 fén # Character è¦
+#U+80a7 pÄi # Character è§
+U+80a8 pà ng # Character è¨
+#U+80a9 jiÄn # Character è©
+U+80aa fáng # Character èª
+#U+80ab zhÅ«n # Character è«
+U+80ac yóu # Character è¬
+U+80ad nà # Character è
+U+80ae háng # Character è®
+#U+80af kÄn # Character è¯
+U+80b0 rán # Character è°
+#U+80b1 gÅng # Character è±
+U+80b2 yù # Character è²
+#U+80b3 wÄn # Character è³
+U+80b4 yáo # Character è´
+U+80b5 jìn # Character èµ
+U+80b6 pà # Character è¶
+#U+80b7 qiÄn # Character è·
+U+80b8 xì # Character è¸
+#U+80b9 xÄ« # Character è¹
+U+80ba fèi # Character èº
+#U+80bb kÄn # Character è»
+#U+80bc jÇng # Character è¼
+U+80bd tà i # Character è½
+U+80be shèn # Character è¾
+#U+80bf zhÇng # Character è¿
+U+80c0 zhà ng # Character è
+U+80c1 xié # Character è
+#U+80c2 shÄn # Character è
+U+80c3 wèi # Character è
+U+80c4 zhòu # Character è
+U+80c5 dié # Character è
+#U+80c6 dÇn # Character è
+U+80c7 fèi # Character è
+U+80c8 bá # Character è
+U+80c9 bó # Character è
+U+80ca qú # Character è
+U+80cb tián # Character è
+U+80cc bèi # Character è
+#U+80cd guÄ # Character è
+#U+80ce tÄi # Character è
+#U+80cf zÇ # Character è
+#U+80d0 kÅ« # Character è
+#U+80d1 zhÄ« # Character è
+U+80d2 nì # Character è
+U+80d3 pÃng # Character è
+U+80d4 zì # Character è
+U+80d5 fù # Character è
+U+80d6 pà ng # Character è
+#U+80d7 zhÄn # Character è
+U+80d8 xián # Character è
+U+80d9 zuò # Character è
+#U+80da pÄi # Character è
+#U+80db jiÇ # Character è
+U+80dc shèng # Character è
+#U+80dd zhÄ« # Character è
+#U+80de bÄo # Character è
+#U+80df mÇ # Character è
+#U+80e0 qÅ« # Character è
+U+80e1 hú # Character è¡
+#U+80e2 kÄ # Character è¢
+#U+80e3 yÇ # Character è£
+U+80e4 yìn # Character è¤
+#U+80e5 xÅ« # Character è¥
+#U+80e6 yÄng # Character è¦
+U+80e7 lóng # Character è§
+U+80e8 dòng # Character è¨
+#U+80e9 kÇ # Character è©
+U+80ea lú # Character èª
+U+80eb jìng # Character è«
+#U+80ec nÇ # Character è¬
+#U+80ed yÄn # Character è
+U+80ee páng # Character è®
+U+80ef kuà # Character è¯
+U+80f0 yà # Character è°
+#U+80f1 guÄng # Character è±
+#U+80f2 gÄi # Character è²
+#U+80f3 gÄ # Character è³
+U+80f4 dòng # Character è´
+U+80f5 zhì # Character èµ
+#U+80f6 jiÄo # Character è¶
+#U+80f7 xiÅng # Character è·
+#U+80f8 xiÅng # Character è¸
+U+80f9 ér # Character è¹
+U+80fa è # Character èº
+U+80fb xÃng # Character è»
+U+80fc pián # Character è¼
+U+80fd néng # Character è½
+U+80fe zì # Character è¾
+U+80ff ? # Character è¿
diff --git a/resources/chars/latin1/row81.trans b/resources/chars/latin1/row81.trans
new file mode 100644
index 0000000..7a48a80
--- /dev/null
+++ b/resources/chars/latin1/row81.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+8100 chéng # Character è
+U+8101 tià o # Character è
+#U+8102 zhÄ« # Character è
+U+8103 cuì # Character è
+U+8104 méi # Character è
+U+8105 xié # Character è
+U+8106 cuì # Character è
+U+8107 xié # Character è
+U+8108 mà i # Character è
+U+8109 mà i # Character è
+U+810a jà # Character è
+U+810b ? # Character è
+U+810c ? # Character è
+U+810d kuà i # Character è
+U+810e sà # Character è
+U+810f zà ng # Character è
+U+8110 qà # Character è
+#U+8111 nÇo # Character è
+#U+8112 mÇ # Character è
+U+8113 nóng # Character è
+U+8114 luán # Character è
+#U+8115 wÇn # Character è
+U+8116 bó # Character è
+#U+8117 wÄn # Character è
+#U+8118 guÇn # Character è
+U+8119 qiú # Character è
+#U+811a jiÇo # Character è
+U+811b jìng # Character è
+U+811c róu # Character è
+#U+811d hÄng # Character è
+#U+811e cuÇ # Character è
+U+811f liè # Character è
+#U+8120 shÄn # Character è
+#U+8121 tÇng # Character è¡
+U+8122 méi # Character è¢
+U+8123 chún # Character è£
+U+8124 shèn # Character è¤
+U+8125 xié # Character è¥
+U+8126 tè # Character è¦
+#U+8127 zuÄ« # Character è§
+U+8128 cù # Character è¨
+#U+8129 xiÅ« # Character è©
+U+812a xìn # Character èª
+#U+812b tuÅ # Character è«
+#U+812c pÄo # Character è¬
+U+812d chéng # Character è
+#U+812e nÄi # Character è®
+U+812f pú # Character è¯
+U+8130 dòu # Character è°
+#U+8131 tuÅ # Character è±
+U+8132 nià o # Character è²
+U+8133 ? # Character è³
+#U+8134 pÇ # Character è´
+#U+8135 gÇ # Character èµ
+#U+8136 guÄ # Character è¶
+U+8137 lì # Character è·
+#U+8138 liÇn # Character è¸
+U+8139 zhà ng # Character è¹
+U+813a cuì # Character èº
+U+813b jié # Character è»
+#U+813c liÇng # Character è¼
+#U+813d zhÅu # Character è½
+U+813e pà # Character è¾
+#U+813f biÄo # Character è¿
+U+8140 lún # Character è
+U+8141 pián # Character è
+U+8142 guò # Character è
+U+8143 kuì # Character è
+U+8144 chuà # Character è
+U+8145 dà n # Character è
+#U+8146 tiÇn # Character è
+#U+8147 nÄi # Character è
+#U+8148 jÄ«ng # Character è
+#U+8149 jiÄ # Character è
+U+814a là # Character è
+U+814b yì # Character è
+#U+814c Än # Character è
+#U+814d rÄn # Character è
+U+814e shèn # Character è
+U+814f chuò # Character è
+#U+8150 fÇ # Character è
+#U+8151 fÇ # Character è
+#U+8152 jÅ« # Character è
+U+8153 féi # Character è
+#U+8154 qiÄng # Character è
+U+8155 wà n # Character è
+U+8156 dòng # Character è
+U+8157 pà # Character è
+U+8158 guó # Character è
+#U+8159 zÅng # Character è
+U+815a dìng # Character è
+#U+815b wÅ« # Character è
+U+815c méi # Character è
+#U+815d ruÇn # Character è
+U+815e zhuà n # Character è
+U+815f zhì # Character è
+U+8160 còu # Character è
+#U+8161 guÄ # Character è
¡
+#U+8162 Çu # Character è
¢
+U+8163 dì # Character è
£
+#U+8164 Än # Character è
¤
+#U+8165 xÄ«ng # Character è
¥
+#U+8166 nÇo # Character è
¦
+U+8167 yú # Character è
§
+#U+8168 chuÇn # Character è
¨
+#U+8169 nÇn # Character è
©
+U+816a yùn # Character è
ª
+#U+816b zhÇng # Character è
«
+U+816c róu # Character è
¬
+U+816d è # Character è
+#U+816e sÄi # Character è
®
+U+816f tú # Character è
¯
+#U+8170 yÄo # Character è
°
+U+8171 jià n # Character è
±
+#U+8172 wÄi # Character è
²
+#U+8173 jiÇo # Character è
³
+U+8174 yú # Character è
´
+#U+8175 jiÄ # Character è
µ
+U+8176 duà n # Character è
¶
+U+8177 bì # Character è
·
+U+8178 cháng # Character è
¸
+U+8179 fù # Character è
¹
+U+817a xià n # Character è
º
+U+817b nì # Character è
»
+#U+817c miÇn # Character è
¼
+U+817d wà # Character è
½
+U+817e téng # Character è
¾
+#U+817f tuÇ # Character è
¿
+#U+8180 bÇng # Character è
+#U+8181 qiÄn # Character è
+#U+8182 lÇ # Character è
+U+8183 wà # Character è
+U+8184 sòu # Character è
+U+8185 táng # Character è
+U+8186 sù # Character è
+U+8187 zhuì # Character è
+U+8188 gé # Character è
+U+8189 yì # Character è
+U+818a bo # Character è
+U+818b liáo # Character è
+U+818c jà # Character è
+U+818d pà # Character è
+U+818e xié # Character è
+#U+818f gÄo # Character è
+#U+8190 lÇ # Character è
+U+8191 bìn # Character è
+U+8192 ? # Character è
+U+8193 cháng # Character è
+U+8194 lù # Character è
+U+8195 guó # Character è
+#U+8196 pÄng # Character è
+U+8197 chuái # Character è
+#U+8198 piÇo # Character è
+#U+8199 jiÇng # Character è
+#U+819a fÅ« # Character è
+U+819b táng # Character è
+U+819c mó # Character è
+#U+819d xÄ« # Character è
+#U+819e zhuÄn # Character è
+#U+819f lÇ # Character è
+#U+81a0 jiÄo # Character è
+U+81a1 yìng # Character è¡
+#U+81a2 lÇ # Character è¢
+U+81a3 zhì # Character è£
+U+81a4 ? # Character è¤
+#U+81a5 chÅ«n # Character è¥
+#U+81a6 liÇn # Character è¦
+U+81a7 tóng # Character è§
+U+81a8 péng # Character è¨
+U+81a9 nì # Character è©
+U+81aa zhà # Character èª
+U+81ab liáo # Character è«
+U+81ac cuì # Character è¬
+#U+81ad guÄ« # Character è
+#U+81ae xiÄo # Character è®
+#U+81af tÄng # Character è¯
+U+81b0 fán # Character è°
+U+81b1 zhà # Character è±
+#U+81b2 jiÄo # Character è²
+U+81b3 shà n # Character è³
+U+81b4 wú # Character è´
+U+81b5 cuì # Character èµ
+U+81b6 rùn # Character è¶
+#U+81b7 xiÄng # Character è·
+#U+81b8 suÇ # Character è¸
+U+81b9 fèn # Character è¹
+#U+81ba yÄ«ng # Character èº
+#U+81bb tÇn # Character è»
+#U+81bc zhuÄ # Character è¼
+#U+81bd dÇn # Character è½
+U+81be kuà i # Character è¾
+U+81bf nóng # Character è¿
+U+81c0 tún # Character è
+U+81c1 lián # Character è
+U+81c2 bì # Character è
+#U+81c3 yÇng # Character è
+U+81c4 jué # Character è
+U+81c5 chù # Character è
+U+81c6 yì # Character è
+#U+81c7 juÇn # Character è
+U+81c8 là # Character è
+#U+81c9 liÇn # Character è
+#U+81ca sÄo # Character è
+U+81cb tún # Character è
+#U+81cc gÇ # Character è
+U+81cd qà # Character è
+U+81ce cuì # Character è
+U+81cf bìn # Character è
+#U+81d0 xÅ«n # Character è
+U+81d1 rú # Character è
+U+81d2 huò # Character è
+U+81d3 zà ng # Character è
+U+81d4 xià n # Character è
+#U+81d5 biÄo # Character è
+U+81d6 xìng # Character è
+#U+81d7 kuÄn # Character è
+U+81d8 là # Character è
+#U+81d9 yÄn # Character è
+U+81da lú # Character è
+U+81db huò # Character è
+#U+81dc zÄng # Character è
+#U+81dd luÇ # Character è
+U+81de qú # Character è
+U+81df zà ng # Character è
+U+81e0 luán # Character è
+U+81e1 nà # Character è¡
+#U+81e2 zÄng # Character è¢
+U+81e3 chén # Character è£
+#U+81e4 qiÄn # Character è¤
+U+81e5 wò # Character è¥
+U+81e6 guà ng # Character è¦
+U+81e7 záng # Character è§
+U+81e8 lÃn # Character è¨
+U+81e9 guà ng # Character è©
+U+81ea zì # Character èª
+#U+81eb jiÇo # Character è«
+U+81ec niè # Character è¬
+U+81ed chòu # Character è
+U+81ee jì # Character è®
+#U+81ef gÄo # Character è¯
+U+81f0 chòu # Character è°
+U+81f1 mián # Character è±
+U+81f2 niè # Character è²
+U+81f3 zhì # Character è³
+U+81f4 zhì # Character è´
+U+81f5 gé # Character èµ
+U+81f6 jià n # Character è¶
+U+81f7 dié # Character è·
+U+81f8 zhì # Character è¸
+#U+81f9 xiÅ« # Character è¹
+U+81fa tái # Character èº
+#U+81fb zhÄn # Character è»
+U+81fc jiù # Character è¼
+U+81fd xià n # Character è½
+U+81fe yú # Character è¾
+#U+81ff chÄ # Character è¿
diff --git a/resources/chars/latin1/row82.trans b/resources/chars/latin1/row82.trans
new file mode 100644
index 0000000..0100a9e
--- /dev/null
+++ b/resources/chars/latin1/row82.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+8200 yÇo # Character è
+U+8201 yú # Character è
+#U+8202 chÅng # Character è
+U+8203 xì # Character è
+U+8204 xì # Character è
+U+8205 jiù # Character è
+U+8206 yú # Character è
+#U+8207 yÇ # Character è
+U+8208 xìng # Character è
+#U+8209 jÇ # Character è
+U+820a jiù # Character è
+U+820b xìn # Character è
+U+820c shé # Character è
+#U+820d shÄ # Character è
+U+820e ? # Character è
+#U+820f jiÇ # Character è
+U+8210 shì # Character è
+#U+8211 tÄn # Character è
+#U+8212 shÅ« # Character è
+U+8213 shì # Character è
+#U+8214 tiÇn # Character è
+U+8215 dà n # Character è
+U+8216 pù # Character è
+U+8217 pù # Character è
+#U+8218 guÇn # Character è
+U+8219 huà # Character è
+#U+821a tÄn # Character è
+#U+821b chuÇn # Character è
+U+821c shùn # Character è
+U+821d xiá # Character è
+#U+821e wÇ # Character è
+#U+821f zhÅu # Character è
+#U+8220 dÄo # Character è
+#U+8221 gÄng # Character è¡
+#U+8222 shÄn # Character è¢
+#U+8223 yÇ # Character è£
+U+8224 ? # Character è¤
+#U+8225 pÄ # Character è¥
+U+8226 tà i # Character è¦
+U+8227 fán # Character è§
+#U+8228 bÇn # Character è¨
+U+8229 chuán # Character è©
+U+822a háng # Character èª
+#U+822b fÇng # Character è«
+#U+822c bÄn # Character è¬
+U+822d què # Character è
+U+822e ? # Character è®
+#U+822f zhÅng # Character è¯
+U+8230 jià n # Character è°
+#U+8231 cÄng # Character è±
+U+8232 lÃng # Character è²
+U+8233 zhú # Character è³
+U+8234 zé # Character è´
+U+8235 duò # Character èµ
+U+8236 bó # Character è¶
+U+8237 xián # Character è·
+#U+8238 gÄ # Character è¸
+U+8239 chuán # Character è¹
+U+823a jiá # Character èº
+#U+823b lÇ # Character è»
+U+823c hóng # Character è¼
+U+823d páng # Character è½
+#U+823e xÄ« # Character è¾
+U+823f ? # Character è¿
+U+8240 fú # Character è
+U+8241 zà o # Character è
+U+8242 féng # Character è
+U+8243 là # Character è
+#U+8244 shÄo # Character è
+U+8245 yú # Character è
+U+8246 láng # Character è
+#U+8247 tÇng # Character è
+U+8248 ? # Character è
+#U+8249 wÄi # Character è
+U+824a bó # Character è
+#U+824b mÄng # Character è
+U+824c nià n # Character è
+#U+824d jÅ« # Character è
+U+824e huáng # Character è
+#U+824f shÇu # Character è
+#U+8250 zÅng # Character è
+U+8251 bià n # Character è
+U+8252 mà o # Character è
+U+8253 dié # Character è
+U+8254 ? # Character è
+U+8255 bà ng # Character è
+#U+8256 chÄ # Character è
+U+8257 yì # Character è
+#U+8258 sÅu # Character è
+#U+8259 cÄng # Character è
+U+825a cáo # Character è
+U+825b lóu # Character è
+U+825c dà i # Character è
+U+825d ? # Character è
+U+825e yà o # Character è
+U+825f tóng # Character è
+U+8260 ? # Character è
+#U+8261 dÄng # Character è¡
+U+8262 tán # Character è¢
+#U+8263 lÇ # Character è£
+#U+8264 yÇ # Character è¤
+U+8265 jiè # Character è¥
+U+8266 jià n # Character è¦
+U+8267 huò # Character è§
+U+8268 méng # Character è¨
+U+8269 qà # Character è©
+#U+826a lÇ # Character èª
+U+826b lú # Character è«
+U+826c chán # Character è¬
+#U+826d shuÄng # Character è
+U+826e gèn # Character è®
+U+826f liáng # Character è¯
+#U+8270 jiÄn # Character è°
+#U+8271 jiÄn # Character è±
+U+8272 sè # Character è²
+U+8273 yà n # Character è³
+U+8274 fú # Character è´
+U+8275 pÃng # Character èµ
+U+8276 yà n # Character è¶
+U+8277 yà n # Character è·
+#U+8278 cÇo # Character è¸
+U+8279 ? # Character è¹
+U+827a yì # Character èº
+U+827b lè # Character è»
+#U+827c tÄ«ng # Character è¼
+U+827d qiú # Character è½
+U+827e à i # Character è¾
+#U+827f nÇi # Character è¿
+U+8280 tiáo # Character è
+#U+8281 jiÄo # Character è
+U+8282 jié # Character è
+U+8283 péng # Character è
+U+8284 wán # Character è
+U+8285 yì # Character è
+#U+8286 chÄi # Character è
+U+8287 mián # Character è
+#U+8288 miÄ # Character è
+#U+8289 gÄn # Character è
+#U+828a qiÄn # Character è
+U+828b yù # Character è
+U+828c yù # Character è
+U+828d shuò # Character è
+#U+828e qiÅng # Character è
+#U+828f tÇ # Character è
+U+8290 xià # Character è
+#U+8291 qÇ # Character è
+U+8292 máng # Character è
+#U+8293 zÇ # Character è
+#U+8294 huÇ # Character è
+#U+8295 suÄ« # Character è
+U+8296 zhì # Character è
+#U+8297 xiÄng # Character è
+#U+8298 bÄ« # Character è
+U+8299 fú # Character è
+U+829a tún # Character è
+#U+829b wÄi # Character è
+U+829c wú # Character è
+#U+829d zhÄ« # Character è
+#U+829e qÇ # Character è
+#U+829f shÄn # Character è
+U+82a0 wén # Character è
+U+82a1 qià n # Character è¡
+U+82a2 rén # Character è¢
+#U+82a3 fÇu # Character è£
+#U+82a4 kÅu # Character è¤
+U+82a5 jiè # Character è¥
+U+82a6 lú # Character è¦
+U+82a7 xù # Character è§
+U+82a8 jà # Character è¨
+U+82a9 qÃn # Character è©
+U+82aa qà # Character èª
+U+82ab yuán # Character è«
+#U+82ac fÄn # Character è¬
+#U+82ad bÄ # Character è
+U+82ae ruì # Character è®
+#U+82af xÄ«n # Character è¯
+U+82b0 jì # Character è°
+#U+82b1 huÄ # Character è±
+#U+82b2 huÄ # Character è²
+#U+82b3 fÄng # Character è³
+U+82b4 wù # Character è´
+U+82b5 jué # Character èµ
+#U+82b6 gÅu # Character è¶
+#U+82b7 zhÇ # Character è·
+U+82b8 yún # Character è¸
+U+82b9 qÃn # Character è¹
+#U+82ba Ço # Character èº
+U+82bb chú # Character è»
+U+82bc mà o # Character è¼
+U+82bd yá # Character è½
+U+82be fèi # Character è¾
+U+82bf rèng # Character è¿
+U+82c0 háng # Character è
+#U+82c1 cÅng # Character è
+U+82c2 yÃn # Character è
+#U+82c3 yÇu # Character è
+U+82c4 bià n # Character è
+U+82c5 yì # Character è
+U+82c6 ? # Character è
+#U+82c7 wÄi # Character è
+U+82c8 lì # Character è
+#U+82c9 pÇ # Character è
+U+82ca è # Character è
+U+82cb xià n # Character è
+U+82cc cháng # Character è
+#U+82cd cÄng # Character è
+U+82ce méng # Character è
+#U+82cf sÅ« # Character è
+U+82d0 yà # Character è
+U+82d1 yuà n # Character è
+#U+82d2 rÇn # Character è
+U+82d3 lÃng # Character è
+U+82d4 tái # Character è
+U+82d5 tiáo # Character è
+#U+82d6 dÇ # Character è
+U+82d7 miáo # Character è
+#U+82d8 qiÇng # Character è
+U+82d9 lì # Character è
+U+82da yòng # Character è
+#U+82db kÄ # Character è
+U+82dc mù # Character è
+U+82dd pèi # Character è
+#U+82de bÄo # Character è
+#U+82df gÇu # Character è
+U+82e0 mÃn # Character è
+#U+82e1 yÇ # Character è¡
+#U+82e2 yÇ # Character è¢
+U+82e3 jù # Character è£
+#U+82e4 pÇ # Character è¤
+U+82e5 ruò # Character è¥
+#U+82e6 kÇ # Character è¦
+U+82e7 zhù # Character è§
+#U+82e8 nÇ # Character è¨
+U+82e9 bó # Character è©
+#U+82ea bÇng # Character èª
+#U+82eb shÄn # Character è«
+U+82ec qiú # Character è¬
+#U+82ed yÇo # Character è
+#U+82ee xiÄn # Character è®
+#U+82ef bÄn # Character è¯
+U+82f0 hóng # Character è°
+#U+82f1 yÄ«ng # Character è±
+#U+82f2 zhÇ # Character è²
+#U+82f3 dÅng # Character è³
+#U+82f4 jÅ« # Character è´
+U+82f5 dié # Character èµ
+U+82f6 nié # Character è¶
+#U+82f7 gÄn # Character è·
+#U+82f8 hÅ« # Character è¸
+U+82f9 pÃng # Character è¹
+U+82fa méi # Character èº
+U+82fb fú # Character è»
+#U+82fc shÄng # Character è¼
+#U+82fd gÅ« # Character è½
+U+82fe bì # Character è¾
+U+82ff wèi # Character è¿
diff --git a/resources/chars/latin1/row83.trans b/resources/chars/latin1/row83.trans
new file mode 100644
index 0000000..dad49fe
--- /dev/null
+++ b/resources/chars/latin1/row83.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+8300 fú # Character è
+U+8301 zhuó # Character è
+U+8302 mà o # Character è
+U+8303 fà n # Character è
+#U+8304 jiÄ # Character è
+U+8305 máo # Character è
+#U+8306 mÇo # Character è
+U+8307 bá # Character è
+#U+8308 zÇ # Character è
+U+8309 mò # Character è
+#U+830a zÄ« # Character è
+#U+830b dÇ # Character è
+U+830c chà # Character è
+U+830d jì # Character è
+#U+830e jÄ«ng # Character è
+U+830f lóng # Character è
+U+8310 ? # Character è
+#U+8311 niÇo # Character è
+U+8312 ? # Character è
+U+8313 xué # Character è
+U+8314 yÃng # Character è
+U+8315 qióng # Character è
+U+8316 gé # Character è
+#U+8317 mÇng # Character è
+U+8318 lì # Character è
+U+8319 róng # Character è
+U+831a yìn # Character è
+U+831b gèn # Character è
+U+831c qià n # Character è
+#U+831d chÇi # Character è
+U+831e chén # Character è
+U+831f yù # Character è
+#U+8320 xiÅ« # Character è
+U+8321 zì # Character è¡
+U+8322 liè # Character è¢
+U+8323 wú # Character è£
+U+8324 jì # Character è¤
+#U+8325 kuÄ« # Character è¥
+U+8326 cè # Character è¦
+#U+8327 jiÇn # Character è§
+U+8328 cà # Character è¨
+#U+8329 gÇu # Character è©
+#U+832a guÄng # Character èª
+U+832b máng # Character è«
+U+832c chà # Character è¬
+#U+832d jiÄo # Character è
+#U+832e jiÄo # Character è®
+U+832f fú # Character è¯
+U+8330 yú # Character è°
+#U+8331 zhÅ« # Character è±
+#U+8332 zÄ« # Character è²
+#U+8333 jiÄng # Character è³
+U+8334 huà # Character è´
+#U+8335 yÄ«n # Character èµ
+U+8336 chá # Character è¶
+U+8337 fá # Character è·
+#U+8338 rÅng # Character è¸
+U+8339 rú # Character è¹
+#U+833a chÅng # Character èº
+#U+833b mÇng # Character è»
+U+833c tóng # Character è¼
+U+833d zhòng # Character è½
+U+833e ? # Character è¾
+U+833f zhú # Character è¿
+U+8340 xún # Character è
+U+8341 huán # Character è
+#U+8342 kuÄ # Character è
+U+8343 quán # Character è
+#U+8344 gÄi # Character è
+#U+8345 dÄ # Character è
+#U+8346 jÄ«ng # Character è
+U+8347 xìng # Character è
+U+8348 quà n # Character è
+#U+8349 cÇo # Character è
+#U+834a jÄ«ng # Character è
+U+834b ér # Character è
+U+834c à n # Character è
+#U+834d shÅu # Character è
+U+834e chà # Character è
+#U+834f rÄn # Character è
+U+8350 jià n # Character è
+U+8351 tà # Character è
+#U+8352 huÄng # Character è
+U+8353 pÃng # Character è
+U+8354 lì # Character è
+#U+8355 jÄ«n # Character è
+#U+8356 lÇo # Character è
+U+8357 shù # Character è
+#U+8358 zhuÄng # Character è
+U+8359 dá # Character è
+U+835a jiá # Character è
+U+835b ráo # Character è
+U+835c bì # Character è
+U+835d zé # Character è
+U+835e qiáo # Character è
+U+835f huì # Character è
+U+8360 qà # Character è
+U+8361 dà ng # Character è¡
+U+8362 ? # Character è¢
+U+8363 róng # Character è£
+#U+8364 hÅ«n # Character è¤
+U+8365 yÃng # Character è¥
+U+8366 luò # Character è¦
+U+8367 yÃng # Character è§
+U+8368 xún # Character è¨
+U+8369 jìn # Character è©
+#U+836a sÅ«n # Character èª
+U+836b yìn # Character è«
+#U+836c mÇi # Character è¬
+U+836d hóng # Character è
+U+836e zhòu # Character è®
+U+836f yà o # Character è¯
+U+8370 dù # Character è°
+#U+8371 wÄi # Character è±
+U+8372 chù # Character è²
+U+8373 dòu # Character è³
+#U+8374 fÅ« # Character è´
+#U+8375 rÄn # Character èµ
+U+8376 yÃn # Character è¶
+U+8377 hé # Character è·
+U+8378 bà # Character è¸
+U+8379 bù # Character è¹
+U+837a yún # Character èº
+U+837b dà # Character è»
+U+837c tú # Character è¼
+#U+837d suÄ« # Character è½
+#U+837e suÄ« # Character è¾
+U+837f chéng # Character è¿
+U+8380 chén # Character è
+U+8381 wú # Character è
+U+8382 bié # Character è
+#U+8383 xÄ« # Character è
+#U+8384 gÄng # Character è
+U+8385 lì # Character è
+#U+8386 fÇ # Character è
+U+8387 zhù # Character è
+U+8388 mò # Character è
+U+8389 lì # Character è
+#U+838a zhuÄng # Character è
+U+838b jà # Character è
+U+838c duó # Character è
+U+838d qiú # Character è
+#U+838e shÄ # Character è
+#U+838f suÅ # Character è
+U+8390 chén # Character è
+#U+8391 fÄng # Character è
+#U+8392 jÇ # Character è
+U+8393 méi # Character è
+U+8394 méng # Character è
+U+8395 xìng # Character è
+#U+8396 jÄ«ng # Character è
+#U+8397 chÄ # Character è
+#U+8398 xÄ«n # Character è
+#U+8399 jÅ«n # Character è
+U+839a yán # Character è
+U+839b tÃng # Character è
+U+839c dià o # Character è
+U+839d cuò # Character è
+#U+839e wÇn # Character è
+U+839f hà n # Character è
+#U+83a0 yÇu # Character è
+U+83a1 cuò # Character è¡
+U+83a2 jiá # Character è¢
+U+83a3 wáng # Character è£
+U+83a4 yóu # Character è¤
+#U+83a5 niÇ # Character è¥
+#U+83a6 shÄo # Character è¦
+U+83a7 xià n # Character è§
+U+83a8 láng # Character è¨
+U+83a9 fú # Character è©
+U+83aa é # Character èª
+U+83ab mò # Character è«
+U+83ac wèn # Character è¬
+U+83ad jié # Character è
+U+83ae nán # Character è®
+U+83af mù # Character è¯
+#U+83b0 kÇn # Character è°
+U+83b1 lái # Character è±
+U+83b2 lián # Character è²
+U+83b3 shà # Character è³
+#U+83b4 wÅ # Character è´
+U+83b5 ? # Character èµ
+#U+83b6 liÇn # Character è¶
+U+83b7 huò # Character è·
+U+83b8 yóu # Character è¸
+U+83b9 yÃng # Character è¹
+#U+83ba yÄ«ng # Character èº
+U+83bb ? # Character è»
+U+83bc chún # Character è¼
+#U+83bd mÇng # Character è½
+#U+83be mÇng # Character è¾
+U+83bf cì # Character è¿
+#U+83c0 wÇn # Character è
+#U+83c1 jÄ«ng # Character è
+#U+83c2 dÄ« # Character è
+U+83c3 qú # Character è
+#U+83c4 dÅng # Character è
+#U+83c5 jiÄn # Character è
+#U+83c6 zÅu # Character è
+U+83c7 gu # Character è
+#U+83c8 lÄ # Character è
+U+83c9 lù # Character è
+U+83ca jú # Character è
+U+83cb wèi # Character è
+#U+83cc jÅ«n # Character è
+U+83cd niè # Character è
+#U+83ce kÅ«n # Character è
+U+83cf hé # Character è
+U+83d0 pú # Character è
+#U+83d1 zÄ« # Character è
+#U+83d2 gÇo # Character è
+#U+83d3 guÇ # Character è
+U+83d4 fú # Character è
+U+83d5 lún # Character è
+#U+83d6 chÄng # Character è
+U+83d7 chóu # Character è
+#U+83d8 sÅng # Character è
+U+83d9 chuà # Character è
+U+83da zhà n # Character è
+U+83db mén # Character è
+U+83dc cà i # Character è
+U+83dd bá # Character è
+U+83de là # Character è
+U+83df tù # Character è
+#U+83e0 bÅ # Character è
+U+83e1 hà n # Character è¡
+U+83e2 bà o # Character è¢
+U+83e3 qìn # Character è£
+#U+83e4 juÇn # Character è¤
+#U+83e5 xÄ« # Character è¥
+U+83e6 qÃn # Character è¦
+#U+83e7 dÇ # Character è§
+#U+83e8 jiÄ # Character è¨
+U+83e9 pú # Character è©
+U+83ea dà ng # Character èª
+#U+83eb jÇn # Character è«
+#U+83ec zhÇo # Character è¬
+U+83ed tái # Character è
+#U+83ee gÄng # Character è®
+U+83ef huá # Character è¯
+#U+83f0 gÅ« # Character è°
+U+83f1 lÃng # Character è±
+#U+83f2 fÄi # Character è²
+#U+83f3 jÄ«n # Character è³
+#U+83f4 Än # Character è´
+#U+83f5 wÇng # Character èµ
+#U+83f6 bÄng # Character è¶
+#U+83f7 zhÇu # Character è·
+#U+83f8 yÄn # Character è¸
+#U+83f9 jÅ« # Character è¹
+#U+83fa jiÄn # Character èº
+#U+83fb lÇn # Character è»
+#U+83fc tÇn # Character è¼
+U+83fd shú # Character è½
+U+83fe tián # Character è¾
+U+83ff dà o # Character è¿
diff --git a/resources/chars/latin1/row84.trans b/resources/chars/latin1/row84.trans
new file mode 100644
index 0000000..f63f8b2
--- /dev/null
+++ b/resources/chars/latin1/row84.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+8400 hÇ # Character è
+U+8401 qà # Character è
+U+8402 hé # Character è
+U+8403 cuì # Character è
+U+8404 táo # Character è
+#U+8405 chÅ«n # Character è
+#U+8406 bÄi # Character è
+U+8407 cháng # Character è
+U+8408 huán # Character è
+U+8409 féi # Character è
+U+840a lái # Character è
+#U+840b qÄ« # Character è
+U+840c méng # Character è
+U+840d pÃng # Character è
+#U+840e wÄi # Character è
+U+840f dà n # Character è
+U+8410 shà # Character è
+U+8411 huán # Character è
+#U+8412 yÇn # Character è
+U+8413 yà # Character è
+U+8414 tiáo # Character è
+U+8415 qà # Character è
+#U+8416 wÇn # Character è
+U+8417 cè # Character è
+U+8418 nà i # Character è
+U+8419 ? # Character è
+U+841a tuò # Character è
+#U+841b jiÅ« # Character è
+#U+841c tiÄ # Character è
+U+841d luó # Character è
+U+841e ? # Character è
+U+841f ? # Character è
+U+8420 méng # Character è
+U+8421 ? # Character è¡
+U+8422 ? # Character è¢
+U+8423 ? # Character è£
+U+8424 yÃng # Character è¤
+U+8425 yÃng # Character è¥
+U+8426 yÃng # Character è¦
+#U+8427 xiÄo # Character è§
+U+8428 sà # Character è¨
+#U+8429 qiÅ« # Character è©
+#U+842a kÄ # Character èª
+U+842b xià ng # Character è«
+U+842c wà n # Character è¬
+#U+842d yÇ # Character è
+U+842e yù # Character è®
+U+842f fù # Character è¯
+U+8430 lià n # Character è°
+#U+8431 xuÄn # Character è±
+U+8432 yuán # Character è²
+U+8433 nán # Character è³
+U+8434 zé # Character è´
+#U+8435 wÅ # Character èµ
+#U+8436 chÇn # Character è¶
+#U+8437 xiÄo # Character è·
+U+8438 yú # Character è¸
+#U+8439 piÄn # Character è¹
+U+843a mà o # Character èº
+#U+843b Än # Character è»
+U+843c è # Character è¼
+U+843d luò # Character è½
+U+843e yÃng # Character è¾
+U+843f huó # Character è¿
+#U+8440 guÄ # Character è
+#U+8441 jiÄng # Character è
+#U+8442 miÇn # Character è
+U+8443 zuó # Character è
+U+8444 zuò # Character è
+#U+8445 jÅ« # Character è
+#U+8446 bÇo # Character è
+U+8447 róu # Character è
+#U+8448 xÇ # Character è
+U+8449 yè # Character è
+#U+844a Än # Character è
+U+844b qú # Character è
+#U+844c jiÄn # Character è
+U+844d fú # Character è
+#U+844e lÇ # Character è
+#U+844f jÄ«ng # Character è
+U+8450 pén # Character è
+#U+8451 fÄng # Character è
+U+8452 hóng # Character è
+U+8453 hóng # Character è
+U+8454 hóu # Character è
+U+8455 yán # Character è
+U+8456 tú # Character è
+U+8457 zhe # Character è
+#U+8458 zÄ« # Character è
+#U+8459 xiÄng # Character è
+U+845a shèn # Character è
+#U+845b gÄ # Character è
+U+845c jié # Character è
+U+845d jìng # Character è
+#U+845e mÇ # Character è
+U+845f huáng # Character è
+#U+8460 shÄn # Character è
+U+8461 pú # Character è¡
+U+8462 gà i # Character è¢
+#U+8463 dÇng # Character è£
+U+8464 zhòu # Character è¤
+U+8465 qián # Character è¥
+#U+8466 wÄi # Character è¦
+U+8467 bó # Character è§
+#U+8468 wÄi # Character è¨
+#U+8469 pÄ # Character è©
+U+846a jì # Character èª
+U+846b hú # Character è«
+U+846c zà ng # Character è¬
+#U+846d jiÄ # Character è
+U+846e duà n # Character è®
+U+846f yà o # Character è¯
+U+8470 jùn # Character è°
+#U+8471 cÅng # Character è±
+U+8472 quán # Character è²
+#U+8473 wÄi # Character è³
+U+8474 xián # Character è´
+U+8475 kuà # Character èµ
+U+8476 tÃng # Character è¶
+#U+8477 hÅ«n # Character è·
+#U+8478 xÇ # Character è¸
+#U+8479 shÄ« # Character è¹
+U+847a qì # Character èº
+U+847b lán # Character è»
+#U+847c zÅng # Character è¼
+#U+847d yÄo # Character è½
+#U+847e yuÄn # Character è¾
+U+847f méi # Character è¿
+#U+8480 yÅ«n # Character è
+U+8481 shù # Character è
+U+8482 dì # Character è
+U+8483 zhuà n # Character è
+#U+8484 guÄn # Character è
+U+8485 ? # Character è
+#U+8486 xuÄ # Character è
+#U+8487 chÇn # Character è
+#U+8488 kÇi # Character è
+U+8489 kuì # Character è
+U+848a ? # Character è
+#U+848b jiÇng # Character è
+U+848c lóu # Character è
+U+848d wéi # Character è
+U+848e pà i # Character è
+U+848f ? # Character è
+#U+8490 sÅu # Character è
+#U+8491 yÄ«n # Character è
+#U+8492 shÄ« # Character è
+U+8493 chún # Character è
+U+8494 shà # Character è
+#U+8495 yÅ«n # Character è
+#U+8496 zhÄn # Character è
+U+8497 là ng # Character è
+U+8498 nú # Character è
+U+8499 méng # Character è
+U+849a hé # Character è
+#U+849b quÄ # Character è
+U+849c suà n # Character è
+U+849d yuán # Character è
+U+849e lì # Character è
+#U+849f jÇ # Character è
+U+84a0 xà # Character è
+U+84a1 páng # Character è¡
+U+84a2 chú # Character è¢
+U+84a3 xú # Character è£
+U+84a4 tú # Character è¤
+U+84a5 liú # Character è¥
+U+84a6 wò # Character è¦
+#U+84a7 zhÄn # Character è§
+U+84a8 qià n # Character è¨
+#U+84a9 zÅ« # Character è©
+U+84aa pò # Character èª
+#U+84ab cuÅ # Character è«
+#U+84ac yuÄn # Character è¬
+U+84ad chú # Character è
+U+84ae yù # Character è®
+#U+84af kuÇi # Character è¯
+U+84b0 pán # Character è°
+U+84b1 pú # Character è±
+U+84b2 pú # Character è²
+U+84b3 nà # Character è³
+U+84b4 shuò # Character è´
+#U+84b5 xÄ« # Character èµ
+U+84b6 fén # Character è¶
+U+84b7 yún # Character è·
+#U+84b8 zhÄng # Character è¸
+#U+84b9 jiÄn # Character è¹
+U+84ba jà # Character èº
+U+84bb ruò # Character è»
+#U+84bc cÄng # Character è¼
+#U+84bd Än # Character è½
+U+84be mà # Character è¾
+#U+84bf hÄo # Character è¿
+#U+84c0 sÅ«n # Character è
+#U+84c1 zhÄn # Character è
+U+84c2 mÃng # Character è
+U+84c3 huò # Character è
+U+84c4 xù # Character è
+U+84c5 liú # Character è
+U+84c6 xà # Character è
+#U+84c7 gÇ # Character è
+U+84c8 láng # Character è
+U+84c9 róng # Character è
+#U+84ca wÄng # Character è
+U+84cb gà i # Character è
+U+84cc cuò # Character è
+#U+84cd shÄ« # Character è
+U+84ce táng # Character è
+#U+84cf luÇ # Character è
+U+84d0 rù # Character è
+#U+84d1 suÅ # Character è
+#U+84d2 xiÄn # Character è
+U+84d3 bèi # Character è
+#U+84d4 yÇo # Character è
+U+84d5 guì # Character è
+#U+84d6 bÄ« # Character è
+#U+84d7 zÇng # Character è
+#U+84d8 gÇn # Character è
+U+84d9 ? # Character è
+#U+84da xiÅ« # Character è
+U+84db cè # Character è
+U+84dc ? # Character è
+U+84dd lán # Character è
+U+84de ? # Character è
+U+84df jì # Character è
+U+84e0 là # Character è
+#U+84e1 cÄn # Character è¡
+U+84e2 láng # Character è¢
+U+84e3 yù # Character è£
+U+84e4 ? # Character è¤
+U+84e5 yìng # Character è¥
+U+84e6 mò # Character è¦
+U+84e7 dià o # Character è§
+#U+84e8 tiÄo # Character è¨
+U+84e9 mà o # Character è©
+#U+84ea tÅng # Character èª
+U+84eb zhú # Character è«
+U+84ec péng # Character è¬
+#U+84ed Än # Character è
+U+84ee lián # Character è®
+#U+84ef cÅng # Character è¯
+#U+84f0 xÇ # Character è°
+U+84f1 pÃng # Character è±
+#U+84f2 qiÅ« # Character è²
+U+84f3 jìn # Character è³
+U+84f4 chún # Character è´
+U+84f5 jié # Character èµ
+#U+84f6 wÄi # Character è¶
+#U+84f7 tuÄ« # Character è·
+U+84f8 cáo # Character è¸
+#U+84f9 yÇ # Character è¹
+U+84fa yì # Character èº
+U+84fb jà # Character è»
+#U+84fc liÇo # Character è¼
+U+84fd bì # Character è½
+#U+84fe lÇ # Character è¾
+U+84ff sù # Character è¿
diff --git a/resources/chars/latin1/row85.trans b/resources/chars/latin1/row85.trans
new file mode 100644
index 0000000..7c7b195
--- /dev/null
+++ b/resources/chars/latin1/row85.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+8500 bù # Character è
+#U+8501 zhÄng # Character è
+U+8502 luó # Character è
+U+8503 jià ng # Character è
+U+8504 mà n # Character è
+U+8505 yán # Character è
+U+8506 lÃng # Character è
+U+8507 jì # Character è
+#U+8508 piÇo # Character è
+#U+8509 gÇn # Character è
+#U+850a hÇn # Character è
+U+850b dà # Character è
+U+850c sù # Character è
+U+850d lù # Character è
+U+850e shè # Character è
+#U+850f shÄng # Character è
+U+8510 dà # Character è
+U+8511 miè # Character è
+#U+8512 xÅ«n # Character è
+U+8513 mà n # Character è
+U+8514 bó # Character è
+U+8515 dì # Character è
+U+8516 cuó # Character è
+U+8517 zhe # Character è
+#U+8518 sÄn # Character è
+U+8519 xuà n # Character è
+U+851a wèi # Character è
+U+851b hú # Character è
+U+851c áo # Character è
+#U+851d mÇ # Character è
+U+851e lóu # Character è
+U+851f cù # Character è
+#U+8520 zhÅng # Character è
+U+8521 cà i # Character è¡
+U+8522 pó # Character è¢
+#U+8523 jiÇng # Character è£
+U+8524 mì # Character è¤
+#U+8525 cÅng # Character è¥
+#U+8526 niÇo # Character è¦
+U+8527 huì # Character è§
+U+8528 jùn # Character è¨
+U+8529 yÃn # Character è©
+U+852a jià n # Character èª
+#U+852b yÄn # Character è«
+#U+852c shÅ« # Character è¬
+U+852d yìn # Character è
+U+852e kuì # Character è®
+U+852f chén # Character è¯
+U+8530 hù # Character è°
+#U+8531 shÄ # Character è±
+U+8532 kòu # Character è²
+U+8533 qià n # Character è³
+U+8534 má # Character è´
+#U+8535 zÄng # Character èµ
+U+8536 ? # Character è¶
+U+8537 qiáng # Character è·
+#U+8538 dÅu # Character è¸
+U+8539 lià n # Character è¹
+U+853a lìn # Character èº
+U+853b kòu # Character è»
+#U+853c Çi # Character è¼
+U+853d bì # Character è½
+U+853e là # Character è¾
+U+853f wéi # Character è¿
+U+8540 jà # Character è
+U+8541 xún # Character è
+U+8542 shèng # Character è
+U+8543 fán # Character è
+U+8544 méng # Character è
+#U+8545 Çu # Character è
+#U+8546 chÇn # Character è
+#U+8547 diÇn # Character è
+U+8548 xùn # Character è
+#U+8549 jiÄo # Character è
+#U+854a ruÇ # Character è
+#U+854b ruÇ # Character è
+#U+854c lÄi # Character è
+U+854d yú # Character è
+U+854e qiáo # Character è
+U+854f chú # Character è
+U+8550 huá # Character è
+#U+8551 jiÄn # Character è
+#U+8552 mÇi # Character è
+U+8553 yún # Character è
+#U+8554 bÄo # Character è
+U+8555 yóu # Character è
+U+8556 qú # Character è
+U+8557 lù # Character è
+U+8558 ráo # Character è
+U+8559 huì # Character è
+U+855a è # Character è
+U+855b téng # Character è
+#U+855c fÄi # Character è
+U+855d jué # Character è
+U+855e zuì # Character è
+U+855f fà # Character è
+U+8560 rú # Character è
+U+8561 fén # Character è¡
+U+8562 kuì # Character è¢
+U+8563 shùn # Character è£
+U+8564 ruà # Character è¤
+#U+8565 yÇ # Character è¥
+#U+8566 xÅ« # Character è¦
+U+8567 fù # Character è§
+U+8568 jué # Character è¨
+U+8569 dà ng # Character è©
+U+856a wú # Character èª
+U+856b tóng # Character è«
+#U+856c sÄ« # Character è¬
+#U+856d xiÄo # Character è
+U+856e xì # Character è®
+U+856f lóng # Character è¯
+U+8570 yùn # Character è°
+U+8571 ? # Character è±
+U+8572 qà # Character è²
+#U+8573 jiÄn # Character è³
+U+8574 yùn # Character è´
+#U+8575 sÅ«n # Character èµ
+U+8576 lÃng # Character è¶
+U+8577 yù # Character è·
+U+8578 xiá # Character è¸
+#U+8579 yÅng # Character è¹
+U+857a jà # Character èº
+U+857b hòng # Character è»
+U+857c sì # Character è¼
+U+857d nóng # Character è½
+#U+857e lÄi # Character è¾
+#U+857f xuÄn # Character è¿
+U+8580 yùn # Character è
+U+8581 yù # Character è
+U+8582 xà # Character è
+U+8583 hà o # Character è
+U+8584 báo # Character è
+#U+8585 hÄo # Character è
+U+8586 Ã i # Character è
+U+8587 wéi # Character è
+U+8588 huì # Character è
+U+8589 wèi # Character è
+U+858a jì # Character è
+#U+858b cÄ« # Character è
+#U+858c xiÄng # Character è
+U+858d luà n # Character è
+U+858e miè # Character è
+U+858f yì # Character è
+U+8590 léng # Character è
+#U+8591 jiÄng # Character è
+U+8592 cà n # Character è
+#U+8593 shÄn # Character è
+U+8594 qiáng # Character è
+U+8595 lián # Character è
+#U+8596 kÄ # Character è
+U+8597 yuán # Character è
+U+8598 dá # Character è
+U+8599 tì # Character è
+U+859a táng # Character è
+#U+859b xiÄ # Character è
+U+859c bì # Character è
+U+859d zhán # Character è
+#U+859e sÅ«n # Character è
+#U+859f liÇn # Character è
+U+85a0 fán # Character è
+#U+85a1 dÇng # Character è¡
+#U+85a2 jiÄ # Character è¢
+#U+85a3 gÇ # Character è£
+U+85a4 xiè # Character è¤
+#U+85a5 shÇ # Character è¥
+U+85a6 jià n # Character è¦
+#U+85a7 kÇo # Character è§
+#U+85a8 hÅng # Character è¨
+U+85a9 sà # Character è©
+#U+85aa xÄ«n # Character èª
+#U+85ab xÅ«n # Character è«
+U+85ac yà o # Character è¬
+U+85ad ? # Character è
+#U+85ae sÇu # Character è®
+#U+85af shÇ # Character è¯
+#U+85b0 xÅ«n # Character è°
+U+85b1 duì # Character è±
+U+85b2 pÃn # Character è²
+#U+85b3 wÄi # Character è³
+U+85b4 néng # Character è´
+U+85b5 chóu # Character èµ
+U+85b6 mái # Character è¶
+U+85b7 rú # Character è·
+#U+85b8 piÄo # Character è¸
+U+85b9 tái # Character è¹
+U+85ba qà # Character èº
+#U+85bb zÇo # Character è»
+U+85bc chén # Character è¼
+#U+85bd zhÄn # Character è½
+#U+85be Är # Character è¾
+#U+85bf nÇ # Character è¿
+U+85c0 yÃng # Character è
+#U+85c1 gÇo # Character è
+U+85c2 còng # Character è
+#U+85c3 xiÄo # Character è
+U+85c4 qà # Character è
+U+85c5 fá # Character è
+#U+85c6 jiÇn # Character è
+U+85c7 xù # Character è
+#U+85c8 kuÄ« # Character è
+U+85c9 jiè # Character è
+#U+85ca biÇn # Character è
+U+85cb dià o # Character è
+U+85cc mì # Character è
+U+85cd lán # Character è
+U+85ce jìn # Character è
+U+85cf cáng # Character è
+#U+85d0 miÇo # Character è
+U+85d1 qióng # Character è
+U+85d2 qiè # Character è
+#U+85d3 xiÇn # Character è
+U+85d4 ? # Character è
+#U+85d5 Çu # Character è
+U+85d6 xián # Character è
+U+85d7 sù # Character è
+#U+85d8 lÇ # Character è
+U+85d9 yì # Character è
+U+85da xù # Character è
+#U+85db xiÄ # Character è
+U+85dc là # Character è
+U+85dd yì # Character è
+#U+85de lÇ # Character è
+#U+85df lÄi # Character è
+U+85e0 xià o # Character è
+U+85e1 dà # Character è¡
+#U+85e2 zhÇ # Character è¢
+#U+85e3 bÄi # Character è£
+U+85e4 téng # Character è¤
+U+85e5 yà o # Character è¥
+U+85e6 mò # Character è¦
+#U+85e7 huÇn # Character è§
+#U+85e8 piÇo # Character è¨
+U+85e9 fán # Character è©
+#U+85ea sÇu # Character èª
+U+85eb tán # Character è«
+#U+85ec tuÄ« # Character è¬
+U+85ed qióng # Character è
+U+85ee qiáo # Character è®
+U+85ef wèi # Character è¯
+U+85f0 liú # Character è°
+U+85f1 huì # Character è±
+U+85f2 ? # Character è²
+#U+85f3 gÇo # Character è³
+U+85f4 yùn # Character è´
+U+85f5 ? # Character èµ
+U+85f6 lì # Character è¶
+#U+85f7 shÇ # Character è·
+U+85f8 chú # Character è¸
+#U+85f9 Çi # Character è¹
+U+85fa lìn # Character èº
+#U+85fb zÇo # Character è»
+#U+85fc xuÄn # Character è¼
+U+85fd chèn # Character è½
+U+85fe là i # Character è¾
+U+85ff huò # Character è¿
diff --git a/resources/chars/latin1/row86.trans b/resources/chars/latin1/row86.trans
new file mode 100644
index 0000000..3e28ffe
--- /dev/null
+++ b/resources/chars/latin1/row86.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+8600 tuò # Character è
+U+8601 wù # Character è
+#U+8602 ruÇ # Character è
+#U+8603 ruÇ # Character è
+U+8604 qà # Character è
+U+8605 héng # Character è
+U+8606 lú # Character è
+#U+8607 sÅ« # Character è
+U+8608 tuà # Character è
+U+8609 máng # Character è
+U+860a yùn # Character è
+U+860b pÃng # Character è
+#U+860c yÇ # Character è
+#U+860d xÅ«n # Character è
+U+860e jì # Character è
+#U+860f jiÅng # Character è
+#U+8610 xiÄn # Character è
+U+8611 mó # Character è
+U+8612 ? # Character è
+#U+8613 sÅ« # Character è
+#U+8614 jiÅng # Character è
+U+8615 ? # Character è
+U+8616 niè # Character è
+U+8617 bò # Character è
+U+8618 ráng # Character è
+U+8619 yì # Character è
+#U+861a xiÇn # Character è
+U+861b yú # Character è
+U+861c jú # Character è
+U+861d lià n # Character è
+U+861e lià n # Character è
+#U+861f yÇn # Character è
+U+8620 qiáng # Character è
+#U+8621 yÄ«ng # Character è¡
+U+8622 lóng # Character è¢
+U+8623 tòng # Character è£
+#U+8624 wÄi # Character è¤
+U+8625 yuè # Character è¥
+U+8626 lÃng # Character è¦
+U+8627 qú # Character è§
+U+8628 yáo # Character è¨
+U+8629 fán # Character è©
+U+862a mà # Character èª
+U+862b lán # Character è«
+#U+862c kuÄ« # Character è¬
+U+862d lán # Character è
+U+862e jì # Character è®
+U+862f dà ng # Character è¯
+U+8630 ? # Character è°
+U+8631 lèi # Character è±
+U+8632 léi # Character è²
+#U+8633 huÇ # Character è³
+#U+8634 fÄng # Character è´
+U+8635 zhà # Character èµ
+U+8636 wèi # Character è¶
+U+8637 kuà # Character è·
+U+8638 zhà n # Character è¸
+U+8639 huà i # Character è¹
+U+863a là # Character èº
+U+863b jì # Character è»
+U+863c mà # Character è¼
+#U+863d lÄi # Character è½
+U+863e huà i # Character è¾
+U+863f luó # Character è¿
+#U+8640 jÄ« # Character è
+U+8641 kuà # Character è
+U+8642 lù # Character è
+#U+8643 jiÄn # Character è
+U+8644 ? # Character è
+U+8645 ? # Character è
+U+8646 léi # Character è
+#U+8647 quÇn # Character è
+#U+8648 xiÄo # Character è
+U+8649 yì # Character è
+U+864a luán # Character è
+U+864b mén # Character è
+#U+864c biÄ # Character è
+#U+864d hÅ« # Character è
+#U+864e hÇ # Character è
+#U+864f lÇ # Character è
+U+8650 nüè # Character è
+#U+8651 lÇ # Character è
+#U+8652 sÄ« # Character è
+#U+8653 xiÄo # Character è
+U+8654 qián # Character è
+U+8655 chù # Character è
+#U+8656 hÅ« # Character è
+#U+8657 xÅ« # Character è
+U+8658 cuó # Character è
+U+8659 fú # Character è
+#U+865a xÅ« # Character è
+#U+865b xÅ« # Character è
+#U+865c lÇ # Character è
+#U+865d hÇ # Character è
+U+865e yú # Character è
+U+865f hà o # Character è
+#U+8660 jiÇo # Character è
+U+8661 jù # Character è¡
+U+8662 guó # Character è¢
+U+8663 bà o # Character è£
+U+8664 yán # Character è¤
+U+8665 zhà n # Character è¥
+U+8666 zhà n # Character è¦
+#U+8667 kuÄ« # Character è§
+#U+8668 bÄn # Character è¨
+U+8669 xì # Character è©
+U+866a shú # Character èª
+U+866b chóng # Character è«
+U+866c qiú # Character è¬
+#U+866d diÄo # Character è
+#U+866e jÄ« # Character è®
+U+866f qiú # Character è¯
+U+8670 chéng # Character è°
+#U+8671 shÄ« # Character è±
+U+8672 ? # Character è²
+U+8673 dì # Character è³
+U+8674 zhé # Character è´
+U+8675 shé # Character èµ
+#U+8676 yÅ« # Character è¶
+#U+8677 gÄn # Character è·
+#U+8678 zÇ # Character è¸
+U+8679 hóng # Character è¹
+#U+867a huÇ # Character èº
+U+867b méng # Character è»
+U+867c gè # Character è¼
+#U+867d suÄ« # Character è½
+#U+867e xiÄ # Character è¾
+U+867f chà i # Character è¿
+U+8680 shà # Character è
+#U+8681 yÇ # Character è
+#U+8682 mÇ # Character è
+U+8683 xià ng # Character è
+#U+8684 fÄng # Character è
+U+8685 è # Character è
+#U+8686 pÄ # Character è
+#U+8687 chÇ # Character è
+#U+8688 qiÄn # Character è
+U+8689 wén # Character è
+U+868a wén # Character è
+U+868b ruì # Character è
+U+868c bà ng # Character è
+#U+868d bÇ # Character è
+U+868e yuè # Character è
+U+868f yuè # Character è
+#U+8690 jÅ«n # Character è
+U+8691 qà # Character è
+U+8692 tóng # Character è
+#U+8693 yÇn # Character è
+U+8694 qà # Character è
+U+8695 cán # Character è
+U+8696 yuán # Character è
+U+8697 jué # Character è
+U+8698 huà # Character è
+U+8699 qÃn # Character è
+U+869a qà # Character è
+U+869b zhòng # Character è
+U+869c yá # Character è
+U+869d cì # Character è
+U+869e mù # Character è
+U+869f wáng # Character è
+U+86a0 fén # Character è
+U+86a1 fén # Character è¡
+U+86a2 háng # Character è¢
+U+86a3 gong # Character è£
+#U+86a4 zÇo # Character è¤
+#U+86a5 fÇ # Character è¥
+U+86a6 rán # Character è¦
+U+86a7 jiè # Character è§
+U+86a8 fú # Character è¨
+#U+86a9 chÄ« # Character è©
+#U+86aa dÇu # Character èª
+U+86ab piáo # Character è«
+U+86ac xià n # Character è¬
+U+86ad nà # Character è
+U+86ae tè # Character è®
+#U+86af qiÅ« # Character è¯
+U+86b0 yóu # Character è°
+U+86b1 zhà # Character è±
+U+86b2 pÃng # Character è²
+U+86b3 chà # Character è³
+#U+86b4 yÇu # Character è´
+U+86b5 hé # Character èµ
+#U+86b6 hÄn # Character è¶
+U+86b7 jù # Character è·
+U+86b8 lì # Character è¸
+U+86b9 fù # Character è¹
+U+86ba rán # Character èº
+U+86bb zhá # Character è»
+#U+86bc gÇu # Character è¼
+U+86bd pà # Character è½
+#U+86be bÇ # Character è¾
+U+86bf xián # Character è¿
+U+86c0 zhù # Character è
+#U+86c1 diÄo # Character è
+#U+86c2 biÄ # Character è
+#U+86c3 bÇng # Character è
+#U+86c4 gÅ« # Character è
+U+86c5 rán # Character è
+#U+86c6 qÅ« # Character è
+U+86c7 shé # Character è
+U+86c8 tiè # Character è
+U+86c9 lÃng # Character è
+#U+86ca gÇ # Character è
+U+86cb dà n # Character è
+#U+86cc gÇ # Character è
+U+86cd yÃng # Character è
+U+86ce lì # Character è
+#U+86cf chÄng # Character è
+#U+86d0 qÅ« # Character è
+U+86d1 móu # Character è
+U+86d2 gé # Character è
+U+86d3 cì # Character è
+U+86d4 huà # Character è
+U+86d5 huà # Character è
+U+86d6 máng # Character è
+U+86d7 fù # Character è
+U+86d8 yáng # Character è
+#U+86d9 wÄ # Character è
+U+86da liè # Character è
+#U+86db zhÅ« # Character è
+#U+86dc yÄ« # Character è
+U+86dd xián # Character è
+U+86de kuò # Character è
+#U+86df jiÄo # Character è
+U+86e0 lì # Character è
+U+86e1 yì # Character è¡
+U+86e2 pÃng # Character è¢
+#U+86e3 jÄ« # Character è£
+U+86e4 há # Character è¤
+U+86e5 shé # Character è¥
+U+86e6 yà # Character è¦
+#U+86e7 wÇng # Character è§
+U+86e8 mò # Character è¨
+U+86e9 qióng # Character è©
+U+86ea qiè # Character èª
+#U+86eb guÇ # Character è«
+#U+86ec gÇng # Character è¬
+U+86ed zhì # Character è
+U+86ee mán # Character è®
+U+86ef ? # Character è¯
+U+86f0 zhà # Character è°
+U+86f1 jiá # Character è±
+U+86f2 ráo # Character è²
+#U+86f3 sÄ« # Character è³
+U+86f4 qà # Character è´
+#U+86f5 xÄ«ng # Character èµ
+U+86f6 liè # Character è¶
+U+86f7 qiú # Character è·
+#U+86f8 shÄo # Character è¸
+#U+86f9 yÇng # Character è¹
+U+86fa jiá # Character èº
+U+86fb shuì # Character è»
+#U+86fc chÄ # Character è¼
+U+86fd bà i # Character è½
+U+86fe é # Character è¾
+U+86ff hà n # Character è¿
diff --git a/resources/chars/latin1/row87.trans b/resources/chars/latin1/row87.trans
new file mode 100644
index 0000000..14b4a91
--- /dev/null
+++ b/resources/chars/latin1/row87.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+8700 shÇ # Character è
+U+8701 xuán # Character è
+#U+8702 fÄng # Character è
+U+8703 shèn # Character è
+U+8704 zhèn # Character è
+#U+8705 fÇ # Character è
+U+8706 xià n # Character è
+U+8707 zhé # Character è
+U+8708 wú # Character è
+U+8709 fú # Character è
+U+870a là # Character è
+U+870b láng # Character è
+U+870c bì # Character è
+U+870d chú # Character è
+#U+870e yuÄn # Character è
+#U+870f yÇu # Character è
+U+8710 jié # Character è
+U+8711 dà n # Character è
+U+8712 yán # Character è
+U+8713 tÃng # Character è
+U+8714 dià n # Character è
+U+8715 shuì # Character è
+U+8716 huà # Character è
+#U+8717 wÅ # Character è
+#U+8718 zhÄ« # Character è
+#U+8719 sÅng # Character è
+#U+871a fÄi # Character è
+#U+871b jÅ« # Character è
+U+871c mì # Character è
+U+871d qà # Character è
+U+871e qà # Character è
+U+871f yù # Character è
+#U+8720 jÇn # Character è
+U+8721 là # Character è¡
+#U+8722 mÄng # Character è¢
+#U+8723 qiÄng # Character è£
+#U+8724 sÄ« # Character è¤
+#U+8725 xÄ« # Character è¥
+U+8726 lún # Character è¦
+U+8727 lì # Character è§
+U+8728 dié # Character è¨
+U+8729 tiáo # Character è©
+#U+872a tÄo # Character èª
+#U+872b kÅ«n # Character è«
+#U+872c gÄn # Character è¬
+U+872d hà n # Character è
+U+872e yù # Character è®
+U+872f bà ng # Character è¯
+U+8730 féi # Character è°
+U+8731 pà # Character è±
+#U+8732 wÄi # Character è²
+#U+8733 dÅ«n # Character è³
+U+8734 yì # Character è´
+#U+8735 yuÄn # Character èµ
+U+8736 sù # Character è¶
+U+8737 quán # Character è·
+#U+8738 qiÇn # Character è¸
+U+8739 ruì # Character è¹
+U+873a nà # Character èº
+#U+873b qÄ«ng # Character è»
+U+873c wèi # Character è¼
+#U+873d liÇng # Character è½
+#U+873e guÇ # Character è¾
+#U+873f wÄn # Character è¿
+#U+8740 dÅng # Character è
+U+8741 è # Character è
+#U+8742 bÇn # Character è
+U+8743 dì # Character è
+#U+8744 wÇng # Character è
+U+8745 cán # Character è
+#U+8746 yÇng # Character è
+U+8747 ying # Character è
+#U+8748 guÅ # Character è
+U+8749 chán # Character è
+U+874a ? # Character è
+U+874b là # Character è
+#U+874c kÄ # Character è
+U+874d jà # Character è
+U+874e hé # Character è
+U+874f tÃng # Character è
+U+8750 mà i # Character è
+#U+8751 xÅ« # Character è
+U+8752 mián # Character è
+U+8753 yú # Character è
+#U+8754 jiÄ # Character è
+U+8755 shà # Character è
+#U+8756 xuÄn # Character è
+U+8757 huáng # Character è
+#U+8758 yÇn # Character è
+#U+8759 biÄn # Character è
+U+875a róu # Character è
+#U+875b wÄi # Character è
+U+875c fù # Character è
+U+875d yuán # Character è
+U+875e mèi # Character è
+U+875f wei # Character è
+U+8760 fú # Character è
+#U+8761 ruÇn # Character è¡
+U+8762 xié # Character è¢
+U+8763 yóu # Character è£
+U+8764 qiú # Character è¤
+U+8765 máo # Character è¥
+#U+8766 xiÄ # Character è¦
+#U+8767 yÄ«ng # Character è§
+#U+8768 shÄ« # Character è¨
+U+8769 chóng # Character è©
+#U+876a tÄng # Character èª
+#U+876b zhÅ« # Character è«
+#U+876c zÅng # Character è¬
+U+876d tà # Character è
+U+876e fù # Character è®
+U+876f yuán # Character è¯
+#U+8770 huÇ # Character è°
+U+8771 méng # Character è±
+U+8772 là # Character è²
+U+8773 dú # Character è³
+U+8774 hú # Character è´
+#U+8775 qiÅ« # Character èµ
+U+8776 dié # Character è¶
+U+8777 lì # Character è·
+#U+8778 wÅ # Character è¸
+#U+8779 yÅ«n # Character è¹
+#U+877a jÇ # Character èº
+#U+877b nÇn # Character è»
+U+877c lóu # Character è¼
+#U+877d qÇn # Character è½
+U+877e róng # Character è¾
+U+877f yÃng # Character è¿
+#U+8780 jiÄng # Character è
+U+8781 ? # Character è
+U+8782 láng # Character è
+U+8783 páng # Character è
+#U+8784 sÄ« # Character è
+#U+8785 xÄ« # Character è
+U+8786 cì # Character è
+#U+8787 xÄ« # Character è
+U+8788 yuán # Character è
+#U+8789 wÄng # Character è
+U+878a lián # Character è
+#U+878b sÅu # Character è
+#U+878c bÄn # Character è
+U+878d róng # Character è
+U+878e róng # Character è
+U+878f jà # Character è
+#U+8790 wÅ« # Character è
+U+8791 qiù # Character è
+U+8792 hà n # Character è
+U+8793 qÃn # Character è
+U+8794 yà # Character è
+#U+8795 bÄ« # Character è
+U+8796 huá # Character è
+U+8797 táng # Character è
+#U+8798 yÇ # Character è
+U+8799 dù # Character è
+U+879a nà i # Character è
+U+879b hé # Character è
+U+879c hú # Character è
+U+879d huì # Character è
+#U+879e mÇ # Character è
+U+879f mÃng # Character è
+U+87a0 yì # Character è
+U+87a1 wén # Character è¡
+U+87a2 yÃng # Character è¢
+U+87a3 téng # Character è£
+#U+87a4 yÇ # Character è¤
+#U+87a5 cÄng # Character è¥
+U+87a6 ? # Character è¦
+U+87a7 ? # Character è§
+#U+87a8 mÇn # Character è¨
+U+87a9 ? # Character è©
+#U+87aa shÄng # Character èª
+#U+87ab zhÄ # Character è«
+U+87ac cáo # Character è¬
+#U+87ad chÄ« # Character è
+U+87ae dì # Character è®
+U+87af áo # Character è¯
+U+87b0 lù # Character è°
+U+87b1 wèi # Character è±
+U+87b2 zhì # Character è²
+U+87b3 táng # Character è³
+U+87b4 chén # Character è´
+#U+87b5 piÄo # Character èµ
+U+87b6 qú # Character è¶
+U+87b7 pà # Character è·
+U+87b8 yú # Character è¸
+U+87b9 jià n # Character è¹
+U+87ba luó # Character èº
+U+87bb lóu # Character è»
+#U+87bc qÇn # Character è¼
+#U+87bd zhÅng # Character è½
+#U+87be yÇn # Character è¾
+#U+87bf jiÄng # Character è¿
+U+87c0 shuà i # Character è
+U+87c1 wén # Character è
+#U+87c2 jiÄo # Character è
+U+87c3 wà n # Character è
+U+87c4 zhà # Character è
+U+87c5 zhè # Character è
+U+87c6 ma # Character è
+U+87c7 má # Character è
+#U+87c8 guÅ # Character è
+U+87c9 liú # Character è
+U+87ca máo # Character è
+#U+87cb xÄ« # Character è
+#U+87cc cÅng # Character è
+U+87cd là # Character è
+#U+87ce mÇn # Character è
+#U+87cf xiÄo # Character è
+U+87d0 ? # Character è
+#U+87d1 zhÄng # Character è
+#U+87d2 mÇng # Character è
+U+87d3 xià ng # Character è
+U+87d4 mò # Character è
+#U+87d5 zuÄ« # Character è
+#U+87d6 sÄ« # Character è
+#U+87d7 qiÅ« # Character è
+U+87d8 tè # Character è
+U+87d9 zhà # Character è
+U+87da péng # Character è
+U+87db péng # Character è
+#U+87dc jiÇo # Character è
+U+87dd qú # Character è
+U+87de bié # Character è
+U+87df liáo # Character è
+U+87e0 pán # Character è
+#U+87e1 guÇ # Character è¡
+#U+87e2 xÇ # Character è¢
+#U+87e3 jÇ # Character è£
+#U+87e4 zhuÄn # Character è¤
+U+87e5 huáng # Character è¥
+U+87e6 fèi # Character è¦
+U+87e7 láo # Character è§
+U+87e8 jué # Character è¨
+U+87e9 jué # Character è©
+U+87ea huì # Character èª
+U+87eb yÃn # Character è«
+U+87ec chán # Character è¬
+#U+87ed jiÄo # Character è
+U+87ee shà n # Character è®
+U+87ef ráo # Character è¯
+#U+87f0 xiÄo # Character è°
+U+87f1 móu # Character è±
+U+87f2 chóng # Character è²
+U+87f3 xún # Character è³
+#U+87f4 sÄ« # Character è´
+U+87f5 ? # Character èµ
+#U+87f6 chÄng # Character è¶
+#U+87f7 dÄng # Character è·
+#U+87f8 lÇ # Character è¸
+U+87f9 xiè # Character è¹
+U+87fa shà n # Character èº
+#U+87fb yÇ # Character è»
+#U+87fc jÇng # Character è¼
+U+87fd dá # Character è½
+U+87fe chán # Character è¾
+U+87ff qì # Character è¿
diff --git a/resources/chars/latin1/row88.trans b/resources/chars/latin1/row88.trans
new file mode 100644
index 0000000..d8c5652
--- /dev/null
+++ b/resources/chars/latin1/row88.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+8800 cÄ« # Character è
+U+8801 xià ng # Character è
+U+8802 shè # Character è
+#U+8803 luÇ # Character è
+U+8804 qÃn # Character è
+U+8805 ying # Character è
+U+8806 chà i # Character è
+U+8807 lì # Character è
+U+8808 zé # Character è
+#U+8809 xuÄn # Character è
+U+880a lián # Character è
+U+880b zhú # Character è
+U+880c zé # Character è
+#U+880d xiÄ # Character è
+#U+880e mÇng # Character è
+U+880f xiè # Character è
+U+8810 qà # Character è
+U+8811 róng # Character è
+#U+8812 jiÇn # Character è
+#U+8813 mÄng # Character è
+U+8814 háo # Character è
+U+8815 rú # Character è
+U+8816 huò # Character è
+U+8817 zhuó # Character è
+U+8818 jié # Character è
+#U+8819 bÄ«n # Character è
+U+881a hè # Character è
+U+881b miè # Character è
+U+881c fán # Character è
+U+881d léi # Character è
+U+881e jié # Character è
+U+881f là # Character è
+U+8820 mì # Character è
+#U+8821 lÇ # Character è ¡
+#U+8822 chÇn # Character è ¢
+U+8823 lì # Character è £
+#U+8824 qiÅ« # Character è ¤
+U+8825 niè # Character è ¥
+U+8826 lú # Character è ¦
+U+8827 dù # Character è §
+#U+8828 xiÄo # Character è ¨
+#U+8829 zhÅ« # Character è ©
+U+882a lóng # Character è ª
+U+882b lì # Character è «
+U+882c lóng # Character è ¬
+#U+882d fÄng # Character è
+#U+882e yÄ # Character è ®
+U+882f bèng # Character è ¯
+U+8830 shà ng # Character è °
+#U+8831 gÇ # Character è ±
+#U+8832 juÄn # Character è ²
+#U+8833 yÄ«ng # Character è ³
+U+8834 ? # Character è ´
+#U+8835 xÄ« # Character è µ
+U+8836 cán # Character è ¶
+U+8837 qú # Character è ·
+U+8838 quán # Character è ¸
+U+8839 dù # Character è ¹
+U+883a cán # Character è º
+U+883b mán # Character è »
+U+883c jué # Character è ¼
+U+883d jié # Character è ½
+U+883e zhú # Character è ¾
+U+883f zhá # Character è ¿
+U+8840 xuè # Character è¡
+#U+8841 huÄng # Character è¡
+U+8842 niù # Character è¡
+#U+8843 pÄi # Character è¡
+#U+8844 nÇ # Character è¡
+U+8845 xìn # Character è¡
+U+8846 zhòng # Character è¡
+U+8847 mò # Character è¡
+U+8848 èr # Character è¡
+U+8849 kè # Character è¡
+U+884a miè # Character è¡
+U+884b xì # Character è¡
+U+884c xÃng # Character è¡
+#U+884d yÇn # Character è¡
+U+884e kà n # Character è¡
+U+884f yuà n # Character è¡
+U+8850 ? # Character è¡
+U+8851 lÃng # Character è¡
+U+8852 xuà n # Character è¡
+U+8853 shù # Character è¡
+U+8854 xián # Character è¡
+U+8855 tòng # Character è¡
+U+8856 lòng # Character è¡
+#U+8857 jiÄ # Character è¡
+U+8858 xián # Character è¡
+U+8859 yá # Character è¡
+U+885a hú # Character è¡
+U+885b wèi # Character è¡
+U+885c dà o # Character è¡
+#U+885d chÅng # Character è¡
+U+885e wèi # Character è¡
+U+885f dà o # Character è¡
+#U+8860 zhÅ«n # Character è¡
+U+8861 héng # Character 衡
+U+8862 qú # Character 衢
+#U+8863 yī # Character 衣
+U+8864 ? # Character 衤
+#U+8865 bÇ # Character è¡¥
+#U+8866 gÇn # Character 衦
+U+8867 yú # Character 衧
+#U+8868 biÇo # Character 表
+U+8869 chà # Character 衩
+#U+886a yÇ # Character 衪
+#U+886b shÄn # Character è¡«
+U+886c chèn # Character 衬
+#U+886d fÅ« # Character è¡
+#U+886e gÇn # Character è¡®
+#U+886f fÄn # Character 衯
+#U+8870 shuÄi # Character è¡°
+U+8871 jié # Character 衱
+U+8872 nà # Character 衲
+#U+8873 zhÅng # Character 衳
+#U+8874 dÇn # Character è¡´
+U+8875 rì # Character 衵
+U+8876 zhòng # Character 衶
+#U+8877 zhÅng # Character è¡·
+U+8878 xiè # Character 衸
+U+8879 qà # Character 衹
+U+887a xié # Character 衺
+U+887b rán # Character 衻
+#U+887c zhī # Character 衼
+U+887d rèn # Character 衽
+#U+887e qīn # Character 衾
+#U+887f jīn # Character 衿
+#U+8880 jÅ«n # Character è¢
+U+8881 yuán # Character è¢
+U+8882 mèi # Character è¢
+U+8883 chà i # Character è¢
+#U+8884 Ço # Character è¢
+#U+8885 niÇo # Character è¢
+#U+8886 huÄ« # Character è¢
+U+8887 rán # Character è¢
+#U+8888 jiÄ # Character è¢
+U+8889 tuó # Character è¢
+#U+888a lÇng # Character è¢
+U+888b dà i # Character è¢
+U+888c bà o # Character è¢
+U+888d páo # Character è¢
+U+888e yà o # Character è¢
+U+888f zuò # Character è¢
+U+8890 bì # Character è¢
+U+8891 shà o # Character è¢
+#U+8892 tÇn # Character è¢
+#U+8893 jÇ # Character è¢
+U+8894 hè # Character è¢
+U+8895 shù # Character è¢
+U+8896 xiù # Character è¢
+#U+8897 zhÄn # Character è¢
+U+8898 yà # Character è¢
+U+8899 pà # Character è¢
+#U+889a bÅ # Character è¢
+#U+889b dÄ« # Character è¢
+U+889c wà # Character è¢
+U+889d fù # Character è¢
+#U+889e gÇn # Character è¢
+U+889f zhì # Character è¢
+U+88a0 zhì # Character è¢
+U+88a1 rán # Character 袡
+U+88a2 pà n # Character 袢
+U+88a3 yì # Character 袣
+U+88a4 mà o # Character 袤
+U+88a5 ? # Character 袥
+U+88a6 nà # Character 袦
+#U+88a7 kÅu # Character 袧
+U+88a8 xià n # Character 袨
+#U+88a9 chÄn # Character 袩
+#U+88aa qū # Character 袪
+U+88ab bèi # Character 被
+#U+88ac gÇn # Character 袬
+U+88ad xà # Character è¢
+U+88ae ? # Character 袮
+U+88af bó # Character 袯
+U+88b0 ? # Character 袰
+U+88b1 fu # Character 袱
+U+88b2 yà # Character 袲
+#U+88b3 chÇ # Character 袳
+U+88b4 kù # Character 袴
+U+88b5 rèn # Character 袵
+U+88b6 jià ng # Character 袶
+U+88b7 jiá # Character 袷
+U+88b8 cún # Character 袸
+U+88b9 mò # Character 袹
+U+88ba jié # Character 袺
+U+88bb ér # Character 袻
+U+88bc luò # Character 袼
+U+88bd rú # Character 袽
+#U+88be zhū # Character 袾
+#U+88bf guī # Character 袿
+#U+88c0 yÄ«n # Character è£
+U+88c1 cái # Character è£
+U+88c2 liè # Character è£
+U+88c3 ? # Character è£
+U+88c4 ? # Character è£
+#U+88c5 zhuÄng # Character è£
+#U+88c6 dÄng # Character è£
+U+88c7 ? # Character è£
+#U+88c8 kÅ«n # Character è£
+U+88c9 kèn # Character è£
+#U+88ca niÇo # Character è£
+U+88cb shù # Character è£
+U+88cc jiá # Character è£
+#U+88cd kÇn # Character è£
+U+88ce chéng # Character è£
+#U+88cf lÇ # Character è£
+#U+88d0 juÄn # Character è£
+#U+88d1 shÄn # Character è£
+U+88d2 póu # Character è£
+U+88d3 gé # Character è£
+U+88d4 yì # Character è£
+U+88d5 yù # Character è£
+#U+88d6 zhÄn # Character è£
+U+88d7 liú # Character è£
+U+88d8 qiú # Character è£
+U+88d9 qún # Character è£
+U+88da jì # Character è£
+U+88db yì # Character è£
+#U+88dc bÇ # Character è£
+#U+88dd zhuÄng # Character è£
+U+88de shuì # Character è£
+#U+88df shÄ # Character è£
+U+88e0 qún # Character è£
+U+88e1 li # Character 裡
+U+88e2 lián # Character 裢
+U+88e3 lià n # Character 裣
+U+88e4 kù # Character 裤
+#U+88e5 jiÇn # Character 裥
+U+88e6 fóu # Character 裦
+#U+88e7 chÄn # Character 裧
+U+88e8 bì # Character 裨
+#U+88e9 gūn # Character 裩
+U+88ea táo # Character 裪
+U+88eb yuà n # Character 裫
+U+88ec lÃng # Character 裬
+#U+88ed chÇ # Character è£
+#U+88ee chÄng # Character 裮
+U+88ef chóu # Character 裯
+U+88f0 duó # Character 裰
+#U+88f1 biÇo # Character 裱
+#U+88f2 liÇng # Character 裲
+U+88f3 shang # Character 裳
+U+88f4 péi # Character 裴
+U+88f5 péi # Character 裵
+#U+88f6 fÄi # Character 裶
+#U+88f7 yuÄn # Character 裷
+#U+88f8 luÇ # Character 裸
+#U+88f9 guÇ # Character 裹
+#U+88fa yÇn # Character 裺
+#U+88fb dÇ # Character 裻
+U+88fc xà # Character 裼
+U+88fd zhì # Character 製
+#U+88fe jū # Character 裾
+#U+88ff qÇ # Character 裿
diff --git a/resources/chars/latin1/row89.trans b/resources/chars/latin1/row89.trans
new file mode 100644
index 0000000..ca4f8f7
--- /dev/null
+++ b/resources/chars/latin1/row89.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+8900 jì # Character è¤
+U+8901 zhà # Character è¤
+U+8902 guà # Character è¤
+U+8903 kèn # Character è¤
+U+8904 ? # Character è¤
+U+8905 tì # Character è¤
+U+8906 tà # Character è¤
+U+8907 fù # Character è¤
+U+8908 chóng # Character è¤
+#U+8909 xiÄ # Character è¤
+#U+890a biÇn # Character è¤
+U+890b dié # Character è¤
+#U+890c kÅ«n # Character è¤
+#U+890d duÄn # Character è¤
+U+890e xiù # Character è¤
+U+890f xiù # Character è¤
+U+8910 hè # Character è¤
+U+8911 yuà n # Character è¤
+#U+8912 bÄo # Character è¤
+#U+8913 bÇo # Character è¤
+U+8914 fù # Character è¤
+U+8915 yú # Character è¤
+U+8916 tuà n # Character è¤
+#U+8917 yÇn # Character è¤
+#U+8918 huÄ« # Character è¤
+U+8919 bèi # Character è¤
+#U+891a chÇ # Character è¤
+#U+891b lÇ # Character è¤
+U+891c ? # Character è¤
+U+891d ? # Character è¤
+#U+891e yÇn # Character è¤
+U+891f dá # Character è¤
+#U+8920 gÅu # Character è¤
+#U+8921 dÄ # Character 褡
+U+8922 huái # Character 褢
+U+8923 róng # Character 褣
+U+8924 yuà n # Character 褤
+U+8925 rù # Character 褥
+U+8926 nà i # Character 褦
+#U+8927 jiÇng # Character 褧
+#U+8928 suÇ # Character 褨
+#U+8929 bÄn # Character 褩
+U+892a tùn # Character 褪
+#U+892b chÇ # Character 褫
+#U+892c sÇng # Character 褬
+#U+892d niÇo # Character è¤
+#U+892e yīng # Character 褮
+U+892f jiè # Character 褯
+#U+8930 qiÄn # Character 褰
+U+8931 huái # Character 褱
+U+8932 kù # Character 褲
+U+8933 lián # Character 褳
+#U+8934 bÇo # Character 褴
+U+8935 là # Character 褵
+U+8936 zhé # Character 褶
+#U+8937 shī # Character 褷
+#U+8938 lÇ # Character 褸
+U+8939 yì # Character 褹
+U+893a dié # Character 褺
+U+893b xiè # Character 褻
+#U+893c xiÄn # Character 褼
+U+893d wèi # Character 褽
+#U+893e biÇo # Character 褾
+U+893f cáo # Character 褿
+#U+8940 jÄ« # Character è¥
+#U+8941 jiÇng # Character è¥
+#U+8942 sÄn # Character è¥
+#U+8943 bÄo # Character è¥
+#U+8944 xiÄng # Character è¥
+U+8945 ? # Character è¥
+U+8946 pú # Character è¥
+#U+8947 jiÇn # Character è¥
+U+8948 zhuà n # Character è¥
+U+8949 jià n # Character è¥
+U+894a zuì # Character è¥
+U+894b jà # Character è¥
+#U+894c dÄn # Character è¥
+U+894d zá # Character è¥
+U+894e fán # Character è¥
+U+894f bó # Character è¥
+U+8950 xià ng # Character è¥
+U+8951 xÃn # Character è¥
+U+8952 bié # Character è¥
+U+8953 ráo # Character è¥
+#U+8954 mÇn # Character è¥
+U+8955 lán # Character è¥
+#U+8956 Ço # Character è¥
+U+8957 duó # Character è¥
+U+8958 guì # Character è¥
+U+8959 cà o # Character è¥
+U+895a suì # Character è¥
+U+895b nóng # Character è¥
+#U+895c chÄn # Character è¥
+U+895d lià n # Character è¥
+U+895e bì # Character è¥
+#U+895f jÄ«n # Character è¥
+#U+8960 dÄng # Character è¥
+U+8961 shú # Character 襡
+#U+8962 tÇn # Character 襢
+U+8963 bì # Character 襣
+U+8964 lán # Character 襤
+U+8965 pú # Character 襥
+U+8966 rú # Character 襦
+#U+8967 zhÇ # Character 襧
+U+8968 ? # Character 襨
+#U+8969 shÇ # Character 襩
+U+896a wà # Character 襪
+U+896b shì # Character 襫
+#U+896c bÇi # Character 襬
+U+896d xié # Character è¥
+U+896e bó # Character 襮
+U+896f chèn # Character 襯
+U+8970 là i # Character 襰
+U+8971 lóng # Character 襱
+U+8972 xà # Character 襲
+#U+8973 xiÄn # Character 襳
+U+8974 lán # Character 襴
+U+8975 zhé # Character 襵
+U+8976 dà i # Character 襶
+U+8977 ? # Character 襷
+U+8978 zà n # Character 襸
+#U+8979 shī # Character 襹
+#U+897a jiÇn # Character 襺
+U+897b pà n # Character 襻
+U+897c yì # Character 襼
+U+897d ? # Character 襽
+U+897e yà # Character 襾
+U+897f xi # Character 西
+#U+8980 xÄ« # Character è¦
+U+8981 yà o # Character è¦
+#U+8982 fÄng # Character è¦
+U+8983 tán # Character è¦
+U+8984 ? # Character è¦
+U+8985 bià o # Character è¦
+U+8986 fù # Character è¦
+U+8987 bà # Character è¦
+U+8988 hé # Character è¦
+#U+8989 jÄ« # Character è¦
+#U+898a jÄ« # Character è¦
+U+898b jià n # Character è¦
+#U+898c guÄn # Character è¦
+U+898d bià n # Character è¦
+U+898e yà n # Character è¦
+#U+898f guÄ« # Character è¦
+U+8990 jué # Character è¦
+#U+8991 piÇn # Character è¦
+U+8992 máo # Character è¦
+U+8993 mì # Character è¦
+U+8994 mì # Character è¦
+U+8995 miè # Character è¦
+U+8996 shì # Character è¦
+#U+8997 sÄ« # Character è¦
+#U+8998 zhÄn # Character è¦
+U+8999 luó # Character è¦
+U+899a jué # Character è¦
+U+899b mì # Character è¦
+U+899c tià o # Character è¦
+U+899d lián # Character è¦
+U+899e yà o # Character è¦
+U+899f zhì # Character è¦
+#U+89a0 jÅ«n # Character è¦
+U+89a1 xà # Character 覡
+#U+89a2 shÇn # Character 覢
+#U+89a3 wÄi # Character 覣
+U+89a4 xì # Character 覤
+#U+89a5 tiÇn # Character 覥
+U+89a6 yú # Character 覦
+#U+89a7 lÇn # Character 覧
+U+89a8 è # Character 覨
+#U+89a9 dÇ # Character 覩
+#U+89aa qīn # Character 親
+#U+89ab pÇng # Character 覫
+U+89ac jì # Character 覬
+U+89ad mÃng # Character è¦
+U+89ae yÃng # Character 覮
+U+89af gòu # Character 覯
+U+89b0 qù # Character 覰
+U+89b1 zhà n # Character 覱
+#U+89b2 jÇn # Character 覲
+#U+89b3 guÄn # Character 観
+#U+89b4 dÄng # Character 覴
+U+89b5 jià n # Character 覵
+U+89b6 luó # Character 覶
+U+89b7 qù # Character 覷
+U+89b8 jià n # Character 覸
+U+89b9 wéi # Character 覹
+U+89ba jué # Character 覺
+U+89bb qù # Character 覻
+U+89bc luó # Character 覼
+#U+89bd lÇn # Character 覽
+#U+89be shÄn # Character 覾
+U+89bf dà # Character 覿
+#U+89c0 guÄn # Character è§
+U+89c1 jià n # Character è§
+#U+89c2 guÄn # Character è§
+U+89c3 yà n # Character è§
+#U+89c4 guÄ« # Character è§
+U+89c5 mì # Character è§
+U+89c6 shì # Character è§
+#U+89c7 zhÄn # Character è§
+#U+89c8 lÇn # Character è§
+U+89c9 jué # Character è§
+U+89ca jì # Character è§
+U+89cb xà # Character è§
+U+89cc dà # Character è§
+#U+89cd tiÇn # Character è§
+U+89ce yú # Character è§
+U+89cf gòu # Character è§
+#U+89d0 jÇn # Character è§
+U+89d1 qù # Character è§
+#U+89d2 jiÇo # Character è§
+#U+89d3 jiÅ« # Character è§
+#U+89d4 jÄ«n # Character è§
+#U+89d5 cÅ« # Character è§
+U+89d6 jué # Character è§
+U+89d7 zhì # Character è§
+U+89d8 chà o # Character è§
+U+89d9 jà # Character è§
+#U+89da gÅ« # Character è§
+U+89db dà n # Character è§
+#U+89dc zuÇ # Character è§
+#U+89dd dÇ # Character è§
+#U+89de shÄng # Character è§
+U+89df huà # Character è§
+U+89e0 quán # Character è§
+U+89e1 gé # Character 觡
+U+89e2 chì # Character 觢
+#U+89e3 jiÄ # Character 解
+#U+89e4 guÇ # Character 觤
+#U+89e5 gÅng # Character 觥
+U+89e6 chù # Character 触
+#U+89e7 jiÄ # Character 觧
+U+89e8 hùn # Character 觨
+U+89e9 qiú # Character 觩
+#U+89ea xīng # Character 觪
+U+89eb sù # Character 觫
+U+89ec nà # Character 觬
+#U+89ed jÄ« # Character è§
+U+89ee lù # Character 觮
+U+89ef zhì # Character 觯
+#U+89f0 zhÄ # Character 觰
+U+89f1 bì # Character 觱
+#U+89f2 xīng # Character 觲
+U+89f3 hú # Character 觳
+#U+89f4 shÄng # Character 觴
+#U+89f5 gÅng # Character 觵
+U+89f6 zhì # Character 觶
+U+89f7 xué # Character 觷
+U+89f8 chù # Character 觸
+#U+89f9 xī # Character 觹
+U+89fa yà # Character 觺
+U+89fb lù # Character 觻
+U+89fc jué # Character 觼
+#U+89fd xī # Character 觽
+U+89fe yà n # Character 觾
+#U+89ff xī # Character 觿
diff --git a/resources/chars/latin1/row8a.trans b/resources/chars/latin1/row8a.trans
new file mode 100644
index 0000000..92e017b
--- /dev/null
+++ b/resources/chars/latin1/row8a.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+8a00 yán # Character è¨
+U+8a01 ? # Character è¨
+U+8a02 dìng # Character è¨
+U+8a03 fù # Character è¨
+U+8a04 qiú # Character è¨
+U+8a05 qiú # Character è¨
+U+8a06 jià o # Character è¨
+#U+8a07 hÅng # Character è¨
+U+8a08 jì # Character è¨
+U+8a09 fà n # Character è¨
+U+8a0a xùn # Character è¨
+U+8a0b dià o # Character è¨
+U+8a0c hóng # Character è¨
+U+8a0d chà # Character è¨
+#U+8a0e tÇo # Character è¨
+#U+8a0f xÅ« # Character è¨
+U+8a10 jié # Character è¨
+U+8a11 yà # Character è¨
+U+8a12 rèn # Character è¨
+U+8a13 xun # Character è¨
+U+8a14 yÃn # Character è¨
+U+8a15 shà n # Character è¨
+U+8a16 qì # Character è¨
+#U+8a17 tuÅ # Character è¨
+U+8a18 jì # Character è¨
+U+8a19 xùn # Character è¨
+U+8a1a yÃn # Character è¨
+U+8a1b é # Character è¨
+#U+8a1c fÄn # Character è¨
+U+8a1d yà # Character è¨
+#U+8a1e yÄo # Character è¨
+U+8a1f sòng # Character è¨
+#U+8a20 shÄn # Character è¨
+U+8a21 yÃn # Character 訡
+#U+8a22 xīn # Character 訢
+U+8a23 jué # Character 訣
+U+8a24 xiáo # Character 訤
+U+8a25 nè # Character 訥
+U+8a26 chén # Character 訦
+U+8a27 yóu # Character 訧
+#U+8a28 zhÇ # Character 訨
+#U+8a29 xiÅng # Character 訩
+#U+8a2a fÇng # Character 訪
+U+8a2b xìn # Character 訫
+#U+8a2c chÄo # Character 訬
+U+8a2d shè # Character è¨
+#U+8a2e xiÄn # Character 訮
+#U+8a2f shÇ # Character 訯
+U+8a30 tún # Character 訰
+#U+8a31 xÇ # Character 許
+U+8a32 yì # Character 訲
+U+8a33 yì # Character 訳
+U+8a34 su # Character 訴
+#U+8a35 chī # Character 訵
+#U+8a36 hÄ # Character 訶
+#U+8a37 shÄn # Character 訷
+U+8a38 hé # Character 訸
+U+8a39 xù # Character 訹
+#U+8a3a zhÄn # Character 診
+U+8a3b zhù # Character 註
+U+8a3c zhèng # Character 証
+U+8a3d gòu # Character 訽
+#U+8a3e zÇ # Character 訾
+#U+8a3f zÇ # Character 訿
+#U+8a40 zhÄn # Character è©
+#U+8a41 gÇ # Character è©
+U+8a42 fù # Character è©
+#U+8a43 quÇn # Character è©
+U+8a44 dié # Character è©
+U+8a45 lÃng # Character è©
+#U+8a46 dÇ # Character è©
+U+8a47 yà ng # Character è©
+U+8a48 lì # Character è©
+U+8a49 náo # Character è©
+U+8a4a pà n # Character è©
+U+8a4b zhòu # Character è©
+U+8a4c gà n # Character è©
+U+8a4d yì # Character è©
+U+8a4e jù # Character è©
+U+8a4f à o # Character è©
+U+8a50 zhà # Character è©
+U+8a51 tuó # Character è©
+U+8a52 yà # Character è©
+#U+8a53 qÇ # Character è©
+U+8a54 zhà o # Character è©
+U+8a55 pÃng # Character è©
+U+8a56 bì # Character è©
+U+8a57 xiòng # Character è©
+U+8a58 qù # Character è©
+U+8a59 bá # Character è©
+U+8a5a dá # Character è©
+#U+8a5b zÇ # Character è©
+#U+8a5c tÄo # Character è©
+#U+8a5d zhÇ # Character è©
+U+8a5e cà # Character è©
+U+8a5f zhé # Character è©
+#U+8a60 yÇng # Character è©
+#U+8a61 xÇ # Character è©¡
+U+8a62 xún # Character 詢
+U+8a63 yì # Character 詣
+#U+8a64 huÇng # Character 詤
+U+8a65 hé # Character 詥
+U+8a66 shì # Character 試
+U+8a67 chá # Character 詧
+#U+8a68 jiÄo # Character 詨
+#U+8a69 shī # Character 詩
+#U+8a6a hÄn # Character 詪
+U+8a6b chà # Character 詫
+U+8a6c gòu # Character 詬
+#U+8a6d guÇ # Character è©
+U+8a6e quán # Character 詮
+U+8a6f huì # Character 詯
+U+8a70 jié # Character 詰
+U+8a71 huà # Character 話
+#U+8a72 gÄi # Character 該
+U+8a73 xiáng # Character 詳
+#U+8a74 wÄi # Character è©´
+#U+8a75 shÄn # Character 詵
+U+8a76 chóu # Character 詶
+U+8a77 tóng # Character 詷
+U+8a78 mà # Character 詸
+#U+8a79 zhÄn # Character 詹
+U+8a7a mìng # Character 詺
+U+8a7b è # Character 詻
+#U+8a7c huī # Character 詼
+U+8a7d yán # Character 詽
+#U+8a7e xiÅng # Character 詾
+U+8a7f guà # Character 詿
+U+8a80 èr # Character èª
+#U+8a81 bÄng # Character èª
+#U+8a82 tiÇo # Character èª
+#U+8a83 chÇ # Character èª
+#U+8a84 lÄi # Character èª
+#U+8a85 zhÅ« # Character èª
+#U+8a86 kuÄng # Character èª
+#U+8a87 kuÄ # Character èª
+U+8a88 wú # Character èª
+U+8a89 yù # Character èª
+U+8a8a téng # Character èª
+U+8a8b jì # Character èª
+U+8a8c zhì # Character èª
+U+8a8d rèn # Character èª
+U+8a8e sù # Character èª
+#U+8a8f lÇng # Character èª
+U+8a90 é # Character èª
+U+8a91 kuáng # Character èª
+U+8a92 éi # Character èª
+U+8a93 shì # Character èª
+#U+8a94 tÇng # Character èª
+U+8a95 dà n # Character èª
+U+8a96 bó # Character èª
+U+8a97 chán # Character èª
+U+8a98 yòu # Character èª
+U+8a99 héng # Character èª
+U+8a9a qià o # Character èª
+#U+8a9b qÄ«n # Character èª
+U+8a9c shuà # Character èª
+#U+8a9d Än # Character èª
+#U+8a9e yÇ # Character èª
+U+8a9f xià o # Character èª
+U+8aa0 chéng # Character èª
+U+8aa1 jiè # Character 誡
+U+8aa2 xià n # Character 誢
+#U+8aa3 wū # Character 誣
+U+8aa4 wù # Character 誤
+U+8aa5 gà o # Character 誥
+U+8aa6 sòng # Character 誦
+#U+8aa7 pÇ # Character 誧
+U+8aa8 huì # Character 誨
+U+8aa9 jìng # Character 誩
+#U+8aaa shuŠ# Character 說
+U+8aab zhèn # Character 誫
+#U+8aac shuŠ# Character 説
+U+8aad dú # Character èª
+U+8aae ? # Character 誮
+U+8aaf chà ng # Character 誯
+U+8ab0 shuà # Character 誰
+U+8ab1 jié # Character 誱
+U+8ab2 kè # Character 課
+#U+8ab3 qū # Character 誳
+U+8ab4 cóng # Character 誴
+U+8ab5 xiáo # Character 誵
+U+8ab6 suì # Character 誶
+#U+8ab7 wÇng # Character 誷
+U+8ab8 xuán # Character 誸
+#U+8ab9 fÄi # Character 誹
+#U+8aba chī # Character 誺
+U+8abb tà # Character 誻
+U+8abc yì # Character 誼
+U+8abd ná # Character 誽
+U+8abe yÃn # Character 誾
+U+8abf dià o # Character 調
+#U+8ac0 pÇ # Character è«
+U+8ac1 chuò # Character è«
+#U+8ac2 chÇn # Character è«
+#U+8ac3 chÄn # Character è«
+#U+8ac4 zhÅ«n # Character è«
+#U+8ac5 jÄ« # Character è«
+#U+8ac6 qÄ« # Character è«
+U+8ac7 tán # Character è«
+U+8ac8 zhuì # Character è«
+#U+8ac9 wÄi # Character è«
+U+8aca jú # Character è«
+#U+8acb qÇng # Character è«
+U+8acc jià n # Character è«
+#U+8acd zhÄng # Character è«
+U+8ace zé # Character è«
+#U+8acf zÅu # Character è«
+#U+8ad0 qiÄn # Character è«
+U+8ad1 zhuó # Character è«
+U+8ad2 lià ng # Character è«
+U+8ad3 jià n # Character è«
+U+8ad4 zhù # Character è«
+U+8ad5 háo # Character è«
+U+8ad6 lùn # Character è«
+#U+8ad7 shÄn # Character è«
+#U+8ad8 biÇo # Character è«
+U+8ad9 huà i # Character è«
+U+8ada pián # Character è«
+U+8adb yú # Character è«
+U+8adc dié # Character è«
+#U+8add xÇ # Character è«
+U+8ade pián # Character è«
+U+8adf shì # Character è«
+#U+8ae0 xuÄn # Character è«
+U+8ae1 shì # Character 諡
+U+8ae2 hùn # Character 諢
+U+8ae3 huà # Character 諣
+U+8ae4 è # Character 諤
+U+8ae5 zhòng # Character 諥
+U+8ae6 dì # Character 諦
+U+8ae7 xié # Character 諧
+U+8ae8 fú # Character 諨
+#U+8ae9 pÇ # Character è«©
+U+8aea tÃng # Character 諪
+U+8aeb jià n # Character 諫
+#U+8aec qÇ # Character 諬
+U+8aed yù # Character è«
+#U+8aee zī # Character 諮
+U+8aef chuán # Character 諯
+#U+8af0 xÇ # Character è«°
+U+8af1 huì # Character 諱
+#U+8af2 yīn # Character 諲
+#U+8af3 Än # Character 諳
+U+8af4 xián # Character 諴
+U+8af5 nán # Character 諵
+U+8af6 chén # Character 諶
+#U+8af7 fÄng # Character è«·
+#U+8af8 zhū # Character 諸
+U+8af9 yáng # Character 諹
+U+8afa yà n # Character 諺
+#U+8afb hÄng # Character è«»
+#U+8afc xuÄn # Character 諼
+U+8afd gé # Character 諽
+U+8afe nuò # Character 諾
+U+8aff qì # Character 諿
diff --git a/resources/chars/latin1/row8b.trans b/resources/chars/latin1/row8b.trans
new file mode 100644
index 0000000..2b2a3bb
--- /dev/null
+++ b/resources/chars/latin1/row8b.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+8b00 móu # Character è¬
+U+8b01 yè # Character è¬
+U+8b02 wèi # Character è¬
+U+8b03 ? # Character è¬
+U+8b04 téng # Character è¬
+#U+8b05 zÅu # Character è¬
+U+8b06 shà n # Character è¬
+#U+8b07 jiÇn # Character è¬
+U+8b08 bó # Character è¬
+U+8b09 ? # Character è¬
+#U+8b0a huÇng # Character è¬
+U+8b0b huò # Character è¬
+#U+8b0c gÄ # Character è¬
+U+8b0d yÃng # Character è¬
+U+8b0e mà # Character è¬
+#U+8b0f xiÇo # Character è¬
+U+8b10 mì # Character è¬
+U+8b11 xì # Character è¬
+#U+8b12 qiÄng # Character è¬
+#U+8b13 chÄn # Character è¬
+U+8b14 nüè # Character è¬
+U+8b15 tà # Character è¬
+U+8b16 sù # Character è¬
+U+8b17 bà ng # Character è¬
+U+8b18 chà # Character è¬
+#U+8b19 qiÄn # Character è¬
+U+8b1a shì # Character è¬
+#U+8b1b jiÇng # Character è¬
+U+8b1c yuà n # Character è¬
+U+8b1d xiè # Character è¬
+U+8b1e xuè # Character è¬
+#U+8b1f tÄo # Character è¬
+U+8b20 yáo # Character è¬
+U+8b21 yáo # Character 謡
+U+8b22 ? # Character 謢
+U+8b23 yú # Character 謣
+#U+8b24 biÄo # Character 謤
+U+8b25 còng # Character 謥
+U+8b26 qìng # Character 謦
+U+8b27 là # Character 謧
+U+8b28 mó # Character 謨
+U+8b29 mò # Character 謩
+#U+8b2a shÄng # Character 謪
+U+8b2b zhé # Character 謫
+U+8b2c miù # Character 謬
+#U+8b2d jiÇn # Character è¬
+U+8b2e zé # Character 謮
+#U+8b2f jiÄ # Character 謯
+U+8b30 lián # Character 謰
+U+8b31 lóu # Character 謱
+#U+8b32 cÄn # Character 謲
+#U+8b33 Åu # Character 謳
+U+8b34 guà n # Character 謴
+U+8b35 xà # Character 謵
+U+8b36 zhuó # Character 謶
+U+8b37 áo # Character 謷
+U+8b38 áo # Character 謸
+#U+8b39 jÇn # Character 謹
+U+8b3a zhé # Character 謺
+U+8b3b yà # Character 謻
+U+8b3c hù # Character 謼
+U+8b3d jià ng # Character 謽
+U+8b3e mán # Character 謾
+U+8b3f cháo # Character 謿
+U+8b40 hà n # Character è
+U+8b41 huá # Character è
+#U+8b42 chÇn # Character è
+#U+8b43 xÅ« # Character è
+#U+8b44 zÄng # Character è
+U+8b45 sè # Character è
+#U+8b46 xÄ« # Character è
+#U+8b47 shÄ # Character è
+U+8b48 duì # Character è
+U+8b49 zhèng # Character è
+U+8b4a náo # Character è
+U+8b4b lán # Character è
+U+8b4c é # Character è
+U+8b4d yìng # Character è
+U+8b4e jué # Character è
+#U+8b4f jÄ« # Character è
+#U+8b50 zÇn # Character è
+#U+8b51 jiÇo # Character è
+U+8b52 bò # Character è
+U+8b53 huì # Character è
+U+8b54 zhuà n # Character è
+U+8b55 mú # Character è
+U+8b56 zèn # Character è
+U+8b57 zhá # Character è
+U+8b58 shi # Character è
+U+8b59 qiáo # Character è
+U+8b5a tán # Character è
+U+8b5b zèn # Character è
+#U+8b5c pÇ # Character è
+U+8b5d shéng # Character è
+#U+8b5e xuÄn # Character è
+U+8b5f zà o # Character è
+#U+8b60 tÄn # Character è
+#U+8b61 dÇng # Character è¡
+U+8b62 suì # Character è¢
+#U+8b63 qiÄn # Character è£
+#U+8b64 jÄ« # Character è¤
+U+8b65 jià o # Character è¥
+#U+8b66 jÇng # Character è¦
+U+8b67 lián # Character è§
+U+8b68 nóu # Character è¨
+#U+8b69 yÄ« # Character è©
+U+8b6a à i # Character èª
+#U+8b6b zhÄn # Character è«
+U+8b6c pì # Character è¬
+#U+8b6d huÇ # Character è
+U+8b6e huà # Character è®
+U+8b6f yì # Character è¯
+U+8b70 yì # Character è°
+U+8b71 shà n # Character è±
+U+8b72 rà ng # Character è²
+U+8b73 nòu # Character è³
+#U+8b74 qiÇn # Character è´
+U+8b75 zhuì # Character èµ
+U+8b76 tà # Character è¶
+U+8b77 hù # Character è·
+#U+8b78 zhÅu # Character è¸
+U+8b79 háo # Character è¹
+U+8b7a yè # Character èº
+#U+8b7b yÄ«ng # Character è»
+U+8b7c jià n # Character è¼
+U+8b7d yù # Character è½
+#U+8b7e jiÇn # Character è¾
+U+8b7f huì # Character è¿
+U+8b80 dú # Character è®
+U+8b81 zhé # Character è®
+U+8b82 xuà n # Character è®
+U+8b83 zà n # Character è®
+#U+8b84 lÄi # Character è®
+#U+8b85 shÄn # Character è®
+U+8b86 wèi # Character è®
+#U+8b87 chÇn # Character è®
+U+8b88 lì # Character è®
+U+8b89 yà # Character è®
+U+8b8a bià n # Character è®
+U+8b8b zhé # Character è®
+U+8b8c yà n # Character è®
+U+8b8d è # Character è®
+U+8b8e chóu # Character è®
+U+8b8f wèi # Character è®
+U+8b90 chóu # Character è®
+U+8b91 yà o # Character è®
+U+8b92 chán # Character è®
+U+8b93 rà ng # Character è®
+#U+8b94 yÇn # Character è®
+U+8b95 lán # Character è®
+U+8b96 chèn # Character è®
+U+8b97 huò # Character è®
+U+8b98 zhé # Character è®
+#U+8b99 huÄn # Character è®
+U+8b9a zà n # Character è®
+U+8b9b yì # Character è®
+#U+8b9c dÇng # Character è®
+#U+8b9d zhÄn # Character è®
+U+8b9e yà n # Character è®
+U+8b9f dú # Character è®
+U+8ba0 yán # Character è®
+U+8ba1 jì # Character 计
+U+8ba2 dìng # Character 订
+U+8ba3 fù # Character 讣
+U+8ba4 rèn # Character 认
+#U+8ba5 jī # Character 讥
+U+8ba6 jié # Character 讦
+U+8ba7 hóng # Character 讧
+#U+8ba8 tÇo # Character 讨
+U+8ba9 rà ng # Character 让
+U+8baa shà n # Character 讪
+U+8bab qì # Character 讫
+#U+8bac tuŠ# Character 讬
+U+8bad xun # Character è®
+U+8bae yì # Character 议
+U+8baf xùn # Character 讯
+U+8bb0 jì # Character 记
+U+8bb1 rèn # Character 讱
+#U+8bb2 jiÇng # Character 讲
+U+8bb3 huì # Character 讳
+#U+8bb4 Åu # Character è®´
+U+8bb5 jù # Character 讵
+U+8bb6 yà # Character 讶
+U+8bb7 nè # Character 讷
+#U+8bb8 xÇ # Character 许
+U+8bb9 é # Character 讹
+U+8bba lùn # Character 论
+#U+8bbb xiÅng # Character è®»
+U+8bbc sòng # Character 讼
+#U+8bbd fÄng # Character 讽
+U+8bbe shè # Character 设
+#U+8bbf fÇng # Character 访
+U+8bc0 jué # Character è¯
+U+8bc1 zhèng # Character è¯
+#U+8bc2 gÇ # Character è¯
+#U+8bc3 hÄ # Character è¯
+U+8bc4 pÃng # Character è¯
+#U+8bc5 zÇ # Character è¯
+U+8bc6 shi # Character è¯
+U+8bc7 xiòng # Character è¯
+U+8bc8 zhà # Character è¯
+U+8bc9 su # Character è¯
+#U+8bca zhÄn # Character è¯
+#U+8bcb dÇ # Character è¯
+#U+8bcc zÅu # Character è¯
+U+8bcd cà # Character è¯
+U+8bce qù # Character è¯
+U+8bcf zhà o # Character è¯
+U+8bd0 bì # Character è¯
+U+8bd1 yì # Character è¯
+U+8bd2 yà # Character è¯
+#U+8bd3 kuÄng # Character è¯
+#U+8bd4 lÄi # Character è¯
+U+8bd5 shì # Character è¯
+U+8bd6 guà # Character è¯
+#U+8bd7 shÄ« # Character è¯
+U+8bd8 jié # Character è¯
+#U+8bd9 huÄ« # Character è¯
+U+8bda chéng # Character è¯
+#U+8bdb zhÅ« # Character è¯
+#U+8bdc shÄn # Character è¯
+U+8bdd huà # Character è¯
+U+8bde dà n # Character è¯
+U+8bdf gòu # Character è¯
+U+8be0 quán # Character è¯
+#U+8be1 guÇ # Character 诡
+U+8be2 xún # Character 询
+U+8be3 yì # Character 诣
+#U+8be4 zhÄng # Character 诤
+#U+8be5 gÄi # Character 该
+U+8be6 xiáng # Character 详
+U+8be7 chà # Character 诧
+U+8be8 hùn # Character 诨
+#U+8be9 xÇ # Character 诩
+#U+8bea zhÅu # Character 诪
+U+8beb jiè # Character 诫
+#U+8bec wū # Character 诬
+#U+8bed yÇ # Character è¯
+U+8bee qià o # Character 诮
+U+8bef wù # Character 误
+U+8bf0 gà o # Character 诰
+U+8bf1 yòu # Character 诱
+U+8bf2 huì # Character 诲
+U+8bf3 kuáng # Character 诳
+#U+8bf4 shuŠ# Character 说
+U+8bf5 sòng # Character 诵
+U+8bf6 éi # Character 诶
+#U+8bf7 qÇng # Character 请
+#U+8bf8 zhū # Character 诸
+#U+8bf9 zÅu # Character 诹
+U+8bfa nuò # Character 诺
+U+8bfb dú # Character 读
+U+8bfc zhuó # Character 诼
+#U+8bfd fÄi # Character 诽
+U+8bfe kè # Character 课
+#U+8bff wÄi # Character 诿
diff --git a/resources/chars/latin1/row8c.trans b/resources/chars/latin1/row8c.trans
new file mode 100644
index 0000000..74acc95
--- /dev/null
+++ b/resources/chars/latin1/row8c.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+8c00 yú # Character è°
+U+8c01 shuà # Character è°
+#U+8c02 shÄn # Character è°
+U+8c03 dià o # Character è°
+#U+8c04 chÇn # Character è°
+U+8c05 lià ng # Character è°
+#U+8c06 zhÅ«n # Character è°
+U+8c07 suì # Character è°
+U+8c08 tán # Character è°
+#U+8c09 shÄn # Character è°
+U+8c0a yì # Character è°
+U+8c0b móu # Character è°
+U+8c0c chén # Character è°
+U+8c0d dié # Character è°
+#U+8c0e huÇng # Character è°
+U+8c0f jià n # Character è°
+U+8c10 xié # Character è°
+U+8c11 nüè # Character è°
+U+8c12 yè # Character è°
+U+8c13 wèi # Character è°
+U+8c14 è # Character è°
+U+8c15 yù # Character è°
+#U+8c16 xuÄn # Character è°
+U+8c17 chán # Character è°
+#U+8c18 zÄ« # Character è°
+#U+8c19 Än # Character è°
+U+8c1a yà n # Character è°
+U+8c1b dì # Character è°
+U+8c1c mà # Character è°
+U+8c1d pián # Character è°
+#U+8c1e xÇ # Character è°
+U+8c1f mó # Character è°
+#U+8c20 dÇng # Character è°
+U+8c21 sù # Character 谡
+U+8c22 xiè # Character 谢
+U+8c23 yáo # Character 谣
+U+8c24 bà ng # Character 谤
+U+8c25 shì # Character 谥
+#U+8c26 qiÄn # Character è°¦
+U+8c27 mì # Character 谧
+#U+8c28 jÇn # Character è°¨
+U+8c29 mán # Character 谩
+U+8c2a zhé # Character 谪
+#U+8c2b jiÇn # Character è°«
+U+8c2c miù # Character 谬
+U+8c2d tán # Character è°
+U+8c2e zèn # Character 谮
+U+8c2f qiáo # Character 谯
+U+8c30 lán # Character 谰
+#U+8c31 pÇ # Character è°±
+U+8c32 jué # Character 谲
+U+8c33 yà n # Character 谳
+#U+8c34 qiÇn # Character è°´
+#U+8c35 zhÄn # Character è°µ
+U+8c36 chèn # Character 谶
+#U+8c37 gÇ # Character è°·
+#U+8c38 qiÄn # Character è°¸
+U+8c39 hóng # Character 谹
+#U+8c3a xiÄ # Character è°º
+U+8c3b jué # Character 谻
+U+8c3c hóng # Character 谼
+#U+8c3d hÄn # Character è°½
+#U+8c3e hÅng # Character è°¾
+#U+8c3f xī # Character 谿
+#U+8c40 xÄ« # Character è±
+#U+8c41 huÅ # Character è±
+U+8c42 liáo # Character è±
+#U+8c43 hÇn # Character è±
+U+8c44 dú # Character è±
+U+8c45 lóng # Character è±
+U+8c46 dòu # Character è±
+#U+8c47 jiÄng # Character è±
+#U+8c48 qÇ # Character è±
+U+8c49 shì # Character è±
+#U+8c4a lÇ # Character è±
+#U+8c4b dÄng # Character è±
+#U+8c4c wÄn # Character è±
+#U+8c4d bÄ« # Character è±
+U+8c4e shù # Character è±
+U+8c4f xià n # Character è±
+#U+8c50 fÄng # Character è±
+U+8c51 zhì # Character è±
+U+8c52 zhì # Character è±
+U+8c53 yà n # Character è±
+U+8c54 yà n # Character è±
+#U+8c55 shÇ # Character è±
+U+8c56 chù # Character è±
+#U+8c57 huÄ« # Character è±
+U+8c58 tún # Character è±
+U+8c59 yì # Character è±
+U+8c5a tún # Character è±
+U+8c5b yì # Character è±
+#U+8c5c jiÄn # Character è±
+#U+8c5d bÄ # Character è±
+U+8c5e hòu # Character è±
+U+8c5f è # Character è±
+U+8c60 cú # Character è±
+U+8c61 xià ng # Character 象
+U+8c62 huà n # Character 豢
+#U+8c63 jiÄn # Character è±£
+#U+8c64 kÄn # Character 豤
+#U+8c65 gÄi # Character è±¥
+U+8c66 qú # Character 豦
+#U+8c67 fū # Character 豧
+#U+8c68 xī # Character 豨
+#U+8c69 bīn # Character 豩
+U+8c6a háo # Character 豪
+U+8c6b yù # Character 豫
+#U+8c6c zhū # Character 豬
+#U+8c6d jiÄ # Character è±
+U+8c6e fén # Character 豮
+#U+8c6f xī # Character 豯
+U+8c70 bó # Character 豰
+#U+8c71 wÄn # Character è±±
+U+8c72 huán # Character 豲
+#U+8c73 bīn # Character 豳
+U+8c74 dà # Character 豴
+#U+8c75 zÅng # Character è±µ
+U+8c76 fén # Character 豶
+U+8c77 yì # Character 豷
+U+8c78 zhì # Character 豸
+U+8c79 bà o # Character 豹
+U+8c7a chái # Character 豺
+U+8c7b hà n # Character 豻
+U+8c7c pà # Character 豼
+U+8c7d nà # Character 豽
+#U+8c7e pī # Character 豾
+#U+8c7f gÇu # Character 豿
+U+8c80 nà # Character è²
+U+8c81 yòu # Character è²
+#U+8c82 diÄo # Character è²
+U+8c83 mò # Character è²
+U+8c84 sì # Character è²
+#U+8c85 xiÅ« # Character è²
+U+8c86 huán # Character è²
+#U+8c87 kÅ«n # Character è²
+U+8c88 hé # Character è²
+U+8c89 hé # Character è²
+U+8c8a mò # Character è²
+U+8c8b hà n # Character è²
+U+8c8c mà o # Character è²
+U+8c8d là # Character è²
+U+8c8e nà # Character è²
+#U+8c8f bÇ # Character è²
+#U+8c90 yÇ # Character è²
+#U+8c91 jiÄ # Character è²
+#U+8c92 tuÄn # Character è²
+#U+8c93 mÄo # Character è²
+U+8c94 pà # Character è²
+#U+8c95 xÄ« # Character è²
+U+8c96 è # Character è²
+U+8c97 jù # Character è²
+U+8c98 mò # Character è²
+#U+8c99 chÅ« # Character è²
+U+8c9a tán # Character è²
+#U+8c9b huÄn # Character è²
+U+8c9c jué # Character è²
+U+8c9d bèi # Character è²
+#U+8c9e zhÄn # Character è²
+U+8c9f yuán # Character è²
+U+8ca0 fù # Character è²
+U+8ca1 cái # Character 財
+U+8ca2 gòng # Character 貢
+U+8ca3 tè # Character 貣
+U+8ca4 yà # Character 貤
+U+8ca5 háng # Character 貥
+U+8ca6 wà n # Character 貦
+U+8ca7 pÃn # Character 貧
+U+8ca8 huò # Character 貨
+U+8ca9 fà n # Character 販
+#U+8caa tÄn # Character 貪
+U+8cab guà n # Character 貫
+U+8cac zé # Character 責
+U+8cad zhà # Character è²
+U+8cae èr # Character 貮
+#U+8caf zhÇ # Character 貯
+U+8cb0 shì # Character 貰
+U+8cb1 bì # Character 貱
+#U+8cb2 zī # Character 貲
+U+8cb3 èr # Character 貳
+U+8cb4 guì # Character 貴
+#U+8cb5 piÇn # Character è²µ
+#U+8cb6 biÇn # Character 貶
+#U+8cb7 mÇi # Character è²·
+U+8cb8 dà i # Character 貸
+U+8cb9 shèng # Character 貹
+U+8cba kuà ng # Character 貺
+U+8cbb fèi # Character 費
+#U+8cbc tiÄ # Character è²¼
+U+8cbd yà # Character 貽
+U+8cbe chà # Character 貾
+U+8cbf mà o # Character 貿
+U+8cc0 hè # Character è³
+U+8cc1 bì # Character è³
+U+8cc2 lù # Character è³
+U+8cc3 rèn # Character è³
+U+8cc4 huì # Character è³
+#U+8cc5 gÄi # Character è³
+U+8cc6 pián # Character è³
+#U+8cc7 zÄ« # Character è³
+#U+8cc8 jiÇ # Character è³
+U+8cc9 xù # Character è³
+U+8cca zéi # Character è³
+#U+8ccb jiÇo # Character è³
+U+8ccc gà i # Character è³
+#U+8ccd zÄng # Character è³
+U+8cce jià n # Character è³
+U+8ccf yìng # Character è³
+U+8cd0 xùn # Character è³
+U+8cd1 zhèn # Character è³
+#U+8cd2 shÄ # Character è³
+#U+8cd3 bÄ«n # Character è³
+#U+8cd4 bÄ«n # Character è³
+U+8cd5 qiú # Character è³
+#U+8cd6 shÄ # Character è³
+U+8cd7 chuà n # Character è³
+#U+8cd8 zÄng # Character è³
+#U+8cd9 zhÅu # Character è³
+U+8cda là i # Character è³
+U+8cdb zà n # Character è³
+U+8cdc sì # Character è³
+#U+8cdd chÄn # Character è³
+#U+8cde shÇng # Character è³
+#U+8cdf tiÇn # Character è³
+U+8ce0 péi # Character è³
+#U+8ce1 gÄng # Character 賡
+U+8ce2 xián # Character 賢
+U+8ce3 mà i # Character 賣
+U+8ce4 jià n # Character 賤
+U+8ce5 suì # Character 賥
+U+8ce6 fù # Character 賦
+U+8ce7 tà n # Character 賧
+U+8ce8 cóng # Character 賨
+U+8ce9 cóng # Character 賩
+U+8cea zhì # Character 質
+#U+8ceb jī # Character 賫
+U+8cec zhà ng # Character 賬
+#U+8ced dÇ # Character è³
+U+8cee jìn # Character 賮
+#U+8cef xiÅng # Character 賯
+#U+8cf0 shÇn # Character è³°
+#U+8cf1 yÇn # Character è³±
+#U+8cf2 bÇo # Character è³²
+#U+8cf3 zÄi # Character è³³
+U+8cf4 là i # Character 賴
+U+8cf5 fèng # Character 賵
+U+8cf6 cà ng # Character 賶
+#U+8cf7 jī # Character 賷
+U+8cf8 shèng # Character 賸
+U+8cf9 Ã i # Character è³¹
+U+8cfa zhuà n # Character 賺
+U+8cfb fù # Character 賻
+U+8cfc gòu # Character 購
+U+8cfd sà i # Character 賽
+U+8cfe zé # Character 賾
+U+8cff liáo # Character 賿
diff --git a/resources/chars/latin1/row8d.trans b/resources/chars/latin1/row8d.trans
new file mode 100644
index 0000000..8409a8a
--- /dev/null
+++ b/resources/chars/latin1/row8d.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+8d00 wèi # Character è´
+U+8d01 bà i # Character è´
+#U+8d02 chÄn # Character è´
+U+8d03 zhuà n # Character è´
+U+8d04 zhì # Character è´
+U+8d05 zhuì # Character è´
+#U+8d06 biÄo # Character è´
+#U+8d07 yÅ«n # Character è´
+U+8d08 zèng # Character è´
+#U+8d09 tÇn # Character è´
+U+8d0a zà n # Character è´
+U+8d0b yà n # Character è´
+U+8d0c ? # Character è´
+U+8d0d shà n # Character è´
+U+8d0e wà n # Character è´
+U+8d0f yÃng # Character è´
+U+8d10 jìn # Character è´
+#U+8d11 gÇn # Character è´
+U+8d12 xián # Character è´
+#U+8d13 zÄng # Character è´
+U+8d14 bì # Character è´
+U+8d15 dú # Character è´
+U+8d16 shú # Character è´
+U+8d17 yà n # Character è´
+U+8d18 ? # Character è´
+U+8d19 xuà n # Character è´
+U+8d1a lòng # Character è´
+U+8d1b gà n # Character è´
+#U+8d1c zÄng # Character è´
+U+8d1d bèi # Character è´
+#U+8d1e zhÄn # Character è´
+U+8d1f fù # Character è´
+U+8d20 yuán # Character è´
+U+8d21 gòng # Character 贡
+U+8d22 cái # Character 财
+U+8d23 zé # Character 责
+U+8d24 xián # Character 贤
+U+8d25 bà i # Character 败
+U+8d26 zhà ng # Character 账
+U+8d27 huò # Character 货
+U+8d28 zhì # Character 质
+U+8d29 fà n # Character 贩
+#U+8d2a tÄn # Character è´ª
+U+8d2b pÃn # Character è´«
+#U+8d2c biÇn # Character è´¬
+U+8d2d gòu # Character è´
+#U+8d2e zhÇ # Character è´®
+U+8d2f guà n # Character 贯
+U+8d30 èr # Character 贰
+U+8d31 jià n # Character 贱
+U+8d32 bì # Character 贲
+U+8d33 shì # Character 贳
+#U+8d34 tiÄ # Character è´´
+U+8d35 guì # Character 贵
+U+8d36 kuà ng # Character 贶
+U+8d37 dà i # Character 贷
+U+8d38 mà o # Character 贸
+U+8d39 fèi # Character 费
+U+8d3a hè # Character 贺
+U+8d3b yà # Character 贻
+U+8d3c zéi # Character 贼
+U+8d3d zhì # Character 贽
+#U+8d3e jiÇ # Character è´¾
+U+8d3f huì # Character 贿
+#U+8d40 zÄ« # Character èµ
+U+8d41 rèn # Character èµ
+U+8d42 lù # Character èµ
+#U+8d43 zÄng # Character èµ
+#U+8d44 zÄ« # Character èµ
+#U+8d45 gÄi # Character èµ
+U+8d46 jìn # Character èµ
+U+8d47 qiú # Character èµ
+U+8d48 zhèn # Character èµ
+U+8d49 là i # Character èµ
+#U+8d4a shÄ # Character èµ
+U+8d4b fù # Character èµ
+#U+8d4c dÇ # Character èµ
+#U+8d4d jÄ« # Character èµ
+U+8d4e shú # Character èµ
+#U+8d4f shÇng # Character èµ
+U+8d50 sì # Character èµ
+U+8d51 bì # Character èµ
+#U+8d52 zhÅu # Character èµ
+#U+8d53 gÄng # Character èµ
+U+8d54 péi # Character èµ
+U+8d55 tà n # Character èµ
+U+8d56 là i # Character èµ
+U+8d57 fèng # Character èµ
+U+8d58 zhuì # Character èµ
+U+8d59 fù # Character èµ
+U+8d5a zhuà n # Character èµ
+U+8d5b sà i # Character èµ
+U+8d5c zé # Character èµ
+U+8d5d yà n # Character èµ
+U+8d5e zà n # Character èµ
+#U+8d5f yÅ«n # Character èµ
+U+8d60 zèng # Character èµ
+U+8d61 shà n # Character 赡
+U+8d62 yÃng # Character èµ¢
+U+8d63 gà n # Character 赣
+U+8d64 chì # Character 赤
+U+8d65 xì # Character 赥
+U+8d66 shè # Character 赦
+#U+8d67 nÇn # Character 赧
+U+8d68 xióng # Character 赨
+U+8d69 xì # Character 赩
+#U+8d6a chÄng # Character 赪
+U+8d6b hè # Character 赫
+#U+8d6c chÄng # Character 赬
+#U+8d6d zhÄ # Character èµ
+U+8d6e xiá # Character 赮
+U+8d6f táng # Character 赯
+#U+8d70 zÇu # Character èµ°
+#U+8d71 zÇu # Character èµ±
+U+8d72 lì # Character 赲
+#U+8d73 jiÇ # Character èµ³
+U+8d74 fù # Character 赴
+U+8d75 zhà o # Character 赵
+#U+8d76 gÇn # Character 赶
+#U+8d77 qÇ # Character èµ·
+U+8d78 shà n # Character 赸
+U+8d79 qióng # Character 赹
+U+8d7a qÃn # Character 赺
+#U+8d7b xiÇn # Character èµ»
+#U+8d7c cī # Character 赼
+U+8d7d jué # Character 赽
+#U+8d7e qÇn # Character èµ¾
+U+8d7f chà # Character 赿
+#U+8d80 cÄ« # Character è¶
+U+8d81 chèn # Character è¶
+U+8d82 chèn # Character è¶
+U+8d83 dié # Character è¶
+#U+8d84 jÅ« # Character è¶
+#U+8d85 chÄo # Character è¶
+#U+8d86 dÄ« # Character è¶
+U+8d87 sè # Character è¶
+#U+8d88 zhÄn # Character è¶
+U+8d89 zhú # Character è¶
+U+8d8a yuè # Character è¶
+#U+8d8b qÅ« # Character è¶
+U+8d8c jié # Character è¶
+U+8d8d chà # Character è¶
+U+8d8e chú # Character è¶
+#U+8d8f guÄ # Character è¶
+U+8d90 xuè # Character è¶
+#U+8d91 cÄ« # Character è¶
+U+8d92 tiáo # Character è¶
+#U+8d93 duÇ # Character è¶
+U+8d94 liè # Character è¶
+#U+8d95 gÇn # Character è¶
+#U+8d96 suÅ # Character è¶
+U+8d97 cù # Character è¶
+U+8d98 xà # Character è¶
+U+8d99 zhà o # Character è¶
+U+8d9a sù # Character è¶
+#U+8d9b yÇn # Character è¶
+U+8d9c jú # Character è¶
+U+8d9d jià n # Character è¶
+U+8d9e què # Character è¶
+U+8d9f tà ng # Character è¶
+U+8da0 chuò # Character è¶
+#U+8da1 cuÇ # Character 趡
+U+8da2 lù # Character 趢
+U+8da3 qù # Character 趣
+U+8da4 dà ng # Character 趤
+#U+8da5 qiū # Character 趥
+#U+8da6 zī # Character 趦
+U+8da7 tà # Character 趧
+#U+8da8 qū # Character 趨
+U+8da9 chì # Character 趩
+U+8daa huáng # Character 趪
+U+8dab qiáo # Character 趫
+U+8dac qiáo # Character 趬
+U+8dad yà o # Character è¶
+U+8dae zà o # Character 趮
+U+8daf tì # Character 趯
+U+8db0 ? # Character 趰
+#U+8db1 zÇn # Character 趱
+#U+8db2 zÇn # Character 趲
+U+8db3 zú # Character 足
+#U+8db4 pÄ # Character 趴
+U+8db5 bà o # Character 趵
+U+8db6 kù # Character 趶
+#U+8db7 kÄ # Character 趷
+#U+8db8 dÇn # Character 趸
+U+8db9 jué # Character 趹
+#U+8dba fū # Character 趺
+#U+8dbb chÄn # Character 趻
+#U+8dbc jiÇn # Character 趼
+U+8dbd fà ng # Character 趽
+#U+8dbe zhÇ # Character 趾
+U+8dbf sà # Character 趿
+U+8dc0 yuè # Character è·
+U+8dc1 pá # Character è·
+U+8dc2 qà # Character è·
+U+8dc3 yuè # Character è·
+#U+8dc4 qiÄng # Character è·
+U+8dc5 tuò # Character è·
+U+8dc6 tái # Character è·
+U+8dc7 yì # Character è·
+#U+8dc8 niÇn # Character è·
+U+8dc9 lÃng # Character è·
+U+8dca mèi # Character è·
+U+8dcb bá # Character è·
+#U+8dcc diÄ # Character è·
+#U+8dcd kÅ« # Character è·
+U+8dce tuó # Character è·
+#U+8dcf jiÄ # Character è·
+#U+8dd0 cÇ # Character è·
+#U+8dd1 pÇo # Character è·
+#U+8dd2 qiÇ # Character è·
+U+8dd3 zhù # Character è·
+#U+8dd4 jÅ« # Character è·
+U+8dd5 dié # Character è·
+#U+8dd6 zhÄ« # Character è·
+#U+8dd7 fÅ« # Character è·
+U+8dd8 pán # Character è·
+#U+8dd9 jÇ # Character è·
+#U+8dda shÄn # Character è·
+#U+8ddb bÇ # Character è·
+U+8ddc nà # Character è·
+U+8ddd jù # Character è·
+U+8dde lì # Character è·
+#U+8ddf gÄn # Character è·
+U+8de0 yà # Character è·
+#U+8de1 jī # Character 跡
+U+8de2 dà i # Character 跢
+#U+8de3 xiÇn # Character è·£
+#U+8de4 jiÄo # Character è·¤
+U+8de5 duò # Character 跥
+#U+8de6 zhū # Character 跦
+#U+8de7 zhuÄn # Character è·§
+U+8de8 kuà # Character 跨
+#U+8de9 zhuÇi # Character è·©
+U+8dea guì # Character 跪
+U+8deb qióng # Character 跫
+#U+8dec kuÇ # Character è·¬
+U+8ded xiáng # Character è·
+U+8dee chì # Character 跮
+U+8def lù # Character 路
+U+8df0 bèng # Character 跰
+U+8df1 zhì # Character 跱
+U+8df2 jiá # Character 跲
+U+8df3 tià o # Character 跳
+#U+8df4 cÇi # Character è·´
+U+8df5 jià n # Character 践
+U+8df6 tà # Character 跶
+#U+8df7 qiÄo # Character è··
+U+8df8 bì # Character 跸
+#U+8df9 xiÄn # Character è·¹
+U+8dfa duò # Character 跺
+#U+8dfb jī # Character 跻
+U+8dfc jú # Character 跼
+U+8dfd jì # Character 跽
+U+8dfe shú # Character 跾
+U+8dff tú # Character 跿
diff --git a/resources/chars/latin1/row8e.trans b/resources/chars/latin1/row8e.trans
new file mode 100644
index 0000000..65158de
--- /dev/null
+++ b/resources/chars/latin1/row8e.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+8e00 chù # Character è¸
+U+8e01 jìng # Character è¸
+U+8e02 niè # Character è¸
+#U+8e03 xiÄo # Character è¸
+U+8e04 bó # Character è¸
+U+8e05 chì # Character è¸
+#U+8e06 qÅ«n # Character è¸
+#U+8e07 mÇu # Character è¸
+#U+8e08 shÅ« # Character è¸
+U+8e09 láng # Character è¸
+#U+8e0a yÇng # Character è¸
+#U+8e0b jiÇo # Character è¸
+U+8e0c chóu # Character è¸
+#U+8e0d qiÄo # Character è¸
+U+8e0e ? # Character è¸
+U+8e0f tà # Character è¸
+U+8e10 jià n # Character è¸
+U+8e11 qà # Character è¸
+#U+8e12 wÅ # Character è¸
+#U+8e13 wÄi # Character è¸
+U+8e14 zhuó # Character è¸
+U+8e15 jié # Character è¸
+U+8e16 jà # Character è¸
+#U+8e17 niÄ # Character è¸
+U+8e18 jú # Character è¸
+#U+8e19 jÅ« # Character è¸
+U+8e1a lún # Character è¸
+U+8e1b lù # Character è¸
+U+8e1c lèng # Character è¸
+U+8e1d huái # Character è¸
+U+8e1e jù # Character è¸
+U+8e1f chà # Character è¸
+#U+8e20 wÇn # Character è¸
+U+8e21 quán # Character 踡
+#U+8e22 tī # Character 踢
+U+8e23 bó # Character 踣
+U+8e24 zú # Character 踤
+U+8e25 qiè # Character 踥
+#U+8e26 jÇ # Character 踦
+U+8e27 cù # Character 踧
+#U+8e28 zÅng # Character 踨
+#U+8e29 cÇi # Character 踩
+#U+8e2a zÅng # Character 踪
+U+8e2b pèng # Character 踫
+U+8e2c zhì # Character 踬
+#U+8e2d zhÄng # Character è¸
+#U+8e2e diÇn # Character 踮
+U+8e2f zhà # Character 踯
+U+8e30 yú # Character 踰
+U+8e31 duó # Character 踱
+U+8e32 dùn # Character 踲
+#U+8e33 chÇn # Character 踳
+#U+8e34 yÇng # Character 踴
+#U+8e35 zhÇng # Character 踵
+U+8e36 dì # Character 踶
+#U+8e37 zhÄ # Character 踷
+#U+8e38 chÄn # Character 踸
+U+8e39 chuà i # Character 踹
+U+8e3a jià n # Character 踺
+#U+8e3b guÄ # Character 踻
+U+8e3c táng # Character 踼
+#U+8e3d jÇ # Character 踽
+U+8e3e fú # Character 踾
+U+8e3f zú # Character 踿
+U+8e40 dié # Character è¹
+U+8e41 pián # Character è¹
+U+8e42 róu # Character è¹
+U+8e43 nuò # Character è¹
+U+8e44 tà # Character è¹
+#U+8e45 chÇ # Character è¹
+#U+8e46 tuÇ # Character è¹
+#U+8e47 jiÇn # Character è¹
+#U+8e48 dÇo # Character è¹
+#U+8e49 cuÅ # Character è¹
+#U+8e4a xÄ« # Character è¹
+U+8e4b tà # Character è¹
+#U+8e4c qiÄng # Character è¹
+#U+8e4d zhÇn # Character è¹
+#U+8e4e diÄn # Character è¹
+U+8e4f tà # Character è¹
+U+8e50 jà # Character è¹
+U+8e51 niè # Character è¹
+U+8e52 mán # Character è¹
+#U+8e53 liÅ« # Character è¹
+U+8e54 zhà n # Character è¹
+U+8e55 bì # Character è¹
+#U+8e56 chÅng # Character è¹
+U+8e57 lù # Character è¹
+U+8e58 liáo # Character è¹
+U+8e59 cù # Character è¹
+#U+8e5a tÄng # Character è¹
+U+8e5b dà i # Character è¹
+#U+8e5c suÅ # Character è¹
+#U+8e5d xÇ # Character è¹
+#U+8e5e kuÇ # Character è¹
+#U+8e5f jÄ« # Character è¹
+U+8e60 zhà # Character è¹
+#U+8e61 qiÄng # Character 蹡
+U+8e62 dà # Character 蹢
+U+8e63 mán # Character 蹣
+#U+8e64 zÅng # Character 蹤
+U+8e65 lián # Character 蹥
+U+8e66 bèng # Character 蹦
+#U+8e67 zÄo # Character 蹧
+#U+8e68 niÇn # Character 蹨
+U+8e69 bié # Character 蹩
+U+8e6a tuà # Character 蹪
+U+8e6b jú # Character 蹫
+#U+8e6c dÄng # Character 蹬
+U+8e6d cèng # Character è¹
+#U+8e6e xiÄn # Character è¹®
+U+8e6f fán # Character 蹯
+U+8e70 chú # Character 蹰
+#U+8e71 zhÅng # Character è¹±
+#U+8e72 dūn # Character 蹲
+#U+8e73 bÅ # Character è¹³
+U+8e74 cù # Character 蹴
+U+8e75 zú # Character 蹵
+U+8e76 jué # Character 蹶
+U+8e77 jué # Character 蹷
+U+8e78 lìn # Character 蹸
+U+8e79 tà # Character 蹹
+#U+8e7a qiÄo # Character 蹺
+#U+8e7b qiÄo # Character è¹»
+U+8e7c pú # Character 蹼
+#U+8e7d liÄo # Character è¹½
+#U+8e7e dūn # Character 蹾
+#U+8e7f cuÄn # Character 蹿
+U+8e80 kuà ng # Character èº
+U+8e81 zà o # Character èº
+U+8e82 tà # Character èº
+U+8e83 bì # Character èº
+U+8e84 bì # Character èº
+U+8e85 zhú # Character èº
+U+8e86 jù # Character èº
+U+8e87 chú # Character èº
+U+8e88 qià o # Character èº
+#U+8e89 dÇn # Character èº
+U+8e8a chóu # Character èº
+#U+8e8b jÄ« # Character èº
+#U+8e8c wÇ # Character èº
+U+8e8d yuè # Character èº
+#U+8e8e niÇn # Character èº
+U+8e8f lìn # Character èº
+U+8e90 liè # Character èº
+U+8e91 zhà # Character èº
+U+8e92 lì # Character èº
+U+8e93 zhì # Character èº
+U+8e94 chán # Character èº
+U+8e95 chú # Character èº
+U+8e96 duà n # Character èº
+U+8e97 wèi # Character èº
+U+8e98 lóng # Character èº
+U+8e99 lìn # Character èº
+#U+8e9a xiÄn # Character èº
+U+8e9b wèi # Character èº
+#U+8e9c zuÄn # Character èº
+U+8e9d lán # Character èº
+U+8e9e xiè # Character èº
+U+8e9f ráng # Character èº
+#U+8ea0 xiÄ # Character èº
+U+8ea1 niè # Character 躡
+U+8ea2 tà # Character 躢
+U+8ea3 qú # Character 躣
+U+8ea4 jiè # Character 躤
+#U+8ea5 cuÄn # Character 躥
+#U+8ea6 zuÄn # Character 躦
+#U+8ea7 xÇ # Character 躧
+U+8ea8 kuà # Character 躨
+U+8ea9 jué # Character 躩
+U+8eaa lìn # Character 躪
+#U+8eab shÄn # Character 身
+#U+8eac gÅng # Character 躬
+#U+8ead dÄn # Character èº
+U+8eae ? # Character 躮
+#U+8eaf qū # Character 躯
+#U+8eb0 tÇ # Character 躰
+#U+8eb1 duÇ # Character 躱
+#U+8eb2 duÇ # Character 躲
+#U+8eb3 gÅng # Character 躳
+U+8eb4 láng # Character 躴
+U+8eb5 ? # Character 躵
+#U+8eb6 luÇ # Character 躶
+#U+8eb7 Çi # Character 躷
+#U+8eb8 jī # Character 躸
+U+8eb9 jú # Character 躹
+#U+8eba tÇng # Character 躺
+U+8ebb ? # Character 躻
+U+8ebc ? # Character 躼
+#U+8ebd yÇn # Character 躽
+U+8ebe ? # Character 躾
+#U+8ebf kÄng # Character 躿
+#U+8ec0 qÅ« # Character è»
+U+8ec1 lóu # Character è»
+U+8ec2 là o # Character è»
+#U+8ec3 tuÇ # Character è»
+U+8ec4 zhà # Character è»
+U+8ec5 ? # Character è»
+#U+8ec6 tÇ # Character è»
+U+8ec7 dà o # Character è»
+U+8ec8 ? # Character è»
+U+8ec9 yù # Character è»
+#U+8eca chÄ # Character è»
+U+8ecb yà # Character è»
+#U+8ecc guÇ # Character è»
+#U+8ecd jÅ«n # Character è»
+U+8ece wèi # Character è»
+U+8ecf yuè # Character è»
+U+8ed0 xìn # Character è»
+U+8ed1 dì # Character è»
+#U+8ed2 xuÄn # Character è»
+U+8ed3 fà n # Character è»
+U+8ed4 rèn # Character è»
+#U+8ed5 shÄn # Character è»
+U+8ed6 qiáng # Character è»
+#U+8ed7 shÅ« # Character è»
+U+8ed8 tún # Character è»
+U+8ed9 chén # Character è»
+U+8eda dà i # Character è»
+U+8edb è # Character è»
+U+8edc nà # Character è»
+U+8edd qà # Character è»
+U+8ede máo # Character è»
+#U+8edf ruÇn # Character è»
+U+8ee0 rèn # Character è»
+#U+8ee1 fÇn # Character 軡
+#U+8ee2 zhuÇn # Character 転
+#U+8ee3 hÅng # Character 軣
+#U+8ee4 hū # Character 軤
+U+8ee5 qú # Character 軥
+U+8ee6 huà ng # Character 軦
+#U+8ee7 dÇ # Character 軧
+U+8ee8 lÃng # Character 軨
+U+8ee9 dà i # Character 軩
+#U+8eea Äo # Character 軪
+#U+8eeb zhÄn # Character 軫
+U+8eec fà n # Character 軬
+#U+8eed kuÄng # Character è»
+#U+8eee Çng # Character è»®
+#U+8eef pÄng # Character 軯
+U+8ef0 bèi # Character 軰
+#U+8ef1 gū # Character 軱
+#U+8ef2 kū # Character 軲
+U+8ef3 páo # Character 軳
+U+8ef4 zhù # Character 軴
+#U+8ef5 rÇng # Character 軵
+U+8ef6 è # Character 軶
+U+8ef7 bá # Character 軷
+U+8ef8 zhóu # Character 軸
+#U+8ef9 zhÇ # Character 軹
+U+8efa yáo # Character 軺
+#U+8efb kÄ # Character è»»
+U+8efc yì # Character 軼
+#U+8efd qīng # Character 軽
+U+8efe shì # Character 軾
+U+8eff pÃng # Character 軿
diff --git a/resources/chars/latin1/row8f.trans b/resources/chars/latin1/row8f.trans
new file mode 100644
index 0000000..0718bfe
--- /dev/null
+++ b/resources/chars/latin1/row8f.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+8f00 ér # Character è¼
+U+8f01 qióng # Character è¼
+U+8f02 jú # Character è¼
+U+8f03 jià o # Character è¼
+#U+8f04 guÄng # Character è¼
+U+8f05 lù # Character è¼
+#U+8f06 kÇi # Character è¼
+U+8f07 quán # Character è¼
+#U+8f08 zhÅu # Character è¼
+U+8f09 zà i # Character è¼
+U+8f0a zhì # Character è¼
+#U+8f0b shÄ # Character è¼
+U+8f0c lià ng # Character è¼
+U+8f0d yù # Character è¼
+#U+8f0e shÄo # Character è¼
+U+8f0f yóu # Character è¼
+#U+8f10 huÇn # Character è¼
+#U+8f11 yÇn # Character è¼
+U+8f12 zhé # Character è¼
+#U+8f13 wÇn # Character è¼
+#U+8f14 fÇ # Character è¼
+#U+8f15 qÄ«ng # Character è¼
+#U+8f16 zhÅu # Character è¼
+U+8f17 nà # Character è¼
+U+8f18 lÃng # Character è¼
+U+8f19 zhé # Character è¼
+U+8f1a zhà n # Character è¼
+U+8f1b lià ng # Character è¼
+#U+8f1c zÄ« # Character è¼
+#U+8f1d huÄ« # Character è¼
+#U+8f1e wÇng # Character è¼
+U+8f1f chuò # Character è¼
+#U+8f20 guÇ # Character è¼
+#U+8f21 kÇn # Character 輡
+#U+8f22 yÇ # Character è¼¢
+U+8f23 péng # Character 輣
+U+8f24 qià n # Character 輤
+#U+8f25 gÇn # Character è¼¥
+#U+8f26 niÇn # Character 輦
+U+8f27 pián # Character 輧
+#U+8f28 guÇn # Character 輨
+U+8f29 bèi # Character 輩
+U+8f2a lún # Character 輪
+U+8f2b pái # Character 輫
+U+8f2c liáng # Character 輬
+#U+8f2d ruÇn # Character è¼
+U+8f2e róu # Character 輮
+U+8f2f ji # Character 輯
+U+8f30 yáng # Character 輰
+U+8f31 xián # Character 輱
+U+8f32 chuán # Character 輲
+U+8f33 còu # Character 輳
+#U+8f34 qūn # Character 輴
+U+8f35 gé # Character 輵
+U+8f36 yóu # Character 輶
+#U+8f37 hÅng # Character è¼·
+#U+8f38 shū # Character 輸
+U+8f39 fù # Character 輹
+#U+8f3a zī # Character 輺
+U+8f3b fú # Character 輻
+#U+8f3c wÄn # Character è¼¼
+U+8f3d bèn # Character 輽
+#U+8f3e zhÇn # Character è¼¾
+U+8f3f yú # Character 輿
+#U+8f40 wÄn # Character è½
+#U+8f41 tÄo # Character è½
+#U+8f42 gÇ # Character è½
+#U+8f43 zhÄn # Character è½
+U+8f44 xiá # Character è½
+U+8f45 yuán # Character è½
+U+8f46 lù # Character è½
+#U+8f47 jiÅ« # Character è½
+U+8f48 cháo # Character è½
+#U+8f49 zhuÇn # Character è½
+U+8f4a wèi # Character è½
+U+8f4b hún # Character è½
+U+8f4c ? # Character è½
+U+8f4d chè # Character è½
+U+8f4e jià o # Character è½
+U+8f4f zhà n # Character è½
+U+8f50 pú # Character è½
+#U+8f51 lÇo # Character è½
+U+8f52 fén # Character è½
+#U+8f53 fÄn # Character è½
+U+8f54 lÃn # Character è½
+U+8f55 gé # Character è½
+U+8f56 sè # Character è½
+#U+8f57 kÇn # Character è½
+U+8f58 huà n # Character è½
+#U+8f59 yÇ # Character è½
+U+8f5a jà # Character è½
+U+8f5b duì # Character è½
+U+8f5c ér # Character è½
+U+8f5d yú # Character è½
+U+8f5e xià n # Character è½
+#U+8f5f hÅng # Character è½
+#U+8f60 lÄi # Character è½
+U+8f61 pèi # Character 轡
+U+8f62 lì # Character 轢
+U+8f63 lì # Character 轣
+U+8f64 lú # Character 轤
+U+8f65 lìn # Character 轥
+#U+8f66 chÄ # Character 车
+U+8f67 yà # Character 轧
+#U+8f68 guÇ # Character 轨
+#U+8f69 xuÄn # Character 轩
+U+8f6a dì # Character 轪
+U+8f6b rèn # Character 轫
+#U+8f6c zhuÇn # Character 转
+U+8f6d è # Character è½
+U+8f6e lún # Character 轮
+#U+8f6f ruÇn # Character 软
+#U+8f70 hÅng # Character è½°
+#U+8f71 kū # Character 轱
+#U+8f72 kÄ # Character è½²
+U+8f73 lú # Character 轳
+U+8f74 zhóu # Character 轴
+#U+8f75 zhÇ # Character è½µ
+U+8f76 yì # Character 轶
+#U+8f77 hū # Character 轷
+#U+8f78 zhÄn # Character 轸
+U+8f79 lì # Character 轹
+U+8f7a yáo # Character 轺
+#U+8f7b qīng # Character 轻
+U+8f7c shì # Character 轼
+U+8f7d zà i # Character 载
+U+8f7e zhì # Character 轾
+U+8f7f jià o # Character 轿
+#U+8f80 zhÅu # Character è¾
+U+8f81 quán # Character è¾
+U+8f82 lù # Character è¾
+U+8f83 jià o # Character è¾
+U+8f84 zhé # Character è¾
+#U+8f85 fÇ # Character è¾
+U+8f86 lià ng # Character è¾
+#U+8f87 niÇn # Character è¾
+U+8f88 bèi # Character è¾
+#U+8f89 huÄ« # Character è¾
+#U+8f8a gÇn # Character è¾
+#U+8f8b wÇng # Character è¾
+U+8f8c liáng # Character è¾
+U+8f8d chuò # Character è¾
+#U+8f8e zÄ« # Character è¾
+U+8f8f còu # Character è¾
+U+8f90 fú # Character è¾
+U+8f91 ji # Character è¾
+#U+8f92 wÄn # Character è¾
+#U+8f93 shÅ« # Character è¾
+U+8f94 pèi # Character è¾
+U+8f95 yuán # Character è¾
+U+8f96 xiá # Character è¾
+#U+8f97 zhÇn # Character è¾
+U+8f98 lù # Character è¾
+U+8f99 chè # Character è¾
+U+8f9a lÃn # Character è¾
+#U+8f9b xÄ«n # Character è¾
+#U+8f9c gÅ« # Character è¾
+U+8f9d cà # Character è¾
+U+8f9e cà # Character è¾
+U+8f9f pì # Character è¾
+U+8fa0 zuì # Character è¾
+U+8fa1 bià n # Character 辡
+U+8fa2 là # Character 辢
+U+8fa3 là # Character 辣
+U+8fa4 cà # Character 辤
+#U+8fa5 xuÄ # Character è¾¥
+U+8fa6 bà n # Character 辦
+U+8fa7 bià n # Character 辧
+U+8fa8 bià n # Character 辨
+U+8fa9 bià n # Character 辩
+U+8faa ? # Character 辪
+U+8fab bià n # Character 辫
+#U+8fac bÄn # Character 辬
+U+8fad cà # Character è¾
+U+8fae bià n # Character 辮
+U+8faf bià n # Character 辯
+U+8fb0 chén # Character 辰
+#U+8fb1 rÇ # Character è¾±
+U+8fb2 nóng # Character 農
+U+8fb3 nóng # Character 辳
+#U+8fb4 zhÄn # Character è¾´
+U+8fb5 chuò # Character 辵
+U+8fb6 chuò # Character 辶
+U+8fb7 ? # Character è¾·
+U+8fb8 réng # Character 辸
+#U+8fb9 biÄn # Character è¾¹
+#U+8fba biÄn # Character 辺
+U+8fbb ? # Character è¾»
+U+8fbc ? # Character è¾¼
+U+8fbd liáo # Character 辽
+U+8fbe dá # Character 达
+#U+8fbf chÄn # Character 辿
+#U+8fc0 gÄn # Character è¿
+#U+8fc1 qiÄn # Character è¿
+#U+8fc2 yÅ« # Character è¿
+#U+8fc3 yÅ« # Character è¿
+U+8fc4 qì # Character è¿
+U+8fc5 xùn # Character è¿
+#U+8fc6 yÇ # Character è¿
+U+8fc7 guò # Character è¿
+U+8fc8 mà i # Character è¿
+U+8fc9 qà # Character è¿
+#U+8fca zÄ # Character è¿
+U+8fcb wà ng # Character è¿
+U+8fcc ? # Character è¿
+#U+8fcd zhÅ«n # Character è¿
+U+8fce yÃng # Character è¿
+U+8fcf tì # Character è¿
+U+8fd0 yùn # Character è¿
+U+8fd1 jìn # Character è¿
+U+8fd2 háng # Character è¿
+U+8fd3 yà # Character è¿
+#U+8fd4 fÇn # Character è¿
+U+8fd5 wù # Character è¿
+U+8fd6 dá # Character è¿
+U+8fd7 é # Character è¿
+U+8fd8 hái # Character è¿
+U+8fd9 zhè # Character è¿
+U+8fda ? # Character è¿
+U+8fdb jìn # Character è¿
+#U+8fdc yuÇn # Character è¿
+U+8fdd wéi # Character è¿
+U+8fde lián # Character è¿
+U+8fdf chà # Character è¿
+U+8fe0 chè # Character è¿
+U+8fe1 nì # Character 迡
+U+8fe2 tiáo # Character 迢
+U+8fe3 zhì # Character 迣
+#U+8fe4 yÇ # Character 迤
+#U+8fe5 jiÇng # Character è¿¥
+#U+8fe6 jiÄ # Character 迦
+U+8fe7 chén # Character 迧
+U+8fe8 dà i # Character 迨
+#U+8fe9 Är # Character è¿©
+U+8fea dà # Character 迪
+U+8feb pò # Character 迫
+#U+8fec wÇng # Character 迬
+U+8fed dié # Character è¿
+U+8fee zé # Character 迮
+U+8fef táo # Character 迯
+U+8ff0 shù # Character 述
+U+8ff1 tuó # Character 迱
+U+8ff2 ? # Character 迲
+U+8ff3 jìng # Character 迳
+U+8ff4 huà # Character 迴
+U+8ff5 tóng # Character 迵
+U+8ff6 yòu # Character 迶
+U+8ff7 mà # Character 迷
+U+8ff8 bèng # Character 迸
+#U+8ff9 jī # Character 迹
+#U+8ffa nÇi # Character 迺
+U+8ffb yà # Character 迻
+U+8ffc jié # Character 迼
+#U+8ffd zhuī # Character 追
+U+8ffe liè # Character 迾
+U+8fff xùn # Character 迿
diff --git a/resources/chars/latin1/row90.trans b/resources/chars/latin1/row90.trans
new file mode 100644
index 0000000..cdc92d4
--- /dev/null
+++ b/resources/chars/latin1/row90.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+9000 tuì # Character é
+U+9001 sòng # Character é
+U+9002 shì # Character é
+U+9003 táo # Character é
+U+9004 páng # Character é
+U+9005 hòu # Character é
+U+9006 nì # Character é
+U+9007 dùn # Character é
+#U+9008 jiÇng # Character é
+#U+9009 xuÇn # Character é
+U+900a xùn # Character é
+#U+900b bÅ« # Character é
+U+900c yóu # Character é
+#U+900d xiÄo # Character é
+U+900e qiú # Character é
+U+900f tòu # Character é
+U+9010 zhú # Character é
+U+9011 qiú # Character é
+U+9012 dì # Character é
+U+9013 dì # Character é
+U+9014 tú # Character é
+U+9015 jìng # Character é
+U+9016 tì # Character é
+U+9017 dòu # Character é
+#U+9018 yÇ # Character é
+U+9019 zhè # Character é
+#U+901a tÅng # Character é
+U+901b guà ng # Character é
+U+901c wù # Character é
+U+901d shì # Character é
+#U+901e chÄng # Character é
+U+901f sù # Character é
+U+9020 zà o # Character é
+#U+9021 qÅ«n # Character é¡
+U+9022 féng # Character é¢
+U+9023 lián # Character é£
+U+9024 suò # Character é¤
+U+9025 huà # Character é¥
+#U+9026 lÇ # Character é¦
+U+9027 ? # Character é§
+U+9028 lái # Character é¨
+U+9029 bèn # Character é©
+U+902a cuò # Character éª
+U+902b jué # Character é«
+U+902c bèng # Character é¬
+U+902d huà n # Character é
+#U+902e dÇi # Character é®
+U+902f lù # Character é¯
+U+9030 yóu # Character é°
+#U+9031 zhÅu # Character é±
+U+9032 jìn # Character é²
+U+9033 yù # Character é³
+U+9034 chuò # Character é´
+U+9035 kuà # Character éµ
+#U+9036 wÄi # Character é¶
+U+9037 tì # Character é·
+U+9038 yì # Character é¸
+U+9039 dá # Character é¹
+#U+903a yuÇn # Character éº
+U+903b luó # Character é»
+#U+903c bÄ« # Character é¼
+U+903d nuò # Character é½
+U+903e yú # Character é¾
+U+903f dà ng # Character é¿
+U+9040 suà # Character é
+U+9041 dùn # Character é
+U+9042 suì # Character é
+#U+9043 yÇn # Character é
+U+9044 chuán # Character é
+U+9045 chà # Character é
+U+9046 tà # Character é
+U+9047 yù # Character é
+U+9048 shà # Character é
+#U+9049 zhÄn # Character é
+U+904a yóu # Character é
+U+904b yùn # Character é
+U+904c è # Character é
+U+904d bià n # Character é
+U+904e guò # Character é
+U+904f è # Character é
+U+9050 xiá # Character é
+U+9051 huáng # Character é
+U+9052 qiú # Character é
+U+9053 dà o # Character é
+U+9054 dá # Character é
+U+9055 wéi # Character é
+U+9056 ? # Character é
+U+9057 yà # Character é
+U+9058 gòu # Character é
+U+9059 yáo # Character é
+U+905a chù # Character é
+U+905b liú # Character é
+U+905c xùn # Character é
+U+905d tà # Character é
+U+905e dì # Character é
+U+905f chà # Character é
+#U+9060 yuÇn # Character é
+U+9061 sù # Character é¡
+U+9062 tà # Character é¢
+#U+9063 qiÇn # Character é£
+U+9064 ? # Character é¤
+U+9065 yáo # Character é¥
+U+9066 guà n # Character é¦
+#U+9067 zhÄng # Character é§
+U+9068 áo # Character é¨
+U+9069 shì # Character é©
+U+906a cè # Character éª
+U+906b chì # Character é«
+U+906c sù # Character é¬
+#U+906d zÄo # Character é
+#U+906e zhÄ # Character é®
+U+906f dùn # Character é¯
+U+9070 dì # Character é°
+U+9071 lóu # Character é±
+U+9072 chà # Character é²
+#U+9073 cuÅ # Character é³
+U+9074 lÃn # Character é´
+#U+9075 zÅ«n # Character éµ
+U+9076 rà o # Character é¶
+#U+9077 qiÄn # Character é·
+#U+9078 xuÇn # Character é¸
+U+9079 yù # Character é¹
+U+907a yà # Character éº
+U+907b wù # Character é»
+U+907c liáo # Character é¼
+U+907d jù # Character é½
+U+907e shì # Character é¾
+U+907f bì # Character é¿
+#U+9080 yÄo # Character é
+U+9081 mà i # Character é
+U+9082 xiè # Character é
+U+9083 suì # Character é
+U+9084 hái # Character é
+#U+9085 zhÄn # Character é
+U+9086 téng # Character é
+#U+9087 Är # Character é
+#U+9088 miÇo # Character é
+#U+9089 biÄn # Character é
+#U+908a biÄn # Character é
+U+908b lá # Character é
+U+908c là # Character é
+U+908d yuán # Character é
+U+908e yáo # Character é
+U+908f luó # Character é
+#U+9090 lÇ # Character é
+U+9091 yì # Character é
+U+9092 tÃng # Character é
+U+9093 dèng # Character é
+#U+9094 qÇ # Character é
+#U+9095 yÅng # Character é
+#U+9096 shÄn # Character é
+U+9097 hán # Character é
+U+9098 yú # Character é
+U+9099 máng # Character é
+U+909a rú # Character é
+U+909b qióng # Character é
+U+909c ? # Character é
+U+909d kuà ng # Character é
+#U+909e fÅ« # Character é
+U+909f kà ng # Character é
+#U+90a0 bÄ«n # Character é
+#U+90a1 fÄng # Character é¡
+U+90a2 xÃng # Character é¢
+U+90a3 nà # Character é£
+U+90a4 ? # Character é¤
+#U+90a5 shÄn # Character é¥
+#U+90a6 bÄng # Character é¦
+U+90a7 yuán # Character é§
+#U+90a8 cÅ«n # Character é¨
+#U+90a9 huÇ # Character é©
+U+90aa xié # Character éª
+#U+90ab bÄng # Character é«
+#U+90ac wÅ« # Character é¬
+U+90ad jù # Character é
+U+90ae yóu # Character é®
+U+90af hán # Character é¯
+U+90b0 tái # Character é°
+#U+90b1 qiÅ« # Character é±
+U+90b2 bì # Character é²
+U+90b3 péi # Character é³
+#U+90b4 bÇng # Character é´
+U+90b5 shà o # Character éµ
+U+90b6 bèi # Character é¶
+#U+90b7 wÇ # Character é·
+#U+90b8 dÇ # Character é¸
+#U+90b9 zÅu # Character é¹
+U+90ba yè # Character éº
+U+90bb lÃn # Character é»
+#U+90bc kuÄng # Character é¼
+#U+90bd guÄ« # Character é½
+#U+90be zhÅ« # Character é¾
+#U+90bf shÄ« # Character é¿
+#U+90c0 kÅ« # Character é
+U+90c1 yù # Character é
+#U+90c2 gÄi # Character é
+U+90c3 gé # Character é
+U+90c4 xì # Character é
+U+90c5 zhì # Character é
+U+90c6 jà # Character é
+U+90c7 xún # Character é
+U+90c8 hòu # Character é
+U+90c9 xÃng # Character é
+#U+90ca jiÄo # Character é
+U+90cb xà # Character é
+#U+90cc guÄ« # Character é
+U+90cd nuó # Character é
+U+90ce láng # Character é
+U+90cf jiá # Character é
+U+90d0 kuà i # Character é
+U+90d1 zhèng # Character é
+U+90d2 ? # Character é
+U+90d3 yùn # Character é
+U+90d4 yán # Character é
+U+90d5 chéng # Character é
+#U+90d6 dÅu # Character é
+#U+90d7 chÄ« # Character é
+#U+90d8 lÇ # Character é
+#U+90d9 fÇ # Character é
+U+90da wú # Character é
+U+90db fú # Character é
+U+90dc gà o # Character é
+#U+90dd hÇo # Character é
+U+90de láng # Character é
+U+90df jiá # Character é
+#U+90e0 gÄng # Character é
+U+90e1 jùn # Character é¡
+#U+90e2 yÇng # Character é¢
+U+90e3 bó # Character é£
+U+90e4 xì # Character é¤
+U+90e5 bèi # Character é¥
+U+90e6 lì # Character é¦
+U+90e7 yún # Character é§
+U+90e8 bù # Character é¨
+U+90e9 xiáo # Character é©
+#U+90ea qÄ« # Character éª
+U+90eb pà # Character é«
+#U+90ec qÄ«ng # Character é¬
+#U+90ed guÅ # Character é
+U+90ee ? # Character é®
+U+90ef tán # Character é¯
+#U+90f0 zÅu # Character é°
+U+90f1 pÃng # Character é±
+U+90f2 lái # Character é²
+U+90f3 nà # Character é³
+#U+90f4 chÄn # Character é´
+U+90f5 yóu # Character éµ
+U+90f6 bù # Character é¶
+#U+90f7 xiÄng # Character é·
+#U+90f8 dÄn # Character é¸
+U+90f9 jú # Character é¹
+#U+90fa yÅng # Character éº
+#U+90fb qiÄo # Character é»
+#U+90fc yÄ« # Character é¼
+#U+90fd dÅu # Character é½
+#U+90fe yÇn # Character é¾
+U+90ff méi # Character é¿
diff --git a/resources/chars/latin1/row91.trans b/resources/chars/latin1/row91.trans
new file mode 100644
index 0000000..8fdc1bd
--- /dev/null
+++ b/resources/chars/latin1/row91.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+9100 ruò # Character é
+U+9101 bèi # Character é
+U+9102 è # Character é
+U+9103 yú # Character é
+U+9104 juà n # Character é
+#U+9105 yÇ # Character é
+U+9106 yùn # Character é
+U+9107 hòu # Character é
+U+9108 kuà # Character é
+#U+9109 xiÄng # Character é
+#U+910a xiÄng # Character é
+#U+910b sÅu # Character é
+U+910c táng # Character é
+U+910d mÃng # Character é
+U+910e xì # Character é
+U+910f rù # Character é
+U+9110 chù # Character é
+#U+9111 zÄ« # Character é
+#U+9112 zÅu # Character é
+U+9113 jú # Character é
+#U+9114 wÅ« # Character é
+#U+9115 xiÄng # Character é
+U+9116 yún # Character é
+U+9117 hà o # Character é
+#U+9118 yÅng # Character é
+#U+9119 bÇ # Character é
+U+911a mò # Character é
+U+911b cháo # Character é
+#U+911c fÅ« # Character é
+#U+911d liÇo # Character é
+U+911e yÃn # Character é
+#U+911f zhuÄn # Character é
+U+9120 hù # Character é
+#U+9121 qiÄo # Character é¡
+#U+9122 yÄn # Character é¢
+#U+9123 zhÄng # Character é£
+U+9124 fà n # Character é¤
+#U+9125 qiÄo # Character é¥
+#U+9126 xÇ # Character é¦
+U+9127 dèng # Character é§
+U+9128 bì # Character é¨
+U+9129 xÃn # Character é©
+U+912a bì # Character éª
+U+912b céng # Character é«
+U+912c wéi # Character é¬
+U+912d zhèng # Character é
+U+912e mà o # Character é®
+U+912f shà n # Character é¯
+U+9130 lÃn # Character é°
+U+9131 pó # Character é±
+#U+9132 dÄn # Character é²
+U+9133 méng # Character é³
+U+9134 yè # Character é´
+#U+9135 cÄo # Character éµ
+U+9136 kuà i # Character é¶
+#U+9137 fÄng # Character é·
+U+9138 méng # Character é¸
+#U+9139 zÅu # Character é¹
+U+913a kuà ng # Character éº
+U+913b lián # Character é»
+U+913c zà n # Character é¼
+U+913d chán # Character é½
+#U+913e yÅu # Character é¾
+U+913f qà # Character é¿
+#U+9140 yÄn # Character é
+U+9141 chán # Character é
+U+9142 zà n # Character é
+U+9143 lÃng # Character é
+#U+9144 huÄn # Character é
+#U+9145 xÄ« # Character é
+#U+9146 fÄng # Character é
+U+9147 zà n # Character é
+U+9148 lì # Character é
+#U+9149 yÇu # Character é
+#U+914a dÇng # Character é
+U+914b qiú # Character é
+U+914c zhuó # Character é
+U+914d pèi # Character é
+U+914e zhòu # Character é
+U+914f yà # Character é
+#U+9150 hÇng # Character é
+#U+9151 yÇ # Character é
+#U+9152 jiÇ # Character é
+#U+9153 yÇn # Character é
+U+9154 zuì # Character é
+U+9155 máo # Character é
+#U+9156 dÄn # Character é
+U+9157 xù # Character é
+U+9158 tóu # Character é
+#U+9159 zhÄn # Character é
+#U+915a fÄn # Character é
+U+915b ? # Character é
+U+915c ? # Character é
+U+915d yùn # Character é
+U+915e tà i # Character é
+#U+915f tiÄn # Character é
+#U+9160 qiÇ # Character é
+U+9161 tuó # Character é
¡
+U+9162 zuò # Character é
¢
+#U+9163 hÄn # Character é
£
+#U+9164 gÅ« # Character é
¤
+#U+9165 sÅ« # Character é
¥
+U+9166 pò # Character é
¦
+U+9167 chóu # Character é
§
+U+9168 zà i # Character é
¨
+U+9169 mÃng # Character é
©
+U+916a luò # Character é
ª
+U+916b chuò # Character é
«
+U+916c chou # Character é
¬
+U+916d yòu # Character é
+U+916e tóng # Character é
®
+#U+916f zhÇ # Character é
¯
+#U+9170 xiÄn # Character é
°
+U+9171 jià ng # Character é
±
+U+9172 chéng # Character é
²
+U+9173 yìn # Character é
³
+U+9174 tú # Character é
´
+U+9175 jià o # Character é
µ
+U+9176 méi # Character é
¶
+U+9177 kù # Character é
·
+#U+9178 suÄn # Character é
¸
+U+9179 lèi # Character é
¹
+U+917a pú # Character é
º
+U+917b zuì # Character é
»
+#U+917c hÇi # Character é
¼
+U+917d yà n # Character é
½
+#U+917e xÇ # Character é
¾
+U+917f nià ng # Character é
¿
+U+9180 wéi # Character é
+U+9181 lù # Character é
+#U+9182 lÇn # Character é
+#U+9183 yÄn # Character é
+U+9184 táo # Character é
+#U+9185 pÄi # Character é
+#U+9186 zhÇn # Character é
+U+9187 chún # Character é
+U+9188 tán # Character é
+U+9189 zuì # Character é
+U+918a chuò # Character é
+U+918b cù # Character é
+#U+918c kÅ«n # Character é
+U+918d tà # Character é
+U+918e mián # Character é
+#U+918f dÅ« # Character é
+U+9190 hú # Character é
+#U+9191 xÇ # Character é
+#U+9192 xÇng # Character é
+#U+9193 tÇn # Character é
+#U+9194 jiÅ« # Character é
+U+9195 chún # Character é
+U+9196 yùn # Character é
+U+9197 pò # Character é
+U+9198 kè # Character é
+#U+9199 sÅu # Character é
+U+919a mà # Character é
+U+919b quán # Character é
+#U+919c chÇu # Character é
+U+919d cuó # Character é
+U+919e yùn # Character é
+U+919f yòng # Character é
+U+91a0 Ã ng # Character é
+U+91a1 zhà # Character é¡
+#U+91a2 hÇi # Character é¢
+U+91a3 táng # Character é£
+U+91a4 jià ng # Character é¤
+#U+91a5 piÇo # Character é¥
+#U+91a6 shÇn # Character é¦
+U+91a7 yù # Character é§
+U+91a8 là # Character é¨
+U+91a9 záo # Character é©
+U+91aa láo # Character éª
+#U+91ab yÄ« # Character é«
+U+91ac jià ng # Character é¬
+#U+91ad pÅ« # Character é
+U+91ae jià o # Character é®
+#U+91af xÄ« # Character é¯
+U+91b0 tán # Character é°
+U+91b1 pò # Character é±
+U+91b2 nóng # Character é²
+U+91b3 yì # Character é³
+#U+91b4 lÇ # Character é´
+U+91b5 jù # Character éµ
+U+91b6 jià o # Character é¶
+U+91b7 yì # Character é·
+U+91b8 nià ng # Character é¸
+U+91b9 rú # Character é¹
+#U+91ba xÅ«n # Character éº
+U+91bb chóu # Character é»
+U+91bc yà n # Character é¼
+U+91bd lÃng # Character é½
+U+91be mà # Character é¾
+U+91bf mà # Character é¿
+U+91c0 nià ng # Character é
+U+91c1 xìn # Character é
+U+91c2 jià o # Character é
+#U+91c3 xÇ # Character é
+U+91c4 mà # Character é
+U+91c5 yà n # Character é
+U+91c6 bià n # Character é
+#U+91c7 cÇi # Character é
+U+91c8 shì # Character é
+U+91c9 yòu # Character é
+U+91ca shì # Character é
+U+91cb shì # Character é
+#U+91cc lÇ # Character é
+U+91cd zhòng # Character é
+#U+91ce yÄ # Character é
+U+91cf lià ng # Character é
+U+91d0 là # Character é
+#U+91d1 jÄ«n # Character é
+U+91d2 ? # Character é
+U+91d3 qiú # Character é
+#U+91d4 yÇ # Character é
+#U+91d5 diÇo # Character é
+#U+91d6 dÄo # Character é
+#U+91d7 zhÄo # Character é
+#U+91d8 dÄ«ng # Character é
+U+91d9 pò # Character é
+U+91da qiú # Character é
+U+91db hé # Character é
+#U+91dc fÇ # Character é
+#U+91dd zhÄn # Character é
+U+91de zhà # Character é
+#U+91df bÄ # Character é
+U+91e0 luà n # Character é
+#U+91e1 fÇ # Character é¡
+U+91e2 nái # Character é¢
+U+91e3 dià o # Character é£
+U+91e4 shà n # Character é¤
+#U+91e5 qiÇo # Character é¥
+U+91e6 kòu # Character é¦
+U+91e7 chuà n # Character é§
+#U+91e8 zÇ # Character é¨
+U+91e9 fán # Character é©
+U+91ea yú # Character éª
+U+91eb huá # Character é«
+U+91ec hà n # Character é¬
+#U+91ed gÅng # Character é
+U+91ee qà # Character é®
+U+91ef máng # Character é¯
+U+91f0 rì # Character é°
+U+91f1 dì # Character é±
+U+91f2 sì # Character é²
+U+91f3 xì # Character é³
+U+91f4 yì # Character é´
+#U+91f5 chÄi # Character éµ
+#U+91f6 shÄ« # Character é¶
+#U+91f7 tÇ # Character é·
+U+91f8 xì # Character é¸
+#U+91f9 nÇ # Character é¹
+#U+91fa qiÄn # Character éº
+U+91fb ? # Character é»
+U+91fc jià n # Character é¼
+#U+91fd pÄ« # Character é½
+U+91fe yé # Character é¾
+U+91ff yÃn # Character é¿
diff --git a/resources/chars/latin1/row92.trans b/resources/chars/latin1/row92.trans
new file mode 100644
index 0000000..d45d023
--- /dev/null
+++ b/resources/chars/latin1/row92.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+9200 bÇ # Character é
+#U+9201 fÄng # Character é
+U+9202 chén # Character é
+U+9203 xÃng # Character é
+#U+9204 tÇu # Character é
+U+9205 yuè # Character é
+U+9206 yán # Character é
+#U+9207 fÅ« # Character é
+#U+9208 pÄ« # Character é
+U+9209 nà # Character é
+#U+920a xÄ«n # Character é
+U+920b é # Character é
+U+920c jué # Character é
+U+920d dùn # Character é
+#U+920e gÅu # Character é
+#U+920f yÇn # Character é
+U+9210 qián # Character é
+#U+9211 bÇn # Character é
+U+9212 jà # Character é
+U+9213 rén # Character é
+#U+9214 chÄo # Character é
+#U+9215 niÇ # Character é
+#U+9216 fÄn # Character é
+#U+9217 yÇn # Character é
+#U+9218 jÇ # Character é
+U+9219 qÃn # Character é
+U+921a pà # Character é
+#U+921b guÅ # Character é
+U+921c hóng # Character é
+U+921d yÃn # Character é
+#U+921e jÅ«n # Character é
+#U+921f shÄ« # Character é
+U+9220 yì # Character é
+#U+9221 zhÅng # Character é¡
+#U+9222 niÄ # Character é¢
+U+9223 gà i # Character é£
+U+9224 rì # Character é¤
+U+9225 huó # Character é¥
+U+9226 tà i # Character é¦
+U+9227 kà ng # Character é§
+U+9228 ? # Character é¨
+U+9229 ? # Character é©
+U+922a ? # Character éª
+U+922b ? # Character é«
+U+922c duó # Character é¬
+#U+922d zÄ« # Character é
+#U+922e nÇ # Character é®
+U+922f tú # Character é¯
+U+9230 shì # Character é°
+U+9231 mÃn # Character é±
+#U+9232 gÅ« # Character é²
+#U+9233 Ä # Character é³
+U+9234 lÃng # Character é´
+U+9235 bìng # Character éµ
+U+9236 yà # Character é¶
+#U+9237 gÇ # Character é·
+U+9238 bá # Character é¸
+#U+9239 pÄ« # Character é¹
+U+923a yù # Character éº
+U+923b sì # Character é»
+U+923c zuó # Character é¼
+U+923d bù # Character é½
+U+923e yóu # Character é¾
+U+923f dià n # Character é¿
+#U+9240 jiÇ # Character é
+#U+9241 zhÄn # Character é
+#U+9242 shÇ # Character é
+U+9243 shì # Character é
+#U+9244 tiÄ # Character é
+U+9245 jù # Character é
+#U+9246 zhÄn # Character é
+#U+9247 shÄ« # Character é
+U+9248 shé # Character é
+U+9249 xuà n # Character é
+#U+924a zhÄo # Character é
+U+924b bà o # Character é
+U+924c hé # Character é
+U+924d bì # Character é
+#U+924e shÄng # Character é
+U+924f chú # Character é
+U+9250 shà # Character é
+U+9251 bó # Character é
+U+9252 zhù # Character é
+U+9253 chì # Character é
+#U+9254 zÄ # Character é
+#U+9255 pÅ # Character é
+U+9256 tóng # Character é
+U+9257 qián # Character é
+U+9258 fú # Character é
+#U+9259 zhÇi # Character é
+#U+925a liÇ # Character é
+#U+925b qiÄn # Character é
+U+925c fú # Character é
+U+925d lì # Character é
+U+925e yuè # Character é
+#U+925f pÄ« # Character é
+#U+9260 yÄng # Character é
+U+9261 bà n # Character é¡
+#U+9262 bÅ # Character é¢
+U+9263 jié # Character é£
+#U+9264 gÅu # Character é¤
+U+9265 shù # Character é¥
+#U+9266 zhÄng # Character é¦
+#U+9267 mÇ # Character é§
+#U+9268 nÇ # Character é¨
+#U+9269 niÄ # Character é©
+U+926a dì # Character éª
+#U+926b jiÄ # Character é«
+U+926c mù # Character é¬
+U+926d dà n # Character é
+#U+926e shÄn # Character é®
+#U+926f yÇ # Character é¯
+#U+9270 sÄ« # Character é°
+U+9271 kuà ng # Character é±
+#U+9272 kÇ # Character é²
+#U+9273 bÄi # Character é³
+U+9274 jià n # Character é´
+U+9275 tóng # Character éµ
+U+9276 xÃng # Character é¶
+U+9277 hóng # Character é·
+#U+9278 jiÇo # Character é¸
+#U+9279 chÇ # Character é¹
+U+927a èr # Character éº
+U+927b gè # Character é»
+#U+927c bÇng # Character é¼
+U+927d shì # Character é½
+U+927e móu # Character é¾
+U+927f jiá # Character é¿
+U+9280 yÃn # Character é
+#U+9281 jÅ«n # Character é
+#U+9282 zhÅu # Character é
+U+9283 chòng # Character é
+U+9284 shà ng # Character é
+U+9285 tóng # Character é
+U+9286 mò # Character é
+U+9287 lèi # Character é
+#U+9288 jÄ« # Character é
+U+9289 yù # Character é
+U+928a xù # Character é
+U+928b rén # Character é
+U+928c zùn # Character é
+U+928d zhì # Character é
+#U+928e qiÅng # Character é
+U+928f shà n # Character é
+U+9290 chì # Character é
+#U+9291 xiÇn # Character é
+U+9292 xÃng # Character é
+U+9293 quán # Character é
+#U+9294 pÄ« # Character é
+#U+9295 tiÄ # Character é
+#U+9296 zhÅ« # Character é
+U+9297 hóu # Character é
+U+9298 mÃng # Character é
+#U+9299 kuÇ # Character é
+U+929a yáo # Character é
+#U+929b xiÄn # Character é
+U+929c xián # Character é
+#U+929d xiÅ« # Character é
+#U+929e jÅ«n # Character é
+#U+929f chÄ # Character é
+#U+92a0 lÇo # Character é
+U+92a1 jà # Character é¡
+#U+92a2 pÇ # Character é¢
+#U+92a3 rÇ # Character é£
+#U+92a4 mÇ # Character é¤
+#U+92a5 yÇ # Character é¥
+#U+92a6 yÄ«n # Character é¦
+#U+92a7 guÄng # Character é§
+#U+92a8 Än # Character é¨
+#U+92a9 diÅ« # Character é©
+#U+92aa yÇu # Character éª
+U+92ab sè # Character é«
+U+92ac kà o # Character é¬
+U+92ad qián # Character é
+U+92ae luán # Character é®
+U+92af ? # Character é¯
+#U+92b0 Äi # Character é°
+U+92b1 dià o # Character é±
+U+92b2 hà n # Character é²
+U+92b3 ruì # Character é³
+U+92b4 shì # Character é´
+#U+92b5 kÄng # Character éµ
+U+92b6 qiú # Character é¶
+#U+92b7 xiÄo # Character é·
+U+92b8 zhé # Character é¸
+U+92b9 xiù # Character é¹
+U+92ba zà ng # Character éº
+U+92bb tì # Character é»
+U+92bc cuò # Character é¼
+#U+92bd guÄ # Character é½
+#U+92be gÇng # Character é¾
+#U+92bf zhÅng # Character é¿
+U+92c0 dòu # Character é
+#U+92c1 lÇ # Character é
+U+92c2 méi # Character é
+U+92c3 láng # Character é
+#U+92c4 wÇn # Character é
+#U+92c5 xÄ«n # Character é
+U+92c6 yún # Character é
+U+92c7 bèi # Character é
+U+92c8 wù # Character é
+U+92c9 sù # Character é
+U+92ca yù # Character é
+U+92cb chán # Character é
+#U+92cc tÇng # Character é
+U+92cd bó # Character é
+U+92ce hà n # Character é
+U+92cf jiá # Character é
+U+92d0 hóng # Character é
+#U+92d1 cuÄn # Character é
+#U+92d2 fÄng # Character é
+#U+92d3 chÄn # Character é
+#U+92d4 wÇn # Character é
+U+92d5 zhì # Character é
+#U+92d6 sÄ« # Character é
+#U+92d7 xuÄn # Character é
+U+92d8 wú # Character é
+U+92d9 wú # Character é
+U+92da tiáo # Character é
+#U+92db gÇng # Character é
+U+92dc zhuó # Character é
+U+92dd lüè # Character é
+U+92de xÃng # Character é
+#U+92df qiÄn # Character é
+U+92e0 shèn # Character é
+U+92e1 hán # Character é¡
+U+92e2 lüè # Character é¢
+U+92e3 xié # Character é£
+U+92e4 chú # Character é¤
+U+92e5 zhèng # Character é¥
+U+92e6 jú # Character é¦
+U+92e7 xià n # Character é§
+#U+92e8 tiÄ # Character é¨
+U+92e9 máng # Character é©
+U+92ea pù # Character éª
+U+92eb là # Character é«
+U+92ec pà n # Character é¬
+U+92ed ruì # Character é
+U+92ee chéng # Character é®
+U+92ef gà o # Character é¯
+#U+92f0 lÇ # Character é°
+U+92f1 tè # Character é±
+U+92f2 ? # Character é²
+U+92f3 zhù # Character é³
+U+92f4 ? # Character é´
+#U+92f5 tÅ« # Character éµ
+#U+92f6 liÇ # Character é¶
+U+92f7 zuì # Character é·
+U+92f8 jù # Character é¸
+#U+92f9 chÇng # Character é¹
+#U+92fa yuÄn # Character éº
+U+92fb jià n # Character é»
+#U+92fc gÄng # Character é¼
+U+92fd dià o # Character é½
+U+92fe táo # Character é¾
+U+92ff cháng # Character é¿
diff --git a/resources/chars/latin1/row93.trans b/resources/chars/latin1/row93.trans
new file mode 100644
index 0000000..716ca19
--- /dev/null
+++ b/resources/chars/latin1/row93.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+9300 lún # Character é
+#U+9301 kuÇ # Character é
+U+9302 lÃng # Character é
+#U+9303 bÄi # Character é
+U+9304 lù # Character é
+U+9305 là # Character é
+#U+9306 qiÄng # Character é
+U+9307 póu # Character é
+U+9308 juà n # Character é
+U+9309 mÃn # Character é
+U+930a zuì # Character é
+U+930b péng # Character é
+U+930c à n # Character é
+U+930d pà # Character é
+U+930e xià n # Character é
+U+930f yà # Character é
+#U+9310 zhuÄ« # Character é
+U+9311 lèi # Character é
+#U+9312 Ä # Character é
+#U+9313 kÅng # Character é
+U+9314 tà # Character é
+#U+9315 kÅ«n # Character é
+#U+9316 dÇ # Character é
+U+9317 wèi # Character é
+U+9318 chuà # Character é
+#U+9319 zÄ« # Character é
+#U+931a zhÄng # Character é
+#U+931b bÄn # Character é
+#U+931c niÄ # Character é
+U+931d cóng # Character é
+U+931e qún # Character é
+U+931f tán # Character é
+U+9320 dìng # Character é
+U+9321 qà # Character é¡
+U+9322 qián # Character é¢
+U+9323 zhuó # Character é£
+U+9324 qà # Character é¤
+U+9325 yù # Character é¥
+#U+9326 jÇn # Character é¦
+#U+9327 guÇn # Character é§
+U+9328 máo # Character é¨
+#U+9329 chÄng # Character é©
+#U+932a tiÇn # Character éª
+#U+932b xÄ« # Character é«
+U+932c lià n # Character é¬
+U+932d táo # Character é
+U+932e gù # Character é®
+U+932f cuò # Character é¯
+U+9330 shù # Character é°
+#U+9331 zhÄn # Character é±
+U+9332 lù # Character é²
+#U+9333 mÄng # Character é³
+U+9334 lù # Character é´
+#U+9335 huÄ # Character éµ
+#U+9336 biÇo # Character é¶
+U+9337 gá # Character é·
+U+9338 lái # Character é¸
+#U+9339 kÄn # Character é¹
+U+933a ? # Character éº
+U+933b ? # Character é»
+U+933c nà i # Character é¼
+#U+933d wÇn # Character é½
+U+933e zà n # Character é¾
+U+933f ? # Character é¿
+U+9340 dé # Character é
+#U+9341 xiÄn # Character é
+U+9342 ? # Character é
+#U+9343 huÅ # Character é
+U+9344 lià ng # Character é
+U+9345 ? # Character é
+U+9346 mén # Character é
+#U+9347 kÇi # Character é
+#U+9348 yÄ«ng # Character é
+#U+9349 dÄ« # Character é
+U+934a lià n # Character é
+#U+934b guÅ # Character é
+#U+934c xiÇn # Character é
+U+934d dù # Character é
+U+934e tú # Character é
+U+934f wéi # Character é
+#U+9350 cÅng # Character é
+U+9351 fù # Character é
+U+9352 róu # Character é
+U+9353 jà # Character é
+U+9354 è # Character é
+U+9355 róu # Character é
+#U+9356 chÄn # Character é
+U+9357 tà # Character é
+U+9358 zhá # Character é
+U+9359 hòng # Character é
+U+935a yáng # Character é
+U+935b duà n # Character é
+#U+935c xiÄ # Character é
+U+935d yú # Character é
+#U+935e kÄng # Character é
+#U+935f xÄ«ng # Character é
+U+9360 huáng # Character é
+#U+9361 wÄi # Character é¡
+U+9362 fù # Character é¢
+#U+9363 zhÄo # Character é£
+U+9364 chá # Character é¤
+U+9365 qiè # Character é¥
+U+9366 shé # Character é¦
+#U+9367 hÅng # Character é§
+U+9368 kuà # Character é¨
+#U+9369 tiÇn # Character é©
+U+936a móu # Character éª
+#U+936b qiÄo # Character é«
+#U+936c qiÄo # Character é¬
+U+936d hóu # Character é
+#U+936e tÅu # Character é®
+#U+936f cÅng # Character é¯
+U+9370 huán # Character é°
+U+9371 yè # Character é±
+U+9372 mÃn # Character é²
+U+9373 jià n # Character é³
+#U+9374 duÄn # Character é´
+U+9375 jià n # Character éµ
+#U+9376 sÅng # Character é¶
+#U+9377 kuÄ« # Character é·
+U+9378 hú # Character é¸
+#U+9379 xuÄn # Character é¹
+#U+937a duÇ # Character éº
+U+937b jié # Character é»
+#U+937c zhÄn # Character é¼
+#U+937d biÄn # Character é½
+#U+937e zhÅng # Character é¾
+#U+937f zÄ« # Character é¿
+#U+9380 xiÅ« # Character é
+U+9381 yé # Character é
+#U+9382 mÄi # Character é
+U+9383 pà i # Character é
+#U+9384 Äi # Character é
+U+9385 jiè # Character é
+U+9386 ? # Character é
+U+9387 méi # Character é
+#U+9388 chuÅ # Character é
+U+9389 tà # Character é
+U+938a bà ng # Character é
+U+938b xiá # Character é
+U+938c lián # Character é
+#U+938d suÇ # Character é
+U+938e xì # Character é
+U+938f liú # Character é
+U+9390 zú # Character é
+U+9391 yè # Character é
+U+9392 nòu # Character é
+#U+9393 wÄng # Character é
+U+9394 róng # Character é
+U+9395 táng # Character é
+#U+9396 suÇ # Character é
+#U+9397 qiÄng # Character é
+U+9398 gé # Character é
+U+9399 shuò # Character é
+U+939a chuà # Character é
+U+939b bó # Character é
+U+939c pán # Character é
+U+939d sà # Character é
+U+939e bì # Character é
+#U+939f sÇng # Character é
+#U+93a0 gÄng # Character é
+#U+93a1 zÄ« # Character é¡
+U+93a2 wù # Character é¢
+U+93a3 yìng # Character é£
+#U+93a4 huÇng # Character é¤
+U+93a5 tiáo # Character é¥
+U+93a6 liú # Character é¦
+#U+93a7 kÇi # Character é§
+#U+93a8 sÇn # Character é¨
+#U+93a9 shÄ # Character é©
+#U+93aa sÅu # Character éª
+U+93ab wà n # Character é«
+U+93ac hà o # Character é¬
+U+93ad zhèn # Character é
+U+93ae zhèn # Character é®
+#U+93af luÇ # Character é¯
+U+93b0 yì # Character é°
+U+93b1 yuán # Character é±
+#U+93b2 tÇng # Character é²
+U+93b3 niè # Character é³
+U+93b4 xà # Character é´
+#U+93b5 jiÄ # Character éµ
+#U+93b6 gÄ # Character é¶
+#U+93b7 mÇ # Character é·
+#U+93b8 juÄn # Character é¸
+U+93b9 ? # Character é¹
+U+93ba ? # Character éº
+#U+93bb suÇ # Character é»
+U+93bc ? # Character é¼
+U+93bd ? # Character é½
+U+93be ? # Character é¾
+U+93bf ná # Character é¿
+#U+93c0 lÇ # Character é
+#U+93c1 suÇ # Character é
+#U+93c2 Åu # Character é
+U+93c3 zú # Character é
+U+93c4 tuán # Character é
+#U+93c5 xiÅ« # Character é
+U+93c6 guà n # Character é
+U+93c7 xuà n # Character é
+U+93c8 lià n # Character é
+U+93c9 shòu # Character é
+U+93ca áo # Character é
+#U+93cb mÇn # Character é
+U+93cc mò # Character é
+U+93cd luó # Character é
+U+93ce bì # Character é
+U+93cf wèi # Character é
+U+93d0 liú # Character é
+U+93d1 dà # Character é
+#U+93d2 qiÄo # Character é
+#U+93d3 cÅng # Character é
+U+93d4 yà # Character é
+U+93d5 lù # Character é
+U+93d6 áo # Character é
+#U+93d7 kÄng # Character é
+#U+93d8 qiÄng # Character é
+#U+93d9 cuÄ« # Character é
+U+93da qì # Character é
+U+93db cháng # Character é
+#U+93dc tÄng # Character é
+U+93dd mà n # Character é
+#U+93de yÅng # Character é
+#U+93df chÇn # Character é
+#U+93e0 fÄng # Character é
+U+93e1 jìng # Character é¡
+#U+93e2 biÄo # Character é¢
+U+93e3 shù # Character é£
+U+93e4 lòu # Character é¤
+U+93e5 xiù # Character é¥
+#U+93e6 cÅng # Character é¦
+U+93e7 lóng # Character é§
+U+93e8 zà n # Character é¨
+U+93e9 jià n # Character é©
+U+93ea cáo # Character éª
+U+93eb là # Character é«
+U+93ec xià # Character é¬
+#U+93ed xÄ« # Character é
+#U+93ee kÄng # Character é®
+U+93ef ? # Character é¯
+U+93f0 bèng # Character é°
+U+93f1 ? # Character é±
+U+93f2 ? # Character é²
+#U+93f3 zhÄng # Character é³
+U+93f4 lù # Character é´
+U+93f5 huá # Character éµ
+U+93f6 jà # Character é¶
+U+93f7 pú # Character é·
+U+93f8 huì # Character é¸
+#U+93f9 qiÄng # Character é¹
+#U+93fa pÅ # Character éº
+U+93fb lÃn # Character é»
+#U+93fc suÇ # Character é¼
+U+93fd xiù # Character é½
+#U+93fe sÇn # Character é¾
+#U+93ff chÄng # Character é¿
diff --git a/resources/chars/latin1/row94.trans b/resources/chars/latin1/row94.trans
new file mode 100644
index 0000000..27e75ad
--- /dev/null
+++ b/resources/chars/latin1/row94.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+9400 kuì # Character é
+#U+9401 sÄ« # Character é
+U+9402 liù # Character é
+U+9403 náo # Character é
+U+9404 héng # Character é
+#U+9405 piÄ # Character é
+U+9406 suì # Character é
+U+9407 fán # Character é
+U+9408 qiáo # Character é
+#U+9409 quÄn # Character é
+U+940a yáng # Character é
+U+940b tà ng # Character é
+U+940c xià ng # Character é
+U+940d jué # Character é
+#U+940e jiÄo # Character é
+#U+940f zÅ«n # Character é
+U+9410 liáo # Character é
+U+9411 jié # Character é
+U+9412 láo # Character é
+U+9413 duì # Character é
+U+9414 tán # Character é
+#U+9415 zÄn # Character é
+#U+9416 jÄ« # Character é
+#U+9417 jiÇn # Character é
+#U+9418 zhÅng # Character é
+#U+9419 dÄng # Character é
+U+941a yà # Character é
+U+941b yìng # Character é
+U+941c duì # Character é
+U+941d jué # Character é
+U+941e nòu # Character é
+U+941f tì # Character é
+#U+9420 pÇ # Character é
+#U+9421 tiÄ # Character é¡
+U+9422 ? # Character é¢
+U+9423 ? # Character é£
+#U+9424 dÇng # Character é¤
+U+9425 shà n # Character é¥
+#U+9426 kÄi # Character é¦
+#U+9427 jiÇn # Character é§
+U+9428 fèi # Character é¨
+U+9429 suì # Character é©
+#U+942a lÇ # Character éª
+#U+942b juÄn # Character é«
+U+942c huì # Character é¬
+U+942d yù # Character é
+U+942e lián # Character é®
+U+942f zhuó # Character é¯
+#U+9430 qiÄo # Character é°
+#U+9431 qiÄn # Character é±
+U+9432 zhuó # Character é²
+U+9433 léi # Character é³
+U+9434 bì # Character é´
+#U+9435 tiÄ # Character éµ
+U+9436 huán # Character é¶
+U+9437 yè # Character é·
+U+9438 duó # Character é¸
+#U+9439 guÇ # Character é¹
+U+943a dang # Character éº
+U+943b jù # Character é»
+U+943c fén # Character é¼
+U+943d dá # Character é½
+U+943e bèi # Character é¾
+U+943f yì # Character é¿
+U+9440 Ã i # Character é
+#U+9441 zÅng # Character é
+U+9442 xùn # Character é
+U+9443 dià o # Character é
+U+9444 zhù # Character é
+U+9445 héng # Character é
+U+9446 zhuì # Character é
+#U+9447 jÄ« # Character é
+#U+9448 niÄ # Character é
+U+9449 tà # Character é
+U+944a huò # Character é
+U+944b qìng # Character é
+#U+944c bÄ«n # Character é
+#U+944d yÄ«ng # Character é
+U+944e kuì # Character é
+U+944f nÃng # Character é
+#U+9450 xÅ« # Character é
+U+9451 jià n # Character é
+U+9452 jià n # Character é
+U+9453 ? # Character é
+#U+9454 chÇ # Character é
+U+9455 zhì # Character é
+U+9456 miè # Character é
+U+9457 là # Character é
+U+9458 léi # Character é
+#U+9459 jÄ« # Character é
+U+945a zuà n # Character é
+U+945b kuà ng # Character é
+U+945c shà ng # Character é
+U+945d péng # Character é
+U+945e là # Character é
+U+945f dú # Character é
+U+9460 shuò # Character é
+U+9461 chuò # Character é¡
+#U+9462 lÇ # Character é¢
+#U+9463 biÄo # Character é£
+U+9464 bà o # Character é¤
+#U+9465 lÇ # Character é¥
+U+9466 ? # Character é¦
+U+9467 ? # Character é§
+U+9468 lóng # Character é¨
+U+9469 è # Character é©
+U+946a lú # Character éª
+#U+946b xÄ«n # Character é«
+U+946c jià n # Character é¬
+U+946d là n # Character é
+U+946e bó # Character é®
+#U+946f jiÄn # Character é¯
+U+9470 yà o # Character é°
+U+9471 chán # Character é±
+#U+9472 xiÄng # Character é²
+U+9473 jià n # Character é³
+#U+9474 xÄ« # Character é´
+U+9475 guà n # Character éµ
+U+9476 cáng # Character é¶
+U+9477 niè # Character é·
+#U+9478 lÄi # Character é¸
+U+9479 cuà n # Character é¹
+U+947a qú # Character éº
+U+947b pà n # Character é»
+U+947c luó # Character é¼
+#U+947d zuÄn # Character é½
+U+947e luán # Character é¾
+U+947f záo # Character é¿
+U+9480 niè # Character é
+U+9481 jué # Character é
+#U+9482 tÇng # Character é
+#U+9483 shÇ # Character é
+U+9484 lán # Character é
+#U+9485 jÄ«n # Character é
+U+9486 qiú # Character é
+#U+9487 yÇ # Character é
+#U+9488 zhÄn # Character é
+#U+9489 dÄ«ng # Character é
+#U+948a zhÄo # Character é
+U+948b pò # Character é
+#U+948c diÇo # Character é
+#U+948d tÇ # Character é
+#U+948e qiÄn # Character é
+U+948f chuà n # Character é
+U+9490 shà n # Character é
+U+9491 jà # Character é
+U+9492 fán # Character é
+U+9493 dià o # Character é
+U+9494 mén # Character é
+#U+9495 nÇ # Character é
+U+9496 xà # Character é
+#U+9497 chÄi # Character é
+U+9498 xÃng # Character é
+U+9499 gà i # Character é
+U+949a bù # Character é
+U+949b tà i # Character é
+U+949c jù # Character é
+U+949d dùn # Character é
+#U+949e chÄo # Character é
+#U+949f zhÅng # Character é
+U+94a0 nà # Character é
+U+94a1 bèi # Character é¡
+#U+94a2 gÄng # Character é¢
+#U+94a3 bÇn # Character é£
+U+94a4 qián # Character é¤
+U+94a5 yà o # Character é¥
+#U+94a6 qÄ«n # Character é¦
+#U+94a7 jÅ«n # Character é§
+U+94a8 wù # Character é¨
+#U+94a9 gÅu # Character é©
+U+94aa kà ng # Character éª
+#U+94ab fÄng # Character é«
+U+94ac huó # Character é¬
+#U+94ad tÇu # Character é
+#U+94ae niÇ # Character é®
+#U+94af bÇ # Character é¯
+U+94b0 yù # Character é°
+U+94b1 qián # Character é±
+#U+94b2 zhÄng # Character é²
+U+94b3 qián # Character é³
+#U+94b4 gÇ # Character é´
+#U+94b5 bÅ # Character éµ
+#U+94b6 Ä # Character é¶
+#U+94b7 pÅ # Character é·
+U+94b8 bù # Character é¸
+U+94b9 bá # Character é¹
+U+94ba yuè # Character éº
+#U+94bb zuÄn # Character é»
+U+94bc mù # Character é¼
+U+94bd dà n # Character é½
+#U+94be jiÇ # Character é¾
+U+94bf dià n # Character é¿
+U+94c0 yóu # Character é
+#U+94c1 tiÄ # Character é
+U+94c2 bó # Character é
+U+94c3 lÃng # Character é
+U+94c4 shuò # Character é
+#U+94c5 qiÄn # Character é
+#U+94c6 liÇ # Character é
+U+94c7 bà o # Character é
+U+94c8 shì # Character é
+U+94c9 xuà n # Character é
+U+94ca shé # Character é
+U+94cb bì # Character é
+#U+94cc nÇ # Character é
+#U+94cd pÄ« # Character é
+U+94ce duó # Character é
+U+94cf xÃng # Character é
+U+94d0 kà o # Character é
+#U+94d1 lÇo # Character é
+U+94d2 èr # Character é
+U+94d3 máng # Character é
+U+94d4 yà # Character é
+#U+94d5 yÇu # Character é
+U+94d6 chéng # Character é
+U+94d7 jiá # Character é
+U+94d8 yé # Character é
+U+94d9 náo # Character é
+U+94da zhì # Character é
+U+94db dang # Character é
+U+94dc tóng # Character é
+#U+94dd lÇ # Character é
+U+94de dià o # Character é
+#U+94df yÄ«n # Character é
+#U+94e0 kÇi # Character é
+U+94e1 zhá # Character é¡
+#U+94e2 zhÅ« # Character é¢
+#U+94e3 xiÇn # Character é£
+#U+94e4 tÇng # Character é¤
+#U+94e5 diÅ« # Character é¥
+#U+94e6 xiÄn # Character é¦
+U+94e7 huá # Character é§
+U+94e8 quán # Character é¨
+#U+94e9 shÄ # Character é©
+U+94ea jiá # Character éª
+U+94eb yáo # Character é«
+U+94ec gè # Character é¬
+U+94ed mÃng # Character é
+#U+94ee zhÄng # Character é®
+U+94ef sè # Character é¯
+#U+94f0 jiÇo # Character é°
+#U+94f1 yÇ # Character é±
+#U+94f2 chÇn # Character é²
+U+94f3 chòng # Character é³
+U+94f4 tà ng # Character é´
+#U+94f5 Än # Character éµ
+U+94f6 yÃn # Character é¶
+#U+94f7 rÇ # Character é·
+U+94f8 zhù # Character é¸
+U+94f9 láo # Character é¹
+U+94fa pù # Character éº
+U+94fb wú # Character é»
+U+94fc lái # Character é¼
+U+94fd tè # Character é½
+U+94fe lià n # Character é¾
+#U+94ff kÄng # Character é¿
diff --git a/resources/chars/latin1/row95.trans b/resources/chars/latin1/row95.trans
new file mode 100644
index 0000000..c4f66dc
--- /dev/null
+++ b/resources/chars/latin1/row95.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+9500 xiÄo # Character é
+#U+9501 suÇ # Character é
+#U+9502 lÇ # Character é
+U+9503 zhèng # Character é
+U+9504 chú # Character é
+#U+9505 guÅ # Character é
+U+9506 gà o # Character é
+#U+9507 tiÄ # Character é
+U+9508 xiù # Character é
+U+9509 cuò # Character é
+U+950a lüè # Character é
+#U+950b fÄng # Character é
+#U+950c xÄ«n # Character é
+#U+950d liÇ # Character é
+#U+950e kÄi # Character é
+#U+950f jiÇn # Character é
+U+9510 ruì # Character é
+U+9511 tì # Character é
+U+9512 láng # Character é
+#U+9513 qiÄn # Character é
+U+9514 jú # Character é
+#U+9515 Ä # Character é
+#U+9516 qiÄng # Character é
+#U+9517 duÇ # Character é
+#U+9518 tiÇn # Character é
+U+9519 cuò # Character é
+U+951a máo # Character é
+#U+951b bÄn # Character é
+U+951c qà # Character é
+U+951d dé # Character é
+#U+951e kuÇ # Character é
+#U+951f kÅ«n # Character é
+#U+9520 chÄng # Character é
+#U+9521 xÄ« # Character é¡
+U+9522 gù # Character é¢
+U+9523 luó # Character é£
+U+9524 chuà # Character é¤
+#U+9525 zhuÄ« # Character é¥
+#U+9526 jÇn # Character é¦
+U+9527 zhì # Character é§
+#U+9528 xiÄn # Character é¨
+U+9529 juà n # Character é©
+#U+952a huÅ # Character éª
+U+952b póu # Character é«
+U+952c tán # Character é¬
+U+952d dìng # Character é
+U+952e jià n # Character é®
+U+952f jù # Character é¯
+#U+9530 mÄng # Character é°
+#U+9531 zÄ« # Character é±
+U+9532 qiè # Character é²
+#U+9533 yÄ«ng # Character é³
+#U+9534 kÇi # Character é´
+#U+9535 qiÄng # Character éµ
+#U+9536 sÅng # Character é¶
+U+9537 è # Character é·
+U+9538 chá # Character é¸
+#U+9539 qiÄo # Character é¹
+#U+953a zhÅng # Character éº
+U+953b duà n # Character é»
+#U+953c sÅu # Character é¼
+U+953d huáng # Character é½
+U+953e huán # Character é¾
+#U+953f Äi # Character é¿
+U+9540 dù # Character é
+#U+9541 mÄi # Character é
+U+9542 lòu # Character é
+#U+9543 zÄ« # Character é
+U+9544 fèi # Character é
+U+9545 méi # Character é
+U+9546 mò # Character é
+U+9547 zhèn # Character é
+U+9548 bó # Character é
+U+9549 gé # Character é
+U+954a niè # Character é
+#U+954b tÇng # Character é
+#U+954c juÄn # Character é
+U+954d niè # Character é
+U+954e ná # Character é
+U+954f liú # Character é
+U+9550 hà o # Character é
+U+9551 bà ng # Character é
+U+9552 yì # Character é
+#U+9553 jiÄ # Character é
+#U+9554 bÄ«n # Character é
+U+9555 róng # Character é
+#U+9556 biÄo # Character é
+#U+9557 tÄng # Character é
+U+9558 mà n # Character é
+U+9559 luó # Character é
+U+955a bèng # Character é
+#U+955b yÅng # Character é
+U+955c jìng # Character é
+U+955d dà # Character é
+U+955e zú # Character é
+U+955f xuà n # Character é
+U+9560 liú # Character é
+U+9561 tán # Character é¡
+U+9562 jué # Character é¢
+U+9563 liáo # Character é£
+U+9564 pú # Character é¤
+#U+9565 lÇ # Character é¥
+U+9566 duì # Character é¦
+U+9567 là n # Character é§
+#U+9568 pÇ # Character é¨
+U+9569 cuà n # Character é©
+#U+956a qiÄng # Character éª
+#U+956b dÄng # Character é«
+U+956c huò # Character é¬
+U+956d léi # Character é
+U+956e huán # Character é®
+U+956f zhuó # Character é¯
+U+9570 lián # Character é°
+U+9571 yì # Character é±
+#U+9572 chÇ # Character é²
+#U+9573 biÄo # Character é³
+U+9574 là # Character é´
+U+9575 chán # Character éµ
+#U+9576 xiÄng # Character é¶
+#U+9577 zhÇng # Character é·
+U+9578 cháng # Character é¸
+#U+9579 jiÇ # Character é¹
+#U+957a Ço # Character éº
+U+957b dié # Character é»
+#U+957c qÅ« # Character é¼
+#U+957d liÇo # Character é½
+U+957e mà # Character é¾
+#U+957f zhÇng # Character é¿
+U+9580 mén # Character é
+U+9581 mà # Character é
+#U+9582 shuÄn # Character é
+#U+9583 shÇn # Character é
+U+9584 huò # Character é
+U+9585 mén # Character é
+U+9586 yà n # Character é
+U+9587 bì # Character é
+U+9588 hà n # Character é
+U+9589 bì # Character é
+U+958a ? # Character é
+#U+958b kÄi # Character é
+U+958c kà ng # Character é
+#U+958d bÄng # Character é
+U+958e hóng # Character é
+U+958f rùn # Character é
+U+9590 sà n # Character é
+U+9591 xián # Character é
+U+9592 xián # Character é
+#U+9593 jiÄn # Character é
+#U+9594 mÇn # Character é
+#U+9595 xiÄ # Character é
+U+9596 ? # Character é
+U+9597 dòu # Character é
+U+9598 zhá # Character é
+U+9599 nà o # Character é
+U+959a ? # Character é
+#U+959b pÄng # Character é
+#U+959c xiÇ # Character é
+U+959d lÃng # Character é
+U+959e bià n # Character é
+U+959f bì # Character é
+U+95a0 rùn # Character é
+U+95a1 hé # Character é¡
+#U+95a2 guÄn # Character é¢
+U+95a3 gé # Character é£
+U+95a4 gé # Character é¤
+U+95a5 fá # Character é¥
+U+95a6 chù # Character é¦
+U+95a7 hòng # Character é§
+#U+95a8 guÄ« # Character é¨
+#U+95a9 mÇn # Character é©
+U+95aa ? # Character éª
+#U+95ab kÇn # Character é«
+#U+95ac lÇng # Character é¬
+#U+95ad lÇ # Character é
+U+95ae tÃng # Character é®
+U+95af shà # Character é¯
+U+95b0 jú # Character é°
+U+95b1 yuè # Character é±
+U+95b2 yuè # Character é²
+#U+95b3 chÇn # Character é³
+U+95b4 qù # Character é´
+U+95b5 lìn # Character éµ
+#U+95b6 chÄng # Character é¶
+U+95b7 shà i # Character é·
+#U+95b8 kÇn # Character é¸
+#U+95b9 yÄn # Character é¹
+U+95ba mÃn # Character éº
+U+95bb yán # Character é»
+U+95bc è # Character é¼
+#U+95bd hÅ«n # Character é½
+U+95be yù # Character é¾
+U+95bf wén # Character é¿
+U+95c0 xià ng # Character é
+#U+95c1 bÄo # Character é
+U+95c2 xià ng # Character é
+U+95c3 qù # Character é
+#U+95c4 yÇo # Character é
+U+95c5 wén # Character é
+#U+95c6 bÇn # Character é
+U+95c7 Ã n # Character é
+U+95c8 wéi # Character é
+#U+95c9 yÄ«n # Character é
+U+95ca kuò # Character é
+U+95cb què # Character é
+U+95cc lán # Character é
+#U+95cd dÅ« # Character é
+U+95ce ? # Character é
+U+95cf ? # Character é
+U+95d0 tián # Character é
+U+95d1 niè # Character é
+U+95d2 tà # Character é
+#U+95d3 kÇi # Character é
+U+95d4 hé # Character é
+U+95d5 què # Character é
+#U+95d6 chuÇng # Character é
+#U+95d7 guÄn # Character é
+U+95d8 dòu # Character é
+#U+95d9 qÇ # Character é
+#U+95da kuÄ« # Character é
+U+95db táng # Character é
+#U+95dc guÄn # Character é
+U+95dd piáo # Character é
+U+95de kà n # Character é
+U+95df xì # Character é
+U+95e0 huì # Character é
+#U+95e1 chÇn # Character é¡
+U+95e2 pì # Character é¢
+U+95e3 dà ng # Character é£
+U+95e4 huán # Character é¤
+U+95e5 tà # Character é¥
+U+95e6 wén # Character é¦
+U+95e7 ? # Character é§
+U+95e8 mén # Character é¨
+#U+95e9 shuÄn # Character é©
+#U+95ea shÇn # Character éª
+U+95eb yà n # Character é«
+U+95ec hà n # Character é¬
+U+95ed bì # Character é
+U+95ee wèn # Character é®
+#U+95ef chuÇng # Character é¯
+U+95f0 rùn # Character é°
+U+95f1 wéi # Character é±
+U+95f2 xián # Character é²
+U+95f3 hóng # Character é³
+#U+95f4 jiÄn # Character é´
+#U+95f5 mÇn # Character éµ
+U+95f6 kà ng # Character é¶
+U+95f7 mèn # Character é·
+U+95f8 zhá # Character é¸
+U+95f9 nà o # Character é¹
+#U+95fa guÄ« # Character éº
+U+95fb wén # Character é»
+U+95fc tà # Character é¼
+#U+95fd mÇn # Character é½
+#U+95fe lÇ # Character é¾
+#U+95ff kÇi # Character é¿
diff --git a/resources/chars/latin1/row96.trans b/resources/chars/latin1/row96.trans
new file mode 100644
index 0000000..19596f8
--- /dev/null
+++ b/resources/chars/latin1/row96.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+9600 fá # Character é
+U+9601 gé # Character é
+U+9602 hé # Character é
+#U+9603 kÇn # Character é
+#U+9604 jiÅ« # Character é
+U+9605 yuè # Character é
+#U+9606 lÇng # Character é
+#U+9607 dÅ« # Character é
+U+9608 yù # Character é
+#U+9609 yÄn # Character é
+#U+960a chÄng # Character é
+U+960b xì # Character é
+U+960c wén # Character é
+#U+960d hÅ«n # Character é
+U+960e yán # Character é
+U+960f è # Character é
+#U+9610 chÇn # Character é
+U+9611 lán # Character é
+U+9612 qù # Character é
+U+9613 huì # Character é
+U+9614 kuò # Character é
+U+9615 què # Character é
+U+9616 gé # Character é
+U+9617 tián # Character é
+U+9618 tà # Character é
+U+9619 què # Character é
+U+961a kà n # Character é
+U+961b huán # Character é
+U+961c fù # Character é
+U+961d fù # Character é
+U+961e lè # Character é
+U+961f duì # Character é
+U+9620 xìn # Character é
+#U+9621 qiÄn # Character é¡
+U+9622 wù # Character é¢
+U+9623 yì # Character é£
+U+9624 tuó # Character é¤
+#U+9625 yÄ«n # Character é¥
+U+9626 yáng # Character é¦
+#U+9627 dÇu # Character é§
+U+9628 è # Character é¨
+#U+9629 shÄng # Character é©
+#U+962a bÇn # Character éª
+U+962b péi # Character é«
+#U+962c kÄng # Character é¬
+#U+962d yÇn # Character é
+#U+962e ruÇn # Character é®
+#U+962f zhÇ # Character é¯
+U+9630 pà # Character é°
+#U+9631 jÇng # Character é±
+U+9632 fáng # Character é²
+U+9633 yáng # Character é³
+#U+9634 yÄ«n # Character é´
+U+9635 zhèn # Character éµ
+#U+9636 jiÄ # Character é¶
+#U+9637 chÄng # Character é·
+U+9638 è # Character é¸
+#U+9639 qÅ« # Character é¹
+#U+963a dÇ # Character éº
+#U+963b zÇ # Character é»
+U+963c zuò # Character é¼
+U+963d dià n # Character é½
+#U+963e lÇng # Character é¾
+#U+963f Ä # Character é¿
+U+9640 tuó # Character é
+U+9641 tuó # Character é
+#U+9642 pÅ # Character é
+#U+9643 bÇng # Character é
+U+9644 fù # Character é
+U+9645 jì # Character é
+U+9646 lù # Character é
+#U+9647 lÇng # Character é
+U+9648 chén # Character é
+U+9649 xÃng # Character é
+U+964a duò # Character é
+U+964b lòu # Character é
+U+964c mò # Character é
+U+964d jià ng # Character é
+#U+964e shÅ« # Character é
+U+964f duò # Character é
+U+9650 xià n # Character é
+U+9651 ér # Character é
+#U+9652 guÇ # Character é
+#U+9653 yÅ« # Character é
+#U+9654 gÄi # Character é
+#U+9655 shÇn # Character é
+U+9656 xùn # Character é
+U+9657 qià o # Character é
+U+9658 xÃng # Character é
+U+9659 chún # Character é
+U+965a fù # Character é
+U+965b bì # Character é
+U+965c xiá # Character é
+#U+965d shÇn # Character é
+#U+965e shÄng # Character é
+U+965f zhì # Character é
+#U+9660 pÅ« # Character é
+#U+9661 dÇu # Character é¡
+U+9662 yuà n # Character é¢
+U+9663 zhèn # Character é£
+U+9664 chú # Character é¤
+U+9665 xià n # Character é¥
+U+9666 ? # Character é¦
+U+9667 niè # Character é§
+#U+9668 yÇn # Character é¨
+#U+9669 xiÇn # Character é©
+U+966a péi # Character éª
+U+966b péi # Character é«
+#U+966c zÅu # Character é¬
+#U+966d yÄ« # Character é
+#U+966e duÇ # Character é®
+U+966f lún # Character é¯
+#U+9670 yÄ«n # Character é°
+#U+9671 jÅ« # Character é±
+U+9672 chuà # Character é²
+U+9673 chén # Character é³
+U+9674 pà # Character é´
+U+9675 lÃng # Character éµ
+U+9676 táo # Character é¶
+U+9677 xià n # Character é·
+U+9678 lù # Character é¸
+U+9679 ? # Character é¹
+#U+967a xiÇn # Character éº
+#U+967b yÄ«n # Character é»
+#U+967c zhÇ # Character é¼
+U+967d yáng # Character é½
+U+967e réng # Character é¾
+#U+967f shÇn # Character é¿
+U+9680 chóng # Character é
+U+9681 yà n # Character é
+#U+9682 yÄ«n # Character é
+U+9683 yú # Character é
+U+9684 tà # Character é
+U+9685 yú # Character é
+U+9686 lóng # Character é
+#U+9687 wÄi # Character é
+#U+9688 wÄi # Character é
+U+9689 niè # Character é
+U+968a duì # Character é
+U+968b suà # Character é
+#U+968c Çn # Character é
+U+968d huáng # Character é
+#U+968e jiÄ # Character é
+U+968f suà # Character é
+#U+9690 yÇn # Character é
+#U+9691 gÄi # Character é
+#U+9692 yÇn # Character é
+#U+9693 huÄ« # Character é
+U+9694 gé # Character é
+#U+9695 yÇn # Character é
+U+9696 wù # Character é
+#U+9697 wÄi # Character é
+U+9698 Ã i # Character é
+U+9699 xì # Character é
+U+969a táng # Character é
+U+969b jì # Character é
+U+969c zhà ng # Character é
+#U+969d dÇo # Character é
+U+969e áo # Character é
+U+969f xì # Character é
+#U+96a0 yÇn # Character é
+U+96a1 ? # Character é¡
+U+96a2 rà o # Character é¢
+U+96a3 lÃn # Character é£
+U+96a4 tuà # Character é¤
+U+96a5 dèng # Character é¥
+#U+96a6 pÇ # Character é¦
+U+96a7 suì # Character é§
+U+96a8 suà # Character é¨
+U+96a9 yù # Character é©
+#U+96aa xiÇn # Character éª
+#U+96ab fÄn # Character é«
+#U+96ac nÇ # Character é¬
+U+96ad ér # Character é
+#U+96ae jÄ« # Character é®
+#U+96af dÇo # Character é¯
+U+96b0 xà # Character é°
+#U+96b1 yÇn # Character é±
+U+96b2 é # Character é²
+#U+96b3 huÄ« # Character é³
+#U+96b4 lÇng # Character é´
+#U+96b5 xÄ« # Character éµ
+U+96b6 lì # Character é¶
+U+96b7 lì # Character é·
+U+96b8 lì # Character é¸
+#U+96b9 zhuÄ« # Character é¹
+U+96ba hè # Character éº
+#U+96bb zhÄ« # Character é»
+#U+96bc zhÇn # Character é¼
+U+96bd jùn # Character é½
+U+96be nán # Character é¾
+U+96bf yì # Character é¿
+U+96c0 què # Character é
+U+96c1 yà n # Character é
+U+96c2 qián # Character é
+#U+96c3 yÇ # Character é
+U+96c4 xióng # Character é
+#U+96c5 yÇ # Character é
+U+96c6 jà # Character é
+U+96c7 gù # Character é
+U+96c8 huán # Character é
+U+96c9 zhì # Character é
+U+96ca gòu # Character é
+U+96cb jùn # Character é
+U+96cc cà # Character é
+#U+96cd yÅng # Character é
+#U+96ce jÅ« # Character é
+U+96cf chú # Character é
+#U+96d0 hÅ« # Character é
+U+96d1 zá # Character é
+U+96d2 luò # Character é
+U+96d3 yú # Character é
+U+96d4 chóu # Character é
+#U+96d5 diÄo # Character é
+#U+96d6 suÄ« # Character é
+U+96d7 hà n # Character é
+U+96d8 huò # Character é
+#U+96d9 shuÄng # Character é
+U+96da guà n # Character é
+U+96db chú # Character é
+U+96dc zá # Character é
+#U+96dd yÅng # Character é
+#U+96de jÄ« # Character é
+#U+96df xÄ« # Character é
+U+96e0 chóu # Character é
+U+96e1 liù # Character é¡
+U+96e2 là # Character é¢
+U+96e3 nán # Character é£
+U+96e4 xué # Character é¤
+U+96e5 zá # Character é¥
+U+96e6 jà # Character é¦
+U+96e7 jà # Character é§
+#U+96e8 yÇ # Character é¨
+U+96e9 yú # Character é©
+#U+96ea xuÄ # Character éª
+#U+96eb nÇ # Character é«
+#U+96ec fÇu # Character é¬
+U+96ed sè # Character é
+U+96ee mù # Character é®
+U+96ef wén # Character é¯
+#U+96f0 fÄn # Character é°
+U+96f1 páng # Character é±
+U+96f2 yún # Character é²
+U+96f3 lì # Character é³
+U+96f4 lì # Character é´
+#U+96f5 Çng # Character éµ
+U+96f6 lÃng # Character é¶
+U+96f7 léi # Character é·
+U+96f8 án # Character é¸
+U+96f9 báo # Character é¹
+U+96fa méng # Character éº
+U+96fb dià n # Character é»
+U+96fc dà ng # Character é¼
+U+96fd xÃng # Character é½
+U+96fe wù # Character é¾
+U+96ff zhà o # Character é¿
diff --git a/resources/chars/latin1/row97.trans b/resources/chars/latin1/row97.trans
new file mode 100644
index 0000000..bb9a9d5
--- /dev/null
+++ b/resources/chars/latin1/row97.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+9700 xÅ« # Character é
+U+9701 jì # Character é
+U+9702 mù # Character é
+U+9703 chén # Character é
+#U+9704 xiÄo # Character é
+U+9705 zhá # Character é
+U+9706 tÃng # Character é
+U+9707 zhèn # Character é
+U+9708 pèi # Character é
+U+9709 méi # Character é
+U+970a lÃng # Character é
+#U+970b qÄ« # Character é
+#U+970c chÅu # Character é
+U+970d huò # Character é
+U+970e shà # Character é
+#U+970f fÄi # Character é
+#U+9710 wÄng # Character é
+#U+9711 zhÄn # Character é
+#U+9712 yÄ«n # Character é
+U+9713 nà # Character é
+U+9714 chòu # Character é
+U+9715 tún # Character é
+U+9716 lÃn # Character é
+U+9717 ? # Character é
+U+9718 dòng # Character é
+#U+9719 yÄ«ng # Character é
+U+971a wù # Character é
+U+971b lÃng # Character é
+#U+971c shuÄng # Character é
+U+971d lÃng # Character é
+U+971e xiá # Character é
+U+971f hóng # Character é
+#U+9720 yÄ«n # Character é
+U+9721 mò # Character é¡
+U+9722 mà i # Character é¢
+#U+9723 yÇn # Character é£
+U+9724 liù # Character é¤
+U+9725 mèng # Character é¥
+#U+9726 bÄ«n # Character é¦
+U+9727 wù # Character é§
+U+9728 wèi # Character é¨
+U+9729 huò # Character é©
+U+972a yÃn # Character éª
+U+972b xà # Character é«
+U+972c yì # Character é¬
+#U+972d Çi # Character é
+U+972e dà n # Character é®
+U+972f dèng # Character é¯
+U+9730 xià n # Character é°
+U+9731 yù # Character é±
+U+9732 lù # Character é²
+U+9733 lóng # Character é³
+U+9734 dà i # Character é´
+U+9735 jà # Character éµ
+U+9736 páng # Character é¶
+U+9737 yáng # Character é·
+U+9738 bà # Character é¸
+#U+9739 pÄ« # Character é¹
+U+973a wéi # Character éº
+U+973b ? # Character é»
+#U+973c xÇ # Character é¼
+U+973d jì # Character é½
+U+973e mái # Character é¾
+U+973f mèng # Character é¿
+U+9740 méng # Character é
+U+9741 léi # Character é
+U+9742 lì # Character é
+U+9743 huò # Character é
+#U+9744 Çi # Character é
+U+9745 fèi # Character é
+U+9746 dà i # Character é
+U+9747 lóng # Character é
+U+9748 lÃng # Character é
+U+9749 Ã i # Character é
+#U+974a fÄng # Character é
+U+974b lì # Character é
+#U+974c bÇo # Character é
+U+974d ? # Character é
+U+974e hè # Character é
+U+974f hè # Character é
+U+9750 bìng # Character é
+#U+9751 qÄ«ng # Character é
+#U+9752 qÄ«ng # Character é
+U+9753 jìng # Character é
+#U+9754 tiÄn # Character é
+#U+9755 zhÄn # Character é
+U+9756 jìng # Character é
+U+9757 chèng # Character é
+U+9758 qìng # Character é
+U+9759 jìng # Character é
+U+975a jìng # Character é
+U+975b dià n # Character é
+U+975c jìng # Character é
+#U+975d tiÄn # Character é
+#U+975e fÄi # Character é
+#U+975f fÄi # Character é
+U+9760 kà o # Character é
+#U+9761 mÇ # Character é¡
+U+9762 mià n # Character é¢
+U+9763 mià n # Character é£
+U+9764 pà o # Character é¤
+U+9765 yè # Character é¥
+#U+9766 tiÇn # Character é¦
+U+9767 huì # Character é§
+U+9768 yè # Character é¨
+U+9769 gé # Character é©
+#U+976a dÄ«ng # Character éª
+#U+976b chÄ # Character é«
+#U+976c jiÄn # Character é¬
+U+976d rèn # Character é
+U+976e dà # Character é®
+U+976f dù # Character é¯
+U+9770 wù # Character é°
+U+9771 rèn # Character é±
+U+9772 qÃn # Character é²
+U+9773 jìn # Character é³
+#U+9774 xuÄ # Character é´
+#U+9775 niÇ # Character éµ
+#U+9776 bÇ # Character é¶
+#U+9777 yÇn # Character é·
+#U+9778 sÇ # Character é¸
+U+9779 nà # Character é¹
+U+977a mò # Character éº
+#U+977b zÇ # Character é»
+U+977c dá # Character é¼
+U+977d bà n # Character é½
+U+977e yì # Character é¾
+U+977f yà o # Character é¿
+U+9780 táo # Character é
+U+9781 tuó # Character é
+U+9782 jiá # Character é
+U+9783 hóng # Character é
+U+9784 páo # Character é
+#U+9785 yÇng # Character é
+U+9786 ? # Character é
+#U+9787 yÄ«n # Character é
+U+9788 jiá # Character é
+U+9789 táo # Character é
+U+978a jà # Character é
+U+978b xié # Character é
+#U+978c Än # Character é
+#U+978d Än # Character é
+U+978e hén # Character é
+#U+978f gÇng # Character é
+U+9790 ? # Character é
+U+9791 dá # Character é
+#U+9792 qiÄo # Character é
+#U+9793 tÄ«ng # Character é
+#U+9794 wÇn # Character é
+U+9795 yìng # Character é
+#U+9796 suÄ« # Character é
+U+9797 tiáo # Character é
+U+9798 qià o # Character é
+U+9799 xuà n # Character é
+U+979a kòng # Character é
+#U+979b bÄng # Character é
+U+979c tà # Character é
+#U+979d zhÇng # Character é
+#U+979e bÇng # Character é
+U+979f kuò # Character é
+#U+97a0 jÅ« # Character é
+U+97a1 la # Character é¡
+U+97a2 xiè # Character é¢
+U+97a3 róu # Character é£
+#U+97a4 bÄng # Character é¤
+U+97a5 yì # Character é¥
+#U+97a6 qiÅ« # Character é¦
+#U+97a7 qiÅ« # Character é§
+U+97a8 hé # Character é¨
+U+97a9 xià o # Character é©
+U+97aa mù # Character éª
+U+97ab jú # Character é«
+#U+97ac jiÄn # Character é¬
+#U+97ad biÄn # Character é
+#U+97ae dÄ« # Character é®
+#U+97af jiÄn # Character é¯
+U+97b0 ? # Character é°
+#U+97b1 tÄo # Character é±
+#U+97b2 gÅu # Character é²
+U+97b3 tà # Character é³
+U+97b4 bèi # Character é´
+U+97b5 xié # Character éµ
+U+97b6 pán # Character é¶
+U+97b7 gé # Character é·
+U+97b8 bì # Character é¸
+U+97b9 kuò # Character é¹
+U+97ba ? # Character éº
+U+97bb lóu # Character é»
+U+97bc guì # Character é¼
+U+97bd qiáo # Character é½
+#U+97be xuÄ # Character é¾
+#U+97bf jÄ« # Character é¿
+#U+97c0 jiÄn # Character é
+#U+97c1 jiÄng # Character é
+U+97c2 chà n # Character é
+U+97c3 dá # Character é
+U+97c4 huò # Character é
+#U+97c5 xiÇn # Character é
+#U+97c6 qiÄn # Character é
+U+97c7 dú # Character é
+U+97c8 wà # Character é
+#U+97c9 jiÄn # Character é
+U+97ca lán # Character é
+U+97cb wéi # Character é
+U+97cc rèn # Character é
+U+97cd fú # Character é
+U+97ce mèi # Character é
+U+97cf juà n # Character é
+U+97d0 gé # Character é
+#U+97d1 wÄi # Character é
+U+97d2 qià o # Character é
+U+97d3 hán # Character é
+U+97d4 chà ng # Character é
+U+97d5 ? # Character é
+U+97d6 róu # Character é
+U+97d7 xùn # Character é
+U+97d8 shè # Character é
+#U+97d9 wÄi # Character é
+U+97da gé # Character é
+U+97db bèi # Character é
+#U+97dc tÄo # Character é
+#U+97dd gÅu # Character é
+U+97de yùn # Character é
+U+97df ? # Character é
+U+97e0 bì # Character é
+#U+97e1 wÄi # Character é¡
+U+97e2 huì # Character é¢
+U+97e3 dú # Character é£
+U+97e4 wà # Character é¤
+U+97e5 dú # Character é¥
+U+97e6 wéi # Character é¦
+U+97e7 rèn # Character é§
+U+97e8 fú # Character é¨
+U+97e9 hán # Character é©
+#U+97ea wÄi # Character éª
+U+97eb yùn # Character é«
+#U+97ec tÄo # Character é¬
+#U+97ed jiÇ # Character é
+#U+97ee jiÇ # Character é®
+#U+97ef xiÄn # Character é¯
+U+97f0 xiè # Character é°
+#U+97f1 xiÄn # Character é±
+#U+97f2 jÄ« # Character é²
+#U+97f3 yÄ«n # Character é³
+U+97f4 zá # Character é´
+U+97f5 yùn # Character éµ
+U+97f6 sháo # Character é¶
+U+97f7 lè # Character é·
+U+97f8 péng # Character é¸
+U+97f9 héng # Character é¹
+#U+97fa yÄ«ng # Character éº
+U+97fb yùn # Character é»
+U+97fc péng # Character é¼
+#U+97fd yÄ«n # Character é½
+#U+97fe yÄ«n # Character é¾
+#U+97ff xiÇng # Character é¿
diff --git a/resources/chars/latin1/row98.trans b/resources/chars/latin1/row98.trans
new file mode 100644
index 0000000..29f53f0
--- /dev/null
+++ b/resources/chars/latin1/row98.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+9800 hù # Character é
+U+9801 yè # Character é
+#U+9802 dÇng # Character é
+#U+9803 qÇng # Character é
+U+9804 pà n # Character é
+U+9805 xià ng # Character é
+U+9806 shùn # Character é
+#U+9807 hÄn # Character é
+#U+9808 xÅ« # Character é
+U+9809 yà # Character é
+U+980a xù # Character é
+U+980b gù # Character é
+U+980c sòng # Character é
+#U+980d kuÇ # Character é
+U+980e qà # Character é
+U+980f háng # Character é
+U+9810 yù # Character é
+U+9811 wán # Character é
+#U+9812 bÄn # Character é
+U+9813 dùn # Character é
+U+9814 dà # Character é
+#U+9815 dÄn # Character é
+U+9816 pà n # Character é
+#U+9817 pÅ # Character é
+#U+9818 lÇng # Character é
+U+9819 cè # Character é
+#U+981a jÇng # Character é
+#U+981b lÄi # Character é
+U+981c hé # Character é
+#U+981d qiÄo # Character é
+U+981e è # Character é
+U+981f é # Character é
+#U+9820 wÄi # Character é
+U+9821 jié # Character é ¡
+#U+9822 guÄ # Character é ¢
+#U+9823 shÄn # Character é £
+U+9824 yà # Character é ¤
+#U+9825 shÄn # Character é ¥
+U+9826 hái # Character é ¦
+#U+9827 duÄ« # Character é §
+#U+9828 piÄn # Character é ¨
+#U+9829 pÄ«ng # Character é ©
+U+982a lèi # Character é ª
+#U+982b fÇ # Character é «
+U+982c jiá # Character é ¬
+U+982d tóu # Character é
+U+982e huì # Character é ®
+U+982f kuà # Character é ¯
+U+9830 jiá # Character é °
+U+9831 lè # Character é ±
+U+9832 tian # Character é ²
+#U+9833 chÄng # Character é ³
+#U+9834 yÇng # Character é ´
+#U+9835 jÅ«n # Character é µ
+U+9836 hú # Character é ¶
+U+9837 hà n # Character é ·
+#U+9838 jÇng # Character é ¸
+U+9839 tuà # Character é ¹
+U+983a tuà # Character é º
+U+983b pÃn # Character é »
+U+983c là i # Character é ¼
+U+983d tuà # Character é ½
+#U+983e zÄ« # Character é ¾
+#U+983f zÄ« # Character é ¿
+U+9840 chuà # Character é¡
+U+9841 dìng # Character é¡
+U+9842 là i # Character é¡
+U+9843 yán # Character é¡
+U+9844 hà n # Character é¡
+#U+9845 jiÄn # Character é¡
+#U+9846 kÄ # Character é¡
+U+9847 cuì # Character é¡
+#U+9848 jiÇng # Character é¡
+#U+9849 qÄ«n # Character é¡
+U+984a yà # Character é¡
+#U+984b sÄi # Character é¡
+U+984c tà # Character é¡
+U+984d é # Character é¡
+U+984e è # Character é¡
+U+984f yán # Character é¡
+U+9850 hún # Character é¡
+#U+9851 kÇn # Character é¡
+U+9852 yóng # Character é¡
+#U+9853 zhuÄn # Character é¡
+U+9854 yán # Character é¡
+#U+9855 xiÇn # Character é¡
+U+9856 xìn # Character é¡
+#U+9857 yÇ # Character é¡
+U+9858 yuà n # Character é¡
+#U+9859 sÇng # Character é¡
+#U+985a diÄn # Character é¡
+#U+985b diÄn # Character é¡
+#U+985c jiÇng # Character é¡
+#U+985d kÅ« # Character é¡
+U+985e lèi # Character é¡
+U+985f liáo # Character é¡
+U+9860 pià o # Character é¡
+U+9861 yì # Character 顡
+U+9862 mán # Character 顢
+#U+9863 qī # Character 顣
+U+9864 rà o # Character 顤
+U+9865 hà o # Character 顥
+U+9866 qiáo # Character 顦
+U+9867 gù # Character 顧
+U+9868 xùn # Character 顨
+#U+9869 qiÄn # Character é¡©
+#U+986a huī # Character 顪
+U+986b chà n # Character 顫
+U+986c rú # Character 顬
+#U+986d hÅng # Character é¡
+#U+986e bīn # Character 顮
+#U+986f xiÇn # Character 顯
+U+9870 pÃn # Character é¡°
+U+9871 lú # Character 顱
+#U+9872 lÇn # Character 顲
+U+9873 niè # Character 顳
+U+9874 quán # Character 顴
+U+9875 yè # Character 页
+#U+9876 dÇng # Character 顶
+#U+9877 qÇng # Character é¡·
+#U+9878 hÄn # Character 顸
+U+9879 xià ng # Character 项
+U+987a shùn # Character 顺
+#U+987b xū # Character 须
+U+987c xù # Character 顼
+U+987d wán # Character 顽
+U+987e gù # Character 顾
+U+987f dùn # Character 顿
+U+9880 qà # Character é¢
+#U+9881 bÄn # Character é¢
+U+9882 sòng # Character é¢
+U+9883 háng # Character é¢
+U+9884 yù # Character é¢
+U+9885 lú # Character é¢
+#U+9886 lÇng # Character é¢
+#U+9887 pÅ # Character é¢
+#U+9888 jÇng # Character é¢
+U+9889 jié # Character é¢
+U+988a jiá # Character é¢
+U+988b tian # Character é¢
+U+988c hà n # Character é¢
+#U+988d yÇng # Character é¢
+#U+988e jiÇng # Character é¢
+U+988f hái # Character é¢
+U+9890 yà # Character é¢
+U+9891 pÃn # Character é¢
+U+9892 huì # Character é¢
+U+9893 tuà # Character é¢
+U+9894 hà n # Character é¢
+#U+9895 yÇng # Character é¢
+#U+9896 yÇng # Character é¢
+#U+9897 kÄ # Character é¢
+U+9898 tà # Character é¢
+U+9899 yóng # Character é¢
+U+989a è # Character é¢
+#U+989b zhuÄn # Character é¢
+U+989c yán # Character é¢
+U+989d é # Character é¢
+U+989e niè # Character é¢
+U+989f mán # Character é¢
+#U+98a0 diÄn # Character é¢
+#U+98a1 sÇng # Character 颡
+U+98a2 hà o # Character 颢
+U+98a3 lèi # Character 颣
+U+98a4 chà n # Character 颤
+U+98a5 rú # Character 颥
+U+98a6 pÃn # Character 颦
+U+98a7 quán # Character 颧
+#U+98a8 fÄng # Character 風
+#U+98a9 biÄo # Character 颩
+U+98aa ? # Character 颪
+U+98ab fú # Character 颫
+#U+98ac xiÄ # Character 颬
+#U+98ad zhÇn # Character é¢
+#U+98ae biÄo # Character 颮
+U+98af sà # Character 颯
+U+98b0 bá # Character 颰
+U+98b1 tái # Character 颱
+U+98b2 liè # Character 颲
+#U+98b3 guÄ # Character 颳
+U+98b4 xuà n # Character 颴
+U+98b5 shà o # Character 颵
+U+98b6 jù # Character 颶
+#U+98b7 bī # Character 颷
+#U+98b8 sī # Character 颸
+#U+98b9 wÄi # Character 颹
+U+98ba yáng # Character 颺
+U+98bb yáo # Character 颻
+#U+98bc sÅu # Character 颼
+#U+98bd kÇi # Character 颽
+#U+98be sÄo # Character 颾
+U+98bf fán # Character 颿
+U+98c0 liú # Character é£
+U+98c1 xà # Character é£
+U+98c2 liáo # Character é£
+#U+98c3 piÄo # Character é£
+#U+98c4 piÄo # Character é£
+U+98c5 liú # Character é£
+#U+98c6 biÄo # Character é£
+#U+98c7 biÄo # Character é£
+#U+98c8 biÇo # Character é£
+U+98c9 liáo # Character é£
+U+98ca ? # Character é£
+U+98cb sè # Character é£
+#U+98cc fÄng # Character é£
+#U+98cd biÄo # Character é£
+#U+98ce fÄng # Character é£
+U+98cf yáng # Character é£
+#U+98d0 zhÇn # Character é£
+#U+98d1 biÄo # Character é£
+U+98d2 sà # Character é£
+U+98d3 jù # Character é£
+#U+98d4 sÄ« # Character é£
+#U+98d5 sÅu # Character é£
+U+98d6 yáo # Character é£
+U+98d7 liú # Character é£
+#U+98d8 piÄo # Character é£
+#U+98d9 biÄo # Character é£
+#U+98da biÄo # Character é£
+#U+98db fÄi # Character é£
+#U+98dc fÄn # Character é£
+#U+98dd fÄi # Character é£
+#U+98de fÄi # Character é£
+U+98df shà # Character é£
+U+98e0 shà # Character é£
+#U+98e1 cÄn # Character 飡
+#U+98e2 jī # Character 飢
+U+98e3 dìng # Character 飣
+U+98e4 sì # Character 飤
+#U+98e5 tuŠ# Character 飥
+#U+98e6 zhÄn # Character 飦
+#U+98e7 sūn # Character 飧
+#U+98e8 xiÇng # Character 飨
+U+98e9 tún # Character 飩
+U+98ea rèn # Character 飪
+U+98eb yù # Character 飫
+U+98ec juà n # Character 飬
+U+98ed chì # Character é£
+#U+98ee yÇn # Character 飮
+U+98ef fà n # Character 飯
+U+98f0 fà n # Character 飰
+#U+98f1 sūn # Character 飱
+#U+98f2 yÇn # Character 飲
+U+98f3 zhù # Character 飳
+U+98f4 yà # Character 飴
+#U+98f5 zhÇi # Character 飵
+U+98f6 bì # Character 飶
+#U+98f7 jiÄ # Character 飷
+#U+98f8 tÄo # Character 飸
+#U+98f9 liÇ # Character 飹
+U+98fa cà # Character 飺
+U+98fb tiè # Character 飻
+U+98fc sì # Character 飼
+#U+98fd bÇo # Character 飽
+U+98fe shì # Character 飾
+U+98ff duò # Character 飿
diff --git a/resources/chars/latin1/row99.trans b/resources/chars/latin1/row99.trans
new file mode 100644
index 0000000..3a92442
--- /dev/null
+++ b/resources/chars/latin1/row99.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+9900 hà i # Character é¤
+U+9901 rèn # Character é¤
+#U+9902 tiÇn # Character é¤
+#U+9903 jiÇo # Character é¤
+U+9904 jiá # Character é¤
+#U+9905 bÇng # Character é¤
+U+9906 yáo # Character é¤
+U+9907 tóng # Character é¤
+U+9908 cà # Character é¤
+#U+9909 xiÇng # Character é¤
+#U+990a yÇng # Character é¤
+#U+990b yÇng # Character é¤
+#U+990c Är # Character é¤
+U+990d yà n # Character é¤
+U+990e le # Character é¤
+#U+990f yÄ« # Character é¤
+#U+9910 cÄn # Character é¤
+U+9911 bó # Character é¤
+#U+9912 nÄi # Character é¤
+U+9913 è # Character é¤
+#U+9914 bÅ« # Character é¤
+U+9915 jùn # Character é¤
+U+9916 dòu # Character é¤
+U+9917 sù # Character é¤
+U+9918 yú # Character é¤
+U+9919 shì # Character é¤
+U+991a yáo # Character é¤
+U+991b hún # Character é¤
+#U+991c guÇ # Character é¤
+U+991d shì # Character é¤
+U+991e jià n # Character é¤
+U+991f zhuì # Character é¤
+#U+9920 bÇng # Character é¤
+U+9921 xià n # Character 餡
+U+9922 bù # Character 餢
+U+9923 yè # Character 餣
+U+9924 tán # Character 餤
+#U+9925 fÄi # Character 餥
+#U+9926 zhÄng # Character 餦
+U+9927 wèi # Character 餧
+#U+9928 guÇn # Character 館
+U+9929 è # Character 餩
+#U+992a nuÇn # Character 餪
+U+992b hún # Character 餫
+U+992c hú # Character 餬
+U+992d huáng # Character é¤
+U+992e tiè # Character 餮
+U+992f huì # Character 餯
+#U+9930 jiÄn # Character 餰
+U+9931 hóu # Character 餱
+U+9932 hé # Character 餲
+U+9933 xÃng # Character 餳
+#U+9934 fÄn # Character 餴
+U+9935 wèi # Character 餵
+#U+9936 gÇ # Character 餶
+#U+9937 chÄ # Character 餷
+U+9938 sòng # Character 餸
+U+9939 táng # Character 餹
+U+993a bó # Character 餺
+#U+993b gÄo # Character 餻
+U+993c xì # Character 餼
+U+993d kuì # Character 餽
+U+993e liù # Character 餾
+#U+993f sÅu # Character 餿
+U+9940 táo # Character é¥
+U+9941 yè # Character é¥
+U+9942 yún # Character é¥
+U+9943 mó # Character é¥
+U+9944 táng # Character é¥
+U+9945 mán # Character é¥
+U+9946 bì # Character é¥
+U+9947 yù # Character é¥
+#U+9948 xiÅ« # Character é¥
+#U+9949 jÇn # Character é¥
+#U+994a sÇn # Character é¥
+U+994b kuì # Character é¥
+U+994c zhuà n # Character é¥
+U+994d shà n # Character é¥
+U+994e chì # Character é¥
+U+994f dà n # Character é¥
+U+9950 yì # Character é¥
+#U+9951 jÄ« # Character é¥
+U+9952 ráo # Character é¥
+#U+9953 chÄng # Character é¥
+#U+9954 yÅng # Character é¥
+#U+9955 tÄo # Character é¥
+U+9956 huì # Character é¥
+#U+9957 xiÇng # Character é¥
+#U+9958 zhÄn # Character é¥
+#U+9959 fÄn # Character é¥
+U+995a hà i # Character é¥
+U+995b méng # Character é¥
+U+995c yà n # Character é¥
+U+995d mó # Character é¥
+U+995e chán # Character é¥
+#U+995f xiÇng # Character é¥
+U+9960 luó # Character é¥
+U+9961 zuà n # Character 饡
+#U+9962 nÇng # Character 饢
+U+9963 shà # Character 饣
+U+9964 dìng # Character 饤
+#U+9965 jī # Character 饥
+#U+9966 tuŠ# Character 饦
+U+9967 xÃng # Character 饧
+U+9968 tún # Character 饨
+U+9969 xì # Character 饩
+U+996a rèn # Character 饪
+U+996b yù # Character 饫
+U+996c chì # Character 饬
+U+996d fà n # Character é¥
+#U+996e yÇn # Character 饮
+U+996f jià n # Character 饯
+U+9970 shì # Character 饰
+#U+9971 bÇo # Character 饱
+U+9972 sì # Character 饲
+U+9973 duò # Character 饳
+U+9974 yà # Character 饴
+#U+9975 Är # Character 饵
+U+9976 ráo # Character 饶
+#U+9977 xiÇng # Character 饷
+U+9978 jiá # Character 饸
+U+9979 le # Character 饹
+#U+997a jiÇo # Character 饺
+#U+997b yī # Character 饻
+#U+997c bÇng # Character 饼
+U+997d bó # Character 饽
+U+997e dòu # Character 饾
+U+997f è # Character 饿
+U+9980 yú # Character é¦
+#U+9981 nÄi # Character é¦
+U+9982 jùn # Character é¦
+#U+9983 guÇ # Character é¦
+U+9984 hún # Character é¦
+U+9985 xià n # Character é¦
+#U+9986 guÇn # Character é¦
+#U+9987 chÄ # Character é¦
+U+9988 kuì # Character é¦
+#U+9989 gÇ # Character é¦
+#U+998a sÅu # Character é¦
+U+998b chán # Character é¦
+U+998c yè # Character é¦
+U+998d mó # Character é¦
+U+998e bó # Character é¦
+U+998f liù # Character é¦
+#U+9990 xiÅ« # Character é¦
+#U+9991 jÇn # Character é¦
+U+9992 mán # Character é¦
+#U+9993 sÇn # Character é¦
+U+9994 zhuà n # Character é¦
+#U+9995 nÇng # Character é¦
+#U+9996 shÇu # Character é¦
+U+9997 kuà # Character é¦
+U+9998 guó # Character é¦
+#U+9999 xiÄng # Character é¦
+U+999a fén # Character é¦
+U+999b bá # Character é¦
+#U+999c nÇ # Character é¦
+U+999d bì # Character é¦
+U+999e bó # Character é¦
+U+999f tú # Character é¦
+#U+99a0 hÄn # Character é¦
+#U+99a1 fÄi # Character 馡
+#U+99a2 jiÄn # Character 馢
+#U+99a3 Än # Character 馣
+#U+99a4 Çi # Character 馤
+U+99a5 fù # Character 馥
+#U+99a6 xiÄn # Character 馦
+#U+99a7 wÄn # Character 馧
+#U+99a8 xīn # Character 馨
+U+99a9 fén # Character 馩
+#U+99aa bīn # Character 馪
+#U+99ab xīng # Character 馫
+#U+99ac mÇ # Character 馬
+U+99ad yù # Character é¦
+U+99ae féng # Character 馮
+U+99af hà n # Character 馯
+U+99b0 dì # Character 馰
+U+99b1 tuó # Character 馱
+#U+99b2 tuŠ# Character 馲
+U+99b3 chà # Character 馳
+U+99b4 xún # Character 馴
+U+99b5 zhù # Character 馵
+#U+99b6 zhī # Character 馶
+U+99b7 pèi # Character 馷
+U+99b8 xìn # Character 馸
+U+99b9 rì # Character 馹
+U+99ba sà # Character 馺
+#U+99bb yÇn # Character 馻
+U+99bc wén # Character 馼
+U+99bd zhà # Character 馽
+U+99be dà n # Character 馾
+#U+99bf lÇ # Character 馿
+U+99c0 yóu # Character é§
+U+99c1 bó # Character é§
+#U+99c2 bÇo # Character é§
+U+99c3 kuà i # Character é§
+U+99c4 tuó # Character é§
+U+99c5 yì # Character é§
+#U+99c6 qÅ« # Character é§
+U+99c7 ? # Character é§
+#U+99c8 qÅ« # Character é§
+#U+99c9 jiÅng # Character é§
+#U+99ca bÇ # Character é§
+#U+99cb zhÄo # Character é§
+#U+99cc yuÄn # Character é§
+#U+99cd pÄng # Character é§
+U+99ce zhòu # Character é§
+U+99cf jù # Character é§
+U+99d0 zhù # Character é§
+U+99d1 nú # Character é§
+#U+99d2 jÅ« # Character é§
+U+99d3 pà # Character é§
+#U+99d4 zÇng # Character é§
+U+99d5 jià # Character é§
+U+99d6 lÃng # Character é§
+#U+99d7 zhÄn # Character é§
+U+99d8 tái # Character é§
+U+99d9 fù # Character é§
+#U+99da yÇng # Character é§
+#U+99db shÇ # Character é§
+U+99dc bì # Character é§
+U+99dd tuo # Character é§
+U+99de tuó # Character é§
+U+99df sì # Character é§
+U+99e0 liú # Character é§
+U+99e1 mà # Character 駡
+U+99e2 pián # Character 駢
+U+99e3 táo # Character 駣
+U+99e4 zhì # Character 駤
+U+99e5 róng # Character 駥
+U+99e6 téng # Character 駦
+U+99e7 dòng # Character 駧
+U+99e8 xún # Character 駨
+U+99e9 quán # Character 駩
+#U+99ea shÄn # Character 駪
+#U+99eb jiÅng # Character 駫
+#U+99ec Är # Character 駬
+U+99ed hà i # Character é§
+U+99ee bó # Character 駮
+U+99ef ? # Character 駯
+#U+99f0 yīn # Character 駰
+U+99f1 luò # Character 駱
+U+99f2 ? # Character 駲
+U+99f3 dà n # Character 駳
+U+99f4 xiè # Character 駴
+U+99f5 liú # Character 駵
+U+99f6 jú # Character 駶
+#U+99f7 sÇng # Character 駷
+#U+99f8 qīn # Character 駸
+U+99f9 máng # Character 駹
+U+99fa liáng # Character 駺
+U+99fb hà n # Character 駻
+U+99fc tú # Character 駼
+U+99fd xuà n # Character 駽
+U+99fe tuì # Character 駾
+U+99ff jùn # Character 駿
diff --git a/resources/chars/latin1/row9a.trans b/resources/chars/latin1/row9a.trans
new file mode 100644
index 0000000..425d728
--- /dev/null
+++ b/resources/chars/latin1/row9a.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+9a00 é # Character é¨
+#U+9a01 chÄng # Character é¨
+#U+9a02 xÄ«n # Character é¨
+U+9a03 ái # Character é¨
+U+9a04 lù # Character é¨
+#U+9a05 zhuÄ« # Character é¨
+#U+9a06 zhÅu # Character é¨
+#U+9a07 shÄ # Character é¨
+U+9a08 pián # Character é¨
+#U+9a09 kÅ«n # Character é¨
+U+9a0a táo # Character é¨
+U+9a0b lái # Character é¨
+#U+9a0c zÅng # Character é¨
+U+9a0d kè # Character é¨
+U+9a0e qà # Character é¨
+U+9a0f qà # Character é¨
+U+9a10 yà n # Character é¨
+#U+9a11 fÄi # Character é¨
+#U+9a12 sÄo # Character é¨
+#U+9a13 yÇn # Character é¨
+U+9a14 jié # Character é¨
+#U+9a15 yÇo # Character é¨
+U+9a16 wù # Character é¨
+U+9a17 pià n # Character é¨
+#U+9a18 cÅng # Character é¨
+U+9a19 pià n # Character é¨
+U+9a1a qián # Character é¨
+#U+9a1b fÄi # Character é¨
+U+9a1c huáng # Character é¨
+#U+9a1d jiÄn # Character é¨
+U+9a1e huò # Character é¨
+U+9a1f yù # Character é¨
+U+9a20 tà # Character é¨
+U+9a21 quán # Character 騡
+U+9a22 xiá # Character 騢
+#U+9a23 zÅng # Character 騣
+U+9a24 kuà # Character 騤
+U+9a25 róu # Character 騥
+#U+9a26 sī # Character 騦
+#U+9a27 guÄ # Character 騧
+U+9a28 tuó # Character 騨
+U+9a29 kuì # Character 騩
+#U+9a2a sÅu # Character 騪
+#U+9a2b qiÄn # Character 騫
+U+9a2c chéng # Character 騬
+U+9a2d zhì # Character é¨
+U+9a2e liú # Character 騮
+U+9a2f páng # Character 騯
+U+9a30 téng # Character 騰
+#U+9a31 xī # Character 騱
+#U+9a32 cÇo # Character 騲
+U+9a33 dú # Character 騳
+U+9a34 yà n # Character 騴
+U+9a35 yuán # Character 騵
+#U+9a36 zÅu # Character 騶
+#U+9a37 sÄo # Character 騷
+U+9a38 shà n # Character 騸
+U+9a39 là # Character 騹
+U+9a3a zhì # Character 騺
+#U+9a3b shuÇng # Character 騻
+U+9a3c lù # Character 騼
+U+9a3d xà # Character 騽
+U+9a3e luó # Character 騾
+#U+9a3f zhÄng # Character 騿
+U+9a40 mò # Character é©
+U+9a41 áo # Character é©
+#U+9a42 cÄn # Character é©
+U+9a43 pià o # Character é©
+#U+9a44 cÅng # Character é©
+#U+9a45 qÅ« # Character é©
+U+9a46 bì # Character é©
+U+9a47 zhì # Character é©
+U+9a48 yù # Character é©
+#U+9a49 xÅ« # Character é©
+U+9a4a huá # Character é©
+#U+9a4b bÅ # Character é©
+U+9a4c sù # Character é©
+#U+9a4d xiÄo # Character é©
+U+9a4e lÃn # Character é©
+#U+9a4f chÇn # Character é©
+#U+9a50 dÅ«n # Character é©
+U+9a51 liú # Character é©
+U+9a52 tuó # Character é©
+#U+9a53 zÄng # Character é©
+U+9a54 tán # Character é©
+#U+9a55 jiÄo # Character é©
+#U+9a56 tiÄ # Character é©
+U+9a57 yà n # Character é©
+U+9a58 luó # Character é©
+#U+9a59 zhÄn # Character é©
+#U+9a5a jÄ«ng # Character é©
+U+9a5b yì # Character é©
+U+9a5c yè # Character é©
+#U+9a5d tuÅ # Character é©
+#U+9a5e bÄ«n # Character é©
+U+9a5f zhòu # Character é©
+U+9a60 yà n # Character é©
+U+9a61 péng # Character 驡
+#U+9a62 lÇ # Character é©¢
+U+9a63 téng # Character 驣
+#U+9a64 xiÄng # Character 驤
+U+9a65 jì # Character 驥
+#U+9a66 shuÄng # Character 驦
+U+9a67 jú # Character 驧
+#U+9a68 xī # Character 驨
+#U+9a69 huÄn # Character é©©
+U+9a6a là # Character 驪
+#U+9a6b biÄo # Character é©«
+#U+9a6c mÇ # Character 马
+U+9a6d yù # Character é©
+U+9a6e tuó # Character 驮
+U+9a6f xún # Character 驯
+U+9a70 chà # Character 驰
+#U+9a71 qū # Character 驱
+U+9a72 rì # Character 驲
+U+9a73 bó # Character 驳
+#U+9a74 lÇ # Character é©´
+#U+9a75 zÇng # Character 驵
+#U+9a76 shÇ # Character 驶
+U+9a77 sì # Character 驷
+U+9a78 fù # Character 驸
+#U+9a79 jū # Character 驹
+#U+9a7a zÅu # Character 驺
+U+9a7b zhù # Character 驻
+U+9a7c tuo # Character 驼
+U+9a7d nú # Character 驽
+U+9a7e jià # Character 驾
+U+9a7f yì # Character 驿
+U+9a80 tái # Character éª
+#U+9a81 xiÄo # Character éª
+U+9a82 mà # Character éª
+#U+9a83 yÄ«n # Character éª
+#U+9a84 jiÄo # Character éª
+U+9a85 huá # Character éª
+U+9a86 luò # Character éª
+U+9a87 hà i # Character éª
+U+9a88 pián # Character éª
+#U+9a89 biÄo # Character éª
+U+9a8a là # Character éª
+#U+9a8b chÄng # Character éª
+U+9a8c yà n # Character éª
+#U+9a8d xÄ«n # Character éª
+#U+9a8e qÄ«n # Character éª
+U+9a8f jùn # Character éª
+U+9a90 qà # Character éª
+U+9a91 qà # Character éª
+U+9a92 kè # Character éª
+#U+9a93 zhuÄ« # Character éª
+#U+9a94 zÅng # Character éª
+U+9a95 sù # Character éª
+#U+9a96 cÄn # Character éª
+U+9a97 pià n # Character éª
+U+9a98 zhì # Character éª
+U+9a99 kuà # Character éª
+#U+9a9a sÄo # Character éª
+U+9a9b wù # Character éª
+U+9a9c áo # Character éª
+U+9a9d liú # Character éª
+#U+9a9e qiÄn # Character éª
+U+9a9f shà n # Character éª
+U+9aa0 pià o # Character éª
+U+9aa1 luó # Character 骡
+#U+9aa2 cÅng # Character 骢
+#U+9aa3 chÇn # Character 骣
+U+9aa4 zhòu # Character 骤
+U+9aa5 jì # Character 骥
+#U+9aa6 shuÄng # Character 骦
+#U+9aa7 xiÄng # Character 骧
+#U+9aa8 gÇ # Character 骨
+#U+9aa9 wÄi # Character 骩
+#U+9aaa wÄi # Character 骪
+#U+9aab wÄi # Character 骫
+U+9aac yú # Character 骬
+U+9aad gà n # Character éª
+U+9aae yì # Character 骮
+#U+9aaf Äng # Character 骯
+U+9ab0 tóu # Character 骰
+U+9ab1 xiè # Character 骱
+#U+9ab2 bÄo # Character 骲
+U+9ab3 bì # Character 骳
+#U+9ab4 chī # Character 骴
+#U+9ab5 tÇ # Character 骵
+#U+9ab6 dÇ # Character 骶
+#U+9ab7 kū # Character 骷
+U+9ab8 hái # Character 骸
+#U+9ab9 qiÄo # Character 骹
+U+9aba gòu # Character 骺
+U+9abb kuà # Character 骻
+U+9abc gé # Character 骼
+#U+9abd tuÇ # Character 骽
+#U+9abe gÄng # Character 骾
+U+9abf pián # Character 骿
+U+9ac0 bì # Character é«
+#U+9ac1 kÄ # Character é«
+U+9ac2 kà # Character é«
+U+9ac3 yú # Character é«
+#U+9ac4 suÇ # Character é«
+U+9ac5 lóu # Character é«
+U+9ac6 bó # Character é«
+#U+9ac7 xiÄo # Character é«
+U+9ac8 páng # Character é«
+#U+9ac9 bÅ # Character é«
+#U+9aca cÄ« # Character é«
+#U+9acb kuÄn # Character é«
+U+9acc bìn # Character é«
+U+9acd mó # Character é«
+U+9ace liáo # Character é«
+U+9acf lóu # Character é«
+U+9ad0 náo # Character é«
+U+9ad1 dú # Character é«
+#U+9ad2 zÄng # Character é«
+#U+9ad3 suÇ # Character é«
+#U+9ad4 tÇ # Character é«
+U+9ad5 bìn # Character é«
+#U+9ad6 kuÄn # Character é«
+U+9ad7 lú # Character é«
+#U+9ad8 gÄo # Character é«
+#U+9ad9 gÄo # Character é«
+U+9ada qià o # Character é«
+#U+9adb kÄo # Character é«
+#U+9adc qiÄo # Character é«
+U+9add là o # Character é«
+U+9ade zà o # Character é«
+#U+9adf biÄo # Character é«
+#U+9ae0 kÅ«n # Character é«
+#U+9ae1 kūn # Character 髡
+U+9ae2 tì # Character 髢
+#U+9ae3 fÇng # Character é«£
+#U+9ae4 xiū # Character 髤
+U+9ae5 rán # Character 髥
+U+9ae6 máo # Character 髦
+U+9ae7 dà n # Character 髧
+#U+9ae8 kūn # Character 髨
+U+9ae9 bìn # Character 髩
+U+9aea fà # Character 髪
+U+9aeb tiáo # Character 髫
+#U+9aec pī # Character 髬
+#U+9aed zÄ« # Character é«
+#U+9aee fÇ # Character é«®
+U+9aef rán # Character 髯
+U+9af0 tì # Character 髰
+U+9af1 pà o # Character 髱
+#U+9af2 pī # Character 髲
+U+9af3 máo # Character 髳
+U+9af4 fú # Character 髴
+U+9af5 ér # Character 髵
+U+9af6 róng # Character 髶
+#U+9af7 qū # Character 髷
+U+9af8 ? # Character 髸
+#U+9af9 xiū # Character 髹
+U+9afa guà # Character 髺
+U+9afb jì # Character 髻
+U+9afc péng # Character 髼
+#U+9afd zhuÄ # Character 髽
+#U+9afe shÄo # Character 髾
+#U+9aff shÄ # Character é«¿
diff --git a/resources/chars/latin1/row9b.trans b/resources/chars/latin1/row9b.trans
new file mode 100644
index 0000000..4422391
--- /dev/null
+++ b/resources/chars/latin1/row9b.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+9b00 tì # Character é¬
+U+9b01 lì # Character é¬
+U+9b02 bìn # Character é¬
+#U+9b03 zÅng # Character é¬
+U+9b04 tì # Character é¬
+U+9b05 péng # Character é¬
+#U+9b06 sÅng # Character é¬
+#U+9b07 zhÄng # Character é¬
+U+9b08 quán # Character é¬
+#U+9b09 zÅng # Character é¬
+U+9b0a shùn # Character é¬
+#U+9b0b jiÄn # Character é¬
+#U+9b0c duÇ # Character é¬
+U+9b0d hú # Character é¬
+U+9b0e là # Character é¬
+#U+9b0f jiÅ« # Character é¬
+U+9b10 qà # Character é¬
+U+9b11 lián # Character é¬
+#U+9b12 zhÄn # Character é¬
+U+9b13 bìn # Character é¬
+U+9b14 péng # Character é¬
+U+9b15 mò # Character é¬
+#U+9b16 sÄn # Character é¬
+U+9b17 mà n # Character é¬
+U+9b18 mán # Character é¬
+#U+9b19 sÄng # Character é¬
+#U+9b1a xÅ« # Character é¬
+U+9b1b liè # Character é¬
+#U+9b1c qiÄn # Character é¬
+#U+9b1d qiÄn # Character é¬
+U+9b1e nóng # Character é¬
+U+9b1f huán # Character é¬
+U+9b20 kuà i # Character é¬
+U+9b21 nÃng # Character 鬡
+U+9b22 bìn # Character 鬢
+U+9b23 liè # Character 鬣
+U+9b24 ráng # Character 鬤
+U+9b25 dòu # Character 鬥
+U+9b26 dòu # Character 鬦
+U+9b27 nà o # Character 鬧
+#U+9b28 hÅng # Character 鬨
+U+9b29 xì # Character 鬩
+U+9b2a dòu # Character 鬪
+#U+9b2b hÇn # Character 鬫
+U+9b2c dòu # Character 鬬
+U+9b2d dòu # Character é¬
+#U+9b2e jiū # Character 鬮
+U+9b2f chà ng # Character 鬯
+U+9b30 yù # Character 鬰
+U+9b31 yù # Character 鬱
+U+9b32 lì # Character 鬲
+U+9b33 juà n # Character 鬳
+#U+9b34 fÇ # Character 鬴
+U+9b35 qián # Character 鬵
+#U+9b36 guī # Character 鬶
+#U+9b37 zÅng # Character 鬷
+U+9b38 liù # Character 鬸
+#U+9b39 guī # Character 鬹
+#U+9b3a shÄng # Character 鬺
+U+9b3b yù # Character 鬻
+#U+9b3c guÇ # Character 鬼
+U+9b3d mèi # Character 鬽
+U+9b3e jì # Character 鬾
+U+9b3f qà # Character 鬿
+U+9b40 jiè # Character é
+U+9b41 kuà # Character é
+U+9b42 hún # Character é
+U+9b43 bá # Character é
+U+9b44 pò # Character é
+U+9b45 mèi # Character é
+U+9b46 xù # Character é
+#U+9b47 yÇn # Character é
+#U+9b48 xiÄo # Character é
+#U+9b49 liÇng # Character é
+U+9b4a yù # Character é
+U+9b4b tuà # Character é
+#U+9b4c qÄ« # Character é
+#U+9b4d wÇng # Character é
+#U+9b4e liÇng # Character é
+U+9b4f wèi # Character é
+#U+9b50 jiÄn # Character é
+#U+9b51 chÄ« # Character é
+#U+9b52 piÄo # Character é
+U+9b53 bì # Character é
+U+9b54 mó # Character é
+#U+9b55 jÇ # Character é
+#U+9b56 xÅ« # Character é
+#U+9b57 chÇu # Character é
+#U+9b58 yÇn # Character é
+#U+9b59 zhÇn # Character é
+U+9b5a yú # Character é
+#U+9b5b dÄo # Character é
+U+9b5c rén # Character é
+U+9b5d jì # Character é
+U+9b5e ? # Character é
+#U+9b5f gÅng # Character é
+U+9b60 tuó # Character é
+U+9b61 dià o # Character é¡
+#U+9b62 jÇ # Character é¢
+U+9b63 xù # Character é£
+U+9b64 é # Character é¤
+U+9b65 è # Character é¥
+#U+9b66 shÄ # Character é¦
+U+9b67 háng # Character é§
+U+9b68 tún # Character é¨
+U+9b69 mò # Character é©
+U+9b6a jiè # Character éª
+#U+9b6b shÄn # Character é«
+#U+9b6c fÇn # Character é¬
+U+9b6d yuán # Character é
+U+9b6e bà # Character é®
+#U+9b6f lÇ # Character é¯
+U+9b70 wén # Character é°
+U+9b71 hú # Character é±
+U+9b72 lú # Character é²
+U+9b73 zá # Character é³
+U+9b74 fáng # Character é´
+U+9b75 fén # Character éµ
+U+9b76 nà # Character é¶
+U+9b77 yóu # Character é·
+U+9b78 ? # Character é¸
+U+9b79 ? # Character é¹
+U+9b7a hé # Character éº
+U+9b7b xiá # Character é»
+#U+9b7c qÅ« # Character é¼
+#U+9b7d hÄn # Character é½
+U+9b7e pà # Character é¾
+U+9b7f lÃng # Character é¿
+U+9b80 tuó # Character é®
+#U+9b81 bÅ # Character é®
+U+9b82 qiú # Character é®
+U+9b83 pÃng # Character é®
+U+9b84 fú # Character é®
+U+9b85 bì # Character é®
+U+9b86 jì # Character é®
+U+9b87 wèi # Character é®
+#U+9b88 jÅ« # Character é®
+#U+9b89 diÄo # Character é®
+U+9b8a bó # Character é®
+U+9b8b yóu # Character é®
+#U+9b8c gÇn # Character é®
+#U+9b8d pÄ« # Character é®
+U+9b8e nián # Character é®
+#U+9b8f xÄ«ng # Character é®
+U+9b90 tái # Character é®
+U+9b91 bà o # Character é®
+U+9b92 fù # Character é®
+#U+9b93 zhÇ # Character é®
+U+9b94 jù # Character é®
+#U+9b95 gÅ« # Character é®
+U+9b96 ? # Character é®
+U+9b97 ? # Character é®
+U+9b98 ? # Character é®
+U+9b99 tà # Character é®
+U+9b9a jié # Character é®
+U+9b9b shù # Character é®
+U+9b9c hòu # Character é®
+#U+9b9d xiÇng # Character é®
+U+9b9e ér # Character é®
+U+9b9f à n # Character é®
+U+9ba0 wéi # Character é®
+#U+9ba1 tiÄo # Character 鮡
+#U+9ba2 zhū # Character 鮢
+U+9ba3 yìn # Character 鮣
+U+9ba4 liè # Character 鮤
+U+9ba5 luò # Character 鮥
+U+9ba6 tóng # Character 鮦
+U+9ba7 yà # Character 鮧
+U+9ba8 qà # Character 鮨
+U+9ba9 bìng # Character 鮩
+#U+9baa wÄi # Character 鮪
+#U+9bab jiÇo # Character 鮫
+U+9bac bù # Character 鮬
+#U+9bad guÄ« # Character é®
+#U+9bae xiÄn # Character é®®
+U+9baf gé # Character 鮯
+U+9bb0 huà # Character 鮰
+U+9bb1 ? # Character é®±
+U+9bb2 ? # Character 鮲
+#U+9bb3 kÇo # Character 鮳
+U+9bb4 ? # Character é®´
+U+9bb5 duó # Character 鮵
+#U+9bb6 jūn # Character 鮶
+U+9bb7 tà # Character 鮷
+#U+9bb8 mÇn # Character 鮸
+#U+9bb9 xiÄo # Character 鮹
+#U+9bba zÇ # Character 鮺
+#U+9bbb shÄ # Character é®»
+#U+9bbc qīn # Character 鮼
+U+9bbd yú # Character 鮽
+#U+9bbe nÄi # Character 鮾
+U+9bbf zhé # Character 鮿
+#U+9bc0 gÇn # Character é¯
+#U+9bc1 gÄng # Character é¯
+U+9bc2 ? # Character é¯
+U+9bc3 wú # Character é¯
+U+9bc4 qiú # Character é¯
+U+9bc5 tÃng # Character é¯
+#U+9bc6 fÇ # Character é¯
+#U+9bc7 wÇn # Character é¯
+U+9bc8 yóu # Character é¯
+#U+9bc9 lÇ # Character é¯
+#U+9bca shÄ # Character é¯
+#U+9bcb shÄ # Character é¯
+U+9bcc gà o # Character é¯
+U+9bcd méng # Character é¯
+U+9bce ? # Character é¯
+U+9bcf ? # Character é¯
+U+9bd0 ? # Character é¯
+U+9bd1 ? # Character é¯
+#U+9bd2 yÇng # Character é¯
+U+9bd3 nà # Character é¯
+#U+9bd4 zÄ« # Character é¯
+U+9bd5 qà # Character é¯
+#U+9bd6 qÄ«ng # Character é¯
+#U+9bd7 xiÇng # Character é¯
+#U+9bd8 nÄi # Character é¯
+U+9bd9 chún # Character é¯
+U+9bda jì # Character é¯
+#U+9bdb diÄo # Character é¯
+U+9bdc qiè # Character é¯
+U+9bdd gù # Character é¯
+#U+9bde zhÇu # Character é¯
+#U+9bdf dÅng # Character é¯
+U+9be0 lái # Character é¯
+#U+9be1 fÄi # Character 鯡
+U+9be2 nà # Character 鯢
+U+9be3 yì # Character 鯣
+#U+9be4 kūn # Character 鯤
+U+9be5 lù # Character 鯥
+U+9be6 jiù # Character 鯦
+#U+9be7 chÄng # Character 鯧
+#U+9be8 jīng # Character 鯨
+U+9be9 lún # Character 鯩
+U+9bea lÃng # Character 鯪
+#U+9beb zÅu # Character 鯫
+U+9bec là # Character 鯬
+#U+9bed mÄng # Character é¯
+#U+9bee zÅng # Character 鯮
+U+9bef zhì # Character 鯯
+U+9bf0 nián # Character 鯰
+U+9bf1 ? # Character 鯱
+U+9bf2 ? # Character 鯲
+U+9bf3 ? # Character 鯳
+#U+9bf4 shī # Character 鯴
+#U+9bf5 shÄn # Character 鯵
+#U+9bf6 hÇn # Character 鯶
+U+9bf7 shì # Character 鯷
+U+9bf8 hóu # Character 鯸
+#U+9bf9 xīng # Character 鯹
+#U+9bfa zhū # Character 鯺
+U+9bfb là # Character 鯻
+#U+9bfc zÅng # Character 鯼
+U+9bfd jì # Character 鯽
+#U+9bfe biÄn # Character 鯾
+#U+9bff biÄn # Character 鯿
diff --git a/resources/chars/latin1/row9c.trans b/resources/chars/latin1/row9c.trans
new file mode 100644
index 0000000..763d554
--- /dev/null
+++ b/resources/chars/latin1/row9c.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+9c00 huà n # Character é°
+U+9c01 quán # Character é°
+U+9c02 zé # Character é°
+#U+9c03 wÄi # Character é°
+#U+9c04 wÄi # Character é°
+U+9c05 yú # Character é°
+#U+9c06 qÅ«n # Character é°
+U+9c07 róu # Character é°
+U+9c08 dié # Character é°
+U+9c09 huáng # Character é°
+U+9c0a lià n # Character é°
+#U+9c0b yÇn # Character é°
+U+9c0c qiú # Character é°
+#U+9c0d qiÅ« # Character é°
+U+9c0e jià n # Character é°
+U+9c0f bì # Character é°
+U+9c10 è # Character é°
+U+9c11 yáng # Character é°
+U+9c12 fù # Character é°
+#U+9c13 sÄi # Character é°
+#U+9c14 jiÇn # Character é°
+U+9c15 xiá # Character é°
+#U+9c16 tuÇ # Character é°
+U+9c17 hú # Character é°
+U+9c18 ? # Character é°
+U+9c19 ruò # Character é°
+U+9c1a ? # Character é°
+#U+9c1b wÄn # Character é°
+#U+9c1c jiÄn # Character é°
+U+9c1d hà o # Character é°
+#U+9c1e wÅ« # Character é°
+U+9c1f fáng # Character é°
+#U+9c20 sÄo # Character é°
+U+9c21 liú # Character 鰡
+#U+9c22 mÇ # Character é°¢
+U+9c23 shà # Character 鰣
+#U+9c24 shī # Character 鰤
+U+9c25 yÃn # Character é°¥
+U+9c26 ? # Character é°¦
+U+9c27 téng # Character 鰧
+U+9c28 tà # Character 鰨
+U+9c29 yáo # Character 鰩
+U+9c2a gé # Character 鰪
+U+9c2b róng # Character 鰫
+U+9c2c qián # Character 鰬
+U+9c2d qà # Character é°
+#U+9c2e wÄn # Character é°®
+U+9c2f ruò # Character 鰯
+U+9c30 ? # Character é°°
+U+9c31 lián # Character 鰱
+U+9c32 áo # Character 鰲
+U+9c33 lè # Character 鰳
+#U+9c34 huī # Character 鰴
+#U+9c35 mÇn # Character é°µ
+U+9c36 jì # Character 鰶
+U+9c37 tiáo # Character 鰷
+#U+9c38 qū # Character 鰸
+#U+9c39 jiÄn # Character é°¹
+#U+9c3a sÄo # Character é°º
+U+9c3b mán # Character 鰻
+U+9c3c xà # Character 鰼
+U+9c3d qiú # Character 鰽
+U+9c3e bià o # Character 鰾
+#U+9c3f jī # Character 鰿
+U+9c40 jì # Character é±
+U+9c41 zhú # Character é±
+#U+9c42 jiÄng # Character é±
+#U+9c43 qiÅ« # Character é±
+#U+9c44 zhuÄn # Character é±
+U+9c45 yóng # Character é±
+#U+9c46 zhÄng # Character é±
+#U+9c47 kÄng # Character é±
+#U+9c48 xuÄ # Character é±
+#U+9c49 biÄ # Character é±
+U+9c4a jué # Character é±
+#U+9c4b qÅ« # Character é±
+U+9c4c xià ng # Character é±
+#U+9c4d bÅ # Character é±
+#U+9c4e jiÄo # Character é±
+U+9c4f xún # Character é±
+U+9c50 sù # Character é±
+U+9c51 huáng # Character é±
+U+9c52 zùn # Character é±
+U+9c53 shà n # Character é±
+U+9c54 shà n # Character é±
+#U+9c55 fÄn # Character é±
+U+9c56 jué # Character é±
+U+9c57 lÃn # Character é±
+U+9c58 xún # Character é±
+U+9c59 miáo # Character é±
+#U+9c5a xÇ # Character é±
+U+9c5b ? # Character é±
+U+9c5c ? # Character é±
+U+9c5d fèn # Character é±
+#U+9c5e guÄn # Character é±
+U+9c5f hòu # Character é±
+U+9c60 kuà i # Character é±
+U+9c61 zéi # Character 鱡
+#U+9c62 sÄo # Character é±¢
+#U+9c63 zhÄn # Character é±£
+#U+9c64 gÇn # Character 鱤
+U+9c65 guì # Character 鱥
+U+9c66 shéng # Character 鱦
+#U+9c67 lÇ # Character 鱧
+U+9c68 cháng # Character 鱨
+U+9c69 ? # Character 鱩
+U+9c6a ? # Character 鱪
+U+9c6b ? # Character 鱫
+U+9c6c rú # Character 鱬
+U+9c6d jì # Character é±
+U+9c6e xù # Character 鱮
+U+9c6f huò # Character 鱯
+U+9c70 ? # Character é±°
+U+9c71 lì # Character 鱱
+U+9c72 liè # Character 鱲
+U+9c73 lì # Character 鱳
+U+9c74 miè # Character 鱴
+#U+9c75 zhÄn # Character é±µ
+#U+9c76 xiÇng # Character 鱶
+U+9c77 è # Character 鱷
+U+9c78 lú # Character 鱸
+U+9c79 guà n # Character 鱹
+U+9c7a là # Character 鱺
+#U+9c7b xiÄn # Character é±»
+U+9c7c yú # Character 鱼
+#U+9c7d dÄo # Character é±½
+#U+9c7e jÇ # Character é±¾
+U+9c7f yóu # Character 鱿
+U+9c80 tún # Character é²
+#U+9c81 lÇ # Character é²
+U+9c82 fáng # Character é²
+#U+9c83 bÄ # Character é²
+U+9c84 hé # Character é²
+#U+9c85 bÅ # Character é²
+U+9c86 pÃng # Character é²
+U+9c87 nián # Character é²
+U+9c88 lú # Character é²
+U+9c89 yóu # Character é²
+#U+9c8a zhÇ # Character é²
+U+9c8b fù # Character é²
+U+9c8c bó # Character é²
+U+9c8d bà o # Character é²
+U+9c8e hòu # Character é²
+#U+9c8f pÄ« # Character é²
+U+9c90 tái # Character é²
+#U+9c91 guÄ« # Character é²
+U+9c92 jié # Character é²
+#U+9c93 kÇo # Character é²
+#U+9c94 wÄi # Character é²
+U+9c95 ér # Character é²
+U+9c96 tóng # Character é²
+U+9c97 zé # Character é²
+U+9c98 hòu # Character é²
+U+9c99 kuà i # Character é²
+U+9c9a jì # Character é²
+#U+9c9b jiÇo # Character é²
+#U+9c9c xiÄn # Character é²
+#U+9c9d zÇ # Character é²
+#U+9c9e xiÇng # Character é²
+U+9c9f xún # Character é²
+#U+9ca0 gÄng # Character é²
+U+9ca1 là # Character 鲡
+U+9ca2 lián # Character 鲢
+#U+9ca3 jiÄn # Character é²£
+#U+9ca4 lÇ # Character 鲤
+U+9ca5 shà # Character 鲥
+U+9ca6 tiáo # Character 鲦
+#U+9ca7 gÇn # Character 鲧
+#U+9ca8 shÄ # Character 鲨
+#U+9ca9 wÇn # Character 鲩
+#U+9caa jūn # Character 鲪
+U+9cab jì # Character 鲫
+#U+9cac yÇng # Character 鲬
+#U+9cad qÄ«ng # Character é²
+U+9cae lÃng # Character é²®
+U+9caf qà # Character 鲯
+#U+9cb0 zÅu # Character é²°
+#U+9cb1 fÄi # Character é²±
+#U+9cb2 kūn # Character 鲲
+#U+9cb3 chÄng # Character é²³
+U+9cb4 gù # Character 鲴
+U+9cb5 nà # Character 鲵
+U+9cb6 nián # Character 鲶
+#U+9cb7 diÄo # Character é²·
+#U+9cb8 jīng # Character 鲸
+#U+9cb9 shÄn # Character é²¹
+#U+9cba shī # Character 鲺
+#U+9cbb zī # Character 鲻
+U+9cbc fèn # Character 鲼
+U+9cbd dié # Character 鲽
+U+9cbe bì # Character 鲾
+U+9cbf cháng # Character 鲿
+U+9cc0 shì # Character é³
+#U+9cc1 wÄn # Character é³
+#U+9cc2 wÄi # Character é³
+#U+9cc3 sÄi # Character é³
+U+9cc4 è # Character é³
+#U+9cc5 qiÅ« # Character é³
+U+9cc6 fù # Character é³
+U+9cc7 huáng # Character é³
+U+9cc8 quán # Character é³
+#U+9cc9 jiÄng # Character é³
+#U+9cca biÄn # Character é³
+#U+9ccb sÄo # Character é³
+U+9ccc áo # Character é³
+U+9ccd qà # Character é³
+U+9cce tà # Character é³
+U+9ccf yÃn # Character é³
+U+9cd0 yáo # Character é³
+U+9cd1 fáng # Character é³
+#U+9cd2 jiÄn # Character é³
+U+9cd3 lè # Character é³
+U+9cd4 bià o # Character é³
+#U+9cd5 xuÄ # Character é³
+#U+9cd6 biÄ # Character é³
+U+9cd7 mán # Character é³
+#U+9cd8 mÇn # Character é³
+U+9cd9 yóng # Character é³
+U+9cda wèi # Character é³
+U+9cdb xà # Character é³
+U+9cdc jué # Character é³
+U+9cdd shà n # Character é³
+U+9cde lÃn # Character é³
+U+9cdf zùn # Character é³
+U+9ce0 huò # Character é³
+#U+9ce1 gÇn # Character 鳡
+#U+9ce2 lÇ # Character é³¢
+#U+9ce3 zhÄn # Character é³£
+#U+9ce4 guÇn # Character 鳤
+#U+9ce5 niÇo # Character é³¥
+#U+9ce6 yÇ # Character 鳦
+U+9ce7 fú # Character 鳧
+U+9ce8 lì # Character 鳨
+#U+9ce9 jiū # Character 鳩
+#U+9cea bÇ # Character 鳪
+U+9ceb yà n # Character 鳫
+U+9cec fú # Character 鳬
+#U+9ced diÄo # Character é³
+#U+9cee jī # Character 鳮
+U+9cef fèng # Character 鳯
+U+9cf0 ? # Character é³°
+#U+9cf1 gÄn # Character é³±
+#U+9cf2 shī # Character 鳲
+U+9cf3 fèng # Character 鳳
+U+9cf4 mÃng # Character é³´
+#U+9cf5 bÇo # Character é³µ
+#U+9cf6 yuÄn # Character 鳶
+#U+9cf7 zhī # Character 鳷
+U+9cf8 hù # Character 鳸
+U+9cf9 qÃn # Character é³¹
+#U+9cfa fū # Character 鳺
+#U+9cfb fÄn # Character é³»
+U+9cfc wén # Character 鳼
+#U+9cfd jiÄn # Character é³½
+#U+9cfe shī # Character 鳾
+U+9cff yù # Character 鳿
diff --git a/resources/chars/latin1/row9d.trans b/resources/chars/latin1/row9d.trans
new file mode 100644
index 0000000..87c1c79
--- /dev/null
+++ b/resources/chars/latin1/row9d.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+9d00 fÇu # Character é´
+#U+9d01 yiÄo # Character é´
+U+9d02 juè # Character é´
+U+9d03 jué # Character é´
+#U+9d04 pÄ« # Character é´
+#U+9d05 huÄn # Character é´
+U+9d06 zhèn # Character é´
+#U+9d07 bÇo # Character é´
+U+9d08 yà n # Character é´
+#U+9d09 yÄ # Character é´
+U+9d0a zhèng # Character é´
+#U+9d0b fÄng # Character é´
+U+9d0c fèng # Character é´
+U+9d0d wén # Character é´
+#U+9d0e Åu # Character é´
+U+9d0f tè # Character é´
+#U+9d10 jiÄ # Character é´
+U+9d11 nú # Character é´
+U+9d12 lÃng # Character é´
+U+9d13 miè # Character é´
+U+9d14 fú # Character é´
+U+9d15 tuó # Character é´
+U+9d16 wén # Character é´
+U+9d17 lì # Character é´
+U+9d18 bià n # Character é´
+U+9d19 zhì # Character é´
+#U+9d1a gÄ # Character é´
+#U+9d1b yuÄn # Character é´
+#U+9d1c zÄ« # Character é´
+U+9d1d qú # Character é´
+#U+9d1e xiÄo # Character é´
+#U+9d1f zhÄ« # Character é´
+U+9d20 dà n # Character é´
+#U+9d21 jū # Character 鴡
+U+9d22 yòu # Character 鴢
+#U+9d23 gū # Character 鴣
+#U+9d24 zhÅng # Character é´¤
+U+9d25 yù # Character 鴥
+#U+9d26 yÄng # Character é´¦
+U+9d27 ròng # Character 鴧
+#U+9d28 yÄ # Character é´¨
+#U+9d29 tiÄ # Character é´©
+U+9d2a yù # Character 鴪
+U+9d2b ? # Character é´«
+#U+9d2c yīng # Character 鴬
+#U+9d2d zhuÄ« # Character é´
+#U+9d2e wū # Character 鴮
+U+9d2f ér # Character 鴯
+#U+9d30 guÄ # Character é´°
+U+9d31 Ã i # Character é´±
+#U+9d32 zhī # Character 鴲
+U+9d33 yà n # Character 鴳
+U+9d34 héng # Character 鴴
+#U+9d35 jiÄo # Character é´µ
+U+9d36 jà # Character 鴶
+U+9d37 liè # Character 鴷
+#U+9d38 zhū # Character 鴸
+U+9d39 rén # Character 鴹
+U+9d3a yà # Character 鴺
+U+9d3b hóng # Character 鴻
+U+9d3c luò # Character 鴼
+U+9d3d rú # Character 鴽
+U+9d3e móu # Character 鴾
+#U+9d3f gÄ # Character é´¿
+U+9d40 rèn # Character éµ
+#U+9d41 jiÄo # Character éµ
+#U+9d42 xiÅ« # Character éµ
+#U+9d43 zhÅu # Character éµ
+#U+9d44 zhÄ« # Character éµ
+U+9d45 luò # Character éµ
+U+9d46 ? # Character éµ
+U+9d47 ? # Character éµ
+U+9d48 ? # Character éµ
+U+9d49 luán # Character éµ
+U+9d4a jiá # Character éµ
+U+9d4b jì # Character éµ
+U+9d4c yú # Character éµ
+#U+9d4d huÄn # Character éµ
+#U+9d4e tuÇ # Character éµ
+#U+9d4f bÅ« # Character éµ
+U+9d50 wú # Character éµ
+#U+9d51 juÄn # Character éµ
+U+9d52 yù # Character éµ
+U+9d53 bó # Character éµ
+U+9d54 xùn # Character éµ
+U+9d55 xùn # Character éµ
+U+9d56 bì # Character éµ
+#U+9d57 xÄ« # Character éµ
+U+9d58 jùn # Character éµ
+U+9d59 jú # Character éµ
+U+9d5a tú # Character éµ
+#U+9d5b jÄ«ng # Character éµ
+U+9d5c tà # Character éµ
+U+9d5d é # Character éµ
+U+9d5e é # Character éµ
+U+9d5f kuáng # Character éµ
+U+9d60 hú # Character éµ
+#U+9d61 wÇ # Character 鵡
+#U+9d62 shÄn # Character éµ¢
+U+9d63 là i # Character 鵣
+U+9d64 ? # Character 鵤
+U+9d65 ? # Character éµ¥
+U+9d66 lù # Character 鵦
+U+9d67 pÃng # Character 鵧
+#U+9d68 shū # Character 鵨
+U+9d69 fú # Character 鵩
+#U+9d6a Än # Character 鵪
+U+9d6b zhà o # Character 鵫
+U+9d6c péng # Character 鵬
+U+9d6d qÃn # Character éµ
+#U+9d6e qiÄn # Character éµ®
+#U+9d6f bÄi # Character 鵯
+#U+9d70 diÄo # Character éµ°
+U+9d71 lù # Character 鵱
+U+9d72 que # Character éµ²
+#U+9d73 jiÄn # Character éµ³
+U+9d74 jú # Character 鵴
+U+9d75 tù # Character 鵵
+#U+9d76 yÄ # Character 鵶
+#U+9d77 yuÄn # Character éµ·
+U+9d78 qà # Character 鵸
+U+9d79 là # Character 鵹
+U+9d7a yè # Character 鵺
+#U+9d7b zhuī # Character 鵻
+#U+9d7c kÅng # Character éµ¼
+U+9d7d zhuì # Character 鵽
+#U+9d7e kūn # Character 鵾
+#U+9d7f shÄng # Character 鵿
+U+9d80 qà # Character é¶
+#U+9d81 jÄ«ng # Character é¶
+U+9d82 yì # Character é¶
+U+9d83 yì # Character é¶
+#U+9d84 jÄ«ng # Character é¶
+#U+9d85 zÄ« # Character é¶
+U+9d86 lái # Character é¶
+#U+9d87 dÅng # Character é¶
+#U+9d88 qÄ« # Character é¶
+U+9d89 chun # Character é¶
+#U+9d8a gÄng # Character é¶
+#U+9d8b jÅ« # Character é¶
+#U+9d8c qÅ« # Character é¶
+U+9d8d ? # Character é¶
+U+9d8e ? # Character é¶
+#U+9d8f jÄ« # Character é¶
+U+9d90 shù # Character é¶
+U+9d91 ? # Character é¶
+U+9d92 chì # Character é¶
+U+9d93 miáo # Character é¶
+U+9d94 róu # Character é¶
+#U+9d95 Än # Character é¶
+#U+9d96 qiÅ« # Character é¶
+U+9d97 tà # Character é¶
+U+9d98 hú # Character é¶
+U+9d99 tà # Character é¶
+U+9d9a è # Character é¶
+#U+9d9b jiÄ # Character é¶
+U+9d9c máo # Character é¶
+U+9d9d fú # Character é¶
+#U+9d9e chÅ«n # Character é¶
+U+9d9f tú # Character é¶
+#U+9da0 yÇn # Character é¶
+U+9da1 hé # Character 鶡
+U+9da2 yuán # Character 鶢
+#U+9da3 piÄn # Character 鶣
+U+9da4 yùn # Character 鶤
+U+9da5 méi # Character 鶥
+U+9da6 hú # Character 鶦
+#U+9da7 yīng # Character 鶧
+U+9da8 dùn # Character 鶨
+U+9da9 mù # Character 鶩
+U+9daa jú # Character 鶪
+U+9dab ? # Character 鶫
+#U+9dac cÄng # Character 鶬
+#U+9dad fÇng # Character é¶
+U+9dae gù # Character 鶮
+#U+9daf yīng # Character 鶯
+U+9db0 yuán # Character 鶰
+#U+9db1 xuÄn # Character 鶱
+#U+9db2 wÄng # Character 鶲
+#U+9db3 shī # Character 鶳
+U+9db4 hè # Character 鶴
+U+9db5 chú # Character 鶵
+U+9db6 táng # Character 鶶
+U+9db7 xià # Character 鶷
+U+9db8 ruò # Character 鶸
+U+9db9 liú # Character 鶹
+U+9dba jà # Character 鶺
+U+9dbb gú # Character 鶻
+#U+9dbc jiÄn # Character 鶼
+#U+9dbd zhÇn # Character 鶽
+U+9dbe hà n # Character 鶾
+#U+9dbf zī # Character 鶿
+#U+9dc0 zÄ« # Character é·
+U+9dc1 nì # Character é·
+U+9dc2 yà o # Character é·
+U+9dc3 yà n # Character é·
+#U+9dc4 jÄ« # Character é·
+U+9dc5 lì # Character é·
+U+9dc6 tián # Character é·
+U+9dc7 kòu # Character é·
+#U+9dc8 tÄ« # Character é·
+#U+9dc9 tÄ« # Character é·
+U+9dca nì # Character é·
+U+9dcb tú # Character é·
+#U+9dcc mÇ # Character é·
+#U+9dcd jiÄo # Character é·
+#U+9dce gÄo # Character é·
+U+9dcf tián # Character é·
+U+9dd0 chén # Character é·
+U+9dd1 lì # Character é·
+#U+9dd2 zhuÄn # Character é·
+U+9dd3 zhè # Character é·
+U+9dd4 áo # Character é·
+#U+9dd5 yÇo # Character é·
+#U+9dd6 yÄ« # Character é·
+#U+9dd7 Åu # Character é·
+U+9dd8 chì # Character é·
+U+9dd9 zhì # Character é·
+U+9dda liáo # Character é·
+U+9ddb róng # Character é·
+U+9ddc lóu # Character é·
+U+9ddd bì # Character é·
+#U+9dde shuÄng # Character é·
+U+9ddf zhuó # Character é·
+U+9de0 yú # Character é·
+U+9de1 wú # Character 鷡
+U+9de2 jué # Character 鷢
+U+9de3 yÃn # Character é·£
+U+9de4 quán # Character 鷤
+#U+9de5 sī # Character 鷥
+#U+9de6 jiÄo # Character é·¦
+U+9de7 yì # Character 鷧
+#U+9de8 huÄ # Character é·¨
+U+9de9 bì # Character 鷩
+#U+9dea yīng # Character 鷪
+U+9deb sù # Character 鷫
+U+9dec huáng # Character 鷬
+U+9ded fán # Character é·
+#U+9dee jiÄo # Character é·®
+U+9def liáo # Character 鷯
+U+9df0 yà n # Character 鷰
+#U+9df1 kÄo # Character é·±
+U+9df2 jiù # Character 鷲
+U+9df3 xián # Character 鷳
+U+9df4 xián # Character 鷴
+U+9df5 tú # Character 鷵
+#U+9df6 mÇi # Character é·¶
+#U+9df7 zūn # Character 鷷
+U+9df8 yù # Character 鷸
+#U+9df9 yīng # Character 鷹
+U+9dfa lù # Character 鷺
+U+9dfb tuán # Character 鷻
+U+9dfc xián # Character 鷼
+U+9dfd xué # Character 鷽
+U+9dfe yì # Character 鷾
+U+9dff pì # Character 鷿
diff --git a/resources/chars/latin1/row9e.trans b/resources/chars/latin1/row9e.trans
new file mode 100644
index 0000000..c1e6162
--- /dev/null
+++ b/resources/chars/latin1/row9e.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+9e00 shú # Character é¸
+U+9e01 luó # Character é¸
+#U+9e02 qÄ« # Character é¸
+U+9e03 yà # Character é¸
+U+9e04 jà # Character é¸
+U+9e05 zhé # Character é¸
+U+9e06 yú # Character é¸
+#U+9e07 zhÄn # Character é¸
+U+9e08 yè # Character é¸
+U+9e09 yáng # Character é¸
+U+9e0a pì # Character é¸
+U+9e0b nÃng # Character é¸
+U+9e0c huò # Character é¸
+U+9e0d mà # Character é¸
+#U+9e0e yÄ«ng # Character é¸
+U+9e0f méng # Character é¸
+U+9e10 dà # Character é¸
+U+9e11 yuè # Character é¸
+U+9e12 yú # Character é¸
+#U+9e13 lÄi # Character é¸
+U+9e14 bà o # Character é¸
+U+9e15 lú # Character é¸
+U+9e16 hè # Character é¸
+U+9e17 lóng # Character é¸
+#U+9e18 shuÄng # Character é¸
+U+9e19 yuè # Character é¸
+#U+9e1a yÄ«ng # Character é¸
+U+9e1b guà n # Character é¸
+U+9e1c qú # Character é¸
+U+9e1d là # Character é¸
+U+9e1e luán # Character é¸
+#U+9e1f niÇo # Character é¸
+#U+9e20 jiÅ« # Character é¸
+#U+9e21 jī # Character 鸡
+#U+9e22 yuÄn # Character 鸢
+U+9e23 mÃng # Character 鸣
+#U+9e24 shī # Character 鸤
+#U+9e25 Åu # Character 鸥
+#U+9e26 yÄ # Character 鸦
+#U+9e27 cÄng # Character 鸧
+#U+9e28 bÇo # Character 鸨
+U+9e29 zhèn # Character 鸩
+#U+9e2a gū # Character 鸪
+#U+9e2b dÅng # Character 鸫
+U+9e2c lú # Character 鸬
+#U+9e2d yÄ # Character é¸
+#U+9e2e xiÄo # Character 鸮
+#U+9e2f yÄng # Character 鸯
+U+9e30 lÃng # Character 鸰
+#U+9e31 zhī # Character 鸱
+U+9e32 qú # Character 鸲
+#U+9e33 yuÄn # Character 鸳
+U+9e34 xué # Character 鸴
+U+9e35 tuó # Character 鸵
+#U+9e36 sī # Character 鸶
+U+9e37 zhì # Character 鸷
+U+9e38 ér # Character 鸸
+#U+9e39 guÄ # Character 鸹
+#U+9e3a xiū # Character 鸺
+U+9e3b héng # Character 鸻
+#U+9e3c zhÅu # Character 鸼
+#U+9e3d gÄ # Character 鸽
+U+9e3e luán # Character 鸾
+U+9e3f hóng # Character 鸿
+U+9e40 wú # Character é¹
+U+9e41 bó # Character é¹
+U+9e42 là # Character é¹
+#U+9e43 juÄn # Character é¹
+U+9e44 hú # Character é¹
+U+9e45 é # Character é¹
+U+9e46 yù # Character é¹
+U+9e47 xián # Character é¹
+U+9e48 tà # Character é¹
+#U+9e49 wÇ # Character é¹
+U+9e4a que # Character é¹
+U+9e4b miáo # Character é¹
+#U+9e4c Än # Character é¹
+#U+9e4d kÅ«n # Character é¹
+#U+9e4e bÄi # Character é¹
+U+9e4f péng # Character é¹
+#U+9e50 qiÄn # Character é¹
+U+9e51 chun # Character é¹
+#U+9e52 gÄng # Character é¹
+#U+9e53 yuÄn # Character é¹
+U+9e54 sù # Character é¹
+U+9e55 hú # Character é¹
+U+9e56 hé # Character é¹
+U+9e57 è # Character é¹
+U+9e58 gú # Character é¹
+#U+9e59 qiÅ« # Character é¹
+#U+9e5a zÄ« # Character é¹
+U+9e5b méi # Character é¹
+U+9e5c mù # Character é¹
+U+9e5d nì # Character é¹
+U+9e5e yà o # Character é¹
+#U+9e5f wÄng # Character é¹
+U+9e60 liú # Character é¹
+U+9e61 jà # Character 鹡
+U+9e62 nì # Character 鹢
+#U+9e63 jiÄn # Character é¹£
+U+9e64 hè # Character 鹤
+#U+9e65 yī # Character 鹥
+#U+9e66 yīng # Character 鹦
+U+9e67 zhè # Character 鹧
+U+9e68 liáo # Character 鹨
+U+9e69 liáo # Character 鹩
+#U+9e6a jiÄo # Character 鹪
+U+9e6b jiù # Character 鹫
+U+9e6c yù # Character 鹬
+U+9e6d lù # Character é¹
+U+9e6e xuán # Character 鹮
+#U+9e6f zhÄn # Character 鹯
+#U+9e70 yīng # Character 鹰
+U+9e71 huò # Character 鹱
+U+9e72 méng # Character 鹲
+U+9e73 guà n # Character 鹳
+#U+9e74 shuÄng # Character é¹´
+#U+9e75 lÇ # Character é¹µ
+#U+9e76 jīn # Character 鹶
+U+9e77 lÃng # Character é¹·
+#U+9e78 jiÇn # Character 鹸
+U+9e79 xián # Character 鹹
+U+9e7a cuó # Character 鹺
+#U+9e7b jiÇn # Character é¹»
+#U+9e7c jiÇn # Character é¹¼
+U+9e7d yán # Character 鹽
+U+9e7e cuó # Character 鹾
+U+9e7f lù # Character 鹿
+#U+9e80 yÅu # Character éº
+#U+9e81 cÅ« # Character éº
+#U+9e82 jÇ # Character éº
+#U+9e83 biÄo # Character éº
+#U+9e84 cÅ« # Character éº
+#U+9e85 biÄo # Character éº
+U+9e86 zhù # Character éº
+#U+9e87 jÅ«n # Character éº
+#U+9e88 zhÇ # Character éº
+#U+9e89 jiÄn # Character éº
+U+9e8a mà # Character éº
+U+9e8b mà # Character éº
+U+9e8c wú # Character éº
+U+9e8d liú # Character éº
+U+9e8e chén # Character éº
+#U+9e8f jÅ«n # Character éº
+U+9e90 lÃn # Character éº
+U+9e91 nà # Character éº
+U+9e92 qà # Character éº
+U+9e93 lù # Character éº
+U+9e94 jiù # Character éº
+#U+9e95 jÅ«n # Character éº
+#U+9e96 jÄ«ng # Character éº
+U+9e97 lì # Character éº
+#U+9e98 xiÄng # Character éº
+U+9e99 yán # Character éº
+#U+9e9a jiÄ # Character éº
+U+9e9b mà # Character éº
+U+9e9c lì # Character éº
+U+9e9d shè # Character éº
+#U+9e9e zhÄng # Character éº
+U+9e9f lÃn # Character éº
+#U+9ea0 jÄ«ng # Character éº
+#U+9ea1 jī # Character 麡
+U+9ea2 lÃng # Character 麢
+U+9ea3 yán # Character 麣
+#U+9ea4 cū # Character 麤
+U+9ea5 mà i # Character 麥
+U+9ea6 mà i # Character 麦
+#U+9ea7 gÄ # Character 麧
+#U+9ea8 chÇo # Character 麨
+#U+9ea9 fū # Character 麩
+#U+9eaa miÇn # Character 麪
+#U+9eab miÇn # Character 麫
+#U+9eac fū # Character 麬
+U+9ead pà o # Character éº
+U+9eae qù # Character 麮
+U+9eaf qú # Character 麯
+U+9eb0 móu # Character 麰
+#U+9eb1 fū # Character 麱
+U+9eb2 xià n # Character 麲
+U+9eb3 lái # Character 麳
+U+9eb4 qú # Character 麴
+U+9eb5 mià n # Character 麵
+U+9eb6 ? # Character 麶
+#U+9eb7 fÄng # Character 麷
+#U+9eb8 fū # Character 麸
+U+9eb9 qú # Character 麹
+U+9eba mià n # Character 麺
+U+9ebb má # Character 麻
+U+9ebc me # Character 麼
+U+9ebd mo # Character 麽
+#U+9ebe huī # Character 麾
+U+9ebf ? # Character 麿
+#U+9ec0 zÅu # Character é»
+#U+9ec1 nÄn # Character é»
+U+9ec2 fén # Character é»
+U+9ec3 huáng # Character é»
+U+9ec4 huáng # Character é»
+#U+9ec5 jÄ«n # Character é»
+#U+9ec6 guÄng # Character é»
+#U+9ec7 tiÄn # Character é»
+#U+9ec8 tÇu # Character é»
+U+9ec9 héng # Character é»
+#U+9eca xÄ« # Character é»
+#U+9ecb kuÇng # Character é»
+U+9ecc héng # Character é»
+#U+9ecd shÇ # Character é»
+U+9ece là # Character é»
+U+9ecf nián # Character é»
+#U+9ed0 chÄ« # Character é»
+#U+9ed1 hÄi # Character é»
+#U+9ed2 hÄi # Character é»
+U+9ed3 yì # Character é»
+U+9ed4 qián # Character é»
+#U+9ed5 dÄn # Character é»
+U+9ed6 xì # Character é»
+#U+9ed7 tuÇn # Character é»
+U+9ed8 mò # Character é»
+U+9ed9 mò # Character é»
+U+9eda qián # Character é»
+U+9edb dà i # Character é»
+U+9edc chù # Character é»
+#U+9edd yÇu # Character é»
+#U+9ede diÇn # Character é»
+#U+9edf yÄ« # Character é»
+U+9ee0 xiá # Character é»
+#U+9ee1 yÇn # Character 黡
+#U+9ee2 qū # Character 黢
+#U+9ee3 mÄi # Character 黣
+#U+9ee4 yÇn # Character 黤
+#U+9ee5 jīng # Character 黥
+U+9ee6 yù # Character 黦
+U+9ee7 là # Character 黧
+#U+9ee8 dÇng # Character 黨
+U+9ee9 dú # Character 黩
+#U+9eea cÇn # Character 黪
+#U+9eeb yīn # Character 黫
+U+9eec à n # Character 黬
+#U+9eed yÄn # Character é»
+#U+9eee tÇn # Character é»®
+U+9eef à n # Character 黯
+#U+9ef0 zhÄn # Character é»°
+U+9ef1 dà i # Character 黱
+#U+9ef2 cÇn # Character 黲
+#U+9ef3 yī # Character 黳
+U+9ef4 méi # Character 黴
+#U+9ef5 dÇn # Character 黵
+#U+9ef6 yÇn # Character 黶
+U+9ef7 dú # Character 黷
+U+9ef8 lú # Character 黸
+#U+9ef9 zhÇ # Character 黹
+#U+9efa fÄn # Character 黺
+U+9efb fù # Character 黻
+#U+9efc fÇ # Character 黼
+#U+9efd mÇn # Character 黽
+#U+9efe mÇn # Character 黾
+U+9eff yuán # Character 黿
diff --git a/resources/chars/latin1/row9f.trans b/resources/chars/latin1/row9f.trans
new file mode 100644
index 0000000..89c77f7
--- /dev/null
+++ b/resources/chars/latin1/row9f.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+9f00 cù # Character é¼
+U+9f01 qù # Character é¼
+U+9f02 cháo # Character é¼
+#U+9f03 wÄ # Character é¼
+#U+9f04 zhÅ« # Character é¼
+#U+9f05 zhÄ« # Character é¼
+U+9f06 máng # Character é¼
+U+9f07 áo # Character é¼
+#U+9f08 biÄ # Character é¼
+U+9f09 tuó # Character é¼
+U+9f0a bì # Character é¼
+U+9f0b yuán # Character é¼
+U+9f0c cháo # Character é¼
+U+9f0d tuó # Character é¼
+#U+9f0e dÇng # Character é¼
+U+9f0f mì # Character é¼
+U+9f10 nà i # Character é¼
+#U+9f11 dÇng # Character é¼
+#U+9f12 zÄ« # Character é¼
+#U+9f13 gÇ # Character é¼
+#U+9f14 gÇ # Character é¼
+#U+9f15 dÅng # Character é¼
+U+9f16 fén # Character é¼
+U+9f17 táo # Character é¼
+#U+9f18 yuÄn # Character é¼
+U+9f19 pà # Character é¼
+#U+9f1a chÄng # Character é¼
+#U+9f1b gÄo # Character é¼
+U+9f1c qì # Character é¼
+#U+9f1d yuÄn # Character é¼
+#U+9f1e tÄng # Character é¼
+#U+9f1f tÄng # Character é¼
+#U+9f20 shÇ # Character é¼
+#U+9f21 shÇ # Character 鼡
+U+9f22 fén # Character 鼢
+U+9f23 fèi # Character 鼣
+U+9f24 wén # Character 鼤
+U+9f25 bá # Character 鼥
+#U+9f26 diÄo # Character 鼦
+U+9f27 tuó # Character 鼧
+U+9f28 tóng # Character 鼨
+U+9f29 qú # Character 鼩
+#U+9f2a shÄng # Character 鼪
+U+9f2b shà # Character 鼫
+U+9f2c yòu # Character 鼬
+U+9f2d shà # Character é¼
+U+9f2e tÃng # Character é¼®
+U+9f2f wú # Character 鼯
+U+9f30 nià n # Character 鼰
+#U+9f31 jīng # Character 鼱
+U+9f32 hún # Character 鼲
+U+9f33 jú # Character 鼳
+#U+9f34 yÇn # Character é¼´
+U+9f35 tú # Character 鼵
+U+9f36 tà # Character 鼶
+#U+9f37 xī # Character 鼷
+#U+9f38 xiÇn # Character 鼸
+#U+9f39 yÇn # Character é¼¹
+U+9f3a léi # Character 鼺
+U+9f3b bà # Character 鼻
+#U+9f3c yÇo # Character é¼¼
+U+9f3d qiú # Character 鼽
+#U+9f3e hÄn # Character é¼¾
+#U+9f3f wū # Character 鼿
+U+9f40 wù # Character é½
+U+9f41 hóu # Character é½
+U+9f42 xì # Character é½
+U+9f43 gé # Character é½
+#U+9f44 zhÄ # Character é½
+U+9f45 xiù # Character é½
+U+9f46 wèng # Character é½
+#U+9f47 zhÄ # Character é½
+U+9f48 nóng # Character é½
+U+9f49 nà ng # Character é½
+U+9f4a qà # Character é½
+#U+9f4b zhÄi # Character é½
+U+9f4c jì # Character é½
+#U+9f4d zÄ« # Character é½
+#U+9f4e jÄ« # Character é½
+#U+9f4f jÄ« # Character é½
+U+9f50 qà # Character é½
+#U+9f51 jÄ« # Character é½
+#U+9f52 chÇ # Character é½
+U+9f53 chèn # Character é½
+U+9f54 chèn # Character é½
+U+9f55 hé # Character é½
+U+9f56 yá # Character é½
+#U+9f57 kÄn # Character é½
+U+9f58 xiè # Character é½
+U+9f59 páo # Character é½
+U+9f5a cuò # Character é½
+U+9f5b shì # Character é½
+#U+9f5c zÄ« # Character é½
+#U+9f5d chÄ« # Character é½
+U+9f5e nià n # Character é½
+#U+9f5f jÇ # Character é½
+U+9f60 tiáo # Character é½
+U+9f61 lÃng # Character 齡
+U+9f62 lÃng # Character é½¢
+#U+9f63 chū # Character 齣
+U+9f64 quán # Character 齤
+U+9f65 xiè # Character 齥
+#U+9f66 kÄn # Character 齦
+U+9f67 niè # Character 齧
+U+9f68 jiù # Character 齨
+#U+9f69 yÇo # Character 齩
+U+9f6a chuò # Character 齪
+#U+9f6b kÇn # Character 齫
+#U+9f6c yÇ # Character 齬
+#U+9f6d chÇ # Character é½
+#U+9f6e yÇ # Character é½®
+U+9f6f nà # Character 齯
+U+9f70 cuò # Character 齰
+#U+9f71 zÅu # Character é½±
+#U+9f72 qÇ # Character é½²
+#U+9f73 nÄn # Character é½³
+#U+9f74 xiÇn # Character é½´
+U+9f75 óu # Character 齵
+U+9f76 è # Character 齶
+U+9f77 wò # Character 齷
+U+9f78 yì # Character 齸
+#U+9f79 chuÅ # Character é½¹
+#U+9f7a zÅu # Character 齺
+#U+9f7b diÄn # Character é½»
+#U+9f7c chÇ # Character é½¼
+U+9f7d jìn # Character 齽
+U+9f7e yà # Character 齾
+#U+9f7f chÇ # Character 齿
+U+9f80 chèn # Character é¾
+U+9f81 hé # Character é¾
+#U+9f82 kÄn # Character é¾
+#U+9f83 jÇ # Character é¾
+U+9f84 lÃng # Character é¾
+U+9f85 páo # Character é¾
+U+9f86 tiáo # Character é¾
+#U+9f87 zÄ« # Character é¾
+#U+9f88 kÄn # Character é¾
+#U+9f89 yÇ # Character é¾
+U+9f8a chuò # Character é¾
+#U+9f8b qÇ # Character é¾
+U+9f8c wò # Character é¾
+U+9f8d lóng # Character é¾
+U+9f8e páng # Character é¾
+#U+9f8f gÅng # Character é¾
+U+9f90 páng # Character é¾
+#U+9f91 yÇn # Character é¾
+U+9f92 lóng # Character é¾
+U+9f93 lóng # Character é¾
+#U+9f94 gÅng # Character é¾
+#U+9f95 kÄn # Character é¾
+U+9f96 tà # Character é¾
+U+9f97 lÃng # Character é¾
+U+9f98 tà # Character é¾
+U+9f99 lóng # Character é¾
+#U+9f9a gÅng # Character é¾
+#U+9f9b kÄn # Character é¾
+#U+9f9c guÄ« # Character é¾
+#U+9f9d qiÅ« # Character é¾
+#U+9f9e biÄ # Character é¾
+#U+9f9f guÄ« # Character é¾
+U+9fa0 yuè # Character é¾
+U+9fa1 chuì # Character 龡
+U+9fa2 hé # Character 龢
+U+9fa3 jué # Character 龣
+U+9fa4 xié # Character 龤
+U+9fa5 yù # Character 龥
+U+9fa6 ? # Character 龦
+U+9fa7 ? # Character 龧
+U+9fa8 ? # Character 龨
+U+9fa9 ? # Character 龩
+U+9faa ? # Character 龪
+U+9fab ? # Character 龫
+U+9fac ? # Character 龬
+U+9fad ? # Character é¾
+U+9fae ? # Character é¾®
+U+9faf ? # Character 龯
+U+9fb0 ? # Character é¾°
+U+9fb1 ? # Character é¾±
+U+9fb2 ? # Character é¾²
+U+9fb3 ? # Character é¾³
+U+9fb4 ? # Character é¾´
+U+9fb5 ? # Character é¾µ
+U+9fb6 ? # Character 龶
+U+9fb7 ? # Character é¾·
+U+9fb8 ? # Character 龸
+U+9fb9 ? # Character é¾¹
+U+9fba ? # Character 龺
+U+9fbb ? # Character é¾»
+U+9fbc ? # Character é¾¼
+U+9fbd ? # Character é¾½
+U+9fbe ? # Character é¾¾
+U+9fbf ? # Character 龿
+U+9fc0 ? # Character é¿
+U+9fc1 ? # Character é¿
+U+9fc2 ? # Character é¿
+U+9fc3 ? # Character é¿
+U+9fc4 ? # Character é¿
+U+9fc5 ? # Character é¿
+U+9fc6 ? # Character é¿
+U+9fc7 ? # Character é¿
+U+9fc8 ? # Character é¿
+U+9fc9 ? # Character é¿
+U+9fca ? # Character é¿
+U+9fcb ? # Character é¿
+U+9fcc ? # Character é¿
+U+9fcd ? # Character é¿
+U+9fce ? # Character é¿
+U+9fcf ? # Character é¿
+U+9fd0 ? # Character é¿
+U+9fd1 ? # Character é¿
+U+9fd2 ? # Character é¿
+U+9fd3 ? # Character é¿
+U+9fd4 ? # Character é¿
+U+9fd5 ? # Character é¿
+U+9fd6 ? # Character é¿
+U+9fd7 ? # Character é¿
+U+9fd8 ? # Character é¿
+U+9fd9 ? # Character é¿
+U+9fda ? # Character é¿
+U+9fdb ? # Character é¿
+U+9fdc ? # Character é¿
+U+9fdd ? # Character é¿
+U+9fde ? # Character é¿
+U+9fdf ? # Character é¿
+U+9fe0 ? # Character é¿
+U+9fe1 ? # Character é¿¡
+U+9fe2 ? # Character é¿¢
+U+9fe3 ? # Character é¿£
+U+9fe4 ? # Character 鿤
+U+9fe5 ? # Character é¿¥
+U+9fe6 ? # Character 鿦
+U+9fe7 ? # Character 鿧
+U+9fe8 ? # Character 鿨
+U+9fe9 ? # Character é¿©
+U+9fea ? # Character 鿪
+U+9feb ? # Character é¿«
+U+9fec ? # Character 鿬
+U+9fed ? # Character é¿
+U+9fee ? # Character é¿®
+U+9fef ? # Character 鿯
+U+9ff0 ? # Character é¿°
+U+9ff1 ? # Character 鿱
+U+9ff2 ? # Character 鿲
+U+9ff3 ? # Character 鿳
+U+9ff4 ? # Character é¿´
+U+9ff5 ? # Character 鿵
+U+9ff6 ? # Character 鿶
+U+9ff7 ? # Character é¿·
+U+9ff8 ? # Character 鿸
+U+9ff9 ? # Character 鿹
+U+9ffa ? # Character 鿺
+U+9ffb ? # Character é¿»
+U+9ffc ? # Character 鿼
+U+9ffd ? # Character 鿽
+U+9ffe ? # Character 鿾
+U+9fff ? # Character é¿¿
diff --git a/resources/chars/latin1/rowac.trans b/resources/chars/latin1/rowac.trans
new file mode 100644
index 0000000..c0ee6f1
--- /dev/null
+++ b/resources/chars/latin1/rowac.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+ac00 ga # Character ê°
+U+ac01 gag # Character ê°
+U+ac02 gakk # Character ê°
+U+ac03 gags # Character ê°
+U+ac04 gan # Character ê°
+U+ac05 ganj # Character ê°
+U+ac06 ganh # Character ê°
+U+ac07 gad # Character ê°
+U+ac08 gal # Character ê°
+U+ac09 galg # Character ê°
+U+ac0a galm # Character ê°
+U+ac0b galb # Character ê°
+U+ac0c gals # Character ê°
+U+ac0d galt # Character ê°
+U+ac0e galp # Character ê°
+U+ac0f galh # Character ê°
+U+ac10 gam # Character ê°
+U+ac11 gab # Character ê°
+U+ac12 gabs # Character ê°
+U+ac13 gas # Character ê°
+U+ac14 gass # Character ê°
+U+ac15 gang # Character ê°
+U+ac16 gaj # Character ê°
+U+ac17 gach # Character ê°
+U+ac18 gak # Character ê°
+U+ac19 gat # Character ê°
+U+ac1a gap # Character ê°
+U+ac1b gah # Character ê°
+U+ac1c gae # Character ê°
+U+ac1d gaeg # Character ê°
+U+ac1e gaekk # Character ê°
+U+ac1f gaegs # Character ê°
+U+ac20 gaen # Character ê°
+U+ac21 gaenj # Character ê°¡
+U+ac22 gaenh # Character ê°¢
+U+ac23 gaed # Character ê°£
+U+ac24 gael # Character ê°¤
+U+ac25 gaelg # Character ê°¥
+U+ac26 gaelm # Character ê°¦
+U+ac27 gaelb # Character ê°§
+U+ac28 gaels # Character ê°¨
+U+ac29 gaelt # Character ê°©
+U+ac2a gaelp # Character ê°ª
+U+ac2b gaelh # Character ê°«
+U+ac2c gaem # Character ê°¬
+U+ac2d gaeb # Character ê°
+U+ac2e gaebs # Character ê°®
+U+ac2f gaes # Character ê°¯
+U+ac30 gaess # Character ê°°
+U+ac31 gaeng # Character ê°±
+U+ac32 gaej # Character ê°²
+U+ac33 gaech # Character ê°³
+U+ac34 gaek # Character ê°´
+U+ac35 gaet # Character ê°µ
+U+ac36 gaep # Character ê°¶
+U+ac37 gaeh # Character ê°·
+U+ac38 gya # Character ê°¸
+U+ac39 gyag # Character ê°¹
+U+ac3a gyakk # Character ê°º
+U+ac3b gyags # Character ê°»
+U+ac3c gyan # Character ê°¼
+U+ac3d gyanj # Character ê°½
+U+ac3e gyanh # Character ê°¾
+U+ac3f gyad # Character ê°¿
+U+ac40 gyal # Character ê±
+U+ac41 gyalg # Character ê±
+U+ac42 gyalm # Character ê±
+U+ac43 gyalb # Character ê±
+U+ac44 gyals # Character ê±
+U+ac45 gyalt # Character ê±
+U+ac46 gyalp # Character ê±
+U+ac47 gyalh # Character ê±
+U+ac48 gyam # Character ê±
+U+ac49 gyab # Character ê±
+U+ac4a gyabs # Character ê±
+U+ac4b gyas # Character ê±
+U+ac4c gyass # Character ê±
+U+ac4d gyang # Character ê±
+U+ac4e gyaj # Character ê±
+U+ac4f gyach # Character ê±
+U+ac50 gyak # Character ê±
+U+ac51 gyat # Character ê±
+U+ac52 gyap # Character ê±
+U+ac53 gyah # Character ê±
+U+ac54 gyae # Character ê±
+U+ac55 gyaeg # Character ê±
+U+ac56 gyaekk # Character ê±
+U+ac57 gyaegs # Character ê±
+U+ac58 gyaen # Character ê±
+U+ac59 gyaenj # Character ê±
+U+ac5a gyaenh # Character ê±
+U+ac5b gyaed # Character ê±
+U+ac5c gyael # Character ê±
+U+ac5d gyaelg # Character ê±
+U+ac5e gyaelm # Character ê±
+U+ac5f gyaelb # Character ê±
+U+ac60 gyaels # Character ê±
+U+ac61 gyaelt # Character 걡
+U+ac62 gyaelp # Character ê±¢
+U+ac63 gyaelh # Character ê±£
+U+ac64 gyaem # Character 걤
+U+ac65 gyaeb # Character ê±¥
+U+ac66 gyaebs # Character 걦
+U+ac67 gyaes # Character 걧
+U+ac68 gyaess # Character 걨
+U+ac69 gyaeng # Character 걩
+U+ac6a gyaej # Character 걪
+U+ac6b gyaech # Character 걫
+U+ac6c gyaek # Character 걬
+U+ac6d gyaet # Character ê±
+U+ac6e gyaep # Character ê±®
+U+ac6f gyaeh # Character 걯
+U+ac70 geo # Character ê±°
+U+ac71 geog # Character ê±±
+U+ac72 geokk # Character ê±²
+U+ac73 geogs # Character ê±³
+U+ac74 geon # Character ê±´
+U+ac75 geonj # Character ê±µ
+U+ac76 geonh # Character 걶
+U+ac77 geod # Character ê±·
+U+ac78 geol # Character 걸
+U+ac79 geolg # Character ê±¹
+U+ac7a geolm # Character 걺
+U+ac7b geolb # Character ê±»
+U+ac7c geols # Character ê±¼
+U+ac7d geolt # Character ê±½
+U+ac7e geolp # Character ê±¾
+U+ac7f geolh # Character 걿
+U+ac80 geom # Character ê²
+U+ac81 geob # Character ê²
+U+ac82 geobs # Character ê²
+U+ac83 geos # Character ê²
+U+ac84 geoss # Character ê²
+U+ac85 geong # Character ê²
+U+ac86 geoj # Character ê²
+U+ac87 geoch # Character ê²
+U+ac88 geok # Character ê²
+U+ac89 geot # Character ê²
+U+ac8a geop # Character ê²
+U+ac8b geoh # Character ê²
+U+ac8c ge # Character ê²
+U+ac8d geg # Character ê²
+U+ac8e gekk # Character ê²
+U+ac8f gegs # Character ê²
+U+ac90 gen # Character ê²
+U+ac91 genj # Character ê²
+U+ac92 genh # Character ê²
+U+ac93 ged # Character ê²
+U+ac94 gel # Character ê²
+U+ac95 gelg # Character ê²
+U+ac96 gelm # Character ê²
+U+ac97 gelb # Character ê²
+U+ac98 gels # Character ê²
+U+ac99 gelt # Character ê²
+U+ac9a gelp # Character ê²
+U+ac9b gelh # Character ê²
+U+ac9c gem # Character ê²
+U+ac9d geb # Character ê²
+U+ac9e gebs # Character ê²
+U+ac9f ges # Character ê²
+U+aca0 gess # Character ê²
+U+aca1 geng # Character 겡
+U+aca2 gej # Character ê²¢
+U+aca3 gech # Character ê²£
+U+aca4 gek # Character 겤
+U+aca5 get # Character ê²¥
+U+aca6 gep # Character 겦
+U+aca7 geh # Character 겧
+U+aca8 gyeo # Character 겨
+U+aca9 gyeog # Character 격
+U+acaa gyeokk # Character 겪
+U+acab gyeogs # Character 겫
+U+acac gyeon # Character 견
+U+acad gyeonj # Character ê²
+U+acae gyeonh # Character ê²®
+U+acaf gyeod # Character 겯
+U+acb0 gyeol # Character ê²°
+U+acb1 gyeolg # Character ê²±
+U+acb2 gyeolm # Character ê²²
+U+acb3 gyeolb # Character ê²³
+U+acb4 gyeols # Character ê²´
+U+acb5 gyeolt # Character ê²µ
+U+acb6 gyeolp # Character 겶
+U+acb7 gyeolh # Character ê²·
+U+acb8 gyeom # Character 겸
+U+acb9 gyeob # Character ê²¹
+U+acba gyeobs # Character 겺
+U+acbb gyeos # Character ê²»
+U+acbc gyeoss # Character ê²¼
+U+acbd gyeong # Character ê²½
+U+acbe gyeoj # Character ê²¾
+U+acbf gyeoch # Character 겿
+U+acc0 gyeok # Character ê³
+U+acc1 gyeot # Character ê³
+U+acc2 gyeop # Character ê³
+U+acc3 gyeoh # Character ê³
+U+acc4 gye # Character ê³
+U+acc5 gyeg # Character ê³
+U+acc6 gyekk # Character ê³
+U+acc7 gyegs # Character ê³
+U+acc8 gyen # Character ê³
+U+acc9 gyenj # Character ê³
+U+acca gyenh # Character ê³
+U+accb gyed # Character ê³
+U+accc gyel # Character ê³
+U+accd gyelg # Character ê³
+U+acce gyelm # Character ê³
+U+accf gyelb # Character ê³
+U+acd0 gyels # Character ê³
+U+acd1 gyelt # Character ê³
+U+acd2 gyelp # Character ê³
+U+acd3 gyelh # Character ê³
+U+acd4 gyem # Character ê³
+U+acd5 gyeb # Character ê³
+U+acd6 gyebs # Character ê³
+U+acd7 gyes # Character ê³
+U+acd8 gyess # Character ê³
+U+acd9 gyeng # Character ê³
+U+acda gyej # Character ê³
+U+acdb gyech # Character ê³
+U+acdc gyek # Character ê³
+U+acdd gyet # Character ê³
+U+acde gyep # Character ê³
+U+acdf gyeh # Character ê³
+U+ace0 go # Character ê³
+U+ace1 gog # Character 곡
+U+ace2 gokk # Character ê³¢
+U+ace3 gogs # Character ê³£
+U+ace4 gon # Character 곤
+U+ace5 gonj # Character ê³¥
+U+ace6 gonh # Character 곦
+U+ace7 god # Character 곧
+U+ace8 gol # Character 골
+U+ace9 golg # Character 곩
+U+acea golm # Character 곪
+U+aceb golb # Character 곫
+U+acec gols # Character 곬
+U+aced golt # Character ê³
+U+acee golp # Character ê³®
+U+acef golh # Character 곯
+U+acf0 gom # Character ê³°
+U+acf1 gob # Character ê³±
+U+acf2 gobs # Character ê³²
+U+acf3 gos # Character ê³³
+U+acf4 goss # Character ê³´
+U+acf5 gong # Character ê³µ
+U+acf6 goj # Character 곶
+U+acf7 goch # Character ê³·
+U+acf8 gok # Character 곸
+U+acf9 got # Character ê³¹
+U+acfa gop # Character 곺
+U+acfb goh # Character ê³»
+U+acfc gwa # Character ê³¼
+U+acfd gwag # Character ê³½
+U+acfe gwakk # Character ê³¾
+U+acff gwags # Character 곿
diff --git a/resources/chars/latin1/rowad.trans b/resources/chars/latin1/rowad.trans
new file mode 100644
index 0000000..4079d5b
--- /dev/null
+++ b/resources/chars/latin1/rowad.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+ad00 gwan # Character ê´
+U+ad01 gwanj # Character ê´
+U+ad02 gwanh # Character ê´
+U+ad03 gwad # Character ê´
+U+ad04 gwal # Character ê´
+U+ad05 gwalg # Character ê´
+U+ad06 gwalm # Character ê´
+U+ad07 gwalb # Character ê´
+U+ad08 gwals # Character ê´
+U+ad09 gwalt # Character ê´
+U+ad0a gwalp # Character ê´
+U+ad0b gwalh # Character ê´
+U+ad0c gwam # Character ê´
+U+ad0d gwab # Character ê´
+U+ad0e gwabs # Character ê´
+U+ad0f gwas # Character ê´
+U+ad10 gwass # Character ê´
+U+ad11 gwang # Character ê´
+U+ad12 gwaj # Character ê´
+U+ad13 gwach # Character ê´
+U+ad14 gwak # Character ê´
+U+ad15 gwat # Character ê´
+U+ad16 gwap # Character ê´
+U+ad17 gwah # Character ê´
+U+ad18 gwae # Character ê´
+U+ad19 gwaeg # Character ê´
+U+ad1a gwaekk # Character ê´
+U+ad1b gwaegs # Character ê´
+U+ad1c gwaen # Character ê´
+U+ad1d gwaenj # Character ê´
+U+ad1e gwaenh # Character ê´
+U+ad1f gwaed # Character ê´
+U+ad20 gwael # Character ê´
+U+ad21 gwaelg # Character ê´¡
+U+ad22 gwaelm # Character ê´¢
+U+ad23 gwaelb # Character ê´£
+U+ad24 gwaels # Character ê´¤
+U+ad25 gwaelt # Character ê´¥
+U+ad26 gwaelp # Character ê´¦
+U+ad27 gwaelh # Character ê´§
+U+ad28 gwaem # Character ê´¨
+U+ad29 gwaeb # Character ê´©
+U+ad2a gwaebs # Character ê´ª
+U+ad2b gwaes # Character ê´«
+U+ad2c gwaess # Character ê´¬
+U+ad2d gwaeng # Character ê´
+U+ad2e gwaej # Character ê´®
+U+ad2f gwaech # Character ê´¯
+U+ad30 gwaek # Character ê´°
+U+ad31 gwaet # Character ê´±
+U+ad32 gwaep # Character ê´²
+U+ad33 gwaeh # Character ê´³
+U+ad34 goe # Character ê´´
+U+ad35 goeg # Character ê´µ
+U+ad36 goekk # Character ê´¶
+U+ad37 goegs # Character ê´·
+U+ad38 goen # Character ê´¸
+U+ad39 goenj # Character ê´¹
+U+ad3a goenh # Character ê´º
+U+ad3b goed # Character ê´»
+U+ad3c goel # Character ê´¼
+U+ad3d goelg # Character ê´½
+U+ad3e goelm # Character ê´¾
+U+ad3f goelb # Character ê´¿
+U+ad40 goels # Character êµ
+U+ad41 goelt # Character êµ
+U+ad42 goelp # Character êµ
+U+ad43 goelh # Character êµ
+U+ad44 goem # Character êµ
+U+ad45 goeb # Character êµ
+U+ad46 goebs # Character êµ
+U+ad47 goes # Character êµ
+U+ad48 goess # Character êµ
+U+ad49 goeng # Character êµ
+U+ad4a goej # Character êµ
+U+ad4b goech # Character êµ
+U+ad4c goek # Character êµ
+U+ad4d goet # Character êµ
+U+ad4e goep # Character êµ
+U+ad4f goeh # Character êµ
+U+ad50 gyo # Character êµ
+U+ad51 gyog # Character êµ
+U+ad52 gyokk # Character êµ
+U+ad53 gyogs # Character êµ
+U+ad54 gyon # Character êµ
+U+ad55 gyonj # Character êµ
+U+ad56 gyonh # Character êµ
+U+ad57 gyod # Character êµ
+U+ad58 gyol # Character êµ
+U+ad59 gyolg # Character êµ
+U+ad5a gyolm # Character êµ
+U+ad5b gyolb # Character êµ
+U+ad5c gyols # Character êµ
+U+ad5d gyolt # Character êµ
+U+ad5e gyolp # Character êµ
+U+ad5f gyolh # Character êµ
+U+ad60 gyom # Character êµ
+U+ad61 gyob # Character 굡
+U+ad62 gyobs # Character êµ¢
+U+ad63 gyos # Character êµ£
+U+ad64 gyoss # Character 굤
+U+ad65 gyong # Character êµ¥
+U+ad66 gyoj # Character 굦
+U+ad67 gyoch # Character 굧
+U+ad68 gyok # Character 굨
+U+ad69 gyot # Character 굩
+U+ad6a gyop # Character 굪
+U+ad6b gyoh # Character 굫
+U+ad6c gu # Character 구
+U+ad6d gug # Character êµ
+U+ad6e gukk # Character êµ®
+U+ad6f gugs # Character 굯
+U+ad70 gun # Character êµ°
+U+ad71 gunj # Character êµ±
+U+ad72 gunh # Character êµ²
+U+ad73 gud # Character êµ³
+U+ad74 gul # Character êµ´
+U+ad75 gulg # Character êµµ
+U+ad76 gulm # Character 굶
+U+ad77 gulb # Character êµ·
+U+ad78 guls # Character 굸
+U+ad79 gult # Character êµ¹
+U+ad7a gulp # Character 굺
+U+ad7b gulh # Character êµ»
+U+ad7c gum # Character êµ¼
+U+ad7d gub # Character êµ½
+U+ad7e gubs # Character êµ¾
+U+ad7f gus # Character 굿
+U+ad80 guss # Character ê¶
+U+ad81 gung # Character ê¶
+U+ad82 guj # Character ê¶
+U+ad83 guch # Character ê¶
+U+ad84 guk # Character ê¶
+U+ad85 gut # Character ê¶
+U+ad86 gup # Character ê¶
+U+ad87 guh # Character ê¶
+U+ad88 gwo # Character ê¶
+U+ad89 gwog # Character ê¶
+U+ad8a gwokk # Character ê¶
+U+ad8b gwogs # Character ê¶
+U+ad8c gwon # Character ê¶
+U+ad8d gwonj # Character ê¶
+U+ad8e gwonh # Character ê¶
+U+ad8f gwod # Character ê¶
+U+ad90 gwol # Character ê¶
+U+ad91 gwolg # Character ê¶
+U+ad92 gwolm # Character ê¶
+U+ad93 gwolb # Character ê¶
+U+ad94 gwols # Character ê¶
+U+ad95 gwolt # Character ê¶
+U+ad96 gwolp # Character ê¶
+U+ad97 gwolh # Character ê¶
+U+ad98 gwom # Character ê¶
+U+ad99 gwob # Character ê¶
+U+ad9a gwobs # Character ê¶
+U+ad9b gwos # Character ê¶
+U+ad9c gwoss # Character ê¶
+U+ad9d gwong # Character ê¶
+U+ad9e gwoj # Character ê¶
+U+ad9f gwoch # Character ê¶
+U+ada0 gwok # Character ê¶
+U+ada1 gwot # Character 궡
+U+ada2 gwop # Character 궢
+U+ada3 gwoh # Character 궣
+U+ada4 gwe # Character 궤
+U+ada5 gweg # Character 궥
+U+ada6 gwekk # Character 궦
+U+ada7 gwegs # Character 궧
+U+ada8 gwen # Character 궨
+U+ada9 gwenj # Character 궩
+U+adaa gwenh # Character 궪
+U+adab gwed # Character 궫
+U+adac gwel # Character 궬
+U+adad gwelg # Character ê¶
+U+adae gwelm # Character 궮
+U+adaf gwelb # Character 궯
+U+adb0 gwels # Character 궰
+U+adb1 gwelt # Character 궱
+U+adb2 gwelp # Character 궲
+U+adb3 gwelh # Character 궳
+U+adb4 gwem # Character 궴
+U+adb5 gweb # Character 궵
+U+adb6 gwebs # Character 궶
+U+adb7 gwes # Character 궷
+U+adb8 gwess # Character 궸
+U+adb9 gweng # Character 궹
+U+adba gwej # Character 궺
+U+adbb gwech # Character 궻
+U+adbc gwek # Character 궼
+U+adbd gwet # Character 궽
+U+adbe gwep # Character 궾
+U+adbf gweh # Character 궿
+U+adc0 gwi # Character ê·
+U+adc1 gwig # Character ê·
+U+adc2 gwikk # Character ê·
+U+adc3 gwigs # Character ê·
+U+adc4 gwin # Character ê·
+U+adc5 gwinj # Character ê·
+U+adc6 gwinh # Character ê·
+U+adc7 gwid # Character ê·
+U+adc8 gwil # Character ê·
+U+adc9 gwilg # Character ê·
+U+adca gwilm # Character ê·
+U+adcb gwilb # Character ê·
+U+adcc gwils # Character ê·
+U+adcd gwilt # Character ê·
+U+adce gwilp # Character ê·
+U+adcf gwilh # Character ê·
+U+add0 gwim # Character ê·
+U+add1 gwib # Character ê·
+U+add2 gwibs # Character ê·
+U+add3 gwis # Character ê·
+U+add4 gwiss # Character ê·
+U+add5 gwing # Character ê·
+U+add6 gwij # Character ê·
+U+add7 gwich # Character ê·
+U+add8 gwik # Character ê·
+U+add9 gwit # Character ê·
+U+adda gwip # Character ê·
+U+addb gwih # Character ê·
+U+addc gyu # Character ê·
+U+addd gyug # Character ê·
+U+adde gyukk # Character ê·
+U+addf gyugs # Character ê·
+U+ade0 gyun # Character ê·
+U+ade1 gyunj # Character ê·¡
+U+ade2 gyunh # Character ê·¢
+U+ade3 gyud # Character ê·£
+U+ade4 gyul # Character ê·¤
+U+ade5 gyulg # Character ê·¥
+U+ade6 gyulm # Character ê·¦
+U+ade7 gyulb # Character ê·§
+U+ade8 gyuls # Character ê·¨
+U+ade9 gyult # Character ê·©
+U+adea gyulp # Character ê·ª
+U+adeb gyulh # Character ê·«
+U+adec gyum # Character ê·¬
+U+aded gyub # Character ê·
+U+adee gyubs # Character ê·®
+U+adef gyus # Character ê·¯
+U+adf0 gyuss # Character ê·°
+U+adf1 gyung # Character ê·±
+U+adf2 gyuj # Character ê·²
+U+adf3 gyuch # Character ê·³
+U+adf4 gyuk # Character ê·´
+U+adf5 gyut # Character ê·µ
+U+adf6 gyup # Character ê·¶
+U+adf7 gyuh # Character ê··
+U+adf8 geu # Character ê·¸
+U+adf9 geug # Character ê·¹
+U+adfa geukk # Character ê·º
+U+adfb geugs # Character ê·»
+U+adfc geun # Character ê·¼
+U+adfd geunj # Character ê·½
+U+adfe geunh # Character ê·¾
+U+adff geud # Character ê·¿
diff --git a/resources/chars/latin1/rowae.trans b/resources/chars/latin1/rowae.trans
new file mode 100644
index 0000000..80ebb09
--- /dev/null
+++ b/resources/chars/latin1/rowae.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+ae00 geul # Character ê¸
+U+ae01 geulg # Character ê¸
+U+ae02 geulm # Character ê¸
+U+ae03 geulb # Character ê¸
+U+ae04 geuls # Character ê¸
+U+ae05 geult # Character ê¸
+U+ae06 geulp # Character ê¸
+U+ae07 geulh # Character ê¸
+U+ae08 geum # Character ê¸
+U+ae09 geub # Character ê¸
+U+ae0a geubs # Character ê¸
+U+ae0b geus # Character ê¸
+U+ae0c geuss # Character ê¸
+U+ae0d geung # Character ê¸
+U+ae0e geuj # Character ê¸
+U+ae0f geuch # Character ê¸
+U+ae10 geuk # Character ê¸
+U+ae11 geut # Character ê¸
+U+ae12 geup # Character ê¸
+U+ae13 geuh # Character ê¸
+U+ae14 gui # Character ê¸
+U+ae15 guig # Character ê¸
+U+ae16 guikk # Character ê¸
+U+ae17 guigs # Character ê¸
+U+ae18 guin # Character ê¸
+U+ae19 guinj # Character ê¸
+U+ae1a guinh # Character ê¸
+U+ae1b guid # Character ê¸
+U+ae1c guil # Character ê¸
+U+ae1d guilg # Character ê¸
+U+ae1e guilm # Character ê¸
+U+ae1f guilb # Character ê¸
+U+ae20 guils # Character ê¸
+U+ae21 guilt # Character 긡
+U+ae22 guilp # Character 긢
+U+ae23 guilh # Character 긣
+U+ae24 guim # Character 긤
+U+ae25 guib # Character 긥
+U+ae26 guibs # Character 긦
+U+ae27 guis # Character 긧
+U+ae28 guiss # Character 긨
+U+ae29 guing # Character 긩
+U+ae2a guij # Character 긪
+U+ae2b guich # Character 긫
+U+ae2c guik # Character 긬
+U+ae2d guit # Character ê¸
+U+ae2e guip # Character 긮
+U+ae2f guih # Character 긯
+U+ae30 gi # Character 기
+U+ae31 gig # Character 긱
+U+ae32 gikk # Character 긲
+U+ae33 gigs # Character 긳
+U+ae34 gin # Character 긴
+U+ae35 ginj # Character 긵
+U+ae36 ginh # Character 긶
+U+ae37 gid # Character 긷
+U+ae38 gil # Character 길
+U+ae39 gilg # Character 긹
+U+ae3a gilm # Character 긺
+U+ae3b gilb # Character 긻
+U+ae3c gils # Character 긼
+U+ae3d gilt # Character 긽
+U+ae3e gilp # Character 긾
+U+ae3f gilh # Character 긿
+U+ae40 gim # Character ê¹
+U+ae41 gib # Character ê¹
+U+ae42 gibs # Character ê¹
+U+ae43 gis # Character ê¹
+U+ae44 giss # Character ê¹
+U+ae45 ging # Character ê¹
+U+ae46 gij # Character ê¹
+U+ae47 gich # Character ê¹
+U+ae48 gik # Character ê¹
+U+ae49 git # Character ê¹
+U+ae4a gip # Character ê¹
+U+ae4b gih # Character ê¹
+U+ae4c kka # Character ê¹
+U+ae4d kkag # Character ê¹
+U+ae4e kkakk # Character ê¹
+U+ae4f kkags # Character ê¹
+U+ae50 kkan # Character ê¹
+U+ae51 kkanj # Character ê¹
+U+ae52 kkanh # Character ê¹
+U+ae53 kkad # Character ê¹
+U+ae54 kkal # Character ê¹
+U+ae55 kkalg # Character ê¹
+U+ae56 kkalm # Character ê¹
+U+ae57 kkalb # Character ê¹
+U+ae58 kkals # Character ê¹
+U+ae59 kkalt # Character ê¹
+U+ae5a kkalp # Character ê¹
+U+ae5b kkalh # Character ê¹
+U+ae5c kkam # Character ê¹
+U+ae5d kkab # Character ê¹
+U+ae5e kkabs # Character ê¹
+U+ae5f kkas # Character ê¹
+U+ae60 kkass # Character ê¹
+U+ae61 kkang # Character 깡
+U+ae62 kkaj # Character ê¹¢
+U+ae63 kkach # Character ê¹£
+U+ae64 kkak # Character 깤
+U+ae65 kkat # Character ê¹¥
+U+ae66 kkap # Character 깦
+U+ae67 kkah # Character 깧
+U+ae68 kkae # Character 깨
+U+ae69 kkaeg # Character 깩
+U+ae6a kkaekk # Character 깪
+U+ae6b kkaegs # Character 깫
+U+ae6c kkaen # Character 깬
+U+ae6d kkaenj # Character ê¹
+U+ae6e kkaenh # Character ê¹®
+U+ae6f kkaed # Character 깯
+U+ae70 kkael # Character ê¹°
+U+ae71 kkaelg # Character ê¹±
+U+ae72 kkaelm # Character ê¹²
+U+ae73 kkaelb # Character ê¹³
+U+ae74 kkaels # Character ê¹´
+U+ae75 kkaelt # Character ê¹µ
+U+ae76 kkaelp # Character 깶
+U+ae77 kkaelh # Character ê¹·
+U+ae78 kkaem # Character 깸
+U+ae79 kkaeb # Character ê¹¹
+U+ae7a kkaebs # Character 깺
+U+ae7b kkaes # Character ê¹»
+U+ae7c kkaess # Character ê¹¼
+U+ae7d kkaeng # Character ê¹½
+U+ae7e kkaej # Character ê¹¾
+U+ae7f kkaech # Character 깿
+U+ae80 kkaek # Character êº
+U+ae81 kkaet # Character êº
+U+ae82 kkaep # Character êº
+U+ae83 kkaeh # Character êº
+U+ae84 kkya # Character êº
+U+ae85 kkyag # Character êº
+U+ae86 kkyakk # Character êº
+U+ae87 kkyags # Character êº
+U+ae88 kkyan # Character êº
+U+ae89 kkyanj # Character êº
+U+ae8a kkyanh # Character êº
+U+ae8b kkyad # Character êº
+U+ae8c kkyal # Character êº
+U+ae8d kkyalg # Character êº
+U+ae8e kkyalm # Character êº
+U+ae8f kkyalb # Character êº
+U+ae90 kkyals # Character êº
+U+ae91 kkyalt # Character êº
+U+ae92 kkyalp # Character êº
+U+ae93 kkyalh # Character êº
+U+ae94 kkyam # Character êº
+U+ae95 kkyab # Character êº
+U+ae96 kkyabs # Character êº
+U+ae97 kkyas # Character êº
+U+ae98 kkyass # Character êº
+U+ae99 kkyang # Character êº
+U+ae9a kkyaj # Character êº
+U+ae9b kkyach # Character êº
+U+ae9c kkyak # Character êº
+U+ae9d kkyat # Character êº
+U+ae9e kkyap # Character êº
+U+ae9f kkyah # Character êº
+U+aea0 kkyae # Character êº
+U+aea1 kkyaeg # Character 꺡
+U+aea2 kkyaekk # Character 꺢
+U+aea3 kkyaegs # Character 꺣
+U+aea4 kkyaen # Character 꺤
+U+aea5 kkyaenj # Character 꺥
+U+aea6 kkyaenh # Character 꺦
+U+aea7 kkyaed # Character 꺧
+U+aea8 kkyael # Character 꺨
+U+aea9 kkyaelg # Character 꺩
+U+aeaa kkyaelm # Character 꺪
+U+aeab kkyaelb # Character 꺫
+U+aeac kkyaels # Character 꺬
+U+aead kkyaelt # Character êº
+U+aeae kkyaelp # Character 꺮
+U+aeaf kkyaelh # Character 꺯
+U+aeb0 kkyaem # Character 꺰
+U+aeb1 kkyaeb # Character 꺱
+U+aeb2 kkyaebs # Character 꺲
+U+aeb3 kkyaes # Character 꺳
+U+aeb4 kkyaess # Character 꺴
+U+aeb5 kkyaeng # Character 꺵
+U+aeb6 kkyaej # Character 꺶
+U+aeb7 kkyaech # Character 꺷
+U+aeb8 kkyaek # Character 꺸
+U+aeb9 kkyaet # Character 꺹
+U+aeba kkyaep # Character 꺺
+U+aebb kkyaeh # Character 꺻
+U+aebc kkeo # Character 꺼
+U+aebd kkeog # Character 꺽
+U+aebe kkeokk # Character 꺾
+U+aebf kkeogs # Character 꺿
+U+aec0 kkeon # Character ê»
+U+aec1 kkeonj # Character ê»
+U+aec2 kkeonh # Character ê»
+U+aec3 kkeod # Character ê»
+U+aec4 kkeol # Character ê»
+U+aec5 kkeolg # Character ê»
+U+aec6 kkeolm # Character ê»
+U+aec7 kkeolb # Character ê»
+U+aec8 kkeols # Character ê»
+U+aec9 kkeolt # Character ê»
+U+aeca kkeolp # Character ê»
+U+aecb kkeolh # Character ê»
+U+aecc kkeom # Character ê»
+U+aecd kkeob # Character ê»
+U+aece kkeobs # Character ê»
+U+aecf kkeos # Character ê»
+U+aed0 kkeoss # Character ê»
+U+aed1 kkeong # Character ê»
+U+aed2 kkeoj # Character ê»
+U+aed3 kkeoch # Character ê»
+U+aed4 kkeok # Character ê»
+U+aed5 kkeot # Character ê»
+U+aed6 kkeop # Character ê»
+U+aed7 kkeoh # Character ê»
+U+aed8 kke # Character ê»
+U+aed9 kkeg # Character ê»
+U+aeda kkekk # Character ê»
+U+aedb kkegs # Character ê»
+U+aedc kken # Character ê»
+U+aedd kkenj # Character ê»
+U+aede kkenh # Character ê»
+U+aedf kked # Character ê»
+U+aee0 kkel # Character ê»
+U+aee1 kkelg # Character 껡
+U+aee2 kkelm # Character 껢
+U+aee3 kkelb # Character 껣
+U+aee4 kkels # Character 껤
+U+aee5 kkelt # Character 껥
+U+aee6 kkelp # Character 껦
+U+aee7 kkelh # Character 껧
+U+aee8 kkem # Character 껨
+U+aee9 kkeb # Character 껩
+U+aeea kkebs # Character 껪
+U+aeeb kkes # Character 껫
+U+aeec kkess # Character 껬
+U+aeed kkeng # Character ê»
+U+aeee kkej # Character ê»®
+U+aeef kkech # Character 껯
+U+aef0 kkek # Character ê»°
+U+aef1 kket # Character ê»±
+U+aef2 kkep # Character 껲
+U+aef3 kkeh # Character 껳
+U+aef4 kkyeo # Character ê»´
+U+aef5 kkyeog # Character 껵
+U+aef6 kkyeokk # Character 껶
+U+aef7 kkyeogs # Character ê»·
+U+aef8 kkyeon # Character 껸
+U+aef9 kkyeonj # Character 껹
+U+aefa kkyeonh # Character 껺
+U+aefb kkyeod # Character ê»»
+U+aefc kkyeol # Character 껼
+U+aefd kkyeolg # Character 껽
+U+aefe kkyeolm # Character 껾
+U+aeff kkyeolb # Character 껿
diff --git a/resources/chars/latin1/rowaf.trans b/resources/chars/latin1/rowaf.trans
new file mode 100644
index 0000000..a62a5e0
--- /dev/null
+++ b/resources/chars/latin1/rowaf.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+af00 kkyeols # Character ê¼
+U+af01 kkyeolt # Character ê¼
+U+af02 kkyeolp # Character ê¼
+U+af03 kkyeolh # Character ê¼
+U+af04 kkyeom # Character ê¼
+U+af05 kkyeob # Character ê¼
+U+af06 kkyeobs # Character ê¼
+U+af07 kkyeos # Character ê¼
+U+af08 kkyeoss # Character ê¼
+U+af09 kkyeong # Character ê¼
+U+af0a kkyeoj # Character ê¼
+U+af0b kkyeoch # Character ê¼
+U+af0c kkyeok # Character ê¼
+U+af0d kkyeot # Character ê¼
+U+af0e kkyeop # Character ê¼
+U+af0f kkyeoh # Character ê¼
+U+af10 kkye # Character ê¼
+U+af11 kkyeg # Character ê¼
+U+af12 kkyekk # Character ê¼
+U+af13 kkyegs # Character ê¼
+U+af14 kkyen # Character ê¼
+U+af15 kkyenj # Character ê¼
+U+af16 kkyenh # Character ê¼
+U+af17 kkyed # Character ê¼
+U+af18 kkyel # Character ê¼
+U+af19 kkyelg # Character ê¼
+U+af1a kkyelm # Character ê¼
+U+af1b kkyelb # Character ê¼
+U+af1c kkyels # Character ê¼
+U+af1d kkyelt # Character ê¼
+U+af1e kkyelp # Character ê¼
+U+af1f kkyelh # Character ê¼
+U+af20 kkyem # Character ê¼
+U+af21 kkyeb # Character 꼡
+U+af22 kkyebs # Character ê¼¢
+U+af23 kkyes # Character ê¼£
+U+af24 kkyess # Character 꼤
+U+af25 kkyeng # Character ê¼¥
+U+af26 kkyej # Character 꼦
+U+af27 kkyech # Character 꼧
+U+af28 kkyek # Character 꼨
+U+af29 kkyet # Character 꼩
+U+af2a kkyep # Character 꼪
+U+af2b kkyeh # Character 꼫
+U+af2c kko # Character 꼬
+U+af2d kkog # Character ê¼
+U+af2e kkokk # Character ê¼®
+U+af2f kkogs # Character 꼯
+U+af30 kkon # Character ê¼°
+U+af31 kkonj # Character ê¼±
+U+af32 kkonh # Character ê¼²
+U+af33 kkod # Character ê¼³
+U+af34 kkol # Character ê¼´
+U+af35 kkolg # Character ê¼µ
+U+af36 kkolm # Character 꼶
+U+af37 kkolb # Character ê¼·
+U+af38 kkols # Character 꼸
+U+af39 kkolt # Character ê¼¹
+U+af3a kkolp # Character 꼺
+U+af3b kkolh # Character ê¼»
+U+af3c kkom # Character ê¼¼
+U+af3d kkob # Character ê¼½
+U+af3e kkobs # Character ê¼¾
+U+af3f kkos # Character 꼿
+U+af40 kkoss # Character ê½
+U+af41 kkong # Character ê½
+U+af42 kkoj # Character ê½
+U+af43 kkoch # Character ê½
+U+af44 kkok # Character ê½
+U+af45 kkot # Character ê½
+U+af46 kkop # Character ê½
+U+af47 kkoh # Character ê½
+U+af48 kkwa # Character ê½
+U+af49 kkwag # Character ê½
+U+af4a kkwakk # Character ê½
+U+af4b kkwags # Character ê½
+U+af4c kkwan # Character ê½
+U+af4d kkwanj # Character ê½
+U+af4e kkwanh # Character ê½
+U+af4f kkwad # Character ê½
+U+af50 kkwal # Character ê½
+U+af51 kkwalg # Character ê½
+U+af52 kkwalm # Character ê½
+U+af53 kkwalb # Character ê½
+U+af54 kkwals # Character ê½
+U+af55 kkwalt # Character ê½
+U+af56 kkwalp # Character ê½
+U+af57 kkwalh # Character ê½
+U+af58 kkwam # Character ê½
+U+af59 kkwab # Character ê½
+U+af5a kkwabs # Character ê½
+U+af5b kkwas # Character ê½
+U+af5c kkwass # Character ê½
+U+af5d kkwang # Character ê½
+U+af5e kkwaj # Character ê½
+U+af5f kkwach # Character ê½
+U+af60 kkwak # Character ê½
+U+af61 kkwat # Character 꽡
+U+af62 kkwap # Character ê½¢
+U+af63 kkwah # Character ê½£
+U+af64 kkwae # Character 꽤
+U+af65 kkwaeg # Character ê½¥
+U+af66 kkwaekk # Character 꽦
+U+af67 kkwaegs # Character 꽧
+U+af68 kkwaen # Character 꽨
+U+af69 kkwaenj # Character 꽩
+U+af6a kkwaenh # Character 꽪
+U+af6b kkwaed # Character 꽫
+U+af6c kkwael # Character 꽬
+U+af6d kkwaelg # Character ê½
+U+af6e kkwaelm # Character ê½®
+U+af6f kkwaelb # Character 꽯
+U+af70 kkwaels # Character ê½°
+U+af71 kkwaelt # Character ê½±
+U+af72 kkwaelp # Character ê½²
+U+af73 kkwaelh # Character ê½³
+U+af74 kkwaem # Character ê½´
+U+af75 kkwaeb # Character ê½µ
+U+af76 kkwaebs # Character 꽶
+U+af77 kkwaes # Character ê½·
+U+af78 kkwaess # Character 꽸
+U+af79 kkwaeng # Character ê½¹
+U+af7a kkwaej # Character 꽺
+U+af7b kkwaech # Character ê½»
+U+af7c kkwaek # Character ê½¼
+U+af7d kkwaet # Character ê½½
+U+af7e kkwaep # Character ê½¾
+U+af7f kkwaeh # Character 꽿
+U+af80 kkoe # Character ê¾
+U+af81 kkoeg # Character ê¾
+U+af82 kkoekk # Character ê¾
+U+af83 kkoegs # Character ê¾
+U+af84 kkoen # Character ê¾
+U+af85 kkoenj # Character ê¾
+U+af86 kkoenh # Character ê¾
+U+af87 kkoed # Character ê¾
+U+af88 kkoel # Character ê¾
+U+af89 kkoelg # Character ê¾
+U+af8a kkoelm # Character ê¾
+U+af8b kkoelb # Character ê¾
+U+af8c kkoels # Character ê¾
+U+af8d kkoelt # Character ê¾
+U+af8e kkoelp # Character ê¾
+U+af8f kkoelh # Character ê¾
+U+af90 kkoem # Character ê¾
+U+af91 kkoeb # Character ê¾
+U+af92 kkoebs # Character ê¾
+U+af93 kkoes # Character ê¾
+U+af94 kkoess # Character ê¾
+U+af95 kkoeng # Character ê¾
+U+af96 kkoej # Character ê¾
+U+af97 kkoech # Character ê¾
+U+af98 kkoek # Character ê¾
+U+af99 kkoet # Character ê¾
+U+af9a kkoep # Character ê¾
+U+af9b kkoeh # Character ê¾
+U+af9c kkyo # Character ê¾
+U+af9d kkyog # Character ê¾
+U+af9e kkyokk # Character ê¾
+U+af9f kkyogs # Character ê¾
+U+afa0 kkyon # Character ê¾
+U+afa1 kkyonj # Character 꾡
+U+afa2 kkyonh # Character ê¾¢
+U+afa3 kkyod # Character ê¾£
+U+afa4 kkyol # Character 꾤
+U+afa5 kkyolg # Character ê¾¥
+U+afa6 kkyolm # Character 꾦
+U+afa7 kkyolb # Character 꾧
+U+afa8 kkyols # Character 꾨
+U+afa9 kkyolt # Character 꾩
+U+afaa kkyolp # Character 꾪
+U+afab kkyolh # Character 꾫
+U+afac kkyom # Character 꾬
+U+afad kkyob # Character ê¾
+U+afae kkyobs # Character ê¾®
+U+afaf kkyos # Character 꾯
+U+afb0 kkyoss # Character ê¾°
+U+afb1 kkyong # Character ê¾±
+U+afb2 kkyoj # Character ê¾²
+U+afb3 kkyoch # Character ê¾³
+U+afb4 kkyok # Character ê¾´
+U+afb5 kkyot # Character ê¾µ
+U+afb6 kkyop # Character 꾶
+U+afb7 kkyoh # Character ê¾·
+U+afb8 kku # Character 꾸
+U+afb9 kkug # Character ê¾¹
+U+afba kkukk # Character 꾺
+U+afbb kkugs # Character ê¾»
+U+afbc kkun # Character ê¾¼
+U+afbd kkunj # Character ê¾½
+U+afbe kkunh # Character ê¾¾
+U+afbf kkud # Character 꾿
+U+afc0 kkul # Character ê¿
+U+afc1 kkulg # Character ê¿
+U+afc2 kkulm # Character ê¿
+U+afc3 kkulb # Character ê¿
+U+afc4 kkuls # Character ê¿
+U+afc5 kkult # Character ê¿
+U+afc6 kkulp # Character ê¿
+U+afc7 kkulh # Character ê¿
+U+afc8 kkum # Character ê¿
+U+afc9 kkub # Character ê¿
+U+afca kkubs # Character ê¿
+U+afcb kkus # Character ê¿
+U+afcc kkuss # Character ê¿
+U+afcd kkung # Character ê¿
+U+afce kkuj # Character ê¿
+U+afcf kkuch # Character ê¿
+U+afd0 kkuk # Character ê¿
+U+afd1 kkut # Character ê¿
+U+afd2 kkup # Character ê¿
+U+afd3 kkuh # Character ê¿
+U+afd4 kkwo # Character ê¿
+U+afd5 kkwog # Character ê¿
+U+afd6 kkwokk # Character ê¿
+U+afd7 kkwogs # Character ê¿
+U+afd8 kkwon # Character ê¿
+U+afd9 kkwonj # Character ê¿
+U+afda kkwonh # Character ê¿
+U+afdb kkwod # Character ê¿
+U+afdc kkwol # Character ê¿
+U+afdd kkwolg # Character ê¿
+U+afde kkwolm # Character ê¿
+U+afdf kkwolb # Character ê¿
+U+afe0 kkwols # Character ê¿
+U+afe1 kkwolt # Character ê¿¡
+U+afe2 kkwolp # Character ê¿¢
+U+afe3 kkwolh # Character ê¿£
+U+afe4 kkwom # Character 꿤
+U+afe5 kkwob # Character ê¿¥
+U+afe6 kkwobs # Character 꿦
+U+afe7 kkwos # Character 꿧
+U+afe8 kkwoss # Character 꿨
+U+afe9 kkwong # Character ê¿©
+U+afea kkwoj # Character 꿪
+U+afeb kkwoch # Character ê¿«
+U+afec kkwok # Character 꿬
+U+afed kkwot # Character ê¿
+U+afee kkwop # Character ê¿®
+U+afef kkwoh # Character 꿯
+U+aff0 kkwe # Character ê¿°
+U+aff1 kkweg # Character 꿱
+U+aff2 kkwekk # Character 꿲
+U+aff3 kkwegs # Character 꿳
+U+aff4 kkwen # Character ê¿´
+U+aff5 kkwenj # Character 꿵
+U+aff6 kkwenh # Character 꿶
+U+aff7 kkwed # Character ê¿·
+U+aff8 kkwel # Character 꿸
+U+aff9 kkwelg # Character 꿹
+U+affa kkwelm # Character 꿺
+U+affb kkwelb # Character ê¿»
+U+affc kkwels # Character 꿼
+U+affd kkwelt # Character 꿽
+U+affe kkwelp # Character 꿾
+U+afff kkwelh # Character ê¿¿
diff --git a/resources/chars/latin1/rowb0.trans b/resources/chars/latin1/rowb0.trans
new file mode 100644
index 0000000..61ad5a5
--- /dev/null
+++ b/resources/chars/latin1/rowb0.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+b000 kkwem # Character ë
+U+b001 kkweb # Character ë
+U+b002 kkwebs # Character ë
+U+b003 kkwes # Character ë
+U+b004 kkwess # Character ë
+U+b005 kkweng # Character ë
+U+b006 kkwej # Character ë
+U+b007 kkwech # Character ë
+U+b008 kkwek # Character ë
+U+b009 kkwet # Character ë
+U+b00a kkwep # Character ë
+U+b00b kkweh # Character ë
+U+b00c kkwi # Character ë
+U+b00d kkwig # Character ë
+U+b00e kkwikk # Character ë
+U+b00f kkwigs # Character ë
+U+b010 kkwin # Character ë
+U+b011 kkwinj # Character ë
+U+b012 kkwinh # Character ë
+U+b013 kkwid # Character ë
+U+b014 kkwil # Character ë
+U+b015 kkwilg # Character ë
+U+b016 kkwilm # Character ë
+U+b017 kkwilb # Character ë
+U+b018 kkwils # Character ë
+U+b019 kkwilt # Character ë
+U+b01a kkwilp # Character ë
+U+b01b kkwilh # Character ë
+U+b01c kkwim # Character ë
+U+b01d kkwib # Character ë
+U+b01e kkwibs # Character ë
+U+b01f kkwis # Character ë
+U+b020 kkwiss # Character ë
+U+b021 kkwing # Character ë¡
+U+b022 kkwij # Character ë¢
+U+b023 kkwich # Character ë£
+U+b024 kkwik # Character ë¤
+U+b025 kkwit # Character ë¥
+U+b026 kkwip # Character ë¦
+U+b027 kkwih # Character ë§
+U+b028 kkyu # Character ë¨
+U+b029 kkyug # Character ë©
+U+b02a kkyukk # Character ëª
+U+b02b kkyugs # Character ë«
+U+b02c kkyun # Character ë¬
+U+b02d kkyunj # Character ë
+U+b02e kkyunh # Character ë®
+U+b02f kkyud # Character ë¯
+U+b030 kkyul # Character ë°
+U+b031 kkyulg # Character ë±
+U+b032 kkyulm # Character ë²
+U+b033 kkyulb # Character ë³
+U+b034 kkyuls # Character ë´
+U+b035 kkyult # Character ëµ
+U+b036 kkyulp # Character ë¶
+U+b037 kkyulh # Character ë·
+U+b038 kkyum # Character ë¸
+U+b039 kkyub # Character ë¹
+U+b03a kkyubs # Character ëº
+U+b03b kkyus # Character ë»
+U+b03c kkyuss # Character ë¼
+U+b03d kkyung # Character ë½
+U+b03e kkyuj # Character ë¾
+U+b03f kkyuch # Character ë¿
+U+b040 kkyuk # Character ë
+U+b041 kkyut # Character ë
+U+b042 kkyup # Character ë
+U+b043 kkyuh # Character ë
+U+b044 kkeu # Character ë
+U+b045 kkeug # Character ë
+U+b046 kkeukk # Character ë
+U+b047 kkeugs # Character ë
+U+b048 kkeun # Character ë
+U+b049 kkeunj # Character ë
+U+b04a kkeunh # Character ë
+U+b04b kkeud # Character ë
+U+b04c kkeul # Character ë
+U+b04d kkeulg # Character ë
+U+b04e kkeulm # Character ë
+U+b04f kkeulb # Character ë
+U+b050 kkeuls # Character ë
+U+b051 kkeult # Character ë
+U+b052 kkeulp # Character ë
+U+b053 kkeulh # Character ë
+U+b054 kkeum # Character ë
+U+b055 kkeub # Character ë
+U+b056 kkeubs # Character ë
+U+b057 kkeus # Character ë
+U+b058 kkeuss # Character ë
+U+b059 kkeung # Character ë
+U+b05a kkeuj # Character ë
+U+b05b kkeuch # Character ë
+U+b05c kkeuk # Character ë
+U+b05d kkeut # Character ë
+U+b05e kkeup # Character ë
+U+b05f kkeuh # Character ë
+U+b060 kkui # Character ë
+U+b061 kkuig # Character ë¡
+U+b062 kkuikk # Character ë¢
+U+b063 kkuigs # Character ë£
+U+b064 kkuin # Character ë¤
+U+b065 kkuinj # Character ë¥
+U+b066 kkuinh # Character ë¦
+U+b067 kkuid # Character ë§
+U+b068 kkuil # Character ë¨
+U+b069 kkuilg # Character ë©
+U+b06a kkuilm # Character ëª
+U+b06b kkuilb # Character ë«
+U+b06c kkuils # Character ë¬
+U+b06d kkuilt # Character ë
+U+b06e kkuilp # Character ë®
+U+b06f kkuilh # Character ë¯
+U+b070 kkuim # Character ë°
+U+b071 kkuib # Character ë±
+U+b072 kkuibs # Character ë²
+U+b073 kkuis # Character ë³
+U+b074 kkuiss # Character ë´
+U+b075 kkuing # Character ëµ
+U+b076 kkuij # Character ë¶
+U+b077 kkuich # Character ë·
+U+b078 kkuik # Character ë¸
+U+b079 kkuit # Character ë¹
+U+b07a kkuip # Character ëº
+U+b07b kkuih # Character ë»
+U+b07c kki # Character ë¼
+U+b07d kkig # Character ë½
+U+b07e kkikk # Character ë¾
+U+b07f kkigs # Character ë¿
+U+b080 kkin # Character ë
+U+b081 kkinj # Character ë
+U+b082 kkinh # Character ë
+U+b083 kkid # Character ë
+U+b084 kkil # Character ë
+U+b085 kkilg # Character ë
+U+b086 kkilm # Character ë
+U+b087 kkilb # Character ë
+U+b088 kkils # Character ë
+U+b089 kkilt # Character ë
+U+b08a kkilp # Character ë
+U+b08b kkilh # Character ë
+U+b08c kkim # Character ë
+U+b08d kkib # Character ë
+U+b08e kkibs # Character ë
+U+b08f kkis # Character ë
+U+b090 kkiss # Character ë
+U+b091 kking # Character ë
+U+b092 kkij # Character ë
+U+b093 kkich # Character ë
+U+b094 kkik # Character ë
+U+b095 kkit # Character ë
+U+b096 kkip # Character ë
+U+b097 kkih # Character ë
+U+b098 na # Character ë
+U+b099 nag # Character ë
+U+b09a nakk # Character ë
+U+b09b nags # Character ë
+U+b09c nan # Character ë
+U+b09d nanj # Character ë
+U+b09e nanh # Character ë
+U+b09f nad # Character ë
+U+b0a0 nal # Character ë
+U+b0a1 nalg # Character ë¡
+U+b0a2 nalm # Character ë¢
+U+b0a3 nalb # Character ë£
+U+b0a4 nals # Character ë¤
+U+b0a5 nalt # Character ë¥
+U+b0a6 nalp # Character ë¦
+U+b0a7 nalh # Character ë§
+U+b0a8 nam # Character ë¨
+U+b0a9 nab # Character ë©
+U+b0aa nabs # Character ëª
+U+b0ab nas # Character ë«
+U+b0ac nass # Character ë¬
+U+b0ad nang # Character ë
+U+b0ae naj # Character ë®
+U+b0af nach # Character ë¯
+U+b0b0 nak # Character ë°
+U+b0b1 nat # Character ë±
+U+b0b2 nap # Character ë²
+U+b0b3 nah # Character ë³
+U+b0b4 nae # Character ë´
+U+b0b5 naeg # Character ëµ
+U+b0b6 naekk # Character ë¶
+U+b0b7 naegs # Character ë·
+U+b0b8 naen # Character ë¸
+U+b0b9 naenj # Character ë¹
+U+b0ba naenh # Character ëº
+U+b0bb naed # Character ë»
+U+b0bc nael # Character ë¼
+U+b0bd naelg # Character ë½
+U+b0be naelm # Character ë¾
+U+b0bf naelb # Character ë¿
+U+b0c0 naels # Character ë
+U+b0c1 naelt # Character ë
+U+b0c2 naelp # Character ë
+U+b0c3 naelh # Character ë
+U+b0c4 naem # Character ë
+U+b0c5 naeb # Character ë
+U+b0c6 naebs # Character ë
+U+b0c7 naes # Character ë
+U+b0c8 naess # Character ë
+U+b0c9 naeng # Character ë
+U+b0ca naej # Character ë
+U+b0cb naech # Character ë
+U+b0cc naek # Character ë
+U+b0cd naet # Character ë
+U+b0ce naep # Character ë
+U+b0cf naeh # Character ë
+U+b0d0 nya # Character ë
+U+b0d1 nyag # Character ë
+U+b0d2 nyakk # Character ë
+U+b0d3 nyags # Character ë
+U+b0d4 nyan # Character ë
+U+b0d5 nyanj # Character ë
+U+b0d6 nyanh # Character ë
+U+b0d7 nyad # Character ë
+U+b0d8 nyal # Character ë
+U+b0d9 nyalg # Character ë
+U+b0da nyalm # Character ë
+U+b0db nyalb # Character ë
+U+b0dc nyals # Character ë
+U+b0dd nyalt # Character ë
+U+b0de nyalp # Character ë
+U+b0df nyalh # Character ë
+U+b0e0 nyam # Character ë
+U+b0e1 nyab # Character ë¡
+U+b0e2 nyabs # Character ë¢
+U+b0e3 nyas # Character ë£
+U+b0e4 nyass # Character ë¤
+U+b0e5 nyang # Character ë¥
+U+b0e6 nyaj # Character ë¦
+U+b0e7 nyach # Character ë§
+U+b0e8 nyak # Character ë¨
+U+b0e9 nyat # Character ë©
+U+b0ea nyap # Character ëª
+U+b0eb nyah # Character ë«
+U+b0ec nyae # Character ë¬
+U+b0ed nyaeg # Character ë
+U+b0ee nyaekk # Character ë®
+U+b0ef nyaegs # Character ë¯
+U+b0f0 nyaen # Character ë°
+U+b0f1 nyaenj # Character ë±
+U+b0f2 nyaenh # Character ë²
+U+b0f3 nyaed # Character ë³
+U+b0f4 nyael # Character ë´
+U+b0f5 nyaelg # Character ëµ
+U+b0f6 nyaelm # Character ë¶
+U+b0f7 nyaelb # Character ë·
+U+b0f8 nyaels # Character ë¸
+U+b0f9 nyaelt # Character ë¹
+U+b0fa nyaelp # Character ëº
+U+b0fb nyaelh # Character ë»
+U+b0fc nyaem # Character ë¼
+U+b0fd nyaeb # Character ë½
+U+b0fe nyaebs # Character ë¾
+U+b0ff nyaes # Character ë¿
diff --git a/resources/chars/latin1/rowb1.trans b/resources/chars/latin1/rowb1.trans
new file mode 100644
index 0000000..00ca0e3
--- /dev/null
+++ b/resources/chars/latin1/rowb1.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+b100 nyaess # Character ë
+U+b101 nyaeng # Character ë
+U+b102 nyaej # Character ë
+U+b103 nyaech # Character ë
+U+b104 nyaek # Character ë
+U+b105 nyaet # Character ë
+U+b106 nyaep # Character ë
+U+b107 nyaeh # Character ë
+U+b108 neo # Character ë
+U+b109 neog # Character ë
+U+b10a neokk # Character ë
+U+b10b neogs # Character ë
+U+b10c neon # Character ë
+U+b10d neonj # Character ë
+U+b10e neonh # Character ë
+U+b10f neod # Character ë
+U+b110 neol # Character ë
+U+b111 neolg # Character ë
+U+b112 neolm # Character ë
+U+b113 neolb # Character ë
+U+b114 neols # Character ë
+U+b115 neolt # Character ë
+U+b116 neolp # Character ë
+U+b117 neolh # Character ë
+U+b118 neom # Character ë
+U+b119 neob # Character ë
+U+b11a neobs # Character ë
+U+b11b neos # Character ë
+U+b11c neoss # Character ë
+U+b11d neong # Character ë
+U+b11e neoj # Character ë
+U+b11f neoch # Character ë
+U+b120 neok # Character ë
+U+b121 neot # Character ë¡
+U+b122 neop # Character ë¢
+U+b123 neoh # Character ë£
+U+b124 ne # Character ë¤
+U+b125 neg # Character ë¥
+U+b126 nekk # Character ë¦
+U+b127 negs # Character ë§
+U+b128 nen # Character ë¨
+U+b129 nenj # Character ë©
+U+b12a nenh # Character ëª
+U+b12b ned # Character ë«
+U+b12c nel # Character ë¬
+U+b12d nelg # Character ë
+U+b12e nelm # Character ë®
+U+b12f nelb # Character ë¯
+U+b130 nels # Character ë°
+U+b131 nelt # Character ë±
+U+b132 nelp # Character ë²
+U+b133 nelh # Character ë³
+U+b134 nem # Character ë´
+U+b135 neb # Character ëµ
+U+b136 nebs # Character ë¶
+U+b137 nes # Character ë·
+U+b138 ness # Character ë¸
+U+b139 neng # Character ë¹
+U+b13a nej # Character ëº
+U+b13b nech # Character ë»
+U+b13c nek # Character ë¼
+U+b13d net # Character ë½
+U+b13e nep # Character ë¾
+U+b13f neh # Character ë¿
+U+b140 nyeo # Character ë
+U+b141 nyeog # Character ë
+U+b142 nyeokk # Character ë
+U+b143 nyeogs # Character ë
+U+b144 nyeon # Character ë
+U+b145 nyeonj # Character ë
+U+b146 nyeonh # Character ë
+U+b147 nyeod # Character ë
+U+b148 nyeol # Character ë
+U+b149 nyeolg # Character ë
+U+b14a nyeolm # Character ë
+U+b14b nyeolb # Character ë
+U+b14c nyeols # Character ë
+U+b14d nyeolt # Character ë
+U+b14e nyeolp # Character ë
+U+b14f nyeolh # Character ë
+U+b150 nyeom # Character ë
+U+b151 nyeob # Character ë
+U+b152 nyeobs # Character ë
+U+b153 nyeos # Character ë
+U+b154 nyeoss # Character ë
+U+b155 nyeong # Character ë
+U+b156 nyeoj # Character ë
+U+b157 nyeoch # Character ë
+U+b158 nyeok # Character ë
+U+b159 nyeot # Character ë
+U+b15a nyeop # Character ë
+U+b15b nyeoh # Character ë
+U+b15c nye # Character ë
+U+b15d nyeg # Character ë
+U+b15e nyekk # Character ë
+U+b15f nyegs # Character ë
+U+b160 nyen # Character ë
+U+b161 nyenj # Character ë
¡
+U+b162 nyenh # Character ë
¢
+U+b163 nyed # Character ë
£
+U+b164 nyel # Character ë
¤
+U+b165 nyelg # Character ë
¥
+U+b166 nyelm # Character ë
¦
+U+b167 nyelb # Character ë
§
+U+b168 nyels # Character ë
¨
+U+b169 nyelt # Character ë
©
+U+b16a nyelp # Character ë
ª
+U+b16b nyelh # Character ë
«
+U+b16c nyem # Character ë
¬
+U+b16d nyeb # Character ë
+U+b16e nyebs # Character ë
®
+U+b16f nyes # Character ë
¯
+U+b170 nyess # Character ë
°
+U+b171 nyeng # Character ë
±
+U+b172 nyej # Character ë
²
+U+b173 nyech # Character ë
³
+U+b174 nyek # Character ë
´
+U+b175 nyet # Character ë
µ
+U+b176 nyep # Character ë
¶
+U+b177 nyeh # Character ë
·
+U+b178 no # Character ë
¸
+U+b179 nog # Character ë
¹
+U+b17a nokk # Character ë
º
+U+b17b nogs # Character ë
»
+U+b17c non # Character ë
¼
+U+b17d nonj # Character ë
½
+U+b17e nonh # Character ë
¾
+U+b17f nod # Character ë
¿
+U+b180 nol # Character ë
+U+b181 nolg # Character ë
+U+b182 nolm # Character ë
+U+b183 nolb # Character ë
+U+b184 nols # Character ë
+U+b185 nolt # Character ë
+U+b186 nolp # Character ë
+U+b187 nolh # Character ë
+U+b188 nom # Character ë
+U+b189 nob # Character ë
+U+b18a nobs # Character ë
+U+b18b nos # Character ë
+U+b18c noss # Character ë
+U+b18d nong # Character ë
+U+b18e noj # Character ë
+U+b18f noch # Character ë
+U+b190 nok # Character ë
+U+b191 not # Character ë
+U+b192 nop # Character ë
+U+b193 noh # Character ë
+U+b194 nwa # Character ë
+U+b195 nwag # Character ë
+U+b196 nwakk # Character ë
+U+b197 nwags # Character ë
+U+b198 nwan # Character ë
+U+b199 nwanj # Character ë
+U+b19a nwanh # Character ë
+U+b19b nwad # Character ë
+U+b19c nwal # Character ë
+U+b19d nwalg # Character ë
+U+b19e nwalm # Character ë
+U+b19f nwalb # Character ë
+U+b1a0 nwals # Character ë
+U+b1a1 nwalt # Character ë¡
+U+b1a2 nwalp # Character ë¢
+U+b1a3 nwalh # Character ë£
+U+b1a4 nwam # Character ë¤
+U+b1a5 nwab # Character ë¥
+U+b1a6 nwabs # Character ë¦
+U+b1a7 nwas # Character ë§
+U+b1a8 nwass # Character ë¨
+U+b1a9 nwang # Character ë©
+U+b1aa nwaj # Character ëª
+U+b1ab nwach # Character ë«
+U+b1ac nwak # Character ë¬
+U+b1ad nwat # Character ë
+U+b1ae nwap # Character ë®
+U+b1af nwah # Character ë¯
+U+b1b0 nwae # Character ë°
+U+b1b1 nwaeg # Character ë±
+U+b1b2 nwaekk # Character ë²
+U+b1b3 nwaegs # Character ë³
+U+b1b4 nwaen # Character ë´
+U+b1b5 nwaenj # Character ëµ
+U+b1b6 nwaenh # Character ë¶
+U+b1b7 nwaed # Character ë·
+U+b1b8 nwael # Character ë¸
+U+b1b9 nwaelg # Character ë¹
+U+b1ba nwaelm # Character ëº
+U+b1bb nwaelb # Character ë»
+U+b1bc nwaels # Character ë¼
+U+b1bd nwaelt # Character ë½
+U+b1be nwaelp # Character ë¾
+U+b1bf nwaelh # Character ë¿
+U+b1c0 nwaem # Character ë
+U+b1c1 nwaeb # Character ë
+U+b1c2 nwaebs # Character ë
+U+b1c3 nwaes # Character ë
+U+b1c4 nwaess # Character ë
+U+b1c5 nwaeng # Character ë
+U+b1c6 nwaej # Character ë
+U+b1c7 nwaech # Character ë
+U+b1c8 nwaek # Character ë
+U+b1c9 nwaet # Character ë
+U+b1ca nwaep # Character ë
+U+b1cb nwaeh # Character ë
+U+b1cc noe # Character ë
+U+b1cd noeg # Character ë
+U+b1ce noekk # Character ë
+U+b1cf noegs # Character ë
+U+b1d0 noen # Character ë
+U+b1d1 noenj # Character ë
+U+b1d2 noenh # Character ë
+U+b1d3 noed # Character ë
+U+b1d4 noel # Character ë
+U+b1d5 noelg # Character ë
+U+b1d6 noelm # Character ë
+U+b1d7 noelb # Character ë
+U+b1d8 noels # Character ë
+U+b1d9 noelt # Character ë
+U+b1da noelp # Character ë
+U+b1db noelh # Character ë
+U+b1dc noem # Character ë
+U+b1dd noeb # Character ë
+U+b1de noebs # Character ë
+U+b1df noes # Character ë
+U+b1e0 noess # Character ë
+U+b1e1 noeng # Character ë¡
+U+b1e2 noej # Character ë¢
+U+b1e3 noech # Character ë£
+U+b1e4 noek # Character ë¤
+U+b1e5 noet # Character ë¥
+U+b1e6 noep # Character ë¦
+U+b1e7 noeh # Character ë§
+U+b1e8 nyo # Character ë¨
+U+b1e9 nyog # Character ë©
+U+b1ea nyokk # Character ëª
+U+b1eb nyogs # Character ë«
+U+b1ec nyon # Character ë¬
+U+b1ed nyonj # Character ë
+U+b1ee nyonh # Character ë®
+U+b1ef nyod # Character ë¯
+U+b1f0 nyol # Character ë°
+U+b1f1 nyolg # Character ë±
+U+b1f2 nyolm # Character ë²
+U+b1f3 nyolb # Character ë³
+U+b1f4 nyols # Character ë´
+U+b1f5 nyolt # Character ëµ
+U+b1f6 nyolp # Character ë¶
+U+b1f7 nyolh # Character ë·
+U+b1f8 nyom # Character ë¸
+U+b1f9 nyob # Character ë¹
+U+b1fa nyobs # Character ëº
+U+b1fb nyos # Character ë»
+U+b1fc nyoss # Character ë¼
+U+b1fd nyong # Character ë½
+U+b1fe nyoj # Character ë¾
+U+b1ff nyoch # Character ë¿
diff --git a/resources/chars/latin1/rowb2.trans b/resources/chars/latin1/rowb2.trans
new file mode 100644
index 0000000..ebbe3bd
--- /dev/null
+++ b/resources/chars/latin1/rowb2.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+b200 nyok # Character ë
+U+b201 nyot # Character ë
+U+b202 nyop # Character ë
+U+b203 nyoh # Character ë
+U+b204 nu # Character ë
+U+b205 nug # Character ë
+U+b206 nukk # Character ë
+U+b207 nugs # Character ë
+U+b208 nun # Character ë
+U+b209 nunj # Character ë
+U+b20a nunh # Character ë
+U+b20b nud # Character ë
+U+b20c nul # Character ë
+U+b20d nulg # Character ë
+U+b20e nulm # Character ë
+U+b20f nulb # Character ë
+U+b210 nuls # Character ë
+U+b211 nult # Character ë
+U+b212 nulp # Character ë
+U+b213 nulh # Character ë
+U+b214 num # Character ë
+U+b215 nub # Character ë
+U+b216 nubs # Character ë
+U+b217 nus # Character ë
+U+b218 nuss # Character ë
+U+b219 nung # Character ë
+U+b21a nuj # Character ë
+U+b21b nuch # Character ë
+U+b21c nuk # Character ë
+U+b21d nut # Character ë
+U+b21e nup # Character ë
+U+b21f nuh # Character ë
+U+b220 nwo # Character ë
+U+b221 nwog # Character ë¡
+U+b222 nwokk # Character ë¢
+U+b223 nwogs # Character ë£
+U+b224 nwon # Character ë¤
+U+b225 nwonj # Character ë¥
+U+b226 nwonh # Character ë¦
+U+b227 nwod # Character ë§
+U+b228 nwol # Character ë¨
+U+b229 nwolg # Character ë©
+U+b22a nwolm # Character ëª
+U+b22b nwolb # Character ë«
+U+b22c nwols # Character ë¬
+U+b22d nwolt # Character ë
+U+b22e nwolp # Character ë®
+U+b22f nwolh # Character ë¯
+U+b230 nwom # Character ë°
+U+b231 nwob # Character ë±
+U+b232 nwobs # Character ë²
+U+b233 nwos # Character ë³
+U+b234 nwoss # Character ë´
+U+b235 nwong # Character ëµ
+U+b236 nwoj # Character ë¶
+U+b237 nwoch # Character ë·
+U+b238 nwok # Character ë¸
+U+b239 nwot # Character ë¹
+U+b23a nwop # Character ëº
+U+b23b nwoh # Character ë»
+U+b23c nwe # Character ë¼
+U+b23d nweg # Character ë½
+U+b23e nwekk # Character ë¾
+U+b23f nwegs # Character ë¿
+U+b240 nwen # Character ë
+U+b241 nwenj # Character ë
+U+b242 nwenh # Character ë
+U+b243 nwed # Character ë
+U+b244 nwel # Character ë
+U+b245 nwelg # Character ë
+U+b246 nwelm # Character ë
+U+b247 nwelb # Character ë
+U+b248 nwels # Character ë
+U+b249 nwelt # Character ë
+U+b24a nwelp # Character ë
+U+b24b nwelh # Character ë
+U+b24c nwem # Character ë
+U+b24d nweb # Character ë
+U+b24e nwebs # Character ë
+U+b24f nwes # Character ë
+U+b250 nwess # Character ë
+U+b251 nweng # Character ë
+U+b252 nwej # Character ë
+U+b253 nwech # Character ë
+U+b254 nwek # Character ë
+U+b255 nwet # Character ë
+U+b256 nwep # Character ë
+U+b257 nweh # Character ë
+U+b258 nwi # Character ë
+U+b259 nwig # Character ë
+U+b25a nwikk # Character ë
+U+b25b nwigs # Character ë
+U+b25c nwin # Character ë
+U+b25d nwinj # Character ë
+U+b25e nwinh # Character ë
+U+b25f nwid # Character ë
+U+b260 nwil # Character ë
+U+b261 nwilg # Character ë¡
+U+b262 nwilm # Character ë¢
+U+b263 nwilb # Character ë£
+U+b264 nwils # Character ë¤
+U+b265 nwilt # Character ë¥
+U+b266 nwilp # Character ë¦
+U+b267 nwilh # Character ë§
+U+b268 nwim # Character ë¨
+U+b269 nwib # Character ë©
+U+b26a nwibs # Character ëª
+U+b26b nwis # Character ë«
+U+b26c nwiss # Character ë¬
+U+b26d nwing # Character ë
+U+b26e nwij # Character ë®
+U+b26f nwich # Character ë¯
+U+b270 nwik # Character ë°
+U+b271 nwit # Character ë±
+U+b272 nwip # Character ë²
+U+b273 nwih # Character ë³
+U+b274 nyu # Character ë´
+U+b275 nyug # Character ëµ
+U+b276 nyukk # Character ë¶
+U+b277 nyugs # Character ë·
+U+b278 nyun # Character ë¸
+U+b279 nyunj # Character ë¹
+U+b27a nyunh # Character ëº
+U+b27b nyud # Character ë»
+U+b27c nyul # Character ë¼
+U+b27d nyulg # Character ë½
+U+b27e nyulm # Character ë¾
+U+b27f nyulb # Character ë¿
+U+b280 nyuls # Character ë
+U+b281 nyult # Character ë
+U+b282 nyulp # Character ë
+U+b283 nyulh # Character ë
+U+b284 nyum # Character ë
+U+b285 nyub # Character ë
+U+b286 nyubs # Character ë
+U+b287 nyus # Character ë
+U+b288 nyuss # Character ë
+U+b289 nyung # Character ë
+U+b28a nyuj # Character ë
+U+b28b nyuch # Character ë
+U+b28c nyuk # Character ë
+U+b28d nyut # Character ë
+U+b28e nyup # Character ë
+U+b28f nyuh # Character ë
+U+b290 neu # Character ë
+U+b291 neug # Character ë
+U+b292 neukk # Character ë
+U+b293 neugs # Character ë
+U+b294 neun # Character ë
+U+b295 neunj # Character ë
+U+b296 neunh # Character ë
+U+b297 neud # Character ë
+U+b298 neul # Character ë
+U+b299 neulg # Character ë
+U+b29a neulm # Character ë
+U+b29b neulb # Character ë
+U+b29c neuls # Character ë
+U+b29d neult # Character ë
+U+b29e neulp # Character ë
+U+b29f neulh # Character ë
+U+b2a0 neum # Character ë
+U+b2a1 neub # Character ë¡
+U+b2a2 neubs # Character ë¢
+U+b2a3 neus # Character ë£
+U+b2a4 neuss # Character ë¤
+U+b2a5 neung # Character ë¥
+U+b2a6 neuj # Character ë¦
+U+b2a7 neuch # Character ë§
+U+b2a8 neuk # Character ë¨
+U+b2a9 neut # Character ë©
+U+b2aa neup # Character ëª
+U+b2ab neuh # Character ë«
+U+b2ac nui # Character ë¬
+U+b2ad nuig # Character ë
+U+b2ae nuikk # Character ë®
+U+b2af nuigs # Character ë¯
+U+b2b0 nuin # Character ë°
+U+b2b1 nuinj # Character ë±
+U+b2b2 nuinh # Character ë²
+U+b2b3 nuid # Character ë³
+U+b2b4 nuil # Character ë´
+U+b2b5 nuilg # Character ëµ
+U+b2b6 nuilm # Character ë¶
+U+b2b7 nuilb # Character ë·
+U+b2b8 nuils # Character ë¸
+U+b2b9 nuilt # Character ë¹
+U+b2ba nuilp # Character ëº
+U+b2bb nuilh # Character ë»
+U+b2bc nuim # Character ë¼
+U+b2bd nuib # Character ë½
+U+b2be nuibs # Character ë¾
+U+b2bf nuis # Character ë¿
+U+b2c0 nuiss # Character ë
+U+b2c1 nuing # Character ë
+U+b2c2 nuij # Character ë
+U+b2c3 nuich # Character ë
+U+b2c4 nuik # Character ë
+U+b2c5 nuit # Character ë
+U+b2c6 nuip # Character ë
+U+b2c7 nuih # Character ë
+U+b2c8 ni # Character ë
+U+b2c9 nig # Character ë
+U+b2ca nikk # Character ë
+U+b2cb nigs # Character ë
+U+b2cc nin # Character ë
+U+b2cd ninj # Character ë
+U+b2ce ninh # Character ë
+U+b2cf nid # Character ë
+U+b2d0 nil # Character ë
+U+b2d1 nilg # Character ë
+U+b2d2 nilm # Character ë
+U+b2d3 nilb # Character ë
+U+b2d4 nils # Character ë
+U+b2d5 nilt # Character ë
+U+b2d6 nilp # Character ë
+U+b2d7 nilh # Character ë
+U+b2d8 nim # Character ë
+U+b2d9 nib # Character ë
+U+b2da nibs # Character ë
+U+b2db nis # Character ë
+U+b2dc niss # Character ë
+U+b2dd ning # Character ë
+U+b2de nij # Character ë
+U+b2df nich # Character ë
+U+b2e0 nik # Character ë
+U+b2e1 nit # Character ë¡
+U+b2e2 nip # Character ë¢
+U+b2e3 nih # Character ë£
+U+b2e4 da # Character ë¤
+U+b2e5 dag # Character ë¥
+U+b2e6 dakk # Character ë¦
+U+b2e7 dags # Character ë§
+U+b2e8 dan # Character ë¨
+U+b2e9 danj # Character ë©
+U+b2ea danh # Character ëª
+U+b2eb dad # Character ë«
+U+b2ec dal # Character ë¬
+U+b2ed dalg # Character ë
+U+b2ee dalm # Character ë®
+U+b2ef dalb # Character ë¯
+U+b2f0 dals # Character ë°
+U+b2f1 dalt # Character ë±
+U+b2f2 dalp # Character ë²
+U+b2f3 dalh # Character ë³
+U+b2f4 dam # Character ë´
+U+b2f5 dab # Character ëµ
+U+b2f6 dabs # Character ë¶
+U+b2f7 das # Character ë·
+U+b2f8 dass # Character ë¸
+U+b2f9 dang # Character ë¹
+U+b2fa daj # Character ëº
+U+b2fb dach # Character ë»
+U+b2fc dak # Character ë¼
+U+b2fd dat # Character ë½
+U+b2fe dap # Character ë¾
+U+b2ff dah # Character ë¿
diff --git a/resources/chars/latin1/rowb3.trans b/resources/chars/latin1/rowb3.trans
new file mode 100644
index 0000000..bb0dab5
--- /dev/null
+++ b/resources/chars/latin1/rowb3.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+b300 dae # Character ë
+U+b301 daeg # Character ë
+U+b302 daekk # Character ë
+U+b303 daegs # Character ë
+U+b304 daen # Character ë
+U+b305 daenj # Character ë
+U+b306 daenh # Character ë
+U+b307 daed # Character ë
+U+b308 dael # Character ë
+U+b309 daelg # Character ë
+U+b30a daelm # Character ë
+U+b30b daelb # Character ë
+U+b30c daels # Character ë
+U+b30d daelt # Character ë
+U+b30e daelp # Character ë
+U+b30f daelh # Character ë
+U+b310 daem # Character ë
+U+b311 daeb # Character ë
+U+b312 daebs # Character ë
+U+b313 daes # Character ë
+U+b314 daess # Character ë
+U+b315 daeng # Character ë
+U+b316 daej # Character ë
+U+b317 daech # Character ë
+U+b318 daek # Character ë
+U+b319 daet # Character ë
+U+b31a daep # Character ë
+U+b31b daeh # Character ë
+U+b31c dya # Character ë
+U+b31d dyag # Character ë
+U+b31e dyakk # Character ë
+U+b31f dyags # Character ë
+U+b320 dyan # Character ë
+U+b321 dyanj # Character ë¡
+U+b322 dyanh # Character ë¢
+U+b323 dyad # Character ë£
+U+b324 dyal # Character ë¤
+U+b325 dyalg # Character ë¥
+U+b326 dyalm # Character ë¦
+U+b327 dyalb # Character ë§
+U+b328 dyals # Character ë¨
+U+b329 dyalt # Character ë©
+U+b32a dyalp # Character ëª
+U+b32b dyalh # Character ë«
+U+b32c dyam # Character ë¬
+U+b32d dyab # Character ë
+U+b32e dyabs # Character ë®
+U+b32f dyas # Character ë¯
+U+b330 dyass # Character ë°
+U+b331 dyang # Character ë±
+U+b332 dyaj # Character ë²
+U+b333 dyach # Character ë³
+U+b334 dyak # Character ë´
+U+b335 dyat # Character ëµ
+U+b336 dyap # Character ë¶
+U+b337 dyah # Character ë·
+U+b338 dyae # Character ë¸
+U+b339 dyaeg # Character ë¹
+U+b33a dyaekk # Character ëº
+U+b33b dyaegs # Character ë»
+U+b33c dyaen # Character ë¼
+U+b33d dyaenj # Character ë½
+U+b33e dyaenh # Character ë¾
+U+b33f dyaed # Character ë¿
+U+b340 dyael # Character ë
+U+b341 dyaelg # Character ë
+U+b342 dyaelm # Character ë
+U+b343 dyaelb # Character ë
+U+b344 dyaels # Character ë
+U+b345 dyaelt # Character ë
+U+b346 dyaelp # Character ë
+U+b347 dyaelh # Character ë
+U+b348 dyaem # Character ë
+U+b349 dyaeb # Character ë
+U+b34a dyaebs # Character ë
+U+b34b dyaes # Character ë
+U+b34c dyaess # Character ë
+U+b34d dyaeng # Character ë
+U+b34e dyaej # Character ë
+U+b34f dyaech # Character ë
+U+b350 dyaek # Character ë
+U+b351 dyaet # Character ë
+U+b352 dyaep # Character ë
+U+b353 dyaeh # Character ë
+U+b354 deo # Character ë
+U+b355 deog # Character ë
+U+b356 deokk # Character ë
+U+b357 deogs # Character ë
+U+b358 deon # Character ë
+U+b359 deonj # Character ë
+U+b35a deonh # Character ë
+U+b35b deod # Character ë
+U+b35c deol # Character ë
+U+b35d deolg # Character ë
+U+b35e deolm # Character ë
+U+b35f deolb # Character ë
+U+b360 deols # Character ë
+U+b361 deolt # Character ë¡
+U+b362 deolp # Character ë¢
+U+b363 deolh # Character ë£
+U+b364 deom # Character ë¤
+U+b365 deob # Character ë¥
+U+b366 deobs # Character ë¦
+U+b367 deos # Character ë§
+U+b368 deoss # Character ë¨
+U+b369 deong # Character ë©
+U+b36a deoj # Character ëª
+U+b36b deoch # Character ë«
+U+b36c deok # Character ë¬
+U+b36d deot # Character ë
+U+b36e deop # Character ë®
+U+b36f deoh # Character ë¯
+U+b370 de # Character ë°
+U+b371 deg # Character ë±
+U+b372 dekk # Character ë²
+U+b373 degs # Character ë³
+U+b374 den # Character ë´
+U+b375 denj # Character ëµ
+U+b376 denh # Character ë¶
+U+b377 ded # Character ë·
+U+b378 del # Character ë¸
+U+b379 delg # Character ë¹
+U+b37a delm # Character ëº
+U+b37b delb # Character ë»
+U+b37c dels # Character ë¼
+U+b37d delt # Character ë½
+U+b37e delp # Character ë¾
+U+b37f delh # Character ë¿
+U+b380 dem # Character ë
+U+b381 deb # Character ë
+U+b382 debs # Character ë
+U+b383 des # Character ë
+U+b384 dess # Character ë
+U+b385 deng # Character ë
+U+b386 dej # Character ë
+U+b387 dech # Character ë
+U+b388 dek # Character ë
+U+b389 det # Character ë
+U+b38a dep # Character ë
+U+b38b deh # Character ë
+U+b38c dyeo # Character ë
+U+b38d dyeog # Character ë
+U+b38e dyeokk # Character ë
+U+b38f dyeogs # Character ë
+U+b390 dyeon # Character ë
+U+b391 dyeonj # Character ë
+U+b392 dyeonh # Character ë
+U+b393 dyeod # Character ë
+U+b394 dyeol # Character ë
+U+b395 dyeolg # Character ë
+U+b396 dyeolm # Character ë
+U+b397 dyeolb # Character ë
+U+b398 dyeols # Character ë
+U+b399 dyeolt # Character ë
+U+b39a dyeolp # Character ë
+U+b39b dyeolh # Character ë
+U+b39c dyeom # Character ë
+U+b39d dyeob # Character ë
+U+b39e dyeobs # Character ë
+U+b39f dyeos # Character ë
+U+b3a0 dyeoss # Character ë
+U+b3a1 dyeong # Character ë¡
+U+b3a2 dyeoj # Character ë¢
+U+b3a3 dyeoch # Character ë£
+U+b3a4 dyeok # Character ë¤
+U+b3a5 dyeot # Character ë¥
+U+b3a6 dyeop # Character ë¦
+U+b3a7 dyeoh # Character ë§
+U+b3a8 dye # Character ë¨
+U+b3a9 dyeg # Character ë©
+U+b3aa dyekk # Character ëª
+U+b3ab dyegs # Character ë«
+U+b3ac dyen # Character ë¬
+U+b3ad dyenj # Character ë
+U+b3ae dyenh # Character ë®
+U+b3af dyed # Character ë¯
+U+b3b0 dyel # Character ë°
+U+b3b1 dyelg # Character ë±
+U+b3b2 dyelm # Character ë²
+U+b3b3 dyelb # Character ë³
+U+b3b4 dyels # Character ë´
+U+b3b5 dyelt # Character ëµ
+U+b3b6 dyelp # Character ë¶
+U+b3b7 dyelh # Character ë·
+U+b3b8 dyem # Character ë¸
+U+b3b9 dyeb # Character ë¹
+U+b3ba dyebs # Character ëº
+U+b3bb dyes # Character ë»
+U+b3bc dyess # Character ë¼
+U+b3bd dyeng # Character ë½
+U+b3be dyej # Character ë¾
+U+b3bf dyech # Character ë¿
+U+b3c0 dyek # Character ë
+U+b3c1 dyet # Character ë
+U+b3c2 dyep # Character ë
+U+b3c3 dyeh # Character ë
+U+b3c4 do # Character ë
+U+b3c5 dog # Character ë
+U+b3c6 dokk # Character ë
+U+b3c7 dogs # Character ë
+U+b3c8 don # Character ë
+U+b3c9 donj # Character ë
+U+b3ca donh # Character ë
+U+b3cb dod # Character ë
+U+b3cc dol # Character ë
+U+b3cd dolg # Character ë
+U+b3ce dolm # Character ë
+U+b3cf dolb # Character ë
+U+b3d0 dols # Character ë
+U+b3d1 dolt # Character ë
+U+b3d2 dolp # Character ë
+U+b3d3 dolh # Character ë
+U+b3d4 dom # Character ë
+U+b3d5 dob # Character ë
+U+b3d6 dobs # Character ë
+U+b3d7 dos # Character ë
+U+b3d8 doss # Character ë
+U+b3d9 dong # Character ë
+U+b3da doj # Character ë
+U+b3db doch # Character ë
+U+b3dc dok # Character ë
+U+b3dd dot # Character ë
+U+b3de dop # Character ë
+U+b3df doh # Character ë
+U+b3e0 dwa # Character ë
+U+b3e1 dwag # Character ë¡
+U+b3e2 dwakk # Character ë¢
+U+b3e3 dwags # Character ë£
+U+b3e4 dwan # Character ë¤
+U+b3e5 dwanj # Character ë¥
+U+b3e6 dwanh # Character ë¦
+U+b3e7 dwad # Character ë§
+U+b3e8 dwal # Character ë¨
+U+b3e9 dwalg # Character ë©
+U+b3ea dwalm # Character ëª
+U+b3eb dwalb # Character ë«
+U+b3ec dwals # Character ë¬
+U+b3ed dwalt # Character ë
+U+b3ee dwalp # Character ë®
+U+b3ef dwalh # Character ë¯
+U+b3f0 dwam # Character ë°
+U+b3f1 dwab # Character ë±
+U+b3f2 dwabs # Character ë²
+U+b3f3 dwas # Character ë³
+U+b3f4 dwass # Character ë´
+U+b3f5 dwang # Character ëµ
+U+b3f6 dwaj # Character ë¶
+U+b3f7 dwach # Character ë·
+U+b3f8 dwak # Character ë¸
+U+b3f9 dwat # Character ë¹
+U+b3fa dwap # Character ëº
+U+b3fb dwah # Character ë»
+U+b3fc dwae # Character ë¼
+U+b3fd dwaeg # Character ë½
+U+b3fe dwaekk # Character ë¾
+U+b3ff dwaegs # Character ë¿
diff --git a/resources/chars/latin1/rowb4.trans b/resources/chars/latin1/rowb4.trans
new file mode 100644
index 0000000..1dca9f9
--- /dev/null
+++ b/resources/chars/latin1/rowb4.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+b400 dwaen # Character ë
+U+b401 dwaenj # Character ë
+U+b402 dwaenh # Character ë
+U+b403 dwaed # Character ë
+U+b404 dwael # Character ë
+U+b405 dwaelg # Character ë
+U+b406 dwaelm # Character ë
+U+b407 dwaelb # Character ë
+U+b408 dwaels # Character ë
+U+b409 dwaelt # Character ë
+U+b40a dwaelp # Character ë
+U+b40b dwaelh # Character ë
+U+b40c dwaem # Character ë
+U+b40d dwaeb # Character ë
+U+b40e dwaebs # Character ë
+U+b40f dwaes # Character ë
+U+b410 dwaess # Character ë
+U+b411 dwaeng # Character ë
+U+b412 dwaej # Character ë
+U+b413 dwaech # Character ë
+U+b414 dwaek # Character ë
+U+b415 dwaet # Character ë
+U+b416 dwaep # Character ë
+U+b417 dwaeh # Character ë
+U+b418 doe # Character ë
+U+b419 doeg # Character ë
+U+b41a doekk # Character ë
+U+b41b doegs # Character ë
+U+b41c doen # Character ë
+U+b41d doenj # Character ë
+U+b41e doenh # Character ë
+U+b41f doed # Character ë
+U+b420 doel # Character ë
+U+b421 doelg # Character ë¡
+U+b422 doelm # Character ë¢
+U+b423 doelb # Character ë£
+U+b424 doels # Character ë¤
+U+b425 doelt # Character ë¥
+U+b426 doelp # Character ë¦
+U+b427 doelh # Character ë§
+U+b428 doem # Character ë¨
+U+b429 doeb # Character ë©
+U+b42a doebs # Character ëª
+U+b42b does # Character ë«
+U+b42c doess # Character ë¬
+U+b42d doeng # Character ë
+U+b42e doej # Character ë®
+U+b42f doech # Character ë¯
+U+b430 doek # Character ë°
+U+b431 doet # Character ë±
+U+b432 doep # Character ë²
+U+b433 doeh # Character ë³
+U+b434 dyo # Character ë´
+U+b435 dyog # Character ëµ
+U+b436 dyokk # Character ë¶
+U+b437 dyogs # Character ë·
+U+b438 dyon # Character ë¸
+U+b439 dyonj # Character ë¹
+U+b43a dyonh # Character ëº
+U+b43b dyod # Character ë»
+U+b43c dyol # Character ë¼
+U+b43d dyolg # Character ë½
+U+b43e dyolm # Character ë¾
+U+b43f dyolb # Character ë¿
+U+b440 dyols # Character ë
+U+b441 dyolt # Character ë
+U+b442 dyolp # Character ë
+U+b443 dyolh # Character ë
+U+b444 dyom # Character ë
+U+b445 dyob # Character ë
+U+b446 dyobs # Character ë
+U+b447 dyos # Character ë
+U+b448 dyoss # Character ë
+U+b449 dyong # Character ë
+U+b44a dyoj # Character ë
+U+b44b dyoch # Character ë
+U+b44c dyok # Character ë
+U+b44d dyot # Character ë
+U+b44e dyop # Character ë
+U+b44f dyoh # Character ë
+U+b450 du # Character ë
+U+b451 dug # Character ë
+U+b452 dukk # Character ë
+U+b453 dugs # Character ë
+U+b454 dun # Character ë
+U+b455 dunj # Character ë
+U+b456 dunh # Character ë
+U+b457 dud # Character ë
+U+b458 dul # Character ë
+U+b459 dulg # Character ë
+U+b45a dulm # Character ë
+U+b45b dulb # Character ë
+U+b45c duls # Character ë
+U+b45d dult # Character ë
+U+b45e dulp # Character ë
+U+b45f dulh # Character ë
+U+b460 dum # Character ë
+U+b461 dub # Character ë¡
+U+b462 dubs # Character ë¢
+U+b463 dus # Character ë£
+U+b464 duss # Character ë¤
+U+b465 dung # Character ë¥
+U+b466 duj # Character ë¦
+U+b467 duch # Character ë§
+U+b468 duk # Character ë¨
+U+b469 dut # Character ë©
+U+b46a dup # Character ëª
+U+b46b duh # Character ë«
+U+b46c dwo # Character ë¬
+U+b46d dwog # Character ë
+U+b46e dwokk # Character ë®
+U+b46f dwogs # Character ë¯
+U+b470 dwon # Character ë°
+U+b471 dwonj # Character ë±
+U+b472 dwonh # Character ë²
+U+b473 dwod # Character ë³
+U+b474 dwol # Character ë´
+U+b475 dwolg # Character ëµ
+U+b476 dwolm # Character ë¶
+U+b477 dwolb # Character ë·
+U+b478 dwols # Character ë¸
+U+b479 dwolt # Character ë¹
+U+b47a dwolp # Character ëº
+U+b47b dwolh # Character ë»
+U+b47c dwom # Character ë¼
+U+b47d dwob # Character ë½
+U+b47e dwobs # Character ë¾
+U+b47f dwos # Character ë¿
+U+b480 dwoss # Character ë
+U+b481 dwong # Character ë
+U+b482 dwoj # Character ë
+U+b483 dwoch # Character ë
+U+b484 dwok # Character ë
+U+b485 dwot # Character ë
+U+b486 dwop # Character ë
+U+b487 dwoh # Character ë
+U+b488 dwe # Character ë
+U+b489 dweg # Character ë
+U+b48a dwekk # Character ë
+U+b48b dwegs # Character ë
+U+b48c dwen # Character ë
+U+b48d dwenj # Character ë
+U+b48e dwenh # Character ë
+U+b48f dwed # Character ë
+U+b490 dwel # Character ë
+U+b491 dwelg # Character ë
+U+b492 dwelm # Character ë
+U+b493 dwelb # Character ë
+U+b494 dwels # Character ë
+U+b495 dwelt # Character ë
+U+b496 dwelp # Character ë
+U+b497 dwelh # Character ë
+U+b498 dwem # Character ë
+U+b499 dweb # Character ë
+U+b49a dwebs # Character ë
+U+b49b dwes # Character ë
+U+b49c dwess # Character ë
+U+b49d dweng # Character ë
+U+b49e dwej # Character ë
+U+b49f dwech # Character ë
+U+b4a0 dwek # Character ë
+U+b4a1 dwet # Character ë¡
+U+b4a2 dwep # Character ë¢
+U+b4a3 dweh # Character ë£
+U+b4a4 dwi # Character ë¤
+U+b4a5 dwig # Character ë¥
+U+b4a6 dwikk # Character ë¦
+U+b4a7 dwigs # Character ë§
+U+b4a8 dwin # Character ë¨
+U+b4a9 dwinj # Character ë©
+U+b4aa dwinh # Character ëª
+U+b4ab dwid # Character ë«
+U+b4ac dwil # Character ë¬
+U+b4ad dwilg # Character ë
+U+b4ae dwilm # Character ë®
+U+b4af dwilb # Character ë¯
+U+b4b0 dwils # Character ë°
+U+b4b1 dwilt # Character ë±
+U+b4b2 dwilp # Character ë²
+U+b4b3 dwilh # Character ë³
+U+b4b4 dwim # Character ë´
+U+b4b5 dwib # Character ëµ
+U+b4b6 dwibs # Character ë¶
+U+b4b7 dwis # Character ë·
+U+b4b8 dwiss # Character ë¸
+U+b4b9 dwing # Character ë¹
+U+b4ba dwij # Character ëº
+U+b4bb dwich # Character ë»
+U+b4bc dwik # Character ë¼
+U+b4bd dwit # Character ë½
+U+b4be dwip # Character ë¾
+U+b4bf dwih # Character ë¿
+U+b4c0 dyu # Character ë
+U+b4c1 dyug # Character ë
+U+b4c2 dyukk # Character ë
+U+b4c3 dyugs # Character ë
+U+b4c4 dyun # Character ë
+U+b4c5 dyunj # Character ë
+U+b4c6 dyunh # Character ë
+U+b4c7 dyud # Character ë
+U+b4c8 dyul # Character ë
+U+b4c9 dyulg # Character ë
+U+b4ca dyulm # Character ë
+U+b4cb dyulb # Character ë
+U+b4cc dyuls # Character ë
+U+b4cd dyult # Character ë
+U+b4ce dyulp # Character ë
+U+b4cf dyulh # Character ë
+U+b4d0 dyum # Character ë
+U+b4d1 dyub # Character ë
+U+b4d2 dyubs # Character ë
+U+b4d3 dyus # Character ë
+U+b4d4 dyuss # Character ë
+U+b4d5 dyung # Character ë
+U+b4d6 dyuj # Character ë
+U+b4d7 dyuch # Character ë
+U+b4d8 dyuk # Character ë
+U+b4d9 dyut # Character ë
+U+b4da dyup # Character ë
+U+b4db dyuh # Character ë
+U+b4dc deu # Character ë
+U+b4dd deug # Character ë
+U+b4de deukk # Character ë
+U+b4df deugs # Character ë
+U+b4e0 deun # Character ë
+U+b4e1 deunj # Character ë¡
+U+b4e2 deunh # Character ë¢
+U+b4e3 deud # Character ë£
+U+b4e4 deul # Character ë¤
+U+b4e5 deulg # Character ë¥
+U+b4e6 deulm # Character ë¦
+U+b4e7 deulb # Character ë§
+U+b4e8 deuls # Character ë¨
+U+b4e9 deult # Character ë©
+U+b4ea deulp # Character ëª
+U+b4eb deulh # Character ë«
+U+b4ec deum # Character ë¬
+U+b4ed deub # Character ë
+U+b4ee deubs # Character ë®
+U+b4ef deus # Character ë¯
+U+b4f0 deuss # Character ë°
+U+b4f1 deung # Character ë±
+U+b4f2 deuj # Character ë²
+U+b4f3 deuch # Character ë³
+U+b4f4 deuk # Character ë´
+U+b4f5 deut # Character ëµ
+U+b4f6 deup # Character ë¶
+U+b4f7 deuh # Character ë·
+U+b4f8 dui # Character ë¸
+U+b4f9 duig # Character ë¹
+U+b4fa duikk # Character ëº
+U+b4fb duigs # Character ë»
+U+b4fc duin # Character ë¼
+U+b4fd duinj # Character ë½
+U+b4fe duinh # Character ë¾
+U+b4ff duid # Character ë¿
diff --git a/resources/chars/latin1/rowb5.trans b/resources/chars/latin1/rowb5.trans
new file mode 100644
index 0000000..e584907
--- /dev/null
+++ b/resources/chars/latin1/rowb5.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+b500 duil # Character ë
+U+b501 duilg # Character ë
+U+b502 duilm # Character ë
+U+b503 duilb # Character ë
+U+b504 duils # Character ë
+U+b505 duilt # Character ë
+U+b506 duilp # Character ë
+U+b507 duilh # Character ë
+U+b508 duim # Character ë
+U+b509 duib # Character ë
+U+b50a duibs # Character ë
+U+b50b duis # Character ë
+U+b50c duiss # Character ë
+U+b50d duing # Character ë
+U+b50e duij # Character ë
+U+b50f duich # Character ë
+U+b510 duik # Character ë
+U+b511 duit # Character ë
+U+b512 duip # Character ë
+U+b513 duih # Character ë
+U+b514 di # Character ë
+U+b515 dig # Character ë
+U+b516 dikk # Character ë
+U+b517 digs # Character ë
+U+b518 din # Character ë
+U+b519 dinj # Character ë
+U+b51a dinh # Character ë
+U+b51b did # Character ë
+U+b51c dil # Character ë
+U+b51d dilg # Character ë
+U+b51e dilm # Character ë
+U+b51f dilb # Character ë
+U+b520 dils # Character ë
+U+b521 dilt # Character ë¡
+U+b522 dilp # Character ë¢
+U+b523 dilh # Character ë£
+U+b524 dim # Character ë¤
+U+b525 dib # Character ë¥
+U+b526 dibs # Character ë¦
+U+b527 dis # Character ë§
+U+b528 diss # Character ë¨
+U+b529 ding # Character ë©
+U+b52a dij # Character ëª
+U+b52b dich # Character ë«
+U+b52c dik # Character ë¬
+U+b52d dit # Character ë
+U+b52e dip # Character ë®
+U+b52f dih # Character ë¯
+U+b530 tta # Character ë°
+U+b531 ttag # Character ë±
+U+b532 ttakk # Character ë²
+U+b533 ttags # Character ë³
+U+b534 ttan # Character ë´
+U+b535 ttanj # Character ëµ
+U+b536 ttanh # Character ë¶
+U+b537 ttad # Character ë·
+U+b538 ttal # Character ë¸
+U+b539 ttalg # Character ë¹
+U+b53a ttalm # Character ëº
+U+b53b ttalb # Character ë»
+U+b53c ttals # Character ë¼
+U+b53d ttalt # Character ë½
+U+b53e ttalp # Character ë¾
+U+b53f ttalh # Character ë¿
+U+b540 ttam # Character ë
+U+b541 ttab # Character ë
+U+b542 ttabs # Character ë
+U+b543 ttas # Character ë
+U+b544 ttass # Character ë
+U+b545 ttang # Character ë
+U+b546 ttaj # Character ë
+U+b547 ttach # Character ë
+U+b548 ttak # Character ë
+U+b549 ttat # Character ë
+U+b54a ttap # Character ë
+U+b54b ttah # Character ë
+U+b54c ttae # Character ë
+U+b54d ttaeg # Character ë
+U+b54e ttaekk # Character ë
+U+b54f ttaegs # Character ë
+U+b550 ttaen # Character ë
+U+b551 ttaenj # Character ë
+U+b552 ttaenh # Character ë
+U+b553 ttaed # Character ë
+U+b554 ttael # Character ë
+U+b555 ttaelg # Character ë
+U+b556 ttaelm # Character ë
+U+b557 ttaelb # Character ë
+U+b558 ttaels # Character ë
+U+b559 ttaelt # Character ë
+U+b55a ttaelp # Character ë
+U+b55b ttaelh # Character ë
+U+b55c ttaem # Character ë
+U+b55d ttaeb # Character ë
+U+b55e ttaebs # Character ë
+U+b55f ttaes # Character ë
+U+b560 ttaess # Character ë
+U+b561 ttaeng # Character ë¡
+U+b562 ttaej # Character ë¢
+U+b563 ttaech # Character ë£
+U+b564 ttaek # Character ë¤
+U+b565 ttaet # Character ë¥
+U+b566 ttaep # Character ë¦
+U+b567 ttaeh # Character ë§
+U+b568 ttya # Character ë¨
+U+b569 ttyag # Character ë©
+U+b56a ttyakk # Character ëª
+U+b56b ttyags # Character ë«
+U+b56c ttyan # Character ë¬
+U+b56d ttyanj # Character ë
+U+b56e ttyanh # Character ë®
+U+b56f ttyad # Character ë¯
+U+b570 ttyal # Character ë°
+U+b571 ttyalg # Character ë±
+U+b572 ttyalm # Character ë²
+U+b573 ttyalb # Character ë³
+U+b574 ttyals # Character ë´
+U+b575 ttyalt # Character ëµ
+U+b576 ttyalp # Character ë¶
+U+b577 ttyalh # Character ë·
+U+b578 ttyam # Character ë¸
+U+b579 ttyab # Character ë¹
+U+b57a ttyabs # Character ëº
+U+b57b ttyas # Character ë»
+U+b57c ttyass # Character ë¼
+U+b57d ttyang # Character ë½
+U+b57e ttyaj # Character ë¾
+U+b57f ttyach # Character ë¿
+U+b580 ttyak # Character ë
+U+b581 ttyat # Character ë
+U+b582 ttyap # Character ë
+U+b583 ttyah # Character ë
+U+b584 ttyae # Character ë
+U+b585 ttyaeg # Character ë
+U+b586 ttyaekk # Character ë
+U+b587 ttyaegs # Character ë
+U+b588 ttyaen # Character ë
+U+b589 ttyaenj # Character ë
+U+b58a ttyaenh # Character ë
+U+b58b ttyaed # Character ë
+U+b58c ttyael # Character ë
+U+b58d ttyaelg # Character ë
+U+b58e ttyaelm # Character ë
+U+b58f ttyaelb # Character ë
+U+b590 ttyaels # Character ë
+U+b591 ttyaelt # Character ë
+U+b592 ttyaelp # Character ë
+U+b593 ttyaelh # Character ë
+U+b594 ttyaem # Character ë
+U+b595 ttyaeb # Character ë
+U+b596 ttyaebs # Character ë
+U+b597 ttyaes # Character ë
+U+b598 ttyaess # Character ë
+U+b599 ttyaeng # Character ë
+U+b59a ttyaej # Character ë
+U+b59b ttyaech # Character ë
+U+b59c ttyaek # Character ë
+U+b59d ttyaet # Character ë
+U+b59e ttyaep # Character ë
+U+b59f ttyaeh # Character ë
+U+b5a0 tteo # Character ë
+U+b5a1 tteog # Character ë¡
+U+b5a2 tteokk # Character ë¢
+U+b5a3 tteogs # Character ë£
+U+b5a4 tteon # Character ë¤
+U+b5a5 tteonj # Character ë¥
+U+b5a6 tteonh # Character ë¦
+U+b5a7 tteod # Character ë§
+U+b5a8 tteol # Character ë¨
+U+b5a9 tteolg # Character ë©
+U+b5aa tteolm # Character ëª
+U+b5ab tteolb # Character ë«
+U+b5ac tteols # Character ë¬
+U+b5ad tteolt # Character ë
+U+b5ae tteolp # Character ë®
+U+b5af tteolh # Character ë¯
+U+b5b0 tteom # Character ë°
+U+b5b1 tteob # Character ë±
+U+b5b2 tteobs # Character ë²
+U+b5b3 tteos # Character ë³
+U+b5b4 tteoss # Character ë´
+U+b5b5 tteong # Character ëµ
+U+b5b6 tteoj # Character ë¶
+U+b5b7 tteoch # Character ë·
+U+b5b8 tteok # Character ë¸
+U+b5b9 tteot # Character ë¹
+U+b5ba tteop # Character ëº
+U+b5bb tteoh # Character ë»
+U+b5bc tte # Character ë¼
+U+b5bd tteg # Character ë½
+U+b5be ttekk # Character ë¾
+U+b5bf ttegs # Character ë¿
+U+b5c0 tten # Character ë
+U+b5c1 ttenj # Character ë
+U+b5c2 ttenh # Character ë
+U+b5c3 tted # Character ë
+U+b5c4 ttel # Character ë
+U+b5c5 ttelg # Character ë
+U+b5c6 ttelm # Character ë
+U+b5c7 ttelb # Character ë
+U+b5c8 ttels # Character ë
+U+b5c9 ttelt # Character ë
+U+b5ca ttelp # Character ë
+U+b5cb ttelh # Character ë
+U+b5cc ttem # Character ë
+U+b5cd tteb # Character ë
+U+b5ce ttebs # Character ë
+U+b5cf ttes # Character ë
+U+b5d0 ttess # Character ë
+U+b5d1 tteng # Character ë
+U+b5d2 ttej # Character ë
+U+b5d3 ttech # Character ë
+U+b5d4 ttek # Character ë
+U+b5d5 ttet # Character ë
+U+b5d6 ttep # Character ë
+U+b5d7 tteh # Character ë
+U+b5d8 ttyeo # Character ë
+U+b5d9 ttyeog # Character ë
+U+b5da ttyeokk # Character ë
+U+b5db ttyeogs # Character ë
+U+b5dc ttyeon # Character ë
+U+b5dd ttyeonj # Character ë
+U+b5de ttyeonh # Character ë
+U+b5df ttyeod # Character ë
+U+b5e0 ttyeol # Character ë
+U+b5e1 ttyeolg # Character ë¡
+U+b5e2 ttyeolm # Character ë¢
+U+b5e3 ttyeolb # Character ë£
+U+b5e4 ttyeols # Character ë¤
+U+b5e5 ttyeolt # Character ë¥
+U+b5e6 ttyeolp # Character ë¦
+U+b5e7 ttyeolh # Character ë§
+U+b5e8 ttyeom # Character ë¨
+U+b5e9 ttyeob # Character ë©
+U+b5ea ttyeobs # Character ëª
+U+b5eb ttyeos # Character ë«
+U+b5ec ttyeoss # Character ë¬
+U+b5ed ttyeong # Character ë
+U+b5ee ttyeoj # Character ë®
+U+b5ef ttyeoch # Character ë¯
+U+b5f0 ttyeok # Character ë°
+U+b5f1 ttyeot # Character ë±
+U+b5f2 ttyeop # Character ë²
+U+b5f3 ttyeoh # Character ë³
+U+b5f4 ttye # Character ë´
+U+b5f5 ttyeg # Character ëµ
+U+b5f6 ttyekk # Character ë¶
+U+b5f7 ttyegs # Character ë·
+U+b5f8 ttyen # Character ë¸
+U+b5f9 ttyenj # Character ë¹
+U+b5fa ttyenh # Character ëº
+U+b5fb ttyed # Character ë»
+U+b5fc ttyel # Character ë¼
+U+b5fd ttyelg # Character ë½
+U+b5fe ttyelm # Character ë¾
+U+b5ff ttyelb # Character ë¿
diff --git a/resources/chars/latin1/rowb6.trans b/resources/chars/latin1/rowb6.trans
new file mode 100644
index 0000000..19755c0
--- /dev/null
+++ b/resources/chars/latin1/rowb6.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+b600 ttyels # Character ë
+U+b601 ttyelt # Character ë
+U+b602 ttyelp # Character ë
+U+b603 ttyelh # Character ë
+U+b604 ttyem # Character ë
+U+b605 ttyeb # Character ë
+U+b606 ttyebs # Character ë
+U+b607 ttyes # Character ë
+U+b608 ttyess # Character ë
+U+b609 ttyeng # Character ë
+U+b60a ttyej # Character ë
+U+b60b ttyech # Character ë
+U+b60c ttyek # Character ë
+U+b60d ttyet # Character ë
+U+b60e ttyep # Character ë
+U+b60f ttyeh # Character ë
+U+b610 tto # Character ë
+U+b611 ttog # Character ë
+U+b612 ttokk # Character ë
+U+b613 ttogs # Character ë
+U+b614 tton # Character ë
+U+b615 ttonj # Character ë
+U+b616 ttonh # Character ë
+U+b617 ttod # Character ë
+U+b618 ttol # Character ë
+U+b619 ttolg # Character ë
+U+b61a ttolm # Character ë
+U+b61b ttolb # Character ë
+U+b61c ttols # Character ë
+U+b61d ttolt # Character ë
+U+b61e ttolp # Character ë
+U+b61f ttolh # Character ë
+U+b620 ttom # Character ë
+U+b621 ttob # Character ë¡
+U+b622 ttobs # Character ë¢
+U+b623 ttos # Character ë£
+U+b624 ttoss # Character ë¤
+U+b625 ttong # Character ë¥
+U+b626 ttoj # Character ë¦
+U+b627 ttoch # Character ë§
+U+b628 ttok # Character ë¨
+U+b629 ttot # Character ë©
+U+b62a ttop # Character ëª
+U+b62b ttoh # Character ë«
+U+b62c ttwa # Character ë¬
+U+b62d ttwag # Character ë
+U+b62e ttwakk # Character ë®
+U+b62f ttwags # Character ë¯
+U+b630 ttwan # Character ë°
+U+b631 ttwanj # Character ë±
+U+b632 ttwanh # Character ë²
+U+b633 ttwad # Character ë³
+U+b634 ttwal # Character ë´
+U+b635 ttwalg # Character ëµ
+U+b636 ttwalm # Character ë¶
+U+b637 ttwalb # Character ë·
+U+b638 ttwals # Character ë¸
+U+b639 ttwalt # Character ë¹
+U+b63a ttwalp # Character ëº
+U+b63b ttwalh # Character ë»
+U+b63c ttwam # Character ë¼
+U+b63d ttwab # Character ë½
+U+b63e ttwabs # Character ë¾
+U+b63f ttwas # Character ë¿
+U+b640 ttwass # Character ë
+U+b641 ttwang # Character ë
+U+b642 ttwaj # Character ë
+U+b643 ttwach # Character ë
+U+b644 ttwak # Character ë
+U+b645 ttwat # Character ë
+U+b646 ttwap # Character ë
+U+b647 ttwah # Character ë
+U+b648 ttwae # Character ë
+U+b649 ttwaeg # Character ë
+U+b64a ttwaekk # Character ë
+U+b64b ttwaegs # Character ë
+U+b64c ttwaen # Character ë
+U+b64d ttwaenj # Character ë
+U+b64e ttwaenh # Character ë
+U+b64f ttwaed # Character ë
+U+b650 ttwael # Character ë
+U+b651 ttwaelg # Character ë
+U+b652 ttwaelm # Character ë
+U+b653 ttwaelb # Character ë
+U+b654 ttwaels # Character ë
+U+b655 ttwaelt # Character ë
+U+b656 ttwaelp # Character ë
+U+b657 ttwaelh # Character ë
+U+b658 ttwaem # Character ë
+U+b659 ttwaeb # Character ë
+U+b65a ttwaebs # Character ë
+U+b65b ttwaes # Character ë
+U+b65c ttwaess # Character ë
+U+b65d ttwaeng # Character ë
+U+b65e ttwaej # Character ë
+U+b65f ttwaech # Character ë
+U+b660 ttwaek # Character ë
+U+b661 ttwaet # Character ë¡
+U+b662 ttwaep # Character ë¢
+U+b663 ttwaeh # Character ë£
+U+b664 ttoe # Character ë¤
+U+b665 ttoeg # Character ë¥
+U+b666 ttoekk # Character ë¦
+U+b667 ttoegs # Character ë§
+U+b668 ttoen # Character ë¨
+U+b669 ttoenj # Character ë©
+U+b66a ttoenh # Character ëª
+U+b66b ttoed # Character ë«
+U+b66c ttoel # Character ë¬
+U+b66d ttoelg # Character ë
+U+b66e ttoelm # Character ë®
+U+b66f ttoelb # Character ë¯
+U+b670 ttoels # Character ë°
+U+b671 ttoelt # Character ë±
+U+b672 ttoelp # Character ë²
+U+b673 ttoelh # Character ë³
+U+b674 ttoem # Character ë´
+U+b675 ttoeb # Character ëµ
+U+b676 ttoebs # Character ë¶
+U+b677 ttoes # Character ë·
+U+b678 ttoess # Character ë¸
+U+b679 ttoeng # Character ë¹
+U+b67a ttoej # Character ëº
+U+b67b ttoech # Character ë»
+U+b67c ttoek # Character ë¼
+U+b67d ttoet # Character ë½
+U+b67e ttoep # Character ë¾
+U+b67f ttoeh # Character ë¿
+U+b680 ttyo # Character ë
+U+b681 ttyog # Character ë
+U+b682 ttyokk # Character ë
+U+b683 ttyogs # Character ë
+U+b684 ttyon # Character ë
+U+b685 ttyonj # Character ë
+U+b686 ttyonh # Character ë
+U+b687 ttyod # Character ë
+U+b688 ttyol # Character ë
+U+b689 ttyolg # Character ë
+U+b68a ttyolm # Character ë
+U+b68b ttyolb # Character ë
+U+b68c ttyols # Character ë
+U+b68d ttyolt # Character ë
+U+b68e ttyolp # Character ë
+U+b68f ttyolh # Character ë
+U+b690 ttyom # Character ë
+U+b691 ttyob # Character ë
+U+b692 ttyobs # Character ë
+U+b693 ttyos # Character ë
+U+b694 ttyoss # Character ë
+U+b695 ttyong # Character ë
+U+b696 ttyoj # Character ë
+U+b697 ttyoch # Character ë
+U+b698 ttyok # Character ë
+U+b699 ttyot # Character ë
+U+b69a ttyop # Character ë
+U+b69b ttyoh # Character ë
+U+b69c ttu # Character ë
+U+b69d ttug # Character ë
+U+b69e ttukk # Character ë
+U+b69f ttugs # Character ë
+U+b6a0 ttun # Character ë
+U+b6a1 ttunj # Character ë¡
+U+b6a2 ttunh # Character ë¢
+U+b6a3 ttud # Character ë£
+U+b6a4 ttul # Character ë¤
+U+b6a5 ttulg # Character ë¥
+U+b6a6 ttulm # Character ë¦
+U+b6a7 ttulb # Character ë§
+U+b6a8 ttuls # Character ë¨
+U+b6a9 ttult # Character ë©
+U+b6aa ttulp # Character ëª
+U+b6ab ttulh # Character ë«
+U+b6ac ttum # Character ë¬
+U+b6ad ttub # Character ë
+U+b6ae ttubs # Character ë®
+U+b6af ttus # Character ë¯
+U+b6b0 ttuss # Character ë°
+U+b6b1 ttung # Character ë±
+U+b6b2 ttuj # Character ë²
+U+b6b3 ttuch # Character ë³
+U+b6b4 ttuk # Character ë´
+U+b6b5 ttut # Character ëµ
+U+b6b6 ttup # Character ë¶
+U+b6b7 ttuh # Character ë·
+U+b6b8 ttwo # Character ë¸
+U+b6b9 ttwog # Character ë¹
+U+b6ba ttwokk # Character ëº
+U+b6bb ttwogs # Character ë»
+U+b6bc ttwon # Character ë¼
+U+b6bd ttwonj # Character ë½
+U+b6be ttwonh # Character ë¾
+U+b6bf ttwod # Character ë¿
+U+b6c0 ttwol # Character ë
+U+b6c1 ttwolg # Character ë
+U+b6c2 ttwolm # Character ë
+U+b6c3 ttwolb # Character ë
+U+b6c4 ttwols # Character ë
+U+b6c5 ttwolt # Character ë
+U+b6c6 ttwolp # Character ë
+U+b6c7 ttwolh # Character ë
+U+b6c8 ttwom # Character ë
+U+b6c9 ttwob # Character ë
+U+b6ca ttwobs # Character ë
+U+b6cb ttwos # Character ë
+U+b6cc ttwoss # Character ë
+U+b6cd ttwong # Character ë
+U+b6ce ttwoj # Character ë
+U+b6cf ttwoch # Character ë
+U+b6d0 ttwok # Character ë
+U+b6d1 ttwot # Character ë
+U+b6d2 ttwop # Character ë
+U+b6d3 ttwoh # Character ë
+U+b6d4 ttwe # Character ë
+U+b6d5 ttweg # Character ë
+U+b6d6 ttwekk # Character ë
+U+b6d7 ttwegs # Character ë
+U+b6d8 ttwen # Character ë
+U+b6d9 ttwenj # Character ë
+U+b6da ttwenh # Character ë
+U+b6db ttwed # Character ë
+U+b6dc ttwel # Character ë
+U+b6dd ttwelg # Character ë
+U+b6de ttwelm # Character ë
+U+b6df ttwelb # Character ë
+U+b6e0 ttwels # Character ë
+U+b6e1 ttwelt # Character ë¡
+U+b6e2 ttwelp # Character ë¢
+U+b6e3 ttwelh # Character ë£
+U+b6e4 ttwem # Character ë¤
+U+b6e5 ttweb # Character ë¥
+U+b6e6 ttwebs # Character ë¦
+U+b6e7 ttwes # Character ë§
+U+b6e8 ttwess # Character ë¨
+U+b6e9 ttweng # Character ë©
+U+b6ea ttwej # Character ëª
+U+b6eb ttwech # Character ë«
+U+b6ec ttwek # Character ë¬
+U+b6ed ttwet # Character ë
+U+b6ee ttwep # Character ë®
+U+b6ef ttweh # Character ë¯
+U+b6f0 ttwi # Character ë°
+U+b6f1 ttwig # Character ë±
+U+b6f2 ttwikk # Character ë²
+U+b6f3 ttwigs # Character ë³
+U+b6f4 ttwin # Character ë´
+U+b6f5 ttwinj # Character ëµ
+U+b6f6 ttwinh # Character ë¶
+U+b6f7 ttwid # Character ë·
+U+b6f8 ttwil # Character ë¸
+U+b6f9 ttwilg # Character ë¹
+U+b6fa ttwilm # Character ëº
+U+b6fb ttwilb # Character ë»
+U+b6fc ttwils # Character ë¼
+U+b6fd ttwilt # Character ë½
+U+b6fe ttwilp # Character ë¾
+U+b6ff ttwilh # Character ë¿
diff --git a/resources/chars/latin1/rowb7.trans b/resources/chars/latin1/rowb7.trans
new file mode 100644
index 0000000..0c18b60
--- /dev/null
+++ b/resources/chars/latin1/rowb7.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+b700 ttwim # Character ë
+U+b701 ttwib # Character ë
+U+b702 ttwibs # Character ë
+U+b703 ttwis # Character ë
+U+b704 ttwiss # Character ë
+U+b705 ttwing # Character ë
+U+b706 ttwij # Character ë
+U+b707 ttwich # Character ë
+U+b708 ttwik # Character ë
+U+b709 ttwit # Character ë
+U+b70a ttwip # Character ë
+U+b70b ttwih # Character ë
+U+b70c ttyu # Character ë
+U+b70d ttyug # Character ë
+U+b70e ttyukk # Character ë
+U+b70f ttyugs # Character ë
+U+b710 ttyun # Character ë
+U+b711 ttyunj # Character ë
+U+b712 ttyunh # Character ë
+U+b713 ttyud # Character ë
+U+b714 ttyul # Character ë
+U+b715 ttyulg # Character ë
+U+b716 ttyulm # Character ë
+U+b717 ttyulb # Character ë
+U+b718 ttyuls # Character ë
+U+b719 ttyult # Character ë
+U+b71a ttyulp # Character ë
+U+b71b ttyulh # Character ë
+U+b71c ttyum # Character ë
+U+b71d ttyub # Character ë
+U+b71e ttyubs # Character ë
+U+b71f ttyus # Character ë
+U+b720 ttyuss # Character ë
+U+b721 ttyung # Character ë¡
+U+b722 ttyuj # Character ë¢
+U+b723 ttyuch # Character ë£
+U+b724 ttyuk # Character ë¤
+U+b725 ttyut # Character ë¥
+U+b726 ttyup # Character ë¦
+U+b727 ttyuh # Character ë§
+U+b728 tteu # Character ë¨
+U+b729 tteug # Character ë©
+U+b72a tteukk # Character ëª
+U+b72b tteugs # Character ë«
+U+b72c tteun # Character ë¬
+U+b72d tteunj # Character ë
+U+b72e tteunh # Character ë®
+U+b72f tteud # Character ë¯
+U+b730 tteul # Character ë°
+U+b731 tteulg # Character ë±
+U+b732 tteulm # Character ë²
+U+b733 tteulb # Character ë³
+U+b734 tteuls # Character ë´
+U+b735 tteult # Character ëµ
+U+b736 tteulp # Character ë¶
+U+b737 tteulh # Character ë·
+U+b738 tteum # Character ë¸
+U+b739 tteub # Character ë¹
+U+b73a tteubs # Character ëº
+U+b73b tteus # Character ë»
+U+b73c tteuss # Character ë¼
+U+b73d tteung # Character ë½
+U+b73e tteuj # Character ë¾
+U+b73f tteuch # Character ë¿
+U+b740 tteuk # Character ë
+U+b741 tteut # Character ë
+U+b742 tteup # Character ë
+U+b743 tteuh # Character ë
+U+b744 ttui # Character ë
+U+b745 ttuig # Character ë
+U+b746 ttuikk # Character ë
+U+b747 ttuigs # Character ë
+U+b748 ttuin # Character ë
+U+b749 ttuinj # Character ë
+U+b74a ttuinh # Character ë
+U+b74b ttuid # Character ë
+U+b74c ttuil # Character ë
+U+b74d ttuilg # Character ë
+U+b74e ttuilm # Character ë
+U+b74f ttuilb # Character ë
+U+b750 ttuils # Character ë
+U+b751 ttuilt # Character ë
+U+b752 ttuilp # Character ë
+U+b753 ttuilh # Character ë
+U+b754 ttuim # Character ë
+U+b755 ttuib # Character ë
+U+b756 ttuibs # Character ë
+U+b757 ttuis # Character ë
+U+b758 ttuiss # Character ë
+U+b759 ttuing # Character ë
+U+b75a ttuij # Character ë
+U+b75b ttuich # Character ë
+U+b75c ttuik # Character ë
+U+b75d ttuit # Character ë
+U+b75e ttuip # Character ë
+U+b75f ttuih # Character ë
+U+b760 tti # Character ë
+U+b761 ttig # Character ë¡
+U+b762 ttikk # Character ë¢
+U+b763 ttigs # Character ë£
+U+b764 ttin # Character ë¤
+U+b765 ttinj # Character ë¥
+U+b766 ttinh # Character ë¦
+U+b767 ttid # Character ë§
+U+b768 ttil # Character ë¨
+U+b769 ttilg # Character ë©
+U+b76a ttilm # Character ëª
+U+b76b ttilb # Character ë«
+U+b76c ttils # Character ë¬
+U+b76d ttilt # Character ë
+U+b76e ttilp # Character ë®
+U+b76f ttilh # Character ë¯
+U+b770 ttim # Character ë°
+U+b771 ttib # Character ë±
+U+b772 ttibs # Character ë²
+U+b773 ttis # Character ë³
+U+b774 ttiss # Character ë´
+U+b775 tting # Character ëµ
+U+b776 ttij # Character ë¶
+U+b777 ttich # Character ë·
+U+b778 ttik # Character ë¸
+U+b779 ttit # Character ë¹
+U+b77a ttip # Character ëº
+U+b77b ttih # Character ë»
+U+b77c la # Character ë¼
+U+b77d lag # Character ë½
+U+b77e lakk # Character ë¾
+U+b77f lags # Character ë¿
+U+b780 lan # Character ë
+U+b781 lanj # Character ë
+U+b782 lanh # Character ë
+U+b783 lad # Character ë
+U+b784 lal # Character ë
+U+b785 lalg # Character ë
+U+b786 lalm # Character ë
+U+b787 lalb # Character ë
+U+b788 lals # Character ë
+U+b789 lalt # Character ë
+U+b78a lalp # Character ë
+U+b78b lalh # Character ë
+U+b78c lam # Character ë
+U+b78d lab # Character ë
+U+b78e labs # Character ë
+U+b78f las # Character ë
+U+b790 lass # Character ë
+U+b791 lang # Character ë
+U+b792 laj # Character ë
+U+b793 lach # Character ë
+U+b794 lak # Character ë
+U+b795 lat # Character ë
+U+b796 lap # Character ë
+U+b797 lah # Character ë
+U+b798 lae # Character ë
+U+b799 laeg # Character ë
+U+b79a laekk # Character ë
+U+b79b laegs # Character ë
+U+b79c laen # Character ë
+U+b79d laenj # Character ë
+U+b79e laenh # Character ë
+U+b79f laed # Character ë
+U+b7a0 lael # Character ë
+U+b7a1 laelg # Character ë¡
+U+b7a2 laelm # Character ë¢
+U+b7a3 laelb # Character ë£
+U+b7a4 laels # Character ë¤
+U+b7a5 laelt # Character ë¥
+U+b7a6 laelp # Character ë¦
+U+b7a7 laelh # Character ë§
+U+b7a8 laem # Character ë¨
+U+b7a9 laeb # Character ë©
+U+b7aa laebs # Character ëª
+U+b7ab laes # Character ë«
+U+b7ac laess # Character ë¬
+U+b7ad laeng # Character ë
+U+b7ae laej # Character ë®
+U+b7af laech # Character ë¯
+U+b7b0 laek # Character ë°
+U+b7b1 laet # Character ë±
+U+b7b2 laep # Character ë²
+U+b7b3 laeh # Character ë³
+U+b7b4 lya # Character ë´
+U+b7b5 lyag # Character ëµ
+U+b7b6 lyakk # Character ë¶
+U+b7b7 lyags # Character ë·
+U+b7b8 lyan # Character ë¸
+U+b7b9 lyanj # Character ë¹
+U+b7ba lyanh # Character ëº
+U+b7bb lyad # Character ë»
+U+b7bc lyal # Character ë¼
+U+b7bd lyalg # Character ë½
+U+b7be lyalm # Character ë¾
+U+b7bf lyalb # Character ë¿
+U+b7c0 lyals # Character ë
+U+b7c1 lyalt # Character ë
+U+b7c2 lyalp # Character ë
+U+b7c3 lyalh # Character ë
+U+b7c4 lyam # Character ë
+U+b7c5 lyab # Character ë
+U+b7c6 lyabs # Character ë
+U+b7c7 lyas # Character ë
+U+b7c8 lyass # Character ë
+U+b7c9 lyang # Character ë
+U+b7ca lyaj # Character ë
+U+b7cb lyach # Character ë
+U+b7cc lyak # Character ë
+U+b7cd lyat # Character ë
+U+b7ce lyap # Character ë
+U+b7cf lyah # Character ë
+U+b7d0 lyae # Character ë
+U+b7d1 lyaeg # Character ë
+U+b7d2 lyaekk # Character ë
+U+b7d3 lyaegs # Character ë
+U+b7d4 lyaen # Character ë
+U+b7d5 lyaenj # Character ë
+U+b7d6 lyaenh # Character ë
+U+b7d7 lyaed # Character ë
+U+b7d8 lyael # Character ë
+U+b7d9 lyaelg # Character ë
+U+b7da lyaelm # Character ë
+U+b7db lyaelb # Character ë
+U+b7dc lyaels # Character ë
+U+b7dd lyaelt # Character ë
+U+b7de lyaelp # Character ë
+U+b7df lyaelh # Character ë
+U+b7e0 lyaem # Character ë
+U+b7e1 lyaeb # Character ë¡
+U+b7e2 lyaebs # Character ë¢
+U+b7e3 lyaes # Character ë£
+U+b7e4 lyaess # Character ë¤
+U+b7e5 lyaeng # Character ë¥
+U+b7e6 lyaej # Character ë¦
+U+b7e7 lyaech # Character ë§
+U+b7e8 lyaek # Character ë¨
+U+b7e9 lyaet # Character ë©
+U+b7ea lyaep # Character ëª
+U+b7eb lyaeh # Character ë«
+U+b7ec leo # Character ë¬
+U+b7ed leog # Character ë
+U+b7ee leokk # Character ë®
+U+b7ef leogs # Character ë¯
+U+b7f0 leon # Character ë°
+U+b7f1 leonj # Character ë±
+U+b7f2 leonh # Character ë²
+U+b7f3 leod # Character ë³
+U+b7f4 leol # Character ë´
+U+b7f5 leolg # Character ëµ
+U+b7f6 leolm # Character ë¶
+U+b7f7 leolb # Character ë·
+U+b7f8 leols # Character ë¸
+U+b7f9 leolt # Character ë¹
+U+b7fa leolp # Character ëº
+U+b7fb leolh # Character ë»
+U+b7fc leom # Character ë¼
+U+b7fd leob # Character ë½
+U+b7fe leobs # Character ë¾
+U+b7ff leos # Character ë¿
diff --git a/resources/chars/latin1/rowb8.trans b/resources/chars/latin1/rowb8.trans
new file mode 100644
index 0000000..324fc67
--- /dev/null
+++ b/resources/chars/latin1/rowb8.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+b800 leoss # Character ë
+U+b801 leong # Character ë
+U+b802 leoj # Character ë
+U+b803 leoch # Character ë
+U+b804 leok # Character ë
+U+b805 leot # Character ë
+U+b806 leop # Character ë
+U+b807 leoh # Character ë
+U+b808 le # Character ë
+U+b809 leg # Character ë
+U+b80a lekk # Character ë
+U+b80b legs # Character ë
+U+b80c len # Character ë
+U+b80d lenj # Character ë
+U+b80e lenh # Character ë
+U+b80f led # Character ë
+U+b810 lel # Character ë
+U+b811 lelg # Character ë
+U+b812 lelm # Character ë
+U+b813 lelb # Character ë
+U+b814 lels # Character ë
+U+b815 lelt # Character ë
+U+b816 lelp # Character ë
+U+b817 lelh # Character ë
+U+b818 lem # Character ë
+U+b819 leb # Character ë
+U+b81a lebs # Character ë
+U+b81b les # Character ë
+U+b81c less # Character ë
+U+b81d leng # Character ë
+U+b81e lej # Character ë
+U+b81f lech # Character ë
+U+b820 lek # Character ë
+U+b821 let # Character ë ¡
+U+b822 lep # Character ë ¢
+U+b823 leh # Character ë £
+U+b824 lyeo # Character ë ¤
+U+b825 lyeog # Character ë ¥
+U+b826 lyeokk # Character ë ¦
+U+b827 lyeogs # Character ë §
+U+b828 lyeon # Character ë ¨
+U+b829 lyeonj # Character ë ©
+U+b82a lyeonh # Character ë ª
+U+b82b lyeod # Character ë «
+U+b82c lyeol # Character ë ¬
+U+b82d lyeolg # Character ë
+U+b82e lyeolm # Character ë ®
+U+b82f lyeolb # Character ë ¯
+U+b830 lyeols # Character ë °
+U+b831 lyeolt # Character ë ±
+U+b832 lyeolp # Character ë ²
+U+b833 lyeolh # Character ë ³
+U+b834 lyeom # Character ë ´
+U+b835 lyeob # Character ë µ
+U+b836 lyeobs # Character ë ¶
+U+b837 lyeos # Character ë ·
+U+b838 lyeoss # Character ë ¸
+U+b839 lyeong # Character ë ¹
+U+b83a lyeoj # Character ë º
+U+b83b lyeoch # Character ë »
+U+b83c lyeok # Character ë ¼
+U+b83d lyeot # Character ë ½
+U+b83e lyeop # Character ë ¾
+U+b83f lyeoh # Character ë ¿
+U+b840 lye # Character ë¡
+U+b841 lyeg # Character ë¡
+U+b842 lyekk # Character ë¡
+U+b843 lyegs # Character ë¡
+U+b844 lyen # Character ë¡
+U+b845 lyenj # Character ë¡
+U+b846 lyenh # Character ë¡
+U+b847 lyed # Character ë¡
+U+b848 lyel # Character ë¡
+U+b849 lyelg # Character ë¡
+U+b84a lyelm # Character ë¡
+U+b84b lyelb # Character ë¡
+U+b84c lyels # Character ë¡
+U+b84d lyelt # Character ë¡
+U+b84e lyelp # Character ë¡
+U+b84f lyelh # Character ë¡
+U+b850 lyem # Character ë¡
+U+b851 lyeb # Character ë¡
+U+b852 lyebs # Character ë¡
+U+b853 lyes # Character ë¡
+U+b854 lyess # Character ë¡
+U+b855 lyeng # Character ë¡
+U+b856 lyej # Character ë¡
+U+b857 lyech # Character ë¡
+U+b858 lyek # Character ë¡
+U+b859 lyet # Character ë¡
+U+b85a lyep # Character ë¡
+U+b85b lyeh # Character ë¡
+U+b85c lo # Character ë¡
+U+b85d log # Character ë¡
+U+b85e lokk # Character ë¡
+U+b85f logs # Character ë¡
+U+b860 lon # Character ë¡
+U+b861 lonj # Character ë¡¡
+U+b862 lonh # Character ë¡¢
+U+b863 lod # Character ë¡£
+U+b864 lol # Character 롤
+U+b865 lolg # Character ë¡¥
+U+b866 lolm # Character 롦
+U+b867 lolb # Character 롧
+U+b868 lols # Character 롨
+U+b869 lolt # Character ë¡©
+U+b86a lolp # Character 롪
+U+b86b lolh # Character ë¡«
+U+b86c lom # Character 롬
+U+b86d lob # Character ë¡
+U+b86e lobs # Character ë¡®
+U+b86f los # Character 롯
+U+b870 loss # Character ë¡°
+U+b871 long # Character 롱
+U+b872 loj # Character 롲
+U+b873 loch # Character 롳
+U+b874 lok # Character ë¡´
+U+b875 lot # Character 롵
+U+b876 lop # Character 롶
+U+b877 loh # Character ë¡·
+U+b878 lwa # Character 롸
+U+b879 lwag # Character 롹
+U+b87a lwakk # Character 롺
+U+b87b lwags # Character ë¡»
+U+b87c lwan # Character 롼
+U+b87d lwanj # Character 롽
+U+b87e lwanh # Character 롾
+U+b87f lwad # Character ë¡¿
+U+b880 lwal # Character ë¢
+U+b881 lwalg # Character ë¢
+U+b882 lwalm # Character ë¢
+U+b883 lwalb # Character ë¢
+U+b884 lwals # Character ë¢
+U+b885 lwalt # Character ë¢
+U+b886 lwalp # Character ë¢
+U+b887 lwalh # Character ë¢
+U+b888 lwam # Character ë¢
+U+b889 lwab # Character ë¢
+U+b88a lwabs # Character ë¢
+U+b88b lwas # Character ë¢
+U+b88c lwass # Character ë¢
+U+b88d lwang # Character ë¢
+U+b88e lwaj # Character ë¢
+U+b88f lwach # Character ë¢
+U+b890 lwak # Character ë¢
+U+b891 lwat # Character ë¢
+U+b892 lwap # Character ë¢
+U+b893 lwah # Character ë¢
+U+b894 lwae # Character ë¢
+U+b895 lwaeg # Character ë¢
+U+b896 lwaekk # Character ë¢
+U+b897 lwaegs # Character ë¢
+U+b898 lwaen # Character ë¢
+U+b899 lwaenj # Character ë¢
+U+b89a lwaenh # Character ë¢
+U+b89b lwaed # Character ë¢
+U+b89c lwael # Character ë¢
+U+b89d lwaelg # Character ë¢
+U+b89e lwaelm # Character ë¢
+U+b89f lwaelb # Character ë¢
+U+b8a0 lwaels # Character ë¢
+U+b8a1 lwaelt # Character 뢡
+U+b8a2 lwaelp # Character 뢢
+U+b8a3 lwaelh # Character 뢣
+U+b8a4 lwaem # Character 뢤
+U+b8a5 lwaeb # Character 뢥
+U+b8a6 lwaebs # Character 뢦
+U+b8a7 lwaes # Character 뢧
+U+b8a8 lwaess # Character 뢨
+U+b8a9 lwaeng # Character 뢩
+U+b8aa lwaej # Character 뢪
+U+b8ab lwaech # Character 뢫
+U+b8ac lwaek # Character 뢬
+U+b8ad lwaet # Character ë¢
+U+b8ae lwaep # Character 뢮
+U+b8af lwaeh # Character 뢯
+U+b8b0 loe # Character 뢰
+U+b8b1 loeg # Character 뢱
+U+b8b2 loekk # Character 뢲
+U+b8b3 loegs # Character 뢳
+U+b8b4 loen # Character 뢴
+U+b8b5 loenj # Character 뢵
+U+b8b6 loenh # Character 뢶
+U+b8b7 loed # Character 뢷
+U+b8b8 loel # Character 뢸
+U+b8b9 loelg # Character 뢹
+U+b8ba loelm # Character 뢺
+U+b8bb loelb # Character 뢻
+U+b8bc loels # Character 뢼
+U+b8bd loelt # Character 뢽
+U+b8be loelp # Character 뢾
+U+b8bf loelh # Character 뢿
+U+b8c0 loem # Character ë£
+U+b8c1 loeb # Character ë£
+U+b8c2 loebs # Character ë£
+U+b8c3 loes # Character ë£
+U+b8c4 loess # Character ë£
+U+b8c5 loeng # Character ë£
+U+b8c6 loej # Character ë£
+U+b8c7 loech # Character ë£
+U+b8c8 loek # Character ë£
+U+b8c9 loet # Character ë£
+U+b8ca loep # Character ë£
+U+b8cb loeh # Character ë£
+U+b8cc lyo # Character ë£
+U+b8cd lyog # Character ë£
+U+b8ce lyokk # Character ë£
+U+b8cf lyogs # Character ë£
+U+b8d0 lyon # Character ë£
+U+b8d1 lyonj # Character ë£
+U+b8d2 lyonh # Character ë£
+U+b8d3 lyod # Character ë£
+U+b8d4 lyol # Character ë£
+U+b8d5 lyolg # Character ë£
+U+b8d6 lyolm # Character ë£
+U+b8d7 lyolb # Character ë£
+U+b8d8 lyols # Character ë£
+U+b8d9 lyolt # Character ë£
+U+b8da lyolp # Character ë£
+U+b8db lyolh # Character ë£
+U+b8dc lyom # Character ë£
+U+b8dd lyob # Character ë£
+U+b8de lyobs # Character ë£
+U+b8df lyos # Character ë£
+U+b8e0 lyoss # Character ë£
+U+b8e1 lyong # Character 룡
+U+b8e2 lyoj # Character 룢
+U+b8e3 lyoch # Character 룣
+U+b8e4 lyok # Character 룤
+U+b8e5 lyot # Character 룥
+U+b8e6 lyop # Character 룦
+U+b8e7 lyoh # Character 룧
+U+b8e8 lu # Character 루
+U+b8e9 lug # Character 룩
+U+b8ea lukk # Character 룪
+U+b8eb lugs # Character 룫
+U+b8ec lun # Character 룬
+U+b8ed lunj # Character ë£
+U+b8ee lunh # Character 룮
+U+b8ef lud # Character 룯
+U+b8f0 lul # Character 룰
+U+b8f1 lulg # Character 룱
+U+b8f2 lulm # Character 룲
+U+b8f3 lulb # Character 룳
+U+b8f4 luls # Character 룴
+U+b8f5 lult # Character 룵
+U+b8f6 lulp # Character 룶
+U+b8f7 lulh # Character 룷
+U+b8f8 lum # Character 룸
+U+b8f9 lub # Character 룹
+U+b8fa lubs # Character 룺
+U+b8fb lus # Character 룻
+U+b8fc luss # Character 룼
+U+b8fd lung # Character 룽
+U+b8fe luj # Character 룾
+U+b8ff luch # Character 룿
diff --git a/resources/chars/latin1/rowb9.trans b/resources/chars/latin1/rowb9.trans
new file mode 100644
index 0000000..0b2fde4
--- /dev/null
+++ b/resources/chars/latin1/rowb9.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+b900 luk # Character ë¤
+U+b901 lut # Character ë¤
+U+b902 lup # Character ë¤
+U+b903 luh # Character ë¤
+U+b904 lwo # Character ë¤
+U+b905 lwog # Character ë¤
+U+b906 lwokk # Character ë¤
+U+b907 lwogs # Character ë¤
+U+b908 lwon # Character ë¤
+U+b909 lwonj # Character ë¤
+U+b90a lwonh # Character ë¤
+U+b90b lwod # Character ë¤
+U+b90c lwol # Character ë¤
+U+b90d lwolg # Character ë¤
+U+b90e lwolm # Character ë¤
+U+b90f lwolb # Character ë¤
+U+b910 lwols # Character ë¤
+U+b911 lwolt # Character ë¤
+U+b912 lwolp # Character ë¤
+U+b913 lwolh # Character ë¤
+U+b914 lwom # Character ë¤
+U+b915 lwob # Character ë¤
+U+b916 lwobs # Character ë¤
+U+b917 lwos # Character ë¤
+U+b918 lwoss # Character ë¤
+U+b919 lwong # Character ë¤
+U+b91a lwoj # Character ë¤
+U+b91b lwoch # Character ë¤
+U+b91c lwok # Character ë¤
+U+b91d lwot # Character ë¤
+U+b91e lwop # Character ë¤
+U+b91f lwoh # Character ë¤
+U+b920 lwe # Character ë¤
+U+b921 lweg # Character 뤡
+U+b922 lwekk # Character 뤢
+U+b923 lwegs # Character 뤣
+U+b924 lwen # Character 뤤
+U+b925 lwenj # Character 뤥
+U+b926 lwenh # Character 뤦
+U+b927 lwed # Character 뤧
+U+b928 lwel # Character 뤨
+U+b929 lwelg # Character 뤩
+U+b92a lwelm # Character 뤪
+U+b92b lwelb # Character 뤫
+U+b92c lwels # Character 뤬
+U+b92d lwelt # Character ë¤
+U+b92e lwelp # Character 뤮
+U+b92f lwelh # Character 뤯
+U+b930 lwem # Character 뤰
+U+b931 lweb # Character 뤱
+U+b932 lwebs # Character 뤲
+U+b933 lwes # Character 뤳
+U+b934 lwess # Character 뤴
+U+b935 lweng # Character 뤵
+U+b936 lwej # Character 뤶
+U+b937 lwech # Character 뤷
+U+b938 lwek # Character 뤸
+U+b939 lwet # Character 뤹
+U+b93a lwep # Character 뤺
+U+b93b lweh # Character 뤻
+U+b93c lwi # Character 뤼
+U+b93d lwig # Character 뤽
+U+b93e lwikk # Character 뤾
+U+b93f lwigs # Character 뤿
+U+b940 lwin # Character ë¥
+U+b941 lwinj # Character ë¥
+U+b942 lwinh # Character ë¥
+U+b943 lwid # Character ë¥
+U+b944 lwil # Character ë¥
+U+b945 lwilg # Character ë¥
+U+b946 lwilm # Character ë¥
+U+b947 lwilb # Character ë¥
+U+b948 lwils # Character ë¥
+U+b949 lwilt # Character ë¥
+U+b94a lwilp # Character ë¥
+U+b94b lwilh # Character ë¥
+U+b94c lwim # Character ë¥
+U+b94d lwib # Character ë¥
+U+b94e lwibs # Character ë¥
+U+b94f lwis # Character ë¥
+U+b950 lwiss # Character ë¥
+U+b951 lwing # Character ë¥
+U+b952 lwij # Character ë¥
+U+b953 lwich # Character ë¥
+U+b954 lwik # Character ë¥
+U+b955 lwit # Character ë¥
+U+b956 lwip # Character ë¥
+U+b957 lwih # Character ë¥
+U+b958 lyu # Character ë¥
+U+b959 lyug # Character ë¥
+U+b95a lyukk # Character ë¥
+U+b95b lyugs # Character ë¥
+U+b95c lyun # Character ë¥
+U+b95d lyunj # Character ë¥
+U+b95e lyunh # Character ë¥
+U+b95f lyud # Character ë¥
+U+b960 lyul # Character ë¥
+U+b961 lyulg # Character 륡
+U+b962 lyulm # Character 륢
+U+b963 lyulb # Character 륣
+U+b964 lyuls # Character 륤
+U+b965 lyult # Character 륥
+U+b966 lyulp # Character 륦
+U+b967 lyulh # Character 륧
+U+b968 lyum # Character 륨
+U+b969 lyub # Character 륩
+U+b96a lyubs # Character 륪
+U+b96b lyus # Character 륫
+U+b96c lyuss # Character 륬
+U+b96d lyung # Character ë¥
+U+b96e lyuj # Character 륮
+U+b96f lyuch # Character 륯
+U+b970 lyuk # Character 륰
+U+b971 lyut # Character 륱
+U+b972 lyup # Character 륲
+U+b973 lyuh # Character 륳
+U+b974 leu # Character 르
+U+b975 leug # Character 륵
+U+b976 leukk # Character 륶
+U+b977 leugs # Character 륷
+U+b978 leun # Character 른
+U+b979 leunj # Character 륹
+U+b97a leunh # Character 륺
+U+b97b leud # Character 륻
+U+b97c leul # Character 를
+U+b97d leulg # Character 륽
+U+b97e leulm # Character 륾
+U+b97f leulb # Character 륿
+U+b980 leuls # Character ë¦
+U+b981 leult # Character ë¦
+U+b982 leulp # Character ë¦
+U+b983 leulh # Character ë¦
+U+b984 leum # Character ë¦
+U+b985 leub # Character ë¦
+U+b986 leubs # Character ë¦
+U+b987 leus # Character ë¦
+U+b988 leuss # Character ë¦
+U+b989 leung # Character ë¦
+U+b98a leuj # Character ë¦
+U+b98b leuch # Character ë¦
+U+b98c leuk # Character ë¦
+U+b98d leut # Character ë¦
+U+b98e leup # Character ë¦
+U+b98f leuh # Character ë¦
+U+b990 lui # Character ë¦
+U+b991 luig # Character ë¦
+U+b992 luikk # Character ë¦
+U+b993 luigs # Character ë¦
+U+b994 luin # Character ë¦
+U+b995 luinj # Character ë¦
+U+b996 luinh # Character ë¦
+U+b997 luid # Character ë¦
+U+b998 luil # Character ë¦
+U+b999 luilg # Character ë¦
+U+b99a luilm # Character ë¦
+U+b99b luilb # Character ë¦
+U+b99c luils # Character ë¦
+U+b99d luilt # Character ë¦
+U+b99e luilp # Character ë¦
+U+b99f luilh # Character ë¦
+U+b9a0 luim # Character ë¦
+U+b9a1 luib # Character 릡
+U+b9a2 luibs # Character 릢
+U+b9a3 luis # Character 릣
+U+b9a4 luiss # Character 릤
+U+b9a5 luing # Character 릥
+U+b9a6 luij # Character 릦
+U+b9a7 luich # Character 릧
+U+b9a8 luik # Character 릨
+U+b9a9 luit # Character 릩
+U+b9aa luip # Character 릪
+U+b9ab luih # Character 릫
+U+b9ac li # Character 리
+U+b9ad lig # Character ë¦
+U+b9ae likk # Character 릮
+U+b9af ligs # Character 릯
+U+b9b0 lin # Character 린
+U+b9b1 linj # Character 릱
+U+b9b2 linh # Character 릲
+U+b9b3 lid # Character 릳
+U+b9b4 lil # Character 릴
+U+b9b5 lilg # Character 릵
+U+b9b6 lilm # Character 릶
+U+b9b7 lilb # Character 릷
+U+b9b8 lils # Character 릸
+U+b9b9 lilt # Character 릹
+U+b9ba lilp # Character 릺
+U+b9bb lilh # Character 릻
+U+b9bc lim # Character 림
+U+b9bd lib # Character 립
+U+b9be libs # Character 릾
+U+b9bf lis # Character 릿
+U+b9c0 liss # Character ë§
+U+b9c1 ling # Character ë§
+U+b9c2 lij # Character ë§
+U+b9c3 lich # Character ë§
+U+b9c4 lik # Character ë§
+U+b9c5 lit # Character ë§
+U+b9c6 lip # Character ë§
+U+b9c7 lih # Character ë§
+U+b9c8 ma # Character ë§
+U+b9c9 mag # Character ë§
+U+b9ca makk # Character ë§
+U+b9cb mags # Character ë§
+U+b9cc man # Character ë§
+U+b9cd manj # Character ë§
+U+b9ce manh # Character ë§
+U+b9cf mad # Character ë§
+U+b9d0 mal # Character ë§
+U+b9d1 malg # Character ë§
+U+b9d2 malm # Character ë§
+U+b9d3 malb # Character ë§
+U+b9d4 mals # Character ë§
+U+b9d5 malt # Character ë§
+U+b9d6 malp # Character ë§
+U+b9d7 malh # Character ë§
+U+b9d8 mam # Character ë§
+U+b9d9 mab # Character ë§
+U+b9da mabs # Character ë§
+U+b9db mas # Character ë§
+U+b9dc mass # Character ë§
+U+b9dd mang # Character ë§
+U+b9de maj # Character ë§
+U+b9df mach # Character ë§
+U+b9e0 mak # Character ë§
+U+b9e1 mat # Character 맡
+U+b9e2 map # Character 맢
+U+b9e3 mah # Character 맣
+U+b9e4 mae # Character 매
+U+b9e5 maeg # Character 맥
+U+b9e6 maekk # Character 맦
+U+b9e7 maegs # Character 맧
+U+b9e8 maen # Character 맨
+U+b9e9 maenj # Character 맩
+U+b9ea maenh # Character 맪
+U+b9eb maed # Character 맫
+U+b9ec mael # Character 맬
+U+b9ed maelg # Character ë§
+U+b9ee maelm # Character 맮
+U+b9ef maelb # Character 맯
+U+b9f0 maels # Character 맰
+U+b9f1 maelt # Character 맱
+U+b9f2 maelp # Character 맲
+U+b9f3 maelh # Character 맳
+U+b9f4 maem # Character 맴
+U+b9f5 maeb # Character 맵
+U+b9f6 maebs # Character 맶
+U+b9f7 maes # Character 맷
+U+b9f8 maess # Character 맸
+U+b9f9 maeng # Character 맹
+U+b9fa maej # Character 맺
+U+b9fb maech # Character 맻
+U+b9fc maek # Character 맼
+U+b9fd maet # Character 맽
+U+b9fe maep # Character 맾
+U+b9ff maeh # Character 맿
diff --git a/resources/chars/latin1/rowba.trans b/resources/chars/latin1/rowba.trans
new file mode 100644
index 0000000..d7522f9
--- /dev/null
+++ b/resources/chars/latin1/rowba.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+ba00 mya # Character ë¨
+U+ba01 myag # Character ë¨
+U+ba02 myakk # Character ë¨
+U+ba03 myags # Character ë¨
+U+ba04 myan # Character ë¨
+U+ba05 myanj # Character ë¨
+U+ba06 myanh # Character ë¨
+U+ba07 myad # Character ë¨
+U+ba08 myal # Character ë¨
+U+ba09 myalg # Character ë¨
+U+ba0a myalm # Character ë¨
+U+ba0b myalb # Character ë¨
+U+ba0c myals # Character ë¨
+U+ba0d myalt # Character ë¨
+U+ba0e myalp # Character ë¨
+U+ba0f myalh # Character ë¨
+U+ba10 myam # Character ë¨
+U+ba11 myab # Character ë¨
+U+ba12 myabs # Character ë¨
+U+ba13 myas # Character ë¨
+U+ba14 myass # Character ë¨
+U+ba15 myang # Character ë¨
+U+ba16 myaj # Character ë¨
+U+ba17 myach # Character ë¨
+U+ba18 myak # Character ë¨
+U+ba19 myat # Character ë¨
+U+ba1a myap # Character ë¨
+U+ba1b myah # Character ë¨
+U+ba1c myae # Character ë¨
+U+ba1d myaeg # Character ë¨
+U+ba1e myaekk # Character ë¨
+U+ba1f myaegs # Character ë¨
+U+ba20 myaen # Character ë¨
+U+ba21 myaenj # Character 먡
+U+ba22 myaenh # Character 먢
+U+ba23 myaed # Character 먣
+U+ba24 myael # Character 먤
+U+ba25 myaelg # Character 먥
+U+ba26 myaelm # Character 먦
+U+ba27 myaelb # Character 먧
+U+ba28 myaels # Character 먨
+U+ba29 myaelt # Character 먩
+U+ba2a myaelp # Character 먪
+U+ba2b myaelh # Character 먫
+U+ba2c myaem # Character 먬
+U+ba2d myaeb # Character ë¨
+U+ba2e myaebs # Character 먮
+U+ba2f myaes # Character 먯
+U+ba30 myaess # Character 먰
+U+ba31 myaeng # Character 먱
+U+ba32 myaej # Character 먲
+U+ba33 myaech # Character 먳
+U+ba34 myaek # Character 먴
+U+ba35 myaet # Character 먵
+U+ba36 myaep # Character 먶
+U+ba37 myaeh # Character 먷
+U+ba38 meo # Character 머
+U+ba39 meog # Character 먹
+U+ba3a meokk # Character 먺
+U+ba3b meogs # Character 먻
+U+ba3c meon # Character 먼
+U+ba3d meonj # Character 먽
+U+ba3e meonh # Character 먾
+U+ba3f meod # Character 먿
+U+ba40 meol # Character ë©
+U+ba41 meolg # Character ë©
+U+ba42 meolm # Character ë©
+U+ba43 meolb # Character ë©
+U+ba44 meols # Character ë©
+U+ba45 meolt # Character ë©
+U+ba46 meolp # Character ë©
+U+ba47 meolh # Character ë©
+U+ba48 meom # Character ë©
+U+ba49 meob # Character ë©
+U+ba4a meobs # Character ë©
+U+ba4b meos # Character ë©
+U+ba4c meoss # Character ë©
+U+ba4d meong # Character ë©
+U+ba4e meoj # Character ë©
+U+ba4f meoch # Character ë©
+U+ba50 meok # Character ë©
+U+ba51 meot # Character ë©
+U+ba52 meop # Character ë©
+U+ba53 meoh # Character ë©
+U+ba54 me # Character ë©
+U+ba55 meg # Character ë©
+U+ba56 mekk # Character ë©
+U+ba57 megs # Character ë©
+U+ba58 men # Character ë©
+U+ba59 menj # Character ë©
+U+ba5a menh # Character ë©
+U+ba5b med # Character ë©
+U+ba5c mel # Character ë©
+U+ba5d melg # Character ë©
+U+ba5e melm # Character ë©
+U+ba5f melb # Character ë©
+U+ba60 mels # Character ë©
+U+ba61 melt # Character ë©¡
+U+ba62 melp # Character ë©¢
+U+ba63 melh # Character ë©£
+U+ba64 mem # Character 멤
+U+ba65 meb # Character ë©¥
+U+ba66 mebs # Character 멦
+U+ba67 mes # Character 멧
+U+ba68 mess # Character 멨
+U+ba69 meng # Character ë©©
+U+ba6a mej # Character 멪
+U+ba6b mech # Character ë©«
+U+ba6c mek # Character 멬
+U+ba6d met # Character ë©
+U+ba6e mep # Character ë©®
+U+ba6f meh # Character 멯
+U+ba70 myeo # Character ë©°
+U+ba71 myeog # Character 멱
+U+ba72 myeokk # Character 멲
+U+ba73 myeogs # Character 멳
+U+ba74 myeon # Character ë©´
+U+ba75 myeonj # Character 멵
+U+ba76 myeonh # Character 멶
+U+ba77 myeod # Character ë©·
+U+ba78 myeol # Character 멸
+U+ba79 myeolg # Character 멹
+U+ba7a myeolm # Character 멺
+U+ba7b myeolb # Character ë©»
+U+ba7c myeols # Character 멼
+U+ba7d myeolt # Character 멽
+U+ba7e myeolp # Character 멾
+U+ba7f myeolh # Character ë©¿
+U+ba80 myeom # Character ëª
+U+ba81 myeob # Character ëª
+U+ba82 myeobs # Character ëª
+U+ba83 myeos # Character ëª
+U+ba84 myeoss # Character ëª
+U+ba85 myeong # Character ëª
+U+ba86 myeoj # Character ëª
+U+ba87 myeoch # Character ëª
+U+ba88 myeok # Character ëª
+U+ba89 myeot # Character ëª
+U+ba8a myeop # Character ëª
+U+ba8b myeoh # Character ëª
+U+ba8c mye # Character ëª
+U+ba8d myeg # Character ëª
+U+ba8e myekk # Character ëª
+U+ba8f myegs # Character ëª
+U+ba90 myen # Character ëª
+U+ba91 myenj # Character ëª
+U+ba92 myenh # Character ëª
+U+ba93 myed # Character ëª
+U+ba94 myel # Character ëª
+U+ba95 myelg # Character ëª
+U+ba96 myelm # Character ëª
+U+ba97 myelb # Character ëª
+U+ba98 myels # Character ëª
+U+ba99 myelt # Character ëª
+U+ba9a myelp # Character ëª
+U+ba9b myelh # Character ëª
+U+ba9c myem # Character ëª
+U+ba9d myeb # Character ëª
+U+ba9e myebs # Character ëª
+U+ba9f myes # Character ëª
+U+baa0 myess # Character ëª
+U+baa1 myeng # Character 몡
+U+baa2 myej # Character 몢
+U+baa3 myech # Character 몣
+U+baa4 myek # Character 몤
+U+baa5 myet # Character 몥
+U+baa6 myep # Character 몦
+U+baa7 myeh # Character 몧
+U+baa8 mo # Character 모
+U+baa9 mog # Character 목
+U+baaa mokk # Character 몪
+U+baab mogs # Character 몫
+U+baac mon # Character 몬
+U+baad monj # Character ëª
+U+baae monh # Character 몮
+U+baaf mod # Character 몯
+U+bab0 mol # Character 몰
+U+bab1 molg # Character 몱
+U+bab2 molm # Character 몲
+U+bab3 molb # Character 몳
+U+bab4 mols # Character 몴
+U+bab5 molt # Character 몵
+U+bab6 molp # Character 몶
+U+bab7 molh # Character 몷
+U+bab8 mom # Character 몸
+U+bab9 mob # Character 몹
+U+baba mobs # Character 몺
+U+babb mos # Character 못
+U+babc moss # Character 몼
+U+babd mong # Character 몽
+U+babe moj # Character 몾
+U+babf moch # Character 몿
+U+bac0 mok # Character ë«
+U+bac1 mot # Character ë«
+U+bac2 mop # Character ë«
+U+bac3 moh # Character ë«
+U+bac4 mwa # Character ë«
+U+bac5 mwag # Character ë«
+U+bac6 mwakk # Character ë«
+U+bac7 mwags # Character ë«
+U+bac8 mwan # Character ë«
+U+bac9 mwanj # Character ë«
+U+baca mwanh # Character ë«
+U+bacb mwad # Character ë«
+U+bacc mwal # Character ë«
+U+bacd mwalg # Character ë«
+U+bace mwalm # Character ë«
+U+bacf mwalb # Character ë«
+U+bad0 mwals # Character ë«
+U+bad1 mwalt # Character ë«
+U+bad2 mwalp # Character ë«
+U+bad3 mwalh # Character ë«
+U+bad4 mwam # Character ë«
+U+bad5 mwab # Character ë«
+U+bad6 mwabs # Character ë«
+U+bad7 mwas # Character ë«
+U+bad8 mwass # Character ë«
+U+bad9 mwang # Character ë«
+U+bada mwaj # Character ë«
+U+badb mwach # Character ë«
+U+badc mwak # Character ë«
+U+badd mwat # Character ë«
+U+bade mwap # Character ë«
+U+badf mwah # Character ë«
+U+bae0 mwae # Character ë«
+U+bae1 mwaeg # Character ë«¡
+U+bae2 mwaekk # Character ë«¢
+U+bae3 mwaegs # Character ë«£
+U+bae4 mwaen # Character 뫤
+U+bae5 mwaenj # Character ë«¥
+U+bae6 mwaenh # Character 뫦
+U+bae7 mwaed # Character 뫧
+U+bae8 mwael # Character 뫨
+U+bae9 mwaelg # Character ë«©
+U+baea mwaelm # Character 뫪
+U+baeb mwaelb # Character ë««
+U+baec mwaels # Character 뫬
+U+baed mwaelt # Character ë«
+U+baee mwaelp # Character ë«®
+U+baef mwaelh # Character 뫯
+U+baf0 mwaem # Character ë«°
+U+baf1 mwaeb # Character 뫱
+U+baf2 mwaebs # Character 뫲
+U+baf3 mwaes # Character 뫳
+U+baf4 mwaess # Character ë«´
+U+baf5 mwaeng # Character 뫵
+U+baf6 mwaej # Character 뫶
+U+baf7 mwaech # Character ë«·
+U+baf8 mwaek # Character 뫸
+U+baf9 mwaet # Character 뫹
+U+bafa mwaep # Character 뫺
+U+bafb mwaeh # Character ë«»
+U+bafc moe # Character 뫼
+U+bafd moeg # Character 뫽
+U+bafe moekk # Character 뫾
+U+baff moegs # Character ë«¿
diff --git a/resources/chars/latin1/rowbb.trans b/resources/chars/latin1/rowbb.trans
new file mode 100644
index 0000000..d06fee4
--- /dev/null
+++ b/resources/chars/latin1/rowbb.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+bb00 moen # Character ë¬
+U+bb01 moenj # Character ë¬
+U+bb02 moenh # Character ë¬
+U+bb03 moed # Character ë¬
+U+bb04 moel # Character ë¬
+U+bb05 moelg # Character ë¬
+U+bb06 moelm # Character ë¬
+U+bb07 moelb # Character ë¬
+U+bb08 moels # Character ë¬
+U+bb09 moelt # Character ë¬
+U+bb0a moelp # Character ë¬
+U+bb0b moelh # Character ë¬
+U+bb0c moem # Character ë¬
+U+bb0d moeb # Character ë¬
+U+bb0e moebs # Character ë¬
+U+bb0f moes # Character ë¬
+U+bb10 moess # Character ë¬
+U+bb11 moeng # Character ë¬
+U+bb12 moej # Character ë¬
+U+bb13 moech # Character ë¬
+U+bb14 moek # Character ë¬
+U+bb15 moet # Character ë¬
+U+bb16 moep # Character ë¬
+U+bb17 moeh # Character ë¬
+U+bb18 myo # Character ë¬
+U+bb19 myog # Character ë¬
+U+bb1a myokk # Character ë¬
+U+bb1b myogs # Character ë¬
+U+bb1c myon # Character ë¬
+U+bb1d myonj # Character ë¬
+U+bb1e myonh # Character ë¬
+U+bb1f myod # Character ë¬
+U+bb20 myol # Character ë¬
+U+bb21 myolg # Character 묡
+U+bb22 myolm # Character 묢
+U+bb23 myolb # Character 묣
+U+bb24 myols # Character 묤
+U+bb25 myolt # Character 묥
+U+bb26 myolp # Character 묦
+U+bb27 myolh # Character 묧
+U+bb28 myom # Character 묨
+U+bb29 myob # Character 묩
+U+bb2a myobs # Character 묪
+U+bb2b myos # Character 묫
+U+bb2c myoss # Character 묬
+U+bb2d myong # Character ë¬
+U+bb2e myoj # Character 묮
+U+bb2f myoch # Character 묯
+U+bb30 myok # Character 묰
+U+bb31 myot # Character 묱
+U+bb32 myop # Character 묲
+U+bb33 myoh # Character 묳
+U+bb34 mu # Character 무
+U+bb35 mug # Character 묵
+U+bb36 mukk # Character 묶
+U+bb37 mugs # Character 묷
+U+bb38 mun # Character 문
+U+bb39 munj # Character 묹
+U+bb3a munh # Character 묺
+U+bb3b mud # Character 묻
+U+bb3c mul # Character 물
+U+bb3d mulg # Character 묽
+U+bb3e mulm # Character 묾
+U+bb3f mulb # Character 묿
+U+bb40 muls # Character ë
+U+bb41 mult # Character ë
+U+bb42 mulp # Character ë
+U+bb43 mulh # Character ë
+U+bb44 mum # Character ë
+U+bb45 mub # Character ë
+U+bb46 mubs # Character ë
+U+bb47 mus # Character ë
+U+bb48 muss # Character ë
+U+bb49 mung # Character ë
+U+bb4a muj # Character ë
+U+bb4b much # Character ë
+U+bb4c muk # Character ë
+U+bb4d mut # Character ë
+U+bb4e mup # Character ë
+U+bb4f muh # Character ë
+U+bb50 mwo # Character ë
+U+bb51 mwog # Character ë
+U+bb52 mwokk # Character ë
+U+bb53 mwogs # Character ë
+U+bb54 mwon # Character ë
+U+bb55 mwonj # Character ë
+U+bb56 mwonh # Character ë
+U+bb57 mwod # Character ë
+U+bb58 mwol # Character ë
+U+bb59 mwolg # Character ë
+U+bb5a mwolm # Character ë
+U+bb5b mwolb # Character ë
+U+bb5c mwols # Character ë
+U+bb5d mwolt # Character ë
+U+bb5e mwolp # Character ë
+U+bb5f mwolh # Character ë
+U+bb60 mwom # Character ë
+U+bb61 mwob # Character ë¡
+U+bb62 mwobs # Character ë¢
+U+bb63 mwos # Character ë£
+U+bb64 mwoss # Character ë¤
+U+bb65 mwong # Character ë¥
+U+bb66 mwoj # Character ë¦
+U+bb67 mwoch # Character ë§
+U+bb68 mwok # Character ë¨
+U+bb69 mwot # Character ë©
+U+bb6a mwop # Character ëª
+U+bb6b mwoh # Character ë«
+U+bb6c mwe # Character ë¬
+U+bb6d mweg # Character ë
+U+bb6e mwekk # Character ë®
+U+bb6f mwegs # Character ë¯
+U+bb70 mwen # Character ë°
+U+bb71 mwenj # Character ë±
+U+bb72 mwenh # Character ë²
+U+bb73 mwed # Character ë³
+U+bb74 mwel # Character ë´
+U+bb75 mwelg # Character ëµ
+U+bb76 mwelm # Character ë¶
+U+bb77 mwelb # Character ë·
+U+bb78 mwels # Character ë¸
+U+bb79 mwelt # Character ë¹
+U+bb7a mwelp # Character ëº
+U+bb7b mwelh # Character ë»
+U+bb7c mwem # Character ë¼
+U+bb7d mweb # Character ë½
+U+bb7e mwebs # Character ë¾
+U+bb7f mwes # Character ë¿
+U+bb80 mwess # Character ë®
+U+bb81 mweng # Character ë®
+U+bb82 mwej # Character ë®
+U+bb83 mwech # Character ë®
+U+bb84 mwek # Character ë®
+U+bb85 mwet # Character ë®
+U+bb86 mwep # Character ë®
+U+bb87 mweh # Character ë®
+U+bb88 mwi # Character ë®
+U+bb89 mwig # Character ë®
+U+bb8a mwikk # Character ë®
+U+bb8b mwigs # Character ë®
+U+bb8c mwin # Character ë®
+U+bb8d mwinj # Character ë®
+U+bb8e mwinh # Character ë®
+U+bb8f mwid # Character ë®
+U+bb90 mwil # Character ë®
+U+bb91 mwilg # Character ë®
+U+bb92 mwilm # Character ë®
+U+bb93 mwilb # Character ë®
+U+bb94 mwils # Character ë®
+U+bb95 mwilt # Character ë®
+U+bb96 mwilp # Character ë®
+U+bb97 mwilh # Character ë®
+U+bb98 mwim # Character ë®
+U+bb99 mwib # Character ë®
+U+bb9a mwibs # Character ë®
+U+bb9b mwis # Character ë®
+U+bb9c mwiss # Character ë®
+U+bb9d mwing # Character ë®
+U+bb9e mwij # Character ë®
+U+bb9f mwich # Character ë®
+U+bba0 mwik # Character ë®
+U+bba1 mwit # Character 뮡
+U+bba2 mwip # Character 뮢
+U+bba3 mwih # Character 뮣
+U+bba4 myu # Character 뮤
+U+bba5 myug # Character 뮥
+U+bba6 myukk # Character 뮦
+U+bba7 myugs # Character 뮧
+U+bba8 myun # Character 뮨
+U+bba9 myunj # Character 뮩
+U+bbaa myunh # Character 뮪
+U+bbab myud # Character 뮫
+U+bbac myul # Character 뮬
+U+bbad myulg # Character ë®
+U+bbae myulm # Character ë®®
+U+bbaf myulb # Character 뮯
+U+bbb0 myuls # Character ë®°
+U+bbb1 myult # Character ë®±
+U+bbb2 myulp # Character 뮲
+U+bbb3 myulh # Character 뮳
+U+bbb4 myum # Character ë®´
+U+bbb5 myub # Character 뮵
+U+bbb6 myubs # Character 뮶
+U+bbb7 myus # Character ë®·
+U+bbb8 myuss # Character 뮸
+U+bbb9 myung # Character 뮹
+U+bbba myuj # Character 뮺
+U+bbbb myuch # Character ë®»
+U+bbbc myuk # Character 뮼
+U+bbbd myut # Character 뮽
+U+bbbe myup # Character 뮾
+U+bbbf myuh # Character 뮿
+U+bbc0 meu # Character ë¯
+U+bbc1 meug # Character ë¯
+U+bbc2 meukk # Character ë¯
+U+bbc3 meugs # Character ë¯
+U+bbc4 meun # Character ë¯
+U+bbc5 meunj # Character ë¯
+U+bbc6 meunh # Character ë¯
+U+bbc7 meud # Character ë¯
+U+bbc8 meul # Character ë¯
+U+bbc9 meulg # Character ë¯
+U+bbca meulm # Character ë¯
+U+bbcb meulb # Character ë¯
+U+bbcc meuls # Character ë¯
+U+bbcd meult # Character ë¯
+U+bbce meulp # Character ë¯
+U+bbcf meulh # Character ë¯
+U+bbd0 meum # Character ë¯
+U+bbd1 meub # Character ë¯
+U+bbd2 meubs # Character ë¯
+U+bbd3 meus # Character ë¯
+U+bbd4 meuss # Character ë¯
+U+bbd5 meung # Character ë¯
+U+bbd6 meuj # Character ë¯
+U+bbd7 meuch # Character ë¯
+U+bbd8 meuk # Character ë¯
+U+bbd9 meut # Character ë¯
+U+bbda meup # Character ë¯
+U+bbdb meuh # Character ë¯
+U+bbdc mui # Character ë¯
+U+bbdd muig # Character ë¯
+U+bbde muikk # Character ë¯
+U+bbdf muigs # Character ë¯
+U+bbe0 muin # Character ë¯
+U+bbe1 muinj # Character 믡
+U+bbe2 muinh # Character 믢
+U+bbe3 muid # Character 믣
+U+bbe4 muil # Character 믤
+U+bbe5 muilg # Character 믥
+U+bbe6 muilm # Character 믦
+U+bbe7 muilb # Character 믧
+U+bbe8 muils # Character 믨
+U+bbe9 muilt # Character 믩
+U+bbea muilp # Character 믪
+U+bbeb muilh # Character 믫
+U+bbec muim # Character 믬
+U+bbed muib # Character ë¯
+U+bbee muibs # Character 믮
+U+bbef muis # Character 믯
+U+bbf0 muiss # Character 믰
+U+bbf1 muing # Character 믱
+U+bbf2 muij # Character 믲
+U+bbf3 muich # Character 믳
+U+bbf4 muik # Character 믴
+U+bbf5 muit # Character 믵
+U+bbf6 muip # Character 믶
+U+bbf7 muih # Character 믷
+U+bbf8 mi # Character 미
+U+bbf9 mig # Character 믹
+U+bbfa mikk # Character 믺
+U+bbfb migs # Character 믻
+U+bbfc min # Character 민
+U+bbfd minj # Character 믽
+U+bbfe minh # Character 믾
+U+bbff mid # Character 믿
diff --git a/resources/chars/latin1/rowbc.trans b/resources/chars/latin1/rowbc.trans
new file mode 100644
index 0000000..d84b547
--- /dev/null
+++ b/resources/chars/latin1/rowbc.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+bc00 mil # Character ë°
+U+bc01 milg # Character ë°
+U+bc02 milm # Character ë°
+U+bc03 milb # Character ë°
+U+bc04 mils # Character ë°
+U+bc05 milt # Character ë°
+U+bc06 milp # Character ë°
+U+bc07 milh # Character ë°
+U+bc08 mim # Character ë°
+U+bc09 mib # Character ë°
+U+bc0a mibs # Character ë°
+U+bc0b mis # Character ë°
+U+bc0c miss # Character ë°
+U+bc0d ming # Character ë°
+U+bc0e mij # Character ë°
+U+bc0f mich # Character ë°
+U+bc10 mik # Character ë°
+U+bc11 mit # Character ë°
+U+bc12 mip # Character ë°
+U+bc13 mih # Character ë°
+U+bc14 ba # Character ë°
+U+bc15 bag # Character ë°
+U+bc16 bakk # Character ë°
+U+bc17 bags # Character ë°
+U+bc18 ban # Character ë°
+U+bc19 banj # Character ë°
+U+bc1a banh # Character ë°
+U+bc1b bad # Character ë°
+U+bc1c bal # Character ë°
+U+bc1d balg # Character ë°
+U+bc1e balm # Character ë°
+U+bc1f balb # Character ë°
+U+bc20 bals # Character ë°
+U+bc21 balt # Character ë°¡
+U+bc22 balp # Character ë°¢
+U+bc23 balh # Character ë°£
+U+bc24 bam # Character ë°¤
+U+bc25 bab # Character ë°¥
+U+bc26 babs # Character ë°¦
+U+bc27 bas # Character ë°§
+U+bc28 bass # Character ë°¨
+U+bc29 bang # Character ë°©
+U+bc2a baj # Character ë°ª
+U+bc2b bach # Character ë°«
+U+bc2c bak # Character ë°¬
+U+bc2d bat # Character ë°
+U+bc2e bap # Character ë°®
+U+bc2f bah # Character ë°¯
+U+bc30 bae # Character ë°°
+U+bc31 baeg # Character ë°±
+U+bc32 baekk # Character ë°²
+U+bc33 baegs # Character ë°³
+U+bc34 baen # Character ë°´
+U+bc35 baenj # Character ë°µ
+U+bc36 baenh # Character ë°¶
+U+bc37 baed # Character ë°·
+U+bc38 bael # Character ë°¸
+U+bc39 baelg # Character ë°¹
+U+bc3a baelm # Character ë°º
+U+bc3b baelb # Character ë°»
+U+bc3c baels # Character ë°¼
+U+bc3d baelt # Character ë°½
+U+bc3e baelp # Character ë°¾
+U+bc3f baelh # Character ë°¿
+U+bc40 baem # Character ë±
+U+bc41 baeb # Character ë±
+U+bc42 baebs # Character ë±
+U+bc43 baes # Character ë±
+U+bc44 baess # Character ë±
+U+bc45 baeng # Character ë±
+U+bc46 baej # Character ë±
+U+bc47 baech # Character ë±
+U+bc48 baek # Character ë±
+U+bc49 baet # Character ë±
+U+bc4a baep # Character ë±
+U+bc4b baeh # Character ë±
+U+bc4c bya # Character ë±
+U+bc4d byag # Character ë±
+U+bc4e byakk # Character ë±
+U+bc4f byags # Character ë±
+U+bc50 byan # Character ë±
+U+bc51 byanj # Character ë±
+U+bc52 byanh # Character ë±
+U+bc53 byad # Character ë±
+U+bc54 byal # Character ë±
+U+bc55 byalg # Character ë±
+U+bc56 byalm # Character ë±
+U+bc57 byalb # Character ë±
+U+bc58 byals # Character ë±
+U+bc59 byalt # Character ë±
+U+bc5a byalp # Character ë±
+U+bc5b byalh # Character ë±
+U+bc5c byam # Character ë±
+U+bc5d byab # Character ë±
+U+bc5e byabs # Character ë±
+U+bc5f byas # Character ë±
+U+bc60 byass # Character ë±
+U+bc61 byang # Character 뱡
+U+bc62 byaj # Character ë±¢
+U+bc63 byach # Character ë±£
+U+bc64 byak # Character 뱤
+U+bc65 byat # Character ë±¥
+U+bc66 byap # Character 뱦
+U+bc67 byah # Character 뱧
+U+bc68 byae # Character 뱨
+U+bc69 byaeg # Character 뱩
+U+bc6a byaekk # Character 뱪
+U+bc6b byaegs # Character 뱫
+U+bc6c byaen # Character 뱬
+U+bc6d byaenj # Character ë±
+U+bc6e byaenh # Character ë±®
+U+bc6f byaed # Character 뱯
+U+bc70 byael # Character ë±°
+U+bc71 byaelg # Character ë±±
+U+bc72 byaelm # Character ë±²
+U+bc73 byaelb # Character ë±³
+U+bc74 byaels # Character ë±´
+U+bc75 byaelt # Character ë±µ
+U+bc76 byaelp # Character 뱶
+U+bc77 byaelh # Character ë±·
+U+bc78 byaem # Character 뱸
+U+bc79 byaeb # Character ë±¹
+U+bc7a byaebs # Character 뱺
+U+bc7b byaes # Character ë±»
+U+bc7c byaess # Character ë±¼
+U+bc7d byaeng # Character ë±½
+U+bc7e byaej # Character ë±¾
+U+bc7f byaech # Character 뱿
+U+bc80 byaek # Character ë²
+U+bc81 byaet # Character ë²
+U+bc82 byaep # Character ë²
+U+bc83 byaeh # Character ë²
+U+bc84 beo # Character ë²
+U+bc85 beog # Character ë²
+U+bc86 beokk # Character ë²
+U+bc87 beogs # Character ë²
+U+bc88 beon # Character ë²
+U+bc89 beonj # Character ë²
+U+bc8a beonh # Character ë²
+U+bc8b beod # Character ë²
+U+bc8c beol # Character ë²
+U+bc8d beolg # Character ë²
+U+bc8e beolm # Character ë²
+U+bc8f beolb # Character ë²
+U+bc90 beols # Character ë²
+U+bc91 beolt # Character ë²
+U+bc92 beolp # Character ë²
+U+bc93 beolh # Character ë²
+U+bc94 beom # Character ë²
+U+bc95 beob # Character ë²
+U+bc96 beobs # Character ë²
+U+bc97 beos # Character ë²
+U+bc98 beoss # Character ë²
+U+bc99 beong # Character ë²
+U+bc9a beoj # Character ë²
+U+bc9b beoch # Character ë²
+U+bc9c beok # Character ë²
+U+bc9d beot # Character ë²
+U+bc9e beop # Character ë²
+U+bc9f beoh # Character ë²
+U+bca0 be # Character ë²
+U+bca1 beg # Character 벡
+U+bca2 bekk # Character ë²¢
+U+bca3 begs # Character ë²£
+U+bca4 ben # Character 벤
+U+bca5 benj # Character ë²¥
+U+bca6 benh # Character 벦
+U+bca7 bed # Character 벧
+U+bca8 bel # Character 벨
+U+bca9 belg # Character 벩
+U+bcaa belm # Character 벪
+U+bcab belb # Character 벫
+U+bcac bels # Character 벬
+U+bcad belt # Character ë²
+U+bcae belp # Character ë²®
+U+bcaf belh # Character 벯
+U+bcb0 bem # Character ë²°
+U+bcb1 beb # Character ë²±
+U+bcb2 bebs # Character ë²²
+U+bcb3 bes # Character ë²³
+U+bcb4 bess # Character ë²´
+U+bcb5 beng # Character ë²µ
+U+bcb6 bej # Character 벶
+U+bcb7 bech # Character ë²·
+U+bcb8 bek # Character 벸
+U+bcb9 bet # Character ë²¹
+U+bcba bep # Character 벺
+U+bcbb beh # Character ë²»
+U+bcbc byeo # Character ë²¼
+U+bcbd byeog # Character ë²½
+U+bcbe byeokk # Character ë²¾
+U+bcbf byeogs # Character 벿
+U+bcc0 byeon # Character ë³
+U+bcc1 byeonj # Character ë³
+U+bcc2 byeonh # Character ë³
+U+bcc3 byeod # Character ë³
+U+bcc4 byeol # Character ë³
+U+bcc5 byeolg # Character ë³
+U+bcc6 byeolm # Character ë³
+U+bcc7 byeolb # Character ë³
+U+bcc8 byeols # Character ë³
+U+bcc9 byeolt # Character ë³
+U+bcca byeolp # Character ë³
+U+bccb byeolh # Character ë³
+U+bccc byeom # Character ë³
+U+bccd byeob # Character ë³
+U+bcce byeobs # Character ë³
+U+bccf byeos # Character ë³
+U+bcd0 byeoss # Character ë³
+U+bcd1 byeong # Character ë³
+U+bcd2 byeoj # Character ë³
+U+bcd3 byeoch # Character ë³
+U+bcd4 byeok # Character ë³
+U+bcd5 byeot # Character ë³
+U+bcd6 byeop # Character ë³
+U+bcd7 byeoh # Character ë³
+U+bcd8 bye # Character ë³
+U+bcd9 byeg # Character ë³
+U+bcda byekk # Character ë³
+U+bcdb byegs # Character ë³
+U+bcdc byen # Character ë³
+U+bcdd byenj # Character ë³
+U+bcde byenh # Character ë³
+U+bcdf byed # Character ë³
+U+bce0 byel # Character ë³
+U+bce1 byelg # Character 볡
+U+bce2 byelm # Character ë³¢
+U+bce3 byelb # Character ë³£
+U+bce4 byels # Character 볤
+U+bce5 byelt # Character ë³¥
+U+bce6 byelp # Character 볦
+U+bce7 byelh # Character 볧
+U+bce8 byem # Character 볨
+U+bce9 byeb # Character 볩
+U+bcea byebs # Character 볪
+U+bceb byes # Character 볫
+U+bcec byess # Character 볬
+U+bced byeng # Character ë³
+U+bcee byej # Character ë³®
+U+bcef byech # Character 볯
+U+bcf0 byek # Character ë³°
+U+bcf1 byet # Character ë³±
+U+bcf2 byep # Character ë³²
+U+bcf3 byeh # Character ë³³
+U+bcf4 bo # Character ë³´
+U+bcf5 bog # Character ë³µ
+U+bcf6 bokk # Character 볶
+U+bcf7 bogs # Character ë³·
+U+bcf8 bon # Character 본
+U+bcf9 bonj # Character ë³¹
+U+bcfa bonh # Character 볺
+U+bcfb bod # Character ë³»
+U+bcfc bol # Character ë³¼
+U+bcfd bolg # Character ë³½
+U+bcfe bolm # Character ë³¾
+U+bcff bolb # Character 볿
diff --git a/resources/chars/latin1/rowbd.trans b/resources/chars/latin1/rowbd.trans
new file mode 100644
index 0000000..08ccc09
--- /dev/null
+++ b/resources/chars/latin1/rowbd.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+bd00 bols # Character ë´
+U+bd01 bolt # Character ë´
+U+bd02 bolp # Character ë´
+U+bd03 bolh # Character ë´
+U+bd04 bom # Character ë´
+U+bd05 bob # Character ë´
+U+bd06 bobs # Character ë´
+U+bd07 bos # Character ë´
+U+bd08 boss # Character ë´
+U+bd09 bong # Character ë´
+U+bd0a boj # Character ë´
+U+bd0b boch # Character ë´
+U+bd0c bok # Character ë´
+U+bd0d bot # Character ë´
+U+bd0e bop # Character ë´
+U+bd0f boh # Character ë´
+U+bd10 bwa # Character ë´
+U+bd11 bwag # Character ë´
+U+bd12 bwakk # Character ë´
+U+bd13 bwags # Character ë´
+U+bd14 bwan # Character ë´
+U+bd15 bwanj # Character ë´
+U+bd16 bwanh # Character ë´
+U+bd17 bwad # Character ë´
+U+bd18 bwal # Character ë´
+U+bd19 bwalg # Character ë´
+U+bd1a bwalm # Character ë´
+U+bd1b bwalb # Character ë´
+U+bd1c bwals # Character ë´
+U+bd1d bwalt # Character ë´
+U+bd1e bwalp # Character ë´
+U+bd1f bwalh # Character ë´
+U+bd20 bwam # Character ë´
+U+bd21 bwab # Character ë´¡
+U+bd22 bwabs # Character ë´¢
+U+bd23 bwas # Character ë´£
+U+bd24 bwass # Character ë´¤
+U+bd25 bwang # Character ë´¥
+U+bd26 bwaj # Character ë´¦
+U+bd27 bwach # Character ë´§
+U+bd28 bwak # Character ë´¨
+U+bd29 bwat # Character ë´©
+U+bd2a bwap # Character ë´ª
+U+bd2b bwah # Character ë´«
+U+bd2c bwae # Character ë´¬
+U+bd2d bwaeg # Character ë´
+U+bd2e bwaekk # Character ë´®
+U+bd2f bwaegs # Character ë´¯
+U+bd30 bwaen # Character ë´°
+U+bd31 bwaenj # Character ë´±
+U+bd32 bwaenh # Character ë´²
+U+bd33 bwaed # Character ë´³
+U+bd34 bwael # Character ë´´
+U+bd35 bwaelg # Character ë´µ
+U+bd36 bwaelm # Character ë´¶
+U+bd37 bwaelb # Character ë´·
+U+bd38 bwaels # Character ë´¸
+U+bd39 bwaelt # Character ë´¹
+U+bd3a bwaelp # Character ë´º
+U+bd3b bwaelh # Character ë´»
+U+bd3c bwaem # Character ë´¼
+U+bd3d bwaeb # Character ë´½
+U+bd3e bwaebs # Character ë´¾
+U+bd3f bwaes # Character ë´¿
+U+bd40 bwaess # Character ëµ
+U+bd41 bwaeng # Character ëµ
+U+bd42 bwaej # Character ëµ
+U+bd43 bwaech # Character ëµ
+U+bd44 bwaek # Character ëµ
+U+bd45 bwaet # Character ëµ
+U+bd46 bwaep # Character ëµ
+U+bd47 bwaeh # Character ëµ
+U+bd48 boe # Character ëµ
+U+bd49 boeg # Character ëµ
+U+bd4a boekk # Character ëµ
+U+bd4b boegs # Character ëµ
+U+bd4c boen # Character ëµ
+U+bd4d boenj # Character ëµ
+U+bd4e boenh # Character ëµ
+U+bd4f boed # Character ëµ
+U+bd50 boel # Character ëµ
+U+bd51 boelg # Character ëµ
+U+bd52 boelm # Character ëµ
+U+bd53 boelb # Character ëµ
+U+bd54 boels # Character ëµ
+U+bd55 boelt # Character ëµ
+U+bd56 boelp # Character ëµ
+U+bd57 boelh # Character ëµ
+U+bd58 boem # Character ëµ
+U+bd59 boeb # Character ëµ
+U+bd5a boebs # Character ëµ
+U+bd5b boes # Character ëµ
+U+bd5c boess # Character ëµ
+U+bd5d boeng # Character ëµ
+U+bd5e boej # Character ëµ
+U+bd5f boech # Character ëµ
+U+bd60 boek # Character ëµ
+U+bd61 boet # Character 뵡
+U+bd62 boep # Character ëµ¢
+U+bd63 boeh # Character ëµ£
+U+bd64 byo # Character 뵤
+U+bd65 byog # Character ëµ¥
+U+bd66 byokk # Character 뵦
+U+bd67 byogs # Character 뵧
+U+bd68 byon # Character 뵨
+U+bd69 byonj # Character 뵩
+U+bd6a byonh # Character 뵪
+U+bd6b byod # Character 뵫
+U+bd6c byol # Character 뵬
+U+bd6d byolg # Character ëµ
+U+bd6e byolm # Character ëµ®
+U+bd6f byolb # Character 뵯
+U+bd70 byols # Character ëµ°
+U+bd71 byolt # Character ëµ±
+U+bd72 byolp # Character ëµ²
+U+bd73 byolh # Character ëµ³
+U+bd74 byom # Character ëµ´
+U+bd75 byob # Character ëµµ
+U+bd76 byobs # Character 뵶
+U+bd77 byos # Character ëµ·
+U+bd78 byoss # Character 뵸
+U+bd79 byong # Character ëµ¹
+U+bd7a byoj # Character 뵺
+U+bd7b byoch # Character ëµ»
+U+bd7c byok # Character ëµ¼
+U+bd7d byot # Character ëµ½
+U+bd7e byop # Character ëµ¾
+U+bd7f byoh # Character 뵿
+U+bd80 bu # Character ë¶
+U+bd81 bug # Character ë¶
+U+bd82 bukk # Character ë¶
+U+bd83 bugs # Character ë¶
+U+bd84 bun # Character ë¶
+U+bd85 bunj # Character ë¶
+U+bd86 bunh # Character ë¶
+U+bd87 bud # Character ë¶
+U+bd88 bul # Character ë¶
+U+bd89 bulg # Character ë¶
+U+bd8a bulm # Character ë¶
+U+bd8b bulb # Character ë¶
+U+bd8c buls # Character ë¶
+U+bd8d bult # Character ë¶
+U+bd8e bulp # Character ë¶
+U+bd8f bulh # Character ë¶
+U+bd90 bum # Character ë¶
+U+bd91 bub # Character ë¶
+U+bd92 bubs # Character ë¶
+U+bd93 bus # Character ë¶
+U+bd94 buss # Character ë¶
+U+bd95 bung # Character ë¶
+U+bd96 buj # Character ë¶
+U+bd97 buch # Character ë¶
+U+bd98 buk # Character ë¶
+U+bd99 but # Character ë¶
+U+bd9a bup # Character ë¶
+U+bd9b buh # Character ë¶
+U+bd9c bwo # Character ë¶
+U+bd9d bwog # Character ë¶
+U+bd9e bwokk # Character ë¶
+U+bd9f bwogs # Character ë¶
+U+bda0 bwon # Character ë¶
+U+bda1 bwonj # Character 붡
+U+bda2 bwonh # Character 붢
+U+bda3 bwod # Character 붣
+U+bda4 bwol # Character 붤
+U+bda5 bwolg # Character 붥
+U+bda6 bwolm # Character 붦
+U+bda7 bwolb # Character 붧
+U+bda8 bwols # Character 붨
+U+bda9 bwolt # Character 붩
+U+bdaa bwolp # Character 붪
+U+bdab bwolh # Character 붫
+U+bdac bwom # Character 붬
+U+bdad bwob # Character ë¶
+U+bdae bwobs # Character 붮
+U+bdaf bwos # Character 붯
+U+bdb0 bwoss # Character 붰
+U+bdb1 bwong # Character 붱
+U+bdb2 bwoj # Character 붲
+U+bdb3 bwoch # Character 붳
+U+bdb4 bwok # Character 붴
+U+bdb5 bwot # Character 붵
+U+bdb6 bwop # Character 붶
+U+bdb7 bwoh # Character 붷
+U+bdb8 bwe # Character 붸
+U+bdb9 bweg # Character 붹
+U+bdba bwekk # Character 붺
+U+bdbb bwegs # Character 붻
+U+bdbc bwen # Character 붼
+U+bdbd bwenj # Character 붽
+U+bdbe bwenh # Character 붾
+U+bdbf bwed # Character 붿
+U+bdc0 bwel # Character ë·
+U+bdc1 bwelg # Character ë·
+U+bdc2 bwelm # Character ë·
+U+bdc3 bwelb # Character ë·
+U+bdc4 bwels # Character ë·
+U+bdc5 bwelt # Character ë·
+U+bdc6 bwelp # Character ë·
+U+bdc7 bwelh # Character ë·
+U+bdc8 bwem # Character ë·
+U+bdc9 bweb # Character ë·
+U+bdca bwebs # Character ë·
+U+bdcb bwes # Character ë·
+U+bdcc bwess # Character ë·
+U+bdcd bweng # Character ë·
+U+bdce bwej # Character ë·
+U+bdcf bwech # Character ë·
+U+bdd0 bwek # Character ë·
+U+bdd1 bwet # Character ë·
+U+bdd2 bwep # Character ë·
+U+bdd3 bweh # Character ë·
+U+bdd4 bwi # Character ë·
+U+bdd5 bwig # Character ë·
+U+bdd6 bwikk # Character ë·
+U+bdd7 bwigs # Character ë·
+U+bdd8 bwin # Character ë·
+U+bdd9 bwinj # Character ë·
+U+bdda bwinh # Character ë·
+U+bddb bwid # Character ë·
+U+bddc bwil # Character ë·
+U+bddd bwilg # Character ë·
+U+bdde bwilm # Character ë·
+U+bddf bwilb # Character ë·
+U+bde0 bwils # Character ë·
+U+bde1 bwilt # Character ë·¡
+U+bde2 bwilp # Character ë·¢
+U+bde3 bwilh # Character ë·£
+U+bde4 bwim # Character ë·¤
+U+bde5 bwib # Character ë·¥
+U+bde6 bwibs # Character ë·¦
+U+bde7 bwis # Character ë·§
+U+bde8 bwiss # Character ë·¨
+U+bde9 bwing # Character ë·©
+U+bdea bwij # Character ë·ª
+U+bdeb bwich # Character ë·«
+U+bdec bwik # Character ë·¬
+U+bded bwit # Character ë·
+U+bdee bwip # Character ë·®
+U+bdef bwih # Character ë·¯
+U+bdf0 byu # Character ë·°
+U+bdf1 byug # Character ë·±
+U+bdf2 byukk # Character ë·²
+U+bdf3 byugs # Character ë·³
+U+bdf4 byun # Character ë·´
+U+bdf5 byunj # Character ë·µ
+U+bdf6 byunh # Character ë·¶
+U+bdf7 byud # Character ë··
+U+bdf8 byul # Character ë·¸
+U+bdf9 byulg # Character ë·¹
+U+bdfa byulm # Character ë·º
+U+bdfb byulb # Character ë·»
+U+bdfc byuls # Character ë·¼
+U+bdfd byult # Character ë·½
+U+bdfe byulp # Character ë·¾
+U+bdff byulh # Character ë·¿
diff --git a/resources/chars/latin1/rowbe.trans b/resources/chars/latin1/rowbe.trans
new file mode 100644
index 0000000..13fe656
--- /dev/null
+++ b/resources/chars/latin1/rowbe.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+be00 byum # Character ë¸
+U+be01 byub # Character ë¸
+U+be02 byubs # Character ë¸
+U+be03 byus # Character ë¸
+U+be04 byuss # Character ë¸
+U+be05 byung # Character ë¸
+U+be06 byuj # Character ë¸
+U+be07 byuch # Character ë¸
+U+be08 byuk # Character ë¸
+U+be09 byut # Character ë¸
+U+be0a byup # Character ë¸
+U+be0b byuh # Character ë¸
+U+be0c beu # Character ë¸
+U+be0d beug # Character ë¸
+U+be0e beukk # Character ë¸
+U+be0f beugs # Character ë¸
+U+be10 beun # Character ë¸
+U+be11 beunj # Character ë¸
+U+be12 beunh # Character ë¸
+U+be13 beud # Character ë¸
+U+be14 beul # Character ë¸
+U+be15 beulg # Character ë¸
+U+be16 beulm # Character ë¸
+U+be17 beulb # Character ë¸
+U+be18 beuls # Character ë¸
+U+be19 beult # Character ë¸
+U+be1a beulp # Character ë¸
+U+be1b beulh # Character ë¸
+U+be1c beum # Character ë¸
+U+be1d beub # Character ë¸
+U+be1e beubs # Character ë¸
+U+be1f beus # Character ë¸
+U+be20 beuss # Character ë¸
+U+be21 beung # Character 븡
+U+be22 beuj # Character 븢
+U+be23 beuch # Character 븣
+U+be24 beuk # Character 븤
+U+be25 beut # Character 븥
+U+be26 beup # Character 븦
+U+be27 beuh # Character 븧
+U+be28 bui # Character 븨
+U+be29 buig # Character 븩
+U+be2a buikk # Character 븪
+U+be2b buigs # Character 븫
+U+be2c buin # Character 븬
+U+be2d buinj # Character ë¸
+U+be2e buinh # Character 븮
+U+be2f buid # Character 븯
+U+be30 buil # Character 븰
+U+be31 builg # Character 븱
+U+be32 builm # Character 븲
+U+be33 builb # Character 븳
+U+be34 buils # Character 븴
+U+be35 built # Character 븵
+U+be36 builp # Character 븶
+U+be37 builh # Character 븷
+U+be38 buim # Character 븸
+U+be39 buib # Character 븹
+U+be3a buibs # Character 븺
+U+be3b buis # Character 븻
+U+be3c buiss # Character 븼
+U+be3d buing # Character 븽
+U+be3e buij # Character 븾
+U+be3f buich # Character 븿
+U+be40 buik # Character ë¹
+U+be41 buit # Character ë¹
+U+be42 buip # Character ë¹
+U+be43 buih # Character ë¹
+U+be44 bi # Character ë¹
+U+be45 big # Character ë¹
+U+be46 bikk # Character ë¹
+U+be47 bigs # Character ë¹
+U+be48 bin # Character ë¹
+U+be49 binj # Character ë¹
+U+be4a binh # Character ë¹
+U+be4b bid # Character ë¹
+U+be4c bil # Character ë¹
+U+be4d bilg # Character ë¹
+U+be4e bilm # Character ë¹
+U+be4f bilb # Character ë¹
+U+be50 bils # Character ë¹
+U+be51 bilt # Character ë¹
+U+be52 bilp # Character ë¹
+U+be53 bilh # Character ë¹
+U+be54 bim # Character ë¹
+U+be55 bib # Character ë¹
+U+be56 bibs # Character ë¹
+U+be57 bis # Character ë¹
+U+be58 biss # Character ë¹
+U+be59 bing # Character ë¹
+U+be5a bij # Character ë¹
+U+be5b bich # Character ë¹
+U+be5c bik # Character ë¹
+U+be5d bit # Character ë¹
+U+be5e bip # Character ë¹
+U+be5f bih # Character ë¹
+U+be60 ppa # Character ë¹
+U+be61 ppag # Character 빡
+U+be62 ppakk # Character ë¹¢
+U+be63 ppags # Character ë¹£
+U+be64 ppan # Character 빤
+U+be65 ppanj # Character ë¹¥
+U+be66 ppanh # Character 빦
+U+be67 ppad # Character 빧
+U+be68 ppal # Character 빨
+U+be69 ppalg # Character 빩
+U+be6a ppalm # Character 빪
+U+be6b ppalb # Character 빫
+U+be6c ppals # Character 빬
+U+be6d ppalt # Character ë¹
+U+be6e ppalp # Character ë¹®
+U+be6f ppalh # Character 빯
+U+be70 ppam # Character ë¹°
+U+be71 ppab # Character ë¹±
+U+be72 ppabs # Character ë¹²
+U+be73 ppas # Character ë¹³
+U+be74 ppass # Character ë¹´
+U+be75 ppang # Character ë¹µ
+U+be76 ppaj # Character 빶
+U+be77 ppach # Character ë¹·
+U+be78 ppak # Character 빸
+U+be79 ppat # Character ë¹¹
+U+be7a ppap # Character 빺
+U+be7b ppah # Character ë¹»
+U+be7c ppae # Character ë¹¼
+U+be7d ppaeg # Character ë¹½
+U+be7e ppaekk # Character ë¹¾
+U+be7f ppaegs # Character 빿
+U+be80 ppaen # Character ëº
+U+be81 ppaenj # Character ëº
+U+be82 ppaenh # Character ëº
+U+be83 ppaed # Character ëº
+U+be84 ppael # Character ëº
+U+be85 ppaelg # Character ëº
+U+be86 ppaelm # Character ëº
+U+be87 ppaelb # Character ëº
+U+be88 ppaels # Character ëº
+U+be89 ppaelt # Character ëº
+U+be8a ppaelp # Character ëº
+U+be8b ppaelh # Character ëº
+U+be8c ppaem # Character ëº
+U+be8d ppaeb # Character ëº
+U+be8e ppaebs # Character ëº
+U+be8f ppaes # Character ëº
+U+be90 ppaess # Character ëº
+U+be91 ppaeng # Character ëº
+U+be92 ppaej # Character ëº
+U+be93 ppaech # Character ëº
+U+be94 ppaek # Character ëº
+U+be95 ppaet # Character ëº
+U+be96 ppaep # Character ëº
+U+be97 ppaeh # Character ëº
+U+be98 ppya # Character ëº
+U+be99 ppyag # Character ëº
+U+be9a ppyakk # Character ëº
+U+be9b ppyags # Character ëº
+U+be9c ppyan # Character ëº
+U+be9d ppyanj # Character ëº
+U+be9e ppyanh # Character ëº
+U+be9f ppyad # Character ëº
+U+bea0 ppyal # Character ëº
+U+bea1 ppyalg # Character 뺡
+U+bea2 ppyalm # Character 뺢
+U+bea3 ppyalb # Character 뺣
+U+bea4 ppyals # Character 뺤
+U+bea5 ppyalt # Character 뺥
+U+bea6 ppyalp # Character 뺦
+U+bea7 ppyalh # Character 뺧
+U+bea8 ppyam # Character 뺨
+U+bea9 ppyab # Character 뺩
+U+beaa ppyabs # Character 뺪
+U+beab ppyas # Character 뺫
+U+beac ppyass # Character 뺬
+U+bead ppyang # Character ëº
+U+beae ppyaj # Character 뺮
+U+beaf ppyach # Character 뺯
+U+beb0 ppyak # Character 뺰
+U+beb1 ppyat # Character 뺱
+U+beb2 ppyap # Character 뺲
+U+beb3 ppyah # Character 뺳
+U+beb4 ppyae # Character 뺴
+U+beb5 ppyaeg # Character 뺵
+U+beb6 ppyaekk # Character 뺶
+U+beb7 ppyaegs # Character 뺷
+U+beb8 ppyaen # Character 뺸
+U+beb9 ppyaenj # Character 뺹
+U+beba ppyaenh # Character 뺺
+U+bebb ppyaed # Character 뺻
+U+bebc ppyael # Character 뺼
+U+bebd ppyaelg # Character 뺽
+U+bebe ppyaelm # Character 뺾
+U+bebf ppyaelb # Character 뺿
+U+bec0 ppyaels # Character ë»
+U+bec1 ppyaelt # Character ë»
+U+bec2 ppyaelp # Character ë»
+U+bec3 ppyaelh # Character ë»
+U+bec4 ppyaem # Character ë»
+U+bec5 ppyaeb # Character ë»
+U+bec6 ppyaebs # Character ë»
+U+bec7 ppyaes # Character ë»
+U+bec8 ppyaess # Character ë»
+U+bec9 ppyaeng # Character ë»
+U+beca ppyaej # Character ë»
+U+becb ppyaech # Character ë»
+U+becc ppyaek # Character ë»
+U+becd ppyaet # Character ë»
+U+bece ppyaep # Character ë»
+U+becf ppyaeh # Character ë»
+U+bed0 ppeo # Character ë»
+U+bed1 ppeog # Character ë»
+U+bed2 ppeokk # Character ë»
+U+bed3 ppeogs # Character ë»
+U+bed4 ppeon # Character ë»
+U+bed5 ppeonj # Character ë»
+U+bed6 ppeonh # Character ë»
+U+bed7 ppeod # Character ë»
+U+bed8 ppeol # Character ë»
+U+bed9 ppeolg # Character ë»
+U+beda ppeolm # Character ë»
+U+bedb ppeolb # Character ë»
+U+bedc ppeols # Character ë»
+U+bedd ppeolt # Character ë»
+U+bede ppeolp # Character ë»
+U+bedf ppeolh # Character ë»
+U+bee0 ppeom # Character ë»
+U+bee1 ppeob # Character 뻡
+U+bee2 ppeobs # Character 뻢
+U+bee3 ppeos # Character 뻣
+U+bee4 ppeoss # Character 뻤
+U+bee5 ppeong # Character 뻥
+U+bee6 ppeoj # Character 뻦
+U+bee7 ppeoch # Character 뻧
+U+bee8 ppeok # Character 뻨
+U+bee9 ppeot # Character 뻩
+U+beea ppeop # Character 뻪
+U+beeb ppeoh # Character 뻫
+U+beec ppe # Character 뻬
+U+beed ppeg # Character ë»
+U+beee ppekk # Character ë»®
+U+beef ppegs # Character 뻯
+U+bef0 ppen # Character ë»°
+U+bef1 ppenj # Character ë»±
+U+bef2 ppenh # Character 뻲
+U+bef3 pped # Character 뻳
+U+bef4 ppel # Character ë»´
+U+bef5 ppelg # Character 뻵
+U+bef6 ppelm # Character 뻶
+U+bef7 ppelb # Character ë»·
+U+bef8 ppels # Character 뻸
+U+bef9 ppelt # Character 뻹
+U+befa ppelp # Character 뻺
+U+befb ppelh # Character ë»»
+U+befc ppem # Character 뻼
+U+befd ppeb # Character 뻽
+U+befe ppebs # Character 뻾
+U+beff ppes # Character 뻿
diff --git a/resources/chars/latin1/rowbf.trans b/resources/chars/latin1/rowbf.trans
new file mode 100644
index 0000000..06f3ea2
--- /dev/null
+++ b/resources/chars/latin1/rowbf.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+bf00 ppess # Character ë¼
+U+bf01 ppeng # Character ë¼
+U+bf02 ppej # Character ë¼
+U+bf03 ppech # Character ë¼
+U+bf04 ppek # Character ë¼
+U+bf05 ppet # Character ë¼
+U+bf06 ppep # Character ë¼
+U+bf07 ppeh # Character ë¼
+U+bf08 ppyeo # Character ë¼
+U+bf09 ppyeog # Character ë¼
+U+bf0a ppyeokk # Character ë¼
+U+bf0b ppyeogs # Character ë¼
+U+bf0c ppyeon # Character ë¼
+U+bf0d ppyeonj # Character ë¼
+U+bf0e ppyeonh # Character ë¼
+U+bf0f ppyeod # Character ë¼
+U+bf10 ppyeol # Character ë¼
+U+bf11 ppyeolg # Character ë¼
+U+bf12 ppyeolm # Character ë¼
+U+bf13 ppyeolb # Character ë¼
+U+bf14 ppyeols # Character ë¼
+U+bf15 ppyeolt # Character ë¼
+U+bf16 ppyeolp # Character ë¼
+U+bf17 ppyeolh # Character ë¼
+U+bf18 ppyeom # Character ë¼
+U+bf19 ppyeob # Character ë¼
+U+bf1a ppyeobs # Character ë¼
+U+bf1b ppyeos # Character ë¼
+U+bf1c ppyeoss # Character ë¼
+U+bf1d ppyeong # Character ë¼
+U+bf1e ppyeoj # Character ë¼
+U+bf1f ppyeoch # Character ë¼
+U+bf20 ppyeok # Character ë¼
+U+bf21 ppyeot # Character 뼡
+U+bf22 ppyeop # Character ë¼¢
+U+bf23 ppyeoh # Character ë¼£
+U+bf24 ppye # Character 뼤
+U+bf25 ppyeg # Character ë¼¥
+U+bf26 ppyekk # Character 뼦
+U+bf27 ppyegs # Character 뼧
+U+bf28 ppyen # Character 뼨
+U+bf29 ppyenj # Character 뼩
+U+bf2a ppyenh # Character 뼪
+U+bf2b ppyed # Character 뼫
+U+bf2c ppyel # Character 뼬
+U+bf2d ppyelg # Character ë¼
+U+bf2e ppyelm # Character ë¼®
+U+bf2f ppyelb # Character 뼯
+U+bf30 ppyels # Character ë¼°
+U+bf31 ppyelt # Character ë¼±
+U+bf32 ppyelp # Character ë¼²
+U+bf33 ppyelh # Character ë¼³
+U+bf34 ppyem # Character ë¼´
+U+bf35 ppyeb # Character ë¼µ
+U+bf36 ppyebs # Character 뼶
+U+bf37 ppyes # Character ë¼·
+U+bf38 ppyess # Character 뼸
+U+bf39 ppyeng # Character ë¼¹
+U+bf3a ppyej # Character 뼺
+U+bf3b ppyech # Character ë¼»
+U+bf3c ppyek # Character ë¼¼
+U+bf3d ppyet # Character ë¼½
+U+bf3e ppyep # Character ë¼¾
+U+bf3f ppyeh # Character 뼿
+U+bf40 ppo # Character ë½
+U+bf41 ppog # Character ë½
+U+bf42 ppokk # Character ë½
+U+bf43 ppogs # Character ë½
+U+bf44 ppon # Character ë½
+U+bf45 pponj # Character ë½
+U+bf46 pponh # Character ë½
+U+bf47 ppod # Character ë½
+U+bf48 ppol # Character ë½
+U+bf49 ppolg # Character ë½
+U+bf4a ppolm # Character ë½
+U+bf4b ppolb # Character ë½
+U+bf4c ppols # Character ë½
+U+bf4d ppolt # Character ë½
+U+bf4e ppolp # Character ë½
+U+bf4f ppolh # Character ë½
+U+bf50 ppom # Character ë½
+U+bf51 ppob # Character ë½
+U+bf52 ppobs # Character ë½
+U+bf53 ppos # Character ë½
+U+bf54 pposs # Character ë½
+U+bf55 ppong # Character ë½
+U+bf56 ppoj # Character ë½
+U+bf57 ppoch # Character ë½
+U+bf58 ppok # Character ë½
+U+bf59 ppot # Character ë½
+U+bf5a ppop # Character ë½
+U+bf5b ppoh # Character ë½
+U+bf5c ppwa # Character ë½
+U+bf5d ppwag # Character ë½
+U+bf5e ppwakk # Character ë½
+U+bf5f ppwags # Character ë½
+U+bf60 ppwan # Character ë½
+U+bf61 ppwanj # Character 뽡
+U+bf62 ppwanh # Character ë½¢
+U+bf63 ppwad # Character ë½£
+U+bf64 ppwal # Character 뽤
+U+bf65 ppwalg # Character ë½¥
+U+bf66 ppwalm # Character 뽦
+U+bf67 ppwalb # Character 뽧
+U+bf68 ppwals # Character 뽨
+U+bf69 ppwalt # Character 뽩
+U+bf6a ppwalp # Character 뽪
+U+bf6b ppwalh # Character 뽫
+U+bf6c ppwam # Character 뽬
+U+bf6d ppwab # Character ë½
+U+bf6e ppwabs # Character ë½®
+U+bf6f ppwas # Character 뽯
+U+bf70 ppwass # Character ë½°
+U+bf71 ppwang # Character ë½±
+U+bf72 ppwaj # Character ë½²
+U+bf73 ppwach # Character ë½³
+U+bf74 ppwak # Character ë½´
+U+bf75 ppwat # Character ë½µ
+U+bf76 ppwap # Character 뽶
+U+bf77 ppwah # Character ë½·
+U+bf78 ppwae # Character 뽸
+U+bf79 ppwaeg # Character ë½¹
+U+bf7a ppwaekk # Character 뽺
+U+bf7b ppwaegs # Character ë½»
+U+bf7c ppwaen # Character ë½¼
+U+bf7d ppwaenj # Character ë½½
+U+bf7e ppwaenh # Character ë½¾
+U+bf7f ppwaed # Character 뽿
+U+bf80 ppwael # Character ë¾
+U+bf81 ppwaelg # Character ë¾
+U+bf82 ppwaelm # Character ë¾
+U+bf83 ppwaelb # Character ë¾
+U+bf84 ppwaels # Character ë¾
+U+bf85 ppwaelt # Character ë¾
+U+bf86 ppwaelp # Character ë¾
+U+bf87 ppwaelh # Character ë¾
+U+bf88 ppwaem # Character ë¾
+U+bf89 ppwaeb # Character ë¾
+U+bf8a ppwaebs # Character ë¾
+U+bf8b ppwaes # Character ë¾
+U+bf8c ppwaess # Character ë¾
+U+bf8d ppwaeng # Character ë¾
+U+bf8e ppwaej # Character ë¾
+U+bf8f ppwaech # Character ë¾
+U+bf90 ppwaek # Character ë¾
+U+bf91 ppwaet # Character ë¾
+U+bf92 ppwaep # Character ë¾
+U+bf93 ppwaeh # Character ë¾
+U+bf94 ppoe # Character ë¾
+U+bf95 ppoeg # Character ë¾
+U+bf96 ppoekk # Character ë¾
+U+bf97 ppoegs # Character ë¾
+U+bf98 ppoen # Character ë¾
+U+bf99 ppoenj # Character ë¾
+U+bf9a ppoenh # Character ë¾
+U+bf9b ppoed # Character ë¾
+U+bf9c ppoel # Character ë¾
+U+bf9d ppoelg # Character ë¾
+U+bf9e ppoelm # Character ë¾
+U+bf9f ppoelb # Character ë¾
+U+bfa0 ppoels # Character ë¾
+U+bfa1 ppoelt # Character 뾡
+U+bfa2 ppoelp # Character ë¾¢
+U+bfa3 ppoelh # Character ë¾£
+U+bfa4 ppoem # Character 뾤
+U+bfa5 ppoeb # Character ë¾¥
+U+bfa6 ppoebs # Character 뾦
+U+bfa7 ppoes # Character 뾧
+U+bfa8 ppoess # Character 뾨
+U+bfa9 ppoeng # Character 뾩
+U+bfaa ppoej # Character 뾪
+U+bfab ppoech # Character 뾫
+U+bfac ppoek # Character 뾬
+U+bfad ppoet # Character ë¾
+U+bfae ppoep # Character ë¾®
+U+bfaf ppoeh # Character 뾯
+U+bfb0 ppyo # Character ë¾°
+U+bfb1 ppyog # Character ë¾±
+U+bfb2 ppyokk # Character ë¾²
+U+bfb3 ppyogs # Character ë¾³
+U+bfb4 ppyon # Character ë¾´
+U+bfb5 ppyonj # Character ë¾µ
+U+bfb6 ppyonh # Character 뾶
+U+bfb7 ppyod # Character ë¾·
+U+bfb8 ppyol # Character 뾸
+U+bfb9 ppyolg # Character ë¾¹
+U+bfba ppyolm # Character 뾺
+U+bfbb ppyolb # Character ë¾»
+U+bfbc ppyols # Character ë¾¼
+U+bfbd ppyolt # Character ë¾½
+U+bfbe ppyolp # Character ë¾¾
+U+bfbf ppyolh # Character 뾿
+U+bfc0 ppyom # Character ë¿
+U+bfc1 ppyob # Character ë¿
+U+bfc2 ppyobs # Character ë¿
+U+bfc3 ppyos # Character ë¿
+U+bfc4 ppyoss # Character ë¿
+U+bfc5 ppyong # Character ë¿
+U+bfc6 ppyoj # Character ë¿
+U+bfc7 ppyoch # Character ë¿
+U+bfc8 ppyok # Character ë¿
+U+bfc9 ppyot # Character ë¿
+U+bfca ppyop # Character ë¿
+U+bfcb ppyoh # Character ë¿
+U+bfcc ppu # Character ë¿
+U+bfcd ppug # Character ë¿
+U+bfce ppukk # Character ë¿
+U+bfcf ppugs # Character ë¿
+U+bfd0 ppun # Character ë¿
+U+bfd1 ppunj # Character ë¿
+U+bfd2 ppunh # Character ë¿
+U+bfd3 ppud # Character ë¿
+U+bfd4 ppul # Character ë¿
+U+bfd5 ppulg # Character ë¿
+U+bfd6 ppulm # Character ë¿
+U+bfd7 ppulb # Character ë¿
+U+bfd8 ppuls # Character ë¿
+U+bfd9 ppult # Character ë¿
+U+bfda ppulp # Character ë¿
+U+bfdb ppulh # Character ë¿
+U+bfdc ppum # Character ë¿
+U+bfdd ppub # Character ë¿
+U+bfde ppubs # Character ë¿
+U+bfdf ppus # Character ë¿
+U+bfe0 ppuss # Character ë¿
+U+bfe1 ppung # Character ë¿¡
+U+bfe2 ppuj # Character ë¿¢
+U+bfe3 ppuch # Character ë¿£
+U+bfe4 ppuk # Character 뿤
+U+bfe5 pput # Character ë¿¥
+U+bfe6 ppup # Character 뿦
+U+bfe7 ppuh # Character 뿧
+U+bfe8 ppwo # Character 뿨
+U+bfe9 ppwog # Character ë¿©
+U+bfea ppwokk # Character 뿪
+U+bfeb ppwogs # Character ë¿«
+U+bfec ppwon # Character 뿬
+U+bfed ppwonj # Character ë¿
+U+bfee ppwonh # Character ë¿®
+U+bfef ppwod # Character 뿯
+U+bff0 ppwol # Character ë¿°
+U+bff1 ppwolg # Character 뿱
+U+bff2 ppwolm # Character 뿲
+U+bff3 ppwolb # Character 뿳
+U+bff4 ppwols # Character ë¿´
+U+bff5 ppwolt # Character 뿵
+U+bff6 ppwolp # Character 뿶
+U+bff7 ppwolh # Character ë¿·
+U+bff8 ppwom # Character 뿸
+U+bff9 ppwob # Character 뿹
+U+bffa ppwobs # Character 뿺
+U+bffb ppwos # Character ë¿»
+U+bffc ppwoss # Character 뿼
+U+bffd ppwong # Character 뿽
+U+bffe ppwoj # Character 뿾
+U+bfff ppwoch # Character ë¿¿
diff --git a/resources/chars/latin1/rowc0.trans b/resources/chars/latin1/rowc0.trans
new file mode 100644
index 0000000..9c54a80
--- /dev/null
+++ b/resources/chars/latin1/rowc0.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+c000 ppwok # Character ì
+U+c001 ppwot # Character ì
+U+c002 ppwop # Character ì
+U+c003 ppwoh # Character ì
+U+c004 ppwe # Character ì
+U+c005 ppweg # Character ì
+U+c006 ppwekk # Character ì
+U+c007 ppwegs # Character ì
+U+c008 ppwen # Character ì
+U+c009 ppwenj # Character ì
+U+c00a ppwenh # Character ì
+U+c00b ppwed # Character ì
+U+c00c ppwel # Character ì
+U+c00d ppwelg # Character ì
+U+c00e ppwelm # Character ì
+U+c00f ppwelb # Character ì
+U+c010 ppwels # Character ì
+U+c011 ppwelt # Character ì
+U+c012 ppwelp # Character ì
+U+c013 ppwelh # Character ì
+U+c014 ppwem # Character ì
+U+c015 ppweb # Character ì
+U+c016 ppwebs # Character ì
+U+c017 ppwes # Character ì
+U+c018 ppwess # Character ì
+U+c019 ppweng # Character ì
+U+c01a ppwej # Character ì
+U+c01b ppwech # Character ì
+U+c01c ppwek # Character ì
+U+c01d ppwet # Character ì
+U+c01e ppwep # Character ì
+U+c01f ppweh # Character ì
+U+c020 ppwi # Character ì
+U+c021 ppwig # Character ì¡
+U+c022 ppwikk # Character ì¢
+U+c023 ppwigs # Character ì£
+U+c024 ppwin # Character ì¤
+U+c025 ppwinj # Character ì¥
+U+c026 ppwinh # Character ì¦
+U+c027 ppwid # Character ì§
+U+c028 ppwil # Character ì¨
+U+c029 ppwilg # Character ì©
+U+c02a ppwilm # Character ìª
+U+c02b ppwilb # Character ì«
+U+c02c ppwils # Character ì¬
+U+c02d ppwilt # Character ì
+U+c02e ppwilp # Character ì®
+U+c02f ppwilh # Character ì¯
+U+c030 ppwim # Character ì°
+U+c031 ppwib # Character ì±
+U+c032 ppwibs # Character ì²
+U+c033 ppwis # Character ì³
+U+c034 ppwiss # Character ì´
+U+c035 ppwing # Character ìµ
+U+c036 ppwij # Character ì¶
+U+c037 ppwich # Character ì·
+U+c038 ppwik # Character ì¸
+U+c039 ppwit # Character ì¹
+U+c03a ppwip # Character ìº
+U+c03b ppwih # Character ì»
+U+c03c ppyu # Character ì¼
+U+c03d ppyug # Character ì½
+U+c03e ppyukk # Character ì¾
+U+c03f ppyugs # Character ì¿
+U+c040 ppyun # Character ì
+U+c041 ppyunj # Character ì
+U+c042 ppyunh # Character ì
+U+c043 ppyud # Character ì
+U+c044 ppyul # Character ì
+U+c045 ppyulg # Character ì
+U+c046 ppyulm # Character ì
+U+c047 ppyulb # Character ì
+U+c048 ppyuls # Character ì
+U+c049 ppyult # Character ì
+U+c04a ppyulp # Character ì
+U+c04b ppyulh # Character ì
+U+c04c ppyum # Character ì
+U+c04d ppyub # Character ì
+U+c04e ppyubs # Character ì
+U+c04f ppyus # Character ì
+U+c050 ppyuss # Character ì
+U+c051 ppyung # Character ì
+U+c052 ppyuj # Character ì
+U+c053 ppyuch # Character ì
+U+c054 ppyuk # Character ì
+U+c055 ppyut # Character ì
+U+c056 ppyup # Character ì
+U+c057 ppyuh # Character ì
+U+c058 ppeu # Character ì
+U+c059 ppeug # Character ì
+U+c05a ppeukk # Character ì
+U+c05b ppeugs # Character ì
+U+c05c ppeun # Character ì
+U+c05d ppeunj # Character ì
+U+c05e ppeunh # Character ì
+U+c05f ppeud # Character ì
+U+c060 ppeul # Character ì
+U+c061 ppeulg # Character ì¡
+U+c062 ppeulm # Character ì¢
+U+c063 ppeulb # Character ì£
+U+c064 ppeuls # Character ì¤
+U+c065 ppeult # Character ì¥
+U+c066 ppeulp # Character ì¦
+U+c067 ppeulh # Character ì§
+U+c068 ppeum # Character ì¨
+U+c069 ppeub # Character ì©
+U+c06a ppeubs # Character ìª
+U+c06b ppeus # Character ì«
+U+c06c ppeuss # Character ì¬
+U+c06d ppeung # Character ì
+U+c06e ppeuj # Character ì®
+U+c06f ppeuch # Character ì¯
+U+c070 ppeuk # Character ì°
+U+c071 ppeut # Character ì±
+U+c072 ppeup # Character ì²
+U+c073 ppeuh # Character ì³
+U+c074 ppui # Character ì´
+U+c075 ppuig # Character ìµ
+U+c076 ppuikk # Character ì¶
+U+c077 ppuigs # Character ì·
+U+c078 ppuin # Character ì¸
+U+c079 ppuinj # Character ì¹
+U+c07a ppuinh # Character ìº
+U+c07b ppuid # Character ì»
+U+c07c ppuil # Character ì¼
+U+c07d ppuilg # Character ì½
+U+c07e ppuilm # Character ì¾
+U+c07f ppuilb # Character ì¿
+U+c080 ppuils # Character ì
+U+c081 ppuilt # Character ì
+U+c082 ppuilp # Character ì
+U+c083 ppuilh # Character ì
+U+c084 ppuim # Character ì
+U+c085 ppuib # Character ì
+U+c086 ppuibs # Character ì
+U+c087 ppuis # Character ì
+U+c088 ppuiss # Character ì
+U+c089 ppuing # Character ì
+U+c08a ppuij # Character ì
+U+c08b ppuich # Character ì
+U+c08c ppuik # Character ì
+U+c08d ppuit # Character ì
+U+c08e ppuip # Character ì
+U+c08f ppuih # Character ì
+U+c090 ppi # Character ì
+U+c091 ppig # Character ì
+U+c092 ppikk # Character ì
+U+c093 ppigs # Character ì
+U+c094 ppin # Character ì
+U+c095 ppinj # Character ì
+U+c096 ppinh # Character ì
+U+c097 ppid # Character ì
+U+c098 ppil # Character ì
+U+c099 ppilg # Character ì
+U+c09a ppilm # Character ì
+U+c09b ppilb # Character ì
+U+c09c ppils # Character ì
+U+c09d ppilt # Character ì
+U+c09e ppilp # Character ì
+U+c09f ppilh # Character ì
+U+c0a0 ppim # Character ì
+U+c0a1 ppib # Character ì¡
+U+c0a2 ppibs # Character ì¢
+U+c0a3 ppis # Character ì£
+U+c0a4 ppiss # Character ì¤
+U+c0a5 pping # Character ì¥
+U+c0a6 ppij # Character ì¦
+U+c0a7 ppich # Character ì§
+U+c0a8 ppik # Character ì¨
+U+c0a9 ppit # Character ì©
+U+c0aa ppip # Character ìª
+U+c0ab ppih # Character ì«
+U+c0ac sa # Character ì¬
+U+c0ad sag # Character ì
+U+c0ae sakk # Character ì®
+U+c0af sags # Character ì¯
+U+c0b0 san # Character ì°
+U+c0b1 sanj # Character ì±
+U+c0b2 sanh # Character ì²
+U+c0b3 sad # Character ì³
+U+c0b4 sal # Character ì´
+U+c0b5 salg # Character ìµ
+U+c0b6 salm # Character ì¶
+U+c0b7 salb # Character ì·
+U+c0b8 sals # Character ì¸
+U+c0b9 salt # Character ì¹
+U+c0ba salp # Character ìº
+U+c0bb salh # Character ì»
+U+c0bc sam # Character ì¼
+U+c0bd sab # Character ì½
+U+c0be sabs # Character ì¾
+U+c0bf sas # Character ì¿
+U+c0c0 sass # Character ì
+U+c0c1 sang # Character ì
+U+c0c2 saj # Character ì
+U+c0c3 sach # Character ì
+U+c0c4 sak # Character ì
+U+c0c5 sat # Character ì
+U+c0c6 sap # Character ì
+U+c0c7 sah # Character ì
+U+c0c8 sae # Character ì
+U+c0c9 saeg # Character ì
+U+c0ca saekk # Character ì
+U+c0cb saegs # Character ì
+U+c0cc saen # Character ì
+U+c0cd saenj # Character ì
+U+c0ce saenh # Character ì
+U+c0cf saed # Character ì
+U+c0d0 sael # Character ì
+U+c0d1 saelg # Character ì
+U+c0d2 saelm # Character ì
+U+c0d3 saelb # Character ì
+U+c0d4 saels # Character ì
+U+c0d5 saelt # Character ì
+U+c0d6 saelp # Character ì
+U+c0d7 saelh # Character ì
+U+c0d8 saem # Character ì
+U+c0d9 saeb # Character ì
+U+c0da saebs # Character ì
+U+c0db saes # Character ì
+U+c0dc saess # Character ì
+U+c0dd saeng # Character ì
+U+c0de saej # Character ì
+U+c0df saech # Character ì
+U+c0e0 saek # Character ì
+U+c0e1 saet # Character ì¡
+U+c0e2 saep # Character ì¢
+U+c0e3 saeh # Character ì£
+U+c0e4 sya # Character ì¤
+U+c0e5 syag # Character ì¥
+U+c0e6 syakk # Character ì¦
+U+c0e7 syags # Character ì§
+U+c0e8 syan # Character ì¨
+U+c0e9 syanj # Character ì©
+U+c0ea syanh # Character ìª
+U+c0eb syad # Character ì«
+U+c0ec syal # Character ì¬
+U+c0ed syalg # Character ì
+U+c0ee syalm # Character ì®
+U+c0ef syalb # Character ì¯
+U+c0f0 syals # Character ì°
+U+c0f1 syalt # Character ì±
+U+c0f2 syalp # Character ì²
+U+c0f3 syalh # Character ì³
+U+c0f4 syam # Character ì´
+U+c0f5 syab # Character ìµ
+U+c0f6 syabs # Character ì¶
+U+c0f7 syas # Character ì·
+U+c0f8 syass # Character ì¸
+U+c0f9 syang # Character ì¹
+U+c0fa syaj # Character ìº
+U+c0fb syach # Character ì»
+U+c0fc syak # Character ì¼
+U+c0fd syat # Character ì½
+U+c0fe syap # Character ì¾
+U+c0ff syah # Character ì¿
diff --git a/resources/chars/latin1/rowc1.trans b/resources/chars/latin1/rowc1.trans
new file mode 100644
index 0000000..cc097fb
--- /dev/null
+++ b/resources/chars/latin1/rowc1.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+c100 syae # Character ì
+U+c101 syaeg # Character ì
+U+c102 syaekk # Character ì
+U+c103 syaegs # Character ì
+U+c104 syaen # Character ì
+U+c105 syaenj # Character ì
+U+c106 syaenh # Character ì
+U+c107 syaed # Character ì
+U+c108 syael # Character ì
+U+c109 syaelg # Character ì
+U+c10a syaelm # Character ì
+U+c10b syaelb # Character ì
+U+c10c syaels # Character ì
+U+c10d syaelt # Character ì
+U+c10e syaelp # Character ì
+U+c10f syaelh # Character ì
+U+c110 syaem # Character ì
+U+c111 syaeb # Character ì
+U+c112 syaebs # Character ì
+U+c113 syaes # Character ì
+U+c114 syaess # Character ì
+U+c115 syaeng # Character ì
+U+c116 syaej # Character ì
+U+c117 syaech # Character ì
+U+c118 syaek # Character ì
+U+c119 syaet # Character ì
+U+c11a syaep # Character ì
+U+c11b syaeh # Character ì
+U+c11c seo # Character ì
+U+c11d seog # Character ì
+U+c11e seokk # Character ì
+U+c11f seogs # Character ì
+U+c120 seon # Character ì
+U+c121 seonj # Character ì¡
+U+c122 seonh # Character ì¢
+U+c123 seod # Character ì£
+U+c124 seol # Character ì¤
+U+c125 seolg # Character ì¥
+U+c126 seolm # Character ì¦
+U+c127 seolb # Character ì§
+U+c128 seols # Character ì¨
+U+c129 seolt # Character ì©
+U+c12a seolp # Character ìª
+U+c12b seolh # Character ì«
+U+c12c seom # Character ì¬
+U+c12d seob # Character ì
+U+c12e seobs # Character ì®
+U+c12f seos # Character ì¯
+U+c130 seoss # Character ì°
+U+c131 seong # Character ì±
+U+c132 seoj # Character ì²
+U+c133 seoch # Character ì³
+U+c134 seok # Character ì´
+U+c135 seot # Character ìµ
+U+c136 seop # Character ì¶
+U+c137 seoh # Character ì·
+U+c138 se # Character ì¸
+U+c139 seg # Character ì¹
+U+c13a sekk # Character ìº
+U+c13b segs # Character ì»
+U+c13c sen # Character ì¼
+U+c13d senj # Character ì½
+U+c13e senh # Character ì¾
+U+c13f sed # Character ì¿
+U+c140 sel # Character ì
+U+c141 selg # Character ì
+U+c142 selm # Character ì
+U+c143 selb # Character ì
+U+c144 sels # Character ì
+U+c145 selt # Character ì
+U+c146 selp # Character ì
+U+c147 selh # Character ì
+U+c148 sem # Character ì
+U+c149 seb # Character ì
+U+c14a sebs # Character ì
+U+c14b ses # Character ì
+U+c14c sess # Character ì
+U+c14d seng # Character ì
+U+c14e sej # Character ì
+U+c14f sech # Character ì
+U+c150 sek # Character ì
+U+c151 set # Character ì
+U+c152 sep # Character ì
+U+c153 seh # Character ì
+U+c154 syeo # Character ì
+U+c155 syeog # Character ì
+U+c156 syeokk # Character ì
+U+c157 syeogs # Character ì
+U+c158 syeon # Character ì
+U+c159 syeonj # Character ì
+U+c15a syeonh # Character ì
+U+c15b syeod # Character ì
+U+c15c syeol # Character ì
+U+c15d syeolg # Character ì
+U+c15e syeolm # Character ì
+U+c15f syeolb # Character ì
+U+c160 syeols # Character ì
+U+c161 syeolt # Character ì
¡
+U+c162 syeolp # Character ì
¢
+U+c163 syeolh # Character ì
£
+U+c164 syeom # Character ì
¤
+U+c165 syeob # Character ì
¥
+U+c166 syeobs # Character ì
¦
+U+c167 syeos # Character ì
§
+U+c168 syeoss # Character ì
¨
+U+c169 syeong # Character ì
©
+U+c16a syeoj # Character ì
ª
+U+c16b syeoch # Character ì
«
+U+c16c syeok # Character ì
¬
+U+c16d syeot # Character ì
+U+c16e syeop # Character ì
®
+U+c16f syeoh # Character ì
¯
+U+c170 sye # Character ì
°
+U+c171 syeg # Character ì
±
+U+c172 syekk # Character ì
²
+U+c173 syegs # Character ì
³
+U+c174 syen # Character ì
´
+U+c175 syenj # Character ì
µ
+U+c176 syenh # Character ì
¶
+U+c177 syed # Character ì
·
+U+c178 syel # Character ì
¸
+U+c179 syelg # Character ì
¹
+U+c17a syelm # Character ì
º
+U+c17b syelb # Character ì
»
+U+c17c syels # Character ì
¼
+U+c17d syelt # Character ì
½
+U+c17e syelp # Character ì
¾
+U+c17f syelh # Character ì
¿
+U+c180 syem # Character ì
+U+c181 syeb # Character ì
+U+c182 syebs # Character ì
+U+c183 syes # Character ì
+U+c184 syess # Character ì
+U+c185 syeng # Character ì
+U+c186 syej # Character ì
+U+c187 syech # Character ì
+U+c188 syek # Character ì
+U+c189 syet # Character ì
+U+c18a syep # Character ì
+U+c18b syeh # Character ì
+U+c18c so # Character ì
+U+c18d sog # Character ì
+U+c18e sokk # Character ì
+U+c18f sogs # Character ì
+U+c190 son # Character ì
+U+c191 sonj # Character ì
+U+c192 sonh # Character ì
+U+c193 sod # Character ì
+U+c194 sol # Character ì
+U+c195 solg # Character ì
+U+c196 solm # Character ì
+U+c197 solb # Character ì
+U+c198 sols # Character ì
+U+c199 solt # Character ì
+U+c19a solp # Character ì
+U+c19b solh # Character ì
+U+c19c som # Character ì
+U+c19d sob # Character ì
+U+c19e sobs # Character ì
+U+c19f sos # Character ì
+U+c1a0 soss # Character ì
+U+c1a1 song # Character ì¡
+U+c1a2 soj # Character ì¢
+U+c1a3 soch # Character ì£
+U+c1a4 sok # Character ì¤
+U+c1a5 sot # Character ì¥
+U+c1a6 sop # Character ì¦
+U+c1a7 soh # Character ì§
+U+c1a8 swa # Character ì¨
+U+c1a9 swag # Character ì©
+U+c1aa swakk # Character ìª
+U+c1ab swags # Character ì«
+U+c1ac swan # Character ì¬
+U+c1ad swanj # Character ì
+U+c1ae swanh # Character ì®
+U+c1af swad # Character ì¯
+U+c1b0 swal # Character ì°
+U+c1b1 swalg # Character ì±
+U+c1b2 swalm # Character ì²
+U+c1b3 swalb # Character ì³
+U+c1b4 swals # Character ì´
+U+c1b5 swalt # Character ìµ
+U+c1b6 swalp # Character ì¶
+U+c1b7 swalh # Character ì·
+U+c1b8 swam # Character ì¸
+U+c1b9 swab # Character ì¹
+U+c1ba swabs # Character ìº
+U+c1bb swas # Character ì»
+U+c1bc swass # Character ì¼
+U+c1bd swang # Character ì½
+U+c1be swaj # Character ì¾
+U+c1bf swach # Character ì¿
+U+c1c0 swak # Character ì
+U+c1c1 swat # Character ì
+U+c1c2 swap # Character ì
+U+c1c3 swah # Character ì
+U+c1c4 swae # Character ì
+U+c1c5 swaeg # Character ì
+U+c1c6 swaekk # Character ì
+U+c1c7 swaegs # Character ì
+U+c1c8 swaen # Character ì
+U+c1c9 swaenj # Character ì
+U+c1ca swaenh # Character ì
+U+c1cb swaed # Character ì
+U+c1cc swael # Character ì
+U+c1cd swaelg # Character ì
+U+c1ce swaelm # Character ì
+U+c1cf swaelb # Character ì
+U+c1d0 swaels # Character ì
+U+c1d1 swaelt # Character ì
+U+c1d2 swaelp # Character ì
+U+c1d3 swaelh # Character ì
+U+c1d4 swaem # Character ì
+U+c1d5 swaeb # Character ì
+U+c1d6 swaebs # Character ì
+U+c1d7 swaes # Character ì
+U+c1d8 swaess # Character ì
+U+c1d9 swaeng # Character ì
+U+c1da swaej # Character ì
+U+c1db swaech # Character ì
+U+c1dc swaek # Character ì
+U+c1dd swaet # Character ì
+U+c1de swaep # Character ì
+U+c1df swaeh # Character ì
+U+c1e0 soe # Character ì
+U+c1e1 soeg # Character ì¡
+U+c1e2 soekk # Character ì¢
+U+c1e3 soegs # Character ì£
+U+c1e4 soen # Character ì¤
+U+c1e5 soenj # Character ì¥
+U+c1e6 soenh # Character ì¦
+U+c1e7 soed # Character ì§
+U+c1e8 soel # Character ì¨
+U+c1e9 soelg # Character ì©
+U+c1ea soelm # Character ìª
+U+c1eb soelb # Character ì«
+U+c1ec soels # Character ì¬
+U+c1ed soelt # Character ì
+U+c1ee soelp # Character ì®
+U+c1ef soelh # Character ì¯
+U+c1f0 soem # Character ì°
+U+c1f1 soeb # Character ì±
+U+c1f2 soebs # Character ì²
+U+c1f3 soes # Character ì³
+U+c1f4 soess # Character ì´
+U+c1f5 soeng # Character ìµ
+U+c1f6 soej # Character ì¶
+U+c1f7 soech # Character ì·
+U+c1f8 soek # Character ì¸
+U+c1f9 soet # Character ì¹
+U+c1fa soep # Character ìº
+U+c1fb soeh # Character ì»
+U+c1fc syo # Character ì¼
+U+c1fd syog # Character ì½
+U+c1fe syokk # Character ì¾
+U+c1ff syogs # Character ì¿
diff --git a/resources/chars/latin1/rowc2.trans b/resources/chars/latin1/rowc2.trans
new file mode 100644
index 0000000..e08a137
--- /dev/null
+++ b/resources/chars/latin1/rowc2.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+c200 syon # Character ì
+U+c201 syonj # Character ì
+U+c202 syonh # Character ì
+U+c203 syod # Character ì
+U+c204 syol # Character ì
+U+c205 syolg # Character ì
+U+c206 syolm # Character ì
+U+c207 syolb # Character ì
+U+c208 syols # Character ì
+U+c209 syolt # Character ì
+U+c20a syolp # Character ì
+U+c20b syolh # Character ì
+U+c20c syom # Character ì
+U+c20d syob # Character ì
+U+c20e syobs # Character ì
+U+c20f syos # Character ì
+U+c210 syoss # Character ì
+U+c211 syong # Character ì
+U+c212 syoj # Character ì
+U+c213 syoch # Character ì
+U+c214 syok # Character ì
+U+c215 syot # Character ì
+U+c216 syop # Character ì
+U+c217 syoh # Character ì
+U+c218 su # Character ì
+U+c219 sug # Character ì
+U+c21a sukk # Character ì
+U+c21b sugs # Character ì
+U+c21c sun # Character ì
+U+c21d sunj # Character ì
+U+c21e sunh # Character ì
+U+c21f sud # Character ì
+U+c220 sul # Character ì
+U+c221 sulg # Character ì¡
+U+c222 sulm # Character ì¢
+U+c223 sulb # Character ì£
+U+c224 suls # Character ì¤
+U+c225 sult # Character ì¥
+U+c226 sulp # Character ì¦
+U+c227 sulh # Character ì§
+U+c228 sum # Character ì¨
+U+c229 sub # Character ì©
+U+c22a subs # Character ìª
+U+c22b sus # Character ì«
+U+c22c suss # Character ì¬
+U+c22d sung # Character ì
+U+c22e suj # Character ì®
+U+c22f such # Character ì¯
+U+c230 suk # Character ì°
+U+c231 sut # Character ì±
+U+c232 sup # Character ì²
+U+c233 suh # Character ì³
+U+c234 swo # Character ì´
+U+c235 swog # Character ìµ
+U+c236 swokk # Character ì¶
+U+c237 swogs # Character ì·
+U+c238 swon # Character ì¸
+U+c239 swonj # Character ì¹
+U+c23a swonh # Character ìº
+U+c23b swod # Character ì»
+U+c23c swol # Character ì¼
+U+c23d swolg # Character ì½
+U+c23e swolm # Character ì¾
+U+c23f swolb # Character ì¿
+U+c240 swols # Character ì
+U+c241 swolt # Character ì
+U+c242 swolp # Character ì
+U+c243 swolh # Character ì
+U+c244 swom # Character ì
+U+c245 swob # Character ì
+U+c246 swobs # Character ì
+U+c247 swos # Character ì
+U+c248 swoss # Character ì
+U+c249 swong # Character ì
+U+c24a swoj # Character ì
+U+c24b swoch # Character ì
+U+c24c swok # Character ì
+U+c24d swot # Character ì
+U+c24e swop # Character ì
+U+c24f swoh # Character ì
+U+c250 swe # Character ì
+U+c251 sweg # Character ì
+U+c252 swekk # Character ì
+U+c253 swegs # Character ì
+U+c254 swen # Character ì
+U+c255 swenj # Character ì
+U+c256 swenh # Character ì
+U+c257 swed # Character ì
+U+c258 swel # Character ì
+U+c259 swelg # Character ì
+U+c25a swelm # Character ì
+U+c25b swelb # Character ì
+U+c25c swels # Character ì
+U+c25d swelt # Character ì
+U+c25e swelp # Character ì
+U+c25f swelh # Character ì
+U+c260 swem # Character ì
+U+c261 sweb # Character ì¡
+U+c262 swebs # Character ì¢
+U+c263 swes # Character ì£
+U+c264 swess # Character ì¤
+U+c265 sweng # Character ì¥
+U+c266 swej # Character ì¦
+U+c267 swech # Character ì§
+U+c268 swek # Character ì¨
+U+c269 swet # Character ì©
+U+c26a swep # Character ìª
+U+c26b sweh # Character ì«
+U+c26c swi # Character ì¬
+U+c26d swig # Character ì
+U+c26e swikk # Character ì®
+U+c26f swigs # Character ì¯
+U+c270 swin # Character ì°
+U+c271 swinj # Character ì±
+U+c272 swinh # Character ì²
+U+c273 swid # Character ì³
+U+c274 swil # Character ì´
+U+c275 swilg # Character ìµ
+U+c276 swilm # Character ì¶
+U+c277 swilb # Character ì·
+U+c278 swils # Character ì¸
+U+c279 swilt # Character ì¹
+U+c27a swilp # Character ìº
+U+c27b swilh # Character ì»
+U+c27c swim # Character ì¼
+U+c27d swib # Character ì½
+U+c27e swibs # Character ì¾
+U+c27f swis # Character ì¿
+U+c280 swiss # Character ì
+U+c281 swing # Character ì
+U+c282 swij # Character ì
+U+c283 swich # Character ì
+U+c284 swik # Character ì
+U+c285 swit # Character ì
+U+c286 swip # Character ì
+U+c287 swih # Character ì
+U+c288 syu # Character ì
+U+c289 syug # Character ì
+U+c28a syukk # Character ì
+U+c28b syugs # Character ì
+U+c28c syun # Character ì
+U+c28d syunj # Character ì
+U+c28e syunh # Character ì
+U+c28f syud # Character ì
+U+c290 syul # Character ì
+U+c291 syulg # Character ì
+U+c292 syulm # Character ì
+U+c293 syulb # Character ì
+U+c294 syuls # Character ì
+U+c295 syult # Character ì
+U+c296 syulp # Character ì
+U+c297 syulh # Character ì
+U+c298 syum # Character ì
+U+c299 syub # Character ì
+U+c29a syubs # Character ì
+U+c29b syus # Character ì
+U+c29c syuss # Character ì
+U+c29d syung # Character ì
+U+c29e syuj # Character ì
+U+c29f syuch # Character ì
+U+c2a0 syuk # Character ì
+U+c2a1 syut # Character ì¡
+U+c2a2 syup # Character ì¢
+U+c2a3 syuh # Character ì£
+U+c2a4 seu # Character ì¤
+U+c2a5 seug # Character ì¥
+U+c2a6 seukk # Character ì¦
+U+c2a7 seugs # Character ì§
+U+c2a8 seun # Character ì¨
+U+c2a9 seunj # Character ì©
+U+c2aa seunh # Character ìª
+U+c2ab seud # Character ì«
+U+c2ac seul # Character ì¬
+U+c2ad seulg # Character ì
+U+c2ae seulm # Character ì®
+U+c2af seulb # Character ì¯
+U+c2b0 seuls # Character ì°
+U+c2b1 seult # Character ì±
+U+c2b2 seulp # Character ì²
+U+c2b3 seulh # Character ì³
+U+c2b4 seum # Character ì´
+U+c2b5 seub # Character ìµ
+U+c2b6 seubs # Character ì¶
+U+c2b7 seus # Character ì·
+U+c2b8 seuss # Character ì¸
+U+c2b9 seung # Character ì¹
+U+c2ba seuj # Character ìº
+U+c2bb seuch # Character ì»
+U+c2bc seuk # Character ì¼
+U+c2bd seut # Character ì½
+U+c2be seup # Character ì¾
+U+c2bf seuh # Character ì¿
+U+c2c0 sui # Character ì
+U+c2c1 suig # Character ì
+U+c2c2 suikk # Character ì
+U+c2c3 suigs # Character ì
+U+c2c4 suin # Character ì
+U+c2c5 suinj # Character ì
+U+c2c6 suinh # Character ì
+U+c2c7 suid # Character ì
+U+c2c8 suil # Character ì
+U+c2c9 suilg # Character ì
+U+c2ca suilm # Character ì
+U+c2cb suilb # Character ì
+U+c2cc suils # Character ì
+U+c2cd suilt # Character ì
+U+c2ce suilp # Character ì
+U+c2cf suilh # Character ì
+U+c2d0 suim # Character ì
+U+c2d1 suib # Character ì
+U+c2d2 suibs # Character ì
+U+c2d3 suis # Character ì
+U+c2d4 suiss # Character ì
+U+c2d5 suing # Character ì
+U+c2d6 suij # Character ì
+U+c2d7 suich # Character ì
+U+c2d8 suik # Character ì
+U+c2d9 suit # Character ì
+U+c2da suip # Character ì
+U+c2db suih # Character ì
+U+c2dc si # Character ì
+U+c2dd sig # Character ì
+U+c2de sikk # Character ì
+U+c2df sigs # Character ì
+U+c2e0 sin # Character ì
+U+c2e1 sinj # Character ì¡
+U+c2e2 sinh # Character ì¢
+U+c2e3 sid # Character ì£
+U+c2e4 sil # Character ì¤
+U+c2e5 silg # Character ì¥
+U+c2e6 silm # Character ì¦
+U+c2e7 silb # Character ì§
+U+c2e8 sils # Character ì¨
+U+c2e9 silt # Character ì©
+U+c2ea silp # Character ìª
+U+c2eb silh # Character ì«
+U+c2ec sim # Character ì¬
+U+c2ed sib # Character ì
+U+c2ee sibs # Character ì®
+U+c2ef sis # Character ì¯
+U+c2f0 siss # Character ì°
+U+c2f1 sing # Character ì±
+U+c2f2 sij # Character ì²
+U+c2f3 sich # Character ì³
+U+c2f4 sik # Character ì´
+U+c2f5 sit # Character ìµ
+U+c2f6 sip # Character ì¶
+U+c2f7 sih # Character ì·
+U+c2f8 ssa # Character ì¸
+U+c2f9 ssag # Character ì¹
+U+c2fa ssakk # Character ìº
+U+c2fb ssags # Character ì»
+U+c2fc ssan # Character ì¼
+U+c2fd ssanj # Character ì½
+U+c2fe ssanh # Character ì¾
+U+c2ff ssad # Character ì¿
diff --git a/resources/chars/latin1/rowc3.trans b/resources/chars/latin1/rowc3.trans
new file mode 100644
index 0000000..797d433
--- /dev/null
+++ b/resources/chars/latin1/rowc3.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+c300 ssal # Character ì
+U+c301 ssalg # Character ì
+U+c302 ssalm # Character ì
+U+c303 ssalb # Character ì
+U+c304 ssals # Character ì
+U+c305 ssalt # Character ì
+U+c306 ssalp # Character ì
+U+c307 ssalh # Character ì
+U+c308 ssam # Character ì
+U+c309 ssab # Character ì
+U+c30a ssabs # Character ì
+U+c30b ssas # Character ì
+U+c30c ssass # Character ì
+U+c30d ssang # Character ì
+U+c30e ssaj # Character ì
+U+c30f ssach # Character ì
+U+c310 ssak # Character ì
+U+c311 ssat # Character ì
+U+c312 ssap # Character ì
+U+c313 ssah # Character ì
+U+c314 ssae # Character ì
+U+c315 ssaeg # Character ì
+U+c316 ssaekk # Character ì
+U+c317 ssaegs # Character ì
+U+c318 ssaen # Character ì
+U+c319 ssaenj # Character ì
+U+c31a ssaenh # Character ì
+U+c31b ssaed # Character ì
+U+c31c ssael # Character ì
+U+c31d ssaelg # Character ì
+U+c31e ssaelm # Character ì
+U+c31f ssaelb # Character ì
+U+c320 ssaels # Character ì
+U+c321 ssaelt # Character ì¡
+U+c322 ssaelp # Character ì¢
+U+c323 ssaelh # Character ì£
+U+c324 ssaem # Character ì¤
+U+c325 ssaeb # Character ì¥
+U+c326 ssaebs # Character ì¦
+U+c327 ssaes # Character ì§
+U+c328 ssaess # Character ì¨
+U+c329 ssaeng # Character ì©
+U+c32a ssaej # Character ìª
+U+c32b ssaech # Character ì«
+U+c32c ssaek # Character ì¬
+U+c32d ssaet # Character ì
+U+c32e ssaep # Character ì®
+U+c32f ssaeh # Character ì¯
+U+c330 ssya # Character ì°
+U+c331 ssyag # Character ì±
+U+c332 ssyakk # Character ì²
+U+c333 ssyags # Character ì³
+U+c334 ssyan # Character ì´
+U+c335 ssyanj # Character ìµ
+U+c336 ssyanh # Character ì¶
+U+c337 ssyad # Character ì·
+U+c338 ssyal # Character ì¸
+U+c339 ssyalg # Character ì¹
+U+c33a ssyalm # Character ìº
+U+c33b ssyalb # Character ì»
+U+c33c ssyals # Character ì¼
+U+c33d ssyalt # Character ì½
+U+c33e ssyalp # Character ì¾
+U+c33f ssyalh # Character ì¿
+U+c340 ssyam # Character ì
+U+c341 ssyab # Character ì
+U+c342 ssyabs # Character ì
+U+c343 ssyas # Character ì
+U+c344 ssyass # Character ì
+U+c345 ssyang # Character ì
+U+c346 ssyaj # Character ì
+U+c347 ssyach # Character ì
+U+c348 ssyak # Character ì
+U+c349 ssyat # Character ì
+U+c34a ssyap # Character ì
+U+c34b ssyah # Character ì
+U+c34c ssyae # Character ì
+U+c34d ssyaeg # Character ì
+U+c34e ssyaekk # Character ì
+U+c34f ssyaegs # Character ì
+U+c350 ssyaen # Character ì
+U+c351 ssyaenj # Character ì
+U+c352 ssyaenh # Character ì
+U+c353 ssyaed # Character ì
+U+c354 ssyael # Character ì
+U+c355 ssyaelg # Character ì
+U+c356 ssyaelm # Character ì
+U+c357 ssyaelb # Character ì
+U+c358 ssyaels # Character ì
+U+c359 ssyaelt # Character ì
+U+c35a ssyaelp # Character ì
+U+c35b ssyaelh # Character ì
+U+c35c ssyaem # Character ì
+U+c35d ssyaeb # Character ì
+U+c35e ssyaebs # Character ì
+U+c35f ssyaes # Character ì
+U+c360 ssyaess # Character ì
+U+c361 ssyaeng # Character ì¡
+U+c362 ssyaej # Character ì¢
+U+c363 ssyaech # Character ì£
+U+c364 ssyaek # Character ì¤
+U+c365 ssyaet # Character ì¥
+U+c366 ssyaep # Character ì¦
+U+c367 ssyaeh # Character ì§
+U+c368 sseo # Character ì¨
+U+c369 sseog # Character ì©
+U+c36a sseokk # Character ìª
+U+c36b sseogs # Character ì«
+U+c36c sseon # Character ì¬
+U+c36d sseonj # Character ì
+U+c36e sseonh # Character ì®
+U+c36f sseod # Character ì¯
+U+c370 sseol # Character ì°
+U+c371 sseolg # Character ì±
+U+c372 sseolm # Character ì²
+U+c373 sseolb # Character ì³
+U+c374 sseols # Character ì´
+U+c375 sseolt # Character ìµ
+U+c376 sseolp # Character ì¶
+U+c377 sseolh # Character ì·
+U+c378 sseom # Character ì¸
+U+c379 sseob # Character ì¹
+U+c37a sseobs # Character ìº
+U+c37b sseos # Character ì»
+U+c37c sseoss # Character ì¼
+U+c37d sseong # Character ì½
+U+c37e sseoj # Character ì¾
+U+c37f sseoch # Character ì¿
+U+c380 sseok # Character ì
+U+c381 sseot # Character ì
+U+c382 sseop # Character ì
+U+c383 sseoh # Character ì
+U+c384 sse # Character ì
+U+c385 sseg # Character ì
+U+c386 ssekk # Character ì
+U+c387 ssegs # Character ì
+U+c388 ssen # Character ì
+U+c389 ssenj # Character ì
+U+c38a ssenh # Character ì
+U+c38b ssed # Character ì
+U+c38c ssel # Character ì
+U+c38d sselg # Character ì
+U+c38e sselm # Character ì
+U+c38f sselb # Character ì
+U+c390 ssels # Character ì
+U+c391 sselt # Character ì
+U+c392 sselp # Character ì
+U+c393 sselh # Character ì
+U+c394 ssem # Character ì
+U+c395 sseb # Character ì
+U+c396 ssebs # Character ì
+U+c397 sses # Character ì
+U+c398 ssess # Character ì
+U+c399 sseng # Character ì
+U+c39a ssej # Character ì
+U+c39b ssech # Character ì
+U+c39c ssek # Character ì
+U+c39d sset # Character ì
+U+c39e ssep # Character ì
+U+c39f sseh # Character ì
+U+c3a0 ssyeo # Character ì
+U+c3a1 ssyeog # Character ì¡
+U+c3a2 ssyeokk # Character ì¢
+U+c3a3 ssyeogs # Character ì£
+U+c3a4 ssyeon # Character ì¤
+U+c3a5 ssyeonj # Character ì¥
+U+c3a6 ssyeonh # Character ì¦
+U+c3a7 ssyeod # Character ì§
+U+c3a8 ssyeol # Character ì¨
+U+c3a9 ssyeolg # Character ì©
+U+c3aa ssyeolm # Character ìª
+U+c3ab ssyeolb # Character ì«
+U+c3ac ssyeols # Character ì¬
+U+c3ad ssyeolt # Character ì
+U+c3ae ssyeolp # Character ì®
+U+c3af ssyeolh # Character ì¯
+U+c3b0 ssyeom # Character ì°
+U+c3b1 ssyeob # Character ì±
+U+c3b2 ssyeobs # Character ì²
+U+c3b3 ssyeos # Character ì³
+U+c3b4 ssyeoss # Character ì´
+U+c3b5 ssyeong # Character ìµ
+U+c3b6 ssyeoj # Character ì¶
+U+c3b7 ssyeoch # Character ì·
+U+c3b8 ssyeok # Character ì¸
+U+c3b9 ssyeot # Character ì¹
+U+c3ba ssyeop # Character ìº
+U+c3bb ssyeoh # Character ì»
+U+c3bc ssye # Character ì¼
+U+c3bd ssyeg # Character ì½
+U+c3be ssyekk # Character ì¾
+U+c3bf ssyegs # Character ì¿
+U+c3c0 ssyen # Character ì
+U+c3c1 ssyenj # Character ì
+U+c3c2 ssyenh # Character ì
+U+c3c3 ssyed # Character ì
+U+c3c4 ssyel # Character ì
+U+c3c5 ssyelg # Character ì
+U+c3c6 ssyelm # Character ì
+U+c3c7 ssyelb # Character ì
+U+c3c8 ssyels # Character ì
+U+c3c9 ssyelt # Character ì
+U+c3ca ssyelp # Character ì
+U+c3cb ssyelh # Character ì
+U+c3cc ssyem # Character ì
+U+c3cd ssyeb # Character ì
+U+c3ce ssyebs # Character ì
+U+c3cf ssyes # Character ì
+U+c3d0 ssyess # Character ì
+U+c3d1 ssyeng # Character ì
+U+c3d2 ssyej # Character ì
+U+c3d3 ssyech # Character ì
+U+c3d4 ssyek # Character ì
+U+c3d5 ssyet # Character ì
+U+c3d6 ssyep # Character ì
+U+c3d7 ssyeh # Character ì
+U+c3d8 sso # Character ì
+U+c3d9 ssog # Character ì
+U+c3da ssokk # Character ì
+U+c3db ssogs # Character ì
+U+c3dc sson # Character ì
+U+c3dd ssonj # Character ì
+U+c3de ssonh # Character ì
+U+c3df ssod # Character ì
+U+c3e0 ssol # Character ì
+U+c3e1 ssolg # Character ì¡
+U+c3e2 ssolm # Character ì¢
+U+c3e3 ssolb # Character ì£
+U+c3e4 ssols # Character ì¤
+U+c3e5 ssolt # Character ì¥
+U+c3e6 ssolp # Character ì¦
+U+c3e7 ssolh # Character ì§
+U+c3e8 ssom # Character ì¨
+U+c3e9 ssob # Character ì©
+U+c3ea ssobs # Character ìª
+U+c3eb ssos # Character ì«
+U+c3ec ssoss # Character ì¬
+U+c3ed ssong # Character ì
+U+c3ee ssoj # Character ì®
+U+c3ef ssoch # Character ì¯
+U+c3f0 ssok # Character ì°
+U+c3f1 ssot # Character ì±
+U+c3f2 ssop # Character ì²
+U+c3f3 ssoh # Character ì³
+U+c3f4 sswa # Character ì´
+U+c3f5 sswag # Character ìµ
+U+c3f6 sswakk # Character ì¶
+U+c3f7 sswags # Character ì·
+U+c3f8 sswan # Character ì¸
+U+c3f9 sswanj # Character ì¹
+U+c3fa sswanh # Character ìº
+U+c3fb sswad # Character ì»
+U+c3fc sswal # Character ì¼
+U+c3fd sswalg # Character ì½
+U+c3fe sswalm # Character ì¾
+U+c3ff sswalb # Character ì¿
diff --git a/resources/chars/latin1/rowc4.trans b/resources/chars/latin1/rowc4.trans
new file mode 100644
index 0000000..51b3ec5
--- /dev/null
+++ b/resources/chars/latin1/rowc4.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+c400 sswals # Character ì
+U+c401 sswalt # Character ì
+U+c402 sswalp # Character ì
+U+c403 sswalh # Character ì
+U+c404 sswam # Character ì
+U+c405 sswab # Character ì
+U+c406 sswabs # Character ì
+U+c407 sswas # Character ì
+U+c408 sswass # Character ì
+U+c409 sswang # Character ì
+U+c40a sswaj # Character ì
+U+c40b sswach # Character ì
+U+c40c sswak # Character ì
+U+c40d sswat # Character ì
+U+c40e sswap # Character ì
+U+c40f sswah # Character ì
+U+c410 sswae # Character ì
+U+c411 sswaeg # Character ì
+U+c412 sswaekk # Character ì
+U+c413 sswaegs # Character ì
+U+c414 sswaen # Character ì
+U+c415 sswaenj # Character ì
+U+c416 sswaenh # Character ì
+U+c417 sswaed # Character ì
+U+c418 sswael # Character ì
+U+c419 sswaelg # Character ì
+U+c41a sswaelm # Character ì
+U+c41b sswaelb # Character ì
+U+c41c sswaels # Character ì
+U+c41d sswaelt # Character ì
+U+c41e sswaelp # Character ì
+U+c41f sswaelh # Character ì
+U+c420 sswaem # Character ì
+U+c421 sswaeb # Character ì¡
+U+c422 sswaebs # Character ì¢
+U+c423 sswaes # Character ì£
+U+c424 sswaess # Character ì¤
+U+c425 sswaeng # Character ì¥
+U+c426 sswaej # Character ì¦
+U+c427 sswaech # Character ì§
+U+c428 sswaek # Character ì¨
+U+c429 sswaet # Character ì©
+U+c42a sswaep # Character ìª
+U+c42b sswaeh # Character ì«
+U+c42c ssoe # Character ì¬
+U+c42d ssoeg # Character ì
+U+c42e ssoekk # Character ì®
+U+c42f ssoegs # Character ì¯
+U+c430 ssoen # Character ì°
+U+c431 ssoenj # Character ì±
+U+c432 ssoenh # Character ì²
+U+c433 ssoed # Character ì³
+U+c434 ssoel # Character ì´
+U+c435 ssoelg # Character ìµ
+U+c436 ssoelm # Character ì¶
+U+c437 ssoelb # Character ì·
+U+c438 ssoels # Character ì¸
+U+c439 ssoelt # Character ì¹
+U+c43a ssoelp # Character ìº
+U+c43b ssoelh # Character ì»
+U+c43c ssoem # Character ì¼
+U+c43d ssoeb # Character ì½
+U+c43e ssoebs # Character ì¾
+U+c43f ssoes # Character ì¿
+U+c440 ssoess # Character ì
+U+c441 ssoeng # Character ì
+U+c442 ssoej # Character ì
+U+c443 ssoech # Character ì
+U+c444 ssoek # Character ì
+U+c445 ssoet # Character ì
+U+c446 ssoep # Character ì
+U+c447 ssoeh # Character ì
+U+c448 ssyo # Character ì
+U+c449 ssyog # Character ì
+U+c44a ssyokk # Character ì
+U+c44b ssyogs # Character ì
+U+c44c ssyon # Character ì
+U+c44d ssyonj # Character ì
+U+c44e ssyonh # Character ì
+U+c44f ssyod # Character ì
+U+c450 ssyol # Character ì
+U+c451 ssyolg # Character ì
+U+c452 ssyolm # Character ì
+U+c453 ssyolb # Character ì
+U+c454 ssyols # Character ì
+U+c455 ssyolt # Character ì
+U+c456 ssyolp # Character ì
+U+c457 ssyolh # Character ì
+U+c458 ssyom # Character ì
+U+c459 ssyob # Character ì
+U+c45a ssyobs # Character ì
+U+c45b ssyos # Character ì
+U+c45c ssyoss # Character ì
+U+c45d ssyong # Character ì
+U+c45e ssyoj # Character ì
+U+c45f ssyoch # Character ì
+U+c460 ssyok # Character ì
+U+c461 ssyot # Character ì¡
+U+c462 ssyop # Character ì¢
+U+c463 ssyoh # Character ì£
+U+c464 ssu # Character ì¤
+U+c465 ssug # Character ì¥
+U+c466 ssukk # Character ì¦
+U+c467 ssugs # Character ì§
+U+c468 ssun # Character ì¨
+U+c469 ssunj # Character ì©
+U+c46a ssunh # Character ìª
+U+c46b ssud # Character ì«
+U+c46c ssul # Character ì¬
+U+c46d ssulg # Character ì
+U+c46e ssulm # Character ì®
+U+c46f ssulb # Character ì¯
+U+c470 ssuls # Character ì°
+U+c471 ssult # Character ì±
+U+c472 ssulp # Character ì²
+U+c473 ssulh # Character ì³
+U+c474 ssum # Character ì´
+U+c475 ssub # Character ìµ
+U+c476 ssubs # Character ì¶
+U+c477 ssus # Character ì·
+U+c478 ssuss # Character ì¸
+U+c479 ssung # Character ì¹
+U+c47a ssuj # Character ìº
+U+c47b ssuch # Character ì»
+U+c47c ssuk # Character ì¼
+U+c47d ssut # Character ì½
+U+c47e ssup # Character ì¾
+U+c47f ssuh # Character ì¿
+U+c480 sswo # Character ì
+U+c481 sswog # Character ì
+U+c482 sswokk # Character ì
+U+c483 sswogs # Character ì
+U+c484 sswon # Character ì
+U+c485 sswonj # Character ì
+U+c486 sswonh # Character ì
+U+c487 sswod # Character ì
+U+c488 sswol # Character ì
+U+c489 sswolg # Character ì
+U+c48a sswolm # Character ì
+U+c48b sswolb # Character ì
+U+c48c sswols # Character ì
+U+c48d sswolt # Character ì
+U+c48e sswolp # Character ì
+U+c48f sswolh # Character ì
+U+c490 sswom # Character ì
+U+c491 sswob # Character ì
+U+c492 sswobs # Character ì
+U+c493 sswos # Character ì
+U+c494 sswoss # Character ì
+U+c495 sswong # Character ì
+U+c496 sswoj # Character ì
+U+c497 sswoch # Character ì
+U+c498 sswok # Character ì
+U+c499 sswot # Character ì
+U+c49a sswop # Character ì
+U+c49b sswoh # Character ì
+U+c49c sswe # Character ì
+U+c49d ssweg # Character ì
+U+c49e sswekk # Character ì
+U+c49f sswegs # Character ì
+U+c4a0 sswen # Character ì
+U+c4a1 sswenj # Character ì¡
+U+c4a2 sswenh # Character ì¢
+U+c4a3 sswed # Character ì£
+U+c4a4 sswel # Character ì¤
+U+c4a5 sswelg # Character ì¥
+U+c4a6 sswelm # Character ì¦
+U+c4a7 sswelb # Character ì§
+U+c4a8 sswels # Character ì¨
+U+c4a9 sswelt # Character ì©
+U+c4aa sswelp # Character ìª
+U+c4ab sswelh # Character ì«
+U+c4ac sswem # Character ì¬
+U+c4ad ssweb # Character ì
+U+c4ae sswebs # Character ì®
+U+c4af sswes # Character ì¯
+U+c4b0 sswess # Character ì°
+U+c4b1 ssweng # Character ì±
+U+c4b2 sswej # Character ì²
+U+c4b3 sswech # Character ì³
+U+c4b4 sswek # Character ì´
+U+c4b5 sswet # Character ìµ
+U+c4b6 sswep # Character ì¶
+U+c4b7 ssweh # Character ì·
+U+c4b8 sswi # Character ì¸
+U+c4b9 sswig # Character ì¹
+U+c4ba sswikk # Character ìº
+U+c4bb sswigs # Character ì»
+U+c4bc sswin # Character ì¼
+U+c4bd sswinj # Character ì½
+U+c4be sswinh # Character ì¾
+U+c4bf sswid # Character ì¿
+U+c4c0 sswil # Character ì
+U+c4c1 sswilg # Character ì
+U+c4c2 sswilm # Character ì
+U+c4c3 sswilb # Character ì
+U+c4c4 sswils # Character ì
+U+c4c5 sswilt # Character ì
+U+c4c6 sswilp # Character ì
+U+c4c7 sswilh # Character ì
+U+c4c8 sswim # Character ì
+U+c4c9 sswib # Character ì
+U+c4ca sswibs # Character ì
+U+c4cb sswis # Character ì
+U+c4cc sswiss # Character ì
+U+c4cd sswing # Character ì
+U+c4ce sswij # Character ì
+U+c4cf sswich # Character ì
+U+c4d0 sswik # Character ì
+U+c4d1 sswit # Character ì
+U+c4d2 sswip # Character ì
+U+c4d3 sswih # Character ì
+U+c4d4 ssyu # Character ì
+U+c4d5 ssyug # Character ì
+U+c4d6 ssyukk # Character ì
+U+c4d7 ssyugs # Character ì
+U+c4d8 ssyun # Character ì
+U+c4d9 ssyunj # Character ì
+U+c4da ssyunh # Character ì
+U+c4db ssyud # Character ì
+U+c4dc ssyul # Character ì
+U+c4dd ssyulg # Character ì
+U+c4de ssyulm # Character ì
+U+c4df ssyulb # Character ì
+U+c4e0 ssyuls # Character ì
+U+c4e1 ssyult # Character ì¡
+U+c4e2 ssyulp # Character ì¢
+U+c4e3 ssyulh # Character ì£
+U+c4e4 ssyum # Character ì¤
+U+c4e5 ssyub # Character ì¥
+U+c4e6 ssyubs # Character ì¦
+U+c4e7 ssyus # Character ì§
+U+c4e8 ssyuss # Character ì¨
+U+c4e9 ssyung # Character ì©
+U+c4ea ssyuj # Character ìª
+U+c4eb ssyuch # Character ì«
+U+c4ec ssyuk # Character ì¬
+U+c4ed ssyut # Character ì
+U+c4ee ssyup # Character ì®
+U+c4ef ssyuh # Character ì¯
+U+c4f0 sseu # Character ì°
+U+c4f1 sseug # Character ì±
+U+c4f2 sseukk # Character ì²
+U+c4f3 sseugs # Character ì³
+U+c4f4 sseun # Character ì´
+U+c4f5 sseunj # Character ìµ
+U+c4f6 sseunh # Character ì¶
+U+c4f7 sseud # Character ì·
+U+c4f8 sseul # Character ì¸
+U+c4f9 sseulg # Character ì¹
+U+c4fa sseulm # Character ìº
+U+c4fb sseulb # Character ì»
+U+c4fc sseuls # Character ì¼
+U+c4fd sseult # Character ì½
+U+c4fe sseulp # Character ì¾
+U+c4ff sseulh # Character ì¿
diff --git a/resources/chars/latin1/rowc5.trans b/resources/chars/latin1/rowc5.trans
new file mode 100644
index 0000000..59a8b0f
--- /dev/null
+++ b/resources/chars/latin1/rowc5.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+c500 sseum # Character ì
+U+c501 sseub # Character ì
+U+c502 sseubs # Character ì
+U+c503 sseus # Character ì
+U+c504 sseuss # Character ì
+U+c505 sseung # Character ì
+U+c506 sseuj # Character ì
+U+c507 sseuch # Character ì
+U+c508 sseuk # Character ì
+U+c509 sseut # Character ì
+U+c50a sseup # Character ì
+U+c50b sseuh # Character ì
+U+c50c ssui # Character ì
+U+c50d ssuig # Character ì
+U+c50e ssuikk # Character ì
+U+c50f ssuigs # Character ì
+U+c510 ssuin # Character ì
+U+c511 ssuinj # Character ì
+U+c512 ssuinh # Character ì
+U+c513 ssuid # Character ì
+U+c514 ssuil # Character ì
+U+c515 ssuilg # Character ì
+U+c516 ssuilm # Character ì
+U+c517 ssuilb # Character ì
+U+c518 ssuils # Character ì
+U+c519 ssuilt # Character ì
+U+c51a ssuilp # Character ì
+U+c51b ssuilh # Character ì
+U+c51c ssuim # Character ì
+U+c51d ssuib # Character ì
+U+c51e ssuibs # Character ì
+U+c51f ssuis # Character ì
+U+c520 ssuiss # Character ì
+U+c521 ssuing # Character ì¡
+U+c522 ssuij # Character ì¢
+U+c523 ssuich # Character ì£
+U+c524 ssuik # Character ì¤
+U+c525 ssuit # Character ì¥
+U+c526 ssuip # Character ì¦
+U+c527 ssuih # Character ì§
+U+c528 ssi # Character ì¨
+U+c529 ssig # Character ì©
+U+c52a ssikk # Character ìª
+U+c52b ssigs # Character ì«
+U+c52c ssin # Character ì¬
+U+c52d ssinj # Character ì
+U+c52e ssinh # Character ì®
+U+c52f ssid # Character ì¯
+U+c530 ssil # Character ì°
+U+c531 ssilg # Character ì±
+U+c532 ssilm # Character ì²
+U+c533 ssilb # Character ì³
+U+c534 ssils # Character ì´
+U+c535 ssilt # Character ìµ
+U+c536 ssilp # Character ì¶
+U+c537 ssilh # Character ì·
+U+c538 ssim # Character ì¸
+U+c539 ssib # Character ì¹
+U+c53a ssibs # Character ìº
+U+c53b ssis # Character ì»
+U+c53c ssiss # Character ì¼
+U+c53d ssing # Character ì½
+U+c53e ssij # Character ì¾
+U+c53f ssich # Character ì¿
+U+c540 ssik # Character ì
+U+c541 ssit # Character ì
+U+c542 ssip # Character ì
+U+c543 ssih # Character ì
+U+c544 a # Character ì
+U+c545 ag # Character ì
+U+c546 akk # Character ì
+U+c547 ags # Character ì
+U+c548 an # Character ì
+U+c549 anj # Character ì
+U+c54a anh # Character ì
+U+c54b ad # Character ì
+U+c54c al # Character ì
+U+c54d alg # Character ì
+U+c54e alm # Character ì
+U+c54f alb # Character ì
+U+c550 als # Character ì
+U+c551 alt # Character ì
+U+c552 alp # Character ì
+U+c553 alh # Character ì
+U+c554 am # Character ì
+U+c555 ab # Character ì
+U+c556 abs # Character ì
+U+c557 as # Character ì
+U+c558 ass # Character ì
+U+c559 ang # Character ì
+U+c55a aj # Character ì
+U+c55b ach # Character ì
+U+c55c ak # Character ì
+U+c55d at # Character ì
+U+c55e ap # Character ì
+U+c55f ah # Character ì
+U+c560 ae # Character ì
+U+c561 aeg # Character ì¡
+U+c562 aekk # Character ì¢
+U+c563 aegs # Character ì£
+U+c564 aen # Character ì¤
+U+c565 aenj # Character ì¥
+U+c566 aenh # Character ì¦
+U+c567 aed # Character ì§
+U+c568 ael # Character ì¨
+U+c569 aelg # Character ì©
+U+c56a aelm # Character ìª
+U+c56b aelb # Character ì«
+U+c56c aels # Character ì¬
+U+c56d aelt # Character ì
+U+c56e aelp # Character ì®
+U+c56f aelh # Character ì¯
+U+c570 aem # Character ì°
+U+c571 aeb # Character ì±
+U+c572 aebs # Character ì²
+U+c573 aes # Character ì³
+U+c574 aess # Character ì´
+U+c575 aeng # Character ìµ
+U+c576 aej # Character ì¶
+U+c577 aech # Character ì·
+U+c578 aek # Character ì¸
+U+c579 aet # Character ì¹
+U+c57a aep # Character ìº
+U+c57b aeh # Character ì»
+U+c57c ya # Character ì¼
+U+c57d yag # Character ì½
+U+c57e yakk # Character ì¾
+U+c57f yags # Character ì¿
+U+c580 yan # Character ì
+U+c581 yanj # Character ì
+U+c582 yanh # Character ì
+U+c583 yad # Character ì
+U+c584 yal # Character ì
+U+c585 yalg # Character ì
+U+c586 yalm # Character ì
+U+c587 yalb # Character ì
+U+c588 yals # Character ì
+U+c589 yalt # Character ì
+U+c58a yalp # Character ì
+U+c58b yalh # Character ì
+U+c58c yam # Character ì
+U+c58d yab # Character ì
+U+c58e yabs # Character ì
+U+c58f yas # Character ì
+U+c590 yass # Character ì
+U+c591 yang # Character ì
+U+c592 yaj # Character ì
+U+c593 yach # Character ì
+U+c594 yak # Character ì
+U+c595 yat # Character ì
+U+c596 yap # Character ì
+U+c597 yah # Character ì
+U+c598 yae # Character ì
+U+c599 yaeg # Character ì
+U+c59a yaekk # Character ì
+U+c59b yaegs # Character ì
+U+c59c yaen # Character ì
+U+c59d yaenj # Character ì
+U+c59e yaenh # Character ì
+U+c59f yaed # Character ì
+U+c5a0 yael # Character ì
+U+c5a1 yaelg # Character ì¡
+U+c5a2 yaelm # Character ì¢
+U+c5a3 yaelb # Character ì£
+U+c5a4 yaels # Character ì¤
+U+c5a5 yaelt # Character ì¥
+U+c5a6 yaelp # Character ì¦
+U+c5a7 yaelh # Character ì§
+U+c5a8 yaem # Character ì¨
+U+c5a9 yaeb # Character ì©
+U+c5aa yaebs # Character ìª
+U+c5ab yaes # Character ì«
+U+c5ac yaess # Character ì¬
+U+c5ad yaeng # Character ì
+U+c5ae yaej # Character ì®
+U+c5af yaech # Character ì¯
+U+c5b0 yaek # Character ì°
+U+c5b1 yaet # Character ì±
+U+c5b2 yaep # Character ì²
+U+c5b3 yaeh # Character ì³
+U+c5b4 eo # Character ì´
+U+c5b5 eog # Character ìµ
+U+c5b6 eokk # Character ì¶
+U+c5b7 eogs # Character ì·
+U+c5b8 eon # Character ì¸
+U+c5b9 eonj # Character ì¹
+U+c5ba eonh # Character ìº
+U+c5bb eod # Character ì»
+U+c5bc eol # Character ì¼
+U+c5bd eolg # Character ì½
+U+c5be eolm # Character ì¾
+U+c5bf eolb # Character ì¿
+U+c5c0 eols # Character ì
+U+c5c1 eolt # Character ì
+U+c5c2 eolp # Character ì
+U+c5c3 eolh # Character ì
+U+c5c4 eom # Character ì
+U+c5c5 eob # Character ì
+U+c5c6 eobs # Character ì
+U+c5c7 eos # Character ì
+U+c5c8 eoss # Character ì
+U+c5c9 eong # Character ì
+U+c5ca eoj # Character ì
+U+c5cb eoch # Character ì
+U+c5cc eok # Character ì
+U+c5cd eot # Character ì
+U+c5ce eop # Character ì
+U+c5cf eoh # Character ì
+U+c5d0 e # Character ì
+U+c5d1 eg # Character ì
+U+c5d2 ekk # Character ì
+U+c5d3 egs # Character ì
+U+c5d4 en # Character ì
+U+c5d5 enj # Character ì
+U+c5d6 enh # Character ì
+U+c5d7 ed # Character ì
+U+c5d8 el # Character ì
+U+c5d9 elg # Character ì
+U+c5da elm # Character ì
+U+c5db elb # Character ì
+U+c5dc els # Character ì
+U+c5dd elt # Character ì
+U+c5de elp # Character ì
+U+c5df elh # Character ì
+U+c5e0 em # Character ì
+U+c5e1 eb # Character ì¡
+U+c5e2 ebs # Character ì¢
+U+c5e3 es # Character ì£
+U+c5e4 ess # Character ì¤
+U+c5e5 eng # Character ì¥
+U+c5e6 ej # Character ì¦
+U+c5e7 ech # Character ì§
+U+c5e8 ek # Character ì¨
+U+c5e9 et # Character ì©
+U+c5ea ep # Character ìª
+U+c5eb eh # Character ì«
+U+c5ec yeo # Character ì¬
+U+c5ed yeog # Character ì
+U+c5ee yeokk # Character ì®
+U+c5ef yeogs # Character ì¯
+U+c5f0 yeon # Character ì°
+U+c5f1 yeonj # Character ì±
+U+c5f2 yeonh # Character ì²
+U+c5f3 yeod # Character ì³
+U+c5f4 yeol # Character ì´
+U+c5f5 yeolg # Character ìµ
+U+c5f6 yeolm # Character ì¶
+U+c5f7 yeolb # Character ì·
+U+c5f8 yeols # Character ì¸
+U+c5f9 yeolt # Character ì¹
+U+c5fa yeolp # Character ìº
+U+c5fb yeolh # Character ì»
+U+c5fc yeom # Character ì¼
+U+c5fd yeob # Character ì½
+U+c5fe yeobs # Character ì¾
+U+c5ff yeos # Character ì¿
diff --git a/resources/chars/latin1/rowc6.trans b/resources/chars/latin1/rowc6.trans
new file mode 100644
index 0000000..f4eb63a
--- /dev/null
+++ b/resources/chars/latin1/rowc6.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+c600 yeoss # Character ì
+U+c601 yeong # Character ì
+U+c602 yeoj # Character ì
+U+c603 yeoch # Character ì
+U+c604 yeok # Character ì
+U+c605 yeot # Character ì
+U+c606 yeop # Character ì
+U+c607 yeoh # Character ì
+U+c608 ye # Character ì
+U+c609 yeg # Character ì
+U+c60a yekk # Character ì
+U+c60b yegs # Character ì
+U+c60c yen # Character ì
+U+c60d yenj # Character ì
+U+c60e yenh # Character ì
+U+c60f yed # Character ì
+U+c610 yel # Character ì
+U+c611 yelg # Character ì
+U+c612 yelm # Character ì
+U+c613 yelb # Character ì
+U+c614 yels # Character ì
+U+c615 yelt # Character ì
+U+c616 yelp # Character ì
+U+c617 yelh # Character ì
+U+c618 yem # Character ì
+U+c619 yeb # Character ì
+U+c61a yebs # Character ì
+U+c61b yes # Character ì
+U+c61c yess # Character ì
+U+c61d yeng # Character ì
+U+c61e yej # Character ì
+U+c61f yech # Character ì
+U+c620 yek # Character ì
+U+c621 yet # Character ì¡
+U+c622 yep # Character ì¢
+U+c623 yeh # Character ì£
+U+c624 o # Character ì¤
+U+c625 og # Character ì¥
+U+c626 okk # Character ì¦
+U+c627 ogs # Character ì§
+U+c628 on # Character ì¨
+U+c629 onj # Character ì©
+U+c62a onh # Character ìª
+U+c62b od # Character ì«
+U+c62c ol # Character ì¬
+U+c62d olg # Character ì
+U+c62e olm # Character ì®
+U+c62f olb # Character ì¯
+U+c630 ols # Character ì°
+U+c631 olt # Character ì±
+U+c632 olp # Character ì²
+U+c633 olh # Character ì³
+U+c634 om # Character ì´
+U+c635 ob # Character ìµ
+U+c636 obs # Character ì¶
+U+c637 os # Character ì·
+U+c638 oss # Character ì¸
+U+c639 ong # Character ì¹
+U+c63a oj # Character ìº
+U+c63b och # Character ì»
+U+c63c ok # Character ì¼
+U+c63d ot # Character ì½
+U+c63e op # Character ì¾
+U+c63f oh # Character ì¿
+U+c640 wa # Character ì
+U+c641 wag # Character ì
+U+c642 wakk # Character ì
+U+c643 wags # Character ì
+U+c644 wan # Character ì
+U+c645 wanj # Character ì
+U+c646 wanh # Character ì
+U+c647 wad # Character ì
+U+c648 wal # Character ì
+U+c649 walg # Character ì
+U+c64a walm # Character ì
+U+c64b walb # Character ì
+U+c64c wals # Character ì
+U+c64d walt # Character ì
+U+c64e walp # Character ì
+U+c64f walh # Character ì
+U+c650 wam # Character ì
+U+c651 wab # Character ì
+U+c652 wabs # Character ì
+U+c653 was # Character ì
+U+c654 wass # Character ì
+U+c655 wang # Character ì
+U+c656 waj # Character ì
+U+c657 wach # Character ì
+U+c658 wak # Character ì
+U+c659 wat # Character ì
+U+c65a wap # Character ì
+U+c65b wah # Character ì
+U+c65c wae # Character ì
+U+c65d waeg # Character ì
+U+c65e waekk # Character ì
+U+c65f waegs # Character ì
+U+c660 waen # Character ì
+U+c661 waenj # Character ì¡
+U+c662 waenh # Character ì¢
+U+c663 waed # Character ì£
+U+c664 wael # Character ì¤
+U+c665 waelg # Character ì¥
+U+c666 waelm # Character ì¦
+U+c667 waelb # Character ì§
+U+c668 waels # Character ì¨
+U+c669 waelt # Character ì©
+U+c66a waelp # Character ìª
+U+c66b waelh # Character ì«
+U+c66c waem # Character ì¬
+U+c66d waeb # Character ì
+U+c66e waebs # Character ì®
+U+c66f waes # Character ì¯
+U+c670 waess # Character ì°
+U+c671 waeng # Character ì±
+U+c672 waej # Character ì²
+U+c673 waech # Character ì³
+U+c674 waek # Character ì´
+U+c675 waet # Character ìµ
+U+c676 waep # Character ì¶
+U+c677 waeh # Character ì·
+U+c678 oe # Character ì¸
+U+c679 oeg # Character ì¹
+U+c67a oekk # Character ìº
+U+c67b oegs # Character ì»
+U+c67c oen # Character ì¼
+U+c67d oenj # Character ì½
+U+c67e oenh # Character ì¾
+U+c67f oed # Character ì¿
+U+c680 oel # Character ì
+U+c681 oelg # Character ì
+U+c682 oelm # Character ì
+U+c683 oelb # Character ì
+U+c684 oels # Character ì
+U+c685 oelt # Character ì
+U+c686 oelp # Character ì
+U+c687 oelh # Character ì
+U+c688 oem # Character ì
+U+c689 oeb # Character ì
+U+c68a oebs # Character ì
+U+c68b oes # Character ì
+U+c68c oess # Character ì
+U+c68d oeng # Character ì
+U+c68e oej # Character ì
+U+c68f oech # Character ì
+U+c690 oek # Character ì
+U+c691 oet # Character ì
+U+c692 oep # Character ì
+U+c693 oeh # Character ì
+U+c694 yo # Character ì
+U+c695 yog # Character ì
+U+c696 yokk # Character ì
+U+c697 yogs # Character ì
+U+c698 yon # Character ì
+U+c699 yonj # Character ì
+U+c69a yonh # Character ì
+U+c69b yod # Character ì
+U+c69c yol # Character ì
+U+c69d yolg # Character ì
+U+c69e yolm # Character ì
+U+c69f yolb # Character ì
+U+c6a0 yols # Character ì
+U+c6a1 yolt # Character ì¡
+U+c6a2 yolp # Character ì¢
+U+c6a3 yolh # Character ì£
+U+c6a4 yom # Character ì¤
+U+c6a5 yob # Character ì¥
+U+c6a6 yobs # Character ì¦
+U+c6a7 yos # Character ì§
+U+c6a8 yoss # Character ì¨
+U+c6a9 yong # Character ì©
+U+c6aa yoj # Character ìª
+U+c6ab yoch # Character ì«
+U+c6ac yok # Character ì¬
+U+c6ad yot # Character ì
+U+c6ae yop # Character ì®
+U+c6af yoh # Character ì¯
+U+c6b0 u # Character ì°
+U+c6b1 ug # Character ì±
+U+c6b2 ukk # Character ì²
+U+c6b3 ugs # Character ì³
+U+c6b4 un # Character ì´
+U+c6b5 unj # Character ìµ
+U+c6b6 unh # Character ì¶
+U+c6b7 ud # Character ì·
+U+c6b8 ul # Character ì¸
+U+c6b9 ulg # Character ì¹
+U+c6ba ulm # Character ìº
+U+c6bb ulb # Character ì»
+U+c6bc uls # Character ì¼
+U+c6bd ult # Character ì½
+U+c6be ulp # Character ì¾
+U+c6bf ulh # Character ì¿
+U+c6c0 um # Character ì
+U+c6c1 ub # Character ì
+U+c6c2 ubs # Character ì
+U+c6c3 us # Character ì
+U+c6c4 uss # Character ì
+U+c6c5 ung # Character ì
+U+c6c6 uj # Character ì
+U+c6c7 uch # Character ì
+U+c6c8 uk # Character ì
+U+c6c9 ut # Character ì
+U+c6ca up # Character ì
+U+c6cb uh # Character ì
+U+c6cc wo # Character ì
+U+c6cd wog # Character ì
+U+c6ce wokk # Character ì
+U+c6cf wogs # Character ì
+U+c6d0 won # Character ì
+U+c6d1 wonj # Character ì
+U+c6d2 wonh # Character ì
+U+c6d3 wod # Character ì
+U+c6d4 wol # Character ì
+U+c6d5 wolg # Character ì
+U+c6d6 wolm # Character ì
+U+c6d7 wolb # Character ì
+U+c6d8 wols # Character ì
+U+c6d9 wolt # Character ì
+U+c6da wolp # Character ì
+U+c6db wolh # Character ì
+U+c6dc wom # Character ì
+U+c6dd wob # Character ì
+U+c6de wobs # Character ì
+U+c6df wos # Character ì
+U+c6e0 woss # Character ì
+U+c6e1 wong # Character ì¡
+U+c6e2 woj # Character ì¢
+U+c6e3 woch # Character ì£
+U+c6e4 wok # Character ì¤
+U+c6e5 wot # Character ì¥
+U+c6e6 wop # Character ì¦
+U+c6e7 woh # Character ì§
+U+c6e8 we # Character ì¨
+U+c6e9 weg # Character ì©
+U+c6ea wekk # Character ìª
+U+c6eb wegs # Character ì«
+U+c6ec wen # Character ì¬
+U+c6ed wenj # Character ì
+U+c6ee wenh # Character ì®
+U+c6ef wed # Character ì¯
+U+c6f0 wel # Character ì°
+U+c6f1 welg # Character ì±
+U+c6f2 welm # Character ì²
+U+c6f3 welb # Character ì³
+U+c6f4 wels # Character ì´
+U+c6f5 welt # Character ìµ
+U+c6f6 welp # Character ì¶
+U+c6f7 welh # Character ì·
+U+c6f8 wem # Character ì¸
+U+c6f9 web # Character ì¹
+U+c6fa webs # Character ìº
+U+c6fb wes # Character ì»
+U+c6fc wess # Character ì¼
+U+c6fd weng # Character ì½
+U+c6fe wej # Character ì¾
+U+c6ff wech # Character ì¿
diff --git a/resources/chars/latin1/rowc7.trans b/resources/chars/latin1/rowc7.trans
new file mode 100644
index 0000000..1a721b6
--- /dev/null
+++ b/resources/chars/latin1/rowc7.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+c700 wek # Character ì
+U+c701 wet # Character ì
+U+c702 wep # Character ì
+U+c703 weh # Character ì
+U+c704 wi # Character ì
+U+c705 wig # Character ì
+U+c706 wikk # Character ì
+U+c707 wigs # Character ì
+U+c708 win # Character ì
+U+c709 winj # Character ì
+U+c70a winh # Character ì
+U+c70b wid # Character ì
+U+c70c wil # Character ì
+U+c70d wilg # Character ì
+U+c70e wilm # Character ì
+U+c70f wilb # Character ì
+U+c710 wils # Character ì
+U+c711 wilt # Character ì
+U+c712 wilp # Character ì
+U+c713 wilh # Character ì
+U+c714 wim # Character ì
+U+c715 wib # Character ì
+U+c716 wibs # Character ì
+U+c717 wis # Character ì
+U+c718 wiss # Character ì
+U+c719 wing # Character ì
+U+c71a wij # Character ì
+U+c71b wich # Character ì
+U+c71c wik # Character ì
+U+c71d wit # Character ì
+U+c71e wip # Character ì
+U+c71f wih # Character ì
+U+c720 yu # Character ì
+U+c721 yug # Character ì¡
+U+c722 yukk # Character ì¢
+U+c723 yugs # Character ì£
+U+c724 yun # Character ì¤
+U+c725 yunj # Character ì¥
+U+c726 yunh # Character ì¦
+U+c727 yud # Character ì§
+U+c728 yul # Character ì¨
+U+c729 yulg # Character ì©
+U+c72a yulm # Character ìª
+U+c72b yulb # Character ì«
+U+c72c yuls # Character ì¬
+U+c72d yult # Character ì
+U+c72e yulp # Character ì®
+U+c72f yulh # Character ì¯
+U+c730 yum # Character ì°
+U+c731 yub # Character ì±
+U+c732 yubs # Character ì²
+U+c733 yus # Character ì³
+U+c734 yuss # Character ì´
+U+c735 yung # Character ìµ
+U+c736 yuj # Character ì¶
+U+c737 yuch # Character ì·
+U+c738 yuk # Character ì¸
+U+c739 yut # Character ì¹
+U+c73a yup # Character ìº
+U+c73b yuh # Character ì»
+U+c73c eu # Character ì¼
+U+c73d eug # Character ì½
+U+c73e eukk # Character ì¾
+U+c73f eugs # Character ì¿
+U+c740 eun # Character ì
+U+c741 eunj # Character ì
+U+c742 eunh # Character ì
+U+c743 eud # Character ì
+U+c744 eul # Character ì
+U+c745 eulg # Character ì
+U+c746 eulm # Character ì
+U+c747 eulb # Character ì
+U+c748 euls # Character ì
+U+c749 eult # Character ì
+U+c74a eulp # Character ì
+U+c74b eulh # Character ì
+U+c74c eum # Character ì
+U+c74d eub # Character ì
+U+c74e eubs # Character ì
+U+c74f eus # Character ì
+U+c750 euss # Character ì
+U+c751 eung # Character ì
+U+c752 euj # Character ì
+U+c753 euch # Character ì
+U+c754 euk # Character ì
+U+c755 eut # Character ì
+U+c756 eup # Character ì
+U+c757 euh # Character ì
+U+c758 ui # Character ì
+U+c759 uig # Character ì
+U+c75a uikk # Character ì
+U+c75b uigs # Character ì
+U+c75c uin # Character ì
+U+c75d uinj # Character ì
+U+c75e uinh # Character ì
+U+c75f uid # Character ì
+U+c760 uil # Character ì
+U+c761 uilg # Character ì¡
+U+c762 uilm # Character ì¢
+U+c763 uilb # Character ì£
+U+c764 uils # Character ì¤
+U+c765 uilt # Character ì¥
+U+c766 uilp # Character ì¦
+U+c767 uilh # Character ì§
+U+c768 uim # Character ì¨
+U+c769 uib # Character ì©
+U+c76a uibs # Character ìª
+U+c76b uis # Character ì«
+U+c76c uiss # Character ì¬
+U+c76d uing # Character ì
+U+c76e uij # Character ì®
+U+c76f uich # Character ì¯
+U+c770 uik # Character ì°
+U+c771 uit # Character ì±
+U+c772 uip # Character ì²
+U+c773 uih # Character ì³
+U+c774 i # Character ì´
+U+c775 ig # Character ìµ
+U+c776 ikk # Character ì¶
+U+c777 igs # Character ì·
+U+c778 in # Character ì¸
+U+c779 inj # Character ì¹
+U+c77a inh # Character ìº
+U+c77b id # Character ì»
+U+c77c il # Character ì¼
+U+c77d ilg # Character ì½
+U+c77e ilm # Character ì¾
+U+c77f ilb # Character ì¿
+U+c780 ils # Character ì
+U+c781 ilt # Character ì
+U+c782 ilp # Character ì
+U+c783 ilh # Character ì
+U+c784 im # Character ì
+U+c785 ib # Character ì
+U+c786 ibs # Character ì
+U+c787 is # Character ì
+U+c788 iss # Character ì
+U+c789 ing # Character ì
+U+c78a ij # Character ì
+U+c78b ich # Character ì
+U+c78c ik # Character ì
+U+c78d it # Character ì
+U+c78e ip # Character ì
+U+c78f ih # Character ì
+U+c790 ja # Character ì
+U+c791 jag # Character ì
+U+c792 jakk # Character ì
+U+c793 jags # Character ì
+U+c794 jan # Character ì
+U+c795 janj # Character ì
+U+c796 janh # Character ì
+U+c797 jad # Character ì
+U+c798 jal # Character ì
+U+c799 jalg # Character ì
+U+c79a jalm # Character ì
+U+c79b jalb # Character ì
+U+c79c jals # Character ì
+U+c79d jalt # Character ì
+U+c79e jalp # Character ì
+U+c79f jalh # Character ì
+U+c7a0 jam # Character ì
+U+c7a1 jab # Character ì¡
+U+c7a2 jabs # Character ì¢
+U+c7a3 jas # Character ì£
+U+c7a4 jass # Character ì¤
+U+c7a5 jang # Character ì¥
+U+c7a6 jaj # Character ì¦
+U+c7a7 jach # Character ì§
+U+c7a8 jak # Character ì¨
+U+c7a9 jat # Character ì©
+U+c7aa jap # Character ìª
+U+c7ab jah # Character ì«
+U+c7ac jae # Character ì¬
+U+c7ad jaeg # Character ì
+U+c7ae jaekk # Character ì®
+U+c7af jaegs # Character ì¯
+U+c7b0 jaen # Character ì°
+U+c7b1 jaenj # Character ì±
+U+c7b2 jaenh # Character ì²
+U+c7b3 jaed # Character ì³
+U+c7b4 jael # Character ì´
+U+c7b5 jaelg # Character ìµ
+U+c7b6 jaelm # Character ì¶
+U+c7b7 jaelb # Character ì·
+U+c7b8 jaels # Character ì¸
+U+c7b9 jaelt # Character ì¹
+U+c7ba jaelp # Character ìº
+U+c7bb jaelh # Character ì»
+U+c7bc jaem # Character ì¼
+U+c7bd jaeb # Character ì½
+U+c7be jaebs # Character ì¾
+U+c7bf jaes # Character ì¿
+U+c7c0 jaess # Character ì
+U+c7c1 jaeng # Character ì
+U+c7c2 jaej # Character ì
+U+c7c3 jaech # Character ì
+U+c7c4 jaek # Character ì
+U+c7c5 jaet # Character ì
+U+c7c6 jaep # Character ì
+U+c7c7 jaeh # Character ì
+U+c7c8 jya # Character ì
+U+c7c9 jyag # Character ì
+U+c7ca jyakk # Character ì
+U+c7cb jyags # Character ì
+U+c7cc jyan # Character ì
+U+c7cd jyanj # Character ì
+U+c7ce jyanh # Character ì
+U+c7cf jyad # Character ì
+U+c7d0 jyal # Character ì
+U+c7d1 jyalg # Character ì
+U+c7d2 jyalm # Character ì
+U+c7d3 jyalb # Character ì
+U+c7d4 jyals # Character ì
+U+c7d5 jyalt # Character ì
+U+c7d6 jyalp # Character ì
+U+c7d7 jyalh # Character ì
+U+c7d8 jyam # Character ì
+U+c7d9 jyab # Character ì
+U+c7da jyabs # Character ì
+U+c7db jyas # Character ì
+U+c7dc jyass # Character ì
+U+c7dd jyang # Character ì
+U+c7de jyaj # Character ì
+U+c7df jyach # Character ì
+U+c7e0 jyak # Character ì
+U+c7e1 jyat # Character ì¡
+U+c7e2 jyap # Character ì¢
+U+c7e3 jyah # Character ì£
+U+c7e4 jyae # Character ì¤
+U+c7e5 jyaeg # Character ì¥
+U+c7e6 jyaekk # Character ì¦
+U+c7e7 jyaegs # Character ì§
+U+c7e8 jyaen # Character ì¨
+U+c7e9 jyaenj # Character ì©
+U+c7ea jyaenh # Character ìª
+U+c7eb jyaed # Character ì«
+U+c7ec jyael # Character ì¬
+U+c7ed jyaelg # Character ì
+U+c7ee jyaelm # Character ì®
+U+c7ef jyaelb # Character ì¯
+U+c7f0 jyaels # Character ì°
+U+c7f1 jyaelt # Character ì±
+U+c7f2 jyaelp # Character ì²
+U+c7f3 jyaelh # Character ì³
+U+c7f4 jyaem # Character ì´
+U+c7f5 jyaeb # Character ìµ
+U+c7f6 jyaebs # Character ì¶
+U+c7f7 jyaes # Character ì·
+U+c7f8 jyaess # Character ì¸
+U+c7f9 jyaeng # Character ì¹
+U+c7fa jyaej # Character ìº
+U+c7fb jyaech # Character ì»
+U+c7fc jyaek # Character ì¼
+U+c7fd jyaet # Character ì½
+U+c7fe jyaep # Character ì¾
+U+c7ff jyaeh # Character ì¿
diff --git a/resources/chars/latin1/rowc8.trans b/resources/chars/latin1/rowc8.trans
new file mode 100644
index 0000000..9f6fc9c
--- /dev/null
+++ b/resources/chars/latin1/rowc8.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+c800 jeo # Character ì
+U+c801 jeog # Character ì
+U+c802 jeokk # Character ì
+U+c803 jeogs # Character ì
+U+c804 jeon # Character ì
+U+c805 jeonj # Character ì
+U+c806 jeonh # Character ì
+U+c807 jeod # Character ì
+U+c808 jeol # Character ì
+U+c809 jeolg # Character ì
+U+c80a jeolm # Character ì
+U+c80b jeolb # Character ì
+U+c80c jeols # Character ì
+U+c80d jeolt # Character ì
+U+c80e jeolp # Character ì
+U+c80f jeolh # Character ì
+U+c810 jeom # Character ì
+U+c811 jeob # Character ì
+U+c812 jeobs # Character ì
+U+c813 jeos # Character ì
+U+c814 jeoss # Character ì
+U+c815 jeong # Character ì
+U+c816 jeoj # Character ì
+U+c817 jeoch # Character ì
+U+c818 jeok # Character ì
+U+c819 jeot # Character ì
+U+c81a jeop # Character ì
+U+c81b jeoh # Character ì
+U+c81c je # Character ì
+U+c81d jeg # Character ì
+U+c81e jekk # Character ì
+U+c81f jegs # Character ì
+U+c820 jen # Character ì
+U+c821 jenj # Character ì ¡
+U+c822 jenh # Character ì ¢
+U+c823 jed # Character ì £
+U+c824 jel # Character ì ¤
+U+c825 jelg # Character ì ¥
+U+c826 jelm # Character ì ¦
+U+c827 jelb # Character ì §
+U+c828 jels # Character ì ¨
+U+c829 jelt # Character ì ©
+U+c82a jelp # Character ì ª
+U+c82b jelh # Character ì «
+U+c82c jem # Character ì ¬
+U+c82d jeb # Character ì
+U+c82e jebs # Character ì ®
+U+c82f jes # Character ì ¯
+U+c830 jess # Character ì °
+U+c831 jeng # Character ì ±
+U+c832 jej # Character ì ²
+U+c833 jech # Character ì ³
+U+c834 jek # Character ì ´
+U+c835 jet # Character ì µ
+U+c836 jep # Character ì ¶
+U+c837 jeh # Character ì ·
+U+c838 jyeo # Character ì ¸
+U+c839 jyeog # Character ì ¹
+U+c83a jyeokk # Character ì º
+U+c83b jyeogs # Character ì »
+U+c83c jyeon # Character ì ¼
+U+c83d jyeonj # Character ì ½
+U+c83e jyeonh # Character ì ¾
+U+c83f jyeod # Character ì ¿
+U+c840 jyeol # Character ì¡
+U+c841 jyeolg # Character ì¡
+U+c842 jyeolm # Character ì¡
+U+c843 jyeolb # Character ì¡
+U+c844 jyeols # Character ì¡
+U+c845 jyeolt # Character ì¡
+U+c846 jyeolp # Character ì¡
+U+c847 jyeolh # Character ì¡
+U+c848 jyeom # Character ì¡
+U+c849 jyeob # Character ì¡
+U+c84a jyeobs # Character ì¡
+U+c84b jyeos # Character ì¡
+U+c84c jyeoss # Character ì¡
+U+c84d jyeong # Character ì¡
+U+c84e jyeoj # Character ì¡
+U+c84f jyeoch # Character ì¡
+U+c850 jyeok # Character ì¡
+U+c851 jyeot # Character ì¡
+U+c852 jyeop # Character ì¡
+U+c853 jyeoh # Character ì¡
+U+c854 jye # Character ì¡
+U+c855 jyeg # Character ì¡
+U+c856 jyekk # Character ì¡
+U+c857 jyegs # Character ì¡
+U+c858 jyen # Character ì¡
+U+c859 jyenj # Character ì¡
+U+c85a jyenh # Character ì¡
+U+c85b jyed # Character ì¡
+U+c85c jyel # Character ì¡
+U+c85d jyelg # Character ì¡
+U+c85e jyelm # Character ì¡
+U+c85f jyelb # Character ì¡
+U+c860 jyels # Character ì¡
+U+c861 jyelt # Character ì¡¡
+U+c862 jyelp # Character ì¡¢
+U+c863 jyelh # Character ì¡£
+U+c864 jyem # Character 졤
+U+c865 jyeb # Character ì¡¥
+U+c866 jyebs # Character 졦
+U+c867 jyes # Character 졧
+U+c868 jyess # Character 졨
+U+c869 jyeng # Character ì¡©
+U+c86a jyej # Character 졪
+U+c86b jyech # Character ì¡«
+U+c86c jyek # Character 졬
+U+c86d jyet # Character ì¡
+U+c86e jyep # Character ì¡®
+U+c86f jyeh # Character 졯
+U+c870 jo # Character ì¡°
+U+c871 jog # Character 족
+U+c872 jokk # Character 졲
+U+c873 jogs # Character 졳
+U+c874 jon # Character ì¡´
+U+c875 jonj # Character 졵
+U+c876 jonh # Character 졶
+U+c877 jod # Character ì¡·
+U+c878 jol # Character 졸
+U+c879 jolg # Character 졹
+U+c87a jolm # Character 졺
+U+c87b jolb # Character ì¡»
+U+c87c jols # Character 졼
+U+c87d jolt # Character 졽
+U+c87e jolp # Character 졾
+U+c87f jolh # Character ì¡¿
+U+c880 jom # Character ì¢
+U+c881 job # Character ì¢
+U+c882 jobs # Character ì¢
+U+c883 jos # Character ì¢
+U+c884 joss # Character ì¢
+U+c885 jong # Character ì¢
+U+c886 joj # Character ì¢
+U+c887 joch # Character ì¢
+U+c888 jok # Character ì¢
+U+c889 jot # Character ì¢
+U+c88a jop # Character ì¢
+U+c88b joh # Character ì¢
+U+c88c jwa # Character ì¢
+U+c88d jwag # Character ì¢
+U+c88e jwakk # Character ì¢
+U+c88f jwags # Character ì¢
+U+c890 jwan # Character ì¢
+U+c891 jwanj # Character ì¢
+U+c892 jwanh # Character ì¢
+U+c893 jwad # Character ì¢
+U+c894 jwal # Character ì¢
+U+c895 jwalg # Character ì¢
+U+c896 jwalm # Character ì¢
+U+c897 jwalb # Character ì¢
+U+c898 jwals # Character ì¢
+U+c899 jwalt # Character ì¢
+U+c89a jwalp # Character ì¢
+U+c89b jwalh # Character ì¢
+U+c89c jwam # Character ì¢
+U+c89d jwab # Character ì¢
+U+c89e jwabs # Character ì¢
+U+c89f jwas # Character ì¢
+U+c8a0 jwass # Character ì¢
+U+c8a1 jwang # Character 좡
+U+c8a2 jwaj # Character 좢
+U+c8a3 jwach # Character 좣
+U+c8a4 jwak # Character 좤
+U+c8a5 jwat # Character 좥
+U+c8a6 jwap # Character 좦
+U+c8a7 jwah # Character 좧
+U+c8a8 jwae # Character 좨
+U+c8a9 jwaeg # Character 좩
+U+c8aa jwaekk # Character 좪
+U+c8ab jwaegs # Character 좫
+U+c8ac jwaen # Character 좬
+U+c8ad jwaenj # Character ì¢
+U+c8ae jwaenh # Character 좮
+U+c8af jwaed # Character 좯
+U+c8b0 jwael # Character 좰
+U+c8b1 jwaelg # Character 좱
+U+c8b2 jwaelm # Character 좲
+U+c8b3 jwaelb # Character 좳
+U+c8b4 jwaels # Character 좴
+U+c8b5 jwaelt # Character 좵
+U+c8b6 jwaelp # Character 좶
+U+c8b7 jwaelh # Character 좷
+U+c8b8 jwaem # Character 좸
+U+c8b9 jwaeb # Character 좹
+U+c8ba jwaebs # Character 좺
+U+c8bb jwaes # Character 좻
+U+c8bc jwaess # Character 좼
+U+c8bd jwaeng # Character 좽
+U+c8be jwaej # Character 좾
+U+c8bf jwaech # Character 좿
+U+c8c0 jwaek # Character ì£
+U+c8c1 jwaet # Character ì£
+U+c8c2 jwaep # Character ì£
+U+c8c3 jwaeh # Character ì£
+U+c8c4 joe # Character ì£
+U+c8c5 joeg # Character ì£
+U+c8c6 joekk # Character ì£
+U+c8c7 joegs # Character ì£
+U+c8c8 joen # Character ì£
+U+c8c9 joenj # Character ì£
+U+c8ca joenh # Character ì£
+U+c8cb joed # Character ì£
+U+c8cc joel # Character ì£
+U+c8cd joelg # Character ì£
+U+c8ce joelm # Character ì£
+U+c8cf joelb # Character ì£
+U+c8d0 joels # Character ì£
+U+c8d1 joelt # Character ì£
+U+c8d2 joelp # Character ì£
+U+c8d3 joelh # Character ì£
+U+c8d4 joem # Character ì£
+U+c8d5 joeb # Character ì£
+U+c8d6 joebs # Character ì£
+U+c8d7 joes # Character ì£
+U+c8d8 joess # Character ì£
+U+c8d9 joeng # Character ì£
+U+c8da joej # Character ì£
+U+c8db joech # Character ì£
+U+c8dc joek # Character ì£
+U+c8dd joet # Character ì£
+U+c8de joep # Character ì£
+U+c8df joeh # Character ì£
+U+c8e0 jyo # Character ì£
+U+c8e1 jyog # Character 죡
+U+c8e2 jyokk # Character 죢
+U+c8e3 jyogs # Character 죣
+U+c8e4 jyon # Character 죤
+U+c8e5 jyonj # Character 죥
+U+c8e6 jyonh # Character 죦
+U+c8e7 jyod # Character 죧
+U+c8e8 jyol # Character 죨
+U+c8e9 jyolg # Character 죩
+U+c8ea jyolm # Character 죪
+U+c8eb jyolb # Character 죫
+U+c8ec jyols # Character 죬
+U+c8ed jyolt # Character ì£
+U+c8ee jyolp # Character 죮
+U+c8ef jyolh # Character 죯
+U+c8f0 jyom # Character 죰
+U+c8f1 jyob # Character 죱
+U+c8f2 jyobs # Character 죲
+U+c8f3 jyos # Character 죳
+U+c8f4 jyoss # Character 죴
+U+c8f5 jyong # Character 죵
+U+c8f6 jyoj # Character 죶
+U+c8f7 jyoch # Character 죷
+U+c8f8 jyok # Character 죸
+U+c8f9 jyot # Character 죹
+U+c8fa jyop # Character 죺
+U+c8fb jyoh # Character 죻
+U+c8fc ju # Character 주
+U+c8fd jug # Character 죽
+U+c8fe jukk # Character 죾
+U+c8ff jugs # Character 죿
diff --git a/resources/chars/latin1/rowc9.trans b/resources/chars/latin1/rowc9.trans
new file mode 100644
index 0000000..c5a0ae0
--- /dev/null
+++ b/resources/chars/latin1/rowc9.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+c900 jun # Character ì¤
+U+c901 junj # Character ì¤
+U+c902 junh # Character ì¤
+U+c903 jud # Character ì¤
+U+c904 jul # Character ì¤
+U+c905 julg # Character ì¤
+U+c906 julm # Character ì¤
+U+c907 julb # Character ì¤
+U+c908 juls # Character ì¤
+U+c909 jult # Character ì¤
+U+c90a julp # Character ì¤
+U+c90b julh # Character ì¤
+U+c90c jum # Character ì¤
+U+c90d jub # Character ì¤
+U+c90e jubs # Character ì¤
+U+c90f jus # Character ì¤
+U+c910 juss # Character ì¤
+U+c911 jung # Character ì¤
+U+c912 juj # Character ì¤
+U+c913 juch # Character ì¤
+U+c914 juk # Character ì¤
+U+c915 jut # Character ì¤
+U+c916 jup # Character ì¤
+U+c917 juh # Character ì¤
+U+c918 jwo # Character ì¤
+U+c919 jwog # Character ì¤
+U+c91a jwokk # Character ì¤
+U+c91b jwogs # Character ì¤
+U+c91c jwon # Character ì¤
+U+c91d jwonj # Character ì¤
+U+c91e jwonh # Character ì¤
+U+c91f jwod # Character ì¤
+U+c920 jwol # Character ì¤
+U+c921 jwolg # Character 줡
+U+c922 jwolm # Character 줢
+U+c923 jwolb # Character 줣
+U+c924 jwols # Character 줤
+U+c925 jwolt # Character 줥
+U+c926 jwolp # Character 줦
+U+c927 jwolh # Character 줧
+U+c928 jwom # Character 줨
+U+c929 jwob # Character 줩
+U+c92a jwobs # Character 줪
+U+c92b jwos # Character 줫
+U+c92c jwoss # Character 줬
+U+c92d jwong # Character ì¤
+U+c92e jwoj # Character 줮
+U+c92f jwoch # Character 줯
+U+c930 jwok # Character 줰
+U+c931 jwot # Character 줱
+U+c932 jwop # Character 줲
+U+c933 jwoh # Character 줳
+U+c934 jwe # Character 줴
+U+c935 jweg # Character 줵
+U+c936 jwekk # Character 줶
+U+c937 jwegs # Character 줷
+U+c938 jwen # Character 줸
+U+c939 jwenj # Character 줹
+U+c93a jwenh # Character 줺
+U+c93b jwed # Character 줻
+U+c93c jwel # Character 줼
+U+c93d jwelg # Character 줽
+U+c93e jwelm # Character 줾
+U+c93f jwelb # Character 줿
+U+c940 jwels # Character ì¥
+U+c941 jwelt # Character ì¥
+U+c942 jwelp # Character ì¥
+U+c943 jwelh # Character ì¥
+U+c944 jwem # Character ì¥
+U+c945 jweb # Character ì¥
+U+c946 jwebs # Character ì¥
+U+c947 jwes # Character ì¥
+U+c948 jwess # Character ì¥
+U+c949 jweng # Character ì¥
+U+c94a jwej # Character ì¥
+U+c94b jwech # Character ì¥
+U+c94c jwek # Character ì¥
+U+c94d jwet # Character ì¥
+U+c94e jwep # Character ì¥
+U+c94f jweh # Character ì¥
+U+c950 jwi # Character ì¥
+U+c951 jwig # Character ì¥
+U+c952 jwikk # Character ì¥
+U+c953 jwigs # Character ì¥
+U+c954 jwin # Character ì¥
+U+c955 jwinj # Character ì¥
+U+c956 jwinh # Character ì¥
+U+c957 jwid # Character ì¥
+U+c958 jwil # Character ì¥
+U+c959 jwilg # Character ì¥
+U+c95a jwilm # Character ì¥
+U+c95b jwilb # Character ì¥
+U+c95c jwils # Character ì¥
+U+c95d jwilt # Character ì¥
+U+c95e jwilp # Character ì¥
+U+c95f jwilh # Character ì¥
+U+c960 jwim # Character ì¥
+U+c961 jwib # Character 쥡
+U+c962 jwibs # Character 쥢
+U+c963 jwis # Character 쥣
+U+c964 jwiss # Character 쥤
+U+c965 jwing # Character 쥥
+U+c966 jwij # Character 쥦
+U+c967 jwich # Character 쥧
+U+c968 jwik # Character 쥨
+U+c969 jwit # Character 쥩
+U+c96a jwip # Character 쥪
+U+c96b jwih # Character 쥫
+U+c96c jyu # Character 쥬
+U+c96d jyug # Character ì¥
+U+c96e jyukk # Character 쥮
+U+c96f jyugs # Character 쥯
+U+c970 jyun # Character 쥰
+U+c971 jyunj # Character 쥱
+U+c972 jyunh # Character 쥲
+U+c973 jyud # Character 쥳
+U+c974 jyul # Character 쥴
+U+c975 jyulg # Character 쥵
+U+c976 jyulm # Character 쥶
+U+c977 jyulb # Character 쥷
+U+c978 jyuls # Character 쥸
+U+c979 jyult # Character 쥹
+U+c97a jyulp # Character 쥺
+U+c97b jyulh # Character 쥻
+U+c97c jyum # Character 쥼
+U+c97d jyub # Character 쥽
+U+c97e jyubs # Character 쥾
+U+c97f jyus # Character 쥿
+U+c980 jyuss # Character ì¦
+U+c981 jyung # Character ì¦
+U+c982 jyuj # Character ì¦
+U+c983 jyuch # Character ì¦
+U+c984 jyuk # Character ì¦
+U+c985 jyut # Character ì¦
+U+c986 jyup # Character ì¦
+U+c987 jyuh # Character ì¦
+U+c988 jeu # Character ì¦
+U+c989 jeug # Character ì¦
+U+c98a jeukk # Character ì¦
+U+c98b jeugs # Character ì¦
+U+c98c jeun # Character ì¦
+U+c98d jeunj # Character ì¦
+U+c98e jeunh # Character ì¦
+U+c98f jeud # Character ì¦
+U+c990 jeul # Character ì¦
+U+c991 jeulg # Character ì¦
+U+c992 jeulm # Character ì¦
+U+c993 jeulb # Character ì¦
+U+c994 jeuls # Character ì¦
+U+c995 jeult # Character ì¦
+U+c996 jeulp # Character ì¦
+U+c997 jeulh # Character ì¦
+U+c998 jeum # Character ì¦
+U+c999 jeub # Character ì¦
+U+c99a jeubs # Character ì¦
+U+c99b jeus # Character ì¦
+U+c99c jeuss # Character ì¦
+U+c99d jeung # Character ì¦
+U+c99e jeuj # Character ì¦
+U+c99f jeuch # Character ì¦
+U+c9a0 jeuk # Character ì¦
+U+c9a1 jeut # Character 즡
+U+c9a2 jeup # Character 즢
+U+c9a3 jeuh # Character 즣
+U+c9a4 jui # Character 즤
+U+c9a5 juig # Character 즥
+U+c9a6 juikk # Character 즦
+U+c9a7 juigs # Character 즧
+U+c9a8 juin # Character 즨
+U+c9a9 juinj # Character 즩
+U+c9aa juinh # Character 즪
+U+c9ab juid # Character 즫
+U+c9ac juil # Character 즬
+U+c9ad juilg # Character ì¦
+U+c9ae juilm # Character 즮
+U+c9af juilb # Character 즯
+U+c9b0 juils # Character 즰
+U+c9b1 juilt # Character 즱
+U+c9b2 juilp # Character 즲
+U+c9b3 juilh # Character 즳
+U+c9b4 juim # Character 즴
+U+c9b5 juib # Character 즵
+U+c9b6 juibs # Character 즶
+U+c9b7 juis # Character 즷
+U+c9b8 juiss # Character 즸
+U+c9b9 juing # Character 즹
+U+c9ba juij # Character 즺
+U+c9bb juich # Character 즻
+U+c9bc juik # Character 즼
+U+c9bd juit # Character 즽
+U+c9be juip # Character 즾
+U+c9bf juih # Character 즿
+U+c9c0 ji # Character ì§
+U+c9c1 jig # Character ì§
+U+c9c2 jikk # Character ì§
+U+c9c3 jigs # Character ì§
+U+c9c4 jin # Character ì§
+U+c9c5 jinj # Character ì§
+U+c9c6 jinh # Character ì§
+U+c9c7 jid # Character ì§
+U+c9c8 jil # Character ì§
+U+c9c9 jilg # Character ì§
+U+c9ca jilm # Character ì§
+U+c9cb jilb # Character ì§
+U+c9cc jils # Character ì§
+U+c9cd jilt # Character ì§
+U+c9ce jilp # Character ì§
+U+c9cf jilh # Character ì§
+U+c9d0 jim # Character ì§
+U+c9d1 jib # Character ì§
+U+c9d2 jibs # Character ì§
+U+c9d3 jis # Character ì§
+U+c9d4 jiss # Character ì§
+U+c9d5 jing # Character ì§
+U+c9d6 jij # Character ì§
+U+c9d7 jich # Character ì§
+U+c9d8 jik # Character ì§
+U+c9d9 jit # Character ì§
+U+c9da jip # Character ì§
+U+c9db jih # Character ì§
+U+c9dc jja # Character ì§
+U+c9dd jjag # Character ì§
+U+c9de jjakk # Character ì§
+U+c9df jjags # Character ì§
+U+c9e0 jjan # Character ì§
+U+c9e1 jjanj # Character 짡
+U+c9e2 jjanh # Character 짢
+U+c9e3 jjad # Character 짣
+U+c9e4 jjal # Character 짤
+U+c9e5 jjalg # Character 짥
+U+c9e6 jjalm # Character 짦
+U+c9e7 jjalb # Character 짧
+U+c9e8 jjals # Character 짨
+U+c9e9 jjalt # Character 짩
+U+c9ea jjalp # Character 짪
+U+c9eb jjalh # Character 짫
+U+c9ec jjam # Character 짬
+U+c9ed jjab # Character ì§
+U+c9ee jjabs # Character 짮
+U+c9ef jjas # Character 짯
+U+c9f0 jjass # Character 짰
+U+c9f1 jjang # Character 짱
+U+c9f2 jjaj # Character 짲
+U+c9f3 jjach # Character 짳
+U+c9f4 jjak # Character 짴
+U+c9f5 jjat # Character 짵
+U+c9f6 jjap # Character 짶
+U+c9f7 jjah # Character 짷
+U+c9f8 jjae # Character 째
+U+c9f9 jjaeg # Character 짹
+U+c9fa jjaekk # Character 짺
+U+c9fb jjaegs # Character 짻
+U+c9fc jjaen # Character 짼
+U+c9fd jjaenj # Character 짽
+U+c9fe jjaenh # Character 짾
+U+c9ff jjaed # Character 짿
diff --git a/resources/chars/latin1/rowca.trans b/resources/chars/latin1/rowca.trans
new file mode 100644
index 0000000..e47c10f
--- /dev/null
+++ b/resources/chars/latin1/rowca.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+ca00 jjael # Character ì¨
+U+ca01 jjaelg # Character ì¨
+U+ca02 jjaelm # Character ì¨
+U+ca03 jjaelb # Character ì¨
+U+ca04 jjaels # Character ì¨
+U+ca05 jjaelt # Character ì¨
+U+ca06 jjaelp # Character ì¨
+U+ca07 jjaelh # Character ì¨
+U+ca08 jjaem # Character ì¨
+U+ca09 jjaeb # Character ì¨
+U+ca0a jjaebs # Character ì¨
+U+ca0b jjaes # Character ì¨
+U+ca0c jjaess # Character ì¨
+U+ca0d jjaeng # Character ì¨
+U+ca0e jjaej # Character ì¨
+U+ca0f jjaech # Character ì¨
+U+ca10 jjaek # Character ì¨
+U+ca11 jjaet # Character ì¨
+U+ca12 jjaep # Character ì¨
+U+ca13 jjaeh # Character ì¨
+U+ca14 jjya # Character ì¨
+U+ca15 jjyag # Character ì¨
+U+ca16 jjyakk # Character ì¨
+U+ca17 jjyags # Character ì¨
+U+ca18 jjyan # Character ì¨
+U+ca19 jjyanj # Character ì¨
+U+ca1a jjyanh # Character ì¨
+U+ca1b jjyad # Character ì¨
+U+ca1c jjyal # Character ì¨
+U+ca1d jjyalg # Character ì¨
+U+ca1e jjyalm # Character ì¨
+U+ca1f jjyalb # Character ì¨
+U+ca20 jjyals # Character ì¨
+U+ca21 jjyalt # Character 쨡
+U+ca22 jjyalp # Character 쨢
+U+ca23 jjyalh # Character 쨣
+U+ca24 jjyam # Character 쨤
+U+ca25 jjyab # Character 쨥
+U+ca26 jjyabs # Character 쨦
+U+ca27 jjyas # Character 쨧
+U+ca28 jjyass # Character 쨨
+U+ca29 jjyang # Character 쨩
+U+ca2a jjyaj # Character 쨪
+U+ca2b jjyach # Character 쨫
+U+ca2c jjyak # Character 쨬
+U+ca2d jjyat # Character ì¨
+U+ca2e jjyap # Character 쨮
+U+ca2f jjyah # Character 쨯
+U+ca30 jjyae # Character 쨰
+U+ca31 jjyaeg # Character 쨱
+U+ca32 jjyaekk # Character 쨲
+U+ca33 jjyaegs # Character 쨳
+U+ca34 jjyaen # Character 쨴
+U+ca35 jjyaenj # Character 쨵
+U+ca36 jjyaenh # Character 쨶
+U+ca37 jjyaed # Character 쨷
+U+ca38 jjyael # Character 쨸
+U+ca39 jjyaelg # Character 쨹
+U+ca3a jjyaelm # Character 쨺
+U+ca3b jjyaelb # Character 쨻
+U+ca3c jjyaels # Character 쨼
+U+ca3d jjyaelt # Character 쨽
+U+ca3e jjyaelp # Character 쨾
+U+ca3f jjyaelh # Character 쨿
+U+ca40 jjyaem # Character ì©
+U+ca41 jjyaeb # Character ì©
+U+ca42 jjyaebs # Character ì©
+U+ca43 jjyaes # Character ì©
+U+ca44 jjyaess # Character ì©
+U+ca45 jjyaeng # Character ì©
+U+ca46 jjyaej # Character ì©
+U+ca47 jjyaech # Character ì©
+U+ca48 jjyaek # Character ì©
+U+ca49 jjyaet # Character ì©
+U+ca4a jjyaep # Character ì©
+U+ca4b jjyaeh # Character ì©
+U+ca4c jjeo # Character ì©
+U+ca4d jjeog # Character ì©
+U+ca4e jjeokk # Character ì©
+U+ca4f jjeogs # Character ì©
+U+ca50 jjeon # Character ì©
+U+ca51 jjeonj # Character ì©
+U+ca52 jjeonh # Character ì©
+U+ca53 jjeod # Character ì©
+U+ca54 jjeol # Character ì©
+U+ca55 jjeolg # Character ì©
+U+ca56 jjeolm # Character ì©
+U+ca57 jjeolb # Character ì©
+U+ca58 jjeols # Character ì©
+U+ca59 jjeolt # Character ì©
+U+ca5a jjeolp # Character ì©
+U+ca5b jjeolh # Character ì©
+U+ca5c jjeom # Character ì©
+U+ca5d jjeob # Character ì©
+U+ca5e jjeobs # Character ì©
+U+ca5f jjeos # Character ì©
+U+ca60 jjeoss # Character ì©
+U+ca61 jjeong # Character ì©¡
+U+ca62 jjeoj # Character ì©¢
+U+ca63 jjeoch # Character ì©£
+U+ca64 jjeok # Character 쩤
+U+ca65 jjeot # Character ì©¥
+U+ca66 jjeop # Character 쩦
+U+ca67 jjeoh # Character 쩧
+U+ca68 jje # Character 쩨
+U+ca69 jjeg # Character ì©©
+U+ca6a jjekk # Character 쩪
+U+ca6b jjegs # Character ì©«
+U+ca6c jjen # Character 쩬
+U+ca6d jjenj # Character ì©
+U+ca6e jjenh # Character ì©®
+U+ca6f jjed # Character 쩯
+U+ca70 jjel # Character ì©°
+U+ca71 jjelg # Character 쩱
+U+ca72 jjelm # Character 쩲
+U+ca73 jjelb # Character 쩳
+U+ca74 jjels # Character ì©´
+U+ca75 jjelt # Character 쩵
+U+ca76 jjelp # Character 쩶
+U+ca77 jjelh # Character ì©·
+U+ca78 jjem # Character 쩸
+U+ca79 jjeb # Character 쩹
+U+ca7a jjebs # Character 쩺
+U+ca7b jjes # Character ì©»
+U+ca7c jjess # Character 쩼
+U+ca7d jjeng # Character 쩽
+U+ca7e jjej # Character 쩾
+U+ca7f jjech # Character ì©¿
+U+ca80 jjek # Character ìª
+U+ca81 jjet # Character ìª
+U+ca82 jjep # Character ìª
+U+ca83 jjeh # Character ìª
+U+ca84 jjyeo # Character ìª
+U+ca85 jjyeog # Character ìª
+U+ca86 jjyeokk # Character ìª
+U+ca87 jjyeogs # Character ìª
+U+ca88 jjyeon # Character ìª
+U+ca89 jjyeonj # Character ìª
+U+ca8a jjyeonh # Character ìª
+U+ca8b jjyeod # Character ìª
+U+ca8c jjyeol # Character ìª
+U+ca8d jjyeolg # Character ìª
+U+ca8e jjyeolm # Character ìª
+U+ca8f jjyeolb # Character ìª
+U+ca90 jjyeols # Character ìª
+U+ca91 jjyeolt # Character ìª
+U+ca92 jjyeolp # Character ìª
+U+ca93 jjyeolh # Character ìª
+U+ca94 jjyeom # Character ìª
+U+ca95 jjyeob # Character ìª
+U+ca96 jjyeobs # Character ìª
+U+ca97 jjyeos # Character ìª
+U+ca98 jjyeoss # Character ìª
+U+ca99 jjyeong # Character ìª
+U+ca9a jjyeoj # Character ìª
+U+ca9b jjyeoch # Character ìª
+U+ca9c jjyeok # Character ìª
+U+ca9d jjyeot # Character ìª
+U+ca9e jjyeop # Character ìª
+U+ca9f jjyeoh # Character ìª
+U+caa0 jjye # Character ìª
+U+caa1 jjyeg # Character 쪡
+U+caa2 jjyekk # Character 쪢
+U+caa3 jjyegs # Character 쪣
+U+caa4 jjyen # Character 쪤
+U+caa5 jjyenj # Character 쪥
+U+caa6 jjyenh # Character 쪦
+U+caa7 jjyed # Character 쪧
+U+caa8 jjyel # Character 쪨
+U+caa9 jjyelg # Character 쪩
+U+caaa jjyelm # Character 쪪
+U+caab jjyelb # Character 쪫
+U+caac jjyels # Character 쪬
+U+caad jjyelt # Character ìª
+U+caae jjyelp # Character 쪮
+U+caaf jjyelh # Character 쪯
+U+cab0 jjyem # Character 쪰
+U+cab1 jjyeb # Character 쪱
+U+cab2 jjyebs # Character 쪲
+U+cab3 jjyes # Character 쪳
+U+cab4 jjyess # Character 쪴
+U+cab5 jjyeng # Character 쪵
+U+cab6 jjyej # Character 쪶
+U+cab7 jjyech # Character 쪷
+U+cab8 jjyek # Character 쪸
+U+cab9 jjyet # Character 쪹
+U+caba jjyep # Character 쪺
+U+cabb jjyeh # Character 쪻
+U+cabc jjo # Character 쪼
+U+cabd jjog # Character 쪽
+U+cabe jjokk # Character 쪾
+U+cabf jjogs # Character 쪿
+U+cac0 jjon # Character ì«
+U+cac1 jjonj # Character ì«
+U+cac2 jjonh # Character ì«
+U+cac3 jjod # Character ì«
+U+cac4 jjol # Character ì«
+U+cac5 jjolg # Character ì«
+U+cac6 jjolm # Character ì«
+U+cac7 jjolb # Character ì«
+U+cac8 jjols # Character ì«
+U+cac9 jjolt # Character ì«
+U+caca jjolp # Character ì«
+U+cacb jjolh # Character ì«
+U+cacc jjom # Character ì«
+U+cacd jjob # Character ì«
+U+cace jjobs # Character ì«
+U+cacf jjos # Character ì«
+U+cad0 jjoss # Character ì«
+U+cad1 jjong # Character ì«
+U+cad2 jjoj # Character ì«
+U+cad3 jjoch # Character ì«
+U+cad4 jjok # Character ì«
+U+cad5 jjot # Character ì«
+U+cad6 jjop # Character ì«
+U+cad7 jjoh # Character ì«
+U+cad8 jjwa # Character ì«
+U+cad9 jjwag # Character ì«
+U+cada jjwakk # Character ì«
+U+cadb jjwags # Character ì«
+U+cadc jjwan # Character ì«
+U+cadd jjwanj # Character ì«
+U+cade jjwanh # Character ì«
+U+cadf jjwad # Character ì«
+U+cae0 jjwal # Character ì«
+U+cae1 jjwalg # Character ì«¡
+U+cae2 jjwalm # Character ì«¢
+U+cae3 jjwalb # Character ì«£
+U+cae4 jjwals # Character 쫤
+U+cae5 jjwalt # Character ì«¥
+U+cae6 jjwalp # Character 쫦
+U+cae7 jjwalh # Character 쫧
+U+cae8 jjwam # Character 쫨
+U+cae9 jjwab # Character ì«©
+U+caea jjwabs # Character 쫪
+U+caeb jjwas # Character ì««
+U+caec jjwass # Character 쫬
+U+caed jjwang # Character ì«
+U+caee jjwaj # Character ì«®
+U+caef jjwach # Character 쫯
+U+caf0 jjwak # Character ì«°
+U+caf1 jjwat # Character 쫱
+U+caf2 jjwap # Character 쫲
+U+caf3 jjwah # Character 쫳
+U+caf4 jjwae # Character ì«´
+U+caf5 jjwaeg # Character 쫵
+U+caf6 jjwaekk # Character 쫶
+U+caf7 jjwaegs # Character ì«·
+U+caf8 jjwaen # Character 쫸
+U+caf9 jjwaenj # Character 쫹
+U+cafa jjwaenh # Character 쫺
+U+cafb jjwaed # Character ì«»
+U+cafc jjwael # Character 쫼
+U+cafd jjwaelg # Character 쫽
+U+cafe jjwaelm # Character 쫾
+U+caff jjwaelb # Character ì«¿
diff --git a/resources/chars/latin1/rowcb.trans b/resources/chars/latin1/rowcb.trans
new file mode 100644
index 0000000..f0b94fe
--- /dev/null
+++ b/resources/chars/latin1/rowcb.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+cb00 jjwaels # Character ì¬
+U+cb01 jjwaelt # Character ì¬
+U+cb02 jjwaelp # Character ì¬
+U+cb03 jjwaelh # Character ì¬
+U+cb04 jjwaem # Character ì¬
+U+cb05 jjwaeb # Character ì¬
+U+cb06 jjwaebs # Character ì¬
+U+cb07 jjwaes # Character ì¬
+U+cb08 jjwaess # Character ì¬
+U+cb09 jjwaeng # Character ì¬
+U+cb0a jjwaej # Character ì¬
+U+cb0b jjwaech # Character ì¬
+U+cb0c jjwaek # Character ì¬
+U+cb0d jjwaet # Character ì¬
+U+cb0e jjwaep # Character ì¬
+U+cb0f jjwaeh # Character ì¬
+U+cb10 jjoe # Character ì¬
+U+cb11 jjoeg # Character ì¬
+U+cb12 jjoekk # Character ì¬
+U+cb13 jjoegs # Character ì¬
+U+cb14 jjoen # Character ì¬
+U+cb15 jjoenj # Character ì¬
+U+cb16 jjoenh # Character ì¬
+U+cb17 jjoed # Character ì¬
+U+cb18 jjoel # Character ì¬
+U+cb19 jjoelg # Character ì¬
+U+cb1a jjoelm # Character ì¬
+U+cb1b jjoelb # Character ì¬
+U+cb1c jjoels # Character ì¬
+U+cb1d jjoelt # Character ì¬
+U+cb1e jjoelp # Character ì¬
+U+cb1f jjoelh # Character ì¬
+U+cb20 jjoem # Character ì¬
+U+cb21 jjoeb # Character 쬡
+U+cb22 jjoebs # Character 쬢
+U+cb23 jjoes # Character 쬣
+U+cb24 jjoess # Character 쬤
+U+cb25 jjoeng # Character 쬥
+U+cb26 jjoej # Character 쬦
+U+cb27 jjoech # Character 쬧
+U+cb28 jjoek # Character 쬨
+U+cb29 jjoet # Character 쬩
+U+cb2a jjoep # Character 쬪
+U+cb2b jjoeh # Character 쬫
+U+cb2c jjyo # Character 쬬
+U+cb2d jjyog # Character ì¬
+U+cb2e jjyokk # Character 쬮
+U+cb2f jjyogs # Character 쬯
+U+cb30 jjyon # Character 쬰
+U+cb31 jjyonj # Character 쬱
+U+cb32 jjyonh # Character 쬲
+U+cb33 jjyod # Character 쬳
+U+cb34 jjyol # Character 쬴
+U+cb35 jjyolg # Character 쬵
+U+cb36 jjyolm # Character 쬶
+U+cb37 jjyolb # Character 쬷
+U+cb38 jjyols # Character 쬸
+U+cb39 jjyolt # Character 쬹
+U+cb3a jjyolp # Character 쬺
+U+cb3b jjyolh # Character 쬻
+U+cb3c jjyom # Character 쬼
+U+cb3d jjyob # Character 쬽
+U+cb3e jjyobs # Character 쬾
+U+cb3f jjyos # Character 쬿
+U+cb40 jjyoss # Character ì
+U+cb41 jjyong # Character ì
+U+cb42 jjyoj # Character ì
+U+cb43 jjyoch # Character ì
+U+cb44 jjyok # Character ì
+U+cb45 jjyot # Character ì
+U+cb46 jjyop # Character ì
+U+cb47 jjyoh # Character ì
+U+cb48 jju # Character ì
+U+cb49 jjug # Character ì
+U+cb4a jjukk # Character ì
+U+cb4b jjugs # Character ì
+U+cb4c jjun # Character ì
+U+cb4d jjunj # Character ì
+U+cb4e jjunh # Character ì
+U+cb4f jjud # Character ì
+U+cb50 jjul # Character ì
+U+cb51 jjulg # Character ì
+U+cb52 jjulm # Character ì
+U+cb53 jjulb # Character ì
+U+cb54 jjuls # Character ì
+U+cb55 jjult # Character ì
+U+cb56 jjulp # Character ì
+U+cb57 jjulh # Character ì
+U+cb58 jjum # Character ì
+U+cb59 jjub # Character ì
+U+cb5a jjubs # Character ì
+U+cb5b jjus # Character ì
+U+cb5c jjuss # Character ì
+U+cb5d jjung # Character ì
+U+cb5e jjuj # Character ì
+U+cb5f jjuch # Character ì
+U+cb60 jjuk # Character ì
+U+cb61 jjut # Character ì¡
+U+cb62 jjup # Character ì¢
+U+cb63 jjuh # Character ì£
+U+cb64 jjwo # Character ì¤
+U+cb65 jjwog # Character ì¥
+U+cb66 jjwokk # Character ì¦
+U+cb67 jjwogs # Character ì§
+U+cb68 jjwon # Character ì¨
+U+cb69 jjwonj # Character ì©
+U+cb6a jjwonh # Character ìª
+U+cb6b jjwod # Character ì«
+U+cb6c jjwol # Character ì¬
+U+cb6d jjwolg # Character ì
+U+cb6e jjwolm # Character ì®
+U+cb6f jjwolb # Character ì¯
+U+cb70 jjwols # Character ì°
+U+cb71 jjwolt # Character ì±
+U+cb72 jjwolp # Character ì²
+U+cb73 jjwolh # Character ì³
+U+cb74 jjwom # Character ì´
+U+cb75 jjwob # Character ìµ
+U+cb76 jjwobs # Character ì¶
+U+cb77 jjwos # Character ì·
+U+cb78 jjwoss # Character ì¸
+U+cb79 jjwong # Character ì¹
+U+cb7a jjwoj # Character ìº
+U+cb7b jjwoch # Character ì»
+U+cb7c jjwok # Character ì¼
+U+cb7d jjwot # Character ì½
+U+cb7e jjwop # Character ì¾
+U+cb7f jjwoh # Character ì¿
+U+cb80 jjwe # Character ì®
+U+cb81 jjweg # Character ì®
+U+cb82 jjwekk # Character ì®
+U+cb83 jjwegs # Character ì®
+U+cb84 jjwen # Character ì®
+U+cb85 jjwenj # Character ì®
+U+cb86 jjwenh # Character ì®
+U+cb87 jjwed # Character ì®
+U+cb88 jjwel # Character ì®
+U+cb89 jjwelg # Character ì®
+U+cb8a jjwelm # Character ì®
+U+cb8b jjwelb # Character ì®
+U+cb8c jjwels # Character ì®
+U+cb8d jjwelt # Character ì®
+U+cb8e jjwelp # Character ì®
+U+cb8f jjwelh # Character ì®
+U+cb90 jjwem # Character ì®
+U+cb91 jjweb # Character ì®
+U+cb92 jjwebs # Character ì®
+U+cb93 jjwes # Character ì®
+U+cb94 jjwess # Character ì®
+U+cb95 jjweng # Character ì®
+U+cb96 jjwej # Character ì®
+U+cb97 jjwech # Character ì®
+U+cb98 jjwek # Character ì®
+U+cb99 jjwet # Character ì®
+U+cb9a jjwep # Character ì®
+U+cb9b jjweh # Character ì®
+U+cb9c jjwi # Character ì®
+U+cb9d jjwig # Character ì®
+U+cb9e jjwikk # Character ì®
+U+cb9f jjwigs # Character ì®
+U+cba0 jjwin # Character ì®
+U+cba1 jjwinj # Character 쮡
+U+cba2 jjwinh # Character 쮢
+U+cba3 jjwid # Character 쮣
+U+cba4 jjwil # Character 쮤
+U+cba5 jjwilg # Character 쮥
+U+cba6 jjwilm # Character 쮦
+U+cba7 jjwilb # Character 쮧
+U+cba8 jjwils # Character 쮨
+U+cba9 jjwilt # Character 쮩
+U+cbaa jjwilp # Character 쮪
+U+cbab jjwilh # Character 쮫
+U+cbac jjwim # Character 쮬
+U+cbad jjwib # Character ì®
+U+cbae jjwibs # Character ì®®
+U+cbaf jjwis # Character 쮯
+U+cbb0 jjwiss # Character ì®°
+U+cbb1 jjwing # Character ì®±
+U+cbb2 jjwij # Character 쮲
+U+cbb3 jjwich # Character 쮳
+U+cbb4 jjwik # Character ì®´
+U+cbb5 jjwit # Character 쮵
+U+cbb6 jjwip # Character 쮶
+U+cbb7 jjwih # Character ì®·
+U+cbb8 jjyu # Character 쮸
+U+cbb9 jjyug # Character 쮹
+U+cbba jjyukk # Character 쮺
+U+cbbb jjyugs # Character ì®»
+U+cbbc jjyun # Character 쮼
+U+cbbd jjyunj # Character 쮽
+U+cbbe jjyunh # Character 쮾
+U+cbbf jjyud # Character 쮿
+U+cbc0 jjyul # Character ì¯
+U+cbc1 jjyulg # Character ì¯
+U+cbc2 jjyulm # Character ì¯
+U+cbc3 jjyulb # Character ì¯
+U+cbc4 jjyuls # Character ì¯
+U+cbc5 jjyult # Character ì¯
+U+cbc6 jjyulp # Character ì¯
+U+cbc7 jjyulh # Character ì¯
+U+cbc8 jjyum # Character ì¯
+U+cbc9 jjyub # Character ì¯
+U+cbca jjyubs # Character ì¯
+U+cbcb jjyus # Character ì¯
+U+cbcc jjyuss # Character ì¯
+U+cbcd jjyung # Character ì¯
+U+cbce jjyuj # Character ì¯
+U+cbcf jjyuch # Character ì¯
+U+cbd0 jjyuk # Character ì¯
+U+cbd1 jjyut # Character ì¯
+U+cbd2 jjyup # Character ì¯
+U+cbd3 jjyuh # Character ì¯
+U+cbd4 jjeu # Character ì¯
+U+cbd5 jjeug # Character ì¯
+U+cbd6 jjeukk # Character ì¯
+U+cbd7 jjeugs # Character ì¯
+U+cbd8 jjeun # Character ì¯
+U+cbd9 jjeunj # Character ì¯
+U+cbda jjeunh # Character ì¯
+U+cbdb jjeud # Character ì¯
+U+cbdc jjeul # Character ì¯
+U+cbdd jjeulg # Character ì¯
+U+cbde jjeulm # Character ì¯
+U+cbdf jjeulb # Character ì¯
+U+cbe0 jjeuls # Character ì¯
+U+cbe1 jjeult # Character 쯡
+U+cbe2 jjeulp # Character 쯢
+U+cbe3 jjeulh # Character 쯣
+U+cbe4 jjeum # Character 쯤
+U+cbe5 jjeub # Character 쯥
+U+cbe6 jjeubs # Character 쯦
+U+cbe7 jjeus # Character 쯧
+U+cbe8 jjeuss # Character 쯨
+U+cbe9 jjeung # Character 쯩
+U+cbea jjeuj # Character 쯪
+U+cbeb jjeuch # Character 쯫
+U+cbec jjeuk # Character 쯬
+U+cbed jjeut # Character ì¯
+U+cbee jjeup # Character 쯮
+U+cbef jjeuh # Character 쯯
+U+cbf0 jjui # Character 쯰
+U+cbf1 jjuig # Character 쯱
+U+cbf2 jjuikk # Character 쯲
+U+cbf3 jjuigs # Character 쯳
+U+cbf4 jjuin # Character 쯴
+U+cbf5 jjuinj # Character 쯵
+U+cbf6 jjuinh # Character 쯶
+U+cbf7 jjuid # Character 쯷
+U+cbf8 jjuil # Character 쯸
+U+cbf9 jjuilg # Character 쯹
+U+cbfa jjuilm # Character 쯺
+U+cbfb jjuilb # Character 쯻
+U+cbfc jjuils # Character 쯼
+U+cbfd jjuilt # Character 쯽
+U+cbfe jjuilp # Character 쯾
+U+cbff jjuilh # Character 쯿
diff --git a/resources/chars/latin1/rowcc.trans b/resources/chars/latin1/rowcc.trans
new file mode 100644
index 0000000..5d3b569
--- /dev/null
+++ b/resources/chars/latin1/rowcc.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+cc00 jjuim # Character ì°
+U+cc01 jjuib # Character ì°
+U+cc02 jjuibs # Character ì°
+U+cc03 jjuis # Character ì°
+U+cc04 jjuiss # Character ì°
+U+cc05 jjuing # Character ì°
+U+cc06 jjuij # Character ì°
+U+cc07 jjuich # Character ì°
+U+cc08 jjuik # Character ì°
+U+cc09 jjuit # Character ì°
+U+cc0a jjuip # Character ì°
+U+cc0b jjuih # Character ì°
+U+cc0c jji # Character ì°
+U+cc0d jjig # Character ì°
+U+cc0e jjikk # Character ì°
+U+cc0f jjigs # Character ì°
+U+cc10 jjin # Character ì°
+U+cc11 jjinj # Character ì°
+U+cc12 jjinh # Character ì°
+U+cc13 jjid # Character ì°
+U+cc14 jjil # Character ì°
+U+cc15 jjilg # Character ì°
+U+cc16 jjilm # Character ì°
+U+cc17 jjilb # Character ì°
+U+cc18 jjils # Character ì°
+U+cc19 jjilt # Character ì°
+U+cc1a jjilp # Character ì°
+U+cc1b jjilh # Character ì°
+U+cc1c jjim # Character ì°
+U+cc1d jjib # Character ì°
+U+cc1e jjibs # Character ì°
+U+cc1f jjis # Character ì°
+U+cc20 jjiss # Character ì°
+U+cc21 jjing # Character ì°¡
+U+cc22 jjij # Character ì°¢
+U+cc23 jjich # Character ì°£
+U+cc24 jjik # Character ì°¤
+U+cc25 jjit # Character ì°¥
+U+cc26 jjip # Character ì°¦
+U+cc27 jjih # Character ì°§
+U+cc28 cha # Character ì°¨
+U+cc29 chag # Character ì°©
+U+cc2a chakk # Character ì°ª
+U+cc2b chags # Character ì°«
+U+cc2c chan # Character ì°¬
+U+cc2d chanj # Character ì°
+U+cc2e chanh # Character ì°®
+U+cc2f chad # Character ì°¯
+U+cc30 chal # Character ì°°
+U+cc31 chalg # Character ì°±
+U+cc32 chalm # Character ì°²
+U+cc33 chalb # Character ì°³
+U+cc34 chals # Character ì°´
+U+cc35 chalt # Character ì°µ
+U+cc36 chalp # Character ì°¶
+U+cc37 chalh # Character ì°·
+U+cc38 cham # Character ì°¸
+U+cc39 chab # Character ì°¹
+U+cc3a chabs # Character ì°º
+U+cc3b chas # Character ì°»
+U+cc3c chass # Character ì°¼
+U+cc3d chang # Character ì°½
+U+cc3e chaj # Character ì°¾
+U+cc3f chach # Character ì°¿
+U+cc40 chak # Character ì±
+U+cc41 chat # Character ì±
+U+cc42 chap # Character ì±
+U+cc43 chah # Character ì±
+U+cc44 chae # Character ì±
+U+cc45 chaeg # Character ì±
+U+cc46 chaekk # Character ì±
+U+cc47 chaegs # Character ì±
+U+cc48 chaen # Character ì±
+U+cc49 chaenj # Character ì±
+U+cc4a chaenh # Character ì±
+U+cc4b chaed # Character ì±
+U+cc4c chael # Character ì±
+U+cc4d chaelg # Character ì±
+U+cc4e chaelm # Character ì±
+U+cc4f chaelb # Character ì±
+U+cc50 chaels # Character ì±
+U+cc51 chaelt # Character ì±
+U+cc52 chaelp # Character ì±
+U+cc53 chaelh # Character ì±
+U+cc54 chaem # Character ì±
+U+cc55 chaeb # Character ì±
+U+cc56 chaebs # Character ì±
+U+cc57 chaes # Character ì±
+U+cc58 chaess # Character ì±
+U+cc59 chaeng # Character ì±
+U+cc5a chaej # Character ì±
+U+cc5b chaech # Character ì±
+U+cc5c chaek # Character ì±
+U+cc5d chaet # Character ì±
+U+cc5e chaep # Character ì±
+U+cc5f chaeh # Character ì±
+U+cc60 chya # Character ì±
+U+cc61 chyag # Character 챡
+U+cc62 chyakk # Character ì±¢
+U+cc63 chyags # Character ì±£
+U+cc64 chyan # Character 챤
+U+cc65 chyanj # Character ì±¥
+U+cc66 chyanh # Character 챦
+U+cc67 chyad # Character 챧
+U+cc68 chyal # Character 챨
+U+cc69 chyalg # Character 챩
+U+cc6a chyalm # Character 챪
+U+cc6b chyalb # Character 챫
+U+cc6c chyals # Character 챬
+U+cc6d chyalt # Character ì±
+U+cc6e chyalp # Character ì±®
+U+cc6f chyalh # Character 챯
+U+cc70 chyam # Character ì±°
+U+cc71 chyab # Character ì±±
+U+cc72 chyabs # Character ì±²
+U+cc73 chyas # Character ì±³
+U+cc74 chyass # Character ì±´
+U+cc75 chyang # Character ì±µ
+U+cc76 chyaj # Character 챶
+U+cc77 chyach # Character ì±·
+U+cc78 chyak # Character 챸
+U+cc79 chyat # Character ì±¹
+U+cc7a chyap # Character 챺
+U+cc7b chyah # Character ì±»
+U+cc7c chyae # Character ì±¼
+U+cc7d chyaeg # Character ì±½
+U+cc7e chyaekk # Character ì±¾
+U+cc7f chyaegs # Character 챿
+U+cc80 chyaen # Character ì²
+U+cc81 chyaenj # Character ì²
+U+cc82 chyaenh # Character ì²
+U+cc83 chyaed # Character ì²
+U+cc84 chyael # Character ì²
+U+cc85 chyaelg # Character ì²
+U+cc86 chyaelm # Character ì²
+U+cc87 chyaelb # Character ì²
+U+cc88 chyaels # Character ì²
+U+cc89 chyaelt # Character ì²
+U+cc8a chyaelp # Character ì²
+U+cc8b chyaelh # Character ì²
+U+cc8c chyaem # Character ì²
+U+cc8d chyaeb # Character ì²
+U+cc8e chyaebs # Character ì²
+U+cc8f chyaes # Character ì²
+U+cc90 chyaess # Character ì²
+U+cc91 chyaeng # Character ì²
+U+cc92 chyaej # Character ì²
+U+cc93 chyaech # Character ì²
+U+cc94 chyaek # Character ì²
+U+cc95 chyaet # Character ì²
+U+cc96 chyaep # Character ì²
+U+cc97 chyaeh # Character ì²
+U+cc98 cheo # Character ì²
+U+cc99 cheog # Character ì²
+U+cc9a cheokk # Character ì²
+U+cc9b cheogs # Character ì²
+U+cc9c cheon # Character ì²
+U+cc9d cheonj # Character ì²
+U+cc9e cheonh # Character ì²
+U+cc9f cheod # Character ì²
+U+cca0 cheol # Character ì²
+U+cca1 cheolg # Character 첡
+U+cca2 cheolm # Character ì²¢
+U+cca3 cheolb # Character ì²£
+U+cca4 cheols # Character 첤
+U+cca5 cheolt # Character ì²¥
+U+cca6 cheolp # Character 첦
+U+cca7 cheolh # Character 첧
+U+cca8 cheom # Character 첨
+U+cca9 cheob # Character 첩
+U+ccaa cheobs # Character 첪
+U+ccab cheos # Character 첫
+U+ccac cheoss # Character 첬
+U+ccad cheong # Character ì²
+U+ccae cheoj # Character ì²®
+U+ccaf cheoch # Character 첯
+U+ccb0 cheok # Character ì²°
+U+ccb1 cheot # Character ì²±
+U+ccb2 cheop # Character ì²²
+U+ccb3 cheoh # Character ì²³
+U+ccb4 che # Character ì²´
+U+ccb5 cheg # Character ì²µ
+U+ccb6 chekk # Character 첶
+U+ccb7 chegs # Character ì²·
+U+ccb8 chen # Character 첸
+U+ccb9 chenj # Character ì²¹
+U+ccba chenh # Character 첺
+U+ccbb ched # Character ì²»
+U+ccbc chel # Character ì²¼
+U+ccbd chelg # Character ì²½
+U+ccbe chelm # Character ì²¾
+U+ccbf chelb # Character 첿
+U+ccc0 chels # Character ì³
+U+ccc1 chelt # Character ì³
+U+ccc2 chelp # Character ì³
+U+ccc3 chelh # Character ì³
+U+ccc4 chem # Character ì³
+U+ccc5 cheb # Character ì³
+U+ccc6 chebs # Character ì³
+U+ccc7 ches # Character ì³
+U+ccc8 chess # Character ì³
+U+ccc9 cheng # Character ì³
+U+ccca chej # Character ì³
+U+cccb chech # Character ì³
+U+cccc chek # Character ì³
+U+cccd chet # Character ì³
+U+ccce chep # Character ì³
+U+cccf cheh # Character ì³
+U+ccd0 chyeo # Character ì³
+U+ccd1 chyeog # Character ì³
+U+ccd2 chyeokk # Character ì³
+U+ccd3 chyeogs # Character ì³
+U+ccd4 chyeon # Character ì³
+U+ccd5 chyeonj # Character ì³
+U+ccd6 chyeonh # Character ì³
+U+ccd7 chyeod # Character ì³
+U+ccd8 chyeol # Character ì³
+U+ccd9 chyeolg # Character ì³
+U+ccda chyeolm # Character ì³
+U+ccdb chyeolb # Character ì³
+U+ccdc chyeols # Character ì³
+U+ccdd chyeolt # Character ì³
+U+ccde chyeolp # Character ì³
+U+ccdf chyeolh # Character ì³
+U+cce0 chyeom # Character ì³
+U+cce1 chyeob # Character 쳡
+U+cce2 chyeobs # Character ì³¢
+U+cce3 chyeos # Character ì³£
+U+cce4 chyeoss # Character 쳤
+U+cce5 chyeong # Character ì³¥
+U+cce6 chyeoj # Character 쳦
+U+cce7 chyeoch # Character 쳧
+U+cce8 chyeok # Character 쳨
+U+cce9 chyeot # Character 쳩
+U+ccea chyeop # Character 쳪
+U+cceb chyeoh # Character 쳫
+U+ccec chye # Character 쳬
+U+cced chyeg # Character ì³
+U+ccee chyekk # Character ì³®
+U+ccef chyegs # Character 쳯
+U+ccf0 chyen # Character ì³°
+U+ccf1 chyenj # Character ì³±
+U+ccf2 chyenh # Character ì³²
+U+ccf3 chyed # Character ì³³
+U+ccf4 chyel # Character ì³´
+U+ccf5 chyelg # Character ì³µ
+U+ccf6 chyelm # Character 쳶
+U+ccf7 chyelb # Character ì³·
+U+ccf8 chyels # Character 쳸
+U+ccf9 chyelt # Character ì³¹
+U+ccfa chyelp # Character 쳺
+U+ccfb chyelh # Character ì³»
+U+ccfc chyem # Character ì³¼
+U+ccfd chyeb # Character ì³½
+U+ccfe chyebs # Character ì³¾
+U+ccff chyes # Character 쳿
diff --git a/resources/chars/latin1/rowcd.trans b/resources/chars/latin1/rowcd.trans
new file mode 100644
index 0000000..509a9f8
--- /dev/null
+++ b/resources/chars/latin1/rowcd.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+cd00 chyess # Character ì´
+U+cd01 chyeng # Character ì´
+U+cd02 chyej # Character ì´
+U+cd03 chyech # Character ì´
+U+cd04 chyek # Character ì´
+U+cd05 chyet # Character ì´
+U+cd06 chyep # Character ì´
+U+cd07 chyeh # Character ì´
+U+cd08 cho # Character ì´
+U+cd09 chog # Character ì´
+U+cd0a chokk # Character ì´
+U+cd0b chogs # Character ì´
+U+cd0c chon # Character ì´
+U+cd0d chonj # Character ì´
+U+cd0e chonh # Character ì´
+U+cd0f chod # Character ì´
+U+cd10 chol # Character ì´
+U+cd11 cholg # Character ì´
+U+cd12 cholm # Character ì´
+U+cd13 cholb # Character ì´
+U+cd14 chols # Character ì´
+U+cd15 cholt # Character ì´
+U+cd16 cholp # Character ì´
+U+cd17 cholh # Character ì´
+U+cd18 chom # Character ì´
+U+cd19 chob # Character ì´
+U+cd1a chobs # Character ì´
+U+cd1b chos # Character ì´
+U+cd1c choss # Character ì´
+U+cd1d chong # Character ì´
+U+cd1e choj # Character ì´
+U+cd1f choch # Character ì´
+U+cd20 chok # Character ì´
+U+cd21 chot # Character ì´¡
+U+cd22 chop # Character ì´¢
+U+cd23 choh # Character ì´£
+U+cd24 chwa # Character ì´¤
+U+cd25 chwag # Character ì´¥
+U+cd26 chwakk # Character ì´¦
+U+cd27 chwags # Character ì´§
+U+cd28 chwan # Character ì´¨
+U+cd29 chwanj # Character ì´©
+U+cd2a chwanh # Character ì´ª
+U+cd2b chwad # Character ì´«
+U+cd2c chwal # Character ì´¬
+U+cd2d chwalg # Character ì´
+U+cd2e chwalm # Character ì´®
+U+cd2f chwalb # Character ì´¯
+U+cd30 chwals # Character ì´°
+U+cd31 chwalt # Character ì´±
+U+cd32 chwalp # Character ì´²
+U+cd33 chwalh # Character ì´³
+U+cd34 chwam # Character ì´´
+U+cd35 chwab # Character ì´µ
+U+cd36 chwabs # Character ì´¶
+U+cd37 chwas # Character ì´·
+U+cd38 chwass # Character ì´¸
+U+cd39 chwang # Character ì´¹
+U+cd3a chwaj # Character ì´º
+U+cd3b chwach # Character ì´»
+U+cd3c chwak # Character ì´¼
+U+cd3d chwat # Character ì´½
+U+cd3e chwap # Character ì´¾
+U+cd3f chwah # Character ì´¿
+U+cd40 chwae # Character ìµ
+U+cd41 chwaeg # Character ìµ
+U+cd42 chwaekk # Character ìµ
+U+cd43 chwaegs # Character ìµ
+U+cd44 chwaen # Character ìµ
+U+cd45 chwaenj # Character ìµ
+U+cd46 chwaenh # Character ìµ
+U+cd47 chwaed # Character ìµ
+U+cd48 chwael # Character ìµ
+U+cd49 chwaelg # Character ìµ
+U+cd4a chwaelm # Character ìµ
+U+cd4b chwaelb # Character ìµ
+U+cd4c chwaels # Character ìµ
+U+cd4d chwaelt # Character ìµ
+U+cd4e chwaelp # Character ìµ
+U+cd4f chwaelh # Character ìµ
+U+cd50 chwaem # Character ìµ
+U+cd51 chwaeb # Character ìµ
+U+cd52 chwaebs # Character ìµ
+U+cd53 chwaes # Character ìµ
+U+cd54 chwaess # Character ìµ
+U+cd55 chwaeng # Character ìµ
+U+cd56 chwaej # Character ìµ
+U+cd57 chwaech # Character ìµ
+U+cd58 chwaek # Character ìµ
+U+cd59 chwaet # Character ìµ
+U+cd5a chwaep # Character ìµ
+U+cd5b chwaeh # Character ìµ
+U+cd5c choe # Character ìµ
+U+cd5d choeg # Character ìµ
+U+cd5e choekk # Character ìµ
+U+cd5f choegs # Character ìµ
+U+cd60 choen # Character ìµ
+U+cd61 choenj # Character 쵡
+U+cd62 choenh # Character ìµ¢
+U+cd63 choed # Character ìµ£
+U+cd64 choel # Character 쵤
+U+cd65 choelg # Character ìµ¥
+U+cd66 choelm # Character 쵦
+U+cd67 choelb # Character 쵧
+U+cd68 choels # Character 쵨
+U+cd69 choelt # Character 쵩
+U+cd6a choelp # Character 쵪
+U+cd6b choelh # Character 쵫
+U+cd6c choem # Character 쵬
+U+cd6d choeb # Character ìµ
+U+cd6e choebs # Character ìµ®
+U+cd6f choes # Character 쵯
+U+cd70 choess # Character ìµ°
+U+cd71 choeng # Character ìµ±
+U+cd72 choej # Character ìµ²
+U+cd73 choech # Character ìµ³
+U+cd74 choek # Character ìµ´
+U+cd75 choet # Character ìµµ
+U+cd76 choep # Character 쵶
+U+cd77 choeh # Character ìµ·
+U+cd78 chyo # Character 쵸
+U+cd79 chyog # Character ìµ¹
+U+cd7a chyokk # Character 쵺
+U+cd7b chyogs # Character ìµ»
+U+cd7c chyon # Character ìµ¼
+U+cd7d chyonj # Character ìµ½
+U+cd7e chyonh # Character ìµ¾
+U+cd7f chyod # Character 쵿
+U+cd80 chyol # Character ì¶
+U+cd81 chyolg # Character ì¶
+U+cd82 chyolm # Character ì¶
+U+cd83 chyolb # Character ì¶
+U+cd84 chyols # Character ì¶
+U+cd85 chyolt # Character ì¶
+U+cd86 chyolp # Character ì¶
+U+cd87 chyolh # Character ì¶
+U+cd88 chyom # Character ì¶
+U+cd89 chyob # Character ì¶
+U+cd8a chyobs # Character ì¶
+U+cd8b chyos # Character ì¶
+U+cd8c chyoss # Character ì¶
+U+cd8d chyong # Character ì¶
+U+cd8e chyoj # Character ì¶
+U+cd8f chyoch # Character ì¶
+U+cd90 chyok # Character ì¶
+U+cd91 chyot # Character ì¶
+U+cd92 chyop # Character ì¶
+U+cd93 chyoh # Character ì¶
+U+cd94 chu # Character ì¶
+U+cd95 chug # Character ì¶
+U+cd96 chukk # Character ì¶
+U+cd97 chugs # Character ì¶
+U+cd98 chun # Character ì¶
+U+cd99 chunj # Character ì¶
+U+cd9a chunh # Character ì¶
+U+cd9b chud # Character ì¶
+U+cd9c chul # Character ì¶
+U+cd9d chulg # Character ì¶
+U+cd9e chulm # Character ì¶
+U+cd9f chulb # Character ì¶
+U+cda0 chuls # Character ì¶
+U+cda1 chult # Character 춡
+U+cda2 chulp # Character 춢
+U+cda3 chulh # Character 춣
+U+cda4 chum # Character 춤
+U+cda5 chub # Character 춥
+U+cda6 chubs # Character 춦
+U+cda7 chus # Character 춧
+U+cda8 chuss # Character 춨
+U+cda9 chung # Character 충
+U+cdaa chuj # Character 춪
+U+cdab chuch # Character 춫
+U+cdac chuk # Character 춬
+U+cdad chut # Character ì¶
+U+cdae chup # Character 춮
+U+cdaf chuh # Character 춯
+U+cdb0 chwo # Character 춰
+U+cdb1 chwog # Character 춱
+U+cdb2 chwokk # Character 춲
+U+cdb3 chwogs # Character 춳
+U+cdb4 chwon # Character 춴
+U+cdb5 chwonj # Character 춵
+U+cdb6 chwonh # Character 춶
+U+cdb7 chwod # Character 춷
+U+cdb8 chwol # Character 춸
+U+cdb9 chwolg # Character 춹
+U+cdba chwolm # Character 춺
+U+cdbb chwolb # Character 춻
+U+cdbc chwols # Character 춼
+U+cdbd chwolt # Character 춽
+U+cdbe chwolp # Character 춾
+U+cdbf chwolh # Character 춿
+U+cdc0 chwom # Character ì·
+U+cdc1 chwob # Character ì·
+U+cdc2 chwobs # Character ì·
+U+cdc3 chwos # Character ì·
+U+cdc4 chwoss # Character ì·
+U+cdc5 chwong # Character ì·
+U+cdc6 chwoj # Character ì·
+U+cdc7 chwoch # Character ì·
+U+cdc8 chwok # Character ì·
+U+cdc9 chwot # Character ì·
+U+cdca chwop # Character ì·
+U+cdcb chwoh # Character ì·
+U+cdcc chwe # Character ì·
+U+cdcd chweg # Character ì·
+U+cdce chwekk # Character ì·
+U+cdcf chwegs # Character ì·
+U+cdd0 chwen # Character ì·
+U+cdd1 chwenj # Character ì·
+U+cdd2 chwenh # Character ì·
+U+cdd3 chwed # Character ì·
+U+cdd4 chwel # Character ì·
+U+cdd5 chwelg # Character ì·
+U+cdd6 chwelm # Character ì·
+U+cdd7 chwelb # Character ì·
+U+cdd8 chwels # Character ì·
+U+cdd9 chwelt # Character ì·
+U+cdda chwelp # Character ì·
+U+cddb chwelh # Character ì·
+U+cddc chwem # Character ì·
+U+cddd chweb # Character ì·
+U+cdde chwebs # Character ì·
+U+cddf chwes # Character ì·
+U+cde0 chwess # Character ì·
+U+cde1 chweng # Character ì·¡
+U+cde2 chwej # Character ì·¢
+U+cde3 chwech # Character ì·£
+U+cde4 chwek # Character ì·¤
+U+cde5 chwet # Character ì·¥
+U+cde6 chwep # Character ì·¦
+U+cde7 chweh # Character ì·§
+U+cde8 chwi # Character ì·¨
+U+cde9 chwig # Character ì·©
+U+cdea chwikk # Character ì·ª
+U+cdeb chwigs # Character ì·«
+U+cdec chwin # Character ì·¬
+U+cded chwinj # Character ì·
+U+cdee chwinh # Character ì·®
+U+cdef chwid # Character ì·¯
+U+cdf0 chwil # Character ì·°
+U+cdf1 chwilg # Character ì·±
+U+cdf2 chwilm # Character ì·²
+U+cdf3 chwilb # Character ì·³
+U+cdf4 chwils # Character ì·´
+U+cdf5 chwilt # Character ì·µ
+U+cdf6 chwilp # Character ì·¶
+U+cdf7 chwilh # Character ì··
+U+cdf8 chwim # Character ì·¸
+U+cdf9 chwib # Character ì·¹
+U+cdfa chwibs # Character ì·º
+U+cdfb chwis # Character ì·»
+U+cdfc chwiss # Character ì·¼
+U+cdfd chwing # Character ì·½
+U+cdfe chwij # Character ì·¾
+U+cdff chwich # Character ì·¿
diff --git a/resources/chars/latin1/rowce.trans b/resources/chars/latin1/rowce.trans
new file mode 100644
index 0000000..bee8d75
--- /dev/null
+++ b/resources/chars/latin1/rowce.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+ce00 chwik # Character ì¸
+U+ce01 chwit # Character ì¸
+U+ce02 chwip # Character ì¸
+U+ce03 chwih # Character ì¸
+U+ce04 chyu # Character ì¸
+U+ce05 chyug # Character ì¸
+U+ce06 chyukk # Character ì¸
+U+ce07 chyugs # Character ì¸
+U+ce08 chyun # Character ì¸
+U+ce09 chyunj # Character ì¸
+U+ce0a chyunh # Character ì¸
+U+ce0b chyud # Character ì¸
+U+ce0c chyul # Character ì¸
+U+ce0d chyulg # Character ì¸
+U+ce0e chyulm # Character ì¸
+U+ce0f chyulb # Character ì¸
+U+ce10 chyuls # Character ì¸
+U+ce11 chyult # Character ì¸
+U+ce12 chyulp # Character ì¸
+U+ce13 chyulh # Character ì¸
+U+ce14 chyum # Character ì¸
+U+ce15 chyub # Character ì¸
+U+ce16 chyubs # Character ì¸
+U+ce17 chyus # Character ì¸
+U+ce18 chyuss # Character ì¸
+U+ce19 chyung # Character ì¸
+U+ce1a chyuj # Character ì¸
+U+ce1b chyuch # Character ì¸
+U+ce1c chyuk # Character ì¸
+U+ce1d chyut # Character ì¸
+U+ce1e chyup # Character ì¸
+U+ce1f chyuh # Character ì¸
+U+ce20 cheu # Character ì¸
+U+ce21 cheug # Character 측
+U+ce22 cheukk # Character 츢
+U+ce23 cheugs # Character 츣
+U+ce24 cheun # Character 츤
+U+ce25 cheunj # Character 츥
+U+ce26 cheunh # Character 츦
+U+ce27 cheud # Character 츧
+U+ce28 cheul # Character 츨
+U+ce29 cheulg # Character 츩
+U+ce2a cheulm # Character 츪
+U+ce2b cheulb # Character 츫
+U+ce2c cheuls # Character 츬
+U+ce2d cheult # Character ì¸
+U+ce2e cheulp # Character 츮
+U+ce2f cheulh # Character 츯
+U+ce30 cheum # Character 츰
+U+ce31 cheub # Character 츱
+U+ce32 cheubs # Character 츲
+U+ce33 cheus # Character 츳
+U+ce34 cheuss # Character 츴
+U+ce35 cheung # Character 층
+U+ce36 cheuj # Character 츶
+U+ce37 cheuch # Character 츷
+U+ce38 cheuk # Character 츸
+U+ce39 cheut # Character 츹
+U+ce3a cheup # Character 츺
+U+ce3b cheuh # Character 츻
+U+ce3c chui # Character 츼
+U+ce3d chuig # Character 츽
+U+ce3e chuikk # Character 츾
+U+ce3f chuigs # Character 츿
+U+ce40 chuin # Character ì¹
+U+ce41 chuinj # Character ì¹
+U+ce42 chuinh # Character ì¹
+U+ce43 chuid # Character ì¹
+U+ce44 chuil # Character ì¹
+U+ce45 chuilg # Character ì¹
+U+ce46 chuilm # Character ì¹
+U+ce47 chuilb # Character ì¹
+U+ce48 chuils # Character ì¹
+U+ce49 chuilt # Character ì¹
+U+ce4a chuilp # Character ì¹
+U+ce4b chuilh # Character ì¹
+U+ce4c chuim # Character ì¹
+U+ce4d chuib # Character ì¹
+U+ce4e chuibs # Character ì¹
+U+ce4f chuis # Character ì¹
+U+ce50 chuiss # Character ì¹
+U+ce51 chuing # Character ì¹
+U+ce52 chuij # Character ì¹
+U+ce53 chuich # Character ì¹
+U+ce54 chuik # Character ì¹
+U+ce55 chuit # Character ì¹
+U+ce56 chuip # Character ì¹
+U+ce57 chuih # Character ì¹
+U+ce58 chi # Character ì¹
+U+ce59 chig # Character ì¹
+U+ce5a chikk # Character ì¹
+U+ce5b chigs # Character ì¹
+U+ce5c chin # Character ì¹
+U+ce5d chinj # Character ì¹
+U+ce5e chinh # Character ì¹
+U+ce5f chid # Character ì¹
+U+ce60 chil # Character ì¹
+U+ce61 chilg # Character 칡
+U+ce62 chilm # Character ì¹¢
+U+ce63 chilb # Character ì¹£
+U+ce64 chils # Character 칤
+U+ce65 chilt # Character ì¹¥
+U+ce66 chilp # Character 칦
+U+ce67 chilh # Character 칧
+U+ce68 chim # Character 침
+U+ce69 chib # Character 칩
+U+ce6a chibs # Character 칪
+U+ce6b chis # Character 칫
+U+ce6c chiss # Character 칬
+U+ce6d ching # Character ì¹
+U+ce6e chij # Character ì¹®
+U+ce6f chich # Character 칯
+U+ce70 chik # Character ì¹°
+U+ce71 chit # Character ì¹±
+U+ce72 chip # Character ì¹²
+U+ce73 chih # Character ì¹³
+U+ce74 ka # Character ì¹´
+U+ce75 kag # Character ì¹µ
+U+ce76 kakk # Character 칶
+U+ce77 kags # Character ì¹·
+U+ce78 kan # Character 칸
+U+ce79 kanj # Character ì¹¹
+U+ce7a kanh # Character 칺
+U+ce7b kad # Character ì¹»
+U+ce7c kal # Character ì¹¼
+U+ce7d kalg # Character ì¹½
+U+ce7e kalm # Character ì¹¾
+U+ce7f kalb # Character 칿
+U+ce80 kals # Character ìº
+U+ce81 kalt # Character ìº
+U+ce82 kalp # Character ìº
+U+ce83 kalh # Character ìº
+U+ce84 kam # Character ìº
+U+ce85 kab # Character ìº
+U+ce86 kabs # Character ìº
+U+ce87 kas # Character ìº
+U+ce88 kass # Character ìº
+U+ce89 kang # Character ìº
+U+ce8a kaj # Character ìº
+U+ce8b kach # Character ìº
+U+ce8c kak # Character ìº
+U+ce8d kat # Character ìº
+U+ce8e kap # Character ìº
+U+ce8f kah # Character ìº
+U+ce90 kae # Character ìº
+U+ce91 kaeg # Character ìº
+U+ce92 kaekk # Character ìº
+U+ce93 kaegs # Character ìº
+U+ce94 kaen # Character ìº
+U+ce95 kaenj # Character ìº
+U+ce96 kaenh # Character ìº
+U+ce97 kaed # Character ìº
+U+ce98 kael # Character ìº
+U+ce99 kaelg # Character ìº
+U+ce9a kaelm # Character ìº
+U+ce9b kaelb # Character ìº
+U+ce9c kaels # Character ìº
+U+ce9d kaelt # Character ìº
+U+ce9e kaelp # Character ìº
+U+ce9f kaelh # Character ìº
+U+cea0 kaem # Character ìº
+U+cea1 kaeb # Character 캡
+U+cea2 kaebs # Character 캢
+U+cea3 kaes # Character 캣
+U+cea4 kaess # Character 캤
+U+cea5 kaeng # Character 캥
+U+cea6 kaej # Character 캦
+U+cea7 kaech # Character 캧
+U+cea8 kaek # Character 캨
+U+cea9 kaet # Character 캩
+U+ceaa kaep # Character 캪
+U+ceab kaeh # Character 캫
+U+ceac kya # Character 캬
+U+cead kyag # Character ìº
+U+ceae kyakk # Character 캮
+U+ceaf kyags # Character 캯
+U+ceb0 kyan # Character 캰
+U+ceb1 kyanj # Character 캱
+U+ceb2 kyanh # Character 캲
+U+ceb3 kyad # Character 캳
+U+ceb4 kyal # Character 캴
+U+ceb5 kyalg # Character 캵
+U+ceb6 kyalm # Character 캶
+U+ceb7 kyalb # Character 캷
+U+ceb8 kyals # Character 캸
+U+ceb9 kyalt # Character 캹
+U+ceba kyalp # Character 캺
+U+cebb kyalh # Character 캻
+U+cebc kyam # Character 캼
+U+cebd kyab # Character 캽
+U+cebe kyabs # Character 캾
+U+cebf kyas # Character 캿
+U+cec0 kyass # Character ì»
+U+cec1 kyang # Character ì»
+U+cec2 kyaj # Character ì»
+U+cec3 kyach # Character ì»
+U+cec4 kyak # Character ì»
+U+cec5 kyat # Character ì»
+U+cec6 kyap # Character ì»
+U+cec7 kyah # Character ì»
+U+cec8 kyae # Character ì»
+U+cec9 kyaeg # Character ì»
+U+ceca kyaekk # Character ì»
+U+cecb kyaegs # Character ì»
+U+cecc kyaen # Character ì»
+U+cecd kyaenj # Character ì»
+U+cece kyaenh # Character ì»
+U+cecf kyaed # Character ì»
+U+ced0 kyael # Character ì»
+U+ced1 kyaelg # Character ì»
+U+ced2 kyaelm # Character ì»
+U+ced3 kyaelb # Character ì»
+U+ced4 kyaels # Character ì»
+U+ced5 kyaelt # Character ì»
+U+ced6 kyaelp # Character ì»
+U+ced7 kyaelh # Character ì»
+U+ced8 kyaem # Character ì»
+U+ced9 kyaeb # Character ì»
+U+ceda kyaebs # Character ì»
+U+cedb kyaes # Character ì»
+U+cedc kyaess # Character ì»
+U+cedd kyaeng # Character ì»
+U+cede kyaej # Character ì»
+U+cedf kyaech # Character ì»
+U+cee0 kyaek # Character ì»
+U+cee1 kyaet # Character 컡
+U+cee2 kyaep # Character 컢
+U+cee3 kyaeh # Character 컣
+U+cee4 keo # Character 커
+U+cee5 keog # Character 컥
+U+cee6 keokk # Character 컦
+U+cee7 keogs # Character 컧
+U+cee8 keon # Character 컨
+U+cee9 keonj # Character 컩
+U+ceea keonh # Character 컪
+U+ceeb keod # Character 컫
+U+ceec keol # Character 컬
+U+ceed keolg # Character ì»
+U+ceee keolm # Character ì»®
+U+ceef keolb # Character 컯
+U+cef0 keols # Character ì»°
+U+cef1 keolt # Character ì»±
+U+cef2 keolp # Character 컲
+U+cef3 keolh # Character 컳
+U+cef4 keom # Character ì»´
+U+cef5 keob # Character 컵
+U+cef6 keobs # Character 컶
+U+cef7 keos # Character ì»·
+U+cef8 keoss # Character 컸
+U+cef9 keong # Character 컹
+U+cefa keoj # Character 컺
+U+cefb keoch # Character ì»»
+U+cefc keok # Character 컼
+U+cefd keot # Character 컽
+U+cefe keop # Character 컾
+U+ceff keoh # Character 컿
diff --git a/resources/chars/latin1/rowcf.trans b/resources/chars/latin1/rowcf.trans
new file mode 100644
index 0000000..c1f0994
--- /dev/null
+++ b/resources/chars/latin1/rowcf.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+cf00 ke # Character ì¼
+U+cf01 keg # Character ì¼
+U+cf02 kekk # Character ì¼
+U+cf03 kegs # Character ì¼
+U+cf04 ken # Character ì¼
+U+cf05 kenj # Character ì¼
+U+cf06 kenh # Character ì¼
+U+cf07 ked # Character ì¼
+U+cf08 kel # Character ì¼
+U+cf09 kelg # Character ì¼
+U+cf0a kelm # Character ì¼
+U+cf0b kelb # Character ì¼
+U+cf0c kels # Character ì¼
+U+cf0d kelt # Character ì¼
+U+cf0e kelp # Character ì¼
+U+cf0f kelh # Character ì¼
+U+cf10 kem # Character ì¼
+U+cf11 keb # Character ì¼
+U+cf12 kebs # Character ì¼
+U+cf13 kes # Character ì¼
+U+cf14 kess # Character ì¼
+U+cf15 keng # Character ì¼
+U+cf16 kej # Character ì¼
+U+cf17 kech # Character ì¼
+U+cf18 kek # Character ì¼
+U+cf19 ket # Character ì¼
+U+cf1a kep # Character ì¼
+U+cf1b keh # Character ì¼
+U+cf1c kyeo # Character ì¼
+U+cf1d kyeog # Character ì¼
+U+cf1e kyeokk # Character ì¼
+U+cf1f kyeogs # Character ì¼
+U+cf20 kyeon # Character ì¼
+U+cf21 kyeonj # Character 켡
+U+cf22 kyeonh # Character ì¼¢
+U+cf23 kyeod # Character ì¼£
+U+cf24 kyeol # Character 켤
+U+cf25 kyeolg # Character ì¼¥
+U+cf26 kyeolm # Character 켦
+U+cf27 kyeolb # Character 켧
+U+cf28 kyeols # Character 켨
+U+cf29 kyeolt # Character 켩
+U+cf2a kyeolp # Character 켪
+U+cf2b kyeolh # Character 켫
+U+cf2c kyeom # Character 켬
+U+cf2d kyeob # Character ì¼
+U+cf2e kyeobs # Character ì¼®
+U+cf2f kyeos # Character 켯
+U+cf30 kyeoss # Character ì¼°
+U+cf31 kyeong # Character ì¼±
+U+cf32 kyeoj # Character ì¼²
+U+cf33 kyeoch # Character ì¼³
+U+cf34 kyeok # Character ì¼´
+U+cf35 kyeot # Character ì¼µ
+U+cf36 kyeop # Character 켶
+U+cf37 kyeoh # Character ì¼·
+U+cf38 kye # Character 켸
+U+cf39 kyeg # Character ì¼¹
+U+cf3a kyekk # Character 켺
+U+cf3b kyegs # Character ì¼»
+U+cf3c kyen # Character ì¼¼
+U+cf3d kyenj # Character ì¼½
+U+cf3e kyenh # Character ì¼¾
+U+cf3f kyed # Character 켿
+U+cf40 kyel # Character ì½
+U+cf41 kyelg # Character ì½
+U+cf42 kyelm # Character ì½
+U+cf43 kyelb # Character ì½
+U+cf44 kyels # Character ì½
+U+cf45 kyelt # Character ì½
+U+cf46 kyelp # Character ì½
+U+cf47 kyelh # Character ì½
+U+cf48 kyem # Character ì½
+U+cf49 kyeb # Character ì½
+U+cf4a kyebs # Character ì½
+U+cf4b kyes # Character ì½
+U+cf4c kyess # Character ì½
+U+cf4d kyeng # Character ì½
+U+cf4e kyej # Character ì½
+U+cf4f kyech # Character ì½
+U+cf50 kyek # Character ì½
+U+cf51 kyet # Character ì½
+U+cf52 kyep # Character ì½
+U+cf53 kyeh # Character ì½
+U+cf54 ko # Character ì½
+U+cf55 kog # Character ì½
+U+cf56 kokk # Character ì½
+U+cf57 kogs # Character ì½
+U+cf58 kon # Character ì½
+U+cf59 konj # Character ì½
+U+cf5a konh # Character ì½
+U+cf5b kod # Character ì½
+U+cf5c kol # Character ì½
+U+cf5d kolg # Character ì½
+U+cf5e kolm # Character ì½
+U+cf5f kolb # Character ì½
+U+cf60 kols # Character ì½
+U+cf61 kolt # Character 콡
+U+cf62 kolp # Character ì½¢
+U+cf63 kolh # Character ì½£
+U+cf64 kom # Character 콤
+U+cf65 kob # Character ì½¥
+U+cf66 kobs # Character 콦
+U+cf67 kos # Character 콧
+U+cf68 koss # Character 콨
+U+cf69 kong # Character 콩
+U+cf6a koj # Character 콪
+U+cf6b koch # Character 콫
+U+cf6c kok # Character 콬
+U+cf6d kot # Character ì½
+U+cf6e kop # Character ì½®
+U+cf6f koh # Character 콯
+U+cf70 kwa # Character ì½°
+U+cf71 kwag # Character ì½±
+U+cf72 kwakk # Character ì½²
+U+cf73 kwags # Character ì½³
+U+cf74 kwan # Character ì½´
+U+cf75 kwanj # Character ì½µ
+U+cf76 kwanh # Character 콶
+U+cf77 kwad # Character ì½·
+U+cf78 kwal # Character 콸
+U+cf79 kwalg # Character ì½¹
+U+cf7a kwalm # Character 콺
+U+cf7b kwalb # Character ì½»
+U+cf7c kwals # Character ì½¼
+U+cf7d kwalt # Character ì½½
+U+cf7e kwalp # Character ì½¾
+U+cf7f kwalh # Character 콿
+U+cf80 kwam # Character ì¾
+U+cf81 kwab # Character ì¾
+U+cf82 kwabs # Character ì¾
+U+cf83 kwas # Character ì¾
+U+cf84 kwass # Character ì¾
+U+cf85 kwang # Character ì¾
+U+cf86 kwaj # Character ì¾
+U+cf87 kwach # Character ì¾
+U+cf88 kwak # Character ì¾
+U+cf89 kwat # Character ì¾
+U+cf8a kwap # Character ì¾
+U+cf8b kwah # Character ì¾
+U+cf8c kwae # Character ì¾
+U+cf8d kwaeg # Character ì¾
+U+cf8e kwaekk # Character ì¾
+U+cf8f kwaegs # Character ì¾
+U+cf90 kwaen # Character ì¾
+U+cf91 kwaenj # Character ì¾
+U+cf92 kwaenh # Character ì¾
+U+cf93 kwaed # Character ì¾
+U+cf94 kwael # Character ì¾
+U+cf95 kwaelg # Character ì¾
+U+cf96 kwaelm # Character ì¾
+U+cf97 kwaelb # Character ì¾
+U+cf98 kwaels # Character ì¾
+U+cf99 kwaelt # Character ì¾
+U+cf9a kwaelp # Character ì¾
+U+cf9b kwaelh # Character ì¾
+U+cf9c kwaem # Character ì¾
+U+cf9d kwaeb # Character ì¾
+U+cf9e kwaebs # Character ì¾
+U+cf9f kwaes # Character ì¾
+U+cfa0 kwaess # Character ì¾
+U+cfa1 kwaeng # Character 쾡
+U+cfa2 kwaej # Character ì¾¢
+U+cfa3 kwaech # Character ì¾£
+U+cfa4 kwaek # Character 쾤
+U+cfa5 kwaet # Character ì¾¥
+U+cfa6 kwaep # Character 쾦
+U+cfa7 kwaeh # Character 쾧
+U+cfa8 koe # Character 쾨
+U+cfa9 koeg # Character 쾩
+U+cfaa koekk # Character 쾪
+U+cfab koegs # Character 쾫
+U+cfac koen # Character 쾬
+U+cfad koenj # Character ì¾
+U+cfae koenh # Character ì¾®
+U+cfaf koed # Character 쾯
+U+cfb0 koel # Character ì¾°
+U+cfb1 koelg # Character ì¾±
+U+cfb2 koelm # Character ì¾²
+U+cfb3 koelb # Character ì¾³
+U+cfb4 koels # Character ì¾´
+U+cfb5 koelt # Character ì¾µ
+U+cfb6 koelp # Character 쾶
+U+cfb7 koelh # Character ì¾·
+U+cfb8 koem # Character 쾸
+U+cfb9 koeb # Character ì¾¹
+U+cfba koebs # Character 쾺
+U+cfbb koes # Character ì¾»
+U+cfbc koess # Character ì¾¼
+U+cfbd koeng # Character ì¾½
+U+cfbe koej # Character ì¾¾
+U+cfbf koech # Character 쾿
+U+cfc0 koek # Character ì¿
+U+cfc1 koet # Character ì¿
+U+cfc2 koep # Character ì¿
+U+cfc3 koeh # Character ì¿
+U+cfc4 kyo # Character ì¿
+U+cfc5 kyog # Character ì¿
+U+cfc6 kyokk # Character ì¿
+U+cfc7 kyogs # Character ì¿
+U+cfc8 kyon # Character ì¿
+U+cfc9 kyonj # Character ì¿
+U+cfca kyonh # Character ì¿
+U+cfcb kyod # Character ì¿
+U+cfcc kyol # Character ì¿
+U+cfcd kyolg # Character ì¿
+U+cfce kyolm # Character ì¿
+U+cfcf kyolb # Character ì¿
+U+cfd0 kyols # Character ì¿
+U+cfd1 kyolt # Character ì¿
+U+cfd2 kyolp # Character ì¿
+U+cfd3 kyolh # Character ì¿
+U+cfd4 kyom # Character ì¿
+U+cfd5 kyob # Character ì¿
+U+cfd6 kyobs # Character ì¿
+U+cfd7 kyos # Character ì¿
+U+cfd8 kyoss # Character ì¿
+U+cfd9 kyong # Character ì¿
+U+cfda kyoj # Character ì¿
+U+cfdb kyoch # Character ì¿
+U+cfdc kyok # Character ì¿
+U+cfdd kyot # Character ì¿
+U+cfde kyop # Character ì¿
+U+cfdf kyoh # Character ì¿
+U+cfe0 ku # Character ì¿
+U+cfe1 kug # Character ì¿¡
+U+cfe2 kukk # Character ì¿¢
+U+cfe3 kugs # Character ì¿£
+U+cfe4 kun # Character 쿤
+U+cfe5 kunj # Character ì¿¥
+U+cfe6 kunh # Character 쿦
+U+cfe7 kud # Character 쿧
+U+cfe8 kul # Character 쿨
+U+cfe9 kulg # Character ì¿©
+U+cfea kulm # Character 쿪
+U+cfeb kulb # Character ì¿«
+U+cfec kuls # Character 쿬
+U+cfed kult # Character ì¿
+U+cfee kulp # Character ì¿®
+U+cfef kulh # Character 쿯
+U+cff0 kum # Character ì¿°
+U+cff1 kub # Character 쿱
+U+cff2 kubs # Character 쿲
+U+cff3 kus # Character 쿳
+U+cff4 kuss # Character ì¿´
+U+cff5 kung # Character 쿵
+U+cff6 kuj # Character 쿶
+U+cff7 kuch # Character ì¿·
+U+cff8 kuk # Character 쿸
+U+cff9 kut # Character 쿹
+U+cffa kup # Character 쿺
+U+cffb kuh # Character ì¿»
+U+cffc kwo # Character 쿼
+U+cffd kwog # Character 쿽
+U+cffe kwokk # Character 쿾
+U+cfff kwogs # Character ì¿¿
diff --git a/resources/chars/latin1/rowd0.trans b/resources/chars/latin1/rowd0.trans
new file mode 100644
index 0000000..4ffee81
--- /dev/null
+++ b/resources/chars/latin1/rowd0.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+d000 kwon # Character í
+U+d001 kwonj # Character í
+U+d002 kwonh # Character í
+U+d003 kwod # Character í
+U+d004 kwol # Character í
+U+d005 kwolg # Character í
+U+d006 kwolm # Character í
+U+d007 kwolb # Character í
+U+d008 kwols # Character í
+U+d009 kwolt # Character í
+U+d00a kwolp # Character í
+U+d00b kwolh # Character í
+U+d00c kwom # Character í
+U+d00d kwob # Character í
+U+d00e kwobs # Character í
+U+d00f kwos # Character í
+U+d010 kwoss # Character í
+U+d011 kwong # Character í
+U+d012 kwoj # Character í
+U+d013 kwoch # Character í
+U+d014 kwok # Character í
+U+d015 kwot # Character í
+U+d016 kwop # Character í
+U+d017 kwoh # Character í
+U+d018 kwe # Character í
+U+d019 kweg # Character í
+U+d01a kwekk # Character í
+U+d01b kwegs # Character í
+U+d01c kwen # Character í
+U+d01d kwenj # Character í
+U+d01e kwenh # Character í
+U+d01f kwed # Character í
+U+d020 kwel # Character í
+U+d021 kwelg # Character í¡
+U+d022 kwelm # Character í¢
+U+d023 kwelb # Character í£
+U+d024 kwels # Character í¤
+U+d025 kwelt # Character í¥
+U+d026 kwelp # Character í¦
+U+d027 kwelh # Character í§
+U+d028 kwem # Character í¨
+U+d029 kweb # Character í©
+U+d02a kwebs # Character íª
+U+d02b kwes # Character í«
+U+d02c kwess # Character í¬
+U+d02d kweng # Character í
+U+d02e kwej # Character í®
+U+d02f kwech # Character í¯
+U+d030 kwek # Character í°
+U+d031 kwet # Character í±
+U+d032 kwep # Character í²
+U+d033 kweh # Character í³
+U+d034 kwi # Character í´
+U+d035 kwig # Character íµ
+U+d036 kwikk # Character í¶
+U+d037 kwigs # Character í·
+U+d038 kwin # Character í¸
+U+d039 kwinj # Character í¹
+U+d03a kwinh # Character íº
+U+d03b kwid # Character í»
+U+d03c kwil # Character í¼
+U+d03d kwilg # Character í½
+U+d03e kwilm # Character í¾
+U+d03f kwilb # Character í¿
+U+d040 kwils # Character í
+U+d041 kwilt # Character í
+U+d042 kwilp # Character í
+U+d043 kwilh # Character í
+U+d044 kwim # Character í
+U+d045 kwib # Character í
+U+d046 kwibs # Character í
+U+d047 kwis # Character í
+U+d048 kwiss # Character í
+U+d049 kwing # Character í
+U+d04a kwij # Character í
+U+d04b kwich # Character í
+U+d04c kwik # Character í
+U+d04d kwit # Character í
+U+d04e kwip # Character í
+U+d04f kwih # Character í
+U+d050 kyu # Character í
+U+d051 kyug # Character í
+U+d052 kyukk # Character í
+U+d053 kyugs # Character í
+U+d054 kyun # Character í
+U+d055 kyunj # Character í
+U+d056 kyunh # Character í
+U+d057 kyud # Character í
+U+d058 kyul # Character í
+U+d059 kyulg # Character í
+U+d05a kyulm # Character í
+U+d05b kyulb # Character í
+U+d05c kyuls # Character í
+U+d05d kyult # Character í
+U+d05e kyulp # Character í
+U+d05f kyulh # Character í
+U+d060 kyum # Character í
+U+d061 kyub # Character í¡
+U+d062 kyubs # Character í¢
+U+d063 kyus # Character í£
+U+d064 kyuss # Character í¤
+U+d065 kyung # Character í¥
+U+d066 kyuj # Character í¦
+U+d067 kyuch # Character í§
+U+d068 kyuk # Character í¨
+U+d069 kyut # Character í©
+U+d06a kyup # Character íª
+U+d06b kyuh # Character í«
+U+d06c keu # Character í¬
+U+d06d keug # Character í
+U+d06e keukk # Character í®
+U+d06f keugs # Character í¯
+U+d070 keun # Character í°
+U+d071 keunj # Character í±
+U+d072 keunh # Character í²
+U+d073 keud # Character í³
+U+d074 keul # Character í´
+U+d075 keulg # Character íµ
+U+d076 keulm # Character í¶
+U+d077 keulb # Character í·
+U+d078 keuls # Character í¸
+U+d079 keult # Character í¹
+U+d07a keulp # Character íº
+U+d07b keulh # Character í»
+U+d07c keum # Character í¼
+U+d07d keub # Character í½
+U+d07e keubs # Character í¾
+U+d07f keus # Character í¿
+U+d080 keuss # Character í
+U+d081 keung # Character í
+U+d082 keuj # Character í
+U+d083 keuch # Character í
+U+d084 keuk # Character í
+U+d085 keut # Character í
+U+d086 keup # Character í
+U+d087 keuh # Character í
+U+d088 kui # Character í
+U+d089 kuig # Character í
+U+d08a kuikk # Character í
+U+d08b kuigs # Character í
+U+d08c kuin # Character í
+U+d08d kuinj # Character í
+U+d08e kuinh # Character í
+U+d08f kuid # Character í
+U+d090 kuil # Character í
+U+d091 kuilg # Character í
+U+d092 kuilm # Character í
+U+d093 kuilb # Character í
+U+d094 kuils # Character í
+U+d095 kuilt # Character í
+U+d096 kuilp # Character í
+U+d097 kuilh # Character í
+U+d098 kuim # Character í
+U+d099 kuib # Character í
+U+d09a kuibs # Character í
+U+d09b kuis # Character í
+U+d09c kuiss # Character í
+U+d09d kuing # Character í
+U+d09e kuij # Character í
+U+d09f kuich # Character í
+U+d0a0 kuik # Character í
+U+d0a1 kuit # Character í¡
+U+d0a2 kuip # Character í¢
+U+d0a3 kuih # Character í£
+U+d0a4 ki # Character í¤
+U+d0a5 kig # Character í¥
+U+d0a6 kikk # Character í¦
+U+d0a7 kigs # Character í§
+U+d0a8 kin # Character í¨
+U+d0a9 kinj # Character í©
+U+d0aa kinh # Character íª
+U+d0ab kid # Character í«
+U+d0ac kil # Character í¬
+U+d0ad kilg # Character í
+U+d0ae kilm # Character í®
+U+d0af kilb # Character í¯
+U+d0b0 kils # Character í°
+U+d0b1 kilt # Character í±
+U+d0b2 kilp # Character í²
+U+d0b3 kilh # Character í³
+U+d0b4 kim # Character í´
+U+d0b5 kib # Character íµ
+U+d0b6 kibs # Character í¶
+U+d0b7 kis # Character í·
+U+d0b8 kiss # Character í¸
+U+d0b9 king # Character í¹
+U+d0ba kij # Character íº
+U+d0bb kich # Character í»
+U+d0bc kik # Character í¼
+U+d0bd kit # Character í½
+U+d0be kip # Character í¾
+U+d0bf kih # Character í¿
+U+d0c0 ta # Character í
+U+d0c1 tag # Character í
+U+d0c2 takk # Character í
+U+d0c3 tags # Character í
+U+d0c4 tan # Character í
+U+d0c5 tanj # Character í
+U+d0c6 tanh # Character í
+U+d0c7 tad # Character í
+U+d0c8 tal # Character í
+U+d0c9 talg # Character í
+U+d0ca talm # Character í
+U+d0cb talb # Character í
+U+d0cc tals # Character í
+U+d0cd talt # Character í
+U+d0ce talp # Character í
+U+d0cf talh # Character í
+U+d0d0 tam # Character í
+U+d0d1 tab # Character í
+U+d0d2 tabs # Character í
+U+d0d3 tas # Character í
+U+d0d4 tass # Character í
+U+d0d5 tang # Character í
+U+d0d6 taj # Character í
+U+d0d7 tach # Character í
+U+d0d8 tak # Character í
+U+d0d9 tat # Character í
+U+d0da tap # Character í
+U+d0db tah # Character í
+U+d0dc tae # Character í
+U+d0dd taeg # Character í
+U+d0de taekk # Character í
+U+d0df taegs # Character í
+U+d0e0 taen # Character í
+U+d0e1 taenj # Character í¡
+U+d0e2 taenh # Character í¢
+U+d0e3 taed # Character í£
+U+d0e4 tael # Character í¤
+U+d0e5 taelg # Character í¥
+U+d0e6 taelm # Character í¦
+U+d0e7 taelb # Character í§
+U+d0e8 taels # Character í¨
+U+d0e9 taelt # Character í©
+U+d0ea taelp # Character íª
+U+d0eb taelh # Character í«
+U+d0ec taem # Character í¬
+U+d0ed taeb # Character í
+U+d0ee taebs # Character í®
+U+d0ef taes # Character í¯
+U+d0f0 taess # Character í°
+U+d0f1 taeng # Character í±
+U+d0f2 taej # Character í²
+U+d0f3 taech # Character í³
+U+d0f4 taek # Character í´
+U+d0f5 taet # Character íµ
+U+d0f6 taep # Character í¶
+U+d0f7 taeh # Character í·
+U+d0f8 tya # Character í¸
+U+d0f9 tyag # Character í¹
+U+d0fa tyakk # Character íº
+U+d0fb tyags # Character í»
+U+d0fc tyan # Character í¼
+U+d0fd tyanj # Character í½
+U+d0fe tyanh # Character í¾
+U+d0ff tyad # Character í¿
diff --git a/resources/chars/latin1/rowd1.trans b/resources/chars/latin1/rowd1.trans
new file mode 100644
index 0000000..45842a8
--- /dev/null
+++ b/resources/chars/latin1/rowd1.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+d100 tyal # Character í
+U+d101 tyalg # Character í
+U+d102 tyalm # Character í
+U+d103 tyalb # Character í
+U+d104 tyals # Character í
+U+d105 tyalt # Character í
+U+d106 tyalp # Character í
+U+d107 tyalh # Character í
+U+d108 tyam # Character í
+U+d109 tyab # Character í
+U+d10a tyabs # Character í
+U+d10b tyas # Character í
+U+d10c tyass # Character í
+U+d10d tyang # Character í
+U+d10e tyaj # Character í
+U+d10f tyach # Character í
+U+d110 tyak # Character í
+U+d111 tyat # Character í
+U+d112 tyap # Character í
+U+d113 tyah # Character í
+U+d114 tyae # Character í
+U+d115 tyaeg # Character í
+U+d116 tyaekk # Character í
+U+d117 tyaegs # Character í
+U+d118 tyaen # Character í
+U+d119 tyaenj # Character í
+U+d11a tyaenh # Character í
+U+d11b tyaed # Character í
+U+d11c tyael # Character í
+U+d11d tyaelg # Character í
+U+d11e tyaelm # Character í
+U+d11f tyaelb # Character í
+U+d120 tyaels # Character í
+U+d121 tyaelt # Character í¡
+U+d122 tyaelp # Character í¢
+U+d123 tyaelh # Character í£
+U+d124 tyaem # Character í¤
+U+d125 tyaeb # Character í¥
+U+d126 tyaebs # Character í¦
+U+d127 tyaes # Character í§
+U+d128 tyaess # Character í¨
+U+d129 tyaeng # Character í©
+U+d12a tyaej # Character íª
+U+d12b tyaech # Character í«
+U+d12c tyaek # Character í¬
+U+d12d tyaet # Character í
+U+d12e tyaep # Character í®
+U+d12f tyaeh # Character í¯
+U+d130 teo # Character í°
+U+d131 teog # Character í±
+U+d132 teokk # Character í²
+U+d133 teogs # Character í³
+U+d134 teon # Character í´
+U+d135 teonj # Character íµ
+U+d136 teonh # Character í¶
+U+d137 teod # Character í·
+U+d138 teol # Character í¸
+U+d139 teolg # Character í¹
+U+d13a teolm # Character íº
+U+d13b teolb # Character í»
+U+d13c teols # Character í¼
+U+d13d teolt # Character í½
+U+d13e teolp # Character í¾
+U+d13f teolh # Character í¿
+U+d140 teom # Character í
+U+d141 teob # Character í
+U+d142 teobs # Character í
+U+d143 teos # Character í
+U+d144 teoss # Character í
+U+d145 teong # Character í
+U+d146 teoj # Character í
+U+d147 teoch # Character í
+U+d148 teok # Character í
+U+d149 teot # Character í
+U+d14a teop # Character í
+U+d14b teoh # Character í
+U+d14c te # Character í
+U+d14d teg # Character í
+U+d14e tekk # Character í
+U+d14f tegs # Character í
+U+d150 ten # Character í
+U+d151 tenj # Character í
+U+d152 tenh # Character í
+U+d153 ted # Character í
+U+d154 tel # Character í
+U+d155 telg # Character í
+U+d156 telm # Character í
+U+d157 telb # Character í
+U+d158 tels # Character í
+U+d159 telt # Character í
+U+d15a telp # Character í
+U+d15b telh # Character í
+U+d15c tem # Character í
+U+d15d teb # Character í
+U+d15e tebs # Character í
+U+d15f tes # Character í
+U+d160 tess # Character í
+U+d161 teng # Character í
¡
+U+d162 tej # Character í
¢
+U+d163 tech # Character í
£
+U+d164 tek # Character í
¤
+U+d165 tet # Character í
¥
+U+d166 tep # Character í
¦
+U+d167 teh # Character í
§
+U+d168 tyeo # Character í
¨
+U+d169 tyeog # Character í
©
+U+d16a tyeokk # Character í
ª
+U+d16b tyeogs # Character í
«
+U+d16c tyeon # Character í
¬
+U+d16d tyeonj # Character í
+U+d16e tyeonh # Character í
®
+U+d16f tyeod # Character í
¯
+U+d170 tyeol # Character í
°
+U+d171 tyeolg # Character í
±
+U+d172 tyeolm # Character í
²
+U+d173 tyeolb # Character í
³
+U+d174 tyeols # Character í
´
+U+d175 tyeolt # Character í
µ
+U+d176 tyeolp # Character í
¶
+U+d177 tyeolh # Character í
·
+U+d178 tyeom # Character í
¸
+U+d179 tyeob # Character í
¹
+U+d17a tyeobs # Character í
º
+U+d17b tyeos # Character í
»
+U+d17c tyeoss # Character í
¼
+U+d17d tyeong # Character í
½
+U+d17e tyeoj # Character í
¾
+U+d17f tyeoch # Character í
¿
+U+d180 tyeok # Character í
+U+d181 tyeot # Character í
+U+d182 tyeop # Character í
+U+d183 tyeoh # Character í
+U+d184 tye # Character í
+U+d185 tyeg # Character í
+U+d186 tyekk # Character í
+U+d187 tyegs # Character í
+U+d188 tyen # Character í
+U+d189 tyenj # Character í
+U+d18a tyenh # Character í
+U+d18b tyed # Character í
+U+d18c tyel # Character í
+U+d18d tyelg # Character í
+U+d18e tyelm # Character í
+U+d18f tyelb # Character í
+U+d190 tyels # Character í
+U+d191 tyelt # Character í
+U+d192 tyelp # Character í
+U+d193 tyelh # Character í
+U+d194 tyem # Character í
+U+d195 tyeb # Character í
+U+d196 tyebs # Character í
+U+d197 tyes # Character í
+U+d198 tyess # Character í
+U+d199 tyeng # Character í
+U+d19a tyej # Character í
+U+d19b tyech # Character í
+U+d19c tyek # Character í
+U+d19d tyet # Character í
+U+d19e tyep # Character í
+U+d19f tyeh # Character í
+U+d1a0 to # Character í
+U+d1a1 tog # Character í¡
+U+d1a2 tokk # Character í¢
+U+d1a3 togs # Character í£
+U+d1a4 ton # Character í¤
+U+d1a5 tonj # Character í¥
+U+d1a6 tonh # Character í¦
+U+d1a7 tod # Character í§
+U+d1a8 tol # Character í¨
+U+d1a9 tolg # Character í©
+U+d1aa tolm # Character íª
+U+d1ab tolb # Character í«
+U+d1ac tols # Character í¬
+U+d1ad tolt # Character í
+U+d1ae tolp # Character í®
+U+d1af tolh # Character í¯
+U+d1b0 tom # Character í°
+U+d1b1 tob # Character í±
+U+d1b2 tobs # Character í²
+U+d1b3 tos # Character í³
+U+d1b4 toss # Character í´
+U+d1b5 tong # Character íµ
+U+d1b6 toj # Character í¶
+U+d1b7 toch # Character í·
+U+d1b8 tok # Character í¸
+U+d1b9 tot # Character í¹
+U+d1ba top # Character íº
+U+d1bb toh # Character í»
+U+d1bc twa # Character í¼
+U+d1bd twag # Character í½
+U+d1be twakk # Character í¾
+U+d1bf twags # Character í¿
+U+d1c0 twan # Character í
+U+d1c1 twanj # Character í
+U+d1c2 twanh # Character í
+U+d1c3 twad # Character í
+U+d1c4 twal # Character í
+U+d1c5 twalg # Character í
+U+d1c6 twalm # Character í
+U+d1c7 twalb # Character í
+U+d1c8 twals # Character í
+U+d1c9 twalt # Character í
+U+d1ca twalp # Character í
+U+d1cb twalh # Character í
+U+d1cc twam # Character í
+U+d1cd twab # Character í
+U+d1ce twabs # Character í
+U+d1cf twas # Character í
+U+d1d0 twass # Character í
+U+d1d1 twang # Character í
+U+d1d2 twaj # Character í
+U+d1d3 twach # Character í
+U+d1d4 twak # Character í
+U+d1d5 twat # Character í
+U+d1d6 twap # Character í
+U+d1d7 twah # Character í
+U+d1d8 twae # Character í
+U+d1d9 twaeg # Character í
+U+d1da twaekk # Character í
+U+d1db twaegs # Character í
+U+d1dc twaen # Character í
+U+d1dd twaenj # Character í
+U+d1de twaenh # Character í
+U+d1df twaed # Character í
+U+d1e0 twael # Character í
+U+d1e1 twaelg # Character í¡
+U+d1e2 twaelm # Character í¢
+U+d1e3 twaelb # Character í£
+U+d1e4 twaels # Character í¤
+U+d1e5 twaelt # Character í¥
+U+d1e6 twaelp # Character í¦
+U+d1e7 twaelh # Character í§
+U+d1e8 twaem # Character í¨
+U+d1e9 twaeb # Character í©
+U+d1ea twaebs # Character íª
+U+d1eb twaes # Character í«
+U+d1ec twaess # Character í¬
+U+d1ed twaeng # Character í
+U+d1ee twaej # Character í®
+U+d1ef twaech # Character í¯
+U+d1f0 twaek # Character í°
+U+d1f1 twaet # Character í±
+U+d1f2 twaep # Character í²
+U+d1f3 twaeh # Character í³
+U+d1f4 toe # Character í´
+U+d1f5 toeg # Character íµ
+U+d1f6 toekk # Character í¶
+U+d1f7 toegs # Character í·
+U+d1f8 toen # Character í¸
+U+d1f9 toenj # Character í¹
+U+d1fa toenh # Character íº
+U+d1fb toed # Character í»
+U+d1fc toel # Character í¼
+U+d1fd toelg # Character í½
+U+d1fe toelm # Character í¾
+U+d1ff toelb # Character í¿
diff --git a/resources/chars/latin1/rowd2.trans b/resources/chars/latin1/rowd2.trans
new file mode 100644
index 0000000..71637a6
--- /dev/null
+++ b/resources/chars/latin1/rowd2.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+d200 toels # Character í
+U+d201 toelt # Character í
+U+d202 toelp # Character í
+U+d203 toelh # Character í
+U+d204 toem # Character í
+U+d205 toeb # Character í
+U+d206 toebs # Character í
+U+d207 toes # Character í
+U+d208 toess # Character í
+U+d209 toeng # Character í
+U+d20a toej # Character í
+U+d20b toech # Character í
+U+d20c toek # Character í
+U+d20d toet # Character í
+U+d20e toep # Character í
+U+d20f toeh # Character í
+U+d210 tyo # Character í
+U+d211 tyog # Character í
+U+d212 tyokk # Character í
+U+d213 tyogs # Character í
+U+d214 tyon # Character í
+U+d215 tyonj # Character í
+U+d216 tyonh # Character í
+U+d217 tyod # Character í
+U+d218 tyol # Character í
+U+d219 tyolg # Character í
+U+d21a tyolm # Character í
+U+d21b tyolb # Character í
+U+d21c tyols # Character í
+U+d21d tyolt # Character í
+U+d21e tyolp # Character í
+U+d21f tyolh # Character í
+U+d220 tyom # Character í
+U+d221 tyob # Character í¡
+U+d222 tyobs # Character í¢
+U+d223 tyos # Character í£
+U+d224 tyoss # Character í¤
+U+d225 tyong # Character í¥
+U+d226 tyoj # Character í¦
+U+d227 tyoch # Character í§
+U+d228 tyok # Character í¨
+U+d229 tyot # Character í©
+U+d22a tyop # Character íª
+U+d22b tyoh # Character í«
+U+d22c tu # Character í¬
+U+d22d tug # Character í
+U+d22e tukk # Character í®
+U+d22f tugs # Character í¯
+U+d230 tun # Character í°
+U+d231 tunj # Character í±
+U+d232 tunh # Character í²
+U+d233 tud # Character í³
+U+d234 tul # Character í´
+U+d235 tulg # Character íµ
+U+d236 tulm # Character í¶
+U+d237 tulb # Character í·
+U+d238 tuls # Character í¸
+U+d239 tult # Character í¹
+U+d23a tulp # Character íº
+U+d23b tulh # Character í»
+U+d23c tum # Character í¼
+U+d23d tub # Character í½
+U+d23e tubs # Character í¾
+U+d23f tus # Character í¿
+U+d240 tuss # Character í
+U+d241 tung # Character í
+U+d242 tuj # Character í
+U+d243 tuch # Character í
+U+d244 tuk # Character í
+U+d245 tut # Character í
+U+d246 tup # Character í
+U+d247 tuh # Character í
+U+d248 two # Character í
+U+d249 twog # Character í
+U+d24a twokk # Character í
+U+d24b twogs # Character í
+U+d24c twon # Character í
+U+d24d twonj # Character í
+U+d24e twonh # Character í
+U+d24f twod # Character í
+U+d250 twol # Character í
+U+d251 twolg # Character í
+U+d252 twolm # Character í
+U+d253 twolb # Character í
+U+d254 twols # Character í
+U+d255 twolt # Character í
+U+d256 twolp # Character í
+U+d257 twolh # Character í
+U+d258 twom # Character í
+U+d259 twob # Character í
+U+d25a twobs # Character í
+U+d25b twos # Character í
+U+d25c twoss # Character í
+U+d25d twong # Character í
+U+d25e twoj # Character í
+U+d25f twoch # Character í
+U+d260 twok # Character í
+U+d261 twot # Character í¡
+U+d262 twop # Character í¢
+U+d263 twoh # Character í£
+U+d264 twe # Character í¤
+U+d265 tweg # Character í¥
+U+d266 twekk # Character í¦
+U+d267 twegs # Character í§
+U+d268 twen # Character í¨
+U+d269 twenj # Character í©
+U+d26a twenh # Character íª
+U+d26b twed # Character í«
+U+d26c twel # Character í¬
+U+d26d twelg # Character í
+U+d26e twelm # Character í®
+U+d26f twelb # Character í¯
+U+d270 twels # Character í°
+U+d271 twelt # Character í±
+U+d272 twelp # Character í²
+U+d273 twelh # Character í³
+U+d274 twem # Character í´
+U+d275 tweb # Character íµ
+U+d276 twebs # Character í¶
+U+d277 twes # Character í·
+U+d278 twess # Character í¸
+U+d279 tweng # Character í¹
+U+d27a twej # Character íº
+U+d27b twech # Character í»
+U+d27c twek # Character í¼
+U+d27d twet # Character í½
+U+d27e twep # Character í¾
+U+d27f tweh # Character í¿
+U+d280 twi # Character í
+U+d281 twig # Character í
+U+d282 twikk # Character í
+U+d283 twigs # Character í
+U+d284 twin # Character í
+U+d285 twinj # Character í
+U+d286 twinh # Character í
+U+d287 twid # Character í
+U+d288 twil # Character í
+U+d289 twilg # Character í
+U+d28a twilm # Character í
+U+d28b twilb # Character í
+U+d28c twils # Character í
+U+d28d twilt # Character í
+U+d28e twilp # Character í
+U+d28f twilh # Character í
+U+d290 twim # Character í
+U+d291 twib # Character í
+U+d292 twibs # Character í
+U+d293 twis # Character í
+U+d294 twiss # Character í
+U+d295 twing # Character í
+U+d296 twij # Character í
+U+d297 twich # Character í
+U+d298 twik # Character í
+U+d299 twit # Character í
+U+d29a twip # Character í
+U+d29b twih # Character í
+U+d29c tyu # Character í
+U+d29d tyug # Character í
+U+d29e tyukk # Character í
+U+d29f tyugs # Character í
+U+d2a0 tyun # Character í
+U+d2a1 tyunj # Character í¡
+U+d2a2 tyunh # Character í¢
+U+d2a3 tyud # Character í£
+U+d2a4 tyul # Character í¤
+U+d2a5 tyulg # Character í¥
+U+d2a6 tyulm # Character í¦
+U+d2a7 tyulb # Character í§
+U+d2a8 tyuls # Character í¨
+U+d2a9 tyult # Character í©
+U+d2aa tyulp # Character íª
+U+d2ab tyulh # Character í«
+U+d2ac tyum # Character í¬
+U+d2ad tyub # Character í
+U+d2ae tyubs # Character í®
+U+d2af tyus # Character í¯
+U+d2b0 tyuss # Character í°
+U+d2b1 tyung # Character í±
+U+d2b2 tyuj # Character í²
+U+d2b3 tyuch # Character í³
+U+d2b4 tyuk # Character í´
+U+d2b5 tyut # Character íµ
+U+d2b6 tyup # Character í¶
+U+d2b7 tyuh # Character í·
+U+d2b8 teu # Character í¸
+U+d2b9 teug # Character í¹
+U+d2ba teukk # Character íº
+U+d2bb teugs # Character í»
+U+d2bc teun # Character í¼
+U+d2bd teunj # Character í½
+U+d2be teunh # Character í¾
+U+d2bf teud # Character í¿
+U+d2c0 teul # Character í
+U+d2c1 teulg # Character í
+U+d2c2 teulm # Character í
+U+d2c3 teulb # Character í
+U+d2c4 teuls # Character í
+U+d2c5 teult # Character í
+U+d2c6 teulp # Character í
+U+d2c7 teulh # Character í
+U+d2c8 teum # Character í
+U+d2c9 teub # Character í
+U+d2ca teubs # Character í
+U+d2cb teus # Character í
+U+d2cc teuss # Character í
+U+d2cd teung # Character í
+U+d2ce teuj # Character í
+U+d2cf teuch # Character í
+U+d2d0 teuk # Character í
+U+d2d1 teut # Character í
+U+d2d2 teup # Character í
+U+d2d3 teuh # Character í
+U+d2d4 tui # Character í
+U+d2d5 tuig # Character í
+U+d2d6 tuikk # Character í
+U+d2d7 tuigs # Character í
+U+d2d8 tuin # Character í
+U+d2d9 tuinj # Character í
+U+d2da tuinh # Character í
+U+d2db tuid # Character í
+U+d2dc tuil # Character í
+U+d2dd tuilg # Character í
+U+d2de tuilm # Character í
+U+d2df tuilb # Character í
+U+d2e0 tuils # Character í
+U+d2e1 tuilt # Character í¡
+U+d2e2 tuilp # Character í¢
+U+d2e3 tuilh # Character í£
+U+d2e4 tuim # Character í¤
+U+d2e5 tuib # Character í¥
+U+d2e6 tuibs # Character í¦
+U+d2e7 tuis # Character í§
+U+d2e8 tuiss # Character í¨
+U+d2e9 tuing # Character í©
+U+d2ea tuij # Character íª
+U+d2eb tuich # Character í«
+U+d2ec tuik # Character í¬
+U+d2ed tuit # Character í
+U+d2ee tuip # Character í®
+U+d2ef tuih # Character í¯
+U+d2f0 ti # Character í°
+U+d2f1 tig # Character í±
+U+d2f2 tikk # Character í²
+U+d2f3 tigs # Character í³
+U+d2f4 tin # Character í´
+U+d2f5 tinj # Character íµ
+U+d2f6 tinh # Character í¶
+U+d2f7 tid # Character í·
+U+d2f8 til # Character í¸
+U+d2f9 tilg # Character í¹
+U+d2fa tilm # Character íº
+U+d2fb tilb # Character í»
+U+d2fc tils # Character í¼
+U+d2fd tilt # Character í½
+U+d2fe tilp # Character í¾
+U+d2ff tilh # Character í¿
diff --git a/resources/chars/latin1/rowd3.trans b/resources/chars/latin1/rowd3.trans
new file mode 100644
index 0000000..39cb648
--- /dev/null
+++ b/resources/chars/latin1/rowd3.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+d300 tim # Character í
+U+d301 tib # Character í
+U+d302 tibs # Character í
+U+d303 tis # Character í
+U+d304 tiss # Character í
+U+d305 ting # Character í
+U+d306 tij # Character í
+U+d307 tich # Character í
+U+d308 tik # Character í
+U+d309 tit # Character í
+U+d30a tip # Character í
+U+d30b tih # Character í
+U+d30c pa # Character í
+U+d30d pag # Character í
+U+d30e pakk # Character í
+U+d30f pags # Character í
+U+d310 pan # Character í
+U+d311 panj # Character í
+U+d312 panh # Character í
+U+d313 pad # Character í
+U+d314 pal # Character í
+U+d315 palg # Character í
+U+d316 palm # Character í
+U+d317 palb # Character í
+U+d318 pals # Character í
+U+d319 palt # Character í
+U+d31a palp # Character í
+U+d31b palh # Character í
+U+d31c pam # Character í
+U+d31d pab # Character í
+U+d31e pabs # Character í
+U+d31f pas # Character í
+U+d320 pass # Character í
+U+d321 pang # Character í¡
+U+d322 paj # Character í¢
+U+d323 pach # Character í£
+U+d324 pak # Character í¤
+U+d325 pat # Character í¥
+U+d326 pap # Character í¦
+U+d327 pah # Character í§
+U+d328 pae # Character í¨
+U+d329 paeg # Character í©
+U+d32a paekk # Character íª
+U+d32b paegs # Character í«
+U+d32c paen # Character í¬
+U+d32d paenj # Character í
+U+d32e paenh # Character í®
+U+d32f paed # Character í¯
+U+d330 pael # Character í°
+U+d331 paelg # Character í±
+U+d332 paelm # Character í²
+U+d333 paelb # Character í³
+U+d334 paels # Character í´
+U+d335 paelt # Character íµ
+U+d336 paelp # Character í¶
+U+d337 paelh # Character í·
+U+d338 paem # Character í¸
+U+d339 paeb # Character í¹
+U+d33a paebs # Character íº
+U+d33b paes # Character í»
+U+d33c paess # Character í¼
+U+d33d paeng # Character í½
+U+d33e paej # Character í¾
+U+d33f paech # Character í¿
+U+d340 paek # Character í
+U+d341 paet # Character í
+U+d342 paep # Character í
+U+d343 paeh # Character í
+U+d344 pya # Character í
+U+d345 pyag # Character í
+U+d346 pyakk # Character í
+U+d347 pyags # Character í
+U+d348 pyan # Character í
+U+d349 pyanj # Character í
+U+d34a pyanh # Character í
+U+d34b pyad # Character í
+U+d34c pyal # Character í
+U+d34d pyalg # Character í
+U+d34e pyalm # Character í
+U+d34f pyalb # Character í
+U+d350 pyals # Character í
+U+d351 pyalt # Character í
+U+d352 pyalp # Character í
+U+d353 pyalh # Character í
+U+d354 pyam # Character í
+U+d355 pyab # Character í
+U+d356 pyabs # Character í
+U+d357 pyas # Character í
+U+d358 pyass # Character í
+U+d359 pyang # Character í
+U+d35a pyaj # Character í
+U+d35b pyach # Character í
+U+d35c pyak # Character í
+U+d35d pyat # Character í
+U+d35e pyap # Character í
+U+d35f pyah # Character í
+U+d360 pyae # Character í
+U+d361 pyaeg # Character í¡
+U+d362 pyaekk # Character í¢
+U+d363 pyaegs # Character í£
+U+d364 pyaen # Character í¤
+U+d365 pyaenj # Character í¥
+U+d366 pyaenh # Character í¦
+U+d367 pyaed # Character í§
+U+d368 pyael # Character í¨
+U+d369 pyaelg # Character í©
+U+d36a pyaelm # Character íª
+U+d36b pyaelb # Character í«
+U+d36c pyaels # Character í¬
+U+d36d pyaelt # Character í
+U+d36e pyaelp # Character í®
+U+d36f pyaelh # Character í¯
+U+d370 pyaem # Character í°
+U+d371 pyaeb # Character í±
+U+d372 pyaebs # Character í²
+U+d373 pyaes # Character í³
+U+d374 pyaess # Character í´
+U+d375 pyaeng # Character íµ
+U+d376 pyaej # Character í¶
+U+d377 pyaech # Character í·
+U+d378 pyaek # Character í¸
+U+d379 pyaet # Character í¹
+U+d37a pyaep # Character íº
+U+d37b pyaeh # Character í»
+U+d37c peo # Character í¼
+U+d37d peog # Character í½
+U+d37e peokk # Character í¾
+U+d37f peogs # Character í¿
+U+d380 peon # Character í
+U+d381 peonj # Character í
+U+d382 peonh # Character í
+U+d383 peod # Character í
+U+d384 peol # Character í
+U+d385 peolg # Character í
+U+d386 peolm # Character í
+U+d387 peolb # Character í
+U+d388 peols # Character í
+U+d389 peolt # Character í
+U+d38a peolp # Character í
+U+d38b peolh # Character í
+U+d38c peom # Character í
+U+d38d peob # Character í
+U+d38e peobs # Character í
+U+d38f peos # Character í
+U+d390 peoss # Character í
+U+d391 peong # Character í
+U+d392 peoj # Character í
+U+d393 peoch # Character í
+U+d394 peok # Character í
+U+d395 peot # Character í
+U+d396 peop # Character í
+U+d397 peoh # Character í
+U+d398 pe # Character í
+U+d399 peg # Character í
+U+d39a pekk # Character í
+U+d39b pegs # Character í
+U+d39c pen # Character í
+U+d39d penj # Character í
+U+d39e penh # Character í
+U+d39f ped # Character í
+U+d3a0 pel # Character í
+U+d3a1 pelg # Character í¡
+U+d3a2 pelm # Character í¢
+U+d3a3 pelb # Character í£
+U+d3a4 pels # Character í¤
+U+d3a5 pelt # Character í¥
+U+d3a6 pelp # Character í¦
+U+d3a7 pelh # Character í§
+U+d3a8 pem # Character í¨
+U+d3a9 peb # Character í©
+U+d3aa pebs # Character íª
+U+d3ab pes # Character í«
+U+d3ac pess # Character í¬
+U+d3ad peng # Character í
+U+d3ae pej # Character í®
+U+d3af pech # Character í¯
+U+d3b0 pek # Character í°
+U+d3b1 pet # Character í±
+U+d3b2 pep # Character í²
+U+d3b3 peh # Character í³
+U+d3b4 pyeo # Character í´
+U+d3b5 pyeog # Character íµ
+U+d3b6 pyeokk # Character í¶
+U+d3b7 pyeogs # Character í·
+U+d3b8 pyeon # Character í¸
+U+d3b9 pyeonj # Character í¹
+U+d3ba pyeonh # Character íº
+U+d3bb pyeod # Character í»
+U+d3bc pyeol # Character í¼
+U+d3bd pyeolg # Character í½
+U+d3be pyeolm # Character í¾
+U+d3bf pyeolb # Character í¿
+U+d3c0 pyeols # Character í
+U+d3c1 pyeolt # Character í
+U+d3c2 pyeolp # Character í
+U+d3c3 pyeolh # Character í
+U+d3c4 pyeom # Character í
+U+d3c5 pyeob # Character í
+U+d3c6 pyeobs # Character í
+U+d3c7 pyeos # Character í
+U+d3c8 pyeoss # Character í
+U+d3c9 pyeong # Character í
+U+d3ca pyeoj # Character í
+U+d3cb pyeoch # Character í
+U+d3cc pyeok # Character í
+U+d3cd pyeot # Character í
+U+d3ce pyeop # Character í
+U+d3cf pyeoh # Character í
+U+d3d0 pye # Character í
+U+d3d1 pyeg # Character í
+U+d3d2 pyekk # Character í
+U+d3d3 pyegs # Character í
+U+d3d4 pyen # Character í
+U+d3d5 pyenj # Character í
+U+d3d6 pyenh # Character í
+U+d3d7 pyed # Character í
+U+d3d8 pyel # Character í
+U+d3d9 pyelg # Character í
+U+d3da pyelm # Character í
+U+d3db pyelb # Character í
+U+d3dc pyels # Character í
+U+d3dd pyelt # Character í
+U+d3de pyelp # Character í
+U+d3df pyelh # Character í
+U+d3e0 pyem # Character í
+U+d3e1 pyeb # Character í¡
+U+d3e2 pyebs # Character í¢
+U+d3e3 pyes # Character í£
+U+d3e4 pyess # Character í¤
+U+d3e5 pyeng # Character í¥
+U+d3e6 pyej # Character í¦
+U+d3e7 pyech # Character í§
+U+d3e8 pyek # Character í¨
+U+d3e9 pyet # Character í©
+U+d3ea pyep # Character íª
+U+d3eb pyeh # Character í«
+U+d3ec po # Character í¬
+U+d3ed pog # Character í
+U+d3ee pokk # Character í®
+U+d3ef pogs # Character í¯
+U+d3f0 pon # Character í°
+U+d3f1 ponj # Character í±
+U+d3f2 ponh # Character í²
+U+d3f3 pod # Character í³
+U+d3f4 pol # Character í´
+U+d3f5 polg # Character íµ
+U+d3f6 polm # Character í¶
+U+d3f7 polb # Character í·
+U+d3f8 pols # Character í¸
+U+d3f9 polt # Character í¹
+U+d3fa polp # Character íº
+U+d3fb polh # Character í»
+U+d3fc pom # Character í¼
+U+d3fd pob # Character í½
+U+d3fe pobs # Character í¾
+U+d3ff pos # Character í¿
diff --git a/resources/chars/latin1/rowd4.trans b/resources/chars/latin1/rowd4.trans
new file mode 100644
index 0000000..073ed7a
--- /dev/null
+++ b/resources/chars/latin1/rowd4.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+d400 poss # Character í
+U+d401 pong # Character í
+U+d402 poj # Character í
+U+d403 poch # Character í
+U+d404 pok # Character í
+U+d405 pot # Character í
+U+d406 pop # Character í
+U+d407 poh # Character í
+U+d408 pwa # Character í
+U+d409 pwag # Character í
+U+d40a pwakk # Character í
+U+d40b pwags # Character í
+U+d40c pwan # Character í
+U+d40d pwanj # Character í
+U+d40e pwanh # Character í
+U+d40f pwad # Character í
+U+d410 pwal # Character í
+U+d411 pwalg # Character í
+U+d412 pwalm # Character í
+U+d413 pwalb # Character í
+U+d414 pwals # Character í
+U+d415 pwalt # Character í
+U+d416 pwalp # Character í
+U+d417 pwalh # Character í
+U+d418 pwam # Character í
+U+d419 pwab # Character í
+U+d41a pwabs # Character í
+U+d41b pwas # Character í
+U+d41c pwass # Character í
+U+d41d pwang # Character í
+U+d41e pwaj # Character í
+U+d41f pwach # Character í
+U+d420 pwak # Character í
+U+d421 pwat # Character í¡
+U+d422 pwap # Character í¢
+U+d423 pwah # Character í£
+U+d424 pwae # Character í¤
+U+d425 pwaeg # Character í¥
+U+d426 pwaekk # Character í¦
+U+d427 pwaegs # Character í§
+U+d428 pwaen # Character í¨
+U+d429 pwaenj # Character í©
+U+d42a pwaenh # Character íª
+U+d42b pwaed # Character í«
+U+d42c pwael # Character í¬
+U+d42d pwaelg # Character í
+U+d42e pwaelm # Character í®
+U+d42f pwaelb # Character í¯
+U+d430 pwaels # Character í°
+U+d431 pwaelt # Character í±
+U+d432 pwaelp # Character í²
+U+d433 pwaelh # Character í³
+U+d434 pwaem # Character í´
+U+d435 pwaeb # Character íµ
+U+d436 pwaebs # Character í¶
+U+d437 pwaes # Character í·
+U+d438 pwaess # Character í¸
+U+d439 pwaeng # Character í¹
+U+d43a pwaej # Character íº
+U+d43b pwaech # Character í»
+U+d43c pwaek # Character í¼
+U+d43d pwaet # Character í½
+U+d43e pwaep # Character í¾
+U+d43f pwaeh # Character í¿
+U+d440 poe # Character í
+U+d441 poeg # Character í
+U+d442 poekk # Character í
+U+d443 poegs # Character í
+U+d444 poen # Character í
+U+d445 poenj # Character í
+U+d446 poenh # Character í
+U+d447 poed # Character í
+U+d448 poel # Character í
+U+d449 poelg # Character í
+U+d44a poelm # Character í
+U+d44b poelb # Character í
+U+d44c poels # Character í
+U+d44d poelt # Character í
+U+d44e poelp # Character í
+U+d44f poelh # Character í
+U+d450 poem # Character í
+U+d451 poeb # Character í
+U+d452 poebs # Character í
+U+d453 poes # Character í
+U+d454 poess # Character í
+U+d455 poeng # Character í
+U+d456 poej # Character í
+U+d457 poech # Character í
+U+d458 poek # Character í
+U+d459 poet # Character í
+U+d45a poep # Character í
+U+d45b poeh # Character í
+U+d45c pyo # Character í
+U+d45d pyog # Character í
+U+d45e pyokk # Character í
+U+d45f pyogs # Character í
+U+d460 pyon # Character í
+U+d461 pyonj # Character í¡
+U+d462 pyonh # Character í¢
+U+d463 pyod # Character í£
+U+d464 pyol # Character í¤
+U+d465 pyolg # Character í¥
+U+d466 pyolm # Character í¦
+U+d467 pyolb # Character í§
+U+d468 pyols # Character í¨
+U+d469 pyolt # Character í©
+U+d46a pyolp # Character íª
+U+d46b pyolh # Character í«
+U+d46c pyom # Character í¬
+U+d46d pyob # Character í
+U+d46e pyobs # Character í®
+U+d46f pyos # Character í¯
+U+d470 pyoss # Character í°
+U+d471 pyong # Character í±
+U+d472 pyoj # Character í²
+U+d473 pyoch # Character í³
+U+d474 pyok # Character í´
+U+d475 pyot # Character íµ
+U+d476 pyop # Character í¶
+U+d477 pyoh # Character í·
+U+d478 pu # Character í¸
+U+d479 pug # Character í¹
+U+d47a pukk # Character íº
+U+d47b pugs # Character í»
+U+d47c pun # Character í¼
+U+d47d punj # Character í½
+U+d47e punh # Character í¾
+U+d47f pud # Character í¿
+U+d480 pul # Character í
+U+d481 pulg # Character í
+U+d482 pulm # Character í
+U+d483 pulb # Character í
+U+d484 puls # Character í
+U+d485 pult # Character í
+U+d486 pulp # Character í
+U+d487 pulh # Character í
+U+d488 pum # Character í
+U+d489 pub # Character í
+U+d48a pubs # Character í
+U+d48b pus # Character í
+U+d48c puss # Character í
+U+d48d pung # Character í
+U+d48e puj # Character í
+U+d48f puch # Character í
+U+d490 puk # Character í
+U+d491 put # Character í
+U+d492 pup # Character í
+U+d493 puh # Character í
+U+d494 pwo # Character í
+U+d495 pwog # Character í
+U+d496 pwokk # Character í
+U+d497 pwogs # Character í
+U+d498 pwon # Character í
+U+d499 pwonj # Character í
+U+d49a pwonh # Character í
+U+d49b pwod # Character í
+U+d49c pwol # Character í
+U+d49d pwolg # Character í
+U+d49e pwolm # Character í
+U+d49f pwolb # Character í
+U+d4a0 pwols # Character í
+U+d4a1 pwolt # Character í¡
+U+d4a2 pwolp # Character í¢
+U+d4a3 pwolh # Character í£
+U+d4a4 pwom # Character í¤
+U+d4a5 pwob # Character í¥
+U+d4a6 pwobs # Character í¦
+U+d4a7 pwos # Character í§
+U+d4a8 pwoss # Character í¨
+U+d4a9 pwong # Character í©
+U+d4aa pwoj # Character íª
+U+d4ab pwoch # Character í«
+U+d4ac pwok # Character í¬
+U+d4ad pwot # Character í
+U+d4ae pwop # Character í®
+U+d4af pwoh # Character í¯
+U+d4b0 pwe # Character í°
+U+d4b1 pweg # Character í±
+U+d4b2 pwekk # Character í²
+U+d4b3 pwegs # Character í³
+U+d4b4 pwen # Character í´
+U+d4b5 pwenj # Character íµ
+U+d4b6 pwenh # Character í¶
+U+d4b7 pwed # Character í·
+U+d4b8 pwel # Character í¸
+U+d4b9 pwelg # Character í¹
+U+d4ba pwelm # Character íº
+U+d4bb pwelb # Character í»
+U+d4bc pwels # Character í¼
+U+d4bd pwelt # Character í½
+U+d4be pwelp # Character í¾
+U+d4bf pwelh # Character í¿
+U+d4c0 pwem # Character í
+U+d4c1 pweb # Character í
+U+d4c2 pwebs # Character í
+U+d4c3 pwes # Character í
+U+d4c4 pwess # Character í
+U+d4c5 pweng # Character í
+U+d4c6 pwej # Character í
+U+d4c7 pwech # Character í
+U+d4c8 pwek # Character í
+U+d4c9 pwet # Character í
+U+d4ca pwep # Character í
+U+d4cb pweh # Character í
+U+d4cc pwi # Character í
+U+d4cd pwig # Character í
+U+d4ce pwikk # Character í
+U+d4cf pwigs # Character í
+U+d4d0 pwin # Character í
+U+d4d1 pwinj # Character í
+U+d4d2 pwinh # Character í
+U+d4d3 pwid # Character í
+U+d4d4 pwil # Character í
+U+d4d5 pwilg # Character í
+U+d4d6 pwilm # Character í
+U+d4d7 pwilb # Character í
+U+d4d8 pwils # Character í
+U+d4d9 pwilt # Character í
+U+d4da pwilp # Character í
+U+d4db pwilh # Character í
+U+d4dc pwim # Character í
+U+d4dd pwib # Character í
+U+d4de pwibs # Character í
+U+d4df pwis # Character í
+U+d4e0 pwiss # Character í
+U+d4e1 pwing # Character í¡
+U+d4e2 pwij # Character í¢
+U+d4e3 pwich # Character í£
+U+d4e4 pwik # Character í¤
+U+d4e5 pwit # Character í¥
+U+d4e6 pwip # Character í¦
+U+d4e7 pwih # Character í§
+U+d4e8 pyu # Character í¨
+U+d4e9 pyug # Character í©
+U+d4ea pyukk # Character íª
+U+d4eb pyugs # Character í«
+U+d4ec pyun # Character í¬
+U+d4ed pyunj # Character í
+U+d4ee pyunh # Character í®
+U+d4ef pyud # Character í¯
+U+d4f0 pyul # Character í°
+U+d4f1 pyulg # Character í±
+U+d4f2 pyulm # Character í²
+U+d4f3 pyulb # Character í³
+U+d4f4 pyuls # Character í´
+U+d4f5 pyult # Character íµ
+U+d4f6 pyulp # Character í¶
+U+d4f7 pyulh # Character í·
+U+d4f8 pyum # Character í¸
+U+d4f9 pyub # Character í¹
+U+d4fa pyubs # Character íº
+U+d4fb pyus # Character í»
+U+d4fc pyuss # Character í¼
+U+d4fd pyung # Character í½
+U+d4fe pyuj # Character í¾
+U+d4ff pyuch # Character í¿
diff --git a/resources/chars/latin1/rowd5.trans b/resources/chars/latin1/rowd5.trans
new file mode 100644
index 0000000..4eef846
--- /dev/null
+++ b/resources/chars/latin1/rowd5.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+d500 pyuk # Character í
+U+d501 pyut # Character í
+U+d502 pyup # Character í
+U+d503 pyuh # Character í
+U+d504 peu # Character í
+U+d505 peug # Character í
+U+d506 peukk # Character í
+U+d507 peugs # Character í
+U+d508 peun # Character í
+U+d509 peunj # Character í
+U+d50a peunh # Character í
+U+d50b peud # Character í
+U+d50c peul # Character í
+U+d50d peulg # Character í
+U+d50e peulm # Character í
+U+d50f peulb # Character í
+U+d510 peuls # Character í
+U+d511 peult # Character í
+U+d512 peulp # Character í
+U+d513 peulh # Character í
+U+d514 peum # Character í
+U+d515 peub # Character í
+U+d516 peubs # Character í
+U+d517 peus # Character í
+U+d518 peuss # Character í
+U+d519 peung # Character í
+U+d51a peuj # Character í
+U+d51b peuch # Character í
+U+d51c peuk # Character í
+U+d51d peut # Character í
+U+d51e peup # Character í
+U+d51f peuh # Character í
+U+d520 pui # Character í
+U+d521 puig # Character í¡
+U+d522 puikk # Character í¢
+U+d523 puigs # Character í£
+U+d524 puin # Character í¤
+U+d525 puinj # Character í¥
+U+d526 puinh # Character í¦
+U+d527 puid # Character í§
+U+d528 puil # Character í¨
+U+d529 puilg # Character í©
+U+d52a puilm # Character íª
+U+d52b puilb # Character í«
+U+d52c puils # Character í¬
+U+d52d puilt # Character í
+U+d52e puilp # Character í®
+U+d52f puilh # Character í¯
+U+d530 puim # Character í°
+U+d531 puib # Character í±
+U+d532 puibs # Character í²
+U+d533 puis # Character í³
+U+d534 puiss # Character í´
+U+d535 puing # Character íµ
+U+d536 puij # Character í¶
+U+d537 puich # Character í·
+U+d538 puik # Character í¸
+U+d539 puit # Character í¹
+U+d53a puip # Character íº
+U+d53b puih # Character í»
+U+d53c pi # Character í¼
+U+d53d pig # Character í½
+U+d53e pikk # Character í¾
+U+d53f pigs # Character í¿
+U+d540 pin # Character í
+U+d541 pinj # Character í
+U+d542 pinh # Character í
+U+d543 pid # Character í
+U+d544 pil # Character í
+U+d545 pilg # Character í
+U+d546 pilm # Character í
+U+d547 pilb # Character í
+U+d548 pils # Character í
+U+d549 pilt # Character í
+U+d54a pilp # Character í
+U+d54b pilh # Character í
+U+d54c pim # Character í
+U+d54d pib # Character í
+U+d54e pibs # Character í
+U+d54f pis # Character í
+U+d550 piss # Character í
+U+d551 ping # Character í
+U+d552 pij # Character í
+U+d553 pich # Character í
+U+d554 pik # Character í
+U+d555 pit # Character í
+U+d556 pip # Character í
+U+d557 pih # Character í
+U+d558 ha # Character í
+U+d559 hag # Character í
+U+d55a hakk # Character í
+U+d55b hags # Character í
+U+d55c han # Character í
+U+d55d hanj # Character í
+U+d55e hanh # Character í
+U+d55f had # Character í
+U+d560 hal # Character í
+U+d561 halg # Character í¡
+U+d562 halm # Character í¢
+U+d563 halb # Character í£
+U+d564 hals # Character í¤
+U+d565 halt # Character í¥
+U+d566 halp # Character í¦
+U+d567 halh # Character í§
+U+d568 ham # Character í¨
+U+d569 hab # Character í©
+U+d56a habs # Character íª
+U+d56b has # Character í«
+U+d56c hass # Character í¬
+U+d56d hang # Character í
+U+d56e haj # Character í®
+U+d56f hach # Character í¯
+U+d570 hak # Character í°
+U+d571 hat # Character í±
+U+d572 hap # Character í²
+U+d573 hah # Character í³
+U+d574 hae # Character í´
+U+d575 haeg # Character íµ
+U+d576 haekk # Character í¶
+U+d577 haegs # Character í·
+U+d578 haen # Character í¸
+U+d579 haenj # Character í¹
+U+d57a haenh # Character íº
+U+d57b haed # Character í»
+U+d57c hael # Character í¼
+U+d57d haelg # Character í½
+U+d57e haelm # Character í¾
+U+d57f haelb # Character í¿
+U+d580 haels # Character í
+U+d581 haelt # Character í
+U+d582 haelp # Character í
+U+d583 haelh # Character í
+U+d584 haem # Character í
+U+d585 haeb # Character í
+U+d586 haebs # Character í
+U+d587 haes # Character í
+U+d588 haess # Character í
+U+d589 haeng # Character í
+U+d58a haej # Character í
+U+d58b haech # Character í
+U+d58c haek # Character í
+U+d58d haet # Character í
+U+d58e haep # Character í
+U+d58f haeh # Character í
+U+d590 hya # Character í
+U+d591 hyag # Character í
+U+d592 hyakk # Character í
+U+d593 hyags # Character í
+U+d594 hyan # Character í
+U+d595 hyanj # Character í
+U+d596 hyanh # Character í
+U+d597 hyad # Character í
+U+d598 hyal # Character í
+U+d599 hyalg # Character í
+U+d59a hyalm # Character í
+U+d59b hyalb # Character í
+U+d59c hyals # Character í
+U+d59d hyalt # Character í
+U+d59e hyalp # Character í
+U+d59f hyalh # Character í
+U+d5a0 hyam # Character í
+U+d5a1 hyab # Character í¡
+U+d5a2 hyabs # Character í¢
+U+d5a3 hyas # Character í£
+U+d5a4 hyass # Character í¤
+U+d5a5 hyang # Character í¥
+U+d5a6 hyaj # Character í¦
+U+d5a7 hyach # Character í§
+U+d5a8 hyak # Character í¨
+U+d5a9 hyat # Character í©
+U+d5aa hyap # Character íª
+U+d5ab hyah # Character í«
+U+d5ac hyae # Character í¬
+U+d5ad hyaeg # Character í
+U+d5ae hyaekk # Character í®
+U+d5af hyaegs # Character í¯
+U+d5b0 hyaen # Character í°
+U+d5b1 hyaenj # Character í±
+U+d5b2 hyaenh # Character í²
+U+d5b3 hyaed # Character í³
+U+d5b4 hyael # Character í´
+U+d5b5 hyaelg # Character íµ
+U+d5b6 hyaelm # Character í¶
+U+d5b7 hyaelb # Character í·
+U+d5b8 hyaels # Character í¸
+U+d5b9 hyaelt # Character í¹
+U+d5ba hyaelp # Character íº
+U+d5bb hyaelh # Character í»
+U+d5bc hyaem # Character í¼
+U+d5bd hyaeb # Character í½
+U+d5be hyaebs # Character í¾
+U+d5bf hyaes # Character í¿
+U+d5c0 hyaess # Character í
+U+d5c1 hyaeng # Character í
+U+d5c2 hyaej # Character í
+U+d5c3 hyaech # Character í
+U+d5c4 hyaek # Character í
+U+d5c5 hyaet # Character í
+U+d5c6 hyaep # Character í
+U+d5c7 hyaeh # Character í
+U+d5c8 heo # Character í
+U+d5c9 heog # Character í
+U+d5ca heokk # Character í
+U+d5cb heogs # Character í
+U+d5cc heon # Character í
+U+d5cd heonj # Character í
+U+d5ce heonh # Character í
+U+d5cf heod # Character í
+U+d5d0 heol # Character í
+U+d5d1 heolg # Character í
+U+d5d2 heolm # Character í
+U+d5d3 heolb # Character í
+U+d5d4 heols # Character í
+U+d5d5 heolt # Character í
+U+d5d6 heolp # Character í
+U+d5d7 heolh # Character í
+U+d5d8 heom # Character í
+U+d5d9 heob # Character í
+U+d5da heobs # Character í
+U+d5db heos # Character í
+U+d5dc heoss # Character í
+U+d5dd heong # Character í
+U+d5de heoj # Character í
+U+d5df heoch # Character í
+U+d5e0 heok # Character í
+U+d5e1 heot # Character í¡
+U+d5e2 heop # Character í¢
+U+d5e3 heoh # Character í£
+U+d5e4 he # Character í¤
+U+d5e5 heg # Character í¥
+U+d5e6 hekk # Character í¦
+U+d5e7 hegs # Character í§
+U+d5e8 hen # Character í¨
+U+d5e9 henj # Character í©
+U+d5ea henh # Character íª
+U+d5eb hed # Character í«
+U+d5ec hel # Character í¬
+U+d5ed helg # Character í
+U+d5ee helm # Character í®
+U+d5ef helb # Character í¯
+U+d5f0 hels # Character í°
+U+d5f1 helt # Character í±
+U+d5f2 help # Character í²
+U+d5f3 helh # Character í³
+U+d5f4 hem # Character í´
+U+d5f5 heb # Character íµ
+U+d5f6 hebs # Character í¶
+U+d5f7 hes # Character í·
+U+d5f8 hess # Character í¸
+U+d5f9 heng # Character í¹
+U+d5fa hej # Character íº
+U+d5fb hech # Character í»
+U+d5fc hek # Character í¼
+U+d5fd het # Character í½
+U+d5fe hep # Character í¾
+U+d5ff heh # Character í¿
diff --git a/resources/chars/latin1/rowd6.trans b/resources/chars/latin1/rowd6.trans
new file mode 100644
index 0000000..a664cbd
--- /dev/null
+++ b/resources/chars/latin1/rowd6.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+d600 hyeo # Character í
+U+d601 hyeog # Character í
+U+d602 hyeokk # Character í
+U+d603 hyeogs # Character í
+U+d604 hyeon # Character í
+U+d605 hyeonj # Character í
+U+d606 hyeonh # Character í
+U+d607 hyeod # Character í
+U+d608 hyeol # Character í
+U+d609 hyeolg # Character í
+U+d60a hyeolm # Character í
+U+d60b hyeolb # Character í
+U+d60c hyeols # Character í
+U+d60d hyeolt # Character í
+U+d60e hyeolp # Character í
+U+d60f hyeolh # Character í
+U+d610 hyeom # Character í
+U+d611 hyeob # Character í
+U+d612 hyeobs # Character í
+U+d613 hyeos # Character í
+U+d614 hyeoss # Character í
+U+d615 hyeong # Character í
+U+d616 hyeoj # Character í
+U+d617 hyeoch # Character í
+U+d618 hyeok # Character í
+U+d619 hyeot # Character í
+U+d61a hyeop # Character í
+U+d61b hyeoh # Character í
+U+d61c hye # Character í
+U+d61d hyeg # Character í
+U+d61e hyekk # Character í
+U+d61f hyegs # Character í
+U+d620 hyen # Character í
+U+d621 hyenj # Character í¡
+U+d622 hyenh # Character í¢
+U+d623 hyed # Character í£
+U+d624 hyel # Character í¤
+U+d625 hyelg # Character í¥
+U+d626 hyelm # Character í¦
+U+d627 hyelb # Character í§
+U+d628 hyels # Character í¨
+U+d629 hyelt # Character í©
+U+d62a hyelp # Character íª
+U+d62b hyelh # Character í«
+U+d62c hyem # Character í¬
+U+d62d hyeb # Character í
+U+d62e hyebs # Character í®
+U+d62f hyes # Character í¯
+U+d630 hyess # Character í°
+U+d631 hyeng # Character í±
+U+d632 hyej # Character í²
+U+d633 hyech # Character í³
+U+d634 hyek # Character í´
+U+d635 hyet # Character íµ
+U+d636 hyep # Character í¶
+U+d637 hyeh # Character í·
+U+d638 ho # Character í¸
+U+d639 hog # Character í¹
+U+d63a hokk # Character íº
+U+d63b hogs # Character í»
+U+d63c hon # Character í¼
+U+d63d honj # Character í½
+U+d63e honh # Character í¾
+U+d63f hod # Character í¿
+U+d640 hol # Character í
+U+d641 holg # Character í
+U+d642 holm # Character í
+U+d643 holb # Character í
+U+d644 hols # Character í
+U+d645 holt # Character í
+U+d646 holp # Character í
+U+d647 holh # Character í
+U+d648 hom # Character í
+U+d649 hob # Character í
+U+d64a hobs # Character í
+U+d64b hos # Character í
+U+d64c hoss # Character í
+U+d64d hong # Character í
+U+d64e hoj # Character í
+U+d64f hoch # Character í
+U+d650 hok # Character í
+U+d651 hot # Character í
+U+d652 hop # Character í
+U+d653 hoh # Character í
+U+d654 hwa # Character í
+U+d655 hwag # Character í
+U+d656 hwakk # Character í
+U+d657 hwags # Character í
+U+d658 hwan # Character í
+U+d659 hwanj # Character í
+U+d65a hwanh # Character í
+U+d65b hwad # Character í
+U+d65c hwal # Character í
+U+d65d hwalg # Character í
+U+d65e hwalm # Character í
+U+d65f hwalb # Character í
+U+d660 hwals # Character í
+U+d661 hwalt # Character í¡
+U+d662 hwalp # Character í¢
+U+d663 hwalh # Character í£
+U+d664 hwam # Character í¤
+U+d665 hwab # Character í¥
+U+d666 hwabs # Character í¦
+U+d667 hwas # Character í§
+U+d668 hwass # Character í¨
+U+d669 hwang # Character í©
+U+d66a hwaj # Character íª
+U+d66b hwach # Character í«
+U+d66c hwak # Character í¬
+U+d66d hwat # Character í
+U+d66e hwap # Character í®
+U+d66f hwah # Character í¯
+U+d670 hwae # Character í°
+U+d671 hwaeg # Character í±
+U+d672 hwaekk # Character í²
+U+d673 hwaegs # Character í³
+U+d674 hwaen # Character í´
+U+d675 hwaenj # Character íµ
+U+d676 hwaenh # Character í¶
+U+d677 hwaed # Character í·
+U+d678 hwael # Character í¸
+U+d679 hwaelg # Character í¹
+U+d67a hwaelm # Character íº
+U+d67b hwaelb # Character í»
+U+d67c hwaels # Character í¼
+U+d67d hwaelt # Character í½
+U+d67e hwaelp # Character í¾
+U+d67f hwaelh # Character í¿
+U+d680 hwaem # Character í
+U+d681 hwaeb # Character í
+U+d682 hwaebs # Character í
+U+d683 hwaes # Character í
+U+d684 hwaess # Character í
+U+d685 hwaeng # Character í
+U+d686 hwaej # Character í
+U+d687 hwaech # Character í
+U+d688 hwaek # Character í
+U+d689 hwaet # Character í
+U+d68a hwaep # Character í
+U+d68b hwaeh # Character í
+U+d68c hoe # Character í
+U+d68d hoeg # Character í
+U+d68e hoekk # Character í
+U+d68f hoegs # Character í
+U+d690 hoen # Character í
+U+d691 hoenj # Character í
+U+d692 hoenh # Character í
+U+d693 hoed # Character í
+U+d694 hoel # Character í
+U+d695 hoelg # Character í
+U+d696 hoelm # Character í
+U+d697 hoelb # Character í
+U+d698 hoels # Character í
+U+d699 hoelt # Character í
+U+d69a hoelp # Character í
+U+d69b hoelh # Character í
+U+d69c hoem # Character í
+U+d69d hoeb # Character í
+U+d69e hoebs # Character í
+U+d69f hoes # Character í
+U+d6a0 hoess # Character í
+U+d6a1 hoeng # Character í¡
+U+d6a2 hoej # Character í¢
+U+d6a3 hoech # Character í£
+U+d6a4 hoek # Character í¤
+U+d6a5 hoet # Character í¥
+U+d6a6 hoep # Character í¦
+U+d6a7 hoeh # Character í§
+U+d6a8 hyo # Character í¨
+U+d6a9 hyog # Character í©
+U+d6aa hyokk # Character íª
+U+d6ab hyogs # Character í«
+U+d6ac hyon # Character í¬
+U+d6ad hyonj # Character í
+U+d6ae hyonh # Character í®
+U+d6af hyod # Character í¯
+U+d6b0 hyol # Character í°
+U+d6b1 hyolg # Character í±
+U+d6b2 hyolm # Character í²
+U+d6b3 hyolb # Character í³
+U+d6b4 hyols # Character í´
+U+d6b5 hyolt # Character íµ
+U+d6b6 hyolp # Character í¶
+U+d6b7 hyolh # Character í·
+U+d6b8 hyom # Character í¸
+U+d6b9 hyob # Character í¹
+U+d6ba hyobs # Character íº
+U+d6bb hyos # Character í»
+U+d6bc hyoss # Character í¼
+U+d6bd hyong # Character í½
+U+d6be hyoj # Character í¾
+U+d6bf hyoch # Character í¿
+U+d6c0 hyok # Character í
+U+d6c1 hyot # Character í
+U+d6c2 hyop # Character í
+U+d6c3 hyoh # Character í
+U+d6c4 hu # Character í
+U+d6c5 hug # Character í
+U+d6c6 hukk # Character í
+U+d6c7 hugs # Character í
+U+d6c8 hun # Character í
+U+d6c9 hunj # Character í
+U+d6ca hunh # Character í
+U+d6cb hud # Character í
+U+d6cc hul # Character í
+U+d6cd hulg # Character í
+U+d6ce hulm # Character í
+U+d6cf hulb # Character í
+U+d6d0 huls # Character í
+U+d6d1 hult # Character í
+U+d6d2 hulp # Character í
+U+d6d3 hulh # Character í
+U+d6d4 hum # Character í
+U+d6d5 hub # Character í
+U+d6d6 hubs # Character í
+U+d6d7 hus # Character í
+U+d6d8 huss # Character í
+U+d6d9 hung # Character í
+U+d6da huj # Character í
+U+d6db huch # Character í
+U+d6dc huk # Character í
+U+d6dd hut # Character í
+U+d6de hup # Character í
+U+d6df huh # Character í
+U+d6e0 hwo # Character í
+U+d6e1 hwog # Character í¡
+U+d6e2 hwokk # Character í¢
+U+d6e3 hwogs # Character í£
+U+d6e4 hwon # Character í¤
+U+d6e5 hwonj # Character í¥
+U+d6e6 hwonh # Character í¦
+U+d6e7 hwod # Character í§
+U+d6e8 hwol # Character í¨
+U+d6e9 hwolg # Character í©
+U+d6ea hwolm # Character íª
+U+d6eb hwolb # Character í«
+U+d6ec hwols # Character í¬
+U+d6ed hwolt # Character í
+U+d6ee hwolp # Character í®
+U+d6ef hwolh # Character í¯
+U+d6f0 hwom # Character í°
+U+d6f1 hwob # Character í±
+U+d6f2 hwobs # Character í²
+U+d6f3 hwos # Character í³
+U+d6f4 hwoss # Character í´
+U+d6f5 hwong # Character íµ
+U+d6f6 hwoj # Character í¶
+U+d6f7 hwoch # Character í·
+U+d6f8 hwok # Character í¸
+U+d6f9 hwot # Character í¹
+U+d6fa hwop # Character íº
+U+d6fb hwoh # Character í»
+U+d6fc hwe # Character í¼
+U+d6fd hweg # Character í½
+U+d6fe hwekk # Character í¾
+U+d6ff hwegs # Character í¿
diff --git a/resources/chars/latin1/rowd7.trans b/resources/chars/latin1/rowd7.trans
new file mode 100644
index 0000000..7508941
--- /dev/null
+++ b/resources/chars/latin1/rowd7.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+d700 hwen # Character í
+U+d701 hwenj # Character í
+U+d702 hwenh # Character í
+U+d703 hwed # Character í
+U+d704 hwel # Character í
+U+d705 hwelg # Character í
+U+d706 hwelm # Character í
+U+d707 hwelb # Character í
+U+d708 hwels # Character í
+U+d709 hwelt # Character í
+U+d70a hwelp # Character í
+U+d70b hwelh # Character í
+U+d70c hwem # Character í
+U+d70d hweb # Character í
+U+d70e hwebs # Character í
+U+d70f hwes # Character í
+U+d710 hwess # Character í
+U+d711 hweng # Character í
+U+d712 hwej # Character í
+U+d713 hwech # Character í
+U+d714 hwek # Character í
+U+d715 hwet # Character í
+U+d716 hwep # Character í
+U+d717 hweh # Character í
+U+d718 hwi # Character í
+U+d719 hwig # Character í
+U+d71a hwikk # Character í
+U+d71b hwigs # Character í
+U+d71c hwin # Character í
+U+d71d hwinj # Character í
+U+d71e hwinh # Character í
+U+d71f hwid # Character í
+U+d720 hwil # Character í
+U+d721 hwilg # Character í¡
+U+d722 hwilm # Character í¢
+U+d723 hwilb # Character í£
+U+d724 hwils # Character í¤
+U+d725 hwilt # Character í¥
+U+d726 hwilp # Character í¦
+U+d727 hwilh # Character í§
+U+d728 hwim # Character í¨
+U+d729 hwib # Character í©
+U+d72a hwibs # Character íª
+U+d72b hwis # Character í«
+U+d72c hwiss # Character í¬
+U+d72d hwing # Character í
+U+d72e hwij # Character í®
+U+d72f hwich # Character í¯
+U+d730 hwik # Character í°
+U+d731 hwit # Character í±
+U+d732 hwip # Character í²
+U+d733 hwih # Character í³
+U+d734 hyu # Character í´
+U+d735 hyug # Character íµ
+U+d736 hyukk # Character í¶
+U+d737 hyugs # Character í·
+U+d738 hyun # Character í¸
+U+d739 hyunj # Character í¹
+U+d73a hyunh # Character íº
+U+d73b hyud # Character í»
+U+d73c hyul # Character í¼
+U+d73d hyulg # Character í½
+U+d73e hyulm # Character í¾
+U+d73f hyulb # Character í¿
+U+d740 hyuls # Character í
+U+d741 hyult # Character í
+U+d742 hyulp # Character í
+U+d743 hyulh # Character í
+U+d744 hyum # Character í
+U+d745 hyub # Character í
+U+d746 hyubs # Character í
+U+d747 hyus # Character í
+U+d748 hyuss # Character í
+U+d749 hyung # Character í
+U+d74a hyuj # Character í
+U+d74b hyuch # Character í
+U+d74c hyuk # Character í
+U+d74d hyut # Character í
+U+d74e hyup # Character í
+U+d74f hyuh # Character í
+U+d750 heu # Character í
+U+d751 heug # Character í
+U+d752 heukk # Character í
+U+d753 heugs # Character í
+U+d754 heun # Character í
+U+d755 heunj # Character í
+U+d756 heunh # Character í
+U+d757 heud # Character í
+U+d758 heul # Character í
+U+d759 heulg # Character í
+U+d75a heulm # Character í
+U+d75b heulb # Character í
+U+d75c heuls # Character í
+U+d75d heult # Character í
+U+d75e heulp # Character í
+U+d75f heulh # Character í
+U+d760 heum # Character í
+U+d761 heub # Character í¡
+U+d762 heubs # Character í¢
+U+d763 heus # Character í£
+U+d764 heuss # Character í¤
+U+d765 heung # Character í¥
+U+d766 heuj # Character í¦
+U+d767 heuch # Character í§
+U+d768 heuk # Character í¨
+U+d769 heut # Character í©
+U+d76a heup # Character íª
+U+d76b heuh # Character í«
+U+d76c hui # Character í¬
+U+d76d huig # Character í
+U+d76e huikk # Character í®
+U+d76f huigs # Character í¯
+U+d770 huin # Character í°
+U+d771 huinj # Character í±
+U+d772 huinh # Character í²
+U+d773 huid # Character í³
+U+d774 huil # Character í´
+U+d775 huilg # Character íµ
+U+d776 huilm # Character í¶
+U+d777 huilb # Character í·
+U+d778 huils # Character í¸
+U+d779 huilt # Character í¹
+U+d77a huilp # Character íº
+U+d77b huilh # Character í»
+U+d77c huim # Character í¼
+U+d77d huib # Character í½
+U+d77e huibs # Character í¾
+U+d77f huis # Character í¿
+U+d780 huiss # Character í
+U+d781 huing # Character í
+U+d782 huij # Character í
+U+d783 huich # Character í
+U+d784 huik # Character í
+U+d785 huit # Character í
+U+d786 huip # Character í
+U+d787 huih # Character í
+U+d788 hi # Character í
+U+d789 hig # Character í
+U+d78a hikk # Character í
+U+d78b higs # Character í
+U+d78c hin # Character í
+U+d78d hinj # Character í
+U+d78e hinh # Character í
+U+d78f hid # Character í
+U+d790 hil # Character í
+U+d791 hilg # Character í
+U+d792 hilm # Character í
+U+d793 hilb # Character í
+U+d794 hils # Character í
+U+d795 hilt # Character í
+U+d796 hilp # Character í
+U+d797 hilh # Character í
+U+d798 him # Character í
+U+d799 hib # Character í
+U+d79a hibs # Character í
+U+d79b his # Character í
+U+d79c hiss # Character í
+U+d79d hing # Character í
+U+d79e hij # Character í
+U+d79f hich # Character í
+U+d7a0 hik # Character í
+U+d7a1 hit # Character í¡
+U+d7a2 hip # Character í¢
+U+d7a3 hih # Character í£
+U+d7a4 ? # Character í¤
+U+d7a5 ? # Character í¥
+U+d7a6 ? # Character í¦
+U+d7a7 ? # Character í§
+U+d7a8 ? # Character í¨
+U+d7a9 ? # Character í©
+U+d7aa ? # Character íª
+U+d7ab ? # Character í«
+U+d7ac ? # Character í¬
+U+d7ad ? # Character í
+U+d7ae ? # Character í®
+U+d7af ? # Character í¯
+U+d7b0 ? # Character í°
+U+d7b1 ? # Character í±
+U+d7b2 ? # Character í²
+U+d7b3 ? # Character í³
+U+d7b4 ? # Character í´
+U+d7b5 ? # Character íµ
+U+d7b6 ? # Character í¶
+U+d7b7 ? # Character í·
+U+d7b8 ? # Character í¸
+U+d7b9 ? # Character í¹
+U+d7ba ? # Character íº
+U+d7bb ? # Character í»
+U+d7bc ? # Character í¼
+U+d7bd ? # Character í½
+U+d7be ? # Character í¾
+U+d7bf ? # Character í¿
+U+d7c0 ? # Character í
+U+d7c1 ? # Character í
+U+d7c2 ? # Character í
+U+d7c3 ? # Character í
+U+d7c4 ? # Character í
+U+d7c5 ? # Character í
+U+d7c6 ? # Character í
+U+d7c7 ? # Character í
+U+d7c8 ? # Character í
+U+d7c9 ? # Character í
+U+d7ca ? # Character í
+U+d7cb ? # Character í
+U+d7cc ? # Character í
+U+d7cd ? # Character í
+U+d7ce ? # Character í
+U+d7cf ? # Character í
+U+d7d0 ? # Character í
+U+d7d1 ? # Character í
+U+d7d2 ? # Character í
+U+d7d3 ? # Character í
+U+d7d4 ? # Character í
+U+d7d5 ? # Character í
+U+d7d6 ? # Character í
+U+d7d7 ? # Character í
+U+d7d8 ? # Character í
+U+d7d9 ? # Character í
+U+d7da ? # Character í
+U+d7db ? # Character í
+U+d7dc ? # Character í
+U+d7dd ? # Character í
+U+d7de ? # Character í
+U+d7df ? # Character í
+U+d7e0 ? # Character í
+U+d7e1 ? # Character í¡
+U+d7e2 ? # Character í¢
+U+d7e3 ? # Character í£
+U+d7e4 ? # Character í¤
+U+d7e5 ? # Character í¥
+U+d7e6 ? # Character í¦
+U+d7e7 ? # Character í§
+U+d7e8 ? # Character í¨
+U+d7e9 ? # Character í©
+U+d7ea ? # Character íª
+U+d7eb ? # Character í«
+U+d7ec ? # Character í¬
+U+d7ed ? # Character í
+U+d7ee ? # Character í®
+U+d7ef ? # Character í¯
+U+d7f0 ? # Character í°
+U+d7f1 ? # Character í±
+U+d7f2 ? # Character í²
+U+d7f3 ? # Character í³
+U+d7f4 ? # Character í´
+U+d7f5 ? # Character íµ
+U+d7f6 ? # Character í¶
+U+d7f7 ? # Character í·
+U+d7f8 ? # Character í¸
+U+d7f9 ? # Character í¹
+U+d7fa ? # Character íº
+U+d7fb ? # Character í»
+U+d7fc ? # Character í¼
+U+d7fd ? # Character í½
+U+d7fe ? # Character í¾
+U+d7ff ? # Character í¿
diff --git a/resources/chars/latin1/rowf9.trans b/resources/chars/latin1/rowf9.trans
new file mode 100644
index 0000000..746335d
--- /dev/null
+++ b/resources/chars/latin1/rowf9.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+f900 ? # Character ï¤
+U+f901 ? # Character ï¤
+U+f902 ? # Character ï¤
+U+f903 ? # Character ï¤
+U+f904 ? # Character ï¤
+U+f905 ? # Character ï¤
+U+f906 ? # Character ï¤
+U+f907 ? # Character ï¤
+U+f908 ? # Character ï¤
+U+f909 ? # Character ï¤
+U+f90a ? # Character ï¤
+U+f90b ? # Character ï¤
+U+f90c ? # Character ï¤
+U+f90d ? # Character ï¤
+U+f90e là # Character ï¤
+U+f90f ? # Character ï¤
+U+f910 ? # Character ï¤
+U+f911 ? # Character ï¤
+U+f912 ? # Character ï¤
+U+f913 ? # Character ï¤
+U+f914 ? # Character ï¤
+U+f915 ? # Character ï¤
+U+f916 ? # Character ï¤
+U+f917 ? # Character ï¤
+U+f918 ? # Character ï¤
+U+f919 ? # Character ï¤
+U+f91a ? # Character ï¤
+U+f91b ? # Character ï¤
+U+f91c ? # Character ï¤
+U+f91d ? # Character ï¤
+U+f91e ? # Character ï¤
+U+f91f ? # Character ï¤
+U+f920 ? # Character ï¤
+U+f921 ? # Character 嵐
+U+f922 ? # Character 濫
+U+f923 ? # Character 藍
+U+f924 ? # Character 襤
+U+f925 ? # Character 拉
+U+f926 ? # Character 臘
+U+f927 ? # Character 蠟
+U+f928 ? # Character 廊
+U+f929 ? # Character 朗
+U+f92a ? # Character 浪
+U+f92b ? # Character 狼
+U+f92c ? # Character 郎
+U+f92d ? # Character ï¤
+U+f92e ? # Character 冷
+U+f92f ? # Character 勞
+U+f930 ? # Character 擄
+U+f931 ? # Character 櫓
+U+f932 ? # Character 爐
+U+f933 ? # Character 盧
+U+f934 ? # Character 老
+U+f935 ? # Character 蘆
+U+f936 ? # Character 虜
+U+f937 ? # Character 路
+U+f938 ? # Character 露
+U+f939 ? # Character 魯
+U+f93a ? # Character 鷺
+U+f93b ? # Character 碌
+U+f93c ? # Character 祿
+U+f93d ? # Character 綠
+U+f93e ? # Character 菉
+U+f93f ? # Character 錄
+U+f940 ? # Character ï¥
+U+f941 ? # Character ï¥
+U+f942 ? # Character ï¥
+U+f943 ? # Character ï¥
+U+f944 ? # Character ï¥
+U+f945 ? # Character ï¥
+U+f946 ? # Character ï¥
+U+f947 ? # Character ï¥
+U+f948 ? # Character ï¥
+U+f949 ? # Character ï¥
+U+f94a ? # Character ï¥
+U+f94b ? # Character ï¥
+U+f94c ? # Character ï¥
+U+f94d ? # Character ï¥
+U+f94e ? # Character ï¥
+U+f94f ? # Character ï¥
+U+f950 ? # Character ï¥
+U+f951 ? # Character ï¥
+U+f952 ? # Character ï¥
+U+f953 ? # Character ï¥
+U+f954 ? # Character ï¥
+U+f955 ? # Character ï¥
+U+f956 ? # Character ï¥
+U+f957 ? # Character ï¥
+U+f958 ? # Character ï¥
+U+f959 ? # Character ï¥
+U+f95a ? # Character ï¥
+U+f95b ? # Character ï¥
+U+f95c ? # Character ï¥
+U+f95d ? # Character ï¥
+U+f95e ? # Character ï¥
+U+f95f ? # Character ï¥
+U+f960 ? # Character ï¥
+U+f961 ? # Character 率
+U+f962 ? # Character 異
+U+f963 ? # Character 北
+U+f964 ? # Character 磻
+U+f965 ? # Character 便
+U+f966 ? # Character 復
+U+f967 ? # Character 不
+U+f968 ? # Character 泌
+U+f969 ? # Character 數
+U+f96a ? # Character 索
+U+f96b ? # Character 參
+U+f96c ? # Character 塞
+U+f96d ? # Character ï¥
+U+f96e ? # Character 葉
+U+f96f ? # Character 說
+U+f970 ? # Character 殺
+U+f971 ? # Character 辰
+U+f972 ? # Character 沈
+U+f973 ? # Character 拾
+U+f974 ? # Character 若
+U+f975 ? # Character 掠
+U+f976 ? # Character 略
+U+f977 ? # Character 亮
+U+f978 ? # Character 兩
+U+f979 ? # Character 凉
+U+f97a ? # Character 梁
+U+f97b ? # Character 糧
+U+f97c ? # Character 良
+U+f97d ? # Character 諒
+U+f97e ? # Character 量
+U+f97f ? # Character 勵
+U+f980 ? # Character ï¦
+U+f981 ? # Character ï¦
+U+f982 ? # Character ï¦
+U+f983 ? # Character ï¦
+U+f984 ? # Character ï¦
+U+f985 ? # Character ï¦
+U+f986 ? # Character ï¦
+U+f987 ? # Character ï¦
+U+f988 ? # Character ï¦
+U+f989 ? # Character ï¦
+U+f98a ? # Character ï¦
+U+f98b ? # Character ï¦
+U+f98c ? # Character ï¦
+U+f98d ? # Character ï¦
+U+f98e ? # Character ï¦
+U+f98f ? # Character ï¦
+U+f990 ? # Character ï¦
+U+f991 ? # Character ï¦
+U+f992 ? # Character ï¦
+U+f993 ? # Character ï¦
+U+f994 ? # Character ï¦
+U+f995 ? # Character ï¦
+U+f996 ? # Character ï¦
+U+f997 ? # Character ï¦
+U+f998 ? # Character ï¦
+U+f999 ? # Character ï¦
+U+f99a ? # Character ï¦
+U+f99b ? # Character ï¦
+U+f99c ? # Character ï¦
+U+f99d ? # Character ï¦
+U+f99e ? # Character ï¦
+U+f99f ? # Character ï¦
+U+f9a0 ? # Character ï¦
+U+f9a1 ? # Character 說
+U+f9a2 ? # Character 廉
+U+f9a3 ? # Character 念
+U+f9a4 ? # Character 捻
+U+f9a5 ? # Character 殮
+U+f9a6 ? # Character 簾
+U+f9a7 ? # Character 獵
+U+f9a8 ? # Character 令
+U+f9a9 ? # Character 囹
+U+f9aa ? # Character 寧
+U+f9ab ? # Character 嶺
+U+f9ac ? # Character 怜
+U+f9ad ? # Character ï¦
+U+f9ae ? # Character 瑩
+U+f9af ? # Character 羚
+U+f9b0 ? # Character 聆
+U+f9b1 ? # Character 鈴
+U+f9b2 ? # Character 零
+U+f9b3 ? # Character 靈
+U+f9b4 ? # Character 領
+U+f9b5 ? # Character 例
+U+f9b6 ? # Character 禮
+U+f9b7 ? # Character 醴
+U+f9b8 ? # Character 隸
+U+f9b9 ? # Character 惡
+U+f9ba ? # Character 了
+U+f9bb ? # Character 僚
+U+f9bc ? # Character 寮
+U+f9bd ? # Character 尿
+U+f9be ? # Character 料
+U+f9bf ? # Character 樂
+U+f9c0 ? # Character ï§
+U+f9c1 ? # Character ï§
+U+f9c2 ? # Character ï§
+U+f9c3 ? # Character ï§
+U+f9c4 ? # Character ï§
+U+f9c5 ? # Character ï§
+U+f9c6 ? # Character ï§
+U+f9c7 ? # Character ï§
+U+f9c8 ? # Character ï§
+U+f9c9 ? # Character ï§
+U+f9ca ? # Character ï§
+U+f9cb ? # Character ï§
+U+f9cc ? # Character ï§
+U+f9cd ? # Character ï§
+U+f9ce ? # Character ï§
+U+f9cf ? # Character ï§
+U+f9d0 ? # Character ï§
+U+f9d1 ? # Character ï§
+U+f9d2 ? # Character ï§
+U+f9d3 ? # Character ï§
+U+f9d4 ? # Character ï§
+U+f9d5 ? # Character ï§
+U+f9d6 ? # Character ï§
+U+f9d7 ? # Character ï§
+U+f9d8 ? # Character ï§
+U+f9d9 ? # Character ï§
+U+f9da ? # Character ï§
+U+f9db ? # Character ï§
+U+f9dc ? # Character ï§
+U+f9dd ? # Character ï§
+U+f9de ? # Character ï§
+U+f9df ? # Character ï§
+U+f9e0 ? # Character ï§
+U+f9e1 ? # Character 李
+U+f9e2 ? # Character 梨
+U+f9e3 ? # Character 泥
+U+f9e4 ? # Character 理
+U+f9e5 ? # Character 痢
+U+f9e6 ? # Character 罹
+U+f9e7 ? # Character 裏
+U+f9e8 ? # Character 裡
+U+f9e9 ? # Character 里
+U+f9ea ? # Character 離
+U+f9eb ? # Character 匿
+U+f9ec ? # Character 溺
+U+f9ed ? # Character ï§
+U+f9ee ? # Character 燐
+U+f9ef ? # Character 璘
+U+f9f0 ? # Character 藺
+U+f9f1 ? # Character 隣
+U+f9f2 ? # Character 鱗
+U+f9f3 ? # Character 麟
+U+f9f4 ? # Character 林
+U+f9f5 ? # Character 淋
+U+f9f6 ? # Character 臨
+U+f9f7 ? # Character 立
+U+f9f8 ? # Character 笠
+U+f9f9 ? # Character 粒
+U+f9fa ? # Character 狀
+U+f9fb ? # Character 炙
+U+f9fc ? # Character 識
+U+f9fd ? # Character 什
+U+f9fe ? # Character 茶
+U+f9ff ? # Character 刺
diff --git a/resources/chars/latin1/rowfa.trans b/resources/chars/latin1/rowfa.trans
new file mode 100644
index 0000000..3777a19
--- /dev/null
+++ b/resources/chars/latin1/rowfa.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+fa00 ? # Character ï¨
+U+fa01 ? # Character ï¨
+U+fa02 ? # Character ï¨
+U+fa03 ? # Character ï¨
+U+fa04 ? # Character ï¨
+U+fa05 ? # Character ï¨
+U+fa06 ? # Character ï¨
+U+fa07 ? # Character ï¨
+U+fa08 ? # Character ï¨
+U+fa09 ? # Character ï¨
+U+fa0a ? # Character ï¨
+U+fa0b ? # Character ï¨
+U+fa0c wù # Character ï¨
+U+fa0d huò # Character ï¨
+U+fa0e ? # Character ï¨
+U+fa0f ? # Character ï¨
+#U+fa10 zhÇng # Character ï¨
+U+fa11 ? # Character ï¨
+U+fa12 qÃng # Character ï¨
+U+fa13 ? # Character ï¨
+U+fa14 ? # Character ï¨
+#U+fa15 xÄ« # Character ï¨
+#U+fa16 zhÅ« # Character ï¨
+U+fa17 yì # Character ï¨
+#U+fa18 lÇ # Character ï¨
+U+fa19 shén # Character ï¨
+U+fa1a xiáng # Character ï¨
+U+fa1b fú # Character ï¨
+U+fa1c jìng # Character ï¨
+#U+fa1d jÄ«ng # Character ï¨
+#U+fa1e yÇ # Character ï¨
+U+fa1f ? # Character ï¨
+U+fa20 ? # Character ï¨
+U+fa21 ? # Character 﨡
+#U+fa22 zhū # Character 諸
+U+fa23 ? # Character 﨣
+U+fa24 ? # Character 﨤
+U+fa25 yì # Character 逸
+#U+fa26 dū # Character 都
+U+fa27 ? # Character 﨧
+U+fa28 ? # Character 﨨
+U+fa29 ? # Character 﨩
+U+fa2a fà n # Character 飯
+U+fa2b sì # Character 飼
+#U+fa2c guÇn # Character 館
+U+fa2d hè # Character ï¨
+U+fa2e ? # Character 郞
+U+fa2f ? # Character 隷
+U+fa30 ? # Character 侮
+U+fa31 ? # Character 僧
+U+fa32 ? # Character 免
+U+fa33 ? # Character 勉
+U+fa34 ? # Character 勤
+U+fa35 ? # Character 卑
+U+fa36 ? # Character 喝
+U+fa37 ? # Character 嘆
+U+fa38 ? # Character 器
+U+fa39 ? # Character 塀
+U+fa3a ? # Character 墨
+U+fa3b ? # Character 層
+U+fa3c ? # Character 屮
+U+fa3d ? # Character 悔
+U+fa3e ? # Character 慨
+U+fa3f ? # Character 憎
+U+fa40 ? # Character ï©
+U+fa41 ? # Character ï©
+U+fa42 ? # Character ï©
+U+fa43 ? # Character ï©
+U+fa44 ? # Character ï©
+U+fa45 ? # Character ï©
+U+fa46 ? # Character ï©
+U+fa47 ? # Character ï©
+U+fa48 ? # Character ï©
+U+fa49 ? # Character ï©
+U+fa4a ? # Character ï©
+U+fa4b ? # Character ï©
+U+fa4c ? # Character ï©
+U+fa4d ? # Character ï©
+U+fa4e ? # Character ï©
+U+fa4f ? # Character ï©
+U+fa50 ? # Character ï©
+U+fa51 ? # Character ï©
+U+fa52 ? # Character ï©
+U+fa53 ? # Character ï©
+U+fa54 ? # Character ï©
+U+fa55 ? # Character ï©
+U+fa56 ? # Character ï©
+U+fa57 ? # Character ï©
+U+fa58 ? # Character ï©
+U+fa59 ? # Character ï©
+U+fa5a ? # Character ï©
+U+fa5b ? # Character ï©
+U+fa5c ? # Character ï©
+U+fa5d ? # Character ï©
+U+fa5e ? # Character ï©
+U+fa5f ? # Character ï©
+U+fa60 ? # Character ï©
+U+fa61 ? # Character ï©¡
+U+fa62 ? # Character ï©¢
+U+fa63 ? # Character ï©£
+U+fa64 ? # Character 賓
+U+fa65 ? # Character ï©¥
+U+fa66 ? # Character 辶
+U+fa67 ? # Character 逸
+U+fa68 ? # Character 難
+U+fa69 ? # Character ï©©
+U+fa6a ? # Character 頻
+U+fa6b ? # Character ï©«
+U+fa6c ? # Character 𤋮
+U+fa6d ? # Character ï©
+U+fa6e ? # Character ï©®
+U+fa6f ? # Character 﩯
+U+fa70 ? # Character ï©°
+U+fa71 ? # Character 况
+U+fa72 ? # Character 全
+U+fa73 ? # Character 侀
+U+fa74 ? # Character ï©´
+U+fa75 ? # Character 冀
+U+fa76 ? # Character 勇
+U+fa77 ? # Character ï©·
+U+fa78 ? # Character 喝
+U+fa79 ? # Character 啕
+U+fa7a ? # Character 喙
+U+fa7b ? # Character ï©»
+U+fa7c ? # Character 塚
+U+fa7d ? # Character 墳
+U+fa7e ? # Character 奄
+U+fa7f ? # Character ï©¿
+U+fa80 ? # Character ïª
+U+fa81 ? # Character ïª
+U+fa82 ? # Character ïª
+U+fa83 ? # Character ïª
+U+fa84 ? # Character ïª
+U+fa85 ? # Character ïª
+U+fa86 ? # Character ïª
+U+fa87 ? # Character ïª
+U+fa88 ? # Character ïª
+U+fa89 ? # Character ïª
+U+fa8a ? # Character ïª
+U+fa8b ? # Character ïª
+U+fa8c ? # Character ïª
+U+fa8d ? # Character ïª
+U+fa8e ? # Character ïª
+U+fa8f ? # Character ïª
+U+fa90 ? # Character ïª
+U+fa91 ? # Character ïª
+U+fa92 ? # Character ïª
+U+fa93 ? # Character ïª
+U+fa94 ? # Character ïª
+U+fa95 ? # Character ïª
+U+fa96 ? # Character ïª
+U+fa97 ? # Character ïª
+U+fa98 ? # Character ïª
+U+fa99 ? # Character ïª
+U+fa9a ? # Character ïª
+U+fa9b ? # Character ïª
+U+fa9c ? # Character ïª
+U+fa9d ? # Character ïª
+U+fa9e ? # Character ïª
+U+fa9f ? # Character ïª
+U+faa0 ? # Character ïª
+U+faa1 ? # Character 瑱
+U+faa2 ? # Character 甆
+U+faa3 ? # Character 画
+U+faa4 ? # Character 瘝
+U+faa5 ? # Character 瘟
+U+faa6 ? # Character 益
+U+faa7 ? # Character 盛
+U+faa8 ? # Character 直
+U+faa9 ? # Character 睊
+U+faaa ? # Character 着
+U+faab ? # Character 磌
+U+faac ? # Character 窱
+U+faad ? # Character ïª
+U+faae ? # Character 类
+U+faaf ? # Character 絛
+U+fab0 ? # Character 練
+U+fab1 ? # Character 缾
+U+fab2 ? # Character 者
+U+fab3 ? # Character 荒
+U+fab4 ? # Character 華
+U+fab5 ? # Character 蝹
+U+fab6 ? # Character 襁
+U+fab7 ? # Character 覆
+U+fab8 ? # Character 視
+U+fab9 ? # Character 調
+U+faba ? # Character 諸
+U+fabb ? # Character 請
+U+fabc ? # Character 謁
+U+fabd ? # Character 諾
+U+fabe ? # Character 諭
+U+fabf ? # Character 謹
+U+fac0 ? # Character ï«
+U+fac1 ? # Character ï«
+U+fac2 ? # Character ï«
+U+fac3 ? # Character ï«
+U+fac4 ? # Character ï«
+U+fac5 ? # Character ï«
+U+fac6 ? # Character ï«
+U+fac7 ? # Character ï«
+U+fac8 ? # Character ï«
+U+fac9 ? # Character ï«
+U+faca ? # Character ï«
+U+facb ? # Character ï«
+U+facc ? # Character ï«
+U+facd ? # Character ï«
+U+face ? # Character ï«
+U+facf ? # Character ï«
+U+fad0 ? # Character ï«
+U+fad1 ? # Character ï«
+U+fad2 ? # Character ï«
+U+fad3 ? # Character ï«
+U+fad4 ? # Character ï«
+U+fad5 ? # Character ï«
+U+fad6 ? # Character ï«
+U+fad7 ? # Character ï«
+U+fad8 ? # Character ï«
+U+fad9 ? # Character ï«
+U+fada ? # Character ï«
+U+fadb ? # Character ï«
+U+fadc ? # Character ï«
+U+fadd ? # Character ï«
+U+fade ? # Character ï«
+U+fadf ? # Character ï«
+U+fae0 ? # Character ï«
+U+fae1 ? # Character ï«¡
+U+fae2 ? # Character ï«¢
+U+fae3 ? # Character ï«£
+U+fae4 ? # Character 﫤
+U+fae5 ? # Character ï«¥
+U+fae6 ? # Character 﫦
+U+fae7 ? # Character 﫧
+U+fae8 ? # Character 﫨
+U+fae9 ? # Character ï«©
+U+faea ? # Character 﫪
+U+faeb ? # Character ï««
+U+faec ? # Character 﫬
+U+faed ? # Character ï«
+U+faee ? # Character ï«®
+U+faef ? # Character 﫯
+U+faf0 ? # Character ï«°
+U+faf1 ? # Character 﫱
+U+faf2 ? # Character 﫲
+U+faf3 ? # Character 﫳
+U+faf4 ? # Character ï«´
+U+faf5 ? # Character 﫵
+U+faf6 ? # Character 﫶
+U+faf7 ? # Character ï«·
+U+faf8 ? # Character 﫸
+U+faf9 ? # Character 﫹
+U+fafa ? # Character 﫺
+U+fafb ? # Character ï«»
+U+fafc ? # Character 﫼
+U+fafd ? # Character 﫽
+U+fafe ? # Character 﫾
+U+faff ? # Character ï«¿
diff --git a/resources/chars/latin1/rowfb.trans b/resources/chars/latin1/rowfb.trans
new file mode 100644
index 0000000..605a02c
--- /dev/null
+++ b/resources/chars/latin1/rowfb.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+fb00 ? # Character ï¬
+U+fb01 ? # Character ï¬
+U+fb02 ? # Character ï¬
+U+fb03 ? # Character ï¬
+U+fb04 ? # Character ï¬
+U+fb05 ? # Character ï¬
+U+fb06 ? # Character ï¬
+U+fb07 ? # Character ï¬
+U+fb08 ? # Character ï¬
+U+fb09 ? # Character ï¬
+U+fb0a ? # Character ï¬
+U+fb0b ? # Character ï¬
+U+fb0c ? # Character ï¬
+U+fb0d ? # Character ï¬
+U+fb0e ? # Character ï¬
+U+fb0f ? # Character ï¬
+U+fb10 ? # Character ï¬
+U+fb11 ? # Character ï¬
+U+fb12 ? # Character ï¬
+U+fb13 ? # Character ï¬
+U+fb14 ? # Character ï¬
+U+fb15 ? # Character ï¬
+U+fb16 ? # Character ï¬
+U+fb17 ? # Character ï¬
+U+fb18 ? # Character ï¬
+U+fb19 ? # Character ï¬
+U+fb1a ? # Character ï¬
+U+fb1b ? # Character ï¬
+U+fb1c ? # Character ï¬
+U+fb1d yi # Character ï¬
+U+fb1e ? # Character ï¬
+U+fb1f yya # Character ï¬
+#U+fb20 Ê» # Character ï¬
+#U+fb21 ʼ # Character ﬡ
+U+fb22 d # Character ﬢ
+U+fb23 h # Character ﬣ
+U+fb24 k # Character ﬤ
+U+fb25 l # Character ﬥ
+U+fb26 m # Character ﬦ
+U+fb27 r # Character ﬧ
+#U+fb28 ţ # Character ﬨ
+U+fb29 + # Character ﬩
+#U+fb2a ÅÌ # Character שׁ
+#U+fb2b ÅÌ # Character שׂ
+#U+fb2c ÅÌÌ # Character שּׁ
+#U+fb2d ÅÌÌ # Character ï¬
+#U+fb2e ʼa # Character אַ
+#U+fb2f ʼá # Character אָ
+#U+fb30 Ê¼Ì # Character אּ
+#U+fb31 Ḡ# Character בּ
+#U+fb32 ġ # Character גּ
+#U+fb33 Ḡ# Character דּ
+#U+fb34 ḣ # Character הּ
+#U+fb35 Ạ# Character וּ
+#U+fb36 ż # Character זּ
+U+fb37 ? # Character ﬷
+#U+fb38 ṫ # Character טּ
+#U+fb39 Ạ# Character יּ
+#U+fb3a kÌ # Character ךּ
+#U+fb3b kÌ # Character כּ
+#U+fb3c lÌ # Character לּ
+U+fb3d ? # Character ﬽
+#U+fb3e Ṡ# Character מּ
+U+fb3f ? # Character ﬿
+#U+fb40 á¹
# Character ï
+#U+fb41 ṡ # Character ï
+U+fb42 ? # Character ï
+#U+fb43 á¹ # Character ï
+#U+fb44 á¹ # Character ï
+U+fb45 ? # Character ï
+#U+fb46 áºÌ # Character ï
+#U+fb47 qÌ # Character ï
+#U+fb48 á¹ # Character ï
+#U+fb49 ÅÌ # Character ï
+#U+fb4a Å£Ì # Character ï
+U+fb4b wò # Character ï
+#U+fb4c bÌ # Character ï
+#U+fb4d kÌ # Character ï
+#U+fb4e pÌ # Character ï
+#U+fb4f ʼl # Character ï
+#U+fb50 Ù± # Character ï
+#U+fb51 Ù± # Character ï
+#U+fb52 Ù» # Character ï
+#U+fb53 Ù» # Character ï
+#U+fb54 Ù» # Character ï
+#U+fb55 Ù» # Character ï
+U+fb56 p # Character ï
+U+fb57 p # Character ï
+U+fb58 p # Character ï
+U+fb59 p # Character ï
+#U+fb5a Ú # Character ï
+#U+fb5b Ú # Character ï
+#U+fb5c Ú # Character ï
+#U+fb5d Ú # Character ï
+#U+fb5e Ùº # Character ï
+#U+fb5f Ùº # Character ï
+#U+fb60 Ùº # Character ï
+#U+fb61 Ùº # Character ï¡
+#U+fb62 Ù¿ # Character ï¢
+#U+fb63 Ù¿ # Character ï£
+#U+fb64 Ù¿ # Character ï¤
+#U+fb65 Ù¿ # Character ï¥
+#U+fb66 Ù¹ # Character ï¦
+#U+fb67 Ù¹ # Character ï§
+#U+fb68 Ù¹ # Character ï¨
+#U+fb69 Ù¹ # Character ï©
+U+fb6a v # Character ïª
+U+fb6b v # Character ï«
+U+fb6c v # Character ï¬
+U+fb6d v # Character ï
+#U+fb6e Ú¦ # Character ï®
+#U+fb6f Ú¦ # Character ï¯
+#U+fb70 Ú¦ # Character ï°
+#U+fb71 Ú¦ # Character ï±
+#U+fb72 Ú # Character ï²
+#U+fb73 Ú # Character ï³
+#U+fb74 Ú # Character ï´
+#U+fb75 Ú # Character ïµ
+#U+fb76 Ú # Character ï¶
+#U+fb77 Ú # Character ï·
+#U+fb78 Ú # Character ï¸
+#U+fb79 Ú # Character ï¹
+#U+fb7a cẠ# Character ïº
+#U+fb7b cẠ# Character ï»
+#U+fb7c cẠ# Character ï¼
+#U+fb7d cẠ# Character ï½
+#U+fb7e Ú # Character ï¾
+#U+fb7f Ú # Character ï¿
+#U+fb80 Ú # Character ï®
+#U+fb81 Ú # Character ï®
+#U+fb82 Ú # Character ï®
+#U+fb83 Ú # Character ï®
+#U+fb84 Ú # Character ï®
+#U+fb85 Ú # Character ï®
+#U+fb86 Ú # Character ï®
+#U+fb87 Ú # Character ï®
+#U+fb88 Ú # Character ï®
+#U+fb89 Ú # Character ï®
+#U+fb8a zẠ# Character ï®
+#U+fb8b zẠ# Character ï®
+#U+fb8c Ú # Character ï®
+#U+fb8d Ú # Character ï®
+#U+fb8e ḵ # Character ï®
+#U+fb8f ḵ # Character ï®
+#U+fb90 ḵ # Character ï®
+#U+fb91 ḵ # Character ï®
+U+fb92 g # Character ï®
+U+fb93 g # Character ï®
+U+fb94 g # Character ï®
+U+fb95 g # Character ï®
+#U+fb96 Ú³ # Character ï®
+#U+fb97 Ú³ # Character ï®
+#U+fb98 Ú³ # Character ï®
+#U+fb99 Ú³ # Character ï®
+#U+fb9a Ú± # Character ï®
+#U+fb9b Ú± # Character ï®
+#U+fb9c Ú± # Character ï®
+#U+fb9d Ú± # Character ï®
+#U+fb9e Úº # Character ï®
+#U+fb9f Úº # Character ï®
+#U+fba0 Ú» # Character ï®
+#U+fba1 ڻ # Character ﮡ
+#U+fba2 ڻ # Character ﮢ
+#U+fba3 ڻ # Character ﮣ
+#U+fba4 ÛÌ # Character ﮤ
+#U+fba5 ÛÌ # Character ﮥ
+#U+fba6 Û # Character ﮦ
+#U+fba7 Û # Character ﮧ
+#U+fba8 Û # Character ﮨ
+#U+fba9 Û # Character ﮩ
+#U+fbaa ھ # Character ﮪ
+#U+fbab ھ # Character ﮫ
+#U+fbac ھ # Character ﮬ
+#U+fbad Ú¾ # Character ï®
+#U+fbae Û # Character ï®®
+#U+fbaf Û # Character ﮯ
+#U+fbb0 ÛÌ # Character ï®°
+#U+fbb1 ÛÌ # Character ï®±
+U+fbb2 ? # Character ﮲
+U+fbb3 ? # Character ﮳
+U+fbb4 ? # Character ï®´
+U+fbb5 ? # Character ﮵
+U+fbb6 ? # Character ﮶
+U+fbb7 ? # Character ï®·
+U+fbb8 ? # Character ﮸
+U+fbb9 ? # Character ﮹
+U+fbba ? # Character ﮺
+U+fbbb ? # Character ï®»
+U+fbbc ? # Character ﮼
+U+fbbd ? # Character ﮽
+U+fbbe ? # Character ﮾
+U+fbbf ? # Character ﮿
+U+fbc0 ? # Character ï¯
+U+fbc1 ? # Character ï¯
+U+fbc2 ? # Character ï¯
+U+fbc3 ? # Character ï¯
+U+fbc4 ? # Character ï¯
+U+fbc5 ? # Character ï¯
+U+fbc6 ? # Character ï¯
+U+fbc7 ? # Character ï¯
+U+fbc8 ? # Character ï¯
+U+fbc9 ? # Character ï¯
+U+fbca ? # Character ï¯
+U+fbcb ? # Character ï¯
+U+fbcc ? # Character ï¯
+U+fbcd ? # Character ï¯
+U+fbce ? # Character ï¯
+U+fbcf ? # Character ï¯
+U+fbd0 ? # Character ï¯
+U+fbd1 ? # Character ï¯
+U+fbd2 ? # Character ï¯
+#U+fbd3 á¹g # Character ï¯
+#U+fbd4 á¹g # Character ï¯
+#U+fbd5 á¹g # Character ï¯
+#U+fbd6 á¹g # Character ï¯
+#U+fbd7 Û # Character ï¯
+#U+fbd8 Û # Character ï¯
+#U+fbd9 Û # Character ï¯
+#U+fbda Û # Character ï¯
+#U+fbdb Û # Character ï¯
+#U+fbdc Û # Character ï¯
+#U+fbdd ÛÙ´ # Character ï¯
+#U+fbde v̱ # Character ï¯
+#U+fbdf v̱ # Character ï¯
+#U+fbe0 Û
# Character ï¯
+#U+fbe1 Û
# Character ﯡ
+#U+fbe2 Û # Character ﯢ
+#U+fbe3 Û # Character ﯣ
+#U+fbe4 Û # Character ﯤ
+#U+fbe5 Û # Character ﯥ
+#U+fbe6 Û # Character ﯦ
+#U+fbe7 Û # Character ﯧ
+#U+fbe8 y̱ # Character ﯨ
+#U+fbe9 y̱ # Character ﯩ
+#U+fbea ỷạ # Character ﯪ
+#U+fbeb ỷạ # Character ﯫ
+#U+fbec á»·Û # Character ﯬ
+#U+fbed á»·Û # Character ï¯
+#U+fbee ỷw # Character ﯮ
+#U+fbef ỷw # Character ﯯ
+#U+fbf0 á»·Û # Character ﯰ
+#U+fbf1 á»·Û # Character ﯱ
+#U+fbf2 á»·Û # Character ﯲ
+#U+fbf3 á»·Û # Character ﯳ
+#U+fbf4 á»·Û # Character ﯴ
+#U+fbf5 á»·Û # Character ﯵ
+#U+fbf6 á»·Û # Character ﯶ
+#U+fbf7 á»·Û # Character ﯷ
+#U+fbf8 á»·Û # Character ﯸ
+#U+fbf9 ỷy̱ # Character ﯹ
+#U+fbfa ỷy̱ # Character ﯺ
+#U+fbfb ỷy̱ # Character ﯻ
+#U+fbfc y̰ # Character ﯼ
+#U+fbfd y̰ # Character ﯽ
+#U+fbfe y̰ # Character ﯾ
+#U+fbff y̰ # Character ﯿ
diff --git a/resources/chars/latin1/rowfc.trans b/resources/chars/latin1/rowfc.trans
new file mode 100644
index 0000000..c2d9574
--- /dev/null
+++ b/resources/chars/latin1/rowfc.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+fc00 á»·j # Character ï°
+#U+fc01 ỷḥ # Character ï°
+#U+fc02 á»·m # Character ï°
+#U+fc03 á»·y̱ # Character ï°
+#U+fc04 á»·y # Character ï°
+U+fc05 bj # Character ï°
+#U+fc06 bḥ # Character ï°
+#U+fc07 bkẠ# Character ï°
+U+fc08 bm # Character ï°
+#U+fc09 by̱ # Character ï°
+U+fc0a by # Character ï°
+U+fc0b tj # Character ï°
+#U+fc0c tḥ # Character ï°
+#U+fc0d tkẠ# Character ï°
+U+fc0e tm # Character ï°
+#U+fc0f ty̱ # Character ï°
+U+fc10 ty # Character ï°
+#U+fc11 táºj # Character ï°
+#U+fc12 táºm # Character ï°
+#U+fc13 táºy̱ # Character ï°
+#U+fc14 táºy # Character ï°
+#U+fc15 jḥ # Character ï°
+U+fc16 jm # Character ï°
+#U+fc17 ḥj # Character ï°
+#U+fc18 ḥm # Character ï°
+#U+fc19 káºj # Character ï°
+#U+fc1a káºá¸¥ # Character ï°
+#U+fc1b káºm # Character ï°
+U+fc1c sj # Character ï°
+#U+fc1d sḥ # Character ï°
+#U+fc1e skẠ# Character ï°
+U+fc1f sm # Character ï°
+#U+fc20 ṣḥ # Character ï°
+#U+fc21 á¹£m # Character ï°¡
+#U+fc22 á¸j # Character ï°¢
+#U+fc23 á¸á¸¥ # Character ï°£
+#U+fc24 á¸kẠ# Character ï°¤
+#U+fc25 á¸m # Character ï°¥
+#U+fc26 á¹á¸¥ # Character ï°¦
+#U+fc27 á¹m # Character ï°§
+#U+fc28 áºm # Character ï°¨
+#U+fc29 Ê¿j # Character ï°©
+#U+fc2a Ê¿m # Character ï°ª
+#U+fc2b gáºj # Character ï°«
+#U+fc2c gáºm # Character ï°¬
+U+fc2d fj # Character ï°
+#U+fc2e fḥ # Character ﰮ
+#U+fc2f fkẠ# Character ﰯ
+U+fc30 fm # Character ï°°
+#U+fc31 fy̱ # Character ﰱ
+U+fc32 fy # Character ï°²
+#U+fc33 qḥ # Character ﰳ
+U+fc34 qm # Character ï°´
+#U+fc35 qy̱ # Character ﰵ
+U+fc36 qy # Character ï°¶
+#U+fc37 kạ # Character ﰷ
+U+fc38 kj # Character ï°¸
+#U+fc39 kḥ # Character ﰹ
+#U+fc3a kkẠ# Character ﰺ
+U+fc3b kl # Character ï°»
+U+fc3c km # Character ï°¼
+#U+fc3d ky̱ # Character ﰽ
+U+fc3e ky # Character ï°¾
+U+fc3f lj # Character ï°¿
+#U+fc40 lḥ # Character ï±
+#U+fc41 lkẠ# Character ï±
+U+fc42 lm # Character ï±
+#U+fc43 ly̱ # Character ï±
+U+fc44 ly # Character ï±
+U+fc45 mj # Character ï±
+#U+fc46 mḥ # Character ï±
+#U+fc47 mkẠ# Character ï±
+U+fc48 mm # Character ï±
+#U+fc49 my̱ # Character ï±
+U+fc4a my # Character ï±
+U+fc4b nj # Character ï±
+#U+fc4c nḥ # Character ï±
+#U+fc4d nkẠ# Character ï±
+U+fc4e nm # Character ï±
+#U+fc4f ny̱ # Character ï±
+U+fc50 ny # Character ï±
+U+fc51 hj # Character ï±
+U+fc52 hm # Character ï±
+#U+fc53 hy̱ # Character ï±
+U+fc54 hy # Character ï±
+U+fc55 yj # Character ï±
+#U+fc56 yḥ # Character ï±
+#U+fc57 ykẠ# Character ï±
+U+fc58 ym # Character ï±
+#U+fc59 yy̱ # Character ï±
+U+fc5a yy # Character ï±
+#U+fc5b dáºÙ° # Character ï±
+#U+fc5c rÙ° # Character ï±
+#U+fc5d yٰ̱ # Character ï±
+#U+fc5e uâ¿Ì # Character ï±
+#U+fc5f iâ¿Ì # Character ï±
+U+fc60 ã # Character ï±
+#U+fc61 ũ # Character ﱡ
+#U+fc62 Ä© # Character ï±¢
+#U+fc63 Ù°Ì # Character ï±£
+#U+fc64 ỷr # Character ﱤ
+#U+fc65 á»·z # Character ï±¥
+#U+fc66 ỷm # Character ﱦ
+#U+fc67 ỷn # Character ﱧ
+#U+fc68 ỷy̱ # Character ﱨ
+#U+fc69 ỷy # Character ﱩ
+U+fc6a br # Character ﱪ
+U+fc6b bz # Character ﱫ
+U+fc6c bm # Character ﱬ
+U+fc6d bn # Character ï±
+#U+fc6e by̱ # Character ﱮ
+U+fc6f by # Character ﱯ
+U+fc70 tr # Character ï±°
+U+fc71 tz # Character ï±±
+U+fc72 tm # Character ï±²
+U+fc73 tn # Character ï±³
+#U+fc74 ty̱ # Character ﱴ
+U+fc75 ty # Character ï±µ
+#U+fc76 táºr # Character ﱶ
+#U+fc77 táºz # Character ï±·
+#U+fc78 táºm # Character ﱸ
+#U+fc79 táºn # Character ï±¹
+#U+fc7a táºy̱ # Character ﱺ
+#U+fc7b táºy # Character ï±»
+#U+fc7c fy̱ # Character ﱼ
+U+fc7d fy # Character ï±½
+#U+fc7e qy̱ # Character ﱾ
+U+fc7f qy # Character ﱿ
+#U+fc80 kạ # Character ï²
+U+fc81 kl # Character ï²
+U+fc82 km # Character ï²
+#U+fc83 ky̱ # Character ï²
+U+fc84 ky # Character ï²
+U+fc85 lm # Character ï²
+#U+fc86 ly̱ # Character ï²
+U+fc87 ly # Character ï²
+#U+fc88 mạ # Character ï²
+U+fc89 mm # Character ï²
+U+fc8a nr # Character ï²
+U+fc8b nz # Character ï²
+U+fc8c nm # Character ï²
+U+fc8d nn # Character ï²
+#U+fc8e ny̱ # Character ï²
+U+fc8f ny # Character ï²
+#U+fc90 yٰ̱ # Character ï²
+U+fc91 yr # Character ï²
+U+fc92 yz # Character ï²
+U+fc93 ym # Character ï²
+U+fc94 yn # Character ï²
+#U+fc95 yy̱ # Character ï²
+U+fc96 yy # Character ï²
+#U+fc97 á»·j # Character ï²
+#U+fc98 ỷḥ # Character ï²
+#U+fc99 á»·kẠ# Character ï²
+#U+fc9a á»·m # Character ï²
+#U+fc9b á»·h # Character ï²
+U+fc9c bj # Character ï²
+#U+fc9d bḥ # Character ï²
+#U+fc9e bkẠ# Character ï²
+U+fc9f bm # Character ï²
+U+fca0 bh # Character ï²
+U+fca1 tj # Character ﲡ
+#U+fca2 tḥ # Character ﲢ
+#U+fca3 tkẠ# Character ﲣ
+U+fca4 tm # Character ﲤ
+U+fca5 th # Character ï²¥
+#U+fca6 táºm # Character ﲦ
+#U+fca7 jḥ # Character ﲧ
+U+fca8 jm # Character ﲨ
+#U+fca9 ḥj # Character ﲩ
+#U+fcaa ḥm # Character ﲪ
+#U+fcab káºj # Character ﲫ
+#U+fcac káºm # Character ﲬ
+U+fcad sj # Character ï²
+#U+fcae sḥ # Character ﲮ
+#U+fcaf skẠ# Character ﲯ
+U+fcb0 sm # Character ï²°
+#U+fcb1 ṣḥ # Character ﲱ
+#U+fcb2 ṣkẠ# Character ﲲ
+#U+fcb3 á¹£m # Character ï²³
+#U+fcb4 á¸j # Character ï²´
+#U+fcb5 á¸á¸¥ # Character ï²µ
+#U+fcb6 á¸kẠ# Character ﲶ
+#U+fcb7 á¸m # Character ï²·
+#U+fcb8 á¹á¸¥ # Character ﲸ
+#U+fcb9 áºm # Character ï²¹
+#U+fcba ʿj # Character ﲺ
+#U+fcbb Ê¿m # Character ï²»
+#U+fcbc gáºj # Character ï²¼
+#U+fcbd gáºm # Character ï²½
+U+fcbe fj # Character ï²¾
+#U+fcbf fḥ # Character ﲿ
+#U+fcc0 fkẠ# Character ï³
+U+fcc1 fm # Character ï³
+#U+fcc2 qḥ # Character ï³
+U+fcc3 qm # Character ï³
+U+fcc4 kj # Character ï³
+#U+fcc5 kḥ # Character ï³
+#U+fcc6 kkẠ# Character ï³
+U+fcc7 kl # Character ï³
+U+fcc8 km # Character ï³
+U+fcc9 lj # Character ï³
+#U+fcca lḥ # Character ï³
+#U+fccb lkẠ# Character ï³
+U+fccc lm # Character ï³
+U+fccd lh # Character ï³
+U+fcce mj # Character ï³
+#U+fccf mḥ # Character ï³
+#U+fcd0 mkẠ# Character ï³
+U+fcd1 mm # Character ï³
+U+fcd2 nj # Character ï³
+#U+fcd3 nḥ # Character ï³
+#U+fcd4 nkẠ# Character ï³
+U+fcd5 nm # Character ï³
+U+fcd6 nh # Character ï³
+U+fcd7 hj # Character ï³
+U+fcd8 hm # Character ï³
+#U+fcd9 hÙ° # Character ï³
+U+fcda yj # Character ï³
+#U+fcdb yḥ # Character ï³
+#U+fcdc ykẠ# Character ï³
+U+fcdd ym # Character ï³
+U+fcde yh # Character ï³
+#U+fcdf á»·m # Character ï³
+#U+fce0 á»·h # Character ï³
+U+fce1 bm # Character ﳡ
+U+fce2 bh # Character ï³¢
+U+fce3 tm # Character ï³£
+U+fce4 th # Character ﳤ
+#U+fce5 táºm # Character ï³¥
+#U+fce6 táºh # Character ﳦ
+U+fce7 sm # Character ﳧ
+U+fce8 sh # Character ﳨ
+#U+fce9 sáºm # Character ﳩ
+#U+fcea sáºh # Character ﳪ
+U+fceb kl # Character ﳫ
+U+fcec km # Character ﳬ
+U+fced lm # Character ï³
+U+fcee nm # Character ï³®
+U+fcef nh # Character ﳯ
+U+fcf0 ym # Character ï³°
+U+fcf1 yh # Character ï³±
+U+fcf2 ã # Character ﳲ
+#U+fcf3 Å© # Character ï³³
+#U+fcf4 Ä© # Character ï³´
+#U+fcf5 á¹y̱ # Character ï³µ
+#U+fcf6 á¹y # Character ﳶ
+#U+fcf7 ʿy̱ # Character ﳷ
+#U+fcf8 ʿy # Character ﳸ
+#U+fcf9 gáºy̱ # Character ï³¹
+#U+fcfa gáºy # Character ﳺ
+#U+fcfb sy̱ # Character ﳻ
+U+fcfc sy # Character ï³¼
+#U+fcfd sáºy̱ # Character ï³½
+#U+fcfe sáºy # Character ï³¾
+#U+fcff ḥy̱ # Character ﳿ
diff --git a/resources/chars/latin1/rowfd.trans b/resources/chars/latin1/rowfd.trans
new file mode 100644
index 0000000..52a6072
--- /dev/null
+++ b/resources/chars/latin1/rowfd.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+#U+fd00 ḥy # Character ï´
+#U+fd01 jy̱ # Character ï´
+U+fd02 jy # Character ï´
+#U+fd03 káºy̱ # Character ï´
+#U+fd04 káºy # Character ï´
+#U+fd05 á¹£y̱ # Character ï´
+#U+fd06 á¹£y # Character ï´
+#U+fd07 á¸y̱ # Character ï´
+#U+fd08 á¸y # Character ï´
+#U+fd09 sáºj # Character ï´
+#U+fd0a sáºá¸¥ # Character ï´
+#U+fd0b sáºkẠ# Character ï´
+#U+fd0c sáºm # Character ï´
+#U+fd0d sáºr # Character ï´
+U+fd0e sr # Character ï´
+#U+fd0f á¹£r # Character ï´
+#U+fd10 á¸r # Character ï´
+#U+fd11 á¹y̱ # Character ï´
+#U+fd12 á¹y # Character ï´
+#U+fd13 Ê¿y̱ # Character ï´
+#U+fd14 Ê¿y # Character ï´
+#U+fd15 gáºy̱ # Character ï´
+#U+fd16 gáºy # Character ï´
+#U+fd17 sy̱ # Character ï´
+U+fd18 sy # Character ï´
+#U+fd19 sáºy̱ # Character ï´
+#U+fd1a sáºy # Character ï´
+#U+fd1b ḥy̱ # Character ï´
+#U+fd1c ḥy # Character ï´
+#U+fd1d jy̱ # Character ï´
+U+fd1e jy # Character ï´
+#U+fd1f káºy̱ # Character ï´
+#U+fd20 káºy # Character ï´
+#U+fd21 ṣy̱ # Character ﴡ
+#U+fd22 á¹£y # Character ï´¢
+#U+fd23 á¸y̱ # Character ï´£
+#U+fd24 á¸y # Character ï´¤
+#U+fd25 sáºj # Character ï´¥
+#U+fd26 sáºá¸¥ # Character ï´¦
+#U+fd27 sáºkẠ# Character ï´§
+#U+fd28 sáºm # Character ï´¨
+#U+fd29 sáºr # Character ï´©
+U+fd2a sr # Character ï´ª
+#U+fd2b á¹£r # Character ï´«
+#U+fd2c á¸r # Character ï´¬
+#U+fd2d sáºj # Character ï´
+#U+fd2e sáºá¸¥ # Character ï´®
+#U+fd2f sáºkẠ# Character ï´¯
+#U+fd30 sáºm # Character ï´°
+U+fd31 sh # Character ï´±
+#U+fd32 sáºh # Character ï´²
+#U+fd33 á¹m # Character ï´³
+U+fd34 sj # Character ï´´
+#U+fd35 sḥ # Character ﴵ
+#U+fd36 skẠ# Character ﴶ
+#U+fd37 sáºj # Character ï´·
+#U+fd38 sáºá¸¥ # Character ï´¸
+#U+fd39 sáºkẠ# Character ï´¹
+#U+fd3a á¹m # Character ï´º
+#U+fd3b áºm # Character ï´»
+#U+fd3c ạa⿠# Character ﴼ
+#U+fd3d ạa⿠# Character ﴽ
+U+fd3e ? # Character ï´¾
+U+fd3f ? # Character ï´¿
+U+fd40 ? # Character ïµ
+U+fd41 ? # Character ïµ
+U+fd42 ? # Character ïµ
+U+fd43 ? # Character ïµ
+U+fd44 ? # Character ïµ
+U+fd45 ? # Character ïµ
+U+fd46 ? # Character ïµ
+U+fd47 ? # Character ïµ
+U+fd48 ? # Character ïµ
+U+fd49 ? # Character ïµ
+U+fd4a ? # Character ïµ
+U+fd4b ? # Character ïµ
+U+fd4c ? # Character ïµ
+U+fd4d ? # Character ïµ
+U+fd4e ? # Character ïµ
+U+fd4f ? # Character ïµ
+U+fd50 tjm # Character ïµ
+#U+fd51 tḥj # Character ïµ
+#U+fd52 tḥj # Character ïµ
+#U+fd53 tḥm # Character ïµ
+#U+fd54 tkáºm # Character ïµ
+U+fd55 tmj # Character ïµ
+#U+fd56 tmḥ # Character ïµ
+#U+fd57 tmkẠ# Character ïµ
+#U+fd58 jmḥ # Character ïµ
+#U+fd59 jmḥ # Character ïµ
+#U+fd5a ḥmy # Character ïµ
+#U+fd5b ḥmy̱ # Character ïµ
+#U+fd5c sḥj # Character ïµ
+#U+fd5d sjḥ # Character ïµ
+#U+fd5e sjy̱ # Character ïµ
+#U+fd5f smḥ # Character ïµ
+#U+fd60 smḥ # Character ïµ
+U+fd61 smj # Character ﵡ
+U+fd62 smm # Character ïµ¢
+U+fd63 smm # Character ïµ£
+#U+fd64 ṣḥḥ # Character ﵤ
+#U+fd65 ṣḥḥ # Character ﵥ
+#U+fd66 ṣmm # Character ﵦ
+#U+fd67 sáºá¸¥m # Character ﵧ
+#U+fd68 sáºá¸¥m # Character ﵨ
+#U+fd69 sáºjy # Character ﵩ
+#U+fd6a sáºmkẠ# Character ﵪ
+#U+fd6b sáºmkẠ# Character ﵫ
+#U+fd6c sáºmm # Character ﵬ
+#U+fd6d sáºmm # Character ïµ
+#U+fd6e á¸á¸¥y̱ # Character ïµ®
+#U+fd6f á¸káºm # Character ﵯ
+#U+fd70 á¸káºm # Character ïµ°
+#U+fd71 á¹mḥ # Character ïµ±
+#U+fd72 á¹mḥ # Character ïµ²
+#U+fd73 á¹mm # Character ïµ³
+#U+fd74 á¹my # Character ïµ´
+#U+fd75 Ê¿jm # Character ïµµ
+#U+fd76 ʿmm # Character ﵶ
+#U+fd77 Ê¿mm # Character ïµ·
+#U+fd78 ʿmy̱ # Character ﵸ
+#U+fd79 gáºmm # Character ïµ¹
+#U+fd7a gáºmy # Character ﵺ
+#U+fd7b gáºmy̱ # Character ïµ»
+#U+fd7c fkáºm # Character ïµ¼
+#U+fd7d fkáºm # Character ïµ½
+#U+fd7e qmḥ # Character ﵾ
+U+fd7f qmm # Character ﵿ
+#U+fd80 lḥm # Character ï¶
+#U+fd81 lḥy # Character ï¶
+#U+fd82 lḥy̱ # Character ï¶
+U+fd83 ljj # Character ï¶
+U+fd84 ljj # Character ï¶
+#U+fd85 lkáºm # Character ï¶
+#U+fd86 lkáºm # Character ï¶
+#U+fd87 lmḥ # Character ï¶
+#U+fd88 lmḥ # Character ï¶
+#U+fd89 mḥj # Character ï¶
+#U+fd8a mḥm # Character ï¶
+#U+fd8b mḥy # Character ï¶
+#U+fd8c mjḥ # Character ï¶
+U+fd8d mjm # Character ï¶
+#U+fd8e mkáºj # Character ï¶
+#U+fd8f mkáºm # Character ï¶
+U+fd90 ? # Character ï¶
+U+fd91 ? # Character ï¶
+#U+fd92 mjkẠ# Character ï¶
+U+fd93 hmj # Character ï¶
+U+fd94 hmm # Character ï¶
+#U+fd95 nḥm # Character ï¶
+#U+fd96 nḥy̱ # Character ï¶
+U+fd97 njm # Character ï¶
+U+fd98 njm # Character ï¶
+#U+fd99 njy̱ # Character ï¶
+U+fd9a nmy # Character ï¶
+#U+fd9b nmy̱ # Character ï¶
+U+fd9c ymm # Character ï¶
+U+fd9d ymm # Character ï¶
+#U+fd9e bkáºy # Character ï¶
+U+fd9f tjy # Character ï¶
+#U+fda0 tjy̱ # Character ï¶
+#U+fda1 tkáºy # Character ﶡ
+#U+fda2 tkáºy̱ # Character ﶢ
+U+fda3 tmy # Character ﶣ
+#U+fda4 tmy̱ # Character ﶤ
+U+fda5 jmy # Character ﶥ
+#U+fda6 jḥy̱ # Character ﶦ
+#U+fda7 jmy̱ # Character ﶧ
+#U+fda8 skáºy̱ # Character ﶨ
+#U+fda9 ṣḥy # Character ﶩ
+#U+fdaa sáºá¸¥y # Character ﶪ
+#U+fdab á¸á¸¥y # Character ﶫ
+U+fdac ljy # Character ﶬ
+U+fdad lmy # Character ï¶
+#U+fdae yḥy # Character ﶮ
+U+fdaf yjy # Character ﶯ
+U+fdb0 ymy # Character ﶰ
+U+fdb1 mmy # Character ﶱ
+U+fdb2 qmy # Character ﶲ
+#U+fdb3 nḥy # Character ﶳ
+#U+fdb4 qmḥ # Character ﶴ
+#U+fdb5 lḥm # Character ﶵ
+#U+fdb6 ʿmy # Character ﶶ
+U+fdb7 kmy # Character ﶷ
+#U+fdb8 njḥ # Character ﶸ
+#U+fdb9 mkáºy # Character ﶹ
+U+fdba ljm # Character ﶺ
+U+fdbb kmm # Character ﶻ
+U+fdbc ljm # Character ﶼ
+#U+fdbd njḥ # Character ﶽ
+#U+fdbe jḥy # Character ﶾ
+#U+fdbf ḥjy # Character ﶿ
+U+fdc0 mjy # Character ï·
+U+fdc1 fmy # Character ï·
+#U+fdc2 bḥy # Character ï·
+U+fdc3 kmm # Character ï·
+#U+fdc4 Ê¿jm # Character ï·
+#U+fdc5 á¹£mm # Character ï·
+#U+fdc6 skáºy # Character ï·
+U+fdc7 njy # Character ï·
+U+fdc8 ? # Character ï·
+U+fdc9 ? # Character ï·
+U+fdca ? # Character ï·
+U+fdcb ? # Character ï·
+U+fdcc ? # Character ï·
+U+fdcd ? # Character ï·
+U+fdce ? # Character ï·
+U+fdcf ? # Character ï·
+U+fdd0 ? # Character ï·
+U+fdd1 ? # Character ï·
+U+fdd2 ? # Character ï·
+U+fdd3 ? # Character ï·
+U+fdd4 ? # Character ï·
+U+fdd5 ? # Character ï·
+U+fdd6 ? # Character ï·
+U+fdd7 ? # Character ï·
+U+fdd8 ? # Character ï·
+U+fdd9 ? # Character ï·
+U+fdda ? # Character ï·
+U+fddb ? # Character ï·
+U+fddc ? # Character ï·
+U+fddd ? # Character ï·
+U+fdde ? # Character ï·
+U+fddf ? # Character ï·
+U+fde0 ? # Character ï·
+U+fde1 ? # Character ï·¡
+U+fde2 ? # Character ï·¢
+U+fde3 ? # Character ï·£
+U+fde4 ? # Character ï·¤
+U+fde5 ? # Character ï·¥
+U+fde6 ? # Character ï·¦
+U+fde7 ? # Character ï·§
+U+fde8 ? # Character ï·¨
+U+fde9 ? # Character ï·©
+U+fdea ? # Character ï·ª
+U+fdeb ? # Character ï·«
+U+fdec ? # Character ï·¬
+U+fded ? # Character ï·
+U+fdee ? # Character ï·®
+U+fdef ? # Character ï·¯
+#U+fdf0 á¹£lÛ # Character ï·°
+#U+fdf1 qlÛ # Character ï·±
+#U+fdf2 ạllh # Character ﷲ
+#U+fdf3 ạkbr # Character ﷳ
+#U+fdf4 mḥmd # Character ﷴ
+#U+fdf5 ṣlʿm # Character ﷵ
+U+fdf6 rswl # Character ï·¶
+#U+fdf7 Ê¿lyh # Character ï··
+U+fdf8 wslm # Character ï·¸
+#U+fdf9 ṣly̱ # Character ﷹ
+#U+fdfa ṣly̱ ạllh ʿl # Character ﷺ
+#U+fdfb jl jlạlh # Character ﷻ
+#U+fdfc ry̰ạl # Character ﷼
+U+fdfd ? # Character ï·½
+U+fdfe ? # Character ï·¾
+U+fdff ? # Character ï·¿
diff --git a/resources/chars/latin1/rowfe.trans b/resources/chars/latin1/rowfe.trans
new file mode 100644
index 0000000..37922c3
--- /dev/null
+++ b/resources/chars/latin1/rowfe.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+fe00 ? # Character ï¸
+U+fe01 ? # Character ï¸
+U+fe02 ? # Character ï¸
+U+fe03 ? # Character ï¸
+U+fe04 ? # Character ï¸
+U+fe05 ? # Character ï¸
+U+fe06 ? # Character ï¸
+U+fe07 ? # Character ï¸
+U+fe08 ? # Character ï¸
+U+fe09 ? # Character ï¸
+U+fe0a ? # Character ï¸
+U+fe0b ? # Character ï¸
+U+fe0c ? # Character ï¸
+U+fe0d ? # Character ï¸
+U+fe0e ? # Character ï¸
+U+fe0f ? # Character ï¸
+U+fe10 ? # Character ï¸
+U+fe11 ? # Character ï¸
+U+fe12 ? # Character ï¸
+U+fe13 ? # Character ï¸
+U+fe14 ? # Character ï¸
+U+fe15 ? # Character ï¸
+U+fe16 ? # Character ï¸
+U+fe17 ? # Character ï¸
+U+fe18 ? # Character ï¸
+U+fe19 ? # Character ï¸
+U+fe1a ? # Character ï¸
+U+fe1b ? # Character ï¸
+U+fe1c ? # Character ï¸
+U+fe1d ? # Character ï¸
+U+fe1e ? # Character ï¸
+U+fe1f ? # Character ï¸
+U+fe20 ? # Character ï¸
+U+fe21 ? # Character ︡
+U+fe22 ? # Character ︢
+U+fe23 ? # Character ︣
+U+fe24 ? # Character ︤
+U+fe25 ? # Character ︥
+U+fe26 ? # Character ︦
+U+fe27 ? # Character ︧
+U+fe28 ? # Character ︨
+U+fe29 ? # Character ︩
+U+fe2a ? # Character ︪
+U+fe2b ? # Character ︫
+U+fe2c ? # Character ︬
+U+fe2d ? # Character ï¸
+U+fe2e ? # Character ︮
+U+fe2f ? # Character ︯
+U+fe30 ? # Character ︰
+U+fe31 ? # Character ︱
+U+fe32 ? # Character ︲
+U+fe33 ? # Character ︳
+U+fe34 ? # Character ︴
+U+fe35 ? # Character ︵
+U+fe36 ? # Character ︶
+U+fe37 ? # Character ︷
+U+fe38 ? # Character ︸
+U+fe39 ? # Character ︹
+U+fe3a ? # Character ︺
+U+fe3b ? # Character ︻
+U+fe3c ? # Character ︼
+U+fe3d ? # Character ︽
+U+fe3e ? # Character ︾
+U+fe3f ? # Character ︿
+U+fe40 ? # Character ï¹
+U+fe41 ? # Character ï¹
+U+fe42 ? # Character ï¹
+U+fe43 ? # Character ï¹
+U+fe44 ? # Character ï¹
+U+fe45 ? # Character ï¹
+U+fe46 ? # Character ï¹
+U+fe47 ? # Character ï¹
+U+fe48 ? # Character ï¹
+U+fe49 ? # Character ï¹
+U+fe4a ? # Character ï¹
+U+fe4b ? # Character ï¹
+U+fe4c ? # Character ï¹
+U+fe4d ? # Character ï¹
+U+fe4e ? # Character ï¹
+U+fe4f ? # Character ï¹
+U+fe50 ? # Character ï¹
+U+fe51 ? # Character ï¹
+U+fe52 ? # Character ï¹
+U+fe53 ? # Character ï¹
+U+fe54 ? # Character ï¹
+U+fe55 ? # Character ï¹
+U+fe56 ? # Character ï¹
+U+fe57 ? # Character ï¹
+U+fe58 ? # Character ï¹
+U+fe59 ? # Character ï¹
+U+fe5a ? # Character ï¹
+U+fe5b ? # Character ï¹
+U+fe5c ? # Character ï¹
+U+fe5d ? # Character ï¹
+U+fe5e ? # Character ï¹
+U+fe5f ? # Character ï¹
+U+fe60 ? # Character ï¹
+U+fe61 ? # Character ﹡
+U+fe62 ? # Character ï¹¢
+U+fe63 ? # Character ï¹£
+U+fe64 ? # Character ﹤
+U+fe65 ? # Character ï¹¥
+U+fe66 ? # Character ﹦
+U+fe67 ? # Character ﹧
+U+fe68 ? # Character ﹨
+U+fe69 ? # Character ﹩
+U+fe6a ? # Character ﹪
+U+fe6b ? # Character ﹫
+U+fe6c ? # Character ﹬
+U+fe6d ? # Character ï¹
+U+fe6e ? # Character ï¹®
+U+fe6f ? # Character ﹯
+#U+fe70 aâ¿ # Character ï¹°
+#U+fe71 aâ¿ # Character ï¹±
+#U+fe72 uâ¿ # Character ï¹²
+U+fe73 ? # Character ï¹³
+#U+fe74 iâ¿ # Character ï¹´
+U+fe75 ? # Character ï¹µ
+U+fe76 a # Character ﹶ
+U+fe77 a # Character ï¹·
+U+fe78 u # Character ﹸ
+U+fe79 u # Character ï¹¹
+U+fe7a i # Character ﹺ
+U+fe7b i # Character ï¹»
+#U+fe7c Ì # Character ï¹¼
+#U+fe7d Ì # Character ï¹½
+#U+fe7e Ì # Character ï¹¾
+#U+fe7f Ì # Character ﹿ
+#U+fe80 ʾ # Character ïº
+#U+fe81 Ạ# Character ïº
+#U+fe82 Ạ# Character ïº
+#U+fe83 áº¡Ì # Character ïº
+#U+fe84 áº¡Ì # Character ïº
+#U+fe85 wÌ # Character ïº
+#U+fe86 wÌ # Character ïº
+#U+fe87 ạ̹ # Character ïº
+#U+fe88 ạ̹ # Character ïº
+#U+fe89 á»· # Character ïº
+#U+fe8a á»· # Character ïº
+#U+fe8b á»· # Character ïº
+#U+fe8c á»· # Character ïº
+#U+fe8d ạ # Character ïº
+#U+fe8e ạ # Character ïº
+U+fe8f b # Character ïº
+U+fe90 b # Character ïº
+U+fe91 b # Character ïº
+U+fe92 b # Character ïº
+#U+fe93 Ạ# Character ïº
+#U+fe94 Ạ# Character ïº
+U+fe95 t # Character ïº
+U+fe96 t # Character ïº
+U+fe97 t # Character ïº
+U+fe98 t # Character ïº
+#U+fe99 tẠ# Character ïº
+#U+fe9a tẠ# Character ïº
+#U+fe9b tẠ# Character ïº
+#U+fe9c tẠ# Character ïº
+U+fe9d j # Character ïº
+U+fe9e j # Character ïº
+U+fe9f j # Character ïº
+U+fea0 j # Character ïº
+#U+fea1 ḥ # Character ﺡ
+#U+fea2 ḥ # Character ﺢ
+#U+fea3 ḥ # Character ﺣ
+#U+fea4 ḥ # Character ﺤ
+#U+fea5 kẠ# Character ﺥ
+#U+fea6 kẠ# Character ﺦ
+#U+fea7 kẠ# Character ﺧ
+#U+fea8 kẠ# Character ﺨ
+U+fea9 d # Character ﺩ
+U+feaa d # Character ﺪ
+#U+feab dẠ# Character ﺫ
+#U+feac dẠ# Character ﺬ
+U+fead r # Character ïº
+U+feae r # Character ﺮ
+U+feaf z # Character ﺯ
+U+feb0 z # Character ﺰ
+U+feb1 s # Character ﺱ
+U+feb2 s # Character ﺲ
+U+feb3 s # Character ﺳ
+U+feb4 s # Character ﺴ
+#U+feb5 sẠ# Character ﺵ
+#U+feb6 sẠ# Character ﺶ
+#U+feb7 sẠ# Character ﺷ
+#U+feb8 sẠ# Character ﺸ
+#U+feb9 ṣ # Character ﺹ
+#U+feba ṣ # Character ﺺ
+#U+febb ṣ # Character ﺻ
+#U+febc ṣ # Character ﺼ
+#U+febd Ḡ# Character ﺽ
+#U+febe Ḡ# Character ﺾ
+#U+febf Ḡ# Character ﺿ
+#U+fec0 Ḡ# Character ï»
+#U+fec1 á¹ # Character ï»
+#U+fec2 á¹ # Character ï»
+#U+fec3 á¹ # Character ï»
+#U+fec4 á¹ # Character ï»
+#U+fec5 Ạ# Character ï»
+#U+fec6 Ạ# Character ï»
+#U+fec7 Ạ# Character ï»
+#U+fec8 Ạ# Character ï»
+#U+fec9 Ê¿ # Character ï»
+#U+feca Ê¿ # Character ï»
+#U+fecb Ê¿ # Character ï»
+#U+fecc Ê¿ # Character ï»
+#U+fecd gẠ# Character ï»
+#U+fece gẠ# Character ï»
+#U+fecf gẠ# Character ï»
+#U+fed0 gẠ# Character ï»
+U+fed1 f # Character ï»
+U+fed2 f # Character ï»
+U+fed3 f # Character ï»
+U+fed4 f # Character ï»
+U+fed5 q # Character ï»
+U+fed6 q # Character ï»
+U+fed7 q # Character ï»
+U+fed8 q # Character ï»
+U+fed9 k # Character ï»
+U+feda k # Character ï»
+U+fedb k # Character ï»
+U+fedc k # Character ï»
+U+fedd l # Character ï»
+U+fede l # Character ï»
+U+fedf l # Character ï»
+U+fee0 l # Character ï»
+U+fee1 m # Character ﻡ
+U+fee2 m # Character ﻢ
+U+fee3 m # Character ﻣ
+U+fee4 m # Character ﻤ
+U+fee5 n # Character ﻥ
+U+fee6 n # Character ﻦ
+U+fee7 n # Character ﻧ
+U+fee8 n # Character ﻨ
+U+fee9 h # Character ﻩ
+U+feea h # Character ﻪ
+U+feeb h # Character ﻫ
+U+feec h # Character ﻬ
+U+feed w # Character ï»
+U+feee w # Character ï»®
+#U+feef y̱ # Character ﻯ
+#U+fef0 y̱ # Character ﻰ
+U+fef1 y # Character ï»±
+U+fef2 y # Character ﻲ
+U+fef3 y # Character ﻳ
+U+fef4 y # Character ï»´
+#U+fef5 lẠ# Character ﻵ
+#U+fef6 lẠ# Character ﻶ
+#U+fef7 láº¡Ì # Character ï»·
+#U+fef8 láº¡Ì # Character ﻸ
+#U+fef9 lạ̹ # Character ﻹ
+#U+fefa lạ̹ # Character ﻺ
+#U+fefb lạ # Character ﻻ
+#U+fefc lạ # Character ﻼ
+U+fefd ? # Character ﻽
+U+fefe ? # Character ﻾
+U+feff ? # Character 
diff --git a/resources/chars/latin1/rowff.trans b/resources/chars/latin1/rowff.trans
new file mode 100644
index 0000000..43709e7
--- /dev/null
+++ b/resources/chars/latin1/rowff.trans
@@ -0,0 +1,264 @@
+#
+# This is a table for transliterating characters.
+# It was created using icu4j
+#
+# All resulting strings that contained characters outside the
+# range of iso 8859-1 are commented out
+#
+
+U+ff00 ? # Character ï¼
+U+ff01 ! # Character ï¼
+U+ff02 " # Character ï¼
+U+ff03 # # Character ï¼
+U+ff04 $ # Character ï¼
+U+ff05 % # Character ï¼
+U+ff06 & # Character ï¼
+U+ff07 ' # Character ï¼
+U+ff08 ( # Character ï¼
+U+ff09 ) # Character ï¼
+U+ff0a * # Character ï¼
+U+ff0b + # Character ï¼
+U+ff0c , # Character ï¼
+U+ff0d - # Character ï¼
+U+ff0e . # Character ï¼
+U+ff0f / # Character ï¼
+U+ff10 0 # Character ï¼
+U+ff11 1 # Character ï¼
+U+ff12 2 # Character ï¼
+U+ff13 3 # Character ï¼
+U+ff14 4 # Character ï¼
+U+ff15 5 # Character ï¼
+U+ff16 6 # Character ï¼
+U+ff17 7 # Character ï¼
+U+ff18 8 # Character ï¼
+U+ff19 9 # Character ï¼
+U+ff1a : # Character ï¼
+U+ff1b ; # Character ï¼
+U+ff1c < # Character ï¼
+U+ff1d = # Character ï¼
+U+ff1e > # Character ï¼
+U+ff1f ? # Character ï¼
+U+ff20 @ # Character ï¼
+U+ff21 A # Character A
+U+ff22 B # Character ï¼¢
+U+ff23 C # Character ï¼£
+U+ff24 D # Character D
+U+ff25 E # Character ï¼¥
+U+ff26 F # Character F
+U+ff27 G # Character G
+U+ff28 H # Character H
+U+ff29 I # Character I
+U+ff2a J # Character J
+U+ff2b K # Character K
+U+ff2c L # Character L
+U+ff2d M # Character ï¼
+U+ff2e N # Character ï¼®
+U+ff2f O # Character O
+U+ff30 P # Character ï¼°
+U+ff31 Q # Character ï¼±
+U+ff32 R # Character ï¼²
+U+ff33 S # Character ï¼³
+U+ff34 T # Character ï¼´
+U+ff35 U # Character ï¼µ
+U+ff36 V # Character V
+U+ff37 W # Character ï¼·
+U+ff38 X # Character X
+U+ff39 Y # Character ï¼¹
+U+ff3a Z # Character Z
+U+ff3b [ # Character ï¼»
+U+ff3c \ # Character ï¼¼
+U+ff3d ] # Character ï¼½
+U+ff3e ^ # Character ï¼¾
+U+ff3f _ # Character _
+U+ff40 ` # Character ï½
+U+ff41 a # Character ï½
+U+ff42 b # Character ï½
+U+ff43 c # Character ï½
+U+ff44 d # Character ï½
+U+ff45 e # Character ï½
+U+ff46 f # Character ï½
+U+ff47 g # Character ï½
+U+ff48 h # Character ï½
+U+ff49 i # Character ï½
+U+ff4a j # Character ï½
+U+ff4b k # Character ï½
+U+ff4c l # Character ï½
+U+ff4d m # Character ï½
+U+ff4e n # Character ï½
+U+ff4f o # Character ï½
+U+ff50 p # Character ï½
+U+ff51 q # Character ï½
+U+ff52 r # Character ï½
+U+ff53 s # Character ï½
+U+ff54 t # Character ï½
+U+ff55 u # Character ï½
+U+ff56 v # Character ï½
+U+ff57 w # Character ï½
+U+ff58 x # Character ï½
+U+ff59 y # Character ï½
+U+ff5a z # Character ï½
+U+ff5b { # Character ï½
+U+ff5c | # Character ï½
+U+ff5d } # Character ï½
+U+ff5e ~ # Character ï½
+#U+ff5f â¦
# Character ï½
+#U+ff60 ⦠# Character ï½
+#U+ff61 ã # Character 。
+#U+ff62 ã # Character ï½¢
+#U+ff63 ã # Character ï½£
+#U+ff64 ã # Character 、
+#U+ff65 ã» # Character ï½¥
+U+ff66 wo # Character ヲ
+U+ff67 ~a # Character ァ
+U+ff68 ~i # Character ィ
+U+ff69 ~u # Character ゥ
+U+ff6a ~e # Character ェ
+U+ff6b ~o # Character ォ
+U+ff6c ~ya # Character ャ
+U+ff6d ~yu # Character ï½
+U+ff6e ~yo # Character ï½®
+U+ff6f ~tsu # Character ッ
+#U+ff70 ã¼ # Character ï½°
+U+ff71 a # Character ï½±
+U+ff72 i # Character ï½²
+U+ff73 u # Character ï½³
+U+ff74 e # Character ï½´
+U+ff75 o # Character ï½µ
+U+ff76 ka # Character カ
+U+ff77 ki # Character ï½·
+U+ff78 ku # Character ク
+U+ff79 ke # Character ï½¹
+U+ff7a ko # Character コ
+U+ff7b sa # Character ï½»
+U+ff7c shi # Character ï½¼
+U+ff7d su # Character ï½½
+U+ff7e se # Character ï½¾
+U+ff7f so # Character ソ
+U+ff80 ta # Character ï¾
+U+ff81 chi # Character ï¾
+U+ff82 tsu # Character ï¾
+U+ff83 te # Character ï¾
+U+ff84 to # Character ï¾
+U+ff85 na # Character ï¾
+U+ff86 ni # Character ï¾
+U+ff87 nu # Character ï¾
+U+ff88 ne # Character ï¾
+U+ff89 no # Character ï¾
+U+ff8a ha # Character ï¾
+U+ff8b hi # Character ï¾
+U+ff8c fu # Character ï¾
+U+ff8d he # Character ï¾
+U+ff8e ho # Character ï¾
+U+ff8f ma # Character ï¾
+U+ff90 mi # Character ï¾
+U+ff91 mu # Character ï¾
+U+ff92 me # Character ï¾
+U+ff93 mo # Character ï¾
+U+ff94 ya # Character ï¾
+U+ff95 yu # Character ï¾
+U+ff96 yo # Character ï¾
+U+ff97 ra # Character ï¾
+U+ff98 ri # Character ï¾
+U+ff99 ru # Character ï¾
+U+ff9a re # Character ï¾
+U+ff9b ro # Character ï¾
+U+ff9c wa # Character ï¾
+U+ff9d n # Character ï¾
+#U+ff9e ã # Character ï¾
+#U+ff9f ã # Character ï¾
+#U+ffa0 á
# Character ï¾
+U+ffa1 g # Character ᄀ
+U+ffa2 kk # Character ï¾¢
+U+ffa3 gs # Character ï¾£
+U+ffa4 n # Character ᄂ
+U+ffa5 nj # Character ï¾¥
+U+ffa6 nh # Character ᆭ
+U+ffa7 d # Character ᄃ
+U+ffa8 tt # Character ᄄ
+U+ffa9 l # Character ᄅ
+U+ffaa lg # Character ᆰ
+U+ffab lm # Character ᆱ
+U+ffac lb # Character ᆲ
+U+ffad ls # Character ï¾
+U+ffae lt # Character ï¾®
+U+ffaf lp # Character ᆵ
+#U+ffb0 á # Character ï¾°
+U+ffb1 m # Character ï¾±
+U+ffb2 b # Character ï¾²
+U+ffb3 pp # Character ï¾³
+#U+ffb4 á¡ # Character ï¾´
+U+ffb5 s # Character ï¾µ
+U+ffb6 ss # Character ᄊ
+U+ffb7 # Character ï¾·
+U+ffb8 j # Character ᄌ
+U+ffb9 jj # Character ï¾¹
+U+ffba ch # Character ᄎ
+U+ffbb k # Character ï¾»
+U+ffbc t # Character ï¾¼
+U+ffbd p # Character ï¾½
+U+ffbe h # Character ï¾¾
+U+ffbf ? # Character ﾿
+U+ffc0 ? # Character ï¿
+U+ffc1 ? # Character ï¿
+U+ffc2 a # Character ï¿
+U+ffc3 ae # Character ï¿
+U+ffc4 ya # Character ï¿
+U+ffc5 yae # Character ï¿
+U+ffc6 eo # Character ï¿
+U+ffc7 e # Character ï¿
+U+ffc8 ? # Character ï¿
+U+ffc9 ? # Character ï¿
+U+ffca yeo # Character ï¿
+U+ffcb ye # Character ï¿
+U+ffcc o # Character ï¿
+U+ffcd wa # Character ï¿
+U+ffce wae # Character ï¿
+U+ffcf oe # Character ï¿
+U+ffd0 ? # Character ï¿
+U+ffd1 ? # Character ï¿
+U+ffd2 yo # Character ï¿
+U+ffd3 u # Character ï¿
+U+ffd4 wo # Character ï¿
+U+ffd5 we # Character ï¿
+U+ffd6 wi # Character ï¿
+U+ffd7 yu # Character ï¿
+U+ffd8 ? # Character ï¿
+U+ffd9 ? # Character ï¿
+U+ffda eu # Character ï¿
+U+ffdb ui # Character ï¿
+U+ffdc i # Character ï¿
+U+ffdd ? # Character ï¿
+U+ffde ? # Character ï¿
+U+ffdf ? # Character ï¿
+U+ffe0 ¢ # Character ï¿
+U+ffe1 £ # Character £
+U+ffe2 ¬ # Character ¬
+#U+ffe3 Ì # Character ï¿£
+U+ffe4 ¦ # Character ¦
+U+ffe5 ¥ # Character ¥
+#U+ffe6 ⩠# Character ₩
+U+ffe7 ? # Character ￧
+#U+ffe8 â # Character │
+#U+ffe9 â # Character ï¿©
+#U+ffea â # Character ↑
+#U+ffeb â # Character ï¿«
+#U+ffec â # Character ↓
+#U+ffed â # Character ï¿
+#U+ffee â # Character ï¿®
+U+ffef ? # Character ￯
+U+fff0 ? # Character ï¿°
+U+fff1 ? # Character ￱
+U+fff2 ? # Character ￲
+U+fff3 ? # Character ￳
+U+fff4 ? # Character ï¿´
+U+fff5 ? # Character ￵
+U+fff6 ? # Character ￶
+U+fff7 ? # Character ï¿·
+U+fff8 ? # Character ￸
+U+fff9 ? # Character 
+U+fffa ? # Character 
+U+fffb ? # Character ï¿»
+U+fffc ? # Character 
+U+fffd ? # Character �
+U+fffe ? # Character ￾
+U+ffff ? # Character ï¿¿
diff --git a/resources/help/en/copyright b/resources/help/en/copyright
new file mode 100644
index 0000000..43aaf5e
--- /dev/null
+++ b/resources/help/en/copyright
@@ -0,0 +1,12 @@
+
+This software is Copyright 2006-2012 by the mkgmap authors
+and contributors.
+
+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.
diff --git a/resources/help/en/help b/resources/help/en/help
new file mode 100644
index 0000000..3aa96df
--- /dev/null
+++ b/resources/help/en/help
@@ -0,0 +1,12 @@
+
+Help is available on the following topics:
+
+--help=options
+ The command line options
+
+--help=links
+ Browser links to more information about mkgmap
+ and Open Street Map.
+
+--help=copyright
+ Copyright information
diff --git a/resources/help/en/inputs b/resources/help/en/inputs
new file mode 100644
index 0000000..2896725
--- /dev/null
+++ b/resources/help/en/inputs
@@ -0,0 +1,27 @@
+
+OSM 0.5 api XML format
+----------------------
+This is the newer format consisting of just nodes and ways, that is
+due to go live on Sun 7 Oct 2007. This is recognised by looking for
+the version declaration within the file. Once the 0.5 version is
+established, then this will become the default version for mkgmap.
+
+Polish format
+-------------
+This reads the map format that is read by cGPSmapper and produced
+by map editing programs such as GPSMapEdit. If an input file ends
+with .mp the it is assumed to be in this format. The support is
+pretty basic and is more of a proof of concept. It does handle
+some files well though.
+
+Test maps
+---------
+There are some built in maps in mkgmap. These all have names
+beginning test-map:. This is a way of producing a map for
+development purposes without actually needing an input file.
+The ones available may change over time. The most useful one
+that is likely to stay contains every single element that can
+be displayed in a Garmin map. To produce this map, just use
+test-map:all-elements instead of a file name.
+
+ mkgmap test-map:all-elements
diff --git a/resources/help/en/links b/resources/help/en/links
new file mode 100644
index 0000000..a8e6ee9
--- /dev/null
+++ b/resources/help/en/links
@@ -0,0 +1,32 @@
+
+Main mkgmap links
+-----------------
+The mkgmap home page:
+ http://www.mkgmap.org.uk
+
+The mkgmap download page:
+ http://www.mkgmap.org.uk/snapshots/
+
+OpenStreetMap mkgmap pages
+--------------------------
+The mkgmap page on the OSM wiki:
+ http://wiki.openstreetmap.org/index.php/Mkgmap
+
+Help page for mkgmap on the OSM wiki:
+ http://wiki.openstreetmap.org/index.php/Mkgmap/help
+
+The mkgmap development wiki page:
+ http://wiki.openstreetmap.org/index.php/Mkgmap/dev
+
+General OpenStreetMap links
+---------------------------
+OpenStreetMap main page:
+ http://www.openstreetmap.org/
+
+OpenStreetMap wiki:
+ http://wiki.openstreetmap.org/
+
+Other links
+-----------
+Garmin img format documentation:
+ http://sourceforge.net/projects/garmin-img
diff --git a/resources/help/en/options b/resources/help/en/options
new file mode 100644
index 0000000..280c28c
--- /dev/null
+++ b/resources/help/en/options
@@ -0,0 +1,631 @@
+Note that option order is significant: An option only applies to
+subsequent input files. (So if you are using splitter, you probably
+want to put most of your options before '-c template.args'.)
+
+General options:
+
+--help=topic
+ Print help on the given topic. If the topic is omitted then a
+ list of all the help topics is printed instead.
+
+--version
+ Output program version to stderr.
+
+filename
+--input-file=filename
+ Read input data from the give file. This option (or just a
+ filename) may be given more than once.
+
+--gmapsupp
+ Create a gmapsupp.img file that can be uploaded to a Garmin or
+ placed in "/Garmin" in a microSD card (such as by mounting the
+ device in USB mass storage mode). It can be used on ready
+ compiled img files, if the input files are not already compiled
+ then they are compiled first and then the gmapsupp is created.
+
+-c filename
+--read-config=filename
+ The given file is opened and each line is an option setting of
+ the form option=value, any option that could be used on the command
+ line can be used, however you omit the leading '--'. The short
+ option names with a single '-' cannot be used, simply use the
+ long name instead.
+
+--output-dir=filename
+ The directory in which all output files are written. It defaults
+ to the current working directory, ie. the directory the command is
+ executed from.
+
+-n name
+--mapname=name
+ Set the name of the map. Garmin maps are named by 8 digit
+ numbersList. The default is 63240001. It is best to use a different
+ name if you are going to be making a map for others to use so
+ that it is unique and does not clash with others.
+
+--description=text
+ Sets the descriptive text for the map. This may be displayed in
+ QLandkarte, MapSource on on a GPS etc, where it is normally shown
+ below the family name. Example: --description="Germany, Denmark"
+ Please note: if you use splitter.jar to build a template.args file
+ and use -c template.args, then that file may contain a
+ "description" that will override this option. Use "--description" in
+ splitter.jar to change the description in the template.args file.
+
+--country-name=name
+ Sets the map's country name. The default is "COUNTRY".
+
+--country-abbr=abbreviation
+ Sets the map's abbreviated country name. The default is "ABC".
+
+--region-name=name
+ Sets the map's region name. By default, the map has no region name.
+
+--region-abbr=abbreviation
+ Sets the map's abbreviated region name. By default, the map has
+ no abbreviated region name.
+
+Label options:
+
+--latin1
+ This is equivalent to --code-page=1252.
+
+--code-page=number
+ This option enables the use of international characters. Only 8 bit
+ character sets are supported and so you have to specify which code page
+ you want to use.
+
+ It is entirely dependant on the device firmware which code pages are
+ supported.
+
+--charset=name
+ This option is obsolete. Change the character set with the --code-page
+ option.
+
+--lower-case
+ Allow labels to contain lower case letters. Note that most or all
+ Garmin devices are not able to display lower case letters at an angle
+ so this option is not generally useful.
+
+Address search options:
+--index
+ Generate a global address search index. If the --gmapsupp option is
+ also given, then the index is generated within the resulting
+ gmapsupp.img file so that address search will work on a GPS
+ device.
+
+ If instead the --tdbfile option is given then the index consists
+ of two files named osmmap.mdx and osmmap_mdr.img which can be used
+ with mapsource. (For compatibility, you do not need the tdbfile
+ option if gmapsupp is not given).
+
+ If both the --gmapsupp and --tdbfile options are given alongside
+ the --index option, then both indexes will be created. Note that
+ this will require roughly twice as much memory.
+
+ The --overview-mapname option can be used to change these names. If
+ the mapset is sent to the device from MapSource, it will enable
+ find by name and address search on the GPS.
+
+ The address fields are assigned by special mkgmap address
+ tags using the style file:
+ mkgmap:country
+ mkgmap:region
+ mkgmap:city
+ mkgmap:postal_code
+ mkgmap:street
+ mkgmap:housenumber
+ mkgmap:phone
+ (mkgmap:is_in - used by location-autofill=is_in)
+
+ If the index is created from previously compiled .img files, then the
+ same code page and sorting options (eg. --code-page, --latin1 etc) must
+ be used as were used to compile the individual map tiles.
+
+--bounds=directory|zipfile
+ A directory or a zipfile containing the preprocessed bounds files.
+ Bounds files in a zipfile must be located in the zipfiles root directory.
+
+ The preprocessed boundaries are used to add special tags to all elements
+ (points, lines and polygons) containing the elements location information.
+ The style file can be used to assign the address tags mkgmap:country,
+ mkgmap:region etc. using these values.
+
+ The following special tags are added:
+ mkgmap:admin_level2 : Name of the admin_level=2 boundary
+ mkgmap:admin_level3 : Name of the admin_level=3 boundary
+ ..
+ mkgmap:admin_level11
+ mkgmap:postcode : the postal_code value
+
+ Preprocessed bounds can be created with the following command:
+ java -cp mkgmap.jar
+ uk.me.parabola.mkgmap.reader.osm.boundary.BoundaryPreprocessor
+ <inputfile> <boundsdir>
+
+ The input file must contain the boundaries that should be preprocessed.
+ It can have OSM, PBF or O5M fileformat. It is recommended that it
+ contains the boundary data only to avoid very high memory usage.
+ The boundsdir gives the directory where the processed files are stored.
+ This directory can be used as --bounds parameter with mkgmap.
+
+--location-autofill=[option1,[option2]]
+ Controls how the address fields for country, region, city and zip info
+ are gathered automatically if the fields are not set by using the special
+ mkgmap address tags (e.g. mkgmap:city - see option index).
+ Warning: automatic assignment of address fields is somehow a best guess.
+
+ is_in The is_in tag is analyzed for country and region information.
+
+ nearest The city/hamlet points that are closest to the element are used
+ to assign the missing address fields. Beware that cities located
+ in the same tile are used only. So the results close to a tile
+ border have less quality.
+
+--housenumbers
+ Enables house number search for OSM input files.
+ All nodes and polygons having addr:housenumber and addr:street set are matched
+ to streets. A match between a house number element and a street is created if
+ the street is located within a radius of 150m and the addr:street tag value of
+ the house number element equals the mgkmap:street tag value of the street.
+ The mkgmap:street tag must be added to the street in the style file.
+ Example:
+ Node - addr:street=Main Street addr:housenumber=2
+ Way 1 - name=Main Street
+ Way 2 - name=Main Street, mkgmap:street=Main Street
+ Way 3 - mkgmap:street=Mainstreet
+ Way 4 - name=Main Street [A504]
+ The node matches to way 2. It has mkgmap:street set with a value equal to
+ the addr:street tag value of the house number node.
+
+Overview map options:
+--overview-mapname=name
+ If --tdbfile is enabled, this gives the name of the overview
+ .img and .tdb files. The default map name is osmmap.
+
+--overview-mapnumber=8 digit number
+ If --tdbfile is enabled, this gives the internal 8 digit
+ number used in the overview map and tdb file. The default
+ number is 63240000.
+
+--overview-levels
+ like levels, specifies additional levels that are to be written to the
+ overview map. Counting of the levels should continue. Up to 8 additional
+ levels may be specified, but the lowest usable resolution with MapSource
+ seems to be 11. The hard coded default is empty.
+
+--remove-ovm-work-files
+ If overview-levels is used, mkgmap creates one additional file
+ with the prefix ovm_ for each map (*.img) file.
+ These files are used to create the overview map.
+ With option --remove-ovm-work-files=true the files are removed
+ after the overview map was created. The default is to keep the files.
+
+Style options:
+--style-file=file
+ Specify an external file to obtain the style from. "file" can
+ be a directory containing files such as info, lines, options
+ (see resources/styles/default for an example). The directory
+ path must be absolute or relative to the current working
+ directory when mkgmap is invoked.
+
+ The file can be a zip file containing the files instead of a
+ directory.
+
+ The files can be at the top level or contained in a folder within
+ the zip file. If the zip file contains more than one top level
+ folder then each folder is the name of a style that can be selected
+ with the --style option.
+
+ The argument can also be a URL that specifies the location of a
+ style file.
+
+--style=name
+ Specify a style name. Must be used if --style-file points to a
+ directory or zip file containing multiple styles. If --style-file
+ is not used, it selects one of the builtin styles.
+
+--list-styles
+ List the available styles. If this option is preceeded by a style-file
+ option then it lists the styles available within that file.
+
+--check-styles
+ Perform some checks on the available styles. If this option is
+ preceeded by a style-file option then it checks the styles
+ available within that file. If it is also preceded by the style
+ option it will only check that style.
+
+--levels=levels code
+ Change the way that the levels on the map correspond to the zoom
+ levels in the device. See customisation help. The default is:
+ "0:24, 1:22, 2:20, 3:18, 4:16", although each style can have
+ its own default. Up to 8 levels may be specified.
+
+--name-tag-list
+ Get the tag that will be used to supply the name. Useful for
+ language variations. You can supply a list and the first one
+ will be used. eg. --name-tag-list=name:en,int_name,name
+
+--map-features=file
+ This option is ignored; use the --style-file option instead.
+
+Product description options:
+
+--family-id
+ This is an integer that identifies a family of products.
+ Range: [1..9999]
+ Mkgmap default: 6324
+
+--family-name
+ If you build several maps, this option describes the
+ family name of all of your maps. Garmin will display this
+ in the map selection screen.
+ Example: --family-name="OpenStreetmap mkgmap XL 2019"
+
+--product-id
+ This is an integer that identifies a product within a family.
+ It is often just 1, which is the default.
+
+--product-version
+ The version of the product. Default value is 1.
+
+--series-name
+ This name will be displayed in MapSource in the map selection
+ drop-down. The default is "OSM map".
+
+--area-name
+ Area name is displayed on Garmin units (or at least on eTrex) as the second
+ part of the mapname in the list of the individual maps.
+
+--copyright-message=note
+ Specify a copyright message for files that do not contain one.
+
+--license-file=file
+ Specify a file which content will be added as license.
+ All entrys of all maps will be merged in the overview map.
+
+Optimization options:
+
+--reduce-point-density=NUM
+ Simplifies the ways with the Douglas Peucker algorithm.
+ NUM is the maximal allowed error distance, by which the resulting
+ way may differ from the original one.
+ This distance gets shifted with lower zoom levels.
+ Recommended setting is 4, this should lead to only small differences
+ (Default is 2.6, which should lead to invisible changes)
+
+--reduce-point-density-polygon=NUM
+ Allows to set the maximal allowed error distance for the DP algorythm
+ to be applied against polygons. Recommended setting is 8.
+
+--merge-lines
+ Try to merge lines. This helps the simplify filter to straighten out
+ longer chunks at lower zoom levels. Decreases file size more.
+ Increases paint speed at low zoom levels.
+ Default is enabled, use --no-merge-lines to disable.
+
+--min-size-polygon=NUM
+ Removes all polygons smaller than NUM from the map.
+ This reduces map size and speeds up redrawing of maps.
+ Recommended value is 8 to 15, default is 8.
+ See also polygon-size-limits.
+
+--polygon-size-limits=limits code
+ Allows to specify different min-size-polygon values for each resolution.
+ Sample:
+ --polygon-size-limits="24:12, 18:10, 16:8, 14:4, 12:2, 11:0"
+ If a resolution is not given, mkgmap uses the value for the next higher
+ one. For the given sample, resolutions 19 to 24 will use value 12,
+ resolution 17 and 18 will use 10, and so on.
+ Value 0 means to skip the size filter.
+ Note that in resolution 24 the filter is not used.
+
+Miscellaneous options:
+
+--max-jobs[=number]
+ When number is specified, allow that number of maps to be
+ processed concurrently. If number is not specified, the limit
+ is set equal to the number of CPU cores. If this option is not
+ given at all, the limit is 1 (i.e., the maps are processed
+ sequentially).
+
+--keep-going
+ Don't quit whole application if an exception occurs while
+ processing a map - continue to process the other maps.
+
+--block-size=number
+ Changes the block size that is used in the generated map. This
+ option is not usually needed, but sometimes an error message
+ will ask you to try a value for this option.
+
+--net
+ Obsolete, use --route instead.
+
+--route
+ Create maps that support routing.
+
+--drive-on-left
+--drive-on-right
+ Explicitly specify which side of the road vehicles are
+ expected to drive on. If neither of these options are
+ specified, it is assumed that vehicles drive on the right
+ unless --check-roundabouts is specified and the first
+ roundabout processed is clockwise.
+
+--check-roundabouts
+ Check that roundabouts have the expected direction (clockwise
+ when vehicles drive on the left). Roundabouts that are complete
+ loops and have the wrong direction are reversed. Also checks
+ that the roundabouts do not fork or overlap other roundabouts.
+
+--check-roundabout-flares
+ Sanity check roundabout flare roads - warn if they don't point
+ in the correct direction or if they are not oneway or if they
+ extend too far.
+
+--max-flare-length-ratio=NUM
+ When checking flare roads, ignore roads whose length is
+ greater than NUM (an integer) times the distance between the
+ nodes on the roundabout that the flare roads connect to. Using
+ this option with a value of at least 5 will cut down the
+ number of legitimate roads that are flagged as flare road
+ problems. Default value is 0 (disabled) because it's not a
+ completely reliable heuristic.
+
+--ignore-builtin-relations
+ When reading OSM files, skip the built-in processing of
+ relations. This speeds up the processing non-routable map
+ layers that do not contain multipolygons. This implies
+ --ignore-turn-restrictions.
+
+--ignore-turn-restrictions
+ When reading OSM files, ignore any "restriction" relations.
+
+--ignore-osm-bounds
+ When reading OSM files, ignore any "bounds" elements.
+ With this option selected generate-sea sometimes works better,
+ but routing across tiles will not work.
+
+--preserve-element-order
+ Process the map elements (nodes, ways, relations) in the order
+ in which they appear in the OSM input. Without this option,
+ the order in which the elements are processed is not defined.
+
+--remove-short-arcs[=MinLength]
+ Merge nodes to remove short arcs that can cause routing
+ problems. If MinLength is specified (in metres), arcs shorter
+ than that length will be removed. If a length is not
+ specified, only zero-length arcs will be removed.
+
+--adjust-turn-headings[=BITMASK]
+ Where possible, ensure that turns off to side roads change
+ heading sufficiently so that the GPS believes that a turn is
+ required rather than a fork. This also avoids spurious
+ instructions to "keep right/left" when the road doesn't
+ actually fork.
+
+ Optional BITMASK (default value 3) allows you to specify which
+ adjustments are to be made (where necessary):
+
+ 1 = increase angle between side road and outgoing main road
+ 2 = increase angle between side road and incoming main road
+
+--report-similar-arcs
+ Issue a warning when more than one arc connects two nodes and
+ the ways that the arcs are derived from contain identical
+ points. It doesn't make sense to use this option at the same
+ time as using the cycleway creating options.
+
+--report-dead-ends=LEVEL
+ Set the dead end road warning level. The value of LEVEL (which
+ defaults to 1 if this option is not specified) determines
+ those roads to report: 0 = none, 1 = multiple oneway roads
+ that join together but go nowhere, 2 = individual oneway roads
+ that go nowhere.
+
+--road-name-pois[=GarminCode]
+ Generate a POI for each named road. By default, the POIs'
+ Garmin type code is 0x640a. If desired, a different type code
+ can be specified with this option. This is a workaround for not
+ being able to search for roads.
+ 0x2f15: a blue dot in the middle of the road, and if you select,
+ or 'hover' over it, the streetname appears.
+
+--add-pois-to-lines
+ Generate POIs for lines. For each line (must not be closed) POIs are
+ created at several points of the line. Each POI is tagged with the
+ same tags like the line and additional tags added by mkgmap:
+ mkgmap:line2poi=true and tag mkgmap:line2poitype having
+ the following values:
+ * start - The first point of the line
+ * end - The last point of the line
+ * inner - Each point of the line except the first and the last
+ * mid - The middle point
+
+--add-pois-to-areas
+ Generate a POI for each polygon and multipolygon. The POIs are created
+ after the relation style but before the other styles are applied. Each
+ POI is tagged with the same tags of
+ the area/multipolygon. Additionally the tag mkgmap:area2poi=true is
+ set so that it is possible to use that information in the points style
+ file. Artifical polygons created by multipolyon processing are not used.
+ The POIs are created at the following positions (first rule that applies):
+ polygons:
+ * the first node tagged with a tag defined by the pois-to-areas-placement
+ option
+ * the center point
+ multipolygons:
+ * the node with role=label
+ * the center point of the biggest area
+
+--pois-to-areas-placement[=taglist]
+ A semicolon separated list of tag=value definitions. A POI is placed at the first
+ node of the polygon tagged with the first tag/value pair. If none of the nodes are
+ tagged with the first tag-value pair the first node tagged with the second tag-value
+ pair is used and so on. If none of the tag-value pairs matches or the taglist is empty
+ the center of the polygon is used.
+ It is possible to define wildcards for tag values like entrance=*.
+ Default: entrance=main;entrance=yes;building=entrance
+
+--precomp-sea=directory|zipfile
+ Defines the directory or a zip file that contains precompiled sea tiles.
+ Sea files in a zipfile must be located in the zipfiles root directory or in
+ a sub directory sea. When this option is defined all natural=coastline tags
+ from the input OSM tiles are removed and the precompiled data is used instead.
+ This option can be combined with the generate-sea options multipolygon, polygons
+ and land-tag. The coastlinefile option is ignored if precomp-sea is set.
+
+--coastlinefile=filename[,filename]
+ Defines a comma separated list of files that contain coastline
+ data. The coastline data from the input files is removed if
+ this option is set. Files must have OSM or PBF fileformat.
+
+--generate-sea[=ValueList]
+ Generate sea polygons. ValueList is an optional comma
+ separated list of values:
+
+ multipolygon
+ generate the sea using a multipolygon (the default
+ behaviour so this really doesn't need to be specified).
+
+ polygons | no-mp
+ don't generate the sea using a multipolygon - instead,
+ generate a background sea polygon plus individual land
+ polygons with tag natural=land. This requires a
+ suitable land polygon type to be defined in the style
+ file (suggested type is 0x010100) and the polygon must
+ be defined in the TYP file as having a higher drawing
+ level than the sea polygon type.
+
+ no-sea-sectors
+ disable the generation of "sea sectors" when the
+ coastline fails to reach the tile's boundary.
+
+ extend-sea-sectors
+ same as no-sea-sectors. Additional adds a point so
+ coastline reaches the nearest tile boundary.
+
+ land-tag=TAG=VAL
+ tag to use for land polygons (default natural=land).
+
+ close-gaps=NUM
+ close gaps in coastline that are less than this
+ distance (metres)
+
+ floodblocker
+ enable the flood blocker that prevents a flooding of
+ land by checking if the sea polygons contain streets
+ (works only with multipolygon processing)
+
+ fbgap=NUM
+ flood blocker gap in metre (default 40)
+ points that are closer to the sea polygon do not block
+
+ fbthres=NUM
+ at least so many highway points must be contained in
+ a sea polygon so that it may be removed by the flood
+ blocker (default 20)
+
+ fbratio=NUM
+ only sea polygons with a higher ratio
+ (highway points * 100000 / polygon size) are removed
+ (default 0.5)
+
+ fbdebug
+ switches on the debugging of the flood blocker
+ generates GPX files for each polygon checked by
+ the flood blocker
+
+--make-poi-index
+ Generate the POI index (not yet useful).
+
+--nsis
+ Write a .nsi file that can be used with the Nullsoft Scriptable Install System
+ (NSIS) to create a Windows Mapsource Installer.
+
+--make-all-cycleways
+ Turn on all of the options that make cycleways.
+
+--make-opposite-cycleways
+ Some oneway streets allow bicycle traffic in the reverse
+ direction and this option makes a way with the same points as
+ the original that allows bicycle traffic (in both directions).
+
+--make-cycleways
+ Some streets have a separate cycleway track/lane just for
+ bicycle traffic and this option makes a way with the same
+ points as the original that allows bicycle traffic. Also,
+ bicycle traffic is prohibited from using the original way
+ (unless that way's bicycle access has been defined).
+
+--link-pois-to-ways
+ This option copies some specific attributes of a POI to a
+ small part of the way the POI is located on. This can be used
+ to let barriers block a way or to lower the calculated speed
+ around traffic signals.
+ POIs with the tags highway=* (e.g. highway=traffic_signals)
+ or barrier=* (e.g. barrier=cycle_barrier) are supported.
+ The style developer must add at least one of the access tags
+ (mkgmap:foot, mkgmap:car etc.), mkgmap:road-speed and/or
+ mkgmap:road-class to the POI. These tags are copied to a small
+ part of the way around the POI.
+
+--process-destination
+ Splits all motorway_link and trunk_link ways tagged with
+ destination into two or three parts where the second part
+ is additionally tagged with mkgmap:dest_hint=true. This
+ allows to use any routable Garmin type (except 0x08 and 0x09)
+ for that part so that the Garmin device tells the name of
+ this part as hint which destination to follow.
+
+--process-exits
+ Usual Garmin devices do not tell the name of the exit on motorways
+ while routing with mkgmap created maps. This option splits the each
+ motorway_link and trunk_link into three parts. All parts are tagged
+ with the original tags of the link. Additionally the middle part is
+ tagged with the following tags:
+ mkgmap:exit_hint=true
+ mkgmap:exit_hint_ref=<ref tag value of the exit>
+ mkgmap:exit_hint_name=<name tag value of the exit>
+ mkgmap:exit_hint_exit_to=<exit_to tag value of the exit>
+ Adding a rule checking the mkgmap:exit_hint=true makes it possible
+ to use any routable Garmin type (except 0x08 and 0x09) for the middle
+ part so that the Garmin device tells the name of this middle part as
+ hint where to leave the motorway/trunk.
+
+--delete-tags-file=FILENAME
+ Names a file that should contain one or more lines of the form
+ TAG=VALUE or TAG=*. Blank lines and lines that start with
+ # or ; are ignored. All tag/value pairs in the OSM input are
+ compared with these patterns and those that match are deleted.
+
+--tdbfile
+ Write files that are essential to running with MapSource, a .tdb file and
+ an overview map.
+
+--show-profiles=1
+ Sets a flag in tdb file which marks set mapset as having contour
+ lines and allows showing profile in MapSource. Default is 0
+ which means disabled.
+
+--draw-priority=25
+ When two maps cover the same area, this option controls what
+ order they are drawn in and therefore which map is on top of
+ which. Higher priorities are drawn "on top" of lower
+ priorities.
+
+--transparent
+ Make the map transparent, so that if two maps are loaded that
+ cover the same area, you can see through this map and see the
+ lower map too. Useful for contour line maps among other
+ things.
+
+--poi-address
+ Enable address / phone information to POIs. Address info is
+ read according to the "Karlsruhe" tagging schema. Automatic
+ filling of missing information could be enabled using the
+ "location-autofill" option.
+ Default is enabled, use --no-poi-address to disable.
+
+--verbose
+ Makes some operations more verbose. Mostly used with --list-styles.
diff --git a/resources/installer/installer_template.nsi b/resources/installer/installer_template.nsi
new file mode 100644
index 0000000..7e7caab
--- /dev/null
+++ b/resources/installer/installer_template.nsi
@@ -0,0 +1,132 @@
+; INSERT_DEFINES_HERE
+
+SetCompressor /SOLID lzma
+
+; Includes
+!include "MUI2.nsh"
+
+; Installer pages
+!define MUI_CUSTOMFUNCTION_GUIINIT myGuiInit
+!insertmacro MUI_PAGE_WELCOME
+!insertmacro MUI_PAGE_LICENSE ${MAPNAME}_license.txt
+!insertmacro MUI_PAGE_DIRECTORY
+!insertmacro MUI_PAGE_INSTFILES
+!insertmacro MUI_PAGE_FINISH
+
+; Uninstaller pages
+!define MUI_UNPAGE_INSTFILES
+
+; Language files
+!define MUI_LANGDLL_ALLLANGUAGES
+!insertmacro MUI_LANGUAGE "English"
+!insertmacro MUI_LANGUAGE "French"
+!insertmacro MUI_LANGUAGE "Spanish"
+!insertmacro MUI_LANGUAGE "German"
+!insertmacro MUI_LANGUAGE "Dutch"
+
+
+LangString AlreadyInstalled ${LANG_ENGLISH} "${INSTALLER_NAME} is already installed. $\n$\nClick `OK` to remove the previous version and continue installation or `Cancel` to cancel this upgrade."
+LangString AlreadyInstalled ${LANG_FRENCH} "${INSTALLER_NAME} est déjà installé. $\n$\nAppuyez sur `OK` pour retirer la version précédente et continuer avec l'installation ou sur `Annuler` pour annuler cette mise à jour."
+LangString AlreadyInstalled ${LANG_SPANISH} "${INSTALLER_NAME} ya está instalado. $\n$\nPulse `Aceptar` para eliminar la versión anterior y continuar la instalación o `Cancelar` para cancelar esta actualización."
+LangString AlreadyInstalled ${LANG_GERMAN} "${INSTALLER_NAME} ist bereits installiert. $\n$\nKlick `OK` um die alte Version zu deinstallieren oder `Abbrechen` um die Installation abzubrechen."
+LangString AlreadyInstalled ${LANG_DUTCH} "${INSTALLER_NAME} is reeds geinstalleerd. $\n$\nKlik op `OK` om de oude versie te verwijderen of `Annuleren` om deze update te onderbreken."
+
+; Reservefiles
+!insertmacro MUI_RESERVEFILE_LANGDLL ;Language selection dialog
+
+
+Name "${INSTALLER_DESCRIPTION}"
+OutFile "${INSTALLER_NAME}.exe"
+InstallDir "${DEFAULT_DIR}"
+
+Function .onInit
+ !insertmacro MUI_LANGDLL_DISPLAY
+FunctionEnd
+
+Function myGUIInit
+ ; Uninstall before installing (code from http://nsis.sourceforge.net/Auto-uninstall_old_before_installing_new )
+ ReadRegStr $R0 HKLM \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\${REG_KEY}" "UninstallString"
+ StrCmp $R0 "" done
+
+ IfSilent silent
+ MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "$(AlreadyInstalled)" IDOK uninst
+ Abort
+
+ ;Run the uninstaller
+ uninst:
+ ClearErrors
+ ExecWait '"$R0" _?=$INSTDIR' ;Do not copy the uninstaller to a temp file
+
+ IfErrors no_remove_uninstaller done
+ ;You can either use Delete /REBOOTOK in the uninstaller or add some code
+ ;here to remove the uninstaller. Use a registry key to check
+ ;whether the user has chosen to uninstall. If you are using an uninstaller
+ ;components page, make sure all sections are uninstalled.
+ no_remove_uninstaller:
+
+ Goto done
+
+ silent:
+ ExecWait '"$R0" /S _?=$INSTDIR' ;Do not copy the uninstaller to a temp file
+
+ done:
+
+FunctionEnd
+
+Function un.onInit
+!insertmacro MUI_UNGETLANGUAGE
+FunctionEnd
+
+Section "MainSection" SectionMain
+; Files to be installed
+ SetOutPath "$INSTDIR"
+; INSERT_ADDED_FILES_HERE
+
+; Create MapSource registry keys
+; INSERT_REGBIN_HERE
+!ifdef INDEX
+ WriteRegStr HKLM "SOFTWARE\Garmin\MapSource\Families\${REG_KEY}" "IDX" "$INSTDIR\${MAPNAME}.mdx"
+ WriteRegStr HKLM "SOFTWARE\Garmin\MapSource\Families\${REG_KEY}" "MDR" "$INSTDIR\${MAPNAME}_mdr.img"
+!endif
+!ifdef TYPNAME
+ WriteRegStr HKLM "SOFTWARE\Garmin\MapSource\Families\${REG_KEY}" "TYP" "$INSTDIR\${TYPNAME}"
+!endif
+ WriteRegStr HKLM "SOFTWARE\Garmin\MapSource\Families\${REG_KEY}\${PRODUCT_ID}" "BMAP" "$INSTDIR\${MAPNAME}.img"
+ WriteRegStr HKLM "SOFTWARE\Garmin\MapSource\Families\${REG_KEY}\${PRODUCT_ID}" "LOC" "$INSTDIR"
+ WriteRegStr HKLM "SOFTWARE\Garmin\MapSource\Families\${REG_KEY}\${PRODUCT_ID}" "TDB" "$INSTDIR\${MAPNAME}.tdb"
+
+; Write uninstaller
+ WriteUninstaller "$INSTDIR\Uninstall.exe"
+
+; Create uninstaller registry keys
+ WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${REG_KEY}" "DisplayName" "$(^Name)"
+ WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${REG_KEY}" "UninstallString" "$INSTDIR\Uninstall.exe"
+ WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${REG_KEY}" "NoModify" 1
+
+SectionEnd
+
+Section "Uninstall"
+; Files to be uninstalled
+; INSERT_REMOVED_FILES_HERE
+
+ RmDir "$INSTDIR"
+
+; Registry cleanup
+ DeleteRegValue HKLM "SOFTWARE\Garmin\MapSource\Families\${REG_KEY}" "ID"
+!ifdef INDEX
+ DeleteRegValue HKLM "SOFTWARE\Garmin\MapSource\Families\${REG_KEY}" "IDX"
+ DeleteRegValue HKLM "SOFTWARE\Garmin\MapSource\Families\${REG_KEY}" "MDR"
+!endif
+!ifdef TYPNAME
+ DeleteRegValue HKLM "SOFTWARE\Garmin\MapSource\Families\${REG_KEY}" "TYP"
+!endif
+ DeleteRegValue HKLM "SOFTWARE\Garmin\MapSource\Families\${REG_KEY}\${PRODUCT_ID}" "BMAP"
+ DeleteRegValue HKLM "SOFTWARE\Garmin\MapSource\Families\${REG_KEY}\${PRODUCT_ID}" "LOC"
+ DeleteRegValue HKLM "SOFTWARE\Garmin\MapSource\Families\${REG_KEY}\${PRODUCT_ID}" "TDB"
+ DeleteRegKey /IfEmpty HKLM "SOFTWARE\Garmin\MapSource\Families\${REG_KEY}\${PRODUCT_ID}"
+ DeleteRegKey /IfEmpty HKLM "SOFTWARE\Garmin\MapSource\Families\${REG_KEY}"
+
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${REG_KEY}"
+
+SectionEnd
diff --git a/resources/installer/license_template.txt b/resources/installer/license_template.txt
new file mode 100644
index 0000000..3caa234
--- /dev/null
+++ b/resources/installer/license_template.txt
@@ -0,0 +1,7 @@
+Map data (c) OpenStreetMap and its contributors
+http://www.openstreetmap.org/copyright
+
+This map data is made available under the Open Database License:
+http://opendatacommons.org/licenses/odbl/1.0/.
+Any rights in individual contents of the database are licensed under the
+Database Contents License: http://opendatacommons.org/licenses/dbcl/1.0/
diff --git a/resources/logging.properties b/resources/logging.properties
new file mode 100644
index 0000000..92d1770
--- /dev/null
+++ b/resources/logging.properties
@@ -0,0 +1,11 @@
+
+.level=FINE
+
+handlers: java.util.logging.FileHandler
+
+java.util.logging.FileHandler.level=FINE
+java.util.logging.FileHandler.formatter=uk.me.parabola.log.UsefulFormatter
+java.util.logging.FileHandler.limit=5000000
+java.util.logging.FileHandler.count=4
+java.util.logging.FileHandler.pattern=mkgmap.log
+java.util.logging.FileHandler.append=true
diff --git a/resources/mkgmap-version.properties b/resources/mkgmap-version.properties
new file mode 100644
index 0000000..bc82089
--- /dev/null
+++ b/resources/mkgmap-version.properties
@@ -0,0 +1,2 @@
+svn.version: 2981
+build.timestamp: 2014-01-23T11:59:50+0000
diff --git a/resources/sort/cp1250.txt b/resources/sort/cp1250.txt
new file mode 100644
index 0000000..699502e
--- /dev/null
+++ b/resources/sort/cp1250.txt
@@ -0,0 +1,88 @@
+codepage 1250
+id1 12
+id2 1
+description "Central European sort"
+
+code pos2=0 01, 02, 03, 04, 05, 06, 07
+
+code pos=1 20 < a0 < 09 < 0a < 0b < 0c < 0d < ! < " < 23 < $ < %
+code & < ( < ) < * < , < . < / < : < ; < ? < @ < [
+code \ < ] < ^ < _ < ` < { < | < } < ~ < a6 < a8 < '
+code b8 < a1 < a2
+
+code ff
+code b2
+code bd
+code 91
+code 92
+code 82
+code 93
+code 94
+code 84
+code 8B
+code 9B
+code a4
+code 80
+code +
+code 3c
+code =
+code >
+code b1
+code ab
+code bb
+code d7
+code f7
+code a7
+code a9
+code ac
+code ae
+code b0
+code b5
+code b6
+code b7
+code 86
+code 87
+code 95
+code 89
+
+code 0
+code 1
+code 2
+code 3
+code 4
+code 5
+code 6
+code 7
+code 8
+code 9
+
+code a,A; ä,Ã; á,Ã; â,Ã; Ä,Ä; Ä
,Ä
+code b,B
+code c,C; Ä,Ä; Ä,Ä; ç,Ã
+code d,D; Ä,Ä; Ä,Ä
+code e,E; ë,Ã; é,Ã; Ä,Ä; Ä,Ä
+code f,F
+code g,G
+code h,H
+code i,I; Ã,Ã; î,Ã
+code j,J
+code k,K
+code l,L; ĺ,Ĺ; ľ,Ľ; Å,Å
+code m,M
+code n,N; Å,Å; Å,Å
+code o,O; ö,Ã; ó,Ã; ô,Ã; Å,Å
+code p,P
+code q,Q
+code r,R; Å,Å
+code s,S; Å,Å; Å¡,Å ; Å,Å
+code t,T; ť,Ť; ţ,Ţ
+code 99
+code u,U; ü,Ã; ú,Ã; ů,Å®; ű,Å°
+code v,V
+code w,W
+code x,X
+code y,Y; ý,Ã
+code z,Z; ż,Ż; ź,Ź; ž,Ž
+
+expand à to s s
+expand 85 to . . .
diff --git a/resources/sort/cp1251.txt b/resources/sort/cp1251.txt
new file mode 100644
index 0000000..2c2a391
--- /dev/null
+++ b/resources/sort/cp1251.txt
@@ -0,0 +1,160 @@
+codepage 1251
+id1 8
+id2 1
+description "Cyrillic Sort"
+code 01
+code 02
+code 03
+code 04
+code 05
+code 06
+code 07
+code 08
+code 09, 0a, 0b, 0c, 0d, 20, a0
+code 0e
+code 0f
+code 10
+code 11
+code 12
+code 13
+code 14
+code 15
+code 16
+code 17
+code 18
+code 19
+code 1a
+code 1b
+code 1c
+code 1d
+code 1e
+code 1f
+code !
+code "
+code â
+code â
+code «
+code »
+code â
+code '
+code â
+code â
+code â
+code 2c
+code 3b
+code :
+code .
+code â¦
+code $
+code ¤
+code â¬
+code %
+code â°
+code &
+code 23
+code (
+code )
+code â¹, 3c
+code âº, 3e
+code [
+code ]
+code {
+code }
+code *
+code +
+code -, â, â
+code ±
+code =
+code ad
+code /
+code \
+code ?
+code @
+code ^
+code ~
+code ¬
+code _
+code `
+code |
+code 7f
+code â
+code â¡
+# code 98
+code ¦
+code §
+code â¢
+code ©
+code ®
+code °
+code ¶
+code â¢
+code ·
+code â
+code 0
+code 1
+code 2
+code 3
+code 4
+code 5
+code 6
+code 7
+code 8
+code 9
+code a, A
+code b, B
+code c, C
+code d, D
+code e, E
+code f, F
+code g, G
+code h, H
+code i, I; Ñ, Ð; Ñ, Ð
+code j, J; Ñ, Ð
+code k, K
+code l, L
+code m, M
+code n, N
+code o, O
+code p, P
+code q, Q
+code r, R
+code s, S; Ñ, Ð
+code t, T
+code u, U
+code v, V
+code w, W
+code x, X
+code y, Y
+code z, Z
+code а, Ð
+code б, Ð
+code в, Ð
+code г, Ð; Ò, Ò; Ñ, Ð; Ñ, Ð
+code д, Ð; Ñ, Ð
+code е, Ð; Ñ, Ð; Ñ, Ð
+code ж, Ð
+code з, Ð
+code и, Ð
+code й, Ð
+code к, Ð; Ñ, Ð
+code л, Ð; Ñ, Ð
+code м, Ð; µ
+code н, Ð; Ñ, Ð
+code о, Ð
+code п, Ð
+code Ñ, Ð
+code Ñ, С
+code Ñ, Т
+code Ñ, У; Ñ, Ð
+code Ñ, Ф
+code Ñ
, Х
+code Ñ, Ц
+code Ñ, Ч; Ñ, Ð
+code Ñ, Ш
+code Ñ, Щ
+code Ñ, Ъ
+code Ñ, Ы
+code Ñ, Ь
+code Ñ, Ð
+code Ñ, Ю
+code Ñ, Я
diff --git a/resources/sort/cp1252.txt b/resources/sort/cp1252.txt
new file mode 100644
index 0000000..ac08df1
--- /dev/null
+++ b/resources/sort/cp1252.txt
@@ -0,0 +1,154 @@
+#
+# An ordering of characters for a given code page.
+# Characters are represented either as themselves (in unicode) or
+# as two hex digits in the target codepage.
+# Characters later, reading left to right from top to bottom, sort
+# after those that are earlier in the file.
+#
+# There are three ordering strengths represented in this file.
+#
+# These are Primary (different letters), secondary (different
+# accents), tertiary (different case).
+# See the java documentation for the Collator class for some more
+# discussion of the strength concept and examples.
+#
+# Note that primary differences always determine the order even if
+# they are later in the word than secondary differences.
+# ie A B comes after A-acute A, even though A-acute sorts after A.
+#
+# In this file Primary differences are represented by lines begining
+# with the keyword 'code'. All the letters following are the same
+# letter ignoring case and accents.
+# Characters with secondary differences are separated by semicolons
+# and characters with tertiary differences are separated by commas.
+#
+# You can also separate different letters with '<' instead of starting a new
+# 'code' line.
+#
+# You can split lines after a semi-colon or comma, but otherwise a new
+# line ends the 'code' command.
+
+
+# This must be first before any 'code' lines.
+codepage 1252
+id1 7
+id2 2
+description "Western European Sort"
+
+code pos2=0 pos3=8 01, 02, 03, 04, 05, 06, 07
+code flags=w ¼
+code 20,a0,1e,1f; _ ;b4;`;^;a8;98;b8;af
+code pos2=1 ad
+code -
+code 96
+code 97
+code 2c
+code 3b
+code :
+code !
+code ¡
+code ?
+code ¿
+code .
+code ·
+code '
+code 91
+code 92
+code 82
+code 8b
+code 9b
+code "
+code 93
+code 94
+code 84
+code «
+code »
+code (
+code )
+code [
+code ]
+code {
+code }
+code §
+code ¶
+code ©
+code ®
+code @
+code *
+code /
+code \
+code &
+code 23
+code %
+code 89
+code 86
+code 87
+code 95
+code ¤
+code ¢
+code $
+code £
+code ¥
+code °
+code +
+code ±
+code ÷
+code 88
+code 3c
+code =
+code >
+code ¬
+code |
+code ¦
+code ~
+code 0
+code 1,¹
+code 2,²
+code 3,³
+code 4
+code 5
+code 6
+code 7
+code 8
+code 9
+code a,A,,ª; á,Ã; à ,Ã; â,Ã; Ã¥,Ã
; ä,Ã; ã,Ã
+code b,B
+code c,C; ç,Ã
+code d,D;;ð,Ã
+code e,E; é,Ã; è,Ã;ê,Ã;ë,Ã
+code f,F
+code 83
+code g,G
+code h,H
+code i,I;Ã,Ã;ì,Ã;î,Ã;ï,Ã
+code j,J
+code k,K
+code l,L
+code m,M
+code n,N;ñ,Ã
+code o,O,,º;;ó,Ã;ò,Ã;ô,Ã;ö,Ã;õ,Ã;;ø,Ã
+code p,P
+code q,Q
+code r,R
+code s,S;;; 9a,8a
+code t,T,,99
+code u,U;ú,Ã;ù,Ã;û,Ã;ü,Ã
+code v,V
+code w,W
+code x,X
+code y,Y;ý,Ã;ÿ,9f
+code z,Z
+code þ,Ã
+code flags=0 µ
+
+expand æ to a e
+expand à to A E
+
+expand à to s s
+expand 85 to . . .
+expand 9c to o e
+expand 8c to O E
+expand ½ to 1 / 2
+expand ¼ to 1 / 4
+expand ¾ to 3 / 4
+
diff --git a/resources/sort/cp1256.txt b/resources/sort/cp1256.txt
new file mode 100644
index 0000000..b80f704
--- /dev/null
+++ b/resources/sort/cp1256.txt
@@ -0,0 +1,115 @@
+
+codepage 1256
+id1 9
+id2 1
+description "Arabic"
+
+code pos2=0 pos3=8 01, 02, 03, 04, 05, 06, 07
+
+
+code 85
+code 20 < a0 < 09 < 0a < 0b < 0c < 0d
+code !
+code "
+code 23
+code $
+code %
+code &
+code (
+code )
+code *
+code ,
+code .
+code /
+code :
+code ;
+code ?
+code @
+code [
+code \
+code ]
+code ^ 88
+code `
+code {
+code |
+code }
+code ~
+code a6
+code a8
+code af
+code b4
+code b8
+code a1
+code ba
+code bf
+code 91
+code 92
+code 82
+code 93
+code 94
+code 84
+code 8b
+code 9b
+code _
+code <
+code =
+code >
+code ±
+code ab
+code bb
+code d7
+code f7
+code a2
+code a3
+code a4
+code a5
+code a7
+code a9 < ac < ae < b0 < b5 < b6 < b7 < 86 < 87 < 95 < 85 < 89
+code 80
+code 0 < bc < bd < be
+code 1,¹
+code 2,²
+code 3,³
+code 4
+code 5
+code 6
+code 7
+code 8
+code 9
+code a,A; e0; e2
+code b,B
+code c,C; e7
+code d,D
+code e,E; e9; e8; ea; eb
+code f,F; 83
+code g,G
+code h,H
+code i,I; ee; ef
+code j,J
+code k,K
+code l,L
+code m,M
+code n,N
+code o,O; f4
+code 9c,8c
+code p,P
+code q,Q
+code r,R
+code s,S
+code t,T
+code 99
+code u,U; f9; fb; fc
+code v,V
+code w,W
+code x,X
+code y,Y
+code z,Z
+code c1; c4; c6
+code c7; c2; c3; c5
+code c8 < 81
+code c9, ca
+code cb < cc < 8d < cd < ce < cf < d0 < d1 < d2 < 8e < d3 < d4
+code d5 < d6 < d8 < d9 < da < db < dd < de < df < 90 < e1 < e3
+code e4 < e5 < e6
+code ec; ed
+code 8a < 8f < 9a < 98 < 9f < aa < c0 < ff < f8
diff --git a/resources/styles/builtin-tag-list b/resources/styles/builtin-tag-list
new file mode 100644
index 0000000..bc71af9
--- /dev/null
+++ b/resources/styles/builtin-tag-list
@@ -0,0 +1,16 @@
+#
+# There are a large number of tags names that
+# have become hardwired into mkgmap. This is list
+# of these tags.
+#
+# It only includes tags that are expected in the input file
+# and not tags that might be added in a style file that are
+# later recognised by mkgmap. In general these begin with the
+# string 'mkgmap:'
+#
+exit:facility
+exit:road_ref
+exit:to
+junction
+name
+oneway
diff --git a/resources/styles/contours_ft/info b/resources/styles/contours_ft/info
new file mode 100644
index 0000000..3e8bfe3
--- /dev/null
+++ b/resources/styles/contours_ft/info
@@ -0,0 +1,8 @@
+summary: Elevation contour lines in feet
+
+version=1.0
+
+# A longer description of the style.
+description {
+Contour lines, with elevation above sea level represented in feet.
+}
diff --git a/resources/styles/contours_ft/lines b/resources/styles/contours_ft/lines
new file mode 100644
index 0000000..6c09fad
--- /dev/null
+++ b/resources/styles/contours_ft/lines
@@ -0,0 +1,13 @@
+# Contours take their name from the elevation setting.
+contour=elevation & contour_ext=elevation_minor
+ { name '${ele|conv:m=>ft}'; }
+ [0x20 resolution 23]
+contour=elevation & contour_ext=elevation_medium
+ { name '${ele|conv:m=>ft}'; }
+ [0x21 resolution 21]
+contour=elevation & contour_ext=elevation_major
+ { name '${ele|conv:m=>ft}'; }
+ [0x22 resolution 20]
+contour=elevation | contour_ext=elevation
+ { name '${ele|conv:m=>ft}'; }
+ [0x21 resolution 20]
diff --git a/resources/styles/contours_ft/version b/resources/styles/contours_ft/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/resources/styles/contours_ft/version
@@ -0,0 +1 @@
+0
diff --git a/resources/styles/control/info b/resources/styles/control/info
new file mode 100644
index 0000000..91ff02b
--- /dev/null
+++ b/resources/styles/control/info
@@ -0,0 +1,19 @@
+#
+# This file contains information about the style.
+# It is completely optional.
+#
+
+
+# A short one line description of the style
+#
+summary: A style for traffic control features
+
+# Version of the style itself
+#
+version=0.1
+
+description {
+A style for traffic control features. This aims to be useful for
+highlighting features such as speed bumps, zebra crossings,
+traffic signals, speed limits and oneway streets on a separate map layer.
+}
diff --git a/resources/styles/control/points b/resources/styles/control/points
new file mode 100644
index 0000000..8b36d3c
--- /dev/null
+++ b/resources/styles/control/points
@@ -0,0 +1 @@
+traffic_calming=* [0x6614 resolution 21]
diff --git a/resources/styles/control/version b/resources/styles/control/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/resources/styles/control/version
@@ -0,0 +1 @@
+0
diff --git a/resources/styles/default/inc/access b/resources/styles/default/inc/access
new file mode 100644
index 0000000..277df4a
--- /dev/null
+++ b/resources/styles/default/inc/access
@@ -0,0 +1,72 @@
+# Define the access restrictions
+# The following tags define the restrictions:
+# mkgmap:bicycle
+# mkgmap:foot
+# mkgmap:car
+# mkgmap:truck
+# mkgmap:taxi
+# mkgmap:bus
+# mkgmap:emergency
+# mkgmap:delivery
+# A class is not allowed to use the way if its tag is set to 'no'
+
+highway=steps { add foot=yes; add access=no }
+highway=* & motorroad=yes { add bicycle=no; add foot=no }
+highway=motorway|highway=motorway_link { add bicycle=no; add foot=no }
+highway=pedestrian & area!=yes { add foot=yes; add access=no }
+highway=path { add foot=yes; add bicycle=yes; add access=no }
+highway=bridleway { add access=no }
+highway=cycleway { add bicycle=yes; add access=no }
+highway=footway { add foot=yes; add access=no }
+railway=platform { add foot=yes; add access=no }
+
+
+motorcar=destination { set mkgmap:throughroute=no; set motorcar=yes }
+motorcycle=destination { set mkgmap:throughroute=no; set motorcycle=yes }
+access=destination { set mkgmap:throughroute=no; set access=yes }
+bicycle=destination { set bicycle=yes }
+foot=destination { set foot=yes }
+hgv=destination { delete hgv }
+psv=destination { delete psv }
+taxi=destination { delete taxi }
+emergency=destination { delete emergency }
+delivery=destination { delete delivery }
+goods=destination { delete goods }
+
+bicycle=private | bicycle=agricultural { set bicycle=no }
+foot=private | foot=agricultural { set foot=no }
+hgv=private | hgv=agricultural { set hgv=no }
+motorcar=private | motorcar=agricultural { set motorcar=no }
+psv=private | psv=agricultural { set psv=no }
+taxi=private | taxi=agricultural { set taxi=no }
+emergency=private | emergency=agricultural { set emergency=no }
+delivery=private | delivery=agricultural { set delivery=no }
+goods=private | goods=agricultural { set goods=no }
+motorcycle=private | motorcycle=agricultural { set motorcycle=no }
+motor_vehicle=private | motor_vehicle=agricultural { set motor_vehicle=no }
+vehicle=private | vehicle=agricultural { set vehicle=no }
+access=private { set access=no }
+access=agricultural { set access=no; add foot=yes }
+
+# set (override) specific restrictions
+bicycle=* { set mkgmap:bicycle='${bicycle}' }
+foot=* { set mkgmap:foot='${foot}' }
+hgv=* { set mkgmap:truck='${hgv}' }
+motorcar=* { set mkgmap:car='${motorcar}' }
+psv=* { set mkgmap:bus='${psv}' }
+taxi=* { set mkgmap:taxi='${taxi}' }
+emergency=* { set mkgmap:emergency='${emergency}' }
+delivery=* { set mkgmap:delivery='${delivery}' }
+goods=* { set mkgmap:delivery='${goods}' }
+
+# Translate motor_vehicle and vehicle access rules.
+motorcycle=* { add mkgmap:car='${motorcycle}' }
+motor_vehicle=* { add mkgmap:car='${motor_vehicle}' }
+vehicle=* { add mkgmap:car='${vehicle}'; add mkgmap:bicycle='${vehicle}' }
+
+# the access tag defines all restrictions
+access=* { addaccess '${access}' }
+
+
+# check for carpool lane
+(carpool=yes | carpool=designated | carpool=permissive | carpool=official) { set mkgmap:carpool=yes }
diff --git a/resources/styles/default/inc/address b/resources/styles/default/inc/address
new file mode 100644
index 0000000..f1bb3a0
--- /dev/null
+++ b/resources/styles/default/inc/address
@@ -0,0 +1,93 @@
+#
+# This file contains all the rules to set up address information from
+# the tags that are added by the boundary processing.
+
+
+# first set the country code
+mkgmap:country!=* & mkgmap:admin_level2=* { set mkgmap:country='${mkgmap:admin_level2}' }
+mkgmap:country!=* & addr:country=* { set mkgmap:country='${addr:country}' }
+mkgmap:country!=* & is_in:country=* { set mkgmap:country='${is_in:country}' }
+
+# country specific rules first
+
+# Netherlands = NLD
+mkgmap:country=NLD & mkgmap:region!=* & mkgmap:admin_level4=* { set mkgmap:region='${mkgmap:admin_level4}' }
+mkgmap:country=NLD & mkgmap:city!=* & mkgmap:admin_level10=* { set mkgmap:city='${mkgmap:admin_level10}' }
+mkgmap:country=NLD & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+
+# Germany = DEU cities
+mkgmap:country=DEU & mkgmap:city!=* & mkgmap:admin_level4=Hamburg {set mkgmap:city='${mkgmap:admin_level4}' }
+mkgmap:country=DEU & mkgmap:city!=* & mkgmap:admin_level4=Berlin {set mkgmap:city='${mkgmap:admin_level4}' }
+mkgmap:country=DEU & mkgmap:region!=* & mkgmap:admin_level4=* { set mkgmap:region='${mkgmap:admin_level4}' }
+mkgmap:country=DEU & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8|subst:Gemeinde |subst:Stadt}' }
+mkgmap:country=DEU & mkgmap:city!=* & mkgmap:admin_level7=* { set mkgmap:city='${mkgmap:admin_level7|subst:Gemeinde |subst:Stadt}' }
+mkgmap:country=DEU & mkgmap:city!=* & mkgmap:admin_level6=* { set mkgmap:city='${mkgmap:admin_level6|subst:Gemeinde |subst:Stadt}' }
+mkgmap:country=DEU & mkgmap:city!=* & mkgmap:admin_level9=* { set mkgmap:city='${mkgmap:admin_level9|subst:Gemeinde |subst:Stadt}' }
+mkgmap:country=DEU & mkgmap:city!=* & mkgmap:admin_level10=* { set mkgmap:city='${mkgmap:admin_level10|subst:Gemeinde |subst:Stadt}' }
+
+
+# Austria = AUT
+mkgmap:country=AUT & mkgmap:city!=* & mkgmap:admin_level10=* { set mkgmap:city='${mkgmap:admin_level10|subst:Gemeinde |subst:Stadt }' }
+mkgmap:country=AUT & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8|subst:Gemeinde |subst:Stadt }' }
+
+# other european countries
+mkgmap:country=BEL & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+mkgmap:country=CZE & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+mkgmap:country=CZE & mkgmap:city!=* & mkgmap:admin_level7=* { set mkgmap:city='${mkgmap:admin_level7}' }
+mkgmap:country=DNK & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+mkgmap:country=DNK & mkgmap:city!=* & mkgmap:admin_level7=* { set mkgmap:city='${mkgmap:admin_level7}' }
+mkgmap:country=FIN & mkgmap:city!=* & mkgmap:admin_level9=* { set mkgmap:city='${mkgmap:admin_level9}' }
+mkgmap:country=FIN & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+mkgmap:country=FRA & mkgmap:city!=* & mkgmap:admin_level9=* { set mkgmap:city='${mkgmap:admin_level9}' }
+mkgmap:country=FRA & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+mkgmap:country=ISL & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+mkgmap:country=ITA & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+mkgmap:country=LUX & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+mkgmap:country=NOR & mkgmap:city!=* & mkgmap:admin_level9=* { set mkgmap:city='${mkgmap:admin_level9}' }
+mkgmap:country=POL & mkgmap:city!=* & mkgmap:admin_level10=* { set mkgmap:city='${mkgmap:admin_level10}' }
+mkgmap:country=POL & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+mkgmap:country=PRT & mkgmap:city!=* & mkgmap:admin_level9=* { set mkgmap:city='${mkgmap:admin_level9}' }
+mkgmap:country=PRT & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+mkgmap:country=SVN & mkgmap:city!=* & mkgmap:admin_level10=* { set mkgmap:city='${mkgmap:admin_level10}' }
+mkgmap:country=ESP & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+mkgmap:country=SWE & mkgmap:city!=* & mkgmap:admin_level9=* { set mkgmap:city='${mkgmap:admin_level9}' }
+mkgmap:country=SWE & mkgmap:city!=* & mkgmap:admin_level7=* { set mkgmap:city='${mkgmap:admin_level7}' }
+mkgmap:country=CHE & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+
+# Canada
+mkgmap:country=CAN & mkgmap:region!=* & mkgmap:admin_level4=* { set mkgmap:region='${mkgmap:admin_level4}' }
+mkgmap:country=CAN & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+
+# Ecuador = ECU
+mkgmap:country=ECU & mkgmap:region!=* & mkgmap:admin_level4=* { set mkgmap:region='${mkgmap:admin_level4}' }
+mkgmap:country=ECU & mkgmap:city!=* & mkgmap:admin_level6=* { set mkgmap:city='${mkgmap:admin_level6}' }
+mkgmap:country=ECU & mkgmap:city!=* & mkgmap:admin_level7=* { set mkgmap:city='${mkgmap:admin_level7}' }
+mkgmap:country=ECU & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+
+# common rules for all the rest of countries
+mkgmap:region!=* & mkgmap:admin_level6=* { set mkgmap:region='${mkgmap:admin_level6}' }
+mkgmap:region!=* & mkgmap:admin_level5=* { set mkgmap:region='${mkgmap:admin_level5}' }
+mkgmap:region!=* & mkgmap:admin_level4=* { set mkgmap:region='${mkgmap:admin_level4}' }
+mkgmap:region!=* & mkgmap:admin_level3=* { set mkgmap:region='${mkgmap:admin_level3}' }
+mkgmap:region!=* & is_in:county=* { set mkgmap:region='${is_in:county}' }
+
+mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+mkgmap:city!=* & mkgmap:admin_level7=* { set mkgmap:city='${mkgmap:admin_level7}' }
+mkgmap:city!=* & mkgmap:admin_level9=* { set mkgmap:city='${mkgmap:admin_level9}' }
+mkgmap:city!=* & mkgmap:admin_level10=* { set mkgmap:city='${mkgmap:admin_level10}' }
+mkgmap:city!=* & is_in:city=* { set mkgmap:city='${is_in:city}' }
+mkgmap:city!=* & addr:city=* { set mkgmap:city='${addr:city}' }
+
+mkgmap:postal_code!=* & mkgmap:postcode=* { set mkgmap:postal_code='${mkgmap:postcode}' }
+mkgmap:postal_code!=* & addr:postcode=* { set mkgmap:postal_code='${addr:postcode}' }
+
+mkgmap:street!=* & addr:street=* { set mkgmap:street='${addr:street}' }
+mkgmap:street!=* & addr:housename=* { set mkgmap:street='${addr:housename}' }
+
+mkgmap:housenumber!=* & addr:housenumber=* { set mkgmap:housenumber='${addr:housenumber}' }
+
+mkgmap:phone!=* & phone=* { set mkgmap:phone='${phone}' }
+mkgmap:phone!=* & contact:phone=* { add mkgmap:phone='${contact:phone}' }
+
+mkgmap:is_in!=* & is_in=* { set mkgmap:is_in='${is_in}' }
+
diff --git a/resources/styles/default/inc/compat_lines b/resources/styles/default/inc/compat_lines
new file mode 100644
index 0000000..f514b22
--- /dev/null
+++ b/resources/styles/default/inc/compat_lines
@@ -0,0 +1,125 @@
+include 'inc/roadspeed';
+
+name=* { name '${name}' }
+mkgmap:default_name=* { name '${mkgmap:default_name}' }
+mkgmap:display_name=* { addlabel '${mkgmap:display_name|subst:;=>/}' }
+
+mkgmap:label:1!=* & ref=* { addlabel '${ref|part:;:1}' }
+mkgmap:label:1!=* & int_ref=* { addlabel '${int_ref|part:;:1}' }
+mkgmap:label:1!=* & nat_ref=* { addlabel '${nat_ref|part:;:1}' }
+mkgmap:label:1!=* & reg_ref=* { addlabel '${reg_ref|part:;:1}' }
+
+ref=* { addlabel '${ref|part:;:1}'; addlabel '${ref|part:;:2}'; addlabel '${ref|part:;:3}' }
+int_ref=* { addlabel '${int_ref|part:;:1}'; addlabel '${int_ref|part:;:2}'; addlabel '${int_ref|part:;:3}' }
+nat_ref=* { addlabel '${nat_ref|part:;:1}'; addlabel '${nat_ref|part:;:2}'; addlabel '${nat_ref|part:;:3}' }
+reg_ref=* { addlabel '${reg_ref|part:;:1}'; addlabel '${reg_ref|part:;:2}'; addlabel '${reg_ref|part:;:3}' }
+
+highway=* & mkgmap:label:1=* & mkgmap:street!=* { add mkgmap:street='${mkgmap:label:1}' }
+
+toll=* { set mkgmap:toll='${toll}' }
+
+# new AccessMapping("access", RoadNetwork.NO_MAX), // must be first in list
+# new AccessMapping("bicycle", RoadNetwork.NO_BIKE),
+# new AccessMapping("carpool", RoadNetwork.NO_CARPOOL),
+# new AccessMapping("foot", RoadNetwork.NO_FOOT),
+# new AccessMapping("hgv", RoadNetwork.NO_TRUCK),
+# new AccessMapping("motorcar", RoadNetwork.NO_CAR),
+# new AccessMapping("motorcycle", RoadNetwork.NO_CAR),
+# new AccessMapping("psv", RoadNetwork.NO_BUS),
+# new AccessMapping("taxi", RoadNetwork.NO_TAXI),
+# new AccessMapping("emergency", RoadNetwork.NO_EMERGENCY),
+# new AccessMapping("delivery", RoadNetwork.NO_DELIVERY),
+# new AccessMapping("goods", RoadNetwork.NO_DELIVERY),
+# for (AccessMapping anAccessMap : accessMap) {
+# int index = anAccessMap.index;
+# String type = anAccessMap.type;
+# String accessTagValue = way.getTag(type);
+# if (accessTagValue == null)
+# continue;
+# if (accessExplicitlyDenied(accessTagValue)) {
+# if (index == RoadNetwork.NO_MAX) {
+# // everything is denied access
+# for (int j = 1; j < accessMap.length; ++j)
+# noAccess[accessMap[j].index] = true;
+# } else {
+# // just the specific vehicle class is denied
+# // access
+# noAccess[index] = true;
+# }
+# log.debug(type + " is not allowed in " + highwayType + " " + debugWayName);
+# } else if (accessExplicitlyAllowed(accessTagValue)) {
+# if (index == RoadNetwork.NO_MAX) {
+# // everything is allowed access
+# for (int j = 1; j < accessMap.length; ++j)
+# noAccess[accessMap[j].index] = false;
+# } else {
+# // just the specific vehicle class is allowed
+# // access
+# noAccess[index] = false;
+# }
+# log.debug(type + " is allowed in " + highwayType + " " + debugWayName);
+# }
+# else if (accessTagValue.equalsIgnoreCase("destination")) {
+# if (type.equals("motorcar") ||
+# type.equals("motorcycle")) {
+# road.setNoThroughRouting();
+# } else if (type.equals("access")) {
+# log.info("access=destination only affects routing for cars in " + highwayType + " " + debugWayName);
+# road.setNoThroughRouting();
+# } else {
+# log.info(type + "=destination ignored in " + highwayType + " " + debugWayName);
+# }
+# } else if (accessTagValue.equalsIgnoreCase("unknown")) {
+# // implicitly allow access
+# } else {
+# log.info("Ignoring unsupported access tag value " + type + "=" + accessTagValue + " in " + highwayType + " " + debugWayName);
+# }
+# }
+#
+
+# mkgmap:carpool tag is set but before new access handling was introduced it had a
+# different meaning. Copy it to keep its value which is handled in the old behaviour last.
+mkgmap:carpool=* { set mkgmap:carpool_compat='${mkgmap:carpool}'; delete mkgmap:carpool }
+
+access=private | access=no { setaccess no; set mkgmap:carpool=yes; }
+access=yes | access=permissive | access=official | access=designated { setaccess yes; set mkgmap:carpool=no; }
+access=destination { set mkgmap:throughroute=no }
+
+bicycle=private | bicycle=no { set mkgmap:bicycle=no; }
+bicycle=yes | bicycle=permissive | bicycle=official | bicycle=designated { set mkgmap:bicycle=yes; }
+
+carpool=private | carpool=no { set mkgmap:carpool=no; }
+carpool=yes | carpool=permissive | carpool=official | carpool=designated { set mkgmap:carpool=yes; }
+
+foot=private | foot=no { set mkgmap:foot=no; }
+foot=yes | foot=permissive | foot=official | foot=designated { set mkgmap:foot=yes; }
+
+hgv=private | hgv=no { set mkgmap:truck=no; }
+hgv=yes | hgv=permissive | hgv=official | hgv=designated { set mkgmap:truck=yes; }
+
+motorcar=private | motorcar=no { set mkgmap:car=no; }
+motorcar=yes | motorcar=permissive | motorcar=official | motorcar=designated { set mkgmap:car=yes; }
+motorcar=destination { set mkgmap:throughroute=no }
+
+motorcycle=private | motorcycle=no { set mkgmap:car=no; }
+motorcycle=yes | motorcycle=permissive | motorcycle=official | motorcycle=designated { set mkgmap:car=yes; }
+motorcycle=destination { set mkgmap:throughroute=no }
+
+psv=private | psv=no { set mkgmap:bus=no; }
+psv=yes | psv=permissive | psv=official | psv=designated { set mkgmap:bus=yes; }
+
+taxi=private | taxi=no { set mkgmap:taxi=no; }
+taxi=yes | taxi=permissive | taxi=official | taxi=designated { set mkgmap:taxi=yes; }
+
+emergency=private | emergency=no { set mkgmap:emergency=no; }
+emergency=yes | emergency=permissive | emergency=official | emergency=designated { set mkgmap:emergency=yes; }
+
+delivery=private | delivery=no { set mkgmap:delivery=no; }
+delivery=yes | delivery=permissive | delivery=official | delivery=designated { set mkgmap:delivery=yes; }
+
+goods=private | goods=no { set mkgmap:delivery=no; }
+goods=yes | goods=permissive | goods=official | goods=designated { set mkgmap:delivery=yes; }
+
+# Reintroduce the old carpool handling which allows access only for bus and emergency plus setting the carpool bit
+mkgmap:carpool_compat=yes { setaccess=no; set mkgmap:bus=yes; set mkgmap:emergency=yes; set mkgmap:carpool=yes }
+
diff --git a/resources/styles/default/inc/compat_points b/resources/styles/default/inc/compat_points
new file mode 100644
index 0000000..e6d75fe
--- /dev/null
+++ b/resources/styles/default/inc/compat_points
@@ -0,0 +1,13 @@
+name=* { name '${name}' }
+mkgmap:default_name=* { name '${mkgmap:default_name}' }
+mkgmap:display_name=* { addlabel '${mkgmap:display_name|subst:;=>/}' }
+
+mkgmap:label:1!=* & ref=* { addlabel '${ref|part:;:1}' }
+mkgmap:label:1!=* & int_ref=* { addlabel '${int_ref|part:;:1}' }
+mkgmap:label:1!=* & nat_ref=* { addlabel '${nat_ref|part:;:1}' }
+mkgmap:label:1!=* & reg_ref=* { addlabel '${reg_ref|part:;:1}' }
+
+ref=* { addlabel '${ref|part:;:1}'; addlabel '${ref|part:;:2}'; addlabel '${ref|part:;:3}' }
+int_ref=* { addlabel '${int_ref|part:;:1}'; addlabel '${int_ref|part:;:2}'; addlabel '${int_ref|part:;:3}' }
+nat_ref=* { addlabel '${nat_ref|part:;:1}'; addlabel '${nat_ref|part:;:2}'; addlabel '${nat_ref|part:;:3}' }
+reg_ref=* { addlabel '${reg_ref|part:;:1}'; addlabel '${reg_ref|part:;:2}'; addlabel '${reg_ref|part:;:3}' }
diff --git a/resources/styles/default/inc/compat_polygons b/resources/styles/default/inc/compat_polygons
new file mode 100644
index 0000000..e6d75fe
--- /dev/null
+++ b/resources/styles/default/inc/compat_polygons
@@ -0,0 +1,13 @@
+name=* { name '${name}' }
+mkgmap:default_name=* { name '${mkgmap:default_name}' }
+mkgmap:display_name=* { addlabel '${mkgmap:display_name|subst:;=>/}' }
+
+mkgmap:label:1!=* & ref=* { addlabel '${ref|part:;:1}' }
+mkgmap:label:1!=* & int_ref=* { addlabel '${int_ref|part:;:1}' }
+mkgmap:label:1!=* & nat_ref=* { addlabel '${nat_ref|part:;:1}' }
+mkgmap:label:1!=* & reg_ref=* { addlabel '${reg_ref|part:;:1}' }
+
+ref=* { addlabel '${ref|part:;:1}'; addlabel '${ref|part:;:2}'; addlabel '${ref|part:;:3}' }
+int_ref=* { addlabel '${int_ref|part:;:1}'; addlabel '${int_ref|part:;:2}'; addlabel '${int_ref|part:;:3}' }
+nat_ref=* { addlabel '${nat_ref|part:;:1}'; addlabel '${nat_ref|part:;:2}'; addlabel '${nat_ref|part:;:3}' }
+reg_ref=* { addlabel '${reg_ref|part:;:1}'; addlabel '${reg_ref|part:;:2}'; addlabel '${reg_ref|part:;:3}' }
diff --git a/resources/styles/default/inc/contour_lines b/resources/styles/default/inc/contour_lines
new file mode 100644
index 0000000..6c09fad
--- /dev/null
+++ b/resources/styles/default/inc/contour_lines
@@ -0,0 +1,13 @@
+# Contours take their name from the elevation setting.
+contour=elevation & contour_ext=elevation_minor
+ { name '${ele|conv:m=>ft}'; }
+ [0x20 resolution 23]
+contour=elevation & contour_ext=elevation_medium
+ { name '${ele|conv:m=>ft}'; }
+ [0x21 resolution 21]
+contour=elevation & contour_ext=elevation_major
+ { name '${ele|conv:m=>ft}'; }
+ [0x22 resolution 20]
+contour=elevation | contour_ext=elevation
+ { name '${ele|conv:m=>ft}'; }
+ [0x21 resolution 20]
diff --git a/resources/styles/default/inc/landuse_points b/resources/styles/default/inc/landuse_points
new file mode 100644
index 0000000..380338a
--- /dev/null
+++ b/resources/styles/default/inc/landuse_points
@@ -0,0 +1,4 @@
+landuse=cemetery|landuse=cemetary|amenity=grave_yard [0x6403 resolution 24]
+landuse=military [0x640b resolution 24]
+landuse=village_green & name=* [0x2c06 resolution 24]
+(landuse=wood|landuse=forest|natural=wood) & name=* [0x6618 resolution 24]
diff --git a/resources/styles/default/inc/landuse_polygons b/resources/styles/default/inc/landuse_polygons
new file mode 100644
index 0000000..7e7e627
--- /dev/null
+++ b/resources/styles/default/inc/landuse_polygons
@@ -0,0 +1,26 @@
+landuse=allotments [0x4e resolution 21]
+landuse=cemetery|landuse=cemetary|amenity=grave_yard [0x1a resolution 21]
+landuse=commercial [0x0c resolution 19]
+landuse=construction [0x0c resolution 21]
+landuse=farm [0x4e resolution 20]
+landuse=farmyard [0x4e resolution 22]
+landuse=forest|landuse=wood [0x50 resolution 20]
+landuse=greenfield [0x17 resolution 20]
+landuse=meadow [0x17 resolution 19]
+landuse=military [0x04 resolution 19]
+landuse=quarry [0x0c resolution 19]
+landuse=recreation_ground [0x19 resolution 19]
+# dedicate resolution 24 for building=* instead of related landuse=*
+landuse=industrial [0x0c resolution 23-19]
+landuse=residential [0x10 resolution 23-19]
+landuse=retail [0x08 resolution 23-20]
+landuse=village_green [0x17 resolution 20]
+landuse=vineyard [0x4e resolution 20]
+
+military=airfield [0x04 resolution 20]
+military=barracks [0x04 resolution 23]
+military=danger_area [0x04 resolution 20]
+military=range [0x04 resolution 20]
+
+natural=scrub [0x4f resolution 20]
+natural=wood [0x50 resolution 20]
diff --git a/resources/styles/default/inc/name b/resources/styles/default/inc/name
new file mode 100644
index 0000000..91b5f09
--- /dev/null
+++ b/resources/styles/default/inc/name
@@ -0,0 +1,29 @@
+# Rules for naming objects, based on the following tags:
+# name, brand, operator, ref
+
+# None of operator, brand given
+ref=* & (operator!=* & brand!=*) { name '${ref} ${name}' | '${ref}' }
+
+# Both operator and brand given
+operator=* & brand=* {
+ name '${brand}: ${ref} ${name} (${operator})' |
+ '${brand} ${ref} (${operator})' |
+ '${brand}: ${name} (${operator})' |
+ '${brand} (${operator})'
+}
+
+# One of operator or brand given
+operator=* & brand!=* {
+ name '${operator}: ${ref} ${name}' |
+ '${operator}: ${name}' |
+ '${operator}: ${ref}' |
+ '${operator}' |
+ '${ref}'
+}
+brand=* & operator!=* {
+ name '${brand}: ${ref} ${name}' |
+ '${brand}: ${name}' |
+ '${brand}: ${ref}' |
+ '${brand}' |
+ '${ref}'
+}
diff --git a/resources/styles/default/inc/roadspeed b/resources/styles/default/inc/roadspeed
new file mode 100644
index 0000000..47eb94d
--- /dev/null
+++ b/resources/styles/default/inc/roadspeed
@@ -0,0 +1,26 @@
+#
+# Sets the road speed based on the maxspeed tag.
+# In case mkgmap:road-speed-class is set the element
+# road_speed is overriden.
+#
+# road_speed classification:
+# road_speed | highest speed
+# 7 | No speed limit
+# 6 | 70 mph / 110 km/h
+# 5 | 60 mph / 90 km/h
+# 4 | 50 mph / 80 km/h
+# 3 | 35 mph / 60 km/h
+# 2 | 25 mph / 40 km/h
+# 1 | 15 mph / 20 km/h
+# 0 | 3 mph / 5 km/h
+#
+
+maxspeed=* & mkgmap:road-speed-class!=* & maxspeedkmh() > 110 { set mkgmap:road-speed-class = 7 }
+maxspeed=* & mkgmap:road-speed-class!=* & maxspeedkmh() > 90 { set mkgmap:road-speed-class = 6 }
+maxspeed=* & mkgmap:road-speed-class!=* & maxspeedkmh() > 80 { set mkgmap:road-speed-class = 5 }
+maxspeed=* & mkgmap:road-speed-class!=* & maxspeedkmh() > 60 { set mkgmap:road-speed-class = 4 }
+maxspeed=* & mkgmap:road-speed-class!=* & maxspeedkmh() > 40 { set mkgmap:road-speed-class = 3 }
+maxspeed=* & mkgmap:road-speed-class!=* & maxspeedkmh() > 20 { set mkgmap:road-speed-class = 2 }
+# change class 1 to 10 km/h which is not correct but better handles living_streets with maxspeed=7
+maxspeed=* & mkgmap:road-speed-class!=* & maxspeedkmh() > 10 { set mkgmap:road-speed-class = 1 }
+maxspeed=* & mkgmap:road-speed-class!=* & maxspeedkmh()=* { set mkgmap:road-speed-class = 0 }
diff --git a/resources/styles/default/inc/water_lines b/resources/styles/default/inc/water_lines
new file mode 100644
index 0000000..908f028
--- /dev/null
+++ b/resources/styles/default/inc/water_lines
@@ -0,0 +1,9 @@
+natural=coastline [0x15 resolution 12]
+
+route=ferry {add mkgmap:ferry=1} [0x1b road_class=3 road_speed=0 resolution 19]
+
+waterway=canal [0x1f resolution 21]
+waterway=drain [0x1f resolution 22]
+waterway=river [0x1f resolution 18]
+waterway=rapids|waterway=waterfall [0x1f resolution 22]
+waterway=stream [0x18 resolution 22]
diff --git a/resources/styles/default/inc/water_points b/resources/styles/default/inc/water_points
new file mode 100644
index 0000000..b830a28
--- /dev/null
+++ b/resources/styles/default/inc/water_points
@@ -0,0 +1,9 @@
+landuse=basin|landuse=reservoir [0x650f resolution 24]
+
+natural=beach [0x6604 resolution 24]
+natural=glacier [0x650a resolution 24]
+natural=spring [0x6511 resolution 24]
+natural=stream [0x6512 resolution 24]
+natural=water & name=* [0x6603 resolution 24]
+natural=waterfall | waterway=waterfall [0x6508 resolution 24]
+natural=wetland & name=* [0x6513 resolution 24]
diff --git a/resources/styles/default/inc/water_polygons b/resources/styles/default/inc/water_polygons
new file mode 100644
index 0000000..5fb376a
--- /dev/null
+++ b/resources/styles/default/inc/water_polygons
@@ -0,0 +1,12 @@
+landuse=basin|landuse=reservoir [0x3f resolution 20]
+
+natural=bay [0x3d resolution 18]
+natural=glacier [0x4d resolution 18]
+natural=marsh [0x51 resolution 20]
+natural=mud [0x51 resolution 20]
+natural=wetland [0x51 resolution 20]
+natural=water [0x3c resolution 18]
+natural=waterfall | waterway=waterfall [0x47 resolution 21]
+natural=sea { add mkgmap:skipSizeFilter=true } [0x32 resolution 10]
+
+waterway=riverbank [0x46 resolution 20]
diff --git a/resources/styles/default/info b/resources/styles/default/info
new file mode 100644
index 0000000..3dbab5f
--- /dev/null
+++ b/resources/styles/default/info
@@ -0,0 +1,20 @@
+#
+# This file contains information about the style.
+# It is completely optional.
+#
+
+
+# A short one line description of the style
+#
+summary: The default style
+
+# Version of the style itself
+#
+version=1.0
+
+# A longer description of the style.
+description {
+The default style. This is a heavyweight style that is
+designed for use when mapping and especially in lightly covered
+areas.
+}
diff --git a/resources/styles/default/lines b/resources/styles/default/lines
new file mode 100644
index 0000000..bd2c239
--- /dev/null
+++ b/resources/styles/default/lines
@@ -0,0 +1,202 @@
+# -------------------------------------------------------------------
+# This is the default mkgmap style file for converting OSM ways
+# into Garmin lines.
+# Any line prefaced with # is a comment and will not be applied.
+# Each line is a rule, of the generalised format:
+# OSM_tag(s)_to_match [Garmin_type_code resolution]
+# See http://wiki.openstreetmap.org/wiki/Mkgmap/help/style_rules
+# and http://wiki.openstreetmap.org/wiki/Mkgmap/help/Custom_styles
+# for more information.
+
+aeroway=runway [0x27 resolution 20]
+aeroway=taxiway [0x27 resolution 24]
+
+# Assign the street name for house number search
+highway=* & name=* { set mkgmap:street='${name}' }
+
+# Mark highways with the toll flag
+highway=* & (toll=yes|toll=true) { set mkgmap:toll=yes }
+
+# Hide proposed ways
+highway=proposed {delete highway;delete junction}
+# Hide unaccessible tunnels
+highway=* & tunnel=yes & (access=private|access=no)
+& foot!=* & bicycle!=* {delete highway;delete junction}
+# Disable dead-end-checks for unaccessible oneways
+highway=* & oneway=yes & (access=private|access=no)
+{add mkgmap:dead-end-check=false}
+# Validation-like checks (uncomment to enable)
+#highway=motorway_link & oneway!=yes & oneway!=no { echo "motorway_link lacks oneway" }
+highway=motorway|highway=motorway_link { add oneway=yes }
+
+# Set highway names to include the reference if there is one
+highway=motorway { name '${ref|highway-symbol:hbox} ${name}' | '${ref|highway-symbol:hbox}' | '${name}' }
+
+(highway=motorway_link | highway=trunk_link) & mkgmap:exit_hint=true & mkgmap:dest_hint=true
+ { name '${destination:ref|subst: =>} ${destination|subst:;=> |subst:/=> }' |
+ '${ref|subst: =>} ${destination|subst:;=> |subst:/=> }' |
+ '${destination|subst:;=> |subst:/=> }' |
+ 'Exit ${mkgmap:exit_hint_ref} ${mkgmap:exit_hint_name}' |
+ 'Exit ${mkgmap:exit_hint_ref} ${mkgmap:exit_hint_exit_to}' |
+ 'Exit ${mkgmap:exit_hint_exit_to}' |
+ 'Exit ${mkgmap:exit_hint_name}' |
+ 'Exit ${mkgmap:exit_hint_ref}'
+ }
+
+(highway=motorway_link | highway=trunk_link) & mkgmap:exit_hint!=* & mkgmap:dest_hint=true
+ { name '${destination:ref|subst: =>} ${destination|subst:;=> |subst:/=> }' |
+ '${ref|subst: =>} ${destination|subst:;=> |subst:/=> }' |
+ '${destination|subst:;=> |subst:/=> }'
+ }
+
+(highway=motorway_link | highway=trunk_link) & mkgmap:exit_hint=true & mkgmap:dest_hint!=*
+ { name 'Exit ${mkgmap:exit_hint_ref} ${mkgmap:exit_hint_name}' |
+ 'Exit ${mkgmap:exit_hint_ref} ${mkgmap:exit_hint_exit_to}' |
+ 'Exit ${mkgmap:exit_hint_exit_to}' |
+ 'Exit ${mkgmap:exit_hint_name}' |
+ 'Exit ${mkgmap:exit_hint_ref}'
+ }
+
+highway=trunk {name '${ref|highway-symbol:hbox} ${name}' | '${ref|highway-symbol:hbox}' | '${name}'; addlabel '${name} (${ref})' }
+highway=primary {name '${ref|highway-symbol:box} ${name}' | '${ref|highway-symbol:box}' | '${name}'; addlabel '${name} (${ref})' }
+highway=secondary | highway=tertiary {name '${ref|highway-symbol:oval} ${name}' | '${ref|highway-symbol:oval}' | '${name}'; addlabel '${name} (${ref})' }
+highway=* {name '${name}' | '${ref}' }
+
+# Flag unpaved roads.
+highway=*
+& (surface=cobblestone | surface=compacted | surface=dirt |
+ surface=earth | surface=grass | surface=grass_paver |
+ surface=gravel | surface=grit | surface=ground | surface=mud |
+ surface=pebblestone | surface=sand | surface=unpaved |
+ mtb:scale=* |
+ tracktype ~ 'grade[2-6]' |
+ smoothness ~ '.*(bad|horrible|impassable)' |
+ sac_scale ~ '.*(mountain|alpine)_hiking' |
+ sport=via_ferrata)
+{ add mkgmap:unpaved=1 }
+(highway=bridleway | highway=path | highway=track | highway=unsurfaced)
+& surface!=* & tracktype!=* & smoothness!=* & sac_scale!=*
+{ add mkgmap:unpaved=1 }
+
+# Convert generic path to most specific
+highway=footway & snowplowing!=no
+& (bicycle=yes|bicycle=designated|bicycle=permissive|bicycle=official)
+{set highway=cycleway; set bicycle=yes}
+highway=path & snowplowing!=no
+& (bicycle=designated|bicycle=permissive|bicycle=official)
+{set highway=cycleway; set bicycle=yes}
+highway=path & (horse=designated|horse=permissive|horse=official)
+{set highway=bridleway; set horse=yes}
+highway=path
+{set highway=footway}
+
+leisure=track & area!=yes
+{add highway=footway; name '${name} (${sport})' | '${name}'}
+(man_made=pier | man_made=piste:halfpipe) & area!=yes
+{add highway=footway; name '${ref} ${name}' | '${ref}' | '${name}' }
+
+# Roundabouts
+junction=roundabout & highway=trunk [0x0c road_class=3 road_speed=2 resolution 18]
+junction=roundabout & highway=primary [0x0c road_class=3 road_speed=2 resolution 19]
+junction=roundabout & highway=secondary [0x0c road_class=2 road_speed=2 resolution 20]
+junction=roundabout & highway=tertiary [0x0c road_class=1 road_speed=1 resolution 21]
+junction=roundabout & highway=unclassified [0x0c road_class=1 road_speed=1 resolution 21]
+junction=roundabout [0x0c road_class=0 road_speed=1 resolution 22]
+
+# Ways that may or may not be useable
+
+# Treat ways under construction almost as highway=path
+highway=construction { add mkgmap:dead-end-check = false; }
+[0x16 road_class=0 road_speed=0 resolution 23]
+
+# Lower the road speed of ways under some construction.
+highway=* & construction=* & maxspeed!=* { add mkgmap:road-speed = '-1' }
+# Lower the road speed of disused ways.
+highway=* & disused=yes & maxspeed!=* { add mkgmap:road-speed = '-2' }
+
+# Ways sorted roughly by descending order of class
+highway=motorway & network=e-road [0x01 resolution 14-14 continue]
+highway=motorway [0x01 road_class=4 road_speed=7 resolution 15]
+highway=motorway_link & (mkgmap:exit_hint=true | mkgmap:dest_hint=true) [0x06 road_class=3 road_speed=2 resolution 20]
+highway=motorway_link [0x09 road_class=3 road_speed=2 resolution 20]
+
+highway=trunk & ( network=e-road | int_ref=* ) [0x02 resolution 15-17 continue]
+highway=trunk [0x02 road_class=4 road_speed=5 resolution 18]
+highway=trunk_link & (mkgmap:exit_hint=true | mkgmap:dest_hint=true) [0x06 road_class=3 road_speed=2 resolution 20]
+highway=trunk_link [0x09 road_class=3 road_speed=2 resolution 20]
+highway=* & highway!=proposed & motorroad=yes [0x02 road_class=4 road_speed=4 resolution 18]
+highway=primary & ( network=e-road | int_ref=* ) [0x03 resolution 17-18 continue]
+highway=primary [0x03 road_class=3 road_speed=4 resolution 19]
+highway=primary_link [0x08 road_class=3 road_speed=1 resolution 21]
+highway=secondary & ( network=e-road | int_ref=* ) [0x04 resolution 18-19 continue]
+highway=secondary [0x04 road_class=2 road_speed=3 resolution 20]
+highway=secondary_link [0x08 road_class=2 road_speed=1 resolution 22]
+highway=tertiary [0x05 road_class=1 road_speed=3 resolution 20]
+highway=tertiary_link [0x08 road_class=1 road_speed=1 resolution 22]
+highway=minor [0x06 road_class=1 road_speed=3 resolution 21]
+highway=unclassified [0x06 road_class=0 road_speed=3 resolution 21]
+
+# Some countries allow, others disallow bicycling on pedestrian streets.
+# To allow bicycling, add 'add bicycle=yes'
+highway=pedestrian & area!=yes [0x16 road_class=0 road_speed=0 resolution 22]
+highway=living_street [0x06 road_class=0 road_speed=1 resolution 22]
+highway=residential [0x06 road_class=0 road_speed=2 resolution 22]
+highway=bridleway [0x07 road_class=0 road_speed=0 resolution 23]
+highway=byway [0x16 road_class=0 road_speed=0 resolution 23]
+
+highway=service & service=parking_aisle
+[0x07 road_class=0 road_speed=1 resolution 24]
+highway=service & (service=alley|service=driveway)
+[0x07 road_class=0 road_speed=0 resolution 23]
+highway=service [0x07 road_class=0 road_speed=2 resolution 22]
+
+highway=cycleway [0x07 road_class=0 road_speed=1 resolution 23]
+
+highway=footway|highway=path|highway=steps [0x16 road_class=0 road_speed=0 resolution 23]
+highway=track [0x0a road_class=0 road_speed=1 resolution 22]
+highway=unsurfaced [0x0a road_class=0 road_speed=1 resolution 22]
+highway=road { add mkgmap:dead-end-check = false} [0x06 road_class=0 road_speed=1 resolution 22]
+
+# Mop up any unrecognised highway types
+highway=* & highway!=proposed & area!=yes [0x07 road_class=0 road_speed=0 resolution 23]
+
+natural=coastline [0x15 resolution 12]
+power=line [0x29 resolution 21]
+
+railway=abandoned [0x0a road_class=0 road_speed=1 resolution 22]
+railway=platform [0x16 road_class=0 road_speed=0 resolution 23]
+railway=* & !(tunnel=yes) [0x14 resolution 22]
+
+man_made=cable|(man_made=* & man_made ~ '.*pipe.*')
+{name '${name} (${operator})' | '${name}' | '${operator}' }
+[0x28 resolution 23]
+
+# The following boundary styles are after the highway rules because ways
+# are frequently tagged with both and we want the highway to take priority.
+boundary=administrative { name '${mkgmap:boundary_name}' }
+boundary=administrative & admin_level<3 [0x1e resolution 12]
+boundary=administrative & admin_level<5 [0x1d resolution 19]
+boundary=administrative & admin_level<7 [0x1c resolution 21]
+boundary=administrative & admin_level<9 [0x1c resolution 22]
+boundary=administrative [0x1c resolution 22]
+boundary=national [0x1e resolution 17]
+boundary=political [0x1c resolution 19]
+
+include 'inc/water_lines';
+include 'inc/contour_lines';
+
+<finalize>
+# The finalizer section is executed for each element when a rule with an element type matches
+
+include 'inc/address';
+# calculate the road speed based on maxspeed tag
+include 'inc/roadspeed';
+# calculate the access rules
+include 'inc/access';
+
+name=* { name '${name}' }
+
+highway=* & ref=* { addlabel '${ref}' }
+highway=* & int_ref=* { addlabel '${int_ref}' }
+highway=* & nat_ref=* { addlabel '${nat_ref}' }
+highway=* & reg_ref=* { addlabel '${reg_ref}' }
diff --git a/resources/styles/default/options b/resources/styles/default/options
new file mode 100644
index 0000000..6e66ea5
--- /dev/null
+++ b/resources/styles/default/options
@@ -0,0 +1,14 @@
+
+#
+# Style options.
+#
+
+# The levels specification for this style
+#
+levels = 0:24, 1:22, 2:20, 3:18
+# More levels may make zooming smoother, but it will generate larger map tiles.
+#levels = 0:24, 1:22, 2:21, 3:20, 4:19, 5:18, 6:16
+
+overview-levels = 4:17, 5:16, 6:15, 7:14, 8:12
+#extra-used-tags=
+
diff --git a/resources/styles/default/points b/resources/styles/default/points
new file mode 100644
index 0000000..c7ed57b
--- /dev/null
+++ b/resources/styles/default/points
@@ -0,0 +1,303 @@
+# -------------------------------------------------------------------
+# This is the default mkgmap style file for converting OSM nodes
+# into Garmin POIs.
+# Any line prefaced with # is a comment and will not be applied.
+# Each line is a rule, of the generalised format:
+# OSM_tag(s)_to_match [Garmin_type_code resolution]
+# See http://wiki.openstreetmap.org/wiki/Mkgmap/help/style_rules
+# and http://wiki.openstreetmap.org/wiki/Mkgmap/help/Custom_styles
+# for more information.
+
+barrier=* & bicycle=* { set mkgmap:bicycle='${bicycle|subst:private=>no}' }
+barrier=* & foot=* { set mkgmap:foot='${foot|subst:private=>no}' }
+barrier=* & hgv=* { set mkgmap:truck='${hgv|subst:private=>no}' }
+barrier=* & motorcar=* { set mkgmap:car='${motorcar|subst:private=>no}' }
+barrier=* & psv=* { set mkgmap:bus='${psv|subst:private=>no}' }
+barrier=* & taxi=* { set mkgmap:taxi='${taxi|subst:private=>no}' }
+barrier=* & emergency=* { set mkgmap:emergency='${emergency|subst:private=>no}' }
+barrier=* & delivery=* { set mkgmap:delivery='${delivery|subst:private=>no}' }
+barrier=* & access=* { addaccess '${access|subst:private=>no}' }
+
+barrier=bollard | barrier=cycle_barrier
+ { add mkgmap:bicycle=yes;
+ add mkgmap:foot=yes;
+ addaccess no;
+ set mkgmap:road-speed=1; }
+barrier=bus_trap
+ { add mkgmap:bus=yes;
+ add mkgmap:foot=yes;
+ add mkgmap:bicycle=yes;
+ addaccess no;
+ set mkgmap:road-speed=1; }
+barrier=gate
+ { add mkgmap:bicycle=yes;
+ add mkgmap:foot=yes;
+ addaccess no;
+ set mkgmap:road-speed=0; }
+barrier=kissing_gate | barrier=stile | barrier=block
+ { add mkgmap:foot=yes;
+ addaccess no;
+ set mkgmap:road-speed=0; }
+
+internet_access=yes { name 'Internet ${name}' | 'Internet' } [0x2f12 resolution 24 continue]
+internet_access=* & internet_access!=no & internet_access!=yes { name 'Internet(${internet_access}) ${name|def:}' } [0x2f12 resolution 24 continue]
+
+(highway=bus_stop | railway=tram_stop | railway=halt | railway=station)
+& (ref=* | route_ref=*) {
+ set ref='${ref|def:}(${route_ref})';
+}
+(highway=bus_stop | railway=tram_stop | railway=halt | railway=station)
+& lit=yes & (shelter=yes | covered=yes)
+{
+ set ref='${ref|def:}*';
+}
+(highway=bus_stop | railway=tram_stop | railway=halt | railway=station)
+& lit!=yes & (shelter=yes | covered=yes)
+{
+ set ref='${ref|def:}+';
+}
+(highway=bus_stop | railway=tram_stop | railway=halt | railway=station)
+& (shelter=no | covered=no)
+{
+ set ref='${ref|def:}-';
+}
+
+include 'inc/name';
+
+place=city & population > 999999 & name=* {set cityxx=yes} [0x0100 resolution 12 continue with_actions]
+place=city & population > 799999 & cityxx!=yes & name=* {set cityxx=yes} [0x0200 resolution 14 continue with_actions]
+place=city & population > 399999 & cityxx!=yes & name=* {set cityxx=yes} [0x0300 resolution 15 continue with_actions]
+place=city & population > 299999 & cityxx!=yes & name=* {set cityxx=yes} [0x0400 resolution 16 continue with_actions]
+place=city & population > 199999 & cityxx!=yes & name=* {set cityxx=yes} [0x0500 resolution 16 continue with_actions]
+place=city & population > 99999 & cityxx!=yes & name=* {set cityxx=yes} [0x0600 resolution 17 continue with_actions]
+place=city & population > 49999 & cityxx!=yes & name=* {set cityxx=yes} [0x0700 resolution 17 continue with_actions]
+place=city & population > 9999 & cityxx!=yes & name=* {set cityxx=yes} [0x0800 resolution 18 continue with_actions]
+
+place=city & population > 0 & cityxx!=yes & name=* {set cityxx=yes} [0x0800 resolution 18 continue with_actions]
+place=city & cityxx!=yes & name=* {set cityxx=yes} [0x0700 resolution 18 continue with_actions]
+
+place=town & population > 69999 & cityxx!=yes & name=* {set cityxx=yes} [0x0600 resolution 17 continue with_actions]
+place=town & population > 19999 & cityxx!=yes & name=* {set cityxx=yes} [0x0700 resolution 18 continue with_actions]
+place=town & population > 9999 & cityxx!=yes & name=* {set cityxx=yes} [0x0800 resolution 19 continue with_actions]
+place=town & population > 4999 & cityxx!=yes & name=* {set cityxx=yes} [0x0900 resolution 19 continue with_actions]
+place=town & population > 999 & cityxx!=yes & name=* {set cityxx=yes} [0x0a00 resolution 19 continue with_actions]
+place=town & population > 0 & cityxx!=yes & name=* {set cityxx=yes} [0x0b00 resolution 20 continue with_actions]
+place=town & cityxx!=yes & name=* {set cityxx=yes} [0x0800 resolution 19 continue with_actions]
+
+place=island & cityxx!=yes {set cityxx=yes} [0x650c resolution 20 continue with_actions]
+place=islet & cityxx!=yes {set cityxx=yes} [0x650c resolution 22 continue with_actions]
+place=village & cityxx!=yes {set cityxx=yes} [0x0900 resolution 22 continue with_actions]
+place=suburb & cityxx!=yes {set cityxx=yes} [0x0a00 resolution 22 continue with_actions]
+place=hamlet & cityxx!=yes {set cityxx=yes} [0x0b00 resolution 24 continue with_actions]
+
+#aeroway=airport [0x5900 resolution 22]
+aeroway=airport [0x2f04 resolution 22]
+aeroway=aerodrome [0x2f04 resolution 22]
+aeroway=helipad [0x5904 resolution 23]
+aeroway=terminal [0x2f04 resolution 24]
+
+amenity=atm [0x2f06 resolution 24]
+amenity=arts_centre [0x2c04 resolution 24]
+amenity=bank [0x2f06 resolution 24]
+amenity=bar [0x2d02 resolution 24]
+amenity=biergarten [0x2d02 resolution 24]
+amenity=border_control | barrier=border_control [0x3006 resolution 20]
+amenity=bus_station [0x2f08 resolution 23]
+amenity=cafe [0x2a0e resolution 24]
+amenity=car_club [0x2f0d resolution 24]
+amenity=car_rental [0x2f02 resolution 24]
+amenity=car_sharing [0x2f02 resolution 24]
+amenity=car_wash [0x2f0e resolution 24]
+amenity=casino [0x2d04 resolution 24]
+amenity=cinema [0x2d03 resolution 24]
+amenity=college [0x2c05 resolution 24]
+amenity=concert_hall [0x2c09 resolution 24]
+amenity=conference_centre [0x2c09 resolution 24]
+amenity=convention_center [0x2c09 resolution 24]
+amenity=community_centre [0x3005 resolution 24]
+amenity=community_center [0x3005 resolution 24]
+amenity=courthouse [0x3004 resolution 24]
+amenity=drinking_water [0x5000 resolution 24 default_name 'Water']
+amenity=embassy & country=* { set name='${country} ${name|def:}' } [0x3003 resolution 24]
+amenity=embassy & country!=* [0x3003 resolution 24 default_name 'Embassy']
+amenity=emergency_phone [0x2f12 resolution 24 default_name 'Emergency Phone']
+amenity=ferry_terminal [0x2f08 resolution 22]
+amenity=fast_food & cuisine=grill [0x2a03 resolution 24]
+amenity=fast_food & cuisine ~ '.*pizza.*' [0x2a0a resolution 24]
+amenity=fast_food [0x2a07 resolution 24]
+amenity=fire_station [0x3008 resolution 24]
+amenity=food_court [0x2a13 resolution 24]
+amenity=fuel & fuel:HGV_diesel=yes [ 0x2f16 resolution 23]
+amenity=fuel & shop=convenience [ 0x2e06 resolution 24]
+amenity=fuel [0x2f01 resolution 24]
+amenity=kindergarten [0x2c05 resolution 24]
+amenity=library [0x2c03 resolution 24]
+amenity=nightclub [0x2d02 resolution 24]
+amenity=nursing_home [0x2b04 resolution 24]
+amenity=parking [0x2f0b resolution 24 default_name 'Parking']
+amenity=pharmacy [0x2e05 resolution 24]
+amenity=place_of_worship [0x2c0b resolution 24]
+amenity=police [0x3001 resolution 24]
+amenity=post_office [0x2f05 resolution 24]
+amenity=prison [0x3007 resolution 24]
+amenity=pub [0x2d02 resolution 24]
+amenity=public_building [0x3007 resolution 24]
+amenity=recycling [0x2f15 resolution 24]
+amenity=restaurant & cuisine=american [0x2a01 resolution 24]
+amenity=restaurant & cuisine=asian [0x2a02 resolution 24]
+amenity=restaurant & cuisine=bagel [0x2a0d resolution 24]
+amenity=restaurant & cuisine=barbecue [0x2a03 resolution 24]
+amenity=restaurant & cuisine=british [0x2a11 resolution 24]
+amenity=restaurant & cuisine='cafe/diner' [0x2a0e resolution 24]
+amenity=restaurant & cuisine=chinese [0x2a04 resolution 24]
+amenity=restaurant & cuisine=deli [0x2a05 resolution 24]
+amenity=restaurant & cuisine=french [0x2a0f resolution 24]
+amenity=restaurant & (cuisine=german | cuisine=bavarian) [0x2a10 resolution 24]
+amenity=restaurant & cuisine=grill [0x2a03 resolution 24]
+amenity=restaurant & cuisine=international [0x2a06 resolution 24]
+amenity=restaurant & cuisine=italian [0x2a08 resolution 24]
+amenity=restaurant & cuisine=japanese [0x2a02 resolution 24]
+amenity=restaurant & cuisine=korean [0x2a02 resolution 24]
+amenity=restaurant & cuisine=mexican [0x2a09 resolution 24]
+amenity=restaurant & cuisine ~ '.*pizza.*' [0x2a0a resolution 24]
+amenity=restaurant & cuisine=sea_food [0x2a0b resolution 24]
+amenity=restaurant & cuisine=spanish [0x2a09 resolution 24]
+amenity=restaurant & cuisine=speciality [0x2a12 resolution 24]
+amenity=restaurant & cuisine=steak [0x2a0c resolution 24]
+amenity=restaurant & cuisine=thai [0x2a02 resolution 24]
+amenity=restaurant & cuisine=* [0x2a13 resolution 24]
+amenity=restaurant [0x2a00 resolution 24]
+amenity=school [0x2c05 resolution 24]
+# amenity=shelter is ambiguous; when possible, consider using other tags:
+# tourism=lean_to or tourism=picnic_site
+# shelter=yes on highway=bus_stop or highway=tram_stop or railway=halt
+amenity=shelter [0x2b06 resolution 24 default_name 'Shelter']
+# amenity=supermarket is superceded by shop=supermarket
+amenity=supermarket [0x2e02 resolution 24]
+amenity=taxi [0x2f17 resolution 24]
+amenity=telephone [0x2f12 resolution 24 default_name 'Telephone']
+amenity=theatre [0x2d01 resolution 24]
+amenity=toilets & tourism=information [0x2f0c resolution 24]
+amenity=toilets [0x4e00 resolution 24 default_name 'Toilets' ]
+amenity=townhall [0x3003 resolution 24]
+amenity=university [0x2c05 resolution 24]
+# amenity=zoo is superceded by tourism=zoo
+amenity=zoo [0x2c07 resolution 24]
+
+landuse=military [0x640b resolution 24]
+landuse=village_green & name=* [0x2c06 resolution 24]
+
+healthcare=hospital | amenity=hospital [0x3002 resolution 22]
+healthcare=* | amenity=dentist | amenity=doctors [0x3002 resolution 24]
+
+highway=bus_stop [0x2f17 resolution 24]
+
+highway=motorway_junction [0x2100 resolution 24]
+
+highway=services & mkgmap:area2poi!=true [0x210f resolution 24 default_name 'Services']
+
+historic=museum [0x2c02 resolution 24]
+historic=archaeological_site | historic=ruins [0x2c02 resolution 24]
+historic=memorial [0x2c02 resolution 24]
+
+leisure=common & name=* [0x2c06 resolution 24]
+leisure=garden & name=* [0x2c06 resolution 24]
+leisure=golf_course [0x2d05 resolution 24]
+leisure=ice_rink [0x2d08 resolution 24]
+leisure=marina [0x4300 resolution 24]
+leisure=nature_reserve & name=* [0x6612 resolution 24]
+leisure=park [0x2c06 resolution 24]
+leisure=pitch { name '${name} (${sport})' | '${name}' } [0x2c08 resolution 24]
+leisure=playground [0x2c06 resolution 24]
+leisure=recreation_ground [0x2c08 resolution 24]
+leisure=sports_center | leisure=sports_centre { name '${name} (${sport})' | '${name}' } [0x2d0a resolution 24]
+leisure=stadium { name '${name} (${sport})' | '${name}' } [0x2c08 resolution 24]
+leisure=track { name '${name} (${sport})' | '${name}' } [0x2c08 resolution 24]
+leisure=water_park [0x2b04 resolution 24]
+
+man_made=tower|landmark=chimney [0x6411 resolution 24]
+
+# Edge 705 displays 0x650a,0x6511,0x6512,0x6513,0x6603,0x6614 as hollow white circles, no menu
+natural=cave_entrance [0x6601 resolution 24]
+natural=cliff [0x6607 resolution 24]
+natural=peak {name '${name|def:}${ele|height:m=>ft|def:}' } [0x6616 resolution 24]
+natural=rock [0x6614 resolution 24]
+natural=volcano [0x2c0c resolution 24]
+
+railway=halt [0x2f08 resolution 23]
+railway=station [0x2f08 resolution 22]
+railway=tram_stop [0x2f17 resolution 24]
+
+shop=bakers [0x2e02 resolution 24]
+shop=bakery [0x2e02 resolution 24]
+shop=beauty [0x2f10 resolution 24]
+shop=bicycle [0x2f13 resolution 24]
+shop=boat [0x2f09 resolution 24]
+shop=butcher [0x2e0c resolution 24]
+shop=car [0x2f07 resolution 24]
+shop=car_dealer [0x2f07 resolution 24]
+shop=car_parts [0x2f07 resolution 24]
+shop=car_rental [0x2f02 resolution 24]
+shop=car_repair [0x2f03 resolution 24]
+shop=car_wrecker [0x2f0a resolution 24]
+shop=chemist [0x2e05 resolution 24]
+shop=clothes [0x2e07 resolution 24]
+shop=computer [0x2e0b resolution 24]
+shop=convenience [0x2e02 resolution 24]
+shop=department_store [0x2e01 resolution 24]
+shop=doityourself [0x2e09 resolution 24]
+shop=fashion [0x2e07 resolution 24]
+shop=furniture [0x2e09 resolution 24]
+shop=garden_centre [0x2e08 resolution 24]
+shop=garden_center [0x2e08 resolution 24]
+shop=general [0x2e03 resolution 24]
+shop=hardware [0x2e09 resolution 24]
+shop=hairdresser [0x2f10 resolution 24]
+shop=mall [0x2e04 resolution 24]
+shop=organic [0x2e0a resolution 24]
+shop=shoes [0x2e07 resolution 24]
+shop=supermarket [0x2e02 resolution 24]
+shop=tires [0x2f07 resolution 24]
+shop=tyres [0x2f07 resolution 24]
+shop=* [0x2e0c resolution 24]
+
+sport=9pin [0x2d07 resolution 24]
+sport=10pin [0x2d07 resolution 24]
+sport=airport [0x2d0b resolution 24]
+sport=multi [0x2d0a resolution 24]
+sport=skating [0x2d08 resolution 24]
+sport=skiing [0x2d06 resolution 24]
+sport=swimming [0x2d09 resolution 24]
+
+tourism=alpine_hut [0x2b02 resolution 24]
+tourism=attraction & historic=* [0x2c02 resolution 24]
+tourism=attraction [0x2c04 resolution 24]
+tourism=artwork [0x2c04 resolution 24]
+tourism=aquarium [0x2c07 resolution 24]
+tourism=camp_site [0x2b03 resolution 24]
+tourism=caravan_site [0x2b03 resolution 24]
+tourism=chalet [0x2b02 resolution 24]
+tourism=guest_house [0x2b02 resolution 24]
+tourism=hostel [0x2b02 resolution 24]
+tourism=hotel | tourism=motel [0x2b01 resolution 24]
+tourism=information [0x2f0c resolution 24]
+# tourism=lean_to replaces some uses of amenity=shelter
+tourism=lean_to [0x2b05 resolution 24 default_name 'lean-to']
+tourism=wilderness_hut [0x2b07 resolution 24 default_name 'wilderness hut']
+tourism=museum [0x2c02 resolution 24]
+tourism=picnic_site [0x4a00 resolution 24]
+tourism=theme_park [0x2c01 resolution 24]
+tourism=viewpoint {name '${name} - ${description}' | '${name}'} [0x2c04 resolution 24]
+tourism=wine_cellar [0x2c0a resolution 24]
+tourism=zoo [0x2c07 resolution 24]
+
+barrier=bollard | barrier=bus_trap | barrier=gate [0x660f resolution 24]
+barrier=block | barrier=cycle_barrier | barrier=stile | barrier=kissing_gate [0x660f resolution 24]
+
+include 'inc/water_points';
+include 'inc/landuse_points';
+
+<finalize>
+# The finalizer section is executed for each element when a rule with an element type matches
+name=* { name '${name}' }
+include 'inc/address';
\ No newline at end of file
diff --git a/resources/styles/default/polygons b/resources/styles/default/polygons
new file mode 100644
index 0000000..edb9a28
--- /dev/null
+++ b/resources/styles/default/polygons
@@ -0,0 +1,81 @@
+# -------------------------------------------------------------------
+# This is the default mkgmap style file for converting closed OSM ways
+# into Garmin polygons.
+# Any line prefaced with # is a comment and will not be applied.
+# Each line is a rule, of the generalised format:
+# OSM_tag(s)_to_match [Garmin_type_code resolution]
+# See http://wiki.openstreetmap.org/wiki/Mkgmap/help/style_rules
+# and http://wiki.openstreetmap.org/wiki/Mkgmap/help/Custom_styles
+# for more information.
+
+leisure=* & sport=* & name=* { set name='${name} (${sport})' }
+leisure=* & sport=* & name!=* { add name='${sport}' }
+
+include 'inc/name';
+
+aeroway=airport [0x07 resolution 20]
+aeroway=aerodrome [0x07 resolution 20]
+aeroway=helipad [0x0e resolution 22]
+
+amenity=kindergarten [0x0a resolution 22]
+amenity=cafe | amenity=fast_food | amenity=restaurant | amenity=food_court [0x08 resolution 22]
+amenity=college [0x0a resolution 22]
+parking=underground | parking=multi-storey [0x06 resolution 22]
+amenity=parking | parking=surface [0x05 resolution 22]
+amenity=prison [0x04 resolution 22]
+amenity=school [0x0a resolution 22]
+# amenity=supermarket is superceded by shop=supermarket or landuse=retail
+amenity=supermarket [0x08 resolution 22]
+amenity=university [0x0a resolution 21]
+
+healthcare=hospital | amenity=hospital [0x0b resolution 22]
+healthcare=* | amenity=dentist | amenity=doctors | amenity=nursing_home
+[0x0b resolution 23]
+
+leisure=common [0x17 resolution 21]
+leisure=garden [0x17 resolution 21]
+leisure=golf_course [0x18 resolution 21]
+leisure=ice_rink [0x19 resolution 22]
+leisure=nature_reserve [0x16 resolution 19]
+leisure=park [0x17 resolution 20]
+leisure=pitch [0x19 resolution 21]
+leisure=playground [0x17 resolution 22]
+leisure=recreation_ground [0x19 resolution 21]
+leisure=sports_center | leisure=sports_centre [0x19 resolution 20]
+leisure=stadium [0x19 resolution 20]
+leisure=track & area=yes [0x19 resolution 21]
+leisure=water_park [0x09 resolution 21]
+
+place=village [0x03 resolution 19]
+place=island & name=* [0x53 resolution 19]
+place=islet & name=* [0x53 resolution 20]
+
+shop=* [0x08 resolution 22]
+
+# squares and plazas
+highway=pedestrian & area=yes [0x17 resolution 22]
+# other highways that have area=yes set must be parking lots
+highway=* & area=yes [0x05 resolution 22]
+
+historic=museum | historic=memorial [0x1e resolution 21]
+historic=archaeological_site | historic=ruins [0x1e resolution 21]
+
+# building tag should be last
+(building=* | amenity=*) & area!=no [0x13 resolution 24]
+tourism=* & area!=no & waterway!=* [0x13 resolution 24]
+# man_made can be used on areas or lines
+man_made=* & area!=no
+& (man_made!=door & man_made!=embankment & man_made!=breakwater
+ & man_made!=cable_line & man_made!=cutline & man_made!=cutting
+ & man_made!=levee & man_made!=trench)
+[0x13 resolution 24]
+man_made=* & area=yes
+[0x13 resolution 24]
+
+include 'inc/water_polygons';
+include 'inc/landuse_polygons';
+
+<finalize>
+# The finalizer section is executed for each element when a rule with an element type matches
+
+name=* { name '${name}' }
\ No newline at end of file
diff --git a/resources/styles/default/relations b/resources/styles/default/relations
new file mode 100644
index 0000000..f3d0418
--- /dev/null
+++ b/resources/styles/default/relations
@@ -0,0 +1,56 @@
+# -------------------------------------------------------------------
+# This is the default mkgmap style file for applying rules on
+# OSM relations. Usually you will set tags on the
+# elements that make up the relation, and the tags will be
+# processed by the rules defined in the "points" or "lines" files.
+#
+# Any line prefaced with # is a comment and will not be applied.
+# Each line is a rule, of the generalised format:
+# OSM_tag(s)_to_match [Garmin_type_code resolution]
+# See http://wiki.openstreetmap.org/wiki/Mkgmap/help/style_rules
+# and http://wiki.openstreetmap.org/wiki/Mkgmap/help/Custom_styles
+# for more information.
+
+# Names of administrative boundaries.
+# We could want to sort the relations in ascending order of admin_level
+# and alphabetically by name first.
+# Currently, the matching relations will be processed and the names
+# appended to the boundary lines in an arbitrary order.
+(type=boundary | type=multipolygon) & boundary=administrative & name=*
+{ apply
+ {
+ set mkgmap:boundary_name='$(mkgmap:boundary_name)/${name}' | '${name}';
+ }
+}
+
+# European E-Road network
+route=road & network=e-road { apply { add ref='${ref}'; add int_ref='${int_ref'}; add network=e-road }
+
+# Public transportation routes.
+# We could want to sort the matching relations by ref first.
+type=route
+& (route=bus|route=trolleybus|route=ferry|route=subway|route=train|route=tram)
+& (ref=* | name=*)
+{
+ add ref='${name}'; # if ref is missing, use name
+ # Append the ref of the route relation to the route_ref attribute of
+ # the member nodes recursively (even to members of subrelations).
+ # Stops can be grouped within subrelations comprising the vehicle
+ # stop node and the passenger wait node.
+ apply { # node role ~ '(start_|end_)stop'
+ set route_ref='$(route_ref),${ref}' | '${ref}';
+
+ # In route relations, stops may be defined as relations that group
+ # the passenger wait area and the vehicle stop area. If such
+ # subrelations exist, copy the ref to them too.
+ set mkgmap:relref='${ref}';
+
+ apply role=passengers {
+ set route_ref='$(route_ref),${mkgmap:relref}' | '${mkgmap:relref}';
+ }
+
+ delete mkgmap:relref;
+ }
+ # We could want to copy the route relation name to unnamed route=ferry ways.
+ # apply way { add name='${name}' }
+}
diff --git a/resources/styles/default/version b/resources/styles/default/version
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/resources/styles/default/version
@@ -0,0 +1 @@
+1
diff --git a/resources/styles/floodblocker/info b/resources/styles/floodblocker/info
new file mode 100644
index 0000000..fa7a4bd
--- /dev/null
+++ b/resources/styles/floodblocker/info
@@ -0,0 +1,17 @@
+#
+# This file contains information about the style.
+# It is completely optional.
+#
+
+
+# A short one line description of the style
+#
+summary: A style for controlling the detection of land and sea areas
+
+# Version of the style itself
+#
+version=0.1
+
+description {
+A style for controlling the detection of land and sea areas
+}
diff --git a/resources/styles/floodblocker/lines b/resources/styles/floodblocker/lines
new file mode 100644
index 0000000..1354e3a
--- /dev/null
+++ b/resources/styles/floodblocker/lines
@@ -0,0 +1,26 @@
+# -------------------------------------------------------------------
+# This is the rules file to configure the rules which lines are
+# identified as land or sea
+# Set the type 0x01 for each land line and 0x02 for each sea line
+#
+# Any line prefaced with # is a comment and will not be applied.
+# Each line is a rule, of the generalised format:
+# OSM_tag(s)_to_match [Garmin_type_code resolution]
+# See http://wiki.openstreetmap.org/wiki/Mkgmap/help/style_rules
+# and http://wiki.openstreetmap.org/wiki/Mkgmap/help/Custom_styles
+# for more information.
+
+# land rules (set 0x01)
+highway=*
+& highway!=construction
+& construction!=*
+& bridge!=yes
+& tunnel!=yes
+& (layer!=* | layer=0)
+& waterway!=dam
+& man_made!=pier [0x01]
+
+
+# sea rules (set 0x02)
+route=ferry [0x02]
+boundary=administrative & maritime=yes [0x02]
\ No newline at end of file
diff --git a/resources/styles/floodblocker/version b/resources/styles/floodblocker/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/resources/styles/floodblocker/version
@@ -0,0 +1 @@
+0
diff --git a/resources/styles/landuse/info b/resources/styles/landuse/info
new file mode 100644
index 0000000..137acd3
--- /dev/null
+++ b/resources/styles/landuse/info
@@ -0,0 +1,11 @@
+summary: The landuse style. Most natural=*, landuse=* except water features
+
+# Version of the style itself
+#
+version=1.0
+
+# A longer description of the style.
+description {
+The landuse style. This generates polygons and points for most other features
+than water features and man-made structures, such as buildings.
+}
diff --git a/resources/styles/landuse/points b/resources/styles/landuse/points
new file mode 100644
index 0000000..380338a
--- /dev/null
+++ b/resources/styles/landuse/points
@@ -0,0 +1,4 @@
+landuse=cemetery|landuse=cemetary|amenity=grave_yard [0x6403 resolution 24]
+landuse=military [0x640b resolution 24]
+landuse=village_green & name=* [0x2c06 resolution 24]
+(landuse=wood|landuse=forest|natural=wood) & name=* [0x6618 resolution 24]
diff --git a/resources/styles/landuse/polygons b/resources/styles/landuse/polygons
new file mode 100644
index 0000000..7e7e627
--- /dev/null
+++ b/resources/styles/landuse/polygons
@@ -0,0 +1,26 @@
+landuse=allotments [0x4e resolution 21]
+landuse=cemetery|landuse=cemetary|amenity=grave_yard [0x1a resolution 21]
+landuse=commercial [0x0c resolution 19]
+landuse=construction [0x0c resolution 21]
+landuse=farm [0x4e resolution 20]
+landuse=farmyard [0x4e resolution 22]
+landuse=forest|landuse=wood [0x50 resolution 20]
+landuse=greenfield [0x17 resolution 20]
+landuse=meadow [0x17 resolution 19]
+landuse=military [0x04 resolution 19]
+landuse=quarry [0x0c resolution 19]
+landuse=recreation_ground [0x19 resolution 19]
+# dedicate resolution 24 for building=* instead of related landuse=*
+landuse=industrial [0x0c resolution 23-19]
+landuse=residential [0x10 resolution 23-19]
+landuse=retail [0x08 resolution 23-20]
+landuse=village_green [0x17 resolution 20]
+landuse=vineyard [0x4e resolution 20]
+
+military=airfield [0x04 resolution 20]
+military=barracks [0x04 resolution 23]
+military=danger_area [0x04 resolution 20]
+military=range [0x04 resolution 20]
+
+natural=scrub [0x4f resolution 20]
+natural=wood [0x50 resolution 20]
diff --git a/resources/styles/landuse/version b/resources/styles/landuse/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/resources/styles/landuse/version
@@ -0,0 +1 @@
+0
diff --git a/resources/styles/marine/info b/resources/styles/marine/info
new file mode 100644
index 0000000..7bd146a
--- /dev/null
+++ b/resources/styles/marine/info
@@ -0,0 +1,2 @@
+
+summary=marine objects
diff --git a/resources/styles/marine/lines b/resources/styles/marine/lines
new file mode 100644
index 0000000..f156170
--- /dev/null
+++ b/resources/styles/marine/lines
@@ -0,0 +1,5 @@
+
+man_made=pier [0x01040c resolution 22]
+man_made=breakwater [0x010400 resolution 22]
+
+leisure=marina [0x010500 resolution 20]
diff --git a/resources/styles/marine/options b/resources/styles/marine/options
new file mode 100644
index 0000000..75840fd
--- /dev/null
+++ b/resources/styles/marine/options
@@ -0,0 +1,10 @@
+
+#
+# Style options.
+#
+
+# The levels specification for this style
+#
+levels = 0:24, 1:22, 2:20, 3:18, 4:16
+
+extra-used-tags=seamark:light:character seamark:light:sequence seamark:light:range
diff --git a/resources/styles/marine/points b/resources/styles/marine/points
new file mode 100644
index 0000000..83981ee
--- /dev/null
+++ b/resources/styles/marine/points
@@ -0,0 +1,186 @@
+leisure=marina [0x4300 resolution 20]
+
+############################################################################
+# begin seamark marine objects
+
+################################################
+# add mkgmap:xt- tags
+
+seamark:light:ref=* { add mkgmap:xt-int-desig='${seamark:light:ref}'; }
+seamark:beacon_lateral:ref=* { add mkgmap:xt-int-desig='${seamark:beacon_lateral:ref}'; }
+seamark:buoy_lateral:ref=* { add mkgmap:xt-int-desig='${seamark:buoy_lateral:ref}'; }
+
+seamark:light:height=* { add mkgmap:xt-height-above-datum='${seamark:light:height}'; }
+seamark:light:colour=* { add mkgmap:xt-light='${seamark:light:colour}'; }
+seamark:light:period=* { add mkgmap:xt-period='${seamark:light:period}'; }
+seamark:light:group=* { add mkgmap:xt-note='Group: ${seamark:light:group}'; }
+
+# deprecated
+seamark:light:signal:period=* { add mkgmap:xt-period='${seamark:light:signal:period}'; }
+seamark:light:signal:sequence=* { add mkgmap:xt-note='${seamark:light:signal:sequence}'; }
+light:signal_sequence=* & seamark:light:sequence!=* { add seamark:light:sequence='${light:signal_sequence}'; }
+light:character=* & seamark:light:character!=* { add seamark:light:character='${light:character}'; }
+light:range=* & seamark:light:range!=* { add seamark:light:range='${light:range}'; }
+light:colour=* { add mkgmap:xt-light='${light:colour}'; }
+light:ele=* { add mkgmap:xt-height-above-datum='${light:ele}'; }
+light:signal_group=* { add mkgmap:xt-note='Group: ${light:signal_group}'; }
+light:signal_period=* { add mkgmap:xt-period='${light:signal_period}'; }
+
+seamark:buoy_special_purpose:colour=* { add mkgmap:xt-colour='${seamark:buoy_special_purpose:colour}'; }
+seamark:buoy_lateral:colour=* { add mkgmap:xt-colour='${seamark:buoy_lateral:colour}'; }
+
+seamark:buoy_safe_water:colour='red,white,red' { add mkgmap:xt-colour='red-white'; }
+seamark:buoy_safe_water:colour=* { add mkgmap:xt-colour='${seamark:buoy_safe_water:colour}'; }
+
+seamark:buoy_race:colour=* { add mkgmap:xt-colour='${seamark:buoy_race:colour}'; }
+
+seamark:beacon_isolated_danger:colour=* { add mkgmap:xt-colour='${seamark:beacon_isolated_danger:colour}'; }
+seamark:beacon_special_purpose:colour=* { add mkgmap:xt-colour='${seamark:beacon_special_purpose:colour}'; }
+seamark:beacon_safe_water:colour=* { add mkgmap:xt-colour='${seamark:beacon_safe_water:colour}'; }
+seamark:beacon_lateral:colour=* { add mkgmap:xt-colour='${seamark:beacon_lateral:colour}'; }
+
+# sectors
+seamark:light:1!=* & seamark:light:1:sector_start=*
+& seamark:light:1:sector_end=* & seamark:light:1:colour=*
+& seamark:light:1:range=*
+{add seamark:light:1='${seamark:light:1:colour}:${seamark:light:1:sector_start}:${seamark:light:1:sector_end}:${seamark:light:1:range}'}
+
+seamark:light:2!=* & seamark:light:2:sector_start=*
+& seamark:light:2:sector_end=* & seamark:light:2:colour=*
+& seamark:light:2:range=*
+{add seamark:light:2='${seamark:light:2:colour}:${seamark:light:2:sector_start}:${seamark:light:2:sector_end}:${seamark:light:2:range}'}
+
+seamark:light:3!=* & seamark:light:3:sector_start=*
+& seamark:light:3:sector_end=* & seamark:light:3:colour=*
+& seamark:light:3:range=*
+{add seamark:light:3='${seamark:light:3:colour}:${seamark:light:3:sector_start}:${seamark:light:3:sector_end}:${seamark:light:3:range}'}
+
+seamark:light:4!=* & seamark:light:4:sector_start=*
+& seamark:light:4:sector_end=* & seamark:light:4:colour=*
+& seamark:light:4:range=*
+{add seamark:light:4='${seamark:light:4:colour}:${seamark:light:4:sector_start}:${seamark:light:4:sector_end}:${seamark:light:4:range}'}
+
+seamark:light:5!=* & seamark:light:5:sector_start=*
+& seamark:light:5:sector_end=* & seamark:light:5:colour=*
+& seamark:light:5:range=*
+{add seamark:light:5='${seamark:light:5:colour}:${seamark:light:5:sector_start}:${seamark:light:5:sector_end}:${seamark:light:5:range}'}
+
+seamark:light:6!=* & seamark:light:6:sector_start=*
+& seamark:light:6:sector_end=* & seamark:light:6:colour=*
+& seamark:light:6:range=*
+{add seamark:light:6='${seamark:light:6:colour}:${seamark:light:6:sector_start}:${seamark:light:6:sector_end}:${seamark:light:6:range}'}
+
+seamark:light:7!=* & seamark:light:7:sector_start=*
+& seamark:light:7:sector_end=* & seamark:light:7:colour=*
+& seamark:light:7:range=*
+{add seamark:light:7='${seamark:light:7:colour}:${seamark:light:7:sector_start}:${seamark:light:7:sector_end}:${seamark:light:7:range}'}
+
+seamark:light:8!=* & seamark:light:8:sector_start=*
+& seamark:light:8:sector_end=* & seamark:light:8:colour=*
+& seamark:light:8:range=*
+{add seamark:light:8='${seamark:light:8:colour}:${seamark:light:8:sector_start}:${seamark:light:8:sector_end}:${seamark:light:8:range}'}
+
+seamark:light:9!=* & seamark:light:9:sector_start=*
+& seamark:light:9:sector_end=* & seamark:light:9:colour=*
+& seamark:light:9:range=*
+{add seamark:light:9='${seamark:light:9:colour}:${seamark:light:9:sector_start}:${seamark:light:9:sector_end}:${seamark:light:9:range}'}
+
+seamark:light:10!=* & seamark:light:10:sector_start=*
+& seamark:light:10:sector_end=* & seamark:light:10:colour=*
+& seamark:light:10:range=*
+{add seamark:light:10='${seamark:light:10:colour}:${seamark:light:10:sector_start}:${seamark:light:10:sector_end}:${seamark:light:10:range}'}
+
+seamark:light:11!=* & seamark:light:11:sector_start=*
+& seamark:light:11:sector_end=* & seamark:light:11:colour=*
+& seamark:light:11:range=*
+{add seamark:light:11='${seamark:light:11:colour}:${seamark:light:11:sector_start}:${seamark:light:11:sector_end}:${seamark:light:11:range}'}
+
+seamark:light:12!=* & seamark:light:12:sector_start=*
+& seamark:light:12:sector_end=* & seamark:light:12:colour=*
+& seamark:light:12:range=*
+{add seamark:light:12='${seamark:light:12:colour}:${seamark:light:12:sector_start}:${seamark:light:12:sector_end}:${seamark:light:12:range}'}
+
+seamark:light:13!=* & seamark:light:13:sector_start=*
+& seamark:light:13:sector_end=* & seamark:light:13:colour=*
+& seamark:light:13:range=*
+{add seamark:light:13='${seamark:light:13:colour}:${seamark:light:13:sector_start}:${seamark:light:13:sector_end}:${seamark:light:13:range}'}
+
+seamark:light:14!=* & seamark:light:14:sector_start=*
+& seamark:light:14:sector_end=* & seamark:light:14:colour=*
+& seamark:light:14:range=*
+{add seamark:light:14='${seamark:light:14:colour}:${seamark:light:14:sector_start}:${seamark:light:14:sector_end}:${seamark:light:14:range}'}
+
+seamark:light:15!=* & seamark:light:15:sector_start=*
+& seamark:light:15:sector_end=* & seamark:light:15:colour=*
+& seamark:light:15:range=*
+{add seamark:light:15='${seamark:light:15:colour}:${seamark:light:15:sector_start}:${seamark:light:15:sector_end}:${seamark:light:15:range}'}
+
+
+######
+# define types
+
+# buoys
+seamark:buoy_lateral:shape=spar [0x010207 resolution 22]
+seamark:buoy_lateral:category=port { add mkgmap:xt-colour='red'; } [0x010209 resolution 22]
+seamark:buoy_lateral:category=starboard { add mkgmap:xt-colour='green'; } [0x01020a resolution 22]
+seamark:buoy_lateral:category=preferred_channel_port { add mkgmap:xt-colour='green-red-green'; } [0x010209 resolution 22]
+seamark:buoy_lateral:category=preferred_channel_starboard { add mkgmap:xt-colour='red-green-red'; } [0x01020a resolution 22]
+seamark:type=buoy_lateral [0x010200 resolution 22]
+
+seamark:buoy_cardinal:category=north { add mkgmap:xt-colour='black-yellow'; } [0x010202 resolution 22]
+seamark:buoy_cardinal:category=south { add mkgmap:xt-colour='yellow-black'; } [0x010203 resolution 22]
+seamark:buoy_cardinal:category=east { add mkgmap:xt-colour='black-yellow-black'; } [0x010204 resolution 22]
+seamark:buoy_cardinal:category=west { add mkgmap:xt-colour='yellow-black-yellow'; } [0x010205 resolution 22]
+
+seamark:buoy_special_purpose:shape=pillar [0x010207 resolution 22]
+seamark:buoy_special_purpose:shape=spar [0x010207 resolution 22]
+seamark:buoy_special_purpose:shape=barrel [0x01020d resolution 22]
+seamark:type=buoy_special_purpose [0x01020b resolution 22]
+
+seamark:type=buoy_isolated_danger { add mkgmap:xt-colour='black-red-black'; } [0x010208 resolution 22]
+
+seamark:type=buoy_safe_water [0x01020c resolution 22]
+
+seamark:buoy_race:shape=* { add mkgmap:xt-note='Race Buoy' } [0x010200 resolution 22]
+
+#lights
+seamark=lighthouse & seamark:light:colour='red' [0x010107 resolution 20]
+seamark=lighthouse & seamark:light:colour='green' [0x010108 resolution 20]
+# approved?
+seamark:lighthouse:colour='red,white,red' & seamark:lighthouse:light='yes' { add mkgmap:xt-light='red'; } [0x010107 resolution 20]
+seamark:lighthouse:colour='green,white,green' & seamark:lighthouse:light='yes' { add mkgmap:xt-light='green'; } [0x010108 resolution 20]
+
+seamark=lighthouse [0x010100 resolution 20]
+seamark:type=landmark [0x010100 resolution 20]
+seamark:type=light_major [0x010100 resolution 20]
+seamark:type=light_minor [0x010100 resolution 22]
+seamark:type=light_vessel [0x010100 resolution 20]
+seamark:type=light_float [0x010100 resolution 20]
+
+#beacons
+seamark:beacon_lateral:category=port [0x010213 resolution 22]
+seamark:beacon_lateral:category=starboard [0x010214 resolution 22]
+seamark:beacon_lateral:category=preferred_channel_port [0x010206 resolution 22]
+seamark:beacon_lateral:category=preferred_channel_starboard [0x010206 resolution 22]
+seamark:type:beacon_lateral=* [0x010206 resolution 22]
+
+seamark:beacon_cardinal:category=north { add mkgmap:xt-colour='black-yellow'; } [0x01020e resolution 22]
+seamark:beacon_cardinal:category=south { add mkgmap:xt-colour='yellow-black'; } [0x01020f resolution 22]
+seamark:beacon_cardinal:category=east { add mkgmap:xt-colour='black-yellow-black'; } [0x010210 resolution 22]
+seamark:beacon_cardinal:category=west { add mkgmap:xt-colour='yellow-black-yellow'; } [0x010211 resolution 22]
+
+seamark:type=beacon_special_purpose [0x010215 resolution 22]
+seamark:type=beacon_safe_water [0x010206 resolution 22]
+seamark:type=beacon_isolated_danger [0x010212 resolution 22]
+
+seamark:light:1=* [0x010100 resolution 20]
+
+#other
+waterway=depth & name=* { name '${name|subst:,=>.}' } [ 0x6200 resolution 22]
+waterway=fuel { add mkgmap:xt-facilities='0x40'; }[ 0x010903 resolution 22 ]
+waterway=wreck [ 0x010402 resolution 22 ]
+historic=wreck [ 0x010402 resolution 22 ]
+
+# end seamark marine objects
+############################################################################
+
diff --git a/resources/styles/marine/version b/resources/styles/marine/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/resources/styles/marine/version
@@ -0,0 +1 @@
+0
diff --git a/resources/styles/noname/info b/resources/styles/noname/info
new file mode 100644
index 0000000..d170cc9
--- /dev/null
+++ b/resources/styles/noname/info
@@ -0,0 +1,19 @@
+
+#
+# Suggested by Michel Marti on the mailing list and
+# enhanced to use the newer features of the style system.
+#
+
+version: 1
+
+summary: Special map to highlight roads with no name
+
+description {
+ This style is to help find roads that don't yet have a name in OSM
+ by highlighting those roads. Roads that have a name or a ref
+ are shown as thin lines, ones that are missing a name are shown
+ as thick lines.
+
+ If there is a noname=yes tag this means that the road really doesn't have
+ a name and so they won't be highlighted.
+}
diff --git a/resources/styles/noname/lines b/resources/styles/noname/lines
new file mode 100644
index 0000000..5300da4
--- /dev/null
+++ b/resources/styles/noname/lines
@@ -0,0 +1,30 @@
+
+# If something is not meant to have a name, record this so
+# that it doesn't get highlighted.
+noname=yes { name 'deliberately does not have a name' }
+
+# Catch no-name main road separately so we can give them different
+# zoom levels.
+highway=motorway & ref != * {add oneway = yes } [0x01 resolution 12]
+highway=primary & (ref!=* & name != *) [0x01 resolution 19]
+highway=secondary & (ref != * & name != *) [0x01 resolution 20]
+
+# Catch residential streets with no name display them even at lower
+# zooms than you would normally.
+(highway=residential
+ | highway=living_street
+ | highway=unclassified) & name != *
+ [0x01 resolution 21]
+
+# Give the main roads that are OK slightly more prominence so you
+# can get your bearings easier
+highway=motorway [0x6 resolution 12]
+highway=trunk [0x6 resolution 16]
+highway=primary [0x6 resolution 19]
+
+# Everything else goes as a thin line.
+highway=*
+ {name '${name} (${ref})' | '${ref}' }
+ [0x7 resolution 22]
+
+include lines from default;
diff --git a/resources/styles/noname/points b/resources/styles/noname/points
new file mode 100644
index 0000000..f718572
--- /dev/null
+++ b/resources/styles/noname/points
@@ -0,0 +1,2 @@
+
+include points from default;
diff --git a/resources/styles/noname/polygons b/resources/styles/noname/polygons
new file mode 100644
index 0000000..cdc8f25
--- /dev/null
+++ b/resources/styles/noname/polygons
@@ -0,0 +1,2 @@
+
+include polygons from default;
diff --git a/resources/styles/noname/version b/resources/styles/noname/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/resources/styles/noname/version
@@ -0,0 +1 @@
+0
diff --git a/resources/styles/routes-bicycle/info b/resources/styles/routes-bicycle/info
new file mode 100644
index 0000000..9c6fd82
--- /dev/null
+++ b/resources/styles/routes-bicycle/info
@@ -0,0 +1,17 @@
+#
+# This file contains information about the style.
+# It is completely optional.
+#
+
+
+# A short one line description of the style
+#
+summary: A style for bicycle routes
+
+# Version of the style itself
+#
+version=1.0
+
+description {
+This style is useful for highlighting bicycle routes on a separate map layer.
+}
diff --git a/resources/styles/routes-bicycle/lines b/resources/styles/routes-bicycle/lines
new file mode 100644
index 0000000..5cceade
--- /dev/null
+++ b/resources/styles/routes-bicycle/lines
@@ -0,0 +1 @@
+mkgmap:route=* { name '${mkgmap:route}' } [0x1a resolution 21]
diff --git a/resources/styles/routes-bicycle/relations b/resources/styles/routes-bicycle/relations
new file mode 100644
index 0000000..5c48619
--- /dev/null
+++ b/resources/styles/routes-bicycle/relations
@@ -0,0 +1,6 @@
+type=route & route=bicycle
+{
+ add ref='${name}'; # if ref is missing, use name
+ set ref='${network} ${ref}' | '${ref}' | '${network}';
+ apply { set mkgmap:route='$(mkgmap:route),${ref}' | '${ref}' }
+}
diff --git a/resources/styles/routes-bicycle/version b/resources/styles/routes-bicycle/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/resources/styles/routes-bicycle/version
@@ -0,0 +1 @@
+0
diff --git a/resources/styles/routes-bus/info b/resources/styles/routes-bus/info
new file mode 100644
index 0000000..b6bb149
--- /dev/null
+++ b/resources/styles/routes-bus/info
@@ -0,0 +1,17 @@
+#
+# This file contains information about the style.
+# It is completely optional.
+#
+
+
+# A short one line description of the style
+#
+summary: A style for public transportation (bus) routes
+
+# Version of the style itself
+#
+version=1.0
+
+description {
+This style is useful for highlighting bus routes on a separate map layer.
+}
diff --git a/resources/styles/routes-bus/lines b/resources/styles/routes-bus/lines
new file mode 100644
index 0000000..b2c9f79
--- /dev/null
+++ b/resources/styles/routes-bus/lines
@@ -0,0 +1 @@
+mkgmap:route=* { name '${mkgmap:route}' } [0x19 resolution 20]
diff --git a/resources/styles/routes-bus/relations b/resources/styles/routes-bus/relations
new file mode 100644
index 0000000..81a2bda
--- /dev/null
+++ b/resources/styles/routes-bus/relations
@@ -0,0 +1,6 @@
+type=route & route=bus
+{
+ add ref='${name}'; # if ref is missing, use name
+ set ref='${network} ${ref}' | '${ref}' | '${network}';
+ apply { set mkgmap:route='$(mkgmap:route),${ref}' | '${ref}' }
+}
diff --git a/resources/styles/routes-bus/version b/resources/styles/routes-bus/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/resources/styles/routes-bus/version
@@ -0,0 +1 @@
+0
diff --git a/resources/styles/routes-ferry/info b/resources/styles/routes-ferry/info
new file mode 100644
index 0000000..ddb0b09
--- /dev/null
+++ b/resources/styles/routes-ferry/info
@@ -0,0 +1,17 @@
+#
+# This file contains information about the style.
+# It is completely optional.
+#
+
+
+# A short one line description of the style
+#
+summary: A style for ferry route relations
+
+# Version of the style itself
+#
+version=1.0
+
+description {
+This style is useful for highlighting ferry routes on a separate map layer.
+}
diff --git a/resources/styles/routes-ferry/lines b/resources/styles/routes-ferry/lines
new file mode 100644
index 0000000..df848a3
--- /dev/null
+++ b/resources/styles/routes-ferry/lines
@@ -0,0 +1 @@
+mkgmap:route=* { name '${mkgmap:route}' } [0x1b resolution 20]
diff --git a/resources/styles/routes-ferry/relations b/resources/styles/routes-ferry/relations
new file mode 100644
index 0000000..a6922ac
--- /dev/null
+++ b/resources/styles/routes-ferry/relations
@@ -0,0 +1,6 @@
+type=route & route=ferry
+{
+ add ref='${name}'; # if ref is missing, use name
+ set ref='${network} ${ref}' | '${ref}' | '${network}';
+ apply { set mkgmap:route='$(mkgmap:route),${ref}' | '${ref}' }
+}
diff --git a/resources/styles/routes-ferry/version b/resources/styles/routes-ferry/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/resources/styles/routes-ferry/version
@@ -0,0 +1 @@
+0
diff --git a/resources/styles/routes-foot/info b/resources/styles/routes-foot/info
new file mode 100644
index 0000000..b910ea1
--- /dev/null
+++ b/resources/styles/routes-foot/info
@@ -0,0 +1,18 @@
+#
+# This file contains information about the style.
+# It is completely optional.
+#
+
+
+# A short one line description of the style
+#
+summary: A style for pedestrian routes
+
+# Version of the style itself
+#
+version=1.0
+
+description {
+This style is useful for highlighting pedestrian or hiking routes on a
+separate map layer.
+}
diff --git a/resources/styles/routes-foot/lines b/resources/styles/routes-foot/lines
new file mode 100644
index 0000000..5cceade
--- /dev/null
+++ b/resources/styles/routes-foot/lines
@@ -0,0 +1 @@
+mkgmap:route=* { name '${mkgmap:route}' } [0x1a resolution 21]
diff --git a/resources/styles/routes-foot/relations b/resources/styles/routes-foot/relations
new file mode 100644
index 0000000..ff46dcf
--- /dev/null
+++ b/resources/styles/routes-foot/relations
@@ -0,0 +1,6 @@
+type=route & (route=foot|route=hiking)
+{
+ add ref='${name}'; # if ref is missing, use name
+ set ref='${network} ${ref}' | '${ref}' | '${network}';
+ apply { set mkgmap:route='$(mkgmap:route),${ref}' | '${ref}' }
+}
diff --git a/resources/styles/routes-foot/version b/resources/styles/routes-foot/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/resources/styles/routes-foot/version
@@ -0,0 +1 @@
+0
diff --git a/resources/styles/routes-rail/info b/resources/styles/routes-rail/info
new file mode 100644
index 0000000..0803f47
--- /dev/null
+++ b/resources/styles/routes-rail/info
@@ -0,0 +1,17 @@
+#
+# This file contains information about the style.
+# It is completely optional.
+#
+
+
+# A short one line description of the style
+#
+summary: A style for railway routes
+
+# Version of the style itself
+#
+version=1.0
+
+description {
+This style is useful for highlighting rail routes on a separate map layer.
+}
diff --git a/resources/styles/routes-rail/lines b/resources/styles/routes-rail/lines
new file mode 100644
index 0000000..b2c9f79
--- /dev/null
+++ b/resources/styles/routes-rail/lines
@@ -0,0 +1 @@
+mkgmap:route=* { name '${mkgmap:route}' } [0x19 resolution 20]
diff --git a/resources/styles/routes-rail/relations b/resources/styles/routes-rail/relations
new file mode 100644
index 0000000..00fe3bb
--- /dev/null
+++ b/resources/styles/routes-rail/relations
@@ -0,0 +1,6 @@
+type=route & (route=subway|route=train|route=tram)
+{
+ add ref='${name}'; # if ref is missing, use name
+ set ref='${network} ${ref}' | '${ref}' | '${network}';
+ apply { set mkgmap:route='$(mkgmap:route),${ref}' | '${ref}' }
+}
diff --git a/resources/styles/routes-rail/version b/resources/styles/routes-rail/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/resources/styles/routes-rail/version
@@ -0,0 +1 @@
+0
diff --git a/resources/styles/routes-road/info b/resources/styles/routes-road/info
new file mode 100644
index 0000000..accf0ee
--- /dev/null
+++ b/resources/styles/routes-road/info
@@ -0,0 +1,17 @@
+#
+# This file contains information about the style.
+# It is completely optional.
+#
+
+
+# A short one line description of the style
+#
+summary: A style for road networks
+
+# Version of the style itself
+#
+version=1.0
+
+description {
+This style is useful for highlighting road relations on a separate map layer.
+}
diff --git a/resources/styles/routes-road/lines b/resources/styles/routes-road/lines
new file mode 100644
index 0000000..1df7b1d
--- /dev/null
+++ b/resources/styles/routes-road/lines
@@ -0,0 +1 @@
+mkgmap:route=* { name '${mkgmap:route}' } [0x1a resolution 18]
diff --git a/resources/styles/routes-road/relations b/resources/styles/routes-road/relations
new file mode 100644
index 0000000..aeefa30
--- /dev/null
+++ b/resources/styles/routes-road/relations
@@ -0,0 +1,6 @@
+type=route & route=road
+{
+ add ref='${name}'; # if ref is missing, use name
+ set ref='${network} ${ref}' | '${ref}' | '${network}';
+ apply { set mkgmap:route='$(mkgmap:route),${ref}' | '${ref}' }
+}
diff --git a/resources/styles/routes-road/version b/resources/styles/routes-road/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/resources/styles/routes-road/version
@@ -0,0 +1 @@
+0
diff --git a/resources/styles/routes-ski/info b/resources/styles/routes-ski/info
new file mode 100644
index 0000000..5462c45
--- /dev/null
+++ b/resources/styles/routes-ski/info
@@ -0,0 +1,17 @@
+#
+# This file contains information about the style.
+# It is completely optional.
+#
+
+
+# A short one line description of the style
+#
+summary: A style for ski routes
+
+# Version of the style itself
+#
+version=1.0
+
+description {
+This style is useful for highlighting ski routes on a separate map layer.
+}
diff --git a/resources/styles/routes-ski/lines b/resources/styles/routes-ski/lines
new file mode 100644
index 0000000..e7ac19f
--- /dev/null
+++ b/resources/styles/routes-ski/lines
@@ -0,0 +1 @@
+mkgmap:route=* { name '${mkgmap:route}' } [0x1a resolution 22]
diff --git a/resources/styles/routes-ski/relations b/resources/styles/routes-ski/relations
new file mode 100644
index 0000000..edf9b78
--- /dev/null
+++ b/resources/styles/routes-ski/relations
@@ -0,0 +1,6 @@
+type=route & route=ski
+{
+ add ref='${name}'; # if ref is missing, use name
+ set ref='${network} ${ref}' | '${ref}' | '${network}';
+ apply { set mkgmap:route='$(mkgmap:route),${ref}' | '${ref}' }
+}
diff --git a/resources/styles/routes-ski/version b/resources/styles/routes-ski/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/resources/styles/routes-ski/version
@@ -0,0 +1 @@
+0
diff --git a/resources/styles/routes/info b/resources/styles/routes/info
new file mode 100644
index 0000000..dd31ada
--- /dev/null
+++ b/resources/styles/routes/info
@@ -0,0 +1,17 @@
+#
+# This file contains information about the style.
+# It is completely optional.
+#
+
+
+# A short one line description of the style
+#
+summary: A style for route relations
+
+# Version of the style itself
+#
+version=1.0
+
+description {
+This style is useful for highlighting route relations on a separate map layer.
+}
diff --git a/resources/styles/routes/lines b/resources/styles/routes/lines
new file mode 100644
index 0000000..e384424
--- /dev/null
+++ b/resources/styles/routes/lines
@@ -0,0 +1,3 @@
+railway=* & mkgmap:route=* { name '${mkgmap:route}' } [0x1e resolution 16]
+route=ferry & mkgmap:route=* { name '${mkgmap:route}' } [0x1b resolution 16]
+highway=* & mkgmap:route=* { name '${mkgmap:route}' } [0x1d resolution 16]
diff --git a/resources/styles/routes/relations b/resources/styles/routes/relations
new file mode 100644
index 0000000..8ecb137
--- /dev/null
+++ b/resources/styles/routes/relations
@@ -0,0 +1,9 @@
+type=route
+& (route=bus|route=ferry|route=subway|route=train|route=tram|
+ route=road|
+ route=bicycle|route=foot|route=hiking|route=ski)
+{
+ add ref='${name}'; # if ref is missing, use name
+ set ref='${route} ${network} ${ref}' | '${route} ${ref}' | '${route} ${network}' | '${route}';
+ apply { set mkgmap:route='$(mkgmap:route),${ref}' | '${ref}' }
+}
diff --git a/resources/styles/routes/version b/resources/styles/routes/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/resources/styles/routes/version
@@ -0,0 +1 @@
+0
diff --git a/resources/styles/test/info b/resources/styles/test/info
new file mode 100644
index 0000000..7226488
--- /dev/null
+++ b/resources/styles/test/info
@@ -0,0 +1,2 @@
+
+description: A test style, may change often.
diff --git a/resources/styles/test/version b/resources/styles/test/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/resources/styles/test/version
@@ -0,0 +1 @@
+0
diff --git a/resources/styles/waters/info b/resources/styles/waters/info
new file mode 100644
index 0000000..05867f7
--- /dev/null
+++ b/resources/styles/waters/info
@@ -0,0 +1,11 @@
+summary: Water features
+
+# Version of the style itself
+#
+version=1.0
+
+# A longer description of the style.
+description {
+The water features style. Generates lines for rivers and the like,
+and polygons for seas, lakes, reservoirs, swamps and similar.
+}
diff --git a/resources/styles/waters/lines b/resources/styles/waters/lines
new file mode 100644
index 0000000..908f028
--- /dev/null
+++ b/resources/styles/waters/lines
@@ -0,0 +1,9 @@
+natural=coastline [0x15 resolution 12]
+
+route=ferry {add mkgmap:ferry=1} [0x1b road_class=3 road_speed=0 resolution 19]
+
+waterway=canal [0x1f resolution 21]
+waterway=drain [0x1f resolution 22]
+waterway=river [0x1f resolution 18]
+waterway=rapids|waterway=waterfall [0x1f resolution 22]
+waterway=stream [0x18 resolution 22]
diff --git a/resources/styles/waters/points b/resources/styles/waters/points
new file mode 100644
index 0000000..b830a28
--- /dev/null
+++ b/resources/styles/waters/points
@@ -0,0 +1,9 @@
+landuse=basin|landuse=reservoir [0x650f resolution 24]
+
+natural=beach [0x6604 resolution 24]
+natural=glacier [0x650a resolution 24]
+natural=spring [0x6511 resolution 24]
+natural=stream [0x6512 resolution 24]
+natural=water & name=* [0x6603 resolution 24]
+natural=waterfall | waterway=waterfall [0x6508 resolution 24]
+natural=wetland & name=* [0x6513 resolution 24]
diff --git a/resources/styles/waters/polygons b/resources/styles/waters/polygons
new file mode 100644
index 0000000..5cf6222
--- /dev/null
+++ b/resources/styles/waters/polygons
@@ -0,0 +1,12 @@
+landuse=basin|landuse=reservoir [0x3f resolution 20]
+
+natural=bay [0x3d resolution 18]
+natural=glacier [0x4d resolution 18]
+natural=marsh [0x51 resolution 20]
+natural=mud [0x51 resolution 20]
+natural=wetland [0x51 resolution 20]
+natural=water [0x3c resolution 18]
+natural=waterfall | waterway=waterfall [0x47 resolution 21]
+natural=sea [0x32 resolution 10]
+
+waterway=riverbank [0x46 resolution 20]
diff --git a/resources/styles/waters/version b/resources/styles/waters/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/resources/styles/waters/version
@@ -0,0 +1 @@
+0
diff --git a/scripts/checksum.py b/scripts/checksum.py
new file mode 100644
index 0000000..7cb3839
--- /dev/null
+++ b/scripts/checksum.py
@@ -0,0 +1,48 @@
+#
+# 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: 10 Dec 2006
+#
+
+#
+# Sets the check sum for the file. It is possible that the check sum
+# is not actually checked by anything.
+#
+
+import sys
+
+file = sys.argv[1]
+print "file is", file
+
+f = open(file)
+
+cksum = 0
+while 1:
+ block = f.read(512)
+ if not block: break
+ for c in block:
+ cksum -= ord(c)
+
+cksum = (cksum & 0xff)
+print "checksum is", cksum, hex(cksum)
+
+if cksum != 0:
+ fw = open(file, "r+b")
+ fw.seek(15)
+ print "setting checksum, please re-check afterwards"
+ ch = chr(cksum)
+ print 'chr', ord(ch)
+ fw.write(ch)
+ fw.close()
+
diff --git a/scripts/download/README b/scripts/download/README
new file mode 100644
index 0000000..e31cf4b
--- /dev/null
+++ b/scripts/download/README
@@ -0,0 +1,5 @@
+
+These scripts are used to create the download page on
+the mkgmap website.
+
+For reference - they have no general use.
diff --git a/scripts/download/buildwatch b/scripts/download/buildwatch
new file mode 100755
index 0000000..7511e8a
--- /dev/null
+++ b/scripts/download/buildwatch
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+BIN=/home/steve/scripts/mkgmap
+
+while :
+do
+ redis-cli blpop svn:branch-build-trigger 0
+ if [ "$?" != "0" ]; then
+ echo redis connection failed
+ sleep 60
+ continue
+ fi
+
+ (
+ $BIN/mksnapbranches mkgmap
+ $BIN/mksnapbranches splitter
+ ) | mail -s 'Branch builds' steve at parabola.me.uk
+ sleep 120
+done
diff --git a/scripts/download/mkdoc b/scripts/download/mkdoc
new file mode 100755
index 0000000..e8ca1ed
--- /dev/null
+++ b/scripts/download/mkdoc
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# Create the documentation
+#
+# We will be in the root directory of a just-built distribution
+# when called normally.
+#
+
+(
+cd doc
+
+if [ -f makefile -o -f Makefile ]; then
+ make install
+fi
+
+for f in *.txt
+do
+ export PYTHONPATH=$HOME/www/mkgmap.org.uk
+ python -m wiki.main -t text $f > ../dist/doc/$f
+done
+
+DOC=~/www/web/mkgmap/content/doc
+WEB_DOC_PDF=~/www/mkgmap.org.uk/docroot/doc/pdf
+cp *.txt $DOC
+cp styles/style-manual.pdf $WEB_DOC_PDF
+)
diff --git a/scripts/download/mksnap b/scripts/download/mksnap
new file mode 100755
index 0000000..ea1123b
--- /dev/null
+++ b/scripts/download/mksnap
@@ -0,0 +1,136 @@
+#!/bin/bash
+
+PROGDIR=$(dirname $(readlink -f $0))
+ANT_JAVAC_TARGET="-Dant.build.javac.target=1.6 -Dant.build.javac.source=1.6"
+
+export JAVA_HOME=/opt/java
+export PATH=$JAVA_HOME/bin:/opt/jars/apache-ant-1.8.2/bin:/opt/jars/apache-ant-1.7.1/bin:/usr/bin:/bin:/usr/local/bin:$PROGDIR
+export LANG=en_GB.UTF-8
+
+source mksnapfuncs
+
+typeset -i VERSION
+while getopts "r:d:b:" c
+do
+ case $c in
+ b) BRANCH=$OPTARG
+ if [ $OPTARG != 'trunk' ];then
+ BRANCH_URL=branches/$OPTARG
+ fi
+ ;;
+ r) VERSION=$OPTARG;;
+ d) SNAPDIR=$OPTARG;;
+ esac
+done
+shift $[OPTIND-1]
+
+PRODUCT=$1
+if [ "$PRODUCT" = "" ]; then
+ echo Usage: "mksnap [-d dir] [-b branch] [-r vers] <product>"
+ exit
+fi
+
+SVN=http://svn.mkgmap.org.uk/$PRODUCT
+BRANCH=${BRANCH:-trunk}
+BRANCH_URL=${BRANCH_URL:-trunk}
+SNAPDIR=${SNAPDIR:-$HOME/www/mkgmap.org.uk/docroot/download}
+
+#
+# Get the real highest revision that was commited to the given branch
+# that is less that the given revision.
+# If no revision given then get the latest on the branch.
+#
+CHECK_URL=$SVN/$BRANCH_URL
+if [ "$VERSION" != "" ]; then
+ CHECK_URL="${CHECK_URL}@$VERSION"
+fi
+VERSION=$(svn log --xml --limit 1 $CHECK_URL 2> /dev/null | \
+ sed -n '/<logentry/N;/\n/s/.*revision="\([0-9]*\)".*/\1/p')
+
+RELNAME=$PRODUCT-$BRANCH-r$VERSION
+RELNAME=${RELNAME/-trunk/}
+
+TARGET=$SNAPDIR/$RELNAME.tar.gz
+TARGET_ZIP=$SNAPDIR/$RELNAME.zip
+TARGET_JAR=$SNAPDIR/$RELNAME.jar
+TARGET_SRC=$SNAPDIR/$RELNAME-src.tar.gz
+TARGET_SRC_ZIP=$SNAPDIR/$RELNAME-src.zip
+
+BUILD_DIST=1
+BUILD_TARGETS='dist'
+
+# No standard between different products, so set the build target
+# appropriate to the product.
+case "$PRODUCT" in
+display)
+ BUILD_DIST=0
+ BUILD_TARGETS='dist'
+ ;;
+mkgmap)
+ BUILD_TARGETS='dist obtain-test-input-files test'
+ ;;
+splitter)
+ BUILD_TARGETS='dist run.tests'
+ ;;
+esac
+
+# On a branch we do not run the tests, anything goes!
+if [ $BRANCH != 'trunk' ]; then
+ BUILD_TARGETS='dist'
+fi
+
+if [ ! -f $TARGET ]; then
+ echo Rebuilding
+ cd /usr/tmp
+
+ BUILD_DIR=/usr/tmp/build-mkgmap/$RELNAME
+ mkdir -p $(dirname $BUILD_DIR)
+ trap "rm -rf $BUILD_DIR" 0
+
+ rm -rf $BUILD_DIR # make sure it does not exist before export
+ svn export -q -r$VERSION $SVN/$BRANCH_URL $BUILD_DIR
+
+ cd $BUILD_DIR
+
+ # Create version files to record the version that is being built
+ if [ -d resources ]; then
+ echo "svn.version: $VERSION" > resources/$PRODUCT-version.properties
+ echo "build.timestamp: $(date -Iseconds)" >> resources/$PRODUCT-version.properties
+ fi
+
+ # Create a pure source distribution as tar
+ tar czCf $(dirname $BUILD_DIR) $TARGET_SRC $RELNAME
+
+ # Create source as zip
+ (cd $(dirname $BUILD_DIR); zip -r $TARGET_SRC_ZIP $RELNAME) > /dev/null
+
+ if [ "$BUILD_DIST" = 1 ]; then
+ echo BUILDING TARGET
+ ant $ANT_JAVAC_TARGET -Dhave.version=1 $BUILD_TARGETS || {
+ redis-cli lpush svn:build "failed:$PRODUCT:$BRANCH:$VERSION"
+ exit 1
+ }
+
+ if [ -x $PROGDIR/mkdoc ]; then
+ $PROGDIR/mkdoc $PRODUCT
+ fi
+
+ # Save the jar file separately
+ cp dist/$PRODUCT.jar $TARGET_JAR
+
+ mv dist $RELNAME
+ tar czf $TARGET $RELNAME
+ zip -r $TARGET_ZIP $RELNAME
+
+ redis-cli lpush svn:build "success:$PRODUCT:$BRANCH:$VERSION"
+ fi
+fi
+
+cd $SNAPDIR
+
+if [ "$BUILD_DIST" = 1 ]; then
+ mksnap_setdate $VERSION $TARGET $TARGET_ZIP \
+ $TARGET_SRC $TARGET_SRC_ZIP \
+ $TARGET_JAR
+fi
+
diff --git a/scripts/download/mksnapbranches b/scripts/download/mksnapbranches
new file mode 100755
index 0000000..b1e14f7
--- /dev/null
+++ b/scripts/download/mksnapbranches
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+PROGDIR=$(dirname $(readlink -f $0))
+
+export JAVA_HOME=/opt/java
+PATH=$JAVA_HOME/bin:/opt/jars/apache-ant-1.7.1/bin:/usr/bin:/bin:/usr/local/bin:$PROGDIR
+
+typeset -i VERSION
+typeset -i MIN_VERSION
+
+while getopts "d:" c
+do
+ case $c in
+ d) SNAPDIR=$OPTARG;;
+ esac
+done
+shift $[OPTIND-1]
+
+PRODUCT=$1
+if [ "$PRODUCT" = "" ]; then
+ echo Usage: "mksnapbranches [-d dir] [-r vers] <product>"
+ exit
+fi
+
+source mksnapfuncs
+
+export LANG=en_GB.UTF-8
+
+SVN=http://svn.mkgmap.org.uk/$PRODUCT
+SNAPDIR=${SNAPDIR:-$HOME/www/mkgmap.org.uk/docroot/download}
+
+# Get the commit time of the given path
+svn_get_time() {
+ typeset time
+ time=$(svn log --xml --limit 1 $SVN/$1 2> /dev/null | sed \
+ -n -e 's/<date>\(.*\)<\/date>/\1/;s/T/ /;s/Z/+0000/p'
+ )
+ date -d"$time" +%s
+}
+
+# We ignore all branches older than 90 days
+MIN_TIME=$(svn_get_time trunk)
+((MIN_TIME=MIN_TIME - 3600*24*90))
+
+BRANCHES=$(svn ls $SVN/branches)
+for branch in $BRANCHES
+do
+ BRANCH=${branch%/}
+ BRANCH_TIME=$(svn_get_time branches/$BRANCH)
+
+ if [ $BRANCH_TIME -lt $MIN_TIME ]; then
+ echo Too old ignoring $BRANCH
+ continue
+ fi
+
+ echo Building $BRANCH
+ redis-cli lpush svn:build build:$PRODUCT:$BRANCH:
+done
diff --git a/scripts/download/mksnapclean b/scripts/download/mksnapclean
new file mode 100755
index 0000000..30a0288
--- /dev/null
+++ b/scripts/download/mksnapclean
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+PROGDIR=$(dirname $(readlink -f $0))
+PATH=/bin:/usr/bin:/usr/local/bin:$PROGDIR
+
+SNAPDIR=/home/steve/www/mkgmap.org.uk/docroot/download
+
+while getopts "d:" c
+do
+ case $c in
+ d) SNAPDIR=$OPTARG;;
+ esac
+done
+shift $[OPTIND-1]
+
+PRODUCT=$1
+USEFILE=/tmp/$PRODUCT-used
+SVN=http://svn.mkgmap.org.uk/$PRODUCT
+
+if [ $PRODUCT = "" ]; then
+ echo Usage: $0 [-d snapshot-dir] product
+ exit 1
+fi
+
+source mksnapfuncs
+
+# Check file exists and has some lines in it
+if [ ! -f $USEFILE ]; then
+ echo No usage file $USEFILE
+ exit 1
+fi
+if [ $(wc -l < $USEFILE) -lt 1 ]; then
+ echo Not enough lines in usage file
+ exit 1
+fi
+
+# Check that we are not working with old data
+if (( $(stat -c %Y $USEFILE) < $(date +%s) - 1060 )); then
+ echo The $USEFILE was generated too long ago
+ exit 1
+fi
+
+cd $SNAPDIR
+for f in $(ls ${PRODUCT}-r*.zip)
+do
+ base=${f%.zip}
+ echo -n $base ' '
+ grep -q $f $USEFILE
+
+ case $? in
+ 0)
+ echo 'ok'
+ version=${base#*-r}
+ mksnap_setdate $version ${base}.tar.gz
+ ;;
+ 1) rm ${base}[.-]*
+ echo 'removed'
+ ;;
+ esac
+done
+
+mksnapindex -d $SNAPDIR $PRODUCT
diff --git a/scripts/download/mksnapfuncs b/scripts/download/mksnapfuncs
new file mode 100644
index 0000000..a82e040
--- /dev/null
+++ b/scripts/download/mksnapfuncs
@@ -0,0 +1,17 @@
+
+mksnap_setdate() {
+(
+ # Must pass the .tar.gz form of the name
+ version=$1
+ shift
+
+ cd $SNAPDIR
+ date=$(svn log --xml -r $version $SVN 2> /dev/null \
+ | sed -n -e 's/<date>\(.*\)<\/date>/\1/p')
+
+ for file in "$@"; do
+ touch -d "${date%T*} ${date#*T}" ${file}
+ done
+)
+}
+
diff --git a/scripts/download/mksnapindex b/scripts/download/mksnapindex
new file mode 100755
index 0000000..254e327
--- /dev/null
+++ b/scripts/download/mksnapindex
@@ -0,0 +1,110 @@
+#!/bin/bash
+
+PROGDIR=$(dirname $(readlink -f $0))
+
+while getopts "r:d:" c
+do
+ case $c in
+ d) SNAPDIR=$OPTARG;;
+ esac
+done
+shift $[OPTIND-1]
+
+PRODUCT=$1
+if [ "$PRODUCT" = "" ]; then
+ echo Usage: "mksnap [-d dir] <product>"
+ exit
+fi
+
+SNAPDIR=${SNAPDIR:-$HOME/www/mkgmap.org.uk/docroot/download}
+
+print_product_line() {
+ file=$1
+ set $file $(ls -Lhtl $file| sed 's/ */ /' | sed 's/ \+/ /g' | cut -d ' ' -f5-9)
+
+ case $file in
+ *-src.tar.gz)
+ return;;
+ *latest*)
+ fileref=$(ls -l $file | cut -d' ' -f11)
+ ;;
+ *)
+ fileref=$file
+ ;;
+ esac
+
+ name=${file%.tar.gz}
+ refbase=${fileref%.tar.gz}
+
+ if [ -f $file ]; then
+ echo '<tr>'
+ echo "<td>$name</td>"
+ case $name in
+ *.jar)
+ echo "<td> <a href='$fileref'>[.jar]</a> "
+ ;;
+ *)
+ echo "<td> <a href='$fileref'>[.tar.gz]</a> "
+ echo "<a href='$refbase.zip'>[.zip]</a> "
+ echo "<a href='${refbase}-src.tar.gz'>[src]</a> </td>"
+ ;;
+ esac
+ echo "<td> </td>"
+ echo "<td>$3 $4</td>"
+ echo "<td>$5</td>"
+ echo "<td> </td>"
+ echo "<td>$2</td>"
+ echo '</tr>'
+ fi
+}
+
+cd $SNAPDIR
+
+sed -e "s/%(PRODUCT)s/$PRODUCT/" $PROGDIR/skel-top > $PRODUCT.html
+
+(
+#print_product_line $PRODUCT-latest.tar.gz
+for file in $(ls -t)
+do
+ case $file in
+ $PRODUCT-r*tar.gz)
+ print_product_line $file
+ ;;
+ *)
+ ;;
+ esac
+done
+) >> $PRODUCT.html
+
+if [ $(echo *.jar | wc -c) -gt 6 ] ; then
+ echo '</table><h1>Branch builds</h1>
+ <p>These jar files are latest builds of recent development branches.
+ They are useful if you want to quickly test a branch without having
+ obtain and build it. The source code is available via subversion.
+ <p>As this is an automatic process, some of the branches might be
+ already merged with the main line, or abandoned and of course they
+ may not work.
+ <table>
+ ' >> $PRODUCT.html
+
+ for file in $(ls -t)
+ do
+ case $file in
+ $PRODUCT-*jar)
+ print_product_line $file $(ls -Ltl $file| sed 's/ */ /' | sed 's/ \+/ /g' | cut -d ' ' -f6-9,11-)
+ ;;
+ *)
+ ;;
+ esac
+ done >> $PRODUCT.html
+else
+ echo '<tr><td></td></tr>' >> $PRODUCT.html
+fi
+
+if [ $PRODUCT = mkgmap ]; then
+ PRODUCT_AD=9104507573
+else
+ PRODUCT_AD=0835769470
+fi
+
+sed -e "s/%(PRODUCT_AD)s/$PRODUCT_AD/" $PROGDIR/skel-bot >> $PRODUCT.html
diff --git a/scripts/download/recentversions b/scripts/download/recentversions
new file mode 100755
index 0000000..6887564
--- /dev/null
+++ b/scripts/download/recentversions
@@ -0,0 +1,32 @@
+cd /var/log/nginx
+
+MIN=8
+
+while getopts "n:" c
+do
+ case $c in
+ n) MIN=$OPTARG;;
+ esac
+done
+shift $[$OPTIND-1]
+
+for PRODUCT in mkgmap splitter
+do
+tail -12000 mkgmap.org.uk | egrep $PRODUCT-'(r|latest).* 200 ' | awk "{
+ s = match(\$7, /[^/]*\$/);
+ s = substr(\$7, s);
+ sub(\"$PRODUCT-r\", \"\", s);
+ sub(\"-src\", \"\", s);
+ sub(\".tar.gz\", \"\", s);
+ sub(\".zip\", \"\", s);
+ print s;
+}" | sort -n | uniq -c | awk "
+ /oute-/ {next;}
+ /$PRODUCT/ {next;}
+ {
+ if (\$1 > $MIN)
+ printf \"$PRODUCT-r%s.zip %d\n\", \$2, \$1
+ }
+" > /tmp/$PRODUCT-used
+
+done
diff --git a/scripts/download/skel-bot b/scripts/download/skel-bot
new file mode 100644
index 0000000..5fb9f1f
--- /dev/null
+++ b/scripts/download/skel-bot
@@ -0,0 +1,45 @@
+</table>
+</div>
+</div>
+
+<div id="rightbar">
+<div id="right-inner">
+
+ <div class="text-links">
+ <script type="text/javascript"><!--
+ google_ad_client = "ca-pub-0485692618255663";
+ /* mkgmap files */
+ google_ad_slot = "%(PRODUCT_AD)s";
+ google_ad_width = 160;
+ google_ad_height = 600;
+ //-->
+ </script>
+ <script type="text/javascript"
+ src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
+ </script>
+ </div>
+
+
+<div style="margin-top: 50px">
+ <a href="http://www.jetbrains.com/idea/" style="position:
+ relative;display:block; width:127px; height:37px; border:0;
+ margin:0;padding:0;text-decoration:none;text-indent:0;"><span
+ style="margin: 0;padding: 0;position: absolute;top: 0;left: 33px;font-size:
+ 10px;cursor:pointer; background-image:none;border:0;color: #acc4f9;
+ font-family: trebuchet ms,arial,sans-serif;font-weight: normal;">Developed
+ with</span><img src="http://www.jetbrains.com/idea/opensource/img/all/banners/idea125x37_blue.gif"
+ alt="The best Java IDE" border="0"/></a>
+</div>
+
+</div>
+</div>
+
+</div>
+
+<div id="footer">
+ Copyright © 2012 Steve Ratcliffe
+</div>
+
+
+</body>
+</html>
diff --git a/scripts/download/skel-top b/scripts/download/skel-top
new file mode 100644
index 0000000..e3148da
--- /dev/null
+++ b/scripts/download/skel-top
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title> mkgmap </title>
+ <link rel="stylesheet" type="text/css" href="/static/css/bundle.css">
+ <script src="/static/js/bundle.js" type="text/javascript"></script>
+ <link rel="alternate" type="application/atom+xml" title="mkgmap - Atom" href="http://www.mkgmap.org.uk/feed/atom">
+ <link rel="alternate" type="application/rss+xml" title="mkgmap - Rss" href="http://www.mkgmap.org.uk/feed/rss">
+
+</head>
+<body>
+<div id="heading">
+ <img src="/static/img/logo.png" alt="logo">
+ <img src="/static/img/separator.png" alt="separator">
+</div>
+
+<div id="page">
+
+<div id="sidenav">
+
+<ul>
+<li><a href="/">Home</a></li>
+<li><a href="/news/">News</a></li>
+<li><a href="/doc/index.html">Documentation</a></li>
+<li class="active"><a href="/download/mkgmap.html">Download</a></li>
+<li class="active subnav"><a href="/download/mkgmap.html">mkgmap</a></li>
+<li class="active subnav"><a href="/download/splitter.html">splitter</a></li>
+<li><a href="/develop.html">Development</a></li>
+<li> <hr> </li>
+</ul>
+
+</div>
+
+<div id="maincontent" >
+<div id="main-inner">
+
+
+<h1>Download %(PRODUCT)s</h1>
+<p>
+These snapshots are created automatically each night when there are changes.
+Each version can be downloaded in tar or zip format as well as its source code.
+The dates are the time that the version was created and can be used to
+judge the freshness of the release, you would normally download the top
+one unless you know it has a problem.
+<table>
+<col span="2">
+<col width="20px">
diff --git a/scripts/gmapi-builder.py b/scripts/gmapi-builder.py
new file mode 100755
index 0000000..0e2e09d
--- /dev/null
+++ b/scripts/gmapi-builder.py
@@ -0,0 +1,578 @@
+#!/usr/bin/python
+
+"""
+ Simple convertor for files in Garmins MapSource format to the directory
+ structure RoadTrip for OS X uses.
+
+ Copyright (c) 2009, Berteun Damman
+ 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 the OpenStreetMap Project 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 AUTHOR ''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 THE AUTHOR 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.
+
+ First of all: This program is not a replacement for Garmins MapConverter.exe.
+ It was specifically written to convert a bunch of .IMG and .TDB files of
+ the OpenStreetmap project to a .gmapi directory structure which can be
+ installed under OS X. As such it is geared towards the versions of the format
+ used by OSM. This means it will most certain not work on non-OSM files (this
+ has not been tested in anyway!).
+
+ The conversion itself is fairly simple, under Windows you have:
+ * Registry entries indicating the TDB-file, the Base Image and the Image dir,
+ and optionally a TYP file and some other types.
+ * A single TDB-file
+ * A whole collection of IMG files.
+
+ Under Mac you have:
+ * An XML file which contains the information of the Windows Register
+ * For each IMG file a directory with the same basename as the IMG-file,
+ and with the subfiles of this IMG extracted into this directory; the IMG-files
+ are in fact containers (they are similar to disk images).
+
+ This program does the conversion.
+"""
+
+import logging
+import optparse
+import os
+import shutil
+import struct
+import sys
+import StringIO
+
+# Logger setup
+logging.NORMAL = logging.INFO + 5
+logging.addLevelName(logging.NORMAL, 'NORMAL')
+logger = logging.getLogger('logger')
+logger.setLevel(logging.DEBUG)
+
+# Program options can increase the verbosity
+cons = logging.StreamHandler(sys.stdout)
+cons.setLevel(logging.NORMAL)
+logger.addHandler(cons)
+
+def error_exit(msg):
+ sys.exit(msg)
+
+def write(msg, *args, **kwargs):
+ logger.log(logging.NORMAL, msg, *args, **kwargs)
+
+class EndOfFile(IOError):
+ pass
+
+class FileFormatError(Exception):
+ pass
+
+# Auxiliary functions that make life easier to read bytes, shorts, int and
+# so on from a file.
+def getX(length, fmt):
+ def get(f):
+ v = f.read(length)
+ if len(v) < length:
+ raise EndOfFile("End of file reached on '%s'." % f.name)
+ return struct.unpack(fmt, v)[0]
+ return get
+
+# See the documentation of struct for an explanation of these
+# format specifiers. Notably, the < indicates little endian
+# format.
+get_short = getX(2, '<h')
+get_ushort = getX(2, '<H')
+get_int = getX(4, '<i')
+get_uint = getX(4, '<I')
+get_byte = getX(1, 'B')
+
+def get_str(f):
+ c = f.read(1)
+ s = ''
+ while c != '\x00':
+ s += c
+ c = f.read(1)
+ return s
+
+def get_nstr(f, n):
+ c = f.read(n)
+ if len(c) < n:
+ raise EndOfFile("End of file reached on '%s'." % f.name)
+ s = struct.unpack('%ds' % n, c)[0]
+ return s
+
+# For the 4.X TDB file format, 24bit integers are used; already here
+# for the future.
+#def get_middle(f):
+# l = list(f.read(3))
+# if len(l) < 3:
+# raise EndOfFile("End of file reached on '%s'." % f.name)
+# sign, l[2] = l[2] >> 7, l[2] & 0x7F
+# v = -sign * (1<<23) + (l[2] << 16) + (l[1] << 8) + l[0]
+
+def todegrees(n):
+ return (n * 360.0) / (2 ** 32)
+
+# A TDB file consists of a sequence of blocks, the format of each
+# block is simply:
+# 1 Byte: Block ID
+# 2 Bytes: Block length (l):
+# l Bytes: Data
+
+class Block(object):
+ def __init__(self, f):
+ self.bid = get_byte(f)
+ self.length = get_ushort(f)
+ self.data = StringIO.StringIO(f.read(self.length))
+ if len(self.data.buf) < self.length:
+ raise EndOfFile("End of file reached early on '%s'." % f.name)
+
+class TDBFile(object):
+ """This represents the TDBFile with its known blocks, such as
+ the header, copyright block, overview block and detailed maps."""
+ def __init__(self, filename):
+ self.f = open(filename, 'rb')
+ self.header_block = None
+ self.copyright_block = None
+ self.overview_block = None
+ self.trademark_block = None
+ self.detail_blocks = []
+ self._parse()
+
+ def _parse(self):
+ """Dispatches subparsers for *known* blocks"""
+ block_parsers = {
+ 0x50: self.parse_header,
+ 0x44: self.parse_copyright,
+ 0x42: self.parse_overview,
+ 0x4C: self.parse_detail,
+ 0x52: self.parse_trademark,
+ }
+
+ while self.f.read(1):
+ self.f.seek(-1, 1)
+ b = Block(self.f)
+ if b.bid in block_parsers:
+ block_parsers[b.bid](b)
+ else:
+ logger.info('Unknown Block: %02X, length: %d, %s' % (b.bid, b.length, repr(b.data.buf)))
+ self.f.close()
+
+ def parse_header(self, block):
+ hb = {}
+ hb['Product ID'] = get_ushort(block.data)
+ hb['Family ID'] = get_ushort(block.data)
+
+ tdb_version = get_ushort(block.data)
+ hb['TDB Major Version'] = tdb_version / 100
+ hb['TDB Minor Version'] = tdb_version % 100
+ hb['TDB Version'] = "%d.%02d" % (hb['TDB Major Version'], hb['TDB Minor Version'])
+
+ hb['Map Series'] = get_str(block.data)
+
+ prod_version = get_ushort(block.data)
+ hb['Product Major Version'] = prod_version / 100
+ hb['Product Minor Version'] = prod_version % 100
+ hb['Product Version'] = "%d.%02d" % (hb['Product Major Version'], hb['Product Minor Version'])
+
+ hb['Map Family'] = get_str(block.data)
+
+ self.header_block = hb
+
+ def parse_copyright(self, block):
+ cl = []
+ while block.data.pos < len(block.data.buf):
+ copyright_code = get_byte(block.data)
+ where_code = get_byte(block.data)
+ extra = get_short(block.data)
+ copyright_string = get_str(block.data)
+ if copyright_code == 0x00:
+ cl.append({'Source': copyright_string.decode('latin1').encode('utf-8')})
+ elif copyright_code == 0x06:
+ cl.append({'Copyright': copyright_string.decode('latin1').encode('utf-8')})
+ elif copyright_code == 0x07:
+ cl.append({'Bitmap': copyright_string, 'Scale factor': extra})
+ else:
+ cl.append({'Unknown (%02X)' % copyright_code: copyright_string, 'Extra': extra})
+ self.copyright_block = cl
+
+ def parse_overview(self, block):
+ ob = {}
+ ob['Map Number'] = get_uint(block.data)
+ ob['Parent Map'] = get_uint(block.data)
+ ob['Latitude North'] = "%7.4f" % todegrees(get_int(block.data))
+ ob['Longitude East'] = "%7.4f" % todegrees(get_int(block.data))
+ ob['Latitude South'] = "%7.4f" % todegrees(get_int(block.data))
+ ob['Longitude West'] = "%7.4f" % todegrees(get_int(block.data))
+ ob['Description'] = get_str(block.data)
+ self.overview_block = ob
+
+ def parse_detail(self, block):
+ db = {}
+ db['Map Number'] = get_uint(block.data)
+ db['Parent Map'] = get_uint(block.data)
+ db['Latitude North'] = "%7.4f" % todegrees(get_int(block.data))
+ db['Longitude East'] = "%7.4f" % todegrees(get_int(block.data))
+ db['Latitude South'] = "%7.4f" % todegrees(get_int(block.data))
+ db['Longitude West'] = "%7.4f" % todegrees(get_int(block.data))
+ db['Description'] = get_str(block.data)
+ # Unknown
+ block.data.seek(4, 1)
+ # Could it be that these values have changed in v4?
+ db['RGN Size'] = get_uint(block.data)
+ db['TRE Size'] = get_uint(block.data)
+ db['LBL Size'] = get_uint(block.data)
+ self.detail_blocks.append(db)
+
+ def parse_trademark(self, block):
+ tb = {}
+ block.data.seek(1, 1)
+ tb['Trademark'] = get_str(block.data)
+ self.trademark_block = tb
+
+ def print_header(self):
+ for f in ['TDB Version', 'Product ID', 'Family ID', 'Map Series', 'Map Family', 'Product Version']:
+ write("%-20s%s" % (f + ':', str(self.header_block[f])))
+
+ def print_copyright(self):
+ for c in self.copyright_block:
+ write('\n '.join(["%-20s%s" % (f + ":", str(c[f])) for f in c]))
+
+ def print_trademark(self):
+ write("%-20s%s" % ('Trademark:', self.trademark_block['Trademark'].encode('utf-8')))
+
+ def print_overview(self):
+ logger.info('Overview map:')
+ for f in ['Map Number', 'Parent Map', 'Latitude North', 'Longitude East',
+ 'Latitude South', 'Longitude West', 'Description']:
+ logger.info(" %-20s%s" % (f + ':', str(self.overview_block[f])))
+
+ def print_detail_blocks(self):
+ logger.debug('Detailed maps:')
+ for db in self.detail_blocks:
+ logger.debug(" %-20s%s" % ('Map Number:', str(db['Map Number'])))
+ logger.debug(" %-20s%s" % ('Parent Map:', str(db['Parent Map'])))
+ logger.debug(" %-20s%s" % ('Description:', str(db['Description'])))
+ logger.debug(" N: %s, S: %s, W: %s, E: %s" % (db['Latitude North'], db['Latitude South'],
+ db['Longitude West'], db['Longitude East']))
+ logger.debug(" RGN: %d, TRE: %d, LBL: %d" % (db['RGN Size'], db['TRE Size'], db['LBL Size']))
+ logger.debug("")
+
+
+ def print_dump(self):
+ """Gives a short textual description of the data."""
+ if self.header_block:
+ self.print_header()
+ else:
+ logger.warning('TDB file contains no header block.')
+ write("")
+ if self.copyright_block:
+ self.print_copyright()
+ else:
+ logger.info('TDB file contains no copyright block.')
+ write("")
+ if self.trademark_block:
+ self.print_trademark()
+ write("")
+ else:
+ logger.info('TDB file contains no trademark block.')
+ logger.info("")
+ if self.overview_block:
+ self.print_overview()
+ else:
+ logger.warning('TDB file contains no overview map.')
+ logger.info("")
+ if self.detail_blocks:
+ self.print_detail_blocks()
+ else:
+ logger.warning('TDB file contains no detail blocks.')
+
+class SubFile(object):
+ """Represents a subfile in the IMG file
+
+ The image is like a FAT file system; for each file it lists
+ the sectors on which a part of the file can be found. If the
+ file is larger than 240 sectors, it split into parts.
+ """
+ def __init__(self, name, extension):
+ self.name = name
+ self.extension = extension
+ self.fullname = '%s.%s' % (name, extension)
+ self.size = None
+ self.part_list = []
+
+ def add_part(self, part, sectors):
+ self.part_list.append((part, sectors))
+
+ def merge_parts(self):
+ """Merges all the sectors in the parts into
+ a large (sorted) sector list which can be used to dump the file.
+ """
+ self.part_list.sort()
+ for n in range(len(self.part_list)):
+ if self.part_list[n][0] != n:
+ raise FileFormatError('Missing part: %d of %s in IMG-file.' % (n, self.fullname))
+ self.sector_list = []
+ for (n, sl) in self.part_list:
+ self.sector_list.extend(sl)
+
+class IMGFile(object):
+ """Very crude representation of the IMG file
+
+ We only want to extract the subfiles, so we ignore lots of infomation in this file."""
+ def __init__(self, filename):
+ self.f = open(filename)
+ self.basename = os.path.basename(filename[:filename.rfind('.')])
+ self._check_file()
+ self.block_size = self._get_block_size()
+ self._read_files()
+
+ def _check_file(self):
+ first_b = get_byte(self.f)
+ if first_b != 0x00:
+ raise FileFormatError("%s is not a Garmin IMG file, or it is encrypted." % self.f.name)
+ self.f.seek(0x10)
+ if get_str(self.f) != "DSKIMG":
+ raise FileFormatError("%s is not a Garmin IMG file, or is an unknown version." % self.f.name)
+ self.f.seek(0x41)
+ if get_str(self.f) != "GARMIN":
+ raise FileFormatError("%s is not a Garmin IMG file, or is an unknown version." % self.f.name)
+
+ def _get_block_size(self):
+ # Probably 512
+ self.f.seek(0x61)
+ e1 = get_byte(self.f)
+ e2 = get_byte(self.f)
+ bs = 1<<(e1 + e2)
+ return bs
+
+ def _read_files(self):
+ """Scans the FAT for files"""
+ files = {}
+ file_count = 0
+ while True:
+ # FAT starts at 0x600, each entry is
+ # exactly 512 bytes, padded if necessary.
+ self.f.seek(0x600 + file_count * 512)
+ if get_byte(self.f) == 0:
+ break
+
+ filename = get_nstr(self.f, 8)
+ file_type = get_nstr(self.f, 3)
+ size = get_uint(self.f)
+
+ self.f.seek(1, 1)
+ part_no = get_byte(self.f)
+ fullname ='%s.%s' % (filename, file_type)
+ self.f.seek(14, 1)
+ sector_list = []
+ for n in range(240):
+ sector_no = get_ushort(self.f)
+ if sector_no != -1:
+ sector_list.append(sector_no)
+
+ if not fullname in files:
+ files[fullname] = SubFile(filename, file_type)
+ if part_no == 0:
+ files[fullname].size = size
+
+ files[fullname].add_part(part_no, sector_list)
+ file_count += 1
+
+ for fn in files:
+ files[fn].merge_parts()
+ self.files = files
+
+ def dump(self, base_dir):
+ """Dumps the subfiles of this IMG file"""
+ output_dir = os.path.join(base_dir, self.basename)
+ os.mkdir(output_dir)
+ for sfn in self.files:
+ subfile = self.files[sfn]
+ out = open(os.path.join(output_dir, subfile.fullname), 'w')
+ for s in subfile.sector_list:
+ self.f.seek(s * self.block_size)
+ out.write(self.f.read(self.block_size))
+ out.truncate(subfile.size)
+ logger.debug('Wrote: %s/%s' % (output_dir, subfile.fullname))
+ out.close()
+
+ def close(self):
+ self.f.close()
+
+ def print_info(self):
+ logger.debug("Contents of %s:" % (self.basename))
+ for fn in self.files:
+ logger.debug(" %s: Size: %d" % (self.files[fn].fullname, self.files[fn].size))
+
+def parse_options(option_list):
+ usage = 'usage: %prog: [-h] [-o <outputdir>] [-s <typfile>] -t <tdbfile> -b <base-image> <file1.img> [<file2.img> [<file3.img> ... ]]'
+ oparser = optparse.OptionParser(usage=usage)
+ oparser.add_option("-o", "--output", dest="output", default="./",
+ help="specify the output directory for the .gmapi folder")
+ oparser.add_option("-t", "--tdbfile", dest="tdbfile",
+ help="the name of this mapset's TDB file")
+ oparser.add_option("-b", "--baseimg", dest="baseimg",
+ help="the name of the base img")
+ oparser.add_option("-i", "--idxfile", dest="mdx",
+ help="the name of this mapset's index (mdx) file")
+ oparser.add_option("-m", "--mdrfile", dest="mdr",
+ help="the name of this mapset's MDR file")
+ oparser.add_option("-v", "--verbose", dest="verbosity",
+ action="count", help="verbosity")
+ oparser.add_option("-s", "--style", dest="style",
+ help="an optional style-file (TYP)")
+ oparser.add_option("-d", "--dryrun", dest="dryrun",
+ action="store_true", default=False)
+
+ (options, args) = oparser.parse_args(option_list)
+
+ if options.verbosity:
+ if options.verbosity == 1:
+ cons.setLevel(logging.INFO)
+ elif options.verbosity > 1:
+ cons.setLevel(logging.DEBUG)
+
+ if not options.tdbfile:
+ oparser.print_help()
+ error_exit("\nError: You must specify a TDB-file with -t!")
+
+ if not options.baseimg:
+ oparser.print_help()
+ error_exit("\nError: You must specify the base image with -b!")
+ elif not os.path.isfile(options.baseimg):
+ error_exit("\nError: Baseimage not found.")
+
+ if options.style:
+ if not os.path.isfile(options.style):
+ error_exit("\nError: Style file not found.")
+
+ if options.mdx:
+ if not os.path.isfile(options.mdx):
+ error_exit("\nError: Index (mdx) file not found.")
+
+ if options.mdr:
+ if not os.path.isfile(options.mdr):
+ error_exit("\nError: MDR file not found.")
+
+ if not args:
+ oparser.print_help()
+ error_exit('No filenames specified!')
+
+ return (options, args)
+
+def prepare_output_dir(tdbfile, options):
+ dir_prefix = tdbfile.header_block['Map Series']
+ if not os.path.isdir(options.output):
+ error_exit('Output dir does not exist')
+ gmapi = os.path.join(options.output, dir_prefix + '.gmapi')
+ gmap = os.path.join(gmapi, dir_prefix + '.gmap')
+ if os.path.exists(gmapi):
+ logger.info("Removing existing file '%s' recursively" % gmapi)
+ if os.path.isdir(gmapi):
+ shutil.rmtree(gmapi)
+ else:
+ os.unlink(gmapi)
+ if os.path.exists(gmapi):
+ error_exit("Could not remove existing '%s', please do so yourself, or specify another output dir.")
+ # This directory is empty indeed
+ os.mkdir(gmapi)
+ os.mkdir(gmap)
+ return gmap
+
+def write_xml_file(tdbfile, options, output_dir):
+ def write_field(field, value, indent):
+ f.write('%s<%s>%s</%s>\n' % (indent * ' ', field, value, field))
+ f = open(os.path.join(output_dir, 'Info.xml'), 'w')
+ f.write('<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n')
+ f.write('<MapProduct xmlns="http://www.garmin.com/xmlschemas/MapProduct/v1">\n\n')
+ write_field('Name', tdbfile.header_block['Map Family'], 1)
+ f.write('\n')
+ write_field('DataVersion', str(tdbfile.header_block['Product Major Version']) + ("%02d" % tdbfile.header_block['Product Minor Version']), 1)
+ f.write('\n')
+ write_field('DataFormat', 'Original', 1)
+ f.write('\n')
+ # It appears the windows converter does not write the family ID
+ # if it is zero, so neither do we!"
+ if tdbfile.header_block['Family ID'] > 0:
+ write_field('ID', tdbfile.header_block['Family ID'], 1)
+ f.write('\n')
+ if options.mdx:
+ write_field('IDX', os.path.basename(options.mdx), 1)
+ f.write('\n')
+ if options.mdr:
+ mdr = os.path.basename(options.mdr)
+ mdr = mdr[:mdr.rfind('.')]
+ write_field('MDR', mdr, 1)
+ f.write('\n')
+ if options.style:
+ write_field('TYP', os.path.basename(options.style), 1)
+ f.write('\n')
+ f.write(' <SubProduct>\n')
+ write_field('Name', tdbfile.header_block['Map Series'], 2)
+ write_field('ID', tdbfile.header_block['Product ID'], 2)
+ baseimg = os.path.basename(options.baseimg)
+ baseimg = baseimg[:baseimg.rfind('.')]
+ write_field('BaseMap', baseimg, 2)
+ write_field('TDB', os.path.basename(options.tdbfile), 2)
+ write_field('Directory', 'OSMTiles', 2)
+ f.write(' </SubProduct>\n')
+ f.write('</MapProduct>\n')
+ f.close()
+
+if __name__ == '__main__':
+ (options, filenames) = parse_options(sys.argv[1:])
+ try:
+ tdbfile = TDBFile(options.tdbfile)
+ tdbfile.print_dump()
+ except IOError:
+ error_exit("Could not open '%s' for reading." % options.tdbfile)
+
+ if not options.dryrun:
+ output_dir = prepare_output_dir(tdbfile, options)
+ write_xml_file(tdbfile, options, output_dir)
+
+ try:
+ if not options.dryrun:
+ imgoutput = os.path.join(output_dir, 'OSMTiles')
+ os.mkdir(imgoutput)
+ shutil.copy(options.tdbfile, os.path.join(imgoutput, os.path.basename(options.tdbfile)))
+ if options.style:
+ shutil.copy(options.style, os.path.join(output_dir, os.path.basename(options.style)))
+
+ if options.mdx:
+ shutil.copy(options.mdx, os.path.join(output_dir, os.path.basename(options.mdx)))
+
+ if options.mdr:
+ mdr_file = os.path.basename(options.mdr)
+
+ for fn in filenames:
+ logger.info("Processing " + fn)
+ imgfile = IMGFile(fn)
+ imgfile.print_info()
+ if not options.dryrun:
+ if fn != options.mdr:
+ imgfile.dump(imgoutput)
+ else:
+ logger.info("MDR file")
+ imgfile.dump(output_dir)
+ imgfile.close()
+ except IOError:
+ error_exit("Could not open '%s' for reading." % fn)
+ except FileFormatError, m:
+ error_exit(m)
diff --git a/scripts/imgfile.py b/scripts/imgfile.py
new file mode 100644
index 0000000..5f6e500
--- /dev/null
+++ b/scripts/imgfile.py
@@ -0,0 +1,75 @@
+#
+# 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: 18 Dec 2006
+#
+
+import sys
+import time
+from struct import *
+
+class Imgfile:
+ def __init__(self, name):
+ self.name = name
+ self.block_size = 512
+ self.fp = open(name, 'r+')
+
+ def close(self):
+ self.fp.close()
+
+ def get_block(self, bn):
+ pos = bn * self.block_size
+ self.fp.seek(pos)
+ return self.fp.read(self.block_size)
+
+ def write_block(self, bn, bl):
+ pos = bn * self.block_size
+ self.fp.seek(pos)
+ return self.fp.write(bl)
+
+ def get_dirent(self, type):
+ for bn in xrange(2, 12):
+ bl = self.get_block(bn)
+ print bl[9:12], type
+ if bl[9:12] == type:
+ dent = Dirent(self, bl)
+ dent.dir_block_num = bn
+ return dent
+
+ def set_time(self):
+ self.fp.seek(0)
+ self.fp.read(self.block_size)
+ t = time.localtime()
+ s = pack("<HBBBBB", t[0], t[1], t[2], t[3], t[4], t[5])
+ self.fp.seek(0x39)
+ self.fp.write(s)
+
+class Dirent:
+ def __init__(self, img, block):
+ self.img = img
+ self.block = block
+
+ def get_block(self, lbn):
+ pbn = self.get_phys_block(lbn)
+ return self.img.get_block(pbn)
+
+ def write_block(self, lbn, bl):
+ pbn = self.get_phys_block(lbn)
+ self.img.write_block(pbn, bl)
+
+ def get_phys_block(self, lbn):
+ """Get the physical block number from the logical."""
+ loc = 0x20 + 2*lbn
+ pbn = unpack("<H", self.block[loc:loc+2])
+ return pbn[0]
diff --git a/scripts/make-transliteration-table.pl b/scripts/make-transliteration-table.pl
new file mode 100644
index 0000000..77df1c3
--- /dev/null
+++ b/scripts/make-transliteration-table.pl
@@ -0,0 +1,59 @@
+#!/usr/bin/env perl
+#
+# Create a transliteration table for the TableTransliterator.
+# It just gets the values from the Test::Unidecode module of perl.
+#
+# Based on a script by Ãvar Arnfjörð Bjarmason
+#
+
+use feature ':5.10';
+use strict;
+use warnings;
+
+use Unicode::UCD 'charinfo';
+use Text::Unidecode;
+use Data::Dump 'dump';
+
+#
+# Based on a script by Ãvar Arnfjörð Bjarmason
+#
+my $row = $ARGV[0];
+#if (!$row) {
+# exit 1;
+#}
+
+sub new_trans {
+ my $char_val = shift;
+
+ my $t;
+ if ($t = unidecode($char_val) and $t !~ /[?].*/) {
+ return $t;
+ }
+
+ return "?";
+}
+
+binmode STDOUT, ":utf8";
+
+say <<EOF;
+#
+# A look up table to transliterate to ascii.
+# Created with the Text::Unidecode module of perl
+#
+EOF
+
+for (my $i = 0; $i < 256; $i++) {
+ my $trans;
+
+ my $c = $row * 256 + $i;
+ $trans = new_trans(chr $c);
+
+ my $char_name = sprintf("U+%02x%02x", $row, $i);
+ if ($trans) {
+ say sprintf("%s %-12.12s # Character %c", $char_name,
+ $trans, $c);
+ } else {
+ say sprintf("%s %-12.12s # Character %c", $char_name, "?",
+ $c);
+ }
+}
diff --git a/scripts/mk_map_table.py b/scripts/mk_map_table.py
new file mode 100644
index 0000000..fc3690b
--- /dev/null
+++ b/scripts/mk_map_table.py
@@ -0,0 +1,87 @@
+#
+# File: p.py
+#
+# 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: 31 Dec 2006
+#
+
+#
+# The OSMGarminMap project contains two files that map
+# OSM map-features to the codes used in Garmin maps. This
+# script does a join between them to produce one file.
+#
+
+import sys
+import libxml2
+import csv
+
+# The list of garmin features.
+FEATURE_LIST_FILE = 'garmin_feature_list.csv'
+
+# The mapping between OSM and garmin features
+FEATURE_MAP_FILE = 'osm_garmin_map.csv'
+
+if len(sys.argv) > 2:
+ FEATURE_LIST_FILE = sys.argv[1]
+ FEATURE_MAP_FILE = sys.argv[2]
+
+features = {}
+
+def main():
+
+ # Read the garmin feature name to internal number file
+ f = open(FEATURE_LIST_FILE)
+ r = csv.reader(f, delimiter='|')
+ for line in r:
+ kind = line[0]
+ if kind[0] == '#': continue
+ key = (line[4], line[5])
+ val = (line[2], line[3])
+ try:
+ ft = features[kind]
+ except KeyError:
+ ft = {}
+ features[kind] = ft
+ ft[key] = val
+
+ # Get the osm to garmin map rules
+ f = open(FEATURE_MAP_FILE)
+ r = csv.reader(f, delimiter='|')
+ w = csv.writer(sys.stdout, delimiter='|', lineterminator='\n')
+
+ for line in r:
+ kind = line[0]
+ if kind[0] == '#': continue
+ key = (line[3], line[4])
+ res = line[5]
+ try:
+ val = features[kind][key]
+ l = []
+ l.append(kind)
+ l.append(line[1])
+ l.append(line[2])
+ l.append(val[0])
+ if val[1]:
+ l.append(val[1])
+ else:
+ l.append('')
+ l.append(res)
+ w.writerow(l)
+ except KeyError:
+ print >>sys.stderr, "No garmin entry at", kind, key
+
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/munger.py b/scripts/munger.py
new file mode 100644
index 0000000..6f6cc51
--- /dev/null
+++ b/scripts/munger.py
@@ -0,0 +1,78 @@
+#
+# 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: 18 Dec 2006
+#
+
+import sys
+from imgfile import Imgfile
+from struct import *
+
+def main():
+ myimg = Imgfile('gmapsupp.bad')
+ workimg = Imgfile('pp')
+
+ for dtype in ('LBL','RGN'):
+ ld1 = myimg.get_dirent(dtype)
+ ld2 = workimg.get_dirent(dtype)
+
+ # Get first block of the sub file itself
+ bl = ld1.get_block(0)
+ ld2.write_block(0, bl)
+
+ # So TRE is what kills it, investigate further.
+
+ # copy our first block
+ bl = myimg.get_block(0)
+ workimg.write_block(0, bl)
+
+ dtype = 'TRE'
+ ld1 = myimg.get_dirent(dtype)
+ ld2 = workimg.get_dirent(dtype)
+
+ ld2.get_block(0)
+ new = ld1.get_block(0)
+
+ # Works
+ #off = 0x10
+ #new = wrk[0:off] + new[off:]
+
+ off = 0x10
+ ch1 = pack("<H10s2BBB", 0x78, "GARMIN TRE", 1, 0, 7, 0x07)
+ new = ch1 + new[off:]
+ ld2.write_block(0, new)
+
+ workimg.set_time()
+ workimg.close()
+ #return
+
+ # Copy over the directory entries apart from the block numbers
+ for dtype in ('LBL', 'TRE', 'RGN'):
+ ld1 = myimg.get_dirent(dtype)
+ ld2 = workimg.get_dirent(dtype)
+
+ # existing block
+ bl = workimg.get_block(ld2.dir_block_num)
+
+ # transfer first 32 bytes from our file
+ bl2 = myimg.get_block(ld1.dir_block_num)
+ #bl[0:0x20] = bl2[0:0x20]
+ bl = bl2[0:0x20] + bl[0x20:]
+
+ # write it back
+ workimg.write_block(ld2.dir_block_num, bl)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/namesum.py b/scripts/namesum.py
new file mode 100644
index 0000000..c9d614b
--- /dev/null
+++ b/scripts/namesum.py
@@ -0,0 +1,73 @@
+#
+# 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: 11 Dec 2006
+#
+
+import sys
+from imgfile import Imgfile
+
+def main(name):
+
+ img = Imgfile(name)
+
+ bl = img.get_block(0)
+
+ ranges = [
+ (0x39, 0x5d),
+ (0x65, 0x84)
+ ]
+
+ sums = []
+ sn = 0
+
+ sum = 0
+ for r in ranges:
+ for i in xrange(r[0], r[1]):
+ b = ord(bl[i])
+ sum += b
+ sums.append( sum)
+ sum = 0
+ sn += 1
+
+ headb = img.get_block(2)
+ for i in xrange(0x20, 0x30, 2):
+ bn = headb[i]
+ bn = ord(bn)
+ if bn <= 2:
+ continue
+ if bn == 255:
+ break
+ bl = img.get_block(bn)
+ for i in xrange(0x20, 256):
+ b = ord(bl[i])
+ sum += b
+ sums.append(sum)
+ sum = 0
+ sn += 1
+
+ tot = 0
+ for sum in sums:
+ print hex(sum),
+ tot += sum
+
+ print 'tot', tot, hex(tot)
+ print
+ return
+
+
+
+if __name__ == '__main__':
+ for name in sys.argv[1:]:
+ main(name)
diff --git a/scripts/new_style.py b/scripts/new_style.py
new file mode 100644
index 0000000..25ef002
--- /dev/null
+++ b/scripts/new_style.py
@@ -0,0 +1,77 @@
+#
+# File: p.py
+#
+# 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: 31 Dec 2006
+#
+
+#
+# Create the new style files points, lines and polygons from a map-features file.
+#
+
+import sys
+import csv
+
+MAP_FEATURES = 'map-features.csv'
+
+if len(sys.argv) > 1:
+ MAP_FEATURES = sys.argv[1]
+
+points = []
+lines = []
+polygons = []
+
+features = {
+ 'polyline': lines,
+ 'polygon': polygons,
+ 'point': points,
+ }
+file_names = {
+ 'polyline': 'lines',
+ 'polygon': 'polygons',
+ 'point': 'points',
+ }
+
+def main():
+
+ # Read the garmin feature name to internal number file
+ f = open(MAP_FEATURES)
+ r = csv.reader(f, delimiter='|')
+ for line in r:
+ kind = line[0]
+ if kind[0] == '#': continue
+ key = line[1] + '=' + line[2]
+ value = makeval(line[3], line[4])
+ res = int(line[5])
+
+ line = "%s [%s resolution %d]" % (key, value, res)
+ ft = features[kind]
+ ft.append(line)
+
+
+ # Write out the files
+ for name in features.keys():
+ f = open(file_names[name], 'w')
+ ft = features[name]
+ for line in ft:
+ f.write(line)
+ f.write("\n")
+
+def makeval(a, b):
+ if not b: return a
+ return a + b[2:]
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/options_to_doc.py b/scripts/options_to_doc.py
new file mode 100644
index 0000000..e969fd2
--- /dev/null
+++ b/scripts/options_to_doc.py
@@ -0,0 +1,101 @@
+#
+# File: options_conv.py
+#
+# Copyright (C) 2013 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 or
+# version 3 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: 28 Jun 2013
+#
+
+import sys
+import re
+
+f = open('options')
+
+NONE = 0
+OPT = 1
+DESC = 2
+
+WS=(' ', '\t')
+
+def count_indent(line):
+ count = 0
+ for c in line:
+ if c == ' ':
+ count += 1
+ elif c == '\t':
+ count += 4
+ else:
+ break
+ return count
+
+state = NONE
+in_preserve = False
+desc_indent = 0
+last_indent = 0
+
+def start_preserve():
+ global in_preserve
+ if in_preserve: return
+ in_preserve = True
+ print '<div class=preserve><nowiki>'
+
+def end_preserve():
+ global in_preserve
+ if not in_preserve: return
+ in_preserve = False
+ print '</nowiki></div>'
+
+print '= List of options ='
+
+for line in f.xreadlines():
+ line = line[:-1]
+
+ if len(line) == 0 or len(line.strip()) == 0:
+ if state == DESC:
+ if in_preserve:
+ print
+ else:
+ print '<p>'
+ continue
+ print
+ continue
+
+ if line[0] == '-':
+ end_preserve()
+ line = ';' + line
+ state = OPT
+
+ if state == OPT and line[0] in WS:
+ state = DESC
+ desc_indent = count_indent(line)
+ last_indent = desc_indent
+ print ':', line
+ continue
+ elif state == DESC and line[0] not in WS:
+ if last_indent > desc_indent:
+ end_preserve()
+ print
+ last_indent = 0
+ state = NONE
+
+ if state == DESC:
+ new_indent = count_indent(line)
+ line = re.sub(r'^(\t| {1,4})', '', line)
+ if new_indent > last_indent:
+ start_preserve()
+ elif new_indent < last_indent and new_indent == desc_indent:
+ end_preserve()
+ last_indent = new_indent
+
+ print line
diff --git a/src/uk/me/parabola/imgfmt/ExitException.java b/src/uk/me/parabola/imgfmt/ExitException.java
new file mode 100644
index 0000000..d1fae4a
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/ExitException.java
@@ -0,0 +1,57 @@
+/*
+ * 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: 20-Dec-2006
+ */
+package uk.me.parabola.imgfmt;
+
+/**
+ * Used to exit the program. So that System.exit need only be called
+ * in the one place, or indeed not at all.
+ *
+ * @author Steve Ratcliffe
+ */
+public class ExitException extends RuntimeException {
+
+
+ /**
+ * Constructs a new runtime exception with the specified detail message.
+ * The cause is not initialized, and may subsequently be initialized by a
+ * call to {@link #initCause}.
+ *
+ * @param message the detail message. The detail message is saved for
+ * later retrieval by the {@link #getMessage()} method.
+ */
+ public ExitException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new runtime exception with the specified detail message and
+ * cause. <p>Note that the detail message associated with
+ * <code>cause</code> is <i>not</i> automatically incorporated in
+ * this runtime exception's detail message.
+ *
+ * @param message the detail message (which is saved for later retrieval
+ * by the {@link #getMessage()} method).
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A <tt>null</tt> value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.4
+ */
+ public ExitException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/FileExistsException.java b/src/uk/me/parabola/imgfmt/FileExistsException.java
new file mode 100644
index 0000000..34e8dfa
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/FileExistsException.java
@@ -0,0 +1,39 @@
+/*
+ * 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: 02-Dec-2006
+ */
+package uk.me.parabola.imgfmt;
+
+import java.io.IOException;
+
+/**
+ * Thrown when a file already exists and would be overwritten.
+ *
+ * @author Steve Ratcliffe
+ */
+public class FileExistsException extends IOException {
+
+ /**
+ * Constructs a new exception with the specified detail message. The
+ * cause is not initialized, and may subsequently be initialized by
+ * a call to {@link #initCause}.
+ *
+ * @param message the detail message. The detail message is saved for
+ * later retrieval by the {@link #getMessage()} method.
+ */
+ public FileExistsException(String message) {
+ super(message);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/FileNotWritableException.java b/src/uk/me/parabola/imgfmt/FileNotWritableException.java
new file mode 100644
index 0000000..1f4c9bf
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/FileNotWritableException.java
@@ -0,0 +1,30 @@
+/*
+ * 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: 02-Sep-2007
+ */
+package uk.me.parabola.imgfmt;
+
+import java.io.IOException;
+
+/**
+ * If a file cannot be created, or written to, then this exception is thrown.
+ * @author Steve Ratcliffe
+ */
+public class FileNotWritableException extends IOException {
+ public FileNotWritableException(String s, Exception e) {
+ // super class does not have the constructor that takes an exception
+ super(s + ' ' + e.getMessage());
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/FileSystemParam.java b/src/uk/me/parabola/imgfmt/FileSystemParam.java
new file mode 100644
index 0000000..3a19ae1
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/FileSystemParam.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2006, 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.imgfmt;
+
+/**
+ * Small class to hold all kinds of filesystem parameters. If a field
+ * is not set then it is not used.
+ *
+ * @author Steve Ratcliffe
+ */
+public class FileSystemParam {
+ private String filename;
+ private String mapDescription = "Open Street Map";
+ private int blockSize = 512;
+ private int directoryStartEntry = 2; // Always in terms of entries of 512 bytes
+ private int reservedDirectoryBlocks = 202;
+ private boolean gmapsupp;
+
+ public String getFilename() {
+ return filename;
+ }
+
+ public void setFilename(String filename) {
+ this.filename = filename;
+ }
+
+ public String getMapDescription() {
+ return mapDescription;
+ }
+
+ public void setMapDescription(String mapDescription) {
+ this.mapDescription = mapDescription;
+ if (this.mapDescription == null)
+ this.mapDescription = "";
+ }
+
+ public int getBlockSize() {
+ return blockSize;
+ }
+
+ public void setBlockSize(int blockSize) {
+ this.blockSize = blockSize;
+ }
+
+ public int getDirectoryStartEntry() {
+ return directoryStartEntry;
+ }
+
+ public void setDirectoryStartEntry(int directoryStartBlock) {
+ this.directoryStartEntry = directoryStartBlock;
+ }
+
+ public int getReservedDirectoryBlocks() {
+ return reservedDirectoryBlocks;
+ }
+
+ public void setReservedDirectoryBlocks(int blocks) {
+ this.reservedDirectoryBlocks = blocks;
+ }
+
+ public boolean isGmapsupp() {
+ return gmapsupp;
+ }
+
+ public void setGmapsupp(boolean gmapsupp) {
+ this.gmapsupp = gmapsupp;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/FormatException.java b/src/uk/me/parabola/imgfmt/FormatException.java
new file mode 100644
index 0000000..aa15dfc
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/FormatException.java
@@ -0,0 +1,47 @@
+/*
+ * 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: 18-Dec-2006
+ */
+package uk.me.parabola.imgfmt;
+
+/**
+ * Thrown for any kind of malformed input to the mapping program.
+ *
+ * @author Steve Ratcliffe
+ */
+public class FormatException extends RuntimeException {
+
+ /**
+ * Constructs a new exception with the specified detail message and
+ * cause. <p>Note that the detail message associated with
+ * <code>cause</code> is <i>not</i> automatically incorporated in
+ * this exception's detail message.
+ *
+ * @param message the detail message (which is saved for later retrieval
+ * by the {@link #getMessage()} method).
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A <tt>null</tt> value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.4
+ */
+ public FormatException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public FormatException(String message) {
+ super(message);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/MapFailedException.java b/src/uk/me/parabola/imgfmt/MapFailedException.java
new file mode 100644
index 0000000..abea490
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/MapFailedException.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.imgfmt;
+
+/**
+ * Used for cases where the current map has failed to compile, but the error
+ * is expected to be specific to the map (eg it is too big etc). When this
+ * error is thrown it may be possible for other maps on the command line to
+ * succeed.
+ *
+ * If the error is such that processing further maps is not likely to be
+ * successful then use {@link ExitException} instead.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MapFailedException extends RuntimeException {
+
+
+ /**
+ * Constructs a new runtime exception with the specified detail message.
+ * The cause is not initialized, and may subsequently be initialized by a
+ * call to {@link #initCause}.
+ *
+ * @param message the detail message. The detail message is saved for
+ * later retrieval by the {@link #getMessage()} method.
+ */
+ public MapFailedException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new runtime exception with the specified detail message and
+ * cause. <p>Note that the detail message associated with
+ * <code>cause</code> is <i>not</i> automatically incorporated in
+ * this runtime exception's detail message.
+ *
+ * @param message the detail message (which is saved for later retrieval
+ * by the {@link #getMessage()} method).
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A <tt>null</tt> value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.4
+ */
+ public MapFailedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/ReadFailedException.java b/src/uk/me/parabola/imgfmt/ReadFailedException.java
new file mode 100644
index 0000000..0266753
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/ReadFailedException.java
@@ -0,0 +1,40 @@
+/*
+ * 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: Dec 14, 2007
+ */
+package uk.me.parabola.imgfmt;
+
+/**
+ * @author Steve Ratcliffe
+ */
+public class ReadFailedException extends RuntimeException {
+
+ /**
+ * Constructs a new runtime exception with the specified detail message and
+ * cause. <p>Note that the detail message associated with <code>cause</code>
+ * is <i>not</i> automatically incorporated in this runtime exception's detail
+ * message.
+ *
+ * @param message the detail message (which is saved for later retrieval by the
+ * {@link #getMessage()} method).
+ * @param cause the cause (which is saved for later retrieval by the {@link
+ * #getCause()} method). (A <tt>null</tt> value is permitted, and indicates
+ * that the cause is nonexistent or unknown.)
+ * @since 1.4
+ */
+ public ReadFailedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/Utils.java b/src/uk/me/parabola/imgfmt/Utils.java
new file mode 100644
index 0000000..d4bc516
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/Utils.java
@@ -0,0 +1,286 @@
+/*
+ * 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: 03-Dec-2006
+ */
+package uk.me.parabola.imgfmt;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.zip.GZIPInputStream;
+
+import uk.me.parabola.imgfmt.app.Coord;
+/**
+ * Some miscellaneous functions that are used within the .img code.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Utils {
+ /**
+ * Routine to convert a string to bytes and pad with a character up
+ * to a given length.
+ * Only to be used for strings that are expressible in latin1.
+ *
+ * @param s The original string.
+ * @param len The length to pad to.
+ * @param pad The byte used to pad.
+ * @return An array created from the string.
+ */
+ public static byte[] toBytes(String s, int len, byte pad) {
+ if (s == null)
+ throw new IllegalArgumentException("null string provided");
+
+ byte[] out = new byte[len];
+ for (int i = 0; i < len; i++) {
+ if (i > s.length()) {
+ out[i] = pad;
+ } else {
+ out[i] = (byte) s.charAt(i);
+ }
+ }
+ return out;
+ }
+
+ public static byte[] toBytes(String s) {
+ return toBytes(s, s.length(), (byte) 0);
+ }
+
+ /**
+ * Convert from bytes to a string. Only to be used when the character set
+ * is ascii or latin1.
+ *
+ * @param buf A byte buffer to get the bytes from. Should be ascii or latin1.
+ * @param off The offset into buf.
+ * @param len The length to get.
+ * @return A string.
+ */
+ public static String bytesToString(ByteBuffer buf, int off, int len) {
+ if (buf == null)
+ throw new IllegalArgumentException("null byte buffer provided");
+
+ byte[] bbuf = new byte[len];
+ buf.position(off);
+ buf.get(bbuf);
+ char[] cbuf = new char[len];
+ for (int i = 0; i < bbuf.length; i++) {
+ cbuf[i] = (char) bbuf[i];
+ }
+
+ return new String(cbuf);
+ }
+
+ /**
+ * Set the creation date. Note that the year is encoded specially.
+ *
+ * @param buf The buffer to write into. It must have been properly positioned
+ * beforehand.
+ * @param date The date to set.
+ */
+ public static void setCreationTime(ByteBuffer buf, Date date) {
+ Calendar cal = Calendar.getInstance();
+
+ if (date != null)
+ cal.setTime(date);
+
+ fillBufFromTime(buf, cal);
+ }
+
+ /**
+ * A map unit is an integer value that is 1/(2^24) degrees of latitude or
+ * longitude.
+ *
+ * @param l The lat or long as decimal degrees.
+ * @return An integer value in map units.
+ */
+ public static int toMapUnit(double l) {
+ double DELTA = 360.0D / (1 << 24) / 2; //Correct rounding
+ if (l > 0)
+ return (int) ((l + DELTA) * (1 << 24)/360);
+ else
+ return (int) ((l - DELTA) * (1 << 24)/360);
+ }
+
+ /**
+ * Convert a date into the in-file representation of a date.
+ *
+ * @param date The date.
+ * @return A byte stream in .img format.
+ */
+ public static byte[] makeCreationTime(Date date) {
+ Calendar cal = Calendar.getInstance();
+
+ if (date != null)
+ cal.setTime(date);
+
+ byte[] ret = new byte[7];
+
+ ByteBuffer buf = ByteBuffer.wrap(ret);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ fillBufFromTime(buf, cal);
+
+ return ret;
+ }
+
+ private static void fillBufFromTime(ByteBuffer buf, Calendar cal) {
+ buf.putChar((char) cal.get(Calendar.YEAR));
+ buf.put((byte) (cal.get(Calendar.MONTH)+1));
+ buf.put((byte) cal.get(Calendar.DAY_OF_MONTH));
+ buf.put((byte) cal.get(Calendar.HOUR_OF_DAY));
+ buf.put((byte) cal.get(Calendar.MINUTE));
+ buf.put((byte) cal.get(Calendar.SECOND));
+ }
+
+ /**
+ * Make a date from the garmin representation.
+ * @param date The bytes representing the date.
+ * @return A java date.
+ */
+ public static Date makeCreationTime(byte[] date) {
+ Calendar cal = Calendar.getInstance();
+
+ int y = ((date[1] & 0xff) << 8) + (date[0] & 0xff);
+ cal.set(y, date[2]-1, date[3], date[4], date[5], date[6]);
+
+ return cal.getTime();
+ }
+
+ /**
+ * Convert an angle in map units to degrees.
+ */
+ public static double toDegrees(int val) {
+ return (double) val * (360.0 / (1 << 24));
+ }
+
+ /**
+ * Convert an angle in map units to radians.
+ */
+ public static double toRadians(int mapunits) {
+ return toDegrees(mapunits) * (Math.PI / 180);
+ }
+
+ public static void closeFile(Closeable f) {
+ if (f != null) {
+ try {
+ f.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Open a file and apply filters necessary for reading it such as
+ * decompression.
+ *
+ * @param name The file to open.
+ * @return A stream that will read the file, positioned at the beginning.
+ * @throws FileNotFoundException If the file cannot be opened for any reason.
+ */
+ public static InputStream openFile(String name) throws FileNotFoundException {
+ InputStream is = new FileInputStream(name);
+ if (name.endsWith(".gz")) {
+ try {
+ is = new GZIPInputStream(is);
+ } catch (IOException e) {
+ throw new FileNotFoundException( "Could not read as compressed file");
+ }
+ }
+ return is;
+ }
+
+ public static String joinPath(String dir, String basename, String ext) {
+ return joinPath(dir, basename + "." + ext);
+ }
+ public static String joinPath(String dir, String basename) {
+ File file = new File(dir, basename);
+ return file.getAbsolutePath();
+ }
+
+ /**
+ * Rounds an integer up to the nearest multiple of {@code 2^shift}.
+ * Works with both positive and negative integers.
+ * @param val the integer to round up.
+ * @param shift the power of two to round up to.
+ * @return the rounded integer.
+ */
+ public static int roundUp(int val, int shift) {
+ return (val + (1 << shift) - 1) >>> shift << shift;
+ }
+
+ /**
+ * Calculates the angle between the two segments (c1,c2),(c2,c3).
+ * @param c1 first point
+ * @param c2 second point
+ * @param c3 third point
+ * @return angle between the two segments in degree [-180;180]
+ */
+ public static double getAngle(Coord c1, Coord c2, Coord c3) {
+ double a = c2.bearingTo(c1);
+ double b = c2.bearingTo(c3);
+ double angle = b - (a - 180);
+ while(angle > 180)
+ angle -= 360;
+ while(angle < -180)
+ angle += 360;
+
+ return angle;
+ }
+ public final static int NOT_STRAIGHT = 0;
+ public final static int STRAIGHT_SPIKE = 1;
+ public final static int STRICTLY_STRAIGHT = 2;
+ /**
+ * Checks if the two segments (c1,c2),(c2,c3) form a straight line.
+ * @param c1 first point
+ * @param c2 second point
+ * @param c3 third point
+ * @return NOT_STRAIGHT, STRAIGHT_SPIKE or STRICTLY_STRAIGHT
+ */
+ public static int isStraight(Coord c1, Coord c2, Coord c3) {
+ if (c1.equals(c3))
+ return STRAIGHT_SPIKE;
+ long area;
+ // calculate the area that is enclosed by the three points
+ // (as if a closing line is drawn from c3 back to c1)
+ area = ((long)c1.getLongitude() * c2.getLatitude() -
+ (long)c2.getLongitude() * c1.getLatitude());
+ area += ((long)c2.getLongitude() * c3.getLatitude() -
+ (long)c3.getLongitude() * c2.getLatitude());
+ area += ((long)c3.getLongitude() * c1.getLatitude() -
+ (long)c1.getLongitude() * c3.getLatitude());
+ if (area == 0){
+ // area is empty-> points lie on a straight line
+ int delta1 = c1.getLatitude() - c2.getLatitude();
+ int delta2 = c2.getLatitude() - c3.getLatitude();
+ if (delta1 < 0 && delta2 > 0 || delta1 > 0 && delta2 < 0)
+ return STRAIGHT_SPIKE;
+ delta1 = c1.getLongitude() - c2.getLongitude();
+ delta2 = c2.getLongitude() - c3.getLongitude();
+ if (delta1 < 0 && delta2 > 0 || delta1 > 0 && delta2 < 0)
+ return STRAIGHT_SPIKE;
+ return STRICTLY_STRAIGHT;
+ }
+ // line is not straight
+ return NOT_STRAIGHT;
+
+ }
+}
+
diff --git a/src/uk/me/parabola/imgfmt/app/Area.java b/src/uk/me/parabola/imgfmt/app/Area.java
new file mode 100644
index 0000000..7dbf8d6
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/Area.java
@@ -0,0 +1,242 @@
+/*
+ * 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: 07-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.log.Logger;
+
+/**
+ * A map area in map units. There is a constructor available for creating
+ * in lat/long form.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Area {
+ private static final Logger log = Logger.getLogger(Area.class);
+
+ private final int minLat;
+ private final int minLong;
+ private final int maxLat;
+ private final int maxLong;
+
+ /**
+ * Create an area from the given coordinates. We ensure that no dimension
+ * is zero.
+ *
+ * @param minLat The western latitude.
+ * @param minLong The southern longitude.
+ * @param maxLat The eastern lat.
+ * @param maxLong The northern long.
+ */
+ public Area(int minLat, int minLong, int maxLat, int maxLong) {
+ this.minLat = minLat;
+ if (maxLat == minLat)
+ this.maxLat = minLat+1;
+ else
+ this.maxLat = maxLat;
+
+ this.minLong = minLong;
+ if (minLong == maxLong)
+ this.maxLong = maxLong+1;
+ else
+ this.maxLong = maxLong;
+ }
+
+ public Area(double minLat, double minLong, double maxLat,
+ double maxLong)
+ {
+ this(Utils.toMapUnit(minLat), Utils.toMapUnit(minLong)
+ , Utils.toMapUnit(maxLat), Utils.toMapUnit(maxLong));
+ }
+
+ public int getMinLat() {
+ return minLat;
+ }
+
+ public int getMinLong() {
+ return minLong;
+ }
+
+ public int getMaxLat() {
+ return maxLat;
+ }
+
+ public int getMaxLong() {
+ return maxLong;
+ }
+
+ public int getWidth() {
+ return maxLong - minLong;
+ }
+
+ public int getHeight() {
+ return maxLat - minLat;
+ }
+
+ public Coord getCenter() {
+ return new Coord((minLat + maxLat)/2, (minLong + maxLong)/2);
+ }
+
+ public String toString() {
+ return "("
+ + Utils.toDegrees(minLat) + ','
+ + Utils.toDegrees(minLong) + ") to ("
+ + Utils.toDegrees(maxLat) + ','
+ + Utils.toDegrees(maxLong) + ')'
+ ;
+ }
+
+ /**
+ * Split this area up into a number of smaller areas.
+ *
+ * @param xsplit The number of pieces to split this area into in the x
+ * direction.
+ * @param ysplit The number of pieces to split this area into in the y
+ * direction.
+ * @return An area containing xsplit*ysplit areas.
+ */
+ public Area[] split(int xsplit, int ysplit) {
+ Area[] areas = new Area[xsplit * ysplit];
+
+
+ int xsize = getWidth() / xsplit;
+ int ysize = getHeight() / ysplit;
+
+ int xextra = getWidth() - xsize * xsplit;
+ int yextra = getHeight() - ysize * ysplit;
+
+ for (int x = 0; x < xsplit; x++) {
+ int xstart = minLong + x * xsize;
+ int xend = xstart + xsize;
+ if (x == xsplit - 1)
+ xend += xextra;
+
+ for (int y = 0; y < ysplit; y++) {
+ int ystart = minLat + y * ysize;
+ int yend = ystart + ysize;
+ if (y == ysplit - 1)
+ yend += yextra;
+ Area a = new Area(ystart, xstart, yend, xend);
+ log.debug(x, y, a);
+ areas[x * ysplit + y] = a;
+ }
+ }
+
+ assert areas.length == xsplit * ysplit;
+ return areas;
+ }
+
+ /**
+ * Get the largest dimension. So either the width or height, depending
+ * on which is larger.
+ *
+ * @return The largest dimension in map units.
+ */
+ public int getMaxDimension() {
+ return Math.max(getWidth(), getHeight());
+ }
+
+ public final boolean contains(Coord co) {
+ // return true if co is inside the Area (it may touch the
+ // boundary)
+ return co.getLatitude() >= minLat
+ && co.getLatitude() <= maxLat
+ && co.getLongitude() >= minLong
+ && co.getLongitude() <= maxLong;
+ }
+
+ public final boolean insideBoundary(Coord co) {
+ // return true if co is inside the Area and doesn't touch the
+ // boundary
+ return co.getLatitude() > minLat
+ && co.getLatitude() < maxLat
+ && co.getLongitude() > minLong
+ && co.getLongitude() < maxLong;
+ }
+
+ public final boolean onBoundary(Coord co) {
+ // return true if co is on the boundary
+ return contains(co) && !insideBoundary(co);
+ }
+
+ /**
+ * Checks if this area intersects the given bounding box at least
+ * in one point.
+ *
+ * @param bbox an area
+ * @return <code>true</code> if this area intersects the bbox;
+ * <code>false</code> else
+ */
+ public final boolean intersects(Area bbox) {
+ return minLat <= bbox.getMaxLat() && maxLat >= bbox.getMinLat() &&
+ minLong <= bbox.getMaxLong() && maxLong >= bbox.getMinLong();
+ }
+
+ public boolean isEmpty() {
+ return minLat >= maxLat || minLong >= maxLong;
+ }
+
+ public boolean allInsideBoundary(List<Coord> coords) {
+ for (Coord co : coords) {
+ if (!insideBoundary(co))
+ return false;
+ }
+ return true;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Area area = (Area) o;
+
+ if (maxLat != area.maxLat) return false;
+ if (maxLong != area.maxLong) return false;
+ if (minLat != area.minLat) return false;
+ if (minLong != area.minLong) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result = minLat;
+ result = 31 * result + minLong;
+ result = 31 * result + maxLat;
+ result = 31 * result + maxLong;
+ return result;
+ }
+
+ /**
+ * @return list of coords that form the rectangle
+ */
+ public List<Coord> toCoords(){
+ List<Coord> coords = new ArrayList<Coord>(5);
+ Coord start = new Coord(minLat, minLong);
+ coords.add(start);
+ Coord co = new Coord(minLat, maxLong);
+ coords.add(co);
+ co = new Coord(maxLat, maxLong);
+ coords.add(co);
+ co = new Coord(maxLat, minLong);
+ coords.add(co);
+ coords.add(start);
+ return coords;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/BitReader.java b/src/uk/me/parabola/imgfmt/app/BitReader.java
new file mode 100644
index 0000000..225295d
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/BitReader.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2008 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: 29-Aug-2008
+ */
+package uk.me.parabola.imgfmt.app;
+
+/**
+ * Read an array as a bit stream.
+ *
+ * @author Steve Ratcliffe
+ */
+public class BitReader {
+ private final byte[] buf;
+ private int bitPosition;
+
+ public BitReader(byte[] buf) {
+ this.buf = buf;
+ }
+
+ public boolean get1() {
+ int off = bitPosition % 8;
+ byte b = buf[bitPosition / 8];
+
+ bitPosition++;
+ return ((b >> off) & 1) == 1;
+ }
+
+ public int get(int n) {
+ int res = 0;
+
+ int pos = 0;
+ while (pos < n) {
+ int index = bitPosition / 8;
+ int off = bitPosition % 8;
+
+ byte b = buf[index];
+ b >>= off;
+ int nbits = n - pos;
+ if (nbits > (8-off))
+ nbits = 8 - off;
+
+ int mask = ((1 << nbits) - 1);
+ res |= ((b & mask) << pos);
+ pos += nbits;
+ bitPosition += nbits;
+ }
+
+ return res;
+ }
+
+ /**
+ * Get a signed quantity.
+ *
+ * The sign bit is the last bit in the field.
+ *
+ * @param n The field width, including the sign bit.
+ * @return A signed number.
+ */
+ public int sget(int n) {
+ int res = get(n);
+ int top = 1 << (n - 1);
+
+ if ((res & top) != 0) {
+ int mask = top - 1;
+ res = ~mask | res;
+ }
+ return res;
+ }
+
+ /**
+ * Get a signed n-bit value, treating 1 << (n-1) as a flag to read another signed n-bit value
+ * for extended range.
+ */
+ public int sget2(int n) {
+ int top = 1 << (n - 1);
+ int mask = top - 1;
+ int base = 0;
+
+ int res = get(n);
+ while (res == top) {
+ // Add to the base value, and read another
+ base += mask;
+ res = get(n);
+ }
+
+ // The final byte determines the sign of the result. Add or subtract the base as
+ // appropriate.
+ if ((res & top) == 0)
+ res += base;
+ else
+ res = (res | ~mask) - base; // Make negative and subtract the base
+
+ return res;
+ }
+
+ public int getBitPosition() {
+ return bitPosition;
+ }
+
+ public int getNumberOfBits() {
+ return buf.length * 8;
+ }
+
+ /**
+ * Debugging routine that returns the remainder of the stream as a string.
+ * The bits are in little endian order, so that numbers can be read from left
+ * to right, although the whole string has to read from right to left.
+ *
+ * @return A string in binary.
+ */
+ public String remainder() {
+ int save = bitPosition;
+ StringBuilder sb = new StringBuilder();
+ while (bitPosition < buf.length * 8) {
+ sb.insert(0, get1() ? "1" : "0");
+ }
+ bitPosition = save;
+ return sb.toString();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/BitWriter.java b/src/uk/me/parabola/imgfmt/app/BitWriter.java
new file mode 100644
index 0000000..2c813f5
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/BitWriter.java
@@ -0,0 +1,167 @@
+/*
+ * 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: 14-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app;
+
+import uk.me.parabola.log.Logger;
+
+/**
+ * A class to write the bitstream.
+ *
+ * @author Steve Ratcliffe
+ */
+public class BitWriter {
+ private static final Logger log = Logger.getLogger(BitWriter.class);
+
+ // Choose so that most roads will not fill it.
+ private static final int INITIAL_BUF_SIZE = 20;
+
+ // The byte buffer and its current length (allocated length)
+ private byte[] buf; // The buffer
+ private int bufsize; // The allocated size
+ private int buflen; // The actual used length
+
+ // The bit offset into the byte array.
+ private int bitoff;
+ private static final int BUFSIZE_INC = 50;
+
+ public BitWriter() {
+ bufsize = INITIAL_BUF_SIZE;
+ buf = new byte[bufsize];
+ }
+
+ /**
+ * Put exactly one bit into the buffer.
+ *
+ * @param b The bottom bit of the integer is set at the current bit position.
+ */
+ private void put1(int b) {
+ ensureSize(bitoff + 1);
+
+ int off = getByteOffset(bitoff);
+
+ // Get the remaining bits into the byte.
+ int rem = bitoff - 8 * off;
+
+ // Or it in, we are assuming that the position is never turned back.
+ buf[off] |= (b & 0x1) << rem;
+
+ // Increment position
+ bitoff++;
+
+ // If we are in a new byte, increase the byte length.
+ if ((bitoff & 0x7) == 1)
+ buflen++;
+
+ debugPrint(b, 1);
+ }
+
+ public void put1(boolean b) {
+ put1(b ? 1 : 0);
+ }
+
+ /**
+ * Put a number of bits into the buffer, growing it if necessary.
+ *
+ * @param bval The bits to add, the lowest <b>n</b> bits will be added to
+ * the buffer.
+ * @param nb The number of bits.
+ */
+ public void putn(int bval, int nb) {
+ int val = bval & ((1<<nb) - 1);
+ int n = nb;
+
+ // We need to be able to deal with more than 24 bits, but now we can't yet
+ if (n >= 24)
+ throw new IllegalArgumentException();
+
+ ensureSize(bitoff + n);
+
+ // Get each affected byte and set bits into it until we are done.
+ while (n > 0) {
+ int ind = getByteOffset(bitoff);
+ int rem = bitoff - 8*ind;
+
+ buf[ind] |= ((val << rem) & 0xff);
+
+ // Shift down in preparation for next byte.
+ val >>>= 8-rem;
+
+ // Account for change so far
+ int nput = 8 - rem;
+ if (nput > n)
+ nput = n;
+ bitoff += nput;
+ n -= nput;
+ }
+
+ buflen = (bitoff+7)/8;
+ }
+
+ public byte[] getBytes() {
+ return buf;
+ }
+
+ /**
+ * Get the number of bytes actually used to hold the bit stream. This therefore can be and usually
+ * is less than the length of the buffer returned by {@link #getBytes()}.
+ * @return Number of bytes required to hold the output.
+ */
+ public int getLength() {
+ return buflen;
+ }
+
+ /**
+ * Get the byte offset for the given bit number.
+ *
+ * @param boff The number of the bit in question.
+ * @return The index into the byte array where the bit resides.
+ */
+ private int getByteOffset(int boff) {
+ return boff/8;
+ }
+
+ /**
+ * Set everything up so that the given size can be accommodated.
+ * The buffer is re-sized if necessary.
+ *
+ * @param newlen The new length of the bit buffer in bits.
+ */
+ private void ensureSize(int newlen) {
+ if (newlen/8 >= bufsize)
+ reallocBuffer();
+ }
+
+ /**
+ * Reallocate the byte buffer.
+ */
+ private void reallocBuffer() {
+ log.debug("reallocating buffer");
+ bufsize += BUFSIZE_INC;
+ byte[] newbuf = new byte[bufsize];
+
+ System.arraycopy(this.buf, 0, newbuf, 0, this.buf.length);
+ this.buf = newbuf;
+ }
+
+ private void debugPrint(int b, int i) {
+ if (log.isDebugEnabled())
+ log.debug("after put", i, "of", b, " bufsize=", bufsize, ", len=",
+ buflen, ", pos=", bitoff);
+ }
+
+
+}
diff --git a/src/uk/me/parabola/imgfmt/app/BufferedImgFileReader.java b/src/uk/me/parabola/imgfmt/app/BufferedImgFileReader.java
new file mode 100644
index 0000000..0a1776c
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/BufferedImgFileReader.java
@@ -0,0 +1,280 @@
+/*
+ * 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: Dec 14, 2007
+ */
+package uk.me.parabola.imgfmt.app;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import uk.me.parabola.imgfmt.MapFailedException;
+import uk.me.parabola.imgfmt.ReadFailedException;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.log.Logger;
+
+/**
+ * Read from an img file via a buffer.
+ *
+ * @author Steve Ratcliffe
+ */
+public class BufferedImgFileReader implements ImgFileReader {
+ private static final Logger log = Logger.getLogger(BufferedImgFileReader.class);
+
+ // Buffer size, must be a power of 2
+ private static final int BUF_SIZE = 0x1000;
+
+ private final ImgChannel chan;
+
+ // The buffer that we read out of
+ private final ByteBuffer buf = ByteBuffer.allocate(BUF_SIZE);
+ private long bufStart;
+ private int bufSize = -1;
+
+ // We keep our own idea of the file position.
+ private long position;
+
+ public BufferedImgFileReader(ImgChannel chan) {
+ this.chan = chan;
+ }
+
+ /**
+ * Called when the stream is closed. Any resources can be freed.
+ *
+ * @throws IOException When there is an error in closing.
+ */
+ public void close() throws IOException {
+ chan.close();
+ }
+
+ /**
+ * Get the position. Needed because may not be reflected in the underlying
+ * file if being buffered.
+ *
+ * @return The logical position within the file.
+ */
+ public long position() {
+ return position;
+ }
+
+ /**
+ * Set the position of the file.
+ *
+ * @param pos The new position in the file.
+ */
+ public void position(long pos) {
+ position = pos;
+ }
+
+ /**
+ * Read in a single byte from the current position.
+ *
+ * @return The byte that was read.
+ */
+ public byte get() throws ReadFailedException {
+ // Check if the current position is within the buffer
+ fillBuffer();
+
+ int pos = (int) (position - bufStart);
+ if (pos >= bufSize)
+ return 0; // XXX do something else
+
+ position++;
+ return buf.get(pos);
+ }
+
+ /**
+ * Read in two bytes. Done in the correct byte order.
+ *
+ * @return The 2 byte integer that was read.
+ */
+ public char getChar() throws ReadFailedException {
+ // Slow but sure implementation
+ byte b1 = get();
+ byte b2 = get();
+ return (char) (((b2 & 0xff) << 8) + (b1 & 0xff));
+ }
+
+ /**
+ * Read a three byte signed quantity.
+ * @return The read value.
+ * @throws ReadFailedException
+ */
+ public int get3() throws ReadFailedException {
+ // Slow but sure implementation
+ byte b1 = get();
+ byte b2 = get();
+ byte b3 = get();
+
+ return (b1 & 0xff)
+ | ((b2 & 0xff) << 8)
+ | (b3 << 16)
+ ;
+ }
+
+ public int getu3() throws ReadFailedException {
+ return get3() & 0xffffff;
+ }
+
+ /**
+ * Read in a 4 byte value.
+ *
+ * @return A 4 byte integer.
+ */
+ public int getInt() throws ReadFailedException {
+ // Slow but sure implementation
+ byte b1 = get();
+ byte b2 = get();
+ byte b3 = get();
+ byte b4 = get();
+ return (b1 & 0xff)
+ | ((b2 & 0xff) << 8)
+ | ((b3 & 0xff) << 16)
+ | ((b4 & 0xff) << 24)
+ ;
+ }
+
+ public int getUint(int n) throws ReadFailedException {
+ switch (n) {
+ case 1: return get() & 0xff;
+ case 2: return getChar();
+ case 3: return getu3();
+ case 4: return getInt();
+ default: // this is a programming error so exit
+ throw new MapFailedException("bad integer size " + n);
+ }
+ }
+
+ /**
+ * Read in an arbitrary length sequence of bytes.
+ *
+ * @param len The number of bytes to read.
+ */
+ public byte[] get(int len) throws ReadFailedException {
+ byte[] bytes = new byte[len];
+
+ // Slow but sure implementation.
+ for (int i = 0; i < len; i++) {
+ bytes[i] = get();
+ }
+ return bytes;
+ }
+
+ /**
+ * Read a zero terminated string from the file.
+ * @return A string
+ * @throws ReadFailedException For failures.
+ */
+ public String getZString() throws ReadFailedException {
+ StringBuffer sb = new StringBuffer();
+
+ // Slow but sure implementation.
+ for (byte b = get(); b != 0; b = get()) {
+ sb.append((char) b);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Read in a string of digits in the compressed base 11 format that is used
+ * for phone numbers in the POI section.
+ * @param delimiter This will replace all digit 11 characters. Usually a
+ * '-' to separate numbers in a telephone. No doubt there is a different
+ * standard in each country.
+ * @return A phone number possibly containing the delimiter character.
+ */
+ public String getBase11str(byte firstChar, char delimiter) {
+ // NB totally untested.
+ StringBuilder str11 = new StringBuilder();
+ int term = 2;
+
+ int ch = firstChar & 0xff;
+ do {
+ if (str11.length() == 0) {
+ // Not found
+ if (ch < 0x80)
+ return "";
+ }
+
+ if ((ch & 0x80) != 0)
+ --term;
+ str11.append(base(ch & 0x7F, 11, 2));
+ if (term != 0)
+ ch = get();
+ } while (term != 0);
+
+ // Remove any trailing delimiters
+ int idx;
+ if ((idx = str11.lastIndexOf("A")) >= 0)
+ str11.setLength(idx);
+
+ // Convert in-line delimiters to the char delimiter
+ int len = str11.length();
+ for (int i = 0; i < len; i++) {
+ if (str11.charAt(i) == 'A')
+ str11.setCharAt(i, delimiter);
+ }
+
+ return str11.toString();
+ }
+
+ private String base(int inNum, int base, int width) {
+ int num = inNum;
+ StringBuilder val = new StringBuilder();
+
+ if (base < 2 || base > 36 || width < 1)
+ return "";
+
+ String digit = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ while (num != 0) {
+ val.append(digit.charAt(num % base));
+ num /= base;
+ }
+
+ while (val.length() < width)
+ val.append('0');
+
+ val.reverse();
+ return val.toString();
+ }
+
+ /**
+ * Check to see if the buffer contains the byte at the current position.
+ * If not then it is re-read so that it does.
+ *
+ * @throws ReadFailedException If the buffer needs filling and the file cannot be
+ * read.
+ */
+ private void fillBuffer() throws ReadFailedException {
+ // If we are no longer inside the buffer, then re-read it.
+ if (position < bufStart || position >= bufStart + bufSize) {
+
+ // Get channel position on a block boundary.
+ bufStart = position & ~(BUF_SIZE - 1);
+ chan.position(bufStart);
+ log.debug("reading in a buffer start=", bufStart);
+
+ // Fill buffer
+ buf.clear();
+ bufSize = 0;
+ try {
+ bufSize = chan.read(buf);
+ } catch (IOException e) {
+ throw new ReadFailedException("failed to fill buffer", e);
+ }
+
+ log.debug("there were", bufSize, "bytes read");
+ }
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/BufferedImgFileWriter.java b/src/uk/me/parabola/imgfmt/app/BufferedImgFileWriter.java
new file mode 100644
index 0000000..d94d33a
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/BufferedImgFileWriter.java
@@ -0,0 +1,212 @@
+/*
+ * 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: 07-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import uk.me.parabola.imgfmt.MapFailedException;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.log.Logger;
+
+/**
+ * A straight forward implementation that just keeps all the data in a buffer
+ * until the file needs to be written to disk.
+ *
+ * @author Steve Ratcliffe
+ */
+public class BufferedImgFileWriter implements ImgFileWriter {
+ private static final Logger log = Logger.getLogger(BufferedImgFileWriter.class);
+
+ private static final int KBYTE = 1024;
+ private static final int INIT_SIZE = 16 * KBYTE;
+ private static final int GROW_SIZE = 128 * KBYTE;
+ private static final int GUARD_SIZE = KBYTE;
+
+ private final ImgChannel chan;
+
+ private ByteBuffer buf = ByteBuffer.allocate(INIT_SIZE);
+ private int bufferSize = INIT_SIZE;
+
+ // The size of the file. Note that for this to be set properly, the
+ // position must be set to a low value after the full file is written. This
+ // always happens because we go back and write the header after all is
+ // written.
+ private int maxSize;
+
+ // The maximum allowed file size.
+ private long maxAllowedSize = 0xffffff;
+
+ public BufferedImgFileWriter(ImgChannel chan) {
+ this.chan = chan;
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ }
+
+ /**
+ * Called to write out any saved buffers. The strategy may write
+ * directly to the file in which case this would have nothing or
+ * little to do.
+ */
+ public void sync() throws IOException {
+ buf.limit(maxSize);
+ buf.position(0);
+ log.debug("syncing to pos", chan.position(), ", size", buf.limit());
+ chan.write(buf);
+ }
+
+ /**
+ * Get the position. Needed because may not be reflected in the underlying
+ * file if being buffered.
+ *
+ * @return The logical position within the file.
+ */
+ public int position() {
+ return buf.position();
+ }
+
+ /**
+ * Set the position of the file.
+ *
+ * @param pos The new position in the file.
+ */
+ public void position(long pos) {
+ int cur = position();
+ if (cur > maxSize)
+ maxSize = cur;
+ buf.position((int) pos);
+ }
+
+ /**
+ * Called when the stream is closed. Any resources can be freed.
+ */
+ public void close() throws IOException {
+ chan.close();
+ }
+
+ /**
+ * Write out a single byte.
+ *
+ * @param b The byte to write.
+ */
+ public void put(byte b) {
+ ensureSize(1);
+ buf.put(b);
+ }
+
+ /**
+ * Write out two bytes. Done in the correct byte order.
+ *
+ * @param c The value to write.
+ */
+ public void putChar(char c) {
+ ensureSize(2);
+ buf.putChar(c);
+ }
+
+ /**
+ * Write out a 3 byte value in the correct byte order etc.
+ *
+ * @param val The value to write.
+ */
+ public void put3(int val) {
+ ensureSize(3);
+ buf.put((byte) (val & 0xff));
+ buf.putChar((char) (val >> 8));
+ }
+
+ /**
+ * Write out 4 byte value.
+ *
+ * @param val The value to write.
+ */
+ public void putInt(int val) {
+ ensureSize(4);
+ buf.putInt(val);
+ }
+
+ /**
+ * Write out an arbitrary length sequence of bytes.
+ *
+ * @param val The values to write.
+ */
+ public void put(byte[] val) {
+ ensureSize(val.length);
+ buf.put(val);
+ }
+
+ /**
+ * Write out part of a byte array.
+ *
+ * @param src The array to take bytes from.
+ * @param start The start position.
+ * @param length The number of bytes to write.
+ */
+ public void put(byte[] src, int start, int length) {
+ ensureSize(length);
+ buf.put(src, start, length);
+ }
+
+ public void put(ByteBuffer src) {
+ ensureSize(src.limit());
+ buf.put(src);
+ }
+
+ /**
+ * Get the size of the file as written.
+ *
+ * NOTE: that calling this is only valid at certain times.
+ *
+ * @return The size of the file, if it is available.
+ */
+ public long getSize() {
+ return maxSize;
+ }
+
+ public ByteBuffer getBuffer() {
+ return buf;
+ }
+
+ /**
+ * Make sure there is enough room for the data we are about to write.
+ *
+ * @param length The amount of data.
+ */
+ private void ensureSize(int length) {
+ int needed = buf.position() + length;
+ if (needed > (bufferSize - GUARD_SIZE)) {
+ while(needed > (bufferSize - GUARD_SIZE))
+ bufferSize += GROW_SIZE;
+ if (bufferSize > maxAllowedSize) {
+ // Previous message was confusing people, although it is difficult to come
+ // up with something that is strictly true in all situations.
+ throw new MapFailedException(
+ "There is not enough room in a single garmin map for all the input data\n" +
+ " The .osm file should be split into smaller pieces first.");
+ }
+ ByteBuffer newb = ByteBuffer.allocate(bufferSize);
+ newb.order(ByteOrder.LITTLE_ENDIAN);
+ buf.flip();
+ newb.put(buf);
+ buf = newb;
+ }
+ }
+
+ public void setMaxSize(long maxSize) {
+ this.maxAllowedSize = maxSize;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/CommonHeader.java b/src/uk/me/parabola/imgfmt/app/CommonHeader.java
new file mode 100644
index 0000000..9df53e5
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/CommonHeader.java
@@ -0,0 +1,123 @@
+/*
+ * 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: Dec 14, 2007
+ */
+package uk.me.parabola.imgfmt.app;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+
+import uk.me.parabola.imgfmt.ReadFailedException;
+import uk.me.parabola.imgfmt.Utils;
+
+/**
+ * The header that is common to all application files within the .img file.
+ * It basically contains two things of interest, the size of the header and
+ * its type. The type is usually of the form 'GARMIN.YYY' where YYY is the
+ * file extension of the type eg TRE, LBL, RGN etc.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class CommonHeader {
+ protected static final int COMMON_HEADER_LEN = 21;
+ private static final int TYPE_LEN = 10;
+
+ // The common header contains the length and the type which are set at
+ // construction time.
+ private int headerLength;
+ private String type;
+
+ // Set to 0x80 on locked maps. We are not interested in creating locked
+ // maps, but may be useful to recognise them for completeness.
+ // private byte lockFlag;
+
+ // A date of creation.
+ private Date creationDate;
+
+ protected CommonHeader(int headerLength, String type) {
+ this.headerLength = headerLength;
+ this.type = type;
+ }
+
+ /**
+ * Writes out the header that is common to all the file types. It should
+ * be called by the sync() methods of subclasses when they are ready.
+ * @param writer Used to write the header.
+ */
+ public final void writeHeader(ImgFileWriter writer) {
+ writePrepare();
+
+ writer.position(0);
+
+ writer.putChar((char) headerLength);
+ writer.put(Utils.toBytes(type, TYPE_LEN, (byte) 0));
+
+ writer.put((byte) 1); // unknown
+ writer.put((byte) 0); // not locked
+
+ byte[] date = Utils.makeCreationTime(new Date());
+ writer.put(date);
+
+ writeFileHeader(writer);
+ }
+
+ /**
+ * Read the common header. It starts at the beginning of the file.
+ * @param reader Used to read the header.
+ */
+ public final void readHeader(ImgFileReader reader) throws ReadFailedException {
+ reader.position(0);
+ headerLength = reader.getChar();
+ byte[] bytes = reader.get(TYPE_LEN);
+ try {
+ type = new String(bytes, "ascii");
+ } catch (UnsupportedEncodingException e) {
+ // ascii is supported always, so this can't happen
+ }
+ reader.get(); // ignore
+ reader.get(); // ignore
+
+ byte[] date = reader.get(7);
+ creationDate = Utils.makeCreationTime(date);
+
+ readFileHeader(reader);
+ }
+
+ /**
+ * Read the rest of the header. Specific to the given file. It is
+ * guaranteed that the file position will be set to the correct place
+ * before this is called.
+ * @param reader The header is read from here.
+ */
+ protected abstract void readFileHeader(ImgFileReader reader) throws ReadFailedException;
+
+ /**
+ * Write the rest of the header. It is guaranteed that the writer will
+ * be set to the correct position before calling.
+ * @param writer The header is written here.
+ */
+ protected abstract void writeFileHeader(ImgFileWriter writer);
+
+ public int getHeaderLength() {
+ return headerLength;
+ }
+
+ private void writePrepare() {
+ // Prepare for write by setting our defaults.
+ // lockFlag = 0;
+ if (creationDate == null)
+ creationDate = new Date();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/Coord.java b/src/uk/me/parabola/imgfmt/app/Coord.java
new file mode 100644
index 0000000..2db395e
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/Coord.java
@@ -0,0 +1,322 @@
+/*
+ * 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: 11-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app;
+
+import java.util.Formatter;
+import java.util.Locale;
+
+import uk.me.parabola.imgfmt.Utils;
+
+/**
+ * A point coordinate in unshifted map-units.
+ * A map unit is 360/2^24 degrees. In some places <i>shifted</i> coordinates
+ * are used, which means that they are divided by some power of two to save
+ * space in the file.
+ *
+ * You can create one of these with lat/long by calling the constructor with
+ * double args.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Coord implements Comparable<Coord> {
+ private final static byte ON_BOUNDARY_MASK = 0x01; // bit in flags is true if point lies on a boundary
+ private final static byte PRESERVED_MASK = 0x02; // bit in flags is true if point should not be filtered out
+ private final static byte REPLACED_MASK = 0x04; // bit in flags is true if point was replaced
+ private final static byte TREAT_AS_NODE_MASK = 0x08; // bit in flags is true if point should be treated as a node
+ private final static byte FIXME_NODE_MASK = 0x10; // bit in flags is true if a node with this coords has a fixme tag
+ private final int latitude;
+ private final int longitude;
+ private byte highwayCount; // number of highways that use this point
+ private byte flags; // further attributes
+
+ /**
+ * Construct from co-ordinates that are already in map-units.
+ * @param latitude The latitude in map units.
+ * @param longitude The longitude in map units.
+ */
+ public Coord(int latitude, int longitude) {
+ this.latitude = latitude;
+ this.longitude = longitude;
+ }
+
+ /**
+ * Construct from regular latitude and longitude.
+ * @param latitude The latitude in degrees.
+ * @param longitude The longitude in degrees.
+ */
+ public Coord(double latitude, double longitude) {
+ this.latitude = Utils.toMapUnit(latitude);
+ this.longitude = Utils.toMapUnit(longitude);
+ }
+
+ public int getLatitude() {
+ return latitude;
+ }
+
+ public int getLongitude() {
+ return longitude;
+ }
+
+ public long getId() {
+ return 0;
+ }
+
+ public int getHighwayCount() {
+ return highwayCount;
+ }
+
+ /**
+ * Increase the counter how many highways use this coord.
+ */
+ public void incHighwayCount() {
+ // don't let it wrap
+ if(highwayCount < Byte.MAX_VALUE)
+ ++highwayCount;
+ }
+
+ /**
+ * Decrease the counter how many highways use this coord.
+ */
+ public void decHighwayCount() {
+ // don't let it wrap
+ if(highwayCount > 0)
+ --highwayCount;
+ }
+
+ /**
+ * Resets the highway counter to 0.
+ */
+ public void resetHighwayCount() {
+ highwayCount = 0;
+ }
+
+ public boolean getOnBoundary() {
+ return (flags & ON_BOUNDARY_MASK) != 0;
+ }
+
+ public void setOnBoundary(boolean onBoundary) {
+ if (onBoundary)
+ this.flags |= ON_BOUNDARY_MASK;
+ else
+ this.flags &= ~ON_BOUNDARY_MASK;
+ }
+
+ public boolean preserved() {
+ return (flags & PRESERVED_MASK) != 0;
+ }
+
+ public void preserved(boolean preserved) {
+ if (preserved)
+ this.flags |= PRESERVED_MASK;
+ else
+ this.flags &= ~PRESERVED_MASK;
+ }
+
+ /**
+ * Returns if this coord was marked to be replaced in short arc removal.
+ * @return True means the replacement has to be looked up.
+ */
+ public boolean isReplaced() {
+ return (flags & REPLACED_MASK) != 0;
+ }
+
+ /**
+ * Mark a point as replaced in short arc removal process.
+ * @param replaced true or false
+ */
+ public void setReplaced(boolean replaced) {
+ if (replaced)
+ this.flags |= REPLACED_MASK;
+ else
+ this.flags &= ~REPLACED_MASK;
+ }
+
+ /**
+ * Should this Coord be treated like a Garmin node in short arc removal?
+ * The value has no meaning outside of short arc removal.
+ * @return true if this coord should be treated like a Garmin node, else false
+ */
+ public boolean isTreatAsNode() {
+ return (flags & TREAT_AS_NODE_MASK) != 0;
+ }
+
+ /**
+ * Mark the Coord to be treated like a Node in short arc removal
+ * @param treatAsNode true or false
+ */
+ public void setTreatAsNode(boolean treatAsNode) {
+ if (treatAsNode)
+ this.flags |= TREAT_AS_NODE_MASK;
+ else
+ this.flags &= ~TREAT_AS_NODE_MASK;
+ }
+
+ /**
+ * Does this coordinate belong to a node with a fixme tag?
+ * Note that the value is set after evaluating the points style.
+ * @return true if the fixme flag is set, else false
+ */
+ public boolean isFixme() {
+ return (flags & FIXME_NODE_MASK) != 0;
+ }
+
+ public void setFixme(boolean b) {
+ if (b)
+ this.flags |= FIXME_NODE_MASK;
+ else
+ this.flags &= ~FIXME_NODE_MASK;
+ }
+
+ public int hashCode() {
+ // Use a factor for latitude to span over the whole integer range:
+ // max lat: 4194304
+ // max lon: 8388608
+ // max hashCode: 2118123520 < 2147483647 (Integer.MAX_VALUE)
+ return 503 * latitude + longitude;
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == null || !(obj instanceof Coord))
+ return false;
+ Coord other = (Coord) obj;
+ return latitude == other.latitude && longitude == other.longitude;
+ }
+
+ /**
+ * Distance to other point in meters.
+ */
+ public double distance(Coord other) {
+ return quickDistance(other);
+ }
+
+ protected double slowDistance(Coord other) {
+ if (equals(other))
+ return 0;
+
+ double lat1 = Utils.toRadians(latitude);
+ double lat2 = Utils.toRadians(other.getLatitude());
+ double lon1 = Utils.toRadians(getLongitude());
+ double lon2 = Utils.toRadians(other.getLongitude());
+
+ double R = 6371000; // meters
+
+ // cosine of great circle angle between points
+ double cangle = Math.sin(lat1)*Math.sin(lat2) +
+ Math.cos(lat1)*Math.cos(lat2) * Math.cos(lon2-lon1);
+
+ return Math.acos(cangle) * R;
+ }
+
+ public double quickDistance(Coord other){
+ return 40075000 * Math.sqrt(distanceInDegreesSquared(other)) / 360;
+ }
+
+ public double distanceInDegreesSquared(Coord other) {
+ if (equals(other))
+ return 0;
+
+ double lat1 = Utils.toDegrees(getLatitude());
+ double lat2 = Utils.toDegrees(other.getLatitude());
+ double long1 = Utils.toDegrees(getLongitude());
+ double long2 = Utils.toDegrees(other.getLongitude());
+
+ double latDiff;
+ if (lat1 < lat2)
+ latDiff = lat2 - lat1;
+ else
+ latDiff = lat1 - lat2;
+ if (latDiff > 90)
+ latDiff -= 180;
+
+ double longDiff;
+ if (long1 < long2)
+ longDiff = long2 - long1;
+ else
+ longDiff = long1 - long2;
+ if (longDiff > 180)
+ longDiff -= 360;
+
+ // scale longDiff by cosine of average latitude
+ longDiff *= Math.cos(Math.PI / 180 * Math.abs((lat1 + lat2) / 2));
+
+ return (latDiff * latDiff) + (longDiff * longDiff);
+ }
+
+ public Coord makeBetweenPoint(Coord other, double fraction) {
+ return new Coord((int)(latitude + (other.latitude - latitude) * fraction),
+ (int)(longitude + (other.longitude - longitude) * fraction));
+ }
+
+
+ // returns bearing (in degrees) from current point to another point
+ public double bearingTo(Coord point) {
+ double lat1 = Utils.toRadians(latitude);
+ double lat2 = Utils.toRadians(point.latitude);
+ double lon1 = Utils.toRadians(longitude);
+ double lon2 = Utils.toRadians(point.longitude);
+
+ double dlon = lon2 - lon1;
+
+ double y = Math.sin(dlon) * Math.cos(lat2);
+ double x = Math.cos(lat1)*Math.sin(lat2) -
+ Math.sin(lat1)*Math.cos(lat2)*Math.cos(dlon);
+ return Math.atan2(y, x) * 180 / Math.PI;
+ }
+
+ /**
+ * Sort lexicographically by longitude, then latitude.
+ *
+ * This ordering is used for sorting entries in NOD3.
+ */
+ public int compareTo(Coord other) {
+ if (longitude == other.getLongitude())
+ if (latitude == other.getLatitude()) return 0;
+ else return latitude > other.getLatitude() ? 1 : -1;
+ else
+ return longitude > other.getLongitude()? 1: -1;
+ }
+
+ /**
+ * Returns a string representation of the object.
+ *
+ * @return a string representation of the object.
+ */
+ public String toString() {
+ return (latitude) + "/" + (longitude);
+ }
+
+ public String toDegreeString() {
+ Formatter fmt = new Formatter();
+ return fmt.format("%.5f/%.5f",
+ Utils.toDegrees(latitude),
+ Utils.toDegrees(longitude)).toString();
+ }
+
+ protected String toOSMURL(int zoom) {
+ return ("http://www.openstreetmap.org/?mlat=" +
+ new Formatter(Locale.ENGLISH).format("%.5f", Utils.toDegrees(latitude)) +
+ "&mlon=" +
+ new Formatter(Locale.ENGLISH).format("%.5f", Utils.toDegrees(longitude)) +
+ "&zoom=" +
+ zoom);
+ }
+
+ public String toOSMURL() {
+ return toOSMURL(17);
+ }
+
+}
diff --git a/src/uk/me/parabola/imgfmt/app/CoordNode.java b/src/uk/me/parabola/imgfmt/app/CoordNode.java
new file mode 100644
index 0000000..9e9872f
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/CoordNode.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 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: 13-Jul-2008
+ */
+package uk.me.parabola.imgfmt.app;
+
+/**
+ * A coordinate that is known to be a routing node. You can tell by the fact
+ * that getId() returns != 0.
+ *
+ * @author Steve Ratcliffe
+ */
+public class CoordNode extends Coord {
+ private final long id;
+
+ /**
+ * Construct from co-ordinates that are already in map-units.
+ *
+ * @param latitude The latitude in map units.
+ * @param longitude The longitude in map units.
+ * @param id The ID of this routing node.
+ * @param boundary This is a routing node on the boundary.
+ */
+ public CoordNode(int latitude, int longitude, long id, boolean boundary) {
+ super(latitude, longitude);
+ this.id = id;
+ setOnBoundary(boundary);
+ preserved(true);
+ }
+
+ public long getId() {
+ return id;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/Exit.java b/src/uk/me/parabola/imgfmt/app/Exit.java
new file mode 100644
index 0000000..ab3cbda
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/Exit.java
@@ -0,0 +1,67 @@
+/*
+ * 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: Jan 1, 2008
+ */
+package uk.me.parabola.imgfmt.app;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.lbl.ExitFacility;
+import uk.me.parabola.imgfmt.app.lbl.Highway;
+
+/**
+ * Represent a motorway exit
+ *
+ * @author Mark Burton
+ */
+public class Exit {
+
+ public final static String TAG_ROAD_REF = "exit:road_ref";
+ public final static String TAG_TO = "exit:to";
+ public final static String TAG_FACILITY = "exit:facility";
+
+ private final Highway highway;
+ private Label description;
+ private final List<ExitFacility> facilities = new ArrayList<ExitFacility>();
+
+ public Exit(Highway highway) {
+ this.highway = highway;
+ }
+
+ public void setDescription(Label description) {
+ this.description = description;
+ }
+
+ public void addFacility(ExitFacility facility) {
+ facilities.add(facility);
+ }
+
+ public boolean getOvernightParking() {
+ return false; // FIXME
+ }
+
+ public Highway getHighway() {
+ return highway;
+ }
+
+ public List<ExitFacility> getFacilities() {
+ return facilities;
+ }
+
+ public Label getDescription() {
+ return description;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/FileBackedImgFileWriter.java b/src/uk/me/parabola/imgfmt/app/FileBackedImgFileWriter.java
new file mode 100644
index 0000000..5a8d127
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/FileBackedImgFileWriter.java
@@ -0,0 +1,228 @@
+/*
+ * 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.imgfmt.app;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+
+import uk.me.parabola.imgfmt.MapFailedException;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+
+/**
+ * Write img file data to a temporary file. On a call to sync() the data
+ * is copied to the output channel.
+ *
+ * @author Steve Ratcliffe
+ */
+public class FileBackedImgFileWriter implements ImgFileWriter{
+ private final ImgChannel outputChan;
+ private final File tmpFile;
+ private final BufferedOutputStream file;
+ private final FileChannel tmpChannel;
+
+ public FileBackedImgFileWriter(ImgChannel chan, File outputDir) {
+ this.outputChan = chan;
+
+ try {
+ tmpFile = File.createTempFile("img", null, outputDir);
+ tmpFile.deleteOnExit();
+
+ FileOutputStream out = new FileOutputStream(tmpFile);
+ tmpChannel = out.getChannel();
+ file = new BufferedOutputStream(out, 16*1024);
+ } catch (IOException e) {
+ throw new MapFailedException("Could not create mdr temporary file");
+ }
+ }
+
+ /**
+ * Maps the temporary file and copies to the output channel.
+ *
+ * @throws IOException If there is an error writing.
+ */
+ public void sync() throws IOException {
+ file.close();
+
+ FileInputStream is = null;
+ try {
+ is = new FileInputStream(tmpFile);
+ FileChannel channel = is.getChannel();
+ channel.transferTo(0, channel.size(), outputChan);
+ channel.close();
+ } finally {
+ Utils.closeFile(is);
+ if (!tmpFile.delete())
+ System.err.println("Could not delete mdr img temporary file");
+ }
+ }
+
+ /**
+ * Get the position. Have to flush the buffer before getting the position.
+ *
+ * @return The logical position within the file.
+ */
+ public int position() {
+ try {
+ file.flush();
+ return (int) tmpChannel.position();
+ } catch (IOException e) {
+ return 0;
+ }
+ }
+
+ /**
+ * Set the position of the file.
+ * The buffer has to be flushed first.
+ *
+ * @param pos The new position in the file.
+ */
+ public void position(long pos) {
+ try {
+ file.flush();
+ tmpChannel.position(pos);
+ } catch (IOException e) {
+ throw new MapFailedException("Could not set position in mdr tmp file");
+ }
+ }
+
+ /**
+ * Write out a single byte.
+ *
+ * @param b The byte to write.
+ */
+ public void put(byte b) {
+ try {
+ file.write(b);
+ } catch (IOException e) {
+ throw new MapFailedException("could not write byte to mdr tmp file");
+ }
+ }
+
+ /**
+ * Write out two bytes. Can't use writeChar() since need to reverse the byte
+ * order.
+ *
+ * @param c The value to write.
+ */
+ public void putChar(char c) {
+ try {
+ file.write(c);
+ file.write(c >> 8);
+ } catch (IOException e) {
+ throw new MapFailedException("could not write char to mdr tmp file");
+ }
+ }
+
+ /**
+ * Write out three bytes. Done in the little endian byte order.
+ *
+ * @param val The value to write, only the bottom three bytes will be written.
+ */
+ public void put3(int val) {
+ try {
+ file.write(val);
+ file.write(val >> 8);
+ file.write(val >> 16);
+ } catch (IOException e) {
+ throw new MapFailedException("could not write3 to mdr tmp file");
+ }
+ }
+
+ /**
+ * Write out 4 byte value.
+ *
+ * @param val The value to write.
+ */
+ public void putInt(int val) {
+ try {
+ file.write(val);
+ file.write(val >> 8);
+ file.write(val >> 16);
+ file.write(val >> 24);
+ } catch (IOException e) {
+ throw new MapFailedException("could not write int to mdr tmp file");
+ }
+ }
+
+ /**
+ * Write out an arbitrary length sequence of bytes.
+ *
+ * @param val The values to write.
+ */
+ public void put(byte[] val) {
+ try {
+ file.write(val);
+ } catch (IOException e) {
+ throw new MapFailedException("could not write bytes to mdr tmp file");
+ }
+ }
+
+ /**
+ * Write out part of a byte array.
+ *
+ * @param src The array to take bytes from.
+ * @param start The start position.
+ * @param length The number of bytes to write.
+ */
+ public void put(byte[] src, int start, int length) {
+ try {
+ file.write(src, start, length);
+ } catch (IOException e) {
+ throw new MapFailedException("could not write bytes to mdr tmp file");
+ }
+ }
+
+ /**
+ * Write out a complete byte buffer.
+ *
+ * @param src The buffer to write.
+ */
+ public void put(ByteBuffer src) {
+ try {
+ file.flush();
+ tmpChannel.write(src);
+ } catch (IOException e) {
+ throw new MapFailedException("could not write buffer to mdr tmp file");
+ }
+ }
+
+ /**
+ * Returns the size of the file.
+ *
+ * @return The file size in bytes.
+ */
+ public long getSize() {
+ try {
+ file.flush();
+ return tmpChannel.size();
+ } catch (IOException e) {
+ throw new MapFailedException("could not get size of mdr tmp file");
+ }
+ }
+
+ /**
+ * Closes this stream and releases any system resources associated with it. If the stream is already closed then
+ * invoking this method has no effect.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ public void close() throws IOException {
+ outputChan.close();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/ImgFile.java b/src/uk/me/parabola/imgfmt/app/ImgFile.java
new file mode 100644
index 0000000..7b4180e
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/ImgFile.java
@@ -0,0 +1,105 @@
+/*
+ * 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: 03-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.log.Logger;
+
+/**
+ * Base class for all the img files. There is a common header that
+ * all the sub-files share. They also have means of reading and writing
+ * themselves.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class ImgFile implements Closeable {
+ private static final Logger log = Logger.getLogger(ImgFile.class);
+
+ private CommonHeader header;
+
+ private ImgFileWriter writer;
+ private ImgFileReader reader;
+
+ private boolean readable;
+ private boolean writable;
+
+ public void close() {
+ try {
+ sync();
+ } catch (IOException e) {
+ log.debug("could not sync file");
+ }
+ Utils.closeFile(writer);
+ Utils.closeFile(reader);
+ }
+
+ public int position() {
+ if (readable)
+ return (int) reader.position();
+ else
+ return writer.position();
+ }
+
+ protected CommonHeader getHeader() {
+ return header;
+ }
+
+ public long getSize() {
+ if (writable)
+ return writer.getSize();
+ throw new UnsupportedOperationException("getSize not implemented for read");
+ }
+
+ protected void position(long pos) {
+ writer.position(pos);
+ }
+
+ protected final void sync() throws IOException {
+ if (!writable)
+ return;
+ getWriter().sync();
+ }
+
+ protected ImgFileWriter getWriter() {
+ return writer;
+ }
+
+ protected void setWriter(ImgFileWriter writer) {
+ writable = true;
+ this.writer = writer;
+ }
+
+ protected ImgFileReader getReader() {
+ return reader;
+ }
+
+ protected void setReader(ImgFileReader reader) {
+ readable = true;
+ this.reader = reader;
+ }
+
+ protected final void setHeader(CommonHeader header) {
+ this.header = header;
+ }
+
+ protected boolean isWritable() {
+ return writable;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/ImgFileReader.java b/src/uk/me/parabola/imgfmt/app/ImgFileReader.java
new file mode 100644
index 0000000..6603128
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/ImgFileReader.java
@@ -0,0 +1,110 @@
+/*
+ * 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: 07-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app;
+
+import java.io.Closeable;
+
+import uk.me.parabola.imgfmt.ReadFailedException;
+
+/**
+ * For reading subfiles from the img. The focus of mkgmap is on writing,
+ * but some limited reading is needed for several operations.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface ImgFileReader extends Closeable {
+
+ /**
+ * Get the position. Needed because may not be reflected in the underlying
+ * file if being buffered.
+ *
+ * @return The logical position within the file.
+ */
+ public long position();
+
+ /**
+ * Set the position of the file.
+ * @param pos The new position in the file.
+ */
+ void position(long pos);
+
+ /**
+ * Read in a single byte.
+ * @return The byte that was read.
+ */
+ public byte get() throws ReadFailedException;
+
+ /**
+ * Read in two bytes. Done in the correct byte order.
+ * @return The 2 byte integer that was read.
+ */
+ public char getChar() throws ReadFailedException;
+
+ /**
+ * Get a 3byte signed quantity.
+ *
+ * @return The value read.
+ * @throws ReadFailedException When the file cannot be read.
+ */
+ public int get3() throws ReadFailedException;
+
+ /**
+ * Get a 3byte unsigned quantity.
+ *
+ * @return The value read.
+ * @throws ReadFailedException When the file cannot be read.
+ */
+ public int getu3() throws ReadFailedException;
+
+ /**
+ * Read in a 4 byte value.
+ * @return A 4 byte integer.
+ */
+ public int getInt() throws ReadFailedException;
+
+ /**
+ * Read a variable sized integer. The size is given.
+ * @param n The size of the integer to read. Must be 1 to 4.
+ * @return The integer which will not be sign extended if it is less
+ * than 4 bytes long.
+ */
+ public int getUint(int n) throws ReadFailedException;
+
+ /**
+ * Read in an arbitrary length sequence of bytes.
+ *
+ * @param len The number of bytes to read.
+ */
+ public byte[] get(int len) throws ReadFailedException;
+
+ /**
+ * Read a zero terminated string from the file.
+ * @return A string
+ * @throws ReadFailedException For failures.
+ */
+ public String getZString() throws ReadFailedException;
+
+ /**
+ * Read in a string of digits in the compressed base 11 format that is used
+ * for phone numbers in the POI section.
+ * @param delimiter This will replace all digit 11 characters. Usually a
+ * '-' to separate numbers in a telephone. No doubt there is a different
+ * standard in each country.
+ * @return A phone number possibly containing the delimiter character.
+ */
+ public String getBase11str(byte firstChar, char delimiter);
+}
diff --git a/src/uk/me/parabola/imgfmt/app/ImgFileWriter.java b/src/uk/me/parabola/imgfmt/app/ImgFileWriter.java
new file mode 100644
index 0000000..9a094c3
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/ImgFileWriter.java
@@ -0,0 +1,112 @@
+/*
+ * 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: 07-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Interface for writing structured data to an img file.
+ *
+ * Implementations will have a constructor that passes in a file channel that will eventually
+ * be written to. If the output is being buffered, then it should be written on a call to sync().
+ *
+ * @author Steve Ratcliffe
+ */
+public interface ImgFileWriter extends Closeable {
+ /**
+ * Called to write out any saved buffers. The strategy may write
+ * directly to the file in which case this would have nothing or
+ * little to do.
+ * @throws IOException If there is an error writing.
+ */
+ public void sync() throws IOException;
+
+ /**
+ * Get the position. Needed because may not be reflected in the underlying
+ * file if being buffered.
+ *
+ * @return The logical position within the file.
+ */
+ public int position();
+
+ /**
+ * Set the position of the file.
+ * @param pos The new position in the file.
+ */
+ void position(long pos);
+
+ /**
+ * Write out a single byte.
+ * @param b The byte to write.
+ */
+ public void put(byte b);
+
+ /**
+ * Write out two bytes. Done in the correct byte order.
+ * @param c The value to write.
+ */
+ public void putChar(char c);
+
+ /**
+ * Write out three bytes. Done in the correct byte order.
+ *
+ * @param val The value to write, only the bottom three bytes will be
+ * written.
+ */
+ public void put3(int val);
+
+ /**
+ * Write out 4 byte value.
+ * @param val The value to write.
+ */
+ public void putInt(int val);
+
+ /**
+ * Write out an arbitrary length sequence of bytes.
+ *
+ * @param val The values to write.
+ */
+ public void put(byte[] val);
+
+ /**
+ * Write out part of a byte array.
+ *
+ * @param src The array to take bytes from.
+ * @param start The start position.
+ * @param length The number of bytes to write.
+ */
+ public void put(byte[] src, int start, int length);
+
+ /**
+ * Write out a complete byte buffer.
+ *
+ * @param src The buffer to write.
+ */
+ public void put(ByteBuffer src);
+
+ /**
+ * Returns the size of the file.
+ *
+ * Note that this is not a general purpose routine and it may not be
+ * possible to give the correct answer at all times.
+ *
+ * @return The file size in bytes.
+ */
+ public long getSize();
+}
diff --git a/src/uk/me/parabola/imgfmt/app/ImgReader.java b/src/uk/me/parabola/imgfmt/app/ImgReader.java
new file mode 100644
index 0000000..6229ada
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/ImgReader.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app;
+
+import java.io.Closeable;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.util.Configurable;
+
+/**
+ * Base class for all the img sub file reading classes.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class ImgReader implements Closeable, Configurable {
+
+ private CommonHeader header;
+ private ImgFileReader reader;
+
+ public void close() {
+ Utils.closeFile(reader);
+ }
+
+ protected long position() {
+ return reader.position();
+ }
+
+ protected void position(long pos) {
+ reader.position(pos);
+ }
+
+ public CommonHeader getHeader() {
+ return header;
+ }
+
+ protected final void setHeader(CommonHeader header) {
+ this.header = header;
+ }
+
+ protected ImgFileReader getReader() {
+ return reader;
+ }
+
+ protected void setReader(ImgFileReader reader) {
+ this.reader = reader;
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/app/Label.java b/src/uk/me/parabola/imgfmt/app/Label.java
new file mode 100644
index 0000000..ad93db3
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/Label.java
@@ -0,0 +1,142 @@
+/*
+ * 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: 10-Jan-2007
+ */
+package uk.me.parabola.imgfmt.app;
+
+import java.util.regex.Pattern;
+
+import uk.me.parabola.imgfmt.app.labelenc.EncodedText;
+
+/**
+ * Labels are used for names of roads, points of interest etc.
+ *
+ * There are different storage formats.
+ *
+ * 1. A 6 bit compact uppercase ascii format, that has escape codes for some
+ * special characters.
+ *
+ * 2. An 8 bit format. This seems to be a fairly straightforward latin-1 like
+ * encoding with no tricks to reduce the amount of space required.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Label implements Comparable<Label> {
+
+ private final String text;
+
+ // The offset in to the data section.
+ private int offset;
+
+ public Label(String text) {
+ this.text = text;
+ }
+
+ public int getLength() {
+ if (text == null)
+ return 0;
+ else
+ return text.length();
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ // highway shields and "thin" separators
+ public final static Pattern SHIELDS = Pattern.compile("[\u0001-\u0006\u001b-\u001c]");
+
+ // "fat" separators
+ private final static Pattern SEPARATORS = Pattern.compile("[\u001d-\u001f]");
+
+ // two or more whitespace characters
+ private final static Pattern SQUASH_SPACES = Pattern.compile("\\s\\s+");
+
+ public static String stripGarminCodes(String s) {
+ if(s == null)
+ return null;
+ s = SHIELDS.matcher(s).replaceAll(""); // remove
+ s = SEPARATORS.matcher(s).replaceAll(" "); // replace with a space
+ s = SQUASH_SPACES.matcher(s).replaceAll(" "); // replace with a space
+ // a leading separator would have turned into a space so trim it
+ return s.trim();
+ }
+
+ public static String squashSpaces(String s) {
+ if(s == null || s.isEmpty())
+ return null;
+ return SQUASH_SPACES.matcher(s).replaceAll(" "); // replace with single space
+ }
+
+ /**
+ * The offset of this label in the LBL file. The first byte of this file
+ * is zero and an offset of zero means that the label has a zero length/is
+ * empty.
+ *
+ * @return The offset within the LBL file of this string.
+ */
+ public int getOffset() {
+ if (text == null || text.isEmpty())
+ return 0;
+ else
+ return offset;
+ }
+
+ public void setOffset(int offset) {
+ this.offset = offset;
+ }
+
+ /**
+ * Write this label to the given img file.
+ *
+ * @param writer The LBL file to write to.
+ * @param encText The encoded version of the text for this label.
+ */
+ public void write(ImgFileWriter writer, EncodedText encText) {
+ assert encText != null;
+
+ if (encText.getLength() > 0)
+ writer.put(encText.getCtext(), 0, encText.getLength());
+ }
+
+ /**
+ * String version of the label, for diagnostic purposes.
+ */
+ public String toString() {
+ return "[" + offset + "]" + text;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ return offset == ((Label) o).offset;
+
+ }
+
+ public int hashCode() {
+ return offset;
+ }
+
+ /**
+ * Note: this class has a natural ordering that is inconsistent with equals.
+ * (But perhaps it shouldn't?)
+ */
+ public int compareTo(Label other) {
+ if(this == other)
+ return 0;
+ return text.compareToIgnoreCase(other.text);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/Section.java b/src/uk/me/parabola/imgfmt/app/Section.java
new file mode 100644
index 0000000..d2ca13c
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/Section.java
@@ -0,0 +1,156 @@
+/*
+ * 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: Dec 15, 2007
+ */
+package uk.me.parabola.imgfmt.app;
+
+import java.io.IOException;
+
+/**
+ * Represents an item size the position where those items start and the
+ * total size of the section.
+ */
+public class Section {
+ private char itemSize;
+ private int size;
+ private int position;
+ private Section link;
+ private int extraValue;
+
+ public Section() {
+ }
+
+ public Section(char itemSize) {
+ this.itemSize = itemSize;
+ }
+
+ public Section(Section link, char itemSize) {
+ this.itemSize = itemSize;
+ this.link = link;
+ }
+
+ public Section(Section link) {
+ this.link = link;
+ }
+
+ public void inc() {
+ size += itemSize;
+ }
+
+ public char getItemSize() {
+ return itemSize;
+ }
+
+ public void setItemSize(char itemSize) {
+ this.itemSize = itemSize;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public void setSize(int size) {
+ this.size = size;
+ }
+
+ /**
+ * Get the start position of this section. If this is linked to another
+ * section, then we return the end address of that section.
+ * @return The first offset for this section.
+ */
+ public int getPosition() {
+ if (link != null)
+ return link.getEndPos();
+ return position;
+ }
+
+ public void setPosition(int position) {
+ this.position = position;
+ // Setting a position breaks the link
+ this.link = null;
+ }
+
+ /**
+ * Get the position of the end of the section.
+ * @return The offset of the end of the section relative to the beginning
+ * of the application file.
+ */
+ public int getEndPos() {
+ return getPosition() + size;
+ }
+
+ public String toString() {
+ return "pos=" + getPosition() + ", size=" + size + ", itemSize=" + itemSize;
+ }
+
+ /**
+ * Get the number of items in the section. This should only be called
+ * if the itemSize is set.
+ * @return The number of items in the section, or zero if this is not
+ * a fixed size item kind of section.
+ */
+ public int getNumItems() {
+ if (itemSize == 0)
+ return 0;
+
+ return size/ (int) itemSize;
+ }
+
+ protected int getExtraValue() {
+ return extraValue;
+ }
+
+ public void setExtraValue(int extraValue) {
+ this.extraValue = extraValue;
+ }
+
+ public void readSectionInfo(ImgFileReader reader, boolean withItemSize) {
+ setPosition(reader.getInt());
+ setSize(reader.getInt());
+ if (withItemSize)
+ setItemSize(reader.getChar());
+ }
+
+ public SectionWriter makeSectionWriter(ImgFileWriter writer) {
+ setPosition(writer.position());
+ return new SectionWriter(writer, this);
+ }
+
+ public void writeSectionInfo(ImgFileWriter writer) {
+ writeSectionInfo(writer, false);
+ }
+
+ public void writeSectionInfo(ImgFileWriter writer, boolean withItemSize) {
+ writeSectionInfo(writer, withItemSize, false);
+ }
+
+ public void writeSectionInfo(ImgFileWriter writer, boolean withItemSize, boolean withExtraValue) {
+ writer.putInt(getPosition());
+ writer.putInt(getSize());
+ if (withItemSize || getItemSize() > 0)
+ writer.putChar(getItemSize());
+ if (withExtraValue)
+ writer.putInt(getExtraValue());
+ }
+
+ public static void close(ImgFileWriter writer) {
+ assert writer instanceof SectionWriter;
+ try {
+ writer.close();
+ } catch (IOException e) {
+ // ignore as this is only for section writers.
+ }
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/SectionWriter.java b/src/uk/me/parabola/imgfmt/app/SectionWriter.java
new file mode 100644
index 0000000..126564a
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/SectionWriter.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2008 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: 19-Jul-2008
+ */
+package uk.me.parabola.imgfmt.app;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * A section writer wraps a regular writer so that all the offsets
+ * are relative to the start of a section.
+ *
+ * @author Steve Ratcliffe
+ */
+public class SectionWriter implements ImgFileWriter {
+
+ private final ImgFileWriter writer;
+ private final Section section;
+ private final int secStart;
+
+ public SectionWriter(ImgFileWriter writer, Section section) {
+ this.writer = writer;
+ this.secStart = section.getPosition();
+ this.section = section;
+ }
+
+ public void sync() throws IOException {
+ writer.sync();
+ }
+
+ /**
+ * Note that this does not close the underlying file.
+ */
+ public void close() {
+ if (section != null)
+ section.setSize(writer.position() - secStart);
+ //writer.close();
+ }
+
+ public int position() {
+ return writer.position() - secStart;
+ }
+
+ public void position(long pos) {
+ writer.position(pos + secStart);
+ }
+
+ public void put(byte b) {
+ writer.put(b);
+ }
+
+ public void putChar(char c) {
+ writer.putChar(c);
+ }
+
+ public void put3(int val) {
+ writer.put3(val);
+ }
+
+ public void putInt(int val) {
+ writer.putInt(val);
+ }
+
+ public void put(byte[] val) {
+ writer.put(val);
+ }
+
+ public void put(byte[] src, int start, int length) {
+ writer.put(src, start, length);
+ }
+
+ public void put(ByteBuffer src) {
+ writer.put(src);
+ }
+
+ public long getSize() {
+ throw new UnsupportedOperationException("Cannot get size at this point");
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/Writeable.java b/src/uk/me/parabola/imgfmt/app/Writeable.java
new file mode 100644
index 0000000..273db7c
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/Writeable.java
@@ -0,0 +1,10 @@
+package uk.me.parabola.imgfmt.app;
+
+/**
+ * Interface that can be implemented by objects that write to an ImgFile.
+ * @author Thomas LuÃnig
+ */
+public interface Writeable {
+
+ public void write(ImgFileWriter writer);
+}
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/AnyCharsetDecoder.java b/src/uk/me/parabola/imgfmt/app/labelenc/AnyCharsetDecoder.java
new file mode 100644
index 0000000..c9b4761
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/AnyCharsetDecoder.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.labelenc;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.Charset;
+
+/**
+ * Decodes strings from format 9 and a given character set to java strings.
+ */
+public class AnyCharsetDecoder implements CharacterDecoder {
+ private final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ private boolean needReset;
+ private final Charset charSet;
+
+ public AnyCharsetDecoder(String charsetName) {
+ charSet = Charset.forName(charsetName);
+ }
+
+ public boolean addByte(int b) {
+ if (b == 0) {
+ needReset = true;
+ return true;
+ }
+
+ if (needReset) {
+ needReset = false;
+ out.reset();
+ }
+
+ out.write(b);
+ return false;
+ }
+
+ public DecodedText getText() {
+ byte[] ba = out.toByteArray();
+ return new DecodedText(ba, charSet);
+ }
+
+ public void reset() {
+ needReset = false;
+ out.reset();
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/AnyCharsetEncoder.java b/src/uk/me/parabola/imgfmt/app/labelenc/AnyCharsetEncoder.java
new file mode 100644
index 0000000..c7e0165
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/AnyCharsetEncoder.java
@@ -0,0 +1,130 @@
+/*
+ * 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: 31-Oct-2007
+ */
+package uk.me.parabola.imgfmt.app.labelenc;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.util.Arrays;
+import java.util.Locale;
+
+/**
+ * Convert text to a specified charset. This is used when you give a
+ * charset name on the command line to convert to.
+ *
+ * @author Steve Ratcliffe
+ */
+public class AnyCharsetEncoder extends BaseEncoder implements CharacterEncoder {
+
+ private final CharsetEncoder encoder;
+ private final Transliterator transliterator;
+
+ public AnyCharsetEncoder(String cs, Transliterator transliterator) {
+ this.transliterator = transliterator;
+ prepareForCharacterSet(cs);
+ if (isCharsetSupported()) {
+ encoder = Charset.forName(cs).newEncoder();
+ encoder.onUnmappableCharacter(CodingErrorAction.REPORT);
+ } else {
+ encoder = null;
+ }
+ }
+
+ public EncodedText encodeText(String text) {
+ if (text == null)
+ return NO_TEXT;
+
+ if (!isCharsetSupported())
+ return simpleEncode(text);
+
+ String ucText;
+ if (isUpperCase())
+ ucText = text.toUpperCase(Locale.ENGLISH);
+ else
+ ucText = text;
+
+ // Allocate a buffer for the encoded text. This will be large enough in almost all cases,
+ // but the code below allocates more space if necessary.
+ ByteBuffer outBuf = ByteBuffer.allocate(ucText.length() + 20);
+ CharBuffer charBuffer = CharBuffer.wrap(ucText);
+
+ CoderResult result;
+
+ do {
+ result = encoder.encode(charBuffer, outBuf, true);
+
+ if (result.isUnmappable()) {
+ // There is a character that cannot be represented in the target code page.
+ // Read the character(s), transliterate them, and add them to the output.
+ // We then continue onward with the rest of the string.
+ String s;
+ if (result.length() == 1) {
+ s = String.valueOf(charBuffer.get());
+ } else {
+ // Don't know under what circumstances this will be called and may not be the
+ // correct thing to do when it does happen.
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < result.length(); i++)
+ sb.append(charBuffer.get());
+
+ s = sb.toString();
+ }
+
+ s = transliterator.transliterate(s);
+
+ // Make sure that there is enough space for the transliterated string
+ while (outBuf.limit() < outBuf.position() + s.length())
+ outBuf = reallocBuf(outBuf);
+
+ for (int i = 0; i < s.length(); i++)
+ outBuf.put((byte) s.charAt(i));
+
+ } else if (result == CoderResult.OVERFLOW) {
+ // Ran out of space in the output
+ outBuf = reallocBuf(outBuf);
+ }
+ } while (result != CoderResult.UNDERFLOW);
+
+ // We need it to be null terminated but also to trim any extra memory from the allocated
+ // buffer.
+ byte[] res = Arrays.copyOf(outBuf.array(), outBuf.position() + 1);
+ return new EncodedText(res, res.length);
+ }
+
+ /**
+ * Allocate a new byte buffer that has more space.
+ *
+ * It will have the same contents as the existing one and the same position, so you can
+ * continue writing to it.
+ *
+ * @param bb The original byte buffer.
+ * @return A new byte buffer with the same contents with more space that you can continue
+ * writing to.
+ */
+ private ByteBuffer reallocBuf(ByteBuffer bb) {
+ byte[] newbuf = Arrays.copyOf(bb.array(), bb.capacity() * 2);
+ return ByteBuffer.wrap(newbuf, bb.position(), newbuf.length - bb.position());
+ }
+
+ public void setUpperCase(boolean upperCase) {
+ super.setUpperCase(upperCase);
+ transliterator.forceUppercase(upperCase);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/BaseEncoder.java b/src/uk/me/parabola/imgfmt/app/labelenc/BaseEncoder.java
new file mode 100644
index 0000000..fd06368
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/BaseEncoder.java
@@ -0,0 +1,75 @@
+/*
+ * 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: 14-Jan-2007
+ */
+package uk.me.parabola.imgfmt.app.labelenc;
+
+import java.nio.charset.Charset;
+
+import uk.me.parabola.log.Logger;
+
+/**
+ * Useful routines for the other encoders.
+ * Provides some default behaviour when a conversion is not possible for
+ * example.
+ *
+ * @author Steve Ratcliffe
+ */
+public class BaseEncoder {
+ private static final Logger log = Logger.getLogger(BaseEncoder.class);
+
+ protected static final EncodedText NO_TEXT = new EncodedText(null, 0);
+
+ private boolean charsetSupported = true;
+
+ // Whether to uppercase the labels or not. Default is true because many
+ // GPS devices do not display labels in lower case.
+ private boolean upperCase;
+
+ protected boolean isCharsetSupported() {
+ return charsetSupported;
+ }
+
+ protected void prepareForCharacterSet(String name) {
+ if (Charset.isSupported(name)) {
+ charsetSupported = true;
+ } else {
+ charsetSupported = false;
+ log.warn("requested character set not found " + name);
+ }
+ }
+
+ protected EncodedText simpleEncode(String text) {
+ if (text == null)
+ return NO_TEXT;
+
+ char[] in = text.toCharArray();
+ byte[] out = new byte[in.length + 1];
+
+ int off = 0;
+ for (char c : in)
+ out[off++] = (byte) (c & 0xff);
+
+ return new EncodedText(out, out.length);
+ }
+
+ public boolean isUpperCase() {
+ return upperCase;
+ }
+
+ public void setUpperCase(boolean upperCase) {
+ this.upperCase = upperCase;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/CharacterDecoder.java b/src/uk/me/parabola/imgfmt/app/labelenc/CharacterDecoder.java
new file mode 100644
index 0000000..7d34832
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/CharacterDecoder.java
@@ -0,0 +1,54 @@
+/*
+ * 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: 14-Jan-2007
+ */
+package uk.me.parabola.imgfmt.app.labelenc;
+
+/**
+ * Interface for decoding characters for use in the Label section of a .img
+ * file.
+ *
+ * These things are stateful, you add bytes read from the file to them and
+ * they return a status when a complete label has been obtained. At this point
+ * you retrieve the text.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface CharacterDecoder {
+
+ /**
+ * Add a byte to this decoder. This will be saved until a complete
+ * label string has been detected.
+ *
+ * @param b The byte read from the lbl file.
+ * @return True if a label string is finished and is ready to be retrieved
+ * via the {@link #getText} method.
+ */
+ public boolean addByte(int b);
+
+ /**
+ * Get the valid text. This is guaranteed to be encoded as utf-8.
+ *
+ * @return The byte array and length as an EncodedText struct.
+ */
+ public DecodedText getText();
+
+ /**
+ * Resets the state. This should be called for example if the reader is
+ * jumping to a new place in the file and cannot guarantee that the
+ * previous label was fully read.
+ */
+ public void reset();
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/CharacterEncoder.java b/src/uk/me/parabola/imgfmt/app/labelenc/CharacterEncoder.java
new file mode 100644
index 0000000..8d884e5
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/CharacterEncoder.java
@@ -0,0 +1,37 @@
+/*
+ * 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: 14-Jan-2007
+ */
+package uk.me.parabola.imgfmt.app.labelenc;
+
+/**
+ * Interface for encoding characters for use in the Label section of a .img
+ * file.
+ *
+ * Older units are only able to display uppercase ascii characters. Newer ones
+ * can also display latin1 characters and perhaps lowercase too. I believe
+ * that it is possible to buy Japanese units that display Japanese characters
+ * too.
+ *
+ * So we need different implementations to deal with all this. It is made
+ * harder because the possibilities are not known. Many experimental
+ * implementations may be needed before settling on a good one.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface CharacterEncoder {
+
+ public EncodedText encodeText(String text);
+}
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/CodeFunctions.java b/src/uk/me/parabola/imgfmt/app/labelenc/CodeFunctions.java
new file mode 100644
index 0000000..9d4c916
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/CodeFunctions.java
@@ -0,0 +1,161 @@
+/*
+ * 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: Jan 1, 2008
+ */
+package uk.me.parabola.imgfmt.app.labelenc;
+
+import uk.me.parabola.imgfmt.ExitException;
+
+/**
+ * @author Steve Ratcliffe
+ */
+public class CodeFunctions {
+ // Label encoding length
+ public static final int ENCODING_FORMAT6 = 6;
+ private static final int ENCODING_FORMAT9 = 9;
+ private static final int ENCODING_FORMAT10 = 10;
+
+ private int codepage;
+ private int encodingType;
+ private CharacterEncoder encoder;
+ private CharacterDecoder decoder;
+
+ protected void setEncoder(CharacterEncoder encoder) {
+ this.encoder = encoder;
+ }
+
+ public CharacterEncoder getEncoder() {
+ return encoder;
+ }
+
+ protected void setDecoder(CharacterDecoder decoder) {
+ this.decoder = decoder;
+ }
+
+ public CharacterDecoder getDecoder() {
+ return decoder;
+ }
+
+ public int getEncodingType() {
+ return encodingType;
+ }
+
+ protected void setEncodingType(int encodingType) {
+ this.encodingType = encodingType;
+ }
+
+ public int getCodepage() {
+ return codepage;
+ }
+
+ protected void setCodepage(int codepage) {
+ this.codepage = codepage;
+ }
+
+ /**
+ * Create a CharacterEncoder for the given charset option. Note that this
+ * routine also writes to the lblHeader parameter to set the encoding type.
+ * @param charset The mkgmap command line option to be interpreted.
+ * @return The various character set parameters that will be needed.
+ */
+ public static CodeFunctions createEncoderForLBL(String charset) {
+ CodeFunctions funcs = new CodeFunctions();
+ if ("ascii".equals(charset)) {
+ funcs.setEncodingType(ENCODING_FORMAT6);
+ funcs.setEncoder(new Format6Encoder());
+ funcs.setDecoder(new Format6Decoder());
+ } else if ("cp1252".equals(charset) || "latin1".equals(charset)) {
+ funcs.setEncodingType(ENCODING_FORMAT9);
+ funcs.setEncoder(new AnyCharsetEncoder("cp1252", new TableTransliterator("latin1")));
+ funcs.setDecoder(new AnyCharsetDecoder("cp1252"));
+ funcs.setCodepage(1252);
+ } else if ("cp65001".equals(charset) || "unicode".equals(charset)) {
+ funcs.setEncodingType(ENCODING_FORMAT10);
+ funcs.setEncoder(new Utf8Encoder());
+ funcs.setDecoder(new Utf8Decoder());
+ funcs.setCodepage(65001);
+ } else if ("simple8".equals(charset)) {
+ funcs.setEncodingType(ENCODING_FORMAT9);
+ funcs.setEncoder(new Simple8Encoder());
+ } else if ("cp932".equals(charset) || "ms932".equals(charset)) {
+ funcs.setEncodingType(ENCODING_FORMAT10);
+ funcs.setEncoder(new AnyCharsetEncoder("ms932", new SparseTransliterator("nomacron")));
+ funcs.setDecoder(new AnyCharsetDecoder("ms932"));
+ funcs.setCodepage(932);
+ } else {
+ funcs.setEncodingType(ENCODING_FORMAT9);
+ funcs.setDecoder(new AnyCharsetDecoder(charset));
+ funcs.setEncoder(new AnyCharsetEncoder(charset, new TableTransliterator("ascii")));
+ funcs.setCodepage(guessCodepage(charset));
+ }
+
+ return funcs;
+ }
+
+ /**
+ * Sets encoding functions for a given format and code page. This is used
+ * when reading from an existing file.
+ *
+ * @param format The format from the lbl header.
+ * @param codePage The codepage found in the header.
+ * @return The various character set parameters that will be needed.
+ */
+ public static CodeFunctions createEncoderForLBL(int format, int codePage) {
+ CodeFunctions funcs;
+
+ if (format == ENCODING_FORMAT6) {
+ funcs = createEncoderForLBL("ascii");
+ } else {
+ funcs = createEncoderForLBL("cp" + codePage);
+ }
+
+ return funcs;
+ }
+
+ /**
+ * Guess the code page from the given charset. Only works with things
+ * like cp1252, windows-1252 and some well known ones.
+ * @param charset The charset that was given.
+ */
+ private static int guessCodepage(String charset) {
+ String cs = charset.toLowerCase();
+ if (cs.startsWith("cp")) {
+ try {
+ return Integer.parseInt(charset.substring(2));
+ } catch (NumberFormatException e) {
+ // wasn't in the right form
+ throw new ExitException("Invalid character set: " + cs);
+ }
+ } else if (cs.startsWith("windows-")) {
+ try {
+ return Integer.parseInt(charset.substring(8));
+ } catch (NumberFormatException e) {
+ // wasn't in the right form to guess
+ throw new ExitException("Invalid character set: " + cs);
+ }
+ } else if (cs.equals("latin1")) {
+ return 1252;
+ }
+ return 0;
+ }
+
+ public static CharacterEncoder getDefaultEncoder() {
+ return new Format6Encoder();
+ }
+
+ public static CharacterDecoder getDefaultDecoder() {
+ return new Format6Decoder();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/DecodedText.java b/src/uk/me/parabola/imgfmt/app/labelenc/DecodedText.java
new file mode 100644
index 0000000..c6e1687
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/DecodedText.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.labelenc;
+
+import java.nio.charset.Charset;
+
+/**
+ * Holds information about a label that has been read in from an img file.
+ *
+ * @author Steve Ratcliffe
+ */
+public class DecodedText {
+ /** The actual text as a proper java string */
+ private final String text;
+
+ /**
+ * Used during reading, the offset of the next label is at next byte that
+ * is added to the decoder plus this value. The value is usually negative
+ * or zero.
+ */
+ private int offsetAdjustment;
+
+ public DecodedText(byte[] ba, Charset charSet) {
+ text = new String(ba, 0, ba.length, charSet);
+ }
+
+
+ public String getText() {
+ return text;
+ }
+
+ public int getOffsetAdjustment() {
+ return offsetAdjustment;
+ }
+
+ public void setOffsetAdjustment(int offsetAdjustment) {
+ this.offsetAdjustment = offsetAdjustment;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/EncodedText.java b/src/uk/me/parabola/imgfmt/app/labelenc/EncodedText.java
new file mode 100644
index 0000000..0beb5a5
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/EncodedText.java
@@ -0,0 +1,64 @@
+/*
+ * 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: 14-Jan-2007
+ */
+package uk.me.parabola.imgfmt.app.labelenc;
+
+import java.util.Arrays;
+
+/**
+ * Holds the bytes and length of an encoded character string used in a label.
+ * The length of the byte array may be longer than the part that is actually
+ * used, so the length property should always be used.
+ *
+ * Class is immutable.
+ *
+ * @author Steve Ratcliffe
+ */
+public class EncodedText {
+ private final byte[] ctext;
+ private final int length;
+
+ public EncodedText(byte[] buf, int len) {
+ this.ctext = buf;
+ this.length = len;
+ }
+
+ public byte[] getCtext() {
+ return ctext;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ EncodedText that = (EncodedText) o;
+
+ if (length != that.length) return false;
+ if (!Arrays.equals(ctext, that.ctext)) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result = Arrays.hashCode(ctext);
+ result = 31 * result + length;
+ return result;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/Format6Decoder.java b/src/uk/me/parabola/imgfmt/app/labelenc/Format6Decoder.java
new file mode 100644
index 0000000..25d6fe9
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/Format6Decoder.java
@@ -0,0 +1,129 @@
+package uk.me.parabola.imgfmt.app.labelenc;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.Charset;
+
+/**
+ * Convert the 6-bit label format back to a java string.
+ */
+public class Format6Decoder implements CharacterDecoder {
+ private final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ private boolean needReset;
+
+ private boolean symbol;
+ private boolean lowerCaseOrSeparator;
+
+ private int store;
+ private int nbits;
+
+ private final Charset charset = Charset.forName("ascii");
+
+ public boolean addByte(int in) {
+ int b = 0xff & in; //wipe out high bits (in case of negative byte)
+
+ if (needReset) {
+ needReset = false;
+ out.reset();
+ }
+
+ store <<= 8;
+ store |= b;
+ nbits += 8;
+
+ while (nbits >= 6) {
+ convertChar((store >> (nbits-6)) & 0x3f);
+
+ if (needReset) {
+ // Skip until the next byte boundary. Note that may mean that
+ // we skip more or *less* than 6 bits.
+ if (nbits > 8)
+ nbits = 8;
+ else
+ nbits = 0;
+
+ break;
+ } else
+ nbits -= 6;
+ }
+
+ return needReset;
+ }
+
+ public DecodedText getText() {
+ byte[] ba = out.toByteArray();
+ DecodedText text = new DecodedText(ba, charset);
+
+ assert nbits == 0 || nbits == 8;
+ // If there is a byte left inside the decoder then we have to let our
+ // caller know, so that they can adjust the offset of the next label
+ // appropriately.
+ if (nbits == 8)
+ text.setOffsetAdjustment(-1);
+ return text;
+ }
+
+ public void reset() {
+ needReset = false;
+ out.reset();
+ store = 0;
+ nbits = 0;
+ }
+
+
+ /**
+ * Convert a single 6 bit quantity into a character.
+ * @param b The six bit int.
+ */
+ private void convertChar(int b) {
+ if (b > 0x2f) {
+ needReset = true;
+ return;
+ }
+
+ char c;
+
+ if (symbol) {
+ symbol = false;
+ c = Format6Encoder.SYMBOLS.charAt(b);
+ }
+ else if(lowerCaseOrSeparator) {
+ lowerCaseOrSeparator = false;
+ if(b == 0x2b || b == 0x2c) {
+ c = (char)(b - 0x10); // "thin" separator
+ }
+ else if(Character.isLetter(b)) {
+ // lower case letter
+ c = Character.toLowerCase(Format6Encoder.LETTERS.charAt(b));
+ }
+ else {
+ // not a letter so just use as is (could be a digit)
+ c = Format6Encoder.LETTERS.charAt(b);
+ }
+ }
+ else {
+ switch(b) {
+ case 0x1B:
+ // next char is lower case or a separator
+ lowerCaseOrSeparator = true;
+ return;
+
+ case 0x1C:
+ // next char is symbol
+ symbol = true;
+ return;
+
+ case 0x1D:
+ case 0x1E:
+ case 0x1F:
+ // these are separators - use as is
+ c = (char)b;
+ break;
+
+ default:
+ c = Format6Encoder.LETTERS.charAt(b);
+ break;
+ }
+ }
+ out.write(c);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java b/src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java
new file mode 100644
index 0000000..92b575f
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/Format6Encoder.java
@@ -0,0 +1,151 @@
+/*
+ * 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: 14-Jan-2007
+ */
+package uk.me.parabola.imgfmt.app.labelenc;
+
+import java.util.Locale;
+
+/**
+ * Format according to the '6 bit' .img format. The text is first upper
+ * cased. Any letter with a diacritic or accent is replaced with its base
+ * letter.
+ *
+ * For example KörnerstraÃe would become KORNERSTRASSE,
+ * ÅÃpovská would become RIPOVSKA etc.
+ *
+ * I believe that some Garmin units are only capable of showing uppercase
+ * ascii characters, so this will be the default.
+ *
+ * @author Steve Ratcliffe
+ * @see <a href="http://garmin-img.sf.net">Garmin IMG File Format</a>
+ */
+public class Format6Encoder extends BaseEncoder implements CharacterEncoder {
+
+ // This is 0x1b is the source document, but the accompanying code uses
+ // the value 0x1c, which seems to work.
+ private static final int SYMBOL_SHIFT = 0x1c;
+
+ public static final String LETTERS =
+ " ABCDEFGHIJKLMNO" + // 0x00-0x0F
+ "PQRSTUVWXYZxx " + // 0x10-0x1F
+ "0123456789\u0001\u0002\u0003\u0004\u0005\u0006"; // 0x20-0x2F
+
+ public static final String SYMBOLS =
+ "@!\"#$%&'()*+,-./" + // 0x00-0x0F
+ "xxxxxxxxxx:;<=>?" + // 0x10-0x1F
+ "xxxxxxxxxxx[\\]^_"; // 0x20-0x2F
+
+ private final Transliterator transliterator = new TableTransliterator("ascii");
+
+ /**
+ * Encode the text into the 6 bit format. See the class level notes.
+ *
+ * @param text The original text, which can contain non-ascii characters.
+ * @return Encoded form of the text. Only uppercase ascii characters and
+ * some escape sequences will be present.
+ */
+ public EncodedText encodeText(String text) {
+ if (text == null)
+ return NO_TEXT;
+
+ String s = transliterator.transliterate(text).toUpperCase(Locale.ENGLISH);
+
+ // Allocate more than enough space on average for the label.
+ // if you overdo it then it will waste a lot of space , but
+ // not enough and there will be an error
+ byte[] buf = new byte[2 * s.length() + 4];
+ int off = 0;
+
+ for (char c : s.toCharArray()) {
+
+ if (c == ' ') {
+ put6(buf, off++, 0);
+ } else if (c >= 'A' && c <= 'Z') {
+ put6(buf, off++, c - 'A' + 1);
+ } else if (c >= '0' && c <= '9') {
+ put6(buf, off++, c - '0' + 0x20);
+ } else if (c == 0x1b || c == 0x1c) {
+ put6(buf, off++, 0x1b);
+ put6(buf, off++, c + 0x10);
+ } else if (c >= 0x1d && c <= 0x1f) {
+ put6(buf, off++, c);
+ } else if (c >= 1 && c <= 6) {
+ // Highway shields
+ put6(buf, off++, 0x29 + c);
+ } else {
+ off = shiftedSymbol(buf, off, c);
+ }
+ }
+
+ buf = put6(buf, off++, 0xff);
+
+ int len = ((off - 1) * 6) / 8 + 1;
+
+ return new EncodedText(buf, len);
+ }
+
+ /**
+ * Certain characters have to be represented by two 6byte quantities. This
+ * routine sorts these out.
+ *
+ * @param buf The buffer to write into.
+ * @param startOffset The offset to start writing to in the output buffer.
+ * @param c The character that we are decoding.
+ * @return The final offset. This will be unchanged if there was nothing
+ * written because the character does not have any representation.
+ */
+ private int shiftedSymbol(byte[] buf, int startOffset, char c) {
+ int off = startOffset;
+ int ind = SYMBOLS.indexOf(c);
+ if (ind >= 0) {
+ put6(buf, off++, SYMBOL_SHIFT);
+ put6(buf, off++, ind);
+ }
+ return off;
+ }
+
+ /**
+ * Each character is packed into 6 bits. This keeps track of everything so
+ * that the character can be put into the right place in the byte array.
+ *
+ * @param buf The buffer to populate.
+ * @param off The character offset, that is the number of the six bit
+ * character.
+ * @param c The character to place.
+ */
+ private byte[] put6(byte[] buf, int off, int c) {
+ int bitOff = off * 6;
+
+ // The byte offset
+ int byteOff = bitOff/8;
+
+ // The offset within the byte
+ int shift = bitOff - 8*byteOff;
+
+ int mask = 0xfc >> shift;
+ buf[byteOff] |= ((c << 2) >> shift) & mask;
+
+ // IF the shift is greater than two we have to put the rest in the
+ // next byte.
+ if (shift > 2) {
+ mask = 0xfc << (8 - shift);
+ buf[byteOff + 1] = (byte) (((c << 2) << (8 - shift)) & mask);
+ }
+
+ return buf;
+ }
+
+}
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/Simple8Encoder.java b/src/uk/me/parabola/imgfmt/app/labelenc/Simple8Encoder.java
new file mode 100644
index 0000000..fa45e1d
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/Simple8Encoder.java
@@ -0,0 +1,30 @@
+/*
+ * 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: 14-Jan-2007
+ */
+package uk.me.parabola.imgfmt.app.labelenc;
+
+/**
+ * An encoder that just takes the lower 8 bits of the char and uses that
+ * without any character set conversion. Useful for testing mainly (only?).
+ *
+ * @author Steve Ratcliffe
+ */
+public class Simple8Encoder extends BaseEncoder implements CharacterEncoder {
+
+ public EncodedText encodeText(String text) {
+ return simpleEncode(text);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/SparseTransliterator.java b/src/uk/me/parabola/imgfmt/app/labelenc/SparseTransliterator.java
new file mode 100644
index 0000000..fa2d6b5
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/SparseTransliterator.java
@@ -0,0 +1,72 @@
+/*
+ * 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.imgfmt.app.labelenc;
+
+import java.util.Locale;
+
+import uk.me.parabola.log.Logger;
+
+/**
+ * A sparse character-based transliterator that leaves most characters unchanged.
+ *
+ */
+public class SparseTransliterator implements Transliterator {
+ private static final Logger log = Logger.getLogger(SparseTransliterator.class);
+
+ private final boolean useNoMacron;
+ private boolean forceUppercase;
+
+ public SparseTransliterator(String targetCharset) {
+ useNoMacron = (targetCharset.equals("nomacron")) ? true : false;
+ }
+
+ /**
+ * Convert a string into a string that uses only acceptable characters.
+ *
+ * @param s The original string. It can use any unicode character. Can be null in which case null will
+ * be returned.
+ * @return A string that uses only acceptable characters.
+ */
+ public String transliterate(String s) {
+ if (s == null)
+ return null;
+
+ StringBuilder sb = new StringBuilder(s.length() + 5);
+ for (char c : s.toCharArray()) {
+ if (useNoMacron) {
+ // Only macrons are modified, all other chars (including non-ascii) are left unchanged
+ if (c == 0x101) // Unicode Character 'LATIN SMALL LETTER A WITH MACRON' (U+0101)
+ c = 'a';
+ if (c == 0x113) // Unicode Character 'LATIN SMALL LETTER E WITH MACRON' (U+0113)
+ c = 'e';
+ if (c == 0x12b) // Unicode Character 'LATIN SMALL LETTER I WITH MACRON' (U+012B)
+ c = 'i';
+ if (c == 0x14d) // Unicode Character 'LATIN SMALL LETTER O WITH MACRON' (U+014D)
+ c = 'o';
+ if (c == 0x16b) // Unicode Character 'LATIN SMALL LETTER U WITH MACRON' (U+016B)
+ c = 'u';
+ }
+ sb.append(c);
+ }
+
+ String text = sb.toString();
+ if (forceUppercase)
+ text = text.toUpperCase(Locale.ENGLISH);
+ return text;
+ }
+
+ public void forceUppercase(boolean uc) {
+ forceUppercase = uc;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/TableCreator.java b/src/uk/me/parabola/imgfmt/app/labelenc/TableCreator.java
new file mode 100644
index 0000000..6e0ac03
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/TableCreator.java
@@ -0,0 +1,55 @@
+/*
+ * 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: 04-Nov-2007
+ */
+package uk.me.parabola.imgfmt.app.labelenc;
+
+import java.io.PrintStream;
+
+/**
+ * Call this with a unicode row number and it will produce an empty table
+ * that can be modified.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TableCreator {
+ public static void main(String[] args) {
+ int row = Integer.parseInt(args[0]);
+
+ PrintStream out = System.out;
+
+ out.println("");
+ out.println("# This is table for transliterating characters in the range");
+ out.format( "# from U+%02x00 to U+%02xff\n", row, row);
+ out.println("#");
+ out.println("# The first column is the unicode character and the second");
+ out.println("# column is the transliteration of that character to ascii characters.");
+ out.println("# One or more characters can be used, for example for a character æ which");
+ out.println("# is a combined a and e you could write 'ae' (without the quotes) as the ");
+ out.println("# transliteration.");
+ out.println("#");
+ out.println("# There are languages where this will not work very well, in case");
+ out.println("# another approach should be tried.");
+ out.println("#");
+ out.println("# Any line can be deleted and will default to a '?' character");
+ out.println("#");
+ out.println("");
+
+ for (int i = 0; i < 256; i++) {
+ out.format("U+%02x%02x ? # character %c\n",
+ row, i, (char) (row*256+i));
+ }
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/TableTransliterator.java b/src/uk/me/parabola/imgfmt/app/labelenc/TableTransliterator.java
new file mode 100644
index 0000000..492e916
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/TableTransliterator.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.imgfmt.app.labelenc;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.Locale;
+
+import uk.me.parabola.log.Logger;
+
+/**
+ * A simple transliterator that transliterates character by character based
+ * on pre-prepared tables. It is not context sensitive - the same input character
+ * always produces the same output character(s), so the results are
+ * not very good for languages where that is important.
+ *
+ * Tables are only read when needed, so for a typical map only a small
+ * number of files will actually be read.
+ */
+public class TableTransliterator implements Transliterator {
+ private static final Logger log = Logger.getLogger(TableTransliterator.class);
+
+ private final String[][] rows = new String[256][];
+ private final boolean useLatin;
+ private boolean forceUppercase;
+
+ public TableTransliterator(String targetCharset) {
+ if (targetCharset.equals("latin1") || targetCharset.equals("cp1252"))
+ useLatin = true;
+ else
+ useLatin = false;
+ }
+
+ /**
+ * Convert a string into a string that uses only ascii characters.
+ *
+ * @param s The original string. It can use any unicode character. Can be null in which case null will
+ * be returned.
+ * @return A string that uses only ascii characters that is a transcription or
+ * transliteration of the original string.
+ */
+ public String transliterate(String s) {
+ if (s == null)
+ return null;
+
+ StringBuilder sb = new StringBuilder(s.length() + 5);
+ for (char c : s.toCharArray()) {
+ if (c <= (useLatin? 0xff: 0x7f)) {
+ sb.append(c);
+ } else {
+ int row = c >>> 8;
+
+ String[] rowmap = rows[row];
+ if (rowmap == null)
+ rowmap = loadRow(row);
+ sb.append(rowmap[c & 0xff]);
+ }
+ }
+
+ String text = sb.toString();
+ if (forceUppercase)
+ text = text.toUpperCase(Locale.ENGLISH);
+ return text;
+ }
+
+ public void forceUppercase(boolean uc) {
+ forceUppercase = uc;
+ }
+
+ /**
+ * Load one row of characters. This means unicode characters that are of the
+ * form U+RRXX where RR is the row.
+ *
+ * @param row Row number 0-255.
+ * @return An array of strings, one for each character in the row. If there is
+ * no ascii representation then a '?' character will fill that
+ * position.
+ */
+ private String[] loadRow(int row) {
+ if (rows[row] != null)
+ return rows[row];
+
+ String[] newRow = new String[256];
+ rows[row] = newRow;
+
+ // Default all to a question mark
+ Arrays.fill(newRow, "?");
+
+ // If we are doing latin1, see if there is a specific file for latin
+ // characters first.
+ if (useLatin) {
+ String name = String.format("/chars/latin1/row%02x.trans", row);
+ readCharFile(name, newRow);
+ }
+
+ // Fill in any remaining characters from the ascii mappings.
+ String name = String.format("/chars/ascii/row%02x.trans", row);
+ readCharFile(name, newRow);
+
+ return newRow;
+ }
+
+ private void readCharFile(String name, String[] newRow) {
+ InputStream is = getClass().getResourceAsStream(name);
+ if (is == null)
+ return;
+
+ try {
+ BufferedReader br = new BufferedReader(new InputStreamReader(is, "utf-8"));
+
+ String line;
+ while ((line = br.readLine()) != null) {
+ line = line.trim();
+ if (line.isEmpty() || line.charAt(0) == '#')
+ continue;
+
+ String[] fields = line.split("\\s+");
+ if (fields.length < 2)
+ continue;
+
+ String upoint = fields[0];
+ String translation = fields[1];
+
+ if ("?".equals(translation)) continue;
+ if (upoint.length() != 6 || upoint.charAt(0) != 'U') continue;
+
+ // The first field must look like 'U+RRXX', we extract the XX part
+ int index = Integer.parseInt(upoint.substring(4), 16);
+ if (newRow[index].equals("?")) {
+ if (forceUppercase)
+ newRow[index] = translation.toUpperCase(Locale.ENGLISH);
+ else
+ newRow[index] = translation;
+ }
+ }
+ } catch (IOException e) {
+ log.error("Could not read character translation table");
+ }
+ }
+
+}
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/Transliterator.java b/src/uk/me/parabola/imgfmt/app/labelenc/Transliterator.java
new file mode 100644
index 0000000..e9ba915
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/Transliterator.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.labelenc;
+
+/**
+ * Interface for transliterator functions.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface Transliterator {
+ /**
+ * Convert a string into a string that uses only ascii or latin1 characters.
+ *
+ * @param s The original string. It can use any unicode character. Can be null in which
+ * case null will be returned.
+ * @return A string that uses a restricted subset of characters (ascii or
+ * latin) that is a transliterated form of the input string.
+ */
+ public String transliterate(String s);
+
+ /**
+ * Force the use of uppercase in this transliterator.
+ * Note that it is normal to set this.
+ */
+ public void forceUppercase(boolean uc);
+}
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/Utf8Decoder.java b/src/uk/me/parabola/imgfmt/app/labelenc/Utf8Decoder.java
new file mode 100644
index 0000000..73345fc
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/Utf8Decoder.java
@@ -0,0 +1,77 @@
+/*
+ * 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: Feb 19, 2008
+ */
+package uk.me.parabola.imgfmt.app.labelenc;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.Charset;
+
+/**
+ * Decoder for labels in utf-8, note that I am not actually sure that any
+ * map uses utf-8.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Utf8Decoder implements CharacterDecoder {
+ private final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ private boolean needreset;
+
+ private final Charset charset = Charset.forName("utf-8");
+
+ /**
+ * Add a byte to this decoder. This will be saved until a complete
+ * label string has been detected.
+ *
+ * @param b The byte read from the lbl file.
+ * @return True if a label string is finished and is ready to be retrieved
+ * via the {@link #getText} method.
+ */
+ public boolean addByte(int b) {
+ if (b == 0) {
+ needreset = true;
+ out.write(0);
+ return true;
+ }
+
+ if (needreset) {
+ out.reset();
+ needreset = false;
+ }
+
+ out.write(b);
+ return false;
+ }
+
+ /**
+ * Get the valid text. This is guaranteed to be encoded as utf-8.
+ *
+ * @return The byte array and length as an EncodedText struct.
+ */
+ public DecodedText getText() {
+ byte[] ba = out.toByteArray();
+ return new DecodedText(ba, charset);
+ }
+
+ /**
+ * Resets the state. This should be called for example if the reader is
+ * jumping to a new place in the file and cannot guarantee that the previous
+ * label was fully read.
+ */
+ public void reset() {
+ needreset = false;
+ out.reset();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/Utf8Encoder.java b/src/uk/me/parabola/imgfmt/app/labelenc/Utf8Encoder.java
new file mode 100644
index 0000000..53e9aaf
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/Utf8Encoder.java
@@ -0,0 +1,54 @@
+/*
+ * 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: Feb 19, 2008
+ */
+package uk.me.parabola.imgfmt.app.labelenc;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Locale;
+
+/**
+ * Encoder for labels in utf-8, note that I am not actually sure that this
+ * is in fact used anywhere.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Utf8Encoder extends BaseEncoder implements CharacterEncoder {
+
+ public EncodedText encodeText(String text) {
+ if (text == null)
+ return NO_TEXT;
+
+ String uctext;
+ if (isUpperCase())
+ uctext = text.toUpperCase(Locale.ENGLISH);
+ else
+ uctext = text;
+
+ EncodedText et;
+ try {
+ byte[] buf = uctext.getBytes("utf-8");
+ byte[] res = new byte[buf.length + 1];
+ System.arraycopy(buf, 0, res, 0, buf.length);
+ res[buf.length] = 0;
+ et = new EncodedText(res, res.length);
+ } catch (UnsupportedEncodingException e) {
+ // As utf-8 must be supported, this can't happen
+ byte[] buf = uctext.getBytes();
+ et = new EncodedText(buf, buf.length);
+ }
+ return et;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/package.html b/src/uk/me/parabola/imgfmt/app/labelenc/package.html
new file mode 100644
index 0000000..cc5eb43
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/labelenc/package.html
@@ -0,0 +1,5 @@
+<body>
+<h3>Label encoding routines</h3>
+This package holds routines that encode the labels in the LBL section.
+There are both useful and experimental schemes here.
+</body>
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/City.java b/src/uk/me/parabola/imgfmt/app/lbl/City.java
new file mode 100644
index 0000000..c48babd
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/City.java
@@ -0,0 +1,164 @@
+/*
+ * 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: Jan 1, 2008
+ */
+package uk.me.parabola.imgfmt.app.lbl;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+
+/**
+ * A city is in a region. It also has (or can have anyway) a reference to
+ * an indexed point within the map itself.
+ *
+ * @author Steve Ratcliffe
+ */
+public class City {
+ private static final int POINT_REF = 0x8000;
+ private static final int REGION_IS_COUNTRY = 0x4000;
+
+ private int index = -1;
+
+ private final Region region;
+ private final Country country;
+
+ // This determines if a label is being used or a subdivision and point
+ // combo.
+ private boolean pointRef;
+
+ // The location of the city. These could both be zero if we are using a
+ // label instead.
+ private Subdivision subdivision;
+ private byte pointIndex;
+
+
+ // You can have either a label or a subdivision and point. This will be
+ // null if the location is being specified.
+ private Label label;
+
+ public City(Region region) {
+ this.region = region;
+ this.country = null;
+ }
+
+ public City(Country country) {
+ this.country = country;
+ this.region = null;
+ }
+
+ void write(ImgFileWriter writer) {
+ //writer.put3()
+ if (pointRef) {
+ // System.err.println("City point = " + (int)pointIndex + " div = " + subdivision.getNumber());
+ writer.put(pointIndex);
+ writer.putChar((char)subdivision.getNumber());
+ } else {
+ writer.put3(label.getOffset());
+ }
+
+ char info;
+ if(region != null)
+ info = (char) (region.getIndex() & 0x3fff);
+ else
+ info = (char) (REGION_IS_COUNTRY | (country.getIndex() & 0x3fff));
+ if (pointRef)
+ info |= POINT_REF;
+
+ writer.putChar(info);
+ }
+
+ public int getIndex() {
+ if (index == -1)
+ throw new IllegalStateException("Offset not known yet.");
+ return index;
+ }
+
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
+ public void setLabel(Label label) {
+ pointRef = false;
+ this.label = label;
+ }
+
+ public void setPointIndex(byte pointIndex) {
+ pointRef = true;
+ this.pointIndex = pointIndex;
+ }
+
+ public void setSubdivision(Subdivision subdivision) {
+ pointRef = true;
+ this.subdivision = subdivision;
+ }
+
+ public String getName() {
+ if (label == null)
+ return "";
+ return label.getText();
+ }
+
+ public int getLblOffset() {
+ if (label == null)
+ return 0;
+ return label.getOffset();
+ }
+
+ public String toString() {
+ String result = "";
+ if(label != null)
+ result += label.getText();
+ if (subdivision != null)
+ result += " " + subdivision.getNumber() + "/" + pointIndex;
+ if(country != null)
+ result += " in country " + (0 + country.getIndex());
+ if(region != null)
+ result += " in region " + (0 + region.getIndex());
+
+ return result;
+ }
+
+ public int getSubdivNumber() {
+ return subdivision.getNumber();
+ }
+
+ public int getPointIndex() {
+ return pointIndex;
+ }
+
+ /**
+ * Get the region or country number.
+ * @return The region number if there is one, else the country number
+ * with a flag bit set to indicate that it is one.
+ */
+ public int getRegionCountryNumber() {
+ if (region == null) {
+ if (country != null)
+ return country.getIndex() | 0x4000;
+ } else {
+ return region.getIndex();
+ }
+ return 0;
+ }
+
+ public int getRegionNumber() {
+ return region == null? 0: region.getIndex();
+ }
+
+ public int getCountryNumber() {
+ return country != null ? country.getIndex() : 0;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/Country.java b/src/uk/me/parabola/imgfmt/app/lbl/Country.java
new file mode 100644
index 0000000..2e6272e
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/Country.java
@@ -0,0 +1,55 @@
+/*
+ * 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: Jan 1, 2008
+ */
+package uk.me.parabola.imgfmt.app.lbl;
+
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * A country contains one or more regions.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Country {
+ // The country number. This is not recorded in the file
+ private char index;
+ private Label label;
+
+ public Country(int index) {
+ this.index = (char) index;
+ }
+
+ void write(ImgFileWriter writer) {
+ writer.put3(label.getOffset());
+ }
+
+ public char getIndex() {
+ return index;
+ }
+
+ public void setLabel(Label label) {
+ this.label = label;
+ }
+
+ public Label getLabel() {
+ return label;
+ }
+
+ public void setIndex(int index) {
+ this.index = (char) index;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/ExitFacility.java b/src/uk/me/parabola/imgfmt/app/lbl/ExitFacility.java
new file mode 100644
index 0000000..a869a27
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/ExitFacility.java
@@ -0,0 +1,73 @@
+/*
+ * 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: Jan 1, 2008
+ */
+package uk.me.parabola.imgfmt.app.lbl;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+
+/**
+ * Represent a facility at a motorway exit
+ *
+ * @author Mark Burton
+ */
+public class ExitFacility {
+
+ private final int index;
+ private final Label description;
+ private final int type; // truck stop - 24 hour diesel + food
+ private final int direction; // undefined
+ private final int facilities; // none
+ private final boolean last;
+
+ public ExitFacility(int type, char direction, int facilities, Label description, boolean last, int index) {
+ this.type = type;
+ this.direction = directionCode(direction);
+ this.facilities = facilities;
+ this.description = description;
+ this.last = last;
+ this.index = index;
+ }
+
+ void write(ImgFileWriter writer) {
+ int word = 0;
+ word |= description.getOffset(); // 0:21 = label offset
+ // 22 = unknown
+ if(last)
+ word |= 1 << 23; // 23 = last facility for this exit
+ word |= type << 24; // 24:27 = 4 bit type
+ // 28 = unknown
+ word |= direction << 29; // 29:31 = 3 bit direction
+ writer.putChar((char)word);
+ writer.putChar((char)(word >> 16));
+ writer.put((byte)facilities);
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public boolean getOvernightParking() {
+ return false;
+ }
+
+ private int directionCode(char direction) {
+ int code = "NSEWIOB".indexOf(direction);
+ if(code < 0)
+ code = 7; // undefined
+ return code;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/Highway.java b/src/uk/me/parabola/imgfmt/app/lbl/Highway.java
new file mode 100644
index 0000000..57ed3d9
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/Highway.java
@@ -0,0 +1,101 @@
+/*
+ * 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: Jan 1, 2008
+ */
+package uk.me.parabola.imgfmt.app.lbl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+
+/**
+ * A highway is in a region.
+ *
+ * @author Mark Burton
+ */
+public class Highway {
+
+ class ExitPoint implements Comparable<ExitPoint> {
+ final String name;
+ final byte index;
+ final Subdivision div;
+ public ExitPoint(String name, byte index, Subdivision div) {
+ this.name = name;
+ this.index = index;
+ this.div = div;
+ }
+
+ public int compareTo(ExitPoint o) {
+ return name.compareTo(o.name);
+ }
+ }
+
+ private final int index;
+
+ private final Region region;
+
+ private final List<ExitPoint> exits = new ArrayList<ExitPoint>();
+
+ private Label label;
+
+ private int extraDataOffset; // in 3-byte records - 1 based
+
+ public Highway(Region region, int index) {
+ this.region = region;
+ this.index = index;
+ }
+
+ void write(ImgFileWriter writer, boolean extraData) {
+ if(extraData) {
+ writer.put((byte)0);
+ writer.putChar(region == null? 0 : region.getIndex());
+ Collections.sort(exits);
+ for(ExitPoint ep : exits) {
+ writer.put(ep.index);
+ writer.putChar((char)ep.div.getNumber());
+ }
+ }
+ else {
+ assert extraDataOffset != 0;
+ writer.put3(label.getOffset());
+ writer.putChar((char)extraDataOffset);
+ writer.put((byte)0); // unknown (setting any of 0x3f stops exits being found)
+ }
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public void setLabel(Label label) {
+ this.label = label;
+ }
+
+ public void setExtraDataOffset(int extraDataOffset) {
+ this.extraDataOffset = extraDataOffset / 3 + 1;
+ }
+
+ public int getExtraDataSize() {
+ return (1 + exits.size()) * 3;
+ }
+
+ public void addExitPoint(String name, int index, Subdivision div) {
+ exits.add(new ExitPoint(name, (byte)index, div));
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java b/src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java
new file mode 100644
index 0000000..d486b63
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java
@@ -0,0 +1,225 @@
+/*
+ * 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: 03-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app.lbl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.MapFailedException;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.BufferedImgFileWriter;
+import uk.me.parabola.imgfmt.app.Exit;
+import uk.me.parabola.imgfmt.app.ImgFile;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.labelenc.BaseEncoder;
+import uk.me.parabola.imgfmt.app.labelenc.CharacterEncoder;
+import uk.me.parabola.imgfmt.app.labelenc.CodeFunctions;
+import uk.me.parabola.imgfmt.app.labelenc.EncodedText;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.log.Logger;
+
+/**
+ * The file that holds all the labels for the map.
+ *
+ * Would be quite simple, but there are a number of sections that hold country,
+ * region, city, etc. records.
+ *
+ * To begin with I shall only support regular labels.
+ *
+ * @author Steve Ratcliffe
+ */
+public class LBLFile extends ImgFile {
+ private static final Logger log = Logger.getLogger(LBLFile.class);
+
+ private CharacterEncoder textEncoder = CodeFunctions.getDefaultEncoder();
+
+ private final Map<EncodedText, Label> labelCache = new HashMap<EncodedText, Label>();
+
+ private final LBLHeader lblHeader = new LBLHeader();
+
+ private final PlacesFile places = new PlacesFile();
+ private Sort sort;
+
+ // Shift value for the label offset.
+ private final int offsetMultiplier = 1;
+
+ public LBLFile(ImgChannel chan, Sort sort) {
+ this.sort = sort;
+ lblHeader.setSort(sort);
+ lblHeader.setOffsetMultiplier(offsetMultiplier);
+ setHeader(lblHeader);
+
+ setWriter(new BufferedImgFileWriter(chan));
+
+ position(LBLHeader.HEADER_LEN + lblHeader.getSortDescriptionLength());
+
+ // The zero offset is for no label.
+ getWriter().put((byte) 0);
+ alignForNext();
+
+ places.init(this, lblHeader.getPlaceHeader());
+ places.setSort(sort);
+ }
+
+ public void write() {
+ writeBody();
+ }
+
+ public void writePost() {
+ // Now that the body is written all the required offsets will be set up
+ // inside the header, so we can go back and write it.
+ ImgFileWriter writer = getWriter();
+ getHeader().writeHeader(writer);
+
+ // Text can be put between the header and the body of the file.
+ writer.put(Utils.toBytes(sort.getDescription()));
+ writer.put((byte) 0);
+ assert writer.position() == LBLHeader.HEADER_LEN + lblHeader.getSortDescriptionLength();
+ }
+
+ private void writeBody() {
+ // The label section has already been written, but we need to record
+ // its size before doing anything else.
+ lblHeader.setLabelSize(getWriter().position() - (LBLHeader.HEADER_LEN + lblHeader.getSortDescriptionLength()));
+ places.write(getWriter());
+ }
+
+ public void setCharacterType(String cs, boolean forceUpper) {
+ log.info("encoding type " + cs);
+ CodeFunctions cfuncs = CodeFunctions.createEncoderForLBL(cs);
+
+ lblHeader.setEncodingType(cfuncs.getEncodingType());
+ textEncoder = cfuncs.getEncoder();
+ if (forceUpper && textEncoder instanceof BaseEncoder) {
+ BaseEncoder baseEncoder = (BaseEncoder) textEncoder;
+ baseEncoder.setUpperCase(true);
+ }
+ }
+
+ public void setEncoder(int encodingType, int codepage ) {
+ CodeFunctions cfuncs = CodeFunctions.createEncoderForLBL(encodingType, codepage);
+
+ lblHeader.setEncodingType(cfuncs.getEncodingType());
+ textEncoder = cfuncs.getEncoder();
+ }
+
+ /**
+ * Add a new label with the given text. Labels are shared, so that identical
+ * text is always represented by the same label.
+ *
+ * @param text The text of the label, it will be in uppercase.
+ * @return A reference to the created label.
+ */
+ public Label newLabel(String text) {
+ EncodedText encodedText = textEncoder.encodeText(text);
+ Label l = labelCache.get(encodedText);
+ if (l == null) {
+ l = new Label(text);
+ labelCache.put(encodedText, l);
+
+ l.setOffset(getNextLabelOffset());
+ l.write(getWriter(), encodedText);
+
+ alignForNext();
+
+ if (l.getOffset() > 0x3fffff)
+ throw new MapFailedException("Overflow of LBL section");
+ }
+
+ return l;
+ }
+
+ /**
+ * Align for the next label.
+ *
+ * Only has any effect when offsetMultiplier is not zero.
+ */
+ private void alignForNext() {
+ // Align ready for next label
+ while ((getCurrentLabelOffset() & ((1 << offsetMultiplier) - 1)) != 0)
+ getWriter().put((byte) 0);
+ }
+
+ private int getNextLabelOffset() {
+ return getCurrentLabelOffset() >> offsetMultiplier;
+ }
+
+ private int getCurrentLabelOffset() {
+ return position() - (LBLHeader.HEADER_LEN + lblHeader.getSortDescriptionLength());
+ }
+
+ public POIRecord createPOI(String name) {
+ return places.createPOI(name);
+ }
+
+ public POIRecord createExitPOI(String name, Exit exit) {
+ return places.createExitPOI(name, exit);
+ }
+
+ public POIIndex createPOIIndex(String name, int poiIndex, Subdivision group, int type) {
+ return places.createPOIIndex(name, poiIndex, group, type);
+ }
+
+ public Country createCountry(String name, String abbr) {
+ return places.createCountry(name, abbr);
+ }
+
+ public Region createRegion(Country country, String region, String abbr) {
+ return places.createRegion(country, region, abbr);
+ }
+
+ public City createCity(Region region, String city, boolean unique) {
+ return places.createCity(region, city, unique);
+ }
+
+ public City createCity(Country country, String city, boolean unique) {
+ return places.createCity(country, city, unique);
+ }
+
+ public Zip createZip(String code) {
+ return places.createZip(code);
+ }
+
+ public Highway createHighway(Region region, String name) {
+ return places.createHighway(region, name);
+ }
+
+ public ExitFacility createExitFacility(int type, char direction, int facilities, String description, boolean last) {
+ return places.createExitFacility(type, direction, facilities, description, last);
+ }
+
+ public void allPOIsDone() {
+ places.allPOIsDone();
+ }
+
+ public void setSort(Sort sort) {
+ this.sort = sort;
+ lblHeader.setSort(sort);
+ places.setSort(sort);
+ }
+
+ public int numCities() {
+ return places.numCities();
+ }
+
+ public int numZips() {
+ return places.numZips();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/LBLFileReader.java b/src/uk/me/parabola/imgfmt/app/lbl/LBLFileReader.java
new file mode 100644
index 0000000..ba2d9e7
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/LBLFileReader.java
@@ -0,0 +1,552 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.lbl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.app.BufferedImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgFile;
+import uk.me.parabola.imgfmt.app.ImgFileReader;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.labelenc.CharacterDecoder;
+import uk.me.parabola.imgfmt.app.labelenc.CodeFunctions;
+import uk.me.parabola.imgfmt.app.labelenc.DecodedText;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+
+/**
+ * The file that holds all the labels for the map.
+ *
+ * There are also a number of sections that hold country,
+ * region, city, etc. records.
+ *
+ * The main focus of mkgmap is creating files, there are plenty of applications
+ * that read and display the data, reading is implemented only to the
+ * extent required to support creating the various auxiliary files etc.
+ *
+ * @author Steve Ratcliffe
+ */
+public class LBLFileReader extends ImgFile {
+ private static final Label NULL_LABEL = new Label("");
+
+ private CharacterDecoder textDecoder = CodeFunctions.getDefaultDecoder();
+
+ private final LBLHeader header = new LBLHeader();
+
+ private final Map<Integer, Label> labels = new HashMap<Integer, Label>();
+ private final Map<Integer, POIRecord> pois = new HashMap<Integer, POIRecord>();
+ private final List<Country> countries = new ArrayList<Country>();
+ private final List<Region> regions = new ArrayList<Region>();
+ private final Map<Integer, Zip> zips = new HashMap<Integer, Zip>();
+ private final List<City> cities = new ArrayList<City>();
+
+ public LBLFileReader(ImgChannel chan) {
+ setHeader(header);
+
+ setReader(new BufferedImgFileReader(chan));
+ header.readHeader(getReader());
+ int offsetMultiplier = header.getOffsetMultiplier();
+ CodeFunctions funcs = CodeFunctions.createEncoderForLBL(
+ header.getEncodingType(), header.getCodePage());
+ textDecoder = funcs.getDecoder();
+
+ readLables(offsetMultiplier);
+
+ readCountries();
+ readRegions();
+
+ readCities();
+ readZips();
+ readPoiInfo();
+ }
+
+ /**
+ * Get a label by its offset in the label area.
+ * @param offset The offset in the label section. The offset 0 always
+ * is an empty string.
+ * @return The label including its text.
+ */
+ public Label fetchLabel(int offset) {
+ Label label = labels.get(offset);
+ if (label == null) {
+ assert offset == 0 : "Invalid label offset found " + offset;
+ return NULL_LABEL;
+ }
+
+ return label;
+ }
+
+ /**
+ * Get a list of cites. This is not cached here.
+ * @return A list of City objects.
+ */
+ public List<City> getCities() {
+ return cities;
+ }
+
+ public List<Country> getCountries() {
+ return Collections.unmodifiableList(countries);
+ }
+
+ public List<Region> getRegions() {
+ return Collections.unmodifiableList(regions);
+ }
+
+ public List<Zip> getZips() {
+ return new ArrayList<Zip>(zips.values());
+ }
+
+ /**
+ * Return POI information.
+ * @param offset The offset of the poi information in the header.
+ * @return Returns a poi record at the given offset. Returns null if
+ * there isn't one at that offset (probably a bug if that does happen though...).
+ */
+ public POIRecord fetchPoi(int offset) {
+ return pois.get(offset);
+ }
+
+ /**
+ * Read a cache the countries. These are used when reading cities.
+ */
+ private void readCountries() {
+ ImgFileReader reader = getReader();
+
+ PlacesHeader placeHeader = header.getPlaceHeader();
+
+ countries.add(null); // 1 based indexes
+
+ int start = placeHeader.getCountriesStart();
+ int end = placeHeader.getCountriesEnd();
+
+ reader.position(start);
+ int index = 1;
+ while (reader.position() < end) {
+ int offset = reader.getu3();
+ Label label = fetchLabel(offset);
+
+ if (label != null) {
+ Country country = new Country(index);
+ country.setLabel(label);
+ countries.add(country);
+ }
+ index++;
+ }
+ }
+
+ /**
+ * Read an cache the regions. These are used when reading cities.
+ */
+ private void readRegions() {
+ ImgFileReader reader = getReader();
+
+ PlacesHeader placeHeader = header.getPlaceHeader();
+
+ int start = placeHeader.getRegionsStart();
+ int end = placeHeader.getRegionsEnd();
+
+ regions.add(null);
+
+ reader.position(start);
+ int index = 1;
+ while (reader.position() < end) {
+ int country = reader.getChar();
+ int offset = reader.getu3();
+ Label label = fetchLabel(offset);
+ if (label != null) {
+ Region region = new Region(countries.get(country));
+ region.setIndex(index);
+ region.setLabel(label);
+
+ regions.add(region);
+ }
+
+ index++;
+ }
+ }
+
+ /**
+ * Read in the city section and cache the results here. They are needed
+ * to read in the POI properties section.
+ */
+ private void readCities() {
+ PlacesHeader placeHeader = header.getPlaceHeader();
+ int start = placeHeader.getCitiesStart();
+ int end = placeHeader.getCitiesEnd();
+
+ ImgFileReader reader = getReader();
+
+ // Since cities are indexed starting from 1, we add a null one at index 0
+
+ reader.position(start);
+ int index = 1;
+ while (reader.position() < end) {
+ // First is either a label offset or a point/subdiv combo, we
+ // don't know until we have read further
+ int label = reader.getu3();
+ int info = reader.getChar();
+
+ City city;
+ if ((info & 0x4000) == 0) {
+ Region region = regions.get(info & 0x3fff);
+ city = new City(region);
+ } else {
+ Country country = countries.get(info & 0x3fff);
+ city = new City(country);
+ }
+
+ city.setIndex(index);
+ if ((info & 0x8000) == 0) {
+ city.setSubdivision(Subdivision.createEmptySubdivision(1));
+ Label label1 = labels.get(label & 0x3fffff);
+ city.setLabel(label1);
+ } else {
+ // Has subdiv/point index
+ int pointIndex = label & 0xff;
+ int subdiv = (label >> 8) & 0xffff;
+ city.setPointIndex((byte) pointIndex);
+ city.setSubdivision(Subdivision.createEmptySubdivision(subdiv));
+ }
+ cities.add(city);
+
+ index++;
+ }
+ }
+
+ /**
+ * Read and cache all the labels.
+ *
+ * Note: It is pretty pointless saving the whole label rather than just
+ * the text, except that other objects take a Label. Perhaps this can
+ * be changed.
+ */
+ private void readLables(int mult) {
+ ImgFileReader reader = getReader();
+
+ labels.put(0, NULL_LABEL);
+
+ int start = header.getLabelStart();
+ int size = header.getLabelSize();
+
+ reader.position(start + mult);
+ int labelOffset = mult;
+
+ for (int off = mult; off <= size; off++) {
+ byte b = reader.get();
+ if (textDecoder.addByte(b)) {
+ labelOffset = saveLabel(labelOffset, off, mult);
+
+ // If there is an offset multiplier greater than one then padding will be used to
+ // ensure that the labels are on suitable boundaries. We must skip over any such padding.
+ while ((labelOffset & (mult - 1)) != 0) {
+ textDecoder.reset();
+ if (labelOffset <= off) {
+ // In the 6bit decoder, we may have already read the (first) padding byte and so
+ // we increment the label offset without reading anything more.
+ labelOffset++;
+ } else {
+ reader.get();
+ //noinspection AssignmentToForLoopParameter
+ off++;
+ labelOffset++;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * We have a label and we need to save it.
+ *
+ * @param labelOffset The offset of the label we are about to save.
+ * @param currentOffset The current offset that last read from.
+ * @param multiplier The label offset multiplier.
+ * @return The offset of the next label.
+ */
+ private int saveLabel(int labelOffset, int currentOffset, int multiplier) {
+ DecodedText encText = textDecoder.getText();
+ String text = encText.getText();
+
+ Label label = new Label(text);
+ assert (labelOffset & (multiplier - 1)) == 0;
+ int adustedOffset = labelOffset / multiplier;
+ label.setOffset(adustedOffset);
+ labels.put(adustedOffset, label);
+
+ // Calculate the offset of the next label. This is not always
+ // the current offset + 1 because there may be bytes left
+ // inside the decoder.
+ return currentOffset + 1 + encText.getOffsetAdjustment();
+ }
+
+
+ /**
+ * Reads the zips.
+ */
+ private void readZips() {
+ ImgFileReader reader = getReader();
+
+ PlacesHeader placeHeader = header.getPlaceHeader();
+ int start = placeHeader.getZipsStart();
+ int end = placeHeader.getZipsEnd();
+
+ reader.position(start);
+
+ int zipIndex = 1;
+ while (reader.position() < end) {
+ int lblOffset = reader.get3();
+
+ Zip zip = new Zip();
+ zip.setLabel(fetchLabel(lblOffset));
+ zip.setIndex(zipIndex);
+
+ zips.put(zip.getIndex(), zip);
+
+ zipIndex++;
+ }
+ }
+
+ /**
+ * Read all the POI information.
+ * This will create a POIRecord, but we just get the name at the minute.
+ *
+ * TODO: not finished
+ */
+ private void readPoiInfo() {
+ ImgFileReader reader = getReader();
+
+ PlacesHeader placeHeader = header.getPlaceHeader();
+ int poiGlobalFlags = placeHeader.getPOIGlobalFlags();
+
+ int start = placeHeader.getPoiPropertiesStart();
+ int end = placeHeader.getPoiPropertiesEnd();
+
+ reader.position(start);
+
+ PoiMasks localMask = makeLocalMask(placeHeader);
+
+ while (reader.position() < end) {
+ int poiOffset = position() - start;
+ int val = reader.getu3();
+ int labelOffset = val & 0x3fffff;
+
+
+ boolean override = (val & 0x800000) != 0;
+
+ POIRecord poi = new POIRecord();
+ poi.setLabel(fetchLabel(labelOffset));
+
+ // We have what we want, but now have to find the start of the
+ // next record as they are not fixed length.
+ int flags;
+ boolean hasStreet;
+ boolean hasStreetNum;
+ boolean hasCity;
+ boolean hasZip;
+ boolean hasPhone;
+ boolean hasHighwayExit;
+ boolean hasTides;
+
+ if (override) {
+ flags = reader.get();
+
+ hasStreetNum = (flags & localMask.streetNumMask) != 0;
+ hasStreet = (flags & localMask.streetMask) != 0;
+ hasCity = (flags & localMask.cityMask) != 0;
+ hasZip = (flags & localMask.zipMask) != 0;
+ hasPhone = (flags & localMask.phoneMask) != 0;
+ hasHighwayExit = (flags & localMask.highwayExitMask) != 0;
+ hasTides = (flags & localMask.tidesMask) != 0;
+ } else {
+ flags = poiGlobalFlags;
+
+ hasStreetNum = (flags & POIRecord.HAS_STREET_NUM) != 0;
+ hasStreet = (flags & POIRecord.HAS_STREET) != 0;
+ hasCity = (flags & POIRecord.HAS_CITY) != 0;
+ hasZip = (flags & POIRecord.HAS_ZIP) != 0;
+ hasPhone = (flags & POIRecord.HAS_PHONE) != 0;
+ hasHighwayExit = (flags & POIRecord.HAS_EXIT) != 0;
+ hasTides = (flags & POIRecord.HAS_TIDE_PREDICTION) != 0;
+ }
+
+ if (hasStreetNum) {
+ byte b = reader.get();
+ String num = reader.getBase11str(b, '-');
+ if (num.isEmpty()) {
+ int mpoffset = (b << 16) & 0xff0000;
+ mpoffset |= reader.getChar() & 0xffff;
+
+ poi.setComplexPhoneNumber(fetchLabel(mpoffset));
+ } else {
+ poi.setSimpleStreetNumber(num);
+ }
+ }
+
+ if (hasStreet) {
+ int streetNameOffset = reader.getu3();// label for street
+ Label label = fetchLabel(streetNameOffset);
+ poi.setStreetName(label);
+ }
+
+ if (hasCity) {
+ int cityIndex;
+
+ if (placeHeader.getNumCities() > 0xFF)
+ cityIndex = reader.getChar();
+ else
+ cityIndex = reader.get() & 0xff;
+
+ poi.setCity(cities.get(cityIndex-1));
+ }
+
+ if (hasZip) {
+ int zipIndex;
+ if (placeHeader.getNumZips() > 0xff)
+ zipIndex = reader.getChar();
+ else
+ zipIndex = reader.get() & 0xff;
+ poi.setZip(zips.get(zipIndex-1));
+ }
+
+ if (hasPhone) {
+ byte b = reader.get();
+ String num = reader.getBase11str(b, '-');
+ if (num.isEmpty()) {
+ // Yes this is a bit strange it is a byte followed by a char
+ int mpoffset = (b << 16) & 0xff0000;
+ mpoffset |= reader.getChar() & 0xffff;
+
+ Label label = fetchLabel(mpoffset);
+ poi.setComplexPhoneNumber(label);
+ } else {
+ poi.setSimplePhoneNumber(num);
+ }
+ }
+
+ if (hasHighwayExit) {
+ int lblinfo = reader.getu3();
+ int highwayLabelOffset = lblinfo & 0x3FFFF;
+ boolean indexed = (lblinfo & 0x800000) != 0;
+ boolean overnightParking = (lblinfo & 0x400000) != 0;
+
+ int highwayIndex = (placeHeader.getNumHighways() > 255)
+ ? reader.getChar() : reader.get();
+ if (indexed) {
+ int eidx = (placeHeader.getNumExits() > 255) ?
+ reader.getChar() :
+ reader.get();
+ }
+ }
+
+ if (hasTides) {
+ System.out.println("Map has tide prediction, please implement!");
+ }
+
+ pois.put(poiOffset, poi);
+ }
+ }
+
+ /**
+ * The meaning of the bits in the local flags depends on which bits
+ * are set in the global flags. Hence we have to calculate the
+ * masks to use. These are held in an instance of PoiMasks
+ * @param placeHeader The label header.
+ * @return The masks as modified by the global flags.
+ */
+ private PoiMasks makeLocalMask(PlacesHeader placeHeader) {
+ int globalPoi = placeHeader.getPOIGlobalFlags();
+
+ char mask= 0x1;
+
+ boolean hasStreetNum = (globalPoi & POIRecord.HAS_STREET_NUM) != 0;
+ boolean hasStreet = (globalPoi & POIRecord.HAS_STREET) != 0;
+ boolean hasCity = (globalPoi & POIRecord.HAS_CITY) != 0;
+ boolean hasZip = (globalPoi & POIRecord.HAS_ZIP) != 0;
+ boolean hasPhone = (globalPoi & POIRecord.HAS_PHONE) != 0;
+ boolean hasHighwayExit = (globalPoi & POIRecord.HAS_EXIT) != 0;
+ boolean hasTides = (globalPoi & POIRecord.HAS_TIDE_PREDICTION) != 0;
+
+ PoiMasks localMask = new PoiMasks();
+
+ if (hasStreetNum) {
+ localMask.streetNumMask = mask;
+ mask <<= 1;
+ }
+
+ if (hasStreet) {
+ localMask.streetMask = mask;
+ mask <<= 1;
+ }
+
+ if (hasCity) {
+ localMask.cityMask = mask;
+ mask <<= 1;
+ }
+
+ if (hasZip) {
+ localMask.zipMask = mask;
+ mask <<= 1;
+ }
+
+ if (hasPhone) {
+ localMask.phoneMask = mask;
+ mask <<= 1;
+ }
+
+ if (hasHighwayExit) {
+ localMask.highwayExitMask = mask;
+ mask <<= 1;
+ }
+
+ if (hasTides) {
+ localMask.tidesMask = mask;
+ mask <<= 1;
+ }
+
+ return localMask;
+ }
+
+ public Map<Integer, String> getLabels() {
+ Map<Integer, String> m = new HashMap<Integer, String>();
+ for (Map.Entry<Integer, Label> ent : labels.entrySet()) {
+ m.put(ent.getKey(), ent.getValue().getText());
+ }
+ return m;
+ }
+
+ public int getCodePage() {
+ return header.getCodePage();
+ }
+
+ public int getSortOrderId() {
+ return header.getSortOrderId();
+ }
+
+ private class PoiMasks {
+ private char streetNumMask;
+ private char streetMask;
+ private char cityMask;
+ private char zipMask;
+ private char phoneMask;
+ private char highwayExitMask;
+ private char tidesMask;
+ }
+
+ public int getEncodingType() {
+ return header.getEncodingType();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/LBLHeader.java b/src/uk/me/parabola/imgfmt/app/lbl/LBLHeader.java
new file mode 100644
index 0000000..6fad909
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/LBLHeader.java
@@ -0,0 +1,185 @@
+/*
+ * 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: Dec 14, 2007
+ */
+package uk.me.parabola.imgfmt.app.lbl;
+
+import java.io.UnsupportedEncodingException;
+
+import uk.me.parabola.imgfmt.app.CommonHeader;
+import uk.me.parabola.imgfmt.app.ImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.labelenc.CodeFunctions;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+
+/**
+ * The header for the LBL file.
+ *
+ * @author Steve Ratcliffe
+ */
+public class LBLHeader extends CommonHeader {
+ public static final int HEADER_LEN = 196; // Other lengths are possible
+
+ private static final char UNK3_REC_LEN = 0;
+
+ private int labelStart; // Start of labels.
+ private int labelSize; // Size of file.
+
+ private int offsetMultiplier;
+
+ // Code page and sorting info.
+ private Sort sort;
+
+ private int sortDescriptionLength;
+
+ // The type of encoding employed. This is not a length.
+ private int encodingType = CodeFunctions.ENCODING_FORMAT6;
+
+ // The label section also contains all kinds of records related to place,
+ // so these have all been put in their own class.
+ private final PlacesHeader placeHeader;
+
+ public LBLHeader() {
+ super(HEADER_LEN, "GARMIN LBL");
+ placeHeader = new PlacesHeader();
+ }
+
+ public int getSortDescriptionLength() {
+ return sortDescriptionLength;
+ }
+
+ /**
+ * Read the rest of the header. Specific to the given file. It is guaranteed
+ * that the file position will be set to the correct place before this is
+ * called.
+ *
+ * @param reader The header is read from here.
+ */
+ protected void readFileHeader(ImgFileReader reader) {
+ labelStart = reader.getInt();
+ labelSize = reader.getInt();
+ offsetMultiplier = 1 << reader.get();
+ encodingType = reader.get();
+
+ // Read the places part of the header.
+ placeHeader.readFileHeader(reader);
+
+ int codepage = reader.getChar();
+ int id1 = reader.getChar();
+ int id2 = reader.getChar();
+ int descOff = reader.getInt();
+ int descLen = reader.getInt();
+
+ reader.position(descOff);
+ byte[] bytes = reader.get(descLen);
+ String description;
+ try {
+ description = new String(bytes, "ascii");
+ } catch (UnsupportedEncodingException e) {
+ description = "Unknown";
+ }
+
+ sort = new Sort();
+ sort.setCodepage(codepage);
+ sort.setId1(id1);
+ sort.setId2(id2);
+ sort.setDescription(description);
+
+ // more to do but not needed yet... Just set position
+ reader.position(labelStart);
+ }
+
+ /**
+ * Write the rest of the header. It is guaranteed that the writer will be set
+ * to the correct position before calling.
+ *
+ * @param writer The header is written here.
+ */
+ protected void writeFileHeader(ImgFileWriter writer) {
+ // LBL1 section, these are regular labels
+ writer.putInt(HEADER_LEN + sortDescriptionLength);
+ writer.putInt(getLabelSize());
+
+ writer.put((byte) offsetMultiplier);
+ writer.put((byte) encodingType);
+
+ placeHeader.writeFileHeader(writer);
+
+ writer.putChar((char) getCodePage());
+
+ // Identifying the sort
+ char id1 = (char) sort.getId1();
+ writer.putChar(id1);
+
+ char id2 = (char) sort.getId2();
+ if (id1 != 0 && id2 != 0)
+ id2 |= 0x8000;
+ writer.putChar(id2);
+
+ writer.putInt(HEADER_LEN);
+ writer.putInt(sortDescriptionLength);
+
+ writer.putInt(placeHeader.getLastPos());
+ writer.putInt(0);
+ writer.putChar(UNK3_REC_LEN);
+ writer.putChar((char) 0);
+ }
+
+ protected int getEncodingType() {
+ return encodingType;
+ }
+
+ public void setEncodingType(int type) {
+ this.encodingType = type;
+ }
+
+ protected int getLabelSize() {
+ return labelSize;
+ }
+
+ public void setLabelSize(int labelSize) {
+ this.labelSize = labelSize;
+ placeHeader.setLabelEnd(HEADER_LEN + sortDescriptionLength + labelSize);
+ }
+
+ protected int getCodePage() {
+ return sort.getCodepage();
+ }
+
+ public void setSort(Sort sort) {
+ sortDescriptionLength = sort.getDescription().length() + 1;
+ this.sort = sort;
+ }
+
+ public int getSortOrderId() {
+ return sort.getSortOrderId();
+ }
+
+ public int getLabelStart() {
+ return labelStart;
+ }
+
+ public int getOffsetMultiplier() {
+ return offsetMultiplier;
+ }
+
+ public PlacesHeader getPlaceHeader() {
+ return placeHeader;
+ }
+
+ public void setOffsetMultiplier(int offsetMultiplier) {
+ this.offsetMultiplier = offsetMultiplier;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/POIIndex.java b/src/uk/me/parabola/imgfmt/app/lbl/POIIndex.java
new file mode 100644
index 0000000..4a8ef1e
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/POIIndex.java
@@ -0,0 +1,50 @@
+/*
+ * 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: Jan 1, 2008
+ */
+package uk.me.parabola.imgfmt.app.lbl;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+
+/**
+ * Represent a POI index entry
+ *
+ * @author Mark Burton
+ */
+public class POIIndex {
+
+ private final String name;
+ private final byte poiIndex;
+ private final Subdivision group;
+ private final byte subType;
+
+ public POIIndex(String name, byte poiIndex, Subdivision group, byte subType) {
+ this.name = name;
+ this.poiIndex = poiIndex;
+ this.group = group;
+ this.subType = subType;
+ }
+
+ void write(ImgFileWriter writer) {
+ writer.put(poiIndex);
+ writer.putChar((char)group.getNumber());
+ writer.put(subType);
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java b/src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java
new file mode 100644
index 0000000..a44e945
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java
@@ -0,0 +1,402 @@
+/*
+ * 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: Jan 1, 2008
+ */
+package uk.me.parabola.imgfmt.app.lbl;
+
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Exit;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+
+/**
+ * @author Steve Ratcliffe
+ */
+public class POIRecord {
+
+ static final byte HAS_STREET_NUM = 0x01;
+ static final byte HAS_STREET = 0x02;
+ static final byte HAS_CITY = 0x04;
+ static final byte HAS_ZIP = 0x08;
+ static final byte HAS_PHONE = 0x10;
+ static final byte HAS_EXIT = 0x20;
+ static final byte HAS_TIDE_PREDICTION = 0x40;
+
+ /* Not used yet
+ private static final AddrAbbr ABBR_HASH = new AddrAbbr(' ', "#");
+ private static final AddrAbbr ABBR_APARTMENT = new AddrAbbr('1', "APT");
+ private static final AddrAbbr ABBR_BUILDING = new AddrAbbr('2', "BLDG");
+ private static final AddrAbbr ABBR_DEPT = new AddrAbbr('3', "DEPT");
+ private static final AddrAbbr ABBR_FLAT = new AddrAbbr('4', "FL");
+ private static final AddrAbbr ABBR_ROOM = new AddrAbbr('5', "RM");
+ private static final AddrAbbr ABBR_STE = new AddrAbbr('6', "STE"); // don't know what this is?
+ private static final AddrAbbr ABBR_UNIT = new AddrAbbr('7', "UNIT");
+ */
+
+ private int offset = -1;
+ private Label poiName;
+
+ private final SimpleStreetPhoneNumber simpleStreetNumber = new SimpleStreetPhoneNumber();
+ private final SimpleStreetPhoneNumber simplePhoneNumber = new SimpleStreetPhoneNumber();
+
+ private Label streetName;
+ private Label streetNumberName; // Used for numbers such as 221b
+ private Label complexPhoneNumber; // Used for numbers such as 221b
+
+ private City city;
+ private Zip zip;
+ private Exit exit;
+
+ //private String phoneNumber;
+
+ public void setLabel(Label label) {
+ this.poiName = label;
+ }
+
+ public void setStreetName(Label label) {
+ this.streetName = label;
+ }
+
+ public boolean setSimpleStreetNumber(String streetNumber)
+ {
+ return simpleStreetNumber.set(streetNumber);
+ }
+
+ public void setComplexStreetNumber(Label label)
+ {
+ streetNumberName = label;
+ }
+
+ public boolean setSimplePhoneNumber(String phone)
+ {
+ return simplePhoneNumber.set(phone);
+ }
+
+ public void setComplexPhoneNumber(Label label)
+ {
+ complexPhoneNumber = label;
+ }
+
+
+ public void setZip(Zip zip) {
+ this.zip = zip;
+ }
+
+ public void setCity(City city)
+ {
+ this.city = city;
+ }
+
+ public void setExit(Exit exit) {
+ this.exit = exit;
+ }
+
+ void write(ImgFileWriter writer, byte POIGlobalFlags, int realofs,
+ long numCities, long numZips, long numHighways, long numExitFacilities) {
+ assert offset == realofs : "offset = " + offset + " realofs = " + realofs;
+ int ptr = poiName.getOffset();
+ if (POIGlobalFlags != getPOIFlags())
+ ptr |= 0x800000;
+ writer.put3(ptr);
+
+ if (POIGlobalFlags != getPOIFlags())
+ writer.put(getWrittenPOIFlags(POIGlobalFlags));
+
+ if (streetNumberName != null)
+ {
+ int labOff = streetNumberName.getOffset();
+ writer.put((byte)((labOff & 0x7F0000) >> 16));
+ writer.putChar((char)(labOff & 0xFFFF));
+ }
+ else if (simpleStreetNumber.isUsed())
+ simpleStreetNumber.write(writer);
+
+ if (streetName != null)
+ writer.put3(streetName.getOffset());
+
+ if (city != null)
+ {
+ char cityIndex = (char) city.getIndex();
+ if(numCities > 255)
+ writer.putChar(cityIndex);
+ else
+ writer.put((byte)cityIndex);
+ }
+
+ if (zip != null) {
+ char zipIndex = (char) zip.getIndex();
+ if(numZips > 255)
+ writer.putChar(zipIndex);
+ else
+ writer.put((byte) zipIndex);
+ }
+
+ if (complexPhoneNumber != null)
+ {
+ int labOff = complexPhoneNumber.getOffset();
+ writer.put((byte)((labOff & 0x7F0000) >> 16));
+ writer.putChar((char)(labOff & 0xFFFF));
+ }
+ else if (simplePhoneNumber.isUsed())
+ simplePhoneNumber.write(writer);
+
+ if(exit != null) {
+ Label description = exit.getDescription();
+ int val = 0;
+ if(description != null) {
+ val = description.getOffset();
+ assert val < 0x400000 : "Exit description label offset too large";
+ }
+ if(exit.getOvernightParking())
+ val |= 0x400000;
+ List<ExitFacility> facilites = exit.getFacilities();
+ ExitFacility ef = null;
+ if(!facilites.isEmpty())
+ ef = facilites.get(0);
+ if(ef != null)
+ val |= 0x800000; // exit facilities defined
+ writer.put3(val);
+
+ char highwayIndex = (char)exit.getHighway().getIndex();
+ if(numHighways > 255)
+ writer.putChar(highwayIndex);
+ else
+ writer.put((byte)highwayIndex);
+
+ if(ef != null) {
+ char exitFacilityIndex = (char)ef.getIndex();
+ if(numExitFacilities > 255)
+ writer.putChar(exitFacilityIndex);
+ else
+ writer.put((byte)exitFacilityIndex);
+ }
+ }
+ }
+
+ byte getPOIFlags() {
+ byte b = 0;
+ if (streetName != null)
+ b |= HAS_STREET;
+ if (simpleStreetNumber.isUsed() || streetNumberName != null)
+ b |= HAS_STREET_NUM;
+ if (city != null)
+ b |= HAS_CITY;
+ if (zip != null)
+ b |= HAS_ZIP;
+ if (simplePhoneNumber.isUsed() || complexPhoneNumber != null)
+ b |= HAS_PHONE;
+ if (exit != null)
+ b |= HAS_EXIT;
+ return b;
+ }
+
+ byte getWrittenPOIFlags(byte POIGlobalFlags)
+ {
+ int flag = 0;
+ int j = 0;
+
+ int usedFields = getPOIFlags();
+
+ /* the local POI flag is really tricky if a bit is not set in the global mask
+ we have to skip this bit in the local mask. In other words the meaning of the local bits
+ change influenced by the global bits */
+
+ for(byte i = 0; i < 6; i++)
+ {
+ int mask = 1 << i;
+
+ if((mask & POIGlobalFlags) == mask)
+ {
+ if((mask & usedFields) == mask)
+ flag |= (1 << j);
+ j++;
+ }
+
+ }
+
+ flag |= 0x80; // gpsmapedit asserts for this bit set
+
+ return (byte) flag;
+ }
+
+ /**
+ * Sets the start offset of this POIRecord
+ *
+ * \return Number of bytes needed by this entry
+ */
+ int calcOffset(int ofs, byte POIGlobalFlags, long numCities, long numZips, long numHighways, long numExitFacilities) {
+ offset = ofs;
+ int size = 3;
+ if (exit != null) {
+ size += 3;
+ size += (numHighways > 255)? 2 : 1;
+ if(!exit.getFacilities().isEmpty())
+ size += (numExitFacilities > 255)? 2 : 1;
+ }
+ if (POIGlobalFlags != getPOIFlags())
+ size += 1;
+ if (simpleStreetNumber.isUsed())
+ size += simpleStreetNumber.getSize();
+ if (streetNumberName != null)
+ size += 3;
+ if (simplePhoneNumber.isUsed())
+ size += simplePhoneNumber.getSize();
+ if (complexPhoneNumber != null)
+ size += 3;
+ if (streetName != null)
+ size += 3;
+ if (city != null)
+ {
+ /*
+ depending on how many cities are in the LBL block we have
+ to write one or two bytes
+ */
+
+ if(numCities > 255)
+ size += 2;
+ else
+ size += 1;
+ }
+ if (zip != null) {
+ // depending on how many zips are in the LBL block we have to write one or two bytes
+ if(numZips > 255)
+ size += 2;
+ else
+ size += 1;
+ }
+ return size;
+ }
+
+ public int getOffset() {
+ if (offset == -1)
+ throw new IllegalStateException("Offset not known yet.");
+ return offset;
+ }
+
+ public Label getNameLabel() {
+ return poiName;
+ }
+
+ public City getCity() {
+ return city;
+ }
+
+ /**
+ * Address abbreviations.
+ */
+ //static class AddrAbbr {
+ // private final char code;
+ // private final String value;
+ //
+ // AddrAbbr(char code, String value) {
+ // this.code = code;
+ // this.value = value;
+ // }
+ //
+ // public String toString() {
+ // return value;
+ // }
+ //
+ // public char getCode() {
+ // return code;
+ // }
+ //}
+
+ /**
+ * Street and Phone numbers can be stored in two different ways in the poi record
+ * Simple Number that only contain digits are coded in base 11 coding.
+ * This helper class tries to code the given number. If the number contains other
+ * chars like in 4a the coding fails and the caller has to use a Label instead
+ */
+ class SimpleStreetPhoneNumber {
+
+ private byte[] encodedNumber;
+ private int encodedSize;
+
+ /**
+ * Encode a string as base 11.
+ * @param str The input string.
+ * @return If the string is not all numeric (or A) then false is returned
+ * and the string will be encoded as a label instead.
+ */
+ public boolean set(String str) {
+
+ // remove surrounding whitespace to increase chance for simple encoding
+ String number = str.trim();
+
+ encodedNumber = new byte[(number.length()/2)+2];
+
+ int i = 0;
+ int j = 0;
+ while (i < number.length()) {
+
+ int c1 = decodeChar(number.charAt(i++));
+
+ int c2;
+ if (i < number.length()) {
+ c2 = decodeChar(number.charAt(i++));
+ } else
+ c2 = 10;
+
+ // Only 0-9 and - allowed
+ if (c1 < 0 || c1 > 10 || c2 < 0 || c2 > 10)
+ return false;
+
+ // Encode as base 11
+ int val = c1 * 11 + c2;
+
+ // first byte needs special marking with 0x80
+ // If this is not set would be treated as label pointer
+ if (j == 0)
+ val |= 0x80;
+
+ encodedNumber[j++] = (byte)val;
+ }
+ if (j == 0)
+ return false;
+
+ if (j == 1)
+ encodedNumber[j++] = (byte) 0xf8;
+ else
+ encodedNumber[j-1] |= 0x80;
+ encodedSize = j;
+
+ return true;
+ }
+
+ public void write(ImgFileWriter writer)
+ {
+ for(int i = 0; i < encodedSize; i++)
+ writer.put(encodedNumber[i]);
+ }
+
+ public boolean isUsed()
+ {
+ return (encodedSize > 0);
+ }
+
+ public int getSize()
+ {
+ return encodedSize;
+ }
+
+ private int decodeChar(char ch)
+ {
+ return (ch - '0');
+ }
+
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java b/src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java
new file mode 100644
index 0000000..245382a
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java
@@ -0,0 +1,421 @@
+/*
+ * 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: Jan 1, 2008
+ */
+package uk.me.parabola.imgfmt.app.lbl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import uk.me.parabola.imgfmt.app.Exit;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.srt.CombinedSortKey;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+
+/**
+ * This is really part of the LBLFile. We split out all the parts of the file
+ * that are to do with location to here.
+ */
+ at SuppressWarnings({"RawUseOfParameterizedType"})
+public class PlacesFile {
+ private final Map<String, Country> countries = new LinkedHashMap<String, Country>();
+ private final List<Country> countryList = new ArrayList<Country>();
+
+ private final Map<String, Region> regions = new LinkedHashMap<String, Region>();
+ private final List<Region> regionList = new ArrayList<Region>();
+
+ private final Map<String, City> cities = new LinkedHashMap<String, City>();
+ private final List<City> cityList = new ArrayList<City>();
+
+ private final Map<String, Zip> postalCodes = new LinkedHashMap<String, Zip>();
+ private final List<Zip> zipList = new ArrayList<Zip>();
+
+ private final List<Highway> highways = new ArrayList<Highway>();
+ private final List<ExitFacility> exitFacilities = new ArrayList<ExitFacility>();
+ private final List<POIRecord> pois = new ArrayList<POIRecord>();
+ private final List[] poiIndex = new ArrayList[256];
+
+ private LBLFile lblFile;
+ private PlacesHeader placeHeader;
+ private boolean poisClosed;
+
+ private Sort sort;
+
+ private final Random random = new Random();
+
+ /**
+ * We need to have links back to the main LBL file and need to be passed
+ * the part of the header that we manage here.
+ *
+ * @param file The main LBL file, used so that we can create labels.
+ * @param pheader The place header.
+ */
+ void init(LBLFile file, PlacesHeader pheader) {
+ lblFile = file;
+ placeHeader = pheader;
+ }
+
+ void write(ImgFileWriter writer) {
+ for (Country c : countryList)
+ c.write(writer);
+ placeHeader.endCountries(writer.position());
+
+ for (Region region : regionList)
+ region.write(writer);
+ placeHeader.endRegions(writer.position());
+
+ for (City sc : cityList)
+ sc.write(writer);
+
+ placeHeader.endCity(writer.position());
+
+ for (List<POIIndex> pil : poiIndex) {
+ if(pil != null) {
+ // sort entries by POI name
+ List<SortKey<POIIndex>> sorted = new ArrayList<SortKey<POIIndex>>();
+ for (POIIndex index : pil) {
+ SortKey<POIIndex> sortKey = sort.createSortKey(index, index.getName());
+ sorted.add(sortKey);
+ }
+ Collections.sort(sorted);
+
+ for (SortKey<POIIndex> key : sorted) {
+ key.getObject().write(writer);
+ }
+ }
+ }
+ placeHeader.endPOIIndex(writer.position());
+
+ int poistart = writer.position();
+ byte poiglobalflags = placeHeader.getPOIGlobalFlags();
+ for (POIRecord p : pois)
+ p.write(writer, poiglobalflags,
+ writer.position() - poistart, cityList.size(), postalCodes.size(), highways.size(), exitFacilities.size());
+ placeHeader.endPOI(writer.position());
+
+ int numPoiIndexEntries = 0;
+ for (int i = 0; i < 256; ++i) {
+ if(poiIndex[i] != null) {
+ writer.put((byte)i);
+ writer.put3(numPoiIndexEntries + 1);
+ numPoiIndexEntries += poiIndex[i].size();
+ }
+ }
+ placeHeader.endPOITypeIndex(writer.position());
+
+ for (Zip z : zipList)
+ z.write(writer);
+ placeHeader.endZip(writer.position());
+
+ int extraHighwayDataOffset = 0;
+ for (Highway h : highways) {
+ h.setExtraDataOffset(extraHighwayDataOffset);
+ extraHighwayDataOffset += h.getExtraDataSize();
+ h.write(writer, false);
+ }
+ placeHeader.endHighway(writer.position());
+
+ for (ExitFacility ef : exitFacilities)
+ ef.write(writer);
+ placeHeader.endExitFacility(writer.position());
+
+ for (Highway h : highways)
+ h.write(writer, true);
+ placeHeader.endHighwayData(writer.position());
+ }
+
+ Country createCountry(String name, String abbr) {
+
+ String s = abbr != null ? name + (char)0x1d + abbr : name;
+
+ Country c = countries.get(s);
+
+ if(c == null) {
+ c = new Country(countries.size()+1);
+
+ Label l = lblFile.newLabel(s);
+ c.setLabel(l);
+ countries.put(s, c);
+ }
+ return c;
+ }
+
+ Region createRegion(Country country, String name, String abbr) {
+
+ String s = abbr != null ? name + (char)0x1d + abbr : name;
+
+ String uniqueRegionName = s.toUpperCase() + "_C" + country.getLabel().getOffset();
+
+ Region r = regions.get(uniqueRegionName);
+
+ if(r == null) {
+ r = new Region(country);
+ Label l = lblFile.newLabel(s);
+ r.setLabel(l);
+ regionList.add(r);
+ regions.put(uniqueRegionName, r);
+ }
+ return r;
+ }
+
+ City createCity(Country country, String name, boolean unique) {
+
+ String uniqueCityName = name.toUpperCase() + "_C" + country.getLabel().getOffset();
+
+ // if unique is true, make sure that the name really is unique
+ if(unique && cities.get(uniqueCityName) != null) {
+ do {
+ // add random suffix
+ uniqueCityName += "_" + new Random().nextInt(0x10000);
+ } while(cities.get(uniqueCityName) != null);
+ }
+
+ City c = null;
+ if (!unique)
+ c = cities.get(uniqueCityName);
+
+ if (c == null) {
+ c = new City(country);
+
+ Label l = lblFile.newLabel(name);
+ c.setLabel(l);
+
+ cityList.add(c);
+ cities.put(uniqueCityName, c);
+ assert cityList.size() == cities.size() : " cityList and cities are different lengths after inserting " + name + " and " + uniqueCityName;
+ }
+
+ return c;
+ }
+
+ City createCity(Region region, String name, boolean unique) {
+
+ String uniqueCityName = name.toUpperCase() + "_R" + region.getLabel().getOffset();
+
+ // if unique is true, make sure that the name really is unique
+ if (unique && cities.get(uniqueCityName) != null) {
+ do {
+ // add semi-random suffix.
+ uniqueCityName += "_" + random.nextInt(0x10000);
+ } while(cities.get(uniqueCityName) != null);
+ }
+
+ City c = null;
+ if(!unique)
+ c = cities.get(uniqueCityName);
+
+ if(c == null) {
+ c = new City(region);
+
+ Label l = lblFile.newLabel(name);
+ c.setLabel(l);
+
+ cityList.add(c);
+ cities.put(uniqueCityName, c);
+ assert cityList.size() == cities.size() : " cityList and cities are different lengths after inserting " + name + " and " + uniqueCityName;
+ }
+
+ return c;
+ }
+
+ Zip createZip(String code) {
+ Zip z = postalCodes.get(code);
+
+ if(z == null) {
+ z = new Zip();
+
+ Label l = lblFile.newLabel(code);
+ z.setLabel(l);
+
+ zipList.add(z);
+ postalCodes.put(code, z);
+ }
+ return z;
+ }
+
+ Highway createHighway(Region region, String name) {
+ Highway h = new Highway(region, highways.size()+1);
+
+ Label l = lblFile.newLabel(name);
+ h.setLabel(l);
+
+ highways.add(h);
+ return h;
+ }
+
+ public ExitFacility createExitFacility(int type, char direction, int facilities, String description, boolean last) {
+ Label d = lblFile.newLabel(description);
+ ExitFacility ef = new ExitFacility(type, direction, facilities, d, last, exitFacilities.size()+1);
+ exitFacilities.add(ef);
+ return ef;
+ }
+
+ POIRecord createPOI(String name) {
+ assert !poisClosed;
+ // TODO...
+ POIRecord p = new POIRecord();
+
+ Label l = lblFile.newLabel(name);
+ p.setLabel(l);
+
+ pois.add(p);
+
+ return p;
+ }
+
+ POIRecord createExitPOI(String name, Exit exit) {
+ assert !poisClosed;
+ // TODO...
+ POIRecord p = new POIRecord();
+
+ Label l = lblFile.newLabel(name);
+ p.setLabel(l);
+
+ p.setExit(exit);
+
+ pois.add(p);
+
+ return p;
+ }
+
+ POIIndex createPOIIndex(String name, int index, Subdivision group, int type) {
+ assert index < 0x100 : "Too many POIS in division";
+ POIIndex pi = new POIIndex(name, (byte)index, group, (byte)type);
+ int t = type >> 8;
+ if(poiIndex[t] == null)
+ poiIndex[t] = new ArrayList<POIIndex>();
+ poiIndex[t].add(pi);
+ return pi;
+ }
+
+ void allPOIsDone() {
+ sortCountries();
+ sortRegions();
+ sortCities();
+ sortZips();
+
+ poisClosed = true;
+
+ byte poiFlags = 0;
+ for (POIRecord p : pois) {
+ poiFlags |= p.getPOIFlags();
+ }
+ placeHeader.setPOIGlobalFlags(poiFlags);
+
+ int ofs = 0;
+ for (POIRecord p : pois)
+ ofs += p.calcOffset(ofs, poiFlags, cityList.size(), postalCodes.size(), highways.size(), exitFacilities.size());
+ }
+
+ /**
+ * I don't know that you have to sort these (after all most tiles will
+ * only be in one country or at least a very small number).
+ *
+ * But why not?
+ */
+ private void sortCountries() {
+ List<SortKey<Country>> keys = new ArrayList<SortKey<Country>>();
+ for (Country c : countries.values()) {
+ SortKey<Country> key = sort.createSortKey(c, c.getLabel().getText());
+ keys.add(key);
+ }
+ Collections.sort(keys);
+
+ countryList.clear();
+ int index = 1;
+ for (SortKey<Country> key : keys) {
+ Country c = key.getObject();
+ c.setIndex(index++);
+ countryList.add(c);
+ }
+ }
+
+ /**
+ * Sort the regions by the defined sort.
+ */
+ private void sortRegions() {
+ List<SortKey<Region>> keys = new ArrayList<SortKey<Region>>();
+ for (Region r : regionList) {
+ SortKey<Region> key = sort.createSortKey(r, r.getLabel().getText(), r.getCountry().getIndex());
+ keys.add(key);
+ }
+ Collections.sort(keys);
+
+ regionList.clear();
+ int index = 1;
+ for (SortKey<Region> key : keys) {
+ Region r = key.getObject();
+ r.setIndex(index++);
+ regionList.add(r);
+ }
+ }
+
+ /**
+ * Sort the cities by the defined sort.
+ */
+ private void sortCities() {
+ List<SortKey<City>> keys = new ArrayList<SortKey<City>>();
+ for (City c : cityList) {
+ SortKey<City> sortKey = sort.createSortKey(c, c.getName());
+ sortKey = new CombinedSortKey<City>(sortKey, c.getRegionNumber(), c.getCountryNumber());
+ keys.add(sortKey);
+ }
+ Collections.sort(keys);
+
+ cityList.clear();
+ int index = 1;
+ for (SortKey<City> sc: keys) {
+ City city = sc.getObject();
+ city.setIndex(index++);
+ cityList.add(city);
+ }
+ }
+
+ private void sortZips() {
+ List<SortKey<Zip>> keys = new ArrayList<SortKey<Zip>>();
+ for (Zip c : postalCodes.values()) {
+ SortKey<Zip> sortKey = sort.createSortKey(c, c.getLabel().getText());
+ keys.add(sortKey);
+ }
+ Collections.sort(keys);
+
+ zipList.clear();
+ int index = 1;
+ for (SortKey<Zip> sc: keys) {
+ Zip zip = sc.getObject();
+ zip.setIndex(index++);
+ zipList.add(zip);
+ }
+ }
+
+ public int numCities() {
+ return cityList.size();
+ }
+
+ public int numZips() {
+ return postalCodes.size();
+ }
+
+ public void setSort(Sort sort) {
+ this.sort = sort;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/PlacesHeader.java b/src/uk/me/parabola/imgfmt/app/lbl/PlacesHeader.java
new file mode 100644
index 0000000..0ef201a
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/PlacesHeader.java
@@ -0,0 +1,264 @@
+/*
+ * 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: Jan 1, 2008
+ */
+package uk.me.parabola.imgfmt.app.lbl;
+
+import uk.me.parabola.imgfmt.app.ImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Section;
+
+/**
+ * This is not a separate header, but rather part of the LBL header. It is just
+ * separated out for convenience. All the records that have some kind of
+ * meaning associated with a place are put here.
+ *
+ * @author Steve Ratcliffe
+ */
+public class PlacesHeader {
+
+ private static final char COUNTRY_REC_LEN = 3;
+ private static final char REGION_REC_LEN = 5;
+ private static final char CITY_REC_LEN = 5;
+ private static final char POI_INDEX_REC_LEN = 4;
+ private static final char POI_TYPE_INDEX_REC_LEN = 4;
+ private static final char ZIP_REC_LEN = 3;
+ private static final char HIGHWAY_REC_LEN = 6;
+ private static final char EXIT_REC_LEN = 5;
+ private static final char HIGHWAYDATA_REC_LEN = 3;
+
+ private final Section country = new Section(COUNTRY_REC_LEN);
+ private final Section region = new Section(country, REGION_REC_LEN);
+ private final Section city = new Section(region, CITY_REC_LEN);
+ private final Section poiIndex = new Section(city, POI_INDEX_REC_LEN);
+ private final Section poiProperties = new Section(poiIndex);
+ private final Section poiTypeIndex = new Section(poiProperties, POI_TYPE_INDEX_REC_LEN);
+ private final Section zip = new Section(poiTypeIndex, ZIP_REC_LEN);
+ private final Section highway = new Section(zip, HIGHWAY_REC_LEN);
+ private final Section exitFacility = new Section(highway, EXIT_REC_LEN);
+ private final Section highwayData = new Section(exitFacility, HIGHWAYDATA_REC_LEN);
+ private byte POIGlobalFlags ;
+
+ void setPOIGlobalFlags(byte flags) {
+ this.POIGlobalFlags = flags;
+ }
+
+ byte getPOIGlobalFlags() {
+ return POIGlobalFlags;
+ }
+
+ void writeFileHeader(ImgFileWriter writer) {
+ writer.putInt(country.getPosition());
+ writer.putInt(country.getSize());
+ writer.putChar(country.getItemSize());
+ writer.putInt(0);
+
+ writer.putInt(region.getPosition());
+ writer.putInt(region.getSize());
+ writer.putChar(region.getItemSize());
+ writer.putInt(0);
+
+ writer.putInt(city.getPosition());
+ writer.putInt(city.getSize());
+ writer.putChar(city.getItemSize());
+ writer.putInt(0);
+
+ writer.putInt(poiIndex.getPosition());
+ writer.putInt(poiIndex.getSize());
+ writer.putChar(poiIndex.getItemSize());
+ writer.putInt(0);
+
+ writer.putInt(poiProperties.getPosition());
+ writer.putInt(poiProperties.getSize());
+ writer.put((byte) 0); // offset multiplier
+
+ // mb 5/9/2009 - discovered that Garmin maps can contain more
+ // than 8 bits of POI global flags - have seen the 9th bit set
+ // to indicate the presence of some extra POI info (purpose
+ // unknown but it starts with a byte that contains the number
+ // of further bytes to read << 1) - therefore, this group
+ // should probably be: 16 bits of POI global flags followed by
+ // 16 zero bits rather than 8 bits of flags and 24 zero bits
+ writer.put(POIGlobalFlags); // properties global mask
+ writer.putChar((char) 0);
+ writer.put((byte) 0);
+
+ writer.putInt(poiTypeIndex.getPosition());
+ writer.putInt(poiTypeIndex.getSize());
+ writer.putChar(poiTypeIndex.getItemSize());
+ writer.putInt(0);
+
+ writer.putInt(zip.getPosition());
+ writer.putInt(zip.getSize());
+ writer.putChar(zip.getItemSize());
+ writer.putInt(0);
+
+ writer.putInt(highway.getPosition());
+ writer.putInt(highway.getSize());
+ writer.putChar(highway.getItemSize());
+ writer.putInt(0);
+
+ writer.putInt(exitFacility.getPosition());
+ writer.putInt(exitFacility.getSize());
+ writer.putChar(exitFacility.getItemSize());
+ writer.putInt(0);
+
+ writer.putInt(highwayData.getPosition());
+ writer.putInt(highwayData.getSize());
+ writer.putChar(highwayData.getItemSize());
+ writer.putInt(0);
+ }
+
+ void readFileHeader(ImgFileReader reader) {
+ reader.position(0x1f);
+
+ country.readSectionInfo(reader, true);
+ reader.getInt();
+
+ region.readSectionInfo(reader, true);
+ reader.getInt();
+
+ city.readSectionInfo(reader, true);
+ reader.getInt();
+
+ poiIndex.readSectionInfo(reader, true);
+ reader.getInt();
+
+ poiProperties.readSectionInfo(reader, false);
+ reader.get(); // offset multiplier
+
+ POIGlobalFlags = reader.get();
+ reader.getChar();
+ reader.get();
+
+ poiTypeIndex.readSectionInfo(reader, true);
+ reader.getInt();
+
+ zip.readSectionInfo(reader, true);
+ reader.getInt();
+
+ highway.readSectionInfo(reader, true);
+ reader.getInt();
+
+ exitFacility.readSectionInfo(reader, true);
+ reader.getInt();
+
+ highwayData.readSectionInfo(reader, true);
+ reader.getInt();
+ }
+
+ int getLastPos() {
+ // Beware this is not really valid until all is written.
+ return highwayData.getEndPos();
+ }
+
+ void setLabelEnd(int pos) {
+ country.setPosition(pos);
+ }
+
+ void endCountries(int pos) {
+ country.setSize(pos - country.getPosition());
+ }
+
+ void endRegions(int pos) {
+ region.setSize(pos - region.getPosition());
+ }
+
+ void endCity(int pos) {
+ city.setSize(pos - city.getPosition());
+ }
+
+ void endPOI(int pos) {
+ poiProperties.setSize(pos - poiProperties.getPosition());
+ }
+
+ void endPOIIndex(int pos) {
+ poiIndex.setSize(pos - poiIndex.getPosition());
+ }
+
+ void endPOITypeIndex(int pos) {
+ poiTypeIndex.setSize(pos - poiTypeIndex.getPosition());
+ }
+
+ void endZip(int pos) {
+ zip.setSize(pos - zip.getPosition());
+ }
+
+ void endHighway(int pos) {
+ highway.setSize(pos - highway.getPosition());
+ }
+
+ void endExitFacility(int pos) {
+ exitFacility.setSize(pos - exitFacility.getPosition());
+ }
+
+ void endHighwayData(int pos) {
+ highwayData.setSize(pos - highwayData.getPosition());
+ }
+
+ public int getNumCities() {
+ return city.getNumItems();
+ }
+
+ public int getNumZips() {
+ return zip.getNumItems();
+ }
+
+ public int getPoiPropertiesStart() {
+ return poiProperties.getPosition();
+ }
+ public int getPoiPropertiesEnd() {
+ return poiProperties.getEndPos();
+ }
+
+ public int getCitiesStart() {
+ return city.getPosition();
+ }
+ public int getCitiesEnd() {
+ return city.getEndPos();
+ }
+
+ public int getNumExits() {
+ return exitFacility.getNumItems();
+ }
+
+ public int getCountriesStart() {
+ return country.getPosition();
+ }
+
+ public int getCountriesEnd() {
+ return country.getEndPos();
+ }
+
+ public int getRegionsStart() {
+ return region.getPosition();
+ }
+
+ public int getRegionsEnd() {
+ return region.getEndPos();
+ }
+
+ public int getNumHighways() {
+ return highway.getNumItems();
+ }
+
+ public int getZipsStart() {
+ return zip.getPosition();
+ }
+
+ public int getZipsEnd() {
+ return zip.getEndPos();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/Region.java b/src/uk/me/parabola/imgfmt/app/lbl/Region.java
new file mode 100644
index 0000000..36d7ede
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/Region.java
@@ -0,0 +1,62 @@
+/*
+ * 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: Jan 1, 2008
+ */
+package uk.me.parabola.imgfmt.app.lbl;
+
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * A region is in a country and contains one or more cities.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Region {
+ private char index;
+
+ private final Country country;
+ private Label label;
+
+ public Region(Country country) {
+ this.country = country;
+ }
+
+ public void write(ImgFileWriter writer) {
+ writer.putChar(country.getIndex());
+ writer.put3(label.getOffset());
+ }
+
+ public char getIndex() {
+ assert index > 0 : "Index not yet set";
+ return index;
+ }
+
+ public Country getCountry() {
+ return country;
+ }
+
+ public void setIndex(int index) {
+ this.index = (char)index;
+ }
+
+ public void setLabel(Label label) {
+ this.label = label;
+ }
+
+ public Label getLabel() {
+ return label;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/Zip.java b/src/uk/me/parabola/imgfmt/app/lbl/Zip.java
new file mode 100644
index 0000000..08e5560
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/Zip.java
@@ -0,0 +1,52 @@
+/*
+ * 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: Jan 1, 2008
+ */
+package uk.me.parabola.imgfmt.app.lbl;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+
+/**
+ * A zip or postal code record.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Zip {
+ // The index is not stored in the file, you just use the index of it in
+ // the section.
+ private int index;
+ private Label label;
+
+ public void write(ImgFileWriter writer) {
+ writer.put3(label.getOffset());
+ }
+
+ public Label getLabel() {
+ return label;
+ }
+
+ public void setLabel(Label label) {
+ this.label = label;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public void setIndex(int index) {
+ this.index = index;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/package.html b/src/uk/me/parabola/imgfmt/app/lbl/package.html
new file mode 100644
index 0000000..09e910b
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/package.html
@@ -0,0 +1,7 @@
+<body><h3>The LBL file</h3>
+<p>This file holds the textual labels. There are a number of different
+formats that the text is stored in, the default format is a space saving format
+that saves characters in 6 bits but doesn't allow for non-ascii characters.</p>
+
+<p>This file can also hold region, town/city and point of interest names</p>
+</body>
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/app/map/Map.java b/src/uk/me/parabola/imgfmt/app/map/Map.java
new file mode 100644
index 0000000..18f94fb
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/map/Map.java
@@ -0,0 +1,328 @@
+/*
+ * 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: 03-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app.map;
+
+import uk.me.parabola.imgfmt.FileExistsException;
+import uk.me.parabola.imgfmt.FileNotWritableException;
+import uk.me.parabola.imgfmt.FileSystemParam;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.ImgFile;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.lbl.LBLFile;
+import uk.me.parabola.imgfmt.app.net.NETFile;
+import uk.me.parabola.imgfmt.app.net.NODFile;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.trergn.InternalFiles;
+import uk.me.parabola.imgfmt.app.trergn.MapObject;
+import uk.me.parabola.imgfmt.app.trergn.PointOverview;
+import uk.me.parabola.imgfmt.app.trergn.PolygonOverview;
+import uk.me.parabola.imgfmt.app.trergn.PolylineOverview;
+import uk.me.parabola.imgfmt.app.trergn.RGNFile;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+import uk.me.parabola.imgfmt.app.trergn.TREFile;
+import uk.me.parabola.imgfmt.app.trergn.Zoom;
+import uk.me.parabola.imgfmt.fs.DirectoryEntry;
+import uk.me.parabola.imgfmt.fs.FileSystem;
+import uk.me.parabola.imgfmt.sys.ImgFS;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.combiners.OverviewBuilder;
+import uk.me.parabola.util.Configurable;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * Holder for a complete map. A map is made up of several files which
+ * include at least the TRE, LBL and RGN files.
+ *
+ * It is the interface for all information about the whole map, such as the
+ * point overviews etc. Subdivision will hold the map elements.
+ *
+ * <p>Needless to say, it has nothing to do with java.util.Map and given
+ * how it has turned out, with all reading functionality in MapReader
+ * it would have been better named MapWriter.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Map implements InternalFiles, Configurable {
+ private static final Logger log = Logger.getLogger(Map.class);
+ private String filename;
+ private String mapName;
+ private FileSystem fileSystem;
+
+ private TREFile treFile;
+ private RGNFile rgnFile;
+ private LBLFile lblFile;
+ private NETFile netFile;
+ private NODFile nodFile;
+
+ // Use createMap() or loadMap() instead of creating a map directly.
+ private Map() {
+ }
+
+ /**
+ * Create a complete map. This consists of (at least) three
+ * files that all have the same basename and different extensions.
+ *
+ * @param mapname The name of the map. This is an 8 digit number as a
+ * string.
+ * @param params Parameters that describe the file system that the map
+ * will be created in.
+ * @return A map object that holds together all the files that make it up.
+ * @throws FileExistsException If the file already exists and we do not
+ * want to overwrite it.
+ * @throws FileNotWritableException If the file cannot
+ * be opened for write.
+ */
+ public static Map createMap(String mapname, String outputdir, FileSystemParam params, String mapnumber, Sort sort)
+ throws FileExistsException, FileNotWritableException
+ {
+ Map m = new Map();
+ m.mapName = mapname;
+ String outFilename = Utils.joinPath(outputdir, mapname, "img");
+
+ FileSystem fs = ImgFS.createFs(outFilename, params);
+ m.filename = outFilename;
+ m.fileSystem = fs;
+
+ m.rgnFile = new RGNFile(m.fileSystem.create(mapnumber + ".RGN"));
+ m.treFile = new TREFile(m.fileSystem.create(mapnumber + ".TRE"));
+ m.lblFile = new LBLFile(m.fileSystem.create(mapnumber + ".LBL"), sort);
+
+ int mapid;
+ try {
+ mapid = Integer.parseInt(mapnumber);
+ } catch (NumberFormatException e) {
+ mapid = 0;
+ }
+ m.treFile.setMapId(mapid);
+ m.fileSystem = fs;
+
+ return m;
+ }
+
+ public void config(EnhancedProperties props) {
+ // we don't want routing infos in the overview map (for now)
+ if (OverviewBuilder.isOverviewImg(mapName) == false){
+ try {
+ if (props.containsKey("route")) {
+ addNet();
+ addNod();
+ } else if (props.containsKey("net")) {
+ addNet();
+ }
+ } catch (FileExistsException e) {
+ log.warn("Could not add NET and/or NOD sections");
+ }
+ }
+ treFile.config(props);
+ }
+
+ protected void addNet() throws FileExistsException {
+ netFile = new NETFile(fileSystem.create(mapName + ".NET"));
+ }
+
+ protected void addNod() throws FileExistsException {
+ nodFile = new NODFile(fileSystem.create(mapName + ".NOD"), true);
+ }
+
+ /**
+ * Set the area that the map covers.
+ * @param area The outer bounds of the map.
+ */
+ public void setBounds(Area area) {
+ treFile.setBounds(area);
+ }
+
+ /**
+ * Add a copyright message to the map.
+ * @param str the copyright message. The second (last?) one set
+ * gets shown when the device starts (sometimes?).
+ */
+ public void addCopyright(String str) {
+ Label cpy = lblFile.newLabel(str);
+ treFile.addCopyright(cpy);
+ }
+
+ /**
+ * There is an area after the TRE header and before its data
+ * starts that can be used to save any old junk it seems.
+ *
+ * @param info Any string.
+ */
+ public void addInfo(String info) {
+ treFile.addInfo(info);
+ }
+
+ /**
+ * Create a new zoom level. The level 0 is the most detailed and
+ * level 15 is the most general. Most maps would just have 4
+ * different levels or less. We are just having two to start with
+ * but will probably advance to at least 3.
+ *
+ * @param level The zoom level, and integer between 0 and 15. Its
+ * like a logical zoom level.
+ * @param bits The number of bits per coordinate, a measure of
+ * the actual amount of detail that will be in the level. So this
+ * is like a physical zoom level.
+ * @return The zoom object.
+ */
+ public Zoom createZoom(int level, int bits) {
+ return treFile.createZoom(level, bits);
+ }
+
+ /**
+ * Create the top level division. It must be empty afaik and cover
+ * the whole area of the map.
+ *
+ * @param area The whole map area.
+ * @param zoom The zoom level that you want the top level to be
+ * at. Its going to be at least level 1.
+ * @return The top level division.
+ */
+ public Subdivision topLevelSubdivision(Area area, Zoom zoom) {
+ zoom.setInherited(true); // May not always be necessary/desired
+
+ InternalFiles ifiles = this;
+ Subdivision sub = Subdivision.topLevelSubdivision(ifiles, area, zoom);
+ rgnFile.startDivision(sub);
+ return sub;
+ }
+
+ /**
+ * Create a subdivision that is beneath the top level. We have to
+ * pass the parent division.
+ * <p>
+ * Note that you cannot create these all up front. You must
+ * create it, fill it will its map elements and then create the
+ * next one. You must also start at the top level and work down.
+ *
+ * @param parent The parent subdivision.
+ * @param area The area of the new child subdiv.
+ * @param zoom The zoom level of the child.
+ * @return The new division.
+ */
+ public Subdivision createSubdivision(Subdivision parent, Area area, Zoom zoom)
+ {
+ log.debug("creating division");
+ return parent.createSubdivision(this, area, zoom);
+ }
+
+ public void addPointOverview(PointOverview ov) {
+ treFile.addPointOverview(ov);
+ }
+
+ public void addPolylineOverview(PolylineOverview ov) {
+ treFile.addPolylineOverview(ov);
+ }
+
+ public void addPolygonOverview(PolygonOverview ov) {
+ treFile.addPolygonOverview(ov);
+ }
+
+ /**
+ * Adds the bits to the point of interest flags.
+ * @param flags The POI flags.
+ */
+ public void addPoiDisplayFlags(int flags) {
+ treFile.addPoiDisplayFlags((byte) flags);
+ }
+
+ public void addMapObject(MapObject item) {
+ rgnFile.addMapObject(item);
+ }
+
+ public void setSort(Sort sort) {
+ lblFile.setSort(sort);
+ if (netFile != null)
+ netFile.setSort(sort);
+ }
+
+ public void setLabelCharset(String desc, boolean forceUpper) {
+ lblFile.setCharacterType(desc, forceUpper);
+ }
+
+ /**
+ * Close this map by closing all the constituent files.
+ *
+ * Some history:
+ */
+ public void close() {
+ ImgFile[] files = {
+ rgnFile, treFile, lblFile,
+ netFile, nodFile
+ };
+
+ int headerSlotsRequired = 0;
+
+ FileSystemParam param = fileSystem.fsparam();
+ int blockSize = param.getBlockSize();
+
+ for (ImgFile f : files) {
+ if (f == null)
+ continue;
+
+ long len = f.getSize();
+ log.debug("img file len=", len);
+
+ // Blocks required for this file
+ int nBlocks = (int) ((len + blockSize - 1) / blockSize);
+
+ // Now we calculate how many directory blocks we need, you have
+ // to round up as files do not share directory blocks.
+ headerSlotsRequired += (nBlocks + DirectoryEntry.SLOTS_PER_ENTRY - 1)/DirectoryEntry.SLOTS_PER_ENTRY;
+ }
+
+ log.debug("header slots required", headerSlotsRequired);
+
+ // A header slot is always 512 bytes, so we need to calculate the
+ // number of blocks if the block-size is different.
+ // There are 2 slots for the header itself.
+ int blocksRequired = 2 + headerSlotsRequired * 512 / blockSize;
+
+ param.setReservedDirectoryBlocks(blocksRequired);
+ fileSystem.fsparam(param);
+
+ for (ImgFile f : files)
+ Utils.closeFile(f);
+
+ fileSystem.close();
+ }
+
+ public String getFilename() {
+ return filename;
+ }
+
+ public RGNFile getRgnFile() {
+ return rgnFile;
+ }
+
+ public LBLFile getLblFile() {
+ return lblFile;
+ }
+
+ public TREFile getTreFile() {
+ return treFile;
+ }
+
+ public NETFile getNetFile() {
+ return netFile;
+ }
+
+ public NODFile getNodFile() {
+ return nodFile;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/map/MapReader.java b/src/uk/me/parabola/imgfmt/app/map/MapReader.java
new file mode 100644
index 0000000..1d02045
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/map/MapReader.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.map;
+
+import java.io.Closeable;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.lbl.City;
+import uk.me.parabola.imgfmt.app.lbl.Country;
+import uk.me.parabola.imgfmt.app.lbl.LBLFileReader;
+import uk.me.parabola.imgfmt.app.lbl.Region;
+import uk.me.parabola.imgfmt.app.lbl.Zip;
+import uk.me.parabola.imgfmt.app.net.NETFileReader;
+import uk.me.parabola.imgfmt.app.net.RoadDef;
+import uk.me.parabola.imgfmt.app.trergn.Point;
+import uk.me.parabola.imgfmt.app.trergn.Polygon;
+import uk.me.parabola.imgfmt.app.trergn.Polyline;
+import uk.me.parabola.imgfmt.app.trergn.RGNFileReader;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+import uk.me.parabola.imgfmt.app.trergn.TREFileReader;
+import uk.me.parabola.imgfmt.app.trergn.Zoom;
+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.ImgFS;
+
+/**
+ * This is a view of a .img file when we are reading it. The {@link Map}
+ * class is the equivalent for writing.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MapReader implements Closeable {
+ private final TREFileReader treFile;
+ private final RGNFileReader rgnFile;
+ private final LBLFileReader lblFile;
+ private final NETFileReader netFile;
+
+ public static final boolean WITH_EXT_TYPE_DATA = true;
+ public static final boolean WITHOUT_EXT_TYPE_DATA = false;
+
+ private final Deque<Closeable> toClose = new ArrayDeque<Closeable>();
+
+ public MapReader(String filename) throws FileNotFoundException {
+ FileSystem fs = ImgFS.openFs(filename);
+ saveForClose(fs);
+
+ List<DirectoryEntry> entries = fs.list();
+
+ // Find the TRE entry
+ String mapname = null;
+ for (DirectoryEntry ent : entries) {
+ if ("TRE".equals(ent.getExt())) {
+ mapname = ent.getName();
+ break;
+ }
+ }
+
+ if (mapname == null)
+ throw new FileNotFoundException("No TRE entry in img file");
+
+ ImgChannel chan = fs.open(mapname + ".TRE", "r");
+ treFile = new TREFileReader(chan);
+ saveForClose(treFile, chan);
+
+ chan = fs.open(mapname + ".RGN", "r");
+ rgnFile = new RGNFileReader(chan);
+ saveForClose(rgnFile, chan);
+
+ chan = fs.open(mapname + ".LBL", "r");
+ lblFile = new LBLFileReader(chan);
+ saveForClose(lblFile, chan);
+
+ // The NET file is optional
+ NETFileReader nr;
+ try {
+ chan = fs.open(mapname + ".NET", "r");
+ nr = new NETFileReader(chan);
+ nr.setLabels(lblFile);
+ nr.setCities(lblFile.getCities());
+ nr.setZips(lblFile.getZips());
+ saveForClose(nr);
+ } catch (FileNotFoundException e) {
+ nr = null;
+ }
+ netFile = nr;
+
+ rgnFile.setNetFile(netFile);
+ rgnFile.setLblFile(lblFile);
+ }
+
+ /**
+ * Get a list of all the points for a given level.
+ * @param level The level, lower numbers are the most detailed.
+ */
+ public List<Point> pointsForLevel(int level, boolean withExtType) {
+ List<Point> points = new ArrayList<Point>();
+
+ Subdivision[] subdivisions = treFile.subdivForLevel(level);
+ for (Subdivision sd : subdivisions) {
+ List<Point> subdivPoints = rgnFile.pointsForSubdiv(sd, withExtType);
+ points.addAll(subdivPoints);
+ }
+
+ return points;
+ }
+
+ public Zoom[] getLevels() {
+ return treFile.getMapLevels();
+ }
+
+ public String[] getCopyrights(){
+ return treFile.getCopyrights(lblFile);
+ }
+ /**
+ * Get a list of all the lines for a given level.
+ * @param level The level, lower numbers are the most detailed.
+ */
+ public List<Polyline> linesForLevel(int level) {
+ ArrayList<Polyline> lines = new ArrayList<Polyline>();
+
+ Subdivision[] subdivisions = treFile.subdivForLevel(level);
+ for (Subdivision div : subdivisions) {
+ List<Polyline> subdivLines = rgnFile.linesForSubdiv(div);
+ lines.addAll(subdivLines);
+ }
+
+ return lines;
+ }
+
+
+ public List<Polygon> shapesForLevel(int level) {
+ ArrayList<Polygon> shapes = new ArrayList<Polygon>();
+
+ Subdivision[] subdivisions = treFile.subdivForLevel(level);
+ for (Subdivision div : subdivisions) {
+ List<Polygon> subdivShapes = rgnFile.shapesForSubdiv(div);
+ shapes.addAll(subdivShapes);
+ }
+
+ return shapes;
+ }
+
+ public void close() throws IOException {
+ for (Closeable c : toClose)
+ Utils.closeFile(c);
+ }
+
+ private void saveForClose(Closeable c1, Closeable c2) {
+ saveForClose(c1);
+ saveForClose(c2);
+ }
+
+ private void saveForClose(Closeable c) {
+ toClose.push(c);
+ }
+
+ public List<City> getCities() {
+ return lblFile.getCities();
+ }
+
+ public List<Country> getCountries() {
+ return lblFile.getCountries();
+ }
+
+ public List<Region> getRegions() {
+ return lblFile.getRegions();
+ }
+
+ public List<Zip> getZips() {
+ // need to be joined with zip information from the addresses
+ // where are the addresses stored?
+ return lblFile.getZips();
+ }
+
+ public Area getTreBounds() {
+ return treFile.getBounds();
+ }
+
+ public java.util.Map<Integer, String> getLabels() {
+ return lblFile.getLabels();
+ }
+
+ public List<RoadDef> getRoads() {
+ if (netFile == null)
+ return Collections.emptyList();
+ return netFile.getRoads();
+ }
+
+ public int getEncodingType(){
+ return lblFile.getEncodingType();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/map/package.html b/src/uk/me/parabola/imgfmt/app/map/package.html
new file mode 100644
index 0000000..3466175
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/map/package.html
@@ -0,0 +1,5 @@
+<body>
+<h3>Complete maps</h3>
+<p>A complete map consists of at least a TRE RGN and LBL file.
+This package holds classes that combine these files into a whole.</p>
+</body>
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/ConfigBase.java b/src/uk/me/parabola/imgfmt/app/mdr/ConfigBase.java
new file mode 100644
index 0000000..a986eb4
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/ConfigBase.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+/**
+ * A base class that provides access to the MDR configuration data.
+ */
+public abstract class ConfigBase {
+ private MdrConfig config;
+
+ protected boolean isForDevice() {
+ return config.isForDevice();
+ }
+
+ public void setConfig(MdrConfig config) {
+ this.config = config;
+ }
+
+ protected MdrConfig getConfig() {
+ return config;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/HasHeaderFlags.java b/src/uk/me/parabola/imgfmt/app/mdr/HasHeaderFlags.java
new file mode 100644
index 0000000..f472b75
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/HasHeaderFlags.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2008 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 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.imgfmt.app.mdr;
+
+/**
+ * @author Steve Ratcliffe
+ */
+public interface HasHeaderFlags {
+ /**
+ * Return the value that is put in the header after the section start, len
+ * and record size fields.
+ * At least in some cases this field controls what fields and/or size
+ * exist in the section.
+ * @return The correct value based on the contents of the section. Zero
+ * if nothing needs to be done.
+ */
+ int getExtraValue();
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/MDRFile.java b/src/uk/me/parabola/imgfmt/app/mdr/MDRFile.java
new file mode 100644
index 0000000..4dbd295
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/MDRFile.java
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import java.util.Arrays;
+
+import uk.me.parabola.imgfmt.app.BufferedImgFileReader;
+import uk.me.parabola.imgfmt.app.FileBackedImgFileWriter;
+import uk.me.parabola.imgfmt.app.ImgFile;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.lbl.Country;
+import uk.me.parabola.imgfmt.app.lbl.Region;
+import uk.me.parabola.imgfmt.app.lbl.Zip;
+import uk.me.parabola.imgfmt.app.mdr.MdrSection.PointerSizes;
+import uk.me.parabola.imgfmt.app.net.RoadDef;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.trergn.Point;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+
+/**
+ * The MDR file. This is embedded into a .img file, either its own
+ * separate one, or as one file in the gmapsupp.img.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MDRFile extends ImgFile {
+ private final MDRHeader mdrHeader;
+
+ // The sections
+ private final Mdr1 mdr1;
+ private final Mdr4 mdr4;
+ private final Mdr5 mdr5;
+ private final Mdr6 mdr6;
+ private final Mdr7 mdr7;
+ private final Mdr8 mdr8;
+ private final Mdr9 mdr9;
+ private final Mdr10 mdr10;
+ private final Mdr11 mdr11;
+ private final Mdr12 mdr12;
+ private final Mdr13 mdr13;
+ private final Mdr14 mdr14;
+ private final Mdr15 mdr15;
+ private final Mdr17 mdr17;
+ private final Mdr18 mdr18;
+ private final Mdr19 mdr19;
+ private final Mdr20 mdr20;
+ private final Mdr21 mdr21;
+ private final Mdr22 mdr22;
+ private final Mdr23 mdr23;
+ private final Mdr24 mdr24;
+ private final Mdr25 mdr25;
+ private final Mdr26 mdr26;
+ private final Mdr27 mdr27;
+ private final Mdr28 mdr28;
+ private final Mdr29 mdr29;
+
+ private int currentMap;
+
+ private final boolean forDevice;
+
+ private final MdrSection[] sections;
+ private PointerSizes sizes;
+
+ public MDRFile(ImgChannel chan, MdrConfig config) {
+ Sort sort = config.getSort();
+
+ forDevice = config.isForDevice();
+
+ mdrHeader = new MDRHeader(config.getHeaderLen());
+ mdrHeader.setSort(sort);
+ setHeader(mdrHeader);
+ if (config.isWritable()) {
+ ImgFileWriter fileWriter = new FileBackedImgFileWriter(chan, config.getOutputDir());
+ setWriter(fileWriter);
+
+ // Position at the start of the writable area.
+ position(mdrHeader.getHeaderLength());
+ } else {
+ setReader(new BufferedImgFileReader(chan));
+ mdrHeader.readHeader(getReader());
+ }
+
+ // Initialise the sections
+ mdr1 = new Mdr1(config);
+ mdr4 = new Mdr4(config);
+ mdr5 = new Mdr5(config);
+ mdr6 = new Mdr6(config);
+ mdr7 = new Mdr7(config);
+ mdr8 = new Mdr8(config);
+ mdr9 = new Mdr9(config);
+ mdr10 = new Mdr10(config);
+ mdr11 = new Mdr11(config);
+ mdr12 = new Mdr12(config);
+ mdr13 = new Mdr13(config);
+ mdr14 = new Mdr14(config);
+ mdr15 = new Mdr15(config);
+ mdr17 = new Mdr17(config);
+ mdr18 = new Mdr18(config);
+ mdr19 = new Mdr19(config);
+ mdr20 = new Mdr20(config);
+ mdr21 = new Mdr21(config);
+ mdr22 = new Mdr22(config);
+ mdr23 = new Mdr23(config);
+ mdr24 = new Mdr24(config);
+ mdr25 = new Mdr25(config);
+ mdr26 = new Mdr26(config);
+ mdr27 = new Mdr27(config);
+ mdr28 = new Mdr28(config);
+ mdr29 = new Mdr29(config);
+
+ this.sections = new MdrSection[]{
+ null,
+ mdr1, null, null, mdr4, mdr5, mdr6,
+ mdr7, mdr8, mdr9, mdr10, mdr11, mdr12,
+ mdr13, mdr14, mdr15, null, mdr17, mdr18, mdr19,
+ mdr20, mdr21, mdr22, mdr23, mdr24, mdr25,
+ mdr26, mdr27, mdr28, mdr29,
+ };
+
+ mdr11.setMdr10(mdr10);
+ }
+
+ /**
+ * Add a map to the index. You must add the map, then all of the items
+ * that belong to it, before adding the next map.
+ * @param mapName The numeric name of the map.
+ * @param codePage The code page of the map.
+ */
+ public void addMap(int mapName, int codePage) {
+ currentMap++;
+ mdr1.addMap(mapName);
+ Sort sort = mdrHeader.getSort();
+
+ if (sort.getCodepage() != codePage)
+ System.err.println("WARNING: input files have different code pages");
+ }
+
+ public Mdr14Record addCountry(Country country) {
+ Mdr14Record record = new Mdr14Record();
+
+ String name = country.getLabel().getText();
+ record.setMapIndex(currentMap);
+ record.setCountryIndex((int) country.getIndex());
+ record.setLblOffset(country.getLabel().getOffset());
+ record.setName(name);
+ record.setStrOff(createString(name));
+
+ mdr14.addCountry(record);
+ return record;
+ }
+
+ public Mdr13Record addRegion(Region region, Mdr14Record country) {
+ Mdr13Record record = new Mdr13Record();
+
+ String name = region.getLabel().getText();
+ record.setMapIndex(currentMap);
+ record.setLblOffset(region.getLabel().getOffset());
+ record.setCountryIndex(region.getCountry().getIndex());
+ record.setRegionIndex(region.getIndex());
+ record.setName(name);
+ record.setStrOffset(createString(name));
+ record.setMdr14(country);
+
+ mdr13.addRegion(record);
+ return record;
+ }
+
+ public void addCity(Mdr5Record city) {
+ int labelOffset = city.getLblOffset();
+ if (labelOffset != 0) {
+ String name = city.getName();
+ assert name != null : "off=" + labelOffset;
+ city.setMapIndex(currentMap);
+ city.setStringOffset(createString(name));
+ mdr5.addCity(city);
+ }
+ }
+
+ public void addZip(Zip zip) {
+ int strOff = createString(zip.getLabel().getText());
+ mdr6.addZip(currentMap, zip, strOff);
+ }
+
+ public void addPoint(Point point, Mdr5Record city, boolean isCity) {
+ assert currentMap > 0;
+
+ int fullType = point.getType();
+ if (!MdrUtils.canBeIndexed(fullType))
+ return;
+
+ Label label = point.getLabel();
+ String name = label.getText();
+ int strOff = createString(name);
+
+ Mdr11Record poi = mdr11.addPoi(currentMap, point, name, strOff);
+ poi.setCity(city);
+ poi.setIsCity(isCity);
+ poi.setType(fullType);
+
+ mdr4.addType(point.getType());
+ }
+
+ public void addStreet(RoadDef street, Mdr5Record mdrCity) {
+ // Add a separate record for each name
+ for (Label lab : street.getLabels()) {
+ if (lab == null)
+ break;
+
+ if (lab.getOffset() == 0)
+ continue;
+
+ String name = lab.getText();
+ String cleanName = cleanUpName(name);
+ int strOff = createString(cleanName);
+
+ // We sort on the dirty name (ie with the Garmin shield codes) although those codes do not
+ // affect the sort order. The string for mdr15 does not include the shield codes.
+ mdr7.addStreet(currentMap, name, lab.getOffset(), strOff, mdrCity);
+ }
+ }
+
+ /**
+ * Remove shields and other kinds of strange characters. Perform any
+ * rearrangement of the name to make it searchable.
+ * @param name The street name as read from the img file.
+ * @return The name as it will go into the index.
+ */
+ private String cleanUpName(String name) {
+ return Label.stripGarminCodes(name);
+ }
+
+ public void write() {
+ mdr15.release();
+
+ for (MdrSection s : sections) {
+ if (s != null)
+ s.finish();
+ }
+
+ ImgFileWriter writer = getWriter();
+ writeSections(writer);
+
+ // Now refresh the header
+ position(0);
+ getHeader().writeHeader(writer);
+ }
+
+ /**
+ * Write all the sections out.
+ *
+ * The order of all the operations in this method is important. The order
+ * of the sections in the actual output file doesn't matter at all, so
+ * they can be re-ordered to suit.
+ *
+ * Most of the complexity here is arranging the order of things so that the smallest
+ * amount of temporary memory is required.
+ *
+ * @param writer File is written here.
+ */
+ private void writeSections(ImgFileWriter writer) {
+ sizes = new MdrMapSection.PointerSizes(sections);
+
+ // Deal with the dependencies between the sections. The order of the following
+ // statements is sometimes important.
+ mdr28.buildFromRegions(mdr13.getRegions());
+ mdr23.sortRegions(mdr13.getRegions());
+ mdr29.buildFromCountries(mdr14.getCountries());
+ mdr24.sortCountries(mdr14.getCountries());
+ mdr26.sortMdr28(mdr28.getIndex());
+
+ writeSection(writer, 4, mdr4);
+
+ mdr1.preWrite();
+ mdr5.preWrite();
+ mdr20.preWrite();
+
+ // We write the following sections that contain per-map data, in the
+ // order of the subsections of the reverse index that they are associated
+ // with.
+ writeSection(writer, 11, mdr11);
+ mdr10.setNumberOfPois(mdr11.getNumberOfPois());
+ mdr12.setIndex(mdr11.getIndex());
+ mdr19.setPois(mdr11.getPois());
+ mdr17.addPois(mdr11.getPois());
+ mdr11.release();
+
+ if (forDevice) {
+ mdr19.preWrite();
+ writeSection(writer, 19, mdr19);
+ mdr18.setPoiTypes(mdr19.getPoiTypes());
+ mdr19.release();
+ writeSection(writer, 18, mdr18);
+ }
+
+ writeSection(writer, 10, mdr10);
+ mdr9.setGroups(mdr10.getGroupSizes());
+ mdr10.release();
+
+ // mdr7 depends on the size of mdr20, so mdr20 must be built first
+ mdr7.preWrite();
+ mdr20.buildFromStreets(mdr7.getStreets());
+ writeSection(writer, 7, mdr7);
+
+ writeSection(writer, 5, mdr5);
+ mdr25.sortCities(mdr5.getCities());
+ mdr27.sortCities(mdr5.getCities());
+ mdr17.addCities(mdr5.getSortedCities());
+ mdr5.release();
+ writeSection(writer, 6, mdr6);
+
+ writeSection(writer, 20, mdr20);
+ mdr20.release();
+
+ mdr21.buildFromStreets(mdr7.getStreets());
+ writeSection(writer, 21, mdr21);
+ mdr21.release();
+
+ mdr22.buildFromStreets(mdr7.getStreets());
+ mdr8.setIndex(mdr7.getIndex());
+ mdr17.addStreets(mdr7.getSortedStreets());
+
+ mdr7.release();
+ writeSection(writer, 22, mdr22);
+ mdr17.addStreetsByCountry(mdr22.getStreets());
+ mdr22.release();
+
+ if (forDevice) {
+ writeSection(writer, 17, mdr17);
+ mdr17.release();
+ }
+
+ // The following do not have mdr1 subsections
+ //writeSection(writer, 8, mdr8);
+ writeSection(writer, 9, mdr9);
+ writeSection(writer, 12, mdr12);
+ writeSection(writer, 13, mdr13);
+ writeSection(writer, 14, mdr14);
+ writeSection(writer, 15, mdr15);
+
+ writeSection(writer, 23, mdr23);
+ writeSection(writer, 24, mdr24);
+ writeSection(writer, 25, mdr25);
+ mdr28.preWrite(); // TODO reorder writes below so this is not needed. Changes the output file though
+ writeSection(writer, 26, mdr26);
+ writeSection(writer, 27, mdr27);
+ writeSection(writer, 28, mdr28);
+ writeSection(writer, 29, mdr29);
+
+ // write the reverse index last.
+ mdr1.writeSubSections(writer);
+ mdrHeader.setPosition(1, writer.position());
+
+ mdr1.writeSectData(writer);
+ mdrHeader.setItemSize(1, mdr1.getItemSize());
+ mdrHeader.setEnd(1, writer.position());
+ mdrHeader.setExtraValue(1, mdr1.getExtraValue());
+ }
+
+ /**
+ * Write out the given single section.
+ */
+ private void writeSection(ImgFileWriter writer, int sectionNumber, MdrSection section) {
+
+ // Some sections are just not written in the device config
+ if (forDevice && Arrays.asList(12, 13, 14, 15, 21, 23, 26, 27, 28).contains(sectionNumber))
+ return;
+
+ section.setSizes(sizes);
+
+ mdrHeader.setPosition(sectionNumber, writer.position());
+ mdr1.setStartPosition(sectionNumber);
+
+ section.preWrite();
+ if (!forDevice && section instanceof MdrMapSection) {
+ MdrMapSection mapSection = (MdrMapSection) section;
+ mapSection.setMapIndex(mdr1);
+ mapSection.initIndex(sectionNumber);
+ }
+
+ if (section instanceof HasHeaderFlags)
+ mdrHeader.setExtraValue(sectionNumber, ((HasHeaderFlags) section).getExtraValue());
+
+ section.writeSectData(writer);
+
+ int itemSize = section.getItemSize();
+ if (itemSize > 0)
+ mdrHeader.setItemSize(sectionNumber, itemSize);
+
+ mdrHeader.setEnd(sectionNumber, writer.position());
+ mdr1.setEndPosition(sectionNumber);
+ }
+
+ /**
+ * Creates a string in MDR 15 and returns an offset value that can be
+ * used to refer to it in the other sections.
+ * @param str The text of the string.
+ * @return An offset value.
+ */
+ private int createString(String str) {
+ return mdr15.createString(str);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/MDRHeader.java b/src/uk/me/parabola/imgfmt/app/mdr/MDRHeader.java
new file mode 100644
index 0000000..ae5f99a
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/MDRHeader.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import uk.me.parabola.imgfmt.ReadFailedException;
+import uk.me.parabola.imgfmt.app.CommonHeader;
+import uk.me.parabola.imgfmt.app.ImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Section;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+
+/**
+ * The header of the MDR file.
+ *
+ * Note that there are many possible sections in this file and that
+ * only a certain number of them are needed. There are also many
+ * different lengths for the record sizes of the sections. Finally
+ * there are different sections and record sizes for the version
+ * that gets loaded into the gmapsupp.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MDRHeader extends CommonHeader {
+
+ private static final int MAX_SECTIONS = 40;
+ private final Section[] sections = new Section[MAX_SECTIONS+1];
+
+ private Sort sort;
+
+ public MDRHeader(int headerLen) {
+ super(headerLen, "GARMIN MDR");
+
+ // Do a quick initialisation. Link every section to the
+ // previous one so that all the positions are correct.
+ for (int i = 1; i < sections.length; i++) {
+ Section prev = (i == 0) ? null : sections[i - 1];
+ sections[i] = new Section(prev);
+ }
+ sections[1].setPosition(getHeaderLength());
+ }
+
+ protected void readFileHeader(ImgFileReader reader) throws ReadFailedException {
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Write out the application header.
+ */
+ protected void writeFileHeader(ImgFileWriter writer) {
+ writer.putChar((char) sort.getCodepage());
+ writer.putChar((char) sort.getId1());
+ writer.putChar((char) sort.getId2());
+ writer.putChar((char) 14);
+
+ sections[1].writeSectionInfo(writer, true, true);
+ sections[2].writeSectionInfo(writer, true, true);
+ sections[3].writeSectionInfo(writer, true, true);
+ sections[4].writeSectionInfo(writer, true, true);
+ sections[5].writeSectionInfo(writer, true, true);
+ sections[6].writeSectionInfo(writer, true, true);
+ sections[7].writeSectionInfo(writer, true, true);
+ sections[8].writeSectionInfo(writer, true, true);
+ sections[9].writeSectionInfo(writer, true, true);
+ sections[10].writeSectionInfo(writer, false, true);
+ sections[11].writeSectionInfo(writer, true, true);
+ sections[12].writeSectionInfo(writer, true, true);
+ sections[13].writeSectionInfo(writer, true, true);
+ sections[14].writeSectionInfo(writer, true, true);
+ sections[15].writeSectionInfo(writer);
+ writer.put((byte) 0);
+
+ sections[16].writeSectionInfo(writer, true, true);
+ sections[17].writeSectionInfo(writer, false, true);
+ for (int n = 18; n <= 30; n++)
+ sections[n].writeSectionInfo(writer, true, true);
+ }
+
+ public void setItemSize(int sectionNumber, int itemSize) {
+ Section section = sections[sectionNumber];
+ section.setItemSize((char) itemSize);
+ }
+
+ public void setExtraValue(int sectionNumber, int extraValue) {
+ Section section = sections[sectionNumber];
+ section.setExtraValue(extraValue);
+ }
+
+ public void setPosition(int sectionNumber, int position) {
+ sections[sectionNumber].setPosition(position);
+ }
+
+ public void setEnd(int sectionNumber, int position) {
+ Section s = sections[sectionNumber];
+ s.setSize(position - s.getPosition());
+ }
+
+ public Sort getSort() {
+ return sort;
+ }
+
+ public void setSort(Sort sort) {
+ this.sort = sort;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr1.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr1.java
new file mode 100644
index 0000000..9ab0c9a
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr1.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * The section MDR 1 contains a list of maps and for each map
+ * an offset to a reverse index for that map.
+ *
+ * The reverse index consists of a number of sections, that I call sub-sections
+ * here. The sub-sections are all lists of record numbers in other sections
+ * in the MDR that contain records belonging to more than one map.
+ *
+ * Using the index you could extract records that belong to an individual map
+ * from other MDR sections without having to go through them all and check
+ * which map they belong to.
+ *
+ * The subsections are as follows:
+ *
+ * sub1 points into MDR 11 (POIs)
+ * sub2 points into MDR 10 (POI types)
+ * sub3 points into MDR 7 (street names)
+ * sub4 points into MDR 5 (cities)
+ * sub5 points into MDR 6 (zips)
+ * sub6 points into MDR 20
+ * sub7 points into MDR 21
+ * sub8 points into MDR 22
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr1 extends MdrSection implements HasHeaderFlags {
+ private final List<Mdr1Record> maps = new ArrayList<Mdr1Record>();
+
+ public Mdr1(MdrConfig config) {
+ setConfig(config);
+ }
+
+ /**
+ * Add a map. Create an MDR1 record for it and also allocate its reverse
+ * index if this is not for a device.
+ * @param mapNumber The map index number.
+ */
+ public void addMap(int mapNumber) {
+ Mdr1Record rec = new Mdr1Record(mapNumber, getConfig());
+ maps.add(rec);
+
+ if (!isForDevice()) {
+ Mdr1MapIndex mapIndex = new Mdr1MapIndex();
+ rec.setMdrMapIndex(mapIndex);
+ }
+ }
+
+ /**
+ * The maps must be sorted in numerical order.
+ */
+ public void finish() {
+ Collections.sort(maps, new Comparator<Mdr1Record>() {
+ public int compare(Mdr1Record o1, Mdr1Record o2) {
+ if (o1.getMapNumber() == o2.getMapNumber())
+ return 0;
+ else if (o1.getMapNumber() < o2.getMapNumber())
+ return -1;
+ else
+ return 1;
+ }
+ });
+ }
+
+ public void writeSubSections(ImgFileWriter writer) {
+ if (isForDevice())
+ return;
+ for (Mdr1Record rec : maps) {
+ rec.setIndexOffset(writer.position());
+ Mdr1MapIndex mapIndex = rec.getMdrMapIndex();
+ mapIndex.writeSubSection(writer);
+ }
+ }
+
+ /**
+ * This is written right at the end after we know all the offsets in
+ * the MDR 1 record.
+ * @param writer The mdr 1 records are written out to this writer.
+ */
+ public void writeSectData(ImgFileWriter writer) {
+ boolean revIndex = (getExtraValue() & 1) != 0;
+ for (Mdr1Record rec : maps) {
+ writer.putInt(rec.getMapNumber());
+ if (revIndex)
+ writer.putInt(rec.getIndexOffset());
+ }
+ }
+
+ public int getItemSize() {
+ return isForDevice()? 4: 8;
+ }
+
+ public void setStartPosition(int sectionNumber) {
+ if (isForDevice())
+ return;
+
+ for (Mdr1Record mi : maps)
+ mi.getMdrMapIndex().startSection(sectionNumber);
+ }
+
+ public void setEndPosition(int sectionNumber) {
+ if (isForDevice())
+ return;
+
+ for (Mdr1Record mi : maps) {
+ mi.getMdrMapIndex().endSection(sectionNumber);
+ }
+}
+
+ public void setPointerSize(int sectionSize, int recordSize) {
+ for (Mdr1Record mi : maps) {
+ Mdr1MapIndex mapIndex = mi.getMdrMapIndex();
+ mapIndex.setPointerSize(sectionSize, recordSize);
+ }
+ }
+
+ public void addPointer(int mapNumber, int recordNumber) {
+ Mdr1MapIndex mi = maps.get(mapNumber - 1).getMdrMapIndex();
+ mi.addPointer(recordNumber);
+ }
+
+ /**
+ * The number of records in this section.
+ *
+ * @return The number of items in the section.
+ */
+ protected int numberOfItems() {
+ return maps.size();
+ }
+
+ public int getExtraValue() {
+ int magic = 0;
+ if (!isForDevice())
+ magic |= 1;
+ return magic;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr10.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr10.java
new file mode 100644
index 0000000..4f3fec3
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr10.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * POI subtype with a reference to MDR11.
+ * These are sorted into groups based on the type, and contain the
+ * subtype.
+ *
+ * The mdr9 section contains an index to this section based on the
+ * the type groups.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr10 extends MdrMapSection {
+ // The maximum group number. Note that this is 1 based, not 0 based.
+ private static final int MAX_GROUP_NUMBER = 9;
+
+ @SuppressWarnings({"unchecked"})
+ private List<Mdr10Record>[] poiTypes = new ArrayList[MAX_GROUP_NUMBER+1];
+
+ private int numberOfPois;
+
+ public Mdr10(MdrConfig config) {
+ setConfig(config);
+
+ for (int i = 1; i <= MAX_GROUP_NUMBER; i++) {
+ poiTypes[i] = new ArrayList<Mdr10Record>();
+ }
+ }
+
+ public void addPoiType(Mdr11Record poi) {
+ Mdr10Record t = new Mdr10Record();
+
+ int type = poi.getType();
+ t.setSubtype(MdrUtils.getSubtypeOrTypeFromFullType(type));
+ t.setMdr11ref(poi);
+
+ int group = MdrUtils.getGroupForPoi(type);
+ if (group == 0)
+ return;
+ poiTypes[group].add(t);
+ }
+
+ public void writeSectData(ImgFileWriter writer) {
+ int count = 0;
+ for (List<Mdr10Record> poiGroup : poiTypes) {
+ if (poiGroup == null)
+ continue;
+
+ Collections.sort(poiGroup);
+
+ String lastName = null;
+ int lastSub = -1;
+ for (Mdr10Record t : poiGroup) {
+
+ count++;
+ Mdr11Record mdr11ref = t.getMdr11ref();
+ addIndexPointer(mdr11ref.getMapIndex(), count);
+
+ writer.put((byte) t.getSubtype());
+ int offset = mdr11ref.getRecordNumber();
+
+ // Top bit actually represents a non-repeated name. ie if
+ // the bit is not set, then the name is the same as the previous
+ // record.
+ String name = mdr11ref.getName();
+ boolean isNew = !(name.equals(lastName) && (t.getSubtype() == lastSub));
+ putPoiIndex(writer, offset, isNew);
+ lastName = name;
+ lastSub = t.getSubtype();
+ }
+ }
+ }
+
+ /**
+ * Get a list of the group sizes along with the group index number.
+ * @return A map that is guaranteed to iterate in the correct order for
+ * writing mdr9. The key is the group number and the value is the
+ * number of entries in that group.
+ */
+ public Map<Integer, Integer> getGroupSizes() {
+ Map<Integer, Integer> m = new LinkedHashMap<Integer, Integer>();
+
+ for (int i = 1; i < MAX_GROUP_NUMBER; i++) {
+ List<Mdr10Record> poiGroup = poiTypes[i];
+ if (!poiGroup.isEmpty())
+ m.put(i, poiGroup.size());
+ }
+ return m;
+ }
+
+ /**
+ * This does not have a record size.
+ * @return Always zero to indicate that there is not a record size.
+ */
+ public int getItemSize() {
+ return 0;
+ }
+
+ protected int numberOfItems() {
+ return numberOfPois;
+ }
+
+ public void setNumberOfPois(int numberOfPois) {
+ this.numberOfPois = numberOfPois;
+ }
+
+ protected void releaseMemory() {
+ poiTypes = null;
+ }
+
+ public int getExtraValue() {
+ // Nothing to do here
+ return 0;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr10Record.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr10Record.java
new file mode 100644
index 0000000..0303bb7
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr10Record.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+/**
+ * An index into mdr11.
+ * There is a primary ordering on the type and a secondary ordering on the
+ * record number of the mdr11 record. The type is not actually stored
+ * in this section, you use mdr9 to divide up this section into groups of
+ * types.
+ *
+ * This section contains the subtype of each point.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr10Record extends RecordBase implements Comparable<Mdr10Record> {
+ private int subtype;
+ private Mdr11Record mdr11ref;
+
+ public int compareTo(Mdr10Record o) {
+ if (mdr11ref.getRecordNumber() == o.mdr11ref.getRecordNumber())
+ return 0;
+ else if (mdr11ref.getRecordNumber() < o.mdr11ref.getRecordNumber())
+ return -1;
+ else
+ return 1;
+ }
+
+ public Mdr11Record getMdr11ref() {
+ return mdr11ref;
+ }
+
+ public void setMdr11ref(Mdr11Record mdr11ref) {
+ this.mdr11ref = mdr11ref;
+ }
+
+ public int getSubtype() {
+ return subtype;
+ }
+
+ public void setSubtype(int subtype) {
+ this.subtype = subtype;
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr11.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr11.java
new file mode 100644
index 0000000..7ccb7d7
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr11.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+import uk.me.parabola.imgfmt.app.trergn.Point;
+
+/**
+ * Holds all the POIs, including cities. Arranged alphabetically by
+ * the name.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr11 extends MdrMapSection {
+ private List<Mdr11Record> pois = new ArrayList<Mdr11Record>();
+ private Mdr10 mdr10;
+
+ public Mdr11(MdrConfig config) {
+ setConfig(config);
+ }
+
+ public Mdr11Record addPoi(int mapIndex, Point point, String name, int strOff) {
+ Mdr11Record poi = new Mdr11Record();
+ poi.setMapIndex(mapIndex);
+ poi.setPointIndex(point.getNumber());
+ poi.setSubdiv(point.getSubdiv().getNumber());
+ poi.setLblOffset(point.getLabel().getOffset());
+ poi.setName(name);
+ poi.setStrOffset(strOff);
+
+ pois.add(poi);
+ return poi;
+ }
+
+ /**
+ * Sort and fill in the mdr10 information.
+ *
+ * The POI index contains individual references to POI by subdiv and index, so they are not
+ * de-duplicated in the index in the same way that streets and cities are.
+ */
+ protected void preWriteImpl() {
+ List<SortKey<Mdr11Record>> keys = MdrUtils.sortList(getConfig().getSort(), pois);
+
+ pois.clear();
+ for (SortKey<Mdr11Record> sk : keys) {
+ Mdr11Record poi = sk.getObject();
+
+ mdr10.addPoiType(poi);
+ pois.add(poi);
+ }
+ }
+
+ public void writeSectData(ImgFileWriter writer) {
+ int count = 1;
+ boolean hasStrings = hasFlag(2);
+ for (Mdr11Record poi : pois) {
+ addIndexPointer(poi.getMapIndex(), count);
+ poi.setRecordNumber(count++);
+
+ putMapIndex(writer, poi.getMapIndex());
+ writer.put((byte) poi.getPointIndex());
+ writer.putChar((char) poi.getSubdiv());
+ writer.put3(poi.getLblOffset());
+ if (poi.isCity())
+ putRegionIndex(writer, poi.getRegionIndex());
+ else
+ putCityIndex(writer, poi.getCityIndex(), true);
+ if (hasStrings)
+ putStringOffset(writer, poi.getStrOffset());
+ }
+ }
+
+ public int getItemSize() {
+ PointerSizes sizes = getSizes();
+ int size = sizes.getMapSize() + 6 + sizes.getCitySizeFlagged();
+ if (hasFlag(0x2))
+ size += sizes.getStrOffSize();
+ return size;
+ }
+
+ protected int numberOfItems() {
+ return pois.size();
+ }
+
+ public int getNumberOfPois() {
+ return getNumberOfItems();
+ }
+
+ public int getExtraValue() {
+ int mdr11flags = 0x11;
+ PointerSizes sizes = getSizes();
+
+ // two bit field for city bytes. minimum size of 2
+ int citySize = sizes.getCitySizeFlagged();
+ if (citySize > 2)
+ mdr11flags |= (citySize-2) << 2;
+
+ if (isForDevice())
+ mdr11flags |= 0x80;
+ else
+ mdr11flags |= 0x2;
+
+ return mdr11flags;
+ }
+
+ public List<Mdr8Record> getIndex() {
+ List<Mdr8Record> list = new ArrayList<Mdr8Record>();
+ for (int number = 1; number <= pois.size(); number += 10240) {
+ String prefix = getPrefixForRecord(number);
+
+ // need to step back to find the first...
+ int rec = number;
+ while (rec > 1) {
+ String p = getPrefixForRecord(rec);
+ if (!p.equals(prefix)) {
+ rec++;
+ break;
+ }
+ rec--;
+ }
+
+ Mdr12Record indexRecord = new Mdr12Record();
+ indexRecord.setPrefix(prefix);
+ indexRecord.setRecordNumber(rec);
+ list.add(indexRecord);
+ }
+ return list;
+ }
+
+ /**
+ * Get the prefix of the name at the given record.
+ * @param number The record number.
+ * @return The first 4 (or whatever value is set) characters of the street
+ * name.
+ */
+ private String getPrefixForRecord(int number) {
+ Mdr11Record record = pois.get(number-1);
+ int endIndex = MdrUtils.POI_INDEX_PREFIX_LEN;
+ String name = record.getName();
+ if (endIndex > name.length()) {
+ StringBuilder sb = new StringBuilder(name);
+ while (sb.length() < endIndex)
+ sb.append('\0');
+ name = sb.toString();
+ }
+ return name.substring(0, endIndex);
+ }
+
+ public void setMdr10(Mdr10 mdr10) {
+ this.mdr10 = mdr10;
+ }
+
+ public void releaseMemory() {
+ pois = null;
+ mdr10 = null;
+ }
+
+ public List<Mdr11Record> getPois() {
+ return new ArrayList<Mdr11Record>(pois);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr11Record.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr11Record.java
new file mode 100644
index 0000000..385c34c
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr11Record.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+/**
+ * The details required to write a POI record to mdr 11.
+ * @author Steve Ratcliffe
+ */
+public class Mdr11Record extends RecordBase implements NamedRecord {
+ private int pointIndex;
+ private int subdiv;
+ private int lblOffset;
+ private int strOffset;
+ private int recordNumber;
+ private String name;
+ private Mdr5Record city;
+ private boolean isCity;
+ private int type;
+
+ public boolean isCity() {
+ return isCity;
+ }
+
+ public void setIsCity(boolean isCity) {
+ this.isCity = isCity;
+ }
+
+ public int getPointIndex() {
+ return pointIndex;
+ }
+
+ public void setPointIndex(int pointIndex) {
+ this.pointIndex = pointIndex;
+ }
+
+ public int getSubdiv() {
+ return subdiv;
+ }
+
+ public void setSubdiv(int subdiv) {
+ this.subdiv = subdiv;
+ }
+
+ public int getLblOffset() {
+ return lblOffset;
+ }
+
+ public void setLblOffset(int lblOffset) {
+ this.lblOffset = lblOffset;
+ }
+
+ public int getCityIndex() {
+ return city == null ? 0 : city.getGlobalCityIndex();
+ }
+
+ public int getRegionIndex() {
+ return city == null ? 0 : city.getRegionIndex();
+ }
+
+ public int getStrOffset() {
+ return strOffset;
+ }
+
+ public void setStrOffset(int strOffset) {
+ this.strOffset = strOffset;
+ }
+
+ public int getRecordNumber() {
+ return recordNumber;
+ }
+
+ public void setRecordNumber(int recordNumber) {
+ this.recordNumber = recordNumber;
+ }
+
+ public String getName() {
+ assert name!=null;
+ return name;
+ }
+
+ public void setName(String name) {
+ assert name!=null;
+ this.name = name;
+ }
+
+ public void setCity(Mdr5Record city) {
+ this.city = city;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ public int getType() {
+ return type;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr12.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr12.java
new file mode 100644
index 0000000..cbfbace
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr12.java
@@ -0,0 +1,29 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+/**
+ * This is the index for the POI section (Mdr11).
+ * It works exactly the same way as Mdr8 as far as we know.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr12 extends Mdr8 {
+ public Mdr12(MdrConfig config) {
+ super(config);
+ }
+
+ protected int associatedSize() {
+ return getSizes().getPoiSize();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr12Record.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr12Record.java
new file mode 100644
index 0000000..3303c7e
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr12Record.java
@@ -0,0 +1,22 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+/**
+ * This is an index into mdr11 (pois).
+ * @author Steve Ratcliffe
+ */
+ at SuppressWarnings({"EmptyClass"})
+public class Mdr12Record extends Mdr8Record {
+ // This is exactly the same as mdr8
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr13.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr13.java
new file mode 100644
index 0000000..41c3b4d
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr13.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * Holds all the regions for each map.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr13 extends MdrSection implements HasHeaderFlags {
+ private final List<Mdr13Record> regions = new ArrayList<Mdr13Record>();
+
+ public Mdr13(MdrConfig config) {
+ setConfig(config);
+ }
+
+ public void addRegion(Mdr13Record rec) {
+ regions.add(rec);
+ }
+
+ public void writeSectData(ImgFileWriter writer) {
+ Collections.sort(regions);
+
+ for (Mdr13Record region : regions) {
+ putMapIndex(writer, region.getMapIndex());
+ writer.putChar((char) region.getRegionIndex());
+ writer.putChar((char) region.getCountryIndex());
+ putStringOffset(writer, region.getStrOffset());
+ }
+ }
+
+ public int getItemSize() {
+ return getSizes().getMapSize() + 4 + getSizes().getStrOffSize();
+ }
+
+ /**
+ * The number of records in this section.
+ *
+ * @return The number of items in the section.
+ */
+ protected int numberOfItems() {
+ return regions.size();
+ }
+
+ @Override
+ public int getExtraValue() {
+ return 0x00;
+ }
+
+ public List<Mdr13Record> getRegions() {
+ return regions;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr13Record.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr13Record.java
new file mode 100644
index 0000000..ddf9e58
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr13Record.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+/**
+ * Information about a region.
+ * @author Steve Ratcliffe
+ */
+public class Mdr13Record extends RecordBase implements Comparable<Mdr13Record>, NamedRecord {
+ private int regionIndex;
+ private int countryIndex;
+ private int lblOffset;
+ private int strOffset;
+ private String name;
+ private Mdr14Record mdr14;
+ private Mdr28Record mdr28;
+
+ /**
+ * We sort first by map id and then by region id.
+ */
+ public int compareTo(Mdr13Record o) {
+ int v1 = (getMapIndex()<<16) + regionIndex;
+ int v2 = (o.getMapIndex()<<16) + o.regionIndex;
+ if (v1 < v2)
+ return -1;
+ else if (v1 > v2)
+ return 1;
+ else
+ return 0;
+ }
+
+ public int getRegionIndex() {
+ return regionIndex;
+ }
+
+ public void setRegionIndex(int regionIndex) {
+ this.regionIndex = regionIndex;
+ }
+
+ public int getStrOffset() {
+ return strOffset;
+ }
+
+ public void setStrOffset(int strOffset) {
+ this.strOffset = strOffset;
+ }
+
+ public void setCountryIndex(int countryIndex) {
+ this.countryIndex = countryIndex;
+ }
+
+ public int getCountryIndex() {
+ return countryIndex;
+ }
+
+ public int getLblOffset() {
+ return lblOffset;
+ }
+
+ public void setLblOffset(int lblOffset) {
+ this.lblOffset = lblOffset;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Mdr14Record getMdr14() {
+ return mdr14;
+ }
+
+ public void setMdr14(Mdr14Record mdr14) {
+ this.mdr14 = mdr14;
+ }
+
+ public Mdr28Record getMdr28() {
+ return mdr28;
+ }
+
+ public void setMdr28(Mdr28Record mdr28) {
+ this.mdr28 = mdr28;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr14.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr14.java
new file mode 100644
index 0000000..025091e
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr14.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * The countries that occur in each map.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr14 extends MdrSection implements HasHeaderFlags {
+ private final List<Mdr14Record> countries = new ArrayList<Mdr14Record>();
+
+ public Mdr14(MdrConfig config) {
+ setConfig(config);
+ }
+
+ public void writeSectData(ImgFileWriter writer) {
+ Collections.sort(countries);
+
+ for (Mdr14Record country : countries) {
+ putMapIndex(writer, country.getMapIndex());
+ writer.putChar((char) country.getCountryIndex());
+ putStringOffset(writer, country.getStrOff());
+ }
+ }
+
+ public void addCountry(Mdr14Record country) {
+ countries.add(country);
+ }
+
+ public int getItemSize() {
+ PointerSizes sizes = getSizes();
+ return sizes.getMapSize() + 2 + sizes.getStrOffSize();
+ }
+
+ /**
+ * The number of records in this section.
+ * @return The number of items in the section.
+ */
+ protected int numberOfItems() {
+ return countries.size();
+ }
+
+ public int getExtraValue() {
+ return 0x00;
+ }
+
+ public List<Mdr14Record> getCountries() {
+ return countries;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr14Record.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr14Record.java
new file mode 100644
index 0000000..271066f
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr14Record.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+/**
+ * A country record.
+ * @author Steve Ratcliffe
+ */
+public class Mdr14Record extends RecordBase implements Comparable<Mdr14Record>, NamedRecord {
+ private int countryIndex;
+ private int lblOffset;
+ private int strOff;
+ private String name;
+ private Mdr29Record mdr29;
+
+ /**
+ * Sort by map id and then country id like for regions. We don't have
+ * any evidence that this is necessary, but it would be surprising if
+ * it wasn't.
+ */
+ public int compareTo(Mdr14Record o) {
+ int v1 = (getMapIndex()<<16) + countryIndex;
+ int v2 = (o.getMapIndex()<<16) + o.countryIndex;
+ if (v1 < v2)
+ return -1;
+ else if (v1 > v2)
+ return 1;
+ else
+ return 0;
+ }
+
+ public int getCountryIndex() {
+ return countryIndex;
+ }
+
+ public void setCountryIndex(int countryIndex) {
+ this.countryIndex = countryIndex;
+ }
+
+ public int getLblOffset() {
+ return lblOffset;
+ }
+
+ public void setLblOffset(int lblOffset) {
+ this.lblOffset = lblOffset;
+ }
+
+ public int getStrOff() {
+ return strOff;
+ }
+
+ public void setStrOff(int strOff) {
+ this.strOff = strOff;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Mdr29Record getMdr29() {
+ return mdr29;
+ }
+
+ public void setMdr29(Mdr29Record mdr29) {
+ this.mdr29 = mdr29;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr15.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr15.java
new file mode 100644
index 0000000..9f33ff8
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr15.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.ExitException;
+import uk.me.parabola.imgfmt.MapFailedException;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * The string table. This is not used by the device.
+ *
+ * There is a compressed and non-compressed version of this section.
+ * We are starting with the regular string version.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr15 extends MdrSection {
+ private final OutputStream stringFile;
+ private int nextOffset;
+
+ private Map<String, Integer> strings = new HashMap<String, Integer>();
+ private final Charset charset;
+ private final File tempFile;
+
+ public Mdr15(MdrConfig config) {
+ setConfig(config);
+
+ charset = config.getSort().getCharset();
+
+ try {
+ tempFile = File.createTempFile("strings", null, config.getOutputDir());
+ tempFile.deleteOnExit();
+
+ stringFile = new BufferedOutputStream(new FileOutputStream(tempFile), 64 * 1024);
+
+ // reserve the string at offset 0 to be the empty string.
+ stringFile.write(0);
+ nextOffset = 1;
+
+ } catch (IOException e) {
+ throw new ExitException("Could not create temporary file");
+ }
+ }
+
+ public int createString(String str) {
+ Integer offset = strings.get(str);
+ if (offset != null)
+ return offset;
+
+ int off;
+ try {
+ off = nextOffset;
+
+ byte[] bytes = str.getBytes(charset);
+ stringFile.write(bytes);
+ stringFile.write(0);
+
+ // Increase offset for the length of the string and the null byte
+ nextOffset += bytes.length + 1;
+ } catch (IOException e) {
+ // Can't convert, return empty string instead.
+ off = 0;
+ }
+
+ strings.put(str, off);
+ return off;
+ }
+
+ /**
+ * Tidy up after reading files.
+ * Close the temporary file, and release the string table which is no longer
+ * needed.
+ */
+ public void releaseMemory() {
+ strings = null;
+ try {
+ stringFile.close();
+ } catch (IOException e) {
+ throw new MapFailedException("Could not close string temporary file");
+ }
+ }
+
+ public void writeSectData(ImgFileWriter writer) {
+ FileInputStream stream = null;
+ try {
+ stream = new FileInputStream(tempFile);
+ FileChannel channel = stream.getChannel();
+ ByteBuffer buf = ByteBuffer.allocate(32 * 1024);
+ while (channel.read(buf) > 0) {
+ buf.flip();
+ writer.put(buf);
+ buf.compact();
+ }
+ } catch (IOException e) {
+ throw new ExitException("Could not write string section of index");
+ } finally {
+ Utils.closeFile(stream);
+ }
+ }
+
+ public int getItemSize() {
+ // variable sized records.
+ return 0;
+ }
+
+ /**
+ * The meaning of number of items for this section is the largest string
+ * offset possible. We are taking the total size of the string section
+ * for this.
+ */
+ public int getSizeForRecord() {
+ return numberToPointerSize(nextOffset);
+ }
+
+ /**
+ * There is no use for this as the records are not fixed length.
+ *
+ * @return Always zero, could return the number of strings.
+ */
+ protected int numberOfItems() {
+ return 0;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr17.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr17.java
new file mode 100644
index 0000000..767403c
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr17.java
@@ -0,0 +1,110 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * Name indexes consisting of a prefix of the string and the record
+ * number at which that prefix first occurs. So it is like 8 and 12
+ * except that they are all combined together in this one section.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr17 extends MdrSection {
+ private PrefixIndex streets;
+ private PrefixIndex streetsByCountry;
+ private PrefixIndex cities;
+ private PrefixIndex pois;
+
+ public Mdr17(MdrConfig config) {
+ setConfig(config);
+ streets = new PrefixIndex(getConfig(), 4);
+ streetsByCountry = new PrefixIndex(getConfig(), 4);
+ cities = new PrefixIndex(getConfig(), 2);
+ pois = new PrefixIndex(getConfig(), 4);
+ }
+
+ public void writeSectData(ImgFileWriter writer) {
+ writeSubSect(writer, streets);
+ writeSubSect(writer, cities);
+ writeSubSect(writer, streetsByCountry);
+ writeSubSect(writer, pois);
+ }
+
+ /**
+ * Write one of the subsections that makes up the section. They are all similar and
+ * have a header with the length and the record size and prefix length of the
+ * records in the subsection.
+ */
+ private void writeSubSect(ImgFileWriter writer, PrefixIndex index) {
+ index.preWrite();
+ int len = index.getItemSize() * index.getNumberOfItems() + 2;
+ if (len == 2)
+ return; // nothing to do
+
+ // The length is a variable length integer with the length indicated by a suffix.
+ len = (len << 1) + 1;
+ int mask = ~0xff;
+ int count = 1;
+ while ((len & mask) != 0) {
+ mask <<= 8;
+ len <<= 1;
+ count++;
+ }
+ putN(writer, count, len);
+
+ // Calculate the header. This code is unlikely to survive the finding of another example!
+ // Have no idea what the real thinking behind this is.
+ int prefixLength = index.getPrefixLength();
+ int header = (prefixLength - 1) << 8;
+ header += (prefixLength + 1) * (prefixLength + 1);
+ header += (index.getItemSize() - prefixLength - 1) * 0xa;
+
+ writer.putChar((char) header);
+ index.writeSectData(writer);
+ }
+
+ protected void releaseMemory() {
+ streets = null;
+ cities = null;
+ streetsByCountry = null;
+ pois = null;
+ }
+
+ public void addStreets(List<Mdr7Record> streetList) {
+ streets.createFromList(streetList);
+ }
+
+ public void addCities(List<Mdr5Record> cityList) {
+ cities.createFromList(cityList);
+ }
+
+ public void addStreetsByCountry(List<Mdr7Record> streets) {
+ streetsByCountry.createFromList(streets, true);
+ }
+
+ public void addPois(List<Mdr11Record> poiList) {
+ pois.createFromList(poiList);
+ }
+
+ public int getItemSize() {
+ return 0;
+ }
+
+ protected int numberOfItems() {
+ return 0;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr18.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr18.java
new file mode 100644
index 0000000..59b3477
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr18.java
@@ -0,0 +1,57 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * This is an index into 19 showing the start of each new type.
+ *
+ * Section 19 creates the data for this, we just write it out here.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr18 extends MdrSection implements HasHeaderFlags {
+ private List<Mdr18Record> poiTypes = new ArrayList<Mdr18Record>();
+
+ public Mdr18(MdrConfig config) {
+ setConfig(config);
+ }
+
+ public void writeSectData(ImgFileWriter writer) {
+ int poiSize = getSizes().getSize(19);
+ for (Mdr18Record pt : poiTypes) {
+ writer.putChar((char) (pt.getType() | 0x4000));
+ putN(writer, poiSize, pt.getRecord());
+ }
+ }
+
+ public int getItemSize() {
+ return 2 + getSizes().getSize(19);
+ }
+
+ protected int numberOfItems() {
+ return poiTypes.size();
+ }
+
+ public void setPoiTypes(List<Mdr18Record> poiTypes) {
+ this.poiTypes = poiTypes;
+ }
+
+ public int getExtraValue() {
+ return 4 + getSizes().getSize(19)-1;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr18Record.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr18Record.java
new file mode 100644
index 0000000..27d922d
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr18Record.java
@@ -0,0 +1,39 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+/**
+ * An index entry into mdr 19.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr18Record {
+ private int type;
+ private int record;
+
+ public int getType() {
+ return type;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ public int getRecord() {
+ return record;
+ }
+
+ public void setRecord(int record) {
+ this.record = record;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr19.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr19.java
new file mode 100644
index 0000000..46df5dc
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr19.java
@@ -0,0 +1,135 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * POIs ordered by type. Section 18 is the index into this.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr19 extends MdrSection implements HasHeaderFlags {
+ private List<Mdr11Record> pois;
+ private final List<Mdr18Record> poiTypes = new ArrayList<Mdr18Record>();
+
+ public Mdr19(MdrConfig config) {
+ setConfig(config);
+ }
+
+ /**
+ * Sort the pois by type.
+ */
+ public void preWriteImpl() {
+ Collections.sort(pois, new Comparator<Mdr11Record>() {
+ public int compare(Mdr11Record o1, Mdr11Record o2) {
+ // For mainly historical reasons, we keep the element type in a number of different
+ // formats. Need to normalise it before sorting.
+ int t1 = MdrUtils.fullTypeToNaturalType(o1.getType());
+ int t2 = MdrUtils.fullTypeToNaturalType(o2.getType());
+
+ if (t1 == t2) return 0;
+ else if (t1 < t2) return -1;
+ else return 1;
+ }
+ });
+ }
+
+ /**
+ * Write out the contents of this section.
+ *
+ * @param writer Where to write it.
+ */
+ public void writeSectData(ImgFileWriter writer) {
+ int n = getSizes().getPoiSizeFlagged();
+ int flag = getSizes().getPoiFlag();
+
+ String lastName = null;
+ int lastType = -1;
+ int record = 1;
+ for (Mdr11Record p : pois) {
+ int index = p.getRecordNumber();
+ String name = p.getName();
+ if (!name.equals(lastName)) {
+ index |= flag;
+ lastName = name;
+ }
+ putN(writer, n, index);
+
+ int type = MdrUtils.fullTypeToNaturalType(p.getType());
+ if (type != lastType) {
+ Mdr18Record mdr18 = new Mdr18Record();
+ mdr18.setType(type);
+ mdr18.setRecord(record);
+ poiTypes.add(mdr18);
+ lastType = type;
+ }
+ record++;
+ }
+
+ Mdr18Record m18 = new Mdr18Record();
+ m18.setRecord(record);
+ m18.setType(~0);
+ poiTypes.add(m18);
+ }
+
+ /**
+ * Release the copy of the pois. The other index is small and not worth
+ * worrying about.
+ */
+ protected void releaseMemory() {
+ pois = null;
+ }
+
+ /**
+ * Records in this section are record numbers into mdr 11 with a flag
+ * so has to be large enough for a flagged index.
+ *
+ * @return The size of a record in this section.
+ */
+ public int getItemSize() {
+ return getSizes().getPoiSizeFlagged();
+ }
+
+ /**
+ * Method to be implemented by subclasses to return the number of items in the section. This will only be valid after
+ * the section is completely finished etc.
+ *
+ * @return The number of items in the section.
+ */
+ protected int numberOfItems() {
+ return pois.size();
+ }
+
+ /**
+ * Not yet known.
+ *
+ * @return The correct value based on the contents of the section. Zero if nothing needs to be done.
+ */
+ public int getExtraValue() {
+ return getSizes().getSize(19) - 1;
+ }
+
+ public void setPois(List<Mdr11Record> pois) {
+ this.pois = pois;
+ }
+
+ public List<Mdr18Record> getPoiTypes() {
+ return poiTypes;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr1MapIndex.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr1MapIndex.java
new file mode 100644
index 0000000..12cf0e4
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr1MapIndex.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import java.nio.ByteBuffer;
+
+import uk.me.parabola.imgfmt.app.BufferedImgFileWriter;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * Each map has one of these and it is used to provide a list of records
+ * in the various sections that actually belong to this map.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr1MapIndex {
+ private final Mdr1SubHeader subHeader = new Mdr1SubHeader();
+ private final BufferedImgFileWriter subWriter = new BufferedImgFileWriter(null);
+
+ private int pointerSize;
+
+ public Mdr1MapIndex() {
+ // skip over where the header will be
+ this.subWriter.position(subHeader.getHeaderLen());
+ }
+
+ public void startSection(int n) {
+ }
+
+ public void endSection(int n) {
+ int sn = sectionToSubsection(n);
+ if (sn != 0)
+ subHeader.setEndSubsection(sn, subWriter.position());
+ }
+
+ public void addPointer(int recordNumber) {
+ switch (pointerSize) {
+ case 4:
+ subWriter.putInt(recordNumber);
+ break;
+ case 3:
+ subWriter.put3(recordNumber);
+ break;
+ case 2:
+ subWriter.putChar((char) recordNumber);
+ break;
+ case 1:
+ subWriter.put((byte) recordNumber);
+ break;
+ default:
+ assert false;
+ }
+ }
+
+ private int sectionToSubsection(int n) {
+ int sn;
+ switch (n) {
+ case 11: sn = 1; break;
+ case 10: sn = 2; break;
+ case 7: sn = 3; break;
+ case 5: sn = 4; break;
+ case 6: sn = 5; break;
+ case 20: sn = 6; break;
+ case 21: sn = 7; break;
+ case 22: sn = 8; break;
+ default: sn = 0; break;
+ }
+ return sn;
+ }
+
+ public void writeSubSection(ImgFileWriter writer) {
+ subHeader.writeFileHeader(writer);
+
+ ByteBuffer buffer = subWriter.getBuffer();
+ byte[] bytes = buffer.array();
+ int hl = (int) subHeader.getHeaderLen();
+ writer.put(bytes, hl, buffer.position() - hl);
+ }
+
+ public void setPointerSize(int sectionNumber, int pointerSize) {
+ this.pointerSize = pointerSize;
+ int sn = sectionToSubsection(sectionNumber);
+ if (sn != 0)
+ subHeader.setItemSize(sn, pointerSize);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr1Record.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr1Record.java
new file mode 100644
index 0000000..6cdda41
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr1Record.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+/**
+ * @author Steve Ratcliffe
+ */
+public class Mdr1Record extends RecordBase {
+ private final int mapNumber;
+ private Mdr1MapIndex mdrMapIndex;
+ private int indexOffset;
+
+ public Mdr1Record(int mapNumber, MdrConfig config) {
+ this.mapNumber = mapNumber;
+ }
+
+ public int getMapNumber() {
+ return mapNumber;
+ }
+
+ public Mdr1MapIndex getMdrMapIndex() {
+ return mdrMapIndex;
+ }
+
+ public void setMdrMapIndex(Mdr1MapIndex mdrMapIndex) {
+ this.mdrMapIndex = mdrMapIndex;
+ }
+
+ public int getIndexOffset() {
+ return indexOffset;
+ }
+
+ public void setIndexOffset(int indexOffset) {
+ this.indexOffset = indexOffset;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr1SubHeader.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr1SubHeader.java
new file mode 100644
index 0000000..77a9d15
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr1SubHeader.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Section;
+
+/**
+ * A header for the map index, pointed to from MDR 1.
+ * There is one of these for each map.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr1SubHeader {
+ // The number of subsections, this starts at 1. Larger numbers are possible
+ // for larger MDR header sizes.
+ private static final int MAX_SECTION = 9;
+
+ // Each sub header requires 8 bytes apart from sub2 which only needs 4.
+ private static final int HEADER_SIZE = 70;
+
+ private final Section[] sections = new Section[MAX_SECTION+1];
+
+ public Mdr1SubHeader() {
+ // Initialise the sections.
+ for (int n = 1; n <= MAX_SECTION; n++) {
+ Section prev = sections[n - 1];
+ sections[n] = new Section(prev);
+ }
+
+ sections[1].setPosition(HEADER_SIZE);
+ }
+
+ protected void writeFileHeader(ImgFileWriter writer) {
+ writer.putChar((char) HEADER_SIZE);
+ for (int n = 1; n <= MAX_SECTION; n++) {
+ Section section = sections[n];
+
+ // The second subsection does not have a length, because it always
+ // has the same length as subsection 1.
+ if (n == 2)
+ writer.putInt(section.getPosition());
+ else {
+ //section.writeSectionInfo(writer);
+ writer.putInt(section.getPosition());
+ int size = section.getSize();
+ if (size == 0)
+ writer.putInt(0);
+ else
+ writer.putInt(size / section.getItemSize());
+ }
+ }
+ }
+
+ public void setEndSubsection(int sub, int pos) {
+ sections[sub].setSize(pos - sections[sub].getPosition());
+ }
+
+ public long getHeaderLen() {
+ return HEADER_SIZE;
+ }
+
+ public void setItemSize(int sectionNumber, int itemSize) {
+ sections[sectionNumber].setItemSize((char) itemSize);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr20.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr20.java
new file mode 100644
index 0000000..076bcf5
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr20.java
@@ -0,0 +1,129 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.app.srt.MultiSortKey;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+
+/**
+ * This is a list of streets that belong to each city.
+ *
+ * It is sorted with each group of streets that belong to a city in the same
+ * order as the cities, within each group the sort is by street id in mdr7.
+ *
+ * Streets that do not have an associated city are not included.
+ *
+ * There is a subsection in the mdr1 reverse index for this section, however
+ * the map index is not saved as part of this record.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr20 extends Mdr2x {
+
+ public Mdr20(MdrConfig config) {
+ setConfig(config);
+ }
+
+ /**
+ * We need to sort the streets by the name of the city. Within a city
+ * group the streets are ordered by their own index.
+ *
+ * Also have to set the record number of the first record in this section
+ * on the city.
+ *
+ * @param inStreets The list of streets from mdr7, must have Mdr7.index set.
+ */
+ public void buildFromStreets(List<Mdr7Record> inStreets) {
+ Sort sort = getConfig().getSort();
+
+ // Use a key cache because there are a large number of street names but a much smaller number
+ // of city, region and country names. Therefore we can reuse the memory needed for the keys
+ // most of the time, particularly for the country and region names.
+ Map<String, byte[]> cache = new HashMap<String, byte[]>();
+
+ List<SortKey<Mdr7Record>> keys = new ArrayList<SortKey<Mdr7Record>>();
+ for (Mdr7Record s : inStreets) {
+ Mdr5Record city = s.getCity();
+ if (city == null)
+ continue;
+
+ String name = city.getName();
+ if (name == null || name.isEmpty())
+ assert false;
+
+ // We are sorting the streets, but we are sorting primarily on the
+ // city name associated with the street, then on the street name.
+ SortKey<Mdr7Record> cityKey = sort.createSortKey(s, city.getName(), 0, cache);
+ SortKey<Mdr7Record> regionKey = sort.createSortKey(null, city.getRegionName(), 0, cache);
+ // The streets are already sorted, with the getIndex() method revealing the sort order
+ SortKey<Mdr7Record> countryStreetKey = sort.createSortKey(null, city.getCountryName(), s.getIndex(),
+ cache);
+
+ // Combine all together so we can sort on it.
+ SortKey<Mdr7Record> key = new MultiSortKey<Mdr7Record>(cityKey, regionKey, countryStreetKey);
+
+ keys.add(key);
+ }
+ Collections.sort(keys);
+
+ String lastName = null;
+ Mdr5Record lastCity = null;
+ int record = 0;
+ int cityRecord = 0;
+ int lastMapNumber = 0;
+ for (SortKey<Mdr7Record> key : keys) {
+ Mdr7Record street = key.getObject();
+
+ String name = street.getName();
+ Mdr5Record city = street.getCity();
+
+ boolean citySameByName = city.isSameByName(lastCity);
+
+ int mapNumber = city.getMapIndex();
+
+ // Only save a single copy of each street name.
+ if (!name.equals(lastName) || !citySameByName || mapNumber != lastMapNumber) {
+ record++;
+
+ streets.add(street);
+ lastName = name;
+ }
+
+ // The mdr20 value changes for each new city name
+ if (citySameByName) {
+ city.setMdr20(cityRecord);
+ } else {
+ // New city name, this marks the start of a new section in mdr20
+ cityRecord = record;
+ city.setMdr20(cityRecord);
+ lastCity = city;
+ }
+ lastMapNumber = mapNumber;
+ }
+ }
+
+ /**
+ * Unknown.
+ */
+ public int getExtraValue() {
+ return isForDevice() ? 0xa : 0x8800;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr21.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr21.java
new file mode 100644
index 0000000..8c86983
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr21.java
@@ -0,0 +1,94 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+
+/**
+ * This section contains the streets sorted by region.
+ * There is no pointer from region, unlike in the case with cities.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr21 extends Mdr2x {
+
+ public Mdr21(MdrConfig config) {
+ setConfig(config);
+ }
+
+ /**
+ * We need to sort the streets by the name of their region. Within a region
+ * group the streets are ordered by their own index.
+ *
+ * @param inStreets The list of streets from mdr7.
+ */
+ public void buildFromStreets(List<Mdr7Record> inStreets) {
+ Sort sort = getConfig().getSort();
+
+ List<SortKey<Mdr7Record>> keys = new ArrayList<SortKey<Mdr7Record>>();
+ Map<String, byte[]> cache = new HashMap<String, byte[]>();
+
+ for (Mdr7Record s : inStreets) {
+ Mdr5Record city = s.getCity();
+ if (city == null) continue;
+
+ Mdr13Record region = city.getMdrRegion();
+ if (region == null) continue;
+
+ String name = region.getName();
+ if (name == null)
+ continue;
+
+ keys.add(sort.createSortKey(s, name, s.getIndex(), cache));
+ }
+
+ Collections.sort(keys);
+
+ String lastName = null;
+ int lastMapid = 0;
+ int record = 0;
+ for (SortKey<Mdr7Record> key : keys) {
+ Mdr7Record street = key.getObject();
+
+ String name = street.getName();
+ int mapid = street.getMapIndex();
+ if (mapid != lastMapid || !name.equals(lastName)) {
+ record++;
+ streets.add(street);
+
+ Mdr13Record mdrRegion = street.getCity().getMdrRegion();
+ if (mdrRegion != null) {
+ Mdr28Record mdr28 = mdrRegion.getMdr28();
+ mdr28.setMdr21(record);
+ }
+
+ lastMapid = mapid;
+ lastName = name;
+ }
+ }
+ }
+
+ /**
+ * Not known what these flags signify.
+ */
+ public int getExtraValue() {
+ return 0x11800;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr22.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr22.java
new file mode 100644
index 0000000..f218f3b
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr22.java
@@ -0,0 +1,107 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+
+/**
+ * Index of streets by country.
+ *
+ * There is no pointer from the country section into this like there is with
+ * cities.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr22 extends Mdr2x {
+
+ public Mdr22(MdrConfig config) {
+ setConfig(config);
+ }
+
+ /**
+ * We need to sort the streets by the name of the country. Within a city
+ * group the streets are ordered by their own index.
+ *
+ * Also have to set the record number of the first record in this section
+ * on the city.
+ *
+ * @param inStreets The list of streets from mdr7.
+ */
+ public void buildFromStreets(List<Mdr7Record> inStreets) {
+ Sort sort = getConfig().getSort();
+
+ List<SortKey<Mdr7Record>> keys = new ArrayList<SortKey<Mdr7Record>>();
+ Map<String, byte[]> cache = new HashMap<String, byte[]>();
+ for (Mdr7Record s : inStreets) {
+ Mdr5Record city = s.getCity();
+ if (city == null) continue;
+
+ String name = city.getMdrCountry().getName();
+ assert name != null;
+
+ // We are sorting the streets, but we are sorting primarily on the
+ // country name associated with the street.
+ // For memory use, we re-use country name part of the key.
+ keys.add(sort.createSortKey(s, name, s.getIndex(), cache));
+ }
+ Collections.sort(keys);
+
+ int record = 0;
+
+ String lastName = null;
+ int lastMapid = 0;
+
+ for (SortKey<Mdr7Record> key : keys) {
+ Mdr7Record street = key.getObject();
+
+ String name = street.getName();
+ int mapid = street.getMapIndex();
+ if (mapid != lastMapid || !name.equals(lastName)) {
+ record++;
+ streets.add(street);
+
+ // Include in the mdr29 index if we have one for this record.
+ Mdr14Record mdrCountry = street.getCity().getMdrCountry();
+ if (mdrCountry != null) {
+ Mdr29Record mdr29 = mdrCountry.getMdr29();
+ mdr29.setMdr22(record);
+ }
+
+ lastMapid = mapid;
+ lastName = name;
+ }
+ }
+ }
+
+ public List<Mdr7Record> getStreets() {
+ return Collections.unmodifiableList(streets);
+ }
+
+ /**
+ * Unknown flag
+ */
+ public int getExtraValue() {
+ if (isForDevice())
+ return 0xc000a;
+ else
+ return 0x11000;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr23.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr23.java
new file mode 100644
index 0000000..9e64c5d
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr23.java
@@ -0,0 +1,105 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+
+/**
+ * Regions sorted by name. Same number of records as mdr13.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr23 extends MdrSection {
+ private final List<Mdr13Record> regions = new ArrayList<Mdr13Record>();
+
+ public Mdr23(MdrConfig config) {
+ setConfig(config);
+ }
+
+ /**
+ * Takes the region list and sorts it according to the name.
+ * @param list Original region list.
+ */
+ public void sortRegions(List<Mdr13Record> list) {
+ Sort sort = getConfig().getSort();
+ List<SortKey<Mdr13Record>> keys = MdrUtils.sortList(sort, list);
+ Collections.sort(keys);
+
+ String lastName = null;
+ int lastMapIndex = 0;
+ int record = 0;
+ for (SortKey<Mdr13Record> key : keys) {
+ Mdr13Record reg = key.getObject();
+
+ // Only add if different name or map
+ String name = reg.getName();
+ if (reg.getMapIndex() != lastMapIndex || !name.equals(lastName)) {
+ record++;
+ reg.getMdr28().setMdr23(record);
+ regions.add(reg);
+
+ lastName = name;
+ lastMapIndex = reg.getMapIndex();
+ }
+ }
+ }
+
+ /**
+ * Write out the contents of this section.
+ *
+ * @param writer Where to write it.
+ */
+ public void writeSectData(ImgFileWriter writer) {
+ String lastName = null;
+ for (Mdr13Record reg : regions) {
+ putMapIndex(writer, reg.getMapIndex());
+
+ int flag = 0;
+ String name = reg.getName();
+ if (!name.equals(lastName)) {
+ flag = 0x800000;
+ lastName = name;
+ }
+
+ writer.putChar((char) reg.getRegionIndex());
+ writer.putChar((char) reg.getCountryIndex());
+ writer.put3(reg.getLblOffset() | flag);
+ }
+ }
+
+ /**
+ * There is a map index followed by file region and country indexes.
+ * Then there is a label offset for the name, which strangely appears
+ * to be three bytes always, although that many would rarely (or never?) be
+ * required.
+ */
+ public int getItemSize() {
+ PointerSizes sizes = getSizes();
+ return sizes.getMapSize() + 2 + 2 + 3;
+ }
+
+ /**
+ * The number of records in this section.
+ *
+ * @return The number of items in the section.
+ */
+ protected int numberOfItems() {
+ return regions.size();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr24.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr24.java
new file mode 100644
index 0000000..07d6a35
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr24.java
@@ -0,0 +1,107 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+
+/**
+ * Countries sorted by name. Same number of entries as 14.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr24 extends MdrSection {
+ private final List<Mdr14Record> countries = new ArrayList<Mdr14Record>();
+
+ public Mdr24(MdrConfig config) {
+ setConfig(config);
+ }
+
+ /**
+ * Sort the countries by name. Duplicates are kept.
+ * @param list The full list of countries.
+ */
+ public void sortCountries(List<Mdr14Record> list) {
+ Sort sort = getConfig().getSort();
+ List<SortKey<Mdr14Record>> keys = MdrUtils.sortList(sort, list);
+
+ Collections.sort(keys);
+
+ String lastName = null;
+ int lastMapIndex = 0;
+ int record = 0;
+ for (SortKey<Mdr14Record> key : keys) {
+ Mdr14Record c = key.getObject();
+
+ // If this is a new name, then we prepare a mdr29 record for it.
+ String name = c.getName();
+
+ if (lastMapIndex != c.getMapIndex() || !name.equals(lastName)) {
+ record++;
+ c.getMdr29().setMdr24(record);
+ countries.add(c);
+
+ lastName = name;
+ lastMapIndex = c.getMapIndex();
+ }
+ }
+ }
+
+ /**
+ * Write out the contents of this section.
+ *
+ * @param writer Where to write it.
+ */
+ public void writeSectData(ImgFileWriter writer) {
+ String lastName = null;
+ for (Mdr14Record c : countries) {
+ putMapIndex(writer, c.getMapIndex());
+
+ int flag = 0;
+ String name = c.getName();
+ if (!name.equals(lastName)) {
+ flag = 0x800000;
+ lastName = name;
+ }
+
+ writer.putChar((char) c.getCountryIndex());
+ writer.put3(c.getLblOffset() | flag);
+ }
+ }
+
+ /**
+ * The size of a record in the section. This is not a constant and might vary
+ * on various factors, such as the file version, if we are preparing for a
+ * device, the number of maps etc.
+ *
+ * @return The size of a record in this section.
+ */
+ public int getItemSize() {
+ PointerSizes sizes = getSizes();
+ return sizes.getMapSize() + 2 + 3;
+ }
+
+ /**
+ * The number of records in this section.
+ *
+ * @return The number of items in the section.
+ */
+ protected int numberOfItems() {
+ return countries.size();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr25.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr25.java
new file mode 100644
index 0000000..cf4b94a
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr25.java
@@ -0,0 +1,103 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+
+/**
+ * Cities sorted by country.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr25 extends MdrSection {
+ private final List<Mdr5Record> cities = new ArrayList<Mdr5Record>();
+
+ public Mdr25(MdrConfig config) {
+ setConfig(config);
+ }
+
+ /**
+ * Cities are sorted by country and then by the mdr5 city record number.
+ * @param list The complete list of cities from mdr5.
+ */
+ public void sortCities(List<Mdr5Record> list) {
+ Sort sort = getConfig().getSort();
+
+ List<SortKey<Mdr5Record>> keys = new ArrayList<SortKey<Mdr5Record>>();
+ for (Mdr5Record c : list) {
+ SortKey<Mdr5Record> key = sort.createSortKey(c, c.getMdrCountry().getName(), c.getGlobalCityIndex());
+ keys.add(key);
+ }
+
+ Collections.sort(keys);
+
+ String lastName = null;
+ Mdr5Record lastCity = null;
+ int record = 0;
+ for (SortKey<Mdr5Record> key : keys) {
+ Mdr5Record city = key.getObject();
+
+ if (lastCity == null ||
+ (!city.getName().equals(lastCity.getName()) || !(city.getRegionName().equals(lastCity.getRegionName()))))
+ {
+ record++;
+
+ // Record in the 29 index if there is one for this record
+ Mdr14Record mdrCountry = city.getMdrCountry();
+ Mdr29Record mdr29 = mdrCountry.getMdr29();
+ String name = mdr29.getName();
+ assert mdrCountry.getName().equals(name);
+ if (!name.equals(lastName)) {
+ mdr29.setMdr25(record);
+ lastName = name;
+ }
+ cities.add(city);
+ lastCity = city;
+ }
+ }
+ }
+
+ /**
+ * Write out the contents of this section.
+ *
+ * @param writer Where to write it.
+ */
+ public void writeSectData(ImgFileWriter writer) {
+ int size = getItemSize();
+ for (Mdr5Record city : cities) {
+ putN(writer, size, city.getGlobalCityIndex());
+ }
+ }
+
+ /**
+ * One field pointing to a city. Not flagged.
+ */
+ public int getItemSize() {
+ return getSizes().getCitySize();
+ }
+
+ /**
+ * The number of records in this section.
+ *
+ * @return The number of items in the section.
+ */
+ protected int numberOfItems() {
+ return cities.size();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr26.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr26.java
new file mode 100644
index 0000000..8882e84
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr26.java
@@ -0,0 +1,100 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+
+/**
+ * An index into mdr28 (region names), sorted by country name.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr26 extends MdrSection {
+ private final List<Mdr28Record> index = new ArrayList<Mdr28Record>();
+
+ public Mdr26(MdrConfig config) {
+ setConfig(config);
+ }
+
+ public void sortMdr28(List<Mdr28Record> in) {
+ Sort sort = getConfig().getSort();
+
+ List<SortKey<Mdr28Record>> sortList = new ArrayList<SortKey<Mdr28Record>>();
+ int record = 0;
+ for (Mdr28Record mdr28 : in) {
+ SortKey<Mdr28Record> key = sort.createSortKey(mdr28, mdr28.getMdr14().getName(), ++record);
+ sortList.add(key);
+ }
+ Collections.sort(sortList);
+
+ addToIndex(sortList);
+ }
+
+ private void addToIndex(List<SortKey<Mdr28Record>> sortList) {
+ String lastName = null;
+ int record26 = 0;
+ for (SortKey<Mdr28Record> key : sortList) {
+ record26++;
+ Mdr28Record mdr28 = key.getObject();
+ Mdr14Record mdr14 = mdr28.getMdr14();
+ assert mdr14 != null;
+
+ // For each new name, set up the mdr29 record for it.
+ String name = mdr14.getName();
+ if (!name.equals(lastName)) {
+ Mdr29Record mdr29 = mdr14.getMdr29();
+ mdr29.setMdr26(record26);
+ lastName = name;
+ }
+ index.add(mdr28);
+ }
+ }
+
+ /**
+ * Write out the contents of this section.
+ *
+ * @param writer Where to write it.
+ */
+ public void writeSectData(ImgFileWriter writer) {
+ int size = getSizes().getSize(28);
+ for (Mdr28Record record : index) {
+ putN(writer, size, record.getIndex());
+ }
+ }
+
+ /**
+ * The size of a record in the section. This is not a constant and might vary
+ * on various factors, such as the file version, if we are preparing for a
+ * device, the number of maps etc.
+ *
+ * @return The size of a record in this section.
+ */
+ public int getItemSize() {
+ return getSizes().getSize(28);
+ }
+
+ /**
+ * The number of records in this section.
+ *
+ * @return The number of items in the section.
+ */
+ protected int numberOfItems() {
+ return index.size();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr27.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr27.java
new file mode 100644
index 0000000..095c3a5
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr27.java
@@ -0,0 +1,102 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+
+/**
+ * Cities sorted by region name.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr27 extends MdrSection {
+ private final List<Mdr5Record> cities = new ArrayList<Mdr5Record>();
+
+ public Mdr27(MdrConfig config) {
+ setConfig(config);
+ }
+
+ /**
+ * Cities are sorted by region and then by the mdr5 city record number.
+ * @param list The complete list of cities from mdr5.
+ */
+ public void sortCities(List<Mdr5Record> list) {
+ Sort sort = getConfig().getSort();
+
+ List<SortKey<Mdr5Record>> keys = new ArrayList<SortKey<Mdr5Record>>();
+ for (Mdr5Record c : list) {
+ Mdr13Record mdrRegion = c.getMdrRegion();
+ if (mdrRegion != null) {
+ SortKey<Mdr5Record> key = sort.createSortKey(c, mdrRegion.getName(), c.getGlobalCityIndex());
+ keys.add(key);
+ }
+ }
+
+ Collections.sort(keys);
+
+ String lastName = null;
+ int record = 0;
+ for (SortKey<Mdr5Record> key : keys) {
+ record++;
+ Mdr5Record city = key.getObject();
+
+ Mdr13Record mdrRegion = city.getMdrRegion();
+ Mdr28Record mdr28 = mdrRegion.getMdr28();
+ String name = mdr28.getName();
+ if (!name.equals(lastName)) {
+ mdr28.setMdr27(record);
+ lastName = name;
+ }
+
+ cities.add(city);
+ }
+ }
+
+ /**
+ * Write out the contents of this section.
+ *
+ * @param writer Where to write it.
+ */
+ public void writeSectData(ImgFileWriter writer) {
+ int size = getItemSize();
+ for (Mdr5Record city : cities) {
+ putN(writer, size, city.getGlobalCityIndex());
+ }
+ }
+
+ /**
+ * The size of a record in the section. This is not a constant and might vary
+ * on various factors, such as the file version, if we are preparing for a
+ * device, the number of maps etc.
+ *
+ * @return The size of a record in this section.
+ */
+ public int getItemSize() {
+ return getSizes().getCitySize();
+ }
+
+ /**
+ * The number of records in this section.
+ *
+ * @return The number of items in the section.
+ */
+ protected int numberOfItems() {
+ return cities.size();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr28.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr28.java
new file mode 100644
index 0000000..5d6f396
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr28.java
@@ -0,0 +1,121 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+
+/**
+ * One of these per region name. There are pointers into the other sections
+ * that are sorted by region to the first record that has the given name.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr28 extends MdrSection implements HasHeaderFlags {
+ private final List<Mdr28Record> index = new ArrayList<Mdr28Record>();
+
+ public Mdr28(MdrConfig config) {
+ setConfig(config);
+ }
+
+ public void buildFromRegions(List<Mdr13Record> regions) {
+ Sort sort = getConfig().getSort();
+ List<SortKey<Mdr13Record>> keys = MdrUtils.sortList(sort, regions);
+
+ int record = 0;
+ Mdr28Record mdr28 = null;
+ String lastName = null;
+ for (SortKey<Mdr13Record> key : keys) {
+ Mdr13Record region = key.getObject();
+
+ String name = region.getName();
+ if (!name.equals(lastName)) {
+ record++;
+ mdr28 = new Mdr28Record();
+ mdr28.setIndex(record);
+ mdr28.setName(name);
+ mdr28.setStrOffset(region.getStrOffset());
+ mdr28.setMdr14(region.getMdr14());
+
+ index.add(mdr28);
+ lastName = name;
+ }
+
+ assert mdr28 != null;
+ region.setMdr28(mdr28);
+ }
+ }
+
+ /**
+ * Write out the contents of this section.
+ *
+ * @param writer Where to write it.
+ */
+ public void writeSectData(ImgFileWriter writer) {
+ PointerSizes sizes = getSizes();
+ int size21 = sizes.getSize(21);
+ int size23 = sizes.getSize(23);
+ int size27 = sizes.getSize(27);
+
+ int idx = 0;
+ for (Mdr28Record mdr28 : index) {
+ putN(writer, size23, mdr28.getMdr23());
+ putStringOffset(writer, mdr28.getStrOffset());
+ putN(writer, size21, mdr28.getMdr21());
+ putN(writer, size27, mdr28.getMdr27());
+
+ idx++;
+ }
+ }
+
+ /**
+ * The size of a record in the section. This is not a constant and might vary
+ * on various factors, such as the file version, if we are preparing for a
+ * device, the number of maps etc.
+ *
+ * @return The size of a record in this section.
+ */
+ public int getItemSize() {
+ PointerSizes sizes = getSizes();
+
+ return sizes.getSize(23)
+ + sizes.getStrOffSize()
+ + sizes.getSize(21)
+ + sizes.getSize(27);
+ }
+
+ /**
+ * The number of records in this section.
+ *
+ * @return The number of items in the section.
+ */
+ protected int numberOfItems() {
+ return index.size();
+ }
+
+ /**
+ * Flag purposes are not known.
+ */
+ public int getExtraValue() {
+ return 0x7;
+ }
+
+ public List<Mdr28Record> getIndex() {
+ return Collections.unmodifiableList(index);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr28Record.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr28Record.java
new file mode 100644
index 0000000..cce543a
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr28Record.java
@@ -0,0 +1,89 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+/**
+ * There is one of these for each region name (ie no repeats) there are indexes
+ * to the first entry with the same name in various other sections.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr28Record extends ConfigBase {
+ private int index;
+ private String name;
+ private int mdr21;
+ private int mdr23;
+ private int mdr27;
+ private int strOffset;
+ private Mdr14Record mdr14;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getMdr21() {
+ return mdr21;
+ }
+
+ public void setMdr21(int mdr21) {
+ if (this.mdr21 == 0)
+ this.mdr21 = mdr21;
+ }
+
+ public int getMdr23() {
+ return mdr23;
+ }
+
+ public void setMdr23(int mdr23) {
+ if (this.mdr23 == 0)
+ this.mdr23 = mdr23;
+ }
+
+ public int getMdr27() {
+ return mdr27;
+ }
+
+ public void setMdr27(int mdr27) {
+ if (this.mdr27 == 0)
+ this.mdr27 = mdr27;
+ }
+
+ public int getStrOffset() {
+ return strOffset;
+ }
+
+ public void setStrOffset(int strOffset) {
+ this.strOffset = strOffset;
+ }
+
+ public Mdr14Record getMdr14() {
+ return mdr14;
+ }
+
+ public void setMdr14(Mdr14Record mdr14) {
+ this.mdr14 = mdr14;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public void setIndex(int index) {
+ this.index = index;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr29.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr29.java
new file mode 100644
index 0000000..7a506db
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr29.java
@@ -0,0 +1,145 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+
+/**
+ * An index of countries sorted by name with pointers to the other country related sections.
+ * There is only one per name, not per name and map.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr29 extends MdrSection implements HasHeaderFlags {
+ private final List<Mdr29Record> index = new ArrayList<Mdr29Record>();
+ private int max17;
+
+ public Mdr29(MdrConfig config) {
+ setConfig(config);
+ }
+
+ public void buildFromCountries(List<Mdr14Record> countries) {
+ Sort sort = getConfig().getSort();
+ List<SortKey<Mdr14Record>> keys = MdrUtils.sortList(sort, countries);
+
+ // Sorted by name, for every new name we allocate a new 29 record and set the same one in every
+ // country with the same name.
+ String lastName = null;
+ Mdr29Record mdr29 = null;
+ for (SortKey<Mdr14Record> key : keys) {
+ Mdr14Record country = key.getObject();
+
+ String name = country.getName();
+ if (!name.equals(lastName)) {
+ mdr29 = new Mdr29Record();
+ mdr29.setName(name);
+ mdr29.setStrOffset(country.getStrOff());
+ index.add(mdr29);
+ lastName = name;
+ }
+
+ assert mdr29 != null;
+ country.setMdr29(mdr29);
+ }
+ }
+
+ protected void preWriteImpl() {
+ if (!index.isEmpty()) {
+ Mdr29Record r = index.get(index.size() - 1);
+ this.max17 = r.getMdr17();
+ }
+ }
+
+ /**
+ * Write out the contents of this section.
+ *
+ * @param writer Where to write it.
+ */
+ public void writeSectData(ImgFileWriter writer) {
+ int magic = getExtraValue();
+
+ boolean hasString = (magic & 1) != 0;
+ boolean has26 = (magic & 0x8) != 0;
+ boolean has17 = (magic & 0x30) != 0;
+
+ PointerSizes sizes = getSizes();
+ int size24 = sizes.getSize(24);
+ int size22 = sizes.getSize(22);
+ int size25 = sizes.getSize(25);
+ int size26 = has26? sizes.getSize(26): 0;
+ int size17 = numberToPointerSize(max17);
+ for (Mdr29Record record : index) {
+ putN(writer, size24, record.getMdr24());
+ if (hasString)
+ putStringOffset(writer, record.getStrOffset());
+ putN(writer, size22, record.getMdr22());
+ putN(writer, size25, record.getMdr25());
+ if (has26)
+ putN(writer, size26, record.getMdr26());
+ if (has17)
+ putN(writer, size17, record.getMdr17());
+ }
+ }
+
+ /**
+ * The size of a record in the section. This is not a constant and might vary
+ * on various factors, such as the file version, if we are preparing for a
+ * device, the number of maps etc.
+ *
+ * @return The size of a record in this section.
+ */
+ public int getItemSize() {
+ PointerSizes sizes = getSizes();
+ int size = sizes.getSize(24)
+ + sizes.getSize(22)
+ + sizes.getSize(25)
+ ;
+ if (isForDevice()) {
+ size += numberToPointerSize(max17);
+ } else {
+ size += sizes.getStrOffSize();
+ size += sizes.getSize(26);
+ }
+ return size;
+ }
+
+ /**
+ * The number of records in this section.
+ *
+ * @return The number of items in the section.
+ */
+ protected int numberOfItems() {
+ return index.size();
+ }
+
+ /**
+ * Unknown flags.
+ *
+ * As there are 4 bits set and 4 extra fields, that might be it. Compare
+ * to mdr28 where there are 3 extra fields and 3 bits set. Just a guess...
+ */
+ public int getExtraValue() {
+ if (isForDevice()) {
+ int magic = 0x6; // 22 and 25
+ magic |= numberToPointerSize(max17) << 4;
+ return magic; // +17, -26, -strings
+ }
+ else
+ return 0xf; // strings, 22, 25 and 26
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr29Record.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr29Record.java
new file mode 100644
index 0000000..d4db861
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr29Record.java
@@ -0,0 +1,90 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+/**
+ * Holds the name and pointers to all the other country related sections for
+ * the given name.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr29Record {
+ private String name;
+ private int mdr24;
+ private int mdr22;
+ private int mdr25;
+ private int mdr26;
+ private int strOffset;
+ private int mdr17;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getMdr24() {
+ return mdr24;
+ }
+
+ public void setMdr24(int mdr24) {
+ if (this.mdr24 == 0)
+ this.mdr24 = mdr24;
+ }
+
+ public int getMdr22() {
+ return mdr22;
+ }
+
+ public void setMdr22(int mdr22) {
+ if (this.mdr22 == 0)
+ this.mdr22 = mdr22;
+ }
+
+ public int getMdr25() {
+ return mdr25;
+ }
+
+ public void setMdr25(int mdr25) {
+ if (this.mdr25 == 0)
+ this.mdr25 = mdr25;
+ }
+
+ public int getMdr26() {
+ return mdr26;
+ }
+
+ public void setMdr26(int mdr26) {
+ if (this.mdr26 == 0)
+ this.mdr26 = mdr26;
+ }
+
+ public int getStrOffset() {
+ return strOffset;
+ }
+
+ public void setStrOffset(int strOffset) {
+ this.strOffset = strOffset;
+ }
+
+ public int getMdr17() {
+ return mdr17;
+ }
+
+ public void setMdr17(int mdr17) {
+ if (this.mdr17 == 0)
+ this.mdr17 = mdr17;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr2x.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr2x.java
new file mode 100644
index 0000000..965b260
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr2x.java
@@ -0,0 +1,101 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+
+/**
+ * Common code for 20, 21, 22 which are all lists of streets ordered in
+ * different ways.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class Mdr2x extends MdrMapSection implements HasHeaderFlags {
+ protected List<Mdr7Record> streets = new ArrayList<Mdr7Record>();
+
+ /**
+ * Write out the contents of this section.
+ *
+ * @param writer Where to write it.
+ */
+ public void writeSectData(ImgFileWriter writer) {
+ String lastName = null;
+
+ int size = getSizes().getStreetSizeFlagged();
+
+ boolean hasLabel = hasFlag(0x2);
+ int recordNumber = 0;
+ for (Mdr7Record street : streets) {
+ assert street.getMapIndex() == street.getCity().getMapIndex() : street.getMapIndex() + "/" + street.getCity().getMapIndex();
+ addIndexPointer(street.getMapIndex(), ++recordNumber);
+
+ int index = street.getIndex();
+ String name = Label.stripGarminCodes(street.getName());
+
+ int flag = 1;
+ if (name.equals(lastName)) {
+ flag = 0;
+ } else {
+ lastName = name;
+ }
+
+ if (hasLabel) {
+ putMapIndex(writer, street.getMapIndex());
+ int offset = street.getLabelOffset();
+ if (flag != 0)
+ offset |= 0x800000;
+ writer.put3(offset);
+ writer.put((byte) flag);
+ }
+ else
+ putN(writer, size, (index << 1) | flag);
+ }
+ }
+
+ /**
+ * The size of a record in the section.
+ *
+ * For these sections there is one field that is an index into the
+ * streets with an extra bit for a flag.
+ *
+ * In the device configuration, then there is a label and a flag, just like
+ * for mdr7.
+ */
+ public int getItemSize() {
+ int size;
+ if (isForDevice()) {
+ size = getSizes().getMapSize() + 3 + 1;
+ } else {
+ size = getSizes().getStreetSizeFlagged();
+ }
+
+ return size;
+ }
+
+ /**
+ * The number of records in this section.
+ *
+ * @return The number of items in the section.
+ */
+ protected int numberOfItems() {
+ return streets.size();
+ }
+
+ protected void releaseMemory() {
+ streets = null;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr4.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr4.java
new file mode 100644
index 0000000..6581f54
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr4.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * POI types. A simple list of the types that are used?
+ * If you have this section, then the ability to select POI categories
+ * goes away.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr4 extends MdrSection implements HasHeaderFlags {
+ private final Set<Mdr4Record> poiTypes = new HashSet<Mdr4Record>();
+
+ public Mdr4(MdrConfig config) {
+ setConfig(config);
+ }
+
+
+ public void writeSectData(ImgFileWriter writer) {
+ List<Mdr4Record> list = new ArrayList<Mdr4Record>(poiTypes);
+ Collections.sort(list);
+
+ for (Mdr4Record r : list) {
+ writer.put((byte) r.getType());
+ writer.put((byte) r.getUnknown());
+ writer.put((byte) r.getSubtype());
+ }
+ }
+
+ public int getItemSize() {
+ return 3;
+ }
+
+ public void addType(int type) {
+ Mdr4Record r = new Mdr4Record();
+ if (type <= 0xff)
+ r.setType(type);
+ else {
+ r.setType((type >> 8) & 0xff);
+ r.setSubtype(type & 0xff);
+ }
+ r.setUnknown(0);
+
+ poiTypes.add(r);
+ }
+
+ /**
+ * The number of records in this section.
+ *
+ * @return The number of items in the section.
+ */
+ protected int numberOfItems() {
+ return poiTypes.size();
+ }
+
+
+ public int getExtraValue() {
+ return 0x00;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr4Record.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr4Record.java
new file mode 100644
index 0000000..8c11cb0
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr4Record.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+/**
+ * The records in MDR 4 are a list of poi types with an unknown byte.
+ */
+public class Mdr4Record implements Comparable<Mdr4Record> {
+ private int type;
+ private int subtype;
+ private int unknown;
+
+ public int compareTo(Mdr4Record o) {
+ int t1 = ((type<<8) + subtype) & 0xffff;
+ int t2 = ((o.type<<8) + o.subtype) & 0xffff;
+ if (t1 == t2)
+ return 0;
+ else if (t1 < t2)
+ return -1;
+ else
+ return 1;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Mdr4Record that = (Mdr4Record) o;
+
+ if (subtype != that.subtype) return false;
+ if (type != that.type) return false;
+
+ return true;
+ }
+
+
+ public int hashCode() {
+ int result = type;
+ result = 31 * result + subtype;
+ return result;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ public int getSubtype() {
+ return subtype;
+ }
+
+ public void setSubtype(int subtype) {
+ this.subtype = subtype;
+ }
+
+ public int getUnknown() {
+ return unknown;
+ }
+
+ public void setUnknown(int unknown) {
+ this.unknown = unknown;
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr5.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr5.java
new file mode 100644
index 0000000..7503359
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr5.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.srt.MultiSortKey;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+
+/**
+ * Section containing cities.
+ *
+ * We need: map number, city index in map, offset in LBL, flags
+ * and pointer into MDR 15 for the string name.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr5 extends MdrMapSection {
+ private List<Mdr5Record> allCities = new ArrayList<Mdr5Record>();
+ private List<Mdr5Record> cities = new ArrayList<Mdr5Record>();
+ private int maxCityIndex;
+ private int localCitySize;
+
+ public Mdr5(MdrConfig config) {
+ setConfig(config);
+ }
+
+ public void addCity(Mdr5Record record) {
+ assert record.getMapIndex() != 0;
+ allCities.add(record);
+ if (record.getCityIndex() > maxCityIndex)
+ maxCityIndex = record.getCityIndex();
+ }
+
+ /**
+ * Called after all cities to sort and number them.
+ */
+ public void preWriteImpl() {
+ localCitySize = numberToPointerSize(maxCityIndex + 1);
+
+ List<SortKey<Mdr5Record>> sortKeys = new ArrayList<SortKey<Mdr5Record>>(allCities.size());
+ Sort sort = getConfig().getSort();
+ for (Mdr5Record m : allCities) {
+ if (m.getName() == null)
+ continue;
+
+ // Sort by city name, region name, country name and map index.
+ SortKey<Mdr5Record> sortKey = sort.createSortKey(m, m.getName());
+ SortKey<Mdr5Record> regionKey = sort.createSortKey(null, m.getRegionName());
+ SortKey<Mdr5Record> countryKey = sort.createSortKey(null, m.getCountryName(), m.getMapIndex());
+ sortKey = new MultiSortKey<Mdr5Record>(sortKey, regionKey, countryKey);
+ sortKeys.add(sortKey);
+ }
+ Collections.sort(sortKeys);
+
+ int count = 0;
+ Mdr5Record lastCity = null;
+
+ // We need a common area to save the mdr20 values, since there can be multiple
+ // city records with the same global city index
+ int[] mdr20s = new int[sortKeys.size()+1];
+ int mdr20count = 0;
+
+ for (SortKey<Mdr5Record> key : sortKeys) {
+ Mdr5Record c = key.getObject();
+ c.setMdr20set(mdr20s);
+
+ if (!c.isSameByName(lastCity))
+ mdr20count++;
+ c.setMdr20Index(mdr20count);
+
+ if (c.isSameByMapAndName(lastCity)) {
+ c.setGlobalCityIndex(count);
+ } else {
+ count++;
+ c.setGlobalCityIndex(count);
+ cities.add(c);
+
+ lastCity = c;
+ }
+ }
+ }
+
+ public void writeSectData(ImgFileWriter writer) {
+ int size20 = getSizes().getMdr20Size();
+ Mdr5Record lastCity = null;
+ boolean hasString = hasFlag(0x8);
+ boolean hasRegion = hasFlag(0x4);
+ for (Mdr5Record city : cities) {
+ int gci = city.getGlobalCityIndex();
+ addIndexPointer(city.getMapIndex(), gci);
+
+ // Work out if the name is the same as the previous one and set
+ // the flag if so.
+ int flag = 0;
+ int mapIndex = city.getMapIndex();
+ int region = city.getRegionIndex();
+
+ // Set the no-repeat flag if the name/region is different
+ if (!city.isSameByName(lastCity)) {
+ flag = 0x800000;
+ lastCity = city;
+ }
+
+ // Write out the record
+ putMapIndex(writer, mapIndex);
+ putLocalCityIndex(writer, city.getCityIndex());
+ writer.put3(flag | city.getLblOffset());
+ if (hasRegion)
+ writer.putChar((char) region);
+ if (hasString)
+ putStringOffset(writer, city.getStringOffset());
+ putN(writer, size20, city.getMdr20());
+ }
+ }
+
+ /**
+ * Put the map city index. This is the index within the individual map
+ * and not the global city index used in mdr11.
+ */
+ private void putLocalCityIndex(ImgFileWriter writer, int cityIndex) {
+ if (localCitySize == 2) // 3 probably not possible in actual maps.
+ writer.putChar((char) cityIndex);
+ else
+ writer.put((byte) cityIndex);
+ }
+
+ /**
+ * Base size of 8, plus enough bytes to represent the map number
+ * and the city number.
+ * @return The size of a record in this section.
+ */
+ public int getItemSize() {
+ PointerSizes sizes = getSizes();
+ int size = sizes.getMapSize()
+ + localCitySize
+ + 3
+ + sizes.getMdr20Size();
+ if (hasFlag(0x4))
+ size += 2;
+ if (hasFlag(0x8))
+ size += sizes.getStrOffSize();
+ return size;
+ }
+
+ protected int numberOfItems() {
+ return cities.size();
+ }
+
+ /**
+ * Known structure:
+ * bits 0-1: size of local city index - 1 (all values appear to work)
+ * bit 3: has region
+ * bit 4: has string
+ * @return The value to be placed in the header.
+ */
+ public int getExtraValue() {
+ int val = (localCitySize - 1);
+ // String offset is only included for a mapsource index.
+ if (isForDevice()) {
+ val |= 0x40; // not known, probably refers to mdr17.
+ } else {
+ val |= 0x04; // region
+ val |= 0x08; // string
+ }
+ val |= 0x10;
+ val |= 0x100; // mdr20 present
+ return val;
+ }
+
+ protected void releaseMemory() {
+ allCities = null;
+ cities = null;
+ }
+
+ /**
+ * Get a list of all the cities, including duplicate named ones.
+ * @return All cities.
+ */
+ public List<Mdr5Record> getCities() {
+ return Collections.unmodifiableList(allCities);
+ }
+
+ public List<Mdr5Record> getSortedCities() {
+ return Collections.unmodifiableList(cities);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr5Record.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr5Record.java
new file mode 100644
index 0000000..702cc49
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr5Record.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+/**
+ * Holds information about a city that will make its way into mdr 5.
+ * This class is used in several places as the information has to be gathered
+ * from the cities section of LBL and the points in RGN.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr5Record extends RecordBase implements NamedRecord {
+ /** The city index within its own map */
+ private int cityIndex;
+
+ /** The index across all maps */
+ private int globalCityIndex;
+
+ private int regionIndex;
+ private int lblOffset;
+ private int stringOffset;
+ private String name;
+ private Mdr13Record region;
+ private Mdr14Record country;
+ private int[] mdr20;
+ private int mdr20Index;
+
+ public int getCityIndex() {
+ return cityIndex;
+ }
+
+ public void setCityIndex(int cityIndex) {
+ this.cityIndex = cityIndex;
+ }
+
+ public int getGlobalCityIndex() {
+ return globalCityIndex;
+ }
+
+ public void setGlobalCityIndex(int globalCityIndex) {
+ this.globalCityIndex = globalCityIndex;
+ }
+
+ public int getRegionIndex() {
+ return regionIndex;
+ }
+
+ public void setRegionIndex(int regionIndex) {
+ this.regionIndex = regionIndex;
+ }
+
+ public int getLblOffset() {
+ return lblOffset;
+ }
+
+ public void setLblOffset(int lblOffset) {
+ this.lblOffset = lblOffset;
+ }
+
+ public int getStringOffset() {
+ return stringOffset;
+ }
+
+ public void setStringOffset(int stringOffset) {
+ this.stringOffset = stringOffset;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Mdr13Record getMdrRegion() {
+ return region;
+ }
+
+ public void setMdrRegion(Mdr13Record region) {
+ this.region = region;
+ }
+
+ public Mdr14Record getMdrCountry() {
+ return country;
+ }
+
+ public void setMdrCountry(Mdr14Record country) {
+ this.country = country;
+ }
+
+ /**
+ * Every mdr5 record contains the same array of values. It is only
+ * allowed to access the one at the index globalCityIndex. Since
+ * the array is shared, every record with the same global city index
+ * knows the correct mdr20 value, regardless of where it was set.
+ *
+ * @param mdr20 An array large enough to hold all the cities (one based index).
+ * This must be the same array for all mdr5records (in the same map set).
+ */
+ public void setMdr20set(int[] mdr20) {
+ this.mdr20 = mdr20;
+ }
+
+ /**
+ * Set the index into the mdr20 array that we use to get/set the value.
+ * @see #setMdr20set(int[])
+ */
+ public void setMdr20Index(int mdr20Index) {
+ this.mdr20Index = mdr20Index;
+ }
+
+ public int getMdr20() {
+ return mdr20[mdr20Index];
+ }
+
+ public void setMdr20(int n) {
+ int prev = mdr20[mdr20Index];
+ assert prev == 0 || prev == n : "mdr20 value changed f=" + prev + " t=" + n + " count=" + mdr20Index;
+
+ mdr20[mdr20Index] = n;
+ }
+
+ /**
+ * Is this the same city, by the rules segregating the cities in mdr5 and 20.
+ * @return True if in the same tile and has the same name for city/region/country.
+ */
+ public boolean isSameByMapAndName(Mdr5Record other) {
+ if (other == null)
+ return false;
+
+ return getMapIndex() == other.getMapIndex() && isSameByName(other);
+ }
+
+ /**
+ * Same city by the name of the city/region/country combination.
+ * @param other The other city to compare with.
+ * @return True if is the same city, maybe in a different tile.
+ */
+ public boolean isSameByName(Mdr5Record other) {
+ if (other == null)
+ return false;
+
+ return getName().equals(other.getName())
+ && getRegionName().equals(other.getRegionName())
+ && getCountryName().equals(other.getCountryName());
+ }
+
+ public String toString() {
+ return String.format("%d: %s r=%s c=%s", globalCityIndex, name, getRegionName(), country.getName());
+ }
+
+ public String getRegionName() {
+ if (region == null)
+ return "";
+ else
+ return region.getName();
+ }
+
+ public String getCountryName() {
+ return country.getName();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr6.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr6.java
new file mode 100644
index 0000000..5005432
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr6.java
@@ -0,0 +1,91 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.lbl.Zip;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+
+/**
+ * Section containing zip codes.
+ *
+ * We need: map number, zip index in map, pointer into MDR 15 for the string name.
+ *
+ * @author WanMil
+ */
+public class Mdr6 extends MdrMapSection {
+
+ private final List<Mdr6Record> zips = new ArrayList<Mdr6Record>();
+
+
+ public Mdr6(MdrConfig config) {
+ setConfig(config);
+ }
+
+ public void addZip(int mapIndex, Zip zip, int strOff) {
+ Mdr6Record record = new Mdr6Record(zip);
+ record.setMapIndex(mapIndex);
+ record.setStringOffset(strOff);
+ zips.add(record);
+ }
+
+
+ public void writeSectData(ImgFileWriter writer) {
+ int zipSize = getSizes().getZipSize();
+
+ List<SortKey<Mdr6Record>> sortKeys = MdrUtils.sortList(getConfig().getSort(), zips);
+
+ boolean hasString = hasFlag(0x4);
+ int record = 1;
+ for (SortKey<Mdr6Record> key : sortKeys) {
+ Mdr6Record z = key.getObject();
+ addIndexPointer(z.getMapIndex(), record++);
+
+ putMapIndex(writer, z.getMapIndex());
+ putN(writer, zipSize, z.getZipIndex());
+ if (hasString)
+ putStringOffset(writer, z.getStringOffset());
+ }
+ }
+
+ /**
+ * Enough bytes to represent the map number
+ * and the zip index and the string offset.
+ * @return The size of a record in this section.
+ */
+ public int getItemSize() {
+ PointerSizes sizes = getSizes();
+ int size = sizes.getMapSize() + sizes.getZipSize();
+ if (hasFlag(0x4))
+ size += sizes.getStrOffSize();
+ return size;
+ }
+
+ protected int numberOfItems() {
+ return zips.size();
+ }
+
+ /**
+ * Known structure:
+ * bits 0-1: size of local zip index - 1 (all values appear to work)
+ * bits 2: if MDR 15 available
+ * @return The value to be placed in the header.
+ */
+ public int getExtraValue() {
+ return ((getSizes().getZipSize()-1)&0x03) | (isForDevice() ? 0 : 0x04);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr6Record.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr6Record.java
new file mode 100644
index 0000000..081f139
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr6Record.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import uk.me.parabola.imgfmt.app.lbl.Zip;
+
+/**
+ * Holds information about a zip that will make its way into mdr 6.
+ *
+ * @author WanMil
+ */
+public class Mdr6Record extends RecordBase implements NamedRecord {
+ /** The zip index within its own map */
+ private final int zipIndex;
+
+ private final String name;
+ private int stringOffset;
+
+ public Mdr6Record(Zip zip) {
+ zipIndex = zip.getIndex();
+ name = zip.getLabel().getText();
+ }
+
+ public int getZipIndex() {
+ return zipIndex;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getStringOffset() {
+ return stringOffset;
+ }
+
+ public void setStringOffset(int stringOffset) {
+ this.stringOffset = stringOffset;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr7.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr7.java
new file mode 100644
index 0000000..b59936e
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr7.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+
+/**
+ * The MDR 7 section is a list of all streets. Only street names are saved
+ * and so I believe that the NET section is required to make this work.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr7 extends MdrMapSection {
+ private List<Mdr7Record> allStreets = new ArrayList<Mdr7Record>();
+ private List<Mdr7Record> streets = new ArrayList<Mdr7Record>();
+
+ public Mdr7(MdrConfig config) {
+ setConfig(config);
+ }
+
+ public void addStreet(int mapId, String name, int lblOffset, int strOff, Mdr5Record mdrCity) {
+ Mdr7Record st = new Mdr7Record();
+ st.setMapIndex(mapId);
+ st.setLabelOffset(lblOffset);
+ st.setStringOffset(strOff);
+ st.setName(name);
+ st.setCity(mdrCity);
+ allStreets.add(st);
+ }
+
+ /**
+ * Since we change the number of records by removing some after sorting,
+ * we sort and de-duplicate here.
+ */
+ protected void preWriteImpl() {
+ List<SortKey<Mdr7Record>> sortedStreets = MdrUtils.sortList(getConfig().getSort(), allStreets);
+
+ // De-duplicate the street names so that there is only one entry
+ // per map for the same name.
+ int recordNumber = 0;
+ Mdr7Record last = new Mdr7Record();
+ for (SortKey<Mdr7Record> sk : sortedStreets) {
+ Mdr7Record r = sk.getObject();
+ if (r.getMapIndex() != last.getMapIndex() || !r.getName().equals(last.getName())) {
+ recordNumber++;
+ last = r;
+ r.setIndex(recordNumber);
+ streets.add(r);
+ } else {
+ // This has the same name (and map number) as the previous one. Save the pointer to that one
+ // which is going into the file.
+ r.setIndex(recordNumber);
+ }
+ }
+ }
+
+ public void writeSectData(ImgFileWriter writer) {
+ String lastName = null;
+ boolean hasStrings = hasFlag(0x1);
+ for (Mdr7Record s : streets) {
+ addIndexPointer(s.getMapIndex(), s.getIndex());
+
+ putMapIndex(writer, s.getMapIndex());
+ int lab = s.getLabelOffset();
+ String name = Label.stripGarminCodes(s.getName());
+ int trailingFlags = 0;
+ if (!name.equals(lastName)) {
+ lab |= 0x800000;
+ lastName = name;
+ trailingFlags = 1;
+ }
+ writer.put3(lab);
+ if (hasStrings)
+ putStringOffset(writer, s.getStringOffset());
+
+ writer.put((byte) trailingFlags);
+ }
+ }
+
+ /**
+ * For the map number, label, string (opt), and trailing flags (opt).
+ * The trailing flags are variable size. We are just using 1 now.
+ */
+ public int getItemSize() {
+ PointerSizes sizes = getSizes();
+ int size = sizes.getMapSize() + 3 + 1;
+ if (!isForDevice())
+ size += sizes.getStrOffSize();
+ return size;
+ }
+
+ protected int numberOfItems() {
+ return streets.size();
+ }
+
+ /**
+ * Value of 3 possibly the existence of the lbl field.
+ */
+ public int getExtraValue() {
+ int magic = 0x42;
+ if (isForDevice()) {
+ magic |= 0x4;
+ } else {
+ magic |= 0x1; //strings
+ }
+
+ return magic;
+ }
+
+ protected void releaseMemory() {
+ allStreets = null;
+ streets = null;
+ }
+
+ /**
+ * Must be called after the section data is written so that the streets
+ * array is already sorted.
+ * @return List of index records.
+ */
+ public List<Mdr8Record> getIndex() {
+ List<Mdr8Record> list = new ArrayList<Mdr8Record>();
+ for (int number = 1; number <= streets.size(); number += 10240) {
+ String prefix = getPrefixForRecord(number);
+
+ // need to step back to find the first...
+ int rec = number;
+ while (rec > 1) {
+ String p = getPrefixForRecord(rec);
+ if (!p.equals(prefix)) {
+ rec++;
+ break;
+ }
+ rec--;
+ }
+
+ Mdr8Record indexRecord = new Mdr8Record();
+ indexRecord.setPrefix(prefix);
+ indexRecord.setRecordNumber(rec);
+ list.add(indexRecord);
+ }
+ return list;
+ }
+
+ /**
+ * Get the prefix of the name at the given record.
+ * @param number The record number.
+ * @return The first 4 (or whatever value is set) characters of the street
+ * name.
+ */
+ private String getPrefixForRecord(int number) {
+ Mdr7Record record = streets.get(number-1);
+ int endIndex = MdrUtils.STREET_INDEX_PREFIX_LEN;
+ String name = record.getName();
+ if (endIndex > name.length()) {
+ StringBuilder sb = new StringBuilder(name);
+ while (sb.length() < endIndex)
+ sb.append('\0');
+ name = sb.toString();
+ }
+ return name.substring(0, endIndex);
+ }
+
+ public List<Mdr7Record> getStreets() {
+ return Collections.unmodifiableList(allStreets);
+ }
+
+ public List<Mdr7Record> getSortedStreets() {
+ return Collections.unmodifiableList(streets);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr7Record.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr7Record.java
new file mode 100644
index 0000000..d26af18
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr7Record.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+/**
+ * Holds details of a single street.
+ * @author Steve Ratcliffe
+ */
+public class Mdr7Record extends RecordBase implements NamedRecord {
+ private int labelOffset;
+ private int stringOffset;
+ private String name;
+ private int index;
+ private Mdr5Record city;
+
+ public int getLabelOffset() {
+ return labelOffset;
+ }
+
+ public void setLabelOffset(int labelOffset) {
+ this.labelOffset = labelOffset;
+ }
+
+ public int getStringOffset() {
+ return stringOffset;
+ }
+
+ public void setStringOffset(int stringOffset) {
+ this.stringOffset = stringOffset;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public void setCity(Mdr5Record city) {
+ this.city = city;
+ }
+
+ public Mdr5Record getCity() {
+ return city;
+ }
+
+ public String toString() {
+ return name + " in " + city.getName();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr8.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr8.java
new file mode 100644
index 0000000..6113d1f
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr8.java
@@ -0,0 +1,88 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * This section is a simple index into the streets section (mdr7).
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr8 extends MdrSection implements HasHeaderFlags {
+ private static final int STRING_WIDTH = 4;
+
+ private List<Mdr8Record> index = new ArrayList<Mdr8Record>();
+
+ public Mdr8(MdrConfig config) {
+ setConfig(config);
+ }
+
+ /**
+ * Write out the contents of this section.
+ *
+ * @param writer Where to write it.
+ */
+ public void writeSectData(ImgFileWriter writer) {
+ int size = associatedSize();
+ Charset charset = getConfig().getSort().getCharset();
+ for (Mdr8Record s : index) {
+ writer.put(s.getPrefix().getBytes(charset), 0, STRING_WIDTH);
+ putN(writer, size, s.getRecordNumber());
+ }
+ }
+
+ protected int associatedSize() {
+ return getSizes().getStreetSize();
+ }
+
+ /**
+ * The number of records in this section.
+ *
+ * @return The number of items in the section.
+ */
+ protected int numberOfItems() {
+ return index.size();
+ }
+
+ /**
+ * The size of a record in the section. This is not a constant and might vary
+ * on various factors, such as the file version, if we are preparing for a
+ * device, the number of maps etc.
+ *
+ * @return The size of a record in this section.
+ */
+ public int getItemSize() {
+ return STRING_WIDTH + associatedSize();
+ }
+
+ public void setIndex(List<Mdr8Record> index) {
+ this.index = index;
+ }
+
+ /**
+ * The header flags for the section.
+ * Possible values are not known.
+ *
+ * @return The correct value based on the contents of the section. Zero if
+ * nothing needs to be done.
+ */
+ public int getExtraValue() {
+ // this value is likely to depend on the size of the max record number.
+ return (STRING_WIDTH << 8) + 0x0a;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr8Record.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr8Record.java
new file mode 100644
index 0000000..0c09e67
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr8Record.java
@@ -0,0 +1,39 @@
+/*
+ * 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.imgfmt.app.mdr;
+
+/**
+ * This section is a simple index into the streets section (mdr7).
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr8Record extends ConfigBase {
+ private String prefix;
+ private int recordNumber;
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public int getRecordNumber() {
+ return recordNumber;
+ }
+
+ public void setRecordNumber(int recordNumber) {
+ this.recordNumber = recordNumber;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr9.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr9.java
new file mode 100644
index 0000000..58ebc33
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr9.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * An index into mdr10. There is a single byte group number followed by
+ * the first record in mdr10 that belongs to that group.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Mdr9 extends MdrSection implements HasHeaderFlags {
+ private final Map<Integer, Integer> index = new LinkedHashMap<Integer, Integer>();
+
+ public Mdr9(MdrConfig config) {
+ setConfig(config);
+ }
+
+ public void writeSectData(ImgFileWriter writer) {
+ int poiSize = getSizes().getPoiSize();
+ for (Map.Entry<Integer, Integer> ent : index.entrySet()) {
+ int group = ent.getKey();
+ writer.put((byte) group);
+ putN(writer, poiSize, ent.getValue());
+ }
+ }
+
+ /**
+ * The item size is one byte for the group and then enough bytes for the
+ * index into mdr10.
+ * @return Just return 4 for now.
+ */
+ public int getItemSize() {
+ return 1 + getSizes().getPoiSize();
+ }
+
+ /**
+ * The number of records in this section.
+ *
+ * @return The number of items in the section.
+ */
+ protected int numberOfItems() {
+ return index.size();
+ }
+
+ public void setGroups(Map<Integer, Integer> groupSizes) {
+ int offset = 1;
+ for (Map.Entry<Integer, Integer> ent : groupSizes.entrySet()) {
+ index.put(ent.getKey(), offset);
+ offset += ent.getValue();
+ }
+ }
+
+ public int getExtraValue() {
+ return 0x00;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/MdrConfig.java b/src/uk/me/parabola/imgfmt/app/mdr/MdrConfig.java
new file mode 100644
index 0000000..893e83f
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/MdrConfig.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import java.io.File;
+
+import uk.me.parabola.imgfmt.app.srt.Sort;
+
+/**
+ * Configuration for the MDR file.
+ * Mostly used when creating a file as there are a number of different options
+ * in the way that it is done.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MdrConfig {
+ //private static final int DEFAULT_HEADER_LEN = 286;
+ private static final int DEFAULT_HEADER_LEN = 568;
+
+ private boolean writable;
+ private boolean forDevice;
+ private int headerLen = DEFAULT_HEADER_LEN;
+ private Sort sort;
+ private File outputDir;
+
+ /**
+ * True if we are creating the file, rather than reading it.
+ */
+ public boolean isWritable() {
+ return writable;
+ }
+
+ public void setWritable(boolean writable) {
+ this.writable = writable;
+ }
+
+ /**
+ * The format that is used by the GPS devices is different to that used
+ * by Map Source. This parameter says which to do.
+ * @return True if we are creating the the more compact format required
+ * for a device.
+ */
+ public boolean isForDevice() {
+ return forDevice;
+ }
+
+ public void setForDevice(boolean forDevice) {
+ this.forDevice = forDevice;
+ }
+
+ /**
+ * There are a number of different header lengths in existence. This
+ * controls what sections can exist (and perhaps what must exist).
+ * @return The header length.
+ */
+ public int getHeaderLen() {
+ return headerLen;
+ }
+
+ public void setHeaderLen(int headerLen) {
+ this.headerLen = headerLen;
+ }
+
+ public Sort getSort() {
+ return sort;
+ }
+
+ public void setSort(Sort sort) {
+ this.sort = sort;
+ }
+
+ public File getOutputDir() {
+ return outputDir;
+ }
+
+ public void setOutputDir(String outputDir) {
+ if (outputDir != null)
+ this.outputDir = new File(outputDir);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/MdrMapSection.java b/src/uk/me/parabola/imgfmt/app/mdr/MdrMapSection.java
new file mode 100644
index 0000000..14ab889
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/MdrMapSection.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * Super class of all sections that contain items that belong to a particular
+ * map.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class MdrMapSection extends MdrSection implements HasHeaderFlags {
+ private Mdr1 index;
+
+ public void setMapIndex(Mdr1 index) {
+ this.index = index;
+ }
+
+ /**
+ * This is called before the sections are written out, but after all the
+ * data is read into them.
+ * @param sectionNumber The one-based section number.
+ */
+ public final void initIndex(int sectionNumber) {
+ // Set the size required to store the record numbers for this section.
+ // There are no flags or minimums required here, unlike in setPointerSize()
+ // which does a similar thing.
+ int n = getNumberOfItems();
+ index.setPointerSize(sectionNumber, numberToPointerSize(n));
+ }
+
+ /**
+ * Add a pointer to the reverse index for this section.
+ * @param recordNumber A record number in this section, belonging to the
+ * given map.
+ */
+ public void addIndexPointer(int mapNumber, int recordNumber) {
+ if (!isForDevice())
+ index.addPointer(mapNumber, recordNumber);
+ }
+
+ protected void putCityIndex(ImgFileWriter writer, int cityIndex, boolean isNew) {
+ int flag = (isNew && cityIndex > 0)? getSizes().getCityFlag(): 0;
+ putN(writer, getSizes().getCitySizeFlagged(), cityIndex | flag);
+ }
+
+ protected void putRegionIndex(ImgFileWriter writer, int region) {
+ // This is only called when putCityIndex might also be called and so has to be
+ // the same size (probably ;)
+ putN(writer, getSizes().getCitySizeFlagged(), region);
+ }
+
+ protected void putPoiIndex(ImgFileWriter writer, int poiIndex, boolean isNew) {
+ int flag = isNew? getSizes().getPoiFlag(): 0;
+ putN(writer, getSizes().getPoiSizeFlagged(), poiIndex | flag);
+ }
+
+ protected boolean hasFlag(int val) {
+ return (getExtraValue() & val) != 0;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/MdrSection.java b/src/uk/me/parabola/imgfmt/app/mdr/MdrSection.java
new file mode 100644
index 0000000..1d0b652
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/MdrSection.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * Super class of all sections.
+ * @author Steve Ratcliffe
+ */
+public abstract class MdrSection extends ConfigBase {
+ private PointerSizes sizes;
+ private boolean released;
+ protected int nItems;
+ private boolean sizeValid;
+
+ /**
+ * Write out the contents of this section.
+ * @param writer Where to write it.
+ */
+ public abstract void writeSectData(ImgFileWriter writer);
+
+ /**
+ * The size of a record in the section. This is not a constant and
+ * might vary on various factors, such as the file version, if we are
+ * preparing for a device, the number of maps etc.
+ *
+ * @return The size of a record in this section.
+ */
+ public abstract int getItemSize();
+
+ protected PointerSizes getSizes() {
+ return sizes;
+ }
+
+ public void setSizes(PointerSizes sizes) {
+ this.sizes = sizes;
+ }
+
+ protected void putMapIndex(ImgFileWriter writer, int mapIndex) {
+ putN(writer, sizes.getMapSize(), mapIndex);
+ }
+
+ protected void putStringOffset(ImgFileWriter writer, int strOff) {
+ putN(writer, sizes.getStrOffSize(), strOff);
+ }
+
+ protected void putN(ImgFileWriter writer, int n, int value) {
+ switch (n) {
+ case 1:
+ writer.put((byte) value);
+ break;
+ case 2:
+ writer.putChar((char) value);
+ break;
+ case 3:
+ writer.put3(value);
+ break;
+ case 4:
+ writer.putInt(value);
+ break;
+ default: // Don't write anything.
+ assert false;
+ break;
+ }
+ }
+
+ protected static int numberToPointerSize(int n) {
+ if (n > 0xffffff)
+ return 4;
+ else if (n > 0xffff)
+ return 3;
+ else if (n > 0xff)
+ return 2;
+ else
+ return 1;
+ }
+
+ /**
+ * The number of records in this section.
+ * @return The number of items in the section.
+ */
+ public final int getNumberOfItems() {
+ assert sizeValid;
+ if (released)
+ return nItems;
+ else
+ return numberOfItems();
+ }
+
+ /**
+ * Method to be implemented by subclasses to return the number of items in the section.
+ * This will only be valid after the section is completely finished etc.
+ * @return The number of items in the section.
+ */
+ protected abstract int numberOfItems();
+
+ /**
+ * Get the size of an integer that is sufficient to store a record number
+ * from this section. If the pointer has a flag(s) then this must be
+ * taken into account too.
+ * @return A number between 1 and 4 giving the number of bytes required
+ * to store the largest record number in this section.
+ */
+ public int getSizeForRecord() {
+ return numberToPointerSize(getNumberOfItems());
+ }
+
+ /**
+ * This is called after all the sections are read in but before any section is written.
+ *
+ * This is now pretty much redundant and could be replaced with direct calls for sections
+ * that need it.
+ */
+ public void finish() {
+ }
+
+ /**
+ * Called before the section is written and before the actual size of the section
+ * is required.
+ *
+ * Calling it more than once is ok.
+ *
+ * The actual work is implemented in the subclass via the {@link #preWriteImpl()} method.
+ */
+ public final void preWrite() {
+ if (!sizeValid)
+ preWriteImpl();
+ sizeValid = true;
+ }
+
+ /**
+ * Prepare the final list of items to be written.
+ * Used to de-duplicate or remove invalid entries from the raw data that was
+ * saved.
+ *
+ * In particular after this call the number of items must not change.
+ */
+ protected void preWriteImpl() {
+ }
+
+ public final void release() {
+ nItems = numberOfItems();
+ releaseMemory();
+ released = true;
+ }
+
+ protected void releaseMemory() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Provides the pointer sizes required to hold record of offset values
+ * in the various sections.
+ */
+ static class PointerSizes {
+
+ private final MdrSection[] sections;
+
+ public PointerSizes(MdrSection[] sections) {
+ this.sections = sections;
+ }
+
+ public int getMapSize() {
+ return sections[1].getSizeForRecord();
+ }
+
+ public int getCitySize() {
+ return sections[5].getSizeForRecord();
+ }
+
+ /**
+ * Get the number of bytes required to represent a city when there is
+ * one bit reserved for a flag.
+ * There is a minimum size of 2.
+ * @return Number of bytes to represent a city record number and a
+ * one bit flag.
+ */
+ public int getCitySizeFlagged() {
+ return Math.max(2, numberToPointerSize(sections[5].getNumberOfItems() << 1));
+ }
+
+ public int getCityFlag() {
+ return flagForSize(getCitySizeFlagged());
+ }
+
+ public int getStreetSize() {
+ return sections[7].getSizeForRecord();
+ }
+
+ public int getStreetSizeFlagged() {
+ return numberToPointerSize(sections[7].getNumberOfItems() << 1);
+ }
+
+ public int getPoiSize() {
+ return sections[11].getSizeForRecord();
+ }
+
+ public int getZipSize() {
+ //return Math.max(2, sections[6].getSizeForRecord());
+ return sections[6].getSizeForRecord();
+ }
+
+ /**
+ * The number of bytes required to represent a POI (mdr11) record number
+ * and a flag bit.
+ */
+ public int getPoiSizeFlagged() {
+ return numberToPointerSize(sections[11].getNumberOfItems() << 1);
+ }
+
+ public int getPoiFlag() {
+ return flagForSize(getPoiSizeFlagged());
+ }
+
+ /**
+ * Size of the pointer required to index a byte offset into mdr15 (strings).
+ * There is a minimum of 3 for this value.
+ * @return Pointer size required for the string offset value.
+ */
+ public int getStrOffSize() {
+ return Math.max(3, sections[15].getSizeForRecord());
+ }
+
+ public int getMdr20Size() {
+ return sections[20].getSizeForRecord();
+ }
+
+ private int flagForSize(int size) {
+ int flag;
+ if (size == 1)
+ flag = 0x80;
+ else if (size == 2)
+ flag = 0x8000;
+ else if (size == 3)
+ flag = 0x800000;
+ else if (size == 4)
+ flag = 0x80000000;
+ else
+ flag = 0;
+ return flag;
+ }
+
+ public int getSize(int sect) {
+ return sections[sect].getSizeForRecord();
+ }
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/MdrUtils.java b/src/uk/me/parabola/imgfmt/app/mdr/MdrUtils.java
new file mode 100644
index 0000000..0bc6074
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/MdrUtils.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+
+/**
+ * A bunch of static routines for use in creating the MDR file.
+ */
+public class MdrUtils {
+
+ public static final int STREET_INDEX_PREFIX_LEN = 4;
+ public static final int POI_INDEX_PREFIX_LEN = 4;
+
+ /**
+ * Get the group number for the poi. This is the first byte of the records
+ * in mdr9.
+ *
+ * Not entirely sure about how this works yet.
+ * @param fullType The primary type of the object.
+ * @return The group number. This is a number between 1 and 9 (and later
+ * perhaps higher numbers such as 0x40, so do not assume there are no
+ * gaps).
+ */
+ public static int getGroupForPoi(int fullType) {
+ // We group pois based on their type. This may not be the final thoughts on this.
+ int type = MdrUtils.getTypeFromFullType(fullType);
+ int group = 0;
+ if (fullType < 0xf)
+ group = 1;
+ else if (type >= 0x2a && type <= 0x30) {
+ group = type - 0x28;
+ } else if (type == 0x28) {
+ group = 9;
+ }
+ return group;
+ }
+
+ public static boolean canBeIndexed(int fullType) {
+ return getGroupForPoi(fullType) != 0;
+ }
+
+ private static int getTypeFromFullType(int fullType) {
+ if ((fullType & 0xfff00) > 0)
+ return (fullType>>8) & 0xfff;
+ else
+ return fullType & 0xff;
+ }
+
+ /**
+ * Gets the subtype if there is one, else the type.
+ * @param fullType The type in the so-called 'full' format.
+ * @return If there is a subtype, then it is returned. Otherwise the type is returned.
+ */
+ public static int getSubtypeOrTypeFromFullType(int fullType) {
+ return fullType & 0xff;
+ }
+
+ /**
+ * Sort records that are sorted by a name. They appropriate sort order will be used.
+ * @param sort The sort to be applied.
+ * @param list The list to be sorted.
+ * @param <T> One of the Mdr?Record types that need to be sorted on a text field, eg street name.
+ * @return A list of sort keys in the sorted order. The original object is retrieved from the key
+ * by calling getObject().
+ */
+ public static <T extends NamedRecord> List<SortKey<T>> sortList(Sort sort, List<T> list) {
+ List<SortKey<T>> toSort = new ArrayList<SortKey<T>>(list.size());
+ for (T m : list) {
+ SortKey<T> sortKey = sort.createSortKey(m, m.getName(), m.getMapIndex());
+ toSort.add(sortKey);
+ }
+ Collections.sort(toSort);
+ return toSort;
+ }
+
+ /**
+ * The 'natural' type is always a combination of the type and subtype with the type
+ * shifted 5 bits and the sub type in the low 5 bits.
+ *
+ * For various reasons, we use 'fullType' in which the type is shifted up a full byte
+ * or is in the lower byte.
+ *
+ * @param ftype The so-called full type of the object.
+ * @return The natural type as defined above.
+ */
+ public static int fullTypeToNaturalType(int ftype) {
+ int type = getTypeFromFullType(ftype);
+ int sub = 0;
+ if ((ftype & ~0xff) != 0)
+ sub = ftype & 0x1f;
+
+ return type << 5 | sub;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/NamedRecord.java b/src/uk/me/parabola/imgfmt/app/mdr/NamedRecord.java
new file mode 100644
index 0000000..fb83aa2
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/NamedRecord.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.imgfmt.app.mdr;
+
+/**
+ * Marks a record that has a name.
+ */
+public interface NamedRecord {
+ public int getMapIndex();
+ public String getName();
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/PrefixIndex.java b/src/uk/me/parabola/imgfmt/app/mdr/PrefixIndex.java
new file mode 100644
index 0000000..7cf0218
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/PrefixIndex.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.imgfmt.app.mdr;
+
+import java.nio.charset.Charset;
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+
+/**
+ * Holds an index of name prefixes to record numbers.
+ *
+ * Extends MdrSection, although is sometimes a subsection, not an actual section.
+ *
+ * @author Steve Ratcliffe
+ */
+public class PrefixIndex extends MdrSection {
+ private final int prefixLength;
+ private int maxIndex;
+
+ // We use mdr8record for all similar indexes.
+ private final List<Mdr8Record> index = new ArrayList<Mdr8Record>();
+
+ /**
+ * Sets the config and the prefix length for this index.
+ *
+ * Prefix length may differ depending on the amount of data, so will have
+ * to deal with that when it happens.
+ *
+ * @param config Configuration for sorting methods.
+ * @param prefixLength The prefix length for this index.
+ */
+ public PrefixIndex(MdrConfig config, int prefixLength) {
+ setConfig(config);
+ this.prefixLength = prefixLength;
+ }
+
+ /**
+ * We can create an index for any type that has a name.
+ * @param list A list of items that have a name.
+ */
+ public void createFromList(List<? extends NamedRecord> list, boolean grouped) {
+ maxIndex = list.size();
+
+ // Prefixes are equal based on the primary unaccented character, so
+ // we need to use the collator to test for equality and not equals().
+ Sort sort = getConfig().getSort();
+ Collator collator = sort.getCollator();
+ collator.setStrength(Collator.PRIMARY);
+
+ String lastCountryName = null;
+ String lastPrefix = "";
+ int inRecord = 0; // record number of the input list
+ int outRecord = 0; // record number of the index
+ for (NamedRecord r : list) {
+ inRecord++;
+
+ String prefix = getPrefix(r.getName());
+ if (collator.compare(prefix, lastPrefix) != 0) {
+ outRecord++;
+
+ Mdr8Record ind = new Mdr8Record();
+ ind.setPrefix(prefix);
+ ind.setRecordNumber(inRecord);
+ index.add(ind);
+
+ lastPrefix = prefix;
+
+ if (grouped) {
+ // Peek into the real type to support the mdr17 feature of indexes sorted on country.
+ Mdr5Record city = ((Mdr7Record) r).getCity();
+ if (city != null) {
+ String countryName = city.getCountryName();
+ if (!countryName.equals(lastCountryName)) {
+ city.getMdrCountry().getMdr29().setMdr17(outRecord);
+ lastCountryName = countryName;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void createFromList(List<? extends NamedRecord> list) {
+ createFromList(list, false);
+ }
+
+ /**
+ * Write the section or subsection.
+ */
+ public void writeSectData(ImgFileWriter writer) {
+ int size = numberToPointerSize(maxIndex);
+ Charset charset = getConfig().getSort().getCharset();
+ for (Mdr8Record s : index) {
+ writer.put(s.getPrefix().getBytes(charset), 0, prefixLength);
+ putN(writer, size, s.getRecordNumber());
+ }
+ }
+
+ public int getItemSize() {
+ return prefixLength + numberToPointerSize(maxIndex);
+ }
+
+ protected int numberOfItems() {
+ return index.size();
+ }
+
+ /**
+ * Get the prefix of the name at the given record.
+ * If the name is shorter than the prefix length, then it padded with nul characters.
+ * So it can be longer than the input string.
+ *
+ * @param in The name to truncate.
+ * @return A string prefixLength characters long, consisting of the initial
+ * prefix of name and padded with nulls if necessary to make up the length.
+ */
+ private String getPrefix(String in) {
+ String name = Label.stripGarminCodes(in);
+ if (prefixLength > name.length()) {
+ StringBuilder sb = new StringBuilder(name);
+ while (sb.length() < prefixLength)
+ sb.append('\0');
+ return sb.toString();
+ }
+ return name.substring(0, prefixLength);
+ }
+
+ public int getPrefixLength() {
+ return prefixLength;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/RecordBase.java b/src/uk/me/parabola/imgfmt/app/mdr/RecordBase.java
new file mode 100644
index 0000000..df3a23a
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/RecordBase.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.mdr;
+
+/**
+ * Records that belong to a particular map should extend this class.
+ * Otherwise they can extend ConfigBase.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class RecordBase {
+ private short mapIndex;
+
+ public int getMapIndex() {
+ return mapIndex;
+ }
+
+ public void setMapIndex(int mapIndex) {
+ this.mapIndex = (short) mapIndex;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/mdr/package.html b/src/uk/me/parabola/imgfmt/app/mdr/package.html
new file mode 100644
index 0000000..655ac38
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/mdr/package.html
@@ -0,0 +1,16 @@
+<body>
+<h2>Overview</h2>
+<p>This package creates the MDR file.
+
+<p>There are many, many possible sections in the file. We will attempt
+ to find the minimum number required to make something work.
+
+<h2>Sections to be implemented first</h2>
+<p>Use a header of size 286.
+ This gives us the possibility of the first 19 sections.
+<p>
+ Initial sections to implement: 1, 4, 5, 6, 7, 11, 15.
+
+ Of these 4 is not known and only some subsection of MDR 1 are
+ also not known.
+</body>
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/app/net/NETFile.java b/src/uk/me/parabola/imgfmt/app/net/NETFile.java
new file mode 100644
index 0000000..53c422b
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/NETFile.java
@@ -0,0 +1,304 @@
+/*
+ * 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: Jan 5, 2008
+ */
+package uk.me.parabola.imgfmt.app.net;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.BufferedImgFileWriter;
+import uk.me.parabola.imgfmt.app.ImgFile;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.lbl.City;
+import uk.me.parabola.imgfmt.app.srt.IntegerSortKey;
+import uk.me.parabola.imgfmt.app.srt.MultiSortKey;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+
+/**
+ * The NET file. This consists of information about roads. It is not clear
+ * what this file brings on its own (without NOD) but may allow some better
+ * searching, street addresses etc.
+ *
+ * @author Steve Ratcliffe
+ */
+public class NETFile extends ImgFile {
+ private final NETHeader netHeader = new NETHeader();
+ private List<RoadDef> roads;
+ private Sort sort;
+
+ public NETFile(ImgChannel chan) {
+ setHeader(netHeader);
+ setWriter(new BufferedImgFileWriter(chan));
+ position(NETHeader.HEADER_LEN);
+ }
+
+ /**
+ * Write out NET1.
+ * @param numCities The number of cities in the map. Needed for the size of the written fields.
+ * @param numZips The number of zips in the map. Needed for the size of the written fields.
+ */
+ public void write(int numCities, int numZips) {
+ // Write out the actual file body.
+ ImgFileWriter writer = netHeader.makeRoadWriter(getWriter());
+ try {
+ for (RoadDef rd : roads)
+ rd.writeNet1(writer, numCities, numZips);
+
+ } finally {
+ Utils.closeFile(writer);
+ }
+ }
+
+ /**
+ * Final writing out of net sections.
+ *
+ * We patch the NET offsets into the RGN file and create the sorted roads section.
+ *
+ * @param rgn The region file, this has to be patched with the calculated net offsets.
+ */
+ public void writePost(ImgFileWriter rgn) {
+ for (RoadDef rd : roads)
+ rd.writeRgnOffsets(rgn);
+
+ ImgFileWriter writer = netHeader.makeSortedRoadWriter(getWriter());
+ try {
+ List<LabeledRoadDef> labeledRoadDefs = sortRoads();
+ for (LabeledRoadDef labeledRoadDef : labeledRoadDefs)
+ labeledRoadDef.roadDef.putSortedRoadEntry(writer, labeledRoadDef.label);
+ } finally {
+ Utils.closeFile(writer);
+ }
+
+ getHeader().writeHeader(getWriter());
+ }
+
+ /**
+ * Sort the roads by name and remove duplicates.
+ *
+ * We want a list of roads such that every entry in the list is a different road. Since in osm
+ * roads are frequently chopped into small pieces we have to remove the duplicates.
+ * This doesn't have to be perfect, it needs to be useful when searching for roads.
+ *
+ * So we have a separate entry if the road is in a different city. This would probably be enough
+ * except that associating streets with cities is not always very good in OSM. So I also create an
+ * extra entry for each subdivision. Finally there a search for disconnected roads within the subdivision
+ * with the same name.
+ *
+ * Performance note: The previous implementation was very, very slow when there were a large number
+ * of roads with the same name. Although this was an unusual situation, when it happened it appears
+ * that mkgmap has hung. This implementation takes a fraction of a second even for large numbers of
+ * same named roads.
+ *
+ * @return A sorted list of road labels that identify all the different roads.
+ */
+ private List<LabeledRoadDef> sortRoads() {
+ List<SortKey<LabeledRoadDef>> sortKeys = new ArrayList<SortKey<LabeledRoadDef>>(roads.size());
+ Map<String, byte[]> cache = new HashMap<String, byte[]>();
+
+ for (RoadDef rd : roads) {
+ Label[] labels = rd.getLabels();
+ for (int i = 0; i < labels.length && labels[i] != null; ++i) {
+ Label label = labels[i];
+ if (label.getLength() == 0)
+ continue;
+
+ // Sort by name, city, region/country and subdivision number.
+ LabeledRoadDef lrd = new LabeledRoadDef(label, rd);
+ SortKey<LabeledRoadDef> nameKey = sort.createSortKey(lrd, label.getText(), 0, cache);
+
+ // If there is a city add it to the sort.
+ City city = rd.getCity();
+ SortKey<LabeledRoadDef> cityKey;
+ if (city != null) {
+ int region = city.getRegionNumber();
+ int country = city.getCountryNumber();
+ cityKey = sort.createSortKey(null, city.getName(), (region & 0xffff) << 16 | (country & 0xffff), cache);
+ } else {
+ cityKey = sort.createSortKey(null, "", 0, cache);
+ }
+
+ SortKey<LabeledRoadDef> sortKey = new MultiSortKey<LabeledRoadDef>(nameKey, cityKey,
+ new IntegerSortKey<LabeledRoadDef>(null, rd.getStartSubdivNumber(), 0));
+ sortKeys.add(sortKey);
+ }
+ }
+
+ Collections.sort(sortKeys);
+
+ List<LabeledRoadDef> out = new ArrayList<LabeledRoadDef>(sortKeys.size());
+
+ String lastName = null;
+ City lastCity = null;
+ List<LabeledRoadDef> dupes = new ArrayList<LabeledRoadDef>();
+
+ // Since they are sorted we can easily remove the duplicates.
+ // The duplicates are saved to the dupes list.
+ for (SortKey<LabeledRoadDef> key : sortKeys) {
+ LabeledRoadDef lrd = key.getObject();
+
+ String name = lrd.label.getText();
+ RoadDef road = lrd.roadDef;
+ City city = road.getCity();
+
+ if (road.hasHouseNumbers() || !name.equals(lastName) || city != lastCity) {
+
+ // process any previously collected duplicate road names and reset.
+ addDisconnected(dupes, out);
+ dupes = new ArrayList<LabeledRoadDef>();
+
+ lastName = name;
+ lastCity = city;
+ }
+ dupes.add(lrd);
+ }
+
+ // Finish off the final set of duplicates.
+ addDisconnected(dupes, out);
+
+ return out;
+ }
+
+ /**
+ * Take a set of roads with the same name/city etc and find sets of roads that do not
+ * connect with each other. One of the members of each set is added to the road list.
+ *
+ * @param in A list of duplicate roads.
+ * @param out The list of sorted roads. Any new road is added to this.
+ */
+ private void addDisconnected(List<LabeledRoadDef> in, List<LabeledRoadDef> out) {
+ // switch out to different routines depending on the input size. A normal number of
+ // roads with the same name in the same city is a few tens.
+ if (in.size() > 200) {
+ addDisconnectedLarge(in, out);
+ } else {
+ addDisconnectedSmall(in, out);
+ }
+ }
+
+ /**
+ * Split the input set of roads into disconnected groups and output one member from each group.
+ *
+ * This is done in an accurate manner which is slow for large numbers (eg thousands) of items in the
+ * input.
+ *
+ * @param in Input set of roads with the same name.
+ * @param out List to add the discovered groups.
+ */
+ private void addDisconnectedSmall(List<LabeledRoadDef> in, List<LabeledRoadDef> out) {
+ // Each road starts out with a different group number
+ int[] groups = new int[in.size()];
+ for (int i = 0; i < groups.length; i++)
+ groups[i] = i;
+
+ // Go through pairs of roads, any that are connected we mark with the same (lowest) group number.
+ boolean done;
+ do {
+ done = true;
+ for (int current = 0; current < groups.length; current++) {
+ RoadDef first = in.get(current).roadDef;
+
+ for (int i = current; i < groups.length; i++) {
+ // If the groups are already the same, then no need to test
+ if (groups[current] == groups[i])
+ continue;
+
+ if (first.connectedTo(in.get(i).roadDef)) {
+ groups[current] = groups[i] = Math.min(groups[current], groups[i]);
+ done = false;
+ }
+ }
+ }
+ } while (!done);
+
+ // Output the first road in each group
+ int last = -1;
+ for (int i = 0; i < groups.length; i++) {
+ if (groups[i] > last) {
+ LabeledRoadDef lrd = in.get(i);
+ out.add(lrd);
+ last = groups[i];
+ }
+ }
+ }
+
+ /**
+ * Split the input set of roads into disconnected groups and output one member from each group.
+ *
+ * This is an modified algorithm for large numbers in the input set (eg thousands).
+ * First sort into groups by subdivision and then call {@link #addDisconnectedSmall} on each
+ * one. Since roads in the same subdivision are near each other this finds most connected roads, but
+ * since there is a maximum number of roads in a subdivision, the test can be done very quickly.
+ * You will get a few extra duplicate entries in the index.
+ *
+ * In normal cases this routine gives almost the same results as {@link #addDisconnectedSmall}.
+ *
+ * @param in Input set of roads with the same name.
+ * @param out List to add the discovered groups.
+ */
+ private void addDisconnectedLarge(List<LabeledRoadDef> in, List<LabeledRoadDef> out) {
+ Collections.sort(in, new Comparator<LabeledRoadDef>() {
+ public int compare(LabeledRoadDef o1, LabeledRoadDef o2) {
+ Integer i1 = o1.roadDef.getStartSubdivNumber();
+ Integer i2 = o2.roadDef.getStartSubdivNumber();
+ return i1.compareTo(i2);
+ }
+ });
+
+ int lastDiv = 0;
+ List<LabeledRoadDef> dupes = new ArrayList<LabeledRoadDef>();
+ for (LabeledRoadDef lrd : in) {
+ int sd = lrd.roadDef.getStartSubdivNumber();
+ if (sd != lastDiv) {
+ addDisconnectedSmall(dupes, out);
+ dupes = new ArrayList<LabeledRoadDef>();
+ lastDiv = sd;
+ }
+ dupes.add(lrd);
+ }
+
+ addDisconnectedSmall(dupes, out);
+ }
+
+ public void setNetwork(List<RoadDef> roads) {
+ this.roads = roads;
+ }
+
+ public void setSort(Sort sort) {
+ this.sort = sort;
+ }
+
+ /**
+ * A road can have several names. Keep an association between a road def
+ * and one of its names.
+ */
+ class LabeledRoadDef {
+ private final Label label;
+ private final RoadDef roadDef;
+
+ LabeledRoadDef(Label label, RoadDef roadDef) {
+ this.label = label;
+ this.roadDef = roadDef;
+ }
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/NETFileReader.java b/src/uk/me/parabola/imgfmt/app/net/NETFileReader.java
new file mode 100644
index 0000000..bd93449
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/NETFileReader.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.net;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.app.BufferedImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgFile;
+import uk.me.parabola.imgfmt.app.ImgFileReader;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.lbl.City;
+import uk.me.parabola.imgfmt.app.lbl.LBLFileReader;
+import uk.me.parabola.imgfmt.app.lbl.Zip;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+
+/**
+ * Read the NET file.
+ */
+public class NETFileReader extends ImgFile {
+ private final NETHeader netHeader = new NETHeader();
+
+ // To begin with we only need LBL offsets.
+ private final Map<Integer, Integer> offsetLabelMap = new HashMap<Integer, Integer>();
+ private List<Integer> offsets;
+
+ private List<City> cities;
+ private int citySize;
+
+ private List<Zip> zips;
+ private int zipSize;
+ private LBLFileReader labels;
+
+ public NETFileReader(ImgChannel chan) {
+ setHeader(netHeader);
+
+ setReader(new BufferedImgFileReader(chan));
+ netHeader.readHeader(getReader());
+
+ readLabelOffsets();
+ }
+
+ /**
+ * Get the label offset, given the NET offset.
+ * @param netOffset An offset into NET 1, as found in the road entries in
+ * RGN for example.
+ * @return The offset into LBL as found in NET 1.
+ */
+ public int getLabelOffset(int netOffset) {
+ Integer off = offsetLabelMap.get(netOffset);
+ if (off == null)
+ return 0;
+ else
+ return off;
+ }
+
+ /**
+ * Get the list of roads from the net section.
+ *
+ * Saving the bare minimum that is needed, please improve.
+ * @return A list of RoadDefs. Note that currently not everything is
+ * populated in the road def so it can't be written out as is.
+ */
+ public List<RoadDef> getRoads() {
+ ImgFileReader reader = getReader();
+ int start = netHeader.getRoadDefinitionsStart();
+
+ List<RoadDef> roads = new ArrayList<RoadDef>();
+ int record = 0;
+ for (int off : offsets) {
+ reader.position(start + off);
+
+ RoadDef road = new RoadDef(++record, off, null);
+ readLabels(reader, road);
+ byte netFlags = reader.get();
+ /*int len =*/ reader.getu3();
+
+ int[] counts = new int[24];
+ int level = 0;
+ while (level < 24) {
+ int n = reader.get();
+ counts[level++] = (n & 0x7f);
+ if ((n & 0x80) != 0)
+ break;
+ }
+
+ for (int i = 0; i < level; i++) {
+ int c = counts[i];
+ for (int j = 0; j < c; j++) {
+ /*byte b =*/ reader.get();
+ /*char sub =*/ reader.getChar();
+ }
+ }
+
+ if ((netFlags & RoadDef.NET_FLAG_ADDRINFO) != 0) {
+ char flags2 = reader.getChar();
+
+ int zipFlag = (flags2 >> 10) & 0x3;
+ int cityFlag = (flags2 >> 12) & 0x3;
+ int numberFlag = (flags2 >> 14) & 0x3;
+
+ road.setZip(fetchZipCity(reader, zipFlag, zips, zipSize));
+ road.setCity(fetchZipCity(reader, cityFlag, cities, citySize));
+
+ fetchNumber(reader, numberFlag);
+ }
+
+ if ((netFlags & RoadDef.NET_FLAG_NODINFO) != 0) {
+ int nodFlags = reader.get();
+ int nbytes = nodFlags & 0x3;
+ if (nbytes > 0) {
+ /*int nod = */reader.getUint(nbytes+1);
+ }
+ }
+
+ roads.add(road);
+ }
+ return roads;
+ }
+
+ /**
+ * Fetch a zip or a city.
+ * @param <T> Can be city or zip.
+ * @return The found City or Zip.
+ */
+ private <T> T fetchZipCity(ImgFileReader reader, int flag, List<T> list, int size) {
+ T item = null;
+ if (flag == 2) {
+ // fetch city/zip index
+ int ind = (size == 2)? reader.getChar(): (reader.get() & 0xff);
+ if (ind != 0)
+ item = list.get(ind-1);
+ } else if (flag == 3) {
+ // there is no item
+ } else if (flag == 0) {
+ // Skip over these
+ int n = reader.get();
+ reader.get(n);
+ } else if (flag == 1) {
+ // Skip over these
+ int n = reader.getChar();
+ reader.get(n);
+ } else {
+ assert false : "flag is " + flag;
+ }
+ return item;
+ }
+
+ /**
+ * Fetch a block of numbers.
+ * @param reader The reader.
+ * @param numberFlag The flag that says how the block is formatted.
+ */
+ private void fetchNumber(ImgFileReader reader, int numberFlag) {
+ int n = 0;
+ if (numberFlag == 0) {
+ n = reader.get();
+ } else if (numberFlag == 1) {
+ n = reader.getChar();
+ } else if (numberFlag == 3) {
+ // There is no block
+ return;
+ } else {
+ // Possible but don't know what to do in this context
+ assert false;
+ }
+ if (n > 0)
+ reader.get(n);
+ }
+
+ private void readLabels(ImgFileReader reader, RoadDef road) {
+ for (int i = 0; i < 4; i++) {
+ int lab = reader.getu3();
+ Label label = labels.fetchLabel(lab & 0x7fffff);
+ road.addLabel(label);
+ if ((lab & 0x800000) != 0)
+ break;
+ }
+ }
+
+ /**
+ * The first field in NET 1 is a label offset in LBL. Currently we
+ * are only interested in that to convert between a NET 1 offset and
+ * a LBL offset.
+ */
+ private void readLabelOffsets() {
+ ImgFileReader reader = getReader();
+ offsets = readOffsets();
+ int start = netHeader.getRoadDefinitionsStart();
+ for (int off : offsets) {
+ reader.position(start + off);
+ int labelOffset = reader.getu3();
+ // TODO what if top bit is not set?, there can be more than one name and we will miss them
+ offsetLabelMap.put(off, labelOffset & 0x7fffff);
+ }
+ }
+
+ /**
+ * NET 3 contains a list of all the NET 1 record start positions. They
+ * are in alphabetical order of name. So read them in and sort into
+ * memory address order.
+ * @return A list of start offsets in NET 1, sorted by increasing offset.
+ */
+ private List<Integer> readOffsets() {
+ int start = netHeader.getSortedRoadsStart();
+ int end = netHeader.getSortedRoadsEnd();
+ ImgFileReader reader = getReader();
+ reader.position(start);
+
+ List<Integer> offsets = new ArrayList<Integer>();
+ while (reader.position() < end) {
+ int net1 = reader.getu3();
+
+ // The offset is stored in the bottom 22 bits. The top 2 bits are an index into the list
+ // of lbl pointers in the net1 entry. Since we pick up all the labels at a particular net1
+ // entry we only need one of the offsets so pick the first one.
+ int idx = (net1 >> 22) & 0x3;
+ if (idx == 0)
+ offsets.add(net1 & 0x3fffff);
+ }
+
+ // Sort in address order in the hope of speeding up reading.
+ Collections.sort(offsets);
+ return offsets;
+ }
+
+ public void setCities(List<City> cities) {
+ this.cities = cities;
+ this.citySize = cities.size() > 255? 2: 1;
+ }
+
+ public void setZips(List<Zip> zips) {
+ this.zips = zips;
+ this.zipSize = zips.size() > 255? 2: 1;
+ }
+
+ public void setLabels(LBLFileReader labels) {
+ this.labels = labels;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/NETHeader.java b/src/uk/me/parabola/imgfmt/app/net/NETHeader.java
new file mode 100644
index 0000000..351acd0
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/NETHeader.java
@@ -0,0 +1,111 @@
+/*
+ * 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: Jan 5, 2008
+ */
+package uk.me.parabola.imgfmt.app.net;
+
+import uk.me.parabola.imgfmt.ReadFailedException;
+import uk.me.parabola.imgfmt.app.CommonHeader;
+import uk.me.parabola.imgfmt.app.ImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Section;
+import uk.me.parabola.imgfmt.app.SectionWriter;
+
+/**
+ * The header of the NET file.
+ *
+ * @author Steve Ratcliffe
+ */
+public class NETHeader extends CommonHeader {
+ public static final int HEADER_LEN = 55; // Other lengths are possible
+
+ private static final char SORTED_ROAD_RECSIZE = 3;
+
+ private final Section roadDefinitions = new Section();
+ private final Section segmentedRoads = new Section(roadDefinitions);
+ private final Section sortedRoads = new Section(segmentedRoads, SORTED_ROAD_RECSIZE);
+
+ private byte roadShift;
+ private byte segmentShift;
+
+ public NETHeader() {
+ super(HEADER_LEN, "GARMIN NET");
+ }
+
+ /**
+ * Read the rest of the header. Specific to the given file. It is guaranteed
+ * that the file position will be set to the correct place before this is
+ * called.
+ *
+ * @param reader The header is read from here.
+ */
+ protected void readFileHeader(ImgFileReader reader) throws ReadFailedException {
+ roadDefinitions.readSectionInfo(reader, false);
+ roadShift = reader.get();
+
+ segmentedRoads.readSectionInfo(reader, false);
+ segmentShift = reader.get();
+
+ sortedRoads.readSectionInfo(reader, true);
+
+ reader.getInt();
+ reader.get();
+ reader.get();
+ }
+
+ /**
+ * Write the rest of the header. It is guaranteed that the writer will be set
+ * to the correct position before calling.
+ *
+ * @param writer The header is written here.
+ */
+ protected void writeFileHeader(ImgFileWriter writer) {
+ roadDefinitions.writeSectionInfo(writer);
+
+ writer.put(roadShift); // offset multiplier
+
+ segmentedRoads.writeSectionInfo(writer);
+
+ writer.put(segmentShift); // offset multiplier
+
+ sortedRoads.writeSectionInfo(writer);
+
+ writer.putInt(0);
+ writer.put((byte) 1);
+ writer.put((byte) 0);
+ }
+
+ ImgFileWriter makeRoadWriter(ImgFileWriter writer) {
+ roadDefinitions.setPosition(writer.position());
+ return new SectionWriter(writer, roadDefinitions);
+ }
+
+ ImgFileWriter makeSortedRoadWriter(ImgFileWriter writer) {
+ sortedRoads.setPosition(writer.position());
+ return new SectionWriter(writer, sortedRoads);
+ }
+
+ public int getRoadDefinitionsStart() {
+ return roadDefinitions.getPosition();
+ }
+
+ public int getSortedRoadsStart() {
+ return sortedRoads.getPosition();
+ }
+
+ public int getSortedRoadsEnd() {
+ return sortedRoads.getEndPos();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/NOD1Part.java b/src/uk/me/parabola/imgfmt/app/net/NOD1Part.java
new file mode 100644
index 0000000..729d761
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/NOD1Part.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2008 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: Robert Vollmert
+ * Create date: 02-Dec-2008
+ */
+package uk.me.parabola.imgfmt.app.net;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+
+/**
+ * This is a component of the RoadNetwork.
+ *
+ * Keeps track of outside neighbours and allows subdivision
+ * to satisfy NOD1 constraints.
+ *
+ * The approach to subdivision is to tile the map into RouteCenters.
+ * One could imagine that overlapping RouteCenters would be an option,
+ * say by splitting largely independent networks (motorways, footways).
+ *
+ * Could be rolled into RouteCenter.
+ */
+public class NOD1Part {
+ private static final Logger log = Logger.getLogger(NOD1Part.class);
+
+ /*
+ * Constraints:
+ *
+ * 1. Nodes section smaller than about 0x4000, which gives
+ * a bound on the number of nodes.
+ * 2. At most 0x100 entries in Table A. This gives a bound
+ * on the number of (forward) arcs meeting this
+ * RouteCenter.
+ * 3. At most 0x40 entries in Table B. This gives a bound
+ * on the number of neighboring nodes.
+ * 4. Absolute values of coordinate offsets at most 0x8000,
+ * which translates to about 0.7 degrees, so bounding
+ * box should be at most 1.4 x 1.4 degrees assuming
+ * the reference is in the middle. (With small offsets,
+ * this would be 0.08 x 0.08 degrees.)
+ * 5. Absolute values of relative NOD1 offsets at most
+ * 0x2000, which limits the nodes section to 0x2000
+ * unless we take care to order the nodes nicely.
+ * 6. Distance between nodes and start of tables must
+ * fit in a char for writing Table C. So nodes
+ * section smaller than 0x10000.
+ */
+
+ // maximal width and height of the bounding box, since
+ // NOD 1 coordinate offsets are at most 16 bit wide.
+ private static final int MAX_SIZE_UNSAFE = 1 << 16;
+// private static final int MAX_SIZE = MAX_SIZE_UNSAFE / 2;
+ private static final int MAX_SIZE = MAX_SIZE_UNSAFE - 0x800;
+
+ // Table A has at most 0x100 entries
+ private static final int MAX_TABA_UNSAFE = 0x100;
+// private static final int MAX_TABA = MAX_TABA_UNSAFE / 2;
+ private static final int MAX_TABA = MAX_TABA_UNSAFE - 0x8;
+
+ // Table B has at most 0x100 entries
+ private static final int MAX_TABB_UNSAFE = 0x100;
+// private static final int MAX_TABB = MAX_TABB_UNSAFE / 2;
+ private static final int MAX_TABB = MAX_TABB_UNSAFE - 0x2;
+
+ // Nodes size is max 0x2000 to cope with signed 14 bit node offsets
+ private static final int MAX_NODES_SIZE = 0x2000;
+ private int nodesSize;
+
+ public class BBox {
+ int maxLat, minLat, maxLon, minLon;
+ boolean empty;
+
+ BBox() {
+ empty = true;
+ }
+
+ BBox(Coord co) {
+ empty = false;
+ int lat = co.getLatitude();
+ int lon = co.getLongitude();
+ minLat = lat;
+ maxLat = lat+1;
+ minLon = lon;
+ maxLon = lon+1;
+ }
+
+ BBox(int minLat, int maxLat, int minLon, int maxLon) {
+ empty = false;
+ this.minLat = minLat;
+ this.maxLat = maxLat;
+ this.minLon = minLon;
+ this.maxLon = maxLon;
+ }
+
+ Area toArea() {
+ return new Area(minLat, minLon, maxLat, maxLon);
+ }
+
+ boolean contains(BBox bbox) {
+ return minLat <= bbox.minLat && bbox.maxLat <= maxLat
+ && minLon <= bbox.minLon && bbox.maxLon <= maxLon;
+ }
+
+ boolean contains(Coord co) {
+ return contains(new BBox(co));
+ }
+
+ void extend(BBox bbox) {
+ if (bbox.empty)
+ return;
+ if (empty) {
+ empty = false;
+ minLat = bbox.minLat;
+ maxLat = bbox.maxLat;
+ minLon = bbox.minLon;
+ maxLon = bbox.maxLon;
+ } else {
+ minLat = Math.min(minLat, bbox.minLat);
+ maxLat = Math.max(maxLat, bbox.maxLat);
+ minLon = Math.min(minLon, bbox.minLon);
+ maxLon = Math.max(maxLon, bbox.maxLon);
+ }
+ }
+
+ void extend(Coord co) {
+ extend(new BBox(co));
+ }
+
+ BBox[] splitLat() {
+ BBox[] ret = new BBox[2];
+ int midLat = (minLat + maxLat) / 2;
+ ret[0] = new BBox(minLat, midLat, minLon, maxLon);
+ ret[1] = new BBox(midLat, maxLat, minLon, maxLon);
+ return ret;
+ }
+
+ BBox[] splitLon() {
+ BBox[] ret = new BBox[2];
+ int midLon = (minLon + maxLon) / 2;
+ ret[0] = new BBox(minLat, maxLat, minLon, midLon);
+ ret[1] = new BBox(minLat, maxLat, midLon, maxLon);
+ return ret;
+ }
+
+ int getWidth() {
+ return maxLon - minLon;
+ }
+
+ int getHeight() {
+ return maxLat - minLat;
+ }
+
+ int getMaxDimension() {
+ return Math.max(getWidth(), getHeight());
+ }
+
+ public String toString() {
+ return "BBox[" + new Coord(minLat,minLon).toDegreeString()
+ + ", " + new Coord(maxLat,maxLon).toDegreeString() + "]";
+ }
+ }
+
+ // The area we are supposed to cover.
+ private final BBox bbox;
+ // The area that actually has nodes.
+ private final BBox bboxActual = new BBox();
+
+ private final List<RouteNode> nodes = new ArrayList<RouteNode>();
+ private final TableA tabA = new TableA();
+ private final TableB tabB = new TableB();
+
+ /**
+ * Create an unbounded NOD1Part.
+ *
+ * All nodes will be accepted by addNode and
+ * all arcs will be considered internal.
+ */
+ public NOD1Part() {
+ log.info("creating new unbounded NOD1Part");
+ this.bbox = null;
+ }
+
+ /**
+ * Create a bounded NOD1Part.
+ *
+ * The bounding box is used to decide which arcs
+ * are internal.
+ */
+ private NOD1Part(BBox bbox) {
+ log.info("creating new NOD1Part:", bbox);
+ this.bbox = bbox;
+ }
+
+ /**
+ * Add a node to this part.
+ *
+ * The node is used to populate the tables. If an
+ * arc points outside the bbox, we know it's not
+ * an internal arc. It might still turn into an
+ * external arc at a deeper level of recursion.
+ */
+ public void addNode(RouteNode node) {
+ assert bbox == null || bbox.contains(node.getCoord())
+ : "trying to add out-of-bounds node: " + node;
+
+ bboxActual.extend(node.getCoord());
+ nodes.add(node);
+ for (RouteArc arc : node.arcsIteration()) {
+ tabA.addArc(arc);
+ RouteNode dest = arc.getDest();
+ if (bbox != null && !bbox.contains(dest.getCoord())) {
+ arc.setInternal(false);
+ tabB.addNode(dest);
+ }
+ }
+ nodesSize += node.boundSize();
+ }
+
+ /**
+ * Subdivide this part recursively until it satisfies the constraints.
+ */
+ public List<RouteCenter> subdivide() {
+ return subdivideHelper(0);
+ }
+
+ /**
+ * Subdivide this part recursively until it satisfies the constraints.
+ */
+ protected List<RouteCenter> subdivideHelper(int depth) {
+ List<RouteCenter> centers = new LinkedList<RouteCenter>();
+
+ if (satisfiesConstraints()) {
+ centers.add(this.toRouteCenter());
+ return centers;
+ }
+
+ if(depth > 48) {
+ log.error("Region contains too many nodes/arcs (discarding " + nodes.size() + " nodes to be able to continue)");
+ log.error(" Expect the routing to be broken near " + bbox);
+ for (RouteNode node : nodes)
+ node.discard();
+ return centers;
+ }
+
+ log.info("subdividing", bbox, bboxActual);
+ BBox[] split ;
+ if (bboxActual.getWidth() > bboxActual.getHeight())
+ split = bboxActual.splitLon();
+ else
+ split = bboxActual.splitLat();
+
+ NOD1Part[] parts = new NOD1Part[2];
+
+ for (int i = 0; i < split.length; i++)
+ parts[i] = new NOD1Part(split[i]);
+
+ for (RouteNode node : nodes) {
+ int i = 0;
+ while (!split[i].contains(node.getCoord()))
+ i++;
+ parts[i].addNode(node);
+ }
+
+ for (NOD1Part part : parts)
+ if(!part.bboxActual.empty)
+ centers.addAll(part.subdivideHelper(depth + 1));
+
+ return centers;
+ }
+
+ private boolean satisfiesConstraints() {
+ log.debug("constraints:", bboxActual, tabA.size(), tabB.size(), nodesSize);
+ return bboxActual.getMaxDimension() < MAX_SIZE
+ && tabA.size() < MAX_TABA
+ && tabB.size() < MAX_TABB
+ && nodesSize < MAX_NODES_SIZE;
+ }
+
+ /**
+ * Convert to a RouteCenter.
+ *
+ * satisfiesConstraints() should be true for this to
+ * be a legal RouteCenter.
+ */
+ private RouteCenter toRouteCenter() {
+ return new RouteCenter(bboxActual.toArea(), nodes, tabA, tabB);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/NODFile.java b/src/uk/me/parabola/imgfmt/app/net/NODFile.java
new file mode 100644
index 0000000..ed930da
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/NODFile.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2008 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: 06-Jul-2008
+ */
+package uk.me.parabola.imgfmt.app.net;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.BufferedImgFileReader;
+import uk.me.parabola.imgfmt.app.BufferedImgFileWriter;
+import uk.me.parabola.imgfmt.app.ImgFile;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Section;
+import uk.me.parabola.imgfmt.app.SectionWriter;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.log.Logger;
+
+/**
+ * The NOD file that contains routing information.
+ *
+ * NOD1 contains several groups of routing nodes.
+ * NOD2 contains road data with links into NOD1.
+ *
+ * NOD1 contains links back to NET (and NET contains links to NOD2). So there
+ * is a loop and we have to write one section first, retaining the offsets
+ * and then go back and fill in offsets that were found later.
+ *
+ * I'm choosing to this with Table A, as the records are fixed size and so
+ * we can write them blank the first time and then go back and fix them
+ * up, once the NET offsets are known.
+ *
+ * So we are writing NOD first before NET and NOD1 before NOD2. Once NET is
+ * written then go back to Table A and fix the label offsets in RGN.
+ *
+ * @author Steve Ratcliffe
+ */
+public class NODFile extends ImgFile {
+ private static final Logger log = Logger.getLogger(NODFile.class);
+
+ private final NODHeader nodHeader = new NODHeader();
+
+ private List<RouteCenter> centers = new ArrayList<RouteCenter>();
+ private List<RoadDef> roads = new ArrayList<RoadDef>();
+ private List<RouteNode> boundary = new ArrayList<RouteNode>();
+
+ public NODFile(ImgChannel chan, boolean write) {
+ setHeader(nodHeader);
+ if (write) {
+ setWriter(new BufferedImgFileWriter(chan));
+ position(NODHeader.HEADER_LEN);
+ } else {
+ setReader(new BufferedImgFileReader(chan));
+ nodHeader.readHeader(getReader());
+ }
+ }
+
+ public void write() {
+ writeNodes();
+ writeRoadData();
+ writeBoundary();
+ }
+
+ public void writePost() {
+ ImgFileWriter writer = new SectionWriter(getWriter(), nodHeader.getNodeSection());
+
+ for (RouteCenter rc : centers) {
+ rc.writePost(writer);
+ }
+ // Refresh the header
+ position(0);
+ getHeader().writeHeader(getWriter());
+ }
+
+ /**
+ * Write the nodes (NOD 1). This is done first as the offsets into
+ * this section are needed to write NOD2.
+ */
+ private void writeNodes() {
+ ImgFileWriter writer = getWriter();
+ nodHeader.setNodeStart(writer.position());
+
+ Section section = nodHeader.getNodeSection();
+ writer = new SectionWriter(writer, section);
+
+ for (RouteCenter cp : centers)
+ cp.write(writer);
+ nodHeader.setNodeSize(writer.position());
+ log.debug("the nod offset", Integer.toHexString(getWriter().position()));
+ Section.close(writer);
+ }
+
+ /**
+ * Write the road data (NOD2).
+ */
+ private void writeRoadData() {
+ log.info("writeRoadData");
+
+ ImgFileWriter writer = new SectionWriter(getWriter(), nodHeader.getRoadSection());
+
+ boolean debug = log.isDebugEnabled();
+ for (RoadDef rd : roads) {
+ if(debug)
+ log.debug("wrting nod2", writer.position());
+ rd.writeNod2(writer);
+ }
+ if(debug)
+ log.debug("ending nod2", writer.position());
+ nodHeader.setRoadSize(writer.position());
+ }
+
+ /**
+ * Write the boundary node table (NOD3).
+ */
+ private void writeBoundary() {
+ log.info("writeBoundary");
+
+ Collections.sort(boundary);
+
+ ImgFileWriter writer = new SectionWriter(getWriter(), nodHeader.getBoundarySection());
+
+ boolean debug = log.isDebugEnabled();
+ for (RouteNode node : boundary) {
+ if(debug)
+ log.debug("wrting nod3", writer.position());
+ node.writeNod3(writer);
+ }
+ if(debug)
+ log.debug("ending nod3", writer.position());
+ nodHeader.setBoundarySize(writer.position());
+ }
+
+ public void setNetwork(List<RouteCenter> centers, List<RoadDef> roads, List<RouteNode> boundary) {
+ this.centers = centers;
+ this.roads = roads;
+ this.boundary = boundary;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/NODHeader.java b/src/uk/me/parabola/imgfmt/app/net/NODHeader.java
new file mode 100644
index 0000000..3e41d54
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/NODHeader.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2008 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: 06-Jul-2008
+ */
+package uk.me.parabola.imgfmt.app.net;
+
+import uk.me.parabola.imgfmt.ReadFailedException;
+import uk.me.parabola.imgfmt.app.CommonHeader;
+import uk.me.parabola.imgfmt.app.ImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Section;
+
+/**
+ * @author Steve Ratcliffe
+ */
+public class NODHeader extends CommonHeader {
+ public static final int HEADER_LEN = 63;
+
+ static final char DEF_ALIGN = 6;
+ private static final char BOUNDARY_ITEM_SIZE = 9;
+
+ private final Section nodes = new Section();
+ private final Section roads = new Section(nodes);
+ private final Section boundary = new Section(roads, BOUNDARY_ITEM_SIZE);
+
+ private int flags;
+ private int align;
+ private int tableARecordLen;
+
+ /**
+ * The driveOnLeft flag is set via a static method. Using a ThreadLocal
+ * ensures thread safety when using more than one thread.
+ */
+ private static final ThreadLocal<Boolean> driveOnLeft = new ThreadLocal<Boolean>() {
+ protected Boolean initialValue() {
+ return Boolean.FALSE;
+ }
+ };
+
+ public NODHeader() {
+ super(HEADER_LEN, "GARMIN NOD");
+ }
+
+ /**
+ * Read the rest of the header. Specific to the given file. It is guaranteed
+ * that the file position will be set to the correct place before this is
+ * called.
+ *
+ * @param reader The header is read from here.
+ */
+ protected void readFileHeader(ImgFileReader reader) throws ReadFailedException {
+ nodes.readSectionInfo(reader, false);
+ flags = reader.getChar();
+ reader.getChar();
+ align = reader.getChar();
+ tableARecordLen = reader.getChar();
+ roads.readSectionInfo(reader, false);
+ reader.getInt();
+ boundary.readSectionInfo(reader, true);
+ }
+
+ /**
+ * Write the rest of the header. It is guaranteed that the writer will be set
+ * to the correct position before calling.
+ *
+ * @param writer The header is written here.
+ */
+ protected void writeFileHeader(ImgFileWriter writer) {
+ nodes.setPosition(HEADER_LEN);
+ nodes.writeSectionInfo(writer);
+
+ // now sets 0x02 (enable turn restrictions?)
+ int val = 0x27;
+ if(driveOnLeft.get())
+ val |= 0x0300;
+ writer.putInt(val);
+
+ char align = DEF_ALIGN;
+ writer.putChar(align);
+ writer.putChar((char) 5);
+
+ roads.writeSectionInfo(writer);
+ writer.putInt(0);
+
+ boundary.writeSectionInfo(writer);
+ }
+
+ public int getNodeStart() {
+ return nodes.getPosition();
+ }
+
+ public void setNodeStart(int start) {
+ nodes.setPosition(start);
+ }
+
+ public int getNodeSize() {
+ return nodes.getSize();
+ }
+
+ public void setNodeSize(int size) {
+ nodes.setSize(size);
+ }
+
+ public Section getNodeSection() {
+ return nodes;
+ }
+
+ public void setRoadSize(int size) {
+ roads.setSize(size);
+ }
+
+ public Section getRoadSection() {
+ return roads;
+ }
+
+ public void setBoundarySize(int size) {
+ boundary.setSize(size);
+ }
+
+ public Section getBoundarySection() {
+ return boundary;
+ }
+
+ public static void setDriveOnLeft(boolean dol) {
+ driveOnLeft.set(dol);
+ }
+
+ public int getFlags() {
+ return flags;
+ }
+
+ public int getAlign() {
+ return align;
+ }
+
+ public int getTableARecordLen() {
+ return tableARecordLen;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/NumberPreparer.java b/src/uk/me/parabola/imgfmt/app/net/NumberPreparer.java
new file mode 100644
index 0000000..3224841
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/NumberPreparer.java
@@ -0,0 +1,851 @@
+/*
+ * Copyright (C) 2008 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 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.imgfmt.app.net;
+
+import java.util.Iterator;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.BitWriter;
+
+import static uk.me.parabola.imgfmt.app.net.NumberStyle.*;
+
+/**
+ * Class to prepare the bit stream of the house numbering information.
+ *
+ * There are multiple ways to encode the same numbers, the trick is to find a way that is reasonably
+ * small. We recognise a few common cases to reduce the size of the bit stream, but mostly just concentrating
+ * on clarity and correctness. Optimisations only made a few percent difference at most.
+ *
+ * @author Steve Ratcliffe
+ */
+public class NumberPreparer {
+
+ private final List<Numbers> numbers;
+ private boolean valid;
+
+ // The minimum values of the start and end bit widths.
+ private static final int START_WIDTH_MIN = 5;
+ private static final int END_WIDTH_MIN = 2;
+
+ private BitWriter bw;
+ private boolean swappedDefaultStyle;
+
+ public NumberPreparer(List<Numbers> numbers) {
+ this.numbers = numbers;
+ }
+
+ /**
+ * Make the bit stream and return it. This is only done once, if you call this several times
+ * the same bit writer is returned every time.
+ * @return A bit writer containing the computed house number stream.
+ */
+ public BitWriter fetchBitStream() {
+ if (bw != null)
+ return bw;
+
+ int initialValue = setup();
+
+ // Write the bitstream
+ bw = new BitWriter();
+
+ try {
+
+ // Look at the numbers and calculate some optimal values for the bit field widths etc.
+ State state = new GatheringState(initialValue);
+ process(new BitWriter(), state);
+
+ // Write the initial values.
+ writeWidths(state);
+ writeInitialValue(state);
+
+ state = new WritingState(state);
+ process(bw, state);
+
+ // If we get this far and there is something there, the stream might be valid!
+ if (bw.getLength() > 1)
+ valid = true;
+ } catch (Abandon e) {
+ System.out.println(e.getMessage());
+ valid = false;
+ }
+
+ return bw;
+ }
+
+ /**
+ * Do some initial calculation and sanity checking of the numbers that we are to
+ * write.
+ * @return The initial base value that all other values are derived from.
+ */
+ private int setup() {
+ // Should we use the swapped default numbering style EVEN/ODD rather than
+ // ODD/EVEN and the initialValue.
+ for (Iterator<Numbers> iterator = numbers.listIterator(); iterator.hasNext(); ) {
+ Numbers n = iterator.next();
+ if (n.getLeftNumberStyle() == NONE && n.getRightNumberStyle() == NONE)
+ iterator.remove();
+ }
+ if (numbers.isEmpty())
+ throw new Abandon("no numbers");
+
+ Numbers first = numbers.get(0);
+ if (first.getLeftNumberStyle() == EVEN && first.getRightNumberStyle() == ODD)
+ swappedDefaultStyle = true;
+
+ // Calculate the initial value we want to use
+ int initial = 0;
+ if (first.getLeftNumberStyle() != NONE)
+ initial = first.getLeftStart();
+
+ int rightStart = 0;
+ if (first.getRightNumberStyle() != NONE)
+ rightStart = first.getRightStart();
+
+ if (initial == 0)
+ initial = rightStart;
+
+ if (first.getLeftStart() > first.getLeftEnd() || first.getRightStart() > first.getRightEnd())
+ initial = Math.max(initial, rightStart);
+ else if (rightStart > 0)
+ initial = Math.min(initial, rightStart);
+ return initial;
+ }
+
+ /**
+ * Process the list of number ranges and compile them into a bit stream.
+ *
+ * This is done twice, once to calculate the sizes of the bit fields needed, and again
+ * to do the actual writing.
+ *
+ * @param bw The bit stream to write to.
+ * @param state Use to keep track of state during the construction process.
+ */
+ private void process(BitWriter bw, State state) {
+ if (swappedDefaultStyle)
+ state.swapDefaults();
+
+ int lastNode = -1;
+ for (Numbers n : numbers) {
+ if (!n.hasRnodNumber())
+ throw new Abandon("no r node set");
+
+ // See if we need to skip some nodes
+ if (n.getRnodNumber() != lastNode + 1)
+ state.writeSkip(bw, n.getRnodNumber() - lastNode - 2);
+
+ // Normal case write out the next node.
+ state.setTarget(n);
+
+ state.writeNumberingStyle(bw);
+ state.calcNumbers();
+ state.writeBitWidths(bw);
+ state.writeNumbers(bw);
+ state.restoreWriters();
+
+ lastNode = n.getRnodNumber();
+ }
+ }
+
+ /**
+ * The initial base value is written out separately before anything else.
+ * All numbers are derived from differences from this value.
+ * @param state Holds the initial value to write.
+ */
+ private void writeInitialValue(State state) {
+ assert state.initialValue >= 0 : "initial value is not positive: " + state.initialValue;
+ int width = 32 - Integer.numberOfLeadingZeros(state.initialValue);
+ if (width > 20)
+ throw new Abandon("Initial value too large: " + state.initialValue);
+
+ if (width > 5) {
+ bw.put1(false);
+ bw.putn(width - 5, 4);
+ } else {
+ bw.put1(true);
+ width = 5;
+ }
+ bw.putn(state.initialValue, width);
+ }
+
+ /**
+ * Write out a block that describes the number of bits to use. Numbers can be
+ * either all positive or all negative, or they can be signed and each bit field
+ * also has an extra sign bit. This is like how lines are encoded. See the LinePreparer
+ * class.
+ * @param state Holds the width information.
+ */
+ private void writeWidths(State state) {
+ state.getStartWriter().writeFormat();
+ state.getEndWriter().writeFormat();
+ }
+
+ /**
+ * Returns true if the bit stream was calculated on the basis that the initial even/odd defaults
+ * should be swapped.
+ * @return True to signify swapped default, ie bit 0x20 in the net flags should be set.
+ */
+ public boolean getSwapped() {
+ return swappedDefaultStyle;
+ }
+
+ /**
+ * During development, any case that cannot be written correctly is marked invalid so it can
+ * be skipped on output.
+ *
+ * This will probably go away when complete.
+ *
+ * @return True if the preparer believes that the output is valid.
+ */
+ public boolean isValid() {
+ return valid;
+ }
+
+ /**
+ * The current state of the writing process.
+ */
+ static abstract class State {
+
+ protected final Side left = new Side(true);
+ protected final Side right = new Side(false);
+ private int initialValue;
+
+ State() {
+ left.style = ODD;
+ right.style = EVEN;
+ }
+
+ /**
+ * Set the initial value. All numbers are derived from this by adding differences.
+ */
+ public void setInitialValue(int val) {
+ initialValue = val;
+ left.base = val;
+ right.base = val;
+ }
+
+ /**
+ * Set the next number to output. Once the target is set, we then output commands to
+ * transform the current state into the target state.
+ * @param numbers The target numbers.
+ */
+ public void setTarget(Numbers numbers) {
+ left.setTargets(numbers.getLeftNumberStyle(), numbers.getLeftStart(), numbers.getLeftEnd());
+ right.setTargets(numbers.getRightNumberStyle(), numbers.getRightStart(), numbers.getRightEnd());
+ }
+
+ /**
+ * If the target numbering style is different to the current one, then write out
+ * the command to change it.
+ */
+ public void writeNumberingStyle(BitWriter bw) {
+ }
+
+ /**
+ * If we need a larger bit width for this node, then write out a command to
+ * change it. Changes are temporary and it reverts to the default after the
+ * next number output command.
+ */
+ public void writeBitWidths(BitWriter bw) {
+ }
+
+ public void writeSkip(BitWriter bw, int n) {
+ }
+
+ /**
+ * Calculate the number difference to represent the current number range.
+ */
+ public void calcNumbers() {
+ if (left.style == NONE)
+ left.base = right.base;
+
+ equalizeBases();
+
+ left.calc(right);
+ right.calc(left);
+ }
+
+ /**
+ * See if we can set the bases of both sides of the road to be equal. Doesn't seem to be
+ * that useful, but does not cost any bits, as long as doing so doesn't cause you to write
+ * a difference when you wouldn't without.
+ * @return True if the bases have been set equal. There are two cases, the left can be set equal to
+ * the right, or visa versa. The flags on the left/right objects will say which.
+ */
+ private boolean equalizeBases() {
+ left.equalized = right.equalized = false;
+
+ // Don't if runs are in different directions
+ if (left.direction != right.direction) {
+ return false;
+ }
+
+ int diff = left.targetStart - left.base;
+
+ // Do not lose the benefit of a 0 start.
+ if (left.tryStart(left.base))
+ diff = 0;
+
+ if (right.tryStart(left.base + diff)) {
+ left.equalized = true;
+ right.base = left.base;
+ left.startDiff = right.startDiff = diff;
+ return true;
+ }
+
+ diff = right.targetStart - right.base;
+ if (left.tryStart(right.base + diff)) {
+ right.equalized = true;
+ left.base = right.base;
+ left.startDiff = right.startDiff = diff;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Write the bit stream to the given bit writer.
+ *
+ * When this is called, all the calculations as to what is to be done have been made and
+ * it is just a case of translating those into the correct format.
+ *
+ * @param bw Bit writer to use. In the gathering phase this must be a throw away one.
+ */
+ public void writeNumbers(BitWriter bw) {
+ boolean doSingleSide = left.style == NONE || right.style == NONE;
+
+ // Output the command that a number follows.
+ bw.put1(true);
+
+ boolean equalized = false;
+ if (!doSingleSide) {
+ equalized = left.equalized || right.equalized;
+ bw.put1(equalized);
+ if (equalized)
+ bw.put1(left.equalized);
+ }
+
+ if (!doSingleSide) {
+ bw.put1(!right.needOverride(left));
+ }
+
+ Side firstSide = left;
+ if (doSingleSide && left.style == NONE)
+ firstSide = right;
+
+ boolean doStart = firstSide.startDiff != 0;
+ boolean doEnd = firstSide.endDiff != 0;
+ bw.put1(!doStart);
+ bw.put1(!doEnd);
+
+ if (doStart)
+ writeStart(firstSide.startDiff);
+ if (doEnd)
+ writeEnd(firstSide.endDiff);
+
+ firstSide.finish();
+
+ if (doSingleSide) {
+ left.base = right.base = firstSide.base;
+ left.lastEndDiff = right.lastEndDiff = firstSide.lastEndDiff;
+ return;
+ }
+
+ doStart = right.startDiff != 0;
+ doEnd = right.endDiff != 0;
+
+ if (!equalized)
+ bw.put1(!doStart);
+ if (right.needOverride(left))
+ bw.put1(!doEnd);
+
+ if (doStart && !equalized)
+ writeStart(right.startDiff);
+ if (doEnd)
+ writeEnd(right.endDiff);
+
+ right.finish();
+ }
+
+ protected void restoreWriters() {
+ }
+
+ /** Write a start difference */
+ public abstract void writeStart(int diff);
+ /** Write an end difference */
+ public abstract void writeEnd(int diff);
+
+ public abstract VarBitWriter getStartWriter();
+ public abstract VarBitWriter getEndWriter();
+
+ /**
+ * By default the left side of the road is odd numbered and the right even.
+ * Calling this swaps that around. If NONE or BOTH is needed then an explicit set of
+ * the numbering styles must be made.
+ */
+ public void swapDefaults() {
+ left.style = EVEN;
+ right.style = ODD;
+ }
+ }
+
+ /**
+ * Represents one side of the road.
+ */
+ static class Side {
+ private final boolean left;
+
+ private NumberStyle style;
+ private int base;
+
+ // The calculated end number for the node. Might be different to the actual number
+ // that are wanted that are in targetEnd.
+ private int end;
+
+ // These are the target start and end numbers for the node. The real numbers are different as there
+ // is an adjustment applied.
+ private NumberStyle targetStyle;
+ private int targetStart;
+ private int targetEnd;
+
+ // Everything is represented as a difference from a previous value.
+ private int startDiff;
+ private int endDiff;
+ private int lastEndDiff;
+
+ // This is +1 if the numbers are ascending, and -1 if descending.
+ private int direction;
+
+ // Bases equalised to this side.
+ private boolean equalized;
+
+ Side(boolean left) {
+ this.left = left;
+ }
+
+ /**
+ * Set the wanted values for start and end for this side of the road.
+ */
+ public void setTargets(NumberStyle style, int start, int end) {
+ this.targetStyle = style;
+ this.targetStart = start;
+ this.targetEnd = end;
+
+ // In reality should use the calculated start and end values, not the targets. Real start and end
+ // values are not ever the same (in this implementation) so that is why the case where start==end
+ // is given the value +1.
+ if (targetStart < targetEnd)
+ direction = 1;
+ else if (targetEnd < targetStart)
+ direction = -1;
+ else
+ direction = 1;
+ }
+
+ /**
+ * Try a start value to see if it will work. Obviously a value equal to the target will work
+ * but so will a value that equals it after rounding for odd/even.
+ * @param value The value to test.
+ * @return True if this value would result in the targetStart.
+ */
+ private boolean tryStart(int value) {
+ return value == targetStart || style.round(value, direction) == targetStart;
+ }
+
+ /**
+ * For the right hand side, read and end value, or use the last end value as default.
+ *
+ * Otherwise, the same end diff is used for the right side as the left.
+ * @param left Reference to the left hand side.
+ */
+ public boolean needOverride(Side left) {
+ return endDiff != 0 || left.endDiff == 0;
+ }
+
+ /**
+ * There is more than one way to represent the same range of numbers. The idea is to pick one of
+ * the shorter ways. We don't make any effort to find the shortest, but just pick a reasonable
+ * strategy for some common cases, and making use of defaults where we can.
+ *
+ * @param other The details of the other side of the road.
+ *
+ */
+ private void calc(Side other) {
+ if (style == NONE)
+ return;
+
+ boolean equalized = this.equalized || other.equalized;
+
+ if (!equalized)
+ startDiff = tryStart(base)? 0: targetStart - base;
+
+ endDiff = targetEnd - (base+startDiff) + direction;
+
+ // Special for start == end, we can often do without an end diff.
+ if (targetStart == targetEnd && base == targetStart && lastEndDiff == 0 && !equalized) {
+ if (left || (other.endDiff == 0))
+ endDiff = 0;
+ }
+
+ // Now that end is calculated we fix it and see if we can obtain it by default instead.
+ end = base+startDiff+endDiff;
+
+ if (left) {
+ if (endDiff == lastEndDiff) endDiff = 0; // default is our last diff.
+
+ } else if (other.style != NONE) {
+ // right side (and left not NONE)
+ if (other.endDiff == 0 && endDiff == lastEndDiff) endDiff = 0; // No left diff, default is our last
+ if (other.endDiff != 0 && other.endDiff == endDiff) endDiff = 0; // Left diff set, that's our default
+ }
+ }
+
+ /**
+ * Called at the end of processing a number range. Sets up the fields for the next one.
+ */
+ public void finish() {
+ lastEndDiff = end - (base + startDiff);
+ base = end;
+ }
+ }
+
+ /**
+ * The calculations are run on this class first, which keeps track of the sizes required to
+ * write the values without actually writing them anywhere.
+ *
+ * When passing a BitWriter to any method on this class, it must be a throw away one, as it
+ * will actually be written to by some of the common methods.
+ */
+ private class GatheringState extends State {
+ class BitSizes {
+ private boolean positive;
+ private boolean negative;
+ private int diff;
+
+ private boolean isSigned() {
+ return positive && negative;
+ }
+
+ private int calcWidth() {
+ int n = diff;
+ if (isSigned())
+ n++;
+ return 32 - Integer.numberOfLeadingZeros(n);
+ }
+ }
+
+ private final BitSizes start = new BitSizes();
+ private final BitSizes end = new BitSizes();
+
+ public GatheringState(int initialValue) {
+ setInitialValue(initialValue);
+ }
+
+ public void writeNumberingStyle(BitWriter bw) {
+ left.style = left.targetStyle;
+ right.style = right.targetStyle;
+ }
+
+ /**
+ * Calculate the size required for this write and keeps the maximum values.
+ * @param diff The value to examine.
+ */
+ public void writeStart(int diff) {
+ int val = testSign(start, diff);
+ if (val > start.diff)
+ start.diff = val;
+ }
+
+ /**
+ * Calculate the size required to hold this write and keeps the maximum.
+ * @param diff The value to be examined.
+ */
+ public void writeEnd(int diff) {
+ int val = testSign(end, diff);
+ if (val > end.diff)
+ end.diff = val;
+ }
+
+ /**
+ * Checks the sign properties required for the write.
+ */
+ private int testSign(BitSizes bs, int val) {
+ if (val > 0) {
+ bs.positive = true;
+ } else if (val < 0) {
+ bs.negative = true;
+ return -val;
+ }
+ return val;
+ }
+
+ /**
+ * Construct a writer that uses a bit width and sign properties that are sufficient to write
+ * all of the values found in the gathering phase. This is for start differences.
+ */
+ public VarBitWriter getStartWriter() {
+ return getVarBitWriter(start, START_WIDTH_MIN);
+ }
+ /**
+ * Construct a writer that uses a bit width and sign properties that are sufficient to write
+ * all of the values found in the gathering phase. This is for end differences.
+ */
+ public VarBitWriter getEndWriter() {
+ return getVarBitWriter(end, END_WIDTH_MIN);
+ }
+
+ /**
+ * Common code to create the bit writer.
+ * @see #getStartWriter()
+ * @see #getEndWriter()
+ */
+ private VarBitWriter getVarBitWriter(BitSizes bs, int minWidth) {
+ VarBitWriter writer = new VarBitWriter(bw, minWidth);
+ if (bs.isSigned())
+ writer.signed = true;
+ else if (bs.negative)
+ writer.negative = true;
+ int width = bs.calcWidth();
+ if (width > minWidth)
+ writer.bitWidth = width - minWidth;
+ if (writer.bitWidth > 15)
+ throw new Abandon("Difference too large");
+ return writer;
+ }
+ }
+
+ /**
+ * This is used to actually write the bit stream.
+ * @see GatheringState
+ */
+ static class WritingState extends State {
+
+ private VarBitWriter startWriter;
+ private VarBitWriter endWriter;
+ private boolean restoreBitWriters;
+ private final VarBitWriter savedStartWriter;
+ private final VarBitWriter savedEndWriter;
+
+ public WritingState(State state) {
+ setInitialValue(state.initialValue);
+ left.base = state.initialValue;
+ right.base = state.initialValue;
+
+ startWriter = state.getStartWriter();
+ endWriter = state.getEndWriter();
+ this.savedStartWriter = startWriter;
+ this.savedEndWriter = endWriter;
+ }
+
+ public void writeStart(int diff) {
+ startWriter.write(diff);
+ }
+
+ public void writeEnd(int diff) {
+ endWriter.write(diff);
+ }
+
+ public void writeNumberingStyle(BitWriter bw) {
+ if (left.targetStyle != left.style || right.targetStyle != right.style) {
+ bw.putn(0, 2);
+ bw.putn(left.targetStyle.getVal(), 2);
+ bw.putn(right.targetStyle.getVal(), 2);
+ left.style = left.targetStyle;
+ right.style = right.targetStyle;
+ }
+ }
+
+ /**
+ * You can change the number of bits and the sign properties of the writers before writing a nodes
+ * numbers. We don't try and work out the optimum sequence, but use this for tricky cases where
+ * we fail to work out the correct sizes in advance.
+ *
+ * This routine means that we will always be using writers that will deal with the next node numbers.
+ *
+ * @param bw The output stream writer.
+ */
+ public void writeBitWidths(BitWriter bw) {
+ newWriter(bw, startWriter, left.startDiff, right.startDiff, true);
+ newWriter(bw, endWriter, left.endDiff, right.endDiff, false);
+ }
+
+ /**
+ * Common code for writeBitWidths. Calculate the width and the sign properties required to
+ * represent the two numbers.
+ * @param leftDiff One of the numbers to be represented.
+ * @param rightDiff The other number to be represented.
+ * @param start Set to true if this is the start writer, else it is for the end writer.
+ */
+ private void newWriter(BitWriter bw, VarBitWriter writer, int leftDiff, int rightDiff, boolean start) {
+ if (!writer.checkFit(leftDiff) || !writer.checkFit(rightDiff)) {
+ int min = Math.min(leftDiff, rightDiff);
+ int max = Math.max(leftDiff, rightDiff);
+ boolean signed = false;
+ boolean negative = false;
+ if (max < 0)
+ negative = true;
+ else if (min < 0)
+ signed = true;
+
+ int val = Math.max(Math.abs(min), Math.abs(max));
+ int width = 32 - Integer.numberOfLeadingZeros(val);
+ if (signed) width++;
+
+ restoreBitWriters = true;
+ VarBitWriter nw;
+ if (start) {
+ startWriter = nw = new VarBitWriter(bw, START_WIDTH_MIN, negative, signed, width);
+ bw.putn(2, 4); // change width start
+ } else {
+ endWriter = nw = new VarBitWriter(bw, END_WIDTH_MIN, negative, signed, width);
+ bw.putn(0xa, 4); // change width end (0x8 | 0x2)
+ }
+ nw.writeFormat();
+ }
+ }
+
+ public void writeSkip(BitWriter bw, int n) {
+ if (n < 0)
+ throw new Abandon("bad skip value:" + n);
+
+ bw.putn(6, 3);
+
+ int width = 32 - Integer.numberOfLeadingZeros(n);
+ if (width > 5) {
+ bw.put1(true);
+ width = 10;
+ } else {
+ bw.put1(false);
+ width = 5;
+ }
+ bw.putn(n, width);
+ }
+
+ public VarBitWriter getStartWriter() {
+ return startWriter;
+ }
+
+ public VarBitWriter getEndWriter() {
+ return endWriter;
+ }
+
+ /**
+ * If we used an alternate writer for a node's numbers then we restore the default
+ * writers afterwards.
+ */
+ protected void restoreWriters() {
+ if (restoreBitWriters) {
+ startWriter = savedStartWriter;
+ endWriter = savedEndWriter;
+ restoreBitWriters = false;
+ }
+ }
+ }
+}
+
+/**
+ * A bit writer that can be configured with different bit width and sign properties.
+ *
+ * The sign choices are:
+ * negative: all numbers are negative and so can be represented without a sign bit. (or all positive
+ * if this is false).
+ * signed: numbers are positive and negative, and so have sign bit.
+ *
+ * The bit width is composed of two parts since it is represented as a difference between
+ * a well known minimum value and the actual value.
+ */
+class VarBitWriter {
+ private final BitWriter bw;
+ private final int minWidth;
+ int bitWidth;
+ boolean negative;
+ boolean signed;
+
+ VarBitWriter(BitWriter bw, int minWidth) {
+ this.bw = bw;
+ this.minWidth = minWidth;
+ }
+
+ public VarBitWriter(BitWriter bw, int minWidth, boolean negative, boolean signed, int width) {
+ this(bw, minWidth);
+ this.negative = negative;
+ this.signed = signed;
+ if (width > minWidth)
+ this.bitWidth = width - minWidth;
+ }
+
+ /**
+ * Write the number to the bit stream. If the number cannot be written
+ * correctly with this bit writer then an exception is thrown. This shouldn't
+ * happen since we check before hand and create a new writer if the numbers are not
+ * going to fit.
+ *
+ * @param n The number to be written.
+ */
+ public void write(int n) {
+ if (!checkFit(n))
+ throw new Abandon("number does not fit bit space available");
+
+ if (n < 0 && negative)
+ n = -n;
+
+ if (signed) {
+ int mask = (1 << (minWidth + bitWidth+2)) - 1;
+ n &= mask;
+ }
+
+ bw.putn(n, minWidth+bitWidth + ((signed)?1:0));
+ }
+
+ /**
+ * Checks to see if the number that we want to write can be written by this writer.
+ * @param n The number we would like to write.
+ * @return True if all is OK for writing it.
+ */
+ boolean checkFit(int n) {
+ if (negative) {
+ if (n > 0)
+ return false;
+ else
+ n = -n;
+ } else if (signed && n < 0)
+ n = -1 - n;
+
+ int mask = (1 << minWidth + bitWidth) - 1;
+
+ return n == (n & mask);
+ }
+
+ /**
+ * Write the format of this bit writer to the output stream. Used at the beginning and
+ * when changing the bit widths.
+ */
+ public void writeFormat() {
+ bw.put1(negative);
+ bw.put1(signed);
+ bw.putn(bitWidth, 4);
+ }
+}
+
+/**
+ * Exception to throw when we detect that we do not know how to encode a particular case.
+ * This should not be thrown any more, when the preparers is called correctly.
+ *
+ * If it is, then the number preparer is marked as invalid and the data is not written to the
+ * output file.
+ */
+class Abandon extends RuntimeException {
+ Abandon(String message) {
+ super("HOUSE NUMBER RANGE: " + message);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/NumberStyle.java b/src/uk/me/parabola/imgfmt/app/net/NumberStyle.java
new file mode 100644
index 0000000..8300433
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/NumberStyle.java
@@ -0,0 +1,70 @@
+package uk.me.parabola.imgfmt.app.net;
+
+/**
+ * The number style down one side of a side of a road.
+ *
+ * @author Steve Ratcliffe
+ */
+public enum NumberStyle {
+ NONE(0), // No numbers.
+
+ EVEN(1) {
+ public int round(int val, int direction) {
+ if ((val & 1) == 1) return val + direction;
+ return val;
+ }
+ }, // Numbers are even on this side of the road.
+
+ ODD(2) {
+ @Override
+ public int round(int val, int direction) {
+ if ((val & 1) == 0) return val + direction;
+ return val;
+ }
+ }, // Numbers are odd on this side of the road
+
+ BOTH(3), // Both odd and even numbers (can also be used for a range of a single number)
+ ;
+
+ private final int val;
+
+ NumberStyle(int val) {
+ this.val = val;
+ }
+
+ public int getVal() {
+ return val;
+ }
+
+ public int round(int val, int direction) {
+ return val;
+ }
+
+ public static NumberStyle fromInt(int n) {
+ switch (n) {
+ case 0: return NONE;
+ case 1: return EVEN;
+ case 2: return ODD;
+ case 3: return BOTH;
+ default: return NONE;
+ }
+ }
+
+
+ public String toString() {
+ return super.toString().substring(0, 1);
+ }
+
+ public static NumberStyle fromChar(String string) {
+ switch (string.charAt(0)) {
+ case 'N': return NONE;
+ case 'E': return EVEN;
+ case 'O': return ODD;
+ case 'B': return BOTH;
+ case '0':
+ System.err.println("zero instead of capital O in number spec");
+ return ODD;
+ default: return NONE;
+ }
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/Numbers.java b/src/uk/me/parabola/imgfmt/app/net/Numbers.java
new file mode 100644
index 0000000..43bd9c0
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/Numbers.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2008 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 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.imgfmt.app.net;
+
+import uk.me.parabola.log.Logger;
+
+/**
+ * Describes the house numbering from a node in the road.
+ * @author Steve Ratcliffe
+ */
+public class Numbers {
+ private static final Logger log = Logger.getLogger(Numbers.class);
+
+ // The node in the road where these numbers apply. In the polish notation it is the
+ // node in the road, whereas in the NET file it is the number of the routing node.
+ private int nodeNumber; // node in road index
+ private Integer rnodNumber; // routing node index
+
+ // On the left hand side of the road.
+ private NumberStyle leftNumberStyle;
+ private int leftStart;
+ private int leftEnd;
+
+ // On the right hand side of the road.
+ private NumberStyle rightNumberStyle;
+ private int rightStart;
+ private int rightEnd;
+
+ public Numbers() {
+ }
+
+ /**
+ * This constructor takes a comma separated list as in the polish format. Also used in testing as
+ * it is an easy way to set all the parameters at once.
+ *
+ * @param spec Node number, followed by left and then right parameters as in the polish format.
+ */
+ public Numbers(String spec) {
+ String[] strings = spec.split(",");
+ nodeNumber = Integer.valueOf(strings[0]);
+ leftNumberStyle = NumberStyle.fromChar(strings[1]);
+ leftStart = Integer.valueOf(strings[2]);
+ leftEnd = Integer.valueOf(strings[3]);
+ rightNumberStyle = NumberStyle.fromChar(strings[4]);
+ rightStart = Integer.valueOf(strings[5]);
+ rightEnd = Integer.valueOf(strings[6]);
+ }
+
+ public int getNodeNumber() {
+ return nodeNumber;
+ }
+
+ public void setNodeNumber(int nodeNumber) {
+ this.nodeNumber = nodeNumber;
+ }
+
+ public int getRnodNumber() {
+ if (rnodNumber == null) {
+ log.error("WARNING: rnod not set!!");
+ return nodeNumber;
+ }
+ return rnodNumber;
+ }
+
+ public boolean hasRnodNumber() {
+ return rnodNumber != null;
+ }
+
+ public void setRnodNumber(int rnodNumber) {
+ this.rnodNumber = rnodNumber;
+ }
+
+ public NumberStyle getLeftNumberStyle() {
+ return leftNumberStyle;
+ }
+
+ public void setLeftNumberStyle(NumberStyle leftNumberStyle) {
+ this.leftNumberStyle = leftNumberStyle;
+ }
+
+ public int getLeftStart() {
+ return leftStart;
+ }
+
+ public void setLeftStart(int leftStart) {
+ this.leftStart = leftStart;
+ }
+
+ public int getLeftEnd() {
+ return leftEnd;
+ }
+
+ public void setLeftEnd(int leftEnd) {
+ this.leftEnd = leftEnd;
+ }
+
+ public NumberStyle getRightNumberStyle() {
+ return rightNumberStyle;
+ }
+
+ public void setRightNumberStyle(NumberStyle rightNumberStyle) {
+ this.rightNumberStyle = rightNumberStyle;
+ }
+
+ public int getRightStart() {
+ return rightStart;
+ }
+
+ public void setRightStart(int rightStart) {
+ this.rightStart = rightStart;
+ }
+
+ public int getRightEnd() {
+ return rightEnd;
+ }
+
+ public void setRightEnd(int rightEnd) {
+ this.rightEnd = rightEnd;
+ }
+
+ public String toString() {
+ String nodeStr = "0";
+ if (nodeNumber > 0)
+ nodeStr = String.valueOf(nodeNumber);
+ else if (getRnodNumber() > 0)
+ nodeStr = String.format("(n%d)", getRnodNumber());
+
+ return String.format("%s,%s,%d,%d,%s,%d,%d",
+ nodeStr,
+ leftNumberStyle,
+ leftStart,
+ leftEnd,
+ rightNumberStyle,
+ rightStart,
+ rightEnd);
+ }
+
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Numbers))
+ return false;
+
+ Numbers other = (Numbers) obj;
+ return toString().equals(other.toString());
+ }
+
+ public int hashCode() {
+ return toString().hashCode();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/RoadDef.java b/src/uk/me/parabola/imgfmt/app/net/RoadDef.java
new file mode 100644
index 0000000..505369d
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/RoadDef.java
@@ -0,0 +1,739 @@
+/*
+ * 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: Jan 5, 2008
+ */
+package uk.me.parabola.imgfmt.app.net;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import uk.me.parabola.imgfmt.MapFailedException;
+import uk.me.parabola.imgfmt.app.BitWriter;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.lbl.City;
+import uk.me.parabola.imgfmt.app.lbl.Zip;
+import uk.me.parabola.imgfmt.app.trergn.Polyline;
+import uk.me.parabola.log.Logger;
+
+/**
+ * A road definition. This ties together all segments of a single road
+ * and provides street address information.
+ *
+ * This corresponds to an entry in NET1, which is linked with the
+ * polylines making up this road in RGN. Links to RGN are written
+ * via RoadIndex, while writing links from RGN to NET1 is delayed
+ * via setOffsetWriter.
+ *
+ * If the map includes routing, the NET1 record also points to
+ * a NOD2 record, written by writeNod2.
+ *
+ * Edges in the routing graph ("arcs") link to the corresponding
+ * road via the RoadDef, storing the NET1 offset via TableA,
+ * which also includes some road information.
+ *
+ * @author Elrond
+ * @author Steve Ratcliffe
+ * @author Robert Vollmert
+ */
+
+public class RoadDef implements Comparable<RoadDef> {
+ private static final Logger log = Logger.getLogger(RoadDef.class);
+
+ public static final int NET_FLAG_NODINFO = 0x40;
+ public static final int NET_FLAG_ADDRINFO = 0x10;
+ private static final int NET_FLAG_UNK1 = 0x04; // lock on road?
+ private static final int NET_FLAG_ONEWAY = 0x02;
+
+ private static final int NOD2_FLAG_UNK = 0x01;
+ private static final int NOD2_FLAG_EXTRA_DATA = 0x80;
+
+ // first byte of Table A info in NOD 1
+ private static final int TABA_FLAG_TOLL = 0x80;
+ private static final int TABA_MASK_CLASS = 0x70;
+ private static final int TABA_FLAG_ONEWAY = 0x08;
+ private static final int TABA_MASK_SPEED = 0x07;
+
+ private static final int TABAACCESS_FLAG_CARPOOL = 0x0008;
+ private static final int TABAACCESS_FLAG_NOTHROUGHROUTE = 0x0080;
+
+ // second byte: access flags - order must correspond to constants
+ // in RoadNetwork
+ // bits 0x08, 0x80 are set separately
+ private static final int[] ACCESS = {
+ 0x8000, // emergency (net pointer bit 31)
+ 0x4000, // delivery (net pointer bit 30)
+ 0x0001, // car
+ 0x0002, // bus
+ 0x0004, // taxi
+ 0x0010, // foot
+ 0x0020, // bike
+ 0x0040, // truck
+ };
+
+ // the offset in Nod2 of our Nod2 record
+ private int offsetNod2;
+
+ // the offset in Net1 of our Net1 record
+ private int offsetNet1;
+
+ /*
+ * Everything that's relevant for writing to NET1.
+ */
+ private int netFlags = NET_FLAG_UNK1;
+
+ // The road length units may be affected by other flags in the header as
+ // there is doubt as to the formula.
+ private int roadLength;
+
+ // There can be up to 4 labels for the same road.
+ private static final int MAX_LABELS = 4;
+
+ private final Label[] labels = new Label[MAX_LABELS];
+ private int numlabels;
+
+ private final SortedMap<Integer,List<RoadIndex>> roadIndexes = new TreeMap<Integer,List<RoadIndex>>();
+
+ private City city;
+ private Zip zip;
+ private boolean paved = true;
+ private boolean ferry;
+ private boolean roundabout;
+ private boolean linkRoad;
+ private boolean synthesised;
+ private boolean flareCheck;
+ private Set<String> messageIssued;
+
+ private final List<Offset> rgnOffsets = new ArrayList<Offset>(4);
+
+ /*
+ * Everything that's relevant for writing out Nod 2.
+ */
+ // This is the node associated with the road. I'm not certain about how
+ // this works, but in NOD2 each road has a reference to only one node.
+ // This is that node.
+ private RouteNode node;
+
+ // the first point in the road is a node (the above routing node)
+ private boolean startsWithNode = true;
+ // number of nodes in the road
+ private int nnodes;
+
+ // always appears to be set
+ private int nod2Flags = NOD2_FLAG_UNK;
+
+ // The data for Table A
+ private int tabAInfo;
+ private int tabAAccess;
+
+ // for diagnostic purposes
+ private final long id;
+ private final String name;
+ private List<Numbers> numbersList;
+ private int nodeCount;
+
+ public RoadDef(long id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ /**
+ * A constructor that is used when reading a file and you know the NET1 offset. When writing
+ * the offsetNet1 field is filled in during the writing process.
+ * @param id Road id
+ * @param net1offset The offset in the road defs section of the NET file.
+ * @param name The main of the road.
+ */
+ public RoadDef(long id, int net1offset, String name) {
+ this.id = id;
+ this.offsetNet1 = net1offset;
+ this.name = name;
+ }
+
+ // for diagnostic purposes
+ public String toString() {
+ // assumes id is an OSM id
+ String browseURL = "http://www.openstreetmap.org/browse/way/" + id;
+ if(getName() != null)
+ return "(" + getName() + ", " + browseURL + ")";
+ else
+ return "(" + browseURL + ")";
+ }
+
+ public String getName() {
+ if (name != null)
+ return name;
+ if (labels[0] != null)
+ return labels[0].getText();
+ return null;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+
+ /**
+ * This is for writing to NET1.
+ * @param writer A writer that is positioned within NET1.
+ */
+ void writeNet1(ImgFileWriter writer, int numCities, int numZips) {
+ if (numlabels == 0)
+ return;
+ assert numlabels > 0;
+
+ offsetNet1 = writer.position();
+
+ NumberPreparer numbers = null;
+ if (numbersList != null) {
+ numbers = new NumberPreparer(numbersList);
+ numbers.fetchBitStream();
+ if (!numbers.isValid()){
+ numbers = null;
+ log.warn("Invalid housenumbers in",this.toString());
+ }
+ }
+
+ writeLabels(writer);
+ if (numbers != null) { // TODO combine if
+ if (numbers.getSwapped())
+ netFlags |= 0x20; // swapped default; left=even, right=odd
+ }
+ writer.put((byte) netFlags);
+ writer.put3(roadLength);
+
+ int maxlevel = writeLevelCount(writer);
+
+ writeLevelDivs(writer, maxlevel);
+
+ if((netFlags & NET_FLAG_ADDRINFO) != 0) {
+ nodeCount--;
+ writer.put((byte) (nodeCount & 0xff)); // lo bits of node count
+
+ int code = 0xe8; // zip and city present
+ code |= ((nodeCount >> 8) & 0x3); // top bits of node count
+ if(city == null)
+ code |= 0x10; // no city
+ if(zip == null)
+ code |= 0x04; // no zip
+ if (numbers != null) {
+ code &= ~0xc0;
+ if (numbers.fetchBitStream().getLength() > 255)
+ code |= 0x40;
+ }
+ writer.put((byte)code);
+ if(zip != null) {
+ char zipIndex = (char)zip.getIndex();
+ if(numZips > 255)
+ writer.putChar(zipIndex);
+ else
+ writer.put((byte)zipIndex);
+ }
+ if(city != null) {
+ char cityIndex = (char)city.getIndex();
+ if(numCities > 255)
+ writer.putChar(cityIndex);
+ else
+ writer.put((byte)cityIndex);
+ }
+ if (numbers != null) {
+ BitWriter bw = numbers.fetchBitStream();
+ if (bw.getLength() > 255)
+ writer.putChar((char) bw.getLength());
+ else
+ writer.put((byte) bw.getLength());
+ writer.put(bw.getBytes(), 0, bw.getLength());
+ }
+ }
+
+ if (hasNodInfo()) {
+ // This is the offset of an entry in NOD2
+ int val = offsetNod2;
+ if (val < 0x7fff) {
+ writer.put((byte) 1);
+ writer.putChar((char) val);
+ } else {
+ writer.put((byte) 2);
+ writer.put3(val);
+ }
+ }
+ }
+
+ private void writeLabels(ImgFileWriter writer) {
+ for (int i = 0; i < numlabels; i++) {
+ Label l = labels[i];
+ int ptr = l.getOffset();
+ if (i == (numlabels-1))
+ ptr |= 0x800000;
+ writer.put3(ptr);
+ }
+ }
+
+ public void putSortedRoadEntry(ImgFileWriter writer, Label label) {
+ for(int i = 0; i < labels.length && labels[i] != null; ++i) {
+ if(labels[i].equals(label)) {
+ writer.put3((i << 22) | offsetNet1);
+ return;
+ }
+ }
+ }
+
+ private int writeLevelCount(ImgFileWriter writer) {
+ int maxlevel = getMaxZoomLevel();
+ for (int i = 0; i <= maxlevel; i++) {
+ List<RoadIndex> l = roadIndexes.get(i);
+ int b = (l == null) ? 0 : l.size();
+ assert b < 0x80 : "too many polylines at level " + i;
+ if (i == maxlevel)
+ b |= 0x80;
+ writer.put((byte) b);
+ }
+ return maxlevel;
+ }
+
+ private void writeLevelDivs(ImgFileWriter writer, int maxlevel) {
+ for (int i = 0; i <= maxlevel; i++) {
+ List<RoadIndex> l = roadIndexes.get(i);
+ if (l != null) {
+ for (RoadIndex ri : l)
+ ri.write(writer);
+ }
+ }
+ }
+
+ public void addLabel(Label l) {
+ int i;
+ for (i = 0; i < MAX_LABELS && labels[i] != null; ++i) {
+ if (l.equals(labels[i])) {
+ // label already present
+ return;
+ }
+ }
+
+ if (i < MAX_LABELS) {
+ labels[i] = l;
+ ++numlabels;
+ }
+ else
+ log.warn(this.toString() + " discarding extra label (already have " + MAX_LABELS + ")");
+ }
+
+ public Label[] getLabels() {
+ return labels;
+ }
+
+ /**
+ * Add a polyline to this road.
+ *
+ * References to these are written to NET. At a given zoom
+ * level, we're writing these in the order we get them,
+ * which must(!) be the order the segments have
+ * in the road.
+ */
+ public void addPolylineRef(Polyline pl) {
+ if(log.isDebugEnabled())
+ log.debug("adding polyline ref", this, pl.getSubdiv());
+ int level = pl.getSubdiv().getZoom().getLevel();
+ List<RoadIndex> l = roadIndexes.get(level);
+ if (l == null) {
+ l = new ArrayList<RoadIndex>(4);
+ roadIndexes.put(level, l);
+ }
+ int s = l.size();
+ l.add(new RoadIndex(pl));
+
+ // XXX needs to be the lowest level, which might not always be zero in the future
+ if (level == 0) {
+ nodeCount += pl.getNodeCount();
+ }
+ }
+
+ private int getMaxZoomLevel() {
+ return roadIndexes.lastKey();
+ }
+
+ public boolean connectedTo(RoadDef other) {
+ List<RoadIndex> l = roadIndexes.get(0);
+ if(l == null)
+ return false;
+
+ List<RoadIndex> ol = other.roadIndexes.get(0);
+ if(ol == null)
+ return false;
+
+ for(RoadIndex ri : l)
+ for(RoadIndex ori : ol)
+ if(ri.getLine().sharesNodeWith(ori.getLine()))
+ return true;
+ return false;
+ }
+
+ public boolean sameDiv(RoadDef other) {
+ return getStartSubdivNumber() == other.getStartSubdivNumber();
+ }
+
+ public int getStartSubdivNumber() {
+ Integer key = roadIndexes.firstKey();
+ return roadIndexes.get(key).get(0).getLine().getSubdiv().getNumber();
+ }
+
+ /**
+ * Set the road length (in meters).
+ */
+ public void setLength(double l) {
+ // XXX: this is from test.display.NetDisplay, possibly varies
+ roadLength = (int) l / 2;
+ }
+
+ public boolean hasHouseNumbers() {
+ return numbersList != null && !numbersList.isEmpty();
+ }
+
+ /*
+ * Everything that's relevant for writing to RGN.
+ */
+ class Offset {
+ final int position;
+ final int flags;
+
+ Offset(int position, int flags) {
+ this.position = position;
+ this.flags = flags;
+ }
+
+ int getPosition() {
+ return position;
+ }
+
+ int getFlags() {
+ return flags;
+ }
+ }
+
+
+ /**
+ * Add a target location in the RGN section where we should write the
+ * offset of this road def when it is written to NET.
+ *
+ * @param position The offset in RGN.
+ * @param flags The flags that should be set.
+ */
+ public void addOffsetTarget(int position, int flags) {
+ rgnOffsets.add(new Offset(position, flags));
+ }
+
+ /**
+ * Write into the RGN the offset in net1 of this road.
+ * @param rgn A writer for the rgn file.
+ */
+ void writeRgnOffsets(ImgFileWriter rgn) {
+ if (offsetNet1 >= 0x400000)
+ throw new MapFailedException("Overflow of the NET1. The tile ("
+ + log.threadTag()
+ + ") must be split so that there are fewer roads in it");
+
+ for (Offset off : rgnOffsets) {
+ rgn.position(off.getPosition());
+ rgn.put3(offsetNet1 | off.getFlags());
+ }
+ }
+
+ private boolean internalNodes = true;
+
+ /**
+ * Does the road have any nodes besides start and end?
+ *
+ * This affects whether we need to write extra bits in
+ * the bitstream in RGN.
+ */
+ public boolean hasInternalNodes() {
+ return internalNodes;
+ }
+
+ public void setInternalNodes(boolean n) {
+ internalNodes = n;
+ }
+
+ /**
+ * Set the routing node associated with this road.
+ *
+ * This implies that the road has an entry in NOD 2
+ * which will be pointed at from NET 1.
+ */
+ public void setNode(RouteNode node) {
+ netFlags |= NET_FLAG_NODINFO;
+ this.node = node;
+ }
+
+ private boolean hasNodInfo() {
+ return (netFlags & NET_FLAG_NODINFO) != 0;
+ }
+
+ public void setStartsWithNode(boolean s) {
+ startsWithNode = s;
+ }
+
+ public void setNumNodes(int n) {
+ nnodes = n;
+ }
+
+ public void setNumbersList(List<Numbers> numbersList) {
+ if (numbersList != null && !numbersList.isEmpty()) {
+ this.numbersList = numbersList;
+ netFlags |= NET_FLAG_ADDRINFO;
+ }
+ }
+
+ /**
+ * Write this road's NOD2 entry.
+ *
+ * Stores the writing position to be able to link here
+ * from NET 1 later.
+ *
+ * @param writer A writer positioned in NOD2.
+ */
+ public void writeNod2(ImgFileWriter writer) {
+ if (!hasNodInfo())
+ return;
+
+ log.debug("writing nod2");
+
+ offsetNod2 = writer.position();
+
+ writer.put((byte) nod2Flags);
+ writer.put3(node.getOffsetNod1()); // offset in nod1
+
+ // this is related to the number of nodes, but there
+ // is more to it...
+ // For now, shift by one if the first node is not a
+ // routing node. Supposedly, other holes are also
+ // possible.
+ // This might be unnecessary if we just make sure
+ // that every road starts with a node.
+ int nbits = nnodes;
+ if (!startsWithNode)
+ nbits++;
+ writer.putChar((char) nbits);
+ boolean[] bits = new boolean[nbits];
+ for (int i = 0; i < bits.length; i++)
+ bits[i] = true;
+ if (!startsWithNode)
+ bits[0] = false;
+ for (int i = 0; i < bits.length; i += 8) {
+ int b = 0;
+ for (int j = 0; j < 8 && j < bits.length - i; j++)
+ if (bits[i+j])
+ b |= 1 << j;
+ writer.put((byte) b);
+ }
+ }
+
+ /*
+ * Everything that's relevant for writing out Table A.
+ *
+ * Storing this info in the RoadDef means that each
+ * arc gets the same version of the below info, which
+ * makes sense for the moment considering polish format
+ * doesn't provide for different speeds and restrictions
+ * for segments of roads.
+ */
+
+ /**
+ * Return the offset of this road's NET1 entry. Assumes
+ * writeNet1() has been called.
+ */
+ public int getOffsetNet1() {
+ return offsetNet1;
+ }
+
+ /**
+ * Flag that a toll must be payed when using this road.
+ */
+ public void setToll() {
+ tabAInfo |= TABA_FLAG_TOLL;
+ }
+
+ /**
+ * Flag that the road has a carpool lane.<br>
+ * Warning: This bit does not seem to work. Maybe it does not control
+ * the carpool flag.
+ */
+ public void setCarpoolLane() {
+ tabAAccess |= TABAACCESS_FLAG_CARPOOL;
+ }
+
+ /**
+ * Sets the flag that routing is allowed only if the route starts or
+ * end on this road.
+ */
+ public void setNoThroughRouting() {
+ tabAAccess |= TABAACCESS_FLAG_NOTHROUGHROUTE;
+ }
+
+ public void setAccess(boolean[] access) {
+ assert access.length <= ACCESS.length;
+ for (int i = 0; i < access.length; i++)
+ if (access[i])
+ tabAAccess |= ACCESS[i];
+ }
+
+ public int getTabAInfo() {
+ return tabAInfo;
+ }
+
+ public int getTabAAccess() {
+ return tabAAccess;
+ }
+
+ /*
+ * These affect various parts.
+ */
+
+ private int roadClass = -1;
+
+ // road class that goes in various places (really?)
+ public void setRoadClass(int roadClass) {
+ assert roadClass < 0x08;
+
+ /* for RouteArcs to get as their "destination class" */
+ this.roadClass = roadClass;
+
+ /* for Table A */
+ int shifted = (roadClass << 4) & 0xff;
+ tabAInfo |= shifted;
+
+ /* for NOD 2 */
+ nod2Flags |= shifted;
+ }
+
+ public int getRoadClass() {
+ assert roadClass >= 0 : "roadClass not set";
+ return roadClass;
+ }
+
+ public void setSpeed(int speed) {
+ assert speed < 0x08;
+
+ /* for Table A */
+ tabAInfo |= speed;
+
+ /* for NOD 2 */
+ nod2Flags |= (speed << 1);
+ }
+
+ public int getRoadSpeed() {
+ return tabAInfo & 7;
+ }
+
+ public void setOneway() {
+ tabAInfo |= TABA_FLAG_ONEWAY;
+ netFlags |= NET_FLAG_ONEWAY;
+ }
+
+ public boolean isOneway() {
+ return (netFlags & NET_FLAG_ONEWAY) != 0;
+ }
+
+ public void setCity(City city) {
+ this.city = city;
+ netFlags |= NET_FLAG_ADDRINFO;
+ }
+
+ public void setZip(Zip zip) {
+ this.zip = zip;
+ netFlags |= NET_FLAG_ADDRINFO;
+ }
+
+ public int compareTo(RoadDef other) {
+ // sort by city name - this is used to group together
+ // roads that have been split into segments
+ if(other == this)
+ return 0;
+
+ // TODO: look at what this is doing...
+ if(city != null && other.city != null)
+ return city.getName().compareTo(other.city.getName());
+ if (hashCode() == other.hashCode())
+ return 0;
+ else if (hashCode() < other.hashCode())
+ return -1;
+ else
+ return 0;
+ }
+
+ public City getCity() {
+ return city;
+ }
+
+ public boolean paved() {
+ return paved;
+ }
+
+ public void paved(boolean p) {
+ paved = p;
+ }
+
+ public void ferry(boolean f) {
+ ferry = f;
+ }
+
+ public boolean ferry() {
+ return ferry;
+ }
+
+ public void setRoundabout(boolean r) {
+ roundabout = r;
+ }
+
+ public boolean isRoundabout() {
+ return roundabout;
+ }
+
+ public void setLinkRoad(boolean lr) {
+ linkRoad = lr;
+ }
+
+ public boolean isLinkRoad() {
+ return linkRoad;
+ }
+
+ public void setSynthesised(boolean s) {
+ synthesised = s;
+ }
+
+ public boolean isSynthesised() {
+ return synthesised;
+ }
+
+ public void doFlareCheck(boolean fc) {
+ flareCheck = fc;
+ }
+
+ public boolean doFlareCheck() {
+ return flareCheck;
+ }
+
+ public boolean messagePreviouslyIssued(String key) {
+ if(messageIssued == null)
+ messageIssued = new HashSet<String>();
+ boolean previouslyIssued = messageIssued.contains(key);
+ messageIssued.add(key);
+ return previouslyIssued;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/RoadIndex.java b/src/uk/me/parabola/imgfmt/app/net/RoadIndex.java
new file mode 100644
index 0000000..eada983
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/RoadIndex.java
@@ -0,0 +1,50 @@
+/*
+ * 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: Jan 5, 2008
+ */
+package uk.me.parabola.imgfmt.app.net;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.trergn.Polyline;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+
+
+/**
+ * @author Steve Ratcliffe
+ */
+public class RoadIndex {
+ private final Polyline linkedRoad;
+ // int Subdivision.getNumber()
+
+ public RoadIndex(Polyline road) {
+ linkedRoad = road;
+ }
+
+ private Subdivision getSubdiv() {
+ return linkedRoad.getSubdiv();
+ }
+
+ Polyline getLine() {
+ return linkedRoad;
+ }
+
+ void write(ImgFileWriter writer) {
+ int roadnum = linkedRoad.getNumber();
+ assert roadnum < 256;
+ writer.put((byte) roadnum);
+ char subdivnum = (char) getSubdiv().getNumber();
+ writer.putChar(subdivnum);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/RouteArc.java b/src/uk/me/parabola/imgfmt/app/net/RouteArc.java
new file mode 100644
index 0000000..dca1f85
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/RouteArc.java
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2008
+ *
+ * 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.
+ *
+ * Create date: 07-Jul-2008
+ */
+package uk.me.parabola.imgfmt.app.net;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.log.Logger;
+
+/**
+ * An arc joins two nodes within a {@link RouteCenter}. This may be renamed
+ * to a Segment.
+ * The arc also references the road that it is a part of.
+ *
+ * There are also links between nodes in different centers.
+ *
+ * @author Steve Ratcliffe
+ */
+public class RouteArc {
+ private static final Logger log = Logger.getLogger(RouteArc.class);
+
+ // Flags A
+ private static final int FLAG_NEWDIR = 0x80;
+ private static final int FLAG_FORWARD = 0x40;
+ private static final int MASK_DESTCLASS = 0x7;
+ public static final int MASK_CURVE_LEN = 0x38;
+
+ // Flags B
+ private static final int FLAG_LAST_LINK = 0x80;
+ private static final int FLAG_EXTERNAL = 0x40;
+
+ private int offset;
+
+ private int initialHeading; // degrees
+ private final int finalHeading; // degrees
+
+ private final RoadDef roadDef;
+
+ // The nodes that this arc comes from and goes to
+ private final RouteNode source;
+ private final RouteNode dest;
+
+ // The index in Table A describing this arc.
+ private byte indexA;
+ // The index in Table B that this arc goes via, if external.
+ private byte indexB;
+
+ private byte flagA;
+ private byte flagB;
+
+ private boolean haveCurve;
+ private int length;
+ private final int pointsHash;
+ private final boolean curveEnabled;
+
+ /**
+ * Create a new arc.
+ *
+ * @param roadDef The road that this arc segment is part of.
+ * @param source The source node.
+ * @param dest The destination node.
+ * @param initialHeading The initial heading (signed degrees)
+ */
+ public RouteArc(RoadDef roadDef,
+ RouteNode source, RouteNode dest,
+ int initialHeading, int finalHeading,
+ double length,
+ boolean curveEnabled,
+ int pointsHash) {
+ this.roadDef = roadDef;
+ this.source = source;
+ this.dest = dest;
+ this.initialHeading = initialHeading;
+ this.finalHeading = finalHeading;
+ this.length = convertMeters(length);
+ this.curveEnabled = curveEnabled;
+ this.pointsHash = pointsHash;
+ }
+
+ public int getInitialHeading() {
+ return initialHeading;
+ }
+
+ public void setInitialHeading(int ih) {
+ initialHeading = ih;
+ }
+
+ public int getFinalHeading() {
+ return finalHeading;
+ }
+
+ public RouteNode getSource() {
+ return source;
+ }
+
+ public RouteNode getDest() {
+ return dest;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ public int getPointsHash() {
+ return pointsHash;
+ }
+
+ /**
+ * Provide an upper bound for the written size in bytes.
+ */
+ public int boundSize() {
+
+ int[] lendat = encodeLength();
+
+ // 1 (flagA) + 1-2 (offset) + 1 (indexA) + 1 (initialHeading)
+ int size = 5 + lendat.length;
+ if(haveCurve)
+ size += encodeCurve().length;
+ return size;
+ }
+
+ /**
+ * Is this an arc within the RouteCenter?
+ */
+ public boolean isInternal() {
+ // we might check that setInternal has been called before
+ return (flagB & FLAG_EXTERNAL) == 0;
+ }
+
+ public void setInternal(boolean internal) {
+ if (internal)
+ flagB &= ~FLAG_EXTERNAL;
+ else
+ flagB |= FLAG_EXTERNAL;
+ }
+
+
+ /**
+ * Set this arc's index into Table A.
+ */
+ public void setIndexA(byte indexA) {
+ this.indexA = indexA;
+ }
+
+ /**
+ * Get this arc's index into Table A.
+ *
+ * Required for writing restrictions (Table C).
+ */
+ public byte getIndexA() {
+ return indexA;
+ }
+
+ /**
+ * Set this arc's index into Table B. Applies to external arcs only.
+ */
+ public void setIndexB(byte indexB) {
+ assert !isInternal() : "Trying to set index on internal arc.";
+ this.indexB = indexB;
+ }
+
+ /**
+ * Get this arc's index into Table B.
+ *
+ * Required for writing restrictions (Table C).
+ */
+ public byte getIndexB() {
+ return indexB;
+ }
+
+
+ // units of 16 feet
+ final static double LENGTH_FACTOR = 3.2808 / 16;
+ private static int convertMeters(double l) {
+ return (int) (l * LENGTH_FACTOR);
+ }
+
+ public void write(ImgFileWriter writer) {
+ offset = writer.position();
+ if(log.isDebugEnabled())
+ log.debug("writing arc at", offset, ", flagA=", Integer.toHexString(flagA));
+
+ // fetch destination class -- will have been set correctly by now
+ setDestinationClass(dest.getNodeClass());
+
+ // determine how to write length and curve bit
+ int[] lendat = encodeLength();
+
+ writer.put(flagA);
+
+ if (isInternal()) {
+ // space for 14 bit node offset, written in writeSecond.
+ writer.put(flagB);
+ writer.put((byte) 0);
+ } else {
+ if(indexB >= 0x3f) {
+ writer.put((byte) (flagB | 0x3f));
+ writer.put(indexB);
+ }
+ else
+ writer.put((byte) (flagB | indexB));
+ }
+
+ writer.put(indexA);
+
+ if(log.isDebugEnabled())
+ log.debug("writing length", length);
+ for (int aLendat : lendat)
+ writer.put((byte) aLendat);
+
+ writer.put((byte)(256 * initialHeading / 360));
+
+ if (haveCurve) {
+ int[] curvedat = encodeCurve();
+ for (int aCurvedat : curvedat)
+ writer.put((byte) aCurvedat);
+ }
+ }
+
+ /**
+ * Second pass over the nodes in this RouteCenter.
+ * Node offsets are now all known, so we can write the pointers
+ * for internal arcs.
+ */
+ public void writeSecond(ImgFileWriter writer) {
+ if (!isInternal())
+ return;
+
+ writer.position(offset + 1);
+ char val = (char) (flagB << 8);
+ int diff = dest.getOffsetNod1() - source.getOffsetNod1();
+ assert diff < 0x2000 && diff >= -0x2000
+ : "relative pointer too large for 14 bits (source offset = " + source.getOffsetNod1() + ", dest offset = " + dest.getOffsetNod1() + ")";
+ val |= diff & 0x3fff;
+
+ // We write this big endian
+ if(log.isDebugEnabled())
+ log.debug("val is", Integer.toHexString((int)val));
+ writer.put((byte) (val >> 8));
+ writer.put((byte) val);
+ }
+
+ /*
+ * length and curve flag are stored in a variety of ways, involving
+ * 1. flagA & 0x38 (3 bits)
+ * 2. 1-3 bytes following the possible Table A index
+ *
+ * There's even more different encodings supposedly.
+ */
+ private int[] encodeLength() {
+
+ // update haveCurve
+ haveCurve = (curveEnabled && finalHeading != initialHeading);
+
+ if (length >= (1 << 22)) {
+ log.error("Way " + roadDef.getName() + " (id " + roadDef.getId() + ") contains an arc whose length (" + length + " units) is too big to be encoded so the way might not be routable");
+ length = (1 << 22) - 1;
+ }
+
+ // clear existing bits in case length or final heading have
+ // been changed
+ flagA &= ~0x38;
+ int[] lendat;
+ if(length < 0x200) {
+ // 9 bit length optional curve
+ if(haveCurve)
+ flagA |= 0x20;
+ flagA |= (length >> 5) & 0x08; // top bit of length
+ lendat = new int[1]; // one byte of data
+ lendat[0] = length; // bottom 8 bits of length
+ }
+ else if(length >= (1 << 14)) {
+ // 22 bit length with curve
+ flagA |= 0x38;
+ lendat = new int[3]; // three bytes of data
+ lendat[0] = 0xC0 | (length & 0x3f); // 0x80 set, 0x40 set, 6 low bits of length
+ lendat[1] = (length >> 6) & 0xff; // 8 more bits of length
+ lendat[2] = (length >> 14) & 0xff; // 8 more bits of length
+ }
+
+ else if(haveCurve) {
+ // 15 bit length with curve
+ flagA |= 0x38; // all three bits set
+ lendat = new int[2]; // two bytes of data
+ lendat[0] = (length & 0x7f); // 0x80 not set, 7 low bits of length
+ lendat[1] = (length >> 7) & 0xff; // 8 more bits of length
+ }
+ else {
+ // 14 bit length no curve
+ flagA |= 0x38; // all three bits set
+ lendat = new int[2]; // two bytes of data
+ lendat[0] = 0x80 | (length & 0x3f); // 0x80 set, 0x40 not set, 6 low bits of length
+ lendat[1] = (length >> 6) & 0xff; // 8 more bits of length
+ }
+
+ return lendat;
+ }
+
+ /**
+ * Encode the curve data into a sequence of bytes.
+ *
+ * 1 or 2 bytes show up in practice, but they're not at
+ * all well understood yet.
+ */
+ private int[] encodeCurve() {
+ // most examples of curve data are a single byte that encodes
+ // the final heading of the arc. The bits appear to be
+ // reorganised into the order 21076543 (i.e. the top 5 bits
+ // are shifted down to the bottom). Unfortunately, it's not
+ // that simple because sometimes the curve is encoded using 2
+ // bytes. The presence of the 2nd byte is indicated by the top
+ // 3 bits of the first byte all being zero. As the encoding of
+ // the 2-byte variant is not yet understood, for the moment,
+ // if the resulting value would have the top 3 bits all zero,
+ // we set what we hope is the LSB so that it becomes valid
+ // 1-byte curve data
+ int heading = 256 * finalHeading / 360;
+ int encodedHeading = ((heading & 0xf8) >> 3) | ((heading & 0x07) << 5);
+ if((encodedHeading & 0xe0) == 0) {
+ // hack - set a bit (hopefully, the LSB) to force 1-byte
+ // encoding
+ encodedHeading |= 0x20;
+ }
+ int[] curveData = new int[1];
+ curveData[0] = encodedHeading;
+ return curveData;
+ }
+
+ public RoadDef getRoadDef() {
+ return roadDef;
+ }
+
+ public void setNewDir() {
+ flagA |= FLAG_NEWDIR;
+ }
+
+ public void setForward() {
+ flagA |= FLAG_FORWARD;
+ }
+
+ public boolean isForward() {
+ return (flagA & FLAG_FORWARD) != 0;
+ }
+
+ public void setLast() {
+ flagB |= FLAG_LAST_LINK;
+ }
+
+ protected void setDestinationClass(int destinationClass) {
+ if(log.isDebugEnabled())
+ log.debug("setting destination class", destinationClass);
+ flagA |= (destinationClass & MASK_DESTCLASS);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/RouteCenter.java b/src/uk/me/parabola/imgfmt/app/net/RouteCenter.java
new file mode 100644
index 0000000..84ea542
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/RouteCenter.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2008
+ *
+ * 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.
+ *
+ * Create date: 07-Jul-2008
+ */
+package uk.me.parabola.imgfmt.app.net;
+
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.log.Logger;
+
+/**
+ * Routing nodes are divided into areas which I am calling RouteCenter's.
+ * The center has a location and it contains nodes that are nearby.
+ * There is routing between nodes in the center and there are links
+ * to nodes in other centers.
+ */
+public class RouteCenter {
+ private static final Logger log = Logger.getLogger(RouteCenter.class);
+
+ private final Area area;
+ private final Coord centralPoint;
+
+ private final List<RouteNode> nodes;
+
+ private final TableA tabA;
+ private final TableB tabB;
+ private final TableC tabC;
+
+ public RouteCenter(Area area, List<RouteNode> nodes,
+ TableA tabA, TableB tabB) {
+
+ this.area = area;
+ this.centralPoint = area.getCenter();
+ this.nodes = nodes;
+ this.tabA = tabA;
+ this.tabB = tabB;
+ this.tabC = new TableC(tabA);
+
+ log.info("new RouteCenter at " + centralPoint.toDegreeString() +
+ ", nodes: " + nodes.size() + " tabA: " + tabA.size() +
+ " tabB: " + tabB.size());
+
+ // update lat/lon offsets; update arcs with table indices; populate tabC
+ for (RouteNode node : nodes) {
+ node.setOffsets(centralPoint);
+ for (RouteArc arc : node.arcsIteration()) {
+ arc.setIndexA(tabA.getIndex(arc));
+ if (!arc.isInternal())
+ arc.setIndexB(tabB.getIndex(arc.getDest()));
+ }
+ for (RouteRestriction restr : node.getRestrictions())
+ restr.setOffsetC(tabC.addRestriction(restr));
+ }
+ // update size of tabC offsets, now that tabC has been populated
+ tabC.propagateSizeBytes();
+ }
+
+ /**
+ * Write a route center.
+ *
+ * writer.position() is relative to the start of NOD 1.
+ * Space for Table A is reserved but not written. See writeTableA.
+ */
+ public void write(ImgFileWriter writer) {
+ assert !nodes.isEmpty(): "RouteCenter without nodes";
+
+ for (RouteNode node : nodes)
+ node.write(writer);
+
+ int mult = 1 << NODHeader.DEF_ALIGN;
+
+ // Get the position of the tables, and position there.
+ int roundpos = (writer.position() + mult - 1)
+ >> NODHeader.DEF_ALIGN
+ << NODHeader.DEF_ALIGN;
+ int tablesOffset = roundpos + mult;
+ log.debug("write table a at offset", Integer.toHexString(tablesOffset));
+
+ // Go back and fill in all the table offsets
+ for (RouteNode node : nodes) {
+ int pos = node.getOffsetNod1();
+ log.debug("node pos", pos);
+ byte bo = (byte) calcLowByte(pos, tablesOffset);
+
+ writer.position(pos);
+ log.debug("rewrite taba offset", writer.position(), bo);
+ writer.put(bo);
+
+ // fill in arc pointers
+ node.writeSecond(writer);
+ }
+
+ writer.position(tablesOffset);
+
+ // Write the tables header
+ writer.put(tabC.getFormat());
+ writer.put3(centralPoint.getLongitude());
+ writer.put3(centralPoint.getLatitude());
+ writer.put(tabA.getNumberOfItems());
+ writer.put(tabB.getNumberOfItems());
+
+ tabA.write(writer);
+ tabB.write(writer);
+ tabC.write(writer, tablesOffset);
+ log.info("end of center:", writer.position());
+ }
+
+ public void writePost(ImgFileWriter writer) {
+ // NET addresses are now known
+ tabA.writePost(writer);
+ // all RouteNodes now have their NOD1 offsets
+ tabB.writePost(writer);
+ }
+
+ /**
+ * Inverse of calcTableOffset.
+ */
+ private static int calcLowByte(int nodeOffset, int tablesOffset) {
+ assert nodeOffset < tablesOffset;
+ int align = NODHeader.DEF_ALIGN;
+ int mask = (1 << align) - 1;
+ if ((tablesOffset & mask) != 0) {
+ log.warn("tablesOffset not a multiple of (1<<align): %x", tablesOffset);
+ // round up to next multiple
+ tablesOffset = ((tablesOffset >> align) + 1) << align;
+ }
+ int low = (tablesOffset >> align) - (nodeOffset >> align) - 1;
+ assert 0 <= low && low < 0x100;
+ return low;
+ }
+
+ public Area getArea() {
+ return area;
+ }
+
+ public String reportSizes() {
+ int nodesSize = 0;
+ for(RouteNode n : nodes)
+ nodesSize += n.boundSize();
+ return "n=(" + nodes.size() + "," + nodesSize + "), a=" + tabA.size() + ", b=" + tabB.size();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/RouteNode.java b/src/uk/me/parabola/imgfmt/app/net/RouteNode.java
new file mode 100644
index 0000000..23370de
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/RouteNode.java
@@ -0,0 +1,858 @@
+/*
+ * Copyright (C) 2008
+ *
+ * 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.
+ *
+ * Create date: 07-Jul-2008
+ */
+package uk.me.parabola.imgfmt.app.net;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.CoordNode;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.log.Logger;
+
+/**
+ * A routing node with its connections to other nodes via roads.
+ *
+ * @author Steve Ratcliffe
+ */
+public class RouteNode implements Comparable<RouteNode> {
+ private static final Logger log = Logger.getLogger(RouteNode.class);
+
+ /*
+ * 1. instantiate
+ * 2. setCoord, addArc
+ * arcs, coords set
+ * 3. write
+ * node offsets set in all nodes
+ * 4. writeSecond
+ */
+
+ // Values for the first flag byte at offset 1
+ private static final int F_BOUNDARY = 0x08;
+ private static final int F_RESTRICTIONS = 0x10;
+ private static final int F_LARGE_OFFSETS = 0x20;
+ private static final int F_ARCS = 0x40;
+ private static final int F_UNK_NEEDED = 0x04; // XXX
+ // only used internally in mkgmap
+ private static final int F_DISCARDED = 0x100; // node has been discarded
+
+ private static final int MAX_MAIN_ROAD_HEADING_CHANGE = 120;
+ private static final int MIN_DIFF_BETWEEN_OUTGOING_AND_OTHER_ARCS = 45;
+ private static final int MIN_DIFF_BETWEEN_INCOMING_AND_OTHER_ARCS = 50;
+
+ private int offsetNod1 = -1;
+
+ // arcs from this node
+ private final List<RouteArc> arcs = new ArrayList<RouteArc>(4);
+ // restrictions at (via) this node
+ private final List<RouteRestriction> restrictions = new ArrayList<RouteRestriction>(4);
+ // arcs to this node
+ private final List<RouteArc> incomingArcs = new ArrayList<RouteArc>(4);
+
+ private int flags = F_UNK_NEEDED;
+
+ private final CoordNode coord;
+ private char latOff;
+ private char lonOff;
+ private List<RouteArc[]> throughRoutes;
+
+ // this is for setting destination class on arcs
+ // we're taking the maximum of roads this node is
+ // on for now -- unsure of precise mechanic
+ private int nodeClass;
+
+ public RouteNode(Coord coord) {
+ this.coord = (CoordNode) coord;
+ setBoundary(this.coord.getOnBoundary());
+ }
+
+ private boolean haveLargeOffsets() {
+ return (flags & F_LARGE_OFFSETS) != 0;
+ }
+
+ protected void setBoundary(boolean b) {
+ if (b)
+ flags |= F_BOUNDARY;
+ else
+ flags &= (~F_BOUNDARY) & 0xff;
+ }
+
+ public boolean isBoundary() {
+ return (flags & F_BOUNDARY) != 0;
+ }
+
+ public void addArc(RouteArc arc) {
+ if (!arcs.isEmpty())
+ arc.setNewDir();
+ arcs.add(arc);
+ int cl = arc.getRoadDef().getRoadClass();
+ if(log.isDebugEnabled())
+ log.debug("adding arc", arc.getRoadDef(), cl);
+ if (cl > nodeClass)
+ nodeClass = cl;
+ flags |= F_ARCS;
+ }
+
+ public void addIncomingArc(RouteArc arc) {
+ incomingArcs.add(arc);
+ }
+
+ public void addRestriction(RouteRestriction restr) {
+ restrictions.add(restr);
+ flags |= F_RESTRICTIONS;
+ }
+
+ public RouteArc getArcTo(RouteNode otherNode) {
+ for(RouteArc a : arcs)
+ if(a.getDest() == otherNode)
+ return a;
+
+ return null;
+ }
+
+ /**
+ * Provide an upper bound to the size (in bytes) that
+ * writing this node will take.
+ *
+ * Should be called only after arcs and restrictions
+ * have been set. The size of arcs depends on whether
+ * or not they are internal to the RoutingCenter.
+ */
+ public int boundSize() {
+ return 1 // table pointer
+ + 1 // flags
+ + 4 // assume large offsets required
+ + arcsSize()
+ + restrSize();
+ }
+
+ private int arcsSize() {
+ int s = 0;
+ for (RouteArc arc : arcs) {
+ s += arc.boundSize();
+ }
+ return s;
+ }
+
+ private int restrSize() {
+ return 2*restrictions.size();
+ }
+
+ /**
+ * Writes a nod1 entry.
+ */
+ public void write(ImgFileWriter writer) {
+ if(log.isDebugEnabled())
+ log.debug("writing node, first pass, nod1", coord.getId());
+ offsetNod1 = writer.position();
+ assert offsetNod1 < 0x1000000 : "node offset doesn't fit in 3 bytes";
+
+ assert (flags & F_DISCARDED) == 0 : "attempt to write discarded node";
+
+ writer.put((byte) 0); // will be overwritten later
+ writer.put((byte) flags);
+
+ if (haveLargeOffsets()) {
+ writer.putInt((latOff << 16) | (lonOff & 0xffff));
+ } else {
+ writer.put3((latOff << 12) | (lonOff & 0xfff));
+ }
+
+ if (!arcs.isEmpty()) {
+ arcs.get(arcs.size() - 1).setLast();
+ for (RouteArc arc : arcs)
+ arc.write(writer);
+ }
+
+ if (!restrictions.isEmpty()) {
+ restrictions.get(restrictions.size() - 1).setLast();
+ for (RouteRestriction restr : restrictions)
+ restr.writeOffset(writer);
+ }
+ }
+
+ /**
+ * Writes a nod3 entry.
+ */
+ public void writeNod3(ImgFileWriter writer) {
+ assert isBoundary() : "trying to write nod3 for non-boundary node";
+
+ writer.put3(coord.getLongitude());
+ writer.put3(coord.getLatitude() + 0x800000); // + 180 degrees
+ writer.put3(offsetNod1);
+ }
+
+ public void discard() {
+ // mark the node as having been discarded
+ flags |= F_DISCARDED;
+ }
+
+ public int getOffsetNod1() {
+ if((flags & F_DISCARDED) != 0) {
+ // return something so that the program can continue
+ return 0;
+ }
+ assert offsetNod1 != -1: "failed for node " + coord.getId() + " at " + coord.toDegreeString();
+ return offsetNod1;
+ }
+
+ public void setOffsets(Coord centralPoint) {
+ if(log.isDebugEnabled())
+ log.debug("center", centralPoint, ", coord", coord.toDegreeString());
+ setLatOff(coord.getLatitude() - centralPoint.getLatitude());
+ setLonOff(coord.getLongitude() - centralPoint.getLongitude());
+ }
+
+ public Coord getCoord() {
+ return coord;
+ }
+
+ private void checkOffSize(int off) {
+ if (off > 0x7ff || off < -0x800)
+ // does off fit in signed 12 bit quantity?
+ flags |= F_LARGE_OFFSETS;
+ // does off fit in signed 16 bit quantity?
+ assert (off <= 0x7fff && off >= -0x8000);
+ }
+
+ private void setLatOff(int latOff) {
+ if(log.isDebugEnabled())
+ log.debug("lat off", Integer.toHexString(latOff));
+ this.latOff = (char) latOff;
+ checkOffSize(latOff);
+ }
+
+ private void setLonOff(int lonOff) {
+ if(log.isDebugEnabled())
+ log.debug("long off", Integer.toHexString(lonOff));
+ this.lonOff = (char) lonOff;
+ checkOffSize(lonOff);
+ }
+
+ /**
+ * Second pass over the nodes. Fill in pointers and Table A indices.
+ */
+ public void writeSecond(ImgFileWriter writer) {
+ for (RouteArc arc : arcs)
+ arc.writeSecond(writer);
+ }
+
+ /**
+ * Return the node's class, which is the maximum of
+ * classes of the roads it's on.
+ */
+ public int getNodeClass() {
+ return nodeClass;
+ }
+
+ public Iterable<? extends RouteArc> arcsIteration() {
+ return new Iterable<RouteArc>() {
+ public Iterator<RouteArc> iterator() {
+ return arcs.iterator();
+ }
+ };
+ }
+
+ public List<RouteRestriction> getRestrictions() {
+ return restrictions;
+ }
+
+ public String toString() {
+ return String.valueOf(coord.getId());
+ }
+
+ /*
+ * For sorting node entries in NOD 3.
+ */
+ public int compareTo(RouteNode otherNode) {
+ return coord.compareTo(otherNode.getCoord());
+ }
+
+ private static boolean possiblySameRoad(RouteArc raa, RouteArc rab) {
+
+ RoadDef rda = raa.getRoadDef();
+ RoadDef rdb = rab.getRoadDef();
+
+ if(rda.getId() == rdb.getId()) {
+ // roads have the same (OSM) id
+ return true;
+ }
+
+ boolean bothArcsNamed = false;
+ for(Label laba : rda.getLabels()) {
+ if(laba != null && laba.getOffset() != 0) {
+ for(Label labb : rdb.getLabels()) {
+ if(labb != null && labb.getOffset() != 0) {
+ bothArcsNamed = true;
+ if(laba.equals(labb)) {
+ // the roads have the same name
+ if(rda.isLinkRoad() == rdb.isLinkRoad()) {
+ // if both are a link road or both are
+ // not a link road, consider them the
+ // same road
+ return true;
+ }
+ // One is a link road and the other isn't
+ // so consider them different roads - this
+ // is because people often give a link
+ // road that's leaving some road the same
+ // ref as that road but it suits us better
+ // to consider them as different roads
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ if(bothArcsNamed) {
+ // both roads have names and they don't match
+ return false;
+ }
+
+ // at least one road is unnamed
+ if(rda.isRoundabout() && rdb.isRoundabout()) {
+ // hopefully, segments of the same (unnamed) roundabout
+ return true;
+ }
+
+ return false;
+ }
+
+ private static boolean rightTurnRequired(int inHeading, int outHeading, int sideHeading) {
+ // given the headings of the incoming, outgoing and side
+ // roads, decide whether a side road is to the left or the
+ // right of the main road
+
+ outHeading -= inHeading;
+ while(outHeading < -180)
+ outHeading += 360;
+ while(outHeading > 180)
+ outHeading -= 360;
+
+ sideHeading -= inHeading;
+ while(sideHeading < -180)
+ sideHeading += 360;
+ while(sideHeading > 180)
+ sideHeading -= 360;
+
+ return sideHeading > outHeading;
+ }
+
+ private static final int ATH_OUTGOING = 1;
+ private static final int ATH_INCOMING = 2;
+
+ public static final int ATH_DEFAULT_MASK = ATH_OUTGOING | ATH_INCOMING;
+
+ public void tweezeArcs(int mask) {
+ if(arcs.size() >= 3) {
+
+ // detect the "shallow turn" scenario where at a junction
+ // on some "main" road, the side road leaves the main
+ // road at a very shallow angle and the GPS says "keep
+ // right/left" when it would be better if it said "turn
+ // right/left"
+
+ // also helps to produce a turn instruction when the main
+ // road bends sharply but the side road keeps close to the
+ // original heading
+
+ // the code tries to detect a pair of arcs (the "incoming"
+ // arc and the "outgoing" arc) that are the "main road"
+ // and the remaining arc (called the "other" arc) which is
+ // the "side road"
+
+ // having worked out the roles for the arcs, the heuristic
+ // applied is that if the main road doesn't change its
+ // heading by more than maxMainRoadHeadingChange, ensure
+ // that the side road heading differs from the outgoing
+ // heading by at least
+ // minDiffBetweenOutgoingAndOtherArcs and the side road
+ // heading differs from the incoming heading by at least
+ // minDiffBetweenIncomingAndOtherArcs
+
+ // list of outgoing arcs discovered at this node
+ List<RouteArc> outgoingArcs = new ArrayList<RouteArc>();
+
+ // sort incoming arcs by decreasing class/speed
+ List<RouteArc> inArcs = new ArrayList<RouteArc>(incomingArcs);
+
+ Collections.sort(inArcs, new Comparator<RouteArc>() {
+ public int compare(RouteArc ra1, RouteArc ra2) {
+ int c1 = ra1.getRoadDef().getRoadClass();
+ int c2 = ra2.getRoadDef().getRoadClass();
+ if(c1 == c2)
+ return (ra2.getRoadDef().getRoadSpeed() -
+ ra1.getRoadDef().getRoadSpeed());
+ return c2 - c1;
+ }
+ });
+
+ // look at incoming arcs in order of decreasing class/speed
+ for(RouteArc inArc : inArcs) {
+
+ RoadDef inRoadDef = inArc.getRoadDef();
+
+ if(!inArc.isForward() && inRoadDef.isOneway()) {
+ // ignore reverse arc if road is oneway
+ continue;
+ }
+
+ int inHeading = inArc.getFinalHeading();
+ // determine the outgoing arc that is likely to be the
+ // same road as the incoming arc
+ RouteArc outArc = null;
+
+ if(throughRoutes != null) {
+ // through_route relations have the highest precedence
+ for(RouteArc[] pair : throughRoutes) {
+ if(pair[0] == inArc) {
+ outArc = pair[1];
+ log.info("Found through route from " + inRoadDef + " to " + outArc.getRoadDef());
+ break;
+ }
+ }
+ }
+
+ if(outArc == null) {
+ // next, if oa has the same RoadDef as inArc, it's
+ // definitely the same road
+ for(RouteArc oa : arcs) {
+ if(oa.getDest() != inArc.getSource()) {
+ // this arc is not going to the same node as
+ // inArc came from
+ if(oa.getRoadDef() == inRoadDef) {
+ outArc = oa;
+ break;
+ }
+ }
+ }
+ }
+
+ if(outArc == null) {
+ // next, although the RoadDefs don't match, use
+ // possiblySameRoad() to see if the roads' id or
+ // labels (names/refs) match
+ for(RouteArc oa : arcs) {
+ if(oa.getDest() != inArc.getSource()) {
+ // this arc is not going to the same node as
+ // inArc came from
+ if((oa.isForward() || !oa.getRoadDef().isOneway()) &&
+ possiblySameRoad(inArc, oa)) {
+ outArc = oa;
+ break;
+ }
+ }
+ }
+ }
+
+ if(false && outArc == null) {
+ // last ditch attempt to find the outgoing arc -
+ // try and find a single arc that has the same
+ // road class and speed as the incoming arc
+ int inArcClass = inArc.getRoadDef().getRoadClass();
+ int inArcSpeed = inArc.getRoadDef().getRoadSpeed();
+ for(RouteArc oa : arcs) {
+ if(oa.getDest() != inArc.getSource() &&
+ oa.getRoadDef().getRoadClass() == inArcClass &&
+ oa.getRoadDef().getRoadSpeed() == inArcSpeed) {
+ if(outArc != null) {
+ // multiple arcs have the same road
+ // class/speed as the incoming arc so
+ // don't use any of them as the
+ // outgoing arc
+ outArc = null;
+ break;
+ }
+ // oa has the same class/speed as inArc,
+ // now check that oa is not part of
+ // another road by matching names rather
+ // than class/speed because they could be
+ // different
+ boolean paired = false;
+ for(RouteArc z : arcs)
+ if(z != oa && possiblySameRoad(z, oa))
+ paired = true;
+ if(!paired)
+ outArc = oa;
+ }
+ }
+ if(outArc != null)
+ log.info("Matched outgoing arc " + outArc.getRoadDef() + " to " + inRoadDef + " using road class (" + inArcClass + ") and speed (" + inArcSpeed + ") at " + coord.toOSMURL());
+ }
+
+ // if we did not find the outgoing arc, give up with
+ // this incoming arc
+ if(outArc == null) {
+ //log.info("Can't continue road " + inRoadDef + " at " + coord.toOSMURL());
+ continue;
+ }
+
+ // remember that this arc is an outgoing arc
+ outgoingArcs.add(outArc);
+
+ int outHeading = outArc.getInitialHeading();
+ int mainHeadingDelta = outHeading - inHeading;
+ while(mainHeadingDelta > 180)
+ mainHeadingDelta -= 360;
+ while(mainHeadingDelta < -180)
+ mainHeadingDelta += 360;
+ //log.info(inRoadDef + " continues to " + outArc.getRoadDef() + " with a heading change of " + mainHeadingDelta + " at " + coord.toOSMURL());
+
+ if(Math.abs(mainHeadingDelta) > MAX_MAIN_ROAD_HEADING_CHANGE) {
+ // if the continuation road heading change is
+ // greater than maxMainRoadHeadingChange don't
+ // adjust anything
+ continue;
+ }
+
+ for(RouteArc otherArc : arcs) {
+
+ // for each other arc leaving this node, tweeze
+ // its heading if its heading change from the
+ // outgoing heading is less than
+ // minDiffBetweenOutgoingAndOtherArcs or its
+ // heading change from the incoming heading is
+ // less than minDiffBetweenIncomingAndOtherArcs
+
+ if(otherArc.getDest() == inArc.getSource() ||
+ otherArc == outArc) {
+ // we're looking at the incoming or outgoing
+ // arc, ignore it
+ continue;
+ }
+
+ if(!otherArc.isForward() &&
+ otherArc.getRoadDef().isOneway()) {
+ // ignore reverse arc if road is oneway
+ continue;
+ }
+
+ if(inRoadDef.isLinkRoad() &&
+ otherArc.getRoadDef().isLinkRoad()) {
+ // it's a link road leaving a link road so
+ // leave the angle unchanged to avoid
+ // introducing a time penalty by increasing
+ // the angle (this stops the router using link
+ // roads that "cut the corner" at roundabouts)
+ continue;
+ }
+
+ if(outgoingArcs.contains(otherArc)) {
+ // this arc was previously matched as an
+ // outgoing arc so we don't want to change its
+ // heading now
+ continue;
+ }
+
+ int otherHeading = otherArc.getInitialHeading();
+ int outToOtherDelta = otherHeading - outHeading;
+ while(outToOtherDelta > 180)
+ outToOtherDelta -= 360;
+ while(outToOtherDelta < -180)
+ outToOtherDelta += 360;
+ int inToOtherDelta = otherHeading - inHeading;
+ while(inToOtherDelta > 180)
+ inToOtherDelta -= 360;
+ while(inToOtherDelta < -180)
+ inToOtherDelta += 360;
+
+ int newHeading = otherHeading;
+ if(rightTurnRequired(inHeading, outHeading, otherHeading)) {
+ // side road to the right
+ if((mask & ATH_OUTGOING) != 0 &&
+ Math.abs(outToOtherDelta) < MIN_DIFF_BETWEEN_OUTGOING_AND_OTHER_ARCS)
+ newHeading = outHeading + MIN_DIFF_BETWEEN_OUTGOING_AND_OTHER_ARCS;
+ if((mask & ATH_INCOMING) != 0 &&
+ Math.abs(inToOtherDelta) < MIN_DIFF_BETWEEN_INCOMING_AND_OTHER_ARCS) {
+ int nh = inHeading + MIN_DIFF_BETWEEN_INCOMING_AND_OTHER_ARCS;
+ if(nh > newHeading)
+ newHeading = nh;
+ }
+
+ if(newHeading > 180)
+ newHeading -= 360;
+ }
+ else {
+ // side road to the left
+ if((mask & ATH_OUTGOING) != 0 &&
+ Math.abs(outToOtherDelta) < MIN_DIFF_BETWEEN_OUTGOING_AND_OTHER_ARCS)
+ newHeading = outHeading - MIN_DIFF_BETWEEN_OUTGOING_AND_OTHER_ARCS;
+ if((mask & ATH_INCOMING) != 0 &&
+ Math.abs(inToOtherDelta) < MIN_DIFF_BETWEEN_INCOMING_AND_OTHER_ARCS) {
+ int nh = inHeading - MIN_DIFF_BETWEEN_INCOMING_AND_OTHER_ARCS;
+ if(nh < newHeading)
+ newHeading = nh;
+ }
+
+ if(newHeading < -180)
+ newHeading += 360;
+ }
+ if(newHeading != otherHeading) {
+ otherArc.setInitialHeading(newHeading);
+ log.info("Adjusting turn heading from " + otherHeading + " to " + newHeading + " at junction of " + inRoadDef + " and " + otherArc.getRoadDef() + " at " + coord.toOSMURL());
+ }
+ }
+ }
+ }
+ }
+
+ public void checkRoundabouts() {
+
+ List<RouteArc> roundaboutArcs = new ArrayList<RouteArc>();
+
+ for(RouteArc a : arcs) {
+ // ignore ways that have been synthesised by mkgmap
+ if(!a.getRoadDef().isSynthesised() &&
+ a.getRoadDef().isRoundabout()) {
+ roundaboutArcs.add(a);
+ }
+ }
+
+ if(arcs.size() > 1 && roundaboutArcs.size() == 1) {
+ if(roundaboutArcs.get(0).isForward())
+ log.warn("Roundabout " + roundaboutArcs.get(0).getRoadDef() + " starts at " + coord.toOSMURL());
+ else
+ log.warn("Roundabout " + roundaboutArcs.get(0).getRoadDef() + " ends at " + coord.toOSMURL());
+ }
+
+ if(roundaboutArcs.size() > 2) {
+ for(RouteArc fa : arcs) {
+ if(fa.isForward()) {
+ RoadDef rd = fa.getRoadDef();
+ for(RouteArc fb : arcs) {
+ if(fb != fa &&
+ fa.getPointsHash() == fb.getPointsHash() &&
+ ((fb.isForward() && fb.getDest() == fa.getDest()) ||
+ (!fb.isForward() && fb.getSource() == fa.getDest()))) {
+ if(!rd.messagePreviouslyIssued("roundabout forks/overlaps")) {
+ log.warn("Roundabout " + rd + " overlaps " + fb.getRoadDef() + " at " + coord.toOSMURL());
+ }
+ }
+ else if(fa != fb && fb.isForward()) {
+ if(!rd.messagePreviouslyIssued("roundabout forks/overlaps")) {
+ log.warn("Roundabout " + rd + " forks at " + coord.toOSMURL());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // determine "distance" between two nodes on a roundabout
+ private int roundaboutSegmentLength(final RouteNode n1, final RouteNode n2) {
+ List<RouteNode> seen = new ArrayList<RouteNode>();
+ int len = 0;
+ RouteNode n = n1;
+ boolean checkMoreLinks = true;
+ while(checkMoreLinks && !seen.contains(n)) {
+ checkMoreLinks = false;
+ seen.add(n);
+ for(RouteArc a : n.arcs) {
+ if(a.isForward() &&
+ a.getRoadDef().isRoundabout() &&
+ !a.getRoadDef().isSynthesised()) {
+ len += a.getLength();
+ n = a.getDest();
+ if(n == n2)
+ return len;
+ checkMoreLinks = true;
+ break;
+ }
+ }
+ }
+ // didn't find n2
+ return Integer.MAX_VALUE;
+ }
+
+ // sanity check roundabout flare roads - the flare roads connect a
+ // two-way road to a roundabout using short one-way segments so
+ // the resulting sub-junction looks like a triangle with two
+ // corners of the triangle being attached to the roundabout and
+ // the last corner being connected to the two-way road
+
+ public void checkRoundaboutFlares(int maxFlareLengthRatio) {
+ for(RouteArc r : arcs) {
+ // see if node has a forward arc that is part of a
+ // roundabout
+ if(!r.isForward() || !r.getRoadDef().isRoundabout() || r.getRoadDef().isSynthesised())
+ continue;
+
+ // follow the arc to find the first node that connects the
+ // roundabout to a non-roundabout segment
+ RouteNode nb = r.getDest();
+ List<RouteNode> seen = new ArrayList<RouteNode>();
+ seen.add(this);
+
+ while (true) {
+
+ if (seen.contains(nb)) {
+ // looped - give up
+ nb = null;
+ break;
+ }
+
+ // remember we have seen this node
+ seen.add(nb);
+
+ boolean connectsToNonRoundaboutSegment = false;
+ RouteArc nextRoundaboutArc = null;
+ for (RouteArc nba : nb.arcs) {
+ if (!nba.getRoadDef().isSynthesised()) {
+ if (nba.getRoadDef().isRoundabout()) {
+ if (nba.isForward())
+ nextRoundaboutArc = nba;
+ } else
+ connectsToNonRoundaboutSegment = true;
+ }
+ }
+
+ if (connectsToNonRoundaboutSegment) {
+ // great, that's what we're looking for
+ break;
+ }
+
+ if (nextRoundaboutArc == null) {
+ // not so good, the roundabout stops in mid air?
+ nb = null;
+ break;
+ }
+
+ nb = nextRoundaboutArc.getDest();
+ }
+
+ if(nb == null) {
+ // something is not right so give up
+ continue;
+ }
+
+ // now try and find the two arcs that make up the
+ // triangular "flare" connected to both ends of the
+ // roundabout segment
+ for(RouteArc fa : arcs) {
+ if(!fa.getRoadDef().doFlareCheck())
+ continue;
+
+ for(RouteArc fb : nb.arcs) {
+ if(!fb.getRoadDef().doFlareCheck())
+ continue;
+ if(fa.getDest() == fb.getDest()) {
+ // found the 3rd point of the triangle that
+ // should be connecting the two flare roads
+
+ // first, special test required to cope with
+ // roundabouts that have a single flare and no
+ // other connections - only check the flare
+ // for the shorter of the two roundabout
+ // segments
+
+ if(roundaboutSegmentLength(this, nb) >=
+ roundaboutSegmentLength(nb, this))
+ continue;
+
+ if(maxFlareLengthRatio > 0) {
+ // if both of the flare roads are much
+ // longer than the length of the
+ // roundabout segment, they are probably
+ // not flare roads at all but just two
+ // roads that meet up - so ignore them
+ final int maxFlareLength = roundaboutSegmentLength(this, nb) * maxFlareLengthRatio;
+ if(maxFlareLength > 0 &&
+ fa.getLength() > maxFlareLength &&
+ fb.getLength() > maxFlareLength) {
+ continue;
+ }
+ }
+
+ // now check the flare roads for direction and
+ // oneway
+
+ // only issue one warning per flare
+ if(!fa.isForward())
+ log.warn("Outgoing roundabout flare road " + fa.getRoadDef() + " points in wrong direction? " + fa.getSource().coord.toOSMURL());
+ else if(fb.isForward())
+ log.warn("Incoming roundabout flare road " + fb.getRoadDef() + " points in wrong direction? " + fb.getSource().coord.toOSMURL());
+ else if(!fa.getRoadDef().isOneway())
+ log.warn("Outgoing roundabout flare road " + fa.getRoadDef() + " is not oneway? " + fa.getSource().coord.toOSMURL());
+
+ else if(!fb.getRoadDef().isOneway())
+ log.warn("Incoming roundabout flare road " + fb.getRoadDef() + " is not oneway? " + fb.getDest().coord.toOSMURL());
+ else {
+ // check that the flare road arcs are not
+ // part of a longer way
+ for(RouteArc a : fa.getDest().arcs) {
+ if(a.getDest() != this && a.getDest() != nb) {
+ if(a.getRoadDef() == fa.getRoadDef())
+ log.warn("Outgoing roundabout flare road " + fb.getRoadDef() + " does not finish at flare? " + fa.getDest().coord.toOSMURL());
+ else if(a.getRoadDef() == fb.getRoadDef())
+ log.warn("Incoming roundabout flare road " + fb.getRoadDef() + " does not start at flare? " + fb.getDest().coord.toOSMURL());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void reportSimilarArcs() {
+ for(int i = 0; i < arcs.size(); ++i) {
+ RouteArc arci = arcs.get(i);
+ for(int j = i + 1; j < arcs.size(); ++j) {
+ RouteArc arcj = arcs.get(j);
+ if(arci.getDest() == arcj.getDest() &&
+ arci.getLength() == arcj.getLength() &&
+ arci.getPointsHash() == arcj.getPointsHash()) {
+ log.warn("Similar arcs (" + arci.getRoadDef() + " and " + arcj.getRoadDef() + ") from " + coord.toOSMURL());
+ }
+ }
+ }
+ }
+
+ public void addThroughRoute(long roadIdA, long roadIdB) {
+ if(throughRoutes == null)
+ throughRoutes = new ArrayList<RouteArc[]>();
+ boolean success = false;
+ for(RouteArc arc1 : incomingArcs) {
+ if(arc1.getRoadDef().getId() == roadIdA) {
+ for(RouteArc arc2 : arcs) {
+ if(arc2.getRoadDef().getId() == roadIdB) {
+ throughRoutes.add(new RouteArc[] { arc1, arc2 });
+ success = true;
+ break;
+ }
+ }
+ }
+ else if(arc1.getRoadDef().getId() == roadIdB) {
+ for(RouteArc arc2 : arcs) {
+ if(arc2.getRoadDef().getId() == roadIdA) {
+ throughRoutes.add(new RouteArc[] { arc1, arc2 });
+ success = true;
+ break;
+ }
+ }
+ }
+ }
+ if(success)
+ log.info("Added through route between ways " + roadIdA + " and " + roadIdB + " at " + coord.toOSMURL());
+ else
+ log.warn("Failed to add through route between ways " + roadIdA + " and " + roadIdB + " at " + coord.toOSMURL() + " - perhaps they don't meet here?");
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/RouteRestriction.java b/src/uk/me/parabola/imgfmt/app/net/RouteRestriction.java
new file mode 100644
index 0000000..3e29076
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/RouteRestriction.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2008
+ *
+ * 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.
+ *
+ * Create date: 07-Jul-2008
+ */
+package uk.me.parabola.imgfmt.app.net;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * A restriction in the routing graph.
+ *
+ * There may eventually be several types of these at which point
+ * we might consider splitting them into several classes. For the
+ * moment, just simple from-to-via restrictions.
+ *
+ * A from-to-via restriction says you can't go along arc "to"
+ * if you came to node to.getSource() == from.getSource()
+ * via the inverse arc of "from". We're using the inverse of
+ * "from" since that has the information we need for writing
+ * the Table C entry.
+ *
+ * @author Robert Vollmert
+ */
+public class RouteRestriction {
+ //private static final Logger log = Logger.getLogger(RouteRestriction.class);
+
+ // size in bytes
+ private static final int SIZE = 11;
+
+ // first three bytes of the header -- might specify the type of restriction
+ // and when it is active
+ private static final int HEADER = 0x004005;
+
+ // To specify that a node is given by a relative offset instead
+ // of an entry to Table B.
+ private static final int F_INTERNAL = 0x8000;
+
+ // the arcs
+ private final RouteArc from;
+ private final RouteArc to;
+
+ // offset in Table C
+ private byte offsetSize;
+ private int offsetC;
+
+ // last restriction in a node
+ private boolean last;
+
+ // mask that specifies which vehicle types the restriction doesn't apply to
+ private final byte exceptMask;
+
+ public final static byte EXCEPT_CAR = 0x01;
+ public final static byte EXCEPT_BUS = 0x02;
+ public final static byte EXCEPT_TAXI = 0x04;
+ public final static byte EXCEPT_DELIVERY = 0x10;
+ public final static byte EXCEPT_BICYCLE = 0x20;
+ public final static byte EXCEPT_TRUCK = 0x40;
+
+ /**
+ * Create a route restriction.
+ *
+ * @param from The inverse arc of "from" arc.
+ * @param to The "to" arc.
+ */
+ public RouteRestriction(RouteArc from, RouteArc to, byte exceptMask) {
+ assert from.getSource().equals(to.getSource()) : "arcs in restriction don't meet";
+ this.from = from;
+ this.to = to;
+ this.exceptMask = exceptMask;
+ }
+
+ private int calcOffset(RouteNode node, int tableOffset) {
+ int offset = tableOffset - node.getOffsetNod1();
+ assert offset >= 0 : "node behind start of tables";
+ assert offset < 0x8000 : "node offset too large";
+ return offset | F_INTERNAL;
+ }
+
+ /**
+ * Writes a Table C entry.
+ *
+ * @param writer The writer.
+ * @param tableOffset The offset in NOD 1 of the tables area.
+ */
+ public void write(ImgFileWriter writer, int tableOffset) {
+ int header = HEADER;
+
+ if(exceptMask != 0)
+ header |= 0x0800;
+
+ writer.put3(header);
+
+ if(exceptMask != 0)
+ writer.put(exceptMask);
+
+ int[] offsets = new int[3];
+
+ if (from.isInternal())
+ offsets[0] = calcOffset(from.getDest(), tableOffset);
+ else
+ offsets[0] = from.getIndexB();
+ offsets[1] = calcOffset(to.getSource(), tableOffset);
+ if (to.isInternal())
+ offsets[2] = calcOffset(to.getDest(), tableOffset);
+ else
+ offsets[2] = to.getIndexB();
+
+ for (int offset : offsets)
+ writer.putChar((char) offset);
+
+ writer.put(from.getIndexA());
+ writer.put(to.getIndexA());
+ }
+
+ /**
+ * Write this restriction's offset within Table C into a node record.
+ */
+ public void writeOffset(ImgFileWriter writer) {
+ assert 0 < offsetSize && offsetSize <= 2 : "illegal offset size";
+ int offset = offsetC;
+ if (offsetSize == 1) {
+ assert offset < 0x80;
+ if (last)
+ offset |= 0x80;
+ writer.put((byte) offset);
+ } else {
+ assert offset < 0x8000;
+ if (last)
+ offset |= 0x8000;
+ writer.putChar((char) offset);
+ }
+ }
+
+ /**
+ * Size in bytes of the Table C entry.
+ */
+ public int getSize() {
+ int size = SIZE;
+ if(exceptMask != 0)
+ ++size;
+ return size;
+ }
+
+ public void setOffsetC(int offsetC) {
+ this.offsetC = offsetC;
+ }
+
+ public int getOffsetC() {
+ return offsetC;
+ }
+
+ public void setOffsetSize(byte size) {
+ offsetSize = size;
+ }
+
+ public void setLast() {
+ last = true;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/TableA.java b/src/uk/me/parabola/imgfmt/app/net/TableA.java
new file mode 100644
index 0000000..90aa916
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/TableA.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2008 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: 18-Jul-2008
+ */
+package uk.me.parabola.imgfmt.app.net;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.log.Logger;
+
+/**
+ * Table A that contains road information for segments in one RouteCenter.
+ *
+ * Each arc starting from a node in the RouteCenter has an associated
+ * entry in Table A, shared by the inverse arc for internal arcs. This
+ * entry consists of some routing parameters and a link to the road in
+ * NET.
+ */
+public class TableA {
+ private static final Logger log = Logger.getLogger(TableA.class);
+
+ private static final int ITEM_SIZE = 5;
+
+ // This table's start position relative to the start of NOD 1
+ private int offset;
+
+ // arcs for paved ways
+ private final HashMap<Arc,Integer> pavedArcs = new LinkedHashMap<Arc,Integer>();
+ // arcs for unpaved ways
+ private final HashMap<Arc,Integer> unpavedArcs = new LinkedHashMap<Arc,Integer>();
+ // arcs for ferry ways
+ private final HashMap<Arc,Integer> ferryArcs = new LinkedHashMap<Arc,Integer>();
+
+ private static int count;
+
+ private boolean frozen ; // true when no more arcs should be added
+
+ public TableA() {
+ log.debug("creating TableA", count);
+ count++;
+ }
+
+ /**
+ * Internal class tracking all the data a Table A entry needs.
+ * Basically a "forward arc".
+ */
+ private class Arc {
+ final RouteNode first; final RouteNode second;
+ final RoadDef roadDef;
+
+ Arc(RouteArc arc) {
+ if (arc.isForward()) {
+ first = arc.getSource();
+ second = arc.getDest();
+ } else {
+ first = arc.getDest();
+ second = arc.getSource();
+ }
+ roadDef = arc.getRoadDef();
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null || getClass() != obj.getClass()) return false;
+
+ Arc arc = (Arc) obj;
+ return first.equals(arc.first)
+ && second.equals(arc.second)
+ && roadDef.equals(arc.roadDef);
+ }
+
+ public int hashCode() {
+ return first.hashCode() + 2*second.hashCode() + roadDef.hashCode();
+ }
+
+ public String toString() {
+ return "" + first + "->" + second + " (" + roadDef + ")";
+ }
+ }
+
+ /**
+ * Add an arc to the table if not present and set its index.
+ *
+ * The value may overflow while it isn't certain that
+ * the table fulfills the size constraint.
+ */
+ public void addArc(RouteArc arc) {
+ assert !frozen : "trying to add arc to Table A after it has been frozen";
+ Arc narc = new Arc(arc);
+ int i;
+ if(arc.getRoadDef().ferry()) {
+ if (!ferryArcs.containsKey(narc)) {
+ i = ferryArcs.size();
+ ferryArcs.put(narc, i);
+ log.debug("added ferry arc", count, narc, i);
+ }
+ }
+ else if(arc.getRoadDef().paved()) {
+ if (!pavedArcs.containsKey(narc)) {
+ i = pavedArcs.size();
+ pavedArcs.put(narc, i);
+ log.debug("added paved arc", count, narc, i);
+ }
+ }
+ else {
+ if (!unpavedArcs.containsKey(narc)) {
+ i = unpavedArcs.size();
+ unpavedArcs.put(narc, i);
+ log.debug("added unpaved arc", count, narc, i);
+ }
+ }
+ }
+
+ /**
+ * Retrieve an arc's index.
+ */
+ public byte getIndex(RouteArc arc) {
+ frozen = true; // don't allow any more arcs to be added
+ Arc narc = new Arc(arc);
+ int i;
+ if(arc.getRoadDef().ferry()) {
+ assert ferryArcs.containsKey(narc):
+ "Trying to read Table A index for non-registered arc: " + count + " " + narc;
+ i = unpavedArcs.size() + ferryArcs.get(narc);
+ }
+ else if(arc.getRoadDef().paved()) {
+ assert pavedArcs.containsKey(narc):
+ "Trying to read Table A index for non-registered arc: " + count + " " + narc;
+ i = unpavedArcs.size() + ferryArcs.size() + pavedArcs.get(narc);
+ }
+ else {
+ assert unpavedArcs.containsKey(narc):
+ "Trying to read Table A index for non-registered arc: " + count + " " + narc;
+ i = unpavedArcs.get(narc);
+ }
+ assert i < 0x100 : "Table A index too large: " + narc;
+ return (byte) i;
+ }
+
+ /**
+ * Retrieve the size of the Table as an int.
+ *
+ * While Table A is limited to byte size (0x100 entries),
+ * we temporarily build larger tables while subdividing
+ * the network.
+ */
+ public int size() {
+ return ferryArcs.size() + unpavedArcs.size() + pavedArcs.size();
+ }
+
+ public int numUnpavedArcs() {
+ return unpavedArcs.size();
+ }
+
+ public int numFerryArcs() {
+ return ferryArcs.size();
+ }
+
+ /**
+ * Retrieve the size of the table as byte.
+ *
+ * This value is what should be written to the table
+ * header. When this is read, the table is assumed to
+ * be fit for writing, so at this point we check
+ * it isn't too large.
+ */
+ public byte getNumberOfItems() {
+ assert size() < 0x100 : "Table A too large";
+ return (byte)size();
+ }
+
+ /**
+ * This is called first to reserve enough space. It will be rewritten
+ * later.
+ */
+ public void write(ImgFileWriter writer) {
+ offset = writer.position();
+ int size = size() * ITEM_SIZE;
+ log.debug("tab a offset", offset, "tab a size", size);
+
+ for (int i = 0; i < size; i++)
+ writer.put((byte) 0);
+ }
+
+ /**
+ * Fill in the table once the NET offsets of the roads are known.
+ */
+ public void writePost(ImgFileWriter writer) {
+ writer.position(offset);
+ // unpaved arcs first
+ for (Arc arc : unpavedArcs.keySet()) {
+ writePost(writer, arc);
+ }
+ // followed by the ferry arcs
+ for (Arc arc : ferryArcs.keySet()) {
+ writePost(writer, arc);
+ }
+ // followed by the paved arcs
+ for (Arc arc : pavedArcs.keySet()) {
+ writePost(writer, arc);
+ }
+ }
+
+ public void writePost(ImgFileWriter writer, Arc arc) {
+ // write the table A entries. Consists of a pointer to net
+ // followed by 2 bytes of class and speed flags and road restrictions.
+ int pos = arc.roadDef.getOffsetNet1();
+ int access = arc.roadDef.getTabAAccess();
+ // top bits of access go into net1 offset
+ final int ACCESS_TOP_BITS = 0xc000;
+ pos |= (access & ACCESS_TOP_BITS) << 8;
+ access &= ~ACCESS_TOP_BITS;
+ writer.put3(pos);
+ writer.put((byte) arc.roadDef.getTabAInfo());
+ writer.put((byte) access);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/TableB.java b/src/uk/me/parabola/imgfmt/app/net/TableB.java
new file mode 100644
index 0000000..23f63c6
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/TableB.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2008 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: 18-Jul-2008
+ */
+package uk.me.parabola.imgfmt.app.net;
+
+import java.util.ArrayList;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * Table B contains offsets in NOD1 of neighbouring nodes
+ * outside the containing RouteCenter.
+ */
+public class TableB {
+
+ private final ArrayList<RouteNode> nodes = new ArrayList<RouteNode>();
+
+ private final static int ITEM_SIZE = 3;
+
+ private int offset;
+
+ /**
+ * Retrieve the size of the Table as an int.
+ *
+ * While Table B is limited in size (0x100 entries),
+ * we temporarily build larger tables while subdividing
+ * the network.
+ */
+ public int size() {
+ return nodes.size();
+ }
+
+ /**
+ * Retrieve the size of the table as byte.
+ *
+ * This value is what should be written to the table
+ * header. When this is read, the table is assumed to
+ * be fit for writing, so at this point we check
+ * it isn't too large.
+ */
+ public byte getNumberOfItems() {
+ assert nodes.size() < 0x100 : "Table B too large.";
+ return (byte) nodes.size();
+ }
+
+ /**
+ * Add a node (in another RouteCenter) to this Table and return its index.
+ *
+ * This index may overflow while it isn't certain that the
+ * table fulfills the size constraint.
+ */
+ public void addNode(RouteNode node) {
+ int i = nodes.indexOf(node);
+ if (i < 0) {
+ //i = nodes.size();
+ nodes.add(node);
+ }
+ }
+
+ /**
+ * Retrieve a nodes index. Checked for correct bounds.
+ */
+ public byte getIndex(RouteNode node) {
+ int i = nodes.indexOf(node);
+ assert i >= 0 : "Trying to read Table B index for non-registered node.";
+ assert i < 0x100 : "Table B index too large.";
+ return (byte) i;
+ }
+
+ /**
+ * Reserve space, since node offsets in other
+ * RoutingCenters need not be known yet. See writePost.
+ */
+ public void write(ImgFileWriter writer) {
+ offset = writer.position();
+ int size = nodes.size() * ITEM_SIZE;
+ for (int i = 0; i < size; i++)
+ writer.put((byte) 0);
+ }
+
+ /**
+ * Fill in node offsets.
+ */
+ public void writePost(ImgFileWriter writer) {
+ writer.position(offset);
+ for (RouteNode node : nodes)
+ writer.put3(node.getOffsetNod1());
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/TableC.java b/src/uk/me/parabola/imgfmt/app/net/TableC.java
new file mode 100644
index 0000000..c36257c
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/TableC.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008 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, Robert Vollmert
+ * Create date: 18-Jul-2008
+ */
+package uk.me.parabola.imgfmt.app.net;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.FormatException;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * @author Steve Ratcliffe, Robert Vollmert
+ */
+public class TableC {
+ // size of the table, excluding the size field
+ private int size;
+
+ private final TableA tabA;
+
+ private final List<RouteRestriction> restrictions = new ArrayList<RouteRestriction>();
+
+ public TableC(TableA tabA) {
+ this.tabA = tabA;
+ }
+
+ /**
+ * Write the table including size field.
+ */
+ public void write(ImgFileWriter writer, int tablesOffset) {
+ if (restrictions.isEmpty()) {
+ if(tabA.numUnpavedArcs() > 0)
+ writer.put((byte)tabA.numUnpavedArcs());
+ if(tabA.numFerryArcs() > 0)
+ writer.put((byte)tabA.numFerryArcs());
+ writer.put((byte) 0);
+ }
+ else {
+ if (size < 0x100)
+ writer.put((byte) size);
+ else
+ writer.putChar((char) size);
+ for (RouteRestriction restr : restrictions)
+ restr.write(writer, tablesOffset);
+ if(tabA.numUnpavedArcs() > 0)
+ writer.put((byte)tabA.numUnpavedArcs());
+ if(tabA.numFerryArcs() > 0)
+ writer.put((byte)tabA.numFerryArcs());
+ }
+ }
+
+ /**
+ * Add a restriction.
+ *
+ * @param restr A new restriction.
+ * @return The offset into Table C at which the restriction will
+ * be written.
+ */
+ public int addRestriction(RouteRestriction restr) {
+ int offset = size;
+ restrictions.add(restr);
+ size += restr.getSize();
+ return offset;
+ }
+
+ /**
+ * The size of restriction indices in the nodes area.
+ */
+ private byte getOffsetSize() {
+ if (size < 0x80)
+ return 1; // allows 7 bit index (8th bit is flag)
+ else if (size < 0x8000)
+ return 2; // allows 15 bit index (16th bit is flag)
+ else
+ // XXX: haven't seen larger than 2, may well be possible
+ throw new FormatException("too many restrictions");
+ }
+
+ public void propagateSizeBytes() {
+ byte b = getOffsetSize();
+ for (RouteRestriction restr : restrictions)
+ restr.setOffsetSize(b);
+ }
+
+ public byte getFormat() {
+ // Table C format bitmask
+ // 0x01 = 1-255 bytes of restrictions
+ // 0x02 = 256-65535 bytes of restrictions
+ // 0x08 = unpaved roads count present
+ // 0x10 = ferry count present
+ int format = 0;
+ if(size > 0) {
+ ++format;
+ if(size > 0xff)
+ ++format;
+ }
+ if(tabA.numUnpavedArcs() > 0)
+ format |= 0x08;
+ if(tabA.numFerryArcs() > 0)
+ format |= 0x10;
+ return (byte)format;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/net/package.html b/src/uk/me/parabola/imgfmt/app/net/package.html
new file mode 100644
index 0000000..e8013da
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/net/package.html
@@ -0,0 +1,4 @@
+<body>
+<h3>The NET and NOD files</h3>
+<p>These files are used for routing.</p>
+</body>
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/app/package.html b/src/uk/me/parabola/imgfmt/app/package.html
new file mode 100644
index 0000000..89d1e4c
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/package.html
@@ -0,0 +1,28 @@
+<body>
+<h3>Application files</h3>
+This package and its subpackages contain the application files that appear
+in the IMG file-system.
+
+<p>The files that will be supported are</p>
+<dl>
+ <dt>TRE</dt>
+ <dd>The tree view of the map that is needed to make sense of
+ the rest of the file. A map is divided into a number of different levels
+ of detail. At each level of detail it is divided into a number of areas
+ (called sub-divisions here. In general there will be more sub-divisions
+ at the better zoom levels. Each subdivision points to the ones in the
+ zoom level below it.
+ </dd>
+
+ <dt>RGN</dt>
+ <dd>This file contains the definitions of the points, lines and polygons.
+ They have to be read in conjunction with the <strong>TRE</strong> section however,
+ as they don't make sense by themselves.
+ </dd>
+
+ <dt>LBL</dt>
+ <dd>This file contains all the text lables. Other
+ files refer to the labels that are defined in this file.
+ </dd>
+</dl>
+</body>
diff --git a/src/uk/me/parabola/imgfmt/app/srt/CodePosition.java b/src/uk/me/parabola/imgfmt/app/srt/CodePosition.java
new file mode 100644
index 0000000..3b075a5
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/srt/CodePosition.java
@@ -0,0 +1,69 @@
+/*
+ * 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.imgfmt.app.srt;
+
+import java.text.Collator;
+
+/**
+ * Represents the collation positions of a given code point.
+ *
+ * @author Steve Ratcliffe
+ */
+class CodePosition {
+ private byte primary;
+ private byte secondary;
+ private byte tertiary;
+
+ public byte getPrimary() {
+ return primary;
+ }
+
+ public byte getSecondary() {
+ return secondary;
+ }
+
+ public byte getTertiary() {
+ return tertiary;
+ }
+
+ /**
+ * Get the position with the given strength.
+ *
+ * @param type The strength, Collator.PRIMARY, SECONDARY etc.
+ * @return The collation position at the given strength.
+ */
+ public byte getPosition(int type) {
+ switch (type) {
+ case Collator.PRIMARY:
+ return primary;
+ case Collator.SECONDARY:
+ return secondary;
+ case Collator.TERTIARY:
+ return tertiary;
+ default:
+ return 0;
+ }
+ }
+
+ public void setPrimary(byte primary) {
+ this.primary = primary;
+ }
+
+ public void setSecondary(byte secondary) {
+ this.secondary = secondary;
+ }
+
+ public void setTertiary(byte tertiary) {
+ this.tertiary = tertiary;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/srt/CombinedSortKey.java b/src/uk/me/parabola/imgfmt/app/srt/CombinedSortKey.java
new file mode 100644
index 0000000..14fbae0
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/srt/CombinedSortKey.java
@@ -0,0 +1,63 @@
+/*
+ * 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.imgfmt.app.srt;
+
+/**
+ * Allows you to combine another sort key with further integer comparisons.
+ * Avoids having to cram two integers into one when there is the possibility that
+ * they may not be enough bits to represent all values.
+ *
+ * @author Steve Ratcliffe
+ */
+public class CombinedSortKey<T> implements SortKey<T> {
+ private final SortKey<T> key;
+ private final int first;
+ private final int second;
+
+ //public CombinedSortKey(SortKey<T> key, int first) {
+ // this(key, first, 0);
+ //}
+
+ public CombinedSortKey(SortKey<T> obj, int first, int second) {
+ this.key = obj;
+ this.first = first;
+ this.second = second;
+ }
+
+ public T getObject() {
+ return key.getObject();
+ }
+
+ public int compareTo(SortKey<T> o) {
+ CombinedSortKey<T> other = (CombinedSortKey<T>) o;
+ int res = key.compareTo(other.key);
+ if (res == 0) {
+ res = compareInts(first, other.first);
+ if (res == 0) {
+ res = compareInts(second, other.second);
+ }
+ }
+ return res;
+ }
+
+ private int compareInts(int i1, int i2) {
+ int res;
+ if (i1 == i2)
+ res = 0;
+ else if (i1 < i2)
+ res = -1;
+ else
+ res = 1;
+ return res;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/srt/IntegerSortKey.java b/src/uk/me/parabola/imgfmt/app/srt/IntegerSortKey.java
new file mode 100644
index 0000000..2c526f8
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/srt/IntegerSortKey.java
@@ -0,0 +1,53 @@
+/*
+ * 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.imgfmt.app.srt;
+
+/**
+ * Sort key when you are soring on a simple integer.
+ *
+ * @author Steve Ratcliffe
+ */
+public class IntegerSortKey<T> implements SortKey<T> {
+ private final T object;
+ private final int val;
+ private final int second;
+
+ public IntegerSortKey(T object, int val, int second) {
+ this.object = object;
+ this.val = val;
+ this.second = second;
+ }
+
+ /**
+ * Get the object associated with this sort key. This will usually be the real object being sorted.
+ */
+ public T getObject() {
+ return object;
+ }
+
+ public int compareTo(SortKey<T> o) {
+ IntegerSortKey<T> other = (IntegerSortKey<T>) o;
+ if (val == other.val) {
+ if (second == other.second)
+ return 0;
+ else if (second < other.second)
+ return -1;
+ else
+ return 1;
+ }
+ else if (val < other.val)
+ return -1;
+ else
+ return 1;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/srt/MultiSortKey.java b/src/uk/me/parabola/imgfmt/app/srt/MultiSortKey.java
new file mode 100644
index 0000000..f382d9a
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/srt/MultiSortKey.java
@@ -0,0 +1,48 @@
+/*
+ * 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.imgfmt.app.srt;
+
+/**
+ * Combines a number of sort keys into one. The first is the primary sort and contains the
+ * actual object being sorted.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MultiSortKey<T> implements SortKey<T> {
+ private final SortKey<T> key1;
+ private final SortKey<T> key2;
+ private final SortKey<T> key3;
+
+ public MultiSortKey(SortKey<T> key1, SortKey<T> key2, SortKey<T> key3) {
+ this.key1 = key1;
+ this.key2 = key2;
+ this.key3 = key3;
+ }
+
+ public T getObject() {
+ return key1.getObject();
+ }
+
+ public int compareTo(SortKey<T> o) {
+ MultiSortKey<T> other = (MultiSortKey<T>) o;
+ int res = key1.compareTo(other.key1);
+ if (res == 0) {
+ res = key2.compareTo(other.key2);
+ if (res == 0 && key3 != null) {
+ res = key3.compareTo(other.key3);
+ }
+ }
+ return res;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/srt/SRTFile.java b/src/uk/me/parabola/imgfmt/app/srt/SRTFile.java
new file mode 100644
index 0000000..510c340
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/srt/SRTFile.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.imgfmt.app.srt;
+
+import java.nio.charset.Charset;
+
+import uk.me.parabola.imgfmt.app.BufferedImgFileWriter;
+import uk.me.parabola.imgfmt.app.ImgFile;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.SectionWriter;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+
+/**
+ * The SRT file. This contains a table showing the sort order of
+ * the characters that is being used.
+ *
+ * @author Steve Ratcliffe
+ */
+public class SRTFile extends ImgFile {
+
+ private final SRTHeader header;
+
+ private Sort sort;
+
+ private String description;
+
+ public SRTFile(ImgChannel chan) {
+ header = new SRTHeader();
+ setHeader(header);
+
+ BufferedImgFileWriter fileWriter = new BufferedImgFileWriter(chan);
+ fileWriter.setMaxSize(Long.MAX_VALUE);
+ setWriter(fileWriter);
+
+ // Position at the start of the writable area.
+ position(header.getHeaderLength());
+ }
+
+ /**
+ * Write out the file.
+ * This file has an unusual layout. There are several header like structures within
+ * the main body of the file, with the real header being very small.
+ */
+ public void write() {
+ ImgFileWriter writer = getWriter();
+ writeDescription(writer);
+
+ SectionWriter subWriter = header.makeSectionWriter(writer);
+ subWriter.position(SRTHeader.HEADER3_LEN);
+ writeCharacterTable(subWriter);
+ writeExpansions(subWriter);
+ subWriter.close();
+
+ // Header 2 is just after the real header
+ writer.position(header.getHeaderLength());
+ header.writeHeader2(writer);
+
+ // Header 3 is after the description
+ writer.position(header.getHeaderLength() + description.length() + 1 + SRTHeader.HEADER2_LEN);
+ header.writeHeader3(writer);
+
+ header.writeHeader(writer);
+ }
+
+ private void writeDescription(ImgFileWriter writer) {
+ writer.position(header.getHeaderLength() + SRTHeader.HEADER2_LEN);
+ writer.put(description.getBytes(Charset.forName("ascii")));
+ writer.put((byte) 0);
+ header.endDescription(writer.position());
+ }
+
+ private void writeCharacterTable(ImgFileWriter writer) {
+ for (int i = 1; i < 256; i++) {
+ writer.put(sort.getFlags(i));
+ writeWeights(writer, i);
+ }
+ header.endCharTable(writer.position());
+ }
+
+ private void writeWeights(ImgFileWriter writer, int i) {
+ writer.put(sort.getPrimary(i));
+ writer.put((byte) ((sort.getTertiary(i) << 4) | (sort.getSecondary(i) & 0xf)));
+ }
+
+ /**
+ * Write out the expansion table. This is referenced from the character table, when
+ * the top nibble of the type is set via the primary position value.
+ */
+ private void writeExpansions(ImgFileWriter writer) {
+
+ int size = sort.getExpansionSize();
+ for (int j = 1; j <= size; j++) {
+ CodePosition b = sort.getExpansion(j);
+ writer.put(b.getPrimary());
+ writer.put((byte) ((b.getTertiary() << 4) | (b.getSecondary() & 0xf)));
+ }
+
+ header.endTab2(writer.position());
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public void setSort(Sort sort) {
+ this.sort = sort;
+ header.setSort(sort);
+ description = sort.getDescription();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/srt/SRTHeader.java b/src/uk/me/parabola/imgfmt/app/srt/SRTHeader.java
new file mode 100644
index 0000000..5b106d9
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/srt/SRTHeader.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.imgfmt.app.srt;
+
+import uk.me.parabola.imgfmt.ReadFailedException;
+import uk.me.parabola.imgfmt.app.CommonHeader;
+import uk.me.parabola.imgfmt.app.ImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Section;
+import uk.me.parabola.imgfmt.app.SectionWriter;
+
+/**
+ * The header of the SRT file.
+ *
+ * This file determines the sort order of the label characters.
+ *
+ * @author Steve Ratcliffe
+ */
+public class SRTHeader extends CommonHeader {
+ // The header length we are using for the SRT file
+ private static final int HEADER_LEN = 29;
+ protected static final int HEADER2_LEN = 16;
+ protected static final int HEADER3_LEN = 52;
+
+ // The section structure of this file is somewhat different to other
+ // files, but I am still going to model it using Section.
+ private final Section header = new Section();
+ //private final Section pointers = new Section(header);
+ private final Section desc = new Section(header);
+ private final Section subheader = new Section(desc);
+ private final Section chartab = new Section((char) 3);
+ private final Section tab2 = new Section(chartab, (char) 2);
+
+ private Sort sort;
+
+ public SRTHeader() {
+ super(HEADER_LEN, "GARMIN SRT");
+ header.setPosition(HEADER_LEN);
+ header.setSize(16);
+
+ chartab.setPosition(HEADER3_LEN);
+ }
+
+ protected void readFileHeader(ImgFileReader reader) throws ReadFailedException {
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Write out the application header. This is unusual as it just points
+ * to an area which is itself just a header.
+ */
+ protected void writeFileHeader(ImgFileWriter writer) {
+ writer.putChar((char) 1);
+
+ writer.putInt(header.getPosition());
+ writer.putChar((char) header.getSize());
+
+ //writeHeader2(writer);
+
+ //writeDescription(writer);
+ //writeHeader3(writer);
+ }
+
+ /**
+ * Section writer to write the character and tab2 sections. These two sections are embedded within another
+ * section and their offsets are relative to that section.
+ * @param writer The real underlying writer.
+ * @return A new writer where offsets are relative to the start of the sub-header section.
+ */
+ SectionWriter makeSectionWriter(ImgFileWriter writer) {
+ return new SectionWriter(writer, subheader);
+ }
+
+ /**
+ * This is a header with pointers to the description and the main section.
+ * The offsets contained in this section are relative to the beginning of the file.
+ * @param writer Header is written here.
+ */
+ protected void writeHeader2(ImgFileWriter writer) {
+ desc.writeSectionInfo(writer);
+ subheader.writeSectionInfo(writer);
+ }
+
+ /**
+ * Header contained within the main section. Offsets within this section are relative to the beginning
+ * of the section.
+ * @param writer Header is written here.
+ */
+ protected void writeHeader3(ImgFileWriter writer) {
+ writer.putChar((char) HEADER3_LEN);
+ writer.putChar((char) sort.getId1());
+ writer.putChar((char) sort.getId2());
+ writer.putChar((char) sort.getCodepage());
+ writer.putInt(0x2002);
+
+ chartab.writeSectionInfo(writer, true, true);
+
+ writer.putChar((char) 0);
+ tab2.writeSectionInfo(writer, true, true);
+
+ writer.putChar((char) 0);
+ writer.putInt(0x34);
+ writer.putInt(0);
+ }
+
+ public void setSort(Sort sort) {
+ this.sort = sort;
+ }
+
+ /** Called after the description has been written to record the position. */
+ public void endDescription(int position) {
+ desc.setSize(position - desc.getPosition());
+ subheader.setPosition(position);
+ }
+
+ /** Called after the character table has been written to record the position. */
+ public void endCharTable(int position) {
+ chartab.setSize(position - chartab.getPosition());
+ }
+
+ /** Called after the tab2 has been written to record the position. */
+ public void endTab2(int postition) {
+ subheader.setSize(postition - subheader.getPosition());
+ tab2.setSize(postition - tab2.getPosition());
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/srt/Sort.java b/src/uk/me/parabola/imgfmt/app/srt/Sort.java
new file mode 100644
index 0000000..7719b44
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/srt/Sort.java
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2010, 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.imgfmt.app.srt;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CodingErrorAction;
+import java.text.CollationKey;
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.ExitException;
+
+/**
+ * Represents the sorting positions for all the characters in a codepage.
+ * @author Steve Ratcliffe
+ */
+public class Sort {
+
+ private static final byte[] ZERO_KEY = new byte[3];
+
+ private int codepage;
+ private int id1; // Unknown - identifies the sort
+ private int id2; // Unknown - identifies the sort
+
+ private String description;
+ private Charset charset;
+
+ private final byte[] primary = new byte[256];
+ private final byte[] secondary = new byte[256];
+ private final byte[] tertiary = new byte[256];
+ private final byte[] flags = new byte[256];
+
+ private final List<CodePosition> expansions = new ArrayList<CodePosition>();
+ private int maxExpSize = 1;
+
+ private CharsetEncoder encoder;
+
+ public void add(int ch, int primary, int secondary, int tertiary, int flags) {
+ if (this.primary[ch & 0xff] != 0)
+ throw new ExitException(String.format("Repeated primary index 0x%x", ch & 0xff));
+ this.primary[ch & 0xff] = (byte) primary;
+ this.secondary[ch & 0xff] = (byte) secondary;
+ this.tertiary[ch & 0xff] = (byte) tertiary;
+
+ this.flags[ch & 0xff] = (byte) flags;
+ }
+
+ /**
+ * Return a table indexed by a character value in the target codepage, that gives the complete sort
+ * position of the character.
+ * @return A table of sort positions.
+ */
+ public char[] getSortPositions() {
+ char[] tab = new char[256];
+
+ for (int i = 1; i < 256; i++) {
+ tab[i] = (char) (((primary[i] << 8) & 0xff00) | ((secondary[i] << 4) & 0xf0) | (tertiary[i] & 0xf));
+ }
+
+ return tab;
+ }
+
+ /**
+ * Create a sort key for a given unicode string. The sort key can be compared instead of the original strings
+ * and will compare based on the sorting represented by this Sort class.
+ *
+ * Using a sort key is more efficient if many comparisons are being done (for example if you are sorting a
+ * list of strings).
+ *
+ * @param object This is saved in the sort key for later retrieval and plays no part in the sorting.
+ * @param s The string for which the sort key is to be created.
+ * @param second Secondary sort key.
+ * @param cache A cache for the created keys. This is for saving memory so it is essential that this
+ * is managed by the caller.
+ * @return A sort key.
+ */
+ public <T> SortKey<T> createSortKey(T object, String s, int second, Map<String, byte[]> cache) {
+ // If there is a cache then look up and return the key.
+ // This is primarily for memory management, not for speed.
+ byte[] key;
+ if (cache != null) {
+ key = cache.get(s);
+ if (key != null)
+ return new SrtSortKey<T>(object, key, second);
+ }
+
+ CharBuffer inb = CharBuffer.wrap(s);
+ try {
+ ByteBuffer out = encoder.encode(inb);
+ byte[] bval = out.array();
+
+ // In theory you could have a string where every character expands into maxExpSize separate characters
+ // in the key. However if we allocate enough space to deal with the worst case, then we waste a
+ // vast amount of memory. So allocate a minimal amount of space, try it and if it fails reallocate the
+ // maximum amount.
+ //
+ // We need +1 for the null bytes, we also +2 for a couple of expanded characters. For a complete
+ // german map this was always enough in tests.
+ key = new byte[(bval.length + 1 + 2) * 3];
+ try {
+ fillCompleteKey(bval, key);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Ok try again with the max possible key size allocated.
+ key = new byte[bval.length * 3 * maxExpSize + 3];
+ }
+
+ if (cache != null)
+ cache.put(s, key);
+
+ return new SrtSortKey<T>(object, key, second);
+ } catch (CharacterCodingException e) {
+ return new SrtSortKey<T>(object, ZERO_KEY);
+ }
+ }
+
+ public <T> SortKey<T> createSortKey(T object, String s, int second) {
+ return createSortKey(object, s, second, null);
+ }
+
+ public <T> SortKey<T> createSortKey(T object, String s) {
+ return createSortKey(object, s, 0, null);
+ }
+
+ /**
+ * Fill in the key from the given byte string.
+ *
+ * @param bval The string for which we are creating the sort key.
+ * @param key The sort key. This will be filled in.
+ */
+ private void fillCompleteKey(byte[] bval, byte[] key) {
+ int start = fillKey(Collator.PRIMARY, primary, bval, key, 0);
+ start = fillKey(Collator.SECONDARY, secondary, bval, key, start);
+ fillKey(Collator.TERTIARY, tertiary, bval, key, start);
+ }
+
+ /**
+ * Fill in the output key for a given strength.
+ *
+ * @param sortPositions An array giving the sort position for each of the 256 characters.
+ * @param input The input string in a particular 8 bit codepage.
+ * @param outKey The output sort key.
+ * @param start The index into the output key to start at.
+ * @return The next position in the output key.
+ */
+ private int fillKey(int type, byte[] sortPositions, byte[] input, byte[] outKey, int start) {
+ int index = start;
+ for (byte inb : input) {
+ int b = inb & 0xff;
+
+ int exp = (flags[b] >> 4) & 0x3;
+ if (exp == 0) {
+ // I am guessing that a sort position of 0 means that the character is ignorable at this
+ // strength. In other words it is as if it is not present in the string. This appears to
+ // be true for shield symbols, but perhaps not for other kinds of control characters.
+ byte pos = sortPositions[b];
+ if (pos != 0)
+ outKey[index++] = pos;
+ } else {
+ // now have to redirect to a list of input chars, get the list via the primary value always.
+ byte idx = primary[b];
+ //List<CodePosition> list = expansions.get(idx-1);
+
+ for (int i = idx - 1; i < idx + exp; i++) {
+ byte pos = expansions.get(i).getPosition(type);
+ if (pos != 0)
+ outKey[index++] = pos;
+ }
+ }
+ }
+
+ outKey[index++] = '\0';
+ return index;
+ }
+
+ public byte getPrimary(int ch) {
+ return primary[ch];
+ }
+
+ public byte getSecondary(int ch) {
+ return secondary[ch];
+ }
+
+ public byte getTertiary(int ch) {
+ return tertiary[ch];
+ }
+
+ public byte getFlags(int ch) {
+ return flags[ch];
+ }
+
+ public int getCodepage() {
+ return codepage;
+ }
+
+ public Charset getCharset() {
+ return charset;
+ }
+
+ public int getId1() {
+ return id1;
+ }
+
+ public void setId1(int id1) {
+ this.id1 = id1;
+ }
+
+ public int getId2() {
+ return id2;
+ }
+
+ public void setId2(int id2) {
+ this.id2 = id2 & 0x7fff;
+ }
+
+ /**
+ * Get the sort order as a single integer.
+ * A combination of id1 and id2. I think that they are arbitrary so may as well treat them as one.
+ *
+ * @return id1 and id2 as if they were a little endian 2 byte integer.
+ */
+ public int getSortOrderId() {
+ return (this.id2 << 16) + (this.id1 & 0xffff);
+ }
+
+ /**
+ * Set the sort order as a single integer.
+ * @param id The sort order id.
+ */
+ public void setSortOrderId(int id) {
+ id1 = id & 0xffff;
+ id2 = (id >>> 16) & 0x7fff;
+ }
+
+ public void setCodepage(int codepage) {
+ this.codepage = codepage;
+ if (codepage == 0)
+ charset = Charset.forName("cp1252");
+ else if (codepage == 65001)
+ charset = Charset.forName("UTF-8");
+ else if (codepage == 932)
+ // Java uses "ms932" for code page 932
+ // (Windows-31J, Shift-JIS + MS extensions)
+ charset = Charset.forName("ms932");
+ else
+ charset = Charset.forName("cp" + codepage);
+ encoder = charset.newEncoder();
+ encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Add an expansion to the sort.
+ * An expansion is a letter that sorts as if it were two separate letters.
+ *
+ * The case were two letters sort as if the were just one (and more complex cases) are
+ * not supported or are unknown to us.
+ *
+ * @param bval The code point of this letter in the code page.
+ * @param inFlags The initial flags, eg if it is a letter or not.
+ * @param expansionList The letters that this letter sorts as, as code points in the codepage.
+ */
+ public void addExpansion(byte bval, int inFlags, List<Byte> expansionList) {
+ int idx = bval & 0xff;
+ flags[idx] = (byte) ((inFlags & 0xf) | (((expansionList.size()-1) << 4) & 0x30));
+
+ // Check for repeated definitions
+ if (primary[idx] != 0)
+ throw new ExitException(String.format("repeated code point %x", idx));
+
+ primary[idx] = (byte) (expansions.size() + 1);
+ secondary[idx] = 0;
+ tertiary[idx] = 0;
+ maxExpSize = Math.max(maxExpSize, expansionList.size());
+
+ for (Byte b : expansionList) {
+ CodePosition cp = new CodePosition();
+ cp.setPrimary(primary[b & 0xff]);
+ cp.setSecondary(secondary[b & 0xff]);
+ cp.setTertiary((byte) (tertiary[b & 0xff] + 2));
+ expansions.add(cp);
+ }
+ }
+
+ /**
+ * Get the expansion with the given index, one based.
+ * @param val The one-based index number of the extension.
+ */
+ public CodePosition getExpansion(int val) {
+ return expansions.get(val - 1);
+ }
+
+ public Collator getCollator() {
+ return new SrtCollator(codepage);
+ }
+
+ /**
+ * Create a default sort that simply sorts by the values of the characters.
+ * It has to pretend to be associated with a particular code page, otherwise
+ * it will not be recognised at all.
+ *
+ * This is not likely to be very useful. You need to create a sort description for your language
+ * to make things work properly.
+ *
+ * @return A default sort.
+ * @param codepage The code page that we are pretending to be.
+ */
+ public static Sort defaultSort(int codepage) {
+ Sort sort = new Sort();
+ for (int i = 1; i < 256; i++) {
+ sort.add(i, i, 0, 0, 0);
+ }
+ sort.charset = Charset.forName("ascii");
+ sort.encoder = sort.charset.newEncoder();
+ sort.setDescription("Default sort");
+ sort.setCodepage(codepage);
+ return sort;
+ }
+
+ public int getExpansionSize() {
+ return expansions.size();
+ }
+
+ public String toString() {
+ return String.format("sort cp=%d order=%08x", codepage, getSortOrderId());
+ }
+
+ /**
+ * A collator that works with this sort. This should be used if you just need to compare two
+ * strings against each other once.
+ *
+ * The sort key is better when the comparison must be done several times as in a sort operation.
+ */
+ private class SrtCollator extends Collator {
+ private final int codepage;
+
+ private SrtCollator(int codepage) {
+ this.codepage = codepage;
+ }
+
+ public int compare(String source, String target) {
+ CharBuffer in1 = CharBuffer.wrap(source);
+ CharBuffer in2 = CharBuffer.wrap(target);
+ byte[] bytes1;
+ byte[] bytes2;
+ try {
+ bytes1 = encoder.encode(in1).array();
+ bytes2 = encoder.encode(in2).array();
+ } catch (CharacterCodingException e) {
+ throw new ExitException("character encoding failed unexpectedly", e);
+ }
+
+ int strength = getStrength();
+ int res = compareOneStrength(bytes1, bytes2, primary, Collator.PRIMARY);
+
+ if (res == 0 && strength != PRIMARY) {
+ res = compareOneStrength(bytes1, bytes2, secondary, Collator.SECONDARY);
+ if (res == 0 && strength != SECONDARY) {
+ res = compareOneStrength(bytes1, bytes2, tertiary, Collator.TERTIARY);
+ }
+ }
+
+ if (res == 0) {
+ if (source.length() < target.length())
+ res = -1;
+ else if (source.length() > target.length())
+ res = 1;
+ }
+ return res;
+ }
+
+ /**
+ * Compare the bytes against primary, secondary or tertiary arrays.
+ * @param bytes1 Bytes for the first string in the codepage encoding.
+ * @param bytes2 Bytes for the second string in the codepage encoding.
+ * @param typePositions The strength array to use in the comparison.
+ * @return Comparison result -1, 0 or 1.
+ */
+ @SuppressWarnings({"AssignmentToForLoopParameter"})
+ private int compareOneStrength(byte[] bytes1, byte[] bytes2, byte[] typePositions, int type) {
+ int res = 0;
+
+ PositionIterator it1 = new PositionIterator(bytes1, typePositions, type);
+ PositionIterator it2 = new PositionIterator(bytes2, typePositions, type);
+
+ while (it1.hasNext() && it2.hasNext()) {
+ int p1 = it1.next();
+ int p2 = it2.next();
+
+ if (p1 < p2) {
+ res = -1;
+ break;
+ } else if (p1 > p2) {
+ res = 1;
+ break;
+ }
+ }
+ return res;
+ }
+
+ public CollationKey getCollationKey(String source) {
+ throw new UnsupportedOperationException("use Sort.createSortKey() instead");
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ SrtCollator that = (SrtCollator) o;
+
+ if (codepage != that.codepage) return false;
+ return true;
+ }
+
+ public int hashCode() {
+ return codepage;
+ }
+
+ class PositionIterator implements Iterator<Integer> {
+ private final byte[] bytes;
+ private final byte[] sortPositions;
+ private final int len;
+ private final int type;
+
+ private int pos;
+
+ private int expStart;
+ private int expEnd;
+ private int expPos;
+
+ PositionIterator(byte[] bytes, byte[] sortPositions, int type) {
+ this.bytes = bytes;
+ this.sortPositions = sortPositions;
+ this.len = bytes.length;
+ this.type = type;
+ }
+
+ public boolean hasNext() {
+ return pos < len || expPos != 0;
+ }
+
+ public Integer next() {
+ int next;
+ if (expPos == 0) {
+ int in = pos++ & 0xff;
+ byte b = bytes[in];
+ int n = (flags[b & 0xff] >> 4) & 0x3;
+ if (n > 0) {
+ expStart = primary[b & 0xff] - 1;
+ expEnd = expStart + n;
+ expPos = expStart;
+ next = expansions.get(expPos).getPosition(type);
+
+ if (++expPos > expEnd)
+ expPos = 0;
+
+ } else {
+ for (next = sortPositions[bytes[in] & 0xff]; next == 0 && pos < len; ) {
+ next = sortPositions[bytes[pos++ & 0xff] & 0xff];
+ }
+ }
+ } else {
+ next = expansions.get(expPos).getPosition(type);
+ if (++expPos > expEnd)
+ expPos = 0;
+
+ }
+ return next;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("remove not supported");
+ }
+ }
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/srt/SortKey.java b/src/uk/me/parabola/imgfmt/app/srt/SortKey.java
new file mode 100644
index 0000000..2aed0ca
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/srt/SortKey.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.imgfmt.app.srt;
+
+/**
+ * A sort key that allows efficient comparison of a string with a particular sorting order multiple times.
+ *
+ * The general idea is that you create a key for each object to be sorted and then sort the keys. Once the
+ * keys are sorted you retrieve the original object via the {@link #getObject} method.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface SortKey<T> extends Comparable<SortKey<T>> {
+ /**
+ * Get the object associated with this sort key.
+ * This will usually be the real object being sorted.
+ */
+ public T getObject();
+}
diff --git a/src/uk/me/parabola/imgfmt/app/srt/SrtSortKey.java b/src/uk/me/parabola/imgfmt/app/srt/SrtSortKey.java
new file mode 100644
index 0000000..632efda
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/srt/SrtSortKey.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.imgfmt.app.srt;
+
+/**
+ * Sort key created from a Srt {@link Sort} object that allows strings to be compared according to that sorting
+ * scheme.
+ *
+ * @author Steve Ratcliffe
+ */
+class SrtSortKey<T> implements SortKey<T> {
+ private final T orig;
+ private final byte[] key;
+ private int second;
+
+ public SrtSortKey(T orig, byte[] key) {
+ this.orig = orig;
+ this.key = key;
+ }
+
+ public SrtSortKey(T orig, byte[] key, int second) {
+ this.orig = orig;
+ this.key = key;
+ this.second = second;
+ }
+
+ public int compareTo(SortKey<T> o) {
+ SrtSortKey<T> other = (SrtSortKey<T>) o;
+ int length = Math.min(this.key.length, other.key.length);
+ for (int i = 0; i < length; i++) {
+ int k1 = this.key[i] & 0xff;
+ int k2 = other.key[i] & 0xff;
+ if (k1 < k2) {
+ return -1;
+ } else if (k1 > k2) {
+ return 1;
+ }
+ }
+
+ if (this.key.length < other.key.length)
+ return -1;
+ else if (this.key.length > other.key.length)
+ return 1;
+
+ if (second == other.second)
+ return 0;
+ else if (second < other.second)
+ return -1;
+ else
+ return 1;
+ }
+
+ public T getObject() {
+ return orig;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/srt/package.html b/src/uk/me/parabola/imgfmt/app/srt/package.html
new file mode 100644
index 0000000..2cf7b10
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/srt/package.html
@@ -0,0 +1,43 @@
+<body>
+<h3>SRT File</h3>
+<p>This file is used to specify the character sorting order and which
+characters are the 'same' for the purposes of searching. All accented versions
+of a character will have the same code.</p>
+<p>The first section has three byte records that have the following meaning</p>
+<table>
+ <tr>
+ <th>Byte number</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>1</td>
+ <td>The low nibble is 1 for letters, 2 for digits and zero for everything
+ else.</td>
+ </tr>
+
+ <tr>
+ <td>2</td>
+ <td>This is the sort order for the unaccented form of the character.
+ So a, à, á, ä and å would all have the same code here. The next byte allows
+ you to put them in order.</td>
+ </tr>
+
+ <tr>
+ <td>3</td>
+ <td>Upper nibble is 2 for uppercase letters, 1 for lowercase letters.
+ It can also have the values 3 or 4 for unknown reasons.
+ <p>The lower nibble is a number that can be added to byte 2 to get the full
+ sorting order. This sorts the accented versions of the characters</p></td>
+ </tr>
+</table>
+<p>The next section has two byte records with an unknown function.</p>
+<h3>Unknowns</h3>
+At the time of writing Jan 2010 certain things are not known.
+<ul>
+ <li>If it can deal with character pairs that sort as one.</li>
+ <li>What the second section is for.</li>
+ <li>Sorting for scandinavian languages where the accented characters come at
+ the end of the alphabet. Perhaps you just treat them as separate letters and
+ not as a base + accent, or perhaps there is a way of specifying it.</li>
+</ul>
+</body>
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/ExtTypeAttributes.java b/src/uk/me/parabola/imgfmt/app/trergn/ExtTypeAttributes.java
new file mode 100644
index 0000000..bb83e8a
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/ExtTypeAttributes.java
@@ -0,0 +1,1130 @@
+/*
+ * 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: 12-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app.trergn;
+
+import java.text.DecimalFormat;
+import java.text.ParsePosition;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.lbl.LBLFile;
+import uk.me.parabola.log.Logger;
+
+/*
+Add support for extended type attributes.
+
+These are nearly all for marine objects. Attribute values are supplied
+as tags with a mkgmap:xt- prefix. These tags are supported:
+
+mkgmap:xt-depth
+mkgmap:xt-height
+ value is distance with optional units suffix (ft or m)
+ applicable to points with types 0x0103xx and 0x0104xx and
+ lines with types 0x0103xx and 0x010105-0x010107 and areas
+ with types 0x0103xx.
+
+mkgmap:xt-style
+ value is 16 bit integer that specifies colour (lower 8 bits)
+ and line style (upper 8 bits) - applicable to lines with types
+ 0x0104xx, 0x0105xx, 0x0106xx and points with type 0x010500 (colour
+ only).
+
+mkgmap:xt-colour
+ value is one of:
+ red
+ green
+ yellow
+ white
+ black
+ black-yellow
+ white-red
+ black-red
+ white-green
+ red-yellow
+ red-green
+ orange
+ black-yellow-black
+ yellow-black
+ yellow-black-yellow
+ red-white
+ green-red-green
+ red-green-red
+ black-red-black
+ yellow-red-yellow
+ green-red
+ black-white
+ white-orange
+ orange-white
+ green-white
+ applicable to points with type 0x0102xx (buoys) and it specifies the
+ foundation colour of the buoy.
+
+mkgmap:xt-type
+ value is one of:
+ fixed
+ isophase
+ flashing
+ group flashing
+ composite group flashing
+ occulting
+ group occulting
+ composite group occulting
+ long flashing
+ group long flashing
+ (a morse code letter)
+ quick
+ group quick
+ group quick and long flashing
+ interrupted quick
+ very quick
+ group very quick
+ group very quick and long flashing
+ interrupted very quick
+ ultra quick
+ interrupted ultra quick
+ fixed and occulting
+ fixed and group occulting
+ fixed and isophase
+ fixed and flashing
+ fixed and group flashing
+ fixed and long flashing
+ alternating
+ alternating occulting
+ alternating flashing
+ alternating group flashing
+ applicable to points with types 0x0101xx (lights) and 0x0102xx (buoys)
+ and it specifies the type of light
+
+mkgmap:xt-light
+ one or more light definitions (separated by ;: or /) - each light
+ definition is of the form colour,range,angle where colour is one
+ of:
+ unlit
+ red
+ green
+ white
+ blue
+ yellow
+ violet
+ amber
+ range is an optional number that specifies the visible range in nm -
+ angle is the start angle for the light (only makes sense when more than
+ one light is defined.
+
+mkgmap:xt-period
+ value is one or more period values (in seconds) (separated by commas) -
+ applicable to point types 0x0101xx (lights) and 0x0102xx (buoys).
+
+mkgmap:xt-racon
+ when set to yes/true/1 specifies object has a racon - applicable to
+ point types 0x0101xx (lights).
+
+mkgmap:xt-height-above-foundation
+mkgmap:xt-height-above-datum
+ value is distance with optional units (m or ft) - applicable to
+ point types 0x0101xx (lights).
+
+mkgmap:xt-leading-angle
+ value is a number - applicable to point types 0x0101xx (lights).
+
+mkgmap:xt-note
+mkgmap:xt-int-desig
+mkgmap:xt-local-desig
+ values are strings that are encoded as labels - applicable to
+ points of type 0x01xx (lights) and 0x0102xx (buoys).
+
+mkgmap:xt-facilities
+ value is a bitmask of facilities available:
+ 0x000001 boat ramp
+ 0x000002 drinking water
+ 0x000004 restrooms
+ 0x000008 picnic area
+ 0x000010 campground
+ 0x000020 marina
+ 0x000040 fuel
+ 0x000080 marine supply
+ 0x000100 bait and tackle
+ 0x000200 groceries
+ 0x000400 restaurant
+ 0x000800 water/electric hook-up
+ 0x001000 boat/motor rental
+ 0x002000 guide service
+ 0x004000 lodging
+ 0x008000 dump station
+ 0x010000 handicap accessible
+ applicable only to points of type 0x010903 (facility)
+ */
+
+public class ExtTypeAttributes {
+
+ private static final Logger log = Logger.getLogger(ExtTypeAttributes.class);
+
+ private final Map<String, String> attributes;
+ private final String objectName;
+
+ private byte[] extraBytes;
+
+ private Label note;
+ private Label intDesig;
+ private Label localDesig;
+
+ private Byte morseLetter;
+
+ private final int DISTANCE_FLAG_METRIC_INDEX = 0;
+ private final int DISTANCE_FLAG_TENTHS_INDEX = 1;
+
+ private static final byte FLAGS0_RACON_BIT = (1);
+ private static final byte FLAGS0_NOTE_BIT = (1 << 1);
+ private static final byte FLAGS0_LOCAL_DESIG_BIT = (1 << 2);
+ private static final byte FLAGS0_INT_DESIG_BIT = (1 << 3);
+ private static final int[] ZERO_INT_ARRAY = new int[0];
+
+ public ExtTypeAttributes(Map<String, String> attributes, String objectName) {
+ this.attributes = attributes;
+ this.objectName = objectName;
+ }
+
+ public void processLabels(LBLFile lbl) {
+ if(note == null) {
+ String ns = attributes.get("note");
+ if(ns != null)
+ note = lbl.newLabel(ns);
+ }
+ if(intDesig == null) {
+ String ids = attributes.get("int-desig");
+ if(ids != null)
+ intDesig = lbl.newLabel(ids);
+ }
+ if(localDesig == null) {
+ String lds = attributes.get("local-desig");
+ if(lds != null)
+ localDesig = lbl.newLabel(lds);
+ }
+ }
+
+ protected byte[] getExtTypeExtraBytes(MapObject mapObject) {
+ try {
+ return encodeExtraBytes(mapObject);
+ }
+ catch (Exception e) {
+ log.error(objectName + " (" + e + ")");
+ return null;
+ }
+ }
+
+ private byte[] encodeExtraBytes(MapObject mapObject) {
+
+ // if we get called again, just return same result as before
+ if(extraBytes != null)
+ return extraBytes;
+
+ // first see if a string of raw hex digits has been supplied
+ // if so, use that and ignore everything else
+ String eb = attributes.get("extra-bytes");
+ if(eb != null) {
+ extraBytes = new byte[(eb.length() + 1) / 2];
+ for(int i = 0; i < eb.length(); ++i) {
+ int d = Integer.parseInt(eb.substring(i, i + 1), 16);
+ extraBytes[i / 2] |= (byte)(d << (4 * (1 - (i & 1))));
+ }
+ return extraBytes;
+ }
+
+ int type0to15 = mapObject.getType() & 0xffff;
+ int type8to15 = type0to15 & 0xff00;
+
+ // seamark:light:character = type [[(group)] colour period 's' height 'm' range 'M']
+ if(attributes.get("seamark:light:character") != null) {
+ String[] parts = attributes.get("seamark:light:character").split(" ");
+ String group = attributes.get("seamark:light:group");
+
+ if(parts.length > 0) {
+ String lt = null;
+ int i = 1;
+ if(parts[0].startsWith("Fl"))
+ lt = "flashing";
+ else if(parts[0].startsWith("F"))
+ lt = "fixed";
+ else if(parts[0].startsWith("LFL"))
+ lt = "long flashing";
+ else if(parts[0].startsWith("Q"))
+ lt = "quick";
+ else if(parts[0].startsWith("VQ"))
+ lt = "very quick";
+ else if(parts[0].startsWith("UQ"))
+ lt = "ultra quick";
+ else if(parts[0].startsWith("Iso"))
+ lt = "isophase";
+ else if(parts[0].startsWith("Oc"))
+ lt = "occulting";
+ else if(parts[0].startsWith("IQ"))
+ lt = "interrupted quick";
+ else if(parts[0].startsWith("IVQ "))
+ lt = "interrupted very quick";
+ else if(parts[0].startsWith("UQ"))
+ lt = "interrupted ultra quick";
+ else if(parts[0].startsWith("AI"))
+ lt = "alternating";
+ else if(parts[0].startsWith("Mo")) {
+ if(parts[0].indexOf("(") == 2)
+ lt = parts[0].substring(3, 4);
+ else if(parts.length > 1 && parts[i].startsWith("(")) {
+ lt = parts[i].substring(1, 2);
+ ++i;
+ }
+ }
+
+ String group2 = null;
+ if(!parts[0].startsWith("Mo") && parts[0].indexOf("(") > 0) {
+ group2 = parts[0].substring(parts[0].indexOf("(") + 1, parts[0].length() - 1);
+ }
+ else if(i < parts.length && parts[i].startsWith("(")) {
+ // should be (group)
+ group2 = parts[i].substring(1, parts[i].length() - 1);
+ ++i;
+ }
+
+ if(group2 != null) {
+ if(group != null && !group.equals(group2))
+ log.warn("Inconsistent light description - seamark:light:group = '" + group + "' but seamark:light:character contains '" + parts[0] + "'");
+ else
+ group = group2;
+ }
+
+ if(lt != null) {
+ if(group != null) {
+ attributes.put("group", group); // FIXME - implement?
+ lt = "group " + lt;
+ if(group.split("\\+").length > 1)
+ lt = "composite " + lt;
+ }
+ attributes.put("type", lt);
+ }
+
+ String light = null;
+ if(i < parts.length) {
+ // colour
+ String c = parts[i].toUpperCase();
+ if(c.startsWith("W"))
+ light = "white";
+ else if(c.startsWith("R"))
+ light = "red";
+ else if(c.startsWith("G"))
+ light = "green";
+ else if(c.startsWith("Y"))
+ light = "yellow";
+ ++i;
+ } else {
+ light = attributes.get("light");
+ }
+
+ String period = null;
+ if((i + 1) < parts.length && parts[i+1].equals("s")) {
+ // period
+ period = parts[i];
+ i += 2;
+ }
+
+ String height = null;
+ if((i + 1) < parts.length && parts[i+1].equals("m")) {
+ // height
+ height = parts[i];
+ i += 2;
+ }
+
+ String range = null;
+ if((i + 1) < parts.length && parts[i+1].equals("M")) {
+ // range
+ range = parts[i];
+ i += 2;
+ } else {
+ range = attributes.get("seamark:light:range");
+ }
+
+ if(light != null) {
+ if(range != null)
+ light += "," + range;
+ attributes.put("light", light);
+ if(period != null)
+ attributes.put("period", period);
+ if(height != null)
+ attributes.put("height-above-datum", height + "m");
+ }
+ }
+ }
+
+ // seamark:light:# = colour ':' sectorStart ':' sectorEnd ':' range
+ if(attributes.get("seamark:light:1") != null) {
+ // when multiple lights are defined, they must be ordered
+ // by increasing sector start angle
+ class SeamarkLight implements Comparable<SeamarkLight> {
+ String colour;
+ int sectorStart;
+ int sectorEnd;
+ int range;
+ SeamarkLight(String desc) {
+ String[] parts = desc.split(":");
+ if(parts.length == 4) {
+ colour = parts[0];
+ if (parts[1].equalsIgnoreCase("shore") || parts[2].equalsIgnoreCase("shore")) {
+ log.error(objectName + ": shore is no valid sector bound, please annotate a numeric value");
+ } else {
+ sectorStart = Double.valueOf(parts[1]).intValue();
+ while(sectorStart >= 360)
+ sectorStart -= 360;
+ sectorEnd = Double.valueOf(parts[2]).intValue();
+ while(sectorEnd >= 360)
+ sectorEnd -= 360;
+ range = Double.valueOf(parts[3]).intValue();
+ }
+ }
+ }
+ public int compareTo(SeamarkLight other) {
+ if (sectorStart == other.sectorStart) return 0;
+ else return sectorStart > other.sectorStart? 1: -1;
+ }
+ }
+ List<SeamarkLight> lights = new ArrayList<SeamarkLight>();
+ // create a SeamarkLight for each light
+ for(int n = 1; n <= 100; ++n) {
+ String desc = attributes.get("seamark:light:" + n);
+ if(desc != null)
+ lights.add(new SeamarkLight(desc));
+ else
+ break;
+ }
+ // sort the lights by increasing sector start angle
+ Collections.sort(lights);
+ // generate the descriptor string - each light is
+ // specified as color,range,sectorStartAngle
+ String light = null;
+ for(int i = 0; i < lights.size(); ++i) {
+ SeamarkLight sml = lights.get(i);
+ if(light == null)
+ light = "";
+ else
+ light += "/";
+ light += sml.colour + "," + sml.range + "," + sml.sectorStart;
+ //light += sml.colour + "," + sml.range/10 + "." + sml.range%10 + "," + sml.sectorStart;
+ if((i + 1) < lights.size()) {
+ if(sml.sectorEnd != lights.get(i + 1).sectorStart) {
+ // gap between lit sectors
+ light += "/unlit,0," + sml.sectorEnd;
+ }
+ }
+ else if(sml.sectorEnd != lights.get(0).sectorStart) {
+ // gap to end
+ light += "/unlit,0," + sml.sectorEnd;
+ }
+ }
+ if(light != null) {
+ //System.err.println(light);
+ attributes.put("light", light);
+ if(attributes.get("seamark:light:character") == null)
+ attributes.put("type", "fixed");
+ }
+ }
+
+ String sequence = attributes.get("seamark:light:sequence");
+
+ if(sequence != null) {
+ StringBuffer periods = new StringBuffer();
+ StringBuffer eclipse = new StringBuffer();
+ for(String p : sequence.split("[+,]")) {
+ if (p.startsWith("(") && p.endsWith(")")) {
+ // phases of eclipse are enclosed in (), remove them
+ p = p.substring(1, p.length()-1);
+ if(eclipse.length() > 0)
+ eclipse.append(",");
+ eclipse.append(Double.parseDouble(p));
+ } else {
+ if(periods.length() > 0)
+ periods.append(",");
+ periods.append(Double.parseDouble(p));
+ }
+ }
+ attributes.put("period", periods.toString());
+ attributes.put("eclipse", eclipse.toString());
+ }
+
+ if(mapObject instanceof Point) {
+
+ Light[] lights = parseLights(attributes.get("light"));
+ int[] periods = parsePeriods(attributes.get("period"));
+ int[] eclipse = parsePeriods(attributes.get("eclipse"));
+ if (!(periods.length == eclipse.length || 1 == periods.length))
+ log.error(objectName + ": number of light and eclipse phases has to be equal");
+
+ if(type8to15 == 0x0100) { // lights
+ byte flags0 = 0;
+ int lightType = lightType("");
+ if(meansYes(attributes.get("racon")))
+ flags0 |= FLAGS0_RACON_BIT;
+ int nob = 6;
+ if(note != null) {
+ nob += 3;
+ flags0 |= FLAGS0_NOTE_BIT;
+ }
+ if(intDesig != null) {
+ nob += 3;
+ flags0 |= FLAGS0_INT_DESIG_BIT;
+ }
+ if(localDesig != null) {
+ nob += 3;
+ flags0 |= FLAGS0_LOCAL_DESIG_BIT;
+ }
+ byte flags1 = 0;
+ if(lights.length > 1) {
+ for(Light l : lights)
+ nob += (l.colour != 0)? 3 : 2;
+ flags1 |= 0x08; // multiple lights
+ }
+ if(0 != eclipse.length) {
+ for(int p : periods) {
+ while(p > 0x3f) {
+ ++nob;
+ p -= 0x3f;
+ }
+ ++nob;
+ }
+ for(int p : eclipse) {
+ while(p > 0x3f) {
+ ++nob;
+ p -= 0x3f;
+ }
+ ++nob;
+ }
+ flags1 |= 0x01; // further record present?
+ }
+ else if(morseLetter != null)
+ flags1 |= 0x01; // further record present?
+ byte lightsDef = 0x22;
+ String hafs = attributes.get("height-above-foundation");
+ Integer hafi = null;
+ if(hafs != null) {
+ boolean[] hafsDistFlags = new boolean[2];
+ hafi = parseDistance(hafs, hafsDistFlags);
+ if(hafsDistFlags[DISTANCE_FLAG_TENTHS_INDEX])
+ hafi /= 10;
+ nob += (hafi > 255)? 2 : 1;
+ if(hafi > 255)
+ lightsDef |= 0x80;
+ else
+ lightsDef |= 0x40;
+ if(!hafsDistFlags[DISTANCE_FLAG_METRIC_INDEX])
+ lightsDef &= ~0x20;
+ }
+ String hads = attributes.get("height-above-datum");
+ Integer hadi = null;
+ if(hads != null) {
+ boolean[] hadsDistFlags = new boolean[2];
+ hadi = parseDistance(hads, hadsDistFlags);
+ if(hadsDistFlags[DISTANCE_FLAG_TENTHS_INDEX])
+ hadi /= 10;
+ nob += (hadi > 255)? 2 : 1;
+ if(hadi > 255)
+ lightsDef |= 0x08;
+ else
+ lightsDef |= 0x04;
+ if(!hadsDistFlags[DISTANCE_FLAG_METRIC_INDEX])
+ lightsDef &= ~0x02;
+ }
+ String las = attributes.get("leading-angle");
+ Integer leadingAngle = null;
+ if(las != null) {
+ leadingAngle = (int)(Double.parseDouble(las.trim()) * 10);
+ nob += 2;
+ flags1 |= 0x02; // leading angle present
+ }
+ int period = 0;
+ for(int p : periods)
+ period += p;
+ for(int p : eclipse)
+ period += p;
+ if(period > 255)
+ lightType |= 0x40; // 9th bit of period
+ else if(period > 511) {
+ period = 511;
+ log.warn("Can't encode periods greater than 51.1 seconds for lights");
+ }
+
+ extraBytes = new byte[nob + 2];
+ int i = 0;
+ extraBytes[i++] = (byte)(0xe0 | flags0);
+ extraBytes[i++] = (byte)((nob << 1) | 1); // bit0 always set?
+ extraBytes[i++] = (byte)(0x80 | lightType);
+ extraBytes[i++] = flags1;
+ extraBytes[i++] = lightsDef;
+ if(hafi != null) {
+ extraBytes[i++] = (byte)(int)hafi;
+ if(hafi > 255)
+ extraBytes[i++] = (byte)(hafi >> 8);
+ }
+ if(hadi != null) {
+ extraBytes[i++] = (byte)(int)hadi;
+ if(hadi > 255)
+ extraBytes[i++] = (byte)(hadi >> 8);
+ }
+ extraBytes[i++] = (byte)period;
+ if(note != null) {
+ int off = note.getOffset();
+ extraBytes[i++] = (byte)off;
+ extraBytes[i++] = (byte)(off >> 8);
+ extraBytes[i++] = (byte)(off >> 16);
+ }
+ if(localDesig != null) {
+ int off = localDesig.getOffset();
+ extraBytes[i++] = (byte)off;
+ extraBytes[i++] = (byte)(off >> 8);
+ extraBytes[i++] = (byte)(off >> 16);
+ }
+ if(intDesig != null) {
+ int off = intDesig.getOffset();
+ extraBytes[i++] = (byte)off;
+ extraBytes[i++] = (byte)(off >> 8);
+ extraBytes[i++] = (byte)(off >> 16);
+ }
+ if(leadingAngle != null) {
+ extraBytes[i++] = (byte)(int)leadingAngle;
+ extraBytes[i++] = (byte)(leadingAngle >> 8);
+ }
+ if(lights.length > 1) {
+ for(int l = 0; l < lights.length; ++l) {
+ int val = (lights[l].colour << 12) | (int)(lights[l].angle * 10);
+ if((l + 1) == lights.length)
+ val |= 0x8000;
+ extraBytes[i++] = (byte)val;
+ extraBytes[i++] = (byte)(val >> 8);
+ if(lights[l].colour != 0)
+ extraBytes[i++] = (byte)lights[l].range;
+ }
+ }
+ else {
+ int lc = 0;
+ int lr = 0;
+ if(lights.length > 0) {
+ lc = lights[0].colour;
+ lr = (int)lights[0].range & 0x1f;
+ }
+ extraBytes[i++] = (byte)((lc << 5) | lr);
+ }
+ if(periods.length > 1) {
+ extraBytes[i++] = (byte)(0x80 + periods.length);
+ // first all lights
+ for (int p : periods) {
+ while(p > 0x3f) {
+ extraBytes[i++] = (byte)0x3f;
+ p -= 0x3f;
+ }
+ extraBytes[i++] = (byte)p;
+ }
+ // second all pause
+ for (int p : eclipse) {
+ while(p > 0x3f) {
+ extraBytes[i++] = (byte)0x3f;
+ p -= 0x3f;
+ }
+ extraBytes[i++] = (byte)p;
+ }
+ }
+ else if(morseLetter != null)
+ extraBytes[i++] = morseLetter;
+ else
+ extraBytes[i++] = 0x01; // terminator?
+
+ return extraBytes;
+ }
+ else if(type8to15 == 0x0200) { // buoys
+ byte flags0 = 0;
+ int lt = lightType("");
+ if(meansYes(attributes.get("racon"))) {
+ // this doesn't get reported on mapsource
+ // maybe racons aren't supported for buoys?
+ flags0 |= FLAGS0_RACON_BIT;
+ }
+ int nob = 4;
+ if(note != null) {
+ nob += 3;
+ flags0 |= FLAGS0_NOTE_BIT;
+ }
+ if(intDesig != null) {
+ nob += 3;
+ flags0 |= FLAGS0_INT_DESIG_BIT;
+ }
+ if(localDesig != null) {
+ nob += 3;
+ flags0 |= FLAGS0_LOCAL_DESIG_BIT;
+ }
+ if(periods.length > 0)
+ ++nob; // for total period
+ byte flags1 = 0;
+ if(periods.length > 1) {
+ for(int p : periods) {
+ while(p > 0x3f) {
+ ++nob;
+ p -= 0x3f;
+ }
+ ++nob;
+ }
+ flags1 |= 0x02; // further record present?
+ }
+ else if(morseLetter != null)
+ flags1 |= 0x02; // further record present?
+ extraBytes = new byte[nob + 2];
+ int i = 0;
+ extraBytes[i++] = (byte)(0xe0 | flags0);
+ extraBytes[i++] = (byte)((nob << 1) | 1); // bit0 always set?
+ int lc = 0;
+ if(lights.length > 0) {
+ lc = lights[0].colour;
+ }
+ extraBytes[i++] = (byte)((lc << 6) | colour(""));
+ flags1 |= (byte)((lc >> 2) & 1); // bit 0 is MSB of light colour
+ extraBytes[i++] = flags1;
+ if(note != null) {
+ int off = note.getOffset();
+ extraBytes[i++] = (byte)off;
+ extraBytes[i++] = (byte)(off >> 8);
+ extraBytes[i++] = (byte)(off >> 16);
+ }
+ if(localDesig != null) {
+ int off = localDesig.getOffset();
+ extraBytes[i++] = (byte)off;
+ extraBytes[i++] = (byte)(off >> 8);
+ extraBytes[i++] = (byte)(off >> 16);
+ }
+ if(intDesig != null) {
+ int off = intDesig.getOffset();
+ extraBytes[i++] = (byte)off;
+ extraBytes[i++] = (byte)(off >> 8);
+ extraBytes[i++] = (byte)(off >> 16);
+ }
+ int period = 0;
+ for(int p : periods)
+ period += p;
+ if(period > 255) {
+ period = 255;
+ log.warn("Can't encode periods greater than 25.5 seconds for buoy lights");
+ }
+ byte flags2 = 0;
+ if(periods.length > 0)
+ flags2 |= (byte)0x80;
+ extraBytes[i++] = (byte)(flags2 | lt);
+ if(periods.length > 0) {
+ extraBytes[i++] = (byte)period;
+ if(periods.length > 1) {
+ if(periods.length > 2)
+ extraBytes[i++] = (byte)0x82;
+ else
+ extraBytes[i++] = (byte)0x81;
+ for(int p : periods) {
+ while(p > 0x3f) {
+ extraBytes[i++] = (byte)0x3f;
+ p -= 0x3f;
+ }
+ extraBytes[i++] = (byte)p;
+ }
+ }
+ else
+ extraBytes[i++] = 0x01; // terminator?
+ }
+ else if(morseLetter != null)
+ extraBytes[i++] = morseLetter;
+ else
+ extraBytes[i++] = 0x01; // terminator?
+
+ return extraBytes;
+ }
+ else if(type8to15 == 0x0300 || // things with depth/height
+ type8to15 == 0x0400) { // obstructions
+ String ds = attributes.get("depth");
+ if(ds == null)
+ ds = attributes.get("height");
+ if(ds != null) {
+ boolean[] distFlags = new boolean[2];
+ Integer di = parseDistance(ds, distFlags);
+ if(di != null) {
+ if(di > 255) {
+ extraBytes = new byte[3];
+ extraBytes[0] = (byte)0xa0;
+ }
+ else {
+ extraBytes = new byte[2];
+ extraBytes[0] = (byte)0x80;
+ }
+ if(distFlags[DISTANCE_FLAG_METRIC_INDEX])
+ extraBytes[0] |= 0x10;
+ if(distFlags[DISTANCE_FLAG_TENTHS_INDEX])
+ extraBytes[0] |= 0x08;
+ if(type8to15 == 0x0400) { // obstructions
+ extraBytes[0] |= position();
+ }
+ extraBytes[1] = (byte)(int)di;
+ if(di > 255)
+ extraBytes[2] = (byte)(di >> 8);
+
+ return extraBytes;
+ }
+ }
+ }
+ else if(type8to15 == 0x0500) { // label
+ String ss = attributes.get("style");
+ if(ss != null) {
+ int style = Integer.decode(ss.trim());
+ // format is 0xCC (CC = colour)
+ extraBytes = new byte[1];
+ extraBytes[0] = (byte)(style & 0xf);
+ return extraBytes;
+ }
+ }
+ else if(type0to15 == 0x0903) { // facility
+ String fs = attributes.get("facilities");
+ if(fs != null) {
+ int facilities = Integer.decode(fs.trim());
+ extraBytes = new byte[3];
+ extraBytes[0] = (byte)(0xa0 | (facilities & 0x1f));
+ extraBytes[1] = (byte)(facilities >> 5);
+ extraBytes[2] = (byte)(((facilities >> 13) & 0x07) |
+ ((facilities >> 12) & 0x18));
+ return extraBytes;
+ }
+ }
+ }
+ else if(mapObject instanceof Polyline) {
+
+ if(type8to15 == 0x0300 || // depth areas
+ (!(mapObject instanceof Polygon) &&
+ (type0to15 == 0x0105 || // contour line
+ type0to15 == 0x0106 || // overhead cable
+ type0to15 == 0x0107))) { // bridge
+ String ds = attributes.get("depth");
+ if(ds == null)
+ ds = attributes.get("height");
+ if(ds != null) {
+ boolean[] distFlags = new boolean[2];
+ Integer di = parseDistance(ds, distFlags);
+ if(di != null) {
+ if(di > 255) {
+ extraBytes = new byte[3];
+ extraBytes[0] = (byte)0xa0;
+ }
+ else {
+ extraBytes = new byte[2];
+ extraBytes[0] = (byte)0x80;
+ }
+ if(distFlags[DISTANCE_FLAG_METRIC_INDEX])
+ extraBytes[0] |= 0x10;
+ if(distFlags[DISTANCE_FLAG_TENTHS_INDEX])
+ extraBytes[0] |= 0x08;
+ if(type8to15 == 0x04) { // obstructions
+ extraBytes[0] |= position();
+ }
+ extraBytes[1] = (byte)(int)di;
+ if(di > 255)
+ extraBytes[2] = (byte)(di >> 8);
+
+ return extraBytes;
+ }
+ }
+ }
+ else if(!(mapObject instanceof Polygon) &&
+ (type8to15 == 0x0400 || // various lines
+ type8to15 == 0x0500 ||
+ type8to15 == 0x0600)) {
+ String ss = attributes.get("style");
+ if(ss != null) {
+ int style = Integer.decode(ss.trim());
+ if ((style & 0xff00) == 0) {
+ // format is 0xCC (CC = colour)
+ extraBytes = new byte[1];
+ extraBytes[0] = (byte) (style & 0xf);
+ } else {
+ // format is 0xSSCC (SS = style, CC = colour)
+ extraBytes = new byte[2];
+ extraBytes[0] = (byte) (0x80 | (style & 0xf));
+ extraBytes[1] = (byte) (((style >> 9) & 0x18) | ((style >> 8) & 0x3));
+ }
+ return extraBytes;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private boolean meansYes(String s) {
+ if(s == null)
+ return false;
+ s = s.toLowerCase();
+ return ("yes".startsWith(s) || "true".startsWith(s) || "1".equals(s));
+ }
+
+ private Integer parseDistance(String ds, boolean[] flags) {
+ ParsePosition pp = new ParsePosition(0);
+ Number dn = new DecimalFormat().parse(ds, pp);
+ if(dn != null) {
+ double dd = dn.doubleValue();
+ int di = dn.intValue();
+ flags[DISTANCE_FLAG_METRIC_INDEX] = true;
+ flags[DISTANCE_FLAG_TENTHS_INDEX] = false;
+ if("ft".equals(ds.substring(pp.getIndex()).trim().toLowerCase()))
+ flags[DISTANCE_FLAG_METRIC_INDEX] = false;
+ if((double)di != dd) {
+ // number has fractional part
+ di = (int)(dd * 10);
+ flags[DISTANCE_FLAG_TENTHS_INDEX] = true;
+ }
+
+ return di;
+ }
+
+ return null;
+ }
+
+ private int colour(String prefix) {
+
+ String c = attributes.get(prefix + "colour");
+ if(c == null)
+ c = attributes.get(prefix + "color");
+ if(c == null)
+ return 0;
+
+ c = c.trim();
+
+ if(Character.isDigit(c.charAt(0))) {
+ return Integer.decode(c);
+ }
+
+ String[] colours = {
+ "",
+ "red",
+ "green",
+ "yellow",
+ "white",
+ "black",
+ "black-yellow",
+ "white-red",
+ "black-red",
+ "white-green",
+ "red-yellow",
+ "red-green",
+ "orange",
+ "black-yellow-black",
+ "yellow-black",
+ "yellow-black-yellow",
+ "red-white",
+ "green-red-green",
+ "red-green-red",
+ "black-red-black",
+ "yellow-red-yellow",
+ "green-red",
+ "black-white",
+ "white-orange",
+ "orange-white",
+ "green-white"
+ };
+
+ c = c.toLowerCase().replaceAll("[;, ]+", "-");
+
+ for(int i = 0; i < colours.length; ++i)
+ if(colours[i].equals(c))
+ return i;
+
+ return 0;
+ }
+
+ private int lightType(String prefix) {
+ String lt = attributes.get(prefix + "type");
+ if(lt == null)
+ return 0;
+
+ lt = lt.trim();
+
+ if(Character.isDigit(lt.charAt(0))) {
+ return Integer.decode(lt);
+ }
+
+ if(lt.length() == 1) {
+ morseLetter = (byte)lt.charAt(0);
+ return 0x0b;
+ }
+
+ String[] types = {
+ "",
+ "fixed",
+ "isophase",
+ "flashing",
+ "group flashing",
+ "composite group flashing",
+ "occulting",
+ "group occulting",
+ "composite group occulting",
+ "long flashing",
+ "group long flashing",
+ "morse code letter",
+ "quick",
+ "group quick",
+ "group quick and long flashing",
+ "interrupted quick",
+ "very quick",
+ "group very quick",
+ "group very quick and long flashing",
+ "interrupted very quick",
+ "ultra quick",
+ "interrupted ultra quick",
+ "fixed and occulting",
+ "fixed and group occulting",
+ "fixed and isophase",
+ "fixed and flashing",
+ "fixed and group flashing",
+ "fixed and long flashing",
+ "alternating",
+ "alternating occulting",
+ "alternating flashing",
+ "alternating group flashing"
+ };
+
+ lt = lt.toLowerCase();
+
+ for(int i = 0; i < types.length; ++i)
+ if(types[i].equals(lt))
+ return i;
+
+ return 0;
+ }
+
+ private int position() {
+ String ps = attributes.get("position");
+ if(ps == null)
+ return 0;
+
+ ps = ps.trim();
+
+ if(Character.isDigit(ps.charAt(0))) {
+ return Integer.decode(ps);
+ }
+
+ String[] positions = {
+ "unknown",
+ "",
+ "doubtful",
+ "existence doubtful",
+ "approximate",
+ "reported"
+ };
+
+ ps = ps.toLowerCase();
+
+ for(int i = 0; i < positions.length; ++i)
+ if(positions[i].equals(ps))
+ return i;
+
+ return 0;
+ }
+
+ private int[] parsePeriods(String ps) {
+ if(ps == null)
+ return ZERO_INT_ARRAY;
+ String [] psa = ps.split(",");
+ int [] periods = new int[psa.length];
+ for(int i = 0; i < psa.length; ++i)
+ periods[i] = (int)(Double.parseDouble(psa[i].trim()) * 10);
+ return periods;
+ }
+
+ private Light[] parseLights(String ls) {
+ if(ls == null)
+ return new Light[0];
+ ls = ls.trim();
+ String[] defs = new String[0];
+ if(ls.startsWith("(")) {
+ // handle polish syntax "(c,r,a),(c,r,a)..."
+ List<String> out = new ArrayList<String>();
+ int start = 0;
+ // start should be on the '(' at the start of the loop
+ while(start < ls.length()) {
+ int end = ++start;
+ while(end < ls.length() && ls.charAt(end) != ')')
+ ++end;
+ out.add(ls.substring(start, end));
+ start = end + 1;
+ while(start < ls.length() && ls.charAt(start) != '(')
+ ++start;
+ }
+ defs = out.toArray(defs);
+ }
+ else {
+ // handle our "simple" syntax
+ defs = ls.split("[:;/]");
+ }
+ Light[] lights = new Light[defs.length];
+ for(int i = 0; i < defs.length; ++i) {
+ String def = defs[i].trim();
+ if(def.length() > 0)
+ lights[i] = new Light(def);
+ }
+ return lights;
+ }
+
+ class Light {
+ private int colour;
+ private double range;
+ private double angle;
+
+ final String[] colours = {
+ "unlit",
+ "red",
+ "green",
+ "white",
+ "blue",
+ "yellow",
+ "violet",
+ "amber"
+ };
+
+ public Light(String desc) {
+ String[] parts = desc.split(",");
+ if(parts.length > 0) {
+ String lc = parts[0].trim().toLowerCase();
+ if(Character.isDigit(lc.charAt(0))) {
+ colour = Integer.decode(lc);
+ }
+ else {
+ for(int i = 0; i < colours.length; ++i) {
+ if(colours[i].equals(lc)) {
+ colour = i;
+ break;
+ }
+ }
+ }
+ }
+ if(parts.length > 1 && colour != 0)
+ range = Double.parseDouble(parts[1]);
+ if(parts.length > 2)
+ angle = Double.parseDouble(parts[2]);
+
+ //System.err.println("light = " + this);
+ }
+
+ public String toString() {
+ return "(" + colours[colour] + "," + range + "," + angle + ")";
+ }
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/InternalFiles.java b/src/uk/me/parabola/imgfmt/app/trergn/InternalFiles.java
new file mode 100644
index 0000000..180e0be
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/InternalFiles.java
@@ -0,0 +1,41 @@
+/*
+ * 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: 21-Jan-2007
+ */
+package uk.me.parabola.imgfmt.app.trergn;
+
+import uk.me.parabola.imgfmt.app.lbl.LBLFile;
+import uk.me.parabola.imgfmt.app.net.NETFile;
+import uk.me.parabola.imgfmt.app.net.NODFile;
+
+/**
+ * Interface to pass around the internal files in the map without
+ * passing the whole thing.
+ *
+ * This is a bad part of the design, particularly how it is used in Subdivision.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface InternalFiles {
+ public RGNFile getRgnFile();
+
+ public LBLFile getLblFile();
+
+ public TREFile getTreFile();
+
+ public NETFile getNetFile();
+
+ public NODFile getNodFile();
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/LinePreparer.java b/src/uk/me/parabola/imgfmt/app/trergn/LinePreparer.java
new file mode 100644
index 0000000..5bf334e
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/LinePreparer.java
@@ -0,0 +1,383 @@
+/**
+ * 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
+ * Date: 24-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app.trergn;
+
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.BitWriter;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+
+/**
+ * This class holds all of the calculations needed to encode a line into
+ * the garmin format.
+ */
+class LinePreparer {
+ private static final Logger log = Logger.getLogger(LinePreparer.class);
+
+ // These are our inputs.
+ private final Polyline polyline;
+
+ private boolean extraBit;
+ private final boolean extTypeLine;
+ private boolean xSameSign;
+ private boolean xSignNegative; // Set if all negative
+
+ private boolean ySameSign;
+ private boolean ySignNegative; // Set if all negative
+
+ // The base number of bits
+ private int xBase;
+ private int yBase;
+
+ // The delta changes between the points.
+ private int[] deltas;
+ private boolean[] nodes;
+
+ LinePreparer(Polyline line) {
+ if (line.isRoad() &&
+ line.getSubdiv().getZoom().getLevel() == 0 &&
+ line.roadHasInternalNodes()) {
+ // it might be safe to write the extra bits regardless,
+ // but who knows
+ extraBit = true;
+ }
+
+ extTypeLine = line.hasExtendedType();
+
+ polyline = line;
+ calcLatLong();
+ calcDeltas();
+ }
+
+ /**
+ * Write the bit stream to a BitWriter and return it.
+ *
+ * @return A class containing the written byte stream.
+ */
+ public BitWriter makeBitStream(int minPointsRequired) {
+
+ assert xBase >= 0 && yBase >= 0;
+
+ int xbits = 2;
+ if (xBase < 10)
+ xbits += xBase;
+ else
+ xbits += (2 * xBase) - 9;
+
+ int ybits = 2;
+ if (yBase < 10)
+ ybits += yBase;
+ else
+ ybits += (2 * yBase) - 9;
+
+ // Note no sign included.
+ if (log.isDebugEnabled())
+ log.debug("xbits", xbits, ", y=", ybits);
+
+ // Write the bitstream
+ BitWriter bw = new BitWriter();
+
+ // Pre bit stream info
+ bw.putn(xBase, 4);
+ bw.putn(yBase, 4);
+
+ bw.put1(xSameSign);
+ if (xSameSign)
+ bw.put1(xSignNegative);
+
+ bw.put1(ySameSign);
+ if (ySameSign)
+ bw.put1(ySignNegative);
+
+ if (log.isDebugEnabled()) {
+ log.debug("x same is", xSameSign, "sign is", xSignNegative);
+ log.debug("y same is", ySameSign, "sign is", ySignNegative);
+ }
+
+ if(extTypeLine) {
+ bw.put1(false); // no extra bits required
+ }
+
+ // first extra bit always appears to be false
+ // refers to the start point?
+ if (extraBit)
+ bw.put1(false);
+
+ int numPointsEncoded = 1;
+ for (int i = 0; i < deltas.length; i+=2) {
+ int dx = deltas[i];
+ int dy = deltas[i + 1];
+ if (dx == 0 && dy == 0)
+ continue;
+
+ ++numPointsEncoded;
+
+ if (log.isDebugEnabled())
+ log.debug("x delta", dx, "~", xbits);
+ assert dx >> xbits == 0 || dx >> xbits == -1;
+ if (xSameSign) {
+ bw.putn(abs(dx), xbits);
+ } else {
+ // catch inadvertent output of "magic" value that has
+ // sign bit set but other bits all 0
+ assert dx >= 0 || (dx & ((1 << xbits) - 1)) != 0;
+ bw.putn(dx, xbits);
+ bw.put1(dx < 0);
+ }
+
+ if (log.isDebugEnabled())
+ log.debug("y delta", dy, ybits);
+ assert dy >> ybits == 0 || dy >> ybits == -1;
+ if (ySameSign) {
+ bw.putn(abs(dy), ybits);
+ } else {
+ // catch inadvertent output of "magic" value that has
+ // sign bit set but other bits all 0
+ assert dy >= 0 || (dy & ((1 << ybits) - 1)) != 0;
+ bw.putn(dy, ybits);
+ bw.put1(dy < 0);
+ }
+ if (extraBit)
+ bw.put1(nodes[i/2+1]);
+ }
+
+ if (log.isDebugEnabled())
+ log.debug(bw);
+
+ if(numPointsEncoded < minPointsRequired)
+ return null;
+
+ return bw;
+ }
+
+ /**
+ * Calculate the correct lat and long points. They must be shifted if
+ * required by the zoom level. The point that is taken to be the
+ * location is just the first point in the line.
+ */
+ private void calcLatLong() {
+ Coord co = polyline.getPoints().get(0);
+
+ polyline.setLatitude(co.getLatitude());
+ polyline.setLongitude(co.getLongitude());
+ }
+
+ /**
+ * Calculate the deltas of one point to the other. While we are doing
+ * this we must save more information about the maximum sizes, if they
+ * are all the same sign etc. This must be done separately for both
+ * the lat and long values.
+ */
+ private void calcDeltas() {
+ Subdivision subdiv = polyline.getSubdiv();
+ if(log.isDebugEnabled())
+ log.debug("label offset", polyline.getLabel().getOffset());
+ int shift = subdiv.getShift();
+ List<Coord> points = polyline.getPoints();
+
+ // Space to hold the deltas
+ int numPointsToUse = points.size();
+ if (polyline instanceof Polygon){
+ if (points.get(0).equals(points.get(points.size()-1)))
+ --numPointsToUse; // no need to write the closing point
+ }
+ deltas = new int[2 * (numPointsToUse - 1)];
+
+ if (extraBit)
+ nodes = new boolean[numPointsToUse];
+ boolean first = true;
+
+ // OK go through the points
+ int lastLat = 0;
+ int lastLong = 0;
+ boolean xDiffSign = false; // The long values have different sign
+ boolean yDiffSign = false; // The lat values have different sign
+ int xSign = 0; // If all the same sign, then this 1 or -1 depending on +ve or -ve
+ int ySign = 0; // As above for lat.
+ int xBits = 0; // Number of bits needed for long
+ int yBits = 0; // Number of bits needed for lat.
+
+ // index of first point in a series of identical coords (after shift)
+ int firstsame = 0;
+ for (int i = 0; i < numPointsToUse; i++) {
+ Coord co = points.get(i);
+
+ int lat = subdiv.roundLatToLocalShifted(co.getLatitude());
+ int lon = subdiv.roundLonToLocalShifted(co.getLongitude());
+ if (log.isDebugEnabled())
+ log.debug("shifted pos", lat, lon);
+ if (first) {
+ lastLat = lat;
+ lastLong = lon;
+ first = false;
+ continue;
+ }
+
+ // compute normalized differences
+ // -2^(shift-1) <= dx, dy < 2^(shift-1)
+ // XXX: relies on the fact that java integers are 32 bit signed
+ final int offset = 8+shift;
+ int dx = (lon - lastLong) << offset >> offset;
+ int dy = (lat - lastLat) << offset >> offset;
+ assert (dx == 0 && lon != lastLong) == false: ("delta lon too large: " + (lon - lastLong));
+ assert (dy == 0 && lat != lastLat) == false: ("delta lat too large: " + (lat - lastLat));
+ lastLong = lon;
+ lastLat = lat;
+
+ if (dx != 0 || dy != 0)
+ firstsame = i;
+
+ /*
+ * Current thought is that the node indicator is set when
+ * the point is a node. There's a separate first extra bit
+ * that always appears to be false. The last points' extra bit
+ * is set if the point is a node and this is not the last
+ * polyline making up the road.
+ * Todo: special case the last bit
+ */
+ if (extraBit) {
+ boolean extra = false;
+ if (co.getId() != 0) {
+ if (i < nodes.length - 1)
+ // inner node of polyline
+ extra = true;
+ else
+ // end node of polyline: set if inner
+ // node of road
+ extra = !polyline.isLastSegment();
+ }
+
+ /*
+ * Only the first among a range of equal points
+ * is written, so set the bit if any of the points
+ * is a node.
+ * Since we only write extra bits at level 0 now,
+ * this can only happen when points in the input
+ * data round to the same point in map units, so
+ * it may be better to handle this in the
+ * reader.
+ */
+ nodes[firstsame] = nodes[firstsame] || extra;
+ }
+
+ // See if they can all be the same sign.
+ if (!xDiffSign) {
+ int thisSign = (dx >= 0)? 1: -1;
+ if (xSign == 0) {
+ xSign = thisSign;
+ } else if (thisSign != xSign) {
+ // The signs are different
+ xDiffSign = true;
+ }
+ }
+ if (!yDiffSign) {
+ int thisSign = (dy >= 0)? 1: -1;
+ if (ySign == 0) {
+ ySign = thisSign;
+ } else if (thisSign != ySign) {
+ // The signs are different
+ yDiffSign = true;
+ }
+ }
+
+ // Find the maximum number of bits required to hold the value.
+ int nbits = bitsNeeded(dx);
+ if (nbits > xBits)
+ xBits = nbits;
+
+ nbits = bitsNeeded(dy);
+ if (nbits > yBits)
+ yBits = nbits;
+
+ // Save the deltas
+ deltas[2*(i-1)] = dx;
+ deltas[2*(i-1) + 1] = dy;
+ }
+
+ // Now we need to know the 'base' number of bits used to represent
+ // the value. In decoding you start with that number and add various
+ // adjustments to get the final value. We need to try and work
+ // backwards from this.
+ //
+ // I don't care about getting the smallest possible file size so
+ // err on the side of caution.
+ //
+ // Note that the sign bit is already not included so there is
+ // no adjustment needed for it.
+
+ if (log.isDebugEnabled())
+ log.debug("initial xBits, yBits", xBits, yBits);
+
+ if (xBits < 2)
+ xBits = 2;
+ int tmp = xBits - 2;
+ if (tmp > 10) {
+ if ((tmp & 0x1) == 0)
+ tmp++;
+ tmp = 9 + (tmp - 9) / 2;
+ }
+ this.xBase = tmp;
+
+ if (yBits < 2)
+ yBits = 2;
+ tmp = yBits - 2;
+ if (tmp > 10) {
+ if ((tmp & 0x1) == 0)
+ tmp++;
+ tmp = 9 + (tmp - 9) / 2;
+ }
+ this.yBase = tmp;
+
+ if (log.isDebugEnabled())
+ log.debug("initial xBase, yBase", xBase, yBase);
+
+ // Set flags for same sign etc.
+ this.xSameSign = !xDiffSign;
+ this.ySameSign = !yDiffSign;
+ this.xSignNegative = xSign < 0;
+ this.ySignNegative = ySign < 0;
+ }
+
+ /**
+ * The bits needed to hold a number without truncating it.
+ *
+ * @param val The number for bit counting.
+ * @return The number of bits required.
+ */
+ private int bitsNeeded(int val) {
+ int n = abs(val);
+
+ int count = val < 0? 1: 0;
+ while (n != 0) {
+ n >>>= 1;
+ count++;
+ }
+ return count;
+ }
+
+ private int abs(int val) {
+ if (val < 0)
+ return -val;
+ else
+ return val;
+ }
+
+ public boolean isExtraBit() {
+ return extraBit;
+ }
+
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/MapObject.java b/src/uk/me/parabola/imgfmt/app/trergn/MapObject.java
new file mode 100644
index 0000000..4152e66
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/MapObject.java
@@ -0,0 +1,178 @@
+/*
+ * 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: 12-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app.trergn;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+
+/**
+ * An object that appears in a map. One of point, polyline, polygon or indexed
+ * point.
+ *
+ * All objects appear in a subdivision and are relative to it. You cannot
+ * know where the object is or its size without knowing the subdivision it
+ * is in.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class MapObject {
+
+ // All lines are in a division and many aspects of it are with respect to
+ // the division.
+ private Subdivision subdiv;
+
+ // The label(s) for this object
+ private Label label;
+ private List<Label> refLabels;
+
+ // The type of road etc.
+ private int type;
+
+ // These long and lat values are relative to the subdivision center.
+ // Must be shifted depending on the zoom level.
+ private int deltaLong;
+ private int deltaLat;
+
+ private ExtTypeAttributes extTypeAttributes;
+
+ // The number of this point within its subdivision. Set on read only.
+ private int number;
+
+ /**
+ * Write this object to the given file.
+ *
+ * @param file The file to write to. It is usually the RGN file.
+ */
+ public abstract void write(ImgFileWriter file);
+
+ public abstract void write(OutputStream stream) throws IOException;
+
+ int getDeltaLat() {
+ return deltaLat;
+ }
+
+ protected int getDeltaLong() {
+ return deltaLong;
+ }
+
+ public void setLabel(Label label) {
+ this.label = label;
+ }
+
+ public void addRefLabel(Label refLabel) {
+ if(refLabels == null)
+ refLabels = new ArrayList<Label>();
+ refLabels.add(refLabel);
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ public boolean hasExtendedType() {
+ return hasExtendedType(type);
+ }
+
+ public static boolean hasExtendedType(int type) {
+ return type >= 0x010000;
+ }
+
+ /**
+ * Set an ordinary unshifted latitude. It will be calculated
+ * relative to the subdivision.
+ *
+ * @param lat The original latitude.
+ */
+ public void setLatitude(int lat) {
+ Subdivision div = getSubdiv();
+
+ int diff = div.roundLatToLocalShifted(lat);
+
+ setDeltaLat(diff);
+ }
+
+ /**
+ * Set an ordinary unshifted longitude. It will be calculated
+ * relative to the subdivision.
+ *
+ * @param lon The original longitude.
+ */
+ public void setLongitude(int lon) {
+ Subdivision div = getSubdiv();
+
+ int diff = div.roundLonToLocalShifted(lon);
+
+ setDeltaLong(diff);
+ }
+
+ // directly setting shouldn't be done, unless reading from a file
+ protected void setDeltaLat(int deltaLat) {
+ assert deltaLat >= -0x8000 && deltaLat <= 0x7fff : "deltaLat = " + deltaLat;
+ this.deltaLat = deltaLat;
+ }
+
+ // directly setting shouldn't be done, unless reading from a file
+ protected void setDeltaLong(int deltaLong) {
+ assert deltaLong >= -0x8000 && deltaLong <= 0x7fff : "deltaLong = " + deltaLong;
+ this.deltaLong = deltaLong;
+ }
+
+ public Subdivision getSubdiv() {
+ return subdiv;
+ }
+
+ protected void setSubdiv(Subdivision subdiv) {
+ this.subdiv = subdiv;
+ }
+
+ public Label getLabel() {
+ return label;
+ }
+
+ public List<Label> getRefLabels() {
+ return refLabels;
+ }
+
+ protected byte[] getExtTypeExtraBytes() {
+ return (extTypeAttributes != null)? extTypeAttributes.getExtTypeExtraBytes(this) : null;
+ }
+
+ public void setExtTypeAttributes(ExtTypeAttributes eta) {
+ extTypeAttributes = eta;
+ }
+
+ public String toString() {
+ return "Type=" + type + ", l=" + label;
+ }
+
+ public int getNumber() {
+ return number;
+ }
+
+ public void setNumber(int number) {
+ this.number = number;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/MapValues.java b/src/uk/me/parabola/imgfmt/app/trergn/MapValues.java
new file mode 100644
index 0000000..a56e236
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/MapValues.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2008 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: 18-Jun-2008
+ */
+package uk.me.parabola.imgfmt.app.trergn;
+
+/**
+ * Class to calculate the values that occur at offset 9a in the TRE header.
+ * As I don't know the purpose of these the naming is a bit arbitrary here...
+ *
+ * This was worked out in the display project, so see the TreCalc file
+ * there for more history. This is a cleaned up version of what was
+ * written there.
+ *
+ * @author Steve Ratcliffe
+ * @see <a href="http://svn.parabola.me.uk/display/trunk/src/test/display/TreCalc.java">TreCalc.java</a>
+ */
+public class MapValues {
+ private final int mapId;
+ private final int length;
+
+ private final byte[][] values = new byte[4][8];
+
+ // Converts the digits in the map id to the values seen in this section.
+ private static final byte[] mapIdCodeTable = {
+ 0, 1, 0xf, 5,
+ 0xd, 4, 7, 6,
+ 0xb, 9, 0xe, 8,
+ 2, 0xa, 0xc, 3
+ };
+
+ // Used to work out the required offset that is applied to all the
+ // digits of the values.
+ private final int[] offsetMap = {
+ 6, 7, 5, 11,
+ 3, 10, 13, 12,
+ 1, 15, 4, 14,
+ 8, 0, 2, 9
+ };
+
+ public MapValues(int mapId, int headerLength) {
+ this.mapId = mapId;
+ this.length = headerLength;
+ }
+
+ /**
+ * There are four values. Get value n.
+ * @param n Get value n, starting at 0 up to four.
+ */
+ public int value(int n) {
+ byte[] out = values[n];
+
+ int res = 0;
+ for (int i = 0; i < 8; i++) {
+ res |= ((out[i] & 0xf) << (4 * (7 - i)));
+ }
+ return res;
+ }
+
+ public void calculate() {
+ // Done in this order because the first and second depend on things
+ // we have already calculated in three.
+ calcThird();
+ calcFourth();
+ calcFirst();
+ calcSecond();
+
+ addOffset();
+ }
+
+ /**
+ * Add an offset to all previously calculated values.
+ */
+ private void addOffset() {
+ // To get the offset value we add up all the even nibbles of the map
+ // number and transform via a table.
+ int n = mapIdDigit(1) + mapIdDigit(3) + mapIdDigit(5) + mapIdDigit(7);
+
+ int offset = offsetMap[n & 0xf];
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 8; j++) {
+ values[i][j] += offset;
+ }
+ }
+ }
+
+ /**
+ * This value is made from the third value, combined with the raw
+ * map id values.
+ */
+ private void calcFirst() {
+ byte[] out = values[0];
+ byte[] v3 = values[3];
+
+ // First bytes are the low bytes of the mapId, with the corresponding
+ // value from value[3] added.
+ out[0] = (byte) (mapIdDigit(4) + v3[0]);
+ out[1] = (byte) (mapIdDigit(5) + v3[1]);
+ out[2] = (byte) (mapIdDigit(6) + v3[2]);
+ out[3] = (byte) (mapIdDigit(7) + v3[3]);
+
+ // Copies of v3
+ out[4] = v3[4];
+ out[5] = v3[5];
+ out[6] = v3[6];
+
+ // Always (?) one more. The one likely comes from some other
+ // part of the header, but we don't know if or where.
+ out[7] = (byte) (v3[7] + 1);
+ }
+
+ /**
+ * This is made from various parts of the third value and the raw digits
+ * from the map id. There are two digits where the header length digits
+ * are used (or that could be a coincidence, but it holds up well so far).
+ */
+ private void calcSecond() {
+ byte[] out = values[1];
+ byte[] v3 = values[3];
+
+ // Just same as in v3
+ out[0] = v3[0];
+ out[1] = v3[1];
+
+ int h1 = length >> 4;
+ int h2 = length;
+ out[2] = (byte) ((v3[2] + h1) & 0xf);
+ out[3] = (byte) ((v3[3] + h2) & 0xf);
+
+ // The following are the sum of individual nibbles in U3 and the
+ // corresponding nibble in the top half of mapId.
+ out[4] = (byte) (v3[4] + mapIdDigit(0));
+ out[5] = (byte) (v3[5] + mapIdDigit(1));
+ out[6] = (byte) (v3[6] + mapIdDigit(2));
+ out[7] = (byte) (v3[7] + mapIdDigit(3));
+ }
+
+ /**
+ * This is made of the hex digits of the map id in a given order
+ * translated according to a given table of values.
+ */
+ private void calcThird() {
+ byte[] out = values[2];
+ for (int i = 0; i < 8; i++) {
+ int n = mapIdDigit(i);
+ out[(i ^ 1)] = mapIdCodeTable[n];
+ }
+ }
+
+ /**
+ * This is just a copy of the third value.
+ */
+ private void calcFourth() {
+ System.arraycopy(values[2], 0, values[3], 0, values[3].length);
+ }
+
+ /**
+ * Extract the given nibble of the map id. 0 is the highest four bits.
+ * @param i The nibble number, 0 most significant, 7 the least.
+ * @return The given nibble of the map id.
+ */
+ private int mapIdDigit(int i) {
+ return (mapId >>> (4 * (7 - i))) & 0xf;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/Overview.java b/src/uk/me/parabola/imgfmt/app/trergn/Overview.java
new file mode 100644
index 0000000..9d5076b
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/Overview.java
@@ -0,0 +1,155 @@
+/*
+ * 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: 09-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app.trergn;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * This is for polyline, polygon and point overviews. A simple record that
+ * holds the type of an object and the highest level at which it is found.
+ *
+ * It kind of declares which objects will appear in the map and if they
+ * are not included here they will not be shown.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class Overview implements Comparable<Overview> {
+ public static final int POINT_KIND = 1;
+ public static final int LINE_KIND = 2;
+ public static final int SHAPE_KIND = 3;
+
+ private final int kind; // The kind of overview; point, line etc.
+ private final char extType;
+ private final char type;
+ private final char subType;
+ private final int minResolution;
+ private final int size;
+
+ private int maxLevel;
+
+ protected Overview(int kind, int fullType, int minres) {
+ this.kind = kind;
+
+ this.extType = (char)((fullType >> 16) & 0xff);
+ this.type = (char) (fullType >> 8 & 0xff);
+ this.subType = (char) (fullType & 0xff);
+ this.minResolution = minres;
+
+ if (kind == POINT_KIND)
+ size = 3;
+ else
+ size = 2;
+ }
+
+ public void write(ImgFileWriter file) {
+ if (extType == 0) {
+ file.put((byte) (type & 0xff));
+ file.put((byte) maxLevel);
+ if (size > 2)
+ file.put((byte) (subType & 0xff));
+ } else {
+ file.put((byte) type);
+ file.put((byte) maxLevel);
+ file.put((byte) subType);
+ file.put((byte) 0);
+ }
+ }
+
+ /**
+ * Returns a hash code value for the object.
+ *
+ * @return a hash code value for this object.
+ * @see Object#equals(Object)
+ */
+ public int hashCode() {
+ return (kind << 7) + (type << 3) + subType;
+ }
+
+ /**
+ * Indicates whether some other object is "equal to" this one.
+ *
+ * @param obj the reference object with which to compare.
+ * @return <code>true</code> if this object is the same as the obj
+ * argument; <code>false</code> otherwise.
+ * @see #hashCode()
+ */
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Overview))
+ return false;
+
+ Overview ov = (Overview) obj;
+ return (ov.kind == kind &&
+ ov.extType == extType &&
+ ov.type == type &&
+ ov.subType == subType);
+ }
+
+ public int getKind() {
+ return kind;
+ }
+
+ /**
+ * Compares this object with the specified object for order. Returns a
+ * negative integer, zero, or a positive integer as this object is less
+ * than, equal to, or greater than the specified object.
+ *
+ * @param ov the object to be compared.
+ * @return a negative integer, zero, or a positive integer as this object
+ * is less than, equal to, or greater than the specified object.
+ * @throws ClassCastException if the specified object's type prevents it
+ * from being compared to this object.
+ */
+ public int compareTo(Overview ov) {
+ if (kind != ov.kind) {
+ return kind > ov.kind ? 1 : -1;
+ }
+
+ if(extType != ov.extType) {
+ return extType > ov.extType? 1: -1;
+ }
+
+ int res;
+ if (type == ov.type) {
+ if (subType == ov.subType)
+ res = 0;
+ else if (subType > ov.subType)
+ res = 1;
+ else
+ res = -1;
+ } else {
+ if (type == ov.type)
+ res = 0;
+ else if (type > ov.type)
+ res = 1;
+ else
+ res = -1;
+ }
+ return res;
+ }
+
+ public void setMaxLevel(int maxLevel) {
+ this.maxLevel = maxLevel;
+ }
+
+ public int getMinResolution() {
+ return minResolution;
+ }
+
+ public boolean hasExtType() {
+ return extType != 0;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/Point.java b/src/uk/me/parabola/imgfmt/app/trergn/Point.java
new file mode 100644
index 0000000..d72d31f
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/Point.java
@@ -0,0 +1,133 @@
+/*
+ * 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: 09-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app.trergn;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.lbl.POIRecord;
+
+/**
+ * Represents a particular point object on a map. A point has a type (town
+ * restaurant etc) and a location as well as a name.
+ *
+ * A point belongs to a particular subdivision and cannot be interpreted without
+ * it as all details are relative to the subdivision.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Point extends MapObject {
+ // Points can link to a POIRecord
+ private POIRecord poi;
+
+ public Point(Subdivision div) {
+ setSubdiv(div);
+ }
+
+ /**
+ * Format and write the contents of the object to the given
+ * file.
+ *
+ * @param file A reference to the file that should be written to.
+ */
+ public void write(ImgFileWriter file) {
+ boolean hasSubtype = false;
+ int type = getType();
+ byte subtype = 0;
+ if (type > 0xff) {
+ if((type & 0xff) != 0) {
+ hasSubtype = true;
+ subtype = (byte) type;
+ }
+ type >>= 8;
+ }
+
+ file.put((byte) type);
+
+ int off = getLabel().getOffset();
+ if (poi != null) {
+ off = poi.getOffset();
+ off |= 0x400000;
+ }
+ if (hasSubtype)
+ off |= 0x800000;
+
+ file.put3(off);
+ file.putChar((char) getDeltaLong());
+ file.putChar((char) getDeltaLat());
+ if (hasSubtype)
+ file.put(subtype);
+ }
+
+ /*
+ * write the point to an OutputStream - only use for outputting
+ * points with extended (3 byte) types.
+ *
+ */
+ public void write(OutputStream stream) throws IOException {
+ assert hasExtendedType();
+ int type = getType();
+ int labelOff = getLabel().getOffset();
+ byte[] extraBytes = getExtTypeExtraBytes();
+
+ if (poi != null) {
+ labelOff = poi.getOffset();
+ labelOff |= 0x400000;
+ }
+ if(labelOff != 0)
+ type |= 0x20; // has label
+ if(extraBytes != null)
+ type |= 0x80; // has extra bytes
+ stream.write(type >> 8);
+ stream.write(type);
+
+ int deltaLong = getDeltaLong();
+ int deltaLat = getDeltaLat();
+ stream.write(deltaLong);
+ stream.write(deltaLong >> 8);
+ stream.write(deltaLat);
+ stream.write(deltaLat >> 8);
+
+ if(labelOff != 0) {
+ stream.write(labelOff);
+ stream.write(labelOff >> 8);
+ stream.write(labelOff >> 16);
+ }
+
+ if(extraBytes != null)
+ stream.write(extraBytes);
+ }
+
+ public void setPOIRecord(POIRecord poirecord) {
+ this.poi = poirecord;
+ }
+
+ public POIRecord getPOIRecord() {
+ if (poi == null)
+ return new POIRecord();
+ return poi;
+ }
+
+ public Coord getLocation() {
+ int shift = getSubdiv().getShift();
+ Coord co = new Coord(getSubdiv().getLatitude() + (getDeltaLat() << shift),
+ getSubdiv().getLongitude() + (getDeltaLong() << shift) );
+ return co;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/PointOverview.java b/src/uk/me/parabola/imgfmt/app/trergn/PointOverview.java
new file mode 100644
index 0000000..536eea0
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/PointOverview.java
@@ -0,0 +1,29 @@
+/*
+ * 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: 01-Jan-2007
+ */
+package uk.me.parabola.imgfmt.app.trergn;
+
+/**
+ * Points have both a type and a subtype.
+ *
+ * @author Steve Ratcliffe
+ */
+public class PointOverview extends Overview {
+
+ public PointOverview(int type, int minResolution) {
+ super(POINT_KIND, type, minResolution);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/Polygon.java b/src/uk/me/parabola/imgfmt/app/trergn/Polygon.java
new file mode 100644
index 0000000..5e7b582
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/Polygon.java
@@ -0,0 +1,28 @@
+/**
+ * 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
+ * Date: 22-Dec-2006
+ */
+
+package uk.me.parabola.imgfmt.app.trergn;
+
+/**
+ * A Polygon on a garmin map is pretty much treated like a line.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Polygon extends Polyline {
+ public Polygon(Subdivision div) {
+ super(div);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/PolygonOverview.java b/src/uk/me/parabola/imgfmt/app/trergn/PolygonOverview.java
new file mode 100644
index 0000000..cde64da
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/PolygonOverview.java
@@ -0,0 +1,29 @@
+/*
+ * 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: 01-Jan-2007
+ */
+package uk.me.parabola.imgfmt.app.trergn;
+
+/**
+ * Polygons just have a type (no subtype).
+ *
+ * @author Steve Ratcliffe
+ */
+public class PolygonOverview extends Overview {
+
+ public PolygonOverview(int type, int minResolution) {
+ super(SHAPE_KIND, type, minResolution);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/Polyline.java b/src/uk/me/parabola/imgfmt/app/trergn/Polyline.java
new file mode 100644
index 0000000..76df145
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/Polyline.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2006 - 2012.
+ *
+ * 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.imgfmt.app.trergn;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.BitWriter;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.net.RoadDef;
+import uk.me.parabola.log.Logger;
+
+/**
+ * Represents a multi-segment line. Eg for a road. As with all map objects
+ * it can only exist as part of a subdivision.
+ *
+ * Writing these out is particularly tricky as deltas between points are packed
+ * into the smallest number of bits possible.
+ *
+ * I am not trying to make the smallest map, so it will not be totally optimum.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Polyline extends MapObject {
+ private static final Logger log = Logger.getLogger(Polyline.class);
+
+ // flags in the label offset
+ private static final int FLAG_NETINFO = 0x800000;
+ private static final int FLAG_EXTRABIT = 0x400000;
+
+ // flags in the type
+ private static final int FLAG_DIR = 0x40;
+ private static final int FLAG_2BYTE_LEN = 0x80;
+
+ // Reference to NET section, if any
+ private RoadDef roaddef;
+
+ // If a road gets subdivided into several segments, this
+ // says whether this line is the last segment. Need this
+ // for writing extra bits.
+ private boolean lastSegment = true;
+
+ // Set if it is a one-way street for example.
+ private boolean direction;
+
+ // The actual points that make up the line.
+ private final List<Coord> points = new ArrayList<Coord>();
+
+ public Polyline(Subdivision div) {
+ setSubdiv(div);
+ }
+
+ /**
+ * Format and write the contents of the object to the given
+ * file.
+ *
+ * @param file A reference to the file that should be written to.
+ */
+ public void write(ImgFileWriter file) {
+
+ // Prepare for writing by doing all the required calculations.
+
+ LinePreparer w;
+ try {
+ // Prepare the information that we need.
+ w = new LinePreparer(this);
+ }
+ catch (AssertionError ae) {
+ log.error("Problem writing line (" + getClass() + ") of type 0x" + Integer.toHexString(getType()) + " containing " + points.size() + " points and starting at " + points.get(0).toOSMURL());
+ log.error(" Subdivision shift is " + getSubdiv().getShift() +
+ " and its centre is at " + new Coord(getSubdiv().getLatitude(), getSubdiv().getLongitude()).toOSMURL());
+ log.error(" " + ae.getMessage());
+ if(roaddef != null)
+ log.error(" Way is " + roaddef);
+ return;
+ }
+
+ int minPointsRequired = (this instanceof Polygon)? 3 : 2;
+ BitWriter bw = w.makeBitStream(minPointsRequired);
+ if(bw == null) {
+ log.error("Level " + getSubdiv().getZoom().getLevel() + " " + ((this instanceof Polygon)? "polygon" : "polyline") + " has less than " + minPointsRequired + " points, discarding");
+ return;
+ }
+
+ // The type of feature, also contains a couple of flags hidden inside.
+ byte b1 = (byte) getType();
+ if (direction)
+ b1 |= FLAG_DIR; // Polylines only.
+
+ int blen = bw.getLength() - 1; // allow for the sizes
+ assert blen > 0 : "zero length bitstream";
+ assert blen < 0x10000 : "bitstream too long " + blen;
+ if (blen >= 0x100)
+ b1 |= FLAG_2BYTE_LEN;
+
+ file.put(b1);
+
+ // The label, contains a couple of flags within it.
+ int loff = getLabel().getOffset();
+ if (w.isExtraBit())
+ loff |= FLAG_EXTRABIT;
+
+ // If this is a road, then we need to save the offset of the label
+ // so that we can change it to the index in the net section
+ if (roaddef != null) {
+ roaddef.addLabel(getLabel());
+ roaddef.addOffsetTarget(file.position(),
+ FLAG_NETINFO | (loff & FLAG_EXTRABIT));
+ // also add ref label(s) if present
+ List<Label> refLabels = getRefLabels();
+ if(refLabels != null)
+ for(Label rl : refLabels)
+ roaddef.addLabel(rl);
+ }
+
+ file.put3(loff);
+
+ // The delta of the longitude from the subdivision centre point
+ // note that this has already been calculated.
+ file.putChar((char) getDeltaLong());
+ file.putChar((char) getDeltaLat());
+ if(log.isDebugEnabled())
+ log.debug("out center", getDeltaLat(), getDeltaLong());
+
+ if (blen < 0x100)
+ file.put((byte) (blen & 0xff));
+ else
+ file.putChar((char) (blen & 0xffff));
+
+ file.put(bw.getBytes(), 0, blen+1);
+ }
+
+ /*
+ * write the polyline to an OutputStream - only use for outputting
+ * lines with extended (3 byte) types.
+ *
+ */
+ public void write(OutputStream stream) throws IOException {
+ assert hasExtendedType();
+ int type = getType();
+ int labelOff = getLabel().getOffset();
+ byte[] extraBytes = getExtTypeExtraBytes();
+
+ LinePreparer w;
+ try {
+ // need to prepare line info before outputing lat/lon
+ w = new LinePreparer(this);
+ }
+ catch (AssertionError ae) {
+ log.error("Problem writing line (" + getClass() + ") of type 0x" + Integer.toHexString(getType()) + " containing " + points.size() + " points and starting at " + points.get(0).toOSMURL());
+ log.error(" Subdivision shift is " + getSubdiv().getShift() +
+ " and its centre is at " + new Coord(getSubdiv().getLatitude(), getSubdiv().getLongitude()).toOSMURL());
+ log.error(" " + ae.getMessage());
+ if(roaddef != null)
+ log.error(" Way is " + roaddef);
+ return;
+ }
+ int minPointsRequired = (this instanceof Polygon)? 3 : 2;
+ BitWriter bw = w.makeBitStream(minPointsRequired);
+ if(bw == null) {
+ log.error("Level " + getSubdiv().getZoom().getLevel() + " " + ((this instanceof Polygon)? "polygon" : "polyline") + " has less than " + minPointsRequired + " points, discarding");
+ return;
+ }
+ int blen = bw.getLength();
+ assert blen > 1 : "zero length bitstream";
+ assert blen < 0x10000 : "bitstream too long " + blen;
+
+ if(labelOff != 0)
+ type |= 0x20; // has label
+ if(extraBytes != null)
+ type |= 0x80; // has extra bytes
+ stream.write(type >> 8);
+ stream.write(type);
+
+ int deltaLong = getDeltaLong();
+ int deltaLat = getDeltaLat();
+ stream.write(deltaLong);
+ stream.write(deltaLong >> 8);
+ stream.write(deltaLat);
+ stream.write(deltaLat >> 8);
+
+ if (blen >= 0x7f) {
+ stream.write((blen << 2) | 2);
+ stream.write((blen << 2) >> 8);
+ }
+ else {
+ stream.write((blen << 1) | 1);
+ }
+
+ stream.write(bw.getBytes(), 0, blen);
+
+ if(labelOff != 0) {
+ stream.write(labelOff);
+ stream.write(labelOff >> 8);
+ stream.write(labelOff >> 16);
+ }
+
+ if(extraBytes != null)
+ stream.write(extraBytes);
+ }
+
+ public void addCoord(Coord co) {
+ points.add(co);
+ }
+
+ public void addCoords(List<Coord> coords) {
+ points.addAll(coords);
+ }
+
+ public List<Coord> getPoints() {
+ return points;
+ }
+
+ public void setDirection(boolean direction) {
+ this.direction = direction;
+ }
+
+ public boolean isRoad() {
+ return roaddef != null;
+ }
+
+ public boolean roadHasInternalNodes() {
+ return roaddef.hasInternalNodes();
+ }
+
+ public void setLastSegment(boolean last) {
+ lastSegment = last;
+ }
+
+ public boolean isLastSegment() {
+ return lastSegment;
+ }
+
+ public void setRoadDef(RoadDef rd) {
+ this.roaddef = rd;
+ }
+
+ public int getOffsetNet1() {
+ if (!isRoad())
+ return 0;
+ return roaddef.getOffsetNet1();
+ }
+
+ public boolean sharesNodeWith(Polyline other) {
+ for (Coord p1 : points) {
+ if (p1.getId() != 0) {
+ // point is a node, see if the other line contain the
+ // same node
+ for (Coord p2 : other.points)
+ if (p1.getId() == p2.getId())
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public int getLat() {
+ return getSubdiv().getLatitude() + (getDeltaLat() << getSubdiv().getShift());
+ }
+
+ public int getLong() {
+ return getSubdiv().getLongitude() + (getDeltaLong() << getSubdiv().getShift());
+ }
+
+ public int getNodeCount() {
+ int idx = 0;
+ int count = 0;
+ for (Coord co : points) {
+ if (idx++ > 0 && co.getId() > 0)
+ count++;
+ }
+ return count;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/PolylineOverview.java b/src/uk/me/parabola/imgfmt/app/trergn/PolylineOverview.java
new file mode 100644
index 0000000..dfb112d
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/PolylineOverview.java
@@ -0,0 +1,29 @@
+/*
+ * 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: 01-Jan-2007
+ */
+package uk.me.parabola.imgfmt.app.trergn;
+
+/**
+ * Polylines have a type and no subtype.
+ *
+ * @author Steve Ratcliffe
+ */
+public class PolylineOverview extends Overview {
+
+ public PolylineOverview(int type, int minResolution) {
+ super(LINE_KIND, type, minResolution);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/RGNFile.java b/src/uk/me/parabola/imgfmt/app/trergn/RGNFile.java
new file mode 100644
index 0000000..b5c56cb
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/RGNFile.java
@@ -0,0 +1,210 @@
+/*
+ * 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: 03-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app.trergn;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import uk.me.parabola.imgfmt.app.BufferedImgFileWriter;
+import uk.me.parabola.imgfmt.app.ImgFile;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.log.Logger;
+
+/**
+ * The region file. Holds actual details of points and lines etc.
+ *
+ *
+ *
+ * The data is rather complicated and is packed to save space. This class does
+ * not really handle that format however as it is written by the
+ * {@link MapObject}s themselves.
+ *
+ * Each subdivision takes space in this file. The I am expecting this to be the
+ * biggest file, although it seems that TRE may be in some circumstances.
+ *
+ * @author Steve Ratcliffe
+ */
+public class RGNFile extends ImgFile {
+ private static final Logger log = Logger.getLogger(RGNFile.class);
+
+ private static final int HEADER_LEN = RGNHeader.HEADER_LEN;
+
+ private final RGNHeader header = new RGNHeader();
+
+ private Subdivision currentDivision;
+ private int indPointPtrOff;
+ private int polylinePtrOff;
+ private int polygonPtrOff;
+ private ByteArrayOutputStream extTypePointsData;
+ private ByteArrayOutputStream extTypeLinesData;
+ private ByteArrayOutputStream extTypeAreasData;
+
+ public RGNFile(ImgChannel chan) {
+ setHeader(header);
+
+ setWriter(new BufferedImgFileWriter(chan));
+
+ // Position at the start of the writable area.
+ position(HEADER_LEN);
+ }
+
+ public void write() {
+ if (!isWritable())
+ throw new IllegalStateException("File not writable");
+
+ header.setDataSize(position() - HEADER_LEN);
+
+ if(extTypeAreasData != null) {
+ header.setExtTypeAreasInfo(position(), extTypeAreasData.size());
+ getWriter().put(extTypeAreasData.toByteArray());
+ }
+ if(extTypeLinesData != null) {
+ header.setExtTypeLinesInfo(position(), extTypeLinesData.size());
+ getWriter().put(extTypeLinesData.toByteArray());
+ }
+ if(extTypePointsData != null) {
+ header.setExtTypePointsInfo(position(), extTypePointsData.size());
+ getWriter().put(extTypePointsData.toByteArray());
+ }
+
+ getHeader().writeHeader(getWriter());
+ }
+
+ public void startDivision(Subdivision sd) {
+
+ sd.setStartRgnPointer(position() - HEADER_LEN);
+
+ // We need to reserve space for a pointer for each type of map
+ // element that is supported by this division. Note that these
+ // pointers are only 2bytes long. A pointer to the points is never
+ // needed as it will always be first if present.
+ if (sd.needsIndPointPtr()) {
+ indPointPtrOff = position();
+ position(position() + 2);
+ }
+
+ if (sd.needsPolylinePtr()) {
+ polylinePtrOff = position();
+ position(position() + 2);
+ }
+
+ if (sd.needsPolygonPtr()) {
+ polygonPtrOff = position();
+ position(position() + 2);
+ }
+
+ currentDivision = sd;
+ }
+
+ public void addMapObject(MapObject item) {
+ if(item.hasExtendedType()) {
+ try {
+ if(item instanceof Point) {
+ if(extTypePointsData == null)
+ extTypePointsData = new ByteArrayOutputStream();
+ item.write(extTypePointsData);
+ }
+ else if(item instanceof Polygon) {
+ if(extTypeAreasData == null)
+ extTypeAreasData = new ByteArrayOutputStream();
+ item.write(extTypeAreasData);
+ }
+ else if(item instanceof Polyline) {
+ if(extTypeLinesData == null)
+ extTypeLinesData = new ByteArrayOutputStream();
+ item.write(extTypeLinesData);
+ }
+ else
+ log.error("Can't add object of type " + item.getClass());
+ }
+ catch (IOException ioe) {
+ log.error("Error writing extended type object: " + ioe.getMessage());
+ }
+ }
+ else {
+ item.write(getWriter());
+ }
+ }
+
+ public void setIndPointPtr() {
+ if (currentDivision.needsIndPointPtr()) {
+ long currPos = position();
+ position(indPointPtrOff);
+ long off = currPos - currentDivision.getStartRgnPointer() - HEADER_LEN;
+ if (off > 0xffff)
+ throw new IllegalStateException("IndPoint offset too large: " + off);
+
+ getWriter().putChar((char) off);
+ position(currPos);
+ }
+ }
+
+ public void setPolylinePtr() {
+ if (currentDivision.needsPolylinePtr()) {
+ long currPos = position();
+ position(polylinePtrOff);
+ long off = currPos - currentDivision.getStartRgnPointer() - HEADER_LEN;
+ if (off > 0xffff)
+ throw new IllegalStateException("Polyline offset too large: " + off);
+
+ if (log.isDebugEnabled())
+ log.debug("setting polyline offset to", off);
+ getWriter().putChar((char) off);
+
+ position(currPos);
+ }
+ }
+
+ public void setPolygonPtr() {
+ if (currentDivision.needsPolygonPtr()) {
+ long currPos = position();
+ long off = currPos - currentDivision.getStartRgnPointer() - HEADER_LEN;
+ log.debug("currpos=", currPos, ", off=", off);
+ if (off > 0xffff)
+ throw new IllegalStateException("Polygon offset too large: " + off);
+
+ if (log.isDebugEnabled())
+ log.debug("setting polygon offset to ", off, " @", polygonPtrOff);
+ position(polygonPtrOff);
+ getWriter().putChar((char) off);
+ position(currPos);
+ }
+ }
+
+ public ImgFileWriter getWriter() {
+ return super.getWriter();
+ }
+
+ public int getExtTypePointsSize() {
+ return (extTypePointsData == null)? 0 : extTypePointsData.size();
+ }
+
+ public int getExtTypeLinesSize() {
+ return (extTypeLinesData == null)? 0 : extTypeLinesData.size();
+ }
+
+ public int getExtTypeAreasSize() {
+ return (extTypeAreasData == null)? 0 : extTypeAreasData.size();
+ }
+
+ public boolean haveExtendedTypes() {
+ return (extTypePointsData != null ||
+ extTypeLinesData != null ||
+ extTypeAreasData != null);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/RGNFileReader.java b/src/uk/me/parabola/imgfmt/app/trergn/RGNFileReader.java
new file mode 100644
index 0000000..b181e02
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/RGNFileReader.java
@@ -0,0 +1,629 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.trergn;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.BitReader;
+import uk.me.parabola.imgfmt.app.BufferedImgFileReader;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.CoordNode;
+import uk.me.parabola.imgfmt.app.ImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgReader;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.lbl.LBLFileReader;
+import uk.me.parabola.imgfmt.app.lbl.POIRecord;
+import uk.me.parabola.imgfmt.app.net.NETFileReader;
+import uk.me.parabola.imgfmt.app.net.RoadDef;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * The region file. Holds actual details of points and lines etc.
+ *
+ * This is the view of the file when it is being read. Use {@link RGNFile}
+ * for writing the file.
+ *
+ * The main focus of mkgmap is creating files, there are plenty of applications
+ * that read and display the data, reading is implemented only to the
+ * extent required to support creating the various auxiliary files etc.
+ *
+ * @author Steve Ratcliffe
+ */
+public class RGNFileReader extends ImgReader {
+ private static final Logger log = Logger.getLogger(RGNFileReader.class);
+
+ private final RGNHeader rgnHeader;
+ private LBLFileReader lblFile;
+ private NETFileReader netFile;
+
+ public RGNFileReader(ImgChannel chan) {
+ rgnHeader = new RGNHeader();
+ setHeader(rgnHeader);
+
+ setReader(new BufferedImgFileReader(chan));
+ rgnHeader.readHeader(getReader());
+ }
+
+ public void config(EnhancedProperties props) {
+ //config = props;
+ }
+
+ /**
+ * Get a list of all points for the given subdivision. This includes
+ * both the indexed points section and the points section.
+ *
+ * The numbering of the points carries through the sections.
+ * @param sd The subdivision that we are interested in.
+ * @return A list of all points for the subdiv.
+ */
+ public List<Point> pointsForSubdiv(Subdivision sd, boolean withExtType) {
+ ArrayList<Point> list = new ArrayList<Point>();
+ if (sd.hasIndPoints() || sd.hasPoints()){
+
+ RgnOffsets rgnOffsets = getOffsets(sd);
+
+ // Even though the indexed points are after the points, the numbering
+ // starts with 1 for the first indexed point and carries on into the
+ // points section.
+ fetchPointsCommon(sd, rgnOffsets.getIndPointStart(), rgnOffsets.getIndPointEnd(), list);
+ fetchPointsCommon(sd, rgnOffsets.getPointStart(), rgnOffsets.getPointEnd(), list);
+ }
+ if (withExtType && sd.getExtTypePointsSize() > 0)
+ fetchPointsCommonExtType(sd, rgnHeader.getExtTypePointsOffset() + sd.getExtTypePointsOffset(), sd.getExtTypePointsSize(), list);
+
+ return list;
+ }
+
+ /**
+ * The indexed points and the points sections are both read just the same.
+ */
+ private void fetchPointsCommon(Subdivision sd, long start, long end, List<Point> points) {
+ position(start);
+ ImgFileReader reader = getReader();
+
+ int number = points.size() + 1;
+ while (position() < end) {
+ Point p = new Point(sd);
+
+ byte t = reader.get();
+ int val = reader.getu3();
+ boolean hasSubtype = false;
+ if ((val & 0x800000) != 0)
+ hasSubtype = true;
+
+ boolean hasPoi = false;
+ if ((val & 0x400000) != 0)
+ hasPoi = true;
+
+ Label l;
+ int labelOffset = val & 0x3fffff;
+ if (hasPoi) {
+ POIRecord record = lblFile.fetchPoi(labelOffset);
+ if (record != null) {
+ l = record.getNameLabel();
+ p.setPOIRecord(record);
+ } else
+ l = lblFile.fetchLabel(0);
+ } else {
+ l = lblFile.fetchLabel(labelOffset);
+ }
+ p.setLabel(l);
+
+ p.setDeltaLong((short)reader.getChar());
+ p.setDeltaLat((short)reader.getChar());
+
+ if (hasSubtype) {
+ byte st = reader.get();
+ p.setType(((t & 0xff) << 8) | (st & 0xff));
+ //p.setHasSubtype(true);
+ } else {
+ p.setType(t & 0xff);
+ }
+
+ p.setNumber(number++);
+ points.add(p);
+ }
+ }
+
+ /**
+ * The indexed points and the points sections are both read just the same.
+ */
+ private void fetchPointsCommonExtType(Subdivision sd, long start, long end, List<Point> points) {
+ position(start);
+ ImgFileReader reader = getReader();
+
+ int number = points.size() + 1;
+ while (position() < end) {
+ Point p = new Point(sd);
+
+ int type = reader.get() << 8;
+ byte b = reader.get();
+ type |= 0x10000 + (b & 0x1f);
+ p.setType(type);
+ p.setDeltaLong((short)reader.getChar());
+ p.setDeltaLat((short)reader.getChar());
+ Label l;
+ if ((b & 0x20) != 0 ){
+ int labelOffset = reader.getu3();
+ boolean hasPoi = (labelOffset & 0x400000) != 0;
+ if (hasPoi) {
+ POIRecord record = lblFile.fetchPoi(labelOffset);
+ if (record != null) {
+ l = record.getNameLabel();
+ p.setPOIRecord(record);
+ } else
+ l = lblFile.fetchLabel(0);
+ } else {
+ l = lblFile.fetchLabel(labelOffset);
+ }
+ p.setLabel(l);
+ }
+
+ if ((b & 0x80) != 0){
+ extractExtraBytes(reader, p);
+ }
+ p.setNumber(number++);
+ points.add(p);
+ }
+ }
+
+ /**
+ * Get all the lines for a given subdivision.
+ * @param div The subdivision we want the line from.
+ * @return A list of lines.
+ */
+ public List<Polyline> linesForSubdiv(Subdivision div) {
+ ArrayList<Polyline> list = new ArrayList<Polyline>();
+
+ if (div.hasPolylines()){
+ RgnOffsets rgnOffsets = getOffsets(div);
+
+ int start = rgnOffsets.getLineStart();
+ int end = rgnOffsets.getLineEnd();
+
+ position(start);
+ while (position() < end) {
+ Polyline line = new Polyline(div);
+ readLineCommon(getReader(), div, line);
+ list.add(line);
+ }
+ }
+ if (div.getExtTypeLinesSize() > 0){
+ int start = rgnHeader.getExtTypeLinesOffset() + div.getExtTypeLinesOffset();
+ int end = start + div.getExtTypeLinesSize();
+ position(start);
+ while (position() < end) {
+ Polyline line = new Polyline(div);
+ readLineCommonExtType(getReader(), div, line);
+ list.add(line);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Get all the polygons for a given subdivision.
+ */
+ public List<Polygon> shapesForSubdiv(Subdivision div) {
+ ArrayList<Polygon> list = new ArrayList<Polygon>();
+ if (div.hasPolygons()){
+
+ RgnOffsets rgnOffsets = getOffsets(div);
+
+ int start = rgnOffsets.getPolygonStart();
+ int end = rgnOffsets.getPolygonEnd();
+
+ position(start);
+
+ while (position() < end) {
+ Polygon line = new Polygon(div);
+ readLineCommon(getReader(), div, line);
+ list.add(line);
+ }
+ }
+ if (div.getExtTypeAreasSize() > 0){
+ int start = rgnHeader.getExtTypeAreasOffset() + div.getExtTypeAreasOffset();
+ int end = start + div.getExtTypeAreasSize();
+ position(start);
+ while (position() < end) {
+ Polygon line = new Polygon(div);
+ readLineCommonExtType(getReader(), div, line);
+ list.add(line);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Since polygons are pretty much like polylines in the img format the
+ * reading code can be shared.
+ *
+ * @param reader The reader for the img file.
+ * @param div The subdivision.
+ * @param line The line or shape that is to be populated.
+ */
+ private void readLineCommon(ImgFileReader reader, Subdivision div, Polyline line) {
+ byte type = reader.get();
+ if (line instanceof Polygon)
+ line.setType(type & 0x7f);
+ else {
+ line.setType(type & 0x3f);
+ line.setDirection((type & 0x40) != 0);
+ }
+ int labelOffset = reader.getu3();
+ // Extra bit (for bit stream)
+ boolean extra = (labelOffset & 0x400000) != 0;
+ Label label;
+ if ((labelOffset & 0x800000) == 0) {
+ label = lblFile.fetchLabel(labelOffset & 0x7fffff);
+ } else {
+ int netoff = labelOffset & 0x3fffff;
+ labelOffset = netFile.getLabelOffset(netoff);
+ label = lblFile.fetchLabel(labelOffset);
+ RoadDef roadDef = new RoadDef(0, netoff, label.getText());
+ line.setRoadDef(roadDef);
+ }
+ line.setLabel(label);
+
+
+ line.setDeltaLong((short)reader.getChar());
+ line.setDeltaLat((short)reader.getChar());
+ int len;
+ if ((type & 0x80) == 0)
+ len = reader.get() & 0xff;
+ else
+ len = reader.getChar();
+
+ int base = reader.get();
+
+ byte[] bitstream = reader.get(len);
+ BitReader br = new BitReader(bitstream);
+ // This reads the bit stream and adds all the points found
+ readBitStream(br, div, line, extra, len, base);
+ }
+
+
+ /**
+ * Common code to read extended type lines or polygons for a given sub division.
+ * @param reader The reader for the img file.
+ * @param div The subdivision.
+ * @param line The line or shape that is to be populated.
+ */
+ private void readLineCommonExtType(ImgFileReader reader, Subdivision div, Polyline line) {
+ int type = reader.get();
+ type = (type & 0xff) << 8;
+ byte b1 = reader.get();
+ boolean hasExtraBytes = (b1 & 0x80) != 0;
+ boolean hasLabel = (b1 & 0x20) != 0;
+ type |= 0x10000 + (b1 & 0x1f);
+ line.setType(type);
+ line.setDeltaLong((short)reader.getChar());
+ line.setDeltaLat((short)reader.getChar());
+ b1 = reader.get();
+ int len;
+ // one byte or two byte length field?
+ if ((b1 & 0x01) != 0){
+ len = (b1 >> 1) & 0x7f;
+ assert len < 0x7f;
+ }
+ else {
+ byte b2 = reader.get();
+ len = (((b2 & 0xff) << 8) + (b1 & 0xff)) >> 2;
+ assert len >= 0x7f;
+ }
+ --len; // the encoded value includes the base field
+ assert len > 0;
+ int base = reader.get();
+ byte[] bitstream = reader.get(len);
+ BitReader br = new BitReader(bitstream);
+
+ // This reads the bit stream and adds all the points found,
+ readBitStream(br, div, line, false, len, base);
+
+ if (hasLabel){
+ int labelOffset = reader.getu3();
+ Label label;
+ if ((labelOffset & 0x800000) == 0) {
+ label = lblFile.fetchLabel(labelOffset & 0x7fffff);
+ } else {
+ int netoff = labelOffset & 0x3fffff;
+ labelOffset = netFile.getLabelOffset(netoff);
+ label = lblFile.fetchLabel(labelOffset);
+ RoadDef roadDef = new RoadDef(0, netoff, label.getText());
+ line.setRoadDef(roadDef);
+ }
+ line.setLabel(label);
+ }
+ if (hasExtraBytes){
+ extractExtraBytes(reader, line);
+ }
+ }
+
+ /**
+ * Extract extra bytes.
+ * @param reader
+ */
+ void extractExtraBytes(ImgFileReader reader, MapObject o){
+ long pos = reader.position();
+ StringBuilder sb = new StringBuilder();
+ ArrayList<Byte> bytes = new ArrayList<Byte>();
+ byte b1 = reader.get();
+ bytes.add(b1);
+ if ((b1 & 0xe0) != 0){
+ // varying length, search for 0x01 as this seems to be the terminator
+ do{
+ b1 = reader.get();
+ bytes.add(b1);
+ } while (b1 != 0x01);
+ } else if ((b1 & 0xa0) != 0){
+ bytes.add(reader.get());
+ bytes.add(reader.get());
+ }else if ((b1 & 0x80) != 0){
+ bytes.add(reader.get());
+ }
+ for (Byte b: bytes){
+ sb.append(String.format("%x", b));
+ }
+ ExtTypeAttributes eta = new ExtTypeAttributes(Collections.singletonMap("extra-bytes", sb.toString()), "data from img pos " + pos);
+ o.setExtTypeAttributes(eta);
+ }
+ /**
+ * Read the bit stream for a single line in the file.
+ * @param br The bit stream reader.
+ * @param div The subdivision that the line is in.
+ * @param line The line itself.
+ * @param extra True if there is an 'extra' bit in the stream. Used for nodes.
+ * @param len The length of the stream.
+ * @param base The base size of the deltas.
+ */
+ private void readBitStream(BitReader br, Subdivision div, Polyline line, boolean extra, int len, int base) {
+ int currLat = line.getLat();
+ int currLon = line.getLong();
+
+ log.debug(String.format("Start point %.5f,%.5f",
+ Utils.toDegrees(currLat),
+ Utils.toDegrees(currLon)));
+
+ if (extra)
+ line.addCoord(new CoordNode(currLat, currLon, 0/* XXX */, false));
+ else
+ line.addCoord(new Coord(currLat, currLon));
+
+ int xbase = 2;
+ int n = base & 0xf;
+ if (n <= 9)
+ xbase += n;
+ else
+ xbase += (2 * n) - 9;
+
+ n = (base >>> 4) & 0xf;
+ int ybase = 2;
+ if (n <= 9)
+ ybase += n;
+ else
+ ybase += (2 * n) - 9;
+
+ if (len == 0)
+ return;
+
+ boolean xneg = false;
+ boolean xsame = br.get1();
+ if (xsame) {
+ xneg = br.get1();
+ } else
+ xbase++;
+
+ boolean ysame = br.get1();
+ boolean yneg = false;
+ if (ysame) {
+ yneg = br.get1();
+ } else
+ ybase++;
+
+ if(line.hasExtendedType()) {
+ br.get1();
+ }
+
+ if (extra) {
+ boolean firstextra = br.get1();
+ log.debug("the first extra bit is", firstextra);
+ }
+
+ // All is now prepared, read the actual deltas and decode them into
+ // proper lat/long coords.
+ while (br.getBitPosition() <= 8* len - ((extra ? 1:0) + xbase + ybase)) {
+ br.getBitPosition();
+
+ int dx;
+ if (xsame) {
+ dx = br.get(xbase);
+ if (xneg)
+ dx = -dx;
+ } else {
+ dx = br.sget2(xbase);
+ }
+
+ int dy;
+ if (ysame) {
+ dy = br.get(ybase);
+ if (yneg)
+ dy = -dy;
+ } else {
+ dy = br.sget2(ybase);
+ }
+
+ boolean isnode = false;
+ if (extra)
+ isnode = br.get1();
+
+ currLat += dy << (24 - div.getResolution());
+ currLon += dx << (24 - div.getResolution());
+ Coord coord;
+ if (isnode)
+ coord = new CoordNode(currLat, currLon, 0/* XXX */, false);
+ else
+ coord = new Coord(currLat, currLon);
+
+ line.addCoord(coord);
+ }
+ if (line instanceof Polygon){
+ int numPoints = line.getPoints().size();
+ // make sure that polygon is closed
+ if (line.getPoints().get(0).equals(line.getPoints().get(numPoints-1)) == false)
+ line.addCoord(line.getPoints().get(0));
+ }
+ }
+
+ /**
+ * Get the offsets to the points, lines etc in RGN for the given subdiv.
+ * @param sd The subdivision is needed to work out the starting points.
+ * @return An Offsets class that allows you to obtain the offsets.
+ */
+ private RgnOffsets getOffsets(Subdivision sd) {
+ int off = sd.getStartRgnPointer();
+ position(rgnHeader.getDataOffset() + off);
+
+ return new RgnOffsets(sd);
+ }
+
+ public void setLblFile(LBLFileReader lblFile) {
+ this.lblFile = lblFile;
+ }
+
+ public void setNetFile(NETFileReader netFile) {
+ this.netFile = netFile;
+ }
+
+ /**
+ * Class to hold the start and end points of point, lines etc within
+ * the area for a given subdivision in the RGN data.
+ */
+ private class RgnOffsets {
+ private final int pointOffset;
+ private int pointEnd;
+
+ private int indPointOffset;
+ private int indPointEnd;
+
+ private int lineOffset;
+ private int lineEnd;
+
+ private int polygonOffset;
+ private int polygonEnd;
+
+ private final int start;
+ private int headerLen;
+
+ /**
+ * Calculate the offsets for the given subdivision.
+ * After this is called the position will be set after any pointers that
+ * exist at the beginning of the area.
+ *
+ * @param sd The subdivision.
+ */
+ private RgnOffsets(Subdivision sd) {
+ ImgFileReader reader = getReader();
+
+ start = (int) position();
+
+ pointOffset = 0;
+
+ if (sd.needsIndPointPtr()) {
+ indPointOffset = reader.getChar();
+ headerLen += 2;
+ }
+
+ if (sd.needsPolylinePtr()) {
+ lineOffset = reader.getChar();
+ headerLen += 2;
+ }
+
+ if (sd.needsPolygonPtr()) {
+ polygonOffset = reader.getChar();
+ headerLen += 2;
+ }
+
+
+ if (sd.hasPoints()) {
+ if (sd.hasIndPoints())
+ pointEnd = indPointOffset;
+ else if (sd.hasPolylines())
+ pointEnd = lineOffset;
+ else if (sd.hasPolygons())
+ pointEnd = polygonOffset;
+ else
+ pointEnd = sd.getEndRgnPointer() - sd.getStartRgnPointer();
+ }
+ if (sd.hasIndPoints()) {
+ if (sd.hasPolylines())
+ indPointEnd = lineOffset;
+ else if (sd.hasPolygons())
+ indPointEnd = polygonOffset;
+ else
+ indPointEnd = sd.getEndRgnPointer() - sd.getStartRgnPointer();
+ }
+ if (sd.hasPolylines()) {
+ if (sd.hasPolygons())
+ lineEnd = polygonOffset;
+ else
+ lineEnd = sd.getEndRgnPointer() - sd.getStartRgnPointer();
+ }
+ if (sd.hasPolygons()) {
+ polygonEnd = sd.getEndRgnPointer() - sd.getStartRgnPointer();
+ }
+ }
+
+ public String toString() {
+ return String.format("rgn div offsets: %x-%x/%x-%x/%x-%x/%x-%x",
+ pointOffset, pointEnd, indPointOffset, indPointEnd,
+ lineOffset, lineEnd, polygonOffset, polygonEnd);
+ }
+
+ public long getPointStart() {
+ return pointOffset == 0 ? start + headerLen : start + pointOffset;
+ }
+
+ public long getPointEnd() {
+ return start + pointEnd;
+ }
+
+ public long getIndPointStart() {
+ return indPointOffset == 0 ? start + headerLen : start + indPointOffset;
+ }
+
+ public long getIndPointEnd() {
+ return start + indPointEnd;
+ }
+
+ public int getLineStart() {
+ return lineOffset == 0? start + headerLen: start + lineOffset;
+ }
+
+ public int getLineEnd() {
+ return start + lineEnd;
+ }
+
+ public int getPolygonStart() {
+ return polygonOffset == 0? start + headerLen: start + polygonOffset;
+ }
+
+ public int getPolygonEnd() {
+ return start + polygonEnd;
+ }
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/RGNHeader.java b/src/uk/me/parabola/imgfmt/app/trergn/RGNHeader.java
new file mode 100644
index 0000000..bc6c32b
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/RGNHeader.java
@@ -0,0 +1,168 @@
+/*
+ * 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: Dec 14, 2007
+ */
+package uk.me.parabola.imgfmt.app.trergn;
+
+import uk.me.parabola.imgfmt.ReadFailedException;
+import uk.me.parabola.imgfmt.app.CommonHeader;
+import uk.me.parabola.imgfmt.app.ImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Section;
+
+/**
+ * The header for the RGN file. This is very simple, just a location and size.
+ *
+ * @author Steve Ratcliffe
+ */
+public class RGNHeader extends CommonHeader {
+ //private static final int DEF_LEN = 29;
+ private static final int DEF_LEN = 125;
+ public static final int HEADER_LEN = DEF_LEN;
+
+ private final Section data = new Section();
+
+ private int extTypeAreasOffset;
+ private int extTypeAreasSize;
+ private int extTypeLinesOffset;
+ private int extTypeLinesSize;
+ private int extTypePointsOffset;
+ private int extTypePointsSize;
+
+ public RGNHeader() {
+ super(HEADER_LEN, "GARMIN RGN");
+ data.setPosition(HEADER_LEN);
+ }
+
+ /**
+ * Read the rest of the header. Specific to the given file. It is guaranteed
+ * that the file position will be set to the correct place before this is
+ * called.
+ *
+ * @param reader The header is read from here.
+ */
+ protected void readFileHeader(ImgFileReader reader) throws ReadFailedException {
+ data.readSectionInfo(reader, false);
+
+ if (getHeaderLength() > 29){
+ extTypeAreasOffset = reader.getInt();
+ extTypeAreasSize = reader.getInt();
+ reader.getInt();
+ reader.getInt();
+ reader.getInt();
+ reader.getInt();
+ reader.getInt();
+ extTypeLinesOffset = reader.getInt();
+ extTypeLinesSize = reader.getInt();
+ reader.getInt();
+ reader.getInt();
+ reader.getInt();
+ reader.getInt();
+ reader.getInt();
+ extTypePointsOffset = reader.getInt();
+ extTypePointsSize = reader.getInt();
+ reader.getInt();
+ reader.getInt();
+ reader.getInt();
+ reader.getInt();
+ reader.getInt();
+ }
+ }
+
+ /**
+ * Write the rest of the header. It is guaranteed that the writer will be set
+ * to the correct position before calling.
+ *
+ * @param writer The header is written here.
+ */
+ protected void writeFileHeader(ImgFileWriter writer) {
+ data.writeSectionInfo(writer, false);
+
+ if (getHeaderLength() > 29) {
+ writer.putInt(extTypeAreasOffset);
+ writer.putInt(extTypeAreasSize);
+ writer.putInt(0);
+ writer.putInt(0);
+ writer.putInt(0);
+ writer.putInt(0);
+ writer.putInt(0);
+
+ writer.putInt(extTypeLinesOffset);
+ writer.putInt(extTypeLinesSize);
+ writer.putInt(0);
+ writer.putInt(0);
+ writer.putInt(0);
+ writer.putInt(0);
+ writer.putInt(0);
+
+ writer.putInt(extTypePointsOffset);
+ writer.putInt(extTypePointsSize);
+ writer.putInt(0);
+ writer.putInt(0);
+ writer.putInt(0);
+ writer.putInt(0);
+ writer.putInt(0);
+ writer.putInt(0);
+ writer.putInt(0);
+ writer.putInt(0);
+ }
+ }
+
+ public int getDataOffset() {
+ return data.getPosition();
+ }
+
+ public void setDataSize(int dataSize) {
+ data.setSize(dataSize);
+ }
+
+ public void setExtTypeAreasInfo(int offset, int size) {
+ extTypeAreasOffset = offset;
+ extTypeAreasSize = size;
+ }
+
+ public void setExtTypeLinesInfo(int offset, int size) {
+ extTypeLinesOffset = offset;
+ extTypeLinesSize = size;
+ }
+
+ public void setExtTypePointsInfo(int offset, int size) {
+ extTypePointsOffset = offset;
+ extTypePointsSize = size;
+ }
+ public int getExtTypeAreasOffset() {
+ return extTypeAreasOffset;
+ }
+
+ public int getExtTypeAreasSize() {
+ return extTypeAreasSize;
+ }
+
+ public int getExtTypeLinesOffset() {
+ return extTypeLinesOffset;
+ }
+
+ public int getExtTypeLinesSize() {
+ return extTypeLinesSize;
+ }
+
+ public int getExtTypePointsOffset() {
+ return extTypePointsOffset;
+ }
+
+ public int getExtTypePointsSize() {
+ return extTypePointsSize;
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/SubdivData.java b/src/uk/me/parabola/imgfmt/app/trergn/SubdivData.java
new file mode 100644
index 0000000..2a4f09b
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/SubdivData.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.trergn;
+
+/**
+ * Used to initialise a subdivision when we are reading it from a file,
+ * rather than creating it out of thin air.
+ */
+public class SubdivData {
+ private final int flags;
+ private final int lat;
+ private final int lon;
+ private final int width;
+ private final int height;
+ private final int rgnPointer;
+ private final int endRgnOffset;
+
+ public SubdivData(int flags, int lat, int lon, int width, int height, int rgnPointer, int endRgnOffset) {
+ this.flags = flags;
+ this.lat = lat;
+ this.lon = lon;
+ this.width = width;
+ this.height = height;
+ this.rgnPointer = rgnPointer;
+ this.endRgnOffset = endRgnOffset;
+ }
+
+ public int getFlags() {
+ return flags;
+ }
+
+ public int getLat() {
+ return lat;
+ }
+
+ public int getLon() {
+ return lon;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public int getRgnPointer() {
+ return rgnPointer;
+ }
+
+ public int getEndRgnOffset() {
+ return endRgnOffset;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java b/src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java
new file mode 100644
index 0000000..7443469
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java
@@ -0,0 +1,640 @@
+/*
+ * 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: 07-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app.trergn;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.ImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.lbl.LBLFile;
+import uk.me.parabola.log.Logger;
+
+/**
+ * The map is divided into areas, depending on the zoom level. These are
+ * known as subdivisions.
+ *
+ * A subdivision 'belongs' to a zoom level and cannot be interpreted correctly
+ * without knowing the <i>bitsPerCoord</i> of the associated zoom level.
+ *
+ * Subdivisions also form a tree as subdivisions are further divided at
+ * lower levels. The subdivisions need to know their child divisions
+ * because this information is represented in the map.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Subdivision {
+ private static final Logger log = Logger.getLogger(Subdivision.class);
+
+ private static final int MAP_POINT = 0;
+ private static final int MAP_INDEXED_POINT = 1;
+ private static final int MAP_LINE = 2;
+ private static final int MAP_SHAPE = 3;
+
+ private final LBLFile lblFile;
+ private final RGNFile rgnFile;
+
+ // The start pointer is set for read and write. The end pointer is only
+ // set for subdivisions that are read from a file.
+ private int startRgnPointer;
+ private int endRgnPointer;
+
+ private int lastMapElement;
+
+ // The zoom level contains the number of bits per coordinate which is
+ // critical for scaling quantities by.
+ private final Zoom zoomLevel;
+
+ private boolean hasPoints;
+ private boolean hasIndPoints;
+ private boolean hasPolylines;
+ private boolean hasPolygons;
+
+ private int numPolylines;
+
+ // The location of the central point, not scaled AFAIK
+ private final int longitude;
+ private final int latitude;
+
+ // The width and the height in map units scaled by the bits-per-coordinate
+ // that applies at the map level.
+ private final int width;
+ private final int height;
+
+ private int number;
+
+ // Set if this is the last one.
+ private boolean last;
+
+ private final List<Subdivision> divisions = new ArrayList<Subdivision>();
+
+ private int extTypeAreasOffset;
+ private int extTypeLinesOffset;
+ private int extTypePointsOffset;
+ private int extTypeAreasSize;
+ private int extTypeLinesSize;
+ private int extTypePointsSize;
+
+ /**
+ * Subdivisions can not be created directly, use either the
+ * {@link #topLevelSubdivision} or {@link #createSubdivision} factory
+ * methods.
+ *
+ * @param ifiles The internal files.
+ * @param area The area this subdivision should cover.
+ * @param z The zoom level.
+ */
+ private Subdivision(InternalFiles ifiles, Area area, Zoom z) {
+ this.lblFile = ifiles.getLblFile();
+ this.rgnFile = ifiles.getRgnFile();
+
+ this.zoomLevel = z;
+
+ int shift = getShift();
+ int mask = getMask();
+
+ // Calculate the center, move it right and up so that it lies on a point
+ // which is divisible by 2 ^shift
+ this.latitude = Utils.roundUp((area.getMinLat() + area.getMaxLat())/2, shift);
+ this.longitude = Utils.roundUp((area.getMinLong() + area.getMaxLong())/2, shift);
+ int w = 2 * (longitude - area.getMinLong());
+ int h = 2 * (latitude - area.getMinLat());
+
+ // encode the values for the img format
+ w = ((w + 1)/2 + mask) >> shift;
+ h = ((h + 1)/2 + mask) >> shift;
+
+ if (w > 0x7fff) {
+ log.warn("Subdivision width is " + w + " at " + new Coord(latitude, longitude));
+ w = 0x7fff;
+ }
+
+ if (h > 0xffff) {
+ log.warn("Subdivision height is " + h + " at " + new Coord(latitude, longitude));
+ h = 0xffff;
+ }
+
+ this.width = w;
+ this.height = h;
+ }
+
+ private Subdivision(Zoom z, SubdivData data) {
+ lblFile = null;
+ rgnFile = null;
+ zoomLevel = z;
+ latitude = data.getLat();
+ longitude = data.getLon();
+ this.width = data.getWidth();
+ this.height = data.getHeight();
+
+ startRgnPointer = data.getRgnPointer();
+ endRgnPointer = data.getEndRgnOffset();
+
+ int elem = data.getFlags();
+ if ((elem & 0x10) != 0)
+ setHasPoints(true);
+ if ((elem & 0x20) != 0)
+ setHasIndPoints(true);
+ if ((elem & 0x40) != 0)
+ setHasPolylines(true);
+ if ((elem & 0x80) != 0)
+ setHasPolygons(true);
+ }
+
+ /**
+ * Create a subdivision at a given zoom level.
+ *
+ * @param ifiles The RGN and LBL ifiles.
+ * @param area The (unshifted) area that the subdivision covers.
+ * @param zoom The zoom level that this division occupies.
+ *
+ * @return A new subdivision.
+ */
+ public Subdivision createSubdivision(InternalFiles ifiles,
+ Area area, Zoom zoom)
+ {
+ Subdivision div = new Subdivision(ifiles, area, zoom);
+ zoom.addSubdivision(div);
+ addSubdivision(div);
+ return div;
+ }
+
+ /**
+ * This should be called only once per map to create the top level
+ * subdivision. The top level subdivision covers the whole map and it
+ * must be empty.
+ *
+ * @param ifiles The LBL and RGN ifiles.
+ * @param area The area bounded by the map.
+ * @param zoom The zoom level which must be the highest (least detailed)
+ * zoom in the map.
+ *
+ * @return The new subdivision.
+ */
+ public static Subdivision topLevelSubdivision(InternalFiles ifiles,
+ Area area, Zoom zoom)
+ {
+ Subdivision div = new Subdivision(ifiles, area, zoom);
+ zoom.addSubdivision(div);
+ return div;
+ }
+
+ /**
+ * Create a subdivision that only contains the number. This is only
+ * used when reading cities and similar such usages that do not really
+ * require the full subdivision to be present.
+ * @param number The subdivision number.
+ * @return An empty subdivision. Any operation other than getting the
+ * subdiv number is likely to fail.
+ */
+ public static Subdivision createEmptySubdivision(int number) {
+ Subdivision sd = new Subdivision(null, new SubdivData(0,0,0,0,0,0,0));
+ sd.setNumber(number);
+ return sd;
+ }
+
+ public static Subdivision readSubdivision(Zoom zoom, SubdivData subdivData) {
+ return new Subdivision(zoom, subdivData);
+ }
+
+ public Zoom getZoom() {
+ return zoomLevel;
+ }
+
+ /**
+ * Get the shift value, that is the number of bits to left shift by for
+ * values that need to be saved shifted in the file. Related to the
+ * resolution.
+ *
+ * @return The shift value. It is 24 minus the number of bits per coord.
+ * @see #getResolution()
+ */
+ public final int getShift() {
+ return 24 - zoomLevel.getResolution();
+ }
+
+ /**
+ * Get the shift mask. The bits that will be lost due to the resolution
+ * shift level.
+ *
+ * @return A bit mask with the lower <i>shift</i> bits set.
+ */
+ protected int getMask() {
+ return (1 << getShift()) - 1;
+ }
+
+ /**
+ * Get the resolution of this division. Resolution goes from 1 to 24
+ * and the higher the number the more detail there is.
+ *
+ * @return The resolution.
+ */
+ public final int getResolution() {
+ return zoomLevel.getResolution();
+ }
+
+ /**
+ * Format this record to the file.
+ *
+ * @param file The file to write to.
+ */
+ public void write(ImgFileWriter file) {
+ log.debug("write subdiv", latitude, longitude);
+ file.put3(startRgnPointer);
+ file.put(getType());
+ file.put3(longitude);
+ file.put3(latitude);
+
+ assert width <= 0x7fff;
+ assert height <= 0xffff;
+ file.putChar((char) (width | ((last) ? 0x8000 : 0)));
+ file.putChar((char) height);
+
+ if (!divisions.isEmpty()) {
+ file.putChar((char) getNextLevel());
+ }
+ }
+
+ public Point createPoint(String name) {
+ Point p = new Point(this);
+ Label label = lblFile.newLabel(name);
+
+ p.setLabel(label);
+ return p;
+ }
+
+ public Polyline createLine(String[] labels) {
+ // don't be tempted to "trim()" the name as it zaps the highway shields
+ Label label = lblFile.newLabel(labels[0]);
+ String nameSansGC = Label.stripGarminCodes(labels[0]);
+ Polyline pl = new Polyline(this);
+
+ pl.setLabel(label);
+
+ if(labels[1] != null) {
+ // ref may contain multiple ids separated by ";"
+ int maxSetIdx = 3;
+ if (labels[3] == null) {
+ if (labels[2] == null) {
+ maxSetIdx = 1;
+ } else {
+ maxSetIdx = 2;
+ }
+ } else {
+ maxSetIdx = 3;
+ }
+ String[] refs = Arrays.copyOfRange(labels, 1, maxSetIdx+1);
+ if(refs.length == 1) {
+ // don't bother to add a single ref that looks the
+ // same as the name (sans shield) because it doesn't
+ // change the routing directions
+ String tr = refs[0].trim();
+ String trSansGC = Label.stripGarminCodes(tr);
+ if(trSansGC.length() > 0 &&
+ !trSansGC.equalsIgnoreCase(nameSansGC)) {
+ pl.addRefLabel(lblFile.newLabel(tr));
+ }
+ }
+ else if (refs.length > 1){
+ // multiple refs, always add the first so that it will
+ // be used in routing instructions when the name has a
+ // shield prefix
+ pl.addRefLabel(lblFile.newLabel(refs[0].trim()));
+
+ // only add the remaining refs if they differ from the
+ // name (sans shield)
+ for(int i = 1; i < refs.length; ++i) {
+ String tr = refs[i].trim();
+ String trSansGC = Label.stripGarminCodes(tr);
+ if(trSansGC.length() > 0 &&
+ !trSansGC.equalsIgnoreCase(nameSansGC)) {
+ pl.addRefLabel(lblFile.newLabel(tr));
+ }
+ }
+ }
+ }
+ return pl;
+ }
+
+ public void setPolylineNumber(Polyline pl) {
+ pl.setNumber(++numPolylines);
+ }
+
+ public Polygon createPolygon(String name) {
+ Label label = lblFile.newLabel(name);
+ Polygon pg = new Polygon(this);
+
+ pg.setLabel(label);
+ return pg;
+ }
+
+ public void setNumber(int n) {
+ number = n;
+ }
+
+ public void setLast(boolean last) {
+ this.last = last;
+ }
+
+ public void setStartRgnPointer(int startRgnPointer) {
+ this.startRgnPointer = startRgnPointer;
+ }
+
+ public int getStartRgnPointer() {
+ return startRgnPointer;
+ }
+
+ public int getEndRgnPointer() {
+ return endRgnPointer;
+ }
+
+ public int getLongitude() {
+ return longitude;
+ }
+
+ public int getLatitude() {
+ return latitude;
+ }
+
+ public void setHasPoints(boolean hasPoints) {
+ this.hasPoints = hasPoints;
+ }
+
+ public void setHasIndPoints(boolean hasIndPoints) {
+ this.hasIndPoints = hasIndPoints;
+ }
+
+ public void setHasPolylines(boolean hasPolylines) {
+ this.hasPolylines = hasPolylines;
+ }
+
+ public void setHasPolygons(boolean hasPolygons) {
+ this.hasPolygons = hasPolygons;
+ }
+
+ public boolean hasPoints() {
+ return hasPoints;
+ }
+
+ public boolean hasIndPoints() {
+ return hasIndPoints;
+ }
+
+ public boolean hasPolylines() {
+ return hasPolylines;
+ }
+
+ public boolean hasPolygons() {
+ return hasPolygons;
+ }
+
+ /**
+ * Needed if it exists and is not first, ie there is a points
+ * section.
+ * @return true if pointer needed
+ */
+ public boolean needsIndPointPtr() {
+ return hasIndPoints && hasPoints;
+ }
+
+ /**
+ * Needed if it exists and is not first, ie there is a points or
+ * indexed points section.
+ * @return true if pointer needed.
+ */
+ public boolean needsPolylinePtr() {
+ return hasPolylines && (hasPoints || hasIndPoints);
+ }
+
+ /**
+ * As this is last in the list it is needed if it exists and there
+ * is another section.
+ * @return true if pointer needed.
+ */
+ public boolean needsPolygonPtr() {
+ return hasPolygons && (hasPoints || hasIndPoints || hasPolylines);
+ }
+
+ public String toString() {
+ return "Sub" + zoomLevel + '(' + new Coord(latitude, longitude).toOSMURL() + ')';
+ }
+ /**
+ * Get a type that shows if this area has lines, points etc.
+ *
+ * @return A code showing what kinds of element are in this subdivision.
+ */
+ private byte getType() {
+ byte b = 0;
+ if (hasPoints)
+ b |= 0x10;
+ if (hasIndPoints)
+ b |= 0x20;
+ if (hasPolylines)
+ b |= 0x40;
+ if (hasPolygons)
+ b |= 0x80;
+
+ return b;
+ }
+ /**
+ * Get the number of the first subdivision at the next level.
+ * @return The first subdivision at the next level.
+ */
+ private int getNextLevel() {
+ return divisions.get(0).getNumber();
+ }
+
+ public boolean hasNextLevel() {
+ return !divisions.isEmpty();
+ }
+
+ public int getExtTypeAreasOffset() {
+ return extTypeAreasOffset;
+ }
+
+ public int getExtTypeLinesOffset() {
+ return extTypeLinesOffset;
+ }
+
+ public int getExtTypePointsOffset() {
+ return extTypePointsOffset;
+ }
+
+ public int getExtTypeAreasSize() {
+ return extTypeAreasSize;
+ }
+
+ public int getExtTypeLinesSize() {
+ return extTypeLinesSize;
+ }
+
+ public int getExtTypePointsSize() {
+ return extTypePointsSize;
+ }
+
+ public void startDivision() {
+ rgnFile.startDivision(this);
+ extTypeAreasOffset = rgnFile.getExtTypeAreasSize();
+ extTypeLinesOffset = rgnFile.getExtTypeLinesSize();
+ extTypePointsOffset = rgnFile.getExtTypePointsSize();
+ }
+
+ public void endDivision() {
+ extTypeAreasSize = rgnFile.getExtTypeAreasSize() - extTypeAreasOffset;
+ extTypeLinesSize = rgnFile.getExtTypeLinesSize() - extTypeLinesOffset;
+ extTypePointsSize = rgnFile.getExtTypePointsSize() - extTypePointsOffset;
+ }
+
+ public void writeExtTypeOffsetsRecord(ImgFileWriter file) {
+ file.putInt(extTypeAreasOffset);
+ file.putInt(extTypeLinesOffset);
+ file.putInt(extTypePointsOffset);
+ int kinds = 0;
+ if(extTypeAreasSize != 0)
+ ++kinds;
+ if(extTypeLinesSize != 0)
+ ++kinds;
+ if(extTypePointsSize != 0)
+ ++kinds;
+ file.put((byte)kinds);
+ }
+
+ public void writeLastExtTypeOffsetsRecord(ImgFileWriter file) {
+ file.putInt(rgnFile.getExtTypeAreasSize());
+ file.putInt(rgnFile.getExtTypeLinesSize());
+ file.putInt(rgnFile.getExtTypePointsSize());
+ file.put((byte)0);
+ }
+
+ /**
+ * Read offsets for extended type data and set sizes for predecessor sub-div.
+ * Corresponds to {@link #writeExtTypeOffsetsRecord(ImgFileWriter)}
+ * @param reader the reader
+ * @param sdPrev the pred. sub-div or null
+ */
+ public void readExtTypeOffsetsRecord(ImgFileReader reader,
+ Subdivision sdPrev) {
+ extTypeAreasOffset = reader.getInt();
+ extTypeLinesOffset = reader.getInt();
+ extTypePointsOffset = reader.getInt();
+ reader.get();
+ if (sdPrev != null){
+ sdPrev.extTypeAreasSize = extTypeAreasOffset - sdPrev.extTypeAreasOffset;
+ sdPrev.extTypeLinesSize = extTypeLinesOffset - sdPrev.extTypeLinesOffset;
+ sdPrev.extTypePointsSize = extTypePointsOffset - sdPrev.extTypePointsOffset;
+ }
+ }
+ /**
+ * Set the sizes for the extended type data. See {@link #writeLastExtTypeOffsetsRecord(ImgFileWriter)}
+ * @param reader
+ */
+ public void readLastExtTypeOffsetsRecord(ImgFileReader reader) {
+ extTypeAreasSize = reader.getInt() - extTypeAreasOffset;
+ extTypeLinesSize = reader.getInt() - extTypeLinesOffset;
+ extTypePointsSize = reader.getInt() - extTypePointsOffset;
+ byte test = reader.get();
+ assert test == 0;
+ }
+
+ /**
+ * Add this subdivision as our child at the next level. Each subdivision
+ * can be further divided into smaller divisions. They form a tree like
+ * arrangement.
+ *
+ * @param sd One of our subdivisions.
+ */
+ private void addSubdivision(Subdivision sd) {
+ divisions.add(sd);
+ }
+
+ public int getNumber() {
+ return number;
+ }
+
+ /**
+ * We are starting to draw the points. These must be done first.
+ */
+ public void startPoints() {
+ if (lastMapElement > MAP_POINT)
+ throw new IllegalStateException("Points must be drawn first");
+
+ lastMapElement = MAP_POINT;
+ }
+
+ /**
+ * We are starting to draw the lines. These must be done before
+ * polygons.
+ */
+ public void startIndPoints() {
+ if (lastMapElement > MAP_INDEXED_POINT)
+ throw new IllegalStateException("Indexed points must be done before lines and polygons");
+
+ lastMapElement = MAP_INDEXED_POINT;
+
+ rgnFile.setIndPointPtr();
+ }
+
+ /**
+ * We are starting to draw the lines. These must be done before
+ * polygons.
+ */
+ public void startLines() {
+ if (lastMapElement > MAP_LINE)
+ throw new IllegalStateException("Lines must be done before polygons");
+
+ lastMapElement = MAP_LINE;
+
+ rgnFile.setPolylinePtr();
+ }
+
+ /**
+ * We are starting to draw the shapes. This is done last.
+ */
+ public void startShapes() {
+
+ lastMapElement = MAP_SHAPE;
+
+ rgnFile.setPolygonPtr();
+ }
+
+ /**
+ * Convert an absolute Lat to a local, shifted value
+ */
+ public int roundLatToLocalShifted(int absval) {
+ int shift = getShift();
+ int val = absval - getLatitude();
+ val += ((1 << shift) / 2);
+ return (val >> shift);
+ }
+
+ /**
+ * Convert an absolute Lon to a local, shifted value
+ */
+ public int roundLonToLocalShifted(int absval) {
+ int shift = getShift();
+ int val = absval - getLongitude();
+ val += ((1 << shift) / 2);
+ return (val >> shift);
+ }
+
+
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/TREFile.java b/src/uk/me/parabola/imgfmt/app/trergn/TREFile.java
new file mode 100644
index 0000000..589f018
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/TREFile.java
@@ -0,0 +1,364 @@
+/*
+ * 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: 03-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app.trergn;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.BufferedImgFileWriter;
+import uk.me.parabola.imgfmt.app.ImgFile;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.util.Configurable;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * This is the file that contains the overview of the map. There
+ * can be different zoom levels and each level of zoom has an
+ * associated set of subdivided areas. Each of these areas then points
+ * into the RGN file.
+ *
+ * This is quite a complex file as there are quite a few miscellaneous pieces
+ * of information stored.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TREFile extends ImgFile implements Configurable {
+ private static final Logger log = Logger.getLogger(TREFile.class);
+
+ // Zoom levels for map
+ // private List<Zoom> mapLevels = new ArrayList<Zoom>();
+ private final Zoom[] mapLevels = new Zoom[16];
+
+ private final List<Label> copyrights = new ArrayList<Label>();
+
+ // Information about polylines. eg roads etc.
+ private final List<PolylineOverview> polylineOverviews = new ArrayList<PolylineOverview>();
+
+ private final List<PolygonOverview> polygonOverviews = new ArrayList<PolygonOverview>();
+
+ private final List<PointOverview> pointOverviews = new ArrayList<PointOverview>();
+
+ private int lastRgnPos;
+
+ private final TREHeader header = new TREHeader();
+
+
+ public TREFile(ImgChannel chan) {
+ setHeader(header);
+ setWriter(new BufferedImgFileWriter(chan));
+
+ // Position at the start of the writable area.
+ position(header.getHeaderLength());
+ }
+
+ public Zoom createZoom(int zoom, int bits) {
+ Zoom z = new Zoom(zoom, bits);
+ mapLevels[zoom] = z;
+ return z;
+ }
+
+ /**
+ * Add a string to the 'mapinfo' section. This is a section between the
+ * header and the start of the data. Nothing points to it directly.
+ *
+ * @param msg A string, usually used to describe the program that generated
+ * the file.
+ */
+ public void addInfo(String msg) {
+ byte[] val = Utils.toBytes(msg);
+ if (position() != header.getHeaderLength() + header.getMapInfoSize())
+ throw new IllegalStateException("All info must be added before anything else");
+
+ header.setMapInfoSize(header.getMapInfoSize() + (val.length+1));
+ getWriter().put(val);
+ getWriter().put((byte) 0);
+ }
+
+ public void addCopyright(Label cr) {
+ copyrights.add(cr);
+ }
+
+ public void addPointOverview(PointOverview ov) {
+ pointOverviews.add(ov);
+ }
+
+ public void addPolylineOverview(PolylineOverview ov) {
+ polylineOverviews.add(ov);
+ }
+
+ public void addPolygonOverview(PolygonOverview ov) {
+ polygonOverviews.add(ov);
+ }
+
+ public void config(EnhancedProperties props) {
+ header.config(props);
+ }
+
+ /**
+ * Write out the body of the TRE file. The act of writing the body sections
+ * out provides us with pointers that are needed for the header. Therefore
+ * the header needs to be written after the body (or obviously we could
+ * make two passes).
+ */
+ private void writeBody(boolean includeExtendedTypeData) {
+ writeMapLevels();
+
+ writeSubdivs();
+
+ writeCopyrights();
+
+ writeOverviews();
+
+ if(includeExtendedTypeData) {
+ writeExtTypeOffsetsRecords();
+ writeExtTypeOverviews();
+ }
+ }
+
+ /**
+ * Write out the subdivisions. This is quite complex as they have to be
+ * numbered and written out keeping their parent/child relationship
+ * intact.
+ */
+ private void writeSubdivs() {
+ header.setSubdivPos(position());
+ int subdivnum = 1; // numbers start at one
+
+ // First prepare to number them all
+ for (int i = 15; i >= 0; i--) {
+ Zoom z = mapLevels[i];
+ if (z == null)
+ continue;
+
+ Iterator<Subdivision> it = z.subdivIterator();
+ while (it.hasNext()) {
+ Subdivision sd = it.next();
+ log.debug("setting number to", subdivnum);
+ sd.setNumber(subdivnum++);
+ }
+ }
+
+ // Now we can write them all out.
+ for (int i = 15; i >= 0; i--) {
+ Zoom z = mapLevels[i];
+ if (z == null)
+ continue;
+
+ Iterator<Subdivision> it = z.subdivIterator();
+ while (it.hasNext()) {
+ Subdivision sd = it.next();
+
+ sd.write(getWriter());
+ if (sd.hasNextLevel())
+ header.setSubdivSize(header.getSubdivSize() + TREHeader.SUBDIV_REC_SIZE2);
+ else
+ header.setSubdivSize(header.getSubdivSize() + TREHeader.SUBDIV_REC_SIZE);
+ }
+ }
+ getWriter().putInt(lastRgnPos);
+ header.setSubdivSize(header.getSubdivSize() + 4);
+ }
+
+ private void writeExtTypeOffsetsRecords() {
+ header.setExtTypeOffsetsPos(position());
+ Subdivision sd = null;
+ for (int i = 15; i >= 0; i--) {
+ Zoom z = mapLevels[i];
+ if (z == null)
+ continue;
+
+ Iterator<Subdivision> it = z.subdivIterator();
+ while (it.hasNext()) {
+ sd = it.next();
+ sd.writeExtTypeOffsetsRecord(getWriter());
+ header.incExtTypeOffsetsSize();
+ }
+ }
+ if(sd != null) {
+ sd.writeLastExtTypeOffsetsRecord(getWriter());
+ header.incExtTypeOffsetsSize();
+ }
+ }
+
+ /**
+ * Write out the map levels. This is a mapping between the level number
+ * and the resolution.
+ */
+ private void writeMapLevels() {
+ // Write out the map levels (zoom)
+ header.setMapLevelPos(position());
+ for (int i = 15; i >= 0; i--) {
+ // They need to be written in reverse order I think
+ Zoom z = mapLevels[i];
+ if (z == null)
+ continue;
+ header.setMapLevelsSize(header.getMapLevelsSize() + TREHeader.MAP_LEVEL_REC_SIZE);
+ z.write(getWriter());
+ }
+ }
+
+ /**
+ * Write out the overview section. This is a mapping between the map feature
+ * type and the highest level (lowest detail) that it appears at. There
+ * are separate ones for points, lines and polygons.
+ */
+ private void writeOverviews() {
+ header.setPointPos(position());
+
+ // Point overview section
+ Collections.sort(pointOverviews);
+ for (Overview ov : pointOverviews) {
+ if(!ov.hasExtType()) {
+ ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
+ ov.write(getWriter());
+ header.incPointSize();
+ }
+ }
+
+ // Line overview section.
+ header.setPolylinePos(position());
+ Collections.sort(polylineOverviews);
+ for (Overview ov : polylineOverviews) {
+ if(!ov.hasExtType()) {
+ ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
+ ov.write(getWriter());
+ header.incPolylineSize();
+ }
+ }
+
+ // Polygon overview section
+ header.setPolygonPos(position());
+ Collections.sort(polygonOverviews);
+ for (Overview ov : polygonOverviews) {
+ if(!ov.hasExtType()) {
+ ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
+ ov.write(getWriter());
+ header.incPolygonSize();
+ }
+ }
+ }
+
+ private void writeExtTypeOverviews() {
+
+ header.setExtTypeOverviewsPos(position());
+
+ // assumes overviews are already sorted
+
+ for (Overview ov : polylineOverviews) {
+ if(ov.hasExtType()) {
+ ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
+ ov.write(getWriter());
+ header.incExtTypeOverviewsSize();
+ header.incNumExtTypeLineTypes();
+ }
+ }
+
+ for (Overview ov : polygonOverviews) {
+ if(ov.hasExtType()) {
+ ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
+ ov.write(getWriter());
+ header.incExtTypeOverviewsSize();
+ header.incNumExtTypeAreaTypes();
+ }
+ }
+
+ for (Overview ov : pointOverviews) {
+ if(ov.hasExtType()) {
+ ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
+ ov.write(getWriter());
+ header.incExtTypeOverviewsSize();
+ header.incNumExtTypePointTypes();
+ }
+ }
+ }
+
+ /**
+ * Convert a min resolution to a level. We return the lowest level (most
+ * detailed) that has a resolution less than or equal to the given resolution.
+ *
+ * @param minResolution The minimum resolution.
+ * @return The level corresponding to the resolution.
+ */
+ private int decodeLevel(int minResolution) {
+ Zoom top = null;
+ for (int i = 15; i >= 0; i--) {
+ Zoom z = mapLevels[i];
+ if (z == null)
+ continue;
+
+ if (top == null)
+ top = z;
+
+ if (z.getResolution() >= minResolution)
+ return z.getLevel();
+ }
+
+ // If not found, then allow it only at the top level
+ if (top != null)
+ return top.getLevel();
+ else
+ return 0; // Fail safe, shouldn't really happen
+ }
+
+ /**
+ * Write out the copyrights. This is just a list of pointers to strings
+ * in the label section basically.
+ */
+ private void writeCopyrights() {
+ // Write out the pointers to the labels that hold the copyright strings
+ header.setCopyrightPos(position());
+ ImgFileWriter writer = getWriter();
+ for (Label l : copyrights) {
+ header.incCopyrightSize();
+ writer.put3(l.getOffset());
+ }
+ }
+
+ public void setLastRgnPos(int lastRgnPos) {
+ TREFile.this.lastRgnPos = lastRgnPos;
+ }
+
+ public void write(boolean includeExtendedTypeData) {
+ // Do anything that is in structures and that needs to be dealt with.
+ writeBody(includeExtendedTypeData);
+ }
+
+ public void writePost() {
+ // Now refresh the header
+ position(0);
+ getHeader().writeHeader(getWriter());
+ }
+
+ public void setMapId(int mapid) {
+ header.setMapId(mapid);
+ }
+
+ public void setBounds(Area area) {
+ header.setBounds(area);
+ }
+
+ public void addPoiDisplayFlags(byte b) {
+ header.addPoiDisplayFlags(b);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/TREFileReader.java b/src/uk/me/parabola/imgfmt/app/trergn/TREFileReader.java
new file mode 100644
index 0000000..e849f64
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/TREFileReader.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.trergn;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.BufferedImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgReader;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.Section;
+import uk.me.parabola.imgfmt.app.lbl.LBLFileReader;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * This is the file that contains the overview of the map. There
+ * can be different zoom levels and each level of zoom has an
+ * associated set of subdivided areas. Each of these areas then points
+ * into the RGN file.
+ *
+ * The main focus of mkgmap is creating files, there are plenty of applications
+ * that read and display the data, reading is implemented only to the
+ * extent required to support creating the various auxiliary files etc.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TREFileReader extends ImgReader {
+ private Zoom[] mapLevels;
+ private Subdivision[][] levelDivs;
+
+ private static final Subdivision[] EMPTY_SUBDIVISIONS = new Subdivision[0];
+
+ private final TREHeader header = new TREHeader();
+
+
+ public TREFileReader(ImgChannel chan) {
+ setHeader(header);
+
+ setReader(new BufferedImgFileReader(chan));
+ header.readHeader(getReader());
+ readMapLevels();
+ readSubdivs();
+ readExtTypeOffsetsRecords();
+ }
+
+ public Area getBounds() {
+ return header.getBounds();
+ }
+
+ public Zoom[] getMapLevels() {
+ return mapLevels;
+ }
+
+ /**
+ * Return the subdivisions for the given level.
+ * @param level The level, 0 being the most detailed. There may not be
+ * a level zero in the map.
+ * @return The subdivisions for the level. Never returns null; a zero length
+ * array is returned if there is no such level.
+ */
+ public Subdivision[] subdivForLevel(int level) {
+ for (int i = 0; i < mapLevels.length; i++) {
+ if (mapLevels[i].getLevel() == level) {
+ return levelDivs[i];
+ }
+ }
+ return EMPTY_SUBDIVISIONS;
+ }
+
+ /**
+ * Read in the subdivisions. There are a set of subdivision for each level.
+ */
+ private void readSubdivs() {
+ ImgFileReader reader = getReader();
+
+ int start = header.getSubdivPos();
+ int end = start + header.getSubdivSize();
+ reader.position(start);
+
+ int subdivNum = 1;
+ int lastRgnOffset = reader.getu3();
+ for (int count = 0; count < levelDivs.length && reader.position() < end; count++) {
+
+ Subdivision[] divs = levelDivs[count];
+ Zoom zoom = mapLevels[count];
+ if (divs == null)
+ break;
+
+ for (int i = 0; i < divs.length; i++) {
+ int flags = reader.get();
+ int lon = reader.get3();
+ int lat = reader.get3();
+ int width = reader.getChar() & 0x7fff;
+ int height = reader.getChar() & 0xffff;
+
+ if (count < levelDivs.length-1)
+ reader.getChar();
+
+ int endRgnOffset = reader.getu3();
+
+ SubdivData subdivData = new SubdivData(flags,
+ lat, lon, width, height,
+ lastRgnOffset, endRgnOffset);
+
+ Subdivision subdiv = Subdivision.readSubdivision(mapLevels[count], subdivData);
+ subdiv.setNumber(subdivNum++);
+
+ divs[i] = subdiv;
+ zoom.addSubdivision(subdiv);
+
+ lastRgnOffset = endRgnOffset;
+ }
+ }
+ }
+
+ /**
+ * Read the extended type info for the sub divisions. Corresponds to {@link #TREFile.writeExtTypeOffsetsRecords()}.
+ */
+ private void readExtTypeOffsetsRecords() {
+ ImgFileReader reader = getReader();
+ int start = header.getExtTypeOffsetsPos();
+ int end = start + header.getExtTypeOffsetsSize();
+ int skipBytes = header.getExtTypeSectionSize() - 13;
+
+ reader.position(start);
+ Subdivision sd = null;
+ Subdivision sdPrev = null;
+ for (int count = 0; count < levelDivs.length && reader.position() < end; count++) {
+ Subdivision[] divs = levelDivs[count];
+ if (divs == null)
+ break;
+
+ for (int i = 0; i < divs.length; i++) {
+ sdPrev = sd;
+ sd = divs[i];
+ sd.readExtTypeOffsetsRecord(reader, sdPrev);
+ if (skipBytes > 0)
+ reader.get(skipBytes);
+ }
+ }
+ if(sd != null) {
+ sd.readLastExtTypeOffsetsRecord(reader);
+ if (skipBytes > 0)
+ reader.get(skipBytes);
+ }
+
+ }
+
+
+ /**
+ * Read the map levels. This is needed to make sense of the subdivision
+ * data. Unlike in the write case, we just keep an array of zoom levels
+ * as found, there is no correspondence between the array index and level.
+ */
+ private void readMapLevels() {
+ ImgFileReader reader = getReader();
+
+ int levelsPos = header.getMapLevelsPos();
+ int levelsSize = header.getMapLevelsSize();
+ reader.position(levelsPos);
+
+ List<Subdivision[]> levelDivs = new ArrayList<Subdivision[]>();
+ List<Zoom> mapLevels = new ArrayList<Zoom>();
+ int end = levelsPos + levelsSize;
+ while (reader.position() < end) {
+ int level = reader.get();
+ int nbits = reader.get();
+ int ndivs = reader.getChar();
+
+ Subdivision[] divs = new Subdivision[ndivs];
+ levelDivs.add(divs);
+ level &= 0x7f;
+
+ Zoom z = new Zoom(level, nbits);
+ mapLevels.add(z);
+ }
+
+ this.levelDivs = levelDivs.toArray(new Subdivision[levelDivs.size()][]);
+ this.mapLevels = mapLevels.toArray(new Zoom[mapLevels.size()]);
+ }
+
+ public void config(EnhancedProperties props) {
+ header.config(props);
+ }
+
+ public String[] getMapInfo() {
+
+ List<String> msgs = new ArrayList<String>();
+
+ // First do the ones in the TRE header gap
+ ImgFileReader reader = getReader();
+ reader.position(header.getHeaderLength());
+ while (reader.position() < header.getHeaderLength() + header.getMapInfoSize()) {
+ String m = reader.getZString();
+ msgs.add(m);
+ }
+
+
+ return msgs.toArray(new String[msgs.size()]);
+ }
+
+ public String[] getCopyrights(LBLFileReader lblReader) {
+ Section sect = header.getCopyrightSection();
+ ImgFileReader reader = getReader();
+ List<String> msgs = new ArrayList<String>();
+
+ long pos = sect.getPosition();
+ while (pos < sect.getEndPos()) {
+ reader.position(pos);
+ int offset = reader.get3();
+ Label label = lblReader.fetchLabel(offset);
+ if (label != null) {
+ msgs.add(label.getText());
+ }
+
+ pos += sect.getItemSize();
+ }
+ return msgs.toArray(new String[msgs.size()]);
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java b/src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java
new file mode 100644
index 0000000..e3d3fc1
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java
@@ -0,0 +1,397 @@
+/*
+ * 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: Dec 14, 2007
+ */
+package uk.me.parabola.imgfmt.app.trergn;
+
+import uk.me.parabola.imgfmt.ReadFailedException;
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.CommonHeader;
+import uk.me.parabola.imgfmt.app.ImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Section;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * @author Steve Ratcliffe
+ */
+public class TREHeader extends CommonHeader {
+ private static final Logger log = Logger.getLogger(TREHeader.class);
+
+ // The tre section comes in different versions with different length
+ // headers. We just refer to them by the header length for lack of any
+ // better description.
+ public static final int TRE_120 = 120;
+ public static final int TRE_184 = 184;
+ private static final int TRE_188 = 188;
+
+ // The header length to use when creating a file.
+ private static final int DEFAULT_HEADER_LEN = TRE_188;
+
+ // A map has a display priority that determines which map is on top
+ // when two maps cover the same area.
+ private static final int DEFAULT_DISPLAY_PRIORITY = 0x19;
+
+ static final int MAP_LEVEL_REC_SIZE = 4;
+ private static final char POLYLINE_REC_LEN = 2;
+ private static final char POLYGON_REC_LEN = 2;
+ private static final char POINT_REC_LEN = 3;
+ private static final char COPYRIGHT_REC_SIZE = 0x3;
+ private static final char EXT_TYPE_OFFSETS_REC_LEN = 13;
+ private static final char EXT_TYPE_OVERVIEWS_REC_LEN = 4;
+ static final int SUBDIV_REC_SIZE = 14;
+ static final int SUBDIV_REC_SIZE2 = 16;
+
+ public static final int POI_FLAG_TRANSPARENT = 0x2;
+ public static final int POI_FLAG_STREET_BEFORE_HOUSENUMBER = 0x4;
+ public static final int POI_FLAG_POSTALCODE_BEFORE_CITY = 0x8;
+ public static final int POI_FLAG_DRIVE_ON_LEFT = 0x20;
+
+ // Bounding box. All units are in map units.
+ private Area area = new Area(0,0,0,0);
+
+ private int mapInfoSize;
+
+ private int mapLevelPos;
+ private int mapLevelsSize;
+
+ private int subdivPos;
+ private int subdivSize;
+
+ private byte poiDisplayFlags;
+
+ private int displayPriority = DEFAULT_DISPLAY_PRIORITY;
+
+ private final Section copyright = new Section(COPYRIGHT_REC_SIZE);
+ private final Section polyline = new Section(POLYLINE_REC_LEN);
+ private final Section polygon = new Section(POLYGON_REC_LEN);
+ private final Section points = new Section(POINT_REC_LEN);
+ private final Section extTypeOffsets = new Section(points, EXT_TYPE_OFFSETS_REC_LEN);
+ private final Section extTypeOverviews = new Section(extTypeOffsets, EXT_TYPE_OVERVIEWS_REC_LEN);
+
+ private int numExtTypeAreaTypes;
+ private int numExtTypeLineTypes;
+ private int numExtTypePointTypes;
+
+ private int mapId;
+
+ public TREHeader() {
+ super(DEFAULT_HEADER_LEN, "GARMIN TRE");
+ }
+
+ /**
+ * Read the rest of the header. Specific to the given file. It is guaranteed
+ * that the file position will be set to the correct place before this is
+ * called.
+ *
+ * @param reader The header is read from here.
+ */
+ protected void readFileHeader(ImgFileReader reader) throws ReadFailedException {
+ assert reader.position() == COMMON_HEADER_LEN;
+ int maxLat = reader.get3();
+ int maxLon = reader.get3();
+ int minLat = reader.get3();
+ int minLon = reader.get3();
+ // fix problem with value 0x800000 that is interpreted as a negative value
+ if (maxLon < minLon && maxLon == -8388608 )
+ maxLon = 8388608; // its 180 degrees, not -180
+
+ setBounds(new Area(minLat, minLon, maxLat, maxLon));
+ log.info("read area is", getBounds());
+
+ // more to do...
+ mapLevelPos = reader.getInt();
+ mapLevelsSize = reader.getInt();
+ subdivPos = reader.getInt();
+ subdivSize = reader.getInt();
+
+ copyright.readSectionInfo(reader, true);
+ reader.getInt();
+
+ poiDisplayFlags = reader.get();
+ displayPriority = reader.get3();
+ reader.getInt();
+ reader.getChar();
+ reader.get();
+
+ polyline.readSectionInfo(reader, true);
+ reader.getInt();
+ polygon.readSectionInfo(reader, true);
+ reader.getInt();
+ points.readSectionInfo(reader, true);
+ reader.getInt();
+
+ int mapInfoOff = mapLevelPos;
+ if (subdivPos < mapInfoOff)
+ mapInfoOff = subdivPos;
+ if (copyright.getPosition() < mapInfoOff)
+ mapInfoOff = copyright.getPosition();
+
+ mapInfoSize = mapInfoOff - getHeaderLength();
+ if (getHeaderLength() > 116) {
+ reader.position(116);
+ mapId = reader.getInt();
+ }
+ if (getHeaderLength() > 120) {
+ reader.getInt();
+ extTypeOffsets.readSectionInfo(reader, true);
+ }
+ }
+
+ /**
+ * Write the rest of the header. It is guaranteed that the writer will be set
+ * to the correct position before calling.
+ *
+ * @param writer The header is written here.
+ */
+ protected void writeFileHeader(ImgFileWriter writer) {
+ writer.put3(area.getMaxLat());
+ writer.put3(area.getMaxLong());
+ writer.put3(area.getMinLat());
+ writer.put3(area.getMinLong());
+
+ writer.putInt(getMapLevelsPos());
+ writer.putInt(getMapLevelsSize());
+
+ writer.putInt(getSubdivPos());
+ writer.putInt(getSubdivSize());
+
+ copyright.writeSectionInfo(writer);
+ writer.putInt(0);
+
+ writer.put(getPoiDisplayFlags());
+
+ writer.put3(displayPriority);
+ writer.putInt(0x110301);
+
+ writer.putChar((char) 1);
+ writer.put((byte) 0);
+
+ polyline.writeSectionInfo(writer);
+ writer.putInt(0);
+ polygon.writeSectionInfo(writer);
+ writer.putInt(0);
+ points.writeSectionInfo(writer);
+ writer.putInt(0);
+
+ // There are a number of versions of the header with increasing lengths
+ if (getHeaderLength() > 116)
+ writer.putInt(getMapId());
+
+ if (getHeaderLength() > 120) {
+ writer.putInt(0);
+
+ // The record size must be zero if the section is empty for compatibility
+ // with cpreview.
+ if (extTypeOffsets.getSize() == 0)
+ extTypeOffsets.setItemSize((char) 0);
+ extTypeOffsets.writeSectionInfo(writer, true);
+
+ // the second byte value of 6 appears to mean "extended
+ // type info present" - a value of 4 has been seen in some
+ // maps but those maps contain something else in these two
+ // sections and not extended type info - the 7 in the
+ // bottom byte could possibly be a bitmask to say which
+ // types are present (line, area, point) but this is just
+ // conjecture
+ writer.putInt(0x0607);
+
+ extTypeOverviews.writeSectionInfo(writer);
+ writer.putChar((char)numExtTypeLineTypes);
+ writer.putChar((char)numExtTypeAreaTypes);
+ writer.putChar((char)numExtTypePointTypes);
+ }
+
+ if (getHeaderLength() > 154) {
+ MapValues mv = new MapValues(mapId, getHeaderLength());
+ mv.calculate();
+ writer.putInt(mv.value(0));
+ writer.putInt(mv.value(1));
+ writer.putInt(mv.value(2));
+ writer.putInt(mv.value(3));
+
+ writer.putInt(0);
+ writer.putInt(0);
+ writer.putInt(0);
+ writer.putChar((char) 0);
+ writer.putInt(0);
+ }
+
+ writer.position(getHeaderLength());
+ }
+
+ public void config(EnhancedProperties props) {
+ String key = "draw-priority";
+ if (props.containsKey(key))
+ setDisplayPriority(props.getProperty(key, 0x19));
+
+ if (props.containsKey("transparent"))
+ poiDisplayFlags |= POI_FLAG_TRANSPARENT;
+
+ if (props.containsKey("drive-on-left"))
+ poiDisplayFlags |= POI_FLAG_DRIVE_ON_LEFT;
+ }
+
+ /**
+ * Set the bounds based upon the latitude and longitude in degrees.
+ * @param area The area bounded by the map.
+ */
+ public void setBounds(Area area) {
+ this.area = area;
+ }
+
+ public Area getBounds() {
+ return area;
+ }
+
+ public void setMapId(int id) {
+ mapId = id;
+ }
+
+ public void addPoiDisplayFlags(byte poiDisplayFlags) {
+ this.poiDisplayFlags |= poiDisplayFlags;
+ }
+
+ public int getMapInfoSize() {
+ return mapInfoSize;
+ }
+
+ public void setMapInfoSize(int mapInfoSize) {
+ this.mapInfoSize = mapInfoSize;
+ }
+
+ public int getMapLevelsPos() {
+ return mapLevelPos;
+ }
+
+ public void setMapLevelPos(int mapLevelPos) {
+ this.mapLevelPos = mapLevelPos;
+ }
+
+ public int getMapLevelsSize() {
+ return mapLevelsSize;
+ }
+
+ public void setMapLevelsSize(int mapLevelsSize) {
+ this.mapLevelsSize = mapLevelsSize;
+ }
+
+ public int getSubdivPos() {
+ return subdivPos;
+ }
+
+ public void setSubdivPos(int subdivPos) {
+ this.subdivPos = subdivPos;
+ }
+
+ public int getSubdivSize() {
+ return subdivSize;
+ }
+
+ public void setSubdivSize(int subdivSize) {
+ this.subdivSize = subdivSize;
+ }
+
+ public void setCopyrightPos(int copyrightPos) {
+ //this.copyrightPos = copyrightPos;
+ copyright.setPosition(copyrightPos);
+ }
+
+ public void incCopyrightSize() {
+ copyright.inc();
+ }
+
+ protected byte getPoiDisplayFlags() {
+ return poiDisplayFlags;
+ }
+
+ public void setPolylinePos(int polylinePos) {
+ polyline.setPosition(polylinePos);
+ }
+
+ public void incPolylineSize() {
+ polyline.inc();
+ }
+
+ public void setPolygonPos(int polygonPos) {
+ polygon.setPosition(polygonPos);
+ }
+
+ public void incPolygonSize() {
+ polygon.inc();
+ }
+
+ public void setPointPos(int pointPos) {
+ points.setPosition(pointPos);
+ }
+
+ public void incPointSize() {
+ points.inc();
+ }
+
+ public void setExtTypeOffsetsPos(int pos) {
+ extTypeOffsets.setPosition(pos);
+ }
+
+ public void incExtTypeOffsetsSize() {
+ extTypeOffsets.inc();
+ }
+
+ public void setExtTypeOverviewsPos(int pos) {
+ extTypeOverviews.setPosition(pos);
+ }
+
+ public void incExtTypeOverviewsSize() {
+ extTypeOverviews.inc();
+ }
+
+ public void incNumExtTypeAreaTypes() {
+ ++numExtTypeAreaTypes;
+ }
+
+ public void incNumExtTypeLineTypes() {
+ ++numExtTypeLineTypes;
+ }
+ public void incNumExtTypePointTypes() {
+ ++numExtTypePointTypes;
+ }
+
+ public int getMapId() {
+ return mapId;
+ }
+
+ protected void setDisplayPriority(int displayPriority) {
+ this.displayPriority = displayPriority;
+ }
+
+ public int getDisplayPriority() {
+ return displayPriority;
+ }
+
+ public int getExtTypeOffsetsPos() {
+ return extTypeOffsets.getPosition();
+ }
+ public int getExtTypeOffsetsSize() {
+ return extTypeOffsets.getSize();
+ }
+ public int getExtTypeSectionSize() {
+ return extTypeOffsets.getItemSize();
+ }
+
+ public Section getCopyrightSection() {
+ return copyright;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/Zoom.java b/src/uk/me/parabola/imgfmt/app/trergn/Zoom.java
new file mode 100644
index 0000000..f2cacac
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/Zoom.java
@@ -0,0 +1,91 @@
+/*
+ * 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: 07-Dec-2006
+ */
+package uk.me.parabola.imgfmt.app.trergn;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A zoom level (or map level) determines the amount of detail that
+ * is shown as you zoom in and out.
+ * Level 0 is the the most detailed level.
+ *
+ * A zoom level has a number of bits per co-ordinate and the number of
+ * subdivisions at that level.
+ *
+ * The highest level must have one subdivision and have no elements I believe.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Zoom {
+ private final int level;
+ private boolean inherited;
+
+ private final int resolution;
+
+ private final List<Subdivision> subdivs = new ArrayList<Subdivision>();
+
+ /**
+ * Create a new zoom level.
+ *
+ * @param zoom The level between 0 and 15.
+ * @param resolution The number of bits per coordinate, up to 24.
+ */
+ Zoom(int zoom, int resolution) {
+ this.level = zoom;
+ this.resolution = resolution;
+ }
+
+
+ public Iterator<Subdivision> subdivIterator() {
+ return subdivs.iterator();
+ }
+
+ public void setInherited(boolean inherited) {
+ this.inherited = inherited;
+ }
+
+
+ public int getLevel() {
+ return level;
+ }
+
+ public int getResolution() {
+ return resolution;
+ }
+
+ public int getShiftValue() {
+ return 24 - resolution;
+ }
+
+ public void write(ImgFileWriter file) {
+ file.put((byte) ((level & 0xf) | (inherited ? 0x80 : 0)));
+ file.put((byte) resolution);
+ file.putChar((char) subdivs.size());
+ }
+
+ public String toString() {
+ return "L " + level + ':' + resolution;
+ }
+
+ void addSubdivision(Subdivision div) {
+ subdivs.add(div);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/package.html b/src/uk/me/parabola/imgfmt/app/trergn/package.html
new file mode 100644
index 0000000..fafdfbe
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/trergn/package.html
@@ -0,0 +1,22 @@
+<body>
+<h3>The TRE and RGN files</h3>
+
+<p>These files are so inter dependant that it only makes sense to put
+them into the same package.</p>
+
+<h4>The TRE file</h4>
+<p>This file describes the structure of the map. It contains the
+zoom levels that exist in the map and how the map is divided up.</p>
+<p>There are in effect several copies of the map at different levels
+of detail. Each level is divided up into several areas known as subdivisions.
+ These subdivisions form a tree, with more detailed ones being children of
+ the higher (less detailed) levels.
+</p>
+
+<h4>The RGN file</h4>
+<p>This file contains the detailed location and path of all the map
+objects. Pointers from the TRE file indicate the start of the definition
+of a map object and information from the TRE section needs to be used
+to work out where the location of the map object is.</p>
+
+</body>
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/app/typ/AlphaAdder.java b/src/uk/me/parabola/imgfmt/app/typ/AlphaAdder.java
new file mode 100644
index 0000000..55ad15b
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/AlphaAdder.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.imgfmt.app.typ;
+
+/**
+ * Interface for adding an alpha value to a previously saved colour value.
+ *
+ * The current TYP editors place the alpha value after the colour definition, eg:
+ *
+ * "#992299" alpha 5
+ *
+ * so we need to add the alpha value to a colour that has already been read
+ * in.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface AlphaAdder {
+
+ /**
+ * Add an alpha value to the last colour that was saved.
+ *
+ * @param alpha A true alpha value ie 0 is transparent, 255 opaque.
+ */
+ public void addAlpha(int alpha);
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/BitmapImage.java b/src/uk/me/parabola/imgfmt/app/typ/BitmapImage.java
new file mode 100644
index 0000000..4f15401
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/BitmapImage.java
@@ -0,0 +1,66 @@
+package uk.me.parabola.imgfmt.app.typ;
+
+import uk.me.parabola.imgfmt.app.BitWriter;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * Holds a bitmap image for the typ file.
+ *
+ * There are a number of different formats allowed.
+ *
+ * Based on code by Thomas LuÃnig, but type and colour information separated out and
+ * deals with more than just points.
+ */
+public class BitmapImage implements Image {
+
+ private final ColourInfo colourInfo;
+ private final String image;
+
+ public BitmapImage(ColourInfo colourInfo, String image) {
+ this.colourInfo = colourInfo;
+ this.image = image;
+ }
+
+ public void write(ImgFileWriter writer) {
+
+ final int bitSize = colourInfo.getBitsPerPixel();
+ int cpp = colourInfo.getCharsPerPixel();
+
+ int width = colourInfo.getWidth();
+ int height = colourInfo.getHeight();
+
+ int i = 0;
+ for (int h = 0; h < height; h++) {
+ // Each row is padded to a byte boundary, creating a new bit writer for every
+ // row ensures that happens.
+ BitWriter bitWriter = new BitWriter();
+
+ for (int w = 0; w < width; w++) {
+ String idx = image.substring(i, i + cpp);
+ i += cpp;
+
+ int val = colourInfo.getIndex(idx);
+ bitWriter.putn(val, bitSize);
+ }
+ writer.put(bitWriter.getBytes(), 0, bitWriter.getLength());
+ }
+ }
+
+ public int compare(BitmapImage a, BitmapImage b) {
+ throw new UnsupportedOperationException();
+ //if (a == null)
+ // return 1;
+ //if (b == null)
+ // return -1;
+ //if (a.typ < b.typ)
+ // return -1;
+ //if (a.typ > b.typ)
+ // return 1;
+ //if (a.dayNight < b.dayNight)
+ // return -1;
+ //if (a.dayNight > b.dayNight)
+ // return 1;
+ //return 0;
+ }
+
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/ColourInfo.java b/src/uk/me/parabola/imgfmt/app/typ/ColourInfo.java
new file mode 100644
index 0000000..adf2a2d
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/ColourInfo.java
@@ -0,0 +1,353 @@
+/*
+ * 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.imgfmt.app.typ;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.app.BitWriter;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Writeable;
+
+/**
+ * Holds colour information for elements in the typ file.
+ *
+ * The Colour information can relate to a bitmap or solid shapes.
+ *
+ * @author Steve Ratcliffe
+ */
+public class ColourInfo implements Writeable, AlphaAdder {
+ private static final int S_NIGHT = 1;
+ private static final int S_DAY_TRANSPARENT = 0x2;
+ private static final int S_NIGHT_TRANSPARENT = 0x4;
+ private static final int S_HAS_BITMAP = 0x8;
+
+ private int numberOfColours;
+ private int numberOfSolidColours;
+
+ private boolean hasBitmap;
+ private boolean hasBorder;
+ private final List<RgbWithTag> colours = new ArrayList<RgbWithTag>();
+ private final Map<String, Integer> indexMap = new HashMap<String, Integer>();
+
+ private char width;
+ private char height;
+ private char charsPerPixel;
+
+ private boolean simple = true;
+ private char colourMode;
+
+ /**
+ * Add a colour for this element.
+ * @param tag The xpm tag that represents the colour.
+ * @param rgb The actual colour.
+ */
+ public void addColour(String tag, Rgb rgb) {
+ RgbWithTag cwt = new RgbWithTag(tag, rgb);
+ colours.add(cwt);
+ }
+
+ /**
+ * Add a transparent colour. Convenience routine.
+ */
+ public void addTransparent(String colourTag) {
+ addColour(colourTag, new Rgb(0, 0, 0, 0));
+ }
+
+ public void setHasBitmap(boolean hasBitmap) {
+ this.hasBitmap = hasBitmap;
+ }
+
+ /**
+ * The colour scheme in use. This is a bitmask that has the following bits:
+ * 0 - Has night colour
+ * 1 - day background colour is transparent
+ * 2 - night background colour is transparent
+ * 3 - has bitmap
+ *
+ * If there is no night colour, then set the night background colour bit to be the same as
+ * the day one.
+ *
+ * @return The colour scheme bitmask. The term colour scheme is historical, it doesn't really
+ * describe it.
+ */
+ public int getColourScheme() {
+ if (numberOfColours == 0)
+ numberOfColours = colours.size();
+
+ int scheme = 0;
+ if (hasBitmap)
+ scheme |= S_HAS_BITMAP;
+
+ if (numberOfColours == 4)
+ scheme |= S_NIGHT;
+
+ if (!hasBitmap && !hasBorder && numberOfColours == 2)
+ scheme |= S_NIGHT | S_DAY_TRANSPARENT | S_NIGHT_TRANSPARENT;
+
+ if (numberOfColours < 2 || colours.get(1).isTransparent())
+ scheme |= S_DAY_TRANSPARENT;
+ if (numberOfColours == 4 && (colours.get(3).isTransparent()))
+ scheme |= S_NIGHT_TRANSPARENT;
+
+ if ((scheme & S_NIGHT) == 0)
+ if ((scheme & S_DAY_TRANSPARENT) != 0)
+ scheme |= S_NIGHT_TRANSPARENT;
+
+ return scheme;
+ }
+
+ /**
+ * Get the number of bits per pixel that will be used in the written bitmap.
+ *
+ * This depends on the colour mode and number of colours to be represented.
+ */
+ public int getBitsPerPixel() {
+ if (simple)
+ return 1;
+
+ // number of colours includes the transparent pixel in colormode=0x10 so this
+ // works for all colour modes.
+ int nc = numberOfColours;
+ if (nc == 0)
+ return 24;
+ else if (nc < 2)
+ return 1;
+ else if (nc < 4)
+ return 2;
+ else if (nc < 16)
+ return 4;
+ else
+ return 8;
+ }
+
+ /**
+ * Write out the colours only.
+ */
+ public void write(ImgFileWriter writer) {
+ if (colourMode == 0x20) {
+ writeColours20(writer);
+ } else {
+ for (Rgb rgb : colours) {
+ if (!rgb.isTransparent())
+ rgb.write(writer, (byte) 0x10);
+ }
+ }
+ }
+
+ /**
+ * Write out the colours in the colormode=x20 case.
+ */
+ private void writeColours20(ImgFileWriter writer) {
+ BitWriter bw = new BitWriter();
+ for (Rgb rgb : colours) {
+ bw.putn(rgb.getB(), 8);
+ bw.putn(rgb.getG(), 8);
+ bw.putn(rgb.getR(), 8);
+
+ int alpha = 0xff - rgb.getA();
+ alpha = alphaRound4(alpha);
+
+ bw.putn(alpha, 4);
+ }
+ writer.put(bw.getBytes(), 0, bw.getLength());
+ }
+
+ /**
+ * Round alpha value to four bits.
+ * @param alpha The original alpha value eg 0xf0.
+ * @return Rounded alpha to four bits eg 0xe.
+ */
+ static int alphaRound4(int alpha) {
+ int top = (alpha >> 4) & 0xf;
+ int low = alpha & 0xf;
+
+ int diff = low-top;
+ if (diff > 8)
+ top++;
+ else if (diff < -8)
+ top--;
+ return top;
+ }
+
+ public int getIndex(String tag) {
+ Integer ind = indexMap.get(tag);
+
+ // If this is a simple bitmap (for line or polygon), then the foreground colour is
+ // first and so has index 0, but we want the foreground to have index 1, so reverse.
+ if (simple)
+ ind = ~ind;
+
+ return ind;
+ }
+
+ public void setWidth(int width) {
+ this.width = (char) width;
+ }
+
+ public void setHeight(int height) {
+ this.height = (char) height;
+ }
+
+ public void setNumberOfColours(int numberOfColours) {
+ this.numberOfColours = numberOfColours;
+ }
+
+ public void setCharsPerPixel(int charsPerPixel) {
+ this.charsPerPixel = (char) (charsPerPixel == 0 ? 1 : charsPerPixel);
+ }
+
+ public int getNumberOfColours() {
+ return numberOfColours;
+ }
+
+ public int getNumberOfSColoursForCM() {
+ if (colourMode == 0x10)
+ return numberOfSolidColours;
+ else
+ return numberOfColours;
+ }
+
+ public int getCharsPerPixel() {
+ return charsPerPixel;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public int getColourMode() {
+ return colourMode;
+ }
+
+ public void setColourMode(int colourMode) {
+ this.colourMode = (char) colourMode;
+ }
+
+ public void setSimple(boolean simple) {
+ this.simple = simple;
+ }
+
+ public void setHasBorder(boolean hasBorder) {
+ this.hasBorder = hasBorder;
+ }
+
+ /**
+ * Replace the last pixel with a pixel with the same colour components and the given
+ * alpha.
+ *
+ * This is used when the alpha value is specified separately to the colour values in the
+ * input file.
+ * @param alpha The alpha value to be added to the pixel. This is a real alpha, not a transparency.
+ */
+ public void addAlpha(int alpha) {
+ int last = colours.size();
+ RgbWithTag rgb = colours.get(last - 1);
+ rgb = new RgbWithTag(rgb, alpha);
+ colours.set(last - 1, rgb);
+ }
+
+ /**
+ * Analyse the colour pallet and normalise it.
+ *
+ * Try to work out what is required from the supplied colour pallet and set the colour mode
+ * and rearrange transparent pixels if necessary to be in the proper place.
+ *
+ * At the end we build the index from colour tag to pixel index.
+ *
+ * @param simple If this is a line or polygon.
+ * @return A string describing the validation failure.
+ */
+ public String analyseColours(boolean simple) {
+ setSimple(simple);
+
+ if (simple) {
+ // There can be up to four colours, no partial transparency, and a max of one transparent pixel
+ // in each of the day/night sections.
+
+ if (numberOfColours > 4)
+ return ("Too many colours for a line or polygon");
+ if (numberOfColours == 0)
+ return "Line or polygon cannot have zero colours";
+
+ // Putting the transparent pixel first is common, so reverse if found
+ if (colours.get(0).isTransparent()) {
+ if (numberOfColours < 2)
+ return "Only colour cannot be transparent for line or polygon";
+ swapColour(0, 1);
+ }
+ if (numberOfColours > 2 && colours.get(2).isTransparent()) {
+ if (numberOfColours < 4)
+ return "Only colour cannot be transparent for line or polygon";
+ swapColour(2, 3);
+ }
+
+ // There can only be one transparent pixel per colour pair
+ if (numberOfColours > 1 && colours.get(0).isTransparent())
+ return "Both day foreground and background are transparent";
+ if (numberOfColours > 3 && colours.get(2).isTransparent())
+ return "Both night foreground and background are transparent";
+
+ } else {
+ int transIndex = 0; // index of last transparent pixel, only used when there is only one
+ int nTrans = 0; // completely transparent
+ int nAlpha = 0; // partially transparent
+ int count = 0; // total number of colours
+ for (RgbWithTag rgb : colours) {
+ if (rgb.isTransparent()) {
+ nTrans++;
+ transIndex = count;
+ }
+
+ if (rgb.getA() != 0xff && rgb.getA() != 0)
+ nAlpha++;
+ count++;
+ }
+
+ if (nAlpha > 0 || (count > 0 && count == nTrans)) {
+ // If there is any partial transparency we need colour mode 0x20
+ // Also if there is only one pixel and it is transparent, since otherwise there would be zero
+ // solid colours and that is a special case used to indicate a true colour pixmap.
+ colourMode = 0x20;
+
+ } else if (nTrans == 1) {
+ colourMode = 0x10;
+
+ // Ensure the transparent pixel is at the end
+ RgbWithTag rgb = colours.remove(transIndex);
+ colours.add(rgb);
+ }
+ }
+
+ int count = 0;
+ for (RgbWithTag rgb : colours) {
+ indexMap.put(rgb.getTag(), count++);
+ if (!rgb.isTransparent())
+ numberOfSolidColours++;
+ }
+
+ return null;
+ }
+
+ private void swapColour(int c1, int c2) {
+ RgbWithTag tmp = colours.get(c1);
+ colours.set(c1, colours.get(c2));
+ colours.set(c2, tmp);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/DrawOrder.java b/src/uk/me/parabola/imgfmt/app/typ/DrawOrder.java
new file mode 100644
index 0000000..59b1bb1
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/DrawOrder.java
@@ -0,0 +1,32 @@
+package uk.me.parabola.imgfmt.app.typ;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Writeable;
+
+/**
+ * The drawing order for a type and a set of subtypes.
+ *
+ * The drawing order is specified by the order of these within the file, rather than anything
+ * actually in the item.
+ */
+public class DrawOrder implements Writeable {
+ private final byte type;
+ private int subTypes;
+ private boolean hasSubtypes;
+
+ public DrawOrder(int type) {
+ this.type = (byte) (type & 0xff);
+ if (type >= 0x100)
+ hasSubtypes = true;
+ }
+
+ public void write(ImgFileWriter writer) {
+ writer.put(type);
+ writer.putInt(subTypes);
+ }
+
+ public void addSubtype(int subtype) {
+ if (hasSubtypes)
+ subTypes |= 1 << subtype;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/Image.java b/src/uk/me/parabola/imgfmt/app/typ/Image.java
new file mode 100644
index 0000000..fafca6f
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/Image.java
@@ -0,0 +1,23 @@
+/*
+ * 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.imgfmt.app.typ;
+
+import uk.me.parabola.imgfmt.app.Writeable;
+
+/**
+ * Interface for the different image types.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface Image extends Writeable {
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/Rgb.java b/src/uk/me/parabola/imgfmt/app/typ/Rgb.java
new file mode 100644
index 0000000..49e9329
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/Rgb.java
@@ -0,0 +1,87 @@
+package uk.me.parabola.imgfmt.app.typ;
+
+import uk.me.parabola.imgfmt.FormatException;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+public class Rgb {
+ private final int b;
+ private final int g;
+ private final int r;
+ private final int a;
+
+ public Rgb(int r, int g, int b, int a) {
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ this.a = a;
+ }
+
+ public Rgb(int r, int g, int b) {
+ this(r, g, b, 0xff);
+ }
+
+ /**
+ * Initialise from a string.
+ *
+ * The format is #RRGGBB and without the '#'. You can also append
+ * an alpha value. FF for fully opaque, and 00 for fully transparent.
+ * The typ file only deals with fully transparent.
+ *
+ * @param in The string form of the color.
+ */
+ public Rgb(String in) {
+ String colour = in;
+ if (colour.startsWith("#"))
+ colour = colour.substring(1);
+
+ r = Integer.parseInt(colour.substring(0, 2), 16);
+ g = Integer.parseInt(colour.substring(2, 4), 16);
+ b = Integer.parseInt(colour.substring(4, 6), 16);
+ if (colour.length() > 6)
+ a = Integer.parseInt(colour.substring(6, 8), 16);
+ else
+ a = 0xff;
+ }
+
+ /**
+ * Create a new Rgb from the given one, adding the given alpha channel value.
+ */
+ public Rgb(Rgb rgb, int alpha) {
+ this(rgb.r, rgb.g, rgb.b, alpha);
+ }
+
+ public void write(ImgFileWriter writer, byte type) {
+ if (type != 0x10)
+ throw new FormatException("Invalid color deep");
+ writer.put((byte) b);
+ writer.put((byte) g);
+ writer.put((byte) r);
+ }
+
+ public boolean isTransparent() {
+ return a == 0;
+ }
+
+ public String toString() {
+ if (a == 0xff)
+ return String.format("#%02x%02x%02x", r, g, b);
+ else
+ return String.format("#%02x%02x%02x%02x", r, g, b, a);
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public int getG() {
+ return g;
+ }
+
+ public int getR() {
+ return r;
+ }
+
+ public int getA() {
+ return a;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/RgbWithTag.java b/src/uk/me/parabola/imgfmt/app/typ/RgbWithTag.java
new file mode 100644
index 0000000..721f56f
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/RgbWithTag.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 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 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.imgfmt.app.typ;
+
+/**
+ * @author Steve Ratcliffe
+ */
+public class RgbWithTag extends Rgb {
+ private final String tag;
+
+ public RgbWithTag(String tag, Rgb rgb) {
+ super(rgb.getR(), rgb.getG(), rgb.getB(), rgb.getA());
+ this.tag = tag;
+ }
+
+ public RgbWithTag(RgbWithTag rgb, int alpha) {
+ super(rgb, alpha);
+ this.tag = rgb.getTag();
+ }
+
+ public String getTag() {
+ return tag;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/ShapeStacking.java b/src/uk/me/parabola/imgfmt/app/typ/ShapeStacking.java
new file mode 100644
index 0000000..9c32e50
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/ShapeStacking.java
@@ -0,0 +1,64 @@
+/*
+ * 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: Dec 15, 2007
+ */
+package uk.me.parabola.imgfmt.app.typ;
+
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * Holds the shape stacking section.
+ *
+ * Deals with sorting everything correctly, so no need to sort in the input file.
+ *
+ * @author Steve Ratcliffe
+ */
+public class ShapeStacking {
+ private final SortedMap<Integer, DrawOrder> bar = new TreeMap<Integer, DrawOrder>();
+
+ public void addPolygon(int level, int type, int subtype) {
+ int levelType = (level << 16) + type;
+ DrawOrder order = bar.get(levelType);
+ if (order == null) {
+ order = new DrawOrder(type);
+ bar.put(levelType, order);
+ }
+
+ order.addSubtype(subtype);
+ }
+
+ public void write(ImgFileWriter writer) {
+ int lastLevel = 1;
+
+ DrawOrder empty = new DrawOrder(0);
+
+ for (Map.Entry<Integer, DrawOrder> ent : bar.entrySet()) {
+ int level = (ent.getKey() >> 16) & 0xffff;
+ DrawOrder order = ent.getValue();
+
+ if (level != lastLevel) {
+ empty.write(writer);
+ lastLevel = level;
+ }
+
+ order.write(writer);
+ }
+ }
+
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/TYPFile.java b/src/uk/me/parabola/imgfmt/app/typ/TYPFile.java
new file mode 100644
index 0000000..e19208c
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/TYPFile.java
@@ -0,0 +1,236 @@
+/*
+ * 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: 03-Dec-2006
+ * Change: Thomas LuÃnig <gps at suche.org>
+ */
+package uk.me.parabola.imgfmt.app.typ;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetEncoder;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.BufferedImgFileWriter;
+import uk.me.parabola.imgfmt.app.ImgFile;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Section;
+import uk.me.parabola.imgfmt.app.SectionWriter;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.log.Logger;
+
+/**
+ * The TYP file.
+ *
+ * @author Thomas LuÃnig
+ * @author Steve Ratcliffe
+ */
+public class TYPFile extends ImgFile {
+ private static final Logger log = Logger.getLogger(TYPFile.class);
+
+ private final TYPHeader header = new TYPHeader();
+
+ private TypData data;
+
+ private final Map<Integer, Integer> strToType = new TreeMap<Integer, Integer>();
+ private final Map<Integer, Integer> typeToStr = new TreeMap<Integer, Integer>();
+
+ public TYPFile(ImgChannel chan) {
+ setHeader(header);
+ setWriter(new BufferedImgFileWriter(chan));
+ position(TYPHeader.HEADER_LEN);
+ }
+
+ public void write() {
+
+ ImgFileWriter writer = getWriter();
+ writer.position(TYPHeader.HEADER_LEN);
+
+ writeSection(writer, header.getPolygonData(), header.getPolygonIndex(), data.getPolygons());
+ writeSection(writer, header.getLineData(), header.getLineIndex(), data.getLines());
+ writeSection(writer, header.getPointData(), header.getPointIndex(), data.getPoints());
+
+ SectionWriter subWriter = header.getShapeStacking().makeSectionWriter(writer);
+ data.getStacking().write(subWriter);
+ Utils.closeFile(subWriter);
+
+ writeSection(writer, header.getIconData(), header.getIconIndex(), data.getIcons());
+
+ writeLabels(writer);
+ writeStrIndex(writer);
+ writerTypeIndex(writer);
+
+ zapZero(header.getShapeStacking(), header.getLabels(), header.getStringIndex(), header.getTypeIndex());
+
+ log.debug("syncing TYP file");
+ position(0);
+ getHeader().writeHeader(getWriter());
+ }
+
+ private void writeLabels(ImgFileWriter in) {
+ if (data.getIcons().isEmpty())
+ return;
+
+ SectionWriter writer = header.getLabels().makeSectionWriter(in);
+
+ List<SortKey<TypIconSet>> keys = new ArrayList<SortKey<TypIconSet>>();
+ Sort sort = data.getSort();
+ for (TypIconSet icon : data.getIcons()) {
+ String label = icon.getLabel();
+ if (label != null) {
+ SortKey<TypIconSet> key = sort.createSortKey(icon, label);
+ keys.add(key);
+ }
+ }
+ Collections.sort(keys);
+
+ // Offset 0 is reserved to mean no label.
+ writer.put((byte) 0);
+
+ for (SortKey<TypIconSet> key : keys) {
+ int off = writer.position();
+ TypIconSet icon = key.getObject();
+ int type = icon.getTypeForFile();
+
+ String label = icon.getLabel();
+ if (label != null) {
+ CharBuffer cb = CharBuffer.wrap(label);
+ CharsetEncoder encoder = data.getEncoder();
+ try {
+ ByteBuffer buffer = encoder.encode(cb);
+ writer.put(buffer);
+
+ // If we succeeded then note offsets for indexes
+ strToType.put(off, type);
+ typeToStr.put(type, off);
+
+ } catch (CharacterCodingException ignore) {
+ String name = encoder.charset().name();
+ throw new TypLabelException(name);
+ }
+ writer.put((byte) 0);
+ }
+ }
+ Utils.closeFile(writer);
+ }
+
+ private void writeStrIndex(ImgFileWriter in) {
+ SectionWriter writer = header.getStringIndex().makeSectionWriter(in);
+ int psize = ptrSize(header.getLabels().getSize());
+ header.getStringIndex().setItemSize((char) (3 + psize));
+
+ for (Map.Entry<Integer, Integer> ent : strToType.entrySet()) {
+ putN(writer, psize, ent.getKey());
+ putN(writer, 3, ent.getValue());
+ }
+ Utils.closeFile(writer);
+ }
+
+ private void writerTypeIndex(ImgFileWriter in) {
+ SectionWriter writer = header.getTypeIndex().makeSectionWriter(in);
+ int psize = ptrSize(header.getLabels().getSize());
+ header.getTypeIndex().setItemSize((char) (3 + psize));
+
+ for (Map.Entry<Integer, Integer> ent : typeToStr.entrySet()) {
+ putN(writer, 3, ent.getKey());
+ putN(writer, psize, ent.getValue());
+ }
+ Utils.closeFile(writer);
+ }
+
+ private void writeSection(ImgFileWriter writer, Section dataSection, Section indexSection,
+ List<? extends TypElement> elementData)
+ {
+ Collections.sort(elementData);
+
+ SectionWriter subWriter = dataSection.makeSectionWriter(writer);
+ CharsetEncoder encoder = data.getEncoder();
+ for (TypElement elem : elementData)
+ elem.write(subWriter, encoder);
+ Utils.closeFile(subWriter);
+
+ int size = dataSection.getSize();
+ int typeSize = indexSection.getItemSize();
+ int psize = ptrSize(size);
+
+ indexSection.setItemSize((char) (typeSize + psize));
+
+ subWriter = indexSection.makeSectionWriter(writer);
+ for (TypElement elem : elementData) {
+ int offset = elem.getOffset();
+ int type = elem.getTypeForFile();
+ putN(subWriter, typeSize, type);
+ putN(subWriter, psize, offset);
+ }
+ Utils.closeFile(subWriter);
+
+ zapZero(dataSection, indexSection);
+ }
+
+ private void zapZero(Section... sect) {
+ for (Section s : sect) {
+ if (s.getSize() == 0) {
+ s.setPosition(0);
+ s.setItemSize((char) 0);
+ }
+ }
+ }
+
+ private int ptrSize(int size) {
+ int psize = 1;
+ if (size > 0xffffff)
+ psize = 4;
+ else if (size > 0xffff)
+ psize = 3;
+ else if (size > 0xff)
+ psize = 2;
+ return psize;
+ }
+
+ protected void putN(ImgFileWriter writer, int n, int value) {
+ switch (n) {
+ case 1:
+ writer.put((byte) value);
+ break;
+ case 2:
+ writer.putChar((char) value);
+ break;
+ case 3:
+ writer.put3(value);
+ break;
+ case 4:
+ writer.putInt(value);
+ break;
+ default: // Don't write anything.
+ assert false;
+ break;
+ }
+ }
+
+ public void setData(TypData data) {
+ this.data = data;
+ TypParam param = data.getParam();
+ header.setCodePage((char) param.getCodePage());
+ header.setFamilyId((char) param.getFamilyId());
+ header.setProductId((char) param.getProductId());
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/TYPHeader.java b/src/uk/me/parabola/imgfmt/app/typ/TYPHeader.java
new file mode 100644
index 0000000..c6368a4
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/TYPHeader.java
@@ -0,0 +1,215 @@
+/*
+ * 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: Dec 14, 2007
+ */
+package uk.me.parabola.imgfmt.app.typ;
+
+import uk.me.parabola.imgfmt.app.CommonHeader;
+import uk.me.parabola.imgfmt.app.ImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Section;
+
+/**
+ * The header for the TYP file.
+ *
+ * @author Thomas LuÃnig
+ */
+public class TYPHeader extends CommonHeader {
+ public static final int HEADER_LEN = 0x9c; // 0x6e;
+
+ private char familyId;
+ private char productId;
+ private char codePage;
+
+ private final Section pointData = new Section();
+ private final Section lineData = new Section(pointData);
+ private final Section polygonData = new Section(lineData);
+
+ private final Section pointIndex = new Section(polygonData, (char) 2);
+ private final Section lineIndex = new Section(pointIndex, (char) 2);
+ private final Section polygonIndex = new Section(lineIndex, (char) 2);
+
+ private final Section shapeStacking = new Section(polygonIndex, (char) 5);
+
+ private final Section iconData = new Section(polygonIndex);
+ private final Section iconIndex = new Section(iconData, (char) 3);
+
+ private final Section labels = new Section(iconIndex);
+ private final Section stringIndex = new Section(labels);
+ private final Section typeIndex = new Section(stringIndex);
+
+ public TYPHeader() {
+ super(HEADER_LEN, "GARMIN TYP");
+ }
+
+ /**
+ * Read the rest of the header. Specific to the given file. It is guaranteed
+ * that the file position will be set to the correct place before this is
+ * called.
+ *
+ * @param reader The header is read from here.
+ */
+ protected void readFileHeader(ImgFileReader reader) {
+ // Reset position for the real header reading code.
+ reader.position(COMMON_HEADER_LEN);
+ codePage = reader.getChar(); // 1252
+ pointData.setPosition(reader.getInt());
+ pointData.setSize(reader.getInt());
+
+ lineData.setPosition(reader.getInt());
+ lineData.setSize(reader.getInt());
+
+ polygonData.setPosition(reader.getInt());
+ polygonData.setSize(reader.getInt());
+
+ familyId = reader.getChar();
+ productId = reader.getChar();
+
+ pointIndex.setPosition(reader.getInt());
+ pointIndex.setItemSize(reader.getChar());
+ pointIndex.setSize(reader.getInt());
+
+ lineIndex.setPosition(reader.getInt());
+ lineIndex.setItemSize(reader.getChar());
+ lineIndex.setSize(reader.getInt());
+
+ polygonIndex.setPosition(reader.getInt());
+ polygonIndex.setItemSize(reader.getChar());
+ polygonIndex.setSize(reader.getInt());
+
+ shapeStacking.setPosition(reader.getInt());
+ shapeStacking.setItemSize(reader.getChar());
+ shapeStacking.setSize(reader.getInt());
+ }
+
+ /**
+ * Write the rest of the header. It is guaranteed that the writer will be set
+ * to the correct position before calling.
+ *
+ * This header appears to have a different layout to most other headers.
+ *
+ * @param writer The header is written here.
+ */
+ protected void writeFileHeader(ImgFileWriter writer) {
+ writer.putChar(codePage);
+
+ pointData.writeSectionInfo(writer);
+ lineData.writeSectionInfo(writer);
+ polygonData.writeSectionInfo(writer);
+
+ writer.putChar(familyId);
+ writer.putChar(productId);
+
+ // Can't use Section.writeSectionInfo here as there is an unusual layout.
+ writeSectionInfo(writer, pointIndex);
+ writeSectionInfo(writer, lineIndex);
+ writeSectionInfo(writer, polygonIndex);
+ writeSectionInfo(writer, shapeStacking);
+
+ if (getHeaderLength() > 0x5b) {
+ writeSectionInfo(writer, iconIndex);
+ writer.put((byte) 0x13);
+ iconData.writeSectionInfo(writer);
+ writer.putInt(0);
+ }
+
+ if (getHeaderLength() > 0x6e) {
+ labels.writeSectionInfo(writer);
+
+ // not known, guessing. Different layout to other files.
+ writer.putInt(stringIndex.getItemSize());
+ writer.putInt(0x1b);
+ writer.putInt(stringIndex.getPosition());
+ writer.putInt(stringIndex.getSize());
+
+ writer.putInt(typeIndex.getItemSize());
+ writer.putInt(0x1b);
+ writer.putInt(typeIndex.getPosition());
+ writer.putInt(typeIndex.getSize());
+
+ writer.putChar((char) 0);
+ }
+ }
+
+ /**
+ * There is an unusual layout of the section pointers in the TYP file for the sections
+ * that have an item size.
+ */
+ private void writeSectionInfo(ImgFileWriter writer, Section section) {
+ writer.putInt(section.getPosition());
+ writer.putChar(section.getItemSize());
+ writer.putInt(section.getSize());
+ }
+
+ void setCodePage(char codePage) {
+ this.codePage = codePage;
+ }
+
+ Section getPointData() {
+ return pointData;
+ }
+
+ void setFamilyId(char familyId) {
+ this.familyId = familyId;
+ }
+
+ void setProductId(char productId) {
+ this.productId = productId;
+ }
+
+ Section getPointIndex() {
+ return pointIndex;
+ }
+
+ Section getShapeStacking() {
+ return shapeStacking;
+ }
+
+ public Section getPolygonData() {
+ return polygonData;
+ }
+
+ public Section getPolygonIndex() {
+ return polygonIndex;
+ }
+
+ public Section getLineData() {
+ return lineData;
+ }
+
+ public Section getLineIndex() {
+ return lineIndex;
+ }
+
+ public Section getIconData() {
+ return iconData;
+ }
+
+ public Section getIconIndex() {
+ return iconIndex;
+ }
+
+ public Section getLabels() {
+ return labels;
+ }
+
+ public Section getStringIndex() {
+ return stringIndex;
+ }
+
+ public Section getTypeIndex() {
+ return typeIndex;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/TrueImage.java b/src/uk/me/parabola/imgfmt/app/typ/TrueImage.java
new file mode 100644
index 0000000..bae2b01
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/TrueImage.java
@@ -0,0 +1,118 @@
+/*
+ * 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.imgfmt.app.typ;
+
+import uk.me.parabola.imgfmt.app.BitWriter;
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * A true colour image.
+ *
+ * The image is represented by an array of int, with each int in RGBA format.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TrueImage implements Image {
+ private final ColourInfo colourInfo;
+ private final int[] image;
+
+ // If this is mode 16, then the transparent colour is set.
+ private int transparentPixel;
+
+ public TrueImage(ColourInfo colourInfo, int[] image) {
+ analyzeColours(image, colourInfo);
+ this.colourInfo = colourInfo;
+ this.image = image;
+ }
+
+ /**
+ * Write out the image. It is a set of pixel values that are full RGB values, rather than
+ * table driven as in the other image type. If the colour mode is 32 the colours have an
+ * extra 4 bit opacity value following.
+ *
+ * If the colour mode is 16, then the transparent pixel is written just before the image
+ * itself.
+ */
+ public void write(ImgFileWriter writer) {
+ int width = colourInfo.getWidth();
+ int height = colourInfo.getHeight();
+
+ int mode = colourInfo.getColourMode();
+
+ // For mode 16, the transparent pixel precedes the pixmap data.
+ if (mode == 16) {
+ writer.put((byte) (transparentPixel>>8));
+ writer.put((byte) (transparentPixel>>16));
+ writer.put((byte) (transparentPixel>>24));
+ }
+
+ boolean hasAlpha = mode == 32;
+
+ // Unlike the xpm based images, the true-colour image format does not appear to
+ // have any padding so write as a continuous block.
+ BitWriter bitWriter = new BitWriter();
+ for (int h = 0; h < height; h++) {
+
+ for (int w = 0; w < width; w++) {
+ int col = image[h * width + w];
+
+ bitWriter.putn(col>>8 & 0xff, 8);
+ bitWriter.putn(col>>16 & 0xff, 8);
+ bitWriter.putn(col>>24 & 0xff, 8);
+
+ if (hasAlpha) {
+ int alpha = 0xff - (col & 0xff);
+ alpha = ColourInfo.alphaRound4(alpha);
+ bitWriter.putn(alpha, 4);
+ }
+ }
+ }
+ writer.put(bitWriter.getBytes(), 0, bitWriter.getLength());
+ }
+
+ /**
+ * Analyze the colours and determine if this should be a mode 16 or 32 image.
+ *
+ * By default it will be a mode 0 image. If there is any transparency the appropriate
+ * colour mode will be selected.
+ *
+ * @param image An images as an array of integers. Each integer is a colour in RGBA format.
+ * @param colourInfo The colour mode will be set in this.
+ */
+ private void analyzeColours(int[] image, ColourInfo colourInfo) {
+ boolean hasTransparent = false;
+ boolean hasAlpha = false;
+
+ int nPixels = colourInfo.getWidth() * colourInfo.getHeight();
+ for (int i = 0; i < nPixels; i++) {
+ int col = image[i];
+ int a = col & 0xff;
+ if (a == 0) {
+ // Completely transparent, change all transparent pixels to the same value
+ if (hasTransparent)
+ image[i] = transparentPixel;
+ else
+ transparentPixel = image[i];
+ hasTransparent = true;
+ } else if (a < 255) {
+ // Partially transparent
+ hasAlpha = true;
+ }
+ }
+
+ if (hasAlpha)
+ colourInfo.setColourMode(32);
+ else if (hasTransparent)
+ colourInfo.setColourMode(16);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/TypData.java b/src/uk/me/parabola/imgfmt/app/typ/TypData.java
new file mode 100644
index 0000000..0e4ed18
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/TypData.java
@@ -0,0 +1,115 @@
+/*
+ * 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.imgfmt.app.typ;
+
+import java.nio.charset.CharsetEncoder;
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.srt.Sort;
+
+/**
+ * Holds all the data for a typ file.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TypData {
+ private final ShapeStacking stacking = new ShapeStacking();
+ private final TypParam param = new TypParam();
+ private final List<TypPolygon> polygons = new ArrayList<TypPolygon>();
+ private final List<TypLine> lines = new ArrayList<TypLine>();
+ private final List<TypPoint> points = new ArrayList<TypPoint>();
+ private final List<TypIconSet> icons = new ArrayList<TypIconSet>();
+
+ private Sort sort;
+ private CharsetEncoder encoder;
+
+ public void addPolygonStackOrder(int level, int type, int subtype) {
+ stacking.addPolygon(level, type, subtype);
+ }
+
+ public Sort getSort() {
+ return sort;
+ }
+
+ public void setSort(Sort sort) {
+ if (sort == null)
+ return;
+
+ if (this.sort != null) {
+ int origCodepage = this.sort.getCodepage();
+ if (origCodepage != 0) {
+ if (origCodepage != sort.getCodepage()) {
+ // This is just a warning, not a definite problem
+ System.out.println("WARNING: SortCode in TYP txt file different from" +
+ " command line setting");
+ }
+ }
+ }
+ this.sort = sort;
+ encoder = sort.getCharset().newEncoder();
+ param.setCodePage(sort.getCodepage());
+ }
+
+ public void setFamilyId(int val) {
+ param.setFamilyId(val);
+ }
+
+ public void setProductId(int val) {
+ param.setProductId(val);
+ }
+
+ public ShapeStacking getStacking() {
+ return stacking;
+ }
+
+ public TypParam getParam() {
+ return param;
+ }
+
+ public void addPolygon(TypPolygon polygon) {
+ polygons.add(polygon);
+ }
+
+ public CharsetEncoder getEncoder() {
+ return encoder;
+ }
+
+ public List<TypPolygon> getPolygons() {
+ return polygons;
+ }
+
+ public void addLine(TypLine line) {
+ lines.add(line);
+ }
+
+ public List<TypLine> getLines() {
+ return lines;
+ }
+
+ public void addPoint(TypPoint point) {
+ points.add(point);
+ }
+
+ public List<TypPoint> getPoints() {
+ return points;
+ }
+
+ public void addIcon(TypIconSet current) {
+ icons.add(current);
+ }
+
+ public List<TypIconSet> getIcons() {
+ return icons;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/TypElement.java b/src/uk/me/parabola/imgfmt/app/typ/TypElement.java
new file mode 100644
index 0000000..59bc607
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/TypElement.java
@@ -0,0 +1,208 @@
+/*
+ * 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.imgfmt.app.typ;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetEncoder;
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * Base routines and data used by points, lines and polygons.
+ *
+ * If fact they are all very similar, so there is very little extra in the
+ * subclasses apart from the write routine.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class TypElement implements Comparable<TypElement> {
+ private int type;
+ private int subType;
+
+ protected final List<TypLabel> labels = new ArrayList<TypLabel>();
+
+ protected Xpm xpm;
+
+ protected int fontStyle;
+ protected Rgb dayFontColour;
+ protected Rgb nightFontColour;
+
+ protected int offset;
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ public void setSubType(int subType) {
+ this.subType = subType;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ /**
+ * We sort these by type.
+ * Only the index needs to be sorted (probably) but we don't create the index separately.
+ *
+ * @param o The other object to compare against.
+ * @return The usual -1, 0, 1 for the other object being less than, equal, greater than than this.
+ */
+ public int compareTo(TypElement o) {
+ int t1 = getTypeForFile();
+ int t2 = o.getTypeForFile();
+ if (t1 == t2)
+ return 0;
+ else if (t1 < t2)
+ return -1;
+ else
+ return 1;
+ }
+
+ /**
+ * Get the type in the format required for writing in the typ file sections.
+ */
+ public int getTypeForFile() {
+ return (type << 5) | (subType & 0x1f);
+ }
+
+ public void addLabel(String text) {
+ labels.add(new TypLabel(text));
+ }
+
+ public void setXpm(Xpm xpm) {
+ this.xpm = xpm;
+ }
+
+ public void setFontStyle(int font) {
+ this.fontStyle = font;
+ }
+
+ public void setDayFontColor(String value) {
+ dayFontColour = new Rgb(value);
+ }
+
+ public void setNightCustomColor(String value) {
+ nightFontColour = new Rgb(value);
+ }
+
+ public abstract void write(ImgFileWriter writer, CharsetEncoder encoder);
+
+ public int getOffset() {
+ return offset;
+ }
+
+ /**
+ * Does this element have two colour bitmaps, with possible automatic night colours. For lines and polygons.
+ *
+ * Overridden for points and icons.
+ */
+ public boolean simpleBitmap() {
+ return true;
+ }
+
+ /**
+ * Make the label block separately as we need its length before we write it out properly.
+ *
+ * @param encoder For encoding the strings as bytes.
+ * @return A byte buffer with position set to the length of the block.
+ */
+ protected ByteBuffer makeLabelBlock(CharsetEncoder encoder) {
+ ByteBuffer out = ByteBuffer.allocate(256 * labels.size());
+ for (TypLabel tl : labels) {
+ out.put((byte) tl.getLang());
+ CharBuffer cb = CharBuffer.wrap(tl.getText());
+ try {
+ ByteBuffer buffer = encoder.encode(cb);
+ out.put(buffer);
+ } catch (CharacterCodingException ignore) {
+ String name = encoder.charset().name();
+ //System.out.println("cs " + name);
+ throw new TypLabelException(name);
+ }
+ out.put((byte) 0);
+ }
+
+ return out;
+ }
+
+ /**
+ * Write the label block, this is the same for all element types.
+ * @param encoder To properly encode the labels.
+ */
+ protected void writeLabelBlock(ImgFileWriter writer, CharsetEncoder encoder) {
+ ByteBuffer out = makeLabelBlock(encoder);
+
+ int len = out.position();
+
+ // The length is encoded as a variable length integer with the length indicated by a suffix.
+ len = (len << 1) + 1;
+ int mask = ~0xff;
+ while ((len & mask) != 0) {
+ mask <<= 8;
+ len <<= 1;
+ }
+
+ // write out the length, I'm assuming that it will be 1 or 2 bytes
+ if (len > 0xff)
+ writer.putChar((char) len);
+ else
+ writer.put((byte) len);
+
+ // Prepare and write buffer
+ out.flip();
+ writer.put(out);
+ }
+
+ /**
+ * Write out extended font information, colour and size.
+ *
+ * This is the same for each element type.
+ */
+ protected void writeExtendedFontInfo(ImgFileWriter writer) {
+ byte fontExt = (byte) fontStyle;
+ if (dayFontColour != null)
+ fontExt |= 0x8;
+
+ if (nightFontColour != null)
+ fontExt |= 0x10;
+
+ writer.put(fontExt);
+
+ if (dayFontColour != null)
+ dayFontColour.write(writer, (byte) 0x10);
+
+ if (nightFontColour != null)
+ nightFontColour.write(writer, (byte) 0x10);
+ }
+
+ /**
+ * Write out an image. The width and height are written separately, because they are not
+ * repeated for the night image.
+ *
+ * @param xpm Either the day or night XPM.
+ */
+ protected void writeImage(ImgFileWriter writer, Xpm xpm) {
+ ColourInfo colourInfo = xpm.getColourInfo();
+
+ writer.put((byte) colourInfo.getNumberOfSColoursForCM());
+ writer.put((byte) colourInfo.getColourMode());
+
+ colourInfo.write(writer);
+ xpm.writeImage(writer);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/TypIconSet.java b/src/uk/me/parabola/imgfmt/app/typ/TypIconSet.java
new file mode 100644
index 0000000..c97b9e0
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/TypIconSet.java
@@ -0,0 +1,75 @@
+/*
+ * 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.imgfmt.app.typ;
+
+import java.nio.charset.CharsetEncoder;
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * The new multiple icon format.
+ * There can be several icons at different resolutions.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TypIconSet extends TypElement {
+ private final List<Xpm> icons = new ArrayList<Xpm>();
+
+ public void write(ImgFileWriter writer, CharsetEncoder encoder) {
+ offset = writer.position();
+
+ // Start with the number of icons
+ writer.put((byte) icons.size());
+
+ for (Xpm xpm : icons) {
+ ColourInfo colourInfo = xpm.getColourInfo();
+ int nbits = calcBits(colourInfo);
+ writer.putChar((char) (nbits/2));
+ writer.put((byte) 1);
+ writer.put((byte) colourInfo.getWidth());
+ writer.put((byte) colourInfo.getHeight());
+ writeImage(writer, xpm);
+ }
+ }
+
+ private int calcBits(ColourInfo colourInfo) {
+ int bits = 0;
+ int bpp = colourInfo.getBitsPerPixel();
+
+ bits += colourInfo.getWidth() * colourInfo.getHeight() * bpp;
+ bits += colourInfo.getNumberOfSColoursForCM() * 3 * 8;
+ if (colourInfo.getNumberOfColours() == 0 && colourInfo.getColourMode() == 0x10)
+ bits += 3*8;
+ bits += 0x2c;
+ return bits;
+ }
+
+ public void addIcon(Xpm xpm) {
+ icons.add(xpm);
+ }
+
+ public String getLabel() {
+ if (labels.isEmpty())
+ return null;
+ return labels.get(0).getText();
+ }
+
+ /**
+ * Icon sets can have full colour pixmaps.
+ */
+ public boolean simpleBitmap() {
+ return false;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/TypLabel.java b/src/uk/me/parabola/imgfmt/app/typ/TypLabel.java
new file mode 100644
index 0000000..6ea3f52
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/TypLabel.java
@@ -0,0 +1,49 @@
+/*
+ * 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.imgfmt.app.typ;
+
+/**
+ * @author Steve Ratcliffe
+ */
+public class TypLabel {
+ private final int lang;
+ private final String text;
+
+ public TypLabel(String in) {
+ String[] split = in.split(",", 2);
+ int l;
+ String s;
+ try {
+ l = Integer.decode(split[0]);
+ s = split[1];
+ } catch (NumberFormatException e) {
+ l = 0;
+ s = in;
+ }
+ this.lang = l;
+ this.text = s;
+ }
+
+ public TypLabel(int lang, String text) {
+ this.lang = lang;
+ this.text = text;
+ }
+
+ public int getLang() {
+ return lang;
+ }
+
+ public String getText() {
+ return text;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/TypLabelException.java b/src/uk/me/parabola/imgfmt/app/typ/TypLabelException.java
new file mode 100644
index 0000000..f1952b1
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/TypLabelException.java
@@ -0,0 +1,31 @@
+/*
+ * 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.imgfmt.app.typ;
+
+/**
+ * Used when a label cannot be converted. An error is thrown indicating a charset to try
+ * instead of the default system one.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TypLabelException extends RuntimeException {
+ private String charsetName;
+
+ public TypLabelException(String charsetName) {
+ this.charsetName = charsetName;
+ }
+
+ public String getCharsetName() {
+ return charsetName;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/TypLine.java b/src/uk/me/parabola/imgfmt/app/typ/TypLine.java
new file mode 100644
index 0000000..94c12f3
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/TypLine.java
@@ -0,0 +1,104 @@
+/*
+ * 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.imgfmt.app.typ;
+
+import java.nio.charset.CharsetEncoder;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * A line as read from a typ.txt file.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TypLine extends TypElement {
+ private static final int F_LABEL = 0x1;
+ private static final int F_USE_ROTATION = 0x2;
+ private static final int F_EXTENDED = 0x4;
+
+ private boolean useOrientation;
+ private byte lineWidth;
+ private byte borderWidth;
+
+ /**
+ * This is slightly different to the polygon case, but not much.
+ *
+ * The line width is held in the first byte along with the type.
+ * The colour scheme does not have a bit to say if a bitmap is used,
+ * as you can always have one.
+ *
+ * There is a border width that can be specified.
+ *
+ * @param encoder For the labels.
+ */
+ public void write(ImgFileWriter writer, CharsetEncoder encoder) {
+ offset = writer.position();
+
+ byte flags = 0;
+
+ if (!labels.isEmpty())
+ flags |= F_LABEL;
+ if (fontStyle != 0 || dayFontColour != null)
+ flags |= F_EXTENDED;
+ if (!useOrientation)
+ flags |= F_USE_ROTATION;
+
+ int height = 0;
+ if (xpm.hasImage())
+ height = xpm.getColourInfo().getHeight();
+
+ ColourInfo colourInfo = xpm.getColourInfo();
+ int scheme = colourInfo.getColourScheme() & 0x7;
+
+ writer.put((byte) ((scheme & 0x7) | (height << 3)));
+ writer.put(flags);
+
+ colourInfo.write(writer);
+ if (xpm.hasImage())
+ xpm.writeImage(writer);
+
+ if (height == 0) {
+ writer.put(lineWidth);
+ if ((scheme&~1) != 6)
+ writer.put((byte) (lineWidth + 2*borderWidth));
+ }
+
+ // The labels have a length byte to show the number of bytes following. There is
+ // also a flag in the length. The strings have a language number proceeding them.
+ // The strings themselves are null terminated.
+ if ((flags & F_LABEL) != 0)
+ writeLabelBlock(writer, encoder);
+
+ // The extension section hold font style and colour information for the labels.
+ if ((flags & F_EXTENDED) != 0)
+ writeExtendedFontInfo(writer);
+
+ }
+
+ public void setUseOrientation(boolean useOrientation) {
+ this.useOrientation = useOrientation;
+ }
+
+ public void setLineWidth(int val) {
+ lineWidth = (byte) val;
+ }
+
+ public void setBorderWidth(int borderWidth) {
+ this.borderWidth = (byte) borderWidth;
+ }
+
+ public void finish() {
+ if (borderWidth != 0)
+ xpm.getColourInfo().setHasBorder(true);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/TypParam.java b/src/uk/me/parabola/imgfmt/app/typ/TypParam.java
new file mode 100644
index 0000000..36ceee3
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/TypParam.java
@@ -0,0 +1,48 @@
+/*
+ * 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.imgfmt.app.typ;
+
+/**
+ * General TYP file parameters.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TypParam {
+ private int familyId;
+ private int productId;
+ private int codePage;
+
+ public int getFamilyId() {
+ return familyId;
+ }
+
+ public void setFamilyId(int familyId) {
+ this.familyId = familyId;
+ }
+
+ public int getProductId() {
+ return productId;
+ }
+
+ public void setProductId(int productId) {
+ this.productId = productId;
+ }
+
+ public int getCodePage() {
+ return codePage;
+ }
+
+ public void setCodePage(int codePage) {
+ this.codePage = codePage;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/TypPoint.java b/src/uk/me/parabola/imgfmt/app/typ/TypPoint.java
new file mode 100644
index 0000000..b907093
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/TypPoint.java
@@ -0,0 +1,75 @@
+/*
+ * 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.imgfmt.app.typ;
+
+import java.nio.charset.CharsetEncoder;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * Represents a POI in the typ file.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TypPoint extends TypElement {
+ private Xpm nightXpm;
+ private static final byte F_BITMAP = 0x1;
+ private static final byte F_NIGHT_XPM = 0x2;
+ private static final byte F_LABEL = 0x4;
+ private static final byte F_EXTENDED_FONT = 0x8;
+
+ public void write(ImgFileWriter writer, CharsetEncoder encoder) {
+ offset = writer.position();
+
+ byte flags = F_BITMAP;
+
+ if (nightXpm != null)
+ flags |= F_NIGHT_XPM;
+
+ if (!labels.isEmpty())
+ flags |= F_LABEL;
+
+ if (fontStyle != 0 || dayFontColour != null || nightFontColour != null)
+ flags |= F_EXTENDED_FONT;
+
+ writer.put(flags);
+
+ // Width and height is the same for day and night images, so it is written once only.
+ ColourInfo colourInfo = xpm.getColourInfo();
+ writer.put((byte) colourInfo.getWidth());
+ writer.put((byte) colourInfo.getHeight());
+
+ // Day or only image
+ writeImage(writer, xpm);
+
+ if ((flags & F_NIGHT_XPM) != 0)
+ writeImage(writer, nightXpm);
+
+ if ((flags & F_LABEL) != 0)
+ writeLabelBlock(writer, encoder);
+
+ if ((flags & F_EXTENDED_FONT) != 0)
+ writeExtendedFontInfo(writer);
+ }
+
+ public void setNightXpm(Xpm nightXpm) {
+ this.nightXpm = nightXpm;
+ }
+
+ /**
+ * Points have full pixmaps with multiple colours, including 24 full colour images.
+ */
+ public boolean simpleBitmap() {
+ return false;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/TypPolygon.java b/src/uk/me/parabola/imgfmt/app/typ/TypPolygon.java
new file mode 100644
index 0000000..c931714
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/TypPolygon.java
@@ -0,0 +1,56 @@
+/*
+ * 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.imgfmt.app.typ;
+
+import java.nio.charset.CharsetEncoder;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * Holds the data for a polygon style.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TypPolygon extends TypElement {
+
+ private static final int F_LABEL = 0x10;
+ private static final int F_EXTENDED = 0x20;
+
+ public void write(ImgFileWriter writer, CharsetEncoder encoder) {
+ offset = writer.position();
+
+ ColourInfo colourInfo = xpm.getColourInfo();
+ int scheme = colourInfo.getColourScheme();
+ if (!labels.isEmpty())
+ scheme |= F_LABEL;
+ if (fontStyle != 0 || dayFontColour != null)
+ scheme |= F_EXTENDED;
+
+ writer.put((byte) scheme);
+
+ colourInfo.write(writer);
+ if (xpm.hasImage())
+ xpm.writeImage(writer);
+
+ // The labels have a length byte to show the number of bytes following. There is
+ // also a flag in the length. The strings have a language number proceeding them.
+ // The strings themselves are null terminated.
+ if ((scheme & F_LABEL) != 0)
+ writeLabelBlock(writer, encoder);
+
+ // The extension section hold font style and colour information for the labels.
+ if ((scheme & F_EXTENDED) != 0) {
+ writeExtendedFontInfo(writer);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/Xpm.java b/src/uk/me/parabola/imgfmt/app/typ/Xpm.java
new file mode 100644
index 0000000..d529112
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/Xpm.java
@@ -0,0 +1,45 @@
+/*
+ * 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.imgfmt.app.typ;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * Holds everything read from an XPM value in the typ txt file.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Xpm {
+ private ColourInfo colourInfo;
+ private Image image;
+
+ public ColourInfo getColourInfo() {
+ return colourInfo;
+ }
+
+ public void setColourInfo(ColourInfo colourInfo) {
+ this.colourInfo = colourInfo;
+ }
+
+ public void setImage(Image image) {
+ this.image = image;
+ }
+
+ public boolean hasImage() {
+ return image != null;
+ }
+
+ public void writeImage(ImgFileWriter writer) {
+ image.write(writer);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/app/typ/package.html b/src/uk/me/parabola/imgfmt/app/typ/package.html
new file mode 100644
index 0000000..1efbf38
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/typ/package.html
@@ -0,0 +1,5 @@
+<body><h3>The TYP file for custom rendering styles</h3>
+<p>This file contains definitions of how a map element will be rendered
+on the GPS which allows you to display things in a different way.
+Not all devices support the TYP file however.</p>
+</body>
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/fs/DirectoryEntry.java b/src/uk/me/parabola/imgfmt/fs/DirectoryEntry.java
new file mode 100644
index 0000000..7a8df63
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/fs/DirectoryEntry.java
@@ -0,0 +1,61 @@
+/*
+ * 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: 02-Dec-2006
+ */
+package uk.me.parabola.imgfmt.fs;
+
+/**
+ * Interface used for directory entries used to represent <i>files</i>.
+ * A directory entry has the file name, its extension (its a 8+3 filename)
+ * and the size of the file.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface DirectoryEntry {
+ public static final int ENTRY_SIZE = 512;
+ public static final int SLOTS_PER_ENTRY = 240;
+
+ /**
+ * Get the file name.
+ * @return The file name.
+ */
+ public String getName();
+
+ /**
+ * Get the file extension.
+ * @return The file extension.
+ */
+ public String getExt();
+
+ /**
+ * Get the full name. That is name + extension.
+ *
+ * @return The full name as NAME.EXT
+ */
+ public String getFullName();
+
+ /**
+ * Get the file size.
+ * @return The size of the file in bytes.
+ */
+ public int getSize();
+
+ /**
+ * If this is a special 'hidden' file. True for the all-spaces 'file'.
+ *
+ * @return True if this is not a regular file.
+ */
+ public boolean isSpecial();
+}
diff --git a/src/uk/me/parabola/imgfmt/fs/FileSystem.java b/src/uk/me/parabola/imgfmt/fs/FileSystem.java
new file mode 100644
index 0000000..5a9145c
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/fs/FileSystem.java
@@ -0,0 +1,101 @@
+/*
+ * 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: 26-Nov-2006
+ */
+package uk.me.parabola.imgfmt.fs;
+
+import java.io.Closeable;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.FileExistsException;
+import uk.me.parabola.imgfmt.FileSystemParam;
+
+
+/**
+ * File system operations.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface FileSystem extends Closeable {
+
+ /**
+ * Create a new file it must not already exist.
+ * @param name The file name.
+ * @return A directory entry for the new file.
+ * @throws FileExistsException If the file already exists.
+ */
+ public ImgChannel create(String name) throws FileExistsException;
+
+ /**
+ * Open a file. The returned file object can be used to read and write the
+ * underlying file.
+ *
+ * @param name The file name to open.
+ * @param mode Either "r" for read access, "w" for write access or "rw"
+ * for both read and write.
+ * @return A file descriptor.
+ * @throws FileNotFoundException When the file does not exist.
+ */
+ public ImgChannel open(String name, String mode)
+ throws FileNotFoundException;
+
+ /**
+ * Lookup the file and return a directory entry for it.
+ *
+ * @param name The filename to look up.
+ * @return A directory entry.
+ * @throws IOException If an error occurs reading the directory.
+ */
+ public DirectoryEntry lookup(String name) throws IOException;
+
+ /**
+ * List all the files in the directory.
+ * @return A List of directory entries.
+ */
+ public List<DirectoryEntry> list() ;
+
+ /**
+ * Get the filesystem / archive parameters. Things that are stored in
+ * the header.
+ *
+ * @return The filesystem parameters.
+ */
+ public FileSystemParam fsparam();
+
+ /**
+ * Reconfigure the filesystem with the given parameters.
+ * Only some parameters can be changed and the may only be changeable
+ * at certain points in the construction of a file system for example.
+ * @param param The new parameters.
+ * @throws IllegalStateException If the changes cannot be made (for example
+ * if the file system is already written).
+ */
+ public void fsparam(FileSystemParam param);
+
+ /**
+ * Sync with the underlying file. All unwritten data is written out to
+ * the underlying file.
+ * @throws IOException If an error occurs during the write.
+ */
+ public void sync() throws IOException;
+
+ /**
+ * Close the filesystem. Any saved data is flushed out. It is better
+ * to explicitly sync the data out first, to be sure that it has worked.
+ */
+ void close();
+}
diff --git a/src/uk/me/parabola/imgfmt/fs/ImgChannel.java b/src/uk/me/parabola/imgfmt/fs/ImgChannel.java
new file mode 100644
index 0000000..7bdfb76
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/fs/ImgChannel.java
@@ -0,0 +1,45 @@
+/*
+ * 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: 02-Dec-2006
+ */
+package uk.me.parabola.imgfmt.fs;
+
+import java.nio.channels.ByteChannel;
+
+/**
+ * An extension of ByteChannel that allows us to know the position. It may
+ * evolve to have several of the methods of the FileChannel class and plays
+ * a similar role.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface ImgChannel extends ByteChannel {
+
+ /**
+ * Get the file position. Note that this is a logical position relative
+ * to the beginning of the file (the file within the .img file, not the
+ * beginning of the .img file itself).
+ *
+ * @return The offset in bytes from the beginning of the file.
+ */
+ public long position();
+
+ /**
+ * Set the position within the file.
+ *
+ * @param pos The position to set.
+ */
+ public void position(long pos);
+}
diff --git a/src/uk/me/parabola/imgfmt/fs/package.html b/src/uk/me/parabola/imgfmt/fs/package.html
new file mode 100644
index 0000000..89eebe5
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/fs/package.html
@@ -0,0 +1,10 @@
+<body>
+<h3>Interfaces for accessing the filesystem</h3>
+These are the way that application code should access the
+filesystem parts of the code.
+<p>The main interface is {@link uk.me.parabola.imgfmt.fs.FileSystem} which contains
+all the operations that can be performed on the system.</p>
+
+<h3>See also</h3>
+The <a href="http://garmin-img.sf.net">Garmin img project</a>
+</body>
diff --git a/src/uk/me/parabola/imgfmt/mdxfmt/MapInfo.java b/src/uk/me/parabola/imgfmt/mdxfmt/MapInfo.java
new file mode 100644
index 0000000..1bc3260
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/mdxfmt/MapInfo.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.mdxfmt;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Represents an individual file in the MDX file.
+ *
+ * I don't really understand the difference between what I call hex mapname
+ * and mapname. We shall always make them equal.
+ *
+ * There is no good reason to call it 'hexMapname' its just a name that stuck
+ * I still don't know what the difference is. We always make them the same
+ * but they can differ.
+ */
+public class MapInfo {
+ private int hexMapname;
+ private int mapname;
+ private char familyId;
+ private char productId;
+
+ private String filename;
+
+ void write(ByteBuffer os) {
+ os.putInt(hexMapname);
+ os.putChar(productId);
+ os.putChar(familyId);
+ os.putInt(mapname);
+ }
+
+ public int getHexMapname() {
+ return hexMapname;
+ }
+
+ public void setHexMapname(int hexMapname) {
+ this.hexMapname = hexMapname;
+ }
+
+ public void setMapname(int mapname) {
+ this.mapname = mapname;
+ }
+
+ public void setFamilyId(char familyId) {
+ this.familyId = familyId;
+ }
+
+ public void setProductId(char productId) {
+ this.productId = productId;
+ }
+
+ public int getMapname() {
+ return mapname;
+ }
+
+ public String getFilename() {
+ return filename;
+ }
+
+ public void setFilename(String filename) {
+ this.filename = filename;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/mdxfmt/MdxFile.java b/src/uk/me/parabola/imgfmt/mdxfmt/MdxFile.java
new file mode 100644
index 0000000..666c9b3
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/mdxfmt/MdxFile.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.mdxfmt;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * The MDX index file. Used with the global index. This is located
+ * at the family level in the windows registry and can perhaps index
+ * across different products (and maybe families), although such a thing
+ * hasn't been seen.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MdxFile {
+ private final char familyId;
+ private final char productId;
+
+ private final List<MapInfo> maps = new ArrayList<MapInfo>();
+
+ /**
+ * Create with default family and product ids.
+ * @param familyId The default family id that will be used if no other one
+ * is supplied.
+ * @param productId The default product id for the maps indexed by this
+ * file.
+ */
+ public MdxFile(int familyId, int productId) {
+ this.familyId = (char) familyId;
+ this.productId = (char) productId;
+ }
+
+ /**
+ * Add a map with the default family and product id's and with equal
+ * name and hex name.
+ * @param name The map name (from the filename of the map) as an integer.
+ * @param hexname The map id that is inside the TRE header
+ * @param filename The file name of the map being added. Mainly for diagnostics,
+ * it is not needed for the file.
+ */
+ public void addMap(int name, int hexname, String filename) {
+ MapInfo info = new MapInfo();
+ info.setHexMapname(hexname);
+ info.setMapname(name);
+ info.setFamilyId(familyId);
+ info.setProductId(productId);
+ info.setFilename(filename);
+
+ maps.add(info);
+ }
+
+ /**
+ * Write the file out to the given filename.
+ */
+ public void write(String filename) throws IOException {
+ FileOutputStream stream = new FileOutputStream(filename);
+ FileChannel chan = stream.getChannel();
+ ByteBuffer buf = ByteBuffer.allocate(1024);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+
+ try {
+ writeHeader(chan, buf);
+ writeBody(chan, buf);
+ } finally {
+ chan.close();
+ }
+ }
+
+ private void writeHeader(WritableByteChannel chan, ByteBuffer buf) throws IOException {
+ try {
+ buf.put("Midx".getBytes("ascii"));
+ } catch (UnsupportedEncodingException e) {
+ throw new IOException("Could not write header");
+ }
+ buf.putChar((char) 100);
+ buf.putInt(12);
+ buf.putInt(maps.size());
+
+ buf.flip();
+ chan.write(buf);
+ }
+
+ private void writeBody(WritableByteChannel chan, ByteBuffer buf) throws IOException {
+ // Sort the maps by the hex number.
+ Collections.sort(maps, new Comparator<MapInfo>() {
+ public int compare(MapInfo o1, MapInfo o2) {
+ if (o1.getHexMapname() == o2.getHexMapname())
+ return 0;
+ else if (o1.getHexMapname() < o2.getHexMapname())
+ return -1;
+ else
+ return 1;
+ }
+ });
+
+ for (MapInfo info : maps) {
+ // Although its not necessarily wrong for them to be zero, it probably
+ // sign that something is wrong.
+ if (info.getHexMapname() == 0 || info.getMapname() == 0)
+ System.err.println("Invalid mapname for " + info.getFilename() + ", perhaps it is not a .img file");
+
+ buf.compact();
+ info.write(buf);
+
+ buf.flip();
+ chan.write(buf);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/mdxfmt/MdxFileReader.java b/src/uk/me/parabola/imgfmt/mdxfmt/MdxFileReader.java
new file mode 100644
index 0000000..445b135
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/mdxfmt/MdxFileReader.java
@@ -0,0 +1,62 @@
+/*
+ * 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.imgfmt.mdxfmt;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.BufferedImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgFileReader;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+
+
+/**
+ * For reading the MDX file.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MdxFileReader {
+ private final ImgFileReader reader;
+ private int numberOfMaps;
+
+ private final List<MapInfo> maps = new ArrayList<MapInfo>();
+
+ public MdxFileReader(ImgChannel chan) {
+ this.reader = new BufferedImgFileReader(chan);
+
+ readHeader();
+ readMaps();
+ }
+
+ private void readMaps() {
+ for (int i = 0; i < numberOfMaps; i++) {
+ MapInfo info = new MapInfo();
+ info.setHexMapname(reader.getInt());
+ info.setProductId(reader.getChar());
+ info.setFamilyId(reader.getChar());
+ info.setMapname(reader.getInt());
+ maps.add(info);
+ }
+ }
+
+ private void readHeader() {
+ reader.getInt();
+ reader.getChar();
+ reader.getInt();
+ numberOfMaps = reader.getInt();
+ }
+
+ public List<MapInfo> getMaps() {
+ return maps;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/mps/Block.java b/src/uk/me/parabola/imgfmt/mps/Block.java
new file mode 100644
index 0000000..f089692
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/mps/Block.java
@@ -0,0 +1,78 @@
+/*
+ * 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: Dec 19, 2007
+ */
+package uk.me.parabola.imgfmt.mps;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.io.StructuredOutputStream;
+
+/**
+ * All the blocks in the file have a type and a length.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class Block {
+ private final int type;
+ private final ByteArrayOutputStream output = new ByteArrayOutputStream();
+
+ protected Block(int type) {
+ this.type = type;
+ }
+
+ public void write(ImgChannel chan) throws IOException {
+ // First write the body to the byte buffer so that we know its length.
+ writeBody(new StructuredOutputStream(output));
+
+ ByteBuffer buf = ByteBuffer.allocate(16);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ buf.put((byte) type);
+ char len = getLength();
+ buf.putChar(len);
+
+ // write the header.
+ buf.flip();
+ chan.write(buf);
+
+ // write the body.
+ buf = ByteBuffer.allocate(len);
+ buf.put(output.toByteArray());
+ buf.flip();
+ chan.write(buf);
+ }
+
+ /**
+ * Writes the body to the output stream given.
+ *
+ * @param out The stream to write to.
+ */
+ protected abstract void writeBody(StructuredOutputStream out) throws IOException;
+
+ /**
+ * This is only valid after everything is written to the block.
+ *
+ * @return The length of the block (or the amount written already).
+ */
+ private char getLength() {
+ int len = output.toByteArray().length;
+ assert len <= 0xffff;
+ return (char) len;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/mps/MapBlock.java b/src/uk/me/parabola/imgfmt/mps/MapBlock.java
new file mode 100644
index 0000000..296736d
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/mps/MapBlock.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2007,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.imgfmt.mps;
+
+import java.io.IOException;
+
+import uk.me.parabola.io.StructuredOutputStream;
+
+/**
+ * A block describing an individual map.
+ *
+ * The family id, product id, series name, area name and map description can
+ * be set per map.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MapBlock extends Block {
+ private static final int BLOCK_TYPE = 0x4c;
+
+ private int familyId;
+ private int productId;
+
+ private int mapNumber;
+ private int hexNumber;
+ private String seriesName;
+ private String mapDescription;
+ private String areaName;
+
+ public MapBlock() {
+ super(BLOCK_TYPE);
+ }
+
+ protected void writeBody(StructuredOutputStream out) throws IOException {
+ out.write2(productId);
+ out.write2(familyId);
+ out.write4(mapNumber);
+ out.writeString(seriesName);
+ out.writeString(mapDescription);
+ out.writeString(areaName);
+ out.write4(hexNumber);
+ out.write4(0);
+ }
+
+ public void setIds(int familyId, int productId) {
+ this.familyId = familyId;
+ this.productId = productId;
+ }
+
+ public void setSeriesName(String seriesName) {
+ this.seriesName = seriesName;
+ }
+
+ public void setMapNumber(int mapNumber) {
+ this.mapNumber = mapNumber;
+ }
+
+ public void setHexNumber(int hexNumber) {
+ this.hexNumber = hexNumber;
+ }
+
+ public void setMapDescription(String mapDescription) {
+ this.mapDescription = mapDescription;
+ }
+
+ public void setAreaName(String areaName) {
+ this.areaName = areaName;
+ }
+
+ public int getFamilyId() {
+ return familyId;
+ }
+
+ public int getProductId() {
+ return productId;
+ }
+
+ public int getMapNumber() {
+ return mapNumber;
+ }
+
+ public int getHexNumber() {
+ return hexNumber;
+ }
+
+ public String getSeriesName() {
+ return seriesName;
+ }
+
+ public String getMapDescription() {
+ return mapDescription;
+ }
+
+ public String getAreaName() {
+ return areaName;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/mps/MapsetBlock.java b/src/uk/me/parabola/imgfmt/mps/MapsetBlock.java
new file mode 100644
index 0000000..d69736c
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/mps/MapsetBlock.java
@@ -0,0 +1,46 @@
+/*
+ * 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: Dec 19, 2007
+ */
+package uk.me.parabola.imgfmt.mps;
+
+import uk.me.parabola.io.StructuredOutputStream;
+
+import java.io.IOException;
+
+/**
+ * Block describing the map set.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MapsetBlock extends Block {
+ private static final int BLOCK_TYPE = 0x56;
+
+ private String name = "OSM map set";
+
+ public MapsetBlock() {
+ super(BLOCK_TYPE);
+ }
+
+ protected void writeBody(StructuredOutputStream out) throws IOException {
+ out.writeString(name);
+ out.write(0); // unknown
+ }
+
+ public void setName(String name) {
+ if (name != null)
+ this.name = name;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/mps/MpsFile.java b/src/uk/me/parabola/imgfmt/mps/MpsFile.java
new file mode 100644
index 0000000..9b6b9ca
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/mps/MpsFile.java
@@ -0,0 +1,75 @@
+/*
+ * 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: Dec 19, 2007
+ */
+package uk.me.parabola.imgfmt.mps;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+
+/**
+ * This file is a description of the map set that is loaded into the
+ * gmapsupp.img file and an index of the maps that it contains.
+ *
+ * It is different than all the other files that fit inside the gmapsupp file
+ * in that it doesn't contain the common header. So it does not extend ImgFile.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MpsFile {
+ private String mapsetName = "OSM map set";
+
+ private final Set<ProductBlock> products = new HashSet<ProductBlock>();
+ private final List<MapBlock> maps = new ArrayList<MapBlock>();
+
+ private final ImgChannel chan;
+
+ public MpsFile(ImgChannel chan) {
+ this.chan = chan;
+ }
+
+ public void sync() throws IOException {
+ for (MapBlock map : maps)
+ map.write(chan);
+
+ for (ProductBlock block : products)
+ block.write(chan);
+
+ MapsetBlock mapset = new MapsetBlock();
+ mapset.setName(mapsetName);
+ mapset.write(chan);
+ }
+
+ public void addMap(MapBlock map) {
+ maps.add(map);
+ }
+
+ public void addProduct(ProductBlock pb) {
+ products.add(pb);
+ }
+
+ public void setMapsetName(String mapsetName) {
+ this.mapsetName = mapsetName;
+ }
+
+ public void close() throws IOException {
+ chan.close();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/mps/MpsFileReader.java b/src/uk/me/parabola/imgfmt/mps/MpsFileReader.java
new file mode 100644
index 0000000..bfc8c8f
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/mps/MpsFileReader.java
@@ -0,0 +1,104 @@
+/*
+ * 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: Dec 19, 2007
+ */
+package uk.me.parabola.imgfmt.mps;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.BufferedImgFileReader;
+import uk.me.parabola.imgfmt.app.ImgFileReader;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+
+/**
+ * This file is a description of the map set that is loaded into the
+ * gmapsupp.img file and an index of the maps that it contains.
+ *
+ * It is different than all the other files that fit inside the gmapsupp file
+ * in that it doesn't contain the common header. So it does not extend ImgFile.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MpsFileReader implements Closeable {
+
+ private final List<MapBlock> maps = new ArrayList<MapBlock>();
+ private final List<ProductBlock> products = new ArrayList<ProductBlock>();
+
+ private final ImgChannel chan;
+ private final ImgFileReader reader;
+
+ public MpsFileReader(ImgChannel chan) {
+ this.chan = chan;
+ this.reader = new BufferedImgFileReader(chan);
+
+ readBlocks();
+ }
+
+ private void readBlocks() {
+ byte type;
+ while ((type = reader.get()) > 0) {
+ int len = reader.getChar();
+
+ switch (type) {
+ case 0x4c:
+ readMapBlock();
+ break;
+ case 0x46:
+ readProductBlock();
+ break;
+ default:
+ // We always know the length, so just read over it
+ reader.get(len);
+ break;
+ }
+ }
+ }
+
+ private void readMapBlock() {
+ MapBlock block = new MapBlock();
+ int val = reader.getInt();
+ block.setIds(val >>> 16, val & 0xffff);
+ block.setMapNumber(reader.getInt());
+ block.setSeriesName(reader.getZString());
+ block.setMapDescription(reader.getZString());
+ block.setAreaName(reader.getZString());
+ block.setHexNumber(reader.getInt());
+ reader.getInt();
+ maps.add(block);
+ }
+
+ private void readProductBlock() {
+ ProductBlock block = new ProductBlock();
+ block.setProductId(reader.getChar());
+ block.setFamilyId(reader.getChar());
+ block.setDescription(reader.getZString());
+ products.add(block);
+ }
+
+ public List<MapBlock> getMaps() {
+ return maps;
+ }
+
+ public List<ProductBlock> getProducts() {
+ return products;
+ }
+
+ public void close() throws IOException {
+ chan.close();
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/mps/ProductBlock.java b/src/uk/me/parabola/imgfmt/mps/ProductBlock.java
new file mode 100644
index 0000000..e672f46
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/mps/ProductBlock.java
@@ -0,0 +1,87 @@
+/*
+ * 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: Dec 19, 2007
+ */
+package uk.me.parabola.imgfmt.mps;
+
+import java.io.IOException;
+
+import uk.me.parabola.io.StructuredOutputStream;
+
+/**
+ * A block describing a particular product. Not sure how this relates
+ * to the map set.
+ *
+ * @author Steve Ratcliffe
+ */
+public class ProductBlock extends Block {
+ private static final int BLOCK_TYPE = 0x46;
+
+ private int familyId;
+ private int productId;
+ private String description = "OSM maps";
+
+ public ProductBlock() {
+ super(BLOCK_TYPE);
+ }
+
+ protected void writeBody(StructuredOutputStream out) throws IOException {
+ out.write2(productId);
+ out.write2(familyId);
+ out.writeString(description);
+ }
+
+ public void setFamilyId(int familyId) {
+ this.familyId = familyId;
+ }
+
+ public int getFamilyId() {
+ return familyId;
+ }
+
+ public void setProductId(int productId) {
+ this.productId = productId;
+ }
+
+ public int getProductId() {
+ return productId;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ProductBlock that = (ProductBlock) o;
+
+ if (familyId != that.familyId) return false;
+ if (productId != that.productId) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result = familyId;
+ result = 31 * result + productId;
+ return result;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/mps/package.html b/src/uk/me/parabola/imgfmt/mps/package.html
new file mode 100644
index 0000000..961015f
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/mps/package.html
@@ -0,0 +1,21 @@
+<body>
+<h3>The MPS file</h3>
+
+<p>This file is similar to the TDB file in that it is a list of maps along with
+ other information describing the set. It is inserted into the gmapsupp.img
+ file.
+
+<p>A map will work without this file, but it is essential when you have maps from different
+ families loaded together as it allows you to see the names of the map
+ families and turn them on and off separately.
+
+<p>It isn't like the other files in the app package, in that it doesn't
+ begin with the common header. It should perhaps live with the TDB format or
+ in a similar top level place. It is here because it is included inside the
+ gmapsupp.img file and doesn't normally have a separate existance.
+
+<p>
+ The names and lengths of the fields were obtained from the program gpsexplorer
+ by the author identified as 'garminmaploader at yahoo.com' and released under
+ GPL2+.
+</body>
diff --git a/src/uk/me/parabola/imgfmt/package.html b/src/uk/me/parabola/imgfmt/package.html
new file mode 100644
index 0000000..b331ac9
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/package.html
@@ -0,0 +1,28 @@
+<body>
+<h3>The IMG file format</h3>
+
+<p>The IMG file is internally structured like a file-system containing
+ a number of files and a directory. It is common to refer to the whole
+ thing as a file and the contained files as sub-files. However I use the
+ terms file system and file respectively, because it is more descriptive of
+ what is going on I think.</p>
+
+<p>There are two main sub-packages here.</p>
+<dl>
+ <dt>fs</dt>
+ <dd>This deals with filesystem as a whole. The individual files are just
+ blobs of data. You could handle any filename at this level.
+ </dd>
+
+ <dt>app</dt>
+ <dd>Code for actual application files that are used. Code in here knows
+ about the internal structure of individual files.
+ </dd>
+</dl>
+
+<p>As the purpose of this application is to write IMG files (there are plenty
+ of programs that read it), the focus is on writing and not reading. The
+ code to read at the filesystem level will probably be implemented at some
+ stage so that we can combine several .img files into one gmapsupp.img
+ file.</p>
+</body>
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/sys/BlockManager.java b/src/uk/me/parabola/imgfmt/sys/BlockManager.java
new file mode 100644
index 0000000..d69b34e
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/sys/BlockManager.java
@@ -0,0 +1,89 @@
+/*
+ * 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: 25-Oct-2007
+ */
+package uk.me.parabola.imgfmt.sys;
+
+import uk.me.parabola.imgfmt.MapFailedException;
+import uk.me.parabola.log.Logger;
+
+/**
+ * This is used to allocate blocks for files in the filesystem/archive.
+ *
+ * @author Steve Ratcliffe
+ */
+class BlockManager {
+ private static final Logger log = Logger.getLogger(BlockManager.class);
+
+ private final int blockSize;
+
+ private int currentBlock;
+ private int maxBlock = 0xfffe;
+ private int maxBlockAllocated;
+ private final int initialBlock;
+
+ BlockManager(int blockSize, int initialBlock) {
+ this.blockSize = blockSize;
+ this.currentBlock = initialBlock;
+ this.initialBlock = initialBlock;
+ this.maxBlockAllocated = initialBlock;
+ }
+
+ /**
+ * Well the algorithm is pretty simple - you just get the next unused block
+ * number.
+ *
+ * @return A block number that is free to be used.
+ */
+ public int allocate() {
+ int n = currentBlock++;
+ if (maxBlock > 0 && n > maxBlock) {
+ log.error("overflowed directory with max block " + maxBlock + ", current=" + n);
+
+ // This problem is fixable so give some useful advice on what
+ // to do about it
+ String message = String.format("Too many blocks." +
+ " Use a larger block size with an option such as" +
+ " --block-size=%d or --block-size=%d",
+ blockSize * 2, blockSize * 4);
+ throw new MapFailedException(message);
+ }
+ maxBlockAllocated++;
+ return n;
+ }
+
+ public int getBlockSize() {
+ return blockSize;
+ }
+
+ public int getMaxBlock() {
+ return maxBlock;
+ }
+
+ public void setMaxBlock(int maxBlock) {
+ this.maxBlock = maxBlock;
+ }
+
+ public void setCurrentBlock(int n) {
+ if (maxBlockAllocated != initialBlock)
+ throw new IllegalStateException("Blocks already allocated");
+ currentBlock = n;
+ maxBlockAllocated = n;
+ }
+
+ public int getMaxBlockAllocated() {
+ return maxBlockAllocated;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/sys/BlockTable.java b/src/uk/me/parabola/imgfmt/sys/BlockTable.java
new file mode 100644
index 0000000..dcca9a6
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/sys/BlockTable.java
@@ -0,0 +1,141 @@
+/*
+ * 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: 03-Feb-2007
+ */
+package uk.me.parabola.imgfmt.sys;
+
+import uk.me.parabola.log.Logger;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Holds block numbers for a file. It is part of the directory. For a file
+ * that needs more than one block several directory entries exist. Each of
+ * these has the header with the file name etc. in it, but the first one has
+ * extra flags and info.
+ *
+ * <p>What is important here is that only part of a full block is used to
+ * hold block numbers.
+ *
+ * <p>The entries are 512 bytes regardless of the block size.
+ *
+ * @author Steve Ratcliffe
+ */
+class BlockTable {
+ private static final Logger log = Logger.getLogger(BlockTable.class);
+
+ // Offset of the block table in the directory entry block.
+ private static final int BLOCKS_TABLE_START = 0x20;
+ private static final int ENTRY_SIZE = 512;
+
+ private static final int TABLE_SIZE = (ENTRY_SIZE - BLOCKS_TABLE_START)/2;
+ //private final int tableSize;
+
+ private int curroff;
+ private final List<char[]> blocks;
+ private char[] currTable;
+
+ BlockTable() {
+ blocks = new ArrayList<char[]>(200);
+ }
+
+ /**
+ * Write out the specified table to the given buffer.
+ *
+ * @param buf The buffer to write to.
+ * @param n The number of the block table to write out.
+ */
+ public void writeTable(ByteBuffer buf, int n) {
+ char[] cbuf = blocks.get(n);
+ log.debug("block with length", cbuf.length);
+ for (char c : cbuf) {
+ buf.putChar(c);
+ }
+ }
+
+ /**
+ * Read a block table from the given buffer. The table is added to the
+ * list.
+ * @param buf The buffer to read from.
+ */
+ public void readTable(ByteBuffer buf) {
+ buf.position(BLOCKS_TABLE_START);
+ buf.limit(ENTRY_SIZE);
+
+ char[] cbuf = newTable();
+ for (int i = 0; i < cbuf.length; i++) {
+ char c = buf.getChar();
+ cbuf[i] = c;
+ }
+ }
+
+ /**
+ * Add the given block number to this directory.
+ *
+ * @param n The block number to add.
+ */
+ public void addBlock(int n) {
+ char[] thisTable = currTable;
+ if (curroff >= TABLE_SIZE || currTable == null)
+ thisTable = newTable();
+
+ thisTable[curroff++] = (char) n;
+ }
+
+ /**
+ * Given a logical block number, return the physical block number.
+ *
+ * @param lblock The logical block number, ie with respect to the file.
+ * @return The physical block number in the file system.
+ */
+ public int physFromLogical(int lblock) {
+ int blockNum = lblock / TABLE_SIZE;
+ int offset = lblock - blockNum * TABLE_SIZE;
+ if (blockNum >= blocks.size())
+ return 0xffff;
+
+ char[] cbuf = blocks.get(blockNum);
+ return cbuf[offset];
+ }
+
+ /**
+ * Get the number of block tables. This is the number of blocks that
+ * will be used in the on disk directory structure.
+ *
+ * @return The number of blocks tables.
+ */
+ public int getNBlockTables() {
+ return blocks.size();
+ }
+
+ /**
+ * Allocate a new block to hold more directory block numbers.
+ *
+ * @return Array for more numbers.
+ */
+ private char[] newTable() {
+ char[] table = new char[TABLE_SIZE];
+ Arrays.fill(table, (char) 0xffff);
+
+ curroff = 0;
+ blocks.add(table);
+ currTable = table;
+
+ return table;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/sys/Directory.java b/src/uk/me/parabola/imgfmt/sys/Directory.java
new file mode 100644
index 0000000..4404bd1
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/sys/Directory.java
@@ -0,0 +1,226 @@
+/*
+ * 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: 26-Nov-2006
+ */
+package uk.me.parabola.imgfmt.sys;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.FileExistsException;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.fs.DirectoryEntry;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.log.Logger;
+
+/**
+ * The directory. There is only one directory and it contains the
+ * file names and block information. On disk each entry is a
+ * multiple of the block size.
+ *
+ * @author Steve Ratcliffe
+ */
+class Directory {
+ private static final Logger log = Logger.getLogger(Directory.class);
+
+ //private final FileChannel file;
+ private ImgChannel chan;
+
+ private final BlockManager headerBlockManager;
+ private final int startEntry;
+ private long startPos;
+
+ // The list of files themselves.
+ private final Map<String, DirectoryEntry> entries = new LinkedHashMap<String, DirectoryEntry>();
+
+ Directory(BlockManager headerBlockManager, int startEntry) {
+ this.headerBlockManager = headerBlockManager;
+ this.startEntry = startEntry;
+ }
+
+ /**
+ * Create a new file in the directory.
+ *
+ * @param name The file name. Must be 8+3 characters.
+ * @param blockManager To allocate blocks for the created file entry.
+ * @return The new directory entity.
+ * @throws FileExistsException If the entry already
+ * exists.
+ */
+ Dirent create(String name, BlockManager blockManager) throws FileExistsException {
+
+ // Check to see if it is already there.
+ if (entries.get(name) != null)
+ throw new FileExistsException("File " + name + " already exists");
+
+ Dirent ent;
+ if (name.equals(ImgFS.DIRECTORY_FILE_NAME)) {
+ ent = new HeaderDirent(name, blockManager);
+ } else {
+ ent = new Dirent(name, blockManager);
+ }
+ addEntry(ent);
+
+ return ent;
+ }
+
+ /**
+ * Initialise the directory for reading the file. The whole directory
+ * is read in.
+ *
+ * @throws IOException If it cannot be read.
+ */
+ void readInit(byte xorByte) throws IOException {
+ assert chan != null;
+
+ ByteBuffer buf = ByteBuffer.allocate(512);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+
+ chan.position(startPos);
+ Dirent current = null;
+ while ((chan.read(buf)) > 0) {
+ buf.flip();
+ if(xorByte != 0) {
+ byte[] bufBytes = buf.array();
+ for(int i = 0; i < bufBytes.length; ++i)
+ bufBytes[i] ^= xorByte;
+ }
+
+ int used = buf.get(Dirent.OFF_FILE_USED);
+ if (used != 1)
+ continue;
+
+ String name = Utils.bytesToString(buf, Dirent.OFF_NAME, Dirent.MAX_FILE_LEN);
+ String ext = Utils.bytesToString(buf, Dirent.OFF_EXT, Dirent.MAX_EXT_LEN);
+
+ log.debug("readinit name", name, ext);
+
+ int flag = buf.get(Dirent.OFF_FLAG);
+ int part = buf.get(Dirent.OFF_FILE_PART) & 0xff;
+
+ if (flag == 3 && current == null) {
+ current = (Dirent) entries.get(ImgFS.DIRECTORY_FILE_NAME);
+ current.initBlocks(buf);
+ } else if (part == 0) {
+ current = create(name + '.' + ext, headerBlockManager);
+ current.initBlocks(buf);
+ } else {
+ assert current != null;
+ current.initBlocks(buf);
+ }
+ buf.clear();
+ }
+ }
+
+
+ /**
+ * Write out the directory to the file. The file should be correctly
+ * positioned by the caller.
+ *
+ * @throws IOException If there is a problem writing out any
+ * of the directory entries.
+ */
+ public void sync() throws IOException {
+
+ // The first entry can't really be written until the rest of the directory is
+ // so we have to step through once to calculate the size and then again
+ // to write it out.
+ int headerEntries = 0;
+ for (DirectoryEntry dir : entries.values()) {
+ Dirent ent = (Dirent) dir;
+ log.debug("ent size", ent.getSize());
+ int n = ent.numberHeaderBlocks();
+ headerEntries += n;
+ }
+
+ // Save the current position
+ long dirPosition = chan.position();
+ int blockSize = headerBlockManager.getBlockSize();
+
+ // Get the number of blocks required for the directory entry representing the header.
+ // First calculate the number of blocks required for the directory entries.
+ int headerBlocks = (int) Math.ceil((startEntry + 1.0 + headerEntries) * Dirent.ENTRY_SIZE / blockSize);
+ int forHeader = (headerBlocks + Dirent.ENTRY_SIZE - 1)/Dirent.ENTRY_SIZE;
+
+ log.debug("header blocks needed", forHeader);
+
+ // There is nothing really wrong with larger values (perhaps, I don't
+ // know for sure!) but the code is written to make it 1, so make sure that it is.
+ assert forHeader == 1;
+
+ // Write the blocks that will will contain the header blocks.
+ chan.position(dirPosition + (long) forHeader * Dirent.ENTRY_SIZE);
+
+ for (DirectoryEntry dir : entries.values()) {
+ Dirent ent = (Dirent) dir;
+
+ if (!ent.isSpecial()) {
+ log.debug("wrting ", dir.getFullName(), " at ", chan.position());
+ log.debug("ent size", ent.getSize());
+ ent.sync(chan);
+ }
+ }
+
+ long end = (long) blockSize * headerBlockManager.getMaxBlock();
+ ByteBuffer buf = ByteBuffer.allocate((int) (end - chan.position()));
+ for (int i = 0; i < buf.capacity(); i++)
+ buf.put((byte) 0);
+ buf.flip();
+ chan.write(buf);
+
+ // Now go back and write in the directory entry for the header.
+ chan.position(dirPosition);
+ Dirent ent = (Dirent) entries.values().iterator().next();
+ log.debug("ent header size", ent.getSize());
+ ent.sync(chan);
+
+ }
+
+ /**
+ * Get the entries. Used for listing the directory.
+ *
+ * @return A list of the directory entries. They will be in the same
+ * order as in the file.
+ */
+ public List<DirectoryEntry> getEntries() {
+ return new ArrayList<DirectoryEntry>(entries.values());
+ }
+
+ /**
+ * Add an entry to the directory.
+ *
+ * @param ent The entry to add.
+ */
+ private void addEntry(DirectoryEntry ent) {
+ entries.put(ent.getFullName(), ent);
+ }
+
+ public void setFile(ImgChannel chan) {
+ this.chan = chan;
+ }
+
+ public void setStartPos(long startPos) {
+ this.startPos = startPos;
+ }
+
+ public DirectoryEntry lookup(String name) {
+ return entries.get(name);
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/sys/Dirent.java b/src/uk/me/parabola/imgfmt/sys/Dirent.java
new file mode 100644
index 0000000..593a5ff
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/sys/Dirent.java
@@ -0,0 +1,276 @@
+/*
+ * 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: 30-Nov-2006
+ */
+package uk.me.parabola.imgfmt.sys;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.fs.DirectoryEntry;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.log.Logger;
+
+/**
+ * An entry within a directory. This holds its name and a list
+ * of blocks that go to make up this file.
+ *
+ * A directory entry may take more than block in the file system.
+ *
+ * <p>All documentation seems to point to the block numbers having to be
+ * contiguous, but seems strange so I shall experiment.
+ *
+ * <p>Entries are in blocks of 512 bytes, regardless of the block size.
+ *
+ * @author Steve Ratcliffe
+ */
+class Dirent implements DirectoryEntry {
+ protected static final Logger log = Logger.getLogger(Dirent.class);
+
+ // Constants.
+ static final int MAX_FILE_LEN = 8;
+ static final int MAX_EXT_LEN = 3;
+
+ // Offsets
+ static final int OFF_FILE_USED = 0x00;
+ static final int OFF_NAME = 0x01;
+ static final int OFF_EXT = 0x09;
+ static final int OFF_FLAG = 0x10;
+ static final int OFF_FILE_PART = 0x11;
+ private static final int OFF_SIZE = 0x0c;
+
+ // File names are a base+extension
+ private String name;
+ private String ext;
+
+ // The file size.
+ private int size;
+
+ private final BlockManager blockManager;
+
+ // The block table holds all the blocks that belong to this file. The
+ // documentation suggests that block numbers are always contiguous.
+ private final BlockTable blockTable;
+
+ private boolean special;
+ private static final int OFF_USED_FLAG = 0;
+ private boolean initialized;
+
+ Dirent(String name, BlockManager blockManager) {
+ this.blockManager = blockManager;
+
+ int dot = name.lastIndexOf('.');
+ if (dot >= 0) {
+ setName(name.substring(0, dot));
+ setExt(name.substring(dot+1));
+ } else
+ throw new IllegalArgumentException("Filename did not have dot");
+
+ blockTable = new BlockTable();
+ }
+
+ /**
+ * Write this entry out to disk. Note that these are 512 bytes, regardless
+ * of the block size.
+ *
+ * @param file The file to write to.
+ * @throws IOException If writing fails for any reason.
+ */
+ void sync(ImgChannel file) throws IOException {
+ int ntables = blockTable.getNBlockTables();
+ ByteBuffer buf = ByteBuffer.allocate(ENTRY_SIZE * ntables);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+
+ for (int part = 0; part < ntables; part++) {
+ log.debug("position at part", part, "is", buf.position());
+
+ buf.put((byte) 1);
+
+ buf.put(Utils.toBytes(name, MAX_FILE_LEN, (byte) ' '));
+ buf.put(Utils.toBytes(ext, MAX_EXT_LEN, (byte) ' '));
+
+ // Size is only present in the first part
+ if (part == 0) {
+ log.debug("dirent", name, '.', ext, "size is going to", size);
+ buf.putInt(size);
+ } else {
+ buf.putInt(0);
+ }
+
+ buf.put((byte) (special? 0x3: 0));
+ buf.putChar((char) part);
+
+ // Write out the allocation of blocks for this entry.
+ buf.position(ENTRY_SIZE * part + 0x20);
+ blockTable.writeTable(buf, part);
+ }
+
+ buf.flip();
+ file.write(buf);
+ }
+
+ /**
+ * Get the file name.
+ *
+ * @return The file name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Get the file extension.
+ *
+ * @return The file extension.
+ */
+ public String getExt() {
+ return ext;
+ }
+
+ /**
+ * The full name is of the form 8+3 with a dot in between the name and
+ * extension. The full name is used as the index in the directory.
+ *
+ * @return The full name.
+ */
+ public String getFullName() {
+ return name + '.' + ext;
+ }
+
+ /**
+ * Read in the block numbers from the given buffer. If this is the first
+ * directory block for this file, then the size is set too.
+ *
+ * @param buf The data as read from the file.
+ */
+ void initBlocks(ByteBuffer buf) {
+
+ byte used = buf.get(OFF_USED_FLAG);
+ if (used != 1)
+ return;
+
+ int part = buf.get(OFF_FILE_PART) & 0xff;
+ if (part == 0 || (isSpecial() && part == 3))
+ size = buf.getInt(OFF_SIZE);
+
+ blockTable.readTable(buf);
+ initialized = true;
+ }
+
+ /**
+ * Get the file size.
+ *
+ * @return The size of the file in bytes.
+ */
+ public int getSize() {
+ return size;
+ }
+
+ /**
+ * Set the file name. The name should be exactly eight characters long
+ * and it is truncated or left padded with zeros to make this true.
+ *
+ * @param name The file name.
+ */
+ private void setName(String name) {
+ int len = name.length();
+ if (len > MAX_FILE_LEN) {
+ this.name = name.substring(0, 8);
+ } else if (len < MAX_FILE_LEN) {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < MAX_FILE_LEN - len; i++) {
+ sb.append('0');
+ }
+ sb.append(name);
+ this.name = sb.toString();
+ } else
+ this.name = name;
+ }
+
+ /**
+ * Set the file extension. Can't be longer than three characters.
+ * @param ext The file extension.
+ */
+ private void setExt(String ext) {
+ log.debug("ext len", ext.length());
+ if (ext.length() != MAX_EXT_LEN)
+ throw new IllegalArgumentException("File extension is wrong size");
+ this.ext = ext;
+ }
+
+ /**
+ * The number of blocks that the header covers. The header includes
+ * the directory for the purposes of this routine.
+ *
+ * @return The total number of header basic blocks (blocks of 512 bytes).
+ */
+ int numberHeaderBlocks() {
+ return blockTable.getNBlockTables();
+ }
+
+ void setSize(int size) {
+ if (log.isDebugEnabled())
+ log.debug("setting size", getName(), getExt(), "to", size);
+ this.size = size;
+ }
+
+ /**
+ * Add a block without increasing the size of the file.
+ *
+ * @param n The block number.
+ */
+ void addBlock(int n) {
+ blockTable.addBlock(n);
+ }
+
+ /**
+ * Set for the first directory entry that covers the header and directory
+ * itself.
+ *
+ * @param special Set to true to mark as the special first entry.
+ */
+ public void setSpecial(boolean special) {
+ this.special = special;
+ }
+
+ public boolean isSpecial() {
+ return special;
+ }
+
+ /**
+ * Converts from a logical block to a physical block. If the block does
+ * not exist then 0xffff will be returned.
+ *
+ * @param lblock The logical block in the file.
+ * @return The corresponding physical block in the filesystem.
+ */
+ public int getPhysicalBlock(int lblock) {
+ return blockTable.physFromLogical(lblock);
+ }
+
+ public BlockManager getBlockManager() {
+ return blockManager;
+ }
+
+ protected void setInitialized(boolean initialized) {
+ this.initialized = initialized;
+ }
+
+ protected boolean isInitialized() {
+ return initialized;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/sys/FileImgChannel.java b/src/uk/me/parabola/imgfmt/sys/FileImgChannel.java
new file mode 100644
index 0000000..5b353bf
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/sys/FileImgChannel.java
@@ -0,0 +1,97 @@
+/*
+ * 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: Dec 14, 2007
+ */
+package uk.me.parabola.imgfmt.sys;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+
+import uk.me.parabola.imgfmt.ReadFailedException;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+
+/**
+ * This is an implementation of ImgChannel that delegates to a regular channel.
+ * It can therefore be used to read or write regular files on the file system.
+ *
+ * @author Steve Ratcliffe
+ */
+public class FileImgChannel implements ImgChannel {
+ private final FileChannel channel;
+ private long position;
+
+ public FileImgChannel(String filename, String mode) {
+ RandomAccessFile raf;
+ try {
+ raf = new RandomAccessFile(filename, mode);
+ } catch (FileNotFoundException e) {
+ throw new ReadFailedException("Could not open " + filename, e);
+ }
+ this.channel = raf.getChannel();
+ }
+
+ public FileImgChannel(FileChannel channel) {
+ this.channel = channel;
+ }
+
+ public int read(ByteBuffer dst) throws IOException {
+ int n = channel.read(dst);
+ if (n > 0)
+ position += n;
+ return n;
+ }
+
+ public boolean isOpen() {
+ return channel.isOpen();
+ }
+
+ public void close() throws IOException {
+ channel.close();
+ }
+
+ public int write(ByteBuffer src) throws IOException {
+ int n = channel.write(src);
+ position += n;
+ return n;
+ }
+
+ /**
+ * Get the file position. Note that this is a logical position relative to the
+ * beginning of the file (the file within the .img file, not the beginning of the
+ * .img file itself).
+ *
+ * @return The offset in bytes from the beginning of the file.
+ */
+ public long position() {
+ return position;
+ }
+
+ /**
+ * Set the position within the file.
+ *
+ * @param pos The position to set.
+ */
+ public void position(long pos) {
+ try {
+ channel.position(pos);
+ position = pos;
+ } catch (IOException e) {
+ throw new ReadFailedException("Could not seek", e);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/sys/FileNode.java b/src/uk/me/parabola/imgfmt/sys/FileNode.java
new file mode 100644
index 0000000..a97d76a
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/sys/FileNode.java
@@ -0,0 +1,326 @@
+/*
+ * 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: 03-Dec-2006
+ */
+package uk.me.parabola.imgfmt.sys;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.AsynchronousCloseException;
+import java.nio.channels.ClosedByInterruptException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.FileChannel;
+import java.nio.channels.NonReadableChannelException;
+import java.nio.channels.NonWritableChannelException;
+
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.log.Logger;
+
+/**
+ * The internal representation of a file in the file system. In use it
+ * should only be referred to by the {@link ImgChannel} interface.
+ *
+ * @author Steve Ratcliffe
+ */
+public class FileNode implements ImgChannel {
+ private static final Logger log = Logger.getLogger(FileNode.class);
+
+ private boolean open;
+ private boolean writeable;
+ private boolean readable;
+
+ private final FileChannel file;
+ private final BlockManager blockManager;
+ private final Dirent dirent;
+
+ // The position in this file
+ private long position;
+
+ private byte xorByte;
+
+ /**
+ * Creates a new file in the file system. You can treat this just like
+ * a regular file and write or read from it.
+ * Operations to two different files may not be interleaved although
+ * it may be possible to implement this.
+ *
+ * @param file The handle to the underlying file.
+ * @param dir The directory entry associated with this file.
+ * @param mode The mode "rw" for read and write etc.
+ */
+ public FileNode(FileChannel file, Dirent dir, String mode)
+ {
+ this.file = file;
+ this.dirent = dir;
+
+ if (mode.indexOf('r') >= 0)
+ readable = true;
+ if (mode.indexOf('w') >= 0)
+ writeable = true;
+ if (!(readable || writeable))
+ throw new IllegalArgumentException("File must be readable or writeable");
+
+ blockManager = dir.getBlockManager();
+ if (blockManager == null)
+ throw new IllegalArgumentException("no file system supplied");
+
+ open = true;
+ }
+
+ /**
+ * Closes this channel.
+ * <p/>
+ * <p> After a channel is closed, any further attempt to invoke I/O
+ * operations upon it will cause a {@link ClosedChannelException} to be
+ * thrown.
+ * <p/>
+ * <p> If this channel is already closed then invoking this method has no
+ * effect.
+ * <p/>
+ * <p> This method may be invoked at any time. If some other thread has
+ * already invoked it, however, then another invocation will block until
+ * the first invocation is complete, after which it will return without
+ * effect. </p>
+ *
+ * @throws IOException If an I/O error occurs
+ */
+ public void close() throws IOException {
+ if (!open)
+ return;
+
+ sync();
+
+ open = false;
+ readable = false;
+ writeable = false;
+ }
+
+ /**
+ * Tells whether or not this channel is open. </p>
+ *
+ * @return <tt>true</tt> if, and only if, this channel is open
+ */
+ public boolean isOpen() {
+ return open;
+ }
+
+ /**
+ * Reads a sequence of bytes from this channel into the given buffer.
+ *
+ * @param dst The buffer into which bytes are to be transferred
+ *
+ * @return The number of bytes read, possibly zero, or <tt>-1</tt> if the
+ * channel has reached end-of-stream
+ *
+ * @throws NonReadableChannelException If this channel was not opened for reading
+ * @throws ClosedChannelException If this channel is closed
+ * @throws AsynchronousCloseException If another thread closes this channel
+ * while the read operation is in progress
+ * @throws ClosedByInterruptException If another thread interrupts the
+ * current thread while the read operation is in progress, thereby closing
+ * the channel and setting the current thread's interrupt status
+ * @throws IOException If some other I/O error occurs
+ */
+ public int read(ByteBuffer dst) throws IOException {
+ if (!open)
+ throw new ClosedChannelException();
+ if (!readable)
+ throw new NonReadableChannelException();
+
+ int blockSize = blockManager.getBlockSize();
+
+ long size = dst.remaining();
+ long fileSize = dirent.getSize();
+ if (position >= fileSize)
+ return -1;
+ size = Math.min(size, fileSize - position);
+
+ int totalRead = 0;
+
+ while (size > 0) {
+ // Tet the logical block number, as we see it in our file.
+ int lblock = (int) (position / blockSize);
+
+ // Get the physical block number, the actual block number in
+ // the underlying file.
+ int pblock = dirent.getPhysicalBlock(lblock);
+ if (pblock == 0xffff) {
+ // We are at the end of the file.
+ log.debug("at eof");
+ break;
+ }
+
+ // Position the underlying file
+ int off = (int) (position - lblock*blockSize);
+ file.position((long) pblock * blockSize + off);
+
+ int n = (int) size;
+ if (n > blockSize)
+ n = blockSize;
+
+ if (off != 0)
+ n = Math.min(n, blockSize - off);
+
+ dst.limit(dst.position() + n);
+
+ int pos = dst.position();
+ int nr = file.read(dst);
+ if (nr == -1)
+ return -1;
+ if (nr == 0)
+ throw new IOException("Read nothing");
+
+ if(xorByte != 0) {
+ byte[] bufBytes = dst.array();
+ for(int i = pos + n - 1; i >= pos; --i)
+ bufBytes[i] ^= xorByte;
+ }
+
+ // Update the file positions
+ size -= nr;
+ position += nr;
+ totalRead += nr;
+ }
+
+ log.debug("read ret", totalRead);
+ return totalRead;
+ }
+
+ /**
+ * Writes a sequence of bytes to this channel from the given buffer.
+ * <p/>
+ * <p> An attempt is made to write up to <i>r</i> bytes to the channel,
+ * where <i>r</i> is the number of bytes remaining in the buffer, that is,
+ * <tt>dst.remaining()</tt>, at the moment this method is invoked.
+ * <p>The logical block has to be converted to a physical block in the
+ * underlying file.
+ *
+ * @param src The buffer from which bytes are to be retrieved
+ * @return The number of bytes written, possibly zero
+ * @throws NonWritableChannelException
+ * If this channel was not opened for writing
+ * @throws ClosedChannelException
+ * If this channel is closed
+ * @throws IOException If some other I/O error occurs
+ */
+ public int write(ByteBuffer src) throws IOException {
+ if (!open)
+ throw new ClosedChannelException();
+
+ int blockSize = blockManager.getBlockSize();
+
+ // Get the size of this write
+ int size = src.remaining();
+
+ // Loop over each block, this is to support the case (which we may
+ // not implement) of non-contiguous blocks.
+
+ int totalWritten = 0;
+ while (size > 0) {
+ // Get the logical block, ie the block as we see it in our file.
+ int lblock = (int) (position/blockSize);
+
+ // First need to allocate enough blocks for this write. First check
+ // if the block exists already
+ int pblock = dirent.getPhysicalBlock(lblock);
+ log.debug("lblock / pblock", lblock, '/', pblock);
+ if (pblock == 0xffff) {
+ log.debug("allocating new block");
+ pblock = blockManager.allocate();
+ dirent.addBlock(pblock);
+ }
+
+ // Position the underlying file, so that it is in the correct place.
+ int off = (int) (position - lblock*blockSize);
+ file.position((long) pblock * blockSize + off);
+
+ int n = size;
+ if (n > blockSize)
+ n = blockSize;
+
+ if (off != 0)
+ n = Math.min(n, blockSize - off);
+
+ src.limit(src.position() + n);
+
+ // Write to the underlying file.
+ int nw = file.write(src);
+ if (nw == 0)
+ throw new IOException("Wrote nothing");
+
+ // Update the file positions
+ size -= nw;
+ position += nw;
+ totalWritten += nw;
+
+ // Update file size.
+ if (position > dirent.getSize())
+ dirent.setSize((int) position);
+ }
+
+ return totalWritten;
+ }
+
+ public long position() {
+ return position;
+ }
+
+ public void position(long pos) {
+ int blockSize = blockManager.getBlockSize();
+
+ while (pos > position) {
+ long lblock = position / blockSize;
+ int pblock = dirent.getPhysicalBlock((int) lblock);
+
+ if (pblock == 0xffff) {
+ if (writeable) {
+ log.debug("setting position allocating new block", lblock);
+ pblock = blockManager.allocate();
+ dirent.addBlock(pblock);
+ }
+ }
+ position = (lblock+1) * blockSize;
+ }
+
+ this.position = pos;
+ }
+
+ /**
+ * Write out any unsaved data to disk.
+ *
+ * @throws IOException If there is an error writing to disk.
+ */
+ private void sync() throws IOException {
+ if (!writeable)
+ return;
+
+ // Ensure that a complete block is written out.
+ int bs = blockManager.getBlockSize();
+ long rem = bs - (file.position() % bs);
+
+ ByteBuffer buf = ByteBuffer.allocate(blockManager.getBlockSize());
+
+ // Complete any partial block.
+ for (int i = 0; i < rem; i++)
+ buf.put((byte) 0);
+
+ buf.flip();
+ file.write(buf);
+ }
+
+ public void setXorByte(byte xorByte) {
+ this.xorByte = xorByte;
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/sys/HeaderDirent.java b/src/uk/me/parabola/imgfmt/sys/HeaderDirent.java
new file mode 100644
index 0000000..8015ab2
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/sys/HeaderDirent.java
@@ -0,0 +1,72 @@
+/*
+ * 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: 27-Oct-2007
+ */
+package uk.me.parabola.imgfmt.sys;
+
+/**
+ * This is a special class for the header. It makes it easier to bootstrap
+ * the directory by having a special implementation that starts up by knowing
+ * that the blocks in the header start from 0.
+ *
+ * @author Steve Ratcliffe
+ */
+class HeaderDirent extends Dirent {
+ HeaderDirent(String name, BlockManager blockManager) {
+ super(name, blockManager);
+ }
+
+ /**
+ * Converts from a logical block to a physical block. This is a special
+ * version that returns the logical block number when the {@link Dirent} is not
+ * set up. This allows us to bootstrap the reading of the header blocks.
+ * The header blocks always logical and physical blocks the same.
+ *
+ * @param lblock The logical block in the file.
+ * @return The corresponding physical block in the filesystem.
+ */
+ public int getPhysicalBlock(int lblock) {
+ if (isInitialized()) {
+ log.debug("gpb (ok)");
+ return super.getPhysicalBlock(lblock);
+ } else {
+ log.debug("gpb (not setup)");
+ return lblock;
+ }
+ }
+
+ /**
+ * Get the file size. The file appears large until the first blocks are
+ * read in and then it will take on its actual size.
+ *
+ * @return The size of the file in bytes.
+ */
+ public int getSize() {
+ if (isInitialized())
+ return super.getSize();
+ else
+ return getBlockManager().getBlockSize() * 32;
+ }
+
+ /**
+ * Always returns true as this is only used for the special header
+ * directory entry.
+ *
+ * @return Always returns true.
+ */
+ public boolean isSpecial() {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/sys/ImgFS.java b/src/uk/me/parabola/imgfmt/sys/ImgFS.java
new file mode 100644
index 0000000..cee76c0
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/sys/ImgFS.java
@@ -0,0 +1,352 @@
+/*
+ * 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: 26-Nov-2006
+ */
+package uk.me.parabola.imgfmt.sys;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.FileExistsException;
+import uk.me.parabola.imgfmt.FileNotWritableException;
+import uk.me.parabola.imgfmt.FileSystemParam;
+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.log.Logger;
+
+/**
+ * The img file is really a filesystem containing several files.
+ * It is made up of a header, a directory area and a data area which
+ * occur in the filesystem in that order.
+ *
+ * @author steve
+ */
+public class ImgFS implements FileSystem {
+ private static final Logger log = Logger.getLogger(ImgFS.class);
+
+ // The directory is just like any other file, but with a name of 8+3 spaces
+ static final String DIRECTORY_FILE_NAME = " . ";
+
+ // This is the read or write channel to the real file system.
+ private final FileChannel file;
+ private boolean readOnly = true;
+
+ // The header contains general information.
+ private ImgHeader header;
+
+ // There is only one directory that holds all filename and block allocation
+ // information.
+ private Directory directory;
+
+ // The filesystem is responsible for allocating blocks
+ private BlockManager fileBlockManager;
+
+ // The header entries are written in 512 blocks, regardless of the block size of the file itself.
+ private static final long ENTRY_BLOCK_SIZE = 512L;
+ private BlockManager headerBlockManager;
+
+ private byte xorByte; // if non-zero, all bytes are XORed with this
+
+ /**
+ * Private constructor, use the static {@link #createFs} and {@link #openFs}
+ * routines to make a filesystem.
+ *
+ * @param chan The open file.
+ */
+ private ImgFS(FileChannel chan) {
+ file = chan;
+ }
+
+ /**
+ * Create an IMG file from its external filesystem name and optionally some
+ * parameters.
+ *
+ * @param filename The name of the file to be created.
+ * @param params File system parameters. Can not be null.
+ * @throws FileNotWritableException If the file can not be written to.
+ */
+ public static FileSystem createFs(String filename, FileSystemParam params) throws FileNotWritableException {
+ params.setFilename(filename);
+ try {
+ RandomAccessFile rafile = new RandomAccessFile(filename, "rw");
+ return createFs(rafile.getChannel(), params);
+ } catch (FileNotFoundException e) {
+ throw new FileNotWritableException("Could not create file: " + params.getFilename(), e);
+ }
+ }
+
+ private static FileSystem createFs(FileChannel chan, FileSystemParam params)
+ throws FileNotWritableException
+ {
+ assert params != null;
+
+ // Truncate the file, because extra bytes beyond the end make for a
+ // map that doesn't work on the GPS (although its likely to work in
+ // other software viewers).
+ try {
+ chan.truncate(0);
+ } catch (IOException e) {
+ throw new FileNotWritableException("Failed to truncate file", e);
+ }
+
+ ImgFS fs = new ImgFS(chan);
+ fs.createInitFS(chan, params);
+
+ return fs;
+ }
+
+ /**
+ * Open an existing IMG file system.
+ * @param name The file name to open.
+ * @return A File system that can be used lookup the internal files.
+ * @throws FileNotFoundException When the file doesn't exist or can't be
+ * read.
+ */
+ public static FileSystem openFs(String name) throws FileNotFoundException {
+ RandomAccessFile rafile = new RandomAccessFile(name, "r");
+ return openFs(name, rafile.getChannel());
+ }
+
+ private static FileSystem openFs(String name, FileChannel chan) throws FileNotFoundException {
+ ImgFS fs = new ImgFS(chan);
+
+ try {
+ fs.readInitFS(chan);
+ } catch (IOException e) {
+ throw new FileNotFoundException(name + ": " + e.getMessage());
+ }
+
+ return fs;
+ }
+
+ /**
+ * Create a new file, it must not already exist.
+ *
+ * @param name The file name.
+ * @return A directory entry for the new file.
+ */
+ public ImgChannel create(String name) throws FileExistsException {
+ Dirent dir = directory.create(name, fileBlockManager);
+
+ return new FileNode(file, dir, "w");
+ }
+
+ /**
+ * Open a file. The returned file object can be used to read and write the
+ * underlying file.
+ *
+ * @param name The file name to open.
+ * @param mode Either "r" for read access, "w" for write access or "rw"
+ * for both read and write.
+ * @return A file descriptor.
+ * @throws FileNotFoundException When the file does not exist.
+ */
+ public ImgChannel open(String name, String mode) throws FileNotFoundException {
+ if (name == null || mode == null)
+ throw new IllegalArgumentException("null argument");
+
+ if (mode.indexOf('r') >= 0) {
+ Dirent ent = internalLookup(name);
+
+ FileNode fn = new FileNode(file, ent, "r");
+ if(xorByte != 0)
+ fn.setXorByte(xorByte);
+ return fn;
+ } else if (mode.indexOf('w') >= 0) {
+ Dirent ent;
+ try {
+ ent = internalLookup(name);
+ } catch (FileNotFoundException e) {
+ try {
+ ent = directory.create(name, fileBlockManager);
+ } catch (FileExistsException e1) {
+ // This shouldn't happen as we have just checked.
+ throw new FileNotFoundException("Attempt to duplicate a file name");
+ }
+ }
+ return new FileNode(file, ent, "w");
+ } else {
+ throw new IllegalArgumentException("Invalid mode given");
+ }
+ }
+
+ /**
+ * Lookup the file and return a directory entry for it.
+ *
+ * @param name The filename to look up.
+ * @return A directory entry.
+ * @throws FileNotFoundException If an error occurs looking for the file,
+ * including it not existing.
+ */
+ public DirectoryEntry lookup(String name) throws FileNotFoundException {
+ return internalLookup(name);
+ }
+
+ /**
+ * List all the files in the directory.
+ *
+ * @return A List of directory entries.
+ */
+ public List<DirectoryEntry> list() {
+ return directory.getEntries();
+ }
+
+ public FileSystemParam fsparam() {
+ return header.getParams();
+ }
+
+ public void fsparam(FileSystemParam param) {
+ int reserved = param.getReservedDirectoryBlocks() + 2;
+ fileBlockManager.setCurrentBlock(reserved);
+ headerBlockManager.setMaxBlock(reserved);
+ }
+
+ /**
+ * Sync with the underlying file. All unwritten data is written out to
+ * the underlying file.
+ *
+ * @throws IOException If an error occurs during the write.
+ */
+ public void sync() throws IOException {
+ if (readOnly)
+ return;
+
+ header.setNumBlocks(fileBlockManager.getMaxBlockAllocated());
+ header.sync();
+ directory.sync();
+ }
+
+ /**
+ * Close the filesystem. Any saved data is flushed out. It is better
+ * to explicitly sync the data out first, to be sure that it has worked.
+ */
+ public void close() {
+
+ try {
+ sync();
+ } catch (IOException e) {
+ log.debug("could not sync filesystem");
+ } finally {
+ try {
+ file.close();
+ } catch (IOException e) {
+ log.warn("Could not close file");
+ }
+ }
+ }
+
+ /**
+ * Set up and ImgFS that has just been created.
+ *
+ * @param chan The real underlying file to write to.
+ * @param params The file system parameters.
+ * @throws FileNotWritableException If the file cannot be written for any
+ * reason.
+ */
+ private void createInitFS(FileChannel chan, FileSystemParam params) throws FileNotWritableException {
+ readOnly = false;
+
+ // The block manager allocates blocks for files.
+ headerBlockManager = new BlockManager(params.getBlockSize(), 0);
+ headerBlockManager.setMaxBlock(params.getReservedDirectoryBlocks());
+
+ // This bit is tricky. We want to use a regular ImgChannel to write
+ // to the header and directory, but to create one normally would involve
+ // it already existing, so it is created by hand.
+ try {
+ directory = new Directory(headerBlockManager, params.getDirectoryStartEntry());
+
+ Dirent ent = directory.create(DIRECTORY_FILE_NAME, headerBlockManager);
+ ent.setSpecial(true);
+ ent.setInitialized(true);
+
+ FileNode f = new FileNode(chan, ent, "w");
+
+ directory.setFile(f);
+ header = new ImgHeader(f);
+ header.createHeader(params);
+ } catch (FileExistsException e) {
+ throw new FileNotWritableException("Could not create img file directory", e);
+ }
+
+ fileBlockManager = new BlockManager(params.getBlockSize(), params.getReservedDirectoryBlocks());
+
+ assert header != null;
+ }
+
+ /**
+ * Initialise a filesystem that is going to be read from. We need to read
+ * in the header including directory.
+ *
+ * @param chan The file channel to read from.
+ * @throws IOException If the file cannot be read.
+ */
+ private void readInitFS(FileChannel chan) throws IOException {
+ ByteBuffer headerBuf = ByteBuffer.allocate(512);
+ headerBuf.order(ByteOrder.LITTLE_ENDIAN);
+ chan.read(headerBuf);
+ xorByte = headerBuf.get(0);
+ if(xorByte != 0) {
+ byte[] headerBytes = headerBuf.array();
+ for(int i = 0; i < headerBytes.length; ++i)
+ headerBytes[i] ^= xorByte;
+ }
+
+ if (headerBuf.position() < 512)
+ throw new IOException("File too short or corrupted");
+
+ header = new ImgHeader(null);
+ header.setHeader(headerBuf);
+ FileSystemParam params = header.getParams();
+
+ BlockManager headerBlockManager = new BlockManager(params.getBlockSize(), 0);
+ headerBlockManager.setMaxBlock(params.getReservedDirectoryBlocks());
+
+ directory = new Directory(headerBlockManager, params.getDirectoryStartEntry());
+ directory.setStartPos(params.getDirectoryStartEntry() * ENTRY_BLOCK_SIZE);
+
+ Dirent ent = directory.create(DIRECTORY_FILE_NAME, headerBlockManager);
+ FileNode f = new FileNode(chan, ent, "r");
+
+ header.setFile(f);
+ directory.setFile(f);
+ directory.readInit(xorByte);
+ }
+
+ /**
+ * Lookup the file and return a directory entry for it.
+ *
+ * @param name The filename to look up.
+ * @return A directory entry.
+ * @throws FileNotFoundException If an error occurs reading the directory.
+ */
+ private Dirent internalLookup(String name) throws FileNotFoundException {
+ if (name == null)
+ throw new IllegalArgumentException("null name argument");
+
+ Dirent ent = (Dirent) directory.lookup(name);
+ if (ent == null)
+ throw new FileNotFoundException(name + " not found");
+
+ return ent;
+ }
+
+}
diff --git a/src/uk/me/parabola/imgfmt/sys/ImgHeader.java b/src/uk/me/parabola/imgfmt/sys/ImgHeader.java
new file mode 100644
index 0000000..9ab6666
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/sys/ImgHeader.java
@@ -0,0 +1,420 @@
+/*
+ * 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: 26-Nov-2006
+ */
+package uk.me.parabola.imgfmt.sys;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Calendar;
+import java.util.Date;
+
+import uk.me.parabola.imgfmt.FileSystemParam;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.log.Logger;
+
+import static java.util.Arrays.asList;
+
+/**
+ * The header at the very beginning of the .img filesystem. It has the
+ * same signature as a DOS partition table, although I don't know
+ * exactly how much the partition concepts are used.
+ *
+ * @author Steve Ratcliffe
+ */
+class ImgHeader {
+ private static final Logger log = Logger.getLogger(ImgHeader.class);
+
+ // Offsets into the header.
+ private static final int OFF_XOR = 0x0;
+ private static final int OFF_UPDATE_MONTH = 0xa;
+ private static final int OFF_UPDATE_YEAR = 0xb; // +1900 for val >= 0x63, +2000 for less
+ private static final int OFF_SUPP = 0xe; // Appears to be set for gmapsupp files
+ private static final int OFF_CHECKSUM = 0xf;
+ private static final int OFF_SIGNATURE = 0x10;
+ private static final int OFF_UNK_1 = 0x17;
+
+ // If this was a real boot sector these would be the meanings
+ private static final int OFF_SECTORS = 0x18;
+ private static final int OFF_HEADS = 0x1a;
+ private static final int OFF_CYLINDERS = 0x1c;
+
+ private static final int OFF_CREATION_DATE = 0x39;
+
+ // The block number where the directory starts.
+ private static final int OFF_DIRECTORY_START_BLOCK = 0x40;
+
+ private static final int OFF_MAP_FILE_INTENTIFIER = 0x41;
+ private static final int OFF_MAP_DESCRIPTION = 0x49; // 0x20 padded
+
+ private static final int OFF_HEADS2 = 0x5d;
+ private static final int OFF_SECTORS2 = 0x5f;
+
+ private static final int OFF_BLOCK_SIZE_EXPONENT1 = 0x61;
+ private static final int OFF_BLOCK_SIZE_EXPONENT2 = 0x62;
+ private static final int OFF_BLOCK_SIZE = 0x63;
+
+ // private static final int OFF_UKN_3 = 0x63;
+
+ private static final int OFF_MAP_NAME_CONT = 0x65;
+
+ // 'Partition table' offsets.
+ private static final int OFF_START_HEAD = 0x1bf;
+ private static final int OFF_START_SECTOR = 0x1c0;
+ private static final int OFF_START_CYLINDER = 0x1c1;
+ private static final int OFF_SYSTEM_TYPE = 0x1c2;
+ private static final int OFF_END_HEAD = 0x1c3;
+ private static final int OFF_END_SECTOR = 0x1c4;
+ private static final int OFF_END_CYLINDER = 0x1c5;
+ private static final int OFF_REL_SECTORS = 0x1c6;
+ private static final int OFF_NUMBER_OF_SECTORS = 0x1ca;
+ private static final int OFF_PARTITION_SIG = 0x1fe;
+
+ // Lengths of some of the fields
+ private static final int LEN_MAP_NAME_CONT = 30;
+ private static final int LEN_MAP_DESCRIPTION = 20;
+
+ private FileSystemParam fsParams;
+
+ private final ByteBuffer header = ByteBuffer.allocate(512);
+
+ private ImgChannel file;
+ private Date creationTime;
+
+ private int sectorsPerTrack;
+ private int headsPerCylinder;
+
+ // Signatures.
+ private static final byte[] FILE_ID = {
+ 'G', 'A', 'R', 'M', 'I', 'N', '\0'};
+
+ private static final byte[] SIGNATURE = {
+ 'D', 'S', 'K', 'I', 'M', 'G', '\0'};
+
+ private int numBlocks;
+
+ ImgHeader(ImgChannel chan) {
+ this.file = chan;
+ header.order(ByteOrder.LITTLE_ENDIAN);
+ }
+
+ /**
+ * Create a header from scratch.
+ * @param params File system parameters.
+ */
+ void createHeader(FileSystemParam params) {
+ this.fsParams = params;
+
+ header.put(OFF_XOR, (byte) 0);
+
+ // Set the block size. 2^(E1+E2) where E1 is always 9.
+ int exp = 9;
+
+ int bs = params.getBlockSize();
+ for (int i = 0; i < 32; i++) {
+ bs >>>= 1;
+ if (bs == 0) {
+ exp = i;
+ break;
+ }
+ }
+
+ if (exp < 9)
+ throw new IllegalArgumentException("block size too small");
+
+ header.put(OFF_BLOCK_SIZE_EXPONENT1, (byte) 0x9);
+ header.put(OFF_BLOCK_SIZE_EXPONENT2, (byte) (exp - 9));
+
+ header.position(OFF_SIGNATURE);
+ header.put(SIGNATURE);
+
+ header.position(OFF_MAP_FILE_INTENTIFIER);
+ header.put(FILE_ID);
+
+ header.put(OFF_UNK_1, (byte) 0x2);
+
+ // Actually this may not be the directory start block, I am guessing -
+ // always assume it is 2 anyway.
+ header.put(OFF_DIRECTORY_START_BLOCK, (byte) fsParams.getDirectoryStartEntry());
+
+ header.position(OFF_CREATION_DATE);
+ Utils.setCreationTime(header, creationTime);
+
+ setDirectoryStartEntry(params.getDirectoryStartEntry());
+
+ // Set the times.
+ Date date = new Date();
+ setCreationTime(date);
+ setUpdateTime(date);
+ setDescription(params.getMapDescription());
+
+ // Checksum is not checked.
+ header.put(OFF_CHECKSUM, (byte) 0);
+ }
+
+ /**
+ * Write out the values associated with the partition sizes.
+ *
+ * @param blockSize Block size.
+ */
+ private void writeSizeValues(int blockSize) {
+ int endSector = (int) (((numBlocks+1L) * blockSize + 511) / 512);
+ //System.out.printf("end sector %d %x\n", endSector, endSector);
+
+ // We have three maximum values for sectors, heads and cylinders. We attempt to find values
+ // for them that are larger than the
+ sectorsPerTrack = 32; // 6 bit value
+ headsPerCylinder = 128;
+ int cyls = 0x400;
+
+ // Try out various values of h, s and c until we find a combination that is large enough.
+ // I'm not entirely sure about the valid values, but it seems that only certain values work
+ // which is why we use values from a list.
+ // See: http://www.win.tue.nl/~aeb/partitions/partition_types-2.html for justification for the h list
+ out:
+ for (int h : asList(16, 32, 64, 128, 256)) {
+ for (int s : asList(4, 8, 16, 32)) {
+ for (int c : asList(0x20, 0x40, 0x80, 0x100, 0x200, 0x3ff)) {
+ log.info("shc=", s + "," + h + "," + c, "end=", endSector);
+ //System.out.println("shc=" + s + "," + h + "," + c + "end=" + endSector);
+ if (s * h * c > endSector) {
+ headsPerCylinder = h;
+ sectorsPerTrack = s;
+ cyls = c;
+ break out;
+ }
+ }
+ }
+ }
+
+ // This sectors, head, cylinders stuff appears to be used by mapsource
+ // and they have to be larger than the actual size of the map. It
+ // doesn't appear to have any effect on a garmin device or other software.
+ header.putShort(OFF_SECTORS, (short) sectorsPerTrack);
+ header.putShort(OFF_SECTORS2, (short) sectorsPerTrack);
+ header.putShort(OFF_HEADS, (short) headsPerCylinder);
+ header.putShort(OFF_HEADS2, (short) headsPerCylinder);
+ header.putShort(OFF_CYLINDERS, (short) cyls);
+
+ // Since there are only 2 bytes here it can overflow, if it
+ // does we replace it with 0xffff.
+ int blocks = (int) (endSector * 512L / blockSize);
+ char shortBlocks = blocks > 0xffff ? 0xffff : (char) blocks;
+ header.putChar(OFF_BLOCK_SIZE, shortBlocks);
+
+ header.put(OFF_PARTITION_SIG, (byte) 0x55);
+ header.put(OFF_PARTITION_SIG + 1, (byte) 0xaa);
+
+ // Partition starts at zero. This is 0,0,1 in CHS terms.
+ header.put(OFF_START_HEAD, (byte) 0);
+ header.put(OFF_START_SECTOR, (byte) 1);
+ header.put(OFF_START_CYLINDER, (byte) 0);
+
+ header.put(OFF_SYSTEM_TYPE, (byte) 0);
+
+ // Now calculate the CHS address of the last sector of the partition.
+ CHS chs = new CHS(endSector - 1);
+
+ header.put(OFF_END_HEAD, (byte) (chs.h));
+ header.put(OFF_END_SECTOR, (byte) ((chs.s) | ((chs.c >> 2) & 0xc0)));
+ header.put(OFF_END_CYLINDER, (byte) (chs.c & 0xff));
+
+ // Write the LBA block address of the beginning and end of the partition.
+ header.putInt(OFF_REL_SECTORS, 0);
+ header.putInt(OFF_NUMBER_OF_SECTORS, endSector);
+ log.info("number of blocks", endSector - 1);
+ }
+
+ void setHeader(ByteBuffer buf) {
+ buf.flip();
+ header.put(buf);
+
+ byte exp1 = header.get(OFF_BLOCK_SIZE_EXPONENT1);
+ byte exp2 = header.get(OFF_BLOCK_SIZE_EXPONENT2);
+ log.debug("header exponent", exp1, exp2);
+
+ fsParams = new FileSystemParam();
+ fsParams.setBlockSize(1 << (exp1 + exp2));
+ fsParams.setDirectoryStartEntry(header.get(OFF_DIRECTORY_START_BLOCK));
+
+ StringBuffer sb = new StringBuffer();
+ sb.append(Utils.bytesToString(buf, OFF_MAP_DESCRIPTION, LEN_MAP_DESCRIPTION));
+ sb.append(Utils.bytesToString(buf, OFF_MAP_NAME_CONT, LEN_MAP_NAME_CONT));
+
+ fsParams.setMapDescription(sb.toString().trim());
+
+ byte h = header.get(OFF_END_HEAD);
+ byte sc1 = header.get(OFF_END_SECTOR);
+ byte sc2 = header.get(OFF_END_CYLINDER);
+ CHS chs = new CHS();
+ chs.setFromPartition(h, sc1, sc2);
+ int lba = chs.toLba();
+ log.info("partition sectors", lba);
+ // ... more to do
+ }
+
+ void setFile(ImgChannel file) {
+ this.file = file;
+ }
+
+ FileSystemParam getParams() {
+ return fsParams;
+ }
+
+ /**
+ * Sync the header to disk.
+ * @throws IOException If an error occurs during writing.
+ */
+ public void sync() throws IOException {
+ setUpdateTime(new Date());
+
+ writeSizeValues(fsParams.getBlockSize());
+
+ header.rewind();
+ file.position(0);
+ file.write(header);
+ file.position(fsParams.getDirectoryStartEntry() * 512L);
+ }
+
+ /**
+ * Set the update time.
+ * @param date The date to use.
+ */
+ protected void setUpdateTime(Date date) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+
+ header.put(OFF_UPDATE_YEAR, toYearCode(cal.get(Calendar.YEAR)));
+ header.put(OFF_UPDATE_MONTH, (byte) (cal.get(Calendar.MONTH)+1));
+ }
+
+ /**
+ * Set the description. It is spread across two areas in the header.
+ * @param desc The description.
+ */
+ protected void setDescription(String desc) {
+ int len = desc.length();
+ if (len > 50)
+ throw new IllegalArgumentException("Description is too long (max 50)");
+ String part1, part2;
+ if (len > LEN_MAP_DESCRIPTION) {
+ part1 = desc.substring(0, LEN_MAP_DESCRIPTION);
+ part2 = desc.substring(LEN_MAP_DESCRIPTION, len);
+ } else {
+ part1 = desc.substring(0, len);
+ part2 = "";
+ }
+
+ header.position(OFF_MAP_DESCRIPTION);
+ header.put(toByte(part1));
+ for (int i = len; i < LEN_MAP_DESCRIPTION; i++)
+ header.put((byte) ' ');
+
+ header.position(OFF_MAP_NAME_CONT);
+ header.put(toByte(part2));
+ for (int i = Math.max(len - LEN_MAP_DESCRIPTION, 0); i < LEN_MAP_NAME_CONT; i++)
+ header.put((byte) ' ');
+
+ header.put((byte) 0); // really?
+ }
+
+ /**
+ * Convert a string to a byte array.
+ * @param s The string
+ * @return A byte array.
+ */
+ private byte[] toByte(String s) {
+ // NB: what character set should be used?
+ return s.getBytes();
+ }
+
+ /**
+ * Convert to the one byte code that is used for the year.
+ * If the year is in the 1900, then subtract 1900 and add the result to 0x63,
+ * else subtract 2000.
+ * Actually looks simpler, just subtract 1900..
+ * @param y The year in real-world format eg 2006.
+ * @return A one byte code representing the year.
+ */
+ private byte toYearCode(int y) {
+ return (byte) (y - 1900);
+ }
+
+ protected void setDirectoryStartEntry(int directoryStartEntry) {
+ header.put(OFF_DIRECTORY_START_BLOCK, (byte) directoryStartEntry);
+ fsParams.setDirectoryStartEntry(directoryStartEntry);
+ }
+
+ protected void setCreationTime(Date date) {
+ this.creationTime = date;
+ }
+
+ public void setNumBlocks(int numBlocks) {
+ this.numBlocks = numBlocks;
+ }
+
+ /**
+ * Represent a block number in the chs format.
+ *
+ * Note that this class uses the headsPerCylinder and sectorsPerTrack values
+ * from the enclosing class.
+ *
+ * @see <a href="http://en.wikipedia.org/wiki/Logical_Block_Addressing">Logical block addressing</a>
+ */
+ private class CHS {
+ private int h;
+ private int s;
+ private int c;
+
+ private CHS() {
+ }
+
+ public CHS(int lba) {
+ toChs(lba);
+ }
+
+ /**
+ * Calculate the CHS values from the the given logical block address.
+ * @param lba Input logical block address.
+ */
+ private void toChs(int lba) {
+ h = (lba / sectorsPerTrack) % headsPerCylinder;
+ s = (lba % sectorsPerTrack) + 1;
+ c = lba / (sectorsPerTrack * headsPerCylinder);
+ }
+
+ /**
+ * Set from a partition table entry.
+ *
+ * The cylinder is 10 bits and is split between the top 2 bit of the sector
+ * value and its own byte.
+ *
+ * @param h The h value.
+ * @param sc1 The s value (6 bits) and top 2 bits of c.
+ * @param sc2 The bottom 8 bits of c.
+ */
+ public void setFromPartition(byte h, byte sc1, byte sc2) {
+ this.h = h;
+ this.s = (sc1 & 0x3f) + ((sc2 >> 2) & 0xc0);
+ this.c = sc2 & 0xff;
+ }
+
+ public int toLba() {
+ return (c * headsPerCylinder + h) * sectorsPerTrack + (s - 1);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/imgfmt/sys/package.html b/src/uk/me/parabola/imgfmt/sys/package.html
new file mode 100644
index 0000000..73fa974
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/sys/package.html
@@ -0,0 +1,10 @@
+<body>
+<h3>Filesystem implementation</h3>
+<p>This holds the filesystem implementation for the .img
+format. I refer through out to a file system containing
+files, rather than using the term <em>sub-files</em> as in John Mechalas'
+document.</p>
+<p>Another way to look at it (and probably a better one) is that it a kind
+ of archive format just like a .zip file.
+</p>
+</body>
diff --git a/src/uk/me/parabola/io/EndOfFileException.java b/src/uk/me/parabola/io/EndOfFileException.java
new file mode 100644
index 0000000..663e6d6
--- /dev/null
+++ b/src/uk/me/parabola/io/EndOfFileException.java
@@ -0,0 +1,30 @@
+/*
+ * 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: 23-Sep-2007
+ */
+package uk.me.parabola.io;
+
+import java.io.IOException;
+
+/**
+ * Used to note end of streams. Not really used much now.
+ *
+ * @author Steve Ratcliffe
+ */
+public class EndOfFileException extends IOException {
+ public EndOfFileException() {
+ super("End of file");
+ }
+}
diff --git a/src/uk/me/parabola/io/StructuredInputStream.java b/src/uk/me/parabola/io/StructuredInputStream.java
new file mode 100644
index 0000000..c7c5a2f
--- /dev/null
+++ b/src/uk/me/parabola/io/StructuredInputStream.java
@@ -0,0 +1,123 @@
+/*
+ * 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: 23-Sep-2007
+ */
+package uk.me.parabola.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An input stream used to make reading little endian integers and strings from
+ * the tdb file.
+ *
+ * @author Steve Ratcliffe
+ */
+public class StructuredInputStream extends InputStream {
+ private final InputStream in;
+ private boolean eof;
+
+ public StructuredInputStream(InputStream in) {
+ this.in = in;
+ }
+
+ /**
+ * Implementation of read that delegates to the underlying stream. It however
+ * also keeps track of the end of file status.
+ *
+ * @return The next byte, or -1 on eof.
+ * @throws IOException For problems reading.
+ */
+ public int read() throws IOException {
+ int r = in.read();
+ if (r == -1)
+ eof = true;
+ return r;
+ }
+
+ /**
+ * Read a 2 byte little endian integer.
+ *
+ * @return The integer.
+ * @throws IOException If the stream could not be read.
+ */
+ public int read2() throws IOException {
+ int a = read() & 0xff;
+ int b = read() & 0xff;
+
+ if (isEof())
+ throw new EndOfFileException();
+
+ return (b << 8) + a;
+ }
+
+ /**
+ * Read a 4 byte integer quantity. As always this is little endian.
+ *
+ * @return The integer.
+ * @throws IOException If the stream could not be read.
+ */
+ public int read4() throws IOException {
+ int a = read() & 0xff;
+ int b = read() & 0xff;
+ int c = read() & 0xff;
+ int d = read() & 0xff;
+
+ return (d << 24) | (c << 16) | (b << 8) | a;
+ }
+
+ /**
+ * Read a nul terminated string from the input stream.
+ *
+ * @return A string, without the null terminator.
+ * @throws IOException If the stream cannot be read.
+ */
+ public String readString() throws IOException {
+ StringBuffer name = new StringBuffer();
+ int b;
+ while ((b = read()) != '\0' && b != -1) {
+ name.append((char) (b & 0xff));
+ }
+ return name.toString();
+ }
+
+ boolean isEof() {
+ return eof;
+ }
+
+ /**
+ * Test if we are at the end of the file by marking the position and trying
+ * to read the next byte. If not at the end then the stream position is
+ * reset and all is as before.
+ *
+ * @return True if we are at the end of the stream.
+ */
+ public boolean testEof() {
+ assert in.markSupported();
+ in.mark(1);
+ try {
+ int b = in.read();
+ if (b == -1) {
+ eof = true;
+ } else {
+ in.reset();
+ }
+ return isEof();
+ } catch (IOException e) {
+ return true;
+ }
+ }
+
+}
diff --git a/src/uk/me/parabola/io/StructuredOutputStream.java b/src/uk/me/parabola/io/StructuredOutputStream.java
new file mode 100644
index 0000000..53e36cb
--- /dev/null
+++ b/src/uk/me/parabola/io/StructuredOutputStream.java
@@ -0,0 +1,72 @@
+/*
+ * 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: 23-Sep-2007
+ */
+package uk.me.parabola.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.FilterOutputStream;
+
+/**
+ * An output stream that has methods for writing strings and little endian
+ * integers. Its a bit like DataOutput, but for little endian.
+ *
+ * @author Steve Ratcliffe
+ */
+public class StructuredOutputStream extends FilterOutputStream {
+
+ public StructuredOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ public void write(int b) throws IOException {
+ out.write(b);
+ }
+
+ public void write2(int b) throws IOException {
+ out.write(b);
+ out.write(b >> 8);
+ }
+
+ public void write3(int i) throws IOException {
+ out.write(i);
+ out.write(i >> 8);
+ out.write(i >> 16);
+ }
+
+ public void write4(int b) throws IOException {
+ out.write(b);
+ out.write(b >> 8);
+ out.write(b >> 16);
+ out.write(b >> 24);
+ }
+
+ /**
+ * Writes a string including a terminating null byte.
+ *
+ * For each character in the string the low-order byte is written.
+ *
+ * @param s The string to write.
+ * @throws IOException If the write fails.
+ */
+ public void writeString(String s) throws IOException {
+ for (char c : s.toCharArray()) {
+ out.write((byte) c);
+ }
+
+ out.write('\0');
+ }
+}
diff --git a/src/uk/me/parabola/log/Logger.java b/src/uk/me/parabola/log/Logger.java
new file mode 100644
index 0000000..b468730
--- /dev/null
+++ b/src/uk/me/parabola/log/Logger.java
@@ -0,0 +1,235 @@
+/*
+ * 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: 30-Dec-2006
+ */
+package uk.me.parabola.log;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+
+/**
+ * Simple logging class. By default it is disabled. You have to set it up
+ * using (currently) a system property. On the other hand it uses varargs
+ * to make easier logging without having to do string concatenation in the
+ * regular code.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Logger {
+ private final java.util.logging.Logger log;
+
+ private static final ThreadLocal<String> threadTags = new ThreadLocal<String>();
+
+ static {
+ initLogging();
+ }
+
+ private Logger(String name) {
+ this.log = java.util.logging.Logger.getLogger(name);
+ }
+
+ /**
+ * Get a logger by its name.
+ *
+ * @param name The name of the logger. Uses the same conventions as in
+ * java.util.logging.Logger as this is just a thin wrapper around that
+ * class.
+ * @return The logger.
+ */
+ public static Logger getLogger(String name) {
+ return new Logger(name);
+ }
+
+ /**
+ * Convenience class to get a logger using a class name as the name.
+ * @param aClass The class - its name will be used to retrieve the
+ * logger.
+ * @return The logger.
+ */
+ public static Logger getLogger(Class<?> aClass) {
+ String name = aClass.getName();
+ return getLogger(name);
+ }
+
+ public static void resetLogging(String filename) {
+ initLoggingFromFile(filename);
+ }
+
+ private static void initLogging() {
+ Properties props = System.getProperties();
+
+ String logconf = props.getProperty("log.config");
+ if (logconf != null) {
+ initLoggingFromFile(logconf);
+ }
+ else {
+ staticSetup();
+ }
+ }
+
+ private static void initLoggingFromFile(String logconf) {
+ try {
+ InputStream in = new FileInputStream(logconf);
+ LogManager lm = LogManager.getLogManager();
+ lm.reset();
+ lm.readConfiguration(in);
+ } catch (FileNotFoundException e) {
+ System.err.println("Failed to open logging config file " + logconf);
+ staticSetup();
+ } catch (IOException e) {
+ staticSetup();
+ }
+ }
+
+ /**
+ * The default setup, which is basically not to do any logging apart from
+ * showing warnings and errors (and I may remove that).
+ */
+ private static void staticSetup() {
+ // Static setup.
+ LogManager.getLogManager().reset();
+ java.util.logging.Logger l = java.util.logging.Logger.getLogger("");
+
+ ConsoleHandler handler = new ConsoleHandler();
+ UsefulFormatter f = new UsefulFormatter();
+
+ f.setShowTime(false);
+
+ handler.setFormatter(f);
+ handler.setLevel(Level.SEVERE);
+
+ l.addHandler(handler);
+ l.setLevel(Level.WARNING);
+ }
+
+ public boolean isLoggable(Level level) {
+ return log.isLoggable(level);
+ }
+
+ public boolean isDebugEnabled() {
+ return log.isLoggable(Level.FINE);
+ }
+
+ public boolean isInfoEnabled() {
+ return log.isLoggable(Level.INFO);
+ }
+
+ /**
+ * Debug message. We are using the j.u.l FINE level for this. As it is
+ * possible that the toString method on the logged object is expensive
+ * we check that the message should be logged first. Though this is
+ * perhaps overkill.
+ *
+ * This comment applies to all the corresponding methods below.
+ *
+ * @param o The object to be logged.
+ */
+ public void debug(Object o) {
+ if (log.isLoggable(Level.FINE))
+ log.fine(tagMessage(o == null? "null" : o.toString()));
+ }
+
+ /**
+ * Log a message that consists of a variable number of arguments. The
+ * arguments are simply concatenated with a space between them.
+ *
+ * The arrayFormat call is very expensive and checking the log level first
+ * is important. The same applies to all similar routines below.
+ *
+ * @param olist The list of objects to log as one message.
+ */
+ public void debug(Object ... olist) {
+ if (log.isLoggable(Level.FINE))
+ arrayFormat(Level.FINE, olist);
+ }
+
+ public void info(Object o) {
+ if (log.isLoggable(Level.INFO))
+ log.info(tagMessage(o == null? "null" : o.toString()));
+ }
+
+ public void info(Object ... olist) {
+ if (log.isLoggable(Level.INFO))
+ arrayFormat(Level.INFO, olist);
+ }
+
+ public void warn(Object o) {
+ log.warning(tagMessage(o == null? "null" : o.toString()));
+ }
+
+ public void warn(Object ... olist) {
+ if (log.isLoggable(Level.WARNING))
+ arrayFormat(Level.WARNING, olist);
+ }
+
+ public void error(Object o) {
+ log.severe(tagMessage(o == null? "null" : o.toString()));
+ }
+
+ public void error(Object o, Throwable e) {
+ log.log(Level.SEVERE, tagMessage(o == null? "null" : o.toString()), e);
+ }
+
+ public void log(Level level, Object o) {
+ if (log.isLoggable(level))
+ log.log(level, tagMessage(o == null? "null" : o.toString()));
+ }
+
+ public void log(Level level, Object ... olist) {
+ if (log.isLoggable(level))
+ arrayFormat(level, olist);
+ }
+
+ /**
+ * Format the list of arguments by appending them to one string, keeping a
+ * space between them.
+ *
+ * Only call this if you've checked that the message needs to be printed,
+ * otherwise it will all go to waste.
+ *
+ * @param type The Level type FINE, INFO etc.
+ * @param olist The argument list as objects.
+ */
+ private void arrayFormat(Level type, Object... olist) {
+ StringBuffer sb = new StringBuffer();
+
+ for (Object o : olist) {
+ sb.append(o);
+ sb.append(' ');
+ }
+ sb.setLength(sb.length()-1);
+
+ log.log(type, tagMessage(sb.toString()));
+ }
+
+ private String tagMessage(String message) {
+ String threadTag = threadTags.get();
+ return (threadTag != null) ? threadTag + ": " + message : message;
+ }
+
+ public void threadTag(String tag) {
+ threadTags.set(tag);
+ }
+
+ public String threadTag() {
+ return threadTags.get();
+ }
+}
diff --git a/src/uk/me/parabola/log/UsefulFormatter.java b/src/uk/me/parabola/log/UsefulFormatter.java
new file mode 100644
index 0000000..19356d1
--- /dev/null
+++ b/src/uk/me/parabola/log/UsefulFormatter.java
@@ -0,0 +1,96 @@
+/*
+ * 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: 08-Sep-2007
+ */
+package uk.me.parabola.log;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Calendar;
+import java.util.logging.Formatter;
+import java.util.logging.LogRecord;
+
+/**
+ * Prints the message all on one line, which amazingly is not the default
+ * behaviour in j.u.l, no wonder no one uses it.
+ *
+ * MUST be public whatever crazy static analyzers might say.
+ *
+ * @author Steve Ratcliffe
+ */
+public class UsefulFormatter extends Formatter {
+ private boolean showTime = true;
+
+ public String format(LogRecord record) {
+ StringBuffer sb = new StringBuffer();
+
+ if (showTime) {
+ long millis = record.getMillis();
+ Calendar cal = Calendar.getInstance();
+ cal.setTimeInMillis(millis);
+ sb.append(cal.get(Calendar.YEAR));
+ sb.append('/');
+ sb.append(fmt2(cal.get(Calendar.MONTH)+1));
+ sb.append('/');
+ sb.append(fmt2(cal.get(Calendar.DAY_OF_MONTH)));
+ sb.append(' ');
+ sb.append(fmt2(cal.get(Calendar.HOUR_OF_DAY)));
+ sb.append(':');
+ sb.append(fmt2(cal.get(Calendar.MINUTE)));
+ sb.append(':');
+ sb.append(fmt2(cal.get(Calendar.SECOND)));
+ sb.append(' ');
+ }
+
+ sb.append(record.getLevel().getLocalizedName());
+ sb.append(" (");
+ sb.append(shortName(record.getLoggerName()));
+ sb.append("): ");
+
+ sb.append(record.getMessage());
+
+ sb.append('\n');
+
+ @SuppressWarnings({"ThrowableResultOfMethodCallIgnored"})
+ Throwable t = record.getThrown();
+ if (t != null) {
+ StringWriter out = new StringWriter();
+ PrintWriter pw = new PrintWriter(out);
+ t.printStackTrace(pw);
+ sb.append(out.toString());
+ }
+ return sb.toString();
+ }
+
+ public void setShowTime(boolean showTime) {
+ this.showTime = showTime;
+ }
+
+ private String fmt2(int i) {
+ StringBuffer res = new StringBuffer(String.valueOf(i));
+ while (res.length() < 2) {
+ res.insert(0, '0');
+ }
+ return res.toString();
+ }
+
+ private String shortName(String name) {
+ int end = name.lastIndexOf('.');
+ if (end > 0) {
+ return name.substring(end+1);
+ } else
+ return name;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/ArgumentProcessor.java b/src/uk/me/parabola/mkgmap/ArgumentProcessor.java
new file mode 100644
index 0000000..15a6c12
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/ArgumentProcessor.java
@@ -0,0 +1,65 @@
+/*
+ * 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: 29-Sep-2007
+ */
+package uk.me.parabola.mkgmap;
+
+/**
+ * Used to step through each filename that is given to the program.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface ArgumentProcessor {
+
+ /**
+ * Process an option. In general you do not do anything in this callback for most options.
+ * Options that determine how a particular file are processed are saved into a map that
+ * is handed to the map building process.
+ *
+ * Options that are processed here are things like --help or --list-styles that have an
+ * actual effect by themselves.
+ *
+ * @param opt The option name.
+ * @param val The option value.
+ */
+ public void processOption(String opt, String val);
+
+ /**
+ * Called when an option is reset, eg --no-tdbfile.
+ * @param opt The option name.
+ */
+ public void removeOption(String opt);
+
+ /**
+ * Process a filename.
+ *
+ * @param args A copy of the option arguments in force when this filename
+ * was specified.
+ * @param filename The filename.
+ */
+ public void processFilename(CommandArgs args, String filename);
+
+ /**
+ * Called when all the command line options have been processed.
+ * @param args The command line options.
+ */
+ public void endOptions(CommandArgs args);
+
+ /**
+ * Called right at the beginning, before any command line options have
+ * been looked at.
+ */
+ public void startOptions();
+}
diff --git a/src/uk/me/parabola/mkgmap/CommandArgs.java b/src/uk/me/parabola/mkgmap/CommandArgs.java
new file mode 100644
index 0000000..6807263
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/CommandArgs.java
@@ -0,0 +1,119 @@
+package uk.me.parabola.mkgmap;
+
+import java.io.File;
+
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.util.EnhancedProperties;
+
+public class CommandArgs {
+ public static final int DEFAULT_FAMILYID = 6324;
+ public static final int DEFAULT_PRODUCTID = 1;
+
+ private final EnhancedProperties currentOptions;
+ private Sort sort;
+
+ public CommandArgs(EnhancedProperties args) {
+ currentOptions = new EnhancedProperties(args);
+ }
+
+ public EnhancedProperties getProperties() {
+ return currentOptions;
+ }
+
+ public int get(String name, int def) {
+ return currentOptions.getProperty(name, def);
+ }
+
+ public String get(String name, String def) {
+ return currentOptions.getProperty(name, def);
+ }
+
+ public boolean get(String name, boolean def) {
+ return currentOptions.getProperty(name, def);
+ }
+
+ public String getDescription() {
+ return currentOptions.getProperty("description");
+ }
+
+ // ////
+ // There are a number of methods to get specific arguments that follow.
+ // There are many more options in use however. New code should mostly
+ // just use the get methods above.
+ // ////
+
+ public int getBlockSize() {
+ return get("block-size", 512);
+ }
+
+ public String getMapname() {
+ return currentOptions.getProperty("mapname");
+ }
+
+ public String getCharset() {
+
+ String charset = currentOptions.getProperty("charset");
+ if (charset != null)
+ return charset;
+
+ int cp = getCodePage();
+ if (cp != 0)
+ return "cp" + cp;
+
+ return "ascii";
+ }
+
+ public int getCodePage() {
+ int cp;
+
+ String s = currentOptions.getProperty("code-page");
+ try {
+ cp = Integer.parseInt(s);
+ } catch (NumberFormatException e) {
+ cp = 0;
+ }
+
+ return cp;
+ }
+
+ public String getOutputDir() {
+ String DEFAULT_DIR = ".";
+ String fileOutputDir = currentOptions.getProperty("output-dir", DEFAULT_DIR);
+
+ // Test if directory exists
+ File outputDir = new File(fileOutputDir);
+ if (!outputDir.exists()) {
+ System.out.println("Output directory not found. Creating directory '" + fileOutputDir + "'");
+ outputDir.mkdirs();
+ if (!outputDir.exists()) {
+ System.err.println("Unable to create output directory! Using default directory instead");
+ fileOutputDir = DEFAULT_DIR;
+ }
+ } else if (!outputDir.isDirectory()) {
+ System.err.println("The --output-dir parameter must specify a directory. The parameter is being ignored, writing to default directory instead.");
+ fileOutputDir = DEFAULT_DIR;
+ }
+
+ return fileOutputDir;
+ }
+
+ public Sort getSort() {
+ assert sort != null;
+ return sort;
+ }
+
+ public void setSort(Sort sort) {
+ this.sort = sort;
+ }
+
+ public boolean isForceUpper() {
+ return currentOptions.getProperty("lower-case") == null;
+ }
+
+ /**
+ * Test for the existence of an argument.
+ */
+ public boolean exists(String name) {
+ return currentOptions.containsKey(name);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/CommandArgsReader.java b/src/uk/me/parabola/mkgmap/CommandArgsReader.java
new file mode 100644
index 0000000..f21bc54
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/CommandArgsReader.java
@@ -0,0 +1,349 @@
+/*
+ * 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: 01-Jan-2007
+ */
+package uk.me.parabola.mkgmap;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Formatter;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import uk.me.parabola.imgfmt.ExitException;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * Command line arguments for Main. Arguments consist of options and filenames.
+ * You read arguments from left to right and when a filename is encountered
+ * the file is processed with the options that were in force at the time.
+ *
+ * Since it is likely that the number of options will become quite large, you
+ * can place options in a file. Place the options each on a separate line
+ * without the initial '--'.
+ *
+ * @author Steve Ratcliffe
+ */
+public class CommandArgsReader {
+ private static final Logger log = Logger.getLogger(CommandArgsReader.class);
+
+ private final ArgumentProcessor proc;
+
+ private boolean mapnameWasSet;
+
+ private final ArgList arglist = new ArgList();
+
+ private final EnhancedProperties args = new EnhancedProperties();
+ private Set<String> validOptions;
+
+ {
+ // Set some default values. It is as if these were on the command
+ // line before any user supplied options.
+ add(new CommandOption("mapname", "63240001"));
+ add(new CommandOption("description", "OSM street map"));
+ add(new CommandOption("overview-mapname", "osmmap"));
+ add(new CommandOption("overview-mapnumber", "63240000"));
+ add(new CommandOption("poi-address", ""));
+ add(new CommandOption("merge-lines", ""));
+ }
+
+ public CommandArgsReader(ArgumentProcessor proc) {
+ this.proc = proc;
+ }
+
+ /**
+ * Read and interpret the command line arguments. Most have a double hyphen
+ * preceding them and these work just the same if they are in a config
+ * file.
+ * <p/>
+ * There are a few options that consist of a single hyphen followed by a
+ * single letter that are short cuts for a long option.
+ * <p/>
+ * The -c option is special. It is followed by the name of a file in which
+ * there are further command line options. Any option on the command line
+ * that comes after the -c option will override the value that is set in
+ * this file.
+ *
+ * @param args The command line arguments.
+ */
+ public void readArgs(String[] args) {
+
+ proc.startOptions();
+
+ int i = 0;
+ while (i < args.length) {
+ String arg = args[i++];
+ if (arg.startsWith("--")) {
+ // This is a long style 'property' format option.
+ addOption(arg.substring(2));
+
+ } else if (arg.equals("-c")) {
+ // Config file
+ readConfigFile(args[i++]);
+
+ } else if (arg.equals("-n")) {
+ // Map name (should be an 8 digit number).
+ addOption("mapname", args[i++]);
+
+ } else if (arg.equals("-v")) {
+ // make commands more verbose
+ addOption("verbose");
+
+ } else if (arg.startsWith("-")) {
+ // this is an unrecognised option.
+ System.err.println("unrecognised option " + arg);
+
+ } else {
+ log.debug("adding filename:", arg);
+ add(new Filename(arg));
+ }
+ }
+
+ // If there is more than one filename argument we inform of this fact
+ // via a fake option.
+ proc.processOption("number-of-files", String.valueOf(arglist.getFilenameCount()));
+
+ // Now process the arguments in order.
+ for (ArgType a : arglist) {
+ a.processArg();
+ }
+
+ proc.endOptions(new CommandArgs(this.args));
+ }
+
+
+ /**
+ * Add an option based on the option and value separately.
+ * @param option The option name.
+ * @param value Its value.
+ */
+ private void addOption(String option, String value) {
+ CommandOption opt = new CommandOption(option, value);
+ addOption(opt);
+ }
+
+ /**
+ * Add an option from a raw string.
+ * @param optval The option=value string.
+ */
+ private void addOption(String optval) {
+ CommandOption opt = new CommandOption(new Option(optval));
+ addOption(opt);
+ }
+
+ /**
+ * Actually add the option. Some of these are special in that they are
+ * filename arguments or instructions to read options from another file.
+ *
+ * @param opt The decoded option.
+ */
+ private void addOption(CommandOption opt) {
+ String option = opt.getOption();
+ String value = opt.getValue();
+
+ if (validOptions != null && !validOptions.contains(option) && !opt.isExperimental()) {
+ Formatter f = new Formatter();
+ f.format("Invalid option: '%s'", option);
+ throw new ExitException(f.toString());
+ }
+
+ log.debug("adding option", option, value);
+
+ // Note if an explicit mapname is set
+ if (option.equals("mapname"))
+ mapnameWasSet = true;
+
+ if (option.equals("input-file")) {
+ log.debug("adding filename", value);
+ add(new Filename(value));
+ } else if (option.equals("read-config")) {
+ readConfigFile(value);
+ } else if (option.equals("latin1")) {
+ add(new CommandOption("code-page", "1252"));
+ } else {
+ add(opt);
+ }
+ }
+
+ private void add(CommandOption option) {
+ arglist.add(option);
+ }
+
+ private void add(Filename filename) {
+ arglist.add(filename);
+ }
+
+ /**
+ * Read a config file that contains more options. When the number of
+ * options becomes large it is more convenient to place them in a file.
+ *
+ * @param filename The filename to obtain options from.
+ */
+ private void readConfigFile(String filename) {
+ Options opts = new Options(new OptionProcessor() {
+ public void processOption(Option opt) {
+ log.debug("incoming opt", opt.getOption(), opt.getValue());
+ addOption(new CommandOption(opt));
+ }
+ });
+ try {
+ opts.readOptionFile(filename);
+ } catch (IOException e) {
+ throw new ExitException("Failed to read option file", e);
+ }
+ }
+
+ public void setValidOptions(Set<String> validOptions) {
+ this.validOptions = validOptions;
+ }
+
+ /**
+ * Interface that represents an argument type. It provides a method for
+ * the argument to be processed in order. Options can be interspersed with
+ * filenames. The options take effect where they appear.
+ */
+ interface ArgType {
+ public abstract void processArg();
+ }
+
+ /**
+ * A filename.
+ */
+ class Filename implements ArgType {
+ private final String name;
+ private boolean useFilenameAsMapname = true;
+
+ private Filename(String name) {
+ this.name = name;
+ if (mapnameWasSet)
+ useFilenameAsMapname = false;
+ }
+
+ public void processArg() {
+ // If there was no explicit mapname specified and the input filename
+ // looks like it contains an 8digit number then we use that.
+ String mapname;
+ if (useFilenameAsMapname) {
+ mapname = extractMapName(name);
+ if (mapname != null)
+ args.setProperty("mapname", mapname);
+ }
+
+ // Now process the file
+ proc.processFilename(new CommandArgs(args), name);
+
+ // Increase the name number. If the next arg sets it then that
+ // will override this new name.
+ mapname = args.getProperty("mapname");
+ try {
+ Formatter fmt = new Formatter();
+ try {
+ int n = Integer.parseInt(mapname);
+ fmt.format("%08d", ++n);
+ } catch (NumberFormatException e) {
+ fmt.format("%8.8s", mapname);
+ }
+ args.setProperty("mapname", fmt.toString());
+ } catch (NumberFormatException e) {
+ // If the name is not a number then we just leave it alone...
+ }
+ }
+
+ private String extractMapName(String path) {
+
+ File file = new File(path);
+ String fname = file.getName();
+ Pattern pat = Pattern.compile("([0-9]{8})");
+ Matcher matcher = pat.matcher(fname);
+ boolean found = matcher.find();
+ if (found)
+ return matcher.group(1);
+
+ return null;
+ }
+ }
+
+ /**
+ * An option argument. A key value pair.
+ */
+ class CommandOption implements ArgType {
+ private final Option option;
+
+ private CommandOption(Option option) {
+ this.option = option;
+ }
+
+ private CommandOption(String key, String val) {
+ this.option = new Option(key, val);
+ }
+
+ public void processArg() {
+ if (option.isReset()) {
+ args.remove(option.getOption());
+ proc.removeOption(option.getOption());
+ } else {
+ args.setProperty(option.getOption(), option.getValue());
+ proc.processOption(option.getOption(), option.getValue());
+ }
+ }
+
+ public String getOption() {
+ return option.getOption();
+ }
+
+ public String getValue() {
+ return option.getValue();
+ }
+
+ public boolean isExperimental() {
+ return option.isExperimental();
+ }
+ }
+
+ /**
+ * The arguments are held in this list.
+ */
+ class ArgList implements Iterable<ArgType> {
+ private final List<ArgType> alist;
+
+ private int filenameCount;
+
+ ArgList() {
+ alist = new ArrayList<ArgType>();
+ }
+
+ protected void add(CommandOption option) {
+ alist.add(option);
+ }
+
+ public void add(Filename name) {
+ filenameCount++;
+ alist.add(name);
+ }
+
+ public Iterator<ArgType> iterator() {
+ return alist.iterator();
+ }
+
+ public int getFilenameCount() {
+ return filenameCount;
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/Option.java b/src/uk/me/parabola/mkgmap/Option.java
new file mode 100644
index 0000000..84dd6fb
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/Option.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008, 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;
+
+/**
+ * An option or a key value pair. Immutable class.
+ */
+public class Option {
+ private final String option;
+ private final String value;
+ private final boolean experimental;
+ private final boolean reset;
+
+ protected Option(String optval) {
+ String[] v = optval.split("[=:]", 2);
+
+ String name;
+ String val;
+
+ if (v.length > 1) {
+ name = v[0].trim();
+ val = v[1].trim();
+ } else {
+ name = optval;
+ val = "";
+ }
+
+ boolean reset = false;
+ if (name.startsWith("no-")) {
+ reset = true;
+ name = name.substring(3);
+ val = null;
+ }
+
+ boolean exp = false;
+ if (name.startsWith("x-")) {
+ exp = true;
+ name = name.substring(2);
+ }
+
+ option = name;
+ value = val;
+ experimental = exp;
+ this.reset = reset;
+ }
+
+ protected Option(String option, String value) {
+ this(option + '=' + value);
+ }
+
+ public String getOption() {
+ return option;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public boolean isExperimental() {
+ return experimental;
+ }
+
+ public boolean isReset() {
+ return reset;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/OptionProcessor.java b/src/uk/me/parabola/mkgmap/OptionProcessor.java
new file mode 100644
index 0000000..e02e79f
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/OptionProcessor.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 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: May 26, 2008
+ */
+package uk.me.parabola.mkgmap;
+
+/**
+ * Interface for option processing classes.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface OptionProcessor {
+ /**
+ * Process an option. This is intended for options that change state or
+ * that say how the next filename is to be operated upon.
+ *
+ * @param opt The option.
+ */
+ void processOption(Option opt);
+}
diff --git a/src/uk/me/parabola/mkgmap/Options.java b/src/uk/me/parabola/mkgmap/Options.java
new file mode 100644
index 0000000..07dd0cf
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/Options.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2008 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: May 26, 2008
+ */
+package uk.me.parabola.mkgmap;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Collection;
+import java.util.HashSet;
+
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.scan.TokType;
+import uk.me.parabola.mkgmap.scan.Token;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+/**
+ * Holds and reads options. Like a properties file, but order is important
+ * and events are generated when options are read.
+ *
+ * You can use the normal option syntax <tt>foo=bar</tt>.
+ * You can also use <tt>foo: bar</tt> and for longer options that
+ * span several lines <tt>foo { this can span lines }</tt>
+ *
+ * @author Steve Ratcliffe
+ */
+public class Options {
+ private static final Logger log = Logger.getLogger(Options.class);
+
+ private final OptionProcessor proc;
+
+ // Used to prevent the same file being read more than once.
+ private final Collection<String> readFiles = new HashSet<String>();
+
+ public Options(OptionProcessor proc) {
+ this.proc = proc;
+ }
+
+ /**
+ * Read a config file that contains more options. When the number of
+ * options becomes large it is more convenient to place them in a file.
+ *
+ * If the same file is read more than once, then the second time
+ * will be ignored.
+ *
+ * @param filename The filename to obtain options from.
+ */
+ public void readOptionFile(String filename) throws IOException {
+ log.info("reading option file", filename);
+
+ File file = new File(filename);
+ try {
+ // Don't read the same file twice.
+ String path = file.getCanonicalPath();
+ if (readFiles.contains(path))
+ return;
+ readFiles.add(path);
+ } catch (IOException e) {
+ // Probably want to do more than warn here.
+ log.warn("the config file could not be read");
+ return;
+ }
+
+ Reader r = new FileReader(filename);
+ readOptionFile(r, filename);
+ }
+
+ public void readOptionFile(Reader r, String filename) {
+ BufferedReader br = new BufferedReader(r);
+ TokenScanner ts = new TokenScanner(filename, br);
+ ts.setExtraWordChars("-");
+
+ File file = new File(filename);
+ String parent = file.getParent();
+
+ while (!ts.isEndOfFile()) {
+ Token tok = ts.nextToken();
+ if (tok.isValue("#")) {
+ ts.skipLine();
+ continue;
+ }
+
+ String key = tok.getValue();
+
+ ts.skipSpace();
+ tok = ts.peekToken();
+
+ if (tok.getType() == TokType.SYMBOL) {
+
+ String punc = ts.nextValue();
+ String val;
+ if (punc.equals(":") || punc.equals("=")) {
+ val = ts.readLine();
+ } else if (punc.equals("{")) {
+ ts.skipSpace();
+ val = ts.readUntil(TokType.SYMBOL, "}");
+ ts.nextToken(); // discard the closing brace
+ } else {
+ ts.skipLine();
+ continue;
+ }
+
+ // Relative file names in the file are taken relative to the
+ // location of the argument file.
+ if (key.equals("input-file") && !new File(val).isAbsolute())
+ val = new File(parent, val).getPath();
+
+ proc.processOption(new Option(key, val));
+ } else if (key != null){
+ proc.processOption(new Option(key, ""));
+ } else {
+ ts.skipLine();
+ }
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/Version.java b/src/uk/me/parabola/mkgmap/Version.java
new file mode 100644
index 0000000..975a9c8
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/Version.java
@@ -0,0 +1,66 @@
+/*
+ * File: Version.java
+ *
+ * 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: 12 Dec 2007
+ */
+
+package uk.me.parabola.mkgmap;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * Definitions of version numbers.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Version {
+
+ public static final String VERSION = getSvnVersion();
+
+ // A default version to use. This will be changed from time to time to
+ // be the then current version number with a 'svn' suffix. If this shows
+ // up then a more accurate version was not available, but it may be useful
+ // to know roughly.
+ private static final String DEFAULT_VERSION = "svn";
+
+ /**
+ * Get the version number if we can find one, else a default string.
+ * This looks in a file called mkgmap-version.properties on the
+ * classpath.
+ * This is created outside of the system by the build script.
+ *
+ * @return The version number or a default string if a version number
+ * cannot be found.
+ */
+ private static String getSvnVersion() {
+ InputStream is = Version.class.getResourceAsStream("/mkgmap-version.properties");
+
+ if (is == null)
+ return DEFAULT_VERSION;
+
+ Properties props = new Properties();
+ try {
+ props.load(is);
+ } catch (IOException e) {
+ return DEFAULT_VERSION;
+ }
+
+ return props.getProperty("svn.version", DEFAULT_VERSION);
+ }
+}
+
diff --git a/src/uk/me/parabola/mkgmap/build/LayerFilterChain.java b/src/uk/me/parabola/mkgmap/build/LayerFilterChain.java
new file mode 100644
index 0000000..a237e8a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/build/LayerFilterChain.java
@@ -0,0 +1,82 @@
+/*
+ * 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: Dec 1, 2007
+ */
+package uk.me.parabola.mkgmap.build;
+
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.filters.FilterConfig;
+import uk.me.parabola.mkgmap.filters.MapFilter;
+import uk.me.parabola.mkgmap.filters.MapFilterChain;
+import uk.me.parabola.mkgmap.general.MapElement;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This calls all the filters that are applied to an element as it is added to
+ * the map at a particular level.
+ *
+ * @author Steve Ratcliffe
+ */
+public class LayerFilterChain implements MapFilterChain {
+ private static final Logger log = Logger.getLogger(LayerFilterChain.class);
+
+ // The filters that will be applied to the element.
+ private List<MapFilter> filters = new ArrayList<MapFilter>();
+
+ // The position in the filter list.
+ private int position;
+
+ private final FilterConfig config;
+
+ public LayerFilterChain(FilterConfig config) {
+ this.config = config;
+ }
+
+ public void doFilter(MapElement element) {
+ int nfilters = filters.size();
+
+ log.debug("doing filter pos=", position, "out of=", nfilters);
+ if (position >= nfilters)
+ return;
+
+ MapFilter f = filters.get(position++);
+ f.doFilter(element, this);
+ // maintain chain position for repeated calls in the split filters
+ position--;
+ }
+
+ /**
+ * Start the filtering process for an element.
+ * @param element The element to add to the map.
+ */
+ void startFilter(MapElement element) {
+ position = 0;
+ doFilter(element);
+ }
+
+ /**
+ * Add a filter to this chain.
+ *
+ * @param filter Filter to added at the end of the chain.
+ */
+ void addFilter(MapFilter filter) {
+ assert config != null;
+
+ filter.init(config);
+ filters.add(filter);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/build/Locator.java b/src/uk/me/parabola/mkgmap/build/Locator.java
new file mode 100644
index 0000000..cf21504
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/build/Locator.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2006, 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.build;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.MapPoint;
+import uk.me.parabola.mkgmap.general.MapPointKdTree;
+import uk.me.parabola.mkgmap.reader.osm.Tags;
+import uk.me.parabola.util.EnhancedProperties;
+import uk.me.parabola.util.MultiHashMap;
+
+public class Locator {
+ private static final Logger log = Logger.getLogger(Locator.class);
+
+ /** hash map to collect equally named MapPoints*/
+ private final MultiHashMap<String, MapPoint> cityMap = new MultiHashMap<String, MapPoint>();
+
+ private final MapPointKdTree cityFinder = new MapPointKdTree();
+ private final List<MapPoint> placesMap = new ArrayList<MapPoint>();
+
+ /** Contains the tags defined by the option name-tag-list */
+ private final List<String> nameTags;
+
+ private final LocatorConfig locConfig = LocatorConfig.get();
+
+ private final Set<String> locationAutofill;
+
+ private static final double MAX_CITY_DIST = 30000;
+
+ public Locator() {
+ this(new EnhancedProperties());
+ }
+
+ public Locator(EnhancedProperties props) {
+ this.nameTags = LocatorUtil.getNameTags(props);
+ this.locationAutofill = new HashSet<String>(LocatorUtil.parseAutofillOption(props));
+ }
+
+ public void addCityOrPlace(MapPoint p)
+ {
+ if (p.isCity() == false)
+ {
+ log.warn("MapPoint has no city type id: 0x"+Integer.toHexString(p.getType()));
+ return;
+ }
+
+ if (log.isDebugEnabled())
+ log.debug("S City 0x"+Integer.toHexString(p.getType()), p.getName(), "|", p.getCity(), "|", p.getRegion(), "|", p.getCountry());
+
+ // correct the country name
+ // usually this is the translation from 3letter ISO code to country name
+ if(p.getCountry() != null)
+ p.setCountry(normalizeCountry(p.getCountry()));
+
+ resolveIsInInfo(p); // Pre-process the is_in field
+
+ if(p.getCity() != null)
+ {
+ if (log.isDebugEnabled())
+ log.debug(p.getCity(),p.getRegion(),p.getCountry());
+ // Must use p.getName() here because p.getCity() contains the city name of the preprocessed cities
+ addCity(p.getName(), p);
+ }
+ else
+ {
+ // All other places which do not seam to be a real city has to resolved later
+ placesMap.add(p);
+ }
+
+ if (log.isDebugEnabled())
+ log.debug("E City 0x"+Integer.toHexString(p.getType()), p.getName(), "|", p.getCity(), "|", p.getRegion(), "|", p.getCountry());
+ }
+
+ public void setDefaultCountry(String country, String abbr)
+ {
+ locConfig.setDefaultCountry(country, abbr);
+ }
+
+ public String normalizeCountry(String country)
+ {
+ if (country == null) {
+ return null;
+ }
+
+ String iso = locConfig.getCountryISOCode(country);
+ if (iso != null) {
+ String normedCountryName = locConfig.getCountryName(iso, nameTags);
+ if (normedCountryName != null) {
+ log.debug("Country:",country,"ISO:",iso,"Norm:",normedCountryName);
+ return normedCountryName;
+ }
+ }
+
+ // cannot find the country in our config => return the country itself
+ log.debug("Country:",country,"ISO:",iso,"Norm:",country);
+ return country;
+ }
+
+ /**
+ * Checks if the country given by attached tags is already known, adds or completes
+ * the Locator information about this country and return the three letter ISO code
+ * (in case the country is known in the LocatorConfig.xml) or the country name.
+ *
+ * @param tags the countries tags
+ * @return the three letter ISO code or <code>null</code> if ISO code is unknown
+ */
+ public String addCountry(Tags tags) {
+ synchronized (locConfig) {
+ String iso = getCountryISOCode(tags);
+ if (iso == null) {
+ log.warn("Cannot find iso code for country with tags", tags);
+ } else {
+ locConfig.addCountryWithTags(iso, tags);
+ }
+ return iso;
+ }
+ }
+
+ private final static String[] PREFERRED_NAME_TAGS = {"name","name:en","int_name"};
+
+ public String getCountryISOCode(Tags countryTags) {
+ for (String nameTag : PREFERRED_NAME_TAGS) {
+ String nameValue = countryTags.get(nameTag);
+ String isoCode = getCountryISOCode(nameValue);
+ if (isoCode != null) {
+ return isoCode;
+ }
+ }
+
+ for (String countryStr : countryTags.getTagsWithPrefix("name:", false)
+ .values()) {
+ String isoCode = getCountryISOCode(countryStr);
+ if (isoCode != null) {
+ return isoCode;
+ }
+ }
+ return null;
+ }
+
+ public String getCountryISOCode(String country)
+ {
+ return locConfig.getCountryISOCode(country);
+ }
+
+ public int getPOIDispFlag(String country)
+ {
+ return locConfig.getPoiDispFlag(getCountryISOCode(country));
+ }
+
+ private boolean isContinent(String continent)
+ {
+ return locConfig.isContinent(continent);
+ }
+
+
+ /**
+ * resolveIsInInfo tries to get country and region info out of the is_in field
+ * @param p Point to process
+ */
+ private void resolveIsInInfo(MapPoint p)
+ {
+ if (locationAutofill.contains("is_in") == false) {
+ return;
+ }
+
+ if(p.getCountry() != null && p.getRegion() != null && p.getCity() == null)
+ {
+ p.setCity(p.getName());
+ return;
+ }
+
+ if(p.getIsIn() != null)
+ {
+ String[] cityList = p.getIsIn().split(",");
+
+ //System.out.println(p.getIsIn());
+
+ // is_in content is not well defined so we try our best to get some info out of it
+ // Format 1 popular in Germany: "County,State,Country,Continent"
+
+ if(cityList.length > 1 &&
+ isContinent(cityList[cityList.length-1])) // Is last a continent ?
+ {
+ if (p.getCountry() == null) {
+ // The one before continent should be the country
+ p.setCountry(normalizeCountry(cityList[cityList.length-2].trim()));
+ }
+
+ // aks the config which info to use for region info
+ int offset = locConfig.getRegionOffset(getCountryISOCode(p.getCountry())) + 1;
+
+ if(cityList.length > offset && p.getRegion() == null)
+ p.setRegion(cityList[cityList.length-(offset+1)].trim());
+
+ } else
+
+ // Format 2 other way round: "Continent,Country,State,County"
+
+ if(cityList.length > 1 && isContinent(cityList[0])) // Is first a continent ?
+ {
+ if (p.getCountry() == null) {
+ // The one before continent should be the country
+ p.setCountry(normalizeCountry(cityList[1].trim()));
+ }
+
+ int offset = locConfig.getRegionOffset(getCountryISOCode(p.getCountry())) + 1;
+
+ if(cityList.length > offset && p.getRegion() == null)
+ p.setRegion(cityList[offset].trim());
+ } else
+
+ // Format like this "County,State,Country"
+
+ if(p.getCountry() == null && cityList.length > 0)
+ {
+ // I don't like to check for a list of countries but I don't want other stuff in country field
+ String isoCode = locConfig.getCountryISOCode(cityList[cityList.length-1]);
+ if (isoCode != null)
+ {
+ p.setCountry(normalizeCountry(isoCode));
+
+ int offset = locConfig.getRegionOffset(isoCode) + 1;
+
+ if(cityList.length > offset && p.getRegion() == null)
+ p.setRegion(cityList[cityList.length-(offset+1)].trim());
+ }
+ }
+ }
+
+ if(p.getCountry() != null && p.getRegion() != null && p.getCity() == null)
+ {
+ p.setCity(p.getName());
+ }
+ }
+
+ public MapPoint findNextPoint(MapPoint p)
+ {
+ return cityFinder.findNextPoint(p);
+ }
+
+ public MapPoint findNearbyCityByName(MapPoint p) {
+
+ if (p.getCity() == null)
+ return null;
+
+ Collection<MapPoint> nextCityList = cityMap.get(p.getCity());
+ if (nextCityList.isEmpty()) {
+ return null;
+ }
+
+ MapPoint near = null;
+ double minDist = Double.MAX_VALUE;
+ for (MapPoint nextCity : nextCityList) {
+ double dist = p.getLocation().distance(nextCity.getLocation());
+
+ if (dist < minDist) {
+ minDist = dist;
+ near = nextCity;
+ }
+ }
+
+ if (minDist <= MAX_CITY_DIST) // Wrong hit more the 30 km away ?
+ return near;
+ else
+ return null;
+ }
+
+ private MapPoint findCityByIsIn(MapPoint place) {
+
+ if (locationAutofill.contains("is_in") == false) {
+ return null;
+ }
+
+ String isIn = place.getIsIn();
+
+ if (isIn == null) {
+ return null;
+ }
+
+ String[] cityList = isIn.split(",");
+
+ // Go through the isIn string and check if we find a city with this name
+ // Lets hope we find the next bigger city
+
+ double minDist = Double.MAX_VALUE;
+ Collection<MapPoint> nextCityList = null;
+ for (String cityCandidate : cityList) {
+ cityCandidate = cityCandidate.trim();
+
+ Collection<MapPoint> candidateCityList = cityMap.get(cityCandidate);
+ if (candidateCityList.isEmpty() == false) {
+ if (nextCityList == null) {
+ nextCityList = new ArrayList<MapPoint>(candidateCityList.size());
+ }
+ nextCityList.addAll(candidateCityList);
+ }
+ }
+
+ if (nextCityList == null) {
+ // no city name found in the is_in tag
+ return null;
+ }
+
+ MapPoint nearbyCity = null;
+ for (MapPoint nextCity : nextCityList) {
+ double dist = place.getLocation().distance(nextCity.getLocation());
+
+ if (dist < minDist) {
+ minDist = dist;
+ nearbyCity = nextCity;
+ }
+ }
+
+ // Check if the city is closer than MAX_CITY_DIST
+ // otherwise don't use it but issue a warning
+ if (minDist > MAX_CITY_DIST) {
+ log.warn("is_in of", place.getName(), "is far away from",
+ nearbyCity.getName(), (minDist / 1000.0), "km is_in",
+ place.getIsIn());
+ log.warn("Number of cities with this name:", nextCityList.size());
+ }
+
+ return nearbyCity;
+ }
+
+ public void autofillCities() {
+ if (locationAutofill.contains("nearest") == false && locationAutofill.contains("is_in") == false) {
+ return;
+ }
+
+ log.info("Locator City Map contains", cityMap.size(), "entries");
+ log.info("Locator Places Map contains", placesMap.size(), "entries");
+ log.info("Locator Finder KdTree contains", cityFinder.size(), "entries");
+
+ int runCount = 0;
+ int maxRuns = 2;
+ int unresCount;
+
+ do {
+ unresCount = 0;
+
+ for (MapPoint place : placesMap) {
+ if (place != null) {
+
+ // first lets try exact name
+
+ MapPoint near = findCityByIsIn(place);
+
+ // if this didn't worked try to workaround german umlaut
+
+ if (near == null) {
+ // TODO perform a soundslike search
+ }
+
+ if (near != null) {
+ if (place.getCity() == null)
+ place.setCity(near.getCity());
+ if (place.getZip() == null)
+ place.setZip(near.getZip());
+ } else if (locationAutofill.contains("nearest") && (runCount + 1) == maxRuns) {
+ // In the last resolve run just take info from the next
+ // known city
+ near = cityFinder.findNextPoint(place);
+ if (near != null && near.getCountry() != null) {
+ if (place.getCity() == null)
+ place.setCity(place.getName());
+ }
+ }
+
+ if (near != null) {
+ if (place.getRegion() == null)
+ place.setRegion(near.getRegion());
+
+ if (place.getCountry() == null)
+ place.setCountry(near.getCountry());
+
+ }
+
+ if (near == null)
+ unresCount++;
+ }
+ }
+
+ for (int i = 0; i < placesMap.size(); i++) {
+ MapPoint place = placesMap.get(i);
+
+ if (place != null) {
+ if (place.getCity() != null) {
+ addCity(place.getName(), place);
+ placesMap.set(i, null);
+ } else if ((runCount + 1) == maxRuns) {
+ place.setCity(place.getName());
+ addCity(place.getName(), place);
+ }
+ }
+ }
+
+ runCount++;
+
+ log.info("Locator City Map contains", cityMap.size(),
+ "entries after resolver run", runCount,
+ "Still unresolved", unresCount);
+
+ } while (unresCount > 0 && runCount < maxRuns);
+
+ }
+
+ /**
+ * Add MapPoint to cityMap and cityFinder
+ *
+ * @param name Name that is used to find the city
+ * @param p the MapPoint
+ */
+ private void addCity(String name, MapPoint p){
+ if(name != null)
+ {
+ cityMap.add(name, p);
+
+ // add point to the kd-tree
+ cityFinder.add(p);
+ }
+
+ }
+}
+
diff --git a/src/uk/me/parabola/mkgmap/build/LocatorConfig.java b/src/uk/me/parabola/mkgmap/build/LocatorConfig.java
new file mode 100644
index 0000000..d29de30
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/build/LocatorConfig.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2006, 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.build;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import uk.me.parabola.imgfmt.app.trergn.TREHeader;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.reader.osm.Tags;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+public class LocatorConfig {
+ private static final Logger log = Logger.getLogger(LocatorConfig.class);
+
+ /** maps country name (in all variants) to the 3 letter ISO code */
+ private final Map<String,String> isoMap = new HashMap<String,String>();
+ /** maps the ISO code to the offset of the region in the is_in tag */
+ private final Map<String,Integer> regOffsetMap = new HashMap<String,Integer>();
+ /** maps the ISO code to the POI display flag */
+ private final Map<String,Integer> poiDispFlagMap = new HashMap<String,Integer>();
+ /** contains the names of all continents */
+ private final Set<String> continents = new HashSet<String>();
+
+ /** maps ISO => default country name */
+ private final Map<String, String> defaultCountryNames = new HashMap<String, String>();
+
+ /** Maps 3 letter ISO code to all tags of a country */
+ private final Map<String, Tags> countryTagMap = new HashMap<String, Tags>();
+
+ private final static LocatorConfig instance = new LocatorConfig();
+
+ public static LocatorConfig get() {
+ return instance;
+ }
+
+ private LocatorConfig()
+ {
+ loadConfig("/LocatorConfig.xml");
+ }
+
+ private void loadConfig(String fileName)
+ {
+ try
+ {
+ DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+
+ InputStream inStream;
+
+ try
+ {
+ inStream = new FileInputStream("resources/" + fileName);
+ }
+ catch (Exception ex)
+ {
+ inStream = null;
+ }
+
+ if(inStream == null) // If not loaded from disk use from jar file
+ inStream = this.getClass().getResourceAsStream(fileName);
+
+ Document document = builder.parse(inStream);
+
+ Node rootNode = document.getDocumentElement();
+
+ if(rootNode.getNodeName().equals("locator"))
+ {
+ Node cNode = rootNode.getFirstChild();
+
+ while(cNode != null)
+ {
+ if(cNode.getNodeName().equals("continent"))
+ {
+ NamedNodeMap attr = cNode.getAttributes();
+
+ if(attr != null)
+ {
+ Node nameTag = attr.getNamedItem("name");
+ if(nameTag != null)
+ addContinent(nameTag.getNodeValue());
+ }
+
+ }
+
+ if (cNode.getNodeName().equals("country")) {
+ NamedNodeMap attr = cNode.getAttributes();
+ String iso = null;
+ if (attr != null) {
+ Node nameTag = null;
+ Node abrTag = attr.getNamedItem("abr");
+ if (abrTag != null) {
+ iso = abrTag.getNodeValue().toUpperCase().trim().intern();
+ if (iso.length() != 3) {
+ log.error("ISO code (abr) must have three characters: "
+ + iso);
+ }
+ }
+
+ nameTag = attr.getNamedItem("name");
+
+ if (iso != null && nameTag != null) {
+ addISO(nameTag.getNodeValue(), iso);
+ defaultCountryNames.put(iso, nameTag
+ .getNodeValue().trim());
+ }
+
+ if (iso != null)
+ addISO(iso, iso);
+
+ if(iso == null && nameTag != null)
+ addISO(nameTag.getNodeValue(),"");
+
+
+ Node regionOffsetTag = attr.getNamedItem("regionOffset");
+
+ if(regionOffsetTag != null && iso != null)
+ {
+ addRegionOffset(iso,Integer.parseInt(regionOffsetTag.getNodeValue()));
+ }
+
+ int poiDispTag = 0x0;
+ Node streetBeforeHousenumber = attr.getNamedItem("streetBeforeHousenumber");
+ if (streetBeforeHousenumber != null && "true".equals(streetBeforeHousenumber.getNodeValue())) {
+ poiDispTag |= TREHeader.POI_FLAG_STREET_BEFORE_HOUSENUMBER;
+ }
+
+ Node postalcodeBeforeCity = attr.getNamedItem("postalcodeBeforeCity");
+ if (postalcodeBeforeCity != null && "true".equals(postalcodeBeforeCity.getNodeValue())) {
+ poiDispTag |= TREHeader.POI_FLAG_POSTALCODE_BEFORE_CITY;
+ }
+
+ if (poiDispTag != 0x0 && iso != null) {
+ setPoiDispTag(iso, poiDispTag);
+ }
+ }
+
+ if (iso != null) {
+ Node cEntryNode = cNode.getFirstChild();
+ while(cEntryNode != null)
+ {
+ if(cEntryNode.getNodeName().equals("variant"))
+ {
+ Node nodeText = cEntryNode.getFirstChild();
+
+ if (nodeText != null)
+ addISO(nodeText.getNodeValue(), iso);
+ }
+ cEntryNode = cEntryNode.getNextSibling();
+ }
+ }
+ }
+
+ cNode = cNode.getNextSibling();
+ }
+ }
+ else
+ {
+ System.out.println(fileName + "contains invalid root tag " + rootNode.getNodeName());
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ //System.out.println("Something is wrong here");
+ }
+ }
+
+ private void addISO(String country, String iso)
+ {
+ String cStr = country.toUpperCase().trim();
+
+ isoMap.put(cStr,iso);
+ }
+
+ private void addRegionOffset(String iso, Integer offset)
+ {
+ regOffsetMap.put(iso,offset);
+ }
+
+ private void setPoiDispTag(String iso, int flag)
+ {
+ // only two flags are allowed to be configured
+ poiDispFlagMap.put(iso, flag & (TREHeader.POI_FLAG_STREET_BEFORE_HOUSENUMBER | TREHeader.POI_FLAG_POSTALCODE_BEFORE_CITY));
+ }
+
+ private void addContinent(String continent)
+ {
+ String cStr = continent.toUpperCase().trim();
+
+ continents.add(cStr);
+ }
+
+
+ public synchronized void setDefaultCountry(String country, String abbr)
+ {
+ addISO(country, abbr);
+ }
+
+ public synchronized boolean isCountry(String country)
+ {
+ return isoMap.containsKey(country.toUpperCase().trim());
+ }
+
+ public synchronized boolean countryHasTags(String isoCode) {
+ return countryTagMap.containsKey(isoCode);
+ }
+
+ public synchronized String addCountryWithTags(String isoCode, Tags countryTags) {
+
+ if (isoCode == null) {
+ // cannot find three letter iso code for this countries
+ // do not use it
+ log.warn("Cannot find country with tags", countryTags);
+ return null;
+ }
+
+ if (countryHasTags(isoCode)) {
+ // country is already known
+ return isoCode;
+ }
+
+ // add it as new country to the tag map
+ countryTagMap.put(isoCode, countryTags.copy());
+
+ String name = countryTags.get("name");
+ if (name != null) {
+ addISO(name, isoCode);
+ }
+ String int_name = countryTags.get("int_name");
+ if (int_name != null) {
+ addISO(int_name, isoCode);
+ }
+ // add all variants to the abbreviation map
+ for (String countryName : countryTags.getTagsWithPrefix("name:", false).values()) {
+ addISO(countryName, isoCode);
+ }
+ return isoCode;
+ }
+
+ /**
+ * Retrieves the three letter ISO code which is used by the Garmins.
+ * @param country a country name
+ * @return the three letter ISO code (<code>null</code> = unknown)
+ */
+ public synchronized String getCountryISOCode(String country)
+ {
+ if (country == null) {
+ return null;
+ }
+ String res = isoMap.get(country);
+ if (res == null){
+ res = isoMap.get(country.toUpperCase().trim());
+ if (res != null) {
+ isoMap.put(country, res);
+ }
+ }
+ return res;
+ }
+
+ /**
+ * Retrieves the name of a country by its three letter iso code and the list of
+ * name tags. The first available value of the tags in the nameTags list is returned.
+ *
+ * @param isoCode the three letter ISO code
+ * @param nameTags the list of name tags
+ * @return the full country name (<code>null</code> if unknown)
+ */
+ public synchronized String getCountryName(String isoCode, List<String> nameTags) {
+ Tags countryTags = countryTagMap.get(isoCode);
+ if (countryTags==null) {
+ // no tags for this country available
+ // return the default country name from the LocatorConfig.xml
+ return defaultCountryNames.get(isoCode);
+ }
+
+ // search for the first available tag of the nameTags list
+ for (String nameTag : nameTags) {
+ String name = countryTags.get(nameTag);
+ if (name != null) {
+ return name;
+ }
+ }
+
+ // last try: just the simple "name" tag
+ return countryTags.get("name");
+ }
+
+ public synchronized int getRegionOffset(String iso)
+ {
+ if (iso == null) {
+ return 1;
+ }
+
+ Integer regOffset = regOffsetMap.get(iso);
+
+ if(regOffset != null)
+ return regOffset;
+ else
+ return 1; // Default is 1 the next string after before country
+ }
+
+ public synchronized int getPoiDispFlag(String iso)
+ {
+ if (iso == null) {
+ return 0;
+ }
+
+ Integer flag = poiDispFlagMap.get(iso);
+
+ if(flag != null)
+ return flag;
+ else
+ return 0; // Default is 0
+ }
+
+ public synchronized boolean isContinent(String continent)
+ {
+ String s = continent.toUpperCase().trim();
+ return continents.contains(s);
+ }
+}
+
diff --git a/src/uk/me/parabola/mkgmap/build/LocatorUtil.java b/src/uk/me/parabola/mkgmap/build/LocatorUtil.java
new file mode 100644
index 0000000..3bb11b7
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/build/LocatorUtil.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2006, 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.build;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import uk.me.parabola.util.EnhancedProperties;
+
+public class LocatorUtil {
+
+ private static final Pattern COMMA_OR_SPACE_PATTERN = Pattern
+ .compile("[,\\s]+");
+
+ public static List<String> getNameTags(Properties props) {
+ String nameTagProp = props.getProperty("name-tag-list", "name");
+ return Arrays.asList(COMMA_OR_SPACE_PATTERN.split(nameTagProp));
+ }
+
+ /**
+ * Parses the parameters of the location-autofill option. Establishes also downwards
+ * compatibility with the old integer values of location-autofill.
+ * @param props program properties
+ * @return the options
+ */
+ public static Set<String> parseAutofillOption(EnhancedProperties props) {
+ String optionStr = props.getProperty("location-autofill", null);
+ if (optionStr == null) {
+ return Collections.emptySet();
+ }
+
+ Set<String> autofillOptions = new HashSet<String>(Arrays.asList(COMMA_OR_SPACE_PATTERN
+ .split(optionStr)));
+
+ // convert the old autofill options to the new parameters
+ if (autofillOptions.contains("0")) {
+ autofillOptions.add("is_in");
+ autofillOptions.remove("0");
+ }
+ if (autofillOptions.contains("1")) {
+ autofillOptions.add("is_in");
+ // PENDING: fuzzy search
+ autofillOptions.remove("1");
+ }
+ if (autofillOptions.contains("2")) {
+ autofillOptions.add("is_in");
+ // PENDING: fuzzy search
+ autofillOptions.add("nearest");
+ autofillOptions.remove("2");
+ }
+ if (autofillOptions.contains("3")) {
+ autofillOptions.add("is_in");
+ // PENDING: fuzzy search
+ autofillOptions.add("nearest");
+ autofillOptions.remove("3");
+ }
+ return autofillOptions;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/build/MapArea.java b/src/uk/me/parabola/mkgmap/build/MapArea.java
new file mode 100644
index 0000000..a3588c4
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/build/MapArea.java
@@ -0,0 +1,561 @@
+/*
+ * 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: 21-Jan-2007
+ */
+package uk.me.parabola.mkgmap.build;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.trergn.Overview;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.filters.FilterConfig;
+import uk.me.parabola.mkgmap.filters.LineSizeSplitterFilter;
+import uk.me.parabola.mkgmap.filters.LineSplitterFilter;
+import uk.me.parabola.mkgmap.filters.MapFilterChain;
+import uk.me.parabola.mkgmap.filters.PolygonSplitterFilter;
+import uk.me.parabola.mkgmap.filters.PolygonSubdivSizeSplitterFilter;
+import uk.me.parabola.mkgmap.general.MapDataSource;
+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.general.RoadNetwork;
+
+/**
+ * A sub area of the map. We have to divide the map up into areas to meet the
+ * format of the Garmin map. This class holds all the map elements that belong
+ * to a particular area and provides a way of splitting areas into smaller ones.
+ *
+ * It also acts as a map data source so that we can derive lower level
+ * areas from it.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MapArea implements MapDataSource {
+ private static final Logger log = Logger.getLogger(MapArea.class);
+
+ private static final int INITIAL_CAPACITY = 100;
+ private static final int MAX_RESOLUTION = 24;
+
+ public static final int POINT_KIND = 0;
+ public static final int LINE_KIND = 1;
+ public static final int SHAPE_KIND = 2;
+ public static final int XT_POINT_KIND = 3;
+ public static final int XT_LINE_KIND = 4;
+ public static final int XT_SHAPE_KIND = 5;
+ public static final int NUM_KINDS = 6;
+
+ // This is the initial area.
+ private final Area bounds;
+
+ // Because ways may extend beyond the bounds, we keep track of the actual
+ // bounding box here.
+ private int minLat = Integer.MAX_VALUE;
+ private int minLon = Integer.MAX_VALUE;
+ private int maxLat = Integer.MIN_VALUE;
+ private int maxLon = Integer.MIN_VALUE;
+
+ // The contents of the area.
+ private final List<MapPoint> points = new ArrayList<MapPoint>(INITIAL_CAPACITY);
+ private final List<MapLine> lines = new ArrayList<MapLine>(INITIAL_CAPACITY);
+ private final List<MapShape> shapes = new ArrayList<MapShape>(INITIAL_CAPACITY);
+
+ // amount of space required for the contents
+ private final int[] sizes = new int[NUM_KINDS];
+
+ private int nActivePoints;
+ private int nActiveIndPoints;
+ private int nActiveLines;
+ private int nActiveShapes;
+
+ /** The resolution that this area is at */
+ private final int areaResolution;
+
+ /**
+ * Create a map area from the given map data source. This map
+ * area will have the same bounds as the map data source and
+ * will contain all the same map elements.
+ *
+ * @param src The map data source to initialise this area with.
+ * @param resolution The resolution of this area.
+ */
+ public MapArea(MapDataSource src, int resolution) {
+ this.areaResolution = 0;
+ this.bounds = src.getBounds();
+ addToBounds(bounds);
+
+ for (MapPoint p : src.getPoints()) {
+ if(bounds.contains(p.getLocation()))
+ addPoint(p);
+ else
+ log.error("Point with type 0x" + Integer.toHexString(p.getType()) + " at " + p.getLocation().toOSMURL() + " is outside of the map area centred on " + bounds.getCenter().toOSMURL() + " width = " + bounds.getWidth() + " height = " + bounds.getHeight() + " resolution = " + resolution);
+ }
+ addLines(src, resolution);
+ addPolygons(src, resolution);
+ }
+
+ /**
+ * Add the polygons, making sure that they are not too big.
+ * @param src The map data.
+ * @param resolution The resolution of this layer.
+ */
+ private void addPolygons(MapDataSource src, final int resolution) {
+ MapFilterChain chain = new MapFilterChain() {
+ public void doFilter(MapElement element) {
+ MapShape shape = (MapShape) element;
+ shapes.add(shape);
+ addToBounds(shape.getBounds());
+ addSize(element, shape.hasExtendedType()? XT_SHAPE_KIND : SHAPE_KIND);
+ }
+ };
+
+ PolygonSubdivSizeSplitterFilter filter = new PolygonSubdivSizeSplitterFilter();
+ FilterConfig config = new FilterConfig();
+ config.setResolution(resolution);
+ config.setBounds(bounds);
+ filter.init(config);
+
+ for (MapShape s : src.getShapes()) {
+ filter.doFilter(s, chain);
+ }
+ }
+
+ /**
+ * Add the lines, making sure that they are not too big for resolution
+ * that we are working with.
+ * @param src The map data.
+ * @param resolution The current resolution of the layer.
+ */
+ private void addLines(MapDataSource src, final int resolution) {
+ // Split lines for size, such that it is appropriate for the
+ // resolution that it is at.
+ MapFilterChain chain = new MapFilterChain() {
+ public void doFilter(MapElement element) {
+ MapLine line = (MapLine) element;
+ lines.add(line);
+ addToBounds(line.getBounds());
+ addSize(element, line.hasExtendedType()? XT_LINE_KIND : LINE_KIND);
+ }
+ };
+
+ LineSizeSplitterFilter filter = new LineSizeSplitterFilter();
+ FilterConfig config = new FilterConfig();
+ config.setResolution(resolution);
+ config.setBounds(bounds);
+ filter.init(config);
+ for (MapLine l : src.getLines()) {
+ filter.doFilter(l, chain);
+ }
+ }
+
+ /**
+ * Create an map area with the given initial bounds.
+ *
+ * @param area The bounds for this area.
+ * @param res The minimum resolution for this area.
+ */
+ private MapArea(Area area, int res) {
+ bounds = area;
+ areaResolution = res;
+ addToBounds(area);
+ }
+
+ /**
+ * Split this area into several pieces. All the map elements are reallocated
+ * to the appropriate subarea. Usually this instance would now be thrown
+ * away and the new sub areas used instead.
+ *
+ * @param nx The number of pieces in the x (longitude) direction.
+ * @param ny The number of pieces in the y direction.
+ * @param resolution The resolution of the level.
+ * @param bounds the bounding box that is used to create the areas.
+ * @return An array of the new MapArea's.
+ */
+ public MapArea[] split(int nx, int ny, int resolution, Area bounds) {
+ Area[] areas = bounds.split(nx, ny);
+ MapArea[] mapAreas = new MapArea[nx * ny];
+ log.info("Splitting area " + bounds + " into " + nx + "x" + ny + " pieces at resolution " + resolution);
+ boolean useNormalSplit = true;
+ while (true){
+ for (int i = 0; i < nx * ny; i++) {
+ mapAreas[i] = new MapArea(areas[i], resolution);
+ if (log.isDebugEnabled())
+ log.debug("area before", mapAreas[i].getBounds());
+ }
+
+ int xbase = areas[0].getMinLong();
+ int ybase = areas[0].getMinLat();
+ int dx = areas[0].getWidth();
+ int dy = areas[0].getHeight();
+
+ boolean[] used = new boolean[nx * ny];
+ // Now sprinkle each map element into the correct map area.
+ for (MapPoint p : this.points) {
+ int pos = pickArea(mapAreas, p, xbase, ybase, nx, ny, dx, dy);
+ mapAreas[pos].addPoint(p);
+ used[pos] = true;
+ }
+
+
+ int areaIndex = 0;
+ for (MapLine l : this.lines) {
+ // Drop any zero sized lines.
+ if (l.getBounds().getMaxDimension() <= 0)
+ continue;
+ if (useNormalSplit)
+ areaIndex = pickArea(mapAreas, l, xbase, ybase, nx, ny, dx, dy);
+ else
+ areaIndex = ++areaIndex % mapAreas.length;
+ mapAreas[areaIndex].addLine(l);
+ used[areaIndex] = true;
+ }
+
+ for (MapShape e : this.shapes) {
+ if (useNormalSplit)
+ areaIndex = pickArea(mapAreas, e, xbase, ybase, nx, ny, dx, dy);
+ else
+ areaIndex = ++areaIndex % mapAreas.length;
+ mapAreas[areaIndex].addShape(e);
+ used[areaIndex] = true;
+ }
+ // detect special case
+ if (useNormalSplit && mapAreas.length == 2 && bounds.getMaxDimension() < 2 * (MapSplitter.MIN_DIMENSION + 1)
+ && used[0] != used[1]
+ && (this.lines.size() > 1 || this.shapes.size() > 1)) {
+ /* if we get here we probably have two or more identical long ways or
+ * big shapes with the same center point. We can safely distribute
+ * them equally to the two areas.
+ */
+ useNormalSplit = false;
+ continue;
+ }
+ return mapAreas;
+ }
+ }
+
+
+ /**
+ * Get the full bounds of this area. As lines and polylines are
+ * added then may go outside of the initial area. When this happens
+ * we need to increase the size of the area.
+ *
+ * @return The full size required to hold all the included
+ * elements.
+ */
+ public Area getFullBounds() {
+ return new Area(minLat, minLon, maxLat, maxLon);
+ }
+
+ /**
+ * Get an estimate of the size of the RGN space that will be required to
+ * hold the elements
+ *
+ * @return Estimates of the max size that will be needed in the RGN file
+ * for the points/lines/shapes in this sub-division.
+ */
+ public int[] getEstimatedSizes() {
+ return sizes;
+ }
+
+ /**
+ * Get the initial bounds of this area. That is the initial
+ * bounds before anything was added.
+ *
+ * @return The initial bounds as when it was created.
+ * @see #getFullBounds
+ */
+ public Area getBounds() {
+ return bounds;
+ }
+
+ /**
+ * Get a list of all the points.
+ *
+ * @return The points.
+ */
+ public List<MapPoint> getPoints() {
+ return points;
+ }
+
+ /**
+ * Get a list of all the lines.
+ *
+ * @return The lines.
+ */
+ public List<MapLine> getLines() {
+ return lines;
+ }
+
+ /**
+ * Get a list of all the shapes.
+ *
+ * @return The shapes.
+ */
+ public List<MapShape> getShapes() {
+ return shapes;
+ }
+
+ public RoadNetwork getRoadNetwork() {
+ // I don't think this is needed here.
+ return null;
+ }
+
+ /**
+ * This is not used for areas.
+ * @return Always returns null.
+ */
+ public List<Overview> getOverviews() {
+ return null;
+ }
+
+ /**
+ * True if there are any 'active' points in this area. Ie ones that will be
+ * shown because their resolution is at least as high as that of the
+ * area.
+ *
+ * @return True if any active points in this area.
+ */
+ public boolean hasPoints() {
+ return nActivePoints > 0;
+ }
+
+ /**
+ * True if there are active indexed points in the area.
+ * @return True if any active indexed points in the area.
+ */
+ public boolean hasIndPoints() {
+ return nActiveIndPoints > 0;
+ }
+
+ /**
+ * True if there are any 'active' points in this area. Ie ones that will be
+ * shown because their resolution is at least as high as that of the
+ * area.
+ *
+ * @return True if any active points in this area.
+ */
+ public boolean hasLines() {
+ return nActiveLines > 0;
+ }
+
+ /**
+ * Return number of lines in this area.
+ */
+ public int getNumLines() {
+ return nActiveLines;
+ }
+
+ /**
+ * Return number of shapes in this area.
+ */
+ public int getNumShapes() {
+ return nActiveShapes;
+ }
+
+ /**
+ * Return number of points in this area.
+ */
+ public int getNumPoints() {
+ return nActivePoints + nActiveIndPoints;
+ }
+
+ /**
+ * True if there are any 'active' points in this area. Ie ones that will be
+ * shown because their resolution is at least as high as that of the
+ * area.
+ *
+ * @return True if any active points in this area.
+ */
+ public boolean hasShapes() {
+ return nActiveShapes > 0;
+ }
+
+ /**
+ * Add an estimate of the size that will be required to hold this element
+ * if it should be displayed at the given resolution. We also keep track
+ * of the number of <i>active</i> elements here ie elements that will be
+ * shown because they are at a resolution at least as great as the resolution
+ * of the area.
+ *
+ * @param p The element containing the minimum resolution that it will be
+ * displayed at.
+ * @param kind What kind of element this is KIND_POINT etc.
+ */
+ private void addSize(MapElement p, int kind) {
+
+ int res = p.getMinResolution();
+ if (res > MAX_RESOLUTION)
+ return;
+
+ int numPoints;
+ int numElements;
+
+ switch (kind) {
+ case POINT_KIND:
+ case XT_POINT_KIND:
+ if(res <= areaResolution) {
+ // Points are predictably less than 9 bytes.
+ sizes[kind] += 9;
+ if(!p.hasExtendedType()) {
+ if(((MapPoint) p).isCity())
+ nActiveIndPoints++;
+ else
+ nActivePoints++;
+ }
+ }
+ break;
+
+ case LINE_KIND:
+ case XT_LINE_KIND:
+ if(res <= areaResolution) {
+ // Estimate the size taken by lines and shapes as a constant plus
+ // a factor based on the number of points.
+ numPoints = ((MapLine) p).getPoints().size();
+ numElements = 1 + ((numPoints - 1) / LineSplitterFilter.MAX_POINTS_IN_LINE);
+ sizes[kind] += numElements * 11 + numPoints * 4;
+ if (!p.hasExtendedType())
+ nActiveLines += numElements;
+ }
+ break;
+
+ case SHAPE_KIND:
+ case XT_SHAPE_KIND:
+ if(res <= areaResolution) {
+ // Estimate the size taken by lines and shapes as a constant plus
+ // a factor based on the number of points.
+ numPoints = ((MapLine) p).getPoints().size();
+ numElements = 1 + ((numPoints - 1) / PolygonSplitterFilter.MAX_POINT_IN_ELEMENT);
+ sizes[kind] += numElements * 11 + numPoints * 4;
+ if (!p.hasExtendedType())
+ nActiveShapes += numElements;
+ }
+ break;
+
+ default:
+ log.error("should not be here");
+ assert false;
+ break;
+ }
+
+ }
+
+ /**
+ * Add a single point to this area.
+ *
+ * @param p The point to add.
+ */
+ private void addPoint(MapPoint p) {
+ points.add(p);
+ addToBounds(p.getBounds());
+ addSize(p, p.hasExtendedType()? XT_POINT_KIND : POINT_KIND);
+ }
+
+ /**
+ * Add a single line to this area.
+ *
+ * @param l The line to add.
+ */
+ private void addLine(MapLine l) {
+ lines.add(l);
+ addToBounds(l.getBounds());
+ addSize(l, l.hasExtendedType()? XT_LINE_KIND : LINE_KIND);
+ }
+
+ /**
+ * Add a single shape to this map area.
+ *
+ * @param s The shape to add.
+ */
+ private void addShape(MapShape s) {
+ shapes.add(s);
+ addToBounds(s.getBounds());
+ addSize(s, s.hasExtendedType()? XT_SHAPE_KIND : SHAPE_KIND);
+ }
+
+ /**
+ * Add to the bounds of this area. That is the new bounds
+ * for this area will cover the existing ones plus the new
+ * area.
+ *
+ * @param a Area to add into this map area.
+ */
+ private void addToBounds(Area a) {
+ int l = a.getMinLat();
+ if (l < minLat)
+ minLat = l;
+ l = a.getMaxLat();
+ if (l > maxLat)
+ maxLat = l;
+
+ l = a.getMinLong();
+ if (l < minLon)
+ minLon = l;
+ l = a.getMaxLong();
+ if (l > maxLon)
+ maxLon = l;
+ }
+
+ /**
+ * Out of all the available areas, it picks the one that the map element
+ * should be placed into.
+ *
+ * Since we know how the area is divided (equal sizes) we can work out
+ * which one it fits into without stepping through them all and checking
+ * coordinates.
+ *
+ * @param areas The available areas to choose from.
+ * @param e The map element.
+ * @param xbase The x coord at the origin
+ * @param ybase The y coord of the origin
+ * @param nx number of divisions.
+ * @param ny number of divisions in y.
+ * @param dx The size of each division (x direction)
+ * @param dy The size of each division (y direction)
+ * @return The index to areas where the map element fits.
+ */
+ private int pickArea(MapArea[] areas, MapElement e,
+ int xbase, int ybase,
+ int nx, int ny,
+ int dx, int dy)
+ {
+ int x = e.getLocation().getLongitude();
+ int y = e.getLocation().getLatitude();
+
+ int xcell = (x - xbase) / dx;
+ int ycell = (y - ybase) / dy;
+
+ if (xcell < 0) {
+ log.info("xcell was", xcell, "x", x, "xbase", xbase);
+ xcell = 0;
+ }
+ if (ycell < 0) {
+ log.info("ycell was", ycell, "y", y, "ybase", ybase);
+ ycell = 0;
+ }
+
+ if (xcell >= nx)
+ xcell = nx - 1;
+ if (ycell >= ny)
+ ycell = ny - 1;
+
+ if (log.isDebugEnabled()) {
+ log.debug("adding", e.getLocation(), "to", xcell, "/", ycell,
+ areas[xcell * ny + ycell].getBounds());
+ }
+ return xcell * ny + ycell;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/build/MapBuilder.java b/src/uk/me/parabola/mkgmap/build/MapBuilder.java
new file mode 100644
index 0000000..c86884a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/build/MapBuilder.java
@@ -0,0 +1,1292 @@
+/*
+ * Copyright (C) 2007 - 2012.
+ *
+ * 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.build;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.ExitException;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.Exit;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.lbl.City;
+import uk.me.parabola.imgfmt.app.lbl.Country;
+import uk.me.parabola.imgfmt.app.lbl.ExitFacility;
+import uk.me.parabola.imgfmt.app.lbl.Highway;
+import uk.me.parabola.imgfmt.app.lbl.LBLFile;
+import uk.me.parabola.imgfmt.app.lbl.POIRecord;
+import uk.me.parabola.imgfmt.app.lbl.Region;
+import uk.me.parabola.imgfmt.app.lbl.Zip;
+import uk.me.parabola.imgfmt.app.map.Map;
+import uk.me.parabola.imgfmt.app.net.NETFile;
+import uk.me.parabola.imgfmt.app.net.NODFile;
+import uk.me.parabola.imgfmt.app.net.RoadDef;
+import uk.me.parabola.imgfmt.app.net.RouteCenter;
+import uk.me.parabola.imgfmt.app.trergn.ExtTypeAttributes;
+import uk.me.parabola.imgfmt.app.trergn.Overview;
+import uk.me.parabola.imgfmt.app.trergn.Point;
+import uk.me.parabola.imgfmt.app.trergn.PointOverview;
+import uk.me.parabola.imgfmt.app.trergn.Polygon;
+import uk.me.parabola.imgfmt.app.trergn.PolygonOverview;
+import uk.me.parabola.imgfmt.app.trergn.Polyline;
+import uk.me.parabola.imgfmt.app.trergn.PolylineOverview;
+import uk.me.parabola.imgfmt.app.trergn.RGNFile;
+import uk.me.parabola.imgfmt.app.trergn.RGNHeader;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+import uk.me.parabola.imgfmt.app.trergn.TREFile;
+import uk.me.parabola.imgfmt.app.trergn.Zoom;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.Version;
+import uk.me.parabola.mkgmap.combiners.OverviewBuilder;
+import uk.me.parabola.mkgmap.filters.BaseFilter;
+import uk.me.parabola.mkgmap.filters.DouglasPeuckerFilter;
+import uk.me.parabola.mkgmap.filters.FilterConfig;
+import uk.me.parabola.mkgmap.filters.LineMergeFilter;
+import uk.me.parabola.mkgmap.filters.LinePreparerFilter;
+import uk.me.parabola.mkgmap.filters.LineSplitterFilter;
+import uk.me.parabola.mkgmap.filters.MapFilter;
+import uk.me.parabola.mkgmap.filters.MapFilterChain;
+import uk.me.parabola.mkgmap.filters.PolygonSplitterFilter;
+import uk.me.parabola.mkgmap.filters.PreserveHorizontalAndVerticalLinesFilter;
+import uk.me.parabola.mkgmap.filters.RemoveEmpty;
+import uk.me.parabola.mkgmap.filters.RemoveObsoletePointsFilter;
+import uk.me.parabola.mkgmap.filters.RoundCoordsFilter;
+import uk.me.parabola.mkgmap.filters.SizeFilter;
+import uk.me.parabola.mkgmap.general.LevelInfo;
+import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
+import uk.me.parabola.mkgmap.general.MapDataSource;
+import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapExitPoint;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapPoint;
+import uk.me.parabola.mkgmap.general.MapRoad;
+import uk.me.parabola.mkgmap.general.MapShape;
+import uk.me.parabola.mkgmap.general.RoadNetwork;
+import uk.me.parabola.mkgmap.reader.MapperBasedMapDataSource;
+import uk.me.parabola.mkgmap.reader.osm.GType;
+import uk.me.parabola.mkgmap.reader.overview.OverviewMapDataSource;
+import uk.me.parabola.util.Configurable;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * This is the core of the code to translate from the general representation
+ * into the garmin representation.
+ *
+ * We need to go through the data several times, once for each level, filter
+ * out features that are not required at the level and simplify paths for
+ * lower resolutions if required.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MapBuilder implements Configurable {
+ private static final Logger log = Logger.getLogger(MapBuilder.class);
+ private static final int CLEAR_TOP_BITS = (32 - 15);
+
+ private static final int MIN_SIZE_LINE = 1;
+
+ private final java.util.Map<MapPoint,POIRecord> poimap = new HashMap<MapPoint,POIRecord>();
+ private final java.util.Map<MapPoint,City> cityMap = new HashMap<MapPoint,City>();
+ private List<String> mapInfo = new ArrayList<String>();
+ private List<String> copyrights = new ArrayList<String>();
+
+ private boolean doRoads;
+ private boolean routingErrorMsgPrinted;
+
+ private Locator locator;
+
+ private final java.util.Map<String, Highway> highways = new HashMap<String, Highway>();
+
+ /** name that is used for cities which name are unknown */
+ private final static String UNKNOWN_CITY_NAME = "";
+
+ private Country defaultCountry;
+ private String countryName = "COUNTRY";
+ private String countryAbbr = "ABC";
+ private String regionName;
+ private String regionAbbr;
+
+ private Set<String> locationAutofill;
+
+ private int minSizePolygon;
+ private String polygonSizeLimitsOpt;
+ private HashMap<Integer,Integer> polygonSizeLimits = null;
+ private double reducePointError;
+ private double reducePointErrorPolygon;
+ private boolean mergeLines;
+
+ private boolean poiAddresses;
+ private int poiDisplayFlags;
+ private boolean enableLineCleanFilters = true;
+ private boolean makePOIIndex;
+ private int routeCenterBoundaryType;
+
+ private LBLFile lblFile;
+
+ private String licenseFileName;
+
+ public MapBuilder() {
+ regionName = null;
+ locationAutofill = Collections.emptySet();
+ locator = new Locator();
+ }
+
+ public void config(EnhancedProperties props) {
+
+ countryName = props.getProperty("country-name", countryName);
+ countryAbbr = props.getProperty("country-abbr", countryAbbr);
+ regionName = props.getProperty("region-name", null);
+ regionAbbr = props.getProperty("region-abbr", null);
+ minSizePolygon = props.getProperty("min-size-polygon", 8);
+ polygonSizeLimitsOpt = props.getProperty("polygon-size-limits", null);
+ reducePointError = props.getProperty("reduce-point-density", 2.6);
+ reducePointErrorPolygon = props.getProperty("reduce-point-density-polygon", -1);
+ if (reducePointErrorPolygon == -1)
+ reducePointErrorPolygon = reducePointError;
+ mergeLines = props.containsKey("merge-lines");
+
+ makePOIIndex = props.getProperty("make-poi-index", false);
+
+ if(props.getProperty("poi-address") != null)
+ poiAddresses = true;
+
+ routeCenterBoundaryType = props.getProperty("route-center-boundary", 0);
+
+ licenseFileName = props.getProperty("license-file", null);
+
+ locationAutofill = LocatorUtil.parseAutofillOption(props);
+
+ locator = new Locator(props);
+ locator.setDefaultCountry(countryName, countryAbbr);
+ }
+
+ /**
+ * Main method to create the map, just calls out to several routines
+ * that do the work.
+ *
+ * @param map The map.
+ * @param src The map data.
+ */
+ public void makeMap(Map map, LoadableMapDataSource src) {
+
+ RGNFile rgnFile = map.getRgnFile();
+ TREFile treFile = map.getTreFile();
+ lblFile = map.getLblFile();
+ NETFile netFile = map.getNetFile();
+
+ if(routeCenterBoundaryType != 0 &&
+ netFile != null &&
+ src instanceof MapperBasedMapDataSource) {
+ for(RouteCenter rc : src.getRoadNetwork().getCenters()) {
+ ((MapperBasedMapDataSource)src).addBoundaryLine(rc.getArea(), routeCenterBoundaryType, rc.reportSizes());
+ }
+ }
+ if (mapInfo.isEmpty())
+ getMapInfo();
+
+ normalizeCountries(src);
+
+ processCities(map, src);
+ processRoads(map,src);
+ processPOIs(map, src);
+ processOverviews(map, src);
+ processInfo(map, src);
+ makeMapAreas(map, src);
+
+ treFile.setLastRgnPos(rgnFile.position() - RGNHeader.HEADER_LEN);
+
+ rgnFile.write();
+ treFile.write(rgnFile.haveExtendedTypes());
+ treFile.writePost();
+ lblFile.write();
+ lblFile.writePost();
+
+ if (netFile != null) {
+ RoadNetwork network = src.getRoadNetwork();
+ netFile.setNetwork(network.getRoadDefs());
+ NODFile nodFile = map.getNodFile();
+ if (nodFile != null) {
+ nodFile.setNetwork(network.getCenters(), network.getRoadDefs(), network.getBoundary());
+ nodFile.write();
+ }
+ netFile.write(lblFile.numCities(), lblFile.numZips());
+
+ if (nodFile != null) {
+ nodFile.writePost();
+ }
+ netFile.writePost(rgnFile.getWriter());
+ }
+ }
+
+ private Country getDefaultCountry() {
+ if (defaultCountry == null && lblFile != null) {
+ defaultCountry = lblFile.createCountry(countryName, countryAbbr);
+ }
+ return defaultCountry;
+ }
+
+ /**
+ * Retrieves the region with the default name in the given country.
+ * @param country the country ({@code null} = use default country)
+ * @return the default region in the given country ({@code null} if not available)
+ */
+ private Region getDefaultRegion(Country country) {
+ if (lblFile==null || regionName == null) {
+ return null;
+ }
+ if (country == null) {
+ if (getDefaultCountry() == null) {
+ return null;
+ } else {
+ return lblFile.createRegion(getDefaultCountry(), regionName, regionAbbr);
+ }
+ } else {
+ return lblFile.createRegion(country, regionName, regionAbbr);
+ }
+ }
+
+ /**
+ * Process the country names of all elements and normalize them
+ * so that one consistent country name is used for the same country
+ * instead of different spellings.
+ * @param src the source of elements
+ */
+ private void normalizeCountries(MapDataSource src) {
+ for (MapPoint p : src.getPoints()) {
+ String countryStr = p.getCountry();
+ if (countryStr != null) {
+ countryStr = locator.normalizeCountry(countryStr);
+ p.setCountry(countryStr);
+ }
+ }
+
+ for (MapLine l : src.getLines()) {
+ String countryStr = l.getCountry();
+ if (countryStr != null) {
+ countryStr = locator.normalizeCountry(countryStr);
+ l.setCountry(countryStr);
+ }
+ }
+
+ // shapes do not have address information
+ // untag the following lines if this is wrong
+// for (MapShape s : src.getShapes()) {
+// String countryStr = s.getCountry();
+// if (countryStr != null) {
+// countryStr = locator.normalizeCountry(countryStr);
+// s.setCountry(countryStr);
+// }
+// }
+
+ }
+
+ /**
+ * Processing of Cities
+ *
+ * Fills the city list in lbl block that is required for find by name
+ * It also builds up information that is required to get address info
+ * for the POIs
+ *
+ * @param map The map.
+ * @param src The map data.
+ */
+ private void processCities(Map map, MapDataSource src) {
+ LBLFile lbl = map.getLblFile();
+
+ if (locationAutofill.isEmpty() == false) {
+ // collect the names of the cities
+ for (MapPoint p : src.getPoints()) {
+ if(p.isCity() && p.getName() != null)
+ locator.addCityOrPlace(p); // Put the city info the map for missing info
+ }
+
+ locator.autofillCities(); // Try to fill missing information that include search of next city
+ }
+
+ for (MapPoint p : src.getPoints())
+ {
+ if(p.isCity() && p.getName() != null)
+ {
+ String countryStr = p.getCountry();
+ Country thisCountry;
+ if(countryStr != null) {
+ thisCountry = lbl.createCountry(countryStr, locator.getCountryISOCode(countryStr));
+ } else
+ thisCountry = getDefaultCountry();
+
+ String regionStr = p.getRegion();
+ Region thisRegion;
+ if(regionStr != null)
+ {
+ thisRegion = lbl.createRegion(thisCountry,regionStr, null);
+ }
+ else
+ thisRegion = getDefaultRegion(thisCountry);
+
+ City thisCity;
+ if(thisRegion != null)
+ thisCity = lbl.createCity(thisRegion, p.getName(), true);
+ else
+ thisCity = lbl.createCity(thisCountry, p.getName(), true);
+
+ cityMap.put(p, thisCity);
+ }
+ }
+
+ }
+
+ private void processRoads(Map map, MapDataSource src) {
+ LBLFile lbl = map.getLblFile();
+ MapPoint searchPoint = new MapPoint();
+ for (MapLine line : src.getLines()) {
+ if(line.isRoad()) {
+ String cityName = line.getCity();
+ String cityCountryName = line.getCountry();
+ String cityRegionName = line.getRegion();
+ String zipStr = line.getZip();
+
+ if(cityName == null && locationAutofill.contains("nearest")) {
+ // Get name of next city if untagged
+
+ searchPoint.setLocation(line.getLocation());
+ MapPoint nextCity = locator.findNextPoint(searchPoint);
+
+ if(nextCity != null) {
+ cityName = nextCity.getCity();
+ // city/region/country fields should match to the found city
+ cityCountryName = nextCity.getCountry();
+ cityRegionName = nextCity.getRegion();
+
+ // use the zip code only if no zip code is known
+ if(zipStr == null)
+ zipStr = nextCity.getZip();
+ }
+ }
+
+ if (cityName == null && (cityCountryName != null || cityRegionName != null)) {
+ // if city name is unknown and region and/or country is known
+ // use empty name for the city
+ cityName = UNKNOWN_CITY_NAME;
+ }
+
+ if(cityName != null) {
+
+ Country cc = (cityCountryName == null)? getDefaultCountry() : lbl.createCountry(cityCountryName, locator.getCountryISOCode(cityCountryName));
+
+ Region cr = (cityRegionName == null)? getDefaultRegion(cc) : lbl.createRegion(cc, cityRegionName, null);
+
+ if(cr != null) {
+ ((MapRoad)line).setRoadCity(lbl.createCity(cr, cityName, false));
+ }
+ else {
+ ((MapRoad)line).setRoadCity(lbl.createCity(cc, cityName, false));
+ }
+ }
+
+ if(zipStr != null) {
+ ((MapRoad)line).setRoadZip(lbl.createZip(zipStr));
+ }
+
+ }
+ }
+ }
+
+ private void processPOIs(Map map, MapDataSource src) {
+
+ LBLFile lbl = map.getLblFile();
+ boolean checkedForPoiDispFlag = false;
+
+ for (MapPoint p : src.getPoints()) {
+ // special handling for highway exits
+ if(p.isExit()) {
+ processExit(map, (MapExitPoint)p);
+ }
+ // do not process:
+ // * cities (already processed)
+ // * extended types (address information not shown in MapSource and on GPS)
+ // * all POIs except roads in case the no-poi-address option is set
+ else if (!p.isCity() && !p.hasExtendedType() && (p.isRoadNamePOI() || poiAddresses))
+ {
+
+ String countryStr = p.getCountry();
+ String regionStr = p.getRegion();
+ String zipStr = p.getZip();
+ String cityStr = p.getCity();
+
+ if(locationAutofill.contains("nearest") && (countryStr == null || regionStr == null || (zipStr == null && cityStr == null)))
+ {
+ MapPoint nextCity = locator.findNearbyCityByName(p);
+
+ if(nextCity == null)
+ nextCity = locator.findNextPoint(p);
+
+ if(nextCity != null)
+ {
+ if (countryStr == null) countryStr = nextCity.getCountry();
+ if (regionStr == null) regionStr = nextCity.getRegion();
+
+ if(zipStr == null)
+ {
+ String cityZipStr = nextCity.getZip();
+
+ // Ignore list of Zips separated by ;
+
+ if(cityZipStr != null && cityZipStr.indexOf(',') < 0)
+ zipStr = cityZipStr;
+ }
+
+ if(cityStr == null) cityStr = nextCity.getCity();
+
+ }
+ }
+
+
+ if(countryStr != null && !checkedForPoiDispFlag)
+ {
+ // Different countries require different address notation
+
+ poiDisplayFlags = locator.getPOIDispFlag(countryStr);
+ checkedForPoiDispFlag = true;
+ }
+
+
+ if(p.isRoadNamePOI() && cityStr != null)
+ {
+ // If it is road POI add city name and street name into address info
+ p.setStreet(p.getName());
+ p.setName(p.getName() + "/" + cityStr);
+ }
+
+ POIRecord r = lbl.createPOI(p.getName());
+
+ if (cityStr == null && (countryStr != null || regionStr != null)) {
+ // if city name is unknown and region and/or country is known
+ // use empty name for the city
+ cityStr = UNKNOWN_CITY_NAME;
+ }
+
+ if(cityStr != null)
+ {
+ Country thisCountry;
+
+ if(countryStr != null)
+ thisCountry = lbl.createCountry(countryStr, locator.getCountryISOCode(countryStr));
+ else
+ thisCountry = getDefaultCountry();
+
+ Region thisRegion;
+ if(regionStr != null)
+ thisRegion = lbl.createRegion(thisCountry,regionStr, null);
+ else
+ thisRegion = getDefaultRegion(thisCountry);
+
+ City city;
+ if(thisRegion != null)
+ city = lbl.createCity(thisRegion, cityStr, false);
+ else
+ city = lbl.createCity(thisCountry, cityStr, false);
+
+ r.setCity(city);
+
+ }
+
+ if (zipStr != null)
+ {
+ Zip zip = lbl.createZip(zipStr);
+ r.setZip(zip);
+ }
+
+ if(p.getStreet() != null)
+ {
+ Label streetName = lbl.newLabel(p.getStreet());
+ r.setStreetName(streetName);
+ }
+
+ if(p.getHouseNumber() != null)
+ {
+ if(!r.setSimpleStreetNumber(p.getHouseNumber()))
+ {
+ Label streetNumber = lbl.newLabel(p.getHouseNumber());
+ r.setComplexStreetNumber(streetNumber);
+ }
+ }
+
+ if(p.getPhone() != null)
+ {
+ if(!r.setSimplePhoneNumber(p.getPhone()))
+ {
+ Label phoneNumber = lbl.newLabel(p.getPhone());
+ r.setComplexPhoneNumber(phoneNumber);
+ }
+ }
+
+ poimap.put(p, r);
+ }
+ }
+
+ lbl.allPOIsDone();
+ }
+
+ private void processExit(Map map, MapExitPoint mep) {
+ LBLFile lbl = map.getLblFile();
+ String ref = mep.getMotorwayRef();
+ String OSMId = mep.getOSMId();
+ if(ref != null) {
+ Highway hw = highways.get(ref);
+ if(hw == null)
+ hw = makeHighway(map, ref);
+ if(hw == null) {
+ log.warn("Can't create exit", mep.getName(), "(OSM id", OSMId, ") on unknown highway", ref);
+ return;
+ }
+ String exitName = mep.getName();
+ String exitTo = mep.getTo();
+ Exit exit = new Exit(hw);
+ String facilityDescription = mep.getFacilityDescription();
+ log.info("Creating", ref, "exit", exitName, "(OSM id", OSMId +") to", exitTo, "with facility", ((facilityDescription == null)? "(none)" : facilityDescription));
+ if(facilityDescription != null) {
+ // description is TYPE,DIR,FACILITIES,LABEL
+ // (same as Polish Format)
+ String[] atts = facilityDescription.split(",");
+ int type = 0;
+ if(atts.length > 0)
+ type = Integer.decode(atts[0]);
+ char direction = ' ';
+ if(atts.length > 1) {
+ direction = atts[1].charAt(0);
+ if(direction == '\'' && atts[1].length() > 1)
+ direction = atts[1].charAt(1);
+ }
+ int facilities = 0x0;
+ if(atts.length > 2)
+ facilities = Integer.decode(atts[2]);
+ String description = "";
+ if(atts.length > 3)
+ description = atts[3];
+ boolean last = true; // FIXME - handle multiple facilities?
+ ExitFacility ef = lbl.createExitFacility(type, direction, facilities, description, last);
+
+ exit.addFacility(ef);
+ }
+ mep.setExit(exit);
+ POIRecord r = lbl.createExitPOI(exitName, exit);
+ if(exitTo != null) {
+ Label ed = lbl.newLabel(exitTo);
+ exit.setDescription(ed);
+ }
+ poimap.put(mep, r);
+ // FIXME - set bottom bits of
+ // type to reflect facilities available?
+ }
+ }
+
+ /**
+ * Drive the map generation by stepping through the levels, generating the
+ * subdivisions for the level and filling in the map elements that should
+ * go into the area.
+ *
+ * This is fairly complex: you need to divide into subdivisions depending on
+ * their size and the number of elements that will be contained.
+ *
+ * @param map The map.
+ * @param src The data for the map.
+ */
+ private void makeMapAreas(Map map, LoadableMapDataSource src) {
+ // The top level has to cover the whole map without subdividing, so
+ // do a special check to make sure.
+ LevelInfo[] levels = null;
+ if (src instanceof OverviewMapDataSource)
+ levels = src.mapLevels();
+ else {
+ if (OverviewBuilder.isOverviewImg(map.getFilename())) {
+ levels = src.overviewMapLevels();
+ } else {
+ levels = src.mapLevels();
+ }
+ }
+ if (levels == null){
+ throw new ExitException("no info about levels available.");
+ }
+ LevelInfo levelInfo = levels[0];
+
+ // If there is already a top level zoom, then we shouldn't add our own
+ Subdivision topdiv;
+ if (levelInfo.isTop()) {
+ // There is already a top level definition. So use the values from it and
+ // then remove it from the levels definition.
+
+ levels = Arrays.copyOfRange(levels, 1, levels.length);
+
+ Zoom zoom = map.createZoom(levelInfo.getLevel(), levelInfo.getBits());
+ topdiv = makeTopArea(src, map, zoom);
+ } else {
+ // We have to automatically create the definition for the top zoom level.
+ int maxBits = getMaxBits(src);
+ // If the max is larger than the top-most data level then we
+ // decrease it so that it is less.
+ if (levelInfo.getBits() <= maxBits)
+ maxBits = levelInfo.getBits() - 1;
+
+ // Create the empty top level
+ Zoom zoom = map.createZoom(levelInfo.getLevel() + 1, maxBits);
+ topdiv = makeTopArea(src, map, zoom);
+ }
+
+ // We start with one map data source.
+ List<SourceSubdiv> srcList = Collections.singletonList(new SourceSubdiv(src, topdiv));
+
+ // Now the levels filled with features.
+ for (LevelInfo linfo : levels) {
+ List<SourceSubdiv> nextList = new ArrayList<SourceSubdiv>();
+
+ Zoom zoom = map.createZoom(linfo.getLevel(), linfo.getBits());
+
+ for (SourceSubdiv srcDivPair : srcList) {
+
+ MapSplitter splitter = new MapSplitter(srcDivPair.getSource(), zoom);
+ MapArea[] areas = splitter.split();
+ log.info("Map region", srcDivPair.getSource().getBounds(), "split into", areas.length, "areas at resolution", zoom.getResolution());
+
+ for (MapArea area : areas) {
+ Subdivision parent = srcDivPair.getSubdiv();
+ Subdivision div = makeSubdivision(map, parent, area, zoom);
+ if (log.isDebugEnabled())
+ log.debug("ADD parent-subdiv", parent, srcDivPair.getSource(), ", z=", zoom, " new=", div);
+ nextList.add(new SourceSubdiv(area, div));
+ }
+
+ Subdivision lastdiv = nextList.get(nextList.size() - 1).getSubdiv();
+ lastdiv.setLast(true);
+ }
+
+ srcList = nextList;
+ }
+ }
+
+ /**
+ * Create the top level subdivision.
+ *
+ * There must be an empty zoom level at the least detailed level. As it
+ * covers the whole area in one it must be zoomed out enough so that
+ * this can be done.
+ *
+ * Note that the width is a 16 bit quantity, but the top bit is a
+ * flag and so that leaves only 15 bits into which the actual width
+ * can fit.
+ *
+ * @param src The source of map data.
+ * @param map The map being created.
+ * @param zoom The zoom level.
+ * @return The new top level subdivision.
+ */
+ private Subdivision makeTopArea(MapDataSource src, Map map, Zoom zoom) {
+ Subdivision topdiv = map.topLevelSubdivision(src.getBounds(), zoom);
+ topdiv.setLast(true);
+ return topdiv;
+ }
+
+ /**
+ * Make an individual subdivision for the map. To do this we need a link
+ * to its parent and the zoom level that we are working at.
+ *
+ * @param map The map to add this subdivision into.
+ * @param parent The parent division.
+ * @param ma The area of the map that we are fitting into this division.
+ * @param z The zoom level.
+ * @return The new subdivsion.
+ */
+ private Subdivision makeSubdivision(Map map, Subdivision parent, MapArea ma, Zoom z) {
+ List<MapPoint> points = ma.getPoints();
+ List<MapLine> lines = ma.getLines();
+ List<MapShape> shapes = ma.getShapes();
+
+ Subdivision div = map.createSubdivision(parent, ma.getFullBounds(), z);
+
+ if (ma.hasPoints())
+ div.setHasPoints(true);
+ if (ma.hasIndPoints())
+ div.setHasIndPoints(true);
+ if (ma.hasLines())
+ div.setHasPolylines(true);
+ if (ma.hasShapes())
+ div.setHasPolygons(true);
+
+ div.startDivision();
+
+ processPoints(map, div, points);
+ processLines(map, div, lines);
+ processShapes(map, div, shapes);
+
+ div.endDivision();
+
+ return div;
+ }
+
+ /**
+ * Create the overview sections.
+ *
+ * @param map The map details.
+ * @param src The map data source.
+ */
+ protected void processOverviews(Map map, MapDataSource src) {
+ List<Overview> features = src.getOverviews();
+ for (Overview ov : features) {
+ switch (ov.getKind()) {
+ case Overview.POINT_KIND:
+ map.addPointOverview((PointOverview) ov);
+ break;
+ case Overview.LINE_KIND:
+ map.addPolylineOverview((PolylineOverview) ov);
+ break;
+ case Overview.SHAPE_KIND:
+ map.addPolygonOverview((PolygonOverview) ov);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
+ * Set all the information that appears in the header.
+ *
+ * @param map The map to write to.
+ * @param src The source of map information.
+ */
+ protected void getMapInfo() {
+ if (licenseFileName != null) {
+ File file = new File(licenseFileName);
+
+ try {
+ BufferedReader reader = new BufferedReader(new FileReader(file));
+ String text;
+
+ // repeat until all lines is read
+ while ((text = reader.readLine()) != null) {
+ if (!text.isEmpty()) {
+ mapInfo.add(text);
+ }
+ }
+
+ reader.close();
+ } catch (FileNotFoundException e) {
+ throw new ExitException("Could not open license file " + licenseFileName);
+ } catch (IOException e) {
+ throw new ExitException("Error reading license file " + licenseFileName);
+ }
+ } else {
+ mapInfo.add("Map data (c) OpenStreetMap and its contributors");
+ mapInfo.add("http://www.openstreetmap.org/copyright");
+ mapInfo.add("");
+ mapInfo.add("This map data is made available under the Open Database License:");
+ mapInfo.add("http://opendatacommons.org/licenses/odbl/1.0/");
+ mapInfo.add("Any rights in individual contents of the database are licensed under the");
+ mapInfo.add("Database Contents License: http://opendatacommons.org/licenses/dbcl/1.0/");
+ mapInfo.add("");
+
+ // Pad the version number with spaces so that version
+ // strings that are different lengths do not change the size and
+ // offsets of the following sections.
+ mapInfo.add("Map created with mkgmap-r"
+ + String.format("%-10s", Version.VERSION));
+
+ mapInfo.add("Program released under the GPL");
+ }
+ }
+
+ public void setMapInfo(List<String> msgs){
+ mapInfo = msgs;
+ }
+
+ public void setCopyrights(List<String> msgs){
+ copyrights = msgs;
+ }
+
+
+ /**
+ * Set all the information that appears in the header.
+ *
+ * @param map The map to write to.
+ * @param src The source of map information.
+ */
+ protected void processInfo(Map map, LoadableMapDataSource src) {
+ // The bounds of the map.
+ map.setBounds(src.getBounds());
+
+ if(poiDisplayFlags != 0) // POI requested alternate address notation
+ map.addPoiDisplayFlags(poiDisplayFlags);
+
+ // You can add anything here.
+ // But there has to be something, otherwise the map does not show up.
+ //
+ // We use it to add copyright information that there is no room for
+ // elsewhere
+ String info = "";
+ for (String s: mapInfo){
+ info += s.trim() + "\n";
+ }
+ if (!info.isEmpty())
+ map.addInfo(info);
+ if (copyrights.isEmpty()){
+ // There has to be (at least) two copyright messages or else the map
+ // does not show up. The second one will be displayed at startup,
+ // although the conditions where that happens are not known.
+ map.addCopyright("program licenced under GPL v2");
+
+ // This one gets shown when you switch on, so put the actual
+ // map copyright here.
+ for (String cm : src.copyrightMessages())
+ map.addCopyright(cm);
+ } else {
+ for (String cm : copyrights)
+ map.addCopyright(cm);
+ }
+ }
+
+ /**
+ * Step through the points, filter and create a map point which is then added
+ * to the map.
+ *
+ * Note that the location and resolution of map elements is relative to the
+ * subdivision that they occur in.
+ *
+ * @param map The map to add points to.
+ * @param div The subdivision that the points belong to.
+ * @param points The points to be added.
+ */
+ private void processPoints(Map map, Subdivision div, List<MapPoint> points) {
+ LBLFile lbl = map.getLblFile();
+ div.startPoints();
+ int res = div.getResolution();
+
+ boolean haveIndPoints = false;
+ int pointIndex = 1;
+
+ // although the non-indexed points are output first,
+ // pointIndex must be initialized to the number of indexed
+ // points (not 1)
+ for (MapPoint point : points) {
+ if (point.isCity() &&
+ point.getMinResolution() <= res &&
+ point.getMaxResolution() >= res) {
+ ++pointIndex;
+ haveIndPoints = true;
+ }
+ }
+
+ for (MapPoint point : points) {
+
+ if (point.isCity() ||
+ point.getMinResolution() > res ||
+ point.getMaxResolution() < res)
+ continue;
+
+ String name = point.getName();
+
+ Point p = div.createPoint(name);
+ p.setType(point.getType());
+
+ if(point.hasExtendedType()) {
+ ExtTypeAttributes eta = point.getExtTypeAttributes();
+ if(eta != null) {
+ eta.processLabels(lbl);
+ p.setExtTypeAttributes(eta);
+ }
+ }
+
+ Coord coord = point.getLocation();
+ try {
+ p.setLatitude(coord.getLatitude());
+ p.setLongitude(coord.getLongitude());
+ }
+ catch (AssertionError ae) {
+ log.error("Problem with point of type 0x" + Integer.toHexString(point.getType()) + " at " + coord.toOSMURL());
+ log.error(" Subdivision shift is " + div.getShift() +
+ " and its centre is at " + new Coord(div.getLatitude(), div.getLongitude()).toOSMURL());
+ log.error(" " + ae.getMessage());
+ continue;
+ }
+
+ POIRecord r = poimap.get(point);
+ if (r != null)
+ p.setPOIRecord(r);
+
+ map.addMapObject(p);
+ if(!point.hasExtendedType()) {
+ if(name != null && div.getZoom().getLevel() == 0) {
+ if(pointIndex > 255)
+ log.error("FIXME - too many POIs in group");
+ else if(point.isExit()) {
+ Exit e = ((MapExitPoint)point).getExit();
+ if(e != null)
+ e.getHighway().addExitPoint(name, pointIndex, div);
+ }
+ else if(makePOIIndex)
+ lbl.createPOIIndex(name, pointIndex, div, point.getType());
+ }
+
+ ++pointIndex;
+ }
+ }
+
+ if (haveIndPoints) {
+ div.startIndPoints();
+
+ pointIndex = 1; // reset to 1
+ for (MapPoint point : points) {
+
+ if (!point.isCity() ||
+ point.getMinResolution() > res ||
+ point.getMaxResolution() < res)
+ continue;
+
+ String name = point.getName();
+
+ Point p = div.createPoint(name);
+ p.setType(point.getType());
+
+ Coord coord = point.getLocation();
+ try {
+ p.setLatitude(coord.getLatitude());
+ p.setLongitude(coord.getLongitude());
+ }
+ catch (AssertionError ae) {
+ log.error("Problem with point of type 0x" + Integer.toHexString(point.getType()) + " at " + coord.toOSMURL());
+ log.error(" Subdivision shift is " + div.getShift() +
+ " and its centre is at " + new Coord(div.getLatitude(), div.getLongitude()).toOSMURL());
+ log.error(" " + ae.getMessage());
+ continue;
+ }
+
+ map.addMapObject(p);
+ if(name != null && div.getZoom().getLevel() == 0) {
+ // retrieve the City created earlier for this
+ // point and store the point info in it
+ City c = cityMap.get(point);
+
+ if(pointIndex > 255) {
+ System.err.println("Can't set city point index for " + name + " (too many indexed points in division)\n");
+ } else {
+ c.setPointIndex((byte)pointIndex);
+ c.setSubdivision(div);
+ }
+ }
+
+ ++pointIndex;
+ }
+ }
+ }
+
+ /**
+ * Step through the lines, filter, simplify if necessary, and create a map
+ * line which is then added to the map.
+ *
+ * Note that the location and resolution of map elements is relative to the
+ * subdivision that they occur in.
+ *
+ * @param map The map to add points to.
+ * @param div The subdivision that the lines belong to.
+ * @param lines The lines to be added.
+ */
+ private void processLines(Map map, Subdivision div, List<MapLine> lines)
+ {
+ div.startLines(); // Signal that we are beginning to draw the lines.
+
+ int res = div.getResolution();
+
+ FilterConfig config = new FilterConfig();
+ config.setResolution(res);
+ config.setLevel(div.getZoom().getLevel());
+ config.setRoutable(doRoads);
+
+ //TODO: Maybe this is the wrong place to do merging.
+ // Maybe more efficient if merging before creating subdivisions.
+ if (mergeLines) {
+ LineMergeFilter merger = new LineMergeFilter();
+ lines = merger.merge(lines);
+ }
+ LayerFilterChain filters = new LayerFilterChain(config);
+ if (enableLineCleanFilters && (res < 24)) {
+ filters.addFilter(new RoundCoordsFilter());
+ filters.addFilter(new SizeFilter(MIN_SIZE_LINE));
+ if(reducePointError > 0)
+ filters.addFilter(new DouglasPeuckerFilter(reducePointError));
+ }
+ filters.addFilter(new LineSplitterFilter());
+ filters.addFilter(new RemoveEmpty());
+ filters.addFilter(new RemoveObsoletePointsFilter());
+ filters.addFilter(new LinePreparerFilter(div));
+ filters.addFilter(new LineAddFilter(div, map, doRoads));
+
+ for (MapLine line : lines) {
+ if (line.getMinResolution() > res || line.getMaxResolution() < res)
+ continue;
+
+ filters.startFilter(line);
+ }
+ }
+
+ /**
+ * Step through the polygons, filter, simplify if necessary, and create a map
+ * shape which is then added to the map.
+ *
+ * Note that the location and resolution of map elements is relative to the
+ * subdivision that they occur in.
+ *
+ * @param map The map to add polygons to.
+ * @param div The subdivision that the polygons belong to.
+ * @param shapes The polygons to be added.
+ */
+ private void processShapes(Map map, Subdivision div, List<MapShape> shapes)
+ {
+ div.startShapes(); // Signal that we are beginning to draw the shapes.
+
+ int res = div.getResolution();
+
+ FilterConfig config = new FilterConfig();
+ config.setResolution(res);
+ config.setLevel(div.getZoom().getLevel());
+ config.setRoutable(doRoads);
+
+ LayerFilterChain filters = new LayerFilterChain(config);
+ if (enableLineCleanFilters && (res < 24)) {
+ filters.addFilter(new PreserveHorizontalAndVerticalLinesFilter());
+ filters.addFilter(new RoundCoordsFilter());
+ int sizefilterVal = getMinSizePolygonForResolution(res);
+ if (sizefilterVal > 0)
+ filters.addFilter(new SizeFilter(sizefilterVal));
+ //DouglasPeucker behaves at the moment not really optimal at low zooms, but acceptable.
+ //Is there an similar algorithm for polygons?
+ if(reducePointErrorPolygon > 0)
+ filters.addFilter(new DouglasPeuckerFilter(reducePointErrorPolygon));
+ }
+ filters.addFilter(new PolygonSplitterFilter());
+ filters.addFilter(new RemoveEmpty());
+ filters.addFilter(new RemoveObsoletePointsFilter());
+ filters.addFilter(new LinePreparerFilter(div));
+ filters.addFilter(new ShapeAddFilter(div, map));
+
+ for (MapShape shape : shapes) {
+ if (shape.getMinResolution() > res || shape.getMaxResolution() < res)
+ continue;
+
+ filters.startFilter(shape);
+ }
+ }
+
+ Highway makeHighway(Map map, String ref) {
+ if(getDefaultRegion(null) == null) {
+ log.warn("Highway " + ref + " has no region (define a default region to zap this warning)");
+ }
+ Highway hw = highways.get(ref);
+ if(hw == null) {
+ LBLFile lblFile = map.getLblFile();
+ log.info("creating highway " + ref);
+ hw = lblFile.createHighway(getDefaultRegion(null), ref);
+ highways.put(ref, hw);
+ }
+
+ return hw;
+ }
+
+ /**
+ * It is not possible to represent large maps at the 24 bit resolution. This
+ * gets the largest resolution that can still cover the whole area of the
+ * map. It is used for the top most layer.
+ *
+ * @param src The map data.
+ * @return The largest number of bits where we can still represent the
+ * whole map.
+ */
+ private int getMaxBits(MapDataSource src) {
+ int topshift = Integer.numberOfLeadingZeros(src.getBounds().getMaxDimension());
+ int minShift = Math.max(CLEAR_TOP_BITS - topshift, 0);
+ return 24 - minShift;
+ }
+
+ /**
+ * Enable/disable the creation of a routable map
+ * @param doRoads
+ */
+ public void setDoRoads(boolean doRoads) {
+ this.doRoads = doRoads;
+ }
+
+ public void setEnableLineCleanFilters(boolean enable) {
+ this.enableLineCleanFilters = enable;
+ }
+
+ /**
+ * Determine the minimum size for a polygon for the given level.
+ * @param res the resolution
+ * @return the size filter value
+ */
+ private int getMinSizePolygonForResolution(int res) {
+
+ if (polygonSizeLimitsOpt == null)
+ return minSizePolygon;
+
+ if (polygonSizeLimits == null){
+ polygonSizeLimits = new HashMap<Integer, Integer>();
+ String[] desc = polygonSizeLimitsOpt.split("[, \\t\\n]+");
+
+ int count = 0;
+ for (String s : desc) {
+ String[] keyVal = s.split("[=:]");
+ if (keyVal == null || keyVal.length < 2) {
+ System.err.println("incorrect polygon-size-limits specification " + polygonSizeLimitsOpt);
+ continue;
+ }
+
+ try {
+ int key = Integer.parseInt(keyVal[0]);
+ int value = Integer.parseInt(keyVal[1]);
+ Integer testDup = polygonSizeLimits.put(key, value);
+ if (testDup != null){
+ System.err.println("duplicate resolution value in polygon-size-limits specification " + polygonSizeLimitsOpt);
+ continue;
+ }
+ } catch (NumberFormatException e) {
+ System.err.println("polygon-size-limits specification not all numbers " + keyVal[count]);
+ }
+ count++;
+ }
+ }
+ if (polygonSizeLimits != null){
+ // return the value for the desired resolution or the next higher one
+ for (int r = res; r <= 24; r++){
+ Integer limit = polygonSizeLimits.get(r);
+ if (limit != null){
+ if (r != res)
+ polygonSizeLimits.put(res, limit);
+ return limit;
+ }
+ }
+ return 0;
+ }
+ return minSizePolygon;
+ }
+
+ private static class SourceSubdiv {
+ private final MapDataSource source;
+ private final Subdivision subdiv;
+
+ SourceSubdiv(MapDataSource ds, Subdivision subdiv) {
+ this.source = ds;
+ this.subdiv = subdiv;
+ }
+
+ public MapDataSource getSource() {
+ return source;
+ }
+
+ public Subdivision getSubdiv() {
+ return subdiv;
+ }
+ }
+
+ private class LineAddFilter extends BaseFilter implements MapFilter {
+ private final Subdivision div;
+ private final Map map;
+ private final boolean doRoads;
+
+ LineAddFilter(Subdivision div, Map map, boolean doRoads) {
+ this.div = div;
+ this.map = map;
+ this.doRoads = doRoads;
+ }
+
+ public void doFilter(MapElement element, MapFilterChain next) {
+ MapLine line = (MapLine) element;
+ assert line.getPoints().size() < 255 : "too many points";
+
+ Polyline pl = div.createLine(line.getLabels());
+ if (element.hasExtendedType()) {
+ ExtTypeAttributes eta = element.getExtTypeAttributes();
+ if (eta != null) {
+ eta.processLabels(map.getLblFile());
+ pl.setExtTypeAttributes(eta);
+ }
+ } else
+ div.setPolylineNumber(pl);
+
+ pl.setDirection(line.isDirection());
+
+ pl.addCoords(line.getPoints());
+
+ pl.setType(line.getType());
+ if (doRoads){
+ if (line instanceof MapRoad) {
+ if (log.isDebugEnabled())
+ log.debug("adding road def: " + line.getName());
+ MapRoad road = (MapRoad) line;
+ RoadDef roaddef = road.getRoadDef();
+
+ pl.setRoadDef(roaddef);
+ if (road.hasSegmentsFollowing() )
+ pl.setLastSegment(false);
+
+ roaddef.addPolylineRef(pl);
+ } else if (routingErrorMsgPrinted == false){
+ if (div.getZoom().getLevel() == 0 && GType.isRoutableLineType(line.getType())){
+ Coord start = line.getPoints().get(0);
+ log.error("Non-routable way with routable type " + GType.formatType(line.getType()) + " starting at " +
+ start.toOSMURL() +
+ " is used for a routable map. This leads to routing errors. Try --check-styles to check the style.");
+
+ routingErrorMsgPrinted = true;
+ }
+ }
+ }
+ map.addMapObject(pl);
+ }
+ }
+
+ private static class ShapeAddFilter extends BaseFilter implements MapFilter {
+ private final Subdivision div;
+ private final Map map;
+
+ ShapeAddFilter(Subdivision div, Map map) {
+ this.div = div;
+ this.map = map;
+ }
+
+ public void doFilter(MapElement element, MapFilterChain next) {
+ MapShape shape = (MapShape) element;
+ assert shape.getPoints().size() < 255 : "too many points";
+
+ Polygon pg = div.createPolygon(shape.getName());
+
+ pg.addCoords(shape.getPoints());
+
+ pg.setType(shape.getType());
+ if(element.hasExtendedType()) {
+ ExtTypeAttributes eta = element.getExtTypeAttributes();
+ if(eta != null) {
+ eta.processLabels(map.getLblFile());
+ pg.setExtTypeAttributes(eta);
+ }
+ }
+ map.addMapObject(pg);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/build/MapSplitter.java b/src/uk/me/parabola/mkgmap/build/MapSplitter.java
new file mode 100644
index 0000000..e787319
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/build/MapSplitter.java
@@ -0,0 +1,209 @@
+/*
+ * 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: 20-Jan-2007
+ */
+package uk.me.parabola.mkgmap.build;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.trergn.Zoom;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.MapDataSource;
+
+/**
+ * The map must be split into subdivisions. To do this we start off with
+ * one of these MapAreas containing all of the map and split it up into
+ * smaller and smaller areas until each area is below a maximum size and
+ * contains fewer than a maximum number of map features.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MapSplitter {
+ private static final Logger log = Logger.getLogger(MapSplitter.class);
+
+ private final MapDataSource mapSource;
+
+ // There is an absolute largest size as offsets are in 16 bits, we are
+ // staying safely inside it however.
+ public static final int MAX_DIVISION_SIZE = 0x7fff;
+
+ // The maximum region size. Note that the offset to the start of a section
+ // has to fit into 16 bits, the end of the last section could be beyond the
+ // 16 bit limit. Leave a little room for the region pointers
+ public static final int MAX_RGN_SIZE = 0xfff8;
+
+ // The maximum number of lines. NET points to lines in subdivision
+ // using bytes.
+ public static final int MAX_NUM_LINES = 0xff;
+
+ public static final int MAX_NUM_POINTS = 0xff;
+
+ // maximum allowed amounts of points/lines/shapes with extended types
+ // real limits are not known but if these values are too large, data
+ // goes missing (lines disappear, etc.)
+ public static final int MAX_XT_POINTS_SIZE = 0xff00;
+ public static final int MAX_XT_LINES_SIZE = 0xff00;
+ public static final int MAX_XT_SHAPES_SIZE = 0xff00;
+
+ public static final int MIN_DIMENSION = 10; // just a reasonable value
+
+ private final Zoom zoom;
+
+ /**
+ * Creates a list of map areas and keeps splitting them down until they
+ * are small enough. There is both a maximum size to an area and also
+ * a maximum number of things that will fit inside each division.
+ *
+ * Since these are not well defined (it all depends on how complicated the
+ * features are etc), we shall underestimate the maximum sizes and probably
+ * make them configurable.
+ *
+ * @param mapSource The input map data source.
+ * @param zoom The zoom level that we need to split for.
+ */
+ MapSplitter(MapDataSource mapSource, Zoom zoom) {
+ this.mapSource = mapSource;
+ this.zoom = zoom;
+ }
+
+ /**
+ * This splits the map into a series of smaller areas. There is both a
+ * maximum size and a maximum number of features that can be contained
+ * in a single area.
+ *
+ * This routine is not called recursively.
+ *
+ * @return An array of map areas, each of which is within the size limit
+ * and the limit on the number of features.
+ */
+ public MapArea[] split() {
+ log.debug("orig area", mapSource.getBounds());
+
+ MapArea ma = initialArea(mapSource);
+ MapArea[] areas = splitMaxSize(ma);
+
+ // Now step through each area and see if any have too many map features
+ // in them. For those that do, we further split them. This is done
+ // recursively until everything fits.
+ List<MapArea> alist = new ArrayList<MapArea>();
+ addAreasToList(areas, alist, 0);
+
+ MapArea[] results = new MapArea[alist.size()];
+ return alist.toArray(results);
+ }
+
+ /**
+ * Adds map areas to a list. If an area has too many features, then it
+ * is split into 4 and this routine is called recursively to add the new
+ * areas.
+ *
+ * @param areas The areas to add to the list (and possibly split up).
+ * @param alist The list that will finally contain the complete list of
+ * map areas.
+ */
+ private void addAreasToList(MapArea[] areas, List<MapArea> alist, int depth) {
+ int res = zoom.getResolution();
+ for (MapArea area : areas) {
+ Area bounds = area.getBounds();
+ int[] sizes = area.getEstimatedSizes();
+ if(log.isInfoEnabled()) {
+ String padding = depth + " ";
+ log.info(padding.substring(0, (depth + 1) * 2) +
+ bounds.getWidth() + "x" + bounds.getHeight() +
+ ", res = " + res +
+ ", points = " + area.getNumPoints() + "/" + sizes[MapArea.POINT_KIND] +
+ ", lines = " + area.getNumLines() + "/" + sizes[MapArea.LINE_KIND] +
+ ", shapes = " + area.getNumShapes() + "/" + sizes[MapArea.SHAPE_KIND]);
+ }
+
+ if (area.getNumLines() > MAX_NUM_LINES ||
+ area.getNumPoints() > MAX_NUM_POINTS ||
+ (sizes[MapArea.POINT_KIND] +
+ sizes[MapArea.LINE_KIND] +
+ sizes[MapArea.SHAPE_KIND]) > MAX_RGN_SIZE ||
+ sizes[MapArea.XT_POINT_KIND] > MAX_XT_POINTS_SIZE ||
+ sizes[MapArea.XT_LINE_KIND] > MAX_XT_LINES_SIZE ||
+ sizes[MapArea.XT_SHAPE_KIND] > MAX_XT_SHAPES_SIZE) {
+ if (bounds.getMaxDimension() > MIN_DIMENSION) {
+ if (log.isDebugEnabled())
+ log.debug("splitting area", area);
+ MapArea[] sublist;
+ if(bounds.getWidth() > bounds.getHeight())
+ sublist = area.split(2, 1, res, bounds);
+ else
+ sublist = area.split(1, 2, res, bounds);
+ addAreasToList(sublist, alist, depth + 1);
+ continue;
+ } else {
+ log.error("Area too small to split at " + area.getBounds().getCenter().toOSMURL() + " (reduce the density of points, length of lines, etc.)");
+ }
+ }
+
+ log.debug("adding area unsplit", ",has points" + area.hasPoints());
+ alist.add(area);
+ }
+ }
+
+ /**
+ * Split the area into portions that have the maximum size. There is a
+ * maximum limit to the size of a subdivision (16 bits or about 1.4 degrees
+ * at the most detailed zoom level).
+ *
+ * The size depends on the shift level.
+ *
+ * We are choosing a limit smaller than the real max to allow for
+ * uncertainty about what happens with features that extend beyond the box.
+ *
+ * If the area is already small enough then it will be returned unchanged.
+ *
+ * @param mapArea The area that needs to be split down.
+ * @return An array of map areas. Each will be below the max size.
+ */
+ private MapArea[] splitMaxSize(MapArea mapArea) {
+ Area bounds = mapArea.getFullBounds();
+
+ int shift = zoom.getShiftValue();
+ int width = bounds.getWidth() >> shift;
+ int height = bounds.getHeight() >> shift;
+ log.info("splitMaxSize() bounds = " + bounds + " shift = " + shift + " width = " + width + " height = " + height);
+ if (log.isDebugEnabled())
+ log.debug("shifted width", width, "shifted height", height);
+
+ // There is an absolute maximum size that a division can be. Make sure
+ // that we are well inside that.
+ int xsplit = 1;
+ if (width > MAX_DIVISION_SIZE)
+ xsplit = width / MAX_DIVISION_SIZE + 1;
+
+ int ysplit = 1;
+ if (height > MAX_DIVISION_SIZE)
+ ysplit = height / MAX_DIVISION_SIZE + 1;
+
+ return mapArea.split(xsplit, ysplit, zoom.getResolution(), bounds);
+ }
+
+ /**
+ * The initial area contains all the features of the map.
+ *
+ * @param src The map data source.
+ * @return The initial map area covering the whole area and containing
+ * all the map features that are visible.
+ */
+ private MapArea initialArea(MapDataSource src) {
+ return new MapArea(src, zoom.getResolution());
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/build/package.html b/src/uk/me/parabola/mkgmap/build/package.html
new file mode 100644
index 0000000..71feabb
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/build/package.html
@@ -0,0 +1,9 @@
+<body>
+<h3>Map building code</h3>
+<p>This is the code that converts from the general representation to the the
+garmin representation.
+
+<p>The general representation is just one layer at the level of detail in
+the OSM file. This must be then coverted to several layers at different
+levels of detail. This is what the files in this package do.</p>
+</body>
\ No newline at end of file
diff --git a/src/uk/me/parabola/mkgmap/combiners/Combiner.java b/src/uk/me/parabola/mkgmap/combiners/Combiner.java
new file mode 100644
index 0000000..3c5ebb2
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/combiners/Combiner.java
@@ -0,0 +1,51 @@
+/*
+ * 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: Dec 4, 2007
+ */
+package uk.me.parabola.mkgmap.combiners;
+
+import uk.me.parabola.mkgmap.CommandArgs;
+
+/**
+ * The interface for all combining operations. These include creating the
+ * tdb file, the overview map and the gmapsupp.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface Combiner {
+
+ /**
+ * Initialise with the command line arguments. This is called after all
+ * the command line arguments have been processed, but before any calls to
+ * the {@link #onMapEnd} methods.
+ *
+ * @param args The command line arguments.
+ */
+ public void init(CommandArgs args);
+
+ /**
+ * This is called when an individual map is complete.
+ *
+ * @param info An interface to read the map.
+ */
+ public void onMapEnd(FileInfo info);
+
+ /**
+ * The complete map set has been processed. Finish off anything that needs
+ * doing.
+ */
+ public void onFinish();
+
+}
diff --git a/src/uk/me/parabola/mkgmap/combiners/FileInfo.java b/src/uk/me/parabola/mkgmap/combiners/FileInfo.java
new file mode 100644
index 0000000..bd3f62c
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/combiners/FileInfo.java
@@ -0,0 +1,493 @@
+/*
+ * 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.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+import uk.me.parabola.imgfmt.FileSystemParam;
+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.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 int ENTRY_SIZE = 240;
+
+ 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<Integer> fileSizes = new ArrayList<Integer>();
+ private String[] licenceInfo;
+ private CommandArgs args;
+ private String mpsName;
+ private int codePage;
+ private int sortOrderId;
+
+ 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();
+ String ext = inputName.substring(end - 3).toUpperCase(Locale.ENGLISH);
+ FileInfo info;
+
+ if (ext.equals("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);
+ }
+
+ 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.fileSizes.add((int) 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) {
+ ImgChannel chan = new FileImgChannel(filename, "r");
+ try {
+ BufferedImgFileReader fr = new BufferedImgFileReader(chan);
+ fr.position(0x15);
+ info.setCodePage(fr.getChar());
+ } finally {
+ Utils.closeFile(chan);
+ }
+ }
+
+ /**
+ * 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 {
+ FileSystem imgFs = ImgFS.openFs(inputName);
+
+ try {
+ 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;
+ 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());
+
+ treInfo(imgFs, ent, info);
+ hasTre = true;
+ } 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 ("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.fileSizes.add(ent.getSize());
+ }
+
+ if (info.getKind() == UNKNOWN_KIND && hasTre)
+ info.setKind(IMG_KIND);
+
+ return info;
+ } finally {
+ imgFs.close();
+ }
+ }
+
+ /**
+ * 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 {
+ TREFileReader treFile = null;
+ try {
+ ImgChannel treChan = imgFs.open(ent.getFullName(), "r");
+ treFile = new TREFileReader(treChan);
+
+ info.setBounds(treFile.getBounds());
+
+ info.setLicenceInfo(treFile.getMapInfo());
+
+ info.setHexname(((TREHeader) treFile.getHeader()).getMapId());
+ } finally {
+ Utils.closeFile(treFile);
+ }
+ }
+
+ /**
+ * 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) {
+ LBLFileReader lblFile = new LBLFileReader(chan);
+
+ info.setCodePage(lblFile.getCodePage());
+ info.setSortOrderId(lblFile.getSortOrderId());
+ lblFile.close();
+ }
+
+ 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;
+ }
+
+ /**
+ * Get the number header slots (512 byte entry) required to represent this file
+ * at the given block size.
+ * Each sub-file will need at least one block and so we go through each
+ * separately and round up for each and return the total.
+ *
+ * @param blockSize The block size.
+ * @return The number of 512 byte header entries that are needed for all the subfiles
+ * in this .img file.
+ */
+ public int getNumHeaderEntries(int blockSize) {
+ int totHeaderSlots = 0;
+ for (int size : fileSizes) {
+ // You use up one header slot for every 240 blocks with a minimum
+ // of one slot
+ int nblocks = (size + (blockSize-1)) / blockSize;
+ totHeaderSlots += (nblocks + (ENTRY_SIZE - 1)) / ENTRY_SIZE;
+ }
+ return totHeaderSlots;
+ }
+
+ /**
+ * Get the number of blocks for all the sub-files of this file at the given block size.
+ * Note that a complete block is always used for a file.
+ *
+ * For TYP files and other files that do not have sub-files, then it is just the number of blocks
+ * for the complete file.
+ *
+ * @param bs The block size at which to calculate the value.
+ * @return The number of blocks at the given size required to save all the sub-files of this file.
+ */
+ public int getNumBlocks(int bs) {
+ int totBlocks = 0;
+ for (int size : fileSizes) {
+ int nblocks = (size + (bs - 1)) / bs;
+ totBlocks += nblocks;
+ }
+ return totBlocks;
+ }
+
+ public int getMapnameAsInt() {
+ try {
+ return Integer.valueOf(mapname);
+ } catch (NumberFormatException e) {
+ return 0;
+ }
+ }
+
+
+ protected 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", "family name");
+ }
+
+ 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;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/combiners/FileKind.java b/src/uk/me/parabola/mkgmap/combiners/FileKind.java
new file mode 100644
index 0000000..d5250c2
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/combiners/FileKind.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.combiners;
+
+/**
+ * The different kinds of file that can given to mkgmap
+ */
+enum FileKind {
+ // The file is an img file ie. it contains several sub-files.
+ IMG_KIND,
+
+ // The file is a separate TRE, RGN, ... file and it doesn't need to be
+ // extracted from a .img
+ APP_KIND,
+
+ // A TYP file
+ TYP_KIND,
+
+ // The file is an img containing an MDR file
+ MDR_KIND,
+
+ // The file is a gmapsupp and contains an MPS file
+ GMAPSUPP_KIND,
+
+ // The file is of an unknown or unsupported kind, and so it should be ignored.
+ UNKNOWN_KIND
+}
diff --git a/src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java b/src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java
new file mode 100644
index 0000000..e7e490b
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java
@@ -0,0 +1,570 @@
+/*
+ * 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.nio.ByteBuffer;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.FileExistsException;
+import uk.me.parabola.imgfmt.FileNotWritableException;
+import uk.me.parabola.imgfmt.FileSystemParam;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.srt.SRTFile;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+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.mps.MapBlock;
+import uk.me.parabola.imgfmt.mps.MpsFile;
+import uk.me.parabola.imgfmt.mps.MpsFileReader;
+import uk.me.parabola.imgfmt.mps.ProductBlock;
+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;
+
+/**
+ * Create the gmapsupp file. There is nothing much special about this file
+ * (as far as I know - there's not a public official spec or anything) it is
+ * just a regular .img file which is why it works to rename a single .img file
+ * and send it to the device.
+ * <p/>
+ * Effectively we just 'unzip' the constituent .img files and then 'zip' them
+ * back into the gmapsupp.img file.
+ * <p/>
+ * In addition we need to create and add the MPS file, if we don't already
+ * have one.
+ *
+ * @author Steve Ratcliffe
+ */
+public class GmapsuppBuilder implements Combiner {
+ private static final Logger log = Logger.getLogger(GmapsuppBuilder.class);
+
+ private static final String GMAPSUPP = "gmapsupp.img";
+
+ /**
+ * The number of block numbers that will fit into one entry block
+ */
+ private static final int ENTRY_SIZE = 240;
+ private static final int DIRECTORY_OFFSET_ENTRY = 2;
+
+ private final Map<String, FileInfo> files = new LinkedHashMap<String, FileInfo>();
+
+ // all these need to be set in the init routine from arguments.
+ private String areaName;
+ private String mapsetName;
+
+ private String overallDescription = "Combined map";
+ private String outputDir;
+ private MpsFile mpsFile;
+
+ private boolean createIndex; // True if we should create and add an index file
+
+ // There is a separate MDR and SRT file for each family id in the gmapsupp
+ private final Map<Integer, MdrBuilder> mdrBuilderMap = new LinkedHashMap<Integer, MdrBuilder>();
+ private final Map<Integer, Sort> sortMap = new LinkedHashMap<Integer, Sort>();
+
+
+ public void init(CommandArgs args) {
+ areaName = args.get("area-name", null);
+ mapsetName = args.get("mapset-name", "OSM map set");
+ overallDescription = args.getDescription();
+ outputDir = args.getOutputDir();
+ }
+
+ /**
+ * Add or retrieve the MDR file for the given familyId.
+ * @param familyId The family id to create the mdr file for.
+ * @param sort The sort for this family id.
+ * @param outputDir The place to write the file.
+ * @return If there is already an mdr file for this family then it is returned, else the newly created
+ * one.
+ */
+ private MdrBuilder addMdrFile(int familyId, Sort sort, String outputDir) {
+ MdrBuilder mdrBuilder = mdrBuilderMap.get(familyId);
+ if (mdrBuilder != null)
+ return mdrBuilder;
+
+ mdrBuilder = new MdrBuilder();
+ mdrBuilder.initForDevice(sort, outputDir);
+ mdrBuilderMap.put(familyId, mdrBuilder);
+ return mdrBuilder;
+ }
+
+ /**
+ * Add the sort file for the given family id.
+ */
+ private void addSrtFile(int familyId, FileInfo info) {
+ Sort prevSort = sortMap.get(familyId);
+ Sort sort = info.getSort();
+ if (prevSort == null) {
+ if (info.getKind() == FileKind.IMG_KIND) {
+ sortMap.put(familyId, sort);
+ }
+ } else {
+ if (prevSort.getCodepage() != sort.getCodepage())
+ System.err.printf("WARNING: input file '%s' has a different code page (%d rather than %d)\n",
+ info.getFilename(), sort.getCodepage(), prevSort.getCodepage());
+ if (info.hasSortOrder() && prevSort.getSortOrderId() != sort.getSortOrderId())
+ System.err.printf("WARNING: input file '%s' has a different sort order (%x rather than %x\n",
+ info.getFilename(), sort.getSortOrderId(), prevSort.getSortOrderId());
+ }
+ }
+
+ /**
+ * This is called when the map is complete. We collect information about the map to be used in the TDB file and for
+ * preparing the gmapsupp file.
+ *
+ * @param info Information about the img file.
+ */
+ public void onMapEnd(FileInfo info) {
+ files.put(info.getFilename(), info);
+
+ if (info.isImg()) {
+ int familyId = info.getFamilyId();
+ if (createIndex) {
+ MdrBuilder mdrBuilder = addMdrFile(familyId, info.getSort(), info.getOutputDir());
+ mdrBuilder.onMapEnd(info);
+ }
+
+ addSrtFile(familyId, info);
+ }
+ }
+
+ /**
+ * The complete map set has been processed. Creates the gmapsupp file. This is done by stepping through each img file,
+ * reading all the sub files and copying them into the gmapsupp file.
+ */
+ public void onFinish() {
+
+ for (MdrBuilder mdrBuilder : mdrBuilderMap.values()) {
+ mdrBuilder.onFinishForDevice();
+ }
+
+ FileSystem imgFs = null;
+ try {
+ imgFs = createGmapsupp();
+
+ addAllFiles(imgFs);
+
+ // Add all the MDR files (one for each family)
+ for (Map.Entry<Integer, MdrBuilder> ent : mdrBuilderMap.entrySet())
+ addFile(imgFs, ent.getValue().getFileName(), String.format("%08d.MDR", ent.getKey()));
+
+ writeSrtFile(imgFs);
+ writeMpsFile();
+
+ } catch (FileNotWritableException e) {
+ log.warn("Could not create gmapsupp file");
+ System.err.println("Could not create gmapsupp file");
+ } finally {
+ Utils.closeFile(imgFs);
+ }
+ }
+
+ /**
+ * Write the SRT file.
+ *
+ * @param imgFs The filesystem to create the SRT file in.
+ * @throws FileNotWritableException If it cannot be created.
+ */
+ private void writeSrtFile(FileSystem imgFs) throws FileNotWritableException {
+ for (Map.Entry<Integer, Sort> ent : sortMap.entrySet()) {
+ Sort sort = ent.getValue();
+ int familyId = ent.getKey();
+
+ if (sort.getId1() == 0 && sort.getId2() == 0)
+ return;
+
+ ImgChannel channel = null;
+ try {
+ channel = imgFs.create(String.format("%08d.SRT", familyId));
+ SRTFile srtFile = new SRTFile(channel);
+ srtFile.setSort(sort);
+ srtFile.write();
+ srtFile.close();
+ } catch (FileExistsException e) {
+ // well it shouldn't exist!
+ log.error("could not create SRT file as it exists already");
+ throw new FileNotWritableException("already existed", e);
+ } finally {
+ Utils.closeFile(channel);
+ }
+ }
+ }
+
+ /**
+ * Write the MPS file. The gmapsupp file will work without this, but it important if you want to include more than one
+ * map family and be able to turn them on and off separately.
+ */
+ private void writeMpsFile() throws FileNotWritableException {
+ try {
+ mpsFile.sync();
+ mpsFile.close();
+ } catch (IOException e) {
+ throw new FileNotWritableException("Could not finish write to MPS file", e);
+ }
+ }
+
+ private MapBlock makeMapBlock(FileInfo info) {
+ MapBlock mb = new MapBlock();
+ mb.setMapNumber(info.getMapnameAsInt());
+ mb.setHexNumber(info.getHexname());
+ mb.setMapDescription(info.getDescription());
+ mb.setAreaName(areaName != null ? areaName : "Area " + info.getMapname());
+
+ mb.setSeriesName(info.getSeriesName());
+ mb.setIds(info.getFamilyId(), info.getProductId());
+ return mb;
+ }
+
+ private ProductBlock makeProductBlock(FileInfo info) {
+ ProductBlock pb = new ProductBlock();
+ pb.setFamilyId(info.getFamilyId());
+ pb.setProductId(info.getProductId());
+ pb.setDescription(info.getFamilyName());
+ return pb;
+ }
+
+ private void addAllFiles(FileSystem outfs) {
+ for (FileInfo info : files.values()) {
+ String filename = info.getFilename();
+ switch (info.getKind()) {
+ case IMG_KIND:
+ addImg(outfs, filename);
+ addMpsEntry(info);
+ break;
+ case GMAPSUPP_KIND:
+ addImg(outfs, filename);
+ addMpsFile(info);
+ break;
+ case APP_KIND:
+ case TYP_KIND:
+ addFile(outfs, filename);
+ break;
+ case MDR_KIND:
+ break;
+ }
+ }
+ }
+
+ /**
+ * Add a complete pre-existing mps file to the mps file we are currently
+ * building for this gmapsupp.
+ * @param info The details of the gmapsupp file that we need to extract the
+ */
+ private void addMpsFile(FileInfo info) {
+ String name = info.getFilename();
+ FileSystem fs = null;
+ try {
+ fs = ImgFS.openFs(name);
+ MpsFileReader mr = new MpsFileReader(fs.open(info.getMpsName(), "r"));
+ for (MapBlock block : mr.getMaps())
+ mpsFile.addMap(block);
+
+ for (ProductBlock b : mr.getProducts())
+ mpsFile.addProduct(b);
+ mr.close();
+ } catch (IOException e) {
+ log.error("Could not read MPS file from gmapsupp", e);
+ } finally {
+ Utils.closeFile(fs);
+ }
+ }
+
+ /**
+ * Add a single entry to the mps file.
+ * @param info The img file information.
+ */
+ private void addMpsEntry(FileInfo info) {
+ mpsFile.addMap(makeMapBlock(info));
+
+ // Add a new product block if we have found a new product
+ mpsFile.addProduct(makeProductBlock(info));
+ }
+
+ private MpsFile createMpsFile(FileSystem outfs) throws FileNotWritableException {
+ try {
+ ImgChannel channel = outfs.create("MAKEGMAP.MPS");
+ return new MpsFile(channel);
+ } catch (FileExistsException e) {
+ // well it shouldn't exist!
+ log.error("could not create MPS file as it already exists");
+ throw new FileNotWritableException("already existed", e);
+ }
+ }
+
+ /**
+ * Add a single file to the output.
+ *
+ * @param outfs The output gmapsupp file.
+ * @param filename The input filename.
+ */
+ private void addFile(FileSystem outfs, String filename) {
+ String imgname = createImgFilename(filename);
+ addFile(outfs, filename, imgname);
+ }
+
+ private void addFile(FileSystem outfs, String filename, String imgname) {
+ ImgChannel chan = new FileImgChannel(filename, "r");
+ try {
+ copyFile(chan, outfs, imgname);
+ } catch (IOException e) {
+ log.error("Could not write file " + filename);
+ }
+ }
+
+ /**
+ * Create a suitable filename for use in the .img file from the external
+ * file name.
+ *
+ * The external file name might look something like /home/steve/foo.typ
+ * or c:\maps\foo.typ and we need to take the filename part and make
+ * sure that it is no more than 8+3 characters.
+ *
+ * @param pathname The external filesystem path name.
+ * @return The filename part, will be restricted to 8+3 characters and all
+ * in upper case.
+ */
+ private String createImgFilename(String pathname) {
+ File f = new File(pathname);
+ String name = f.getName().toUpperCase(Locale.ENGLISH);
+ int dot = name.lastIndexOf('.');
+
+ String base = name.substring(0, dot);
+ String ext = name.substring(dot + 1);
+ if (base.length() > 8)
+ base = base.substring(0, 8);
+ if (ext.length() > 3)
+ ext = ext.substring(0, 3);
+
+ return base + '.' + ext;
+ }
+
+ /**
+ * Add a complete .img file, that is all the constituent files from it.
+ *
+ * @param outfs The gmapsupp file to write to.
+ * @param filename The input filename.
+ */
+ private void addImg(FileSystem outfs, String filename) {
+ try {
+ FileSystem infs = ImgFS.openFs(filename);
+
+ try {
+ copyAllFiles(infs, outfs);
+ } finally {
+ infs.close();
+ }
+ } catch (FileNotFoundException e) {
+ log.error("Could not open file " + filename);
+ }
+ }
+
+ /**
+ * Copy all files from the input filesystem to the output filesystem.
+ *
+ * @param infs The input filesystem.
+ * @param outfs The output filesystem.
+ */
+ private void copyAllFiles(FileSystem infs, FileSystem outfs) {
+ List<DirectoryEntry> entries = infs.list();
+ for (DirectoryEntry ent : entries) {
+ String ext = ent.getExt();
+ if (ext.equals(" ") || ext.equals("MPS"))
+ continue;
+
+ String inname = ent.getFullName();
+
+ try {
+ copyFile(inname, infs, outfs);
+ } catch (IOException e) {
+ log.warn("Could not copy " + inname, e);
+ }
+ }
+ }
+
+ /**
+ * Create the output file.
+ *
+ * @return The gmapsupp file.
+ * @throws FileNotWritableException If it cannot be created for any reason.
+ */
+ private FileSystem createGmapsupp() throws FileNotWritableException {
+ BlockInfo bi = calcBlockSize();
+ int blockSize = bi.blockSize;
+ // Create this file, containing all the sub files
+ FileSystemParam params = new FileSystemParam();
+ params.setBlockSize(blockSize);
+ params.setMapDescription(overallDescription);
+ params.setDirectoryStartEntry(DIRECTORY_OFFSET_ENTRY);
+ params.setGmapsupp(true);
+
+ int reserveBlocks = (int) Math.ceil(bi.reserveEntries * 512.0 / blockSize);
+ params.setReservedDirectoryBlocks(reserveBlocks);
+
+ FileSystem outfs = ImgFS.createFs(Utils.joinPath(outputDir, GMAPSUPP), params);
+ mpsFile = createMpsFile(outfs);
+ mpsFile.setMapsetName(mapsetName);
+
+ return outfs;
+ }
+
+ /**
+ * Copy an individual file with the given name from the first archive/filesystem
+ * to the second.
+ *
+ * @param inName The name of the file.
+ * @param infs The filesystem to copy from.
+ * @param outfs The filesystem to copy to.
+ * @throws IOException If the copy fails.
+ */
+ private void copyFile(String inName, FileSystem infs, FileSystem outfs) throws IOException {
+ ImgChannel fin = infs.open(inName, "r");
+ copyFile(fin, outfs, inName);
+ }
+
+ /**
+ * Copy a given open file to the a new file in outfs with the name inName.
+ * @param fin The file to copy from.
+ * @param outfs The file system to copy to.
+ * @param inName The name of the file to create on the destination file system.
+ * @throws IOException If a file cannot be read or written.
+ */
+ private void copyFile(ImgChannel fin, FileSystem outfs, String inName) throws IOException {
+ ImgChannel fout = outfs.create(inName);
+
+ copyFile(fin, fout);
+ }
+
+ /**
+ * Copy an individual file with the given name from the first archive/filesystem
+ * to the second.
+ *
+ * @param fin The file to copy from.
+ * @param fout The file to copy to.
+ * @throws IOException If the copy fails.
+ */
+ private void copyFile(ImgChannel fin, ImgChannel fout) throws IOException {
+ try {
+ ByteBuffer buf = ByteBuffer.allocate(1024);
+ while (fin.read(buf) > 0) {
+ buf.flip();
+ fout.write(buf);
+ buf.compact();
+ }
+ } finally {
+ fin.close();
+ fout.close();
+ }
+ }
+
+ /**
+ * Calculate the block size that we need to use. The block size must be such that
+ * the total number of blocks is less than 0xffff.
+ *
+ * I am making sure that the that the root directory entry doesn't require
+ * more than one block to hold its own block list.
+ *
+ * @return A suitable block size to use for the gmapsupp.img file.
+ */
+ private BlockInfo calcBlockSize() {
+ int[] ints = {1 << 9, 1 << 10, 1 << 11, 1 << 12, 1 << 13,
+ 1 << 14, 1 << 15, 1 << 16, 1 << 17, 1 << 18, 1 << 19,
+ 1 << 20, 1 << 21, 1 << 22, 1 << 23, 1 << 24,
+ };
+
+ for (int bs : ints) {
+ int totBlocks = 0;
+ int totHeaderEntries = 0;
+ for (FileInfo info : files.values()) {
+ totBlocks += info.getNumBlocks(bs);
+ // Each file will take up at least one directory block.
+ // Each directory block can hold 480 block-references
+ int slots = info.getNumHeaderEntries(bs);
+ log.info("adding", slots, "slots for", info.getFilename());
+ totHeaderEntries += slots;
+ }
+
+ // Estimate the number of blocks needed for the MPS file
+ int mpsSize = files.size() * 80 + 100;
+ int mpsBlocks = (mpsSize + (bs - 1)) / bs;
+ int mpsSlots = (mpsBlocks + ENTRY_SIZE - 1) / ENTRY_SIZE;
+
+ totBlocks += mpsBlocks;
+ totHeaderEntries += mpsSlots;
+
+ // Add in number of block for mdr
+ if (createIndex) {
+ for (MdrBuilder mdrBuilder : mdrBuilderMap.values()) {
+ int sz = mdrBuilder.getSize();
+ int mdrBlocks = (sz + (bs - 1)) / bs;
+ int mdrSlots = (mdrBlocks + ENTRY_SIZE - 1) / ENTRY_SIZE;
+
+ totBlocks += mdrBlocks;
+ totHeaderEntries += mdrSlots;
+ }
+ }
+
+ for (int i = 0; i < sortMap.size(); i++) {
+ // These files are less than 1k
+ int sz = 1024;
+ int mdrBlocks = (sz + (bs - 1)) / bs;
+ int mdrSlots = (mdrBlocks + ENTRY_SIZE - 1) / ENTRY_SIZE;
+
+ totBlocks += mdrBlocks;
+ totHeaderEntries += mdrSlots;
+ }
+
+ // There are 2 entries for the header itself.
+ totHeaderEntries += 2;
+ int totHeaderBlocks = totHeaderEntries * 512 / bs;
+
+ log.info("total blocks for", bs, "is", totHeaderBlocks, "based on slots=", totHeaderEntries);
+
+ int reserveEntries = (int) Math.ceil(DIRECTORY_OFFSET_ENTRY + 1 + totHeaderEntries);
+ if (totBlocks + reserveEntries < 0xfffe && totHeaderBlocks <= ENTRY_SIZE) {
+ return new BlockInfo(bs, reserveEntries);
+ }
+ }
+
+ throw new IllegalArgumentException("hmm");
+ }
+
+ public void setCreateIndex(boolean create) {
+ this.createIndex = create;
+ }
+
+ /**
+ * Just a data value object for various bits of block size info.
+ */
+ private static class BlockInfo {
+ private final int blockSize;
+ private final int reserveEntries;
+
+ private BlockInfo(int blockSize, int reserveEntries) {
+ this.blockSize = blockSize;
+ this.reserveEntries = reserveEntries;
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/combiners/MdrBuilder.java b/src/uk/me/parabola/mkgmap/combiners/MdrBuilder.java
new file mode 100644
index 0000000..1007fe1
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/combiners/MdrBuilder.java
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.combiners;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.ExitException;
+import uk.me.parabola.imgfmt.FileExistsException;
+import uk.me.parabola.imgfmt.FileSystemParam;
+import uk.me.parabola.imgfmt.MapFailedException;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.lbl.City;
+import uk.me.parabola.imgfmt.app.lbl.Country;
+import uk.me.parabola.imgfmt.app.lbl.POIRecord;
+import uk.me.parabola.imgfmt.app.lbl.Region;
+import uk.me.parabola.imgfmt.app.lbl.Zip;
+import uk.me.parabola.imgfmt.app.map.MapReader;
+import uk.me.parabola.imgfmt.app.mdr.MDRFile;
+import uk.me.parabola.imgfmt.app.mdr.Mdr13Record;
+import uk.me.parabola.imgfmt.app.mdr.Mdr14Record;
+import uk.me.parabola.imgfmt.app.mdr.Mdr5Record;
+import uk.me.parabola.imgfmt.app.mdr.MdrConfig;
+import uk.me.parabola.imgfmt.app.net.RoadDef;
+import uk.me.parabola.imgfmt.app.srt.SRTFile;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.trergn.Point;
+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.mkgmap.CommandArgs;
+import uk.me.parabola.mkgmap.srt.SrtTextReader;
+
+/**
+ * Create the global index file. This consists of an img file containing
+ * an MDR file and optionally an SRT file.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MdrBuilder implements Combiner {
+ private MDRFile mdrFile;
+
+ // Push things onto this stack to have them closed in the reverse order.
+ private final Deque<Closeable> toClose = new ArrayDeque<Closeable>();
+
+ // We write to a temporary file name, and then rename once all is OK.
+ private File tmpName;
+ private String outputName;
+
+ /**
+ * Create the mdr file and initialise.
+ * It has a name that is based on the overview-mapname option, as does
+ * the associated MDX file.
+ *
+ * @param args The command line arguments.
+ */
+ public void init(CommandArgs args) {
+ String name = args.get("overview-mapname", "osmmap");
+ String outputDir = args.getOutputDir();
+
+ outputName = Utils.joinPath(outputDir, name + "_mdr.img");
+
+ FileSystem fs;
+ ImgChannel mdrChan;
+
+ try {
+ // Create the .img file system/archive
+ FileSystemParam params = new FileSystemParam();
+ params.setBlockSize(args.get("block-size", 16384));
+
+ tmpName = File.createTempFile("mdr", null, new File(outputDir));
+ tmpName.deleteOnExit();
+
+ fs = ImgFS.createFs(tmpName.getPath(), params);
+ toClose.push(fs);
+ // Create the MDR file within the .img
+ mdrChan = fs.create(name.toUpperCase(Locale.ENGLISH) + ".MDR");
+ toClose.push(mdrChan);
+ } catch (IOException e) {
+ throw new ExitException("Could not create global index file");
+ }
+
+ // Create the sort description
+ Sort sort = createSort(args.getCodePage());
+
+ // Set the options that we are using for the mdr.
+ MdrConfig config = new MdrConfig();
+ config.setHeaderLen(568);
+ config.setWritable(true);
+ config.setForDevice(false);
+ config.setOutputDir(outputDir);
+ config.setSort(sort);
+
+ // Wrap the MDR channel with the MDRFile object
+ mdrFile = new MDRFile(mdrChan, config);
+ toClose.push(mdrFile);
+
+ try {
+ ImgChannel srtChan = fs.create(name.toUpperCase(Locale.ENGLISH) + ".SRT");
+ SRTFile srtFile = new SRTFile(srtChan);
+ srtFile.setSort(sort);
+ srtFile.write();
+ srtFile.close();
+ //toClose.push(srtFile);
+ } catch (FileExistsException e) {
+ throw new ExitException("Could not create SRT file within index file");
+ }
+ }
+
+ void initForDevice(Sort sort, String outputDir) {
+ // Set the options that we are using for the mdr.
+ MdrConfig config = new MdrConfig();
+ config.setHeaderLen(568);
+ config.setWritable(true);
+ config.setForDevice(true);
+ config.setSort(sort);
+
+ // Wrap the MDR channel with the MDRFile object
+ try {
+ tmpName = File.createTempFile("mdr", null, new File(outputDir));
+ tmpName.deleteOnExit();
+ ImgChannel channel = new FileImgChannel(tmpName.getPath(), "rw");
+ mdrFile = new MDRFile(channel, config);
+ toClose.push(mdrFile);
+ } catch (IOException e) {
+ throw new ExitException("Could not create temporary index file");
+ }
+ }
+
+ /**
+ * Create the sort description for the mdr. This is converted into a SRT which is included
+ * in the mdr.img and also it is used to actually sort the text items within the file itself.
+ *
+ * We simply use the code page to locate a sorting description, we could have several for the same
+ * code page for different countries for example.
+ *
+ * @param codepage The code page which is used to find a suitable sort description.
+ * @return A sort description object.
+ */
+ private Sort createSort(int codepage) {
+ String name = "sort/cp" + codepage + ".txt";
+ InputStream is = getClass().getClassLoader().getResourceAsStream(name);
+ if (is == null) {
+ return Sort.defaultSort(codepage);
+ }
+ try {
+ InputStreamReader r = new InputStreamReader(is, "utf-8");
+ SrtTextReader sr = new SrtTextReader(r);
+ return sr.getSort();
+ } catch (IOException e) {
+ return Sort.defaultSort(codepage);
+ }
+ }
+
+ /**
+ * Adds a new map to the file. We need to read in the img file and
+ * extract all the information that can be indexed from it.
+ *
+ * @param info An interface to read the map.
+ */
+ public void onMapEnd(FileInfo info) {
+ if (!info.isImg())
+ return;
+
+ // Add the map name
+ mdrFile.addMap(info.getHexname(), info.getCodePage());
+
+ String filename = info.getFilename();
+ MapReader mr = null;
+ try {
+ mr = new MapReader(filename);
+
+ AreaMaps maps = new AreaMaps();
+
+ maps.countries = addCountries(mr);
+ maps.regions = addRegions(mr, maps);
+ List<Mdr5Record> mdrCityList = fetchCities(mr, maps);
+ maps.cityList = mdrCityList;
+
+ addPoints(mr, maps);
+ addCities(mdrCityList);
+ addStreets(mr, mdrCityList);
+ addZips(mr);
+ } catch (FileNotFoundException e) {
+ throw new ExitException("Could not open " + filename + " when creating mdr file");
+ } finally {
+ Utils.closeFile(mr);
+ }
+ }
+
+ private Map<Integer, Mdr14Record> addCountries(MapReader mr) {
+ Map<Integer, Mdr14Record> countryMap = new HashMap<Integer, Mdr14Record>();
+ List<Country> countries = mr.getCountries();
+ for (Country c : countries) {
+ if (c != null) {
+ Mdr14Record record = mdrFile.addCountry(c);
+ countryMap.put((int) c.getIndex(), record);
+ }
+ }
+ return countryMap;
+ }
+
+ private Map<Integer, Mdr13Record> addRegions(MapReader mr, AreaMaps maps) {
+ Map<Integer, Mdr13Record> regionMap = new HashMap<Integer, Mdr13Record>();
+
+ List<Region> regions = mr.getRegions();
+ for (Region region : regions) {
+ if (region != null) {
+ Mdr14Record mdr14 = maps.countries.get((int) region.getCountry().getIndex());
+ Mdr13Record record = mdrFile.addRegion(region, mdr14);
+ regionMap.put((int) region.getIndex(), record);
+ }
+ }
+ return regionMap;
+ }
+
+ /**
+ * There is not complete information that we need about a city in the city
+ * section, it has to be completed from the points section. So we fetch
+ * and create the mdr5s first before points.
+ */
+ private List<Mdr5Record> fetchCities(MapReader mr, AreaMaps maps) {
+ Map<Integer, Mdr5Record> cityMap = maps.cities;
+
+ List<Mdr5Record> cityList = new ArrayList<Mdr5Record>();
+ List<City> cities = mr.getCities();
+ for (City c : cities) {
+ int regionCountryNumber = c.getRegionCountryNumber();
+ Mdr13Record mdrRegion = null;
+ Mdr14Record mdrCountry;
+ if ((regionCountryNumber & 0x4000) == 0) {
+ mdrRegion = maps.regions.get(regionCountryNumber);
+ mdrCountry = mdrRegion.getMdr14();
+ } else {
+ mdrCountry = maps.countries.get(regionCountryNumber & 0x3fff);
+ }
+ Mdr5Record mdrCity = new Mdr5Record();
+ mdrCity.setCityIndex(c.getIndex());
+ mdrCity.setRegionIndex(c.getRegionCountryNumber());
+ mdrCity.setMdrRegion(mdrRegion);
+ mdrCity.setMdrCountry(mdrCountry);
+ mdrCity.setLblOffset(c.getLblOffset());
+ mdrCity.setName(c.getName());
+
+ int key = (c.getSubdivNumber() << 8) + (c.getPointIndex() & 0xff);
+ assert key < 0xffffff;
+ cityMap.put(key, mdrCity);
+ cityList.add(mdrCity);
+ }
+
+ return cityList;
+ }
+
+ /**
+ * Now really add the cities.
+ * @param cityList The previously saved cities.
+ */
+ private void addCities(List<Mdr5Record> cityList) {
+ for (Mdr5Record c : cityList) {
+ mdrFile.addCity(c);
+ }
+ }
+ private void addZips(MapReader mr) {
+ List<Zip> zips = mr.getZips();
+ for (Zip zip : zips)
+ mdrFile.addZip(zip);
+ }
+
+ /**
+ * Read points from this map and add them to the index.
+ * @param mr The currently open map.
+ * @param maps Maps of regions, cities countries etc.
+ */
+ private void addPoints(MapReader mr, AreaMaps maps) {
+ List<Point> list = mr.pointsForLevel(0, MapReader.WITHOUT_EXT_TYPE_DATA);
+ for (Point p : list) {
+ Label label = p.getLabel();
+ if (p.getNumber() > 256) {
+ // I think we limit the number of points+ind-points, but just in case
+ System.out.println("point number too big");
+ continue;
+ }
+
+ Mdr5Record mdrCity = null;
+ boolean isCity;
+ if (p.getType() >= 0x1 && p.getType() <= 0x11) {
+ // This is itself a city, it gets a reference to its own MDR 5 record.
+ // and we also use it to set the name of the city.
+ mdrCity = maps.cities.get((p.getSubdiv().getNumber() << 8) + p.getNumber());
+ if (mdrCity != null) {
+ mdrCity.setLblOffset(label.getOffset());
+ mdrCity.setName(label.getText());
+ }
+ isCity = true;
+ } else {
+ // This is not a city, but we have information about which city
+ // it is in. If so then add the mdr5 record number of the city.
+ POIRecord poi = p.getPOIRecord();
+ City c = poi.getCity();
+ if (c != null)
+ mdrCity = getMdr5FromCity(maps, c);
+ isCity = false;
+ }
+
+ if (label != null && !label.getText().trim().isEmpty())
+ mdrFile.addPoint(p, mdrCity, isCity);
+ }
+ }
+
+ private void addStreets(MapReader mr, List<Mdr5Record> cityList) {
+ List<RoadDef> roads = mr.getRoads();
+
+ for (RoadDef road : roads) {
+ String name = road.getName();
+ if (name == null || name.isEmpty())
+ continue;
+
+ Mdr5Record mdrCity = null;
+ if (road.getCity() != null) {
+ mdrCity = cityList.get(road.getCity().getIndex() - 1);
+ if (mdrCity.getMapIndex() == 0)
+ mdrCity = null;
+ }
+
+ mdrFile.addStreet(road, mdrCity);
+ }
+ }
+
+ private Mdr5Record getMdr5FromCity(AreaMaps cityMap, City c) {
+ if (c == null)
+ return null;
+
+ if (c.getPointIndex() > 0) {
+ return cityMap.cities.get((c.getSubdivNumber() << 8) + (c.getPointIndex() & 0xff));
+ } else {
+ return cityMap.cityList.get(c.getIndex() - 1);
+ }
+ }
+
+ public void onFinish() {
+ // Write out the mdr file
+ mdrFile.write();
+
+ // Close everything
+ for (Closeable file : toClose)
+ Utils.closeFile(file);
+
+ // Rename from the temporary file to the proper name. On windows the target file must
+ // not exist for rename to work, so we are forced to remove it first.
+ File outputName = new File(this.outputName);
+ outputName.delete();
+ boolean ok = tmpName.renameTo(outputName);
+ if (!ok)
+ throw new MapFailedException("Could not create mdr.img file");
+ }
+
+ void onFinishForDevice() {
+ // Write out the mdr file
+ mdrFile.write();
+
+ // Close everything
+ for (Closeable file : toClose)
+ Utils.closeFile(file);
+ }
+
+ public int getSize() {
+ return (int) tmpName.length();
+ }
+
+ public String getFileName() {
+ return tmpName.getPath();
+ }
+
+ /**
+ * Holds lookup maps for cities, regions and countries. Used to
+ * link streets, pois to cities, regions and countries.
+ *
+ * These are only held for a single map at a time, which is
+ * sufficient to link them all up.
+ */
+ class AreaMaps {
+ private final Map<Integer, Mdr5Record> cities = new HashMap<Integer, Mdr5Record>();
+ private Map<Integer, Mdr13Record> regions;
+ private Map<Integer, Mdr14Record> countries;
+ private List<Mdr5Record> cityList;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/combiners/MdxBuilder.java b/src/uk/me/parabola/mkgmap/combiners/MdxBuilder.java
new file mode 100644
index 0000000..d700f52
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/combiners/MdxBuilder.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.combiners;
+
+import java.io.IOException;
+
+import uk.me.parabola.imgfmt.ExitException;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.mdxfmt.MdxFile;
+import uk.me.parabola.mkgmap.CommandArgs;
+
+/**
+ * Create the mdx file which is basically just a list of maps in a set.
+ * It is required for use with the global index file (mdr).
+ *
+ * @author Steve Ratcliffe
+ */
+public class MdxBuilder implements Combiner {
+ private MdxFile mdx;
+ private String mdxFilename;
+ private String outputDir;
+
+ public void init(CommandArgs args) {
+ int familyId = args.get("family-id", CommandArgs.DEFAULT_FAMILYID);
+ int productId = args.get("product-id", 1);
+
+ mdxFilename = args.get("overview-mapname", "osm") + ".mdx";
+ mdx = new MdxFile(familyId, productId);
+
+ outputDir = args.getOutputDir();
+ }
+
+ public void onMapEnd(FileInfo info) {
+ if (!info.isImg())
+ return;
+
+ mdx.addMap(info.getMapnameAsInt(), info.getHexname(),
+ info.getFilename());
+ }
+
+ public void onFinish() {
+ try {
+ mdx.write(Utils.joinPath(outputDir, mdxFilename));
+ } catch (IOException e) {
+ throw new ExitException("Could not create MDX file", e);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/combiners/NsisBuilder.java b/src/uk/me/parabola/mkgmap/combiners/NsisBuilder.java
new file mode 100644
index 0000000..f59a6fc
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/combiners/NsisBuilder.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.combiners;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.mkgmap.CommandArgs;
+import uk.me.parabola.mkgmap.Version;
+
+
+public class NsisBuilder implements Combiner {
+ private String baseFilename;
+ private String nsisFilename;
+ private String licenseFilename;
+ private String outputDir;
+ private String familyName;
+ private String id;
+ private int productId;
+
+ private boolean hasIndex;
+ private boolean hasTyp;
+
+ private final List<String> mapList = new ArrayList<String>();
+ private String typName;
+
+ public void init(CommandArgs args) {
+ int familyId = args.get("family-id", CommandArgs.DEFAULT_FAMILYID);
+ productId = args.get("product-id", 1);
+
+ baseFilename = args.get("overview-mapname", "osmmap");
+ familyName = args.get("family-name", "OSM map");
+
+ String tmpId = Integer.toHexString(0x10000 | familyId);
+
+ id = tmpId.substring(3, 5) + tmpId.substring(1, 3);
+
+ nsisFilename = baseFilename + ".nsi";
+ licenseFilename = baseFilename + "_license.txt";
+
+ outputDir = args.getOutputDir();
+
+ hasIndex = args.exists("index");
+ }
+
+ public void onMapEnd(FileInfo info) {
+ switch (info.getKind()) {
+ case IMG_KIND:
+ mapList.add(info.getMapname());
+ break;
+ case TYP_KIND:
+ hasTyp = true;
+ File typFile = new File(info.getFilename());
+ typName = typFile.getName();
+ break;
+ case MDR_KIND:
+ hasIndex = true;
+ break;
+ case GMAPSUPP_KIND:
+ break;
+ }
+ }
+
+ public void onFinish() {
+ writeNsisFile();
+ writeLicenceFile();
+ }
+
+ private void writeNsisFile() {
+ InputStream inStream;
+
+ try {
+ inStream = new FileInputStream("resources/installer_template.nsi");
+ } catch (Exception ex) {
+ inStream = null;
+ }
+
+ if(inStream == null) // If not loaded from disk use from jar file
+ inStream = this.getClass().getResourceAsStream("/installer/installer_template.nsi");
+
+ if (inStream == null) {
+ System.err.println("Could not find the installer template.");
+ return;
+ }
+ Writer w = null;
+ try {
+ BufferedReader br = new BufferedReader(new InputStreamReader(inStream));
+ w = new FileWriter(Utils.joinPath(outputDir, nsisFilename));
+ PrintWriter pw = new PrintWriter(w);
+
+ String strLine;
+ while ((strLine = br.readLine()) != null) {
+ if (strLine.contains("INSERT_DEFINES_HERE"))
+ writeDefines(pw);
+ else if (strLine.contains("INSERT_REGBIN_HERE"))
+ writeRegBin(pw);
+ else if (strLine.contains("INSERT_ADDED_FILES_HERE"))
+ writeAddedFiles(pw);
+ else if (strLine.contains("INSERT_REMOVED_FILES_HERE"))
+ writeRemovedFiles(pw);
+ else
+ pw.format(Locale.ROOT, strLine + "\n");
+ }
+ } catch (IOException e) {
+ System.err.println("Could not write NSIS file");
+ } finally {
+ Utils.closeFile(w);
+ }
+ }
+
+ private void writeDefines(PrintWriter pw) {
+ pw.format(Locale.ROOT, "!define DEFAULT_DIR \"C:\\Garmin\\Maps\\%s\"\n", familyName);
+ pw.format(Locale.ROOT, "!define INSTALLER_DESCRIPTION \"%s\"\n", familyName);
+ pw.format(Locale.ROOT, "!define INSTALLER_NAME \"%s\"\n", familyName);
+ pw.format(Locale.ROOT, "!define MAPNAME \"%s\"\n", baseFilename);
+ pw.format(Locale.ROOT, "!define PRODUCT_ID \"%s\"\n", productId);
+ pw.format(Locale.ROOT, "!define REG_KEY \"%s\"\n", familyName);
+ if (hasIndex)
+ pw.format(Locale.ROOT, "!define INDEX\n");
+ if (hasTyp)
+ pw.format(Locale.ROOT, "!define TYPNAME \"%s\"\n", typName);
+ }
+
+ private void writeRegBin(PrintWriter pw) {
+ // Ideally we should have a define for the family value but NSIS won't allow "hexadecimal" variables
+ pw.format(Locale.ROOT, " WriteRegBin HKLM \"SOFTWARE\\Garmin\\MapSource\\Families\\${REG_KEY}\" \"ID\" %s\n", id);
+}
+
+ private void writeAddedFiles(PrintWriter pw) {
+ pw.format(Locale.ROOT, " File \"${MAPNAME}.img\"\n");
+ if (hasIndex) {
+ pw.format(Locale.ROOT, " File \"${MAPNAME}_mdr.img\"\n");
+ pw.format(Locale.ROOT, " File \"${MAPNAME}.mdx\"\n");
+ }
+ if (hasTyp)
+ pw.format(Locale.ROOT, " File \"%s\"\n", typName);
+
+ pw.format(Locale.ROOT, " File \"${MAPNAME}.tdb\"\n");
+ for (String file : mapList)
+ pw.format(Locale.ROOT, " File \"%s.img\"\n", file);
+ }
+
+
+
+ private void writeRemovedFiles(PrintWriter pw) {
+ pw.format(Locale.ROOT, " Delete \"$INSTDIR\\${MAPNAME}.img\"\n");
+ if (hasIndex) {
+ pw.format(Locale.ROOT, " Delete \"$INSTDIR\\${MAPNAME}_mdr.img\"\n");
+ pw.format(Locale.ROOT, " Delete \"$INSTDIR\\${MAPNAME}.mdx\"\n");
+ }
+ if (hasTyp)
+ pw.format(Locale.ROOT, " Delete \"$INSTDIR\\%s\"\n", typName);
+ pw.format(Locale.ROOT, " Delete \"$INSTDIR\\${MAPNAME}.tdb\"\n");
+ for (String file : mapList) {
+ pw.format(Locale.ROOT, " Delete \"$INSTDIR\\%s.img\"\n", file);
+ }
+ pw.format(Locale.ROOT, " Delete \"$INSTDIR\\Uninstall.exe\"\n");
+ }
+
+
+ /**
+ * We write out a license file that is included in the installer.
+ */
+ private void writeLicenceFile() {
+ InputStream inStream;
+ try {
+ inStream = new FileInputStream("resources/license_template.txt");
+ } catch (Exception ex) {
+ inStream = null;
+ }
+
+ if(inStream == null) // If not loaded from disk use from jar file
+ inStream = this.getClass().getResourceAsStream("/installer/license_template.txt");
+
+ if (inStream == null) {
+ System.err.println("Could not find the license template.");
+ return;
+ }
+ Writer w = null;
+ try {
+ BufferedReader br = new BufferedReader(new InputStreamReader(inStream));
+ w = new FileWriter(Utils.joinPath(outputDir, licenseFilename));
+ PrintWriter pw = new PrintWriter(w);
+
+ String strLine;
+ while ((strLine = br.readLine()) != null) {
+ pw.format(Locale.ROOT, strLine + "\n");
+ }
+
+ pw.format(Locale.ROOT, "Map created with mkgmap-r" + Version.VERSION +"\n");
+ } catch (IOException e) {
+ System.err.println("Could not write license file");
+ } finally {
+ Utils.closeFile(w);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/combiners/OverviewBuilder.java b/src/uk/me/parabola/mkgmap/combiners/OverviewBuilder.java
new file mode 100644
index 0000000..9f6fa08
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/combiners/OverviewBuilder.java
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.combiners;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import uk.me.parabola.imgfmt.ExitException;
+import uk.me.parabola.imgfmt.FileExistsException;
+import uk.me.parabola.imgfmt.FileNotWritableException;
+import uk.me.parabola.imgfmt.FileSystemParam;
+import uk.me.parabola.imgfmt.MapFailedException;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.map.Map;
+import uk.me.parabola.imgfmt.app.map.MapReader;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.trergn.Point;
+import uk.me.parabola.imgfmt.app.trergn.Polygon;
+import uk.me.parabola.imgfmt.app.trergn.Polyline;
+import uk.me.parabola.imgfmt.app.trergn.Zoom;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.CommandArgs;
+import uk.me.parabola.mkgmap.build.MapBuilder;
+import uk.me.parabola.mkgmap.general.LevelInfo;
+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.srt.SrtTextReader;
+
+/**
+ * Build the overview map. This is a low resolution map that covers the whole
+ * of a map set. It also contains polygons that correspond to the areas
+ * covered by the individual map tiles.
+ *
+ * @author Steve Ratcliffe
+ */
+public class OverviewBuilder implements Combiner {
+ Logger log = Logger.getLogger(OverviewBuilder.class);
+ public static final String OVERVIEW_PREFIX = "ovm_";
+ private final OverviewMap overviewSource;
+ private String areaName;
+ private String overviewMapname;
+ private String overviewMapnumber;
+ private Zoom[] levels;
+ private String outputDir;
+ private Integer codepage;
+ private Integer encodingType;
+ private List<String[]> copyrightMsgs = new ArrayList<String[]>();
+ private List<String[]> licenseInfos = new ArrayList<String[]>();
+
+
+ public OverviewBuilder(OverviewMap overviewSource) {
+ this.overviewSource = overviewSource;
+ }
+
+ public void init(CommandArgs args) {
+ areaName = args.get("area-name", "Overview Map");
+ overviewMapname = args.get("overview-mapname", "osmmap");
+ overviewMapnumber = args.get("overview-mapnumber", "63240000");
+ outputDir = args.getOutputDir();
+ }
+
+ public void onMapEnd(FileInfo finfo) {
+ if (!finfo.isImg())
+ return;
+
+ try {
+ readFileIntoOverview(finfo);
+ } catch (FileNotFoundException e) {
+ throw new MapFailedException("Could not read detail map " + finfo.getFilename(), e);
+ }
+ }
+
+ public void onFinish() {
+ addBackground();
+ writeOverviewMap();
+ }
+
+ /**
+ * Add background polygon that covers the whole area of the overview map.
+ */
+ private void addBackground() {
+ MapShape background = new MapShape();
+ background.setType(0x4b); // background type
+ background.setMinResolution(0); // On all levels
+ background.setPoints(overviewSource.getBounds().toCoords());
+
+ overviewSource.addShape(background);
+ }
+
+ /**
+ * Write out the overview map.
+ */
+ private void writeOverviewMap() {
+ if (overviewSource.mapLevels() == null)
+ return;
+ MapBuilder mb = new MapBuilder();
+ mb.setEnableLineCleanFilters(false);
+
+ FileSystemParam params = new FileSystemParam();
+ params.setBlockSize(512);
+ params.setMapDescription(areaName);
+ mb.setCopyrights(creMsgList(copyrightMsgs));
+ mb.setMapInfo(creMsgList(licenseInfos));
+
+
+ try {
+ if (codepage == null){
+ codepage = 0; // should not happen
+ }
+ Sort sort = SrtTextReader.sortForCodepage(codepage);
+ Map map = Map.createMap(overviewMapname, outputDir, params, overviewMapnumber, sort);
+
+ if (encodingType != null){
+ map.getLblFile().setEncoder(encodingType, codepage);
+ }
+ mb.makeMap(map, overviewSource);
+ map.close();
+ } catch (FileExistsException e) {
+ throw new ExitException("Could not create overview map", e);
+ } catch (FileNotWritableException e) {
+ throw new ExitException("Could not write to overview map", e);
+ }
+ }
+
+ /**
+ * Add an individual .img file to the overview map.
+ *
+ * @param finfo Information about an individual map.
+ */
+ private void readFileIntoOverview(FileInfo finfo) throws FileNotFoundException {
+ addMapCoverageArea(finfo);
+
+ MapReader mapReader = null;
+ String filename = finfo.getFilename();
+ if (codepage == null){
+ codepage = finfo.getCodePage();
+ }
+ if (codepage != finfo.getCodePage()){
+ System.err.println("WARNING: input file " + filename + " has different code page " + finfo.getCodePage());
+ }
+
+ try{
+ mapReader = new MapReader(filename);
+
+ if (encodingType == null){
+ encodingType = mapReader.getEncodingType();
+ }
+ if (encodingType != mapReader.getEncodingType()){
+ System.err.println("WARNING: input file " + filename + " has different charset type " + encodingType);
+ }
+
+ String[] msgs = mapReader.getCopyrights();
+ boolean found = false;
+ for (String[] block : copyrightMsgs) {
+ if (Arrays.deepEquals(block, msgs)){
+ found = true;
+ break;
+ }
+ }
+ if (!found )
+ copyrightMsgs.add(msgs);
+
+ msgs = finfo.getLicenseInfo();
+ found = false;
+ for (String[] block : licenseInfos) {
+ if (Arrays.deepEquals(block, msgs)){
+ found = true;
+ break;
+ }
+ }
+ if (!found )
+ licenseInfos.add(msgs);
+
+
+ levels = mapReader.getLevels();
+ if (overviewSource.mapLevels() == null){
+ LevelInfo[] mapLevels;
+ if (isOverviewImg(filename)){
+ mapLevels = new LevelInfo[levels.length-1];
+ for (int i = 1; i < levels.length; i++){
+ mapLevels[i-1] = new LevelInfo(levels[i].getLevel(), levels[i].getResolution());
+ }
+ } else {
+ mapLevels = new LevelInfo[1];
+ mapLevels[0] = new LevelInfo(levels[1].getLevel(), levels[1].getResolution());
+ }
+ overviewSource.setMapLevels(mapLevels);
+ }
+ if (isOverviewImg(filename)){
+ readPoints(mapReader);
+ readLines(mapReader);
+ readShapes(mapReader);
+ }
+ } catch (FileNotFoundException e) {
+ throw new ExitException("Could not open " + filename + " when creating overview file");
+ } finally {
+ Utils.closeFile(mapReader);
+ }
+ }
+
+ /**
+ * Read the points from the .img file and add them to the overview map.
+ * We read from the least detailed level (apart from the empty one).
+ *
+ * @param mapReader Map reader on the detailed .img file.
+ */
+ private void readPoints(MapReader mapReader) {
+ Area bounds = overviewSource.getBounds();
+ for (int l = 1; l < levels.length; l++){
+ int min = levels[l].getLevel();
+ int res = levels[l].getResolution();
+ List<Point> pointList = mapReader.pointsForLevel(min, MapReader.WITH_EXT_TYPE_DATA);
+ for (Point point: pointList) {
+ if (log.isDebugEnabled())
+ log.debug("got point", point);
+ if (bounds.contains(point.getLocation()) == false){
+ if (log.isDebugEnabled())
+ log.debug(point, "dropped, is outside of tile boundary");
+ continue;
+ }
+ MapPoint mp = new MapPoint();
+ mp.setType(point.getType());
+ mp.setName(point.getLabel().getText());
+ mp.setMaxResolution(res);
+ mp.setMinResolution(res);
+ mp.setLocation(point.getLocation());
+ overviewSource.addPoint(mp);
+ }
+ }
+ }
+
+ /**
+ * Read the lines from the .img file and add them to the overview map.
+ * We read from the least detailed level (apart from the empty one).
+ *
+ * @param mapReader Map reader on the detailed .img file.
+ */
+ private void readLines(MapReader mapReader) {
+ for (int l = 1; l < levels.length; l++){
+ int min = levels[l].getLevel();
+ int res = levels[l].getResolution();
+ List<Polyline> lineList = mapReader.linesForLevel(min);
+ //System.out.println(lineList.size() + " lines in lowest resolution " + levels[1].getResolution());
+ for (Polyline line : lineList) {
+ if (log.isDebugEnabled())
+ log.debug("got line", line);
+ MapLine ml = new MapLine();
+
+ List<Coord> points = line.getPoints();
+ if (log.isDebugEnabled())
+ log.debug("line point list", points);
+ if (points.size() < 2)
+ continue;
+
+ ml.setType(line.getType());
+ if (line.getLabel() != null)
+ ml.setName(line.getLabel().getText());
+ ml.setMaxResolution(res);
+ ml.setMinResolution(res);
+ ml.setPoints(points);
+
+ overviewSource.addLine(ml);
+ }
+ }
+ }
+
+ /**
+ * Read the polygons from the .img file and add them to the overview map.
+ * We read from the least detailed level (apart from the empty one).
+ *
+ * @param mapReader Map reader on the detailed .img file.
+ */
+ private void readShapes(MapReader mapReader) {
+ for (int l = 1; l < levels.length; l++){
+ int min = levels[l].getLevel();
+ int res = levels[l].getResolution();
+ List<Polygon> list = mapReader.shapesForLevel(min);
+ for (Polygon shape : list) {
+ if (log.isDebugEnabled())
+ log.debug("got polygon", shape);
+ if (shape.getType() == 0x4b){
+ // ignore existing background polygons as we will add our own
+ continue;
+ }
+ MapShape ms = new MapShape();
+
+ List<Coord> points = shape.getPoints();
+ if (log.isDebugEnabled())
+ log.debug("polygon point list", points);
+
+ if (points.size() < 3)
+ continue;
+
+ ms.setType(shape.getType());
+ if (shape.getLabel() != null)
+ ms.setName(shape.getLabel().getText());
+ ms.setMaxResolution(res);
+ ms.setMinResolution(res);
+ ms.setPoints(points);
+
+ overviewSource.addShape(ms);
+ }
+ }
+ }
+
+ /**
+ * Add an area that shows the area covered by a detailed map. This can
+ * be an arbitary shape, although at the current time we only support
+ * rectangles.
+ *
+ * @param finfo Information about a detail map.
+ */
+ private void addMapCoverageArea(FileInfo finfo) {
+ Area bounds = finfo.getBounds();
+ List<Coord> points = bounds.toCoords();
+
+ for (Coord co: points){
+ overviewSource.addToBounds(co);
+ }
+ // Create the background rectangle
+ MapShape bg = new MapShape();
+ bg.setType(0x4a);
+ bg.setPoints(points);
+ bg.setMinResolution(0);
+ bg.setName(finfo.getDescription() + '\u001d' + finfo.getMapname());
+
+ overviewSource.addShape(bg);
+ }
+
+ public Area getBounds() {
+ return overviewSource.getBounds();
+ }
+
+ /**
+ * Check if the the file name points to a partly overview img file
+ * @param name full path or just a name
+ * @return true if the name points to a partly overview img file
+ */
+ public static boolean isOverviewImg (String name){
+ return new File(name).getName().startsWith(OVERVIEW_PREFIX);
+ }
+ /**
+ * Add the prefix to the file name.
+ * @param name filename
+ * @return filename of the corresponding overview img file
+ */
+ public static String getOverviewImgName (String name){
+ File f = new File(name);
+ return new File(f.getParent(),OverviewBuilder.OVERVIEW_PREFIX + f.getName()).getAbsolutePath();
+ }
+
+ public static String getMapName(String name) {
+ String fname = new File(name).getName();
+ if (fname.startsWith(OVERVIEW_PREFIX))
+ return fname.substring(OVERVIEW_PREFIX.length());
+ else return name;
+ }
+
+ private List<String> creMsgList(List<String[]> msgs){
+ ArrayList< String> list = new ArrayList<String>();
+ for (int i = 0; i < msgs.size(); i++){
+ String[] block = msgs.get(i);
+ for (String s : block){
+ list.add(s);
+ }
+ if (i < msgs.size()-1){
+ // separate blocks
+ list.add("");
+ }
+ }
+ return list;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/combiners/OverviewMap.java b/src/uk/me/parabola/mkgmap/combiners/OverviewMap.java
new file mode 100644
index 0000000..25599a7
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/combiners/OverviewMap.java
@@ -0,0 +1,39 @@
+/*
+ * 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: 25-Sep-2007
+ */
+package uk.me.parabola.mkgmap.combiners;
+
+import uk.me.parabola.mkgmap.general.LevelInfo;
+import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
+import uk.me.parabola.mkgmap.general.MapCollector;
+
+/**
+ * This is the interface that is used to create the overview map. We will then
+ * read back the map via a LoadableMapDataSource.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface OverviewMap extends LoadableMapDataSource, MapCollector {
+
+ /**
+ * Add a copyright string to the map.
+ *
+ * @param cw The string to add.
+ */
+ public void addCopyright(String cw);
+
+ public void setMapLevels(LevelInfo[] levels);
+}
diff --git a/src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java b/src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java
new file mode 100644
index 0000000..7d2a34c
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java
@@ -0,0 +1,196 @@
+/*
+ * 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: Dec 9, 2007
+ */
+package uk.me.parabola.mkgmap.combiners;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.ExitException;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.map.MapReader;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.CommandArgs;
+import uk.me.parabola.tdbfmt.DetailMapBlock;
+import uk.me.parabola.tdbfmt.TdbFile;
+
+/**
+ * Build the TDB file and the overview map.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TdbBuilder implements Combiner {
+ private static final Logger log = Logger.getLogger(TdbBuilder.class);
+
+ private final OverviewBuilder overviewBuilder;
+
+ private TdbFile tdb;
+
+ private int parent = 63240000;
+ private String overviewMapname;
+ private String overviewMapnumber;
+ private String outputDir;
+ private int tdbVersion;
+ private List<String[]> copyrightMsgs = new ArrayList<String[]>();
+
+ public TdbBuilder(OverviewBuilder ovb) {
+ overviewBuilder = ovb;
+ }
+
+
+ /**
+ * Initialise by saving all the information we require from the command line
+ * args.
+ *
+ * @param args The command line arguments as they are at the end of the list.
+ * In other words if the same argument appears more than once, then it will
+ */
+ public void init(CommandArgs args) {
+ overviewMapname = args.get("overview-mapname", "osmmap");
+ overviewMapnumber = args.get("overview-mapnumber", "63240000");
+
+ try {
+ parent = Integer.parseInt(overviewMapnumber);
+ } catch (NumberFormatException e) {
+ log.debug("overview map number not an integer", overviewMapnumber);
+ }
+
+ String areaName = args.get("area-name", "Overview Map");
+
+ int familyId = args.get("family-id", CommandArgs.DEFAULT_FAMILYID);
+ int productId = args.get("product-id", 1);
+ short productVersion = (short)args.get("product-version", 100);
+
+ String seriesName = args.get("series-name", "OSM map");
+ String familyName = args.get("family-name", "OSM map");
+
+ tdbVersion = TdbFile.TDB_V407;
+
+ // enable "show profile" button for routes in mapsource
+ // this is supported only in version 403 and above
+ byte enableProfile = (byte) args.get("show-profiles", 0);
+
+ tdb = new TdbFile(tdbVersion);
+ tdb.setProductInfo(familyId, productId, productVersion, seriesName,
+ familyName, areaName, enableProfile);
+ tdb.setCodePage(args.getCodePage());
+
+ outputDir = args.getOutputDir();
+ }
+
+ /**
+ * Called at the end of every map that is to be combined. We only deal
+ * with IMG files and ignore everything else.
+ *
+ * @param info Information on the file.
+ */
+ public void onMapEnd(FileInfo info) {
+ if (!info.isImg())
+ return;
+
+ addToTdb(info);
+ }
+
+ /**
+ * Add the information about the current map to the tdb file.
+ *
+ * @param finfo Information about the current .img file.
+ */
+ private void addToTdb(FileInfo finfo) {
+ DetailMapBlock detail = new DetailMapBlock(tdbVersion);
+ detail.setArea(finfo.getBounds());
+ String mapname = finfo.getMapname();
+ String mapdesc = finfo.getDescription();
+
+ detail.setMapName(mapname);
+ detail.setInnername(finfo.getInnername());
+
+ String desc = mapdesc + " (" + mapname + ')';
+ detail.setDescription(desc);
+ detail.setLblDataSize(finfo.getLblsize());
+ detail.setTreDataSize(finfo.getTresize());
+ detail.setRgnDataSize(finfo.getRgnsize());
+ detail.setNetDataSize(finfo.getNetsize());
+ detail.setNodDataSize(finfo.getNodsize());
+
+ log.info("overview-mapname", overviewMapname);
+ log.info("overview-mapnumber", parent);
+ detail.setParentMapNumber(parent);
+
+ tdb.addDetail(detail);
+
+ String[] msgs = finfo.getLicenseInfo();
+ for (String m : msgs)
+ tdb.addCopyright(m);
+
+ MapReader mapReader = null;
+ String filename = finfo.getFilename();
+ try{
+ mapReader = new MapReader(filename);
+
+ msgs = mapReader.getCopyrights();
+ boolean found = false;
+ for (String[] block : copyrightMsgs) {
+ if (Arrays.deepEquals(block, msgs)){
+ found = true;
+ break;
+ }
+ }
+ if (!found ){
+ copyrightMsgs.add(msgs);
+
+ for (String m : msgs)
+ tdb.addCopyright(m);
+ }
+
+ } catch (FileNotFoundException e) {
+ throw new ExitException("Could not open " + filename + " when creating tdb file");
+ } finally {
+ Utils.closeFile(mapReader);
+ }
+
+
+ }
+
+ /**
+ * Called when all the .img files have been processed. We finish up and
+ * create the TDB file and the overview map.
+ */
+ public void onFinish() {
+ log.debug("finishing overview");
+
+ // We can set the overall bounds easily as it was calculated as part of
+ // the overview map.
+ tdb.setOverview(overviewBuilder.getBounds(), overviewMapnumber);
+
+ writeTdbFile();
+ }
+
+ /**
+ * Write out the TDB file at the end of processing.
+ */
+ private void writeTdbFile() {
+ try {
+ tdb.write(Utils.joinPath(outputDir, overviewMapname, "tdb"));
+ } catch (IOException e) {
+ log.error("tdb write", e);
+ throw new ExitException("Could not write the TDB file", e);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/BaseFilter.java b/src/uk/me/parabola/mkgmap/filters/BaseFilter.java
new file mode 100644
index 0000000..5c826ed
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/BaseFilter.java
@@ -0,0 +1,46 @@
+/*
+ * 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: Dec 3, 2007
+ */
+package uk.me.parabola.mkgmap.filters;
+
+import uk.me.parabola.mkgmap.general.MapElement;
+
+/**
+ * A base filter to use that has empty implementations of methods that are not
+ * always used.
+ *
+ * @author Steve Ratcliffe
+ */
+public class BaseFilter implements MapFilter {
+ /**
+ * Empty implementation of the init function.
+ *
+ * @param config Configuration information, giving parameters of the map
+ * level that is being produced through this filter.
+ */
+ public void init(FilterConfig config) {
+ }
+
+ /**
+ * Empty implementation.
+ *
+ * @param element A map element.
+ * @param next This is used to pass the possibly transformed element onward.
+ */
+ public void doFilter(MapElement element, MapFilterChain next) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/DouglasPeuckerFilter.java b/src/uk/me/parabola/mkgmap/filters/DouglasPeuckerFilter.java
new file mode 100644
index 0000000..a9cac6f
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/DouglasPeuckerFilter.java
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ *
+ */
+package uk.me.parabola.mkgmap.filters;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapShape;
+
+/**
+ * This is a filter that smooths out lines at low resolutions. If the element
+ * has no size at all at the given resolution, then it is not passed on down
+ * the chain at all is excluded from the map at that resolution.
+ */
+public class DouglasPeuckerFilter implements MapFilter {
+
+ //private static final double ERROR_DISTANCE = 5.4 / 2; //One unit is 5.4 m, so error dist is 2.6m
+ //Can be increased more, but may lead to artifacts on T-crossings
+ private final double filterDistance;
+ private double maxErrorDistance;
+ private int resolution;
+ private int level;
+
+ public DouglasPeuckerFilter(double filterDistance) {
+ this.filterDistance = filterDistance;
+ }
+
+ public void init(FilterConfig config) {
+ this.resolution = config.getResolution();
+ this.level = config.getLevel();
+ this.maxErrorDistance = filterDistance * (1<< config.getShift());
+ }
+
+ /**
+ * This applies to both lines and polygons. We are going to smooth out
+ * the points in the line so that you do not get jaggies.
+ *
+ * @param element A map element that will be a line or a polygon.
+ * @param next This is used to pass the possibly transformed element onward.
+ */
+ public void doFilter(MapElement element, MapFilterChain next) {
+ // First off we don't touch things if at the highest level of detail
+ if (resolution == 24) {
+ // XXX 24 is not necessarily the highest level.
+ next.doFilter(element);
+ return;
+ }
+
+ MapLine line = (MapLine) element;
+
+ List<Coord> points = line.getPoints();
+
+ // Create a new list to rewrite the points into. Don't alter the original one
+ List<Coord> coords = new ArrayList<Coord>(points.size());
+ coords.addAll(points);
+
+//#if (Node version)
+//Don't touch Coords, which are nodes.
+//So points at crossings will not be moved
+ // For now simplify all points, which are not nodes
+ // and no start and no end point
+ // Loop runs downwards, as the list length gets modified while running
+ int endIndex = coords.size()-1;
+ if (level == 0 || line instanceof MapShape){
+ for(int i = endIndex-1; i > 0; i--) {
+ Coord p = coords.get(i);
+ //int highwayCount = p.getHighwayCount();
+
+ // If a node in the line use the douglas peucker algorithm for upper segment
+ // TODO: Should consider only nodes connected to roads visible at current resolution.
+ if (p.preserved()) {
+ // point is "preserved", don't remove it
+ douglasPeucker(coords, i, endIndex, maxErrorDistance);
+ endIndex = i;
+ }
+ }
+ }
+ // Simplify the rest
+ douglasPeucker(coords, 0, endIndex, maxErrorDistance);
+
+//#else Straight version
+//Do the douglasPeucker on the whole line.
+//Deletes more points, but may lead to incorrect display of crossings at given high error distances
+/*
+ douglasPeucker(coords, 0, n, maxErrorDistance);
+ */
+//#endif
+ MapLine newline = line.copy();
+
+ newline.setPoints(coords);
+ next.doFilter(newline);
+ }
+
+ /**
+ * Reduces point density by Douglas-Peucker algorithm
+ *
+ * @param points The list of points to simplify.
+ * @param startIndex First index of segment. The point with this index will not be changed
+ * @param endIndex Last index of segment. The point with this index will not be changed
+ * @param allowedError Maximal allowed error to be introduced by simplification.
+ * returns number of removed points.
+ */
+ protected void douglasPeucker(List<Coord> points, int startIndex, int endIndex, double allowedError)
+ {
+ if (startIndex >= endIndex)
+ return;
+
+ double maxDistance = 0; //Highest distance
+ int maxIndex = endIndex; //Index of highest distance
+
+ Coord a = points.get(startIndex);
+ Coord b = points.get(endIndex);
+ double ab = a.distance(b);
+
+ if (ab == 0) { // Start- and endpoint are the same
+ // Find point with highest distance to start- and endpoint
+ for (int i = endIndex-1; i > startIndex; i--) {
+ Coord p = points.get(i);
+ double distance = p.distance(a);
+ if (distance > maxDistance) {
+ maxDistance = distance;
+ maxIndex = i;
+ }
+ }
+ } else {
+ // Find point with highest distance to line between start- and endpoint by using herons formula.
+ for(int i = endIndex-1; i > startIndex; i--) {
+ Coord p = points.get(i);
+ double ap = p.distance(a);
+ double bp = p.distance(b);
+ double abpa = (ab+ap+bp)/2;
+ double distance = 2 * Math.sqrt(abpa * (abpa-ab) * (abpa-ap) * (abpa-bp)) / ab;
+ if (distance > maxDistance) {
+ maxDistance = distance;
+ maxIndex = i;
+ }
+ }
+ }
+ if (maxDistance > allowedError) {
+ // Call recursive for both parts
+ douglasPeucker(points, maxIndex, endIndex, allowedError);
+ douglasPeucker(points, startIndex, maxIndex, allowedError);
+ }
+ else {
+ // All points in tolerance, delete all of them.
+
+ // Remove the endpoint if it is the same as the start point
+ if (ab == 0 && points.get(endIndex).preserved() == false)
+ points.remove(endIndex);
+
+ // Remove the points in between
+ for (int i = endIndex - 1; i > startIndex; i--) {
+ points.remove(i);
+ }
+ }
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/FilterConfig.java b/src/uk/me/parabola/mkgmap/filters/FilterConfig.java
new file mode 100644
index 0000000..ddc839b
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/FilterConfig.java
@@ -0,0 +1,68 @@
+/*
+ * 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: Dec 3, 2007
+ */
+package uk.me.parabola.mkgmap.filters;
+
+import uk.me.parabola.imgfmt.app.Area;
+
+/**
+ * Configuration for filters. Some filters may need extra information that
+ * will be provided here.
+ *
+ * @author Steve Ratcliffe
+ */
+public class FilterConfig {
+ private int resolution;
+ private int level;
+ private boolean routable;
+
+ protected int getResolution() {
+ return resolution;
+ }
+
+ public int getShift() {
+ return 24 - getResolution();
+ }
+
+ /**
+ * Set the resolution and shift values.
+ *
+ * @param resolution The resolution.
+ */
+ public void setResolution(int resolution) {
+ this.resolution = resolution;
+ }
+
+ public void setBounds(Area bounds) {
+ //this.bounds = bounds;
+ }
+
+ public int getLevel() {
+ return level;
+ }
+
+ public void setLevel(int level) {
+ this.level = level;
+ }
+
+ public boolean isRoutable() {
+ return routable;
+ }
+
+ public void setRoutable(boolean routable) {
+ this.routable = routable;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/LineMergeFilter.java b/src/uk/me/parabola/mkgmap/filters/LineMergeFilter.java
new file mode 100644
index 0000000..ccb6f6b
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/LineMergeFilter.java
@@ -0,0 +1,115 @@
+package uk.me.parabola.mkgmap.filters;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.util.MultiHashMap;
+
+
+
+public class LineMergeFilter{
+ private static final Logger log = Logger.getLogger(LineMergeFilter.class);
+
+ private List<MapLine> linesMerged;
+ private final MultiHashMap<Coord, MapLine> startPoints = new MultiHashMap<Coord, MapLine>();
+ private final MultiHashMap<Coord, MapLine> endPoints = new MultiHashMap<Coord, MapLine>();
+
+ private void addLine(MapLine line) {
+ linesMerged.add(line);
+ List<Coord> points = line.getPoints();
+ startPoints.add(points.get(0), line);
+ endPoints.add(points.get(points.size()-1), line);
+ }
+
+ private void mergeLines(MapLine line1, MapLine line2) {
+ // Removes the first line,
+ // Merges the points in the second one
+ List<Coord> points1 = line1.getPoints();
+ List<Coord> points2 = line2.getPoints();
+ startPoints.remove(points1.get(0), line1);
+ endPoints.remove(points1.get(points1.size()-1), line1);
+ startPoints.remove(points2.get(0), line2);
+ startPoints.add(points1.get(0), line2);
+ line2.insertPointsAtStart(points1);
+ linesMerged.remove(line1);
+ }
+
+ private void addPointsAtStart(MapLine line, List<Coord> additionalPoints) {
+ log.info("merged lines before " + line.getName());
+ List<Coord> points = line.getPoints();
+ startPoints.remove(points.get(0), line);
+ line.insertPointsAtStart(additionalPoints);
+ startPoints.add(points.get(0), line);
+ }
+
+ private void addPointsAtEnd(MapLine line, List<Coord> additionalPoints) {
+ log.info("merged lines after " + line.getName());
+ List<Coord> points = line.getPoints();
+ endPoints.remove(points.get(points.size()-1), line);
+ line.insertPointsAtEnd(additionalPoints);
+ endPoints.add(points.get(points.size()-1), line);
+ }
+
+ public List<MapLine> merge(List<MapLine> lines) {
+ linesMerged = new ArrayList<MapLine>(lines.size()); //better use LinkedList??
+ for (MapLine line : lines) {
+
+ if (line.isRoad()){
+ linesMerged.add(line);
+ continue;
+ }
+
+ boolean isMerged = false;
+ List<Coord> points = line.getPoints();
+ Coord start = points.get(0);
+ Coord end = points.get(points.size()-1);
+
+ // Search for start point in hashlist
+ // (can the end of current line connected to an existing line?)
+ for (MapLine line2 : startPoints.get(end)) {
+ if (line.isSimilar(line2)) {
+ addPointsAtStart(line2, points);
+ // Search for endpoint in hashlist
+ // (if the other end (=start of line =start of line2) could be connected to an existing line,
+ // both lines has to be merged and one of them dropped)
+ for (MapLine line1 : endPoints.get(start)) {
+ if (line2.isSimilar(line1)
+ && !line2.equals(line1)) // don't make a closed loop a double loop
+ {
+ mergeLines(line1, line2);
+ break;
+ }
+ }
+ isMerged = true;
+ break;
+ }
+ }
+ if (isMerged)
+ continue;
+
+ // Search for endpoint in hashlist
+ // (can the start of current line connected to an existing line?)
+ for (MapLine line2 : endPoints.get(start)) {
+ if (line.isSimilar(line2)) {
+ addPointsAtEnd(line2, points);
+ isMerged = true;
+ break;
+ }
+ }
+ if (isMerged)
+ continue;
+
+ // No matching, create a copy of line
+ MapLine l = line.copy();
+ List<Coord> p = new ArrayList<Coord>(line.getPoints()); //use better LinkedList for performance?
+ l.setPoints(p);
+ addLine(l);
+ }
+ return linesMerged;
+ }
+
+}
+
diff --git a/src/uk/me/parabola/mkgmap/filters/LinePreparerFilter.java b/src/uk/me/parabola/mkgmap/filters/LinePreparerFilter.java
new file mode 100644
index 0000000..65bdf15
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/LinePreparerFilter.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2013.
+ *
+ * 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.filters;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapShape;
+
+/**
+ * This filter does more or less the same calculations as LinePreparer.calcDeltas
+ * It rejects lines that have not enough different points
+ * @author GerdP
+ *
+ */
+public class LinePreparerFilter implements MapFilter {
+
+ private int shift;
+ private final Subdivision subdiv;
+
+ public LinePreparerFilter(Subdivision subdiv) {
+ this.subdiv = subdiv;
+ }
+
+ public void init(FilterConfig config) {
+ shift = config.getShift();
+ }
+
+ /**
+ * @param element A map element that will be a line or a polygon.
+ * @param next This is used to pass the (unchanged) element onward.
+ */
+ public void doFilter(MapElement element, MapFilterChain next) {
+ MapLine line = (MapLine) element;
+
+ int numPoints = line.getPoints().size();
+ boolean first = true;
+ int minPointsRequired = (element instanceof MapShape) ? 3:2;
+ if (minPointsRequired == 3 && line.getPoints().get(0).equals(line.getPoints().get(numPoints-1)))
+ ++minPointsRequired;
+
+ int lastLat = 0;
+ int lastLong = 0;
+ int numPointsEncoded = 1;
+ for (int i = 0; i < numPoints; i++) {
+ Coord co = line.getPoints().get(i);
+
+ int lat = subdiv.roundLatToLocalShifted(co.getLatitude());
+ int lon = subdiv.roundLonToLocalShifted(co.getLongitude());
+
+ if (first) {
+ lastLat = lat;
+ lastLong = lon;
+ first = false;
+ continue;
+ }
+
+ // compute normalized differences
+ // -2^(shift-1) <= dx, dy < 2^(shift-1)
+ // XXX: relies on the fact that java integers are 32 bit signed
+ final int offset = 8+shift;
+ int dx = (lon - lastLong) << offset >> offset;
+ int dy = (lat - lastLat) << offset >> offset;
+ lastLong = lon;
+ lastLat = lat;
+ if (dx == 0 && dy == 0){
+ continue;
+ }
+
+ ++numPointsEncoded;
+ if (numPointsEncoded >= minPointsRequired)
+ break;
+ }
+ if(numPointsEncoded < minPointsRequired)
+ return;
+
+ next.doFilter(element);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/LineSizeSplitterFilter.java b/src/uk/me/parabola/mkgmap/filters/LineSizeSplitterFilter.java
new file mode 100644
index 0000000..4851a45
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/LineSizeSplitterFilter.java
@@ -0,0 +1,194 @@
+/*
+ * 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: Dec 1, 2007
+ */
+package uk.me.parabola.mkgmap.filters;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapRoad;
+import uk.me.parabola.mkgmap.general.MapShape;
+
+/**
+ * A filter to make sure that a line does not have a greater dimension that
+ * would cause an overflow of a TRE area which can only have 15 bits of
+ * size. We want to keep things well under this.
+ *
+ * @author Steve Ratcliffe
+ */
+public class LineSizeSplitterFilter implements MapFilter {
+ private static final Logger log = Logger.getLogger(LineSizeSplitterFilter.class);
+
+ private static final int MAX_SIZE = 0x7fff;
+
+ private int maxSize;
+
+ public void init(FilterConfig config) {
+ int shift = config.getShift();
+ if (shift > 15)
+ shift = 16;
+ maxSize = Math.min((1<<24)-1, Math.max(MAX_SIZE << shift, 0x8000));
+ }
+
+ // return the greater of the absolute values of HEIGHT and WIDTH
+ // divided by the maximum allowed size - so if the height and
+ // width are not too large, the result will be <= 1.0
+ public static double testDims(int height, int width) {
+ return (double)Math.max(Math.abs(height), Math.abs(width)) / MAX_SIZE;
+ }
+
+ /**
+ * Keep track of the max dimensions of a line and split when they get too
+ * big.
+ *
+ * @param element A map element.
+ * @param next This is used to pass the possibly transformed element onward.
+ */
+ public void doFilter(MapElement element, MapFilterChain next) {
+ // We do not deal with shapes.
+ assert !(element instanceof MapShape) && element instanceof MapLine;
+
+ MapLine line = (MapLine) element;
+
+ if (line.getBounds().getMaxDimension() < maxSize) {
+ next.doFilter(element);
+ return;
+ }
+
+ if(line instanceof MapRoad) {
+ MapRoad road = ((MapRoad)line);
+ log.error("Way " + road.getRoadDef() + " has a max dimension of " + line.getBounds().getMaxDimension() + " and is about to be split (routing will be broken)");
+ }
+
+ // ensure that all single lines do not exceed the maximum size
+ // use a slightly decreased max size (-10) to get better results
+ // in the subdivision creation
+ List<Coord> points = splitLinesToMaxSize(line.getPoints(), maxSize-10);
+
+ log.debug("line bbox too big, splitting");
+
+ MapLine l = line.copy();
+
+ List<Coord> coords = new ArrayList<Coord>();
+ boolean first = true;
+
+ /**
+ * Class to keep track of the dimensions.
+ */
+ class Dim {
+ private int minLat;
+ private int minLong;
+ private int maxLat;
+ private int maxLong;
+
+ Dim() {
+ reset();
+ }
+
+ private void reset() {
+ minLat = Integer.MAX_VALUE;
+ minLong = Integer.MAX_VALUE;
+ maxLat = Integer.MIN_VALUE;
+ maxLong = Integer.MIN_VALUE;
+ }
+
+ private void addToBounds(Coord co) {
+ int lat = co.getLatitude();
+ if (lat < minLat)
+ minLat = lat;
+ if (lat > maxLat)
+ maxLat = lat;
+
+ int lon = co.getLongitude();
+ if (lon < minLong)
+ minLong = lon;
+ if (lon > maxLong)
+ maxLong = lon;
+ }
+
+ private int getMaxDim() {
+ int dx = maxLong - minLong;
+ int dy = maxLat - minLat;
+ return Math.max(dx, dy);
+ }
+ }
+
+ Dim dim = new Dim();
+ Coord prev = null;
+
+ // Add points while not too big and then start again with a fresh line.
+ for (Coord co: points){
+ dim.addToBounds(co);
+ if (dim.getMaxDim() > maxSize) {
+ if (first)
+ log.debug("bigness saving first part");
+ else
+ log.debug("bigness saving next part");
+ l.setPoints(coords);
+ next.doFilter(l);
+
+ l = line.copy();
+
+ first = false;
+ dim.reset();
+ coords = new ArrayList<Coord>();
+ coords.add(prev);
+ dim.addToBounds(prev);
+ dim.addToBounds(co);
+ }
+ coords.add(co);
+ prev = co;
+ }
+ assert coords.size() > 1;
+ if (coords.size() > 1) {
+ log.debug("bigness saving a final part");
+ l.setPoints(coords);
+ next.doFilter(l);
+ }
+ }
+
+ /**
+ * If two points of a line are too far from each other, add points between them
+ * so that the bounding box of each pair of points is smaller than the allowed
+ * maximum.
+ * @param coords the list of points
+ * @param maxSize the allowed bounding box height and width
+ * @return a reference to a new list of points
+ */
+ private static List<Coord> splitLinesToMaxSize(List<Coord> coords, int maxSize){
+ List<Coord> testedCoords = new ArrayList<Coord>(coords);
+ int posToTest = coords.size() -2;
+ while (posToTest >= 0){
+ Coord p1 = testedCoords.get(posToTest);
+ Coord p2 = testedCoords.get(posToTest+1);
+ int width = Math.abs( p1.getLongitude() - p2.getLongitude());
+ int height = Math.abs( p1.getLatitude() - p2.getLatitude());
+ if (width > maxSize || height > maxSize){
+ int midLon = (p1.getLongitude() + p2.getLongitude())/2;
+ int midLat = (p1.getLatitude() + p2.getLatitude())/2;
+ testedCoords.add(posToTest+1, new Coord(midLat,midLon));
+ ++posToTest;
+ }
+ else
+ --posToTest;
+ }
+ return testedCoords;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/LineSplitterFilter.java b/src/uk/me/parabola/mkgmap/filters/LineSplitterFilter.java
new file mode 100644
index 0000000..42cee8f
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/LineSplitterFilter.java
@@ -0,0 +1,118 @@
+/*
+ * 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: Dec 1, 2007
+ */
+package uk.me.parabola.mkgmap.filters;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapRoad;
+import uk.me.parabola.mkgmap.general.MapShape;
+
+/**
+ * A filter that ensures that a line does not exceed the allowed number of
+ * points that a line can have. If the line is split, the last part
+ * will have at least 50 points to avoid that too small parts are filtered later.
+ *
+ * @author Steve Ratcliffe
+ */
+public class LineSplitterFilter implements MapFilter {
+ private static final Logger log = Logger.getLogger(LineSplitterFilter.class);
+
+ // Not sure of the value, probably 255. Say 250 here.
+ public static final int MAX_POINTS_IN_LINE = 250;
+ public static final int MIN_POINTS_IN_LINE = 50;
+
+ private int level;
+ private boolean isRoutable;
+ public void init(FilterConfig config) {
+ this.level = config.getLevel();
+ this.isRoutable = config.isRoutable();
+ }
+
+
+ /**
+ * If the line is short enough then we just pass it on straight away.
+ * Otherwise we cut it into pieces that are short enough and hand them
+ * on.
+ *
+ * @param element A map element.
+ * @param next This is used to pass the possibly transformed element onward.
+ */
+ public void doFilter(MapElement element, MapFilterChain next) {
+ // We do not deal with shapes.
+ assert !(element instanceof MapShape) && element instanceof MapLine;
+
+ MapLine line = (MapLine) element;
+
+ List<Coord> points = line.getPoints();
+ int npoints = points.size();
+ if (npoints <= MAX_POINTS_IN_LINE) {
+ next.doFilter(element);
+ return;
+ }
+
+ log.debug("line has too many points, splitting");
+ if(line.isRoad() && level == 0 && isRoutable) {
+ MapRoad road = ((MapRoad)line);
+ log.debug("Way " + road.getRoadDef() + " has more than "+ MAX_POINTS_IN_LINE + " points and is about to be split");
+ }
+
+ MapLine l = line.copy();
+
+ List<Coord> coords = new ArrayList<Coord>();
+ int count = 0;
+ boolean first = true;
+ int remaining = points.size();
+ int wantedSize = (remaining < MAX_POINTS_IN_LINE + MIN_POINTS_IN_LINE) ? remaining / 2 + 10 : MAX_POINTS_IN_LINE;
+
+ for (Coord co : points) {
+ coords.add(co);
+ --remaining;
+
+ if (++count >= wantedSize) {
+ if (first)
+ log.debug("saving first part");
+ else
+ log.debug("saving next part");
+ l.setPoints(coords);
+ if (l instanceof MapRoad){
+ ((MapRoad)l).setSegmentsFollowing(true);
+ }
+ next.doFilter(l);
+
+ l = line.copy();
+ count = 0;
+ first = false;
+ coords = new ArrayList<Coord>();
+ coords.add(co);
+ // make sure that the last part has at least 50 points
+ if (remaining > MAX_POINTS_IN_LINE && remaining < MAX_POINTS_IN_LINE + MIN_POINTS_IN_LINE)
+ wantedSize = remaining / 2 + 10;
+ }
+ }
+
+ if (count != 0) {
+ log.debug("saving a final part");
+ l.setPoints(coords);
+ next.doFilter(l);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/MapFilter.java b/src/uk/me/parabola/mkgmap/filters/MapFilter.java
new file mode 100644
index 0000000..359afbd
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/MapFilter.java
@@ -0,0 +1,56 @@
+/*
+ * 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: Dec 1, 2007
+ */
+package uk.me.parabola.mkgmap.filters;
+
+import uk.me.parabola.mkgmap.general.MapElement;
+
+/**
+ * Used for filtering the elements that are added to the levels. We make several
+ * transformations, such as smoothing lines and splitting them so they do not
+ * overflow limitations for example.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface MapFilter {
+
+ /**
+ * Initialise the filter and pass in parameters that may be needed for
+ * the run.
+ *
+ * @param config Configuration information, giving parameters of the map
+ * level that is being produced through this filter.
+ */
+ public void init(FilterConfig config);
+
+ /**
+ * Filter an element. The filter looks at the element and can simply
+ * pass it on to the next filter in the chain by calling the
+ * {@link MapFilterChain#doFilter(MapElement)} method.
+ *
+ * <p>The filter may modify the element or create a new element or even
+ * more than one element and pass them all to the next part of the chain.
+ *
+ * <p>It is allowed to call the next doFilter more than once (this is used
+ * to split elements for example). You are also allowed to not call it
+ * at all, in which case the element will not appear in the map at that
+ * level.
+ *
+ * @param element A map element.
+ * @param next This is used to pass the possibly transformed element onward.
+ */
+ public void doFilter(MapElement element, MapFilterChain next);
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/MapFilterChain.java b/src/uk/me/parabola/mkgmap/filters/MapFilterChain.java
new file mode 100644
index 0000000..e7158df
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/MapFilterChain.java
@@ -0,0 +1,40 @@
+/*
+ * 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: Dec 1, 2007
+ */
+package uk.me.parabola.mkgmap.filters;
+
+import uk.me.parabola.mkgmap.general.MapElement;
+
+/**
+ * Used to set up a filter chain for adding map elements to an area of the map
+ * at a given level.
+ *
+ * <p>Although this is based on servlet filters, there is a complication in
+ * that we want to be able to split up an element.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface MapFilterChain {
+
+ /**
+ * Pass the element on to the next filter in the chain. If there are no
+ * more then it will be saved for adding to the map.
+ *
+ * @param element The map element.
+ */
+ public void doFilter(MapElement element);
+
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/PolygonSplitterBase.java b/src/uk/me/parabola/mkgmap/filters/PolygonSplitterBase.java
new file mode 100644
index 0000000..b261aa6
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/PolygonSplitterBase.java
@@ -0,0 +1,92 @@
+/*
+ * 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: Dec 6, 2007
+ */
+package uk.me.parabola.mkgmap.filters;
+
+import java.awt.*;
+import java.awt.geom.Area;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.general.MapShape;
+import uk.me.parabola.util.Java2DConverter;
+
+/**
+ * @author Steve Ratcliffe
+ */
+public class PolygonSplitterBase extends BaseFilter {
+ protected static final int MAX_SIZE = 0x7fff;
+
+ /**
+ * Split the given shape and place the resulting shapes in the outputs list.
+ * @param shape The original shape (that is too big).
+ * @param outputs The output list.
+ */
+ protected void split(MapShape shape, List<MapShape> outputs) {
+
+ // Convert to a awt area
+ Area a1 = Java2DConverter.createArea(shape.getPoints());
+
+ // Get the bounds of this polygon
+ Rectangle bounds = a1.getBounds();
+
+ if (bounds.isEmpty())
+ return; // Drop it
+
+ // Cut the bounding box into two rectangles
+ Rectangle r1;
+ Rectangle r2;
+ if (bounds.width > bounds.height) {
+ int halfWidth = bounds.width / 2;
+ r1 = new Rectangle(bounds.x, bounds.y, halfWidth, bounds.height);
+ r2 = new Rectangle(bounds.x + halfWidth, bounds.y, bounds.width - halfWidth, bounds.height);
+ } else {
+ int halfHeight = bounds.height / 2;
+ r1 = new Rectangle(bounds.x, bounds.y, bounds.width, halfHeight);
+ r2 = new Rectangle(bounds.x, bounds.y + halfHeight, bounds.width, bounds.height - halfHeight);
+ }
+
+ // Now find the intersection of these two boxes with the original
+ // polygon. This will make two new areas, and each area will be one
+ // (or more) polygons.
+ Area a2 = (Area) a1.clone();
+ a1.intersect(new Area(r1));
+ a2.intersect(new Area(r2));
+
+ areaToShapes(shape, a1, outputs);
+ areaToShapes(shape, a2, outputs);
+ }
+
+ /**
+ * Convert the area back into {@link MapShape}s. It is possible that the
+ * area is multiple discontiguous polygons, so you may append more than one
+ * shape to the output list.
+ *
+ * @param origShape The original shape, this is only used as a prototype to
+ * copy for the newly created shapes.
+ * @param area The area to be converted.
+ * @param outputs Used to hold output shapes.
+ */
+ private void areaToShapes(MapShape origShape, Area area, List<MapShape> outputs) {
+ List<List<Coord>> subShapePoints = Java2DConverter.areaToShapes(area);
+
+ for (List<Coord> subShape : subShapePoints) {
+ MapShape s = origShape.copy();
+ s.setPoints(subShape);
+ outputs.add(s);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/PolygonSplitterFilter.java b/src/uk/me/parabola/mkgmap/filters/PolygonSplitterFilter.java
new file mode 100644
index 0000000..e5d65c2
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/PolygonSplitterFilter.java
@@ -0,0 +1,86 @@
+/*
+ * 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: Dec 2, 2007
+ */
+package uk.me.parabola.mkgmap.filters;
+
+import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapShape;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Split polygons so that they have less than the maximum number of points.
+ * This is handled by using java built in classes. Basically I am just taking
+ * the bounding box, splitting that in half and getting the intersection of
+ * each half-box with the original shape. Recurse until all are small enough.
+ *
+ * <p>Cutting things up may make discontiguous shapes, but this is handled by
+ * the java classes (for sure) and my code (probably).
+ *
+ * <p>Written assuming that this is not very common, once we start doing sea
+ * areas, may want to re-examine to see if we can optimize.
+ *
+ * @author Steve Ratcliffe
+ */
+public class PolygonSplitterFilter extends PolygonSplitterBase implements MapFilter {
+ public static final int MAX_POINT_IN_ELEMENT = 250;
+
+ /**
+ * Split up polygons that have more than the max allowed number of points.
+ * Initially I shall just throw out polygons that have too many points
+ * to see if this is causing particular problems.
+ *
+ * @param element A map element, only polygons will be processed.
+ * @param next This is used to pass the possibly transformed element onward.
+ */
+ public void doFilter(MapElement element, MapFilterChain next) {
+ assert element instanceof MapShape;
+ MapShape shape = (MapShape) element;
+
+ int n = shape.getPoints().size();
+ if (n < MAX_POINT_IN_ELEMENT) {
+ // This is ok let it through and return.
+ next.doFilter(element);
+ return;
+ }
+
+ List<MapShape> outputs = new ArrayList<MapShape>();
+
+ // Do an initial split
+ split(shape, outputs);
+
+ // Now check that all the resulting parts are also small enough.
+ // NOTE: the end condition is changed from within the loop.
+ for (int i = 0; i < outputs.size(); i++) {
+ MapShape s = outputs.get(i);
+ if (s.getPoints().size() > MAX_POINT_IN_ELEMENT) {
+ // Not small enough, so remove it and split it again. The resulting
+ // pieces will be placed at the end of the list and will be
+ // picked up later on.
+ outputs.set(i, null);
+ split(s, outputs);
+ }
+ }
+
+ // Now add all to the chain.
+ for (MapShape s : outputs) {
+ if (s == null)
+ continue;
+ next.doFilter(s);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/PolygonSubdivSizeSplitterFilter.java b/src/uk/me/parabola/mkgmap/filters/PolygonSubdivSizeSplitterFilter.java
new file mode 100644
index 0000000..961278d
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/PolygonSubdivSizeSplitterFilter.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2010, 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.filters;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.build.MapSplitter;
+import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapShape;
+
+/**
+ * Split polygon so that it does not exceed the limits of a subdivision. The plan
+ * here is simple, if its too big, then cut it in half. As we always cut the largest
+ * dimension, then we will soon enough have cut it down to be small enough.
+ *
+ * @author WanMil
+ */
+public class PolygonSubdivSizeSplitterFilter extends PolygonSplitterBase implements MapFilter {
+ private static final Logger log = Logger.getLogger(PolygonSubdivSizeSplitterFilter.class);
+
+ private int maxSize;
+
+ /**
+ * Get the scale factor so that we don't over split.
+ *
+ * @param config configuration information, giving parameters of the map level
+ * that is being produced through this filter.
+ */
+ public void init(FilterConfig config) {
+ int shift = config.getShift();
+ if (shift > 15)
+ shift = 16;
+ // allow a size of 0x8000 to avoid splitting of generated precomp-sea polygons
+ maxSize = Math.min((1<<24)-1, Math.max(MAX_SIZE << shift, 0x8000));
+ }
+
+ /**
+ * Split up polygons that exceeds the limits of a subdivision.
+ *
+ * @param element A map element, only polygons will be processed.
+ * @param next This is used to pass the possibly transformed element onward.
+ */
+ public void doFilter(MapElement element, MapFilterChain next) {
+ assert element instanceof MapShape;
+ MapShape shape = (MapShape) element;
+
+ if (isSizeOk(shape)) {
+ // This is ok let it through and return.
+ next.doFilter(element);
+ return;
+ }
+
+ List<MapShape> outputs = new ArrayList<MapShape>();
+
+ // Do an initial split
+ split(shape, outputs);
+
+ // Now check that all the resulting parts are also small enough.
+ // NOTE: the end condition is changed from within the loop.
+ for (int i = 0; i < outputs.size(); i++) {
+ MapShape s = outputs.get(i);
+ if (!isSizeOk(s)) {
+ // Not small enough, so remove it and split it again. The resulting
+ // pieces will be placed at the end of the list and will be
+ // picked up later on.
+ outputs.set(i, null);
+ split(s, outputs);
+ }
+ }
+
+ // Now add all to the chain.
+ for (MapShape s : outputs) {
+ if (s == null)
+ continue;
+ next.doFilter(s);
+ }
+ }
+
+ private boolean isSizeOk(MapShape shape) {
+ // Estimate the size taken by lines and shapes as a constant plus
+ // a factor based on the number of points.
+ int numPoints = shape.getPoints().size();
+ int numElements = 1 + ((numPoints - 1) / PolygonSplitterFilter.MAX_POINT_IN_ELEMENT);
+ int size = numElements * 11 + numPoints * 4;
+
+ if (shape.hasExtendedType()) {
+ if (size > MapSplitter.MAX_XT_SHAPES_SIZE) {
+ log.debug("XTSize larger than", MapSplitter.MAX_XT_SHAPES_SIZE);
+ return false;
+ }
+ } else if (size > MapSplitter.MAX_RGN_SIZE) {
+ log.debug("RGN Size larger than", MapSplitter.MAX_RGN_SIZE);
+ return false;
+ }
+ int maxDim = shape.getBounds().getMaxDimension();
+ if (maxDim > maxSize){
+ log.debug("Size ", maxDim," larger than ", maxSize);
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/PreserveHorizontalAndVerticalLinesFilter.java b/src/uk/me/parabola/mkgmap/filters/PreserveHorizontalAndVerticalLinesFilter.java
new file mode 100644
index 0000000..11e747c
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/PreserveHorizontalAndVerticalLinesFilter.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ *
+ */
+package uk.me.parabola.mkgmap.filters;
+
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapLine;
+
+public class PreserveHorizontalAndVerticalLinesFilter implements MapFilter {
+
+ private int shift;
+
+ public void init(FilterConfig config) {
+ shift = config.getShift();
+ }
+
+ /**
+ * @param element A map element that will be a line or a polygon.
+ * @param next This is used to pass the possibly transformed element onward.
+ */
+ public void doFilter(MapElement element, MapFilterChain next) {
+ MapLine line = (MapLine) element;
+
+ if(shift != 0) {
+ // preserve the end points of horizontal and vertical lines that lie
+ // on the bbox of the shape.
+ int minLat = line.getBounds().getMinLat();
+ int maxLat = line.getBounds().getMaxLat();
+ int minLon = line.getBounds().getMinLong();
+ int maxLon = line.getBounds().getMaxLong();
+
+ List<Coord> points = line.getPoints();
+ Coord first = points.get(0);
+ Coord prev = first;
+ Coord last = first;
+ for(int i = 1; i < points.size(); ++i) {
+ last = points.get(i);
+ if(last.getLatitude() == prev.getLatitude() && (last.getLatitude() == minLat || last.getLatitude() == maxLat) ||
+ last.getLongitude() == prev.getLongitude()&& (last.getLongitude() == minLon || last.getLongitude() == maxLon)){
+ last.preserved(true);
+ prev.preserved(true);
+ }
+ prev = last;
+ }
+ // if the way has the same point at each end, make sure
+ // that if either is preserved, they both are
+ if(first.equals(last) && first.preserved() != last.preserved()) {
+ first.preserved(true);
+ last.preserved(true);
+ }
+ }
+
+ next.doFilter(line);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/RemoveEmpty.java b/src/uk/me/parabola/mkgmap/filters/RemoveEmpty.java
new file mode 100644
index 0000000..de63c7a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/RemoveEmpty.java
@@ -0,0 +1,63 @@
+/*
+ * 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: Dec 1, 2007
+ */
+package uk.me.parabola.mkgmap.filters;
+
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapShape;
+
+/**
+ * Filter for removing empty elements and degenerate elements, for example
+ * lines or shapes with just one point.
+ *
+ * @author Steve Ratcliffe
+ */
+public class RemoveEmpty implements MapFilter {
+ private static final Logger log = Logger.getLogger(RemoveEmpty.class);
+
+ public void init(FilterConfig config) {
+ }
+
+ /**
+ * If this is a line (or a shape, which extends a line) then we check
+ * to see if it is empty or only a single point. If it is then it
+ * is dropped.
+ *
+ * @param element A map element.
+ * @param next This is used to pass the possibly transformed element onward.
+ */
+ public void doFilter(MapElement element, MapFilterChain next) {
+ if (element instanceof MapShape) {
+ MapShape mapShape = (MapShape) element;
+ if (mapShape.getPoints().size() <= 3) {
+ if (log.isDebugEnabled())
+ log.debug("dropping degenerated shape");
+ return;
+ }
+ }
+ else if (element instanceof MapLine) {
+ MapLine mapLine = (MapLine) element;
+ if (mapLine.getPoints().size() <= 1) {
+ if (log.isDebugEnabled())
+ log.debug("dropping degenerated line");
+ return;
+ }
+ }
+ next.doFilter(element);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/RemoveObsoletePointsFilter.java b/src/uk/me/parabola/mkgmap/filters/RemoveObsoletePointsFilter.java
new file mode 100644
index 0000000..183d201
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/RemoveObsoletePointsFilter.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.filters;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapShape;
+
+/**
+ * Filter for lines and shapes. Remove obsolete points on straight lines and spikes.
+ * @author GerdP
+ *
+ */
+public class RemoveObsoletePointsFilter implements MapFilter {
+ private static final Logger log = Logger.getLogger(RemoveObsoletePointsFilter.class);
+
+ final Coord[] areaTest = new Coord[3];
+
+ private boolean checkPreserved;
+ public void init(FilterConfig config) {
+ checkPreserved = config.getLevel() == 0 && config.isRoutable();
+ }
+
+ /**
+ * @param element A map element that will be a line or a polygon.
+ * @param next This is used to pass the possibly transformed element onward.
+ */
+ public void doFilter(MapElement element, MapFilterChain next) {
+ MapLine line = (MapLine) element;
+ int numPoints = line.getPoints().size();
+ if (numPoints <= 1){
+ return;
+ }
+
+ List<Coord> newPoints = new ArrayList<Coord>(numPoints);
+
+ Coord lastP = line.getPoints().get(0);
+ newPoints.add(lastP);
+ for(int i = 1; i < numPoints; i++) {
+ Coord newP = line.getPoints().get(i);
+ int last = newPoints.size()-1;
+ lastP = newPoints.get(last);
+ if (lastP.equals(newP)){
+ // only add the new point if it has different
+ // coordinates to the last point or is preserved
+ if (checkPreserved && line.isRoad()){
+ if (newP.preserved() == false)
+ continue;
+ else if (lastP.preserved() == false){
+ newPoints.set(last, newP); // replace last
+ }
+ }
+ continue;
+ }
+ if (newPoints.size() > 1) {
+ switch (Utils.isStraight(newPoints.get(last-1), lastP, newP)){
+ case Utils.STRICTLY_STRAIGHT:
+ if (checkPreserved && lastP.preserved() && line.isRoad()){
+ // keep it
+ } else {
+ log.debug("found three consecutive points on strictly straight line");
+ newPoints.set(last, newP);
+ continue;
+ }
+ break;
+ case Utils.STRAIGHT_SPIKE:
+ if (line instanceof MapShape){
+ log.debug("removing spike");
+ newPoints.remove(last);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ newPoints.add(newP);
+ }
+ if (newPoints.size() != line.getPoints().size()){
+ if (line instanceof MapShape && newPoints.size() <= 3 || newPoints.size() <= 1)
+ return;
+ MapLine newLine = line.copy();
+ newLine.setPoints(newPoints);
+ next.doFilter(newLine);
+ } else {
+ // no need to create new object
+ next.doFilter(line);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/RoundCoordsFilter.java b/src/uk/me/parabola/mkgmap/filters/RoundCoordsFilter.java
new file mode 100644
index 0000000..62a5ed4
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/RoundCoordsFilter.java
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ *
+ */
+package uk.me.parabola.mkgmap.filters;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.CoordNode;
+import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapLine;
+
+public class RoundCoordsFilter implements MapFilter {
+
+ private int shift;
+ private boolean checkRouting;
+
+ public void init(FilterConfig config) {
+ shift = config.getShift();
+ checkRouting = config.getLevel() == 0 && config.isRoutable() == true;
+
+ }
+
+ /**
+ * @param element A map element that will be a line or a polygon.
+ * @param next This is used to pass the possibly transformed element onward.
+ */
+ public void doFilter(MapElement element, MapFilterChain next) {
+ MapLine line = (MapLine) element;
+ int half = 1 << (shift - 1); // 0.5 shifted
+ int mask = ~((1 << shift) - 1); // to remove fraction bits
+
+ if(shift == 0) {
+ // do nothing
+ next.doFilter(line);
+ }
+ else {
+ // round lat/lon values to nearest for shift
+ List<Coord> newPoints = new ArrayList<Coord>(line.getPoints().size());
+ Coord lastP = null;
+ for(Coord p : line.getPoints()) {
+ int lat = (p.getLatitude() + half) & mask;
+ int lon = (p.getLongitude() + half) & mask;
+ Coord newP;
+
+ if(p instanceof CoordNode && checkRouting)
+ newP = new CoordNode(lat, lon, p.getId(), p.getOnBoundary());
+ else
+ newP = new Coord(lat, lon);
+ newP.preserved(p.preserved());
+
+ // only add the new point if it has different
+ // coordinates to the last point or if it's a
+ // CoordNode and the last point wasn't a CoordNode
+ if(lastP == null ||
+ !lastP.equals(newP) ||
+ (newP instanceof CoordNode && !(lastP instanceof CoordNode))) {
+ newPoints.add(newP);
+ lastP = newP;
+ }
+ else if(newP.preserved()) {
+ // this point is not going to be used because it
+ // has the same (rounded) coordinates as the last
+ // node but it has been marked as being "preserved" -
+ // transfer that property to the previous point so
+ // that it's not lost
+ lastP.preserved(true);
+ }
+ }
+ if(newPoints.size() > 1) {
+ MapLine newLine = line.copy();
+ newLine.setPoints(newPoints);
+ next.doFilter(newLine);
+ }
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/SizeFilter.java b/src/uk/me/parabola/mkgmap/filters/SizeFilter.java
new file mode 100644
index 0000000..e48db48
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/SizeFilter.java
@@ -0,0 +1,59 @@
+/*
+ * 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: Dec 1, 2007
+ */
+package uk.me.parabola.mkgmap.filters;
+
+import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapLine;
+
+/**
+ * This is a filter that dismisses elements too small for the current resolution
+ */
+public class SizeFilter implements MapFilter {
+
+ private final int size;
+
+ private int minSize;
+ private boolean checkRouting;
+
+ public SizeFilter(int s) {
+ size = s;
+ }
+
+ public void init(FilterConfig config) {
+ minSize = size * (1<<config.getShift());
+ // don't remove roads on level 0
+ checkRouting = config.getLevel() == 0 && config.isRoutable() == true;
+ }
+
+ /**
+ * This applies to both lines and polygons.
+ * Elements too small for current resolution will be dropped.
+ *
+ * @param element A map element that will be a line or a polygon.
+ * @param next This is used to pass the possibly transformed element onward.
+ */
+ public void doFilter(MapElement element, MapFilterChain next) {
+ MapLine line = (MapLine) element;
+
+ if ((line.isSkipSizeFilter() || (checkRouting && line.isRoad())) == false){
+ if (line.getBounds().getMaxDimension() < minSize){
+ return;
+ }
+ }
+ next.doFilter(line);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/SmoothingFilter.java b/src/uk/me/parabola/mkgmap/filters/SmoothingFilter.java
new file mode 100644
index 0000000..45b2d1c
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/SmoothingFilter.java
@@ -0,0 +1,173 @@
+/*
+ * 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: Dec 1, 2007
+ */
+package uk.me.parabola.mkgmap.filters;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapLine;
+
+/**
+ * This is a filter that smooths out lines at low resolutions. If the element
+ * has no size at all at the given resolution, then it is not passed on down
+ * the chain at all is excluded from the map at that resolution.
+ *
+ * @author Steve Ratcliffe
+ */
+public class SmoothingFilter implements MapFilter {
+
+ private static final int MIN_SPACING = 5;
+
+ private int shift;
+
+ public void init(FilterConfig config) {
+ this.shift = config.getShift();
+ }
+
+ /**
+ * This applies to both lines and polygons. We are going to smooth out
+ * the points in the line so that you do not get jaggies. We are assuming
+ * that there is not an excess of points at the highest resolution.
+ *
+ * <ol>
+ * <li>If there is just one point, the drop it.
+ * <li>Ff the element is too small altogether, then drop it.
+ * <li>If there are just two points the pass it on unchanged. This is
+ * probably a pretty common case.
+ * <li>The first point goes in unchanged.
+ * <li>Average points in groups so that they exceed the step size
+ * at the shifted resolution.
+ * </ol>
+ *
+ * @param element A map element that will be a line or a polygon.
+ * @param next This is used to pass the possibly transformed element onward.
+ */
+ public void doFilter(MapElement element, MapFilterChain next) {
+ MapLine line = (MapLine) element;
+
+ // First off we don't touch things if at the highest level of detail
+ if (shift == 0) {
+ next.doFilter(element);
+ return;
+ }
+
+ // If the line is not very long then just let it through. This is done
+ // mainly for the background polygons.
+ List<Coord> points = line.getPoints();
+ int n = points.size();
+ if (n <= 5) {
+ next.doFilter(element);
+ return;
+ }
+
+ // Create a new list to rewrite the points into.
+ List<Coord> coords = new ArrayList<Coord>(n);
+
+ // Get the step size, we want to place a point every time the
+ // average exceeds this size.
+ int stepsize = MIN_SPACING << shift;
+
+ // Always add the first point
+ Coord last = points.get(0);
+ coords.add(last);
+
+ // Average the rest
+ Average av = new Average(last, stepsize);
+ for (int i = 1; i < n; i++) {
+ Coord co = points.get(i);
+ av.add(co);
+
+ if (av.isMoreThanStep()) {
+ Coord nco = av.getAverageCoord();
+ coords.add(nco);
+ if (av.pointCounter()>1) i--;
+
+ last = nco;
+ av.reset(last);
+ }
+ }
+
+ Coord end = points.get(n - 1);
+ if (!last.equals(end))
+ coords.add(end);
+
+ MapLine newline = line.copy();
+
+ newline.setPoints(coords);
+ next.doFilter(newline);
+ }
+
+ /**
+ * Class for averaging out points that are close together.
+ */
+ private static class Average {
+ private int count;
+
+ private int startLat;
+ private int startLon;
+
+ private int avlat;
+ private int avlon;
+
+ private int step;
+
+ private final int stepsize;
+
+ Average(Coord start, int stepsize) {
+ this.startLat = start.getLatitude();
+ this.startLon = start.getLongitude();
+ this.stepsize = stepsize;
+ }
+
+ public void add(int lat, int lon) {
+ count++;
+ this.avlat += lat;
+ this.avlon += lon;
+
+ step += Math.abs(startLat - lat);
+ step += Math.abs(startLon - lon);
+ }
+
+ public void reset(Coord start) {
+ this.startLat = start.getLatitude();
+ this.startLon = start.getLongitude();
+ step = 0;
+ count = 0;
+ avlat = 0;
+ avlon = 0;
+ }
+
+ public Coord getAverageCoord() {
+ assert count > 0;
+ return new Coord(avlat / count, avlon / count);
+ }
+
+ public void add(Coord co) {
+ add(co.getLatitude(), co.getLongitude());
+ }
+
+ public boolean isMoreThanStep() {
+ return (step > stepsize);
+ }
+
+ public int pointCounter() {
+ return count;
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/filters/package.html b/src/uk/me/parabola/mkgmap/filters/package.html
new file mode 100644
index 0000000..0043292
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/filters/package.html
@@ -0,0 +1,14 @@
+<body>
+<h3>Filtering at map levels</h3>
+<p>
+ The general representation that is built up in the mkgmap.general package is
+ at the full level of detail that is available in the OSM file. The map however
+ is in different layers at different levels of detail. There are also limitations
+ of the format or the devices that need to be taken care of.
+</p>
+<p>So when we are building up the garmin layers, we send the general representation
+through a series of filters to fix things up before being placed into a layer.
+This can involve spliting up lines and shapes, removing points from lines to
+produce a lower resolution versions and droping elements altogether.</p>
+
+</body>
diff --git a/src/uk/me/parabola/mkgmap/general/AreaClipper.java b/src/uk/me/parabola/mkgmap/general/AreaClipper.java
new file mode 100644
index 0000000..b9bad47
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/AreaClipper.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 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: 08-Nov-2008
+ */
+package uk.me.parabola.mkgmap.general;
+
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+
+/**
+ * Clip objects to a bounding box.
+ *
+ * TODO: migrate LineClipper and PolygonClipper into here and simplify.
+ *
+ * @author Steve Ratcliffe
+ */
+public class AreaClipper implements Clipper {
+ private final Area bbox;
+
+ public AreaClipper(Area bbox) {
+ this.bbox = bbox;
+ }
+
+ public void clipLine(MapLine line, LineAdder collector) {
+ List<List<Coord>> list = LineClipper.clip(bbox, line.getPoints());
+ if (list == null) {
+ collector.add(line);
+ } else {
+ for (List<Coord> lco : list) {
+ MapLine nline = line.copy();
+ nline.setPoints(lco);
+ collector.add(nline);
+ }
+ }
+ }
+
+ public void clipShape(MapShape shape, MapCollector collector) {
+ List<List<Coord>> list = PolygonClipper.clip(bbox, shape.getPoints());
+ if (list == null) {
+ collector.addShape(shape);
+ } else {
+ for (List<Coord> lco : list) {
+ MapShape nshape = new MapShape(shape);
+ nshape.setPoints(lco);
+ collector.addShape(nshape);
+ }
+ }
+ }
+
+ public boolean contains(Coord location) {
+ return bbox == null || bbox.contains(location);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/general/Clipper.java b/src/uk/me/parabola/mkgmap/general/Clipper.java
new file mode 100644
index 0000000..4c571c0
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/Clipper.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 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: 10-Nov-2008
+ */
+package uk.me.parabola.mkgmap.general;
+
+import uk.me.parabola.imgfmt.app.Coord;
+
+/**
+ * For clipping lines and polygons.
+ * @author Steve Ratcliffe
+ */
+public interface Clipper {
+ public static final Clipper NULL_CLIPPER = new NullClipper();
+
+ /**
+ * Clip a line and add the resulting line or lines (if any) to the
+ * collector.
+ */
+ public void clipLine(MapLine line, LineAdder adder);
+
+ /**
+ * Clip a polygon and add the resulting shapes to the collector.
+ */
+ public void clipShape(MapShape shape, MapCollector collector);
+
+ /**
+ * 'Clip' a point - return true if the point is within the clipped region.
+ */
+ public boolean contains(Coord location);
+}
diff --git a/src/uk/me/parabola/mkgmap/general/LevelInfo.java b/src/uk/me/parabola/mkgmap/general/LevelInfo.java
new file mode 100644
index 0000000..9f2cadb
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/LevelInfo.java
@@ -0,0 +1,134 @@
+/*
+ * 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: 02-Sep-2007
+ */
+package uk.me.parabola.mkgmap.general;
+
+import java.util.Arrays;
+
+import uk.me.parabola.imgfmt.ExitException;
+
+/**
+ * Represents the mapping between the Garmin map levels and the built-in
+ * resolutions. The resolutions go from 1 to 24 and the levels start at 0 and
+ * are defined by the map maker. For each level you assign a resolution to it.
+ * The resolution for each level must be lower than that of the level below.
+ *
+ * As an example you might have the following level=resolution pairs:
+ * 0=24, 1=22, 2=20, 3=19.
+ *
+ * Note that level 0 is the most detailed level, whereas 24 is the most detailed
+ * resolution.
+ *
+ * The highest numbered level must be empty and cover the whole map.
+ *
+ * @author Steve Ratcliffe
+*/
+public class LevelInfo implements Comparable<LevelInfo> {
+ public static final String DEFAULT_LEVELS = "0:24, 1:22, 2:20, 3:18, 4:16";
+
+ private final int level;
+ private final int bits;
+
+ // Set if this is a top level, use this when the format is supplying its own
+ // top level.
+ private boolean top;
+
+ public LevelInfo(int level, int bits) {
+ this.level = level;
+ this.bits = bits;
+ }
+
+ /**
+ * Convert a string into an array of LevelInfo structures.
+ */
+ public static LevelInfo[] createFromString(String levelSpec) {
+ String[] desc = levelSpec.split("[, \\t\\n]+");
+ LevelInfo[] levels = new LevelInfo[desc.length];
+
+ int count = 0;
+ for (String s : desc) {
+ String[] keyVal = s.split("[=:]");
+ if (keyVal == null || keyVal.length < 2) {
+ System.err.println("incorrect level specification " + levelSpec);
+ continue;
+ }
+
+ try {
+ int key = Integer.parseInt(keyVal[0]);
+ int value = Integer.parseInt(keyVal[1]);
+ levels[count] = new LevelInfo(key, value);
+ } catch (NumberFormatException e) {
+ System.err.println("Levels specification not all numbers " + keyVal[count]);
+ }
+ count++;
+ }
+
+ Arrays.sort(levels);
+
+ // If there are more than 8 levels the map can cause the
+ // garmin to crash.
+ if (levels.length > 8)
+ throw new ExitException("Too many levels, the maximum is 8");
+
+ return levels;
+ }
+
+ /**
+ * Returns a string representation of the object. In general, the
+ * <code>toString</code> method returns a string that
+ * "textually represents" this object.
+ *
+ * @return a string representation of the object.
+ */
+ public String toString() {
+ return "L" + level + " B" + bits;
+ }
+
+ public int getLevel() {
+ return level;
+ }
+
+ public int getBits() {
+ return bits;
+ }
+
+ public boolean isTop() {
+ return top;
+ }
+
+ public void setTop(boolean top) {
+ this.top = top;
+ }
+
+ /**
+ * These things sort so that the highest level number is the lowest. OK
+ * so its a bit wierd.
+ *
+ * @param other The LevelInfo to compare to.
+ * @return Zero if they are equal and 1 if the object is greater and -1
+ * otherwise.
+ */
+ public int compareTo(LevelInfo other) {
+
+ if (other.getLevel() == getLevel())
+ return 0;
+
+ if (other.getLevel() > getLevel())
+ return 1;
+ else
+ return -1;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/general/LineAdder.java b/src/uk/me/parabola/mkgmap/general/LineAdder.java
new file mode 100644
index 0000000..e276bb8
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/LineAdder.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 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: 10-Dec-2008
+ */
+package uk.me.parabola.mkgmap.general;
+
+/**
+ * For adding a line to the map model. Created for the overlay feature.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface LineAdder {
+
+ /**
+ * Add the given line. This will usually be to a MapCollector.
+ */
+ public void add(MapLine element);
+}
diff --git a/src/uk/me/parabola/mkgmap/general/LineClipper.java b/src/uk/me/parabola/mkgmap/general/LineClipper.java
new file mode 100644
index 0000000..a5f029d
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/LineClipper.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2008 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: 30-Jun-2008
+ */
+package uk.me.parabola.mkgmap.general;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+
+/**
+ * Routine to clip a polyline to a given bounding box.
+ * @author Steve Ratcliffe
+ * @see <a href="http://www.skytopia.com/project/articles/compsci/clipping.html">A very clear explaination of the Liang-Barsky algorithm</a>
+ */
+public class LineClipper {
+
+ /**
+ * Clips a polyline by the given bounding box. This may produce several
+ * separate lines if the line meanders in and out of the box.
+ * This will work even if no point is actually inside the box.
+ * @param a The bounding area.
+ * @param coords A list of the points in the line.
+ * @return Returns null if the line is completely in the bounding box and
+ * this is expected to be the normal case.
+ * If clipping is needed then an array of point lists is returned.
+ */
+ public static List<List<Coord>> clip(Area a, List<Coord> coords) {
+
+ // If all the points are inside the box then we just return null
+ // to show that nothing was done and the line can be used. This
+ // is expected to be the normal case.
+ if (a == null || a.allInsideBoundary(coords))
+ return null;
+
+ class LineCollector {
+ private final List<List<Coord>> ret = new ArrayList<List<Coord>>(4);
+ private List<Coord> currentLine;
+ private Coord last;
+
+ public void add(Coord[] segment) {
+ if (segment == null) {
+ currentLine = null;
+ } else {
+ // we start a new line if there isn't a current one, or if the first
+ // point of the segment is not equal to the last one in the line.
+ if (currentLine == null || !segment[0].equals(last)) {
+ currentLine = new ArrayList<Coord>(5);
+ currentLine.add(segment[0]);
+ currentLine.add(segment[1]);
+ ret.add(currentLine);
+ } else {
+ currentLine.add(segment[1]);
+ }
+ last = segment[1];
+ }
+ }
+
+ }
+
+ LineCollector seg = new LineCollector();
+
+ // Step through each segment, clip it if necessary and create a list of
+ // lines from it.
+ for (int i = 0; i <= coords.size() - 2; i++) {
+ Coord[] pair = {coords.get(i), coords.get(i+1)};
+ if (pair[0].equals(pair[1])) {
+ continue;
+ }
+ Coord[] clippedPair = clip(a, pair);
+ seg.add(clippedPair);
+ }
+
+ // in case the coords build a closed way the first and the last clipped line
+ // might have to be joined
+ if (seg.ret.size() >= 2 && coords.get(0).equals(coords.get(coords.size()-1))) {
+ List<Coord> firstSeg = seg.ret.get(0);
+ List<Coord> lastSeg = seg.ret.get(seg.ret.size()-1);
+ // compare the first point of the first segment with the last point of
+ // the last segment
+ if (firstSeg.get(0).equals(lastSeg.get(lastSeg.size()-1))) {
+ // they are the same so the two segments should be joined
+ lastSeg.addAll(firstSeg.subList(1, firstSeg.size()));
+ seg.ret.remove(0);
+ }
+ }
+
+ return seg.ret;
+ }
+
+ public static Coord[] clip(Area a, Coord[] ends) {
+ return clip(a,ends,false);
+ }
+
+ /**
+ * A straight forward implementation of the Liang-Barsky algorithm as described
+ * in the referenced web page.
+ * @param a The clipping area.
+ * @param ends The start and end of the line the contents of this will
+ * be changed if the line is clipped to contain the new start and end
+ * points. A point that was inside the box will not be changed.
+ * @param nullIfInside true: returns null if all points are within the given area
+ * @return An array of the new start and end points if any of the line is
+ * within the box. If the line is wholly outside then null is returned.
+ * If a point is within the box then the same coordinate object will
+ * be returned as was passed in.
+ * @see <a href="http://www.skytopia.com/project/articles/compsci/clipping.html">Liang-Barsky algorithm</a>
+ */
+ public static Coord[] clip(Area a, Coord[] ends, boolean nullIfInside) {
+ assert ends.length == 2;
+
+ if (a.insideBoundary(ends[0]) && a.insideBoundary(ends[1])) {
+ return (nullIfInside ? null : ends);
+ }
+
+ int x0 = ends[0].getLongitude();
+ int y0 = ends[0].getLatitude();
+
+ int x1 = ends[1].getLongitude();
+ int y1 = ends[1].getLatitude();
+
+ int dx = x1 - x0;
+ int dy = y1 - y0;
+
+ double[] t = {0, 1};
+
+ int p = -dx;
+ int q = -(a.getMinLong() - x0);
+ boolean scrap = checkSide(t, p, q);
+ if (scrap) return null;
+
+ p = dx;
+ q = a.getMaxLong() - x0;
+ scrap = checkSide(t, p, q);
+ if (scrap) return null;
+
+ p = -dy;
+ q = -(a.getMinLat() - y0);
+ scrap = checkSide(t, p, q);
+ if (scrap) return null;
+
+ p = dy;
+ q = a.getMaxLat() - y0;
+ scrap = checkSide(t, p, q);
+ if (scrap) return null;
+
+ assert t[0] >= 0;
+ assert t[1] <= 1;
+
+ Coord orig0 = ends[0];
+ Coord orig1 = ends[1];
+ if(ends[0].getOnBoundary()) {
+ // consistency check
+ assert a.onBoundary(ends[0]) : "Point marked as boundary node at " + ends[0].toString() + " not on boundary of [" + a.getMinLat() + ", " + a.getMinLong() + ", " + a.getMaxLat() + ", " + a.getMaxLong() + "]";
+ }
+ else if (t[0] > 0) {
+ // line requires clipping so create a new end point and if
+ // its position (in map coordinates) is different from the
+ // original point, use the new point as a boundary node
+ Coord new0 = new Coord(calcCoord(y0, dy, t[0]), calcCoord(x0, dx, t[0]));
+
+ // check the maths worked out
+ assert a.onBoundary(new0) : "New boundary point at " + new0.toString() + " not on boundary of [" + a.getMinLat() + ", " + a.getMinLong() + ", " + a.getMaxLat() + ", " + a.getMaxLong() + "]";
+ if(!new0.equals(orig0))
+ ends[0] = new0;
+ ends[0].setOnBoundary(true);
+ }
+ else if(a.onBoundary(ends[0])) {
+ // point lies on the boundary so it's a boundary node
+ ends[0].setOnBoundary(true);
+ }
+
+ if(ends[1].getOnBoundary()) {
+ // consistency check
+ assert a.onBoundary(ends[1]) : "Point marked as boundary node at " + ends[1].toString() + " not on boundary of [" + a.getMinLat() + ", " + a.getMinLong() + ", " + a.getMaxLat() + ", " + a.getMaxLong() + "]";
+ }
+ else if (t[1] < 1) {
+ // line requires clipping so create a new end point and if
+ // its position (in map coordinates) is different from the
+ // original point, use the new point as a boundary node
+ Coord new1 = new Coord(calcCoord(y0, dy, t[1]), calcCoord(x0, dx, t[1]));
+
+ // check the maths worked out
+ assert a.onBoundary(new1) : "New boundary point at " + new1.toString() + " not on boundary of [" + a.getMinLat() + ", " + a.getMinLong() + ", " + a.getMaxLat() + ", " + a.getMaxLong() + "]";
+ if(!new1.equals(orig1))
+ ends[1] = new1;
+ ends[1].setOnBoundary(true);
+ }
+ else if(a.onBoundary(ends[1])) {
+ // point lies on the boundary so it's a boundary node
+ ends[1].setOnBoundary(true);
+ }
+
+ // zero length segments can be created if one point lies on
+ // the boundary and the other is outside of the area
+
+ // try really hard to catch these as they will break the
+ // routing
+
+ // the check for t[0] >= t[1] should quickly find all the zero
+ // length segments but the extra check to see if the points
+ // are equal could catch the situation where although t[0] and
+ // t[1] differ, the coordinates come out the same for both
+ // points
+
+ if(t[0] >= t[1] || ends[0].equals(ends[1]))
+ return null;
+
+ return ends;
+ }
+
+ private static int calcCoord(int base, int delta, double t) {
+ double d = 0.5;
+ double y = (base + t * delta);
+ return (int) ((y >= 0) ? y + d : y - d);
+ }
+
+ private static boolean checkSide(double[] t, double p, double q) {
+ double r = q/p;
+
+ if (p == 0) {
+ if (q < 0)
+ return true;
+ } else if (p < 0) {
+ if (r > t[1])
+ return true;
+ else if (r > t[0])
+ t[0] = r;
+ } else {
+ if (r < t[0])
+ return true;
+ else if (r < t[1])
+ t[1] = r;
+ }
+ return false;
+ }
+}
+
\ No newline at end of file
diff --git a/src/uk/me/parabola/mkgmap/general/LoadableMapDataSource.java b/src/uk/me/parabola/mkgmap/general/LoadableMapDataSource.java
new file mode 100644
index 0000000..4261a21
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/LoadableMapDataSource.java
@@ -0,0 +1,98 @@
+/*
+ * 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.general;
+
+import java.io.FileNotFoundException;
+
+import uk.me.parabola.imgfmt.FormatException;
+import uk.me.parabola.util.Configurable;
+
+/**
+ * A source of map information in a standard format. The OSM reader presents
+ * this interface to the main map making program. OSM concepts are converted
+ * into Garmin map based structures such as {@link MapLine}.
+ *
+ * Note that it does not reference anything from the imgfmt package that
+ * relies on subdivisions. In other words it does not directly reference
+ * Point or Polyline as they depend on the subdivision they are in. It
+ * can refer to Coord and Overview however as they have global meaning.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface LoadableMapDataSource extends MapDataSource, Configurable {
+
+ /**
+ * Determines if the file (or other resource) is supported by this map
+ * data source. The implementation may do this however it likes, eg
+ * by extension or by opening up the file and reading part of it.
+ *
+ * @param name The file (or other resource) to check.
+ * @return True if the loadable map data source supports that file.
+ */
+ public boolean isFileSupported(String name);
+
+ /**
+ * Load map by name. The name is in a suitable form to be recognised
+ * by the particular map source. It could be a file name or a URI.
+ *
+ * You would implement this interface to read mapping data in an other
+ * format.
+ *
+ * @param name The name of the resource to be loaded.
+ * @throws FileNotFoundException When the file or resource is not found.
+ * @throws FormatException For any kind of malformed input.
+ */
+ public void load(String name)
+ throws FileNotFoundException, FormatException;
+
+ /**
+ * Get the map levels for this map. This is an array of @{link LevelInfo}
+ * structures that map a level to a resolution. Some map data sources
+ * may actually have the concept of map layers that can be used to
+ * construct this information. Others may just have to provide a default
+ * that is useful with the map source. In the latter case it would be
+ * important to be able to configure the levels separately while creating
+ * the map.
+ *
+ * <p>Note that it does not include the top empty level as we will always
+ * generate that in the main program automatically.
+ *
+ * @return Array of structures that map the level to the resolution. Never
+ * returns null. Some kind of default should always be returned and this
+ * must include at least one level.
+ */
+ public LevelInfo[] mapLevels();
+
+ /**
+ * Levels for the overview map.
+ * @return Array of structures that map the level to the resolution or null
+ * if not defined in options.
+ */
+ public LevelInfo[] overviewMapLevels();
+
+ /**
+ * Get a suitable copyright message for this map source. You can get
+ * this information from the input file, if the file has such information
+ * or as in the case of OSM the data has a well known copyright, so we
+ * can return fixed strings referring to it.
+ *
+ * @return An array of strings with copyright information. If there are
+ * none then return a zero length array.
+ */
+ public String[] copyrightMessages();
+
+}
diff --git a/src/uk/me/parabola/mkgmap/general/MapCollector.java b/src/uk/me/parabola/mkgmap/general/MapCollector.java
new file mode 100644
index 0000000..176f667
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/MapCollector.java
@@ -0,0 +1,85 @@
+/*
+ * 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: 18-Dec-2006
+ */
+package uk.me.parabola.mkgmap.general;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.CoordNode;
+
+
+/**
+ * This interface can be used by map sources to collect the map elements
+ * in their general form. The general form has garmin types, but the full
+ * detail from the input file.
+ *
+ * It consists of all the 'writable' methods on {@link MapDetails}.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface MapCollector {
+
+ /**
+ * Add the given point to the total bounds for the map.
+ *
+ * @param p The coordinates of the point to add. The type here
+ * will change to Node.
+ */
+ public void addToBounds(Coord p);
+
+ /**
+ * Add a point to the map.
+ *
+ * @param point The point to add.
+ */
+ public void addPoint(MapPoint point);
+
+ /**
+ * Add a line to the map.
+ *
+ * @param line The line information.
+ */
+ public void addLine(MapLine line);
+
+ /**
+ * Add the given shape (polygon) to the map. A shape is very similar to
+ * a line but they are separate because they need to be put in different
+ * sections in the output map.
+ *
+ * @param shape The polygon to add.
+ */
+ public void addShape(MapShape shape);
+
+
+ /**
+ * For adding a road. Although a road is a kind of line, it is treated
+ * differently so that we can join up roads that are split into several
+ * segments and to do routing etc.
+ */
+ public void addRoad(MapRoad road);
+
+ /**
+ * Add a routing restriction to the map. This is something such as
+ * no left turn.
+ * @param exceptMask For exceptions eg. no-left-turn except for buses.
+ */
+ public void addRestriction(CoordNode fromNode, CoordNode toNode, CoordNode viaNode, byte exceptMask);
+
+ /**
+ * Add a through route to the map.
+ *
+ */
+ public void addThroughRoute(long junctionNodeId, long roadIdA, long roadIdB);
+}
diff --git a/src/uk/me/parabola/mkgmap/general/MapDataSource.java b/src/uk/me/parabola/mkgmap/general/MapDataSource.java
new file mode 100644
index 0000000..2fe5984
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/MapDataSource.java
@@ -0,0 +1,82 @@
+/*
+ * 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: 24-Mar-2007
+ */
+package uk.me.parabola.mkgmap.general;
+
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.trergn.Overview;
+
+/**
+ * A source of map data. This base interface is used internally within
+ * the program.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface MapDataSource {
+ /**
+ * Get the area that this map covers.
+ *
+ * @return The area the map covers.
+ */
+ Area getBounds();
+
+ /**
+ * Get the list of points that need to be rendered on the map.
+ *
+ * @return A list of {@link MapPoint} objects.
+ */
+ List<MapPoint> getPoints();
+
+ /**
+ * Get the list of lines that need to be rendered to the map. Includes
+ * lines that are part of roads.
+ *
+ * @return A list of {@link MapLine} objects.
+ */
+ List<MapLine> getLines();
+
+ /**
+ * Get the list of shapes that need to be rendered to the map.
+ *
+ * @return A list of {@link MapShape} objects.
+ */
+ List<MapShape> getShapes();
+
+ /**
+ * Get the high level view of the road network. This is used to write
+ * the net and nod sections. Note that information from the net
+ * section is needed to write the RGN section if routing is wanted.
+ *
+ * @return A {@link RoadNetwork} object with all the connections between
+ * roads. If this returns null, then the NET and NOD sections should
+ * not be written.
+ */
+ RoadNetwork getRoadNetwork();
+
+ /**
+ * Get a list of every feature that is used in the map. As features are
+ * created a list is kept of each separate feature that is used. This
+ * goes into the .img file and is important for points and polygons although
+ * it doesn't seem to matter if lines are represented or not on my Legend Cx
+ * anyway.
+ *
+ * @return A list of all the types of point, polygon and polyline that are
+ * used in the map.
+ */
+ List<Overview> getOverviews();
+}
diff --git a/src/uk/me/parabola/mkgmap/general/MapDetails.java b/src/uk/me/parabola/mkgmap/general/MapDetails.java
new file mode 100644
index 0000000..8ff6839
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/MapDetails.java
@@ -0,0 +1,207 @@
+/*
+ * 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: 18-Dec-2006
+ */
+package uk.me.parabola.mkgmap.general;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.CoordNode;
+import uk.me.parabola.imgfmt.app.trergn.Overview;
+import uk.me.parabola.imgfmt.app.trergn.PointOverview;
+import uk.me.parabola.imgfmt.app.trergn.PolygonOverview;
+import uk.me.parabola.imgfmt.app.trergn.PolylineOverview;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * The map features that we are going to map are collected here.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MapDetails implements MapCollector, MapDataSource {
+ private final List<MapLine> lines = new ArrayList<MapLine>();
+ private final List<MapShape> shapes = new ArrayList<MapShape>();
+ private final List<MapPoint> points = new ArrayList<MapPoint>();
+
+ private int minLat = Utils.toMapUnit(180.0);
+ private int minLon = Utils.toMapUnit(180.0);
+ private int maxLat = Utils.toMapUnit(-180.0);
+ private int maxLon = Utils.toMapUnit(-180.0);
+
+ // Keep lists of all items that were used.
+ private final Map<Integer, Integer> pointOverviews = new HashMap<Integer, Integer>();
+ private final Map<Integer, Integer> lineOverviews = new HashMap<Integer, Integer>();
+ private final Map<Integer, Integer> shapeOverviews = new HashMap<Integer, Integer>();
+
+ private final RoadNetwork roadNetwork = new RoadNetwork();
+
+ public void config(EnhancedProperties props) {
+ roadNetwork.config(props);
+ }
+
+ /**
+ * Add a point to the map.
+ *
+ * @param point Point to add.
+ */
+ public void addPoint(MapPoint point) {
+ updateOverview(pointOverviews, point.getType(), point.getMinResolution());
+
+ points.add(point);
+ }
+
+ /**
+ * Add a line to the map.
+ *
+ * @param line The line information.
+ */
+ public void addLine(MapLine line) {
+ assert !(line instanceof MapShape);
+ if (line.getPoints().isEmpty())
+ return;
+
+ int type;
+ if(line.hasExtendedType())
+ type = line.getType();
+ else
+ type = line.getType() << 8;
+ updateOverview(lineOverviews, type, line.getMinResolution());
+
+ lines.add(line);
+ }
+
+ /**
+ * Add the given shape (polygon) to the map. A shape is very similar to a
+ * line but they are separate because they need to be put in different
+ * sections in the output map.
+ *
+ * @param shape The polygon to add.
+ */
+ public void addShape(MapShape shape) {
+ if (shape.getPoints().isEmpty())
+ return;
+
+ int type;
+ if(shape.hasExtendedType())
+ type = shape.getType();
+ else
+ type = shape.getType() << 8;
+
+ updateOverview(shapeOverviews, type, shape.getMinResolution());
+
+ shapes.add(shape);
+ }
+
+ public void addRoad(MapRoad road) {
+ roadNetwork.addRoad(road);
+ addLine(road);
+ }
+
+ public void addRestriction(CoordNode fromNode, CoordNode toNode, CoordNode viaNode, byte exceptMask) {
+ roadNetwork.addRestriction(fromNode, toNode, viaNode, exceptMask);
+ }
+
+ public void addThroughRoute(long junctionNodeId, long roadIdA, long roadIdB) {
+ roadNetwork.addThroughRoute(junctionNodeId, roadIdA, roadIdB);
+ }
+
+ /**
+ * Add the given point to the total bounds for the map.
+ *
+ * @param p The coordinates of the point to add.
+ */
+ public void addToBounds(Coord p) {
+ int lat = p.getLatitude();
+ int lon = p.getLongitude();
+ if (lat < minLat)
+ minLat = lat;
+ if (lat > maxLat)
+ maxLat = lat;
+ if (lon < minLon)
+ minLon = lon;
+ if (lon > maxLon)
+ maxLon = lon;
+ }
+
+ /**
+ * Get the bounds of this map.
+ *
+ * @return An area covering all the points in the map.
+ */
+ public Area getBounds() {
+ return new Area(minLat, minLon, maxLat, maxLon);
+ }
+
+ public List<MapPoint> getPoints() {
+ return points;
+ }
+
+ /**
+ * Get all the lines for this map.
+ *
+ * @return A list of all lines defined for this map.
+ */
+ public List<MapLine> getLines() {
+ return lines;
+ }
+
+ public List<MapShape> getShapes() {
+ return shapes;
+ }
+
+ public RoadNetwork getRoadNetwork() {
+ return roadNetwork;
+ }
+
+ /**
+ * Get the overviews. We construct them at this point from the information
+ * that we have built up.
+ * Perhaps this could be a separate class rather than a list.
+ *
+ * @return A list of overviews.
+ */
+ public List<Overview> getOverviews() {
+ List<Overview> ovlist = new ArrayList<Overview>();
+
+ for (Map.Entry<Integer, Integer> ent : pointOverviews.entrySet()) {
+ Overview ov = new PointOverview(ent.getKey(), ent.getValue());
+ ovlist.add(ov);
+ }
+
+ for (Map.Entry<Integer, Integer> ent : lineOverviews.entrySet()) {
+ Overview ov = new PolylineOverview(ent.getKey(), ent.getValue());
+ ovlist.add(ov);
+ }
+
+ for (Map.Entry<Integer, Integer> ent : shapeOverviews.entrySet()) {
+ Overview ov = new PolygonOverview(ent.getKey(), ent.getValue());
+ ovlist.add(ov);
+ }
+
+ return ovlist;
+ }
+
+ private void updateOverview(Map<Integer, Integer> overviews, int type, int minResolution) {
+ Integer prev = overviews.get(type);
+ if (prev == null || minResolution < prev)
+ overviews.put(type, minResolution);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/general/MapElement.java b/src/uk/me/parabola/mkgmap/general/MapElement.java
new file mode 100644
index 0000000..ecefca0
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/MapElement.java
@@ -0,0 +1,238 @@
+/**
+ * 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
+ * Date: 26-Dec-2006
+ */
+package uk.me.parabola.mkgmap.general;
+
+import java.util.Arrays;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.trergn.ExtTypeAttributes;
+import uk.me.parabola.imgfmt.app.trergn.MapObject;
+
+/**
+ * A map element is a point, line or shape that appears on the map. This
+ * class holds all the common routines that are shared across all elements.
+ *
+ * @author Steve Ratcliffe.
+ */
+public abstract class MapElement {
+ private String[] labels;
+ private int type;
+
+ private int minResolution = 24;
+ private int maxResolution = 24;
+
+ private ExtTypeAttributes extTypeAttributes;
+ // other attributes
+ private String zip,country,region,city,street,phone,houseNumber,isIn;
+
+ protected MapElement() {
+ labels = new String[4];
+ }
+
+ protected MapElement(MapElement orig) {
+ labels = Arrays.copyOf(orig.labels, 4);
+ type = orig.type;
+ minResolution = orig.minResolution;
+ maxResolution = orig.maxResolution;
+ extTypeAttributes = orig.extTypeAttributes;
+ zip = orig.zip;
+ country = orig.country;
+ region = orig.region;
+ city = orig.city;
+ street = orig.street;
+ phone = orig.phone;
+ houseNumber = orig.houseNumber;
+ isIn = orig.isIn;
+ }
+
+ /**
+ * Provide a copy of this MapElement without geometry. This is used
+ * when filtering and clipping to create modified versions.
+ *
+ * @return the copy;
+ */
+ public abstract MapElement copy();
+
+ public String getName() {
+ return labels[0];
+ }
+
+ public String[] getLabels() {
+ return this.labels;
+ }
+
+ public void setName(String name) {
+ this.labels[0] = name;
+ }
+
+ public void setLabels(String[] labels) {
+ this.labels = Arrays.copyOf(labels, 4);
+ }
+
+ public ExtTypeAttributes getExtTypeAttributes() {
+ return extTypeAttributes;
+ }
+
+ public void setExtTypeAttributes(ExtTypeAttributes eta) {
+ extTypeAttributes = eta;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ public String getZip() {
+ return zip;
+ }
+
+ public void setZip(String zip) {
+ this.zip = zip;
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+ public String getRegion() {
+ return region;
+ }
+
+ public void setRegion(String region) {
+ this.region= region;
+ }
+
+ public String getStreet() {
+ return street;
+ }
+
+ public void setStreet(String street) {
+ this.street = street;
+ }
+
+ public String getPhone() {
+ return phone;
+ }
+
+ public void setPhone(String phone) {
+
+ if(phone.startsWith("00")) {
+ phone = phone.replaceFirst("00","+");
+ }
+ this.phone = phone;
+ }
+
+ public String getHouseNumber() {
+ return houseNumber;
+ }
+
+ public void setHouseNumber(String houseNumber) {
+ this.houseNumber = houseNumber;
+ }
+
+ public String getIsIn() {
+ return isIn;
+ }
+
+ public void setIsIn(String isIn) {
+ if(isIn != null)
+ this.isIn = isIn.toUpperCase();
+ }
+
+
+ /**
+ * This is the type code that goes in the .img file so that the GPS device
+ * knows what to display.
+ *
+ * @return the type.
+ */
+ public int getType() {
+ return type;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ public boolean isSimilar(MapElement other) {
+ if (this.minResolution != other.minResolution)
+ return false;
+ if (this.maxResolution != other.maxResolution)
+ return false;
+ if (this.type != other.type)
+ return false;
+
+ String thisName = getName();
+ String otherName = other.getName();
+
+ if (thisName == null && otherName == null)
+ return true;
+ if (thisName!=null && otherName!=null && thisName.equals(otherName))
+ return true;
+ return false;
+ }
+
+ public boolean hasExtendedType() {
+ return MapObject.hasExtendedType(type);
+ }
+
+ /**
+ * Get the 'location' of the element. This is the mid point of the bounding
+ * box for the element. For a point, this will be the coordinates of the
+ * point itself of course.
+ *
+ * @return Co-ordinate of the mid-point of the bounding box of the element.
+ */
+ public abstract Coord getLocation();
+
+ /**
+ * Get the resolutions that an element should be displayed at.
+ * It will return the minimum resolution at which this element should be
+ * displayed at.
+ *
+ * @return The lowest resolution at which the element will be visible.
+ */
+ public int getMinResolution() {
+ return minResolution;
+ }
+
+ public void setMinResolution(int minResolution) {
+ this.minResolution = minResolution;
+ }
+
+ /**
+ * The maximum resolution at which the element will be visible. This is normally
+ * 24, in other words the element is visible at all resolutions above the minimum.
+ * You can however set this lower, so that it will disappear as you zoom in, presumably to be
+ * replaced by another element.
+ *
+ * @return The max resolution (<= 24), default is 24.
+ */
+ public int getMaxResolution() {
+ return maxResolution;
+ }
+
+ public void setMaxResolution(int maxResolution) {
+ this.maxResolution = maxResolution;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/general/MapExitPoint.java b/src/uk/me/parabola/mkgmap/general/MapExitPoint.java
new file mode 100644
index 0000000..79cc9eb
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/MapExitPoint.java
@@ -0,0 +1,83 @@
+/**
+ * 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
+ * Date: 24-Dec-2006
+ */
+
+package uk.me.parabola.mkgmap.general;
+
+import uk.me.parabola.imgfmt.app.Exit;
+
+/**
+ * A point on the map that represents a motorway exit.
+ *
+ * @author Mark Burton
+ */
+public class MapExitPoint extends MapPoint {
+ private final String motorwayRef;
+ private final String to;
+ private String facilityDescription;
+ private String OSMId;
+ private Exit exit;
+
+ public MapExitPoint(String motorwayRef, String to) {
+ this.motorwayRef = motorwayRef;
+ this.to = to;
+ }
+
+ private MapExitPoint(MapExitPoint p) {
+ super(p);
+ this.motorwayRef = p.motorwayRef;
+ this.to = p.to;
+ }
+
+ public MapExitPoint copy() {
+ return new MapExitPoint(this);
+ }
+
+ public boolean isExit() {
+ return true;
+ }
+
+ public String getMotorwayRef() {
+ return motorwayRef;
+ }
+
+ public String getTo() {
+ return to;
+ }
+
+ public void setFacilityDescription(String facilityDescription) {
+ this.facilityDescription = facilityDescription;
+ }
+
+ public String getFacilityDescription() {
+ return facilityDescription;
+ }
+
+ public void setOSMId(String OSMId) {
+ this.OSMId = OSMId;
+ }
+
+ public String getOSMId() {
+ return OSMId;
+ }
+
+ public void setExit(Exit exit) {
+ this.exit = exit;
+ }
+
+ public Exit getExit() {
+ return exit;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/general/MapLine.java b/src/uk/me/parabola/mkgmap/general/MapLine.java
new file mode 100644
index 0000000..72dff38
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/MapLine.java
@@ -0,0 +1,157 @@
+/*
+ * 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: 18-Dec-2006
+ */
+package uk.me.parabola.mkgmap.general;
+
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+
+/**
+ * Represent a line on a Garmin map. Lines are a list of points. They have
+ * a type (major highway, stream etc) and a name. And that is just about it.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MapLine extends MapElement {
+ private static final Logger log = Logger.getLogger(MapLine.class);
+
+ private List<Coord> points;
+ private boolean direction; // set if direction is important.
+ private boolean skipSizeFilter;
+ private int minLat = Integer.MAX_VALUE;
+ private int minLong = Integer.MAX_VALUE;
+ private int maxLat = Integer.MIN_VALUE;
+ private int maxLong = Integer.MIN_VALUE;
+
+ public MapLine() {
+ }
+
+ public MapLine(MapLine orig) {
+ super(orig);
+ direction = orig.direction;
+ skipSizeFilter = orig.skipSizeFilter;
+ //roadDef = orig.roadDef;
+ }
+
+ public MapLine copy() {
+ return new MapLine(this);
+ }
+
+ public List<Coord> getPoints() {
+ return points;
+ }
+
+ public void setPoints(List<Coord> points) {
+ if (this.points != null)
+ log.warn("overwriting points");
+ assert points != null : "trying to set null points";
+ assert !points.isEmpty() : "trying to set points with zero length";
+
+ this.points = points;
+ testForConsecutivePoints(points);
+ }
+
+ public void testForConsecutivePoints(List<Coord> points) {
+ Coord last = null;
+ for (Coord co : points) {
+ if (last != null && last.equals(co))
+ log.info("Line " + getName() + " has consecutive identical points at " + co.toDegreeString() + " (discarding)");
+ else {
+ addToBounds(co);
+ last = co;
+ }
+ }
+ }
+
+ public void insertPointsAtStart(List<Coord> additionalPoints) {
+ testForConsecutivePoints(additionalPoints);
+ points.get(0).preserved(true);
+ points.addAll(0, additionalPoints);
+ points.remove(additionalPoints.size()-1); //End node exists now twice
+ }
+
+ public void insertPointsAtEnd(List<Coord> additionalPoints) {
+ testForConsecutivePoints(additionalPoints);
+ additionalPoints.get(0).preserved(true);
+ points.remove(points.size()-1);
+ points.addAll(additionalPoints);
+ }
+
+ public boolean isDirection() {
+ return direction;
+ }
+
+ public void setDirection(boolean direction) {
+ this.direction = direction;
+ }
+
+ public boolean isRoad() {
+ return false;
+ }
+
+ public boolean isSkipSizeFilter() {
+ return skipSizeFilter;
+ }
+
+ public void setSkipSizeFilter(boolean skipSizeFilter) {
+ this.skipSizeFilter = skipSizeFilter;
+ }
+
+
+ /**
+ * Get the mid-point of the bounding box for this element. This is as good
+ * an indication of 'where the element is' as any. Previously we just
+ * used the location of the first point which would lead to biases in
+ * allocating elements to subdivisions.
+ *
+ * @return The mid-point of the bounding box.
+ */
+ public Coord getLocation() {
+ return new Coord((minLat + maxLat) / 2, (minLong + maxLong) / 2);
+ }
+
+ /**
+ * We build up the bounding box of this element by calling this routine.
+ *
+ * @param co The coordinate to add.
+ */
+ private void addToBounds(Coord co) {
+ int lat = co.getLatitude();
+ if (lat < minLat)
+ minLat = lat;
+ if (lat > maxLat)
+ maxLat = lat;
+
+ int lon = co.getLongitude();
+ if (lon < minLong)
+ minLong = lon;
+ if (lon > maxLong)
+ maxLong = lon;
+ }
+
+ /**
+ * Get the region that this element covers.
+ *
+ * @return The area that bounds this element.
+ */
+ public Area getBounds() {
+ return new Area(minLat, minLong, maxLat, maxLong);
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/general/MapPoint.java b/src/uk/me/parabola/mkgmap/general/MapPoint.java
new file mode 100644
index 0000000..31e68c8
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/MapPoint.java
@@ -0,0 +1,81 @@
+/**
+ * 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
+ * Date: 24-Dec-2006
+ */
+package uk.me.parabola.mkgmap.general;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+
+/**
+ * A point on the map. This will appear as a symbol on the map and it will
+ * normally be in the list of things that can be seen on the find menu.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MapPoint extends MapElement {
+ private Coord location;
+ private boolean isRoadNamePoi;
+
+ public MapPoint() {
+ }
+
+ protected MapPoint(MapPoint p) {
+ super(p);
+ location = p.location;
+ }
+
+ public MapPoint copy() {
+ return new MapPoint(this);
+ }
+
+ public Coord getLocation() {
+ return location;
+ }
+
+ public void setLocation(Coord location) {
+ this.location = location;
+ }
+
+ /**
+ * Get the region that this element covers.
+ *
+ * @return The area that bounds this element.
+ */
+ public Area getBounds() {
+ return new Area(location.getLatitude(), location.getLongitude(),
+ location.getLatitude(), location.getLongitude());
+ }
+
+ public boolean isCity() {
+ return isCityType(getType());
+ }
+
+ public void setRoadNamePOI(boolean isRoadNamePoi) {
+ this.isRoadNamePoi = isRoadNamePoi;
+ }
+
+ public boolean isRoadNamePOI() {
+ return this.isRoadNamePoi;
+ }
+
+ public static boolean isCityType(int type)
+ {
+ return type >= 0x0100 && type <= 0x1100;
+ }
+
+ public boolean isExit() {
+ return false;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/general/MapPointFastFindMap.java b/src/uk/me/parabola/mkgmap/general/MapPointFastFindMap.java
new file mode 100644
index 0000000..061b417
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/MapPointFastFindMap.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2009 Bernhard Heibler
+ *
+ * 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.
+ *
+ * This is multi-map to store city information for the Address Locator
+ * tt provides also a fast tile based nearest point search function
+ *
+ *
+ * Author: Bernhard Heibler
+ * Create date: 02-Jan-2009
+ */
+
+package uk.me.parabola.mkgmap.general;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.app.Coord;
+
+public class MapPointFastFindMap{
+
+ private final Map<String, ArrayList<MapPoint>> map = new HashMap<String, ArrayList<MapPoint>>();
+ private final Map<Long,ArrayList<MapPoint>> posMap = new HashMap<Long,ArrayList<MapPoint>>();
+ private final ArrayList<MapPoint> points = new ArrayList<MapPoint>();
+
+ private static final long POS_HASH_DIV = 8000; // the smaller -> more tiles
+ private static final long POS_HASH_MUL = 10000; // multiplier for latitude to create hash
+
+ public MapPoint put(String name, MapPoint p)
+ {
+ ArrayList<MapPoint> list;
+
+ if(name != null)
+ {
+ list = map.get(name);
+
+ if(list == null){
+
+ list = new ArrayList<MapPoint>();
+ list.add(p);
+ map.put(name, list);
+ }
+ else
+ list.add(p);
+
+ points.add(p);
+ }
+
+ long posHash = getPosHashVal(p.getLocation().getLatitude(), p.getLocation().getLongitude());
+
+ list = posMap.get(posHash);
+
+ if(list == null)
+ {
+ list = new ArrayList<MapPoint>();
+ list.add(p);
+ posMap.put(posHash, list);
+ }
+ else
+ list.add(p);
+
+ return p;
+ }
+
+ public Collection<MapPoint> getList(String name)
+ {
+ return map.get(name);
+ }
+
+ public long size()
+ {
+ return points.size();
+ }
+
+
+ public MapPoint findNextPoint(MapPoint p)
+ {
+ /* tile based search
+
+ to prevent expensive linear search over all points we put the points
+ into tiles. We just search the tiles the point is in linear and the
+ surrounding tiles. If we don't find a point we have to search further
+ around the central tile
+
+ */
+
+ MapPoint nextPoint = null;
+
+ if(posMap.size() < 1) // No point in list
+ return nextPoint;
+
+ long centLatitIdx = p.getLocation().getLatitude() / POS_HASH_DIV ;
+ long centLongiIdx = p.getLocation().getLongitude() / POS_HASH_DIV ;
+ long delta = 1;
+
+ double minDist = Double.MAX_VALUE;
+ do
+ {
+ // in the first step we only check our tile and the tiles surrounding us
+
+ for(long latitIdx = centLatitIdx - delta; latitIdx <= centLatitIdx + delta; latitIdx++)
+ for(long longiIdx = centLongiIdx - delta; longiIdx <= centLongiIdx + delta; longiIdx++)
+ {
+ if(delta < 2
+ || latitIdx == centLatitIdx - delta
+ || latitIdx == centLatitIdx + delta
+ || longiIdx == centLongiIdx - delta
+ || longiIdx == centLongiIdx + delta)
+ {
+
+ long posHash = latitIdx * POS_HASH_MUL + longiIdx;
+
+ ArrayList<MapPoint> list = posMap.get(posHash);
+
+ if(list != null)
+ {
+
+ for (MapPoint actPoint: list)
+ {
+ double distance = actPoint.getLocation().distanceInDegreesSquared(p.getLocation());
+
+ if(distance < minDist)
+ {
+ nextPoint = actPoint;
+ minDist = distance;
+
+ }
+ }
+ }
+ }
+ }
+ delta ++; // We have to look in tiles fairer away
+ }
+ while(nextPoint == null);
+
+ return nextPoint;
+ }
+
+ public MapPoint findPointInShape(MapShape shape, int pointType, String poiName) {
+ List<Coord> points = shape.getPoints();
+ MapPoint nextPoint = null;
+
+ if(posMap.size() < 1) // No point in list
+ return nextPoint;
+
+ long lastHashValue = -1;
+ for (Coord point : points) {
+ long posHash = getPosHashVal(point.getLatitude(), point.getLongitude());
+
+ if (posHash == lastHashValue) // Have we already checked this tile ?
+ continue;
+
+ lastHashValue = posHash;
+
+ ArrayList<MapPoint> list = posMap.get(posHash);
+
+ if (list != null) {
+ for (MapPoint actPoint : list) {
+ boolean checkThisPoint = false;
+
+ if (pointType == 0 || actPoint.getType() == pointType)
+ checkThisPoint = true;
+
+ if(MapPoint.isCityType(pointType) && actPoint.isCity() &&
+ actPoint.getName() != null && poiName != null)
+ {
+ // Check for city name pois in that shape
+ // Since the types might not be exactly the same we
+ // check for all places pois with the same name
+
+ checkThisPoint = actPoint.getName().equalsIgnoreCase(poiName);
+ }
+
+ if (checkThisPoint && shape.contains(actPoint.getLocation()))
+ return actPoint;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private long getPosHashVal(long lat, long lon)
+ {
+ long latitIdx = lat / POS_HASH_DIV ;
+ long longiIdx = lon / POS_HASH_DIV ;
+
+ return latitIdx * POS_HASH_MUL + longiIdx;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/general/MapPointKdTree.java b/src/uk/me/parabola/mkgmap/general/MapPointKdTree.java
new file mode 100644
index 0000000..010761c
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/MapPointKdTree.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.general;
+
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.general.MapPoint;
+
+
+/**
+ * A kd-tree (2D) implementation to solve the nearest neighbor problem.
+ * The tree is not explicitly balanced.
+ *
+ * @author GerdP
+ *
+ */
+public class MapPointKdTree {
+ private static final boolean ROOT_NODE_USES_LONGITUDE = false;
+
+ private static class KdNode {
+ MapPoint point;
+ KdNode left;
+ KdNode right;
+
+ KdNode(MapPoint p) {
+ point = p;
+ }
+ }
+ // the tree root
+ private KdNode root;
+ // number of saved MapPoint objects
+ private int size;
+
+ // helpers
+ private MapPoint nextPoint ;
+ private double minDist;
+
+ /**
+ * create an empty tree
+ */
+ public MapPointKdTree() {
+ root = null;
+ }
+
+ public long size()
+ {
+ return size;
+ }
+
+
+ /**
+ * Start the add action with the root
+ * @param toAdd
+ */
+ public void add(MapPoint toAdd) {
+ size++;
+ root = add(toAdd, root, ROOT_NODE_USES_LONGITUDE);
+ }
+
+ /**
+ * Compares the given axis of both points.
+ * @param longitude <code>true</code>: compare longitude; <code>false</code> compare latitude
+ * @param c1 a point
+ * @param c2 another point
+ * @return <code>true</code> the axis value of c1 is smaller than c2;
+ * <code>false</code> the axis value of c1 is equal or larger than c2
+ */
+ private boolean isSmaller(boolean longitude, Coord c1, Coord c2) {
+ if (longitude) {
+ return c1.getLongitude() < c2.getLongitude();
+ } else {
+ return c1.getLatitude() < c2.getLatitude();
+ }
+ }
+
+ /**
+ * Recursive routine to find the right place for inserting
+ * into the tree.
+ * @param toAdd the point
+ * @param tree the subtree root node where to add (maybe <code>null</code>)
+ * @param useLongitude <code>true</code> the tree node uses longitude for comparison;
+ * <code>false</code> the tree node uses latitude for comparison
+ * @return the subtree root node after insertion
+ */
+ private KdNode add( MapPoint toAdd, KdNode tree, boolean useLongitude){
+ if( tree == null ) {
+ tree = new KdNode( toAdd );
+ } else {
+ if(isSmaller(useLongitude, toAdd.getLocation(), tree.point.getLocation())) {
+ tree.left = add(toAdd, tree.left, !useLongitude);
+ } else {
+ tree.right = add(toAdd, tree.right, !useLongitude);
+ }
+ }
+ return tree;
+ }
+
+ /**
+ * Searches for the point that has smallest distance to the given point.
+ * @param p the point to search for
+ * @return the point with shortest distance to <var>p</var>
+ */
+ public MapPoint findNextPoint(MapPoint p) {
+ // reset
+ minDist = Double.MAX_VALUE;
+ nextPoint = null;
+
+ // false => first node is a latitude level
+ return findNextPoint(p, root, ROOT_NODE_USES_LONGITUDE);
+ }
+
+ private MapPoint findNextPoint(MapPoint p, KdNode tree, boolean useLongitude) {
+ boolean continueWithLeft = false;
+ if (tree == null)
+ return nextPoint;
+
+ if (tree.left == null && tree.right == null){
+ double dist = tree.point.getLocation().distanceInDegreesSquared(p.getLocation());
+ if (dist < minDist){
+ nextPoint = tree.point;
+ minDist = dist;
+ }
+ return nextPoint;
+ }
+ else {
+ if (isSmaller(useLongitude, p.getLocation(), tree.point.getLocation())){
+ continueWithLeft = false;
+ nextPoint = findNextPoint(p, tree.left, !useLongitude);
+ }
+ else {
+ continueWithLeft = true;
+ nextPoint = findNextPoint(p, tree.right, !useLongitude);
+ }
+ }
+
+ double dist = tree.point.getLocation().distanceInDegreesSquared(p.getLocation());
+ if (dist < minDist){
+ nextPoint = tree.point;
+ minDist = dist;
+ }
+
+ // do we have to search the other part of the tree?
+ Coord test;
+ if (useLongitude)
+ test = new Coord(p.getLocation().getLatitude(),tree.point.getLocation().getLongitude());
+ else
+ test = new Coord(tree.point.getLocation().getLatitude(),p.getLocation().getLongitude());
+ if (test.distanceInDegreesSquared(p.getLocation()) < minDist){
+ if (continueWithLeft)
+ nextPoint = findNextPoint(p, tree.left, !useLongitude);
+ else
+ nextPoint = findNextPoint(p, tree.right, !useLongitude);
+ }
+ return nextPoint;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/general/MapPointMultiMap.java b/src/uk/me/parabola/mkgmap/general/MapPointMultiMap.java
new file mode 100644
index 0000000..497e9c1
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/MapPointMultiMap.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009 Bernhard Heibler
+ *
+ * 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.
+ *
+ * This is multimap to store city information for the Address Locator
+ *
+ *
+ * Author: Bernhard Heibler
+ * Create date: 02-Jan-2009
+ */
+
+package uk.me.parabola.mkgmap.general;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MapPointMultiMap {
+
+ private final Map<String,ArrayList<MapPoint>> map = new HashMap<String, ArrayList<MapPoint>>();
+
+ public MapPoint put(String name, MapPoint p) {
+ ArrayList<MapPoint> list = map.get(name);
+
+ if(list == null){
+
+ list = new ArrayList<MapPoint>();
+ list.add(p);
+ map.put(name, list);
+ }
+ else
+ list.add(p);
+
+ return p;
+ }
+
+ public MapPoint get(String name) {
+ ArrayList<MapPoint> list = map.get(name);
+
+ if(list != null)
+ return list.get(0);
+ else
+ return null;
+ }
+
+ public Collection<MapPoint> getList(String name)
+ {
+ return map.get(name);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/general/MapRoad.java b/src/uk/me/parabola/mkgmap/general/MapRoad.java
new file mode 100644
index 0000000..ed67756
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/MapRoad.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2008 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: 13-Jul-2008
+ */
+package uk.me.parabola.mkgmap.general;
+
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.lbl.City;
+import uk.me.parabola.imgfmt.app.lbl.Zip;
+import uk.me.parabola.imgfmt.app.net.Numbers;
+import uk.me.parabola.imgfmt.app.net.RoadDef;
+
+/**
+ * Used to represent a road. A road is a special kind of line in that
+ * it can be used to route down and can have addresses etc.
+ *
+ * A road has several coordinates, and some of those coordinates can be
+ * routing nodes.
+ *
+ * A lot of the information is kept in a {@link RoadDef} this is done
+ * because it needs to be shared between all sections and all levels
+ * of the same road.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MapRoad extends MapLine {
+
+ private final RoadDef roadDef;
+ private boolean segmentsFollowing;
+
+ public MapRoad(long id, MapLine line) {
+ super(line);
+ setPoints(line.getPoints());
+ roadDef = new RoadDef(id, getName());
+ }
+
+ private MapRoad(MapRoad r) {
+ super(r);
+ roadDef = r.roadDef;
+ segmentsFollowing = r.segmentsFollowing;
+ }
+
+ public MapRoad copy() {
+ return new MapRoad(this);
+ }
+
+ public boolean isRoad() {
+ return true;
+ }
+
+ public void setRoadClass(int roadClass) {
+ roadDef.setRoadClass(roadClass);
+ }
+
+ public void setSpeed(int speed) {
+ roadDef.setSpeed(speed);
+ }
+
+ public void setOneway() {
+ roadDef.setOneway();
+ }
+
+ public void setToll() {
+ roadDef.setToll();
+ }
+
+ public void paved(boolean p) {
+ roadDef.paved(p);
+ }
+
+ public void ferry(boolean f) {
+ roadDef.ferry(f);
+ }
+
+ public void setSynthesised(boolean s) {
+ roadDef.setSynthesised(s);
+ }
+
+ // XXX: currently passing PolishMapSource-internal format
+ public void setAccess(boolean[] access) {
+ roadDef.setAccess(access);
+ }
+
+ public void setCarpoolLane() {
+ roadDef.setCarpoolLane();
+ }
+
+ public void setNoThroughRouting() {
+ roadDef.setNoThroughRouting();
+ }
+
+ public void setStartsWithNode(boolean s) {
+ roadDef.setStartsWithNode(s);
+ }
+
+ public void setInternalNodes(boolean s) {
+ roadDef.setInternalNodes(s);
+ }
+
+ public void setNumNodes(int n) {
+ roadDef.setNumNodes(n);
+ }
+
+ public void setNumbers(List<Numbers> numbers) {
+ roadDef.setNumbersList(numbers);
+ }
+
+ public RoadDef getRoadDef() {
+ return roadDef;
+ }
+
+ public void setRoadCity(City c) {
+ roadDef.setCity(c);
+ }
+
+ public void setRoadZip(Zip z) {
+ roadDef.setZip(z);
+ }
+
+ public void setRoundabout(boolean r) {
+ roadDef.setRoundabout(r);
+ }
+
+ public void doFlareCheck(boolean fc) {
+ roadDef.doFlareCheck(fc);
+ }
+
+ public void setLinkRoad(boolean lr) {
+ roadDef.setLinkRoad(lr);
+ }
+
+ public boolean hasSegmentsFollowing() {
+ return segmentsFollowing;
+ }
+
+ public void setSegmentsFollowing(boolean segmentsFollowing) {
+ this.segmentsFollowing = segmentsFollowing;
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/general/MapShape.java b/src/uk/me/parabola/mkgmap/general/MapShape.java
new file mode 100644
index 0000000..670e43a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/MapShape.java
@@ -0,0 +1,186 @@
+/**
+ * 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
+ * Date: 23-Dec-2006
+ */
+package uk.me.parabola.mkgmap.general;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+
+/**
+ * A shape or polygon is just the same as a line really as far as I can tell.
+ * There are some things that you cannot do with them semantically.
+ *
+ * @author Steve Ratcliffe.
+ */
+public class MapShape extends MapLine {// So top code can link objects from here
+
+ public MapShape() {
+ }
+
+ MapShape(MapShape s) {
+ super(s);
+ }
+
+ public MapShape copy() {
+ return new MapShape(this);
+ }
+
+ public void setDirection(boolean direction) {
+ throw new IllegalArgumentException(
+ "can't set a direction on a polygon");
+ }
+
+ /**
+ * Checks if a point is contained within this shape. Points on the
+ * edge of the shape are considered inside.
+ *
+ * @param co point to check
+ * @return true if point is in shape, false otherwise
+ */
+ public boolean contains(Coord co) {
+ return contains(this.getPoints(), co, true);
+ }
+
+ /**
+ * Checks if a point is contained within a shape.
+ *
+ * @param points points that define the shape
+ * @param target point to check
+ * @param onLineIsInside if a point on the line should be considered inside the shape
+ * @return true if point is contained within the shape, false if the target point is outside the shape
+ */
+ private static boolean contains(List<Coord> points, Coord target, boolean onLineIsInside) {
+ // implementation of the Ray casting algorithm as described here:
+ // http://en.wikipedia.org/wiki/Point_in_polygon
+ // with inspiration from:
+ // http://www.visibone.com/inpoly/
+ if (points.size() < 3)
+ return false;
+
+ // complete the shape if we're dealing with a MapShape that is not closed
+ Coord start = points.get(0);
+ Coord end = points.get(points.size() - 1);
+ if (!start.equals(end)) {
+ // make copy of the shape's geometry
+ List<Coord> pointsTemp = new ArrayList<Coord>(points.size() + 1);
+ for (Coord coord : points) {
+ pointsTemp.add(new Coord(coord.getLatitude(), coord.getLongitude()));
+ }
+ pointsTemp.add(new Coord(start.getLatitude(), start.getLongitude()));
+ points = pointsTemp;
+ }
+
+ int xtarget = target.getLatitude();
+ int ytarget = target.getLongitude();
+
+ boolean inside = false;for (int i = 0; i < points.size() - 1; i++) {
+
+ // apply transformation points to change target point to (0,0)
+ int x0 = points.get(i).getLatitude() - xtarget;
+ int y0 = points.get(i).getLongitude() - ytarget;
+ int x1 = points.get(i+1).getLatitude() - xtarget;
+ int y1 = points.get(i+1).getLongitude() - ytarget;
+
+ // ensure that x0 is smaller than x1 so that we can just check to see if the line intersects the y axis easily
+ if (x0 > x1) {
+ int xtemp = x0;
+ int ytemp = y0;
+ x0 = x1;
+ y0 = y1;
+ x1 = xtemp;
+ y1 = ytemp;
+ }
+
+ // use (0,0) as target because points already transformed
+ if (isPointOnLine(x0, y0, x1, y1, 0, 0))
+ return onLineIsInside;
+
+ // explanation of if statement
+ //
+ // (x0 < 0 && x1 >= 0):
+ // are the x values between the y axis? only include points from the right
+ // with this check so that corners aren't counted twice
+ //
+ // (y0 * (x1 - x0) > (y1 - y0) * x0):
+ // from y = mx + b:
+ // => b = y0 ((y1 - y0) / (x1 - x0)) * x0
+ // for intersection, b > 0
+ // from y = mx + b, b = y - mx
+ // => y - mx > 0
+ // => y0 - ((y1 - y0) / (x1 - x0)) * x0 > 0
+ // => y0 > ((y1 - y0) / (x1 - x0)) * x0
+ // from 'if (x0 > x1)', x1 >= x0
+ // => x1 - x0 >=0
+ // => y0 * (x1 - x0) > (y1 - y0) * x0
+ if ((x0 < 0 && x1 >= 0) && (y0 * (x1 - x0)) > ((y1 - y0) * x0))
+ inside = !inside;
+ }
+
+ return inside;
+ }
+
+ /**
+ * Checks if a point is on a line.
+ *
+ * @param x0 x value of first point in line
+ * @param y0 y value of first point in line
+ * @param x1 x value of second point in line
+ * @param y1 y value of second point in line
+ * @param xt x value of target point
+ * @param yt y value of target point
+ * @return return true if point is on the line, false if the point isn't on the line
+ */
+ private static boolean isPointOnLine(int x0, int y0, int x1, int y1, int xt, int yt) {
+ // this implementation avoids using doubles
+ // apply transformation points to change target point to (0,0)
+ x0 -= xt;
+ y0 -= yt;
+ x1 -= xt;
+ y1 -= yt;
+
+ // ensure that x0 is smaller than x1 so that we can just check to see if the line intersects the y axis easily
+ if (x0 > x1) {
+ int xtemp = x0;
+ int ytemp = y0;
+ x0 = x1;
+ y0 = y1;
+ x1 = xtemp;
+ y1 = ytemp;
+ }
+
+ // if a point is on the edge of shape (on a line), it's considered outside the shape
+ // special case if line is on y-axis
+ if (x0 == 0 && x1 == 0) {
+ // ensure that y0 is smaller than y1 so that we can just check if the line intersects the x axis
+ if (y0 > y1) {
+ int ytemp = y0;
+ y0 = y1;
+ y1 = ytemp;
+ }
+ // test to see if we have a vertical line touches x-axis
+ if (y0 <= 0 && y1 >= 0)
+ return true;
+ // checks if point is on the line, see comments in contain() for derivation of similar
+ // formula - left as an exercise to the reader ;)
+ } else if ((x0 <= 0 && x1 >= 0) && (y0 * (x1 - x0)) == ((y1 - y0) * x0)) {
+ return true;
+ }
+ return false;
+ }
+
+
+}
diff --git a/src/uk/me/parabola/mkgmap/general/NullClipper.java b/src/uk/me/parabola/mkgmap/general/NullClipper.java
new file mode 100644
index 0000000..d94135e
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/NullClipper.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008 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: 10-Nov-2008
+ */
+package uk.me.parabola.mkgmap.general;
+
+import uk.me.parabola.imgfmt.app.Coord;
+
+/**
+ * Does no clipping and just adds the elements directly.
+ *
+ * @author Steve Ratcliffe
+ */
+public class NullClipper implements Clipper {
+ public void clipLine(MapLine line, LineAdder adder) {
+ adder.add(line);
+ }
+
+ public void clipShape(MapShape shape, MapCollector collector) {
+ collector.addShape(shape);
+ }
+
+ public boolean contains(Coord location) {
+ return true;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/general/PolygonClipper.java b/src/uk/me/parabola/mkgmap/general/PolygonClipper.java
new file mode 100644
index 0000000..060d7dd
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/PolygonClipper.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 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: 01-Jul-2008
+ */
+package uk.me.parabola.mkgmap.general;
+
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.util.Java2DConverter;
+
+/**
+ * Clip a polygon to the given bounding box. This may result in more than
+ * one polygon.
+ *
+ * @author Steve Ratcliffe
+ */
+public class PolygonClipper {
+
+ /**
+ * Clip the input polygon to the given area.
+ * @param bbox The bounding box.
+ * @param coords The coords of the polygon.
+ * @return Return null if the polygon is already completely inside the
+ * bounding box.
+ */
+ public static List<List<Coord>> clip(Area bbox, List<Coord> coords) {
+ if (bbox == null)
+ return null;
+
+ // If all the points are inside the box then we just return null
+ // to show that nothing was done and the line can be used. This
+ // is expected to be the normal case.
+ boolean foundOutside = false;
+ for (Coord co : coords) {
+ if (!bbox.contains(co)) {
+ foundOutside = true;
+ break;
+ }
+ }
+ if (!foundOutside)
+ return null;
+
+ java.awt.geom.Area bbarea = Java2DConverter.createBoundsArea(bbox);
+ java.awt.geom.Area shape = Java2DConverter.createArea(coords);
+
+ shape.intersect(bbarea);
+
+ return Java2DConverter.areaToShapes(shape);
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/general/RoadNetwork.java b/src/uk/me/parabola/mkgmap/general/RoadNetwork.java
new file mode 100644
index 0000000..0580b44
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/RoadNetwork.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2008 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: 13-Jul-2008
+ */
+package uk.me.parabola.mkgmap.general;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.CoordNode;
+import uk.me.parabola.imgfmt.app.net.NOD1Part;
+import uk.me.parabola.imgfmt.app.net.RoadDef;
+import uk.me.parabola.imgfmt.app.net.RouteArc;
+import uk.me.parabola.imgfmt.app.net.RouteCenter;
+import uk.me.parabola.imgfmt.app.net.RouteNode;
+import uk.me.parabola.imgfmt.app.net.RouteRestriction;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * This holds the road network. That is all the roads and the nodes
+ * that connect them together.
+ *
+ * @see <a href="http://www.movable-type.co.uk/scripts/latlong.html">Distance / bearing calculations</a>
+ * @author Steve Ratcliffe
+ */
+public class RoadNetwork {
+ private static final Logger log = Logger.getLogger(RoadNetwork.class);
+
+ public static final int NO_EMERGENCY = 0;
+ public static final int NO_DELIVERY = 1;
+ public static final int NO_CAR = 2;
+ public static final int NO_BUS = 3;
+ public static final int NO_TAXI = 4;
+ public static final int NO_FOOT = 5;
+ public static final int NO_BIKE = 6;
+ public static final int NO_TRUCK = 7;
+ public static final int NO_MAX = 8;
+
+ private final Map<Long, RouteNode> nodes = new LinkedHashMap<Long, RouteNode>();
+
+ // boundary nodes
+ // a node should be in here iff the nodes boundary flag is set
+ private final List<RouteNode> boundary = new ArrayList<RouteNode>();
+ //private final List<MapRoad> mapRoads = new ArrayList<MapRoad>();
+
+ private final List<RoadDef> roadDefs = new ArrayList<RoadDef>();
+ private List<RouteCenter> centers = new ArrayList<RouteCenter>();
+ private int adjustTurnHeadings ;
+ private boolean checkRoundabouts;
+ private boolean checkRoundaboutFlares;
+ private int maxFlareLengthRatio ;
+ private boolean reportSimilarArcs;
+ private boolean outputCurveData;
+
+ public void config(EnhancedProperties props) {
+ String ath = props.getProperty("adjust-turn-headings");
+ if(ath != null) {
+ if(ath.length() > 0)
+ adjustTurnHeadings = Integer.decode(ath);
+ else
+ adjustTurnHeadings = RouteNode.ATH_DEFAULT_MASK;
+ }
+ checkRoundabouts = props.getProperty("check-roundabouts", false);
+ checkRoundaboutFlares = props.getProperty("check-roundabout-flares", false);
+ maxFlareLengthRatio = props.getProperty("max-flare-length-ratio", 0);
+
+ reportSimilarArcs = props.getProperty("report-similar-arcs", false);
+
+ outputCurveData = !props.getProperty("no-arc-curves", false);
+ }
+
+ public void addRoad(MapRoad road) {
+ //mapRoads.add(road);
+ roadDefs.add(road.getRoadDef()); //XXX
+
+ CoordNode lastCoord = null;
+ int lastIndex = 0;
+ double roadLength = 0;
+ double arcLength = 0;
+ int pointsHash = 0;
+
+ List<Coord> coordList = road.getPoints();
+ int npoints = coordList.size();
+ for (int index = 0; index < npoints; index++) {
+ Coord co = coordList.get(index);
+
+ if (index > 0) {
+ double d = co.distance(coordList.get(index-1));
+ arcLength += d;
+ roadLength += d;
+ }
+
+ long id = co.getId();
+
+ pointsHash += co.hashCode();
+
+ if (id == 0)
+ // not a routing node
+ continue;
+
+ // The next coord determines the heading
+ // If this is the not the first node, then create an arc from
+ // the previous node to this one (and back again).
+ if (lastCoord != null) {
+ long lastId = lastCoord.getId();
+ if(log.isDebugEnabled()) {
+ log.debug("lastId = " + lastId + " curId = " + id);
+ log.debug("from " + lastCoord.toDegreeString()
+ + " to " + co.toDegreeString());
+ log.debug("arclength=" + arcLength + " roadlength=" + roadLength);
+ }
+
+ RouteNode node1 = getNode(lastId, lastCoord);
+ RouteNode node2 = getNode(id, co);
+
+ if(node1 == node2)
+ log.error("Road " + road.getRoadDef() + " contains consecutive identical nodes at " + co.toOSMURL() + " - routing will be broken");
+ else if(arcLength == 0)
+ log.error("Road " + road.getRoadDef() + " contains zero length arc at " + co.toOSMURL());
+
+
+ Coord bearingPoint = coordList.get(lastIndex + 1);
+ if(lastCoord.equals(bearingPoint)) {
+ // bearing point is too close to last node to be
+ // useful - try some more points
+ for(int bi = lastIndex + 2; bi <= index; ++bi) {
+ if(!lastCoord.equals(coordList.get(bi))) {
+ bearingPoint = coordList.get(bi);
+ break;
+ }
+ }
+ }
+ int forwardBearing = (int)lastCoord.bearingTo(bearingPoint);
+ int inverseForwardBearing = (int)bearingPoint.bearingTo(lastCoord);
+
+ bearingPoint = coordList.get(index - 1);
+ if(co.equals(bearingPoint)) {
+ // bearing point is too close to this node to be
+ // useful - try some more points
+ for(int bi = index - 2; bi > lastIndex; --bi) {
+ if(!co.equals(coordList.get(bi))) {
+ bearingPoint = coordList.get(bi);
+ break;
+ }
+ }
+ }
+ int reverseBearing = (int)co.bearingTo(bearingPoint);
+ int inverseReverseBearing = (int)bearingPoint.bearingTo(co);
+
+ // Create forward arc from node1 to node2
+ RouteArc arc = new RouteArc(road.getRoadDef(),
+ node1,
+ node2,
+ forwardBearing,
+ inverseReverseBearing,
+ arcLength,
+ outputCurveData,
+ pointsHash);
+ arc.setForward();
+ node1.addArc(arc);
+ node2.addIncomingArc(arc);
+
+ // Create the reverse arc
+ arc = new RouteArc(road.getRoadDef(),
+ node2, node1,
+ reverseBearing,
+ inverseForwardBearing,
+ arcLength,
+ outputCurveData,
+ pointsHash);
+ node2.addArc(arc);
+ node1.addIncomingArc(arc);
+ } else {
+ // This is the first node in the road
+ road.getRoadDef().setNode(getNode(id, co));
+ }
+
+ lastCoord = (CoordNode) co;
+ lastIndex = index;
+ arcLength = 0;
+ pointsHash = co.hashCode();
+ }
+ road.getRoadDef().setLength(roadLength);
+ }
+
+ private RouteNode getNode(long id, Coord coord) {
+ RouteNode node = nodes.get(id);
+ if (node == null) {
+ node = new RouteNode(coord);
+ nodes.put(id, node);
+ if (node.isBoundary())
+ boundary.add(node);
+ }
+ return node;
+ }
+
+ public List<RoadDef> getRoadDefs() {
+ return roadDefs;
+ }
+
+ /**
+ * Split the network into RouteCenters.
+ *
+ * The resulting centers must satisfy several constraints,
+ * documented in NOD1Part.
+ */
+ private void splitCenters() {
+ if (nodes.isEmpty())
+ return;
+ assert centers.isEmpty() : "already subdivided into centers";
+
+ NOD1Part nod1 = new NOD1Part();
+
+ for (RouteNode node : nodes.values()) {
+ if(!node.isBoundary()) {
+ if(checkRoundabouts)
+ node.checkRoundabouts();
+ if(checkRoundaboutFlares)
+ node.checkRoundaboutFlares(maxFlareLengthRatio);
+ if(reportSimilarArcs)
+ node.reportSimilarArcs();
+ }
+ if(adjustTurnHeadings != 0)
+ node.tweezeArcs(adjustTurnHeadings);
+ nod1.addNode(node);
+ }
+ centers = nod1.subdivide();
+ }
+
+ public List<RouteCenter> getCenters() {
+ if (centers.isEmpty())
+ splitCenters();
+ return centers;
+ }
+
+ /**
+ * Get the list of nodes on the boundary of the network.
+ *
+ * Currently empty.
+ */
+ public List<RouteNode> getBoundary() {
+ return boundary;
+ }
+
+ public void addRestriction(CoordNode fromNode, CoordNode toNode, CoordNode viaNode, byte exceptMask) {
+ RouteNode fn = nodes.get(fromNode.getId());
+ RouteNode tn = nodes.get(toNode.getId());
+ RouteNode vn = nodes.get(viaNode.getId());
+
+ assert fn != null : "can't locate 'from' RouteNode with id " + fromNode.getId();
+ assert tn != null : "can't locate 'to' RouteNode with id " + toNode.getId();
+ assert vn != null : "can't locate 'via' RouteNode with id " + viaNode.getId();
+
+ RouteArc fa = vn.getArcTo(fn); // inverse arc gets used
+ RouteArc ta = vn.getArcTo(tn);
+
+ assert fa != null : "can't locate arc from 'via' node to 'from' node";
+ assert ta != null : "can't locate arc from 'via' node to 'to' node";
+
+ vn.addRestriction(new RouteRestriction(fa, ta, exceptMask));
+ }
+
+ public void addThroughRoute(long junctionNodeId, long roadIdA, long roadIdB) {
+ RouteNode node = nodes.get(junctionNodeId);
+ assert node != null : "Can't find node with id " + junctionNodeId;
+
+ node.addThroughRoute(roadIdA, roadIdB);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/general/package.html b/src/uk/me/parabola/mkgmap/general/package.html
new file mode 100644
index 0000000..5a930f8
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/package.html
@@ -0,0 +1,15 @@
+<body>
+<h3>Generic map types</h3>
+<p>Here we have the general map types that are used to build the map.
+ Other data sources, such as the OSM reader, have to convert to
+ this format.
+<p>Note that this is the most detailed representation of the map.
+ We use this intermediate form, because a Garmin map has (or can have)
+ different levels of zoom which will be at different levels of detail.
+<p>So we go through this <em>general</em> representation to construct the
+ actual representations at each level. These actual representations will
+ use objects from the @{link uk.me.parabola.imgfmt.app} package, and
+ they may have a different number of points to this general representation.
+ Indeed they may have different points all together since we may take the
+ average of several points in the general representation</p>
+</body>
diff --git a/src/uk/me/parabola/mkgmap/main/AbstractTestMap.java b/src/uk/me/parabola/mkgmap/main/AbstractTestMap.java
new file mode 100644
index 0000000..87b030e
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/main/AbstractTestMap.java
@@ -0,0 +1,99 @@
+/*
+ * 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: 02-Jan-2007
+ */
+package uk.me.parabola.mkgmap.main;
+
+import uk.me.parabola.imgfmt.ExitException;
+import uk.me.parabola.imgfmt.FileExistsException;
+import uk.me.parabola.imgfmt.FileNotWritableException;
+import uk.me.parabola.imgfmt.FileSystemParam;
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.map.Map;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+import uk.me.parabola.imgfmt.app.trergn.Zoom;
+import uk.me.parabola.log.Logger;
+
+/**
+ * Common code used for the test maps. The test maps are programmatically
+ * constructed to contain examples of each type of point and such like.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class AbstractTestMap {
+ private static final Logger log = Logger.getLogger(AbstractTestMap.class);
+
+ protected void makeMap(String[] args) {
+ // Default to nowhere in particular.
+ double lat = 51.724;
+ double lng = 0.2487;
+
+ // Arguments allow you to place the map where ever you wish.
+ if (args.length > 1) {
+ lat = Double.valueOf(args[0]);
+ lng = Double.valueOf(args[1]);
+ }
+
+ log.debug("this is a test make map program. Start", lat, '/', lng);
+
+ FileSystemParam params = new FileSystemParam();
+ params.setBlockSize(512);
+ params.setMapDescription("OSM street map");
+
+ Map map;
+ try {
+ map = Map.createMap("32860003", ".", params, "32860003", Sort.defaultSort(1252));
+ } catch (FileExistsException e) {
+ throw new ExitException("File exists already", e);
+ } catch (FileNotWritableException e) {
+ throw new ExitException("Could not create or write file", e);
+ }
+ map.addInfo("Program released under the GPL");
+ map.addInfo("This map data is made available under the Open Database License:");
+
+ // There has to be (at least) two copyright messages or else the map
+ // does not show up. The second one will be displayed at startup,
+ // although the conditions where that happens are not known.
+ map.addCopyright("program licenced under GPL v2");
+
+ // This one gets shown when you switch on, so put the actual
+ // map copyright here. This is made up data, so no copyright applies.
+ map.addCopyright("No copyright");
+
+ Area area = new Area(lat, lng, lat + 1, lng + 1);
+ map.setBounds(area);
+
+ // There must always be an empty zoom level at the least detailed level.
+ log.info("area " + area);
+ log.info(" or " + lat + '/' + lng);
+
+ Zoom z1 = map.createZoom(1, 24);
+ Subdivision topdiv = map.topLevelSubdivision(area, z1);
+
+ // Create a most detailed view
+ Zoom z = map.createZoom(0, 24);
+ Subdivision div = map.createSubdivision(topdiv, area, z);
+
+ div.startDivision();
+
+ drawTestMap(map, div, lat, lng);
+
+ map.close();
+ }
+
+ protected abstract void drawTestMap(Map map, Subdivision div, double lat, double lng);
+
+}
diff --git a/src/uk/me/parabola/mkgmap/main/Main.java b/src/uk/me/parabola/mkgmap/main/Main.java
new file mode 100644
index 0000000..c487f6b
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/main/Main.java
@@ -0,0 +1,640 @@
+/*
+ * Copyright (C) 2007 - 2012.
+ *
+ * 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.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import uk.me.parabola.imgfmt.ExitException;
+import uk.me.parabola.imgfmt.MapFailedException;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.ArgumentProcessor;
+import uk.me.parabola.mkgmap.CommandArgs;
+import uk.me.parabola.mkgmap.CommandArgsReader;
+import uk.me.parabola.mkgmap.Version;
+import uk.me.parabola.mkgmap.combiners.Combiner;
+import uk.me.parabola.mkgmap.combiners.FileInfo;
+import uk.me.parabola.mkgmap.combiners.GmapsuppBuilder;
+import uk.me.parabola.mkgmap.combiners.MdrBuilder;
+import uk.me.parabola.mkgmap.combiners.MdxBuilder;
+import uk.me.parabola.mkgmap.combiners.NsisBuilder;
+import uk.me.parabola.mkgmap.combiners.OverviewBuilder;
+import uk.me.parabola.mkgmap.combiners.OverviewMap;
+import uk.me.parabola.mkgmap.combiners.TdbBuilder;
+import uk.me.parabola.mkgmap.osmstyle.StyleFileLoader;
+import uk.me.parabola.mkgmap.osmstyle.StyleImpl;
+import uk.me.parabola.mkgmap.reader.osm.Style;
+import uk.me.parabola.mkgmap.reader.osm.StyleInfo;
+import uk.me.parabola.mkgmap.reader.overview.OverviewMapDataSource;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+import uk.me.parabola.mkgmap.srt.SrtTextReader;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * The new main program. There can be many file names to process and there can
+ * be differing outputs determined by options. So the actual work is mostly
+ * done in other classes. This one just works out what is wanted.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Main implements ArgumentProcessor {
+ private static final Logger log = Logger.getLogger(Main.class);
+
+ // Final .img file combiners.
+ private final List<Combiner> combiners = new ArrayList<Combiner>();
+
+ private final Map<String, MapProcessor> processMap = new HashMap<String, MapProcessor>();
+ private String styleFile = "classpath:styles";
+ private String styleOption;
+ private boolean verbose;
+
+ private final List<FilenameTask> futures = new LinkedList<FilenameTask>();
+ private ExecutorService threadPool;
+ // default number of threads
+ private int maxJobs = 1;
+
+ private boolean createTdbFiles = false;
+ private boolean tdbBuilderAdded = false;
+ // used for messages in listStyles and checkStyles
+ private String searchedStyleName;
+
+ /**
+ * The main program to make or combine maps. We now use a two pass process,
+ * first going through the arguments and make any maps and collect names
+ * to be used for creating summary files like the TDB and gmapsupp.
+ *
+ * @param args The command line arguments.
+ */
+ public static void main(String[] args) {
+ long start = System.currentTimeMillis();
+ System.out.println("Time started: " + new Date());
+ // We need at least one argument.
+ if (args.length < 1) {
+ printUsage();
+ printHelp(System.err, getLang(), "options");
+ return;
+ }
+
+ Main mm = new Main();
+
+ try {
+ // Read the command line arguments and process each filename found.
+ CommandArgsReader commandArgs = new CommandArgsReader(mm);
+ commandArgs.setValidOptions(getValidOptions(System.err));
+ commandArgs.readArgs(args);
+ } catch (MapFailedException e) {
+ System.err.println(e.getMessage());
+ } catch (ExitException e) {
+ System.err.println(e.getMessage());
+ }
+ System.out.println("Time finished: " + new Date());
+ System.out.println("Total time taken: " + (System.currentTimeMillis() - start) + "ms");
+ }
+
+ private static void printUsage (){
+ System.err.println("Usage: mkgmap [options...] <file.osm>");
+ }
+
+ /**
+ * Grab the options help file and print it.
+ * @param err The output print stream to write to.
+ * @param lang A language hint. The help will be displayed in this
+ * language if it has been translated.
+ * @param file The help file to display.
+ */
+ private static void printHelp(PrintStream err, String lang, String file) {
+ String path = "/help/" + lang + '/' + file;
+ InputStream stream = Main.class.getResourceAsStream(path);
+ if (stream == null) {
+ err.println("Could not find the help topic: " + file + ", sorry");
+ return;
+ }
+
+ BufferedReader r = new BufferedReader(new InputStreamReader(stream));
+ try {
+ String line;
+ while ((line = r.readLine()) != null)
+ err.println(line);
+ } catch (IOException e) {
+ err.println("Could not read the help topic: " + file + ", sorry");
+ }
+ }
+
+ private static Set<String> getValidOptions(PrintStream err) {
+ String path = "/help/en/options";
+ InputStream stream = Main.class.getResourceAsStream(path);
+ if (stream == null)
+ return null;
+
+ Set<String> result = new HashSet<String>();
+ try {
+ BufferedReader r = new BufferedReader(new InputStreamReader(stream, "utf-8"));
+
+ Pattern p = Pattern.compile("^--?([a-zA-Z0-9-]*).*$");
+ String line;
+ while ((line = r.readLine()) != null) {
+ Matcher matcher = p.matcher(line);
+ if (matcher.matches()) {
+ String opt = matcher.group(1);
+ result.add(opt);
+ }
+ }
+ } catch (IOException e) {
+ err.println("Could not read valid optoins");
+ return null;
+ }
+
+ return result;
+ }
+
+ public void startOptions() {
+ MapProcessor saver = new NameSaver();
+ processMap.put("img", saver);
+ processMap.put("mdx", saver);
+
+ processMap.put("typ", new TypSaver());
+
+ // Normal map files.
+ processMap.put("rgn", saver);
+ processMap.put("tre", saver);
+ processMap.put("lbl", saver);
+ processMap.put("net", saver);
+ processMap.put("nod", saver);
+
+ processMap.put("txt", new TypCompiler());
+ }
+
+ /**
+ * Switch out to the appropriate class to process the filename.
+ */
+ public void processFilename(final CommandArgs args, final String filename) {
+
+ final String ext = extractExtension(filename);
+ log.debug("file", filename, ", extension is", ext);
+ // ignore ovm_* files given as command line arguments
+ if (OverviewBuilder.isOverviewImg(filename))
+ return;
+
+ final MapProcessor mp = mapMaker(ext);
+
+ args.setSort(getSort(args));
+
+ log.info("Submitting job " + filename);
+ FilenameTask task = new FilenameTask(new Callable<String>() {
+ public String call() {
+ log.threadTag(filename);
+ if (filename.startsWith("test-map:") || new File(filename).exists()){
+ String output = mp.makeMap(args, filename);
+ log.debug("adding output name", output);
+ log.threadTag(null);
+ return output;
+ } else {
+ log.error("file " + filename + " doesn't exist");
+ return null;
+ }
+ }
+ });
+ task.setArgs(args);
+ futures.add(task);
+ }
+
+ private MapProcessor mapMaker(String ext) {
+ MapProcessor mp = processMap.get(ext);
+ if (mp == null)
+ mp = new MapMaker(createTdbFiles);
+ return mp;
+ }
+
+ public void processOption(String opt, String val) {
+ log.debug("option:", opt, val);
+
+ if (opt.equals("number-of-files")) {
+
+ // This option always appears first. We use it to turn on/off
+ // generation of the overview files if there is only one file
+ // to process.
+ int n = Integer.valueOf(val);
+ if (n > 0) // TODO temporary, this option will become properly default of on.
+ createTdbFiles = true;
+
+ } else if (opt.equals("help")) {
+ printHelp(System.out, getLang(), (!val.isEmpty()) ? val : "help");
+ } else if (opt.equals("style-file") || opt.equals("map-features")) {
+ styleFile = val;
+ } else if (opt.equals("style")) {
+ styleOption = val;
+ } else if (opt.equals("verbose")) {
+ verbose = true;
+ } else if (opt.equals("list-styles")) {
+ listStyles();
+ } else if (opt.equals("check-styles")) {
+ checkStyles();
+ } else if (opt.equals("max-jobs")) {
+ if (val.isEmpty())
+ maxJobs = Runtime.getRuntime().availableProcessors();
+ else
+ maxJobs = Integer.parseInt(val);
+ if(maxJobs < 1) {
+ log.warn("max-jobs has to be at least 1");
+ maxJobs = 1;
+ }
+ } else if (opt.equals("version")) {
+ System.err.println(Version.VERSION);
+ System.exit(0);
+ }
+ }
+
+ public void removeOption(String opt) {
+ if ("tdbfile".equals(opt))
+ createTdbFiles = false;
+ }
+
+ /**
+ * Add the builders for the TDB and overview map. These are always
+ * generated together as we use some info that is calculated when constructing
+ * the overview map in the TDB file.
+ */
+ private void addTdbBuilder() {
+ if (!tdbBuilderAdded ){
+ OverviewMap overviewSource = new OverviewMapDataSource();
+ OverviewBuilder overviewBuilder = new OverviewBuilder(overviewSource);
+ addCombiner(overviewBuilder);
+ TdbBuilder tdbBuilder = new TdbBuilder(overviewBuilder);
+ addCombiner(tdbBuilder);
+ tdbBuilderAdded = true;
+ }
+ }
+
+ private void listStyles() {
+ String[] names;
+ try {
+ StyleFileLoader loader = StyleFileLoader.createStyleLoader(styleFile, null);
+ names = loader.list();
+ loader.close();
+ } catch (FileNotFoundException e) {
+ log.debug("didn't find style file", e);
+ throw new ExitException("Could not list style file " + styleFile);
+ }
+
+ Arrays.sort(names);
+ System.out.println("The following styles are available:");
+ for (String name : names) {
+ Style style = readOneStyle(name, false);
+ if (style == null)
+ continue;
+ StyleInfo info = style.getInfo();
+ System.out.format("%-15s %6s: %s\n",
+ searchedStyleName,info.getVersion(), info.getSummary());
+ if (verbose) {
+ for (String s : info.getLongDescription().split("\n"))
+ System.out.printf("\t%s\n", s.trim());
+ }
+ }
+ }
+
+ /**
+ * Check one or all styles in the path given in styleFile.
+ */
+ private void checkStyles() {
+ String[] names;
+ int checked = 0;
+ try {
+ StyleFileLoader loader = StyleFileLoader.createStyleLoader(styleFile, null);
+ names = loader.list();
+ loader.close();
+ } catch (FileNotFoundException e) {
+ log.debug("didn't find style file", e);
+ throw new ExitException("Could not check style file " + styleFile);
+ }
+
+ Arrays.sort(names);
+
+ if (styleOption == null){
+ if (names.length > 1)
+ System.out.println("The following styles are available:");
+ else
+ System.out.println("Found one style in " + styleFile);
+ }
+ for (String name : names) {
+ if (styleOption != null && name.equals(styleOption) == false)
+ continue;
+ if (names.length > 1){
+ System.out.println("checking style: " + name);
+ }
+ ++checked;
+ boolean performChecks = true;
+ if ("classpath:styles".equals(styleFile) && "default".equals(name) == false){
+ performChecks = false;
+ }
+ Style style = readOneStyle(name, performChecks);
+ if (style == null){
+ System.out.println("could not open style " + name);
+ }
+ }
+ if (checked == 0)
+ System.out.println("could not open style " + styleOption + " in " + styleFile );
+ System.out.println("finished check-styles");
+ }
+
+ /**
+ * Try to read a style from styleFile directory
+ * @param name name of the style
+ * @param performChecks perform checks?
+ * @return the style or null in case of errors
+ */
+ private Style readOneStyle(String name, boolean performChecks){
+ Style style = null;
+ searchedStyleName = name;
+ try {
+ style = new StyleImpl(styleFile, name, new EnhancedProperties(), performChecks);
+ } catch (SyntaxException e) {
+ System.err.println("Error in style: " + e.getMessage());
+ } catch (FileNotFoundException e) {
+ log.debug("could not find style", name);
+ try {
+ searchedStyleName = new File(styleFile).getName();
+ style = new StyleImpl(styleFile, null, new EnhancedProperties(), performChecks);
+ } catch (SyntaxException e1) {
+ System.err.println("Error in style: " + e1.getMessage());
+ } catch (FileNotFoundException e1) {
+ log.debug("could not find style", styleFile);
+ }
+ }
+ return style;
+ }
+
+ private static String getLang() {
+ return "en";
+ }
+
+ private void addCombiner(Combiner combiner) {
+ combiners.add(combiner);
+ }
+
+ public void endOptions(CommandArgs args) {
+ fileOptions(args);
+
+ log.info("Start tile processors");
+ if (threadPool == null) {
+ log.info("Creating thread pool with " + maxJobs + " threads");
+ threadPool = Executors.newFixedThreadPool(maxJobs);
+ }
+
+ // process all input files
+ for (FilenameTask task : futures) {
+ threadPool.execute(task);
+ }
+
+
+ List<FilenameTask> filenames = new ArrayList<FilenameTask>();
+
+ if (threadPool != null) {
+ threadPool.shutdown();
+ while (!futures.isEmpty()) {
+ try {
+ try {
+ // don't call get() until a job has finished
+ if (futures.get(0).isDone()) {
+ FilenameTask future = futures.remove(0);
+
+ // Provoke any exceptions by calling get and then
+ // save the result for later use
+ future.setFilename(future.get());
+ filenames.add(future);
+ } else
+ Thread.sleep(100);
+ } catch (ExecutionException e) {
+ // Re throw the underlying exception
+ Throwable cause = e.getCause();
+ if (cause instanceof Exception)
+ //noinspection ProhibitedExceptionThrown
+ throw (Exception) cause;
+ else if (cause instanceof Error)
+ //noinspection ProhibitedExceptionThrown
+ throw (Error) cause;
+ else
+ throw e;
+ }
+ } catch (ExitException ee) {
+ throw ee;
+ } catch (MapFailedException mfe) {
+ System.err.println(mfe.getMessage());
+ } catch (Throwable t) {
+ t.printStackTrace();
+ if (!args.getProperties().getProperty("keep-going", false)) {
+ throw new ExitException("Exiting - if you want to carry on regardless, use the --keep-going option");
+ }
+ }
+ }
+ }
+
+ if (combiners.isEmpty())
+ return;
+ boolean hasFiles = false;
+ for (FilenameTask file : filenames) {
+ if (file == null || file.isCancelled() || file.getFilename() == null){
+ if (args.getProperties().getProperty("keep-going", false))
+ continue;
+ else
+ throw new ExitException("Exiting - if you want to carry on regardless, use the --keep-going option");
+ }
+ hasFiles = true;
+ }
+ if (!hasFiles){
+ log.warn("nothing to do for combiners.");
+ return;
+ }
+ log.info("Combining maps");
+
+ args.setSort(getSort(args));
+
+ // Get them all set up.
+ for (Combiner c : combiners)
+ c.init(args);
+
+ // will contain img files for which an additional ovm file was found
+ HashSet<String> foundOvmFiles = new HashSet<String>();
+ // try OverviewBuilder with special files
+ if (tdbBuilderAdded){
+ for (FilenameTask file : filenames) {
+ if (file == null || file.isCancelled())
+ continue;
+
+ try {
+ String fileName = file.getFilename();
+ if (fileName.endsWith(".img") == false)
+ continue;
+ fileName = OverviewBuilder.getOverviewImgName(fileName);
+ log.info(" " + fileName);
+ FileInfo fileInfo = FileInfo.getFileInfo(fileName);
+ fileInfo.setArgs(file.getArgs());
+ // add the real input file
+ foundOvmFiles.add(file.getFilename());
+ for (Combiner c : combiners){
+ if (c instanceof OverviewBuilder)
+ c.onMapEnd(fileInfo);
+ }
+ } catch (FileNotFoundException e) {
+ }
+ }
+ }
+
+ // Tell them about each filename (OverviewBuilder excluded)
+ for (FilenameTask file : filenames) {
+ if (file == null || file.isCancelled())
+ continue;
+
+ try {
+ log.info(" " + file);
+ FileInfo fileInfo = FileInfo.getFileInfo(file.getFilename());
+ fileInfo.setArgs(file.getArgs());
+ for (Combiner c : combiners){
+ if (c instanceof OverviewBuilder && foundOvmFiles.contains(file.getFilename()))
+ continue;
+ c.onMapEnd(fileInfo);
+ }
+ } catch (FileNotFoundException e) {
+ throw new MapFailedException("could not open file " + e.getMessage());
+ }
+ }
+
+
+ // All done, allow tidy up or file creation to happen
+ for (Combiner c : combiners)
+ c.onFinish();
+
+ if (tdbBuilderAdded && args.getProperties().getProperty("remove-ovm-work-files", false)){
+ for (String fName:foundOvmFiles){
+ String ovmFile = OverviewBuilder.getOverviewImgName(fName);
+ log.info("removing " + ovmFile);
+ new File(ovmFile).delete();
+ }
+ }
+ }
+
+ private void fileOptions(CommandArgs args) {
+ boolean indexOpt = args.exists("index");
+ boolean gmapOpt = args.exists("gmapsupp");
+ boolean tdbOpt = args.exists("tdbfile");
+ if (tdbOpt || createTdbFiles){
+ addTdbBuilder();
+ }
+ if (args.exists("nsis")) {
+ addCombiner(new NsisBuilder());
+ }
+ if (gmapOpt) {
+ GmapsuppBuilder gmapBuilder = new GmapsuppBuilder();
+ gmapBuilder.setCreateIndex(indexOpt);
+
+ addCombiner(gmapBuilder);
+ }
+
+ if (indexOpt && (tdbOpt || !gmapOpt)) {
+ addCombiner(new MdrBuilder());
+ addCombiner(new MdxBuilder());
+ }
+ }
+
+ /**
+ * Get the extension of the filename, ignoring any compression suffix.
+ *
+ * @param filename The original filename.
+ * @return The file extension.
+ */
+ private String extractExtension(String filename) {
+ String[] parts = filename.toLowerCase(Locale.ENGLISH).split("\\.");
+ List<String> ignore = Arrays.asList("gz", "bz2", "bz");
+
+ // We want the last part that is not gz, bz etc (and isn't the first part ;)
+ for (int i = parts.length - 1; i > 0; i--) {
+ String ext = parts[i];
+ if (!ignore.contains(ext))
+ return ext;
+ }
+ return "";
+ }
+
+ /**
+ * Create the sort description for the map. This is used to sort items in the files
+ * and also is converted into a SRT file which is included in the MDR file.
+ *
+ * We simply use the code page to locate a sorting description, but it would be possible to
+ * specify the sort separately.
+ *
+ * @return A sort description object.
+ */
+ public Sort getSort(CommandArgs args) {
+ return SrtTextReader.sortForCodepage(args.getCodePage());
+ }
+
+ /**
+ * A null implementation that just returns the input name as the output.
+ */
+ private static class NameSaver implements MapProcessor {
+ public String makeMap(CommandArgs args, String filename) {
+ return filename;
+ }
+ }
+
+ private static class FilenameTask extends FutureTask<String> {
+ private CommandArgs args;
+ private String filename;
+
+ private FilenameTask(Callable<String> callable) {
+ super(callable);
+ }
+
+ public void setArgs(CommandArgs args) {
+ this.args = args;
+ }
+
+ public CommandArgs getArgs() {
+ return args;
+ }
+
+ public void setFilename(String filename) {
+ this.filename = filename;
+ }
+
+ public String getFilename() {
+ return filename;
+ }
+
+ public String toString() {
+ return filename;
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/main/MakeTestLangMap.java b/src/uk/me/parabola/mkgmap/main/MakeTestLangMap.java
new file mode 100644
index 0000000..3547091
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/main/MakeTestLangMap.java
@@ -0,0 +1,87 @@
+/*
+ * 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: 13-Jan-2007
+ */
+package uk.me.parabola.mkgmap.main;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.map.Map;
+import uk.me.parabola.imgfmt.app.trergn.Polyline;
+import uk.me.parabola.imgfmt.app.trergn.PolylineOverview;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+
+/**
+ * A test map for language support. It has a series of roads all with names
+ * that use the whole of the character set.
+ *
+ * Each 'road name' will contain a number of characters above 0x80. The name
+ * will start with a number that is the first non-ascii character in the name
+ * then the characters will be interspaced with the letters a, b, c, d, etc.
+ *
+ * Its probably easier just to look at it.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MakeTestLangMap extends AbstractTestMap {
+
+ public static void main(String[] args) {
+ MakeTestLangMap tm = new MakeTestLangMap();
+ tm.makeMap(args);
+ }
+
+ protected void drawTestMap(Map map, Subdivision div, double lat, double lng) {
+ drawStreetnames(map, div, lat, lng);
+ }
+
+ private void drawStreetnames(Map map, Subdivision div, double slat, double slon) {
+
+ char[] hexChars = "0123456789ABCDEF".toCharArray();
+
+ double lat = slat + 0.004;
+ double lon = slon + 0.002;
+
+ div.startLines();
+
+ map.setLabelCharset("simple8", true);
+
+ double space = 0.002;
+ double size = 0.006;for (int y = 0; y < 16; y++) {
+
+ int start = 128 + 8*y;
+
+ char[] out = new char[19];
+ out[0] = hexChars[(start & 0xf0) >> 4];
+ out[1] = hexChars[(start & 0x0f)];
+ out[2] = ' ';
+
+ for (int i = 0; i < 8; i++) {
+ out[3 + 2 * i] = (char) ('A' + i);
+ out[3 + 2 * i + 1] = (char) (start + i);
+ }
+
+ String name = new String(out);
+ Polyline l = div.createLine(new String[]{name, null, null, null});
+ double baseLat = lat + y * space;
+ Coord co = new Coord(baseLat, lon);
+ l.addCoord(co);
+ co = new Coord(baseLat, lon + size);
+ l.addCoord(co);
+
+ l.setType(6);
+ map.addMapObject(l);
+ }
+ map.addPolylineOverview(new PolylineOverview(0x600, 10));
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/main/MapMaker.java b/src/uk/me/parabola/mkgmap/main/MapMaker.java
new file mode 100644
index 0000000..f56f79a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/main/MapMaker.java
@@ -0,0 +1,332 @@
+/*
+ * 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.main;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.FileExistsException;
+import uk.me.parabola.imgfmt.FileNotWritableException;
+import uk.me.parabola.imgfmt.FileSystemParam;
+import uk.me.parabola.imgfmt.FormatException;
+import uk.me.parabola.imgfmt.MapFailedException;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.map.Map;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.srt.SortKey;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.CommandArgs;
+import uk.me.parabola.mkgmap.build.MapBuilder;
+import uk.me.parabola.mkgmap.combiners.OverviewBuilder;
+import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapPoint;
+import uk.me.parabola.mkgmap.general.MapRoad;
+import uk.me.parabola.mkgmap.reader.plugin.MapReader;
+
+/**
+ * Main routine for the command line map-making utility.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MapMaker implements MapProcessor {
+ private static final Logger log = Logger.getLogger(MapMaker.class);
+ private Sort sort;
+ private final boolean createOverviewFiles;
+
+ public MapMaker(boolean createOverviewFiles) {
+ this.createOverviewFiles = createOverviewFiles;
+ }
+
+ public String makeMap(CommandArgs args, String filename) {
+ try {
+ LoadableMapDataSource src = loadFromFile(args, filename);
+ sort = args.getSort();
+ log.info("Making Road Name POIs for", filename);
+ makeRoadNamePOIS(args, src);
+ if (createOverviewFiles){
+ if (src.overviewMapLevels() != null){
+ makeMap(args, src, OverviewBuilder.OVERVIEW_PREFIX);
+ } else {
+ String fname = OverviewBuilder.getOverviewImgName(args.getMapname());
+ File f = new File(fname);
+ if (f.exists()) {
+ if (f.isFile() )
+ f.delete();
+ else {
+ // TODO: error message ?
+ }
+ }
+ }
+ }
+ return makeMap(args, src, "");
+ } catch (FormatException e) {
+ System.err.println("Bad file format: " + filename);
+ System.err.println(e.getMessage());
+ return filename;
+ } catch (FileNotFoundException e) {
+ System.err.println("Could not open file: " + filename);
+ return filename;
+ }
+ }
+
+ /**
+ * Make a map from the given map data source.
+ *
+ * @param args User supplied arguments.
+ * @param src The data source to load.
+ * @param mapNameExt
+ * @return The output filename for the map.
+ */
+ private String makeMap(CommandArgs args, LoadableMapDataSource src, String mapNamePrefix) {
+
+ if (src.getBounds().isEmpty())
+ return null;
+
+ FileSystemParam params = new FileSystemParam();
+ params.setBlockSize(args.getBlockSize());
+ params.setMapDescription(args.getDescription());
+ log.info("Started making", args.getMapname(), "(" + args.getDescription() + ")");
+ try {
+ Map map = Map.createMap(mapNamePrefix + args.getMapname(), args.getOutputDir(), params, args.getMapname(), sort);
+ setOptions(map, args);
+
+ MapBuilder builder = new MapBuilder();
+ builder.config(args.getProperties());
+ if (args.getProperties().getProperty("route", false)){
+ if(! OverviewBuilder.OVERVIEW_PREFIX.equals(mapNamePrefix))
+ builder.setDoRoads(true);
+ }
+ builder.makeMap(map, src);
+
+ // Collect information on map complete.
+ String outName = map.getFilename();
+ log.info("finished making map", outName, "closing");
+ map.close();
+ return outName;
+ } catch (FileExistsException e) {
+ throw new MapFailedException("File exists already", e);
+ } catch (FileNotWritableException e) {
+ throw new MapFailedException("Could not create or write to file", e);
+ }
+ }
+
+ /**
+ * Set options from the command line.
+ *
+ * @param map The map to modify.
+ * @param args The command line arguments.
+ */
+ private void setOptions(Map map, CommandArgs args) {
+ map.config(args.getProperties());
+
+ String s = args.getCharset();
+ if (s != null)
+ map.setLabelCharset(s, args.isForceUpper());
+
+ Sort sort = args.getSort();
+ map.setSort(sort);
+ }
+
+ /**
+ * Load up from the file. It is not necessary for the map reader to completely
+ * read the whole file in at once, it could pull in map-features as needed.
+ *
+ * @param args The user supplied parameters.
+ * @param name The filename or resource name to be read.
+ * @return A LoadableMapDataSource that will be used to construct the map.
+ * @throws FileNotFoundException For non existing files.
+ * @throws FormatException When the file format is not valid.
+ */
+ private LoadableMapDataSource loadFromFile(CommandArgs args, String name) throws
+ FileNotFoundException, FormatException
+ {
+ LoadableMapDataSource src = MapReader.createMapReader(name);
+ src.config(args.getProperties());
+ log.info("Started loading", name);
+ src.load(name);
+ log.info("Finished loading", name);
+ return src;
+ }
+
+ void makeRoadNamePOIS(CommandArgs args, LoadableMapDataSource src) {
+ String rnp = args.get("road-name-pois", null);
+ // are road name POIS wanted?
+ if(rnp != null) {
+ rnp = rnp.toUpperCase();
+ int rnpt = 0x640a; // Garmin type 'Locale'
+ if(rnp.length() > 0) {
+ // override type code
+ rnpt = Integer.decode(rnp);
+ }
+ // collect lists of roads that have the same name
+ java.util.Map<String, List<MapRoad>> namedRoads = new HashMap<String, List<MapRoad>>();
+ for(MapLine l : src.getLines()) {
+ if(l.isRoad()) {
+ MapRoad r = (MapRoad)l;
+ String rn = r.getName();
+ if(rn != null) {
+ List<MapRoad> rl = namedRoads.get(rn);
+ if(rl == null) {
+ rl = new ArrayList<MapRoad>();
+ namedRoads.put(rn, rl);
+ }
+ rl.add(r);
+ }
+ }
+ }
+
+ // generate a POI for each named road
+
+ // sort by name and coordinate of first point so that
+ // the order is always the same for the same input
+ List<SortKey<MapRoad>> rnpRoads = new ArrayList<SortKey<MapRoad>>();
+ for(List<MapRoad> lr : findConnectedRoadsWithSameName(namedRoads)) {
+ // connected roads are not ordered so just use first in list
+ MapRoad r = lr.get(0);
+ String key = r.getName();
+ List<Coord> points = r.getPoints();
+ if(!points.isEmpty())
+ key += "_" + points.get(0);
+ rnpRoads.add(sort.createSortKey(r, key));
+ }
+ Collections.sort(rnpRoads);
+ for(SortKey<MapRoad> sr : rnpRoads)
+ src.getPoints().add(makeRoadNamePOI(sr.getObject(), rnpt));
+ }
+ }
+
+ private boolean roadsAreJoined(MapLine r1, MapLine r2) {
+ if (r1.getBounds().intersects(r2.getBounds()) == false) {
+ return false;
+ }
+
+ if(r1 != r2) {
+ for(Coord c1 : r1.getPoints()) {
+ for(Coord c2 : r2.getPoints()) {
+ if(c1 == c2 || c1.equals(c2))
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ // hairy function to build a set of lists - each list contains
+ // the roads that have the same name and are connected
+
+ private Set<List<MapRoad>> findConnectedRoadsWithSameName(java.util.Map<String, List<MapRoad>> namedRoads) {
+ // roadGroups is a set to avoid duplicate groups
+ Set<List<MapRoad>> roadGroups = new HashSet<List<MapRoad>>();
+
+ // loop over the lists of roads that have the same name
+ for(List<MapRoad> allRoadsWithSameName : namedRoads.values()) {
+ // for each road that has the same name, keep track of its group
+ java.util.Map<MapRoad,List<MapRoad>> roadGroupMap = new HashMap<MapRoad,List<MapRoad>>();
+
+ // loop over all of the roads with the same name
+ for(int i = 0; i < allRoadsWithSameName.size(); ++i) {
+ boolean roadWasJoined = false;
+ for(int j = 0; j < allRoadsWithSameName.size(); ++j) {
+ if(i != j) {
+ // see if these two roads are joined
+ MapRoad ri = allRoadsWithSameName.get(i);
+ MapRoad rj = allRoadsWithSameName.get(j);
+ if(roadsAreJoined(ri, rj)) {
+ // yes, they are joined so put both in a group
+ // and associate the group with each road
+ roadWasJoined = true;
+ List<MapRoad> groupi = roadGroupMap.get(ri);
+ List<MapRoad> groupj = roadGroupMap.get(rj);
+ if(groupi == null) {
+ // ri is not in a group yet
+ if(groupj == null) {
+ // neither is rj so make a new group
+ groupi = new ArrayList<MapRoad>();
+ groupi.add(ri);
+ groupi.add(rj);
+ roadGroupMap.put(ri, groupi);
+ roadGroupMap.put(rj, groupi);
+ }
+ else {
+ // add ri to groupj
+ groupj.add(ri);
+ roadGroupMap.put(ri, groupj);
+ }
+ }
+ else if(groupj == null) {
+ // add rj to groupi
+ groupi.add(rj);
+ roadGroupMap.put(rj, groupi);
+ }
+ else if(groupi != groupj) {
+ // ri and rj are in separate groups so put
+ // all the roads in groupj into groupi
+ for(MapRoad r : groupj)
+ roadGroupMap.put(r, groupi);
+ groupi.addAll(groupj);
+ }
+ }
+ }
+ }
+ if(!roadWasJoined) {
+ // make a group with just one entry
+ MapRoad ri = allRoadsWithSameName.get(i);
+ List<MapRoad>group = new ArrayList<MapRoad>();
+ group.add(ri);
+ roadGroupMap.put(ri, group);
+ }
+ }
+
+ // now add the new group(s) to the final result
+ for(List<MapRoad> r : roadGroupMap.values())
+ roadGroups.add(r);
+ }
+ return roadGroups;
+ }
+
+ private MapPoint makeRoadNamePOI(MapRoad road, int type) {
+ List<Coord> points = road.getPoints();
+ int numPoints = points.size();
+ Coord coord;
+ if ((numPoints & 1) == 0) {
+ int i2 = numPoints / 2;
+ int i1 = i2 - 1;
+ coord = new Coord((points.get(i1).getLatitude() +
+ points.get(i2).getLatitude()) / 2,
+ (points.get(i1).getLongitude() +
+ points.get(i2).getLongitude()) / 2);
+ } else {
+ coord = points.get(numPoints / 2);
+ }
+
+ String name = road.getName();
+ MapPoint rnp = new MapPoint();
+
+ rnp.setName(name);
+ rnp.setRoadNamePOI(true);
+ rnp.setType(type);
+ rnp.setLocation(coord);
+ return rnp;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/main/MapProcessor.java b/src/uk/me/parabola/mkgmap/main/MapProcessor.java
new file mode 100644
index 0000000..07baeb5
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/main/MapProcessor.java
@@ -0,0 +1,37 @@
+/*
+ * 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: 29-Sep-2007
+ */
+package uk.me.parabola.mkgmap.main;
+
+import uk.me.parabola.mkgmap.CommandArgs;
+
+/**
+ * Different options that can be supplied that change the mode and operation
+ * of the program.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface MapProcessor {
+
+ /**
+ * Make a map from the given input filename and options.
+ *
+ * @param args The options that are in force.
+ * @param filename The input filename.
+ * @return The output filename; the name of the file that was created.
+ */
+ public String makeMap(CommandArgs args, String filename);
+}
diff --git a/src/uk/me/parabola/mkgmap/main/StyleTester.java b/src/uk/me/parabola/mkgmap/main/StyleTester.java
new file mode 100644
index 0000000..ac655c8
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/main/StyleTester.java
@@ -0,0 +1,863 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Formatter;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import uk.me.parabola.imgfmt.FormatException;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.CoordNode;
+import uk.me.parabola.imgfmt.app.net.RoadDef;
+import uk.me.parabola.mkgmap.general.LevelInfo;
+import uk.me.parabola.mkgmap.general.MapCollector;
+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.MapRoad;
+import uk.me.parabola.mkgmap.general.MapShape;
+import uk.me.parabola.mkgmap.osmstyle.ActionRule;
+import uk.me.parabola.mkgmap.osmstyle.ExpressionRule;
+import uk.me.parabola.mkgmap.osmstyle.StyleFileLoader;
+import uk.me.parabola.mkgmap.osmstyle.StyleImpl;
+import uk.me.parabola.mkgmap.osmstyle.StyledConverter;
+import uk.me.parabola.mkgmap.osmstyle.TypeReader;
+import uk.me.parabola.mkgmap.osmstyle.actions.ActionList;
+import uk.me.parabola.mkgmap.osmstyle.actions.ActionReader;
+import uk.me.parabola.mkgmap.osmstyle.eval.ExpressionReader;
+import uk.me.parabola.mkgmap.osmstyle.eval.Op;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.ElementSaver;
+import uk.me.parabola.mkgmap.reader.osm.FeatureKind;
+import uk.me.parabola.mkgmap.reader.osm.GType;
+import uk.me.parabola.mkgmap.reader.osm.Node;
+import uk.me.parabola.mkgmap.reader.osm.OsmConverter;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.Rule;
+import uk.me.parabola.mkgmap.reader.osm.Style;
+import uk.me.parabola.mkgmap.reader.osm.TypeResult;
+import uk.me.parabola.mkgmap.reader.osm.WatchableTypeResult;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.mkgmap.reader.osm.xml.Osm5XmlHandler;
+import uk.me.parabola.mkgmap.reader.osm.xml.Osm5XmlHandler.SaxHandler;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+import uk.me.parabola.mkgmap.scan.Token;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+import uk.me.parabola.util.EnhancedProperties;
+
+import org.xml.sax.SAXException;
+
+
+/**
+ * Test style rules by converting to a text format, rather than a .img file.
+ * In addition you can specify a .osm file and a style file separately.
+ *
+ * <h2>Single test file</h2>
+ * The format of the file is as follows
+ *
+ * <pre>
+ * WAY 42
+ * highway=primary
+ * oneway=reverse
+ *
+ * <<<lines>>>
+ * highway=primary [0x3 road_class=2 road_speed=2]
+ * power=line [0x29 resolution 20]
+ * </pre>
+ *
+ * You can have any number of ways, each must end with a blank line.
+ * A way will be created with two points (1,1),(2,2) (so you can see the
+ * action of oneway=reverse) and the tags that you specify. If you give
+ * a number after WAY it will be printed on output so that if you have more
+ * than one you can tell which is which. If the number is omitted it will
+ * default to 1.
+ *
+ * You can have as many rules as you like after the <<<lines>>> and you
+ * can include any other style files such as <<<options>>> or <<<info>>> if
+ * you like.
+ *
+ * <h2>osm file mode</h2>
+ * Takes two arguments, first the style file and then the osm file.
+ *
+ * You can give a --reference flag and it will run style file in reference mode,
+ * that is each rule will be applied to the element without any attempt at
+ * optimisation. This acts as an independent check of the main style code
+ * which may have more optimisations.
+ *
+ * @author Steve Ratcliffe
+ */
+public class StyleTester implements OsmConverter {
+ private static final Pattern SPACES_PATTERN = Pattern.compile(" +");
+ private static final Pattern EQUAL_PATTERN = Pattern.compile("=");
+
+ private static final String STYLETESTER_STYLE = "styletester.style";
+
+ private static PrintStream out = System.out;
+ private static boolean reference;
+
+ private final OsmConverter converter;
+
+ // The file may contain a known good set of results. They are saved here
+ private final List<String> givenResults = new ArrayList<String>();
+ private static boolean forceUseOfGiven;
+ private static boolean showMatches;
+ private static boolean print = true;
+
+ private StyleTester(String stylefile, MapCollector coll, boolean reference) throws FileNotFoundException {
+ if (reference)
+ converter = makeStrictStyleConverter(stylefile, coll);
+ else
+ converter = makeStyleConverter(stylefile, coll);
+ }
+
+ public static void main(String[] args) throws IOException {
+ String[] a = processOptions(args);
+ if (a.length == 1)
+ runSimpleTest(a[0]);
+ else
+ runTest(a[0], a[1]);
+ }
+
+ public static void setOut(PrintStream out) {
+ StyleTester.out = out;
+ }
+
+ private static String[] processOptions(String[] args) {
+ List<String> a = new ArrayList<String>();
+ for (String s : args) {
+ if (s.startsWith("--reference")) {
+ System.out.println("# using reference method of calculation");
+ reference = true;
+ } else if (s.startsWith("--show-matches")) {
+ if (!reference)
+ System.out.println("# using reference method of calculation");
+ reference = true;
+ showMatches = true;
+ } else if (s.startsWith("--no-print")) {
+ print = false;
+ } else
+ a.add(s);
+ }
+ return a.toArray(new String[a.size()]);
+ }
+
+ private static void runTest(String stylefile, String mapfile) {
+ PrintingMapCollector collector = new PrintingMapCollector();
+ OsmConverter normal;
+ try {
+ normal = new StyleTester(stylefile, collector, reference);
+ } catch (FileNotFoundException e) {
+ System.err.println("Could not open style file " + stylefile);
+ return;
+ }
+ try {
+
+ InputStream is = Utils.openFile(mapfile);
+ SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+ parserFactory.setXIncludeAware(true);
+ parserFactory.setNamespaceAware(true);
+ SAXParser parser = parserFactory.newSAXParser();
+
+ try {
+ EnhancedProperties props = new EnhancedProperties();
+ props.put("preserve-element-order", "1");
+ ElementSaver saver = new ElementSaver(props);
+ Osm5XmlHandler handler = new Osm5XmlHandler(props);
+ SaxHandler saxHandler = handler.new SaxHandler();
+ handler.setElementSaver(saver);
+ parser.parse(is, saxHandler);
+ saver.finishLoading();
+ saver.convert(normal);
+
+ System.err.println("Conversion time " + (System.currentTimeMillis() - collector.getStart()) + "ms");
+ } catch (IOException e) {
+ throw new FormatException("Error reading file", e);
+ }
+ } catch (SAXException e) {
+ throw new FormatException("Error parsing file", e);
+ } catch (ParserConfigurationException e) {
+ throw new FormatException("Internal error configuring xml parser", e);
+ } catch (FileNotFoundException e) {
+ System.err.println("Cannot open file " + mapfile);
+ }
+ }
+
+
+ /**
+ * Run a simple test with a combined test file.
+ * @param filename The test file contains text way definitions and a style
+ * file all in one.
+ */
+ public static void runSimpleTest(String filename) {
+ try {
+ FileReader reader = new FileReader(filename);
+ BufferedReader br = new BufferedReader(reader);
+ List<Way> ways = readSimpleTestFile(br);
+
+ List<MapElement> results = new ArrayList<MapElement>();
+
+ List<MapElement> strictResults = new ArrayList<MapElement>();
+
+ OsmConverter strict = new StyleTester("styletester.style", new LocalMapCollector(strictResults), true);
+ List<String> givenList = ((StyleTester) strict).givenResults;
+
+ List<String> all = new ArrayList<String>();
+ for (Way w : ways) {
+ OsmConverter normal = new StyleTester("styletester.style", new LocalMapCollector(results), false);
+ strict = new StyleTester("styletester.style", new LocalMapCollector(strictResults), true);
+
+ String prefix = "WAY " + w.getId() + ": ";
+ normal.convertWay(w.copy());
+ normal.end();
+ String[] actual = formatResults(prefix, results);
+ all.addAll(Arrays.asList(actual));
+ results.clear();
+
+ strict.convertWay(w.copy());
+ strict.end();
+ String[] expected = formatResults(prefix, strictResults);
+ strictResults.clear();
+
+ printResult(actual);
+
+ if (!Arrays.deepEquals(actual, expected)) {
+ out.println("ERROR expected result is:");
+ printResult(expected);
+ }
+
+ out.println();
+ }
+
+ String[] given = givenList.toArray(new String[givenList.size()]);
+ if ((given.length > 0 || forceUseOfGiven) && !Arrays.deepEquals(all.toArray(), givenList.toArray())) {
+ out.println("ERROR given results were:");
+ printResult(given);
+ }
+ } catch (FileNotFoundException e) {
+ System.err.println("Cannot open test file " + filename);
+ } catch (IOException e) {
+ System.err.println("Failure while reading test file " + filename);
+ }
+ }
+
+
+ public void convertWay(Way way) {
+ converter.convertWay(way);
+ }
+
+ public void convertNode(Node node) {
+ converter.convertNode(node);
+ }
+
+ public void convertRelation(Relation relation) {
+ converter.convertRelation(relation);
+ }
+
+ public void setBoundingBox(Area bbox) {
+ converter.setBoundingBox(bbox);
+ }
+
+ public void end() {
+ converter.end();
+ }
+
+
+ private static void printResult(String[] results) {
+ for (String s : results) {
+ out.println(s);
+ }
+ }
+
+ /**
+ * Read in the combined test file. This contains some ways and a style.
+ * The style does not need to include 'version' as this is added for you.
+ */
+ private static List<Way> readSimpleTestFile(BufferedReader br) throws IOException {
+ List<Way> ways = new ArrayList<Way>();
+
+ String line;
+ while ((line = br.readLine()) != null) {
+ line = line.trim();
+ if (line.toLowerCase(Locale.ENGLISH).startsWith("way")) {
+ Way w = readWayTags(br, line);
+ ways.add(w);
+ } else if (line.startsWith("<<<")) {
+ // read the rest of the file
+ readStyles(br, line);
+ }
+ /*else if ("".equals(line) || line.startsWith("#")) {
+ // ignore blank lines.
+ }*/
+ }
+ br.close();
+
+ return ways;
+ }
+
+ /**
+ * You can have a number of ways defined in the file. If you give a
+ * number after 'way' that is used as the way id so that you can identify
+ * it in the results.
+ *
+ * A list of tags are read and added to the way up until a blank line.
+ *
+ * @param br Read from here.
+ * @param waydef This will contain the way-id if one was given. Otherwise
+ * the way id will be 1.
+ * @throws IOException If the file cannot be read.
+ */
+ private static Way readWayTags(BufferedReader br, String waydef) throws IOException {
+ int id = 1;
+ String[] strings = SPACES_PATTERN.split(waydef);
+ if (strings.length > 1)
+ id = Integer.parseInt(strings[1]);
+
+ Way w = new Way(id);
+ w.addPoint(new Coord(1, 1));
+ w.addPoint(new Coord(2, 2));
+
+ String line;
+ while ((line = br.readLine()) != null) {
+ if (line.indexOf('=') < 0)
+ break;
+ String[] tagval = EQUAL_PATTERN.split(line, 2);
+ if (tagval.length == 2)
+ w.addTag(tagval[0], tagval[1]);
+ }
+
+ return w;
+ }
+
+ /**
+ * Print out the garmin elements that were produced by the rules.
+ * @param prefix This string will be prepended to the formatted result.
+ * @param lines The resulting map elements.
+ */
+ private static String[] formatResults(String prefix, List<MapElement> lines) {
+ String[] result = new String[lines.size()];
+ int i = 0;
+ for (MapElement el : lines) {
+ String s;
+ // So we can run against versions that do not have toString() methods
+ if (el instanceof MapRoad)
+ s = roadToString((MapRoad) el);
+ else
+ s = lineToString((MapLine) el);
+ result[i++] = prefix + s;
+ }
+ return result;
+ }
+
+ /**
+ * This is so we can run against versions of mkgmap that do not have
+ * toString methods on MapLine and MapRoad.
+ */
+ private static String lineToString(MapLine el) {
+ Formatter fmt = new Formatter();
+ fmt.format("Line 0x%x, labels=%s, res=%d-%d",
+ el.getType(), Arrays.toString(el.getLabels()),
+ el.getMinResolution(), el.getMaxResolution());
+ if (el.isDirection())
+ fmt.format(" oneway");
+
+ fmt.format(" ");
+ for (Coord co : el.getPoints())
+ fmt.format("(%s),", co);
+
+ return fmt.toString();
+ }
+
+ /**
+ * This is so we can run against versions of mkgmap that do not have
+ * toString methods on MapLine and MapRoad.
+ */
+ private static String roadToString(MapRoad el) {
+ StringBuffer sb = new StringBuffer(lineToString(el));
+ sb.delete(0, 4);
+ sb.insert(0, "Road");
+ Formatter fmt = new Formatter(sb);
+ fmt.format(" road class=%d speed=%d", el.getRoadDef().getRoadClass(),
+ getRoadSpeed(el.getRoadDef()));
+ return fmt.toString();
+ }
+
+ /**
+ * Implement a method to get the road speed from RoadDef.
+ */
+ private static int getRoadSpeed(RoadDef roadDef) {
+ try {
+ Field field = RoadDef.class.getDeclaredField("tabAInfo");
+ field.setAccessible(true);
+ int tabA = (Integer) field.get(roadDef);
+ return tabA & 0x7;
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ return 0;
+ }
+
+ /**
+ * Read the style definitions. The rest of the file is just copied to
+ * a style file named 'styletester.style' so that it can be read in the
+ * normal manner.
+ * @param br Read from here.
+ * @param initLine The first line of the style definition that has already been read.
+ * @throws IOException If writing fails.
+ */
+ private static void readStyles(BufferedReader br, String initLine) throws IOException {
+ FileWriter writer = new FileWriter(STYLETESTER_STYLE);
+ PrintWriter pw = new PrintWriter(writer);
+
+ pw.println("<<<version>>>\n0");
+ pw.println(initLine);
+
+ try {
+ String line;
+ while ((line = br.readLine()) != null)
+ pw.println(line);
+ } finally {
+ pw.close();
+ }
+
+ }
+
+ /**
+ * A styled converter that should work exactly the same as the version of
+ * mkgmap you are using.
+ * @param styleFile The name of the style file to process.
+ * @param coll A map collector to receive the created elements.
+
+ */
+ private StyledConverter makeStyleConverter(String styleFile, MapCollector coll) throws FileNotFoundException {
+ Style style = new StyleImpl(styleFile, null);
+ return new StyledConverter(style, coll, new EnhancedProperties());
+ }
+
+ /**
+ * A special styled converted that attempts to produce the correct theoretical
+ * result of running the style rules in order by literally doing that.
+ * This should produce the same result as {@link #makeStyleConverter} and
+ * can be used as a test of the strict style ordering branch.
+ * @param styleFile The name of the style file to process.
+ * @param coll A map collector to receive the created elements.
+ */
+ private StyledConverter makeStrictStyleConverter(String styleFile, MapCollector coll) throws FileNotFoundException {
+ Style style = new ReferenceStyle(styleFile, null);
+ return new StyledConverter(style, coll, new EnhancedProperties());
+ }
+
+ public static void forceUseOfGiven(boolean force) {
+ forceUseOfGiven = force;
+ }
+
+ /**
+ * This is a reference implementation of the style engine which is somewhat
+ * independent of the main implementation and does not have any kind of
+ * optimisations. You can compare the results from the two implementations
+ * to find bugs and regressions.
+ */
+ private class ReferenceStyle extends StyleImpl {
+ private final StyleFileLoader fileLoader;
+ private LevelInfo[] levels;
+
+ /**
+ * Create a style from the given location and name.
+ *
+ * @param loc The location of the style. Can be null to mean just check the
+ * classpath.
+ * @param name The name. Can be null if the location isn't. If it is null
+ * then we just check for the first version file that can be found.
+ * @throws FileNotFoundException If the file doesn't exist. This can include
+ * the version file being missing.
+ */
+ public ReferenceStyle(String loc, String name) throws FileNotFoundException {
+ super(loc, name);
+ fileLoader = StyleFileLoader.createStyleLoader(loc, name);
+
+ setupReader();
+ readGivenResults();
+ }
+
+ private void setupReader() {
+ String l = LevelInfo.DEFAULT_LEVELS;
+ levels = LevelInfo.createFromString(l);
+ }
+
+ private void readGivenResults() {
+ givenResults.clear();
+ BufferedReader br = null;
+ try {
+ Reader reader = fileLoader.open("results");
+ br = new BufferedReader(reader);
+ String line;
+ while ((line = br.readLine()) != null) {
+ line = line.trim();
+ if (line.isEmpty())
+ continue;
+ givenResults.add(line);
+ }
+ } catch (IOException e) {
+ // there are no known good results given, that is OK
+ } finally {
+ Utils.closeFile(br);
+ }
+ }
+
+ /**
+ * Throws away the rules as previously read and reads again using the
+ * SimpleRuleFileReader which does not re-order or optimise the rules
+ * in any way.
+ *
+ * @return A simple list of rules with a resolving method that applies
+ * each rule in turn to the element until there is match.
+ */
+ public Rule getWayRules() {
+ ReferenceRuleSet r = new ReferenceRuleSet();
+ r.addAll((ReferenceRuleSet) getLineRules());
+ r.addAll((ReferenceRuleSet) getPolygonRules());
+ return r;
+ }
+
+ /**
+ * Throws away the existing rules for the lines and re-reads them using
+ * the SimpleRuleFileReader that does not re-order or optimise the rules in any
+ * way.
+ *
+ * @return A Reference rule set of the lines.
+ */
+ public Rule getLineRules() {
+ ReferenceRuleSet r = new ReferenceRuleSet();
+
+ SimpleRuleFileReader ruleFileReader = new SimpleRuleFileReader(FeatureKind.POLYLINE, levels, r);
+ try {
+ ruleFileReader.load(fileLoader, "lines");
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ return r;
+ }
+
+ /**
+ * Throws away the existing rules for the polygons and re-reads them using
+ * the SimpleRuleFileReader that does not re-order or optimise the rules in any
+ * way.
+ *
+ * @return A Reference rule set of the polygons.
+ */
+ public Rule getPolygonRules() {
+ ReferenceRuleSet r = new ReferenceRuleSet();
+
+ SimpleRuleFileReader ruleFileReader = new SimpleRuleFileReader(FeatureKind.POLYGON, levels, r);
+ try {
+ ruleFileReader.load(fileLoader, "polygons");
+ } catch (FileNotFoundException e) {
+ // not a problem
+ }
+
+ return r;
+ }
+
+ public Rule getRelationRules() {
+ ReferenceRuleSet r = new ReferenceRuleSet();
+
+ SimpleRuleFileReader ruleFileReader = new SimpleRuleFileReader(FeatureKind.RELATION, levels, r);
+ try {
+ ruleFileReader.load(fileLoader, "relations");
+ } catch (FileNotFoundException e) {
+ // its not a problem
+ }
+
+ return r;
+ }
+
+ public Set<String> getUsedTags() {
+ return null;
+ }
+
+ /**
+ * Keeps each rule in an ordered list.
+ *
+ * Types are resolved by literally applying the rules in order to the
+ * element.
+ *
+ * As long as the rules are added in the order they are encountered in
+ * the file, this should work.
+ */
+ private class ReferenceRuleSet implements Rule {
+ private final List<Rule> rules = new ArrayList<Rule>();
+
+ public void add(Rule rule) {
+ rules.add(rule);
+ }
+
+ public void addAll(ReferenceRuleSet rs) {
+ for (Rule r : rs.rules) {
+ add(r);
+ }
+ }
+
+ public void resolveType(Element el, TypeResult result) {
+ String tagsBefore = wayTags(el);
+ if (showMatches) {
+ out.println("# Tags before: " + tagsBefore);
+ }
+ WatchableTypeResult a = new WatchableTypeResult(result);
+ // Start by literally running through the rules in order.
+ for (Rule rule : rules) {
+ a.reset();
+ rule.resolveType(el, a);
+
+ if (showMatches) {
+ if (a.isFound()) {
+ out.println("# Matched: " + rule);
+ } else if (a.isActionsOnly())
+ out.println("# Matched for actions: " + rule);
+ }
+
+ if (a.isResolved())
+ break;
+ }
+ if (showMatches && !tagsBefore.equals(wayTags(el)))
+ out.println("# Way tags after: " + wayTags(el));
+ }
+
+ private String wayTags(Element el) {
+ StringBuilder sb = new StringBuilder();
+ for (String t : el) {
+ sb.append(t);
+ sb.append(",");
+ }
+ return sb.toString();
+ }
+
+ public void setFinalizeRule(Rule finalizeRule) {
+ for (Rule rule : rules) {
+ rule.setFinalizeRule(finalizeRule);
+ }
+ }
+ }
+
+ /**
+ * A reimplementation of RuleFileReader that does no optimisation but
+ * just reads the rules into a list.
+ *
+ * Again this can be compared with the main implementation which may
+ * attempt more optimisations.
+ */
+ class SimpleRuleFileReader {
+ private final TypeReader typeReader;
+
+ private final ReferenceRuleSet rules;
+ private ReferenceRuleSet finalizeRules;
+ private TokenScanner scanner;
+ private boolean inFinalizeSection = false;
+
+ public SimpleRuleFileReader(FeatureKind kind, LevelInfo[] levels, ReferenceRuleSet rules) {
+ this.rules = rules;
+ typeReader = new TypeReader(kind, levels);
+ }
+
+ /**
+ * Read a rules file.
+ * @param loader A file loader.
+ * @param name The name of the file to open.
+ * @throws FileNotFoundException If the given file does not exist.
+ */
+ public void load(StyleFileLoader loader, String name) throws FileNotFoundException {
+ Reader r = loader.open(name);
+ load(r, name);
+ }
+
+ void load(Reader r, String name) {
+ scanner = new TokenScanner(name, r);
+ scanner.setExtraWordChars("-:");
+
+ ExpressionReader expressionReader = new ExpressionReader(scanner, FeatureKind.POLYLINE);
+ ActionReader actionReader = new ActionReader(scanner);
+
+ // Read all the rules in the file.
+ scanner.skipSpace();
+ while (!scanner.isEndOfFile()) {
+ if (checkCommand(scanner))
+ continue;
+
+ Op expr = expressionReader.readConditions();
+
+ ActionList actions = actionReader.readActions();
+
+ // If there is an action list, then we don't need a type
+ GType type = null;
+ if (scanner.checkToken("["))
+ type = typeReader.readType(scanner);
+ else if (actions == null)
+ throw new SyntaxException(scanner, "No type definition given");
+
+ saveRule(expr, actions, type);
+ scanner.skipSpace();
+ }
+ if (finalizeRules != null) {
+ rules.setFinalizeRule(finalizeRules);
+ }
+ }
+
+ private boolean checkCommand(TokenScanner scanner) {
+ scanner.skipSpace();
+ if (scanner.isEndOfFile())
+ return false;
+
+ if (inFinalizeSection == false && scanner.checkToken("<")) {
+ Token token = scanner.nextToken();
+ if (scanner.checkToken("finalize")) {
+ Token finalizeToken = scanner.nextToken();
+ if (scanner.checkToken(">")) {
+ // consume the > token
+ scanner.nextToken();
+ // mark start of the finalize block
+ inFinalizeSection = true;
+ finalizeRules = new ReferenceRuleSet();
+ return true;
+ } else {
+ scanner.pushToken(finalizeToken);
+ scanner.pushToken(token);
+ }
+ } else {
+ scanner.pushToken(token);
+ }
+ }
+ scanner.skipSpace();
+ return false;
+ }
+
+ /**
+ * Save the expression as a rule.
+ */
+ private void saveRule(Op op, ActionList actions, GType gt) {
+ Rule rule;
+ if (actions.isEmpty())
+ rule = new ExpressionRule(op, gt);
+ else
+ rule = new ActionRule(op, actions.getList(), gt);
+
+ if (inFinalizeSection)
+ finalizeRules.add(rule);
+ else
+ rules.add(rule);
+ }
+ }
+ }
+
+ /**
+ * A map collector that just adds any line or road we find to the end of
+ * a list.
+ */
+ private static class LocalMapCollector implements MapCollector {
+ private final List<MapElement> lines;
+
+ private LocalMapCollector(List<MapElement> lines) {
+ this.lines = lines;
+ }
+
+ public void addToBounds(Coord p) { }
+
+ // could save points in the same way as lines to test them
+ public void addPoint(MapPoint point) { }
+
+ public void addLine(MapLine line) {
+ lines.add(line);
+ }
+
+ public void addShape(MapShape shape) { }
+
+ public void addRoad(MapRoad road) {
+ lines.add(road);
+ }
+
+ public void addRestriction(CoordNode fromNode, CoordNode toNode, CoordNode viaNode, byte exceptMask) {
+ }
+
+ public void addThroughRoute(long junctionNodeId, long roadIdA, long roadIdB) {
+ }
+ }
+
+ /**
+ * A map collector that just prints elements found.
+ * (lines and roads only at present).
+ */
+ private static class PrintingMapCollector implements MapCollector {
+ private long start;
+
+ public void addToBounds(Coord p) { if (start == 0) {
+ System.err.println("start collection");
+ start = System.currentTimeMillis();
+ }}
+
+ // could save points in the same way as lines to test them
+ public void addPoint(MapPoint point) { }
+
+ public void addLine(MapLine line) {
+ if (start == 0) {
+ System.err.println("start collection");
+ start = System.currentTimeMillis();
+ }
+ if (print) {
+ String[] strings = formatResults("", Arrays.<MapElement>asList(line));
+ printResult(strings);
+ }
+ }
+
+ public void addShape(MapShape shape) { }
+
+ public void addRoad(MapRoad road) {
+ if (print) {
+ String[] strings = formatResults("", Collections.<MapElement>singletonList(road));
+ printResult(strings);
+ }
+ }
+
+ public void addRestriction(CoordNode fromNode, CoordNode toNode, CoordNode viaNode, byte exceptMask) {
+ }
+
+ public void addThroughRoute(long junctionNodeId, long roadIdA, long roadIdB) {
+ }
+
+ public long getStart() {
+ return start;
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/main/TypCompiler.java b/src/uk/me/parabola/mkgmap/main/TypCompiler.java
new file mode 100644
index 0000000..e2baa70
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/main/TypCompiler.java
@@ -0,0 +1,279 @@
+/*
+ * 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);
+ }
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/main/TypSaver.java b/src/uk/me/parabola/mkgmap/main/TypSaver.java
new file mode 100644
index 0000000..5c26d9a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/main/TypSaver.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import uk.me.parabola.imgfmt.ExitException;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.mkgmap.CommandArgs;
+
+/**
+ * Ensure that the TYP file has the correct family and product id's as given by the
+ * command line arguments.
+ *
+ * If they are correct, then returns the original name and nothing else is done.
+ *
+ * If they are not correct, then a new file is created which patches the id's
+ * and its name is returned.
+ */
+class TypSaver implements MapProcessor {
+ public String makeMap(CommandArgs args, String filename) {
+ String outfilename = filename;
+
+ // These are the family and product id's that are wanted.
+ int familyId = args.get("family-id", CommandArgs.DEFAULT_FAMILYID);
+ int productId = args.get("product-id", CommandArgs.DEFAULT_PRODUCTID);
+
+ FileInputStream in = null;
+ try {
+ in = new FileInputStream(filename);
+ byte[] buf = new byte[256];
+ int n = in.read(buf);
+
+ ByteBuffer buffer = ByteBuffer.wrap(buf);
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
+
+ // Get the product and family id's that are actually in the supplied TYP file.
+ int foundFamily = buffer.getChar(0x2f);
+ int foundProduct = buffer.getChar(0x31);
+
+ if (familyId != foundFamily || productId != foundProduct) {
+ buffer.putChar(0x2f, (char) familyId);
+ buffer.putChar(0x31, (char) productId);
+
+ outfilename = makeOutName(filename);
+ writeAlteredTyp(outfilename, in, buf, n);
+ }
+
+ } catch (IOException e) {
+ throw new ExitException("TYP file cannot be opened or read: " + filename);
+ } finally {
+ Utils.closeFile(in);
+ }
+ return outfilename;
+ }
+
+ /**
+ * Write out the altered TYP file.
+ *
+ * @param outFilename The name to write to.
+ * @param in The input file. This has already had the first block read from it.
+ * @param buf The buffer holding the first block of the file. It is already modified, so just needs
+ * to be written out.
+ * @param n The number of characters in the first block. The minimum size of the TYP file is
+ * less than the buffer size.
+ */
+ private void writeAlteredTyp(String outFilename, FileInputStream in, byte[] buf, int n) {
+ FileOutputStream out = null;
+ try {
+ out = new FileOutputStream(outFilename);
+ do {
+ out.write(buf, 0, n);
+ } while ((n = in.read(buf)) > 0);
+ } catch (IOException e) {
+ throw new ExitException("Could not write temporary TYP file: " + outFilename);
+ } finally {
+ Utils.closeFile(out);
+ }
+ }
+
+ /**
+ * Create a name for the patched file.
+ *
+ * We pre-pend a 'x' to the name part of the path.
+ *
+ * If the name is already 8+3 characters, then the name that appears inside the gmapsupp, will
+ * not have the added character and so it is possible to have internal files with the same name.
+ * I don't think this matters, since I don't think that the name is important, but I could be wrong.
+ *
+ * @param path The original name
+ * @return The modified name.
+ */
+ private String makeOutName(String path) {
+ File f = new File(path);
+ File dir = f.getParentFile();
+
+ String name = f.getName();
+
+ File out = new File(dir, "x" + name);
+ return out.getPath();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/main/package.html b/src/uk/me/parabola/mkgmap/main/package.html
new file mode 100644
index 0000000..a30fd85
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/main/package.html
@@ -0,0 +1,9 @@
+<body>
+<h3>Main programs</h3>
+<p>This package contains the entry point, command line processing etc
+ for the mkgmap program.
+ For making a map, you need to call {@link uk.me.parabola.mkgmap.main.Main}.
+</p>
+
+</body>
+
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java b/src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java
new file mode 100644
index 0000000..35d377a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2008 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: 15-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle;
+
+import java.util.List;
+
+import uk.me.parabola.mkgmap.osmstyle.actions.Action;
+import uk.me.parabola.mkgmap.osmstyle.eval.Op;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.GType;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.Rule;
+import uk.me.parabola.mkgmap.reader.osm.TypeResult;
+
+/**
+ * An action rule modifies the tags on the incoming element.
+ *
+ * It can also have an expression, and does not need to have a Type. If
+ * there is no type then the resolve method does not send any results.
+ * The tags on the element may have been modified however.
+ *
+ * @author Steve Ratcliffe
+ */
+public class ActionRule implements Rule {
+ private final Op expression;
+ private final List<Action> actions;
+ private final GType type;
+ private Rule finalizeRule;
+
+ /** Finalize rules must not have an element type definition so the add method must never be called. */
+ private final static TypeResult finalizeTypeResult = new TypeResult() {
+ public void add(Element el, GType type) {
+ throw new UnsupportedOperationException("Finalize rules must not contain an action block.");
+ }
+ };
+
+ public ActionRule(Op expression, List<Action> actions, GType type) {
+ assert actions != null;
+ this.expression = expression;
+ this.actions = actions;
+ this.type = type;
+ }
+
+ public ActionRule(Op expression, List<Action> actions) {
+ assert actions != null;
+ this.expression = expression;
+ this.actions = actions;
+ this.type = null;
+ }
+
+ public void resolveType(Element el, TypeResult result) {
+ Element element = el;
+ if (expression != null) {
+ if (!expression.eval(element))
+ return;
+ // If this is a continue and we are not to propagate the effects
+ // of the action on the element to further rules, then make
+ // a copy of the element so that the original is unsullied.
+ //
+ // There is another reason we need to copy: since there will be
+ if (type != null && !type.isPropogateActions() && !(element instanceof Relation)) {
+ element = element.copy();
+ }
+ }
+
+ for (Action a : actions)
+ a.perform(element);
+
+ if (type != null && finalizeRule != null) {
+ if (el == element && type.isContinueSearch())
+ // if there is a continue statement changes performed in
+ // the finalize block must not be persistent
+ element = element.copy();
+ // there is a type so first execute the finalize rules
+ if (type.getDefaultName() != null)
+ element.addTag("mkgmap:default_name", type.getDefaultName());
+ finalizeRule.resolveType(element, finalizeTypeResult);
+ }
+
+ result.add(element, type);
+ }
+
+ public String toString() {
+ StringBuilder fmt = new StringBuilder();
+ if (expression != null)
+ fmt.append(expression);
+
+ fmt.append(" {");
+ for (Action a : actions)
+ fmt.append(a);
+ fmt.append("}");
+
+ if (type != null) {
+ fmt.append(' ');
+ fmt.append(type);
+ }
+
+ return fmt.toString();
+ }
+
+ public void setFinalizeRule(Rule finalizeRule) {
+ this.finalizeRule = finalizeRule;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/CombinedStyleFileLoader.java b/src/uk/me/parabola/mkgmap/osmstyle/CombinedStyleFileLoader.java
new file mode 100644
index 0000000..ef8edd6
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/CombinedStyleFileLoader.java
@@ -0,0 +1,226 @@
+/*
+ * 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: Apr 13, 2008
+ */
+package uk.me.parabola.mkgmap.osmstyle;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.log.Logger;
+
+/**
+ * Load a style from a single file. All the files that make up the style
+ * are held in the same file and delimited by a simple header.
+ *
+ * <p>Lines before the first header are ignored. A header looks like this:
+ * <<<filename>>>, that is three opening angle brackets, the name
+ * of the file and three closing angle brackets. The opening brackets
+ * must be at the beginning of the line, there can be trailing junk after
+ * the closing brackets which is ignored.
+ *
+ * <p>All lines after the header and before the next header or end of file
+ * are part of the named file.
+ *
+ * @author Steve Ratcliffe
+ */
+public class CombinedStyleFileLoader extends StyleFileLoader {
+ private static final Logger log = Logger.getLogger(CombinedStyleFileLoader.class);
+
+ private final Map<String, String> files = new HashMap<String, String>();
+ private final String styleName;
+ private static final Pattern STYLE_SUFFIX = Pattern.compile("\\.style$");
+ private static final Pattern FILENAME_START_MARK = Pattern.compile("<<<");
+ private static final Pattern FILENAME_END_MARK = Pattern.compile(">>>.*");
+
+ public CombinedStyleFileLoader(String filename) throws FileNotFoundException {
+ styleName = STYLE_SUFFIX.matcher(filename).replaceFirst("");
+
+ Reader in = new FileReader(filename);
+
+ try {
+ loadFiles(in);
+ } finally {
+ Utils.closeFile(in);
+ }
+ }
+
+ private void loadFiles(Reader in) {
+ BufferedReader r = new BufferedReader(in);
+
+ StringBuffer currentFile = new StringBuffer();
+ try {
+ String line;
+ String currentName = null;
+ while ((line = r.readLine()) != null) {
+ if (line.startsWith("<<<")) {
+ if (currentName != null) {
+ // Save previous file if any.
+ files.put(currentName, currentFile.toString());
+ }
+
+ line = FILENAME_START_MARK.matcher(line).replaceFirst("");
+ line = FILENAME_END_MARK.matcher(line).replaceFirst("");
+ log.debug("reading file", line);
+ currentName = line;
+ currentFile = new StringBuffer();
+ } else {
+ currentFile.append(line);
+ currentFile.append('\n');
+ }
+ }
+ if (currentName == null) {
+ log.error("failed to read style file");
+ } else {
+ files.put(currentName, currentFile.toString());
+ }
+ } catch (IOException e) {
+ log.error("failed to read style file");
+ }
+ }
+
+ /**
+ * Open the specified file in the style definition.
+ *
+ * @param filename The name of the file in the style.
+ * @return An open file reader for the file.
+ * @throws FileNotFoundException When the file can't be opened.
+ */
+ public Reader open(String filename) throws FileNotFoundException {
+ log.info("opening", filename);
+ String contents = files.get(filename);
+ if (contents == null)
+ throw new FileNotFoundException(filename);
+
+ log.debug("file", filename, "found");
+ return new StringReader(contents);
+ }
+
+ /**
+ * Close the FileLoader. This is different from closing individual files that
+ * were opened via {@link #open}. After this call then you shouldn't open any
+ * more files.
+ */
+ public void close() {
+ files.clear();
+ }
+
+ public String[] list() {
+ String basename = styleName.replaceFirst(".*[/\\\\]", "");
+ basename = basename.replaceFirst("\\.[^.]+$", "");
+ return new String[] {basename};
+ }
+
+ /**
+ * Covert between the single file simple-archive form and the directory
+ * form. Mostly for fun.
+ *
+ * @param args Arguments, you supply a directory or a file. If its a
+ * directory then covert into a simple-archive file and if it is a
+ * file then expand into separate files.
+ */
+ public static void main(String[] args) {
+ String name = args[0];
+ File file = new File(name);
+
+ PrintStream out = System.out;
+ try {
+ if (file.isDirectory()) {
+ convertToFile(file, out);
+ } else {
+ String dirname;
+ int ind = name.lastIndexOf('.');
+ if (ind > 0)
+ dirname = name.substring(0, ind);
+ else
+ dirname = name + ".d"; // got to do something...
+ convertToDirectory(name, dirname);
+ }
+ } catch (FileNotFoundException e) {
+ System.err.println("Could not open file " + e);
+ System.exit(1);
+ } catch (IOException e) {
+ System.err.println("Could not read file " + e);
+ System.exit(1);
+ }
+ }
+
+ private static void convertToDirectory(String name, String dirname) throws IOException {
+ CombinedStyleFileLoader loader = new CombinedStyleFileLoader(name);
+ File dir = new File(dirname);
+ dir.mkdir();
+ for (String s : loader.files.keySet()) {
+ File ent = new File(dir, s);
+ ent.getParentFile().mkdirs();
+ FileWriter writer = new FileWriter(ent);
+ BufferedReader r = null;
+ try {
+ r = new BufferedReader(loader.open(s));
+ String line;
+ while ((line = r.readLine()) != null) {
+ writer.write(line);
+ writer.write('\n');
+ }
+ } finally {
+ if (r != null) r.close();
+ writer.close();
+ }
+ }
+ }
+
+ private static void convertToFile(File file, PrintStream out) throws IOException {
+ File[] list = file.listFiles(new NoHiddenFilter());
+ convertToFile(out, list, null);
+ }
+
+ private static void convertToFile(PrintStream out, File[] list, String prefix) throws IOException {
+ for (File entry : list) {
+ if (entry.isFile()) {
+ out.print("<<<");
+ if (prefix != null) {
+ out.print(prefix);
+ out.print('/');
+ }
+ out.print(entry.getName());
+ out.println(">>>");
+
+ BufferedReader r = new BufferedReader(new FileReader(entry));
+ String line;
+ while ((line = r.readLine()) != null)
+ out.println(line);
+ } else {
+ convertToFile(out, entry.listFiles(new NoHiddenFilter()), entry.getName());
+ }
+ }
+ }
+
+ private static class NoHiddenFilter implements FilenameFilter {
+ public boolean accept(File dir, String name) {
+ return !(name.isEmpty() || name.charAt(0) == '.');
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/DirectoryFileLoader.java b/src/uk/me/parabola/mkgmap/osmstyle/DirectoryFileLoader.java
new file mode 100644
index 0000000..7f32c94
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/DirectoryFileLoader.java
@@ -0,0 +1,94 @@
+/*
+ * 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: Feb 17, 2008
+ */
+package uk.me.parabola.mkgmap.osmstyle;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStreamReader;
+import java.io.FileInputStream;
+import java.io.UnsupportedEncodingException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.log.Logger;
+
+/**
+ * Deal with a style that is contained in a directory.
+ *
+ * @author Steve Ratcliffe
+ */
+public class DirectoryFileLoader extends StyleFileLoader {
+ private static final Logger log = Logger.getLogger(DirectoryFileLoader.class);
+
+ private final File dir;
+
+ /**
+ * Create a loader given the directory as a File object.
+ * @param dir The directory containing the style files.
+ */
+ public DirectoryFileLoader(File dir) {
+ assert dir.isDirectory();
+ this.dir = dir;
+ }
+
+ /**
+ * Open the specified file in the style definition.
+ *
+ * @param filename The name of the file in the style.
+ * @return An open file reader for the file.
+ */
+ public Reader open(String filename) throws FileNotFoundException {
+ File file = new File(dir, filename);
+
+ Reader r = null;
+ try {
+ r = new InputStreamReader(new FileInputStream(file), "UTF-8");
+ } catch (UnsupportedEncodingException uee) {
+ System.out.println("DirectoryFileLoader: Encoding UTF-8 not supported");
+ }
+
+ return new BufferedReader(r);
+ }
+
+ /**
+ * Nothing needs doing in this case.
+ */
+ public void close() {
+ }
+
+ public String[] list() {
+ log.debug("dir list", dir);
+ List<String> res = new ArrayList<String>();
+
+ File[] allFiles = dir.listFiles();
+ for (File file : allFiles) {
+ log.debug("dir loader", file);
+ if (file.isDirectory()) {
+ res.add(file.getName());
+ }
+ }
+
+ // If there were no included directories, then the style name is the
+ // name of the directory itself.
+ if (res.isEmpty())
+ res.add(dir.getName());
+
+ return res.toArray(new String[res.size()]);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java b/src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java
new file mode 100644
index 0000000..49a4c6e
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2008 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: 07-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle;
+
+import uk.me.parabola.mkgmap.osmstyle.eval.Op;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.GType;
+import uk.me.parabola.mkgmap.reader.osm.Rule;
+import uk.me.parabola.mkgmap.reader.osm.TypeResult;
+
+/**
+ * A rule that contains a condition. If the condition is matched by the
+ * element then the finalize rule is executed and the held gtype is returned.
+ *
+ * @author Steve Ratcliffe
+ */
+public class ExpressionRule implements Rule {
+ private final Op expression;
+ private final GType gtype;
+ private Rule finalizeRule;
+
+ /** Finalize rules must not have an element type definition so the add method must never be called. */
+ private final static TypeResult finalizeTypeResult = new TypeResult() {
+ public void add(Element el, GType type) {
+ throw new UnsupportedOperationException("Finalize rules must not contain an action block.");
+ }
+ };
+
+ public ExpressionRule(Op expression, GType gtype) {
+ this.expression = expression;
+ this.gtype = gtype;
+ }
+
+ public void resolveType(Element el, TypeResult result) {
+ if (expression.eval(el)) {
+ // expression matches
+ if (finalizeRule != null) {
+ if (gtype.isContinueSearch()) {
+ el = el.copy();
+ }
+ // run the finalize rules
+ if (gtype.getDefaultName() != null)
+ el.addTag("mkgmap:default_name", gtype.getDefaultName());
+ finalizeRule.resolveType(el, finalizeTypeResult);
+ }
+ result.add(el, gtype);
+ }
+ }
+
+ public String toString() {
+ return expression.toString() + ' ' + gtype;
+ }
+
+ public void setFinalizeRule(Rule finalizeRule) {
+ this.finalizeRule = finalizeRule;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/JarFileLoader.java b/src/uk/me/parabola/mkgmap/osmstyle/JarFileLoader.java
new file mode 100644
index 0000000..d4aacef
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/JarFileLoader.java
@@ -0,0 +1,175 @@
+/*
+ * 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: Feb 17, 2008
+ */
+package uk.me.parabola.mkgmap.osmstyle;
+
+import java.io.BufferedInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import uk.me.parabola.log.Logger;
+
+/**
+ * Load a style from a jar file.
+ *
+ * The style can just be jared up at the top level or it can be
+ * contained within a directory in the jar. You can have more than one
+ * style in the jar. In this case a name will be required to select
+ * the one that you want to use. It looks for a file with a name that
+ * ends with 'version' to work out where the style is. If a name is given
+ * then it looks for a file path ending {@code name/version}.
+ *
+ * @author Steve Ratcliffe
+ */
+public class JarFileLoader extends StyleFileLoader {
+ private static final Logger log = Logger.getLogger(JarFileLoader.class);
+ private JarFile jarFile;
+ private String prefix;
+
+ public JarFileLoader(URL url) throws FileNotFoundException {
+ jarInit(url, null);
+ }
+
+ public JarFileLoader(String url, String name) throws FileNotFoundException {
+ try {
+ jarInit(new URL(makeJarUrl(url)), name);
+ } catch (MalformedURLException e) {
+ throw new FileNotFoundException("Could not open style at " + url);
+ }
+ }
+
+ private String makeJarUrl(String url) {
+ if (url.toLowerCase().startsWith("jar:"))
+ return url;
+ else
+ return "jar:" + url + "!/";
+ }
+
+ private void jarInit(URL url, String name) throws FileNotFoundException {
+ log.debug("opening", url);
+ try {
+ JarURLConnection jurl = (JarURLConnection) url.openConnection();
+ jurl.setUseCaches(false);
+ jarFile = jurl.getJarFile();
+ prefix = jurl.getEntryName();
+ if (prefix == null) {
+ prefix = searchVersion(jarFile, name);
+ }
+
+ log.debug("jar prefix is", prefix);
+ } catch (IOException e) {
+ throw new FileNotFoundException("Could not open style at " + url);
+ }
+ }
+
+ /**
+ * Find path in archive
+ * @param file the JarFile instance
+ * @param style a style name or null to find any version file
+ * @return return prefix of (first) entry that contains file version
+ */
+ private String searchVersion(JarFile file, String style) {
+ Enumeration<JarEntry> en = file.entries();
+ String flatEnd = style==null ? "version" : style + "/version";
+ String end = "/" + flatEnd;
+ while (en.hasMoreElements()) {
+ JarEntry entry = en.nextElement();
+ String ename = entry.getName();
+ if (ename.endsWith(end) || ename.equals(flatEnd))
+ return ename.substring(0, ename.length() - "version".length());
+ }
+ return null;
+ }
+
+ /**
+ * Open the specified file in the style definition.
+ *
+ * @param filename The name of the file in the style.
+ * @return An open file reader for the file.
+ * @throws FileNotFoundException When the file can't be opened.
+ */
+ public Reader open(String filename) throws FileNotFoundException {
+ if (jarFile == null)
+ throw new FileNotFoundException("Could not open file " + filename);
+
+ String path = filename;
+ if (prefix != null)
+ path = prefix + filename;
+
+ JarEntry jarEntry = jarFile.getJarEntry(path);
+ if (jarEntry == null)
+ throw new FileNotFoundException("Could not open style file " + filename);
+
+ InputStream stream;
+ try {
+ stream = jarFile.getInputStream(jarEntry);
+ } catch (IOException e) {
+ throw new FileNotFoundException("Could not open " + filename);
+ }
+ return new InputStreamReader(new BufferedInputStream(stream));
+ }
+
+ public void close() {
+ try {
+ jarFile.close();
+ } catch (IOException e) {
+ log.debug("failed to close jar file");
+ }
+ }
+
+ protected void finalize() throws Throwable {
+ super.finalize();
+ close();
+ }
+
+ public String[] list() {
+ Enumeration<JarEntry> en = jarFile.entries();
+ List<String> list = new ArrayList<String>();
+ while (en.hasMoreElements()) {
+ JarEntry entry = en.nextElement();
+
+ if (!entry.isDirectory()) {
+ String name = entry.getName();
+ if (name.endsWith("version")) {
+ log.debug("name is", name);
+ String[] dirs = name.split("/");
+ if (dirs.length == 1) {
+ String s = jarFile.getName();
+ s = s.replaceFirst("\\..*$", "");
+ s = s.replaceAll(".*/", "");
+ list.add(s);
+ }
+ else
+ list.add(dirs[dirs.length - 2]);
+ }
+ }
+ }
+
+ return list.toArray(new String[list.size()]);
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/OverlayReader.java b/src/uk/me/parabola/mkgmap/osmstyle/OverlayReader.java
new file mode 100644
index 0000000..10bafdb
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/OverlayReader.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2008 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: 10-Dec-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle;
+
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.general.LineAdder;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+/**
+ * Reads the overlay file.
+ * There are not many line types available in the version of the .img
+ * format that we are using, but you can simulate more by clever use
+ * of TYP files and overlaying lines on top of each other.
+ *
+ * The format of the file is just a series of lines that start with
+ * the fake type and followed by a list of types that will actually
+ * be created.
+ *
+ * Eg.
+ * 0x123: 0x12, 0x14, 0x15
+ *
+ * If a rule results in the type 0x123 (which wouldn't normally show up)
+ * it is replaced by three lines with the type 0x12, 0x14, 0x15.
+ *
+ * @author Steve Ratcliffe
+ * @see <a href="TODO: find url">Example of the technique</a>
+ *
+ */
+public class OverlayReader {
+ private final Map<Integer, List<Integer>> overlays = new HashMap<Integer, List<Integer>>();
+ private final Reader reader;
+ private final String filename;
+
+ public OverlayReader(Reader r, String filename) {
+ reader = r;
+ this.filename = filename;
+ }
+
+ public void readOverlays() {
+ TokenScanner ts = new TokenScanner(filename, reader);
+ while (!ts.isEndOfFile()) {
+ String line = ts.readLine();
+
+ // Remove comments before parsing
+ int commentstart = line.indexOf("#");
+ if (commentstart != -1)
+ line = line.substring(0, commentstart);
+
+ String[] fields = line.split(":", 2);
+ if (fields.length == 2) {
+ try {
+ overlays.put(Integer.decode(fields[0]), readReplacements(ts, fields[1]));
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(ts, "Expecting a number");
+ }
+ }
+ }
+ }
+
+ /**
+ * Read the line of replacements.
+ */
+ private List<Integer> readReplacements(TokenScanner ts, String line) {
+ List<Integer> l = new ArrayList<Integer>();
+
+ String[] nums = line.split("[ ,]");
+ for (String n : nums) {
+ if (n == null || n.length() == 0)
+ continue;
+
+ try {
+ l.add(Integer.decode(n));
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(ts, "List of numbers expected");
+ }
+ }
+
+ return l;
+ }
+
+ public void addLine(MapLine line, LineAdder adder) {
+ int origType = line.getType();
+ List<Integer> integerList = overlays.get(origType);
+ if (integerList != null) {
+ MapLine newline = line.copy();
+ newline.setType(integerList.get(0));
+ List<Coord> points = line.getPoints();
+ newline.setPoints(points);
+ adder.add(newline);
+
+ // Force all following types to be added as lines rather than roads.
+ for (ListIterator<Integer> t=integerList.listIterator(1); t.hasNext(); ) {
+ newline = new MapLine(line);
+ newline.setType(t.next());
+ newline.setPoints(new ArrayList<Coord>(points));
+ adder.add(newline);
+ }
+ } else {
+ adder.add(line);
+ }
+ }
+
+ public Map<Integer, List<Integer>> getOverlays() {
+ return overlays;
+ }
+
+
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/RoadMerger.java b/src/uk/me/parabola/mkgmap/osmstyle/RoadMerger.java
new file mode 100644
index 0000000..766115f
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/RoadMerger.java
@@ -0,0 +1,627 @@
+/*
+ * Copyright (C) 2013.
+ *
+ * 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.osmstyle;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.GType;
+import uk.me.parabola.mkgmap.reader.osm.Node;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.RestrictionRelation;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.MultiIdentityHashMap;
+
+/**
+ * Merges connected roads with identical road relevant tags based on the OSM elements
+ * and the GType class.
+ *
+ * @author WanMil
+ */
+public class RoadMerger {
+ private static final Logger log = Logger.getLogger(RoadMerger.class);
+
+ private static final double MAX_MERGE_ANGLE = 130d;
+
+ /** maps which coord of a way(id) are restricted - they should not be merged */
+ private final MultiIdentityHashMap<Coord, Long> restrictions;
+ /** Contains a list of all roads (GType + Way) */
+ private final List<Road> roads;
+
+ /** maps the start point of a road to its road definition */
+ private final MultiIdentityHashMap<Coord, Road> startPoints = new MultiIdentityHashMap<Coord, Road>();
+ /** maps the end point of a road to its road definition */
+ private final MultiIdentityHashMap<Coord, Road> endPoints = new MultiIdentityHashMap<Coord, Road>();
+
+ /**
+ * Helper class to keep the Way and the GType object of a road.
+ * Also provides methods that are able to decide if two roads can
+ * be merged.
+ *
+ * @author WanMil
+ */
+ private static class Road {
+ /** gives the index of the original position in the way/road list */
+ private final int index;
+ private final Way way;
+ private final GType gtype;
+
+ /**
+ * For these tags two ways need to return the same value for {@link Way#isNotBoolTag(String)}
+ * so that their roads can be merged.
+ */
+ private final static Set<String> mergeTagsNotBool = new HashSet<String>() {
+ {
+ add("mkgmap:emergency");
+ add("mkgmap:delivery");
+ add("mkgmap:car");
+ add("mkgmap:bus");
+ add("mkgmap:taxi");
+ add("mkgmap:foot");
+ add("mkgmap:bicycle");
+ add("mkgmap:truck");
+ add("mkgmap:throughroute");
+ }
+ };
+
+ /**
+ * For these tags two ways need to return the same value for {@link Way#isBoolTag(String)}
+ * so that their roads can be merged.
+ */
+ private final static Set<String> mergeTagsBool = new HashSet<String>() {
+ {
+ add("mkgmap:carpool");
+ add("mkgmap:toll");
+ add("mkgmap:unpaved");
+ add("mkgmap:ferry");
+ }
+ };
+
+ /**
+ * For these tags two ways need to have an equal value so that their roads can be merged.
+ */
+ private final static Set<String> mergeTagsEqualValue = new HashSet<String>() {
+ {
+ add("mkgmap:label:1");
+ add("mkgmap:label:2");
+ add("mkgmap:label:3");
+ add("mkgmap:label:4");
+ add("mkgmap:postal_code");
+ add("mkgmap:city");
+ add("mkgmap:region");
+ add("mkgmap:country");
+ add("mkgmap:is_in");
+ add("mkgmap:skipSizeFilter");
+ add("junction");
+ add("mkgmap:synthesised");
+ add("mkgmap:flare-check");
+ }
+ };
+
+ public Road(int index, Way way, GType gtype) {
+ this.index = index;
+ this.way = way;
+ this.gtype = gtype;
+ }
+
+ /**
+ * Checks if the given {@code otherRoad} can be merged with this road at
+ * the given {@code mergePoint}.
+ * @param mergePoint the coord where this road and otherRoad might be merged
+ * @param otherRoad another road instance
+ * @return {@code true} this road can be merged with {@code otherRoad};
+ * {@code false} the roads cannot be merged at {@code mergePoint}
+ */
+ public boolean isMergable(Coord mergePoint, Road otherRoad) {
+ // first check if this road starts or stops at the mergePoint
+ Coord cStart = way.getPoints().get(0);
+ Coord cEnd = way.getPoints().get(way.getPoints().size() - 1);
+ if (cStart != mergePoint && cEnd != mergePoint) {
+ // it doesn't => roads not mergeable at mergePoint
+ return false;
+ }
+
+ // do the same check for the otherRoad
+ Coord cOtherStart = otherRoad.getWay().getPoints().get(0);
+ Coord cOtherEnd = otherRoad.getWay().getPoints()
+ .get(otherRoad.getWay().getPoints().size() - 1);
+ if (cOtherStart != mergePoint && cOtherEnd != mergePoint) {
+ // otherRoad does not start or stop at mergePoint =>
+ // roads not mergeable at mergePoint
+ return false;
+ }
+
+ // check if merging would create a closed way - which should not
+ // be done (why? WanMil)
+ if (cStart == cOtherEnd) {
+ return false;
+ }
+
+ // check if the GType objects are the same
+ if (isGTypeMergable(otherRoad.getGtype()) == false) {
+ return false;
+ }
+
+ // checks if the tag values of both ways match so that the ways
+ // can be merged
+ if (isWayMergable(mergePoint, otherRoad.getWay()) == false) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if the given GType can be merged with the GType of this road.
+ * @param otherGType the GType of the other road
+ * @return {@code true} both GType objects can be merged; {@code false} GType
+ * objects do not match and must not be merged
+ */
+ private boolean isGTypeMergable(GType otherGType) {
+ // log.info("Gtype1",gtype);
+ // log.info("Gtype2",otherGType);
+
+ // check all fields of the GType objects for equality
+
+ if (gtype.getType() != otherGType.getType()) {
+ return false;
+ }
+ if (gtype.getMinResolution() != otherGType.getMinResolution()) {
+ return false;
+ }
+ if (gtype.getMaxResolution() != otherGType.getMaxResolution()) {
+ return false;
+ }
+ if (gtype.getMinLevel() != otherGType.getMinLevel()) {
+ return false;
+ }
+ if (gtype.getMaxLevel() != otherGType.getMaxLevel()) {
+ return false;
+ }
+ if (gtype.getRoadClass() != otherGType.getRoadClass()){
+ return false;
+ }
+ if (gtype.getRoadSpeed() != otherGType.getRoadSpeed()){
+ return false;
+ }
+// default name is applied before the RoadMerger starts
+// so they needn't be equal
+// if (stringEquals(gtype.getDefaultName(),
+// otherGType.getDefaultName()) == false) {
+// return false;
+// }
+
+ // log.info("Matches");
+ return true;
+ }
+
+ /**
+ * Checks if the tag values of the {@link Way} objects of both roads
+ * match so that both roads can be merged.
+ * @param mergePoint the coord where both roads should be merged
+ * @param otherWay the way of the road to merge
+ * @return {@code true} tag values match so that both roads might be merged;
+ * {@code false} tag values differ so that road must not be merged
+ */
+ private boolean isWayMergable(Coord mergePoint, Way otherWay) {
+
+ // oneway must not only be checked for equal tag values
+ // but also for correct direction of both ways
+
+ // first map the different oneway values
+ String thisOneway = getWay().getTag("oneway");
+ // map oneway value for the other way
+ String otherOneway = otherWay.getTag("oneway");
+
+ if (stringEquals(thisOneway, otherOneway) == false) {
+ // the oneway tags differ => cannot merge
+ // (It might be possible to reverse the direction of one way
+ // but this might be implemented later)
+ log.debug("oneway does not match", way.getId(), "("
+ + thisOneway + ")", otherWay.getId(), "(" + otherOneway
+ + ")");
+ return false;
+
+ } else if ("yes".equals(thisOneway)) {
+ // the oneway tags match and both ways are oneway
+ // now check if both ways have the same direction
+
+ boolean thisStart = (getWay().getPoints().get(0) == mergePoint);
+ boolean otherStart = (otherWay.getPoints().get(0) == mergePoint);
+
+ if (thisStart == otherStart) {
+ // both ways are oneway but they have a different direction
+ log.warn("oneway with different direction", way.getId(),
+ otherWay.getId());
+ return false;
+ }
+ }
+ // oneway matches
+
+ // now check the other tag lists
+
+ // first: tags that need to have an equal value
+ for (String tagname : mergeTagsEqualValue) {
+ String thisTag = getWay().getTag(tagname);
+ String otherTag = otherWay.getTag(tagname);
+ if (stringEquals(thisTag, otherTag) == false) {
+ log.debug(tagname, "does not match", way.getId(), "("
+ + thisTag + ")", otherWay.getId(), "(" + otherTag
+ + ")");
+ // log.warn(way.getId(), way.toTagString());
+ // log.warn(otherWay.getId(), otherWay.toTagString());
+ return false;
+ }
+ }
+
+ // second: tags for which only the NotBool value must be equal
+ for (String tagname : mergeTagsNotBool) {
+ boolean thisNo = getWay().isNotBoolTag(tagname);
+ boolean otherNo = otherWay.isNotBoolTag(tagname);
+ if (thisNo != otherNo) {
+ log.debug(tagname, "does not match", way.getId(), "("
+ + getWay().getTag(tagname) + ")", otherWay.getId(),
+ "(" + otherWay.getTag(tagname) + ")");
+ return false;
+ }
+ }
+
+ // third: tags for which only the bool value must be equal
+ for (String tagname : mergeTagsBool) {
+ boolean thisYes = getWay().isBoolTag(tagname);
+ boolean otherYes = otherWay.isBoolTag(tagname);
+ if (thisYes != otherYes) {
+ log.debug(tagname, "does not match", way.getId(), "("
+ + getWay().getTag(tagname) + ")", otherWay.getId(),
+ "(" + otherWay.getTag(tagname) + ")");
+ return false;
+ }
+ }
+
+ // Check the angle of the two ways
+ Coord c1;
+ if (getWay().getPoints().get(0) == mergePoint) {
+ c1 = getWay().getPoints().get(1);
+ } else {
+ c1 = getWay().getPoints().get(getWay().getPoints().size() - 2);
+ }
+ Coord cOther;
+ if (otherWay.getPoints().get(0) == mergePoint) {
+ cOther = otherWay.getPoints().get(1);
+ } else {
+ cOther = otherWay.getPoints().get(
+ otherWay.getPoints().size() - 2);
+ }
+
+ double angle = Math.abs(Utils.getAngle(c1, mergePoint, cOther));
+ if (angle > MAX_MERGE_ANGLE) {
+ // The angle exceeds the limit => do not merge
+ // Don't know if this is really required or not.
+ // But the number of merges which do not succeed due to this
+ // restriction is quite low and there have been requests
+ // for this: http://www.mkgmap.org.uk/pipermail/mkgmap-dev/2013q3/018649.html
+
+ log.info("Do not merge ways",getWay().getId(),"and",otherWay.getId(),"because they span a too big angle",angle,"°");
+ return false;
+ }
+
+ return true;
+ }
+
+ public Way getWay() {
+ return way;
+ }
+
+ public GType getGtype() {
+ return gtype;
+ }
+
+ /**
+ * Checks if two strings are equal ({@code null} supported).
+ * @param s1 first string ({@code null} allowed)
+ * @param s2 second string ({@code null} allowed)
+ * @return {@code true} both strings are equal or both {@code null}; {@code false} both strings are not equal
+ */
+ private boolean stringEquals(String s1, String s2) {
+ if (s1 == null) {
+ return s2 == null;
+ } else {
+ return s1.equals(s2);
+ }
+ }
+
+ public String toString() {
+ return gtype + " " + way.getId() + " " + way.toTagString();
+ }
+
+ public final int getIndex() {
+ return index;
+ }
+ }
+
+ public RoadMerger(List<Way> ways, List<GType> gtypes,
+ Map<Coord, List<RestrictionRelation>> restrictions,
+ List<Relation> throughRouteRelations) {
+ assert ways.size() == gtypes.size();
+
+ this.roads = new ArrayList<Road>(ways.size());
+
+ for (int i = 0; i < ways.size(); i++) {
+ if (ways.get(i) != null)
+ roads.add(new Road(i, ways.get(i), gtypes.get(i)));
+ }
+
+ this.restrictions = new MultiIdentityHashMap<Coord, Long>();
+ workoutRestrictionRelations(restrictions);
+ workoutThroughRoutes(throughRouteRelations);
+ }
+
+ private void workoutRestrictionRelations(Map<Coord, List<RestrictionRelation>> restrictionRels) {
+ for (List<RestrictionRelation> rels : restrictionRels.values()) {
+ for (RestrictionRelation rel : rels) {
+ if (rel.getViaCoord() == null) {
+ continue;
+ }
+ if (rel.getFromWay() != null) {
+ restrictions.add(rel.getViaCoord(), rel.getFromWay().getId());
+ }
+ if (rel.getToWay() != null) {
+ restrictions.add(rel.getViaCoord(), rel.getToWay().getId());
+ }
+ }
+ }
+ }
+
+ private void workoutThroughRoutes(List<Relation> throughRouteRelations) {
+ for (Relation relation : throughRouteRelations) {
+ Node node = null;
+ Way w1 = null;
+ Way w2 = null;
+ for (Map.Entry<String, Element> member : relation.getElements()) {
+ if (member.getValue() instanceof Node) {
+ if (node == null)
+ node = (Node) member.getValue();
+ else
+ log.warn("Through route relation "
+ + relation.toBrowseURL()
+ + " has more than 1 node");
+ } else if (member.getValue() instanceof Way) {
+ Way w = (Way) member.getValue();
+ if (w1 == null)
+ w1 = w;
+ else if (w2 == null)
+ w2 = w;
+ else
+ log.warn("Through route relation "
+ + relation.toBrowseURL()
+ + " has more than 2 ways");
+ }
+ }
+
+ if (node == null)
+ log.warn("Through route relation " + relation.toBrowseURL()
+ + " is missing the junction node");
+
+ if (w1 == null || w2 == null)
+ log.warn("Through route relation "
+ + relation.toBrowseURL()
+ + " should reference 2 ways that meet at the junction node");
+
+ if (node != null && w1 != null && w2 != null) {
+ restrictions.add(node.getLocation(), w1.getId());
+ restrictions.add(node.getLocation(), w2.getId());
+ }
+ }
+ }
+
+ private boolean hasRestriction(Coord c, Way w) {
+ List<Long> wayRestrictions = restrictions.get(c);
+ return wayRestrictions.contains(w.getId());
+ }
+
+ /**
+ * Merges {@code road2} into {@code road1}. This means that
+ * only the way id and the tags of {@code road1} is kept.
+ * For the tag it should not matter because all tags used after the
+ * RoadMerger are compared to be the same.
+ *
+ * @param road1 first road (will keep the merged road)
+ * @param road2 second road
+ */
+ private void mergeRoads(Road road1, Road road2) {
+ // Removes the second line,
+ // Merges the points in the first one
+ List<Coord> points1 = road1.getWay().getPoints();
+ List<Coord> points2 = road2.getWay().getPoints();
+
+ Coord mergePoint = points2.get(0);
+ Coord endPoint= points2.get(points2.size()-1);
+
+ startPoints.remove(mergePoint, road2);
+ endPoints.remove(endPoint, road2);
+ endPoints.remove(mergePoint, road1);
+
+ points1.addAll(points2.subList(1, points2.size()));
+ endPoints.add(endPoint, road1);
+
+ // merge the POI info
+ String wayPOI2 = road2.getWay().getTag(StyledConverter.WAY_POI_NODE_IDS);
+ if (wayPOI2 != null){
+ String WayPOI1 = road1.getWay().getTag(StyledConverter.WAY_POI_NODE_IDS);
+ if (wayPOI2.equals(WayPOI1) == false){
+ if (WayPOI1 == null)
+ WayPOI1 = "";
+ // store combination of both ways. This might contain
+ // duplicates, but that is not a problem.
+ road1.getWay().addTag(StyledConverter.WAY_POI_NODE_IDS, WayPOI1 + wayPOI2);
+ }
+ }
+
+// // the mergePoint is now used by one highway less
+ mergePoint.decHighwayCount();
+
+ // road2 is removed - it must not be part of a restriction
+ assert (restrictions.get(endPoint).contains(road2.getWay().getId()) == false);
+
+ }
+
+ /**
+ * Merge the roads and copy the results to the given lists.
+ * @param resultingWays list for the merged (and not mergeable) ways
+ * @param resultingGTypes list for the merged (and not mergeable) GTypes
+ */
+ public void merge(List<Way> resultingWays, List<GType> resultingGTypes) {
+
+ int noRoadsBeforeMerge = this.roads.size();
+ int noMerges = 0;
+ List<Road> roadsToMerge = new ArrayList<Road>(this.roads);
+ this.roads.clear();
+
+ List<Coord> mergePoints = new ArrayList<>();
+
+ // first add all roads with their start and end points to the
+ // start/endpoint lists
+ for (Road road : roadsToMerge) {
+ List<Coord> points = road.getWay().getPoints();
+ Coord start = points.get(0);
+ Coord end = points.get(points.size() - 1);
+
+ if (start == end) {
+ // do not merge closed roads
+ roads.add(road);
+ continue;
+ }
+
+ mergePoints.add(start);
+ mergePoints.add(end);
+ startPoints.add(start, road);
+ endPoints.add(end, road);
+ }
+
+ // a set of all points where no more merging is possible
+ Set<Coord> mergeCompletedPoints = Collections.newSetFromMap(new IdentityHashMap<Coord, Boolean>());
+
+ // go through all start/end points and check if a merge is possible
+ for (Coord mergePoint : mergePoints) {
+ if (mergeCompletedPoints.contains(mergePoint)) {
+ // a previous run did not show any possible merge
+ // do not check again
+ continue;
+ }
+
+ // get all road that start with the merge point
+ List<Road> startRoads = startPoints.get(mergePoint);
+ // get all roads that end with the merge point
+ List<Road> endRoads = endPoints.get(mergePoint);
+
+ if (endRoads.isEmpty() || startRoads.isEmpty()) {
+ // this might happen if another merge operation changed endPoints and/or startPoints
+ mergeCompletedPoints.add(mergePoint);
+ continue;
+ }
+
+ // go through all combinations and test which combination is the best
+ double bestAngle = Double.MAX_VALUE;
+ Road mergeRoad1 = null;
+ Road mergeRoad2 = null;
+
+ for (Road road1 : endRoads) {
+ // check if the road has a restriction at the merge point
+ // which does not allow us to merge the road at this point
+ if (hasRestriction(mergePoint, road1.getWay())) {
+ continue;
+ }
+
+ List<Coord> points1 = road1.getWay().getPoints();
+
+ // go through all candidates to merge
+ for (Road road2 : startRoads) {
+ if (hasRestriction(mergePoint, road2.getWay())) {
+ continue;
+ }
+ List<Coord> points2 = road2.getWay().getPoints();
+
+ // the second road is merged into the first road
+ // so only the id of the first road is kept
+ // This also means that the second road must not have a restriction on
+ // both start and end point
+ if (hasRestriction(points2.get(points2.size()-1), road2.getWay())) {
+ continue;
+ }
+
+ // check if both roads can be merged
+ if (road1.isMergable(mergePoint, road2)) {
+ // yes they might be merged
+ // calculate the angle between them
+ // if there is more then one road to merge the one with the lowest angle is merged
+ double angle = Math.abs(Utils.getAngle(points1.get(points1.size()-2), mergePoint, points2.get(1)));
+ log.debug("Road",road1.getWay().getId(),"and road",road2.getWay().getId(),"are mergeable with angle",angle);
+ if (angle < bestAngle) {
+ mergeRoad1 = road1;
+ mergeRoad2 = road2;
+ bestAngle = angle;
+ }
+ }
+ }
+ }
+
+ // is there a pair of roads that can be merged?
+ if (mergeRoad1 != null && mergeRoad2 != null) {
+ // yes!! => merge them
+ log.debug("Merge",mergeRoad1.getWay().getId(),"and",mergeRoad2.getWay().getId(),"with angle",bestAngle);
+ mergeRoads(mergeRoad1, mergeRoad2);
+ noMerges++;
+ } else {
+ // no => do not check again this point again
+ mergeCompletedPoints.add(mergePoint);
+ }
+ }
+
+ // copy all merged roads to the roads list
+ for (List<Road> mergedRoads : endPoints.values()) {
+ this.roads.addAll(mergedRoads);
+ }
+
+ // sort the roads to ensure that the order of roads is constant for two runs
+ Collections.sort(this.roads, new Comparator<Road>() {
+ public int compare(Road o1, Road o2) {
+ return Integer.compare(o1.getIndex(), o2.getIndex());
+ }
+ });
+
+ // copy the roads to the resulting lists
+ for (Road r : roads) {
+ resultingWays.add(r.getWay());
+ resultingGTypes.add(r.getGtype());
+ }
+
+ // print out some statistics
+ int noRoadsAfterMerge = this.roads.size();
+ log.info("Roads before/after merge:", noRoadsBeforeMerge, "/",
+ noRoadsAfterMerge);
+ int percentage = (int) Math.round((noRoadsBeforeMerge - noRoadsAfterMerge) * 100.0d
+ / noRoadsBeforeMerge);
+ log.info("Road network reduced by", percentage, "%",noMerges,"merges");
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/RuleDetails.java b/src/uk/me/parabola/mkgmap/osmstyle/RuleDetails.java
new file mode 100644
index 0000000..5ceaf71
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/RuleDetails.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.osmstyle;
+
+import java.util.Set;
+
+import uk.me.parabola.mkgmap.reader.osm.Rule;
+
+/**
+ * Holds the key string, rule and tags that can be changed by the rule.
+ * @author Steve Ratcliffe
+ */
+class RuleDetails {
+ private final String keystring;
+ private final Rule rule;
+ private final Set<String> changingTags;
+
+ RuleDetails(String keystring, Rule rule, Set<String> changingTags) {
+ this.keystring = keystring;
+ this.rule = rule;
+ this.changingTags = changingTags;
+ }
+
+ public String getKeystring() {
+ return keystring;
+ }
+
+ public Rule getRule() {
+ return rule;
+ }
+
+ public Set<String> getChangingTags() {
+ return changingTags;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java b/src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java
new file mode 100644
index 0000000..ee115b0
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java
@@ -0,0 +1,546 @@
+/*
+ * Copyright (C) 2008, 2012 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 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.
+ *
+ *
+ * Author: Steve Ratcliffe
+ * Create date: 02-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.Reader;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.LevelInfo;
+import uk.me.parabola.mkgmap.osmstyle.actions.ActionList;
+import uk.me.parabola.mkgmap.osmstyle.actions.ActionReader;
+import uk.me.parabola.mkgmap.osmstyle.eval.AndOp;
+import uk.me.parabola.mkgmap.osmstyle.eval.BinaryOp;
+import uk.me.parabola.mkgmap.osmstyle.eval.ExistsOp;
+import uk.me.parabola.mkgmap.osmstyle.eval.ExpressionReader;
+import uk.me.parabola.mkgmap.osmstyle.eval.LinkedOp;
+import uk.me.parabola.mkgmap.osmstyle.eval.NodeType;
+import uk.me.parabola.mkgmap.osmstyle.eval.Op;
+import uk.me.parabola.mkgmap.osmstyle.eval.OrOp;
+import uk.me.parabola.mkgmap.osmstyle.eval.ValueOp;
+import uk.me.parabola.mkgmap.osmstyle.function.StyleFunction;
+import uk.me.parabola.mkgmap.reader.osm.FeatureKind;
+import uk.me.parabola.mkgmap.reader.osm.GType;
+import uk.me.parabola.mkgmap.reader.osm.Rule;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+import uk.me.parabola.mkgmap.scan.TokType;
+import uk.me.parabola.mkgmap.scan.Token;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+import static uk.me.parabola.mkgmap.osmstyle.eval.NodeType.*;
+
+/**
+ * Read a rules file. A rules file contains a list of rules and the
+ * resulting garmin type, should the rule match.
+ *
+ * @author Steve Ratcliffe
+ */
+public class RuleFileReader {
+ private static final Logger log = Logger.getLogger(RuleFileReader.class);
+
+ private final FeatureKind kind;
+ private final TypeReader typeReader;
+
+ private final RuleSet rules;
+ private RuleSet finalizeRules;
+ private final boolean performChecks;
+ private final Map<Integer, List<Integer>> overlays;
+
+ private boolean inFinalizeSection = false;
+
+ public RuleFileReader(FeatureKind kind, LevelInfo[] levels, RuleSet rules, boolean performChecks,
+ Map<Integer, List<Integer>> overlays) {
+ this.kind = kind;
+ this.rules = rules;
+ this.performChecks = performChecks;
+ this.overlays = overlays;
+ typeReader = new TypeReader(kind, levels);
+ }
+
+ /**
+ * Read a rules file.
+ * @param loader A file loader.
+ * @param name The name of the file to open.
+ * @throws FileNotFoundException If the given file does not exist.
+ */
+ public void load(StyleFileLoader loader, String name) throws FileNotFoundException {
+ loadFile(loader, name);
+ rules.prepare();
+ if (finalizeRules != null) {
+ finalizeRules.prepare();
+ rules.setFinalizeRule(finalizeRules);
+ }
+ }
+
+ /**
+ * Load a rules file. This should be used when calling recursively when including
+ * files.
+ */
+ private void loadFile(StyleFileLoader loader, String name) throws FileNotFoundException {
+ Reader r = loader.open(name);
+ TokenScanner scanner = new TokenScanner(name, r);
+ scanner.setExtraWordChars("-:.");
+
+ ExpressionReader expressionReader = new ExpressionReader(scanner, kind);
+ ActionReader actionReader = new ActionReader(scanner);
+
+ // Read all the rules in the file.
+ scanner.skipSpace();
+ while (!scanner.isEndOfFile()) {
+ if (checkCommand(loader, scanner))
+ continue;
+
+ if (scanner.isEndOfFile())
+ break;
+
+ Op expr = expressionReader.readConditions();
+
+ ActionList actionList = actionReader.readActions();
+
+ // If there is an action list, then we don't need a type
+ GType type = null;
+ if (scanner.checkToken("["))
+ type = typeReader.readType(scanner, performChecks, overlays);
+ else if (actionList == null)
+ throw new SyntaxException(scanner, "No type definition given");
+
+ saveRule(scanner, expr, actionList, type);
+ scanner.skipSpace();
+ }
+
+ rules.addUsedTags(expressionReader.getUsedTags());
+ rules.addUsedTags(actionReader.getUsedTags());
+ }
+
+ /**
+ * Check for a keyword that introduces a command.
+ *
+ * Commands are context sensitive, if a keyword is used is part of an expression, then it must still
+ * work. In other words the following is valid:
+ * <pre>
+ * include 'filename';
+ *
+ * include=yes [0x02 ...]
+ * </pre>
+ * To achieve this the keyword is a) not quoted, b) is followed by text or quoted text or some symbol that cannot
+ * be part of an expression.
+ *
+ * Called before reading an expression, must put back any token (apart from whitespace) if there is
+ * not a command.
+ * @return true if a command was found. The caller should check again for a command.
+ * @param currentLoader The current style loader. Any included files are loaded from here, if no other
+ * style is specified.
+ * @param scanner The current token scanner.
+ */
+ private boolean checkCommand(StyleFileLoader currentLoader, TokenScanner scanner) {
+ scanner.skipSpace();
+ if (scanner.isEndOfFile())
+ return false;
+
+ if (scanner.checkToken("include")) {
+ // Consume the 'include' token and skip spaces
+ Token token = scanner.nextToken();
+ scanner.skipSpace();
+
+ // If include is being used as a keyword then it is followed by a word or a quoted word.
+ Token next = scanner.peekToken();
+ if (next.getType() == TokType.TEXT
+ || (next.getType() == TokType.SYMBOL && (next.isValue("'") || next.isValue("\""))))
+ {
+ String filename = scanner.nextWord();
+
+ StyleFileLoader loader = currentLoader;
+ scanner.skipSpace();
+
+ // The include can be followed by an optional 'from' clause. The file is read from the given
+ // style-name in that case.
+ if (scanner.checkToken("from")) {
+ scanner.nextToken();
+ String styleName = scanner.nextWord();
+ if (styleName.equals(";"))
+ throw new SyntaxException(scanner, "No style name after 'from'");
+
+ try {
+ loader = StyleFileLoader.createStyleLoader(null, styleName);
+ } catch (FileNotFoundException e) {
+ throw new SyntaxException(scanner, "Cannot find style: " + styleName);
+ }
+ }
+
+ scanner.validateNext(";");
+
+ try {
+ loadFile(loader, filename);
+ return true;
+ } catch (FileNotFoundException e) {
+ throw new SyntaxException(scanner, "Cannot open included file: " + filename);
+ } finally {
+ if (loader != currentLoader)
+ Utils.closeFile(loader);
+ }
+ } else {
+ // Wrong syntax for include statement, so push back token to allow a possible expression to be read
+ scanner.pushToken(token);
+ }
+ }
+ // check if it is the start label of the <finalize> section
+ else if (scanner.checkToken("<")) {
+ Token token = scanner.nextToken();
+ if (scanner.checkToken("finalize")) {
+ Token finalizeToken = scanner.nextToken();
+ if (scanner.checkToken(">")) {
+ if (inFinalizeSection) {
+ // there are two finalize sections which is not allowed
+ throw new SyntaxException(scanner, "There is only one finalize section allowed");
+ } else {
+ // consume the > token
+ scanner.nextToken();
+ // mark start of the finalize block
+ inFinalizeSection = true;
+ finalizeRules = new RuleSet();
+ return true;
+ }
+ } else {
+ scanner.pushToken(finalizeToken);
+ scanner.pushToken(token);
+ }
+ } else {
+ scanner.pushToken(token);
+ }
+ }
+ scanner.skipSpace();
+ return false;
+ }
+
+ /**
+ * Save the expression as a rule. We need to extract an index such
+ * as highway=primary first and then add the rest of the expression as
+ * the condition for it.
+ *
+ * So in other words each condition is dropped into a number of different
+ * baskets based on the first 'tag=value' term. We then only look
+ * for expressions that are in the correct basket. For each expression
+ * in a basket we know that the first term is true so we can drop that
+ * from the expression.
+ */
+ private void saveRule(TokenScanner scanner, Op op, ActionList actions, GType gt) {
+ log.info("EXP", op, ", type=", gt);
+
+ // check if the type definition is allowed
+ if (inFinalizeSection && gt != null)
+ throw new SyntaxException(scanner, "Element type definition is not allowed in <finalize> section");
+
+ //System.out.println("From: " + op);
+ Op op2 = rearrangeExpression(op);
+ //System.out.println("TO : " + op2);
+
+ if (op2 instanceof BinaryOp) {
+ optimiseAndSaveBinaryOp(scanner, (BinaryOp) op2, actions, gt);
+ } else {
+ optimiseAndSaveOtherOp(scanner, op2, actions, gt);
+ }
+ }
+
+ /**
+ * Rearrange the expression so that it is solvable, that is it starts with
+ * an EQUALS or an EXISTS.
+ * @param op The expression to be rearranged.
+ * @return An equivalent expression re-arranged so that it starts with an
+ * indexable term. If that is not possible then the original expression is
+ * returned.
+ */
+ private static Op rearrangeExpression(Op op) {
+ if (isFinished(op))
+ return op;
+
+ if (op.isType(AND)) {
+ // Recursively re-arrange the child nodes
+ rearrangeExpression(op.getFirst());
+ rearrangeExpression(op.getSecond());
+
+ swapForSelectivity((BinaryOp) op);
+ Op op1 = op.getFirst();
+ Op op2 = op.getSecond();
+
+ // If the first term is an EQUALS or EXISTS then this subtree is
+ // already solved and we need to do no more.
+ if (isSolved(op1)) {
+ return rearrangeAnd((BinaryOp) op, op1, op2);
+ } else if (isSolved(op2)) {
+ return rearrangeAnd((BinaryOp) op, op2, op1);
+ }
+ }
+
+ return op;
+ }
+
+ /**
+ * Swap the terms so that the most selective or fastest term to calculate
+ * is first.
+ * @param op A AND operation.
+ */
+ private static void swapForSelectivity(BinaryOp op) {
+ Op first = op.getFirst();
+ int sel1 = selectivity(first);
+ Op second = op.getSecond();
+ int sel2 = selectivity(second);
+ if (sel1 > sel2) {
+ op.setFirst(second);
+ op.setSecond(first);
+ }
+ }
+
+ /**
+ * Rearrange an AND expression so that it can be executed with indexable
+ * terms at the front.
+ * @param top This will be an AndOp.
+ * @param op1 This is a child of top that is guaranteed to be
+ * solved already.
+ * @param op2 This expression is the other child of top.
+ * @return A re-arranged expression with an indexable term at the beginning
+ * or several such expressions ORed together.
+ */
+ private static BinaryOp rearrangeAnd(BinaryOp top, Op op1, Op op2) {
+ if (isIndexable(op1)) {
+ top.setFirst(op1);
+ top.setSecond(op2);
+ return top;
+ } else if (op1.isType(AND)) {
+ // The first term is AND.
+ // If its first term is indexable (EQUALS or EXIST) then we
+ // re-arrange the tree so that that term is first.
+ Op first = op1.getFirst();
+ if (isIndexable(first)) {
+ top.setFirst(first);
+ op1.setFirst(op2);
+ swapForSelectivity((AndOp) op1);
+ top.setSecond(op1);
+ return top;
+ }
+ } else if (op1.isType(OR)) {
+ // Transform ((first | second) & topSecond)
+ // into (first & topSecond) | (second & topSecond)
+
+ Op first = op1.getFirst();
+ OrOp orOp = new OrOp();
+
+ Op topSecond = top.getSecond();
+
+ AndOp and1 = new AndOp();
+ and1.setFirst(first);
+ and1.setSecond(topSecond);
+
+ AndOp and2 = new AndOp();
+ Op second = rearrangeExpression(op1.getSecond());
+ and2.setFirst(second);
+ and2.setSecond(topSecond);
+
+ orOp.setFirst(and1);
+ orOp.setSecond(and2);
+ return orOp;
+ } else {
+ // This shouldn't happen
+ throw new SyntaxException("X3:" + op1.getType());
+ }
+ return top;
+ }
+
+ /**
+ * True if this operation can be indexed. It is a plain equality or
+ * Exists operation.
+ */
+ private static boolean isIndexable(Op op) {
+ return (op.isType(EQUALS)
+ && ((ValueOp) op.getFirst()).isIndexable() && op.getSecond().isType(VALUE))
+ || (op.isType(EXISTS) && ((ValueOp) op.getFirst()).isIndexable());
+ }
+
+ /**
+ * True if this expression is 'solved'. This means that the first term
+ * is indexable or it is indexable itself.
+ */
+ private static boolean isSolved(Op op) {
+ return isIndexable(op) || isIndexable(op.getFirst());
+ }
+
+ /**
+ * True if there is nothing more that we can do to rearrange this expression.
+ * It is either solved or it cannot be solved.
+ */
+ private static boolean isFinished(Op op) {
+ // If we can improve the ordering then we are not done just yet
+ if (op.isType(AND) && selectivity(op.getFirst()) > selectivity(op.getSecond()))
+ return false;
+
+ if (isSolved(op))
+ return true;
+
+ NodeType type = op.getType();
+ switch (type) {
+ case AND:
+ return false;
+ case OR:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * Get a value for how selective this operation is. We try to bring
+ * EQUALS to the front followed by EXISTS. Without knowing tag
+ * frequency you can only guess at what the most selective operations
+ * are, so all we do is arrange EQUALS - EXISTS - everything else.
+ * Note that you must have an EQUALS or EXISTS first, so you can't
+ * bring anything else earlier than them.
+ *
+ * @return An integer, lower values mean the operation should be earlier
+ * in the expression than operations with higher values.
+ */
+ private static int selectivity(Op op) {
+ switch (op.getType()) {
+ case EQUALS:
+ return 0;
+ case EXISTS:
+ return 10;
+
+ case AND:
+ case OR:
+ return Math.min(selectivity(op.getFirst()), selectivity(op.getSecond()));
+
+ default:
+ return 1000;
+ }
+ }
+
+ private void optimiseAndSaveOtherOp(TokenScanner scanner, Op op, ActionList actions, GType gt) {
+ if (op.isType(EXISTS)) {
+ // The lookup key for the exists operation is 'tag=*'
+ createAndSaveRule(op.getFirst().getKeyValue() + "=*", op, actions, gt);
+ } else {
+ throw new SyntaxException(scanner, "Cannot start expression with: " + op);
+ }
+ }
+
+ /**
+ * Optimise the expression tree, extract the primary key and
+ * save it as a rule.
+ * @param scanner The token scanner, used for error message file/line numbers.
+ * @param op a binary expression
+ * @param actions list of actions to execute on match
+ * @param gt the Garmin type of the element
+ */
+ private void optimiseAndSaveBinaryOp(TokenScanner scanner, BinaryOp op, ActionList actions, GType gt) {
+ Op first = op.getFirst();
+ Op second = op.getSecond();
+
+ log.debug("binop", op.getType(), first.getType());
+
+ /*
+ * We allow the following cases:
+ * An EQUALS at the top.
+ * An AND at the top level.
+ * An OR at the top level.
+ */
+ String keystring;
+ if (op.isType(EQUALS) && (first.isType(FUNCTION) && second.isType(VALUE))) {
+ keystring = first.getKeyValue() + "=" + second.getKeyValue();
+ } else if (op.isType(AND)) {
+ if (first.isType(EQUALS)) {
+ keystring = first.getFirst().getKeyValue() + "=" + first.getSecond().getKeyValue();
+ } else if (first.isType(EXISTS)) {
+ keystring = first.getFirst().getKeyValue() + "=*";
+ } else if (first.isType(NOT_EXISTS)) {
+ throw new SyntaxException(scanner, "Cannot start rule with tag!=*");
+ } else {
+ throw new SyntaxException(scanner, "Invalid rule expression: " + op);
+ }
+ } else if (op.isType(OR)) {
+ LinkedOp op1 = LinkedOp.create(first, true);
+ saveRule(scanner, op1, actions, gt);
+
+ saveRestOfOr(scanner, actions, gt, second, op1);
+ return;
+ } else {
+ if (!first.isType(FUNCTION) || !((StyleFunction) first).isIndexable())
+ throw new SyntaxException("Cannot use " + first + " without tag matches");
+
+ // We can make every other binary op work by converting to AND(EXISTS, op), as long as it does
+ // not involve an un-indexable function.
+ Op existsOp = new ExistsOp();
+ existsOp.setFirst(first);
+
+ AndOp andOp = new AndOp();
+ andOp.setFirst(existsOp);
+ andOp.setSecond(op);
+ optimiseAndSaveBinaryOp(scanner, andOp, actions, gt);
+ return;
+ }
+
+ createAndSaveRule(keystring, op, actions, gt);
+ }
+
+ private void saveRestOfOr(TokenScanner scanner, ActionList actions, GType gt, Op second, LinkedOp op1) {
+ if (second.isType(OR)) {
+ LinkedOp nl = LinkedOp.create(second.getFirst(), false);
+ op1.setLink(nl);
+ saveRule(scanner, nl, actions, gt);
+ saveRestOfOr(scanner, actions, gt, second.getSecond(), op1);
+ } else {
+ LinkedOp op2 = LinkedOp.create(second, false);
+ op1.setLink(op2);
+ saveRule(scanner, op2, actions, gt);
+ }
+ }
+
+ private void createAndSaveRule(String keystring, Op expr, ActionList actions, GType gt) {
+
+ Rule rule;
+ if (actions.isEmpty())
+ rule = new ExpressionRule(expr, gt);
+ else
+ rule = new ActionRule(expr, actions.getList(), gt);
+
+ if (inFinalizeSection)
+ finalizeRules.add(keystring, rule, actions.getChangeableTags());
+ else
+ rules.add(keystring, rule, actions.getChangeableTags());
+ }
+
+ public static void main(String[] args) throws FileNotFoundException {
+ if (args.length > 0) {
+ RuleSet rs = new RuleSet();
+ RuleFileReader rr = new RuleFileReader(FeatureKind.POLYLINE,
+ LevelInfo.createFromString("0:24 1:20 2:18 3:16 4:14"), rs, false,
+ Collections.<Integer, List <Integer>>emptyMap());
+
+ StyleFileLoader loader = new DirectoryFileLoader(
+ new File(args[0]).getAbsoluteFile().getParentFile());
+ String fname = new File(args[0]).getName();
+ rr.load(loader, fname);
+
+ System.out.println("Result: " + rs);
+ } else {
+ System.err.println("Usage: RuleFileReader <file>");
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/RuleIndex.java b/src/uk/me/parabola/mkgmap/osmstyle/RuleIndex.java
new file mode 100644
index 0000000..30a803f
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/RuleIndex.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.osmstyle;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import uk.me.parabola.mkgmap.reader.osm.Rule;
+
+/**
+ * An index to reduce the number of rules that have to be executed.
+ *
+ * <p>Only the first term (after rearrangement) of the rule is used in the
+ * index. This will (currently) always be an EQUALS or EXISTS (A=B or A=*).
+ *
+ * <p>We look at the tags of the element and pick out all rules that have the
+ * first term that matches the tag=value and tag=*, this is done by a single
+ * lookup for each tag in the element (on average a low number such as 3).
+ *
+ * <p>So if the element had the one tag highway=primary and the rules were as
+ * follows:
+ *
+ * <pre>
+ * 1 surface=good { ... }
+ * 2 highway=secondary { set fence=no; }
+ * 3 highway=primary { set surface=good; }
+ * 4 highway=* & abc=yes { }
+ * 5 surface=good { }
+ * 6 oneway=yes & highway=primary { }
+ * </pre>
+ *
+ * We would select rules 3 and 4. No other rule can match initially. But there
+ * is a further issue; if rule 3 matched it could set the surface tag. So we also
+ * need to select rule 5. Rule 1 can not be matched because it occurs before
+ * the rule that sets the tag, so it is not included. All this is precomputed
+ * when the index is created, so we can still do a single lookup.
+ *
+ * <p>So the full set of rules that we need to match is 3, 4 and 5.
+ * If rule 5 itself sets a tag, then we might have to add more rules and
+ * so on.
+ *
+ * @author Steve Ratcliffe
+ */
+public class RuleIndex {
+ private final List<RuleDetails> ruleDetails = new ArrayList<RuleDetails>();
+
+ // This is an index of all rules that start with EQUALS (A=B)
+ private final Map<String, BitSet> existKeys = new HashMap<String, BitSet>();
+ // This is an index of all rules that start with EXISTS (A=*)
+ private final Map<String, BitSet> tagVals = new HashMap<String, BitSet>();
+ // This is an index of all rules by the tag name (A).
+ private final Map<String, BitSet> tagnames = new HashMap<String, BitSet>();
+
+ // Maps a rule number to the tags that might be changed by that rule
+ private final Map<Integer, List<String>> changeTags = new HashMap<Integer, List<String>>();
+
+ private boolean inited;
+
+ /**
+ * Save the rule and maintains several lists related to it from the other
+ * information that is supplied.
+ * @param rd Contains 1) the key string which is the key into the index.
+ * 2) the rule itself. 3) a list of the tags that might be changed by
+ * this rule, should it be matched.
+ */
+ public void addRuleToIndex(RuleDetails rd) {
+ assert !inited;
+ int ruleNumber = ruleDetails.size();
+ String keystring = rd.getKeystring();
+ Set<String> changeableTags = rd.getChangingTags();
+
+ if (keystring.endsWith("=*")) {
+ String key = keystring.substring(0, keystring.length() - 2);
+ addExists(key, ruleNumber);
+ addUnknowns(key, ruleNumber);
+ } else {
+ addKeyVal(keystring, ruleNumber);
+ int ind = keystring.indexOf('=');
+ if (ind >= 0) {
+ String key = keystring.substring(0, ind);
+ addUnknowns(key, ruleNumber);
+ }
+ }
+
+ addChangables(changeableTags, ruleNumber);
+ ruleDetails.add(rd);
+ }
+
+ /**
+ * Get all the rules that have been added. This is used in the RuleSet
+ * for looking up by number.
+ * @return The rules as an array for quick lookup.
+ */
+ public Rule[] getRules() {
+ int len = ruleDetails.size();
+ Rule[] rules = new Rule[len];
+ for (int i = 0, ruleDetailsSize = ruleDetails.size(); i < ruleDetailsSize; i++) {
+ RuleDetails rd = ruleDetails.get(i);
+ rules[i] = rd.getRule();
+ }
+ return rules;
+ }
+
+ /**
+ * Get a list of rules that might be matched by this tag.
+ * @param tagval The tag and its value eg highway=primary.
+ * @return A BitSet of rules numbers.
+ * If there are no rules then null will be returned.
+ */
+ public BitSet getRulesForTag(String tagval) {
+ BitSet set = tagVals.get(tagval);
+
+ // Need to also look up all rules that might match highway=*
+ int i = tagval.indexOf('=');
+ String s2 = tagval.substring(0, i);
+ BitSet set2 = existKeys.get(s2);
+
+ BitSet res = new BitSet();
+ if (set != null)
+ res.or(set);
+ if (set2 != null)
+ res.or(set2);
+ return res;
+ }
+
+ /**
+ * Prepare the index for use. This involves merging in all the possible
+ * rules that could be run as a result of actions changing tags.
+ */
+ public void prepare() {
+ for (Map.Entry<Integer, List<String>> ent : changeTags.entrySet()) {
+ int ruleNumber = ent.getKey();
+ List<String> changeTagList = ent.getValue();
+
+ // When we add new rules, we may, in turn get more changeable tags
+ // which will force us to run again to find more rules that could
+ // be executed. So save rules that we find here.
+ Set<String> newChanged = new HashSet<String>(changeTagList);
+ // we have to find all rules that might be now matched
+ do {
+ for (String s : new ArrayList<String>(newChanged)) {
+ BitSet set;
+
+ // If we know the value that could be set, then we can restrict to
+ // rules that would match that value. Otherwise we look for any
+ // rule using the tag, no matter what the value.
+ int ind = s.indexOf('=');
+ if (ind >= 0) {
+ set = tagVals.get(s);
+
+ // Exists rules can also be triggered, so add them too.
+ String key = s.substring(0, ind);
+ BitSet set1 = existKeys.get(key);
+
+ if (set == null)
+ set = set1;
+ else if (set1 != null)
+ set.or(set1);
+
+ } else {
+ set = tagnames.get(s);
+ }
+
+ if (set != null && !set.isEmpty()) {
+ // create copy that can be safely modified
+ BitSet tmp = new BitSet();
+ tmp.or(set);
+ set = tmp;
+
+ for (int i = set.nextSetBit(0); i >= 0; i = set.nextSetBit(i + 1)) {
+ // Only rules after this one can be affected
+ if (i > ruleNumber) {
+ newChanged.addAll(ruleDetails.get(i).getChangingTags());
+ } else {
+ set.clear(i);
+ }
+ }
+
+ // Find every rule number set that contains the rule number that we
+ // are examining and add all the newly found rules to each such set.
+ for (Map<String, BitSet> m : Arrays.asList(existKeys, tagVals, tagnames)) {
+ Collection<BitSet> bitSets = m.values();
+ for (BitSet bi : bitSets) {
+ if (bi.get(ruleNumber)) {
+ // contains the rule that we are looking at so we must
+ // also add the rules in the set we found.
+ bi.or(set);
+ }
+ }
+ }
+ }
+ }
+
+ newChanged.removeAll(changeTagList);
+ changeTagList.addAll(newChanged);
+ } while (!newChanged.isEmpty());
+ }
+
+ inited = true;
+ }
+
+ private void addExists(String keystring, int ruleNumber) {
+ addNumberToMap(existKeys, keystring, ruleNumber);
+ }
+
+ private void addKeyVal(String keystring, int ruleNumber) {
+ addNumberToMap(tagVals, keystring, ruleNumber);
+
+ }
+
+ private void addUnknowns(String keystring, int ruleNumber) {
+ addNumberToMap(tagnames, keystring, ruleNumber);
+ }
+
+ private void addNumberToMap(Map<String, BitSet> map, String key, int ruleNumber) {
+ BitSet set = map.get(key);
+ if (set == null) {
+ set = new BitSet();
+ map.put(key, set);
+ }
+ set.set(ruleNumber);
+ }
+
+ /**
+ * For each rule number, we maintain a list of tags that might be
+ * changed by that rule.
+ * @param changeableTags The tags that might be changed if the rule is
+ * matched.
+ * @param ruleNumber The rule number.
+ */
+ private void addChangables(Set<String> changeableTags, int ruleNumber) {
+ List<String> tags = changeTags.get(ruleNumber);
+ if (tags == null) {
+ tags = new ArrayList<String>();
+ changeTags.put(ruleNumber, tags);
+ }
+ tags.addAll(changeableTags);
+ }
+
+ public List<RuleDetails> getRuleDetails() {
+ return ruleDetails;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java b/src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java
new file mode 100644
index 0000000..b816035
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2008 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: 08-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle;
+
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.Rule;
+import uk.me.parabola.mkgmap.reader.osm.TypeResult;
+import uk.me.parabola.mkgmap.reader.osm.WatchableTypeResult;
+
+/**
+ * A list of rules and the logic to select the correct one.
+ *
+ * A separate {@link RuleIndex} class is used to speed access to the rule list.
+ *
+ * @author Steve Ratcliffe
+ */
+public class RuleSet implements Rule, Iterable<Rule> {
+ private Rule[] rules;
+
+ private RuleIndex index = new RuleIndex();
+ private final Set<String> usedTags = new HashSet<String>();
+
+ /**
+ * Resolve the type for this element by running the rules in order.
+ *
+ * This is a very performance critical part of the style system as parts
+ * of the code are run for every tag in the input file.
+ *
+ * @param el The element as read from an OSM xml file in 'tag' format.
+ * @param result A GType describing the Garmin type of the first rule that
+ * matches is returned here. If continue types are used then more than
+ * one type may be saved here. If there are no matches then nothing will
+ * be saved.
+ */
+ public void resolveType(Element el, TypeResult result) {
+ WatchableTypeResult a = new WatchableTypeResult(result);
+
+ // Get all the rules that could match from the index.
+ BitSet candidates = new BitSet();
+ for (String tag : el) {
+ BitSet rules = index.getRulesForTag(tag);
+ if (rules != null)
+ candidates.or(rules);
+ }
+
+ for (int i = candidates.nextSetBit(0); i >= 0; i = candidates.nextSetBit(i + 1)) {
+ a.reset();
+ rules[i].resolveType(el, a);
+ if (a.isResolved())
+ return;
+ }
+ }
+
+ public Iterator<Rule> iterator() {
+ if (rules == null)
+ prepare();
+ return Arrays.asList(rules).iterator();
+ }
+
+ /**
+ * Add a rule to this rule set.
+ * @param keystring The string form of the first term of the rule. It will
+ * be A=B or A=*. (In the future we may allow other forms).
+ * @param rule The actual rule.
+ * @param changeableTags The tags that may be changed by the rule. This
+ * will be either a plain tag name A, or with a value A=B.
+ */
+ public void add(String keystring, Rule rule, Set<String> changeableTags) {
+ index.addRuleToIndex(new RuleDetails(keystring, rule, changeableTags));
+ }
+
+ /**
+ * Add all rules from the given rule set to this one.
+ * @param rs The other rule set.
+ */
+ public void addAll(RuleSet rs) {
+ for (RuleDetails rd : rs.index.getRuleDetails())
+ add(rd.getKeystring(), rd.getRule(), rd.getChangingTags());
+ }
+
+ /**
+ * Format the rule set. Warning: this doesn't produce a valid input
+ * rule file.
+ */
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (Rule rule : rules) {
+ sb.append(rule.toString());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Merge the two rulesets together so that they appear to be one.
+ * @param rs The other rule set, it will have lower priority, that is the
+ * rules will be tried after the rules of this ruleset.
+ */
+ public void merge(RuleSet rs) {
+ // We have to basically rebuild the index and reset the rule list.
+ RuleIndex newIndex = new RuleIndex();
+
+ for (RuleDetails rd : index.getRuleDetails())
+ newIndex.addRuleToIndex(rd);
+
+ for (RuleDetails rd : rs.index.getRuleDetails())
+ newIndex.addRuleToIndex(rd);
+
+ index = newIndex;
+ rules = newIndex.getRules();
+ //System.out.println("Merging used tags: "
+ // + getUsedTags().toString()
+ // + " + "
+ // + rs.getUsedTags());
+ addUsedTags(rs.usedTags);
+ //System.out.println("Result: " + getUsedTags().toString());
+ }
+
+ /**
+ * Prepare this rule set for use. The index is built and and the rules
+ * are saved to an array for fast access.
+ */
+ public void prepare() {
+ index.prepare();
+ rules = index.getRules();
+ }
+
+ public Set<String> getUsedTags() {
+ return usedTags;
+ }
+
+ public void addUsedTags(Collection<String> usedTags) {
+ this.usedTags.addAll(usedTags);
+ }
+
+ public void setFinalizeRule(Rule finalizeRule) {
+ if (rules == null) {
+ // this method must be called after prepare() is called so
+ // that we have rules to which the finalize rules can be applied
+ throw new IllegalStateException("First call prepare() before setting the finalize rules");
+ }
+ for (Rule rule : rules)
+ rule.setFinalizeRule(finalizeRule);
+
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/StyleFileLoader.java b/src/uk/me/parabola/mkgmap/osmstyle/StyleFileLoader.java
new file mode 100644
index 0000000..373ef20
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/StyleFileLoader.java
@@ -0,0 +1,158 @@
+/*
+ * 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: Feb 17, 2008
+ */
+package uk.me.parabola.mkgmap.osmstyle;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.Reader;
+import java.net.URL;
+
+import uk.me.parabola.log.Logger;
+
+/**
+ * Open a style which can be on the classpath (mainly for the built-in styles)
+ * or in a specified file or directory.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class StyleFileLoader implements Closeable {
+ private static final Logger log = Logger.getLogger(StyleFileLoader.class);
+
+ /**
+ * Open a style that is contained in a file. This is expected to be a
+ * directory or zip file containing the files that make up the style.
+ *
+ * @param loc The file or directory containing the style(s). If this is null then the location "classpath:styles"
+ * is used.
+ * @param name If the name is given then we look for a directory with the
+ * given name. If there is no name, then the style is assumed to be at
+ * the top level and/or the only file.
+ *
+ * @return A style loader.
+ */
+ public static StyleFileLoader createStyleLoader(String loc, String name)
+ throws FileNotFoundException
+ {
+ if (loc == null)
+ return createStyleLoader("classpath:styles", name);
+
+ StyleFileLoader loader;
+
+ File file = new File(loc);
+ if (file.isDirectory()) {
+ File dir = file;
+ if (name != null) {
+ dir = new File(file, name);
+ if (dir.exists() == false)
+ throw new FileNotFoundException("style " + name + " not found in " + dir);
+ if (!dir.isDirectory())
+ dir = file;
+ }
+
+ log.debug("style directory", dir);
+ loader = new DirectoryFileLoader(dir);
+ } else if (file.isFile()) {
+ String loclc = loc.toLowerCase();
+ if (loclc.endsWith(".style")) {
+ if (name != null)
+ throw new FileNotFoundException("no sub styles in a simple style file");
+ log.debug("a single file style");
+ loader = new CombinedStyleFileLoader(loc);
+ } else {
+ log.debug("jar file", file);
+ loader = new JarFileLoader(file.toURI().toString(), name);
+ }
+ } else {
+ log.debug("style url location", loc);
+ String s = loc.toLowerCase();
+ if (s.startsWith("classpath:")) {
+ log.debug("load style off classpath");
+ loader = classpathLoader(loc.substring(10), name);
+ return loader;
+ } else if (s.startsWith("jar:")) {
+ loader = new JarFileLoader(loc, name);
+ } else if (s.indexOf(':') > 0) {
+ loader = new JarFileLoader(s, name);
+ } else {
+ throw new FileNotFoundException("no such file or path: " + loc);
+ }
+ }
+
+ return loader;
+ }
+
+ /**
+ * Open the specified file in the style definition.
+ * @param filename The name of the file in the style.
+ * @return An open file reader for the file.
+ * @throws FileNotFoundException When the file can't be opened.
+ */
+ public abstract Reader open(String filename) throws FileNotFoundException;
+
+ /**
+ * Close the FileLoader. This is different from closing individual files
+ * that were opened via {@link #open}. After this call then you shouldn't
+ * open any more files.
+ */
+ public abstract void close();
+
+ /**
+ * List the names of the styles that are contained in this loader.
+ * @return An array of style names.
+ */
+ public abstract String[] list();
+
+ /**
+ * Find a style on the class path. First we find out if the style is in
+ * a jar or a directory and then use the appropriate Loader.
+ *
+ * @param loc The file or directory location.
+ * @param name The style name.
+ * @return A loader for the style.
+ * @throws FileNotFoundException If it can't be found.
+ */
+ private static StyleFileLoader classpathLoader(String loc, String name) throws FileNotFoundException
+ {
+ String path = loc;
+ if (name != null)
+ path = loc + '/' + name + '/';
+
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ if (classLoader == null)
+ throw new FileNotFoundException("no classloader to find style");
+
+ // all style files must be in the same directory or zip
+ URL url = classLoader.getResource(path);
+ if (url == null) {
+ classLoader = StyleFileLoader.class.getClassLoader();
+ url = classLoader.getResource(path);
+ if (url == null)
+ throw new FileNotFoundException("Could not find style " + path);
+ }
+
+ String proto = url.getProtocol().toLowerCase();
+ if (proto.equals("jar")) {
+ log.debug("classpath loading from jar with url", url);
+ return new JarFileLoader(url);
+ } else if (proto.equals("file")) {
+ log.debug("classpath loading from directory", url.getPath());
+ return new DirectoryFileLoader(new File(url.getPath()));
+ }
+ throw new FileNotFoundException("Could not load style from classpath");
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java b/src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java
new file mode 100644
index 0000000..3d45a16
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java
@@ -0,0 +1,581 @@
+/*
+ * 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: Feb 17, 2008
+ */
+package uk.me.parabola.mkgmap.osmstyle;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import uk.me.parabola.imgfmt.ExitException;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.Option;
+import uk.me.parabola.mkgmap.OptionProcessor;
+import uk.me.parabola.mkgmap.Options;
+import uk.me.parabola.mkgmap.build.LocatorUtil;
+import uk.me.parabola.mkgmap.general.LevelInfo;
+import uk.me.parabola.mkgmap.general.LineAdder;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.reader.osm.FeatureKind;
+import uk.me.parabola.mkgmap.reader.osm.Rule;
+import uk.me.parabola.mkgmap.reader.osm.Style;
+import uk.me.parabola.mkgmap.reader.osm.StyleInfo;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * A style is a collection of files that describe the mapping between the OSM
+ * features and the garmin features. This file reads in those files and
+ * provides methods for using the information.
+ *
+ * The files are either contained in a directory, in a package or in a zip'ed
+ * file.
+ *
+ * @author Steve Ratcliffe
+ */
+public class StyleImpl implements Style {
+ private static final Logger log = Logger.getLogger(StyleImpl.class);
+
+ public static final boolean WITH_CHECKS = true;
+ public static final boolean WITHOUT_CHECKS = false;
+
+ // This is max the version that we understand
+ private static final int VERSION = 1;
+
+ // General options just have a value and don't need any special processing.
+ private static final Collection<String> OPTION_LIST = new ArrayList<String>(
+ Arrays.asList("levels", "overview-levels", "extra-used-tags"));
+
+ // File names
+ private static final String FILE_VERSION = "version";
+ private static final String FILE_INFO = "info";
+ private static final String FILE_OPTIONS = "options";
+ private static final String FILE_OVERLAYS = "overlays";
+
+ // Patterns
+ private static final Pattern COMMA_OR_SPACE_PATTERN = Pattern.compile("[,\\s]+");
+
+ // A handle on the style directory or file.
+ private final StyleFileLoader fileLoader;
+ private final String location;
+
+ // The general information in the 'info' file.
+ private StyleInfo info = new StyleInfo();
+
+ // Set if this style is based on another one.
+ private final List<StyleImpl> baseStyles = new ArrayList<StyleImpl>();
+
+ // A list of tag names to be used as the element name
+ private List<String> nameTagList;
+
+ // Options from the option file that are used outside this file.
+ private final Map<String, String> generalOptions = new HashMap<String, String>();
+
+ private final RuleSet lines = new RuleSet();
+ private final RuleSet polygons = new RuleSet();
+ private final RuleSet nodes = new RuleSet();
+ private final RuleSet relations = new RuleSet();
+
+ private OverlayReader overlays;
+ private final boolean performChecks;
+
+
+ /**
+ * Create a style from the given location and name.
+ * @param loc The location of the style. Can be null to mean just check
+ * the classpath.
+ * @param name The name. Can be null if the location isn't. If it is
+ * null then we just check for the first version file that can be found.
+ * @throws FileNotFoundException If the file doesn't exist. This can
+ * include the version file being missing.
+ */
+ public StyleImpl(String loc, String name) throws FileNotFoundException {
+ this(loc, name, new EnhancedProperties(), WITHOUT_CHECKS);
+ }
+
+ /**
+ * Create a style from the given location and name.
+ * @param loc The location of the style. Can be null to mean just check
+ * the classpath.
+ * @param name The name. Can be null if the location isn't. If it is
+ * null then we just check for the first version file that can be found.
+ * @param props optional program properties (may be null)
+ * @throws FileNotFoundException If the file doesn't exist. This can
+ * include the version file being missing.
+ */
+ public StyleImpl(String loc, String name, EnhancedProperties props, boolean performChecks) throws FileNotFoundException {
+ location = loc;
+ fileLoader = StyleFileLoader.createStyleLoader(loc, name);
+ this.performChecks = performChecks;
+ nameTagList = LocatorUtil.getNameTags(props);
+
+ // There must be a version file, if not then we don't create the style.
+ checkVersion();
+
+ readInfo();
+
+ for (String baseName : info.baseStyles())
+ readBaseStyle(baseName, props);
+
+ for (StyleImpl baseStyle : baseStyles)
+ mergeOptions(baseStyle);
+
+ readOptions();
+
+ // read overlays before the style rules to be able to ignore overlaid "wrong" types.
+ readOverlays();
+
+ readRules();
+
+ ListIterator<StyleImpl> listIterator = baseStyles.listIterator(baseStyles.size());
+ while (listIterator.hasPrevious())
+ mergeRules(listIterator.previous());
+
+ // OR: other way
+ //for (StyleImpl s : baseStyles)
+ // mergeRules(s);
+ }
+
+ public String getOption(String name) {
+ return generalOptions.get(name);
+ }
+
+ public StyleInfo getInfo() {
+ return info;
+ }
+
+ public Rule getNodeRules() {
+ nodes.prepare();
+ return nodes;
+ }
+
+ public Rule getWayRules() {
+ RuleSet r = new RuleSet();
+ r.addAll(lines);
+ r.addAll(polygons);
+ r.prepare();
+ return r;
+ }
+
+ public Rule getLineRules() {
+ lines.prepare();
+ return lines;
+ }
+
+ public Rule getPolygonRules() {
+ polygons.prepare();
+ return polygons;
+ }
+
+ public Rule getRelationRules() {
+ relations.prepare();
+ return relations;
+ }
+
+ public LineAdder getOverlays(final LineAdder lineAdder) {
+ LineAdder adder = null;
+
+ if (overlays != null) {
+ adder = new LineAdder() {
+ public void add(MapLine element) {
+ overlays.addLine(element, lineAdder);
+ }
+ };
+ }
+ return adder;
+ }
+
+ public Set<String> getUsedTags() {
+ Set<String> set = new HashSet<String>();
+ set.addAll(relations.getUsedTags());
+ set.addAll(lines.getUsedTags());
+ set.addAll(polygons.getUsedTags());
+ set.addAll(nodes.getUsedTags());
+
+ // this is to allow style authors to say that tags are really used even
+ // if they are not found in the style file. This is mostly to work
+ // around situations that we haven't thought of - the style is expected
+ // to get it right for itself.
+ String s = getOption("extra-used-tags");
+ if (s != null && s.trim().isEmpty() == false)
+ set.addAll(Arrays.asList(COMMA_OR_SPACE_PATTERN.split(s)));
+
+ // These tags are passed on the command line and so must be added
+ if (nameTagList != null)
+ set.addAll(nameTagList);
+
+ // There are a lot of tags that are used within mkgmap that
+ InputStream is = getClass().getResourceAsStream("/styles/builtin-tag-list");
+ try {
+ if (is != null) {
+ BufferedReader br = new BufferedReader(new InputStreamReader(is));
+ //System.out.println("Got built in list");
+ String line;
+ while ((line = br.readLine()) != null) {
+ line = line.trim();
+ if (line.startsWith("#"))
+ continue;
+ //System.out.println("adding " + line);
+ set.add(line);
+ }
+ }
+ } catch (IOException e) {
+ // the file doesn't exist, this is ok but unlikely
+ System.err.println("warning: built in tag list not found");
+ } finally {
+ Utils.closeFile(is);
+ }
+ return set;
+ }
+
+ private void readRules() {
+ String l = generalOptions.get("levels");
+ if (l == null)
+ l = LevelInfo.DEFAULT_LEVELS;
+ LevelInfo[] levels = LevelInfo.createFromString(l);
+ if (performChecks){
+ if (levels[0].getBits() <= 10){
+ System.err.println("Warning: Resolution values <= 10 may confuse MapSource: " + l);
+ }
+ }
+ l = generalOptions.get("overview-levels");
+ if (l != null){
+ LevelInfo[] ovLevels = LevelInfo.createFromString(l);
+ // TODO: make sure that the combination of the two level strings makes sense
+ if (performChecks){
+ if (ovLevels[0].getBits() <= 10){
+ System.err.println("Warning: Resolution values <= 10 may confuse MapSource: " + l);
+ }
+ if (levels[0].getLevel() >= ovLevels[ovLevels.length-1].getLevel()){
+ System.err.println("Warning: Overview level not higher than highest normal level. " + l);
+ }
+ }
+ List<LevelInfo> tmp = new ArrayList<LevelInfo>();
+ tmp.addAll(Arrays.asList(levels));
+ tmp.addAll(Arrays.asList(ovLevels));
+ levels = tmp.toArray(new LevelInfo[tmp.size()]);
+ Arrays.sort(levels);
+ }
+
+ try {
+ RuleFileReader reader = new RuleFileReader(FeatureKind.RELATION, levels, relations, performChecks, getOverlaidTypeMap());
+ reader.load(fileLoader, "relations");
+ } catch (FileNotFoundException e) {
+ // it is ok for this file to not exist.
+ log.debug("no relations file");
+ }
+
+ try {
+ RuleFileReader reader = new RuleFileReader(FeatureKind.POINT, levels, nodes, performChecks, getOverlaidTypeMap());
+ reader.load(fileLoader, "points");
+ } catch (FileNotFoundException e) {
+ // it is ok for this file to not exist.
+ log.debug("no points file");
+ }
+
+ try {
+ RuleFileReader reader = new RuleFileReader(FeatureKind.POLYLINE, levels, lines, performChecks, getOverlaidTypeMap());
+ reader.load(fileLoader, "lines");
+ } catch (FileNotFoundException e) {
+ log.debug("no lines file");
+ }
+
+ try {
+ RuleFileReader reader = new RuleFileReader(FeatureKind.POLYGON, levels, polygons, performChecks, getOverlaidTypeMap());
+ reader.load(fileLoader, "polygons");
+ } catch (FileNotFoundException e) {
+ log.debug("no polygons file");
+ }
+ }
+
+ /**
+ * If there is an options file, then read it and keep options that
+ * we are interested in.
+ *
+ * Only specific options can be set.
+ */
+ private void readOptions() {
+ try {
+ Reader r = fileLoader.open(FILE_OPTIONS);
+ Options opts = new Options(new OptionProcessor() {
+ public void processOption(Option opt) {
+ String key = opt.getOption();
+ String val = opt.getValue();
+ if (key.equals("name-tag-list")) {
+ if ("name".equals(val) == false){
+ System.err.println("Warning: option name-tag-list used in the style options is ignored. "
+ + "Please use only the command line option to specify this value." );
+ }
+ } else if (OPTION_LIST.contains(key)) {
+ // Simple options that have string value. Perhaps we should allow
+ // anything here?
+ generalOptions.put(key, val);
+ }
+ }
+ });
+
+ opts.readOptionFile(r, FILE_OPTIONS);
+ } catch (FileNotFoundException e) {
+ // the file is optional, so ignore if not present, or causes error
+ log.debug("no options file");
+ }
+ }
+
+ /**
+ * Read the info file. This is just information about the style.
+ */
+ private void readInfo() {
+ try {
+ Reader br = new BufferedReader(fileLoader.open(FILE_INFO));
+ info = new StyleInfo();
+
+ Options opts = new Options(new OptionProcessor() {
+ public void processOption(Option opt) {
+ String word = opt.getOption();
+ String value = opt.getValue();
+ if (word.equals("summary"))
+ info.setSummary(value);
+ else if (word.equals("version")) {
+ info.setVersion(value);
+ } else if (word.equals("base-style")) {
+ info.addBaseStyleName(value);
+ } else if (word.equals("description")) {
+ info.setLongDescription(value);
+ }
+
+ }
+ });
+
+ opts.readOptionFile(br, FILE_INFO);
+
+ } catch (FileNotFoundException e) {
+ // optional file..
+ log.debug("no info file");
+ }
+ }
+
+ private void readOverlays() {
+ try {
+ Reader r = fileLoader.open(FILE_OVERLAYS);
+ overlays = new OverlayReader(r, FILE_OVERLAYS);
+ overlays.readOverlays();
+ } catch (FileNotFoundException e) {
+ // this is perfectly normal
+ log.debug("no overlay file");
+ }
+ }
+
+ /**
+ * If this style is based upon another one then read it in now. The rules
+ * for merging styles are that it is as-if the style was read just after
+ * the current styles 'info' section and any option or rule specified
+ * in the current style will override any corresponding item in the
+ * base style.
+ * @param name The name of the base style
+ * @param props program properties
+ */
+ private void readBaseStyle(String name, EnhancedProperties props) {
+ if (name == null)
+ return;
+
+ try {
+ baseStyles.add(new StyleImpl(location, name, props, performChecks));
+ } catch (SyntaxException e) {
+ System.err.println("Error in style: " + e.getMessage());
+ } catch (FileNotFoundException e) {
+ // not found, try on the classpath. This is the common
+ // case where you have an external style, but want to
+ // base it on a built in one.
+ log.debug("could not open base style file", e);
+
+ try {
+ baseStyles.add(new StyleImpl(null, name, props, performChecks));
+ } catch (SyntaxException se) {
+ System.err.println("Error in style: " + se.getMessage());
+ } catch (FileNotFoundException e1) {
+ log.error("Could not find base style", e);
+ }
+ }
+ }
+
+ /**
+ * Merge another style's options into this one. The style will have a lower
+ * priority, in other words any option set in 'other' and this style will
+ * take the value given in this style.
+ *
+ * This is used to base styles on other ones, without having to repeat
+ * everything.
+ *
+ * @see #mergeRules(StyleImpl)
+ */
+ private void mergeOptions(StyleImpl other) {
+ for (Entry<String, String> ent : other.generalOptions.entrySet()) {
+ String opt = ent.getKey();
+ String val = ent.getValue();
+ if (OPTION_LIST.contains(opt)) {
+ // Simple options that have string value. Perhaps we should allow
+ // anything here?
+ generalOptions.put(opt, val);
+ }
+ }
+ }
+
+ /**
+ * Merge rules from the base style. This has to called after this
+ * style's rules are read.
+ *
+ * The other rules have a lower priority than the rules in this file; it is as if they
+ * were appended to the rule files of this style.
+ *
+ * @see #mergeOptions(StyleImpl)
+ */
+ private void mergeRules(StyleImpl other) {
+ lines.merge(other.lines);
+ polygons.merge(other.polygons);
+ nodes.merge(other.nodes);
+ relations.merge(other.relations);
+ }
+
+ private void checkVersion() throws FileNotFoundException {
+ Reader r = fileLoader.open(FILE_VERSION);
+ TokenScanner scan = new TokenScanner(FILE_VERSION, r);
+ int version;
+ try {
+ version = scan.nextInt();
+ log.debug("Got version", version);
+ } catch (NumberFormatException e) {
+ // default to 0 if no version can be found.
+ version = 0;
+ }
+
+ if (version > VERSION) {
+ System.err.println("Warning: unrecognised style version " + version +
+ ", but only versions up to " + VERSION + " are understood");
+ }
+ }
+
+ /**
+ * Writes out this file to the given writer in the single file format.
+ * This produces a valid style file, although it is mostly used
+ * for testing.
+ */
+ void dumpToFile(Writer out) {
+ StylePrinter stylePrinter = new StylePrinter(this);
+ stylePrinter.setGeneralOptions(generalOptions);
+ stylePrinter.setRelations(relations);
+ stylePrinter.setLines(lines);
+ stylePrinter.setNodes(nodes);
+ stylePrinter.setPolygons(polygons);
+ stylePrinter.dumpToFile(out);
+ }
+
+ /**
+ *
+ * @return null or the map that was read from the overlays file
+ */
+ private Map<Integer, List<Integer>> getOverlaidTypeMap() {
+ if (overlays != null)
+ return overlays.getOverlays();
+ return Collections.emptyMap();
+ }
+
+ /**
+ * Evaluate the style options and try to read the style.
+ *
+ * The option --style-file give the location of an alternate file or
+ * directory containing styles rather than the default built in ones.
+ *
+ * The option --style gives the name of a style, either one of the
+ * built in ones or selects one from the given style-file.
+ *
+ * If there is no name given, but there is a file then the file should
+ * just contain one style.
+ *
+ * @param props the program properties
+ * @return A style instance or null in case of error.
+ */
+ public static Style readStyle(EnhancedProperties props) {
+ String loc = props.getProperty("style-file");
+ if (loc == null)
+ loc = props.getProperty("map-features");
+ String name = props.getProperty("style");
+
+ if (loc == null && name == null)
+ name = "default";
+
+ if (name == null){
+ StyleFileLoader loader = null;
+ try {
+ loader = StyleFileLoader.createStyleLoader(loc, null);
+ int numEntries = loader.list().length;
+ if (numEntries > 1)
+ throw new ExitException("Style file " + loc + " contains multiple styles, use option --style to select one.");
+ } catch (FileNotFoundException e) {
+ throw new ExitException("Could not open style file " + loc);
+ } finally {
+ Utils.closeFile(loader);
+ }
+ }
+
+ Style style;
+ try {
+ style = new StyleImpl(loc, name, props, WITHOUT_CHECKS);
+ } catch (SyntaxException e) {
+ System.err.println("Error in style: " + e.getMessage());
+ throw new ExitException("Could not open style " + (name == null? "":name));
+ } catch (FileNotFoundException e) {
+ String msg = "Could not open style ";
+ if (name != null){
+ msg += name;
+ if (loc != null)
+ msg += " in " + loc;
+ }
+ else
+ msg += loc + " . Make sure that it points to a style or add the --style option.";
+ throw new ExitException(msg);
+ }
+ return style;
+ }
+
+ public static void main(String[] args) throws FileNotFoundException {
+ String file = args[0];
+ String name = null;
+ if (args.length > 1)
+ name = args[1];
+ StyleImpl style = new StyleImpl(file, name, new EnhancedProperties(), WITH_CHECKS);
+
+ style.dumpToFile(new OutputStreamWriter(System.out));
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/StylePrinter.java b/src/uk/me/parabola/mkgmap/osmstyle/StylePrinter.java
new file mode 100644
index 0000000..5aff590
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/StylePrinter.java
@@ -0,0 +1,115 @@
+package uk.me.parabola.mkgmap.osmstyle;
+
+import java.io.Writer;
+import java.util.Formatter;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import uk.me.parabola.mkgmap.reader.osm.Rule;
+import uk.me.parabola.mkgmap.reader.osm.Style;
+import uk.me.parabola.mkgmap.reader.osm.StyleInfo;
+
+/**
+ * Class for printing out a style.
+ * Code extracted from StyleImpl, but still needs information from the
+ * implementation of the style.
+ */
+public class StylePrinter {
+ private final Style style;
+
+ private Map<String, String> generalOptions;
+ private RuleSet nodes;
+ private RuleSet lines;
+ private RuleSet polygons;
+ private RuleSet relations;
+
+ public StylePrinter(Style style) {
+ this.style = style;
+ }
+
+ /**
+ * Writes out this file to the given writer in the single file format. This
+ * produces a valid style file, although it is mostly used for testing.
+ */
+ public void dumpToFile(Writer out) {
+ Formatter fmt = new Formatter(out);
+ fmt.format("<<<version>>>\n0\n");
+
+ dumpInfo(fmt);
+
+ dumpOptions(fmt);
+
+ if (relations != null)
+ dumpRuleSet(fmt, "relations", relations);
+
+ if (nodes != null)
+ dumpRuleSet(fmt, "points", nodes);
+
+ if (lines != null)
+ dumpRuleSet(fmt, "lines", lines);
+
+ if (polygons != null)
+ dumpRuleSet(fmt, "polygons", polygons);
+
+ fmt.flush();
+ }
+
+ private void dumpOptions(Formatter fmt) {
+ fmt.format("<<<options>>>\n");
+
+ if (generalOptions != null) {
+ for (Entry<String, String> entry : generalOptions.entrySet())
+ fmt.format("%s: %s\n", entry.getKey(), entry.getValue());
+ }
+ }
+
+ private void dumpInfo(Formatter fmt) {
+ fmt.format("<<<info>>>\n");
+ StyleInfo styleInfo = style.getInfo();
+ fmt.format("version %s\n", dumpInfoVal(styleInfo.getVersion()));
+ fmt.format("summary %s\n", dumpInfoVal(styleInfo.getSummary()));
+
+ // The base styles are combined already, so should not be output. Retained as comments for
+ // documentation/testing purposes.
+ for (String name : styleInfo.baseStyles())
+ fmt.format("# base-style %s\n", dumpInfoVal(name));
+
+ fmt.format("description %s\n", dumpInfoVal(styleInfo.getLongDescription()));
+ }
+
+ private String dumpInfoVal(String str) {
+ if (str.indexOf('\n') >= 0)
+ return "{\n" + str + "\n}";
+ else
+ return ": " + str;
+ }
+
+ private void dumpRuleSet(Formatter fmt, String name, RuleSet set) {
+ fmt.format("<<<%s>>>\n", name);
+ for (Rule rule : set) {
+ fmt.format("%s\n", rule.toString());
+ }
+ }
+
+
+
+ void setGeneralOptions(Map<String, String> generalOptions) {
+ this.generalOptions = generalOptions;
+ }
+
+ void setNodes(RuleSet nodes) {
+ this.nodes = nodes;
+ }
+
+ void setLines(RuleSet lines) {
+ this.lines = lines;
+ }
+
+ void setPolygons(RuleSet polygons) {
+ this.polygons = polygons;
+ }
+
+ public void setRelations(RuleSet relations) {
+ this.relations = relations;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java b/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
new file mode 100644
index 0000000..653f810
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
@@ -0,0 +1,2157 @@
+/*
+ * 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: Feb 17, 2008
+ */
+package uk.me.parabola.mkgmap.osmstyle;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.CoordNode;
+import uk.me.parabola.imgfmt.app.Exit;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.net.NODHeader;
+import uk.me.parabola.imgfmt.app.trergn.ExtTypeAttributes;
+import uk.me.parabola.imgfmt.app.trergn.MapObject;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.build.LocatorUtil;
+import uk.me.parabola.mkgmap.filters.LineSizeSplitterFilter;
+import uk.me.parabola.mkgmap.general.AreaClipper;
+import uk.me.parabola.mkgmap.general.Clipper;
+import uk.me.parabola.mkgmap.general.LineAdder;
+import uk.me.parabola.mkgmap.general.LineClipper;
+import uk.me.parabola.mkgmap.general.MapCollector;
+import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapExitPoint;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapPoint;
+import uk.me.parabola.mkgmap.general.MapRoad;
+import uk.me.parabola.mkgmap.general.MapShape;
+import uk.me.parabola.mkgmap.general.RoadNetwork;
+import uk.me.parabola.mkgmap.osmstyle.housenumber.HousenumberGenerator;
+import uk.me.parabola.mkgmap.reader.osm.CoordPOI;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.FeatureKind;
+import uk.me.parabola.mkgmap.reader.osm.GType;
+import uk.me.parabola.mkgmap.reader.osm.Node;
+import uk.me.parabola.mkgmap.reader.osm.OsmConverter;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.RestrictionRelation;
+import uk.me.parabola.mkgmap.reader.osm.Rule;
+import uk.me.parabola.mkgmap.reader.osm.Style;
+import uk.me.parabola.mkgmap.reader.osm.TypeResult;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * Convert from OSM to the mkgmap intermediate format using a style.
+ * A style is a collection of files that describe the mappings to be used
+ * when converting.
+ *
+ * @author Steve Ratcliffe
+ */
+public class StyledConverter implements OsmConverter {
+ private static final Logger log = Logger.getLogger(StyledConverter.class);
+ private static final Logger roadLog = Logger.getLogger(StyledConverter.class.getName()+".roads");
+
+ private final List<String> nameTagList;
+
+ private final MapCollector collector;
+
+ private Clipper clipper = Clipper.NULL_CLIPPER;
+ private Area bbox = new Area(-90.0d, -180.0d, 90.0d, 180.0d); // default is planet
+
+ // restrictions associates lists of turn restrictions with the
+ // Coord corresponding to the restrictions' 'via' node
+ private final Map<Coord, List<RestrictionRelation>> restrictions = new IdentityHashMap<Coord, List<RestrictionRelation>>();
+
+ private final List<Relation> throughRouteRelations = new ArrayList<Relation>();
+
+ /** all tags used for access restrictions */
+ public final static List<String> ACCESS_TAGS = Arrays.asList(
+ "mkgmap:bicycle",
+ "mkgmap:foot",
+ "mkgmap:truck",
+ "mkgmap:car",
+ "mkgmap:bus",
+ "mkgmap:taxi",
+ "mkgmap:emergency",
+ "mkgmap:delivery");
+
+ // limit line length to avoid problems with portions of really
+ // long lines being assigned to the wrong subdivision
+ private static final int MAX_LINE_LENGTH = 40000;
+
+ // limit arc lengths to what can be handled by RouteArc
+ private static final int MAX_ARC_LENGTH = 20450000; // (1 << 22) * 16 / 3.2808 ~ 20455030*/
+
+ private static final int MAX_NODES_IN_WAY = 64; // possibly could be increased
+
+ // nodeIdMap maps a Coord into a CoordNode
+ private IdentityHashMap<Coord, CoordNode> nodeIdMap = new IdentityHashMap<Coord, CoordNode>();
+
+ public final static String WAY_POI_NODE_IDS = "mkgmap:way-poi-node-ids";
+
+ private List<Way> roads = new ArrayList<Way>();
+ private List<GType> roadTypes = new ArrayList<GType>();
+ private List<Way> lines = new ArrayList<Way>();
+ private List<GType> lineTypes = new ArrayList<GType>();
+ private HashMap<Long, Way> modifiedRoads = new HashMap<Long, Way>();
+ private HashSet<Long> deletedRoads = new HashSet<Long>();
+
+ private final double minimumArcLength;
+
+ private int nextNodeId = 1;
+
+ private HousenumberGenerator housenumberGenerator;
+
+ private final Rule wayRules;
+ private final Rule nodeRules;
+ private final Rule lineRules;
+ private final Rule polygonRules;
+
+ private boolean driveOnLeft;
+ private boolean driveOnRight;
+ private final boolean checkRoundabouts;
+ private int reportDeadEnds;
+ private final boolean linkPOIsToWays;
+ private final boolean mergeRoads;
+
+ private LineAdder lineAdder = new LineAdder() {
+ public void add(MapLine element) {
+ if (element instanceof MapRoad)
+ collector.addRoad((MapRoad) element);
+ else
+ collector.addLine(element);
+ }
+ };
+
+ public StyledConverter(Style style, MapCollector collector, EnhancedProperties props) {
+ this.collector = collector;
+
+ nameTagList = LocatorUtil.getNameTags(props);
+
+ wayRules = style.getWayRules();
+ nodeRules = style.getNodeRules();
+ lineRules = style.getLineRules();
+ polygonRules = style.getPolygonRules();
+
+ housenumberGenerator = new HousenumberGenerator(props);
+
+ driveOnLeft = props.getProperty("drive-on-left") != null;
+ // check if the setDriveOnLeft flag should be ignored
+ // (this is the case if precompiled sea is loaded)
+ if (props.getProperty("ignore-drive-on-left") == null)
+ // do not ignore the flag => initialize it
+ NODHeader.setDriveOnLeft(driveOnLeft);
+ driveOnRight = props.getProperty("drive-on-right") != null;
+ checkRoundabouts = props.getProperty("check-roundabouts") != null;
+ reportDeadEnds = props.getProperty("report-dead-ends", 1);
+
+ LineAdder overlayAdder = style.getOverlays(lineAdder);
+ if (overlayAdder != null)
+ lineAdder = overlayAdder;
+ String rsa = props.getProperty("remove-short-arcs", "0");
+ minimumArcLength = (!rsa.isEmpty())? Double.parseDouble(rsa) : 0.0;
+ if (minimumArcLength > 0){
+ System.err.println("Warning: remove-short-arcs=" + rsa + " overrides default 0." +
+ " This is no longer recommended for a routable map.");
+ }
+ linkPOIsToWays = props.getProperty("link-pois-to-ways", false);
+
+ // undocumented option - usually used for debugging only
+ mergeRoads = props.getProperty("no-mergeroads", false) == false;
+ }
+
+ /** One type result for ways to avoid recreating one for each way. */
+ private final WayTypeResult wayTypeResult = new WayTypeResult();
+ private class WayTypeResult implements TypeResult
+ {
+ private Way way;
+ public void setWay(Way way) {
+ this.way = way;
+ }
+
+ public void add(Element el, GType type) {
+ if (type.isContinueSearch()) {
+ // If not already copied, do so now
+ if (el == way)
+ el = way.copy();
+ }
+ postConvertRules(el, type);
+ addConvertedWay((Way) el, type);
+ }
+ }
+
+ /**
+ * This takes the way and works out what kind of map feature it is and makes
+ * the relevant call to the mapper callback.
+ * <p>
+ * As a few examples we might want to check for the 'highway' tag, work out
+ * if it is an area of a park etc.
+ *
+ * @param way The OSM way.
+ */
+ public void convertWay(final Way way) {
+ if (way.getPoints().size() < 2)
+ return;
+
+ if (way.getTagCount() == 0) {
+ // no tags => nothing to convert
+ return;
+ }
+
+ preConvertRules(way);
+
+ housenumberGenerator.addWay(way);
+
+ Rule rules;
+ if ("polyline".equals(way.getTag("mkgmap:stylefilter")))
+ rules = lineRules;
+ else if ("polygon".equals(way.getTag("mkgmap:stylefilter")))
+ rules = polygonRules;
+ else
+ rules = wayRules;
+
+ wayTypeResult.setWay(way);
+ rules.resolveType(way, wayTypeResult);
+ }
+
+
+ private void addConvertedWay(Way way, GType foundType) {
+
+ if (foundType.getFeatureKind() == FeatureKind.POLYLINE) {
+ GType type = new GType(foundType);
+
+ String oneWay = way.getTag("oneway");
+ if("-1".equals(oneWay) || "reverse".equals(oneWay)) {
+ // it's a oneway street in the reverse direction
+ // so reverse the order of the nodes and change
+ // the oneway tag to "yes"
+ way.reverse();
+ way.addTag("oneway", "yes");
+ if (type.isRoad() && "roundabout".equals(way.getTag("junction")))
+ log.warn("Roundabout", way.getId(), "has reverse oneway tag (" + way.getPoints().get(0).toOSMURL() + ")");
+ }
+
+ if (way.isBoolTag("oneway")) {
+ way.addTag("oneway", "yes");
+ if (type.isRoad() && checkFixmeCoords(way) )
+ way.addTag("mkgmap:dead-end-check", "false");
+ } else
+ way.deleteTag("oneway");
+
+ if(foundType.isRoad() &&
+ !MapObject.hasExtendedType(foundType.getType())){
+ recalcRoadClass(way, type);
+ recalcRoadSpeed(way, type);
+ roads.add(way);
+ roadTypes.add(type);
+ }
+ else {
+ lines.add(way);
+ lineTypes.add(type);
+ }
+ }
+ else
+ addShape(way, foundType);
+ }
+
+ /** One type result for nodes to avoid recreating one for each node. */
+ private NodeTypeResult nodeTypeResult = new NodeTypeResult();
+ private class NodeTypeResult implements TypeResult {
+ private Node node;
+ public void setNode(Node node) {
+ this.node = node;
+ }
+
+ public void add(Element el, GType type) {
+ if (type.isContinueSearch()) {
+ // If not already copied, do so now
+ if (el == node)
+ el = node.copy();
+ }
+
+ postConvertRules(el, type);
+ addPoint((Node) el, type);
+ }
+ }
+
+ /**
+ * Takes a node (that has its own identity) and converts it from the OSM
+ * type to the Garmin map type.
+ *
+ * @param node The node to convert.
+ */
+ public void convertNode(final Node node) {
+ if (node.getTagCount() == 0) {
+ // no tags => nothing to convert
+ return;
+ }
+
+ preConvertRules(node);
+
+ housenumberGenerator.addNode(node);
+
+ nodeTypeResult.setNode(node);
+ nodeRules.resolveType(node, nodeTypeResult);
+ }
+
+
+ /**
+ * Rules to run before converting the element.
+ */
+ private void preConvertRules(Element el) {
+ if (nameTagList == null)
+ return;
+
+ for (String t : nameTagList) {
+ String val = el.getTag(t);
+ if (val != null) {
+ el.addTag("name", val);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Recalculates the road class defined in the given {@link GType} object based on the tags
+ * <ul>
+ * <li>{@code mkgmap:road-class}</li>
+ * <li>{@code mkgmap:road-class-min}</li>
+ * <li>{@code mkgmap:road-class-max}</li>
+ * </ul>
+ * The road class of the {@link GType} object is changed if the tags modify its road class.
+ *
+ * @param el an element
+ * @param type a GType instance with the current road class.
+ * @return {@code true} the road class of {@code type} has been changed;
+ * {@code false} the road class of of {@code type} has not been changed
+ */
+ private boolean recalcRoadClass(Element el, GType type) {
+ // retrieve the original road class value
+ int roadClass = type.getRoadClass();
+
+ // check if the road class is modified
+ String val = el.getTag("mkgmap:road-class");
+ if (val != null) {
+ if (val.startsWith("-")) {
+ roadClass -= Integer.decode(val.substring(1));
+ } else if (val.startsWith("+")) {
+ roadClass += Integer.decode(val.substring(1));
+ } else {
+ roadClass = Integer.decode(val);
+ }
+ val = el.getTag("mkgmap:road-class-max");
+ int roadClassMax = 4;
+ if (val != null)
+ roadClassMax = Integer.decode(val);
+ val = el.getTag("mkgmap:road-class-min");
+
+ int roadClassMin = 0;
+ if (val != null)
+ roadClassMin = Integer.decode(val);
+ if (roadClass > roadClassMax)
+ roadClass = roadClassMax;
+ else if (roadClass < roadClassMin)
+ roadClass = roadClassMin;
+
+ }
+
+ if (roadClass == type.getRoadClass()) {
+ // no change of road class
+ return false;
+ } else {
+ // change the road class
+ type.setRoadClass(roadClass);
+ return true;
+ }
+ }
+
+ /**
+ * Recalculates the road speed defined in the given {@link GType} object based on the tags
+ * <ul>
+ * <li>{@code mkgmap:road-speed-class}</li>
+ * <li>{@code mkgmap:road-speed}</li>
+ * <li>{@code mkgmap:road-speed-min}</li>
+ * <li>{@code mkgmap:road-speed-max}</li>
+ * </ul>
+ * The road speed of the {@link GType} object is changed if the tags modify its road speed.
+ *
+ * @param el an element
+ * @param type a GType instance with the current road speed.
+ * @return {@code true} the road speed of {@code type} has been changed;
+ * {@code false} the road speed of of {@code type} has not been changed
+ */
+ private boolean recalcRoadSpeed(Element el, GType type) {
+ // retrieve the original road speed value
+ int roadSpeed = type.getRoadSpeed();
+
+ // check if the road speed defined in the GType object is overridden
+ String roadSpeedOverride = el.getTag("mkgmap:road-speed-class");
+ if (roadSpeedOverride != null) {
+ try {
+ int rs = Integer.decode(roadSpeedOverride);
+ if (rs >= 0 && rs <= 7) {
+ // override the road speed class
+ roadSpeed = rs;
+ } else {
+ log.error(getDebugName(el)
+ + " road classification mkgmap:road-speed-class="
+ + roadSpeedOverride + " must be in [0;7]");
+ }
+ } catch (Exception exp) {
+ log.error(getDebugName(el)
+ + " road classification mkgmap:road-speed-class="
+ + roadSpeedOverride + " must be in [0;7]");
+ }
+ }
+
+ // check if the road speed should be modified more
+ String val = el.getTag("mkgmap:road-speed");
+ if(val != null) {
+ if(val.startsWith("-")) {
+ roadSpeed -= Integer.decode(val.substring(1));
+ }
+ else if(val.startsWith("+")) {
+ roadSpeed += Integer.decode(val.substring(1));
+ }
+ else {
+ roadSpeed = Integer.decode(val);
+ }
+ val = el.getTag("mkgmap:road-speed-max");
+ int roadSpeedMax = 7;
+ if(val != null)
+ roadSpeedMax = Integer.decode(val);
+ val = el.getTag("mkgmap:road-speed-min");
+
+ int roadSpeedMin = 0;
+ if(val != null)
+ roadSpeedMin = Integer.decode(val);
+ if(roadSpeed > roadSpeedMax)
+ roadSpeed = roadSpeedMax;
+ else if(roadSpeed < roadSpeedMin)
+ roadSpeed = roadSpeedMin;
+ }
+
+ if (roadSpeed == type.getRoadSpeed()) {
+ // road speed is not changed
+ return false;
+ } else {
+ type.setRoadSpeed(roadSpeed);
+ return true;
+ }
+ }
+
+ /**
+ * Built in rules to run after converting the element.
+ */
+ private void postConvertRules(Element el, GType type) {
+ // Set the default_name if no name is set
+ if (type.getDefaultName() != null && el.getName() == null)
+ el.addTag("mkgmap:label:1", type.getDefaultName());
+ }
+
+ /**
+ * Set the bounding box for this map. This should be set before any other
+ * elements are converted if you want to use it. All elements that are added
+ * are clipped to this box, new points are added as needed at the boundary.
+ *
+ * If a node or a way falls completely outside the boundary then it would be
+ * omitted. This would not normally happen in the way this option is typically
+ * used however.
+ *
+ * @param bbox The bounding area, must not be null.
+ */
+ public void setBoundingBox(Area bbox) {
+ this.clipper = new AreaClipper(bbox);
+ this.bbox = bbox;
+
+ // we calculate our own bounding box, now let the collector know about it.
+ collector.addToBounds(new Coord(bbox.getMinLat(), bbox.getMinLong()));
+ collector.addToBounds(new Coord(bbox.getMaxLat(), bbox.getMaxLong()));
+ }
+
+ /**
+ * Merges roads with identical attributes (gtype, OSM tags) to reduce the size of the
+ * road network.
+ */
+ private void mergeRoads() {
+ if (mergeRoads == false) {
+ log.info("Merging roads is disabled");
+ return;
+ }
+
+ // instantiate the RoadMerger - the roads and roadTypes lists are copied
+ RoadMerger merger = new RoadMerger(roads, roadTypes, restrictions, throughRouteRelations);
+ // clear the lists
+ roads.clear();
+ roadTypes.clear();
+ // merge the roads and copy the results to the roads and roadTypes list
+ merger.merge(roads, roadTypes);
+ }
+
+ public void end() {
+ setHighwayCounts();
+ findUnconnectedRoads();
+ filterCoordPOI();
+ removeShortArcsByMergingNodes();
+ // make sure that copies of modified roads have equal points
+ for (int i = 0; i < lines.size(); i++){
+ Way line = lines.get(i);
+ if (deletedRoads.contains(line.getId())){
+ lines.set(i, null);
+ continue;
+ }
+ Way modWay = modifiedRoads.get(line.getId());
+ if (modWay != null){
+ List<Coord> points = line.getPoints();
+ points.clear();
+ points.addAll(modWay.getPoints());
+ }
+ }
+ deletedRoads = null;
+ modifiedRoads = null;
+
+ mergeRoads();
+
+ resetHighwayCounts();
+ setHighwayCounts();
+
+ for (int i = 0; i < lines.size(); i++){
+ Way line = lines.get(i);
+ if (line == null)
+ continue;
+ GType gt = lineTypes.get(i);
+ addLine(line, gt);
+ }
+ lines = null;
+ lineTypes = null;
+ if (roadLog.isInfoEnabled()) {
+ roadLog.info("Flags: oneway,no-emergency, no-delivery, no-throughroute, no-truck, no-bike, no-foot, carpool, no-taxi, no-bus, no-car");
+ roadLog.info(String.format("%19s %4s %11s %s", "Road-OSM-Id","Type","Flags", "Labels"));
+ }
+ // add the roads after the other lines
+ for (int i = 0; i < roads.size(); i++){
+ Way road = roads.get(i);
+ if (road == null)
+ continue;
+ GType gt = roadTypes.get(i);
+ addRoad(road, gt);
+ }
+ roads = null;
+ roadTypes = null;
+
+ housenumberGenerator.generate(lineAdder);
+
+ Collection<List<RestrictionRelation>> lists = restrictions.values();
+ for (List<RestrictionRelation> l : lists) {
+
+ for (RestrictionRelation rr : l) {
+ rr.addRestriction(collector);
+ }
+ }
+
+ for(Relation relation : throughRouteRelations) {
+ Node node = null;
+ Way w1 = null;
+ Way w2 = null;
+ for(Map.Entry<String,Element> member : relation.getElements()) {
+ if(member.getValue() instanceof Node) {
+ if(node == null)
+ node = (Node)member.getValue();
+ else
+ log.warn("Through route relation", relation.toBrowseURL(), "has more than 1 node");
+ }
+ else if(member.getValue() instanceof Way) {
+ Way w = (Way)member.getValue();
+ if(w1 == null)
+ w1 = w;
+ else if(w2 == null)
+ w2 = w;
+ else
+ log.warn("Through route relation", relation.toBrowseURL(), "has more than 2 ways");
+ }
+ }
+
+ CoordNode coordNode = null;
+ if(node == null)
+ log.warn("Through route relation", relation.toBrowseURL(), "is missing the junction node");
+ else {
+ Coord junctionPoint = node.getLocation();
+ if(bbox != null && !bbox.contains(junctionPoint)) {
+ // junction is outside of the tile - ignore it
+ continue;
+ }
+ coordNode = nodeIdMap.get(junctionPoint);
+ if(coordNode == null)
+ log.warn("Through route relation", relation.toBrowseURL(), "junction node at", junctionPoint.toOSMURL(), "is not a routing node");
+ }
+
+ if(w1 == null || w2 == null)
+ log.warn("Through route relation", relation.toBrowseURL(), "should reference 2 ways that meet at the junction node");
+
+ if(coordNode != null && w1 != null && w2 != null)
+ collector.addThroughRoute(coordNode.getId(), w1.getId(), w2.getId());
+ }
+ // return memory to GC
+ nodeIdMap = null;
+ throughRouteRelations.clear();
+ restrictions.clear();
+ }
+
+ /**
+ * Run the rules for this relation. As this is not an end object, then
+ * the only useful rules are action rules that set tags on the contained
+ * ways or nodes. Every rule should probably start with 'type=".."'.
+ *
+ * @param relation The relation to convert.
+ */
+ public void convertRelation(Relation relation) {
+ if (relation.getTagCount() == 0) {
+ // no tags => nothing to convert
+ return;
+ }
+
+ housenumberGenerator.addRelation(relation);
+
+ // relation rules are not applied here because they are applied
+ // earlier by the RelationStyleHook
+
+ if(relation instanceof RestrictionRelation) {
+ RestrictionRelation rr = (RestrictionRelation)relation;
+ if(rr.isValid()) {
+ List<RestrictionRelation> lrr = restrictions.get(rr.getViaCoord());
+ if(lrr == null) {
+ lrr = new ArrayList<RestrictionRelation>();
+ restrictions.put(rr.getViaCoord(), lrr);
+ }
+ lrr.add(rr);
+ }
+ }
+ else if("through_route".equals(relation.getTag("type"))) {
+ throughRouteRelations.add(relation);
+ }
+ }
+
+ private void addLine(Way way, GType gt) {
+ List<Coord> wayPoints = way.getPoints();
+ List<Coord> points = new ArrayList<Coord>(wayPoints.size());
+ double lineLength = 0;
+ Coord lastP = null;
+ for (Coord p : wayPoints) {
+ if (lastP != null && p.equals(lastP))
+ continue;
+ points.add(p);
+ if(lastP != null) {
+ lineLength += p.distance(lastP);
+ if(lineLength >= MAX_LINE_LENGTH) {
+ if (log.isInfoEnabled())
+ log.info("Splitting line", way.toBrowseURL(), "at", p.toOSMURL(), "to limit its length to", (long)lineLength + "m");
+ addLine(way, gt, points);
+ points = new ArrayList<Coord>(wayPoints.size() - points.size() + 1);
+ points.add(p);
+ lineLength = 0;
+ }
+ }
+ lastP = p;
+ }
+
+ if(points.size() > 1)
+ addLine(way, gt, points);
+ }
+
+ private void addLine(Way way, GType gt, List<Coord> points) {
+ MapLine line = new MapLine();
+ elementSetup(line, gt, way);
+ line.setPoints(points);
+
+
+ if (way.isBoolTag("oneway"))
+ line.setDirection(true);
+ if (way.isBoolTag("mkgmap:skipSizeFilter"))
+ line.setSkipSizeFilter(true);
+
+ clipper.clipLine(line, lineAdder);
+ }
+
+ private void addShape(Way way, GType gt) {
+ // This is deceptively simple. At the time of writing, splitter only retains points that are within
+ // the tile and some distance around it. Therefore a way that is closed in reality may not be closed
+ // as we see it in its incomplete state.
+ //
+ // Here isClosed means that it is really closed in OSM, and therefore it is safe to clip the line
+ // segment to the tile boundaries.
+ if (!way.isClosed())
+ return;
+
+ final MapShape shape = new MapShape();
+ elementSetup(shape, gt, way);
+ shape.setPoints(way.getPoints());
+ if (way.isBoolTag("mkgmap:skipSizeFilter"))
+ shape.setSkipSizeFilter(true);
+
+ clipper.clipShape(shape, collector);
+ }
+
+ private void addPoint(Node node, GType gt) {
+ if (!clipper.contains(node.getLocation()))
+ return;
+
+ // to handle exit points we use a subclass of MapPoint
+ // to carry some extra info (a reference to the
+ // motorway associated with the exit)
+ MapPoint mp;
+ int type = gt.getType();
+ if(type >= 0x2000 && type < 0x2800) {
+ String ref = node.getTag(Exit.TAG_ROAD_REF);
+ String id = node.getTag("mkgmap:osmid");
+ if(ref != null) {
+ String to = node.getTag(Exit.TAG_TO);
+ MapExitPoint mep = new MapExitPoint(ref, to);
+ String fd = node.getTag(Exit.TAG_FACILITY);
+ if(fd != null)
+ mep.setFacilityDescription(fd);
+ if(id != null)
+ mep.setOSMId(id);
+ mp = mep;
+ }
+ else {
+ mp = new MapPoint();
+ log.warn("Motorway exit", node.getName(), "(" + node.getLocation().toOSMURL() + ") has no motorway! (either make the exit share a node with the motorway or specify the motorway ref with a", Exit.TAG_ROAD_REF, "tag)");
+ }
+ }
+ else {
+ mp = new MapPoint();
+ }
+ elementSetup(mp, gt, node);
+ mp.setLocation(node.getLocation());
+
+ collector.addPoint(mp);
+ }
+
+ private void elementSetup(MapElement ms, GType gt, Element element) {
+ String[] labels = new String[4];
+ int noLabels = 0;
+ for (int labelNo = 1; labelNo <= 4; labelNo++) {
+ String label1 = element.getTag("mkgmap:label:"+labelNo);
+ String label = Label.squashSpaces(label1);
+ if (label != null) {
+ labels[noLabels] = label;
+ noLabels++;
+ }
+ }
+
+ if (labels[0] != null) {
+ ms.setLabels(labels);
+ }
+ ms.setType(gt.getType());
+ ms.setMinResolution(gt.getMinResolution());
+ ms.setMaxResolution(gt.getMaxResolution());
+
+ // Now try to get some address info for POIs
+
+ String country = element.getTag("mkgmap:country");
+ String region = element.getTag("mkgmap:region");
+ String city = element.getTag("mkgmap:city");
+ String zip = element.getTag("mkgmap:postal_code");
+ String street = element.getTag("mkgmap:street");
+ String houseNumber = element.getTag("mkgmap:housenumber");
+ String phone = element.getTag("mkgmap:phone");
+ String isIn = element.getTag("mkgmap:is_in");
+
+ if(country != null)
+ ms.setCountry(country);
+
+ if(region != null)
+ ms.setRegion(region);
+
+ if(city != null)
+ ms.setCity(city);
+
+ if(zip != null)
+ ms.setZip(zip);
+
+ if(street != null)
+ ms.setStreet(street);
+
+ if(houseNumber != null)
+ ms.setHouseNumber(houseNumber);
+
+ if(isIn != null)
+ ms.setIsIn(isIn);
+
+ if(phone != null)
+ ms.setPhone(phone);
+
+
+
+ if(MapObject.hasExtendedType(gt.getType())) {
+ // pass attributes with mkgmap:xt- prefix (strip prefix)
+ Map<String,String> xta = element.getTagsWithPrefix("mkgmap:xt-", true);
+ // also pass all attributes with seamark: prefix (no strip prefix)
+ xta.putAll(element.getTagsWithPrefix("seamark:", false));
+ ms.setExtTypeAttributes(new ExtTypeAttributes(xta, "OSM id " + element.getId()));
+ }
+ }
+
+ private boolean hasAccessRestriction(Element osmElement) {
+ for (String tag : ACCESS_TAGS) {
+ if (osmElement.isNotBoolTag(tag)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Add a way to the road network. May call itself recursively and
+ * might truncate the way if splitting is required.
+ * @param way the way
+ * @param gt the type assigned by the style
+ */
+ private void addRoad(Way way, GType gtParm) {
+ GType gt = new GType(gtParm);
+ if (way.getPoints().size() < 2){
+ log.warn("road has < 2 points",way.getId(),"(discarding)");
+ return;
+ }
+
+ if("roundabout".equals(way.getTag("junction"))) {
+ List<Coord> points = way.getPoints();
+ // if roundabout checking is enabled and roundabout has at
+ // least 3 points and it has not been marked as "don't
+ // check", check its direction
+ if(checkRoundabouts &&
+ way.getPoints().size() > 2 &&
+ !way.isBoolTag("mkgmap:no-dir-check") &&
+ !way.isNotBoolTag("mkgmap:dir-check")) {
+ Coord centre = way.getCofG();
+ int dir = 0;
+ // check every third segment
+ for(int i = 0; (i + 1) < points.size(); i += 3) {
+ Coord pi = points.get(i);
+ Coord pi1 = points.get(i + 1);
+ // don't check segments that are very short
+ if(pi.quickDistance(centre) > 2.5 &&
+ pi.quickDistance(pi1) > 2.5) {
+ // determine bearing from segment that starts with
+ // point i to centre of roundabout
+ double a = pi.bearingTo(pi1);
+ double b = pi.bearingTo(centre) - a;
+ while(b > 180)
+ b -= 360;
+ while(b < -180)
+ b += 360;
+ // if bearing to centre is between 15 and 165
+ // degrees consider it trustworthy
+ if(b >= 15 && b < 165)
+ ++dir;
+ else if(b <= -15 && b > -165)
+ --dir;
+ }
+ }
+ if (dir == 0)
+ log.info("Roundabout segment", way.getId(), "direction unknown (see", points.get(0).toOSMURL() + ")");
+ else {
+ boolean clockwise = dir > 0;
+ if (points.get(0) == points.get(points.size() - 1)) {
+ // roundabout is a loop
+ if (!driveOnLeft && !driveOnRight) {
+ if (clockwise) {
+ if (log.isInfoEnabled())
+ log.info("Roundabout", way.getId(), "is clockwise so assuming vehicles should drive on left side of road (" + centre.toOSMURL() + ")");
+ driveOnLeft = true;
+ NODHeader.setDriveOnLeft(true);
+ } else {
+ if (log.isInfoEnabled())
+ log.info("Roundabout", way.getId(), "is anti-clockwise so assuming vehicles should drive on right side of road (" + centre.toOSMURL() + ")");
+ driveOnRight = true;
+ }
+ }
+ if (driveOnLeft && !clockwise ||
+ driveOnRight && clockwise)
+ {
+ log.warn("Roundabout", way.getId(), "direction is wrong - reversing it (see", centre.toOSMURL() + ")");
+ way.reverse();
+ }
+ } else if (driveOnLeft && !clockwise ||
+ driveOnRight && clockwise)
+ {
+ // roundabout is a line
+ log.warn("Roundabout segment", way.getId(), "direction looks wrong (see", points.get(0).toOSMURL() + ")");
+ }
+ }
+ }
+ }
+
+ // process any Coords that have a POI associated with them
+ String wayPOI = way.getTag(WAY_POI_NODE_IDS);
+ if (wayPOI != null) {
+ List<Coord> points = way.getPoints();
+
+ // look for POIs that modify the way's road class or speed
+ // this could be e.g. highway=traffic_signals that reduces the
+ // road speed to cause a short increase of traveling time
+ for(int i = 0; i < points.size(); ++i) {
+ Coord p = points.get(i);
+ if (p instanceof CoordPOI && ((CoordPOI) p).isUsed()) {
+ CoordPOI cp = (CoordPOI) p;
+ Node node = cp.getNode();
+ if (wayPOI.contains("["+node.getId()+"]")){
+ log.debug("POI",node.getId(),"changes way",way.getId());
+ String roadClass = node.getTag("mkgmap:road-class");
+ String roadSpeed = node.getTag("mkgmap:road-speed");
+ if(roadClass != null || roadSpeed != null) {
+ // if the way has more than one point
+ // following this one, split the way at the
+ // next point to limit the size of the
+ // affected region
+ if((i + 2) < points.size() &&
+ safeToSplitWay(points, i + 1, i, points.size() - 1)) {
+ Way tail = splitWayAt(way, i + 1);
+ // recursively process tail of way
+ addRoad(tail, gt);
+ }
+ boolean classChanged = recalcRoadClass(node, gt);
+ if (classChanged && log.isInfoEnabled()){
+ log.info("POI changing road class of", way.toBrowseURL(), "to", gt.getRoadClass(), "at", points.get(0).toOSMURL());
+ }
+ boolean speedChanged = recalcRoadSpeed(node, gt);
+ if (speedChanged && log.isInfoEnabled()){
+ log.info("POI changing road speed of", way.toBrowseURL(), "to", gt.getRoadSpeed(), "at" , points.get(0).toOSMURL());
+ }
+ }
+ }
+ }
+
+ // if this isn't the first (or last) point in the way
+ // and the next point modifies the way's speed/class,
+ // split the way at this point to limit the size of
+ // the affected region
+ if (i > 0 && (i + 1) < points.size()
+ && points.get(i + 1) instanceof CoordPOI) {
+ CoordPOI cp = (CoordPOI) points.get(i + 1);
+ Node node = cp.getNode();
+ if (cp.isUsed() && wayPOI.contains("["+node.getId()+"]")){
+ if (node.getTag("mkgmap:road-class") != null
+ || node.getTag("mkgmap:road-speed") != null) {
+ if (safeToSplitWay(points, i, i - 1,
+ points.size() - 1)) {
+ Way tail = splitWayAt(way, i);
+ // recursively process tail of way
+ addRoad(tail, gt);
+ }
+ }
+ }
+ }
+ }
+
+ // now look for POIs that have an access restriction defined -
+ // if they do, copy the access permissions to the way -
+ // what we want to achieve is modifying the way's access
+ // permissions where it passes through the POI without
+ // affecting the rest of the way too much - to that end we
+ // split the way before and after the POI - if necessary,
+ // extra points are inserted before and after the POI to
+ // limit the size of the affected region
+
+ final double stubSegmentLength = 25; // metres
+ for(int i = 0; i < points.size(); ++i) {
+ Coord p = points.get(i);
+ // check if this POI modifies access and if so, split
+ // the way at the following point (if any) and then
+ // copy its access restrictions to the way
+ if (p instanceof CoordPOI && ((CoordPOI) p).isUsed()) {
+ CoordPOI cp = (CoordPOI) p;
+ Node node = cp.getNode();
+ if (hasAccessRestriction(node) && wayPOI.contains("["+node.getId()+"]")){
+ // if this or the next point are not the last
+ // points in the way, split at the next point
+ // taking care not to produce a short arc
+ if((i + 1) < points.size()) {
+ Coord p1 = points.get(i + 1);
+ // check if the next point is further away
+ // than we would like
+ double dist = p.distance(p1);
+ if(dist >= (2 * stubSegmentLength)) {
+ // insert a new point after the POI to
+ // make a short stub segment
+ p1 = p.makeBetweenPoint(p1, stubSegmentLength / dist);
+ p1.incHighwayCount();
+ points.add(i + 1, p1);
+ }
+
+ // now split the way at the next point to
+ // limit the region that has restricted
+ // access
+ if((i+2 < points.size() &&
+ safeToSplitWay(points, i+1, 0, points.size()-1))) {
+ Way tail = splitWayAt(way, i + 1);
+ // recursively process tail of way
+ addRoad(tail, gt);
+ }
+ }
+
+ // make the POI a node so that the region with
+ // restricted access is split into two as far
+ // as routing is concerned - this should stop
+ // routing across the POI when the start point
+ // is within the restricted region and the
+ // destination point is outside of the
+ // restricted region on the other side of the
+ // POI
+
+ // however, this still doesn't stop routing
+ // across the POI when both the start and end
+ // points are either side of the POI and both
+ // are in the restricted region
+ if (p.getHighwayCount() < 2){
+ if (i == 0|| i == points.size()-1 ||
+ safeToSplitWay(points, i, 0, points.size()-1))
+ p.incHighwayCount();
+ else {
+ points.set(i,new Coord(p.getLatitude(),p.getLongitude()));
+ points.get(i).incHighwayCount();
+ }
+ }
+
+ // copy all of the POI's access restrictions
+ // to the way segment
+ for (String accessTag : ACCESS_TAGS) {
+ if(node.isNotBoolTag(accessTag))
+ way.addTag(accessTag, "no");
+
+ }
+ }
+ }
+
+ // check if the next point modifies access and if so,
+ // split the way either here or at a new point that's
+ // closer to the POI taking care not to introduce a
+ // short arc
+ if((i + 1) < points.size()) {
+ Coord p1 = points.get(i + 1);
+ if (p1 instanceof CoordPOI && ((CoordPOI) p1).isUsed()) {
+ CoordPOI cp = (CoordPOI) p1;
+ Node node = cp.getNode();
+ if (hasAccessRestriction(node) && wayPOI.contains("["+node.getId()+"]")){
+ // check if this point is further away
+ // from the POI than we would like
+ double dist = p.distance(p1);
+ if(dist >= (2 * stubSegmentLength)) {
+ // insert a new point to make a short
+ // stub segment
+ p1 = p1.makeBetweenPoint(p, stubSegmentLength / dist);
+ p1.incHighwayCount();
+ points.add(i + 1, p1);
+ continue;
+ }
+
+ // now split the way here if it is not the
+ // first point in the way
+ if(i > 0 &&
+ safeToSplitWay(points, i, 0, points.size() - 1)) {
+ Way tail = splitWayAt(way, i);
+ // recursively process tail of road
+ addRoad(tail, gt);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // if there is a bounding box, clip the way with it
+
+ List<Way> clippedWays = null;
+
+ if(bbox != null) {
+ List<List<Coord>> lineSegs = LineClipper.clip(bbox, way.getPoints());
+
+ if (lineSegs != null) {
+
+ clippedWays = new ArrayList<Way>();
+
+ for (List<Coord> lco : lineSegs) {
+ Way nWay = new Way(way.getId());
+ nWay.copyTags(way);
+ for(Coord co : lco) {
+ nWay.addPoint(co);
+ if(co.getOnBoundary()) {
+ // this point lies on a boundary
+ // make sure it becomes a node
+ co.incHighwayCount();
+ }
+ }
+ clippedWays.add(nWay);
+ }
+ }
+ }
+
+ if(clippedWays != null) {
+ for(Way cw : clippedWays) {
+ addRoadAfterSplittingLoops(cw, gt);
+ }
+ }
+ else {
+ // no bounding box or way was not clipped
+ addRoadAfterSplittingLoops(way, gt);
+ }
+ }
+
+ private void addRoadAfterSplittingLoops(Way way, final GType gtParm) {
+ GType gt = new GType(gtParm);
+ // make sure the way has nodes at each end
+ way.getPoints().get(0).incHighwayCount();
+ way.getPoints().get(way.getPoints().size() - 1).incHighwayCount();
+
+ // check if the way is a loop or intersects with itself
+
+ boolean wayWasSplit = true; // aka rescan required
+
+ while(wayWasSplit) {
+ List<Coord> wayPoints = way.getPoints();
+ int numPointsInWay = wayPoints.size();
+
+ wayWasSplit = false; // assume way won't be split
+
+ // check each point in the way to see if it is the same
+ // point as a following point in the way (actually the
+ // same object not just the same coordinates)
+ for(int p1I = 0; !wayWasSplit && p1I < (numPointsInWay - 1); p1I++) {
+ Coord p1 = wayPoints.get(p1I);
+ if (p1.getHighwayCount() < 2)
+ continue;
+ for(int p2I = p1I + 1; !wayWasSplit && p2I < numPointsInWay; p2I++) {
+ if(p1 == wayPoints.get(p2I)) {
+ // way is a loop or intersects itself
+ // attempt to split it into two ways
+
+ // start at point before intersection point
+ // check that splitting there will not produce
+ // a zero length arc - if it does try the
+ // previous point(s)
+ int splitI = p2I - 1;
+ while(splitI > p1I &&
+ !safeToSplitWay(wayPoints, splitI, p1I, p2I)) {
+ if (log.isInfoEnabled())
+ log.info("Looped way", getDebugName(way), "can't safely split at point[" + splitI + "], trying the preceeding point");
+ --splitI;
+ }
+
+ if(splitI == p1I) {
+ log.warn("Splitting looped way", getDebugName(way), "would make a zero length arc, so it will have to be pruned at", wayPoints.get(p2I).toOSMURL());
+ do {
+ log.warn(" Pruning point[" + p2I + "]");
+ wayPoints.remove(p2I);
+ // next point to inspect has same index
+ --p2I;
+ // but number of points has reduced
+ --numPointsInWay;
+
+ if (p2I + 1 == numPointsInWay)
+ wayPoints.get(p2I).incHighwayCount();
+ // if wayPoints[p2I] is the last point
+ // in the way and it is so close to p1
+ // that a short arc would be produced,
+ // loop back and prune it
+ } while(p2I > p1I &&
+ (p2I + 1) == numPointsInWay &&
+ p1.equals(wayPoints.get(p2I)));
+ }
+ else {
+ // split the way before the second point
+ if (log.isInfoEnabled())
+ log.info("Splitting looped way", getDebugName(way), "at", wayPoints.get(splitI).toOSMURL(), "- it has", (numPointsInWay - splitI - 1 ), "following segment(s).");
+ Way loopTail = splitWayAt(way, splitI);
+ // recursively check (shortened) head for
+ // more loops
+ addRoadAfterSplittingLoops(way, gt);
+ // now process the tail of the way
+ way = loopTail;
+ wayWasSplit = true;
+ }
+ }
+ }
+ }
+
+ if(!wayWasSplit) {
+ // no split required so make road from way
+ addRoadWithoutLoops(way, gt);
+ }
+ }
+ }
+
+ /**
+ * safeToSplitWay() returns true if it is safe (no short arcs will be
+ * created) to split a way at a given position - assumes that the
+ * floor and ceiling points will become nodes even if they are not
+ * yet.
+ * @param points the way's points
+ * @param pos the position we are testing
+ * @param floor lower limit of points to test (inclusive)
+ * @param ceiling upper limit of points to test (inclusive)
+ * @return true if is OK to split as pos
+ */
+ private boolean safeToSplitWay(List<Coord> points, int pos, int floor, int ceiling) {
+ Coord candidate = points.get(pos);
+ // avoid running off the ends of the list
+ if(floor < 0)
+ floor = 0;
+ if(ceiling >= points.size())
+ ceiling = points.size() - 1;
+ double arcLength = 0;
+ Coord prev = candidate;
+ // test points after pos
+ for(int i = pos + 1; i <= ceiling; ++i) {
+ Coord p = points.get(i);
+ arcLength += p.distance(prev);
+ if(i == ceiling || p.getHighwayCount() > 1) {
+ // point is going to be a node
+ if(candidate.equals(p)) {
+ // coordinates are equal, that's too close
+ return false;
+ }
+ // no need to test further
+ break;
+ }
+ prev = p;
+ }
+ if (arcLength == 0 || arcLength < minimumArcLength)
+ return false;
+ prev = candidate;
+ arcLength = 0;
+ // test points before pos
+ for(int i = pos - 1; i >= floor; --i) {
+ Coord p = points.get(i);
+ arcLength += p.distance(prev);
+ if(i == floor || p.getHighwayCount() > 1) {
+ // point is going to be a node
+ if(candidate.equals(p)) {
+ // coordinates are equal, that's too close
+ return false;
+ }
+ // no need to test further
+ break;
+ }
+ }
+
+ return (arcLength != 0 && arcLength >= minimumArcLength);
+ }
+
+ private static String getDebugName(Element el) {
+ String name = el.getName();
+ if(name == null)
+ name = el.getTag("ref");
+ if(name == null)
+ name = "";
+ else
+ name += " ";
+ return name + "(OSM id " + el.getId() + ")";
+ }
+
+ private void addRoadWithoutLoops(Way way, GType gt) {
+ List<Integer> nodeIndices = new ArrayList<Integer>();
+ List<Coord> points = way.getPoints();
+ Way trailingWay = null;
+ String debugWayName = getDebugName(way);
+
+ // collect the Way's nodes and also split the way if any
+ // inter-node arc length becomes excessive
+ double arcLength = 0;
+ // track the dimensions of the way's bbox so that we can
+ // detect if it would be split by the LineSizeSplitterFilter
+ class WayBBox {
+ int minLat = Integer.MAX_VALUE;
+ int maxLat = Integer.MIN_VALUE;
+ int minLon = Integer.MAX_VALUE;
+ int maxLon = Integer.MIN_VALUE;
+
+ void addPoint(Coord co) {
+ int lat = co.getLatitude();
+ if(lat < minLat)
+ minLat = lat;
+ if(lat > maxLat)
+ maxLat = lat;
+ int lon = co.getLongitude();
+ if(lon < minLon)
+ minLon = lon;
+ if(lon > maxLon)
+ maxLon = lon;
+ }
+
+ boolean tooBig() {
+ return LineSizeSplitterFilter.testDims(maxLat - minLat,
+ maxLon - minLon) >= 1.0;
+ }
+ }
+
+ WayBBox wayBBox = new WayBBox();
+
+ for(int i = 0; i < points.size(); ++i) {
+ Coord p = points.get(i);
+
+ wayBBox.addPoint(p);
+
+ // check if we should split the way at this point to limit
+ // the arc length between nodes
+ if((i + 1) < points.size()) {
+ Coord nextP = points.get(i + 1);
+ double d = p.distance(nextP);
+ // get arc size as a proportion of the max allowed - a
+ // value greater than 1.0 indicate that the bbox is
+ // too large in at least one dimension
+ double arcProp = LineSizeSplitterFilter.testDims(nextP.getLatitude() -
+ p.getLatitude(),
+ nextP.getLongitude() -
+ p.getLongitude());
+ if(arcProp >= 1.0 || d > MAX_ARC_LENGTH) {
+ nextP = p.makeBetweenPoint(nextP, 0.95 * Math.min(1 / arcProp, MAX_ARC_LENGTH / d));
+ nextP.incHighwayCount();
+ points.add(i + 1, nextP);
+ double newD = p.distance(nextP);
+ if (log.isInfoEnabled())
+ log.info("Way", debugWayName, "contains a segment that is", (int)d + "m long but I am adding a new point to reduce its length to", (int)newD + "m");
+ d = newD;
+ }
+
+ wayBBox.addPoint(nextP);
+
+ if((arcLength + d) > MAX_ARC_LENGTH) {
+ assert i > 0 : "long arc segment was not split";
+ assert trailingWay == null : "trailingWay not null #1";
+ trailingWay = splitWayAt(way, i);
+ // this will have truncated the current Way's
+ // points so the loop will now terminate
+ if (log.isInfoEnabled())
+ log.info("Splitting way", debugWayName, "at", points.get(i).toOSMURL(), "to limit arc length to", (long)arcLength + "m");
+ }
+ else if(wayBBox.tooBig()) {
+ assert i > 0 : "arc segment with big bbox not split";
+ assert trailingWay == null : "trailingWay not null #2";
+ trailingWay = splitWayAt(way, i);
+ // this will have truncated the current Way's
+ // points so the loop will now terminate
+ if (log.isInfoEnabled())
+ log.info("Splitting way", debugWayName, "at", points.get(i).toOSMURL(), "to limit the size of its bounding box");
+ }
+ else {
+ if(p.getHighwayCount() > 1) {
+ // point is a node so zero arc length
+ arcLength = 0;
+ }
+
+ arcLength += d;
+ }
+ }
+
+ if(p.getHighwayCount() > 1) {
+ // this point is a node connecting highways
+ CoordNode coordNode = nodeIdMap.get(p);
+ if(coordNode == null) {
+ // assign a node id
+ coordNode = new CoordNode(p.getLatitude(), p.getLongitude(), nextNodeId++, p.getOnBoundary());
+ nodeIdMap.put(p, coordNode);
+ }
+
+ // add this index to node Indexes (should not already be there)
+ assert !nodeIndices.contains(i) : debugWayName + " has multiple nodes for point " + i + " new node is " + p.toOSMURL();
+ nodeIndices.add(i);
+
+ if((i + 1) < points.size() &&
+ nodeIndices.size() == MAX_NODES_IN_WAY) {
+ // this isn't the last point in the way so split
+ // it here to avoid exceeding the max nodes in way
+ // limit
+ assert trailingWay == null : "trailingWay not null #7";
+ trailingWay = splitWayAt(way, i);
+ // this will have truncated the current Way's
+ // points so the loop will now terminate
+ if (log.isInfoEnabled())
+ log.info("Splitting way", debugWayName, "at", points.get(i).toOSMURL(), "as it has at least", MAX_NODES_IN_WAY, "nodes");
+ }
+ }
+ }
+
+ MapLine line = new MapLine();
+ elementSetup(line, gt, way);
+ line.setPoints(points);
+
+ MapRoad road = new MapRoad(way.getId(), line);
+ if (way.isBoolTag("mkgmap:skipSizeFilter"))
+ road.setSkipSizeFilter(true);
+
+ boolean doFlareCheck = true;
+ if("roundabout".equals(way.getTag("junction"))) {
+ road.setRoundabout(true);
+ doFlareCheck = false;
+ }
+
+ if(way.isBoolTag("mkgmap:synthesised")) {
+ road.setSynthesised(true);
+ doFlareCheck = false;
+ }
+
+ if(way.isNotBoolTag("mkgmap:flare-check")) {
+ doFlareCheck = false;
+ }
+ else if(way.isBoolTag("mkgmap:flare-check")) {
+ doFlareCheck = true;
+ }
+ road.doFlareCheck(doFlareCheck);
+
+ road.setLinkRoad(gt.getType() == 0x08 || gt.getType() == 0x09);
+
+ // set road parameters
+
+ // copy road class and road speed
+ road.setRoadClass(gt.getRoadClass());
+ road.setSpeed(gt.getRoadSpeed());
+
+ if (way.isBoolTag("oneway")) {
+ road.setDirection(true);
+ road.setOneway();
+ }
+
+ boolean[] noAccess = new boolean[RoadNetwork.NO_MAX];
+ noAccess[RoadNetwork.NO_EMERGENCY] = way.isNotBoolTag("mkgmap:emergency");
+ noAccess[RoadNetwork.NO_DELIVERY] = way.isNotBoolTag("mkgmap:delivery");
+ noAccess[RoadNetwork.NO_CAR] = way.isNotBoolTag("mkgmap:car");
+ noAccess[RoadNetwork.NO_BUS] = way.isNotBoolTag("mkgmap:bus");
+ noAccess[RoadNetwork.NO_TAXI] = way.isNotBoolTag("mkgmap:taxi");
+ noAccess[RoadNetwork.NO_FOOT] = way.isNotBoolTag("mkgmap:foot");
+ noAccess[RoadNetwork.NO_BIKE] = way.isNotBoolTag("mkgmap:bicycle");
+ noAccess[RoadNetwork.NO_TRUCK] = way.isNotBoolTag("mkgmap:truck");
+ road.setAccess(noAccess);
+
+ // does the road have a carpool lane?
+ if (way.isBoolTag("mkgmap:carpool"))
+ road.setCarpoolLane();
+
+ if (way.isNotBoolTag("mkgmap:throughroute"))
+ road.setNoThroughRouting();
+
+ if(way.isBoolTag("mkgmap:toll"))
+ road.setToll();
+
+ // by default, ways are paved
+ if(way.isBoolTag("mkgmap:unpaved"))
+ road.paved(false);
+
+ // by default, way's are not ferry routes
+ if(way.isBoolTag("mkgmap:ferry"))
+ road.ferry(true);
+
+ int numNodes = nodeIndices.size();
+ road.setNumNodes(numNodes);
+
+ if(numNodes > 0) {
+ // replace Coords that are nodes with CoordNodes
+ boolean hasInternalNodes = false;
+ CoordNode lastCoordNode = null;
+ List<RestrictionRelation> lastRestrictions = null;
+ for(int i = 0; i < numNodes; ++i) {
+ int n = nodeIndices.get(i);
+ if(n > 0 && n < points.size() - 1)
+ hasInternalNodes = true;
+ Coord coord = points.get(n);
+ CoordNode thisCoordNode = nodeIdMap.get(coord);
+ assert thisCoordNode != null : "Way " + debugWayName + " node " + i + " (point index " + n + ") at " + coord.toOSMURL() + " yields a null coord node";
+ boolean boundary = coord.getOnBoundary();
+ if(boundary && log.isInfoEnabled()) {
+ log.info("Way", debugWayName + "'s point #" + n, "at", coord.toOSMURL(), "is a boundary node");
+ }
+ points.set(n, thisCoordNode);
+
+ // see if this node plays a role in any turn
+ // restrictions
+
+ if(lastRestrictions != null) {
+ // the previous node was the location of one or
+ // more restrictions
+ for(RestrictionRelation rr : lastRestrictions) {
+ if(rr.getToWay().getId() == way.getId()) {
+ rr.setToNode(thisCoordNode);
+ }
+ else if(rr.getFromWay().getId() == way.getId()) {
+ rr.setFromNode(thisCoordNode);
+ }
+ else {
+ rr.addOtherNode(thisCoordNode);
+ }
+ }
+ }
+
+ List<RestrictionRelation> theseRestrictions = restrictions.get(coord);
+ if(theseRestrictions != null) {
+ // this node is the location of one or more
+ // restrictions
+ for(RestrictionRelation rr : theseRestrictions) {
+ rr.setViaNode(thisCoordNode);
+ if(rr.getToWay().getId() == way.getId()) {
+ if(lastCoordNode != null)
+ rr.setToNode(lastCoordNode);
+ }
+ else if(rr.getFromWay().getId() == way.getId()) {
+ if(lastCoordNode != null)
+ rr.setFromNode(lastCoordNode);
+ }
+ else if(lastCoordNode != null) {
+ rr.addOtherNode(lastCoordNode);
+ }
+ }
+ }
+
+ lastRestrictions = theseRestrictions;
+ lastCoordNode = thisCoordNode;
+ }
+
+ road.setStartsWithNode(nodeIndices.get(0) == 0);
+ road.setInternalNodes(hasInternalNodes);
+ }
+
+ if (roadLog.isInfoEnabled()) {
+ // shift the bits so that they have the correct position
+ int cmpAccess = (road.getRoadDef().getTabAAccess() & 0xff) + ((road.getRoadDef().getTabAAccess() & 0xc000) >> 6);
+ if (road.isDirection()) {
+
+ cmpAccess |= 1<<10;
+ }
+ String access = String.format("%11s",Integer.toBinaryString(cmpAccess)).replace(' ', '0');
+ roadLog.info(String.format("%19d 0x%-2x %11s %s", way.getId(), road.getType(), access, Arrays.toString(road.getLabels())));
+ }
+
+ // add the road to the housenumber generator
+ // it will add the road later on to the lineAdder
+ housenumberGenerator.addRoad(way, road);
+
+ if(trailingWay != null)
+ addRoadWithoutLoops(trailingWay, gt);
+ }
+
+ /**
+ * Check if the first or last of the coords of the way has the fixme flag set
+ * @param way the way to check
+ * @return true if fixme flag was found
+ */
+ private boolean checkFixmeCoords(Way way) {
+ if (way.getPoints().get(0).isFixme())
+ return true;
+ if (way.getPoints().get(way.getPoints().size()-1).isFixme())
+ return true;
+ return false;
+ }
+
+ /**
+ * split a Way at the specified point and return the new Way (the
+ * original Way is truncated, both ways will contain the split point)
+ * @param way the way to split
+ * @param index the split position.
+ * @return the trailing part of the way
+ */
+ private Way splitWayAt(Way way, int index) {
+ Way trailingWay = new Way(way.getId());
+ List<Coord> wayPoints = way.getPoints();
+ int numPointsInWay = wayPoints.size();
+
+ for(int i = index; i < numPointsInWay; ++i)
+ trailingWay.addPoint(wayPoints.get(i));
+
+ // ensure split point becomes a node
+ wayPoints.get(index).incHighwayCount();
+
+ // copy the way's name and tags to the new way
+ trailingWay.copyTags(way);
+
+ // remove the points after the split from the original way
+ // it's probably more efficient to remove from the end first
+ for(int i = numPointsInWay - 1; i > index; --i)
+ wayPoints.remove(i);
+
+ return trailingWay;
+ }
+
+ protected boolean accessExplicitlyAllowed(String val) {
+ if (val == null)
+ return false;
+
+ return (val.equalsIgnoreCase("yes") ||
+ val.equalsIgnoreCase("designated") ||
+ val.equalsIgnoreCase("permissive") ||
+ val.equalsIgnoreCase("official"));
+ }
+
+ private boolean isFootOnlyAccess(Way way){
+
+ // foot must be allowed
+ if (way.isNotBoolTag("mkgmap:foot")) {
+ return false;
+ }
+ // check if bike, truck, car, bus, taxi and emergency are not allowed
+ // not sure about delivery - but check if also
+ // carpool and throughroute can be ignored (I think so...)
+ for (String accessTag : Arrays.asList("mkgmap:bicycle","mkgmap:truck","mkgmap:car","mkgmap:bus","mkgmap:taxi","mkgmap:emergency","mkgmap:delivery"))
+ {
+ if (way.isNotBoolTag(accessTag) == false) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Increment the highway counter for each coord of each road.
+ * As a result, all road junctions have a count > 1.
+ */
+ private void setHighwayCounts(){
+ log.info("Maintaining highway counters");
+ long lastId = 0;
+ List<Way> dupIdHighways = new ArrayList<Way>();
+ for (Way way :roads){
+ if (way == null)
+ continue;
+
+ if (way.getId() == lastId) {
+ log.debug("Road with identical id:", way.getId());
+ dupIdHighways.add(way);
+ continue;
+ }
+ lastId = way.getId();
+ List<Coord> points = way.getPoints();
+ for (Coord p:points){
+ p.incHighwayCount();
+ }
+ }
+
+ // go through all duplicated highways and increase the highway counter of all crossroads
+ for (Way way : dupIdHighways) {
+ List<Coord> points = way.getPoints();
+ // increase the highway counter of the first and last point
+ points.get(0).incHighwayCount();
+ points.get(points.size()-1).incHighwayCount();
+
+ // for all other points increase the counter only if other roads are connected
+ for (int i = 1; i < points.size()-1; i++) {
+ Coord p = points.get(i);
+ if (p.getHighwayCount() > 1) {
+ // this is a crossroads - mark that the duplicated way is also part of it
+ p.incHighwayCount();
+ }
+ }
+ }
+ }
+
+ /**
+ * Increment the highway counter for each coord of each road.
+ * As a result, all road junctions have a count > 1.
+ */
+ private void resetHighwayCounts(){
+ log.info("Resetting highway counters");
+ long lastId = 0;
+ for (Way way :roads){
+ if (way == null)
+ continue;
+
+ if (way.getId() == lastId) {
+ continue;
+ }
+ lastId = way.getId();
+ List<Coord> points = way.getPoints();
+ for (Coord p:points){
+ p.resetHighwayCount();
+ }
+ }
+ }
+
+ /**
+ * Detect roads that do not share any node with another road.
+ * If such a road has the mkgmap:set_unconnected_type tag, add it as line, not as a road.
+ */
+ private void findUnconnectedRoads(){
+ Map<Coord, HashSet<Way>> connectors = new IdentityHashMap<Coord, HashSet<Way>>(roads.size()*2);
+
+ // for dead-end-check only: will contain ways with loops (also simply closed ways)
+ HashSet<Way> selfConnectors = new HashSet<Way>();
+
+ // collect nodes that might connect roads
+ long lastId = 0;
+ for (Way way :roads){
+ if (way.getId() == lastId)
+ continue;
+ lastId = way.getId();
+ for (Coord p:way.getPoints()){
+ if (p.getHighwayCount() > 1){
+ HashSet<Way> ways = connectors.get(p);
+ if (ways == null){
+ ways = new HashSet<Way>(4);
+ connectors.put(p, ways);
+ }
+ boolean wasNew = ways.add(way);
+ if (!wasNew && reportDeadEnds > 0)
+ selfConnectors.add(way);
+ }
+ }
+ }
+
+ // find roads that are not connected
+ for (int i = 0; i < roads.size(); i++){
+ Way way = roads.get(i);
+ if(reportDeadEnds > 0){
+ // report dead ends of oneway roads
+ if (way.isBoolTag("oneway") && !way.isNotBoolTag("mkgmap:dead-end-check")) {
+ List<Coord> points = way.getPoints();
+ int[] pointsToCheck = {0, points.size()-1};
+ if (points.get(pointsToCheck[0]) == points.get(pointsToCheck[1]))
+ continue; // skip closed way
+ for (int pos: pointsToCheck ){
+ boolean isDeadEnd = true;
+ boolean isDeadEndOfMultipleWays = true;
+ Coord p = points.get(pos);
+ if (bbox.contains(p) == false || p.getOnBoundary())
+ isDeadEnd = false; // we don't know enough about possible connections
+ else if (p.getHighwayCount() < 2){
+ isDeadEndOfMultipleWays = false;
+ } else {
+ HashSet<Way> ways = connectors.get(p);
+ if (ways.size() <= 1)
+ isDeadEndOfMultipleWays = false;
+ for (Way connectedWay: ways){
+ if (!isDeadEnd)
+ break;
+ if (way == connectedWay){
+ if (selfConnectors.contains(way)){
+ // this might be a P-shaped oneway,
+ // check if it has other exists in the loop part
+ if (pos == 0){
+ for (int k = pos+1; k < points.size()-1; k++){
+ Coord pTest = points.get(k);
+ if (pTest == p)
+ break; // found no other exit
+ if (pTest.getHighwayCount() > 1){
+ isDeadEnd = false;
+ break;
+ }
+ }
+
+ }else {
+ for (int k = pos-1; k >= 0; k--){
+ Coord pTest = points.get(k);
+ if (pTest == p)
+ break; // found no other exit
+ if (pTest.getHighwayCount() > 1){
+ isDeadEnd = false;
+ break;
+ }
+ }
+ }
+ }
+ continue;
+ }
+ List<Coord> otherPoints = connectedWay.getPoints();
+ Coord otherFirst = otherPoints.get(0);
+ Coord otherLast = otherPoints.get(otherPoints.size()-1);
+ if (otherFirst == otherLast || connectedWay.isBoolTag("oneway") == false)
+ isDeadEnd = false;
+ else {
+ Coord pOther;
+ if (pos != 0)
+ pOther = otherLast;
+ else
+ pOther = otherFirst;
+ if (p != pOther){
+ // way is connected to a point on a oneway which allows going on
+ isDeadEnd = false;
+ }
+ }
+ }
+ }
+
+ if (isDeadEnd && (isDeadEndOfMultipleWays || reportDeadEnds > 1)){
+ log.warn("Oneway road " + way.getId() + " with tags " + way.toTagString() + ((pos==0) ? " comes from":" goes to") + " nowhere at " + p.toOSMURL());
+ }
+ }
+ }
+ }
+ String check_type = way.getTag("mkgmap:set_unconnected_type");
+ if (check_type != null){
+ boolean isConnected = false;
+ boolean onBoundary = false;
+ for (Coord p:way.getPoints()){
+ if (p.getOnBoundary())
+ onBoundary = true;
+ if (p.getHighwayCount() > 1){
+ HashSet<Way> ways = connectors.get(p);
+ if (ways != null && ways.size() > 1){
+ isConnected = true;
+ break;
+ }
+ }
+ }
+ if (!isConnected){
+ if (onBoundary){
+ log.info("road not connected to other roads but is on boundary:", way.toBrowseURL());
+ } else {
+ if ("none".equals(check_type))
+ log.info("road not connected to other roads, is ignored:", way.toBrowseURL());
+ else {
+ int type = -1;
+ try{
+ type = Integer.decode(check_type);
+ if (GType.isRoutableLineType(type)){
+ type = -1;
+ log.error("type value in mkgmap:set_unconnected_type should not be a routable type:" + check_type);
+ }
+ } catch (NumberFormatException e){
+ log.warn("invalid type value in mkgmap:set_unconnected_type:", check_type);
+ }
+ if (type != -1 ){
+ log.info("road not connected to other roads, added as line with type", check_type + ":", way.toBrowseURL());
+ GType gt = new GType(roadTypes.get(i), check_type);
+ addLine(way, gt);
+ } else {
+ log.warn("road not connected to other roads, but replacement type is invalid. Dropped:", way.toBrowseURL());
+ }
+ }
+ roads.set(i, null);
+ roadTypes.set(i, null);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Make sure that only CoordPOI which affect routing will be treated as
+ * nodes in the following routines.
+ */
+ private void filterCoordPOI() {
+ if (!linkPOIsToWays)
+ return;
+ log.info("translating CoordPOI");
+ for (Way way : roads) {
+ if (way == null)
+ continue;
+ if ("true".equals(way.getTag("mkgmap:way-has-pois"))) {
+ String wayPOI = "";
+ boolean isFootWay = isFootOnlyAccess(way);
+ if (!isFootWay){
+ // check if the way is for pedestrians only
+ List<Coord> points = way.getPoints();
+ int numPoints = points.size();
+ for (int i = 0;i < numPoints; i++) {
+ Coord p = points.get(i);
+ if (p instanceof CoordPOI){
+ CoordPOI cp = (CoordPOI) p;
+ Node node = cp.getNode();
+ if(hasAccessRestriction(node) ||
+ node.getTag("mkgmap:road-class") != null ||
+ node.getTag("mkgmap:road-speed") != null){
+ wayPOI += "["+ node.getId()+"]";
+ cp.setUsed(true);
+ }
+ }
+ }
+ }
+ if (wayPOI.isEmpty()) {
+ way.deleteTag("mkgmap:way-has-pois");
+ log.info("ignoring CoordPOI(s) for way", way.toBrowseURL(), "because routing is not affected.");
+ }
+ else {
+ way.addTag(WAY_POI_NODE_IDS, wayPOI);
+ }
+ }
+ }
+ }
+
+ /**
+ * Routing nodes must not be too close together as this
+ * causes routing errors. We try to merge these nodes here.
+ */
+ private void removeShortArcsByMergingNodes() {
+ log.info("Removing short arcs (min arc length =", minimumArcLength + "m)");
+ log.info("Removing short arcs - marking points as node-alike and removing obsolete points");
+ for (Way way : roads) {
+ if (way == null)
+ continue;
+ List<Coord> points = way.getPoints();
+ int numPoints = points.size();
+ if (numPoints >= 2) {
+ // all end points should be treated as nodes
+ points.get(0).setTreatAsNode(true);
+ points.get(numPoints - 1).setTreatAsNode(true);
+ // non-end points have 2 arcs but ignore points that
+ // are only in a single way
+ Coord prev = points.get(numPoints - 1);
+ for (int i = numPoints - 2; i >= 0; --i) {
+ Coord p = points.get(i);
+ // if this point is a CoordPOI it may become a
+ // node later even if it isn't actually a connection
+ // between roads at this time - so for the purposes
+ // of short arc removal, consider it to be a node
+ // if it is on a boundary it will become a node later
+ if (p.getHighwayCount() > 1 || p instanceof CoordPOI || p.getOnBoundary())
+ p.setTreatAsNode(true);
+ // remove equal points
+ if (p.equals(prev)) {
+ int removePos = -1;
+ if (prev.isTreatAsNode() == false){
+ removePos = i+1;
+ prev = p;
+ }
+ else if (p.isTreatAsNode() == false){
+ removePos = i;
+ }
+ if (removePos >= 0){
+ points.remove(removePos);
+ if (log.isInfoEnabled())
+ log.info("Way", way.toBrowseURL(), "has consecutive equal points at node numbers",i+1, "and",i+2,"(discarding",removePos+1,")");
+ modifiedRoads.put(way.getId(), way);
+ }
+ } else {
+ prev = p;
+ }
+ }
+ }
+ }
+
+ // replacements maps those nodes that have been replaced to
+ // the node that replaces them
+ Map<Coord, Coord> replacements = new IdentityHashMap<Coord, Coord>();
+ Map<Way, Way> complainedAbout = new HashMap<Way, Way>();
+ boolean anotherPassRequired = true;
+ int pass = 0;
+ int numWaysDeleted = 0;
+ int numNodesMerged = 0;
+
+ while (anotherPassRequired && pass < 10) {
+ anotherPassRequired = false;
+ log.info("Removing short arcs - PASS", ++pass);
+ for (int w = 0; w < roads.size(); w++){
+ Way way = roads.get(w);
+ if (way == null)
+ continue;
+ List<Coord> points = way.getPoints();
+ if (points.size() < 2) {
+ if (log.isInfoEnabled())
+ log.info(" Way", way.getTag("name"), "(" + way.toBrowseURL() + ") has less than 2 points - deleting it");
+ roads.set(w, null);
+ deletedRoads.add(way.getId());
+ ++numWaysDeleted;
+ continue;
+ }
+ // scan through the way's points looking for nodes and
+ // check to see that the nodes are not too close to
+ // each other
+ int previousNodeIndex = 0; // first point will be a node
+ Coord previousPoint = points.get(0);
+ double arcLength = 0;
+
+ for (int i = 0; i < points.size(); ++i) {
+ Coord p = points.get(i);
+
+ // check if this point is to be replaced because
+ // it was previously merged into another point
+ if (p.isReplaced()){
+ Coord replacement = null;
+ Coord r = p;
+ while ((r = replacements.get(r)) != null) {
+ replacement = r;
+ }
+
+ if (replacement != null) {
+ assert !p.getOnBoundary() : "Boundary node replaced";
+ if (p instanceof CoordPOI){
+ CoordPOI cp = (CoordPOI) p;
+ Node node = cp.getNode();
+ if (cp.isUsed() && way != null && way.getId() != 0) {
+ String wayPOI = way.getTag(WAY_POI_NODE_IDS);
+ if (wayPOI != null && wayPOI.contains("["+node.getId()+"]")){
+ if (replacement instanceof CoordPOI){
+ Node rNode = ((CoordPOI) replacement).getNode();
+ if (wayPOI.contains("["+ rNode.getId() + "]"))
+ log.warn("CoordPOI", node.getId(), "replaced by CoordPOI",rNode.getId(), "in way", way.toBrowseURL());
+ else
+ log.warn("CoordPOI", node.getId(), "replaced by ignored CoordPOI",rNode.getId(), "in way", way.toBrowseURL());
+ }
+ else
+ log.warn("CoordPOI", node.getId(),"replaced by simple coord in way", way.toBrowseURL());
+ }
+ }
+ }
+ p = replacement;
+ p.incHighwayCount();
+ // replace point in way
+ points.set(i, p);
+ if (i == 0)
+ previousPoint = p;
+ modifiedRoads.put(way.getId(), way);
+ }
+ }
+ if (i == 0) {
+ // nothing more to do with this point
+ continue;
+ }
+
+ // this is not the first point in the way
+ if (p == previousPoint) {
+ if (log.isInfoEnabled())
+ log.info(" Way", way.getTag("name"), "(" + way.toBrowseURL() + ") has consecutive identical points at", p.toOSMURL(), "- deleting the second point");
+ points.remove(i);
+ // hack alert! rewind the loop index
+ --i;
+ modifiedRoads.put(way.getId(), way);
+ anotherPassRequired = true;
+ continue;
+ }
+
+ if (minimumArcLength > 0){
+ // we have to calculate the length of the arc
+ arcLength += p.distance(previousPoint);
+ }
+ else {
+ // if the points are not equal, the arc length is > 0
+ if (!p.equals(previousPoint)){
+ arcLength = 1; // just a value > 0
+ }
+ }
+ previousPoint = p;
+
+ // do we treat this point as a node ?
+ if (!p.isTreatAsNode()) {
+ // it's not a node so go on to next point
+ continue;
+ }
+ Coord previousNode = points.get(previousNodeIndex);
+ if (p == previousNode) {
+ // this node is the same point object as the
+ // previous node - leave it for now and it
+ // will be handled later by the road loop
+ // splitter
+ previousNodeIndex = i;
+ arcLength = 0;
+ continue;
+ }
+
+ boolean mergeNodes = false;
+
+ if (p.equals(previousNode)) {
+ // nodes have identical coordinates and are
+ // candidates for being merged
+
+ // however, to avoid trashing unclosed loops
+ // (e.g. contours) we only want to merge the
+ // nodes when the length of the arc between
+ // the nodes is small
+
+ if(arcLength == 0 || arcLength < minimumArcLength)
+ mergeNodes = true;
+ else if(complainedAbout.get(way) == null) {
+ if (log.isInfoEnabled())
+ log.info(" Way", way.getTag("name"), "(" + way.toBrowseURL() + ") has unmerged co-located nodes at", p.toOSMURL(), "- they are joined by a", (int)(arcLength * 10) / 10.0 + "m arc");
+ complainedAbout.put(way, way);
+ }
+ }
+ else if(minimumArcLength > 0 && minimumArcLength > arcLength) {
+ // nodes have different coordinates but the
+ // arc length is less than minArcLength so
+ // they will be merged
+ mergeNodes = true;
+ }
+
+ if (!mergeNodes) {
+ // keep this node and go look at the next point
+ previousNodeIndex = i;
+ arcLength = 0;
+ continue;
+ }
+
+ if (previousNode.getOnBoundary() && p.getOnBoundary()) {
+ if (p.equals(previousNode)) {
+ // the previous node has identical
+ // coordinates to the current node so it
+ // can be replaced but to avoid the
+ // assertion above we need to forget that
+ // it is on the boundary
+ previousNode.setOnBoundary(false);
+ } else {
+ // both the previous node and this node
+ // are on the boundary and they don't have
+ // identical coordinates
+ if(complainedAbout.get(way) == null) {
+ if (log.isLoggable(Level.WARNING))
+ log.warn(" Way", way.getTag("name"), "(" + way.toBrowseURL() + ") has short arc (" + String.format("%.2f", arcLength) + "m) at", p.toOSMURL(), "- but it can't be removed because both ends of the arc are boundary nodes!");
+ complainedAbout.put(way, way);
+ }
+ break; // give up with this way
+ }
+ }
+
+ // reset arc length
+ arcLength = 0;
+
+ // do the merge
+ ++numNodesMerged;
+ if (p.getOnBoundary()) {
+ // current point is a boundary node so we need
+ // to merge the previous node into this node
+ replacements.put(previousNode, p);
+ previousNode.setReplaced(true);
+ p.setTreatAsNode(true);
+ // remove the preceding point(s) back to and
+ // including the previous node
+ for(int j = i - 1; j >= previousNodeIndex; --j) {
+ points.remove(j);
+ }
+ } else {
+ // current point is not on a boundary so merge
+ // this node into the previous one
+ replacements.put(p, previousNode);
+ p.setReplaced(true);
+ previousNode.setTreatAsNode(true);
+ // reset previous point to be the previous
+ // node
+ previousPoint = previousNode;
+ // remove the point(s) back to the previous
+ // node
+ for (int j = i; j > previousNodeIndex; --j) {
+ points.remove(j);
+ }
+ }
+
+ // hack alert! rewind the loop index
+ i = previousNodeIndex;
+ modifiedRoads.put(way.getId(), way);
+ anotherPassRequired = true;
+ }
+ }
+ }
+ if (anotherPassRequired)
+ log.error("Removing short arcs - didn't finish in " + pass + " passes, giving up!");
+ else
+ log.info("Removing short arcs - finished in", pass, "passes (", numNodesMerged, "nodes merged,", numWaysDeleted, "ways deleted)");
+ }
+
+}
+
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/TypeReader.java b/src/uk/me/parabola/mkgmap/osmstyle/TypeReader.java
new file mode 100644
index 0000000..72c96b0
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/TypeReader.java
@@ -0,0 +1,221 @@
+package uk.me.parabola.mkgmap.osmstyle;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.LevelInfo;
+import uk.me.parabola.mkgmap.reader.osm.FeatureKind;
+import uk.me.parabola.mkgmap.reader.osm.GType;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+import uk.me.parabola.mkgmap.scan.TokType;
+import uk.me.parabola.mkgmap.scan.Token;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+/**
+ * Read a type description from a style file.
+ */
+public class TypeReader {
+ private static final Logger log = Logger.getLogger(TypeReader.class);
+
+ private final FeatureKind kind;
+ private final LevelInfo[] levels;
+ private static final Pattern HYPHEN_PATTERN = Pattern.compile("-");
+
+ public TypeReader(FeatureKind kind, LevelInfo[] levels) {
+ this.kind = kind;
+ this.levels = levels;
+ }
+
+ public GType readType(TokenScanner ts){
+ return readType(ts, false, null);
+ }
+
+ public GType readType(TokenScanner ts, boolean performChecks, Map<Integer, List<Integer>> overlays) {
+ // We should have a '[' to start with
+ Token t = ts.nextToken();
+ if (t == null || t.getType() == TokType.EOF)
+ throw new SyntaxException(ts, "No garmin type information given");
+
+ if (!t.getValue().equals("[")) {
+ throw new SyntaxException(ts, "No type definition");
+ }
+
+ ts.skipSpace();
+ String type = ts.nextValue();
+ if (!Character.isDigit(type.charAt(0)))
+ throw new SyntaxException(ts, "Garmin type number must be first. Saw '" + type + '\'');
+
+ log.debug("gtype", type);
+
+
+ GType gt = new GType(kind, type);
+ if (GType.checkType(gt.getFeatureKind(), gt.getType()) == false){
+ if (!performChecks && (kind != FeatureKind.POLYLINE || overlays == null || overlays.get(gt.getType()) == null))
+ throw new SyntaxException("invalid type " + type + " for " + kind + " in style file " + ts.getFileName() + ", line " + ts.getLinenumber());
+ }
+
+ while (!ts.isEndOfFile()) {
+ ts.skipSpace();
+ String w = ts.nextValue();
+ if (w.equals("]"))
+ break;
+
+ if (w.equals("level")) {
+ setLevel(ts, gt);
+ } else if (w.equals("resolution")) {
+ setResolution(ts, gt);
+ } else if (w.equals("default_name")) {
+ gt.setDefaultName(nextValue(ts));
+ } else if (w.equals("road_class")) {
+ gt.setRoadClass(nextIntValue(ts));
+ } else if (w.equals("road_speed")) {
+ gt.setRoadSpeed(nextIntValue(ts));
+ } else if (w.equals("copy")) {
+ // Reserved
+ } else if (w.equals("continue")) {
+ gt.setContinueSearch(true);
+ // By default no propagate of actions on continue
+ gt.propagateActions(false);
+ } else if (w.equals("propagate") || w.equals("with_actions") || w.equals("withactions")) {
+ gt.propagateActions(true);
+ } else if (w.equals("no_propagate")) {
+ gt.propagateActions(false);
+ } else if (w.equals("oneway")) {
+ // reserved
+ } else if (w.equals("access")) {
+ // reserved
+ } else {
+ throw new SyntaxException(ts, "Unrecognised type command '" + w + '\'');
+ }
+ }
+
+ gt.fixLevels(levels);
+ if (performChecks){
+ boolean fromOverlays = false;
+ List<Integer> usedTypes = null;
+ if (gt.getMaxResolution() < levels[0].getBits()){
+ System.out.println("Warning: Object with max resolution of " + gt.getMaxResolution() + " is ignored. Check levels option and style file "+ ts.getFileName() + ", line " + ts.getLinenumber());
+ }
+ if (overlays != null && kind == FeatureKind.POLYLINE){
+ usedTypes = overlays.get(gt.getType());
+ if (usedTypes != null)
+ fromOverlays = true;
+ }
+ if (usedTypes == null)
+ usedTypes = Arrays.asList(gt.getType());
+ for (int i = 0; i < usedTypes.size(); i++){
+ int usedType = usedTypes.get(i);
+ String typeOverlaidMsg = ". Type is overlaid with " + GType.formatType(usedType);
+ if (GType.checkType(kind, usedType) == false){
+ String msg = "Warning: invalid type " + type + " for " + kind + " in style file " + ts.getFileName() + ", line " + ts.getLinenumber();
+ if (fromOverlays)
+ msg += typeOverlaidMsg;
+ System.out.println(msg);
+ }
+ if (kind == FeatureKind.POLYLINE && gt.getMinLevel() == 0 && gt.getMaxLevel() >= 0 && GType.isRoutableLineType(usedType)){
+ if (gt.isRoad() == false){
+ String msg = "Warning: routable type " + type + " is used for non-routable line with level 0. This may break routing. Style file "+ ts.getFileName() + ", line " + ts.getLinenumber();
+ if (fromOverlays)
+ msg += typeOverlaidMsg;
+ System.out.println(msg);
+ }
+ else if (i > 0){
+ System.out.println("Warning: routable type " + type + " is used for non-routable line with level 0. " +
+ "This may break routing. Style file " + ts.getFileName() + ", line " + ts.getLinenumber() +
+ typeOverlaidMsg +
+ " which is used for adding the non-routable copy of the way.");
+ }
+ }
+ }
+ }
+
+ return gt;
+ }
+
+ private int nextIntValue(TokenScanner ts) {
+ if (ts.checkToken("="))
+ ts.nextToken();
+ try {
+ return ts.nextInt();
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(ts, "Expecting numeric value");
+ }
+ }
+
+ /**
+ * Get the value in a 'name=value' pair.
+ */
+ private String nextValue(TokenScanner ts) {
+ if (ts.checkToken("="))
+ ts.nextToken();
+ return ts.nextWord();
+ }
+
+ /**
+ * A resolution can be just a single number, in which case that is the
+ * min resolution and the max defaults to 24. Or a min to max range.
+ */
+ private void setResolution(TokenScanner ts, GType gt) {
+ String str = ts.nextWord();
+ log.debug("res word value", str);
+ try {
+ if (str.indexOf('-') >= 0) {
+ String[] minmax = HYPHEN_PATTERN.split(str, 2);
+ int val1 = Integer.parseInt(minmax[0]);
+ int val2 = Integer.parseInt(minmax[1]);
+ if (val1 > val2) {
+ // Previously there was a bug where the order was reversed, so we swap the numbers if they are
+ // the wrong way round.
+ int h = val1;
+ val1 = val2;
+ val2 = h;
+ }
+ gt.setMinResolution(val1);
+ gt.setMaxResolution(val2);
+ } else {
+ gt.setMinResolution(Integer.parseInt(str));
+ }
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(ts, "Invalid value for resolution: '" + str + '\'');
+ }
+ }
+
+ /**
+ * Read a level spec, which is either the max level or a min to max range.
+ * This is immediately converted to resolution(s).
+ */
+ private void setLevel(TokenScanner ts, GType gt) {
+ String str = ts.nextWord();
+ try {
+ if (str.indexOf('-') >= 0) {
+ String[] minmax = HYPHEN_PATTERN.split(str, 2);
+ int val1 = toResolution(Integer.parseInt(minmax[0]));
+ int val2 = toResolution(Integer.parseInt(minmax[1]));
+ if (val1 > val2) {
+ // Previously there was a bug where the order was reversed, so we swap the numbers if they are
+ // the wrong way round.
+ int h = val1;
+ val1 = val2;
+ val2 = h;
+ }
+ gt.setMinResolution(val1);
+ gt.setMaxResolution(val2);
+ } else {
+ gt.setMinResolution(toResolution(Integer.parseInt(str)));
+ }
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(ts, "Invalid value for level: '" + str + '\'');
+ }
+ }
+
+ private int toResolution(int level) {
+ int max = levels.length - 1;
+ if (level > max)
+ throw new SyntaxException("Level number too large, max=" + max);
+
+ return levels[max - level].getBits();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/Action.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/Action.java
new file mode 100644
index 0000000..85afc9b
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/Action.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 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: 15-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Perform some action on an Element. Add, change or remove tags.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface Action {
+
+ /**
+ * Perform the action on the element.
+ */
+ public void perform(Element el);
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/ActionList.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/ActionList.java
new file mode 100644
index 0000000..af4ae2a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/ActionList.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2009.
+ *
+ * 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.osmstyle.actions;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Wrap an a action list along with information about tags that could be
+ * affected by the actions.
+ * @author Steve Ratcliffe
+ */
+public class ActionList {
+ private final List<Action> list;
+ private final Set<String> changeableTags;
+
+ public ActionList(List<Action> list, Set<String> changeableTags) {
+ this.list = list;
+ this.changeableTags = changeableTags;
+ }
+
+ public List<Action> getList() {
+ return list;
+ }
+
+ public boolean isEmpty() {
+ return list.isEmpty();
+ }
+
+ public Set<String> getChangeableTags() {
+ return changeableTags;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/ActionReader.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/ActionReader.java
new file mode 100644
index 0000000..09b2659
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/ActionReader.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2008 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-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import uk.me.parabola.mkgmap.osmstyle.StyledConverter;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+import uk.me.parabola.mkgmap.scan.Token;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+/**
+ * Read an action block. This is contained within braces and contains
+ * commands to change tags etc.
+ *
+ * @author Steve Ratcliffe
+ */
+public class ActionReader {
+ private final TokenScanner scanner;
+
+ private final Set<String> usedTags = new HashSet<String>();
+
+ public ActionReader(TokenScanner scanner) {
+ this.scanner = scanner;
+ }
+
+ public ActionList readActions() {
+ List<Action> actions = new ArrayList<Action>();
+ Set<String> changeableTags = new HashSet<String>();
+ scanner.skipSpace();
+ if (!scanner.checkToken("{"))
+ return new ActionList(actions, changeableTags);
+
+ scanner.nextToken();
+ while (inAction()) {
+ Token tok = scanner.nextToken();
+ if (tok.isValue(";"))
+ continue;
+
+ String cmd = tok.getValue();
+ if ("set".equals(cmd)) {
+ actions.add(readTagValue(true, changeableTags));
+ } else if ("add".equals(cmd)) {
+ actions.add(readTagValue(false, changeableTags));
+ } else if ("setaccess".equals(cmd)) {
+ actions.add(readAccessValue(true, changeableTags));
+ } else if ("addaccess".equals(cmd)) {
+ actions.add(readAccessValue(false, changeableTags));
+ } else if ("apply".equals(cmd)) {
+ actions.add(readAllCmd(false));
+ } else if ("apply_once".equals(cmd)) {
+ actions.add(readAllCmd(true));
+ } else if ("name".equals(cmd)) {
+ actions.add(readValueBuilder(new NameAction()));
+ changeableTags.add("mkgmap:label:1");
+ } else if ("addlabel".equals(cmd)) {
+ actions.add(readValueBuilder(new AddLabelAction()));
+ for (int labelNo = 1; labelNo <= 4; labelNo++)
+ changeableTags.add("mkgmap:label:"+labelNo);
+ } else if ("delete".equals(cmd)) {
+ String tag = scanner.nextWord();
+ actions.add(new DeleteAction(tag));
+ } else if ("deletealltags".equals(cmd)) {
+ actions.add(new DeleteAllTagsAction());
+ } else if ("rename".equals(cmd)) {
+ String from = scanner.nextWord();
+ String to = scanner.nextWord();
+ Action act = new RenameAction(from, to);
+ actions.add(act);
+ // The 'to' tag may come into existence and you may attempt
+ // to match on it, therefore we have to save it.
+ changeableTags.add(to);
+ // the from tag must not be dropped from the input
+ usedTags.add(from);
+ } else if ("echo".equals(cmd)) {
+ String str = scanner.nextWord();
+ actions.add(new EchoAction(str));
+ } else if ("echotags".equals(cmd)) {
+ String str = scanner.nextWord();
+ actions.add(new EchoTagsAction(str));
+ } else {
+ throw new SyntaxException(scanner, "Unrecognised command '" + cmd + '\'');
+ }
+
+ scanner.skipSpace();
+ }
+ if (scanner.checkToken("}"))
+ scanner.nextToken();
+ scanner.skipSpace();
+
+ return new ActionList(actions, changeableTags);
+ }
+
+ private Action readAllCmd(boolean once) {
+ String role = null;
+ if (scanner.checkToken("role")) {
+ scanner.nextToken();
+ String eq = scanner.nextValue();
+ if (!"=".equals(eq))
+ throw new SyntaxException(scanner, "Expecting '=' after role keyword");
+ role = scanner.nextWord();
+ }
+ SubAction subAction = new SubAction(role, once);
+
+ List<Action> actionList = readActions().getList();
+ for (Action a : actionList)
+ subAction.add(a);
+
+ return subAction;
+ }
+
+ /**
+ * A name command has a number of alternatives separated by '|' characters.
+ */
+ private Action readValueBuilder(ValueBuildedAction action) {
+ while (inActionCmd()) {
+ if (scanner.checkToken("|")) {
+ scanner.nextToken();
+ continue;
+ }
+ String val = scanner.nextWord();
+ action.add(val);
+ }
+ usedTags.addAll(action.getUsedTags());
+ return action;
+ }
+
+ /**
+ * Read a tag/value pair. If the action is executed then the tag name
+ * will possibly be modified or set. If that is the case then we will
+ * have to make sure that we are executing rules for that tag.
+ *
+ * @param modify If true the tag value can be modified. If it is not set
+ * then a tag can only be added; if it already exists, then it will not
+ * be changed.
+ * @param changeableTags Tags that could be changed by the action. This is
+ * an output parameter, any such tags should be added to this set.
+ * @return The new add tag action.
+ */
+ private AddTagAction readTagValue(boolean modify, Set<String> changeableTags) {
+ String key = scanner.nextWord();
+ if (!scanner.checkToken("="))
+ throw new SyntaxException(scanner, "Expecting tag=value");
+ scanner.nextToken();
+
+ AddTagAction action = null;
+ while (inActionCmd()) {
+
+ String val = scanner.nextWord();
+ if (action == null)
+ action = new AddTagAction(key, val, modify);
+ else
+ action.add(val);
+ // Save the tag as one that is potentially set during the operation.
+ // If the value contains a variable, then we do not know what the
+ // value will be. Otherwise save the full tag=value
+ if (val.contains("$")) {
+ changeableTags.add(key);
+ } else {
+ changeableTags.add(key + "=" + val);
+ }
+ if (scanner.checkToken("|"))
+ scanner.nextToken();
+ }
+ if (action != null)
+ usedTags.addAll(action.getUsedTags());
+ return action;
+ }
+
+ /**
+ * Read a tag/value pair. If the action is executed then the tag name
+ * will possibly be modified or set. If that is the case then we will
+ * have to make sure that we are executing rules for that tag.
+ *
+ * @param modify If true the tag value can be modified. If it is not set
+ * then a tag can only be added; if it already exists, then it will not
+ * be changed.
+ * @param changeableTags Tags that could be changed by the action. This is
+ * an output parameter, any such tags should be added to this set.
+ * @return The new add tag action.
+ */
+ private AddAccessAction readAccessValue(boolean modify, Set<String> changeableTags) {
+ AddAccessAction action = null;
+ while (inActionCmd()) {
+
+ String val = scanner.nextWord();
+ if (action == null)
+ action = new AddAccessAction(val, modify);
+ else
+ action.add(val);
+ // Save the tag as one that is potentially set during the operation.
+ // If the value contains a variable, then we do not know what the
+ // value will be. Otherwise save the full tag=value
+ if (val.contains("$")) {
+ for (String accessTag : StyledConverter.ACCESS_TAGS)
+ changeableTags.add(accessTag);
+ } else {
+ for (String accessTag : StyledConverter.ACCESS_TAGS)
+ changeableTags.add(accessTag + "=" + val);
+ }
+ if (scanner.checkToken("|"))
+ scanner.nextToken();
+ }
+ if (action != null)
+ usedTags.addAll(action.getUsedTags());
+ return action;
+ }
+
+ private boolean inActionCmd() {
+ boolean end = scanner.checkToken(";");
+ return inAction() && !end;
+ }
+
+ private boolean inAction() {
+ return !scanner.isEndOfFile() && !scanner.checkToken("}");
+ }
+
+ public Set<String> getUsedTags() {
+ return usedTags;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/AddAccessAction.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/AddAccessAction.java
new file mode 100644
index 0000000..58fa53c
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/AddAccessAction.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2013.
+ *
+ * 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.osmstyle.actions;
+
+import java.util.List;
+
+import uk.me.parabola.mkgmap.osmstyle.StyledConverter;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Add one value to all mkgmap access tags, optionally changing them if they already exist.
+ * The value can have replacements from the current tags.
+ *
+ * @author WanMil
+ */
+public class AddAccessAction extends ValueBuildedAction {
+ private final boolean modify;
+
+ // The tags used to build the value.
+ private Element valueTags;
+
+ /**
+ * Create an action to add the given value to all mkgmap access tags.
+ * If the modify flag is false, then only those tags are set that do
+ * not already exist.
+ */
+ public AddAccessAction(String value, boolean modify) {
+ this.modify = modify;
+ add(value);
+ }
+
+ public void perform(Element el) {
+ // 1st build the value
+ Element tags = valueTags!=null? valueTags: el;
+ String accessValue = null;
+ for (ValueBuilder value : getValueBuilder()) {
+ accessValue = value.build(tags, el);
+ if (accessValue != null) {
+ break;
+ }
+ }
+ if (accessValue == null) {
+ return;
+ }
+ for (String accessTag : StyledConverter.ACCESS_TAGS) {
+ setTag(el, accessTag, accessValue);
+ }
+ }
+
+ /**
+ * Set the tag of the given element. In case the modify flag
+ * is {@code true} the tag is always set. Otherwise the tag
+ * is set only if it does not already exist.
+ * @param el OSM element
+ * @param tag the tag name
+ * @param value the value to be set
+ */
+ private void setTag(Element el, String tag, String value) {
+ String tv = el.getTag(tag);
+ if (tv != null && !modify)
+ return;
+
+ el.addTag(tag, value);
+ }
+
+ public void setValueTags(Element valueTags) {
+ this.valueTags = valueTags;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(modify ? "setaccess " : "addaccess ");
+ List<ValueBuilder> values = getValueBuilder();
+ for (int i = 0; i < values.size(); i++) {
+ sb.append(values.get(i));
+ if (i < values.size() - 1)
+ sb.append(" | ");
+ }
+ sb.append(';');
+ return sb.toString();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/AddLabelAction.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/AddLabelAction.java
new file mode 100644
index 0000000..f267f8e
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/AddLabelAction.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013
+ *
+ * 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.
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Set the first unset label on the given element. The tags of the element may be
+ * used in setting the label.
+ *
+ * We have a list of possible substitutions.
+ */
+public class AddLabelAction extends ValueBuildedAction {
+
+ /**
+ * Search for the first matching pattern and set the first unset element label
+ * to it.
+ *
+ * If all four labels are already set, then nothing is done.
+ *
+ * @param el The element on which a label may be set.
+ */
+ public void perform(Element el) {
+ for (int index = 1; index <=4; index++) {
+ // find the first unset label and set it
+ if (el.getTag("mkgmap:label:"+index) == null) {
+ for (ValueBuilder vb : getValueBuilder()) {
+ String s = vb.build(el, el);
+ if (s != null) {
+ // now check if the new label is different to all other labels
+ for (int n = index-1; n>= 1; n--) {
+ if (s.equals(el.getTag("mkgmap:label:"+n))) {
+ // value is equal to a previous label
+ // do not use it
+ return;
+ }
+ }
+
+ // set the label
+ el.addTag("mkgmap:label:"+index, s);
+ return;
+ }
+ }
+ return;
+ }
+ }
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("addlabel ");
+ for (ValueBuilder vb : getValueBuilder()) {
+ sb.append(vb);
+ sb.append(" | ");
+ }
+ sb.setLength(sb.length() - 1);
+ return sb.toString();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/AddTagAction.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/AddTagAction.java
new file mode 100644
index 0000000..969c51c
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/AddTagAction.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2008 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: 15-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import java.util.List;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Add a tag, optionally changing it if it already exists. The value that
+ * the tag is set to can have replacements from the current tags.
+ *
+ * @author Steve Ratcliffe
+ */
+public class AddTagAction extends ValueBuildedAction {
+ private final boolean modify;
+ private final String tag;
+
+ // The tags used to build the value.
+ private Element valueTags;
+
+ /**
+ * Create an action to add the given tag with a value.
+ * If the modify flag is true, then we change the tag if it
+ * already exists.
+ */
+ public AddTagAction(String tag, String value, boolean modify) {
+ this.modify = modify;
+ this.tag = tag;
+ add(value);
+ }
+
+ public void perform(Element el) {
+ String tv = el.getTag(tag);
+ if (tv != null && !modify)
+ return;
+
+ Element tags = valueTags!=null? valueTags: el;
+
+ for (ValueBuilder value : getValueBuilder()) {
+ String newval = value.build(tags, el);
+ if (newval != null) {
+ el.addTag(tag, newval);
+ break;
+ }
+ }
+ }
+
+
+ public void setValueTags(Element valueTags) {
+ this.valueTags = valueTags;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(modify ? "set " : "add ");
+ sb.append(tag);
+ sb.append("=");
+ List<ValueBuilder> values = getValueBuilder();
+ for (int i = 0; i < values.size(); i++) {
+ sb.append(values.get(i));
+ if (i < values.size() - 1)
+ sb.append(" | ");
+ }
+ sb.append(';');
+ return sb.toString();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/ConvertFilter.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/ConvertFilter.java
new file mode 100644
index 0000000..64ce549
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/ConvertFilter.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2008 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: 07-Dec-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.osmstyle.eval.UnitConversions;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Convert a numeric quantity from one set of units to another.
+ *
+ * TODO: this will change a lot it is just here for backward compatibility
+ * at present.
+ * @author Steve Ratcliffe
+ */
+public class ConvertFilter extends ValueFilter {
+ private final double factor;
+
+ public ConvertFilter(String arg) {
+ factor = UnitConversions.convertFactor(arg);
+ }
+
+ protected String doFilter(String value, Element el) {
+ if (value == null) return null;
+
+ try {
+ double d = Double.parseDouble(value);
+
+ double res = d * factor;
+ res = Math.round(res);
+ return String.valueOf((int) res);
+ } catch (NumberFormatException e) {
+ return value;
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/DefaultFilter.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/DefaultFilter.java
new file mode 100644
index 0000000..17f5084
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/DefaultFilter.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 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: 07-Dec-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Provide a default value if there is not one present.
+ * Do we really need this?
+ * @author Steve Ratcliffe
+ */
+public class DefaultFilter extends ValueFilter {
+ private final String def;
+
+ public DefaultFilter(String d) {
+ def = d;
+ }
+
+ public String doFilter(String value, Element el) {
+ return value == null || value.length() == 0 ? def : value;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/DeleteAction.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/DeleteAction.java
new file mode 100644
index 0000000..faac87f
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/DeleteAction.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 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: 29-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Deletes a tag.
+ *
+ * @author Steve Ratcliffe
+ */
+public class DeleteAction implements Action {
+ private final String tag;
+
+ public DeleteAction(String tag) {
+ this.tag = tag;
+ }
+
+ public void perform(Element el) {
+ el.deleteTag(tag);
+ }
+
+ public String toString() {
+ return "delete " + tag + ";";
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/DeleteAllTagsAction.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/DeleteAllTagsAction.java
new file mode 100644
index 0000000..b446640
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/DeleteAllTagsAction.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013.
+ *
+ * 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.osmstyle.actions;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.Node;
+
+/**
+ * Delete all tags from an element. This is useful to stop its processing.
+ *
+ * @author WanMil
+ */
+public class DeleteAllTagsAction implements Action {
+
+ // as long as there is not deleteAll method copy the tags of element without tags
+ private final Element noTagElement;
+
+ public DeleteAllTagsAction() {
+ this.noTagElement = new Node(0, new Coord(0,0));
+ }
+
+ public void perform(Element el) {
+ // remove all tags by copying the tags from a no tag element
+ el.copyTags(noTagElement);
+ }
+
+ public String toString() {
+ return "deletealltags;";
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/EchoAction.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/EchoAction.java
new file mode 100644
index 0000000..062953b
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/EchoAction.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2009
+ *
+ * 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: Richard Fairhurst
+ * Create date: 29-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Sends a message to the console.
+ *
+ * @author Richard Fairhurst
+ */
+public class EchoAction implements Action {
+ private final ValueBuilder value;
+
+ public EchoAction(String str) {
+ this.value = new ValueBuilder(str, false);
+ }
+
+ public void perform(Element el) {
+ String e = value.build(el, el);
+ System.err.println(el.getId() + ": " + e);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/EchoTagsAction.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/EchoTagsAction.java
new file mode 100644
index 0000000..99650a2
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/EchoTagsAction.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2013.
+ *
+ * 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.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Sends a message including the tags of an element to System.err.
+ *
+ * @author WanMil
+ */
+public class EchoTagsAction implements Action {
+ private final ValueBuilder value;
+
+ public EchoTagsAction(String str) {
+ this.value = new ValueBuilder(str, false);
+ }
+
+ public void perform(Element el) {
+ String e = value.build(el, el);
+ System.err.println(el.getId() + " - " + el.toTagString()+" " + e);
+ }
+
+ public String toString() {
+ return "echotags " + value + ";";
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/HeightFilter.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/HeightFilter.java
new file mode 100644
index 0000000..33b2180
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/HeightFilter.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2009 Toby Speight
+ *
+ * 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.
+ */
+
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * A <code>HeightFilter</code> transforms values into Garmin-tagged elevations.
+ *
+ * @author Toby Speight
+ *
+ * @since 2009-04-26
+ */
+public class HeightFilter extends ConvertFilter {
+
+ public HeightFilter(String s) {
+ super(s);
+ }
+
+ public String doFilter(String value, Element el) {
+ String s = super.doFilter(value, el);
+ if (s != null)
+ s = "\u001f" + s;
+ return s;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/HighwaySymbolFilter.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/HighwaySymbolFilter.java
new file mode 100644
index 0000000..a63bf1f
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/HighwaySymbolFilter.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2009 Toby Speight
+ *
+ * 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.
+ */
+
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+
+/**
+ * Prepend a Garmin magic-character to the value.
+ * TODO: symbolic names?
+ *
+ * @author Toby Speight
+ */
+public class HighwaySymbolFilter extends ValueFilter {
+ private final String prefix;
+
+ private static final Map<String, String>symbols = new HashMap<String, String>();
+ private static final int MAX_REF_LENGTH = 8; // enough for "A6144(M)" (RIP)
+
+ private int maxAlphaNum = MAX_REF_LENGTH; // Max. length for alphanumeric (e.g., 'A67')
+ private int maxAlpha = MAX_REF_LENGTH; // Max. length for alpha only signs (e.g., 'QEW')
+
+ static {
+ //symbols.put("ele", "\u001f"); // name.height separator
+
+ // Now add other symbols
+ symbols.put("interstate", "\u0001"); // US Interstate
+ symbols.put("shield", "\u0002"); // US Highway shield
+ symbols.put("round", "\u0003"); // US Highway round
+ symbols.put("hbox", "\u0004"); // box with horizontal bands
+ symbols.put("box", "\u0005"); // Square box
+ symbols.put("oval", "\u0006"); // box with rounded ends
+ }
+
+ public HighwaySymbolFilter(String s) {
+
+ String[] filters = s.split(":");
+
+ // First, try the lookup table
+ String p = symbols.get(filters[0]);
+ if (p == null) {
+ p = "[" + filters[0] + "]";
+ }
+ prefix = p;
+
+ // Set maximum length for alpha/alphanumeric signs:
+ if ( filters.length == 3 ) {
+ maxAlphaNum = Integer.parseInt(filters[1]);
+ maxAlpha = Integer.parseInt(filters[2]);
+ } else if ( filters.length == 2 ) {
+ maxAlphaNum = Integer.parseInt(filters[1]);
+ maxAlpha = maxAlphaNum; // If only one option specified, use for both
+ } else {
+ maxAlphaNum = MAX_REF_LENGTH; // Ensure use of defaults if none specified
+ maxAlpha = MAX_REF_LENGTH;
+ }
+
+ }
+
+ public String doFilter(String value, Element el) {
+ if (value == null) return value;
+
+ // is it mostly alphabetic?
+ /* int alpha_balance = 0;
+ for (char c : value.toCharArray()) {
+ alpha_balance += (Character.isLetter(c)) ? 1 : -1;
+ }
+ if (alpha_balance > 0) return value;
+
+ // remove space if there is exactly one
+ int first_space = value.indexOf(" ");
+ if (first_space >= 0 && value.indexOf(" ", first_space + 1) < 0) {
+ value = value.replace(" ", "");
+ } */
+
+
+ // Nuke all spaces
+ String shieldText = value.replace(" ", "");
+
+ // Also replace ";" with "/", to change B3;B4 to B3/B4
+ shieldText = shieldText.replace(";", "/");
+
+ // Check if value is alphanumeric
+ boolean isAlphaNum = false;
+
+ for (char c : shieldText.toCharArray()) {
+ if (Character.isDigit(c)) {
+ isAlphaNum = true; // Consider alphanumeric if we find one or more digits
+ }
+ }
+
+ // Check if shield exceeds maximum length:
+ if ( (isAlphaNum && shieldText.length() > maxAlphaNum) || (! isAlphaNum) && shieldText.length() > maxAlpha ) {
+ return value; // If so, return original value
+ } else {
+ return prefix + shieldText; // If not, return condensed value with magic code
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/NameAction.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/NameAction.java
new file mode 100644
index 0000000..ce3aa2a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/NameAction.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2008 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: 02-Dec-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Set the name on the given element. The tags of the element may be
+ * used in setting the name.
+ *
+ * We have a list of possible substitutions.
+ *
+ * @author Steve Ratcliffe
+ */
+public class NameAction extends ValueBuildedAction {
+
+ /**
+ * search for the first matching name pattern and set the element name
+ * to it.
+ *
+ * If the element name is already set, then nothing is done.
+ *
+ * @param el The element on which the name may be set.
+ */
+ public void perform(Element el) {
+ if (el.getTag("mkgmap:label:1") != null)
+ return;
+
+ for (ValueBuilder vb : getValueBuilder()) {
+ String s = vb.build(el, el);
+ if (s != null) {
+ el.addTag("mkgmap:label:1", s);
+ break;
+ }
+ }
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("name ");
+ for (ValueBuilder vb : getValueBuilder()) {
+ sb.append(vb);
+ sb.append(" | ");
+ }
+ sb.setLength(sb.length() - 1);
+ return sb.toString();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/NotEqualFilter.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/NotEqualFilter.java
new file mode 100644
index 0000000..a7eaee9
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/NotEqualFilter.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2009 Clinton Gladstone
+ *
+ * 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.
+ */
+
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * This can be used to filter out redundant values.
+ *
+ * The filter checks the equality of a value with another tag's value.
+ * If the two values match, a null string is returned.
+ *
+ * @author Clinton Gladstone
+ */
+public class NotEqualFilter extends ValueFilter {
+
+ private final String tagName;
+
+ public NotEqualFilter(String s) {
+
+ tagName = s;
+
+ }
+
+ public String doFilter(String value, Element el) {
+ if (value == null) return value;
+
+ String tagValue = el.getTag(tagName);
+
+ if (tagValue == null)
+ return value;
+
+ if (value.equals(tagValue))
+ return null; // Return nothing if value is identical to the tag's value
+ else
+ return value;
+
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/PartFilter.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/PartFilter.java
new file mode 100644
index 0000000..c1a447e
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/PartFilter.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2013.
+ *
+ * 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.osmstyle.actions;
+
+import java.util.regex.Pattern;
+import uk.me.parabola.imgfmt.ExitException;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Split a value in parts and returns one or more part(s) of a value.
+ * value is split at a separator that defaults to semicolon ';'
+ * by default the first part is returned
+ *
+ * if the optional second parameter 'partnumber' is out of
+ * range then null is returned
+ *
+ * if the optional second parameter is negative
+ * the part returned is counted from the end of the split
+ *
+ * if the the split operator is a > or < and the
+ * the correspondent number of parts are returned
+ *
+ * Example: if the value is "Aa#Bb#Cc#Dd#Ee"
+ * part:#:1 returns Aa
+ * part:#:-1 returns Ee
+ * part:#:2 returns Bb
+ * part:#:-2 returns Dd
+ * part:#>1 returns Bb#Cc#Dd#Ee#
+ * part:#<5 returns Aa#Bb#Cc#Dd#
+ * part:#<-1 returns Aa#Bb#Cc#Dd#
+ *
+ * @author Franco Bez
+ * @author Enrico Liboni
+ */
+public class PartFilter extends ValueFilter {
+ private String separator;
+ private int partnumber;
+ private boolean isLt=false; // less than <
+ private boolean isGt=false; // great than >
+
+ public PartFilter(String arg) {
+ String[] temp;
+
+ // detect which operator is used
+ if (arg.contains(":")) {
+ temp = arg.split(":");
+ } else if (arg.contains(">")) {
+ temp = arg.split(">");
+ isGt = true;
+ } else if (arg.contains("<")) {
+ temp = arg.split("<");
+ isLt = true;
+ } else { // no operators default to arg
+ temp = new String[] { arg };
+ }
+
+ partnumber = 1;
+ try {
+ // set the part number (default is 1)
+ if( temp.length > 1 ) {
+ partnumber = Integer.parseInt(temp[1]);
+ }
+ // set the separator (default to ;)
+ if(temp[0].length() > 0 ){
+ separator = temp[0];
+ }
+ else{
+ separator = ";";
+ }
+ } catch (NumberFormatException e) {
+ throw new ExitException("Not valid numbers in style part command: " + arg);
+ }
+ }
+
+ public String doFilter(String value, Element el) {
+ if (value == null || partnumber == 0) return null;
+ // split uses a regex we need to replace special characters
+ String[] temp = value.split(Pattern.quote(separator));
+
+ // check if partnumber is in range, if not return null
+ if (temp.length < Math.abs(partnumber) ) return null;
+
+ // get the index of the partnumber
+ // if the partnumber is negative the part is counted from the end of the split
+ int idx=(partnumber > 0)?(partnumber-1):(temp.length+partnumber);
+
+ // default operator ":": return the part
+ if ( !isLt && !isGt ) {
+ return temp[idx].trim();
+ } else {
+ StringBuffer returnValue= new StringBuffer();
+
+ // operator "<": collate all the parts before the partnumber
+ if ( isLt ) {
+ for (int i=0;i<idx;i++) {
+ returnValue.append(temp[i]).append(separator);
+ }
+ }
+
+ // operator ">": collate all the parts after the partnumber
+ if ( isGt ) {
+ for (int i=idx+1;i<temp.length;i++) {
+ returnValue.append(temp[i]).append(separator);
+ }
+ }
+
+ // return the result
+ return returnValue.toString();
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/PrependFilter.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/PrependFilter.java
new file mode 100644
index 0000000..653d33b
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/PrependFilter.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2009 Toby Speight
+ *
+ * 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.
+ */
+
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+
+/**
+ * Prepend a Garmin magic-character to the value.
+ * TODO: symbolic names?
+ *
+ * @author Toby Speight
+ */
+public class PrependFilter extends ValueFilter {
+ private final String prefix;
+
+ private static final Map<String, String> symbols_6bit;
+ private static final Map<String, String> symbols_8bit;
+
+ static {
+ // Firstly, the symbols common to both encodings.
+ symbols_6bit = new HashMap<String, String>();
+ symbols_6bit.put("ele", "\u001f"); // name.height separator
+
+ // Copy to other encoding
+ symbols_8bit = new HashMap<String, String>(symbols_6bit);
+
+ // Now add other symbols
+ symbols_6bit.put("interstate", "\u002a"); // US Interstate
+ symbols_8bit.put("interstate", "\u0001");
+ symbols_6bit.put("shield", "\u002b"); // US Highway shield
+ symbols_8bit.put("shield", "\u0002");
+ symbols_6bit.put("round", "\u002c"); // US Highway round
+ symbols_8bit.put("round", "\u0003");
+ symbols_6bit.put("boxx", "\u002d"); // box with horizontal bands
+ symbols_8bit.put("boxx", "\u0004");
+ symbols_6bit.put("box", "\u002e"); // Square box
+ symbols_8bit.put("box", "\u0005");
+ symbols_6bit.put("oval", "\u002f"); // box with rounded ends
+ symbols_8bit.put("oval", "\u0006");
+ }
+
+ // TODO: runtime select appropriate table
+
+ public PrependFilter(String s) {
+ // First, try the lookup table
+ Map<String, String> symbols = symbols_8bit;
+ String p = symbols.get(s);
+ if (p == null) {
+ // else, s is a hex constant character number
+ try {
+ p = Character.toString((char)Integer.parseInt(s, 16));
+ } catch (NumberFormatException e) {
+ // failed - use string literally
+ p = s;
+ }
+ }
+ prefix = p;
+ }
+
+ public String doFilter(String value, Element el) {
+ return value == null ? null : prefix + value;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/RenameAction.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/RenameAction.java
new file mode 100644
index 0000000..c31115e
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/RenameAction.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008 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: 29-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Renames a tag. Specifically takes the value of the 'from' tag, sets
+ * the value of the 'to' tag and removes the 'from' tag.
+ * @author Steve Ratcliffe
+ */
+public class RenameAction implements Action {
+ private final String from;
+ private final String to;
+
+ public RenameAction(String from, String to) {
+ this.from = from;
+ this.to = to;
+ }
+
+ public void perform(Element el) {
+ String fromval = el.getTag(from);
+ if (fromval != null) {
+ el.addTag(to, fromval);
+ el.deleteTag(from);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/SubAction.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/SubAction.java
new file mode 100644
index 0000000..83c834b
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/SubAction.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2008 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: 06-Dec-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import java.util.ArrayList;
+import java.util.Formatter;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+
+/**
+ * This is an action that contains sub-actions. It is used for Relations
+ * where you want to apply the commands to the elements that are contained
+ * in the relation and not on the relation itself.
+ *
+ * @author Steve Ratcliffe
+ */
+public class SubAction implements Action {
+ private final List<Action> actionList = new ArrayList<Action>();
+ private final String role;
+ private final boolean once;
+
+ public SubAction(String role, boolean once) {
+ this.role = role;
+ this.once = once;
+ }
+
+ public void perform(Element el) {
+ if (el instanceof Relation)
+ performOnSubElements((Relation) el);
+ }
+
+ private void performOnSubElements(Relation rel) {
+ List<Map.Entry<String,Element>> elements = rel.getElements();
+
+ for (Action a : actionList)
+ if (a instanceof AddTagAction)
+ ((AddTagAction) a).setValueTags(rel);
+ else if (a instanceof AddAccessAction)
+ ((AddAccessAction) a).setValueTags(rel);
+
+ HashSet<Element> elems = once ? new HashSet<Element>() : null;
+
+ for (Map.Entry<String,Element> r_el : elements) {
+ if ((role == null || role.equals(r_el.getKey())) &&
+ (!once || elems.add(r_el.getValue()))) {
+
+ for (Action a : actionList)
+ a.perform(r_el.getValue());
+ }
+ }
+ }
+
+ public void add(Action act) {
+ actionList.add(act);
+ }
+
+ public String toString() {
+ Formatter fmt = new Formatter();
+ fmt.format(once ? "apply_once" : "apply");
+ if (role != null)
+ fmt.format(" role=%s ", role);
+
+ fmt.format(" {");
+
+ for (Iterator<Action> it = actionList.iterator(); it.hasNext();) {
+ Action a = it.next();
+ fmt.format(a.toString());
+ if (it.hasNext())
+ fmt.format(" ");
+ }
+
+ fmt.format("}");
+ return fmt.toString();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/SubstitutionFilter.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/SubstitutionFilter.java
new file mode 100644
index 0000000..3344bfa
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/SubstitutionFilter.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2009 Toby Speight
+ *
+ * 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.
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Perform string substitution on a value.
+ * The operator => can be used for exact string substitution
+ * The operator ~> can be used for regexp substitutions
+ * If no operator is set, the matching string is deleted
+ *
+ * @author Toby Speight
+ * @author Enrico Liboni
+ */
+public class SubstitutionFilter extends ValueFilter {
+ private final String from;
+ private final String to;
+ private boolean isRegexp = false;
+
+ public SubstitutionFilter(String arg) {
+ int i = arg.indexOf("=>");
+
+ if (i == -1) { // no occurrences of =>, let's try with ~>
+ i = arg.indexOf("~>");
+ if ( i >= 0 ) isRegexp = true;
+ }
+
+ if (i >= 0) {
+ from = arg.substring(0, i);
+ to = arg.substring(i + 2);
+ } else {
+ from = arg;
+ to = "";
+ }
+ }
+
+ public String doFilter(String value, Element el) {
+ if (value == null) return null;
+ if (from == null || to == null)
+ // can't happen!
+ return value;
+ // replaceAll expects a regexp as 1st argument
+ return (isRegexp ? value.replaceAll(from, to) : value.replace(from, to) );
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/SubstringFilter.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/SubstringFilter.java
new file mode 100644
index 0000000..3710a81
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/SubstringFilter.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 Jeffrey C. Ollie
+ *
+ * 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: Jeffrey C. Ollie
+ * Create date: 08-March-2010
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import uk.me.parabola.imgfmt.ExitException;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Extract a substring from a value
+ *
+ * @author Jeffrey C. Ollie
+ */
+public class SubstringFilter extends ValueFilter {
+ private int args;
+ private int start;
+ private int end;
+
+ public SubstringFilter(String arg) {
+ start = 0;
+ end = 0;
+ args = 0;
+
+ String[] temp = arg.split(":");
+
+ try {
+ if (temp.length == 1) {
+ start = Integer.parseInt(temp[0]);
+ args = 1;
+ } else if (temp.length == 2) {
+ start = Integer.parseInt(temp[0]);
+ end = Integer.parseInt(temp[1]);
+ args = 2;
+ } else {
+ start = 0;
+ end = 0;
+ args = 0;
+ }
+ } catch (NumberFormatException e) {
+ throw new ExitException("Not valid numbers in style substring command: " + arg);
+ }
+ }
+
+ protected String doFilter(String value, Element el) {
+ if (value == null) return null;
+
+ if (args == 1) {
+ return value.substring(start);
+ }
+ if (args == 2) {
+ return value.substring(start, end);
+ }
+ return value;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuildedAction.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuildedAction.java
new file mode 100644
index 0000000..be9019a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuildedAction.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2013
+ *
+ * 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.
+ *
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public abstract class ValueBuildedAction implements Action {
+
+ private final List<ValueBuilder> valueBuilder = new ArrayList<ValueBuilder>();
+
+ /**
+ * Adds a value building rule.
+ * @param val rule
+ */
+ public void add(String val) {
+ valueBuilder.add(new ValueBuilder(val));
+ }
+
+ /**
+ * Retrieve the tags that might be used to build the value.
+ * @return all required tags
+ */
+ public Set<String> getUsedTags() {
+ Set<String> set = new HashSet<String>();
+ for (ValueBuilder vb : valueBuilder) {
+ set.addAll(vb.getUsedTags());
+ }
+ return set;
+ }
+
+ /**
+ * Retrieves the list of value builders.
+ * @return value builders
+ */
+ protected List<ValueBuilder> getValueBuilder() {
+ return valueBuilder;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuilder.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuilder.java
new file mode 100644
index 0000000..5c0e516
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuilder.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2008 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: 02-Dec-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Build a value that can have tag values substituted in it.
+ *
+ * @author Steve Ratcliffe
+ * @author Toby Speight
+ */
+public class ValueBuilder {
+
+ private final List<ValueItem> items = new ArrayList<ValueItem>();
+ private final boolean completeCheck;
+
+ public ValueBuilder(String pattern) {
+ this (pattern, true);
+ }
+
+ public ValueBuilder(String pattern, boolean completeCheck) {
+ this.completeCheck =completeCheck;
+ compile(pattern);
+ }
+
+ /**
+ * Build this string if all the tags that are required are available.
+ *
+ * If a tag does not exist then the whole string is rejected. This allows
+ * you to make conditional replacements.
+ *
+ * @param el Used as a source of tags.
+ * @param lel Used as a source of local tags.
+ * @return The built string if all required tags are available. If any
+ * are missing then it returns null.
+ */
+ public String build(Element el, Element lel) {
+ if (completeCheck) {
+ // Check early for no match and return early
+ for (ValueItem item : items) {
+ if (item.getValue(el, lel) == null)
+ return null;
+ }
+ }
+
+ // If we get here we can build the final string. A common case
+ // is that there is just one, so return it directly.
+ if (items.size() == 1)
+ return items.get(0).getValue(el, lel);
+
+ // OK we have to construct the result.
+ StringBuilder sb = new StringBuilder();
+ for (ValueItem item : items)
+ sb.append(item.getValue(el, lel));
+
+ return sb.toString();
+ }
+
+ /**
+ * A tag value can contain variables that are the values of other tags.
+ * This is especially useful for 'name', as you might want to set it to
+ * some combination of other tags.
+ *
+ * If there are no replacement values, the same string as was passed
+ * in. If all the replacement values exist, then the string with the
+ * values all replaced. If any replacement tagname does not exist
+ * then returns null.
+
+ * @param in An input string that may contain tag replacement introduced
+ * by ${tagname}.
+ */
+ private void compile(String in) {
+ if (!in.contains("$")) {
+ items.add(new ValueItem(in));
+ return;
+ }
+
+ char state = '\0';
+ StringBuilder text = new StringBuilder();
+ StringBuilder tagname = null;
+ for (char c : in.toCharArray()) {
+ switch (state) {
+ case '\0':
+ if (c == '$') {
+ state = '$';
+ } else
+ text.append(c);
+ break;
+ case '$':
+ switch (c) {
+ case '{':
+ case '(':
+ if (text.length() > 0) {
+ items.add(new ValueItem(text.toString()));
+ text.setLength(0);
+ }
+ tagname = new StringBuilder();
+ state = (c == '{') ? '}' : ')';
+ break;
+ default:
+ state = '\0';
+ text.append('$');
+ text.append(c);
+ }
+ break;
+ case '}':
+ case ')':
+ if (c == state) {
+ //noinspection ConstantConditions
+ assert tagname != null;
+ addTagValue(tagname.toString(), c == ')');
+ state = '\0';
+ tagname = null;
+ } else {
+ tagname.append(c);
+ }
+ break;
+ default:
+ assert false;
+ }
+ }
+
+ if (text.length() > 0)
+ items.add(new ValueItem(text.toString()));
+ }
+
+ private void addTagValue(String tagname, boolean is_local) {
+ ValueItem item = new ValueItem();
+ if (tagname.contains("|")) {
+ String[] parts = tagname.split("\\|");
+ assert parts.length > 1;
+ item.setTagname(parts[0], is_local);
+ for (int i = 1; i < parts.length; i++)
+ addFilter(item, parts[i]);
+ } else {
+ item.setTagname(tagname, is_local);
+ }
+ items.add(item);
+ }
+
+ private void addFilter(ValueItem item, String expr) {
+ Pattern pattern = Pattern.compile("([^:]+):(.*)");
+ //pattern.
+ Matcher matcher = pattern.matcher(expr);
+ matcher.find();
+ String cmd = matcher.group(1);
+ String arg = matcher.group(2);
+ if (cmd.equals("def")) {
+ item.addFilter(new DefaultFilter(arg));
+ } else if (cmd.equals("conv")) {
+ item.addFilter(new ConvertFilter(arg));
+ } else if (cmd.equals("subst")) {
+ item.addFilter(new SubstitutionFilter(arg));
+ } else if (cmd.equals("prefix")) {
+ item.addFilter(new PrependFilter(arg));
+ } else if (cmd.equals("highway-symbol")) {
+ item.addFilter(new HighwaySymbolFilter(arg));
+ } else if (cmd.equals("height")) {
+ item.addFilter(new HeightFilter(arg));
+ } else if (cmd.equals("not-equal")) {
+ item.addFilter(new NotEqualFilter(arg));
+ } else if (cmd.equals("substring")) {
+ item.addFilter(new SubstringFilter(arg));
+ } else if (cmd.equals("part")) {
+ item.addFilter(new PartFilter(arg));
+ }
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder("'");
+ for (ValueItem v : items) {
+ sb.append(v);
+ }
+ sb.append("'");
+ return sb.toString();
+ }
+
+ public Set<String> getUsedTags() {
+ Set<String> set = new HashSet<String>();
+ for (ValueItem v : items) {
+ String tagname = v.getTagname();
+ if (tagname != null)
+ set.add(tagname);
+ }
+ return set;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/ValueFilter.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/ValueFilter.java
new file mode 100644
index 0000000..172e7c3
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/ValueFilter.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 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: 07-Dec-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Filter a value. This is used for special effects and not for the majority
+ * of substitutions.
+ *
+ * Takes a value, applies the filter and returns the result. Filters
+ * can be chained.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class ValueFilter {
+ private ValueFilter next;
+
+ public final String filter(String value, Element el) {
+ String res = doFilter(value, el);
+
+ ValueFilter current = next;
+ while (current != null) {
+ res = current.doFilter(res, el);
+ current = current.next;
+ }
+
+ return res;
+ }
+
+ protected abstract String doFilter(String value, Element el);
+
+ public void add(ValueFilter f) {
+ if (next == null)
+ next = f;
+ else
+ next.add(f);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/ValueItem.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/ValueItem.java
new file mode 100644
index 0000000..b1f0ab5
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/ValueItem.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2008 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: 07-Dec-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Part of a substitution string. This can represent a constant
+ * value or value that is taken from the element tags.
+ *
+ * @author Steve Ratcliffe
+ */
+public class ValueItem {
+ private String tagname;
+ private boolean tagname_is_local;
+ private ValueFilter filter;
+ private String value;
+
+ public ValueItem() {
+ }
+
+ public ValueItem(String value) {
+ this.value = value;
+ }
+
+ public String getValue(Element el, Element local_el) {
+ if (tagname == null && value != null)
+ return value; // already known
+
+ if (tagname != null) {
+ Element e = tagname_is_local ? local_el : el;
+ String tagval = e.getTag(tagname);
+ if (filter != null)
+ value = filter.filter(tagval,el);
+ else
+ value = tagval;
+ }
+
+ return value;
+ }
+
+ public void addFilter(ValueFilter f) {
+ if (filter == null)
+ filter = f;
+ else
+ filter.add(f);
+ }
+
+ public String getTagname() {
+ return tagname;
+ }
+
+ public void setTagname(String tagname, boolean local) {
+ this.tagname = tagname;
+ this.tagname_is_local = local;
+ }
+
+ public String toString() {
+ if (tagname == null)
+ return value;
+ if (tagname_is_local) {
+ // TODO: don't ignore filter.
+ return "$(" + tagname + ")";
+ } else {
+ // TODO: don't ignore filter.
+ return "${" + tagname + "}";
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/AbstractBinaryOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/AbstractBinaryOp.java
new file mode 100644
index 0000000..bf9f8bb
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/AbstractBinaryOp.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 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: 03-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import static uk.me.parabola.mkgmap.osmstyle.eval.NodeType.VALUE;
+
+/**
+ * A base class that can be used for binary operations.
+ * It has a second operand.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class AbstractBinaryOp extends AbstractOp implements BinaryOp {
+
+ private Op second;
+
+ public Op getSecond() {
+ return second;
+ }
+
+ public void setSecond(Op second) {
+ this.second = second;
+ }
+
+ public String toString() {
+ String t2 = second.isType(VALUE) ? "'" + second + "'" : second.toString();
+ return "(" + getFirst() + getType().toSymbol() + t2 + ')';
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/AbstractOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/AbstractOp.java
new file mode 100644
index 0000000..58ded00
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/AbstractOp.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2008-2012 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: 03-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+
+/**
+ * A base class that can be used as the superclass of an operation.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class AbstractOp implements Op {
+
+ protected Op first;
+ private NodeType type;
+
+ public static Op createOp(String value) {
+ char c = value.charAt(0);
+ Op op;
+ switch (c) {
+ case '=': op = new EqualsOp(); break;
+ case '&':
+ if (value.length() > 1)
+ throw new SyntaxException(String.format("Use '&' instead of '%s'", value));
+ op = new AndOp();
+ break;
+ case '|':
+ if (value.length() > 1)
+ throw new SyntaxException(String.format("Use '|' instead of '%s'", value));
+ op = new OrOp();
+ break;
+ case '~': op = new RegexOp(); break;
+ case '(': op = new OpenOp(); break;
+ case ')': op = new CloseOp(); break;
+ case '>':
+ if (value.equals(">="))
+ op = new GTEOp();
+ else
+ op = new GTOp();
+ break;
+ case '<':
+ if (value.equals("<="))
+ op = new LTEOp();
+ else
+ op = new LTOp();
+ break;
+ case '!':
+ if (value.equals("!="))
+ op = new NotEqualOp();
+ else
+ op = new NotOp();
+ break;
+ default:
+ throw new SyntaxException("Unrecognised operation " + c);
+ }
+ return op;
+ }
+
+ /**
+ * Does this operation have a higher priority that the other one?
+ * @param other The other operation.
+ */
+ public boolean hasHigherPriority(Op other) {
+ return priority() > other.priority();
+ }
+
+ public Op getFirst() {
+ return first;
+ }
+
+ public void setFirst(Op first) {
+ this.first = first;
+ }
+
+ /**
+ * Only supported on Binary operations, but useful to return null to make code simpler, rather than
+ * defaulting to UnsupportedOperation.
+ */
+ public Op getSecond() {
+ return null;
+ }
+
+ public NodeType getType() {
+ return type;
+ }
+
+ protected void setType(NodeType type) {
+ this.type = type;
+ }
+
+ /**
+ * Only supported on value nodes.
+ */
+ public String value(Element el) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * This is only supported on value nodes.
+ */
+ public String getKeyValue() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isType(NodeType value) {
+ return type == value;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/AndOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/AndOp.java
new file mode 100644
index 0000000..63b034a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/AndOp.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 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: 03-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * The AND operation. The second term is not executed if the first one
+ * fails.
+ *
+ * @author Steve Ratcliffe
+ */
+public class AndOp extends AbstractBinaryOp {
+
+ public AndOp() {
+ setType(NodeType.AND);
+ }
+
+ public boolean eval(Element el) {
+ return getFirst().eval(el) && getSecond().eval(el);
+ }
+
+ public int priority() {
+ return 5;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/BinaryOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/BinaryOp.java
new file mode 100644
index 0000000..001d7ad
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/BinaryOp.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.osmstyle.eval;
+
+/**
+ * Interface for operations with two operands.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface BinaryOp extends Op {
+
+ /**
+ * Get the second operand.
+ */
+ public Op getSecond();
+
+ /**
+ * Set the second operand.
+ */
+ public void setSecond(Op second);
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/CloseOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/CloseOp.java
new file mode 100644
index 0000000..48cdcf2
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/CloseOp.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2008 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: 08-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import static uk.me.parabola.mkgmap.osmstyle.eval.NodeType.*;
+
+/**
+ * A closing parenthesis. It has a lower priority than anything
+ * apart from its matching opening parenthesis.
+ *
+ * @author Steve Ratcliffe
+ */
+public class CloseOp extends AbstractOp {
+ public CloseOp() {
+ setType(CLOSE_PAREN);
+ }
+
+ public boolean eval(Element el) {
+ return false;
+ }
+
+ public int priority() {
+ return -100;
+ }
+
+ public boolean hasHigherPriority(Op other) {
+ return other.isType(OPEN_PAREN);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/EqualsOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/EqualsOp.java
new file mode 100644
index 0000000..f7c6529
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/EqualsOp.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008-2012 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: 03-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Holds tag=value relationship.
+ *
+ * @author Steve Ratcliffe
+ */
+public class EqualsOp extends AbstractBinaryOp {
+
+ public EqualsOp() {
+ setType(NodeType.EQUALS);
+ }
+
+ public void setFirst(Op first) {
+ super.setFirst(first);
+ }
+
+ public void setSecond(Op second) {
+ super.setSecond(second);
+ }
+
+ public boolean eval(Element el) {
+ String s = first.value(el);
+ if (s == null)
+ return false;
+ return s.equals(getSecond().value(el));
+ }
+
+ public int priority() {
+ return 10;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/ExistsOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/ExistsOp.java
new file mode 100644
index 0000000..57de1dd
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/ExistsOp.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008-2012 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: 06-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Tests for the existence of a tag. Return true if the tag exists, regardless
+ * of value.
+ *
+ * @author Steve Ratcliffe
+ */
+public class ExistsOp extends AbstractOp {
+
+ public ExistsOp() {
+ setType(NodeType.EXISTS);
+ }
+
+ public void setFirst(Op first) {
+ super.setFirst(first);
+ }
+
+ public boolean eval(Element el) {
+ return first.value(el) != null;
+ }
+
+ public int priority() {
+ return 10;
+ }
+
+ public String toString() {
+ return first + "=*";
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/ExpressionReader.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/ExpressionReader.java
new file mode 100644
index 0000000..0c068b5
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/ExpressionReader.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2013
+ *
+ * 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.
+ *
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Stack;
+
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.osmstyle.function.FunctionFactory;
+import uk.me.parabola.mkgmap.osmstyle.function.GetTagFunction;
+import uk.me.parabola.mkgmap.osmstyle.function.StyleFunction;
+import uk.me.parabola.mkgmap.reader.osm.FeatureKind;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+import uk.me.parabola.mkgmap.scan.WordInfo;
+
+import static uk.me.parabola.mkgmap.osmstyle.eval.NodeType.*;
+
+
+/**
+ * Read an expression from a style file.
+ */
+public class ExpressionReader {
+ private static final Logger log = Logger.getLogger(ExpressionReader.class);
+
+ private final Stack<Op> stack = new Stack<Op>();
+ private final Stack<Op> opStack = new Stack<Op>();
+ private final TokenScanner scanner;
+ private final FeatureKind kind;
+
+ private final Set<String> usedTags = new HashSet<String>();
+
+ public ExpressionReader(TokenScanner scanner, FeatureKind kind) {
+ this.scanner = scanner;
+ this.kind = kind;
+ }
+
+ /**
+ * Read the conditions. They are terminated by a '[' or '{' character
+ * or by end of file.
+ */
+ public Op readConditions() {
+ while (!scanner.isEndOfFile()) {
+ scanner.skipSpace();
+ if (scanner.checkToken("[") || scanner.checkToken("{"))
+ break;
+
+ WordInfo wordInfo = scanner.nextWordWithInfo();
+ if (isOperation(wordInfo)) {
+ saveOp(wordInfo.getText());
+ } else if (wordInfo.isQuoted()) {
+ pushValue(wordInfo.getText());
+ } else if (wordInfo.getText().charAt(0) == '$') {
+ String tagname = scanner.nextWord();
+ if (tagname.equals("{")) {
+ tagname = scanner.nextWord();
+ scanner.validateNext("}");
+ }
+ stack.push(new GetTagFunction(tagname));
+ } else if (scanner.checkToken("(")) {
+ // it is a function
+ // this requires a () after the function name
+ scanner.validateNext("(");
+ scanner.validateNext(")");
+ saveFunction(wordInfo.getText());
+ } else {
+ pushValue(wordInfo.getText());
+ }
+ }
+
+ // Complete building the tree
+ while (!opStack.isEmpty())
+ runOp(scanner);
+
+ // The stack should contain one entry which is the complete tree
+ if (stack.size() != 1)
+ throw new SyntaxException(scanner, "Stack size is "+stack.size());
+
+ assert stack.size() == 1;
+ Op op = stack.pop();
+ if (op instanceof ValueOp)
+ throw new SyntaxException(scanner, "Incomplete expression, just a single symbol: " + op);
+ return op;
+ }
+
+ /**
+ * Is this a token representing an operation?
+ * @param token The string to test.
+ * @return True if this looks like an operator.
+ */
+ private boolean isOperation(WordInfo token) {
+ // A quoted word is not an operator eg: '=' is a string.
+ if (token.isQuoted())
+ return false;
+
+ // Quick check, operators are 1 or 2 characters long.
+ String text = token.getText();
+ if (text.length() > 2 || text.isEmpty())
+ return false;
+
+ // If first character is an operation character then it is an operator
+ // (or a syntax error)
+ char first = text.charAt(0);
+ String chars = "&|!=~()><";
+ return chars.indexOf(first) >= 0;
+ }
+
+ /**
+ * Tags used in all the expressions in this file.
+ * @return A set of tag names.
+ */
+ public Set<String> getUsedTags() {
+ return usedTags;
+ }
+
+ /**
+ * An operation is saved on the operation stack. The tree is built
+ * as operations of different priorities arrive.
+ */
+ private void saveOp(String value) {
+ log.debug("save op", value);
+ if (value.equals("#")) {
+ scanner.skipLine();
+ return;
+ }
+
+ Op op;
+ try {
+ op = AbstractOp.createOp(value);
+ while (!opStack.isEmpty() && opStack.peek().hasHigherPriority(op))
+ runOp(scanner);
+ } catch (SyntaxException e) {
+ throw new SyntaxException(scanner, e.getRawMessage());
+ }
+
+ if (op.getType() == CLOSE_PAREN) {
+ // Check that there was an opening parenthesis and remove it
+ if (opStack.isEmpty() || !opStack.peek().isType(OPEN_PAREN))
+ throw new SyntaxException(scanner, "No matching open parenthesis");
+ opStack.pop();
+ } else {
+ opStack.push(op);
+ }
+ }
+
+ /**
+ * Combine the operation at the top of its stack with its values.
+ * @param scanner The token scanner; used for line numbers.
+ */
+ private void runOp(TokenScanner scanner) {
+ Op op = opStack.pop();
+ log.debug("Running op...", op.getType());
+
+ if (op instanceof BinaryOp) {
+ if (stack.size() < 2) {
+ throw new SyntaxException(scanner, String.format("Not enough arguments for '%s' operator",
+ op.getType().toSymbol()));
+ }
+
+ Op arg2 = stack.pop();
+ Op arg1 = stack.pop();
+
+ if (arg1.isType(VALUE) /*&& arg2.isType(VALUE)*/)
+ arg1 = new GetTagFunction(arg1.getKeyValue());
+
+ BinaryOp binaryOp = (BinaryOp) op;
+ binaryOp.setFirst(arg1);
+ binaryOp.setSecond(arg2);
+
+ // Deal with the case where you have: a & b=2. The 'a' is a syntax error in this case.
+ if (op.isType(OR) || op.isType(AND)) {
+ if (arg1.isType(VALUE) || arg1.isType(FUNCTION))
+ throw new SyntaxException(scanner, String.format("Value '%s' is not part of an expression", arg1));
+
+ if (arg2.isType(VALUE) || arg2.isType(FUNCTION))
+ throw new SyntaxException(scanner, String.format("Value '%s' is not part of an expression", arg2));
+ } else {
+ // All binary ops other than OR and AND take two values. A function is a value
+ // type too.
+ if (!(arg1.isType(VALUE) || arg1.isType(FUNCTION))
+ || !(arg2.isType(VALUE) || arg2.isType(FUNCTION)))
+ {
+ String msg = String.format("Invalid arguments to %s: %s (%s) and %s (%s)",
+ op.getType(), arg1.getType(), arg1, arg2.getType(), arg2);
+ throw new SyntaxException(scanner, msg);
+ }
+
+ }
+
+ // The combination foo=* is converted to exists(foo).
+ if (op.isType(EQUALS) && arg2.isType(VALUE) && ((ValueOp) arg2).isValue("*")) {
+ log.debug("convert to EXISTS");
+ op = new ExistsOp();
+ op.setFirst(arg1);
+ } else if (op.isType(NOT_EQUALS) && arg2.isType(VALUE) && ((ValueOp) arg2).isValue("*")) {
+ log.debug("convert to NOT EXISTS");
+ op = new NotExistsOp();
+ op.setFirst(arg1);
+ }
+ } else if (!op.isType(OPEN_PAREN)) {
+ if (stack.size() < 1)
+ throw new SyntaxException(scanner, String.format("Missing argument for %s operator",
+ op.getType().toSymbol()));
+ op.setFirst(stack.pop());
+ }
+
+ Op first = op.getFirst();
+ if (first == null)
+ throw new SyntaxException(scanner, "Invalid expression");
+
+ if (first.isType(FUNCTION))
+ usedTags.add(first.getKeyValue());
+
+ stack.push(op);
+ }
+
+ /**
+ * Lookup a function by its name and check that it is allowed for the kind of features that we
+ * are reading.
+ *
+ * @param functionName A name to look up.
+ */
+ private void saveFunction(String functionName) {
+ StyleFunction function = FunctionFactory.createFunction(functionName);
+ if (function == null)
+ throw new SyntaxException(String.format("No function with name '%s()'", functionName));
+
+ // TODO: supportsWay split into supportsPoly{line,gon}, or one function supports(kind)
+ boolean supported = false;
+ switch (kind) {
+ case POINT:
+ if (function.supportsNode()) supported = true;
+ break;
+ case POLYLINE:
+ if (function.supportsWay()) supported = true;
+ break;
+ case POLYGON:
+ if (function.supportsWay()) supported = true;
+ break;
+ case RELATION:
+ if (function.supportsRelation()) supported = true;
+ break;
+ case ALL:
+ if (function.supportsNode() || function.supportsWay() || function.supportsRelation()) supported = true;
+ break;
+ }
+
+ if (!supported)
+ throw new SyntaxException(String.format("Function '%s()' not supported for %s", functionName, kind));
+
+ stack.push(function);
+ }
+
+ private void pushValue(String value) {
+ stack.push(new ValueOp(value));
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/GTEOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/GTEOp.java
new file mode 100644
index 0000000..5aed169
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/GTEOp.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 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: 09-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+/**
+ * Greater than or equal to. For population, speeds etc.
+ * @author Steve Ratcliffe
+ */
+public class GTEOp extends NumericOp {
+ public GTEOp() {
+ setType(NodeType.GTE);
+ }
+
+ protected boolean doesCompare(int result) {
+ return result >= 0;
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/GTOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/GTOp.java
new file mode 100644
index 0000000..2114d59
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/GTOp.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 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: 09-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+/**
+ * Greater than. For population, speeds etc.
+ * @author Steve Ratcliffe
+ */
+public class GTOp extends NumericOp {
+ public GTOp() {
+ setType(NodeType.GT);
+ }
+
+ protected boolean doesCompare(int result) {
+ return result > 0;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/LTEOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/LTEOp.java
new file mode 100644
index 0000000..d3d925e
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/LTEOp.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 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: 09-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+/**
+ * Less than or equal. For population, speeds etc.
+ * @author Steve Ratcliffe
+ */
+public class LTEOp extends NumericOp {
+ public LTEOp() {
+ setType(NodeType.LTE);
+ }
+
+ protected boolean doesCompare(int result) {
+ return result <= 0;
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/LTOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/LTOp.java
new file mode 100644
index 0000000..f1bc59e
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/LTOp.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 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: 09-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+/**
+ * Less than. For population, speeds etc.
+ * @author Steve Ratcliffe
+ */
+public class LTOp extends NumericOp {
+ public LTOp() {
+ setType(NodeType.LT);
+ }
+
+ protected boolean doesCompare(int result) {
+ return result < 0;
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/LinkedBinaryOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/LinkedBinaryOp.java
new file mode 100644
index 0000000..ba896f4
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/LinkedBinaryOp.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.osmstyle.eval;
+
+/**
+ * The binary version of {@link LinkedOp}, see that class for
+ * a description.
+ *
+ * @author Steve Ratcliffe
+ */
+public class LinkedBinaryOp extends LinkedOp implements BinaryOp {
+
+ public LinkedBinaryOp(BinaryOp other, boolean first) {
+ super(other, first);
+ }
+
+ public Op getSecond() {
+ return ((BinaryOp) wrapped).getSecond();
+ }
+
+ public void setSecond(Op second) {
+ ((BinaryOp) wrapped).setSecond(second);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/LinkedOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/LinkedOp.java
new file mode 100644
index 0000000..b52752a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/LinkedOp.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.osmstyle.eval;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * This is used to implement OR expressions as if each term was a separate
+ * indexable expression.
+ *
+ * <p>So if you have:
+ * <pre>
+ * A=1 | B=1 | C=1 {set name='${name} ${A}' | '${B}'; }
+ * </pre>
+ * This is represented by:
+ * <pre>
+ * A=1 {set name='${name} ${A}' | '${B}'; }
+ * B=1 {set name='${name} ${A}' | '${B}'; }
+ * C=1 {set name='${name} ${A}' | '${B}'; }
+ * </pre>
+ * So that each term can be index separately. However we need to be able to
+ * prevent the second and/or third terms running if the first (or second) matches.
+ * That is what this class does. It acts in most respects like the operation
+ * it is wrapping, but when a successful evaluation is performed on an
+ * element, the test is suppressed for the subsequent terms in the chain.
+ *
+ * @author Steve Ratcliffe
+ */
+public class LinkedOp implements Op {
+ protected final Op wrapped;
+ private final boolean first;
+ private LinkedOp link;
+ private Element current;
+
+ protected LinkedOp(Op wrapped, boolean first) {
+ this.wrapped = wrapped;
+ this.first = first;
+ }
+
+ public boolean eval(Element el) {
+ if (el == current)
+ return false;
+
+ boolean b = wrapped.eval(el);
+ if (link != null && b)
+ link.setMatched(el);
+ return b;
+ }
+
+ public String toString() {
+ if (first) {
+ StringBuilder sb = new StringBuilder();
+ sb.append('(');
+ sb.append(wrapped);
+ LinkedOp l = link;
+ while (l != null) {
+ sb.append(" | ");
+ sb.append(l.wrapped);
+ l = l.link;
+ }
+ sb.append(')');
+ return sb.toString();
+ } else {
+ return "# Part of the previous OR expression.";
+ }
+ }
+
+ public int priority() {
+ return wrapped.priority();
+ }
+
+ public boolean hasHigherPriority(Op other) {
+ return this.wrapped.hasHigherPriority(other);
+ }
+
+ public Op getFirst() {
+ return wrapped.getFirst();
+ }
+
+ public void setFirst(Op first) {
+ wrapped.setFirst(first);
+ }
+
+ public Op getSecond() {
+ return null;
+ }
+
+ public NodeType getType() {
+ return wrapped.getType();
+ }
+
+ public String value(Element el) {
+ return wrapped.value(el);
+ }
+
+ public String getKeyValue() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isType(NodeType value) {
+ return wrapped.isType(value);
+ }
+
+ /**
+ * Set the fact that the given element has been matched already. If we
+ * are called to evaluate and find that the element we are given
+ * has already been matched by an earlier term in the OR then we just
+ * return without doing anything.
+ * @param el The element to mark as being matched.
+ */
+ private void setMatched(Element el) {
+ this.current = el;
+ if (link != null)
+ link.setMatched(el);
+ }
+
+ public void setLink(LinkedOp link) {
+ if (this.link == null)
+ this.link = link;
+ else
+ this.link.setLink(link);
+ }
+
+ /**
+ * Create either a LinkedOp or a LinkedBinaryOp as appropriate
+ * for the type of operation that is passed in.
+ */
+ public static LinkedOp create(Op op, boolean first) {
+ if (op instanceof BinaryOp) {
+ return new LinkedBinaryOp((BinaryOp) op, first);
+ } else {
+ return new LinkedOp(op, first);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/NodeType.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/NodeType.java
new file mode 100644
index 0000000..1282d22
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/NodeType.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.osmstyle.eval;
+
+/**
+ * The different node types that an {@link Op} can have.
+ *
+ * @author Steve Ratcliffe
+ */
+public enum NodeType {
+ EQUALS("="),
+ GT(">"),
+ GTE(">="),
+ LT("<"),
+ LTE("<="),
+ NOT_EQUALS("!="),
+ EXISTS("=*"),
+ NOT_EXISTS("!=*"),
+ AND("&"),
+ OR("|"),
+ VALUE(null),
+ FUNCTION(null),
+ OPEN_PAREN("("),
+ CLOSE_PAREN(")"),
+ NOT("!"),
+ REGEX("~");
+
+ private final String symbol;
+
+ private NodeType(String symbol) {
+ this.symbol = symbol;
+ }
+
+ public String toSymbol() {
+ return symbol;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/NotEqualOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/NotEqualOp.java
new file mode 100644
index 0000000..42b30a3
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/NotEqualOp.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008 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: 08-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * True when the tag does not have the given value.
+ *
+ * @author Steve Ratcliffe
+ */
+public class NotEqualOp extends EqualsOp {
+ public NotEqualOp() {
+ setType(NodeType.NOT_EQUALS);
+ }
+
+ public boolean eval(Element el) {
+ return !super.eval(el);
+ }
+
+ public String toString() {
+ return getFirst().toString() + "!=" + getSecond();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/NotExistsOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/NotExistsOp.java
new file mode 100644
index 0000000..30d8f10
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/NotExistsOp.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008-2012 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: 08-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * True of the tag does not exist.
+ * @author Steve Ratcliffe
+ */
+public class NotExistsOp extends AbstractOp {
+ public NotExistsOp() {
+ setType(NodeType.NOT_EXISTS);
+ }
+
+ public boolean eval(Element el) {
+ return first.value(el) == null;
+ }
+
+ public int priority() {
+ return 10;
+ }
+
+ public String toString() {
+ return getFirst().toString() + "!=*";
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/NotOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/NotOp.java
new file mode 100644
index 0000000..7b51aa4
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/NotOp.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008 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: 08-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Reverses the sense of the operation it is applied to.
+ * @author Steve Ratcliffe
+ */
+public class NotOp extends AbstractOp {
+
+ public NotOp() {
+ setType(NodeType.NOT);
+ }
+
+ public boolean eval(Element el) {
+ return !first.eval(el);
+ }
+
+ public int priority() {
+ return 50;
+ }
+
+ public String toString() {
+ return "!" + first;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/NumericOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/NumericOp.java
new file mode 100644
index 0000000..da895c9
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/NumericOp.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008-2012 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: 10-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Class for numeric operations.
+ *
+ * This may include Equals at some point so that you can do max_speed=20mph
+ * even when the tag doesn't include mph etc.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class NumericOp extends AbstractBinaryOp {
+
+ /**
+ * This is passed the result of a compareTo and the subclass
+ * returns true or false depending on the operation.
+ */
+ protected abstract boolean doesCompare(int result);
+
+ public int priority() {
+ return 10;
+ }
+
+ /**
+ * This evaluation routine works for all numeric tests. Implement the
+ * {@link #doesCompare} routine instead of this.
+ */
+ public final boolean eval(Element el) {
+ // get the value of the tag, if it doesn't exist then false.
+ String val = first.value(el);
+ if (val == null)
+ return false;
+
+ ValueWithUnit result = new ValueWithUnit(val);
+ String val2 = getSecond().value(el);
+ if (val2 == null)
+ return false;
+ ValueWithUnit ourVal = new ValueWithUnit(val2);
+
+ if (!result.isValid() || !ourVal.isValid())
+ return false;
+ int inter = result.compareTo(ourVal);
+ return doesCompare(inter);
+ }
+
+ public String toString() {
+ return "(" + first + getType().toSymbol() + getSecond() + ')';
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/Op.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/Op.java
new file mode 100644
index 0000000..c7be904
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/Op.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.osmstyle.eval;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Interface for an node in the style expression language.
+ * Operations need have only one operand, use {@link BinaryOp} for
+ * when they definitely have two.
+ *
+ * In spite of the name this covers both values and operations.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface Op {
+
+ /**
+ * Evaluate the expression.
+ * @param el The OSM element to be tested.
+ * @return True if the expression is true for the given element.
+ */
+ public boolean eval(Element el);
+
+ /**
+ * Does this operation have a higher priority that the other one?
+ * @param other The other operation.
+ */
+ public boolean hasHigherPriority(Op other);
+
+ /**
+ * Get the first operand.
+ */
+ public Op getFirst();
+
+ /**
+ * Set the first operand.
+ */
+ public void setFirst(Op first);
+
+ /**
+ * Return the second operand for a binary operation. If this is not a binary operation,
+ * then null is returned.
+ * @return The right hand side, or null if there is not one.
+ */
+ public Op getSecond();
+
+ /** Get the operation type */
+ public NodeType getType();
+
+ /**
+ * For operations that are value types this is the string value.
+ *
+ * Only applies to nodes of type VALUE and FUNCTION, returns null for all
+ * other kinds of node.
+ *
+ * @return The value, or UnsupportedOperationException if it does not have a value.
+ */
+ public String value(Element el);
+
+ /**
+ * For a value-type node, this is a key value associated with value. For a base Value node
+ * this is the same as value(), but if value() is overridden then it may not be.
+ */
+ public String getKeyValue();
+
+ /**
+ * Test the node type and return true if it matches the given argument.
+ */
+ public boolean isType(NodeType value);
+
+ /**
+ * For an operation this is a number that determines the precedence of this operation.
+ * Used when building the node tree. Higher numbers bind more tightly.
+ */
+ public int priority();
+
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/OpenOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/OpenOp.java
new file mode 100644
index 0000000..1b359b3
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/OpenOp.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 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: 08-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+
+/**
+ * An open parenthesis. This is treated specially.
+ * @author Steve Ratcliffe
+ */
+public class OpenOp extends AbstractOp {
+
+ public OpenOp() {
+ setType(NodeType.OPEN_PAREN);
+ }
+
+ public boolean eval(Element el) {
+ throw new SyntaxException("Programming error, trying to eval an open parenthesis");
+ }
+
+ /**
+ * This is used when placing this on the top of the stack, for that
+ * purpose it has a very high priority and will not cause anything
+ * below to execute.
+ */
+ public int priority() {
+ return 100;
+ }
+
+ /**
+ * This is called when it is on the top of the stack. In this case all
+ * other operations have a higher priority.
+ * @param other The other operation.
+ * @return Always returns false.
+ */
+ public boolean hasHigherPriority(Op other) {
+ return false;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/OrOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/OrOp.java
new file mode 100644
index 0000000..1d66d45
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/OrOp.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2008 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: 06-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * An OR operation. The second is only run if the first fails.
+ *
+ * @author Steve Ratcliffe
+ */
+public class OrOp extends AbstractBinaryOp {
+
+ public OrOp() {
+ setType(NodeType.OR);
+ }
+
+ public boolean eval(Element el) {
+ return getFirst().eval(el) || getSecond().eval(el);
+ }
+
+ public int priority() {
+ return 3;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/RegexOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/RegexOp.java
new file mode 100644
index 0000000..bd5c312
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/RegexOp.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008-2012 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: 11-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import java.util.regex.Pattern;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+import static uk.me.parabola.mkgmap.osmstyle.eval.NodeType.*;
+
+/**
+ * Regular expression matching.
+ * @author Steve Ratcliffe
+ */
+public class RegexOp extends AbstractBinaryOp {
+ private Pattern pattern;
+
+ public RegexOp() {
+ setType(REGEX);
+ }
+
+ public boolean eval(Element el) {
+ String tagval = first.value(el);
+ if (tagval == null)
+ return false;
+
+ return pattern.matcher(tagval).matches();
+ }
+
+ public int priority() {
+ return 10;
+ }
+
+ public void setSecond(Op second) {
+ assert second.isType(VALUE);
+ super.setSecond(second);
+ pattern = Pattern.compile(second.getKeyValue());
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/UnitConversions.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/UnitConversions.java
new file mode 100644
index 0000000..51737d4
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/UnitConversions.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008 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: 07-Dec-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Converting quantities from one unit to another.
+ *
+ * TODO: this will probably change a lot.
+ *
+ * @author Steve Ratcliffe
+ */
+public class UnitConversions {
+ private static final Map<String, Double> conversions = new HashMap<String, Double>();
+
+ // Initially we are just supporting the existing case for contour
+ // lines where we convert to feet.
+ static {
+ Map<String, Double> m = conversions;
+ m.put("m=>ft", 3.2808399);
+ }
+ //
+ //private double factor;
+ //
+ //public double convert(double in) {
+ // return in * factor;
+ //}
+
+ /**
+ * Get the conversion factor for the given conversion.
+ * @param code A string such as 'm=>ft' which would mean meters
+ * to feet.
+ * @return The factor required to convert the first to the second.
+ */
+ public static double convertFactor(String code) {
+ Double f = conversions.get(code);
+ return (f == null)?1 :f;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/ValueOp.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/ValueOp.java
new file mode 100644
index 0000000..cdef5ae
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/ValueOp.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2008 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: 03-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Holds a string value; the name of a tag or the value of a tag for example.
+ *
+ * @author Steve Ratcliffe
+ */
+public class ValueOp extends AbstractOp {
+ private final String value;
+
+ public ValueOp(String value) {
+ setType(NodeType.VALUE);
+ this.value = value;
+ }
+
+ public boolean eval(Element el) {
+ return true;
+ }
+
+ public int priority() {
+ return 0;
+ }
+
+ public String value(Element el) {
+ return value;
+ }
+
+ /**
+ * Get the saved value.
+ * For a base ValueOp this returns the same as {@link #value} but in classes where value is
+ * overridden it returns the base value.
+ */
+ public final String getKeyValue() {
+ return value;
+ }
+
+ public boolean isValue(String val) {
+ return value.equals(val);
+ }
+
+ /**
+ * Returns true if you can index the rule from this value.
+ * This should almost always return false, override in subclasses that are indexable.
+ */
+ public boolean isIndexable() {
+ return false;
+ }
+
+ public String toString() {
+ return value;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/ValueWithUnit.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/ValueWithUnit.java
new file mode 100644
index 0000000..13b90cc
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/ValueWithUnit.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2008 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: 09-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.eval;
+
+import java.math.BigDecimal;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+/**
+ * Represents a number and the units it is in. We want ultimately to be
+ * able to do things like: is 10km/h > 8mph, and get the right answer
+ * by converting to a common unit.
+ *
+ * To start with we will just compare the numbers.
+ *
+ * @author Steve Ratcliffe
+ */
+public class ValueWithUnit implements Comparable<ValueWithUnit> {
+ private static final Pattern EXTRACT_NUMBER_UNIT
+ = Pattern.compile("[ \t]*(-?[0-9.]+)[ \t]*(.*)");
+ private static final BigDecimal ZERO = new BigDecimal(0);
+
+ private final BigDecimal value;
+ private final String unit;
+
+ private final boolean valid;
+
+ public ValueWithUnit(String val) {
+ Matcher m = EXTRACT_NUMBER_UNIT.matcher(val);
+ boolean found = m.find();
+
+ BigDecimal value = ZERO;
+ String unit = "";
+ boolean ok = false;
+
+ if (found) {
+ try {
+ value = new BigDecimal(m.group(1));
+ unit = m.group(2).trim();
+ ok = true;
+ } catch (NumberFormatException e) {
+ ok = false;
+ }
+ }
+
+ this.value = value;
+ this.unit = unit;
+ this.valid = ok;
+ }
+
+ /**
+ * Compares this object with the specified object for order. Returns
+ * a negative integer, zero, or a positive integer as this object
+ * is less than, equal to, or greater than the specified object.
+ *
+ * To start with, just compare the value and ignore the unit.
+ */
+ public int compareTo(ValueWithUnit o) {
+ return value.compareTo(o.value);
+ }
+
+ public boolean isValid() {
+ return valid;
+ }
+
+ public String toString() {
+ return value + unit;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/function/AreaSizeFunction.java b/src/uk/me/parabola/mkgmap/osmstyle/function/AreaSizeFunction.java
new file mode 100644
index 0000000..6964eda
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/function/AreaSizeFunction.java
@@ -0,0 +1,43 @@
+package uk.me.parabola.mkgmap.osmstyle.function;
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.MultiPolygonRelation;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+
+/**
+ * Calculates the area size of a polygon in garmin units ^ 2.
+ * @author WanMil
+ */
+public class AreaSizeFunction extends CachedFunction {
+
+ private final DecimalFormat nf = new DecimalFormat("0.0#####################", DecimalFormatSymbols.getInstance(Locale.US));
+
+ public AreaSizeFunction() {
+ super(null);
+ }
+
+ protected String calcImpl(Element el) {
+ if (el instanceof Way) {
+ Way w = (Way)el;
+ // a non closed way has size 0
+ if (w.isClosed() == false) {
+ return "0";
+ }
+ return nf.format(MultiPolygonRelation.calcAreaSize(((Way) el).getPoints()));
+ }
+ return null;
+ }
+
+ public String getName() {
+ return "area_size";
+ }
+
+ public boolean supportsWay() {
+ return true;
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/function/CachedFunction.java b/src/uk/me/parabola/mkgmap/osmstyle/function/CachedFunction.java
new file mode 100644
index 0000000..2f730da
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/function/CachedFunction.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.osmstyle.function;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.Node;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+
+/**
+ * Abstract implementation of a style function that is able
+ * to cache the function values.
+ * @author WanMil
+ */
+public abstract class CachedFunction extends StyleFunction {
+
+ public CachedFunction(String value) {
+ super(value);
+ }
+
+ public final String value(Element el) {
+ // check if the element type is supported by this function
+ if (el instanceof Node ) {
+ if (supportsNode() == false) {
+ return null;
+ }
+ } else if (el instanceof Way) {
+ if (supportsWay() == false) {
+ return null;
+ }
+ } else if (el instanceof Relation) {
+ if (supportsRelation() == false) {
+ return null;
+ }
+ }
+
+ if (isCached()) {
+ // if caching is supported check if the value has already
+ // been calculated
+ String cachedValue = el.getTag(getCacheTag());
+ if (cachedValue != null) {
+ return cachedValue;
+ }
+ }
+
+ // calculate the function value
+ String functionResult = calcImpl(el);
+
+ if (functionResult != null && isCached()) {
+ // if caching is supported save the value for later usage
+ el.addTag(getCacheTag(), functionResult);
+ }
+
+ return functionResult;
+ }
+
+ /**
+ * This method contains the real calculation of the function value and must be
+ * implemented by subclasses.
+ * @param el the function parameter
+ * @return the function value
+ */
+ protected abstract String calcImpl(Element el);
+
+ /**
+ * Retrieves the tag name that is used to cache the function value to
+ * avoid multiple calculations for the same element.
+ * @return tag name used for caching
+ */
+ protected String getCacheTag() {
+ return "mkgmap:cache_"+getName();
+ }
+
+ public boolean isCached() {
+ return true;
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/function/FunctionFactory.java b/src/uk/me/parabola/mkgmap/osmstyle/function/FunctionFactory.java
new file mode 100644
index 0000000..828b0a0
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/function/FunctionFactory.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.osmstyle.function;
+
+import uk.me.parabola.mkgmap.osmstyle.function.MaxSpeedFunction.SpeedUnit;
+
+/**
+ * A factory for style functions.
+ * @author WanMil
+ */
+public class FunctionFactory {
+
+ /**
+ * Returns a new instance of a style function with the given name.
+ *
+ * @param name the style function name
+ * @return the style function instance or {@code null} if there is no such function
+ */
+ public static StyleFunction createFunction(String name) {
+ if ("length".equals(name))
+ return new LengthFunction();
+ //} else if ("get_tag".equals(name))
+ // return new GetTagFunction(tag);
+ if ("is_closed".equals(name)) {
+ return new IsClosedFunction();
+ }
+ if ("is_complete".equals(name)) {
+ return new IsCompleteFunction();
+ }
+ if ("area_size".equals(name))
+ return new AreaSizeFunction();
+ if ("maxspeedkmh".equals(name))
+ return new MaxSpeedFunction(SpeedUnit.KMH);
+ if ("maxspeedmph".equals(name))
+ return new MaxSpeedFunction(SpeedUnit.MPH);
+ if ("type".equals(name))
+ return new TypeFunction();
+ if ("osmid".equals(name))
+ return new OsmIdFunction();
+
+ return null;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/function/GetTagFunction.java b/src/uk/me/parabola/mkgmap/osmstyle/function/GetTagFunction.java
new file mode 100644
index 0000000..0d6cbb1
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/function/GetTagFunction.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.osmstyle.function;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Get the value of a tag from the element.
+ *
+ * In the style language: highway = primary
+ * This is effectively a shorthand for: get_tag(highway) = primary
+ *
+ * @author Steve Ratcliffe
+ */
+public class GetTagFunction extends StyleFunction {
+
+ public GetTagFunction(String value) {
+ super(value);
+ }
+
+ public String value(Element el) {
+ return el.getTag(getKeyValue());
+ }
+
+ /**
+ * Since this contains a tag value it can potentially be used to index the whole rule,
+ * so return true here.
+ */
+ public boolean isIndexable() {
+ return true;
+ }
+
+ public String toString() {
+ return "$" + getKeyValue();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/function/IsClosedFunction.java b/src/uk/me/parabola/mkgmap/osmstyle/function/IsClosedFunction.java
new file mode 100644
index 0000000..2d76b72
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/function/IsClosedFunction.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.osmstyle.function;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.
+ */
+
+import uk.me.parabola.mkgmap.reader.osm.Way;
+
+/**
+ * Checks if a way is closed.
+ * @author WanMil
+ */
+public class IsClosedFunction extends StyleFunction {
+
+ public IsClosedFunction() {
+ super(null);
+ }
+
+ public boolean supportsWay() {
+ return true;
+ }
+
+ public String value(Element el) {
+ if (el instanceof Way) {
+ return String.valueOf(((Way)el).isClosed());
+ }
+ return null;
+ }
+
+ public String getName() {
+ return "is_closed";
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/function/IsCompleteFunction.java b/src/uk/me/parabola/mkgmap/osmstyle/function/IsCompleteFunction.java
new file mode 100644
index 0000000..8de4508
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/function/IsCompleteFunction.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.osmstyle.function;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+
+/**
+ * Checks if a way has been loaded completely or if some points are missing.
+ * @author WanMil
+ */
+public class IsCompleteFunction extends StyleFunction {
+
+ public IsCompleteFunction() {
+ super(null);
+ }
+
+ public boolean supportsWay() {
+ return true;
+ }
+
+ public String value(Element el) {
+ if (el instanceof Way) {
+ return String.valueOf(((Way) el).isComplete());
+ }
+ return null;
+ }
+
+ public String getName() {
+ return "is_complete";
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/function/LengthFunction.java b/src/uk/me/parabola/mkgmap/osmstyle/function/LengthFunction.java
new file mode 100644
index 0000000..d28098e
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/function/LengthFunction.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.osmstyle.function;
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
+import java.util.Map.Entry;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+
+/**
+ * Calculates the length of a way or a relation in meter. The length of a
+ * relation is defined as the sum of its member lengths.
+ *
+ * @author WanMil
+ */
+public class LengthFunction extends CachedFunction {
+ private static final Logger log = Logger.getLogger(LengthFunction.class);
+
+ private final DecimalFormat nf = new DecimalFormat("0.0#####################", DecimalFormatSymbols.getInstance(Locale.US));
+
+ public LengthFunction() {
+ super(null);
+ }
+
+ protected String calcImpl(Element el) {
+ double length = calcLength(el);
+ return nf.format(length);
+ }
+
+ private double calcLength(Element el) {
+ if (el instanceof Way) {
+ Way w = (Way)el;
+ double length = 0;
+ Coord prevC = null;
+ for (Coord c : w.getPoints()) {
+ if (prevC != null) {
+ length += prevC.distance(c);
+ }
+ prevC = c;
+ }
+ return length;
+ } else if (el instanceof Relation) {
+ Relation rel = (Relation)el;
+ double length = 0;
+ for (Entry<String,Element> relElem : rel.getElements()) {
+ if (relElem.getValue() instanceof Way || relElem.getValue() instanceof Relation) {
+ if (rel == relElem.getValue()) {
+ // avoid recursive call
+ log.error("Relation "+rel.getId()+" contains itself as element. This is not supported.");
+ } else {
+ length += calcLength(relElem.getValue());
+ }
+ }
+ }
+ return length;
+ } else {
+ throw new SyntaxException("length() cannot calculate elements of type "+el.getClass().getName());
+ }
+ }
+
+ public String getName() {
+ return "length";
+ }
+
+ public boolean supportsWay() {
+ return true;
+ }
+
+ public boolean supportsRelation() {
+ return true;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/function/MaxSpeedFunction.java b/src/uk/me/parabola/mkgmap/osmstyle/function/MaxSpeedFunction.java
new file mode 100644
index 0000000..004fa11
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/function/MaxSpeedFunction.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2013.
+ *
+ * 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.osmstyle.function;
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
+import java.util.regex.Pattern;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Returns the maxspeed converted either to km/h or mph.
+ *
+ * @author WanMil
+ */
+public class MaxSpeedFunction extends CachedFunction {
+
+ public enum SpeedUnit {
+ KMH, MPH;
+
+ public double convert(double value, SpeedUnit valueUnit) {
+ if (this == valueUnit) {
+ // same unit => no conversion necessary
+ return value;
+ } else if (valueUnit == MPH) {
+ // not the same unit - value is mph => target is km/h => factor
+ // 1.61
+ return value * 1.61;
+ } else {
+ // not the same unit - value is kmh => target is mph => factor
+ // 1/1.61
+ return value / 1.61;
+ }
+ }
+ }
+
+ private static final Pattern ENDS_IN_MPH_PATTERN = Pattern.compile(".*mph");
+ private static final Pattern REMOVE_MPH_PATTERN = Pattern
+ .compile("[ \t]*mph");
+ private static final Pattern REMOVE_KMH_PATTERN = Pattern
+ .compile("[ \t]*km/?h");
+
+ private final DecimalFormat nf = new DecimalFormat("0.0#",
+ DecimalFormatSymbols.getInstance(Locale.US));
+
+ private final SpeedUnit unit;
+
+ public MaxSpeedFunction(SpeedUnit unit) {
+ // requires maxspeed
+ super("maxspeed");
+
+ this.unit = unit;
+ }
+
+ protected String calcImpl(Element el) {
+ // get the maxspeed value
+ String tagValue = el.getTag("maxspeed");
+ if (tagValue == null) {
+ // there is no maxspeed => function has no value
+ return null;
+ }
+
+ String speedTag = tagValue.toLowerCase().trim();
+
+ // take KMH as default
+ SpeedUnit speedTagUnit = SpeedUnit.KMH;
+ if (ENDS_IN_MPH_PATTERN.matcher(speedTag).matches()) {
+ // Check if it is a limit in mph
+ speedTag = REMOVE_MPH_PATTERN.matcher(speedTag).replaceFirst("");
+ speedTagUnit = SpeedUnit.MPH;
+ } else
+ // get rid of kmh just in case
+ speedTag = REMOVE_KMH_PATTERN.matcher(speedTag).replaceFirst("");
+
+ try {
+ // convert to the target unit
+ double speed = this.unit.convert(Integer.parseInt(speedTag), speedTagUnit);
+ // format with two decimals
+ return nf.format(speed);
+ } catch (Exception e) {
+ // parse error => maxspeed cannot be calculated
+ return null;
+ }
+
+ }
+
+ public String getName() {
+ switch (this.unit) {
+ case MPH:
+ return "maxspeedmph";
+ case KMH:
+ default:
+ return "maxspeedkmh";
+ }
+ }
+
+ public boolean supportsWay() {
+ return true;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/function/OsmIdFunction.java b/src/uk/me/parabola/mkgmap/osmstyle/function/OsmIdFunction.java
new file mode 100644
index 0000000..c692040
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/function/OsmIdFunction.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013.
+ *
+ * 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.osmstyle.function;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Function that returns the id of the OSM element.
+ * @author WanMil
+ */
+public class OsmIdFunction extends StyleFunction {
+
+ public OsmIdFunction() {
+ super(null);
+ }
+
+ public boolean supportsNode() {
+ return true;
+ }
+
+ public boolean supportsWay() {
+ return true;
+ }
+
+ public boolean supportsRelation() {
+ return true;
+ }
+
+ public String value(Element el) {
+ // return the osm id
+ return String.valueOf(el.getId());
+ }
+
+ public String getName() {
+ return "osmid";
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/function/StyleFunction.java b/src/uk/me/parabola/mkgmap/osmstyle/function/StyleFunction.java
new file mode 100644
index 0000000..b497394
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/function/StyleFunction.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.osmstyle.function;
+
+import uk.me.parabola.mkgmap.osmstyle.eval.ValueOp;
+import uk.me.parabola.mkgmap.reader.osm.Node;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+
+import static uk.me.parabola.mkgmap.osmstyle.eval.NodeType.FUNCTION;
+
+/**
+ * The interface for all functions that can be used within a style file.<br>
+ * The input parameter of a function is one element. The resulting value is a
+ * string which can carry number values.
+ * @author WanMil
+ */
+public abstract class StyleFunction extends ValueOp {
+
+ public StyleFunction(String value) {
+ super(value);
+ setType(FUNCTION);
+ }
+
+ /**
+ * Retrieves if the function accepts {@link Node} objects as input parameter.
+ *
+ * @return {@code true} {@link Node} objects are supported; {@code false} .. are not supported
+ */
+ public boolean supportsNode() {
+ return false;
+ }
+
+ /**
+ * Retrieves if the function accepts {@link Way} objects as input parameter.
+ *
+ * @return {@code true} {@link Way} objects are supported; {@code false} .. are not supported
+ */
+ public boolean supportsWay() {
+ return false;
+ }
+
+ /**
+ * Retrieves if the function accepts {@link Relation} objects as input parameter.
+ *
+ * @return {@code true} {@link Relation} objects are supported; {@code false} .. are not supported
+ */
+ public boolean supportsRelation() {
+ return false;
+ }
+
+ /**
+ * Retrieves the function name. This is the part without function brackets (). It is case sensitive but should be lower
+ * case.
+ *
+ * @return the function name (e.g. length for length())
+ */
+ public String getName() {
+ return getKeyValue();
+ }
+
+ public String toString() {
+ return getName() + "()";
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/function/TypeFunction.java b/src/uk/me/parabola/mkgmap/osmstyle/function/TypeFunction.java
new file mode 100644
index 0000000..b04fa4e
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/function/TypeFunction.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2013.
+ *
+ * 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.osmstyle.function;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.Node;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+
+/**
+ * Retrieves the OSM type of an element. Values:
+ * <ul>
+ * <li>node</li>
+ * <li>way</li>
+ * <li>relation</li>
+ * </ul>
+ * @author WanMil
+ *
+ */
+public class TypeFunction extends StyleFunction {
+
+ public TypeFunction() {
+ super(null);
+ }
+
+ public boolean supportsNode() {
+ return true;
+ }
+
+ public boolean supportsWay() {
+ return true;
+ }
+
+ public boolean supportsRelation() {
+ return true;
+ }
+
+ public String value(Element el) {
+ if (el instanceof Node)
+ return "node";
+ if (el instanceof Way)
+ return "way";
+ if (el instanceof Relation)
+ return "relation";
+ return null;
+ }
+
+ public String getName() {
+ return "type";
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/housenumber/HousenumberGenerator.java b/src/uk/me/parabola/mkgmap/osmstyle/housenumber/HousenumberGenerator.java
new file mode 100644
index 0000000..148438d
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/housenumber/HousenumberGenerator.java
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2013.
+ *
+ * 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.osmstyle.housenumber;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.regex.Pattern;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.CoordNode;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.net.NumberStyle;
+import uk.me.parabola.imgfmt.app.net.Numbers;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.LineAdder;
+import uk.me.parabola.mkgmap.general.MapRoad;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.Node;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.MultiHashMap;
+
+/**
+ * Collects all data required for OSM house number handling and adds the
+ * house number information to the roads.
+ *
+ * @author WanMil
+ */
+public class HousenumberGenerator {
+
+ private static final Logger log = Logger
+ .getLogger(HousenumberGenerator.class);
+
+ /** Gives the maximum distance between house number element and the matching road */
+ private static final double MAX_DISTANCE_TO_ROAD = 150d;
+
+ private boolean numbersEnabled;
+
+ private MultiHashMap<String, MapRoad> roadByNames;
+ private List<MapRoad> roads;
+ private MultiHashMap<String, Element> houseNumbers;
+
+ public HousenumberGenerator(Properties props) {
+ this.roadByNames = new MultiHashMap<String,MapRoad>();
+ this.houseNumbers = new MultiHashMap<String,Element>();
+ this.roads = new ArrayList<MapRoad>();
+
+ numbersEnabled=props.containsKey("housenumbers");
+ }
+
+ /**
+ * Retrieves the street name of this element.
+ * @param e an OSM element
+ * @return the street name (or {@code null} if no street name set)
+ */
+ private String getStreetname(Element e) {
+ String streetname = stripStreetName(e.getTag("mkgmap:street"));
+ if (streetname == null) {
+ streetname = stripStreetName(e.getTag("addr:street"));
+ }
+ return streetname;
+ }
+
+ /**
+ * Adds a node for house number processing.
+ * @param n an OSM node
+ */
+ public void addNode(Node n) {
+ if (numbersEnabled == false) {
+ return;
+ }
+ if (HousenumberMatch.getHousenumber(n) != null) {
+ String streetname = getStreetname(n);
+ if (streetname != null) {
+ houseNumbers.add(streetname, n);
+ }
+ }
+ }
+
+ /**
+ * Adds a way for house number processing.
+ * @param w a way
+ */
+ public void addWay(Way w) {
+ if (numbersEnabled == false) {
+ return;
+ }
+ if (HousenumberMatch.getHousenumber(w) != null) {
+ String streetname = getStreetname(w);
+ if (streetname != null) {
+ houseNumbers.add(streetname, w);
+ }
+ }
+ }
+
+ private static final Pattern BRACKETS = Pattern.compile("\\(.*\\)");
+
+ /**
+ * Removes the shield from the given string. This is the shield character
+ * including the following part until the first whitespace. Additionally all
+ * text within brackets is removed.
+ * @param s a label
+ * @return the label without shield ({@code null} if stripped label is empty)
+ */
+ public static String stripStreetName(String s) {
+ if (s == null || s.isEmpty())
+ return null;
+
+ if (Label.SHIELDS.matcher(s.substring(0, 1)).matches()) {
+ int whitespaceIndex = s.indexOf(' ', 1);
+ if (whitespaceIndex < 0) {
+ return null;
+ } else {
+ s = s.substring(whitespaceIndex);
+ }
+ }
+ s = BRACKETS.matcher(s).replaceAll(""); // remove text in brackets
+ s = Label.squashSpaces(s);
+ if (s == null) {
+ return null;
+ }
+ s = s.trim();
+ if (s.isEmpty()) {
+ return null;
+ }
+ return s;
+
+ }
+
+
+ /**
+ * Adds a road to be processed by the house number generator.
+ * @param osmRoad the OSM way the defines the road
+ * @param road a road
+ */
+ public void addRoad(Way osmRoad, MapRoad road) {
+ roads.add(road);
+ if (numbersEnabled) {
+ // first try to get the streetname from mkgmap:streetname
+ String name = getStreetname(osmRoad);
+ if (name != null) {
+ if (log.isDebugEnabled())
+ log.debug("Housenumber - Streetname:", name, "Way:",osmRoad.getId(),osmRoad.toTagString());
+ roadByNames.add(name, road);
+ }
+ }
+ }
+
+ public void addRelation(Relation r) {
+ // TODO
+ }
+
+ public void generate(LineAdder adder) {
+ if (numbersEnabled) {
+ for (Entry<String, List<Element>> numbers : houseNumbers.entrySet()) {
+ List<MapRoad> possibleRoads = roadByNames.get(numbers.getKey());
+
+ if (possibleRoads.isEmpty()) {
+ continue;
+ }
+
+ match(numbers.getKey(), numbers.getValue(), possibleRoads);
+ }
+ }
+
+ for (MapRoad r : roads) {
+ adder.add(r);
+ }
+
+ houseNumbers.clear();
+ roadByNames.clear();
+ roads.clear();
+ }
+
+ /**
+ * Sorts house numbers by roads, road segments and position of the house number.
+ * @author WanMil
+ */
+ private static class HousenumberMatchComparator implements Comparator<HousenumberMatch> {
+
+ public int compare(HousenumberMatch o1, HousenumberMatch o2) {
+ if (o1 == o2) {
+ return 0;
+ }
+
+ if (o1.getRoad() != o2.getRoad()) {
+ return o1.getRoad().hashCode() - o2.getRoad().hashCode();
+ }
+
+ int dSegment = o1.getSegment() - o2.getSegment();
+ if (dSegment != 0) {
+ return dSegment;
+ }
+
+ double dFrac = o1.getSegmentFrac() - o2.getSegmentFrac();
+ if (dFrac != 0d) {
+ return (int)Math.signum(dFrac);
+ }
+
+ double dDist = o1.getDistance() - o2.getDistance();
+ if (dDist != 0d) {
+ return (int)Math.signum(dDist);
+ }
+
+ return 0;
+ }
+
+ }
+
+ /**
+ * Matches the house numbers of one street name to its OSM elements and roads.
+ * @param streetname name of street
+ * @param elements a list of OSM elements belonging to this street name
+ * @param roads a list of roads with the given street name
+ */
+ private void match(String streetname, List<Element> elements, List<MapRoad> roads) {
+ List<HousenumberMatch> numbersList = new ArrayList<HousenumberMatch>(
+ elements.size());
+ for (Element node : elements) {
+ try {
+ numbersList.add(new HousenumberMatch(node));
+ } catch (IllegalArgumentException exp) {
+ log.debug(exp);
+ }
+ }
+
+ MultiHashMap<MapRoad, HousenumberMatch> roadNumbers = new MultiHashMap<MapRoad, HousenumberMatch>();
+
+ for (HousenumberMatch n : numbersList) {
+
+ for (MapRoad r : roads) {
+ int node = -1;
+ Coord c1 = null;
+ for (Coord c2 : r.getPoints()) {
+ if (c1 != null) {
+ Coord cx = n.getLocation();
+ double frac = getFrac(c1, c2, cx);
+ double dist = distanceToSegment(c1,c2,cx,frac);
+ if (dist <= MAX_DISTANCE_TO_ROAD && dist < n.getDistance()) {
+ n.setDistance(dist);
+ n.setSegmentFrac(frac);
+ n.setRoad(r);
+ n.setSegment(node);
+ }
+ }
+ c1 = c2;
+ node++;
+ }
+ }
+
+ if (n.getRoad() != null) {
+ Coord c1 = n.getRoad().getPoints().get(n.getSegment());
+ Coord c2 = n.getRoad().getPoints().get(n.getSegment()+1);
+
+ n.setLeft(isLeft(c1, c2, n.getLocation()));
+ roadNumbers.add(n.getRoad(), n);
+ }
+ }
+
+ // go through all roads and apply the house numbers
+ for (Entry<MapRoad, List<HousenumberMatch>> roadX : roadNumbers.entrySet()) {
+ MapRoad r = roadX.getKey();
+ if (roadX.getValue().isEmpty()) {
+ continue;
+ }
+
+ List<HousenumberMatch> leftNumbers = new ArrayList<HousenumberMatch>();
+ List<HousenumberMatch> rightNumbers = new ArrayList<HousenumberMatch>();
+ for (HousenumberMatch hr : roadX.getValue()) {
+ if (hr.isLeft()) {
+ leftNumbers.add(hr);
+ } else {
+ rightNumbers.add(hr);
+ }
+ }
+
+ Collections.sort(leftNumbers, new HousenumberMatchComparator());
+ Collections.sort(rightNumbers, new HousenumberMatchComparator());
+
+ List<Numbers> numbersListing = new ArrayList<Numbers>();
+
+ log.info("Housenumbers for",r.getName(),r.getCity());
+ log.info("Numbers:",roadX.getValue());
+
+ int n = 0;
+ int lastRoutableNodeIndex = -1;
+ for (Coord p : r.getPoints()) {
+ if (n== 0) {
+ assert p instanceof CoordNode;
+ }
+
+ if (p instanceof CoordNode == false) {
+ n++;
+ continue;
+ }
+
+ if (lastRoutableNodeIndex < 0) {
+ lastRoutableNodeIndex=n;
+ n++;
+ continue;
+ }
+
+ Numbers numbers = new Numbers();
+ numbers.setNodeNumber(0);
+ numbers.setRnodNumber(lastRoutableNodeIndex);
+
+ applyNumbers(numbers,leftNumbers,n,true);
+ applyNumbers(numbers,rightNumbers,n,false);
+ log.info("Left: ",numbers.getLeftNumberStyle(),numbers.getRnodNumber(),"Start:",numbers.getLeftStart(),"End:",numbers.getLeftEnd(), "Remaining: "+leftNumbers);
+ log.info("Right:",numbers.getRightNumberStyle(),numbers.getRnodNumber(),"Start:",numbers.getRightStart(),"End:",numbers.getRightEnd(), "Remaining: "+rightNumbers);
+
+ numbersListing.add(numbers);
+
+ lastRoutableNodeIndex=n;
+
+ n++;
+ }
+
+ r.setNumbers(numbersListing);
+ }
+ }
+
+ /**
+ * Apply the given house numbers to the numbers object.
+ * @param numbers the numbers object to be configured
+ * @param housenumbers a list of house numbers
+ * @param maxSegment the highest segment number to use
+ * @param left {@code true} the left side of the street; {@code false} the right side of the street
+ */
+ private void applyNumbers(Numbers numbers, List<HousenumberMatch> housenumbers, int maxSegment, boolean left) {
+ NumberStyle style = NumberStyle.NONE;
+
+ if (housenumbers.isEmpty() == false) {
+ // get the sublist of housenumbers
+ int maxN = -1;
+ boolean even = false;
+ boolean odd = false;
+ for (int i = 0; i< housenumbers.size(); i++) {
+ HousenumberMatch hn = housenumbers.get(i);
+ if (hn.getSegment() >= maxSegment) {
+ break;
+ } else {
+ maxN = i;
+ if (hn.getHousenumber() % 2 == 0) {
+ even = true;
+ } else {
+ odd = true;
+ }
+ }
+ }
+
+ if (maxN >= 0) {
+ if (even && odd) {
+ style = NumberStyle.BOTH;
+ } else if (even) {
+ style = NumberStyle.EVEN;
+ } else {
+ style = NumberStyle.ODD;
+ }
+
+ int start = housenumbers.get(0).getHousenumber();
+ int end = housenumbers.get(maxN).getHousenumber();
+ if (left) {
+ numbers.setLeftStart(start);
+ numbers.setLeftEnd(end);
+ } else {
+ numbers.setRightStart(start);
+ numbers.setRightEnd(end);
+ }
+
+ housenumbers.subList(0, maxN+1).clear();
+ }
+ }
+
+ if (left)
+ numbers.setLeftNumberStyle(style);
+ else
+ numbers.setRightNumberStyle(style);
+
+ }
+
+ /**
+ * Evaluates if the given point lies on the left side of the line spanned by spoint1 and spoint2.
+ * @param spoint1 first point of line
+ * @param spoint2 second point of line
+ * @param point the point to check
+ * @return {@code true} point lies on the left side; {@code false} point lies on the right side
+ */
+ private boolean isLeft(Coord spoint1, Coord spoint2, Coord point) {
+
+ boolean left = ((spoint2.getLongitude() - spoint1.getLongitude())
+ * (point.getLatitude() - spoint1.getLatitude()) - (spoint2.getLatitude() - spoint1
+ .getLatitude()) * (point.getLongitude() - spoint1.getLongitude())) > 0;
+
+ return left;
+ }
+
+ /**
+ * Calculates the distance to the given segment in meter.
+ * @param spoint1 segment point 1
+ * @param spoint2 segment point 2
+ * @param point point
+ * @return the distance in meter
+ */
+ private double distanceToSegment(Coord spoint1, Coord spoint2, Coord point, double frac) {
+
+ if (frac <= 0) {
+ return spoint1.distance(point);
+ } else if (frac >= 1) {
+ return spoint2.distance(point);
+ } else {
+ return spoint1.makeBetweenPoint(spoint2, frac).distance(point);
+ }
+
+ }
+
+ /**
+ * Calculates the fraction at which the given point is closest to the line segment.
+ * @param spoint1 segment point 1
+ * @param spoint2 segment point 2
+ * @param point point
+ * @return the fraction
+ */
+ private double getFrac(Coord spoint1, Coord spoint2, Coord point) {
+
+ double dx = spoint2.getLongitude() - spoint1.getLongitude();
+ double dy = spoint2.getLatitude() - spoint1.getLatitude();
+
+ if ((dx == 0) && (dy == 0)) {
+ return 0;
+ }
+
+ return ((point.getLongitude() - spoint1.getLongitude()) * dx + (point
+ .getLatitude() - spoint1.getLatitude()) * dy)
+ / (dx * dx + dy * dy);
+
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/housenumber/HousenumberMatch.java b/src/uk/me/parabola/mkgmap/osmstyle/housenumber/HousenumberMatch.java
new file mode 100644
index 0000000..56a609c
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/housenumber/HousenumberMatch.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2013.
+ *
+ * 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.osmstyle.housenumber;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.general.MapRoad;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.Node;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+
+/**
+ * Stores the matching data between a housenumber and its road.
+ * @author WanMil
+ */
+public class HousenumberMatch {
+
+ private final Element element;
+
+ private MapRoad road;
+
+ private double distance = Double.POSITIVE_INFINITY;
+ private int segment = -1;
+ private boolean left;
+
+ private double segmentFrac;
+
+ private int housenumber;
+
+ /**
+ * Instantiates a new housenumber match element.
+ * @param element the OSM element tagged with mkgmap:housenumber
+ * @throws IllegalArgumentException if the housenumber cannot be parsed
+ */
+ public HousenumberMatch(Element element) {
+ this.element = element;
+ parseHousenumber();
+ }
+
+ /**
+ * Retrieves the location of the housenumber.
+ * @return location of housenumber
+ */
+ public Coord getLocation() {
+ return (element instanceof Node ? ((Node)element).getLocation() : ((Way)element).getCofG());
+ }
+
+ /**
+ * Retrieves the house number of this element.
+ * @param e an OSM element
+ * @return the house number (or {@code null} if no house number set)
+ */
+ public static String getHousenumber(Element e) {
+ if (e.getTag("mkgmap:housenumber") != null) {
+ return e.getTag("mkgmap:housenumber");
+ }
+ if (e.getTag("addr:housenumber") != null) {
+ return e.getTag("addr:housenumber");
+ }
+ return null;
+ }
+
+ /**
+ * Parses the house number string. It accepts the first positive number part
+ * of a string. So all leading and preceding non number parts are ignored.
+ * So the following strings are accepted:
+ * <table>
+ * <tr>
+ * <th>Input</th>
+ * <th>Output</th>
+ * </tr>
+ * <tr>
+ * <td>23</td>
+ * <td>23</td>
+ * </tr>
+ * <tr>
+ * <td>-23</td>
+ * <td>23</td>
+ * </tr>
+ * <tr>
+ * <td>21-23</td>
+ * <td>21</td>
+ * </tr>
+ * <tr>
+ * <td>Abc 21</td>
+ * <td>21</td>
+ * </tr>
+ * <tr>
+ * <td>Abc 21.45</td>
+ * <td>21</td>
+ * </tr>
+ * <tr>
+ * <td>21 Main Street</td>
+ * <td>21</td>
+ * </tr>
+ * <tr>
+ * <td>Main Street</td>
+ * <td><i>IllegalArgumentException</i></td>
+ * </tr>
+ * </table>
+ * @throws IllegalArgumentException if parsing fails
+ */
+ private void parseHousenumber() {
+ String housenumberString = getHousenumber(element);
+
+ if (housenumberString == null) {
+ throw new IllegalArgumentException("No housenumber found in "+element.toBrowseURL());
+ }
+
+ // the housenumber must match against the pattern <anything>number<notnumber><anything>
+ Pattern p = Pattern.compile("\\D*(\\d+)\\D?.*");
+ Matcher m = p.matcher(housenumberString);
+ if (m.matches() == false) {
+ throw new IllegalArgumentException("No housenumber ("+element.toBrowseURL()+"): "+housenumberString);
+ }
+ try {
+ // get the number part and parse it
+ housenumber = Integer.parseInt(m.group(1));
+ } catch (NumberFormatException exp) {
+ throw new IllegalArgumentException("No housenumber ("+element.toBrowseURL()+"): "+housenumberString);
+ }
+
+ // a housenumber must be > 0
+ if (housenumber <= 0) {
+ throw new IllegalArgumentException("No housenumber ("+element.toBrowseURL()+"): "+housenumberString);
+ }
+ }
+
+ public MapRoad getRoad() {
+ return road;
+ }
+
+ public void setRoad(MapRoad road) {
+ this.road = road;
+ }
+
+ /**
+ * Retrieves the distance to the road.
+ * @return distance in m
+ */
+ public double getDistance() {
+ return distance;
+ }
+
+ /**
+ * Sets the distance to the road
+ * @param distance distance in m
+ */
+ public void setDistance(double distance) {
+ this.distance = distance;
+ }
+
+ /**
+ * Retrieves the segment number the house number belongs to.
+ * @return the segment number
+ */
+ public int getSegment() {
+ return segment;
+ }
+
+ /**
+ * Sets the segment number the house number belongs to.
+ * @param segment the segment number
+ */
+ public void setSegment(int segment) {
+ this.segment = segment;
+ }
+
+ public boolean isLeft() {
+ return left;
+ }
+
+ /**
+ * Sets if the house number is on the left or right side of the street.
+ * @param left {@code true} left side; {@code false} right side
+ */
+ public void setLeft(boolean left) {
+ this.left = left;
+ }
+
+ /**
+ * Retrieve the relative position of this house number within the segement
+ * of the related road.
+ * @return the relative position within the roads segment
+ */
+ public double getSegmentFrac() {
+ return segmentFrac;
+ }
+
+ /**
+ * Sets the relative position of this house number within its segment
+ * of the related road.
+ * @param segmentFrac relative position within the segment
+ */
+ public void setSegmentFrac(double segmentFrac) {
+ this.segmentFrac = segmentFrac;
+ }
+
+ /**
+ * Retrieve the house number
+ * @return the house number
+ */
+ public int getHousenumber() {
+ return housenumber;
+ }
+
+ /**
+ * Set the house number.
+ * @param housenumber house number
+ */
+ public void setHousenumber(int housenumber) {
+ this.housenumber = housenumber;
+ }
+
+ /**
+ * Retrieve the OSM element that defines the house number.
+ * @return the OSM element
+ */
+ public Element getElement() {
+ return element;
+ }
+
+ public String toString() {
+ return String.valueOf(housenumber)+"("+segment+")";
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/package.html b/src/uk/me/parabola/mkgmap/osmstyle/package.html
new file mode 100644
index 0000000..9f061bb
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/package.html
@@ -0,0 +1,10 @@
+<body>
+<h3>OSM style code</h3>
+<p>
+ This code deals with getting the appropriate garmin tag to use for an
+ OSM node or way, based on the tags for the element.
+ This code should be independant of the method used to read the data,
+ which may be from an xml file or from a database for example.
+</p>
+
+</body>
diff --git a/src/uk/me/parabola/mkgmap/reader/MapperBasedMapDataSource.java b/src/uk/me/parabola/mkgmap/reader/MapperBasedMapDataSource.java
new file mode 100644
index 0000000..b1f72b5
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/MapperBasedMapDataSource.java
@@ -0,0 +1,141 @@
+/*
+ * 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: 25-Sep-2007
+ */
+package uk.me.parabola.mkgmap.reader;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.trergn.Overview;
+import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
+import uk.me.parabola.mkgmap.general.MapDataSource;
+import uk.me.parabola.mkgmap.general.MapDetails;
+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.general.RoadNetwork;
+import uk.me.parabola.mkgmap.reader.dem.DEM;
+import uk.me.parabola.util.Configurable;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * A convenient base class for all map data that is based on the MapDetails
+ * class (which is all of them so far).
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class MapperBasedMapDataSource implements MapDataSource, Configurable {
+ protected final MapDetails mapper = new MapDetails();
+ private EnhancedProperties configProps;
+
+ /**
+ * Get the area that this map covers. Delegates to the map collector.
+ *
+ * @return The area the map covers.
+ */
+ public Area getBounds() {
+ return mapper.getBounds();
+ }
+
+ /**
+ * Get the list of lines that need to be rendered to the map. Delegates to
+ * the map collector.
+ *
+ * @return A list of {@link MapLine} objects.
+ */
+ public List<MapLine> getLines() {
+ return mapper.getLines();
+ }
+
+ public List<MapShape> getShapes() {
+ return mapper.getShapes();
+ }
+
+ public RoadNetwork getRoadNetwork() {
+ return mapper.getRoadNetwork();
+ }
+
+ /**
+ * Get a list of every feature that is used in the map. As features are
+ * created a list is kept of each separate feature that is used. This
+ * goes into the .img file and is important for points and polygons although
+ * it doesn't seem to matter if lines are represented or not on my Legend Cx
+ * anyway.
+ *
+ * @return A list of all the types of point, polygon and polyline that are
+ * used in the map.
+ */
+ public List<Overview> getOverviews() {
+ return mapper.getOverviews();
+ }
+
+ public List<MapPoint> getPoints() {
+ return mapper.getPoints();
+ }
+
+ public void config(EnhancedProperties props) {
+ configProps = props;
+ mapper.config(props);
+ }
+
+ protected EnhancedProperties getConfig() {
+ return configProps;
+ }
+
+ public MapDetails getMapper() {
+ return mapper;
+ }
+
+ /**
+ * We add the background polygons if the map is not transparent.
+ */
+ protected void addBackground() {
+ addBackground(false);
+ }
+
+ protected void addBackground(boolean mapHasPolygon4B) {
+ if (!mapHasPolygon4B && !getConfig().getProperty("transparent", false)) {
+
+ MapShape background = new MapShape();
+ background.setPoints(mapper.getBounds().toCoords());
+ background.setType(0x4b); // background type
+ background.setMinResolution(0); // On all levels
+
+ mapper.addShape(background);
+ }
+ if (getConfig().getProperty("contours", false)) {
+ DEM.createContours((LoadableMapDataSource) this, getConfig());
+ }
+ }
+
+ public void addBoundaryLine(Area area, int type, String name) {
+ List<Coord> coords = new ArrayList<Coord>();
+ coords.add(new Coord(area.getMinLat(), area.getMinLong()));
+ coords.add(new Coord(area.getMinLat(), area.getMaxLong()));
+ coords.add(new Coord(area.getMaxLat(), area.getMaxLong()));
+ coords.add(new Coord(area.getMaxLat(), area.getMinLong()));
+ coords.add(new Coord(area.getMinLat() + 1, area.getMinLong()));
+ MapLine boundary = new MapLine();
+ boundary.setType(type);
+ if(name != null)
+ boundary.setName(name);
+ boundary.setMinResolution(0); // On all levels
+ boundary.setPoints(coords);
+ mapper.addLine(boundary);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/dem/Brent.java b/src/uk/me/parabola/mkgmap/reader/dem/Brent.java
new file mode 100644
index 0000000..19e47b6
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/dem/Brent.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2009 Christian Gawron
+ *
+ * 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: Christian Gawron
+ * Create date: 03-Jul-2009
+ */
+package uk.me.parabola.mkgmap.reader.dem;
+
+/**
+ * Find zero of a function using Brent's method.
+ */
+public class Brent {
+
+ public interface Function {
+ public double eval(double x);
+ }
+
+ private static final double epsilon = 3.0e-10;
+
+ public static double zero(Function f, double x1, double x2) {
+ return zero(f, x1, x2, 1e-8, 100);
+ }
+
+ public static double zero(Function f, double x1, double x2, double tol, int maxit) {
+ double a=x1, b=x2, c=x2;
+ double fa=f.eval(a), fb=f.eval(b);
+
+ if ((fa > 0.0 && fb > 0.0) || (fa < 0.0 && fb < 0.0))
+ throw new ArithmeticException("Root must be bracketed");
+
+ double fc = fb;
+ double d = 0;
+ double e = 0;
+ for (int iterations=0; iterations < maxit; iterations++) {
+ if ((fb > 0.0 && fc > 0.0) || (fb < 0.0 && fc < 0.0)) {
+ c=a;
+ fc=fa;
+ e=d=b-a;
+ }
+ if (Math.abs(fc) < Math.abs(fb)) {
+ a=b;
+ b=c;
+ c=a;
+ fa=fb;
+ fb=fc;
+ fc=fa;
+ }
+ double tolerance = 2.0 * epsilon * Math.abs(b) + 0.5 * tol;
+ double xm = 0.5 * (c - b);
+ if (Math.abs(xm) <= tolerance || fb == 0.0) return b;
+ if (Math.abs(e) >= tolerance && Math.abs(fa) > Math.abs(fb)) {
+ double s = fb / fa;
+ double p;
+ double q;
+ if (a == c) {
+ p=2.0*xm*s;
+ q=1.0-s;
+ } else {
+ q=fa/fc;
+ double r = fb / fc;
+ p=s*(2.0*xm*q*(q-r)-(b-a)*(r-1.0));
+ q=(q-1.0)*(r-1.0)*(s-1.0);
+ }
+ if (p > 0.0) q = -q;
+ p=Math.abs(p);
+ double min1 = 3.0 * xm * q - Math.abs(tolerance * q);
+ double min2 = Math.abs(e * q);
+ if (2.0*p < (min1 < min2 ? min1 : min2)) {
+ e=d;
+ d=p/q;
+ } else {
+ d=xm;
+ e=d;
+ }
+ } else {
+ d=xm;
+ e=d;
+ }
+ a=b;
+ fa=fb;
+ if (Math.abs(d) > tolerance)
+ b += d;
+ else
+ b += xm >= 0 ? tolerance : -tolerance;
+ fb=f.eval(b);
+ }
+ throw new ArithmeticException("Maximum number of iterations exceeded");
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/mkgmap/reader/dem/DEM.java b/src/uk/me/parabola/mkgmap/reader/dem/DEM.java
new file mode 100644
index 0000000..71bc07b
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/dem/DEM.java
@@ -0,0 +1,859 @@
+/*
+ * Copyright (C) 2009 Christian Gawron
+ *
+ * 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: Christian Gawron
+ * Create date: 03-Jul-2009
+ */
+package uk.me.parabola.mkgmap.reader.dem;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.ExitException;
+import uk.me.parabola.imgfmt.FileSystemParam;
+import uk.me.parabola.imgfmt.FormatException;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.map.Map;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.build.MapBuilder;
+import uk.me.parabola.mkgmap.general.LevelInfo;
+import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
+import uk.me.parabola.mkgmap.osmstyle.StyleImpl;
+import uk.me.parabola.mkgmap.osmstyle.StyledConverter;
+import uk.me.parabola.mkgmap.reader.MapperBasedMapDataSource;
+import uk.me.parabola.mkgmap.reader.osm.OsmConverter;
+import uk.me.parabola.mkgmap.reader.osm.Style;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.EnhancedProperties;
+
+
+/**
+ * Create contour lines using an algorithm similar to that described in <a
+ * href="http://mapcontext.com/autocarto/proceedings/auto-carto-5/pdf/an-adaptive-grid-contouring-algorithm.pdf">An
+ * Adaptive Grid Contouring Algorithm</a> by Downing and Zoraster.
+ */
+public abstract class DEM {
+ private static final Logger log = Logger.getLogger(DEM.class);
+
+ private final static double epsilon = 1e-9;
+ final protected static double delta = 1.5;
+ private final static int maxPoints = 200000;
+ private final static double minDist = 15;
+ private final static double maxDist = 21;
+
+ protected static int M = 1200;
+ protected static int N = M;
+ protected static double res = 1.0 / N;
+ private static int id = -1;
+
+ protected int lat;
+ protected int lon;
+
+ protected abstract double ele(int x, int y);
+
+ protected abstract void read(int minLon, int minLat, int maxLon, int maxLat);
+
+ public static void createContours(LoadableMapDataSource mapData, EnhancedProperties config) {
+ Area bounds = mapData.getBounds();
+
+ double minLat = Utils.toDegrees(bounds.getMinLat());
+ double minLon = Utils.toDegrees(bounds.getMinLong());
+ double maxLat = Utils.toDegrees(bounds.getMaxLat());
+ double maxLon = Utils.toDegrees(bounds.getMaxLong());
+
+ System.out.printf("bounds: %f %f %f %f\n", minLat, minLon, maxLat, maxLon);
+ DEM data;
+ String demType = config.getProperty("dem-type", "SRTM");
+
+ try {
+ String dataPath;
+ Class demClass;
+ if (demType.equals("ASTER")) {
+ dataPath = config.getProperty("dem-path", "ASTER");
+ demClass = Class.forName("uk.me.parabola.mkgmap.reader.dem.optional.GeoTiffDEM$ASTER");
+ } else if (demType.equals("CGIAR")) {
+ dataPath = config.getProperty("dem-path", "CGIAR");
+ demClass = Class.forName("uk.me.parabola.mkgmap.reader.dem.optional.GeoTiffDEM$CGIAR");
+ } else {
+ dataPath = config.getProperty("dem-path", "SRTM");
+ demClass = Class.forName("uk.me.parabola.mkgmap.reader.dem.HGTDEM");
+ }
+ Constructor<DEM> constructor = demClass.getConstructor(String.class,
+ Double.TYPE, Double.TYPE,
+ Double.TYPE, Double.TYPE);
+ data = constructor.newInstance(dataPath, minLat, minLon, maxLat, maxLon);
+ }
+ catch (Exception ex) {
+ throw new ExitException("failed to create DEM", ex);
+ }
+
+ Isolines lines = data.new Isolines(data, minLat, minLon, maxLat, maxLon);
+ int increment = config.getProperty("dem-increment", 10);
+
+ double minHeight = lines.getMinHeight();
+ double maxHeight = lines.getMaxHeight();
+ int maxLevels = config.getProperty("dem-maxlevels", 100);
+ while ((maxHeight - minHeight) / increment > maxLevels)
+ increment *= 2;
+
+ Style style = StyleImpl.readStyle(config);
+
+ LoadableMapDataSource dest = mapData;
+ if (config.getProperty("dem-separate-img", false)) {
+ dest = new DEMMapDataSource(mapData, config);
+ }
+
+ OsmConverter converter = new StyledConverter(style, ((MapperBasedMapDataSource) dest).getMapper(), config);
+
+ for (int level = 0; level < maxHeight; level += increment) {
+ if (level < minHeight) continue;
+
+ // create isolines
+ lines.addLevel(level);
+
+ for (Isolines.Isoline line : lines.isolines) {
+ Way way = new Way(id--, line.points);
+ way.addTag("contour", "elevation");
+ way.addTag("ele", String.format("%d", (int) line.level));
+ converter.convertWay(way);
+ }
+ lines.isolines.clear();
+ }
+
+ if (config.getProperty("dem-separate-img", false)) {
+ MapBuilder builder = new MapBuilder();
+ builder.config(config);
+
+ // Get output directory
+ String DEFAULT_DIR = ".";
+ String fileOutputDir = config.getProperty("output-dir", DEFAULT_DIR);
+
+ // Test if directory exists
+ File outputDir = new File(fileOutputDir);
+ if (!outputDir.exists()) {
+ System.out.println("Output directory not found. Creating directory '" + fileOutputDir + "'");
+ if (!outputDir.mkdirs()) {
+ System.err.println("Unable to create output directory! Using default directory instead");
+ fileOutputDir = DEFAULT_DIR;
+ }
+ } else if (!outputDir.isDirectory()) {
+ System.err.println("The --output-dir parameter must specify a directory. The parameter is being ignored, writing to default directory instead.");
+ fileOutputDir = DEFAULT_DIR;
+ }
+
+ FileSystemParam params = new FileSystemParam();
+ params.setMapDescription("contour lines");
+ long mapName = Integer.valueOf(config.getProperty("mapname", "63240000"));
+ try {
+ String mapname = String.format("%08d", mapName + 10000000);
+ Map map = Map.createMap(mapname, fileOutputDir, params, mapname, Sort.defaultSort(1252));
+ builder.makeMap(map, dest);
+ map.close();
+ }
+ catch (Exception ex) {
+ throw new ExitException("could not open " + mapName, ex);
+ }
+ }
+ }
+
+ private int lastXi = -1;
+ private int lastYi = -1;
+
+ private final static int[][] bcInv = {
+ {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
+ {-3, 0, 0, 3, 0, 0, 0, 0, -2, 0, 0, -1, 0, 0, 0, 0},
+ {2, 0, 0, -2, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0},
+ {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
+ {0, 0, 0, 0, -3, 0, 0, 3, 0, 0, 0, 0, -2, 0, 0, -1},
+ {0, 0, 0, 0, 2, 0, 0, -2, 0, 0, 0, 0, 1, 0, 0, 1},
+ {-3, 3, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, -2, -1, 0, 0},
+ {9, -9, 9, -9, 6, 3, -3, -6, 6, -6, -3, 3, 4, 2, 1, 2},
+ {-6, 6, -6, 6, -4, -2, 2, 4, -3, 3, 3, -3, -2, -1, -1, -2},
+ {2, -2, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 1, 1, 0, 0},
+ {-6, 6, -6, 6, -3, -3, 3, 3, -4, 4, 2, -2, -2, -2, -1, -1},
+ {4, -4, 4, -4, 2, 2, -2, -2, 2, -2, -2, 2, 1, 1, 1, 1}
+ };
+
+ private static int lastId = 1000000000;
+ private static double lastX;
+ private static double lastY;
+
+ private static final int[][] off0 = {{0, 0},
+ {0, 0},
+ {0, 1},
+ {1, 1}};
+
+ private static final int[][] off1 = {{1, 0},
+ {0, 1},
+ {1, 1},
+ {1, 0}};
+
+ private static final int[] brd = {1, 2, 4, 8};
+
+ private static final int[] rev = {2, 3, 0, 1};
+
+ private static final int[][] mov = {{0, -1},
+ {-1, 0},
+ {0, 1},
+ {1, 0}};
+
+
+ private final double[][] bc = new double[4][4];
+ private final double[] bc_y = new double[4];
+ private final double[] bc_y1 = new double[4];
+ private final double[] bc_y2 = new double[4];
+ private final double[] bc_y12 = new double[4];
+ private final double[] bc_Coeff = new double[16];
+ private final double[] bc_x = new double[16];
+
+ private void recalculateCoefficients(int xi, int yi) {
+
+ double v00 = ele(xi, yi);
+ double v0p = ele(xi, yi + 1);
+ double vpp = ele(xi + 1, yi + 1);
+ double vp0 = ele(xi + 1, yi);
+
+ double vm0 = ele(xi - 1, yi);
+ double v0m = ele(xi, yi - 1);
+ double vmp = ele(xi - 1, yi + 1);
+ double vpm = ele(xi + 1, yi - 1);
+ double vmm = ele(xi - 1, yi - 1);
+ double vmP = ele(xi + 2, yi - 1);
+ double vPm = ele(xi - 1, yi + 2);
+
+ double vP0 = ele(xi + 2, yi);
+ double v0P = ele(xi, yi + 2);
+ double vPp = ele(xi + 2, yi + 1);
+ double vpP = ele(xi + 1, yi + 2);
+ double vPP = ele(xi + 2, yi + 2);
+
+ bc_y[0] = v00;
+ bc_y[1] = vp0;
+ bc_y[2] = vpp;
+ bc_y[3] = v0p;
+
+ bc_y1[0] = (vp0 - vm0) / 2;
+ bc_y1[1] = (vP0 - v00) / 2;
+ bc_y1[2] = (vPp - v0p) / 2;
+ bc_y1[3] = (vpp - vmp) / 2;
+
+ bc_y2[0] = (v0p - v0m) / 2;
+ bc_y2[1] = (vpp - vpm) / 2;
+ bc_y2[2] = (vpP - vp0) / 2;
+ bc_y2[3] = (v0P - v00) / 2;
+
+ bc_y12[0] = (vpp - vpm - vmp + vmm) / 4;
+ bc_y12[0] = (vPp - vPm - v0p + v0m) / 4;
+ bc_y12[2] = (vPP - vP0 - v0P + v00) / 4;
+ bc_y12[0] = (vpP - vp0 - vmP + vm0) / 4;
+
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ bc_x[i] = bc_y[i];
+ bc_x[i + 4] = bc_y1[i];
+ bc_x[i + 8] = bc_y2[i];
+ bc_x[i + 12] = bc_y12[i];
+ }
+
+ for (i = 0; i < 16; i++) {
+ double s = 0;
+ for (int k = 0; k < 16; k++) s += bcInv[i][k] * bc_x[k];
+ bc_Coeff[i] = s;
+ }
+
+ int l = 0;
+ for (i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ bc[i][j] = bc_Coeff[l++];
+ }
+
+ protected double gradient(double lat, double lon, double[] grad) {
+ grad[0] = 0;
+ grad[1] = 0;
+
+ double x = (lon - this.lon) / res;
+ double y = (lat - this.lat) / res;
+
+ int xi = (int) x;
+ int yi = (int) y;
+
+ if (lastXi != xi || lastYi != yi) {
+ log.debug("new Cell for interpolation: %d %d", xi, yi);
+ recalculateCoefficients(xi, yi);
+ lastXi = xi;
+ lastYi = yi;
+ }
+
+ double t = x - xi;
+ double u = y - yi;
+
+ if (xi < 0 || xi > N + 1 || yi < 0 || yi > N + 1)
+ throw new IndexOutOfBoundsException(String.format("(%f, %f)->(%d, %d)", lat, lon, xi, yi));
+
+ double val = 0;
+ for (int i = 3; i >= 0; i--) {
+ val = t * val + ((bc[i][3] * u + bc[i][2]) * u + bc[i][1]) * u + bc[i][0];
+ grad[0] = u * grad[0] + (3 * bc[3][i] * t + 2 * bc[2][i]) * t + bc[1][i];
+ grad[1] = t * grad[1] + (3 * bc[i][3] * t + 2 * bc[i][2]) * t + bc[i][1];
+ }
+
+ return val;
+ }
+
+ protected double elevation(double lat, double lon) {
+ double x = (lon - this.lon) / res;
+ double y = (lat - this.lat) / res;
+
+ int xi = (int) x;
+ int yi = (int) y;
+
+ if (lastXi != xi || lastYi != yi) {
+ log.debug("new Cell for interpolation: %d %d", xi, yi);
+ recalculateCoefficients(xi, yi);
+ lastXi = xi;
+ lastYi = yi;
+ }
+
+ double t = x - xi;
+ double u = y - yi;
+
+ if (xi < 0 || xi > N + 1 || yi < 0 || yi > N + 1)
+ throw new IndexOutOfBoundsException(String.format("(%f, %f)->(%d, %d)", lat, lon, xi, yi));
+
+ double val = 0;
+ for (int i = 3; i >= 0; i--) {
+ val = t * val + ((bc[i][3] * u + bc[i][2]) * u + bc[i][1]) * u + bc[i][0];
+ }
+
+ return val;
+ }
+
+ protected double elevation(int x, int y) {
+ if (x < 0 || x > N || y < 0 || y > N)
+ throw new IndexOutOfBoundsException(String.format("elevation: %d %d", x, y));
+ return ele(x, y);
+ }
+
+
+ class Isolines {
+ final DEM data;
+ final int minX;
+ final int maxX;
+ final int minY;
+ final int maxY;
+
+ double min;
+ double max;
+
+ final ArrayList<Isoline> isolines = new ArrayList<Isoline>();
+
+ class Isoline {
+ final int id;
+ final ArrayList<Coord> points;
+ final double level;
+
+ private Isoline(double level) {
+ this.level = level;
+ id = lastId++;
+ points = new ArrayList<Coord>();
+ }
+
+ private class Edge implements Brent.Function {
+ final double x0;
+ final double y0;
+ final double x1;
+ final double y1;
+
+ Edge(double x0, double y0, double x1, double y1) {
+ this.x0 = x0;
+ this.y0 = y0;
+ this.x1 = x1;
+ this.y1 = y1;
+ }
+
+ public double eval(double d) {
+ return data.elevation(x0 + d * (x1 - x0), y0 + d * (y1 - y0)) - level;
+ }
+ }
+
+ private class FN implements Brent.Function {
+ double x0, y0;
+ double dx, dy;
+
+ public void setParameter(double x0, double y0, double dx, double dy) {
+ this.x0 = x0;
+ this.y0 = y0;
+ this.dx = dx;
+ this.dy = dy;
+ }
+
+ public double eval(double t) {
+ return data.elevation(y0 + t * dy, x0 + t * dx) - level;
+ }
+ }
+
+ private final FN fn = new FN();
+
+ final double[] grad = new double[2];
+ final double[] px = new double[4];
+ final double[] py = new double[4];
+ final int[] edges = new int[4];
+
+ boolean addCell(Position p, int direction) {
+ log.debug("addCell: %f %d %d %d %d", level, p.ix, p.iy, p.edge, direction);
+
+ int c = 0;
+ for (int k = 0; k < 4; k++) {
+ if (k == p.edge)
+ continue;
+
+ int x0 = p.ix + off0[k][0];
+ int y0 = p.iy + off0[k][1];
+ int x1 = p.ix + off1[k][0];
+ int y1 = p.iy + off1[k][1];
+
+ double l0 = elevation(x0, y0) - level;
+ double l1 = elevation(x1, y1) - level;
+
+ if (Math.abs(l1) < epsilon || l0 * l1 < 0) {
+ edges[c] = k;
+
+ Brent.Function f = new Edge(data.lat + y0 * DEM.res, data.lon + x0 * DEM.res, data.lat + y1 * DEM.res, data.lon + x1 * DEM.res);
+ double f0 = elevation(x0, y0) - level;
+ double delta;
+
+ if (Math.abs(1) < epsilon) {
+ delta = 1;
+ } else if (Math.abs(f0) < epsilon)
+ throw new ExitException("implementation error!");
+ else
+ delta = Brent.zero(f, epsilon, 1 - epsilon);
+
+ px[c] = data.lon + (x0 + delta * (x1 - x0)) * DEM.res;
+ py[c] = data.lat + (y0 + delta * (y1 - y0)) * DEM.res;
+ c++;
+ }
+ }
+
+
+ if (c == 1) {
+ p.edge = edges[0];
+
+ double px0 = p.x;
+ double py0 = p.y;
+ p.x = px[0];
+ p.y = py[0];
+ double px1 = p.x;
+ double py1 = p.y;
+
+ double xMin = data.lon + p.ix * DEM.res;
+ double xMax = xMin + DEM.res;
+ double yMin = data.lat + p.iy * DEM.res;
+ double yMax = yMin + DEM.res;
+
+ refineAdaptively(xMin, yMin, xMax, yMax, px0, py0, px1, py1, direction, maxDist);
+
+ addPoint(p.x, p.y, direction);
+ p.moveCell();
+ return true;
+ } else {
+ log.debug("addCellByStepping: %d", c);
+ return addCellByStepping(p, direction, c, edges, px, py);
+ }
+ }
+
+ private void refineAdaptively(double xMin, double yMin, double xMax, double yMax,
+ double x0, double y0, double x1, double y1,
+ int direction, double maxDist)
+ {
+ double dist = quickDistance(x0, y0, x1, y1);
+ if (dist > maxDist) {
+ double dx = x1 - x0;
+ double dy = y1 - y0;
+
+ double xm = x0 + 0.5 * dx;
+ double ym = y0 + 0.5 * dy;
+ double n = Math.sqrt(dx * dx + dy * dy);
+ fn.setParameter(xm, ym, -dy / n, dx / n);
+ Brent.Function f = fn;
+ double t0 = -0.05 * res;
+ double t1 = 0.05 * res;
+ double f0 = f.eval(t0);
+ double f1 = f.eval(t1);
+
+ int count = 0;
+ while (f0 * f1 > 0 && count++ < 20) {
+ if ((count & 1) > 0)
+ t0 -= 0.05 * res;
+ else
+ t1 += 0.05 * res;
+ f0 = f.eval(t0);
+ f1 = f.eval(t1);
+ log.debug("refine: %f %f %f %f", t0, t1, f0, f1);
+ }
+
+ if (f0 * f1 < 0) {
+ double t = Brent.zero(f, t0, t1);
+ xm -= t * dy;
+ ym += t * dx;
+ } else {
+ log.debug("refine failed: %f %f %f %f", t0, t1, f0, f1);
+ return;
+ }
+
+ if (xm > xMin && xm < xMax && ym > yMin && ym < yMax)
+ refineAdaptively(xMin, yMin, xMax, yMax, x0, y0, xm, ym, direction, maxDist * 1.1);
+ addPoint(xm, ym, direction);
+ if (xm > xMin && xm < xMax && ym > yMin && ym < yMax)
+ refineAdaptively(xMin, yMin, xMax, yMax, xm, ym, x1, y1, direction, maxDist * 1.1);
+ }
+ }
+
+ boolean addCellByStepping(Position p, int direction, int numEdges, int[] edges, double[] px, double[] py) {
+ log.debug("addCellByStepping: %f %d %d %d %d", level, p.ix, p.iy, p.edge, direction);
+
+ int iMin = -1;
+ double md = 5000;
+
+ for (int i = 0; i < numEdges; i++) {
+ gradient(p.y, p.x, grad);
+ double dist = quickDistance(p.x, p.y, px[i], py[i]);
+ log.debug("distance %d: %f", i, dist);
+
+ if (dist < md && (visited[p.iy * (N + 1) + p.ix] & brd[edges[i]]) == 0) {
+ md = dist;
+ iMin = i;
+ }
+ }
+
+ p.edge = edges[iMin];
+
+ double px0 = p.x;
+ double py0 = p.y;
+ p.x = px[iMin];
+ p.y = py[iMin];
+ double px1 = p.x;
+ double py1 = p.y;
+
+ double xMin = data.lon + p.ix * DEM.res;
+ double xMax = xMin + DEM.res;
+ double yMin = data.lat + p.iy * DEM.res;
+ double yMax = yMin + DEM.res;
+
+ refineAdaptively(xMin, yMin, xMax, yMax, px0, py0, px1, py1, direction, maxDist);
+
+ addPoint(p.x, p.y, direction);
+ p.moveCell();
+ return true;
+ }
+
+ private void addPoint(double x, double y, int direction) {
+ double dist = quickDistance(x, y, lastX, lastY);
+ log.debug("addPoint: %f %f %f", x, y, dist);
+
+ if (dist > minDist) {
+ if (direction > 0)
+ points.add(0, new Coord(y, x));
+ else
+ points.add(points.size(), new Coord(y, x));
+ lastX = x;
+ lastY = y;
+ }
+ }
+
+ private void close() {
+ points.add(points.size(), points.get(0));
+ }
+
+ }
+
+ public Isolines(DEM data, double minLat, double minLon, double maxLat, double maxLon) {
+ System.out.printf("init: %f %f %f %f\n", minLat, minLon, maxLat, maxLon);
+
+ this.data = data;
+ this.minX = (int) ((minLon - data.lon) / res);
+ this.minY = (int) ((minLat - data.lat) / res);
+ this.maxX = (int) ((maxLon - data.lon) / res);
+ this.maxY = (int) ((maxLat - data.lat) / res);
+
+ init();
+ }
+
+ private void init() {
+ System.out.printf("init: %d %d %d %d\n", minX, minY, maxX, maxY);
+ data.read(minX - 2, minY - 2, maxX + 2, maxY + 2);
+ // we need some overlap for bicubic interpolation
+ max = -1000;
+ min = 10000;
+ for (int i = minX; i < maxX; i++)
+ for (int j = minY; j < maxY; j++) {
+ if (data.elevation(i, j) < min) min = data.elevation(i, j);
+ if (data.elevation(i, j) > max) max = data.elevation(i, j);
+ }
+
+ log.debug("min: %f, max: %f\n", min, max);
+ }
+
+ double getMinHeight() {
+ return min;
+ }
+
+ double getMaxHeight() {
+ return max;
+ }
+
+ private class Edge implements Brent.Function {
+ final double x0, y0, x1, y1, level;
+
+ Edge(double x0, double y0, double x1, double y1, double level) {
+ this.x0 = x0;
+ this.y0 = y0;
+ this.x1 = x1;
+ this.y1 = y1;
+ this.level = level;
+ }
+
+ public double eval(double d) {
+ return data.elevation(x0 + d * (x1 - x0), y0 + d * (y1 - y0)) - level;
+ }
+ }
+
+ private class Position {
+ int ix, iy;
+ double x, y;
+ int edge;
+
+ Position(int ix, int iy, double x, double y, int edge) {
+ this.ix = ix;
+ this.iy = iy;
+ this.x = x;
+ this.y = y;
+ this.edge = edge;
+ }
+
+ Position(Position p) {
+ this.ix = p.ix;
+ this.iy = p.iy;
+ this.x = p.x;
+ this.y = p.y;
+ this.edge = p.edge;
+ }
+
+ void markEdge() {
+ log.debug("marking edge: %d %d %d %d", ix, iy, edge, brd[edge]);
+ visited[iy * (N + 1) + ix] |= brd[edge];
+ }
+
+ void moveCell() {
+ markEdge();
+ ix += mov[edge][0];
+ iy += mov[edge][1];
+ edge = rev[edge];
+ markEdge();
+ }
+ }
+
+ final byte[] visited = new byte[(N + 1) * (N + 1)];
+
+ public void addLevel(double level) {
+ if (level < min || level > max)
+ return;
+
+ System.out.printf("addLevel: %f\n", level);
+ Arrays.fill(visited, (byte) 0);
+
+ for (int y = minY; y < maxY; y++) {
+ for (int x = minX; x < maxX; x++) {
+ byte v = 0;
+ int direction;
+ // Mark the borders of the cell, represented by the four points (i, j), (i+1, j), (i, j+1), (i+1, j+1),
+ // which are intersected by the contour. The values are:
+ // 1: top
+ // 2: left
+ // 4: bottom
+ // 8: right
+ if (data.elevation(x, y) >= level) {
+ if (data.elevation(x + 1, y) < level) {
+ v |= 1;
+ }
+ if (data.elevation(x, y + 1) < level) {
+ v |= 2;
+ }
+ direction = 1;
+ } else {
+ if (data.elevation(x + 1, y) > level) {
+ v |= 1;
+ }
+ if (data.elevation(x, y + 1) > level) {
+ v |= 2;
+ }
+ direction = -1;
+ }
+
+ int k = -1;
+
+ if ((v & 1) > 0 && (visited[y * (N + 1) + x] & 1) == 0) {
+ k = 0;
+ } else if ((v & 2) > 0 && (visited[y * (N + 1) + x] & 2) == 0) {
+ k = 1;
+ }
+
+ if (k >= 0) {
+ int x0 = x + off0[k][0];
+ int y0 = y + off0[k][1];
+ int x1 = x + off1[k][0];
+ int y1 = y + off1[k][1];
+
+ try {
+ Brent.Function f = new Edge(data.lat + y0 * DEM.res, data.lon + x0 * DEM.res,
+ data.lat + y1 * DEM.res, data.lon + x1 * DEM.res,
+ level);
+ double f0 = elevation(x0, y0) - level;
+ double f1 = elevation(x1, y1) - level;
+ double delta;
+ if (Math.abs(f0) < epsilon) {
+ delta = 0;
+ } else if (Math.abs(f1) < epsilon)
+ continue;
+ else
+ delta = Brent.zero(f, 0, 1 - epsilon);
+
+ Position p = new Position(x, y, data.lon + (x0 + delta * (x1 - x0)) * DEM.res, data.lat + (y0 + delta * (y1 - y0)) * DEM.res, k);
+ p.markEdge();
+ isolines.add(traceByStepping(level, p, direction));
+ }
+ catch (RuntimeException ex) {
+ log.debug("error: %s", ex.toString());
+ ex.printStackTrace();
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ private Isoline traceByStepping(double level, Position p, int direction) {
+ log.debug("traceByStepping: starting contour %f %d %d %f %f %d", level, p.ix, p.iy, p.x, p.y, p.edge);
+ int n = 0;
+ Position startP = new Position(p);
+ boolean foundEnd = false;
+
+ Isoline line = new Isoline(level);
+
+ while (true) {
+ log.debug("traceByStepping: %f %d %d %f %f %d", level, p.ix, p.iy, p.x, p.y, p.edge);
+ visited[p.iy * (N + 1) + p.ix] |= brd[p.edge];
+
+ if (n > 0 && p.ix == startP.ix && p.iy == startP.iy && quickDistance(p.x, p.y, startP.x, startP.y) < 5) {
+ log.debug("closed curve!");
+ line.close();
+ break;
+ } else if (p.ix < minX || p.iy < minY || p.ix >= maxX || p.iy >= maxY) {
+ if (foundEnd) // did we already reach one end?
+ {
+ log.debug("second border reached!");
+ break;
+ } else {
+ log.debug("border reached!");
+ foundEnd = true;
+ n = 0;
+ direction *= -1;
+ p = new Position(startP);
+ p.moveCell();
+ continue;
+ }
+ }
+ n++;
+ if (!line.addCell(p, direction) || line.points.size() > maxPoints) {
+ log.debug("ending contour");
+ isolines.add(line);
+ return line;
+ }
+ }
+
+ return line;
+ }
+
+ }
+
+ private static double quickDistance(double long1, double lat1, double long2, double lat2) {
+ double latDiff;
+ if (lat1 < lat2)
+ latDiff = lat2 - lat1;
+ else
+ latDiff = lat1 - lat2;
+ if (latDiff > 90)
+ latDiff -= 180;
+
+ double longDiff;
+ if (long1 < long2)
+ longDiff = long2 - long1;
+ else
+ longDiff = long1 - long2;
+ if (longDiff > 180)
+ longDiff -= 360;
+
+ // scale longDiff by cosine of average latitude
+ longDiff *= Math.cos(Math.PI / 180 * Math.abs((lat1 + lat2) / 2));
+
+ double distDegSq = (latDiff * latDiff) + (longDiff * longDiff);
+
+ return 40075000 * Math.sqrt(distDegSq) / 360;
+ }
+
+
+ private static class DEMMapDataSource extends MapperBasedMapDataSource implements LoadableMapDataSource {
+ final LoadableMapDataSource parent;
+ final List<String> copyright = new ArrayList<String>();
+
+ DEMMapDataSource(LoadableMapDataSource parent, EnhancedProperties props) {
+ this.parent = parent;
+ config(props);
+ }
+
+ public boolean isFileSupported(String name) {
+ return false;
+ }
+
+ public void load(String name)
+ throws FileNotFoundException, FormatException
+ {
+ throw new FormatException("load not supported");
+ }
+
+ public LevelInfo[] mapLevels() {
+ return parent.mapLevels();
+ }
+
+ public LevelInfo[] overviewMapLevels() {
+ return parent.overviewMapLevels();
+ }
+
+ public String[] copyrightMessages() {
+ return copyright.toArray(new String[1]);
+ }
+
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/dem/HGTDEM.java b/src/uk/me/parabola/mkgmap/reader/dem/HGTDEM.java
new file mode 100644
index 0000000..f153c5f
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/dem/HGTDEM.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 Christian Gawron
+ *
+ * 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: Christian Gawron
+ * Create date: 03-Jul-2009
+ */
+package uk.me.parabola.mkgmap.reader.dem;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.MappedByteBuffer;
+
+import uk.me.parabola.imgfmt.ExitException;
+
+import static java.nio.channels.FileChannel.MapMode.READ_ONLY;
+
+public class HGTDEM extends DEM
+{
+ private MappedByteBuffer buffer ;
+
+ public HGTDEM(String dataPath, double minLat, double minLon, double maxLat, double maxLon)
+ {
+ this.lat = (int) minLat;
+ this.lon = (int) minLon;
+ if (maxLat > lat+1 || maxLon > lon+1)
+ throw new ExitException("Area too large (must not span more than one SRTM file)");
+
+ String northSouth = lat < 0 ? "S" : "N";
+ String eastWest = lon > 0 ? "E" : "W";
+ String fileName = String.format("%s/%s%02d%s%03d.hgt", dataPath,
+ northSouth, lat < 0 ? -lat : lat,
+ eastWest, lon < 0 ? -lon : lon);
+ try {
+ FileInputStream is = new FileInputStream(fileName);
+ buffer = is.getChannel().map(READ_ONLY, 0, 2*(M+1)*(M+1));
+ }
+ catch (Exception e) {
+ throw new ExitException("failed to open " + fileName, e);
+ }
+ }
+
+ public void read(int minLon, int minLat, int maxLon, int maxLat)
+ {
+ }
+
+ public double ele(int x, int y)
+ {
+ return buffer.getShort(2*((M-y)*(M+1)+x))+delta;
+ }
+
+ public void serializeCopyRight(Writer out) throws IOException
+ {
+ out.write(" <copyright>\n");
+ out.write(" Contour lines generated from DEM data by NASA\n");
+ out.write(" </copyright>\n");
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/dem/optional/GeoTiffDEM.java b/src/uk/me/parabola/mkgmap/reader/dem/optional/GeoTiffDEM.java
new file mode 100644
index 0000000..61283ed
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/dem/optional/GeoTiffDEM.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2009 Christian Gawron
+ *
+ * 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: Christian Gawron
+ * Create date: 03-Jul-2009
+ */
+package uk.me.parabola.mkgmap.reader.dem.optional;
+
+import java.awt.*;
+import java.awt.image.Raster;
+import java.awt.image.renderable.ParameterBlock;
+import java.io.IOException;
+import java.io.Writer;
+
+import javax.media.jai.JAI;
+import javax.media.jai.PlanarImage;
+import javax.media.jai.RenderedOp;
+
+import uk.me.parabola.imgfmt.ExitException;
+import uk.me.parabola.mkgmap.reader.dem.DEM;
+
+import com.sun.media.jai.codec.FileSeekableStream;
+import com.sun.media.jai.codec.SeekableStream;
+import com.sun.media.jai.codec.TIFFDecodeParam;
+
+public abstract class GeoTiffDEM extends DEM
+{
+ Raster raster;
+ String fileName;
+ int minLat, minLon, maxLat, maxLon;
+ PlanarImage image;
+
+ void initData()
+ {
+
+ try {
+ SeekableStream s = new FileSeekableStream(fileName);
+ ParameterBlock pb = new ParameterBlock();
+ pb.add(s);
+
+ TIFFDecodeParam param = new TIFFDecodeParam();
+ pb.add(param);
+
+ RenderedOp op = JAI.create("tiff", pb);
+ image = op.createInstance();
+ System.out.printf("Image: %d %d %d %d\n", image.getWidth(), image.getHeight(),
+ image.getNumXTiles(), image.getNumYTiles());
+ }
+ catch (Exception e) {
+ throw new ExitException("Failed to open/process " + fileName, e);
+ }
+ }
+
+ protected static class CGIAR extends GeoTiffDEM
+ {
+ public CGIAR(String dataPath, double minLat, double minLon, double maxLat, double maxLon)
+ {
+ this.lat = ((int) (minLat/5))*5;
+ this.lon = ((int) (minLon/5))*5;
+ if (maxLat > lat+5 || maxLon > lon+5)
+ throw new ExitException("Area too large (must not span more than one CGIAR GeoTIFF)");
+
+ int tileX = (180 + lon) / 5 + 1;
+ int tileY = (60 - lat) / 5;
+ this.fileName = String.format("%s/srtm_%02d_%02d.tif", dataPath, tileX, tileY);
+ System.out.printf("CGIAR GeoTIFF: %s\n", fileName);
+ N = 6000;
+ M = 6000;
+ res = 5.0/M;
+
+ initData();
+ }
+
+ public void serializeCopyRight(Writer out) throws IOException
+ {
+ out.write(" <copyright>\n");
+ out.write(" Contour lines generated from improved SRTM data by CIAT-CSI (see http://srtm.csi.cgiar.org)\n");
+ out.write(" </copyright>\n");
+ }
+
+ protected void read(int minLon, int minLat, int maxLon, int maxLat)
+ {
+ this.minLon = minLon;
+ this.minLat = minLat;
+ this.maxLon = maxLon;
+ this.maxLat = maxLat;
+ raster = image.getData(new Rectangle(minLon, 6000-maxLat-1, maxLon-minLon+1, maxLat-minLat+1));
+ System.out.printf("read: %d %d %d %d\n", minLon, 6000-maxLat-1, maxLon-minLon+1, maxLat-minLat+1);
+ }
+
+ public double ele(int x, int y)
+ {
+ int elevation = raster.getPixel(x, 6000-y-1, (int[])null)[0];
+ return elevation+delta;
+ }
+ }
+
+ protected static class ASTER extends GeoTiffDEM
+ {
+
+ public ASTER(String dataPath, double minLat, double minLon, double maxLat, double maxLon)
+ {
+ this.lat = (int) minLat;
+ this.lon = (int) minLon;
+ if (maxLat > lat+1 || maxLon > lon+1)
+ throw new ExitException("Area too large (must not span more than one ASTER GeoTIFF)");
+
+ String northSouth = lat < 0 ? "S" : "N";
+ String eastWest = lon > 0 ? "E" : "W";
+ fileName = String.format("%s/ASTGTM_%s%02d%s%03d_dem.tif", dataPath,
+ northSouth, lat < 0 ? -lat : lat,
+ eastWest, lon < 0 ? -lon : lon);
+
+ System.out.printf("ASTER GeoTIFF: %s\n", fileName);
+ N = 3600;
+ M = 3600;
+ res = 1.0/M;
+ initData();
+ }
+
+ public void serializeCopyRight(Writer out) throws IOException
+ {
+ out.write(" <copyright>\n");
+ out.write(" Contour lines generated from DGM data by ASTER (see https://wist.echo.nasa.gov/~wist/api/imswelcome)\n");
+ out.write(" </copyright>\n");
+ }
+
+ protected void read(int minLon, int minLat, int maxLon, int maxLat)
+ {
+ this.minLon = minLon;
+ this.minLat = minLat;
+ this.maxLon = maxLon;
+ this.maxLat = maxLat;
+ raster = image.getData(new Rectangle(minLon, 3601-maxLat-1, maxLon-minLon+1, maxLat-minLat+1));
+ System.out.printf("read: %d %d %d %d\n", minLon, 3601-maxLat-1, maxLon-minLon+1, maxLat-minLat+1);
+ }
+
+ public double ele(int x, int y)
+ {
+ int elevation = raster.getPixel(x, 3601-y-1, (int[])null)[0];
+ return elevation+delta;
+ }
+ }
+
+}
+
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/CoastlineElementSaver.java b/src/uk/me/parabola/mkgmap/reader/osm/CoastlineElementSaver.java
new file mode 100644
index 0000000..7b3659b
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/CoastlineElementSaver.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010, 2012.
+ *
+ * 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.reader.osm;
+
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * This saver only keeps ways with <code>natural=coastline</code> tags.
+ * This is used for loading of extra coastline files.
+ * @author WanMil
+ */
+public class CoastlineElementSaver extends ElementSaver {
+
+ public CoastlineElementSaver(EnhancedProperties args) {
+ super(args);
+ }
+
+ public void addNode(Node node) {
+ }
+
+ public void addWay(Way way) {
+ String tag = way.getTag("natural");
+ if (tag != null && tag.contains("coastline")) {
+ // remove all tags => the natural=coastline is implicitly known
+ way.removeAllTags();
+ super.addWay(way);
+ }
+ }
+
+ public void addRelation(Relation rel) {
+ }
+
+ public void convert(OsmConverter converter) {
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/CoastlineFileLoader.java b/src/uk/me/parabola/mkgmap/reader/osm/CoastlineFileLoader.java
new file mode 100644
index 0000000..15b068f
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/CoastlineFileLoader.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2010, 2012.
+ *
+ * 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.reader.osm;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import uk.me.parabola.imgfmt.FormatException;
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
+import uk.me.parabola.mkgmap.reader.osm.xml.Osm5CoastDataSource;
+import uk.me.parabola.util.EnhancedProperties;
+
+public final class CoastlineFileLoader {
+
+ private static final Logger log = Logger
+ .getLogger(CoastlineFileLoader.class);
+
+ private static final List<Class<? extends LoadableMapDataSource>> coastFileLoaders;
+
+ static {
+ String[] sources = {
+ "uk.me.parabola.mkgmap.reader.osm.bin.OsmBinCoastDataSource",
+ // must be last as it is the default
+ "uk.me.parabola.mkgmap.reader.osm.xml.Osm5CoastDataSource", };
+
+ coastFileLoaders = new ArrayList<Class<? extends LoadableMapDataSource>>();
+
+ for (String source : sources) {
+ try {
+ @SuppressWarnings({ "unchecked" })
+ Class<? extends LoadableMapDataSource> c = (Class<? extends LoadableMapDataSource>) Class
+ .forName(source);
+ coastFileLoaders.add(c);
+ } catch (ClassNotFoundException e) {
+ // not available, try the rest
+ } catch (NoClassDefFoundError e) {
+ // not available, try the rest
+ }
+ }
+ }
+
+ private final Set<String> coastlineFiles;
+ private final Collection<CoastlineWay> coastlines = new ArrayList<CoastlineWay>();
+
+ private final AtomicBoolean coastlinesLoaded = new AtomicBoolean(false);
+ private final AtomicBoolean loadingStarted = new AtomicBoolean(false);
+
+ private final EnhancedProperties coastConfig;
+
+ private CoastlineFileLoader() {
+ this.coastlineFiles = new HashSet<String>();
+ this.coastConfig = new EnhancedProperties();
+ // disable drive-on-left handling
+ this.coastConfig.setProperty("ignore-drive-on-left", "true");
+ }
+
+ private static final CoastlineFileLoader loader = new CoastlineFileLoader();
+
+ public static synchronized CoastlineFileLoader getCoastlineLoader() {
+ return loader;
+ }
+
+ public synchronized void setCoastlineFiles(String[] coastlineFiles) {
+ this.coastlineFiles.addAll(Arrays.asList(coastlineFiles));
+ }
+
+ public void loadCoastlines() {
+ boolean loadInThisThread = loadingStarted.compareAndSet(false, true);
+ if (loadInThisThread) {
+ // load it
+ loadCoastlinesImpl();
+ } else {
+ log.info("Coastline loading performed by another thread");
+ }
+ }
+
+ private OsmMapDataSource loadFromFile(String name)
+ throws FileNotFoundException, FormatException {
+ OsmMapDataSource src = createMapReader(name);
+ src.config(getConfig());
+ log.info("Started loading coastlines from", name);
+ src.load(name);
+ log.info("Finished loading coastlines from", name);
+ return src;
+ }
+
+ public static OsmMapDataSource createMapReader(String name) {
+ for (Class<? extends LoadableMapDataSource> loader : coastFileLoaders) {
+ try {
+ LoadableMapDataSource src = loader.newInstance();
+ if (name != null && src instanceof OsmMapDataSource
+ && src.isFileSupported(name))
+ return (OsmMapDataSource) src;
+ } catch (InstantiationException e) {
+ // try the next one.
+ } catch (IllegalAccessException e) {
+ // try the next one.
+ } catch (NoClassDefFoundError e) {
+ // try the next one
+ }
+ }
+
+ // Give up and assume it is in the XML format. If it isn't we will get
+ // an
+ // error soon enough anyway.
+ return new Osm5CoastDataSource();
+ }
+
+ private Collection<Way> loadFile(String filename)
+ throws FileNotFoundException {
+ OsmMapDataSource src = loadFromFile(filename);
+ return src.getElementSaver().getWays().values();
+ }
+
+ private EnhancedProperties getConfig() {
+ return coastConfig;
+ }
+
+ private synchronized void loadCoastlinesImpl() {
+ log.info("Load coastlines");
+ for (String coastlineFile : coastlineFiles) {
+ try {
+ int nBefore = coastlines.size();
+
+ Collection<Way> loadedCoastlines = loadFile(coastlineFile);
+ log.info(loadedCoastlines.size(), "coastline ways from",
+ coastlineFile, "loaded.");
+
+ ArrayList<Way> ways = SeaGenerator.joinWays(loadedCoastlines);
+ ListIterator<Way> wayIter = ways.listIterator();
+ ways = null;
+ while (wayIter.hasNext()) {
+ Way way = wayIter.next();
+ wayIter.remove();
+ coastlines.add(new CoastlineWay(way.getId(), way
+ .getPoints()));
+ }
+
+ log.info((coastlines.size() - nBefore),
+ "coastlines loaded from", coastlineFile);
+ } catch (FileNotFoundException exp) {
+ log.error("Coastline file " + coastlineFile + " not found.");
+ } catch (Exception exp) {
+ log.error(exp);
+ exp.printStackTrace();
+ }
+ }
+ coastlinesLoaded.set(true);
+ }
+
+ public Collection<Way> getCoastlines(Area bbox) {
+ if (coastlinesLoaded.get() == false) {
+ synchronized (this) {
+ loadCoastlines();
+ }
+ }
+ Collection<Way> ways = new ArrayList<Way>();
+ for (CoastlineWay w : coastlines) {
+ if (w.getBbox().intersects(bbox)) {
+ Way x = new Way(FakeIdGenerator.makeFakeId(), w.getPoints());
+ x.addTag("natural", "coastline");
+ ways.add(x);
+ }
+ }
+ return ways;
+ }
+
+ public static class CoastlineWay extends Way {
+ private final Area bbox;
+
+ public CoastlineWay(long id, List<Coord> points) {
+ super(id, points);
+ if (points.isEmpty()) {
+ throw new IllegalArgumentException(
+ "No support for empty ways. WayId: " + id);
+ }
+
+ if (log.isDebugEnabled())
+ log.debug("Create coastline way", id, "with", points.size(),
+ "points");
+ Coord firstPoint = getPoints().get(0);
+
+ int minLat = firstPoint.getLatitude();
+ int maxLat = firstPoint.getLatitude();
+ int minLong = firstPoint.getLongitude();
+ int maxLong = firstPoint.getLongitude();
+
+ for (Coord c : getPoints()) {
+ if (c.getLatitude() < minLat) {
+ minLat = c.getLatitude();
+ } else if (c.getLatitude() > maxLat) {
+ maxLat = c.getLatitude();
+ }
+ if (c.getLongitude() < minLong) {
+ minLong = c.getLongitude();
+ } else if (c.getLongitude() > maxLong) {
+ maxLong = c.getLongitude();
+ }
+ }
+ bbox = new Area(minLat, minLong, maxLat, maxLong);
+ }
+
+ @Override
+ public String getTag(String key) {
+ if ("natural".equals(key)) {
+ return "coastline";
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public String toTagString() {
+ return "[natural=coastline]";
+ }
+
+ @Override
+ public Map<String, String> getTagsWithPrefix(String prefix,
+ boolean removePrefix) {
+ if ("natural".startsWith(prefix)) {
+ if (removePrefix) {
+ return Collections.singletonMap(
+ "natural".substring(prefix.length()), "coastline");
+ } else {
+ return Collections.singletonMap("natural", "coastline");
+ }
+ } else {
+ return Collections.emptyMap();
+ }
+ }
+
+ @Override
+ protected void removeAllTags() {
+ }
+
+ @Override
+ public Iterable<Entry<String, String>> getEntryIteratable() {
+ return Collections.singletonMap("natural", "coastline").entrySet();
+ }
+
+ public Area getBbox() {
+ return bbox;
+ }
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/CoordPOI.java b/src/uk/me/parabola/mkgmap/reader/osm/CoordPOI.java
new file mode 100644
index 0000000..914ae38
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/CoordPOI.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 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: 13-Jul-2008
+ */
+package uk.me.parabola.mkgmap.reader.osm;
+
+import uk.me.parabola.imgfmt.app.Coord;
+
+/**
+ * A coordinate that has a POI
+ *
+ * @author Steve Ratcliffe
+ */
+public class CoordPOI extends Coord {
+ private Node node;
+ private boolean used;
+
+ /**
+ * Construct from co-ordinates that are already in map-units.
+ *
+ * @param latitude The latitude in map units.
+ * @param longitude The longitude in map units.
+ */
+ public CoordPOI(int latitude, int longitude) {
+ super(latitude, longitude);
+ }
+
+ public Node getNode() {
+ return node;
+ }
+
+ public void setNode(Node node) {
+ this.node = node;
+ }
+
+ public void setUsed(boolean b) {
+ this.used = b;
+ }
+ public boolean isUsed() {
+ return used;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/Element.java b/src/uk/me/parabola/mkgmap/reader/osm/Element.java
new file mode 100644
index 0000000..0a1a800
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/Element.java
@@ -0,0 +1,188 @@
+/**
+ * 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
+ * Date: 26-Dec-2006
+ */
+package uk.me.parabola.mkgmap.reader.osm;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Superclass of the node, segment and way OSM elements.
+ */
+public abstract class Element implements Iterable<String> {
+ private Tags tags;
+ private long id;
+
+ public int getTagCount() {
+ return (tags == null ? 0 : tags.size());
+ }
+
+ /**
+ * Add a tag to the way. Some tags are recognised separately and saved in
+ * separate fields.
+ *
+ * @param key The tag name.
+ * @param val Its value.
+ */
+ public void addTag(String key, String val) {
+ if (tags == null)
+ tags = new Tags();
+ tags.put(key, val);
+ }
+
+ public String getTag(String key) {
+ if (tags == null)
+ return null;
+ return tags.get(key);
+ }
+
+ public void deleteTag(String tagname) {
+ if(tags != null) {
+ tags.remove(tagname);
+ if (tags.size() == 0) {
+ tags = null;
+ }
+ }
+ }
+
+ public Iterator<String> iterator() {
+ if (tags == null)
+ return Collections.<String>emptyList().iterator();
+
+ return tags.iterator();
+ }
+
+ /**
+ * Retrieves if the given tag has a "positive" boolean value which means its value is
+ * one of
+ * <ul>
+ * <li><code>true</code></li>
+ * <li><code>yes</code></li>
+ * <li><code>1</code></li>
+ * </ul>
+ * @param s tag name
+ * @return <code>true</code> if the tag value is a boolean tag with a "positive" value
+ */
+ public boolean isBoolTag(String s) {
+ String val = getTag(s);
+ if (val == null)
+ return false;
+
+ if (val.equals("yes") || val.equals("true") || val.equals("1"))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Retrieves if the given tag has a "negative" boolean value which means its value is
+ * one of
+ * <ul>
+ * <li><code>false</code></li>
+ * <li><code>no</code></li>
+ * <li><code>0</code></li>
+ * </ul>
+ * @param s tag name
+ * @return <code>true</code> if the tag value is a boolean tag with a "negative" value
+ */
+ public boolean isNotBoolTag(String s) {
+ String val = getTag(s);
+ if (val == null)
+ return false;
+
+ if (val.equals("no") || val.equals("false") || val.equals("0"))
+ return true;
+
+ return false;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ protected void setId(long id) {
+ this.id = id;
+ }
+
+ public String toTagString() {
+ if (tags == null)
+ return "[]";
+
+ StringBuilder sb = new StringBuilder();
+ sb.append('[');
+ for (String nameval : tags) {
+ sb.append(nameval);
+ sb.append(',');
+ }
+ if (sb.length() > 1) {
+ sb.setLength(sb.length()-1);
+ }
+ sb.append(']');
+ return sb.toString();
+ }
+
+ /**
+ * Copy the tags of the other element which replaces all tags of this element.
+ *
+ * @param other The other element. All its tags will be copied to this
+ * element.
+ */
+ public void copyTags(Element other) {
+ if (other.tags == null)
+ tags = null;
+ else
+ tags = other.tags.copy();
+ }
+
+ public String getName() {
+ return getTag("mkgmap:label:1");
+ }
+
+ public Map<String, String> getTagsWithPrefix(String prefix, boolean removePrefix) {
+ if (tags == null)
+ return Collections.emptyMap();
+
+ return tags.getTagsWithPrefix(prefix, removePrefix);
+ }
+
+ protected void removeAllTags() {
+ tags = null;
+ }
+
+ public Iterable<Map.Entry<String, String>> getEntryIteratable() {
+ return new Iterable<Map.Entry<String, String>>() {
+ public Iterator<Map.Entry<String, String>> iterator() {
+ if (tags == null)
+ return Collections.<String, String>emptyMap().entrySet().iterator();
+ else
+ return tags.entryIterator();
+ }
+ };
+ }
+
+ protected String kind() {
+ return "unknown";
+ }
+
+ public String toBrowseURL() {
+ return "http://www.openstreetmap.org/browse/" + kind() + "/" + id;
+ }
+
+ public Element copy() {
+ // Can be implemented in subclasses
+ throw new UnsupportedOperationException("unsupported element copy");
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/ElementSaver.java b/src/uk/me/parabola/mkgmap/reader/osm/ElementSaver.java
new file mode 100644
index 0000000..fedca8e
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/ElementSaver.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.reader.osm;
+
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.LineClipper;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * This is where we save the elements read from any of the file formats that
+ * are in OSM format. OSM format means that there are nodes, ways and relations
+ * and they have tags.
+ *
+ * Both the XML format and the binary format use this.
+ *
+ * In the early days of mkgmap, the nodes and ways were converted as soon
+ * as they were encountered in the input file. After relations that is not
+ * possible, you have to save up all the nodes and ways as they might be
+ * needed for relations.
+ *
+ * We also want access to the other ways/nodes to generate sea polygons,
+ * prepare for routing etc.
+ *
+ * @author Steve Ratcliffe
+ */
+public class ElementSaver {
+ private static final Logger log = Logger.getLogger(ElementSaver.class);
+
+ protected OSMId2ObjectMap<Coord> coordMap = new OSMId2ObjectMap<Coord>();
+
+ protected Map<Long, Node> nodeMap;
+ protected Map<Long, Way> wayMap;
+ protected Map<Long, Relation> relationMap;
+
+ protected final Map<Long, List<Map.Entry<String,Relation>>> deferredRelationMap = new HashMap<Long, List<Map.Entry<String,Relation>>>();
+
+ // This is an explicitly given bounding box from the input file command line etc.
+ private Area boundingBox;
+
+ // This is a calculated bounding box, which is only available if there is
+ // no given bounding box.
+ private int minLat = Utils.toMapUnit(180.0);
+ private int minLon = Utils.toMapUnit(180.0);
+ private int maxLat = Utils.toMapUnit(-180.0);
+ private int maxLon = Utils.toMapUnit(-180.0);
+
+ // Options
+ private final boolean ignoreBuiltinRelations;
+ private final boolean ignoreTurnRestrictions;
+
+ /** name of the tag that contains a ;-separated list of tagnames that should be removed after all elements have been processed */
+ public static final String MKGMAP_REMOVE_TAG = "mkgmap:removetags";
+ /** tagvalue of the {@link ElementSaver#MKGMAP_REMOVE_TAG} if all tags should be removed */
+ public static final String MKGMAP_REMOVE_TAG_ALL_KEY = "mkgmap:ALL";
+
+ public ElementSaver(EnhancedProperties args) {
+ if (args.getProperty("preserve-element-order", false)) {
+ nodeMap = new LinkedHashMap<Long, Node>(5000);
+ wayMap = new LinkedHashMap<Long, Way>(5000);
+ relationMap = new LinkedHashMap<Long, Relation>();
+ } else {
+ nodeMap = new HashMap<Long, Node>();
+ wayMap = new HashMap<Long, Way>();
+ relationMap = new HashMap<Long, Relation>();
+ }
+
+ ignoreBuiltinRelations = args.getProperty("ignore-builtin-relations", false);
+ ignoreTurnRestrictions = args.getProperty("ignore-turn-restrictions", false);
+ }
+
+ /**
+ * Store the {@link Coord} with the associated OSM id.
+ * We use this to calculate a bounding box in the situation where none is
+ * given. In the usual case where there is a bounding box, then nothing
+ * is done.
+ *
+ * @param id the OSM id
+ * @param co The point.
+ */
+ public void addPoint(long id, Coord co) {
+ coordMap.put(id, co);
+ if (boundingBox == null) {
+ if (co.getLatitude() < minLat)
+ minLat = co.getLatitude();
+ if (co.getLatitude() > maxLat)
+ maxLat = co.getLatitude();
+
+ if (co.getLongitude() < minLon)
+ minLon = co.getLongitude();
+ if (co.getLongitude() > maxLon)
+ maxLon = co.getLongitude();
+ }
+ }
+
+ /**
+ * Add the given node and save it. The node should have tags.
+ *
+ * @param node The osm node.
+ */
+ public void addNode(Node node) {
+ nodeMap.put(node.getId(), node);
+ }
+
+ /**
+ * Add the given way.
+ *
+ * @param way The osm way.
+ */
+ public void addWay(Way way) {
+ wayMap.put(way.getId(), way);
+ }
+
+ /**
+ * Add the given relation.
+ *
+ * @param rel The osm relation.
+ */
+ public void addRelation(Relation rel) {
+ if (!ignoreBuiltinRelations) {
+ String type = rel.getTag("type");
+ if (type == null) {
+ } else if ("multipolygon".equals(type) || "boundary".equals(type)) {
+ rel = createMultiPolyRelation(rel);
+ } else if("restriction".equals(type)) {
+ if (ignoreTurnRestrictions)
+ rel = null;
+ else if (rel.getTag("restriction") == null)
+ log.warn("ignoring unspecified restriction " + rel.toBrowseURL());
+ else
+ rel = new RestrictionRelation(rel);
+ }
+ }
+
+ if(rel != null) {
+ long id = rel.getId();
+ relationMap.put(rel.getId(), rel);
+
+ rel.processElements();
+
+ List<Map.Entry<String,Relation>> entries = deferredRelationMap.remove(id);
+ if (entries != null)
+ for (Map.Entry<String,Relation> entry : entries)
+ entry.getValue().addElement(entry.getKey(), rel);
+ }
+ }
+
+ /**
+ * Create a multipolygon relation. Has to be here as they use shared maps.
+ * Would like to change how the constructor works so that was not needed.
+ * @param rel The original relation, that the result will replace.
+ * @return A new multi polygon relation, based on the input relation.
+ */
+ public Relation createMultiPolyRelation(Relation rel) {
+ return new MultiPolygonRelation(rel, wayMap, getBoundingBox());
+ }
+
+ public SeaPolygonRelation createSeaPolyRelation(Relation rel) {
+ return new SeaPolygonRelation(rel, wayMap, getBoundingBox());
+ }
+
+ public void setBoundingBox(Area bbox) {
+ boundingBox = bbox;
+ }
+
+ public Coord getCoord(long id) {
+ return coordMap.get(id);
+ }
+
+ public Node getNode(long id) {
+ return nodeMap.get(id);
+ }
+
+ public Way getWay(long id) {
+ return wayMap.get(id);
+ }
+
+ public Relation getRelation(long id) {
+ return relationMap.get(id);
+ }
+
+ public void finishLoading() {
+ coordMap = null;
+ }
+
+ /**
+ * After the input file is read, this is called to convert the saved information
+ * into the general intermediate format.
+ *
+ * @param converter The Converter to use.
+ */
+ public void convert(OsmConverter converter) {
+
+ // We only do this if an explicit bounding box was given.
+ if (boundingBox != null)
+ makeBoundaryNodes();
+
+ converter.setBoundingBox(getBoundingBox());
+
+ for (Relation r : relationMap.values())
+ converter.convertRelation(r);
+
+ for (Node n : nodeMap.values()){
+ converter.convertNode(n);
+ if (n.getTag("fixme") != null || n.getTag("FIXME") != null){
+ n.getLocation().setFixme(true);
+ }
+ }
+
+ nodeMap = null;
+
+ Iterator<Way> wayIter = wayMap.values().iterator();
+ while (wayIter.hasNext()){
+ Way way = wayIter.next();
+ converter.convertWay(way);
+ wayIter.remove();
+ }
+ wayMap = null;
+
+ converter.end();
+
+ relationMap = null;
+ deferredRelationMap.clear();
+ }
+
+ /**
+ *
+ * "soft clip" each way that crosses a boundary by adding a point
+ * at each place where it meets the boundary
+ */
+ private void makeBoundaryNodes() {
+ log.info("Making boundary nodes");
+ int numBoundaryNodesDetected = 0;
+ int numBoundaryNodesAdded = 0;
+ for(Way way : wayMap.values()) {
+ List<Coord> points = way.getPoints();
+
+ // clip each segment in the way against the bounding box
+ // to find the positions of the boundary nodes - loop runs
+ // backwards so we can safely insert points into way
+ for (int i = points.size() - 1; i >= 1; --i) {
+ Coord[] pair = { points.get(i - 1), points.get(i) };
+ Coord[] clippedPair = LineClipper.clip(getBoundingBox(), pair, true);
+ // we're only interested in segments that touch the
+ // boundary
+ if (clippedPair != null) {
+ // the segment touches the boundary or is
+ // completely inside the bounding box
+ if (clippedPair[1] != points.get(i)) {
+ // the second point in the segment is outside
+ // of the boundary
+ assert clippedPair[1].getOnBoundary();
+ // insert boundary point before the second point
+ points.add(i, clippedPair[1]);
+ ++numBoundaryNodesAdded;
+ } else if(clippedPair[1].getOnBoundary())
+ ++numBoundaryNodesDetected;
+
+
+ if (clippedPair[0] != points.get(i - 1)) {
+ // the first point in the segment is outside
+ // of the boundary
+ assert clippedPair[0].getOnBoundary();
+ // insert boundary point after the first point
+ points.add(i, clippedPair[0]);
+ ++numBoundaryNodesAdded;
+ } else if (clippedPair[0].getOnBoundary())
+ ++numBoundaryNodesDetected;
+ }
+ }
+ }
+
+ log.info("Making boundary nodes - finished (" + numBoundaryNodesAdded + " added, " + numBoundaryNodesDetected + " detected)");
+ }
+
+ public Map<Long, Node> getNodes() {
+ return nodeMap;
+ }
+
+ public Map<Long, Way> getWays() {
+ return wayMap;
+ }
+
+ public Map<Long, Relation> getRelations() {
+ return relationMap;
+ }
+
+ /**
+ * Get the bounding box. This is either the one that was explicitly included in the input
+ * file, or if none was given, the calculated one.
+ */
+ public Area getBoundingBox() {
+ if (boundingBox != null) {
+ return boundingBox;
+ } else if (minLat == Utils.toMapUnit(180.0) && maxLat == Utils.toMapUnit(-180.0)) {
+ return new Area(0, 0, 0, 0);
+ } else {
+ return new Area(minLat, minLon, maxLat, maxLon);
+ }
+ }
+
+ public void deferRelation(long id, Relation rel, String role) {
+ // The relation may be defined later in the input.
+ // Defer the lookup.
+ Map.Entry<String,Relation> entry =
+ new AbstractMap.SimpleEntry<String,Relation>(role, rel);
+
+ List<Map.Entry<String,Relation>> entries = deferredRelationMap.get(id);
+ if (entries == null) {
+ entries = new ArrayList<Map.Entry<String,Relation>>();
+ deferredRelationMap.put(id, entries);
+ }
+
+ entries.add(entry);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/FakeIdGenerator.java b/src/uk/me/parabola/mkgmap/reader/osm/FakeIdGenerator.java
new file mode 100644
index 0000000..2ea1a7a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/FakeIdGenerator.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010-2012.
+ *
+ * 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.reader.osm;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+public class FakeIdGenerator {
+
+ private static final long START_ID = 1L << 62;
+
+ private static final AtomicLong fakeId = new AtomicLong(START_ID);
+
+ private static long startId = START_ID;
+
+ /**
+ * Change the first id that is returned by this generator. The method must
+ * be called <b>before</b> the first call of {@link #makeFakeId()}.
+ * @param firstFakeId the first id returned by this generator
+ */
+ public static void setStartId(long firstFakeId) {
+ fakeId.set(firstFakeId);
+ startId = firstFakeId;
+ }
+
+ /**
+ * Retrieves a unique id that can be used to fake OSM ids.
+ *
+ * @return a unique id
+ */
+ public static long makeFakeId() {
+ return fakeId.incrementAndGet();
+ }
+
+ public static boolean isFakeId(long id) {
+ return id >= startId;
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/FeatureKind.java b/src/uk/me/parabola/mkgmap/reader/osm/FeatureKind.java
new file mode 100644
index 0000000..d33c0fc
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/FeatureKind.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.reader.osm;
+
+/**
+ * Used to classify objects into points, lines, etc.
+ *
+ * @author Steve Ratcliffe
+ */
+public enum FeatureKind {
+ POINT,
+ POLYLINE,
+ POLYGON,
+
+ // These are not really feature kinds, as there is no corresponding Garmin object.
+ RELATION,
+ ALL,
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/GType.java b/src/uk/me/parabola/mkgmap/reader/osm/GType.java
new file mode 100644
index 0000000..d515446
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/GType.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2009.
+ *
+ * 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.
+ *
+ * Created: 13 Sep 2009
+ * By: steve
+ */
+
+package uk.me.parabola.mkgmap.reader.osm;
+
+import java.util.Formatter;
+
+import uk.me.parabola.imgfmt.ExitException;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.LevelInfo;
+
+/**
+ * Holds the garmin type of an element and all the information that
+ * will be needed to represent it on the map. So we have a range of
+ * resolutions at which it will be present.
+ */
+public class GType {
+ private static final Logger log = Logger.getLogger(GType.class);
+
+ private final FeatureKind featureKind;
+ private final int type;
+
+ private int minResolution = 24;
+ private int maxResolution = 24;
+
+ private int maxLevel = -1;
+ private int minLevel;
+
+ private String defaultName;
+
+ // road class and speed will be set on roads.
+ private int roadClass;
+ private int roadSpeed;
+
+ private boolean road;
+
+ /** If this is set, then we look for further types after this one is matched */
+ private boolean continueSearch;
+
+ // by default, a rule's actions are skipped when searching for
+ // further rules to match - by setting this true, the rule's
+ // actions will always be executed
+ private boolean propogateActionsOnContinue;
+
+ public static boolean checkType(FeatureKind featureKind, int type) {
+ if (type >= 0x010000){
+ if ((type & 0xff) > 0x1f)
+ return false;
+ } else {
+ if (featureKind == FeatureKind.POLYLINE && type > 0x3f)
+ return false;
+ else if (featureKind == FeatureKind.POLYGON && (type> 0x7f || type == 0x4a))
+ return false;
+ else if (featureKind == FeatureKind.POINT){
+ if (type < 0x0100 || (type & 0x00ff) > 0x1f)
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public GType(FeatureKind featureKind, String type) {
+ this.featureKind = featureKind;
+ try {
+ int t = Integer.decode(type);
+ if (featureKind == FeatureKind.POLYGON){
+ // allow 0xYY00 instead of 0xYY
+ if (t >= 0x100 && t < 0x10000 && (t & 0xff) == 0)
+ t >>= 8;
+ }
+ this.type = t;
+ } catch (NumberFormatException e) {
+ log.error("not numeric " + type);
+ throw new ExitException("non-numeric type in style file");
+ }
+ }
+
+ public GType(GType other) {
+ this.continueSearch = other.continueSearch;
+ this.defaultName = other.defaultName;
+ this.featureKind = other.featureKind;
+ this.maxLevel = other.maxLevel;
+ this.maxResolution = other.maxResolution;
+ this.minLevel = other.minLevel;
+ this.minResolution = other.minResolution;
+ this.propogateActionsOnContinue = other.propogateActionsOnContinue;
+ this.road = other.road;
+ this.roadClass = other.roadClass;
+ this.roadSpeed = other.roadSpeed;
+ this.type = other.type;
+ }
+
+ /**
+ * Copy all attributes and replace type to a non-routable one.
+ * @param other
+ * @param nonRoutableType
+ */
+ public GType(GType other, String nonRoutableType) {
+ assert other.featureKind == FeatureKind.POLYLINE;
+
+ this.continueSearch = other.continueSearch;
+ this.defaultName = other.defaultName;
+ this.featureKind = other.featureKind;
+ this.maxLevel = other.maxLevel;
+ this.maxResolution = other.maxResolution;
+ this.minLevel = other.minLevel;
+ this.minResolution = other.minResolution;
+ this.propogateActionsOnContinue = other.propogateActionsOnContinue;
+ this.road = false;
+ try {
+ this.type = Integer.decode(nonRoutableType);
+ } catch (NumberFormatException e) {
+ log.error("not numeric " + nonRoutableType);
+ throw new ExitException("non-numeric type in style file");
+ }
+ }
+
+ public FeatureKind getFeatureKind() {
+ return featureKind;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public int getMinResolution() {
+ return minResolution;
+ }
+
+ public void setMinResolution(int minResolution) {
+ this.minResolution = minResolution;
+ }
+
+ public int getMaxResolution() {
+ return maxResolution;
+ }
+
+ public void setMaxResolution(int maxResolution) {
+ this.maxResolution = maxResolution;
+ }
+
+ public String getDefaultName() {
+ return defaultName;
+ }
+
+ public void setDefaultName(String defaultName) {
+ this.defaultName = defaultName;
+ }
+
+ /**
+ * Set minLevel and maxLevel based on the resolution values set and
+ * the given levels info. We do this because we used to work only
+ * on resolution, but we want to move more towards working with
+ * levels.
+ */
+ public void fixLevels(LevelInfo[] levels) {
+ for (LevelInfo info : levels) {
+ if (info.getBits() <= minResolution)
+ maxLevel = info.getLevel();
+ if (info.getBits() <= maxResolution)
+ minLevel = info.getLevel();
+ }
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ Formatter fmt = new Formatter(sb);
+ sb.append('[');
+ fmt.format("%#x", type);
+ if (maxLevel == -1) {
+ if (maxResolution == 24)
+ fmt.format(" resolution %d", minResolution);
+ else
+ fmt.format(" resolution %d-%d", maxResolution, minResolution);
+ } else {
+ if (minLevel == 0)
+ fmt.format(" level %d", maxLevel);
+ else
+ fmt.format(" level %d-%d", minLevel, maxLevel);
+ }
+ if (road)
+ fmt.format(" road_class=%d road_speed=%d", roadClass, roadSpeed);
+
+ if (continueSearch)
+ fmt.format(" continue");
+ if (propogateActionsOnContinue)
+ fmt.format(" propagate");
+ sb.append(']');
+ return sb.toString();
+ }
+
+ public int getMinLevel() {
+ return minLevel;
+ }
+
+ public int getMaxLevel() {
+ return maxLevel;
+ }
+
+ public int getRoadClass() {
+ return roadClass;
+ }
+
+ public void setRoadClass(int roadClass) {
+ // road class might also be set for nodes used by the link-pois-to-ways option
+ if (getFeatureKind() == FeatureKind.POLYLINE)
+ road = true;
+ this.roadClass = roadClass;
+ }
+
+ public int getRoadSpeed() {
+ return roadSpeed;
+ }
+
+ public void setRoadSpeed(int roadSpeed) {
+ // road speed might also be set for nodes used by the link-pois-to-ways option
+ if (getFeatureKind() == FeatureKind.POLYLINE)
+ road = true;
+ this.roadSpeed = roadSpeed;
+ }
+
+ public boolean isRoad() {
+ return road;
+ }
+
+ public boolean isContinueSearch() {
+ return continueSearch;
+ }
+
+ public void propagateActions(boolean propagate) {
+ propogateActionsOnContinue = propagate;
+ }
+
+ public boolean isPropogateActions() {
+ return !continueSearch || propogateActionsOnContinue;
+ }
+
+ public void setContinueSearch(boolean continueSearch) {
+ this.continueSearch = continueSearch;
+ }
+
+ /**
+ *
+ * @param type the type value
+ * @return true if the type is known as routable.
+ */
+ public static boolean isRoutableLineType(int type){
+ return type >= 0x01 && type <= 0x13 || type == 0x1a || type == 0x1b || type == 0x16;
+ }
+
+ /**
+ * Return a type value in the commonly used hex format
+ * @param type the integer value
+ * @return a hex string with even number of digits
+ */
+ public static String formatType(int type){
+ String s = String.format("%x", type);
+ return (s.length() % 2 != 0 ? "0x0":"0x") + s;
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/GeneralRelation.java b/src/uk/me/parabola/mkgmap/reader/osm/GeneralRelation.java
new file mode 100644
index 0000000..c53e705
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/GeneralRelation.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 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: 23-Nov-2008
+ */
+package uk.me.parabola.mkgmap.reader.osm;
+
+/**
+ * A relation to use when no special treatment is required, or when the
+ * relation type is not recognised.
+ *
+ * @author Steve Ratcliffe
+ */
+public class GeneralRelation extends Relation {
+ public GeneralRelation(long id) {
+ setId(id);
+ }
+
+ public void processElements() {
+ // Nothing to do
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/HighwayHooks.java b/src/uk/me/parabola/mkgmap/reader/osm/HighwayHooks.java
new file mode 100644
index 0000000..374a0a2
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/HighwayHooks.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2010 - 2012.
+ *
+ * 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.reader.osm;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.Exit;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * Operations mostly on highways that have to be performed during reading
+ * the OSM input file.
+ *
+ * Some of this would be much better done in a style file or by extending the style system.
+ */
+public class HighwayHooks extends OsmReadingHooksAdaptor {
+ private static final Logger log = Logger.getLogger(HighwayHooks.class);
+
+ private static final long CYCLEWAY_ID_OFFSET = 0x10000000;
+
+ private final List<Way> motorways = new ArrayList<Way>();
+ private final List<Node> exits = new ArrayList<Node>();
+
+ private boolean makeOppositeCycleways;
+ private boolean makeCycleways;
+ private ElementSaver saver;
+ private boolean linkPOIsToWays;
+
+ private Node currentNodeInWay;
+
+
+ private final Set<String> usedTags = new HashSet<String>() {
+ {
+ add("highway");
+ add("access");
+ add("barrier");
+ add("FIXME");
+ add("fixme");
+ add("route");
+ add("oneway");
+ add("junction");
+ add("name");
+ add(Exit.TAG_ROAD_REF);
+ add("ref");
+
+// the following two tags are only added if the cycleway options are set
+// add("cycleway");
+// add("bicycle");
+ }
+ };
+
+ public boolean init(ElementSaver saver, EnhancedProperties props) {
+ this.saver = saver;
+ if(props.getProperty("make-all-cycleways", false)) {
+ makeOppositeCycleways = makeCycleways = true;
+ }
+ else {
+ makeOppositeCycleways = props.getProperty("make-opposite-cycleways", false);
+ makeCycleways = props.getProperty("make-cycleways", false);
+ }
+ linkPOIsToWays = props.getProperty("link-pois-to-ways", false);
+ currentNodeInWay = null;
+
+ if (makeCycleways || makeOppositeCycleways) {
+ // need the additional two tags
+ usedTags.add("cycleway");
+ usedTags.add("bicycle");
+ }
+
+ // add addr:street and addr:housenumber if housenumber search is enabled
+ if (props.getProperty("housenumbers", false)) {
+ usedTags.add("addr:street");
+ usedTags.add("addr:housenumber");
+ }
+
+ return true;
+ }
+
+
+ public Set<String> getUsedTags() {
+ return usedTags;
+ }
+
+ public void onAddNode(Node node) {
+ String val = node.getTag("highway");
+ if (val != null && (val.equals("motorway_junction") || val.equals("services"))) {
+ exits.add(node);
+ node.addTag("mkgmap:osmid", String.valueOf(node.getId()));
+ }
+ }
+
+ public void onCoordAddedToWay(Way way, long id, Coord co) {
+ currentNodeInWay = saver.getNode(id);
+
+ if (linkPOIsToWays) {
+ // if this Coord is also a POI, replace it with an
+ // equivalent CoordPOI that contains a reference to
+ // the POI's Node so we can access the POI's tags
+ if (!(co instanceof CoordPOI) && currentNodeInWay != null) {
+ // for now, only do this for nodes that have
+ // certain tags otherwise we will end up creating
+ // a CoordPOI for every node in the way
+ final String[] coordPOITags = { "access", "barrier", "highway" };
+ for (String cpt : coordPOITags) {
+ if (currentNodeInWay.getTag(cpt) != null) {
+ // the POI has one of the approved tags so
+ // replace the Coord with a CoordPOI
+ CoordPOI cp = new CoordPOI(co.getLatitude(), co.getLongitude());
+ saver.addPoint(id, cp);
+
+ // we also have to jump through hoops to
+ // make a new version of Node because we
+ // can't replace the Coord that defines
+ // its location
+ Node newNode = new Node(id, cp);
+ newNode.copyTags(currentNodeInWay);
+ saver.addNode(newNode);
+ // tell the CoordPOI what node it's
+ // associated with
+ cp.setNode(newNode);
+ co = cp;
+ // if original node is in exits, replace it
+ if (exits.remove(currentNodeInWay))
+ exits.add(newNode);
+ currentNodeInWay = newNode;
+ break;
+ }
+ }
+ }
+
+ if (co instanceof CoordPOI) {
+ // flag this Way as having a CoordPOI so it
+ // will be processed later
+ way.addTag("mkgmap:way-has-pois", "true");
+ if (log.isInfoEnabled())
+ log.info("Linking POI", currentNodeInWay.toBrowseURL(), "to way at", co.toOSMURL());
+ }
+ }
+ }
+
+ public void onAddWay(Way way) {
+ String highway = way.getTag("highway");
+ if (highway != null || "ferry".equals(way.getTag("route"))) {
+ boolean oneway = way.isBoolTag("oneway");
+
+ // if the way is a roundabout but isn't already
+ // flagged as "oneway", flag it here
+ if ("roundabout".equals(way.getTag("junction"))) {
+ if (way.getTag("oneway") == null) {
+ way.addTag("oneway", "yes");
+ }
+
+ }
+
+ String cycleway = way.getTag("cycleway");
+ if (makeOppositeCycleways && cycleway != null && !"cycleway".equals(highway) && oneway &&
+ ("opposite".equals(cycleway) ||
+ "opposite_lane".equals(cycleway) ||
+ "opposite_track".equals(cycleway)))
+ {
+ // what we have here is a oneway street
+ // that allows bicycle traffic in both
+ // directions -- to enable bicycle routing
+ // in the reverse direction, we synthesise
+ // a cycleway that has the same points as
+ // the original way
+ Way cycleWay = makeCycleWay(way);
+ cycleWay.addTag("oneway", "no");
+
+ } else if (makeCycleways && cycleway != null && !"cycleway".equals(highway) &&
+ ("track".equals(cycleway) ||
+ "lane".equals(cycleway) ||
+ "both".equals(cycleway) ||
+ "left".equals(cycleway) ||
+ "right".equals(cycleway)))
+ {
+ // what we have here is a highway with a
+ // separate track for cycles -- to enable
+ // bicycle routing, we synthesise a cycleway
+ // that has the same points as the original
+ // way
+ makeCycleWay(way);
+ if (way.getTag("bicycle") == null)
+ way.addTag("bicycle", "no");
+ }
+ }
+
+ if("motorway".equals(highway) || "trunk".equals(highway))
+ motorways.add(way);
+ }
+
+ /**
+ * Construct a cycleway that has the same points as an existing way. Used for separate
+ * cycle lanes.
+ * @param way The original way.
+ * @return The new way, which will have the same points and have suitable cycle tags.
+ */
+ private Way makeCycleWay(Way way) {
+ long cycleWayId = way.getId() + CYCLEWAY_ID_OFFSET;
+ Way cycleWay = new Way(cycleWayId);
+ saver.addWay(cycleWay);
+
+ // this reverses the direction of the way but
+ // that isn't really necessary as the cycleway
+ // isn't tagged as oneway
+ List<Coord> points = way.getPoints();
+ //for (int i = points.size() - 1; i >= 0; --i)
+ // cycleWay.addPoint(points.get(i));
+ for (Coord point : points)
+ cycleWay.addPoint(point);
+
+ cycleWay.copyTags(way);
+
+ String name = way.getTag("name");
+ if(name != null)
+ name += " (cycleway)";
+ else
+ name = "cycleway";
+ cycleWay.addTag("name", name);
+ cycleWay.addTag("access", "no");
+ cycleWay.addTag("bicycle", "yes");
+ cycleWay.addTag("foot", "no");
+ cycleWay.addTag("mkgmap:synthesised", "yes");
+
+ return cycleWay;
+ }
+
+ public void end() {
+ finishExits();
+ exits.clear();
+ motorways.clear();
+ }
+
+ private void finishExits() {
+ for (Node e : exits) {
+ String refTag = Exit.TAG_ROAD_REF;
+ if (e.getTag(refTag) == null) {
+ String exitName = e.getTag("name");
+ if (exitName == null)
+ exitName = e.getTag("ref");
+
+ String ref = null;
+ Way motorway = null;
+ for (Way w : motorways) {
+ if (w.getPoints().contains(e.getLocation())) {
+ motorway = w;
+ ref = w.getTag("ref");
+ if(ref != null)
+ break;
+ }
+ }
+
+ if (ref != null) {
+ log.info("Adding", refTag + "=" + ref, "to exit", exitName);
+ e.addTag(refTag, ref);
+ } else if(motorway != null) {
+ log.warn("Motorway exit", exitName, "is positioned on a motorway that doesn't have a 'ref' tag (" + e.getLocation().toOSMURL() + ")");
+ }
+ }
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/LinkDestinationHook.java b/src/uk/me/parabola/mkgmap/reader/osm/LinkDestinationHook.java
new file mode 100644
index 0000000..3352de7
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/LinkDestinationHook.java
@@ -0,0 +1,737 @@
+/*
+ * Copyright (C) 2012
+ *
+ * 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.reader.osm;
+
+import java.util.AbstractMap;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Queue;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.build.LocatorUtil;
+import uk.me.parabola.mkgmap.osmstyle.function.LengthFunction;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * Copies the destination tag from motorway_link and trunk_link ways to the
+ * first adjacent non link way so that the Garmin is able to display a valid
+ * destination.
+ * @author WanMil
+ */
+public class LinkDestinationHook extends OsmReadingHooksAdaptor {
+ private static final Logger log = Logger.getLogger(LinkDestinationHook.class);
+
+ private ElementSaver saver;
+
+ /** Maps which ways can be driven from a given Coord */
+ private IdentityHashMap<Coord, Set<Way>> adjacentWays = new IdentityHashMap<Coord, Set<Way>>();
+ /** Contains all _link ways that have to be processed */
+ private Map<Long, Way> destinationLinkWays = new HashMap<Long, Way>();
+
+ private HashSet<String> tagValues = new HashSet<String>(Arrays.asList(
+ "motorway_link", "trunk_link"));
+
+ private List<String> nameTags;
+
+ /** Maps which nodes contains to which ways */
+ private IdentityHashMap<Coord, Set<Way>> wayNodes = new IdentityHashMap<Coord, Set<Way>>();
+
+ private boolean processDestinations;
+ private boolean processExits;
+
+ public boolean init(ElementSaver saver, EnhancedProperties props) {
+ this.saver = saver;
+ nameTags = LocatorUtil.getNameTags(props);
+ processDestinations = props.containsKey("process-destination");
+ processExits = props.containsKey("process-exits");
+ return processDestinations || processExits;
+ }
+
+ /**
+ * Fills the internal lists with the
+ */
+ private void retrieveWays() {
+ // collect all ways tagged with highway
+ for (Way w : saver.getWays().values()) {
+ if (w.getPoints().size() < 2) {
+ // ignore one-node or zero-node ways
+ continue;
+ }
+ String highwayTag = w.getTag("highway");
+ if (highwayTag != null) {
+ // the points of the way are kept so that it is easy to get
+ // the adjacent ways for a given _link way
+ String directedDestination = null;
+ List<Coord> points;
+ if (isOnewayInDirection(w)) {
+ // oneway => don't need the last point because the
+ // way cannot be driven standing at the last point
+ points = w.getPoints().subList(0, w.getPoints().size() - 1);
+ directedDestination = w.getTag("direction:forward");
+ } else if (isOnewayOppositeDirection(w)) {
+ // reverse oneway => don't need the first point because the
+ // way cannot be driven standing at the first point
+ points = w.getPoints().subList(1, w.getPoints().size());
+ directedDestination = w.getTag("direction:backward");
+ } else {
+ points = w.getPoints();
+ }
+ for (Coord c : points) {
+ Set<Way> ways = adjacentWays.get(c);
+ if (ways == null) {
+ ways = new HashSet<Way>(4);
+ adjacentWays.put(c, ways);
+ }
+ ways.add(w);
+ }
+ registerPointsOfWay(w);
+
+ // if the way is a link way and has a destination tag
+ // put it the list of ways that have to be processed
+ if (tagValues.contains(highwayTag)) {
+ String destinationTag = w.getTag("destination");
+
+ if (destinationTag == null) {
+ // destination is not set
+ // => check if destination:lanes is without any lane specific information (no |)
+ String destLanesTag = w.getTag("destination:lanes");
+ if (destLanesTag != null && destLanesTag.contains("|") == false) {
+ // the destination:lanes tag contains no | => no lane specific information
+ // use this tag as destination tag
+ w.addTag("destination", destLanesTag);
+ destinationTag = destLanesTag;
+ if (log.isDebugEnabled())
+ log.debug("Use destination:lanes tag as destination tag because there is one lane information only. Way ",w.getId(),w.toTagString());
+ }
+ }
+
+ if (destinationTag == null) {
+ // use the destination:forward or :backward value
+ destinationTag = directedDestination;
+ }
+
+ if (destinationTag != null)
+ destinationLinkWays.put(w.getId(), w);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Registers the points of the given way for the internal data structures.
+ * @param w a new way
+ */
+ private void registerPointsOfWay(Way w) {
+ for (Coord c : w.getPoints()) {
+ Set<Way> ways = wayNodes.get(c);
+ if (ways == null) {
+ ways = new HashSet<Way>(4);
+ wayNodes.put(c, ways);
+ }
+ ways.add(w);
+ }
+ }
+
+ /**
+ * Removes the points in range from to to from the way and the internal data structures.
+ * @param w way
+ * @param from first point to remove
+ * @param to range end to remove (exclusive)
+ */
+ private void removePointsFromWay(Way w, int from, int to) {
+ // first remove them from the wayNodes map
+ for (Coord c : w.getPoints().subList(from, to)) {
+ wayNodes.get(c).remove(w);
+ }
+ // second remove them from the way
+ w.getPoints().subList(from, to).clear();
+
+ }
+
+ /**
+ * Retrieves the name of the given element based on the name-tag-list option.
+ * @param e an OSM element
+ * @return the name or <code>null</code> if the element has no name
+ */
+ private String getName(Element e) {
+ if (e.getName()!= null) {
+ return e.getName();
+ }
+ for (String nameTag : nameTags) {
+ String nameTagVal = e.getTag(nameTag);
+ if (nameTagVal != null) {
+ return nameTagVal;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Cuts off at least minLength meter of the given way and returns the cut off way tagged
+ * identical to the given way.
+ * @param w the way to be cut
+ * @param maxLength the cut off way is no longer than this value
+ * @return the cut off way or <code>null</code> if cutting not possible
+ */
+ private Way cutoffWay(Way w, double cutLength, double maxLength, Coord c1, Coord c2) {
+ if (w.getPoints().size()<2) {
+ return null;
+ }
+
+ if (w.getPoints().size() >= 3) {
+ // try to use existing points - that does not deform the way
+ Coord firstPoint = w.getPoints().get(0);
+ Coord cutPoint = w.getPoints().get(1);
+
+ // check if the maxLength is not exceeded
+ double dist = firstPoint.distance(cutPoint);
+ if (dist <= maxLength) {
+ // create a new way with the first two points and identical tags
+ Way precedingWay = new Way(FakeIdGenerator.makeFakeId(), w
+ .getPoints().subList(0, 1 + 1));
+ precedingWay.copyTags(w);
+
+ saver.addWay(precedingWay);
+ // remove the points of the new way from the original way
+ removePointsFromWay(w, 0, 1);
+
+ registerPointsOfWay(precedingWay);
+
+ log.debug("Cut way", w, "at existing point 1. New way:",
+ precedingWay);
+
+ // return the new way
+ return precedingWay;
+ } else {
+ log.debug("Cannot cut way", w,
+ "on existing nodes because the first distance is too big:", dist);
+ }
+ }
+
+ double startSegmentLength = 0;
+
+ Coord lastC = w.getPoints().get(0);
+ for (int i = 1; i < w.getPoints().size(); i++) {
+ Coord c = w.getPoints().get(i);
+ double segmentLength = lastC.distance(c);
+
+ if (startSegmentLength + segmentLength >= cutLength) {
+ double frac = (cutLength - startSegmentLength) / segmentLength;
+ // insert a new point at the minimum distance
+ Coord cConnection = lastC.makeBetweenPoint(c, frac);
+
+ if (c1 != null && c2 != null && cConnection != null) {
+ // test if the way using the new point still uses the same
+ // orientation to the main motorway
+ double oldAngle = getAngle(c1, c2, c);
+ double newAngle = getAngle(c1, c2, cConnection);
+ if (Math.signum(oldAngle) != Math.signum(newAngle)) {
+ double bestAngleDiff = 180.0d;
+ Coord bestCoord = cConnection;
+ for (Coord cNeighbour : getDirectNeighbours(cConnection)) {
+ double neighbourAngle = getAngle(c1, c2, cNeighbour);
+ if (Math.signum(oldAngle) == Math.signum(neighbourAngle) &&
+ Math.abs(oldAngle - neighbourAngle) < bestAngleDiff) {
+ bestAngleDiff = Math.abs(oldAngle - neighbourAngle);
+ bestCoord = cNeighbour;
+ }
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("Changed orientation:", oldAngle, "to",
+ newAngle);
+ log.debug("on Link", w);
+ log.debug("Corrected coord ", cConnection, "to",
+ bestCoord);
+ }
+ cConnection = bestCoord;
+ }
+ }
+
+ // create the new way with identical tags
+ w.getPoints().add(i,cConnection);
+ Way precedingWay = new Way(FakeIdGenerator.makeFakeId(), new ArrayList<Coord>(w.getPoints().subList(0, i+1)));
+ precedingWay.copyTags(w);
+
+ saver.addWay(precedingWay);
+
+ // remove the points of the new way from the old way
+ removePointsFromWay(w, 0, i);
+ registerPointsOfWay(precedingWay);
+
+ // return the split way
+ return precedingWay;
+ }
+ lastC = c;
+ }
+
+ // way too short
+ return null;
+ }
+
+ /**
+ * Retrieve a list of all Coords that are the direct neighbours of
+ * the given Coord. A neighbours latitude and longitude does not differ
+ * more than one Garmin unit from the given Coord.
+ * @param c the Coord for which the neighbours should be retrieved.
+ * @return all neighbours of c
+ */
+ private List<Coord> getDirectNeighbours(Coord c) {
+ List<Coord> neighbours = new ArrayList<Coord>(8);
+ for (int dLat = -1; dLat<2; dLat++) {
+ for (int dLon = -1; dLon < 2; dLon++) {
+ if (dLat == 0 && dLon == 0) {
+ continue;
+ }
+ neighbours.add(new Coord(c.getLatitude()+dLat, c.getLongitude()+dLon));
+ }
+ }
+ return neighbours;
+ }
+
+ /**
+ * Retrieves if the given node is tagged as motorway exit. So it must contain at least the tags
+ * highway=motorway_junction and one of the tags ref, name or exit_to.
+ * @param node the node to check
+ * @return <code>true</code> the node is a motorway exit, <code>false</code> the node is not a
+ * motorway exit
+ */
+ private boolean isTaggedAsExit(Node node) {
+ if ("motorway_junction".equals(node.getTag("highway")) == false) {
+ return false;
+ }
+ return node.getTag("ref") != null ||
+ (getName(node) != null) ||
+ node.getTag("exit_to") != null;
+ }
+
+ /**
+ * Retrieve all nodes that are connected to the given node either in
+ * driving direction or reverse.
+ * @param node a coord
+ * @param drivingDirection <code>true</code> driving direction; <code>false</code> reverse direction
+ * @return a list of all coords an the connection ways
+ */
+ private List<Entry<Coord, Way>> getNextNodes(Coord node, boolean drivingDirection) {
+ List<Entry<Coord, Way>> nextNodes = new ArrayList<Entry<Coord, Way>>();
+
+ Set<Way> connectedWays = wayNodes.get(node);
+ for (Way w : connectedWays) {
+ // get the index of the node
+ int index = w.getPoints().indexOf(node);
+ if (index < 0) {
+ // this should not happen
+ log.error("Cannot find node "+node+" in way "+w);
+ continue;
+ }
+
+ boolean oneWayDirection = isOnewayInDirection(w);
+ // calc the index of the next node
+ index += (drivingDirection ? 1 : -1) * (oneWayDirection ? 1 : -1);
+
+ if (index >= 0 && index < w.getPoints().size()) {
+ nextNodes.add(new AbstractMap.SimpleEntry<Coord, Way>(w.getPoints().get(index), w));
+ }
+ }
+
+ return nextNodes;
+ }
+
+ /**
+ * Cuts motorway_link and trunk_link ways into three parts to be able to get
+ * a hint on Garmin GPS. This happens if the the option process-exits is set
+ * and the way is connected to an exit node (highway=motorway_junction)
+ * and/or the option process-destination is set and the destination tag is
+ * set. The mid part way is tagged additionally with the following tags:
+ * <ul>
+ * <li>mkgmap:dest_hint=true (for destinations)</li>
+ * <li>mkgmap:exit_hint=true (for exits)</li>
+ * <li>mkgmap:exit_hint_ref: Tagged with the ref tag value of the motorway
+ * junction node</li>
+ * <li>mkgmap:exit_hint_exit_to: Tagged with the exit_to tag value of the
+ * motorway junction node</li>
+ * <li>mkgmap:exit_hint_name: Tagged with the name tag value of the motorway
+ * junction node</li>
+ * </ul>
+ * Style implementors can use the common Garmin code 0x09 for motorway_links
+ * and any other routable id (except 0x08 and 0x09) for the links with
+ * mkgmap:exit_hint=true and/or mkgmap:dest_hint=true. The naming of this
+ * middle way can be typically assigned from destination, ref, destination:ref,
+ * mkgmap:exit_hint_ref, mkgmap:exit_hint_name and/or mkgmap:exit_hint_exit_to.
+ */
+ private void processWays() {
+ // collect all nodes of highway=motorway/trunk ways so that we can check if an exit node
+ // belongs to a motorway/trunk or is a "subexit" within a motorway/trunk junction
+ Set<Coord> motorwayCoords = new HashSet<Coord>();
+ Set<Coord> trunkCoords = new HashSet<Coord>();
+ for (Way w : saver.getWays().values()) {
+ String motorwayTag = w.getTag("highway");
+ if (motorwayTag != null) {
+ if (motorwayTag.equals("motorway"))
+ motorwayCoords.addAll(w.getPoints());
+ else if (motorwayTag.equals("trunk"))
+ trunkCoords.addAll(w.getPoints());
+ }
+ }
+
+
+ // remove the adjacent links from the destinationLinkWays list
+ // to avoid duplicate dest_hints
+ Queue<Way> linksWithDestination = new ArrayDeque<Way>();
+ linksWithDestination.addAll(destinationLinkWays.values());
+ log.debug(destinationLinkWays.size(),"links with destination tag");
+ while (linksWithDestination.isEmpty()== false) {
+ Way linkWay = linksWithDestination.poll();
+ String destination = linkWay.getTag("destination");
+
+ if (log.isDebugEnabled())
+ log.debug("Check way",linkWay.getId(),linkWay.toTagString());
+
+ // Retrieve all adjacent ways of the current link
+ Coord c = linkWay.getPoints().get(linkWay.getPoints().size()-1);
+ if (isOnewayOppositeDirection(linkWay)) {
+ c = linkWay.getPoints().get(0);
+ }
+
+ Set<Way> nextWays = adjacentWays.get(c);
+ if (nextWays != null) {
+ for (Way connectedWay : nextWays) {
+ String nextDest = connectedWay.getTag("destination");
+ if (log.isDebugEnabled())
+ log.debug("Followed by",connectedWay.getId(),connectedWay.toTagString());
+
+ // remove the way from destination handling only if both ways are connected with start/end points
+ // otherwise it is a crossroads and therefore both ways need to be handled
+ boolean startEndConnection = connectedWay.getPoints().isEmpty()==false && connectedWay.getPoints().get(0).equals(c);
+ if (startEndConnection && connectedWay.equals(linkWay) == false
+ && connectedWay.getTag("highway").endsWith("_link")
+ && destination.equals(nextDest)) {
+ // do not use this way because there is another link before that with the same destination
+ destinationLinkWays.remove(connectedWay.getId());
+ if (log.isDebugEnabled())
+ log.debug("Removed",connectedWay.getId(),connectedWay.toTagString());
+ }
+ }
+ }
+ }
+ log.debug(destinationLinkWays.size(),"links with destination tag after cleanup");
+
+ if (processExits) {
+ // get all nodes tagged with highway=motorway_junction
+ for (Node exitNode : saver.getNodes().values()) {
+ if (isTaggedAsExit(exitNode) && saver.getBoundingBox().contains(exitNode.getLocation())) {
+
+ boolean isMotorwayExit = motorwayCoords.contains(exitNode.getLocation());
+ boolean isTrunkExit = trunkCoords.contains(exitNode.getLocation());
+ boolean isHighwayExit = isMotorwayExit || isTrunkExit;
+ // use exits only if they are located on a motorway or trunk
+ if (isHighwayExit == false) {
+ if (log.isDebugEnabled())
+ log.debug("Skip non highway exit:", exitNode.toBrowseURL(), exitNode.toTagString());
+ continue;
+ }
+
+ // retrieve all ways with this exit node
+ Set<Way> exitWays = adjacentWays.get(exitNode.getLocation());
+ if (exitWays==null) {
+ log.debug("Exit node", exitNode, "has no connected ways. Skip it.");
+ continue;
+ }
+
+ // retrieve the next node on the highway to be able to check if
+ // the inserted node has the correct orientation
+ List<Entry<Coord, Way>> nextNodes = getNextNodes(exitNode.getLocation(), true);
+ Coord nextHighwayNode = null;
+ String expectedHighwayTag = (isMotorwayExit ? "motorway" : "trunk");
+ for (Entry<Coord, Way> nextNode : nextNodes) {
+ if (expectedHighwayTag.equals(nextNode.getValue().getTag("highway"))) {
+ nextHighwayNode = nextNode.getKey();
+ break;
+ }
+ }
+
+ // use link ways only
+ for (Way w : exitWays) {
+ destinationLinkWays.remove(w.getId());
+
+ if (isNotOneway(w)) {
+ log.warn("Ignore way",w,"because it is not oneway");
+ continue;
+ }
+
+ String highwayLinkTag = w.getTag("highway");
+ if (highwayLinkTag.endsWith("_link")) {
+ log.debug("Try to cut",highwayLinkTag, w, "into three parts for giving hint to exit", exitNode);
+
+ // calc the way length to decide how to cut the way
+ double wayLength = getLength(w);
+ if (wayLength < 10 && w.getPoints().size() < 3) {
+ log.info("Way", w, "is too short (", wayLength," m) to cut it into several pieces. Cannot place exit hint.");
+ continue;
+ }
+
+
+ // now create three parts:
+ // wayPart1: original tags only
+ // hintWay: original tags plus the mkgmap:exit_hint* tags
+ // w: rest of the original way
+
+ double cut1 = Math.min(wayLength/2,20.0);
+ double cut2 = Math.min(wayLength, 100);
+ Way wayPart1 = cutoffWay(w,cut1, cut2, exitNode.getLocation(), nextHighwayNode);
+ if (wayPart1 == null) {
+ log.info("Way", w, "is too short to cut at least ",cut1,"m from it. Cannot create exit hint.");
+ continue;
+ } else {
+ if (log.isDebugEnabled())
+ log.debug("Cut off way", wayPart1, wayPart1.toTagString());
+ }
+
+ Way hintWay = w;
+ if (wayLength > 50) {
+ hintWay = cutoffWay(w, 10.0, 50.0, exitNode.getLocation(), nextHighwayNode);
+ }
+ if (hintWay == null) {
+ log.info("Way", w, "is too short to cut at least 20m from it. Cannot create exit hint.");
+ } else {
+ hintWay.addTag("mkgmap:exit_hint", "true");
+
+ if (processDestinations && hintWay.getTag("destination") != null) {
+ hintWay.addTag("mkgmap:dest_hint", "true");
+ }
+ if (exitNode.getTag("ref") != null)
+ hintWay.addTag("mkgmap:exit_hint_ref", exitNode.getTag("ref"));
+ if (exitNode.getTag("exit_to") != null)
+ hintWay.addTag("mkgmap:exit_hint_exit_to", exitNode.getTag("exit_to"));
+ if (getName(exitNode) != null)
+ hintWay.addTag("mkgmap:exit_hint_name", getName(exitNode));
+
+ if (log.isInfoEnabled())
+ log.info("Cut off exit hint way", hintWay, hintWay.toTagString());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (processDestinations) {
+ // use link ways only
+ while (destinationLinkWays.isEmpty() == false) {
+ Way w = destinationLinkWays.values().iterator().next();
+ destinationLinkWays.remove(w.getId());
+
+ if (isNotOneway(w)) {
+ log.warn("Ignore way",w,"because it is not oneway");
+ continue;
+ }
+
+ String highwayLinkTag = w.getTag("highway");
+ if (highwayLinkTag.endsWith("_link")) {
+ log.debug("Try to cut",highwayLinkTag, w, "into three parts for giving hint");
+
+ Coord firstNode = w.getPoints().get(0);
+ Coord secondNode = w.getPoints().get(1);
+ // retrieve the next node on the highway to be able to check if
+ // the inserted node has the correct orientation
+ List<Entry<Coord, Way>> nextNodes = getNextNodes(firstNode, true);
+ Coord nextHighwayNode = null;
+ double angle = Double.MAX_VALUE;
+ for (Entry<Coord, Way> nextNode : nextNodes) {
+ if (nextNode.getValue().equals(w)) {
+ continue;
+ }
+ double thisAngle = getAngle(firstNode, secondNode, nextNode.getKey());
+ if (Math.abs(thisAngle) < angle) {
+ angle = Math.abs(thisAngle);
+ nextHighwayNode = nextNode.getKey();
+ }
+ }
+
+ // calc the way length to decide how to cut the way
+ double wayLength = getLength(w);
+ if (wayLength < 10) {
+ log.info("Way", w, "is too short (", wayLength," m) to cut it into several pieces. Cannot place destination hint.");
+ continue;
+ }
+
+ // now create three parts:
+ // wayPart1: original tags only
+ // hintWay: original tags plus the mkgmap:exit_hint* tags
+ // w: rest of the original way
+
+ double cut1 = Math.min(wayLength/2, 20.0);
+ double cut2 = Math.min(wayLength, 100);
+ Way wayPart1 = cutoffWay(w, cut1, cut2, firstNode, nextHighwayNode);
+ if (wayPart1 == null) {
+ log.info("Way", w, "is too short to cut at least 10m from it. Cannot create destination hint.");
+ continue;
+ } else {
+ if (log.isDebugEnabled())
+ log.debug("Cut off way", wayPart1, wayPart1.toTagString());
+ }
+
+ Way hintWay = w;
+ if (wayLength > 50) {
+ hintWay = cutoffWay(w, 10.0, 50.0, firstNode, nextHighwayNode);
+ }
+ if (hintWay == null) {
+ log.info("Way", w, "is too short to cut at least 20m from it. Cannot create destination hint.");
+ } else {
+ hintWay.addTag("mkgmap:dest_hint", "true");
+
+ if (log.isInfoEnabled())
+ log.info("Cut off exit hint way", hintWay, hintWay.toTagString());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Retrieves the angle in clockwise direction between the line (cCenter, c1)
+ * and the line (cCenter, c2).
+ * @param cCenter the common point of both lines
+ * @param c1 point of the first line
+ * @param c2 point of the second line
+ * @return the angle [-180; 180]
+ */
+ private double getAngle(Coord cCenter, Coord c1, Coord c2)
+ {
+ double dx1 = c1.getLongitude() - cCenter.getLongitude();
+ double dy1 = -(c1.getLatitude() - cCenter.getLatitude());
+
+ double dx2 = c2.getLongitude() - cCenter.getLongitude();
+ double dy2 = -(c2.getLatitude() - cCenter.getLatitude());
+
+ double inRads1 = Math.atan2(dy1,dx1);
+ double inRads2 = Math.atan2(dy2,dx2);
+
+ return Math.toDegrees(inRads2) - Math.toDegrees(inRads1);
+ }
+
+ /**
+ * Cleans all internal data that is no longer used after the hook has been processed.
+ */
+ private void cleanup() {
+ adjacentWays = null;
+ wayNodes = null;
+ destinationLinkWays = null;
+ tagValues = null;
+ saver = null;
+ nameTags = null;
+ }
+
+ public Set<String> getUsedTags() {
+ if (processDestinations) {
+ // When processing destinations also load the destination:lanes,forward and backward tag
+ // to be able to copy the value to the destination tag
+ // Do not load destination because it makes sense only if the tag is
+ // referenced in the style file
+ Set<String> tags = new HashSet<String>();
+ tags.add("destination:lanes");
+ tags.add("destination:forward");
+ tags.add("destination:backward");
+ return tags;
+ } else
+ return Collections.emptySet();
+ }
+
+ public void end() {
+ log.info("LinkDestinationHook started");
+
+ retrieveWays();
+
+// if (processDestinations)
+// processDestinations();
+ if (processExits || processDestinations)
+ processWays();
+
+ cleanup();
+
+ log.info("LinkDestinationHook finished");
+ }
+
+ /**
+ * Retrieves if the given way is tagged as oneway in the direction of the way.
+ * @param w the way
+ * @return <code>true</code> way is oneway
+ */
+ private boolean isOnewayInDirection(Way w) {
+ if (w.isBoolTag("oneway")) {
+ return true;
+ }
+
+ // check if oneway is set implicitly by the highway type (motorway and motorway_link)
+ String onewayTag = w.getTag("oneway");
+ String highwayTag = w.getTag("highway");
+ if (onewayTag == null && highwayTag != null
+ && (highwayTag.equals("motorway") || highwayTag.equals("motorway_link"))) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Retrieves if the given way is tagged as oneway but in opposite direction of the way.
+ * @param w the way
+ * @return <code>true</code> way is oneway in opposite direction
+ */
+ private boolean isOnewayOppositeDirection(Way w) {
+ return "-1".equals(w.getTag("oneway"));
+ }
+
+ /**
+ * Retrieves if the given way is not oneway.
+ * @param w the way
+ * @return <code>true</code> way is not oneway
+ */
+ private boolean isNotOneway(Way w) {
+ return "no".equals(w.getTag("oneway")) ||
+ (isOnewayInDirection(w) == false
+ && isOnewayOppositeDirection(w) == false);
+ }
+
+ /** Private length function without caching */
+ private LengthFunction length = new LengthFunction() {
+ public boolean isCached() {
+ return false;
+ }
+ };
+
+ /**
+ * Retrieve the length of the given way.
+ * @param w way
+ * @return length in m
+ */
+ private double getLength(Way w) {
+ String lengthValue = length.value(w);
+ try {
+ return Math.round(Double.valueOf(lengthValue));
+ } catch (Exception exp) {
+ return 0;
+ }
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/LoadableOsmDataSource.java b/src/uk/me/parabola/mkgmap/reader/osm/LoadableOsmDataSource.java
new file mode 100644
index 0000000..508e6ae
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/LoadableOsmDataSource.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2013.
+ *
+ * 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.reader.osm;
+
+import java.io.InputStream;
+
+import uk.me.parabola.imgfmt.FormatException;
+import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
+
+/**
+ *
+ * @author Gerd
+ *
+ */
+public interface LoadableOsmDataSource extends LoadableMapDataSource{
+ /**
+ * Load osm data from open stream.
+ * You would implement this interface to allow reading data from
+ * zipped files.
+ *
+ * @param is the already opened stream.
+ * @throws FormatException For any kind of malformed input.
+ */
+
+ void load(InputStream is) throws FormatException;
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/LocationHook.java b/src/uk/me/parabola/mkgmap/reader/osm/LocationHook.java
new file mode 100644
index 0000000..ecaa459
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/LocationHook.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2011 - 2012.
+ *
+ * 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.reader.osm;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map.Entry;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.reader.osm.boundary.BoundaryGrid;
+import uk.me.parabola.mkgmap.reader.osm.boundary.BoundaryQuadTree;
+import uk.me.parabola.mkgmap.reader.osm.boundary.BoundaryUtil;
+import uk.me.parabola.util.EnhancedProperties;
+
+public class LocationHook extends OsmReadingHooksAdaptor {
+ private static final Logger log = Logger.getLogger(LocationHook.class);
+ // the resulting assignments are logged with this extra logger
+ // so that it is possible to log only the results of the location hook
+ private static final Logger resultLog = Logger.getLogger(LocationHook.class.getName()+".results");
+
+ // counters for stats
+ private long cntQTSearch = 0;
+ private long cntNotFnd = 0;
+ private long cntwayNotFnd = 0;
+
+ private BoundaryGrid boundaryGrid;
+
+ private ElementSaver saver;
+
+ private String boundaryDirName;
+
+
+ /** this static object is used to synchronize the check if the bounds directory contains any bounds */
+ private static final Object BOUNDS_CHECK_LOCK = new Object();
+
+ /** Stores the name of the bounds dir/file that has been checked. Static so that multiple threads can access. */
+ private static String checkedBoundaryDirName;
+ /** stores the result of the bounds dir/file check */
+ private static boolean checkBoundaryDirOk;
+
+ private EnhancedProperties props;
+
+ public boolean init(ElementSaver saver, EnhancedProperties props) {
+ boundaryDirName = props.getProperty("bounds");
+
+ if (boundaryDirName == null) {
+ // bounds property not set
+ return false;
+ }
+
+ this.props = props;
+ this.saver = saver;
+
+ long t1 = System.currentTimeMillis();
+
+ synchronized (BOUNDS_CHECK_LOCK) {
+ // checking of the boundary dir is expensive
+ // check once only and reuse the result
+ if (boundaryDirName.equals(checkedBoundaryDirName)) {
+ if (checkBoundaryDirOk == false) {
+ log.error("Disable LocationHook because bounds directory is unusable. Dir: "+boundaryDirName);
+ return false;
+ }
+ } else {
+ checkedBoundaryDirName = boundaryDirName;
+ checkBoundaryDirOk = false;
+
+ List<String> boundaryFiles = BoundaryUtil.getBoundaryDirContent(boundaryDirName);
+ if (boundaryFiles == null || boundaryFiles.size() == 0) {
+ log.error("LocationHook is disabled because no bounds files are available. Dir: "
+ + boundaryDirName);
+ return false;
+ }
+ // passed all checks => boundaries are okay
+ checkBoundaryDirOk = true;
+ }
+ }
+ log.info("Checking bounds dir took", (System.currentTimeMillis() - t1), "ms");
+ return true;
+ }
+
+ public void end() {
+ long t1 = System.currentTimeMillis();
+ log.info("Starting with location hook");
+
+ boundaryGrid = new BoundaryGrid(boundaryDirName, saver.getBoundingBox(), props);
+ processLocationRelevantElements();
+
+ boundaryGrid = null;
+
+ long dt = (System.currentTimeMillis() - t1);
+ log.info("======= LocationHook Stats =====");
+ log.info("QuadTree searches :", cntQTSearch);
+ log.info("unsuccesfull :", cntNotFnd);
+ log.info("unsuccesfull for ways:", cntwayNotFnd);
+ log.info("Location hook finished in", dt, "ms");
+
+ }
+
+ /**
+ * Iterate over all elements for which the boundary assignment should be performed.
+ */
+ private void processLocationRelevantElements() {
+ // process all nodes that might be converted to a garmin node (tagcount > 0)
+ for (Node node : saver.getNodes().values()) {
+ if (node.getTagCount() > 0) {
+ if (saver.getBoundingBox().contains(node.getLocation())){
+ processElem(node);
+ if (resultLog.isDebugEnabled())
+ resultLog.debug("N", node.getId(), locationTagsToString(node));
+ }
+ }
+ }
+
+ // process all ways that might be converted to a garmin way (tagcount > 0)
+ for (Way way : saver.getWays().values()) {
+ if (way.getTagCount() > 0) {
+ processElem(way);
+ if (resultLog.isDebugEnabled())
+ resultLog.debug("W", way.getId(), locationTagsToString(way));
+ }
+ }
+
+ // process all multipolygons - the add-pois-to-area function uses its
+ // center point and its tags so the mp must be tagged itself with the bounds
+ // tags
+ for (Relation r : saver.getRelations().values()) {
+ if (r instanceof MultiPolygonRelation) {
+ // check if the mp could be processed
+ Coord mpCenter = ((MultiPolygonRelation) r).getCofG();
+ if (mpCenter != null && saver.getBoundingBox().contains(mpCenter)){
+ // create a fake node for which the bounds information is collected
+ Node mpNode = new Node(FakeIdGenerator.makeFakeId(), mpCenter);
+ processElem(mpNode);
+ // copy the bounds tags back to the multipolygon
+ for (String boundsTag : BoundaryQuadTree.mkgmapTagsArray) {
+ String tagValue = mpNode.getTag(boundsTag);
+ if (tagValue != null) {
+ r.addTag(boundsTag, tagValue);
+ }
+ }
+ if (resultLog.isDebugEnabled())
+ resultLog.debug("R", r.getId(), locationTagsToString(r));
+ }
+ }
+ }
+ }
+
+ /**
+ * Extract the location info and perform a test
+ * against the BoundaryGrid. If found, assign the tags.
+ * @param elem A way or Node
+ */
+ private void processElem(Element elem){
+ Tags tags = null;
+
+ if (elem instanceof Node){
+ Node node = (Node) elem;
+ tags = search(node.getLocation());
+ }
+ else if (elem instanceof Way){
+ Way way = (Way) elem;
+ // try the mid point of the way first
+ int middle = way.getPoints().size() / 2;
+ tags = search(way.getPoints().get(middle));
+ if (tags == null){
+ // try 1st point next
+ tags = search(way.getPoints().get(0));
+ }
+ if (tags == null){
+ // try last point next
+ tags = search(way.getPoints().get(way.getPoints().size()-1));
+ }
+ if (tags == null){
+ // still not found, try rest
+ for (int i = 1; i < way.getPoints().size()-1; i++){
+ if (i == middle)
+ continue;
+ tags = search(way.getPoints().get(i));
+ if (tags != null)
+ break;
+ }
+ }
+ if (tags == null)
+ ++cntwayNotFnd;
+ }
+
+ if (tags == null){
+ ++cntNotFnd;
+ }
+ else{
+ // tag the element with all tags referenced by the boundary
+ Iterator<Entry<String,String>> tagIter = tags.entryIterator();
+ while (tagIter.hasNext()) {
+ Entry<String,String> tag = tagIter.next();
+ if (elem.getTag(tag.getKey()) == null){
+ elem.addTag(tag.getKey(),tag.getValue());
+ }
+ }
+ }
+ }
+
+ /**
+ * perform search in grid and maintain statistic counter
+ * @param co a point that is to be searched
+ * @return location relevant tags or null
+ */
+ private Tags search(Coord co){
+ if (saver.getBoundingBox().contains(co)){
+ ++cntQTSearch;
+ return boundaryGrid.get(co);
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Debugging:
+ * Create a string with location relevant tags ordered by admin_level.
+ * Can be used to compare results with tools like diff.
+ * @param elem the element
+ * @return A new String object
+ */
+ private String locationTagsToString(Element elem){
+ StringBuilder res = new StringBuilder();
+ for (int i = BoundaryQuadTree.mkgmapTagsArray.length-1; i >= 0; --i){
+ String tagVal = elem.getTag(BoundaryQuadTree.mkgmapTagsArray[i] );
+ if (tagVal != null)
+ res.append(tagVal);
+ res.append(";");
+ }
+ return res.toString();
+ }
+
+}
+
+
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonFinishHook.java b/src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonFinishHook.java
new file mode 100644
index 0000000..dba5c23
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonFinishHook.java
@@ -0,0 +1,59 @@
+/*
+ * 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.reader.osm;
+
+import java.util.Arrays;
+
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.util.EnhancedProperties;
+
+public class MultiPolygonFinishHook extends OsmReadingHooksAdaptor {
+ private static final Logger log = Logger.getLogger(MultiPolygonFinishHook.class);
+
+ private ElementSaver saver;
+
+ public MultiPolygonFinishHook() {
+ }
+
+ public boolean init(ElementSaver saver, EnhancedProperties props) {
+ this.saver = saver;
+ return true;
+ }
+
+ public void end() {
+ long t1 = System.currentTimeMillis();
+ log.info("Finishing multipolygons");
+ for (Way way : saver.getWays().values()) {
+ String removeTag = way.getTag(ElementSaver.MKGMAP_REMOVE_TAG);
+ if (removeTag == null) {
+ continue;
+ }
+ if (ElementSaver.MKGMAP_REMOVE_TAG_ALL_KEY.equals(removeTag)) {
+ if (log.isDebugEnabled())
+ log.debug("Remove all tags from way",way.getId(),way.toTagString());
+ way.removeAllTags();
+ } else {
+ String[] tagsToRemove = removeTag.split(";");
+ if (log.isDebugEnabled())
+ log.debug("Remove tags",Arrays.toString(tagsToRemove),"from way",way.getId(),way.toTagString());
+ for (String rTag : tagsToRemove) {
+ way.deleteTag(rTag);
+ }
+ way.deleteTag(ElementSaver.MKGMAP_REMOVE_TAG);
+ }
+ }
+ log.info("Multipolygon hook finished in "+(System.currentTimeMillis()-t1)+" ms");
+
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java b/src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
new file mode 100644
index 0000000..ee40605
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
@@ -0,0 +1,2875 @@
+/*
+ * Copyright (C) 2011-2014.
+ *
+ * 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.reader.osm;
+
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.geom.Area;
+import java.awt.geom.Line2D;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.logging.Level;
+import java.util.LinkedHashMap;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.util.Java2DConverter;
+
+/**
+ * Representation of an OSM Multipolygon Relation.<br/>
+ * The different way of the multipolygon are joined to polygons and inner
+ * polygons are cut out from the outer polygons.
+ *
+ * @author WanMil
+ */
+public class MultiPolygonRelation extends Relation {
+ private static final Logger log = Logger
+ .getLogger(MultiPolygonRelation.class);
+
+ public static final String STYLE_FILTER_TAG = "mkgmap:stylefilter";
+ public static final String STYLE_FILTER_LINE = "polyline";
+ public static final String STYLE_FILTER_POLYGON = "polygon";
+
+ /** A tag that is set with value true on each polygon that is created by the mp processing */
+ public static final String MP_CREATED_TAG = "mkgmap:mp_created";
+
+ private final Map<Long, Way> tileWayMap;
+ private final Map<Long, String> roleMap = new HashMap<Long, String>();
+
+ private Map<Long, Way> mpPolygons = new LinkedHashMap<Long, Way>();
+
+
+ protected ArrayList<BitSet> containsMatrix;
+ protected ArrayList<JoinedWay> polygons;
+ protected Set<JoinedWay> intersectingPolygons;
+
+ protected double largestSize;
+ protected JoinedWay largestOuterPolygon;
+
+ protected Set<Way> outerWaysForLineTagging;
+ protected Map<String, String> outerTags;
+
+ private final uk.me.parabola.imgfmt.app.Area bbox;
+ protected Area bboxArea;
+
+ private Coord cOfG = null;
+
+ // the sum of all outer polygons area size
+ private double mpAreaSize = 0;
+
+ /**
+ * A point that has a lower or equal squared distance from
+ * a line is treated as if it lies one the line.<br/>
+ * 1.0d is very exact. 2.0d covers rounding problems when converting
+ * OSM locations to mkgmap internal format. A larger value
+ * is more tolerant against imprecise OSM data.
+ */
+ private static final double OVERLAP_TOLERANCE_DISTANCE = 2.0d;
+
+ /**
+ * Create an instance based on an existing relation. We need to do this
+ * because the type of the relation is not known until after all its tags
+ * are read in.
+ *
+ * @param other
+ * The relation to base this one on.
+ * @param wayMap
+ * Map of all ways.
+ * @param bbox
+ * The bounding box of the tile
+ */
+ public MultiPolygonRelation(Relation other, Map<Long, Way> wayMap,
+ uk.me.parabola.imgfmt.app.Area bbox) {
+ this.tileWayMap = wayMap;
+ this.bbox = bbox;
+
+ setId(other.getId());
+ copyTags(other);
+
+ if (log.isDebugEnabled()) {
+ log.debug("Construct multipolygon", toBrowseURL(), toTagString());
+ }
+
+ for (Map.Entry<String, Element> pair : other.getElements()) {
+ String role = pair.getKey();
+ Element el = pair.getValue();
+ if (log.isDebugEnabled()) {
+ log.debug(" ", role, el.toBrowseURL(), el.toTagString());
+ }
+ addElement(role, el);
+ roleMap.put(el.getId(), role);
+ }
+ }
+
+
+ /**
+ * Retrieves the center point of this multipolygon. This is set in the
+ * {@link #processElements()} methods so it returns <code>null</code>
+ * before that. It can also return <code>null</code> in case the
+ * multipolygon could not be processed.<br/>
+ * The returned point may lie outside the multipolygon area. It is just
+ * the center point of it.
+ *
+ * @return the center point of this multipolygon (maybe <code>null</code>)
+ */
+ public Coord getCofG() {
+ return cOfG;
+ }
+
+ /**
+ * Retrieves the mp role of the given element.
+ *
+ * @param element
+ * the element
+ * @return the role of the element
+ */
+ protected String getRole(Element element) {
+ String role = roleMap.get(element.getId());
+ if (role != null && ("outer".equals(role) || "inner".equals(role))) {
+ return role;
+ }
+
+ return null;
+ }
+
+ /**
+ * Try to join the two ways.
+ *
+ * @param joinWay
+ * the way to which tempWay is added in case both ways could be
+ * joined and checkOnly is false.
+ * @param tempWay
+ * the way to be added to joinWay
+ * @param checkOnly
+ * <code>true</code> checks only and does not perform the join
+ * operation
+ * @return <code>true</code> if tempWay way is (or could be) joined to
+ * joinWay
+ */
+ private boolean joinWays(JoinedWay joinWay, JoinedWay tempWay,
+ boolean checkOnly) {
+ boolean reverseTempWay = false;
+ int insIdx = -1;
+ int firstTmpIdx = 1;
+ boolean joinable = false;
+
+ // use == or equals as comparator??
+ if (joinWay.getPoints().get(0) == tempWay.getPoints().get(0)) {
+ insIdx = 0;
+ reverseTempWay = true;
+ firstTmpIdx = 1;
+ joinable = true;
+ } else if (joinWay.getPoints().get(joinWay.getPoints().size() - 1) == tempWay
+ .getPoints().get(0)) {
+ insIdx = joinWay.getPoints().size();
+ reverseTempWay = false;
+ firstTmpIdx = 1;
+ joinable = true;
+ } else if (joinWay.getPoints().get(0) == tempWay.getPoints().get(
+ tempWay.getPoints().size() - 1)) {
+ insIdx = 0;
+ reverseTempWay = false;
+ firstTmpIdx = 0;
+ joinable = true;
+ } else if (joinWay.getPoints().get(joinWay.getPoints().size() - 1) == tempWay
+ .getPoints().get(tempWay.getPoints().size() - 1)) {
+ insIdx = joinWay.getPoints().size();
+ reverseTempWay = true;
+ firstTmpIdx = 0;
+ joinable = true;
+ }
+
+ if (!checkOnly && joinable){
+ int lastIdx = tempWay.getPoints().size();
+ if (firstTmpIdx == 0) {
+ // the last temp point is already contained in the joined way - do not copy it
+ lastIdx--;
+ }
+
+ List<Coord> tempCoords = tempWay.getPoints().subList(firstTmpIdx,lastIdx);
+
+ if (reverseTempWay) {
+ // the remp coords need to be reversed so copy the list
+ tempCoords = new ArrayList<Coord>(tempCoords);
+ // and reverse it
+ Collections.reverse(tempCoords);
+ }
+
+ joinWay.getPoints().addAll(insIdx, tempCoords);
+ joinWay.addWay(tempWay);
+ }
+ return joinable;
+ }
+
+ /**
+ * Combine a list of way segments to a list of maximally joined ways
+ *
+ * @param segments
+ * a list of closed or unclosed ways
+ * @return a list of closed ways
+ */
+ protected ArrayList<JoinedWay> joinWays(List<Way> segments) {
+ // TODO check if the closed polygon is valid and implement a
+ // backtracking algorithm to get other combinations
+
+ ArrayList<JoinedWay> joinedWays = new ArrayList<JoinedWay>();
+ if (segments == null || segments.isEmpty()) {
+ return joinedWays;
+ }
+
+ // go through all segments and categorize them to closed and unclosed
+ // list
+ ArrayList<JoinedWay> unclosedWays = new ArrayList<JoinedWay>();
+ for (Way orgSegment : segments) {
+ JoinedWay jw = new JoinedWay(orgSegment);
+ roleMap.put(jw.getId(), getRole(orgSegment));
+ if (orgSegment.isClosed()) {
+ if (orgSegment.isComplete() == false) {
+ // the way is complete in planet but some points are missing in this tile
+ // we can close it artificially
+ if (log.isDebugEnabled())
+ log.debug("Close incomplete but closed polygon:",orgSegment);
+ jw.closeWayArtificially();
+ }
+ joinedWays.add(jw);
+ } else {
+ unclosedWays.add(jw);
+ }
+ }
+
+ while (!unclosedWays.isEmpty()) {
+ JoinedWay joinWay = unclosedWays.remove(0);
+
+ // check if the current way is already closed or if it is the last
+ // way
+ if (joinWay.isClosed() || unclosedWays.isEmpty()) {
+ joinedWays.add(joinWay);
+ continue;
+ }
+
+ boolean joined = false;
+
+ // if we have a way that could be joined but which has a wrong role
+ // then store it here and check in the end if it's working
+ JoinedWay wrongRoleWay = null;
+ String joinRole = getRole(joinWay);
+
+ // go through all ways and check if there is a way that can be
+ // joined with it
+ // in this case join the two ways
+ // => add all points of tempWay to joinWay, remove tempWay and put
+ // joinWay to the beginning of the list
+ // (not optimal but understandable - can be optimized later)
+ for (JoinedWay tempWay : unclosedWays) {
+ if (tempWay.isClosed()) {
+ continue;
+ }
+
+ String tempRole = getRole(tempWay);
+ // if a role is not 'inner' or 'outer' then it is used as
+ // universal
+ // check if the roles of the ways are matching
+ if ((!"outer".equals(joinRole) && !"inner"
+ .equals(joinRole))
+ || (!"outer".equals(tempRole) && !"inner"
+ .equals(tempRole))
+ || (joinRole != null && joinRole.equals(tempRole))) {
+ // the roles are matching => try to join both ways
+ joined = joinWays(joinWay, tempWay, false);
+ } else {
+ // the roles are not matching => test if both ways would
+ // join
+
+ // as long as we don't have an alternative way with wrong
+ // role
+ // or if the alternative way is shorter then check if
+ // the way with the wrong role could be joined
+ if (wrongRoleWay == null
+ || wrongRoleWay.getPoints().size() < tempWay
+ .getPoints().size()) {
+ if (joinWays(joinWay, tempWay, true)) {
+ // save this way => maybe we will use it in the end
+ // if we don't find any other way
+ wrongRoleWay = tempWay;
+ }
+ }
+ }
+
+ if (joined) {
+ // we have joined the way
+ unclosedWays.remove(tempWay);
+ break;
+ }
+ }
+
+ if (!joined && wrongRoleWay != null) {
+
+ log.warn("Join ways with different roles. Multipolygon: "
+ + toBrowseURL());
+ log.warn("Way1 Role:", getRole(joinWay));
+ logWayURLs(Level.WARNING, "-", joinWay);
+ log.warn("Way2 Role:", getRole(wrongRoleWay));
+ logWayURLs(Level.WARNING, "-", wrongRoleWay);
+
+ joined = joinWays(joinWay, wrongRoleWay, false);
+ if (joined) {
+ // we have joined the way
+ unclosedWays.remove(wrongRoleWay);
+ break;
+ }
+ }
+
+ if (joined) {
+ if (joinWay.isClosed()) {
+ // it's closed => don't process it again
+ joinedWays.add(joinWay);
+ } else if (unclosedWays.isEmpty()) {
+ // no more ways to join with
+ // it's not closed but we cannot join it more
+ joinedWays.add(joinWay);
+ } else {
+ // it is not yet closed => process it once again
+ unclosedWays.add(0, joinWay);
+ }
+ } else {
+ // it's not closed but we cannot join it more
+ joinedWays.add(joinWay);
+ }
+ }
+
+ return joinedWays;
+ }
+
+ /**
+ * Try to close all unclosed ways in the given list of ways.
+ *
+ * @param wayList
+ * a list of ways
+ */
+ protected void closeWays(ArrayList<JoinedWay> wayList) {
+ for (JoinedWay way : wayList) {
+ if (way.isClosed() || way.getPoints().size() < 3) {
+ continue;
+ }
+ Coord p1 = way.getPoints().get(0);
+ Coord p2 = way.getPoints().get(way.getPoints().size() - 1);
+
+ if (bbox.insideBoundary(p1) == false
+ && bbox.insideBoundary(p2) == false) {
+ // both points lie outside the bbox or on the bbox
+
+ // check if both points are on the same side of the bounding box
+ if ((p1.getLatitude() <= bbox.getMinLat() && p2.getLatitude() <= bbox
+ .getMinLat())
+ || (p1.getLatitude() >= bbox.getMaxLat() && p2
+ .getLatitude() >= bbox.getMaxLat())
+ || (p1.getLongitude() <= bbox.getMinLong() && p2
+ .getLongitude() <= bbox.getMinLong())
+ || (p1.getLongitude() >= bbox.getMaxLong() && p2
+ .getLongitude() >= bbox.getMaxLong())) {
+ // they are on the same side outside of the bbox
+ // so just close them without worrying about if
+ // they intersect itself because the intersection also
+ // is outside the bbox
+ way.closeWayArtificially();
+ log.info("Endpoints of way", way,
+ "are both outside the bbox. Closing it directly.");
+ continue;
+ }
+ }
+
+ Line2D closingLine = new Line2D.Float(p1.getLongitude(), p1
+ .getLatitude(), p2.getLongitude(), p2.getLatitude());
+
+ boolean intersects = false;
+ Coord lastPoint = null;
+ // don't use the first and the last point
+ // the closing line can intersect only in one point or complete.
+ // Both isn't interesting for this check
+ for (Coord thisPoint : way.getPoints().subList(1,
+ way.getPoints().size() - 1)) {
+ if (lastPoint != null) {
+ if (closingLine.intersectsLine(lastPoint.getLongitude(),
+ lastPoint.getLatitude(), thisPoint.getLongitude(),
+ thisPoint.getLatitude())) {
+ intersects = true;
+ break;
+ }
+ }
+ lastPoint = thisPoint;
+ }
+
+ if (!intersects) {
+ // close the polygon
+ // the new way segment does not intersect the rest of the
+ // polygon
+ log.info("Closing way", way);
+ log.info("from", way.getPoints().get(0).toOSMURL());
+ log.info("to", way.getPoints().get(way.getPoints().size() - 1)
+ .toOSMURL());
+ // mark this ways as artificially closed
+ way.closeWayArtificially();
+ }
+ }
+ }
+
+
+ protected static class ConnectionData {
+ public Coord c1;
+ public Coord c2;
+ public JoinedWay w1;
+ public JoinedWay w2;
+ // sometimes the connection of both points cannot be done directly but with an intermediate point
+ public Coord imC;
+ public double distance;
+
+ public ConnectionData() {
+
+ }
+ }
+
+ protected boolean connectUnclosedWays(List<JoinedWay> allWays) {
+ List<JoinedWay> unclosed = new ArrayList<JoinedWay>();
+
+ for (JoinedWay w : allWays) {
+ if (w.isClosed() == false) {
+ unclosed.add(w);
+ }
+ }
+ // try to connect ways lying outside or on the bbox
+ if (unclosed.size() >= 2) {
+ log.debug("Checking",unclosed.size(),"unclosed ways for connections outside the bbox");
+ Map<Coord, JoinedWay> outOfBboxPoints = new HashMap<Coord, JoinedWay>();
+
+ // check all ways for endpoints outside or on the bbox
+ for (JoinedWay w : unclosed) {
+ Coord c1 = w.getPoints().get(0);
+ if (bbox.insideBoundary(c1)==false) {
+ log.debug("Point",c1,"of way",w.getId(),"outside bbox");
+ outOfBboxPoints.put(c1, w);
+ }
+
+ Coord c2 = w.getPoints().get(w.getPoints().size()-1);
+ if (bbox.insideBoundary(c2)==false) {
+ log.debug("Point",c2,"of way",w.getId(),"outside bbox");
+ outOfBboxPoints.put(c2, w);
+ }
+ }
+
+ if (outOfBboxPoints.size() < 2) {
+ log.debug(outOfBboxPoints.size(),"point outside the bbox. No connection possible.");
+ return false;
+ }
+
+ List<ConnectionData> coordPairs = new ArrayList<ConnectionData>();
+ ArrayList<Coord> coords = new ArrayList<Coord>(outOfBboxPoints.keySet());
+ for (int i = 0; i < coords.size(); i++) {
+ for (int j = i + 1; j < coords.size(); j++) {
+ ConnectionData cd = new ConnectionData();
+ cd.c1 = coords.get(i);
+ cd.c2 = coords.get(j);
+ cd.w1 = outOfBboxPoints.get(cd.c1);
+ cd.w2 = outOfBboxPoints.get(cd.c2);
+
+ if (lineCutsBbox(cd.c1, cd.c2 )) {
+ // Check if the way can be closed with one additional point
+ // outside the bounding box.
+ // The additional point is combination of the coords of both endpoints.
+ // It works if the lines from the endpoints to the additional point does
+ // not cut the bounding box.
+ // This can be removed when the splitter guarantees to provide logical complete
+ // multi-polygons.
+ Coord edgePoint1 = new Coord(cd.c1.getLatitude(), cd.c2
+ .getLongitude());
+ Coord edgePoint2 = new Coord(cd.c2.getLatitude(), cd.c1
+ .getLongitude());
+
+ if (lineCutsBbox(cd.c1, edgePoint1) == false
+ && lineCutsBbox(edgePoint1, cd.c2) == false) {
+ cd.imC = edgePoint1;
+ } else if (lineCutsBbox(cd.c1, edgePoint2) == false
+ && lineCutsBbox(edgePoint2, cd.c2) == false) {
+ cd.imC = edgePoint1;
+ } else {
+ // both endpoints are on opposite sides of the bounding box
+ // automatically closing such points would create wrong polygons in most cases
+ continue;
+ }
+ cd.distance = cd.c1.distance(cd.imC) + cd.imC.distance(cd.c2);
+ } else {
+ cd.distance = cd.c1.distance(cd.c2);
+ }
+ coordPairs.add(cd);
+ }
+ }
+
+ if (coordPairs.isEmpty()) {
+ log.debug("All potential connections cross the bbox. No connection possible.");
+ return false;
+ } else {
+ // retrieve the connection with the minimum distance
+ ConnectionData minCon = Collections.min(coordPairs,
+ new Comparator<ConnectionData>() {
+ public int compare(ConnectionData o1,
+ ConnectionData o2) {
+ return Double.compare(o1.distance, o2.distance);
+ }
+ });
+
+ if (minCon.w1 == minCon.w2) {
+ log.debug("Close a gap in way",minCon.w1);
+ if (minCon.imC != null)
+ minCon.w1.getPoints().add(minCon.imC);
+ minCon.w1.closeWayArtificially();
+ } else {
+ log.debug("Connect", minCon.w1, "with", minCon.w2);
+
+ if (minCon.w1.getPoints().get(0).equals(minCon.c1)) {
+ Collections.reverse(minCon.w1.getPoints());
+ }
+ if (minCon.w2.getPoints().get(0).equals(minCon.c2) == false) {
+ Collections.reverse(minCon.w2.getPoints());
+ }
+
+ minCon.w1.getPoints().addAll(minCon.w2.getPoints());
+ minCon.w1.addWay(minCon.w2);
+ allWays.remove(minCon.w2);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * Removes all ways non closed ways from the given list (
+ * <code>{@link Way#isClosed()} == false</code>)
+ *
+ * @param wayList
+ * list of ways
+ */
+ protected void removeUnclosedWays(ArrayList<JoinedWay> wayList) {
+ Iterator<JoinedWay> it = wayList.iterator();
+ boolean firstWarn = true;
+ while (it.hasNext()) {
+ JoinedWay tempWay = it.next();
+ if (!tempWay.isClosed()) {
+ // warn only if the way intersects the bounding box
+ boolean inBbox = tempWay.intersects(bbox);
+ if (inBbox) {
+ if (firstWarn) {
+ log.warn(
+ "Cannot join the following ways to closed polygons. Multipolygon",
+ toBrowseURL(), toTagString());
+ firstWarn = false;
+ }
+ logWayURLs(Level.WARNING, "- way:", tempWay);
+ logFakeWayDetails(Level.WARNING, tempWay);
+ }
+
+ it.remove();
+
+ if (inBbox) {
+ String role = getRole(tempWay);
+ if (role == null || "".equals(role) || "outer".equals(role)) {
+ // anyhow add the ways to the list for line tagging
+ outerWaysForLineTagging.addAll(tempWay.getOriginalWays());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes all ways that are completely outside the bounding box.
+ * This reduces error messages from problems on the tile bounds.
+ * @param wayList list of ways
+ */
+ protected void removeWaysOutsideBbox(ArrayList<JoinedWay> wayList) {
+ ListIterator<JoinedWay> wayIter = wayList.listIterator();
+ while (wayIter.hasNext()) {
+ JoinedWay w = wayIter.next();
+ boolean remove = true;
+ // check all points
+ for (Coord c : w.getPoints()) {
+ if (bbox.contains(c)) {
+ // if one point is in the bounding box the way should not be removed
+ remove = false;
+ break;
+ }
+ }
+
+ if (remove) {
+ // check if the polygon contains the complete bounding box
+ if (w.getBounds().contains(bboxArea.getBounds())) {
+ remove = false;
+ }
+ }
+
+ if (remove) {
+ if (log.isDebugEnabled()) {
+ log.debug("Remove way", w.getId(),
+ "because it is completely outside the bounding box.");
+ }
+ wayIter.remove();
+ }
+ }
+ }
+
+ /**
+ * Find all polygons that are not contained by any other polygon.
+ *
+ * @param candidates
+ * all polygons that should be checked
+ * @param roleFilter
+ * an additional filter
+ * @return all polygon indexes that are not contained by any other polygon
+ */
+ private BitSet findOutmostPolygons(BitSet candidates, BitSet roleFilter) {
+ BitSet realCandidates = ((BitSet) candidates.clone());
+ realCandidates.and(roleFilter);
+ return findOutmostPolygons(realCandidates);
+ }
+
+ /**
+ * Finds all polygons that are not contained by any other polygons and that match
+ * to the given role. All polygons with index given by <var>candidates</var>
+ * are used.
+ *
+ * @param candidates
+ * indexes of the polygons that should be used
+ * @return the bits of all outermost polygons are set to true
+ */
+ protected BitSet findOutmostPolygons(BitSet candidates) {
+ BitSet outmostPolygons = new BitSet();
+
+ // go through all candidates and check if they are contained by any
+ // other candidate
+ for (int candidateIndex = candidates.nextSetBit(0); candidateIndex >= 0; candidateIndex = candidates
+ .nextSetBit(candidateIndex + 1)) {
+ // check if the candidateIndex polygon is not contained by any
+ // other candidate polygon
+ boolean isOutmost = true;
+ for (int otherCandidateIndex = candidates.nextSetBit(0); otherCandidateIndex >= 0; otherCandidateIndex = candidates
+ .nextSetBit(otherCandidateIndex + 1)) {
+ if (contains(otherCandidateIndex, candidateIndex)) {
+ // candidateIndex is not an outermost polygon because it is
+ // contained by the otherCandidateIndex polygon
+ isOutmost = false;
+ break;
+ }
+ }
+ if (isOutmost) {
+ // this is an outermost polygon
+ // put it to the bitset
+ outmostPolygons.set(candidateIndex);
+ }
+ }
+
+ return outmostPolygons;
+ }
+
+ protected ArrayList<PolygonStatus> getPolygonStatus(BitSet outmostPolygons,
+ String defaultRole) {
+ ArrayList<PolygonStatus> polygonStatusList = new ArrayList<PolygonStatus>();
+ for (int polyIndex = outmostPolygons.nextSetBit(0); polyIndex >= 0; polyIndex = outmostPolygons
+ .nextSetBit(polyIndex + 1)) {
+ // polyIndex is the polygon that is not contained by any other
+ // polygon
+ JoinedWay polygon = polygons.get(polyIndex);
+ String role = getRole(polygon);
+ // if the role is not explicitly set use the default role
+ if (role == null || "".equals(role)) {
+ role = defaultRole;
+ }
+ polygonStatusList.add(new PolygonStatus("outer".equals(role), polyIndex, polygon));
+ }
+ return polygonStatusList;
+ }
+
+ /**
+ * Creates a list of all original ways of the multipolygon.
+ * @return all source ways
+ */
+ protected List<Way> getSourceWays() {
+ ArrayList<Way> allWays = new ArrayList<Way>();
+
+ for (Map.Entry<String, Element> r_e : getElements()) {
+ if (r_e.getValue() instanceof Way) {
+ if (((Way)r_e.getValue()).getPoints().isEmpty()) {
+ log.warn("Way",r_e.getValue(),"has no points and cannot be used for the multipolygon",toBrowseURL());
+ } else {
+ allWays.add((Way) r_e.getValue());
+ }
+ } else if (r_e.getValue() instanceof Node == false ||
+ ("admin_centre".equals(r_e.getKey()) == false && "label".equals(r_e.getKey()) == false)) {
+ log.warn("Non way member in role", r_e.getKey(), r_e.getValue().toBrowseURL(),
+ "in multipolygon", toBrowseURL(), toTagString());
+ }
+ }
+ return allWays;
+ }
+
+
+ // unfinishedPolygons marks which polygons are not yet processed
+ protected BitSet unfinishedPolygons;
+
+ // create bitsets which polygons belong to the outer and to the inner role
+ protected BitSet innerPolygons;
+ protected BitSet taggedInnerPolygons;
+ protected BitSet outerPolygons;
+ protected BitSet taggedOuterPolygons;
+
+ /**
+ * Process the ways in this relation. Joins way with the role "outer" Adds
+ * ways with the role "inner" to the way with the role "outer"
+ */
+ public void processElements() {
+ log.info("Processing multipolygon", toBrowseURL());
+
+ List<Way> allWays = getSourceWays();
+
+ // check if it makes sense to process the mp
+ if (isMpProcessable(allWays) == false) {
+ log.info("Do not process multipolygon",getId(),"because it has no style relevant tags.");
+ return;
+ }
+
+
+ // create an Area for the bbox to clip the polygons
+ bboxArea = Java2DConverter.createBoundsArea(getBbox());
+
+ // join all single ways to polygons, try to close ways and remove non closed ways
+ polygons = joinWays(allWays);
+
+ outerWaysForLineTagging = new HashSet<Way>();
+ outerTags = new HashMap<String,String>();
+
+ closeWays(polygons);
+
+ while (connectUnclosedWays(polygons)) {
+ closeWays(polygons);
+ }
+
+ removeUnclosedWays(polygons);
+
+ // now only closed ways are left => polygons only
+
+ // check if we have at least one polygon left
+ if (polygons.isEmpty()) {
+ // do nothing
+ log.info("Multipolygon " + toBrowseURL()
+ + " does not contain a closed polygon.");
+ tagOuterWays();
+ cleanup();
+ return;
+ }
+
+ removeWaysOutsideBbox(polygons);
+
+ if (polygons.isEmpty()) {
+ // do nothing
+ log.info("Multipolygon", toBrowseURL(),
+ "is completely outside the bounding box. It is not processed.");
+ tagOuterWays();
+ cleanup();
+ return;
+ }
+
+ // the intersectingPolygons marks all intersecting/overlapping polygons
+ intersectingPolygons = new HashSet<JoinedWay>();
+
+ // check which polygons lie inside which other polygon
+ createContainsMatrix(polygons);
+
+ // unfinishedPolygons marks which polygons are not yet processed
+ unfinishedPolygons = new BitSet(polygons.size());
+ unfinishedPolygons.set(0, polygons.size());
+
+ // create bitsets which polygons belong to the outer and to the inner role
+ innerPolygons = new BitSet();
+ taggedInnerPolygons = new BitSet();
+ outerPolygons = new BitSet();
+ taggedOuterPolygons = new BitSet();
+
+ int wi = 0;
+ for (Way w : polygons) {
+ String role = getRole(w);
+ if ("inner".equals(role)) {
+ innerPolygons.set(wi);
+ taggedInnerPolygons.set(wi);
+ } else if ("outer".equals(role)) {
+ outerPolygons.set(wi);
+ taggedOuterPolygons.set(wi);
+ } else {
+ // unknown role => it could be both
+ innerPolygons.set(wi);
+ outerPolygons.set(wi);
+ }
+ wi++;
+ }
+
+ if (outerPolygons.isEmpty()) {
+ log.warn("Multipolygon", toBrowseURL(),
+ "does not contain any way tagged with role=outer or empty role.");
+ cleanup();
+ return;
+ }
+
+ Queue<PolygonStatus> polygonWorkingQueue = new LinkedBlockingQueue<PolygonStatus>();
+ BitSet nestedOuterPolygons = new BitSet();
+ BitSet nestedInnerPolygons = new BitSet();
+
+ BitSet outmostPolygons;
+ BitSet outmostInnerPolygons = new BitSet();
+ boolean outmostInnerFound;
+ do {
+ outmostInnerFound = false;
+ outmostPolygons = findOutmostPolygons(unfinishedPolygons);
+
+ if (outmostPolygons.intersects(taggedInnerPolygons)) {
+ outmostInnerPolygons.or(outmostPolygons);
+ outmostInnerPolygons.and(taggedInnerPolygons);
+
+ if (log.isDebugEnabled())
+ log.debug("wrong inner polygons: " + outmostInnerPolygons);
+ // do not process polygons tagged with role=inner but which are
+ // not contained by any other polygon
+ unfinishedPolygons.andNot(outmostInnerPolygons);
+ outmostPolygons.andNot(outmostInnerPolygons);
+ outmostInnerFound = true;
+ }
+ } while (outmostInnerFound);
+
+ if (!outmostPolygons.isEmpty()) {
+ polygonWorkingQueue.addAll(getPolygonStatus(outmostPolygons, "outer"));
+ }
+
+ boolean outmostPolygonProcessing = true;
+
+
+ while (!polygonWorkingQueue.isEmpty()) {
+
+ // the polygon is not contained by any other unfinished polygon
+ PolygonStatus currentPolygon = polygonWorkingQueue.poll();
+
+ // this polygon is now processed and should not be used by any
+ // further step
+ unfinishedPolygons.clear(currentPolygon.index);
+
+ BitSet polygonContains = new BitSet();
+ polygonContains.or(containsMatrix.get(currentPolygon.index));
+ // use only polygon that are contained by the polygon
+ polygonContains.and(unfinishedPolygons);
+ // polygonContains is the intersection of the unfinished and
+ // the contained polygons
+
+ // get the holes
+ // these are all polygons that are in the main polygon
+ // and that are not contained by any other polygon
+ boolean holesOk;
+ BitSet holeIndexes;
+ do {
+ holeIndexes = findOutmostPolygons(polygonContains);
+ holesOk = true;
+
+ if (currentPolygon.outer) {
+ // for role=outer only role=inner is allowed
+ if (holeIndexes.intersects(taggedOuterPolygons)) {
+ BitSet addOuterNestedPolygons = new BitSet();
+ addOuterNestedPolygons.or(holeIndexes);
+ addOuterNestedPolygons.and(taggedOuterPolygons);
+ nestedOuterPolygons.or(addOuterNestedPolygons);
+ holeIndexes.andNot(addOuterNestedPolygons);
+ // do not process them
+ unfinishedPolygons.andNot(addOuterNestedPolygons);
+ polygonContains.andNot(addOuterNestedPolygons);
+
+ // recalculate the holes again to get all inner polygons
+ // in the nested outer polygons
+ holesOk = false;
+ }
+ } else {
+ // for role=inner both role=inner and role=outer is supported
+ // although inner in inner is not officially allowed
+ if (holeIndexes.intersects(taggedInnerPolygons)) {
+ // process inner in inner but issue a warning later
+ BitSet addInnerNestedPolygons = new BitSet();
+ addInnerNestedPolygons.or(holeIndexes);
+ addInnerNestedPolygons.and(taggedInnerPolygons);
+ nestedInnerPolygons.or(addInnerNestedPolygons);
+ }
+ }
+ } while (!holesOk);
+
+ ArrayList<PolygonStatus> holes = getPolygonStatus(holeIndexes,
+ (currentPolygon.outer ? "inner" : "outer"));
+
+ // these polygons must all be checked for holes
+ polygonWorkingQueue.addAll(holes);
+
+ if (currentPolygon.outer) {
+ // add the original ways to the list of ways that get the line tags of the mp
+ // the joined ways may be changed by the auto closing algorithm
+ outerWaysForLineTagging.addAll(currentPolygon.polygon.getOriginalWays());
+ }
+
+ // calculate the size of the polygon
+ double outerAreaSize = currentPolygon.polygon.getSizeOfArea();
+ if (outerAreaSize > largestSize) {
+ // subtract the holes
+ for (PolygonStatus hole : holes) {
+ outerAreaSize -= hole.polygon.getSizeOfArea();
+ }
+ // is it still larger than the largest known polygon?
+ if (outerAreaSize > largestSize) {
+ largestOuterPolygon = currentPolygon.polygon;
+ largestSize = outerAreaSize;
+ }
+ }
+
+ // check if the polygon is an outer polygon or
+ // if there are some holes
+ boolean processPolygon = currentPolygon.outer
+ || (holes.isEmpty()==false);
+
+ if (processPolygon) {
+ List<Way> singularOuterPolygons;
+ if (holes.isEmpty()) {
+ singularOuterPolygons = Collections
+ .singletonList((Way) new JoinedWay(currentPolygon.polygon));
+ } else {
+ List<Way> innerWays = new ArrayList<Way>(holes.size());
+ for (PolygonStatus polygonHoleStatus : holes) {
+ innerWays.add(polygonHoleStatus.polygon);
+ }
+
+ singularOuterPolygons = cutOutInnerPolygons(currentPolygon.polygon,
+ innerWays);
+ }
+
+ if (singularOuterPolygons.isEmpty()==false) {
+ // handle the tagging
+ if (currentPolygon.outer && hasStyleRelevantTags(this)) {
+ // use the tags of the multipolygon
+ for (Way p : singularOuterPolygons) {
+ // overwrite all tags
+ p.copyTags(this);
+ p.deleteTag("type");
+ }
+ // remove the multipolygon tags in the original ways of the current polygon
+ removeTagsInOrgWays(this, currentPolygon.polygon);
+ } else {
+ // use the tags of the original ways
+ currentPolygon.polygon.mergeTagsFromOrgWays();
+ for (Way p : singularOuterPolygons) {
+ // overwrite all tags
+ p.copyTags(currentPolygon.polygon);
+ }
+ // remove the current polygon tags in its original ways
+ removeTagsInOrgWays(currentPolygon.polygon, currentPolygon.polygon);
+ }
+
+ if (currentPolygon.outer && outmostPolygonProcessing) {
+ // this is the outer most polygon - copy its tags. They will be used
+ // later for tagging of the lines
+
+ // all cut polygons have the same tags - copy them from the first polygon
+ Way outerWay = singularOuterPolygons.get(0);
+ for (Entry<String, String> tag : outerWay.getEntryIteratable()) {
+ outerTags.put(tag.getKey(), tag.getValue());
+ }
+ outmostPolygonProcessing = false;
+ }
+
+ for (Way mpWay : singularOuterPolygons) {
+ // put the cut out polygons to the
+ // final way map
+ if (log.isDebugEnabled())
+ log.debug(mpWay.getId(),mpWay.toTagString());
+
+ // mark this polygons so that only polygon style rules are applied
+ mpWay.addTag(STYLE_FILTER_TAG, STYLE_FILTER_POLYGON);
+ mpWay.addTag(MP_CREATED_TAG, "true");
+
+ if (currentPolygon.outer) {
+ mpWay.addTag("mkgmap:mp_role", "outer");
+ if (isAreaSizeCalculated())
+ mpAreaSize += calcAreaSize(mpWay.getPoints());
+ } else {
+ mpWay.addTag("mkgmap:mp_role", "inner");
+ }
+
+ getMpPolygons().put(mpWay.getId(), mpWay);
+ }
+ }
+ }
+ }
+
+ if (log.isLoggable(Level.WARNING) &&
+ (outmostInnerPolygons.cardinality()+unfinishedPolygons.cardinality()+nestedOuterPolygons.cardinality()+nestedInnerPolygons.cardinality() >= 1)) {
+ log.warn("Multipolygon", toBrowseURL(), toTagString(), "contains errors.");
+
+ BitSet outerUnusedPolys = new BitSet();
+ outerUnusedPolys.or(unfinishedPolygons);
+ outerUnusedPolys.or(outmostInnerPolygons);
+ outerUnusedPolys.or(nestedOuterPolygons);
+ outerUnusedPolys.or(nestedInnerPolygons);
+ outerUnusedPolys.or(unfinishedPolygons);
+ // use only the outer polygons
+ outerUnusedPolys.and(outerPolygons);
+ for (JoinedWay w : getWaysFromPolygonList(outerUnusedPolys)) {
+ outerWaysForLineTagging.addAll(w.getOriginalWays());
+ }
+
+ runIntersectionCheck(unfinishedPolygons);
+ runOutmostInnerPolygonCheck(outmostInnerPolygons);
+ runNestedOuterPolygonCheck(nestedOuterPolygons);
+ runNestedInnerPolygonCheck(nestedInnerPolygons);
+ runWrongInnerPolygonCheck(unfinishedPolygons, innerPolygons);
+
+ // we have at least one polygon that could not be processed
+ // Probably we have intersecting or overlapping polygons
+ // one possible reason is if the relation overlaps the tile
+ // bounds
+ // => issue a warning
+ List<JoinedWay> lostWays = getWaysFromPolygonList(unfinishedPolygons);
+ for (JoinedWay w : lostWays) {
+ log.warn("Polygon", w, "is not processed due to an unknown reason.");
+ logWayURLs(Level.WARNING, "-", w);
+ }
+ }
+
+ if (hasStyleRelevantTags(this) == false) {
+ // add tags to the multipolygon that are taken from the outer ways
+ // they may be required by some hooks (e.g. Area2POIHook)
+ for (Entry<String, String> tags : outerTags.entrySet()) {
+ addTag(tags.getKey(), tags.getValue());
+ }
+ }
+
+ // Go through all original outer ways, create a copy, tag them
+ // with the mp tags and mark them only to be used for polyline processing
+ // This enables the style file to decide if the polygon information or
+ // the simple line information should be used.
+ for (Way orgOuterWay : outerWaysForLineTagging) {
+ Way lineTagWay = new Way(FakeIdGenerator.makeFakeId(), orgOuterWay.getPoints());
+ lineTagWay.addTag(STYLE_FILTER_TAG, STYLE_FILTER_LINE);
+ lineTagWay.addTag(MP_CREATED_TAG, "true");
+ for (Entry<String,String> tag : outerTags.entrySet()) {
+ lineTagWay.addTag(tag.getKey(), tag.getValue());
+
+ // remove the tag from the original way if it has the same value
+ if (tag.getValue().equals(orgOuterWay.getTag(tag.getKey()))) {
+ removeTagsInOrgWays(orgOuterWay, tag.getKey());
+ }
+ }
+
+ if (log.isDebugEnabled())
+ log.debug("Add line way", lineTagWay.getId(), lineTagWay.toTagString());
+ tileWayMap.put(lineTagWay.getId(), lineTagWay);
+ }
+
+ postProcessing();
+ cleanup();
+ }
+
+ protected void postProcessing() {
+
+ if (isAreaSizeCalculated()) {
+ // assign the area size of the whole multipolygon to all outer polygons
+ String mpAreaSizeStr = new DecimalFormat("0.0####################",
+ DecimalFormatSymbols.getInstance(Locale.US)).format(mpAreaSize);
+ for (Way w : mpPolygons.values()) {
+ if ("outer".equals(w.getTag("mkgmap:mp_role"))) {
+ w.addTag("mkgmap:cache_area_size", mpAreaSizeStr);
+ }
+ }
+ }
+
+ for (Way w : mpPolygons.values()) {
+ w.deleteTag("mkgmap:mp_role");
+ }
+
+ // copy all polygons created by the multipolygon algorithm to the global way map
+ tileWayMap.putAll(mpPolygons);
+
+ if (largestOuterPolygon != null) {
+ // check if the mp contains a node with role "label"
+ for (Map.Entry<String, Element> r_e : getElements()) {
+ if (r_e.getValue() instanceof Node && "label".equals(r_e.getKey())) {
+ // yes => use the label node as reference point
+ cOfG = ((Node)r_e.getValue()).getLocation();
+ break;
+ }
+ }
+
+ if (cOfG == null) {
+ // use the center of the largest polygon as reference point
+ cOfG = largestOuterPolygon.getCofG();
+ }
+ }
+ }
+
+ private void runIntersectionCheck(BitSet unfinishedPolys) {
+ if (intersectingPolygons.isEmpty()) {
+ // nothing to do
+ return;
+ }
+
+ log.warn("Some polygons are intersecting. This is not allowed in multipolygons.");
+
+ boolean oneOufOfBbox = false;
+ for (JoinedWay polygon : intersectingPolygons) {
+ int pi = polygons.indexOf(polygon);
+ unfinishedPolys.clear(pi);
+
+ boolean outOfBbox = false;
+ for (Coord c : polygon.getPoints()) {
+ if (!bbox.contains(c)) {
+ outOfBbox = true;
+ oneOufOfBbox = true;
+ break;
+ }
+ }
+
+ logWayURLs(Level.WARNING, (outOfBbox ? "*" : "-"), polygon);
+ }
+
+ for (JoinedWay polygon : intersectingPolygons) {
+ // print out the details of the original ways
+ logFakeWayDetails(Level.WARNING, polygon);
+ }
+
+ if (oneOufOfBbox) {
+ log.warn("Some of these intersections/overlaps may be caused by incomplete data on bounding box edges (*).");
+ }
+ }
+
+ private void runNestedOuterPolygonCheck(BitSet nestedOuterPolygons) {
+ // just print out warnings
+ // the check has been done before
+ for (int wiIndex = nestedOuterPolygons.nextSetBit(0); wiIndex >= 0; wiIndex = nestedOuterPolygons
+ .nextSetBit(wiIndex + 1)) {
+ JoinedWay outerWay = polygons.get(wiIndex);
+ log.warn("Polygon", outerWay, "carries role outer but lies inside an outer polygon. Potentially its role should be inner.");
+ logFakeWayDetails(Level.WARNING, outerWay);
+ }
+ }
+
+ private void runNestedInnerPolygonCheck(BitSet nestedInnerPolygons) {
+ // just print out warnings
+ // the check has been done before
+ for (int wiIndex = nestedInnerPolygons.nextSetBit(0); wiIndex >= 0; wiIndex = nestedInnerPolygons
+ .nextSetBit(wiIndex + 1)) {
+ JoinedWay innerWay = polygons.get(wiIndex);
+ log.warn("Polygon", innerWay, "carries role", getRole(innerWay), "but lies inside an inner polygon. Potentially its role should be outer.");
+ logFakeWayDetails(Level.WARNING, innerWay);
+ }
+ }
+
+ private void runOutmostInnerPolygonCheck(BitSet outmostInnerPolygons) {
+ // just print out warnings
+ // the check has been done before
+ for (int wiIndex = outmostInnerPolygons.nextSetBit(0); wiIndex >= 0; wiIndex = outmostInnerPolygons
+ .nextSetBit(wiIndex + 1)) {
+ JoinedWay innerWay = polygons.get(wiIndex);
+ log.warn("Polygon", innerWay, "carries role", getRole(innerWay), "but is not inside any other polygon. Potentially it does not belong to this multipolygon.");
+ logFakeWayDetails(Level.WARNING, innerWay);
+ }
+ }
+
+ private void runWrongInnerPolygonCheck(BitSet unfinishedPolygons,
+ BitSet innerPolygons) {
+ // find all unfinished inner polygons that are not contained by any
+ BitSet wrongInnerPolygons = findOutmostPolygons(unfinishedPolygons, innerPolygons);
+ if (log.isDebugEnabled()) {
+ log.debug("unfinished", unfinishedPolygons);
+ log.debug("inner", innerPolygons);
+ // other polygon
+ log.debug("wrong", wrongInnerPolygons);
+ }
+ if (!wrongInnerPolygons.isEmpty()) {
+ // we have an inner polygon that is not contained by any outer polygon
+ // check if
+ for (int wiIndex = wrongInnerPolygons.nextSetBit(0); wiIndex >= 0; wiIndex = wrongInnerPolygons
+ .nextSetBit(wiIndex + 1)) {
+ BitSet containedPolygons = new BitSet();
+ containedPolygons.or(unfinishedPolygons);
+ containedPolygons.and(containsMatrix.get(wiIndex));
+
+ JoinedWay innerWay = polygons.get(wiIndex);
+ if (containedPolygons.isEmpty()) {
+ log.warn("Polygon", innerWay, "carries role", getRole(innerWay),
+ "but is not inside any outer polygon. Potentially it does not belong to this multipolygon.");
+ logFakeWayDetails(Level.WARNING, innerWay);
+ } else {
+ log.warn("Polygon", innerWay, "carries role", getRole(innerWay),
+ "but is not inside any outer polygon. Potentially the roles are interchanged with the following",
+ (containedPolygons.cardinality() > 1 ? "ways" : "way"), ".");
+
+ for (int wrIndex = containedPolygons.nextSetBit(0); wrIndex >= 0; wrIndex = containedPolygons
+ .nextSetBit(wrIndex + 1)) {
+ logWayURLs(Level.WARNING, "-", polygons.get(wrIndex));
+ unfinishedPolygons.set(wrIndex);
+ wrongInnerPolygons.set(wrIndex);
+ }
+ logFakeWayDetails(Level.WARNING, innerWay);
+ }
+
+ unfinishedPolygons.clear(wiIndex);
+ wrongInnerPolygons.clear(wiIndex);
+ }
+ }
+ }
+
+ protected void cleanup() {
+ mpPolygons = null;
+ roleMap.clear();
+ containsMatrix = null;
+ polygons = null;
+ bboxArea = null;
+ intersectingPolygons = null;
+ outerWaysForLineTagging = null;
+ outerTags = null;
+
+ unfinishedPolygons = null;
+ innerPolygons = null;
+ taggedInnerPolygons = null;
+ outerPolygons = null;
+ taggedOuterPolygons = null;
+
+ largestOuterPolygon = null;
+ }
+
+ private CutPoint calcNextCutPoint(AreaCutData areaData) {
+ if (areaData.innerAreas == null || areaData.innerAreas.isEmpty()) {
+ return null;
+ }
+
+ Rectangle outerBounds = areaData.outerArea.getBounds();
+
+ if (areaData.innerAreas.size() == 1) {
+ // make it short if there is only one inner area
+ CutPoint cutPoint1 = new CutPoint(CoordinateAxis.LATITUDE, outerBounds);
+ cutPoint1.addArea(areaData.innerAreas.get(0));
+ CutPoint cutPoint2 = new CutPoint(CoordinateAxis.LONGITUDE, outerBounds);
+ cutPoint2.addArea(areaData.innerAreas.get(0));
+ if (cutPoint1.compareTo(cutPoint2) > 0) {
+ return cutPoint1;
+ } else {
+ return cutPoint2;
+ }
+
+ }
+
+ ArrayList<Area> innerStart = new ArrayList<Area>(areaData.innerAreas);
+
+ // first try to cut out all polygons that intersect the boundaries of the outer polygon
+ // this has the advantage that the outer polygon need not be split into two halves
+ for (CoordinateAxis axis : CoordinateAxis.values()) {
+ CutPoint edgeCutPoint = new CutPoint(axis, outerBounds);
+
+ // go through the inner polygon list and use all polygons that intersect the outer polygons bbox at the start
+ Collections.sort(innerStart, (axis == CoordinateAxis.LONGITUDE ? COMP_LONG_START: COMP_LAT_START));
+ for (Area anInnerStart : innerStart) {
+ if (axis.getStart(anInnerStart) <= axis.getStart(outerBounds)) {
+ // found a touching area
+ edgeCutPoint.addArea(anInnerStart);
+ } else {
+ break;
+ }
+ }
+ if (edgeCutPoint.getNumberOfAreas() > 0) {
+ // there at least one intersecting inner polygon
+ return edgeCutPoint;
+ }
+
+ Collections.sort(innerStart, (axis == CoordinateAxis.LONGITUDE ? COMP_LONG_STOP: COMP_LAT_STOP));
+ // go through the inner polygon list and use all polygons that intersect the outer polygons bbox at the stop
+ for (Area anInnerStart : innerStart) {
+ if (axis.getStop(anInnerStart) >= axis.getStop(outerBounds)) {
+ // found a touching area
+ edgeCutPoint.addArea(anInnerStart);
+ } else {
+ break;
+ }
+ }
+ if (edgeCutPoint.getNumberOfAreas() > 0) {
+ // there at least one intersecting inner polygon
+ return edgeCutPoint;
+ }
+ }
+
+
+ ArrayList<CutPoint> bestCutPoints = new ArrayList<CutPoint>(CoordinateAxis.values().length);
+ for (CoordinateAxis axis : CoordinateAxis.values()) {
+ CutPoint bestCutPoint = new CutPoint(axis, outerBounds);
+ CutPoint currentCutPoint = new CutPoint(axis, outerBounds);
+
+ Collections.sort(innerStart, (axis == CoordinateAxis.LONGITUDE ? COMP_LONG_START: COMP_LAT_START));
+
+ for (Area anInnerStart : innerStart) {
+ currentCutPoint.addArea(anInnerStart);
+
+ if (currentCutPoint.compareTo(bestCutPoint) > 0) {
+ bestCutPoint = currentCutPoint.duplicate();
+ }
+ }
+ bestCutPoints.add(bestCutPoint);
+ }
+
+ return Collections.max(bestCutPoints);
+
+ }
+
+ /**
+ * Cut out all inner polygons from the outer polygon. This will divide the outer
+ * polygon in several polygons.
+ *
+ * @param outerPolygon
+ * the outer polygon
+ * @param innerPolygons
+ * a list of inner polygons
+ * @return a list of polygons that make the outer polygon cut by the inner
+ * polygons
+ */
+ private List<Way> cutOutInnerPolygons(Way outerPolygon, List<Way> innerPolygons) {
+ if (innerPolygons.isEmpty()) {
+ Way outerWay = new JoinedWay(outerPolygon);
+ if (log.isDebugEnabled()) {
+ log.debug("Way", outerPolygon.getId(), "splitted to way", outerWay.getId());
+ }
+ return Collections.singletonList(outerWay);
+ }
+
+ // use the java.awt.geom.Area class because it's a quick
+ // implementation of what's needed
+
+ // this list contains all non overlapping and singular areas
+ // of the outerPolygon
+ Queue<AreaCutData> areasToCut = new LinkedList<AreaCutData>();
+ Collection<Area> finishedAreas = new ArrayList<Area>(innerPolygons.size());
+
+ // create a list of Area objects from the outerPolygon (clipped to the bounding box)
+ List<Area> outerAreas = createAreas(outerPolygon, true);
+
+ // create the inner areas
+ List<Area> innerAreas = new ArrayList<Area>(innerPolygons.size()+2);
+ for (Way innerPolygon : innerPolygons) {
+ // don't need to clip to the bounding box because
+ // these polygons are just used to cut out holes
+ innerAreas.addAll(createAreas(innerPolygon, false));
+ }
+
+ // initialize the cut data queue
+ if (innerAreas.isEmpty()) {
+ // this is a multipolygon without any inner areas
+ // nothing to cut
+ finishedAreas.addAll(outerAreas);
+ } else if (outerAreas.size() == 1) {
+ // there is one outer area only
+ // it is checked before that all inner areas are inside this outer area
+ AreaCutData initialCutData = new AreaCutData();
+ initialCutData.outerArea = outerAreas.get(0);
+ initialCutData.innerAreas = innerAreas;
+ areasToCut.add(initialCutData);
+ } else {
+ // multiple outer areas
+ for (Area outerArea : outerAreas) {
+ AreaCutData initialCutData = new AreaCutData();
+ initialCutData.outerArea = outerArea;
+ initialCutData.innerAreas = new ArrayList<Area>(innerAreas
+ .size());
+ for (Area innerArea : innerAreas) {
+ if (outerArea.getBounds().intersects(
+ innerArea.getBounds())) {
+ initialCutData.innerAreas.add(innerArea);
+ }
+ }
+
+ if (initialCutData.innerAreas.isEmpty()) {
+ // this is either an error
+ // or the outer area has been cut into pieces on the tile bounds
+ finishedAreas.add(outerArea);
+ } else {
+ areasToCut.add(initialCutData);
+ }
+ }
+ }
+
+ while (!areasToCut.isEmpty()) {
+ AreaCutData areaCutData = areasToCut.poll();
+ CutPoint cutPoint = calcNextCutPoint(areaCutData);
+
+ if (cutPoint == null) {
+ finishedAreas.add(areaCutData.outerArea);
+ continue;
+ }
+
+ assert cutPoint.getNumberOfAreas() > 0 : "Number of cut areas == 0 in mp "+getId();
+
+ // cut out the holes
+ for (Area cutArea : cutPoint.getAreas()) {
+ areaCutData.outerArea.subtract(cutArea);
+ }
+
+ if (areaCutData.outerArea.isEmpty()) {
+ // this outer area space can be abandoned
+ continue;
+ }
+
+ // the inner areas of the cut point have been processed
+ // they are no longer needed
+ for (Area cutArea : cutPoint.getAreas()) {
+ ListIterator<Area> areaIter = areaCutData.innerAreas.listIterator();
+ while (areaIter.hasNext()) {
+ Area a = areaIter.next();
+ if (a == cutArea) {
+ areaIter.remove();
+ break;
+ }
+ }
+ }
+ // remove all does not seem to work. It removes more than the identical areas.
+// areaCutData.innerAreas.removeAll(cutPoint.getAreas());
+
+ if (areaCutData.outerArea.isSingular()) {
+ // the area is singular
+ // => no further splits necessary
+ if (areaCutData.innerAreas.isEmpty()) {
+ // this area is finished and needs no further cutting
+ finishedAreas.add(areaCutData.outerArea);
+ } else {
+ // read this area to further processing
+ areasToCut.add(areaCutData);
+ }
+ } else {
+ // we need to cut the area into two halves to get singular areas
+ Rectangle r1 = cutPoint.getCutRectangleForArea(areaCutData.outerArea, true);
+ Rectangle r2 = cutPoint.getCutRectangleForArea(areaCutData.outerArea, false);
+
+ // Now find the intersection of these two boxes with the
+ // original polygon. This will make two new areas, and each
+ // area will be one (or more) polygons.
+ Area a1 = areaCutData.outerArea;
+ Area a2 = (Area) a1.clone();
+ a1.intersect(new Area(r1));
+ a2.intersect(new Area(r2));
+
+ if (areaCutData.innerAreas.isEmpty()) {
+ finishedAreas.addAll(Java2DConverter.areaToSingularAreas(a1));
+ finishedAreas.addAll(Java2DConverter.areaToSingularAreas(a2));
+ } else {
+ ArrayList<Area> cuttedAreas = new ArrayList<Area>();
+ cuttedAreas.addAll(Java2DConverter.areaToSingularAreas(a1));
+ cuttedAreas.addAll(Java2DConverter.areaToSingularAreas(a2));
+
+ for (Area nextOuterArea : cuttedAreas) {
+ ArrayList<Area> nextInnerAreas = null;
+ // go through all remaining inner areas and check if they
+ // must be further processed with the nextOuterArea
+ for (Area nonProcessedInner : areaCutData.innerAreas) {
+ if (nextOuterArea.intersects(nonProcessedInner.getBounds2D())) {
+ if (nextInnerAreas == null) {
+ nextInnerAreas = new ArrayList<Area>();
+ }
+ nextInnerAreas.add(nonProcessedInner);
+ }
+ }
+
+ if (nextInnerAreas == null || nextInnerAreas.isEmpty()) {
+ finishedAreas.add(nextOuterArea);
+ } else {
+ AreaCutData outCutData = new AreaCutData();
+ outCutData.outerArea = nextOuterArea;
+ outCutData.innerAreas= nextInnerAreas;
+ areasToCut.add(outCutData);
+ }
+ }
+ }
+ }
+
+ }
+
+ // convert the java.awt.geom.Area back to the mkgmap way
+ List<Way> cuttedOuterPolygon = new ArrayList<Way>(finishedAreas.size());
+ for (Area area : finishedAreas) {
+ Way w = singularAreaToWay(area, FakeIdGenerator.makeFakeId());
+ if (w != null) {
+ w.copyTags(outerPolygon);
+ cuttedOuterPolygon.add(w);
+ if (log.isDebugEnabled()) {
+ log.debug("Way", outerPolygon.getId(), "splitted to way", w.getId());
+ }
+ }
+ }
+
+ return cuttedOuterPolygon;
+ }
+
+ /**
+ * Create the areas that are enclosed by the way. Usually the result should
+ * only be one area but some ways contain intersecting lines. To handle these
+ * erroneous cases properly the method might return a list of areas.
+ *
+ * @param w a closed way
+ * @param clipBbox true if the areas should be clipped to the bounding box; false else
+ * @return a list of enclosed ares
+ */
+ private List<Area> createAreas(Way w, boolean clipBbox) {
+ Area area = Java2DConverter.createArea(w.getPoints());
+ if (clipBbox && !bboxArea.contains(area.getBounds())) {
+ // the area intersects the bounding box => clip it
+ area.intersect(bboxArea);
+ }
+ List<Area> areaList = Java2DConverter.areaToSingularAreas(area);
+ if (log.isDebugEnabled()) {
+ log.debug("Bbox clipped way",w.getId()+"=>",areaList.size(),"distinct area(s).");
+ }
+ return areaList;
+ }
+
+ /**
+ * Convert an area to an mkgmap way. The caller must ensure that the area is singular.
+ * Otherwise only the first part of the area is converted.
+ *
+ * @param area
+ * the area
+ * @param wayId
+ * the wayid for the new way
+ * @return a new mkgmap way
+ */
+ private Way singularAreaToWay(Area area, long wayId) {
+ List<Coord> points = Java2DConverter.singularAreaToPoints(area);
+ if (points == null || points.isEmpty()) {
+ if (log.isDebugEnabled()) {
+ log.debug("Empty area", wayId + ".", toBrowseURL());
+ }
+ return null;
+ }
+
+ return new Way(wayId, points);
+ }
+
+ /**
+ * Retrieves if the given element contains tags that may be relevant
+ * for style processing. If it has no relevant tag it will probably be
+ * dropped by the style.
+ *
+ * @param element the OSM element
+ * @return <code>true</code> has style relevant tags
+ */
+ protected boolean hasStyleRelevantTags(Element element) {
+ if (element instanceof MultiPolygonRelation) {
+ // in case it is a multipolygon the TAGS_INCOMPLETE_TAG declares
+ // that the mp has additional tags removed by the file loader
+ if (element.isBoolTag(OsmHandler.TAGS_INCOMPLETE_TAG)) {
+ return true;
+ }
+ }
+
+ for (Map.Entry<String, String> tagEntry : element.getEntryIteratable()) {
+ String tagName = tagEntry.getKey();
+ // all tags are style relevant
+ // except: type (for relations), mkgmap:*
+ boolean isStyleRelevant = (element instanceof Relation && tagName.equals("type")) == false
+ && tagName.startsWith("mkgmap:") == false;
+ if (isStyleRelevant) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks if this mp should be processed or if it is needless to process it
+ * because there is no result.
+ * @param ways the list of ways of the mp
+ * @return <code>true</code> the mp processing will have a result;
+ * <code>false</code> the mp processing will fail
+ */
+ private boolean isMpProcessable(Collection<Way> ways) {
+ // Check if the multipolygon itself or the member ways have a
+ // tag. If not it does not make sense to process the mp because
+ // the output will not change anything
+ if (hasStyleRelevantTags(this)) {
+ return true;
+ }
+
+ for (Way w : ways) {
+ if (hasStyleRelevantTags(w)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Creates a matrix which polygon contains which polygon. A polygon does not
+ * contain itself.
+ *
+ * @param polygonList
+ * a list of polygons
+ */
+ protected void createContainsMatrix(List<JoinedWay> polygonList) {
+ containsMatrix = new ArrayList<BitSet>();
+ for (int i = 0; i < polygonList.size(); i++) {
+ containsMatrix.add(new BitSet());
+ }
+
+ long t1 = System.currentTimeMillis();
+
+ if (log.isDebugEnabled())
+ log.debug("createContainsMatrix listSize:", polygonList.size());
+
+ // use this matrix to check which matrix element has been
+ // calculated
+ ArrayList<BitSet> finishedMatrix = new ArrayList<BitSet>(polygonList
+ .size());
+
+ for (int i = 0; i < polygonList.size(); i++) {
+ BitSet matrixRow = new BitSet();
+ // a polygon does not contain itself
+ matrixRow.set(i);
+ finishedMatrix.add(matrixRow);
+ }
+
+ for (int rowIndex = 0; rowIndex < polygonList.size(); rowIndex++) {
+ JoinedWay potentialOuterPolygon = polygonList.get(rowIndex);
+ BitSet containsColumns = containsMatrix.get(rowIndex);
+ BitSet finishedCol = finishedMatrix.get(rowIndex);
+
+ // get all non calculated columns of the matrix
+ for (int colIndex = finishedCol.nextClearBit(0); colIndex >= 0
+ && colIndex < polygonList.size(); colIndex = finishedCol
+ .nextClearBit(colIndex + 1)) {
+
+ JoinedWay innerPolygon = polygonList.get(colIndex);
+
+ if (potentialOuterPolygon.getBounds().intersects(
+ innerPolygon.getBounds()))
+ {
+ boolean contains = contains(potentialOuterPolygon,
+ innerPolygon);
+
+ if (contains) {
+ containsColumns.set(colIndex);
+
+ // we also know that the inner polygon does not contain the
+ // outer polygon
+ // so we can set the finished bit for this matrix
+ // element
+ finishedMatrix.get(colIndex).set(rowIndex);
+
+ // additionally we know that the outer polygon contains all
+ // polygons that are contained by the inner polygon
+ containsColumns.or(containsMatrix.get(colIndex));
+ finishedCol.or(containsColumns);
+ }
+ } else {
+ // both polygons do not intersect
+ // we can flag both matrix elements as finished
+ finishedMatrix.get(colIndex).set(rowIndex);
+ finishedMatrix.get(rowIndex).set(colIndex);
+ }
+ // this matrix element is calculated now
+ finishedCol.set(colIndex);
+ }
+ }
+
+ if (log.isDebugEnabled()) {
+ long t2 = System.currentTimeMillis();
+ log.debug("createMatrix for", polygonList.size(), "polygons took",
+ (t2 - t1), "ms");
+
+ log.debug("Containsmatrix:");
+ int i = 0;
+ boolean noContained = true;
+ for (BitSet b : containsMatrix) {
+ if (b.isEmpty()==false) {
+ log.debug(i,"contains",b);
+ noContained = false;
+ }
+ i++;
+ }
+ if (noContained) {
+ log.debug("Matrix is empty");
+ }
+ }
+ }
+
+ /**
+ * Checks if the polygon with polygonIndex1 contains the polygon with polygonIndex2.
+ *
+ * @return true if polygon(polygonIndex1) contains polygon(polygonIndex2)
+ */
+ private boolean contains(int polygonIndex1, int polygonIndex2) {
+ return containsMatrix.get(polygonIndex1).get(polygonIndex2);
+ }
+
+ /**
+ * Checks if polygon1 contains polygon2.
+ *
+ * @param polygon1
+ * a closed way
+ * @param polygon2
+ * a 2nd closed way
+ * @return true if polygon1 contains polygon2
+ */
+ private boolean contains(JoinedWay polygon1, JoinedWay polygon2) {
+ if (!polygon1.isClosed()) {
+ return false;
+ }
+ // check if the bounds of polygon2 are completely inside/enclosed the bounds
+ // of polygon1
+ if (!polygon1.getBounds().contains(polygon2.getBounds())) {
+ return false;
+ }
+
+ Polygon p = Java2DConverter.createPolygon(polygon1.getPoints());
+ // check first if one point of polygon2 is in polygon1
+
+ // ignore intersections outside the bounding box
+ // so it is necessary to check if there is at least one
+ // point of polygon2 in polygon1 ignoring all points outside the bounding box
+ boolean onePointContained = false;
+ boolean allOnLine = true;
+ for (Coord px : polygon2.getPoints()) {
+ if (p.contains(px.getLongitude(), px.getLatitude())) {
+ // there's one point that is in polygon1 and in the bounding
+ // box => polygon1 may contain polygon2
+ onePointContained = true;
+ if (!locatedOnLine(px, polygon1.getPoints())) {
+ allOnLine = false;
+ break;
+ }
+ } else if (bbox.contains(px)) {
+ // we have to check if the point is on one line of the polygon1
+
+ if (!locatedOnLine(px, polygon1.getPoints())) {
+ // there's one point that is not in polygon1 but inside the
+ // bounding box => polygon1 does not contain polygon2
+ //allOnLine = false;
+ return false;
+ }
+ }
+ }
+
+ if (allOnLine) {
+ onePointContained = false;
+ // all points of polygon2 lie on lines of polygon1
+ // => the middle of each line polygon must NOT lie outside polygon1
+ ArrayList<Coord> middlePoints2 = new ArrayList<Coord>(polygon2.getPoints().size());
+ Coord p1 = null;
+ for (Coord p2 : polygon2.getPoints()) {
+ if (p1 != null) {
+ int mLat = p1.getLatitude()+(int)Math.round((p2.getLatitude()-p1.getLatitude())/2d);
+ int mLong = p1.getLongitude()+(int)Math.round((p2.getLongitude()-p1.getLongitude())/2d);
+ Coord pm = new Coord(mLat, mLong);
+ middlePoints2.add(pm);
+ }
+ p1 = p2;
+ }
+
+ for (Coord px : middlePoints2) {
+ if (p.contains(px.getLongitude(), px.getLatitude())) {
+ // there's one point that is in polygon1 and in the bounding
+ // box => polygon1 may contain polygon2
+ onePointContained = true;
+ break;
+ } else if (bbox.contains(px)) {
+ // we have to check if the point is on one line of the polygon1
+
+ if (!locatedOnLine(px, polygon1.getPoints())) {
+ // there's one point that is not in polygon1 but inside the
+ // bounding box => polygon1 does not contain polygon2
+ return false;
+ }
+ }
+ }
+ }
+
+ if (!onePointContained) {
+ // no point of polygon2 is in polygon1 => polygon1 does not contain polygon2
+ return false;
+ }
+
+ Iterator<Coord> it1 = polygon1.getPoints().iterator();
+ Coord p1_1 = it1.next();
+
+ while (it1.hasNext()) {
+ Coord p1_2 = p1_1;
+ p1_1 = it1.next();
+
+ if (!polygon2.linePossiblyIntersectsWay(p1_1, p1_2)) {
+ // don't check it - this segment of the outer polygon
+ // definitely does not intersect the way
+ continue;
+ }
+
+ int lonMin = Math.min(p1_1.getLongitude(), p1_2.getLongitude());
+ int lonMax = Math.max(p1_1.getLongitude(), p1_2.getLongitude());
+ int latMin = Math.min(p1_1.getLatitude(), p1_2.getLatitude());
+ int latMax = Math.max(p1_1.getLatitude(), p1_2.getLatitude());
+
+ // check all lines of way1 and way2 for intersections
+ Iterator<Coord> it2 = polygon2.getPoints().iterator();
+ Coord p2_1 = it2.next();
+
+ // for speedup we divide the area around the second line into
+ // a 3x3 matrix with lon(-1,0,1) and lat(-1,0,1).
+ // -1 means below min lon/lat of bbox line p1_1-p1_2
+ // 0 means inside the bounding box of the line p1_1-p1_2
+ // 1 means above max lon/lat of bbox line p1_1-p1_2
+ int lonField = p2_1.getLongitude() < lonMin ? -1 : p2_1
+ .getLongitude() > lonMax ? 1 : 0;
+ int latField = p2_1.getLatitude() < latMin ? -1 : p2_1
+ .getLatitude() > latMax ? 1 : 0;
+
+ int prevLonField = lonField;
+ int prevLatField = latField;
+
+ while (it2.hasNext()) {
+ Coord p2_2 = p2_1;
+ p2_1 = it2.next();
+
+ int changes = 0;
+ // check if the field of the 3x3 matrix has changed
+ if ((lonField >= 0 && p1_1.getLongitude() < lonMin)
+ || (lonField <= 0 && p1_1.getLongitude() > lonMax)) {
+ changes++;
+ lonField = p1_1.getLongitude() < lonMin ? -1 : p1_1
+ .getLongitude() > lonMax ? 1 : 0;
+ }
+ if ((latField >= 0 && p1_1.getLatitude() < latMin)
+ || (latField <= 0 && p1_1.getLatitude() > latMax)) {
+ changes++;
+ latField = p1_1.getLatitude() < latMin ? -1 : p1_1
+ .getLatitude() > latMax ? 1 : 0;
+ }
+
+ // an intersection is possible if
+ // latField and lonField has changed
+ // or if we come from or go to the inner matrix field
+ boolean intersectionPossible = (changes == 2)
+ || (latField == 0 && lonField == 0)
+ || (prevLatField == 0 && prevLonField == 0);
+
+ boolean intersects = intersectionPossible
+ && linesCutEachOther(p1_1, p1_2, p2_1, p2_2);
+
+ if (intersects) {
+ if ((polygon1.isClosedArtificially() && !it1.hasNext())
+ || (polygon2.isClosedArtificially() && !it2.hasNext())) {
+ // don't care about this intersection
+ // one of the polygons is closed by this mp code and the
+ // closing segment causes the intersection
+ log.info("Polygon", polygon1, "may contain polygon", polygon2,
+ ". Ignoring artificial generated intersection.");
+ } else if ((!bbox.contains(p1_1))
+ || (!bbox.contains(p1_2))
+ || (!bbox.contains(p2_1))
+ || (!bbox.contains(p2_2))) {
+ // at least one point is outside the bounding box
+ // we ignore the intersection because the ways may not
+ // be complete
+ // due to removals of the tile splitter or osmosis
+ log.info("Polygon", polygon1, "may contain polygon", polygon2,
+ ". Ignoring because at least one point is outside the bounding box.");
+ } else {
+ // store them in the intersection polygons set
+ // the error message will be printed out in the end of
+ // the mp handling
+ intersectingPolygons.add(polygon1);
+ intersectingPolygons.add(polygon2);
+ return false;
+ }
+ }
+
+ prevLonField = lonField;
+ prevLatField = latField;
+ }
+ }
+
+ // don't have any intersection
+ // => polygon1 contains polygon2
+ return true;
+ }
+
+ /**
+ * Checks if the point p is located on one line of the given points.
+ * @param p a point
+ * @param points a list of points; all consecutive points are handled as lines
+ * @return true if p is located on one line given by points
+ */
+ private boolean locatedOnLine(Coord p, List<Coord> points) {
+ Coord cp1 = null;
+ for (Coord cp2 : points) {
+ if (p.equals(cp2)) {
+ return true;
+ }
+
+ try {
+ if (cp1 == null) {
+ // first init
+ continue;
+ }
+
+ if (p.getLongitude() < Math.min(cp1.getLongitude(), cp2
+ .getLongitude())) {
+ continue;
+ }
+ if (p.getLongitude() > Math.max(cp1.getLongitude(), cp2
+ .getLongitude())) {
+ continue;
+ }
+ if (p.getLatitude() < Math.min(cp1.getLatitude(), cp2
+ .getLatitude())) {
+ continue;
+ }
+ if (p.getLatitude() > Math.max(cp1.getLatitude(), cp2
+ .getLatitude())) {
+ continue;
+ }
+
+ double dist = Line2D.ptSegDistSq(cp1.getLongitude(), cp1
+ .getLatitude(), cp2.getLongitude(), cp2.getLatitude(),
+ p.getLongitude(), p.getLatitude());
+
+ if (dist <= OVERLAP_TOLERANCE_DISTANCE) {
+ log.debug("Point", p, "is located on line between", cp1, "and",
+ cp2, ". Distance:", dist);
+ return true;
+ }
+ } finally {
+ cp1 = cp2;
+ }
+ }
+ return false;
+ }
+
+ private boolean lineCutsBbox(Coord p1_1, Coord p1_2) {
+ Coord nw = new Coord(bbox.getMaxLat(), bbox.getMinLong());
+ Coord sw = new Coord(bbox.getMinLat(), bbox.getMinLong());
+ Coord se = new Coord(bbox.getMinLat(), bbox.getMaxLong());
+ Coord ne = new Coord(bbox.getMaxLat(), bbox.getMaxLong());
+ return linesCutEachOther(nw, sw, p1_1, p1_2)
+ || linesCutEachOther(sw, se, p1_1, p1_2)
+ || linesCutEachOther(se, ne, p1_1, p1_2)
+ || linesCutEachOther(ne, nw, p1_1, p1_2);
+ }
+
+ /**
+ * Check if the line p1_1 to p1_2 cuts line p2_1 to p2_2 in two pieces and vice versa.
+ * This is a form of intersection check where it is allowed that one line ends on the
+ * other line or that the two lines overlap.
+ * @param p1_1 first point of line 1
+ * @param p1_2 second point of line 1
+ * @param p2_1 first point of line 2
+ * @param p2_2 second point of line 2
+ * @return true if both lines intersect somewhere in the middle of each other
+ */
+ private boolean linesCutEachOther(Coord p1_1, Coord p1_2, Coord p2_1,
+ Coord p2_2) {
+ int width1 = p1_2.getLongitude() - p1_1.getLongitude();
+ int width2 = p2_2.getLongitude() - p2_1.getLongitude();
+
+ int height1 = p1_2.getLatitude() - p1_1.getLatitude();
+ int height2 = p2_2.getLatitude() - p2_1.getLatitude();
+
+ int denominator = ((height2 * width1) - (width2 * height1));
+ if (denominator == 0) {
+ // the lines are parallel
+ // they might overlap but this is ok for this test
+ return false;
+ }
+
+ int x1Mx3 = p1_1.getLongitude() - p2_1.getLongitude();
+ int y1My3 = p1_1.getLatitude() - p2_1.getLatitude();
+
+ double isx = (double)((width2 * y1My3) - (height2 * x1Mx3))
+ / denominator;
+ if (isx < 0 || isx > 1) {
+ return false;
+ }
+
+ double isy = (double)((width1 * y1My3) - (height1 * x1Mx3))
+ / denominator;
+
+ if (isy < 0 || isy > 1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private List<JoinedWay> getWaysFromPolygonList(BitSet selection) {
+ if (selection.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List<JoinedWay> wayList = new ArrayList<JoinedWay>(selection
+ .cardinality());
+ for (int i = selection.nextSetBit(0); i >= 0; i = selection.nextSetBit(i + 1)) {
+ wayList.add(polygons.get(i));
+ }
+ return wayList;
+ }
+
+ private void logWayURLs(Level level, String preMsg, Way way) {
+ if (log.isLoggable(level)) {
+ if (way instanceof JoinedWay) {
+ if (((JoinedWay) way).getOriginalWays().isEmpty()) {
+ log.warn("Way", way, "does not contain any original ways");
+ }
+ for (Way segment : ((JoinedWay) way).getOriginalWays()) {
+ if (preMsg == null || preMsg.length() == 0) {
+ log.log(level, segment.toBrowseURL());
+ } else {
+ log.log(level, preMsg, segment.toBrowseURL());
+ }
+ }
+ } else {
+ if (preMsg == null || preMsg.length() == 0) {
+ log.log(level, way.toBrowseURL());
+ } else {
+ log.log(level, preMsg, way.toBrowseURL());
+ }
+ }
+ }
+ }
+
+ /**
+ * Logs the details of the original ways of a way with a fake id. This is
+ * primarily necessary for the sea multipolygon because it consists of
+ * faked ways only. In this case logging messages can be improved by the
+ * start and end points of the faked ways.
+ * @param logLevel the logging level
+ * @param fakeWay a way composed by other ways with faked ids
+ */
+ private void logFakeWayDetails(Level logLevel, JoinedWay fakeWay) {
+ if (log.isLoggable(logLevel) == false) {
+ return;
+ }
+
+ // only log if this is an artificial multipolygon
+ if (FakeIdGenerator.isFakeId(getId()) == false) {
+ return;
+ }
+
+ boolean containsOrgFakeWay = false;
+ for (Way orgWay : fakeWay.getOriginalWays()) {
+ if (FakeIdGenerator.isFakeId(orgWay.getId())) {
+ containsOrgFakeWay = true;
+ }
+ }
+
+ if (containsOrgFakeWay == false) {
+ return;
+ }
+
+ // the fakeWay consists only of other faked ways
+ // there should be more information about these ways
+ // so that it is possible to retrieve the original
+ // OSM ways
+ // => log the start and end points
+
+ for (Way orgWay : fakeWay.getOriginalWays()) {
+ log.log(logLevel, " Way",orgWay.getId(),"is composed of other artificial ways. Details:");
+ log.log(logLevel, " Start:",orgWay.getPoints().get(0).toOSMURL());
+ if (orgWay.isClosed()) {
+ // the way is closed so start==end - log the point in the middle of the way
+ int mid = orgWay.getPoints().size()/2;
+ log.log(logLevel, " Mid: ",orgWay.getPoints().get(mid).toOSMURL());
+ } else {
+ log.log(logLevel, " End: ",orgWay.getPoints().get(orgWay.getPoints().size()-1).toOSMURL());
+ }
+ }
+ }
+
+ protected void tagOuterWays() {
+ Map<String, String> tags;
+ if (hasStyleRelevantTags(this)) {
+ tags = new HashMap<String, String>();
+ for (Entry<String, String> relTag : getEntryIteratable()) {
+ tags.put(relTag.getKey(), relTag.getValue());
+ }
+ } else {
+ tags = JoinedWay.getMergedTags(outerWaysForLineTagging);
+ }
+
+
+ // Go through all original outer ways, create a copy, tag them
+ // with the mp tags and mark them only to be used for polyline processing
+ // This enables the style file to decide if the polygon information or
+ // the simple line information should be used.
+ for (Way orgOuterWay : outerWaysForLineTagging) {
+ Way lineTagWay = new Way(FakeIdGenerator.makeFakeId(), orgOuterWay.getPoints());
+ lineTagWay.addTag(STYLE_FILTER_TAG, STYLE_FILTER_LINE);
+ lineTagWay.addTag(MP_CREATED_TAG, "true");
+ for (Entry<String,String> tag : tags.entrySet()) {
+ lineTagWay.addTag(tag.getKey(), tag.getValue());
+
+ // remove the tag from the original way if it has the same value
+ if (tag.getValue().equals(orgOuterWay.getTag(tag.getKey()))) {
+ removeTagsInOrgWays(orgOuterWay, tag.getKey());
+ }
+ }
+
+ if (log.isDebugEnabled())
+ log.debug("Add line way", lineTagWay.getId(), lineTagWay.toTagString());
+ tileWayMap.put(lineTagWay.getId(), lineTagWay);
+ }
+ }
+
+
+ /**
+ * Marks all tags of the original ways of the given JoinedWay that are also
+ * contained in the given tagElement for removal.
+ *
+ * @param tagElement
+ * an element contains the tags to be removed
+ * @param way
+ * a joined way
+ */
+ private void removeTagsInOrgWays(Element tagElement, JoinedWay way) {
+ for (Entry<String, String> tag : tagElement.getEntryIteratable()) {
+ removeTagInOrgWays(way, tag.getKey(), tag.getValue());
+ }
+ }
+
+ /**
+ * Mark the given tag of all original ways of the given JoinedWay.
+ *
+ * @param way
+ * a joined way
+ * @param tagname
+ * the tag to be removed (<code>null</code> means remove all
+ * tags)
+ * @param tagvalue
+ * the value of the tag to be removed (<code>null</code> means
+ * don't check the value)
+ */
+ private void removeTagInOrgWays(JoinedWay way, String tagname,
+ String tagvalue) {
+ for (Way w : way.getOriginalWays()) {
+ if (w instanceof JoinedWay) {
+ // remove the tags recursively
+ removeTagInOrgWays((JoinedWay) w, tagname, tagvalue);
+ continue;
+ }
+
+ boolean remove = false;
+ if (tagname == null) {
+ // remove all tags
+ remove = true;
+ } else if (tagvalue == null) {
+ // remove the tag without comparing the value
+ remove = w.getTag(tagname) != null;
+ } else if (tagvalue.equals(w.getTag(tagname))) {
+ remove = true;
+ }
+
+ if (remove) {
+ if (tagname == null) {
+ // remove all tags
+ if (log.isDebugEnabled())
+ log.debug("Will remove all tags from", w.getId(), w
+ .toTagString());
+ removeTagsInOrgWays(w, tagname);
+ } else {
+ if (log.isDebugEnabled())
+ log.debug("Will remove", tagname + "="
+ + w.getTag(tagname), "from way", w.getId(), w
+ .toTagString());
+ removeTagsInOrgWays(w, tagname);
+ }
+ }
+ }
+ }
+
+ protected void removeTagsInOrgWays(Way way, String tag) {
+ if (tag == null) {
+ way.addTag(ElementSaver.MKGMAP_REMOVE_TAG, ElementSaver.MKGMAP_REMOVE_TAG_ALL_KEY);
+ return;
+ }
+ if (tag.isEmpty()) {
+ return;
+ }
+ String removedTagsTag = way.getTag(ElementSaver.MKGMAP_REMOVE_TAG);
+ if (ElementSaver.MKGMAP_REMOVE_TAG_ALL_KEY.equals(removedTagsTag)) {
+ // cannot add more tags to remove
+ return;
+ }
+
+ if (removedTagsTag == null) {
+ way.addTag(ElementSaver.MKGMAP_REMOVE_TAG, tag);
+ } else if (removedTagsTag.equals(tag) == false) {
+ way.addTag(ElementSaver.MKGMAP_REMOVE_TAG, removedTagsTag+";"+tag);
+ }
+ }
+
+ /**
+ * Flag if the area size of the mp should be calculated and added as tag.
+ * @return {@code true} area size should be calculated; {@code false} area size should not be calculated
+ */
+ protected boolean isAreaSizeCalculated() {
+ return true;
+ }
+
+ protected Map<Long, Way> getTileWayMap() {
+ return tileWayMap;
+ }
+
+ protected Map<Long, Way> getMpPolygons() {
+ return mpPolygons;
+ }
+
+ protected uk.me.parabola.imgfmt.app.Area getBbox() {
+ return bbox;
+ }
+
+ /**
+ * Calculates a unitless number that gives a value for the size
+ * of the area. The calculation does not correct to any earth
+ * coordinate system. It uses the simple rectangular coordinate
+ * system of garmin coordinates.
+ *
+ * @param polygon the points of the area
+ * @return the size of the area (unitless)
+ */
+ public static double calcAreaSize(List<Coord> polygon) {
+ if (polygon.size() < 4 || polygon.get(0).equals(polygon.get(polygon.size()-1)) == false) {
+ return 0;
+ }
+ double area = 0;
+ Iterator<Coord> polyIter = polygon.iterator();
+ Coord c2 = polyIter.next();
+ while (polyIter.hasNext()) {
+ Coord c1 = c2;
+ c2 = polyIter.next();
+ area += (double) (c2.getLongitude() + c1.getLongitude())
+ * (c1.getLatitude() - c2.getLatitude());
+ }
+ area /= 2.0d;
+ return Math.abs(area);
+ }
+
+
+ /**
+ * This is a helper class that gives access to the original
+ * segments of a joined way.
+ */
+ public static final class JoinedWay extends Way {
+ private final List<Way> originalWays;
+ private boolean closedArtificially;
+
+ private int minLat;
+ private int maxLat;
+ private int minLon;
+ private int maxLon;
+ private Rectangle bounds;
+
+ public JoinedWay(Way originalWay) {
+ super(FakeIdGenerator.makeFakeId(), originalWay.getPoints());
+ this.originalWays = new ArrayList<Way>();
+ addWay(originalWay);
+
+ // we have to initialize the min/max values
+ Coord c0 = originalWay.getPoints().get(0);
+ minLat = maxLat = c0.getLatitude();
+ minLon = maxLon = c0.getLongitude();
+
+ updateBounds(originalWay.getPoints());
+ }
+
+ public void addPoint(int index, Coord point) {
+ getPoints().add(index, point);
+ updateBounds(point);
+ }
+
+ public void addPoint(Coord point) {
+ super.addPoint(point);
+ updateBounds(point);
+ }
+
+ private void updateBounds(List<Coord> pointList) {
+ for (Coord c : pointList) {
+ updateBounds(c.getLatitude(),c.getLongitude());
+ }
+ }
+
+ private void updateBounds (JoinedWay other){
+ updateBounds(other.minLat,other.minLon);
+ updateBounds(other.maxLat,other.maxLon);
+ }
+
+ private void updateBounds(int lat, int lon) {
+ if (lat < minLat) {
+ minLat = lat;
+ bounds = null;
+ } else if (lat > maxLat) {
+ maxLat = lat;
+ bounds = null;
+ }
+
+ if (lon < minLon) {
+ minLon = lon;
+ bounds = null;
+ } else if (lon > maxLon) {
+ maxLon = lon;
+ bounds = null;
+ }
+
+
+ }
+ private void updateBounds(Coord point) {
+ updateBounds(point.getLatitude(), point.getLongitude());
+ }
+
+ /**
+ * Checks if this way intersects the given bounding box at least with
+ * one point.
+ *
+ * @param bbox
+ * the bounding box
+ * @return <code>true</code> if this way intersects or touches the
+ * bounding box; <code>false</code> else
+ */
+ public boolean intersects(uk.me.parabola.imgfmt.app.Area bbox) {
+ return (maxLat >= bbox.getMinLat() &&
+ minLat <= bbox.getMaxLat() &&
+ maxLon >= bbox.getMinLong() &&
+ minLon <= bbox.getMaxLong());
+ }
+
+ public Rectangle getBounds() {
+ if (bounds == null) {
+ // note that we increase the rectangle by 1 because intersects
+ // checks
+ // only the interior
+ bounds = new Rectangle(minLon - 1, minLat - 1, maxLon - minLon
+ + 2, maxLat - minLat + 2);
+ }
+
+ return bounds;
+ }
+
+ public boolean linePossiblyIntersectsWay(Coord p1, Coord p2) {
+ return getBounds().intersectsLine(p1.getLongitude(),
+ p1.getLatitude(), p2.getLongitude(), p2.getLatitude());
+ }
+
+ public void addWay(Way way) {
+ if (way instanceof JoinedWay) {
+ for (Way w : ((JoinedWay) way).getOriginalWays()) {
+ addWay(w);
+ }
+ updateBounds((JoinedWay)way);
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("Joined", this.getId(), "with", way.getId());
+ }
+ this.originalWays.add(way);
+ }
+ }
+
+ public void closeWayArtificially() {
+ addPoint(getPoints().get(0));
+ closedArtificially = true;
+ }
+
+ public boolean isClosedArtificially() {
+ return closedArtificially;
+ }
+
+ public static Map<String,String> getMergedTags(Collection<Way> ways) {
+ Map<String,String> mergedTags = new HashMap<String, String>();
+ boolean first = true;
+ for (Way way : ways) {
+ if (first) {
+ // the tags of the first way are copied completely
+ for (Map.Entry<String, String> tag : way.getEntryIteratable()) {
+ mergedTags.put(tag.getKey(), tag.getValue());
+ }
+ first = false;
+ } else {
+ // for all other ways all non matching tags are removed
+ ArrayList<String> tagsToRemove = null;
+ for (Map.Entry<String, String> tag : mergedTags.entrySet()) {
+ String wayTagValue = way.getTag(tag.getKey());
+ if (!tag.getValue().equals(wayTagValue)) {
+ // the tags are different
+ if (wayTagValue!= null) {
+ if (tagsToRemove == null) {
+ tagsToRemove=new ArrayList<String>();
+ }
+ tagsToRemove.add(tag.getKey());
+ }
+ }
+ }
+ if (tagsToRemove!=null) {
+ for (String tag : tagsToRemove) {
+ mergedTags.remove(tag);
+ }
+ }
+ }
+ }
+ return mergedTags;
+ }
+
+ /**
+ * Tags this way with a merge of the tags of all original ways.
+ */
+ public void mergeTagsFromOrgWays() {
+ if (log.isDebugEnabled()) {
+ log.debug("Way",getId(),"merge tags from",getOriginalWays().size(),"ways");
+ }
+ removeAllTags();
+
+ Map<String,String> mergedTags = getMergedTags(getOriginalWays());
+ for (Entry<String,String> tag : mergedTags.entrySet()) {
+ addTag(tag.getKey(),tag.getValue());
+ }
+ }
+
+ public List<Way> getOriginalWays() {
+ return originalWays;
+ }
+
+ /**
+ * Retrieves a measurement of the area covered by this polygon. The
+ * returned value has no unit. It is just a rough comparable value
+ * because it uses a rectangular coordinate system without correction.
+ * @return size of the covered areas (0 if the way is not closed)
+ */
+ public double getSizeOfArea() {
+ return MultiPolygonRelation.calcAreaSize(getPoints());
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder(200);
+ sb.append(getId());
+ sb.append("(");
+ sb.append(getPoints().size());
+ sb.append("P)(");
+ boolean first = true;
+ for (Way w : getOriginalWays()) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(",");
+ }
+ sb.append(w.getId());
+ sb.append("[");
+ sb.append(w.getPoints().size());
+ sb.append("P]");
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+ }
+
+ public static class PolygonStatus {
+ public final boolean outer;
+ public final int index;
+ public final JoinedWay polygon;
+
+ public PolygonStatus(boolean outer, int index, JoinedWay polygon) {
+ this.outer = outer;
+ this.index = index;
+ this.polygon = polygon;
+ }
+
+ public String toString() {
+ return polygon+"_"+outer;
+ }
+ }
+
+ private static class AreaCutData {
+ Area outerArea;
+ List<Area> innerAreas;
+ }
+
+ private static final int CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD = 1<<11;
+ private static final int CUT_POINT_CLASSIFICATION_BAD_THRESHOLD = 1<<8;
+ private static class CutPoint implements Comparable<CutPoint>{
+ private int startPoint = Integer.MAX_VALUE;
+ private int stopPoint = Integer.MIN_VALUE;
+ private Integer cutPoint = null;
+ private final LinkedList<Area> areas;
+ private final Comparator<Area> comparator;
+ private final CoordinateAxis axis;
+ private Rectangle bounds;
+ private final Rectangle outerBounds;
+ private Double minAspectRatio;
+
+ public CutPoint(CoordinateAxis axis, Rectangle outerBounds) {
+ this.axis = axis;
+ this.outerBounds = outerBounds;
+ this.areas = new LinkedList<Area>();
+ this.comparator = (axis == CoordinateAxis.LONGITUDE ? COMP_LONG_STOP : COMP_LAT_STOP);
+ }
+
+ public CutPoint duplicate() {
+ CutPoint newCutPoint = new CutPoint(this.axis, this.outerBounds);
+ newCutPoint.areas.addAll(areas);
+ newCutPoint.startPoint = startPoint;
+ newCutPoint.stopPoint = stopPoint;
+ return newCutPoint;
+ }
+
+ private boolean isGoodCutPoint() {
+ // It is better if the cutting line is on a multiple of 2048.
+ // Otherwise MapSource and QLandkarteGT paints gaps between the cuts
+ return getCutPoint() % CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD == 0;
+ }
+
+ private boolean isBadCutPoint() {
+ int d1 = getCutPoint() - startPoint;
+ int d2 = stopPoint - getCutPoint();
+ return Math.min(d1, d2) < CUT_POINT_CLASSIFICATION_BAD_THRESHOLD;
+ }
+
+ private boolean isStartCut() {
+ return (startPoint <= axis.getStart(outerBounds));
+ }
+
+ private boolean isStopCut() {
+ return (stopPoint >= axis.getStop(outerBounds));
+ }
+
+ /**
+ * Calculates the point where the cut should be applied.
+ * @return the point of cut
+ */
+ public int getCutPoint() {
+ if (cutPoint != null) {
+ // already calculated => just return it
+ return cutPoint;
+ }
+
+ if (startPoint == stopPoint) {
+ // there is no choice => return the one possible point
+ cutPoint = startPoint;
+ return cutPoint;
+ }
+
+ if (isStartCut()) {
+ // the polygons can be cut out at the start of the sector
+ // thats good because the big polygon need not to be cut into two halves
+ cutPoint = startPoint;
+ return cutPoint;
+ }
+
+ if (isStopCut()) {
+ // the polygons can be cut out at the end of the sector
+ // thats good because the big polygon need not to be cut into two halves
+ cutPoint = startPoint;
+ return cutPoint;
+ }
+
+ // try to cut with a good aspect ratio so try the middle of the polygon to be cut
+ int midOuter = axis.getStart(outerBounds)+(axis.getStop(outerBounds) - axis.getStart(outerBounds)) / 2;
+ cutPoint = midOuter;
+
+ if (midOuter < startPoint) {
+ // not possible => the start point is greater than the middle so correct to the startPoint
+ cutPoint = startPoint;
+
+ if (((cutPoint & ~(CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD-1)) + CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD) <= stopPoint) {
+ cutPoint = ((cutPoint & ~(CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD-1)) + CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD);
+ }
+
+ } else if (midOuter > stopPoint) {
+ // not possible => the stop point is smaller than the middle so correct to the stopPoint
+ cutPoint = stopPoint;
+
+ if ((cutPoint & ~(CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD-1)) >= startPoint) {
+ cutPoint = (cutPoint & ~(CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD-1));
+ }
+ }
+
+
+ // try to find a cut point that is a multiple of 2048 to
+ // avoid that gaps are painted by MapSource and QLandkarteGT
+ // between the cutting lines
+ int cutMod = cutPoint % CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD;
+ if (cutMod == 0) {
+ return cutPoint;
+ }
+
+ int cut1 = (cutMod > 0 ? cutPoint-cutMod : cutPoint - CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD- cutMod);
+ if (cut1 >= startPoint && cut1 <= stopPoint) {
+ cutPoint = cut1;
+ return cutPoint;
+ }
+
+ int cut2 = (cutMod > 0 ? cutPoint + CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD -cutMod : cutPoint - cutMod);
+ if (cut2 >= startPoint && cut2 <= stopPoint) {
+ cutPoint = cut2;
+ return cutPoint;
+ }
+
+ return cutPoint;
+ }
+
+ public Rectangle getCutRectangleForArea(Area toCut, boolean firstRect) {
+ return getCutRectangleForArea(toCut.getBounds(), firstRect);
+ }
+
+ public Rectangle getCutRectangleForArea(Rectangle areaRect, boolean firstRect) {
+ if (axis == CoordinateAxis.LONGITUDE) {
+ int newWidth = getCutPoint()-areaRect.x;
+ if (firstRect) {
+ return new Rectangle(areaRect.x, areaRect.y, newWidth, areaRect.height);
+ } else {
+ return new Rectangle(areaRect.x+newWidth, areaRect.y, areaRect.width-newWidth, areaRect.height);
+ }
+ } else {
+ int newHeight = getCutPoint()-areaRect.y;
+ if (firstRect) {
+ return new Rectangle(areaRect.x, areaRect.y, areaRect.width, newHeight);
+ } else {
+ return new Rectangle(areaRect.x, areaRect.y+newHeight, areaRect.width, areaRect.height-newHeight);
+ }
+ }
+ }
+
+ public Collection<Area> getAreas() {
+ return areas;
+ }
+
+ public void addArea(Area area) {
+ // remove all areas that do not overlap with the new area
+ while (!areas.isEmpty() && axis.getStop(areas.getFirst()) < axis.getStart(area)) {
+ // remove the first area
+ areas.removeFirst();
+ }
+
+ areas.add(area);
+ Collections.sort(areas, comparator);
+ startPoint = axis.getStart(Collections.max(areas,
+ (axis == CoordinateAxis.LONGITUDE ? COMP_LONG_START
+ : COMP_LAT_START)));
+ stopPoint = axis.getStop(areas.getFirst());
+
+ // reset the cached value => need to be recalculated the next time they are needed
+ bounds = null;
+ cutPoint = null;
+ minAspectRatio = null;
+ }
+
+ public int getNumberOfAreas() {
+ return this.areas.size();
+ }
+
+ /**
+ * Retrieves the minimum aspect ratio of the outer bounds after cutting.
+ *
+ * @return minimum aspect ratio of outer bound after cutting
+ */
+ public double getMinAspectRatio() {
+ if (minAspectRatio == null) {
+ // first get the left/upper cut
+ Rectangle r1 = getCutRectangleForArea(outerBounds, true);
+ double s1_1 = CoordinateAxis.LATITUDE.getSizeOfSide(r1);
+ double s1_2 = CoordinateAxis.LONGITUDE.getSizeOfSide(r1);
+ double ar1 = Math.min(s1_1, s1_2) / Math.max(s1_1, s1_2);
+
+ // second get the right/lower cut
+ Rectangle r2 = getCutRectangleForArea(outerBounds, false);
+ double s2_1 = CoordinateAxis.LATITUDE.getSizeOfSide(r2);
+ double s2_2 = CoordinateAxis.LONGITUDE.getSizeOfSide(r2);
+ double ar2 = Math.min(s2_1, s2_2) / Math.max(s2_1, s2_2);
+
+ // get the minimum
+ minAspectRatio = Math.min(ar1, ar2);
+ }
+ return minAspectRatio;
+ }
+
+ public int compareTo(CutPoint o) {
+ if (this == o) {
+ return 0;
+ }
+ // prefer a cut at the boundaries
+ if (isStartCut() && o.isStartCut() == false) {
+ return 1;
+ }
+ else if (isStartCut() == false && o.isStartCut()) {
+ return -1;
+ }
+ else if (isStopCut() && o.isStopCut() == false) {
+ return 1;
+ }
+ else if (isStopCut() == false && o.isStopCut()) {
+ return -1;
+ }
+
+ // handle the special case that a cut has no area
+ if (getNumberOfAreas() == 0) {
+ if (o.getNumberOfAreas() == 0) {
+ return 0;
+ } else {
+ return -1;
+ }
+ } else if (o.getNumberOfAreas() == 0) {
+ return 1;
+ }
+
+ if (isBadCutPoint() != o.isBadCutPoint()) {
+ if (isBadCutPoint()) {
+ return -1;
+ } else
+ return 1;
+ }
+
+ double dAR = getMinAspectRatio() - o.getMinAspectRatio();
+ if (dAR != 0) {
+ return (dAR > 0 ? 1 : -1);
+ }
+
+ if (isGoodCutPoint() != o.isGoodCutPoint()) {
+ if (isGoodCutPoint())
+ return 1;
+ else
+ return -1;
+ }
+
+ // prefer the larger area that is split
+ double ss1 = axis.getSizeOfSide(getBounds());
+ double ss2 = o.axis.getSizeOfSide(o.getBounds());
+ if (ss1-ss2 != 0)
+ return Double.compare(ss1,ss2);
+
+ int ndiff = getNumberOfAreas()-o.getNumberOfAreas();
+ return ndiff;
+
+ }
+
+ private Rectangle getBounds() {
+ if (bounds == null) {
+ // lazy init
+ bounds = new Rectangle();
+ for (Area a : areas)
+ bounds.add(a.getBounds());
+ }
+ return bounds;
+ }
+
+ public String toString() {
+ return axis +" "+getNumberOfAreas()+" "+startPoint+" "+stopPoint+" "+getCutPoint();
+ }
+ }
+
+ private static enum CoordinateAxis {
+ LATITUDE(false), LONGITUDE(true);
+
+ private CoordinateAxis(boolean useX) {
+ this.useX = useX;
+ }
+
+ private final boolean useX;
+
+ public int getStart(Area area) {
+ return getStart(area.getBounds());
+ }
+
+ public int getStart(Rectangle rect) {
+ return (useX ? rect.x : rect.y);
+ }
+
+ public int getStop(Area area) {
+ return getStop(area.getBounds());
+ }
+
+ public int getStop(Rectangle rect) {
+ return (useX ? rect.x + rect.width : rect.y + rect.height);
+ }
+
+ public double getSizeOfSide(Rectangle rect) {
+ if (useX) {
+ Coord c1 = new Coord(rect.y, getStart(rect));
+ Coord c2 = new Coord(rect.y, getStop(rect));
+ return c1.distance(c2);
+ } else {
+ Coord c1 = new Coord(getStart(rect), rect.x );
+ Coord c2 = new Coord(getStop(rect), rect.x );
+ return c1.distance(c2);
+ }
+ }
+ }
+
+ private static final AreaComparator COMP_LONG_START = new AreaComparator(
+ true, CoordinateAxis.LONGITUDE);
+ private static final AreaComparator COMP_LONG_STOP = new AreaComparator(
+ false, CoordinateAxis.LONGITUDE);
+ private static final AreaComparator COMP_LAT_START = new AreaComparator(
+ true, CoordinateAxis.LATITUDE);
+ private static final AreaComparator COMP_LAT_STOP = new AreaComparator(
+ false, CoordinateAxis.LATITUDE);
+
+ private static class AreaComparator implements Comparator<Area> {
+
+ private final CoordinateAxis axis;
+ private final boolean startPoint;
+
+ public AreaComparator(boolean startPoint, CoordinateAxis axis) {
+ this.startPoint = startPoint;
+ this.axis = axis;
+ }
+
+ public int compare(Area o1, Area o2) {
+ if (o1 == o2) {
+ return 0;
+ }
+
+ if (startPoint) {
+ int cmp = axis.getStart(o1) - axis.getStart(o2);
+ if (cmp == 0) {
+ return axis.getStop(o1) - axis.getStop(o2);
+ } else {
+ return cmp;
+ }
+ } else {
+ int cmp = axis.getStop(o1) - axis.getStop(o2);
+ if (cmp == 0) {
+ return axis.getStart(o1) - axis.getStart(o2);
+ } else {
+ return cmp;
+ }
+ }
+ }
+
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/Node.java b/src/uk/me/parabola/mkgmap/reader/osm/Node.java
new file mode 100644
index 0000000..3413b08
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/Node.java
@@ -0,0 +1,52 @@
+/**
+ * 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
+ * Date: 24-Dec-2006
+ */
+package uk.me.parabola.mkgmap.reader.osm;
+
+import uk.me.parabola.imgfmt.app.Coord;
+
+/**
+ * A node with its own identity. This is a node that is not just being used for
+ * its coordinates (in which case we just use {@link Coord} but has another
+ * use for example it might be a hospital or a candlestick maker.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Node extends Element {
+ private final Coord location;
+
+ public Node(long id, Coord co) {
+ location = co;
+ setId(id);
+ }
+
+ public Coord getLocation() {
+ return location;
+ }
+
+ public String toString() {
+ return "NODE: " + getId() + " @ " + location.toDegreeString();
+ }
+
+ public String kind() {
+ return "node";
+ }
+
+ public Node copy() {
+ Node dup = new Node(getId(), location);
+ dup.copyTags(this);
+ return dup;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/OSMId2ObjectMap.java b/src/uk/me/parabola/mkgmap/reader/osm/OSMId2ObjectMap.java
new file mode 100644
index 0000000..a818309
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/OSMId2ObjectMap.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.reader.osm;
+
+
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
+
+/**
+ * A basic memory efficient Map implementation that stores an OSM id with an Object.
+ * As of 2012, normal OSM IDs still use only 31 bits, but we must support 64 bits.
+ * This map avoids to store many 0 bits by splitting the id into the upper part where
+ * almost all bits are zero and the lower part that changes frequently.
+ * @author GerdP
+ *
+ * @param <V> the type of object that should be stored
+ */
+public class OSMId2ObjectMap<V> {
+ public static final long LOW_ID_MASK = 0x7ffffff;
+ public static final long TOP_ID_MASK = ~LOW_ID_MASK; // the part of the key that is saved in the top HashMap
+ private static final int TOP_ID_SHIFT = Long.numberOfTrailingZeros(TOP_ID_MASK);
+
+ private Long2ObjectOpenHashMap<Int2ObjectOpenHashMap<V>> topMap;
+
+ private int size;
+
+ public OSMId2ObjectMap() {
+ topMap = new Long2ObjectOpenHashMap<Int2ObjectOpenHashMap<V>>();
+ }
+
+ public V put(long key, V object){
+ long topId = key >> TOP_ID_SHIFT;
+ Int2ObjectOpenHashMap<V> midMap = topMap.get(topId);
+ if (midMap == null){
+ midMap = new Int2ObjectOpenHashMap<V>();
+ topMap.put(topId, midMap);
+ }
+ int midId = (int)(key & LOW_ID_MASK);
+ V old = midMap.put(midId, object);
+ if (old == null)
+ size++;
+ return old;
+ }
+
+ public V get(long key){
+ long topId = key >> TOP_ID_SHIFT;
+ Int2ObjectOpenHashMap<V> midMap = topMap.get(topId);
+ if (midMap == null)
+ return null;
+ int midId = (int)(key & LOW_ID_MASK);
+ return midMap.get(midId);
+ }
+ public V remove(long key){
+ long topId = key >> TOP_ID_SHIFT;
+ Int2ObjectOpenHashMap<V> midMap = topMap.get(topId);
+ if (midMap == null)
+ return null;
+ int midId = (int)(key & LOW_ID_MASK);
+ V old = midMap.remove(midId);
+ if (old == null)
+ return null;
+ if (midMap.isEmpty())
+ topMap.remove(topId);
+ size--;
+ return old;
+ }
+
+ public void clear(){
+ topMap.clear();
+ size = 0;
+ }
+
+ public int size(){
+ return size;
+ }
+
+ public boolean isEmpty() {
+ return size == 0;
+ }
+
+ public boolean containsKey(long key) {
+ return get(key) != null;
+ }
+
+}
+
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java b/src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java
new file mode 100644
index 0000000..3354bbf
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java
@@ -0,0 +1,75 @@
+/*
+ * 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: 20-Dec-2006
+ */
+package uk.me.parabola.mkgmap.reader.osm;
+
+import uk.me.parabola.imgfmt.app.Area;
+
+/**
+ * @author Steve Ratcliffe
+ */
+public interface OsmConverter {
+ /**
+ * This takes the way and works out what kind of map feature it is and makes
+ * the relevant call to the mapper callback.
+ *
+ * As a few examples we might want to check for the 'highway' tag, work out
+ * if it is an area of a park etc.
+ *
+ * @param way The OSM way.
+ */
+ public void convertWay(Way way);
+
+ /**
+ * Takes a node (that has its own identity) and converts it from the OSM
+ * type to the Garmin map type.
+ *
+ * @param node The node to convert.
+ */
+ public void convertNode(Node node);
+
+ /**
+ * Takes a relation and applies rules that affect the garmin types
+ * of its contained elements.
+ *
+ * The relation rules are run first. A relation contains references
+ * to a number of nodes, ways and even other relations, as well as its
+ * own set of tags. They have many purposes some of which are not
+ * relevant to styling.
+ *
+ * @param relation The relation to convert.
+ */
+ public void convertRelation(Relation relation);
+
+ /**
+ * Set the bounding box for this map. This should be set before any other
+ * elements are converted if you want to use it.
+ * All elements that are added are clipped to this box, new points are
+ * added as needed at the boundary.
+ *
+ * If a node or a way falls completely outside the boundary then
+ * it would be omitted. This would not normally happen in the way this
+ * option is typically used however.
+ *
+ * @param bbox The bounding area.
+ */
+ public void setBoundingBox(Area bbox);
+
+ /**
+ * Called when all conversion has been done.
+ */
+ public void end();
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/OsmHandler.java b/src/uk/me/parabola/mkgmap/reader/osm/OsmHandler.java
new file mode 100644
index 0000000..5ee23d5
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/OsmHandler.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2006 - 2012.
+ *
+ * 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.reader.osm;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+
+/**
+ * Base class for OSM file handlers.
+ *
+ * @author Steve Ratcliffe
+ */
+public class OsmHandler {
+ // Elements that are read are saved/further processed by these two classes.
+ protected ElementSaver saver;
+ protected OsmReadingHooks hooks;
+
+ private final Map<String, Long> fakeIdMap = new HashMap<String, Long>();
+ private Map<String,Set<String>> deletedTags;
+ private Map<String, String> usedTags;
+
+ // Node references within a way
+ protected long firstNodeRef;
+ protected long lastNodeRef;
+ protected boolean missingNodeRef;
+
+ /**
+ * Tag that is set to <code>true</code> if one or more tags are not loaded.
+ * Only used for multipolygons yet.
+ */
+ public static final String TAGS_INCOMPLETE_TAG = "mkgmap:tagsincomplete";
+
+ /**
+ * Set a set of tags with values that are to be deleted on input.
+ * For each key there is a set of values. If the value set is empty then
+ * all tags with the given key are deleted. If the value set is not empty
+ * then only tags with the given key that has one of the given values are
+ * deleted.
+ *
+ * @param deletedTags A map of tag key, to a set of values to be deleted.
+ */
+ public void setTagsToDelete(Map<String, Set<String>> deletedTags) {
+ this.deletedTags = deletedTags;
+ }
+
+ /**
+ * This sets a list of all the tags that are used in the system.
+ *
+ * Assuming this list is complete, no other tag can have an effect on the output
+ * and can therefore be dropped on input. This reduces memory usage, sometimes
+ * dramatically if there are many useless tags in the input.
+ *
+ * We keep a map of tag-name to tag-name. This allows us to keep only a single
+ * copy of each string. This also results in a reasonable reduction in memory usage.
+ *
+ * @param used The complete set of tags that are used to form the output.
+ */
+ public void setUsedTags(Set<String> used) {
+ if (used == null || used.isEmpty()) {
+ usedTags = null;
+ return;
+ }
+ usedTags = new HashMap<String, String>();
+ for (String s : used) {
+ if (s == null) {
+ continue;
+ }
+ // intern the keys
+ s = s.intern();
+ usedTags.put(s, s);
+ }
+ }
+
+ /**
+ * Some tags are dropped at the input stage. We drop tags that are not going
+ * to be used and there is also an option to provide a file containing tags to
+ * be dropped.
+ *
+ * @param key The tag key.
+ * @param val The tag value.
+ * @return Returns the tag key if this tag should be kept. Returns null if the tag
+ * should be discarded.
+ */
+ protected String keepTag(String key, String val) {
+ if(deletedTags != null) {
+ Set<String> vals = deletedTags.get(key);
+ if(vals != null && (vals.isEmpty() || vals.contains(val))) {
+ return null;
+ }
+ }
+
+ // By returning the value stored in usedTags, instead of the key, we ensure
+ // that the same string is always used so saving some memory.
+ if (usedTags != null)
+ return usedTags.get(key);
+
+ return key;
+ }
+
+ /**
+ * Actually set the bounding box. The boundary values are given.
+ */
+ protected void setBBox(double minlat, double minlong, double maxlat, double maxlong) {
+ Area bbox = new Area(minlat, minlong, maxlat, maxlong);
+ saver.setBoundingBox(bbox);
+ }
+
+ /**
+ * Convert an id as a string to a number. If the id is not a number, then create
+ * a unique number instead.
+ * @param id The id as a string. Does not have to be a numeric quantity.
+ * @return A long id, either parsed from the input, or a unique id generated internally.
+ */
+ protected long idVal(String id) {
+ try {
+ // attempt to parse id as a number
+ return Long.parseLong(id);
+ } catch (NumberFormatException e) {
+ // if that fails, fake a (hopefully) unique value
+ Long fakeIdVal = fakeIdMap.get(id);
+ if(fakeIdVal == null) {
+ fakeIdVal = FakeIdGenerator.makeFakeId();
+ fakeIdMap.put(id, fakeIdVal);
+ }
+ //System.out.printf("%s = 0x%016x\n", id, fakeIdVal);
+ return fakeIdVal;
+ }
+ }
+
+ public void setElementSaver(ElementSaver elementSaver) {
+ this.saver = elementSaver;
+ }
+
+ public void setHooks(OsmReadingHooks plugin) {
+ this.hooks = plugin;
+ }
+
+ /**
+ * Common actions to take when creating a new way.
+ * Reset some state and create the Way object.
+ * @param id The osm id of the new way.
+ * @return The new Way itself.
+ */
+ protected Way startWay(long id) {
+ firstNodeRef = 0;
+ lastNodeRef = 0;
+ missingNodeRef = false;
+ return new Way(id);
+ }
+
+ /**
+ * Common actions to take when a way has been completely read by the parser.
+ * It is saved
+ * @param way The way that was read.
+ */
+ protected void endWay(Way way) {
+ way.setClosed(firstNodeRef == lastNodeRef);
+ way.setComplete(!missingNodeRef);
+
+ saver.addWay(way);
+ hooks.onAddWay(way);
+ }
+
+ /**
+ * Add a coordinate point to the way.
+ * @param way The Way.
+ * @param id The coordinate id.
+ */
+ protected void addCoordToWay(Way way, long id) {
+ lastNodeRef = id;
+ if (firstNodeRef == 0) firstNodeRef = id;
+
+ Coord co = saver.getCoord(id);
+
+ if (co != null) {
+ hooks.onCoordAddedToWay(way, id, co);
+ co = saver.getCoord(id);
+ way.addPoint(co);
+ } else {
+ missingNodeRef = true;
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java b/src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java
new file mode 100644
index 0000000..b78f4a3
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java
@@ -0,0 +1,269 @@
+/*
+ * 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: 22-Sep-2007
+ */
+package uk.me.parabola.mkgmap.reader.osm;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.FormatException;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.LevelInfo;
+import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
+import uk.me.parabola.mkgmap.osmstyle.StyleImpl;
+import uk.me.parabola.mkgmap.osmstyle.StyledConverter;
+import uk.me.parabola.mkgmap.reader.MapperBasedMapDataSource;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * Base class for OSM map sources. It exists so that more than
+ * one version of the api can be supported at a time.
+ *
+ * @author Steve Ratcliffe
+ */
+public abstract class OsmMapDataSource extends MapperBasedMapDataSource
+ implements LoadableMapDataSource, LoadableOsmDataSource
+{
+ private static final Logger log = Logger.getLogger(OsmMapDataSource.class);
+
+ private Style style;
+ private final OsmReadingHooks[] POSSIBLE_HOOKS = {
+ new SeaGenerator(),
+ new MultiPolygonFinishHook(),
+ new LinkDestinationHook(),
+ new UnusedElementsRemoverHook(),
+ new RoutingHook(),
+ new HighwayHooks(),
+ new LocationHook(),
+ new RelationStyleHook(),
+ new POIGeneratorHook(),
+ };
+ protected OsmConverter converter;
+ private final Set<String> usedTags = new HashSet<String>();
+ protected ElementSaver elementSaver;
+ protected OsmReadingHooks osmReadingHooks;
+
+ /**
+ * Get the maps levels to be used for the current map. This can be
+ * specified in a number of ways in order:
+ * <ol>
+ * <li>On the command line with the --levels flag.
+ * The format is a comma (or space) separated list of level/resolution
+ * pairs. Eg --levels=0:24,1:22,2:20
+ * If the flag is given without an argument then the command line override
+ * is turned off for maps following that option.
+ *
+ * <li>In the style options file. This works just like the command line
+ * option, but it applies whenever the given style is used and not overridden
+ * on the command line.
+ *
+ * <li>A default setting.
+ * </ol>
+ *
+ * <p>I'd advise that new styles specify their own set of levels.
+ *
+ * @return An array of level information, basically a [level,resolution]
+ * pair.
+ */
+ public LevelInfo[] mapLevels() {
+ String levelSpec = getLevelSpec("levels");
+ if (levelSpec == null)
+ levelSpec = LevelInfo.DEFAULT_LEVELS;
+
+ return LevelInfo.createFromString(levelSpec);
+ }
+
+ @Override
+ public LevelInfo[] overviewMapLevels() {
+ String levelSpec = getLevelSpec("overview-levels");
+
+ if (levelSpec == null)
+ return null;
+ LevelInfo[] levels = LevelInfo.createFromString(levelSpec);
+ for (int i = 0; i < levels.length; i++)
+ levels[i] = new LevelInfo(levels.length-i-1,levels[i].getBits());
+ return levels;
+ }
+
+ private String getLevelSpec (String optionName){
+ // First try command line, then style, then our default.
+ String levelSpec = getConfig().getProperty(optionName);
+ log.debug(optionName, levelSpec, ", ", ((levelSpec!=null)?levelSpec.length():""));
+ if (levelSpec == null || levelSpec.length() < 2) {
+ if (style != null) {
+ levelSpec = style.getOption(optionName);
+ log.debug("getting " + optionName + " from style:", levelSpec);
+ }
+ }
+ return levelSpec;
+ }
+
+ @Override
+ public void load(String name) throws FileNotFoundException, FormatException {
+ InputStream is = Utils.openFile(name);
+ load(is);
+ }
+
+ /**
+ * There are no copyright messages in the OSM files themselves. So we
+ * include a fixed set of strings on the assumption that .osm files
+ * are probably going to have the OSM copyright statements.
+ *
+ * @return A list of copyright messages as a String array.
+ */
+ public String[] copyrightMessages() {
+ String note = getConfig().getProperty("copyright-message",
+ "OpenStreetMap.org contributors. See: http://wiki.openstreetmap.org/index.php/Attribution");
+ return new String[] { note };
+ }
+
+ protected void setStyle(Style style) {
+ this.style = style;
+ }
+
+ /**
+ * Common code to setup the file handler.
+ * @param handler The file handler.
+ */
+ protected void setupHandler(OsmHandler handler) {
+ createElementSaver();
+ osmReadingHooks = pluginChain(elementSaver, getConfig());
+
+ handler.setElementSaver(elementSaver);
+ handler.setHooks(osmReadingHooks);
+
+ createConverter();
+
+ handler.setUsedTags(getUsedTags());
+
+ String deleteTagsFileName = getConfig().getProperty("delete-tags-file");
+ if(deleteTagsFileName != null) {
+ Map<String, Set<String>> deltags = readDeleteTagsFile(deleteTagsFileName);
+ handler.setTagsToDelete(deltags);
+ }
+ }
+
+ protected void createElementSaver() {
+ elementSaver = new ElementSaver(getConfig());
+ }
+
+ public ElementSaver getElementSaver() {
+ return elementSaver;
+ }
+
+ protected OsmReadingHooks[] getPossibleHooks() {
+ return this.POSSIBLE_HOOKS;
+ }
+
+ protected OsmReadingHooks pluginChain(ElementSaver saver, EnhancedProperties props) {
+ List<OsmReadingHooks> plugins = new ArrayList<OsmReadingHooks>();
+
+ for (OsmReadingHooks p : getPossibleHooks()) {
+ if (p.init(saver, props))
+ plugins.add(p);
+ }
+
+ OsmReadingHooks hooks;
+ switch (plugins.size()) {
+ case 0:
+ hooks = new OsmReadingHooksAdaptor();
+ break;
+ case 1:
+ hooks = plugins.get(0);
+ break;
+ default:
+ OsmReadingHooksChain chain = new OsmReadingHooksChain();
+ for (OsmReadingHooks p : plugins) {
+ chain.add(p);
+ }
+ hooks = chain;
+ }
+ usedTags.addAll(hooks.getUsedTags());
+ return hooks;
+ }
+
+ private Map<String, Set<String>> readDeleteTagsFile(String fileName) {
+ Map<String, Set<String>> deletedTags = new HashMap<String,Set<String>>();
+ try {
+ BufferedReader br = new BufferedReader(new FileReader(fileName));
+ String line;
+ while((line = br.readLine()) != null) {
+ line = line.trim();
+ if(line.length() > 0 && !line.startsWith("#") && !line.startsWith(";")) {
+ String[] parts = line.split("=");
+ if (parts.length == 2) {
+ parts[0] = parts[0].trim();
+ parts[1] = parts[1].trim();
+ if ("*".equals(parts[1])) {
+ deletedTags.put(parts[0], new HashSet<String>());
+ } else {
+ Set<String> vals = deletedTags.get(parts[0]);
+ if (vals == null)
+ vals = new HashSet<String>();
+ vals.add(parts[1]);
+ deletedTags.put(parts[0], vals);
+ }
+ } else {
+ log.error("Ignoring bad line in deleted tags file: " + line);
+ }
+ }
+ }
+ br.close();
+ }
+ catch(FileNotFoundException e) {
+ log.error("Could not open delete tags file " + fileName);
+ }
+ catch(IOException e) {
+ log.error("Error reading delete tags file " + fileName);
+ }
+
+ if(deletedTags.isEmpty())
+ deletedTags = null;
+
+ return deletedTags;
+ }
+
+ /**
+ * Create the appropriate converter from osm to garmin styles.
+ *
+ */
+ protected void createConverter() {
+ EnhancedProperties props = getConfig();
+ Style style = StyleImpl.readStyle(props);
+ setStyle(style);
+
+ usedTags.addAll(style.getUsedTags());
+ converter = new StyledConverter(style, mapper, props);
+ }
+
+ public OsmConverter getConverter() {
+ return converter;
+ }
+
+ public Set<String> getUsedTags() {
+ return usedTags;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/OsmReadingHooks.java b/src/uk/me/parabola/mkgmap/reader/osm/OsmReadingHooks.java
new file mode 100644
index 0000000..ea02afd
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/OsmReadingHooks.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.reader.osm;
+
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * Allows common code to be called during the reading of OSM files in both
+ * their XML and binary formats.
+ *
+ * You should only use this when you need access to other ways or nodes
+ * or the IDs of the individual points that go into a way, which are no
+ * longer available during conversion.
+ *
+ * This is the stage before conversion from the node/way/tag format to the
+ * general intermediate format. Most operations should be done during that
+ * conversion process, which is accessible from the style file language.
+ *
+ * We also want access to the other ways/nodes to generate sea polygons,
+ * cycle lanes and so on.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface OsmReadingHooks {
+
+ /**
+ * Passes in the element saver and the command line options. The hook code
+ * can use the options to set itself up if needed.
+ *
+ * The saver gives access to the previously saved nodes/ways/relations and
+ * also allows you to add extra ways.
+ *
+ * @param saver This is where all the elements are being collected. You can access previously added
+ * elements from here by their id. You can also add generated elements. You must not add the
+ * element that is being passed in as it will be added automatically.
+ *
+ * @param props The command line options.
+ *
+ * @return If you return false then this set of hooks will not be used. So if they
+ * are not needed based on the options supplied you can disable it.
+ */
+ public boolean init(ElementSaver saver, EnhancedProperties props);
+
+ /**
+ * Retrieves the tags that are used by this hook. Tags that are used only if they are referenced
+ * in the style file should not be added to this list.
+ *
+ * @return the tag names used by this hook
+ */
+ public Set<String> getUsedTags();
+
+ /**
+ * Called on adding a node to the saver and just before it is added. You can modify
+ * it, create new nodes etc.
+ *
+ * @param node The node to be added.
+ */
+ void onAddNode(Node node);
+
+ /**
+ * Add the given way. The way must be complete, call after the end tag
+ * is seen for the XML format.
+ *
+ * @param way The osm way.
+ */
+ public void onAddWay(Way way);
+
+ /**
+ * This is called whenever a node is added to a way. A node is something with tags, not just a Coord.
+ *
+ * The way will not have been added via addWay() yet. The node is the node that
+ *
+ * @param way The incomplete way.
+ * @param coordId The coordinate id of the node that is being added.
+ * @param co The coordinate.
+ */
+ public void onCoordAddedToWay(Way way, long coordId, Coord co);
+
+ /**
+ * Called after the file has been read. Can be used to add more elements to the saver
+ * based on information stored up.
+ */
+ public void end();
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/OsmReadingHooksAdaptor.java b/src/uk/me/parabola/mkgmap/reader/osm/OsmReadingHooksAdaptor.java
new file mode 100644
index 0000000..555d52f
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/OsmReadingHooksAdaptor.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.reader.osm;
+
+import java.util.Collections;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * Provides empty implementation of all methods so that subclass that only
+ * need a few can just implement the ones they want.
+ *
+ * @author Steve Ratcliffe
+ */
+public class OsmReadingHooksAdaptor implements OsmReadingHooks {
+
+ public boolean init(ElementSaver saver, EnhancedProperties props) {
+ return true;
+ }
+
+ public Set<String> getUsedTags() {
+ return Collections.emptySet();
+ }
+
+ public void onAddNode(Node node) {
+ }
+
+ public void onAddWay(Way way) {
+ }
+
+ public void onCoordAddedToWay(Way way, long coordId, Coord co) {
+ }
+
+ public void end() {
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/OsmReadingHooksChain.java b/src/uk/me/parabola/mkgmap/reader/osm/OsmReadingHooksChain.java
new file mode 100644
index 0000000..4529b75
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/OsmReadingHooksChain.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.reader.osm;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * A single class that holds several {@link OsmReadingHooks} and calls them in
+ * order.
+ *
+ * It implements {@link OsmReadingHooks} itself.
+ *
+ * @author Steve Ratcliffe
+ */
+ at SuppressWarnings({"ForLoopReplaceableByForEach"})
+public class OsmReadingHooksChain implements OsmReadingHooks {
+
+ private static final OsmReadingHooks[] NO_HOOKS = new OsmReadingHooks[0];
+
+ private OsmReadingHooks[] readingHooks = NO_HOOKS;
+
+ /**
+ * Add a new set of hooks.
+ * @param hooks The reading hooks.
+ */
+ public void add(OsmReadingHooks hooks) {
+ List<OsmReadingHooks> readingHooksList = new ArrayList<OsmReadingHooks>(Arrays.asList(readingHooks));
+ readingHooksList.add(hooks);
+ readingHooks = readingHooksList.toArray(new OsmReadingHooks[readingHooksList.size()]);
+ }
+
+ public Set<String> getUsedTags() {
+ HashSet<String> usedTags = new HashSet<String>();
+ for (int i = 0; i < readingHooks.length; i++)
+ usedTags.addAll(readingHooks[i].getUsedTags());
+ return usedTags;
+ }
+
+ public boolean init(ElementSaver saver, EnhancedProperties props) {
+ for (int i = 0; i < readingHooks.length; i++)
+ readingHooks[i].init(saver, props);
+ return true;
+ }
+
+ public void onAddNode(Node node) {
+ for (int i = 0; i < readingHooks.length; i++)
+ readingHooks[i].onAddNode(node);
+ }
+
+ public void onCoordAddedToWay(Way way, long coordId, Coord co) {
+ for (int i = 0; i < readingHooks.length; i++)
+ readingHooks[i].onCoordAddedToWay(way, coordId, co);
+ }
+
+ public void onAddWay(Way way) {
+ for (int i = 0; i < readingHooks.length; i++)
+ readingHooks[i].onAddWay(way);
+ }
+
+ public void end() {
+ for (int i = 0; i < readingHooks.length; i++)
+ readingHooks[i].end();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/POIGeneratorHook.java b/src/uk/me/parabola/mkgmap/reader/osm/POIGeneratorHook.java
new file mode 100644
index 0000000..96f615e
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/POIGeneratorHook.java
@@ -0,0 +1,360 @@
+/*
+ * 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.reader.osm;
+
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * Adds a POI for each area and multipolygon with the same tags in case the add-pois-to-areas option
+ * is set. Adds multiple POIs to each line if the add-pois-to-lines option is set.<br/>
+ * <br/>
+ * <code>add-pois-to-areas</code><br/>
+ * Artificial areas created by
+ * multipolygon relation processing are not used for POI creation. The location of the POI
+ * is determined in different ways.<br/>
+ * Element is of type {@link Way}:
+ * <ul>
+ * <li>the first node tagged with building=entrance</li>
+ * <li>the center point of the area</li>
+ * </ul>
+ * Element is of type {@link MultiPolygonRelation}:
+ * <ul>
+ * <li>the node with role=label</li>
+ * <li>the center point of the biggest area</li>
+ * </ul>
+ * Each node created is tagged with mkgmap:area2poi=true.<br/>
+ * <br/>
+ * <code>add-pois-to-lines</code><br/>
+ * Adds POIs to lines. Each POI is tagged with mkgmap:line2poi=true.<br/>
+ * The following POIs are created for each line:
+ * <ul>
+ * <li>mkgmap:line2poitype=start: The first point of the line</li>
+ * <li>mkgmap:line2poitype=end: The last point of the line</li>
+ * <li>mkgmap:line2poitype=inner: Each inner point of the line</li>
+ * <li>mkgmap:line2poitype=mid: POI at the middle distance of the line</li>
+ * </ul>
+ * @author WanMil
+ */
+public class POIGeneratorHook extends OsmReadingHooksAdaptor {
+ private static final Logger log = Logger.getLogger(POIGeneratorHook.class);
+
+ private List<Entry<String,String>> poiPlacementTags;
+
+ private ElementSaver saver;
+
+ private boolean poisToAreas = false;
+ private boolean poisToLines = false;
+
+ /** Name of the bool tag that is set to true if a POI is created from an area */
+ public static final String AREA2POI_TAG = "mkgmap:area2poi";
+ public static final String LINE2POI_TAG = "mkgmap:line2poi";
+ public static final String LINE2POI_TYPE_TAG = "mkgmap:line2poitype";
+
+ public boolean init(ElementSaver saver, EnhancedProperties props) {
+ poisToAreas = props.containsKey("add-pois-to-areas");
+ poisToLines = props.containsKey("add-pois-to-lines");
+
+ if ((poisToAreas || poisToLines) == false) {
+ log.info("Disable Areas2POIHook because add-pois-to-areas and add-pois-to-lines option is not set.");
+ return false;
+ }
+
+ this.poiPlacementTags = getPoiPlacementTags(props);
+
+ this.saver = saver;
+
+ return true;
+ }
+
+ /**
+ * Reads the tag definitions of the option poi2area-placement-tags from the given properties.
+ * @param props mkgmap options
+ * @return the parsed tag definition list
+ */
+ public static List<Entry<String,String>> getPoiPlacementTags(EnhancedProperties props) {
+ if (props.containsKey("add-pois-to-areas") == false) {
+ return Collections.emptyList();
+ }
+
+ List<Entry<String,String>> tagList = new ArrayList<Entry<String,String>>();
+
+ String placementDefs = props.getProperty("pois-to-areas-placement", "entrance=main;entrance=yes;building=entrance");
+ placementDefs = placementDefs.trim();
+
+ if (placementDefs.length() == 0) {
+ // the POIs should be placed in the center only
+ // => return an empty list
+ return tagList;
+ }
+
+ String[] placementDefsParts = placementDefs.split(";");
+ for (String placementDef : placementDefsParts) {
+ int ind = placementDef.indexOf('=');
+ String tagName = null;
+ String tagValue = null;
+ if (ind < 0) {
+ // only the tag is defined => interpret it as tag=*
+ tagName = placementDef;
+ tagValue = null;
+ } else if (ind > 0) {
+ tagName = placementDef.substring(0,ind);
+ tagValue = placementDef.substring(ind+1);
+ } else {
+ log.error("Option pois-to-areas-placement contains a tag that starts with '='. This is not allowed. Ignoring it.");
+ continue;
+ }
+ tagName = tagName.trim();
+ if (tagName.length() == 0) {
+ log.error("Option pois-to-areas-placement contains a whitespace tag '='. This is not allowed. Ignoring it.");
+ continue;
+ }
+ if (tagValue != null) {
+ tagValue = tagValue.trim();
+ if (tagValue.length() == 0 || "*".equals(tagValue)) {
+ tagValue = null;
+ }
+ }
+ Entry<String,String> tag = new AbstractMap.SimpleImmutableEntry<String,String>(tagName, tagValue);
+ tagList.add(tag);
+ }
+ return tagList;
+ }
+
+
+ public Set<String> getUsedTags() {
+ // return all tags defined in the poiPlacementTags
+ Set<String> tags = new HashSet<String>();
+ for (Entry<String,String> poiTag : poiPlacementTags) {
+ tags.add(poiTag.getKey());
+ }
+ return tags;
+ }
+
+ public void end() {
+ log.info("Areas2POIHook started");
+ addPOIsToWays();
+ addPOIsToMPs();
+ log.info("Areas2POIHook finished");
+ }
+
+ private int getPlacementOrder(Element elem) {
+ for (int order = 0; order < poiPlacementTags.size(); order++) {
+ Entry<String,String> poiTagDef = poiPlacementTags.get(order);
+ String tagValue = elem.getTag(poiTagDef.getKey());
+ if (tagValue != null) {
+ if (poiTagDef.getValue() == null || poiTagDef.getValue().equals(tagValue)) {
+ return order;
+ }
+ }
+ }
+ // no poi tag match
+ return -1;
+ }
+
+ private void addPOIsToWays() {
+ Map<Coord, Integer> labelCoords = new HashMap<Coord, Integer>();
+
+ // save all coords with one of the placement tags to a map
+ // so that ways use this coord as its labeling point
+ if (poiPlacementTags.isEmpty() == false && poisToAreas) {
+ for (Node n : saver.getNodes().values()) {
+ int order = getPlacementOrder(n);
+ if (order >= 0) {
+ Integer prevOrder = labelCoords.get(n.getLocation());
+ if (prevOrder == null || order < prevOrder.intValue())
+ labelCoords.put(n.getLocation(), order);
+ }
+ }
+ }
+
+ log.debug("Found", labelCoords.size(), "label coords");
+
+ int ways2POI = 0;
+ int lines2POI = 0;
+
+ for (Way w : saver.getWays().values()) {
+ // check if way has any tags
+ if (w.getTagCount() == 0) {
+ continue;
+ }
+
+ // do not add POIs for polygons created by multipolygon processing
+ if (w.isBoolTag(MultiPolygonRelation.MP_CREATED_TAG)) {
+ if (log.isDebugEnabled())
+ log.debug("MP processed: Do not create POI for", w.toTagString());
+ continue;
+ }
+
+
+ // check if it is an area
+ if (w.isClosed()) {
+ if (poisToAreas) {
+ addPOItoPolygon(w, labelCoords);
+ ways2POI++;
+ }
+ } else {
+ if (poisToLines) {
+ lines2POI += addPOItoLine(w);
+ }
+ }
+ }
+
+ if (poisToAreas)
+ log.info(ways2POI, "POIs from single areas created");
+ if (poisToLines)
+ log.info(lines2POI, "POIs from lines created");
+ }
+
+ private void addPOItoPolygon(Way polygon, Map<Coord, Integer> labelCoords) {
+ if (poisToAreas == false) {
+ return;
+ }
+
+ // get the coord where the poi is placed
+ Coord poiCoord = null;
+ // do we have some labeling coords?
+ if (labelCoords.size() > 0) {
+ int poiOrder = Integer.MAX_VALUE;
+ // go through all points of the way and check if one of the coords
+ // is a labeling coord
+ for (Coord c : polygon.getPoints()) {
+ Integer cOrder = labelCoords.get(c);
+ if (cOrder != null && cOrder.intValue() < poiOrder) {
+ // this coord is a labeling coord
+ // use it for the current way
+ poiCoord = c;
+ poiOrder = cOrder;
+ if (poiOrder == 0) {
+ // there is no higher order
+ break;
+ }
+ }
+ }
+ }
+ if (poiCoord == null) {
+ // did not find any label coord
+ // use the common center point of the area
+ poiCoord = polygon.getCofG();
+ }
+
+ Node poi = createPOI(polygon, poiCoord, AREA2POI_TAG);
+ saver.addNode(poi);
+ }
+
+ private int addPOItoLine(Way line) {
+ Node startNode = createPOI(line, line.getPoints().get(0), LINE2POI_TAG);
+ startNode.addTag(LINE2POI_TYPE_TAG,"start");
+ saver.addNode(startNode);
+
+ Node endNode = createPOI(line, line.getPoints().get(line.getPoints().size()-1), LINE2POI_TAG);
+ endNode.addTag(LINE2POI_TYPE_TAG,"end");
+ saver.addNode(endNode);
+
+ int noPOIs = 2;
+
+ if (line.getPoints().size() > 2) {
+ for (Coord inPoint : line.getPoints().subList(1, line.getPoints().size()-1)) {
+ Node innerNode = createPOI(line, inPoint, LINE2POI_TAG);
+ innerNode.addTag(LINE2POI_TYPE_TAG,"inner");
+ saver.addNode(innerNode);
+ noPOIs++;
+ }
+ }
+
+
+ // calculate the middle of the line
+ Coord prevC = null;
+ double sumDist = 0.0;
+ ArrayList<Double> dists = new ArrayList<Double>(line.getPoints().size()-1);
+ for (Coord c : line.getPoints()) {
+ if (prevC != null) {
+ double dist = prevC.distance(c);
+ dists.add(dist);
+ sumDist+=dist;
+ }
+ prevC = c;
+ }
+
+ Coord midPoint = null;
+ double remMidDist = sumDist/2;
+ for (int midPos =0; midPos < dists.size(); midPos++) {
+ double nextDist = dists.get(midPos);
+ if (remMidDist <= nextDist) {
+ double frac = remMidDist/nextDist;
+ midPoint = line.getPoints().get(midPos).makeBetweenPoint(line.getPoints().get(midPos+1), frac);
+ break;
+ }
+ remMidDist -= nextDist;
+ }
+
+ if (midPoint != null) {
+ Node midNode = createPOI(line, midPoint, LINE2POI_TAG);
+ midNode.addTag(LINE2POI_TYPE_TAG,"mid");
+ saver.addNode(midNode);
+ noPOIs++;
+ }
+
+ return noPOIs;
+
+ }
+
+ private Node createPOI(Element source, Coord poiCoord, String poiTypeTag) {
+ Node poi = new Node(FakeIdGenerator.makeFakeId(), poiCoord);
+ poi.copyTags(source);
+ poi.deleteTag(MultiPolygonRelation.STYLE_FILTER_TAG);
+ poi.addTag(poiTypeTag, "true");
+ if (log.isDebugEnabled()) {
+ log.debug("Create POI",poi.toTagString(),"from",source.getId(),source.toTagString());
+ }
+ return poi;
+
+ }
+
+ private void addPOIsToMPs() {
+ int mps2POI = 0;
+ for (Relation r : saver.getRelations().values()) {
+
+ // create POIs for multipolygon relations only
+ if (r instanceof MultiPolygonRelation == false) {
+ continue;
+ }
+
+ Coord point = ((MultiPolygonRelation)r).getCofG();
+ if (point == null) {
+ continue;
+ }
+
+ Node poi = createPOI(r, point, AREA2POI_TAG);
+ // remove the type tag which makes only sense for relations
+ poi.deleteTag("type");
+ saver.addNode(poi);
+ mps2POI++;
+ }
+ log.info(mps2POI,"POIs from multipolygons created");
+ }
+
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/PrecompSeaElementSaver.java b/src/uk/me/parabola/mkgmap/reader/osm/PrecompSeaElementSaver.java
new file mode 100644
index 0000000..adb9ad8
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/PrecompSeaElementSaver.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.reader.osm;
+
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * This saver stores elements loaded from precompiled sea tiles.
+ * It does not convert so the data is still available after loading.
+ * @author WanMil
+ */
+public class PrecompSeaElementSaver extends ElementSaver {
+
+ public PrecompSeaElementSaver(EnhancedProperties args) {
+ super(args);
+ }
+
+ public void convert(OsmConverter converter) {
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/Relation.java b/src/uk/me/parabola/mkgmap/reader/osm/Relation.java
new file mode 100644
index 0000000..d00ccd3
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/Relation.java
@@ -0,0 +1,40 @@
+package uk.me.parabola.mkgmap.reader.osm;
+
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represent a Relation.
+ *
+ * @author Rene_A
+ */
+public abstract class Relation extends Element {
+ private final List<Map.Entry<String,Element>> elements = new ArrayList<Map.Entry<String,Element>>();
+
+ /**
+ * Add a (role, Element) pair to this Relation.
+ * @param role The role this element performs in this relation
+ * @param el The Element added
+ */
+ public void addElement(String role, Element el) {
+ elements.add(new AbstractMap.SimpleEntry<String,Element>(role, el));
+ }
+
+ /** Invoked after addElement() has been invoked on all Node and Way
+ * members of the relations. Relation members (sub-relations) may be
+ * added later. */
+ public abstract void processElements();
+
+ /** Get the ordered list of relation members.
+ * @return list of pairs of (role, Element)
+ */
+ public List<Map.Entry<String,Element>> getElements() {
+ return elements;
+ }
+
+ public String kind() {
+ return "relation";
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/RelationStyleHook.java b/src/uk/me/parabola/mkgmap/reader/osm/RelationStyleHook.java
new file mode 100644
index 0000000..c642dab
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/RelationStyleHook.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011 - 2012.
+ *
+ * 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.reader.osm;
+
+import uk.me.parabola.mkgmap.osmstyle.StyleImpl;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * This hook applies the relation rules of the style system.
+ * @author WanMil
+ */
+public class RelationStyleHook extends OsmReadingHooksAdaptor {
+
+ private Style style;
+ private ElementSaver saver;
+
+ public RelationStyleHook() {
+ }
+
+ public boolean init(ElementSaver saver, EnhancedProperties props) {
+ this.saver = saver;
+ style = StyleImpl.readStyle(props);
+ return super.init(saver, props);
+ }
+
+ public void end() {
+ Rule relationRules = style.getRelationRules();
+ for (Relation rel : saver.getRelations().values()) {
+ relationRules.resolveType(rel, TypeResult.NULL_RESULT);
+ }
+ super.end();
+
+ style = null;
+ }
+
+
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/RestrictionRelation.java b/src/uk/me/parabola/mkgmap/reader/osm/RestrictionRelation.java
new file mode 100644
index 0000000..00fdaa1
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/RestrictionRelation.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2013.
+ *
+ * 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.reader.osm;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.HashSet;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.CoordNode;
+import uk.me.parabola.imgfmt.app.net.RouteRestriction;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.MapCollector;
+
+/**
+ * Representation of an OSM turn restriction
+ *
+ * @author Mark Burton
+ */
+public class RestrictionRelation extends Relation {
+
+ private static final Logger log = Logger.getLogger(RestrictionRelation.class);
+
+ private Way fromWay;
+ private Way toWay;
+ private Way viaWay;
+ private Coord viaCoord;
+ private final String restriction;
+
+ private CoordNode fromNode;
+ private CoordNode toNode;
+ private CoordNode viaNode;
+ private final List<CoordNode> otherNodes = new ArrayList<CoordNode>();
+ private byte exceptMask;
+ private String messagePrefix;
+
+ /**
+ * Create an instance based on an existing relation. We need to do
+ * this because the type of the relation is not known until after all
+ * its tags are read in.
+ * @param other The relation to base this one on.
+ */
+ public RestrictionRelation(Relation other) {
+
+ setId(other.getId());
+
+ final String browseURL = toBrowseURL();
+
+ messagePrefix = "Turn restriction " + browseURL + " ";
+
+ for (Map.Entry<String, Element> pair : other.getElements()) {
+ String role = pair.getKey();
+ Element el = pair.getValue();
+ addElement(role, el);
+
+ Coord location = null;
+
+ if(viaCoord != null)
+ location = viaCoord;
+ else if(fromWay != null && !fromWay.getPoints().isEmpty())
+ location = fromWay.getPoints().get(0);
+ else if(toWay != null && !toWay.getPoints().isEmpty())
+ location = toWay.getPoints().get(0);
+
+ if(location != null)
+ messagePrefix = "Turn restriction " + browseURL + " (at " + location.toOSMURL() + ") ";
+
+ if("to".equals(role)) {
+ if(toWay != null) {
+ log.warn(messagePrefix + "has extra 'to' member " + el.toBrowseURL());
+ }
+ else if(!(el instanceof Way)) {
+ log.warn(messagePrefix + "'to' member " + el.toBrowseURL() + " is not a way but it should be");
+ }
+ else if(((Way)el).getPoints().isEmpty()) {
+ log.warn(messagePrefix + "ignoring empty 'to' way " + el.toBrowseURL());
+ }
+ else
+ toWay = (Way)el;
+ }
+ else if("from".equals(role)) {
+ if(fromWay != null) {
+ log.warn(messagePrefix + "has extra 'from' member " + el.toBrowseURL());
+ }
+ else if(!(el instanceof Way)) {
+ log.warn(messagePrefix + "'from' member " + el.toBrowseURL() + " is not a way but it should be");
+ }
+ else if(((Way)el).getPoints().isEmpty()) {
+ log.warn(messagePrefix + "ignoring empty 'from' way " + el.toBrowseURL());
+ }
+ else
+ fromWay = (Way)el;
+ }
+ else if("via".equals(role)) {
+ if(viaCoord != null || viaWay != null) {
+ log.warn(messagePrefix + "has extra 'via' member " + el.toBrowseURL());
+ }
+ else if(el instanceof Node) {
+ viaCoord = ((Node)el).getLocation();
+ }
+ else if(el instanceof Way) {
+ viaWay = (Way)el;
+ }
+ else {
+ log.warn(messagePrefix + "'via' member " + el.toBrowseURL() + " is not a node or way");
+ }
+ }
+ else if("location_hint".equals(role)) {
+ // relax - we don't care about this
+ }
+ else {
+ log.warn(messagePrefix + "unknown member role '" + role + "'");
+ }
+ }
+
+ copyTags(other);
+
+ restriction = getTag("restriction");
+
+ // These tags are not loaded by default but if they exist issue a warning
+ String[] unsupportedTags = {
+ "day_on",
+ "day_off",
+ "hour_on",
+ "hour_off" };
+ for (String unsupportedTag : unsupportedTags) {
+ if (getTag(unsupportedTag) != null) {
+ log.warn(messagePrefix + "ignoring unsupported '" + unsupportedTag + "' tag");
+ }
+ }
+
+ String except = getTag("except");
+ if(except != null) {
+ for(String e : except.split("[,;]")) { // be nice
+ e = e.trim();
+ if(e.equals("motorcar") || e.equals("motorcycle"))
+ exceptMask |= RouteRestriction.EXCEPT_CAR;
+ else if(e.equals("psv") || e.equals("bus"))
+ exceptMask |= RouteRestriction.EXCEPT_BUS;
+ else if(e.equals("taxi"))
+ exceptMask |= RouteRestriction.EXCEPT_TAXI;
+ else if(e.equals("delivery") || e.equals("goods"))
+ exceptMask |= RouteRestriction.EXCEPT_DELIVERY;
+ else if(e.equals("bicycle"))
+ exceptMask |= RouteRestriction.EXCEPT_BICYCLE;
+ else if(e.equals("hgv") || e.equals("truck"))
+ exceptMask |= RouteRestriction.EXCEPT_TRUCK;
+ else
+ log.warn(messagePrefix + "ignoring unsupported vehicle class '" + e + "' in turn restriction exception");
+ }
+ }
+ }
+
+ public Way getFromWay() {
+ return fromWay;
+ }
+
+ public Way getToWay() {
+ return toWay;
+ }
+
+ public Coord getViaCoord() {
+ return viaCoord;
+ }
+
+ public void setFromNode(CoordNode fromNode) {
+ this.fromNode = fromNode;
+ log.debug(messagePrefix + restriction + " 'from' node is " + fromNode.toOSMURL());
+ }
+
+ public void setToNode(CoordNode toNode) {
+ this.toNode = toNode;
+ log.debug(messagePrefix + restriction + " 'to' node is " + toNode.toOSMURL());
+ }
+
+ public void setViaNode(CoordNode viaNode) {
+ if(this.viaNode == null)
+ log.debug(messagePrefix + restriction + " 'via' node is " + viaNode.toOSMURL());
+ else if(!this.viaNode.equals(viaNode))
+ log.warn(messagePrefix + restriction + " 'via' node redefined from " +
+ this.viaNode.toOSMURL() + " to " + viaNode.toOSMURL());
+ this.viaNode = viaNode;
+ }
+
+ public void addOtherNode(CoordNode otherNode) {
+ otherNodes.add(otherNode);
+ log.debug(messagePrefix + restriction + " adding 'other' node " + otherNode.toOSMURL());
+ }
+
+ public boolean isValid() {
+ boolean result = true;
+
+ if(restriction == null) {
+ log.warn(messagePrefix + "lacks 'restriction' tag (e.g. no_left_turn)");
+ result = false;
+ }
+
+ if(fromWay == null) {
+ log.warn(messagePrefix + "lacks 'from' way");
+ }
+
+ if(toWay == null) {
+ log.warn(messagePrefix + "lacks 'to' way");
+ }
+
+ if(fromWay == null || toWay == null)
+ return false;
+
+ if(viaCoord == null && viaWay == null) {
+ List<Coord>fromPoints = fromWay.getPoints();
+ List<Coord>toPoints = toWay.getPoints();
+ for(Coord fp : fromPoints) {
+ for(Coord tp : toPoints) {
+ if(fp.equals(tp)) {
+ if(viaCoord == null) {
+ viaCoord = fp;
+ }
+ else {
+ log.warn(messagePrefix + "lacks 'via' node and the 'from' (" + fromWay.toBrowseURL() + ") and 'to' (" + toWay.toBrowseURL() + ") ways connect in more than one place");
+ return false;
+ }
+ }
+ }
+ }
+
+ if(viaCoord == null) {
+ log.warn(messagePrefix + "lacks 'via' node and the 'from' (" + fromWay.toBrowseURL() + ") and 'to' (" + toWay.toBrowseURL() + ") ways don't connect");
+ return false;
+ }
+
+ log.warn(messagePrefix + "lacks 'via' node (guessing it should be at " + viaCoord.toOSMURL() + ", why don't you add it to the OSM data?)");
+ }
+
+ Coord v1 = viaCoord;
+ Coord v2 = null;
+
+ if(viaWay != null) {
+ v1 = viaWay.getPoints().get(0);
+ v2 = viaWay.getPoints().get(viaWay.getPoints().size() - 1);
+ }
+
+ Coord e1 = fromWay.getPoints().get(0);
+ Coord e2 = fromWay.getPoints().get(fromWay.getPoints().size() - 1);
+ if(!e1.equals(v1) && !e2.equals(v1) &&
+ !e1.equals(v2) && !e2.equals(v2)) {
+ log.warn(messagePrefix + "'from' way " + fromWay.toBrowseURL() + " doesn't start or end at 'via' node or way");
+ result = false;
+ }
+
+ e1 = toWay.getPoints().get(0);
+ e2 = toWay.getPoints().get(toWay.getPoints().size() - 1);
+ if(!e1.equals(v1) && !e2.equals(v1) &&
+ !e1.equals(v2) && !e2.equals(v2)) {
+ log.warn(messagePrefix + "'to' way " + toWay.toBrowseURL() + " doesn't start or end at 'via' node or way");
+ result = false;
+ }
+
+ if (result && viaWay != null) {
+ log.warn(messagePrefix + "sorry, 'via' ways are not supported - ignoring restriction");
+ result = false;
+ }
+
+ return result;
+ }
+
+ public void addRestriction(MapCollector collector) {
+
+ if(restriction == null || viaNode == null || fromNode == null || toNode == null) {
+ // restriction must have some error (reported earlier)
+ return;
+ }
+
+ if(restriction.equals("no_left_turn") ||
+ restriction.equals("no_right_turn") ||
+ restriction.equals("no_straight_on") ||
+ restriction.equals("no_u_turn") ||
+ restriction.startsWith("no_turn")) {
+ collector.addRestriction(fromNode, toNode, viaNode, exceptMask);
+ if(restriction.startsWith("no_turn"))
+ log.warn(messagePrefix + "has bad type '" + restriction + "' it should be of the form no_X_turn rather than no_turn_X - I added the restriction anyway - blocks routing to way " + toWay.toBrowseURL());
+ else
+ log.info(messagePrefix + restriction + " added - blocks routing to way " + toWay.toBrowseURL());
+ }
+ else if(restriction.equals("only_left_turn") ||
+ restriction.equals("only_right_turn") ||
+ restriction.startsWith("only_straight") ||
+ restriction.startsWith("only_turn")) {
+ if(restriction.startsWith("only_turn"))
+ log.warn(messagePrefix + "has bad type '" + restriction + "' it should be of the form only_X_turn rather than only_turn_X - I added the restriction anyway - allows routing to way " + toWay.toBrowseURL());
+ log.info(messagePrefix + restriction + " added - allows routing to way " + toWay.toBrowseURL());
+ HashSet<CoordNode> otherNodesUnique = new HashSet<CoordNode>(otherNodes);
+ for(CoordNode otherNode : otherNodesUnique) {
+ if (!otherNode.equals(fromNode) && !otherNode.equals(toNode)) {
+ log.info(messagePrefix + restriction + " blocks routing to node " + otherNode.toOSMURL());
+ collector.addRestriction(fromNode, otherNode, viaNode, exceptMask);
+ }
+ }
+ }
+ else {
+ log.warn(messagePrefix + "has unsupported type '" + restriction + "'");
+ }
+ }
+
+ /** Process the members in this relation.
+ */
+ public void processElements() {
+ // relax
+ }
+
+ public String toString() {
+ return "[restriction = " + restriction + ", from = " + fromWay.toBrowseURL() + ", to = " + toWay.toBrowseURL() + ", via = " + viaCoord.toOSMURL() + "]";
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/RoutingHook.java b/src/uk/me/parabola/mkgmap/reader/osm/RoutingHook.java
new file mode 100644
index 0000000..db837fe
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/RoutingHook.java
@@ -0,0 +1,70 @@
+/*
+ * 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.reader.osm;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import uk.me.parabola.mkgmap.osmstyle.StyledConverter;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * This hook performs some steps required for routing. <br/>
+ * At the moment the only function is to add tags used for routing to the
+ * overall tag list. The rest of the routing work is done in the
+ * {@link StyledConverter} class.
+ * @author WanMil
+ *
+ */
+public class RoutingHook extends OsmReadingHooksAdaptor {
+
+ private final Set<String> usedTags;
+
+ public RoutingHook() {
+ usedTags = new HashSet<String>();
+ usedTags.add("except");
+ usedTags.add("restriction");
+ }
+
+ public boolean init(ElementSaver saver, EnhancedProperties props) {
+
+ if (props.getProperty("old-style", false)) {
+ // the access tags need to be loaded if the old style handling
+ // is active and access restrictions are handled by the java
+ // source code and not by the style
+ usedTags.add("access");
+ usedTags.add("bicycle");
+ usedTags.add("carpool");
+ usedTags.add("delivery");
+ usedTags.add("emergency");
+ usedTags.add("foot");
+ usedTags.add("goods");
+ usedTags.add("hgv");
+ usedTags.add("motorcar");
+ usedTags.add("motorcycle");
+ usedTags.add("psv");
+ usedTags.add("route");
+ usedTags.add("taxi");
+ }
+
+ // only enabled if the route option is set
+ return props.containsKey("route");
+ }
+
+
+ public Set<String> getUsedTags() {
+ return usedTags;
+ }
+
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/Rule.java b/src/uk/me/parabola/mkgmap/reader/osm/Rule.java
new file mode 100644
index 0000000..552ea92
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/Rule.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 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: 07-Nov-2008
+ */
+package uk.me.parabola.mkgmap.reader.osm;
+
+/**
+ * A rule takes an element and returns the correct garmin type for it.
+ * Implementations can be simple or complex as needed.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface Rule {
+
+ /**
+ * Given the element return the garmin type that should be used to
+ * represent it.
+ *
+ * @param el The element as read from an OSM xml file in 'tag' format.
+ * @param result The resolved Garmin type that will go into the map.
+ */
+ public void resolveType(Element el, TypeResult result);
+
+ /**
+ * Sets the finalize rules that are executed when
+ * an element type definition matches.
+ *
+ * @param finalizeRule finalize rule(s)
+ */
+ public void setFinalizeRule(Rule finalizeRule);
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/SeaGenerator.java b/src/uk/me/parabola/mkgmap/reader/osm/SeaGenerator.java
new file mode 100644
index 0000000..5afce3a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/SeaGenerator.java
@@ -0,0 +1,1494 @@
+/*
+ * Copyright (C) 2010-2012.
+ *
+ * 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.reader.osm;
+
+import java.awt.Rectangle;
+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.LineNumberReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.regex.Pattern;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import uk.me.parabola.imgfmt.FormatException;
+import uk.me.parabola.imgfmt.MapFailedException;
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.LineClipper;
+import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
+import uk.me.parabola.mkgmap.osmstyle.StyleImpl;
+import uk.me.parabola.mkgmap.reader.osm.xml.Osm5PrecompSeaDataSource;
+import uk.me.parabola.util.EnhancedProperties;
+import uk.me.parabola.util.Java2DConverter;
+
+/**
+ * Code to generate sea polygons from the coastline ways.
+ *
+ * Currently there are a number of different options.
+ * Should pick one that works well and make it the default.
+ *
+ */
+public class SeaGenerator extends OsmReadingHooksAdaptor {
+ private static final Logger log = Logger.getLogger(SeaGenerator.class);
+
+ private boolean generateSeaUsingMP = true;
+ private int maxCoastlineGap;
+ private boolean allowSeaSectors = true;
+ private boolean extendSeaSectors;
+ private String[] landTag = { "natural", "land" };
+ private boolean floodblocker;
+ private int fbGap = 40;
+ private double fbRatio = 0.5d;
+ private int fbThreshold = 20;
+ private boolean fbDebug;
+
+ private ElementSaver saver;
+
+ private List<Way> shoreline = new ArrayList<Way>();
+ private boolean roadsReachBoundary; // todo needs setting somehow
+ private boolean generateSeaBackground = true;
+
+ private String[] coastlineFilenames;
+ private StyleImpl fbRules;
+
+ /** The size (lat and long) of the precompiled sea tiles */
+ public final static int PRECOMP_RASTER = 1 << 15;
+
+ /**
+ * The directory of the precompiled sea tiles or <code>null</code> if
+ * precompiled sea should not be used.
+ */
+ private File precompSeaDir;
+
+ private static final byte SEA_TILE = 's';
+ private static final byte LAND_TILE = 'l';
+ private static final byte MIXED_TILE = 'm';
+
+ private static ThreadLocal<PrecompData> precompIndex = new ThreadLocal<PrecompData>();
+
+ // useful constants defining the min/max map units of the precompiled sea tiles
+ private static final int MIN_LAT = Utils.toMapUnit(-90.0);
+ private static final int MAX_LAT = Utils.toMapUnit(90.0);
+ private static final int MIN_LON = Utils.toMapUnit(-180.0);
+ private static final int MAX_LON = Utils.toMapUnit(180.0);
+ private final static Pattern keySplitter = Pattern.compile(Pattern.quote("_"));
+
+
+ private static final List<Class<? extends LoadableMapDataSource>> precompSeaLoader;
+
+ static {
+ String[] sources = {
+ "uk.me.parabola.mkgmap.reader.osm.bin.OsmBinPrecompSeaDataSource",
+ // must be last as it is the default
+ "uk.me.parabola.mkgmap.reader.osm.xml.Osm5PrecompSeaDataSource", };
+
+ precompSeaLoader = new ArrayList<Class<? extends LoadableMapDataSource>>();
+
+ for (String source : sources) {
+ try {
+ @SuppressWarnings({ "unchecked" })
+ Class<? extends LoadableMapDataSource> c = (Class<? extends LoadableMapDataSource>) Class
+ .forName(source);
+ precompSeaLoader.add(c);
+ } catch (ClassNotFoundException e) {
+ // not available, try the rest
+ } catch (NoClassDefFoundError e) {
+ // not available, try the rest
+ }
+ }
+ }
+
+ /**
+ * Sort out options from the command line.
+ * Returns true only if the option to generate the sea is active, so that
+ * the whole thing is omitted if not used.
+ */
+ public boolean init(ElementSaver saver, EnhancedProperties props) {
+ this.saver = saver;
+
+ String precompSea = props.getProperty("precomp-sea", null);
+ if (precompSea != null) {
+ precompSeaDir = new File(precompSea);
+ if (precompSeaDir.exists()){
+ if (precompIndex.get() == null) {
+ PrecompData precompData = null;
+ String internalPath = null;
+ InputStream indexStream = null;
+ String indexFileName = "index.txt.gz";
+ ZipFile zipFile = null;
+ try{
+ if (precompSeaDir.isDirectory()){
+ File indexFile = new File(precompSeaDir, indexFileName);
+ if (indexFile.exists() == false) {
+ // check if the unzipped index file exists
+ indexFileName = "index.txt";
+ indexFile = new File(precompSeaDir, indexFileName);
+ }
+ if (indexFile.exists()) {
+ indexStream = new FileInputStream(indexFile);
+ }
+ } else if (precompSea.endsWith(".zip")){
+ zipFile = new ZipFile(precompSeaDir);
+ internalPath = "sea";
+ ZipEntry entry = zipFile.getEntry(internalPath);
+ if (entry == null)
+ internalPath = "";
+ else
+ internalPath = internalPath + "/";
+ entry = zipFile.getEntry(internalPath + indexFileName);
+ if (entry == null){
+ indexFileName = "index.txt";
+ entry = zipFile.getEntry(internalPath + indexFileName);
+ }
+ if (entry != null){
+ indexStream = zipFile.getInputStream(entry);
+ }
+ } else {
+ log.error("Don't know how to read " + precompSeaDir);
+ }
+ if (indexStream != null){
+ if (indexFileName.endsWith(".gz")) {
+ indexStream = new GZIPInputStream(indexStream);
+ }
+ try{
+ precompData = loadIndex(indexStream);
+ } catch (IOException exp) {
+ log.error("Cannot read index file " + indexFileName,
+ exp);
+ }
+
+ if (precompData != null){
+ if (zipFile != null){
+ precompData.precompZipFileInternalPath = internalPath;
+ precompData.zipFile = zipFile;
+ }
+ precompIndex.set(precompData);
+ }
+ indexStream.close();
+ }
+ } catch (IOException exp) {
+ log.error("Cannot read index file " + indexFileName,
+ exp);
+
+ }
+ precompIndex.set(precompData);
+ }
+ } else {
+ log.error("Directory or zip file with precompiled sea does not exist: "
+ + precompSea);
+ System.err.println("Directory or zip file with precompiled sea does not exist: "
+ + precompSea);
+ precompSeaDir = null;
+ }
+ }
+ String gs = props.getProperty("generate-sea", null);
+ boolean generateSea = gs != null || precompSea != null;
+ if (gs != null) {
+ for(String o : gs.split(",")) {
+ if("no-mp".equals(o) ||
+ "polygon".equals(o) ||
+ "polygons".equals(o))
+ generateSeaUsingMP = false;
+ else if("multipolygon".equals(o))
+ generateSeaUsingMP = true;
+ else if(o.startsWith("land-tag="))
+ landTag = o.substring(9).split("=");
+ else if (precompSea == null) {
+ // the other options are valid only if not using precompiled sea data
+ if(o.startsWith("close-gaps="))
+ maxCoastlineGap = (int)Double.parseDouble(o.substring(11));
+ else if("no-sea-sectors".equals(o))
+ allowSeaSectors = false;
+ else if("extend-sea-sectors".equals(o)) {
+ allowSeaSectors = false;
+ extendSeaSectors = true;
+ }
+ else if("floodblocker".equals(o))
+ floodblocker = true;
+ else if(o.startsWith("fbgap="))
+ fbGap = (int)Double.parseDouble(o.substring("fbgap=".length()));
+ else if(o.startsWith("fbratio="))
+ fbRatio = Double.parseDouble(o.substring("fbratio=".length()));
+ else if(o.startsWith("fbthres="))
+ fbThreshold = (int)Double.parseDouble(o.substring("fbthres=".length()));
+ else if("fbdebug".equals(o))
+ fbDebug = true;
+ }
+ else if(o.isEmpty())
+ continue;
+ else {
+ if(!"help".equals(o))
+ System.err.println("Unknown sea generation option '" + o + "'");
+ System.err.println("Known sea generation options are:");
+ System.err.println(" multipolygon use a multipolygon (default)");
+ System.err.println(" polygons | no-mp use polygons rather than a multipolygon");
+ System.err.println(" no-sea-sectors disable use of \"sea sectors\"");
+ System.err.println(" extend-sea-sectors extend coastline to reach border");
+ System.err.println(" land-tag=TAG=VAL tag to use for land polygons (default natural=land)");
+ System.err.println(" close-gaps=NUM close gaps in coastline that are less than this distance (metres)");
+ System.err.println(" floodblocker enable the floodblocker (for multipolgon only)");
+ System.err.println(" fbgap=NUM points closer to the coastline are ignored for flood blocking (default 40)");
+ System.err.println(" fbthres=NUM min points contained in a polygon to be flood blocked (default 20)");
+ System.err.println(" fbratio=NUM min ratio (points/area size) for flood blocking (default 0.5)");
+ }
+ }
+
+ // init floodblocker and coastlinefile loader only
+ // if precompSea is not set
+ if (precompSea == null) {
+ if (floodblocker) {
+ try {
+ fbRules = new StyleImpl(null, "floodblocker");
+ } catch (FileNotFoundException e) {
+ log.error("Cannot load file floodblocker rules. Continue floodblocking disabled.");
+ floodblocker = false;
+ }
+ }
+
+ String coastlineFileOpt = props.getProperty("coastlinefile", null);
+ if (coastlineFileOpt != null) {
+ coastlineFilenames = coastlineFileOpt.split(",");
+ CoastlineFileLoader.getCoastlineLoader().setCoastlineFiles(
+ coastlineFilenames);
+ CoastlineFileLoader.getCoastlineLoader().loadCoastlines();
+ log.info("Coastlines loaded");
+ } else {
+ coastlineFilenames = null;
+ }
+ }
+ }
+
+ return generateSea;
+ }
+
+ /**
+ * Read the index from stream and populate the index grid.
+ * @param fileStream already opened stream
+ */
+ private PrecompData loadIndex(InputStream fileStream) throws IOException{
+ int indexWidth = (SeaGenerator.getPrecompTileStart(MAX_LON) - SeaGenerator.getPrecompTileStart(MIN_LON)) / SeaGenerator.PRECOMP_RASTER;
+ int indexHeight = (SeaGenerator.getPrecompTileStart(MAX_LAT) - SeaGenerator.getPrecompTileStart(MIN_LAT)) / SeaGenerator.PRECOMP_RASTER;
+ PrecompData pi = null;
+ LineNumberReader indexReader = new LineNumberReader(
+ new InputStreamReader(fileStream));
+ Pattern csvSplitter = Pattern.compile(Pattern
+ .quote(";"));
+ String indexLine = null;
+
+ byte[][] indexGrid = new byte[indexWidth+1][indexHeight+1];
+ boolean detectExt = true;
+ String prefix = null;
+ String ext = null;
+
+ while ((indexLine = indexReader.readLine()) != null) {
+ if (indexLine.startsWith("#")) {
+ // comment
+ continue;
+ }
+ String[] items = csvSplitter.split(indexLine);
+ if (items.length != 2) {
+ log.warn("Invalid format in index file name:",
+ indexLine);
+ continue;
+ }
+ String precompKey = items[0];
+ byte type = updatePrecompSeaTileIndex(precompKey, items[1], indexGrid);
+ if (type == '?'){
+ log.warn("Invalid format in index file name:",
+ indexLine);
+ continue;
+ }
+ if (type == MIXED_TILE){
+ // make sure that all file names are using the same name scheme
+ int prePos = items[1].indexOf(items[0]);
+ if (prePos >= 0){
+ if (detectExt){
+ prefix = items[1].substring(0, prePos);
+ ext = items[1].substring(prePos+items[0].length());
+ detectExt = false;
+ } else {
+ StringBuilder sb = new StringBuilder(prefix);
+ sb.append(precompKey);
+ sb.append(ext);
+ if (items[1].equals(sb.toString()) == false){
+ log.warn("Unexpected file name in index file:",
+ indexLine);
+ }
+ }
+ }
+ }
+
+ }
+ //
+ pi = new PrecompData();
+ pi.precompIndex = indexGrid;
+ pi.precompSeaPrefix = prefix;
+ pi.precompSeaExt = ext;
+ return pi;
+ }
+
+ /**
+ * Retrieves the start value of the precompiled tile.
+ * @param value the value for which the start value is calculated
+ * @return the tile start value
+ */
+ public static int getPrecompTileStart(int value) {
+ int rem = value % PRECOMP_RASTER;
+ if (rem == 0) {
+ return value;
+ } else if (value >= 0) {
+ return value - rem;
+ } else {
+ return value - PRECOMP_RASTER - rem;
+ }
+ }
+
+ /**
+ * Retrieves the end value of the precompiled tile.
+ * @param value the value for which the end value is calculated
+ * @return the tile end value
+ */
+ public static int getPrecompTileEnd(int value) {
+ int rem = value % PRECOMP_RASTER;
+ if (rem == 0) {
+ return value;
+ } else if (value >= 0) {
+ return value + PRECOMP_RASTER - rem;
+ } else {
+ return value - rem;
+ }
+ }
+
+ public Set<String> getUsedTags() {
+ HashSet<String> usedTags = new HashSet<String>();
+ if (coastlineFilenames == null) {
+ usedTags.add("natural");
+ }
+ if (floodblocker) {
+ usedTags.addAll(fbRules.getUsedTags());
+ }
+
+ if (log.isDebugEnabled())
+ log.debug("Sea generator used tags: "+usedTags);
+
+ return usedTags;
+ }
+
+ /**
+ * Test to see if the way is part of the shoreline and if it is
+ * we save it.
+ * @param way The way to test.
+ */
+ public void onAddWay(Way way) {
+ String natural = way.getTag("natural");
+ if(natural != null) {
+ if("coastline".equals(natural)) {
+ way.deleteTag("natural");
+ if (coastlineFilenames == null && precompSeaDir == null)
+ shoreline.add(way);
+
+ if (precompSeaDir != null) {
+ // add a copy of this way to be able to draw the coastline which is not possible with precompiled sea
+ Way coastlineWay = new Way(FakeIdGenerator.makeFakeId(), way.getPoints());
+ coastlineWay.addTag("natural", "coastline");
+ // tag that this way is used as line only
+ coastlineWay.addTag(MultiPolygonRelation.STYLE_FILTER_TAG, MultiPolygonRelation.STYLE_FILTER_LINE);
+ saver.addWay(coastlineWay);
+ }
+ } else if (natural.contains(";")) {
+ // cope with compound tag value
+ String others = null;
+ boolean foundCoastline = false;
+ for(String n : natural.split(";")) {
+ if("coastline".equals(n.trim()))
+ foundCoastline = true;
+ else if(others == null)
+ others = n;
+ else
+ others += ";" + n;
+ }
+
+ if(foundCoastline) {
+ way.deleteTag("natural");
+ if(others != null)
+ way.addTag("natural", others);
+ if (coastlineFilenames == null && precompSeaDir == null)
+ shoreline.add(way);
+
+ if (precompSeaDir != null) {
+ // add a copy of this way to be able to draw the coastline which is not possible with precompiled sea
+ Way coastlineWay = new Way(FakeIdGenerator.makeFakeId(), way.getPoints());
+ coastlineWay.addTag("natural", "coastline");
+ // tag that this way is used as line only
+ coastlineWay.addTag(MultiPolygonRelation.STYLE_FILTER_TAG, MultiPolygonRelation.STYLE_FILTER_LINE);
+ saver.addWay(coastlineWay);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates a reader for the given filename of the precomiled sea tile.
+ * @param filename precompiled sea tile
+ * @return the reader for the tile
+ */
+ private static OsmMapDataSource createTileReader(String filename) {
+ for (Class<? extends LoadableMapDataSource> loader : precompSeaLoader) {
+ try {
+ LoadableMapDataSource src = loader.newInstance();
+ if (filename != null && src instanceof OsmMapDataSource
+ && src.isFileSupported(filename))
+ return (OsmMapDataSource) src;
+ } catch (InstantiationException e) {
+ // try the next one.
+ } catch (IllegalAccessException e) {
+ // try the next one.
+ } catch (NoClassDefFoundError e) {
+ // try the next one
+ }
+ }
+
+ // Give up and assume it is in the XML format. If it isn't we will get
+ // an error soon enough anyway.
+ return new Osm5PrecompSeaDataSource();
+ }
+
+ /**
+ * Loads the precomp sea tile with the given filename.
+ * @param filename the filename of the precomp sea tile
+ * @return all ways of the tile
+ * @throws FileNotFoundException if the tile could not be found
+ */
+ private Collection<Way> loadPrecompTile(InputStream is, String filename) {
+ OsmMapDataSource src = createTileReader(filename);
+ EnhancedProperties props = new EnhancedProperties();
+ // set a flag that the StyledConverter which is created by the
+ // OsmMapDataSource does not set the drive-on-left flag
+ props.setProperty("ignore-drive-on-left", "true");
+ src.config(props);
+ log.info("Started loading coastlines from", filename);
+ try{
+ src.load(is);
+ } catch (FormatException e) {
+ log.error("Failed to read " + filename);
+ log.error(e);
+ }
+ log.info("Finished loading coastlines from", filename);
+ return src.getElementSaver().getWays().values();
+ }
+
+ /**
+ * Calculates the key names of the precompiled sea tiles for the bounding box.
+ * The key names are compiled of {@code lat+"_"+lon}.
+ * @return the key names for the bounding box
+ */
+ private List<String> getPrecompKeyNames() {
+ Area bounds = saver.getBoundingBox();
+ List<String> precompKeys = new ArrayList<String>();
+ for (int lat = getPrecompTileStart(bounds.getMinLat()); lat < getPrecompTileEnd(bounds
+ .getMaxLat()); lat += PRECOMP_RASTER) {
+ for (int lon = getPrecompTileStart(bounds.getMinLong()); lon < getPrecompTileEnd(bounds
+ .getMaxLong()); lon += PRECOMP_RASTER) {
+ precompKeys.add(lat+"_"+lon);
+ }
+ }
+ return precompKeys;
+ }
+
+ /**
+ * Get the tile name from the index.
+ * @param precompKey The key name is compiled of {@code lat+"_"+lon}.
+ * @return either "land" or "sea" or a file name or null
+ */
+ private String getTileName(String precompKey){
+ PrecompData pi = precompIndex.get();
+ String[] tileCoords = keySplitter.split(precompKey);
+ int lat = Integer.valueOf(tileCoords[0]);
+ int lon = Integer.valueOf(tileCoords[1]);
+ int latIndex = (MAX_LAT-lat) / PRECOMP_RASTER;
+ int lonIndex = (MAX_LON-lon) / PRECOMP_RASTER;
+ byte type = pi.precompIndex[lonIndex][latIndex];
+ switch (type){
+ case SEA_TILE: return "sea";
+ case LAND_TILE: return "land";
+ case MIXED_TILE: return pi.precompSeaPrefix + precompKey + pi.precompSeaExt;
+ default: return null;
+ }
+ }
+
+
+ /**
+ * Update the index grid for the element identified by precompKey.
+ * @param precompKey The key name is compiled of {@code lat+"_"+lon}.
+ * @param fileName either "land", "sea", or a file name containing OSM data
+ * @param indexGrid the previously allocated index grid
+ * @return the byte that was saved in the index grid
+ */
+ private byte updatePrecompSeaTileIndex (String precompKey, String fileName, byte[][] indexGrid){
+ String[] tileCoords = keySplitter.split(precompKey);
+ byte type = '?';
+ if (tileCoords.length == 2){
+ int lat = Integer.valueOf(tileCoords[0]);
+ int lon = Integer.valueOf(tileCoords[1]);
+ int latIndex = (MAX_LAT - lat) / PRECOMP_RASTER;
+ int lonIndex = (MAX_LON - lon) / PRECOMP_RASTER;
+
+ if ("sea".equals(fileName))
+ type = SEA_TILE;
+ else if ("land".equals(fileName))
+ type = LAND_TILE;
+ else
+ type = MIXED_TILE;
+
+ indexGrid[lonIndex][latIndex] = type;
+ }
+ return type;
+ }
+
+ /**
+ * Loads the precompiled sea tiles and adds the data to the
+ * element saver.
+ */
+ private void addPrecompSea() {
+ log.info("Load precompiled sea tiles");
+
+ // flag if all tiles contains sea or way only
+ // this is important for polygon processing
+ boolean distinctTilesOnly = true;
+
+ List<Way> landWays = new ArrayList<Way>();
+ List<Way> seaWays = new ArrayList<Way>();
+ List<java.awt.geom.Area> seaOnlyAreas = new ArrayList<java.awt.geom.Area>();
+ List<java.awt.geom.Area> landOnlyAreas = new ArrayList<java.awt.geom.Area>();
+
+ // get the index with assignment key => sea/land/tilename
+
+ ZipFile zipFile = null;
+ PrecompData pd = precompIndex.get();
+ if (precompSeaDir.getName().endsWith(".zip")){
+ zipFile = pd.zipFile;
+ }
+
+ for (String precompKey : getPrecompKeyNames()) {
+ String tileName = getTileName(precompKey);
+
+ if (tileName == null ) {
+ log.error("Precompile sea tile "+precompKey+" is missing in the index. Skipping.");
+ continue;
+ }
+
+ if ("sea".equals(tileName) || "land".equals(tileName)) {
+ // the whole precompiled tile is filled with either land or sea
+ // => create a rectangle that covers the whole precompiled tile
+ String[] tileCoords = keySplitter.split(precompKey);
+ int minLat = Integer.valueOf(tileCoords[0]);
+ int minLon = Integer.valueOf(tileCoords[1]);
+ Rectangle r = new Rectangle(minLon,minLat,PRECOMP_RASTER,PRECOMP_RASTER);
+
+ if ("sea".equals(tileName)) {
+ seaOnlyAreas = addWithoutCreatingHoles(seaOnlyAreas, new java.awt.geom.Area(r));
+ } else {
+ landOnlyAreas = addWithoutCreatingHoles(landOnlyAreas, new java.awt.geom.Area(r));
+ }
+ } else {
+ distinctTilesOnly = false;
+ try {
+ InputStream is = null;
+ if (zipFile != null){
+ ZipEntry entry = zipFile.getEntry(pd.precompZipFileInternalPath + tileName);
+ if (entry != null){
+ is = zipFile.getInputStream(entry);
+ } else {
+ log.error("Preompiled sea tile " + tileName + " not found.");
+ }
+ } else {
+ File precompTile = new File(precompSeaDir,tileName);
+ is = new FileInputStream(precompTile);
+ }
+ if (is != null){
+ Collection<Way> seaPrecompWays = loadPrecompTile(is, tileName);
+ if (log.isDebugEnabled())
+ log.debug(seaPrecompWays.size(), "precomp sea ways from",
+ tileName, "loaded.");
+
+ for (Way w : seaPrecompWays) {
+ // set a new id to be sure that the precompiled ids do not
+ // interfere with the ids of this run
+ w.setId(FakeIdGenerator.makeFakeId());
+
+ if ("land".equals(w.getTag("natural"))) {
+ landWays.add(w);
+ } else {
+ seaWays.add(w);
+ }
+ }
+ }
+ } catch (FileNotFoundException exp) {
+ log.error("Preompiled sea tile " + tileName + " not found.");
+ } catch (Exception exp) {
+ log.error(exp);
+ exp.printStackTrace();
+ }
+ }
+ }
+ landWays.addAll(areaToWays(landOnlyAreas,"land"));
+ seaWays.addAll(areaToWays(seaOnlyAreas,"sea"));
+ landOnlyAreas = null;
+ seaOnlyAreas = null;
+
+ // check if the land tags need to be changed
+ if (landTag != null && ("natural".equals(landTag[0]) && "land".equals(landTag[1])) == false) {
+ for (Way w : landWays) {
+ w.deleteTag("natural");
+ w.addTag(landTag[0], landTag[1]);
+ }
+ }
+
+ if (generateSeaUsingMP || distinctTilesOnly) {
+ // when using multipolygons use the data directly from the precomp files
+ // also with polygons if all tiles are using either sea or land only
+ for (Way w : landWays) {
+ saver.addWay(w);
+ }
+ for (Way w : seaWays) {
+ saver.addWay(w);
+ }
+ } else {
+ // using polygons
+
+ Area bounds = saver.getBoundingBox();
+ // first add the complete bounding box as sea
+ Way sea = new Way(FakeIdGenerator.makeFakeId());
+ sea.addPoint(new Coord(bounds.getMinLat(), bounds.getMinLong()));
+ sea.addPoint(new Coord(bounds.getMinLat(), bounds.getMaxLong()));
+ sea.addPoint(new Coord(bounds.getMaxLat(), bounds.getMaxLong()));
+ sea.addPoint(new Coord(bounds.getMaxLat(), bounds.getMinLong()));
+ sea.addPoint(new Coord(bounds.getMinLat(), bounds.getMinLong()));
+ sea.addTag("natural", "sea");
+
+ for (Way w : landWays) {
+ saver.addWay(w);
+ }
+ }
+ }
+
+
+ /**
+ * Try to merge an area with one or more other areas without creating holes.
+ * If it cannot be merged, it is added to the list.
+ * @param areas known areas
+ * @param toAdd area to add
+ * @return new list of areas
+ */
+ private List<java.awt.geom.Area> addWithoutCreatingHoles(List<java.awt.geom.Area> areas,
+ final java.awt.geom.Area toAdd) {
+ List<java.awt.geom.Area> result = new LinkedList<java.awt.geom.Area>();
+ java.awt.geom.Area toMerge = new java.awt.geom.Area(toAdd);
+
+ for (java.awt.geom.Area area:areas ){
+ java.awt.geom.Area mergedArea = new java.awt.geom.Area(area);
+ mergedArea.add(toMerge);
+ if (mergedArea.isSingular() == false){
+ result.add(area);
+ continue;
+ }
+ toMerge = mergedArea;
+ }
+ // create a sorted list with "smallest" area at the beginning
+ int dimNew = Math.max(toMerge.getBounds().width,toMerge.getBounds().height);
+ boolean added = false;
+ for (int i = 0; i < result.size(); i++){
+ java.awt.geom.Area area = result.get(i);
+ if (dimNew < Math.max(area.getBounds().width,area.getBounds().height)){
+ result.add(i,toMerge);
+ added = true;
+ break;
+ }
+ }
+ if (!added)
+ result.add(toMerge);
+ return result;
+ }
+
+ /**
+ * @param area
+ * @param type
+ * @return
+ */
+ private List<Way> areaToWays(List<java.awt.geom.Area> areas, String type) {
+ List<Way> ways = new ArrayList<Way>();
+// int count = 0;
+ for (java.awt.geom.Area area : areas) {
+ List<List<Coord>> shapes = Java2DConverter.areaToShapes(area);
+ for (List<Coord> points : shapes) {
+// uk.me.parabola.util.GpxCreator.createGpx(type + "_" + count++, points);
+ Way w = new Way(FakeIdGenerator.makeFakeId(), points);
+ w.addTag("natural", type);
+ ways.add(w);
+ }
+ }
+ return ways;
+ }
+
+ /**
+ * Joins the given segments to closed ways as good as possible.
+ * @param segments a list of closed and unclosed ways
+ * @return a list of ways completely joined
+ */
+ public static ArrayList<Way> joinWays(Collection<Way> segments) {
+ ArrayList<Way> joined = new ArrayList<Way>((int)Math.ceil(segments.size()*0.5));
+ Map<Coord, Way> beginMap = new HashMap<Coord, Way>();
+
+ for (Way w : segments) {
+ if (w.isClosed()) {
+ joined.add(w);
+ } else if (w.getPoints() != null && w.getPoints().size() > 1){
+ List<Coord> points = w.getPoints();
+ beginMap.put(points.get(0), w);
+ } else {
+ log.info("Discard coastline way",w.getId(),"because consists of less than 2 points");
+ }
+ }
+ segments.clear();
+
+ int merged = 1;
+ while (merged > 0) {
+ merged = 0;
+ for (Way w1 : beginMap.values()) {
+ if (w1.isClosed()) {
+ // this should not happen
+ log.error("joinWays2: Way "+w1+" is closed but contained in the begin map");
+ joined.add(w1);
+ beginMap.remove(w1.getPoints().get(0));
+ merged=1;
+ break;
+ }
+
+ List<Coord> points1 = w1.getPoints();
+ Way w2 = beginMap.get(points1.get(points1.size() - 1));
+ if (w2 != null) {
+ log.info("merging: ", beginMap.size(), w1.getId(),
+ w2.getId());
+ List<Coord> points2 = w2.getPoints();
+ Way wm;
+ if (FakeIdGenerator.isFakeId(w1.getId())) {
+ wm = w1;
+ } else {
+ wm = new Way(FakeIdGenerator.makeFakeId());
+ wm.getPoints().addAll(points1);
+ beginMap.put(points1.get(0), wm);
+ }
+ wm.getPoints().addAll(points2.subList(1, points2.size()));
+ beginMap.remove(points2.get(0));
+ merged++;
+
+ if (wm.isClosed()) {
+ joined.add(wm);
+ beginMap.remove(wm.getPoints().get(0));
+ }
+ break;
+ }
+ }
+ }
+ log.info(joined.size(),"closed ways.",beginMap.size(),"unclosed ways.");
+ joined.addAll(beginMap.values());
+ return joined;
+ }
+
+ /**
+ * All done, process the saved shoreline information and construct the polygons.
+ */
+ public void end() {
+ // precompiled sea has highest priority
+ // if it is set do not perform any other algorithm
+ if (precompSeaDir != null) {
+ addPrecompSea();
+ return;
+ }
+
+ Area seaBounds = saver.getBoundingBox();
+ if (coastlineFilenames == null) {
+ log.info("Shorelines before join", shoreline.size());
+ shoreline = joinWays(shoreline);
+ } else {
+ shoreline.addAll(CoastlineFileLoader.getCoastlineLoader()
+ .getCoastlines(seaBounds));
+ log.info("Shorelines from extra file:", shoreline.size());
+ }
+
+ int closedS = 0;
+ int unclosedS = 0;
+ for (Way w : shoreline) {
+ if (w.isClosed()) {
+ closedS++;
+ } else {
+ unclosedS++;
+ }
+ }
+ log.info("Closed shorelines", closedS);
+ log.info("Unclosed shorelines", unclosedS);
+
+ // clip all shoreline segments
+ clipShorlineSegments(shoreline, seaBounds);
+
+ log.info("generating sea, seaBounds=", seaBounds);
+ int minLat = seaBounds.getMinLat();
+ int maxLat = seaBounds.getMaxLat();
+ int minLong = seaBounds.getMinLong();
+ int maxLong = seaBounds.getMaxLong();
+ Coord nw = new Coord(minLat, minLong);
+ Coord ne = new Coord(minLat, maxLong);
+ Coord sw = new Coord(maxLat, minLong);
+ Coord se = new Coord(maxLat, maxLong);
+
+ if(shoreline.isEmpty()) {
+ // no sea required
+ // even though there is no sea, generate a land
+ // polygon so that the tile's background colour will
+ // match the land colour on the tiles that do contain
+ // some sea
+ long landId = FakeIdGenerator.makeFakeId();
+ Way land = new Way(landId);
+ land.addPoint(nw);
+ land.addPoint(sw);
+ land.addPoint(se);
+ land.addPoint(ne);
+ land.addPoint(nw);
+ land.addTag(landTag[0], landTag[1]);
+ // no matter if the multipolygon option is used it is
+ // only necessary to create a land polygon
+ saver.addWay(land);
+ // nothing more to do
+ return;
+ }
+
+ long multiId = FakeIdGenerator.makeFakeId();
+ Relation seaRelation = null;
+ if(generateSeaUsingMP) {
+ log.debug("Generate seabounds relation",multiId);
+ seaRelation = new GeneralRelation(multiId);
+ seaRelation.addTag("type", "multipolygon");
+ seaRelation.addTag("natural", "sea");
+ }
+
+ List<Way> islands = new ArrayList<Way>();
+
+ // handle islands (closed shoreline components) first (they're easy)
+ handleIslands(shoreline, seaBounds, islands);
+
+ // the remaining shoreline segments should intersect the boundary
+ // find the intersection points and store them in a SortedMap
+ NavigableMap<EdgeHit, Way> hitMap = findIntesectionPoints(shoreline, seaBounds, seaRelation);
+
+ // now construct inner ways from these segments
+ boolean shorelineReachesBoundary = createInnerWays(seaBounds, islands, hitMap);
+
+ if(!shorelineReachesBoundary && roadsReachBoundary) {
+ // try to avoid tiles being flooded by anti-lakes or other
+ // bogus uses of natural=coastline
+ generateSeaBackground = false;
+ }
+
+ List<Way> antiIslands = removeAntiIslands(seaRelation, islands);
+ if (islands.isEmpty()) {
+ // the tile doesn't contain any islands so we can assume
+ // that it's showing a land mass that contains some
+ // enclosed sea areas - in which case, we don't want a sea
+ // coloured background
+ generateSeaBackground = false;
+ }
+
+ if (generateSeaBackground) {
+ // the background is sea so all anti-islands should be
+ // contained by land otherwise they won't be visible
+
+ for (Way ai : antiIslands) {
+ boolean containedByLand = false;
+ for(Way i : islands) {
+ if(i.containsPointsOf(ai)) {
+ containedByLand = true;
+ break;
+ }
+ }
+
+ if (!containedByLand) {
+ // found an anti-island that is not contained by
+ // land so convert it back into an island
+ ai.deleteTag("natural");
+ ai.addTag(landTag[0], landTag[1]);
+ if (generateSeaUsingMP) {
+ // create a "inner" way for the island
+ assert seaRelation != null;
+ seaRelation.addElement("inner", ai);
+ }
+ log.warn("Converting anti-island starting at", ai.getPoints().get(0).toOSMURL() , "into an island as it is surrounded by water");
+ }
+ }
+
+ long seaId = FakeIdGenerator.makeFakeId();
+ Way sea = new Way(seaId);
+ // the sea background area must be a little bigger than all
+ // inner land areas. this is a workaround for a mp shortcoming:
+ // mp is not able to combine outer and inner if they intersect
+ // or have overlaying lines
+ // the added area will be clipped later by the style generator
+ sea.addPoint(new Coord(nw.getLatitude() - 1,
+ nw.getLongitude() - 1));
+ sea.addPoint(new Coord(sw.getLatitude() + 1,
+ sw.getLongitude() - 1));
+ sea.addPoint(new Coord(se.getLatitude() + 1,
+ se.getLongitude() + 1));
+ sea.addPoint(new Coord(ne.getLatitude() - 1,
+ ne.getLongitude() + 1));
+ sea.addPoint(new Coord(nw.getLatitude() - 1,
+ nw.getLongitude() - 1));
+ sea.addTag("natural", "sea");
+
+ log.info("sea: ", sea);
+ saver.addWay(sea);
+ if(generateSeaUsingMP) {
+ assert seaRelation != null;
+ seaRelation.addElement("outer", sea);
+ }
+ } else {
+ // background is land
+
+ // generate a land polygon so that the tile's
+ // background colour will match the land colour on the
+ // tiles that do contain some sea
+ long landId = FakeIdGenerator.makeFakeId();
+ Way land = new Way(landId);
+ land.addPoint(nw);
+ land.addPoint(sw);
+ land.addPoint(se);
+ land.addPoint(ne);
+ land.addPoint(nw);
+ land.addTag(landTag[0], landTag[1]);
+ saver.addWay(land);
+ if (generateSeaUsingMP) {
+ seaRelation.addElement("inner", land);
+ }
+ }
+
+ if (generateSeaUsingMP) {
+ SeaPolygonRelation coastRel = saver.createSeaPolyRelation(seaRelation);
+ coastRel.setFloodBlocker(floodblocker);
+ if (floodblocker) {
+ coastRel.setFloodBlockerGap(fbGap);
+ coastRel.setFloodBlockerRatio(fbRatio);
+ coastRel.setFloodBlockerThreshold(fbThreshold);
+ coastRel.setFloodBlockerRules(fbRules.getWayRules());
+ coastRel.setLandTag(landTag[0], landTag[1]);
+ coastRel.setDebug(fbDebug);
+ }
+ saver.addRelation(coastRel);
+ }
+
+ shoreline = null;
+ }
+
+ /**
+ * Clip the shoreline ways to the bounding box of the map.
+ * @param shoreline All the the ways making up the coast.
+ * @param bounds The map bounds.
+ */
+ private void clipShorlineSegments(List<Way> shoreline, Area bounds) {
+ List<Way> toBeRemoved = new ArrayList<Way>();
+ List<Way> toBeAdded = new ArrayList<Way>();
+ for (Way segment : shoreline) {
+ List<Coord> points = segment.getPoints();
+ List<List<Coord>> clipped = LineClipper.clip(bounds, points);
+ if (clipped != null) {
+ log.info("clipping", segment);
+ toBeRemoved.add(segment);
+ for (List<Coord> pts : clipped) {
+ long id = FakeIdGenerator.makeFakeId();
+ Way shore = new Way(id, pts);
+ toBeAdded.add(shore);
+ }
+ }
+ }
+
+ log.info("clipping: adding", toBeAdded.size(), ", removing", toBeRemoved.size());
+ shoreline.removeAll(toBeRemoved);
+ shoreline.addAll(toBeAdded);
+ }
+
+ /**
+ * Pick out the islands and save them for later. They are removed from the
+ * shore line list and added to the island list.
+ *
+ * @param shoreline The collected shore line ways.
+ * @param seaBounds The map boundary.
+ * @param islands The islands are saved to this list.
+ */
+ private void handleIslands(List<Way> shoreline, Area seaBounds, List<Way> islands) {
+ Iterator<Way> it = shoreline.iterator();
+ while (it.hasNext()) {
+ Way w = it.next();
+ if (w.isClosed()) {
+ log.info("adding island", w);
+ islands.add(w);
+ it.remove();
+ }
+ }
+
+ closeGaps(shoreline, seaBounds);
+ // there may be more islands now
+ it = shoreline.iterator();
+ while (it.hasNext()) {
+ Way w = it.next();
+ if (w.isClosed()) {
+ log.debug("island after concatenating");
+ islands.add(w);
+ it.remove();
+ }
+ }
+ }
+
+ private boolean createInnerWays(Area seaBounds, List<Way> islands, NavigableMap<EdgeHit, Way> hitMap) {
+ NavigableSet<EdgeHit> hits = hitMap.navigableKeySet();
+ boolean shorelineReachesBoundary = false;
+ while (!hits.isEmpty()) {
+ long id = FakeIdGenerator.makeFakeId();
+ Way w = new Way(id);
+ saver.addWay(w);
+
+ EdgeHit hit = hits.first();
+ EdgeHit hFirst = hit;
+ do {
+ Way segment = hitMap.get(hit);
+ log.info("current hit:", hit);
+ EdgeHit hNext;
+ if (segment != null) {
+ // add the segment and get the "ending hit"
+ log.info("adding:", segment);
+ for(Coord p : segment.getPoints())
+ w.addPointIfNotEqualToLastPoint(p);
+ hNext = getEdgeHit(seaBounds, segment.getPoints().get(segment.getPoints().size()-1));
+ } else {
+ w.addPointIfNotEqualToLastPoint(hit.getPoint(seaBounds));
+ hNext = hits.higher(hit);
+ if (hNext == null)
+ hNext = hFirst;
+
+ Coord p;
+ if (hit.compareTo(hNext) < 0) {
+ log.info("joining: ", hit, hNext);
+ for (int i=hit.edge; i<hNext.edge; i++) {
+ EdgeHit corner = new EdgeHit(i, 1.0);
+ p = corner.getPoint(seaBounds);
+ log.debug("way: ", corner, p);
+ w.addPointIfNotEqualToLastPoint(p);
+ }
+ } else if (hit.compareTo(hNext) > 0) {
+ log.info("joining: ", hit, hNext);
+ for (int i=hit.edge; i<4; i++) {
+ EdgeHit corner = new EdgeHit(i, 1.0);
+ p = corner.getPoint(seaBounds);
+ log.debug("way: ", corner, p);
+ w.addPointIfNotEqualToLastPoint(p);
+ }
+ for (int i=0; i<hNext.edge; i++) {
+ EdgeHit corner = new EdgeHit(i, 1.0);
+ p = corner.getPoint(seaBounds);
+ log.debug("way: ", corner, p);
+ w.addPointIfNotEqualToLastPoint(p);
+ }
+ }
+ w.addPointIfNotEqualToLastPoint(hNext.getPoint(seaBounds));
+ }
+ hits.remove(hit);
+ hit = hNext;
+ } while (!hits.isEmpty() && !hit.equals(hFirst));
+
+ if (!w.isClosed())
+ w.getPoints().add(w.getPoints().get(0));
+ log.info("adding non-island landmass, hits.size()=" + hits.size());
+ islands.add(w);
+ shorelineReachesBoundary = true;
+ }
+ return shorelineReachesBoundary;
+ }
+
+ /**
+ * An 'anti-island' is something that has been detected as an island, but the water
+ * is on the inside. I think you would call this a lake.
+ * @param seaRelation The relation holding the sea. Only set if we are using multi-polygons for
+ * the sea.
+ * @param islands The island list that was found earlier.
+ * @return The so-called anti-islands.
+ */
+ private List<Way> removeAntiIslands(Relation seaRelation, List<Way> islands) {
+ List<Way> antiIslands = new ArrayList<Way>();
+ for (Way w : islands) {
+
+ if (!FakeIdGenerator.isFakeId(w.getId())) {
+ Way w1 = new Way(FakeIdGenerator.makeFakeId());
+ w1.getPoints().addAll(w.getPoints());
+ // only copy the name tags
+ for(String tag : w)
+ if(tag.equals("name") || tag.endsWith(":name"))
+ w1.addTag(tag, w.getTag(tag));
+ w = w1;
+ }
+
+ // determine where the water is
+ if (Way.clockwise(w.getPoints())) {
+ // water on the inside of the poly, it's an
+ // "anti-island" so tag with natural=water (to
+ // make it visible above the land)
+ w.addTag("natural", "water");
+ antiIslands.add(w);
+ saver.addWay(w);
+ } else {
+ // water on the outside of the poly, it's an island
+ w.addTag(landTag[0], landTag[1]);
+ saver.addWay(w);
+ if(generateSeaUsingMP) {
+ // create a "inner" way for each island
+ seaRelation.addElement("inner", w);
+ }
+ }
+ }
+
+ islands.removeAll(antiIslands);
+ return antiIslands;
+ }
+
+ /**
+ * Find the points where the remaining shore line segments intersect with the
+ * map boundary.
+ *
+ * @param shoreline The remaining shore line segments.
+ * @param seaBounds The map boundary.
+ * @param seaRelation If we are using a multi-polygon, this is it. Otherwise it will be null.
+ * @return A map of the 'hits' where the shore line intersects the boundary.
+ */
+ private NavigableMap<EdgeHit, Way> findIntesectionPoints(List<Way> shoreline, Area seaBounds, Relation seaRelation) {
+ assert !generateSeaUsingMP || seaRelation != null;
+
+ NavigableMap<EdgeHit, Way> hitMap = new TreeMap<EdgeHit, Way>();
+ for (Way w : shoreline) {
+ List<Coord> points = w.getPoints();
+ Coord pStart = points.get(0);
+ Coord pEnd = points.get(points.size()-1);
+
+ EdgeHit hStart = getEdgeHit(seaBounds, pStart);
+ EdgeHit hEnd = getEdgeHit(seaBounds, pEnd);
+ if (hStart == null || hEnd == null) {
+
+ /*
+ * This problem occurs usually when the shoreline is cut by osmosis (e.g. country-extracts from geofabrik)
+ * There are two possibilities to solve this problem:
+ * 1. Close the way and treat it as an island. This is sometimes the best solution (Germany: Usedom at the
+ * border to Poland)
+ * 2. Create a "sea sector" only for this shoreline segment. This may also be the best solution
+ * (see German border to the Netherlands where the shoreline continues in the Netherlands)
+ * The first choice may lead to "flooded" areas, the second may lead to "triangles".
+ *
+ * Usually, the first choice is appropriate if the segment is "nearly" closed.
+ */
+ double length = 0;
+ Coord p0 = pStart;
+ for (Coord p1 : points.subList(1, points.size()-1)) {
+ length += p0.distance(p1);
+ p0 = p1;
+ }
+ boolean nearlyClosed = pStart.distance(pEnd) < 0.1 * length;
+
+ if (nearlyClosed) {
+ // close the way
+ points.add(pStart);
+
+ if(!FakeIdGenerator.isFakeId(w.getId())) {
+ Way w1 = new Way(FakeIdGenerator.makeFakeId());
+ w1.getPoints().addAll(w.getPoints());
+ // only copy the name tags
+ for(String tag : w)
+ if(tag.equals("name") || tag.endsWith(":name"))
+ w1.addTag(tag, w.getTag(tag));
+ w = w1;
+ }
+ w.addTag(landTag[0], landTag[1]);
+ saver.addWay(w);
+ if(generateSeaUsingMP)
+ {
+ seaRelation.addElement("inner", w);
+ }
+ } else if(allowSeaSectors) {
+ long seaId = FakeIdGenerator.makeFakeId();
+ Way sea = new Way(seaId);
+ sea.getPoints().addAll(points);
+ sea.addPoint(new Coord(pEnd.getLatitude(), pStart.getLongitude()));
+ sea.addPoint(pStart);
+ sea.addTag("natural", "sea");
+ log.info("sea: ", sea);
+ saver.addWay(sea);
+ if(generateSeaUsingMP)
+ seaRelation.addElement("outer", sea);
+ generateSeaBackground = false;
+ } else if (extendSeaSectors) {
+ // create additional points at next border to prevent triangles from point 2
+ if (null == hStart) {
+ hStart = getNextEdgeHit(seaBounds, pStart);
+ w.getPoints().add(0, hStart.getPoint(seaBounds));
+ }
+ if (null == hEnd) {
+ hEnd = getNextEdgeHit(seaBounds, pEnd);
+ w.getPoints().add(hEnd.getPoint(seaBounds));
+ }
+ log.debug("hits (second try): ", hStart, hEnd);
+ hitMap.put(hStart, w);
+ hitMap.put(hEnd, null);
+ } else {
+ // show the coastline even though we can't produce
+ // a polygon for the land
+ w.addTag("natural", "coastline");
+ saver.addWay(w);
+ }
+ } else {
+ log.debug("hits: ", hStart, hEnd);
+ hitMap.put(hStart, w);
+ hitMap.put(hEnd, null);
+ }
+ }
+ return hitMap;
+ }
+
+ /**
+ * Specifies where an edge of the bounding box is hit.
+ */
+ private static class EdgeHit implements Comparable<EdgeHit>
+ {
+ private final int edge;
+ private final double t;
+
+ EdgeHit(int edge, double t) {
+ this.edge = edge;
+ this.t = t;
+ }
+
+ public int compareTo(EdgeHit o) {
+ if (edge < o.edge)
+ return -1;
+ else if (edge > o.edge)
+ return +1;
+ else if (t > o.t)
+ return +1;
+ else if (t < o.t)
+ return -1;
+ else
+ return 0;
+ }
+
+ public boolean equals(Object o) {
+ if (o instanceof EdgeHit) {
+ EdgeHit h = (EdgeHit) o;
+ return (h.edge == edge && Double.compare(h.t, t) == 0);
+ } else
+ return false;
+ }
+
+ private Coord getPoint(Area a) {
+ log.info("getPoint: ", this, a);
+ switch (edge) {
+ case 0:
+ return new Coord(a.getMinLat(), (int) (a.getMinLong() + t * (a.getMaxLong()-a.getMinLong())));
+
+ case 1:
+ return new Coord((int)(a.getMinLat() + t * (a.getMaxLat()-a.getMinLat())), a.getMaxLong());
+
+ case 2:
+ return new Coord(a.getMaxLat(), (int)(a.getMaxLong() - t * (a.getMaxLong()-a.getMinLong())));
+
+ case 3:
+ return new Coord((int)(a.getMaxLat() - t * (a.getMaxLat()-a.getMinLat())), a.getMinLong());
+
+ default:
+ throw new MapFailedException("illegal state");
+ }
+ }
+
+ public String toString() {
+ return "EdgeHit " + edge + "@" + t;
+ }
+ }
+
+ private EdgeHit getEdgeHit(Area a, Coord p) {
+ return getEdgeHit(a, p, 10);
+ }
+
+ private EdgeHit getEdgeHit(Area a, Coord p, int tolerance) {
+ int lat = p.getLatitude();
+ int lon = p.getLongitude();
+ int minLat = a.getMinLat();
+ int maxLat = a.getMaxLat();
+ int minLong = a.getMinLong();
+ int maxLong = a.getMaxLong();
+
+ log.info(String.format("getEdgeHit: (%d %d) (%d %d %d %d)", lat, lon, minLat, minLong, maxLat, maxLong));
+ if (lat <= minLat+tolerance) {
+ return new EdgeHit(0, ((double)(lon - minLong))/(maxLong-minLong));
+ } else if (lon >= maxLong-tolerance) {
+ return new EdgeHit(1, ((double)(lat - minLat))/(maxLat-minLat));
+ } else if (lat >= maxLat-tolerance) {
+ return new EdgeHit(2, ((double)(maxLong - lon))/(maxLong-minLong));
+ } else if (lon <= minLong+tolerance) {
+ return new EdgeHit(3, ((double)(maxLat - lat))/(maxLat-minLat));
+ } else
+ return null;
+ }
+
+ /**
+ * Find the nearest edge for supplied Coord p.
+ */
+ private EdgeHit getNextEdgeHit(Area a, Coord p)
+ {
+ int lat = p.getLatitude();
+ int lon = p.getLongitude();
+ int minLat = a.getMinLat();
+ int maxLat = a.getMaxLat();
+ int minLong = a.getMinLong();
+ int maxLong = a.getMaxLong();
+
+ log.info(String.format("getNextEdgeHit: (%d %d) (%d %d %d %d)", lat, lon, minLat, minLong, maxLat, maxLong));
+ // shortest distance to border (init with distance to southern border)
+ int min = lat - minLat;
+ // number of edge as used in getEdgeHit.
+ // 0 = southern
+ // 1 = eastern
+ // 2 = northern
+ // 3 = western edge of Area a
+ int i = 0;
+ // normalized position at border (0..1)
+ double l = ((double)(lon - minLong))/(maxLong-minLong);
+ // now compare distance to eastern border with already known distance
+ if (maxLong - lon < min) {
+ // update data if distance is shorter
+ min = maxLong - lon;
+ i = 1;
+ l = ((double)(lat - minLat))/(maxLat-minLat);
+ }
+ // same for northern border
+ if (maxLat - lat < min) {
+ min = maxLat - lat;
+ i = 2;
+ l = ((double)(maxLong - lon))/(maxLong-minLong);
+ }
+ // same for western border
+ if (lon - minLong < min) {
+ i = 3;
+ l = ((double)(maxLat - lat))/(maxLat-minLat);
+ }
+ // now created the EdgeHit for found values
+ return new EdgeHit(i, l);
+ }
+
+ private void closeGaps(List<Way> ways, Area bounds) {
+
+ // join up coastline segments whose end points are less than
+ // maxCoastlineGap metres apart
+ if (maxCoastlineGap > 0) {
+ boolean changed = true;
+ while (changed) {
+ changed = false;
+ for (Way w1 : ways) {
+ if(w1.isClosed())
+ continue;
+ List<Coord> points1 = w1.getPoints();
+ Coord w1e = points1.get(points1.size() - 1);
+ if(bounds.onBoundary(w1e))
+ continue;
+ Way nearest = null;
+ double smallestGap = Double.MAX_VALUE;
+ for (Way w2 : ways) {
+ if(w1 == w2 || w2.isClosed())
+ continue;
+ List<Coord> points2 = w2.getPoints();
+ Coord w2s = points2.get(0);
+ if(bounds.onBoundary(w2s))
+ continue;
+ double gap = w1e.distance(w2s);
+ if(gap < smallestGap) {
+ nearest = w2;
+ smallestGap = gap;
+ }
+ }
+ if (nearest != null && smallestGap < maxCoastlineGap) {
+ Coord w2s = nearest.getPoints().get(0);
+ log.warn("Bridging " + (int)smallestGap + "m gap in coastline from " + w1e.toOSMURL() + " to " + w2s.toOSMURL());
+ Way wm;
+ if (FakeIdGenerator.isFakeId(w1.getId())) {
+ wm = w1;
+ } else {
+ wm = new Way(FakeIdGenerator.makeFakeId());
+ ways.remove(w1);
+ ways.add(wm);
+ wm.getPoints().addAll(points1);
+ wm.copyTags(w1);
+ }
+ wm.getPoints().addAll(nearest.getPoints());
+ ways.remove(nearest);
+ // make a line that shows the filled gap
+ Way w = new Way(FakeIdGenerator.makeFakeId());
+ w.addTag("natural", "mkgmap:coastline-gap");
+ w.addPoint(w1e);
+ w.addPoint(w2s);
+ saver.addWay(w);
+ changed = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper class for threadlocal vars
+ *
+ *
+ */
+ class PrecompData {
+ /**
+ * The index is a grid [lon][lat]. Each element defines the content of one precompiled
+ * sea tile which are {@link #SEA_TYPE}, {@link #LAND_TYPE}, or {@link #MIXED_TYPE}, or 0 for unknown
+ */
+ private byte[][] precompIndex;
+ private String precompSeaExt;
+ private String precompSeaPrefix;
+ private String precompZipFileInternalPath;
+ private ZipFile zipFile;
+
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/SeaPolygonRelation.java b/src/uk/me/parabola/mkgmap/reader/osm/SeaPolygonRelation.java
new file mode 100644
index 0000000..d1d8a95
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/SeaPolygonRelation.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2014.
+ *
+ * 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.reader.osm;
+
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.util.GpxCreator;
+import uk.me.parabola.util.QuadTree;
+
+/**
+ * A relation used by the sea generation code.
+ *
+ * @author WanMil
+ */
+public class SeaPolygonRelation extends MultiPolygonRelation {
+ private static final Logger log = Logger
+ .getLogger(SeaPolygonRelation.class);
+
+ private final QuadTree landCoords;
+ private final QuadTree seaCoords;
+
+ private boolean floodBlocker = true;
+ private int floodBlockerGap = 40;
+ private double floodBlockerRatio = 0.5d;
+ private int floodBlockerThreshold = 20;
+ private boolean debug;
+ private final DecimalFormat format = new DecimalFormat("0.0000");
+ private Rule floodBlockerRules;
+
+ private final String[] landTag = {"natural","land"};
+
+ public SeaPolygonRelation(Relation other, Map<Long, Way> wayMap, Area bbox) {
+ super(other, wayMap, bbox);
+ this.landCoords = new QuadTree(bbox);
+ this.seaCoords = new QuadTree(bbox);
+ // set a special type because this is not the OSM common multipolygon
+ // relation
+ addTag("type", "mkgmap:seapolygon");
+ }
+
+ protected boolean isAreaSizeCalculated() {
+ return false;
+ }
+
+ protected void postProcessing() {
+ if (isFloodBlocker()) {
+ removeFloodedAreas();
+ }
+ super.postProcessing();
+ }
+
+ private void fillQuadTrees() {
+ final AtomicBoolean isLand = new AtomicBoolean(false);
+ final AtomicBoolean isSea = new AtomicBoolean(false);
+ TypeResult fakedType = new TypeResult() {
+ @Override
+ public void add(Element el, GType type) {
+ if (log.isDebugEnabled())
+ log.debug(el.getId(),type);
+ if (type.getType() == 0x01) {
+ isLand.set(true);
+ } else if (type.getType() == 0x02) {
+ isSea.set(true);
+ }
+ }
+ };
+ for (Way way : getTileWayMap().values()) {
+ if (log.isDebugEnabled())
+ log.debug("Check usage of way for floodblocker:", way.getId(), way.toTagString());
+ floodBlockerRules.resolveType(way, fakedType);
+
+ if (isLand.get()) {
+ // save these coords to check if some sea polygons floods
+ // the land
+ log.debug("Way", way.getId(), "identified as land");
+ landCoords.addAll(way.getPoints());
+ isLand.set(false);
+
+ } else if (isSea.get()) {
+ // save these coords to check if some sea polygons floods the
+ // land
+ log.debug("Way", way.getId(), "identified as sea");
+ seaCoords.addAll(way.getPoints());
+ isSea.set(false);
+ }
+ }
+ }
+
+ private void removeFloodedAreas() {
+ fillQuadTrees();
+
+ // create a copy of all resulting ways - the tile way map contains only
+ // polygons from
+ // the sea generation
+ ArrayList<Way> polygons = new ArrayList<Way>(getMpPolygons().values());
+
+ log.info("Starting flood blocker. Polygons to check:", getMpPolygons()
+ .size());
+
+ String baseName = GpxCreator.getGpxBaseName();
+ if (debug) {
+ GpxCreator.createAreaGpx(baseName + "bbox", getBbox());
+ }
+
+ // go through all polygons and check if it contains too many coords of
+ // the other type
+ for (Way p : polygons) {
+ boolean sea = "sea".equals(p.getTag("natural"));
+
+ QuadTree goodCoords = (sea ? seaCoords : landCoords);
+ QuadTree badCoords = (sea ? landCoords : seaCoords);
+ String polyType = (sea ? "sea" : "land");
+ String otherType = (sea ? "land" : "sea");
+
+ List<Coord> minusCoords = badCoords.get(p.getPoints(),
+ getFloodBlockerGap());
+ List<Coord> positiveCoords = goodCoords.get(p.getPoints());
+
+ log.info(polyType,"polygon", p.getId(), "contains",
+ minusCoords.size(), otherType,"coords and",
+ positiveCoords.size(), polyType,"coords.");
+
+ if (minusCoords.size() > 0) {
+ double area = MultiPolygonRelation.calcAreaSize(p.getPoints());
+ double ratio = ((minusCoords.size() - positiveCoords.size()) * 100000.0d / area);
+ String areaFMT = format.format(area);
+ String ratioFMT = format.format(ratio);
+ log.info("Flood blocker for", polyType, "polygon", p.getId());
+ log.info("area",areaFMT);
+ log.info(polyType, positiveCoords.size());
+ log.info(otherType, minusCoords.size());
+ log.info("ratio", ratioFMT);
+ if (debug) {
+ GpxCreator.createGpx(
+ baseName + p.getId() + "_"+polyType+"_"
+ + minusCoords.size() + "_"
+ + positiveCoords.size() + "_" + ratioFMT,
+ p.getPoints());
+ GpxCreator.createGpx(
+ baseName + p.getId() + "_con_"
+ + minusCoords.size() + "_"
+ + positiveCoords.size() + "_" + ratioFMT,
+ null, minusCoords);
+
+ if (positiveCoords.isEmpty() == false) {
+ GpxCreator.createGpx(
+ baseName + p.getId() + "_pro_"
+ + minusCoords.size() + "_"
+ + positiveCoords.size() + "_"
+ + ratioFMT, null,
+ positiveCoords);
+ }
+ }
+
+ if (minusCoords.size() - positiveCoords.size() >= getFloodBlockerThreshold()
+ && ratio > getFloodBlockerRatio()) {
+ log.warn("Polygon", p.getId(), "type",polyType,"seems to be wrong. Changing it to",otherType);
+ if (sea) {
+ p.deleteTag("natural");
+ p.addTag(landTag[0], landTag[1]);
+ } else {
+ p.deleteTag(landTag[0]);
+ p.addTag("natural", "sea");
+ }
+// getMpPolygons().remove(p.getId());
+ } else {
+ log.info("Polygon",p.getId(), "is not blocked");
+ }
+
+ }
+ }
+ log.info("Flood blocker finished. Resulting polygons:", getMpPolygons()
+ .size());
+
+ landCoords.clear();
+ seaCoords.clear();
+ }
+
+ public boolean isFloodBlocker() {
+ return floodBlocker;
+ }
+
+ public void setFloodBlocker(boolean floodBlocker) {
+ this.floodBlocker = floodBlocker;
+ }
+
+ public int getFloodBlockerGap() {
+ return floodBlockerGap;
+ }
+
+ public void setFloodBlockerGap(int floodBlockerGap) {
+ this.floodBlockerGap = floodBlockerGap;
+ }
+
+ public double getFloodBlockerRatio() {
+ return floodBlockerRatio;
+ }
+
+ public void setFloodBlockerRatio(double floodBlockerRatio) {
+ this.floodBlockerRatio = floodBlockerRatio;
+ }
+
+ public int getFloodBlockerThreshold() {
+ return floodBlockerThreshold;
+ }
+
+ public void setFloodBlockerThreshold(int floodBlockerThreshold) {
+ this.floodBlockerThreshold = floodBlockerThreshold;
+ }
+
+ public boolean isDebug() {
+ return debug;
+ }
+
+ public void setDebug(boolean debug) {
+ this.debug = debug;
+ }
+
+ public Rule getFloodBlockerRules() {
+ return floodBlockerRules;
+ }
+
+ public void setFloodBlockerRules(Rule floodBlockerRules) {
+ this.floodBlockerRules = floodBlockerRules;
+ }
+
+ public void setLandTag(String landTag, String landValue) {
+ this.landTag[0] = landTag;
+ this.landTag[1] = landValue;
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/Style.java b/src/uk/me/parabola/mkgmap/reader/osm/Style.java
new file mode 100644
index 0000000..a974e80
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/Style.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2008 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: 02-Nov-2008
+ */
+package uk.me.parabola.mkgmap.reader.osm;
+
+import java.util.Set;
+
+import uk.me.parabola.mkgmap.general.LineAdder;
+
+/**
+ * A style converts an OSM element into a garmin element.
+ *
+ * You start with an OSM element which is just a bunch of name/value tags
+ * and you need to convert this to the information required by the .img
+ * format which is basically just a name and an
+ * integer type. You also need to know at what zoom levels to show the
+ * element at.
+ *
+ * The Style interface holds the rules for doing this.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface Style {
+ public String getOption(String name);
+
+ public StyleInfo getInfo();
+
+ /**
+ * Get the rules that apply to ways. This includes lines and polygons
+ * as they are not separate primitives in osm. It is a merge of the line
+ * rules and the polygon rules.
+ */
+ public Rule getWayRules();
+
+ /**
+ * Get the rules that apply to nodes.
+ */
+ public Rule getNodeRules();
+
+ /**
+ * Get the rules that apply to lines.
+ */
+ public Rule getLineRules();
+
+ /**
+ * Get the rules that apply to polygons.
+ */
+ public Rule getPolygonRules();
+
+ /**
+ * Get the relation rules.
+ */
+ public Rule getRelationRules();
+
+ /**
+ * Get the overlay definitions. Most styles will not use this.
+ */
+ public LineAdder getOverlays(LineAdder lineAdder);
+
+ /**
+ * Get the tags that are used by this style.
+ */
+ public Set<String> getUsedTags();
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/StyleInfo.java b/src/uk/me/parabola/mkgmap/reader/osm/StyleInfo.java
new file mode 100644
index 0000000..0e0e927
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/StyleInfo.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 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: Apr 20, 2008
+ */
+package uk.me.parabola.mkgmap.reader.osm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Information about a style. This is so style authors can include
+ * descriptions of their styles within the style itself.
+ *
+ * @author Steve Ratcliffe
+ */
+public class StyleInfo {
+
+ private String version;
+ private String summary;
+ private String longDescription;
+ private final List<String> baseStyleNames = new ArrayList<String>();
+
+
+ public String getSummary() {
+ return summary == null ? "No summary available" : summary.trim();
+ }
+
+ public String getVersion() {
+ return version == null ? "1" : version.trim();
+ }
+
+ public String getLongDescription() {
+ return longDescription != null ? longDescription.trim() : "";
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public void setSummary(String summary) {
+ this.summary = summary;
+ }
+
+ public void setLongDescription(String longDescription) {
+ this.longDescription = longDescription;
+ }
+
+ public Iterable<String> baseStyles() {
+ return baseStyleNames;
+ }
+
+ public void addBaseStyleName(String name) {
+ baseStyleNames.add(name.trim());
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/Tags.java b/src/uk/me/parabola/mkgmap/reader/osm/Tags.java
new file mode 100644
index 0000000..21627ab
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/Tags.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2008 - 2012.
+ *
+ * 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.reader.osm;
+
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * Store the tags that belong to an Element.
+ *
+ * Used to use a HashMap for this. We used to have a requirement to be able
+ * to add to the map during iteration over it but now the main reason
+ * to keep this class is that it is more memory efficient than a regular
+ * HashMap (hash maps are the main use of memory in the
+ * application), as it doesn't allocate a Map.Entry object for every tag.
+ * Performance of the whole application is unchanged compared with when
+ * a regular HashMap was used.
+ *
+ * It doesn't fully behave the same way that a map would.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Tags implements Iterable<String> {
+ private static final int INIT_SIZE = 8;
+
+ private short keySize;
+ private short capacity;
+
+ private short size;
+
+ private String[] keys;
+ private String[] values;
+
+ public Tags() {
+ keys = new String[INIT_SIZE];
+ values = new String[INIT_SIZE];
+ capacity = INIT_SIZE;
+ }
+
+ public String get(String key) {
+ int ind = keyPos(key);
+ if (ind < 0)
+ return null;
+
+ return values[ind];
+ }
+
+ /**
+ * Retrieves the number of tags.
+ * @return number of tags
+ */
+ public int size() {
+ return size;
+ }
+
+ public String put(String key, String value) {
+ assert key != null : "key is null";
+ assert value != null : "value is null";
+ ensureSpace();
+ int ind = keyPos(key);
+ if (ind < 0)
+ assert false : "keyPos(" + key + ") returns null - size = " + keySize + ", capacity = " + capacity;
+ keys[ind] = key;
+
+ String old = values[ind];
+ if (old == null) {
+ keySize++;
+ size++;
+ }
+ values[ind] = value;
+
+ return old;
+ }
+
+ public String remove(String key) {
+ int k = keyPos(key);
+
+ if (k >= 0 && values[k] != null) {
+ // because of the way this works, you can never remove keys
+ // except when resizing.
+ String old = values[k];
+ values[k] = null;
+ size--;
+ return old;
+ }
+ return null;
+ }
+
+ /**
+ * Make a deep copy of this object.
+ * @return A copy of this object.
+ */
+ public Tags copy() {
+ Tags cp = new Tags();
+ cp.keySize = keySize;
+ cp.size = size;
+ cp.capacity = capacity;
+
+ cp.keys = Arrays.copyOf(keys, keys.length);
+ cp.values = Arrays.copyOf(values, values.length);
+ return cp;
+ }
+
+ private void ensureSpace() {
+ while (keySize + 1 >= capacity) {
+ short ncap = (short) (capacity*2);
+ String[] okey = keys;
+ String[] oval = values;
+ keys = new String[ncap];
+ values = new String[ncap];
+ capacity = ncap;
+ keySize = 0;
+ size = 0;
+ for (int i = 0; i < okey.length; i++) {
+ String k = okey[i];
+ String v = oval[i]; // null if tag has been removed
+ if (k != null && v != null)
+ put(k, v);
+ }
+ }
+ assert keySize < capacity;
+ }
+
+ private int keyPos(String key) {
+ int h = key.hashCode();
+ int k = h & (capacity - 1);
+
+ int i = k;
+ do {
+ String fk = keys[i];
+ if (fk == null || fk.equals(key))
+ return i;
+ i++;
+ if (i >= capacity)
+ i = 0;
+ } while (i != k);
+ return -1;
+ }
+
+ /**
+ * Iterates over the tags in a special way that is used to look up in
+ * the rules.
+ *
+ * If you have the tags a=b, c=d then you will get the following strings
+ * returned: "a=b", "a=*", "c=d", "c=*".
+ *
+ * If you add a tag during the iteration, then it is guaranteed to
+ * appear later in the iteration.
+ */
+ public Iterator<String> iterator() {
+ return new Iterator<String>() {
+ private int pos;
+
+ public boolean hasNext() {
+ // After every normal entry there is a wild card entry.
+ //if (doWild)
+ // return true;
+
+ // Normal entries in the map
+ for (int i = pos; i < capacity; i++) {
+ if (values[i] != null) {
+ pos = i;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the next tag as a single string. Also returns wild card
+ * entries.
+ */
+ public String next() {
+ /*if (doWild) {
+ doWild = false;
+ return wild + "=*";
+ } else*/ if (pos < capacity) {
+ for (int i = pos; i < capacity; i++) {
+ if (values[i] != null) {
+ pos = i+1;
+ return (keys[i] + "=" + values[i]);
+ }
+ }
+ pos = capacity;
+ }
+
+ return null;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ public Iterator<Map.Entry<String, String>> entryIterator() {
+ return new Iterator<Map.Entry<String, String>>() {
+ private int pos;
+
+ public boolean hasNext() {
+ for (int i = pos; i < capacity; i++) {
+ if (values[i] != null) {
+ pos = i;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public Map.Entry<String, String> next() {
+ Map.Entry<String, String> entry = new AbstractMap.SimpleEntry<String, String>(keys[pos], values[pos]);
+
+ pos++;
+ return entry;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ public Map<String, String> getTagsWithPrefix(String prefix, boolean removePrefix) {
+ Map<String, String> map = new HashMap<String, String>();
+
+ int prefixLen = prefix.length();
+ for(int i = 0; i < capacity; ++i) {
+ if(keys[i] != null && keys[i].startsWith(prefix)) {
+ if(removePrefix)
+ map.put(keys[i].substring(prefixLen), values[i]);
+ else
+ map.put(keys[i], values[i]);
+ }
+ }
+
+ return map;
+ }
+
+ public void removeAll() {
+ for (int i = 0; i < capacity; i++){
+ keys[i] = null;
+ values[i] = null;
+ }
+ keySize = 0;
+ size = 0;
+ }
+
+ public String toString() {
+ StringBuilder s =new StringBuilder();
+ s.append("[");
+ Iterator<Entry<String,String>> tagIter = entryIterator();
+ while (tagIter.hasNext()) {
+ Entry<String,String> tag = tagIter.next();
+ if (s.length() > 1) {
+ s.append("; ");
+ }
+ s.append(tag.getKey());
+ s.append("=");
+ s.append(tag.getValue());
+ }
+ s.append("]");
+ return s.toString();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/TypeResult.java b/src/uk/me/parabola/mkgmap/reader/osm/TypeResult.java
new file mode 100644
index 0000000..e32c63d
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/TypeResult.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.reader.osm;
+
+/**
+ * Interface for adding a map element to the map. Called from the style
+ * engine when it has resolved a type from the input osm tags.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface TypeResult {
+ /**
+ * Add the resolved type to next stage in the map making process.
+ * @param el The OSM element.
+ * @param type The Garmin type that this resolves too.
+ */
+ public void add(Element el, GType type);
+
+ /**
+ * Use this if you don't want to save the results. Only likely to be
+ * used for the test cases.
+ */
+ public static TypeResult NULL_RESULT = new TypeResult() {
+ public void add(Element el, GType type) {
+ }
+ };
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/UnusedElementsRemoverHook.java b/src/uk/me/parabola/mkgmap/reader/osm/UnusedElementsRemoverHook.java
new file mode 100644
index 0000000..4ec11fe
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/UnusedElementsRemoverHook.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.reader.osm;
+
+import java.awt.Rectangle;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * The hook removes all elements that will not be included in the map and can therefore
+ * be safely removed. This improves the performance because the elements does not have
+ * to go through the style system.
+ *
+ * @author WanMil
+ */
+public class UnusedElementsRemoverHook extends OsmReadingHooksAdaptor {
+ private static final Logger log = Logger.getLogger(UnusedElementsRemoverHook.class);
+
+ private ElementSaver saver;
+
+ /** node with tags of this list must not be removed */
+ private Collection<String> nodeTagBlacklist;
+
+ public UnusedElementsRemoverHook() {
+ }
+
+ public boolean init(ElementSaver saver, EnhancedProperties props) {
+ this.saver = saver;
+
+ // Get the tags from the POIGeneratorHook which are used to define the point
+ // where the POI is placed in polygons. They must not be removed if the polygon
+ // is not removed. Checking if the polygon is not removed is too costly therefore
+ // all nodes with these tags are kept.
+ nodeTagBlacklist = new HashSet<String>();
+ List<Entry<String,String>> areasToPoiNodeTags = POIGeneratorHook.getPoiPlacementTags(props);
+ for (Entry<String,String> nodeTags : areasToPoiNodeTags) {
+ nodeTagBlacklist.add(nodeTags.getKey());
+ }
+
+ return true;
+ }
+
+ public void end() {
+ long t1 = System.currentTimeMillis();
+ log.info("Removing unused elements");
+
+ final Area bbox = saver.getBoundingBox();
+
+ long nodes = saver.getNodes().size();
+
+ // go through all nodes
+ for (Node node : new ArrayList<Node>(saver.getNodes().values())) {
+
+ // nodes without tags can be removed
+ if (node.getTagCount() == 0) {
+ saver.getNodes().remove(node.getId());
+ continue;
+ }
+
+ // check if the node is within the tile bounding box
+ if (bbox.contains(node.getLocation()) == false) {
+ boolean removeNode = true;
+
+ // check if the node has no tag of the blacklist
+ if (nodeTagBlacklist.isEmpty() == false) {
+ for (String tag : nodeTagBlacklist ) {
+ if (node.getTag(tag) != null) {
+ // the node contains one tag that might be interesting for the POIGeneratorHook
+ // do not remove it
+ removeNode = false;
+ break;
+ }
+ }
+ }
+ if (removeNode) {
+ saver.getNodes().remove(node.getId());
+ } else {
+ log.debug("Keep node", node, "because it contains a tag which might be required for the area-to-poi function.");
+ }
+ }
+ }
+
+ long tr1 = System.currentTimeMillis();
+
+ // store all way ids that are referenced by a relation
+ // all tags without a tag must not be removed if they are referenced by a relation
+ Set<Long> relationWays = new HashSet<Long>();
+ for (Relation rel : saver.getRelations().values()) {
+ for (Entry<String, Element> relEntry : rel.getElements()) {
+ if (relEntry.getValue() instanceof Way) {
+ relationWays.add(relEntry.getValue().getId());
+ }
+ }
+ }
+ log.debug("Collecting way ids from relations took", (System.currentTimeMillis()-tr1), "ms");
+
+ Rectangle bboxRect = new Rectangle(bbox.getMinLong(), bbox.getMinLat(), bbox.getWidth(), bbox.getHeight());
+ long relWays = 0;
+ long ways = saver.getWays().size();
+ for (Way way : new ArrayList<Way>(saver.getWays().values())) {
+ if (way.getPoints().isEmpty()) {
+ // empty way will not appear in the map => remove it
+ saver.getWays().remove(way.getId());
+ continue;
+ }
+
+ // check if a way has no tags and is not a member of a relation
+ // a relation might be used to add tags to the way using the style file
+ if (way.getTagCount() == 0) {
+ if (relationWays.contains(way.getId())) {
+ relWays++;
+ } else {
+ saver.getWays().remove(way.getId());
+ continue;
+ }
+ }
+
+ // check if the way is completely outside the tile bounding box
+ boolean coordInBbox = false;
+ Coord prevC = null;
+
+ // It is possible that the way is larger than the bounding box and therefore
+ // contains the bbox completely. Especially this is true for the sea polygon
+ // when using --generate-sea=polygon
+ // So need the calc the bbox of the way
+ Coord firstC = way.getPoints().get(0);
+ int minLat = firstC.getLatitude();
+ int maxLat = firstC.getLatitude();
+ int minLong = firstC.getLongitude();
+ int maxLong = firstC.getLongitude();
+
+ for (Coord c : way.getPoints()) {
+ if (bbox.contains(c)) {
+ coordInBbox = true;
+ break;
+ } else if (prevC != null) {
+ // check if the line intersects the bounding box
+ if (bboxRect.intersectsLine(prevC.getLongitude(), prevC.getLatitude(), c.getLongitude(), c.getLatitude())) {
+ if (log.isDebugEnabled()) {
+ log.debug("Intersection!");
+ log.debug("Bbox:", bbox);
+ log.debug("Way coords:", prevC, c);
+ }
+ coordInBbox = true;
+ break;
+ }
+ }
+
+ if (minLat > c.getLatitude()) {
+ minLat = c.getLatitude();
+ } else if (maxLat < c.getLatitude()) {
+ maxLat = c.getLatitude();
+ }
+ if (minLong > c.getLongitude()) {
+ minLong = c.getLongitude();
+ } else if (maxLong < c.getLongitude()) {
+ maxLong = c.getLongitude();
+ }
+
+ prevC = c;
+ }
+ if (coordInBbox==false) {
+ // no coord of the way is within the bounding box
+ // check if the way possibly covers the bounding box completely
+ Area wayBbox = new Area(minLat, minLong, maxLat, maxLong);
+ if (wayBbox.intersects(saver.getBoundingBox())) {
+ log.debug(way, "possibly covers the bbox completely. Keep it.", way.toTagString());
+ } else {
+ saver.getWays().remove(way.getId());
+ }
+ }
+ }
+
+ log.info("Relation referenced ways:", relationWays.size(), "Used:", relWays);
+ log.info("Nodes: before:", nodes, "after:", saver.getNodes().size());
+ log.info("Ways: before:", ways, "after:", saver.getWays().size());
+ log.info("Removing unused elements took", (System.currentTimeMillis()-t1), "ms");
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/WatchableTypeResult.java b/src/uk/me/parabola/mkgmap/reader/osm/WatchableTypeResult.java
new file mode 100644
index 0000000..357a032
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/WatchableTypeResult.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.reader.osm;
+
+/**
+ * At the top level we need to be able to watch to see if a result was found
+ * to implement stop-on-first-match, continue and the like.
+ *
+ * @author Steve Ratcliffe
+ */
+public class WatchableTypeResult implements TypeResult {
+ private boolean actionsOnly;
+ private boolean found;
+ private boolean continued;
+ private int count;
+
+ private final TypeResult result;
+
+ public WatchableTypeResult(TypeResult result) {
+ this.result = result;
+ }
+
+ public void add(Element el, GType type) {
+ if (type == null) {
+ actionsOnly = true;
+ return;
+ }
+
+ if (type.isContinueSearch())
+ continued = true;
+
+ count++;
+ found = true;
+ result.add(el, type);
+ }
+
+ /**
+ * Was a result found.
+ * @return True if one or more results were added since the last reset.
+ */
+ public boolean isFound() {
+ return found;
+ }
+
+ /**
+ * Are we all done for this element?
+ * @return True if we found a matching type and it did not have the continue
+ * flag set.
+ */
+ public boolean isResolved() {
+ return found && !continued;
+ }
+
+ public boolean isActionsOnly() {
+ return actionsOnly;
+ }
+
+ /**
+ * Reset the watcher for the next element.
+ */
+ public void reset() {
+ count = 0;
+ actionsOnly = false;
+ continued = false;
+ found = false;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/Way.java b/src/uk/me/parabola/mkgmap/reader/osm/Way.java
new file mode 100644
index 0000000..a6c5a25
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/Way.java
@@ -0,0 +1,205 @@
+/*
+ * 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: 17-Dec-2006
+ */
+package uk.me.parabola.mkgmap.reader.osm;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Coord;
+
+/**
+ * Represent a OSM way in the 0.5 api. A way consists of an ordered list of
+ * nodes.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Way extends Element {
+
+ private final List<Coord> points;
+
+ // This will be set if a way is read from an OSM file and the first node is the same node as the last
+ // one in the way. This can be set to true even if there are missing nodes and so the nodes that we
+ // have do not form a closed loop.
+ // Note: this is not always set, you must use isClosed()
+ private boolean closed;
+
+ // This is set to false if, we know that there are nodes missing from this way.
+ // If you set this to false, then you *must* also set closed to the correct value.
+ private boolean complete = true;
+
+ public Way(long id) {
+ points = new ArrayList<Coord>(5);
+ setId(id);
+ }
+
+ public Way(long id, List<Coord> points) {
+ this.points = new ArrayList<Coord>(points);
+ setId(id);
+ }
+
+ public Way copy() {
+ Way dup = new Way(getId(), points);
+ dup.copyTags(this);
+ dup.closed = this.closed;
+ dup.complete = this.complete;
+ return dup;
+ }
+
+ /**
+ * Get the points that make up the way. We attempt to re-order the segments
+ * and return a list of points that traces the route of the way.
+ *
+ * @return A simple list of points that form a line.
+ */
+ public List<Coord> getPoints() {
+ return points;
+ }
+
+ public void addPoint(Coord co) {
+ points.add(co);
+ }
+
+ public void addPointIfNotEqualToLastPoint(Coord co) {
+ if(points.isEmpty() || !co.equals(points.get(points.size() - 1)))
+ points.add(co);
+ }
+
+ public void reverse() {
+ Collections.reverse(points);
+ }
+
+ /**
+ * Returns true if the way is really closed in OSM.
+ *
+ * Will return true even if the way is incomplete in the tile that we are reading, but the way is
+ * really closed in OSM.
+ *
+ * @return True if the way is really closed.
+ */
+ public boolean isClosed() {
+ if (!isComplete())
+ return closed;
+
+ return !points.isEmpty() && points.get(0).equals(points.get(points.size()-1));
+ }
+
+ public void setClosed(boolean closed) {
+ this.closed = closed;
+ }
+
+ public boolean isComplete() {
+ return complete;
+ }
+
+ /**
+ * Set this to false if you know that the way does not have its complete set of nodes.
+ *
+ * If you do set this to false, then you must also call {@link #setClosed} to indicate if the way
+ * is really closed or not.
+ */
+ public void setComplete(boolean complete) {
+ this.complete = complete;
+ }
+
+ /**
+ * A simple representation of this way.
+ * @return A string with the name and start point
+ */
+ public String toString() {
+ if (points.isEmpty())
+ return "Way: empty";
+
+ Coord coord = points.get(0);
+ StringBuilder sb = new StringBuilder();
+ sb.append("WAY: ").append(getId()).append(" ");
+ sb.append(getName());
+ sb.append('(');
+ sb.append(Utils.toDegrees(coord.getLatitude()));
+ sb.append('/');
+ sb.append(Utils.toDegrees(coord.getLongitude()));
+ sb.append(')');
+ sb.append(' ');
+ sb.append(toTagString());
+ return sb.toString();
+ }
+
+ public int hashCode() {
+ return (int) getId();
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ return getId() == ((Way) o).getId();
+ }
+
+ public Coord getCofG() {
+ int numPoints = points.size();
+ if(numPoints < 1)
+ return null;
+
+ double lat = 0;
+ double lon = 0;
+ for(Coord p : points) {
+ lat += (double)p.getLatitude()/numPoints;
+ lon += (double)p.getLongitude()/numPoints;
+ }
+ return new Coord((int)Math.round(lat), (int)Math.round(lon));
+ }
+
+ public String kind() {
+ return "way";
+ }
+
+ // returns true if the way is a closed polygon with a clockwise
+ // direction
+ public static boolean clockwise(List<Coord> points) {
+
+ if(points.size() < 3 || !points.get(0).equals(points.get(points.size() - 1)))
+ return false;
+
+ long area = 0;
+ Coord p1 = points.get(0);
+ for(int i = 1; i < points.size(); ++i) {
+ Coord p2 = points.get(i);
+ area += ((long)p1.getLongitude() * p2.getLatitude() -
+ (long)p2.getLongitude() * p1.getLatitude());
+ p1 = p2;
+ }
+
+ // this test looks to be inverted but gives the expected result!
+ // empty linear areas are defined as clockwise
+ return area <= 0;
+ }
+
+ // simplistic check to see if this way "contains" another - for
+ // speed, all we do is check that all of the other way's points
+ // are inside this way's polygon
+ public boolean containsPointsOf(Way other) {
+ Polygon thisPoly = new Polygon();
+ for(Coord p : points)
+ thisPoly.addPoint(p.getLongitude(), p.getLatitude());
+ for(Coord p : other.points)
+ if(!thisPoly.contains(p.getLongitude(), p.getLatitude()))
+ return false;
+ return true;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/bin/OsmBinCoastDataSource.java b/src/uk/me/parabola/mkgmap/reader/osm/bin/OsmBinCoastDataSource.java
new file mode 100644
index 0000000..aa6120a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/bin/OsmBinCoastDataSource.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010, 2012.
+ *
+ * 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.reader.osm.bin;
+
+import java.util.Collections;
+import java.util.Set;
+
+import uk.me.parabola.mkgmap.reader.osm.CoastlineElementSaver;
+import uk.me.parabola.mkgmap.reader.osm.OsmReadingHooks;
+
+public class OsmBinCoastDataSource extends OsmBinMapDataSource {
+
+ private static final Set<String> coastlineTags = Collections.singleton("natural");
+
+ protected void addBackground(boolean mapHasPolygon4B) {
+ // do not add a background polygon
+ }
+
+ protected OsmReadingHooks[] getPossibleHooks() {
+ // no hooks
+ return new OsmReadingHooks[] {};
+ }
+
+ protected void createElementSaver() {
+ elementSaver = new CoastlineElementSaver(getConfig());
+ }
+
+ public Set<String> getUsedTags() {
+ return coastlineTags;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/bin/OsmBinHandler.java b/src/uk/me/parabola/mkgmap/reader/osm/bin/OsmBinHandler.java
new file mode 100644
index 0000000..4031682
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/bin/OsmBinHandler.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.reader.osm.bin;
+
+import java.util.List;
+
+import uk.me.parabola.imgfmt.MapFailedException;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.GeneralRelation;
+import uk.me.parabola.mkgmap.reader.osm.Node;
+import uk.me.parabola.mkgmap.reader.osm.OsmHandler;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.EnhancedProperties;
+
+import crosby.binary.BinaryParser;
+import crosby.binary.Osmformat;
+
+/**
+ * Handler for Scott Crosby's binary format, based on the Google
+ * protobuf format.
+ *
+ * @author Steve Ratcliffe
+ */
+public class OsmBinHandler extends OsmHandler {
+
+ public OsmBinHandler(EnhancedProperties props) {
+ }
+
+ public class BinParser extends BinaryParser {
+
+ protected void parse(Osmformat.HeaderBlock header) {
+ double multiplier = .000000001;
+ double maxLon = header.getBbox().getRight() * multiplier;
+ double minLon = header.getBbox().getLeft() * multiplier;
+ double maxLat = header.getBbox().getTop() * multiplier;
+ double minLat = header.getBbox().getBottom() * multiplier;
+
+ for (String s : header.getRequiredFeaturesList()) {
+ if (s.equals("OsmSchema-V0.6"))
+ continue; // We can parse this.
+
+ if (s.equals("DenseNodes"))
+ continue; // We can parse this.
+
+ throw new MapFailedException("File requires unknown feature: " + s);
+ }
+
+ setBBox(minLat, minLon, maxLat, maxLon);
+ }
+
+ protected void parseNodes(List<Osmformat.Node> nodes) {
+ for (Osmformat.Node binNode : nodes) {
+ Coord co = new Coord(parseLat(binNode.getLat()), parseLon(binNode.getLon()));
+ long id = binNode.getId();
+ saver.addPoint(id, co);
+
+ int tagCount = binNode.getKeysCount();
+ if (tagCount > 0) {
+ Node node = new Node(id, co);
+ for (int tid = 0; tid < tagCount; tid++) {
+ String key = getStringById(binNode.getKeys(tid));
+ String val = getStringById(binNode.getVals(tid));
+ key = keepTag(key, val);
+ if (key != null)
+ node.addTag(key, val.intern());
+ }
+
+ saver.addNode(node);
+ hooks.onAddNode(node);
+ }
+ }
+ }
+
+ protected final void parseDense(Osmformat.DenseNodes nodes) {
+ long lastId = 0, lastLat = 0, lastLon = 0;
+
+ int kvid = 0; // Index into the key val array.
+
+ for (int nid = 0; nid < nodes.getIdCount(); nid++) {
+ long lat = nodes.getLat(nid) + lastLat;
+ long lon = nodes.getLon(nid) + lastLon;
+ long id = nodes.getId(nid) + lastId;
+ lastLat = lat;
+ lastLon = lon;
+ lastId = id;
+
+ Coord co = new Coord(parseLat(lat), parseLon(lon));
+ saver.addPoint(id, co);
+
+ if (nodes.getKeysValsCount() > 0) {
+ int ntags = 0;
+ Node node = null;
+ while (nodes.getKeysVals(kvid) != 0) {
+ int keyid = nodes.getKeysVals(kvid++);
+ int valid = nodes.getKeysVals(kvid++);
+ String key = getStringById(keyid);
+ String val = getStringById(valid);
+ key = keepTag(key, val);
+ if (key != null) {
+ if (node == null)
+ node = new Node(id, co);
+ node.addTag(key, val.intern());
+ ntags++;
+ }
+ }
+ kvid++; // Skip over the '0' delimiter.
+
+ if (ntags > 0) {
+ // If there are tags, then we save a proper node for it.
+ saver.addNode(node);
+ hooks.onAddNode(node);
+ }
+ }
+ }
+ }
+
+ protected void parseWays(List<Osmformat.Way> ways) {
+ for (Osmformat.Way binWay : ways) {
+ Way way = startWay(binWay.getId());
+
+ for (int j = 0; j < binWay.getKeysCount(); j++) {
+
+ String key = getStringById(binWay.getKeys(j));
+ String val = getStringById(binWay.getVals(j));
+ key = keepTag(key, val);
+ if (key != null)
+ way.addTag(key, val.intern());
+ }
+
+ long nid = 0;
+ for (long idDelta : binWay.getRefsList()) {
+ nid += idDelta;
+ addCoordToWay(way, nid);
+ }
+
+ endWay(way);
+ }
+ }
+
+ protected void parseRelations(List<Osmformat.Relation> rels) {
+
+ for (Osmformat.Relation binRel : rels) {
+ long id = binRel.getId();
+ GeneralRelation rel = new GeneralRelation(id);
+
+ boolean tagsIncomplete = false;
+ for (int j = 0; j < binRel.getKeysCount(); j++) {
+ String key = getStringById(binRel.getKeys(j));
+ String val = getStringById(binRel.getVals(j));
+ // type is required for relations - all other tags are filtered
+ if ("type".equals(key))
+ // intern the string
+ key = "type";
+ else
+ key = keepTag(key, val);
+ if (key == null)
+ tagsIncomplete = true;
+ else
+ rel.addTag(key, val.intern());
+ }
+
+ if (tagsIncomplete) {
+ String relType = rel.getTag("type");
+ if ("multipolygon".equals(relType) || "boundary".equals(relType)) {
+ // mark the multipolygons if there are some tags that are not loaded
+ rel.addTag(TAGS_INCOMPLETE_TAG, "true");
+ }
+ }
+
+ long lastMid = 0;
+
+ for (int j = 0; j < binRel.getMemidsCount(); j++) {
+ long mid = lastMid + binRel.getMemids(j);
+ lastMid = mid;
+ String role = getStringById(binRel.getRolesSid(j));
+ Element el = null;
+
+ if (binRel.getTypes(j) == Osmformat.Relation.MemberType.NODE) {
+ el = saver.getNode(mid);
+ if(el == null) {
+ // we didn't make a node for this point earlier,
+ // do it now (if it exists)
+ Coord co = saver.getCoord(mid);
+ if(co != null) {
+ el = new Node(mid, co);
+ saver.addNode((Node)el);
+ }
+ }
+ } else if (binRel.getTypes(j) == Osmformat.Relation.MemberType.WAY) {
+ el = saver.getWay(mid);
+ } else if (binRel.getTypes(j) == Osmformat.Relation.MemberType.RELATION) {
+ el = saver.getRelation(mid);
+ if (el == null) {
+ saver.deferRelation(mid, rel, role);
+ }
+ } else {
+ assert false;
+ }
+
+ if (el != null) // ignore non existing ways caused by splitting files
+ rel.addElement(role, el);
+ }
+ saver.addRelation(rel);
+ }
+ }
+
+ /**
+ * Called when the file is fully read.
+ */
+ public void complete() {
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/bin/OsmBinMapDataSource.java b/src/uk/me/parabola/mkgmap/reader/osm/bin/OsmBinMapDataSource.java
new file mode 100644
index 0000000..e846be1
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/bin/OsmBinMapDataSource.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 - 2012.
+ *
+ * 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.reader.osm.bin;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import uk.me.parabola.imgfmt.FormatException;
+import uk.me.parabola.mkgmap.reader.osm.OsmMapDataSource;
+import uk.me.parabola.mkgmap.reader.osm.bin.OsmBinHandler.BinParser;
+
+import crosby.binary.file.BlockInputStream;
+
+/**
+ * Read an OpenStreetMap data file in .osm version 0.5 format. It is converted
+ * into a generic format that the map is built from.
+ * <p>The intermediate format is important as several passes are required to
+ * produce the map at different zoom levels. At lower resolutions, some roads
+ * will have fewer points or won't be shown at all.
+ *
+ * @author Steve Ratcliffe
+ */
+public class OsmBinMapDataSource extends OsmMapDataSource {
+
+ public boolean isFileSupported(String name) {
+ // The extension for the protobuf format is now fixed at .pbf
+ // Previously we temporarily used the .bin extension to
+ // indicate Scott's format. The .bin extension remains here for the
+ // time being, but may be removed. Please use .pbf.
+ return name.endsWith(".pbf") || name.endsWith(".bin");
+ }
+
+ @Override
+ public void load(InputStream is) throws FormatException {
+
+ OsmBinHandler handler = new OsmBinHandler(getConfig());
+
+ setupHandler(handler);
+
+ try {
+ BinParser reader = handler.new BinParser();
+ handler = null;
+ BlockInputStream stream = new BlockInputStream(is, reader);
+ stream.process();
+ } catch (NoClassDefFoundError e) {
+ throw new FormatException("Failed to read binary file, probably missing protobuf.jar");
+ } catch (IOException e) {
+ throw new FormatException("Failed to read binary file");
+ }
+ elementSaver.finishLoading();
+
+ osmReadingHooks.end();
+ osmReadingHooks = null;
+
+ // now convert the saved elements
+ elementSaver.convert(getConverter());
+
+ addBackground();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/bin/OsmBinPrecompSeaDataSource.java b/src/uk/me/parabola/mkgmap/reader/osm/bin/OsmBinPrecompSeaDataSource.java
new file mode 100644
index 0000000..804964a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/bin/OsmBinPrecompSeaDataSource.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.reader.osm.bin;
+
+import java.util.Collections;
+import java.util.Set;
+
+import uk.me.parabola.mkgmap.reader.osm.OsmReadingHooks;
+import uk.me.parabola.mkgmap.reader.osm.PrecompSeaElementSaver;
+
+public class OsmBinPrecompSeaDataSource extends OsmBinMapDataSource {
+
+ private static final Set<String> coastlineTags = Collections.singleton("natural");
+
+ protected void addBackground(boolean mapHasPolygon4B) {
+ // do not add a background polygon
+ }
+
+ protected OsmReadingHooks[] getPossibleHooks() {
+ // no hooks
+ return new OsmReadingHooks[] {};
+ }
+
+ public Set<String> getUsedTags() {
+ return coastlineTags;
+ }
+
+ protected void createElementSaver() {
+ elementSaver = new PrecompSeaElementSaver(getConfig());
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/bin/package.html b/src/uk/me/parabola/mkgmap/reader/osm/bin/package.html
new file mode 100644
index 0000000..58975eb
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/bin/package.html
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2010.
+ ~
+ ~ 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.
+ -->
+<body>
+<h1>Reader for OSM binary format</h1>
+<p>There are a number of binary formats, this format is Scott Crosby's
+binary format based on Google's protobuf.</p>
+
+<p>To make use of this reader you must have the java protobuf library
+as well as Scott's OSM-binary package http://github.com/scrosby/OSM-binary</p>
+
+<p>The format is a storage format designed to be quicker and smaller than the
+XML format but preserve the element ordering and features of that format.
+We can therefore pretty much re-use most of the code that is used for reading the
+XML format.</p>
+</body>
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/Boundary.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/Boundary.java
new file mode 100644
index 0000000..1539ed7
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/Boundary.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2006, 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.reader.osm.boundary;
+
+import java.awt.geom.Area;
+import java.util.Map.Entry;
+
+import uk.me.parabola.mkgmap.reader.osm.Tags;
+
+public class Boundary {
+ private String id; // the id of the OSM relation (was kept in tag "mkgmap:boundaryid")
+
+ private final Tags tags;
+ private transient Area area;
+
+ public Boundary(Area area, Tags tags, String id) {
+ this.area = new Area(area);
+ this.tags = tags.copy();
+ this.id = id;
+ }
+
+ public Boundary(Area area, Iterable<Entry<String, String>> tags, String id) {
+ this.area = new Area(area);
+ this.id = id;
+ this.tags = new Tags();
+ for (Entry<String, String> tag : tags) {
+ this.tags.put(tag.getKey(), tag.getValue());
+ }
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public Tags getTags() {
+ return tags;
+ }
+
+ public Area getArea() {
+ return area;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryConverter.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryConverter.java
new file mode 100644
index 0000000..7140346
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryConverter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2006, 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.reader.osm.boundary;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.mkgmap.reader.osm.Node;
+import uk.me.parabola.mkgmap.reader.osm.OsmConverter;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.Java2DConverter;
+
+public class BoundaryConverter implements OsmConverter {
+
+ private final BoundarySaver saver;
+ public BoundaryConverter(BoundarySaver saver) {
+ this.saver= saver;
+ }
+
+ @Override
+ public void convertWay(Way way) {
+ if (BoundaryElementSaver.isBoundary(way)) {
+ java.awt.geom.Area boundArea = new java.awt.geom.Area(Java2DConverter.createArea(way.getPoints()));
+ Boundary boundary = new Boundary(boundArea, way.getEntryIteratable(), "w"+way.getId());
+ saver.addBoundary(boundary);
+ }
+ }
+
+ @Override
+ public void convertNode(Node node) {
+ }
+
+ @Override
+ public void convertRelation(Relation relation) {
+ if (relation instanceof BoundaryRelation) {
+ Boundary boundary = ((BoundaryRelation)relation).getBoundary();
+ if (boundary!=null)
+ saver.addBoundary(boundary);
+ }
+ }
+
+ @Override
+ public void setBoundingBox(Area bbox) {
+
+ }
+
+ @Override
+ public void end() {
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryCoverageUtil.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryCoverageUtil.java
new file mode 100644
index 0000000..0e725f7
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryCoverageUtil.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2006, 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.reader.osm.boundary;
+
+import java.awt.geom.Area;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.GpxCreator;
+import uk.me.parabola.util.Java2DConverter;
+
+public class BoundaryCoverageUtil {
+ private final BoundaryQuadTree bqt;
+
+ public BoundaryCoverageUtil(String boundaryDirName, String boundaryFileName) {
+ bqt = BoundaryUtil.loadQuadTree(boundaryDirName, boundaryFileName);
+ }
+
+ public Area getCoveredArea(int admLevel) {
+ return bqt.getCoveredArea(admLevel);
+ }
+
+ private static void saveArea(String attribute, Integer level, Area covered) {
+ String gpxBasename = "gpx/summary/" + attribute + "/admin_level="
+ + level;
+
+ List<List<Coord>> coveredPolys = Java2DConverter.areaToShapes(covered);
+ Collections.reverse(coveredPolys);
+ int i = 0;
+ for (List<Coord> coveredPart : coveredPolys) {
+ String attr = Way.clockwise(coveredPart) ? "o" : "i";
+ GpxCreator.createGpx(gpxBasename + "/" + i + "_" + attr, coveredPart);
+ i++;
+ }
+ }
+
+ public static void main(String[] args) throws InterruptedException {
+ int processors = Runtime.getRuntime().availableProcessors();
+ ExecutorService excSvc = Executors.newFixedThreadPool(processors);
+ ExecutorCompletionService<Area> executor = new ExecutorCompletionService<Area>(
+ excSvc);
+ String workDirName = args[0];
+ System.out.println(workDirName);
+ File boundaryDir = new File(workDirName);
+ final Set<String> boundsFileNames = new HashSet<String>();
+ if (boundaryDir.isFile() && boundaryDir.getName().endsWith(".bnd")) {
+ workDirName = boundaryDir.getParent();
+ if (workDirName == null)
+ workDirName = ".";
+ boundsFileNames.add(boundaryDir.getName());
+ } else {
+ boundsFileNames.addAll(BoundaryUtil
+ .getBoundaryDirContent(workDirName));
+ }
+
+ int minLat = Integer.MAX_VALUE;
+ int maxLat = Integer.MIN_VALUE;
+ int minLon = Integer.MAX_VALUE;
+ int maxLon = Integer.MIN_VALUE;
+ for (String fileName : boundsFileNames) {
+ String[] parts = fileName.substring("bounds_".length(),
+ fileName.length() - 4).split("_");
+ int lat = Integer.valueOf(parts[0]);
+ int lon = Integer.valueOf(parts[1]);
+ if (lat < minLat)
+ minLat = lat;
+ if (lat > maxLat)
+ maxLat = lat;
+ if (lon < minLon)
+ minLon = lon;
+ if (lon > maxLon)
+ maxLon = lon;
+ }
+ System.out.format("Covered area: (%d,%d)-(%d,%d)\n", minLat, minLon,
+ maxLat, maxLon);
+ int maxSteps = 2;
+
+ final String boundaryDirName = workDirName;
+ for (int adminlevel = 2; adminlevel < 12; adminlevel++) {
+ final Set<String> boundaryFileNames = Collections.synchronizedSet(new HashSet<String>(boundsFileNames));
+ final int adminLevel = adminlevel;
+ final Queue<Future<Area>> areas = new LinkedBlockingQueue<Future<Area>>();
+ for (int lat = minLat; lat <= maxLat; lat += maxSteps
+ * BoundaryUtil.RASTER) {
+ for (int lon = minLon; lon <= maxLon; lon += maxSteps
+ * BoundaryUtil.RASTER) {
+ for (int latStep = 0; latStep < maxSteps
+ && lat + latStep * BoundaryUtil.RASTER <= maxLat; latStep++) {
+ for (int lonStep = 0; lonStep < maxSteps
+ && lon + lonStep * BoundaryUtil.RASTER <= maxLon; lonStep++) {
+ final int fLat = lat + latStep
+ * BoundaryUtil.RASTER;
+ final int fLon = lon + lonStep
+ * BoundaryUtil.RASTER;
+
+ areas.add(executor.submit(new Callable<Area>() {
+ public Area call() {
+ String filename = "bounds_" + fLat + "_"
+ + fLon + ".bnd";
+ if (boundaryFileNames.contains(filename) == false) {
+ return new Area();
+ }
+ BoundaryCoverageUtil converter = new BoundaryCoverageUtil(
+ boundaryDirName, filename);
+ boundaryFileNames.remove(filename);
+ System.out.format("%5d bounds files remaining\n", boundaryFileNames.size());
+ return converter.getCoveredArea(adminLevel);
+ }
+ }));
+ }
+ }
+ }
+ }
+
+ final AtomicInteger mergeSteps = new AtomicInteger();
+ while (areas.size() > 1) {
+ final List<Future<Area>> toMerge = new ArrayList<Future<Area>>();
+ for (int i = 0; i < maxSteps * 2 && areas.isEmpty() == false; i++) {
+ toMerge.add(areas.poll());
+ }
+ mergeSteps.incrementAndGet();
+ areas.add(executor.submit(new Callable<Area>() {
+ public Area call() {
+ Area a = new Area();
+ ListIterator<Future<Area>> mergeAreas = toMerge
+ .listIterator();
+ while (mergeAreas.hasNext()) {
+ try {
+ a.add(mergeAreas.next().get());
+ } catch (InterruptedException exp) {
+ System.err.println(exp);
+ } catch (ExecutionException exp) {
+ System.err.println(exp);
+ }
+ mergeAreas.remove();
+ }
+ System.out.format("%5d merges remaining\n",mergeSteps.decrementAndGet());
+ return a;
+ }
+ }));
+ }
+ try {
+ Area finalArea = areas.poll().get();
+ System.out.println("Joining finished. Saving results.");
+ saveArea("covered", adminlevel, finalArea);
+ } catch (Exception exp) {
+ System.err.println(exp);
+ }
+ // }
+ }
+ excSvc.shutdown();
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryDiff.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryDiff.java
new file mode 100644
index 0000000..b485f90
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryDiff.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2006, 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.reader.osm.boundary;
+import java.awt.geom.Area;
+import java.awt.geom.Path2D;
+import java.io.File;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Queue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.regex.Pattern;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.reader.osm.Tags;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.GpxCreator;
+import uk.me.parabola.util.Java2DConverter;
+
+/**
+ * Compare two boundary files or two directories with boundary files.
+ * Write differences as gpx files.
+ *
+ * @author WanMil (initial version), rewritten for BoundaryQuadTree by GerdP
+ *
+ */
+public class BoundaryDiff {
+ private final String inputName1;
+ private final String inputName2;
+
+ public BoundaryDiff(String boundaryDirName1, String boundaryDirName2) {
+ this.inputName1 = boundaryDirName1;
+ this.inputName2 = boundaryDirName2;
+ }
+
+ /**
+ * Return list of file names
+ * @param dirName a directory or a zip file containing *.bnd files,
+ * or a single *.bnd file
+ * @return
+ */
+ private List<String> getBoundsFiles(String dirName) {
+ File dir = new File(dirName);
+ System.out.println(dirName);
+ if (dir.isFile() && dir.getName().endsWith(".bnd")) {
+ List<String> boundaryFiles = new ArrayList<String>();
+ boundaryFiles.add(dir.getName());
+ return boundaryFiles;
+ } else {
+ return BoundaryUtil.getBoundaryDirContent(dirName);
+ }
+ }
+
+ /**
+ * Compare all files in one list with the files in another list.
+ * Optionally restrict the comparison to boundaries with the
+ * given tag/value combination.
+ * @param tag should be admin_level
+ * @param value any value appropriate for the tag
+ */
+ public void compare(String tag, String value) {
+ List<String> b1 = getBoundsFiles(inputName1);
+ List<String> b2 = getBoundsFiles(inputName2);
+
+ if (b1.size() == 0 && b2.size() == 0)
+ return;
+
+ Collections.sort(b1);
+ Collections.sort(b2);
+
+ Queue<String> bounds1 = new LinkedList<String>(b1);
+ Queue<String> bounds2 = new LinkedList<String>(b2);
+ b1 = null;
+ b2 = null;
+
+ Area only1 = new Area();
+ Area only2 = new Area();
+
+ int bAll = bounds1.size() + bounds2.size();
+ long tProgress = System.currentTimeMillis();
+
+ while (bounds1.isEmpty() == false || bounds2.isEmpty() == false) {
+ String f1 = bounds1.peek();
+ String f2 = bounds2.peek();
+
+ if (f1 == null) {
+ only2.add(loadArea(inputName2, f2, tag, value));
+ bounds2.poll();
+ } else if (f2 == null) {
+ only1.add(loadArea(inputName1, f1, tag, value));
+ bounds1.poll();
+ } else {
+ int cmp = f1.compareTo(f2);
+ if (cmp == 0) {
+ Area a1 = loadArea(inputName1, f1, tag, value);
+ Area a2 = loadArea(inputName2, f2, tag, value);
+ if (a1.isEmpty() == false|| a2.isEmpty() == false){
+ Area o1 = new Area(a1);
+ o1.subtract(a2);
+ if (o1.isEmpty() == false)
+ only1.add(o1);
+ Area o2 = new Area(a2);
+ o2.subtract(a1);
+ if (o2.isEmpty() == false)
+ only2.add(o2);
+ }
+ bounds1.poll();
+ bounds2.poll();
+ } else if (cmp < 0) {
+ only1.add(loadArea(inputName1, f1, tag, value));
+ bounds1.poll();
+ } else {
+ only2.add(loadArea(inputName2, f2, tag, value));
+ bounds2.poll();
+ }
+ }
+
+ long tNow = System.currentTimeMillis();
+ if (tNow - tProgress >= 10*1000L) {
+ int bNow = bounds1.size()+ bounds2.size();
+ System.out.println(tag+"="+value+": "+(bAll-bNow)+"/"+bAll+" files - "+(bAll-bNow)*100/bAll+"%");
+ tProgress = tNow;
+ }
+ }
+
+ saveArea(only1, "removed", tag, value);
+ saveArea(only2, "new", tag, value);
+
+ }
+
+ /**
+ * Calculate the area that is covered by a given tag /value pair, e.g. admin_level=2
+ * @param dirName the name of a directory or *.zip file containing *.bnd files, or a single *.bnd file
+ * @param fileName the name of the *.bnd file that should be read
+ * @param tag the tag key
+ * @param value the tag value
+ * @return a new Area (which might be empty)
+ */
+ private Area loadArea(String dirName, String fileName, String tag, String value) {
+ String dir = dirName;
+ String bndFileName = fileName;
+ if (dir.endsWith(".bnd")){
+ File f = new File(dir);
+ if (f.isFile()){
+ dir = f.getParent();
+ bndFileName = f.getName();
+ }
+ if (dir == null)
+ dir = "."; // the local directory
+ }
+ BoundaryQuadTree bqt = BoundaryUtil.loadQuadTree(dir, bndFileName);
+ if (tag.equals("admin_level"))
+ return (bqt.getCoveredArea(Integer.valueOf(value)));
+ Map<String, Tags> bTags = bqt.getTagsMap();
+ Map<String, List<Area>> areas = bqt.getAreas();
+ Area a = new Area();
+ Path2D.Double path = new Path2D.Double();
+ for (Entry<String, Tags> entry: bTags.entrySet()){
+ if (value.equals(entry.getValue().get(tag))){
+ List<Area> aList = areas.get(entry.getKey());
+ for (Area area : aList){
+ BoundaryUtil.addToPath(path, area);
+ }
+ }
+ }
+ a = new Area(path);
+ return a;
+ }
+
+ /**
+ * Create gpx file(s) for a single area.
+ * @param a the Area
+ * @param subDirName target sub-directory
+ * @param tagKey used to build the gpx file name
+ * @param tagValue used to build the gpx file name
+ */
+ private void saveArea(Area a, String subDirName, String tagKey, String tagValue) {
+
+ String gpxBasename = "gpx/diff/" + subDirName + "/"
+ + tagKey + "=" + tagValue + "/";
+
+ List<List<Coord>> singlePolys = Java2DConverter.areaToShapes(a);
+ Collections.reverse(singlePolys);
+
+ int i = 0;
+ for (List<Coord> polyPart : singlePolys) {
+ String attr = Way.clockwise(polyPart) ? "o" : "i";
+ GpxCreator.createGpx(gpxBasename + i + "_" + attr, polyPart);
+ i++;
+ }
+ }
+
+ /**
+ * print usage info
+ */
+ private static void printUsage(){
+ System.err.println("Usage:");
+ System.err
+ .println("java -cp mkgmap.jar uk.me.parabola.mkgmap.reader.osm.boundary.BoundaryDiff <boundsdir1> <boundsdir2> [<tag=value> [<tag=value>]]");
+ System.err.println(" <boundsdir1> ");
+ System.err
+ .println(" <boundsdir2>: defines two directories or zip files containing boundsfiles to be compared ");
+ System.err
+ .println(" <tag=value>: defines a tag/value combination for which the diff is created");
+ System.err
+ .println(" sample:");
+ System.err
+ .println(" java -cp mkgmap.jar uk.me.parabola.mkgmap.reader.osm.boundary.BoundaryDiff world_20120113.zip bounds admin_level=2");
+
+ System.exit(-1);
+ }
+
+ public static void main(final String[] args) {
+ if (args.length < 2)
+ printUsage();
+ File f1 = new File(args[0]);
+ if (f1.exists() == false){
+ System.err.println(args[0] + " does not exist");
+ printUsage();
+ }
+ File f2 = new File(args[1]);
+ if (f2.exists() == false){
+ System.err.println(args[1] + " does not exist");
+ printUsage();
+ }
+
+ List<Entry<String,String>> tags = new ArrayList<Entry<String,String>>();
+
+ if (args.length > 2) {
+ for (int i = 2; i < args.length; i++) {
+ final String[] parts = args[i].split(Pattern.quote("="));
+ tags.add(new AbstractMap.SimpleImmutableEntry<String, String>(
+ parts[0], parts[1]));
+ }
+ } else {
+ for (int adminlevel = 2; adminlevel <= 11; adminlevel++) {
+ tags.add(new AbstractMap.SimpleImmutableEntry<String, String>(
+ "admin_level", String.valueOf(adminlevel)));
+ }
+ }
+
+
+ int processors = Runtime.getRuntime().availableProcessors();
+ ExecutorService excSvc = Executors.newFixedThreadPool(processors);
+ ExecutorCompletionService<String> executor = new ExecutorCompletionService<String>(
+ excSvc);
+
+
+ for (final Entry<String, String> tag : tags) {
+ executor.submit(new Runnable() {
+ public void run() {
+ BoundaryDiff bd = new BoundaryDiff(args[0],args[1]);
+ bd.compare(tag.getKey(), tag.getValue());
+ }
+ }, tag.getKey() + "=" + tag.getValue());
+ }
+
+ for (int i = 0; i < tags.size(); i++) {
+ try {
+ String tag = executor.take().get();
+ System.out.println(tag + " finished.");
+ } catch (InterruptedException exp) {
+ exp.printStackTrace();
+ } catch (ExecutionException exp) {
+ exp.printStackTrace();
+ }
+ }
+
+ excSvc.shutdown();
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryElement.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryElement.java
new file mode 100644
index 0000000..a968e7a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryElement.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2006, 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.reader.osm.boundary;
+
+import java.awt.geom.Area;
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.util.Java2DConverter;
+
+public class BoundaryElement {
+ private final boolean outer;
+ private final List<Coord> points;
+ private Area area;
+
+ public BoundaryElement(boolean outer, List<Coord> points) {
+ this.outer = outer;
+ this.points = new ArrayList<Coord>(points);
+ }
+
+ public Area getArea() {
+ if (area == null) {
+ area = new Area(Java2DConverter.createArea(points));
+ }
+ return area;
+ }
+
+ public boolean isOuter() {
+ return outer;
+ }
+
+ public List<Coord> getPoints() {
+ return points;
+ }
+
+ public String toString() {
+ return (isOuter() ? "outer" : "inner") + " " + points ;
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryElementSaver.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryElementSaver.java
new file mode 100644
index 0000000..0e59f60
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryElementSaver.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2006, 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.reader.osm.boundary;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Map.Entry;
+
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.build.Locator;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.ElementSaver;
+import uk.me.parabola.mkgmap.reader.osm.Node;
+import uk.me.parabola.mkgmap.reader.osm.OsmConverter;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.Tags;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * This saver only keeps ways with <code>natural=coastline</code> tags. This is
+ * used for loading of extra coastline files.
+ *
+ * @author WanMil
+ */
+public class BoundaryElementSaver extends ElementSaver {
+ private static final Logger log = Logger.getLogger(BoundaryElementSaver.class);
+
+ private final static Locator locator = new Locator();
+
+ private final BoundarySaver saver;
+
+ public BoundaryElementSaver(EnhancedProperties args, BoundarySaver saver) {
+ super(args);
+ this.saver = saver;
+ }
+
+ /**
+ * Checks if the given element is an administrative boundary or a
+ * postal code area.
+ * @param element an element
+ * @return <code>true</code> administrative boundary or postal code;
+ * <code>false</code> element cannot be used for precompiled bounds
+ */
+ public static boolean isBoundary(Element element) {
+ if (element instanceof Relation) {
+ String type = element.getTag("type");
+
+ if ("boundary".equals(type) || "multipolygon".equals(type)) {
+ String boundaryVal = element.getTag("boundary");
+ if ("administrative".equals(boundaryVal)) {
+ // for boundary=administrative the admin_level must be set
+ if (element.getTag("admin_level") == null) {
+ return false;
+ }
+
+ // Check for admin_level==2 if the name is known in the LocatorConfig.xml.
+ // This should abandon all non country admin_level 2 boundaries
+ if (element.getTag("admin_level").equals("2")) {
+ Tags copyTags = new Tags();
+ for (Entry<String,String> tag : element.getEntryIteratable()) {
+ copyTags.put(tag.getKey(), tag.getValue());
+ }
+ String iso = locator.getCountryISOCode(copyTags);
+ if (iso == null) {
+ log.warn("Ignore admin_level 2 element:", element.toBrowseURL(), element.toTagString());
+ return false;
+ }
+ }
+ // and a name must be set (check only for a tag containing name
+ for (Entry<String,String> tag : element.getEntryIteratable()) {
+ if (tag.getKey().contains("name")) {
+ return true;
+ }
+ }
+ // does not contain a name tag => do not use it
+ return false;
+ } else if ("postal_code".equals(boundaryVal)) {
+ // perform a positive check
+
+ // is postal_code set?
+ if (element.getTag("postal_code") != null) {
+ return true;
+ }
+ // and a name must be set (check only for a tag containing name
+ for (Entry<String,String> tag : element.getEntryIteratable()) {
+ if (tag.getKey().contains("name")) {
+ return true;
+ }
+ }
+ // does not contain a name tag => do not use it
+ return false;
+ } else if (element.getTag("postal_code") != null){
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ } else if (element instanceof Way) {
+ Way w = (Way) element;
+ // a single way must be closed
+ if (w.isClosed() == false) {
+ return false;
+ }
+ // the boundary tag must be "administrative" or "postal_code"
+ String boundaryVal = element.getTag("boundary");
+ if ("administrative".equals(boundaryVal)) {
+ // for boundary=administrative the admin_level must be set
+ if (element.getTag("admin_level") == null) {
+ return false;
+ }
+
+ // Check for admin_level==2 if the name is known in the LocatorConfig.xml.
+ // This should abandon all non country admin_level 2 boundaries
+ if (element.getTag("admin_level").equals("2")) {
+ Tags copyTags = new Tags();
+ for (Entry<String,String> tag : element.getEntryIteratable()) {
+ copyTags.put(tag.getKey(), tag.getValue());
+ }
+ String iso = locator.getCountryISOCode(copyTags);
+ if (iso == null) {
+ log.warn("Ignore admin_level 2 element:", element.toBrowseURL(), element.toTagString());
+ return false;
+ }
+ }
+
+ // and a name must be set (check only for a tag containing name)
+ for (Entry<String,String> tag : element.getEntryIteratable()) {
+ if (tag.getKey().contains("name")) {
+ return true;
+ }
+ }
+ // does not contain a name tag => do not use it
+ return false;
+ } else if ( "postal_code".equals(boundaryVal)) {
+ // the name tag must be set for it
+ return element.getTag("name") != null;
+ } else if (element.getTag("postal_code") != null) {
+ // postal_code as tag
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ public void addRelation(Relation rel) {
+ if (isBoundary(rel)) {
+ BoundaryRelation bRel = (BoundaryRelation) createMultiPolyRelation(rel);
+ bRel.processElements();
+ Boundary b = bRel.getBoundary();
+ if (b != null)
+ saver.addBoundary(b);
+ } else {
+ log.warn("Relation is not processed due to missing tags:", rel.getId(), rel.toTagString());
+ }
+ }
+
+ public void deferRelation(long id, Relation rel, String role) {
+ return;
+ }
+
+ public Relation createMultiPolyRelation(Relation rel) {
+ return new BoundaryRelation(rel, wayMap, getBoundingBox());
+ }
+
+ public void addNode(Node node) {
+ return;
+ }
+
+ public void convert(OsmConverter converter) {
+ nodeMap = null;
+
+ converter.setBoundingBox(getBoundingBox());
+
+ ArrayList<Relation> relations = new ArrayList<Relation>(
+ relationMap.values());
+ relationMap = null;
+ Collections.reverse(relations);
+ for (int i = relations.size() - 1; i >= 0; i--) {
+ converter.convertRelation(relations.get(i));
+ relations.remove(i);
+ }
+
+
+ for (Way w : wayMap.values())
+ converter.convertWay(w);
+
+ wayMap = null;
+
+ converter.end();
+
+ relationMap = null;
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryFile2Gpx.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryFile2Gpx.java
new file mode 100644
index 0000000..0de2a04
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryFile2Gpx.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2006, 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.reader.osm.boundary;
+
+import java.awt.geom.Area;
+import java.awt.geom.Path2D;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.reader.osm.Tags;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.GpxCreator;
+import uk.me.parabola.util.Java2DConverter;
+
+public class BoundaryFile2Gpx {
+ private final String boundaryFileName;
+ private final BoundaryQuadTree bqt;
+ public BoundaryFile2Gpx(String boundaryDirName, String boundaryFileName) {
+ this.boundaryFileName = boundaryFileName;
+ bqt = BoundaryUtil.loadQuadTree(boundaryDirName, boundaryFileName);
+ }
+
+ /**
+ * Create gpx files for areas which contain no information for a given
+ * admin level.
+ * @param admLevel reasonable values are 2..11
+ */
+ public void saveEmptyAreas(int admLevel) {
+ Area tileArea = Java2DConverter.createBoundsArea(BoundaryUtil
+ .getBbox(boundaryFileName));
+
+ Area coveredArea = bqt.getCoveredArea(admLevel);
+ tileArea.subtract(coveredArea);
+ String levelId = "admin_level" ;
+ if (admLevel < 12)
+ levelId += admLevel;
+ else
+ levelId += "notset";
+ if (tileArea.isEmpty()) {
+ System.out.println(levelId + " is covered completely.");
+ } else {
+ String gpxBasename = "gpx/" + boundaryFileName
+ + "/uncovered/" + levelId + "/";
+
+
+ List<List<Coord>> emptyPolys = Java2DConverter
+ .areaToShapes(tileArea);
+ Collections.reverse(emptyPolys);
+
+ int i = 0;
+ for (List<Coord> emptyPart : emptyPolys) {
+ String attr = Way.clockwise(emptyPart) ? "o" : "i";
+ GpxCreator.createGpx(gpxBasename + i + "_" + attr, emptyPart);
+ i++;
+ }
+ }
+ }
+
+ /**
+ * create gpx files for all boundaries contained in one *.bnd file
+ */
+ public void saveAsGpx() {
+ System.out.println("Start converting " + boundaryFileName);
+
+ Map<String, Tags> bTags = bqt.getTagsMap();
+ Map<String, List<Area>> areas = bqt.getAreas();
+
+ // verify data: remove boundary ids that have no related areas
+ Iterator<Entry<String, Tags>> tagIter = bTags.entrySet().iterator();
+ while (tagIter.hasNext()) {
+ Entry<String, Tags> entry = tagIter.next();
+ List<Area> aList = areas.get(entry.getKey());
+ if (aList == null || aList.isEmpty()){
+ System.err.println("no area info for "+ entry.getKey());
+ tagIter.remove();
+ continue;
+ }
+ }
+
+ for (int adminlevel = 2; adminlevel < 12; adminlevel++) {
+ boolean found = false;
+ for (Entry<String, Tags> entry: bTags.entrySet()){
+ String admLevel = entry.getValue().get("admin_level");
+ if (admLevel != null && admLevel.equals(String.valueOf(adminlevel))){
+ found = true;
+ break;
+ }
+ }
+ if (found == false){
+ System.out.println("No boundary with admin_level=" + adminlevel
+ + " found.");
+ continue;
+ }
+
+ for (Entry<String, Tags> entry: bTags.entrySet()){
+ // get the admin_level tag
+ String admLevel = entry.getValue().get("admin_level");
+ if (admLevel == null) {
+ admLevel = "notset";
+ }
+
+ String bId = entry.getKey();
+
+ String gpxBasename = "gpx/" + boundaryFileName
+ + "/covered/admin_level=" + admLevel + "/" + admLevel + "_" + bId
+ + "_";
+
+ Path2D.Double path = new Path2D.Double();
+ List<Area> aList = areas.get(bId);
+ for (Area area : aList){
+ BoundaryUtil.addToPath(path, area);
+ }
+ int i = 0;
+ List<BoundaryElement> bElements = BoundaryUtil.splitToElements(new Area(path),bId);
+ for (BoundaryElement be : bElements){
+ String gpxFile = gpxBasename;
+ if (be.isOuter()) {
+ gpxFile += "o_" + i;
+ } else {
+ gpxFile = "i_" + i;
+ }
+ GpxCreator.createGpx(gpxFile, be.getPoints());
+ i++;
+ }
+ }
+ saveEmptyAreas(adminlevel);
+ }
+ System.out.println("Finished " + boundaryFileName);
+
+ }
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+ String boundaryDirName = args[0];
+ System.out.println(boundaryDirName);
+ File boundaryDir = new File(boundaryDirName);
+ List<String> boundaryFileNames;
+ if (boundaryDir.isFile() && boundaryDir.getName().endsWith(".bnd")) {
+ boundaryDirName = boundaryDir.getParent();
+ if (boundaryDirName == null)
+ boundaryDirName = ".";
+ boundaryFileNames = new ArrayList<String>();
+ boundaryFileNames.add(boundaryDir.getName());
+ } else {
+ boundaryFileNames = BoundaryUtil.getBoundaryDirContent(boundaryDirName);
+ }
+
+ for (String boundaryFileName : boundaryFileNames) {
+ BoundaryFile2Gpx converter = new BoundaryFile2Gpx(boundaryDirName,boundaryFileName);
+ converter.saveAsGpx();
+ }
+
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryGrid.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryGrid.java
new file mode 100644
index 0000000..fb50462
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryGrid.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.reader.osm.boundary;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.reader.osm.Tags;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * A simple grid that stores the BoundaryQuadTrees that intersect with the grid.
+ * Each element of the grid is related to one *.bnd file.
+ *
+ * @author GerdP
+ *
+ */
+public class BoundaryGrid {
+ private static final Logger log = Logger.getLogger(BoundaryGrid.class);
+
+ private final uk.me.parabola.imgfmt.app.Area searchBbox;
+ private final BoundaryQuadTree[][] grid;
+ private final boolean [][]emptyMessagePrinted;
+ private final int minLat;
+ private final int minLon;
+ private final EnhancedProperties props;
+
+ /**
+ * A simple grid that contains references to BoundaryQuadTrees loaded from
+ * preprocessed boundary files. The grid will fully cover the bounding box
+ * passed in bbox.
+ *
+ * @param boundaryDirName
+ * the path to the preprocessed boundary files
+ * @param bbox
+ * the bounding box of all points that might be searched
+ * @param props
+ * used to determine the ISO code of level 2 boundaries
+ */
+ public BoundaryGrid(String boundaryDirName,
+ uk.me.parabola.imgfmt.app.Area bbox, EnhancedProperties props) {
+ minLat = BoundaryUtil.getSplitBegin(bbox.getMinLat());
+ minLon = BoundaryUtil.getSplitBegin(bbox.getMinLong());
+ int gridMaxLat = BoundaryUtil.getSplitBegin(bbox.getMaxLat());
+ int gridMaxLon = BoundaryUtil.getSplitBegin(bbox.getMaxLong());
+ int dimLat = (gridMaxLat - minLat) / BoundaryUtil.RASTER + 1;
+ int dimLon = (gridMaxLon - minLon) / BoundaryUtil.RASTER + 1;
+ grid = new BoundaryQuadTree[dimLat][dimLon];
+ emptyMessagePrinted = new boolean[dimLat][dimLon];
+ this.searchBbox = bbox;
+
+ this.props = props;
+ init(boundaryDirName);
+ }
+
+ /**
+ * Returns the location relevant tags for a given point
+ * @param co the coords of the point
+ * @return null if not found, else a reference to the Tags
+ * object saved in a BoundaryQuadTree
+ */
+ public Tags get(Coord co) {
+ if (!searchBbox.contains(co))
+ return null;
+ int gridLat = (co.getLatitude() - minLat) / BoundaryUtil.RASTER;
+ int gridLon = (co.getLongitude() - minLon) / BoundaryUtil.RASTER;
+ if (grid[gridLat][gridLon] == null){
+ if (emptyMessagePrinted[gridLat][gridLon] == false){
+ emptyMessagePrinted[gridLat][gridLon] = true;
+ int keyLat = BoundaryUtil.getSplitBegin(co.getLatitude());
+ int keyLon = BoundaryUtil.getSplitBegin(co.getLongitude());
+ log.warn("no precompiled boundary information available for raster tile", BoundaryUtil.getKey(keyLat,keyLon));
+ }
+ return null;
+ }
+ else
+ return grid[gridLat][gridLon].get(co);
+ }
+
+ /**
+ * Fill the grid. Calculate the names of the *.bnd files that
+ * may be needed. For each file, try to create a BoundaryQuadTree.
+ * Save each tree to its place in the grid.
+ *
+ * @param boundaryDir
+ * Directory or a *.zip file with bnd files
+ */
+ private void init(String boundaryDirName){
+ List<String> requiredFileNames = BoundaryUtil.getRequiredBoundaryFileNames(searchBbox);
+ Map<String,BoundaryQuadTree> trees = BoundaryUtil.loadQuadTrees(boundaryDirName, requiredFileNames, searchBbox, props);
+ for (Entry<String,BoundaryQuadTree> entry: trees.entrySet()) {
+ uk.me.parabola.imgfmt.app.Area fileBbox = BoundaryUtil.getBbox(entry.getKey());
+ int gridLat = (fileBbox.getMinLat() - minLat) / BoundaryUtil.RASTER;
+ int gridLon = (fileBbox.getMinLong() - minLon) / BoundaryUtil.RASTER;
+ grid[gridLat][gridLon] = entry.getValue();
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryLister.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryLister.java
new file mode 100644
index 0000000..f6f2eba
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryLister.java
@@ -0,0 +1,64 @@
+package uk.me.parabola.mkgmap.reader.osm.boundary;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.Map.Entry;
+
+import uk.me.parabola.mkgmap.reader.osm.Tags;
+
+public class BoundaryLister {
+
+ /**
+ * @param args
+ * @throws IOException
+ */
+ public static void main(String[] args) throws IOException {
+ String boundsdir = args[0];
+ String outDirName = boundsdir;
+ if (args.length >= 2)
+ outDirName = args[1];
+ File outDir = new File (outDirName);
+
+ if (outDir.exists() ){
+ if (outDir.isDirectory() == false){
+ System.err.println("target is not a directory, output is written to bounds.txt");
+ outDir = new File(".");
+ }
+ }
+
+ List<String> bndFileNames = BoundaryUtil.getBoundaryDirContent(boundsdir);
+ PrintWriter out = new PrintWriter(new File(outDir,"bounds.txt"), "UTF-8");
+ // create an empty search bbox to speedup reading of the bnd file(s)
+ //uk.me.parabola.imgfmt.app.Area searchBbox = new uk.me.parabola.imgfmt.app.Area (0,0,0,0);
+ for (String bndFile : bndFileNames) {
+ out.println(bndFile + "****************");
+ BoundaryQuadTree bqt = BoundaryUtil.loadQuadTree(boundsdir, bndFile);
+ if (bqt == null)
+ break;
+ Map<String, Tags> map = bqt.getTagsMap();
+ for ( Entry<String, Tags> entry: map.entrySet()) {
+ TreeMap<String,String> btree = new TreeMap<String, String>();
+ String line = bndFile+ ":" + entry.getKey();
+ Iterator<Entry<String,String>> tagIter = entry.getValue().entryIterator();
+ while (tagIter.hasNext()) {
+ Entry<String,String> tag = tagIter.next();
+ btree.put(tag.getKey(),tag.getValue());
+ }
+ // print sorted tags
+ for (Entry<String,String> e : btree.entrySet()){
+ out.println(line + ";" + e);
+ }
+
+ }
+ }
+ out.close();
+
+
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryLocationInfo.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryLocationInfo.java
new file mode 100644
index 0000000..7900a01
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryLocationInfo.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2006, 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.reader.osm.boundary;
+
+/**
+ * Stores location relevant information that was extracted
+ * from the tags of a boundary.
+ * @author GerdP
+ *
+ */
+public class BoundaryLocationInfo {
+
+ private final String zip;
+ private final String name;
+ private final int admLevel;
+ private boolean isISO;
+
+ BoundaryLocationInfo (int admLevel, String name, String zip, boolean isISO){
+ this.admLevel = admLevel;
+ if (admLevel > 0 && name == null)
+ this.name = "not_set"; // TODO: review
+ else
+ this.name = name;
+ this.zip = zip;
+ this.isISO = isISO;
+ }
+ public String getZip() {
+ return zip;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAdmLevel() {
+ return admLevel;
+ }
+
+ public boolean isISOName(){
+ return isISO;
+ }
+}
+
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryLocationPreparer.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryLocationPreparer.java
new file mode 100644
index 0000000..b001fb3
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryLocationPreparer.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.reader.osm.boundary;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.build.Locator;
+import uk.me.parabola.mkgmap.build.LocatorUtil;
+import uk.me.parabola.mkgmap.reader.osm.Tags;
+import uk.me.parabola.mkgmap.reader.osm.boundary.Boundary;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * Allows to extract boundary tags into BoundaryLocationInfo.
+ * Uses a locator if possible, else defaults.
+ * The locator is only needed when used with the LocationHook, utilities like the
+ * BoundaryPreparer will work without it.
+ * @author GerdP
+ *
+ */
+public class BoundaryLocationPreparer {
+ private static final Logger log = Logger.getLogger(BoundaryLocationPreparer.class);
+
+ private Locator locator;
+ private static final Pattern COMMA_OR_SEMICOLON_PATTERN = Pattern.compile("[,;]+");
+ // tag keys for name resolution
+ private final List<String> nameList;
+
+
+ /**
+ * Create a preparer.
+ * @param props The program properties or null.
+ */
+ public BoundaryLocationPreparer(EnhancedProperties props) {
+ if (props == null){
+ this.locator = null;
+ this.nameList = new ArrayList<String>();
+ for (String name: BoundaryLocationPreparer.LEVEL2_NAMES){
+ this.nameList.add(name);
+ }
+ }
+ else{
+ this.locator = new Locator(props);
+ this.nameList = LocatorUtil.getNameTags(props);
+ }
+ }
+
+ /**
+ * Extract location relevant information from tags
+ * @param tags the Tags of a boundary
+ * @return a new BoundaryLocationInfo instance
+ */
+ public BoundaryLocationInfo parseTags(Tags tags){
+ String zip = getZip(tags);
+ int admLevel = getAdminLevel(tags);
+ boolean isISO = false;
+ String name = getName(tags);
+ if (locator != null){
+ if (admLevel == 2) {
+ String isoCode = locator.addCountry(tags);
+ if (isoCode != null) {
+ isISO = true;
+ name = isoCode;
+ } else {
+ log.warn("Country name",name,"not in locator config. Country may not be assigned correctly.");
+ }
+ log.debug("Coded:",name);
+ }
+ }
+ return new BoundaryLocationInfo(admLevel, name, zip, isISO);
+ }
+
+ /**
+ * Extract and prepare tag infos from BoundaryList
+ * @param boundaries list of boundaries
+ * @return A Map that maps boundary Ids to the location relevant tags
+ */
+ public HashMap<String, BoundaryLocationInfo> getPreparedLocationInfo(
+ List<Boundary> boundaries) {
+ HashMap<String, BoundaryLocationInfo> preparedLocationInfo = new HashMap<String, BoundaryLocationInfo> ();
+ for (Boundary b :boundaries){
+ preparedLocationInfo.put(b.getId(), parseTags(b.getTags()));
+ }
+ return preparedLocationInfo;
+ }
+
+
+ /**
+ * These tags are used to retrieve the name of admin_level=2 boundaries. They need to
+ * be handled special because their name is changed to the 3 letter ISO code using
+ * the Locator class and the LocatorConfig.xml file.
+ */
+ private static final String[] LEVEL2_NAMES = new String[]{"name","name:en","int_name"};
+
+ /**
+ * Try to extract the name of the boundary.
+ * @param tags the boundary tags
+ * @return a name or null if no usable name tag was found
+ */
+ private String getName(Tags tags) {
+ if ("2".equals(tags.get("admin_level"))) {
+ for (String enNameTag : LEVEL2_NAMES)
+ {
+ String nameTagValue = tags.get(enNameTag);
+ if (nameTagValue == null) {
+ continue;
+ }
+
+ String[] nameParts = COMMA_OR_SEMICOLON_PATTERN.split(nameTagValue);
+ if (nameParts.length == 0) {
+ continue;
+ }
+ return nameParts[0].trim().intern();
+ }
+ }
+
+ for (String nameTag : nameList) {
+ String nameTagValue = tags.get(nameTag);
+ if (nameTagValue == null) {
+ continue;
+ }
+
+ String[] nameParts = COMMA_OR_SEMICOLON_PATTERN.split(nameTagValue);
+ if (nameParts.length == 0) {
+ continue;
+ }
+ return nameParts[0].trim().intern();
+ }
+
+ return null;
+ }
+
+ /**
+ * Try to extract a zip code from the the tags of a boundary.
+ * @param tags the boundary tags
+ * @return null if no zip code was found, else a String that should be a zip code.
+ */
+ private String getZip(Tags tags) {
+ String zip = tags.get("postal_code");
+ if (zip == null) {
+ if ("postal_code".equals(tags.get("boundary"))){
+ String name = tags.get("name");
+ if (name == null) {
+ name = getName(tags);
+ }
+ if (name != null) {
+ String[] nameParts = name.split(Pattern.quote(" "));
+ if (nameParts.length > 0) {
+ zip = nameParts[0].trim();
+ }
+ }
+ }
+ }
+ return zip;
+ }
+
+ public static final int UNSET_ADMIN_LEVEL = 100; // must be higher than real levels
+ /**
+ * translate the admin_level tag to an integer.
+ * @param tags the boundary tags
+ * @return the admin_level value. The value is UNSET_ADMIN_LEVEL if
+ * the conversion failed.
+ */
+ private int getAdminLevel(Tags tags) {
+ String level = tags.get("admin_level");
+ if (level == null) {
+ return UNSET_ADMIN_LEVEL;
+ }
+ try {
+ Integer res = Integer.valueOf(level);
+ if (res < 2 || res > 11)
+ return UNSET_ADMIN_LEVEL;
+ else
+ return res;
+ } catch (NumberFormatException nfe) {
+ return UNSET_ADMIN_LEVEL;
+ }
+ }
+}
+
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryMerger.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryMerger.java
new file mode 100644
index 0000000..371e4f5
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryMerger.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2006, 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.reader.osm.boundary;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * The class merges two directories with precompiled bounds files. Both directory may contain files covering
+ * the same area. These files are merged so that the resulting file contains all boundaries of both
+ * files. Boundaries with the same OSM-id that are contained in both files are merged with a union of its covered area.
+ * <br/><br/>
+ * Using this merger it is possible to create several smaller bounds compilations (e.g. one country only) and merge
+ * these compilations together afterwards.
+ *
+ * @author WanMil
+ */
+public class BoundaryMerger {
+
+ public BoundaryMerger() {
+
+ }
+
+ private void copy(File file, File to) {
+ String filename = file.getName();
+
+ try {
+ FileChannel in = (new FileInputStream(file)).getChannel();
+ FileChannel out = (new FileOutputStream(new File(to,filename))).getChannel();
+ in.transferTo(0, file.length(), out);
+ in.close();
+ out.close();
+ } catch (IOException exp) {
+ System.err.println(exp);
+ }
+ }
+
+ public void merge(File dir1, File dir2, File targetDir) throws IOException {
+ List<String> fl1 = BoundaryUtil.getBoundaryDirContent(dir1.getAbsolutePath());
+ List<String> fl2 = BoundaryUtil.getBoundaryDirContent(dir2.getAbsolutePath());
+
+ Collections.sort(fl1);
+ Collections.sort(fl2);
+
+ ListIterator<String> fl1Iter = fl1.listIterator();
+ ListIterator<String> fl2Iter = fl2.listIterator();
+
+ BoundarySaver bSave = new BoundarySaver(targetDir, BoundarySaver.QUADTREE_DATA_FORMAT);
+ bSave.setCreateEmptyFiles(false);
+
+ List<File> copy = new ArrayList<File>();
+
+ int processed = 0;
+ int all = fl1.size()+fl2.size();
+
+ while (fl1Iter.hasNext() || fl2Iter.hasNext()) {
+ String f1 = (fl1Iter.hasNext() ? fl1Iter.next(): null);
+ String f2 = (fl2Iter.hasNext() ? fl2Iter.next(): null);
+
+ if (f1 == null) {
+ copy.add(new File(dir2,f2));
+ } else if (f2 == null) {
+ copy.add(new File(dir1,f1));
+ } else {
+ int cmp = f1.compareTo(f2);
+ if (cmp < 0) {
+ copy.add(new File(dir1,f1));
+ fl2Iter.previous();
+ } else if (cmp > 0) {
+ copy.add(new File(dir2,f2));
+ fl1Iter.previous();
+ } else {
+ BoundaryQuadTree bqt1 = BoundaryUtil.loadQuadTree(dir1.getAbsolutePath(), f1);
+ if (bqt1 == null){
+ System.err.println("Failed to load quadtree for " + dir1.getAbsolutePath() + f1);
+ System.exit(-1);
+ }
+ BoundaryQuadTree bqt2 = BoundaryUtil.loadQuadTree(dir2.getAbsolutePath(), f2);
+ if (bqt2 == null){
+ System.err.println("Failed to load quadtree for " + dir2.getAbsolutePath() + f2);
+ System.exit(-1);
+ }
+
+ bqt1.merge(bqt2);
+ bSave.saveQuadTree(bqt1, f1);
+ processed += 2;
+ System.out.println(processed+"/"+all+" processed");
+ }
+ }
+ }
+ bSave.end();
+
+ for (File f: copy) {
+ copy(f, targetDir);
+ processed++;
+ System.out.println(processed+"/"+all+" processed");
+ }
+ }
+
+ /**
+ * @param args
+ * @throws IOException
+ */
+ public static void main(String[] args) throws IOException {
+ if (args.length != 3) {
+ System.err.println("java uk.me.parabola.mkgmap.reader.osm.boundary.BoundaryMerger <bounds1> <bounds2> <merge>");
+ System.err.println("<bounds1> <bounds2> : directories with *.bnd files to merge");
+ System.err.println("<merge> target directory, is created if it doesn't exist");
+
+ return;
+ }
+
+ File b1 = new File(args[0]);
+ File b2 = new File(args[1]);
+
+ File merge = new File(args[2]);
+
+ // TODO: maybe allow zip as input
+ if (b1.exists() == false || b1.isDirectory() == false) {
+ System.err.println(b1 + " does not exist or is not a directory");
+ return;
+ }
+
+ if (b2.exists() == false || b2.isDirectory() == false) {
+ System.err.println(b2 + " does not exist or is not a directory");
+ return;
+ }
+
+ if (merge.exists() && merge.isDirectory() == false) {
+ System.err.println(merge + " is not a directory");
+ }
+
+ if (merge.exists() == false) {
+ merge.mkdirs();
+ }
+
+ BoundaryMerger merger = new BoundaryMerger();
+ merger.merge(b1, b2, merge);
+
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryPreprocessor.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryPreprocessor.java
new file mode 100644
index 0000000..9a60da8
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryPreprocessor.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2006, 2012.
+ *
+ * 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.reader.osm.boundary;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import uk.me.parabola.imgfmt.FormatException;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.reader.osm.LocationHook;
+
+/**
+ * Preprocesses the boundary information to be used by the {@link LocationHook} class.
+ * @author WanMil
+ */
+public class BoundaryPreprocessor implements Runnable {
+ private static final Logger log = Logger.getLogger(BoundaryPreprocessor.class);
+ private static final List<Class<? extends LoadableBoundaryDataSource>> loaders;
+ static {
+ String[] sources = {
+ "uk.me.parabola.mkgmap.reader.osm.boundary.OsmBinBoundaryDataSource",
+ "uk.me.parabola.mkgmap.reader.osm.boundary.O5mBinBoundaryDataSource",
+ // must be last as it is the default
+ "uk.me.parabola.mkgmap.reader.osm.boundary.Osm5BoundaryDataSource", };
+
+ loaders = new ArrayList<Class<? extends LoadableBoundaryDataSource>>();
+
+ for (String source : sources) {
+ try {
+ @SuppressWarnings({ "unchecked" })
+ Class<? extends LoadableBoundaryDataSource> c = (Class<? extends LoadableBoundaryDataSource>) Class
+ .forName(source);
+ loaders.add(c);
+ } catch (ClassNotFoundException e) {
+ // not available, try the rest
+ } catch (NoClassDefFoundError e) {
+ // not available, try the rest
+ }
+ }
+ }
+
+ /**
+ * Return a suitable boundary map reader. The name of the resource to be
+ * read is passed in. This is usually a file name, but could be something
+ * else.
+ *
+ * @param name
+ * The resource name to be read.
+ * @return A LoadableBoundaryDataSource that is capable of reading the
+ * resource.
+ */
+ private static LoadableBoundaryDataSource createMapReader(String name) {
+ for (Class<? extends LoadableBoundaryDataSource> loader : loaders) {
+ try {
+ LoadableBoundaryDataSource src = loader.newInstance();
+ if (name != null && src.isFileSupported(name))
+ return src;
+ } catch (InstantiationException e) {
+ // try the next one.
+ } catch (IllegalAccessException e) {
+ // try the next one.
+ } catch (NoClassDefFoundError e) {
+ // try the next one
+ }
+ }
+
+ // Give up and assume it is in the XML format. If it isn't we will get
+ // an error soon enough anyway.
+ return new Osm5BoundaryDataSource();
+ }
+
+
+ private String boundaryFilename;
+ private String outDir;
+ private ExecutorService threadPool;
+ private final BlockingQueue<Future<Object>> remainingTasks = new LinkedBlockingQueue<Future<Object>>();
+
+ /**
+ * constructor for stand-alone usage (workout only)
+ * @param in source directory or zip file
+ * @param out target directory
+ */
+ private BoundaryPreprocessor(String boundaryFilename, String out){
+ this.boundaryFilename = boundaryFilename;
+ this.outDir = out;
+
+ int maxJobs = Runtime.getRuntime().availableProcessors();
+ if (maxJobs > 1)
+ this.threadPool = Executors.newFixedThreadPool(maxJobs);
+ else
+ this.threadPool = null;
+ }
+
+ /**
+ * Sets the number of threads that is used as maximum by the boundary
+ * preparer.
+ *
+ * @param maxThreads the maximum number of threads
+ */
+ public void setMaxThreads(int maxThreads) {
+ if (maxThreads > 1)
+ this.threadPool = Executors.newFixedThreadPool(maxThreads);
+ else
+ this.threadPool = null;
+ }
+
+ public void run() {
+ long t1 = System.currentTimeMillis();
+ boolean prepOK = createRawData();
+ long t2 = System.currentTimeMillis();
+ log.info("BoundaryPreparer pass 1 took", (t2-t1), "ms");
+
+ if (!prepOK){
+ System.err.println("Boundary creation failed.");
+ return;
+ }
+ workoutBoundaryRelations();
+ }
+
+ /**
+ * Parse OSM data and create boundaries. Distribute the boundaries on a grid
+ * with a fixed raster.
+ * @return true if data was successfully written, else false
+ */
+ private boolean createRawData(){
+ File boundsDirectory = new File(outDir);
+ BoundarySaver saver = new BoundarySaver(boundsDirectory, BoundarySaver.RAW_DATA_FORMAT);
+ LoadableBoundaryDataSource dataSource = createMapReader(boundaryFilename);
+ dataSource.setBoundarySaver(saver);
+ log.info("Started loading", boundaryFilename);
+ try {
+ dataSource.load(boundaryFilename);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ return false;
+ } catch (FormatException e) {
+ e.printStackTrace();
+ return false;
+ }
+ saver.setBbox(dataSource.getBounds());
+ log.info("Finished loading", boundaryFilename);
+ saver.end();
+ return true;
+ }
+
+
+ public static void main(String[] args) {
+ if (args[0].equals("--help") || args.length != 2) {
+ System.err.println("Usage:");
+ System.err.println("java -cp mkgmap.jar uk.me.parabola.mkgmap.reader.osm.boundary.BoundaryPreprocessor <inputfile> <boundsdir>");
+ System.err.println(" <inputfile>: File containing boundary data (OSM, PBF or O5M format)");
+ System.err.println(" <boundsdir>: Directory in which the preprocessed bounds files are created");
+
+ System.exit(-1);
+ }
+
+ String inputFile = args[0];
+ String outputDir = args[1];
+
+ long t1 = System.currentTimeMillis();
+
+ BoundaryPreprocessor p = new BoundaryPreprocessor(inputFile, outputDir);
+ try {
+ p.runPreprocessing();
+ } catch (InterruptedException exp) {
+ exp.printStackTrace();
+ } catch (ExecutionException exp) {
+ System.err.println(exp);
+ exp.printStackTrace();
+ }
+
+ log.info("Bnd files converted in", (System.currentTimeMillis()-t1), "ms");
+ }
+
+ /**
+ * Reworks all bounds files of the given directory so that all boundaries
+ * are applied with the information with which boundary they intersect.<br/>
+ * The files are rewritten in the QUADTREE_DATA_FORMAT which is used in the
+ * LocationHook.
+ */
+ private void workoutBoundaryRelations() {
+ List<String> boundsFileNames = BoundaryUtil.getBoundaryDirContent(this.outDir);
+
+ for (String boundsFileName : boundsFileNames) {
+ // start workers that rework the boundary files and add the
+ // quadtree information
+ addWorker(new QuadTreeWorker(this.outDir, boundsFileName));
+ }
+ }
+
+
+
+ @SuppressWarnings("unchecked")
+ protected <V> Future<V> addWorker(Callable<V> worker) {
+ if (threadPool == null) {
+ // only one thread available for the preparer
+ // so execute the task directly
+ FutureTask<V> future = new FutureTask<V>(worker);
+ future.run();
+ return future;
+ } else {
+ Future<Object> task = threadPool.submit((Callable<Object>) worker);
+ remainingTasks.add(task);
+ return (Future<V>) task;
+ }
+ }
+
+ /**
+ * Starts the preprocessing
+ */
+ public void runPreprocessing() throws InterruptedException, ExecutionException {
+ if (threadPool == null) {
+ // there is no thread pool so run it in the same thread and wait for
+ // its completion
+ run();
+ } else {
+
+ // start the preparer
+ Future<Object> prepTask = threadPool.submit(this, new Object());
+
+ // first wait for the main preparer task to finish
+ prepTask.get();
+
+ // then wait for all workers started by the preparer to finish
+ while (true) {
+ Future<Object> task = remainingTasks.poll();
+ if (task == null) {
+ // no more remaining tasks
+ // preparer has finished completely
+ break;
+ }
+ // wait for the task to finish
+ task.get();
+ }
+
+ // stop thread pool
+ threadPool.shutdown();
+ }
+ }
+
+ class QuadTreeWorker implements Callable<String> {
+ private final String boundsDir;
+ private final String boundsFilename;
+
+ public QuadTreeWorker(String boundsDir, String boundsFilename) {
+ this.boundsDir = boundsDir;
+ this.boundsFilename = boundsFilename;
+ }
+
+ @Override
+ public String call() throws Exception {
+ log.info("Workout boundary relations in", boundsDir, boundsFilename);
+ long t1 = System.currentTimeMillis();
+ BoundaryQuadTree bqt = BoundaryUtil.loadQuadTree(boundsDir, boundsFilename);
+ long dt = System.currentTimeMillis() - t1;
+ log.info("splitting", boundsFilename, "took", dt, "ms");
+ if (bqt != null){
+ File outDir = new File(boundsDir);
+ BoundarySaver saver = new BoundarySaver(outDir, BoundarySaver.QUADTREE_DATA_FORMAT);
+ saver.setCreateEmptyFiles(false);
+
+ saver.saveQuadTree(bqt, boundsFilename);
+ saver.end();
+ }
+ return boundsFilename;
+ }
+
+ }
+
+}
+
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryQuadTree.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryQuadTree.java
new file mode 100644
index 0000000..552310a
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryQuadTree.java
@@ -0,0 +1,1352 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.reader.osm.boundary;
+
+import java.awt.Rectangle;
+import java.awt.geom.Area;
+import java.awt.geom.Path2D;
+import java.awt.geom.Rectangle2D;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.reader.osm.Tags;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.EnhancedProperties;
+import uk.me.parabola.util.GpxCreator;
+import uk.me.parabola.util.Java2DConverter;
+
+/**
+ * A quadtree implementation to handle areas formed by boundaries.
+ * Each node of the Quadtree stores a list of NodeElems. A NodeElem
+ * stores one area and the related location relevant tags.
+ * @author GerdP
+ *
+ */
+public class BoundaryQuadTree {
+ private static final Logger log = Logger.getLogger(BoundaryQuadTree.class);
+ private static final boolean DEBUG = false;
+ // debugging aid
+ private static final String DEBUG_TREEPATH = "?";
+ private static final boolean DO_ALL_TESTS = false;
+
+ // maps the "normal" tags of the boundaries that are saved in this tree to
+ // the boundaryId
+ private final HashMap<String, Tags> boundaryTags = new LinkedHashMap<String,Tags>();
+ // maps the location relevant info to the boundaryId
+ private final HashMap<String, BoundaryLocationInfo> preparedLocationInfo;
+ // property controlled preparer
+ private final BoundaryLocationPreparer preparer;
+
+ private final Node root;
+ // the bounding box of the quadtree
+ private final Rectangle bbox;
+ private final String bbox_key;
+
+ // tags that can be returned in the get method
+ public final static String[] mkgmapTagsArray = {
+ "mkgmap:admin_level1",
+ "mkgmap:admin_level2",
+ "mkgmap:admin_level3",
+ "mkgmap:admin_level4",
+ "mkgmap:admin_level5",
+ "mkgmap:admin_level6",
+ "mkgmap:admin_level7",
+ "mkgmap:admin_level8",
+ "mkgmap:admin_level9",
+ "mkgmap:admin_level10",
+ "mkgmap:admin_level11",
+ "mkgmap:postcode"
+ };
+ // 11: the position of "mkgmap:postcode" in the above array
+ public final static short POSTCODE_ONLY = 1 << 11;
+
+ /**
+ * Create a quadtree with the data in an open stream.
+ * @param inpStream the open stream with QUADTREE_DATA_FORMAT
+ * @param fileBbox The bounding box for the quadTree
+ * @param searchBbox The bounding box for the quadTree, only data within this box is used
+ * @param props if not null, use it to set location names
+ */
+ public BoundaryQuadTree(DataInputStream inpStream,
+ uk.me.parabola.imgfmt.app.Area fileBbox,
+ uk.me.parabola.imgfmt.app.Area searchBbox, EnhancedProperties props)
+ throws IOException {
+ preparedLocationInfo = new LinkedHashMap<String, BoundaryLocationInfo> ();
+ preparer = new BoundaryLocationPreparer(props);
+ assert fileBbox != null: "parameter fileBbox must not be null";
+ this.bbox = new Rectangle(fileBbox.getMinLong(), fileBbox.getMinLat(),
+ fileBbox.getMaxLong() - fileBbox.getMinLong(), fileBbox.getMaxLat()
+ - fileBbox.getMinLat());
+ this.bbox_key = BoundaryUtil.getKey(this.bbox.y, this.bbox.x);
+ root = new Node(this.bbox);
+
+ readStreamQuadTreeFormat(inpStream,searchBbox);
+ }
+
+
+ /**
+ * Create a quadtree for a given bounding box and a list of boundaries.
+ * Involves costly calculations to split the areas.
+ * @param givenBbox The bounding box for the quadTree, only data within this box is used
+ * @param boundaries A list of boundaries. For better performance, the list should be sorted so that small areas come first.
+ * @param props if not null, use it to set location names
+ */
+ public BoundaryQuadTree(uk.me.parabola.imgfmt.app.Area givenBbox,
+ List<Boundary> boundaries, EnhancedProperties props) {
+ preparer = new BoundaryLocationPreparer(props);
+ assert givenBbox != null: "parameter givenBbox must not be null";
+ this.bbox = new Rectangle(givenBbox.getMinLong(), givenBbox.getMinLat(),
+ givenBbox.getMaxLong() - givenBbox.getMinLong(),
+ givenBbox.getMaxLat() - givenBbox.getMinLat());
+ this.bbox_key = BoundaryUtil.getKey(this.bbox.y, this.bbox.x);
+
+ root = new Node(this.bbox);
+ // extract the location relevant tags
+ preparedLocationInfo = preparer.getPreparedLocationInfo(boundaries);
+ if (boundaries == null || boundaries.size() == 0)
+ return;
+
+
+ HashMap<String,Boundary> bMap = new HashMap<String,Boundary>();
+ for (Boundary b: boundaries){
+ bMap.put(b.getId(), b);
+ boundaryTags.put(b.getId(), b.getTags());
+ }
+ sortBoundaryTagsMap();
+ // add the boundaries in a specific order
+ for (String id: boundaryTags.keySet()){
+ root.add (bMap.get(id).getArea(), id, null);
+ }
+ bMap = null;
+ root.split("_");
+ }
+
+ /**
+ * Return location relevant Tags for the point defined by Coord
+ * @param co the point
+ * @return a reference to the internal Tags or null if the point was not found.
+ * The returned Tags must not be modified by the caller.
+ */
+ public Tags get(Coord co){
+ Tags res = root.get(co/*, "_"*/);
+ if (res == null && bbox.contains(co.getLongitude(),co.getLatitude())){
+ // we did not find the point, probably it lies on a boundary and
+ // the clauses regarding insideness of areas make it "invisible"
+ // try again a few other nearby points
+ Coord neighbour1 = new Coord(co.getLatitude()-1, co.getLongitude());
+ Coord neighbour2 = new Coord(co.getLatitude() , co.getLongitude()-1);
+ Coord neighbour3 = new Coord(co.getLatitude()+1, co.getLongitude());
+ Coord neighbour4 = new Coord(co.getLatitude() , co.getLongitude()+1);
+ res = root.get(neighbour1/*, "_"*/);
+ if (res == null)
+ res = root.get(neighbour2/*, "_"*/);
+ if (res == null)
+ res = root.get(neighbour3/*, "_"*/);
+ if (res == null)
+ res = root.get(neighbour4/*, "_"*/);
+ }
+ return res;
+ }
+
+ /**
+ * Return a map with boundary IDs and the related tags.
+ * @return the map. It is a LinkedHashMap, the order is created with
+ * AdminLevelCollator and then reversed.
+ */
+ public Map<String, Tags> getTagsMap() {
+ return new LinkedHashMap<String, Tags>(boundaryTags);
+ }
+
+ /**
+ * Create a map with boundary Ids and the related area parts that
+ * are stored in the tree. When the parts are added, they normally
+ * give the original boundary (clipped by the bounding box of the quadtree).
+ * Exception: For overlapping boundaries with equal admin_levels only one
+ * boundary will contain the complete area information.
+ * @return A HashMap mapping BoundaryIds to a List with all area parts
+ */
+ public Map<String, List<Area>> getAreas(){
+ Map<String, List<Area>> areas = new HashMap<String, List<Area>>();
+ root.getAreas(areas, "_", null);
+ return areas;
+ }
+
+ /**
+ * For BoundaryMerger: Add the data of another tree into this tree.
+ * @param other the other instance of BoundaryQuadTree
+ */
+ public void merge(BoundaryQuadTree other){
+ if (bbox.equals(other.bbox) == false){
+ log.error("Cannot merge tree with different bounding box");
+ return;
+ }
+ for (Entry <String, BoundaryLocationInfo> entry : other.preparedLocationInfo.entrySet()){
+ if (this.preparedLocationInfo.containsKey(entry.getKey()) == false){
+ this.preparedLocationInfo.put(entry.getKey(),entry.getValue());
+ }
+ }
+ // add the others tags
+ for (Entry <String, Tags> entry : other.boundaryTags.entrySet()){
+ if (this.boundaryTags.containsKey(entry.getKey()) == false){
+ this.boundaryTags.put(entry.getKey(),entry.getValue());
+ }
+ }
+ sortBoundaryTagsMap();
+ root.mergeNodes(other.root, "_");
+ }
+
+ /**
+ * Return the area that is covered by a given admin level
+ * @param admLevel reasonable values are 2 .. 11 (inclusive)
+ * @return a new Area instance (might be empty)
+ */
+ public Area getCoveredArea (Integer admLevel){
+ return root.getCoveredArea(admLevel, "_");
+ }
+
+ /**
+ * Return boundary names relevant for the point defined by Coord
+ * @param co the point
+ * @return A string with a boundary Id, optionally followed by pairs of admlevel:boundary Id.
+ * Sample: r1184826;6:r62579;4:r62372;2:r51477
+ */
+ public String getBoundaryNames(Coord co){
+ return root.getBoundaryNames(co);
+ }
+
+
+ /**
+ * Save the BoundaryQuadTree to an open stream. The format is QUADTREE_DATA_FORMAT.
+ * @param stream
+ * @throws IOException
+ */
+ public void save(OutputStream stream)throws IOException{
+ // save the tag infos of all boundaries first
+ for (Entry<String,Tags> entry : boundaryTags.entrySet()){
+ writeBoundaryTags(stream, entry.getValue(), entry.getKey());
+ }
+ // now write the area info for those boundaries that have positions in the quadtree
+ root.save(stream, "_");
+ }
+
+ /**
+ * Sort the boundary-Tags-Map so that zip-code-only boundaries appear first, followed by
+ * admin_level-11,10,9,...2
+ */
+ private void sortBoundaryTagsMap(){
+ // make sure that the merged LinkedHashMap is sorted as mergeBoundaries() needs it
+ ArrayList<String> ids = new ArrayList<String>(boundaryTags.keySet());
+ Collections.sort(ids, new AdminLevelCollator());
+ Collections.reverse(ids);
+ HashMap<String,Tags> tmp = new LinkedHashMap<String,Tags>(boundaryTags);
+ boundaryTags.clear();
+ for (String id: ids){
+ boundaryTags.put(id,tmp.get(id));
+ }
+ }
+
+
+ /**
+ * Write the TAGS sections of the QUADTREE_DATA_FORMAT. Each
+ * section starts with the "TAGS" eye catcher followed by the
+ * boundary id, the number of tags and the tags as
+ * key/value pairs.
+ * @param stream an already opened OutputStream
+ * @param tags the boundary tags
+ * @param id the boundaryId
+ * @throws IOException
+ */
+ private void writeBoundaryTags(OutputStream stream, Tags tags, String id) throws IOException{
+ DataOutputStream dOutStream = new DataOutputStream(stream);
+ dOutStream.writeUTF("TAGS");
+ dOutStream.writeUTF(id);
+ // write the tags
+ int noOfTags = tags.size();
+
+ dOutStream.writeInt(noOfTags);
+
+ Iterator<Entry<String, String>> tagIter = tags.entryIterator();
+ while (tagIter.hasNext()) {
+ Entry<String, String> tag = tagIter.next();
+ dOutStream.writeUTF(tag.getKey());
+ dOutStream.writeUTF(tag.getValue());
+ noOfTags--;
+ }
+
+ assert noOfTags == 0 : "Remaining tags: " + noOfTags + " size: "
+ + tags.size() + " " + tags.toString();
+
+ dOutStream.flush();
+ }
+
+ /**
+ * Read a stream in QUADTREE_DATA_FORMAT
+ * @param inpStream the already opened DataInputStream
+ * @param bbox a bounding box. Areas not intersecting the bbox are
+ * ignored.
+ * @throws IOException
+ */
+ private void readStreamQuadTreeFormat(DataInputStream inpStream,
+ uk.me.parabola.imgfmt.app.Area bbox) throws IOException{
+ boolean isFirstArea = true;
+ try {
+ while (true) {
+ String type = inpStream.readUTF();
+ if (type.equals("TAGS")){
+ String id = inpStream.readUTF();
+ Tags tags = new Tags();
+ int noOfTags = inpStream.readInt();
+ for (int i = 0; i < noOfTags; i++) {
+ String name = inpStream.readUTF();
+ String value = inpStream.readUTF();
+ tags.put(name, value.intern());
+ }
+ boundaryTags.put(id, tags);
+ }
+ else if (type.equals("AREA")){
+ if (isFirstArea){
+ isFirstArea = false;
+ prepareLocationInfo();
+ }
+ int minLat = inpStream.readInt();
+ int minLong = inpStream.readInt();
+ int maxLat = inpStream.readInt();
+ int maxLong = inpStream.readInt();
+ log.debug("Next boundary. Lat min:",minLat,"max:",maxLat,"Long min:",minLong,"max:",maxLong);
+ uk.me.parabola.imgfmt.app.Area rBbox = new uk.me.parabola.imgfmt.app.Area(
+ minLat, minLong, maxLat, maxLong);
+ int bSize = inpStream.readInt();
+ log.debug("Size:",bSize);
+
+ if ( bbox == null || bbox.intersects(rBbox)) {
+ log.debug("Bbox intersects. Load the boundary");
+ String treePath = inpStream.readUTF();
+ String id = inpStream.readUTF();
+ String refs = inpStream.readUTF();
+ if (refs.isEmpty())
+ refs = null;
+ Area area = BoundaryUtil.readAreaAsPath(inpStream);
+
+ if (area != null && area.isEmpty() == false)
+ root.add(area, refs, id, treePath);
+ } else {
+ log.debug("Bbox does not intersect. Skip",bSize);
+ inpStream.skipBytes(bSize);
+ }
+ }
+ else{
+ log.error("unknown type field " + type );
+ }
+ }
+ } catch (EOFException exp) {
+ // it's always thrown at the end of the file
+ // log.error("Got EOF at the end of the file");
+ }
+ }
+
+ /**
+ * Fill the map preparedLocationInfo with data from the boundary tags.
+ */
+ private void prepareLocationInfo() {
+ for (Entry<String, Tags> entry : boundaryTags.entrySet()) {
+ BoundaryLocationInfo info = preparer.parseTags(entry.getValue());
+ preparedLocationInfo.put(entry.getKey(), info);
+ }
+ }
+
+
+
+ /**
+ * A node for the BoundaryQuadTree. Many methods use a so-called treePath to identify the position
+ * of the node in the tree. A treePath _021 means root->childs[0]->childs[2]->childs[1].
+ * This path is also saved in the QUADTREE_DATA_FORMAT.
+ * @author GerdP
+ *
+ */
+ private class Node {
+ private Node [] childs;
+ private List<NodeElem> nodes;
+
+ // bounding box of this part of the tree
+ private final Rectangle bbox;
+ private final uk.me.parabola.imgfmt.app.Area bounds;
+
+ private short depth;
+ private boolean isLeaf;
+
+ /**
+ * Create an empty node for the given bbox
+ * @param bbox
+ */
+ private Node (Rectangle bbox){
+ this.bounds = new uk.me.parabola.imgfmt.app.Area (bbox.y, bbox.x, bbox.y+bbox.height, bbox.x+bbox.width);
+ this.bbox = new Rectangle(bbox);
+ isLeaf = true;
+ }
+
+ /**
+ * Constructor that is used by the split method. The parameters give the corners of a bounding box.
+ * @param minLat
+ * @param minLong
+ * @param maxLat
+ * @param maxLong
+ */
+ private Node (int minLat, int minLong, int maxLat, int maxLong){
+ this.bounds = new uk.me.parabola.imgfmt.app.Area (minLat, minLong, maxLat, maxLong);
+ this.bbox = new Rectangle(minLong, minLat, maxLong - minLong, maxLat - minLat);
+ this.isLeaf = true;
+ }
+
+ /**
+ * Travel through the tree, save all usable areas of all leaves
+ * @param stream the open OutputStream
+ * @param treePath the path to this tree node
+ * @throws IOException
+ */
+ private void save(OutputStream stream, String treePath )throws IOException{
+ if (isLeaf){
+ if (nodes != null){
+ for (NodeElem nodeElem :nodes){
+ if (nodeElem.isValid())
+ nodeElem.save(stream, treePath);
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < 4; i++){
+ childs[i].save(stream, treePath + i);
+ }
+ }
+ }
+
+ /**
+ * Return boundary names relevant for the point defined by Coord
+ * @param co the point
+ * @return A string with a boundary Id, optionally followed by pairs of admlevel:boundary Id.
+ * Sample: r1184826;6:r62579;4:r62372;2:r51477
+ */
+ private String getBoundaryNames(Coord co) {
+ if (this.bounds.contains(co) == false)
+ return null;
+ if (isLeaf){
+ if (nodes == null || nodes.size() == 0)
+ return null;
+ int lon = co.getLongitude();
+ int lat = co.getLatitude();
+ for (NodeElem nodeElem: nodes){
+ if (nodeElem.tagMask > 0){
+ if (nodeElem.area.contains(lon,lat)){
+ String res = new String (nodeElem.boundaryId);
+ if (nodeElem.locationDataSrc != null)
+ res += ";" + nodeElem.locationDataSrc;
+ return res;
+ }
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < 4; i++){
+ String res = childs[i].getBoundaryNames(co);
+ if (res != null)
+ return res;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return location relevant Tags for the point defined by Coord
+ * @param co the point
+ * @return a reference to the internal Tags or null if the point was not found.
+ * The returned Tags must not be modified by the caller.
+ */
+ private Tags get(Coord co/*, String treePath*/){
+ if (this.bounds.contains(co) == false)
+ return null;
+ if (isLeaf){
+ if (nodes == null || nodes.size() == 0)
+ return null;
+ int lon = co.getLongitude();
+ int lat = co.getLatitude();
+ for (NodeElem nodeElem: nodes){
+ if (nodeElem.tagMask > 0){
+ if (nodeElem.area.contains(lon,lat)){
+ return nodeElem.locTags;
+ }
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < 4; i++){
+ Tags res = childs[i].get(co/*, treePath+i*/);
+ if (res != null)
+ return res;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Debugging helper: Print node Tags and maybe create gpx
+ * @param prefix identifies the calling routine
+ * @param treePath
+ */
+ private void printNodes(String prefix, String treePath){
+ int n = 0;
+ for (NodeElem nodeElem: nodes){
+ if (treePath.equals(DEBUG_TREEPATH)){
+ nodeElem.saveGPX(prefix,treePath);
+ }
+ String res = new String();
+ for (int i = mkgmapTagsArray.length-1; i >= 0 ; --i){
+ String tagVal = nodeElem.locTags.get(mkgmapTagsArray[i] );
+ if (tagVal != null){
+ res += i+1 + "=" + tagVal + ";";
+ }
+ }
+ System.out.println(prefix + " " + treePath + " " + n + ":" + nodeElem.boundaryId + " " + nodeElem.tagMask + " " + res );
+ ++n;
+ }
+ }
+
+ /**
+ * Test if all areas in one node are distinct areas. This is wanted, but not
+ * absolutely needed.
+ * @param treePath Position in the quadtree. Used for GPX.
+ * @return false if any area intersects with another area and the
+ * intersection has a dimension.
+ */
+ private boolean testIfDistinct(String treePath){
+ boolean ok = true;
+ for (int i=0; i< nodes.size()-1; i++){
+ for (int j=i+1; j < nodes.size(); j++){
+ Area a = new Area (nodes.get(i).area);
+ a.intersect(nodes.get(j).area);
+
+ if (a.isEmpty())
+ continue;
+ Path2D.Double path = new Path2D.Double(a);
+ a = new Area(path);
+ if (a.isEmpty())
+ continue;
+
+ if (a.getBounds2D().getHeight() < 0.1d && a.getBounds2D().getWidth() < 0.1d)
+ continue;
+ ok = false;
+ log.error("boundaries still intersect in tree path "
+ + treePath + " " + nodes.get(i).boundaryId + " "
+ + nodes.get(j).boundaryId + " bbox: " + a.getBounds2D());
+ NodeElem tmpNodeElem = new NodeElem(nodes.get(i).boundaryId+"_"+nodes.get(j).boundaryId,
+ new Area(a.getBounds2D()), null);
+ tmpNodeElem.saveGPX("intersection_rect",treePath);
+ }
+ }
+ if (DEBUG){
+ if (!ok){
+ for (NodeElem nodeElem: nodes){
+ nodeElem.saveGPX("not_distinct",treePath);
+ }
+ }
+ }
+ return ok;
+ }
+ /**
+ * Add an area and the related tags to the tree. The position in the tree is known
+ * and passed via the treePath.
+ * @param area the part of the boundary area that should be added to the tree.
+ * @param refs a string that contains information about other boundaries that share the
+ * same area
+ * @param boundaryId id of the originating boundary
+ * @param treePath empty string: calculate position, else the first character is used as index of the child
+ */
+ private void add(Area area, String refs, String boundaryId, String treePath){
+ Node node = this;
+ String path = treePath;
+ while(path.isEmpty() == false){
+ int idx = Integer.valueOf(path.substring(0, 1));
+ path = path.substring(1);
+ if (node.childs == null)
+ node.allocChilds();
+ node = node.childs[idx];
+ }
+
+ if (node.nodes == null){
+ node.nodes = new ArrayList<NodeElem>();
+ }
+ NodeElem nodeElem = new NodeElem(boundaryId, area, refs);
+ assert (area.getBounds2D().getWidth() == 0 || area.getBounds2D().getHeight() == 0 || this.bbox.intersects(area.getBounds2D())) : "boundary bbox doesn't fit into quadtree "+ bbox + " " + area.getBounds2D();
+ node.nodes.add(nodeElem);
+ }
+
+ /**
+ * Add an area and the related tags to the tree.
+ * @param area the part of the boundary area that should be added to the tree.
+ * @param locTags the location relevant tags from the boundary
+ * @param boundaryId id of the originating boundary
+ */
+ private void add(Area area, String boundaryId, String refs){
+ if (!isLeaf){
+ // should not happen
+ for (int i = 0; i < 4; i++){
+ childs[i].add(area, boundaryId, refs);
+ }
+ return;
+ }
+ // only add areas that intersect with this part of the tree
+ if (area.intersects(this.bbox) == false)
+ return;
+ Area a;
+ if (area.contains(bbox))
+ a = new Area(this.bbox); // quadtree bbox lies entirely in area
+ else {
+ a = new Area(area);
+ Area bboxArea = new Area(this.bbox);
+ // check if area lies entirely in quadtree bbox
+ if (bboxArea.contains(area.getBounds2D()) == false){
+ // worst case: area and bbox partly intersect
+ a.intersect(bboxArea);
+ }
+ }
+ if (a.isEmpty() == false){
+ if (nodes == null)
+ nodes = new ArrayList<NodeElem>();
+ NodeElem nodeElem = new NodeElem(boundaryId, a, refs);
+ nodes.add(nodeElem);
+ }
+ }
+
+ /**
+ * Merge this subtree with another subtree.
+ * @param other A Node of another BoundaryQuadTree
+ * @param treePath position of this node in its tree
+ */
+ private void mergeNodes(Node other, String treePath){
+ if (!this.isLeaf && !other.isLeaf){
+ for (int i = 0; i < 4; i++){
+ childs[i].mergeNodes(other.childs[i], treePath+i);
+ }
+ }
+ else{
+ // (sub) tree is different, rebuild it as combination of
+ // both trees.
+ HashMap<String,List<Area>> areas = new HashMap<String, List<Area>>();
+ this.getAreas(areas, treePath,null);
+ other.getAreas(areas, treePath,null);
+ isLeaf = true;
+ nodes = null;
+ childs = null;
+
+ for (String id: boundaryTags.keySet()){
+ List<Area> aList = areas.get(id);
+ if (aList == null)
+ continue;
+ Path2D.Double path = new Path2D.Double();
+ for (Area area : aList){
+ BoundaryUtil.addToPath(path, area);
+ }
+ add(new Area(path), id, null);
+ }
+ split(treePath);
+ }
+ }
+
+ /**
+ * Calculate the area that is covered by boundaries of a given adminlevel
+ * @param admLevel the admin_level, a value from 2 to 11 (including)
+ * @param treePath A string that helps to identify the position in the quadtree
+ * @return a new Area instance (might be empty)
+ */
+ private Area getCoveredArea(Integer admLevel, String treePath){
+ HashMap<String,List<Area>> areas = new HashMap<String, List<Area>>();
+ this.getAreas(areas, treePath, admLevel);
+ Path2D.Double path = new Path2D.Double();
+ for (Entry <String, List<Area>> entry : areas.entrySet()){
+ for (Area area: entry.getValue()){
+ BoundaryUtil.addToPath(path,area);
+ }
+ }
+ Area combinedArea = new Area(path);
+ return combinedArea;
+ }
+
+ /**
+ * See BoundaryQuadTree {@link #BoundaryQuadTree.getAreas()}
+ * @param areas
+ * @param treePath
+ * @param admLevel
+ */
+ private void getAreas(Map<String, List<Area>> areas, String treePath, Integer admLevel){
+ if (!this.isLeaf ){
+ for (int i = 0; i < 4; i++){
+ childs[i].getAreas(areas, treePath+i, admLevel);
+ }
+ return;
+ }
+ if (nodes == null || nodes.size() == 0)
+ return;
+
+ Short testMask = null;
+ if (admLevel != null)
+ testMask = (short) (1<<(admLevel-1));
+ for (NodeElem nodeElem : nodes){
+ String id = nodeElem.boundaryId;
+ if (testMask != null && (nodeElem.tagMask & testMask) == 0)
+ continue;
+ List<Area> aList = areas.get(id);
+ Area a = new Area(nodeElem.area);
+ if (aList == null){
+ aList = new ArrayList<Area>(4);
+ areas.put(id, aList);
+ }
+ aList.add(a);
+ if (testMask != null)
+ continue;
+
+ String refInfo = nodeElem.locationDataSrc;
+ if (refInfo != null) {
+ String[] relBounds = refInfo.split(Pattern.quote(";"));
+ for (String relBound : relBounds) {
+ String[] relParts = relBound.split(Pattern.quote(":"));
+ if (relParts.length != 2) {
+ log.error("Wrong format in locationDataSrc. Value: " + refInfo);
+ continue;
+ }
+ id = relParts[1];
+ aList = areas.get(id);
+ a = new Area(nodeElem.area);
+ if (aList == null){
+ aList = new ArrayList<Area>(4);
+ areas.put(id, aList);
+ }
+ aList.add(a);
+ }
+ }
+ }
+ }
+
+ /***
+ * Merge information from the boundaries saved by BoundarySaver.
+ * This method is used when bnd file is in raw format.
+ * For intersections, create new areas with the merged
+ * location tags, and subtract the parts from the source
+ * areas. The result should be a reduced number of distinct areas.
+ * @param treePath Identifies the position in the tree
+ */
+ private void makeDistinct(String treePath){
+ if (isLeaf == false || nodes == null || nodes.size() <= 1)
+ return;
+ if (DEBUG){
+ printNodes("start", treePath);
+ }
+ long t1 = System.currentTimeMillis();
+
+ mergeEqualIds();
+ mergeLastRectangles();
+ if (DEBUG)
+ printNodes("prep", treePath);
+
+ List<NodeElem> reworked = new ArrayList<NodeElem>();
+
+ // detect intersection of areas, merge tag info
+ for (int i=0; i < nodes.size(); i++){
+ NodeElem toAdd = nodes.get(i);
+ if (DEBUG){
+ if (treePath.equals(DEBUG_TREEPATH) || DEBUG_TREEPATH.equals("all")){
+ for (NodeElem nodeElem: reworked){
+ nodeElem.saveGPX("debug"+i,treePath);
+ }
+ }
+ }
+ for (int j=0; j < reworked.size(); j++){
+ if (toAdd.isValid() == false)
+ break;
+ NodeElem currElem = reworked.get(j);
+ if (currElem.srcPos == i || currElem.area.isEmpty())
+ continue;
+
+ Rectangle2D rCurr = currElem.area.getBounds2D();
+
+ Rectangle2D rAdd = rCurr.createIntersection(toAdd.area.getBounds2D());
+ if (rAdd.isEmpty()){
+ continue;
+ }
+ // the bounding boxes intersect, so we have to find out if the areas also intersect
+ Area toAddxCurr = new Area(currElem.area);
+ toAddxCurr.intersect(toAdd.area);
+
+ if (!isWritable(toAddxCurr)){
+ continue; // empty or only too small fragments
+ }
+
+ Area toAddMinusCurr = new Area(toAdd.area);
+ toAddMinusCurr.subtract(currElem.area);
+
+ if (toAddMinusCurr.isEmpty()){
+ // toadd is fully covered by curr
+ if (toAdd.tagMask == POSTCODE_ONLY){
+ // if we get here, toAdd has only zip code that is already known
+ // in larger or equal area of currElem
+ toAdd.area.reset(); // ignore this
+ break;
+ }
+ }
+
+ // test if toAdd contains usable tag(s)
+ String chkMsg = currElem.checkAddTags(toAdd, bounds);
+ // warning: intersection of areas with equal levels
+ if (chkMsg != null){
+ if (DEBUG){
+ // save debug GPX for areas that wiil
+ // appear in warning message below
+ toAdd.saveGPX("warn_toAdd",treePath);
+ currElem.saveGPX("warn_curr",treePath);
+ }
+ log.warn(chkMsg);
+ }
+
+ Area currMinusToAdd = new Area(currElem.area);
+ currMinusToAdd.subtract(toAdd.area);
+
+ // remove intersection part from toAdd
+ toAdd.area = toAddMinusCurr;
+ if (!isWritable(currMinusToAdd)){
+ // curr is fully covered by toAdd
+ if (toAdd.tagMask != POSTCODE_ONLY){
+ currElem.addLocInfo(toAdd);
+ }
+ continue; // no need to create new intersection area
+ }
+
+ NodeElem intersect = new NodeElem(currElem, toAddxCurr, i);
+
+ if (DEBUG){
+ if (chkMsg != null)
+ intersect.saveGPX("warn_inter", treePath);
+ }
+
+ // remove intersection part also from curr
+ currElem.area = currMinusToAdd;
+
+ if (toAdd.tagMask != POSTCODE_ONLY){
+ // combine tag info in intersection
+ intersect.addLocInfo(toAdd);
+ reworked.add(intersect);
+ }
+ }
+
+ if (toAdd.isValid())
+ reworked.add(toAdd);
+ }
+ nodes = reworked;
+ // free memory for nodes with empty or too small areas
+ removeEmptyAreas(treePath);
+
+ long dt = System.currentTimeMillis()-t1;
+ if (dt > 1000)
+ log.info(bbox_key, ": merge required long time:", dt, "ms");
+ if (DEBUG)
+ printNodes("end", treePath);
+
+ //double check ?
+ if (DO_ALL_TESTS){
+ testIfDistinct(treePath);
+ }
+ }
+
+ /**
+ * Combine the areas with equal boundary IDs.
+ * We can assume that equal IDs are paired when add is
+ * called with sorted input.
+ */
+ private void mergeEqualIds(){
+ int start = nodes.size()-1;
+ for (int i = start; i > 0; i--){
+ if (nodes.get(i).boundaryId.equals(nodes.get(i-1).boundaryId)){
+ nodes.get(i-1).area.add(nodes.get(i).area);
+ nodes.remove(i);
+ }
+ }
+ }
+ /**
+ * Optimization:
+ * The last nodes are likely to fully cover the quadtree bbox.
+ * Merge the tag information for them to avoid some splitting
+ * and later merging.
+ */
+ private void mergeLastRectangles(){
+ boolean done;
+ //step1: merge nodes that fully cover the quadtree area
+ do{
+ done = true;
+ if (nodes.size()<= 1)
+ break;
+ NodeElem lastNode = nodes.get(nodes.size()-1);
+ NodeElem prevNode = nodes.get(nodes.size()-2);
+ // don't merge admin_level tags into zip-code only boundary
+ if (prevNode.tagMask != POSTCODE_ONLY && lastNode.area.isRectangular() && prevNode.area.isRectangular()){
+ // two areas are rectangles, it is likely that they are equal to the bounding box
+ // In this case we add the tags to the existing area instead of creating a new one
+ if (prevNode.area.equals(lastNode.area)){
+ prevNode.addLocInfo(lastNode);
+ nodes.remove(nodes.size()-1);
+ done = false;
+ }
+ }
+ } while (!done);
+ }
+
+ /**
+ * The mergeBoundaries() algorithm can create empty
+ * areas (points, lines, or extremely small intersections).
+ * These are removed here.
+ * @param treePath
+ */
+ private void removeEmptyAreas(String treePath){
+ for (int j = nodes.size()-1; j >= 0 ; j--){
+ boolean removeThis = false;
+ NodeElem chkRemove = nodes.get(j);
+ if (chkRemove.isValid() == false)
+ removeThis = true;
+ else if (this.bbox.intersects(chkRemove.area.getBounds2D()) == false){
+ // we might get here because of errors in java.awt.geom.Area
+ // sometimes, Area.subtract() seems to produce an area which
+ // lies outside of original areas
+ removeThis = true;
+ }else if (!isWritable(chkRemove.area)){
+ removeThis = true;
+ }
+ if (removeThis){
+ nodes.remove(j);
+ }
+ }
+ }
+
+ /**
+ * allocate 4 childs with bounding boxes that have 1/4 of the
+ * size of the parent.
+ */
+ private void allocChilds(){
+ childs = new Node[4];
+ Coord center = bounds.getCenter();
+
+ childs[0] = new Node(bounds.getMinLat(), bounds.getMinLong(),
+ center.getLatitude(), center.getLongitude());
+ childs[1] = new Node(center.getLatitude(), bounds.getMinLong(),
+ bounds.getMaxLat(), center.getLongitude());
+ childs[2] = new Node(bounds.getMinLat(), center.getLongitude(),
+ center.getLatitude(), bounds.getMaxLong());
+ childs[3] = new Node(center.getLatitude(), center.getLongitude(),
+ bounds.getMaxLat(), bounds.getMaxLong());
+ for (int i = 0; i < 4; i++){
+ childs[i].depth = (short) (this.depth + 1);
+ }
+ isLeaf = false;
+ }
+
+ /**
+ * Split the tree into 4 equally sized parts and
+ * distribute the data.
+ */
+ private void split(String treePath){
+ if (isLeaf == true){
+ if (nodes == null)
+ return;
+ if (DEBUG){
+ String fname = "gpx/" + treePath+ "/bbox"+treePath;
+ List<List<Coord>> polys = Java2DConverter.areaToShapes(Java2DConverter.createBoundsArea(bounds));
+ GpxCreator.createGpx(fname, polys.get(0));
+ }
+ // subject to tuning
+ if (depth >= 5 || nodes.size() <= 7 || bounds.getHeight() < 10 || bounds.getWidth() < 10 ){
+ makeDistinct(treePath);
+ return ;
+ }
+
+ mergeLastRectangles();
+ allocChilds();
+ for (int i = 0; i < 4; i++){
+ for (NodeElem nodeElem: nodes){
+ childs[i].add(nodeElem.area, nodeElem.boundaryId, nodeElem.locationDataSrc);
+ }
+ }
+ // return memory to GC
+ nodes = null;
+ }
+ // finally try splitting the sub trees
+ for (int i = 0; i < 4; i++){
+ childs[i].split(treePath+i);
+ }
+ }
+ }
+
+ private class NodeElem{
+ // the intersections of the boundaries with the bounding box of this node
+ private Area area;
+ // location relevant tags of boundaries that intersect with the bounding box of this node
+ private Tags locTags;
+
+ // a bit mask that helps comparing Tags
+ private short tagMask;
+ // boundary that was initially used
+ private final String boundaryId;
+ // data for the intersects_with tag
+ private String locationDataSrc;
+ private int srcPos;
+
+ /**
+ * Create a node elem.
+ * @param boundaryId The boundary Id
+ * @param area the (part of the) boundary area stored in this node
+ * @param refs A string containing boundaryIds and admin-level infos
+ * of all boundaries with lower admin levels that share the same area.
+ */
+ NodeElem (String boundaryId, Area area, String refs){
+ srcPos = -1;
+ this.boundaryId = boundaryId;
+ this.area = area;
+ this.locationDataSrc = refs;
+ calcLocTags();
+ }
+
+ /**
+ * Create a new node elem as a partly copy of an existing
+ * NodeElem and a new area.
+ * @param other the existing NodeElem instance
+ * @param area the new area
+ * @param srcPos identifies the position of other in the
+ * nodes list of the Node.
+ */
+ NodeElem (NodeElem other, Area area, int srcPos){
+ this.area = area;
+ this.srcPos = srcPos;
+ this.boundaryId = other.boundaryId;
+ this.tagMask = other.tagMask;
+ this.locationDataSrc = other.locationDataSrc;
+ this.locTags = other.locTags.copy();
+ }
+
+ /**
+ * check if a NodeElem contains usable info.
+ * @return false if either the area is not usable or
+ * the tags should be ignored.
+ */
+ private boolean isValid(){
+ if (tagMask == 0 || area == null || area.isEmpty())
+ return false;
+ return true;
+ }
+ /**
+ * Add the location relevant data of another NodeElem
+ * @param toAdd the other NodeElem
+ */
+ private void addLocInfo(NodeElem toAdd){
+ addLocationDataString(toAdd);
+ addMissingTags(toAdd.locTags);
+ tagMask |= toAdd.tagMask;
+ }
+
+ /**
+ * Calculate the tags that are location relevant.
+ * Problem: If the tree is created by BoundaryPreparer, we do not know how to calculate
+ * the name because we don't know which tag to use for this, so be aware that this
+ * may return different results compared to the LocationHook.
+ * @param boundary
+ */
+ private void calcLocTags(){
+ locTags = new Tags();
+ tagMask = 0;
+ BoundaryLocationInfo bInfo = preparedLocationInfo.get(boundaryId);
+ if (bInfo == null){
+ log.error("unknown boundaryId " + boundaryId);
+ return;
+ }
+ if (bInfo.getZip() != null){
+ locTags.put("mkgmap:postcode",bInfo.getZip());
+ }
+
+ if (bInfo.getAdmLevel() != BoundaryLocationPreparer.UNSET_ADMIN_LEVEL){
+ locTags.put(BoundaryQuadTree.mkgmapTagsArray[bInfo.getAdmLevel()-1], bInfo.getName());
+ }
+ if (locationDataSrc != null && locationDataSrc.isEmpty() == false){
+ // the common format of refInfo is
+ // 2:r19884;4:r20039;6:r998818
+ String[] relBounds = locationDataSrc.split(Pattern.quote(";"));
+ for (String relBound : relBounds) {
+ String[] relParts = relBound.split(Pattern.quote(":"));
+ if (relParts.length != 2) {
+ log.error("Wrong format. Value: " + locationDataSrc);
+ continue;
+ }
+ BoundaryLocationInfo addInfo = preparedLocationInfo.get(relParts[1]);
+ if (addInfo == null) {
+ log.warn("Referenced boundary not known:", relParts[1]);
+ continue;
+ }
+
+ int addAdmLevel = addInfo.getAdmLevel();
+ String addAdmName = null;
+ if (addAdmLevel != BoundaryLocationPreparer.UNSET_ADMIN_LEVEL){
+ addAdmName = addInfo.getName();
+ }
+ String addZip = addInfo.getZip();
+
+ if (addAdmName != null){
+ if (locTags.get(BoundaryQuadTree.mkgmapTagsArray[addAdmLevel-1]) == null)
+ locTags.put(BoundaryQuadTree.mkgmapTagsArray[addAdmLevel-1], addAdmName);
+ }
+ if (addZip != null){
+ if (locTags.get("mkgmap:postcode") == null)
+ locTags.put("mkgmap:postcode", addZip);
+ }
+ }
+ }
+ tagMask = calcLocationTagsMask();
+ }
+
+ /**
+ * Merge the locationDataSrc of two NodeElems.
+ * The caller has to make sure that the merge makes sense.
+ * @param toAdd The other NodeElem
+ */
+ private void addLocationDataString (NodeElem toAdd){
+ BoundaryLocationInfo info = preparedLocationInfo.get(toAdd.boundaryId);
+ assert info.getAdmLevel() > 0 : "cannot use admLevel";
+
+ String admLevel = info.getAdmLevel() + ":" + toAdd.boundaryId;
+ if (this.locationDataSrc == null)
+ this.locationDataSrc = admLevel;
+ else
+ this.locationDataSrc += ";" + admLevel;
+ if (toAdd.locationDataSrc != null){
+ this.locationDataSrc += ";" + toAdd.locationDataSrc;
+ }
+ }
+ /**
+ * Write a nodeElem an AREA segment of the QUADTREE_DATA_FORMAT.
+ * @param stream the already opened OutputStream
+ * @param treePath identifies the position within the tree
+ * @throws IOException
+ */
+ private void save(OutputStream stream, String treePath) throws IOException{
+ ByteArrayOutputStream oneItemStream = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(oneItemStream);
+ String id = this.boundaryId;
+ dos.writeUTF(treePath.substring(1));
+ dos.writeUTF(id);
+ if (this.locationDataSrc == null)
+ dos.writeUTF("");
+ else
+ dos.writeUTF(this.locationDataSrc);
+ BoundarySaver.writeArea(dos, this.area);
+ dos.close();
+
+ // now start to write into the real stream
+
+ // first write the bounding box so that is possible to skip the
+ // complete entry
+ uk.me.parabola.imgfmt.app.Area bbox = Java2DConverter.createBbox(this.area);
+ DataOutputStream dOutStream = new DataOutputStream(stream);
+ dOutStream.writeUTF("AREA");
+ dOutStream.writeInt(bbox.getMinLat());
+ dOutStream.writeInt(bbox.getMinLong());
+ dOutStream.writeInt(bbox.getMaxLat());
+ dOutStream.writeInt(bbox.getMaxLong());
+
+ // write the size of the boundary block so that it is possible to
+ // skip it
+ byte[] data = oneItemStream.toByteArray();
+ assert data.length > 0 : "bSize is not > 0 : " + data.length;
+ dOutStream.writeInt(data.length);
+
+ // write the boundary block
+ dOutStream.write(data);
+ dOutStream.flush();
+ }
+
+ /**
+ * calculate a handy short value that represents the available location tags
+ * @return a bit mask, a bit with value 1 means the corresponding entry in {@link locationTagNames }
+ * is available
+ */
+ private short calcLocationTagsMask(){
+ short res = 0;
+ for (int i = 0; i < mkgmapTagsArray.length; i++){
+ if (locTags.get(mkgmapTagsArray[i] ) != null)
+ res |= (1 << i);
+ }
+ return res;
+ }
+
+ /**
+ * For debugging: Save the area in gpx format
+ * @param desc used as directory name
+ * @param treePath
+ */
+ private void saveGPX(String desc, String treePath){
+ if (DEBUG){
+ if (area == null)
+ return;
+ List<List<Coord>> singlePolys = Java2DConverter.areaToShapes(area);
+ Collections.reverse(singlePolys);
+
+ int cntPoly = 0;
+ for (List<Coord> polyPart : singlePolys) {
+ String attr = Way.clockwise(polyPart) ? "o" : "i";
+ String fname = "gpx/" + treePath+ "/" + desc + "_" + area.getBounds().x + "_" + area.getBounds().y + "_" + boundaryId+ "_" + cntPoly + "_"+attr;
+ GpxCreator.createGpx(fname, polyPart);
+ ++cntPoly;
+ }
+
+ }
+ }
+
+
+ /**
+ * Handle errors in OSM data. Two boundaries with equal levels should not intersect.
+ * Special case: zip-code-only boundaries with same zip code
+ * @param other the other NodeElem
+ * @param bounds a bounding box for the intersection of the two areas. Used
+ * to create the error message.
+ * @return null if no error, else a String with an error message
+ */
+ private String checkAddTags(NodeElem other, uk.me.parabola.imgfmt.app.Area bounds){
+ String errMsg = null;
+ int errAdmLevel = 0;
+ // case c) toAdd area is fully covered by currElem area
+ for (int k = 0; k < mkgmapTagsArray.length; k++){
+ int testMask = 1 << k;
+ if ((testMask & other.tagMask) != 0 && (this.tagMask & testMask) != 0){
+ if (testMask == POSTCODE_ONLY){
+ String zipKey = mkgmapTagsArray[k];
+ if (other.locTags.get(zipKey).equals(this.locTags.get(zipKey)) == false){
+ errMsg = "different " + zipKey;
+ break;
+ }
+ }
+ else{
+ errAdmLevel = k+1;
+ errMsg = new String ("same admin_level (" + errAdmLevel + ")");
+ break;
+ }
+ }
+ }
+ if (errMsg != null){
+ String url = bounds.getCenter().toOSMURL() + "&";
+ url += (other.boundaryId.startsWith("w")) ? "way" : "relation";
+ url += "=" + other.boundaryId.substring(1);
+ //http://www.openstreetmap.org/?lat=49.394988&lon=6.551425&zoom=18&layers=M&relation=122907
+ errMsg= "incorrect data: " + url + " intersection of boundaries with " + errMsg + " " + other.boundaryId + " " + this.boundaryId + " " ;
+ if (errAdmLevel != 0 && this.locationDataSrc != null)
+ errMsg += this.locationDataSrc;
+ }
+
+ return errMsg;
+ }
+
+ /**
+ * Add tags from src to locTags if they are missing
+ * @param src the Tags to be added
+ */
+ private void addMissingTags(Tags src){
+ Iterator<Entry<String,String>> tagIter = src.entryIterator();
+ while (tagIter.hasNext()) {
+ Entry<String,String> tag = tagIter.next();
+ if (locTags.get(tag.getKey()) == null){
+ locTags.put(tag.getKey(),tag.getValue());
+ }
+ }
+ }
+ }
+
+ /***
+ * Used to sort BoundaryLocationInfo. Input are boundaryIds.
+ * @author gerd
+ *
+ */
+ public class AdminLevelCollator implements Comparator<String> {
+
+ public int compare(String o1, String o2) {
+ if (o1.equals(o2)) {
+ return 0;
+ }
+
+ BoundaryLocationInfo i1 = preparedLocationInfo.get(o1);
+ BoundaryLocationInfo i2 = preparedLocationInfo.get(o2);
+
+ int adminLevel1 = i1.getAdmLevel();
+ int adminLevel2 = i2.getAdmLevel();
+
+ if (i1.getName() == null || i1.getName() == "?") {
+ // admin_level tag is set but no valid name available
+ adminLevel1= BoundaryLocationPreparer.UNSET_ADMIN_LEVEL;
+ }
+ if (i2.getName() == null || i2.getName() == "?") {
+ // admin_level tag is set but no valid name available
+ adminLevel2= BoundaryLocationPreparer.UNSET_ADMIN_LEVEL;
+ }
+
+ if (adminLevel1 > adminLevel2)
+ return 1;
+ if (adminLevel1 < adminLevel2)
+ return -1;
+
+ if (i1.getAdmLevel() == 2){
+ // prefer countries that are known by the Locator
+ if (i1.isISOName() == true && i2.isISOName() == false)
+ return 1;
+ if (i1.isISOName() == false && i2.isISOName() == true)
+ return -1;
+ }
+ boolean post1set = i1.getZip() != null;
+ boolean post2set = i2.getZip() != null;
+ if (post1set && !post2set)
+ return 1;
+ if (!post1set && post2set)
+ return -1;
+ // if all is equal, prefer the lower boundaryId
+ return o1.compareTo(o2);
+ }
+ }
+
+ /**
+ * test if the conversion to a Path2D and back gives an empty area. If the
+ * area is not already empty this routine simulates the writing and reading
+ * and tests if the result is empty. Returns true is the area is not empty.
+ */
+ public static boolean isWritable(Area area){
+ if (area.isEmpty())
+ return false;
+ Path2D.Double path = new Path2D.Double(area);
+ Area testArea = new Area(path);
+ if (testArea.isEmpty()){
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryRelation.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryRelation.java
new file mode 100644
index 0000000..1b2bf08
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryRelation.java
@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 2006, 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.reader.osm.boundary;
+
+import java.awt.geom.Line2D;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Queue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.reader.osm.MultiPolygonRelation;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.Java2DConverter;
+
+
+public class BoundaryRelation extends MultiPolygonRelation {
+ private static final Logger log = Logger
+ .getLogger(BoundaryRelation.class);
+
+ private java.awt.geom.Area outerResultArea;
+
+ /** keeps the result of the multipolygon processing */
+ private Boundary boundary;
+
+ public BoundaryRelation(Relation other, Map<Long, Way> wayMap, Area bbox) {
+ super(other, wayMap, bbox);
+ }
+
+ public Boundary getBoundary() {
+ if (boundary == null) {
+ if (outerResultArea == null) {
+ return null;
+ }
+ boundary = new Boundary(outerResultArea, this.getEntryIteratable(),"r"+this.getId());
+ outerResultArea = null;
+ }
+ return boundary;
+ }
+
+ /**
+ * Process the ways in this relation. Joins way with the role "outer" Adds
+ * ways with the role "inner" to the way with the role "outer"
+ */
+ public void processElements() {
+ log.info("Processing multipolygon", toBrowseURL());
+
+ List<Way> allWays = getSourceWays();
+
+// // check if the multipolygon itself or the non inner member ways have a tag
+// // if not it does not make sense to process it and we could save the time
+// boolean shouldProcess = hasStyleRelevantTags(this);
+// if (shouldProcess == false) {
+// for (Way w : allWays) {
+// shouldProcess = hasStyleRelevantTags(w);
+// if (shouldProcess) {
+// break;
+// }
+// }
+// }
+// if (shouldProcess==false) {
+// log.info("Do not process multipolygon",getId(),"because it has no style relevant tags.");
+// return;
+// }
+
+
+ // create an Area for the bbox to clip the polygons
+ bboxArea = Java2DConverter.createBoundsArea(getBbox());
+
+ // join all single ways to polygons, try to close ways and remove non closed ways
+ polygons = joinWays(allWays);
+
+ outerWaysForLineTagging = new HashSet<Way>();
+ outerTags = new HashMap<String,String>();
+
+ removeOutOfBbox(polygons);
+
+ boolean changed = true;
+ while (changed) {
+ changed = false;
+ while (connectUnclosedWays(polygons)) {
+ changed = true;
+ }
+ closeWays(polygons);
+ }
+
+ removeUnclosedWays(polygons);
+
+ // now only closed ways are left => polygons only
+
+ // check if we have at least one polygon left
+ if (polygons.isEmpty()) {
+ // do nothing
+ log.info("Multipolygon " + toBrowseURL()
+ + " does not contain a closed polygon.");
+ tagOuterWays();
+ cleanup();
+ return;
+ }
+
+ removeWaysOutsideBbox(polygons);
+
+ if (polygons.isEmpty()) {
+ // do nothing
+ log.info("Multipolygon " + toBrowseURL()
+ + " is completely outside the bounding box. It is not processed.");
+ tagOuterWays();
+ cleanup();
+ return;
+ }
+
+ // the intersectingPolygons marks all intersecting/overlapping polygons
+ intersectingPolygons = new HashSet<JoinedWay>();
+
+ // check which polygons lie inside which other polygon
+ createContainsMatrix(polygons);
+
+ // unfinishedPolygons marks which polygons are not yet processed
+ unfinishedPolygons = new BitSet(polygons.size());
+ unfinishedPolygons.set(0, polygons.size());
+
+ // create bitsets which polygons belong to the outer and to the inner role
+ innerPolygons = new BitSet();
+ taggedInnerPolygons = new BitSet();
+ outerPolygons = new BitSet();
+ taggedOuterPolygons = new BitSet();
+
+ int wi = 0;
+ for (Way w : polygons) {
+ String role = getRole(w);
+ if ("inner".equals(role)) {
+ innerPolygons.set(wi);
+ taggedInnerPolygons.set(wi);
+ } else if ("outer".equals(role)) {
+ outerPolygons.set(wi);
+ taggedOuterPolygons.set(wi);
+ } else {
+ // unknown role => it could be both
+ innerPolygons.set(wi);
+ outerPolygons.set(wi);
+ }
+ wi++;
+ }
+
+ if (outerPolygons.isEmpty()) {
+ log.warn("Multipolygon", toBrowseURL(),
+ "does not contain any way tagged with role=outer or empty role.");
+ cleanup();
+ return;
+ }
+
+ Queue<PolygonStatus> polygonWorkingQueue = new LinkedBlockingQueue<PolygonStatus>();
+ BitSet nestedOuterPolygons = new BitSet();
+ BitSet nestedInnerPolygons = new BitSet();
+
+ BitSet outmostPolygons ;
+ BitSet outmostInnerPolygons = new BitSet();
+ boolean outmostInnerFound;
+ do {
+ outmostInnerFound = false;
+ outmostPolygons = findOutmostPolygons(unfinishedPolygons);
+
+ if (outmostPolygons.intersects(taggedInnerPolygons)) {
+ outmostInnerPolygons.or(outmostPolygons);
+ outmostInnerPolygons.and(taggedInnerPolygons);
+
+ if (log.isDebugEnabled())
+ log.debug("wrong inner polygons: " + outmostInnerPolygons);
+ // do not process polygons tagged with role=inner but which are
+ // not contained by any other polygon
+ unfinishedPolygons.andNot(outmostInnerPolygons);
+ outmostPolygons.andNot(outmostInnerPolygons);
+ outmostInnerFound = true;
+ }
+ } while (outmostInnerFound);
+
+ if (!outmostPolygons.isEmpty()) {
+ polygonWorkingQueue.addAll(getPolygonStatus(outmostPolygons, "outer"));
+ }
+
+ boolean outmostPolygonProcessing = true;
+
+
+ outerResultArea = new java.awt.geom.Area();
+
+ while (!polygonWorkingQueue.isEmpty()) {
+
+ // the polygon is not contained by any other unfinished polygon
+ PolygonStatus currentPolygon = polygonWorkingQueue.poll();
+
+ // this polygon is now processed and should not be used by any
+ // further step
+ unfinishedPolygons.clear(currentPolygon.index);
+
+ BitSet polygonContains = new BitSet();
+ polygonContains.or(containsMatrix.get(currentPolygon.index));
+ // use only polygon that are contained by the polygon
+ polygonContains.and(unfinishedPolygons);
+ // polygonContains is the intersection of the unfinished and
+ // the contained polygons
+
+ // get the holes
+ // these are all polygons that are in the main polygon
+ // and that are not contained by any other polygon
+ boolean holesOk;
+ BitSet holeIndexes;
+ do {
+ holeIndexes = findOutmostPolygons(polygonContains);
+ holesOk = true;
+
+ if (currentPolygon.outer) {
+ // for role=outer only role=inner is allowed
+ if (holeIndexes.intersects(taggedOuterPolygons)) {
+ BitSet addOuterNestedPolygons = new BitSet();
+ addOuterNestedPolygons.or(holeIndexes);
+ addOuterNestedPolygons.and(taggedOuterPolygons);
+ nestedOuterPolygons.or(addOuterNestedPolygons);
+ holeIndexes.andNot(addOuterNestedPolygons);
+ // do not process them
+ unfinishedPolygons.andNot(addOuterNestedPolygons);
+ polygonContains.andNot(addOuterNestedPolygons);
+
+ // recalculate the holes again to get all inner polygons
+ // in the nested outer polygons
+ holesOk = false;
+ }
+ } else {
+ // for role=inner both role=inner and role=outer is supported
+ // although inner in inner is not officially allowed
+ if (holeIndexes.intersects(taggedInnerPolygons)) {
+ // process inner in inner but issue a warning later
+ BitSet addInnerNestedPolygons = new BitSet();
+ addInnerNestedPolygons.or(holeIndexes);
+ addInnerNestedPolygons.and(taggedInnerPolygons);
+ nestedInnerPolygons.or(addInnerNestedPolygons);
+ }
+ }
+ } while (!holesOk);
+
+ ArrayList<PolygonStatus> holes = getPolygonStatus(holeIndexes,
+ (currentPolygon.outer ? "inner" : "outer"));
+
+ // these polygons must all be checked for holes
+ polygonWorkingQueue.addAll(holes);
+
+ if (currentPolygon.outer) {
+ // add the original ways to the list of ways that get the line tags of the mp
+ // the joined ways may be changed by the auto closing algorithm
+ outerWaysForLineTagging.addAll(currentPolygon.polygon.getOriginalWays());
+ }
+
+ if (currentPolygon.outer) {
+ java.awt.geom.Area toAdd = Java2DConverter.createArea(currentPolygon.polygon.getPoints());
+ if (outerResultArea.isEmpty())
+ outerResultArea = toAdd;
+ else
+ outerResultArea.add(toAdd);
+
+ for (Way outerWay : currentPolygon.polygon.getOriginalWays()) {
+ if (outmostPolygonProcessing) {
+ for (Entry<String, String> tag : outerWay.getEntryIteratable()) {
+ outerTags.put(tag.getKey(), tag.getValue());
+ }
+ outmostPolygonProcessing = false;
+ } else {
+ for (String tag : new ArrayList<String>(outerTags.keySet())) {
+ if (outerTags.get(tag).equals(outerWay.getTag(tag)) == false) {
+ outerTags.remove(tag);
+ }
+ }
+ }
+ }
+ } else {
+ outerResultArea.subtract(Java2DConverter
+ .createArea(currentPolygon.polygon.getPoints()));
+ }
+ }
+
+ // TODO tagging of the outer ways
+
+// if (log.isLoggable(Level.WARNING) &&
+// (outmostInnerPolygons.cardinality()+unfinishedPolygons.cardinality()+nestedOuterPolygons.cardinality()+nestedInnerPolygons.cardinality() >= 1)) {
+// log.warn("Multipolygon", toBrowseURL(), "contains errors.");
+//
+// BitSet outerUnusedPolys = new BitSet();
+// outerUnusedPolys.or(unfinishedPolygons);
+// outerUnusedPolys.or(outmostInnerPolygons);
+// outerUnusedPolys.or(nestedOuterPolygons);
+// outerUnusedPolys.or(nestedInnerPolygons);
+// outerUnusedPolys.or(unfinishedPolygons);
+// // use only the outer polygons
+// outerUnusedPolys.and(outerPolygons);
+// for (JoinedWay w : getWaysFromPolygonList(outerUnusedPolys)) {
+// outerWaysForLineTagging.addAll(w.getOriginalWays());
+// }
+//
+// runIntersectionCheck(unfinishedPolygons);
+// runOutmostInnerPolygonCheck(outmostInnerPolygons);
+// runNestedOuterPolygonCheck(nestedOuterPolygons);
+// runNestedInnerPolygonCheck(nestedInnerPolygons);
+// runWrongInnerPolygonCheck(unfinishedPolygons, innerPolygons);
+//
+// // we have at least one polygon that could not be processed
+// // Probably we have intersecting or overlapping polygons
+// // one possible reason is if the relation overlaps the tile
+// // bounds
+// // => issue a warning
+// List<JoinedWay> lostWays = getWaysFromPolygonList(unfinishedPolygons);
+// for (JoinedWay w : lostWays) {
+// log.warn("Polygon", w, "is not processed due to an unknown reason.");
+// logWayURLs(Level.WARNING, "-", w);
+// }
+// }
+//
+
+
+ if (hasStyleRelevantTags(this)) {
+ outerTags.clear();
+ for (Entry<String,String> mpTags : getEntryIteratable()) {
+ if ("type".equals(mpTags.getKey())==false) {
+ outerTags.put(mpTags.getKey(), mpTags.getValue());
+ }
+ }
+ } else {
+ for (Entry<String,String> mpTags : outerTags.entrySet()) {
+ addTag(mpTags.getKey(), mpTags.getValue());
+ }
+ }
+
+ // Go through all original outer ways, create a copy, tag them
+ // with the mp tags and mark them only to be used for polyline processing
+ // This enables the style file to decide if the polygon information or
+ // the simple line information should be used.
+ for (Way orgOuterWay : outerWaysForLineTagging) {
+// Way lineTagWay = new Way(FakeIdGenerator.makeFakeId(), orgOuterWay.getPoints());
+// lineTagWay.setName(orgOuterWay.getName());
+// lineTagWay.addTag(STYLE_FILTER_TAG, STYLE_FILTER_LINE);
+ for (Entry<String,String> tag : outerTags.entrySet()) {
+// lineTagWay.addTag(tag.getKey(), tag.getValue());
+
+ // remove the tag from the original way if it has the same value
+ if (tag.getValue().equals(orgOuterWay.getTag(tag.getKey()))) {
+ removeTagsInOrgWays(orgOuterWay, tag.getKey());
+ }
+ }
+
+// if (log.isDebugEnabled())
+// log.debug("Add line way", lineTagWay.getId(), lineTagWay.toTagString());
+// tileWayMap.put(lineTagWay.getId(), lineTagWay);
+ }
+
+ postProcessing();
+ cleanup();
+ }
+ protected boolean connectUnclosedWays(List<JoinedWay> allWays) {
+ List<JoinedWay> unclosed = new ArrayList<JoinedWay>();
+
+ for (JoinedWay w : allWays) {
+ if (w.isClosed() == false) {
+ unclosed.add(w);
+ }
+ }
+ // try to connect ways lying outside or on the bbox
+ if (unclosed.size() >= 2) {
+ log.debug("Checking",unclosed.size(),"unclosed ways for connections outside the bbox");
+ Map<Coord, JoinedWay> outOfBboxPoints = new HashMap<Coord, JoinedWay>();
+
+ // check all ways for endpoints outside or on the bbox
+ for (JoinedWay w : unclosed) {
+ Coord c1 = w.getPoints().get(0);
+// if (bbox.insideBoundary(c1)==false) {
+// log.debug("Point",c1,"of way",w.getId(),"outside bbox");
+ outOfBboxPoints.put(c1, w);
+// }
+
+ Coord c2 = w.getPoints().get(w.getPoints().size()-1);
+// if (bbox.insideBoundary(c2)==false) {
+// log.debug("Point",c2,"of way",w.getId(),"outside bbox");
+ outOfBboxPoints.put(c2, w);
+// }
+ }
+
+ if (outOfBboxPoints.size() < 2) {
+ log.debug(outOfBboxPoints.size(),"point outside the bbox. No connection possible.");
+ return false;
+ }
+
+ List<ConnectionData> coordPairs = new ArrayList<ConnectionData>();
+ ArrayList<Coord> coords = new ArrayList<Coord>(outOfBboxPoints.keySet());
+ for (int i = 0; i < coords.size(); i++) {
+ for (int j = i + 1; j < coords.size(); j++) {
+ ConnectionData cd = new ConnectionData();
+ cd.c1 = coords.get(i);
+ cd.c2 = coords.get(j);
+ cd.w1 = outOfBboxPoints.get(cd.c1);
+ cd.w2 = outOfBboxPoints.get(cd.c2);
+
+// if (lineCutsBbox(cd.c1, cd.c2 )) {
+// // Check if the way can be closed with one additional point
+// // outside the bounding box.
+// // The additional point is combination of the coords of both endpoints.
+// // It works if the lines from the endpoints to the additional point does
+// // not cut the bounding box.
+// // This can be removed when the splitter guarantees to provide logical complete
+// // multi-polygons.
+// Coord edgePoint1 = new Coord(cd.c1.getLatitude(), cd.c2
+// .getLongitude());
+// Coord edgePoint2 = new Coord(cd.c2.getLatitude(), cd.c1
+// .getLongitude());
+//
+// if (lineCutsBbox(cd.c1, edgePoint1) == false
+// && lineCutsBbox(edgePoint1, cd.c2) == false) {
+// cd.imC = edgePoint1;
+// } else if (lineCutsBbox(cd.c1, edgePoint2) == false
+// && lineCutsBbox(edgePoint2, cd.c2) == false) {
+// cd.imC = edgePoint1;
+// } else {
+// // both endpoints are on opposite sides of the bounding box
+// // automatically closing such points would create wrong polygons in most cases
+// continue;
+// }
+// cd.distance = cd.c1.distance(cd.imC) + cd.imC.distance(cd.c2);
+// } else {
+ cd.distance = cd.c1.distance(cd.c2);
+// }
+ coordPairs.add(cd);
+ }
+ }
+
+ if (coordPairs.isEmpty()) {
+ log.debug("All potential connections cross the bbox. No connection possible.");
+ return false;
+ } else {
+ // retrieve the connection with the minimum distance
+ ConnectionData minCon = Collections.min(coordPairs,
+ new Comparator<ConnectionData>() {
+ public int compare(ConnectionData o1,
+ ConnectionData o2) {
+ return Double.compare(o1.distance, o2.distance);
+ }
+ });
+
+ if (minCon.distance < getMaxCloseDist()) {
+
+ if (minCon.w1 == minCon.w2) {
+ log.debug("Close a gap in way", minCon.w1);
+ if (minCon.imC != null)
+ minCon.w1.getPoints().add(minCon.imC);
+ minCon.w1.closeWayArtificially();
+ } else {
+ log.debug("Connect", minCon.w1, "with", minCon.w2);
+
+ if (minCon.w1.getPoints().get(0).equals(minCon.c1)) {
+ Collections.reverse(minCon.w1.getPoints());
+ }
+ if (minCon.w2.getPoints().get(0).equals(minCon.c2) == false) {
+ Collections.reverse(minCon.w2.getPoints());
+ }
+
+ minCon.w1.getPoints().addAll(minCon.w2.getPoints());
+ minCon.w1.addWay(minCon.w2);
+ allWays.remove(minCon.w2);
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private double getMaxCloseDist() {
+ double dist = 1000;
+ String admString= getTag("admin_level");
+
+ if ("2".equals(admString)) {
+ dist = 50000;
+ } else if ("3".equals(admString)) {
+ dist = 20000;
+ }else if ("4".equals(admString)) {
+ dist = 4000;
+ }
+ return dist;
+ }
+
+ protected void closeWays(ArrayList<JoinedWay> wayList) {
+ for (JoinedWay way : wayList) {
+ if (way.isClosed() || way.getPoints().size() < 3) {
+ continue;
+ }
+ Coord p1 = way.getPoints().get(0);
+ Coord p2 = way.getPoints().get(way.getPoints().size() - 1);
+
+ if (getBbox().insideBoundary(p1) == false
+ && getBbox().insideBoundary(p2) == false) {
+ // both points lie outside the bbox or on the bbox
+
+ // check if both points are on the same side of the bounding box
+ if ((p1.getLatitude() <= getBbox().getMinLat() && p2.getLatitude() <= getBbox()
+ .getMinLat())
+ || (p1.getLatitude() >= getBbox().getMaxLat() && p2
+ .getLatitude() >= getBbox().getMaxLat())
+ || (p1.getLongitude() <= getBbox().getMinLong() && p2
+ .getLongitude() <= getBbox().getMinLong())
+ || (p1.getLongitude() >= getBbox().getMaxLong() && p2
+ .getLongitude() >= getBbox().getMaxLong())) {
+ // they are on the same side outside of the bbox
+ // so just close them without worrying about if
+ // they intersect itself because the intersection also
+ // is outside the bbox
+ way.closeWayArtificially();
+ log.info("Endpoints of way", way,
+ "are both outside the bbox. Closing it directly.");
+ continue;
+ }
+ }
+
+ Line2D closingLine = new Line2D.Float(p1.getLongitude(), p1
+ .getLatitude(), p2.getLongitude(), p2.getLatitude());
+
+ boolean intersects = false;
+ Coord lastPoint = null;
+ // don't use the first and the last point
+ // the closing line can intersect only in one point or complete.
+ // Both isn't interesting for this check
+ for (Coord thisPoint : way.getPoints().subList(1,
+ way.getPoints().size() - 1)) {
+ if (lastPoint != null) {
+ if (closingLine.intersectsLine(lastPoint.getLongitude(),
+ lastPoint.getLatitude(), thisPoint.getLongitude(),
+ thisPoint.getLatitude())) {
+ intersects = true;
+ break;
+ }
+ }
+ lastPoint = thisPoint;
+ }
+
+ if (!intersects) {
+ // close the polygon
+ // the new way segment does not intersect the rest of the
+ // polygon
+
+ // calc the distance to close
+ double closeDist = way.getPoints().get(0).distance(way.getPoints().get(way.getPoints().size()-1));
+
+ if (closeDist <= getMaxCloseDist()) {
+ log.info("Closing way", way);
+ log.info("from", way.getPoints().get(0).toOSMURL());
+ log.info("to", way.getPoints().get(way.getPoints().size() - 1)
+ .toOSMURL());
+ // mark this ways as artificially closed
+ way.closeWayArtificially();
+ }
+ }
+ }
+ }
+
+ private void removeOutOfBbox(List<JoinedWay> polygons) {
+ ListIterator<JoinedWay> pIter = polygons.listIterator();
+ while (pIter.hasNext()) {
+ JoinedWay w = pIter.next();
+ if (w.isClosed() == false) {
+ // the way is not closed
+ // check if one of start/endpoint is out of the bounding box
+ // in this case it is too risky to close it
+ if (getBbox().contains(w.getPoints().get(0)) == false
+ || getBbox().contains(
+ w.getPoints().get(w.getPoints().size() - 1)) == false) {
+ pIter.remove();
+ }
+ }
+ }
+
+ }
+
+ protected void cleanup() {
+ super.cleanup();
+ this.getElements().clear();
+ ((ArrayList<?>)this.getElements()).trimToSize();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundarySaver.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundarySaver.java
new file mode 100644
index 0000000..265be81
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundarySaver.java
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 2006, 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.reader.osm.boundary;
+
+import java.awt.Rectangle;
+import java.awt.geom.Area;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Rectangle2D;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
+
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.Version;
+import uk.me.parabola.util.Java2DConverter;
+
+public class BoundarySaver {
+ private static final Logger log = Logger.getLogger(BoundarySaver.class);
+
+ public static final String LEGACY_DATA_FORMAT = ""; // legacy code just wrote the svn release or "svn"
+ public static final String RAW_DATA_FORMAT = "RAW";
+ public static final String QUADTREE_DATA_FORMAT = "QUADTREE";
+ public static final int CURRENT_RECORD_ID = 1;
+
+ public static final double RESET_DELTA = Double.POSITIVE_INFINITY;
+
+ private final File boundaryDir;
+ private final String dataFormat;
+ private uk.me.parabola.imgfmt.app.Area bbox;
+ private final HashSet<String> writtenFileNames;
+
+ private int minLat = Integer.MAX_VALUE;
+ private int minLong = Integer.MAX_VALUE;
+ private int maxLat = Integer.MIN_VALUE;
+ private int maxLong = Integer.MIN_VALUE;
+
+ private static final class StreamInfo {
+ File file;
+ String boundsKey;
+ OutputStream stream;
+ int lastAccessNo;
+
+ public StreamInfo() {
+ this.lastAccessNo = 0;
+ }
+
+ public boolean isOpen() {
+ return stream != null;
+ }
+
+ public void close() {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException exp) {
+ log.error(exp);
+ }
+ }
+ stream = null;
+ }
+ }
+
+ private int lastAccessNo = 0;
+ private final List<StreamInfo> openStreams = new ArrayList<StreamInfo>();
+ /** keeps the open streams */
+ private final Map<String, StreamInfo> streams;
+ private boolean createEmptyFiles = false;
+
+ public BoundarySaver(File boundaryDir, String mode) {
+ this.boundaryDir = boundaryDir;
+ if (boundaryDir.exists() && boundaryDir.isDirectory() == false){
+ log.error("output target exists and is not a directory");
+ System.exit(-1);
+ }
+ this.dataFormat = mode;
+ this.streams = new HashMap<String, StreamInfo>();
+ this.writtenFileNames = new HashSet<String>();
+ }
+
+ /**
+ * Saves the given BoundaryQuadTree to a stream
+ * @param bqt the BoundaryQuadTree
+ * @param boundsFileName the file name
+ */
+ public void saveQuadTree(BoundaryQuadTree bqt, String boundsFileName) {
+ String[] parts = boundsFileName.split("[_" + Pattern.quote(".") + "]");
+ String key = boundsFileName;
+ if (parts.length >= 3) {
+ key = parts[1] + "_" + parts[2];
+ }
+
+ try {
+ StreamInfo streamInfo = getStream(key);
+ if (streamInfo != null && streamInfo.isOpen()) {
+ bqt.save(streamInfo.stream);
+ writtenFileNames.add(boundsFileName);
+ }
+ } catch (Exception exp) {
+ log.error("Cannot write boundary: " + exp, exp);
+ }
+
+ tidyStreams();
+
+ }
+
+ public void addBoundary(Boundary boundary) {
+ Map<String, Area> splitBounds = splitArea(boundary.getArea());
+ for (Entry<String, Area> split : splitBounds.entrySet()) {
+ saveToFile(split.getKey(),
+ new Boundary(split.getValue(), boundary.getTags(), boundary
+ .getId()));
+ }
+ }
+
+ public HashSet<String> end() {
+ if (isCreateEmptyFiles() && getBbox() != null) {
+ // a bounding box is set => fill the gaps with empty files
+ for (int latSplit = BoundaryUtil.getSplitBegin(getBbox()
+ .getMinLat()); latSplit <= BoundaryUtil
+ .getSplitBegin(getBbox().getMaxLat()); latSplit += BoundaryUtil.RASTER) {
+ for (int lonSplit = BoundaryUtil.getSplitBegin(getBbox()
+ .getMinLong()); lonSplit <= BoundaryUtil
+ .getSplitBegin(getBbox().getMaxLong()); lonSplit += BoundaryUtil.RASTER) {
+ String key = BoundaryUtil.getKey(latSplit, lonSplit);
+
+ // check if the stream already exist but do no open it
+ StreamInfo stream = getStream(key, false);
+ if (stream == null) {
+ // it does not exist => create a new one to write out
+ // the common header of the boundary file
+ stream = getStream(key);
+ }
+
+ // close the stream if it is open
+ if (stream.isOpen())
+ stream.close();
+ streams.remove(key);
+ }
+ }
+ }
+
+ // close the rest of the streams
+ for (StreamInfo streamInfo : streams.values()) {
+ streamInfo.close();
+ }
+ streams.clear();
+ openStreams.clear();
+ return writtenFileNames;
+ }
+
+ private void tidyStreams() {
+ if (openStreams.size() < 100) {
+ return;
+ }
+
+ Collections.sort(openStreams, new Comparator<StreamInfo>() {
+
+ public int compare(StreamInfo o1, StreamInfo o2) {
+ return o1.lastAccessNo - o2.lastAccessNo;
+ }
+ });
+
+ log.debug(openStreams.size(), "open streams.");
+ List<StreamInfo> closingStreams = openStreams.subList(0,
+ openStreams.size() - 80);
+ // close and remove the streams from the open list
+ for (StreamInfo streamInfo : closingStreams) {
+ log.debug("Closing", streamInfo.file);
+ streamInfo.close();
+ }
+ closingStreams.clear();
+ log.debug("Remaining", openStreams.size(), "open streams.");
+ }
+
+ private Map<String, Area> splitArea(Area areaToSplit) {
+ return splitArea(areaToSplit, new HashMap<String, Area>());
+ }
+
+ /**
+ * Split a given area into the raster tiles.
+ * @param areaToSplit the area
+ * @param splits a map the splitted tiles are added to
+ * @return the map with the splitted tiles
+ */
+ private Map<String, Area> splitArea(Area areaToSplit, Map<String, Area> splits) {
+ if (areaToSplit.isEmpty())
+ return splits;
+
+ // use high precision bounds with later rounding to avoid some little rounding
+ // errors (49999.99999999 instead of 50000.0)
+ Rectangle2D areaBounds = areaToSplit.getBounds2D();
+ int sMinLong = BoundaryUtil.getSplitBegin((int)Math.round(areaBounds.getMinX()));
+ int sMinLat = BoundaryUtil.getSplitBegin((int)Math.round(areaBounds.getMinY()));
+ int sMaxLong = BoundaryUtil.getSplitEnd((int)Math.round(areaBounds.getMaxX()));
+ int sMaxLat = BoundaryUtil.getSplitEnd((int)Math.round(areaBounds.getMaxY()));
+
+ int dLon = sMaxLong- sMinLong;
+ int dLat = sMaxLat - sMinLat;
+ if (dLon > BoundaryUtil.RASTER || dLat > BoundaryUtil.RASTER) {
+ // split into two halves
+ Area a1;
+ Area a2;
+ if (dLon > dLat) {
+ int midLon = BoundaryUtil.getSplitEnd(sMinLong+dLon/2);
+ a1 = new Area(new Rectangle(sMinLong, sMinLat, midLon-sMinLong, dLat));
+ a2 = new Area(new Rectangle(midLon, sMinLat, sMaxLong-midLon, dLat));
+ } else {
+ int midLat = BoundaryUtil.getSplitEnd(sMinLat+dLat/2);
+ a1 = new Area(new Rectangle(sMinLong, sMinLat, dLon, midLat-sMinLat));
+ a2 = new Area(new Rectangle(sMinLong, midLat, dLon, sMaxLat-midLat));
+ }
+
+ // intersect with the both halves
+ // and split both halves recursively
+
+ a1.intersect(areaToSplit);
+ splitArea(a1, splits);
+ // a1 is no longer needed => GC
+ a1 = null;
+
+ a2.intersect(areaToSplit);
+ splitArea(a2, splits);
+
+ } else {
+ // the area fully fits into one raster tile
+ splits.put(BoundaryUtil.getKey(sMinLat, sMinLong), areaToSplit);
+ }
+ return splits;
+
+ }
+
+ private void openStream(StreamInfo streamInfo, boolean newFile) {
+ if (streamInfo.file.getParentFile().exists() == false
+ && streamInfo.file.getParentFile() != null)
+ streamInfo.file.getParentFile().mkdirs();
+ FileOutputStream fileStream = null;
+ try {
+ fileStream = new FileOutputStream(streamInfo.file, !newFile);
+ streamInfo.stream = new BufferedOutputStream(fileStream);
+ openStreams.add(streamInfo);
+ if (newFile) {
+ writeDefaultInfos(streamInfo.stream);
+
+ String[] keyParts = streamInfo.boundsKey.split(Pattern
+ .quote("_"));
+ int lat = Integer.valueOf(keyParts[0]);
+ int lon = Integer.valueOf(keyParts[1]);
+ if (lat < minLat) {
+ minLat = lat;
+ log.debug("New min Lat:", minLat);
+ }
+ if (lat > maxLat) {
+ maxLat = lat;
+ log.debug("New max Lat:", maxLat);
+ }
+ if (lon < minLong) {
+ minLong = lon;
+ log.debug("New min Lon:", minLong);
+ }
+ if (lon > maxLong) {
+ maxLong = lon;
+ log.debug("New max Long:", maxLong);
+ }
+ }
+
+ } catch (IOException exp) {
+ log.error("Cannot save boundary: " + exp);
+ if (fileStream != null) {
+ try {
+ fileStream.close();
+ } catch (Throwable thr) {
+ }
+ }
+ }
+ }
+
+ private StreamInfo getStream(String filekey) {
+ return getStream(filekey, true);
+ }
+
+ private StreamInfo getStream(String filekey, boolean autoopen) {
+ StreamInfo stream = streams.get(filekey);
+ if (autoopen) {
+ if (stream == null) {
+ log.debug("Create stream for", filekey);
+ stream = new StreamInfo();
+ stream.boundsKey = filekey;
+ stream.file = new File(boundaryDir, "bounds_" + filekey
+ + ".bnd");
+ streams.put(filekey, stream);
+ openStream(stream, true);
+ } else if (stream.isOpen() == false) {
+ openStream(stream, false);
+ }
+ }
+
+ if (stream != null) {
+ stream.lastAccessNo = ++lastAccessNo;
+ }
+ return stream;
+ }
+
+ private void writeDefaultInfos(OutputStream stream) throws IOException {
+ DataOutputStream dos = new DataOutputStream(stream);
+ dos.writeUTF("BND");
+ dos.writeLong(System.currentTimeMillis());
+
+ // write the header part 2
+ // write it first to a byte array to be able to calculate the length of the header
+ ByteArrayOutputStream headerStream = new ByteArrayOutputStream();
+ DataOutputStream headerDataStream = new DataOutputStream(headerStream);
+ headerDataStream.writeUTF(dataFormat);
+ headerDataStream.writeInt(CURRENT_RECORD_ID);
+ headerDataStream.writeUTF(Version.VERSION);
+ headerDataStream.close();
+
+ byte[] header2 = headerStream.toByteArray();
+ // write the length of the header part 2 so that it is possible to add
+ // values in the future
+ dos.writeInt(header2.length);
+ dos.write(header2);
+ dos.flush();
+ }
+
+ private void saveToFile(String filekey, Boundary boundary) {
+ try {
+ StreamInfo streamInfo = getStream(filekey);
+ if (streamInfo != null && streamInfo.isOpen()) {
+ writeRawFormat(streamInfo.stream, boundary);
+ }
+ } catch (Exception exp) {
+ log.error("Cannot write boundary: " + exp, exp);
+ }
+
+ tidyStreams();
+ }
+
+ /**
+ * Write a boundary to a given stream.
+ * @param stream the already opened OutputStream
+ * @param boundary the boundary
+ */
+ private void writeRawFormat(OutputStream stream, Boundary boundary) {
+ ByteArrayOutputStream oneItemStream = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(oneItemStream);
+ if (dataFormat == QUADTREE_DATA_FORMAT) {
+ log.error("wrong format for write, must use BoundaryQuadTree.save() ");
+ System.exit(1);
+ }
+ try {
+ dos.writeUTF(boundary.getId());
+
+ // write the tags
+ int noOfTags = boundary.getTags().size();
+ dos.writeInt(noOfTags);
+
+ Iterator<Entry<String, String>> tagIter = boundary.getTags()
+ .entryIterator();
+ while (tagIter.hasNext()) {
+ Entry<String, String> tag = tagIter.next();
+ dos.writeUTF(tag.getKey());
+ dos.writeUTF(tag.getValue());
+ noOfTags--;
+ }
+ assert noOfTags == 0 : "Remaining tags: " + noOfTags + " size: "
+ + boundary.getTags().size() + " "
+ + boundary.getTags().toString();
+
+ writeArea(dos,boundary.getArea());
+ dos.close();
+
+ // now start to write into the real stream
+
+ // first write the bounding box so that is possible to skip the
+ // complete entry
+ uk.me.parabola.imgfmt.app.Area bbox = Java2DConverter
+ .createBbox(boundary.getArea());
+ DataOutputStream dOutStream = new DataOutputStream(stream);
+ dOutStream.writeInt(bbox.getMinLat());
+ dOutStream.writeInt(bbox.getMinLong());
+ dOutStream.writeInt(bbox.getMaxLat());
+ dOutStream.writeInt(bbox.getMaxLong());
+
+ // write the size of the boundary block so that it is possible to
+ // skip it
+ byte[] data = oneItemStream.toByteArray();
+ assert data.length > 0 : "bSize is not > 0 : " + data.length;
+ dOutStream.writeInt(data.length);
+
+ // write the boundary block
+ dOutStream.write(data);
+ dOutStream.flush();
+
+ } catch (IOException exp) {
+ log.error(exp.toString());
+ }
+
+ }
+
+ /**
+ * Write area to stream with Double precision. The coordinates
+ * are saved as varying length doubles with delta coding.
+ * @param dos the already opened DataOutputStream
+ * @param area the area (can be non-singular)
+ * @throws IOException
+ */
+ public static void writeArea(DataOutputStream dos, Area area) throws IOException{
+ double[] res = new double[6];
+ double[] lastRes = new double[2];
+ List<Integer> pairs = new LinkedList<Integer>();
+ // step 1: count parts
+ PathIterator pit = area.getPathIterator(null);
+ int prevType = -1;
+ int len = 0;
+ while (!pit.isDone()) {
+ int type = pit.currentSegment(res);
+ if (type != PathIterator.SEG_LINETO && prevType == PathIterator.SEG_LINETO){
+ pairs.add(len);
+ len = 0;
+ }
+ if (type == PathIterator.SEG_LINETO)
+ len++;
+ prevType = type;
+ pit.next();
+ }
+
+ // 2nd pass: write the data
+ pit = area.getPathIterator(null);
+ prevType = -1;
+
+ dos.writeInt(pit.getWindingRule());
+ while (!pit.isDone()) {
+ int type = pit.currentSegment(res);
+ if (type != prevType)
+ dos.writeInt(type);
+ switch (type) {
+ case PathIterator.SEG_LINETO:
+ if (prevType != type){
+ len = pairs.remove(0);
+ dos.writeInt(len);
+ }
+ // no break
+ case PathIterator.SEG_MOVETO:
+ len--;
+ for (int i = 0; i < 2; i++){
+ double delta = res[i] - lastRes[i];
+ if (delta + lastRes[i] != res[i]){
+ // handle rounding error in delta processing
+ // write POSITIVE_INFINITY to signal that next value is
+ // not delta coded
+ //System.out.println("reset " + i ) ;
+ writeVarDouble(dos, BoundarySaver.RESET_DELTA);
+ delta = res[i];
+ }
+ lastRes[i] = res[i];
+ writeVarDouble(dos, delta);
+ }
+ break;
+ case PathIterator.SEG_CLOSE:
+ break;
+ default:
+ log.error("Unsupported path iterator type " + type
+ + ". This is an mkgmap error.");
+ }
+
+ prevType = type;
+ pit.next();
+ }
+ if (len != 0){
+ log.error("len not zero " + len);
+ }
+ dos.writeInt(-1); // isDone flag
+ }
+
+ public uk.me.parabola.imgfmt.app.Area getBbox() {
+ if (bbox == null) {
+ bbox = new uk.me.parabola.imgfmt.app.Area(minLat, minLong, maxLat,
+ maxLong);
+ log.error("Calculate bbox to " + bbox);
+ }
+ return bbox;
+ }
+
+ public void setBbox(uk.me.parabola.imgfmt.app.Area bbox) {
+ if (bbox.isEmpty()) {
+ log.warn("Do not use bounding box because it's empty");
+ this.bbox = null;
+ } else {
+ this.bbox = bbox;
+ log.info("Set bbox: " + bbox.getMinLat() + " " + bbox.getMinLong()
+ + " " + bbox.getMaxLat() + " " + bbox.getMaxLong());
+ }
+ }
+
+ public boolean isCreateEmptyFiles() {
+ return createEmptyFiles;
+ }
+
+ /**
+ * Sets if empty bounds files should be created for areas without any
+ * boundary. Typically these are sea areas or areas not included in the OSM
+ * file.
+ *
+ * @param createEmptyFiles
+ * <code>true</code> create bounds files for uncovered areas;
+ * <code>false</code> create bounds files only for areas
+ * containing boundary information
+ */
+ public void setCreateEmptyFiles(boolean createEmptyFiles) {
+ this.createEmptyFiles = createEmptyFiles;
+ }
+
+ /**
+ * Write a varying length double. A typical double value requires only ~ 20 bits
+ * (the left ones). As in o5m format we use the leftmost bit of a byte to signal
+ * that a further byte is to read, the remaining 7 bits are used to store the value.
+ * Many values are stored within 3 bytes, but some may require 10 bytes
+ * (64 bits = 9*7 + 1) . We start with the highest bits of the long value that
+ * represents the double.
+ *
+ * @param dos the already opened OutputStream
+ * @param val the double value to be written
+ * @throws IOException
+ */
+ private static void writeVarDouble(OutputStream dos, double val) throws IOException{
+ long v64 = Double.doubleToRawLongBits(val);
+ if (v64 == 0){
+ dos.write(0);
+ return;
+ }
+ byte[] buffer = new byte[12];
+ int numBytes = 0;
+ while(v64 != 0){
+ v64 = (v64 << 7) | (v64 >>> -7); // rotate left 7 bits
+ buffer[numBytes++] = (byte)(v64 & 0x7f|0x80L);
+ v64 &= 0xffffffffffffff80L;
+ }
+
+ buffer[numBytes-1] &= 0x7f;
+ dos.write(buffer, 0, numBytes);
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryUtil.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryUtil.java
new file mode 100644
index 0000000..98a8bae
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryUtil.java
@@ -0,0 +1,729 @@
+/*
+ * Copyright (C) 2006, 2013.
+ *
+ * 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.reader.osm.boundary;
+
+import java.awt.geom.Area;
+import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import uk.me.parabola.imgfmt.FormatException;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.reader.osm.Tags;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.EnhancedProperties;
+import uk.me.parabola.util.Java2DConverter;
+import uk.me.parabola.util.MultiHashMap;
+
+public class BoundaryUtil {
+ private static final Logger log = Logger.getLogger(BoundaryUtil.class);
+
+ private static final int UNKNOWN_DATA_FORMAT = 0;
+ private static final int RAW_DATA_FORMAT_V1 = 2;
+ private static final int QUADTREE_DATA_FORMAT_V1 = 3;
+
+ /**
+ * Calculate the polygons that describe the area.
+ * @param area the Area instance
+ * @param id an id that is used to create meaningful messages, typically a boundary Id
+ * @return A list of BoundaryElements (can be empty)
+ */
+ public static List<BoundaryElement> splitToElements(Area area, String id) {
+ if (area.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ Area testArea = area;
+ boolean tryAgain = true;
+ while (true){
+ List<List<Coord>> areaElements = Java2DConverter.areaToShapes(testArea);
+
+ if (areaElements.isEmpty()) {
+ // this may happen if a boundary overlaps a raster tile in a very small area
+ // so that it is has no dimension
+ log.debug("Area has no dimension. Area:",area.getBounds());
+ return Collections.emptyList();
+ }
+
+ List<BoundaryElement> bElements = new ArrayList<BoundaryElement>();
+ for (List<Coord> singleElement : areaElements) {
+ if (singleElement.size() <= 3) {
+ // need at least 4 items to describe a polygon
+ continue;
+ }
+ boolean outer = Way.clockwise(singleElement);
+ bElements.add(new BoundaryElement(outer, singleElement));
+ }
+
+ if (bElements.isEmpty()) {
+ // should not happen because empty polygons should be removed by
+ // the Java2DConverter
+ log.error("Empty boundary elements list after conversion. Area: "+area.getBounds());
+ return Collections.emptyList();
+ }
+
+
+ // reverse the list because it starts with the inner elements first and
+ // we need the other way round
+ Collections.reverse(bElements);
+
+ if (bElements.get(0).isOuter())
+ return bElements;
+
+ // result is not usable if first element is not outer
+ if (tryAgain == false){
+ // cannot convert this area
+ log.error(" first element is not outer. "+ bElements.get(0));
+
+ //createJavaCodeSnippet(area);
+ //String fname = "bnd_gpx/first_not_outer" + id ;
+ //GpxCreator.createGpx(fname, bElements.get(0).getPoints());
+ return Collections.emptyList();
+ }
+ // try converting the area with rounded float values
+ Path2D.Float path = new Path2D.Float(area);
+ testArea = new Area(path);
+ tryAgain = false;
+ }
+ }
+
+ /**
+ * Wrapper for {@link #loadQuadTrees(String, List, uk.me.parabola.imgfmt.app.Area, EnhancedProperties)}
+ * @param boundaryDirName a directory name or zip file containing the *.bnd file
+ * @param boundaryFileName the *.bnd file name
+ * @return the quadtree or null in case of errors
+ */
+ public static BoundaryQuadTree loadQuadTree (String boundaryDirName,
+ String boundaryFileName){
+ Map<String,BoundaryQuadTree> trees = loadQuadTrees (boundaryDirName, Collections.singletonList(boundaryFileName), null, null);
+ return trees.get(boundaryFileName);
+ }
+
+ /**
+ * Create a BoundaryQuadTree for each file listed in boundaryFileNames.
+ * @param boundaryDirName a directory name or zip file containing the *.bnd file
+ * @param boundaryFileNames the list of *.bnd file names
+ * @param searchBbox null or a bounding box. Data outside of this box is ignored.
+ * @param props null or the properties to be used for the locator
+ * @return a map with quadtrees which can be empty
+ */
+ public static Map<String,BoundaryQuadTree> loadQuadTrees (String boundaryDirName,
+ List<String> boundaryFileNames,
+ uk.me.parabola.imgfmt.app.Area searchBbox, EnhancedProperties props){
+ Map<String,BoundaryQuadTree> trees = new HashMap<String,BoundaryQuadTree>();
+ File boundaryDir = new File(boundaryDirName);
+ BoundaryQuadTree bqt;
+ if (boundaryDir.isDirectory()){
+ for (String boundaryFileName: boundaryFileNames){
+ log.info("loading boundary file:", boundaryFileName);
+ // no support for nested directories
+ File boundaryFile = new File(boundaryDir, boundaryFileName);
+ try {
+ if (boundaryFile.exists()){
+ InputStream stream = new FileInputStream(boundaryFile);
+ bqt = BoundaryUtil.loadQuadTreeFromStream(stream, boundaryFileName, searchBbox, props);
+ if (bqt != null)
+ trees.put(boundaryFileName,bqt);
+ }
+ } catch (IOException exp) {
+ log.error("Cannot load boundary file " + boundaryFileName + "." + exp);
+ }
+
+ }
+ } else if (boundaryDirName.endsWith(".zip")) {
+ String currentFileName = "";
+ try{
+ ZipFile zipFile = new ZipFile(boundaryDir);
+
+ for (String boundaryFileName : boundaryFileNames){
+ log.info("loading boundary file:", boundaryFileName);
+ currentFileName = boundaryFileName;
+ // direct access
+ ZipEntry entry = zipFile.getEntry(boundaryFileName);
+ if (entry != null){
+ bqt = BoundaryUtil.loadQuadTreeFromStream(zipFile.getInputStream(entry),
+ boundaryFileName, searchBbox, props);
+ if (bqt != null)
+ trees.put(boundaryFileName,bqt);
+ }
+ }
+ zipFile.close();
+ } catch (IOException exp) {
+ log.error("Cannot load boundary file " + currentFileName + "." + exp);
+ }
+ } else{
+ log.error("Cannot read " + boundaryDirName);
+ }
+ return trees;
+ }
+
+
+ /**
+ * read path iterator info from stream and create Area.
+ * Data is stored with varying length doubles.
+ * @param inpStream the already opened DataInputStream
+ * @return a new Area object or null if not successful
+ * @throws IOException
+ */
+ public static Area readAreaAsPath(DataInputStream inpStream) throws IOException{
+ double[] res = new double[2];
+ Path2D.Double path = new Path2D.Double();
+ int windingRule = inpStream.readInt();
+ path.setWindingRule(windingRule);
+ int type = inpStream.readInt();
+ while (type >= 0) {
+ switch (type) {
+ case PathIterator.SEG_LINETO:
+ int len = inpStream.readInt();
+ while(len > 0){
+ for (int ii = 0; ii < 2; ii++){
+ double delta = readVarDouble(inpStream);
+ if (delta == BoundarySaver.RESET_DELTA)
+ res[ii] = readVarDouble(inpStream);
+ else
+ res[ii] = res[ii] + delta;
+ }
+ path.lineTo(res[0],res[1]);
+ --len;
+ }
+ break;
+ case PathIterator.SEG_MOVETO:
+ for (int ii = 0; ii < 2; ii++){
+ double delta = readVarDouble(inpStream);
+ if (delta == BoundarySaver.RESET_DELTA)
+ res[ii] = readVarDouble(inpStream);
+ else
+ res[ii] = res[ii] + delta;
+ }
+ path.moveTo(res[0],res[1]);
+ break;
+ case PathIterator.SEG_CLOSE:
+ path.closePath();
+ break;
+ default:
+ log.error("Unsupported path iterator type " + type
+ + ". This is an mkgmap error.");
+ return null;
+ }
+
+ type = inpStream.readInt();
+ }
+ if (type != -1){
+ log.error("Final type value != -1: " + type);
+ }
+ else{
+ return new Area(path);
+ }
+ return null;
+ }
+
+ /**
+ * Read boundary info saved in RAW_DATA_FORMAT
+ * (written by 1st pass of preparer)
+ * @param inpStream the already opened DataInputStream
+ * @param fname the related file name of the *.bnd file
+ * @param bbox a bounding box. Data outside of this box is ignored.
+ * @return
+ * @throws IOException
+ */
+ private static List<Boundary> readStreamRawFormat(
+ DataInputStream inpStream, String fname,
+ uk.me.parabola.imgfmt.app.Area bbox) throws IOException {
+ List<Boundary> boundaryList = new ArrayList<Boundary>();
+
+ try {
+ while (true) {
+ int minLat = inpStream.readInt();
+ int minLong = inpStream.readInt();
+ int maxLat = inpStream.readInt();
+ int maxLong = inpStream.readInt();
+ log.debug("Next boundary. Lat min:",minLat,"max:",maxLat,"Long min:",minLong,"max:",maxLong);
+ uk.me.parabola.imgfmt.app.Area rBbox = new uk.me.parabola.imgfmt.app.Area(
+ minLat, minLong, maxLat, maxLong);
+ int bSize = inpStream.readInt();
+ log.debug("Size:",bSize);
+
+ if ( bbox == null || bbox.intersects(rBbox)) {
+ log.debug("Bbox intersects. Load the boundary");
+ String id = inpStream.readUTF();
+ Tags tags = new Tags();
+ int noOfTags = inpStream.readInt();
+ for (int i = 0; i < noOfTags; i++) {
+ String name = inpStream.readUTF();
+ String value = inpStream.readUTF();
+ tags.put(name, value.intern());
+ }
+ Area area = readAreaAsPath(inpStream);
+ if (area != null) {
+ Boundary boundary = new Boundary(area, tags,id);
+ boundaryList.add(boundary);
+ } else {
+ log.warn("Boundary "+tags+" does not contain any valid area in file " + fname);
+ }
+
+ } else {
+ log.debug("Bbox does not intersect. Skip",bSize);
+ inpStream.skipBytes(bSize);
+ }
+ }
+ } catch (EOFException exp) {
+ // it's always thrown at the end of the file
+ // log.error("Got EOF at the end of the file");
+ }
+ return boundaryList;
+ }
+
+ /**
+ * For a given bounding box, calculate the list of file names that have to be read
+ * @param bbox the bounding box
+ * @return a List with the names
+ */
+ public static List<String> getRequiredBoundaryFileNames(uk.me.parabola.imgfmt.app.Area bbox) {
+ List<String> names = new ArrayList<String>();
+ for (int latSplit = BoundaryUtil.getSplitBegin(bbox.getMinLat()); latSplit <= BoundaryUtil
+ .getSplitBegin(bbox.getMaxLat()); latSplit += BoundaryUtil.RASTER) {
+ for (int lonSplit = BoundaryUtil.getSplitBegin(bbox.getMinLong()); lonSplit <= BoundaryUtil
+ .getSplitBegin(bbox.getMaxLong()); lonSplit += BoundaryUtil.RASTER) {
+ names.add("bounds_"+ getKey(latSplit, lonSplit) + ".bnd");
+ }
+ }
+ return names;
+ }
+
+ /**
+ * Check content of directory or zip file with precompiled boundary data,
+ * dirName Name has to be a directory or a zip file.
+ * @param dirName : path to a directory or a zip file containing the *.bnd files
+ * @return the available *.bnd files in dirName.
+ */
+ public static List<String> getBoundaryDirContent(String dirName) {
+ List<String> names = new ArrayList<String>();
+ File boundaryDir = new File(dirName);
+ if (!boundaryDir.exists())
+ log.error("boundary directory/zip does not exist: " + dirName);
+ else{
+ if (boundaryDir.isDirectory()){
+ // boundaryDir.list() is much quicker than boundaryDir.listFiles(FileFilter)
+ String[] allNames = boundaryDir.list();
+ for (String name: allNames){
+ if (name.endsWith(".bnd"))
+ names.add(name);
+ }
+ }
+ else if (boundaryDir.getName().endsWith(".zip")){
+ try {
+ ZipFile zipFile = new ZipFile(boundaryDir);
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
+ boolean isFlat = true;
+ while(entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ if (entry.isDirectory()){
+ isFlat = false;
+ }
+ if (entry.getName().endsWith(".bnd"))
+ names.add(entry.getName());
+ }
+ zipFile.close();
+ if (!isFlat){
+ log.error("boundary zip file contains directories. Files in directories will be ignored." + dirName);
+ }
+ } catch (IOException ioe) {
+ System.err.println("Unhandled exception:");
+ ioe.printStackTrace();
+ }
+ }
+ }
+ return names;
+ }
+
+ public static final int RASTER = 50000;
+
+ public static int getSplitBegin(int value) {
+ int rem = value % RASTER;
+ if (rem == 0) {
+ return value;
+ } else if (value >= 0) {
+ return value - rem;
+ } else {
+ return value - RASTER - rem;
+ }
+ }
+
+ public static int getSplitEnd(int value) {
+ int rem = value % RASTER;
+ if (rem == 0) {
+ return value;
+ } else if (value >= 0) {
+ return value + RASTER - rem;
+ } else {
+ return value - rem;
+ }
+ }
+
+ public static String getKey(int lat, int lon) {
+ return lat + "_" + lon;
+ }
+
+ /**
+ * Retrieve the bounding box of the given boundary file.
+ * @param boundaryFileName the name of the boundary file
+ * @return the bounding box
+ */
+ public static uk.me.parabola.imgfmt.app.Area getBbox(String boundaryFileName) {
+ String filename = new String(boundaryFileName);
+ // cut off the extension
+ filename = filename.substring(0,filename.length()-4);
+ String[] fParts = filename.split(Pattern.quote("_"));
+
+ int lat = Integer.valueOf(fParts[1]);
+ int lon = Integer.valueOf(fParts[2]);
+
+ return new uk.me.parabola.imgfmt.app.Area(lat, lon, lat+RASTER, lon+RASTER);
+ }
+
+ /**
+ * Create and fill a BoundaryQuadTree. Read the header of the stream to detect
+ * the proper reading routine for the different supported formats.
+ * @param stream an already opened InputStream
+ * @param fname the file name of the corresponding *.bnd file
+ * @param searchBbox a bounding box or null. If not null, area info outside of this
+ * bounding box is ignored.
+ * @param props properties to be used or null
+ * @return on success it returns a new BoundaryQuadTree, else null
+ * @throws IOException
+ */
+ private static BoundaryQuadTree loadQuadTreeFromStream(InputStream stream,
+ String fname,
+ uk.me.parabola.imgfmt.app.Area searchBbox,
+ EnhancedProperties props)throws IOException{
+ BoundaryQuadTree bqt = null;
+ uk.me.parabola.imgfmt.app.Area qtBbox = BoundaryUtil.getBbox(fname);
+ try {
+ DataInputStream inpStream = new DataInputStream(
+ new BufferedInputStream(stream, 1024 * 1024));
+
+ try {
+ // 1st read the mkgmap release the boundary file is created by
+ String mkgmapRel = "?";
+ String firstId = inpStream.readUTF();
+ if ("BND".equals(firstId) == false){
+ throw new FormatException("Unsupported boundary data type "+firstId);
+ }
+
+ int format = UNKNOWN_DATA_FORMAT;
+ long createTime = inpStream.readLong();
+ int headerLength = inpStream.readInt();
+ byte[] header = new byte[headerLength];
+ int bytesRead = 0;
+ while (bytesRead < headerLength) {
+ int nBytes = inpStream.read(header, bytesRead, headerLength-bytesRead);
+ if (nBytes<0) {
+ throw new IOException("Cannot read header with size "+headerLength);
+ } else {
+ bytesRead += nBytes;
+ }
+ }
+
+ ByteArrayInputStream rawHeaderStream = new ByteArrayInputStream(header);
+ DataInputStream headerStream =new DataInputStream(rawHeaderStream);
+ String dataFormat = (rawHeaderStream.available() > 0 ? headerStream.readUTF() : "RAW");
+ int recordVersion = (rawHeaderStream.available() > 0 ? headerStream.readInt() : RAW_DATA_FORMAT_V1);
+ mkgmapRel = (rawHeaderStream.available() > 0 ? headerStream.readUTF() : "unknown");
+
+ if ("RAW".equals(dataFormat) && recordVersion == 1)
+ format = RAW_DATA_FORMAT_V1;
+ else if ("QUADTREE".equals(dataFormat) && recordVersion == 1)
+ format = QUADTREE_DATA_FORMAT_V1;
+
+ if (log.isDebugEnabled()) {
+ log.debug("File created by mkgmap release",mkgmapRel,"at",new Date(createTime));
+ }
+
+ switch (format) {
+ case QUADTREE_DATA_FORMAT_V1:
+ bqt = new BoundaryQuadTree(inpStream, qtBbox, searchBbox, props);
+ break;
+ case RAW_DATA_FORMAT_V1:
+ List<Boundary> boundaryList = readStreamRawFormat(inpStream, fname,searchBbox);
+ if (boundaryList == null || boundaryList.isEmpty())
+ return null;
+ boundaryList = mergePostalCodes(boundaryList);
+ bqt = new BoundaryQuadTree(qtBbox, boundaryList, props);
+ break;
+ default:
+ throw new FormatException("Unsupported boundary file format: "+format);
+ }
+ } catch (EOFException exp) {
+ // it's always thrown at the end of the file
+ // log.error("Got EOF at the end of the file");
+ }
+ catch (FormatException exp) {
+ log.error("Failed to read boundary file " + fname + " " + exp.getMessage());
+ }
+ inpStream.close();
+ } finally {
+ if (stream != null)
+ stream.close();
+ }
+ return bqt;
+ }
+
+ /**
+ * Merges boundaries with the same postal code.
+ * @param boundaries a list of boundaries
+ * @return the boundary list with postal code areas merged
+ */
+ private static List<Boundary> mergePostalCodes(List<Boundary> boundaries) {
+ List<Boundary> mergedList = new ArrayList<Boundary>(boundaries.size());
+
+ MultiHashMap<String, Boundary> equalPostalCodes = new MultiHashMap<String, Boundary>();
+ for (Boundary boundary : boundaries) {
+ String postalCode = getPostalCode(boundary.getTags());
+ if (postalCode == null) {
+ // no postal code boundary
+ mergedList.add(boundary);
+ } else {
+ // postal code boundary => merge it later
+ equalPostalCodes.add(postalCode, boundary);
+ }
+ }
+
+ for (Entry<String, List<Boundary>> postCodeBoundary : equalPostalCodes
+ .entrySet()) {
+ if (postCodeBoundary.getValue().size() == 1) {
+ // nothing to merge
+ mergedList.addAll(postCodeBoundary.getValue());
+ continue;
+ }
+
+ // there are more than 2 boundaries with the same post code
+ // => merge them
+ Area newPostCodeArea = new Area();
+ for (Boundary b : postCodeBoundary.getValue()) {
+ newPostCodeArea.add(b.getArea());
+
+ // remove the post code tags from the original boundary
+ if (b.getTags().get("postal_code") != null) {
+ b.getTags().remove("postal_code");
+ } else if ("postal_code".equals(b.getTags().get("boundary"))) {
+ b.getTags().remove("boundary");
+ b.getTags().remove("name");
+ }
+
+ // check if the boundary contains other boundary information
+ if (isAdministrativeBoundary(b)) {
+ mergedList.add(b);
+ } else {
+ log.info("Boundary", b.getId(), b.getTags(), "contains no more boundary tags. Skipping it.");
+ }
+ }
+
+ Tags postalCodeTags = new Tags();
+ postalCodeTags.put("postal_code", postCodeBoundary.getKey());
+ Boundary postalCodeBoundary = new Boundary(newPostCodeArea, postalCodeTags, "p"+postCodeBoundary.getKey());
+
+ log.info("Merged", postCodeBoundary.getValue().size(), "postal code boundaries for postal code", postCodeBoundary.getKey());
+ mergedList.add(postalCodeBoundary);
+ }
+
+ return mergedList;
+ }
+
+ /**
+ * Checks if the given boundary contains tags for an administrative boundary.
+ * @param b a boundary
+ * @return <code>true</code> administrative boundary or postal code;
+ * <code>false</code> element cannot be used for precompiled bounds
+ */
+ public static boolean isAdministrativeBoundary(Boundary b) {
+
+ if (b.getId().startsWith("r")) {
+ String type = b.getTags().get("type");
+
+ if ("boundary".equals(type) || "multipolygon".equals(type)) {
+ String boundaryVal = b.getTags().get("boundary");
+ if ("administrative".equals(boundaryVal)) {
+ // for boundary=administrative the admin_level must be set
+ if (b.getTags().get("admin_level") == null) {
+ return false;
+ }
+ // and a name must be set (check only for a tag containing name
+ Iterator<Entry<String,String>> tagIterator = b.getTags().entryIterator();
+ while (tagIterator.hasNext()) {
+ Entry<String,String> tag = tagIterator.next();
+ if (tag.getKey().contains("name")) {
+ return true;
+ }
+ }
+ // does not contain a name tag => do not use it
+ return false;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ } else if (b.getId().startsWith("w")) {
+ // the boundary tag must be "administrative" or "postal_code"
+ String boundaryVal = b.getTags().get("boundary");
+ if ("administrative".equals(boundaryVal)) {
+ // for boundary=administrative the admin_level must be set
+ if (b.getTags().get("admin_level") == null) {
+ return false;
+ }
+ // and a name must be set (check only for a tag containing name)
+ Iterator<Entry<String,String>> tagIterator = b.getTags().entryIterator();
+ while (tagIterator.hasNext()) {
+ Entry<String,String> tag = tagIterator.next();
+ if (tag.getKey().contains("name")) {
+ return true;
+ }
+ }
+ // does not contain a name tag => do not use it
+ return false;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+
+ private static String getPostalCode(Tags tags) {
+ String zip = tags.get("postal_code");
+ if (zip == null) {
+ if ("postal_code".equals(tags.get("boundary"))){
+ String name = tags.get("name");
+ if (name != null) {
+ String[] nameParts = name.split(Pattern.quote(" "));
+ if (nameParts.length > 0) {
+ zip = nameParts[0].trim();
+ }
+ }
+ }
+ }
+ return zip;
+ }
+ /**
+ * Helper to ease the reporting of errors. Creates a java code snippet
+ * that can be compiled to have the same area.
+ * @param area the area for which the code should be produced
+ */
+ public static void createJavaCodeSnippet(Area area) {
+ double[] res = new double[6];
+ PathIterator pit = area.getPathIterator(null);
+ System.out.println("Path2D.Double path = new Path2D.Double();");
+ System.out.println("path.setWindingRule(" + pit.getWindingRule() + ");");
+ while (!pit.isDone()) {
+ int type = pit.currentSegment(res);
+ switch (type) {
+ case PathIterator.SEG_LINETO:
+ System.out.println("path.lineTo(" + res[0] + "d, " + res[1] + "d);");
+ break;
+ case PathIterator.SEG_MOVETO:
+ System.out.println("path.moveTo(" + res[0] + "d, " + res[1] + "d);");
+ break;
+ case PathIterator.SEG_CLOSE:
+ System.out.println("path.closePath();");
+ break;
+ default:
+ log.error("Unsupported path iterator type " + type
+ + ". This is an mkgmap error.");
+ }
+
+ pit.next();
+ }
+ System.out.println("Area area = new Area(path);");
+
+ }
+
+ /**
+ * Add the path of an area to an existing path.
+ * @param path
+ * @param area
+ */
+ public static void addToPath (Path2D.Double path, Area area){
+ PathIterator pit = area.getPathIterator(null);
+ double[] res = new double[6];
+ path.setWindingRule(pit.getWindingRule());
+ while (!pit.isDone()) {
+ int type = pit.currentSegment(res);
+ switch (type) {
+ case PathIterator.SEG_LINETO:
+ path.lineTo(res[0],res[1]);
+ break;
+ case PathIterator.SEG_MOVETO:
+ path.moveTo(res[0],res[1]);
+ break;
+ case PathIterator.SEG_CLOSE:
+ path.closePath();
+ break;
+ default:
+ log.error("Unsupported path iterator type " + type
+ + ". This is an mkgmap error.");
+ }
+
+ pit.next();
+ }
+ }
+
+ /**
+ * read a varying length double. See BoundarySaver.writeVarDouble().
+ * @param inp the already opened DataInputStream
+ * @return the extracted double value
+ * @throws IOException
+ */
+ static double readVarDouble(DataInputStream inp) throws IOException{
+ byte b;
+ long res = 0;
+ long toShift = 64 - 7;
+ while (((b = inp.readByte()) & 0x80) != 0){ // more bytes will follow
+ res |= (b & 0x7f);
+ toShift -= 7;
+ if (toShift > 0)
+ res <<= 7;
+ }
+ if (toShift > 0){
+ res |= b;
+ res <<= toShift;
+ }
+ else {
+ // special case: all 64 bits were written, 64 = 9*7 + 1
+ res <<= 1;
+ res |= 1;
+ }
+ return Double.longBitsToDouble(res);
+ }
+
+ }
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/LoadableBoundaryDataSource.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/LoadableBoundaryDataSource.java
new file mode 100644
index 0000000..88ca3da
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/LoadableBoundaryDataSource.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2006, 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.reader.osm.boundary;
+
+import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
+
+public interface LoadableBoundaryDataSource extends LoadableMapDataSource {
+
+ public void setBoundarySaver(BoundarySaver saver);
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/O5mBinBoundaryDataSource.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/O5mBinBoundaryDataSource.java
new file mode 100644
index 0000000..ef61510
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/O5mBinBoundaryDataSource.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2006, 2012.
+ *
+ * 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.reader.osm.boundary;
+
+import java.util.Set;
+
+import uk.me.parabola.mkgmap.reader.osm.MultiPolygonFinishHook;
+import uk.me.parabola.mkgmap.reader.osm.OsmReadingHooks;
+import uk.me.parabola.mkgmap.reader.osm.o5m.O5mBinMapDataSource;
+import uk.me.parabola.util.EnhancedProperties;
+
+public class O5mBinBoundaryDataSource
+ extends O5mBinMapDataSource
+ implements LoadableBoundaryDataSource {
+
+ private BoundarySaver saver;
+
+ protected void addBackground(boolean mapHasPolygon4B) {
+ // do not add a background polygon
+ }
+
+ protected OsmReadingHooks[] getPossibleHooks() {
+ return new OsmReadingHooks[] { new MultiPolygonFinishHook() };
+ }
+
+ protected void createElementSaver() {
+ elementSaver = new BoundaryElementSaver(getConfig(), saver);
+ }
+
+ public Set<String> getUsedTags() {
+ // return null => all tags are used
+ return null;
+ }
+
+ protected void createConverter() {
+ converter = new BoundaryConverter(saver);
+ }
+
+ private final EnhancedProperties props = new EnhancedProperties();
+
+ protected EnhancedProperties getConfig() {
+ return props;
+ }
+
+ public void setBoundarySaver(BoundarySaver saver) {
+ this.saver = saver;
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/Osm5BoundaryDataSource.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/Osm5BoundaryDataSource.java
new file mode 100644
index 0000000..7e461cd
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/Osm5BoundaryDataSource.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2006, 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.reader.osm.boundary;
+
+import java.util.Set;
+
+import uk.me.parabola.mkgmap.reader.osm.MultiPolygonFinishHook;
+import uk.me.parabola.mkgmap.reader.osm.OsmReadingHooks;
+import uk.me.parabola.mkgmap.reader.osm.xml.Osm5MapDataSource;
+import uk.me.parabola.util.EnhancedProperties;
+
+public class Osm5BoundaryDataSource
+ extends Osm5MapDataSource
+ implements LoadableBoundaryDataSource {
+
+ private BoundarySaver saver;
+
+ protected void addBackground(boolean mapHasPolygon4B) {
+ // do not add a background polygon
+ }
+
+ protected OsmReadingHooks[] getPossibleHooks() {
+ return new OsmReadingHooks[] { new MultiPolygonFinishHook() };
+ }
+
+ protected void createElementSaver() {
+ elementSaver = new BoundaryElementSaver(getConfig(), saver);
+ }
+
+ public Set<String> getUsedTags() {
+ // return null => all tags are used
+ return null;
+ }
+
+ protected void createConverter() {
+ converter = new BoundaryConverter(saver);
+ }
+
+ private final EnhancedProperties props = new EnhancedProperties();
+
+ protected EnhancedProperties getConfig() {
+ return props;
+ }
+
+ public void setBoundarySaver(BoundarySaver saver) {
+ this.saver = saver;
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/OsmBinBoundaryDataSource.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/OsmBinBoundaryDataSource.java
new file mode 100644
index 0000000..084da76
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/OsmBinBoundaryDataSource.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2006, 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.reader.osm.boundary;
+
+import java.util.Set;
+
+import uk.me.parabola.mkgmap.reader.osm.MultiPolygonFinishHook;
+import uk.me.parabola.mkgmap.reader.osm.OsmReadingHooks;
+import uk.me.parabola.mkgmap.reader.osm.bin.OsmBinMapDataSource;
+import uk.me.parabola.util.EnhancedProperties;
+
+public class OsmBinBoundaryDataSource
+ extends OsmBinMapDataSource
+ implements LoadableBoundaryDataSource {
+
+ private BoundarySaver saver;
+
+ protected void addBackground(boolean mapHasPolygon4B) {
+ // do not add a background polygon
+ }
+
+ protected OsmReadingHooks[] getPossibleHooks() {
+ return new OsmReadingHooks[] { new MultiPolygonFinishHook() };
+ }
+
+ protected void createElementSaver() {
+ elementSaver = new BoundaryElementSaver(getConfig(), saver);
+ }
+
+ public Set<String> getUsedTags() {
+ // return null => all tags are used
+ return null;
+ }
+
+ protected void createConverter() {
+ converter = new BoundaryConverter(saver);
+ }
+
+ private final EnhancedProperties props = new EnhancedProperties();
+
+ protected EnhancedProperties getConfig() {
+ return props;
+ }
+
+ public void setBoundarySaver(BoundarySaver saver) {
+ this.saver = saver;
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/o5m/O5mBinHandler.java b/src/uk/me/parabola/mkgmap/reader/osm/o5m/O5mBinHandler.java
new file mode 100644
index 0000000..c5e843e
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/o5m/O5mBinHandler.java
@@ -0,0 +1,644 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.reader.osm.o5m;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.GeneralRelation;
+import uk.me.parabola.mkgmap.reader.osm.Node;
+import uk.me.parabola.mkgmap.reader.osm.OsmHandler;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+
+/**
+ * Parser for the o5m format described here: http://wiki.openstreetmap.org/wiki/O5m
+ * The routines to are based on the osmconvert.c source from Markus Weber who allows
+ * to copy them for any o5m IO, thanks a lot for that.
+ * @author GerdP
+ *
+ */
+public class O5mBinHandler extends OsmHandler{
+ // O5M data set constants
+ private static final int NODE_DATASET = 0x10;
+ private static final int WAY_DATASET = 0x11;
+ private static final int REL_DATASET = 0x12;
+ private static final int BBOX_DATASET = 0xdb;
+ private static final int TIMESTAMP_DATASET = 0xdc;
+ private static final int HEADER_DATASET = 0xe0;
+ private static final int EOD_FLAG = 0xfe;
+ private static final int RESET_FLAG = 0xff;
+
+ private static final int EOF_FLAG = -1;
+
+ // o5m constants
+ private static final int STRING_TABLE_SIZE = 15000;
+ private static final int MAX_STRING_PAIR_SIZE = 250 + 2;
+ private static final String[] REL_REF_TYPES = {"node", "way", "relation", "?"};
+ private static final double FACTOR = 1d/1000000000; // used with 100*<Val>*FACTOR
+
+ private final BufferedInputStream fis;
+ private InputStream is;
+ private ByteArrayInputStream bis;
+
+ // buffer for byte -> String conversions
+ private byte[] cnvBuffer;
+
+ private byte[] ioBuf;
+ private int ioPos;
+ // the o5m string table
+ private String[][] stringTable;
+ private String[] stringPair;
+ private int currStringTablePos;
+ // a counter that must be maintained by all routines that read data from the stream
+ private int bytesToRead;
+ // total number of bytes read from stream
+ long countBytes;
+
+ // for delta calculations
+ private long lastNodeId;
+ private long lastWayId;
+ private long lastRelId;
+ private long lastRef[];
+ private long lastTs;
+ private long lastChangeSet;
+ private int lastLon,lastLat;
+
+ /**
+ * A parser for the o5m format
+ * @param processor A mapProcessor instance
+ * @param stream The InputStream that contains the OSM data in o5m format
+ * @param skipArray An Array of longs that is used to hold information of file position of the first occurrence of
+ * each known 05m data type (esp. nodes, ways, and relations).
+ */
+ O5mBinHandler(InputStream stream) {
+ this.fis = new BufferedInputStream(stream);
+ is = fis;
+ this.cnvBuffer = new byte[4000]; // OSM data should not contain string pairs with length > 512
+ this.ioBuf = new byte[8192];
+ this.ioPos = 0;
+ this.stringPair = new String[2];
+ this.lastRef = new long[3];
+ reset();
+ }
+
+ /**
+ * parse the input stream
+ */
+ public void parse(){
+ try {
+ int start = is.read();
+ ++countBytes;
+ if (start != RESET_FLAG)
+ throw new IOException("wrong header byte " + start);
+ readFile();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void readFile() throws IOException{
+ boolean done = false;
+ while(!done){
+ is = fis;
+ long size = 0;
+ int fileType = is.read();
+ ++countBytes;
+ if (fileType >= 0 && fileType < 0xf0){
+ bytesToRead = 0;
+ size = readUnsignedNum64FromStream();
+ countBytes += size - bytesToRead; // bytesToRead is negative
+ bytesToRead = (int)size;
+
+ switch(fileType){
+ case NODE_DATASET:
+ case WAY_DATASET:
+ case REL_DATASET:
+ case BBOX_DATASET:
+ case TIMESTAMP_DATASET:
+ case HEADER_DATASET:
+ if (bytesToRead > ioBuf.length){
+ ioBuf = new byte[(int)bytesToRead+100];
+ }
+ int bytesRead = 0;
+ int neededBytes = bytesToRead;
+ while (neededBytes > 0){
+ bytesRead += is.read(ioBuf, bytesRead, neededBytes);
+ neededBytes -= bytesRead;
+ }
+ ioPos = 0;
+ bis = new ByteArrayInputStream(ioBuf,0,bytesToRead);
+ is = bis;
+ break;
+ default:
+ }
+ }
+ if (fileType == EOF_FLAG) done = true;
+ else if (fileType == NODE_DATASET) readNode();
+ else if (fileType == WAY_DATASET) readWay();
+ else if (fileType == REL_DATASET) readRel();
+ else if (fileType == BBOX_DATASET) readBBox();
+ else if (fileType == TIMESTAMP_DATASET) readFileTimestamp();
+ else if (fileType == HEADER_DATASET) readHeader();
+ else if (fileType == EOD_FLAG) done = true;
+ else if (fileType == RESET_FLAG) reset();
+ else {
+ if (fileType < 0xf0 )skip(size); // skip unknown data set
+ }
+ }
+ }
+
+ /**
+ * read (and ignore) the file timestamp data set
+ */
+ private void readFileTimestamp(){
+ /*long fileTimeStamp = */readSignedNum64();
+ }
+
+ /**
+ * Skip the given number of bytes
+ * @param bytes
+ * @throws IOException
+ */
+ private void skip(long bytes)throws IOException{
+ long toSkip = bytes;
+ while (toSkip > 0)
+ toSkip -= is.skip(toSkip);
+ }
+
+ /**
+ * read the bounding box data set
+ * @throws IOException
+ */
+ private void readBBox() {
+ double leftf = (double) (100L*readSignedNum32()) * FACTOR;
+ double bottomf = (double) (100L*readSignedNum32()) * FACTOR;
+ double rightf = (double) (100L*readSignedNum32()) * FACTOR;
+ double topf = (double) (100L*readSignedNum32()) * FACTOR;
+ assert bytesToRead == 0;
+ setBBox(bottomf, leftf, topf, rightf);
+ }
+
+ /**
+ * read a node data set
+ * @throws IOException
+ */
+ private void readNode() throws IOException{
+ lastNodeId += readSignedNum64();
+ if (bytesToRead == 0)
+ return; // only nodeId: this is a delete action, we ignore it
+ readVersionTsAuthor();
+ if (bytesToRead == 0)
+ return; // only nodeId+version: this is a delete action, we ignore it
+ int lon = readSignedNum32() + lastLon; lastLon = lon;
+ int lat = readSignedNum32() + lastLat; lastLat = lat;
+
+ double flon = (double)(100L*lon) * FACTOR;
+ double flat = (double)(100L*lat) * FACTOR;
+ assert flat >= -90.0 && flat <= 90.0;
+ assert flon >= -180.0 && flon <= 180.0;
+
+ Coord co = new Coord(flat, flon);
+ saver.addPoint(lastNodeId, co);
+ if (bytesToRead > 0){
+ Node node = new Node(lastNodeId,co);
+ readTags(node);
+ if (node.getTagCount() > 0){
+ // If there are tags, then we save a proper node for it.
+ saver.addNode(node);
+ hooks.onAddNode(node);
+ }
+ }
+ }
+
+ /**
+ * read a way data set
+ * @throws IOException
+ */
+ private void readWay() throws IOException{
+ lastWayId += readSignedNum64();
+ if (bytesToRead == 0)
+ return; // only wayId: this is a delete action, we ignore it
+
+ readVersionTsAuthor();
+ if (bytesToRead == 0)
+ return; // only wayId + version: this is a delete action, we ignore it
+ Way way = startWay(lastWayId);
+ long refSize = readUnsignedNum32();
+ long stop = bytesToRead - refSize;
+
+ while(bytesToRead > stop){
+ lastRef[0] += readSignedNum64();
+ addCoordToWay(way, lastRef[0]);
+ }
+
+ readTags(way);
+ endWay(way);
+ }
+
+ /**
+ * read a relation data set
+ * @throws IOException
+ */
+ private void readRel() throws IOException{
+ lastRelId += readSignedNum64();
+ if (bytesToRead == 0)
+ return; // only relId: this is a delete action, we ignore it
+ readVersionTsAuthor();
+ if (bytesToRead == 0)
+ return; // only relId + version: this is a delete action, we ignore it
+
+ GeneralRelation rel = new GeneralRelation(lastRelId);
+ long refSize = readUnsignedNum32();
+ long stop = bytesToRead - refSize;
+ while(bytesToRead > stop){
+ Element el = null;
+ long deltaRef = readSignedNum64();
+ int refType = readRelRef();
+ String role = stringPair[1];
+ lastRef[refType] += deltaRef;
+ long memId = lastRef[refType];
+ if (refType == 0){
+ el = saver.getNode(memId);
+ if(el == null) {
+ // we didn't make a node for this point earlier,
+ // do it now (if it exists)
+ Coord co = saver.getCoord(memId);
+ if(co != null) {
+ el = new Node(memId, co);
+ saver.addNode((Node)el);
+ }
+ }
+ }
+ else if (refType == 1){
+ el = saver.getWay(memId);
+ }
+ else if (refType == 2){
+ el = saver.getRelation(memId);
+ if (el == null) {
+ saver.deferRelation(memId, rel, role);
+ }
+ } else {
+ assert false;
+ }
+ if (el != null) // ignore non existing ways caused by splitting files
+ rel.addElement(role, el);
+ }
+ boolean tagsIncomplete = readTags(rel);
+ if (tagsIncomplete) {
+ String relType = rel.getTag("type");
+ if ("multipolygon".equals(relType) || "boundary".equals(relType)) {
+ // mark the multipolygons if there are some tags that are not loaded
+ rel.addTag(TAGS_INCOMPLETE_TAG, "true");
+ }
+ }
+ saver.addRelation(rel);
+ }
+
+ private boolean readTags(Element elem) throws IOException{
+ boolean tagsIncomplete = false;
+ while (bytesToRead > 0){
+ readStringPair();
+ String key = stringPair[0];
+ String val = stringPair[1];
+ // the type tag is required for relations - all other tags are filtered
+ if (elem instanceof Relation && "type".equals(key))
+ // intern the string
+ key = "type";
+ else
+ key = keepTag(key, val);
+ if (key != null)
+ elem.addTag(key, val.intern());
+ else
+ tagsIncomplete = true;
+ }
+ assert bytesToRead == 0;
+ return tagsIncomplete;
+ }
+ /**
+ * Store a new string pair (length check must be performed by caller)
+ */
+ private void storeStringPair(){
+ stringTable[0][currStringTablePos] = stringPair[0];
+ stringTable[1][currStringTablePos] = stringPair[1];
+ ++currStringTablePos;
+ if (currStringTablePos >= STRING_TABLE_SIZE)
+ currStringTablePos = 0;
+ }
+
+ /**
+ * set stringPair to the values referenced by given string reference
+ * No checking is performed.
+ * @param ref valid values are 1 .. STRING_TABLE_SIZE
+ */
+ private void setStringRefPair(int ref){
+ int pos = currStringTablePos - ref;
+ if (pos < 0)
+ pos += STRING_TABLE_SIZE;
+ stringPair[0] = stringTable[0][pos];
+ stringPair[1] = stringTable[1][pos];
+ }
+
+ /**
+ * Read version, time stamp and change set and author.
+ * We are not interested in the values, but we have to maintain the string table.
+ * @throws IOException
+ */
+
+ private void readVersionTsAuthor() throws IOException {
+ int version = readUnsignedNum32();
+ if (version != 0){
+ // version info
+ long ts = readSignedNum64() + lastTs; lastTs = ts;
+ if (ts != 0){
+ long changeSet = readSignedNum32() + lastChangeSet; lastChangeSet = changeSet;
+ readAuthor();
+ }
+ }
+ }
+ /**
+ * Read author .
+ * @throws IOException
+ */
+ private void readAuthor() throws IOException{
+ int stringRef = readUnsignedNum32();
+ if (stringRef == 0){
+ long toReadStart = bytesToRead;
+ long uidNum = readUnsignedNum64();
+ if (uidNum == 0)
+ stringPair[0] = "";
+ else{
+ stringPair[0] = Long.toString(uidNum);
+ ioPos++; // skip terminating zero from uid
+ --bytesToRead;
+ }
+ int start = 0;
+ int buffPos = 0;
+ stringPair[1] = null;
+ while(stringPair[1] == null){
+ final int b = ioBuf[ioPos++];
+ --bytesToRead;
+ cnvBuffer[buffPos++] = (byte) b;
+
+ if (b == 0)
+ stringPair[1] = new String(cnvBuffer, start, buffPos-1, "UTF-8");
+ }
+ long bytes = toReadStart - bytesToRead;
+ if (bytes <= MAX_STRING_PAIR_SIZE)
+ storeStringPair();
+ }
+ else
+ setStringRefPair(stringRef);
+
+ //System.out.println(pair[0]+ "/" + pair[1]);
+ }
+
+ /**
+ * read object type ("0".."2") concatenated with role (single string)
+ * @return 0..3 for type (3 means unknown)
+ */
+ private int readRelRef () throws IOException{
+ int refType = -1;
+ long toReadStart = bytesToRead;
+ int stringRef = readUnsignedNum32();
+ if (stringRef == 0){
+ refType = ioBuf[ioPos++] - 0x30;
+ --bytesToRead;
+
+ if (refType < 0 || refType > 2)
+ refType = 3;
+ stringPair[0] = REL_REF_TYPES[refType];
+
+ int start = 0;
+ int buffPos = 0;
+ stringPair[1] = null;
+ while(stringPair[1] == null){
+ final int b = ioBuf[ioPos++];
+ --bytesToRead;
+ cnvBuffer[buffPos++] = (byte)b;
+
+ if (b == 0)
+ stringPair[1] = new String(cnvBuffer, start, buffPos-1, "UTF-8");
+ }
+ long bytes = toReadStart - bytesToRead;
+ if (bytes <= MAX_STRING_PAIR_SIZE)
+ storeStringPair();
+ }
+ else {
+ setStringRefPair(stringRef);
+ char c = stringPair[0].charAt(0);
+ switch (c){
+ case 'n': refType = 0; break;
+ case 'w': refType = 1; break;
+ case 'r': refType = 2; break;
+ default: refType = 3;
+ }
+ }
+ return refType;
+ }
+
+ /**
+ * read a string pair (see o5m definition)
+ * @throws IOException
+ */
+ private void readStringPair() throws IOException{
+ int stringRef = readUnsignedNum32();
+ if (stringRef == 0){
+ long toReadStart = bytesToRead;
+ int cnt = 0;
+ int buffPos = 0;
+ int start = 0;
+ while (cnt < 2){
+ final int b = ioBuf[ioPos++];
+ --bytesToRead;
+ cnvBuffer[buffPos++] = (byte)b;
+
+ if (b == 0){
+ stringPair[cnt] = new String(cnvBuffer, start, buffPos-start-1, "UTF-8");
+ ++cnt;
+ start = buffPos;
+ }
+ }
+ long bytes = toReadStart - bytesToRead;
+ if (bytes <= MAX_STRING_PAIR_SIZE)
+ storeStringPair();
+ }
+ else
+ setStringRefPair(stringRef);
+ }
+
+ /** reset the delta values and string table */
+ private void reset(){
+ lastNodeId = 0; lastWayId = 0; lastRelId = 0;
+ lastRef[0] = 0; lastRef[1] = 0;lastRef[2] = 0;
+ lastTs = 0; lastChangeSet = 0;
+ lastLon = 0; lastLat = 0;
+ stringTable = new String[2][STRING_TABLE_SIZE];
+ currStringTablePos = 0;
+ }
+
+ /**
+ * read and verify o5m header (known values are o5m2 and o5c2)
+ * @throws IOException
+ */
+ private void readHeader() throws IOException {
+ if (ioBuf[0] != 'o' || ioBuf[1] != '5' || (ioBuf[2]!='c'&&ioBuf[2]!='m') ||ioBuf[3] != '2' ){
+ throw new IOException("unsupported header");
+ }
+ }
+
+ /**
+ * read a varying length signed number (see o5m definition)
+ * @return the number
+ * @throws IOException
+ */
+ private int readSignedNum32() {
+ int result;
+ int b = ioBuf[ioPos++];
+ --bytesToRead;
+ result = b;
+ if ((b & 0x80) == 0){ // just one byte
+ if ((b & 0x01) == 1)
+ return -1-(result>>1);
+ else
+ return result>>1;
+ }
+ int sign = b & 0x01;
+ result = (result & 0x7e)>>1;
+ int fac = 0x40;
+ while (((b = ioBuf[ioPos++]) & 0x80) != 0){ // more bytes will follow
+ --bytesToRead;
+ result += fac * (b & 0x7f) ;
+ fac <<= 7;
+ }
+ --bytesToRead;
+ result += fac * b;
+ if (sign == 1) // negative
+ return -1-result;
+ else
+ return result;
+
+ }
+
+ /**
+ * read a varying length signed number (see o5m definition)
+ * @return the number
+ * @throws IOException
+ */
+ private long readSignedNum64() {
+ long result;
+ int b = ioBuf[ioPos++];
+ --bytesToRead;
+ result = b;
+ if ((b & 0x80) == 0){ // just one byte
+ if ((b & 0x01) == 1)
+ return -1-(result>>1);
+ else
+ return result>>1;
+ }
+ int sign = b & 0x01;
+ result = (result & 0x7e)>>1;
+ long fac = 0x40;
+ while (((b = ioBuf[ioPos++]) & 0x80) != 0){ // more bytes will follow
+ --bytesToRead;
+ result += fac * (b & 0x7f) ;
+ fac <<= 7;
+ }
+ --bytesToRead;
+ result += fac * b;
+ if (sign == 1) // negative
+ return -1-result;
+ else
+ return result;
+
+ }
+
+ /**
+ * read a varying length unsigned number (see o5m definition)
+ * @return a long
+ * @throws IOException
+ */
+ private long readUnsignedNum64FromStream()throws IOException {
+ int b = is.read();
+ --bytesToRead;
+ long result = b;
+ if ((b & 0x80) == 0){ // just one byte
+ return result;
+ }
+ result &= 0x7f;
+ long fac = 0x80;
+ while (((b = is.read()) & 0x80) != 0){ // more bytes will follow
+ --bytesToRead;
+ result += fac * (b & 0x7f) ;
+ fac <<= 7;
+ }
+ --bytesToRead;
+ result += fac * b;
+ return result;
+ }
+
+
+ /**
+ * read a varying length unsigned number (see o5m definition)
+ * @return a long
+ * @throws IOException
+ */
+ private long readUnsignedNum64(){
+ int b = ioBuf[ioPos++];
+ --bytesToRead;
+ long result = b;
+ if ((b & 0x80) == 0){ // just one byte
+ return result;
+ }
+ result &= 0x7f;
+ long fac = 0x80;
+ while (((b = ioBuf[ioPos++]) & 0x80) != 0){ // more bytes will follow
+ --bytesToRead;
+ result += fac * (b & 0x7f) ;
+ fac <<= 7;
+ }
+ --bytesToRead;
+ result += fac * b;
+ return result;
+ }
+
+ /**
+ * read a varying length unsigned number (see o5m definition)
+ * is similar to the 64 bit version.
+ * @return an int
+ * @throws IOException
+ */
+ private int readUnsignedNum32(){
+ int b = ioBuf[ioPos++];
+ --bytesToRead;
+ int result = b;
+ if ((b & 0x80) == 0){ // just one byte
+ return result;
+ }
+ result &= 0x7f;
+ long fac = 0x80;
+ while (((b = ioBuf[ioPos++]) & 0x80) != 0){ // more bytes will follow
+ --bytesToRead;
+ result += fac * (b & 0x7f) ;
+ fac <<= 7;
+ }
+ --bytesToRead;
+ result += fac * b;
+ return result;
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/o5m/O5mBinMapDataSource.java b/src/uk/me/parabola/mkgmap/reader/osm/o5m/O5mBinMapDataSource.java
new file mode 100644
index 0000000..9a038de
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/o5m/O5mBinMapDataSource.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010 - 2012.
+ *
+ * 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.reader.osm.o5m;
+
+import java.io.InputStream;
+
+import uk.me.parabola.imgfmt.FormatException;
+import uk.me.parabola.mkgmap.reader.osm.OsmMapDataSource;
+
+/**
+ * Read an OpenStreetMap data file in .o5m format. It is converted
+ * into a generic format that the map is built from.
+ * <p>The intermediate format is important as several passes are required to
+ * produce the map at different zoom levels. At lower resolutions, some roads
+ * will have fewer points or won't be shown at all.
+ *
+ * @author GerdP
+ */
+public class O5mBinMapDataSource extends OsmMapDataSource {
+
+ @Override
+ public boolean isFileSupported(String name) {
+ return name.endsWith(".o5m");
+ }
+
+
+ @Override
+ public void load(InputStream is) throws FormatException {
+
+ O5mBinHandler handler = new O5mBinHandler(is);
+
+ setupHandler(handler);
+
+ handler.parse();
+ handler = null;
+ elementSaver.finishLoading();
+
+ osmReadingHooks.end();
+ osmReadingHooks = null;
+
+ // now convert the saved elements
+ elementSaver.convert(getConverter());
+
+ addBackground();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/o5m/package.html b/src/uk/me/parabola/mkgmap/reader/osm/o5m/package.html
new file mode 100644
index 0000000..26eb205
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/o5m/package.html
@@ -0,0 +1,22 @@
+<!--
+ ~ Copyright (C) 2012.
+ ~
+ ~ 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.
+ -->
+<body>
+<h1>Reader for OSM binary format</h1>
+<p>There are a number of binary formats, this format is Markus Webers
+o5m format.</p>
+
+<p>The format is a storage format designed to be quicker and smaller than the
+XML format but preserve the element ordering and features of that format.
+We can therefore pretty much re-use most of the code that is used for reading the
+XML format.</p>
+</body>
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/package.html b/src/uk/me/parabola/mkgmap/reader/osm/package.html
new file mode 100644
index 0000000..8e559c8
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/package.html
@@ -0,0 +1,61 @@
+<body>
+<h3>OpenStreetMap converter</h3>
+
+<p>
+ This package has the code to read in a file that is in the Open Street Map
+ format (.osm files). OSM uses an XML format. The bulk of the code exists
+ to map from the OSM format to the garmin types. In general we need
+ to look at several tags to decide on the correct garmin feature type to
+ use. The initial versions of mkgmap could only deal with cases where
+ a single tag value was sufficient. This was simple and works for a large
+ number of cases, but makes some things completely impossible.
+ The <em>new style system</em> will remove this limitation.
+
+<p>
+ Version 0.4 of the api is no longer supported.
+
+<h4>OSM api version 0.5</h4>
+
+<p>This version of the format does away with segments. Ways are sequences of
+nodes. As such it matches the format that we require for the Garmin maps
+much closer than the previous version of the api. Ways cannot branch or have
+out of order segments, so all the code that deals with that is not required.</p>
+
+<h3>About the conversion</h3>
+<p>The following features of the OSM format need to be addressed to create
+the map.
+
+<ul>
+ <li>There is no way to tell a polygon from a line feature apart from
+ looking at the type of feature it is and going from there. Note that a
+ line feature may form a loop (eg a roundabout, circular path in a park
+ etc.) so you can't use that. </li>
+
+ <li>Map features are represented by tags. There is no fixed list of
+ tags and what they mean and new ones can be made up at any time. You
+ do not know which tag is telling you the type of the feature and which
+ tags are just incidental. It is also possible that you need to look at
+ more than one tag to get the map feature. For example with towns you
+ may want to look at the population tag to work out how it is to be
+ represented in Garmin features. We have to have a look up table that
+ maps OSM tags to garmin types and subtypes.</li>
+</ul>
+
+<h3>New Style Converter</h3>
+<p>With this style converter you can have several named styles which
+can be built into mkgmap. A style consists of a number of different
+files held in a directory. The different files mean that there is
+a lot more flexibility available.</p>
+
+<h4>Files</h4>
+The version 0 list of files is as follows.
+<dl>
+ <dt>version</dt>
+ <dd>Every style must have a version file. It contains a single number.</dd>
+
+ <dt>map-features.csv</dt>
+ <dd>This is the map features file exactly as before.</dd>
+</dl>
+
+
+</body>
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5CoastDataSource.java b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5CoastDataSource.java
new file mode 100644
index 0000000..480edcc
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5CoastDataSource.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010, 2012.
+ *
+ * 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.reader.osm.xml;
+
+import java.util.Collections;
+import java.util.Set;
+
+import uk.me.parabola.mkgmap.reader.osm.CoastlineElementSaver;
+import uk.me.parabola.mkgmap.reader.osm.OsmReadingHooks;
+
+public class Osm5CoastDataSource extends Osm5MapDataSource {
+
+ private static final Set<String> coastlineTags = Collections.singleton("natural");
+
+ protected void addBackground(boolean mapHasPolygon4B) {
+ // do not add a background polygon
+ }
+
+ protected OsmReadingHooks[] getPossibleHooks() {
+ // no hooks
+ return new OsmReadingHooks[] {};
+ }
+
+ protected void createElementSaver() {
+ elementSaver = new CoastlineElementSaver(getConfig());
+ }
+
+ public Set<String> getUsedTags() {
+ return coastlineTags;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5MapDataSource.java b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5MapDataSource.java
new file mode 100644
index 0000000..a0f5df6
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5MapDataSource.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2010 - 2012.
+ *
+ * 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.reader.osm.xml;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import uk.me.parabola.imgfmt.FormatException;
+import uk.me.parabola.mkgmap.reader.osm.OsmMapDataSource;
+
+import org.xml.sax.SAXException;
+
+
+/**
+ * Read an OpenStreetMap data file in .osm version 0.5 format. It is converted
+ * into a generic format that the map is built from.
+ * <p>The intermediate format is important as several passes are required to
+ * produce the map at different zoom levels. At lower resolutions, some roads
+ * will have fewer points or won't be shown at all.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Osm5MapDataSource extends OsmMapDataSource {
+
+ @Override
+ public boolean isFileSupported(String name) {
+ // This is the default format so say supported if we get this far,
+ // this one must always be last for this reason.
+ return true;
+ }
+
+ @Override
+ public void load(InputStream is) throws FormatException {
+ try {
+ SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+ parserFactory.setXIncludeAware(true);
+ parserFactory.setNamespaceAware(true);
+ SAXParser parser = parserFactory.newSAXParser();
+
+ try {
+ Osm5XmlHandler handler = new Osm5XmlHandler(getConfig());
+ Osm5XmlHandler.SaxHandler saxHandler = handler.new SaxHandler();
+
+ setupHandler(handler);
+ handler = null;
+
+ // parse the xml file
+ parser.parse(is, saxHandler);
+
+ elementSaver.finishLoading();
+
+ osmReadingHooks.end();
+ osmReadingHooks = null;
+
+ // now convert the saved elements
+ elementSaver.convert(getConverter());
+
+ addBackground();
+
+ } catch (IOException e) {
+ throw new FormatException("Error reading file", e);
+ }
+ } catch (SAXException e) {
+ throw new FormatException("Error parsing file", e);
+ } catch (ParserConfigurationException e) {
+ throw new FormatException("Internal error configuring xml parser", e);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5PrecompSeaDataSource.java b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5PrecompSeaDataSource.java
new file mode 100644
index 0000000..e764436
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5PrecompSeaDataSource.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.reader.osm.xml;
+
+import java.util.Collections;
+import java.util.Set;
+
+import uk.me.parabola.mkgmap.reader.osm.OsmReadingHooks;
+import uk.me.parabola.mkgmap.reader.osm.PrecompSeaElementSaver;
+
+public class Osm5PrecompSeaDataSource extends Osm5MapDataSource {
+
+ private static final Set<String> coastlineTags = Collections.singleton("natural");
+
+ protected void addBackground(boolean mapHasPolygon4B) {
+ // do not add a background polygon
+ }
+
+ protected OsmReadingHooks[] getPossibleHooks() {
+ // no hooks
+ return new OsmReadingHooks[] {};
+ }
+
+ public Set<String> getUsedTags() {
+ return coastlineTags;
+ }
+
+ protected void createElementSaver() {
+ elementSaver = new PrecompSeaElementSaver(getConfig());
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
new file mode 100644
index 0000000..c295b20
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2006 - 2012.
+ *
+ * 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.reader.osm.xml;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.GeneralRelation;
+import uk.me.parabola.mkgmap.reader.osm.Node;
+import uk.me.parabola.mkgmap.reader.osm.OsmHandler;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.EnhancedProperties;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Reads and parses the OSM XML format.
+ *
+ * Creates the nodes/ways and relations that are read from the file and passes
+ * them to the OsmCollector.
+ *
+ * It should not examine tags, or do anything else.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Osm5XmlHandler extends OsmHandler {
+ private static final Logger log = Logger.getLogger(Osm5XmlHandler.class);
+
+ // Set to the currently processing element.
+ private int mode;
+
+ // Values for mode above.
+ private static final int MODE_NODE = 1;
+ private static final int MODE_WAY = 2;
+ private static final int MODE_BOUND = 3;
+ private static final int MODE_RELATION = 4;
+ private static final int MODE_BOUNDS = 5;
+
+ // Options
+ private final boolean ignoreBounds;
+ // Current state.
+ protected Node currentNode;
+ protected Way currentWay;
+ protected Relation currentRelation;
+ protected long currentElementId;
+
+ public Osm5XmlHandler(EnhancedProperties props) {
+ ignoreBounds = props.getProperty("ignore-osm-bounds", false);
+ }
+
+ /**
+ * The XML handler callbacks.
+ *
+ * Need an inner class here so that the top class can inherit from OsmHandler.
+ */
+ public class SaxHandler extends DefaultHandler {
+
+ /**
+ * Receive notification of the start of an element.
+ *
+ * @param uri The Namespace URI, or the empty string if the
+ * element has no Namespace URI or if Namespace
+ * processing is not being performed.
+ * @param localName The local name (without prefix), or the
+ * empty string if Namespace processing is not being
+ * performed.
+ * @param qName The qualified name (with prefix), or the
+ * empty string if qualified names are not available.
+ * @param attributes The attributes attached to the element. If
+ * there are no attributes, it shall be an empty
+ * Attributes object.
+ * @throws SAXException Any SAX exception, possibly
+ * wrapping another exception.
+ * @see ContentHandler#startElement
+ */
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ if (mode == 0) {
+ if (qName.equals("node")) {
+ mode = MODE_NODE;
+ startNode(attributes.getValue("id"),
+ attributes.getValue("lat"),
+ attributes.getValue("lon"));
+
+ } else if (qName.equals("way")) {
+ mode = MODE_WAY;
+ startWay(attributes.getValue("id"));
+
+ } else if (qName.equals("relation")) {
+ mode = MODE_RELATION;
+ currentRelation = new GeneralRelation(idVal(attributes.getValue("id")));
+
+ } else if (qName.equals("bound")) {
+ mode = MODE_BOUND;
+ if(!ignoreBounds) {
+ String box = attributes.getValue("box");
+ setupBBoxFromBound(box);
+ }
+
+ } else if (qName.equals("bounds")) {
+ mode = MODE_BOUNDS;
+ if(!ignoreBounds)
+ setupBBoxFromBounds(attributes);
+ }
+
+ } else if (mode == MODE_NODE) {
+ startInNode(qName, attributes);
+ } else if (mode == MODE_WAY) {
+ startInWay(qName, attributes);
+ } else if (mode == MODE_RELATION) {
+ startInRelation(qName, attributes);
+ }
+ }
+
+ /**
+ * Receive notification of the end of an element.
+ *
+ * @param uri The Namespace URI, or the empty string if the
+ * element has no Namespace URI or if Namespace
+ * processing is not being performed.
+ * @param localName The local name (without prefix), or the
+ * empty string if Namespace processing is not being
+ * performed.
+ * @param qName The qualified name (with prefix), or the
+ * empty string if qualified names are not available.
+ * @throws SAXException Any SAX exception, possibly
+ * wrapping another exception.
+ * @see ContentHandler#endElement
+ */
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ if (mode == MODE_NODE) {
+ if (qName.equals("node")) {
+ mode = 0;
+ if (currentNode != null) {
+ saver.addNode(currentNode);
+ hooks.onAddNode(currentNode);
+ }
+ currentElementId = 0;
+ currentNode = null;
+ }
+
+ } else if (mode == MODE_WAY) {
+ if (qName.equals("way")) {
+ mode = 0;
+
+ endWay(currentWay);
+ currentWay = null;
+ }
+
+ } else if (mode == MODE_BOUND) {
+ if (qName.equals("bound"))
+ mode = 0;
+
+ } else if (mode == MODE_BOUNDS) {
+ if (qName.equals("bounds"))
+ mode = 0;
+
+ } else if (mode == MODE_RELATION) {
+ if (qName.equals("relation")) {
+ mode = 0;
+
+ // remove the mkgmap:tagsincomplete tags which is used in multipolygons only
+ if (currentRelation.getTag(TAGS_INCOMPLETE_TAG) != null) {
+ String type = currentRelation.getTag("type");
+ if ("multipolygon".equals(type) == false && "boundary".equals(type) == false) {
+ currentRelation.deleteTag(TAGS_INCOMPLETE_TAG);
+ }
+ }
+
+ saver.addRelation(currentRelation);
+ }
+ }
+ }
+
+ /**
+ * Called on an XML error. Attempt to print a line number to aid in
+ * working out the problem.
+ * @throws SAXException
+ */
+ public void fatalError(SAXParseException e) throws SAXException {
+ System.err.println("Error at line " + e.getLineNumber() + ", col "
+ + e.getColumnNumber());
+ super.fatalError(e);
+ }
+ }
+
+ /**
+ * A new tag has been started while we are inside a node element.
+ * @param qName The new tag name.
+ * @param attributes Its attributes.
+ */
+ private void startInNode(String qName, Attributes attributes) {
+ if (qName.equals("tag")) {
+ String key = attributes.getValue("k");
+ String val = attributes.getValue("v");
+
+ // We only want to create a full node for nodes that are POI's
+ // and not just one point of a way. Only create if it has tags that
+ // could be used in a POI.
+ key = keepTag(key, val);
+ if (key != null) {
+ if (currentNode == null) {
+ Coord co = saver.getCoord(currentElementId);
+ currentNode = new Node(currentElementId, co);
+ }
+
+ currentNode.addTag(key, val.intern());
+ }
+ }
+ }
+
+ /**
+ * A new tag has been started while we are inside a way element.
+ * @param qName The new tag name.
+ * @param attributes Its attributes.
+ */
+ private void startInWay(String qName, Attributes attributes) {
+ if (qName.equals("nd")) {
+ long id = idVal(attributes.getValue("ref"));
+ addCoordToWay(currentWay, id);
+ } else if (qName.equals("tag")) {
+ String key = attributes.getValue("k");
+ String val = attributes.getValue("v");
+ key = keepTag(key, val);
+ if (key != null)
+ currentWay.addTag(key, val.intern());
+ }
+ }
+
+ /**
+ * A new tag has been started while we are inside the relation tag.
+ * @param qName The new tag name.
+ * @param attributes Its attributes.
+ */
+ private void startInRelation(String qName, Attributes attributes) {
+ if (qName.equals("member")) {
+ long id = idVal(attributes.getValue("ref"));
+ Element el;
+ String type = attributes.getValue("type");
+ if ("way".equals(type)){
+ el = saver.getWay(id);
+ } else if ("node".equals(type)) {
+ el = saver.getNode(id);
+ if(el == null) {
+ // we didn't make a node for this point earlier,
+ // do it now (if it exists)
+ Coord co = saver.getCoord(id);
+ if(co != null) {
+ el = new Node(id, co);
+ saver.addNode((Node)el);
+ }
+ }
+ } else if ("relation".equals(type)) {
+ el = saver.getRelation(id);
+ if (el == null) {
+ saver.deferRelation(id, currentRelation, attributes.getValue("role"));
+ }
+ } else
+ el = null;
+ if (el != null) // ignore non existing ways caused by splitting files
+ currentRelation.addElement(attributes.getValue("role"), el);
+ } else if (qName.equals("tag")) {
+ String key = attributes.getValue("k");
+ String val = attributes.getValue("v");
+ // the type tag is required for relations - all other tags are filtered
+ if ("type".equals(key))
+ // intern the key
+ key = "type";
+ else
+ key = keepTag(key, val);
+ if (key == null) {
+ currentRelation.addTag(TAGS_INCOMPLETE_TAG, "true");
+ } else {
+ currentRelation.addTag(key, val.intern());
+ }
+ }
+ }
+
+ /**
+ * Set a bounding box from the bounds element.
+ * There are two ways of specifying a bounding box in the XML format, this
+ * one uses attributes of the element to give the bounds.
+ * @param xmlattr The bounds element attributes.
+ */
+ private void setupBBoxFromBounds(Attributes xmlattr) {
+ try {
+ setBBox(Double.parseDouble(xmlattr.getValue("minlat")),
+ Double.parseDouble(xmlattr.getValue("minlon")),
+ Double.parseDouble(xmlattr.getValue("maxlat")),
+ Double.parseDouble(xmlattr.getValue("maxlon")));
+ } catch (NumberFormatException e) {
+ // just ignore it
+ log.warn("NumberformatException: Cannot read bbox");
+ }
+ }
+
+ /**
+ * Set a bounding box from the bound element. There are two ways of
+ * specifying a bounding box, this one has a single 'box' attribute that
+ * is a comma separated list of the bounds values.
+ * @param box The value of the box attribute.
+ */
+ private void setupBBoxFromBound(String box) {
+ String[] f = box.split(",");
+ try {
+ setBBox(Double.parseDouble(f[0]), Double.parseDouble(f[1]),
+ Double.parseDouble(f[2]), Double.parseDouble(f[3]));
+ } catch (NumberFormatException e) {
+ // just ignore it
+ log.warn("NumberformatException: Cannot read bbox");
+ }
+ }
+
+ /**
+ * Save node information. Consists of a location specified by lat/long.
+ *
+ * @param sid The id as a string.
+ * @param slat The lat as a string.
+ * @param slon The longitude as a string.
+ */
+ private void startNode(String sid, String slat, String slon) {
+ if (sid == null || slat == null || slon == null)
+ return;
+
+ try {
+ long id = idVal(sid);
+
+ Coord co = new Coord(Double.parseDouble(slat), Double.parseDouble(slon));
+ saver.addPoint(id, co);
+ currentElementId = id;
+ } catch (NumberFormatException e) {
+ // ignore bad numeric data. The coord will be discarded
+ }
+ }
+
+ /**
+ * A new way element has been seen.
+ * @param sid The way id as a string.
+ */
+ private void startWay(String sid) {
+ try {
+ long id = idVal(sid);
+ currentWay = startWay(id);
+ } catch (NumberFormatException e) {
+ // ignore bad numeric data. The way will be discarded
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java b/src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java
new file mode 100644
index 0000000..0091875
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java
@@ -0,0 +1,165 @@
+/*
+ * 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: 25-Sep-2007
+ */
+package uk.me.parabola.mkgmap.reader.overview;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+import uk.me.parabola.imgfmt.FormatException;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.CoordNode;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.combiners.OverviewMap;
+import uk.me.parabola.mkgmap.general.LevelInfo;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapPoint;
+import uk.me.parabola.mkgmap.general.MapRoad;
+import uk.me.parabola.mkgmap.general.MapShape;
+import uk.me.parabola.mkgmap.reader.MapperBasedMapDataSource;
+
+/**
+ * Class for creating an overview map. Nothing is actually read in from a file,
+ * we just save some detail from the other img files that are going into the
+ * map set.
+ *
+ * @author Steve Ratcliffe
+ */
+public class OverviewMapDataSource extends MapperBasedMapDataSource
+ implements OverviewMap
+{
+ private static final Logger log = Logger.getLogger(OverviewMapDataSource.class);
+
+ private final List<String> copyrights = new ArrayList<String>();
+ LevelInfo[] levels = null;
+
+ /**
+ * This is a fake source of data and is not read from a file, so always
+ * return false here.
+ *
+ * @param name The filename, ignored.
+ * @return Always false.
+ */
+ public boolean isFileSupported(String name) {
+ return false;
+ }
+
+ /*
+ * This is never called as isFileSupported always returns false.
+ */
+ public void load(String name) throws FileNotFoundException, FormatException {
+ throw new FileNotFoundException("This is not supposed to be called");
+ }
+
+ public LevelInfo[] mapLevels() {
+ return levels;
+ }
+
+ public LevelInfo[] overviewMapLevels() {
+ return mapLevels();
+ }
+
+ public void setMapLevels (LevelInfo[] mapLevels) {
+ if (levels == null){
+ levels = mapLevels;
+ } else {
+ boolean ok = true;
+ if (levels.length != mapLevels.length)
+ ok = false;
+ else {
+ for (int i = 0; i < levels.length; i++){
+ if (levels[i].compareTo(mapLevels[i]) != 0){
+ ok = false;
+ }
+ }
+ }
+ if (!ok)
+ log.error("invalid attempt to change map levels" );
+ }
+ }
+
+
+
+ /**
+ * Add a copyright string to the map.
+ *
+ * @param cw The string to add.
+ */
+ public void addCopyright(String cw) {
+ copyrights.add(cw);
+ }
+
+ /**
+ * All the copyright messages that were found in the input files are
+ * returned here.
+ *
+ * @return An array of copyright messages.
+ */
+ public String[] copyrightMessages() {
+ return copyrights.toArray(new String[copyrights.size()]);
+ }
+
+ /**
+ * Add the given point to the total bounds for the map.
+ *
+ * @param p The coordinates of the point to add. The type here will change to
+ * Node.
+ */
+ public void addToBounds(Coord p) {
+ mapper.addToBounds(p);
+ }
+
+ /**
+ * Add a point to the map.
+ *
+ * @param point The point to add.
+ */
+ public void addPoint(MapPoint point) {
+ mapper.addPoint(point);
+ }
+
+ /**
+ * Add a line to the map.
+ *
+ * @param line The line information.
+ */
+ public void addLine(MapLine line) {
+ mapper.addLine(line);
+ }
+
+ /**
+ * Add the given shape (polygon) to the map. A shape is very similar to a line
+ * but they are separate because they need to be put in different sections in
+ * the output map.
+ *
+ * @param shape The polygon to add.
+ */
+ public void addShape(MapShape shape) {
+ mapper.addShape(shape);
+ }
+
+ public void addRoad(MapRoad road) {
+ addLine(road);
+ }
+
+ public void addRestriction(CoordNode fromNode, CoordNode toNode, CoordNode viaNode, byte exceptMask) {
+ getRoadNetwork().addRestriction(fromNode, toNode, viaNode, exceptMask);
+ }
+
+ public void addThroughRoute(long junctionNodeId, long roadIdA, long roadIdB) {
+ getRoadNetwork().addThroughRoute(junctionNodeId, roadIdA, roadIdB);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/overview/package.html b/src/uk/me/parabola/mkgmap/reader/overview/package.html
new file mode 100644
index 0000000..29698da
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/overview/package.html
@@ -0,0 +1,6 @@
+<body>
+<h3>Overview map source</h3>
+
+<p>This is used for creating an overview map out of all the processed maps.
+</p>
+</body>
diff --git a/src/uk/me/parabola/mkgmap/reader/plugin/MapReader.java b/src/uk/me/parabola/mkgmap/reader/plugin/MapReader.java
new file mode 100644
index 0000000..2a0b11d
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/plugin/MapReader.java
@@ -0,0 +1,90 @@
+/*
+ * 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: 02-Sep-2007
+ */
+package uk.me.parabola.mkgmap.reader.plugin;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
+import uk.me.parabola.mkgmap.reader.osm.xml.Osm5MapDataSource;
+
+/**
+ * Class to find the correct map reader to use, based on the type of the file
+ * to be read.
+ *
+ * Allows new map readers to be registered, the map readers are in charge of
+ * recognising file formats that they can deal with.
+ *
+ * @author Steve Ratcliffe
+ */
+public class MapReader {
+
+ private static final List<Class<? extends LoadableMapDataSource>> loaders;
+
+ static {
+ String[] sources = {
+ "uk.me.parabola.mkgmap.reader.osm.bin.OsmBinMapDataSource",
+ "uk.me.parabola.mkgmap.reader.osm.o5m.O5mBinMapDataSource",
+ "uk.me.parabola.mkgmap.reader.polish.PolishMapDataSource",
+ "uk.me.parabola.mkgmap.reader.test.ElementTestDataSource",
+
+ // must be last as it is the default
+ "uk.me.parabola.mkgmap.reader.osm.xml.Osm5MapDataSource",
+ };
+
+ loaders = new ArrayList<Class<? extends LoadableMapDataSource>>();
+
+ for (String source : sources) {
+ try {
+ @SuppressWarnings({"unchecked"})
+ Class<? extends LoadableMapDataSource> c = (Class<? extends LoadableMapDataSource>) Class.forName(source);
+ loaders.add(c);
+ } catch (ClassNotFoundException e) {
+ // not available, try the rest
+ } catch (NoClassDefFoundError e) {
+ // not available, try the rest
+ }
+ }
+ }
+
+ /**
+ * Return a suitable map reader. The name of the resource to be read is
+ * passed in. This is usually a file name, but could be something else.
+ *
+ * @param name The resource name to be read.
+ * @return A LoadableMapDataSource that is capable of reading the resource.
+ */
+ public static LoadableMapDataSource createMapReader(String name) {
+ for (Class<? extends LoadableMapDataSource> loader : loaders) {
+ try {
+ LoadableMapDataSource src = loader.newInstance();
+ if (name != null && src.isFileSupported(name))
+ return src;
+ } catch (InstantiationException e) {
+ // try the next one.
+ } catch (IllegalAccessException e) {
+ // try the next one.
+ } catch (NoClassDefFoundError e) {
+ // try the next one
+ }
+ }
+
+ // Give up and assume it is in the XML format. If it isn't we will get an
+ // error soon enough anyway.
+ return new Osm5MapDataSource();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java b/src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java
new file mode 100644
index 0000000..1ce7b8c
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java
@@ -0,0 +1,859 @@
+/*
+ * 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 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.RouteRestriction;
+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;
+
+ // Use to decode labels if they are not in cp1252
+ private CharsetDecoder dec;
+
+ 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);
+ }
+
+ 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() {
+ // TODO Auto-generated method stub
+ 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<Coord>(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<Coord>(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) {
+ 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<String, String>();
+ 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<String, String>();
+ extraAttributes.put(name, value);
+ }
+ }
+
+ private List<Coord> coordsFromString(String value) {
+ String[] ords = value.split("\\) *, *\\(");
+ List<Coord> points = new ArrayList<Coord>();
+
+ 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<String, String>();
+ 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("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(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);
+ }
+ }
+
+ /**
+ * 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]);
+ return new Coord(f1, f2);
+ }
+
+ private ExtTypeAttributes makeExtTypeAttributes() {
+ Map<String, String> eta = new HashMap<String, String>();
+ 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\n" +
+ "from 3 roads are not yet supported\n");
+ }
+ } 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
+ */
+ 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:
+ // Mask is not known for Emergency.
+ break;
+ case 1:
+ exceptMask |= RouteRestriction.EXCEPT_DELIVERY;
+ break;
+ case 2:
+ exceptMask |= RouteRestriction.EXCEPT_CAR;
+ break;
+ case 3:
+ exceptMask |= RouteRestriction.EXCEPT_BUS;
+ break;
+ case 4:
+ exceptMask |= RouteRestriction.EXCEPT_TAXI;
+ break;
+ case 5:
+ // Mask is not known for Pedestrian.
+ break;
+ case 6:
+ exceptMask |= RouteRestriction.EXCEPT_BICYCLE;
+ break;
+ case 7:
+ exceptMask |= RouteRestriction.EXCEPT_TRUCK;
+ break;
+ }
+ }
+ }
+ } else {
+ log.error("Invalid RestrParam definition. -> " + value);
+ }
+
+ return exceptMask;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/polish/PolishTurnRestriction.java b/src/uk/me/parabola/mkgmap/reader/polish/PolishTurnRestriction.java
new file mode 100644
index 0000000..6fd32ef
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/polish/PolishTurnRestriction.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2010, 2012.
+ *
+ * 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.reader.polish;
+
+/**
+ * Holder for each turn restriction definition.
+ * @author Supun Jayathilake
+ */
+public class PolishTurnRestriction {
+ private long nodId;
+ private long toNodId;
+ private long fromNodId;
+ private long roadIdA;
+ private long roadIdB;
+ private byte exceptMask;
+
+
+ // Consider as a valid node upon the instantiation.
+ private boolean valid = true;
+
+ public boolean isValid() {
+ return valid;
+ }
+
+ public void setValid(boolean valid) {
+ this.valid = valid;
+ }
+
+ public long getNodId() {
+ return nodId;
+ }
+
+ public void setNodId(long nodId) {
+ this.nodId = nodId;
+ }
+
+ public long getToNodId() {
+ return toNodId;
+ }
+
+ public void setToNodId(long toNodId) {
+ this.toNodId = toNodId;
+ }
+
+ public long getFromNodId() {
+ return fromNodId;
+ }
+
+ public void setFromNodId(long fromNodId) {
+ this.fromNodId = fromNodId;
+ }
+
+ public long getRoadIdA() {
+ return roadIdA;
+ }
+
+ public void setRoadIdA(long roadIdA) {
+ this.roadIdA = roadIdA;
+ }
+
+ public long getRoadIdB() {
+ return roadIdB;
+ }
+
+ public void setRoadIdB(long roadIdB) {
+ this.roadIdB = roadIdB;
+ }
+
+ public byte getExceptMask() {
+ return exceptMask;
+ }
+
+ public void setExceptMask(byte exceptMask) {
+ this.exceptMask = exceptMask;
+ }
+
+ @Override
+ public String toString() {
+ return "TurnRestriction[FromNodId=" + fromNodId + ", ViaNodId=" + nodId + ", ToNodId=" + toNodId + "]";
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/polish/RestrictionHelper.java b/src/uk/me/parabola/mkgmap/reader/polish/RestrictionHelper.java
new file mode 100644
index 0000000..fe643ab
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/polish/RestrictionHelper.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010, 2012.
+ *
+ * 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.reader.polish;
+
+import uk.me.parabola.imgfmt.app.CoordNode;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.MapDetails;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helps handling turn restrictions for Polish format.
+ * Remembers, and later, after reading through the map,
+ * adds all restrictions to the map.
+ *
+ * Use one instance of this class per file.
+ *
+ * @author Supun Jayathilake
+ */
+public class RestrictionHelper {
+ private static final Logger log = Logger.getLogger(RestrictionHelper.class);
+
+ // Holds all collected restrictions.
+ private final List<PolishTurnRestriction> allRestrictions = new ArrayList<PolishTurnRestriction>();
+
+ public void processAndAddRestrictions(RoadHelper roadHelper, MapDetails mapper) {
+ Map<Long, CoordNode> allNodes = roadHelper.getNodeCoords();
+
+ for (PolishTurnRestriction tr : allRestrictions) {
+ if (tr.isValid()) { // Process only the restrictions marked as valid.
+ CoordNode from = allNodes.get(tr.getFromNodId());
+ CoordNode to = allNodes.get(tr.getToNodId());
+ CoordNode via = allNodes.get(tr.getNodId());
+
+ if (from != null && to != null && via != null) { // All nodes participating in the
+ mapper.addRestriction(from, to, via, tr.getExceptMask()); // restriction should be part of the map
+ } else {
+ log.error("");
+ }
+ }
+ }
+ }
+
+ /**
+ * Restriction collector.
+ * @param restriction Restriction to be added to the map.
+ */
+ public void addRestriction(PolishTurnRestriction restriction) {
+ allRestrictions.add(restriction);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/polish/RoadHelper.java b/src/uk/me/parabola/mkgmap/reader/polish/RoadHelper.java
new file mode 100644
index 0000000..4a2b75b
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/polish/RoadHelper.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2008 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: 04-Aug-2008
+ */
+package uk.me.parabola.mkgmap.reader.polish;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.CoordNode;
+import uk.me.parabola.imgfmt.app.net.NumberStyle;
+import uk.me.parabola.imgfmt.app.net.Numbers;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapRoad;
+
+/**
+ * Used to remember all the road relevant parameters in a definition which
+ * can occur in any order. Also remembers routing nodes and makes sure
+ * the generated MapRoads all have the same RoutingNode objects.
+ *
+ * Use one instance of RoadHelper per file, and reset after reading
+ * each road.
+ */
+class RoadHelper {
+ private static final Logger log = Logger.getLogger(RoadHelper.class);
+
+ private static final int NUM_ACCESS = 8;
+
+ // routing node store, persistent over resets
+ private final Map<Long, CoordNode> nodeCoords = new HashMap<Long, CoordNode>();
+
+ // Next node number to use for nodes constructed for house numbers. Persists over reset.
+ private long houseNumberNodeNumber = 16000000;
+
+ private int roadId;
+ private final List<NodeIndex> nodes = new ArrayList<NodeIndex>();
+
+ private int speed;
+ private int roadClass;
+
+ private boolean oneway;
+ private boolean toll;
+
+ private boolean[] access;
+ private List<Numbers> numbers;
+
+ public RoadHelper() {
+ clear();
+ }
+
+ public void clear() {
+ roadId = 0;
+ nodes.clear();
+
+ speed = 0;
+ roadClass = 0;
+ oneway = false;
+ toll = false;
+ access = new boolean[NUM_ACCESS];
+ numbers = null;
+ }
+
+ public void setRoadId(int roadId) {
+ this.roadId = roadId;
+ }
+
+ public void addNode(String value) {
+ String[] f = value.split(",");
+ nodes.add(new NodeIndex(f));
+ }
+
+ public void setParam(String param) {
+ String[] f = param.split(",");
+ speed = Integer.parseInt(f[0]);
+ roadClass = Integer.parseInt(f[1]);
+ oneway = Integer.parseInt(f[2]) > 0;
+ toll = Integer.parseInt(f[3]) > 0;
+ for (int j = 0; j < f.length - 4; j++)
+ access[j] = Integer.parseInt(f[4+j]) > 0;
+ }
+
+ public MapRoad makeRoad(MapLine l) {
+ assert roadId != 0;
+
+ if (log.isDebugEnabled())
+ log.debug("finishing road id " + roadId);
+
+ MapRoad road = new MapRoad(roadId, l);
+
+ // Set parameters.
+ road.setRoadClass(roadClass);
+ road.setSpeed(speed);
+ if (oneway)
+ road.setOneway();
+ if (toll)
+ road.setToll();
+ road.setAccess(access);
+
+ if (numbers != null && !numbers.isEmpty()) {
+ convertNodesForHouseNumbers();
+ road.setNumbers(numbers);
+ }
+
+ List<Coord> points = road.getPoints();
+ road.setNumNodes(nodes.size());
+
+ boolean starts = false;
+ boolean intern = false;
+ for (NodeIndex ni : nodes) {
+ int n = ni.index;
+ if (n == 0)
+ starts = true;
+ else if (n < points.size() - 1)
+ intern = true;
+ if (log.isDebugEnabled())
+ log.debug("road has " + points.size() +" points");
+ Coord coord = points.get(n);
+ long id = coord.getId();
+ if (id == 0) {
+ CoordNode node = nodeCoords.get((long) ni.nodeId);
+ if (node == null) {
+ node = new CoordNode(coord.getLatitude(), coord.getLongitude(), ni.nodeId, ni.boundary);
+ nodeCoords.put((long) ni.nodeId, node);
+ }
+ points.set(n, node);
+ } else if (id != ni.nodeId) {
+ log.warn("Inconsistant node ids");
+ }
+ }
+ road.setStartsWithNode(starts);
+ road.setInternalNodes(intern);
+
+ return road;
+ }
+
+ /**
+ * Convert the node index into a routing node number.
+ *
+ * If necessary a new routing node is created, if there is not one already
+ * These constructed routing nodes are not connected to any other road and so
+ * should be marked as such in the NOD2 bit stream, but we don't appear to do that yet.
+ *
+ * Only called if numbers is non-null and not empty.
+ */
+ private void convertNodesForHouseNumbers() {
+ for (Numbers n : numbers) {
+ int node = n.getNodeNumber();
+
+ // This assumes that the nodes are sorted by index.
+ ListIterator<NodeIndex> iterator = nodes.listIterator();
+ while (iterator.hasNext()) {
+ NodeIndex ni = iterator.next();
+ if (ni.index == node) {
+ // It was already there (a common case)
+ n.setRnodNumber(iterator.previousIndex());
+ break;
+ } else if (ni.index > node) {
+ // there is no routing node for this node index, need to insert one.
+ break;
+ }
+ }
+
+ // If we don't have a routing node number then we have to construct one.
+ if (!n.hasRnodNumber()) {
+ NodeIndex hnNode = new NodeIndex(new String[] {
+ String.valueOf(node),
+ String.valueOf(houseNumberNodeNumber++),
+ "0"
+ });
+
+ iterator.previous();
+ iterator.add(hnNode);
+ n.setRnodNumber(iterator.previousIndex());
+ //System.out.printf("ADDING RN on %d, hn=%s, rn=%d\n", roadId, hnNode, n.getRnodNumber());
+ }
+ }
+
+ // Sanity checking. TODO remove
+ //int lastInd = -1;
+ //for (NodeIndex n : nodes) {
+ // assert n.index > lastInd;
+ // lastInd = n.index;
+ //
+ //}
+ //System.out.println("start");
+ //Numbers num = null;
+ //for (Numbers n1 : numbers) {
+ // int ncount = 0;
+ // for (NodeIndex n : nodes) {
+ // System.out.printf("n1.node=%d, ni=%s, ni.index=%d\n", n1.getNodeNumber(), n, n.index);
+ // if (n1.getNodeNumber() == n.index) {
+ // num = n1;
+ // break;
+ // }
+ // ncount++;
+ // }
+ // assert num != null && num.getRnodNumber() == ncount;
+ //}
+ }
+
+ public boolean isRoad() {
+ return roadId != 0;
+ }
+
+ public Map<Long, CoordNode> getNodeCoords() {
+ return nodeCoords;
+ }
+
+ public void addNumbers(String value) {
+ if (numbers == null)
+ numbers = new ArrayList<Numbers>();
+ Numbers num = new Numbers(value);
+ if (num.getLeftNumberStyle() != NumberStyle.NONE || num.getRightNumberStyle() != NumberStyle.NONE)
+ numbers.add(num);
+ }
+
+ private static class NodeIndex {
+ private final int index;
+ private final int nodeId;
+ private boolean boundary;
+
+ private NodeIndex(String[] f) {
+ // f[0] is the index into the line
+ // f[1] is the node id
+ // f[2] is whether it's a boundary node
+ index = Integer.parseInt(f[0]);
+ nodeId = Integer.parseInt(f[1]);
+ if (f.length > 2)
+ boundary = Integer.parseInt(f[2]) > 0;
+ if (log.isDebugEnabled())
+ log.debug("ind=%d, node=%d, bound=%b\n", index, nodeId, boundary);
+ }
+
+ public String toString() {
+ return String.format("%d,%d,%b", index, nodeId, boundary);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/polish/package.html b/src/uk/me/parabola/mkgmap/reader/polish/package.html
new file mode 100644
index 0000000..2f20204
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/polish/package.html
@@ -0,0 +1,17 @@
+<body>
+<h3>Polish format input file format</h3>
+<p>This is the input file reader for the <em>Polish</em> format.
+This is the input format for <a href="http://www.cgpsmapper.com">cGPSmapper</a> and
+is also by several other map editing tools.</p>
+
+<p>As the polish format is designed for representing Garmin maps, it is very
+easy to read it into mkgmap, in fact I was a bit suprised how it all just
+worked.
+
+<p>Having said that, this is just a basic implementation and many of the
+command tags in the format are just ignored.</p>
+
+<p>It is a good starting point for someone that is wanting to write a new
+input file plugin for mkgmap as there are no complicating requirements.
+
+</body>
diff --git a/src/uk/me/parabola/mkgmap/reader/test/AllElements.java b/src/uk/me/parabola/mkgmap/reader/test/AllElements.java
new file mode 100644
index 0000000..fc3a609
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/test/AllElements.java
@@ -0,0 +1,224 @@
+/*
+ * 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: 02-Sep-2007
+ */
+package uk.me.parabola.mkgmap.reader.test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.general.MapCollector;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapPoint;
+import uk.me.parabola.mkgmap.general.MapShape;
+
+
+/**
+ * A test map that contains a grid of each point, line and polygon type that
+ * is possible. The name of each element is set to be the numeric type (and
+ * sub-type for points).
+ *
+ * This can be used to decode the type_id's.
+ *
+ * Instructions for use: If you run this program with the environment
+ * variables BASE_LAT and BASE_LONG set to something just SW of where you
+ * are then the map generated will be located near where you are. Otherwise
+ * the default location is at (51.7, 0.24).
+ *
+ * You can then use the find facility of your GPS to
+ * show the near-by points. When viewing a category the menu key will allow
+ * you to select finer categories.
+ *
+ * @author Steve Ratcliffe
+ */
+class AllElements {
+
+ // These values are perhaps bias a bit towards places at mid latitudes,
+ // adjust as required.
+ private static final double ELEMENT_SPACING = 0.002;
+ private static final double ELEMENT_SIZE = 0.001;
+
+ // I don't know what the max types and subtypes actually are, adjust if
+ // there seems to be more beyond.
+ private static final int MAX_POINT_TYPE = 0x7f;
+ private static final int MAX_POINT_SUB_TYPE = 0x30;
+
+ // we draw lines and polygons in a 16x16 square (or whatever is here).
+ private static final int MAX_LINE_TYPE_X = 8;
+ private static final int MAX_LINE_TYPE_Y = 8;
+ private static final int MAX_SHAPE_TYPE_X = 12;
+ private static final int MAX_SHAPE_TYPE_Y = 12;
+
+ /**
+ * Loading the map in this case means generating it.
+ *
+ * @param mapper Used to collect the generated points etc.
+ */
+ public void load(MapCollector mapper) {
+ double baseLat = 51.7;
+
+ String sBaseLat = System.getenv("BASE_LAT");
+ String sBaseLong = System.getenv("BASE_LONG");
+
+ if (sBaseLat != null)
+ baseLat = Double.valueOf(sBaseLat);
+
+ double baseLong = 0.24;
+ if (sBaseLong != null)
+ baseLong = Double.valueOf(sBaseLong);
+
+ drawTestMap(mapper, baseLat, baseLong);
+ }
+
+ /**
+ * We draw points, lines and polygons separately. They should be in
+ * order from west to east of the generated map, starting in the bottom
+ * left hand corner (SW).
+ *
+ * @param map Collector for the generated points etc.
+ * @param startLat The S coord.
+ * @param startLong The W coord.
+ */
+ private void drawTestMap(MapCollector map, double startLat, double startLong) {
+ double lng = startLong;
+
+ drawPoints(map, startLat, lng);
+
+ lng += MAX_POINT_TYPE * ELEMENT_SPACING;
+ drawLines(map, startLat, lng);
+
+ lng += MAX_LINE_TYPE_X * ELEMENT_SPACING;
+ drawPolygons(map, startLat, lng);
+ }
+
+ private void drawPoints(MapCollector mapper, double slat, double slon) {
+
+ double lat = slat + 0.004;
+ double lon = slon + 0.002;
+
+ for (int type = 0; type < MAX_POINT_TYPE; type++) {
+ for (int subtype = 0; subtype < MAX_POINT_SUB_TYPE; subtype++) {
+
+ MapPoint point = new MapPoint();
+
+ double baseLat = lat + subtype * ELEMENT_SPACING;
+ double baseLong = lon + type * ELEMENT_SPACING;
+
+ point.setMinResolution(10);
+ point.setName("0x" + Integer.toHexString(type)
+ + ','
+ + "0x" + Integer.toHexString(subtype));
+
+ point.setLocation(new Coord(baseLat, baseLong));
+ point.setType((type << 8) + subtype);
+
+ mapper.addPoint(point);
+ mapper.addToBounds(point.getLocation()); // XXX shouldn't be needed.
+ }
+ }
+ }
+
+ private void drawLines(MapCollector mapper, double slat, double slon) {
+
+ double lat = slat + 0.004;
+ double lon = slon + 0.002;
+
+ for (int x = 0; x < MAX_LINE_TYPE_X; x++) {
+ for (int y = 0; y < MAX_LINE_TYPE_Y; y++) {
+ int type = x*MAX_LINE_TYPE_X + y;
+ if ((type & 0xc0) != 0)
+ break;
+
+ MapLine line = new MapLine();
+ line.setMinResolution(10);
+ line.setName("0x" + Integer.toHexString(type));
+
+ double baseLat = lat + y * ELEMENT_SPACING;
+ double baseLong = lon + x * ELEMENT_SPACING;
+
+ List<Coord> coords = new ArrayList<Coord>();
+
+ Coord co = new Coord(baseLat, baseLong);
+ coords.add(co);
+ mapper.addToBounds(co);
+
+ co = new Coord(baseLat + ELEMENT_SIZE, baseLong + ELEMENT_SIZE);
+ coords.add(co);
+ mapper.addToBounds(co);
+
+ co = new Coord(baseLat + ELEMENT_SIZE, baseLong + ELEMENT_SIZE + ELEMENT_SIZE/2);
+ coords.add(co);
+ mapper.addToBounds(co);
+
+ line.setType(type);
+ line.setPoints(coords);
+
+ mapper.addLine(line);
+ }
+ }
+ }
+
+
+ private void drawPolygons(MapCollector mapper, double slat, double slon) {
+
+ double lat = slat + 0.004;
+ double lon = slon + 0.002;
+
+ for (int x = 0; x < MAX_SHAPE_TYPE_X; x++) {
+ for (int y = 0; y < MAX_SHAPE_TYPE_Y; y++) {
+ int type = x*16 + y;
+ if ((type & 0x80) != 0)
+ break;
+
+ //Polygon pg = div.createPolygon("0x" + Integer.toHexString(type));
+
+ MapShape shape = new MapShape();
+ shape.setMinResolution(10);
+ shape.setName("0x" + Integer.toHexString(type));
+
+ double baseLat = lat + y * ELEMENT_SPACING;
+ double baseLong = lon + x * ELEMENT_SPACING;
+
+ List<Coord> coords = new ArrayList<Coord>();
+
+ Coord co = new Coord(baseLat, baseLong);
+ //pg.addCoord(co);
+ coords.add(co);
+
+ co = new Coord(baseLat + ELEMENT_SIZE, baseLong);
+ coords.add(co);
+ mapper.addToBounds(co);
+
+ co = new Coord(baseLat + ELEMENT_SIZE, baseLong + ELEMENT_SIZE);
+ coords.add(co);
+ mapper.addToBounds(co);
+
+ co = new Coord(baseLat, baseLong + ELEMENT_SIZE);
+ coords.add(co);
+ mapper.addToBounds(co);
+
+ co = new Coord(baseLat, baseLong);
+ coords.add(co);
+ mapper.addToBounds(co);
+
+ shape.setType(type);
+ shape.setPoints(coords);
+
+ mapper.addShape(shape);
+ }
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java b/src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java
new file mode 100644
index 0000000..63e5cab
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/test/ElementTestDataSource.java
@@ -0,0 +1,82 @@
+/*
+ * 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: 02-Sep-2007
+ */
+package uk.me.parabola.mkgmap.reader.test;
+
+import java.io.FileNotFoundException;
+import java.util.Properties;
+
+import uk.me.parabola.mkgmap.general.LevelInfo;
+import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
+import uk.me.parabola.mkgmap.reader.MapperBasedMapDataSource;
+import uk.me.parabola.util.EnhancedProperties;
+
+/**
+ * This is a map data source that just generates maps without reference to
+ * any external data.
+ *
+ * @author Steve Ratcliffe
+ */
+public class ElementTestDataSource extends MapperBasedMapDataSource implements LoadableMapDataSource {
+ private Properties configProps;
+
+ /**
+ * 'Filenames' that are supported begin with test-map:
+ * @param name The name to check.
+ * @return True If a recognised test name beginning with test-map:
+ */
+ public boolean isFileSupported(String name) {
+ return name != null && name.startsWith("test-map:");
+ }
+
+ /**
+ * Load a map by generating it in code.
+ * @param name The name of the map to generate.
+ * @throws FileNotFoundException If the name is not recognised.
+ */
+ public void load(String name) throws FileNotFoundException {
+ if ("test-map:all-elements".equals(name)) {
+ AllElements all = new AllElements();
+ all.load(mapper);
+ } else if ("test-map:test-points".equals(name)) {
+ TestPoints test = new TestPoints();
+ test.load(mapper, configProps);
+ } else {
+ throw new FileNotFoundException("Invalid test file name");
+ }
+ }
+
+ public LevelInfo[] mapLevels() {
+ return new LevelInfo[] {
+ new LevelInfo(3, 16),
+ new LevelInfo(2, 18),
+ new LevelInfo(1, 20),
+ new LevelInfo(0, 24),
+ };
+ }
+
+ public LevelInfo[] overviewMapLevels() {
+ return null; // TODO: probably this should return something
+ }
+
+ public String[] copyrightMessages() {
+ return new String[] {"test data"};
+ }
+
+ public void config(EnhancedProperties props) {
+ this.configProps = props;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/test/TestPoints.java b/src/uk/me/parabola/mkgmap/reader/test/TestPoints.java
new file mode 100644
index 0000000..45724d1
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/test/TestPoints.java
@@ -0,0 +1,132 @@
+/*
+ * 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: 03-Sep-2007
+ */
+package uk.me.parabola.mkgmap.reader.test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.general.MapCollector;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapPoint;
+
+/**
+ * This is a map that contains many points in a dense grid. It is going to
+ * be used to investigate the 'find' bug.
+ *
+ * @author Steve Ratcliffe
+ */
+class TestPoints {
+ private static final double ELEMENT_SPACING = 0.02;
+
+ private Properties props;
+ //private static final int MAX_LINE_TYPE_X = 100;
+ //private static final int MAX_LINE_TYPE_Y = 50;
+ private static final double ELEMENT_SIZE = 0.002;
+
+ /**
+ * Loading the map in this case means generating it.
+ *
+ * @param mapper Used to collect the generated points etc.
+ * @param in User supplied properties.
+ */
+ public void load(MapCollector mapper, Properties in) {
+ this.props = in;
+
+ double baseLat = 51.7;
+
+ String sBaseLat = System.getenv("BASE_LAT");
+ String sBaseLong = System.getenv("BASE_LONG");
+
+ if (sBaseLat != null)
+ baseLat = Double.valueOf(sBaseLat);
+
+ double baseLong = 0.24;
+ if (sBaseLong != null)
+ baseLong = Double.valueOf(sBaseLong);
+
+ drawTestMap(mapper, baseLat, baseLong);
+ }
+
+ /**
+ * We draw points, lines and polygons separately. They should be in
+ * order from west to east of the generated map, starting in the bottom
+ * left hand corner (SW).
+ *
+ * @param mapper Collector for the generated points etc.
+ * @param startLat The S coord.
+ * @param startLong The W coord.
+ */
+ private void drawTestMap(MapCollector mapper, double startLat, double startLong) {
+
+ String s = props.getProperty("npoints");
+ int npoints = 10;
+ if (s != null)
+ npoints = Integer.valueOf(s);
+
+ for (int x = 0; x < npoints; x++) {
+ for (int y = 0; y < npoints; y++) {
+
+ MapPoint point = new MapPoint();
+
+ double baseLat = startLat + y * ELEMENT_SPACING;
+ double baseLong = startLong + x * ELEMENT_SPACING;
+
+ point.setMinResolution(24 - (x & 0x7));
+ point.setName("P " + (x*npoints + y));
+
+ point.setLocation(new Coord(baseLat, baseLong));
+ point.setType((0x2c << 8) + (y & 0xf));
+
+ mapper.addPoint(point);
+ mapper.addToBounds(point.getLocation()); // XXX shouldn't be needed.
+ }
+ }
+
+ // I think the 'find' bug only shows when there are lines, so lets add
+ // some.
+ for (int x = 0; x < npoints; x++) {
+ for (int y = 0; y < npoints; y++) {
+ int type = x*16 + y;
+ type &= 0xf;
+
+ MapLine line = new MapLine();
+ line.setMinResolution(10);
+ line.setName("0x" + Integer.toHexString(type));
+
+ double baseLat = startLat + y * ELEMENT_SPACING;
+ double baseLong = startLong + x * ELEMENT_SPACING;
+
+ List<Coord> coords = new ArrayList<Coord>();
+
+ for (int i = 0; i < 5; i++) {
+ Coord co = new Coord(baseLat + i * ELEMENT_SIZE, baseLong + i * ELEMENT_SIZE);
+ coords.add(co);
+ mapper.addToBounds(co);
+ }
+
+ line.setType(type);
+ line.setPoints(coords);
+
+ mapper.addLine(line);
+ }
+ }
+
+ }
+
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/test/package.html b/src/uk/me/parabola/mkgmap/reader/test/package.html
new file mode 100644
index 0000000..b6279c5
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/reader/test/package.html
@@ -0,0 +1,11 @@
+<body>
+<h3>Test maps</h3>
+
+<p>This is an example of a map data source that does not read anything in from
+a file at all. It generates the maps with code.
+
+<p>The mapnames begin with <em>TEST:</em> the only one implemented at the time
+ of writing was TEST:ALL-ELEMENTS. This is a map that contains grids of
+ points, lines and polygons all with different types.
+</p>
+</body>
\ No newline at end of file
diff --git a/src/uk/me/parabola/mkgmap/scan/SyntaxException.java b/src/uk/me/parabola/mkgmap/scan/SyntaxException.java
new file mode 100644
index 0000000..66c80da
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/scan/SyntaxException.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 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: 03-Nov-2008
+ */
+package uk.me.parabola.mkgmap.scan;
+
+import java.util.Formatter;
+
+/**
+ * A syntax error in a rule file.
+ * @author Steve Ratcliffe
+ */
+public class SyntaxException extends RuntimeException {
+
+ private String fileName;
+ private int lineNumber;
+
+ public SyntaxException(String message) {
+ super(message);
+ }
+
+ public SyntaxException(TokenScanner ts, String msg) {
+ super(msg);
+ fileName = ts.getFileName();
+ lineNumber = ts.getLinenumber();
+ }
+
+ public String getRawMessage() {
+ return super.getMessage();
+ }
+
+ public String getMessage() {
+ Formatter fmt = new Formatter();
+ fmt.format("Error: ");
+ if (fileName != null)
+ fmt.format("(%s:%d): ", fileName, lineNumber);
+
+ fmt.format(super.getMessage());
+ return fmt.toString();
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/scan/TokType.java b/src/uk/me/parabola/mkgmap/scan/TokType.java
new file mode 100644
index 0000000..313ab1f
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/scan/TokType.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 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: May 25, 2008
+ */
+package uk.me.parabola.mkgmap.scan;
+
+/**
+ * The different token types.
+ */
+public enum TokType {
+ /** A symbol, such as '!', '@' etc. Currently symbols are single
+ * and do not combine. This may change. */
+ SYMBOL,
+
+ /** Text, an alphanumeric string. */
+ TEXT,
+
+ /** A sequence of space characters, not including newline. Several
+ * characters can be combined into one token, but the actual characters
+ * are available as the value. */
+ SPACE,
+
+ /** An end of line character.*/
+ EOL,
+
+ /** Used for end of file.*/
+ EOF,
+}
diff --git a/src/uk/me/parabola/mkgmap/scan/Token.java b/src/uk/me/parabola/mkgmap/scan/Token.java
new file mode 100644
index 0000000..57e3bfc
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/scan/Token.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 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: May 5, 2008
+ */
+package uk.me.parabola.mkgmap.scan;
+
+/**
+ * @author Steve Ratcliffe
+ */
+public class Token {
+ private final TokType type;
+ private String value;
+
+ public boolean isWhiteSpace() {
+ return type == TokType.SPACE || type == TokType.EOL;
+ }
+
+ public Token(TokType type) {
+ this.type = type;
+ }
+
+ public TokType getType() {
+ return type;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public boolean isValue(String val) {
+ return val.equals(value);
+ }
+
+ /**
+ * True if we are at the end of a line. End of file counts as the end of a line.
+ */
+ public boolean isEol() {
+ return type == TokType.EOL || type == TokType.EOF;
+ }
+}
+
diff --git a/src/uk/me/parabola/mkgmap/scan/TokenScanner.java b/src/uk/me/parabola/mkgmap/scan/TokenScanner.java
new file mode 100644
index 0000000..99bde8b
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/scan/TokenScanner.java
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2008 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: May 10, 2008
+ */
+package uk.me.parabola.mkgmap.scan;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.LinkedList;
+
+/**
+ * Read a file in terms of word and symbol tokens.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TokenScanner {
+ private static final int NO_PUSHBACK = 0;
+
+ // Reading state
+ private final Reader reader;
+ private int pushback = NO_PUSHBACK;
+ private boolean isEOF;
+
+ private final String fileName;
+ private int linenumber;
+
+ private final LinkedList<Token> tokens = new LinkedList<Token>();
+
+ private boolean bol = true;
+
+ // Extra word characters.
+ private String extraWordChars = "";
+ private String commentChar = "#";
+
+ public TokenScanner(String filename, Reader reader) {
+ if (reader instanceof BufferedReader)
+ this.reader = reader;
+ else
+ this.reader = new BufferedReader(reader);
+ fileName = filename;
+ }
+
+ /**
+ * Peek and return the first token. It is not consumed.
+ */
+ public Token peekToken() {
+ ensureTok();
+ return tokens.peek();
+ }
+
+ /**
+ * Get and remove the next token. May return space or newline. This is the
+ * only place that a token is removed from the tokens queue.
+ */
+ public Token nextRawToken() {
+ ensureTok();
+
+ if (bol) {
+ bol = false;
+ linenumber++;
+ }
+
+ Token token = tokens.removeFirst();
+ if (token.getType() == TokType.EOL)
+ bol = true;
+
+ return token;
+ }
+
+ /**
+ * Get the next token tht is not a space or newline.
+ * @return The first valid text or symbol token.
+ */
+ public Token nextToken() {
+ skipSpace();
+ return nextRawToken();
+ }
+
+ /**
+ * Push a token back to the beginning of the token queue.
+ * @param tok The token to add to the beginning of the queue.
+ */
+ public void pushToken(Token tok) {
+ tokens.push(tok);
+ }
+
+ /**
+ * Get the value of the next non-space token and consume the token. You'd
+ * probably only call this after having peeked the type earlier.
+ * Any initial space is skipped.
+ */
+ public String nextValue() {
+ skipSpace();
+ return nextRawToken().getValue();
+ }
+
+ public boolean isEndOfFile() {
+ if (tokens.isEmpty()) {
+ return isEOF;
+ } else {
+ return tokens.peek().getType() == TokType.EOF;
+ }
+ }
+
+ /**
+ * Skip any white space. After calling this the next token
+ * will be end of file or something other than SPACE or EOL.
+ */
+ public void skipSpace() {
+ while (!isEndOfFile()) {
+ ensureTok();
+ if (tokens.peek().isValue(commentChar)) {
+ skipLine();
+ continue;
+ }
+ if (!tokens.peek().isWhiteSpace())
+ break;
+ nextRawToken();
+ }
+ }
+
+ /**
+ * Skip everything up to a new line token. The new line
+ * token will be consumed, so the next token will the the first
+ * on a new line (or at EOF).
+ */
+ public void skipLine() {
+ while (!isEndOfFile()) {
+ Token t = nextRawToken();
+ if (t.getType() == TokType.EOL)
+ break;
+ }
+ }
+
+ private void ensureTok() {
+ if (tokens.isEmpty())
+ fillTok();
+ }
+
+ private void fillTok() {
+ Token t = readTok();
+ tokens.add(t);
+ }
+
+ /**
+ * Read a token from the input stream. There are only a few
+ * kinds of token that are recognised on input. Other token
+ * types are recognised or constructed later on.
+ * @return A token. Never returns null or throws an exception.
+ * Once end of file or an error occurs the routine will always return
+ * EOF.
+ */
+ private Token readTok() {
+ if (isEOF)
+ return new Token(TokType.EOF);
+
+ int c = readChar();
+
+ if (c == -1) {
+ isEOF = true;
+ return new Token(TokType.EOF);
+ }
+
+ StringBuilder val = new StringBuilder();
+ val.append((char) c);
+
+ TokType tt;
+ if (c == '\n') {
+ tt = TokType.EOL;
+ } else if (isSpace(c)) {
+ while (isSpace(c = readChar()) && c != '\n')
+ val.append((char) c);
+
+ pushback = c;
+ tt = TokType.SPACE;
+ } else if (isWordChar(c)) {
+ while (isWordChar(c = readChar()))
+ val.append((char) c);
+ pushback = c;
+ tt = TokType.TEXT;
+ } else {
+ // A symbol. The value has already been set. Some symbols
+ // combine from multiple characters.
+ if (c == '!' || c == '<' || c == '>') {
+ c = readChar();
+ if (c == '=')
+ val.append('=');
+ else
+ pushback = c;
+ } else if (c == '&' || c == '|') {
+ // Allow && and || as single symbols
+ int c2 = readChar();
+ if (c2 == c)
+ val.append((char) c2);
+ else
+ pushback = c2;
+ }
+ tt = TokType.SYMBOL;
+ }
+
+ Token t = new Token(tt);
+ t.setValue(val.toString());
+ return t;
+ }
+
+ /**
+ * Read a single character.
+ * @return The next character, or -1 if at EOF. The isEOF field will also be set to true at end of file.
+ */
+ private int readChar() {
+ int c;
+ if (pushback != NO_PUSHBACK) {
+ c = pushback;
+ pushback = NO_PUSHBACK;
+ return c;
+ }
+
+ try {
+ c = reader.read();
+ } catch (IOException e) {
+ isEOF = true;
+ c = -1;
+ }
+
+ return c;
+ }
+
+ private boolean isSpace(int nextch) {
+ return Character.isWhitespace(nextch) || nextch == '\uFEFF';
+ }
+
+ private boolean isWordChar(int ch) {
+ return Character.isLetterOrDigit(ch)
+ || ch == '_'
+ || extraWordChars.indexOf(ch) >= 0;
+ }
+
+ /**
+ * Read the tokens up until the end of the line and combine then
+ * into one string.
+ *
+ * @return A single string, not including the newline terminator. Never
+ * returns null, returns an empty string if there is nothing there. The
+ * end of line is consumed.
+ */
+ public String readLine() {
+ String res = readUntil(TokType.EOL, null);
+ nextRawToken(); // use up new line
+ return res;
+ }
+
+ /**
+ * Read tokens until one of the given type and value is found and return the result as a single string.
+ * The searched token is not consumed from the input.
+ *
+ * @param type The token type to search for.
+ * @param value The string value of the token to search for.
+ * @return A single string of all the tokens preceding the searched token.
+ */
+ public String readUntil(TokType type, String value) {
+ StringBuilder sb = new StringBuilder();
+ while (!isEndOfFile()) {
+ Token t = peekToken();
+ if (t.getType() == type && (value == null || value.equals(t.getValue())))
+ break;
+ sb.append(nextRawToken().getValue());
+ }
+ return sb.toString().trim();
+ }
+
+ /**
+ * Convenience routine to get an integer. Skips space and reads a
+ * token. This token is converted to an integer if possible.
+ * @return An integer as read from the next non space token.
+ * @throws NumberFormatException When the next symbol isn't
+ * a valid integer.
+ */
+ public int nextInt() throws NumberFormatException {
+ skipSpace();
+ Token t = nextRawToken();
+ if (t == null)
+ throw new NumberFormatException("no number");
+
+ return Integer.parseInt(t.getValue());
+ }
+
+ /**
+ * As {@link #nextWordWithInfo()} but just the string is returned.
+ * @return The next word as a string. A quoted entity is regarded as a
+ * word for the purposes of this scanner.
+ */
+ public String nextWord() {
+ WordInfo info = nextWordWithInfo();
+ return info.getText();
+ }
+
+ /**
+ * Read a string that can be quoted. If it is quoted, then everything
+ * until the closing quotes is part of the string. Both single
+ * and double quotes can be used.
+ *
+ * If there are no quotes then it behaves like nextToken apart from
+ * skipping space.
+ *
+ * Initial and final space is skipped.
+ *
+ * The word string is returned along with a flag to indicate whether it
+ * was quoted or not.
+ */
+ public WordInfo nextWordWithInfo() {
+ skipSpace();
+ Token tok = peekToken();
+ char quotec = 0;
+ if (tok.getType() == TokType.SYMBOL) {
+ String s = tok.getValue();
+ if ("'".equals(s) || "\"".equals(s)) {
+ quotec = s.charAt(0);
+ nextRawToken();
+ }
+ }
+
+ StringBuilder sb = new StringBuilder();
+ while (!isEndOfFile()) {
+ tok = nextRawToken();
+ if (quotec == 0) {
+ sb.append(tok.getValue());
+ break;
+ } else {
+ if (tok.isValue(String.valueOf(quotec)))
+ break;
+ sb.append(tok.getValue());
+ }
+ }
+ skipSpace();
+ return new WordInfo(sb.toString(), quotec != 0);
+ }
+
+ /**
+ * Check the value of the next token without consuming it.
+ *
+ * @param val String value to compare against.
+ * @return True if the next token has the same value as the argument.
+ */
+ public boolean checkToken(String val) {
+ skipSpace();
+ Token tok = peekToken();
+ if (val == null || tok.getValue() == null)
+ return false;
+ return val.equals(tok.getValue());
+ }
+
+ /**
+ * Validate the next word is the given value. Space is skipped before
+ * checking, the checked value is consumed. Use when you want to
+ * ensure that a required syntax element is present.
+ *
+ * The input will either be positioned after the required word or an
+ * exception will have been thrown.
+ *
+ * @param val The string value to look for.
+ * @throws SyntaxException If the required string is not found.
+ */
+ public void validateNext(String val) {
+ skipSpace();
+ Token tok = nextToken();
+ if (val == null || !val.equals(tok.getValue()))
+ throw new SyntaxException(this, "Expecting " + val + ", instead saw " + tok.getValue());
+ }
+
+ public int getLinenumber() {
+ return linenumber;
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ /**
+ * Extra word characters are characters that should be considered as part of a word in addition
+ * to alphanumerics and underscore.
+ * @param extraWordChars A string containing all the characters to be considered part of a word.
+ */
+ public void setExtraWordChars(String extraWordChars) {
+ this.extraWordChars = extraWordChars;
+ }
+
+ /**
+ * The skip space routine, will skip all characters after a '#' until the end of the
+ * line as part of its skip white space functionality.
+ *
+ * This is a mis-feature if your comment character is not '#' or that character is
+ * sometimes important. Therefore you can turn this off by passing in an empty string here.
+ */
+ public void setCommentChar(String commentChar) {
+ if (commentChar == null)
+ this.commentChar = "";
+ else
+ this.commentChar = commentChar;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/scan/WordInfo.java b/src/uk/me/parabola/mkgmap/scan/WordInfo.java
new file mode 100644
index 0000000..061d7ff
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/scan/WordInfo.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.scan;
+
+/**
+ * When reading a word you can save the text and if it was quoted or not.
+ *
+ * @author Steve Ratcliffe
+ */
+public class WordInfo {
+ private final String text;
+ private final boolean quoted;
+
+ public WordInfo(String text, boolean quoted) {
+ this.text = text;
+ this.quoted = quoted;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public boolean isQuoted() {
+ return quoted;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaGenerator.java b/src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaGenerator.java
new file mode 100644
index 0000000..c6a2387
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaGenerator.java
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.sea.optional;
+
+import java.awt.Rectangle;
+import java.awt.geom.Area;
+import java.awt.geom.Path2D;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.mkgmap.reader.osm.FakeIdGenerator;
+import uk.me.parabola.mkgmap.reader.osm.SeaGenerator;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+
+import org.geotools.data.DataStore;
+import org.geotools.data.DataStoreFinder;
+import org.geotools.data.simple.SimpleFeatureCollection;
+import org.geotools.data.simple.SimpleFeatureIterator;
+import org.geotools.data.simple.SimpleFeatureSource;
+import org.geotools.filter.text.cql2.CQLException;
+import org.geotools.geometry.jts.JTS;
+import org.geotools.referencing.CRS;
+import org.geotools.referencing.crs.DefaultGeographicCRS;
+import org.opengis.feature.Feature;
+import org.opengis.feature.GeometryAttribute;
+import org.opengis.geometry.MismatchedDimensionException;
+import org.opengis.referencing.FactoryException;
+import org.opengis.referencing.NoSuchAuthorityCodeException;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.TransformException;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Geometry;
+
+/**
+ * Converts a shapefile containing land polygons into mkgmap precompiled sea tiles.
+ * @author WanMil
+ */
+public class PrecompSeaGenerator {
+
+ private final ExecutorService service;
+
+ /** the shapefile (.shp) that contains the land polygons */
+ private final File shapeFile;
+ /** the directory the precomp sea tiles are written to */
+ private final File outputDir;
+
+ private SimpleFeatureCollection shapeCollection;
+ private SimpleFeatureIterator shapeIterator;
+
+ /** transforms the projection of the shapefile to WGS84 ({@code null} if shape file uses WGS84) */
+ private final MathTransform transformation;
+ /** {@code true}: sea tiles are created with PBF format; {@code false}: sea tiles are created with .osm.gz format */
+ private boolean usePbfFormat;
+ /** Number of tiles generated by one full reading of the shapefile. Higher numbers require more memory. */
+ private int tilesPerCycle;
+
+ public PrecompSeaGenerator(File shapeFile, String shapeCRS, File outputDir)
+ throws NoSuchAuthorityCodeException, FactoryException {
+ this.shapeFile = shapeFile;
+ this.outputDir = outputDir;
+ this.transformation = createTransformation(shapeCRS);
+
+ this.service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
+ this.usePbfFormat = true;
+ this.tilesPerCycle = 10 * 512;
+ }
+
+ /**
+ * Sets the flag if pbf format or gzipped osm xml format (.osm.gz) should be used
+ * for the precompiled sea tiles.
+ * @param usePbf {@code true} use PBF format; {@code false} use .osm.gz format
+ */
+ public void setUsePbfFormat(boolean usePbf) {
+ this.usePbfFormat = usePbf;
+ }
+
+ /**
+ * Retrieves the transformation that is necessary to transform the
+ * data from the shape file to WGS84.
+ * @param shapeCRS the projection of the shape file
+ * @return the transformation ({@code null} if no transformation required)
+ * @throws NoSuchAuthorityCodeException if the given projection of the shape file is not supported
+ * @throws FactoryException if the given projection of the shape file is not supported
+ */
+ private MathTransform createTransformation(String shapeCRS)
+ throws NoSuchAuthorityCodeException, FactoryException {
+ if ("WGS84".equals(shapeCRS)) {
+ return null;
+ }
+ if ("Mercator".equals(shapeCRS)) {
+ shapeCRS = "EPSG:3857";
+ }
+ CoordinateReferenceSystem crsInShapefile = CRS.decode(shapeCRS);
+ CoordinateReferenceSystem targetCRS = DefaultGeographicCRS.WGS84;
+ boolean lenient = true; // allow for some error due to different datums
+ return CRS.findMathTransform(crsInShapefile, targetCRS, lenient);
+ }
+
+ /**
+ * Transforms a geometry from the shape file to a geometry with WGS84 projection.
+ * @param geometry a geometry from the shape file
+ * @return a geometry with WGS84 projection
+ * @throws MismatchedDimensionException if the transformation fails
+ * @throws TransformException if the geometry could not be transformed
+ */
+ private Geometry transformToWGS84(Geometry geometry)
+ throws MismatchedDimensionException, TransformException {
+ if (transformation == null) {
+ return geometry;
+ } else {
+ return JTS.transform(geometry, transformation);
+ }
+ }
+
+ /**
+ * Retrieve the areas of all precompiled tiles that have to be worked out.
+ * @return the areas of all tiles
+ */
+ private List<uk.me.parabola.imgfmt.app.Area> getTiles() {
+ uk.me.parabola.imgfmt.app.Area earth = new uk.me.parabola.imgfmt.app.Area(
+ -90.0d, -180.0d, 90.0d, 180.0d);
+ return getTiles(earth);
+ }
+
+ private List<uk.me.parabola.imgfmt.app.Area> getTiles(
+ uk.me.parabola.imgfmt.app.Area wholeArea) {
+ int minLat = wholeArea.getMinLat();
+ int maxLat = wholeArea.getMaxLat();
+ int minLon = wholeArea.getMinLong();
+ int maxLon = wholeArea.getMaxLong();
+
+ List<uk.me.parabola.imgfmt.app.Area> tiles = new ArrayList<uk.me.parabola.imgfmt.app.Area>();
+ for (int lon = SeaGenerator.getPrecompTileStart(minLon); lon < maxLon; lon += SeaGenerator.PRECOMP_RASTER) {
+ for (int lat = SeaGenerator.getPrecompTileStart(minLat); lat < maxLat; lat += SeaGenerator.PRECOMP_RASTER) {
+ uk.me.parabola.imgfmt.app.Area tile = new uk.me.parabola.imgfmt.app.Area(
+ Math.max(lat, minLat), Math.max(lon, minLon), Math.min(
+ lat + SeaGenerator.PRECOMP_RASTER, maxLat),
+ Math.min(lon + SeaGenerator.PRECOMP_RASTER, maxLon));
+ tiles.add(tile);
+ }
+ }
+ return tiles;
+ }
+
+
+ /**
+ * Prints regularly how many tiles are not yet finished.
+ * @author WanMil
+ */
+ private static class ProgressPrinter extends Thread {
+ private final CountDownLatch countdown;
+
+ public ProgressPrinter(CountDownLatch countdown) {
+ super("ProgressPrinter");
+ this.countdown = countdown;
+ setDaemon(true);
+ }
+
+ public void run() {
+ long count = 0;
+ do {
+ count = countdown.getCount();
+ System.out.println(count + " tiles remaining");
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException exp) {
+ }
+ } while (count > 0);
+ }
+ }
+
+ /**
+ * Converts the given geometry to an {@link Area} object.
+ * @param geometry a polygon as {@link Geometry} object
+ * @return the polygon converted to an {@link Area} object.
+ */
+ private Area convertToArea(Geometry geometry) {
+ Coordinate[] c = geometry.getCoordinates();
+ Path2D.Double path = new Path2D.Double();
+ path.moveTo(Utils.toMapUnit(c[0].x), Utils.toMapUnit(c[0].y));
+ for (int n = 1; n < c.length; n++) {
+ path.lineTo(Utils.toMapUnit(c[n].x), Utils.toMapUnit(c[n].y));
+ }
+ path.closePath();
+ return new Area(path);
+ }
+
+
+ /**
+ * Creates the merger threads for the given tiles.
+ * @param tiles the areas of the precompiled tiles
+ * @param tilesCountdown the countdown that should be decreased after a tile is finished
+ * @param saveQueue the queue the merged results should be added to
+ * @return the preinitialized but not started mergers
+ */
+ private List<PrecompSeaMerger> createMergers(
+ Collection<uk.me.parabola.imgfmt.app.Area> tiles,
+ CountDownLatch tilesCountdown,
+ BlockingQueue<Entry<String, List<Way>>> saveQueue) {
+ List<PrecompSeaMerger> mergers = new ArrayList<PrecompSeaMerger>();
+
+ for (uk.me.parabola.imgfmt.app.Area bounds : tiles) {
+
+ Rectangle mergeBounds = new Rectangle(bounds.getMinLong(),
+ bounds.getMinLat(), bounds.getWidth(), bounds.getHeight());
+ String tileKey = bounds.getMinLat() + "_" + bounds.getMinLong();
+
+ PrecompSeaMerger merger = new PrecompSeaMerger(mergeBounds,
+ tileKey, tilesCountdown, saveQueue);
+ merger.setExecutorService(service);
+ mergers.add(merger);
+ }
+ return mergers;
+ }
+
+ private void createShapefileAccess() throws IOException {
+ Map<String,URL> map = new HashMap<String, URL>();
+ map.put("url", shapeFile.toURI().toURL());
+ DataStore dataStore = DataStoreFinder.getDataStore(map);
+ String typeName = dataStore.getTypeNames()[0];
+
+ SimpleFeatureSource source = dataStore.getFeatureSource(typeName);
+ shapeCollection = source.getFeatures();
+ }
+
+ private void openShapefile() {
+ shapeIterator = shapeCollection.features();
+ }
+
+ private void closeShapefile() {
+ shapeIterator.close();
+ shapeIterator = null;
+ }
+
+ /**
+ * Reads the next polygon from the shape file.
+ * @return the next polygon (WGS84 projection)
+ */
+ private Geometry readNextPolygon() {
+ if (shapeIterator.hasNext()) {
+ Feature feature = shapeIterator.next();
+ GeometryAttribute geom = feature.getDefaultGeometryProperty();
+ Geometry poly = (Geometry) geom.getValue();
+ try {
+ return transformToWGS84(poly);
+ } catch (Exception exp) {
+ System.err.println(exp);
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ public void runSeaGeneration() throws MismatchedDimensionException,
+ TransformException, IOException, InterruptedException {
+ createShapefileAccess();
+
+ // get all tiles that need to be processed
+ List<uk.me.parabola.imgfmt.app.Area> remainingTiles = getTiles();
+
+ // initialize the count down so that it is possible to get the
+ // information when all tiles are finished
+ CountDownLatch tilesCountdown = new CountDownLatch(remainingTiles.size());
+
+ // start a printer that outputs how many tiles still need to be
+ // processed
+ new ProgressPrinter(tilesCountdown).start();
+
+ // start the saver thread that stores the tiles to disc and creates
+ // the index file
+ PrecompSeaSaver precompSaver = new PrecompSeaSaver(outputDir, usePbfFormat);
+ new Thread(precompSaver, "SaveThread").start();
+
+ // perform several cycles which is necessary to reduce memory
+ // requirements
+ while (remainingTiles.isEmpty() == false) {
+
+ // create a list with all tiles that are processed within this cycle
+ List<uk.me.parabola.imgfmt.app.Area> tiles = new ArrayList<uk.me.parabola.imgfmt.app.Area>();
+ tiles.addAll(remainingTiles.subList(0,
+ Math.min(tilesPerCycle, remainingTiles.size())));
+ remainingTiles.subList(0,
+ Math.min(tilesPerCycle, remainingTiles.size())).clear();
+
+
+ // create the mergers that merge the data of one tile
+ List<PrecompSeaMerger> mergers = createMergers(tiles, tilesCountdown, precompSaver.getQueue());
+
+ // create an overall area for a simple check if a polygon read from the
+ // shape file intersects one of the currently processed sea tiles
+ Area tileArea = new Area();
+ for (PrecompSeaMerger m : mergers) {
+ tileArea.add(new Area(m.getTileBounds()));
+ // start the mergers
+ service.execute(m);
+ }
+
+ openShapefile();
+
+ int numPolygon = 0;
+ long lastInfo = System.currentTimeMillis();
+
+ // read all polygons from the shape file and add them to the queues of the
+ // merger threads
+ Geometry wgs84Poly = null;
+ while ((wgs84Poly = readNextPolygon()) != null) {
+
+ if (wgs84Poly.getNumGeometries() != 1) {
+ // only simple polygons are supported by now
+ // maybe this could be changed in future?
+ System.err.println("Polygon from shapefile has "
+ + wgs84Poly.getNumGeometries()
+ + " geometries. Only one geometry is supported.");
+ System.err.println("Skip polygon.");
+ continue;
+ }
+
+ Geometry bounds = wgs84Poly.getEnvelope();
+ if (bounds.isEmpty()) {
+ System.err.println("Empty or non polygon: " + bounds);
+ } else {
+ Area polyBounds = convertToArea(bounds);
+
+ // easy check if the polygon is used by any tile that is
+ // currently processed
+ if (polyBounds.intersects(tileArea.getBounds2D())) {
+
+ // yes it touches at least one tile => convert it to
+ // a java.awt.geom.Area object
+ Area polyAsArea = convertToArea(wgs84Poly.getGeometryN(0));
+
+ // go through all current merger threads and add the
+ // polygon to the queues of them
+ for (PrecompSeaMerger mThread : mergers) {
+ if (mThread.getTileBounds().intersects(polyAsArea.getBounds2D())) {
+ try {
+ mThread.getQueue().put(polyAsArea);
+ } catch (InterruptedException exp) {
+ exp.printStackTrace();
+ }
+ }
+ }
+ }
+
+ numPolygon++;
+ if ((numPolygon) % 50000 == 0
+ || System.currentTimeMillis() - lastInfo > 30000) {
+ // print out the current number of polygons already processed
+ System.out.println("Worked out " + (numPolygon) + " polygons");
+ lastInfo = System.currentTimeMillis();
+ }
+
+ }
+ }
+ closeShapefile();
+
+ System.out.println("Reading shapefile finished");
+
+ // signal all mergers that all polygons have been read
+ for (PrecompSeaMerger mThread : mergers) {
+ mThread.signalInputComplete();
+ }
+
+ // Wait until not more than twice the number of tiles per cycle
+ // are waiting for processing. Otherwise OutOfMemory problems
+ // may occurr
+ while (tilesCountdown.getCount() > remainingTiles.size()
+ + 2*tilesPerCycle) {
+ Thread.sleep(50L);
+ }
+ }
+ // wait until all tiles have been merged
+ tilesCountdown.await();
+ // wait until the saver for the tiles is finished
+ precompSaver.waitForFinish();
+ // shutdown the executor service
+ service.shutdown();
+ }
+
+ public static void main(String[] args) throws MismatchedDimensionException,
+ TransformException, IOException, FactoryException, CQLException,
+ InterruptedException {
+ long t1 = System.currentTimeMillis();
+
+ File shapeFile = new File(args[0]);
+ String shapeCRS = args[1];
+ File outputDir = new File(args[2]);
+
+ if (shapeFile.exists() == false) {
+ throw new FileNotFoundException("File "+shapeFile+" does not exist.");
+ }
+
+ // use small fake ids so that the xml files become smaller
+ FakeIdGenerator.setStartId(0);
+
+ PrecompSeaGenerator seaGenerator = new PrecompSeaGenerator(shapeFile,
+ shapeCRS, outputDir);
+ seaGenerator.runSeaGeneration();
+
+ System.out.println("Generation took "+(System.currentTimeMillis()-t1)+" ms");
+
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaMerger.java b/src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaMerger.java
new file mode 100644
index 0000000..eff4131
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaMerger.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2012-2014.
+ *
+ * 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.sea.optional;
+
+import java.awt.geom.Area;
+import java.awt.geom.Rectangle2D;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.reader.osm.FakeIdGenerator;
+import uk.me.parabola.mkgmap.reader.osm.GeneralRelation;
+import uk.me.parabola.mkgmap.reader.osm.MultiPolygonRelation;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.Java2DConverter;
+
+/**
+ * Merges the polygons for one precompiled sea tile.
+ * @author WanMil
+ */
+class PrecompSeaMerger implements Runnable {
+ private final MergeData mergeData;
+ private final CountDownLatch signal;
+ private final BlockingQueue<Entry<String, List<Way>>> saveQueue;
+ private ExecutorService service;
+
+ static class MergeData {
+ public final Rectangle2D bounds;
+ public final BlockingQueue<Area> toMerge;
+ public final AtomicBoolean ready = new AtomicBoolean(false);
+ public Area tmpLandArea = new Area();
+ public final Area landArea = new Area();
+ private final String key;
+
+ public MergeData(Rectangle2D bounds, String key) {
+ this.key = key;
+ this.bounds = bounds;
+ toMerge = new LinkedBlockingQueue<Area>();
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ }
+
+ public PrecompSeaMerger(Rectangle2D bounds, String key,
+ CountDownLatch signal,
+ BlockingQueue<Entry<String, List<Way>>> saveQueue) {
+ this.mergeData = new MergeData(bounds, key);
+ this.signal = signal;
+ this.saveQueue = saveQueue;
+ }
+
+ public MergeData getMergeData() {
+ return mergeData;
+ }
+
+ public BlockingQueue<Area> getQueue() {
+ return mergeData.toMerge;
+ }
+
+ public void signalInputComplete() {
+ mergeData.ready.set(true);
+ }
+
+ public void setExecutorService(ExecutorService service) {
+ this.service = service;
+ }
+
+ public Rectangle2D getTileBounds() {
+ return mergeData.bounds;
+ }
+
+ private List<Way> convertToWays(Area a, String naturalTag) {
+ List<List<Coord>> pointLists = Java2DConverter.areaToShapes(a);
+ List<Way> ways = new ArrayList<Way>(pointLists.size());
+ for (List<Coord> points : pointLists) {
+ Way w = new Way(FakeIdGenerator.makeFakeId(), points);
+ w.addTag("natural", naturalTag);
+ ways.add(w);
+ }
+ return ways;
+ }
+
+ public void run() {
+ Area merge = null;
+ try {
+ merge = mergeData.toMerge.poll(5, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException exp) {
+ exp.printStackTrace();
+ }
+ int merges = 0;
+ while (merge != null) {
+ Area landClipped = new Area(mergeData.bounds);
+ landClipped.intersect(merge);
+ mergeData.tmpLandArea.add(landClipped);
+ merges++;
+ if (merges % 500 == 0) {
+ // store each 500 polygons into a temporary area
+ // and merge them after that. That seems to be quicker
+ // than adding lots of very small areas to a highly
+ // scattered area
+ mergeData.landArea.add(mergeData.tmpLandArea);
+ mergeData.tmpLandArea = new Area();
+ }
+
+ if (merges % 500 == 0) {
+ break;
+ }
+ merge = mergeData.toMerge.poll();
+ }
+
+ if (mergeData.ready.get() == false
+ || mergeData.toMerge.isEmpty() == false) {
+ // repost the merge thread
+ service.execute(this);
+ return;
+ }
+
+ mergeData.landArea.add(mergeData.tmpLandArea);
+ mergeData.tmpLandArea = null;
+
+ // post processing //
+
+ // convert the land area to a list of ways
+ List<Way> ways = convertToWays(mergeData.landArea, "land");
+
+ if (ways.isEmpty()) {
+ // no land in this tile => create a sea way only
+ ways.addAll(convertToWays(new Area(mergeData.bounds), "sea"));
+ } else {
+ Map<Long, Way> landWays = new HashMap<Long, Way>();
+ List<List<Coord>> landParts = Java2DConverter
+ .areaToShapes(mergeData.landArea);
+ for (List<Coord> landPoints : landParts) {
+ Way landWay = new Way(FakeIdGenerator.makeFakeId(), landPoints);
+ landWays.put(landWay.getId(), landWay);
+ }
+
+ Way seaWay = new Way(FakeIdGenerator.makeFakeId());
+ seaWay.addPoint(new Coord(-90.0d, -180.0d));
+ seaWay.addPoint(new Coord(90.0d, -180.0d));
+ seaWay.addPoint(new Coord(90.0d, 180.0d));
+ seaWay.addPoint(new Coord(-90.0d, 180.0d));
+ seaWay.addPoint(new Coord(-90.0d, -180.0d));
+ landWays.put(seaWay.getId(), seaWay);
+
+ Relation rel = new GeneralRelation(FakeIdGenerator.makeFakeId());
+ for (Way w : landWays.values()) {
+ rel.addElement((w == seaWay ? "outer" : "inner"), w);
+ }
+
+ // process the tile as sea multipolygon to create simple polygons only
+ MultiPolygonRelation mpr = new MultiPolygonRelation(rel, landWays,
+ Java2DConverter.createBbox(new Area(mergeData.bounds)))
+ {
+ // do not calculate the area size => it is not required and adds
+ // a superfluous tag
+ protected boolean isAreaSizeCalculated() {
+ return false;
+ }
+ };
+ mpr.addTag("type", "multipolygon");
+ mpr.addTag("natural", "sea");
+ mpr.processElements();
+
+ for (Way w : landWays.values()) {
+ // process the polygon ways only
+ // the mp processing also creates line ways which must
+ // be ignored here
+ if (MultiPolygonRelation.STYLE_FILTER_POLYGON.equals(w
+ .getTag(MultiPolygonRelation.STYLE_FILTER_TAG))) {
+
+ String tag = w.getTag("natural");
+ if ("sea".equals(tag) == false) {
+ // ignore the land polygons - we already have them in our list
+ continue;
+ }
+ w.deleteTag(MultiPolygonRelation.STYLE_FILTER_TAG);
+ w.deleteTag(MultiPolygonRelation.MP_CREATED_TAG);
+ ways.add(w);
+ }
+ }
+ }
+
+ try {
+ // forward the ways to the queue of the saver thread
+ saveQueue.put(new SimpleEntry<String, List<Way>>(
+ mergeData.getKey(), ways));
+ } catch (InterruptedException exp) {
+ exp.printStackTrace();
+ }
+
+ // signal that this tile is finished
+ signal.countDown();
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaSaver.java b/src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaSaver.java
new file mode 100644
index 0000000..98e82c3
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/sea/optional/PrecompSeaSaver.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.sea.optional;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.regex.Pattern;
+import java.util.zip.GZIPOutputStream;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.reader.osm.FakeIdGenerator;
+import uk.me.parabola.mkgmap.reader.osm.SeaGenerator;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.splitter.BinaryMapWriter;
+import uk.me.parabola.splitter.Node;
+import uk.me.parabola.splitter.OSMWriter;
+import uk.me.parabola.splitter.OSMXMLWriter;
+
+class PrecompSeaSaver implements Runnable {
+ private final AtomicBoolean finished = new AtomicBoolean(false);
+ private final CountDownLatch finishWait;
+
+ private final Map<String, String> index;
+
+ private final Map<Integer, String> idMapping;
+ private int nextId = 0;
+ private final boolean usePbf;
+
+ private final File outputDir;
+
+ private final BlockingQueue<Entry<String, List<Way>>> saveQueue = new LinkedBlockingQueue<Entry<String, List<Way>>>();
+
+ public PrecompSeaSaver(File outputDir, boolean usePbf) {
+ this.outputDir = outputDir;
+ finishWait = new CountDownLatch(1);
+ this.usePbf = usePbf;
+ idMapping = new HashMap<Integer, String>();
+ index = new TreeMap<String, String>();
+ this.outputDir.mkdirs();
+ }
+
+ public BlockingQueue<Entry<String, List<Way>>> getQueue() {
+ return saveQueue;
+ }
+
+ private OSMWriter createWriter(int id, String key) {
+ String[] parts = key.split(Pattern.quote("_"));
+ int lat = Integer.valueOf(parts[0]);
+ int lon = Integer.valueOf(parts[1]);
+ uk.me.parabola.splitter.Area bounds = new uk.me.parabola.splitter.Area(
+ lat, lon, lat + SeaGenerator.PRECOMP_RASTER, lon + SeaGenerator.PRECOMP_RASTER);
+ OSMWriter writer = (usePbf ? new BinaryMapWriter(bounds, outputDir, nextId, 0)
+ : new OSMXMLWriter(bounds, outputDir, nextId, 0));
+ idMapping.put(id, key);
+ writer.initForWrite();
+ return writer;
+ }
+
+ public void waitForFinish() throws InterruptedException {
+ this.finished.set(true);
+ this.finishWait.await();
+ }
+
+ public void run() {
+ while (saveQueue.isEmpty() == false || finished.get() == false) {
+ Entry<String, List<Way>> tileData = null;
+ try {
+ tileData = saveQueue.poll(1, TimeUnit.MINUTES);
+ } catch (InterruptedException exp) {
+ exp.printStackTrace();
+ }
+ if (tileData != null) {
+ int id = ++nextId;
+
+ if (tileData.getValue().size() == 1) {
+ // do not write the tile because it consists of one
+ // natural type only
+ // write it only to the index
+ Way singleWay = tileData.getValue().get(0);
+ String naturalTag = singleWay.getTag("natural");
+ index.put(tileData.getKey(), naturalTag);
+ } else {
+ String ext = (usePbf ? "pbf" : "gz");
+ index.put(tileData.getKey(), "sea_" + tileData.getKey()
+ + ".osm." + ext);
+
+ OSMWriter writer = createWriter(id, tileData.getKey());
+
+ Map<Coord, Long> coordIds = new HashMap<Coord, Long>();
+
+ List<uk.me.parabola.splitter.Way> pbfWays = new ArrayList<uk.me.parabola.splitter.Way>();
+
+ for (Way w : tileData.getValue()) {
+ uk.me.parabola.splitter.Way pbfWay = new uk.me.parabola.splitter.Way();
+ pbfWay.set(w.getId());
+ for (Entry<String, String> tag : w
+ .getEntryIteratable()) {
+ pbfWay.addTag(tag.getKey(), tag.getValue());
+ }
+ for (Coord c : w.getPoints()) {
+ Node n = new Node();
+ Long nodeId = coordIds.get(c);
+ if (nodeId == null) {
+ nodeId = FakeIdGenerator.makeFakeId();
+ coordIds.put(c, nodeId);
+ n.set(nodeId,
+ Utils.toDegrees(c.getLatitude()),
+ Utils.toDegrees(c.getLongitude()));
+ try {
+ writer.write(n);
+ } catch (IOException exp) {
+ exp.printStackTrace();
+ }
+ }
+ pbfWay.addRef(nodeId);
+ }
+ pbfWays.add(pbfWay);
+ }
+ for (uk.me.parabola.splitter.Way pbfWay : pbfWays) {
+ try {
+ writer.write(pbfWay);
+ } catch (IOException exp) {
+ exp.printStackTrace();
+ }
+ }
+ writer.finishWrite();
+
+ File tileFile = new File(outputDir, String.format(
+ "%08d.osm." + ext, id));
+ File precompFile = new File(outputDir, "sea_"
+ + tileData.getKey() + ".osm." + ext);
+ if (precompFile.exists()) {
+ precompFile.delete();
+ }
+
+ tileFile.renameTo(precompFile);
+ }
+ }
+ }
+
+ writeIndex();
+
+ finishWait.countDown();
+ }
+
+ private void writeIndex() {
+ try {
+ PrintWriter indexWriter = new PrintWriter(
+ new GZIPOutputStream(new FileOutputStream(
+ new File(outputDir, "index.txt.gz"))));
+
+ for (Entry<String, String> ind : index.entrySet()) {
+ indexWriter.format("%s;%s\n", ind.getKey(), ind.getValue());
+ }
+
+ indexWriter.close();
+ } catch (IOException exp1) {
+ exp1.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/uk/me/parabola/mkgmap/sea/optional/readme.txt b/src/uk/me/parabola/mkgmap/sea/optional/readme.txt
new file mode 100644
index 0000000..ed1c05e
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/sea/optional/readme.txt
@@ -0,0 +1,38 @@
+The PrecompSeaGenerator reads a shapefile containing land polygons and
+creates precompiled sea tiles that can be used by mkgmap to create the
+land and sea areas of a map. Land polygons can be downloaded from other
+sites e.g. http://openstreetmapdata.com/data/land-polygons.
+
+The PrecompSeaGenerator can be started with:
+java -cp <mkgmap classes>;<libs> uk.me.parabola.mkgmap.sea.optional.PrecompSeaGenerator <shapefile> <projection> <outputdir>
+
+Parameters:
+shapefile: The .shp file of the ESRI shape files containing land polygons. Sea
+ polygon files are not supported.
+projection: The projection used in the shapefile (e.g. WGS84 or EPSG:3857)
+outputdir: The directory where the precompiled sea tiles are stored.
+
+
+
+The PrecompSeaGenerator is not included in the mkgmap.jar due to additional
+dependencies. The following libs must be added in order to run the
+PrecompSeaGenerator tool:
+
+Geotools library (http://sourceforge.net/projects/geotools/files/):
+commons-pool-1.5.4.jar
+gt-api-2.7.5.jar
+gt-cql-2.7.5.jar
+gt-data-2.7.5.jar
+gt-main-2.7.5.jar
+gt-metadata-2.7.5.jar
+gt-opengis-2.7.5.jar
+gt-referencing-2.7.5.jar
+gt-shapefile-2.7.5.jar
+jsr-275-1.0-beta-2.jar
+jts-1.11.jar
+vecmath-1.3.2.jar
+
+Splitter (http://www.mkgmap.org.uk/page/tile-splitter):
+splitter.jar
+
+
diff --git a/src/uk/me/parabola/mkgmap/srt/SrtTextReader.java b/src/uk/me/parabola/mkgmap/srt/SrtTextReader.java
new file mode 100644
index 0000000..f29b0f4
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/srt/SrtTextReader.java
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2010, 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.srt;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+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.CharsetEncoder;
+import java.nio.charset.CodingErrorAction;
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.srt.SRTFile;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.imgfmt.sys.FileImgChannel;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+import uk.me.parabola.mkgmap.scan.TokType;
+import uk.me.parabola.mkgmap.scan.Token;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+/**
+ * Read in a sort file from a text format.
+ *
+ * The file is in utf-8, regardless of the target codepage.
+ *
+ * The file should start with a codepage declaration, which determines the
+ * target codepage for the sort. This can be followed by a description which is
+ * added into the SRT file.
+ *
+ * The characters are listed in order arranged in a way that shows the strength of the
+ * difference between the characters. These are:
+ *
+ * Primary difference - different letters (eg a and b)
+ * Secondary difference - different accents (eg a and a-acute)
+ * Tertiary difference - different case (eg a and A)
+ *
+ * Primary differences are represented by an new 'code' line, or alternatively by the less-than separator.
+ * Secondary differences are represented by the semi-colon separator.
+ * Tertiary differences are represented by the comma separator.
+ *
+ * Characters are represented by a two digit hex number that is the code point in the target code page. Alternatively
+ * you can write the characters as themselves in <emphasis>unicode (utf-8)</emphasis> (the whole file must be in utf-8).
+ *
+ * Example
+ * <pre>
+ * # This is a comment
+ * codepage 1252
+ * description "Example sort"
+ * code a, A; â Ã
+ * code b, B
+ * # Last two lines could be written:
+ * # code a, A; â, à < b, B
+ * </pre>
+ *
+ * NOTE: as we always use upper case in an img file, the upper-lower case sorting differences are untested
+ * and based on guess work. In particular you might expect that upper-case sorts before lowercase, but we
+ * have the opposite.
+ *
+ * @author Steve Ratcliffe
+ */
+public class SrtTextReader {
+
+ // States
+ private static final int IN_INITIAL = 0;
+ private static final int IN_CODE = 1;
+ private static final int IN_EXPAND = 2;
+
+ private int codepage;
+
+ // Data that is read in, the output of the reading operation
+ private final Sort sort = new Sort();
+
+ private CharsetEncoder encoder;
+ private CharsetDecoder decoder;
+
+ // Used during parsing.
+ private int pos1;
+ private int pos2;
+ private int pos3;
+ private int state;
+ private String cflags = "";
+
+ public SrtTextReader(Reader r) throws IOException {
+ this("stream", r);
+ }
+
+ private SrtTextReader(String filename) throws IOException {
+ this(filename, new InputStreamReader(new FileInputStream(filename), "utf-8"));
+ }
+
+ private SrtTextReader(String filename, Reader r) throws IOException {
+ read(filename, r);
+ }
+
+ /**
+ * Find and read in the sort description for the given codepage.
+ */
+ public static Sort sortForCodepage(int codepage) {
+ String name = "sort/cp" + codepage + ".txt";
+ InputStream is = Sort.class.getClassLoader().getResourceAsStream(name);
+ if (is == null)
+ return Sort.defaultSort(codepage);
+
+ try {
+ InputStreamReader r = new InputStreamReader(is, "utf-8");
+ SrtTextReader sr = new SrtTextReader(r);
+ return sr.getSort();
+ } catch (IOException e) {
+ return Sort.defaultSort(codepage);
+ }
+ }
+
+ /**
+ * Read in a file and save the information in a form that can be used
+ * to compare strings.
+ * @param filename The name of the file, used for display purposes. It need
+ * not refer to a file that actually exists.
+ * @param r The opened file or other readable source.
+ * @throws SyntaxException If the format of the file is incorrect.
+ */
+ public void read(String filename, Reader r) {
+ TokenScanner scanner = new TokenScanner(filename, r);
+ resetPos();
+ state = IN_INITIAL;
+ while (!scanner.isEndOfFile()) {
+ Token tok = scanner.nextRawToken();
+
+ // We deal with whole line comments here
+ if (tok.isValue("#")) {
+ scanner.skipLine();
+ continue;
+ }
+
+ switch (state) {
+ case IN_INITIAL:
+ initialState(scanner, tok);
+ break;
+ case IN_CODE:
+ codeState(scanner, tok);
+ break;
+ case IN_EXPAND:
+ expandState(scanner, tok);
+ break;
+ }
+ }
+ }
+
+ /**
+ * The initial state, looking for a variable to set or a command to change
+ * the state.
+ * @param scanner The scanner for more tokens.
+ * @param tok The first token to process.
+ */
+ private void initialState(TokenScanner scanner, Token tok) {
+ String val = tok.getValue();
+ TokType type = tok.getType();
+ if (type == TokType.TEXT) {
+ if (val.equals("codepage")) {
+ codepage = scanner.nextInt();
+ sort.setCodepage(codepage);
+ Charset charset = Charset.forName("cp" + codepage);
+ encoder = charset.newEncoder();
+ decoder = charset.newDecoder();
+ decoder.onMalformedInput(CodingErrorAction.REPORT);
+ } else if (val.equals("description")) {
+ sort.setDescription(scanner.nextWord());
+ } else if (val.equals("id1")) {
+ sort.setId1(scanner.nextInt());
+ } else if (val.equals("id2")) {
+ sort.setId2(scanner.nextInt());
+ } else if (val.equals("code")) {
+ if (codepage == 0)
+ throw new SyntaxException(scanner, "Missing codepage declaration before code");
+ state = IN_CODE;
+ scanner.skipSpace();
+ } else if (val.equals("expand")) {
+ state = IN_EXPAND;
+ scanner.skipSpace();
+ } else {
+ throw new SyntaxException(scanner, "Unrecognised command " + val);
+ }
+ }
+ }
+
+ /**
+ * Inside a code block that describes a set of characters that all sort
+ * at the same major position.
+ * @param scanner The scanner for more tokens.
+ * @param tok The current token to process.
+ */
+ private void codeState(TokenScanner scanner, Token tok) {
+ String val = tok.getValue();
+ TokType type = tok.getType();
+ if (type == TokType.TEXT) {
+ if (val.equals("flags")) {
+ scanner.validateNext("=");
+ cflags = scanner.nextWord();
+ // TODO not yet
+ } else if (val.equals("pos")) {
+ scanner.validateNext("=");
+ try {
+ int newPos = Integer.decode(scanner.nextWord());
+ if (newPos < pos1)
+ throw new SyntaxException(scanner, "cannot set primary position backwards, was " + pos1);
+ pos1 = newPos;
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(scanner, "invalid integer for position");
+ }
+ } else if (val.equals("pos2")) {
+ scanner.validateNext("=");
+ pos2 = Integer.decode(scanner.nextWord());
+ } else if (val.equals("pos3")) {
+ scanner.validateNext("=");
+ pos3 = Integer.decode(scanner.nextWord());
+ } else if (val.length() == 1 || val.length() == 2) {
+ addCharacter(scanner, val);
+ } else {
+ throw new SyntaxException(scanner, "Unexpected word " + val);
+ }
+ } else if (type == TokType.SYMBOL) {
+ if (val.equals(",")) {
+ pos3++;
+ } else if (val.equals(";")) {
+ pos3 = 1;
+ pos2++;
+ } else if (val.equals("<")) {
+ advancePos();
+ } else {
+ addCharacter(scanner, val);
+ }
+
+ } else if (type == TokType.EOL) {
+ state = IN_INITIAL;
+ advancePos();
+ }
+ }
+
+ /**
+ * Within an 'expand' command. The whole command is read before
+ * return, they can not span lines.
+ * @param tok The first token after the keyword.
+ */
+ private void expandState(TokenScanner scanner, Token tok) {
+ String val = tok.getValue();
+
+ Code code = new Code(scanner, val).invoke();
+
+ String s = scanner.nextValue();
+ if (!s.equals("to"))
+ throw new SyntaxException(scanner, "Expected the word 'to' in expand command");
+
+ List<Byte> expansionList = new ArrayList<Byte>();
+ while (!scanner.isEndOfFile()) {
+ Token t = scanner.nextRawToken();
+ if (t.isEol())
+ break;
+ if (t.isWhiteSpace())
+ continue;
+
+ Code r = new Code(scanner, t.getValue()).invoke();
+ expansionList.add(r.getBval());
+ }
+
+ sort.addExpansion(code.getBval(), charFlags(code.getCval()), expansionList);
+ state = IN_INITIAL;
+ }
+
+ /**
+ * Add a character to the sort table.
+ * @param scanner Input scanner, for line number information.
+ * @param val A single character string containing the character to be added. This will
+ * be either a single character which is the unicode representation of the character, or
+ * two characters which is the hex representation of the code point in the target codepage.
+ */
+ private void addCharacter(TokenScanner scanner, String val) {
+ Code code = new Code(scanner, val).invoke();
+ setSortcode(code.getBval(), code.getCval());
+ }
+
+ /**
+ * Set the sort code for the given 8-bit character.
+ * @param b The 8-bit character in the character set of the codepage.
+ * @param cval The same character in unicode.
+ */
+ private void setSortcode(byte b, char cval) {
+ int flags = charFlags(cval);
+ if (cflags.contains("0"))
+ flags = 0;
+
+ sort.add(b, pos1, pos2, pos3, flags);
+ this.cflags = "";
+ }
+
+ /**
+ * The flags that describe the kind of character. Known ones
+ * are letter and digit. There may be others.
+ * @param cval The actual character (unicode).
+ * @return The flags that apply to it.
+ */
+ private int charFlags(char cval) {
+ int flags = 0;
+ if (Character.isLetter(cval) && (Character.getType(cval) & Character.MODIFIER_LETTER) == 0)
+ flags = 1;
+ if (Character.isDigit(cval))
+ flags = 2;
+ return flags;
+ }
+
+ /**
+ * Reset the position fields to their initial values.
+ */
+ private void resetPos() {
+ pos1 = 0;
+ pos2 = 1;
+ pos3 = 1;
+ }
+
+ /**
+ * Advance the major position value, resetting the minor position variables.
+ */
+ private void advancePos() {
+ pos1 += pos2;
+ pos2 = 1;
+ pos3 = 1;
+ }
+
+ public Sort getSort() {
+ return sort;
+ }
+
+ /**
+ * Read in a sort description text file and create a SRT from it.
+ * @param args First arg is the text input file, the second is the name of the output file. The defaults are
+ * in.txt and out.srt.
+ */
+ public static void main(String[] args) throws IOException {
+ String infile = "in.txt";
+ if (args.length > 0)
+ infile = args[0];
+
+ String outfile = "out.srt";
+ if (args.length > 1)
+ outfile = args[1];
+ ImgChannel chan = new FileImgChannel(outfile, "rw");
+ SRTFile sf = new SRTFile(chan);
+
+ SrtTextReader tr = new SrtTextReader(infile);
+ Sort sort1 = tr.getSort();
+ sf.setSort(sort1);
+ sf.setDescription(sort1.getDescription());
+ sf.write();
+ sf.close();
+ chan.close();
+ }
+
+ /**
+ * Helper to represent a code read from the file.
+ *
+ * You can write it in unicode, or as a two digit hex number.
+ * We work out what you wrote, and return both the code point in
+ * the codepage and the unicode character form of the letter.
+ */
+ private class Code {
+ private final TokenScanner scanner;
+ private final String val;
+ private byte bval;
+ private char cval;
+
+ public Code(TokenScanner scanner, String val) {
+ this.scanner = scanner;
+ this.val = val;
+ }
+
+ public byte getBval() {
+ return bval;
+ }
+
+ public char getCval() {
+ return cval;
+ }
+
+ public Code invoke() {
+ try {
+ if (val.length() == 1) {
+ CharBuffer cbuf = CharBuffer.wrap(val.toCharArray());
+ ByteBuffer out = encoder.encode(cbuf);
+ if (out.remaining() > 1)
+ throw new SyntaxException(scanner, "more than one character resulted from conversion of " + val);
+
+ bval = out.get();
+ cval = val.charAt(0);
+ } else {
+ bval = (byte) Integer.parseInt(val, 16);
+ ByteBuffer bin = ByteBuffer.allocate(1);
+ bin.put(bval);
+ bin.flip();
+ CharBuffer out = decoder.decode(bin);
+ cval = out.get();
+ }
+ } catch (CharacterCodingException e) {
+ throw new SyntaxException(scanner, "Not a valid character (" + val + ") in codepage");
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(scanner, "Not a valid hex number " + val);
+ }
+ return this;
+ }
+
+ public String toString() {
+ return String.format("%02x: %c (0x%x)", bval, cval, (int) cval);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/typ/CommonSection.java b/src/uk/me/parabola/mkgmap/typ/CommonSection.java
new file mode 100644
index 0000000..b77b052
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/typ/CommonSection.java
@@ -0,0 +1,407 @@
+/*
+ * 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.typ;
+
+import java.io.StringReader;
+import java.util.HashSet;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.app.typ.AlphaAdder;
+import uk.me.parabola.imgfmt.app.typ.BitmapImage;
+import uk.me.parabola.imgfmt.app.typ.ColourInfo;
+import uk.me.parabola.imgfmt.app.typ.Image;
+import uk.me.parabola.imgfmt.app.typ.Rgb;
+import uk.me.parabola.imgfmt.app.typ.TrueImage;
+import uk.me.parabola.imgfmt.app.typ.TypData;
+import uk.me.parabola.imgfmt.app.typ.TypElement;
+import uk.me.parabola.imgfmt.app.typ.Xpm;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+import uk.me.parabola.mkgmap.scan.Token;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+/**
+ * Much of the processing between lines and polygons is the same, these routines
+ * are shared.
+ *
+ * @author Steve Ratcliffe
+ */
+public class CommonSection {
+ private static final Set<String> seen = new HashSet<String>();
+ protected final TypData data;
+ private boolean hasXpm;
+
+ protected CommonSection(TypData data) {
+ this.data = data;
+ }
+
+ /**
+ * Deal with all the keys that are common to the different element types.
+ * Most tags are in fact the same for every element.
+ *
+ * @return True if this routine has processed the tag.
+ */
+ protected boolean commonKey(TokenScanner scanner, TypElement current, String name, String value) {
+ if (name.equalsIgnoreCase("Type")) {
+ try {
+ int ival = Integer.decode(value);
+ if (ival >= 0x100) {
+ current.setType(ival >>> 8);
+ current.setSubType(ival & 0xff);
+ } else {
+ current.setType(ival & 0xff);
+ }
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(scanner, "Bad number " + value);
+ }
+
+ } else if (name.equalsIgnoreCase("SubType")) {
+ try {
+ int ival = Integer.decode(value);
+ current.setSubType(ival);
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(scanner, "Bad number for sub type " + value);
+ }
+
+ } else if (name.toLowerCase().startsWith("string")) {
+ try {
+ current.addLabel(value);
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(scanner, "Bad number in " + value);
+ }
+
+ } else if (name.equalsIgnoreCase("Xpm")) {
+ Xpm xpm = readXpm(scanner, value, current.simpleBitmap());
+ current.setXpm(xpm);
+
+ } else if (name.equalsIgnoreCase("FontStyle")) {
+ int font = decodeFontStyle(value);
+ current.setFontStyle(font);
+
+ } else if (name.equalsIgnoreCase("CustomColor") || name.equals("ExtendedLabels")) {
+ // These are just noise, the appropriate flag is set if any feature is used.
+
+ } else if (name.equalsIgnoreCase("DaycustomColor")) {
+ current.setDayFontColor(value);
+
+ } else if (name.equalsIgnoreCase("NightcustomColor")) {
+ current.setNightCustomColor(value);
+
+ } else if (name.equalsIgnoreCase("Comment")) {
+ // a comment that is ignored.
+ } else {
+ return false;
+ }
+
+ return true;
+ }
+
+ protected int decodeFontStyle(String value) {
+ if (value.startsWith("NoLabel") || value.equalsIgnoreCase("nolabel")) {
+ return 1;
+ } else if (value.equalsIgnoreCase("SmallFont") || value.equalsIgnoreCase("Small")) {
+ return 2;
+ } else if (value.equalsIgnoreCase("NormalFont") || value.equalsIgnoreCase("Normal")) {
+ return 3;
+ } else if (value.equalsIgnoreCase("LargeFont") || value.equalsIgnoreCase("Large")) {
+ return 4;
+ } else if (value.equalsIgnoreCase("Default")) {
+ return 0;
+ } else {
+ warnUnknown("font value " + value);
+ return 0;
+ }
+ }
+
+ /**
+ * Parse the XPM header in a typ file.
+ *
+ * There are extensions compared to a regular XPM file.
+ *
+ * @param scanner Only for reporting syntax errors.
+ * @param info Information read from the string is stored here.
+ * @param header The string containing the xpm header and other extended data provided on the
+ * same line.
+ */
+ private void parseXpmHeader(TokenScanner scanner, ColourInfo info, String header) {
+ TokenScanner s2 = new TokenScanner("string", new StringReader(header));
+
+ if (s2.checkToken("\""))
+ s2.nextToken();
+
+ try {
+ info.setWidth(s2.nextInt());
+ info.setHeight(s2.nextInt());
+ info.setNumberOfColours(s2.nextInt());
+ info.setCharsPerPixel(s2.nextInt());
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(scanner, "Bad number in XPM header " + header);
+ }
+ }
+
+ /**
+ * Read the colour lines from the XPM format image.
+ */
+ protected ColourInfo readColourInfo(TokenScanner scanner, String header) {
+
+ ColourInfo colourInfo = new ColourInfo();
+ parseXpmHeader(scanner, colourInfo, header);
+
+ for (int i = 0; i < colourInfo.getNumberOfColours(); i++) {
+ scanner.validateNext("\"");
+
+ int cpp = colourInfo.getCharsPerPixel();
+
+ Token token = scanner.nextRawToken();
+ String colourTag = token.getValue();
+ while (colourTag.length() < cpp)
+ colourTag += scanner.nextRawToken().getValue();
+ colourTag = colourTag.substring(0, cpp);
+
+ scanner.validateNext("c");
+
+ String colour = scanner.nextValue();
+ if (colour.charAt(0) == '#') {
+ colour = scanner.nextValue();
+ colourInfo.addColour(colourTag, new Rgb(colour));
+ } else if (colour.equalsIgnoreCase("none")) {
+ colourInfo.addTransparent(colourTag);
+ } else {
+ throw new SyntaxException(scanner, "Unrecognised colour: " + colour);
+ }
+
+ scanner.validateNext("\"");
+
+ readExtraColourInfo(scanner, colourInfo);
+ }
+
+ return colourInfo;
+ }
+
+ /**
+ * Get any keywords that are on the end of the colour line. Must not step
+ * over the new line boundary.
+ */
+ private void readExtraColourInfo(TokenScanner scanner, AlphaAdder colour) {
+ while (!scanner.isEndOfFile()) {
+ Token tok = scanner.nextRawToken();
+ if (tok.isEol())
+ break;
+
+ String word = tok.getValue();
+
+ // TypWiz uses alpha, TypViewer uses "canalalpha"
+ if (word.endsWith("alpha")) {
+ scanner.validateNext("=");
+ String aval = scanner.nextValue();
+
+ try {
+ // Convert to rgba format
+ int alpha = Integer.decode(aval);
+ alpha = 255 - ((alpha<<4) + alpha);
+ colour.addAlpha(alpha);
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(scanner, "Bad number for alpha value " + aval);
+ }
+
+ } // ignore everything we don't recognise.
+ }
+ }
+
+ /**
+ * Read the bitmap part of a XPM image.
+ *
+ * In the TYP file, XPM is used when there is not really an image, so this is not
+ * always called.
+ *
+ * Almost all of this routine is checking that the strings are valid. They have the
+ * correct length, there are quotes at the beginning and end at that each pixel tag
+ * is listed in the colours section.
+ */
+ protected BitmapImage readImage(TokenScanner scanner, ColourInfo colourInfo) {
+ StringBuffer sb = new StringBuffer();
+ int width = colourInfo.getWidth();
+ int height = colourInfo.getHeight();
+ int cpp = colourInfo.getCharsPerPixel();
+
+ for (int i = 0; i < height; i++) {
+ String line = scanner.readLine();
+ if (line.isEmpty())
+ throw new SyntaxException(scanner, "Invalid blank line in bitmap.");
+
+ if (line.charAt(0) != '"')
+ throw new SyntaxException(scanner, "xpm bitmap line must start with a quote: " + line);
+ if (line.length() < 1 + width * cpp)
+ throw new SyntaxException(scanner, "short image line: " + line);
+
+ line = line.substring(1, 1+width*cpp);
+ sb.append(line);
+
+ // Do the syntax check, to avoid an error later when we don't have the line number any more
+ for (int cidx = 0; cidx < width * cpp; cidx += cpp) {
+ String tag = line.substring(cidx, cidx + cpp);
+ try {
+ colourInfo.getIndex(tag);
+ } catch (Exception e) {
+ throw new SyntaxException(scanner,
+ String.format("Tag '%s' is not one of the defined colour pixels", tag));
+ }
+ }
+ }
+
+ if (sb.length() != width * height * cpp) {
+ throw new SyntaxException(scanner, "Got " + sb.length() + " of image data, " +
+ "expected " + width * height * cpp);
+ }
+
+ return new BitmapImage(colourInfo, sb.toString());
+ }
+
+
+ /**
+ * The true image format is represented by one colour value for each pixel in the
+ * image.
+ *
+ * The colours are on several lines surrounded by double quotes.
+ * <pre>
+ * "#ff9900 #ffaa11 #feab10 #feab10"
+ * "#f79900 #f7aa11 #feab10 #feab20"
+ * ...
+ * </pre>
+ * There can be any number of colours on the same line, and the spaces are not needed.
+ *
+ * Transparency is represented by using RGBA values "#ffeeff00" or by appending alpha=N
+ * to the end of the colour line. If using the 'alpha=N' method, then there can be only one
+ * colour per line (well it is only the last colour value that is affected if more than one).
+ *
+ * <pre>
+ * "#ff8801" alpha=2
+ * </pre>
+ *
+ * The alpha values go from 0 to 15 where 0 is opaque and 15 transparent.
+ */
+ private Image readTrueImage(TokenScanner scanner, ColourInfo colourInfo) {
+ int width = colourInfo.getWidth();
+ int height = colourInfo.getHeight();
+ final int[] image = new int[width * height];
+
+ int nPixels = width * height;
+
+ int count = 0;
+ while (count < nPixels) {
+ scanner.validateNext("\"");
+ count = readTrueImageLine(scanner, image, count);
+ }
+
+ if (scanner.checkToken("\"")) {
+ // An extra colour, so this is probably meant to be a mode=16 image.
+ // Remove the first pixel and shuffle the rest down, unset the alpha
+ // on all the transparent pixels.
+ int transPixel = image[0];
+ for (int i = 1; i < nPixels; i++) {
+ int pix = image[i];
+ if (pix == transPixel)
+ pix &= ~0xff;
+ image[i-1] = pix;
+ }
+
+ // Add the final pixel
+ scanner.validateNext("\"");
+ readTrueImageLine(scanner, image, nPixels-1);
+ }
+
+ return new TrueImage(colourInfo, image);
+ }
+
+ /**
+ * Read a single line of pixel colours.
+ *
+ * There can be one or more colours on the line and the colours are surrounded
+ * by quotes. The can be trailing attribute that sets the opacity of
+ * the final pixel.
+ */
+ private int readTrueImageLine(TokenScanner scanner, final int[] image, int count) {
+ do {
+ scanner.validateNext("#");
+ String col = scanner.nextValue();
+ try {
+ int val = (int) Long.parseLong(col, 16);
+ if (col.length() <= 6)
+ val = (val << 8) + 0xff;
+
+ image[count++] = val;
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(scanner, "Not a valid colour value ");
+ }
+ } while (scanner.checkToken("#"));
+ scanner.validateNext("\"");
+
+ // Look for any trailing alpha=N stuff.
+ final int lastColourIndex = count - 1;
+ readExtraColourInfo(scanner, new AlphaAdder() {
+ /**
+ * Add the alpha value to the last colour that was read in.
+ *
+ * @param alpha A true alpha value ie 0 is transparent, 255 opaque.
+ */
+ public void addAlpha(int alpha) {
+ image[lastColourIndex] = (image[lastColourIndex] & ~0xff) | (alpha & 0xff);
+ }
+ });
+
+ return count;
+ }
+
+ /**
+ * Read an XMP image from the input scanner.
+ *
+ * Note that this is sometimes used just for colours so need to deal with
+ * different cases.
+ */
+ protected Xpm readXpm(TokenScanner scanner, String header, boolean simple) {
+ ColourInfo colourInfo = readColourInfo(scanner, header);
+ String msg = colourInfo.analyseColours(simple);
+ if (msg != null)
+ throw new SyntaxException(scanner, msg);
+
+ Xpm xpm = new Xpm();
+ xpm.setColourInfo(colourInfo);
+
+ int height = colourInfo.getHeight();
+ int width = colourInfo.getWidth();
+ if (height > 0 && width > 0) {
+ colourInfo.setHasBitmap(true);
+ Image image;
+ if (colourInfo.getNumberOfColours() == 0)
+ image = readTrueImage(scanner, colourInfo);
+ else
+ image = readImage(scanner, colourInfo);
+ xpm.setImage(image);
+ }
+
+ hasXpm = true;
+ return xpm;
+ }
+
+ protected void warnUnknown(String name) {
+ if (seen.contains(name))
+ return;
+
+ seen.add(name);
+ System.out.printf("Warning: tag '%s' not known\n", name);
+ }
+
+ protected void validate(TokenScanner scanner) {
+ if (!hasXpm)
+ throw new SyntaxException(scanner, "No XPM tag in section");
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/typ/DrawOrderSection.java b/src/uk/me/parabola/mkgmap/typ/DrawOrderSection.java
new file mode 100644
index 0000000..fe5fa26
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/typ/DrawOrderSection.java
@@ -0,0 +1,71 @@
+/*
+ * 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.typ;
+
+import uk.me.parabola.imgfmt.app.typ.TypData;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+/**
+ * Process lines from the draw order section of the typ.txt file.
+ *
+ * @author Steve Ratcliffe
+ */
+class DrawOrderSection implements ProcessSection {
+ private final TypData data;
+
+ DrawOrderSection(TypData data) {
+ this.data = data;
+ }
+
+ /**
+ * There is only one tag in this section.
+ */
+ public void processLine(TokenScanner scanner, String name, String value) {
+ if (!name.equalsIgnoreCase("Type"))
+ throw new SyntaxException(scanner, "Unrecognised keyword in draw order section: " + name);
+
+ String[] typeDrawOrder = value.split(",",-1);
+ if (typeDrawOrder.length != 2)
+ throw new SyntaxException(scanner, "Unrecognised drawOrder type " + value);
+
+ int fulltype;
+ try {
+ fulltype = Integer.decode(typeDrawOrder[0]);
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(scanner, "Bad number " + typeDrawOrder[0]);
+ }
+ int type;
+ int subtype = 0;
+
+ if (fulltype >= 0x100) {
+ type = (fulltype >>> 8) & 0x3fff;
+ subtype = fulltype & 0xff;
+ } else {
+ type = fulltype & 0xff;
+ }
+
+ try {
+ int level = Integer.parseInt(typeDrawOrder[1]);
+ data.addPolygonStackOrder(level, type, subtype);
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(scanner, "Bad number '" + typeDrawOrder[1] + "'");
+ }
+ }
+
+ /**
+ * Nothing to do, each line stands by itself.
+ */
+ public void finish(TokenScanner scanner) {
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/typ/IconSection.java b/src/uk/me/parabola/mkgmap/typ/IconSection.java
new file mode 100644
index 0000000..2adb971
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/typ/IconSection.java
@@ -0,0 +1,54 @@
+/*
+ * 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.typ;
+
+import uk.me.parabola.imgfmt.app.typ.TypData;
+import uk.me.parabola.imgfmt.app.typ.TypIconSet;
+import uk.me.parabola.imgfmt.app.typ.Xpm;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+/**
+ * The new icon type. There are several icons at different resolutions.
+ *
+ * @author Steve Ratcliffe
+ */
+public class IconSection extends CommonSection implements ProcessSection {
+ private final TypIconSet current = new TypIconSet();
+
+ protected IconSection(TypData data) {
+ super(data);
+ }
+
+ public void processLine(TokenScanner scanner, String name, String value) {
+ if (name.equalsIgnoreCase("String")) {
+ // There is only one string and it doesn't have a language prefix.
+ // But if it does we will just ignore it.
+ current.addLabel(value);
+ return;
+ }
+
+ if (commonKey(scanner, current, name, value))
+ return;
+
+ if (name.equalsIgnoreCase("IconXpm")) {
+ Xpm xpm = readXpm(scanner, value, current.simpleBitmap());
+ current.addIcon(xpm);
+ } else {
+ warnUnknown(name);
+ }
+ }
+
+ public void finish(TokenScanner scanner) {
+ data.addIcon(current);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/typ/IdSection.java b/src/uk/me/parabola/mkgmap/typ/IdSection.java
new file mode 100644
index 0000000..01dffe8
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/typ/IdSection.java
@@ -0,0 +1,53 @@
+/*
+ * 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.typ;
+
+import uk.me.parabola.imgfmt.app.typ.TypData;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+import uk.me.parabola.mkgmap.srt.SrtTextReader;
+
+/**
+ * Process lines from the id section of a typ.txt file.
+ *
+ * @author Steve Ratcliffe
+ */
+class IdSection implements ProcessSection {
+ private final TypData data;
+
+ public IdSection(TypData data) {
+ this.data = data;
+ }
+
+ public void processLine(TokenScanner scanner, String name, String value) {
+ int ival;
+ try {
+ ival = Integer.decode(value);
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(scanner, "Bad integer " + value);
+ }
+
+ if (name.equalsIgnoreCase("FID")) {
+ data.setFamilyId(ival);
+ } else if (name.equalsIgnoreCase("ProductCode")) {
+ data.setProductId(ival);
+ } else if (name.equalsIgnoreCase("CodePage")) {
+ data.setSort(SrtTextReader.sortForCodepage(ival));
+ } else {
+ throw new SyntaxException(scanner, "Unrecognised keyword in id section: " + name);
+ }
+ }
+
+ public void finish(TokenScanner scanner) {
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/typ/IgnoreSection.java b/src/uk/me/parabola/mkgmap/typ/IgnoreSection.java
new file mode 100644
index 0000000..704e3d9
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/typ/IgnoreSection.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.typ;
+
+import uk.me.parabola.imgfmt.app.typ.TypData;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+/**
+ * A section processor that does nothing.
+ *
+ * Used for unknown sections, or for sections that we want to ignore.
+ *
+ * @author Steve Ratcliffe
+ */
+public class IgnoreSection implements ProcessSection {
+ public IgnoreSection(TypData data) {
+ }
+
+ public void processLine(TokenScanner scanner, String name, String value) {
+ }
+
+ public void finish(TokenScanner scanner) {
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/typ/LineSection.java b/src/uk/me/parabola/mkgmap/typ/LineSection.java
new file mode 100644
index 0000000..ef40449
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/typ/LineSection.java
@@ -0,0 +1,65 @@
+/*
+ * 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.typ;
+
+import uk.me.parabola.imgfmt.app.typ.TypData;
+import uk.me.parabola.imgfmt.app.typ.TypLine;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+/**
+ * Process lines from a line definition in the typ.txt file.
+ *
+ * Most of the work is done in the superclass since all the element types
+ * are very similar.
+ *
+ * @author Steve Ratcliffe
+ */
+class LineSection extends CommonSection implements ProcessSection {
+
+ private final TypLine current = new TypLine();
+
+ LineSection(TypData data) {
+ super(data);
+ }
+
+ public void processLine(TokenScanner scanner, String name, String value) {
+ if (commonKey(scanner, current, name, value))
+ return;
+
+ if (name.equalsIgnoreCase("UseOrientation")) {
+ current.setUseOrientation(value.charAt(0) == 'Y');
+ } else if (name.equalsIgnoreCase("LineWidth")) {
+ try {
+ int ival = Integer.decode(value);
+ current.setLineWidth(ival);
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(scanner, "Bad number for line width: " + value);
+ }
+ } else if (name.equalsIgnoreCase("BorderWidth")) {
+ try {
+ int ival = Integer.decode(value);
+ current.setBorderWidth(ival);
+ } catch (NumberFormatException e) {
+ throw new SyntaxException(scanner, "Bad number for line width: " + value);
+ }
+ } else
+ warnUnknown(name);
+ }
+
+ public void finish(TokenScanner scanner) {
+ validate(scanner);
+ current.finish();
+ data.addLine(current);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/typ/PointSection.java b/src/uk/me/parabola/mkgmap/typ/PointSection.java
new file mode 100644
index 0000000..8f44210
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/typ/PointSection.java
@@ -0,0 +1,54 @@
+/*
+ * 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.typ;
+
+import uk.me.parabola.imgfmt.app.typ.TypData;
+import uk.me.parabola.imgfmt.app.typ.TypPoint;
+import uk.me.parabola.imgfmt.app.typ.Xpm;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+/**
+ * Process lines from the point section.
+ *
+ * @author Steve Ratcliffe
+ */
+class PointSection extends CommonSection implements ProcessSection {
+
+ private final TypPoint current = new TypPoint();
+
+ protected PointSection(TypData data) {
+ super(data);
+ }
+
+ public void processLine(TokenScanner scanner, String name, String value) {
+ if (commonKey(scanner, current, name, value))
+ return;
+
+ if (name.equalsIgnoreCase("DayXpm")) {
+ Xpm xpm = readXpm(scanner, value, current.simpleBitmap());
+ current.setXpm(xpm);
+
+ } else if (name.equalsIgnoreCase("NightXpm")) {
+ Xpm xpm = readXpm(scanner, value, current.simpleBitmap());
+ current.setNightXpm(xpm);
+
+ } else {
+ warnUnknown(name);
+ }
+ }
+
+ public void finish(TokenScanner scanner) {
+ validate(scanner);
+ data.addPoint(current);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/typ/PolygonSection.java b/src/uk/me/parabola/mkgmap/typ/PolygonSection.java
new file mode 100644
index 0000000..66909e3
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/typ/PolygonSection.java
@@ -0,0 +1,48 @@
+/*
+ * 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.typ;
+
+import uk.me.parabola.imgfmt.app.typ.TypData;
+import uk.me.parabola.imgfmt.app.typ.TypPolygon;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+/**
+ * Process lines from the polygon section of a typ.txt file.
+ *
+ * This is the simplest, so all the work is done in the superclass.
+ *
+ * @author Steve Ratcliffe
+ */
+class PolygonSection extends CommonSection implements ProcessSection {
+
+ private final TypPolygon current = new TypPolygon();
+
+ PolygonSection(TypData data) {
+ super(data);
+ }
+
+ public void processLine(TokenScanner scanner, String name, String value) {
+ if (commonKey(scanner, current, name, value))
+ return;
+
+ warnUnknown(name);
+ }
+
+ /**
+ * Add the polygon to the data and reset for the next.
+ */
+ public void finish(TokenScanner scanner) {
+ validate(scanner);
+ data.addPolygon(current);
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/typ/ProcessSection.java b/src/uk/me/parabola/mkgmap/typ/ProcessSection.java
new file mode 100644
index 0000000..769bdf3
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/typ/ProcessSection.java
@@ -0,0 +1,39 @@
+/*
+ * 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.typ;
+
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+/**
+ * Interface for classes that are used to process sections ot the typ.txt file.
+ *
+ * @author Steve Ratcliffe
+ */
+interface ProcessSection {
+ /**
+ * Process a single key value pair read from the typ.txt file.
+ *
+ * If the tag has data on the following lines, then it must read it all before returning.
+ *
+ * @param scanner The scanner to get any extra data and for use in error messages.
+ * @param name The key.
+ * @param value The data value of this line.
+ */
+ public void processLine(TokenScanner scanner, String name, String value);
+
+ /**
+ * Called at the end of a section. The item will have been fully defined and so can be saved.
+ * @param scanner
+ */
+ public void finish(TokenScanner scanner);
+}
diff --git a/src/uk/me/parabola/mkgmap/typ/TypTextReader.java b/src/uk/me/parabola/mkgmap/typ/TypTextReader.java
new file mode 100644
index 0000000..a2c25f8
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/typ/TypTextReader.java
@@ -0,0 +1,127 @@
+/*
+ * 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.typ;
+
+import java.io.Reader;
+
+import uk.me.parabola.imgfmt.app.typ.TypData;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+import uk.me.parabola.mkgmap.scan.TokType;
+import uk.me.parabola.mkgmap.scan.Token;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+/**
+ * Read in a TYP file in the text format.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TypTextReader {
+ private static final Logger log = Logger.getLogger(TypTextReader.class);
+
+ // As the file is read in, the information is saved into this data structure.
+ private final TypData data = new TypData();
+
+ public void read(String filename, Reader r) {
+ TokenScanner scanner = new TokenScanner(filename, r);
+ scanner.setCommentChar(null); // the '#' comment character is not appropriate for this file
+
+ ProcessSection currentSection = null;
+
+ while (!scanner.isEndOfFile()) {
+ Token tok = scanner.nextToken();
+ if (tok.getType() == TokType.EOF)
+ break;
+
+ // We deal with whole line comments here
+ if (tok.isValue(";")) {
+ scanner.skipLine();
+ continue;
+ }
+
+ if (tok.getType() == TokType.SYMBOL) {
+ switch (tok.getValue().charAt(0)) {
+ case ';':
+ scanner.skipLine();
+ break;
+ case '[':
+ ProcessSection newSection = readSectionType(scanner);
+ if (currentSection != null)
+ currentSection.finish(scanner);
+ currentSection = newSection;
+ break;
+ case '"':
+ scanner.skipLine();
+ break;
+ }
+ } else {
+ // Line inside a section
+ String name = tok.getValue();
+
+ String sep = scanner.nextValue();
+ if (!sep.equals("=") && !sep.equals(":"))
+ throw new SyntaxException(scanner, "Expecting '=' or ':' instead of " + sep);
+
+ String value = scanner.readLine();
+
+ if (currentSection == null)
+ throw new SyntaxException(scanner, "Missing section start");
+
+ currentSection.processLine(scanner, name, value);
+ }
+ scanner.skipSpace();
+ }
+ }
+
+ /**
+ * Read the section name and return a section processor for it.
+ *
+ * The input stream must be positioned just after the open bracket of the section name. The closing bracket
+ * is also consumed. The section name is case insensitive.
+ *
+ * Unknown sections result in a processor that ignores all lines in the section.
+ *
+ * @param scanner Input token stream.
+ * @return A section processor to process lines from the section. Returns null if this is
+ * the end of the section rather than the start.
+ */
+ private ProcessSection readSectionType(TokenScanner scanner) {
+ String sectionName = scanner.nextValue().toLowerCase();
+ scanner.validateNext("]"); // Check for closing bracket
+
+ // End of the section, so the processor is reset to null
+ if ("end".equals(sectionName)) {
+ return null;
+
+ } else if ("_point".equals(sectionName)) {
+ return new PointSection(data);
+ } else if ("_line".equals(sectionName)) {
+ return new LineSection(data);
+ } else if ("_polygon".equals(sectionName)) {
+ return new PolygonSection(data);
+ } else if ("_draworder".equals(sectionName)) {
+ return new DrawOrderSection(data);
+ } else if ("_icons".equals(sectionName)) {
+ return new IconSection(data);
+ } else if ("_id".equals(sectionName)) {
+ return new IdSection(data);
+ } else {
+ log.warn("Unrecognised section " + sectionName);
+ return new IgnoreSection(data);
+ }
+ }
+
+ public TypData getData() {
+ return data;
+ }
+}
diff --git a/src/uk/me/parabola/tdbfmt/Block.java b/src/uk/me/parabola/tdbfmt/Block.java
new file mode 100644
index 0000000..5fbe2a2
--- /dev/null
+++ b/src/uk/me/parabola/tdbfmt/Block.java
@@ -0,0 +1,121 @@
+/*
+ * 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: 23-Sep-2007
+ */
+package uk.me.parabola.tdbfmt;
+
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.io.StructuredInputStream;
+import uk.me.parabola.io.StructuredOutputStream;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A block within the tdb file. Really just a type and the contents.
+ *
+ * @author Steve Ratcliffe
+ */
+class Block {
+ private static final Logger log = Logger.getLogger(Block.class);
+
+ private final int blockId;
+ private int blockLength;
+ private byte[] body;
+ private StructuredInputStream istream;
+ private ByteArrayOutputStream arrayBody;
+ private StructuredOutputStream ostream;
+
+ /**
+ * Create a block that is going to be written to.
+ * @param blockId The id for this block.
+ */
+ Block(int blockId) {
+ this.blockId = blockId;
+ }
+
+ /**
+ * Create a block from data that is read in from a file.
+ * @param type The block type.
+ * @param body The raw bytes in the block.
+ */
+ Block(int type, byte[] body) {
+ blockId = type;
+ this.body = body;
+ this.blockLength = body.length;
+ ByteArrayInputStream stream = new ByteArrayInputStream(body);
+ this.istream = new StructuredInputStream(stream);
+ }
+
+ public int getBlockId() {
+ return blockId;
+ }
+
+ /**
+ * Get the raw bytes for this block. The source depends on if this block
+ * was constructed from file data, or is being created from program calls
+ * so that it can be written.
+ *
+ * @return A byte array of the raw bytes representing this block.
+ */
+ byte[] getBody() {
+ if (body == null && arrayBody != null) {
+ byte[] bytes = arrayBody.toByteArray();
+
+ blockLength = bytes.length - 3;
+
+ // Fill in the length in the space that we left earlier.
+ bytes[1] = (byte) (blockLength & 0xff);
+ bytes[2] = (byte) ((blockLength >> 8) & 0xff);
+ return bytes;
+ }
+ return body;
+ }
+
+ /**
+ * Get a stream for the body of this block.
+ *
+ * @return A structured stream that can be used to read the body of this
+ * block.
+ */
+ public StructuredInputStream getInputStream() {
+ arrayBody = null;
+ return this.istream;
+ }
+
+ public StructuredOutputStream getOutputStream() {
+ if (ostream == null) {
+ arrayBody = new ByteArrayOutputStream();
+ body = null;
+ ostream = new StructuredOutputStream(arrayBody);
+ try {
+ ostream.write(blockId);
+ ostream.write2(0); // This will be filled in later.
+ } catch (IOException e) {
+ log.warn("failed writing to array");
+ }
+ }
+
+ return ostream;
+ }
+
+ public void write(OutputStream stream) throws IOException {
+ byte[] b = getBody();
+ if (b != null)
+ stream.write(b);
+ }
+}
diff --git a/src/uk/me/parabola/tdbfmt/CopyrightBlock.java b/src/uk/me/parabola/tdbfmt/CopyrightBlock.java
new file mode 100644
index 0000000..3b03dd3
--- /dev/null
+++ b/src/uk/me/parabola/tdbfmt/CopyrightBlock.java
@@ -0,0 +1,67 @@
+/*
+ * 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: 23-Sep-2007
+ */
+package uk.me.parabola.tdbfmt;
+
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.io.StructuredInputStream;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * A copyright block consists of a number of copyright segments.
+ *
+ * @author Steve Ratcliffe
+ */
+class CopyrightBlock {
+ private static final Logger log = Logger.getLogger(CopyrightBlock.class);
+
+ private final List<CopyrightSegment> segments = new ArrayList<CopyrightSegment>();
+ private final Set<CopyrightSegment> copySet = new HashSet<CopyrightSegment>();
+
+ CopyrightBlock() {
+ }
+
+ CopyrightBlock(Block block) throws IOException {
+ StructuredInputStream ds = block.getInputStream();
+
+ while (!ds.testEof()) {
+ CopyrightSegment segment = new CopyrightSegment(ds);
+
+ log.info("segment: " + segment);
+ segments.add(segment);
+ }
+ }
+
+ public void write(Block block) throws IOException {
+ for (CopyrightSegment seg : segments) {
+ seg.write(block);
+ }
+ }
+
+ /**
+ * Add a copyright segment. We only add unique ones.
+ * @param seg The copyright segment to add.
+ */
+ public void addSegment(CopyrightSegment seg) {
+ if (copySet.add(seg))
+ segments.add(seg);
+ }
+}
diff --git a/src/uk/me/parabola/tdbfmt/CopyrightSegment.java b/src/uk/me/parabola/tdbfmt/CopyrightSegment.java
new file mode 100644
index 0000000..5c5d3f8
--- /dev/null
+++ b/src/uk/me/parabola/tdbfmt/CopyrightSegment.java
@@ -0,0 +1,111 @@
+/*
+ * 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: 23-Sep-2007
+ */
+package uk.me.parabola.tdbfmt;
+
+import uk.me.parabola.io.StructuredInputStream;
+import uk.me.parabola.io.StructuredOutputStream;
+
+import java.io.IOException;
+
+/**
+ * One copyright that is within the copyright block.
+ *
+ * @author Steve Ratcliffe
+ */
+class CopyrightSegment {
+
+ /**
+ * Source information text string. Describes what data sources were used
+ * in generating the map.
+ */
+ public static final int CODE_SOURCE_INFORMATION = 0x00;
+
+ /** Copyright information from the map manufacturer. */
+ public static final int CODE_COPYRIGHT_TEXT_STRING = 0x06;
+
+ /**
+ * A filename that contains a BMP image to be printed along with
+ * the map.
+ */
+ public static final int CODE_COPYRIGHT_BITMAP_REFERENCE = 0x07;
+
+ /**
+ * A code that shows what kind of copyright information is
+ * contained in this segment.
+ * The field {@link #extraProperties} can be used too as extra information.
+ */
+ private final byte copyrightCode;
+ private final byte whereCode;
+ private final short extraProperties;
+ private final String copyright;
+
+ CopyrightSegment(StructuredInputStream ds) throws IOException {
+ copyrightCode = (byte) ds.read();
+ whereCode = (byte) ds.read();
+ extraProperties = (short) ds.read2();
+ copyright = ds.readString();
+ }
+
+ CopyrightSegment(int code, int where, String msg) {
+ this.copyrightCode = (byte) code;
+ this.whereCode = (byte) where;
+ this.copyright = msg;
+ this.extraProperties = 0;
+ }
+
+ public void write(Block block) throws IOException {
+ StructuredOutputStream os = block.getOutputStream();
+ os.write(copyrightCode);
+ os.write(whereCode);
+ os.write2(extraProperties);
+ os.writeString(copyright);
+ }
+
+ public String toString() {
+ return "Copyright: "
+ + copyrightCode
+ + ", where="
+ + whereCode
+ + ", extra="
+ + extraProperties
+ + ": "
+ + copyright
+ ;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || !(o instanceof CopyrightSegment)) return false;
+
+ CopyrightSegment that = (CopyrightSegment) o;
+
+ if (copyrightCode != that.copyrightCode) return false;
+ if (extraProperties != that.extraProperties) return false;
+ if (whereCode != that.whereCode) return false;
+ if (!copyright.equals(that.copyright)) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result = (int) copyrightCode;
+ result = 31 * result + (int) whereCode;
+ result = 31 * result + (int) extraProperties;
+ result = 31 * result + copyright.hashCode();
+ return result;
+ }
+}
diff --git a/src/uk/me/parabola/tdbfmt/DetailMapBlock.java b/src/uk/me/parabola/tdbfmt/DetailMapBlock.java
new file mode 100644
index 0000000..8a78222
--- /dev/null
+++ b/src/uk/me/parabola/tdbfmt/DetailMapBlock.java
@@ -0,0 +1,161 @@
+/*
+ * 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: 23-Sep-2007
+ */
+package uk.me.parabola.tdbfmt;
+
+import java.io.IOException;
+
+import uk.me.parabola.io.StructuredInputStream;
+import uk.me.parabola.io.StructuredOutputStream;
+
+/**
+ * Details of a single .img file that is part of the map set. There will be
+ * one of these for each .img file.
+ *
+ * @author Steve Ratcliffe
+ */
+public class DetailMapBlock extends OverviewMapBlock {
+
+ private int tdbVersion;
+
+ private String innername;
+
+ // Sizes of the regions. It is possible that rgn and tre are reversed?
+ private int rgnDataSize;
+ private int treDataSize;
+ private int lblDataSize;
+ private int netDataSize;
+ private int nodDataSize;
+
+ public DetailMapBlock(int tdbVersion) {
+ assert tdbVersion > 0;
+ this.tdbVersion = tdbVersion;
+ }
+
+ /**
+ * Initialise this block from the raw block given.
+ * @param block The raw block read from the file.
+ * @throws IOException For io problems.
+ */
+ public DetailMapBlock(Block block) throws IOException {
+ super(block);
+
+ StructuredInputStream ds = block.getInputStream();
+
+ // First there are a couple of fields that we ignore.
+ int junk = ds.read2();
+ assert junk == 4;
+
+ junk = ds.read2();
+ assert junk == 3;
+
+ // Sizes of the data
+ rgnDataSize = ds.read4();
+ treDataSize = ds.read4();
+ lblDataSize = ds.read4();
+
+ // Another ignored field
+ junk = ds.read();
+ assert junk == 1;
+ }
+
+ /**
+ * Write into the given block.
+ *
+ * @param block The block that will have been initialised to be a detail
+ * block.
+ * @throws IOException Problems writing, probably can't really happen as
+ * we use an array backed stream.
+ */
+ public void write(Block block) throws IOException {
+ super.write(block);
+
+ StructuredOutputStream os = block.getOutputStream();
+
+ int n = 3;
+ if (tdbVersion >= TdbFile.TDB_V407) {
+ if (netDataSize > 0)
+ n++;
+ if (nodDataSize > 0)
+ n++;
+ }
+
+ os.write2(n+1);
+ os.write2(n);
+
+ os.write4(treDataSize);
+ os.write4(rgnDataSize);
+ os.write4(lblDataSize);
+
+ if (tdbVersion >= TdbFile.TDB_V407) {
+ if (n > 3) os.write4(netDataSize);
+ if (n > 4) os.write4(nodDataSize);
+//01 c3 00 ff
+ os.write4(0xff00c301);
+ os.write(0);
+ os.write(0);
+ os.write(0);
+
+ String mn = getInnername();
+ os.writeString(mn + ".TRE");
+ os.writeString(mn + ".RGN");
+ os.writeString(mn + ".LBL");
+ if (n > 3) os.writeString(mn + ".NET");
+ if (n > 4) os.writeString(mn + ".NOD");
+ } else {
+ os.write(1);
+ }
+ }
+
+ public String getInnername() {
+ return innername;
+ }
+
+ public void setInnername(String innername) {
+ this.innername = innername;
+ }
+
+ public void setRgnDataSize(int rgnDataSize) {
+ this.rgnDataSize = rgnDataSize;
+ }
+
+ public void setTreDataSize(int treDataSize) {
+ this.treDataSize = treDataSize;
+ }
+
+ public void setLblDataSize(int lblDataSize) {
+ this.lblDataSize = lblDataSize;
+ }
+
+ public void setNetDataSize(int netDataSize) {
+ this.netDataSize = netDataSize;
+ }
+
+ public void setNodDataSize(int nodDataSize) {
+ this.nodDataSize = nodDataSize;
+ }
+
+ public String toString() {
+ return super.toString()
+ + ", rgn size="
+ + rgnDataSize
+ + ", tre size="
+ + treDataSize
+ + ", lbl size"
+ + lblDataSize
+ ;
+ }
+}
diff --git a/src/uk/me/parabola/tdbfmt/HeaderBlock.java b/src/uk/me/parabola/tdbfmt/HeaderBlock.java
new file mode 100644
index 0000000..ebdb91c
--- /dev/null
+++ b/src/uk/me/parabola/tdbfmt/HeaderBlock.java
@@ -0,0 +1,172 @@
+/*
+ * 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: 23-Sep-2007
+ */
+package uk.me.parabola.tdbfmt;
+
+import java.io.IOException;
+
+import uk.me.parabola.io.StructuredInputStream;
+import uk.me.parabola.io.StructuredOutputStream;
+
+/**
+ * The header block. Identifies the particular map set.
+ *
+ * @author Steve Ratcliffe
+ */
+class HeaderBlock {
+
+ /** The map family. */
+ private short familyId;
+
+ /** A unique number associated with the map product */
+ private short productId;
+
+ /** The version of TDB */
+ private final int tdbVersion;
+
+ /** The series name is an overall name eg 'US Topo' */
+ private String seriesName;
+
+ /** The version number of the map product */
+ private short productVersion;
+
+ /**
+ * Identifies a map within the series
+ * @see #seriesName
+ */
+ private String familyName;
+
+ private byte enableProfile;
+
+ private int codePage;
+
+ HeaderBlock(int tdbVersion) {
+ this.tdbVersion = tdbVersion;
+ }
+
+ HeaderBlock(Block block) throws IOException {
+ StructuredInputStream ds = block.getInputStream();
+
+ productId = (short) ds.read2();
+ familyId = (short) ds.read2();
+
+ tdbVersion = ds.read2();
+ seriesName = ds.readString();
+ productVersion = (short) ds.read2();
+ familyName = ds.readString();
+ }
+
+ public void write(Block block) throws IOException {
+ StructuredOutputStream os = block.getOutputStream();
+ os.write2(productId);
+ os.write2(familyId);
+ os.write2(tdbVersion);
+ os.writeString(seriesName);
+ os.write2(productVersion);
+ os.writeString(familyName);
+
+ if (tdbVersion >= TdbFile.TDB_V407) {
+ // Unknown purpose
+
+ os.write(0);
+ os.write(0x12); // lowest map level
+ os.write(1);
+ os.write(1);
+ os.write(1);
+ os.write4(0);
+ os.write(0);
+ os.write(0x18); // highest routable? 19 no, 21 ok
+ os.write4(0);
+ os.write4(0);
+ os.write4(0);
+ os.write4(0);
+ os.write3(0);
+ os.write4(codePage);
+ os.write4(10000);
+ os.write(1); // map is routable
+ if (enableProfile == 1)
+ os.write(1); // map has profile information
+ else
+ os.write(0);
+ os.write(0); // map has DEM sub files
+ }
+ }
+
+ // good
+ //os.write(0);
+ //os.write(0x12);
+ //os.write(1);
+ //os.write(1);
+ //os.write(1);
+ //os.write4(0);
+ //os.write(0);
+ //os.write(0x15);
+ //os.write4(0);
+ //os.write4(0);
+ //os.write4(0);
+ //os.write4(0);
+ //os.write3(0);
+ //os.write4(1252);
+ //os.write4(10000);
+ //os.write(1);
+ //os.write(0);
+ //os.write(0);
+ public String toString() {
+ return "TDB header: "
+ + productId
+ + " version="
+ + tdbVersion
+ + ", series:"
+ + seriesName
+ + ", family:"
+ + familyName
+ + ", ver="
+ + productVersion
+ ;
+ }
+
+ public void setProductId(short productId) {
+ this.productId = productId;
+ }
+
+ public void setSeriesName(String seriesName) {
+ this.seriesName = seriesName;
+ }
+
+ public void setFamilyName(String familyName) {
+ this.familyName = familyName;
+ }
+
+ public void setProductVersion(short productVersion) {
+ this.productVersion = productVersion;
+ }
+
+ public void setFamilyId(short familyId) {
+ this.familyId = familyId;
+ }
+
+ void setCodePage(int codePage) {
+ this.codePage = codePage;
+ }
+
+ public int getTdbVersion() {
+ return tdbVersion;
+ }
+
+ public void setEnableProfile(byte enableProfile) {
+ this.enableProfile = enableProfile;
+ }
+}
diff --git a/src/uk/me/parabola/tdbfmt/OverviewMapBlock.java b/src/uk/me/parabola/tdbfmt/OverviewMapBlock.java
new file mode 100644
index 0000000..a8bc223
--- /dev/null
+++ b/src/uk/me/parabola/tdbfmt/OverviewMapBlock.java
@@ -0,0 +1,126 @@
+/*
+ * 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: 23-Sep-2007
+ */
+package uk.me.parabola.tdbfmt;
+
+import java.io.IOException;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.io.StructuredInputStream;
+import uk.me.parabola.io.StructuredOutputStream;
+
+/**
+ * The overview map provides a low-detail image for the detailed maps. It
+ * allows you to see what areas the detail maps cover so they can be selected
+ * in programs such as QLandkarte and Garmin's MapSource.
+ *
+ * In addition to a low detail map, the overview map contains a number of type
+ * 0x4a polygons. These definition areas a labeled after and correspond to
+ * the detail map img files.
+ *
+ * The detail maps contain a background polygon (type 0x4b) that matches the
+ * definition area in the overview map.
+ *
+ * @author Steve Ratcliffe
+ */
+public class OverviewMapBlock {
+
+ private int mapNumber;
+ private String mapName;
+ private int parentMapNumber;
+
+ private String description;
+
+ private int maxLat;
+ private int maxLong;
+ private int minLat;
+ private int minLong;
+
+ public OverviewMapBlock() {
+ description = "overview map";
+ }
+
+ public OverviewMapBlock(Block block) throws IOException {
+ StructuredInputStream ds = block.getInputStream();
+
+ mapNumber = ds.read4();
+ parentMapNumber = ds.read4();
+
+ maxLat = ds.read4();
+ maxLong = ds.read4();
+ minLat = ds.read4();
+ minLong = ds.read4();
+
+ description = ds.readString();
+ }
+
+ public void write(Block block) throws IOException {
+ StructuredOutputStream os = block.getOutputStream();
+
+ os.write4(mapNumber);
+ os.write4(parentMapNumber);
+ os.write4(maxLat);
+ os.write4(maxLong);
+ os.write4(minLat);
+ os.write4(minLong);
+ os.writeString(description);
+ }
+
+ public String toString() {
+ return "Overview: "
+ + mapNumber
+ + ", parent="
+ + parentMapNumber
+ + " covers "
+ + '(' + toDegrees(minLat) + ',' + toDegrees(minLong) + ')'
+ + '(' + toDegrees(maxLat) + ',' + toDegrees(maxLong) + ')'
+ + " : "
+ + description
+ ;
+ }
+
+ private double toDegrees(int tdbunits) {
+ return (double) tdbunits * 360 / Math.pow(2, 32);
+ }
+
+ public void setArea(Area bounds) {
+ minLat = bounds.getMinLat() << 8;
+ minLong = bounds.getMinLong() << 8;
+ maxLat = bounds.getMaxLat() << 8;
+ maxLong = bounds.getMaxLong() << 8;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public void setMapName(String mapName) {
+ this.mapName = mapName;
+ try {
+ this.mapNumber = Integer.parseInt(mapName);
+ } catch (NumberFormatException e) {
+ this.mapNumber = 0;
+ }
+ }
+
+ protected String getMapName() {
+ return mapName;
+ }
+
+ public void setParentMapNumber(int parentMapNumber) {
+ this.parentMapNumber = parentMapNumber;
+ }
+}
diff --git a/src/uk/me/parabola/tdbfmt/RBlock.java b/src/uk/me/parabola/tdbfmt/RBlock.java
new file mode 100644
index 0000000..179c1c8
--- /dev/null
+++ b/src/uk/me/parabola/tdbfmt/RBlock.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 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: 23-Jun-2008
+ */
+package uk.me.parabola.tdbfmt;
+
+import java.io.IOException;
+
+import uk.me.parabola.io.StructuredOutputStream;
+
+/**
+ * @author Steve Ratcliffe
+ */
+public class RBlock {
+ private final String previewDescription = "Test preview map";
+
+ public void write(Block block) throws IOException {
+ StructuredOutputStream os = block.getOutputStream();
+
+ os.write(0xc3);
+ os.writeString(previewDescription);
+ }
+}
diff --git a/src/uk/me/parabola/tdbfmt/TBlock.java b/src/uk/me/parabola/tdbfmt/TBlock.java
new file mode 100644
index 0000000..6335514
--- /dev/null
+++ b/src/uk/me/parabola/tdbfmt/TBlock.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008 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: 23-Jun-2008
+ */
+package uk.me.parabola.tdbfmt;
+
+import java.io.IOException;
+
+import uk.me.parabola.io.StructuredOutputStream;
+
+/**
+ * @author Steve Ratcliffe
+ */
+public class TBlock {
+ private long sum;
+
+ public void write(Block block) throws IOException {
+ StructuredOutputStream os = block.getOutputStream();
+ // If you change A,B,C or D the maps
+ // will not load, you can change the rest without easily visible
+ // problems although I suppose they must do something.
+ //
+ // A,B,C,D is a standard crc32 sum of the rest of the file.
+ // (Andrzej Popowsk)
+ os.write2(0);
+ os.write((int) (sum >> 24)); // A
+ os.write3(0);
+ os.write3(0);
+ os.write((int) (sum >> 16)); // B
+ os.write2(0);
+ os.write((int) (sum >> 8)); // C
+ os.write4(0);
+ os.write((int) sum); // D
+ os.write2(0);
+ }
+
+ public void setSum(long sum) {
+ this.sum = sum;
+ }
+}
diff --git a/src/uk/me/parabola/tdbfmt/TdbFile.java b/src/uk/me/parabola/tdbfmt/TdbFile.java
new file mode 100644
index 0000000..0b9e33d
--- /dev/null
+++ b/src/uk/me/parabola/tdbfmt/TdbFile.java
@@ -0,0 +1,247 @@
+/*
+ * 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: 23-Sep-2007
+ */
+package uk.me.parabola.tdbfmt;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.CRC32;
+import java.util.zip.CheckedOutputStream;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.io.EndOfFileException;
+import uk.me.parabola.io.StructuredInputStream;
+import uk.me.parabola.log.Logger;
+
+/**
+ * The TDB file. See the package documentation for more details.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TdbFile {
+ private static final Logger log = Logger.getLogger(TdbFile.class);
+
+ public static final int TDB_V407 = 407;
+
+ private static final int BLOCK_OVERVIEW = 0x42;
+ private static final int BLOCK_HEADER = 0x50;
+ private static final int BLOCK_COPYRIGHT = 0x44;
+ private static final int BLOCK_DETAIL = 0x4c;
+ private static final int BLOCK_R = 0x52;
+ private static final int BLOCK_T = 0x54;
+
+ // The version number of the TDB format
+ private int tdbVersion;
+
+ // The blocks that go to make up the file.
+ private HeaderBlock headerBlock;
+ private CopyrightBlock copyrightBlock = new CopyrightBlock();
+ private OverviewMapBlock overviewMapBlock;
+ private final List<DetailMapBlock> detailBlocks = new ArrayList<DetailMapBlock>();
+ private final RBlock rblock = new RBlock();
+ private final TBlock tblock = new TBlock();
+ private String overviewDescription;
+
+ public TdbFile() {
+ }
+
+ public TdbFile(int tdbVersion) {
+ this.tdbVersion = tdbVersion;
+ }
+
+ /**
+ * Read in a TDB file from the disk.
+ *
+ * @param name The file name to load.
+ * @return A TdbFile instance.
+ * @throws IOException For problems reading the file.
+ */
+ public static TdbFile read(String name) throws IOException {
+ TdbFile tdb = new TdbFile();
+
+ InputStream is = new BufferedInputStream(new FileInputStream(name));
+
+ try {
+ StructuredInputStream ds = new StructuredInputStream(is);
+ tdb.load(ds);
+ } finally {
+ is.close();
+ }
+
+ return tdb;
+ }
+
+ public void setProductInfo(int familyId, int productId,
+ short productVersion, String seriesName, String familyName, String overviewDescription,
+ byte enableProfile)
+ {
+ headerBlock = new HeaderBlock(tdbVersion);
+ headerBlock.setFamilyId((short) familyId);
+ headerBlock.setProductId((short) productId);
+ headerBlock.setProductVersion(productVersion);
+ headerBlock.setSeriesName(seriesName);
+ headerBlock.setFamilyName(familyName);
+ headerBlock.setEnableProfile(enableProfile);
+ this.overviewDescription = overviewDescription;
+ }
+
+ public void setCodePage(int codePage) {
+ headerBlock.setCodePage(codePage);
+ }
+
+ /**
+ * Add a copyright segment to the file.
+ * @param msg The message to add.
+ */
+ public void addCopyright(String msg) {
+ CopyrightSegment seg = new CopyrightSegment(CopyrightSegment.CODE_COPYRIGHT_TEXT_STRING, 3, msg);
+ copyrightBlock.addSegment(seg);
+ }
+
+ /**
+ * Set the overview information. Basically the overall size of the map
+ * set.
+ * @param bounds The bounds for the map.
+ */
+ public void setOverview(Area bounds, String number) {
+ overviewMapBlock = new OverviewMapBlock();
+ overviewMapBlock.setArea(bounds);
+ overviewMapBlock.setMapName(number);
+ overviewMapBlock.setDescription(overviewDescription);
+ }
+
+ /**
+ * Add a detail block. This describes and names one of the maps in the
+ * map set.
+ * @param detail The detail to add.
+ */
+ public void addDetail(DetailMapBlock detail) {
+ detailBlocks.add(detail);
+ }
+
+ public void write(String name) throws IOException {
+ CheckedOutputStream stream = new CheckedOutputStream(
+ new BufferedOutputStream(new FileOutputStream(name)),
+ new CRC32());
+
+ if (headerBlock == null || overviewMapBlock == null)
+ throw new IOException("Attempting to write file without being fully set up");
+
+ try {
+ Block block = new Block(BLOCK_HEADER);
+ headerBlock.write(block);
+ block.write(stream);
+
+ block = new Block(BLOCK_COPYRIGHT);
+ copyrightBlock.write(block);
+ block.write(stream);
+
+ if (tdbVersion >= TDB_V407) {
+ block = new Block(BLOCK_R);
+ rblock.write(block);
+ block.write(stream);
+ }
+
+ block = new Block(BLOCK_OVERVIEW);
+ overviewMapBlock.write(block);
+ block.write(stream);
+
+ for (DetailMapBlock detail : detailBlocks) {
+ block = new Block(BLOCK_DETAIL);
+ detail.write(block);
+ block.write(stream);
+ }
+
+ if (tdbVersion >= TDB_V407) {
+ tblock.setSum(stream.getChecksum().getValue());
+
+ block = new Block(BLOCK_T);
+ tblock.write(block);
+ block.write(stream);
+ }
+ } finally {
+ stream.close();
+ }
+ }
+
+ /**
+ * Load from the given file name.
+ *
+ * @param ds The stream to read from.
+ * @throws IOException For problems reading the file.
+ */
+ private void load(StructuredInputStream ds) throws IOException {
+
+ while (!ds.testEof()) {
+ Block block = readBlock(ds);
+
+ switch (block.getBlockId()) {
+ case BLOCK_HEADER:
+ headerBlock = new HeaderBlock(block);
+ log.info("header block seen", headerBlock);
+ break;
+ case BLOCK_COPYRIGHT:
+ log.info("copyright block");
+ copyrightBlock = new CopyrightBlock(block);
+ break;
+ case BLOCK_OVERVIEW:
+ overviewMapBlock = new OverviewMapBlock(block);
+ log.info("overview block", overviewMapBlock);
+ break;
+ case BLOCK_DETAIL:
+ DetailMapBlock db = new DetailMapBlock(block);
+ log.info("detail block", db);
+ detailBlocks.add(db);
+ break;
+ default:
+ log.warn("Unknown block in tdb file");
+ break;
+ }
+ }
+
+ }
+
+ /**
+ * The file is divided into blocks. This reads a single block.
+ *
+ * @param is The input stream.
+ * @return A block from the file.
+ * @throws IOException For problems reading the file.
+ */
+ private Block readBlock(StructuredInputStream is) throws IOException {
+ int blockType = is.read();
+ if (blockType == -1)
+ throw new EndOfFileException();
+ int blockLength = is.read2();
+
+ byte[] body = new byte[blockLength];
+ int n = is.read(body);
+ if (n < 0)
+ throw new IOException("failed to read block");
+
+ return new Block(blockType, body);
+ }
+
+ public int getTdbVersion() {
+ return headerBlock.getTdbVersion();
+ }
+}
diff --git a/src/uk/me/parabola/tdbfmt/package.html b/src/uk/me/parabola/tdbfmt/package.html
new file mode 100644
index 0000000..9f93773
--- /dev/null
+++ b/src/uk/me/parabola/tdbfmt/package.html
@@ -0,0 +1,12 @@
+<body>
+
+<h3>The TDB file format</h3>
+
+The TDB file contains summary information about individual IMG files that make
+up a map set. It is usual for a map to be broken down into a set of tiles and
+the TDB file gives an overview of how they all fit together.
+
+<h3>Acknowledgments</h3>
+<p>Based on the document <em>Garmin TDB File Format</em> by John Mechalas</p>
+
+</body>
diff --git a/src/uk/me/parabola/util/Configurable.java b/src/uk/me/parabola/util/Configurable.java
new file mode 100644
index 0000000..ffff676
--- /dev/null
+++ b/src/uk/me/parabola/util/Configurable.java
@@ -0,0 +1,37 @@
+/*
+ * 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: 03-Sep-2007
+ */
+package uk.me.parabola.util;
+
+/**
+ * A map reader that wants to inspect command line arguments. A separate
+ * interface as its only being used for the test maps at present. Want
+ * to leave open the possibility of a more self describing interface that
+ * might extend this one that would allow for a GUI interface.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface Configurable {
+
+ /**
+ * Used to mark that a reader needs to be configured by command line
+ * properties. The MapReader will be given the command line properties
+ * that were set before it is asked to load the map.
+ *
+ * @param props The input properties.
+ */
+ public void config(EnhancedProperties props);
+}
diff --git a/src/uk/me/parabola/util/ElementQuadTree.java b/src/uk/me/parabola/util/ElementQuadTree.java
new file mode 100644
index 0000000..2579498
--- /dev/null
+++ b/src/uk/me/parabola/util/ElementQuadTree.java
@@ -0,0 +1,65 @@
+package uk.me.parabola.util;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.util.ElementQuadTreeNode.ElementQuadTreePolygon;
+
+public class ElementQuadTree {
+
+ private final ElementQuadTreeNode root;
+
+ public ElementQuadTree(Area bbox, Collection<Element> elements) {
+ this.root = new ElementQuadTreeNode(bbox, elements);
+ }
+
+ public void remove(Element element) {
+ root.remove(element);
+ }
+
+ public Set<Element> get(Area bbox) {
+ return root.get(bbox, new HashSet<Element>());
+ }
+
+ public Set<Element> get(java.awt.geom.Area polygon) {
+ return root.get(new ElementQuadTreePolygon(polygon), new HashSet<Element>());
+ }
+
+ public Set<Element> get(Collection<List<Coord>> polygons) {
+ return root.get(new ElementQuadTreePolygon(polygons),
+ new HashSet<Element>());
+ }
+
+ public int getDepth() {
+ return root.getDepth();
+ }
+
+ public Set<Element> get(List<Coord> polygon) {
+ if (polygon.size() < 3) {
+ return new HashSet<Element>();
+ }
+ if (polygon.get(0).equals(polygon.get(polygon.size() - 1)) == false) {
+ return new HashSet<Element>();
+ }
+ return root.get(new ElementQuadTreePolygon(polygon),
+ new HashSet<Element>());
+ }
+
+ public long getCoordSize() {
+ return root.getSize();
+ }
+
+ public boolean isEmpty() {
+ return root.isEmpty();
+ }
+
+
+ public void clear() {
+ root.clear();
+ }
+}
diff --git a/src/uk/me/parabola/util/ElementQuadTreeNode.java b/src/uk/me/parabola/util/ElementQuadTreeNode.java
new file mode 100644
index 0000000..a379e67
--- /dev/null
+++ b/src/uk/me/parabola/util/ElementQuadTreeNode.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2006, 2012.
+ *
+ * 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.util;
+
+import java.awt.Rectangle;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.Node;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+
+public final class ElementQuadTreeNode {
+
+ private static final Logger log = Logger.getLogger(ElementQuadTreeNode.class);
+
+ /**
+ * A static empty list used for node objects. They have one coord only and
+ * it is too costly to create a list for each node
+ */
+ private static final List<Coord> EMPTY_LIST = Collections.emptyList();
+
+ /** The maximum number of coords in the quadtree node. */
+ private static final int MAX_POINTS = 1000;
+
+ /** Maps elements to its coords located in this quadtree node. */
+ private Map<Element, List<Coord>> elementMap;
+
+ /** The bounds of this quadtree node */
+ private final Area bounds;
+ private final Rectangle boundsRect;
+
+ /** Flag if this node and all subnodes are empty */
+ private Boolean empty;
+
+ /** The subnodes in case this node is not a leaf */
+ private ElementQuadTreeNode[] children;
+
+ public static final class ElementQuadTreePolygon {
+ private final java.awt.geom.Area javaArea;
+ private final Area bbox;
+
+ public ElementQuadTreePolygon(java.awt.geom.Area javaArea) {
+ this.javaArea = javaArea;
+ Rectangle bboxRect = javaArea.getBounds();
+ bbox = new Area(bboxRect.y, bboxRect.x, bboxRect.y
+ + bboxRect.height, bboxRect.x + bboxRect.width);
+ }
+
+ public ElementQuadTreePolygon(List<Coord> points) {
+ this(new java.awt.geom.Area(Java2DConverter.createPolygon(points)));
+ }
+
+ public ElementQuadTreePolygon(Collection<List<Coord>> polygonList) {
+ this.javaArea = new java.awt.geom.Area();
+ for (List<Coord> polygon : polygonList) {
+ javaArea.add(new java.awt.geom.Area(Java2DConverter
+ .createPolygon(polygon)));
+ }
+ Rectangle bboxRect = javaArea.getBounds();
+ bbox = new Area(bboxRect.y, bboxRect.x, bboxRect.y
+ + bboxRect.height, bboxRect.x + bboxRect.width);
+ }
+
+ public Area getBbox() {
+ return bbox;
+ }
+
+ public java.awt.geom.Area getArea() {
+ return javaArea;
+ }
+ }
+
+ /**
+ * Retrieves if this quadtree node (and all subnodes) contains any elements.
+ * @return <code>true</code> this quadtree node does not contain any elements; <code>false</code> else
+ */
+ public boolean isEmpty() {
+ if (empty == null) {
+ if (isLeaf()) {
+ empty = elementMap.isEmpty();
+ } else {
+ empty = true;
+ for (ElementQuadTreeNode child : children) {
+ if (child.isEmpty()==false) {
+ empty = false;
+ break;
+ }
+ }
+ }
+ }
+ return empty;
+ }
+
+
+ /**
+ * Retrieves the number of coords hold by this quadtree node and all subnodes.
+ * @return the number of coords
+ */
+ public long getSize() {
+ if (isLeaf()) {
+ int items = 0;
+ for (List<Coord> points : elementMap.values()) {
+ if (points == EMPTY_LIST) {
+ items++;
+ } else {
+ items += points.size();
+ }
+ }
+ return items;
+ } else {
+ int items = 0;
+ for (ElementQuadTreeNode child : children) {
+ items += child.getSize();
+ }
+ return items;
+ }
+ }
+
+ /**
+ * Retrieves the depth of this quadtree node. Leaves have depth 1.
+ * @return the depth of this quadtree node
+ */
+ public int getDepth() {
+ if (isLeaf()) {
+ return 1;
+ } else {
+ int maxDepth = 0;
+ for (ElementQuadTreeNode node : children) {
+ maxDepth = Math.max(node.getDepth(), maxDepth);
+ }
+ return maxDepth + 1;
+ }
+ }
+
+ private ElementQuadTreeNode(Area bounds, Map<Element, List<Coord>> elements) {
+ this.bounds = bounds;
+ boundsRect = new Rectangle(bounds.getMinLong(), bounds.getMinLat(),
+ bounds.getWidth(), bounds.getHeight());
+ this.children = null;
+ elementMap =elements;
+ empty = elementMap.isEmpty();
+
+ checkSplit();
+ }
+
+
+ public ElementQuadTreeNode(Area bounds, Collection<Element> elements) {
+ this.bounds = bounds;
+ boundsRect = new Rectangle(bounds.getMinLong(), bounds.getMinLat(),
+ bounds.getWidth(), bounds.getHeight());
+ this.children = null;
+
+ this.elementMap = new HashMap<Element, List<Coord>>(elements.size()*4/3+10);
+
+ for (Element el : elements) {
+ if (el instanceof Way) {
+ List<Coord> points = ((Way) el).getPoints();
+ // no need to create a copy of the points because the list is never changed
+ elementMap.put(el, points);
+ } else if (el instanceof Node) {
+ elementMap.put(el, EMPTY_LIST);
+ }
+ }
+ empty = elementMap.isEmpty();
+ checkSplit();
+ }
+
+ public Area getBounds() {
+ return this.bounds;
+ }
+
+ public Rectangle getBoundsAsRectangle() {
+ return boundsRect;
+ }
+
+ /**
+ * Checks if this quadtree node exceeds the maximum size and splits it in such a case.
+ */
+ private void checkSplit() {
+ if (getSize() > MAX_POINTS) {
+ split();
+ }
+ }
+
+ /**
+ * Removes the element with the given bounding box from this quadtree node and all subnodes.
+ * @param elem the element to be removed
+ * @param bbox the bounding box of the element
+ */
+ private void remove(Element elem, Area bbox) {
+ if (bbox == null || isEmpty()) {
+ return;
+ }
+ if (isLeaf()) {
+ elementMap.remove(elem);
+ empty = elementMap.isEmpty();
+ } else {
+ for (ElementQuadTreeNode child : children) {
+ if (child.getBounds().intersects(bbox)) {
+ child.remove(elem, bbox);
+ if (child.isEmpty()) {
+ // update the empty flag
+ empty = null;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Calculates the bounding box of the given element.
+ * @param elem an element
+ * @return the bounding box of the element
+ */
+ private Area getBbox(Element elem) {
+ if (elem instanceof Node) {
+ Coord c = ((Node) elem).getLocation();
+ return new Area(c.getLatitude(), c.getLongitude(), c.getLatitude(),c.getLongitude());
+ } else if (elem instanceof Way) {
+ List<Coord> points = ((Way) elem).getPoints();
+ if (points.isEmpty()) {
+ return null;
+ }
+ Coord c = points.get(0);
+ int minLat = c.getLatitude();
+ int maxLat = c.getLatitude();
+ int minLong = c.getLongitude();
+ int maxLong = c.getLongitude();
+ for (Coord co : points) {
+ if (co.getLatitude() < minLat) {
+ minLat = co.getLatitude();
+ } else if (co.getLatitude() > maxLat) {
+ maxLat = co.getLatitude();
+ }
+ if (co.getLongitude() < minLong) {
+ minLong = co.getLongitude();
+ } else if (co.getLongitude() > maxLong) {
+ maxLong = co.getLongitude();
+ }
+ }
+ return new Area(minLat,minLong, maxLat, maxLong);
+ }
+ return null;
+ }
+
+ /**
+ * Removes the element from this quadtree node and all subnodes.
+ * @param elem the element to be removed
+ */
+ public void remove(Element elem) {
+ remove(elem, getBbox(elem));
+ }
+
+ /**
+ * Retrieves all elements that intersects the given bounding box.
+ * @param bbox the bounding box
+ * @param resultList results are stored in this collection
+ * @return the resultList
+ */
+ public Set<Element> get(Area bbox, Set<Element> resultList) {
+ if (isEmpty()) {
+ return resultList;
+ }
+ if (isLeaf()) {
+ if (bbox.getMinLat() <= bounds.getMinLat()
+ && bbox.getMaxLat() >= bounds.getMaxLat()
+ && bbox.getMinLong() <= bounds.getMinLong()
+ && bbox.getMaxLong() >= bounds.getMaxLong()) {
+
+ // the bounding box is contained completely in the bbox
+ // => add all points without further check
+ resultList.addAll(elementMap.keySet());
+ } else {
+ // check each point
+ for (Entry<Element, List<Coord>> elem : elementMap.entrySet()) {
+ if (elem.getKey() instanceof Node) {
+ Node n = (Node) elem.getKey();
+ if (bbox.contains(n.getLocation())) {
+ resultList.add(n);
+ }
+ } else if (elem.getKey() instanceof Way) {
+ // no need to check - the element is already in the result list
+ if (resultList.contains(elem.getKey())) {
+ continue;
+ }
+ for (Coord c : elem.getValue()) {
+ if (bbox.contains(c)) {
+ resultList.add(elem.getKey());
+ break;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ for (ElementQuadTreeNode child : children) {
+ if (child.isEmpty() == false
+ && bbox.intersects(child.getBounds())) {
+ resultList = child.get(bbox, resultList);
+ }
+ }
+ }
+ return resultList;
+ }
+
+ /**
+ * Retrieves all elements that intersects the given polygon.
+ * @param polygon the polygon
+ * @param resultList results are stored in this collection
+ * @return the resultList
+ */
+ public Set<Element> get(ElementQuadTreePolygon polygon,
+ Set<Element> resultList) {
+ if (isEmpty()) {
+ return resultList;
+ }
+ if (polygon.getBbox().intersects(getBounds())) {
+ if (isLeaf()) {
+ for (Entry<Element, List<Coord>> elem : elementMap.entrySet()) {
+ if (resultList.contains(elem.getKey())) {
+ continue;
+ }
+ if (elem.getKey() instanceof Node) {
+ Node n = (Node)elem.getKey();
+ Coord c = n.getLocation();
+ if (polygon.getArea().contains(c.getLongitude(),
+ c.getLatitude())) {
+ resultList.add(n);
+ }
+ } else if (elem.getKey() instanceof Way) {
+ for (Coord c : elem.getValue()) {
+ if (polygon.getArea().contains(c.getLongitude(),
+ c.getLatitude())) {
+ resultList.add(elem.getKey());
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ for (ElementQuadTreeNode child : children) {
+ if (child.isEmpty()==false
+ && polygon.getArea().intersects(
+ child.getBoundsAsRectangle())) {
+ java.awt.geom.Area subArea = (java.awt.geom.Area) polygon
+ .getArea().clone();
+
+ subArea.intersect(Java2DConverter.createBoundsArea(new Area(child.getBounds()
+ .getMinLat() - 1, child.getBounds()
+ .getMinLong() - 1, child.getBounds()
+ .getMaxLat() + 1, child.getBounds()
+ .getMaxLong() + 1))
+ );
+ child.get(new ElementQuadTreePolygon(subArea),
+ resultList);
+ }
+ }
+ }
+ }
+ return resultList;
+
+ }
+
+ /**
+ * Retrieves if this quadtree node is a leaf.
+ * @return <code>true</code> this node is a leaf
+ */
+ public boolean isLeaf() {
+ return elementMap != null;
+ }
+
+ /**
+ * Splits this quadtree node into 4 subnodes.
+ */
+ private void split() {
+ if (bounds.getHeight() <= 5 || bounds.getWidth() <= 5) {
+ log.error("Do not split more due to too small bounds: " + bounds);
+ return;
+ }
+
+ int halfLat = (bounds.getMinLat() + bounds.getMaxLat()) / 2;
+ int halfLong = (bounds.getMinLong() + bounds.getMaxLong()) / 2;
+ children = new ElementQuadTreeNode[4];
+ Area[] childBounds = new Area[4];
+
+ childBounds[0] = new Area(bounds.getMinLat(), bounds.getMinLong(),
+ halfLat, halfLong);
+ childBounds[1] = new Area(halfLat, bounds.getMinLong(),
+ bounds.getMaxLat(), halfLong);
+ childBounds[2] = new Area(bounds.getMinLat(), halfLong, halfLat,
+ bounds.getMaxLong());
+ childBounds[3] = new Area(halfLat, halfLong, bounds.getMaxLat(),
+ bounds.getMaxLong());
+
+ List<Map<Element, List<Coord>>> childElems = new ArrayList<Map<Element, List<Coord>>>(4);
+ for (int i = 0; i < 4; i++) {
+ childElems.add(new HashMap<Element, List<Coord>>());
+ }
+ for (Entry<Element,List<Coord>> elem : elementMap.entrySet()) {
+ if (elem.getKey() instanceof Node) {
+ Node node = (Node) elem.getKey();
+ for (int i = 0; i < childBounds.length; i++) {
+ if (childBounds[i].contains(node.getLocation())) {
+ childElems.get(i).put(node, EMPTY_LIST);
+ break;
+ }
+ }
+ } else if (elem.getKey() instanceof Way) {
+ List<List<Coord>> points = new ArrayList<List<Coord>>(4);
+ for (int i = 0; i < 4; i++) {
+ // usually ways are quite local
+ // therefore there is a high probability that only one child is covered
+ // dim the new list as the old list
+ points.add(new ArrayList<Coord>(elem.getValue().size()));
+ }
+ for (Coord c : elem.getValue()) {
+ for (int i = 0; i < childBounds.length; i++) {
+ if (childBounds[i].contains(c)) {
+ points.get(i).add(c);
+ break;
+ }
+ }
+ }
+ for (int i = 0; i< 4; i++) {
+ if (points.get(i).isEmpty()==false) {
+ childElems.get(i).put(elem.getKey(), points.get(i));
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < 4; i++) {
+ children[i] = new ElementQuadTreeNode(childBounds[i], childElems.get(i));
+ }
+
+ elementMap = null;
+ }
+
+ public void clear() {
+ this.children = null;
+ elementMap = new HashMap<Element, List<Coord>>();
+ }
+}
diff --git a/src/uk/me/parabola/util/EnhancedProperties.java b/src/uk/me/parabola/util/EnhancedProperties.java
new file mode 100644
index 0000000..31609ac
--- /dev/null
+++ b/src/uk/me/parabola/util/EnhancedProperties.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2008 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: May 17, 2008
+ */
+package uk.me.parabola.util;
+
+import java.util.Enumeration;
+import java.util.Properties;
+
+/**
+ * Wrapper that behaves as an enhanced properties class that has getProperty
+ * calls for different data types.
+ *
+ * @author Steve Ratcliffe
+ */
+public class EnhancedProperties extends Properties {
+
+ public EnhancedProperties() {
+ }
+
+ public EnhancedProperties(Properties defaults) {
+ // We copy values, rather than making them default values so that
+ // we can enumerate all the options.
+ Enumeration<?> en = defaults.propertyNames();
+ while (en.hasMoreElements()) {
+ String key = (String) en.nextElement();
+ setProperty(key, defaults.getProperty(key));
+ }
+ }
+
+ /**
+ * Get a property as an integer value. If the property does not exist
+ * or the value is not a valid integer, then the default value is returned
+ * instead.
+ * @param key The property name to retrieve.
+ * @param def The Default value to use if the property does not exist or
+ * if the value is not a valid integer.
+ * @return The value of the property as an integer, or the default value.
+ */
+ public int getProperty(String key, int def) {
+ try {
+ String s = getProperty(key);
+ return s == null ? def : Integer.parseInt(s);
+ } catch (NumberFormatException e) {
+ return def;
+ }
+ }
+
+ /**
+ * Get a property as a boolean value. If the value of the property
+ * begins with a '1', a 'y' or a 't' (for 1, yes, true) then true is
+ * returned. If the property does not exist then the given default
+ * value is returned.
+ *
+ * @param key The property name to get.
+ * @param def The default value that is returned if property does not
+ * exist.
+ * @return The value of the property as a boolean. If the property does
+ * not exist then the value of 'def'.
+ */
+ public boolean getProperty(String key, boolean def) {
+ String s = getProperty(key);
+ if (s != null) {
+ if (s.length() == 0)
+ return true;
+ char c = s.toLowerCase().charAt(0);
+ if (c == '1' || c == 'y' || c == 't')
+ return true;
+ else
+ return false;
+ }
+ return def;
+ }
+
+ /**
+ * Return a property as a double value. If the property does not
+ * exist or is not a valid double, then the given default value
+ * is returned instead.
+ * @param key The property name.
+ * @param def The default value to return if no valid value.
+ * @return The value of the property as a double.
+ */
+ public double getProperty(String key, double def) {
+ try {
+ String s = getProperty(key);
+ return s == null ? def : Double.parseDouble(s);
+ } catch (NumberFormatException e) {
+ return def;
+ }
+ }
+}
diff --git a/src/uk/me/parabola/util/GpxCreator.java b/src/uk/me/parabola/util/GpxCreator.java
new file mode 100644
index 0000000..dbd7b0b
--- /dev/null
+++ b/src/uk/me/parabola/util/GpxCreator.java
@@ -0,0 +1,137 @@
+package uk.me.parabola.util;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+
+public class GpxCreator {
+ private static final Logger log = Logger.getLogger(GpxCreator.class);
+
+ public static String getGpxBaseName() {
+ String tilePath = (log.threadTag() == null ? "unknown" : log.threadTag());
+
+ int tilenameStart = tilePath.lastIndexOf("/");
+ // check the case if the tiles are defined without path
+ tilenameStart = (tilenameStart < 0 ? 0 : tilenameStart+1);
+
+ int tilenameEnd = tilePath.lastIndexOf(".osm");
+ if (tilenameEnd < tilenameStart) {
+ // the tiles do not end with .osm*
+ // do not cut the file ending
+ tilenameEnd = tilePath.length();
+ }
+
+ return tilePath.substring(tilenameStart,tilenameEnd) + "/";
+ }
+
+ private static void addTrkPoint(PrintWriter pw, int latitude, int longitude) {
+ addGpxPoint(pw, "trkpt", latitude, longitude);
+ }
+
+ private static void addWptPoint(PrintWriter pw, int latitude, int longitude) {
+ addGpxPoint(pw, "wpt", latitude, longitude);
+ }
+
+ private static void addGpxPoint(PrintWriter pw, String type, int latitude,
+ int longitude) {
+ pw.print("<");
+ pw.print(type);
+ pw.print(" lat=\"");
+ pw.print(Utils.toDegrees(latitude));
+ pw.print("\" lon=\"");
+ pw.print(Utils.toDegrees(longitude));
+ pw.print("\"/>");
+ }
+
+ public static void createAreaGpx(String name, Area bbox) {
+ List<Coord> points = new ArrayList<Coord>(5);
+ points.add(new Coord(bbox.getMinLat(), bbox.getMinLong()));
+ points.add(new Coord(bbox.getMaxLat(), bbox.getMinLong()));
+ points.add(new Coord(bbox.getMaxLat(), bbox.getMaxLong()));
+ points.add(new Coord(bbox.getMinLat(), bbox.getMaxLong()));
+ points.add(new Coord(bbox.getMinLat(), bbox.getMinLong()));
+
+ GpxCreator.createGpx(name, points);
+ }
+
+ /**
+ * Creates a gpx file for each way. The filename is the baseDir plus the id
+ * of the way.
+ * @param baseDir the base directory name
+ * @param ways list of ways
+ */
+ public static void createGpx(String baseDir, Collection<? extends Way> ways) {
+ for (Way w : ways) {
+ GpxCreator.createGpx(baseDir+w.getId(), w.getPoints());
+ }
+ }
+
+ public static void createGpx(String name, List<Coord> points) {
+ try {
+ File f = new File(name);
+ if (f.getParentFile() != null) {
+ f.getParentFile().mkdirs();
+ }
+ PrintWriter pw = new PrintWriter(new FileWriter(name + ".gpx"));
+ pw.print("<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:gpxx=\"http://www.garmin.com/xmlschemas/GpxExtensions/v3\" ");
+ pw.print("xmlns:gpxtpx=\"http://www.garmin.com/xmlschemas/TrackPointExtension/v1\" version=\"1.1\" ");
+ pw.print("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd\"> ");
+
+ pw.print("<trk><name>");
+ pw.print(name);
+ pw.print("</name><trkseg>");
+
+ for (Coord c : points) {
+ addTrkPoint(pw, c.getLatitude(), c.getLongitude());
+ }
+ pw.print("</trkseg></trk></gpx>");
+ pw.close();
+ } catch (Exception exp) {
+ // only for debugging so just log
+ log.warn("Could not create gpx file ", name);
+ }
+ }
+
+ public static void createGpx(String name, List<Coord> polygonpoints,
+ List<Coord> singlePoints) {
+ try {
+ File f = new File(name);
+ f.getParentFile().mkdirs();
+ PrintWriter pw = new PrintWriter(new FileWriter(name + ".gpx"));
+ pw.print("<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:gpxx=\"http://www.garmin.com/xmlschemas/GpxExtensions/v3\" ");
+ pw.print("xmlns:gpxtpx=\"http://www.garmin.com/xmlschemas/TrackPointExtension/v1\" version=\"1.1\" ");
+ pw.print("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd\"> ");
+
+ if (singlePoints != null) {
+ for (Coord c : singlePoints) {
+ addWptPoint(pw, c.getLatitude(), c.getLongitude());
+ }
+ }
+
+ if (polygonpoints != null && polygonpoints.isEmpty() == false) {
+ pw.print("<trk><name>");
+ pw.print(name);
+ pw.print("</name><trkseg>");
+
+ for (Coord c : polygonpoints) {
+ addTrkPoint(pw, c.getLatitude(), c.getLongitude());
+ }
+ pw.print("</trkseg></trk>");
+ }
+ pw.print("</gpx>");
+ pw.close();
+ } catch (Exception exp) {
+ // only for debugging so just log
+ log.warn("Could not create gpx file ", name);
+ }
+ }
+}
diff --git a/src/uk/me/parabola/util/Java2DConverter.java b/src/uk/me/parabola/util/Java2DConverter.java
new file mode 100644
index 0000000..b4113ea
--- /dev/null
+++ b/src/uk/me/parabola/util/Java2DConverter.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2006, 2012.
+ *
+ * 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.util;
+
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.geom.Area;
+import java.awt.geom.PathIterator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+
+/**
+ * This is a tool class that provides static methods to convert between mkgmap
+ * objects and Java2D objects. The Java2D objects provide some optimized polygon
+ * algorithms that are quite useful so that it makes sense to perform the
+ * conversion.
+ *
+ * @author WanMil
+ */
+public class Java2DConverter {
+ private static final Logger log = Logger.getLogger(Java2DConverter.class);
+
+ /**
+ * Creates a Java2D {@link Area} object from the given mkgmap rectangular
+ * {@link uk.me.parabola.imgfmt.app.Area} object.
+ *
+ * @param bbox a rectangular bounding box
+ * @return the converted Java2D area
+ */
+ public static Area createBoundsArea(uk.me.parabola.imgfmt.app.Area bbox) {
+ return new Area(new Rectangle(bbox.getMinLong(), bbox.getMinLat(),
+ bbox.getMaxLong() - bbox.getMinLong(), bbox.getMaxLat()
+ - bbox.getMinLat()));
+ }
+
+ /**
+ * Converts the bounding box of a Java2D {@link Area} object to an mkgmap
+ * {@link uk.me.parabola.imgfmt.app.Area} object.
+ *
+ * @param area a Java2D area
+ * @return the bounding box
+ */
+ public static uk.me.parabola.imgfmt.app.Area createBbox(Area area) {
+ Rectangle areaBounds = area.getBounds();
+ return new uk.me.parabola.imgfmt.app.Area(areaBounds.y, areaBounds.x,
+ areaBounds.y + areaBounds.height, areaBounds.x
+ + areaBounds.width);
+ }
+
+ /**
+ * Creates a Java2D {@link Area} object from a polygon given as a list of
+ * {@link Coord} objects. This list should describe a closed polygon.
+ *
+ * @param polygonPoints a list of points that describe a closed polygon
+ * @return the converted Java2D area
+ */
+ public static Area createArea(List<Coord> polygonPoints) {
+ return new Area(createPolygon(polygonPoints));
+ }
+
+ /**
+ * Create a polygon from a list of points.
+ *
+ * @param points list of points
+ * @return the polygon
+ */
+ public static Polygon createPolygon(List<Coord> points) {
+ Polygon polygon = new Polygon();
+ for (Coord co : points) {
+ polygon.addPoint(co.getLongitude(), co.getLatitude());
+ }
+ return polygon;
+ }
+
+ /**
+ * Convert an area that may contains multiple areas to a list of singular
+ * areas
+ *
+ * @param area an area
+ * @return list of singular areas
+ */
+ public static List<Area> areaToSingularAreas(Area area) {
+ if (area.isEmpty()) {
+ return Collections.emptyList();
+ } else if (area.isSingular()) {
+ return Collections.singletonList(area);
+ } else {
+ List<Area> singularAreas = new ArrayList<Area>();
+
+ // all ways in the area MUST define outer areas
+ // it is not possible that one of the areas define an inner segment
+
+ float[] res = new float[6];
+ PathIterator pit = area.getPathIterator(null);
+ int prevLat = Integer.MIN_VALUE;
+ int prevLong = Integer.MIN_VALUE;
+
+ Polygon p = null;
+ while (!pit.isDone()) {
+ int type = pit.currentSegment(res);
+ int lat = Math.round(res[1]);
+ int lon = Math.round(res[0]);
+
+ switch (type) {
+ case PathIterator.SEG_LINETO:
+ if (prevLat != lat || prevLong != lon) {
+ p.addPoint(lon, lat);
+ }
+ prevLat = lat;
+ prevLong = lon;
+ break;
+ case PathIterator.SEG_CLOSE:
+ p.addPoint(p.xpoints[0], p.ypoints[0]);
+ Area a = new Area(p);
+ if (!a.isEmpty()) {
+ singularAreas.add(a);
+ }
+ p = null;
+ break;
+ case PathIterator.SEG_MOVETO:
+ if (p != null) {
+ Area a2 = new Area(p);
+ if (!a2.isEmpty()) {
+ singularAreas.add(a2);
+ }
+ }
+ p = new Polygon();
+ p.addPoint(lon, lat);
+ break;
+ default:
+ log.error("Unsupported path iterator type " + type
+ + ". This is an mkgmap error.");
+ }
+
+ prevLat = lat;
+ prevLong = lon;
+
+ pit.next();
+ }
+ return singularAreas;
+ }
+ }
+
+ /**
+ * Convert an area to an mkgmap way. The caller must ensure that the area is
+ * singular. Otherwise only the first part of the area is converted.
+ *
+ * @param area the area
+ * @return a new mkgmap way
+ */
+ public static List<Coord> singularAreaToPoints(Area area) {
+ if (area.isEmpty()) {
+ return null;
+ }
+
+ List<Coord> points = null;
+
+ float[] res = new float[6];
+ PathIterator pit = area.getPathIterator(null);
+ int prevLat = Integer.MIN_VALUE;
+ int prevLong = Integer.MIN_VALUE;
+
+ while (!pit.isDone()) {
+ int type = pit.currentSegment(res);
+
+ int lat = Math.round(res[1]);
+ int lon = Math.round(res[0]);
+
+ switch (type) {
+ case PathIterator.SEG_MOVETO:
+ if (points != null)
+ log.error("area not singular");
+ points = new ArrayList<Coord>();
+ points.add(new Coord(lat, lon));
+ break;
+ case PathIterator.SEG_LINETO:
+ assert points != null;
+ if (prevLat != lat || prevLong != lon) {
+ points.add(new Coord(lat, lon));
+ }
+ break;
+ case PathIterator.SEG_CLOSE:
+ assert points != null;
+ if (points.get(0).equals(points.get(points.size() - 1))) {
+ // replace equal last with closing point
+ points.set(points.size() - 1, points.get(0));
+ }
+ else
+ points.add(points.get(0)); // add closing point
+ return points;
+ default:
+ log.error("Unsupported path iterator type " + type
+ + ". This is an mkgmap error.");
+ }
+
+ prevLat = lat;
+ prevLong = lon;
+
+ pit.next();
+ }
+ return points;
+ }
+
+ /**
+ * Convert the area back into a list of polygons each represented by a list
+ * of coords. It is possible that the area contains multiple discontinuous
+ * polygons, so you may append more than one shape to the output list.<br/>
+ * <b>Attention:</b> The outline of the polygon is has clockwise order whereas
+ * holes in the polygon have counterclockwise order.
+ *
+ * @param area The area to be converted.
+ * @return a list of closed polygons
+ */
+ public static List<List<Coord>> areaToShapes(java.awt.geom.Area area) {
+ List<List<Coord>> outputs = new ArrayList<List<Coord>>(4);
+
+ float[] res = new float[6];
+ PathIterator pit = area.getPathIterator(null);
+
+ // store float precision coords to check if the direction (cw/ccw)
+ // of a polygon changes due to conversion to int precision
+ List<Float> floatLat = null;
+ List<Float> floatLon = null;
+
+ List<Coord> coords = null;
+
+ int iPrevLat = Integer.MIN_VALUE;
+ int iPrevLong = Integer.MIN_VALUE;
+
+ while (!pit.isDone()) {
+ int type = pit.currentSegment(res);
+
+ float fLat = res[1];
+ float fLon = res[0];
+ int iLat = Math.round(fLat);
+ int iLon = Math.round(fLon);
+
+ switch (type) {
+ case PathIterator.SEG_LINETO:
+ floatLat.add(fLat);
+ floatLon.add(fLon);
+
+ if (iPrevLat != iLat || iPrevLong != iLon)
+ coords.add(new Coord(iLat,iLon));
+
+ iPrevLat = iLat;
+ iPrevLong = iLon;
+ break;
+ case PathIterator.SEG_MOVETO:
+ case PathIterator.SEG_CLOSE:
+ if ((type == PathIterator.SEG_MOVETO && coords != null) || type == PathIterator.SEG_CLOSE) {
+ if (coords.size() > 2){
+ if (coords.get(0).equals(coords.get(coords.size() - 1))){
+ // replace equal last with closing point
+ coords.set(coords.size() - 1, coords.get(0));
+ }
+ else
+ coords.add(coords.get(0)); // add closing point
+ }
+ if (coords.size() > 3){
+ // use float values to verify area size calculations with higher precision
+ if (floatLat.size() > 2) {
+ if (floatLat.get(0).equals(floatLat.get(floatLat.size() - 1)) == false
+ || floatLon.get(0).equals(floatLon.get(floatLon.size() - 1)) == false){
+ floatLat.add(floatLat.get(0));
+ floatLon.add(floatLon.get(0));
+ }
+ }
+
+ // calculate area size with float values
+ double realAreaSize = 0;
+ float pf1Lat = floatLat.get(0);
+ float pf1Lon = floatLon.get(0);
+ for(int i = 1; i < floatLat.size(); i++) {
+ float pf2Lat = floatLat.get(i);
+ float pf2Lon = floatLon.get(i);
+ realAreaSize += ((double)pf1Lon * pf2Lat -
+ (double)pf2Lon * pf1Lat);
+ pf1Lat = pf2Lat;
+ pf1Lon = pf2Lon;
+ }
+
+
+ // Check if the polygon with float precision has the same direction
+ // than the polygon with int precision. If not reverse the int precision
+ // polygon. Its direction has changed artificially by the int conversion.
+ boolean floatPrecClockwise = (realAreaSize <= 0);
+ if (Way.clockwise(coords) != floatPrecClockwise) {
+
+ if (log.isInfoEnabled()) {
+ log.info("Converting area to int precision changes direction. Will correct that.");
+ StringBuilder sb = new StringBuilder("[");
+ for (int i = 0; i < floatLat.size(); i++) {
+ if (i > 0) {
+ sb.append(", ");
+ }
+ sb.append(floatLat.get(i));
+ sb.append("/");
+ sb.append(floatLon.get(i));
+ }
+ sb.append("]");
+ log.info("Float area: ", sb);
+ log.info("Int area: ", coords);
+ }
+
+ Collections.reverse(coords);
+ }
+ outputs.add(coords);
+ }
+ }
+ if (type == PathIterator.SEG_MOVETO){
+ floatLat= new ArrayList<Float>();
+ floatLon= new ArrayList<Float>();
+ floatLat.add(fLat);
+ floatLon.add(fLon);
+ coords = new ArrayList<Coord>();
+ coords.add(new Coord(iLat,iLon));
+ iPrevLat = iLat;
+ iPrevLong = iLon;
+ } else {
+ floatLat= null;
+ floatLon= null;
+ coords = null;
+ iPrevLat = Integer.MIN_VALUE;
+ iPrevLong = Integer.MIN_VALUE;
+ }
+ break;
+ default:
+ log.error("Unsupported path iterator type " + type
+ + ". This is an mkgmap error.");
+ }
+
+ pit.next();
+ }
+
+ return outputs;
+ }
+}
diff --git a/src/uk/me/parabola/util/MultiHashMap.java b/src/uk/me/parabola/util/MultiHashMap.java
new file mode 100644
index 0000000..d870cdf
--- /dev/null
+++ b/src/uk/me/parabola/util/MultiHashMap.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2013.
+ *
+ * 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.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+
+public class MultiHashMap<K,V> extends HashMap<K,List<V>> {
+
+ /**
+ * the empty list to be returned when there is key without values.
+ */
+ private final List<V> emptyList = Collections.unmodifiableList(new ArrayList<V>(0));
+
+ /**
+ * Returns the list of values associated with the given key.
+ *
+ * @param key the key to get the values for.
+ * @return a list of values for the given keys or the empty list of no such
+ * value exist.
+ */
+ public List<V> get(Object key) {
+ List<V> result = super.get(key);
+ return result == null ? emptyList : result;
+ }
+
+
+ public V add(K key, V value )
+ {
+
+ List<V> values = super.get(key);
+ if (values == null ) {
+ values = new LinkedList<V>();
+ super.put( key, values );
+ }
+
+ boolean results = values.add(value);
+
+ return ( results ? value : null );
+ }
+
+ public V remove(K key, V value )
+ {
+
+ List<V> values = super.get(key);
+ if (values == null )
+ return null;
+
+ values.remove(value);
+
+ if (values.isEmpty())
+ super.remove(key);
+
+ return value;
+ }
+}
+
diff --git a/src/uk/me/parabola/util/MultiIdentityHashMap.java b/src/uk/me/parabola/util/MultiIdentityHashMap.java
new file mode 100644
index 0000000..47b176d
--- /dev/null
+++ b/src/uk/me/parabola/util/MultiIdentityHashMap.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2013.
+ *
+ * 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.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+
+public class MultiIdentityHashMap<K,V> extends IdentityHashMap<K,List<V>> {
+
+ /**
+ * the empty list to be returned when there is key without values.
+ */
+ private final List<V> emptyList = Collections.unmodifiableList(new ArrayList<V>(0));
+
+ /**
+ * Returns the list of values associated with the given key.
+ *
+ * @param key the key to get the values for.
+ * @return a list of values for the given keys or the empty list of no such
+ * value exist.
+ */
+ public List<V> get(Object key) {
+ List<V> result = super.get(key);
+ return result == null ? emptyList : result;
+ }
+
+
+ public V add(K key, V value )
+ {
+
+ List<V> values = super.get(key);
+ if (values == null ) {
+ values = new LinkedList<V>();
+ super.put( key, values );
+ }
+
+ boolean results = values.add(value);
+
+ return ( results ? value : null );
+ }
+
+ public V remove(K key, V value )
+ {
+
+ List<V> values = super.get(key);
+ if (values == null )
+ return null;
+
+ values.remove(value);
+
+ if (values.isEmpty())
+ super.remove(key);
+
+ return value;
+ }
+}
+
diff --git a/src/uk/me/parabola/util/QuadTree.java b/src/uk/me/parabola/util/QuadTree.java
new file mode 100644
index 0000000..954dd64
--- /dev/null
+++ b/src/uk/me/parabola/util/QuadTree.java
@@ -0,0 +1,127 @@
+package uk.me.parabola.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.util.QuadTreeNode.QuadTreePolygon;
+
+public class QuadTree {
+
+ private final QuadTreeNode root;
+ private long itemCount;
+
+ public QuadTree(Area bbox) {
+ this.root = new QuadTreeNode(bbox);
+ this.itemCount = 0;
+ }
+
+ public boolean addAll(Collection<Coord> coordList) {
+ boolean oneAdded = false;
+ for (Coord c : coordList) {
+ oneAdded = add(c) | oneAdded;
+ }
+ return oneAdded;
+ }
+
+ public boolean add(Coord c) {
+
+ boolean added = root.add(c);
+ if (added) {
+ itemCount++;
+ }
+ return added;
+ }
+
+ public List<Coord> get(Area bbox) {
+ return root.get(bbox, new ArrayList<Coord>(2000));
+ }
+
+ public List<Coord> get(Collection<List<Coord>> polygons) {
+ return root.get(new QuadTreePolygon(polygons), new ArrayList<Coord>(
+ 2000));
+ }
+
+ public List<Coord> get(List<Coord> polygon) {
+ return get(polygon, 0);
+ }
+
+ public List<Coord> get(List<Coord> polygon, int offset) {
+ if (polygon.size() < 3) {
+ return Collections.emptyList();
+ }
+ if (polygon.get(0).equals(polygon.get(polygon.size() - 1)) == false) {
+ return null;
+ }
+ ArrayList<Coord> points = root.get(new QuadTreePolygon(polygon),
+ new ArrayList<Coord>(2000));
+ if (offset > 0) {
+ ListIterator<Coord> pointIter = points.listIterator();
+ while (pointIter.hasNext()) {
+ if (isCloseToPolygon(pointIter.next(), polygon, offset)) {
+ pointIter.remove();
+ }
+ }
+ }
+ return points;
+ }
+
+ public void clear() {
+ itemCount = 0;
+ root.clear();
+ }
+
+ public long getSize() {
+ return itemCount;
+ }
+
+ private boolean isCloseToPolygon(Coord point, List<Coord> polygon,
+ int gap) {
+ Iterator<Coord> polyIter = polygon.iterator();
+ Coord c2 = polyIter.next();
+ while (polyIter.hasNext()) {
+ Coord c1 = c2;
+ c2 = polyIter.next();
+ double dist = distanceToSegment(c1, c2, point);
+ if (dist <= gap) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Calculates the distance to the given segment in meter.
+ * @param spoint1 segment point 1
+ * @param spoint2 segment point 2
+ * @param point point
+ * @return the distance in meter
+ */
+ private double distanceToSegment(Coord spoint1, Coord spoint2, Coord point) {
+
+ double dx = spoint2.getLongitude() - spoint1.getLongitude();
+ double dy = spoint2.getLatitude() - spoint1.getLatitude();
+
+ if ((dx == 0) && (dy == 0)) {
+ return spoint1.distance(point);
+ }
+
+ double frac = ((point.getLongitude() - spoint1.getLongitude()) * dx + (point
+ .getLatitude() - spoint1.getLatitude()) * dy)
+ / (dx * dx + dy * dy);
+
+ if (frac < 0) {
+ return spoint1.distance(point);
+ } else if (frac > 1) {
+ return spoint2.distance(point);
+ } else {
+ return spoint1.makeBetweenPoint(spoint2, frac).distance(point);
+ }
+
+ }
+}
diff --git a/src/uk/me/parabola/util/QuadTreeNode.java b/src/uk/me/parabola/util/QuadTreeNode.java
new file mode 100644
index 0000000..b494ebc
--- /dev/null
+++ b/src/uk/me/parabola/util/QuadTreeNode.java
@@ -0,0 +1,225 @@
+package uk.me.parabola.util;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+
+public class QuadTreeNode {
+
+ private static final int MAX_POINTS = 20;
+
+ private Collection<Coord> points;
+ private final Area bounds;
+ private Area coveredBounds;
+
+ public Area getCoveredBounds() {
+ return coveredBounds;
+ }
+
+ private QuadTreeNode[] children;
+
+ public static final class QuadTreePolygon {
+ private final java.awt.geom.Area javaArea;
+ private final Area bbox;
+
+ public QuadTreePolygon(java.awt.geom.Area javaArea) {
+ this.javaArea = javaArea;
+ Rectangle bboxRect = javaArea.getBounds();
+ bbox = new Area(bboxRect.y, bboxRect.x, bboxRect.y
+ + bboxRect.height, bboxRect.x + bboxRect.width);
+ }
+
+ public QuadTreePolygon(List<Coord> points) {
+ this(new java.awt.geom.Area(Java2DConverter.createPolygon(points)));
+ }
+
+ public QuadTreePolygon(Collection<List<Coord>> polygonList) {
+ this.javaArea = new java.awt.geom.Area();
+ for (List<Coord> polygon : polygonList) {
+ javaArea.add(new java.awt.geom.Area(Java2DConverter
+ .createPolygon(polygon)));
+ }
+ Rectangle bboxRect = javaArea.getBounds();
+ bbox = new Area(bboxRect.y, bboxRect.x, bboxRect.y
+ + bboxRect.height, bboxRect.x + bboxRect.width);
+ }
+
+ public Area getBbox() {
+ return bbox;
+ }
+
+ public java.awt.geom.Area getArea() {
+ return javaArea;
+ }
+ }
+
+ public QuadTreeNode(Area bounds) {
+ this(bounds, Collections.<Coord>emptyList());
+ }
+
+ public QuadTreeNode(Area bounds, Collection<Coord> points) {
+ this.bounds = bounds;
+ this.children = null;
+
+ int minLat = Integer.MAX_VALUE;
+ int maxLat = Integer.MIN_VALUE;
+ int minLong = Integer.MAX_VALUE;
+ int maxLong = Integer.MIN_VALUE;
+ for (Coord c : points) {
+ if (c.getLatitude() < minLat) {
+ minLat = c.getLatitude();
+ }
+ if (c.getLatitude() > maxLat) {
+ maxLat = c.getLatitude();
+ }
+ if (c.getLongitude() < minLong) {
+ minLong = c.getLongitude();
+ }
+ if (c.getLongitude() > maxLong) {
+ maxLong = c.getLongitude();
+ }
+ }
+ coveredBounds = new Area(minLat, minLong, maxLat, maxLong);
+
+ if (points.size() > MAX_POINTS) {
+ this.points = points;
+ split();
+ } else {
+ this.points = new HashSet<Coord>(points);
+ }
+ }
+
+ public Area getBounds() {
+ return this.bounds;
+ }
+
+ public boolean add(Coord c) {
+ if (coveredBounds == null) {
+ coveredBounds = new Area(c.getLatitude(), c.getLongitude(),
+ c.getLatitude(), c.getLongitude());
+ } else if (coveredBounds.contains(c) == false) {
+ coveredBounds = new Area(Math.min(coveredBounds.getMinLat(),
+ c.getLatitude()), Math.min(coveredBounds.getMinLong(),
+ c.getLongitude()), Math.max(coveredBounds.getMaxLat(),
+ c.getLatitude()), Math.max(coveredBounds.getMaxLong(),
+ c.getLongitude()));
+ }
+ if (isLeaf()) {
+ boolean added = points.add(c);
+ if (points.size() > MAX_POINTS)
+ split();
+ return added;
+ } else {
+ for (QuadTreeNode nodes : children) {
+ if (nodes.getBounds().contains(c)) {
+ return nodes.add(c);
+ }
+ }
+ return false;
+ }
+ }
+
+ public List<Coord> get(Area bbox, List<Coord> resultList) {
+ if (isLeaf()) {
+ if (bbox.getMinLat() <= coveredBounds.getMinLat()
+ && bbox.getMaxLat() >= coveredBounds.getMaxLat()
+ && bbox.getMinLong() <= coveredBounds.getMinLong()
+ && bbox.getMaxLong() >= coveredBounds.getMaxLong()) {
+
+ // the bounding box is contained completely in the bbox
+ // => add all points without further check
+ resultList.addAll(points);
+ } else {
+ // check each point
+ for (Coord c : points) {
+ if (bbox.contains(c)) {
+ resultList.add(c);
+ }
+ }
+ }
+ } else {
+ for (QuadTreeNode child : children) {
+ if (bbox.intersects(child.getCoveredBounds())) {
+ resultList = child.get(bbox, resultList);
+ }
+ }
+ }
+ return resultList;
+ }
+
+ public ArrayList<Coord> get(QuadTreePolygon polygon, ArrayList<Coord> resultList) {
+ if (polygon.getBbox().intersects(getBounds())) {
+ if (isLeaf()) {
+ for (Coord c : points) {
+ if (polygon.getArea().contains(c.getLongitude(),
+ c.getLatitude())) {
+ resultList.add(c);
+ }
+ }
+ } else {
+ for (QuadTreeNode child : children) {
+ if (polygon.getBbox().intersects(child.getBounds())) {
+ java.awt.geom.Area subArea = (java.awt.geom.Area) polygon
+ .getArea().clone();
+ subArea.intersect(createArea(child.getBounds()));
+ child.get(new QuadTreePolygon(subArea), resultList);
+ }
+ }
+ }
+ }
+ return resultList;
+
+ }
+
+ private java.awt.geom.Area createArea(Area bbox) {
+ return new java.awt.geom.Area(new Rectangle(bbox.getMinLong(),
+ bbox.getMinLat(), bbox.getWidth(), bbox.getHeight()));
+ }
+
+ public boolean isLeaf() {
+ return points != null;
+ }
+
+ private void split() {
+ if (bounds.getHeight() <= 1 || bounds.getWidth() <= 1) {
+ return;
+ }
+
+ int halfLat = (bounds.getMinLat() + bounds.getMaxLat()) / 2;
+ int halfLong = (bounds.getMinLong() + bounds.getMaxLong()) / 2;
+ children = new QuadTreeNode[4];
+
+ Area swBounds = new Area(bounds.getMinLat(), bounds.getMinLong(),
+ halfLat, halfLong);
+ Area nwBounds = new Area(halfLat + 1, bounds.getMinLong(),
+ bounds.getMaxLat(), halfLong);
+ Area seBounds = new Area(bounds.getMinLat(), halfLong + 1, halfLat,
+ bounds.getMaxLong());
+ Area neBounds = new Area(halfLat + 1, halfLong + 1, bounds.getMaxLat(),
+ bounds.getMaxLong());
+
+ children[0] = new QuadTreeNode(swBounds);
+ children[1] = new QuadTreeNode(nwBounds);
+ children[2] = new QuadTreeNode(seBounds);
+ children[3] = new QuadTreeNode(neBounds);
+
+ Collection<Coord> copyPoints = points;
+ points = null;
+ for (Coord c : copyPoints) {
+ add(c);
+ }
+ }
+
+ public void clear() {
+ this.children = null;
+ points = new HashSet<Coord>();
+ coveredBounds = new Area(Integer.MAX_VALUE, Integer.MAX_VALUE,
+ Integer.MIN_VALUE, Integer.MIN_VALUE);
+ }
+}
diff --git a/test/README b/test/README
new file mode 100644
index 0000000..e6f59b8
--- /dev/null
+++ b/test/README
@@ -0,0 +1,5 @@
+
+The utility programs that used to be in this directory have
+been moved to their own svn reposotory.
+
+This can be found at http://svn.parabola.me.uk/display/trunk
diff --git a/test/func/ArgsTest.java b/test/func/ArgsTest.java
new file mode 100644
index 0000000..4625950
--- /dev/null
+++ b/test/func/ArgsTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2008 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: 11-Jan-2009
+ */
+package func;
+
+import java.io.FileNotFoundException;
+
+import uk.me.parabola.imgfmt.app.trergn.TREFileReader;
+import uk.me.parabola.imgfmt.app.trergn.TREHeader;
+import uk.me.parabola.imgfmt.fs.FileSystem;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+
+import func.lib.Args;
+import func.lib.Outputs;
+import func.lib.TestUtils;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * A basic check of various arguments that can be passed in.
+ *
+ * @author Steve Ratcliffe
+ */
+public class ArgsTest extends Base {
+ @Test
+ public void testHelp() {
+ Outputs outputs = TestUtils.run("--help");
+ outputs.checkOutput("--help=options", "--help=links");
+ outputs.checkNoError();
+ checkNoStdFile();
+ }
+
+ @Test
+ public void testHelpOptions() {
+ Outputs outputs = TestUtils.run("--help=options");
+ outputs.checkNoError();
+ outputs.checkOutput("--mapname=name", "--latin1", "--list-styles");
+ checkNoStdFile();
+ }
+
+ @Test
+ public void testHelpUnknown() {
+ Outputs outputs = TestUtils.run("--help=unknown-help-option");
+ outputs.checkNoError();
+ outputs.checkOutput("Could not find", "unknown-help-option");
+ checkNoStdFile();
+ }
+
+ @Test
+ public void testListStyles() {
+ Outputs op = TestUtils.run("--style-file=test/resources/teststyles", "--list-styles");
+ op.checkNoError();
+ op.checkOutput("empty", "main", "simple", "derived", "2.2: A simple test style");
+ checkNoStdFile();
+ }
+
+ @Test
+ public void testListStylesVerbose() {
+ Outputs op = TestUtils.run("--style-file=test/resources/teststyles",
+ "--verbose", "--list-styles");
+ op.checkNoError();
+ op.checkOutput("empty", "main", "simple", "derived",
+ "2.2: A simple test style", "Used for many functional tests");
+ checkNoStdFile();
+ }
+
+ @Test
+ public void testDisplayPriority() throws FileNotFoundException {
+ int pri = 42;
+ Outputs op = TestUtils.run("--draw-priority=" + pri,
+ Args.TEST_RESOURCE_OSM + "uk-test-1.osm.gz");
+ op.checkNoError();
+
+ FileSystem fs = openFs(Args.DEF_MAP_FILENAME);
+ ImgChannel chan = fs.open(Args.DEF_MAP_ID + ".TRE", "r");
+ TREFileReader treFile = new TREFileReader(chan);
+
+ assertEquals("display priority", pri, ((TREHeader) treFile.getHeader()).getDisplayPriority());
+ }
+}
diff --git a/test/func/Base.java b/test/func/Base.java
new file mode 100644
index 0000000..f1c039d
--- /dev/null
+++ b/test/func/Base.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2008 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: 11-Jan-2009
+ */
+package func;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import uk.me.parabola.imgfmt.fs.FileSystem;
+import uk.me.parabola.imgfmt.sys.ImgFS;
+
+import func.lib.Args;
+import func.lib.TestUtils;
+import org.junit.After;
+import org.junit.Before;
+
+import static org.junit.Assert.*;
+
+/**
+ * Base class for tests with some useful routines. It ensures that created
+ * files are deleted before the test starts.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Base {
+ @Before
+ public void baseSetup() {
+ TestUtils.deleteOutputFiles();
+ }
+
+ @After
+ public void baseTeardown() {
+ TestUtils.closeFiles();
+ }
+
+ protected void checkStdFile() {
+ assertTrue("std output file exists", new File(Args.DEF_MAP_FILENAME).exists());
+ }
+
+ protected void checkNoStdFile() {
+ assertFalse("std output file exists", new File(Args.DEF_MAP_FILENAME).exists());
+ }
+
+ protected FileSystem openFs(String filename) throws FileNotFoundException {
+ FileSystem fs = ImgFS.openFs(filename);
+ TestUtils.registerFile(fs);
+ return fs;
+ }
+}
diff --git a/test/func/SimpleTest.java b/test/func/SimpleTest.java
new file mode 100644
index 0000000..7c6bc56
--- /dev/null
+++ b/test/func/SimpleTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2008 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: 10-Jan-2009
+ */
+package func;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.map.MapReader;
+import uk.me.parabola.imgfmt.app.trergn.Point;
+import uk.me.parabola.imgfmt.app.trergn.Polyline;
+import uk.me.parabola.imgfmt.fs.DirectoryEntry;
+import uk.me.parabola.imgfmt.fs.FileSystem;
+import uk.me.parabola.mkgmap.main.Main;
+
+import func.lib.Args;
+import func.lib.RangeMatcher;
+import func.lib.TestUtils;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Very simple checks. May go away as more detailed checks are developed.
+ *
+ * @author Steve Ratcliffe
+ */
+public class SimpleTest extends Base {
+
+ /**
+ * A very basic check that the size of all the sections has not changed.
+ * This can be used to make sure that a change that is not expected to
+ * change the output does not do so.
+ *
+ * The sizes will have to be always changed when the output does change
+ * though.
+ */
+ @Test
+ public void testBasic() throws FileNotFoundException {
+
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--preserve-element-order",
+ Args.TEST_RESOURCE_OSM + "uk-test-1.osm.gz"
+ });
+
+ MapReader mr = new MapReader(Args.DEF_MAP_ID + ".img");
+ TestUtils.registerFile(mr);
+ //FileSystem fs = ImgFS.openFs(Args.DEF_MAP_ID + ".img");
+ assertNotNull("file exists", mr);
+
+ Area bounds = mr.getTreBounds();
+ Area expBox = new Area(2402404, -11185, 2407064, -6524);
+ assertEquals("bounds of map", expBox, bounds);
+
+ List<Point> list = mr.pointsForLevel(0, MapReader.WITH_EXT_TYPE_DATA);
+ assertEquals("number of points at level 0", 204, list.size());
+
+ List<Polyline> list1 = mr.linesForLevel(0);
+ assertEquals("number of lines at level 0", 3382, list1.size());
+ }
+
+ @Test
+ public void testNoSuchFile() {
+ Main.main(new String[]{
+ "no-such-file-xyz.osm",
+ });
+ assertFalse("no file generated", new File(Args.DEF_MAP_FILENAME).exists());
+ }
+
+ @Test
+ public void testPolish() throws FileNotFoundException {
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ Args.TEST_RESOURCE_MP + "test1.mp"
+ });
+
+ FileSystem fs = openFs(Args.DEF_MAP_FILENAME);
+ assertNotNull("file exists", fs);
+
+ List<DirectoryEntry> entries = fs.list();
+ int count = 0;
+ for (DirectoryEntry ent : entries) {
+ String ext = ent.getExt();
+
+ int size = ent.getSize();
+ if (ext.equals("RGN")) {
+ count++;
+ System.out.println("RGN size " + size);
+ assertThat("RGN size", size, new RangeMatcher(2756));
+ } else if (ext.equals("TRE")) {
+ count++;
+ System.out.println("TRE size " + size);
+ // Size varies depending on svn modified status
+ assertThat("TRE size", size, new RangeMatcher(769, 2));
+ } else if (ext.equals("LBL")) {
+ count++;
+ assertEquals("LBL size", 985, size);
+ }
+ }
+ assertTrue("enough checks run", count >= 3);
+ }
+}
diff --git a/test/func/StructureTest.java b/test/func/StructureTest.java
new file mode 100644
index 0000000..523b632
--- /dev/null
+++ b/test/func/StructureTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2008 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: 10-Jan-2009
+ */
+package func;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import uk.me.parabola.imgfmt.app.lbl.LBLFileReader;
+import uk.me.parabola.imgfmt.app.trergn.RGNFileReader;
+import uk.me.parabola.imgfmt.app.trergn.TREFileReader;
+import uk.me.parabola.imgfmt.app.trergn.TREHeader;
+import uk.me.parabola.imgfmt.fs.FileSystem;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.imgfmt.sys.ImgFS;
+import uk.me.parabola.mkgmap.main.Main;
+
+import func.lib.Args;
+import func.lib.TestUtils;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Creates a single img file and runs several tests on it to verify
+ * the basic structure of it.
+ *
+ * @author Steve Ratcliffe
+ */
+public class StructureTest {
+ private static FileSystem fs;
+
+ private static LBLFileReader lblFile;
+ private static TREFileReader treFile;
+ private static RGNFileReader rgnFile;
+
+ /** Just test is exists. */
+ @Test
+ public void testExists() {
+ File f = new File(Args.DEF_MAP_FILENAME);
+ assertTrue("file exists", f.exists());
+ }
+
+ @Test
+ public void testTreHeader() {
+ TREHeader header = (TREHeader) treFile.getHeader();
+ assertEquals("header length", 188, header.getHeaderLength());
+
+ assertEquals("display priority", 25, header.getDisplayPriority());
+ }
+
+ /**
+ * Read in the file and open all the sections, leave references to them
+ * in fields so that the other tests can check things.
+ */
+ @BeforeClass
+ public static void init() throws FileNotFoundException {
+ TestUtils.deleteOutputFiles();
+
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ Args.TEST_RESOURCE_OSM + "uk-test-1.osm.gz"
+ });
+
+ fs = ImgFS.openFs(Args.DEF_MAP_FILENAME);
+ ImgChannel tre = fs.open(Args.DEF_MAP_ID + ".TRE", "r");
+ treFile = new TREFileReader(tre);
+
+ ImgChannel lbl = fs.open(Args.DEF_MAP_ID + ".LBL", "r");
+ lblFile = new LBLFileReader(lbl);
+
+ ImgChannel rgn = fs.open(Args.DEF_MAP_ID + ".RGN", "r");
+ rgnFile = new RGNFileReader(rgn);
+ }
+
+ /**
+ * Close everything down.
+ */
+ @AfterClass
+ public static void cleanup() {
+ if (fs != null) {
+ fs.close();
+ treFile.close();
+ lblFile.close();
+ rgnFile.close();
+ }
+ TestUtils.deleteOutputFiles();
+ }
+}
diff --git a/test/func/files/GmapsuppTest.java b/test/func/files/GmapsuppTest.java
new file mode 100644
index 0000000..7d1a609
--- /dev/null
+++ b/test/func/files/GmapsuppTest.java
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2008 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 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.
+ */
+/* Create date: 17-Feb-2009 */
+package func.files;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.Utils;
+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.mps.MapBlock;
+import uk.me.parabola.imgfmt.mps.MpsFileReader;
+import uk.me.parabola.imgfmt.mps.ProductBlock;
+import uk.me.parabola.imgfmt.sys.ImgFS;
+import uk.me.parabola.mkgmap.main.Main;
+
+import func.Base;
+import func.lib.Args;
+import func.lib.Outputs;
+import func.lib.TestUtils;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class GmapsuppTest extends Base {
+ private static final String GMAPSUPP_IMG = "gmapsupp.img";
+
+ @Test
+ public void testBasic() throws IOException {
+ File f = new File(GMAPSUPP_IMG);
+ assertFalse("does not pre-exist", f.exists());
+
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--gmapsupp",
+ Args.TEST_RESOURCE_IMG + "63240001.img",
+ Args.TEST_RESOURCE_IMG + "63240002.img"
+ });
+
+ assertTrue("gmapsupp.img is created", f.exists());
+
+ FileSystem fs = openFs(GMAPSUPP_IMG);
+ DirectoryEntry entry = fs.lookup("63240001.TRE");
+ assertNotNull("first file TRE", entry);
+ assertEquals("first file TRE size", getFileSize(Args.TEST_RESOURCE_IMG + "63240001.img", "63240001.TRE"), entry.getSize());
+
+ entry = fs.lookup("63240002.TRE");
+ assertNotNull("second file TRE", entry);
+ assertEquals("second file TRE size", getFileSize(Args.TEST_RESOURCE_IMG + "63240002.img", "63240002.TRE"), entry.getSize());
+ }
+
+ /**
+ * Check the values inside the MPS file, when the family id etc is
+ * common to all files.
+ */
+ @Test
+ public void testMpsFile() throws IOException {
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--gmapsupp",
+ "--family-id=150",
+ "--product-id=24",
+ "--series-name=tst series",
+ "--family-name=tst family",
+ "--area-name=tst area",
+ Args.TEST_RESOURCE_IMG + "63240001.img",
+ Args.TEST_RESOURCE_IMG + "63240002.img"
+ });
+
+ MpsFileReader reader = getMpsFile();
+ List<MapBlock> list = reader.getMaps();
+ reader.close();
+ assertEquals("number of map blocks", 2, list.size());
+
+ // All maps will have the same parameters apart from map name here
+ int count = 0;
+ for (MapBlock map : list) {
+ assertEquals("map number", 63240001 + count++, map.getMapNumber());
+ assertEquals("family id", 150, map.getFamilyId());
+ assertEquals("product id", 24, map.getProductId());
+ assertEquals("series name", "tst series", map.getSeriesName());
+ assertEquals("area name", "tst area", map.getAreaName());
+ assertEquals("map description", "uk test " + count, map.getMapDescription());
+ }
+ }
+
+ /**
+ * Test combining gmapsupp files. The family id etc should be taken from
+ * the MPS file in the gmapsupp.
+ */
+ @Test
+ public void testCombiningSupps() throws IOException {
+ TestUtils.registerFile("g1.img", "g2.img");
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--gmapsupp",
+ "--family-id=150",
+ "--product-id=24",
+ "--series-name=tst series",
+ "--family-name=tst family",
+ "--area-name=tst area",
+ Args.TEST_RESOURCE_IMG + "63240001.img",
+ });
+
+ File f = new File("gmapsupp.img");
+ f.renameTo(new File("g1.img"));
+
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--gmapsupp",
+ "--family-id=152",
+ "--product-id=26",
+ "--series-name=tst series 2",
+ "--family-name=tst family 2",
+ "--area-name=tst area 2",
+ Args.TEST_RESOURCE_IMG + "63240002.img",
+ });
+ f.renameTo(new File("g2.img"));
+
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--gmapsupp",
+ "g1.img",
+ "g2.img"
+ });
+
+
+ MpsFileReader reader = getMpsFile();
+ List<MapBlock> list = reader.getMaps();
+ assertEquals("number of map blocks", 2, list.size());
+
+ for (MapBlock map : list) {
+ if (map.getMapNumber() == 63240001) {
+ assertEquals("family id", 150, map.getFamilyId());
+ assertEquals("product id", 24, map.getProductId());
+ assertEquals("series name", "tst series", map.getSeriesName());
+ assertEquals("area name", "tst area", map.getAreaName());
+ assertEquals("hex name", 63240001, map.getHexNumber());
+ assertEquals("map description", "uk test 1", map.getMapDescription());
+ } else if (map.getMapNumber() == 63240002) {
+ assertEquals("family id", 152, map.getFamilyId());
+ assertEquals("product id", 26, map.getProductId());
+ assertEquals("series name", "tst series 2", map.getSeriesName());
+ assertEquals("area name", "tst area 2", map.getAreaName());
+ assertEquals("hex name", 63240002, map.getHexNumber());
+ assertEquals("map description", "uk test 2", map.getMapDescription());
+ } else {
+ assertTrue("Unexpected map found", false);
+ }
+ }
+ }
+
+ /**
+ * Test the case where we are combining img files with different family
+ * and product ids.
+ */
+ @Test
+ public void testDifferentFamilies() throws IOException {
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--gmapsupp",
+
+ "--family-id=101",
+ "--product-id=1",
+ "--series-name=tst series1",
+ Args.TEST_RESOURCE_IMG + "63240001.img",
+
+ "--family-id=102",
+ "--product-id=2",
+ "--series-name=tst series2",
+ Args.TEST_RESOURCE_IMG + "63240002.img"
+ });
+
+ MpsFileReader reader = getMpsFile();
+ List<MapBlock> list = reader.getMaps();
+ reader.close();
+ assertEquals("number of map blocks", 2, list.size());
+
+ // Directly check the family id's
+ assertEquals("family in map1", 101, list.get(0).getFamilyId());
+ assertEquals("family in map2", 102, list.get(1).getFamilyId());
+
+ // Check more things
+ int count = 0;
+ for (MapBlock map : list) {
+ count++;
+ assertEquals("family in map" + count, 100 + count, map.getFamilyId());
+ assertEquals("product in map" + count, count, map.getProductId());
+ assertEquals("series name in map" + count, "tst series" + count, map.getSeriesName());
+ }
+ }
+
+ /**
+ * The mps file has a block for each family/product in the map set.
+ */
+ @Test
+ public void testProductBlocks() throws IOException {
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--gmapsupp",
+
+ "--family-id=101",
+ "--product-id=1",
+ "--family-name=tst family1",
+ "--series-name=tst series1",
+ Args.TEST_RESOURCE_IMG + "63240001.img",
+
+ "--family-id=102",
+ "--product-id=2",
+ "--family-name=tst family2",
+ "--series-name=tst series2",
+ Args.TEST_RESOURCE_IMG + "63240002.img"
+ });
+
+ MpsFileReader reader = getMpsFile();
+
+ List<ProductBlock> products = reader.getProducts();
+ Collections.sort(products, new Comparator<ProductBlock>() {
+ public int compare(ProductBlock o1, ProductBlock o2) {
+ if (o1.getFamilyId() == o2.getFamilyId())
+ return 0;
+ else if (o1.getFamilyId() > o2.getFamilyId())
+ return 1;
+ else return -1;
+ }
+ });
+
+ ProductBlock block = products.get(0);
+ assertEquals("product block first family", 101, block.getFamilyId());
+ assertEquals("product block first product id", 1, block.getProductId());
+ assertEquals("product block first family name", "tst family1", block.getDescription());
+
+ block = products.get(1);
+ assertEquals("product block second family", 102, block.getFamilyId());
+ assertEquals("product block first product id", 2, block.getProductId());
+ assertEquals("product block first family name", "tst family2", block.getDescription());
+ }
+
+ /**
+ * Make sure that if we have multiple maps in the same family, which after
+ * all is the common case, that we only get one product block.
+ */
+ @Test
+ public void testProductWithSeveralMaps() throws IOException {
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--gmapsupp",
+
+ "--family-id=101",
+ "--product-id=1",
+ "--family-name=tst family1",
+ "--series-name=tst series1",
+ Args.TEST_RESOURCE_IMG + "63240001.img",
+ Args.TEST_RESOURCE_IMG + "63240002.img"
+ });
+
+ MpsFileReader reader = getMpsFile();
+ assertEquals("number of map blocks", 2, reader.getMaps().size());
+ assertEquals("number of product blocks", 1, reader.getProducts().size());
+ }
+
+ @Test
+ public void testWithIndex() throws IOException {
+ new File("osmmap_mdr.img").delete();
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--gmapsupp",
+ "--index",
+ "--latin1",
+
+ "--family-id=101",
+ "--product-id=1",
+ "--family-name=tst family1",
+ "--series-name=tst series1",
+ Args.TEST_RESOURCE_IMG + "63240001.img",
+ Args.TEST_RESOURCE_IMG + "63240002.img"
+ });
+
+ assertFalse(new File("osmmap_mdr.img").exists());
+
+ // All we are doing here is checking that the file was created and that it is
+ // not completely empty.
+ FileSystem fs = openFs(GMAPSUPP_IMG);
+ ImgChannel r = fs.open("00000101.MDR", "r");
+ r.position(2);
+ ByteBuffer buf = ByteBuffer.allocate(1024);
+
+ int read = r.read(buf);
+ assertEquals(1024, read);
+
+ buf.flip();
+ byte[] b = new byte[3];
+ buf.get(b, 0, 3);
+ assertEquals('G', b[0]);
+ }
+
+ @Test
+ public void testWithTwoIndexes() throws IOException {
+ TestUtils.registerFile("osmmap_mdr.img", "osmmap.img", "osmmap.tbd", "osmmap.mdx");
+
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--gmapsupp",
+ "--index",
+ "--tdbfile",
+ "--latin1",
+
+ "--family-id=101",
+ "--product-id=1",
+ "--family-name=tst family1",
+ "--series-name=tst series1",
+ Args.TEST_RESOURCE_IMG + "63240001.img",
+ Args.TEST_RESOURCE_IMG + "63240002.img"
+ });
+
+ assertTrue(new File("osmmap_mdr.img").exists());
+
+ // All we are doing here is checking that the file was created and that it is
+ // not completely empty.
+ FileSystem fs = openFs(GMAPSUPP_IMG);
+ ImgChannel r = fs.open("00000101.MDR", "r");
+ r.position(2);
+ ByteBuffer buf = ByteBuffer.allocate(1024);
+
+ int read = r.read(buf);
+ assertEquals(1024, read);
+
+ buf.flip();
+ byte[] b = new byte[3];
+ buf.get(b, 0, 3);
+ assertEquals('G', b[0]);
+ }
+
+ /**
+ * If there are files in two (or more) families then there should be a MDR and SRT for each.
+ */
+ @Test
+ public void testTwoFamilyIndex() throws IOException {
+ TestUtils.registerFile("osmmap_mdr.img", "osmmap.img", "osmmap.tbd", "osmmap.mdx");
+
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--gmapsupp",
+ "--index",
+ "--latin1",
+
+ "--family-id=101",
+ "--product-id=1",
+ "--family-name=tst family1",
+ "--series-name=tst series1",
+ Args.TEST_RESOURCE_OSM + "uk-test-1.osm.gz",
+ "--family-id=202",
+ "--family-name=tst family2",
+ "--series-name=tst series2",
+ Args.TEST_RESOURCE_OSM + "uk-test-2.osm.gz"
+ });
+
+ assertFalse(new File("osmmap_mdr.img").exists());
+
+ // All we are doing here is checking that the file was created and that it is
+ // not completely empty.
+ FileSystem fs = openFs(GMAPSUPP_IMG);
+ ImgChannel r = fs.open("00000101.MDR", "r");
+ r.position(2);
+ ByteBuffer buf = ByteBuffer.allocate(1024);
+ int read = r.read(buf);
+ assertEquals(1024, read);
+
+ fs = openFs(GMAPSUPP_IMG);
+ r = fs.open("00000202.MDR", "r");
+ r.position(2);
+ buf.clear();
+ read = r.read(buf);
+ assertEquals(1024, read);
+
+ r = fs.open("00000202.SRT", "r");
+ buf = ByteBuffer.allocate(512);
+ read = r.read(buf);
+ assertEquals(512, read);
+ r = fs.open("00000101.SRT", "r");
+ buf.clear();
+ read = r.read(buf);
+ assertEquals(512, read);
+ }
+
+ /**
+ * If no code page is given for the index, it is taken from the input files.
+ */
+ @Test
+ public void testImplicitCodePageIndex() throws IOException {
+ TestUtils.registerFile("osmmap_mdr.img", "osmmap.img", "osmmap.tbd", "osmmap.mdx");
+
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--code-page=1256",
+
+ Args.TEST_RESOURCE_OSM + "uk-test-1.osm.gz",
+ });
+
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--gmapsupp",
+ "--index",
+
+ "63240001.img",
+ });
+
+ assertFalse(new File("osmmap_mdr.img").exists());
+
+ FileSystem fs = openFs(GMAPSUPP_IMG);
+ ImgChannel r = fs.open("00006324.MDR", "r");
+
+ ByteBuffer buf = ByteBuffer.allocate(1024);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+
+ r.read(buf);
+ assertEquals(1256, buf.getChar(0x15));
+ assertEquals(0x010009, buf.getInt(0x17));
+ }
+
+ /**
+ * If there are mis-matching code-pages in the input files there should be a warning.
+ */
+ @Test
+ public void testWarningOnMismatchedCodePages() throws IOException {
+ TestUtils.registerFile("osmmap.img");
+
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--route",
+ "--code-page=1256",
+ Args.TEST_RESOURCE_OSM + "uk-test-1.osm.gz",
+
+ "--latin1",
+ Args.TEST_RESOURCE_OSM + "uk-test-2.osm.gz",
+ });
+
+ Outputs outputs = TestUtils.run(Args.TEST_STYLE_ARG,
+ "--gmapsupp",
+ "--index",
+
+ "63240001.img",
+ "63240002.img"
+ );
+
+ outputs.checkError("different code page");
+ }
+
+ private MpsFileReader getMpsFile() throws IOException {
+ FileSystem fs = openFs(GMAPSUPP_IMG);
+ MpsFileReader reader = new MpsFileReader(fs.open("MAKEGMAP.MPS", "r"));
+ TestUtils.registerFile(reader);
+ return reader;
+ }
+
+ private int getFileSize(String imgName, String fileName) throws IOException {
+ FileSystem fs = ImgFS.openFs(imgName);
+ try {
+ return fs.lookup(fileName).getSize();
+ } finally {
+ Utils.closeFile(fs);
+ }
+ }
+}
diff --git a/test/func/files/IndexTest.java b/test/func/files/IndexTest.java
new file mode 100644
index 0000000..f4bd88d
--- /dev/null
+++ b/test/func/files/IndexTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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 func.files;
+
+import java.io.File;
+import java.io.IOException;
+
+import uk.me.parabola.imgfmt.fs.DirectoryEntry;
+import uk.me.parabola.imgfmt.fs.FileSystem;
+
+import func.Base;
+import func.lib.Args;
+import func.lib.Outputs;
+import func.lib.TestUtils;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class IndexTest extends Base {
+ private static final String OVERVIEW_NAME = "testname";
+ private static final String MDR_IMG = OVERVIEW_NAME + "_mdr.img";
+
+ @Test
+ public void testCreateIndex() throws IOException {
+ File f = new File(MDR_IMG);
+ f.delete();
+ assertFalse("does not pre-exist", f.exists());
+
+ Outputs outputs = TestUtils.run(
+ Args.TEST_STYLE_ARG,
+ "--index",
+ "--latin1",
+ "--family-id=1002",
+ "--overview-mapname=" + OVERVIEW_NAME,
+ Args.TEST_RESOURCE_IMG + "63240001.img",
+ Args.TEST_RESOURCE_IMG + "63240002.img"
+ );
+ outputs.checkNoError();
+
+ TestUtils.registerFile(MDR_IMG);
+ TestUtils.registerFile(OVERVIEW_NAME+".tdb");
+ TestUtils.registerFile(OVERVIEW_NAME+".mdx");
+ TestUtils.registerFile(OVERVIEW_NAME+".img");
+
+ assertTrue(MDR_IMG + " is created", f.exists());
+
+ FileSystem fs = openFs(MDR_IMG);
+ DirectoryEntry entry = fs.lookup(OVERVIEW_NAME.toUpperCase() + ".MDR");
+ assertNotNull("Contains the MDR file", entry);
+
+ entry = fs.lookup(OVERVIEW_NAME.toUpperCase() + ".SRT");
+ assertNotNull("contains the SRT file", entry);
+ fs.close();
+ }
+}
diff --git a/test/func/files/TdbTest.java b/test/func/files/TdbTest.java
new file mode 100644
index 0000000..e881f44
--- /dev/null
+++ b/test/func/files/TdbTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2008 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 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.
+ */
+/* Create date: 17-Feb-2009 */
+package func.files;
+
+import java.io.File;
+import java.io.IOException;
+
+import uk.me.parabola.mkgmap.main.Main;
+import uk.me.parabola.tdbfmt.TdbFile;
+
+import func.Base;
+import func.lib.Args;
+import func.lib.TestUtils;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+public class TdbTest extends Base {
+ private static final String TDBNAME = "osmmap.tdb";
+
+ /**
+ * Basic test that the correct file is created. Check a few
+ * values within it too.
+ */
+ @Test
+ public void testBasic() throws IOException {
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--tdbfile",
+ Args.TEST_RESOURCE_OSM + "uk-test-1.osm.gz",
+ Args.TEST_RESOURCE_OSM + "uk-test-2.osm.gz"
+ });
+
+ File f = new File(TDBNAME);
+ assertTrue("TDB was created", f.exists());
+
+ TdbFile tdb = TdbFile.read(TDBNAME);
+ assertEquals("tdb version", 407, tdb.getTdbVersion());
+ }
+
+
+ /**
+ * Check for each possible option.
+ */
+ @Test
+ public void testOptions() {
+ int thisMapname = 11112222;
+ TestUtils.registerFile(thisMapname + ".img", thisMapname + ".tdb");
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--tdbfile",
+ "--overview-mapname=" + thisMapname,
+ "--family-id=198",
+ "--product-id=2",
+ "--series-name=Test series",
+ "--family-name=Test family",
+ Args.TEST_RESOURCE_OSM + "uk-test-1.osm.gz"
+ });
+
+ File f = new File(thisMapname + ".tdb");
+ assertTrue("TDB was created", f.exists());
+
+ // more to do here...
+ }
+}
diff --git a/test/func/lib/Args.java b/test/func/lib/Args.java
new file mode 100644
index 0000000..3df91da
--- /dev/null
+++ b/test/func/lib/Args.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2008 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: 10-Jan-2009
+ */
+package func.lib;
+
+/**
+ * Useful constants that are used for arguments etc. in the functional
+ * tests.
+ *
+ * @author Steve Ratcliffe
+ */
+public interface Args {
+ public static final String TEST_RESOURCE_OSM = "test/resources/in/osm/";
+ public static final String TEST_RESOURCE_MP = "test/resources/in/mp/";
+ public static final String TEST_RESOURCE_IMG = "test/resources/in/img/";
+
+ public static final String TEST_STYLE_ARG = "--style-file=test/resources/teststyles/main";
+
+ public static final String DEF_MAP_ID = "63240001";
+ public static final String DEF_MAP_ID2 = "63240002";
+ public static final String DEF_MAP_FILENAME = "63240001.img";
+ public static final String DEF_MAP_FILENAME2 = "63240002.img";
+ public static final String DEF_MAP_FILENAME3 = "63240003.img";
+ public static final String DEF_GMAPSUPP_FILENAME = "gmapsupp.img";
+ public static final String DEF_TDB_FILENAME = "osmmap.tdb";
+}
diff --git a/test/func/lib/ArrayImgWriter.java b/test/func/lib/ArrayImgWriter.java
new file mode 100644
index 0000000..437da23
--- /dev/null
+++ b/test/func/lib/ArrayImgWriter.java
@@ -0,0 +1,86 @@
+/*
+ * 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 func.lib;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+
+/**
+ * A writer that just writes to an array for testing.
+ *
+ * @author Steve Ratcliffe
+ */
+public class ArrayImgWriter implements ImgFileWriter {
+ private final ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ public void sync() throws IOException {
+ }
+
+ public int position() {
+ return out.size();
+ }
+
+ public void position(long pos) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void put(byte b) {
+ out.write(b);
+ }
+
+ public void putChar(char c) {
+ out.write(c & 0xff);
+ out.write((c >> 8) & 0xff);
+ }
+
+ public void put3(int val) {
+ out.write(val & 0xff);
+ out.write((val >> 8) & 0xff);
+ out.write((val >> 16) & 0xff);
+ }
+
+ public void putInt(int val) {
+ out.write(val & 0xff);
+ out.write((val >> 8) & 0xff);
+ out.write((val >> 16) & 0xff);
+ out.write((val >> 24) & 0xff);
+ }
+
+ public void put(byte[] val) {
+ out.write(val, 0, val.length);
+ }
+
+ public void put(byte[] src, int start, int length) {
+ out.write(src, start, length);
+ }
+
+ public void put(ByteBuffer src) {
+ byte[] array = src.array();
+ out.write(array, 0, src.limit());
+ }
+
+ public long getSize() {
+ return out.size();
+ }
+
+ public void close() throws IOException {
+ out.close();
+ }
+
+ public byte[] getBytes() {
+ return out.toByteArray();
+ }
+}
diff --git a/test/func/lib/NumberReader.java b/test/func/lib/NumberReader.java
new file mode 100644
index 0000000..f98d1b8
--- /dev/null
+++ b/test/func/lib/NumberReader.java
@@ -0,0 +1,495 @@
+/*
+ * Copyright (C) 2008 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 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 func.lib;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.BitReader;
+import uk.me.parabola.imgfmt.app.net.NumberStyle;
+import uk.me.parabola.imgfmt.app.net.Numbers;
+
+import static uk.me.parabola.imgfmt.app.net.NumberStyle.*;
+
+
+/**
+ * This is a test reader of the numbering streams. Since there are multiple ways of writing
+ * the same set of house numbers, the only reasonable way of testing the write process is to
+ * read the bit stream back and compare with the intended numbers.
+ *
+ * There is no attempt at efficiency given it is for testing, but it is believed to correctly
+ * read numbers from any map.
+ *
+ * This code is derived directly from the NetDisplay class in the display project, so see that
+ * to see the development of this file.
+ * The algorithm that is required to read the bit stream was partly derived by studying the
+ * the released GPL code of cGPSmapper by Stanislaw Kozicki.
+ *
+ * @author Steve Ratcliffe
+ */
+public class NumberReader {
+
+ private final BitReader br;
+
+ // For reading the start differences and end difference numbers.
+ private VarBitReader startReader;
+ private VarBitReader endReader;
+ private VarBitReader savedStartReader;
+ private VarBitReader savedEndReader;
+ private boolean doRestoreBitWidths;
+
+ // base numbers
+ private int leftBase;
+ private int rightBase;
+
+ // numbering styles
+ private NumberStyle leftStyle = ODD;
+ private NumberStyle rightStyle = EVEN;
+
+ // start numbers
+ private int leftStart;
+ private int rightStart;
+
+ // end numbers
+ private int leftEnd;
+ private int rightEnd;
+
+ // saved end numbers
+ private int leftLastEndDiff;
+ private int rightLastEndDiff;
+
+ // Numbers are a range between nodes. Keep count of them here
+ private int nodeCounter;
+ private int numberOfNodes;
+
+ public NumberReader(BitReader br) {
+ this.br = br;
+ }
+
+ public void setNumberOfNodes(int numberOfNodes) {
+ this.numberOfNodes = numberOfNodes;
+ }
+
+ /**
+ * Read the numbers into a list of Numbers classes.
+ * @param swap If the default starting position of left=ODD right=EVEN should be swapped.
+ * @return A list of the numbers that the input stream represents.
+ */
+ public List<Numbers> readNumbers(boolean swap) {
+ if (swap) {
+ leftStyle = EVEN;
+ rightStyle = ODD;
+ }
+
+ getBitWidths();
+
+ getInitialBase();
+
+ List<Numbers> numbers = new ArrayList<Numbers>();
+
+ // To do this properly we need to know the number of nodes I think, this is the
+ // best we can do: if there are more than 8 bits left, there must be another command
+ // left. We could leave a short command at the end.
+ while (br.getBitPosition() < br.getNumberOfBits() && numbers.size() < numberOfNodes) {
+ runCommand(numbers);
+ }
+
+ return numbers;
+ }
+
+
+ /**
+ * Get the bit widths for the start and end differences.
+ * Based on code for reading the RGN streams, but the signed bit is the
+ * opposite value.
+ * x is for start value differences. y is for end value differences.
+ */
+ private void getBitWidths() {
+ startReader = new VarBitReader(br, 5);
+ endReader = new VarBitReader(br, 2);
+ }
+
+ /**
+ * Decode the next command in the stream and run it.
+ * @param numbers When numbers are read, they are saved here.
+ */
+ private void runCommand(List<Numbers> numbers) throws NumberException {
+ int cmd = readCommand(); // fetch 1, 3 skip, 2 reload, 0 style
+
+ switch (cmd) {
+ case 0:
+ changeStyles();
+ break;
+ case 1:
+ fetchNumbers(numbers);
+ break;
+ case 2:
+ useBits();
+ break;
+ case 6:
+ skipNodes();
+ break;
+ default:
+ fail("unimplemented command: " + cmd);
+ }
+ }
+
+ /**
+ * Temporarily use a different bit width for the following number fetch.
+ */
+ private void useBits() {
+ if (!doRestoreBitWidths) {
+ savedStartReader = startReader;
+ savedEndReader = endReader;
+ }
+ doRestoreBitWidths = true;
+
+ if (br.get1()) {
+ endReader = new VarBitReader(br, 2);
+ } else {
+ startReader = new VarBitReader(br, 5);
+ }
+ }
+
+ /**
+ * Skip nodes. For parts of a road that has no numbers.
+ */
+ private void skipNodes() {
+ boolean f = br.get1();
+ int skip;
+ if (f)
+ skip = 1 + br.get(10);
+ else
+ skip = 1 + br.get(5);
+ nodeCounter += skip;
+ }
+
+ /**
+ * Read the next command from the stream. Commands are variable length in the bit
+ * stream.
+ * 0 - numbering style (none, odd, even, both)
+ * 1 - fetch numbers
+ * 2 - change bit widths
+ * 6 - skip nodes
+ * @return The command number
+ */
+ private int readCommand() {
+ int cmd = 0;
+ if (br.get1()) {
+ cmd |= 0x1;
+ } else {
+ if (br.get1()) {
+ cmd |= 0x2;
+ if (br.get1()) {
+ cmd |= 0x4;
+ }
+ }
+ }
+ return cmd;
+ }
+
+ /**
+ * Read the house numbers for a stretch of road.
+ *
+ * The start and end positions of the the left hand side of the road is first, followed
+ * by the right hand side of the road.
+ *
+ * The differences to the last point are stored. It is also possible to
+ * @param numbers When numbers are read, they are saved here.
+ */
+ private void fetchNumbers(List<Numbers> numbers) {
+
+ // If one side has no numbers, then there is only one set of numbers to calculate, but
+ // changes to base are applied to both sides.
+ boolean doSingleSide = (leftStyle == NONE || rightStyle == NONE);
+
+ if (leftStyle == NONE)
+ leftBase = rightBase;
+
+ // Check for command to copy the base number
+ boolean doSameBase = false;
+ if (!doSingleSide) {
+ doSameBase = br.get1();
+ if (doSameBase)
+ copyBase();
+ }
+
+ //int abc = br.get(3);
+ boolean doRightOverride = false;
+ if (!doSingleSide)
+ doRightOverride = !br.get1();
+ boolean doReadStart = !br.get1();
+ boolean doReadEnd = !br.get1();
+
+ //item.addText("cmd: fetch numbers abc: %x", abc);
+
+ int startDiff = 0, endDiff = leftLastEndDiff;
+
+ if (doReadStart) {
+ startDiff = startReader.read();
+ }
+ if (doReadEnd) {
+ endDiff = endReader.read();
+ }
+
+ leftStart = leftBase + startDiff;
+ leftEnd = leftStart + endDiff;
+
+ leftBase = leftEnd;
+ leftLastEndDiff = endDiff;
+
+ if (doSingleSide) {
+ readSingleSide(numbers);
+ restoreReaders();
+ return;
+ }
+
+ // *** Now for the right hand side numbers ***
+
+ // Note that endDiff falls through to this part
+ // start diff falls through at least when doSameBase is in force
+ if (!doSameBase)
+ startDiff = 0;
+
+ // If we didn't read an endDiff value for the left side or right is different then
+ // default to the saved value.
+ if (doRightOverride || !doReadEnd)
+ endDiff = rightLastEndDiff;
+
+ doReadStart = false;
+ doReadEnd = false;
+
+ if (!doSameBase)
+ doReadStart = !br.get1();
+
+ if (doRightOverride)
+ doReadEnd = !br.get1();
+
+ if (doReadStart)
+ startDiff = startReader.read();
+
+ if (doReadEnd)
+ endDiff = endReader.read();
+
+ rightStart = rightBase + startDiff;
+ rightEnd = rightStart + endDiff;
+
+ rightBase = rightEnd;
+ rightLastEndDiff = endDiff;
+
+ adjustValues();
+
+ Numbers n = new Numbers();
+ n.setRnodNumber(nodeCounter);
+
+ n.setLeftNumberStyle(leftStyle);
+ n.setLeftStart(leftStart);
+ n.setLeftEnd(leftEnd);
+
+ n.setRightNumberStyle(rightStyle);
+ n.setRightStart(rightStart);
+ n.setRightEnd(rightEnd);
+
+ numbers.add(n);
+ nodeCounter++;
+
+ restoreReaders();
+ }
+
+ /**
+ * After a temporary bit width change.
+ */
+ private void restoreReaders() {
+ if (doRestoreBitWidths) {
+ startReader = savedStartReader;
+ endReader = savedEndReader;
+ doRestoreBitWidths = false;
+ }
+ }
+
+ /**
+ * If the road has numbers on just one side, then there is a shortened reading routine.
+ * The left variables are mostly used during reading regardless of which side of the
+ * road has numbers. Make everything work here.
+ * @param numbers The output list that the number record should be added to.
+ */
+ private void readSingleSide(List<Numbers> numbers) {
+ rightBase = leftBase;
+ rightStart = leftStart;
+ rightEnd = leftEnd;
+ rightLastEndDiff = leftLastEndDiff;
+ adjustValues();
+
+ Numbers n = new Numbers();
+ if (leftStyle == NONE) {
+ n.setRnodNumber(nodeCounter);
+ n.setRightNumberStyle(rightStyle);
+ n.setRightStart(rightStart);
+ n.setRightEnd(rightEnd);
+
+ n.setLeftNumberStyle(NONE);
+ n.setLeftStart(-1);
+ n.setLeftEnd(-1);
+ }
+ else {
+ n.setRnodNumber(nodeCounter);
+ n.setLeftNumberStyle(leftStyle);
+ n.setLeftStart(leftStart);
+ n.setLeftEnd(leftEnd);
+
+ n.setRightNumberStyle(NONE);
+ n.setRightStart(-1);
+ n.setRightEnd(-1);
+ }
+ numbers.add(n);
+ nodeCounter++;
+ }
+
+ /**
+ * When it is known if the numbers are odd or even, then a shorter bitstream is made
+ * by taking advantage of that fact. This leaves the start and end points needing
+ * adjustment to made them odd or even as appropriate.
+ */
+ private void adjustValues() {
+ int ldirection = 1; // direction start is adjusted in; end in the opposite direction.
+ if (leftStart < leftEnd)
+ leftEnd--;
+ else if (leftStart > leftEnd) {
+ leftEnd++;
+ ldirection = -1;
+ }
+
+ int rdirection = 1; // direction start is adjusted in; end in the opposite direction.
+ if (rightStart < rightEnd)
+ rightEnd--;
+ else if (rightStart > rightEnd) {
+ rightEnd++;
+ rdirection = -1;
+ }
+
+ if (leftStyle == EVEN) {
+ if ((leftStart & 1) == 1) leftStart += ldirection;
+ if ((leftEnd & 1) == 1) leftEnd -= ldirection;
+ } else if (leftStyle == ODD) {
+ if ((leftStart & 1) == 0) leftStart+=ldirection;
+ if ((leftEnd & 1) == 0) leftEnd-=ldirection;
+ }
+ if (rightStyle == EVEN) {
+ if ((rightStart & 1) == 1) rightStart+=rdirection;
+ if ((rightEnd & 1) == 1) rightEnd-=rdirection;
+ } else if (rightStyle == ODD) {
+ if ((rightStart & 1) == 0) rightStart+=rdirection;
+ if ((rightEnd & 1) == 0) rightEnd-=rdirection;
+ }
+ }
+
+ /**
+ * Copy one of the bases to the other so they have the same value.
+ * The source is determined by reading a bit from the input.
+ */
+ private void copyBase() {
+ boolean f2 = br.get1();
+ if (f2) {
+ rightBase = leftBase;
+ } else {
+ leftBase = rightBase;
+ }
+ }
+
+ /**
+ * Change the numbering styles for this section of roads.
+ */
+ private void changeStyles() {
+ leftStyle = fromInt(br.get(2));
+ rightStyle = fromInt(br.get(2));
+ }
+
+ /**
+ * Get the initial base value. The first number for this section of road (although a diff
+ * can be applied to it).
+ *
+ * @throws NumberException
+ */
+ private void getInitialBase() {
+ int extra = 0;
+ boolean b1 = br.get1();
+ if (!b1)
+ extra = br.get(4);
+
+ leftBase = br.get(5 + extra);
+ rightBase = leftBase;
+ }
+
+ /**
+ * For cases that are not implemented yet.
+ */
+ private void fail(String s) throws NumberException {
+ System.out.printf("ABANDON: %s\n", s);
+ remainingBits();
+ throw new NumberException();
+ }
+
+ /**
+ * Just print out any remaining bits.
+ *
+ * Was mostly used during development, before the whole stream was decoded.
+ */
+ private void remainingBits() {
+ StringBuilder sb = new StringBuilder();
+ while (br.getBitPosition() < br.getNumberOfBits()) {
+ sb.insert(0, br.get1() ? "1" : "0");
+ }
+ System.out.print(sb.toString());
+ }
+
+}
+
+/**
+ * Reads integers with specified numbers of bits and optionally with sign bits.
+ */
+class VarBitReader {
+ private final boolean signed; // read as signed values
+ private final boolean negative; // all values are read as positive and then negated
+ private final int width; // the number of bits
+ private final int off; // a value to be added to width to get the true number to read.
+ private final BitReader br;
+
+ public VarBitReader(BitReader br, int off) {
+ this.br = br;
+ this.off = off;
+ negative = br.get1();
+ signed = br.get1();
+ width = br.get(4);
+ }
+
+ public int read() {
+ int val;
+ if (signed) {
+ val = br.sget(width + off + 1);
+ } else {
+ val = br.get(width + off);
+ }
+
+ if (negative)
+ val = -val;
+ return val;
+ }
+
+ public String toString() {
+ return String.format("sign=%b neg=%b width=%d+%d", signed, negative, width, off);
+ }
+}
+
+
+class NumberException extends RuntimeException {
+}
diff --git a/test/func/lib/Outputs.java b/test/func/lib/Outputs.java
new file mode 100644
index 0000000..13df24d
--- /dev/null
+++ b/test/func/lib/Outputs.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2008 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: 11-Jan-2009
+ */
+package func.lib;
+
+import static org.junit.Assert.*;
+
+/**
+ * Standard output and error as produced during a run.
+ *
+ * @author Steve Ratcliffe
+ */
+public class Outputs {
+ private final String out;
+ private final String err;
+
+ public Outputs(String out, String err) {
+ this.out = out;
+ this.err = err;
+ }
+
+ protected String getOut() {
+ return out;
+ }
+
+ protected String getErr() {
+ return err;
+ }
+
+ /**
+ * Check that the standard error is empty.
+ */
+ public void checkNoError() {
+ assertEquals("no error output", "", getErr());
+ }
+
+ /**
+ * Check that the output contains the given strings. You can specify
+ * any number of strings.
+ * @param strings The list of strings to check.
+ */
+ public void checkOutput(String... strings) {
+ String out = getOut();
+ for (String s : strings) {
+ if (!out.contains(s)) {
+ // Test has failed. Construct an assertion that will print
+ // something that is useful to show the problem.
+ assertEquals("contains '" + s + "'",
+ "..." + s + "...",
+ out);
+ }
+ }
+ }
+
+ /**
+ * Check that the output contains the given strings. You can specify
+ * any number of strings.
+ * @param strings The list of strings to check.
+ */
+ public void checkError(String... strings) {
+ String err = getErr();
+ for (String s : strings) {
+ if (!err.contains(s)) {
+ // Test has failed. Construct an assertion that will print
+ // something that is useful to show the problem.
+ assertEquals("contains '" + s + "'",
+ "..." + s + "...",
+ err);
+ }
+ }
+ }
+}
diff --git a/test/func/lib/RangeMatcher.java b/test/func/lib/RangeMatcher.java
new file mode 100644
index 0000000..1225191
--- /dev/null
+++ b/test/func/lib/RangeMatcher.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2008 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 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.
+ */
+/* Create date: 01-Jul-2009 */
+package func.lib;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+
+/**
+ * Test for a range of values around the expected one. This allows
+ * small changes without having to fix the test every time there is a
+ * small change to the output size.
+ *
+ * @author Steve Ratcliffe
+ */
+public class RangeMatcher extends BaseMatcher<Integer> {
+ private final int minVal;
+ private final int maxVal;
+
+ public RangeMatcher(int size) {
+ this(size, size/20+1);
+ }
+
+ public RangeMatcher(int size, int range) {
+ this.minVal = size - range;
+ this.maxVal = size + range;
+ }
+
+ public boolean matches(Object o) {
+ int other = (Integer) o;
+ if (other > minVal && other < maxVal)
+ return true;
+ else return false;
+ }
+
+ public void describeTo(Description description) {
+ description.appendValueList("between ", " and ", "", minVal, maxVal);
+ }
+}
diff --git a/test/func/lib/StringStyleFileLoader.java b/test/func/lib/StringStyleFileLoader.java
new file mode 100644
index 0000000..8dbcbde
--- /dev/null
+++ b/test/func/lib/StringStyleFileLoader.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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 func.lib;
+
+import java.io.FileNotFoundException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import uk.me.parabola.mkgmap.osmstyle.StyleFileLoader;
+
+/**
+ * A style file loader where all the files are held as strings within the loader itself.
+ *
+ * A file name and contents can be added with the {@link #addfile(String, String)} method, or by passing an
+ * array to the constructor of name,content pairs.
+ *
+ * Used for testing.
+ *
+ * @author Steve Ratcliffe
+ */
+public class StringStyleFileLoader extends StyleFileLoader {
+ private final Map<String, String> files = new HashMap<String, String>();
+
+ /**
+ * Pass filename and file contents like so:
+ * <pre>
+ * new String[][] {
+ * {"lines", "highway=primary [0x2]"},
+ * {"points", "amenity=doctors [0x88]"},
+ * ...
+ * }
+ * </pre>
+ * @param files An array of filename, content pairs.
+ */
+ public StringStyleFileLoader(String[][] files) {
+ for (String[] nameContents : files)
+ addfile(nameContents[0], nameContents[1]);
+ }
+
+ public void addfile(String name, String contents) {
+ files.put(name, contents);
+ }
+
+ /**
+ * Open a file within the style. Creates a StringReader with the contents corresponding
+ * to the given filename. If the filename does not exist in the files array, then a FileNotFoundException
+ * is thrown as it would be in a regular style.
+ *
+ * @param filename The name of the file in the style.
+ * @return A StringReader with the contents of the file.
+ * @throws FileNotFoundException If the file name is not found in the files array.
+ */
+ public Reader open(String filename) throws FileNotFoundException {
+ String contents = files.get(filename);
+ if (contents == null)
+ throw new FileNotFoundException("No such file " + filename);
+ return new StringReader(contents);
+ }
+
+ public void close() {
+ // Nothing to do
+ }
+
+ /**
+ * List the filenames in the style.
+ * For completeness, we probably won't use this.
+ */
+ public String[] list() {
+ Set<String> strings = files.keySet();
+ return strings.toArray(new String[strings.size()]);
+ }
+}
diff --git a/test/func/lib/TestDataSource.java b/test/func/lib/TestDataSource.java
new file mode 100644
index 0000000..74047f2
--- /dev/null
+++ b/test/func/lib/TestDataSource.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2008 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 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.
+ */
+/* Create date: 21-Feb-2009 */
+package func.lib;
+
+import java.util.List;
+
+import uk.me.parabola.mkgmap.general.MapDataSource;
+import uk.me.parabola.mkgmap.general.MapPoint;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapShape;
+import uk.me.parabola.mkgmap.general.RoadNetwork;
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.trergn.Overview;
+
+/**
+ * A map source that allows us to create a map to specification without
+ * having a .osm file.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TestDataSource implements MapDataSource {
+ public Area getBounds() {
+ return null;
+ }
+
+ public List<MapPoint> getPoints() {
+ return null;
+ }
+
+ public List<MapLine> getLines() {
+ return null;
+ }
+
+ public List<MapShape> getShapes() {
+ return null;
+ }
+
+ public RoadNetwork getRoadNetwork() {
+ return null;
+ }
+
+ public List<Overview> getOverviews() {
+ return null;
+ }
+}
diff --git a/test/func/lib/TestUtils.java b/test/func/lib/TestUtils.java
new file mode 100644
index 0000000..ecf141f
--- /dev/null
+++ b/test/func/lib/TestUtils.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2008 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: 10-Jan-2009
+ */
+package func.lib;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.mkgmap.general.LevelInfo;
+import uk.me.parabola.mkgmap.main.Main;
+import uk.me.parabola.mkgmap.osmstyle.RuleFileReader;
+import uk.me.parabola.mkgmap.osmstyle.RuleSet;
+import uk.me.parabola.mkgmap.osmstyle.StyleFileLoader;
+import uk.me.parabola.mkgmap.reader.osm.FeatureKind;
+
+import static org.junit.Assert.*;
+
+/**
+ * Useful routines to use during the functional tests.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TestUtils {
+ private static final List<String> files = new ArrayList<String>();
+ private static final Deque<Closeable> open = new ArrayDeque<Closeable>();
+
+ static {
+ files.add(Args.DEF_MAP_FILENAME);
+ files.add(Args.DEF_MAP_FILENAME2);
+ files.add(Args.DEF_GMAPSUPP_FILENAME);
+ files.add(Args.DEF_TDB_FILENAME);
+
+ Runnable r = new Runnable() {
+ public void run() {
+ deleteOutputFiles();
+ }
+ };
+ Thread t = new Thread(r);
+ Runtime.getRuntime().addShutdownHook(t);
+ }
+
+ /**
+ * Delete output files that were created by the tests.
+ * Used to clean up before/after a test.
+ */
+ public static void deleteOutputFiles() {
+ for (String fname : files) {
+ File f = new File(fname);
+
+ if (f.exists())
+ assertTrue("delete existing file: " + f.getName(), f.delete());
+ }
+ }
+
+ public static void closeFiles() {
+ while (!open.isEmpty())
+ Utils.closeFile(open.remove());
+ }
+
+ public static void registerFile(String ... names) {
+ Collections.addAll(files, names);
+ }
+
+ public static void registerFile(Closeable... files) {
+ Collections.addAll(open, files);
+ }
+
+ /**
+ * Run with a single argument. The standard arguments are added first.
+ * @param arg The argument.
+ */
+ public static Outputs run(String arg) {
+ return run(new String[] {arg});
+ }
+
+ /**
+ * Run with the given args. Some standard arguments are added first.
+ *
+ * To run without the standard args, use runRaw().
+ * @param in The arguments to use.
+ */
+ public static Outputs run(String ... in) {
+ List<String> args = new ArrayList<String>(Arrays.asList(in));
+ args.add(0, Args.TEST_STYLE_ARG);
+
+ OutputStream outsink = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(outsink);
+
+ OutputStream errsink = new ByteArrayOutputStream();
+ PrintStream err = new PrintStream(errsink);
+
+ PrintStream origout = System.out;
+ PrintStream origerr = System.err;
+
+ try {
+ System.setOut(out);
+ System.setErr(err);
+ Main.main(args.toArray(new String[args.size()]));
+ } finally {
+ out.close();
+ err.close();
+ System.setOut(origout);
+ System.setErr(origerr);
+ }
+
+ return new Outputs(outsink.toString(), errsink.toString());
+ }
+
+ /**
+ * Create a rule set out of a string. The string is processed
+ * as if it were in a file and the levels spec had been set.
+ */
+ public static RuleSet makeRuleSet(String in) {
+ StringStyleFileLoader loader = new StringStyleFileLoader(new String[][] {
+ {"lines", in}
+ });
+
+ return makeRuleSet(loader);
+ }
+
+ /**
+ * Make a rule set from the "lines" file of the given StyleFileLoader.
+ *
+ * @param loader This will be used to load the file 'lines'. If that file includes any other file, then it
+ * should accessible from the loader too.
+ *
+ * @return A rule set for lines.
+ */
+ public static RuleSet makeRuleSet(StyleFileLoader loader) {
+ RuleSet rs = new RuleSet();
+ RuleFileReader rr = new RuleFileReader(FeatureKind.POLYLINE, LevelInfo.createFromString("0:24 1:20 2:18 3:16 4:14"),
+ rs, false, null);
+ try {
+ rr.load(loader, "lines");
+ } catch (FileNotFoundException e) {
+ throw new AssertionError("Failed to open file: lines");
+ }
+ return rs;
+ }
+
+}
diff --git a/test/func/package.html b/test/func/package.html
new file mode 100644
index 0000000..25d4567
--- /dev/null
+++ b/test/func/package.html
@@ -0,0 +1,5 @@
+<body>
+<h3>Functional tests</h3>
+<p>Functional tests that make complete runs of mkgmap and examine the
+resultant files in some way.</p>
+</body>
\ No newline at end of file
diff --git a/test/func/read/ImgReadTest.java b/test/func/read/ImgReadTest.java
new file mode 100644
index 0000000..e7aff34
--- /dev/null
+++ b/test/func/read/ImgReadTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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 func.read;
+
+import java.io.FileNotFoundException;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.map.MapReader;
+import uk.me.parabola.imgfmt.app.net.RoadDef;
+
+import func.lib.Args;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+public class ImgReadTest {
+
+ @Test
+ public void testNet() throws FileNotFoundException {
+ MapReader mr = new MapReader(Utils.joinPath(Args.TEST_RESOURCE_IMG, Args.DEF_MAP_FILENAME3));
+ List<RoadDef> roads = mr.getRoads();
+
+ assertEquals("number of roads", 1355, roads.size());
+ }
+}
diff --git a/test/func/route/SimpleRouteTest.java b/test/func/route/SimpleRouteTest.java
new file mode 100644
index 0000000..35db3d2
--- /dev/null
+++ b/test/func/route/SimpleRouteTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2008 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 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.
+ */
+/* Create date: 16-Feb-2009 */
+package func.route;
+
+import java.io.FileNotFoundException;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.fs.DirectoryEntry;
+import uk.me.parabola.imgfmt.fs.FileSystem;
+import uk.me.parabola.mkgmap.main.Main;
+
+import func.Base;
+import func.lib.Args;
+import func.lib.RangeMatcher;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class SimpleRouteTest extends Base {
+
+ /**
+ * Simple test to ensure that nothing has changed. Of course
+ * if the output should have changed, then this will have to be altered
+ * to match.
+ */
+ @Test
+ public void testSize() throws FileNotFoundException {
+ Main.main(new String[]{
+ Args.TEST_STYLE_ARG,
+ "--route",
+ Args.TEST_RESOURCE_OSM + "uk-test-1.osm.gz",
+ Args.TEST_RESOURCE_MP + "test1.mp"
+ });
+
+ FileSystem fs = openFs(Args.DEF_MAP_ID + ".img");
+ assertNotNull("file exists", fs);
+
+ List<DirectoryEntry> entries = fs.list();
+ int count = 0;
+ for (DirectoryEntry ent : entries) {
+ String ext = ent.getExt();
+
+ int size = ent.getSize();
+ if (ext.equals("RGN")) {
+ count++;
+ System.out.println("RGN size " + size);
+ assertThat("RGN size", size, new RangeMatcher(130140));
+ } else if (ext.equals("TRE")) {
+ count++;
+ System.out.println("TRE size " + size);
+ // Size varies depending on svn modified status
+ assertThat("TRE size", size, new RangeMatcher(1478, 2));
+ } else if (ext.equals("LBL")) {
+ count++;
+ assertEquals("LBL size", 28730, size);
+ } else if (ext.equals("NET")) {
+ count++;
+ assertEquals("NET size", 66804, size);
+ } else if (ext.equals("NOD")) {
+ count++;
+ assertEquals("NOD size", 186800, size);
+ }
+ }
+ assertTrue("enough checks run", count == 5);
+
+ fs = openFs(Args.DEF_MAP_FILENAME2);
+ assertNotNull("file exists", fs);
+
+ entries = fs.list();
+ count = 0;
+ for (DirectoryEntry ent : entries) {
+ String ext = ent.getExt();
+
+ int size = ent.getSize();
+ if (ext.equals("RGN")) {
+ count++;
+ System.out.println("RGN size " + size);
+ assertThat("RGN size", size, new RangeMatcher(2780));
+ } else if (ext.equals("TRE")) {
+ count++;
+ System.out.println("TRE size " + size);
+ // Size varies depending on svn modified status
+ assertThat("TRE size", size, new RangeMatcher(769, 2));
+ } else if (ext.equals("LBL")) {
+ count++;
+ assertEquals("LBL size", 985, size);
+ } else if (ext.equals("NET")) {
+ count++;
+ assertEquals("NET size", 1280, size);
+ } else if (ext.equals("NOD")) {
+ count++;
+ assertEquals("NOD size", 3114, size);
+ }
+ }
+ assertTrue("enough checks run", count == 5);
+ }
+}
diff --git a/test/func/sources/TestSourceTest.java b/test/func/sources/TestSourceTest.java
new file mode 100644
index 0000000..14db6cf
--- /dev/null
+++ b/test/func/sources/TestSourceTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008 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: 11-Jan-2009
+ */
+package func.sources;
+
+import uk.me.parabola.mkgmap.main.Main;
+
+import func.Base;
+import org.junit.Test;
+
+/**
+ * For the test data sources.
+ *
+ * @author Steve Ratcliffe
+ */
+public class TestSourceTest extends Base {
+ /**
+ * The test map that includes all elements.
+ */
+ @Test
+ public void testAllElements() {
+ checkNoStdFile();
+ Main.main(new String[]{
+ "test-map:all-elements"
+ });
+ checkStdFile();
+ }
+
+ /**
+ * The test map that includes all kinds of points.
+ */
+ @Test
+ public void testAllPoints() {
+ Main.main(new String[]{
+ "test-map:test-points"
+ });
+ checkStdFile();
+ }
+}
diff --git a/test/func/style/ScriptedStyleTest.java b/test/func/style/ScriptedStyleTest.java
new file mode 100644
index 0000000..4915011
--- /dev/null
+++ b/test/func/style/ScriptedStyleTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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 func.style;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import uk.me.parabola.mkgmap.main.StyleTester;
+
+import func.lib.TestUtils;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * A set of tests written as files, using the StyleTester.
+ */
+public class ScriptedStyleTest {
+ private OutputStream output;
+
+ /**
+ * This is to check that the tests are working. Run a test that fails
+ * on purpose to check that we can detect this.
+ */
+ @Test
+ public void failureTest() {
+ TestUtils.registerFile("styletester.style");
+ StyleTester.runSimpleTest("test/resources/rules/fails-on-purpose.fail");
+ String result = output.toString();
+ assertTrue("failure check", result.contains("ERROR"));
+ }
+
+ /**
+ * This is really a whole bunch of tests as we find test files in a
+ * directory and run each one in turn.
+ */
+ @Test
+ public void testAllRuleFiles() throws IOException {
+ File d = new File("test/resources/rules/");
+ assertTrue(d.isDirectory());
+
+ // Only run files ending in .test
+ FilenameFilter filter = new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ if (name.endsWith(".test"))
+ return true;
+ return false;
+ }
+ };
+
+ int count = 0;
+ File[] files = d.listFiles(filter);
+ for (File file : files) {
+ setup();
+ String name = file.getCanonicalPath();
+ StyleTester.runSimpleTest(name);
+ String result = output.toString();
+
+ // Make sure that the result does not contain an error
+ if (result.contains("ERROR")) {
+ System.out.println(result);
+ assertFalse(name, true);
+ }
+
+ // make sure that the output was reasonable (and not 'cannot open
+ // file', for example).
+ assertTrue(name, result.contains("WAY 1:"));
+
+ count++;
+ }
+
+ // Check that some tests were run (ie. it will fail if you just delete
+ // them all).
+ assertTrue("tests run", count >= 3);
+ }
+
+ @Before
+ public void setup() {
+ output = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(output);
+ StyleTester.setOut(ps);
+
+ // Make sure that there is a given result set
+ StyleTester.forceUseOfGiven(true);
+ }
+}
diff --git a/test/main/NumberRangeTest.java b/test/main/NumberRangeTest.java
new file mode 100644
index 0000000..3685fe5
--- /dev/null
+++ b/test/main/NumberRangeTest.java
@@ -0,0 +1,133 @@
+/*
+ * File: NumberRangeTest.java
+ *
+ * Copyright (C) 2012 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 or
+ * version 3 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: 14 Dec 2012
+ */
+
+package main;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+import uk.me.parabola.imgfmt.app.BitReader;
+import uk.me.parabola.imgfmt.app.BitWriter;
+import uk.me.parabola.imgfmt.app.net.NumberPreparer;
+import uk.me.parabola.imgfmt.app.net.Numbers;
+import uk.me.parabola.log.Logger;
+
+import func.lib.NumberReader;
+
+/**
+ *
+ * @author Steve Ratcliffe
+ */
+public class NumberRangeTest {
+
+ static protected Logger log = Logger.getLogger(NumberRangeTest.class);
+
+ private int bytesUsed;
+
+ public void testRandom() {
+ Random rand = new Random(8866028);
+
+ for (int iter = 0; iter < 1000000; iter++) {
+ List<String> sl = new ArrayList<String>();
+ for (int i = 0; i < 20; i++) {
+ String n;
+ do {
+ String r1 = getRange(rand);
+ String r2 = getRange(rand);
+
+ n = String.format("%d,%s,%s", i, r1, r2);
+ } while (i == 0 && n.contains("N,-1,-1,N"));
+
+ sl.add(n);
+ if (rand.nextInt(3) > 1)
+ break;
+ }
+
+ if ((iter % 500000) == 0)
+ System.out.println("Done " + iter);
+
+ run(sl.toArray(new String[sl.size()]));
+ }
+ System.out.println("bytes used: " + bytesUsed);
+ }
+
+ private void run(String[] strings) {
+ List<Numbers> numbers = new ArrayList<Numbers>();
+ for (String s : strings) {
+ Numbers n = new Numbers(s);
+ n.setRnodNumber(n.getNodeNumber());
+ numbers.add(n);
+ }
+
+ NumberPreparer np = new NumberPreparer(numbers);
+ BitWriter bitWriter = np.fetchBitStream();
+ bytesUsed += bitWriter.getLength();
+
+ // Now read it back in
+ byte[] bytes = new byte[bitWriter.getLength()];
+ System.arraycopy(bitWriter.getBytes(), 0, bytes, 0, bytes.length);
+ NumberReader nr = new NumberReader(new BitReader(bytes));
+
+ nr.setNumberOfNodes(numbers.size());
+ List<Numbers> list = nr.readNumbers(np.getSwapped());
+
+ // Have to fix up the node numbers
+ for (Numbers n : list) {
+ n.setNodeNumber(n.getRnodNumber());
+ }
+
+ // Test that they are the same.
+ String orig = numbers.toString();
+ String calculated = list.toString();
+
+ if (!orig.equals(calculated)) {
+ System.out.printf("Fail: expecting: %s\n Got: %s\n", orig, calculated);
+ }
+ }
+
+ private String getRange(Random rand) {
+ char style = "NEEEOOOBB".charAt(rand.nextInt(9));
+ //if (style == 'N') style = 'B';
+ int max = 10;
+ int r = rand.nextInt(20);
+ if (r > 19) max = 200;
+ if (r > 17) max = 30;
+
+ int start = rand.nextInt(max)+1;
+ int end = rand.nextInt(max)+1;
+ if (style == 'O') {
+ start |= 1;
+ end |= 1;
+ } else if (style == 'E') {
+ start++; end++;
+ start &= ~1;
+ end &= ~1;
+ } else if (style == 'N') {
+ start = end = -1;
+ }
+ return String.format("%c,%d,%d", style, start, end);
+ }
+
+ public static void main(String[] args) {
+ (new NumberRangeTest()).testRandom();
+ }
+}
+
diff --git a/test/resources/chars/ascii/row00.trans b/test/resources/chars/ascii/row00.trans
new file mode 100644
index 0000000..9400813
--- /dev/null
+++ b/test/resources/chars/ascii/row00.trans
@@ -0,0 +1,121 @@
+
+# This is the transliteration table for the latin language into ascii
+# (characters above U+0080).
+#
+# I've not included symbols that are not likely to be included in the names
+# of streets on maps, they can always be filled in if need be
+#
+
+# The first points are control characters.
+# U+0080 Â # latin character Â
+# etc...
+
+# U+00a0 # latin character Â
+
+U+00a1 i # latin character ¡
+U+00a2 c # latin character ¢
+U+00a3 # # latin character £
+U+00a4 $ # latin character ¤
+U+00a5 YEN # latin character ¥
+U+00a6 | # latin character ¦
+
+# U+00a7 ? # latin character §
+
+U+00a8 " # latin character ¨
+U+00a9 (C) # latin character ©
+
+# U+00aa ? # latin character ª
+
+U+00ab << # latin character «
+
+# U+00ac ? # latin character ¬
+# U+00ad ? # latin character Â
+
+U+00ae (R) # latin character ®
+
+# U+00af ? # latin character ¯
+# U+00b0 ? # latin character °
+# U+00b1 ? # latin character ±
+# U+00b2 ? # latin character ²
+# U+00b3 ? # latin character ³
+# U+00b4 ? # latin character ´
+# U+00b5 ? # latin character µ
+# U+00b6 ? # latin character ¶
+# U+00b7 ? # latin character ·
+# U+00b8 ? # latin character ¸
+# U+00b9 ? # latin character ¹
+# U+00ba ? # latin character º
+
+U+00bb >> # latin character »
+
+# U+00bc ? # latin character ¼
+# U+00bd ? # latin character ½
+# U+00be ? # latin character ¾
+# U+00bf ? # latin character ¿
+
+U+00c0 A # latin character Ã
+U+00c1 A # latin character Ã
+U+00c2 A # latin character Ã
+U+00c3 A # latin character Ã
+U+00c4 A # latin character Ã
+U+00c5 A # latin character Ã
+U+00c6 AE # latin character Ã
+U+00c7 C # latin character Ã
+U+00c8 E # latin character Ã
+U+00c9 E # latin character Ã
+U+00ca E # latin character Ã
+U+00cb E # latin character Ã
+U+00cc I # latin character Ã
+U+00cd I # latin character Ã
+U+00ce I # latin character Ã
+U+00cf I # latin character Ã
+U+00d0 D # latin character Ã
+U+00d1 N # latin character Ã
+U+00d2 O # latin character Ã
+U+00d3 O # latin character Ã
+U+00d4 O # latin character Ã
+U+00d5 O # latin character Ã
+U+00d6 O # latin character Ã
+U+00d7 x # latin character Ã
+U+00d8 O # latin character Ã
+U+00d9 U # latin character Ã
+U+00da U # latin character Ã
+U+00db U # latin character Ã
+U+00dc U # latin character Ã
+U+00dd Y # latin character Ã
+U+00de th # latin character Ã
+U+00df ss # latin character Ã
+U+00e0 a # latin character Ã
+U+00e1 a # latin character á
+U+00e2 a # latin character â
+U+00e3 a # latin character ã
+U+00e4 a # latin character ä
+U+00e5 a # latin character å
+U+00e6 ae # latin character æ
+U+00e7 c # latin character ç
+U+00e8 e # latin character è
+U+00e9 e # latin character é
+U+00ea e # latin character ê
+U+00eb e # latin character ë
+U+00ec i # latin character ì
+U+00ed i # latin character Ã
+U+00ee i # latin character î
+U+00ef i # latin character ï
+U+00f0 d # latin character ð
+U+00f1 n # latin character ñ
+U+00f2 o # latin character ò
+U+00f3 o # latin character ó
+U+00f4 o # latin character ô
+U+00f5 o # latin character õ
+U+00f6 o # latin character ö
+
+# U+00f7 ? # latin character ÷
+# U+00f8 ? # latin character ø
+
+U+00f9 u # latin character ù
+U+00fa u # latin character ú
+U+00fb u # latin character û
+U+00fc u # latin character ü
+U+00fd y # latin character ý
+U+00fe TH # latin character þ
+U+00ff y # latin character ÿ
diff --git a/test/resources/chars/ascii/row01.trans b/test/resources/chars/ascii/row01.trans
new file mode 100644
index 0000000..7ffca2c
--- /dev/null
+++ b/test/resources/chars/ascii/row01.trans
@@ -0,0 +1,134 @@
+
+#
+# This is the transliteration table for the latin 2 characters
+# that start at unicode U+0100 into ascii.
+#
+
+U+0100 A # latin character Ä
+U+0101 a # latin character Ä
+U+0102 A # latin character Ä
+U+0103 a # latin character Ä
+U+0104 A # latin character Ä
+U+0105 a # latin character Ä
+U+0106 C # latin character Ä
+U+0107 c # latin character Ä
+U+0108 C # latin character Ä
+U+0109 c # latin character Ä
+U+010a C # latin character Ä
+U+010b c # latin character Ä
+U+010c C # latin character Ä
+U+010d c # latin character Ä
+U+010e D # latin character Ä
+U+010f d # latin character Ä
+U+0110 D # latin character Ä
+U+0111 d # latin character Ä
+U+0112 E # latin character Ä
+U+0113 e # latin character Ä
+U+0114 E # latin character Ä
+U+0115 e # latin character Ä
+U+0116 E # latin character Ä
+U+0117 e # latin character Ä
+U+0118 E # latin character Ä
+U+0119 e # latin character Ä
+U+011a E # latin character Ä
+U+011b e # latin character Ä
+U+011c G # latin character Ä
+U+011d g # latin character Ä
+U+011e G # latin character Ä
+U+011f g # latin character Ä
+U+0120 G # latin character Ä
+U+0121 g # latin character Ä¡
+U+0122 G # latin character Ģ
+U+0123 g # latin character ģ
+U+0124 H # latin character Ĥ
+U+0125 h # latin character ĥ
+U+0126 H # latin character Ħ
+U+0127 h # latin character ħ
+U+0128 I # latin character Ĩ
+U+0129 i # latin character Ä©
+U+012a I # latin character Ī
+U+012b i # latin character Ä«
+U+012c I # latin character Ĭ
+U+012d i # latin character Ä
+U+012e I # latin character Ä®
+U+012f i # latin character į
+U+0130 I # latin character Ä°
+U+0131 i # latin character ı
+U+0132 IJ # latin character IJ
+U+0133 ij # latin character ij
+U+0134 J # latin character Ä´
+U+0135 j # latin character ĵ
+U+0136 K # latin character Ķ
+U+0137 k # latin character Ä·
+U+0138 k # latin character ĸ
+U+0139 L # latin character Ĺ
+U+013a l # latin character ĺ
+U+013b L # latin character Ä»
+U+013c l # latin character ļ
+U+013d L # latin character Ľ
+U+013e l # latin character ľ
+U+013f L # latin character Ä¿
+U+0140 l # latin character Å
+U+0141 L # latin character Å
+U+0142 l # latin character Å
+U+0143 N # latin character Å
+U+0144 n # latin character Å
+U+0145 N # latin character Å
+U+0146 n # latin character Å
+U+0147 N # latin character Å
+U+0148 n # latin character Å
+U+0149 n # latin character Å
+U+014a N # latin character Å
+U+014b n # latin character Å
+U+014c O # latin character Å
+U+014d o # latin character Å
+U+014e O # latin character Å
+U+014f o # latin character Å
+U+0150 O # latin character Å
+U+0151 o # latin character Å
+U+0152 OE # latin character Å
+U+0153 oe # latin character Å
+U+0154 R # latin character Å
+U+0155 r # latin character Å
+U+0156 R # latin character Å
+U+0157 r # latin character Å
+U+0158 R # latin character Å
+U+0159 r # latin character Å
+U+015a S # latin character Å
+U+015b s # latin character Å
+U+015c S # latin character Å
+U+015d s # latin character Å
+U+015e S # latin character Å
+U+015f s # latin character Å
+U+0160 S # latin character Å
+U+0161 s # latin character Å¡
+U+0162 T # latin character Ţ
+U+0163 t # latin character ţ
+U+0164 T # latin character Ť
+U+0165 t # latin character ť
+U+0166 T # latin character Ŧ
+U+0167 t # latin character ŧ
+U+0168 U # latin character Ũ
+U+0169 u # latin character Å©
+U+016a U # latin character Ū
+U+016b u # latin character Å«
+U+016c U # latin character Ŭ
+U+016d u # latin character Å
+U+016e U # latin character Å®
+U+016f u # latin character ů
+U+0170 U # latin character Å°
+U+0171 u # latin character ű
+U+0172 U # latin character Ų
+U+0173 u # latin character ų
+U+0174 W # latin character Å´
+U+0175 w # latin character ŵ
+U+0176 Y # latin character Ŷ
+U+0177 y # latin character Å·
+U+0178 Y # latin character Ÿ
+U+0179 Z # latin character Ź
+U+017a z # latin character ź
+U+017b Z # latin character Å»
+U+017c z # latin character ż
+U+017d Z # latin character Ž
+U+017e z # latin character ž
+U+017f f # latin character Å¿
diff --git a/test/resources/chars/ascii/row02.trans b/test/resources/chars/ascii/row02.trans
new file mode 100644
index 0000000..3803d41
--- /dev/null
+++ b/test/resources/chars/ascii/row02.trans
@@ -0,0 +1,269 @@
+
+# This is table for transliterating characters in the range
+# from U+0200 to U+02ff
+#
+# The first column is the unicode character and the second
+# column is the transliteration of that character to ascii characters.
+# One or more characters can be used, for example for a character æ which
+# is a combined a and e you could write 'ae' (without the quotes) as the
+# transliteration.
+#
+# Any line can be deleted and will default to a '?' character
+#
+
+U+0200 A # character È
+U+0201 a # character È
+U+0202 A # character È
+U+0203 a # character È
+U+0204 E # character È
+U+0205 e # character È
+U+0206 E # character È
+U+0207 e # character È
+U+0208 I # character È
+U+0209 I # character È
+U+020a I # character È
+U+020b i # character È
+U+020c I # character È
+U+020d o # character È
+U+020e O # character È
+U+020f o # character È
+U+0210 R # character È
+U+0211 r # character È
+U+0212 R # character È
+U+0213 r # character È
+U+0214 U # character È
+U+0215 u # character È
+U+0216 U # character È
+U+0217 u # character È
+U+0218 S # character È
+U+0219 s # character È
+U+021a T # character È
+U+021b t # character È
+U+021c ? # character È
+U+021d ? # character È
+U+021e H # character È
+U+021f h # character È
+U+0220 ? # character È
+U+0221 ? # character È¡
+U+0222 ? # character Ȣ
+U+0223 ? # character ȣ
+U+0224 Z # character Ȥ
+U+0225 z # character ȥ
+U+0226 A # character Ȧ
+U+0227 a # character ȧ
+U+0228 E # character Ȩ
+U+0229 e # character È©
+U+022a O # character Ȫ
+U+022b o # character È«
+U+022c O # character Ȭ
+U+022d o # character È
+U+022e O # character È®
+U+022f o # character ȯ
+U+0230 O # character È°
+U+0231 o # character ȱ
+U+0232 Y # character Ȳ
+U+0233 y # character ȳ
+U+0234 ? # character È´
+U+0235 ? # character ȵ
+U+0236 ? # character ȶ
+U+0237 ? # character È·
+U+0238 ? # character ȸ
+U+0239 ? # character ȹ
+U+023a ? # character Ⱥ
+U+023b ? # character È»
+U+023c ? # character ȼ
+U+023d ? # character Ƚ
+U+023e ? # character Ⱦ
+U+023f ? # character È¿
+U+0240 ? # character É
+U+0241 ? # character É
+U+0242 ? # character É
+U+0243 ? # character É
+U+0244 ? # character É
+U+0245 ? # character É
+U+0246 ? # character É
+U+0247 ? # character É
+U+0248 ? # character É
+U+0249 ? # character É
+U+024a ? # character É
+U+024b ? # character É
+U+024c ? # character É
+U+024d ? # character É
+U+024e ? # character É
+U+024f ? # character É
+U+0250 ? # character É
+U+0251 ? # character É
+U+0252 ? # character É
+U+0253 ? # character É
+U+0254 ? # character É
+U+0255 ? # character É
+U+0256 ? # character É
+U+0257 ? # character É
+U+0258 ? # character É
+U+0259 ? # character É
+U+025a ? # character É
+U+025b ? # character É
+U+025c ? # character É
+U+025d ? # character É
+U+025e ? # character É
+U+025f ? # character É
+U+0260 g # character É
+U+0261 g # character É¡
+U+0262 G # character ɢ
+U+0263 ? # character ɣ
+U+0264 ? # character ɤ
+U+0265 ? # character ɥ
+U+0266 ? # character ɦ
+U+0267 ? # character ɧ
+U+0268 ? # character ɨ
+U+0269 ? # character É©
+U+026a ? # character ɪ
+U+026b l # character É«
+U+026c l # character ɬ
+U+026d ? # character É
+U+026e ? # character É®
+U+026f ? # character ɯ
+U+0270 ? # character É°
+U+0271 ? # character ɱ
+U+0272 ? # character ɲ
+U+0273 ? # character ɳ
+U+0274 ? # character É´
+U+0275 ? # character ɵ
+U+0276 oe # character ɶ
+U+0277 ? # character É·
+U+0278 ? # character ɸ
+U+0279 ? # character ɹ
+U+027a ? # character ɺ
+U+027b ? # character É»
+U+027c ? # character ɼ
+U+027d ? # character ɽ
+U+027e ? # character ɾ
+U+027f ? # character É¿
+U+0280 ? # character Ê
+U+0281 ? # character Ê
+U+0282 ? # character Ê
+U+0283 ? # character Ê
+U+0284 ? # character Ê
+U+0285 ? # character Ê
+U+0286 ? # character Ê
+U+0287 ? # character Ê
+U+0288 ? # character Ê
+U+0289 ? # character Ê
+U+028a ? # character Ê
+U+028b ? # character Ê
+U+028c ? # character Ê
+U+028d ? # character Ê
+U+028e ? # character Ê
+U+028f ? # character Ê
+U+0290 ? # character Ê
+U+0291 ? # character Ê
+U+0292 ? # character Ê
+U+0293 ? # character Ê
+U+0294 ? # character Ê
+U+0295 ? # character Ê
+U+0296 ? # character Ê
+U+0297 ? # character Ê
+U+0298 ? # character Ê
+U+0299 ? # character Ê
+U+029a ? # character Ê
+U+029b ? # character Ê
+U+029c H # character Ê
+U+029d ? # character Ê
+U+029e ? # character Ê
+U+029f ? # character Ê
+U+02a0 ? # character Ê
+U+02a1 ? # character Ê¡
+U+02a2 ? # character ʢ
+U+02a3 ? # character ʣ
+U+02a4 ? # character ʤ
+U+02a5 ? # character ʥ
+U+02a6 ? # character ʦ
+U+02a7 ? # character ʧ
+U+02a8 ? # character ʨ
+U+02a9 ? # character Ê©
+U+02aa ? # character ʪ
+U+02ab ? # character Ê«
+U+02ac ? # character ʬ
+U+02ad ? # character Ê
+U+02ae ? # character Ê®
+U+02af ? # character ʯ
+U+02b0 ? # character Ê°
+U+02b1 ? # character ʱ
+U+02b2 ? # character ʲ
+U+02b3 ? # character ʳ
+U+02b4 ? # character Ê´
+U+02b5 ? # character ʵ
+U+02b6 ? # character ʶ
+U+02b7 ? # character Ê·
+U+02b8 ? # character ʸ
+U+02b9 ? # character ʹ
+U+02ba ? # character ʺ
+U+02bb ? # character Ê»
+U+02bc ? # character ʼ
+U+02bd ? # character ʽ
+U+02be ? # character ʾ
+U+02bf ? # character Ê¿
+U+02c0 ? # character Ë
+U+02c1 ? # character Ë
+U+02c2 ? # character Ë
+U+02c3 ? # character Ë
+U+02c4 ? # character Ë
+U+02c5 ? # character Ë
+U+02c6 ? # character Ë
+U+02c7 ? # character Ë
+U+02c8 ? # character Ë
+U+02c9 ? # character Ë
+U+02ca ? # character Ë
+U+02cb ? # character Ë
+U+02cc ? # character Ë
+U+02cd ? # character Ë
+U+02ce ? # character Ë
+U+02cf ? # character Ë
+U+02d0 ? # character Ë
+U+02d1 ? # character Ë
+U+02d2 ? # character Ë
+U+02d3 ? # character Ë
+U+02d4 ? # character Ë
+U+02d5 ? # character Ë
+U+02d6 ? # character Ë
+U+02d7 ? # character Ë
+U+02d8 ? # character Ë
+U+02d9 ? # character Ë
+U+02da ? # character Ë
+U+02db ? # character Ë
+U+02dc ? # character Ë
+U+02dd ? # character Ë
+U+02de ? # character Ë
+U+02df ? # character Ë
+U+02e0 ? # character Ë
+U+02e1 ? # character Ë¡
+U+02e2 ? # character ˢ
+U+02e3 ? # character ˣ
+U+02e4 ? # character ˤ
+U+02e5 ? # character ˥
+U+02e6 ? # character ˦
+U+02e7 ? # character ˧
+U+02e8 ? # character ˨
+U+02e9 ? # character Ë©
+U+02ea ? # character ˪
+U+02eb ? # character Ë«
+U+02ec ? # character ˬ
+U+02ed ? # character Ë
+U+02ee ? # character Ë®
+U+02ef ? # character ˯
+U+02f0 ? # character Ë°
+U+02f1 ? # character ˱
+U+02f2 ? # character ˲
+U+02f3 ? # character ˳
+U+02f4 ? # character Ë´
+U+02f5 ? # character ˵
+U+02f6 ? # character ˶
+U+02f7 ? # character Ë·
+U+02f8 ? # character ˸
+U+02f9 ? # character ˹
+U+02fa ? # character ˺
+U+02fb ? # character Ë»
+U+02fc ? # character ˼
+U+02fd ? # character ˽
+U+02fe ? # character ˾
+U+02ff ? # character Ë¿
diff --git a/test/resources/chars/ascii/row03.trans b/test/resources/chars/ascii/row03.trans
new file mode 100644
index 0000000..eecfef5
--- /dev/null
+++ b/test/resources/chars/ascii/row03.trans
@@ -0,0 +1,269 @@
+
+# This is table for transliterating characters in the range
+# from U+0300 to U+03ff
+#
+# The first column is the unicode character and the second
+# column is the transliteration of that character to ascii characters.
+# One or more characters can be used, for example for a character æ which
+# is a combined a and e you could write 'ae' (without the quotes) as the
+# transliteration.
+#
+# Any line can be deleted and will default to a '?' character
+#
+
+U+0300 ? # character Ì
+U+0301 ? # character Ì
+U+0302 ? # character Ì
+U+0303 ? # character Ì
+U+0304 ? # character Ì
+U+0305 ? # character Ì
+U+0306 ? # character Ì
+U+0307 ? # character Ì
+U+0308 ? # character Ì
+U+0309 ? # character Ì
+U+030a ? # character Ì
+U+030b ? # character Ì
+U+030c ? # character Ì
+U+030d ? # character Ì
+U+030e ? # character Ì
+U+030f ? # character Ì
+U+0310 ? # character Ì
+U+0311 ? # character Ì
+U+0312 ? # character Ì
+U+0313 ? # character Ì
+U+0314 ? # character Ì
+U+0315 ? # character Ì
+U+0316 ? # character Ì
+U+0317 ? # character Ì
+U+0318 ? # character Ì
+U+0319 ? # character Ì
+U+031a ? # character Ì
+U+031b ? # character Ì
+U+031c ? # character Ì
+U+031d ? # character Ì
+U+031e ? # character Ì
+U+031f ? # character Ì
+U+0320 ? # character Ì
+U+0321 ? # character Ì¡
+U+0322 ? # character ̢
+U+0323 ? # character ̣
+U+0324 ? # character ̤
+U+0325 ? # character ̥
+U+0326 ? # character ̦
+U+0327 ? # character ̧
+U+0328 ? # character ̨
+U+0329 ? # character Ì©
+U+032a ? # character ̪
+U+032b ? # character Ì«
+U+032c ? # character ̬
+U+032d ? # character Ì
+U+032e ? # character Ì®
+U+032f ? # character ̯
+U+0330 ? # character Ì°
+U+0331 ? # character ̱
+U+0332 ? # character ̲
+U+0333 ? # character ̳
+U+0334 ? # character Ì´
+U+0335 ? # character ̵
+U+0336 ? # character ̶
+U+0337 ? # character Ì·
+U+0338 ? # character ̸
+U+0339 ? # character ̹
+U+033a ? # character ̺
+U+033b ? # character Ì»
+U+033c ? # character ̼
+U+033d ? # character ̽
+U+033e ? # character ̾
+U+033f ? # character Ì¿
+U+0340 ? # character Í
+U+0341 ? # character Í
+U+0342 ? # character Í
+U+0343 ? # character Í
+U+0344 ? # character Í
+U+0345 ? # character Í
+U+0346 ? # character Í
+U+0347 ? # character Í
+U+0348 ? # character Í
+U+0349 ? # character Í
+U+034a ? # character Í
+U+034b ? # character Í
+U+034c ? # character Í
+U+034d ? # character Í
+U+034e ? # character Í
+U+034f ? # character Í
+U+0350 ? # character Í
+U+0351 ? # character Í
+U+0352 ? # character Í
+U+0353 ? # character Í
+U+0354 ? # character Í
+U+0355 ? # character Í
+U+0356 ? # character Í
+U+0357 ? # character Í
+U+0358 ? # character Í
+U+0359 ? # character Í
+U+035a ? # character Í
+U+035b ? # character Í
+U+035c ? # character Í
+U+035d ? # character Í
+U+035e ? # character Í
+U+035f ? # character Í
+U+0360 ? # character Í
+U+0361 ? # character Í¡
+U+0362 ? # character ͢
+U+0363 ? # character ͣ
+U+0364 ? # character ͤ
+U+0365 ? # character ͥ
+U+0366 ? # character ͦ
+U+0367 ? # character ͧ
+U+0368 ? # character ͨ
+U+0369 ? # character Í©
+U+036a ? # character ͪ
+U+036b ? # character Í«
+U+036c ? # character ͬ
+U+036d ? # character Í
+U+036e ? # character Í®
+U+036f ? # character ͯ
+U+0370 ? # character Í°
+U+0371 ? # character ͱ
+U+0372 ? # character Ͳ
+U+0373 ? # character ͳ
+U+0374 ' # character Í´
+U+0375 , # character ͵
+U+0376 ? # character Ͷ
+U+0377 ? # character Í·
+U+0378 ? # character ͸
+U+0379 ? # character ͹
+U+037a ? # character ͺ
+U+037b ? # character Í»
+U+037c ? # character ͼ
+U+037d ? # character ͽ
+U+037e ? # character ;
+U+037f ? # character Í¿
+U+0380 ? # character Î
+U+0381 ? # character Î
+U+0382 ? # character Î
+U+0383 ? # character Î
+U+0384 ? # character Î
+U+0385 ? # character Î
+U+0386 A # character Î
+U+0387 ; # character Î
+U+0388 E # character Î
+U+0389 E # character Î
+U+038a I # character Î
+U+038b ? # character Î
+U+038c O # character Î
+U+038d ? # character Î
+U+038e U # character Î
+U+038f O # character Î
+U+0390 I # character Î
+U+0391 A # character Î
+U+0392 B # character Î
+U+0393 G # character Î
+U+0394 D # character Î
+U+0395 E # character Î
+U+0396 Z # character Î
+U+0397 E # character Î
+U+0398 Th # character Î
+U+0399 I # character Î
+U+039a K # character Î
+U+039b L # character Î
+U+039c M # character Î
+U+039d N # character Î
+U+039e Ks # character Î
+U+039f O # character Î
+U+03a0 P # character Î
+U+03a1 R # character Ρ
+U+03a2 ? # character ΢
+U+03a3 S # character Σ
+U+03a4 T # character Τ
+U+03a5 U # character Υ
+U+03a6 Ph # character Φ
+U+03a7 Kh # character Χ
+U+03a8 Ps # character Ψ
+U+03a9 O # character Ω
+U+03aa I # character Ϊ
+U+03ab U # character Ϋ
+U+03ac a # character ά
+U+03ad e # character Î
+U+03ae e # character ή
+U+03af i # character ί
+U+03b0 u # character ΰ
+U+03b1 a # character α
+U+03b2 b # character β
+U+03b3 g # character γ
+U+03b4 d # character δ
+U+03b5 e # character ε
+U+03b6 z # character ζ
+U+03b7 e # character η
+U+03b8 th # character θ
+U+03b9 i # character ι
+U+03ba k # character κ
+U+03bb l # character λ
+U+03bc m # character μ
+U+03bd n # character ν
+U+03be x # character ξ
+U+03bf o # character ο
+U+03c0 p # character Ï
+U+03c1 r # character Ï
+U+03c2 s # character Ï
+U+03c3 s # character Ï
+U+03c4 t # character Ï
+U+03c5 u # character Ï
+U+03c6 ph # character Ï
+U+03c7 kh # character Ï
+U+03c8 ps # character Ï
+U+03c9 o # character Ï
+U+03ca i # character Ï
+U+03cb u # character Ï
+U+03cc o # character Ï
+U+03cd u # character Ï
+U+03ce o # character Ï
+U+03cf ? # character Ï
+U+03d0 b # character Ï
+U+03d1 th # character Ï
+U+03d2 U # character Ï
+U+03d3 U # character Ï
+U+03d4 U # character Ï
+U+03d5 ph # character Ï
+U+03d6 p # character Ï
+U+03d7 & # character Ï
+U+03d8 ? # character Ï
+U+03d9 ? # character Ï
+U+03da St # character Ï
+U+03db st # character Ï
+U+03dc W # character Ï
+U+03dd w # character Ï
+U+03de Q # character Ï
+U+03df q # character Ï
+U+03e0 Sp # character Ï
+U+03e1 sp # character Ï¡
+U+03e2 Sh # character Ϣ
+U+03e3 sh # character ϣ
+U+03e4 F # character Ϥ
+U+03e5 f # character ϥ
+U+03e6 Kh # character Ϧ
+U+03e7 kh # character ϧ
+U+03e8 H # character Ϩ
+U+03e9 h # character Ï©
+U+03ea G # character Ϫ
+U+03eb g # character Ï«
+U+03ec CH # character Ϭ
+U+03ed ch # character Ï
+U+03ee Ti # character Ï®
+U+03ef ti # character ϯ
+U+03f0 k # character Ï°
+U+03f1 r # character ϱ
+U+03f2 c # character ϲ
+U+03f3 j # character ϳ
+U+03f4 ? # character Ï´
+U+03f5 ? # character ϵ
+U+03f6 ? # character ϶
+U+03f7 ? # character Ï·
+U+03f8 ? # character ϸ
+U+03f9 ? # character Ϲ
+U+03fa ? # character Ϻ
+U+03fb ? # character Ï»
+U+03fc ? # character ϼ
+U+03fd ? # character Ͻ
+U+03fe ? # character Ͼ
+U+03ff ? # character Ï¿
diff --git a/test/resources/chars/ascii/row04.trans b/test/resources/chars/ascii/row04.trans
new file mode 100644
index 0000000..60a5722
--- /dev/null
+++ b/test/resources/chars/ascii/row04.trans
@@ -0,0 +1,269 @@
+
+# This is table for transliterating characters in the range
+# from U+0400 to U+04ff
+#
+# The first column is the unicode character and the second
+# column is the transliteration of that character to ascii characters.
+# One or more characters can be used, for example for a character æ which
+# is a combined a and e you could write 'ae' (without the quotes) as the
+# transliteration.
+#
+# Any line can be deleted and will default to a '?' character
+#
+
+U+0400 ? # character Ð
+U+0401 Yo # character Ð
+U+0402 ? # character Ð
+U+0403 ? # character Ð
+U+0404 ? # character Ð
+U+0405 ? # character Ð
+U+0406 ? # character Ð
+U+0407 ? # character Ð
+U+0408 ? # character Ð
+U+0409 ? # character Ð
+U+040a ? # character Ð
+U+040b ? # character Ð
+U+040c ? # character Ð
+U+040d ? # character Ð
+U+040e ? # character Ð
+U+040f ? # character Ð
+U+0410 A # character Ð
+U+0411 B # character Ð
+U+0412 V # character Ð
+U+0413 G # character Ð
+U+0414 D # character Ð
+U+0415 E # character Ð
+U+0416 Zh # character Ð
+U+0417 Z # character Ð
+U+0418 I # character Ð
+U+0419 Y # character Ð
+U+041a K # character Ð
+U+041b L # character Ð
+U+041c M # character Ð
+U+041d N # character Ð
+U+041e O # character Ð
+U+041f P # character Ð
+U+0420 R # character Ð
+U+0421 S # character С
+U+0422 T # character Т
+U+0423 U # character У
+U+0424 F # character Ф
+U+0425 Kh # character Х
+U+0426 Ts # character Ц
+U+0427 Ch # character Ч
+U+0428 Sh # character Ш
+U+0429 Shch # character Щ
+U+042a ' # character Ъ
+U+042b Y # character Ы
+U+042c ' # character Ь
+U+042d E # character Ð
+U+042e Yu # character Ю
+U+042f Ya # character Я
+U+0430 a # character а
+U+0431 b # character б
+U+0432 v # character в
+U+0433 g # character г
+U+0434 d # character д
+U+0435 e # character е
+U+0436 zh # character ж
+U+0437 z # character з
+U+0438 i # character и
+U+0439 y # character й
+U+043a k # character к
+U+043b l # character л
+U+043c m # character м
+U+043d n # character н
+U+043e o # character о
+U+043f p # character п
+U+0440 r # character Ñ
+U+0441 s # character Ñ
+U+0442 t # character Ñ
+U+0443 u # character Ñ
+U+0444 f # character Ñ
+U+0445 kh # character Ñ
+U+0446 ts # character Ñ
+U+0447 ch # character Ñ
+U+0448 sh # character Ñ
+U+0449 shch # character Ñ
+U+044a ' # character Ñ
+U+044b y # character Ñ
+U+044c ' # character Ñ
+U+044d e # character Ñ
+U+044e yu # character Ñ
+U+044f ya # character Ñ
+U+0450 ? # character Ñ
+U+0451 yo # character Ñ
+U+0452 ? # character Ñ
+U+0453 ? # character Ñ
+U+0454 ? # character Ñ
+U+0455 ? # character Ñ
+U+0456 ? # character Ñ
+U+0457 ? # character Ñ
+U+0458 ? # character Ñ
+U+0459 ? # character Ñ
+U+045a ? # character Ñ
+U+045b ? # character Ñ
+U+045c ? # character Ñ
+U+045d ? # character Ñ
+U+045e ? # character Ñ
+U+045f ? # character Ñ
+U+0460 ? # character Ñ
+U+0461 ? # character Ñ¡
+U+0462 ? # character Ѣ
+U+0463 ? # character ѣ
+U+0464 ? # character Ѥ
+U+0465 ? # character ѥ
+U+0466 ? # character Ѧ
+U+0467 ? # character ѧ
+U+0468 ? # character Ѩ
+U+0469 ? # character Ñ©
+U+046a ? # character Ѫ
+U+046b ? # character Ñ«
+U+046c ? # character Ѭ
+U+046d ? # character Ñ
+U+046e ? # character Ñ®
+U+046f ? # character ѯ
+U+0470 ? # character Ñ°
+U+0471 ? # character ѱ
+U+0472 ? # character Ѳ
+U+0473 ? # character ѳ
+U+0474 ? # character Ñ´
+U+0475 ? # character ѵ
+U+0476 ? # character Ѷ
+U+0477 ? # character Ñ·
+U+0478 ? # character Ѹ
+U+0479 ? # character ѹ
+U+047a ? # character Ѻ
+U+047b ? # character Ñ»
+U+047c ? # character Ѽ
+U+047d ? # character ѽ
+U+047e ? # character Ѿ
+U+047f ? # character Ñ¿
+U+0480 ? # character Ò
+U+0481 ? # character Ò
+U+0482 ? # character Ò
+U+0483 ? # character Ò
+U+0484 ? # character Ò
+U+0485 ? # character Ò
+U+0486 ? # character Ò
+U+0487 ? # character Ò
+U+0488 ? # character Ò
+U+0489 ? # character Ò
+U+048a ? # character Ò
+U+048b ? # character Ò
+U+048c ? # character Ò
+U+048d ? # character Ò
+U+048e ? # character Ò
+U+048f ? # character Ò
+U+0490 ? # character Ò
+U+0491 ? # character Ò
+U+0492 ? # character Ò
+U+0493 ? # character Ò
+U+0494 ? # character Ò
+U+0495 ? # character Ò
+U+0496 ? # character Ò
+U+0497 ? # character Ò
+U+0498 ? # character Ò
+U+0499 ? # character Ò
+U+049a ? # character Ò
+U+049b ? # character Ò
+U+049c ? # character Ò
+U+049d ? # character Ò
+U+049e ? # character Ò
+U+049f ? # character Ò
+U+04a0 ? # character Ò
+U+04a1 ? # character Ò¡
+U+04a2 ? # character Ò¢
+U+04a3 ? # character Ò£
+U+04a4 ? # character Ò¤
+U+04a5 ? # character Ò¥
+U+04a6 ? # character Ò¦
+U+04a7 ? # character Ò§
+U+04a8 ? # character Ò¨
+U+04a9 ? # character Ò©
+U+04aa ? # character Òª
+U+04ab ? # character Ò«
+U+04ac ? # character Ò¬
+U+04ad ? # character Ò
+U+04ae ? # character Ò®
+U+04af ? # character Ò¯
+U+04b0 ? # character Ò°
+U+04b1 ? # character Ò±
+U+04b2 ? # character Ò²
+U+04b3 ? # character Ò³
+U+04b4 ? # character Ò´
+U+04b5 ? # character Òµ
+U+04b6 ? # character Ò¶
+U+04b7 ? # character Ò·
+U+04b8 ? # character Ò¸
+U+04b9 ? # character Ò¹
+U+04ba ? # character Òº
+U+04bb ? # character Ò»
+U+04bc ? # character Ò¼
+U+04bd ? # character Ò½
+U+04be ? # character Ò¾
+U+04bf ? # character Ò¿
+U+04c0 ? # character Ó
+U+04c1 ? # character Ó
+U+04c2 ? # character Ó
+U+04c3 ? # character Ó
+U+04c4 ? # character Ó
+U+04c5 ? # character Ó
+U+04c6 ? # character Ó
+U+04c7 ? # character Ó
+U+04c8 ? # character Ó
+U+04c9 ? # character Ó
+U+04ca ? # character Ó
+U+04cb ? # character Ó
+U+04cc ? # character Ó
+U+04cd ? # character Ó
+U+04ce ? # character Ó
+U+04cf ? # character Ó
+U+04d0 ? # character Ó
+U+04d1 ? # character Ó
+U+04d2 ? # character Ó
+U+04d3 ? # character Ó
+U+04d4 ? # character Ó
+U+04d5 ? # character Ó
+U+04d6 ? # character Ó
+U+04d7 ? # character Ó
+U+04d8 ? # character Ó
+U+04d9 ? # character Ó
+U+04da ? # character Ó
+U+04db ? # character Ó
+U+04dc ? # character Ó
+U+04dd ? # character Ó
+U+04de ? # character Ó
+U+04df ? # character Ó
+U+04e0 ? # character Ó
+U+04e1 ? # character Ó¡
+U+04e2 ? # character Ó¢
+U+04e3 ? # character Ó£
+U+04e4 ? # character Ó¤
+U+04e5 ? # character Ó¥
+U+04e6 ? # character Ó¦
+U+04e7 ? # character Ó§
+U+04e8 ? # character Ó¨
+U+04e9 ? # character Ó©
+U+04ea ? # character Óª
+U+04eb ? # character Ó«
+U+04ec ? # character Ó¬
+U+04ed ? # character Ó
+U+04ee ? # character Ó®
+U+04ef ? # character Ó¯
+U+04f0 ? # character Ó°
+U+04f1 ? # character Ó±
+U+04f2 ? # character Ó²
+U+04f3 ? # character Ó³
+U+04f4 ? # character Ó´
+U+04f5 ? # character Óµ
+U+04f6 ? # character Ó¶
+U+04f7 ? # character Ó·
+U+04f8 ? # character Ó¸
+U+04f9 ? # character Ó¹
+U+04fa ? # character Óº
+U+04fb ? # character Ó»
+U+04fc ? # character Ó¼
+U+04fd ? # character Ó½
+U+04fe ? # character Ó¾
+U+04ff ? # character Ó¿
diff --git a/test/resources/chars/latin1/row04.trans b/test/resources/chars/latin1/row04.trans
new file mode 100644
index 0000000..051b5f3
--- /dev/null
+++ b/test/resources/chars/latin1/row04.trans
@@ -0,0 +1,4 @@
+
+# For testing overriding from the latin tables.
+U+0400 Ã # Character Ð
+U+0401 Ã # Character Ð
diff --git a/test/resources/in/README b/test/resources/in/README
new file mode 100644
index 0000000..1973eee
--- /dev/null
+++ b/test/resources/in/README
@@ -0,0 +1,7 @@
+
+The input files required for this directory are located at
+
+http://www.mkgmap.org.uk/testinput
+
+You can also set up a local cache of the files, see the target
+*obtain-test-input-files* in the build.xml file.
diff --git a/test/resources/rules/action-order.test b/test/resources/rules/action-order.test
new file mode 100644
index 0000000..c7f4426
--- /dev/null
+++ b/test/resources/rules/action-order.test
@@ -0,0 +1,24 @@
+WAY
+highway=path
+name=coutêaué
+name:translit=couteaue
+mtb:scale=1
+mtb:scale:uphill=4
+route=mtb
+route_name=up_the_hill
+
+#Following action rules:
+<<<lines>>>
+name:translit=* {set name='${name:translit}'}
+mtb:scale=1 & mtb:scale:uphill=4 {set name='${name} mtb14' | 'mtb14'}
+route_name=* {set name='${name} ${route_name}' | '${route_name}' }
+mtb:scale=* {set mkgmap:paved=no}
+
+highway=path & mkgmap:paved=no [0x7]
+highway=path [0x8]
+
+<finalize>
+name=* { name '${name}' }
+
+<<<results>>>
+WAY 1: Line 0x7, labels=[couteaue mtb14 up_the_hill, null, null, null], res=24-24 (1/1),(2/2),
diff --git a/test/resources/rules/actions-once-with-or.test b/test/resources/rules/actions-once-with-or.test
new file mode 100644
index 0000000..841b36d
--- /dev/null
+++ b/test/resources/rules/actions-once-with-or.test
@@ -0,0 +1,22 @@
+WAY
+A=1
+B=2
+C=3
+
+WAY 2
+C=3
+E=5
+
+<<<lines>>>
+( A=1 | B=2 | C=3 | D=4 | E=5)
+ { set name='${name}b' | '${A} ${B}' | '${C}' | '${E}'; }
+
+A=1 [0x1]
+E=5 [0x2]
+
+<finalize>
+name=* { name '${name}' }
+
+<<<results>>>
+WAY 1: Line 0x1, labels=[1 2, null, null, null], res=24-24 (1/1),(2/2),
+WAY 2: Line 0x2, labels=[3, null, null, null], res=24-24 (1/1),(2/2),
diff --git a/test/resources/rules/add-tag-and-match.test b/test/resources/rules/add-tag-and-match.test
new file mode 100644
index 0000000..ca90175
--- /dev/null
+++ b/test/resources/rules/add-tag-and-match.test
@@ -0,0 +1,19 @@
+
+# Test that tags that are added by an action work with =* in following
+# rules.
+
+Way
+name=Long Lane
+highway=residential
+
+<<<lines>>>
+highway=residential { add test=yes }
+
+test=* [0x1]
+highway=residential [0x2]
+
+<finalize>
+name=* { name '${name}' }
+
+<<<results>>>
+WAY 1: Line 0x1, labels=[Long Lane, null, null, null], res=24-24 (1/1),(2/2),
diff --git a/test/resources/rules/chain1.test b/test/resources/rules/chain1.test
new file mode 100644
index 0000000..0a8da42
--- /dev/null
+++ b/test/resources/rules/chain1.test
@@ -0,0 +1,14 @@
+# A simple test of the sort of thing that didn't work with the old
+# style engine.
+
+WAY
+highway=primary
+aa=5
+
+<<<lines>>>
+highway=* & aa=5 {set aa=6}
+highway=primary & aa=6 [0x1]
+highway=* & aa=6 [0x2]
+
+<<<results>>>
+WAY 1: Line 0x1, labels=[null, null, null, null], res=24-24 (1/1),(2/2),
diff --git a/test/resources/rules/chain2.test b/test/resources/rules/chain2.test
new file mode 100644
index 0000000..cab3033
--- /dev/null
+++ b/test/resources/rules/chain2.test
@@ -0,0 +1,20 @@
+#
+# Test setting the tag that was just matched.
+# Mixed in with a continue action.
+#
+
+WAY
+highway=primary
+
+<<<lines>>>
+highway = primary {set highway=secondary; }
+highway = secondary {set highway=tertiary; } [0x2 continue with_actions]
+highway = tertiary {set highway=footway; }
+
+highway=primary [0x1]
+highway=footway [0x7]
+
+<<<results>>>
+WAY 1: Line 0x2, labels=[null, null, null, null], res=24-24 (1/1),(2/2),
+WAY 1: Line 0x7, labels=[null, null, null, null], res=24-24 (1/1),(2/2),
+
diff --git a/test/resources/rules/continue.test b/test/resources/rules/continue.test
new file mode 100644
index 0000000..c2cceeb
--- /dev/null
+++ b/test/resources/rules/continue.test
@@ -0,0 +1,26 @@
+# Test of continue with and without with_actions.
+#
+
+WAY 1
+highway=primary
+abc=yes
+
+WAY 2
+highway=secondary
+abc=yes
+
+<<<lines>>>
+highway=primary & abc=yes { set oneway=reverse; } [0x1 road_class=1 continue]
+highway=primary [0x2 road_class=1]
+
+highway=secondary & abc=yes { set oneway=reverse; } [0x3 road_class=2 continue
+with_actions]
+highway=secondary [0x4 road_class=2]
+
+<<<results>>>
+WAY 1: Road 0x1, labels=[null, null, null, null], res=24-24 oneway (2/2),(1/1), road class=1 speed=0
+WAY 1: Road 0x2, labels=[null, null, null, null], res=24-24 (1/1),(2/2), road class=1 speed=0
+
+WAY 2: Road 0x3, labels=[null, null, null, null], res=24-24 oneway (2/2),(1/1), road class=2 speed=0
+WAY 2: Road 0x4, labels=[null, null, null, null], res=24-24 oneway (2/2),(1/1), road class=2 speed=0
+
diff --git a/test/resources/rules/fails-on-purpose.fail b/test/resources/rules/fails-on-purpose.fail
new file mode 100644
index 0000000..645d55e
--- /dev/null
+++ b/test/resources/rules/fails-on-purpose.fail
@@ -0,0 +1,12 @@
+
+# This test is meant to fail to check that the tester is working
+# The given results are incorrect.
+
+WAY
+highway=yes
+
+<<<lines>>>
+highway=yes [0x1]
+
+<<<results>>>
+WAY 1: Line 0x10, labels=[null, null, null, null], res=24-24 (1/1),(2/2),
diff --git a/test/resources/rules/get-tag.test b/test/resources/rules/get-tag.test
new file mode 100644
index 0000000..2a124b7
--- /dev/null
+++ b/test/resources/rules/get-tag.test
@@ -0,0 +1,104 @@
+
+WAY
+highway=primary
+maxspeed=60
+
+WAY 2
+highway=primary
+maxspeed:forward=30
+
+WAY 3
+highway=primary
+maxspeed:backward=20
+
+WAY 4
+highway=primary
+maxspeed=30
+maxspeed:forward=32
+
+WAY 5
+highway=primary
+maxspeed=30
+maxspeed:forward=28
+
+WAY 6
+highway=primary
+maxspeed=30
+maxspeed:backward=32
+
+WAY 7
+highway=primary
+maxspeed=30
+maxspeed:backward=28
+
+WAY 8
+highway=primary
+maxspeed=30
+maxspeed:forward=26
+maxspeed:backward=27
+
+WAY 9
+highway=primary
+maxspeed:forward=26
+maxspeed:backward=27
+
+WAY 10
+highway=secondary
+test=2
+test1=1
+test2=2
+name=fred
+
+WAY 11
+highway=secondary
+test=2
+name=fred
+
+WAY 12
+highway=secondary
+test=2
+test1=10
+name=fred
+
+WAY 14
+highway=secondary
+test3=3
+test1=1
+name=fred
+
+<<<lines>>>
+maxspeed:forward=* & maxspeed!=* { set maxspeed='${maxspeed:forward}' }
+$maxspeed:forward < $maxspeed { set maxspeed='${maxspeed:forward}' }
+maxspeed:backward=* & maxspeed!=* { set maxspeed='${maxspeed:backward}' }
+maxspeed:backward < $maxspeed { set maxspeed='${maxspeed:backward}' }
+
+highway=primary {name '${maxspeed}' } [0x1]
+
+
+test=test1 { name 'wrong' }
+test=test2 { name 'wrong' }
+test=$test1 { name 'wrong' }
+test=$test2 { name 'ok' }
+$test1 < $test2 { set ref=A2 }
+$test1 > 4 { set ref=A4 }
+test1=* & test3 > test1 { set ref=A99}
+highway=secondary [0x2]
+
+<finalize>
+name=* { name '${name}' }
+ref=* { addlabel '${ref}' }
+
+<<<results>>>
+WAY 1: Line 0x1, labels=[60, null, null, null], res=24-24 (1/1),(2/2),
+WAY 2: Line 0x1, labels=[30, null, null, null], res=24-24 (1/1),(2/2),
+WAY 3: Line 0x1, labels=[20, null, null, null], res=24-24 (1/1),(2/2),
+WAY 4: Line 0x1, labels=[30, null, null, null], res=24-24 (1/1),(2/2),
+WAY 5: Line 0x1, labels=[28, null, null, null], res=24-24 (1/1),(2/2),
+WAY 6: Line 0x1, labels=[30, null, null, null], res=24-24 (1/1),(2/2),
+WAY 7: Line 0x1, labels=[28, null, null, null], res=24-24 (1/1),(2/2),
+WAY 8: Line 0x1, labels=[26, null, null, null], res=24-24 (1/1),(2/2),
+WAY 9: Line 0x1, labels=[26, null, null, null], res=24-24 (1/1),(2/2),
+WAY 10: Line 0x2, labels=[ok, A2, null, null], res=24-24 (1/1),(2/2),
+WAY 11: Line 0x2, labels=[fred, null, null, null], res=24-24 (1/1),(2/2),
+WAY 12: Line 0x2, labels=[fred, A4, null, null], res=24-24 (1/1),(2/2),
+WAY 14: Line 0x2, labels=[fred, A99, null, null], res=24-24 (1/1),(2/2),
diff --git a/test/resources/rules/oneway.test b/test/resources/rules/oneway.test
new file mode 100644
index 0000000..8a99373
--- /dev/null
+++ b/test/resources/rules/oneway.test
@@ -0,0 +1,20 @@
+WAY
+highway=primary
+oneway=yes
+
+WAY 2
+highway=secondary
+oneway=reverse
+
+WAY 3
+highway=secondary
+oneway=-1
+
+<<<lines>>>
+highway=primary [0x2 road_class=2 road_speed=2]
+highway=secondary [0x3 road_class=2 road_speed=2]
+
+<<<results>>>
+WAY 1: Road 0x2, labels=[null, null, null, null], res=24-24 oneway (1/1),(2/2), road class=2 speed=2
+WAY 2: Road 0x3, labels=[null, null, null, null], res=24-24 oneway (2/2),(1/1), road class=2 speed=2
+WAY 3: Road 0x3, labels=[null, null, null, null], res=24-24 oneway (2/2),(1/1), road class=2 speed=2
diff --git a/test/resources/rules/or-list.test b/test/resources/rules/or-list.test
new file mode 100644
index 0000000..93fce5f
--- /dev/null
+++ b/test/resources/rules/or-list.test
@@ -0,0 +1,14 @@
+
+#
+# Test for an OR where the the second is the one that matches.
+#
+
+WAY 1
+B=1
+
+<<<lines>>>
+
+A=1 | B=1 | C=1 [0x1 resolution 24]
+
+<<<results>>>
+WAY 1: Line 0x1, labels=[null, null, null, null], res=24-24 (1/1),(2/2),
diff --git a/test/resources/rules/types-once-with-or.test b/test/resources/rules/types-once-with-or.test
new file mode 100644
index 0000000..35ec0e1
--- /dev/null
+++ b/test/resources/rules/types-once-with-or.test
@@ -0,0 +1,9 @@
+WAY
+mtb:scale=2
+mtb:scale:uphill=yes
+
+<<<lines>>>
+( mtb:scale=* | mtb:scale:uphill=* ) [0x1 continue]
+
+<<<results>>>
+WAY 1: Line 0x1, labels=[null, null, null, null], res=24-24 (1/1),(2/2),
diff --git a/test/resources/teststyles/a/info b/test/resources/teststyles/a/info
new file mode 100644
index 0000000..abde155
--- /dev/null
+++ b/test/resources/teststyles/a/info
@@ -0,0 +1,8 @@
+
+version: 1
+summary: Base style test a
+
+description {
+Base style for b.
+b and c are the base styles for d.
+}
diff --git a/test/resources/teststyles/a/lines b/test/resources/teststyles/a/lines
new file mode 100644
index 0000000..85eaf42
--- /dev/null
+++ b/test/resources/teststyles/a/lines
@@ -0,0 +1,12 @@
+
+a=a [0x1]
+
+override=yes [0x1]
+override=a [0x1]
+override=b [0x1]
+override=c [0x1]
+override=d [0x1]
+
+override=ab [0x1]
+override=ac [0x1]
+override=ad [0x1]
diff --git a/test/resources/teststyles/a/version b/test/resources/teststyles/a/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/test/resources/teststyles/a/version
@@ -0,0 +1 @@
+0
diff --git a/test/resources/teststyles/b/info b/test/resources/teststyles/b/info
new file mode 100644
index 0000000..ce5d457
--- /dev/null
+++ b/test/resources/teststyles/b/info
@@ -0,0 +1,4 @@
+
+summary: test style b
+
+base-style: a
diff --git a/test/resources/teststyles/b/lines b/test/resources/teststyles/b/lines
new file mode 100644
index 0000000..15ee025
--- /dev/null
+++ b/test/resources/teststyles/b/lines
@@ -0,0 +1,11 @@
+
+b=b [0x1]
+
+override=yes [0x2]
+override=b [0x2]
+override=c [0x2]
+override=d [0x2]
+
+override=ab [0x2]
+override=bc [0x2]
+override=bd [0x2]
diff --git a/test/resources/teststyles/b/version b/test/resources/teststyles/b/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/test/resources/teststyles/b/version
@@ -0,0 +1 @@
+0
diff --git a/test/resources/teststyles/c/info b/test/resources/teststyles/c/info
new file mode 100644
index 0000000..bac6c3f
--- /dev/null
+++ b/test/resources/teststyles/c/info
@@ -0,0 +1,2 @@
+
+summary: test style c
diff --git a/test/resources/teststyles/c/lines b/test/resources/teststyles/c/lines
new file mode 100644
index 0000000..cae3160
--- /dev/null
+++ b/test/resources/teststyles/c/lines
@@ -0,0 +1,10 @@
+
+c=c [0x1]
+
+override=yes [0x3]
+override=c [0x3]
+override=d [0x3]
+
+override=ac [0x3]
+override=bc [0x3]
+override=cd [0x3]
diff --git a/test/resources/teststyles/c/version b/test/resources/teststyles/c/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/test/resources/teststyles/c/version
@@ -0,0 +1 @@
+0
diff --git a/test/resources/teststyles/d/info b/test/resources/teststyles/d/info
new file mode 100644
index 0000000..c87b1e2
--- /dev/null
+++ b/test/resources/teststyles/d/info
@@ -0,0 +1,5 @@
+
+summary=test style d
+
+base-style: b
+base-style: c
diff --git a/test/resources/teststyles/d/lines b/test/resources/teststyles/d/lines
new file mode 100644
index 0000000..c696f99
--- /dev/null
+++ b/test/resources/teststyles/d/lines
@@ -0,0 +1,9 @@
+
+d=d [0x1]
+
+override=yes [0x4]
+override=d [0x4]
+
+override=ad [0x4]
+override=bd [0x4]
+override=cd [0x4]
diff --git a/test/resources/teststyles/d/version b/test/resources/teststyles/d/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/test/resources/teststyles/d/version
@@ -0,0 +1 @@
+0
diff --git a/test/resources/teststyles/derived/info b/test/resources/teststyles/derived/info
new file mode 100644
index 0000000..63617f2
--- /dev/null
+++ b/test/resources/teststyles/derived/info
@@ -0,0 +1,9 @@
+
+version: 2.2
+
+summary: A style based on simple
+
+base-style: simple
+
+description : testing derived styles.
+
diff --git a/test/resources/teststyles/derived/lines b/test/resources/teststyles/derived/lines
new file mode 100644
index 0000000..7c77765
--- /dev/null
+++ b/test/resources/teststyles/derived/lines
@@ -0,0 +1,9 @@
+
+# All types in this file should be 0x2x
+#
+# This is overridden in this file, all other rules
+# come from the base.
+overridden = xyz [0x22]
+
+#highway=other & derived=first [0x25]
+derived=first [0x25]
diff --git a/test/resources/teststyles/derived/version b/test/resources/teststyles/derived/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/test/resources/teststyles/derived/version
@@ -0,0 +1 @@
+0
diff --git a/test/resources/teststyles/empty/points b/test/resources/teststyles/empty/points
new file mode 100644
index 0000000..e69de29
diff --git a/test/resources/teststyles/empty/relations b/test/resources/teststyles/empty/relations
new file mode 100644
index 0000000..3a8e74a
--- /dev/null
+++ b/test/resources/teststyles/empty/relations
@@ -0,0 +1,4 @@
+
+#
+# Test for files that are empty (although maybe have comments ;)
+#
diff --git a/test/resources/teststyles/empty/version b/test/resources/teststyles/empty/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/test/resources/teststyles/empty/version
@@ -0,0 +1 @@
+0
diff --git a/test/resources/teststyles/finalize/info b/test/resources/teststyles/finalize/info
new file mode 100644
index 0000000..245e4c8
--- /dev/null
+++ b/test/resources/teststyles/finalize/info
@@ -0,0 +1,19 @@
+#
+# This file contains information about the style.
+# It is completely optional.
+#
+
+
+# A short one line description of the style
+#
+summary: A test style for finalize rules
+
+# Version of the style itself
+#
+version=1.0
+
+# A longer description of the style.
+description {
+A style to test if the finalize block is triggered by element type definitions in an
+expression rule and an action rule with element type definition.
+}
diff --git a/test/resources/teststyles/finalize/lines b/test/resources/teststyles/finalize/lines
new file mode 100644
index 0000000..636a52e
--- /dev/null
+++ b/test/resources/teststyles/finalize/lines
@@ -0,0 +1,19 @@
+
+# Expression rule must be matched by the finalize
+highway=residential [0x01 road_class=0 road_speed=0 resolution 22]
+
+# Action rules with element type definition must also run the finalize block
+highway=track { set road=yes } [0x01 road_class=0 road_speed=0 resolution 22]
+
+# The first two action rules should not trigger the finalize block
+highway=secondary { set road=yes }
+road=yes { delete road }
+# this triggers the finalize block but there is no matching rule
+highway=secondary [0x01 road_class=0 road_speed=0 resolution 22]
+
+highway=trunk { set road=yes } [0x01 road_class=0 road_speed=0 resolution 22 continue with_actions]
+highway=trunk & road=yes { delete road } [0x01 road_class=0 road_speed=0 resolution 22]
+
+<finalize>
+highway=residential { name 'OK' }
+road=yes { name 'OK' }
diff --git a/test/resources/teststyles/finalize/options b/test/resources/teststyles/finalize/options
new file mode 100644
index 0000000..1fa9aed
--- /dev/null
+++ b/test/resources/teststyles/finalize/options
@@ -0,0 +1,8 @@
+
+#
+# Style options.
+#
+
+# The levels specification for this style
+#
+levels = 0:24, 1:22, 2:20, 3:18, 4:16
diff --git a/test/resources/teststyles/finalize/version b/test/resources/teststyles/finalize/version
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/test/resources/teststyles/finalize/version
@@ -0,0 +1 @@
+1
diff --git a/test/resources/teststyles/main/info b/test/resources/teststyles/main/info
new file mode 100644
index 0000000..0d918ce
--- /dev/null
+++ b/test/resources/teststyles/main/info
@@ -0,0 +1,18 @@
+#
+# This file contains information about the style.
+# It is completely optional.
+#
+
+
+# A short one line description of the style
+#
+summary: The default test style
+
+# Version of the style itself
+#
+version=1.0
+
+# A longer description of the style.
+description {
+Used for many functional tests. It should not be changed at all ever.
+}
diff --git a/test/resources/teststyles/main/lines b/test/resources/teststyles/main/lines
new file mode 100644
index 0000000..a73fbfa
--- /dev/null
+++ b/test/resources/teststyles/main/lines
@@ -0,0 +1,54 @@
+aeroway=runway [0x27 resolution 20]
+boundary=administrative [0x1c resolution 18]
+boundary=national [0x1e resolution 17]
+boundary=political [0x1c resolution 17]
+
+# Contours take their name from the elevation setting.
+contour=elevation | contour_ext=elevation
+ { name '${ele|conv:m=>ft}'; }
+ [0x21 resolution 20]
+
+# Set highway names to include the reference if there is one
+highway=* {name '${name} (${ref})' | '${ref}' | '${name}' }
+highway=bridleway {set highway=bridleway} [0x16 road_class=0 road_speed=0 resolution 23]
+highway=byway [0x16 road_class=0 road_speed=0 resolution 23]
+highway=cycleway [0x16 road_class=0 road_speed=1 resolution 23]
+highway=footway [0x16 road_class=0 road_speed=0 resolution 23]
+highway=minor [0x06 road_class=1 road_speed=2 resolution 21]
+highway=motorway {add oneway = yes } [0x01 road_class=4 road_speed=6 resolution 12]
+highway=motorway_link [0x01 road_class=4 road_speed=3 resolution 16]
+highway=pedestrian [0x06 road_class=0 road_speed=0 resolution 22]
+highway=primary [0x02 road_class=3 road_speed=4 resolution 19]
+highway=primary_link [0x03 road_class=3 road_speed=3 resolution 19]
+highway=residential | highway=living_street [0x06 road_class=0 road_speed=2 resolution 21]
+highway=secondary [0x04 road_class=2 road_speed=3 resolution 20]
+highway=path [0x16 road_class=0 road_speed=0 resolution 20]
+highway=service [0x07 road_class=0 road_speed=1 resolution 22]
+highway=steps [0x16 road_class=0 road_speed=0 resolution 23]
+highway=tertiary [0x05 road_class=1 road_speed=3 resolution 20]
+highway=track [0x0a road_class=0 road_speed=1 resolution 21]
+highway=trunk [0x02 road_class=3 road_speed=5 resolution 16]
+highway=trunk_link [0x02 road_class=3 road_speed=3 resolution 16]
+highway=unclassified [0x06 road_class=1 road_speed=2 resolution 21]
+highway=unsurfaced [0x0a road_class=0 road_speed=1 resolution 21]
+
+# Mop up any unrecognised highway types
+highway=* [0x07 road_class=0 road_speed=1 resolution 22]
+
+natural=coastline [0x15 resolution 12]
+power=line [0x29 resolution 20]
+
+railway=light_rail [0x14 resolution 17]
+railway=rail [0x14 resolution 17]
+railway=subway [0x14 resolution 17]
+railway=tram [0x14 resolution 18]
+
+route=ferry [0x1a road_class=0 road_speed=1 resolution 18]
+
+waterway=canal [0x1f resolution 21]
+waterway=drain [0x1f resolution 22]
+waterway=river [0x1f resolution 18]
+waterway=stream [0x18 resolution 22]
+
+<finalize>
+name=* | ref=* {name '${name} (${ref})' | '${ref}' | '${name}' }
diff --git a/test/resources/teststyles/main/options b/test/resources/teststyles/main/options
new file mode 100644
index 0000000..1fa9aed
--- /dev/null
+++ b/test/resources/teststyles/main/options
@@ -0,0 +1,8 @@
+
+#
+# Style options.
+#
+
+# The levels specification for this style
+#
+levels = 0:24, 1:22, 2:20, 3:18, 4:16
diff --git a/test/resources/teststyles/main/points b/test/resources/teststyles/main/points
new file mode 100644
index 0000000..d4a9eac
--- /dev/null
+++ b/test/resources/teststyles/main/points
@@ -0,0 +1,86 @@
+aeroway=airport [0x5900 resolution 20]
+
+amenity=atm [0x2f06 resolution 21]
+amenity=bank [0x2f06 resolution 21]
+amenity=atm [0x2f06 resolution 21]
+amenity=biergarten [0x2d02 resolution 21]
+amenity=bus_station [0x2f08 resolution 21]
+amenity=cafe [0x2a0e resolution 21]
+amenity=car_wash [0x2f0e resolution 21]
+amenity=cinema [0x2d03 resolution 20]
+amenity=college [0x2c05 resolution 21]
+amenity=courthouse [0x3004 resolution 20]
+amenity=drinking_water [0x5000 resolution 23]
+amenity=fast_food [0x2a07 resolution 21]
+amenity=fire_station [0x3008 resolution 21]
+amenity=fuel [0x2f01 resolution 19]
+amenity=grave_yard [0x6403 resolution 21]
+amenity=hospital [0x3002 resolution 20]
+amenity=library [0x2c03 resolution 21]
+amenity=parking [0x2f0b resolution 21]
+amenity=pharmacy [0x2e05 resolution 20]
+amenity=place_of_worship [0x2c0b resolution 21]
+amenity=police [0x3001 resolution 21]
+amenity=post_office [0x2f05 resolution 20]
+amenity=pub [0x4600 resolution 20]
+amenity=public_building [0x3000 resolution 21]
+amenity=restaurant [0x2a00 resolution 20]
+amenity=school [0x2c05 resolution 20]
+amenity=supermarket [0x2e02 resolution 20]
+amenity=telephone [0x5100 resolution 21]
+amenity=theatre [0x2d01 resolution 21]
+amenity=toilets [0x4e00 resolution 21]
+amenity=townhall [0x3003 resolution 21]
+amenity=university [0x2c05 resolution 21]
+amenity=zoo [0x2c07 resolution 21]
+
+highway=bus_stop [0x2f08 resolution 21]
+
+historic=museum [0x2c02 resolution 20]
+historic=archaeological_site [0x2c02 resolution 21]
+
+leisure=golf_course [0x2d05 resolution 21]
+leisure=marina [0x4300 resolution 21]
+leisure=park [0x2c06 resolution 21]
+leisure=pitch [0x2c08 resolution 21]
+leisure=sports_centre [0x2d0a resolution 21]
+leisure=stadium [0x2c08 resolution 21]
+leisure=track [0x2c08 resolution 21]
+
+man_made=tower [0x6411 resolution 21]
+
+natural=beach [0x6604 resolution 21]
+natural=cliff [0x6607 resolution 21]
+natural=peak [0x6616 resolution 21]
+
+place=city [0x0400 resolution 17]
+place=hamlet [0x1100 resolution 20]
+place=suburb [0x0a00 resolution 20]
+place=town [0x0800 resolution 18]
+place=village [0x0b00 resolution 20]
+
+railway=halt [0x2f08 resolution 21]
+railway=station [0x2f08 resolution 20]
+railway=tram_stop [0x2f08 resolution 21]
+
+shop=bakers [0x2e02 resolution 20]
+shop=bakery [0x2e02 resolution 20]
+shop=butchers [0x2e00 resolution 20]
+shop=supermarket [0x2e02 resolution 20]
+
+sport=swimming [0x2d09 resolution 20]
+
+tourism=attraction [0x2c04 resolution 20]
+tourism=camp_site [0x2b03 resolution 20]
+tourism=caravan_site [0x2b03 resolution 20]
+tourism=hostel [0x2b02 resolution 20]
+tourism=hotel [0x2b01 resolution 20]
+tourism=information [0x4c00 resolution 20]
+tourism=motel [0x2b01 resolution 20]
+tourism=museum [0x2c02 resolution 20]
+tourism=picnic_site [0x4a00 resolution 20]
+tourism=theme_park [0x2c01 resolution 20]
+tourism=zoo [0x2c07 resolution 20]
+
+<finalize>
+name=* | ref=* {name '${name} (${ref})' | '${ref}' | '${name}' }
diff --git a/test/resources/teststyles/main/polygons b/test/resources/teststyles/main/polygons
new file mode 100644
index 0000000..4c3b73f
--- /dev/null
+++ b/test/resources/teststyles/main/polygons
@@ -0,0 +1,48 @@
+amenity=college [0x0a resolution 18]
+amenity=grave_yard [0x1a resolution 18]
+amenity=hospital [0x0b resolution 18]
+amenity=parking [0x05 resolution 21]
+amenity=school [0x0a resolution 20]
+amenity=supermarket [0x08 resolution 21]
+amenity=university [0x0a resolution 18]
+
+landuse=allotments [0x4e resolution 20]
+landuse=cemetary [0x1a resolution 18]
+landuse=cemetery [0x1a resolution 18]
+landuse=forest [0x50 resolution 18]
+landuse=industrial [0x0c resolution 18]
+landuse=reservoir [0x3f resolution 18]
+landuse=retail [0x08 resolution 20]
+landuse=village_green [0x17 resolution 20]
+
+leisure=common [0x17 resolution 20]
+leisure=garden [0x17 resolution 20]
+leisure=golf_course [0x18 resolution 20]
+leisure=marina [0x09 resolution 20]
+leisure=nature_reserve [0x16 resolution 18]
+leisure=park [0x17 resolution 20]
+leisure=pitch [0x19 resolution 20]
+leisure=playground [0x17 resolution 20]
+leisure=sports_center [0x19 resolution 20]
+leisure=stadium [0x19 resolution 19]
+leisure=track [0x19 resolution 18]
+leisure=water_park [0x09 resolution 18]
+
+military=airfield [0x04 resolution 18]
+military=barracks [0x04 resolution 18]
+military=danger_area [0x04 resolution 18]
+military=range [0x04 resolution 18]
+
+natural=glacier [0x4d resolution 16]
+natural=marsh [0x51 resolution 20]
+natural=mud [0x51 resolution 20]
+natural=scrub [0x4f resolution 20]
+natural=water [0x3c resolution 20]
+natural=wood [0x50 resolution 18]
+
+place=village [0x03 resolution 18]
+
+waterway=riverbank [0x46 resolution 20]
+
+<finalize>
+name=* | ref=* {name '${name} (${ref})' | '${ref}' | '${name}' }
diff --git a/test/resources/teststyles/main/relations b/test/resources/teststyles/main/relations
new file mode 100644
index 0000000..b2b2b11
--- /dev/null
+++ b/test/resources/teststyles/main/relations
@@ -0,0 +1,7 @@
+
+#
+# You can have rules for relations. Usually you will set tags on the
+# elements that make up the relation.
+#
+# eg. type=route route=bus { apply { set route=bus; add rn='${route_no}' ; }}
+#
diff --git a/test/resources/teststyles/main/version b/test/resources/teststyles/main/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/test/resources/teststyles/main/version
@@ -0,0 +1 @@
+0
diff --git a/test/resources/teststyles/simple/info b/test/resources/teststyles/simple/info
new file mode 100644
index 0000000..b6421b0
--- /dev/null
+++ b/test/resources/teststyles/simple/info
@@ -0,0 +1,8 @@
+
+version: 2.2
+
+summary: A simple test style with just one example of most things
+
+description {
+This style is used for testing.
+}
diff --git a/test/resources/teststyles/simple/lines b/test/resources/teststyles/simple/lines
new file mode 100644
index 0000000..7309e24
--- /dev/null
+++ b/test/resources/teststyles/simple/lines
@@ -0,0 +1,23 @@
+#
+# All types should normally be less than 0x20
+#
+
+highway=primary & x=y [0x2 ]
+highway = primary [0x3]
+
+x=z [0x4]
+
+highway=other {set is_a_road = yes; }
+
+# This should win
+is_a_road = yes [0x12]
+
+highway=other [0x8]
+
+
+# A test for overlays
+highway = overlay [0x142]
+
+# Test for overriding in derived styles
+overridden = xyz [0x2]
+
diff --git a/test/resources/teststyles/simple/options b/test/resources/teststyles/simple/options
new file mode 100644
index 0000000..2f87043
--- /dev/null
+++ b/test/resources/teststyles/simple/options
@@ -0,0 +1,5 @@
+
+levels {
+0:24
+1:20
+}
diff --git a/test/resources/teststyles/simple/overlays b/test/resources/teststyles/simple/overlays
new file mode 100644
index 0000000..1eabdcc
--- /dev/null
+++ b/test/resources/teststyles/simple/overlays
@@ -0,0 +1,2 @@
+
+0x142: 0x1, 0x2, 0x3
diff --git a/test/resources/teststyles/simple/version b/test/resources/teststyles/simple/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/test/resources/teststyles/simple/version
@@ -0,0 +1 @@
+0
diff --git a/test/resources/teststyles/waycombine/info b/test/resources/teststyles/waycombine/info
new file mode 100644
index 0000000..3ffb815
--- /dev/null
+++ b/test/resources/teststyles/waycombine/info
@@ -0,0 +1,20 @@
+#
+# This file contains information about the style.
+# It is completely optional.
+#
+
+
+# A short one line description of the style
+#
+summary: A test style for polygon/line conflicts
+
+# Version of the style itself
+#
+version=1.0
+
+# A longer description of the style.
+description {
+Contains a highway=pedestrian rule in bot polygon and line
+style sets. This test ensures that both are picked up
+and that one does not overwrite the other.
+}
diff --git a/test/resources/teststyles/waycombine/lines b/test/resources/teststyles/waycombine/lines
new file mode 100644
index 0000000..c26fea8
--- /dev/null
+++ b/test/resources/teststyles/waycombine/lines
@@ -0,0 +1,5 @@
+
+highway=pedestrian & area!=yes [0x06 road_class=0 road_speed=0 resolution 22]
+
+# This would be wrong for this test
+highway=* [0x07 ]
diff --git a/test/resources/teststyles/waycombine/options b/test/resources/teststyles/waycombine/options
new file mode 100644
index 0000000..1fa9aed
--- /dev/null
+++ b/test/resources/teststyles/waycombine/options
@@ -0,0 +1,8 @@
+
+#
+# Style options.
+#
+
+# The levels specification for this style
+#
+levels = 0:24, 1:22, 2:20, 3:18, 4:16
diff --git a/test/resources/teststyles/waycombine/polygons b/test/resources/teststyles/waycombine/polygons
new file mode 100644
index 0000000..eb8f751
--- /dev/null
+++ b/test/resources/teststyles/waycombine/polygons
@@ -0,0 +1,4 @@
+
+# We are going to test the case where area is not set
+# so this should not be seen.
+highway=pedestrian & area=yes [0x1]
diff --git a/test/resources/teststyles/waycombine/version b/test/resources/teststyles/waycombine/version
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/test/resources/teststyles/waycombine/version
@@ -0,0 +1 @@
+0
diff --git a/test/resources/typ/test.txt b/test/resources/typ/test.txt
new file mode 100644
index 0000000..d724d39
--- /dev/null
+++ b/test/resources/typ/test.txt
@@ -0,0 +1,147 @@
+
+[_id]
+FID=12
+ProductCode=1
+CodePage=1252
+[end]
+
+[_drawOrder]
+Type=0x1,1
+Type=0x10112,2
+Type=0x10113,2
+[end]
+
+[_polygon]
+Type=0x1
+String=0x4,Test
+String=0x5,Txxx
+FontStyle=NoLabel
+DaycustomColor=#110099
+NightcustomColor=#909911
+CustomColor=ignored
+ExtendedLabels=ignored
+Xpm="0 0 2 0"
+"* c #990099"
+" c #889988"
+[end]
+
+[_polygon]
+Type=0x2
+String=0x4,Test
+String=0x5,Txxx
+FontStyle=SmallFont
+Xpm="0 0 2 0"
+"* c #990099"
+" c None"
+[end]
+
+[_polygon]
+Type=0x3
+String=0x4,Test
+String=0x5,Txxx
+FontStyle=Large
+DaycustomColor=#110099
+NightcustomColor=#909911
+Xpm="32 32 4 1"
+"* c #990099"
+"! c None"
+"* c #909090"
+"% c #908090"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"******!!!!!!!!!!****************"
+"*********!!!!!!!%%%%%***********"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"******%%%%%%%%%*****************"
+"************%%%%%%%%%!!!********"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+"********************************"
+[end]
+
+[_line]
+Type=0x1
+String=0x4,Test
+LineWidth=2
+BorderWidth=1
+Xpm="0 0 2 0"
+"a c #909090"
+"2 c #898989"
+[end]
+
+[_line]
+Type=0x2
+String=0x4,Test
+LineWidth=2
+BorderWidth=1
+Xpm="32 2 2 1"
+"* c #909090"
+"! c #898989"
+"********************************"
+"***!!!!!!!!!!!!!!!!!!!!!!*******"
+[end]
+
+[_point]
+Type=0x10203
+String=0x4,Test
+DayXpm="5 6 4 2"
+"** c #909090"
+" c #898989"
+"!! c #198989"
+"$$ c #198989"
+"**********"
+"** ******"
+"** ** **"
+"**** ****"
+"**** ****"
+"**$$******"
+[end]
+
+[_point]
+Type=0x10203
+String=0x4,Test
+DayXpm="5 6 4 2"
+"** c #909090"
+" c #898989"
+"33 c #198989"
+"44 c none"
+"**********"
+"** ******"
+"** ** **"
+"**** ****"
+"**** **33"
+"********44"
+NightXpm="5 6 4 2"
+"** c #909090"
+" c #898989"
+"33 c #198989" baralpha=10
+"44 c #198989ee"
+"**********"
+"** ******"
+"** ** **"
+"**** ****"
+"**** ****"
+"**********"
+[end]
diff --git a/test/uk/me/parabola/imgfmt/app/BitReaderTest.java b/test/uk/me/parabola/imgfmt/app/BitReaderTest.java
new file mode 100644
index 0000000..6ab84c1
--- /dev/null
+++ b/test/uk/me/parabola/imgfmt/app/BitReaderTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 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: 30-Nov-2008
+ */
+package uk.me.parabola.imgfmt.app;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+public class BitReaderTest {
+
+ /**
+ * Very simple test that the bit reader is working.
+ */
+ @Test
+ public void testGetBits() {
+ // Add your code here
+ BitReader br = new BitReader(new byte[]{
+ (byte) 0xf1, 0x73, (byte) 0xc2, 0x5
+ });
+
+ assertTrue("first bit", br.get1());
+ assertEquals("five bits", 0x18, br.get(5));
+ assertEquals("four bits", 0xf, br.get(4));
+ assertEquals("sixteen bits", 0x709c, br.get(16));
+ }
+
+ @Test
+ public void testSpecialNegative() {
+ BitReader br = new BitReader(new byte[]{0x24, 0xb});
+
+ int s = br.sget2(3);
+ assertEquals(-12, s);
+ }
+
+ @Test
+ public void testSpecialPositive() {
+ BitReader br = new BitReader(new byte[]{(byte) 0xa4, 0});
+
+ int s = br.sget2(3);
+ assertEquals(8, s);
+ }
+}
diff --git a/test/uk/me/parabola/imgfmt/app/labelenc/CodeFunctionsTest.java b/test/uk/me/parabola/imgfmt/app/labelenc/CodeFunctionsTest.java
new file mode 100644
index 0000000..bdc4009
--- /dev/null
+++ b/test/uk/me/parabola/imgfmt/app/labelenc/CodeFunctionsTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.labelenc;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class CodeFunctionsTest {
+ /**
+ * Quick check of the ascii 6 bit format conversion.
+ */
+ @Test
+ public void testFormat6() {
+ CodeFunctions functions = CodeFunctions.createEncoderForLBL(6, 0);
+ assertEquals("code page", 0, functions.getCodepage());
+ assertEquals("encoding type", 6, functions.getEncodingType());
+ CharacterEncoder enc = functions.getEncoder();
+
+ EncodedText etext = enc.encodeText("hello world");
+ byte[] ctext = etext.getCtext();
+ int len = etext.getLength();
+
+ // This was determined from the behaviour of the existing code, and not
+ // from first principles.
+ assertEquals("encoded length", 9, len);
+ byte[] foo = {
+ 0x20, 0x53, 0xc, 0x3c, 0x5, 0xffffffcf, 0x48, 0xffffffc1, 0x3f,
+ };
+ assertArrayEquals("encoded text", foo, Arrays.copyOf(ctext, len));
+ }
+
+ @Test
+ public void testAscii() {
+ CodeFunctions f = CodeFunctions.createEncoderForLBL("ascii");
+ assertEquals("code page", 0, f.getCodepage());
+ assertEquals("encoding type", 6, f.getEncodingType());
+ }
+
+ /**
+ * Transliteration when going to ascii in format 6. This was originally
+ * the only place where transliteration was available.
+ */
+ @Test
+ public void testTransliterate6() {
+ CodeFunctions functions = CodeFunctions.createEncoderForLBL(6, 0);
+
+ CharacterEncoder encoder = functions.getEncoder();
+ Transliterator transliterator = new TableTransliterator("ascii");
+ EncodedText text = encoder.encodeText(transliterator.transliterate("KörnerstraÃe, VelkomezeÅÃÄská, Skólavörðustigur"));
+
+ CharacterDecoder decoder = functions.getDecoder();
+ byte[] ctext = text.getCtext();
+ for (int i = 0; i < text.getLength(); i++) {
+ decoder.addByte(ctext[i]);
+ }
+ decoder.addByte(0xff);
+ String result = decoder.getText().getText();
+ assertEquals("transliterated text", "KORNERSTRASSE, VELKOMEZERICSKA, SKOLAVORDUSTIGUR", result);
+ }
+
+ /**
+ * Transliteration when going to ascii in format 6. This was originally
+ * the only place where transliteration was available.
+ */
+ @Test
+ public void testTransliterateLatin() {
+ CodeFunctions functions = CodeFunctions.createEncoderForLBL("latin1");
+
+ CharacterEncoder encoder = functions.getEncoder();
+ Transliterator transliterator = new TableTransliterator("latin1");
+ EncodedText text = encoder.encodeText(transliterator.transliterate("KörnerstraÃe, VelkomezeÅÃÄská, Skólavörðustigur"));
+
+ CharacterDecoder decoder = functions.getDecoder();
+ byte[] ctext = text.getCtext();
+ for (int i = 0; i < text.getLength(); i++) {
+ decoder.addByte(ctext[i]);
+ }
+
+ String result = decoder.getText().getText();
+ assertEquals("transliterated text", "KörnerstraÃe, VelkomezerÃcská, Skólavörðustigur", result);
+ }
+
+ /**
+ * Backward compatibility test.
+ */
+ @Test
+ public void testLatin1() {
+ CodeFunctions functions = CodeFunctions.createEncoderForLBL("latin1");
+ assertEquals("code page", 1252, functions.getCodepage());
+ assertEquals("encoding type", 9, functions.getEncodingType());
+
+ StringBuilder sb = new StringBuilder();
+ for (char c = 1; c < 256; c++) {
+ sb.append(c);
+ }
+
+ CharacterEncoder encoder = functions.getEncoder();
+ EncodedText text = encoder.encodeText(sb.toString());
+
+ // This encoder appends a null byte.
+ assertEquals("length of encoded text", 256, text.getLength());
+
+ for (int i = 1; i < 256; i++) {
+ // The following characters do not display on my GPS. This covers
+ // the region where windows-1252 differs from iso 8859 so we don't
+ // really know which it is meant to be.
+ if (i >= 0x80 && i <= 0xbf)
+ continue;
+ assertEquals("character", i, text.getCtext()[i-1] & 0xff);
+ }
+ }
+}
diff --git a/test/uk/me/parabola/imgfmt/app/labelenc/TableTransliteratorTest.java b/test/uk/me/parabola/imgfmt/app/labelenc/TableTransliteratorTest.java
new file mode 100644
index 0000000..8799395
--- /dev/null
+++ b/test/uk/me/parabola/imgfmt/app/labelenc/TableTransliteratorTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2009.
+ *
+ * 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.imgfmt.app.labelenc;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class TableTransliteratorTest {
+
+ /**
+ * Basic test to ascii.
+ */
+ @Test
+ public void testToAscii() {
+ TableTransliterator tr = new TableTransliterator("ascii");
+
+ String s = tr.transliterate("aéÄsõ\u0446");
+ assertEquals("to ascii", "aecsots", s);
+ }
+
+ /**
+ * Quick check that the latin characters on input survive in the output
+ * when latin1 is requested.
+ */
+ @Test
+ public void testToLatin() {
+ TableTransliterator tr = new TableTransliterator("latin1");
+
+ String s = tr.transliterate("aéÄsõ\u0446");
+ assertEquals("to latin", "aécsõts", s);
+ }
+
+ /**
+ * Characters in the latin table override those in the ascii table, when
+ * it is requested.
+ */
+ @Test
+ public void testLatinOverride() {
+ TableTransliterator tr = new TableTransliterator("latin1");
+
+ String s = tr.transliterate("\u0401");
+ assertEquals("to latin with override", "Ã", s);
+ }
+
+ /**
+ * Not overridden by latin, when it is not requested.
+ */
+ @Test
+ public void testNotOverriden() {
+ TableTransliterator tr = new TableTransliterator("ascii");
+
+ String s = tr.transliterate("\u0401");
+ assertEquals("to latin with override", "Yo", s);
+ }
+}
diff --git a/test/uk/me/parabola/imgfmt/app/net/NumberPreparerTest.java b/test/uk/me/parabola/imgfmt/app/net/NumberPreparerTest.java
new file mode 100644
index 0000000..f373652
--- /dev/null
+++ b/test/uk/me/parabola/imgfmt/app/net/NumberPreparerTest.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2008 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 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.imgfmt.app.net;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.BitReader;
+import uk.me.parabola.imgfmt.app.BitWriter;
+
+import func.lib.NumberReader;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * There are multiple ways of representing the same set of numbers. So these tests will employ a number
+ * reader to parse the resulting bit stream and create a list of numberings that can be compared with
+ * the input ones.
+ */
+public class NumberPreparerTest {
+
+ @Test
+ public void testNumberConstructor() {
+ // A simple test with all numbers increasing.
+ String spec = "0,O,1,7,E,2,12";
+ Numbers n = new Numbers(spec);
+
+ assertEquals(spec, n.toString());
+ }
+
+ /**
+ * Just test that the test infrastructure is working with a known byte stream, this
+ * is testing the tests.
+ */
+ @Test
+ public void testKnownStream() {
+ byte[] buf = {0x41, 0x13, 0x27, 0x49, 0x60};
+ BitReader br = new BitReader(buf);
+ NumberReader nr = new NumberReader(br);
+ nr.setNumberOfNodes(1);
+ List<Numbers> numbers = nr.readNumbers(true);
+
+ assertEquals(1, numbers.size());
+ assertEquals("0,E,24,8,O,23,13", numbers.get(0).toString());
+ }
+
+ /**
+ * Simple test of numbers that increase on both sides.
+ */
+ @Test
+ public void testIncreasingNumbers() {
+ run("0,O,1,11,E,2,12");
+ }
+
+ @Test
+ public void testSwappedDefaultStyles() {
+ List<Numbers> numbers = createList(new String[]{"0,E,2,12,O,1,11"});
+ List<Numbers> output = writeAndRead(numbers);
+ assertEquals(numbers, output);
+ }
+
+ @Test
+ public void testIncreasingHighStarts() {
+ String[] tests = {
+ "0,O,1,5,E,2,6",
+ "0,O,3,7,E,4,8",
+ "0,O,91,99,E,92,98",
+ "0,O,1,15,E,4,8",
+ };
+
+ for (String t : tests) {
+ List<Numbers> numbers = createList(new String[]{t});
+ List<Numbers> output = writeAndRead(numbers);
+ assertEquals(numbers, output);
+ }
+ }
+
+ @Test
+ public void testSingleNumbers() {
+ runSeparate("0,O,7,7,E,8,8", "0,O,7,7,E,6,6");
+ }
+
+ @Test
+ public void testLargeDifferentStarts() {
+ runSeparate("0,O,91,103,E,2,8", "0,E,90,102,O,3,9");
+ }
+
+ @Test
+ public void testMultipleNodes() {
+ List<Numbers> numbers = createList(new String[]{
+ "0,O,1,9,E,2,12",
+ "1,O,11,17,E,14,20",
+ "2,O,21,31,E,26,36",
+ });
+ List<Numbers> output = writeAndRead(numbers);
+ assertEquals(numbers, output);
+ }
+
+ @Test
+ public void testMultipleWithReverse() {
+ run("0,E,2,2,O,1,5", "1,E,2,10,O,5,17");
+ }
+
+ @Test
+ public void testDecreasing() {
+ run("0,O,25,11,E,24,20");
+ }
+
+ @Test
+ public void testMixedStyles() {
+ run("0,O,1,9,E,6,12", "1,E,14,22,O,9,17", "2,O,17,21,E,26,36");
+ }
+
+ @Test
+ public void testOneSide() {
+ runSeparate("0,N,-1,-1,O,9,3");
+ runSeparate("0,E,2,8,N,-1,-1", "0,N,-1,-1,O,9,3");
+ }
+
+ @Test
+ public void testBoth() {
+ runSeparate("0,B,1,10,B,11,20");
+ }
+
+ @Test
+ public void testLargeRunsAndGaps() {
+ run("0,E,100,200,O,111,211", "1,E,400,500,O,421,501", "2,E,600,650,O,601,691");
+ }
+
+ @Test
+ public void testSkip() {
+ run("0,E,2,20,O,1,9", "3,O,3,9,E,2,2");
+ }
+
+ @Test
+ public void testSkipFirst() {
+ run("2,O,1,5,E,2,2");
+ }
+
+ @Test
+ public void testLargeSkip() {
+ run("0,N,-1,-1,E,2,4", "100,O,1,9,E,8,16");
+ }
+
+ @Test
+ public void testRepeatingRun() {
+ run("0,O,1,9,E,2,10",
+ "1,O,11,19,E,12,20",
+ "2,O,21,29,E,22,30",
+ "3,O,31,39,E,32,40"
+ );
+ assertThat(bytesUsed, lessThanOrEqual(8));
+ }
+
+ /**
+ * What to do about the number zero.
+ */
+ @Test
+ public void testZero() {
+ // Includes invalid cases where the numbers are the same down both sides.
+ runSeparate("0,E,0,10,N,-1,-1",
+ "1,B,0,4,B,0,8"
+ );
+ }
+
+ @Test
+ public void testVeryLargeNumber() {
+ String[] numbers = {"0,E,55892490,55892500,N,-1,-1"};
+
+ // Number is way too big, no exception, result just marked invalid.
+ NumberPreparer preparer = new NumberPreparer(createList(numbers));
+ assertFalse(preparer.isValid());
+
+ numbers = new String[] {"0,E,10,55892500,N,-1,-1"};
+ // The difference is too big.
+ preparer = new NumberPreparer(createList(numbers));
+ assertFalse(preparer.isValid());
+ }
+
+ @Test
+ public void testLargeButOK() {
+ run("0,O,1,10001,E,2,12000",
+ "1,O,10003,10301,E,12002,12060",
+ "2,E,1047000,1048000,N,-1,-1");
+ runSeparate("3,E,131000,2,N,-1,-1");
+ }
+
+ /**
+ * Range with differences that are too large. The difference between the start and end
+ * of a range has a lower range than from initial-or-end to start.
+ */
+ @Test
+ public void testLargeDifferenceError() {
+ String[] numbers = {"3,E,131080,2,N,-1,-1"};
+ NumberPreparer preparer = new NumberPreparer(createList(numbers));
+ assertFalse(preparer.isValid());
+ }
+
+ /**
+ * Tests sequences of number ranges that have previously been discovered to fail using the
+ * random range generator test.
+ */
+ @Test
+ public void testRegression() {
+ String[][] tests = {
+ {"0,E,4,2,E,2,2", "1,E,10,8,O,3,1", "2,B,8,6,B,3,3", "3,E,8,2,E,2,2"},
+ {"0,O,5,7,O,9,5", "1,N,-1,-1,O,3,7", "2,N,-1,-1,O,3,5"},
+ {"0,N,-1,-1,O,3,5", "1,O,1,3,N,-1,-1", "2,E,4,4,E,6,8"},
+ {"0,N,-1,-1,E,4,4", "1,E,4,4,O,3,11"},
+ {"0,B,4,8,O,5,9", "1,O,5,3,O,7,7", "2,O,3,3,E,4,20"},
+ {"0,E,8,6,B,6,2", "1,O,5,5,E,4,8"},
+ {"0,B,16,1,B,10,5", "1,O,3,7,E,2,8"},
+ {"0,B,10,5,E,22,10", "1,O,3,1,O,3,5"},
+ {"0,B,10,10,N,-1,-1", "1,O,11,9,O,1,11", "2,O,3,3,E,8,4", "3,O,7,19,E,6,2", "4,E,10,6,E,4,4"},
+ {"0,N,-1,-1,B,6,5", "1,O,3,11,O,3,3"},
+ {"0,O,7,1,O,9,5", "1,O,27,23,O,3,5"},
+ {"0,B,5,5,E,12,8"},
+ };
+
+ for (String[] sarr : tests)
+ run(sarr);
+ }
+
+ // Helper routines
+ private void runSeparate(String... numbers) {
+ for (String s : numbers)
+ run(s);
+ }
+
+ private void run(String ... numbers) {
+ List<Numbers> nList = createList(numbers);
+ List<Numbers> output = writeAndRead(nList);
+ assertEquals(nList, output);
+ }
+
+ private int bytesUsed;
+
+ private List<Numbers> writeAndRead(List<Numbers> numbers) {
+ NumberPreparer preparer = new NumberPreparer(numbers);
+ BitWriter bw = preparer.fetchBitStream();
+ bytesUsed += bw.getLength();
+
+ assertTrue("check valid flag", preparer.isValid());
+
+ boolean swapped = preparer.getSwapped();
+
+ // Now read it all back in again
+ byte[] b1 = bw.getBytes();
+ byte[] bytes = new byte[bw.getLength()];
+ System.arraycopy(b1, 0, bytes, 0, bw.getLength());
+
+ BitReader br = new BitReader(bytes);
+ NumberReader nr = new NumberReader(br);
+ nr.setNumberOfNodes(numbers.size());
+ List<Numbers> list = nr.readNumbers(swapped);
+ for (Numbers n : list)
+ n.setNodeNumber(n.getRnodNumber());
+
+ return list;
+ }
+
+ private List<Numbers> createList(String[] specs) {
+ List<Numbers> numbers = new ArrayList<Numbers>();
+ for (String s : specs) {
+ Numbers n = new Numbers(s);
+ n.setRnodNumber(n.getNodeNumber());
+ numbers.add(n);
+ }
+ return numbers;
+ }
+
+ private Matcher<Integer> lessThanOrEqual(final int val) {
+ return new BaseMatcher<Integer>() {
+ public boolean matches(Object o) {
+ return (Integer) o <= val;
+ }
+
+ public void describeTo(Description description) {
+ description.appendText("value is less than ").appendValue(val);
+ }
+ };
+ }
+}
diff --git a/test/uk/me/parabola/imgfmt/app/net/RoadDefTest.java b/test/uk/me/parabola/imgfmt/app/net/RoadDefTest.java
new file mode 100644
index 0000000..15cd8ce
--- /dev/null
+++ b/test/uk/me/parabola/imgfmt/app/net/RoadDefTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 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 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.
+ */
+/* Create date: 15-Feb-2009 */
+package uk.me.parabola.imgfmt.app.net;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Random;
+
+import uk.me.parabola.imgfmt.app.BitWriter;
+
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+
+public class RoadDefTest {
+
+ /**
+ * Compares the result of the loop in writeNod2 with using a BitWriter.
+ *
+ * You have to copy the code to here for this test to mean anything.
+ */
+ @Test
+ public void testBitArray() {
+
+ Random r = new Random();
+
+ final int MAX_BITS = 26;
+ boolean[] bits = new boolean[MAX_BITS];
+ for (int i = 0; i < bits.length; i++)
+ bits[i] = r.nextBoolean();
+
+ ByteArrayOutputStream writer = new ByteArrayOutputStream();
+
+ // This is the loop taken from the code
+ for (int i = 0; i < bits.length; i += 8) {
+ int b = 0;
+ for (int j = 0; j < 8 && j < bits.length - i; j++)
+ if (bits[i+j])
+ b |= 1 << j;
+ writer.write((byte) b);
+ }
+ // End of loop
+
+ BitWriter bw = new BitWriter();
+ for (boolean b : bits)
+ bw.put1(b);
+
+ byte[] loopResult = writer.toByteArray();
+
+ // Get the bit writer result and trim the array to the correct size
+ byte[] bwResult = new byte[bw.getLength()];
+ System.arraycopy(bw.getBytes(), 0, bwResult, 0, bwResult.length);
+
+ assertArrayEquals("Loop against bitwriter", bwResult, loopResult);
+ }
+}
diff --git a/test/uk/me/parabola/imgfmt/app/net/VarBitWriterTest.java b/test/uk/me/parabola/imgfmt/app/net/VarBitWriterTest.java
new file mode 100644
index 0000000..3b63409
--- /dev/null
+++ b/test/uk/me/parabola/imgfmt/app/net/VarBitWriterTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.imgfmt.app.net;
+
+import uk.me.parabola.imgfmt.app.BitWriter;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+/**
+ * @author Steve Ratcliffe
+ */
+public class VarBitWriterTest {
+
+ private final BitWriter bw = new BitWriter();
+
+ @Test
+ public void testPositive() {
+ VarBitWriter vbw = new VarBitWriter(bw, 3);
+
+ // should be able to write numbers up to 7
+ vbw.write(7);
+
+ byte b = bw.getBytes()[0];
+ assertEquals(b, 7);
+ }
+
+ @Test
+ public void testPositiveWithWidth() {
+ VarBitWriter vbw = new VarBitWriter(bw, 3);
+ vbw.bitWidth = 1;
+
+ // should be able to write numbers up to 15
+ vbw.write(15);
+
+ byte b = bw.getBytes()[0];
+ assertEquals(b, 15);
+ }
+
+ @Test(expected = Abandon.class)
+ public void testPositiveWithWidthFail() {
+ VarBitWriter vbw = new VarBitWriter(bw, 3);
+ vbw.bitWidth = 1;
+
+ // should be able to write numbers up to 15
+ vbw.write(16);
+ assertTrue(false);
+ }
+
+ @Test(expected=Abandon.class)
+ public void testPositiveFail() {
+ VarBitWriter vbw = new VarBitWriter(bw, 3);
+
+ // should be able to write numbers up to 7
+ vbw.write(8);
+ assertTrue(false);
+ }
+
+ @Test
+ public void testNegative() {
+ VarBitWriter vbw = new VarBitWriter(bw, 3);
+ vbw.negative = true;
+
+ // write up to -7
+ vbw.write(-7);
+ byte b = bw.getBytes()[0];
+ assertEquals(b, 7);
+ }
+
+ @Test(expected = Abandon.class)
+ public void testNegativeWithPositive() {
+ VarBitWriter vbw = new VarBitWriter(bw, 3);
+ vbw.negative = true;
+
+ // positive numbers are invalid
+ vbw.write(7);
+ assertTrue(false);
+ }
+
+ @Test(expected = Abandon.class)
+ public void testNegativeTooBig() {
+ VarBitWriter vbw = new VarBitWriter(bw, 3);
+ vbw.negative = true;
+
+ // number too large
+ vbw.write(8);
+ assertTrue(false);
+ }
+
+ @Test
+ public void testSignedPositive() {
+ VarBitWriter vbw = new VarBitWriter(bw, 3);
+ vbw.signed = true;
+
+ // up to 7
+ vbw.write(7);
+ byte b = bw.getBytes()[0];
+ assertEquals(b, 7);
+ }
+
+ @Test
+ public void testSignedNegative() {
+ VarBitWriter vbw = new VarBitWriter(bw, 3);
+ vbw.signed = true;
+
+ // up to -8
+ vbw.write(-8);
+ byte b = bw.getBytes()[0];
+ assertEquals(b, 0x8);
+ }
+
+ @Test(expected = Abandon.class)
+ public void testSignedPositiveTooBig() {
+ VarBitWriter vbw = new VarBitWriter(bw, 3);
+ vbw.signed = true;
+
+ // up to 7, 8 too big
+ vbw.write(8);
+ assertTrue(false);
+ }
+
+ @Test(expected = Abandon.class)
+ public void testSignedNegativeTooBig() {
+ VarBitWriter vbw = new VarBitWriter(bw, 3);
+ vbw.signed = true;
+
+ // up to -8, -9 is too big
+ vbw.write(-9);
+ assertTrue(false);
+ }
+}
diff --git a/test/uk/me/parabola/imgfmt/app/srt/CombinedSortKeyTest.java b/test/uk/me/parabola/imgfmt/app/srt/CombinedSortKeyTest.java
new file mode 100644
index 0000000..2050d4b
--- /dev/null
+++ b/test/uk/me/parabola/imgfmt/app/srt/CombinedSortKeyTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.imgfmt.app.srt;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class CombinedSortKeyTest {
+
+ private static final String HELLO1 = "hello1";
+
+ @Test
+ public void testGetObject() {
+ IntegerSortKey<String> k1 = new IntegerSortKey<String>(HELLO1, 1, 1);
+ CombinedSortKey<String> ck1 = new CombinedSortKey<String>(k1, 2, 2);
+
+ assertEquals("retrieve original object", HELLO1, ck1.getObject());
+ }
+
+ @Test
+ public void testCompletelyEqual() {
+ IntegerSortKey<String> k1 = new IntegerSortKey<String>(HELLO1, 1, 1);
+ CombinedSortKey<String> ck1 = new CombinedSortKey<String>(k1, 2, 2);
+ CombinedSortKey<String> ck2 = new CombinedSortKey<String>(k1, 2, 2);
+
+ assertEquals(0, ck1.compareTo(ck2));
+ }
+
+ @Test
+ public void testDifferentKey() {
+ IntegerSortKey<String> k1 = new IntegerSortKey<String>(HELLO1, 1, 1);
+ IntegerSortKey<String> k2 = new IntegerSortKey<String>(HELLO1, 1, 2);
+ CombinedSortKey<String> ck1 = new CombinedSortKey<String>(k1, 2, 2);
+ CombinedSortKey<String> ck2 = new CombinedSortKey<String>(k2, 2, 2);
+
+ assertEquals(-1, k1.compareTo(k2));
+
+ assertEquals(-1, ck1.compareTo(ck2));
+ assertEquals(1, ck2.compareTo(ck1));
+ }
+
+ @Test
+ public void testDifferentFirst() {
+ IntegerSortKey<String> k1 = new IntegerSortKey<String>(HELLO1, 1, 1);
+ IntegerSortKey<String> k2 = new IntegerSortKey<String>(HELLO1, 1, 1);
+ CombinedSortKey<String> ck1 = new CombinedSortKey<String>(k1, 2, 2);
+ CombinedSortKey<String> ck2 = new CombinedSortKey<String>(k2, 3, 2);
+
+ assertEquals(0, k1.compareTo(k2));
+
+ assertEquals(-1, ck1.compareTo(ck2));
+ assertEquals(1, ck2.compareTo(ck1));
+ }
+
+ @Test
+ public void testDifferentSecond() {
+ IntegerSortKey<String> k1 = new IntegerSortKey<String>(HELLO1, 1, 1);
+ IntegerSortKey<String> k2 = new IntegerSortKey<String>(HELLO1, 1, 1);
+ CombinedSortKey<String> ck1 = new CombinedSortKey<String>(k1, 2, 2);
+ CombinedSortKey<String> ck2 = new CombinedSortKey<String>(k2, 2, 3);
+
+ assertEquals(0, k1.compareTo(k2));
+
+ assertEquals(-1, ck1.compareTo(ck2));
+ assertEquals(1, ck2.compareTo(ck1));
+ }
+
+ @Test
+ public void testKeyOverridesFirst() {
+ IntegerSortKey<String> k1 = new IntegerSortKey<String>(HELLO1, 1, 1);
+ IntegerSortKey<String> k2 = new IntegerSortKey<String>(HELLO1, 2, 1);
+ CombinedSortKey<String> ck1 = new CombinedSortKey<String>(k1, 3, 2);
+ CombinedSortKey<String> ck2 = new CombinedSortKey<String>(k2, 2, 2);
+
+ assertEquals(-1, k1.compareTo(k2));
+
+ assertEquals(-1, ck1.compareTo(ck2));
+ assertEquals(1, ck2.compareTo(ck1));
+ }
+
+ @Test
+ public void testPrimaryOverridesSecond() {
+ IntegerSortKey<String> k1 = new IntegerSortKey<String>(HELLO1, 1, 1);
+ IntegerSortKey<String> k2 = new IntegerSortKey<String>(HELLO1, 1, 1);
+ CombinedSortKey<String> ck1 = new CombinedSortKey<String>(k1, 2, 3);
+ CombinedSortKey<String> ck2 = new CombinedSortKey<String>(k2, 3, 2);
+
+ assertEquals(0, k1.compareTo(k2));
+
+ assertEquals(-1, ck1.compareTo(ck2));
+ assertEquals(1, ck2.compareTo(ck1));
+ }
+}
diff --git a/test/uk/me/parabola/imgfmt/app/srt/SortExpandTest.java b/test/uk/me/parabola/imgfmt/app/srt/SortExpandTest.java
new file mode 100644
index 0000000..5029507
--- /dev/null
+++ b/test/uk/me/parabola/imgfmt/app/srt/SortExpandTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.imgfmt.app.srt;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.text.Collator;
+
+import uk.me.parabola.mkgmap.srt.SrtTextReader;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests for characters that are expanded into two or more sort
+ * positions.
+ */
+public class SortExpandTest {
+ private Sort sort;
+ private Collator collator;
+
+ @Before
+ public void setUp() throws Exception {
+ Reader r = new StringReader("codepage 1252\n" +
+ "code 01\n" +
+ "code a, A; â, à < b, B\n" +
+ "code c < d < e <f < g < h < i < j < k < l < m < n < o\n" +
+ "code p < q < r,R < s,S < t,T < u < v < w < x < y < z\n" +
+ "expand à to s s\n");
+ SrtTextReader srr = new SrtTextReader(r);
+ sort = srr.getSort();
+ collator = sort.getCollator();
+ }
+
+ @Test
+ public void testNormal() {
+ checkOrder("asÃst", "astst");
+ checkOrder("asrst", "asÃst");
+ }
+
+ /**
+ * Expanded letters should sort just after what they expand to.
+ */
+ @Test
+ public void testAgainstExpansion() {
+ checkOrder("asssst", "asÃst");
+ }
+
+ @Test
+ public void testGreaterThanInExpansion() {
+ checkOrder("aÃzaa", "astb");
+ }
+
+ @Test
+ public void testLessThanInExpansion() {
+ checkOrder("asrb", "aÃaaa");
+ }
+
+ /**
+ * Check and assert that the second string is greater than the first.
+ * @param s First string.
+ * @param s1 Second string.
+ */
+ private void checkOrder(String s, String s1) {
+ SortKey<Object> k1 = sort.createSortKey(null, s);
+ SortKey<Object> k2 = sort.createSortKey(null, s1);
+
+ assertEquals(1, k2.compareTo(k1));
+ assertEquals(-1, k1.compareTo(k2));
+
+ assertEquals(-1, collator.compare(s, s1));
+ assertEquals(1, collator.compare(s1, s));
+ }
+}
diff --git a/test/uk/me/parabola/imgfmt/app/srt/SortTest.java b/test/uk/me/parabola/imgfmt/app/srt/SortTest.java
new file mode 100644
index 0000000..3e8acb6
--- /dev/null
+++ b/test/uk/me/parabola/imgfmt/app/srt/SortTest.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.imgfmt.app.srt;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.text.Collator;
+
+import uk.me.parabola.mkgmap.srt.SrtTextReader;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class SortTest {
+ private Sort sort;
+ private Collator collator;
+
+ @Before
+ public void setUp() throws Exception {
+ Reader r = new StringReader("codepage 1252\n" +
+ "code 01\n" +
+ "code a, A; â, à < b, B;\n");
+ SrtTextReader srr = new SrtTextReader(r);
+ sort = srr.getSort();
+ collator = sort.getCollator();
+ collator.setStrength(Collator.TERTIARY);
+ }
+
+ @Test
+ public void testSame() {
+ String s = "aAbâ";
+ SortKey<Object> k1 = sort.createSortKey(null, s);
+ SortKey<Object> k2 = sort.createSortKey(null, s);
+
+ assertEquals(0, k1.compareTo(k2));
+ }
+
+ @Test
+ public void testDifferentLengths() {
+ SortKey<Object> k1 = sort.createSortKey(null, "aabbbb");
+ SortKey<Object> k2 = sort.createSortKey(null, "aab");
+
+ assertEquals(1, k1.compareTo(k2));
+ assertEquals(-1, k2.compareTo(k1));
+ }
+
+ @Test
+ public void testPrimaryDifference() {
+ checkOrder("AAA", "AAB");
+ }
+
+ @Test
+ public void testSecondaryDifferences() {
+ checkOrder("AAA", "AÃA");
+ }
+
+ @Test
+ public void testTertiaryDifferences() {
+ checkOrder("AAa", "AAA");
+ }
+
+ @Test
+ public void testPrimaryOverridesSecondary() {
+ checkOrder("AAAA", "ÃAAA");
+ checkOrder("ÃAAA", "AAAB");
+ }
+
+ @Test
+ public void testSecondaryOverridesTertiary() {
+ checkOrder("aaa", "Aaa");
+ checkOrder("Aaa", "aâa");
+ checkOrder("Aaa", "aÃa");
+ }
+
+ @Test
+ public void testSecondarySort() {
+ checkOrder(1, 24);
+ }
+
+ /**
+ * Test for a bad character in the input.
+ * Probably want the character to be replaced by a question mark rather
+ * than give an error.
+ * Strings with bad characters should not compare equal to other strings
+ * or throw exceptions.
+ */
+ @Test
+ public void testBadCharacter() {
+ String s = "a\u063ab";
+ SortKey<Object> k1 = sort.createSortKey(null, s);
+ SortKey<Object> k2 = sort.createSortKey(null, "aa");
+
+ int res = k1.compareTo(k2);
+ assertTrue(res != 0);
+
+ res = k2.compareTo(k1);
+ assertTrue(res != 0);
+
+ // not equal to an empty string.
+ k2 = sort.createSortKey(null, "");
+ res = k1.compareTo(k2);
+ assertTrue(res != 0);
+
+ // character is replaced with '?'
+ k2 = sort.createSortKey(null, "a?b");
+ res = k1.compareTo(k2);
+ assertEquals(0, res);
+ }
+
+ @Test
+ public void testCollatorPrimary() {
+ Collator collator = sort.getCollator();
+ collator.setStrength(Collator.PRIMARY);
+ assertEquals(0, collator.compare("aa", "aa"));
+ assertEquals(0, collator.compare("aa", "âa"));
+ assertEquals(0, collator.compare("Aa", "aA"));
+ assertEquals(1, collator.compare("ab", "âa"));
+
+ assertEquals(1, collator.compare("aaa", "aa"));
+ assertEquals(-1, collator.compare("aa", "aaa"));
+ }
+
+ @Test
+ public void testCollatorSecondary() {
+ Collator collator = sort.getCollator();
+ collator.setStrength(Collator.SECONDARY);
+ assertEquals(0, collator.compare("aa", "aa"));
+ assertEquals(0, collator.compare("aA", "aa"));
+ assertEquals(-1, collator.compare("aa", "âa"));
+ assertEquals(0, collator.compare("âa", "âa"));
+ assertEquals(1, collator.compare("ab", "âa"));
+
+ assertEquals(1, collator.compare("aaaa", "aaa"));
+ assertEquals(-1, collator.compare("aaa", "aaaa"));
+ }
+
+ @Test
+ public void testCollatorTertiary() {
+ Collator collator = sort.getCollator();
+ collator.setStrength(Collator.TERTIARY);
+ assertEquals(0, collator.compare("aa", "aa"));
+ assertEquals(1, collator.compare("aA", "aa"));
+ assertEquals(-1, collator.compare("aaa", "âaa"));
+ assertEquals(0, collator.compare("âaa", "âaa"));
+ assertEquals(1, collator.compare("ab", "âa"));
+
+ assertEquals(1, collator.compare("AAA", "AA"));
+ assertEquals(-1, collator.compare("AA", "AAA"));
+ }
+
+ @Test
+ public void testIgnorableCharacters() {
+ checkOrder("aa", "\004aa");
+ }
+
+ private void checkOrder(int i1, int i2) {
+ String s = "aaa";
+ SortKey<Object> k1 = sort.createSortKey(null, s, i1);
+ SortKey<Object> k2 = sort.createSortKey(null, s, i2);
+ assertEquals(1, k2.compareTo(k1));
+ }
+
+ /**
+ * Check and assert that the second string is greater than the first.
+ * @param s First string.
+ * @param s1 Second string.
+ */
+ private void checkOrder(String s, String s1) {
+ SortKey<Object> k1 = sort.createSortKey(null, s);
+ SortKey<Object> k2 = sort.createSortKey(null, s1);
+
+ assertEquals(1, k2.compareTo(k1));
+ assertEquals(-1, collator.compare(s, s1));
+ }
+}
diff --git a/test/uk/me/parabola/imgfmt/app/typ/ColourInfoTest.java b/test/uk/me/parabola/imgfmt/app/typ/ColourInfoTest.java
new file mode 100644
index 0000000..1f7f3a6
--- /dev/null
+++ b/test/uk/me/parabola/imgfmt/app/typ/ColourInfoTest.java
@@ -0,0 +1,235 @@
+/*
+ * 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.imgfmt.app.typ;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class ColourInfoTest {
+ private ColourInfo ci;
+
+ @Before
+ public void setUp() {
+ ci = new ColourInfo();
+ }
+
+ /**
+ * One colour, no bitmap, therefore day-only and implied transparent day other.
+ * => 6
+ */
+ @Test
+ public void testSchemeC1() {
+ ci.addColour("a", new Rgb(1,1,1));
+ int cs = ci.getColourScheme();
+ assertEquals(6, cs);
+ }
+
+ /**
+ * Two colours, no bitmap, no border.
+ * day+night, 2 solid, implied transparent other => 7.
+ */
+ @Test
+ public void testSchemeC2() {
+ ci.addColour("a", new Rgb(1,1,1));
+ ci.addColour("b", new Rgb(1,1,2));
+ int cs = ci.getColourScheme();
+ assertEquals(7, cs);
+ }
+
+ /**
+ * Four colours, second transparent, no border or bitmap.
+ * day with transparent, night 2 solid => 3 (probably not allowed)
+ */
+ @Test
+ public void testSchemeC4T2() {
+ ci.addColour("a", new Rgb(1,1,1));
+ ci.addTransparent("b");
+ ci.addColour("c", new Rgb(1,1,2));
+ ci.addColour("d", new Rgb(1,1,2));
+ int cs = ci.getColourScheme();
+ assertEquals(3, cs);
+ }
+
+ /**
+ * Four colours, night has transparent, no border or bitmap.
+ * day solid, night transparent => 5 (probably not allowed)
+ */
+ @Test
+ public void testSchemeC4T4() {
+ ci.addColour("a", new Rgb(1,1,1));
+ ci.addColour("b", new Rgb(1,1,1));
+ ci.addColour("c", new Rgb(1,1,2));
+ ci.addTransparent("d");
+ int cs = ci.getColourScheme();
+ assertEquals(5, cs);
+ }
+
+ /**
+ * Four colours, both have transparent, no border or bitmap.
+ * day transparent, night transparent => 7 (probably not allowed)
+ */
+ @Test
+ public void testSchemeC4T24() {
+ ci.addColour("a", new Rgb(1,1,1));
+ ci.addTransparent("b");
+ ci.addColour("c", new Rgb(1,1,1));
+ ci.addTransparent("d");
+ int cs = ci.getColourScheme();
+ assertEquals(7, cs);
+ }
+
+ /**
+ * Two colours, image.
+ * day 2 solid => 8
+ */
+ @Test
+ public void testSchemeC2Img() {
+ ci.addColour("a", new Rgb(1, 1, 1));
+ ci.addColour("b", new Rgb(1,1,2));
+ ci.setHasBitmap(true);
+ int cs = ci.getColourScheme();
+ assertEquals(8, cs);
+ }
+
+ /*
+ * Two colours, second transparent, image.
+ * Day with transparent, image => e
+ */
+ @Test
+ public void testSchemeC2T2Img() {
+ ci.addColour("a", new Rgb(1,1,1));
+ ci.addTransparent("b");
+ ci.setHasBitmap(true);
+ int cs = ci.getColourScheme();
+ assertEquals(0xe, cs);
+ }
+
+ /**
+ * Four colours, day has transparent, image.
+ * day with transparent, night 2 solid => 8+3
+ */
+ @Test
+ public void testSchemeC4T2Img() {
+ ci.addColour("a", new Rgb(1,1,1));
+ ci.addTransparent("b");
+ ci.addColour("c", new Rgb(1,1,2));
+ ci.addColour("d", new Rgb(1,1,2));
+ ci.setHasBitmap(true);
+ int cs = ci.getColourScheme();
+ assertEquals(0xb, cs);
+ }
+
+ /**
+ * Four colours, night has transparent, image.
+ * day solid, night transparent => 8+5
+ */
+ @Test
+ public void testSchemeC4T4Img() {
+ ci.addColour("a", new Rgb(1,1,1));
+ ci.addColour("b", new Rgb(1,1,1));
+ ci.addColour("c", new Rgb(1,1,2));
+ ci.addTransparent("d");
+ ci.setHasBitmap(true);
+ int cs = ci.getColourScheme();
+ assertEquals(0xd, cs);
+ }
+
+ /**
+ * Four colours, both have transparent, image.
+ * day transparent, night transparent => f
+ */
+ @Test
+ public void testSchemeC4T24Img() {
+ ci.addColour("a", new Rgb(1,1,1));
+ ci.addTransparent("b");
+ ci.addColour("c", new Rgb(1,1,1));
+ ci.addTransparent("d");
+ ci.setHasBitmap(true);
+ int cs = ci.getColourScheme();
+ assertEquals(0xf, cs);
+ }
+
+ /**
+ * One colour, border.
+ * day-only with implied transparent => 6 (but probably not allowed)
+ */
+ @Test
+ public void testSchemeC1Brd() {
+ ci.addColour("a", new Rgb(1,1,1));
+ ci.setHasBorder(true);
+ int cs = ci.getColourScheme();
+ assertEquals(6, cs);
+ }
+
+ /**
+ * Two colours, border.
+ * day 2 solid => 0
+ */
+ @Test
+ public void testSchemeC2Brd() {
+ ci.addColour("a", new Rgb(1,1,1));
+ ci.addColour("b", new Rgb(1,1,2));
+ ci.setHasBorder(true);
+ int cs = ci.getColourScheme();
+ assertEquals(0, cs);
+ }
+
+ /**
+ * Four colours, second transparent, border.
+ * day with transparent, night 2 solid => 3 (probably not allowed)
+ */
+ @Test
+ public void testSchemeC4T2Brd() {
+ ci.addColour("a", new Rgb(1,1,1));
+ ci.addTransparent("b");
+ ci.addColour("c", new Rgb(1,1,2));
+ ci.addColour("d", new Rgb(1,1,2));
+ ci.setHasBorder(true);
+ int cs = ci.getColourScheme();
+ assertEquals(3, cs);
+ }
+
+ /**
+ * Four colours, night has transparent, border.
+ * day solid, night transparent => 5 (probably not allowed)
+ */
+ @Test
+ public void testSchemeC4T4Brd() {
+ ci.addColour("a", new Rgb(1,1,1));
+ ci.addColour("b", new Rgb(1,1,1));
+ ci.addColour("c", new Rgb(1,1,2));
+ ci.addTransparent("d");
+ ci.setHasBorder(true);
+ int cs = ci.getColourScheme();
+ assertEquals(5, cs);
+ }
+
+ /**
+ * Four colours, both have transparent, border.
+ * day transparent, night transparent => 7
+ */
+ @Test
+ public void testSchemeC4T24Brd() {
+ ci.addColour("a", new Rgb(1,1,1));
+ ci.addTransparent("b");
+ ci.addColour("c", new Rgb(1,1,1));
+ ci.addTransparent("d");
+ ci.setHasBorder(true);
+ int cs = ci.getColourScheme();
+ assertEquals(7, cs);
+ }
+
+}
diff --git a/test/uk/me/parabola/imgfmt/app/typ/TYPFileTest.java b/test/uk/me/parabola/imgfmt/app/typ/TYPFileTest.java
new file mode 100644
index 0000000..930ab46
--- /dev/null
+++ b/test/uk/me/parabola/imgfmt/app/typ/TYPFileTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008 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: 01-Dec-2008
+ */
+package uk.me.parabola.imgfmt.app.typ;
+
+import uk.me.parabola.imgfmt.FileSystemParam;
+import uk.me.parabola.imgfmt.fs.FileSystem;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.imgfmt.sys.ImgFS;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class TYPFileTest {
+
+ @Test
+ public void testWrite() throws Exception {
+ FileSystemParam params = new FileSystemParam();
+ FileSystem fs = ImgFS.createFs("test.typ", params);
+ ImgChannel channel = fs.create("XXX.TYP");
+ TYPFile typFile = new TYPFile(channel);
+ assertNotNull("typ file is created", typFile);
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/CommandArgsTest.java b/test/uk/me/parabola/mkgmap/CommandArgsTest.java
new file mode 100644
index 0000000..3a1afaa
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/CommandArgsTest.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2008 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 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.
+ */
+/* Create date: 15-Mar-2009 */
+package uk.me.parabola.mkgmap;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import uk.me.parabola.imgfmt.Utils;
+
+import func.lib.TestUtils;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests for the command line argument processing.
+ * Arguments work like a script. You can set values multiple times
+ * on the command line and they take effect from the point they are
+ * set to the point they are set to something else. File that occur
+ * on the command line are processed with the options that are set at
+ * that point.
+ *
+ * Files that are processed at the end (overview map etc) are
+ * processed with the options that are in effect at the end of the
+ * command line.
+ */
+public class CommandArgsTest {
+ private static final String FILE1 = "00000001.osm";
+ private static final String FILE2 = "00000002.osm";
+ private static final String FILE3 = "00000003.osm";
+
+ private final ArgCollector proc = new ArgCollector();
+ private final CommandArgsReader carg = new CommandArgsReader(proc);
+
+ /**
+ * Test that the default mapnames are correct. Should start with 63240001
+ * and then increase by one for each file.
+ */
+ @Test
+ public void testDefaultMapnames() {
+ carg.readArgs(new String[] {
+ "fred.osm", "bob.osm"
+ });
+
+ assertEquals("first file", "63240001", proc.getProperty(0, "mapname"));
+ assertEquals("second file", "63240002", proc.getProperty(1, "mapname"));
+ }
+
+ /**
+ * Test that if you have numeric names, then the mapname is set to the
+ * value in the filename.
+ */
+ @Test
+ public void testNumericNames() {
+ carg.readArgs(new String[] {
+ FILE1, FILE2
+ });
+
+ assertEquals("first numeric name", "00000001", proc.getProperty(0, "mapname"));
+ assertEquals("first numeric name", "00000002", proc.getProperty(1, "mapname"));
+ }
+
+ /**
+ * Check that if you have numeric names, you can still override with a
+ * --mapname argument.
+ */
+ @Test
+ public void testMapnameWithNumericFilenames() {
+
+ String SETNAME1 = "11110000";
+ String SETNAME2 = "22220000";
+
+ carg.readArgs(new String[]{
+ "--mapname=" + SETNAME1, FILE1,
+ "--mapname=" + SETNAME2, FILE2
+ });
+
+ ArgCollector.FileArgs arg = proc.getFileArg(0);
+ assertEquals("file name", FILE1, arg.name);
+ assertEquals("first file", SETNAME1, arg.getProperty("mapname"));
+
+ arg = proc.getFileArg(1);
+ assertEquals("file name", FILE2, arg.name);
+ assertEquals("second file", SETNAME2, arg.getProperty("mapname"));
+
+ }
+
+ /**
+ * An argument file is parsed a little differently from regular arguments
+ * as the code is reused with the style files.
+ */
+ @Test
+ public void testArgumentFile() throws IOException {
+
+ String SETNAME1 = "11110000";
+ String SETNAME2 = "22220000";
+
+ String F1 = "VIC.osm.gz";
+ String F2 = "NSW.osm.gz";
+
+ String cfile = "family-id=3081\n" +
+ "product-id=2601\n" +
+ "overview-mapname=30810100\n" +
+ "net\n" +
+ "gmapsupp\n" +
+ "tdbfile\n" +
+ "mapname=" + SETNAME1 + "\n" +
+ "description=OSM-AU-Victoria\n" +
+ "country-name=Australia\n" +
+ "country-abbr=AUS\n" +
+ "region-name=Victoria\n" +
+ "region-abbr=VIC\n" +
+ "input-file=" + F1 + "\n" +
+
+ "mapname=" + SETNAME2 + "\n" +
+ "description {\nOSM-AU New South Wales}\n" +
+ "country-name=Australia\n" +
+ "country-abbr=AUS\n" +
+ "# Test that comments are ignored til EOL\n" +
+ "region-name=New-South-Wales\n" +
+ "region-abbr=NSW\n" +
+ "input-file=" + F2 + "\n";
+
+ TestUtils.registerFile("30810100.img");
+ TestUtils.registerFile("30810100.tdb");
+ createFile("args", cfile);
+
+ carg.readArgs(new String[] {
+ "-c", "args",
+ });
+
+ ArgCollector.FileArgs arg = proc.getFileArg(0);
+ assertEquals("file name", F1, arg.name);
+ assertEquals("first file", SETNAME1, arg.getMapname());
+ assertEquals("region-abbr", "VIC", arg.getProperty("region-abbr"));
+
+ arg = proc.getFileArg(1);
+ assertEquals("file name", F2, arg.name);
+ assertEquals("second file", SETNAME2, arg.getMapname());
+ assertEquals("region-abbr", "NSW", arg.getProperty("region-abbr"));
+ assertEquals("description", "OSM-AU New South Wales", arg.getProperty("description"));
+ }
+
+ /**
+ * Combinations of all mapname possibilities.
+ */
+ @Test
+ public void testComplexMapname() {
+ String SETNAME = "12345678";
+
+ carg.readArgs(new String[] {
+ "fred.osm",
+ FILE1,
+ "--mapname=" + SETNAME,
+ FILE2,
+ FILE3,
+ "other.osm"
+ });
+
+ assertEquals("just default", "63240001", proc.getProperty(0, "mapname"));
+ assertEquals("numeric", "00000001", proc.getProperty(1, "mapname"));
+ assertEquals("with mapname", SETNAME, proc.getProperty(2, "mapname"));
+ assertEquals("continue after set", "12345679", proc.getProperty(3, "mapname"));
+ assertEquals("continue after set", "12345680", proc.getProperty(4, "mapname"));
+ }
+
+ /**
+ * Options can be switched off by prefixing them with 'no-'.
+ */
+ @Test
+ public void testArgReset() {
+ carg.readArgs(new String[] {
+ "--keep-going",
+ FILE1,
+ "--no-keep-going",
+ FILE2,
+ "--keep-going",
+ FILE3,
+ });
+
+ assertEquals("first file has keep-going", "", proc.getProperty(0, "keep-going"));
+ assertEquals("second file does not have keep-going", null, proc.getProperty(1, "keep-going"));
+ assertEquals("third file does has keep-going", "", proc.getProperty(2, "keep-going"));
+ assertEquals("any option that was not present is null", null, proc.getProperty(1,
+ "invalid-option-does-not-exist"));
+ }
+
+ private void createFile(String name, String content) throws IOException {
+ TestUtils.registerFile(name);
+ Writer w = null;
+ try {
+ w = new FileWriter(name);
+ w.append(content);
+ } finally {
+ Utils.closeFile(w);
+ }
+ }
+
+ /**
+ * Argument processor that saves the filenames and the values of
+ * the arguments that are in scope for each argument.
+ */
+ private static class ArgCollector implements ArgumentProcessor {
+ private class FileArgs {
+ private String name;
+ private Properties props;
+
+ public String getProperty(String key) {
+ return props.getProperty(key);
+ }
+
+ public String getMapname() {
+ return getProperty("mapname");
+ }
+ }
+
+ private final List<FileArgs> files = new ArrayList<FileArgs>();
+
+ public void processOption(String opt, String val) {
+ }
+
+ public void removeOption(String opt) {
+ }
+
+ public void processFilename(CommandArgs args, String filename) {
+ FileArgs fa = new FileArgs();
+ fa.name = filename;
+
+ fa.props = new Properties();
+ fa.props.putAll(args.getProperties());
+ files.add(fa);
+ }
+
+ public void endOptions(CommandArgs args) {
+ }
+
+ public void startOptions() {
+ }
+
+ public FileArgs getFileArg(int n) {
+ return files.get(n);
+ }
+
+ public String getProperty(int n, String key) {
+ return files.get(n).props.getProperty(key);
+ }
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/OptionTest.java b/test/uk/me/parabola/mkgmap/OptionTest.java
new file mode 100644
index 0000000..6b8af15
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/OptionTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008 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 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.
+ */
+/* Create date: 08-Aug-2009 */
+package uk.me.parabola.mkgmap;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+public class OptionTest {
+ /** If an option does not have a value, then the value is the empty
+ * string.
+ */
+ @Test
+ public void testOptionWithoutValue() {
+ Option o = new Option("hello");
+ assertEquals("name", "hello", o.getOption());
+ assertEquals("value", "", o.getValue());
+ }
+
+
+ @Test
+ public void testOption() {
+ Option o = new Option("hello", "world");
+ assertEquals("name", "hello", o.getOption());
+ assertEquals("value", "world", o.getValue());
+ assertFalse("not experimental", o.isExperimental());
+ }
+
+ /**
+ * Regular option, parsed in constructor.
+ */
+ @Test
+ public void testParseOption() {
+ Option o = new Option("hello=world");
+ assertEquals("name", "hello", o.getOption());
+ assertEquals("value", "world", o.getValue());
+ assertFalse("not experimental", o.isExperimental());
+ }
+
+ /**
+ * Test for an experimental option. These begin with 'x-' but are otherwise
+ * treated as if the 'x-' was not there.
+ */
+ @Test
+ public void testIsExperimental() {
+ Option o = new Option("x-hello=world");
+ assertEquals("name", "hello", o.getOption());
+ assertEquals("value", "world", o.getValue());
+ assertTrue("experimental", o.isExperimental());
+ }
+
+ /**
+ * Test for an negative option eg: no-route. These begin with the prefix 'no-'.
+ * The option name is without the prefix and a flag is set to show that the option
+ * is being reset.
+ */
+ @Test
+ public void testOptionReset() {
+ Option o = new Option("no-hello");
+ assertEquals("name", "hello", o.getOption());
+ assertEquals("value", null, o.getValue());
+ assertTrue("reset", o.isReset());
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/OptionsTest.java b/test/uk/me/parabola/mkgmap/OptionsTest.java
new file mode 100644
index 0000000..045504e
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/OptionsTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2008 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 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.
+ */
+/* Create date: 09-Aug-2009 */
+package uk.me.parabola.mkgmap;
+
+import java.io.File;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class OptionsTest {
+ private static final String[] STD_SINGLE_OPTS = {
+ "pool", "ocean"
+ };
+
+ String PATH_SEP = System.getProperty("file.separator");
+
+ private final List<Option> found = new ArrayList<Option>();
+ private final List<String> options = new ArrayList<String>();
+ private final List<String> values = new ArrayList<String>();
+
+ /**
+ * You can have options with values separated by either a ':' or an
+ * equals sign.
+ */
+ @Test
+ public void testOptionsWithValues() {
+ String s = "three=3\nfour:4\n";
+ readOptionsFromString(s);
+
+ assertEquals("correct number", 2, found.size());
+
+ assertArrayEquals("options", new String[] {
+ "three", "four"
+ }, options.toArray());
+
+ assertArrayEquals("values", new String[] {
+ "3", "4"
+ }, values.toArray());
+ }
+
+ /**
+ * Options do not need to have a value
+ */
+ @Test
+ public void testOptionsWithoutValues() {
+ String s = "pool\nocean\n";
+ readOptionsFromString(s);
+
+ assertEquals("number of options found", 2, found.size());
+ assertArrayEquals("options", STD_SINGLE_OPTS, options.toArray());
+ checkEmptyValues();
+ }
+
+ /**
+ * Comments can appear as the first significant character of a line
+ * and cause the rest of the line to be skipped.
+ */
+ @Test
+ public void testComments() {
+ String s = "pool\n" +
+ " # first comment\n" +
+ "# a whole line of comment \n" +
+ "ocean\n";
+
+ readOptionsFromString(s);
+
+ assertEquals("number of options found", 2, found.size());
+ assertArrayEquals("options", STD_SINGLE_OPTS, options.toArray());
+ checkEmptyValues();
+ }
+
+ /**
+ * An option can have a long value that is surrounded by braces. All
+ * leading and trailing white space is trimmed.
+ */
+ @Test
+ public void testLongValues() {
+ final String OPT1 = "This is a much longer value\n" +
+ "that spans several\n" +
+ "lines\n";
+ final String OPT2 = " and here is another, note that there was no new" +
+ "line before the option name.";
+
+ String s = "pool {" + OPT1 + "}" +
+ "ocean {\n" + OPT2 + "}";
+ readOptionsFromString(s);
+
+ System.out.println(options);
+ System.out.println(values);
+ assertEquals("number of options found", 2, found.size());
+ assertArrayEquals("options", STD_SINGLE_OPTS, options.toArray());
+ assertEquals("first value", OPT1.trim(), values.get(0));
+ assertEquals("second value", OPT2.trim(), values.get(1));
+ }
+
+ /**
+ * Relative input filenames are relative to the directory of the args
+ * file.
+ * Note: does test work on windows?
+ */
+ @Test
+ public void testRelativeFilenamesInFile() {
+ String s = "input-file: foo\n";
+
+ OptionProcessor proc = new MyOptionProcessor();
+ Options opts = new Options(proc);
+ Reader r = new StringReader(s);
+
+ opts.readOptionFile(r, "/bar/string.args");
+ String filename = values.get(0);
+ File file = new File(filename);
+ assertEquals("directory part", PATH_SEP + "bar", file.getParent());
+ assertEquals("file part", "foo", file.getName());
+ }
+
+ /**
+ * Absolute input filenames are unaffected by the directory that the
+ * args file is in.
+ * Note: does test work on windows?
+ */
+ @Test
+ public void testAbsoluteFilenamesInFile() {
+ String s, exp_dir;
+ if (PATH_SEP.equals("\\")) {
+ s = "input-file: c:\\home\\foo\n";
+ exp_dir = "c:\\home";
+ }
+ else {
+ s = "input-file: /home/foo\n";
+ exp_dir = "/home";
+ }
+
+ OptionProcessor proc = new MyOptionProcessor();
+ Options opts = new Options(proc);
+ Reader r = new StringReader(s);
+
+ opts.readOptionFile(r, "/bar/string.args");
+ System.out.println(Arrays.toString(values.toArray()));
+
+ String filename = values.get(0);
+ File file = new File(filename);
+ assertEquals("directory part", exp_dir, file.getParent());
+ assertEquals("file part", "foo", file.getName());
+ }
+
+ private void checkEmptyValues() {
+ for (String s : values) {
+ assertEquals("value", "", s);
+ }
+ }
+
+ private void readOptionsFromString(String s) {
+ OptionProcessor proc = new MyOptionProcessor();
+ Options opts = new Options(proc);
+ Reader r = new StringReader(s);
+
+ opts.readOptionFile(r, "from-string");
+ }
+
+ private class MyOptionProcessor implements OptionProcessor {
+ public void processOption(Option opt) {
+ found.add(opt);
+ options.add(opt.getOption());
+ values.add(opt.getValue());
+ }
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/general/LineClipperTest.java b/test/uk/me/parabola/mkgmap/general/LineClipperTest.java
new file mode 100644
index 0000000..80fdbb9
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/general/LineClipperTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008 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: 29-Nov-2008
+ */
+package uk.me.parabola.mkgmap.general;
+
+import java.util.Arrays;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Area;
+import uk.me.parabola.imgfmt.app.Coord;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+
+public class LineClipperTest {
+
+ /**
+ * This is the example as given on the referenced web page.
+ * We now use integers instead of floats so the 101.425 from the
+ * example is just 101 here.
+ */
+ @Test
+ public void testExampleClip() {
+ Area a = new Area(60, 70, 150, 230);
+ Coord[] co = {
+ new Coord(20, 30),
+ new Coord(160, 280),
+ };
+
+ List<List<Coord>> listList = LineClipper.clip(a, Arrays.asList(co));
+ assertTrue("list should be empty", !listList.isEmpty());
+
+ Coord[] result = {
+ new Coord(60, 101),
+ new Coord(132, 230)
+ };
+ assertArrayEquals("example result", result, listList.get(0).toArray());
+ }
+
+ /**
+ * Test an original line that enters the area, leaves it and then goes back
+ * into the area. This should give two lines in the result set.
+ */
+ @Test
+ public void testListClip() {
+ // Add your code here
+ Area a = new Area(100, 100, 200, 200);
+ List<Coord> l = Arrays.asList(new Coord(20, 30),
+ new Coord(40, 60),
+ new Coord(102, 110),
+ new Coord(150, 150),
+ new Coord(210, 220),
+ new Coord(190, 135)
+ );
+ List<List<Coord>> list = LineClipper.clip(a, l);
+
+ // There should be exactly two lines
+ assertEquals("should be two lines", 2, list.size());
+
+ // No empty lists
+ for (List<Coord> lco : list)
+ assertTrue("empty list", !lco.isEmpty());
+
+ // Check values
+ Coord[] firstExpectedLine = {
+ new Coord(100, 108),
+ new Coord(102, 110),
+ new Coord(150, 150),
+ new Coord(193, 200)
+ };
+ assertArrayEquals(firstExpectedLine, list.get(0).toArray());
+ Coord[] secondExpectedLine = {
+ new Coord(200, 178),
+ new Coord(190, 135)
+ };
+ assertArrayEquals(secondExpectedLine, list.get(1).toArray());
+ }
+
+ /**
+ * If all the lines are inside, then it should just return null to indicate that.
+ */
+ @Test
+ public void testAllInside() {
+ Area a = new Area(100, 100, 200, 200);
+ List<Coord> l = Arrays.asList(
+ new Coord(102, 110),
+ new Coord(150, 150),
+ new Coord(190, 195)
+ );
+ List<List<Coord>> list = LineClipper.clip(a, l);
+ assertNull("all lines inside", list);
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/general/MapPointKdTreeTest.java b/test/uk/me/parabola/mkgmap/general/MapPointKdTreeTest.java
new file mode 100644
index 0000000..15bd6b7
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/general/MapPointKdTreeTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * 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.general;
+
+import static org.junit.Assert.assertFalse;
+import org.junit.Test;
+
+import uk.me.parabola.imgfmt.app.Coord;
+
+public class MapPointKdTreeTest {
+
+ @Test
+ public void TestFindNextPoint(){
+ MapPointKdTree t = new MapPointKdTree( );
+
+ int [][]test = {{70,20}, {50,40}, {90,60}, {20,30}, {40,70}, {80,10}, {-10,20}, {-30,-40} } ;
+ Coord []testCoords = new Coord[test.length];
+
+ for( int i = 0; i < test.length; i++ )
+ {
+ MapPoint p = new MapPoint();
+ testCoords[i] = new Coord(test[i][0],test[i][1]);
+ p.setLocation(testCoords[i]);
+ t.add(p);
+ }
+ // compare naive search result with kd--tree result
+ MapPoint toFind = new MapPoint();
+ for (int x = -100; x < 100; x++){
+ for (int y = -100; y < 100; y++){
+ Coord co = new Coord(x,y);
+ double minDist = Double.MAX_VALUE;
+
+ for (int i = 0; i<testCoords.length; i++){
+ Double dist = testCoords[i].distanceInDegreesSquared(co);
+ if (dist < minDist){
+ minDist = dist;
+ }
+ }
+ toFind.setLocation(co);
+ MapPoint next = t.findNextPoint(toFind);
+ double dist = next.getLocation().distanceInDegreesSquared(co);
+ double delta = Math.abs(dist - minDist);
+ // if this test fails because
+ assertFalse("delta should be 0.0: " + delta, delta != 0.0);
+ }
+ }
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/general/PointInShapeTest.java b/test/uk/me/parabola/mkgmap/general/PointInShapeTest.java
new file mode 100644
index 0000000..aeb3fca
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/general/PointInShapeTest.java
@@ -0,0 +1,286 @@
+/**
+ *
+ */
+package uk.me.parabola.mkgmap.general;
+
+
+import java.util.Arrays;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author ben
+ */
+public class PointInShapeTest {
+
+ private MapShape square;
+ private MapShape triangle;
+ private MapShape line;
+ private final int squareSize = 4;
+
+ /**
+ * @throws Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ // Square
+ List<Coord> points = Arrays.asList(
+ new Coord(0, 0),
+ new Coord(0, squareSize),
+ new Coord(squareSize, squareSize),
+ new Coord(squareSize, 0),
+ new Coord(0,0)
+ );
+ square = new MapShape();
+ square.setPoints(points);
+
+ // Triangle
+ points = Arrays.asList(
+ new Coord(0,0),
+ new Coord(4,4),
+ new Coord(8,0),
+ new Coord(0,0)
+ );
+ triangle = new MapShape();
+ triangle.setPoints(points);
+
+ // Line
+ points = Arrays.asList(
+ new Coord(2,5),
+ new Coord(12,1)
+ );
+ line = new MapShape();
+ line.setPoints(points);
+ }
+
+ @Test
+ public void testLinePointsInsideSquare() {
+
+ // inside square, 1 unit from corners
+ List<Coord> points = Arrays.asList(
+ new Coord(1, squareSize/2),
+ new Coord(squareSize/2, squareSize - 1),
+ new Coord(squareSize - 1, squareSize/2),
+ new Coord(squareSize/2, 1)
+ );
+ for (Coord coord : points) {
+ assertTrue("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be inside square",
+ square.contains(coord));
+ }
+
+ // on the line
+ points = Arrays.asList(
+ new Coord(0, squareSize/2),
+ new Coord(squareSize/2, squareSize),
+ new Coord(squareSize, squareSize/2),
+ new Coord(squareSize/2, 0)
+ );
+ for (Coord coord : points) {
+ assertTrue("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be outside square",
+ square.contains(coord));
+ }
+ }
+
+ @Test
+ public void testLinePointsOutsideSquare() {
+
+ // outside square, 1 unit from line
+ List<Coord> points = Arrays.asList(
+ new Coord(-1, squareSize/2),
+ new Coord(squareSize/2, squareSize + 1),
+ new Coord(squareSize + 1, squareSize/2),
+ new Coord(squareSize/2, -1)
+ );
+ for (Coord coord : points) {
+ assertFalse("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be outside square",
+ square.contains(coord));
+ }
+ }
+
+ @Test
+ public void testCornerPointsInsideSquare() {
+ // corner points
+ for (Coord cornerpoint : square.getPoints()) {
+ Coord co = new Coord(cornerpoint.getLatitude(), cornerpoint.getLongitude());
+ assertTrue("corner point (" + co.getLatitude() + ", " + co.getLongitude() + ") should be outside square",
+ square.contains(co));
+ }
+
+ // sub shape
+ for (Coord cornerpoint : square.getPoints()) {
+ int xadd = cornerpoint.getLatitude() > 0 ? -1 : 1;
+ int yadd = cornerpoint.getLongitude() > 0 ? -1 : 1;
+ int x = cornerpoint.getLatitude() + xadd;
+ int y = cornerpoint.getLongitude() + yadd;
+ Coord co = new Coord(x, y);
+ assertTrue("point (" + x + ", " + y + ") should be inside square", square.contains(co));
+ }
+
+ // tests above / below corner points, on the outside edge
+ for (Coord cornerpoint : square.getPoints()) {
+ int xadd = cornerpoint.getLatitude() > 0 ? -1 : 1;
+ int x = cornerpoint.getLatitude() + xadd;
+ int y = cornerpoint.getLongitude();
+ Coord co = new Coord(x, y);
+ assertTrue("point (" + x + ", " + y + ") should be outside square", square.contains(co));
+ }
+
+ // tests to the right / left side of corner points, on square edge
+ for (Coord cornerpoint : square.getPoints()) {
+ int yadd = cornerpoint.getLongitude() > 0 ? -1 : 1;
+ int x = cornerpoint.getLatitude();
+ int y = cornerpoint.getLongitude() + yadd;
+ Coord co = new Coord(x, y);
+ assertTrue("point (" + x + ", " + y + ") should be outside square", square.contains(co));
+ }
+ }
+
+ @Test
+ public void testCornerPointsOutsideSquare() {
+
+ // tests above / below corner points, outside square
+ for (Coord cornerpoint : square.getPoints()) {
+ int yadd = cornerpoint.getLongitude() > 0 ? 1 : -1;
+ int x = cornerpoint.getLatitude();
+ int y = cornerpoint.getLongitude() + yadd;
+ Coord co = new Coord(x, y);
+ assertFalse("point (" + x + ", " + y + ") should be outside square", square.contains(co));
+ }
+
+ // tests to the right / left side of corner points, outside square
+ for (Coord cornerpoint : square.getPoints()) {
+ int xadd = cornerpoint.getLatitude() > 0 ? 1 : -1;
+ int x = cornerpoint.getLatitude() + xadd;
+ int y = cornerpoint.getLongitude();
+ Coord co = new Coord(x, y);
+ assertFalse("point (" + x + ", " + y + ") should be outside square", square.contains(co));
+ }
+
+ // super shape
+ for (Coord cornerpoint : square.getPoints()) {
+ int xadd = cornerpoint.getLatitude() > 0 ? 1 : -1;
+ int yadd = cornerpoint.getLongitude() > 0 ? 1 : -1;
+ int x = cornerpoint.getLatitude() + xadd;
+ int y = cornerpoint.getLongitude() + yadd;
+ Coord co = new Coord(x, y);
+ assertFalse("point (" + x + ", " + y + ") should be outside square", square.contains(co));
+ }
+ }
+
+
+ @Test
+ public void testLinePointsInsideTriangle() {
+ // inside triangle, above / below lines
+ List<Coord> points = Arrays.asList(
+ new Coord(2,1),
+ new Coord(6,1),
+ new Coord(4,1)
+ );
+ for (Coord coord : points) {
+ assertTrue("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be inside triangle",
+ triangle.contains(coord));
+ }
+
+ // on lines
+ points = Arrays.asList(
+ new Coord(2,2),
+ new Coord(6,2),
+ new Coord(4,0)
+ );
+ for (Coord coord : points) {
+ assertTrue("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be outside triangle",
+ triangle.contains(coord));
+ }
+ }
+
+ @Test
+ public void testLinePointsOutsideTriangle() {
+ // outside triangle, above / below lines
+ List<Coord> points = Arrays.asList(
+ new Coord(2,3),
+ new Coord(6,3),
+ new Coord(4,-1)
+ );
+ for (Coord coord : points) {
+ assertFalse("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be outside triangle",
+ triangle.contains(coord));
+ }
+ }
+
+ @Test
+ public void testCornerPointsInsideTriangle() {
+ // corner points
+ for (Coord cornerpoint : triangle.getPoints()) {
+ assertTrue("point (" + cornerpoint.getLatitude() + ", " + cornerpoint.getLongitude() + ") should be outside triangle",
+ triangle.contains(cornerpoint));
+ }
+
+ // sub shape
+ List<Coord> points = Arrays.asList(
+ new Coord(2,1),
+ new Coord(4,3),
+ new Coord(6,1)
+ );
+ for (Coord coord : points) {
+ assertTrue("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be inside triangle",
+ triangle.contains(coord));
+ }
+
+ // beside points, on edge
+ points = Arrays.asList(
+ new Coord(1,0),
+ new Coord(7,0)
+ );
+ for (Coord coord : points) {
+ assertTrue("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be outside triangle",
+ triangle.contains(coord));
+ }
+ }
+
+ @Test
+ public void testCornerPointsOutsideTriangle() {
+ // above points
+ for (Coord coord : triangle.getPoints()) {
+ Coord co = new Coord(coord.getLatitude(), coord.getLongitude() + 1);
+ assertFalse("point (" + co.getLatitude() + ", " + co.getLongitude() + ") should be outside triangle",
+ triangle.contains(co));
+ }
+
+ // outside triangle, beside / below lines
+ List<Coord> points = Arrays.asList(
+ new Coord(-1,0),
+ new Coord(0,-1),
+ new Coord(3,4),
+ new Coord(5,4),
+ new Coord(9,0),
+ new Coord(8,-1)
+ );
+ for (Coord coord : points) {
+ assertFalse("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be outside triangle",
+ triangle.contains(coord));
+ }
+
+ // super shape
+ for (Coord cornerpoint : triangle.getPoints()) {
+ int xadd = cornerpoint.getLatitude() > 0 ? 1 : -1;
+ int yadd = cornerpoint.getLongitude() > 0 ? 1 : -1;
+ int x = cornerpoint.getLatitude() + xadd;
+ int y = cornerpoint.getLongitude() + yadd;
+ Coord co = new Coord(x, y);
+ assertFalse("point (" + x + ", " + y + ") should be outside triangle", triangle.contains(co));
+ }
+ }
+
+ @Test
+ public void testLine() {
+ // midpoint
+ Coord co = new Coord(7,3);
+ assertFalse("point (" + co.getLatitude() + ", " + co.getLongitude() + ") should be outside line",
+ line.contains(co));
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/osmstyle/ActionReaderTest.java b/test/uk/me/parabola/mkgmap/osmstyle/ActionReaderTest.java
new file mode 100644
index 0000000..ddc1deb
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/osmstyle/ActionReaderTest.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2008 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: 29-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.List;
+import java.util.Map;
+
+import uk.me.parabola.mkgmap.osmstyle.actions.Action;
+import uk.me.parabola.mkgmap.osmstyle.actions.ActionReader;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.GeneralRelation;
+import uk.me.parabola.mkgmap.reader.osm.Relation;
+import uk.me.parabola.mkgmap.reader.osm.Rule;
+import uk.me.parabola.mkgmap.reader.osm.TypeResult;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Test the possible actions that can appear in an action block.
+ * These are run before any rule is finally matched.
+ */
+public class ActionReaderTest {
+
+ @Test
+ public void testSimpleSet() {
+ List<Action> actions = readActionsFromString("{set park=yes}");
+ assertEquals("one action", 1, actions.size());
+
+ Element el = stdElementRun(actions);
+
+ assertEquals("park overwritten", "yes", el.getTag("park"));
+ }
+
+ @Test
+ public void testSimpleAdd() {
+ List<Action> actions = readActionsFromString("{add park=yes}");
+ assertEquals("one action", 1, actions.size());
+
+ // add does not overwrite existing tags.
+ Element el = stdElementRun(actions);
+ assertEquals("park not overwritten", "no", el.getTag("park"));
+ }
+
+ @Test
+ public void testRename() {
+ List<Action> actions = readActionsFromString("{rename park landarea}");
+ assertEquals("one action", 1, actions.size());
+
+ Element el = stdElementRun(actions);
+ assertNull("park should be gone", el.getTag("park"));
+ assertEquals("park renamed", "no", el.getTag("landarea"));
+ }
+
+ /**
+ * Test with embedded comment, newlines, semicolon used as separator.
+ */
+ @Test
+ public void testFreeForm() {
+ List<Action> actions = readActionsFromString(" { set web='world wide';" +
+ "set \nribbon = 'yellow' \n# a comment } ");
+
+ assertEquals("number of actions", 2, actions.size());
+ Element el = stdElementRun(actions);
+ assertEquals("park not overwritten", "no", el.getTag("park"));
+ assertEquals("word with spaces", "world wide", el.getTag("web"));
+ assertEquals("yellow ribbon", "yellow", el.getTag("ribbon"));
+ }
+
+ /**
+ * Test several commands in the block. They should all be executed.
+ */
+ @Test
+ public void testMultipleCommands() {
+ List<Action> actions = readActionsFromString(
+ "{set park=yes; add fred=other;" +
+ "set pooh=bear}");
+
+ assertEquals("number of actions", 3, actions.size());
+
+ Element el = stdElementRun(actions);
+
+ assertEquals("park set to yes", "yes", el.getTag("park"));
+ assertEquals("fred set", "other", el.getTag("fred"));
+ assertEquals("pooh set", "bear", el.getTag("pooh"));
+ }
+
+ @Test(expected = SyntaxException.class)
+ public void testInvalidCommand() {
+ readActionsFromString("{bad }");
+ }
+
+ /**
+ * The name action set the element-name (not the 'name' tag).
+ * The first value to set it counts, later matches are ignored.
+ */
+ @Test
+ public void testName() {
+ List<Action> actions = readActionsFromString("{name '${name} (${ref})' |" +
+ " '${ref}' | '${name}' ; }");
+ Element el = makeElement();
+ el.addTag("name", "Main St");
+ Rule rule = new ActionRule(null, actions);
+ rule.resolveType(el, TypeResult.NULL_RESULT);
+ assertEquals("just name", "Main St", el.getName());
+ }
+
+ /**
+ * Test with two name actions. This works just the same as having several
+ * name options on the same name command, in that it is still the
+ * first one to match that counts.
+ */
+ @Test
+ public void testDoubleName() {
+ List<Action> actions = readActionsFromString("{name '${name} (${ref})' |" +
+ " '${ref}' | '${name}' ; " +
+ " name 'fred';}");
+
+ // Something that matches nothing in the first name command.
+ Element el = makeElement();
+ Rule rule = new ActionRule(null, actions);
+ rule.resolveType(el, TypeResult.NULL_RESULT);
+ assertEquals("no tags, second action matches", "fred", el.getName());
+
+ el = makeElement();
+ el.addTag("ref", "A1");
+ rule.resolveType(el, TypeResult.NULL_RESULT);
+ assertEquals("just a ref tag", "A1", el.getName());
+
+ el = makeElement();
+ el.addTag("ref", "A1");
+ el.addTag("name", "Main St");
+ rule.resolveType(el, TypeResult.NULL_RESULT);
+ assertEquals("ref and name", "Main St (A1)", el.getName());
+ }
+
+ /**
+ * The apply action works on the members of relations.
+ */
+ @Test
+ public void testApplyAction() {
+ List<Action> actions = readActionsFromString("{apply {" +
+ "add route=bike;" +
+ "set foo=bar; }" +
+ "}\n");
+
+ Relation rel = makeRelation();
+ Rule rule = new ActionRule(null, actions);
+ rule.resolveType(rel, TypeResult.NULL_RESULT);
+
+ assertNull("Tag not set on relation", rel.getTag("route"));
+
+ // Will be set on all members as there is no role filter.
+ List<Map.Entry<String,Element>> elements = rel.getElements();
+ Element el1 = elements.get(0).getValue();
+ assertEquals("route tag added to first", "bike", el1.getTag("route"));
+ assertEquals("foo tag set to first", "bar", el1.getTag("foo"));
+
+ Element el2 = elements.get(1).getValue();
+ assertEquals("route tag added to second", "bike", el2.getTag("route"));
+ assertEquals("foo tag set to second", "bar", el2.getTag("foo"));
+ }
+
+ /**
+ * You can have a role filter, so that the actions are only applied
+ * to members with the given role.
+ */
+ @Test
+ public void testApplyWithRole() {
+ List<Action> actions = readActionsFromString("{apply role=bar {" +
+ "add route=bike;" +
+ "set foo=bar; }}");
+
+ Relation rel = makeRelation();
+ Rule rule = new ActionRule(null, actions);
+ rule.resolveType(rel, TypeResult.NULL_RESULT);
+
+ List<Map.Entry<String,Element>> elements = rel.getElements();
+ Element el1 = elements.get(0).getValue();
+ assertEquals("route tag added to first", "bike", el1.getTag("route"));
+ assertEquals("foo tag set to first", "bar", el1.getTag("foo"));
+
+ // Wrong role, so not applied.
+ Element el2 = elements.get(1).getValue();
+ assertNull("route tag not added to second element (role=foo)", el2.getTag("route"));
+ assertNull("foo tag not set in second element (role=foo)", el2.getTag("foo"));
+ }
+
+ /**
+ * When an apply statement runs, then substitutions on the value use
+ * the tags of the relation and not of the sub element.
+ */
+ @Test
+ public void testApplyWithSubst() {
+ List<Action> actions = readActionsFromString("{apply {" +
+ "add route='${route_no}';" +
+ "}}");
+
+ Relation rel = makeRelation();
+ rel.addTag("route_no", "66");
+ Element el1 = rel.getElements().get(0).getValue();
+ el1.addTag("route_no", "42");
+
+ Rule rule = new ActionRule(null, actions);
+ rule.resolveType(rel, TypeResult.NULL_RESULT);
+ assertEquals("route_no taken from relation tags", "66", el1.getTag("route"));
+ }
+
+ @Test
+ public void testEmptyActionList() {
+ List<Action> actions = readActionsFromString("{}");
+ assertEquals("no actions found", 0, actions.size());
+ }
+
+ @Test
+ public void testAlternatives() {
+ List<Action> actions = readActionsFromString(
+ "{set fred = '${park}' | 'default value'}");
+
+ Element el = makeElement();
+ Rule rule = new ActionRule(null, actions);
+ rule.resolveType(el, TypeResult.NULL_RESULT);
+ assertEquals("first alternative", "no", el.getTag("fred"));
+ }
+
+ @Test
+ public void testSecondAlternative() {
+ List<Action> actions = readActionsFromString(
+ "{set fred = '${notset}' | 'default value'}");
+
+ Element el = makeElement();
+ el.addTag("fred", "origvalue");
+ Rule rule = new ActionRule(null, actions);
+ rule.resolveType(el, TypeResult.NULL_RESULT);
+ assertEquals("second alternative", "default value", el.getTag("fred"));
+ }
+
+ private Element stdElementRun(List<Action> actions) {
+ Rule rule = new ActionRule(null, actions);
+ Element el = makeElement();
+ rule.resolveType(el, TypeResult.NULL_RESULT);
+ return el;
+ }
+
+ /**
+ * Make a standard element for the tests.
+ */
+ private Element makeElement() {
+ Element el = new Way(0);
+ el.addTag("park", "no");
+ el.addTag("test", "1");
+ return el;
+ }
+
+ private Relation makeRelation() {
+ Relation rel = new GeneralRelation(23);
+ rel.addElement("bar", makeElement());
+ rel.addElement("foo", makeElement());
+ return rel;
+ }
+ /**
+ * Read a action list from a string.
+ */
+ private List<Action> readActionsFromString(String in) {
+ Reader sr = new StringReader(in);
+ TokenScanner ts = new TokenScanner("string", sr);
+ ActionReader ar = new ActionReader(ts);
+ return ar.readActions().getList();
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java b/test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java
new file mode 100644
index 0000000..18e6492
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java
@@ -0,0 +1,1051 @@
+/*
+ * Copyright (C) 2008 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: 29-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.general.LevelInfo;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.FeatureKind;
+import uk.me.parabola.mkgmap.reader.osm.GType;
+import uk.me.parabola.mkgmap.reader.osm.Rule;
+import uk.me.parabola.mkgmap.reader.osm.TypeResult;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+
+import func.lib.StringStyleFileLoader;
+import org.junit.Test;
+
+import static func.lib.TestUtils.makeRuleSet;
+import static org.junit.Assert.*;
+
+
+public class RuleFileReaderTest {
+ /**
+ * Test of a file containing a number of different rules, with varying
+ * formatting and including comments.
+ */
+ @Test
+ public void testLoad() {
+ RuleSet rs = makeRuleSet("highway=footway & type=rough [0x2 level 2]\n" +
+ "highway=footway | highway = path\n" +
+ " [0x3]\n# comment here\n" +
+ "foo=\nbar & bar=two [0x4]\n" +
+ "highway=* & oneway=true [0x6 level 1]\n" +
+ "");
+
+ Element el = new Way(1);
+ el.addTag("highway", "footway");
+
+ GType type = getFirstType(rs, el);
+ assertEquals("plain footway", "[0x3 level 0]", type.toString());
+
+ el.addTag("type", "rough");
+ type = getFirstType(rs, el);
+ assertEquals("rough footway", "[0x2 level 2]", type.toString());
+ }
+
+ /**
+ * Test for non-standard level specification. You can give a range
+ * of levels, rather than defaulting the max end to 0.
+ */
+ @Test
+ public void testLevel() {
+ RuleSet rs = makeRuleSet(
+ "highway=primary [0x1 level 1-3]"
+ );
+
+ Element el = new Way(1);
+ el.addTag("highway", "primary");
+
+ GType type = getFirstType(rs, el);
+ assertEquals("min level", 1, type.getMinLevel());
+ assertEquals("max level", 3, type.getMaxLevel());
+ }
+
+ /**
+ * Try out arithmetic comparisons and mixtures of 'and' and 'or'.
+ */
+ @Test
+ public void testComplexExpressions() {
+ String str = "a=b & (c=d | e=f) & x>10 [0x1]\n";
+ RuleSet rs = makeRuleSet(str);
+
+ Element el = new Way(1);
+ el.addTag("a", "b");
+ el.addTag("c", "d");
+ el.addTag("x", "11");
+
+ GType type = getFirstType(rs, el);
+ assertEquals("expression ok", 1, type.getType());
+
+ // fails with x less than 10
+ el.addTag("x", "9");
+ type = getFirstType(rs, el);
+ assertNull("x too low", type);
+
+ // also fails with x equal to 10
+ el.addTag("x", "10");
+ type = getFirstType(rs, el);
+ assertNull("x too low", type);
+
+ // OK with x > 10
+ el.addTag("x", "100");
+ el.addTag("e", "f");
+ type = getFirstType(rs, el);
+ assertEquals("c and e set", 1, type.getType());
+
+ el.addTag("c", "");
+ el.addTag("e", "");
+ type = getFirstType(rs, el);
+ assertNull("none of c and e set", type);
+
+ el.addTag("e", "f");
+ type = getFirstType(rs, el);
+ assertEquals("e is set to f", 1, type.getType());
+ }
+
+ /**
+ * Test based on email on the mailing list at:
+ * http://www.mkgmap.org.uk/pipermail/mkgmap-dev/2009q3/003009.html
+ * See that email for an explanation.
+ */
+ @Test
+ public void testComparasons() {
+ String str = "highway=null_null & layer<0 [0x01 resolution 10]\n" +
+ "highway=null_null & layer=0 [0x02 resolution 10]\n" +
+ "highway=null_null & layer>0 [0x03 resolution 10]\n" +
+ "highway=null_null & layer='-1' [0x04 resolution 10]\n" +
+ "highway=null_null & layer='0' [0x05 resolution 10]\n" +
+ "highway=null_null & layer='1' [0x06 resolution 10]\n" +
+ "highway=null_null & layer='+1' [0x07 resolution 10]\n" +
+ "highway=null_null [0x08 resolution 10]";
+ RuleSet rs = makeRuleSet(str);
+
+ // 9902
+ Element el = new Way(1);
+ el.addTag("highway", "null_null");
+ el.addTag("layer", "-1");
+
+ GType type = getFirstType(rs, el);
+ assertEquals("9902 layer = -1", 0x1, type.getType());
+
+ // 9912
+ el.addTag("layer", "0");
+ type = getFirstType(rs, el);
+ assertEquals("9912 layer = 0", 0x2, type.getType());
+
+ // 9922
+ el.deleteTag("layer");
+ type = getFirstType(rs, el);
+ assertEquals("9922 no layer tag", 0x8, type.getType());
+
+ // 9932
+ el.addTag("layer", "1");
+ type = getFirstType(rs, el);
+ assertEquals("9932 layer is 1", 0x3, type.getType());
+
+ // 9952
+ el.addTag("layer", "+1");
+ assertEquals("9952 layer is +1", 0x3, type.getType());
+ }
+
+ @Test
+ public void testMultipleActions() {
+ String rstr = "highway=footway {add access = no; add foot = yes} [0x16 road_class=0 road_speed=0 resolution 23]";
+ RuleSet rs = makeRuleSet(rstr);
+
+ Element el = new Way(1);
+ el.addTag("highway", "footway");
+
+ getFirstType(rs, el);
+ assertEquals("access set", "no", el.getTag("access"));
+ assertEquals("access set", "yes", el.getTag("foot"));
+ }
+
+ /**
+ * You can now have a wild card at the top level.
+ */
+ @Test
+ public void testWildcardTop() {
+ RuleSet rs = makeRuleSet("highway=* {set a=fred} [0x1]\n");
+
+ assertNotNull("rule found", rs);
+
+ Element el = new Way(1);
+ el.addTag("highway", "secondary");
+ GType type = getFirstType(rs, el);
+ assertNotNull("can find match", type);
+ assertEquals("correct type", 1, type.getType());
+ assertEquals("tag set", "fred", el.getTag("a"));
+ }
+
+ /**
+ * Deal with cases such as
+ * (a = b | a = c) & d!=*
+ * where there is no key at the top level. This gets converted
+ * to: (a=b & d!=*) | (a=c & d!= *) which can then be used.
+ *
+ * This is applied recursively, so you can have chains of any length.
+ */
+ @Test
+ public void testLeftSideOr() {
+ RuleSet rs = makeRuleSet("(a = b | a = c | a=d) & e!=* [0x2]" +
+ "a=c & e!=* [0x1]");
+
+ assertNotNull("a=b chain", rs);
+ assertNotNull("a=c chain", rs);
+ assertNotNull("a=d chain", rs);
+
+ // get the a=c chain and look at it more closely
+ Element el = new Way(1);
+ el.addTag("a", "c");
+ GType type = getFirstType(rs, el);
+
+ assertNotNull("match e not existing", type);
+ assertEquals("correct type", 2, type.getType());
+
+ el = new Way(2);
+ el.addTag("a", "d");
+ assertNotNull("match e not existing", type);
+ assertEquals("correct type", 2, type.getType());
+ }
+
+ /**
+ * You can now have a wild card at the top level, here we have & between
+ * two of them.
+ */
+ @Test
+ public void testWildcard2() {
+ RuleSet rs = makeRuleSet("highway=* & z=* {set a=square} [0x1]\n");
+
+ assertNotNull("rule found", rs);
+
+ Element el = new Way(1);
+ el.addTag("highway", "secondary");
+ GType type = getFirstType(rs, el);
+ assertNull("type not found with no z tag", type);
+
+ // now add z
+ el.addTag("z", "1");
+ type = getFirstType(rs, el);
+ assertNotNull("found match", type);
+ assertEquals("correct type", 1, type.getType());
+ assertEquals("tag set", "square", el.getTag("a"));
+ }
+
+ /**
+ * Tests for the road classification and other parts of the GType.
+ */
+ @Test
+ public void testGType() {
+ RuleSet rs = makeRuleSet("highway=motorway " +
+ "[0x1 road_class=4 road_speed=7 default_name='motor way']\n");
+
+ Element el = new Way(1);
+ el.addTag("highway", "motorway");
+ GType type = getFirstType(rs, el);
+
+ // Check that the correct class and speed are returned.
+ assertEquals("class", 4, type.getRoadClass());
+ assertEquals("class", 7, type.getRoadSpeed());
+ assertEquals("default name", "motor way", type.getDefaultName());
+ }
+
+ /**
+ * Check for the regexp handling.
+ */
+ @Test
+ public void testRegexp() {
+ RuleSet rs = makeRuleSet("highway=* & name ~ 'blue.*' [0x2]\n");
+
+ assertNotNull("rule found", rs);
+
+ // Set up element with matching name
+ Element el = new Way(1);
+ el.addTag("highway", "secondary");
+ el.addTag("name", "blue sq");
+ GType type = getFirstType(rs, el);
+ assertNotNull("matched regexp", type);
+ assertEquals("matched type", 2, type.getType());
+
+ // change name to one that should not match
+ el.addTag("name", "yellow");
+ type = getFirstType(rs, el);
+ assertNull("no match for yello", type);
+ }
+
+ @Test
+ public void testRegex2() {
+ RuleSet rs = makeRuleSet("a=b & (smoothness ~ '.*(bad|horrible|impassable)' | sac_scale ~ '.*(mountain|alpine)_hiking') [0x1]" +
+ "a = '>=' & b = '>' [0x2]");
+ assertNotNull(rs);
+
+ Element el = new Way(1);
+ el.addTag("a", "b");
+ el.addTag("smoothness", "zzzbad");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull(type);
+
+ assertEquals("matched .*bad", 1, type.getType());
+
+ el = new Way(1);
+ el.addTag("a", "b");
+ el.addTag("sac_scale", "zzz alpine_hiking");
+
+ type = getFirstType(rs, el);
+ assertNotNull(type);
+
+ el = new Way(1);
+ el.addTag("a", "b");
+ el.addTag("sac_scale", "zzz alp_hiking");
+ type = getFirstType(rs, el);
+ assertNull(type);
+
+ el = new Way(1);
+ el.addTag("a", ">=");
+ el.addTag("b", ">");
+ type = getFirstType(rs, el);
+ assertNotNull(type);
+ assertEquals("match string that is the same as an operator", 2, type.getType());
+ }
+
+ /**
+ * Some operations could not originally be used by themselves but now they are converted
+ * into expressions that can be handled automatically. The following few tests verify this.
+ */
+ @Test
+ public void testRegexAtTop() {
+ RuleSet rs = makeRuleSet("QUOTA ~ ' [05]00\\.0+' [0x2]");
+ Element el = new Way(1);
+ el.addTag("QUOTA", " 500.0");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull(type);
+ assertEquals(2, type.getType());
+ }
+
+ @Test
+ public void testNEAtTop() {
+ RuleSet rs = makeRuleSet("QUOTA != 'fred' [0x2]");
+ Element el = new Way(1);
+ el.addTag("QUOTA", "tom");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull(type);
+ assertEquals(2, type.getType());
+ }
+
+ @Test
+ public void testNumberOpAtTop() {
+ RuleSet rs = makeRuleSet("QUOTA > 10 [0x1] QUOTA < 6 [0x2]");
+ Element el = new Way(1);
+ el.addTag("QUOTA", "2");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull(type);
+ assertEquals(2, type.getType());
+ }
+
+ /**
+ * This simply is to make sure that actions that affect their own
+ * conditions do not hang. There are no defined semantics for this.
+ */
+ @Test
+ public void testSelfReference() {
+ RuleSet rs = makeRuleSet("iii=* { set iii=no }");
+ //Rule rule = rs.getMap().get("foot=*");
+ Way el = new Way(1);
+ el.addTag("foot", "yes");
+ el.addTag("iii", "xyz");
+ getFirstType(rs, el);
+ }
+
+ /**
+ * Test the not operator.
+ */
+ @Test
+ public void testNot() {
+ RuleSet rs = makeRuleSet("tunnel=yes & !(route=mtb | route=bicycle) [0x1]");
+ //RuleSet rs = makeRuleSet("tunnel=yes & (route!=mtb & route!=bicycle) [0x1]");
+
+ Way el = new Way(1);
+ el.addTag("tunnel", "yes");
+ el.addTag("route", "abc");
+ getFirstType(rs, el);
+ }
+
+ @Test
+ public void testGTR() {
+ RuleSet rs = makeRuleSet("z=0 & a >= 10 [0x1]");
+
+ Way el = new Way(1);
+ el.addTag("z", "0");
+ el.addTag("a", "9");
+ GType type = getFirstType(rs, el);
+ assertNull("a less that 10, no result", type);
+
+ el.addTag("a", "10");
+ type = getFirstType(rs, el);
+ assertNotNull(type);
+ assertEquals("Valid type returned", 1, type.getType());
+
+ el.addTag("a", "11");
+ type = getFirstType(rs, el);
+ assertNotNull(type);
+ assertEquals("Valid type returned", 1, type.getType());
+ }
+
+ @Test
+ public void testLTE() {
+ RuleSet rs = makeRuleSet("z=0 & a <= 10 [0x1]");
+
+ Way el = new Way(1);
+ el.addTag("z", "0");
+ el.addTag("a", "9");
+ GType type = getFirstType(rs, el);
+ assertNotNull("a less that 10", type);
+ assertEquals("found type for a <= 10", 1, type.getType());
+
+ el.addTag("a", "10");
+ type = getFirstType(rs, el);
+ assertNotNull(type);
+ assertEquals("Found type for a == 10", 1, type.getType());
+
+ el.addTag("a", "11");
+ type = getFirstType(rs, el);
+ assertNull("a is 11, a <= 10 is false", type);
+ }
+
+ @Test
+ public void testNE() {
+ RuleSet rs = makeRuleSet("z=0 & a != 10 [0x1]");
+
+ Way el = new Way(1);
+ el.addTag("z", "0");
+ el.addTag("a", "9");
+ GType type = getFirstType(rs, el);
+ assertNotNull("a is 9 so a!=10 is true", type);
+
+ el.addTag("a", "10");
+ type = getFirstType(rs, el);
+ assertNull("a is 10, so a!=10 is false", type);
+ }
+
+ /**
+ * Test values such as 3.5 in comparisons.
+ * Originally non-integer values were not allowed and were not even recognised.
+ */
+ @Test
+ public void testDecimalValues() {
+ RuleSet rs = makeRuleSet("z=yes & a < 3.5 [0x1]");
+
+ Way el = new Way(1);
+ el.addTag("z", "yes");
+
+ // Is less than so
+ el.addTag("a", "2");
+ GType type = getFirstType(rs, el);
+ assertNotNull("a is less than 3.5", type);
+
+ el.addTag("a", "4");
+ type = getFirstType(rs, el);
+ assertNull("a is greater than 3.5", type);
+ }
+
+ @Test
+ public void testDecimalAndDecimalCompare() {
+ RuleSet rs = makeRuleSet("z=yes & a < 3.5 [0x1]");
+
+ Way el = new Way(1);
+ el.addTag("z", "yes");
+
+ // Is less than so
+ el.addTag("a", "3.49");
+ GType type = getFirstType(rs, el);
+ assertNotNull("a is less than 3.5", type);
+
+ el.addTag("a", "3.55");
+ type = getFirstType(rs, el);
+ assertNull("a is greater than 3.5", type);
+ }
+
+ /**
+ * A moderately complex set of conditions and substitutions.
+ */
+ @Test
+ public void testMtbRules() {
+ RuleSet rs = makeRuleSet(
+ "(mtb:scale=* | mtb:scale:uphill=*) & route=mtb" +
+ "{ name 'mtbrt${mtb:scale|def:.}${mtb:scale:uphill|def:.} ${name}' " +
+ " | 'mtbrt${mtb:scale|def:.}${mtb:scale:uphill|def:.}' }" +
+ " (mtb:scale=* | mtb:scale:uphill=*) & route!=mtb " +
+ "{ name 'mtb${mtb:scale|def:.}${mtb:scale:uphill|def:.} ${name}' " +
+ " | 'mtb${mtb:scale|def:.}${mtb:scale:uphill|def:.}' }"
+
+ );
+
+ Way el = new Way(1);
+ el.addTag("route", "mtb");
+ el.addTag("mtb:scale", "2");
+ getFirstType(rs, el);
+ assertEquals("mtbrt2.", el.getName());
+
+ el = new Way(1);
+ el.addTag("route", "mtb");
+ el.addTag("mtb:scale:uphill", "3");
+ getFirstType(rs, el);
+ assertEquals("mtbrt.3", el.getName());
+
+ el = new Way(1);
+ el.addTag("name", "myname");
+ el.addTag("route", "mtb");
+ el.addTag("mtb:scale:uphill", "3");
+ getFirstType(rs, el);
+ assertEquals("mtbrt.3 myname", el.getName());
+
+ el = new Way(1);
+ el.addTag("mtb:scale:uphill", "3");
+ getFirstType(rs, el);
+ assertEquals("mtb.3", el.getName());
+ }
+
+ /**
+ * Appending to an existing tag.
+ */
+ @Test
+ public void testTagAppend() {
+ RuleSet rs = makeRuleSet(
+ "highway=*{set fullname='${ref}';" +
+ "set fullname='${fullname} ${name}';" +
+ "set fullname='${fullname} ${name1}';" +
+ "set fullname='${fullname} ${name2}';" +
+ "name '${fullname}'}"
+ );
+
+ Way el = new Way(1);
+ el.addTag("highway", "road");
+ el.addTag("ref", "A1");
+ el.addTag("name", "long lane");
+ el.addTag("name1", "foo");
+ el.addTag("name2", "bar");
+
+ getFirstType(rs, el);
+ assertEquals("appended name", "A1 long lane foo bar", el.getName());
+ }
+
+ @Test
+ public void testExists() {
+ RuleSet rs = makeRuleSet("highway=* & maxspeed=40 {set mcssl=40}" +
+ "highway=primary & mcssl=40 [0x2 ]" +
+ "highway=* & mcssl=40 [0x3]");
+ Way el = new Way(1);
+ el.addTag("ref", "A123");
+ el.addTag("name", "Long Lane");
+ el.addTag("highway", "primary");
+ el.addTag("maxspeed", "40");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull("finds the type", type);
+ assertEquals("resulting type", 2, type.getType());
+ }
+
+ /**
+ * Test the continue keyword. If a type is marked with this word, then
+ * further matches are performed and this might result in more types
+ * being added.
+ */
+ @Test
+ public void testContinue() {
+ RuleSet rs = makeRuleSet("highway=primary [0x1 continue]" +
+ "highway=primary [0x2 continue]" +
+ "highway=primary [0x3]" +
+ "highway=primary [0x4]"
+ );
+
+ Way el = new Way(1);
+ el.addTag("highway", "primary");
+
+ final List<GType> list = new ArrayList<GType>();
+
+ rs.resolveType(el, new TypeResult() {
+ public void add(Element el, GType type) {
+ list.add(type);
+ }
+ });
+
+ GType type = list.get(0);
+ assertEquals("first type", 1, type.getType());
+ assertEquals("continue search", true, type.isContinueSearch());
+
+ assertEquals("number of result types", 3, list.size());
+ assertEquals("type of first", 1, list.get(0).getType());
+ assertEquals("type of second", 2, list.get(1).getType());
+ assertEquals("type of third", 3, list.get(2).getType());
+ }
+
+ @Test
+ public void testContinueRepeat() {
+ RuleSet rs = makeRuleSet("highway=primary [0x1 continue]" +
+ "highway=primary [0x2 continue]" +
+ "highway=primary [0x3]" +
+ "highway=primary [0x4]"
+ );
+
+ Way el = new Way(1);
+ el.addTag("highway", "primary");
+
+ for (int i = 0; i < 3; i++) {
+ GType type = getFirstType(rs, el);
+ assertEquals("first type", 1, type.getType());
+ assertEquals("continue search", true, type.isContinueSearch());
+ }
+ }
+
+ /**
+ * The main point of this test is to ensure that all the examples compile.
+ */
+ @Test
+ public void testComplexRegex() {
+ RuleSet rs = makeRuleSet(
+ //"a~b [0x0]" +
+ "a~b & c=d [0x1]" +
+ "a~b & c~d & e=f [0x2]" +
+ "(a~b | c~d) & e=f [0x3]" +
+ "(a~b | c~d) & e=f & g=h [0x4]" +
+ "((a~b | c~d) & e=f) & g=h [0x5]" +
+ "e=f & g=h & (a~b | c~'d.*') [0x6]" +
+ "(e=f & g=h) & (a~b | c~'d.*') [0x7]" +
+ "a=* & b=* & c=d [0x8]" +
+ "a=* & (b=* | c=d) [0x9]" +
+ ""
+ );
+
+ Way el = new Way(1);
+ el.addTag("c", "df");
+ el.addTag("g", "h");
+ el.addTag("e", "f");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull("matches a rule", type);
+ }
+
+ @Test
+ public void testTagsUsed() {
+ RuleSet rs = makeRuleSet("highway=primary & surface=good [0x1]" +
+ "A=B | C=D & E~'f.*' & G!=9 & K=* & L!=* [0x2]");
+
+ Set<String> tags = rs.getUsedTags();
+ assertEquals("number of tags used", 8, tags.size());
+ assertTrue("has highway", tags.contains("highway"));
+ assertTrue("has surface", tags.contains("surface"));
+ assertTrue("has A", tags.contains("A"));
+ assertTrue("has C", tags.contains("C"));
+ assertTrue("has E", tags.contains("E"));
+ assertTrue("has G", tags.contains("G"));
+ assertTrue("has K", tags.contains("K"));
+ assertTrue("has L", tags.contains("L"));
+ }
+
+ /**
+ * There is a case where a tag is only used in an action but not in any
+ * expression. If we dropped the tags it would not be available for the
+ * action. A typical example might be name.
+ */
+ @Test
+ public void testTagsUsedInActions() {
+ RuleSet rs = makeRuleSet("A=B { set t='${C}'; add t='${D} p ${E}'; name '${F} ${G}'; rename K L");
+
+ Set<String> tags = rs.getUsedTags();
+ assertTrue("has A", tags.contains("A"));
+ assertTrue("has C", tags.contains("C"));
+ assertTrue("has D", tags.contains("D"));
+ assertTrue("has E", tags.contains("E"));
+ assertTrue("has F", tags.contains("F"));
+ assertTrue("has G", tags.contains("G"));
+ assertTrue("has K", tags.contains("K"));
+ }
+
+ @Test
+ public void testIncludeAsTagName() {
+ RuleSet rs = makeRuleSet("include=yes [0x2]");
+
+ Way way = new Way(1);
+ way.addTag("include", "yes");
+
+ GType type = getFirstType(rs, way);
+ assertEquals(2, type.getType());
+ }
+
+ @Test
+ public void testIncludeAsTagName2() {
+ RuleSet rs = makeRuleSet("include = yes [0x2]");
+
+ Way way = new Way(1);
+ way.addTag("include", "yes");
+
+ GType type = getFirstType(rs, way);
+ assertEquals(2, type.getType());
+ }
+
+ @Test
+ public void testIncludeFile() {
+ StyleFileLoader loader = new StringStyleFileLoader(new String[][] {
+ {"lines", "include incfile;"},
+ {"incfile", "highway=secondary [0x3]"},
+ });
+
+ RuleSet rs = makeRuleSet(loader);
+ Element el = new Way(1);
+ el.addTag("highway", "secondary");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull(type);
+ assertEquals(3, type.getType());
+ }
+
+ @Test
+ public void testIncludeFileQuoted() {
+ StyleFileLoader loader = new StringStyleFileLoader(new String[][] {
+ {"lines", "include \n 'inc file' \n;"},
+ {"inc file", "highway=secondary [0x3]"},
+ });
+
+ RuleSet rs = makeRuleSet(loader);
+ Element el = new Way(1);
+ el.addTag("highway", "secondary");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull(type);
+ assertEquals(3, type.getType());
+ }
+
+ /**
+ * Test an include file within an include file.
+ */
+ @Test
+ public void testNestedIncludes() {
+ StyleFileLoader loader = new StringStyleFileLoader(new String[][] {
+ {"lines", "a=1 [0x1] include 'first'; a=2 [0x2]"},
+ {"first", "b=1 [0x1] include 'second'; b=2 [0x2 ]"},
+ {"second", "c=1 [0x1] c=2 [0x2 ]"},
+ });
+
+ RuleSet rs = makeRuleSet(loader);
+ Element el = new Way(1);
+
+ el.addTag("a", "2");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull(type);
+ assertEquals(2, type.getType());
+
+ el = new Way(2);
+ el.addTag("c", "1");
+ type = getFirstType(rs, el);
+ assertEquals(1, type.getType());
+
+ el = new Way(2);
+ el.addTag("c", "2");
+ type = getFirstType(rs, el);
+ assertEquals(2, type.getType());
+ }
+
+ /**
+ * Bug when the first statement of an include file is itself an include statement.
+ * As luck would have the test tested the supposedly more difficult case of an
+ * include statement in the middle of the file.
+ */
+ @Test
+ public void testNestedIncludeAndImmediateInclude() {
+ StyleFileLoader loader = new StringStyleFileLoader(new String[][] {
+ {"lines", "a=1 [0x1] include 'first'; a=2 [0x2]"},
+ {"first", "include 'second'; b=2 [0x2 ]"},
+ {"second", "c=1 [0x1] c=2 [0x2 ]"},
+ });
+
+ RuleSet rs = makeRuleSet(loader);
+ Element el = new Way(1);
+
+ el.addTag("a", "2");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull(type);
+ assertEquals(2, type.getType());
+
+ el = new Way(2);
+ el.addTag("c", "1");
+ type = getFirstType(rs, el);
+ assertEquals(1, type.getType());
+
+ el = new Way(2);
+ el.addTag("c", "2");
+ type = getFirstType(rs, el);
+ assertEquals(2, type.getType());
+ }
+
+ @Test
+ public void testIncludeFrom() {
+ // NOTE: this test uses the default style, which could change.
+ StyleFileLoader loader = new StringStyleFileLoader(new String[][] {
+ {"lines", "include 'lines' from default;\n"},
+ });
+ RuleSet rs = makeRuleSet(loader);
+
+ Way way = new Way(1);
+ way.addTag("highway", "motorway");
+ GType type = getFirstType(rs, way);
+ assertNotNull("Check type not null", type);
+ assertEquals(1, type.getType());
+ }
+
+ @Test
+ public void testLengthFunction() {
+ // Its less than 92m
+ RuleSet rs = makeRuleSet("A=B & length() < 92 [0x5]");
+
+ Way el = getWayWithLength();
+ el.addTag("A", "B");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull(type);
+ assertEquals(5, type.getType());
+ }
+
+ @Test
+ public void testLengthFunction2() {
+ // Its more than 91m
+ RuleSet rs = makeRuleSet("A=B & length() > 91 [0x5]");
+
+ Way el = getWayWithLength();
+ el.addTag("A", "B");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull(type);
+ assertEquals(5, type.getType());
+ }
+
+ @Test
+ public void testFunctionWithSpaces() {
+ RuleSet rs = makeRuleSet("A=B & length ( \n) > 91 & length\n()\n < 92 [0x5]");
+ Way el = getWayWithLength();
+ el.addTag("A", "B");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull(type);
+ }
+
+ @Test
+ public void testFunctionWithParameters() {
+ // a parameter in a function is not allowed yet
+ try {
+ // this should throw a SyntaxException
+ makeRuleSet("A=B & length(a) > 91 [0x5]");
+ assertTrue("Function with parameters are not allowed", false);
+ } catch (SyntaxException exp) {
+ }
+ }
+
+ @Test
+ public void testIsClosedFunction() {
+ RuleSet rs = makeRuleSet("A=B & is_closed() = true [0x5]");
+ Way el = getWayForClosedCompleteCheck(true, true);
+
+ GType type = getFirstType(rs, el);
+ assertNotNull(type);
+ assertEquals(5, type.getType());
+
+ Way el2 = getWayForClosedCompleteCheck(false, true);
+ RuleSet rs2 = makeRuleSet("A=B & is_closed() = false [0x5]");
+ GType type2 = getFirstType(rs2, el2);
+ assertNotNull(type2);
+ assertEquals(5, type2.getType());
+ }
+
+ @Test
+ public void testIsCompleteFunction() {
+ RuleSet rs = makeRuleSet("A=B & is_complete() = true [0x5]");
+ Way el = getWayForClosedCompleteCheck(false, true);
+
+ GType type = getFirstType(rs, el);
+ assertNotNull(type);
+ assertEquals(5, type.getType());
+
+ Way el2 = getWayForClosedCompleteCheck(false, false);
+ RuleSet rs2 = makeRuleSet("A=B & is_complete() = false [0x5]");
+ GType type2 = getFirstType(rs2, el2);
+ assertNotNull(type2);
+ assertEquals(5, type2.getType());
+ }
+
+ @Test(expected=SyntaxException.class)
+ public void testNoFunctionParameters() {
+ // a parameter in a function is not allowed for the length() function
+ // this should throw a SyntaxException
+ makeRuleSet("A=B & length(a) > 91 [0x5]");
+ assertTrue("Function with parameters are not allowed", false);
+ }
+
+ /** You can't use length as the only term */
+ @Test(expected=SyntaxException.class)
+ public void testStandAloneLength() {
+ // a parameter in a function is not allowed for the length() function
+ // this should throw a SyntaxException
+ makeRuleSet("length() > 91 [0x5]");
+ }
+
+ @Test(expected = SyntaxException.class)
+ public void testFunctionDoesNotExist() {
+ makeRuleSet("A=B & non_existing_function() > 10 [0x5]");
+ }
+
+ /**
+ * Functions can be restricted to certain files. Eg length() does not make sense on a point.
+ */
+ @Test(expected = SyntaxException.class)
+ public void testLengthInPoints() {
+ StringStyleFileLoader loader = new StringStyleFileLoader(new String[][] {
+ {"points", "A=B & length() < 100"}
+ });
+
+ RuleSet rs = new RuleSet();
+ RuleFileReader rr = new RuleFileReader(FeatureKind.POINT,
+ LevelInfo.createFromString("0:24 1:20 2:18 3:16 4:14"),
+ rs, false, null);
+ try {
+ rr.load(loader, "points");
+ } catch (FileNotFoundException e) {
+ throw new AssertionError("Failed to open file: lines");
+ }
+ }
+
+ /**
+ * A test between something that is not not a value should be caught as a syntax
+ * error.
+ */
+ @Test(expected = SyntaxException.class)
+ public void testWithNonValue() {
+ RuleSet rs = makeRuleSet("c=b & a=!* [0x5]");
+ Way w = getWayWithLength();
+ w.addTag("c", "b");
+ getFirstType(rs, w);
+ }
+
+ @Test(expected = SyntaxException.class)
+ public void testLessThanWithNonValue() {
+ RuleSet rs = makeRuleSet("c=b & a<!* [0x5]");
+ Way w = getWayWithLength();
+ w.addTag("c", "b");
+ getFirstType(rs, w);
+ }
+
+ /**
+ * Test the syntax to get a tag value on the RHS of the expression.
+ */
+ @Test
+ public void testGetTagValueEquality() {
+ RuleSet rs = makeRuleSet("a=b & a=$c [0x5] a=b [0x6]");
+ Way w = new Way(1);
+ w.addTag("a", "b");
+ w.addTag("c", "b");
+
+ GType type = getFirstType(rs, w);
+ assertNotNull(type);
+ assertEquals(5, type.getType());
+
+ w.addTag("c", "x");
+ type = getFirstType(rs, w);
+ assertEquals(6, type.getType());
+ }
+
+ @Test
+ public void testGetTagValueNotFound() {
+ RuleSet rs = makeRuleSet("a=b & b<$c [0x5] a=b [0x6]");
+ Way w = new Way(1);
+ w.addTag("a", "b");
+ w.addTag("b", "50");
+ GType type = getFirstType(rs, w);
+ assertEquals(6, type.getType());
+ }
+
+ @Test
+ public void testGetTagValueAlone() {
+ RuleSet rs = makeRuleSet("a<$b [0x5] a=b [0x6]");
+ Way w = new Way(1);
+ w.addTag("a", "1");
+ w.addTag("b", "2");
+ GType type = getFirstType(rs, w);
+ assertEquals(5, type.getType());
+ }
+
+ /**
+ * Get a way with a few points for testing length.
+ *
+ * The length of this segment was independently confirmed to be around 91m.
+ */
+ private Way getWayWithLength() {
+ Way el = new Way(1);
+ el.addPoint(new Coord(51.6124376, -0.1777185));
+ el.addPoint(new Coord(51.6127816, -0.1775029));
+ el.addPoint(new Coord(51.6132048, -0.1772467));
+ return el;
+ }
+
+ /**
+ * Get a way with a few points for testing the closed and complete flag.
+ * @param closed way should be closed
+ * @param complete way should not be complete
+ */
+ private Way getWayForClosedCompleteCheck(boolean closed, boolean complete) {
+ Way el = new Way(1);
+ el.addTag("A","B");
+ el.addPoint(new Coord(1000,1000));
+ el.addPoint(new Coord(1000,2000));
+ el.addPoint(new Coord(2000,2000));
+ el.addPoint(new Coord(2000,1000));
+ if (closed)
+ el.addPoint(new Coord(1000,1000));
+ el.setComplete(complete);
+ el.setClosed(true);
+ return el;
+ }
+
+
+
+ /**
+ * Resolve the rule set with the given element and get the first
+ * resolved type.
+ */
+ private GType getFirstType(Rule rs, Element el) {
+ final List<GType> types = new ArrayList<GType>();
+ rs.resolveType(el, new TypeResult() {
+ public void add(Element el, GType type) {
+ types.add(type);
+ }
+ });
+ if (types.isEmpty())
+ return null;
+ else
+ return types.get(0);
+ }
+
+}
diff --git a/test/uk/me/parabola/mkgmap/osmstyle/RuleSetTest.java b/test/uk/me/parabola/mkgmap/osmstyle/RuleSetTest.java
new file mode 100644
index 0000000..ef3c7c2
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/osmstyle/RuleSetTest.java
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2009.
+ *
+ * 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.osmstyle;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.GType;
+import uk.me.parabola.mkgmap.reader.osm.Rule;
+import uk.me.parabola.mkgmap.reader.osm.TypeResult;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+
+import org.junit.Test;
+
+import static func.lib.TestUtils.makeRuleSet;
+import static org.junit.Assert.*;
+
+/**
+ * More tests for rule sets. Mostly concentrating on ordering issues and
+ * not on the resulting type.
+ *
+ * @see RuleFileReaderTest
+ */
+public class RuleSetTest {
+ private final String MAXSPEED_EXAMPLE = "highway=* & maxspeed=40mph {set mcssl=40}" +
+ "highway=primary & mcssl=40 [0x01]" +
+ "highway=* & mcssl=40 [0x02]" +
+ "highway=primary [0x3]";
+
+ /**
+ * A test for matching in the correct order with a simple set
+ * of tags. See also the next test.
+ */
+ @Test
+ public void testFirstMatch1() {
+ RuleSet rs = makeRuleSet("c=d & a=b [0x1]" +
+ "a=b & c=d [0x2]" +
+ "a=b [0x3]");
+
+ Way el = new Way(1);
+ el.addTag("a", "b");
+ el.addTag("c", "d");
+ GType type = getFirstType(rs, el);
+ assertNotNull("should be found", type);
+ assertEquals("first matching rule wins", 1, type.getType());
+ }
+ /**
+ * As previous test but with order reversed. Depending on the order
+ * that the tags iterate from the way, you might get different results.
+ */
+ @Test
+ public void testFirstMatch2() {
+ RuleSet rs = makeRuleSet("a=b & c=d [0x1]" +
+ "c=d & a=b [0x2]" +
+ "a=b [0x3]");
+
+ Way el = new Way(1);
+ el.addTag("a", "b");
+ el.addTag("c", "d");
+ GType type = getFirstType(rs, el);
+ assertNotNull("should be found", type);
+ assertEquals("first matching rule wins", 1, type.getType());
+ }
+
+ /**
+ * An action variable is set on a rule that starts with an exists clause.
+ * We then attempt to match on value that it is
+ * @throws Exception
+ */
+ @Test
+ public void testActionVarSetOnExistsRule1() throws Exception {
+ RuleSet rs = makeRuleSet(MAXSPEED_EXAMPLE);
+
+ Way el = new Way(1);
+ el.addTag("highway", "primary");
+ el.addTag("maxspeed", "40mph");
+ el.addTag("ref", "A123");
+ el.addTag("name", "Long Lane");
+
+ GType type = getFirstType(rs, el);
+ assertEquals("should match first", 1, type.getType());
+ }
+
+ @Test
+ public void testActionVarSetOnExistsRule2() {
+ RuleSet rs = makeRuleSet(MAXSPEED_EXAMPLE);
+
+ Way el = new Way(1);
+ el.addTag("highway", "unclassified");
+ el.addTag("maxspeed", "40mph");
+ el.addTag("ref", "A123");
+ el.addTag("name", "Long Lane");
+
+ GType type = getFirstType(rs, el);
+ assertEquals("should match first", 2, type.getType());
+ }
+
+ /**
+ * Check that actions are run in the order given. Use the add command
+ * to set a variable. The first add that is run will be the value of
+ * the variable.
+ */
+ @Test
+ public void testActionOrder() {
+ RuleSet rs = makeRuleSet("b=c {add fred=1}" +
+ "a=b {add fred=2}" +
+ "c=d {add fred=3}" +
+ "a=b [0x1]");
+
+ // All of the conditions are set.
+ Way el = new Way(1);
+ el.addTag("a", "b");
+ el.addTag("b", "c");
+ el.addTag("c", "d");
+
+ getFirstType(rs, el);
+ assertEquals("b=c was first action", "1", el.getTag("fred"));
+ }
+
+ /**
+ * Match on a tag that was set in a previous action rule and was not
+ * on the original element.
+ */
+ @Test
+ public void testMatchOnSetTag() {
+ RuleSet rs = makeRuleSet("highway=yes {set abcxyz = 1}" +
+ "abcxyz=1 [0x1]");
+
+ Way el = new Way(1);
+ el.addTag("highway", "yes");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull("type matched on previously set tag", type);
+ }
+
+ /**
+ * A chain of rules, some of which contain tags from the element and
+ * some that contain only tags that are set in previous rules.
+ */
+ @Test
+ public void testOrderChain() {
+ RuleSet rs = makeRuleSet("z=1 {add fred=1;}" +
+ "fred=1 {add abba=1}" +
+ "z=1 & abba=1 {add destiny=1}" +
+ "destiny=1 [0x1]" +
+ "z=1 [0x2]");
+
+ Way el = new Way(1);
+ el.addTag("z", "1");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull("chain of commands", type);
+ assertEquals("'destiny' should be selected", 1, type.getType());
+ }
+
+ /**
+ * A chain of rules, some of which contain tags from the element and
+ * some that contain only tags that are set in previous rules.
+ */
+ @Test
+ public void testOrderChain2() {
+ RuleSet rs = makeRuleSet("z=1 {add fred=1;}" +
+ "fred=1 {add abba=1}" +
+ "abba=1 {add destiny=1}" +
+ "destiny=1 [0x1]");
+
+ Way el = new Way(1);
+ el.addTag("z", "1");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull("chain of commands", type);
+ }
+
+ /**
+ * Append to a variable in the correct order as in the rule set.
+ */
+ @Test
+ public void testAppendInOrder() {
+ RuleSet rs = makeRuleSet("highway=primary {set R='${R} a'}" +
+ "ref=A1 {set R='${R} b'}" +
+ "z=1 {set R='${R} c'}" +
+ "a=1 {set R='${R} d'}");
+
+ Way el = new Way(1);
+ el.addTag("R", "init");
+ el.addTag("highway", "primary");
+ el.addTag("ref", "A1");
+ el.addTag("z", "1");
+ el.addTag("a", "1");
+
+ getFirstType(rs, el);
+ String s = el.getTag("R");
+ assertEquals("appended value", "init a b c d", s);
+ }
+
+ /**
+ * Rules should only be evaluated once for an element. Because of the
+ * way that we handle rules that may get run after tags are set in actions
+ * it is possible that a rule would get run twice if not careful.
+ *
+ * It is not that easy to trigger, as this is the second attempt at
+ * showing it is possible...
+ */
+ @Test
+ public void testRuleEvaluatedOnce() {
+ RuleSet rs = makeRuleSet("highway=primary " +
+ " {set highway=primary; set result='${result} 1';}" +
+ "highway='primary' {set result='${result} 2'");
+ Way el = new Way(1);
+ el.addTag("highway", "primary");
+ el.addTag("result", "0");
+
+ getFirstType(rs, el);
+ assertEquals("rules run once", "0 1 2", el.getTag("result"));
+ }
+
+ /**
+ * The example that was in the check in comment, make sure it actually
+ * does work ;)
+ */
+ @Test
+ public void testCheckinExample() {
+ RuleSet rs = makeRuleSet("highway=motorway {set blue=true;}\n" +
+ "blue=true [0x1 ]\n" +
+ "highway=motorway [0x2]");
+
+ Way el = new Way(1);
+ el.addTag("highway", "motorway");
+
+ GType type = getFirstType(rs, el);
+ assertEquals("first match is on blue", 1, type.getType());
+ }
+
+ @Test
+ public void testActionsMixedWithTypes() {
+ RuleSet rs = makeRuleSet("highway=primary {set marker=1}" +
+ "marker=2 [0x1]" +
+ "highway=primary {set marker=2}" +
+ "marker=2 [0x2]");
+
+ Way el = new Way(1);
+ el.addTag("highway", "primary");
+
+ GType type = getFirstType(rs, el);
+ assertEquals("second marker rule", 2, type.getType());
+ }
+
+ @Test
+ public void testContinueDefault() {
+ RuleSet rs = makeRuleSet("highway=footway {set surface=good;} [0x1 continue]" +
+ "surface=good [0x20]" +
+ "surface=bad [0x30]");
+
+ Way el = new Way(1);
+ el.addTag("highway", "footway");
+ el.addTag("surface", "bad");
+
+ List<GType> list = resolveList(rs, el);
+ assertEquals("number of lines returned", 2, list.size());
+ assertEquals("surface setting not propagated", "bad", el.getTag("surface"));
+ assertEquals("result type", 0x30, list.get(1).getType());
+ }
+
+ @Test
+ public void testContinuePropagate() {
+ RuleSet rs = makeRuleSet("highway=footway {set surface=good;} [0x1 continue propagate]" +
+ "surface=good [0x20]" +
+ "surface=bad [0x30]");
+
+ Way el = new Way(1);
+ el.addTag("highway", "footway");
+ el.addTag("surface", "bad");
+
+ List<GType> list = resolveList(rs, el);
+ assertEquals("number of lines returned", 2, list.size());
+ assertEquals("surface setting is propagated", "good", el.getTag("surface"));
+ assertEquals("result type", 0x20, list.get(1).getType());
+ }
+
+ @Test
+ public void testContinueNoPropagate() {
+ RuleSet rs = makeRuleSet("highway=footway {set surface=good;} [0x1 continue no_propagate]" +
+ "surface=good [0x20]" +
+ "surface=bad [0x30]");
+
+ Way el = new Way(1);
+ el.addTag("highway", "footway");
+ el.addTag("surface", "bad");
+
+ List<GType> list = resolveList(rs, el);
+ assertEquals("number of lines returned", 2, list.size());
+ assertEquals("surface setting is not propagated", "bad", el.getTag("surface"));
+ assertEquals("result type", 0x30, list.get(1).getType());
+ }
+
+ @Test
+ public void testContinueWithActions() {
+ RuleSet rs = makeRuleSet("highway=footway {set surface=good;} [0x1 continue with_actions]" +
+ "surface=good [0x20]" +
+ "surface=bad [0x30]");
+
+ Way el = new Way(1);
+ el.addTag("highway", "footway");
+ el.addTag("surface", "bad");
+
+ List<GType> list = resolveList(rs, el);
+ assertEquals("number of lines returned", 2, list.size());
+ assertEquals("surface setting is propagated", "good", el.getTag("surface"));
+ assertEquals("result type", 0x20, list.get(1).getType());
+ }
+
+ @Test
+ public void testContinueChangesTag() {
+ RuleSet rs = makeRuleSet("highway=crossing & crossing=zebra_crossing" +
+ " {set highway=deleted_crossing} [0x10404 resolution 24 continue propagate]" +
+ "highway=crossing [0x1010f resolution 24 continue]" +
+ "highway=deleted_crossing [0x6 resolution 24 continue]"
+ );
+
+ Way el = new Way(1);
+ el.addTag("highway", "crossing");
+ el.addTag("crossing", "zebra_crossing");
+
+ List<GType> list = resolveList(rs, el);
+ assertEquals("first element", 0x10404, list.get(0).getType());
+ assertEquals("second element", 0x6, list.get(1).getType());
+ }
+
+ private List<GType> resolveList(RuleSet rs, Way el) {
+ final List<GType> list = new ArrayList<GType>();
+ rs.resolveType(el, new TypeResult() {
+ public void add(Element el, GType type) {
+ list.add(type);
+ }
+ });
+ return list;
+ }
+
+ private GType getFirstType(Rule rs, Element el) {
+ final List<GType> types = new ArrayList<GType>();
+ rs.resolveType(el, new TypeResult() {
+ public void add(Element el, GType type) {
+ types.add(type);
+ }
+ });
+ if (types.isEmpty())
+ return null;
+ else
+ return types.get(0);
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/osmstyle/StyleImplTest.java b/test/uk/me/parabola/mkgmap/osmstyle/StyleImplTest.java
new file mode 100644
index 0000000..a5a1025
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/osmstyle/StyleImplTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2008 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: 30-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle;
+
+import java.io.FileNotFoundException;
+import java.io.OutputStreamWriter;
+
+import uk.me.parabola.mkgmap.reader.osm.Style;
+import uk.me.parabola.mkgmap.reader.osm.StyleInfo;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests for reading in a complete style.
+ */
+public class StyleImplTest {
+ private static final String STYLE_LOC = "classpath:teststyles";
+
+ @Test
+ public void testGetInfo() throws FileNotFoundException {
+ StyleImpl style = new StyleImpl(STYLE_LOC, "simple");
+
+ printStyle(style);
+ StyleInfo info = style.getInfo();
+ assertEquals("version", "2.2", info.getVersion());
+ assertEquals("version", "A simple test style with just one example of most things", info.getSummary());
+ assertEquals("version", "This style is used for testing.", info.getLongDescription());
+ }
+
+ @Test
+ public void testGetOption() throws FileNotFoundException {
+ StyleImpl style = new StyleImpl(STYLE_LOC, "simple");
+
+ String val = style.getOption("levels");
+
+ assertEquals("option levels", "0:24\n1:20", val);
+ }
+
+ @Test
+ public void testEmptyFiles() throws FileNotFoundException {
+ StyleImpl style = new StyleImpl(STYLE_LOC, "empty");
+ assertNotNull("read style ok", style);
+ }
+
+ /**
+ * The case when a style name does not exist. This has always worked in
+ * the way you would expect - there is an error if it does not exist.
+ * @throws FileNotFoundException This should be thrown.
+ */
+ @Test(expected = FileNotFoundException.class)
+ public void testBadStyleName() throws FileNotFoundException {
+ //noinspection UnusedDeclaration
+ Style style = new StyleImpl(STYLE_LOC, "no-such-style");
+ }
+
+ /**
+ * This tests the case when a style-file is given but does not exist.
+ * This has always worked as expected, ie given an error.
+ * @throws FileNotFoundException This should be thrown by the test as the
+ * style does not exist.
+ */
+ @Test(expected = FileNotFoundException.class)
+ public void testBadStyleFileOnClasspath() throws FileNotFoundException {
+ //noinspection UnusedDeclaration
+ Style style = new StyleImpl("classpath:no-such-place", "default");
+ }
+
+ /**
+ * Test the case where a style file location is given that does not exist.
+ * Previously it used to default to classpath:styles if it did not exist
+ * which was confusing.
+ * @throws FileNotFoundException Should be thrown as the style-file
+ * location does not exist.
+ */
+ @Test(expected = FileNotFoundException.class)
+ public void testBadStyleFileOnFilesystem() throws FileNotFoundException {
+ //noinspection UnusedDeclaration
+ Style style = new StyleImpl("/no-such-place/hopefully", "default");
+ }
+
+ private void printStyle(StyleImpl in) {
+ in.dumpToFile(new OutputStreamWriter(System.out));
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/osmstyle/StyledConverterTest.java b/test/uk/me/parabola/mkgmap/osmstyle/StyledConverterTest.java
new file mode 100644
index 0000000..9c40cf1
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/osmstyle/StyledConverterTest.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2008 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: 02-Dec-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.imgfmt.app.CoordNode;
+import uk.me.parabola.mkgmap.general.MapCollector;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapPoint;
+import uk.me.parabola.mkgmap.general.MapRoad;
+import uk.me.parabola.mkgmap.general.MapShape;
+import uk.me.parabola.mkgmap.reader.osm.OsmConverter;
+import uk.me.parabola.mkgmap.reader.osm.Style;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.EnhancedProperties;
+
+import org.junit.Test;
+
+
+/**
+ * High level tests of the complete converter chain, using an actual
+ * rules file.
+ */
+public class StyledConverterTest {
+ private static final String LOC = "classpath:teststyles";
+ private OsmConverter converter;
+ private final List<MapLine> lines = new ArrayList<MapLine>();
+
+ @Test
+ public void testConvertWay() throws FileNotFoundException {
+ converter = makeConverter("simple");
+ Way way = makeWay();
+ way.addTag("highway", "primary");
+ way.addTag("x", "y");
+ converter.convertWay(way);
+ converter.end();
+
+ assertEquals("line converted", 1, lines.size());
+ assertEquals("line from highway", 0x2, lines.get(0).getType());
+ }
+
+ @Test
+ public void testNullPointerFromSecondMatch() throws FileNotFoundException {
+ converter = makeConverter("simple");
+ Way way = makeWay();
+ way.addTag("highway", "primary");
+ way.addTag("x", "z");
+ converter.convertWay(way);
+ converter.end();
+ assertEquals("line converted", 1, lines.size());
+ assertEquals("line from x=y", 0x3, lines.get(0).getType());
+ }
+
+ @Test
+ public void testModifyingTagsInUse() throws FileNotFoundException {
+ Way way = makeWay();
+ way.addTag("name", "bar");
+ way.addTag("highway", "other");
+ way.addTag("a", "z");
+ way.addTag("z", "z");
+ converter = makeConverter("simple");
+ converter.convertWay(way);
+ converter.end();
+
+ assertEquals("line converted", 1, lines.size());
+ assertEquals("line", 0x12, lines.get(0).getType());
+ }
+
+ /**
+ * Test the overlay feature, when one line is duplicated with different
+ * types.
+ */
+ @Test
+ public void testOverlay() throws FileNotFoundException {
+ Way way = makeWay();
+ way.addTag("highway", "overlay");
+ converter = makeConverter("simple");
+ converter.convertWay(way);
+ converter.end();
+
+ assertEquals("lines produced", 3, lines.size());
+ assertEquals("first line is 1", 1, lines.get(0).getType());
+ assertEquals("second line is 2", 2, lines.get(1).getType());
+ assertEquals("third line is 3", 3, lines.get(2).getType());
+ }
+
+ /**
+ * Test styles that are derived from others. Rules should behave as
+ * if they were combined in order with the base rule last.
+ *
+ * This test contains the exact same rule that occurs in the base
+ * style with a different type. It is the derived style type that we
+ * should see.
+ */
+ @Test
+ public void testBaseStyle() throws FileNotFoundException {
+ converter = makeConverter("derived");
+ Way way = makeWay();
+ way.addTag("overridden", "xyz");
+ converter.convertWay(way);
+
+
+ // Now try a rule that is only in the base 'simple' file.
+ way = makeWay();
+ way.addTag("highway", "primary");
+ converter.convertWay(way);
+ converter.end();
+ assertEquals("lines converted", 2, lines.size());
+ assertEquals("derived type", 0x22, lines.get(0).getType());
+ assertEquals("from base style", 0x3, lines.get(1).getType());
+ }
+
+ /**
+ * The derived style has a rule that is not in the base style. Call with
+ * a way that would match a rule in the base style and with the different
+ * rule in the derived style. You should get the type from the derived
+ * style.
+ * @throws FileNotFoundException
+ */
+ @Test
+ public void testOverridePriority() throws FileNotFoundException {
+ converter = makeConverter("derived");
+ Way way = makeWay();
+ way.addTag("highway", "other"); // this would match in the base
+ way.addTag("derived", "first"); // this matches in the derived style
+ converter.convertWay(way);
+ converter.end();
+
+ assertEquals("lines converted", 1, lines.size());
+ assertEquals("derived type", 0x25, lines.get(0).getType());
+ }
+
+ @Test
+ public void testMultipleBase() throws FileNotFoundException {
+
+ convertTag("a", "a");
+ assertEquals(1, lines.get(0).getType());
+
+ convertTag("b", "b");
+ assertEquals(1, lines.get(0).getType());
+
+ convertTag("c", "c");
+ assertEquals(1, lines.get(0).getType());
+
+ convertTag("d", "d");
+ assertEquals(1, lines.get(0).getType());
+
+ convertTag("override", "ab");
+ assertEquals(2, lines.get(0).getType());
+
+ for (String s : new String[]{"ac", "bc"}) {
+ convertTag("override", s);
+ assertEquals(3, lines.get(0).getType());
+ }
+
+ for (String s : new String[]{"ad", "bd", "cd"}) {
+ convertTag("override", s);
+ assertEquals(4, lines.get(0).getType());
+ }
+ }
+
+ private Way convertTag(String key, String value) throws FileNotFoundException {
+ lines.clear();
+ Way way = makeWay();
+ way.addTag(key, value);
+ converter = makeConverter("d");
+ converter.convertWay(way);
+ converter.end();
+ return way;
+ }
+
+ @Test
+ public void testFileConflicts() throws FileNotFoundException {
+ converter = makeConverter("waycombine");
+ Way w = makeWay();
+ w.addTag("highway", "pedestrian");
+ converter.convertWay(w);
+ converter.end();
+
+ assertEquals("lines converted", 1, lines.size());
+
+ // In particular both 1 and 7 are wrong here.
+ assertEquals("found pedestrian type", 6, lines.get(0).getType());
+ }
+
+ @Test
+ public void testFinalizer() throws FileNotFoundException {
+ // test three ways
+ // the first two ways should get the name "OK" by the finalize part
+ // the third way should not be handled by the finalize part
+ String[][] tests = new String[][] {{"residential","OK"}, {"track","OK"},{"secondary",null}};
+
+ for (String[] test : tests ) {
+ // clear the lines list for each test
+ lines.clear();
+ converter = makeConverter("finalize");
+ Way w = makeWay();
+ w.addTag("highway", test[0]);
+ converter.convertWay(w);
+ converter.end();
+
+ assertEquals("lines converted", 1, lines.size());
+ assertEquals("wrong name set by the finalize block", test[1], lines.get(0).getName());
+ }
+
+ // check if continue works
+ lines.clear();
+ converter = makeConverter("finalize");
+ Way w = makeWay();
+ w.addTag("highway", "trunk");
+ converter.convertWay(w);
+ converter.end();
+
+ assertEquals("lines converted", 2, lines.size());
+ assertEquals("wrong name set by the finalize block", "OK", lines.get(0).getName());
+ assertEquals("wrong name set by the finalize block", null, lines.get(1).getName());
+ }
+
+ private Way makeWay() {
+ Way way = new Way(1);
+ way.addPoint(new Coord(100, 100));
+ way.addPoint(new Coord(100, 102));
+ way.addPoint(new Coord(100, 103));
+ return way;
+ }
+
+ private StyledConverter makeConverter(String name) throws FileNotFoundException {
+ Style style = new StyleImpl(LOC, name);
+ MapCollector coll = new MapCollector() {
+ public void addToBounds(Coord p) { }
+
+ // could save points in the same way as lines to test them
+ public void addPoint(MapPoint point) { }
+
+ public void addLine(MapLine line) {
+ // Save line so that it can be examined in the tests.
+ assertNotNull("points are not null", line.getPoints());
+ lines.add(line);
+ }
+
+ public void addShape(MapShape shape) { }
+
+ public void addRoad(MapRoad road) {
+ lines.add(road);
+ }
+
+ public void addRestriction(CoordNode fromNode, CoordNode toNode, CoordNode viaNode, byte exceptMask) { }
+
+ public void addThroughRoute(long junctionNodeId, long roadIdA, long roadIdB) { }
+ };
+
+ return new StyledConverter(style, coll, new EnhancedProperties());
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/osmstyle/TypeReaderTest.java b/test/uk/me/parabola/mkgmap/osmstyle/TypeReaderTest.java
new file mode 100644
index 0000000..180dcb1
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/osmstyle/TypeReaderTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.osmstyle;
+
+import java.io.StringReader;
+
+import uk.me.parabola.mkgmap.general.LevelInfo;
+import uk.me.parabola.mkgmap.reader.osm.FeatureKind;
+import uk.me.parabola.mkgmap.reader.osm.GType;
+import uk.me.parabola.mkgmap.scan.TokenScanner;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class TypeReaderTest {
+
+ @Test
+ public void testLevel() {
+ GType gType = makeType("[0x1 level 2]");
+
+ assertEquals("min level 0", 0, gType.getMinLevel());
+ assertEquals("max level", 2, gType.getMaxLevel());
+
+ assertEquals("min res", 18, gType.getMinResolution());
+ assertEquals("max res", 24, gType.getMaxResolution());
+ }
+
+ @Test
+ public void testLevelRange() {
+ GType gType = makeType("[0x1 level 1-3]");
+
+ assertEquals("min level", 1, gType.getMinLevel());
+ assertEquals("max level", 3, gType.getMaxLevel());
+
+ assertEquals("min res", 16, gType.getMinResolution());
+ assertEquals("min res", 20, gType.getMaxResolution());
+ }
+
+ @Test
+ public void testResolution() {
+ GType gType = makeType("[0x1 resolution 18]");
+
+ assertEquals("min level 0", 0, gType.getMinLevel());
+ assertEquals("max level", 2, gType.getMaxLevel());
+
+ assertEquals("min res", 18, gType.getMinResolution());
+ assertEquals("max res", 24, gType.getMaxResolution());
+ }
+
+ @Test
+ public void testResolutionRange() {
+ GType gType = makeType("[0x1 resolution 16-20]");
+
+ assertEquals("min res", 16, gType.getMinResolution());
+ assertEquals("max res", 20, gType.getMaxResolution());
+
+ assertEquals("min level", 1, gType.getMinLevel());
+ assertEquals("max level", 3, gType.getMaxLevel());
+
+ }
+
+ private GType makeType(String in) {
+ LevelInfo[] levels = LevelInfo.createFromString("0:24 1:20 2:18 3:16 4:14");
+
+ TypeReader tr = new TypeReader(FeatureKind.POLYLINE, levels);
+ TokenScanner ts = new TokenScanner("string", new StringReader(in));
+ ts.setExtraWordChars("-:");
+
+ return tr.readType(ts);
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/osmstyle/actions/AddAccessActionTest.java b/test/uk/me/parabola/mkgmap/osmstyle/actions/AddAccessActionTest.java
new file mode 100644
index 0000000..7fb8f72
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/osmstyle/actions/AddAccessActionTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2013.
+ *
+ * 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.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.osmstyle.StyledConverter;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+public class AddAccessActionTest {
+ private static final String ACCESSVAL = "no";
+
+ /**
+ * If there are no substitutions, then the exact same string is
+ * used.
+ */
+ @Test
+ public void testNoSub() {
+ String value = "fred";
+ Action act = new AddAccessAction(value, false);
+ Element el = stdElement();
+ act.perform(el);
+ for (String accessTag : StyledConverter.ACCESS_TAGS) {
+ assertSame("a not changed", value, el.getTag(accessTag));
+ }
+ }
+
+ /**
+ * Simple test, substituting the whole string.
+ */
+ @Test
+ public void testBareSubst() {
+ Action act = new AddAccessAction("${access}", false);
+
+ Element el = stdElement();
+ act.perform(el);
+
+ for (String accessTag : StyledConverter.ACCESS_TAGS) {
+ assertEquals("subst access", ACCESSVAL, el.getTag(accessTag));
+ }
+ }
+
+ /**
+ * If a substitution tag has no value then the value of the tag is not
+ * changed by the action.
+ */
+ @Test
+ public void testNoValue() {
+ Action act = new AddAccessAction("${noexist}", true);
+ Element el = stdElement();
+ String val = "before";
+ el.addTag("mkgmap:bicycle", val);
+ act.perform(el);
+ assertSame("no substitution", val, el.getTag("mkgmap:bicycle"));
+ }
+
+ /**
+ * If modify is set to false each single access tag should only be set
+ * if it is not already set.
+ */
+ @Test
+ public void testNoOverwriteValue() {
+ Action act = new AddAccessAction("${access}", false);
+ Element el = stdElement();
+ el.addTag("mkgmap:bicycle", "yes");
+ act.perform(el);
+ for (String accessTag : StyledConverter.ACCESS_TAGS) {
+ if ("mkgmap:bicycle".equals(accessTag))
+ assertEquals("no overwrite", "yes", el.getTag(accessTag));
+ else
+ assertEquals("no overwrite", "no", el.getTag(accessTag));
+ }
+ }
+
+ /**
+ * If modify is set to true all access tags should be set
+ * no matter if they are set before.
+ */
+ @Test
+ public void testOverwriteValue() {
+ Action act = new AddAccessAction("${access}", true);
+ Element el = stdElement();
+ el.addTag("mkgmap:bicycle", "yes");
+ act.perform(el);
+ for (String accessTag : StyledConverter.ACCESS_TAGS) {
+ assertEquals("no overwrite", "no", el.getTag(accessTag));
+ }
+ }
+
+
+ /**
+ * The add/set commands now support alternatives just like the name command
+ * has always done.
+ * Several alternatives, but none match.
+ */
+ @Test
+ public void testNoMatchingAlternatives() {
+ AddAccessAction act = new AddAccessAction("${notset}", false);
+ act.add("${hello}");
+ act.add("${world}");
+
+ Element el = stdElement();
+ act.perform(el);
+
+ for (String accessTag : StyledConverter.ACCESS_TAGS)
+ assertNull(accessTag+"a not set", el.getTag(accessTag));
+ }
+
+ /**
+ * Several alternatives and the first one matches.
+ */
+ @Test
+ public void testFirstAlternativeMatches() {
+ AddAccessAction act = new AddAccessAction("${access}", false);
+ act.add("${hello}");
+ act.add("${world}");
+
+ Element el = stdElement();
+ el.addTag("hello", "hello");
+ act.perform(el);
+
+ for (String accessTag : StyledConverter.ACCESS_TAGS)
+ assertEquals(accessTag+" is set", ACCESSVAL, el.getTag(accessTag));
+ }
+
+ /**
+ * Several alternatives and the second one matches.
+ */
+ @Test
+ public void testSecondAlternativeMatches() {
+ AddAccessAction act = new AddAccessAction("${hello}", false);
+ act.add("${access}");
+ act.add("${world}");
+
+ Element el = stdElement();
+ el.addTag("world", "world");
+ act.perform(el);
+
+ for (String accessTag : StyledConverter.ACCESS_TAGS)
+ assertEquals(accessTag+" is set", ACCESSVAL, el.getTag(accessTag));
+ }
+
+ private Element stdElement() {
+ Element el1 = new Way(1);
+ el1.addTag("access", ACCESSVAL);
+ el1.addTag("bicycle", "yes");
+ el1.addTag("foot", "private");
+ el1.addTag("highway", "track");
+ return el1;
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/osmstyle/actions/AddTagActionTest.java b/test/uk/me/parabola/mkgmap/osmstyle/actions/AddTagActionTest.java
new file mode 100644
index 0000000..78ea140
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/osmstyle/actions/AddTagActionTest.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2008 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: 29-Nov-2008
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+public class AddTagActionTest {
+ private static final String REFVAL = "A11";
+ private static final String PLACENAME = "Trefriw";
+
+ /**
+ * If there are no substitutions, then the exact same string is
+ * used.
+ */
+ @Test
+ public void testNoSub() {
+ String value = "fred";
+ Action act = new AddTagAction("a", value, false);
+ Element el = stdElement();
+ act.perform(el);
+ assertSame("a not changed", value, el.getTag("a"));
+ }
+
+ /**
+ * Simple test, substituting the whole string.
+ */
+ @Test
+ public void testBareSubst() {
+ Action act = new AddTagAction("a", "${ref}", false);
+
+ Element el = stdElement();
+ act.perform(el);
+
+ assertEquals("subst ref", REFVAL, el.getTag("a"));
+ }
+
+ /**
+ * Complex string with more than one substitution.
+ */
+ @Test
+ public void testManySubs() {
+ Action act = new AddTagAction("a", "Road ${ref}, name ${name:cy}", false);
+ Element el = stdElement();
+ act.perform(el);
+
+ assertEquals("many substitutions",
+ "Road " + REFVAL + ", name " + PLACENAME,
+ el.getTag("a"));
+ }
+
+ /**
+ * If a substitution tag has no value then the value of the tag is not
+ * changed by the action.
+ */
+ @Test
+ public void testNoValue() {
+ Action act = new AddTagAction("a", "Road ${noexist}, name ${name:cy}", true);
+ Element el = stdElement();
+ String val = "before";
+ el.addTag("a", val);
+ act.perform(el);
+ assertSame("no substitution", val, el.getTag("a"));
+ }
+
+ /**
+ * Test substitutions that get a conversion factor applied to them.
+ */
+ @Test
+ public void testNumberWithUnit() {
+ Action act = new AddTagAction("result", "${ele|conv:m=>ft}", false);
+
+ Element el = stdElement();
+ el.addTag("ele", "100");
+ act.perform(el);
+
+ assertEquals("subst ref", "328", el.getTag("result"));
+ }
+
+ @Test
+ public void testSubstWithDefault() {
+ Action act = new AddTagAction("result", "${ref|def:default-ref}", true);
+
+ Element el = stdElement();
+ act.perform(el);
+
+ assertEquals("ref not defaulted", REFVAL, el.getTag("result"));
+
+ act = new AddTagAction("result", "${ref|def:default-ref}", true);
+ el = stdElement();
+ el.deleteTag("ref");
+ act.perform(el);
+ assertEquals("ref was defaulted", "default-ref", el.getTag("result"));
+ }
+
+ /**
+ * Test for the highway symbol substitution.
+ */
+ @Test
+ public void testHighwaySymbol() {
+ Action act = new AddTagAction("a", "${ref|highway-symbol:hbox}", false);
+
+ Element el = stdElement();
+ act.perform(el);
+
+ // There should be one of the magic garmin values at the beginning
+ // of the string.
+ assertEquals("subst ref", "\u0004" + REFVAL, el.getTag("a"));
+ }
+
+
+ /**
+ * The add/set commands now support alternatives just like the name command
+ * has always done.
+ * Several alternatives, but none match.
+ */
+ @Test
+ public void testNoMatchingAlternatives() {
+ AddTagAction act = new AddTagAction("a", "${notset}", false);
+ act.add("${hello}");
+ act.add("${world}");
+
+ Element el = stdElement();
+ act.perform(el);
+
+ assertNull("a not set", el.getTag("a"));
+ }
+
+ /**
+ * Several alternatives and the first one matches.
+ */
+ @Test
+ public void testFirstAlternativeMatches() {
+ AddTagAction act = new AddTagAction("a", "${val}", false);
+ act.add("${hello}");
+ act.add("${world}");
+
+ Element el = stdElement();
+ el.addTag("val", "has value");
+ el.addTag("hello", "hello");
+ act.perform(el);
+
+ assertEquals("a is set", "has value", el.getTag("a"));
+ }
+
+ /**
+ * Several alternatives and the second one matches.
+ */
+ @Test
+ public void testSecondAlternativeMatches() {
+ AddTagAction act = new AddTagAction("a", "${val}", false);
+ act.add("${hello}");
+ act.add("${world}");
+
+ Element el = stdElement();
+ el.addTag("hello", "hello");
+ el.addTag("world", "world");
+ act.perform(el);
+
+ assertEquals("a is set", "hello", el.getTag("a"));
+ }
+
+ private Element stdElement() {
+ Element el1 = new Way(1);
+ el1.addTag("ref", REFVAL);
+ el1.addTag("name:cy", PLACENAME);
+ return el1;
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/osmstyle/actions/HighwaySymbolFilterTest.java b/test/uk/me/parabola/mkgmap/osmstyle/actions/HighwaySymbolFilterTest.java
new file mode 100644
index 0000000..cd3d81d
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/osmstyle/actions/HighwaySymbolFilterTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008 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 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.
+ */
+/* Create date: 21-Jul-2009 */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+public class HighwaySymbolFilterTest {
+ /**
+ * Basic test for a mostly numeric ref.
+ */
+ @Test
+ public void testDoFilter() {
+ HighwaySymbolFilter filter = new HighwaySymbolFilter("shield");
+ String s = filter.doFilter("A101", null);
+ assertEquals("A101", "\u0002A101", s);
+ }
+
+ /**
+ * If there is one space, then there should be no spaces in the output.
+ */
+ @Test
+ public void testOneSpace() {
+ HighwaySymbolFilter filter = new HighwaySymbolFilter("shield");
+ String s = filter.doFilter("A 101", null);
+ assertEquals("with one space", "\u0002A101", s);
+ }
+
+ /**
+ * If there are multiple spaces, then all are removed.
+ */
+ @Test
+ public void testMultipleSpaces() {
+ HighwaySymbolFilter filter = new HighwaySymbolFilter("shield");
+ String s = filter.doFilter("A 1 01", null);
+ assertEquals("two spaces", "\u0002A101", s);
+ }
+
+ /**
+ * Strings that are mostly alphabetic used to be unchanged but now
+ * are treated exactly the same.
+ */
+ @Test
+ public void testMostlyAlpha() {
+ HighwaySymbolFilter filter = new HighwaySymbolFilter("shield");
+ String value = "AN1";
+ String s = filter.doFilter(value, null);
+ assertEquals("mostly alphabetic", "\002" + value, s);
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/osmstyle/eval/ValueWithUnitTest.java b/test/uk/me/parabola/mkgmap/osmstyle/eval/ValueWithUnitTest.java
new file mode 100644
index 0000000..7324718
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/osmstyle/eval/ValueWithUnitTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.osmstyle.eval;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests for values that may or may not have an associated unit (eg 70mph).
+ */
+public class ValueWithUnitTest {
+
+ @Test
+ public void testBareInteger() {
+ ValueWithUnit val = new ValueWithUnit("23");
+ assertTrue("valid value", val.isValid());
+ }
+
+ @Test
+ public void testInvalidNumber() {
+ ValueWithUnit val = new ValueWithUnit("abc");
+ assertFalse("invalid value", val.isValid());
+ }
+
+ @Test
+ public void testIntegerCompare() {
+ ValueWithUnit val1 = new ValueWithUnit("23");
+ ValueWithUnit val2 = new ValueWithUnit("24");
+
+ assertEquals(-1, val1.compareTo(val2));
+ assertEquals(1, val2.compareTo(val1));
+ }
+
+ @Test
+ public void testDecimalNumber() {
+ ValueWithUnit val = new ValueWithUnit("23.3");
+ assertTrue("valid value", val.isValid());
+ }
+
+ /**
+ * Test that 23.5 is not the same as 23 alone. (Checks that the decimal part
+ * is not being stripped off as the unit.)
+ */
+ @Test
+ public void testDecimalNotEqualToInteger() {
+ ValueWithUnit val1 = new ValueWithUnit("23.5");
+ ValueWithUnit val2 = new ValueWithUnit("23");
+
+ assertEquals(1, val1.compareTo(val2));
+ }
+
+ @Test
+ public void testDecimalCompare() {
+ ValueWithUnit val1 = new ValueWithUnit("23.45");
+ ValueWithUnit val2 = new ValueWithUnit("23.46");
+
+ assertEquals(-1, val1.compareTo(val2));
+ assertEquals(1, val2.compareTo(val1));
+ }
+
+ /**
+ * Make sure that 2.0 is equal to 2 at this level.
+ */
+ @Test
+ public void testCompareWithDifferentScales() {
+ ValueWithUnit val1 = new ValueWithUnit("23");
+ ValueWithUnit val2 = new ValueWithUnit("23.0");
+
+ assertEquals(0, val1.compareTo(val2));
+ assertEquals(0, val2.compareTo(val1));
+ }
+
+ /**
+ * Test something that looks like a number but has two decimal points.
+ * Used to cause an exception.
+ */
+ @Test
+ public void testTwoDPs() {
+ ValueWithUnit val = new ValueWithUnit("de.08315102.reistenhofweg");
+ ValueWithUnit zero = new ValueWithUnit("0");
+ assertEquals(0, val.compareTo(zero));
+ assertFalse(val.isValid());
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/reader/osm/CustomCollectionsTest.java b/test/uk/me/parabola/mkgmap/reader/osm/CustomCollectionsTest.java
new file mode 100644
index 0000000..98d9738
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/reader/osm/CustomCollectionsTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2012.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 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: GerdP
+ */
+
+package uk.me.parabola.mkgmap.reader.osm;
+
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ */
+public class CustomCollectionsTest {
+
+ @Test
+ public void testOSMId2ObjectMap() {
+ testMap(new OSMId2ObjectMap<Long>(), 0L);
+ testMap(new OSMId2ObjectMap<Long>(), -10000L);
+ testMap(new OSMId2ObjectMap<Long>(), 1L << 35);
+ testMap(new OSMId2ObjectMap<Long>(), -1L << 35);
+ }
+
+ private void testMap(OSMId2ObjectMap<Long> map, long idOffset) {
+
+ for (long i = 1; i < 1000; i++) {
+ Long j = map.put(idOffset + i, new Long(i));
+ assertEquals(true, j == null);
+ assertEquals(map.size(), i);
+ }
+
+ for (long i = 1; i < 1000; i++) {
+ boolean b = map.containsKey(idOffset + i);
+ assertEquals(b, true);
+ }
+
+
+ for (long i = 1; i < 1000; i++) {
+ assertEquals((Long)map.get(idOffset + i), new Long(i));
+ }
+
+ // random read access
+ for (long i = 1; i < 1000; i++) {
+ Long key = (long) Math.max(1, (Math.random() * 1000));
+ assertEquals((Long)map.get(idOffset + key), key);
+ }
+
+ for (long i = 1000; i < 2000; i++) {
+ assertEquals(true, (Long)map.get(idOffset + i) == null);
+ }
+
+ for (long i = 1000; i < 2000; i++) {
+ boolean b = map.containsKey(idOffset + i);
+ assertEquals(b, false);
+ }
+ for (long i = 1000; i < 1200; i++) {
+ Long j = map.put(idOffset + i, new Long(333));
+ assertEquals(true, j == null);
+ assertEquals(map.size(), i);
+ }
+ // random read access 2
+ for (int i = 1; i < 1000; i++) {
+ Long key = 1000 + (long) (Math.random() * 200);
+ assertEquals((Long)map.get(idOffset + key), new Long(333));
+ }
+
+
+ for (long i = -2000; i < -1000; i++) {
+ assertEquals(true, map.get(idOffset + i) == null);
+ }
+ for (long i = -2000; i < -1000; i++) {
+ boolean b = map.containsKey(idOffset + i);
+ assertEquals(b, false);
+ }
+ long mapSize = map.size();
+ // seq. update existing records
+ for (int i = 1; i < 1000; i++) {
+ long j = map.put(idOffset + i, new Long (i+333));
+ assertEquals(j, i);
+ assertEquals(map.size(), mapSize);
+ }
+ // random read access 3, update existing entries
+ for (int i = 1; i < 1000; i++) {
+ long j = map.put(idOffset + i, new Long (i+555));
+ assertEquals(true, j == i+333 | j == i+555);
+ assertEquals(map.size(), mapSize);
+ }
+
+ assertEquals(true, map.get(idOffset + 123456) == null);
+ map.put(idOffset + 123456, (long) 999);
+ assertEquals((Long)map.get(idOffset + 123456), new Long(999));
+ map.put(idOffset + 123456, (long) 888);
+ assertEquals((Long)map.get(idOffset + 123456), new Long(888));
+
+ assertEquals(true, map.get(idOffset - 123456) == null);
+ map.put(idOffset - 123456, (long) 999);
+ assertEquals((Long)map.get(idOffset - 123456), new Long(999));
+ map.put(idOffset - 123456, (long) 888);
+ assertEquals((Long)map.get(idOffset - 123456), new Long(888));
+
+ map.clear();
+ assertEquals(map.size(), 0);
+ for (long i = 0; i < 100; i++){
+ map.put(idOffset + i, new Long(i));
+ }
+ Long old = map.remove(idOffset + 5);
+ assertEquals(old, new Long(5));
+ assertEquals(map.size(), 99);
+ assertEquals(true, map.get(idOffset + 5) == null);
+ }
+
+}
diff --git a/test/uk/me/parabola/mkgmap/reader/osm/ElementTest.java b/test/uk/me/parabola/mkgmap/reader/osm/ElementTest.java
new file mode 100644
index 0000000..cff6916
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/reader/osm/ElementTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2008 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: 30-Nov-2008
+ */
+package uk.me.parabola.mkgmap.reader.osm;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+public class ElementTest {
+ /*
+ * Test the iterator.
+ */
+ @Test
+ public void testIterator() {
+ Element el = new Way(1);
+
+ el.addTag("a", "1");
+ el.addTag("b", "2");
+ el.addTag("c", "3");
+
+ Collection<String> l = new ArrayList<String>();
+ for (String s : el) {
+ l.add(s);
+ }
+ assertEquals("list size", 3, l.size());
+
+ Object[] observeds = l.toArray();
+ Arrays.sort(observeds);
+ String[] res = {"a=1", "b=2", "c=3"};
+ Arrays.sort(res);
+ assertArrayEquals("list includes wildcards", res, observeds);
+ }
+
+ @Test
+ public void testEntryIterator() {
+ Element el = new Way(1);
+
+ el.addTag("a", "1");
+ el.addTag("b", "2");
+ el.addTag("c", "3");
+
+ List<String> keys = new ArrayList<String>();
+ List<String> values = new ArrayList<String>();
+
+ for (Map.Entry<String, String> ent : el.getEntryIteratable()) {
+ keys.add(ent.getKey());
+ values.add(ent.getValue());
+ }
+
+ Collections.sort(keys);
+ Collections.sort(values);
+
+ assertArrayEquals("list of keys",
+ new String[] {"a", "b", "c"},
+ keys.toArray());
+
+ assertArrayEquals("list of values",
+ new String[] {"1", "2", "3"},
+ values.toArray());
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/reader/osm/TagsTest.java b/test/uk/me/parabola/mkgmap/reader/osm/TagsTest.java
new file mode 100644
index 0000000..ae9651f
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/reader/osm/TagsTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2008 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: 09-Dec-2008
+ */
+package uk.me.parabola.mkgmap.reader.osm;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+
+public class TagsTest {
+ private static final String[][] SMALL_SET = {
+ {"highway", "primary"},
+ {"a", "1"},
+ {"b", "2"},
+ {"c", "3"},
+ {"d", "4"},
+ };
+
+ private static final String[][] LARGE_SET = {
+ {"jl1", "99"}, {"jl2", "99"}, {"jl3", "99"}, {"jl4", "99"},
+ {"kl1", "99"}, {"kl2", "99"}, {"kl3", "99"}, {"kl4", "99"},
+ {"ll1", "99"}, {"ll2", "99"}, {"ll3", "99"}, {"ll4", "99"},
+ {"ml1", "99"}, {"ml2", "99"}, {"ml3", "99"}, {"ml4", "99"},
+ {"nl1", "99"}, {"nl2", "99"}, {"nl3", "99"}, {"nl4", "99"},
+ {"jL1", "99"}, {"jL2", "99"}, {"jL3", "99"}, {"jL4", "99"},
+ {"kL1", "99"}, {"kL2", "99"}, {"kL3", "99"}, {"kL4", "99"},
+ {"LL1", "99"}, {"LL2", "99"}, {"LL3", "99"}, {"LL4", "99"},
+ {"mL1", "99"}, {"mL2", "99"}, {"mL3", "99"}, {"mL4", "99"},
+ {"nL1", "99"}, {"nL2", "99"}, {"nL3", "99"}, {"nL4", "99"},
+ };
+
+ /**
+ * Not needing a resize.
+ */
+ @Test
+ public void testSmallSet() {
+ Tags tags = smallSetTags();
+
+ for (String[] ss : SMALL_SET) {
+ assertEquals(ss[1], tags.get(ss[0]));
+ }
+ }
+
+ /**
+ * Larger than the initial size, and so will need to be resized.
+ */
+ @Test
+ public void testLargeSet() {
+ Tags tags = new Tags();
+ for (String[] ss : LARGE_SET) {
+ tags.put(ss[0], ss[1]);
+ }
+
+ for (String[] ss : LARGE_SET) {
+ assertEquals(ss[1], tags.get(ss[0]));
+ }
+ }
+
+ /**
+ * Test removing tags.
+ */
+ @Test
+ public void testRemove() {
+ Tags tags = new Tags();
+ for (String[] ss : LARGE_SET)
+ tags.put(ss[0], ss[1]);
+
+ for (String[] ss : SMALL_SET)
+ tags.put(ss[0], ss[1]);
+
+ String[] toRemove = {"highway", "jl1", "d", "ml3", "nl1", "nL4",
+ "kl2", "kl3", "kl4", "kl5"};
+ for (String s : toRemove)
+ tags.remove(s);
+
+ for (String[] ss : LARGE_SET) {
+ if (Arrays.asList(toRemove).contains(ss[0]))
+ assertNull(tags.get(ss[0]));
+ else
+ assertEquals("find for key " + ss[0], ss[1], tags.get(ss[0]));
+ }
+ }
+
+ /**
+ * Create tags initialised with SMALL_SET.
+ */
+ private Tags smallSetTags() {
+ Tags tags = new Tags();
+ for (String[] ts : SMALL_SET)
+ tags.put(ts[0], ts[1]);
+ return tags;
+ }
+
+ /**
+ * Create an iterator over the tags. This must be initialised to the
+ * values in SMALL_SET.
+ * @param tags The tags containing values from SMALL_SET.
+ * @return An iterator that has iterated over all the tags in set.
+ */
+ private Iterator<String> iterateOverTags(Tags tags) {
+ Iterator<String> it = tags.iterator();
+ int n = SMALL_SET.length * 2;
+ for (int i = 0; i < n; i++) {
+ assertTrue(it.hasNext());
+ assertNotNull("result should be non null", it.next());
+ }
+ return it;
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/scan/TokenScannerTest.java b/test/uk/me/parabola/mkgmap/scan/TokenScannerTest.java
new file mode 100644
index 0000000..3ea8c67
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/scan/TokenScannerTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.scan;
+
+import java.io.StringReader;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+public class TokenScannerTest {
+
+ /**
+ * Before reading anything, the line number is zero.
+ */
+ @Test
+ public void testLinenumberStart() {
+ String s = "hello world\nnext tokens\n";
+ TokenScanner ts = new TokenScanner("", new StringReader(s));
+ assertEquals(0, ts.getLinenumber());
+ }
+
+ /**
+ * Immediately after reading the first token the line number is incremented.
+ */
+ @Test
+ public void testLinenumberInc() {
+ String s = "hello world\nnext tokens\n";
+ TokenScanner ts = new TokenScanner("", new StringReader(s));
+ ts.nextValue();
+ assertEquals(1, ts.getLinenumber());
+
+ // still on first line
+ ts.nextValue();
+ assertEquals(1, ts.getLinenumber());
+
+ // now next line
+ ts.nextValue();
+ assertEquals(2, ts.getLinenumber());
+ }
+
+ @Test
+ public void testLinenumberReadline() {
+ String s = "hello world\nnext tokens\n";
+ TokenScanner ts = new TokenScanner("", new StringReader(s));
+ ts.readLine();
+
+ // still on first line
+ assertEquals(1, ts.getLinenumber());
+
+ // now next line
+ ts.nextValue();
+ assertEquals(2, ts.getLinenumber());
+ }
+
+ /**
+ * This is a misfeature of skipSpace, but relied on everywhere.
+ */
+ @Test
+ public void testSkipOfComments() {
+ String s = "hello # some comment\nnext word\n";
+ TokenScanner ts = new TokenScanner("", new StringReader(s));
+
+ assertEquals("hello", ts.nextValue());
+ assertEquals("next", ts.nextValue());
+ }
+
+ /**
+ * Turning off automatic comment skipping.
+ */
+ @Test
+ public void testNoSkipOfComments() {
+ String s = "hello # some comment\nnext word\n";
+ TokenScanner ts = new TokenScanner("", new StringReader(s));
+ ts.setCommentChar(null);
+
+ assertEquals("hello", ts.nextValue());
+ assertEquals("#", ts.nextValue());
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/srt/SrtTextReaderTest.java b/test/uk/me/parabola/mkgmap/srt/SrtTextReaderTest.java
new file mode 100644
index 0000000..354155c
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/srt/SrtTextReaderTest.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2010.
+ *
+ * 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.srt;
+
+import java.io.CharArrayReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+
+import uk.me.parabola.imgfmt.app.srt.Sort;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class SrtTextReaderTest {
+
+ private static final String BASE = "# comment\n" +
+ "\n" +
+ "codepage 1252\n" +
+ "code 01, 02, 03\n";
+
+ /**
+ * Test for a simple case of two letters that have the same major and minor
+ * sort codes.
+ */
+ @Test
+ public void testSimple() throws Exception {
+ char[] sortcodes = getSortcodes("code a, A\n");
+
+ assertEquals("major code", 1, major(sortcodes['a']));
+ assertEquals("major code", 1, major(sortcodes['A']));
+ assertEquals("minor code", 1, minor(sortcodes['a']));
+ assertEquals("minor code", 1, minor(sortcodes['A']));
+ assertEquals("subminor code", 1, subminor(sortcodes['a']));
+ assertEquals("subminor code", 2, subminor(sortcodes['A']));
+ }
+
+ @Test
+ public void testCodePage() throws Exception {
+ String s = "codepage 1252\n";
+ SrtTextReader sr = new SrtTextReader(new CharArrayReader(s.toCharArray()));
+ assertEquals(1252, sr.getSort().getCodepage());
+ }
+
+ @Test
+ public void testDescription() throws Exception {
+ String val = "Euro Sort";
+ String s = String.format("codepage 1252\n" +
+ "description '%s'\n", val);
+ SrtTextReader sr = new SrtTextReader(new CharArrayReader(s.toCharArray()));
+ assertEquals(val, sr.getSort().getDescription());
+ }
+
+ @Test
+ public void testMinorCodes() throws Exception {
+ char[] sortcodes = getSortcodes("code a;b;c\n");
+
+ assertEquals("first", 1, minor(sortcodes['a']));
+ assertEquals("second", 2, minor(sortcodes['b']));
+ assertEquals("third", 3, minor(sortcodes['c']));
+ }
+
+ @Test
+ public void testSpecifyMajorPos() throws Exception {
+ char[] sortcodes = getSortcodes("code pos=0x98 a;b");
+ assertEquals(0x98, major(sortcodes['a']));
+ assertEquals(0x98, major(sortcodes['b']));
+ }
+
+ /**
+ * Letters can be specified by two character hex string.
+ * In this case the hex string is the character in the given codepage.
+ */
+ @Test
+ public void testHexLetters() throws Exception {
+ char[] sortcodes = getSortcodes("code c4;c6");
+ assertEquals(1, major(sortcodes[0xc4]));
+ assertEquals(0, major(sortcodes[0xc5]));
+ assertEquals(1, major(sortcodes[0xc6]));
+
+ }
+
+ @Test
+ public void testPunct() throws Exception {
+ char[] sortcodes = getSortcodes("code !");
+ assertEquals(1, major(sortcodes['!']));
+ }
+
+ /**
+ * Check that 88 is not a letter in 1252.
+ * @throws Exception
+ */
+ @Test
+ public void testNotLetter() throws Exception {
+ Sort sort = getSort("code 88");
+ byte flags = sort.getFlags(0x88);
+
+ assertEquals(0, flags);
+ }
+
+ @Test
+ public void testShortCodeSeparator() throws Exception {
+ char[] sortcodes = getSortcodes("code a < b < c");
+ assertEquals(1, major(sortcodes['a']));
+ assertEquals(2, major(sortcodes['b']));
+ assertEquals(3, major(sortcodes['c']));
+ }
+
+ private char[] getSortcodes(String text) throws IOException {
+ Sort sort = getSort(text);
+ return sort.getSortPositions();
+ }
+
+ private Sort getSort(String text) throws IOException {
+ String s = BASE + text + "\n";
+
+ Reader r = new StringReader(s);
+
+ SrtTextReader srr = new SrtTextReader(r);
+ return srr.getSort();
+ }
+
+ private int major(int code) {
+ return (code >> 8) & 0xff;
+ }
+
+ private int minor(int code) {
+ return (code >> 4) & 0xf;
+ }
+ private int subminor(int code) {
+ return (code & 0xf);
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/typ/TypTextReaderTest.java b/test/uk/me/parabola/mkgmap/typ/TypTextReaderTest.java
new file mode 100644
index 0000000..d43bfbf
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/typ/TypTextReaderTest.java
@@ -0,0 +1,325 @@
+/*
+ * 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.typ;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.io.Reader;
+import java.io.StringReader;
+import java.nio.channels.FileChannel;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.srt.Sort;
+import uk.me.parabola.imgfmt.app.typ.ShapeStacking;
+import uk.me.parabola.imgfmt.app.typ.TYPFile;
+import uk.me.parabola.imgfmt.app.typ.TypData;
+import uk.me.parabola.imgfmt.app.typ.TypLine;
+import uk.me.parabola.imgfmt.app.typ.TypParam;
+import uk.me.parabola.imgfmt.app.typ.TypPoint;
+import uk.me.parabola.imgfmt.app.typ.TypPolygon;
+import uk.me.parabola.imgfmt.sys.FileImgChannel;
+
+import func.lib.ArrayImgWriter;
+import func.lib.TestUtils;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class TypTextReaderTest {
+ private TypTextReader tr;
+ private static final int ORDER_SIZE = 5;
+
+ @Before
+ public void setUp() {
+ }
+
+ @Test
+ public void testIdSection() {
+ tr = makeTyp("[_id]\n" +
+ "FID=24\n" +
+ "ProductCode=2\n" +
+ "CodePage=1251\n" +
+ "[End]");
+
+ TypParam param = tr.getData().getParam();
+ assertEquals(24, param.getFamilyId());
+ assertEquals(2, param.getProductId());
+ assertEquals(1251, param.getCodePage());
+ }
+
+ @Test
+ public void testStacking() {
+
+ tr = makeTyp("[_drawOrder]\n" +
+ "Type=0x3,1\n" +
+ "Type=0x2,2\n" +
+ "Type=0x1,4\n" +
+ "Type=0x4,2\n" +
+ "Type=0x10402,2\n" +
+ "Type=0x10405,2\n" +
+ "[End]\n");
+
+ ShapeStacking stacking = tr.getData().getStacking();
+
+ ArrayImgWriter out = new ArrayImgWriter();
+ stacking.write(out);
+
+ byte[] buf = out.getBytes();
+ assertEquals(3, buf[0]);
+
+ assertEquals(0, buf[ORDER_SIZE]);
+ assertEquals(2, buf[2 * ORDER_SIZE]);
+ assertEquals(4, buf[3 * ORDER_SIZE]);
+ assertEquals(0, buf[3 * ORDER_SIZE + 1]);
+ assertEquals(4, buf[4 * ORDER_SIZE]);
+ assertEquals((1<<2) + (1<<5), buf[4 * ORDER_SIZE + 1]);
+ }
+
+ @Test
+ public void testPolygon() {
+ tr = makeTyp("[_polygon]\n" +
+ "Type=0x2\n" +
+ "String1=0x04,Parking\n" +
+ "String2=0x03,Parkeergarage\n" +
+ "Xpm=\"0 0 2 0\"\n" +
+ "\"1 c #7BCAD5\"\n" +
+ "\"2 c #00008B\"\n" +
+ "[End]\n"
+ );
+
+ TypData data = tr.getData();
+ List<TypPolygon> polygons = data.getPolygons();
+ TypPolygon p = polygons.get(0);
+ assertEquals(2, p.getType());
+ }
+
+ @Test
+ public void testPolygonWithBitmap() {
+ tr = makeTyp("[_polygon]\n" +
+ "Xpm=\"32 32 4 1\"\n" +
+ "\"! c #FFCC99\"\n" +
+ "\" c none\"\n" +
+ "\"3 c #000000\"\n" +
+ "\"4 c none\"\n" +
+ "\"! !!! !!! !!! !!\"\n" +
+ "\" !!! !!! !!! !!!\"\n" +
+ "\" !!! !!! !!! !!! \"\n" +
+ "\" !!! !!! !!! !!! \"\n" +
+ "\" !!! !!! !!! !!! \"\n" +
+ "\" !!! !!! !!! !!! \"\n" +
+ "\"!!! !!! !!! !!! \"\n" +
+ "\"!! !! !! !! \"\n" +
+ "\"! !!! !!! !!! !!\"\n" +
+ "\" !!! !!! !!! !!!\"\n" +
+ "\" !!! !!! !!! !!! \"\n" +
+ "\" !!! !!! !!! !!! \"\n" +
+ "\" !!! !!! !!! !!! \"\n" +
+ "\" !!! !!! !!! !!! \"\n" +
+ "\"!!! !!! !!! !!! \"\n" +
+ "\"!! !! !! !! \"\n" +
+ "\"! !!! !!! !!! !!\"\n" +
+ "\" !!! !!! !!! !!!\"\n" +
+ "\" !!! !!! !!! !!! \"\n" +
+ "\" !!! !!! !!! !!! \"\n" +
+ "\" !!! !!! !!! !!! \"\n" +
+ "\" !!! !!! !!! !!! \"\n" +
+ "\"!!! !!! !!! !!! \"\n" +
+ "\"!! !! !! !! \"\n" +
+ "\"! !!! !!! !!! !!\"\n" +
+ "\" !!! !!! !!! !!!\"\n" +
+ "\" !!! !!! !!! !!! \"\n" +
+ "\" !!! !!! !!! !!! \"\n" +
+ "\" !!! !!! !!! !!! \"\n" +
+ "\" !!! !!! !!! !!! \"\n" +
+ "\"!!! !!! !!! !!! \"\n" +
+ "\"!! !! !! !! \"\n" +
+ "[End]\n");
+
+ TypData data = tr.getData();
+ List<TypPolygon> polygons = data.getPolygons();
+ TypPolygon p = polygons.get(0);
+ ArrayImgWriter out = new ArrayImgWriter();
+ p.write(out, data.getEncoder());
+
+ byte[] bytes = out.getBytes();
+ assertEquals(135, bytes.length);
+ }
+
+ @Test
+ public void testLineTwoColours() {
+ TypTextReader tr = makeTyp("[_line]\n" +
+ "Type=0x00\n" +
+ "UseOrientation=Y\n" +
+ "LineWidth=2\n" +
+ "BorderWidth=1\n" +
+ "Xpm=\"0 0 2 0\"\n" +
+ "\"1 c #DDDDDD\"\n" +
+ "\"2 c #999999\"\n" +
+ "String1=0x04,Road\n" +
+ "String2=0x01,Route non-définie\n" +
+ "String3=0x03,Weg\n" +
+ "ExtendedLabels=Y\n" +
+ "FontStyle=SmallFont\n" +
+ "CustomColor=No\n" +
+ "[end]");
+
+ TypData data = tr.getData();
+ TypLine line = data.getLines().get(0);
+ ImgFileWriter w = new ArrayImgWriter();
+ line.write(w, data.getEncoder());
+ }
+
+ @Test
+ public void testPointWithAlpha() {
+ TestUtils.registerFile("hello");
+ TypTextReader tr = makeTyp("[_point]\n" +
+ "Type=0x12\n" +
+ "SubType=0x01\n" +
+ ";23E6\n" +
+ ";size: 45\n" +
+ "String1=0x4,Mini round\n" +
+ "String2=0x1,Mini rond-point\n" +
+ "ExtendedLabels=N\n" +
+ "DayXpm=\"9 9 10 1\"\n" +
+ "\"$ c none\"\n" +
+ "\"% c #808080\" alpha=14\n" +
+ "\"& c #808080\"\n" +
+ "\"' c #808080\" alpha=15\n" +
+ "\"( c #808080\" alpha=8\n" +
+ "\") c #F0F7FF\"\n" +
+ "\"* c #808080\" alpha=4\n" +
+ "\"+ c #808080\" alpha=11\n" +
+ "\", c #808080\" alpha=12\n" +
+ "\"- c #808080\" alpha=13\n" +
+ "\"$%&&&&&'$\"\n" +
+ "\"(&&&)&&&*\"\n" +
+ "\"&&)))))&&\"\n" +
+ "\"&&)&&&)&&\"\n" +
+ "\"&))&)&))&\"\n" +
+ "\"&&)&&&)&&\"\n" +
+ "\"&&)))))&&\"\n" +
+ "\"+&&&)&&&,\"\n" +
+ "\"$-&&&&&-$\"\n" +
+ "[end]"
+ );
+
+ TypData data = tr.getData();
+ TypPoint point = data.getPoints().get(0);
+ ArrayImgWriter w = new ArrayImgWriter();
+ point.write(w, data.getEncoder());
+ System.out.println("size " + w.getSize());
+ try {
+ OutputStream os = new FileOutputStream("hello");
+ os.write(w.getBytes());
+ os.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ assertEquals(115, w.getBytes().length);
+
+ }
+
+ @Test
+ public void testZeroColourBug() {
+ String s = "[_point]\n" +
+ "Type=0x01e\n" +
+ "SubType=0x00\n" +
+ "String1=0x04,island\n" +
+ "DayXpm=\"5 5 1 1\" Colormode=32\n" +
+ "\"! c #000000\" canalalpha=15\n" +
+ "\"!!!!!\"\n" +
+ "\"!!!!!\"\n" +
+ "\"!!!!!\"\n" +
+ "\"!!!!!\"\n" +
+ "\"!!!!!\"\n" +
+ "[end]";
+
+ tr = makeTyp(s);
+ TypData data = tr.getData();
+ TypPoint point = data.getPoints().get(0);
+
+ ArrayImgWriter w = new ArrayImgWriter();
+ point.write(w, data.getEncoder());
+
+ byte[] out = w.getBytes();
+
+ assertEquals("width", 5, out[1]);
+ assertEquals("height", 5, out[2]);
+ assertEquals("number of colours", 1, out[3]);
+ }
+
+ /**
+ * Basic test, reading from a file using most features.
+ */
+ @Test
+ public void testFromFile() throws IOException {
+ TestUtils.registerFile("test.typ");
+ Reader r = new BufferedReader(new FileReader("test/resources/typ/test.txt"));
+ TypTextReader tr = new TypTextReader();
+ tr.read("test.typ", r);
+
+ TestUtils.registerFile("ts__test.typ");
+ RandomAccessFile raf = new RandomAccessFile("ts__test.typ", "rw");
+ FileChannel channel = raf.getChannel();
+ channel.truncate(0);
+ FileImgChannel w = new FileImgChannel(channel);
+ TYPFile typ = new TYPFile(w);
+
+ typ.setData(tr.getData());
+ typ.write();
+ typ.close();
+ }
+
+ /**
+ * Check that unknown sections don't throw an exception and are ignored without
+ * affecting anything else.
+ */
+ @Test
+ public void testIgnoreUnknownSections() {
+ tr = makeTyp("[_unknown_section_name]\n" +
+ "Type=0x2\n" +
+ "String1=0x04,Parking\n" +
+ "String2=0x03,Parkeergarage\n" +
+ "OtherStuff=Unknown\n" +
+ "[End]\n" +
+ "[_id]\n" +
+ "FID=4455\n" +
+ "ProductCode=2\n" +
+ "CodePage=1251\n" +
+ "[End]"
+ );
+
+ TypData data = tr.getData();
+ System.out.println(data);
+ assertEquals(4455, data.getParam().getFamilyId());
+ }
+
+ private TypTextReader makeTyp(String in) {
+ Reader r = new StringReader(in);
+
+ TypTextReader tr = new TypTextReader();
+ tr.read("string", r);
+ if (tr.getData().getSort() == null)
+ tr.getData().setSort(Sort.defaultSort(1252));
+ return tr;
+ }
+}
diff --git a/test/uk/me/parabola/util/Java2DConverterTest.java b/test/uk/me/parabola/util/Java2DConverterTest.java
new file mode 100644
index 0000000..46a7551
--- /dev/null
+++ b/test/uk/me/parabola/util/Java2DConverterTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2006, 2012.
+ *
+ * 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.util;
+
+import java.awt.geom.Area;
+import java.awt.geom.Path2D;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class Java2DConverterTest {
+
+ /**
+ * Test if a polygon converted and converted back is equal
+ */
+ @Test
+ public void testPolygonConversion() throws Exception {
+ List<Coord> polygon = new ArrayList<Coord>();
+ polygon.add(new Coord(0,0));
+ polygon.add(new Coord(100,10));
+ polygon.add(new Coord(120,89));
+ polygon.add(new Coord(20,44));
+ polygon.add(new Coord(50,43));
+ polygon.add(new Coord(0,0)); // Note that shape is not closed with identical points
+
+ Area a = Java2DConverter.createArea(polygon);
+ List<List<Coord>> convPolygon = Java2DConverter.areaToShapes(a);
+ List<Coord> singularPolygon = Java2DConverter.singularAreaToPoints(a);
+
+ assertEquals(convPolygon.size(), 1);
+ assertEquals(polygon, convPolygon.get(0));
+ assertEquals(polygon, singularPolygon);
+ assertTrue(convPolygon.get(0).get(0) == convPolygon.get(0).get(convPolygon.get(0).size()-1));
+ assertTrue(singularPolygon.get(0) == singularPolygon.get(singularPolygon.size()-1));
+ }
+
+ @Test
+ public void testPolygonConversionWithEqualPoints() throws Exception {
+ Path2D path1 = new Path2D.Double();
+ Path2D path2 = new Path2D.Double();
+ Path2D path3 = new Path2D.Double();
+ path1.moveTo(0,0);
+ path1.lineTo(100,-10);
+ path1.lineTo(50,-43);
+ path1.closePath();
+
+ path2.moveTo(0,0);
+ path2.lineTo(100,-10);
+ path2.lineTo(50,-43);
+ path2.lineTo(-0.0001,0); // point that is equal to closing points (in map units)
+ path2.closePath();
+
+ path3.moveTo(0,0);
+ path3.lineTo(100,-10);
+ path3.lineTo(50,-43);
+ path3.lineTo(-0.5001,0); // point that is not equal to closing points (in map units)
+ path3.closePath();
+
+ Area a1 = new Area(path1);
+ Area a2 = new Area(path2);
+ Area a3 = new Area(path3);
+
+ List<List<Coord>> convPolygon1 = Java2DConverter.areaToShapes(a1);
+ List<List<Coord>> convPolygon2 = Java2DConverter.areaToShapes(a2);
+ List<List<Coord>> convPolygon3 = Java2DConverter.areaToShapes(a3);
+ List<Coord> singularPolygon1 = Java2DConverter.singularAreaToPoints(a1);
+ List<Coord> singularPolygon2 = Java2DConverter.singularAreaToPoints(a2);
+ List<Coord> singularPolygon3 = Java2DConverter.singularAreaToPoints(a3);
+
+ assertTrue(a1.equals(a2) == false);
+ assertTrue(a1.equals(a3) == false);
+ assertTrue(a2.equals(a3) == false);
+ assertEquals(1, convPolygon1.size());
+ assertEquals(1, convPolygon2.size());
+ assertEquals(1, convPolygon3.size());
+ assertTrue(Arrays.deepEquals(convPolygon1.toArray(), convPolygon2.toArray()) == true);
+ assertTrue(Arrays.deepEquals(convPolygon1.toArray(), convPolygon3.toArray()) == false);
+ assertEquals(4, convPolygon1.get(0).size());
+ assertEquals(4, convPolygon2.get(0).size());
+ assertEquals(5, convPolygon3.get(0).size());
+ assertEquals(4,singularPolygon1.size());
+ assertEquals(4,singularPolygon2.size());
+ assertEquals(5,singularPolygon3.size());
+
+ assertTrue(convPolygon1.get(0).get(0) == convPolygon1.get(0).get(convPolygon1.get(0).size()-1));
+ assertTrue(convPolygon2.get(0).get(0) == convPolygon2.get(0).get(convPolygon2.get(0).size()-1));
+ assertTrue(convPolygon3.get(0).get(0) == convPolygon3.get(0).get(convPolygon3.get(0).size()-1));
+ assertTrue(singularPolygon1.get(0) == singularPolygon1.get(singularPolygon1.size()-1));
+ assertTrue(singularPolygon2.get(0) == singularPolygon2.get(singularPolygon2.size()-1));
+ assertTrue(singularPolygon3.get(0) == singularPolygon3.get(singularPolygon3.size()-1));
+ }
+}
--
Generate Garmin maps from OpenStreetMap data
More information about the Pkg-grass-devel
mailing list