]> Shamusworld >> Repos - ttedit/commitdiff
Move main repo to trunk.
authorShamus Hammons <jlhamm@acm.org>
Tue, 29 May 2007 17:15:58 +0000 (17:15 +0000)
committerShamus Hammons <jlhamm@acm.org>
Tue, 29 May 2007 17:15:58 +0000 (17:15 +0000)
33 files changed:
Makefile [new file with mode: 0755]
res/cur1.xpm [new file with mode: 0755]
res/cur2.xpm [new file with mode: 0755]
res/cur3.xpm [new file with mode: 0755]
res/cur4.xpm [new file with mode: 0755]
res/cur5.xpm [new file with mode: 0755]
res/cur6.xpm [new file with mode: 0755]
res/cur7.xpm [new file with mode: 0755]
res/cur8.xpm [new file with mode: 0755]
res/tool1.xpm [new file with mode: 0755]
res/tool2.xpm [new file with mode: 0755]
res/tool3.xpm [new file with mode: 0755]
res/toolpal1.xpm [new file with mode: 0755]
res/ttedit.xpm [new file with mode: 0755]
src/bezier.cpp [new file with mode: 0755]
src/bezier.h [new file with mode: 0755]
src/charnames.cpp [new file with mode: 0755]
src/charnames.h [new file with mode: 0755]
src/debug.cpp [new file with mode: 0755]
src/debug.h [new file with mode: 0755]
src/glyphpoints.cpp [new file with mode: 0755]
src/glyphpoints.h [new file with mode: 0755]
src/list.h [new file with mode: 0755]
src/registry.cpp [new file with mode: 0755]
src/registry.h [new file with mode: 0755]
src/tte_res.h [new file with mode: 0755]
src/ttedit.cpp [new file with mode: 0755]
src/ttedit.h [new file with mode: 0755]
src/ttf.cpp [new file with mode: 0755]
src/ttf.h [new file with mode: 0755]
src/types.h [new file with mode: 0755]
src/vector.cpp [new file with mode: 0755]
src/vector.h [new file with mode: 0755]

diff --git a/Makefile b/Makefile
new file mode 100755 (executable)
index 0000000..75a82fa
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,184 @@
+#
+# Makefile for TrueType Edit
+#
+# Author:     James Hammons
+# Copyright:  (c) 2006 Underground Software
+#
+
+ifeq "$(OSTYPE)" "msys"                                                        # Win32
+
+SYSTYPE    = __GCCWIN32__
+EXESUFFIX  = .exe
+ICON       = obj/icon.o
+MSG        = Win32 on MinGW
+
+else
+#ifeq "$(OSTYPE)" "darwin"
+ifeq "darwin" "$(findstring darwin,$(OSTYPE))" # Should catch both 'darwin' and 'darwin7.0'
+
+SYSTYPE    = __GCCUNIX__ -D_OSX_
+EXESUFFIX  =
+ICON       =
+MSG        = Mac OS X
+
+else                                                                                   # *nix
+
+SYSTYPE    = __GCCUNIX__
+EXESUFFIX  =
+ICON       =
+MSG        = generic Unix/Linux
+
+endif
+endif
+
+# This is ugly, ugly, ugly. Find a way to fix this crap so it's more unified,
+# like the SDL based makefiles are... !!! FIX !!! [made initial stab at it]
+
+### Variables: ###
+
+#EXEEXT = .exe
+RESCOMP = windres
+srcdir = ./src
+top_srcdir = /local
+top_builddir = /local/
+CXX = g++
+TOOLKIT = MSW
+TOOLKIT_LOWERCASE = msw
+WX_RELEASE = 2.6
+WX_VERSION = $(WX_RELEASE).0
+
+# This is OK
+
+# Note that the -MMD flag is what gives us our automagic dependency information (*.d files)
+# Add -g to compile in debuggin information
+CXXFLAGS = -MMD -Wall -Wno-switch -Wno-non-virtual-dtor -O2 `wx-config --cxxflags` -g
+INCS = -I.
+LIBS = `wx-config --libs`
+
+PROGRAM = ttedit
+
+# KO si sihT
+
+OBJECTS  =            \
+       obj/bezier.o      \
+       obj/charnames.o   \
+       obj/debug.o       \
+       obj/glyphpoints.o \
+       obj/registry.o    \
+       obj/ttf.o         \
+       obj/vector.o      \
+       obj/$(PROGRAM).o  \
+       $(ICON)
+
+BIN_PROGRAM = $(PROGRAM)$(EXESUFFIX)
+#Need to fix this shit
+ifneq "" "$(ICON)"
+RES_PROGRAM_OBJ = obj/$(PROGRAM)_resources.o
+else
+RES_PROGRAM_OBJ =
+endif
+BUNDLE = $(BIN_PROGRAM).app/Contents
+
+### Conditionally set variables: ###
+
+COND_TOOLKIT_MAC___MACOSX_RESOURCES_p_1 = $(RESCOMP) -d __DARWIN__ -t APPL -d \
+       __WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p_1) $(__EXCEPTIONS_DEFINE_p_1) \
+       $(__RTTI_DEFINE_p_1) $(__THREAD_DEFINE_p_1) -i $(srcdir) -d WXUSINGDLL -i \
+       $(srcdir)/../../samples -i $(top_srcdir)/include -o bombs$(EXEEXT) Carbon.r \
+       sample.r
+
+### Targets: ###
+
+all: checkenv message obj $(BIN_PROGRAM) $(__bombs_bundle___depname)
+       @echo
+       @echo "*** Looks like it compiled OK... Give it a whirl!"
+
+obj:
+       @mkdir obj
+
+#install: all
+
+# Check the compilation environment, barf if not appropriate
+
+checkenv:
+       @echo
+       @echo -n "*** Checking compilation environment... "
+ifeq "" "$(shell which wx-config)"
+       @echo
+       @echo
+       @echo "It seems that you don't have the wxWidget development libraries installed."
+       @echo "If you have installed them, make sure that the wx-config file is somewhere"
+       @echo "in your path and is executable."
+       @echo
+#Is there a better way to break out of the makefile?
+#      @break
+       @breakola!
+else
+       @echo "OK"
+endif
+
+message:
+#      @echo
+       @echo "*** Building TTEdit for $(MSG)..."
+       @echo
+
+clean:
+       @echo -n "*** Cleaning out the garbage..."
+       @rm -rf ./obj
+       @rm -f $(BIN_PROGRAM)
+#      rm -rf bombs.app
+       @echo "done!"
+
+## This is only done for Win32 at the moment...
+#
+#ifneq "" "$(ICON)"
+#$(ICON): res/$(TARGET).rc res/$(TARGET).ico
+#      @echo "*** Processing icon..."
+#      @windres -i res/$(TARGET).rc -o $(ICON) --include-dir=./res
+#endif
+
+# This is only done for Win32 at the moment...
+
+ifneq "" "$(ICON)"
+$(RES_PROGRAM_OBJ): res/$(PROGRAM).rc res/$(PROGRAM).ico
+       @echo "*** Processing icon..."
+       @$(RESCOMP) -i$< -o$@ --define __WX$(TOOLKIT)__ --include-dir ./res --define WXUSINGDLL --include-dir $(top_srcdir)/include/wx-2.6
+endif
+
+obj/%.o: $(srcdir)/%.cpp
+       @echo "*** Compiling $<..."
+       @$(CXX) -c -o $@ $(INCS) $(CXXFLAGS) $<
+
+$(BIN_PROGRAM): $(OBJECTS) $(RES_PROGRAM_OBJ)
+       @echo "*** Linking it all together..."
+       @$(CXX) -o $@ $(OBJECTS) $(RES_PROGRAM_OBJ) $(LIBS)
+#      $(_mac_rezcmd)
+#      $(_mac_setfilecmd)
+
+# Mac OSX bundling shit (figure out how to condense this so it works!)
+
+bombs.app/Contents/PkgInfo: bombs$(EXEEXT) $(top_srcdir)/src/mac/carbon/Info.plist.in $(top_srcdir)/src/mac/carbon/wxmac.icns
+       mkdir -p bombs.app/Contents
+       mkdir -p bombs.app/Contents/MacOS
+       mkdir -p bombs.app/Contents/Resources
+
+       sed -e "s/IDENTIFIER/`echo $(srcdir) | sed -e 's,\.\./,,g' | sed -e 's,/,.,g'`/" \
+       -e "s/EXECUTABLE/bombs/" \
+       -e "s/VERSION/$(WX_VERSION)/" \
+       $(top_srcdir)/src/mac/carbon/Info.plist.in >bombs.app/Contents/Info.plist
+
+       echo -n "APPL????" >bombs.app/Contents/PkgInfo
+
+       ln -f bombs$(EXEEXT) bombs.app/Contents/MacOS/bombs
+
+       cp -f $(top_srcdir)/src/mac/carbon/wxmac.icns bombs.app/Contents/Resources/wxmac.icns
+
+#bundle: $(_BUNDLE_TGT_REF_DEP)
+
+### Include dependency info, if present:
+
+-include ./obj/*.d
+
+### No idea what this does
+
+#.PHONY: all install uninstall clean distclean bundle
diff --git a/res/cur1.xpm b/res/cur1.xpm
new file mode 100755 (executable)
index 0000000..46c1adf
--- /dev/null
@@ -0,0 +1,37 @@
+/* XPM */\r
+static char * cur1_xpm[] = {\r
+"32 32 2 1",\r
+"      g #000000",\r
+".     g #FFFFFF",\r
+" ...............................",\r
+"  ..............................",\r
+"   .............................",\r
+"    ............................",\r
+"     ...........................",\r
+"      ..........................",\r
+"       .........................",\r
+"        ........................",\r
+"         .......................",\r
+"          ......................",\r
+"           .....................",\r
+"            ....................",\r
+"       .........................",\r
+"       .........................",\r
+"   ..   ........................",\r
+"  ...   ........................",\r
+" .....   .......................",\r
+"......   .......................",\r
+".......   ......................",\r
+".......  .......................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................"};\r
diff --git a/res/cur2.xpm b/res/cur2.xpm
new file mode 100755 (executable)
index 0000000..4a33bca
--- /dev/null
@@ -0,0 +1,37 @@
+/* XPM */\r
+static char * cur2_xpm[] = {\r
+"32 32 2 1",\r
+"      g #000000",\r
+".     g #FFFFFF",\r
+" ...............................",\r
+"  ..............................",\r
+"   .............................",\r
+"    ............................",\r
+"     ...........................",\r
+"      ..........................",\r
+"       .........................",\r
+"        ........................",\r
+"         .......................",\r
+"          ......................",\r
+"           .....................",\r
+"            ....................",\r
+"       .........................",\r
+"       ......      .............",\r
+"   ..   .....       ............",\r
+"  ...   .....  ...  ............",\r
+" .....   ....  ...  ............",\r
+"......   ....  ...  ............",\r
+".......   ...       ............",\r
+".......  ....      .............",\r
+".............  .................",\r
+".............  .................",\r
+".............  .................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................"};\r
diff --git a/res/cur3.xpm b/res/cur3.xpm
new file mode 100755 (executable)
index 0000000..595a360
--- /dev/null
@@ -0,0 +1,37 @@
+/* XPM */\r
+static char * cur3_xpm[] = {\r
+"32 32 2 1",\r
+"      g #FFFFFF",\r
+".     g #000000",\r
+"          ..                    ",\r
+"          ..                    ",\r
+"         ....                   ",\r
+"         ....                   ",\r
+"        ......                  ",\r
+"        . .. .                  ",\r
+"      .   ..   .                ",\r
+"          ..                    ",\r
+"    ..    ..    ..              ",\r
+"  ...    .  .    ...            ",\r
+"......... .. .........          ",\r
+"......... .. .........          ",\r
+"  ...    .  .    ...            ",\r
+"    ..    ..    ..              ",\r
+"          ..                    ",\r
+"      .   ..   .                ",\r
+"        . .. .                  ",\r
+"        ......                  ",\r
+"        .....                   ",\r
+"         ....                   ",\r
+"          ..                    ",\r
+"          ..                    ",\r
+"                                ",\r
+"                                ",\r
+"                                ",\r
+"                                ",\r
+"                                ",\r
+"                                ",\r
+"                                ",\r
+"                                ",\r
+"                                ",\r
+"                                "};\r
diff --git a/res/cur4.xpm b/res/cur4.xpm
new file mode 100755 (executable)
index 0000000..86c2141
--- /dev/null
@@ -0,0 +1,37 @@
+/* XPM */\r
+static char * cur4_xpm[] = {\r
+"32 32 2 1",\r
+"      g #FFFFFF",\r
+".     g #000000",\r
+"  ..                            ",\r
+"  ..                            ",\r
+"......                          ",\r
+"......                          ",\r
+"  ..                            ",\r
+"  ..                            ",\r
+"             ...                ",\r
+"  ..       ..   ..              ",\r
+"  ..      ..     ..             ",\r
+" ....     .  .    .             ",\r
+" ....    .  .      .            ",\r
+"......   . .       .            ",\r
+". .. .   . .       .            ",\r
+"  ..     .         .            ",\r
+"  ..     .         .            ",\r
+"  ..      .       .             ",\r
+"  ..      ..     ..             ",\r
+"  ..       ..   ...             ",\r
+"  ..         ...   .            ",\r
+". .. .              .           ",\r
+"......               ..         ",\r
+" ....                ...        ",\r
+" ....                 ...       ",\r
+"  ..                   ...      ",\r
+"  ..                    .       ",\r
+"                                ",\r
+"                                ",\r
+"......                          ",\r
+"......                          ",\r
+"                                ",\r
+"                                ",\r
+"                                "};\r
diff --git a/res/cur5.xpm b/res/cur5.xpm
new file mode 100755 (executable)
index 0000000..9bc1b35
--- /dev/null
@@ -0,0 +1,37 @@
+/* XPM */\r
+static char * cur5_xpm[] = {\r
+"32 32 2 1",\r
+"      g #000000",\r
+".     g #FFFFFF",\r
+" ...............................",\r
+"  ..............................",\r
+"   .............................",\r
+"    ............................",\r
+"     ...........................",\r
+"      ..........................",\r
+"       .........................",\r
+"        ........................",\r
+"         .......................",\r
+"          ......................",\r
+"           .....................",\r
+"            ....................",\r
+"       .........................",\r
+"       .........................",\r
+"   ..   ........................",\r
+"  ...   ........................",\r
+" .....   .......................",\r
+"......   .....    ..............",\r
+".......   ...      .............",\r
+".......  ....  ..  .............",\r
+".............  ..  .............",\r
+".............      .............",\r
+"..............    ..............",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................"};\r
diff --git a/res/cur6.xpm b/res/cur6.xpm
new file mode 100755 (executable)
index 0000000..bf24733
--- /dev/null
@@ -0,0 +1,37 @@
+/* XPM */\r
+static char * cur6_xpm[] = {\r
+"32 32 2 1",\r
+"      g #000000",\r
+".     g #FFFFFF",\r
+" ...............................",\r
+"  ..............................",\r
+"   .............................",\r
+"    ............................",\r
+"     ...........................",\r
+"      ..........................",\r
+"       .........................",\r
+"        ........................",\r
+"         .......................",\r
+"          ......................",\r
+"           .....................",\r
+"            ....................",\r
+"       ........  ...............",\r
+"       .......    ..............",\r
+"   ..   ......    ..............",\r
+"  ...   .....  ..  .............",\r
+" .....   ....  ..  .............",\r
+"......   ...  ....  ............",\r
+".......   ..  ....  ............",\r
+".......  ..  ......  ...........",\r
+"...........  ......  ...........",\r
+"..........  ........  ..........",\r
+"..........            ..........",\r
+"...........          ...........",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................"};\r
diff --git a/res/cur7.xpm b/res/cur7.xpm
new file mode 100755 (executable)
index 0000000..1c9fb67
--- /dev/null
@@ -0,0 +1,37 @@
+/* XPM */\r
+static char * cur7_xpm[] = {\r
+"32 32 2 1",\r
+"      g #000000",\r
+".     g #FFFFFF",\r
+" ...............................",\r
+"  ..............................",\r
+"   .............................",\r
+"    ............................",\r
+"     ...........................",\r
+"      ..........................",\r
+"       .........................",\r
+"        ........................",\r
+"         .......................",\r
+"          ......................",\r
+"           .....................",\r
+"            ....................",\r
+"       .........................",\r
+"       .........................",\r
+"   ..   ........................",\r
+"  ...   ...  ......  ...........",\r
+" .....   ..   ....   ...........",\r
+"......   ...        ............",\r
+".......   ...      .............",\r
+".......  ....      .............",\r
+".............      .............",\r
+".............      .............",\r
+"............        ............",\r
+"...........   ....   ...........",\r
+"...........  ......  ...........",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................"};\r
diff --git a/res/cur8.xpm b/res/cur8.xpm
new file mode 100755 (executable)
index 0000000..91d96a5
--- /dev/null
@@ -0,0 +1,37 @@
+/* XPM */\r
+static char * cur8_xpm[] = {\r
+"32 32 2 1",\r
+"      g #000000",\r
+".     g #FFFFFF",\r
+" ...............................",\r
+"  ..............................",\r
+"   .............................",\r
+"    ............................",\r
+"     ...........................",\r
+"      ..........................",\r
+"       .........................",\r
+"        ........................",\r
+"         .......................",\r
+"          ......................",\r
+"           .....................",\r
+"            ....................",\r
+"       .........................",\r
+"       .........................",\r
+"   ..   ........................",\r
+"  ...   ...  ......  ...........",\r
+" .....   ..   ....   ...........",\r
+"......   ...        ............",\r
+".......   ...      .............",\r
+".......  ....      .............",\r
+".............      .............",\r
+".............      .............",\r
+"............        ............",\r
+"...........   ....   ...........",\r
+"...........  ......  ...........",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................"};\r
diff --git a/res/tool1.xpm b/res/tool1.xpm
new file mode 100755 (executable)
index 0000000..200b8c6
--- /dev/null
@@ -0,0 +1,21 @@
+/* XPM */\r
+static char * tool1_xpm[] = {\r
+"16 15 3 1",\r
+"      c None",\r
+".     c #A0A0A0",\r
+"+     c #000000",\r
+"                ",\r
+"                ",\r
+"                ",\r
+"                ",\r
+"      ++        ",\r
+"     ++         ",\r
+"   ++++         ",\r
+" ++++++++++++++ ",\r
+"   ++++         ",\r
+"     ++         ",\r
+"      ++        ",\r
+"                ",\r
+"                ",\r
+"                ",\r
+"                "};\r
diff --git a/res/tool2.xpm b/res/tool2.xpm
new file mode 100755 (executable)
index 0000000..9343889
--- /dev/null
@@ -0,0 +1,21 @@
+/* XPM */\r
+static char * tool2_xpm[] = {\r
+"16 15 3 1",\r
+"      c None",\r
+".     c #C0C0C0",\r
+"+     c #000000",\r
+"                ",\r
+"                ",\r
+"                ",\r
+"                ",\r
+"        ++      ",\r
+"         ++     ",\r
+"         ++++   ",\r
+" ++++++++++++++ ",\r
+"         ++++   ",\r
+"         ++     ",\r
+"        ++      ",\r
+"                ",\r
+"                ",\r
+"                ",\r
+"                "};\r
diff --git a/res/tool3.xpm b/res/tool3.xpm
new file mode 100755 (executable)
index 0000000..06d0c06
--- /dev/null
@@ -0,0 +1,22 @@
+/* XPM */\r
+static char * tool3_xpm[] = {\r
+"16 15 3 1",\r
+"      c None",\r
+".     c #C0C0C0",\r
+"+     c #000000",\r
+"++++++++++++++++",\r
+"+              +",\r
+"+   ++++++++   +",\r
+"+  ++++++++++  +",\r
+"+  ++      ++  +",\r
+"+          ++  +",\r
+"+   +++++++++  +",\r
+"+  ++++++++++  +",\r
+"+  ++      ++  +",\r
+"+  ++      ++  +",\r
+"+  ++     +++  +",\r
+"+  ++++++++++  +",\r
+"+   ++++++  ++ +",\r
+"+              +",\r
+"++++++++++++++++"};\r
+\r
diff --git a/res/toolpal1.xpm b/res/toolpal1.xpm
new file mode 100755 (executable)
index 0000000..a11c7a9
--- /dev/null
@@ -0,0 +1,53 @@
+/* XPM */\r
+static char * toolpal1_xpm[] = {\r
+"96 48 2 1",\r
+"      c #000000",\r
+".     c #FFFFFF",\r
+"                                                                                                ",\r
+"   ..................      ..................      ..................      ..................   ",\r
+"                                                                                                ",\r
+" . .................. .  . .................. .  . .................. .  . .................. . ",\r
+" . .... ............. .  . .................. .  . ........  ........ .  . .................. . ",\r
+" . ....  ............ .  . .................. .  . ........  ........ .  . ......  .......... . ",\r
+" . ....   ........... .  . .. ............... .  . .......    ....... .  . ....  ..  ........ . ",\r
+" . ....    .......... .  . ..  .............. .  . .......    ....... .  . ... ...... ....... . ",\r
+" . ....     ......... .  . ..   ............. .  . ...... .  . ...... .  . ... ...... ....... . ",\r
+" . ....      ........ .  . ..    ............ .  . ..... ..  .. ..... .  . .. ........ ...... . ",\r
+" . ....       ....... .  . ..     ...      .. .  . ...  ...  ...  ... .  . .. ........ ...... . ",\r
+" . ....        ...... .  . ..      ..       . .  . .                . .  . ... ...... ....... . ",\r
+" . ....         ..... .  . ..       .  ...  . .  . .                . .  . ... ...... ....... . ",\r
+" . ....      ........ .  . ..     ...  ...  . .  . ...  ...  ...  ... .  . ....  ..    ...... . ",\r
+" . ....      ........ .  . ..     ...       . .  . ..... ..  .. ..... .  . ......  ..   ..... . ",\r
+" . ....  ..   ....... .  . .. ..   ..      .. .  . ...... .  . ...... .  . ...........   .... . ",\r
+" . .... ...   ....... .  . ......  ..  ...... .  . .......    ....... .  . ............   ... . ",\r
+" . .........   ...... .  . ..........  ...... .  . .......    ....... .  . .............   .. . ",\r
+" . .........   ...... .  . ..........  ...... .  . ........  ........ .  . ..............  .. . ",\r
+" . .......... ....... .  . .................. .  . ........  ........ .  . .................. . ",\r
+" . .................. .  . .................. .  . .................. .  . .................. . ",\r
+"                                                                                                ",\r
+"   ..................      ..................      ..................      ..................   ",\r
+"                                                                                                ",\r
+"                                                                                                ",\r
+"   ..................      ..................      ..................      ..................   ",\r
+"                                                                                                ",\r
+" . .................. .  . .................. .  . .................. .  . .................. . ",\r
+" . .................. .  . .................. .  . .................. .  . .................. . ",\r
+" . .................. .  . ........  ........ .  . ..  ..........  .. .  . ..  ........... .. . ",\r
+" . .................. .  . .......    ....... .  . ..   ........   .. .  . ...  .      ..  .. . ",\r
+" . .................. .  . .......    ....... .  . ...   ......   ... .  . ....           ... . ",\r
+" . .......    ....... .  . ......  ..  ...... .  . ....          .... .  . .....   ...   .... . ",\r
+" . ......      ...... .  . ......  ..  ...... .  . .....        ..... .  . ......  ...  ..... . ",\r
+" . .....        ..... .  . .....  ....  ..... .  . .....        ..... .  . ......   .   ..... . ",\r
+" . .....   ..   ..... .  . .....  ....  ..... .  . .....        ..... .  . ......       ..... . ",\r
+" . .....   ..   ..... .  . ....  ......  .... .  . .....        ..... .  . ......       ..... . ",\r
+" . .....        ..... .  . ....  ......  .... .  . .....        ..... .  . ......      ...... . ",\r
+" . ......      ...... .  . ...  ........  ... .  . .....        ..... .  . ......  ...  ..... . ",\r
+" . .......    ....... .  . ...  ........  ... .  . ....          .... .  . .....   ....  .... . ",\r
+" . .................. .  . ..  ..........  .. .  . ...   ......   ... .  . ....    .....  ... . ",\r
+" . .................. .  . ..              .. .  . ..   ........   .. .  . ...  .  ......  .. . ",\r
+" . .................. .  . ...            ... .  . ..  ..........  .. .  . ..  ........... .. . ",\r
+" . .................. .  . .................. .  . .................. .  . .................. . ",\r
+" . .................. .  . .................. .  . .................. .  . .................. . ",\r
+"                                                                                                ",\r
+"   ..................      ..................      ..................      ..................   ",\r
+"                                                                                                "};\r
diff --git a/res/ttedit.xpm b/res/ttedit.xpm
new file mode 100755 (executable)
index 0000000..9828fe0
--- /dev/null
@@ -0,0 +1,46 @@
+/* XPM */
+static char *ttedit_xpm[]={
+"32 32 11 1",
+". c None",
+"d c #0000ff",
+"a c #00ffff",
+"i c #600000",
+"# c #600040",
+"h c #606040",
+"b c #6060ff",
+"g c #a0a080",
+"c c #ff0000",
+"f c #ff6040",
+"e c #ffffff",
+"................................",
+"................................",
+"................................",
+"................................",
+"................................",
+"................................",
+"................................",
+".##############.................",
+".##############.................",
+".##...####...##............aab..",
+".#....####....#..........aabbbb.",
+"......##cc.c.c.c.c.c.c.aabbbbbb.",
+"......##c#c.c...c.c..aabbbbbbdd.",
+"......###c...c.....aabbbbbbdd...",
+"......##c#......c.ebbbbbbdd.....",
+"......####...c...fgbbbbdd.......",
+"......####......fccgbdd.........",
+"......####...c.fccchd...........",
+"......####....ciiii.............",
+"......####...cc.................",
+"......####...cccc...............",
+".....######..cccc...............",
+".............cccc...............",
+".............cccc...............",
+".............cccc...............",
+"............cccccc..............",
+"................................",
+"................................",
+"................................",
+"................................",
+"................................",
+"................................"};
diff --git a/src/bezier.cpp b/src/bezier.cpp
new file mode 100755 (executable)
index 0000000..415f381
--- /dev/null
@@ -0,0 +1,45 @@
+//\r
+// Bezier curve fitter\r
+// by James L. Hammons\r
+// (C) 2005 Underground Software\r
+//\r
+// This function takes three points and draws a curve using a\r
+// second order Bezier function.\r
+//\r
+// JLH = James L. Hammons <jlhamm@acm.org>\r
+//\r
+// Who  When        What\r
+// ---  ----------  -------------------------------------------------------------\r
+// JLH  03/14/1998  Created this file\r
+// JLH  01/20/2005  Converted to use wxWidgets\r
+//\r
+\r
+#include "bezier.h"\r
+\r
+double abs(double n)                                                   // Helper function\r
+{\r
+       return (n < 0 ? -n : n);\r
+}\r
+\r
+void Bezier(wxDC &dc, point p1, point p2, point p3)\r
+{\r
+       double step = abs(p1.x - p3.x), tmp = abs(p1.y - p3.y);\r
+       step = (tmp > step ? tmp : step);                       // Get the larger of the two...\r
+       step = (step > 0 ? 1/step : 1);                         // & convert to valid step value\r
+\r
+//     MoveToEx(hdc, (int)p1.x, (int)p1.y, NULL);\r
+       wxCoord prevX = (wxCoord)p1.x, prevY = (wxCoord)p1.y;\r
+\r
+       for(double u=0; u<=1; u+=step)\r
+       {\r
+               double _2u = 2*u, _uu = u*u, _2uu = 2*_uu,\r
+                       x = (p1.x * (1 - _2u + _uu)) + (p2.x * (_2u - _2uu)) + (p3.x * _uu),\r
+                       y = (p1.y * (1 - _2u + _uu)) + (p2.y * (_2u - _2uu)) + (p3.y * _uu);\r
+//             LineTo(hdc, (int)x, (int)y);\r
+               dc.DrawLine(prevX, prevY, (wxCoord)x, (wxCoord)y);\r
+               prevX = (wxCoord)x, prevY = (wxCoord)y;\r
+       }\r
+\r
+//     LineTo(hdc, (int)p3.x, (int)p3.y);\r
+       dc.DrawLine(prevX, prevY, (wxCoord)p3.x, (wxCoord)p3.y);\r
+}\r
diff --git a/src/bezier.h b/src/bezier.h
new file mode 100755 (executable)
index 0000000..4a5c5ee
--- /dev/null
@@ -0,0 +1,22 @@
+// True Type Hack\r
+//\r
+// Bezier Curve fitter header\r
+//\r
+// This function takes three points and draws a curve using a\r
+// second order Bezier function.\r
+\r
+#ifndef __BEZIER_H__\r
+#define __BEZIER_H__\r
+\r
+#include <wx/wx.h>                                                             // For device context\r
+\r
+struct point\r
+{\r
+       float x, y;\r
+\r
+       point(float xx = 0, float yy = 0): x(xx), y(yy) {}\r
+};\r
+\r
+void Bezier(wxDC &, point, point, point);\r
+\r
+#endif // __BEZIER_H__\r
diff --git a/src/charnames.cpp b/src/charnames.cpp
new file mode 100755 (executable)
index 0000000..84eaf30
--- /dev/null
@@ -0,0 +1,2632 @@
+//\r
+// CHARNAMES.CPP\r
+//\r
+// A header file that links Unicode character names to character numbers.\r
+// by James L. Hammons\r
+// (C) 2004 Underground Software\r
+//\r
+// JLH = James L. Hammons <jlhamm@acm.org>\r
+//\r
+// Who  When        What\r
+// ---  ----------  -------------------------------------------------------------\r
+// JLH  ??/??/200?  Created this file\r
+//\r
+\r
+unsigned char macStdNames[] = {\r
+  "\x06""notdef"\r
+  "\x05"".null"\r
+  "\x02""CR"\r
+  "\x05""space"\r
+  "\x06""exclam"\r
+  "\x08""quotedbl"\r
+  "\x0A""numbersign"\r
+  "\x06""dollar"\r
+  "\x07""percent"\r
+  "\x09""ampersand"\r
+  "\x0B""quotesingle"\r
+  "\x09""parenleft"\r
+  "\x0A""parenright"\r
+  "\x08""asterisk"\r
+  "\x04""plus"\r
+  "\x05""comma"\r
+  "\x06""hyphen"\r
+  "\x06""period"\r
+  "\x05""slash"\r
+  "\x04""zero"\r
+  "\x03""one"\r
+  "\x03""two"\r
+  "\x05""three"\r
+  "\x04""four"\r
+  "\x04""five"\r
+  "\x03""six"\r
+  "\x05""seven"\r
+  "\x05""eight"\r
+  "\x04""nine"\r
+  "\x05""colon"\r
+  "\x09""semicolon"\r
+  "\x04""less"\r
+  "\x05""equal"\r
+  "\x07""greater"\r
+  "\x08""question"\r
+  "\x02""at"\r
+  "\x01""A"\r
+  "\x01""B"\r
+  "\x01""C"\r
+  "\x01""D"\r
+  "\x01""E"\r
+  "\x01""F"\r
+  "\x01""G"\r
+  "\x01""H"\r
+  "\x01""I"\r
+  "\x01""J"\r
+  "\x01""K"\r
+  "\x01""L"\r
+  "\x01""M"\r
+  "\x01""N"\r
+  "\x01""O"\r
+  "\x01""P"\r
+  "\x01""Q"\r
+  "\x01""R"\r
+  "\x01""S"\r
+  "\x01""T"\r
+  "\x01""U"\r
+  "\x01""V"\r
+  "\x01""W"\r
+  "\x01""X"\r
+  "\x01""Y"\r
+  "\x01""Z"\r
+  "\x0B""bracketleft"\r
+  "\x09""backslash"\r
+  "\x0C""bracketright"\r
+  "\x0B""asciicircum"\r
+  "\x0A""underscore"\r
+  "\x05""grave"\r
+  "\x01""a"\r
+  "\x01""b"\r
+  "\x01""c"\r
+  "\x01""d"\r
+  "\x01""e"\r
+  "\x01""f"\r
+  "\x01""g"\r
+  "\x01""h"\r
+  "\x01""i"\r
+  "\x01""j"\r
+  "\x01""k"\r
+  "\x01""l"\r
+  "\x01""m"\r
+  "\x01""n"\r
+  "\x01""o"\r
+  "\x01""p"\r
+  "\x01""q"\r
+  "\x01""r"\r
+  "\x01""s"\r
+  "\x01""t"\r
+  "\x01""u"\r
+  "\x01""v"\r
+  "\x01""w"\r
+  "\x01""x"\r
+  "\x01""y"\r
+  "\x01""z"\r
+  "\x09""braceleft"\r
+  "\x03""bar"\r
+  "\x0A""braceright"\r
+  "\x0A""asciitilde"\r
+  "\x09""Adieresis"\r
+  "\x05""Aring"\r
+  "\x08""Ccedilla"\r
+  "\x06""Eacute"\r
+  "\x06""Ntilde"\r
+  "\x09""Odieresis"\r
+  "\x09""Udieresis"\r
+  "\x06""aacute"\r
+  "\x06""agrave"\r
+  "\x0B""acircumflex"\r
+  "\x09""adieresis"\r
+  "\x06""atilde"\r
+  "\x05""aring"\r
+  "\x08""ccedilla"\r
+  "\x06""eacute"\r
+  "\x06""egrave"\r
+  "\x0B""ecircumflex"\r
+  "\x09""edieresis"\r
+  "\x06""iacute"\r
+  "\x06""igrave"\r
+  "\x0B""icircumflex"\r
+  "\x09""idieresis"\r
+  "\x06""ntilde"\r
+  "\x06""oacute"\r
+  "\x06""ograve"\r
+  "\x0B""ocircumflex"\r
+  "\x09""odieresis"\r
+  "\x06""otilde"\r
+  "\x06""uacute"\r
+  "\x06""ugrave"\r
+  "\x0B""ucircumflex"\r
+  "\x09""udieresis"\r
+  "\x06""dagger"\r
+  "\x06""degree"\r
+  "\x04""cent"\r
+  "\x08""sterling"\r
+  "\x07""section"\r
+  "\x06""bullet"\r
+  "\x09""paragraph"\r
+  "\x0A""germandbls"\r
+  "\x0A""registered"\r
+  "\x09""copyright"\r
+  "\x09""trademark"\r
+  "\x05""acute"\r
+  "\x08""dieresis"\r
+  "\x08""notequal"\r
+  "\x02""AE"\r
+  "\x06""Oslash"\r
+  "\x08""infinity"\r
+  "\x09""plusminus"\r
+  "\x09""lessequal"\r
+  "\x0C""greaterequal"\r
+  "\x03""yen"\r
+  "\x03""mu1"\r
+  "\x0B""partialdiff"\r
+  "\x09""summation"\r
+  "\x07""product"\r
+  "\x02""pi"\r
+  "\x08""integral"\r
+  "\x0B""ordfeminine"\r
+  "\x0C""ordmasculine"\r
+  "\x03""Ohm"\r
+  "\x02""ae"\r
+  "\x06""oslash"\r
+  "\x0C""questiondown"\r
+  "\x0A""exclamdown"\r
+  "\x0A""logicalnot"\r
+  "\x07""radical"\r
+  "\x06""florin"\r
+  "\x0B""approxequal"\r
+  "\x09""increment"\r
+  "\x0D""guillemotleft"\r
+  "\x0E""guillemotright"\r
+  "\x08""ellipsis"\r
+  "\x07""nbspace"\r
+  "\x06""Agrave"\r
+  "\x06""Atilde"\r
+  "\x06""Otilde"\r
+  "\x02""OE"\r
+  "\x02""oe"\r
+  "\x06""endash"\r
+  "\x06""emdash"\r
+  "\x0C""quotedblleft"\r
+  "\x0D""quotedblright"\r
+  "\x09""quoteleft"\r
+  "\x0A""quoteright"\r
+  "\x06""divide"\r
+  "\x07""lozenge"\r
+  "\x09""ydieresis"\r
+  "\x09""Ydieresis"\r
+  "\x08""fraction"\r
+  "\x08""currency"\r
+  "\x0D""guilsinglleft"\r
+  "\x0E""guilsinglright"\r
+  "\x02""fi"\r
+  "\x02""fl"\r
+  "\x09""daggerdbl"\r
+  "\x0E""periodcentered"\r
+  "\x0E""quotesinglbase"\r
+  "\x0C""quotedblbase"\r
+  "\x0B""perthousand"\r
+  "\x0B""Acircumflex"\r
+  "\x0B""Ecircumflex"\r
+  "\x06""Aacute"\r
+  "\x09""Edieresis"\r
+  "\x06""Egrave"\r
+  "\x06""Iacute"\r
+  "\x0B""Icircumflex"\r
+  "\x09""Idieresis"\r
+  "\x06""Igrave"\r
+  "\x06""Oacute"\r
+  "\x0B""Ocircumflex"\r
+  "\x09""applelogo"\r
+  "\x06""Ograve"\r
+  "\x06""Uacute"\r
+  "\x0B""Ucircumflex"\r
+  "\x06""Ugrave"\r
+  "\x08""dotlessi"\r
+  "\x0A""circumflex"\r
+  "\x05""tilde"\r
+  "\x09""overscore"\r
+  "\x05""breve"\r
+  "\x09""dotaccent"\r
+  "\x04""ring"\r
+  "\x07""cedilla"\r
+  "\x0C""hungarumlaut"\r
+  "\x06""ogonek"\r
+  "\x05""caron"\r
+  "\x06""Lslash"\r
+  "\x06""lslash"\r
+  "\x06""Scaron"\r
+  "\x06""scaron"\r
+  "\x06""Zcaron"\r
+  "\x06""zcaron"\r
+  "\x09""brokenbar"\r
+  "\x03""Eth"\r
+  "\x03""eth"\r
+  "\x06""Yacute"\r
+  "\x06""yacute"\r
+  "\x05""Thorn"\r
+  "\x05""thorn"\r
+  "\x05""minus"\r
+  "\x08""multiply"\r
+  "\x0B""onesuperior"\r
+  "\x0B""twosuperior"\r
+  "\x0D""threesuperior"\r
+  "\x07""onehalf"\r
+  "\x0A""onequarter"\r
+  "\x0D""threequarters"\r
+  "\x05""franc"\r
+  "\x06""Gbreve"\r
+  "\x06""gbreve"\r
+  "\x04""Idot"\r
+  "\x08""Scedilla"\r
+  "\x08""scedilla"\r
+  "\x06""Cacute"\r
+  "\x06""cacute"\r
+  "\x06""Ccaron"\r
+  "\x06""ccaron"\r
+  "\x07""dmacron"\r
+};\r
+\r
+/*struct unicodeChar\r
+{\r
+  int cNum;\r
+\r
+};*/\r
+\r
+unsigned char unicodeChars[] = {\r
+  "\x00\x20""space\0"\r
+  "\x00\x21""exclamation mark\0"\r
+  "\x00\x22""quotation mark\0"\r
+  "\x00\x23""number sign\0"\r
+\r
+};\r
+\r
+/*\r
+\r
+0023   NUMBER SIGN\r
+       = pound sign, hash, crosshatch, octothorpe\r
+0024   DOLLAR SIGN\r
+       = milreis, escudo\r
+       * glyph may have one or two vertical bars\r
+       * other currency symbol characters: 20A0-20AF\r
+       x (currency sign - 00A4)\r
+0025   PERCENT SIGN\r
+       x (arabic percent sign - 066A)\r
+       x (per mille sign - 2030)\r
+       x (per ten thousand sign - 2031)\r
+0026   AMPERSAND\r
+0027   APOSTROPHE\r
+       = APOSTROPHE-QUOTE\r
+       = APL quote\r
+       * neutral (vertical) glyph having mixed usage\r
+       * preferred character for apostrophe is 2019\r
+       * preferred characters in English for paired quotation marks are 2018 & 2019\r
+       x (modifier letter prime - 02B9)\r
+       x (modifier letter apostrophe - 02BC)\r
+       x (modifier letter vertical line - 02C8)\r
+       x (combining acute accent - 0301)\r
+       x (prime - 2032)\r
+0028   LEFT PARENTHESIS\r
+       = OPENING PARENTHESIS\r
+0029   RIGHT PARENTHESIS\r
+       = CLOSING PARENTHESIS\r
+       * see discussion on semantics of paired bracketing characters\r
+002A   ASTERISK\r
+       = star (on phone keypads)\r
+       x (arabic five pointed star - 066D)\r
+       x (asterisk operator - 2217)\r
+       x (heavy asterisk - 2731)\r
+002B   PLUS SIGN\r
+002C   COMMA\r
+       = decimal separator\r
+       x (arabic comma - 060C)\r
+       x (single low-9 quotation mark - 201A)\r
+       x (ideographic comma - 3001)\r
+002D   HYPHEN-MINUS\r
+       = hyphen or minus sign\r
+       * used for either hyphen or minus sign\r
+       x (hyphen - 2010)\r
+       x (non-breaking hyphen - 2011)\r
+       x (figure dash - 2012)\r
+       x (en dash - 2013)\r
+       x (minus sign - 2212)\r
+002E   FULL STOP\r
+       = PERIOD\r
+       = dot, decimal point\r
+       * may be rendered as a raised decimal point in old style numbers\r
+       x (arabic full stop - 06D4)\r
+       x (ideographic full stop - 3002)\r
+002F   SOLIDUS\r
+       = SLASH\r
+       = virgule, shilling (British)\r
+       x (latin letter dental click - 01C0)\r
+       x (combining long solidus overlay - 0338)\r
+       x (fraction slash - 2044)\r
+       x (division slash - 2215)\r
+0030   DIGIT ZERO\r
+0031   DIGIT ONE\r
+0032   DIGIT TWO\r
+0033   DIGIT THREE\r
+0034   DIGIT FOUR\r
+0035   DIGIT FIVE\r
+0036   DIGIT SIX\r
+0037   DIGIT SEVEN\r
+0038   DIGIT EIGHT\r
+0039   DIGIT NINE\r
+003A   COLON\r
+       x (armenian full stop - 0589)\r
+       x (hebrew punctuation sof pasuq - 05C3)\r
+       x (ratio - 2236)\r
+003B   SEMICOLON\r
+       x (greek question mark - 037E)\r
+       x (arabic semicolon - 061B)\r
+003C   LESS-THAN SIGN\r
+       x (single left-pointing angle quotation mark - 2039)\r
+       x (left-pointing angle bracket - 2329)\r
+       x (left angle bracket - 3008)\r
+003D   EQUALS SIGN\r
+       * other related characters: 2241-2263\r
+       x (not equal to - 2260)\r
+       x (identical to - 2261)\r
+003E   GREATER-THAN SIGN\r
+       x (single right-pointing angle quotation mark - 203A)\r
+       x (right-pointing angle bracket - 232A)\r
+       x (right angle bracket - 3009)\r
+003F   QUESTION MARK\r
+       x (inverted question mark - 00BF)\r
+       x (greek question mark - 037E)\r
+       x (arabic question mark - 061F)\r
+       x (interrobang - 203D)\r
+       x (question exclamation mark - 2048)\r
+       x (exclamation question mark - 2049)\r
+0040   COMMERCIAL AT\r
+0041   LATIN CAPITAL LETTER A\r
+0042   LATIN CAPITAL LETTER B\r
+       x (script capital b - 212C)\r
+0043   LATIN CAPITAL LETTER C\r
+       x (double-struck capital c - 2102)\r
+       x (black-letter capital c - 212D)\r
+0044   LATIN CAPITAL LETTER D\r
+0045   LATIN CAPITAL LETTER E\r
+       x (euler constant - 2107)\r
+       x (script capital e - 2130)\r
+0046   LATIN CAPITAL LETTER F\r
+       x (script capital f - 2131)\r
+       x (turned capital f - 2132)\r
+0047   LATIN CAPITAL LETTER G\r
+0048   LATIN CAPITAL LETTER H\r
+       x (script capital h - 210B)\r
+       x (black-letter capital h - 210C)\r
+       x (double-struck capital h - 210D)\r
+0049   LATIN CAPITAL LETTER I\r
+       * Turkish and Azerbaijani use 0131 for lowercase\r
+       x (latin capital letter i with dot above - 0130)\r
+       x (cyrillic capital letter byelorussian-ukrainian i - 0406)\r
+       x (cyrillic letter palochka - 04C0)\r
+       x (script capital i - 2110)\r
+       x (black-letter capital i - 2111)\r
+       x (roman numeral one - 2160)\r
+004A   LATIN CAPITAL LETTER J\r
+004B   LATIN CAPITAL LETTER K\r
+       x (kelvin sign - 212A)\r
+004C   LATIN CAPITAL LETTER L\r
+       x (script capital l - 2112)\r
+004D   LATIN CAPITAL LETTER M\r
+       x (script capital m - 2133)\r
+004E   LATIN CAPITAL LETTER N\r
+       x (double-struck capital n - 2115)\r
+004F   LATIN CAPITAL LETTER O\r
+0050   LATIN CAPITAL LETTER P\r
+       x (double-struck capital p - 2119)\r
+0051   LATIN CAPITAL LETTER Q\r
+       x (double-struck capital q - 211A)\r
+0052   LATIN CAPITAL LETTER R\r
+       x (script capital r - 211B)\r
+       x (black-letter capital r - 211C)\r
+       x (double-struck capital r - 211D)\r
+0053   LATIN CAPITAL LETTER S\r
+0054   LATIN CAPITAL LETTER T\r
+0055   LATIN CAPITAL LETTER U\r
+0056   LATIN CAPITAL LETTER V\r
+0057   LATIN CAPITAL LETTER W\r
+0058   LATIN CAPITAL LETTER X\r
+0059   LATIN CAPITAL LETTER Y\r
+005A   LATIN CAPITAL LETTER Z\r
+       x (double-struck capital z - 2124)\r
+       x (black-letter capital z - 2128)\r
+005B   LEFT SQUARE BRACKET\r
+       = OPENING SQUARE BRACKET\r
+       * other bracket characters: 3008-301B\r
+005C   REVERSE SOLIDUS\r
+       = BACKSLASH\r
+       x (set minus - 2216)\r
+005D   RIGHT SQUARE BRACKET\r
+       = CLOSING SQUARE BRACKET\r
+005E   CIRCUMFLEX ACCENT\r
+       * this is a spacing character\r
+       x (modifier letter up arrowhead - 02C4)\r
+       x (modifier letter circumflex accent - 02C6)\r
+       x (combining circumflex accent - 0302)\r
+       x (up arrowhead - 2303)\r
+005F   LOW LINE\r
+       = SPACING UNDERSCORE\r
+       * this is a spacing character\r
+       x (modifier letter low macron - 02CD)\r
+       x (combining macron below - 0331)\r
+       x (combining low line - 0332)\r
+       x (double low line - 2017)\r
+0060   GRAVE ACCENT\r
+       * this is a spacing character\r
+       x (modifier letter grave accent - 02CB)\r
+       x (combining grave accent - 0300)\r
+       x (reversed prime - 2035)\r
+0061   LATIN SMALL LETTER A\r
+0062   LATIN SMALL LETTER B\r
+0063   LATIN SMALL LETTER C\r
+0064   LATIN SMALL LETTER D\r
+0065   LATIN SMALL LETTER E\r
+       x (estimated symbol - 212E)\r
+       x (script small e - 212F)\r
+0066   LATIN SMALL LETTER F\r
+0067   LATIN SMALL LETTER G\r
+       x (latin small letter script g - 0261)\r
+       x (script small g - 210A)\r
+0068   LATIN SMALL LETTER H\r
+       x (cyrillic small letter shha - 04BB)\r
+       x (planck constant - 210E)\r
+0069   LATIN SMALL LETTER I\r
+       * Turkish and Azerbaijani use 0130 for uppercase\r
+       x (latin small letter dotless i - 0131)\r
+006A   LATIN SMALL LETTER J\r
+006B   LATIN SMALL LETTER K\r
+006C   LATIN SMALL LETTER L\r
+       x (script small l - 2113)\r
+006D   LATIN SMALL LETTER M\r
+006E   LATIN SMALL LETTER N\r
+       x (superscript latin small letter n - 207F)\r
+006F   LATIN SMALL LETTER O\r
+       x (script small o - 2134)\r
+0070   LATIN SMALL LETTER P\r
+0071   LATIN SMALL LETTER Q\r
+0072   LATIN SMALL LETTER R\r
+0073   LATIN SMALL LETTER S\r
+0074   LATIN SMALL LETTER T\r
+0075   LATIN SMALL LETTER U\r
+0076   LATIN SMALL LETTER V\r
+0077   LATIN SMALL LETTER W\r
+0078   LATIN SMALL LETTER X\r
+0079   LATIN SMALL LETTER Y\r
+007A   LATIN SMALL LETTER Z\r
+       x (latin small letter z with stroke - 01B6)\r
+007B   LEFT CURLY BRACKET\r
+       = OPENING CURLY BRACKET\r
+       = opening brace\r
+007C   VERTICAL LINE\r
+       = VERTICAL BAR\r
+       * used in pairs to indicate absolute value\r
+       x (latin letter dental click - 01C0)\r
+       x (hebrew punctuation paseq - 05C0)\r
+       x (divides - 2223)\r
+       x (light vertical bar - 2758)\r
+007D   RIGHT CURLY BRACKET\r
+       = CLOSING CURLY BRACKET\r
+       = closing brace\r
+007E   TILDE\r
+       * this is a spacing character\r
+       x (small tilde - 02DC)\r
+       x (combining tilde - 0303)\r
+       x (tilde operator - 223C)\r
+       x (fullwidth tilde - FF5E)\r
+007F   <control>\r
+       = DELETE\r
+@@     0080    C1 Controls and Latin-1 Supplement (Latin-1 Supplement) 00FF\r
+@              C1 controls\r
+@+             Alias names are those for ISO 6429.\r
+0080   <control>\r
+0081   <control>\r
+0082   <control>\r
+       = BREAK PERMITTED HERE\r
+0083   <control>\r
+       = NO BREAK HERE\r
+0084   <control>\r
+0085   <control>\r
+       = NEXT LINE\r
+0086   <control>\r
+       = START OF SELECTED AREA\r
+0087   <control>\r
+       = END OF SELECTED AREA\r
+0088   <control>\r
+       = CHARACTER TABULATION SET\r
+0089   <control>\r
+       = CHARACTER TABULATION WITH JUSTIFICATION\r
+008A   <control>\r
+       = LINE TABULATION SET\r
+008B   <control>\r
+       = PARTIAL LINE DOWN\r
+008C   <control>\r
+       = PARTIAL LINE UP\r
+008D   <control>\r
+       = REVERSE LINE FEED\r
+008E   <control>\r
+       = SINGLE SHIFT TWO\r
+008F   <control>\r
+       = SINGLE SHIFT THREE\r
+0090   <control>\r
+       = DEVICE CONTROL STRING\r
+0091   <control>\r
+       = PRIVATE USE ONE\r
+0092   <control>\r
+       = PRIVATE USE TWO\r
+0093   <control>\r
+       = SET TRANSMIT STATE\r
+0094   <control>\r
+       = CANCEL CHARACTER\r
+0095   <control>\r
+       = MESSAGE WAITING\r
+0096   <control>\r
+       = START OF GUARDED AREA\r
+0097   <control>\r
+       = END OF GUARDED AREA\r
+0098   <control>\r
+       = START OF STRING\r
+0099   <control>\r
+009A   <control>\r
+       = SINGLE CHARACTER INTRODUCER\r
+009B   <control>\r
+       = CONTROL SEQUENCE INTRODUCER\r
+009C   <control>\r
+       = STRING TERMINATOR\r
+009D   <control>\r
+       = OPERATING SYSTEM COMMAND\r
+009E   <control>\r
+       = PRIVACY MESSAGE\r
+009F   <control>\r
+       = APPLICATION PROGRAM COMMAND\r
+@              ISO 8859-1 (aka Latin-1)\r
+00A0   NO-BREAK SPACE\r
+       x (space - 0020)\r
+       x (figure space - 2007)\r
+       x (narrow no-break space - 202F)\r
+       x (zero width no-break space - FEFF)\r
+       # <noBreak> 0020\r
+00A1   INVERTED EXCLAMATION MARK\r
+       * Spanish, Asturian, Galician\r
+       x (exclamation mark - 0021)\r
+00A2   CENT SIGN\r
+00A3   POUND SIGN\r
+       = pound sterling, Irish punt\r
+       x (lira sign - 20A4)\r
+00A4   CURRENCY SIGN\r
+       = Filzlaus, Ricardi-Sonne (German names)\r
+       * other currency symbol characters: 20A0-20AF\r
+       x (dollar sign - 0024)\r
+00A5   YEN SIGN\r
+       = yuan sign\r
+       * glyph may have one or two crossbars\r
+00A6   BROKEN BAR\r
+       = BROKEN VERTICAL BAR\r
+       = parted rule (in typography)\r
+00A7   SECTION SIGN\r
+       * paragraph sign in some European usage\r
+00A8   DIAERESIS\r
+       * this is a spacing character\r
+       x (combining diaeresis - 0308)\r
+       # 0020 0308\r
+00A9   COPYRIGHT SIGN\r
+       x (sound recording copyright - 2117)\r
+00AA   FEMININE ORDINAL INDICATOR\r
+       * Spanish\r
+       # <super> 0061\r
+00AB   LEFT-POINTING DOUBLE ANGLE QUOTATION MARK *\r
+       = LEFT POINTING GUILLEMET\r
+       = chevrons (in typography)\r
+       * usually opening, sometimes closing\r
+       x (much less-than - 226A)\r
+       x (left double angle bracket - 300A)\r
+00AC   NOT SIGN\r
+       = angled dash (in typography)\r
+       x (reversed not sign - 2310)\r
+00AD   SOFT HYPHEN\r
+       = discretionary hyphen\r
+       x (mongolian todo soft hyphen - 1806)\r
+00AE   REGISTERED SIGN\r
+       = REGISTERED TRADE MARK SIGN\r
+00AF   MACRON\r
+       = overline, APL overbar\r
+       * this is a spacing character\r
+       x (modifier letter macron - 02C9)\r
+       x (combining macron - 0304)\r
+       x (combining overline - 0305)\r
+       # 0020 0304\r
+00B0   DEGREE SIGN\r
+       * this is a spacing character\r
+       x (ring above - 02DA)\r
+       x (combining ring above - 030A)\r
+       x (superscript zero - 2070)\r
+       x (ring operator - 2218)\r
+00B1   PLUS-MINUS SIGN\r
+       x (minus-or-plus sign - 2213)\r
+00B2   SUPERSCRIPT TWO\r
+       = squared\r
+       * other superscript digit characters: 2070-2079\r
+       x (superscript one - 00B9)\r
+       # <super> 0032\r
+00B3   SUPERSCRIPT THREE\r
+       = cubed\r
+       x (superscript one - 00B9)\r
+       # <super> 0033\r
+00B4   ACUTE ACCENT\r
+       * this is a spacing character\r
+       x (modifier letter prime - 02B9)\r
+       x (modifier letter acute accent - 02CA)\r
+       x (combining acute accent - 0301)\r
+       x (prime - 2032)\r
+       # 0020 0301\r
+00B5   MICRO SIGN\r
+       # 03BC greek small letter mu\r
+00B6   PILCROW SIGN\r
+       = PARAGRAPH SIGN\r
+       * section sign in some European usage\r
+       x (reversed pilcrow sign - 204B)\r
+       x (curved stem paragraph sign ornament - 2761)\r
+00B7   MIDDLE DOT\r
+       = midpoint (in typography)\r
+       = Georgian comma\r
+       = Greek middle dot\r
+       x (bullet - 2022)\r
+       x (one dot leader - 2024)\r
+       x (hyphenation point - 2027)\r
+       x (bullet operator - 2219)\r
+       x (dot operator - 22C5)\r
+       x (katakana middle dot - 30FB)\r
+00B8   CEDILLA\r
+       * this is a spacing character\r
+       * other spacing accent characters: 02D8-02DB\r
+       x (combining cedilla - 0327)\r
+       # 0020 0327\r
+00B9   SUPERSCRIPT ONE\r
+       x (superscript two - 00B2)\r
+       x (superscript three - 00B3)\r
+       # <super> 0031\r
+00BA   MASCULINE ORDINAL INDICATOR\r
+       * Spanish\r
+       # <super> 006F\r
+00BB   RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK *\r
+       = RIGHT POINTING GUILLEMET\r
+       * usually closing, sometimes opening\r
+       x (much greater-than - 226B)\r
+       x (right double angle bracket - 300B)\r
+00BC   VULGAR FRACTION ONE QUARTER\r
+       * bar may be horizontal or slanted\r
+       * other fraction characters: 2153-215E\r
+       # 0031 2044 0034\r
+00BD   VULGAR FRACTION ONE HALF\r
+       * bar may be horizontal or slanted\r
+       # 0031 2044 0032\r
+00BE   VULGAR FRACTION THREE QUARTERS\r
+       * bar may be horizontal or slanted\r
+       # 0033 2044 0034\r
+00BF   INVERTED QUESTION MARK\r
+       = turned question mark\r
+       * Spanish\r
+       x (question mark - 003F)\r
+00C0   LATIN CAPITAL LETTER A WITH GRAVE\r
+       : 0041 0300\r
+00C1   LATIN CAPITAL LETTER A WITH ACUTE\r
+       : 0041 0301\r
+00C2   LATIN CAPITAL LETTER A WITH CIRCUMFLEX\r
+       : 0041 0302\r
+00C3   LATIN CAPITAL LETTER A WITH TILDE\r
+       : 0041 0303\r
+00C4   LATIN CAPITAL LETTER A WITH DIAERESIS\r
+       : 0041 0308\r
+00C5   LATIN CAPITAL LETTER A WITH RING ABOVE\r
+       x (angstrom sign - 212B)\r
+       : 0041 030A\r
+00C6   LATIN CAPITAL LETTER AE (ash) *\r
+       = LATIN CAPITAL LIGATURE AE\r
+00C7   LATIN CAPITAL LETTER C WITH CEDILLA\r
+       : 0043 0327\r
+00C8   LATIN CAPITAL LETTER E WITH GRAVE\r
+       : 0045 0300\r
+00C9   LATIN CAPITAL LETTER E WITH ACUTE\r
+       : 0045 0301\r
+00CA   LATIN CAPITAL LETTER E WITH CIRCUMFLEX\r
+       : 0045 0302\r
+00CB   LATIN CAPITAL LETTER E WITH DIAERESIS\r
+       : 0045 0308\r
+00CC   LATIN CAPITAL LETTER I WITH GRAVE\r
+       : 0049 0300\r
+00CD   LATIN CAPITAL LETTER I WITH ACUTE\r
+       : 0049 0301\r
+00CE   LATIN CAPITAL LETTER I WITH CIRCUMFLEX\r
+       : 0049 0302\r
+00CF   LATIN CAPITAL LETTER I WITH DIAERESIS\r
+       : 0049 0308\r
+00D0   LATIN CAPITAL LETTER ETH (Icelandic)\r
+       x (latin small letter eth - 00F0)\r
+       x (latin capital letter d with stroke - 0110)\r
+       x (latin capital letter african d - 0189)\r
+00D1   LATIN CAPITAL LETTER N WITH TILDE\r
+       : 004E 0303\r
+00D2   LATIN CAPITAL LETTER O WITH GRAVE\r
+       : 004F 0300\r
+00D3   LATIN CAPITAL LETTER O WITH ACUTE\r
+       : 004F 0301\r
+00D4   LATIN CAPITAL LETTER O WITH CIRCUMFLEX\r
+       : 004F 0302\r
+00D5   LATIN CAPITAL LETTER O WITH TILDE\r
+       : 004F 0303\r
+00D6   LATIN CAPITAL LETTER O WITH DIAERESIS\r
+       : 004F 0308\r
+00D7   MULTIPLICATION SIGN\r
+       = z notation Cartesian product\r
+00D8   LATIN CAPITAL LETTER O WITH STROKE\r
+       = LATIN CAPITAL LETTER O SLASH\r
+       x (empty set - 2205)\r
+00D9   LATIN CAPITAL LETTER U WITH GRAVE\r
+       : 0055 0300\r
+00DA   LATIN CAPITAL LETTER U WITH ACUTE\r
+       : 0055 0301\r
+00DB   LATIN CAPITAL LETTER U WITH CIRCUMFLEX\r
+       : 0055 0302\r
+00DC   LATIN CAPITAL LETTER U WITH DIAERESIS\r
+       : 0055 0308\r
+00DD   LATIN CAPITAL LETTER Y WITH ACUTE\r
+       : 0059 0301\r
+00DE   LATIN CAPITAL LETTER THORN (Icelandic)\r
+00DF   LATIN SMALL LETTER SHARP S (German)\r
+       = Eszett\r
+       * German\r
+       * uppercase is "SS"\r
+       * in origin a ligature of 017F and 0073\r
+       x (greek small letter beta - 03B2)\r
+00E0   LATIN SMALL LETTER A WITH GRAVE\r
+       : 0061 0300\r
+00E1   LATIN SMALL LETTER A WITH ACUTE\r
+       : 0061 0301\r
+00E2   LATIN SMALL LETTER A WITH CIRCUMFLEX\r
+       : 0061 0302\r
+00E3   LATIN SMALL LETTER A WITH TILDE\r
+       * Portuguese\r
+       : 0061 0303\r
+00E4   LATIN SMALL LETTER A WITH DIAERESIS\r
+       : 0061 0308\r
+00E5   LATIN SMALL LETTER A WITH RING ABOVE\r
+       * Danish, Norwegian, Swedish, Walloon\r
+       : 0061 030A\r
+00E6   LATIN SMALL LETTER AE (ash) *\r
+       = LATIN SMALL LIGATURE AE\r
+       = ash (from Old English Ã¦sc)\r
+       * Danish, Norwegian, Icelandic, Faroese, Old English, French, IPA\r
+       x (latin small ligature oe - 0153)\r
+       x (cyrillic small ligature a ie - 04D5)\r
+00E7   LATIN SMALL LETTER C WITH CEDILLA\r
+       : 0063 0327\r
+00E8   LATIN SMALL LETTER E WITH GRAVE\r
+       : 0065 0300\r
+00E9   LATIN SMALL LETTER E WITH ACUTE\r
+       : 0065 0301\r
+00EA   LATIN SMALL LETTER E WITH CIRCUMFLEX\r
+       : 0065 0302\r
+00EB   LATIN SMALL LETTER E WITH DIAERESIS\r
+       : 0065 0308\r
+00EC   LATIN SMALL LETTER I WITH GRAVE\r
+       * Italian, Malagasy\r
+       : 0069 0300\r
+00ED   LATIN SMALL LETTER I WITH ACUTE\r
+       : 0069 0301\r
+00EE   LATIN SMALL LETTER I WITH CIRCUMFLEX\r
+       : 0069 0302\r
+00EF   LATIN SMALL LETTER I WITH DIAERESIS\r
+       : 0069 0308\r
+00F0   LATIN SMALL LETTER ETH (Icelandic)\r
+       * Icelandic, Faroese, Old English, IPA\r
+       x (latin capital letter eth - 00D0)\r
+       x (greek small letter delta - 03B4)\r
+       x (partial differential - 2202)\r
+00F1   LATIN SMALL LETTER N WITH TILDE\r
+       : 006E 0303\r
+00F2   LATIN SMALL LETTER O WITH GRAVE\r
+       : 006F 0300\r
+00F3   LATIN SMALL LETTER O WITH ACUTE\r
+       : 006F 0301\r
+00F4   LATIN SMALL LETTER O WITH CIRCUMFLEX\r
+       : 006F 0302\r
+00F5   LATIN SMALL LETTER O WITH TILDE\r
+       * Portuguese, Estonian\r
+       : 006F 0303\r
+00F6   LATIN SMALL LETTER O WITH DIAERESIS\r
+       : 006F 0308\r
+00F7   DIVISION SIGN\r
+00F8   LATIN SMALL LETTER O WITH STROKE\r
+       = LATIN SMALL LETTER O SLASH\r
+       * Danish, Norwegian, Faroese, IPA\r
+00F9   LATIN SMALL LETTER U WITH GRAVE\r
+       * French, Italian\r
+       : 0075 0300\r
+00FA   LATIN SMALL LETTER U WITH ACUTE\r
+       : 0075 0301\r
+00FB   LATIN SMALL LETTER U WITH CIRCUMFLEX\r
+       : 0075 0302\r
+00FC   LATIN SMALL LETTER U WITH DIAERESIS\r
+       : 0075 0308\r
+00FD   LATIN SMALL LETTER Y WITH ACUTE\r
+       * Czech, Slovak, Icelandic, Faroese, Welsh, Malagasy\r
+       : 0079 0301\r
+00FE   LATIN SMALL LETTER THORN (Icelandic)\r
+       * Icelandic, Old English, phonetics\r
+       * Runic letter borrowed into Latin script\r
+       x (runic letter thurisaz thurs thorn - 16A6)\r
+00FF   LATIN SMALL LETTER Y WITH DIAERESIS\r
+       * French\r
+       x (latin capital letter y with diaeresis - 0178)\r
+       : 0079 0308\r
+@@     0100    Latin Extended-A        017F\r
+@              European Latin\r
+0100   LATIN CAPITAL LETTER A WITH MACRON\r
+       : 0041 0304\r
+0101   LATIN SMALL LETTER A WITH MACRON\r
+       * Latvian, Latin, ...\r
+       : 0061 0304\r
+0102   LATIN CAPITAL LETTER A WITH BREVE\r
+       : 0041 0306\r
+0103   LATIN SMALL LETTER A WITH BREVE\r
+       * Romanian, Vietnamese, Latin, ...\r
+       : 0061 0306\r
+0104   LATIN CAPITAL LETTER A WITH OGONEK\r
+       : 0041 0328\r
+0105   LATIN SMALL LETTER A WITH OGONEK\r
+       * Polish, Lithuanian, ...\r
+       : 0061 0328\r
+0106   LATIN CAPITAL LETTER C WITH ACUTE\r
+       : 0043 0301\r
+0107   LATIN SMALL LETTER C WITH ACUTE\r
+       * Polish, Croatian, ...\r
+       x (cyrillic small letter tshe - 045B)\r
+       : 0063 0301\r
+0108   LATIN CAPITAL LETTER C WITH CIRCUMFLEX\r
+       : 0043 0302\r
+0109   LATIN SMALL LETTER C WITH CIRCUMFLEX\r
+       * Esperanto\r
+       : 0063 0302\r
+010A   LATIN CAPITAL LETTER C WITH DOT ABOVE\r
+       : 0043 0307\r
+010B   LATIN SMALL LETTER C WITH DOT ABOVE\r
+       * Maltese, Irish Gaelic (old orthography)\r
+       : 0063 0307\r
+010C   LATIN CAPITAL LETTER C WITH CARON\r
+       : 0043 030C\r
+010D   LATIN SMALL LETTER C WITH CARON\r
+       * Czech, Slovak, Slovenian, and many other languages\r
+       : 0063 030C\r
+010E   LATIN CAPITAL LETTER D WITH CARON\r
+       * the form using caron/hacek is preferred in all contexts\r
+       : 0044 030C\r
+010F   LATIN SMALL LETTER D WITH CARON\r
+       * Czech, Slovak\r
+       * the form using apostrophe is preferred in typesetting\r
+       : 0064 030C\r
+0110   LATIN CAPITAL LETTER D WITH STROKE\r
+       x (latin capital letter eth - 00D0)\r
+       x (latin small letter d with stroke - 0111)\r
+       x (latin capital letter african d - 0189)\r
+0111   LATIN SMALL LETTER D WITH STROKE\r
+       * Croatian, Vietnamese, Sámi\r
+       x (latin capital letter d with stroke - 0110)\r
+       x (cyrillic small letter dje - 0452)\r
+0112   LATIN CAPITAL LETTER E WITH MACRON\r
+       : 0045 0304\r
+0113   LATIN SMALL LETTER E WITH MACRON\r
+       * Latvian, Latin, ...\r
+       : 0065 0304\r
+0114   LATIN CAPITAL LETTER E WITH BREVE\r
+       : 0045 0306\r
+0115   LATIN SMALL LETTER E WITH BREVE\r
+       * Malay, Latin, ...\r
+       : 0065 0306\r
+0116   LATIN CAPITAL LETTER E WITH DOT ABOVE\r
+       : 0045 0307\r
+0117   LATIN SMALL LETTER E WITH DOT ABOVE\r
+       * Lithuanian\r
+       : 0065 0307\r
+0118   LATIN CAPITAL LETTER E WITH OGONEK\r
+       : 0045 0328\r
+0119   LATIN SMALL LETTER E WITH OGONEK\r
+       * Polish, Lithuanian, ...\r
+       : 0065 0328\r
+011A   LATIN CAPITAL LETTER E WITH CARON\r
+       : 0045 030C\r
+011B   LATIN SMALL LETTER E WITH CARON\r
+       * Czech, ...\r
+       : 0065 030C\r
+011C   LATIN CAPITAL LETTER G WITH CIRCUMFLEX\r
+       : 0047 0302\r
+011D   LATIN SMALL LETTER G WITH CIRCUMFLEX\r
+       * Esperanto\r
+       : 0067 0302\r
+011E   LATIN CAPITAL LETTER G WITH BREVE\r
+       : 0047 0306\r
+011F   LATIN SMALL LETTER G WITH BREVE\r
+       * Turkish, Azerbaijani\r
+       x (latin small letter g with caron - 01E7)\r
+       : 0067 0306\r
+0120   LATIN CAPITAL LETTER G WITH DOT ABOVE\r
+       : 0047 0307\r
+0121   LATIN SMALL LETTER G WITH DOT ABOVE\r
+       * Maltese, Irish Gaelic (old orthography)\r
+       : 0067 0307\r
+0122   LATIN CAPITAL LETTER G WITH CEDILLA\r
+       : 0047 0327\r
+0123   LATIN SMALL LETTER G WITH CEDILLA\r
+       * Latvian\r
+       * there are three major glyph variants\r
+       : 0067 0327\r
+0124   LATIN CAPITAL LETTER H WITH CIRCUMFLEX\r
+       : 0048 0302\r
+0125   LATIN SMALL LETTER H WITH CIRCUMFLEX\r
+       * Esperanto\r
+       : 0068 0302\r
+0126   LATIN CAPITAL LETTER H WITH STROKE\r
+0127   LATIN SMALL LETTER H WITH STROKE\r
+       * Maltese, IPA, ...\r
+       x (cyrillic small letter tshe - 045B)\r
+       x (planck constant over two pi - 210F)\r
+0128   LATIN CAPITAL LETTER I WITH TILDE\r
+       : 0049 0303\r
+0129   LATIN SMALL LETTER I WITH TILDE\r
+       * Greenlandic (old orthography)\r
+       : 0069 0303\r
+012A   LATIN CAPITAL LETTER I WITH MACRON\r
+       : 0049 0304\r
+012B   LATIN SMALL LETTER I WITH MACRON\r
+       * Latvian, Latin, ...\r
+       : 0069 0304\r
+012C   LATIN CAPITAL LETTER I WITH BREVE\r
+       : 0049 0306\r
+012D   LATIN SMALL LETTER I WITH BREVE\r
+       * Latin, ...\r
+       : 0069 0306\r
+012E   LATIN CAPITAL LETTER I WITH OGONEK\r
+       : 0049 0328\r
+012F   LATIN SMALL LETTER I WITH OGONEK\r
+       * Lithuanian, ...\r
+       : 0069 0328\r
+0130   LATIN CAPITAL LETTER I WITH DOT ABOVE\r
+       = LATIN CAPITAL LETTER I DOT\r
+       * Turkish, Azerbaijani\r
+       * lowercase is 0069\r
+       x (latin capital letter i - 0049)\r
+       : 0049 0307\r
+0131   LATIN SMALL LETTER DOTLESS I\r
+       * Turkish, Azerbaijani\r
+       * uppercase is 0049\r
+       x (latin small letter i - 0069)\r
+0132   LATIN CAPITAL LIGATURE IJ\r
+       # 0049 004A\r
+0133   LATIN SMALL LIGATURE IJ\r
+       * Dutch\r
+       # 0069 006A\r
+0134   LATIN CAPITAL LETTER J WITH CIRCUMFLEX\r
+       : 004A 0302\r
+0135   LATIN SMALL LETTER J WITH CIRCUMFLEX\r
+       * Esperanto\r
+       : 006A 0302\r
+0136   LATIN CAPITAL LETTER K WITH CEDILLA\r
+       : 004B 0327\r
+0137   LATIN SMALL LETTER K WITH CEDILLA\r
+       * Latvian\r
+       : 006B 0327\r
+0138   LATIN SMALL LETTER KRA (Greenlandic)\r
+       * Greenlandic (old orthography)\r
+0139   LATIN CAPITAL LETTER L WITH ACUTE\r
+       : 004C 0301\r
+013A   LATIN SMALL LETTER L WITH ACUTE\r
+       * Slovak\r
+       : 006C 0301\r
+013B   LATIN CAPITAL LETTER L WITH CEDILLA\r
+       : 004C 0327\r
+013C   LATIN SMALL LETTER L WITH CEDILLA\r
+       * Latvian\r
+       : 006C 0327\r
+013D   LATIN CAPITAL LETTER L WITH CARON\r
+       : 004C 030C\r
+013E   LATIN SMALL LETTER L WITH CARON\r
+       * Slovak\r
+       * the form using apostrophe is preferred in typesetting\r
+       : 006C 030C\r
+013F   LATIN CAPITAL LETTER L WITH MIDDLE DOT\r
+       * some fonts show the middle dot inside the L, but the preferred form has the dot following the L\r
+       # 004C 00B7\r
+0140   LATIN SMALL LETTER L WITH MIDDLE DOT\r
+       * Catalan\r
+       # 006C 00B7\r
+0141   LATIN CAPITAL LETTER L WITH STROKE\r
+0142   LATIN SMALL LETTER L WITH STROKE\r
+       * Polish, ...\r
+       x (latin small letter l with bar - 019A)\r
+0143   LATIN CAPITAL LETTER N WITH ACUTE\r
+       : 004E 0301\r
+0144   LATIN SMALL LETTER N WITH ACUTE\r
+       * Polish, ...\r
+       : 006E 0301\r
+0145   LATIN CAPITAL LETTER N WITH CEDILLA\r
+       : 004E 0327\r
+0146   LATIN SMALL LETTER N WITH CEDILLA\r
+       * Latvian\r
+       : 006E 0327\r
+0147   LATIN CAPITAL LETTER N WITH CARON\r
+       : 004E 030C\r
+0148   LATIN SMALL LETTER N WITH CARON\r
+       * Czech, Slovak\r
+       : 006E 030C\r
+0149   LATIN SMALL LETTER N PRECEDED BY APOSTROPHE\r
+       = LATIN SMALL LETTER APOSTROPHE N\r
+       * Afrikaans\r
+       * this is not actually a single letter\r
+       # 02BC 006E\r
+014A   LATIN CAPITAL LETTER ENG (Sami)\r
+       * glyph may also have appearance of large form of the small letter\r
+014B   LATIN SMALL LETTER ENG (Sami)\r
+       * Sámi, Mende, IPA, ...\r
+014C   LATIN CAPITAL LETTER O WITH MACRON\r
+       : 004F 0304\r
+014D   LATIN SMALL LETTER O WITH MACRON\r
+       * Latvian, Latin, ...\r
+       : 006F 0304\r
+014E   LATIN CAPITAL LETTER O WITH BREVE\r
+       : 004F 0306\r
+014F   LATIN SMALL LETTER O WITH BREVE\r
+       * Latin\r
+       : 006F 0306\r
+0150   LATIN CAPITAL LETTER O WITH DOUBLE ACUTE\r
+       : 004F 030B\r
+0151   LATIN SMALL LETTER O WITH DOUBLE ACUTE\r
+       * Hungarian\r
+       : 006F 030B\r
+0152   LATIN CAPITAL LIGATURE OE\r
+0153   LATIN SMALL LIGATURE OE\r
+       = LATIN SMALL LETTER O E\r
+       = ethel (from Old English eðel)\r
+       * French, IPA, Old Icelandic, Old English, ...\r
+       x (latin small letter ae - 00E6)\r
+       x (latin letter small capital oe - 0276)\r
+0154   LATIN CAPITAL LETTER R WITH ACUTE\r
+       : 0052 0301\r
+0155   LATIN SMALL LETTER R WITH ACUTE\r
+       * Slovak, ...\r
+       : 0072 0301\r
+0156   LATIN CAPITAL LETTER R WITH CEDILLA\r
+       : 0052 0327\r
+0157   LATIN SMALL LETTER R WITH CEDILLA\r
+       * Latvian\r
+       : 0072 0327\r
+0158   LATIN CAPITAL LETTER R WITH CARON\r
+       : 0052 030C\r
+0159   LATIN SMALL LETTER R WITH CARON\r
+       * Czech, ...\r
+       : 0072 030C\r
+015A   LATIN CAPITAL LETTER S WITH ACUTE\r
+       : 0053 0301\r
+015B   LATIN SMALL LETTER S WITH ACUTE\r
+       * Polish, Indic transliteration, ...\r
+       : 0073 0301\r
+015C   LATIN CAPITAL LETTER S WITH CIRCUMFLEX\r
+       : 0053 0302\r
+015D   LATIN SMALL LETTER S WITH CIRCUMFLEX\r
+       * Esperanto\r
+       : 0073 0302\r
+015E   LATIN CAPITAL LETTER S WITH CEDILLA *\r
+       : 0053 0327\r
+015F   LATIN SMALL LETTER S WITH CEDILLA *\r
+       * Turkish, Azerbaijani, Romanian, ...\r
+       * this character is used in both Turkish and Romanian data\r
+       * a glyph variant with comma below is preferred for Romanian\r
+       x (latin small letter s with comma below - 0219)\r
+       : 0073 0327\r
+0160   LATIN CAPITAL LETTER S WITH CARON\r
+       : 0053 030C\r
+0161   LATIN SMALL LETTER S WITH CARON\r
+       * Czech, Estonian, Finnish, Slovak, and many other languages\r
+       : 0073 030C\r
+0162   LATIN CAPITAL LETTER T WITH CEDILLA *\r
+       : 0054 0327\r
+0163   LATIN SMALL LETTER T WITH CEDILLA *\r
+       * Romanian, Semitic transliteration, ...\r
+       * this character is used in Romanian data\r
+       * a glyph variant with comma below is preferred for Romanian\r
+       x (latin small letter t with comma below - 021B)\r
+       : 0074 0327\r
+0164   LATIN CAPITAL LETTER T WITH CARON\r
+       * the form using caron/hacek is preferred in all contexts\r
+       : 0054 030C\r
+0165   LATIN SMALL LETTER T WITH CARON\r
+       * Czech, Slovak\r
+       * the form using apostrophe is preferred in typesetting\r
+       : 0074 030C\r
+0166   LATIN CAPITAL LETTER T WITH STROKE\r
+0167   LATIN SMALL LETTER T WITH STROKE\r
+       * Sámi\r
+0168   LATIN CAPITAL LETTER U WITH TILDE\r
+       : 0055 0303\r
+0169   LATIN SMALL LETTER U WITH TILDE\r
+       * Greenlandic (old orthography)\r
+       : 0075 0303\r
+016A   LATIN CAPITAL LETTER U WITH MACRON\r
+       : 0055 0304\r
+016B   LATIN SMALL LETTER U WITH MACRON\r
+       * Latvian, Lithuanian, Latin, ...\r
+       : 0075 0304\r
+016C   LATIN CAPITAL LETTER U WITH BREVE\r
+       : 0055 0306\r
+016D   LATIN SMALL LETTER U WITH BREVE\r
+       * Latin, Esperanto, ...\r
+       : 0075 0306\r
+016E   LATIN CAPITAL LETTER U WITH RING ABOVE\r
+       : 0055 030A\r
+016F   LATIN SMALL LETTER U WITH RING ABOVE\r
+       * Czech, ...\r
+       : 0075 030A\r
+0170   LATIN CAPITAL LETTER U WITH DOUBLE ACUTE\r
+       : 0055 030B\r
+0171   LATIN SMALL LETTER U WITH DOUBLE ACUTE\r
+       * Hungarian\r
+       : 0075 030B\r
+0172   LATIN CAPITAL LETTER U WITH OGONEK\r
+       : 0055 0328\r
+0173   LATIN SMALL LETTER U WITH OGONEK\r
+       * Lithuanian\r
+       : 0075 0328\r
+0174   LATIN CAPITAL LETTER W WITH CIRCUMFLEX\r
+       : 0057 0302\r
+0175   LATIN SMALL LETTER W WITH CIRCUMFLEX\r
+       * Welsh\r
+       : 0077 0302\r
+0176   LATIN CAPITAL LETTER Y WITH CIRCUMFLEX\r
+       : 0059 0302\r
+0177   LATIN SMALL LETTER Y WITH CIRCUMFLEX\r
+       * Welsh\r
+       : 0079 0302\r
+0178   LATIN CAPITAL LETTER Y WITH DIAERESIS\r
+       * French, Igbo\r
+       x (latin small letter y with diaeresis - 00FF)\r
+       : 0059 0308\r
+0179   LATIN CAPITAL LETTER Z WITH ACUTE\r
+       : 005A 0301\r
+017A   LATIN SMALL LETTER Z WITH ACUTE\r
+       * Polish, ...\r
+       : 007A 0301\r
+017B   LATIN CAPITAL LETTER Z WITH DOT ABOVE\r
+       : 005A 0307\r
+017C   LATIN SMALL LETTER Z WITH DOT ABOVE\r
+       * Polish, ...\r
+       : 007A 0307\r
+017D   LATIN CAPITAL LETTER Z WITH CARON\r
+       : 005A 030C\r
+017E   LATIN SMALL LETTER Z WITH CARON\r
+       * Czech, Estonian, Finnish, Slovak, Slovenian, and many other languages\r
+       : 007A 030C\r
+017F   LATIN SMALL LETTER LONG S\r
+       * in common use in Roman types until the 18th century\r
+       * in current use in Fraktur and Gaelic types\r
+       # 0073 latin small letter s\r
+@@     0180    Latin Extended-B        024F\r
+@              Latin extended-B\r
+0180   LATIN SMALL LETTER B WITH STROKE\r
+       * Americanist and Indo-Europeanist usage for phonetic beta\r
+       * Old Saxon\r
+       x (greek small letter beta - 03B2)\r
+       x (blank symbol - 2422)\r
+0181   LATIN CAPITAL LETTER B WITH HOOK\r
+       * Zulu, Pan-Nigerian alphabet\r
+       x (latin small letter b with hook - 0253)\r
+0182   LATIN CAPITAL LETTER B WITH TOPBAR\r
+0183   LATIN SMALL LETTER B WITH TOPBAR\r
+       * Zhuang\r
+       * former Soviet minority language scripts\r
+       x (cyrillic capital letter be - 0411)\r
+0184   LATIN CAPITAL LETTER TONE SIX\r
+0185   LATIN SMALL LETTER TONE SIX\r
+       * Zhuang\r
+       * Zhuang tone three is Cyrillic ze\r
+       * Zhuang tone four is Cyrillic che\r
+       x (latin small letter tone two - 01A8)\r
+       x (latin small letter tone five - 01BD)\r
+       x (cyrillic small letter ze - 0437)\r
+       x (cyrillic small letter che - 0447)\r
+       x (cyrillic small letter soft sign - 044C)\r
+0186   LATIN CAPITAL LETTER OPEN O\r
+       * typographically a turned C\r
+       x (latin small letter open o - 0254)\r
+0187   LATIN CAPITAL LETTER C WITH HOOK\r
+0188   LATIN SMALL LETTER C WITH HOOK\r
+       * African\r
+0189   LATIN CAPITAL LETTER AFRICAN D *\r
+       * Ewe\r
+       x (latin capital letter eth - 00D0)\r
+       x (latin capital letter d with stroke - 0110)\r
+       x (latin small letter d with tail - 0256)\r
+018A   LATIN CAPITAL LETTER D WITH HOOK\r
+       * Pan-Nigerian alphabet\r
+       x (latin small letter d with hook - 0257)\r
+018B   LATIN CAPITAL LETTER D WITH TOPBAR\r
+018C   LATIN SMALL LETTER D WITH TOPBAR\r
+       * former-Soviet minority language scripts\r
+018D   LATIN SMALL LETTER TURNED DELTA\r
+       * archaic phonetic for labialized dental fricative\r
+       * recommended spellings 007A 02B7 or 007A 032B\r
+018E   LATIN CAPITAL LETTER REVERSED E\r
+       = LATIN CAPITAL LETTER TURNED E\r
+       * Pan-Nigerian alphabet\r
+       * lowercase is 01DD\r
+018F   LATIN CAPITAL LETTER SCHWA\r
+       * Azerbaijani, ...\r
+       x (latin small letter schwa - 0259)\r
+       x (cyrillic capital letter schwa - 04D8)\r
+0190   LATIN CAPITAL LETTER OPEN E\r
+       = LATIN CAPITAL LETTER EPSILON\r
+       * African\r
+       x (latin small letter open e - 025B)\r
+       x (euler constant - 2107)\r
+0191   LATIN CAPITAL LETTER F WITH HOOK\r
+       * African\r
+0192   LATIN SMALL LETTER F WITH HOOK\r
+       = LATIN SMALL LETTER SCRIPT F\r
+       = Florin currency symbol (Netherlands)\r
+       = function symbol\r
+       = abbreviation convention for folder\r
+0193   LATIN CAPITAL LETTER G WITH HOOK\r
+       * African\r
+       x (latin small letter g with hook - 0260)\r
+0194   LATIN CAPITAL LETTER GAMMA\r
+       * African\r
+       x (latin small letter gamma - 0263)\r
+0195   LATIN SMALL LETTER HV (hwair)\r
+       * Gothic transliteration\r
+       * uppercase is 01F6\r
+0196   LATIN CAPITAL LETTER IOTA\r
+       * African\r
+       x (latin small letter iota - 0269)\r
+0197   LATIN CAPITAL LETTER I WITH STROKE\r
+       = barred i, i bar\r
+       * African\r
+       * ISO 6438 gives lowercase as 026A, not 0268\r
+       x (latin letter small capital i - 026A)\r
+0198   LATIN CAPITAL LETTER K WITH HOOK\r
+0199   LATIN SMALL LETTER K WITH HOOK\r
+       * Hausa, Pan-Nigerian alphabet\r
+019A   LATIN SMALL LETTER L WITH BAR\r
+       = barred l\r
+       * Americanist phonetic usage for 026C\r
+       x (latin small letter l with stroke - 0142)\r
+019B   LATIN SMALL LETTER LAMBDA WITH STROKE\r
+       = barred lambda, lambda bar\r
+       * Americanist phonetic usage\r
+019C   LATIN CAPITAL LETTER TURNED M\r
+       * Zhuang\r
+       x (latin small letter turned m - 026F)\r
+019D   LATIN CAPITAL LETTER N WITH LEFT HOOK\r
+       * African\r
+       x (latin small letter n with left hook - 0272)\r
+019E   LATIN SMALL LETTER N WITH LONG RIGHT LEG\r
+       * archaic phonetic for Japanese syllabic "n"\r
+       * recommended spelling 006E 0329\r
+019F   LATIN CAPITAL LETTER O WITH MIDDLE TILDE *\r
+       = barred o, o bar\r
+       * lowercase is 0275\r
+       * African\r
+       x (cyrillic capital letter barred o - 04E8)\r
+01A0   LATIN CAPITAL LETTER O WITH HORN\r
+       : 004F 031B\r
+01A1   LATIN SMALL LETTER O WITH HORN\r
+       * Vietnamese\r
+       : 006F 031B\r
+01A2   LATIN CAPITAL LETTER OI (gha)\r
+01A3   LATIN SMALL LETTER OI (gha)\r
+       = gha\r
+       * Pan-Turkic Latin alphabets\r
+01A4   LATIN CAPITAL LETTER P WITH HOOK\r
+01A5   LATIN SMALL LETTER P WITH HOOK\r
+       * African\r
+01A6   LATIN LETTER YR *\r
+       * old Norse\r
+       * from German Standard DIN 31624 and ISO 5246-2\r
+       * lowercase is 0280\r
+01A7   LATIN CAPITAL LETTER TONE TWO\r
+01A8   LATIN SMALL LETTER TONE TWO\r
+       * Zhuang\r
+       * typographically a reversed S\r
+       x (latin small letter tone six - 0185)\r
+01A9   LATIN CAPITAL LETTER ESH\r
+       * African\r
+       x (latin small letter esh - 0283)\r
+       x (greek capital letter sigma - 03A3)\r
+01AA   LATIN LETTER REVERSED ESH LOOP\r
+       * archaic phonetic for labialized palatoalveolar or palatal fricative\r
+       * Twi\r
+       * recommended spellings 0283 02B7, 00E7 02B7, 0068 0265, etc.\r
+01AB   LATIN SMALL LETTER T WITH PALATAL HOOK\r
+       * archaic phonetic for palatalized alveolar or dental stop\r
+       * recommended spelling 0074 02B2\r
+01AC   LATIN CAPITAL LETTER T WITH HOOK\r
+01AD   LATIN SMALL LETTER T WITH HOOK\r
+       * African\r
+01AE   LATIN CAPITAL LETTER T WITH RETROFLEX HOOK\r
+       * African\r
+       x (latin small letter t with retroflex hook - 0288)\r
+01AF   LATIN CAPITAL LETTER U WITH HORN\r
+       : 0055 031B\r
+01B0   LATIN SMALL LETTER U WITH HORN\r
+       * Vietnamese\r
+       : 0075 031B\r
+01B1   LATIN CAPITAL LETTER UPSILON\r
+       * African\r
+       * typographically based on turned capital Greek omega\r
+       x (latin small letter upsilon - 028A)\r
+       x (inverted ohm sign - 2127)\r
+01B2   LATIN CAPITAL LETTER V WITH HOOK\r
+       = LATIN CAPITAL LETTER SCRIPT V\r
+       * African\r
+       x (latin small letter v with hook - 028B)\r
+01B3   LATIN CAPITAL LETTER Y WITH HOOK\r
+01B4   LATIN SMALL LETTER Y WITH HOOK\r
+       * Bini, Esoko, and other Edo languages in West Africa\r
+01B5   LATIN CAPITAL LETTER Z WITH STROKE\r
+01B6   LATIN SMALL LETTER Z WITH STROKE\r
+       = barred z, z bar\r
+       * Pan-Turkic Latin orthography\r
+       * handwritten variant of Latin "z"\r
+       x (latin small letter z - 007A)\r
+01B7   LATIN CAPITAL LETTER EZH\r
+       * African, Skolt Sámi\r
+       * lowercase is 0292\r
+       x (latin capital letter yogh - 021C)\r
+       x (cyrillic capital letter abkhasian dze - 04E0)\r
+01B8   LATIN CAPITAL LETTER EZH REVERSED\r
+01B9   LATIN SMALL LETTER EZH REVERSED\r
+       * archaic phonetic for voiced pharyngeal fricative\r
+       * sometimes typographically rendered with a turned digit 3\r
+       * recommended spelling 0295\r
+       x (latin letter pharyngeal voiced fricative - 0295)\r
+       x (arabic letter ain - 0639)\r
+01BA   LATIN SMALL LETTER EZH WITH TAIL\r
+       * archaic phonetic for labialized voiced palatoalveolar or palatal fricative\r
+       * Twi\r
+       * recommended spellings 0292 02B7 or 006A 02B7\r
+01BB   LATIN LETTER TWO WITH STROKE\r
+       * archaic phonetic for [dz] affricate\r
+       * recommended spellings 0292 or 0064 007A\r
+01BC   LATIN CAPITAL LETTER TONE FIVE\r
+01BD   LATIN SMALL LETTER TONE FIVE\r
+       * Zhuang\r
+       x (latin small letter tone six - 0185)\r
+01BE   LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE\r
+       * archaic phonetic for [ts] affricate\r
+       * recommended spelling 0074 0073\r
+       * letter form is actually derived from ligation of ts, rather than inverted glottal stop\r
+01BF   LATIN LETTER WYNN\r
+       = wen\r
+       * Runic letter borrowed into Latin script\r
+       * replaced by "w" in modern transcriptions of Old English\r
+       * uppercase is 01F7\r
+       x (runic letter wunjo wynn w - 16B9)\r
+01C0   LATIN LETTER DENTAL CLICK\r
+       = pipe\r
+       * Khoisan tradition\r
+       * "c" in Zulu orthography\r
+       x (solidus - 002F)\r
+       x (vertical line - 007C)\r
+       x (latin small letter turned t - 0287)\r
+       x (divides - 2223)\r
+01C1   LATIN LETTER LATERAL CLICK\r
+       = double pipe\r
+       * Khoisan tradition\r
+       * "x" in Zulu orthography\r
+       x (latin letter inverted glottal stop - 0296)\r
+       x (parallel to - 2225)\r
+01C2   LATIN LETTER ALVEOLAR CLICK\r
+       = double-barred pipe\r
+       * Khoisan tradition\r
+       x (not equal to - 2260)\r
+01C3   LATIN LETTER RETROFLEX CLICK\r
+       = LATIN LETTER EXCLAMATION MARK\r
+       * Khoisan tradition\r
+       * "q" in Zulu orthography\r
+       x (exclamation mark - 0021)\r
+       x (latin letter stretched c - 0297)\r
+@              Croatian digraphs matching Serbian Cyrillic letters\r
+01C4   LATIN CAPITAL LETTER DZ WITH CARON\r
+       # 0044 017D\r
+01C5   LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON\r
+       # 0044 017E\r
+01C6   LATIN SMALL LETTER DZ WITH CARON\r
+       x (cyrillic small letter dzhe - 045F)\r
+       # 0064 017E\r
+01C7   LATIN CAPITAL LETTER LJ\r
+       # 004C 004A\r
+01C8   LATIN CAPITAL LETTER L WITH SMALL LETTER J\r
+       # 004C 006A\r
+01C9   LATIN SMALL LETTER LJ\r
+       x (cyrillic small letter lje - 0459)\r
+       # 006C 006A\r
+01CA   LATIN CAPITAL LETTER NJ\r
+       # 004E 004A\r
+01CB   LATIN CAPITAL LETTER N WITH SMALL LETTER J\r
+       # 004E 006A\r
+01CC   LATIN SMALL LETTER NJ\r
+       x (cyrillic small letter nje - 045A)\r
+       # 006E 006A\r
+@              Pinyin diacritic-vowel combinations\r
+01CD   LATIN CAPITAL LETTER A WITH CARON\r
+       : 0041 030C\r
+01CE   LATIN SMALL LETTER A WITH CARON\r
+       * Pinyin third tone\r
+       : 0061 030C\r
+01CF   LATIN CAPITAL LETTER I WITH CARON\r
+       : 0049 030C\r
+01D0   LATIN SMALL LETTER I WITH CARON\r
+       * Pinyin third tone\r
+       : 0069 030C\r
+01D1   LATIN CAPITAL LETTER O WITH CARON\r
+       : 004F 030C\r
+01D2   LATIN SMALL LETTER O WITH CARON\r
+       * Pinyin third tone\r
+       : 006F 030C\r
+01D3   LATIN CAPITAL LETTER U WITH CARON\r
+       : 0055 030C\r
+01D4   LATIN SMALL LETTER U WITH CARON\r
+       * Pinyin third tone\r
+       : 0075 030C\r
+01D5   LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON\r
+       : 00DC 0304\r
+01D6   LATIN SMALL LETTER U WITH DIAERESIS AND MACRON\r
+       * Pinyin first tone\r
+       : 00FC 0304\r
+01D7   LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE\r
+       : 00DC 0301\r
+01D8   LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE\r
+       * Pinyin second tone\r
+       : 00FC 0301\r
+01D9   LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON\r
+       : 00DC 030C\r
+01DA   LATIN SMALL LETTER U WITH DIAERESIS AND CARON\r
+       * Pinyin third tone\r
+       : 00FC 030C\r
+01DB   LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE\r
+       : 00DC 0300\r
+01DC   LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE\r
+       * Pinyin fourth tone\r
+       : 00FC 0300\r
+@              Additions\r
+01DD   LATIN SMALL LETTER TURNED E\r
+       * Pan-Nigerian alphabet\r
+       * all other usages of schwa are 0259\r
+       * uppercase is 018E\r
+       x (latin small letter schwa - 0259)\r
+01DE   LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON\r
+       : 00C4 0304\r
+01DF   LATIN SMALL LETTER A WITH DIAERESIS AND MACRON\r
+       * Livonian, Uralicist usage\r
+       : 00E4 0304\r
+01E0   LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON\r
+       : 0226 0304\r
+01E1   LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON\r
+       * Uralicist usage\r
+       : 0227 0304\r
+01E2   LATIN CAPITAL LETTER AE WITH MACRON (ash) *\r
+       : 00C6 0304\r
+01E3   LATIN SMALL LETTER AE WITH MACRON (ash) *\r
+       * Old Norse, Old English\r
+       : 00E6 0304\r
+01E4   LATIN CAPITAL LETTER G WITH STROKE\r
+01E5   LATIN SMALL LETTER G WITH STROKE\r
+       * Skolt Sámi\r
+01E6   LATIN CAPITAL LETTER G WITH CARON\r
+       : 0047 030C\r
+01E7   LATIN SMALL LETTER G WITH CARON\r
+       * Skolt Sámi\r
+       x (latin small letter g with breve - 011F)\r
+       : 0067 030C\r
+01E8   LATIN CAPITAL LETTER K WITH CARON\r
+       : 004B 030C\r
+01E9   LATIN SMALL LETTER K WITH CARON\r
+       * Skolt Sámi\r
+       : 006B 030C\r
+01EA   LATIN CAPITAL LETTER O WITH OGONEK\r
+       : 004F 0328\r
+01EB   LATIN SMALL LETTER O WITH OGONEK\r
+       * Sámi, Iroquoian, Old Icelandic\r
+       : 006F 0328\r
+01EC   LATIN CAPITAL LETTER O WITH OGONEK AND MACRON\r
+       : 01EA 0304\r
+01ED   LATIN SMALL LETTER O WITH OGONEK AND MACRON\r
+       * Old Icelandic\r
+       : 01EB 0304\r
+01EE   LATIN CAPITAL LETTER EZH WITH CARON\r
+       : 01B7 030C\r
+01EF   LATIN SMALL LETTER EZH WITH CARON\r
+       * Skolt Sámi\r
+       : 0292 030C\r
+01F0   LATIN SMALL LETTER J WITH CARON\r
+       * IPA and many languages\r
+       : 006A 030C\r
+01F1   LATIN CAPITAL LETTER DZ\r
+       # 0044 005A\r
+01F2   LATIN CAPITAL LETTER D WITH SMALL LETTER Z\r
+       # 0044 007A\r
+01F3   LATIN SMALL LETTER DZ\r
+       # 0064 007A\r
+01F4   LATIN CAPITAL LETTER G WITH ACUTE\r
+       : 0047 0301\r
+01F5   LATIN SMALL LETTER G WITH ACUTE\r
+       * Macedonian and Serbian transliteration\r
+       : 0067 0301\r
+01F6   LATIN CAPITAL LETTER HWAIR\r
+       * lowercase is 0195\r
+01F7   LATIN CAPITAL LETTER WYNN\r
+       = wen\r
+       * lowercase is 01BF\r
+01F8   LATIN CAPITAL LETTER N WITH GRAVE\r
+       : 004E 0300\r
+01F9   LATIN SMALL LETTER N WITH GRAVE\r
+       * Pinyin\r
+       : 006E 0300\r
+01FA   LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE\r
+       : 00C5 0301\r
+01FB   LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE\r
+       : 00E5 0301\r
+01FC   LATIN CAPITAL LETTER AE WITH ACUTE (ash) *\r
+       : 00C6 0301\r
+01FD   LATIN SMALL LETTER AE WITH ACUTE (ash) *\r
+       : 00E6 0301\r
+01FE   LATIN CAPITAL LETTER O WITH STROKE AND ACUTE\r
+       : 00D8 0301\r
+01FF   LATIN SMALL LETTER O WITH STROKE AND ACUTE\r
+       : 00F8 0301\r
+@              Additions for Slovenian and Croatian\r
+0200   LATIN CAPITAL LETTER A WITH DOUBLE GRAVE\r
+       : 0041 030F\r
+0201   LATIN SMALL LETTER A WITH DOUBLE GRAVE\r
+       : 0061 030F\r
+0202   LATIN CAPITAL LETTER A WITH INVERTED BREVE\r
+       : 0041 0311\r
+0203   LATIN SMALL LETTER A WITH INVERTED BREVE\r
+       : 0061 0311\r
+0204   LATIN CAPITAL LETTER E WITH DOUBLE GRAVE\r
+       : 0045 030F\r
+0205   LATIN SMALL LETTER E WITH DOUBLE GRAVE\r
+       : 0065 030F\r
+0206   LATIN CAPITAL LETTER E WITH INVERTED BREVE\r
+       : 0045 0311\r
+0207   LATIN SMALL LETTER E WITH INVERTED BREVE\r
+       : 0065 0311\r
+0208   LATIN CAPITAL LETTER I WITH DOUBLE GRAVE\r
+       : 0049 030F\r
+0209   LATIN SMALL LETTER I WITH DOUBLE GRAVE\r
+       : 0069 030F\r
+020A   LATIN CAPITAL LETTER I WITH INVERTED BREVE\r
+       : 0049 0311\r
+020B   LATIN SMALL LETTER I WITH INVERTED BREVE\r
+       : 0069 0311\r
+020C   LATIN CAPITAL LETTER O WITH DOUBLE GRAVE\r
+       : 004F 030F\r
+020D   LATIN SMALL LETTER O WITH DOUBLE GRAVE\r
+       : 006F 030F\r
+020E   LATIN CAPITAL LETTER O WITH INVERTED BREVE\r
+       : 004F 0311\r
+020F   LATIN SMALL LETTER O WITH INVERTED BREVE\r
+       : 006F 0311\r
+0210   LATIN CAPITAL LETTER R WITH DOUBLE GRAVE\r
+       : 0052 030F\r
+0211   LATIN SMALL LETTER R WITH DOUBLE GRAVE\r
+       : 0072 030F\r
+0212   LATIN CAPITAL LETTER R WITH INVERTED BREVE\r
+       : 0052 0311\r
+0213   LATIN SMALL LETTER R WITH INVERTED BREVE\r
+       : 0072 0311\r
+0214   LATIN CAPITAL LETTER U WITH DOUBLE GRAVE\r
+       : 0055 030F\r
+0215   LATIN SMALL LETTER U WITH DOUBLE GRAVE\r
+       : 0075 030F\r
+0216   LATIN CAPITAL LETTER U WITH INVERTED BREVE\r
+       : 0055 0311\r
+0217   LATIN SMALL LETTER U WITH INVERTED BREVE\r
+       : 0075 0311\r
+@              Additions for Romanian\r
+0218   LATIN CAPITAL LETTER S WITH COMMA BELOW *\r
+       : 0053 0326\r
+0219   LATIN SMALL LETTER S WITH COMMA BELOW *\r
+       * Romanian, when distinct comma below form is required\r
+       x (latin small letter s with cedilla - 015F)\r
+       : 0073 0326\r
+021A   LATIN CAPITAL LETTER T WITH COMMA BELOW *\r
+       : 0054 0326\r
+021B   LATIN SMALL LETTER T WITH COMMA BELOW *\r
+       * Romanian, when distinct comma below form is required\r
+       x (latin small letter t with cedilla - 0163)\r
+       : 0074 0326\r
+@              Miscellaneous additions\r
+021C   LATIN CAPITAL LETTER YOGH\r
+       x (latin capital letter ezh - 01B7)\r
+021D   LATIN SMALL LETTER YOGH\r
+       * Middle English, Scots\r
+       x (latin small letter ezh - 0292)\r
+       x (ounce sign - 2125)\r
+021E   LATIN CAPITAL LETTER H WITH CARON\r
+       : 0048 030C\r
+021F   LATIN SMALL LETTER H WITH CARON\r
+       * Finnish Romany\r
+       : 0068 030C\r
+0222   LATIN CAPITAL LETTER OU\r
+0223   LATIN SMALL LETTER OU\r
+       * Algonquin, Huron\r
+       x (digit eight - 0038)\r
+0224   LATIN CAPITAL LETTER Z WITH HOOK\r
+0225   LATIN SMALL LETTER Z WITH HOOK\r
+       * Middle High German\r
+0226   LATIN CAPITAL LETTER A WITH DOT ABOVE\r
+       : 0041 0307\r
+0227   LATIN SMALL LETTER A WITH DOT ABOVE\r
+       * Uralicist usage\r
+       : 0061 0307\r
+0228   LATIN CAPITAL LETTER E WITH CEDILLA\r
+       : 0045 0327\r
+0229   LATIN SMALL LETTER E WITH CEDILLA\r
+       : 0065 0327\r
+@              Additions for Livonian\r
+022A   LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON\r
+       : 00D6 0304\r
+022B   LATIN SMALL LETTER O WITH DIAERESIS AND MACRON\r
+       * Livonian\r
+       : 00F6 0304\r
+022C   LATIN CAPITAL LETTER O WITH TILDE AND MACRON\r
+       : 00D5 0304\r
+022D   LATIN SMALL LETTER O WITH TILDE AND MACRON\r
+       * Livonian\r
+       : 00F5 0304\r
+022E   LATIN CAPITAL LETTER O WITH DOT ABOVE\r
+       : 004F 0307\r
+022F   LATIN SMALL LETTER O WITH DOT ABOVE\r
+       * Livonian\r
+       : 006F 0307\r
+0230   LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON\r
+       : 022E 0304\r
+0231   LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON\r
+       * Livonian\r
+       : 022F 0304\r
+0232   LATIN CAPITAL LETTER Y WITH MACRON\r
+       : 0059 0304\r
+0233   LATIN SMALL LETTER Y WITH MACRON\r
+       * Livonian, Cornish\r
+       : 0079 0304\r
+@@     0250    IPA Extensions  02AF\r
+@              IPA extensions\r
+@+             IPA includes basic Latin letters and a number of Latin letters from other blocks.\r
+               x (latin small letter ae - 00E6)\r
+               x (latin small letter c with cedilla - 00E7)\r
+               x (latin small letter eth - 00F0)\r
+               x (latin small letter o with stroke - 00F8)\r
+               x (latin small letter h with stroke - 0127)\r
+               x (latin small letter eng - 014B)\r
+               x (latin small ligature oe - 0153)\r
+               x (greek small letter beta - 03B2)\r
+               x (greek small letter theta - 03B8)\r
+               x (greek small letter lamda - 03BB)\r
+               x (greek small letter chi - 03C7)\r
+0250   LATIN SMALL LETTER TURNED A\r
+       * low central unrounded vowel\r
+0251   LATIN SMALL LETTER ALPHA\r
+       = LATIN SMALL LETTER SCRIPT A\r
+       * low back unrounded vowel\r
+       x (greek small letter alpha - 03B1)\r
+0252   LATIN SMALL LETTER TURNED ALPHA\r
+       * low back rounded vowel\r
+0253   LATIN SMALL LETTER B WITH HOOK\r
+       * implosive bilabial stop\r
+       * Pan-Nigerian alphabet\r
+       x (latin capital letter b with hook - 0181)\r
+0254   LATIN SMALL LETTER OPEN O\r
+       * typographically a turned c\r
+       * lower-mid back rounded vowel\r
+       x (latin capital letter open o - 0186)\r
+0255   LATIN SMALL LETTER C WITH CURL\r
+       * voiceless alveolo-palatal laminal fricative\r
+       * used in transcription of Mandarin Chinese\r
+       * sound spelled with 015B in Polish\r
+0256   LATIN SMALL LETTER D WITH TAIL\r
+       = LATIN SMALL LETTER D RETROFLEX HOOK\r
+       * voiced retroflex stop\r
+       x (latin capital letter african d - 0189)\r
+0257   LATIN SMALL LETTER D WITH HOOK\r
+       * implosive dental or alveolar stop\r
+       * Ewe, Pan-Nigerian alphabet\r
+       x (latin capital letter d with hook - 018A)\r
+0258   LATIN SMALL LETTER REVERSED E\r
+       * upper-mid central unrounded vowel\r
+0259   LATIN SMALL LETTER SCHWA\r
+       * mid-central unrounded vowel\r
+       * variant uppercase form 018E is associated with 01DD\r
+       x (latin capital letter schwa - 018F)\r
+       x (latin small letter turned e - 01DD)\r
+       x (cyrillic small letter schwa - 04D9)\r
+025A   LATIN SMALL LETTER SCHWA WITH HOOK\r
+       * rhotacized schwa\r
+025B   LATIN SMALL LETTER OPEN E\r
+       = LATIN SMALL LETTER EPSILON\r
+       * lower-mid front unrounded vowel\r
+       x (latin capital letter open e - 0190)\r
+       x (greek small letter epsilon - 03B5)\r
+025C   LATIN SMALL LETTER REVERSED OPEN E\r
+       * lower-mid central unrounded vowel\r
+025D   LATIN SMALL LETTER REVERSED OPEN E WITH HOOK\r
+       * rhotacized lower-mid central vowel\r
+025E   LATIN SMALL LETTER CLOSED REVERSED OPEN E\r
+       = LATIN SMALL LETTER CLOSED REVERSED EPSILON\r
+       * lower-mid central rounded vowel\r
+025F   LATIN SMALL LETTER DOTLESS J WITH STROKE\r
+       * voiced palatal stop\r
+       * typographically a turned f, but better thought of as a form of j\r
+       * "gy" in Hungarian orthography\r
+       * also archaic phonetic for palatoalveolar affricate 02A4\r
+0260   LATIN SMALL LETTER G WITH HOOK\r
+       * implosive velar stop\r
+       x (latin capital letter g with hook - 0193)\r
+0261   LATIN SMALL LETTER SCRIPT G\r
+       * voiced velar stop\r
+       x (latin small letter g - 0067)\r
+0262   LATIN LETTER SMALL CAPITAL G\r
+       * voiced uvular stop\r
+0263   LATIN SMALL LETTER GAMMA\r
+       * voiced velar fricative\r
+       x (latin capital letter gamma - 0194)\r
+       x (greek small letter gamma - 03B3)\r
+0264   LATIN SMALL LETTER RAMS HORN\r
+       = LATIN SMALL LETTER BABY GAMMA\r
+       * upper-mid back unrounded vowel\r
+0265   LATIN SMALL LETTER TURNED H\r
+       * voiced rounded palatal approximant\r
+0266   LATIN SMALL LETTER H WITH HOOK\r
+       * breathy-voiced glottal fricative\r
+       x (modifier letter small h with hook - 02B1)\r
+0267   LATIN SMALL LETTER HENG WITH HOOK\r
+       * voiceless coarticulated velar and palatoalveolar fricative\r
+       * "tj" or "kj" or "sj" in some Swedish dialects\r
+0268   LATIN SMALL LETTER I WITH STROKE\r
+       = barred i, i bar\r
+       * high central unrounded vowel\r
+       * ISO 6438 gives lowercase of 0197 as 026A, not 0268\r
+0269   LATIN SMALL LETTER IOTA\r
+       * semi-high front unrounded vowel\r
+@+             * obsoleted by IPA in 1989\r
+       * preferred use is 026A LATIN LETTER SMALL CAPITAL I\r
+       x (latin capital letter iota - 0196)\r
+       x (greek small letter iota - 03B9)\r
+026A   LATIN LETTER SMALL CAPITAL I\r
+       * semi-high front unrounded vowel\r
+       * preferred IPA alternate for 0269\r
+       x (latin capital letter i with stroke - 0197)\r
+026B   LATIN SMALL LETTER L WITH MIDDLE TILDE\r
+       * velarized voiced alveolar lateral approximant\r
+026C   LATIN SMALL LETTER L WITH BELT\r
+       * voiceless alveolar lateral fricative\r
+026D   LATIN SMALL LETTER L WITH RETROFLEX HOOK\r
+       * voiced retroflex lateral\r
+026E   LATIN SMALL LETTER LEZH\r
+       * voiced lateral fricative\r
+       * "dhl" in Zulu orthography\r
+026F   LATIN SMALL LETTER TURNED M\r
+       * high back unrounded vowel\r
+       x (latin capital letter turned m - 019C)\r
+0270   LATIN SMALL LETTER TURNED M WITH LONG LEG\r
+       * voiced velar approximant\r
+0271   LATIN SMALL LETTER M WITH HOOK\r
+       * voiced labiodental nasal\r
+0272   LATIN SMALL LETTER N WITH LEFT HOOK\r
+       * voiced palatal nasal\r
+       x (latin capital letter n with left hook - 019D)\r
+0273   LATIN SMALL LETTER N WITH RETROFLEX HOOK\r
+       * voiced retroflex nasal\r
+0274   LATIN LETTER SMALL CAPITAL N\r
+       * voiced uvular nasal\r
+0275   LATIN SMALL LETTER BARRED O\r
+       = o bar\r
+       * rounded mid-central vowel, i.e. rounded schwa\r
+       * uppercase is 019F\r
+       x (greek small letter theta - 03B8)\r
+       x (cyrillic small letter fita - 0473)\r
+       x (cyrillic small letter barred o - 04E9)\r
+0276   LATIN LETTER SMALL CAPITAL OE\r
+       * low front rounded vowel\r
+       x (latin small ligature oe - 0153)\r
+0277   LATIN SMALL LETTER CLOSED OMEGA\r
+       * semi-high back rounded vowel\r
+@+             * obsoleted by IPA in 1989\r
+       * preferred use is 028A latin small letter upsilon\r
+0278   LATIN SMALL LETTER PHI\r
+       * voiceless bilabial fricative\r
+       x (greek small letter phi - 03C6)\r
+0279   LATIN SMALL LETTER TURNED R\r
+       * voiced alveolar approximant\r
+       x (modifier letter small turned r - 02B4)\r
+027A   LATIN SMALL LETTER TURNED R WITH LONG LEG\r
+       * voiced lateral flap\r
+027B   LATIN SMALL LETTER TURNED R WITH HOOK\r
+       * voiced retroflex approximant\r
+       x (modifier letter small turned r with hook - 02B5)\r
+027C   LATIN SMALL LETTER R WITH LONG LEG\r
+       * voiced strident apico-alveolar trill\r
+@+             * obsoleted by IPA in 1989\r
+       * sound spelled with 0159 in Czech\r
+       * preferred phonetic representation for Czech is 0072 031D\r
+       * in current use in Gaelic types (as glyph variant of 0072)\r
+027D   LATIN SMALL LETTER R WITH TAIL\r
+       * voiced retroflex flap\r
+027E   LATIN SMALL LETTER R WITH FISHHOOK\r
+       * voiced alveolar flap or tap\r
+027F   LATIN SMALL LETTER REVERSED R WITH FISHHOOK\r
+       * apical dental vowel\r
+       * used in Sinological tradition\r
+       * IPA spelling - 007A 0329\r
+0280   LATIN LETTER SMALL CAPITAL R *\r
+       * voiced uvular trill\r
+       * Germanic, Old Norse\r
+       * uppercase is 01A6\r
+0281   LATIN LETTER SMALL CAPITAL INVERTED R\r
+       * voiced uvular fricative or approximant\r
+       x (modifier letter small capital inverted r - 02B6)\r
+0282   LATIN SMALL LETTER S WITH HOOK\r
+       * voiceless retroflex fricative\r
+0283   LATIN SMALL LETTER ESH\r
+       * voiceless postalveolar fricative\r
+       x (latin capital letter esh - 01A9)\r
+       x (integral - 222B)\r
+0284   LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK\r
+       * implosive palatal stop\r
+       * typographically based on 025F, not on 0283\r
+0285   LATIN SMALL LETTER SQUAT REVERSED ESH\r
+       * apical retroflex vowel\r
+       * used in Sinological tradition\r
+       * IPA spelling - 0290 0329\r
+0286   LATIN SMALL LETTER ESH WITH CURL\r
+       * palatalized voiceless postalveolar fricative\r
+       * suggested spelling - 0283 02B2\r
+0287   LATIN SMALL LETTER TURNED T\r
+       * dental click (sound of "tsk tsk")\r
+       x (latin letter dental click - 01C0)\r
+0288   LATIN SMALL LETTER T WITH RETROFLEX HOOK\r
+       * voiceless retroflex stop\r
+       x (latin capital letter t with retroflex hook - 01AE)\r
+0289   LATIN SMALL LETTER U BAR\r
+       * high central rounded vowel\r
+028A   LATIN SMALL LETTER UPSILON\r
+       * semi-high back rounded vowel\r
+       * preferred IPA alternate to 0277\r
+       x (latin capital letter upsilon - 01B1)\r
+       x (greek small letter upsilon - 03C5)\r
+028B   LATIN SMALL LETTER V WITH HOOK\r
+       = LATIN SMALL LETTER SCRIPT V\r
+       * voiced labiodental approximant\r
+       x (latin capital letter v with hook - 01B2)\r
+       x (greek small letter upsilon - 03C5)\r
+028C   LATIN SMALL LETTER TURNED V\r
+       = caret, wedge\r
+       * lower-mid back unrounded vowel\r
+       x (greek capital letter lamda - 039B)\r
+       x (caret - 2038)\r
+       x (logical and - 2227)\r
+028D   LATIN SMALL LETTER TURNED W\r
+       * voiceless rounded labiovelar approximant\r
+028E   LATIN SMALL LETTER TURNED Y\r
+       * voiced lateral approximant\r
+028F   LATIN LETTER SMALL CAPITAL Y\r
+       * semi-high front rounded vowel\r
+0290   LATIN SMALL LETTER Z WITH RETROFLEX HOOK\r
+       * voiced retroflex fricative\r
+0291   LATIN SMALL LETTER Z WITH CURL\r
+       * voiced alveolo-palatal laminal fricative\r
+       * sound spelled with 017A in Polish\r
+0292   LATIN SMALL LETTER EZH\r
+       = LATIN SMALL LETTER YOGH\r
+       = dram\r
+       * voiced postalveolar fricative\r
+       * uppercase is 01B7\r
+       * Skolt Sámi\r
+       x (latin small letter yogh - 021D)\r
+       x (cyrillic small letter abkhasian dze - 04E1)\r
+       x (ounce sign - 2125)\r
+0293   LATIN SMALL LETTER EZH WITH CURL\r
+       * palatalized voiced postalveolar fricative\r
+0294   LATIN LETTER GLOTTAL STOP\r
+       x (modifier letter glottal stop - 02C0)\r
+0295   LATIN LETTER PHARYNGEAL VOICED FRICATIVE\r
+       = LATIN LETTER REVERSED GLOTTAL STOP\r
+       * voiced pharyngeal fricative\r
+       * ain\r
+       x (latin small letter ezh reversed - 01B9)\r
+       x (modifier letter reversed glottal stop - 02C1)\r
+0296   LATIN LETTER INVERTED GLOTTAL STOP\r
+       * lateral click\r
+       x (latin letter lateral click - 01C1)\r
+0297   LATIN LETTER STRETCHED C\r
+       * palatal (or alveolar) click\r
+       x (latin letter retroflex click - 01C3)\r
+       x (complement - 2201)\r
+0298   LATIN LETTER BILABIAL CLICK\r
+       = LATIN LETTER BULLSEYE\r
+       x (circled dot operator - 2299)\r
+0299   LATIN LETTER SMALL CAPITAL B\r
+       * bilabial trill\r
+029A   LATIN SMALL LETTER CLOSED OPEN E\r
+       = LATIN SMALL LETTER CLOSED EPSILON\r
+       * lower-mid front rounded vowel\r
+       * non-IPA alternate for the preferred 0153\r
+029B   LATIN LETTER SMALL CAPITAL G WITH HOOK\r
+       * voiced uvular implosive\r
+029C   LATIN LETTER SMALL CAPITAL H\r
+       * voiceless epiglottal fricative\r
+029D   LATIN SMALL LETTER J WITH CROSSED-TAIL\r
+       * voiced palatal fricative\r
+029E   LATIN SMALL LETTER TURNED K\r
+       * proposed for velar click\r
+@+             * withdrawn by IPA in 1970\r
+029F   LATIN LETTER SMALL CAPITAL L\r
+       * velar lateral approximant\r
+02A0   LATIN SMALL LETTER Q WITH HOOK\r
+       * voiceless uvular implosive\r
+02A1   LATIN LETTER GLOTTAL STOP WITH STROKE\r
+       * voiced epiglottal stop\r
+02A2   LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE\r
+       * voiced epiglottal fricative\r
+02A3   LATIN SMALL LETTER DZ DIGRAPH\r
+       * voiced dental affricate\r
+02A4   LATIN SMALL LETTER DEZH DIGRAPH\r
+       * voiced postalveolar affricate\r
+02A5   LATIN SMALL LETTER DZ DIGRAPH WITH CURL\r
+       * voiced alveolo-palatal affricate\r
+02A6   LATIN SMALL LETTER TS DIGRAPH\r
+       * voiceless dental affricate\r
+02A7   LATIN SMALL LETTER TESH DIGRAPH\r
+       * voiceless postalveolar affricate\r
+02A8   LATIN SMALL LETTER TC DIGRAPH WITH CURL\r
+       * voiceless alveolo-palatal affricate\r
+@              IPA characters for disordered speech\r
+02A9   LATIN SMALL LETTER FENG DIGRAPH\r
+       * velopharyngeal fricative\r
+02AA   LATIN SMALL LETTER LS DIGRAPH\r
+       * lateral alveolar fricative (lisp)\r
+02AB   LATIN SMALL LETTER LZ DIGRAPH\r
+       * voiced lateral alveolar fricative\r
+02AC   LATIN LETTER BILABIAL PERCUSSIVE\r
+       * audible lip smack\r
+02AD   LATIN LETTER BIDENTAL PERCUSSIVE\r
+       * audible teeth gnashing\r
+@@     02B0    Spacing Modifier Letters        02FF\r
+@              Phonetic modifiers derived from Latin letters\r
+02B0   MODIFIER LETTER SMALL H\r
+       * aspiration\r
+       # <super> 0068\r
+02B1   MODIFIER LETTER SMALL H WITH HOOK\r
+       * breathy voiced, murmured\r
+       x (latin small letter h with hook - 0266)\r
+       x (combining diaeresis below - 0324)\r
+       # <super> 0266\r
+02B2   MODIFIER LETTER SMALL J\r
+       * palatalization\r
+       x (combining palatalized hook below - 0321)\r
+       # <super> 006A\r
+02B3   MODIFIER LETTER SMALL R\r
+       # <super> 0072\r
+02B4   MODIFIER LETTER SMALL TURNED R\r
+       x (latin small letter turned r - 0279)\r
+       # <super> 0279\r
+02B5   MODIFIER LETTER SMALL TURNED R WITH HOOK\r
+       x (latin small letter turned r with hook - 027B)\r
+       # <super> 027B\r
+02B6   MODIFIER LETTER SMALL CAPITAL INVERTED R\r
+       * preceding four used for r-coloring or r-offglides\r
+       x (latin letter small capital inverted r - 0281)\r
+       # <super> 0281\r
+02B7   MODIFIER LETTER SMALL W\r
+       * labialization\r
+       x (combining inverted double arch below - 032B)\r
+       # <super> 0077\r
+02B8   MODIFIER LETTER SMALL Y\r
+       * palatalization\r
+       * common Americanist substitution for 02B2\r
+       # <super> 0079\r
+@              Miscellaneous phonetic modifiers\r
+02B9   MODIFIER LETTER PRIME\r
+       * primary stress, emphasis\r
+       * transliteration of mjagkij znak (Cyrillic soft sign: palatalization)\r
+       x (apostrophe - 0027)\r
+       x (acute accent - 00B4)\r
+       x (modifier letter acute accent - 02CA)\r
+       x (combining acute accent - 0301)\r
+       x (greek numeral sign - 0374)\r
+       x (prime - 2032)\r
+02BA   MODIFIER LETTER DOUBLE PRIME\r
+       * exaggerated stress, contrastive stress\r
+       * transliteration of tverdyj znak (Cyrillic hard sign: no palatalization)\r
+       x (quotation mark - 0022)\r
+       x (combining double acute accent - 030B)\r
+       x (double prime - 2033)\r
+02BB   MODIFIER LETTER TURNED COMMA\r
+       * typographical alternate for 02BD or 02BF\r
+       x (combining turned comma above - 0312)\r
+       x (left single quotation mark - 2018)\r
+02BC   MODIFIER LETTER APOSTROPHE\r
+       = apostrophe\r
+       * glottal stop, glottalization, ejective\r
+       * spacing clone of Greek smooth breathing mark\r
+       * many languages use this as a letter of their alphabets\r
+       x (apostrophe - 0027)\r
+       x (combining comma above - 0313)\r
+       x (combining comma above right - 0315)\r
+       x (armenian apostrophe - 055A)\r
+       x (right single quotation mark - 2019)\r
+02BD   MODIFIER LETTER REVERSED COMMA\r
+       * weak aspiration\r
+       * spacing clone of Greek rough breathing mark\r
+       x (combining reversed comma above - 0314)\r
+       x (armenian modifier letter left half ring - 0559)\r
+       x (single high-reversed-9 quotation mark - 201B)\r
+02BE   MODIFIER LETTER RIGHT HALF RING\r
+       * transliteration of Arabic hamza (glottal stop)\r
+       x (armenian apostrophe - 055A)\r
+       x (arabic letter hamza - 0621)\r
+02BF   MODIFIER LETTER LEFT HALF RING\r
+       * transliteration of Arabic ain (voiced pharyngeal fricative)\r
+       x (armenian modifier letter left half ring - 0559)\r
+       x (arabic letter ain - 0639)\r
+02C0   MODIFIER LETTER GLOTTAL STOP\r
+       * ejective or glottalized\r
+       * typographical alternate for 02BC or 02BE\r
+       x (latin letter glottal stop - 0294)\r
+       x (combining hook above - 0309)\r
+02C1   MODIFIER LETTER REVERSED GLOTTAL STOP\r
+       * typographical alternate for 02BF\r
+       x (latin letter pharyngeal voiced fricative - 0295)\r
+02C2   MODIFIER LETTER LEFT ARROWHEAD\r
+       * fronted articulation\r
+02C3   MODIFIER LETTER RIGHT ARROWHEAD\r
+       * backed articulation\r
+02C4   MODIFIER LETTER UP ARROWHEAD\r
+       * raised articulation\r
+       x (circumflex accent - 005E)\r
+       x (up arrowhead - 2303)\r
+02C5   MODIFIER LETTER DOWN ARROWHEAD\r
+       * lowered articulation\r
+02C6   MODIFIER LETTER CIRCUMFLEX ACCENT\r
+       * rising-falling tone, falling tone, secondary stress, etc.\r
+       x (circumflex accent - 005E)\r
+       x (combining circumflex accent - 0302)\r
+02C7   CARON (Mandarin Chinese third tone)\r
+       = hacek\r
+       * falling-rising tone\r
+       * Mandarin Chinese third tone\r
+       x (combining caron - 030C)\r
+02C8   MODIFIER LETTER VERTICAL LINE\r
+       * primary stress, downstep\r
+       * precedes letter or syllable modified\r
+       x (apostrophe - 0027)\r
+       x (combining vertical line above - 030D)\r
+02C9   MODIFIER LETTER MACRON (Mandarin Chinese first tone)\r
+       * high level tone\r
+       * precedes or follows letter or syllable modified\r
+       * Mandarin Chinese first tone\r
+       x (macron - 00AF)\r
+       x (combining macron - 0304)\r
+02CA   MODIFIER LETTER ACUTE ACCENT (Mandarin Chinese second tone)\r
+       * high-rising tone (IPA), high tone, primary stress\r
+       * Mandarin Chinese second tone\r
+       x (acute accent - 00B4)\r
+       x (modifier letter prime - 02B9)\r
+       x (combining acute accent - 0301)\r
+       x (greek numeral sign - 0374)\r
+       x (armenian emphasis mark - 055B)\r
+02CB   MODIFIER LETTER GRAVE ACCENT (Mandarin Chinese fourth tone)\r
+       * high-falling tone (IPA), low tone, secondary or tertiary stress\r
+       * Mandarin Chinese fourth tone\r
+       x (grave accent - 0060)\r
+       x (combining grave accent - 0300)\r
+       x (armenian comma - 055D)\r
+02CC   MODIFIER LETTER LOW VERTICAL LINE\r
+       * secondary stress\r
+       * precedes letter or syllable modified\r
+       x (combining vertical line below - 0329)\r
+02CD   MODIFIER LETTER LOW MACRON\r
+       * low level tone\r
+       x (low line - 005F)\r
+       x (combining macron below - 0331)\r
+02CE   MODIFIER LETTER LOW GRAVE ACCENT\r
+       * low-falling tone\r
+02CF   MODIFIER LETTER LOW ACUTE ACCENT\r
+       * low-rising tone\r
+       x (greek lower numeral sign - 0375)\r
+02D0   MODIFIER LETTER TRIANGULAR COLON\r
+       * length mark\r
+       x (colon - 003A)\r
+02D1   MODIFIER LETTER HALF TRIANGULAR COLON\r
+       * half-length mark\r
+       x (middle dot - 00B7)\r
+02D2   MODIFIER LETTER CENTRED RIGHT HALF RING\r
+       * more rounded articulation\r
+02D3   MODIFIER LETTER CENTRED LEFT HALF RING\r
+       * less rounded articulation\r
+02D4   MODIFIER LETTER UP TACK\r
+       * vowel raising or closing\r
+       x (combining up tack below - 031D)\r
+       x (combining dot below - 0323)\r
+02D5   MODIFIER LETTER DOWN TACK\r
+       * vowel lowering or opening\r
+       x (combining left half ring below - 031C)\r
+       x (combining down tack below - 031E)\r
+02D6   MODIFIER LETTER PLUS SIGN\r
+       * advanced or fronted articulation\r
+       x (combining plus sign below - 031F)\r
+02D7   MODIFIER LETTER MINUS SIGN\r
+       * retracted or backed articulation\r
+       * glyph may have small end-serifs\r
+       x (combining minus sign below - 0320)\r
+@              Spacing clones of diacritics\r
+02D8   BREVE\r
+       x (combining breve - 0306)\r
+       # 0020 0306\r
+02D9   DOT ABOVE (Mandarin Chinese light tone)\r
+       * Mandarin Chinese fifth tone (light or neutral)\r
+       x (combining dot above - 0307)\r
+       # 0020 0307\r
+02DA   RING ABOVE\r
+       x (degree sign - 00B0)\r
+       x (combining ring above - 030A)\r
+       # 0020 030A\r
+02DB   OGONEK\r
+       x (combining ogonek - 0328)\r
+       # 0020 0328\r
+02DC   SMALL TILDE\r
+       x (tilde - 007E)\r
+       x (combining tilde - 0303)\r
+       x (tilde operator - 223C)\r
+       # 0020 0303\r
+02DD   DOUBLE ACUTE ACCENT\r
+       x (combining double acute accent - 030B)\r
+       # 0020 030B\r
+@              Additions based on 1989 IPA\r
+02DE   MODIFIER LETTER RHOTIC HOOK\r
+       * rhotacization in vowel\r
+       * often ligated: 025A = 0259 + 02DE; 025D = 025C + 02DE\r
+02DF   MODIFIER LETTER CROSS ACCENT\r
+       * Swedish grave accent\r
+02E0   MODIFIER LETTER SMALL GAMMA\r
+       * these modifier letters are occasionally used in transcription of affricates\r
+       # <super> 0263\r
+02E1   MODIFIER LETTER SMALL L\r
+       # <super> 006C\r
+02E2   MODIFIER LETTER SMALL S\r
+       # <super> 0073\r
+02E3   MODIFIER LETTER SMALL X\r
+       # <super> 0078\r
+02E4   MODIFIER LETTER SMALL REVERSED GLOTTAL STOP\r
+       # <super> 0295\r
+@              Tone letters\r
+02E5   MODIFIER LETTER EXTRA-HIGH TONE BAR\r
+02E6   MODIFIER LETTER HIGH TONE BAR\r
+02E7   MODIFIER LETTER MID TONE BAR\r
+02E8   MODIFIER LETTER LOW TONE BAR\r
+02E9   MODIFIER LETTER EXTRA-LOW TONE BAR\r
+02EA   MODIFIER LETTER YIN DEPARTING TONE MARK\r
+02EB   MODIFIER LETTER YANG DEPARTING TONE MARK\r
+@              IPA modifiers\r
+02EC   MODIFIER LETTER VOICING\r
+02ED   MODIFIER LETTER UNASPIRATED\r
+@              Other modifier letters\r
+02EE   MODIFIER LETTER DOUBLE APOSTROPHE\r
+\r
+2000   EN QUAD\r
+       : 2002 en space\r
+2001   EM QUAD\r
+       = mutton quad\r
+       : 2003 em space\r
+2002   EN SPACE\r
+       = nut\r
+       * half an em\r
+       # 0020 space\r
+2003   EM SPACE\r
+       = mutton\r
+       * nominally, a space equal to the type size in points\r
+       * may scale by the condensation factor of a font\r
+       # 0020 space\r
+2004   THREE-PER-EM SPACE\r
+       = thick space\r
+       # 0020 space\r
+2005   FOUR-PER-EM SPACE\r
+       = mid space\r
+       # 0020 space\r
+2006   SIX-PER-EM SPACE\r
+       * in computer typography sometimes equated to thin space\r
+       # 0020 space\r
+2007   FIGURE SPACE\r
+       * space equal to tabular width of a font\r
+       * this is equivalent to the digit width of fonts with fixed-width digits\r
+       # <noBreak> 0020\r
+2008   PUNCTUATION SPACE\r
+       * space equal to narrow punctuation of a font\r
+       # 0020 space\r
+2009   THIN SPACE\r
+       * a fifth of an em (or sometimes a sixth)\r
+       # 0020 space\r
+200A   HAIR SPACE\r
+       * thinner than a thin space\r
+       * in traditional typography, the thinnest space available\r
+       # 0020 space\r
+200B   ZERO WIDTH SPACE\r
+       * nominally zero width, but may expand in justification\r
+@              Formatting characters\r
+200C   ZERO WIDTH NON-JOINER\r
+       = ZWNJ\r
+200D   ZERO WIDTH JOINER\r
+       = ZWJ\r
+200E   LEFT-TO-RIGHT MARK\r
+       = LRM\r
+200F   RIGHT-TO-LEFT MARK\r
+       = RLM\r
+@              Dashes\r
+2010   HYPHEN\r
+       x (hyphen-minus - 002D)\r
+2011   NON-BREAKING HYPHEN\r
+       x (hyphen-minus - 002D)\r
+       # <noBreak> 2010\r
+2012   FIGURE DASH\r
+2013   EN DASH\r
+2014   EM DASH\r
+       * may be used in pairs to offset parenthetical text\r
+       x (katakana-hiragana prolonged sound mark - 30FC)\r
+2015   HORIZONTAL BAR\r
+       = QUOTATION DASH\r
+       * long dash introducing quoted text\r
+@              General punctuation\r
+2016   DOUBLE VERTICAL LINE\r
+       * used in pairs to indicate norm of a matrix\r
+       x (parallel to - 2225)\r
+2017   DOUBLE LOW LINE\r
+       * this is a spacing character\r
+       x (low line - 005F)\r
+       x (combining double low line - 0333)\r
+       # 0020 0333\r
+2018   LEFT SINGLE QUOTATION MARK\r
+       = SINGLE TURNED COMMA QUOTATION MARK\r
+       * this is the preferred glyph (as opposed to 201B)\r
+       x (apostrophe - 0027)\r
+       x (modifier letter turned comma - 02BB)\r
+       x (heavy single turned comma quotation mark ornament - 275B)\r
+2019   RIGHT SINGLE QUOTATION MARK\r
+       = SINGLE COMMA QUOTATION MARK\r
+       * this is the preferred character to use for apostrophe\r
+       x (apostrophe - 0027)\r
+       x (modifier letter apostrophe - 02BC)\r
+       x (heavy single comma quotation mark ornament - 275C)\r
+201A   SINGLE LOW-9 QUOTATION MARK\r
+       = LOW SINGLE COMMA QUOTATION MARK\r
+       * used as opening single quotation mark in some languages\r
+201B   SINGLE HIGH-REVERSED-9 QUOTATION MARK\r
+       = SINGLE REVERSED COMMA QUOTATION MARK\r
+       * glyph variant of 2018\r
+       x (modifier letter reversed comma - 02BD)\r
+201C   LEFT DOUBLE QUOTATION MARK\r
+       = DOUBLE TURNED COMMA QUOTATION MARK\r
+       * this is the preferred glyph (as opposed to 201F)\r
+       x (quotation mark - 0022)\r
+       x (heavy double turned comma quotation mark ornament - 275D)\r
+       x (reversed double prime quotation mark - 301D)\r
+201D   RIGHT DOUBLE QUOTATION MARK\r
+       = DOUBLE COMMA QUOTATION MARK\r
+       x (quotation mark - 0022)\r
+       x (double prime - 2033)\r
+       x (heavy double comma quotation mark ornament - 275E)\r
+       x (double prime quotation mark - 301E)\r
+201E   DOUBLE LOW-9 QUOTATION MARK\r
+       = LOW DOUBLE COMMA QUOTATION MARK\r
+       * used as opening double quotation mark in some languages\r
+       x (low double prime quotation mark - 301F)\r
+201F   DOUBLE HIGH-REVERSED-9 QUOTATION MARK\r
+       = DOUBLE REVERSED COMMA QUOTATION MARK\r
+       * glyph variant of 201C\r
+2020   DAGGER\r
+       = obelisk, obelus, long cross\r
+2021   DOUBLE DAGGER\r
+       = diesis, double obelisk\r
+2022   BULLET\r
+       = black small circle\r
+       x (middle dot - 00B7)\r
+       x (one dot leader - 2024)\r
+       x (bullet operator - 2219)\r
+       x (inverse bullet - 25D8)\r
+       x (white bullet - 25E6)\r
+2023   TRIANGULAR BULLET\r
+       x (end of proof - 220E)\r
+       x (black right-pointing small triangle - 25B8)\r
+2024   ONE DOT LEADER\r
+       x (middle dot - 00B7)\r
+       x (bullet - 2022)\r
+       x (bullet operator - 2219)\r
+       # 002E full stop\r
+2025   TWO DOT LEADER\r
+       # 002E 002E\r
+2026   HORIZONTAL ELLIPSIS\r
+       = three dot leader\r
+       x (vertical ellipsis - 22EE)\r
+       # 002E 002E 002E\r
+2027   HYPHENATION POINT\r
+@              Formatting characters\r
+2028   LINE SEPARATOR\r
+       * may be used to represent this semantic unambiguously\r
+2029   PARAGRAPH SEPARATOR\r
+       * may be used to represent this semantic unambiguously\r
+202A   LEFT-TO-RIGHT EMBEDDING\r
+       = LRE\r
+202B   RIGHT-TO-LEFT EMBEDDING\r
+       = RLE\r
+202C   POP DIRECTIONAL FORMATTING\r
+       = PDF\r
+202D   LEFT-TO-RIGHT OVERRIDE\r
+       = LRO\r
+202E   RIGHT-TO-LEFT OVERRIDE\r
+       = RLO\r
+202F   NARROW NO-BREAK SPACE\r
+       x (no-break space - 00A0)\r
+       # <noBreak> 0020\r
+@              General punctuation\r
+2030   PER MILLE SIGN\r
+       x (percent sign - 0025)\r
+2031   PER TEN THOUSAND SIGN\r
+       x (percent sign - 0025)\r
+2032   PRIME\r
+       = minutes, feet\r
+       x (apostrophe - 0027)\r
+       x (acute accent - 00B4)\r
+       x (modifier letter prime - 02B9)\r
+2033   DOUBLE PRIME\r
+       = seconds, inches\r
+       x (quotation mark - 0022)\r
+       x (modifier letter double prime - 02BA)\r
+       x (right double quotation mark - 201D)\r
+       x (ditto mark - 3003)\r
+       x (double prime quotation mark - 301E)\r
+       # 2032 2032\r
+2034   TRIPLE PRIME\r
+       # 2032 2032 2032\r
+2035   REVERSED PRIME\r
+       x (grave accent - 0060)\r
+2036   REVERSED DOUBLE PRIME\r
+       x (reversed double prime quotation mark - 301D)\r
+       # 2035 2035\r
+2037   REVERSED TRIPLE PRIME\r
+       # 2035 2035 2035\r
+2038   CARET\r
+       x (up arrowhead - 2303)\r
+2039   SINGLE LEFT-POINTING ANGLE QUOTATION MARK\r
+       = LEFT POINTING SINGLE GUILLEMET\r
+       * usually opening, sometimes closing\r
+       x (less-than sign - 003C)\r
+       x (left-pointing angle bracket - 2329)\r
+       x (left angle bracket - 3008)\r
+203A   SINGLE RIGHT-POINTING ANGLE QUOTATION MARK\r
+       = RIGHT POINTING SINGLE GUILLEMET\r
+       * usually closing, sometimes opening\r
+       x (greater-than sign - 003E)\r
+       x (right-pointing angle bracket - 232A)\r
+       x (right angle bracket - 3009)\r
+203B   REFERENCE MARK\r
+       = Japanese kome\r
+       = Urdu paragraph separator\r
+       x (tibetan ku ru kha bzhi mig can - 0FBF)\r
+203C   DOUBLE EXCLAMATION MARK\r
+       x (exclamation mark - 0021)\r
+       # 0021 0021\r
+203D   INTERROBANG\r
+       x (exclamation mark - 0021)\r
+       x (question mark - 003F)\r
+203E   OVERLINE\r
+       = SPACING OVERSCORE\r
+       # 0020 0305\r
+203F   UNDERTIE (Enotikon)\r
+       = Greek enotikon\r
+       x (smile - 2323)\r
+2040   CHARACTER TIE\r
+       x (frown - 2322)\r
+2041   CARET INSERTION POINT\r
+       * proofreader's mark: insert here\r
+       x (right semidirect product - 22CC)\r
+2042   ASTERISM\r
+2043   HYPHEN BULLET\r
+2044   FRACTION SLASH\r
+       = solidus (in typography)\r
+       * for composing arbitrary fractions\r
+       x (solidus - 002F)\r
+       x (division slash - 2215)\r
+2045   LEFT SQUARE BRACKET WITH QUILL\r
+2046   RIGHT SQUARE BRACKET WITH QUILL\r
+2048   QUESTION EXCLAMATION MARK\r
+       * designed for use in vertical text\r
+       # 003F 0021\r
+2049   EXCLAMATION QUESTION MARK\r
+       * designed for use in vertical text\r
+       # 0021 003F\r
+204A   TIRONIAN SIGN ET\r
+       * Irish Gaelic, ...\r
+204B   REVERSED PILCROW SIGN\r
+       x (pilcrow sign - 00B6)\r
+204C   BLACK LEFTWARDS BULLET\r
+204D   BLACK RIGHTWARDS BULLET\r
+@              Deprecated\r
+206A   INHIBIT SYMMETRIC SWAPPING\r
+206B   ACTIVATE SYMMETRIC SWAPPING\r
+206C   INHIBIT ARABIC FORM SHAPING\r
+206D   ACTIVATE ARABIC FORM SHAPING\r
+206E   NATIONAL DIGIT SHAPES\r
+206F   NOMINAL DIGIT SHAPES\r
+@@     2070    Superscripts and Subscripts     209F\r
+@              Superscripts\r
+2070   SUPERSCRIPT ZERO\r
+       # <super> 0030\r
+2071   <reserved>\r
+       x (superscript one - 00B9)\r
+2072   <reserved>\r
+       x (superscript two - 00B2)\r
+2073   <reserved>\r
+       x (superscript three - 00B3)\r
+2074   SUPERSCRIPT FOUR\r
+       # <super> 0034\r
+2075   SUPERSCRIPT FIVE\r
+       # <super> 0035\r
+2076   SUPERSCRIPT SIX\r
+       # <super> 0036\r
+2077   SUPERSCRIPT SEVEN\r
+       # <super> 0037\r
+2078   SUPERSCRIPT EIGHT\r
+       # <super> 0038\r
+2079   SUPERSCRIPT NINE\r
+       # <super> 0039\r
+207A   SUPERSCRIPT PLUS SIGN\r
+       # <super> 002B\r
+207B   SUPERSCRIPT MINUS\r
+       # <super> 2212\r
+207C   SUPERSCRIPT EQUALS SIGN\r
+       # <super> 003D\r
+207D   SUPERSCRIPT LEFT PARENTHESIS\r
+       # <super> 0028\r
+207E   SUPERSCRIPT RIGHT PARENTHESIS\r
+       # <super> 0029\r
+207F   SUPERSCRIPT LATIN SMALL LETTER N\r
+       # <super> 006E\r
+@              Subscripts\r
+2080   SUBSCRIPT ZERO\r
+       # <sub> 0030\r
+2081   SUBSCRIPT ONE\r
+       # <sub> 0031\r
+2082   SUBSCRIPT TWO\r
+       # <sub> 0032\r
+2083   SUBSCRIPT THREE\r
+       # <sub> 0033\r
+2084   SUBSCRIPT FOUR\r
+       # <sub> 0034\r
+2085   SUBSCRIPT FIVE\r
+       # <sub> 0035\r
+2086   SUBSCRIPT SIX\r
+       # <sub> 0036\r
+2087   SUBSCRIPT SEVEN\r
+       # <sub> 0037\r
+2088   SUBSCRIPT EIGHT\r
+       # <sub> 0038\r
+2089   SUBSCRIPT NINE\r
+       # <sub> 0039\r
+208A   SUBSCRIPT PLUS SIGN\r
+       # <sub> 002B\r
+208B   SUBSCRIPT MINUS\r
+       # <sub> 2212\r
+208C   SUBSCRIPT EQUALS SIGN\r
+       # <sub> 003D\r
+208D   SUBSCRIPT LEFT PARENTHESIS\r
+       # <sub> 0028\r
+208E   SUBSCRIPT RIGHT PARENTHESIS\r
+       # <sub> 0029\r
+@@     20A0    Currency Symbols        20CF\r
+@              Currency symbols\r
+@+             A number of currency symbols are found in other blocks.\r
+               x (dollar sign - 0024)\r
+               x (cent sign - 00A2)\r
+               x (pound sign - 00A3)\r
+               x (currency sign - 00A4)\r
+               x (yen sign - 00A5)\r
+               x (bengali rupee mark - 09F2)\r
+               x (bengali rupee sign - 09F3)\r
+               x (thai currency symbol baht - 0E3F)\r
+               x (khmer currency symbol riel - 17DB)\r
+20A0   EURO-CURRENCY SIGN\r
+       * intended for ECU, but not widely used\r
+       * historical character, this is NOT the euro!\r
+       x (euro sign - 20AC)\r
+20A1   COLON SIGN\r
+       * Costa Rica, El Salvador\r
+20A2   CRUZEIRO SIGN\r
+       * Brazil\r
+20A3   FRENCH FRANC SIGN\r
+       * France\r
+20A4   LIRA SIGN\r
+       * Italy, Turkey\r
+       x (pound sign - 00A3)\r
+20A5   MILL SIGN\r
+       * USA (1/10 cent)\r
+20A6   NAIRA SIGN\r
+       * Nigeria\r
+20A7   PESETA SIGN\r
+       * Spain\r
+20A8   RUPEE SIGN\r
+       * India\r
+       # 0052 0073\r
+20A9   WON SIGN\r
+       * Korea\r
+20AA   NEW SHEQEL SIGN\r
+       * Israel\r
+20AB   DONG SIGN\r
+       * Vietnam\r
+20AC   EURO SIGN\r
+       * currency sign for the European Monetary Union\r
+       * euro, not ECU\r
+       x (euro-currency sign - 20A0)\r
+20AD   KIP SIGN\r
+       * Laos\r
+20AE   TUGRIK SIGN\r
+       * Mongolia\r
+       * also transliterated as tugrug, tugric, tugrog, togrog\r
+20AF   DRACHMA SIGN\r
+       * Greece\r
+@@     20D0    Combining Diacritical Marks for Symbols 20FF\r
+@              Combining diacritical marks for symbols\r
+20D0   COMBINING LEFT HARPOON ABOVE\r
+20D1   COMBINING RIGHT HARPOON ABOVE\r
+       * vector\r
+20D2   COMBINING LONG VERTICAL LINE OVERLAY\r
+20D3   COMBINING SHORT VERTICAL LINE OVERLAY\r
+       * negation\r
+20D4   COMBINING ANTICLOCKWISE ARROW ABOVE\r
+20D5   COMBINING CLOCKWISE ARROW ABOVE\r
+       * rotation\r
+20D6   COMBINING LEFT ARROW ABOVE\r
+20D7   COMBINING RIGHT ARROW ABOVE\r
+       * vector\r
+20D8   COMBINING RING OVERLAY\r
+20D9   COMBINING CLOCKWISE RING OVERLAY\r
+20DA   COMBINING ANTICLOCKWISE RING OVERLAY\r
+20DB   COMBINING THREE DOTS ABOVE\r
+       = third derivative\r
+20DC   COMBINING FOUR DOTS ABOVE\r
+       = fourth derivative\r
+@              Enclosing diacritics\r
+20DD   COMBINING ENCLOSING CIRCLE\r
+       = JIS composition circle\r
+       x (white circle - 25CB)\r
+       x (large circle - 25EF)\r
+       x (ideographic number zero - 3007)\r
+20DE   COMBINING ENCLOSING SQUARE\r
+       x (white square - 25A1)\r
+20DF   COMBINING ENCLOSING DIAMOND\r
+       x (white diamond - 25C7)\r
+20E0   COMBINING ENCLOSING CIRCLE BACKSLASH\r
+       * prohibition\r
+@              Additional diacritical mark for symbols\r
+20E1   COMBINING LEFT RIGHT ARROW ABOVE\r
+       * tensor\r
+@              Additional enclosing diacritics\r
+20E2   COMBINING ENCLOSING SCREEN\r
+       x (clear screen symbol - 239A)\r
+20E3   COMBINING ENCLOSING KEYCAP\r
+\r
+*/\r
+\r
diff --git a/src/charnames.h b/src/charnames.h
new file mode 100755 (executable)
index 0000000..53d357c
--- /dev/null
@@ -0,0 +1,18 @@
+//\r
+// charnames.h\r
+//\r
+// A header file that links Unicode character names to character numbers.\r
+// Also, throws in the Macintosh standard glyph names to boot.\r
+//\r
+// by James L. Hammons\r
+//\r
+\r
+extern unsigned char macStdNames[];\r
+extern unsigned char unicodeChars[];\r
+\r
+/*struct unicodeChar\r
+{\r
+  int cNum;\r
+\r
+};*/\r
+\r
diff --git a/src/debug.cpp b/src/debug.cpp
new file mode 100755 (executable)
index 0000000..b165165
--- /dev/null
@@ -0,0 +1,206 @@
+//\r
+// DEBUG.CPP: Debugging support\r
+// by James L. Hammons\r
+// (C) 2002 Underground Software\r
+//\r
+//   JLH = James Hammons <jlhamm@acm.org>\r
+//\r
+// Who  When        What\r
+// ---  ----------  ------------------------------------------------------------\r
+// JLH  07/31/2002  Created this file\r
+// JLH  07/31/2002  Added debug log functions & system error logging functions\r
+// JLH  08/16/2002  Added debug log function for SQL error reporting, made\r
+//                  WriteLogMsg thread safe\r
+// JLH  12/10/2002  Added code to have a background message window\r
+// JLH  05/14/2004  Converted code to C++ (sans ODBC logging)\r
+// JLH  05/15/2005  Converted code to generic C++\r
+//\r
+\r
+//#include <windows.h>\r
+//#include <odbc.h>\r
+#include <stdarg.h>\r
+#include <stdio.h>\r
+#include "debug.h"\r
+\r
+// EQUATES\r
+\r
+//#define USDB_WRITEMESSAGE  WM_USER + 1                       // Display a message on the debug window\r
+\r
+// Function prototypes\r
+\r
+//void CreateDebugWin(void);\r
+//LRESULT CALLBACK DebugWinProc(HWND, UINT, WPARAM, LPARAM);\r
+\r
+// CONSTANTS\r
+\r
+const char logFilename[] = "debug.log";\r
+\r
+// DATA\r
+\r
+FILE * logFile = NULL;\r
+\r
+// UNINITIALIZED DATA\r
+\r
+//CRITICAL_SECTION csLock;                                             // Critical section lock\r
+\r
+//\r
+// Open the debugging log file\r
+//\r
+void OpenDebugLog(void)\r
+{\r
+//     hLogFile = CreateFile(logFilename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+//             NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH | FILE_ATTRIBUTE_NORMAL, NULL);\r
+//     InitializeCriticalSection(&csLock);\r
+       logFile = fopen(logFilename, "wb");\r
+#ifdef DEBUGWIN\r
+       CreateDebugWin();\r
+#endif\r
+}\r
+\r
+//\r
+// Close the debugging log file\r
+//\r
+void CloseDebugLog(void)\r
+{\r
+//     CloseHandle(hLogFile);\r
+       fclose(logFile);\r
+//     DeleteCriticalSection(&csLock);\r
+\r
+//     if (hDebugWnd)\r
+//             DestroyWindow(hDebugWnd);\r
+}\r
+\r
+//\r
+// Write a message to the log file\r
+//\r
+/*void WriteLogMsg(char * msg)\r
+{\r
+       if (!msg)                                                                       // Check for valid pointer\r
+               return;\r
+\r
+       EnterCriticalSection(&csLock);\r
+\r
+       if (hLogFile)\r
+               WriteFile(hLogFile, msg, lstrlen(msg), &wfBytesWritten, NULL);\r
+\r
+       if (hDebugWnd)\r
+               SendMessage(hDebugWnd, USDB_WRITEMESSAGE, FALSE, (LPARAM)msg);\r
+\r
+       LeaveCriticalSection(&csLock);\r
+}//*/\r
+\r
+//\r
+// This logger is used mainly to ensure that text gets written to the log file\r
+// even if the program crashes. The performance hit is acceptable in this case!\r
+//\r
+void WriteLogMsg(const char * msg, ...)\r
+{\r
+       if (!msg)                                                                       // Check for valid pointer\r
+               return;\r
+\r
+//     EnterCriticalSection(&csLock);\r
+\r
+       va_list arg;\r
+\r
+       va_start(arg, msg);\r
+//     wvsprintf(str, msg, arg);\r
+       if (logFile)\r
+       {\r
+               vfprintf(logFile, msg, arg);\r
+               fflush(logFile);\r
+       }\r
+\r
+       va_end(arg);\r
+\r
+//     if (hLogFile)\r
+//             WriteFile(hLogFile, str, lstrlen(msg), &wfBytesWritten, NULL);\r
+\r
+//     if (hDebugWnd)\r
+//             SendMessage(hDebugWnd, USDB_WRITEMESSAGE, FALSE, (LPARAM)str);\r
+\r
+//     LeaveCriticalSection(&csLock);\r
+}\r
+\r
+\r
+//\r
+// Display a system error message on the screen\r
+//\r
+/*void DisplaySysError(HWND hWnd)\r
+{\r
+       FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL,\r
+               GetLastError(), 1024, pBuf, 0, NULL);\r
+       MessageBox(hWnd, pBuf, errTitle, MB_ICONERROR);\r
+       LocalFree(pBuf);\r
+}\r
+\r
+//\r
+// Create "live log" debug window\r
+//\r
+void CreateDebugWin(void)\r
+{\r
+       WNDCLASS wc;\r
+\r
+       RtlZeroMemory(&wc, sizeof(wc));\r
+       wc.lpfnWndProc = DebugWinProc;\r
+       wc.hInstance = GetModuleHandle(NULL);\r
+       wc.hCursor = LoadCursor(NULL, IDC_ARROW);\r
+       wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);\r
+       wc.lpszClassName = CNDebug;\r
+\r
+       if (!RegisterClass(&wc))\r
+               return;\r
+\r
+       hDebugWnd = CreateWindowEx(NULL, CNDebug, debugWin,\r
+               WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_SYSMENU,\r
+               0, 0, 400, 400, NULL, NULL, NULL, NULL);\r
+}\r
+\r
+//\r
+// Debug "live log" window procedure\r
+//\r
+LRESULT CALLBACK DebugWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+       switch (uMsg)\r
+       {\r
+       // *****************\r
+       // *** WM_CREATE ***\r
+       // *****************\r
+\r
+       case WM_CREATE:\r
+               hEdit1 = CreateWindowEx(NULL, CNEdit, NULL,\r
+                       WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_READONLY | ES_MULTILINE | ES_AUTOVSCROLL,\r
+                       0, 0, 1, 1, hWnd, NULL, NULL, NULL);\r
+               break;\r
+\r
+       // ******************\r
+       // *** WM_DESTROY ***\r
+       // ******************\r
+\r
+       case WM_DESTROY:\r
+               hDebugWnd = NULL;                                               // Just in case user closes it himself...\r
+               break;\r
+\r
+       // ***************\r
+       // *** WM_SIZE ***\r
+       // ***************\r
+\r
+       case WM_SIZE:\r
+               SetWindowPos(hEdit1, NULL, 0, 0, lParam & 0xFFFF, lParam >> 16, SWP_NOMOVE | SWP_NOZORDER);\r
+               break;\r
+\r
+       // *************************\r
+       // *** USDB_WRITEMESSAGE ***\r
+       // *************************\r
+\r
+       case USDB_WRITEMESSAGE:\r
+               SendMessage(hEdit1, EM_SETSEL, -2, -2);\r
+               SendMessage(hEdit1, EM_REPLACESEL, wParam, lParam);\r
+               break;\r
+\r
+       default:\r
+               return DefWindowProc(hWnd, uMsg, wParam, lParam);\r
+       }\r
+\r
+       return 0;\r
+}\r
+//*/\r
diff --git a/src/debug.h b/src/debug.h
new file mode 100755 (executable)
index 0000000..b53a15d
--- /dev/null
@@ -0,0 +1,15 @@
+//\r
+// DEBUG.H: Debugging support header\r
+// by James L. Hammons\r
+// (C) 2002 Underground Software\r
+//\r
+\r
+// Function prototypes\r
+\r
+void OpenDebugLog(void);\r
+void CloseDebugLog(void);\r
+void WriteLogMsg(const char *, ...);\r
+//void WriteSysMsg(void);\r
+//void WriteSQLMsg(DWORD, DWORD);\r
+//void DisplaySysError(HWND);\r
+\r
diff --git a/src/glyphpoints.cpp b/src/glyphpoints.cpp
new file mode 100755 (executable)
index 0000000..a2b80aa
--- /dev/null
@@ -0,0 +1,581 @@
+//\r
+// GLYPHPOINTS.CPP\r
+//\r
+// Class implementation. Nothing too inexplicable going on here. Fairly\r
+// straightforward stuff.\r
+//\r
+// by James L. Hammons\r
+// (C) 2004 Underground Software\r
+//\r
+// JLH = James L. Hammons <jlhamm@acm.org>\r
+//\r
+// Who  When        What\r
+// ---  ----------  ------------------------------------------------------------\r
+// JLH  ??/??/200?  Created this file\r
+// JLH  05/18/2004  Added pure point adding, inserting, better polygon handling\r
+//\r
+\r
+// Uncomment this for debugging...\r
+#define DEBUG\r
+\r
+#include "glyphpoints.h"\r
+#ifdef DEBUG\r
+#include "debug.h"\r
+#endif\r
+\r
+/*GlyphPoints::GlyphPoints(void)\r
+{\r
+       GlyphPoints(0, 0, NULL, NULL, NULL, NULL);\r
+}*/\r
+\r
+GlyphPoints::GlyphPoints(int nPts/*=0*/, int nPlys/*=0*/, int * xa/*=null*/, int * ya/*=null*/,\r
+       bool * oca/*=null*/, uint16 * pa/*=null*/): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)\r
+//GlyphPoints::GlyphPoints(int nPts, int nPlys/*=0*/, int * xa/*=null*/, int * ya/*=null*/,\r
+//     bool * oca/*=null*/, uint16 * pa/*=null*/): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)\r
+{\r
+       AllocateAndCopy(nPts, nPlys, xa, ya, oca, pa);\r
+\r
+       if (nPlys == 0)\r
+       {\r
+               numPolys = 1;\r
+               polyEnd = new uint16[numPolys];\r
+               polyEnd[0] = numPoints - 1;\r
+       }\r
+#ifdef DEBUG\r
+WriteLogMsg("GlyphPoints: Default constructor. %u points, %u polys.\n", numPoints, numPolys);\r
+#endif\r
+}\r
+\r
+GlyphPoints::GlyphPoints(int xx, int yy, bool oc)\r
+{\r
+//Hmm. What to do with this...?\r
+       AllocateAndCopy(1, 0, &xx, &yy, &oc, NULL);\r
+#ifdef DEBUG\r
+WriteLogMsg("GlyphPoints: Single point constructor. %u points, %u polys.\n", numPoints, numPolys);\r
+#endif\r
+}\r
+\r
+// Copy constructor (needed for deep copying)\r
+\r
+//GlyphPoints::GlyphPoints(GlyphPoints &c): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)\r
+GlyphPoints::GlyphPoints(const GlyphPoints &c): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)\r
+{\r
+       *this = c;                                                                      // Use overloaded operator=\r
+#ifdef DEBUG\r
+WriteLogMsg("GlyphPoints: Copy constructor. %u points, %u polys.\n", numPoints, numPolys);\r
+#endif\r
+}\r
+\r
+GlyphPoints::~GlyphPoints()\r
+{\r
+       if (x)\r
+               delete[] x;\r
+\r
+       if (y)\r
+               delete[] y;\r
+\r
+       if (onCurve)\r
+               delete[] onCurve;\r
+\r
+       if (polyEnd)\r
+               delete[] polyEnd;\r
+}\r
+\r
+void GlyphPoints::AllocateAndCopy(int nPts, int nPlys, int * xa, int * ya, bool * oca, uint16 * pa)\r
+{\r
+       numPoints = nPts, numPolys = nPlys;\r
+\r
+       if (nPts)\r
+       {\r
+               x = new int[numPoints];\r
+               y = new int[numPoints];\r
+               onCurve = new bool[numPoints];\r
+\r
+               if (xa)                                                                 // Copy points in if they're passed in...\r
+                       for(int i=0; i<nPts; i++)\r
+                               x[i] = xa[i];\r
+\r
+               if (ya)\r
+                       for(int i=0; i<nPts; i++)\r
+                               y[i] = ya[i];\r
+\r
+               if (oca)\r
+                       for(int i=0; i<nPts; i++)\r
+                               onCurve[i] = oca[i];\r
+       }\r
+\r
+       if (numPolys)\r
+       {\r
+               polyEnd = new uint16[numPolys];\r
+\r
+               if (pa)                                                                 // Copy poly ends in if they're passed in...\r
+                       for(int i=0; i<nPlys; i++)\r
+                               polyEnd[i] = pa[i];\r
+       }\r
+}\r
+\r
+GlyphPoints& GlyphPoints::operator=(const GlyphPoints &c)\r
+{\r
+       if (this == &c)\r
+               return *this;                                                   // Take care of self-assignment\r
+\r
+       if (x)\r
+               delete[] x;\r
+\r
+       if (y)\r
+               delete[] y;\r
+\r
+       if (onCurve)\r
+               delete[] onCurve;\r
+\r
+       if (polyEnd)\r
+               delete[] polyEnd;\r
+\r
+       AllocateAndCopy(c.numPoints, c.numPolys, c.x, c.y, c.onCurve, c.polyEnd);\r
+\r
+       return *this;\r
+}\r
+\r
+// Add another GlyphPoints' points to this one...\r
+\r
+GlyphPoints GlyphPoints::operator+(const GlyphPoints &c)\r
+{\r
+       int totPoints = numPoints + c.numPoints, totPolys = numPolys + c.numPolys;\r
+\r
+       int * totX = new int[totPoints];\r
+       int * totY = new int[totPoints];\r
+       bool * totOnCurve = new bool[totPoints];\r
+       uint16 * totPolyEnd = new uint16[totPolys];\r
+\r
+       for(int i=0; i<numPoints; i++)\r
+       {\r
+               totX[i] = x[i];\r
+               totY[i] = y[i];\r
+               totOnCurve[i] = onCurve[i];\r
+       }\r
+\r
+       for(int i=0; i<numPolys; i++)\r
+               totPolyEnd[i] = polyEnd[i];\r
+\r
+       for(int i=0; i<c.numPoints; i++)\r
+       {\r
+               totX[numPoints+i] = c.x[i];\r
+               totY[numPoints+i] = c.y[i];\r
+               totOnCurve[numPoints+i] = c.onCurve[i];\r
+       }\r
+\r
+       for(int i=0; i<c.numPolys; i++)\r
+               totPolyEnd[numPolys+i] = numPoints + c.polyEnd[i];  // Need to adjust the "added in"\r
+                                                        // poly's end points...\r
+\r
+       GlyphPoints retVal(totPoints, totPolys, totX, totY, totOnCurve, totPolyEnd);\r
+       delete[] totX;\r
+       delete[] totY;\r
+       delete[] totOnCurve;\r
+       delete[] totPolyEnd;\r
+\r
+       return retVal;\r
+}\r
+\r
+// Add a point to this GlyphPoints...\r
+\r
+GlyphPoints GlyphPoints::operator+(const IPoint &c)\r
+{\r
+//This is kinda silly. We can do better than this! !!! FIX !!!\r
+       int * totX = new int[numPoints + 1];\r
+       int * totY = new int[numPoints + 1];\r
+       bool * totOnCurve = new bool[numPoints + 1];\r
+       uint16 * totPolyEnd = new uint16[numPolys];\r
+\r
+       for(int i=0; i<numPoints; i++)\r
+               totX[i] = x[i], totY[i] = y[i], totOnCurve[i] = onCurve[i];\r
+\r
+       totX[numPoints] = c.x, totY[numPoints] = c.y, totOnCurve[numPoints] = c.onCurve;\r
+\r
+       for(int i=0; i<numPolys; i++)\r
+               totPolyEnd[i] = polyEnd[i];\r
+\r
+       totPolyEnd[numPolys - 1]++;                                     // Bump polygon's end point\r
+       GlyphPoints retVal(numPoints + 1, numPolys, totX, totY, totOnCurve, totPolyEnd);\r
+\r
+       delete[] totX;\r
+       delete[] totY;\r
+       delete[] totOnCurve;\r
+\r
+       return retVal;\r
+}\r
+\r
+GlyphPoints& GlyphPoints::operator+=(const IPoint &p)\r
+{\r
+       InsertPoint(numPoints, p.x, p.y, p.onCurve);\r
+\r
+       return *this;\r
+}\r
+\r
+void GlyphPoints::InsertPoint(uint16 pt, int xx, int yy, bool oc)\r
+{\r
+       if (pt > numPoints)                                                     // > because we can insert at end...!\r
+               throw GP_OUT_OF_RANGE;\r
+\r
+//This is kinda silly. We can do better than this! !!! FIX !!!\r
+       int * totX = new int[numPoints + 1];\r
+       int * totY = new int[numPoints + 1];\r
+       bool * totOnCurve = new bool[numPoints + 1];\r
+\r
+       for(int i=0; i<pt; i++)\r
+               totX[i] = x[i], totY[i] = y[i], totOnCurve[i] = onCurve[i];\r
+\r
+       for(int i=pt; i<numPoints; i++)\r
+               totX[i + 1] = x[i], totY[i + 1] = y[i], totOnCurve[i + 1] = onCurve[i];\r
+\r
+       totX[pt] = xx, totY[pt] = yy, totOnCurve[pt] = oc;\r
+\r
+//A way to fix the kludge in GetPoly() would be to put a check here to see if \r
+//we're adding to the end of the structure: [DONE, below]\r
+       int polyInsert = (pt == numPoints ? numPolys - 1 : GetPoly(pt));\r
+       for(int i=polyInsert; i<numPolys; i++)\r
+//     for(int i=GetPoly(pt); i<numPolys; i++)\r
+               polyEnd[i]++;                                                   // Bump polygons' end point\r
+\r
+       numPoints++;\r
+\r
+       delete[] x;\r
+       delete[] y;\r
+       delete[] onCurve;\r
+\r
+       x = totX, y = totY, onCurve = totOnCurve;\r
+}\r
+\r
+void GlyphPoints::InsertPoint(uint16 pt, const IPoint &p)\r
+{\r
+       InsertPoint(pt, p.x, p.y, p.onCurve);\r
+}\r
+\r
+//\r
+// Delete a point from the glyph\r
+// Note that we don't bother to reallocate anything here, just bump the\r
+// size counters down as needed. In the future, we'll keep track so we\r
+// don't have to reallocate *every* damn time a point is added...\r
+//\r
+void GlyphPoints::DeletePoint(uint16 pt)\r
+{\r
+       // Adjust polygon ends appropriately\r
+       uint16 poly = GetPoly(pt);\r
+\r
+       for(int i=poly; i<numPolys; i++)\r
+               polyEnd[i]--;\r
+\r
+//Need to check here if we're deleting the last point in the glyph or not.\r
+//!!! FIX !!! [DONE]\r
+       if (GetNumPoints(poly) == 0 && numPoints > 0)\r
+       {\r
+               numPolys--;\r
+\r
+               for(int i=poly; i<numPolys; i++)\r
+                       polyEnd[i] = polyEnd[i + 1];\r
+       }\r
+\r
+//This causes a crash becuz GetPoly() uses numPoints... !!! FIX !!! [DONE by switching poly delete & point delete]\r
+       // Close up the gap left by the current point\r
+       numPoints--;\r
+\r
+       for(int i=pt; i<numPoints; i++)\r
+               x[i] = x[i + 1], y[i] = y[i + 1], onCurve[i] = onCurve[i + 1];\r
+}\r
+\r
+uint16 GlyphPoints::GetNumPoints(void)\r
+{\r
+       return numPoints;\r
+}\r
+\r
+uint16 GlyphPoints::GetNumPoints(uint16 poly)\r
+{\r
+       if (poly >= numPolys)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetNumPoints(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);\r
+#endif\r
+               throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+       return polyEnd[poly] - (poly == 0 ? -1 : polyEnd[poly - 1]);\r
+}\r
+\r
+uint16 GlyphPoints::GetNumPolys(void)\r
+{\r
+       return numPolys;\r
+}\r
+\r
+int GlyphPoints::GetX(uint16 pt)\r
+{\r
+       if (pt >= numPoints)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetX(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);\r
+#endif\r
+               throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+       return x[pt];\r
+}\r
+\r
+int GlyphPoints::GetY(uint16 pt)\r
+{\r
+       if (pt >= numPoints)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetY(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);\r
+#endif\r
+               throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+       return y[pt];\r
+}\r
+\r
+bool GlyphPoints::GetOnCurve(uint16 pt)\r
+{\r
+       if (pt >= numPoints)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetOnCurve(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);\r
+#endif\r
+               throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+       return onCurve[pt];\r
+}\r
+\r
+int GlyphPoints::GetX(uint16 poly, uint16 pt)\r
+{\r
+       if (pt >= GetNumPoints(poly))\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetX(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);\r
+#endif\r
+               throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+       return x[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];\r
+}\r
+\r
+int GlyphPoints::GetY(uint16 poly, uint16 pt)\r
+{\r
+       if (pt >= GetNumPoints(poly))\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetY(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);\r
+#endif\r
+               throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+       return y[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];\r
+}\r
+\r
+bool GlyphPoints::GetOnCurve(uint16 poly, uint16 pt)\r
+{\r
+       if (pt >= GetNumPoints(poly))\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetOnCurve(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);\r
+#endif\r
+               throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+       return onCurve[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];\r
+}\r
+\r
+uint16 GlyphPoints::GetPolyEnd(uint16 poly)\r
+{\r
+       if (poly >= numPolys)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetPolyEnd(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);\r
+#endif\r
+               throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+       return polyEnd[poly];\r
+}\r
+\r
+void GlyphPoints::OffsetPoints(int xOff, int yOff)\r
+{\r
+       for(int i=0; i<numPoints; i++)\r
+               x[i] += xOff, y[i] += yOff;\r
+}\r
+\r
+//\r
+// Offset only a specific polygon in the glyph\r
+//\r
+void GlyphPoints::OffsetPoly(uint16 poly, int32 xOff, int32 yOff)\r
+{\r
+       if (poly >= numPolys)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetPolyEnd(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);\r
+#endif\r
+               throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+       uint16 polyStart = (poly == 0 ? 0 : polyEnd[poly - 1] + 1);\r
+\r
+       for(int i=0; i<GetNumPoints(poly); i++)\r
+               x[polyStart + i] += xOff, y[polyStart + i] += yOff;\r
+}\r
+\r
+void GlyphPoints::ScalePoints(float sc)\r
+{\r
+       for(int i=0; i<numPoints; i++)\r
+               x[i] = (int)(((float)x[i] * sc) + 0.5f),\r
+               y[i] = (int)(((float)y[i] * sc) + 0.5f);\r
+}\r
+\r
+void GlyphPoints::SetXY(uint16 pt, int xx, int yy)\r
+{\r
+       if (pt >= numPoints)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: SetXY(uint16, int, int). pt=%u, numPoints=%u\xD\xA", pt, numPoints);\r
+#endif\r
+               throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+       x[pt] = xx, y[pt] = yy;\r
+}\r
+\r
+void GlyphPoints::SetOnCurve(uint16 pt, bool oc)\r
+{\r
+       if (pt >= numPoints)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: SetOnCurve(uint16, bool). pt=%u, numPoints=%u\xD\xA", pt, numPoints);\r
+#endif\r
+               throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+       onCurve[pt] = oc;\r
+}\r
+\r
+uint16 GlyphPoints::GetPrev(uint16 pt)\r
+{\r
+// pt = 7, polyEnd = 4, 9, 15\r
+       uint16 min = 0, max = numPoints - 1;\r
+\r
+       for(int i=0; i<numPolys; i++)\r
+       {\r
+               if (pt <= polyEnd[i])\r
+               {\r
+                       if (i > 0)\r
+                               min = polyEnd[i - 1] + 1;\r
+\r
+                       max = polyEnd[i];\r
+                       break;\r
+               }\r
+       }\r
+\r
+       uint16 retVal = pt - 1;\r
+\r
+       if (pt == min)\r
+               retVal = max;\r
+\r
+       return retVal;\r
+}\r
+\r
+uint16 GlyphPoints::GetNext(uint16 pt)\r
+{\r
+       uint16 min = 0, max = numPoints - 1;\r
+\r
+       for(int i=0; i<numPolys; i++)\r
+       {\r
+               if (pt <= polyEnd[i])\r
+               {\r
+                       if (i > 0)\r
+                               min = polyEnd[i - 1] + 1;\r
+\r
+                       max = polyEnd[i];\r
+                       break;\r
+               }\r
+       }\r
+\r
+       uint16 retVal = pt + 1;\r
+\r
+       if (pt == max)\r
+               retVal = min;\r
+\r
+       return retVal;\r
+}\r
+\r
+//\r
+// Get previous point for this polygon using wraparound.\r
+// Note that pt is a zero-based index!\r
+//\r
+uint16 GlyphPoints::GetPrev(uint16 poly, uint16 pt)\r
+{\r
+       return (pt == 0 ? GetNumPoints(poly) - 1 : pt - 1);\r
+}\r
+\r
+//\r
+// Get next point for this polygon using wraparound.\r
+// Note that pt is a zero-based index!\r
+//\r
+uint16 GlyphPoints::GetNext(uint16 poly, uint16 pt)\r
+{\r
+       return (pt == GetNumPoints(poly) - 1 ? 0 : pt + 1);\r
+}\r
+\r
+uint16 GlyphPoints::GetPoly(uint16 pt)\r
+{\r
+       if (pt >= numPoints)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetPoly(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);\r
+#endif\r
+               throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+       for(int i=0; i<numPolys; i++)\r
+               if (pt <= polyEnd[i])\r
+                       return i;\r
+\r
+       return (uint16)-1;\r
+}\r
+\r
+void GlyphPoints::AddNewPolyAtEnd(void)\r
+{\r
+       if (numPoints == 0)                                                     // By default, we already *have* a poly\r
+               return;\r
+\r
+       uint16 * newPolyEnd = new uint16[numPolys + 1];\r
+\r
+       for(uint16 i=0; i<numPolys; i++)\r
+               newPolyEnd[i] = polyEnd[i];\r
+\r
+       newPolyEnd[numPolys] = newPolyEnd[numPolys - 1];\r
+       numPolys++;\r
+       delete[] polyEnd;\r
+       polyEnd = newPolyEnd;\r
+}\r
+\r
diff --git a/src/glyphpoints.h b/src/glyphpoints.h
new file mode 100755 (executable)
index 0000000..2348d1e
--- /dev/null
@@ -0,0 +1,85 @@
+//\r
+// glyphpoints.h\r
+//\r
+// by James L. Hammons\r
+//\r
+// This class encapsulates the data associated with a TrueType glyph.\r
+// Data is dynamically allocated.\r
+//\r
+\r
+#ifndef __GLYPHPOINTS_H__\r
+#define __GLYPHPOINTS_H__\r
+\r
+#include "types.h"\r
+\r
+\r
+struct IPoint\r
+{\r
+       int32 x, y;\r
+       bool onCurve;\r
+\r
+       IPoint(int32 xx=0, int32 yy=0, bool oc=true): x(xx), y(yy), onCurve(oc) {}\r
+};\r
+\r
+// Throws the following exceptions:\r
+#define GP_OUT_OF_RANGE  1\r
+\r
+class GlyphPoints\r
+{\r
+       public:\r
+//For some reason, gcc barfs here when something tries to use the copy\r
+//constructor because it gets confused between the optional arguments (which\r
+//start with an INT for cryin' out loud) and the GlyphPoints & argument. So,\r
+//Let's try making it a non-optional first param, and go from there...\r
+//Turns out the compiler barfs regardless...\r
+//Turns out the problem was that the copy ctor wasn't declared as CONST...\r
+               GlyphPoints(int nPts = 0, int nPlys = 0, int * xa = NULL, int * ya = NULL,\r
+                       bool * oca = NULL, uint16 * pa = NULL);\r
+//             GlyphPoints(void);// And now *this* is needed... Bleah!\r
+//             GlyphPoints(int nPts, int nPlys = 0, int * xa = NULL, int * ya = NULL,\r
+//                     bool * oca = NULL, uint16 * pa = NULL);\r
+               GlyphPoints(int xx, int yy, bool oc);\r
+//             GlyphPoints(GlyphPoints &);                             // Copy constructor\r
+               GlyphPoints(const GlyphPoints &);                               // Copy constructor\r
+               ~GlyphPoints();\r
+               GlyphPoints& operator=(const GlyphPoints &);\r
+               GlyphPoints operator+(const GlyphPoints &);\r
+               GlyphPoints operator+(const IPoint &);\r
+               GlyphPoints& operator+=(const IPoint &);\r
+               void InsertPoint(uint16, int, int, bool);\r
+               void InsertPoint(uint16, const IPoint &);\r
+               void DeletePoint(uint16);\r
+               uint16 GetNumPoints(void);\r
+               uint16 GetNumPoints(uint16);\r
+               uint16 GetNumPolys(void);\r
+               int GetX(uint16);\r
+               int GetY(uint16);\r
+               bool GetOnCurve(uint16);\r
+               int GetX(uint16, uint16);\r
+               int GetY(uint16, uint16);\r
+               bool GetOnCurve(uint16, uint16);\r
+               uint16 GetPolyEnd(uint16);\r
+               void OffsetPoints(int, int);\r
+               void OffsetPoly(uint16, int32, int32);\r
+               void ScalePoints(float);\r
+               void SetXY(uint16, int, int);\r
+               void SetOnCurve(uint16, bool);\r
+               uint16 GetPrev(uint16);\r
+               uint16 GetNext(uint16);\r
+               uint16 GetPrev(uint16, uint16);\r
+               uint16 GetNext(uint16, uint16);\r
+               uint16 GetPoly(uint16);\r
+               void AddNewPolyAtEnd(void);\r
+\r
+       private:\r
+               void AllocateAndCopy(int, int, int *, int *, bool *, uint16 *);\r
+\r
+       private:\r
+               int numPoints, numPolys;\r
+               int * x, * y;\r
+               bool * onCurve;\r
+               uint16 * polyEnd;\r
+               uint16 pointsAllocated, polysAllocated;\r
+};\r
+\r
+#endif // __GLYPHPOINTS_H__\r
diff --git a/src/list.h b/src/list.h
new file mode 100755 (executable)
index 0000000..4e516c1
--- /dev/null
@@ -0,0 +1,281 @@
+//\r
+// A generic list class using a circular singly linked list\r
+// by James L. Hammons\r
+// (C) 2004 Underground Software\r
+//\r
+// Based upon work I did for CS240 Project 5 at Cal Poly Pomona for Dr. Bruce Hillam.\r
+// Hello Dr. Hillam! :-)\r
+//\r
+// JLH = James L. Hammons <jlhamm@acm.org>\r
+//\r
+// Who  When        What\r
+// ---  ----------  -------------------------------------------------------------\r
+// JLH  08/30/1999  Created this file\r
+// JLH  05/11/2004  Cleaned up a few things in the implementation\r
+//\r
+\r
+\r
+// Some exception constants\r
+\r
+#define LIST_EMPTY             1\r
+#define OUT_OF_RANGE   2\r
+\r
+template <class T> class List;                                 // Forward declaration...\r
+template <class T> class Node\r
+{\r
+       friend class List<T>;\r
+\r
+       public:\r
+//             Node(void)                         { next = NULL; }\r
+               Node(void): next(NULL) {}\r
+//             Node(const T d, Node * ptr = NULL) { data = d;  next = ptr; }\r
+               Node(const T d, Node * ptr = NULL): data(d), next(ptr) {}\r
+\r
+       private:\r
+               T data;\r
+               Node * next;\r
+};\r
+\r
+template <class T> class List      \r
+{\r
+       // This class implements the following exceptions:\r
+       // LIST_EMPTY is thrown if you attempt to remove an object from an empty list.\r
+       // OUT_OF_RANGE is thrown if you attempt to Add or Get from a position that\r
+       // does not exist for the list.\r
+\r
+       private:\r
+               Node<T> * last;\r
+               int length;\r
+\r
+       public:\r
+               List(void);\r
+               ~List();\r
+               bool operator==(List &l);\r
+               void AddAtFront(T data);\r
+               void AddAtRear(T data);\r
+               void AddAtPosition(int pos, T data);\r
+               T GetFront(void);\r
+               T GetRear(void);\r
+               T GetPosition(int pos);\r
+               T PeekFront(void);\r
+               T PeekRear(void);\r
+               T PeekPosition(int pos);\r
+               bool IsEmpty(void);\r
+               int Length(void);\r
+};\r
+\r
+//\r
+// List class implementation\r
+//\r
+template <class T> List<T>::List(void)\r
+{\r
+       last = NULL;\r
+       length = 0;\r
+}\r
+\r
+template <class T> List<T>::~List()\r
+{\r
+       while (length)                                                          // Destroy all nodes that were created...\r
+       {\r
+               Node<T> * tmp = last;\r
+               last = last->next;\r
+               delete tmp;\r
+               length--;\r
+       }\r
+}\r
+\r
+template <class T> bool List<T>::operator==(List &l)\r
+{\r
+       if (Length() != l.Length())\r
+               return false;\r
+\r
+       Node<T> * ptr1 = last->next, * ptr2 = l.last->next;\r
+\r
+       do\r
+       {\r
+               if (ptr1->data != ptr2->data)\r
+                       return false;\r
+\r
+               ptr1 = ptr1->next, ptr2 = ptr2->next;\r
+       }\r
+       while (ptr1 != last);\r
+\r
+       return true;\r
+}\r
+\r
+template <class T> void List<T>::AddAtFront(T data)\r
+{\r
+       Node<T> * newNode = new Node<T>(data);\r
+\r
+       if (last == NULL)                                                       // i.e., the list is empty...\r
+               last = newNode->next = newNode;\r
+       else\r
+       {\r
+               newNode->next = last->next;\r
+               last->next = newNode;\r
+       }\r
+\r
+       length++;\r
+}\r
+\r
+template <class T> void List<T>::AddAtRear(T data)\r
+{\r
+       Node<T> * newNode = new Node<T>(data);\r
+\r
+       if (last == NULL)                                                       // i.e., the list is empty...\r
+               last = newNode->next = newNode;\r
+       else\r
+       {\r
+               newNode->next = last->next;\r
+               last->next = newNode;\r
+               last = newNode;\r
+       }\r
+\r
+       length++;\r
+}\r
+\r
+template <class T> void List<T>::AddAtPosition(int pos, T data)\r
+{\r
+       if ((pos < 1) || (pos > length))\r
+               throw OUT_OF_RANGE;\r
+\r
+       if (pos == 1)\r
+               AddAtFront(data);                                               // Why reinvent the wheel?\r
+\r
+       if (pos == length)\r
+               AddAtRear(data);\r
+\r
+       Node<T> * newNode = new Node<T>(data), * tmp = last;\r
+\r
+       for(int i=1; i!=pos; i++)                                       // Make tmp point to node ahead of add position\r
+               tmp = tmp->next;\r
+\r
+       newNode->next = tmp->next;\r
+       tmp->next = newNode;\r
+\r
+       length++;\r
+}\r
+\r
+template <class T> T List<T>::GetFront(void)\r
+{\r
+       if (IsEmpty())\r
+               throw LIST_EMPTY;\r
+\r
+       T retVal = last->next->data;\r
+       Node<T> * ptr = last->next;\r
+\r
+       if (length == 1)\r
+               last = NULL;\r
+       else\r
+               last->next = last->next->next;\r
+\r
+       delete ptr;\r
+       length--;\r
+\r
+       return retVal;\r
+}\r
+\r
+template <class T> T List<T>::GetRear(void)\r
+{\r
+       if (IsEmpty())\r
+               throw LIST_EMPTY;\r
+\r
+       T retVal = last->data;\r
+       Node<T> * ptr = last;\r
+\r
+       if (length == 1)\r
+       {\r
+               delete last;\r
+               last = NULL;\r
+       }\r
+       else\r
+       {\r
+               while (ptr->next != last)\r
+                       ptr = ptr->next;\r
+\r
+               ptr->next = ptr->next->next;\r
+               delete last;\r
+               last = ptr;  \r
+       }\r
+\r
+       length--;\r
+\r
+       return retVal;\r
+}\r
+\r
+template <class T> T List<T>::GetPosition(int pos)\r
+{\r
+       if (IsEmpty())\r
+               throw LIST_EMPTY;\r
+\r
+       if ((pos < 1) || (pos > length))\r
+               throw OUT_OF_RANGE;\r
+\r
+       if (pos == 1)\r
+               return GetFront();                                              // Why reinvent the wheel?\r
+\r
+       if (pos == length)\r
+               return GetRear();\r
+\r
+       Node<T> * tmp = last;\r
+\r
+       for(int i=1; i!=pos; i++)                                       // Make tmp point to node ahead of del position\r
+               tmp = tmp->next;\r
+\r
+       Node<T> * nodeToDelete = tmp->next;\r
+               T retVal = nodeToDelete->data;\r
+\r
+       tmp->next = tmp->next->next;\r
+       delete nodeToDelete;\r
+\r
+       length--;\r
+       return retVal;\r
+}\r
+\r
+template <class T> T List<T>::PeekFront(void)\r
+{\r
+       if (IsEmpty())\r
+               throw LIST_EMPTY;\r
+\r
+       return last->next->data;\r
+}\r
+\r
+template <class T> T List<T>::PeekRear(void)\r
+{\r
+       if (IsEmpty())\r
+               throw LIST_EMPTY;\r
+\r
+       return last->data;\r
+}\r
+\r
+template <class T> T List<T>::PeekPosition(int pos)\r
+{\r
+       if (IsEmpty())\r
+               throw LIST_EMPTY;\r
+\r
+       if ((pos < 1) || (pos > length))\r
+               throw OUT_OF_RANGE;\r
+\r
+       if (pos == 1)\r
+               return PeekFront();                                             // Why reinvent the wheel?\r
+\r
+       if (pos == length)\r
+               return PeekRear();\r
+\r
+       Node<T> * tmp = last;\r
+\r
+       for(int i=1; i!=pos; i++)\r
+               tmp = tmp->next;\r
+\r
+       return tmp->next->data;\r
+}\r
+\r
+template <class T> inline bool List<T>::IsEmpty(void)\r
+{\r
+       return (bool)(length == 0);\r
+}\r
+\r
+template <class T> inline int List<T>::Length(void)\r
+{\r
+       return length;\r
+}\r
diff --git a/src/registry.cpp b/src/registry.cpp
new file mode 100755 (executable)
index 0000000..cbf3862
--- /dev/null
@@ -0,0 +1,94 @@
+//\r
+// REGISTRY.CPP - Win32 support file\r
+// by James L. Hammons\r
+// (C) 2002 Underground Software\r
+//\r
+//   JLH = James Hammons <jlhamm@acm.org>\r
+//\r
+// Who  When        What\r
+// ---  ----------  ------------------------------------------------------------\r
+// JLH  05/16/2002  Created this file\r
+// JLH  12/10/2002  Updated InitINIFile to take a parameter so that you can open\r
+//                  an .INI file that doesn't belong to the current module\r
+//\r
+// STILL TO BE DONE:\r
+//\r
+// - Convert to wxWidgets...\r
+//\r
+\r
+#warning This file not yet converted to wxWidgets!!!\r
+\r
+#if 0\r
+#include <windows.h>\r
+#include "registry.h"\r
+\r
+// Local data\r
+\r
+static char INIPath[MAX_PATH];\r
+static char str[4096];\r
+\r
+//\r
+// Initialize the application .INI file\r
+// Returns TRUE if succesful, FALSE otherwise...\r
+//\r
+void InitINIFile(char * path/*= NULL*/)\r
+{\r
+       if (!GetModuleFileName(NULL, INIPath, MAX_PATH))\r
+               return;\r
+\r
+       if (path == NULL)\r
+       {\r
+               int len = lstrlen(INIPath);\r
+               lstrcpy(INIPath + len - 4, ".ini");\r
+       }\r
+       else\r
+       {\r
+               for(int i=lstrlen(INIPath); i>=0; i--)\r
+               {\r
+                       if (INIPath[i] == '\\')\r
+                       {\r
+                               lstrcpy(INIPath + i + 1, path);\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+//\r
+// Write an int value to our .INI file\r
+//\r
+void SetINIInt(char * section, char * entry, int32 value)\r
+{\r
+       const char fmtStr[] = "%d";\r
+       char strVal[20];\r
+\r
+       wsprintf(strVal, fmtStr, value);\r
+       WritePrivateProfileString(section, entry, strVal, INIPath);\r
+}\r
+\r
+//\r
+// Write a string value to our .INI file\r
+//\r
+void SetINIString(char * section, char * entry, char * value)\r
+{\r
+       WritePrivateProfileString(section, entry, value, INIPath);\r
+}\r
+\r
+//\r
+// Get an int value from our .INI file\r
+//\r
+int32 GetINIInt(char * section, char * entry, int32 _default)\r
+{\r
+       return GetPrivateProfileInt(section, entry, _default, INIPath);\r
+}\r
+\r
+//\r
+// Get a string value from our .INI file\r
+//\r
+const char * GetINIString(char * section, char * entry, char * _default)\r
+{\r
+       GetPrivateProfileString(section, entry, _default, str, 4096, INIPath);\r
+\r
+       return str;\r
+}\r
+#endif\r
diff --git a/src/registry.h b/src/registry.h
new file mode 100755 (executable)
index 0000000..7384341
--- /dev/null
@@ -0,0 +1,22 @@
+//\r
+// REGISTRY.H - Win32 support file header\r
+// by James L. Hammons\r
+// (C) 2002 Underground Software\r
+//\r
+//   JLH = James Hammons <jlhamm@acm.org>\r
+//\r
+\r
+#ifndef __REGISTRY_H__\r
+#define __REGISTRY_H__\r
+\r
+#include "types.h"\r
+\r
+// Function prototypes\r
+\r
+void InitINIFile(char * path = NULL);\r
+void SetINIInt(char *, char *, int32);\r
+void SetINIString(char *, char *, char *);\r
+int32 GetINIInt(char *, char *, int32);\r
+const char * GetINIString(char *, char *, char *);\r
+\r
+#endif // __REGISTRY_H__\r
diff --git a/src/tte_res.h b/src/tte_res.h
new file mode 100755 (executable)
index 0000000..3bf6dba
--- /dev/null
@@ -0,0 +1,46 @@
+//\r
+// Resource includes\r
+//\r
+// by James L. Hammons\r
+//\r
+\r
+// Uncomment this to debug logging...\r
+//Actually, this is done on a file by file basis and NOT here...\r
+//#define DEBUG\r
+\r
+//\r
+// Common equates also used in the resource file\r
+//\r
+\r
+#define        IDI_ICON                        0x01L           // IDs same as in ttedit.asm\r
+#define        IDM_MENU                        0x02L\r
+#define        IDA_ACCEL                       0x03L\r
+#define        IDD_ABOUT                       0x04L\r
+#define IDR_TOOLBAR1           0x05L\r
+#define IDB_TOOLBAR1           0x06L\r
+#define IDB_TOOLPAL1           0x07L\r
+#define IDC_CURSOR1                    0x08L\r
+#define IDC_CURSOR2                    0x09L\r
+#define IDC_CURSOR3                    0x0AL\r
+#define IDC_CURSOR4                    0x0BL\r
+#define IDC_CURSOR5                    0x0CL\r
+#define IDC_CURSOR6                    0x0DL\r
+#define IDC_CURSOR7                    0x0EL\r
+#define IDC_CURSOR8                    0x0FL\r
+\r
+#define        IDS_SYSMENU                     0x010L\r
+#define        IDM_FILEMENU            0x011L\r
+#define        IDM_HELPMENU            0x012L\r
+\r
+#define        IDM_NEW                         0x020L\r
+#define        IDM_OPEN                        0x021L\r
+#define        IDM_SAVE                        0x022L\r
+#define        IDM_SAVEAS                      0x023L\r
+#define        IDM_EXIT                        0x024L\r
+#define        IDM_HELPTOPICS          0x025L\r
+#define        IDM_ABOUT                       0x026L\r
+\r
+#define        ID_TBLEFT                       0x030L\r
+#define        ID_TBRIGHT                      0x031L\r
+#define        ID_TBCHARWIN            0x032L\r
+\r
diff --git a/src/ttedit.cpp b/src/ttedit.cpp
new file mode 100755 (executable)
index 0000000..cb19ce2
--- /dev/null
@@ -0,0 +1,2061 @@
+//\r
+// TTEDIT.CPP - The TrueType Editor\r
+// by James L. Hammons\r
+// (C) 2004 Underground Software\r
+//\r
+// JLH = James L. Hammons <jlhamm@acm.org>\r
+//\r
+// Who  When        What\r
+// ---  ----------  -------------------------------------------------------------\r
+// JLH  04/10/2002  Created this file\r
+// JLH  05/10/2004  Translated file from ASM to CPP\r
+// JLH  05/14/2004  Added rudimentary editing capability to tool palette tools\r
+// JLH  11/18/2006  Initial port to Linux\r
+//\r
+\r
+// STILL TO BE DONE:\r
+//\r
+// - Fix bug in Glyphpoints when dragging on an empty canvas or loading a font\r
+// - Fix scrolling, zooming, settings (ini)\r
+// - Finish conversion to wxWidgets for cross-platform portability\r
+// - Fix problem with owned window causing main window refresh problems\r
+//   (ironically enough, it doesn't seem to be a problem anymore...)\r
+//\r
+\r
+// Uncomment this for debugging...\r
+#define DEBUG\r
+#define DEBUGFOO            // Various tool debugging...\r
+\r
+#include <math.h>\r
+#include "types.h"\r
+#include "tte_res.h"\r
+#include "ttf.h"\r
+#include "registry.h"\r
+#include "bezier.h"\r
+#include "glyphpoints.h"\r
+#include "vector.h"\r
+#ifdef DEBUG\r
+#include "debug.h"\r
+#endif\r
+#include "ttedit.h"                                                            // Usually not necessary, but here we are...\r
+#include <wx/confbase.h>\r
+#include <wx/fileconf.h>\r
+#include <wx/image.h>\r
+\r
+#include "res/ttedit.xpm"                                              // *nix only, but small enough to not matter\r
+#include "res/toolpal1.xpm"                                            // Docs say this is portable... Let's see!\r
+#include "res/cur1.xpm"\r
+#include "res/cur2.xpm"\r
+#include "res/cur3.xpm"\r
+#include "res/cur4.xpm"\r
+#include "res/cur5.xpm"\r
+#include "res/cur6.xpm"\r
+#include "res/cur7.xpm"\r
+#include "res/cur8.xpm"\r
+#include "res/tool1.xpm"\r
+#include "res/tool2.xpm"\r
+#include "res/tool3.xpm"\r
+\r
+//\r
+// E Q U A T E S\r
+//\r
+#define TOOLSelect                     0x00                            // The "selection" tool\r
+#define TOOLPolySelect         0x01                            // Polygon selection tool\r
+#define TOOLScroll                     0x02                            // Scroll window tool\r
+#define TOOLZoom                       0x03                            // Zoom window tool\r
+#define TOOLAddPt                      0x04                            // Add point tool\r
+#define TOOLAddPoly                    0x05                            // Polygon creation tool\r
+#define TOOLDelPt                      0x06                            // Delete point tool\r
+#define TOOLDelPoly                    0x07                            // Delete polygon tool\r
+\r
+//\r
+// Function and Procedure Prototypes\r
+//\r
+//BOOL CALLBACK AboutProc(HWND, UINT, WPARAM, LPARAM);\r
+//void MiscCenterWnd(HWND, HWND);\r
+//bool OnlyOneInstance(void);\r
+void CreateResources(void);\r
+bool Initialization(void);\r
+void DeallocateResources(void);\r
+void SaveAppState(void);\r
+void DrawRoundDot(wxDC &, int32, int32);\r
+void DrawSquareDot(wxDC &, int32, int32);\r
+void DrawRoundDotN(wxDC &, int32, int32, uint32);\r
+void DrawSquareDotN(wxDC &, int32, int32, uint32);\r
+void CreateNewDoc(void);\r
+bool SaveChanges(void);\r
+\r
+// Global constant data\r
+\r
+//const char className[] = "TTEDIT";\r
+//const char CNCharWin[] = "US_CHARWIN";\r
+//const char CNToolPal[] = "US_TOOLPALETTE";\r
+//const char CNStatus[] = "msctls_statusbar32";\r
+const char filter[] = "Font Files (*.TTF)\0*.TTF\0All Files (*.*)\0*.*\0";\r
+const char defExt[] = "ttf";\r
+//const char mtitle[] = "Character Window!";\r
+const char zoom[] = "Zoom: %u%%";\r
+\r
+/*const TBBUTTON tbButtons[4] = {\r
+       { 0, ID_TBLEFT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0 },\r
+       { 1, ID_TBRIGHT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0 },\r
+       { 0, 0, 0, TBSTYLE_SEP, 0, 0 },\r
+       { 2, ID_TBCHARWIN, TBSTATE_ENABLED | TBSTATE_CHECKED, TBSTYLE_CHECK, 0, 0 }\r
+};*/\r
+\r
+\r
+//\r
+// U N I N I T I A L I Z E D    D A T A\r
+//\r
+/*\r
+szSaveChanges  SBYTE   "Save changes to the following file?", 0Ah, 0Ah\r
+szFile         SBYTE   MAX_PATH DUP (0)\r
+szWindowName   SBYTE   (MAX_PATH + 10h) DUP (0)\r
+fScaleFactor   REAL4   1.0                     // Window scaling factor\r
+\r
+*/\r
+\r
+//HINSTANCE hInst;\r
+int nCmdShow;\r
+//HWND hMainWnd, hStatusBar, hToolBar, hCharWnd, hToolPalWnd;\r
+char statusBarTxt[64];\r
+char toolTipTxt[16];\r
+char strBuf[1024];\r
+\r
+//HCURSOR hCur[8];\r
+wxCursor * cur[8];\r
+\r
+//HBITMAP hBMToolPal1;\r
+//HPEN hRedPen1, hBluePen1, hGreenPen1, hBlackPen1;\r
+//HBRUSH hNullBrush;\r
+\r
+//POINT sizeStamp, sizeTPBM, ptPrevious;\r
+//PTSTRUCT aPts[16];\r
+//uint32 numPts = 0;\r
+GlyphPoints pts;\r
+int32 ptHighlight = -1, oldPtHighlight = -1, ptNextHighlight = -1, oldPtNextHighlight = -1;\r
+int32 currentTool = TOOLSelect;                                        // Current tool is "selection" tool\r
+bool mouseDown = false;                                                        // Mouse down flag\r
+bool NCMouseDown;\r
+//POINT ptWinOffset;\r
+uint32 zoomWndWidth;\r
+bool polyFirstPoint = true;\r
+\r
+char curCharName[] = "Own3d W1nd0w";                   // Need to make this a buffer w/default\r
+\r
+//WINDOWPLACEMENT wpM, wpC;\r
+//POINT ptVPM;\r
+\r
+\r
+\r
+IMPLEMENT_APP(TTEditApp)                                               // Run the main application loop\r
+\r
+bool TTEditApp::OnInit()\r
+{\r
+       wxLog * logTarget = new wxLogStderr();//fopen("!ttedit_log.txt", "wb"));\r
+       wxLog::SetActiveTarget(logTarget);\r
+#ifdef DEBUG\r
+       OpenDebugLog();\r
+#endif\r
+\r
+       // Initialize all the top-level window members to NULL.\r
+       mainFrame = NULL;\r
+       charWin = NULL;\r
+       toolPalette = NULL;\r
+\r
+       CreateResources();\r
+\r
+       mainFrame = new TTEditFrame(NULL, _("TTEdit"), wxPoint(155, 165), wxSize(300, 300),\r
+               wxDEFAULT_FRAME_STYLE | wxFULL_REPAINT_ON_RESIZE);\r
+//             wxMINIMIZE_BOX | wxRESIZE_BOX | wxMAXIMIZE_BOX | | wxSYSTEM_MENU | wxCAPTION);\r
+\r
+       charWin = new CharWindow(NULL);//, _T("Own3d W1nd0w"), wxDefaultPosition, wxDefaultSize);\r
+       toolPalette = new ToolWindow(mainFrame, _(""), wxDefaultPosition, wxDefaultSize,\r
+               wxNO_BORDER | wxFRAME_NO_TASKBAR);\r
+\r
+       return true;\r
+}\r
+\r
+int TTEditApp::OnExit()\r
+{\r
+#ifdef DEBUG\r
+       CloseDebugLog();\r
+#endif\r
+\r
+       return 0;\r
+}\r
+\r
+BEGIN_EVENT_TABLE(TTEditFrame, wxFrame)\r
+       EVT_MENU(IDM_OPEN, TTEditFrame::OnOpen)\r
+       EVT_MENU(IDM_EXIT, TTEditFrame::OnExit)\r
+       EVT_MENU(IDM_ABOUT, TTEditFrame::OnAbout)\r
+       EVT_CLOSE(TTEditFrame::OnCloseWindow)\r
+END_EVENT_TABLE()\r
+\r
+TTEditFrame::TTEditFrame(wxFrame * parent, const wxString &title, const wxPoint &pos,\r
+       const wxSize &size, long style): wxFrame(parent, -1, title, pos, size, style), app(wxGetApp())\r
+{\r
+       // Initialize child subwindow members (and hopefully avoid subtle bugs)\r
+       mainWindow = NULL;\r
+\r
+       SetIcon(wxICON(ttedit));\r
+//     CreateStatusBar(2);                                                     // Create 2 panes\r
+       int widths[2] = { -1, 100 };\r
+       wxStatusBar * sb = CreateStatusBar(2, 0);       // Create 2 panes\r
+       sb->SetStatusWidths(2, widths);\r
+       wxToolBar * tb = CreateToolBar();\r
+\r
+       if (tb != NULL)\r
+       {\r
+               // Create buttons\r
+\r
+               wxBitmap tool1(tool1_xpm);\r
+               wxBitmap tool2(tool2_xpm);\r
+               wxBitmap tool3(tool3_xpm);\r
+\r
+               tb->AddTool(ID_TBLEFT, _("Prev char"), tool1, _("Go to prev char"), wxITEM_NORMAL);\r
+               tb->AddTool(ID_TBRIGHT, _("Next char"), tool2, _("Go to next char"), wxITEM_NORMAL);\r
+               tb->AddTool(ID_TBCHARWIN, _("Char Wnd"), tool3, _("Toggle char window"), wxITEM_NORMAL);\r
+               tb->Realize();\r
+       }\r
+\r
+       // Create a menu bar for the frame\r
+       menuBar = new wxMenuBar;\r
+       wxMenu * menu1 = new wxMenu;\r
+       menu1->Append(IDM_NEW, _("&New\tCtrl+N"), _("Create a new font."));\r
+       menu1->Append(IDM_OPEN, _("&Open...\tCtrl+O"), _("Opens an existing font."));\r
+       menu1->Append(IDM_SAVE, _("&Save\tCtrl+S"), _("Save the current font."));\r
+       menu1->Append(IDM_SAVEAS, _("Save &As..."), _("Save the current font under a different name."));\r
+       menu1->AppendSeparator();\r
+       menu1->Append(IDM_EXIT, _("E&xit\tAlt+X"), _("Quits the TTEdit program."));\r
+       menuBar->Append(menu1, _("&File"));\r
+       wxMenu * menu2 = new wxMenu;\r
+       menu2->Append(IDM_HELPTOPICS, _("&Help Topics"), _("Displays the Help contents and index."));\r
+       menu2->AppendSeparator();\r
+       menu2->Append(IDM_ABOUT, _("&About TTEdit"), _("Displays information about TTEdit."));\r
+       menuBar->Append(menu2, _("&Help"));\r
+       SetMenuBar(menuBar);\r
+\r
+       // Create child subwindows\r
+       mainWindow = new TTEditWindow(this);\r
+\r
+       Centre(wxBOTH);                                                         // Centre frame on the screen\r
+       Show(true);                                                                     // Show the frame\r
+}\r
+\r
+TTEditFrame::~TTEditFrame()\r
+{\r
+}\r
+\r
+void TTEditFrame::OnOpen(wxCommandEvent &e)\r
+{\r
+       wxFileDialog fd(this, _("Choose a font to load"), _(""), _(""), _("TTF files (*.ttf)|*.ttf|All files (*.*)|*.*"), wxOPEN);\r
+\r
+       if (fd.ShowModal() != wxID_OK)\r
+           return;\r
+\r
+// Hmm. The font object is causing a massive crash... (gdb says it's in "Load")\r
+       if (app.font.Load((char *)fd.GetPath().c_str()) != true)\r
+       {\r
+               wxMessageDialog dlg(NULL, _("Load font failed!"), _("Houston, we have a problem..."), wxOK | wxICON_ERROR);\r
+               dlg.ShowModal();\r
+       }\r
+\r
+//Huzzah! It works! Now just need scaling, scrolling, etc...\r
+//     pts = app.font.GetGlyphPoints(45);\r
+}\r
+\r
+void TTEditFrame::OnAbout(wxCommandEvent &e)\r
+{\r
+       wxMessageDialog dlg(NULL, _("TrueType Edit v1.0.0\n\nA handy tool for editing TrueType fonts!\nby James \"Shamus\" Hammons\n(C) 2006 Underground Software"), _("About TrueType Edit"), wxOK | wxICON_INFORMATION);\r
+       dlg.ShowModal();\r
+}\r
+\r
+void TTEditFrame::OnExit(wxCommandEvent &e)\r
+{\r
+       wxGetApp().toolPalette->Destroy();\r
+       this->Destroy();\r
+}\r
+\r
+void TTEditFrame::OnCloseWindow(wxCloseEvent &e)\r
+{\r
+       wxGetApp().toolPalette->Destroy();\r
+       this->Destroy();\r
+}\r
+\r
+BEGIN_EVENT_TABLE(TTEditWindow, wxWindow)\r
+       EVT_PAINT(TTEditWindow::OnPaint)\r
+       EVT_MOUSE_EVENTS(TTEditWindow::OnMouseEvent)\r
+END_EVENT_TABLE()\r
+\r
+TTEditWindow::TTEditWindow(wxFrame * parent, const wxPoint &pos, const wxSize &size, long style):\r
+       wxWindow(parent, -1, pos, size, style), app(wxGetApp())\r
+{ \r
+       bmp = NULL;\r
+       scale = 1.0;\r
+       offsetX = offsetY = -10;\r
+\r
+       SetCursor(*cur[currentTool]);\r
+       SetBackgroundColour(wxColour(0xFF, 0xFF, 0xFF));\r
+\r
+       wxString s;\r
+       s.Printf(_("Zoom: %.2f%%"), scale * 100.0);\r
+       parent->SetStatusText(s, 1);\r
+}\r
+\r
+TTEditWindow::~TTEditWindow(void)\r
+{\r
+       if (bmp)\r
+               delete bmp;\r
+}\r
+\r
+void TTEditWindow::OnPaint(wxPaintEvent &e)\r
+{\r
+/*     wxPaintDC dc(this);\r
+\r
+       // Insert your drawing code here.\r
+       if (!bmp)\r
+       {\r
+               bmp = new wxBitmap(field_width * x_cell * X_UNIT + 1, field_height * y_cell * Y_UNIT + 1);\r
+\r
+               if (bmp)\r
+               {\r
+                       wxMemoryDC memDC;\r
+                       memDC.SelectObject(*bmp);\r
+                       DrawField(&memDC, 0, 0, field_width - 1, field_height - 1);\r
+                       memDC.SelectObject(wxNullBitmap);\r
+               }\r
+       }\r
+\r
+       if (bmp)\r
+       {\r
+               wxMemoryDC memDC;\r
+               memDC.SelectObject(* bmp);\r
+               dc.Blit(0, 0, field_width * x_cell * X_UNIT + 1, field_height * y_cell * Y_UNIT + 1,\r
+                       &memDC, 0, 0, wxCOPY);\r
+               memDC.SelectObject(wxNullBitmap);\r
+       }\r
+       else\r
+               DrawField(&dc, 0, 0, field_width - 1, field_height - 1);*/\r
+\r
+       wxPaintDC dc(this);\r
+//Doesn't do crap!\r
+//dc.SetBackground(*wxWHITE_BRUSH);\r
+\r
+// Due to the screwiness of wxWidgets coord system, the origin is ALWAYS\r
+// the upper left corner--regardless of axis orientation, etc...\r
+       wxCoord width, height;\r
+       dc.GetSize(&width, &height);\r
+\r
+       dc.SetDeviceOrigin(-offsetX, height - (-offsetY));\r
+       dc.SetAxisOrientation(true, true);\r
+\r
+// Scrolling can be done by using OffsetViewportOrgEx\r
+// Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)\r
+// you'd use: % = ViewportExt / WindowExt\r
+// But it makes the window look like crap: fuggetuboutit.\r
+// Instead, we have to scale EVERYTHING by hand. Crap!\r
+// It's not *that* bad, but not as convenient either...\r
+\r
+       dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0xFF), 1, wxDOT)));\r
+//     dc.DrawLine(0, 0, 10, 10);\r
+\r
+    // Draw coordinate axes\r
+\r
+       dc.CrossHair(0, 0);\r
+\r
+    // Draw points\r
+\r
+       for(int i=0; i<pts.GetNumPoints(); i++)\r
+       {\r
+               if (i == ptHighlight)\r
+               {\r
+                       dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));\r
+//                     SelectObject(hdc, hRedPen1);\r
+\r
+                       if (pts.GetOnCurve(i))\r
+                       {\r
+                               DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);\r
+                               DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);\r
+                       }\r
+                       else\r
+                       {\r
+                               DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);\r
+                               DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);\r
+                       }\r
+               }\r
+               else if ((i == ptHighlight || i == ptNextHighlight) && currentTool == TOOLAddPt)\r
+               {\r
+                       dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0xAF, 0x00), 1, wxSOLID)));\r
+//                     SelectObject(hdc, hGreenPen1);\r
+\r
+                       if (pts.GetOnCurve(i))\r
+                       {\r
+                               DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);\r
+                               DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);\r
+                       }\r
+                       else\r
+                       {\r
+                               DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);\r
+                               DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));\r
+//                     SelectObject(hdc, hBlackPen1);\r
+\r
+                       if (pts.GetOnCurve(i))\r
+                               DrawSquareDot(dc, pts.GetX(i), pts.GetY(i));\r
+                       else\r
+                               DrawRoundDot(dc, pts.GetX(i), pts.GetY(i));\r
+               }\r
+\r
+               if (currentTool == TOOLDelPt && i == ptHighlight)\r
+               {\r
+                       dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));\r
+//                     SelectObject(hdc, hRedPen1);\r
+//                     MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);\r
+//                     LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);\r
+//                     LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!\r
+//                     MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);\r
+//                     LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);\r
+//                     LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!\r
+                       dc.DrawLine(pts.GetX(i) - 5, pts.GetY(i) - 5, pts.GetX(i) + 5, pts.GetY(i) + 5);\r
+                       dc.DrawLine(pts.GetX(i) + 5, pts.GetY(i) - 5, pts.GetX(i) - 5, pts.GetY(i) + 5);\r
+               }\r
+       }\r
+\r
+//             SelectObject(hdc, hBlackPen1);\r
+       dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));\r
+\r
+       // Draw curve formed by points\r
+\r
+       for(int poly=0; poly<pts.GetNumPolys(); poly++)\r
+       {\r
+               if (pts.GetNumPoints(poly) > 2)\r
+               {\r
+                       // Initial move...\r
+                       // If it's not on curve, then move to it, otherwise move to last point...\r
+\r
+                       wxCoord x, y;\r
+       \r
+                       if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))\r
+                               x = (wxCoord)pts.GetX(poly, pts.GetNumPoints(poly) - 1), y = (wxCoord)pts.GetY(poly, pts.GetNumPoints(poly) - 1);\r
+                       else\r
+                               x = (wxCoord)pts.GetX(poly, 0), y = (wxCoord)pts.GetY(poly, 0);\r
+       \r
+                       for(int i=0; i<pts.GetNumPoints(poly); i++)\r
+                       {\r
+                               if (pts.GetOnCurve(poly, i))\r
+//                                     LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));\r
+                               {\r
+                                       dc.DrawLine(x, y, pts.GetX(poly, i), pts.GetY(poly, i));\r
+                                       x = (wxCoord)pts.GetX(poly, i), y = (wxCoord)pts.GetY(poly, i);\r
+                               }\r
+                               else\r
+                               {\r
+                                       uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);\r
+                                       float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),\r
+                                               nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);\r
+       \r
+                                       if (!pts.GetOnCurve(poly, prev))\r
+                                               px = (px + pts.GetX(poly, i)) / 2.0f,\r
+                                               py = (py + pts.GetY(poly, i)) / 2.0f;\r
+       \r
+                                       if (!pts.GetOnCurve(poly, next))\r
+                                               nx = (nx + pts.GetX(poly, i)) / 2.0f,\r
+                                               ny = (ny + pts.GetY(poly, i)) / 2.0f;\r
+       \r
+                                       Bezier(dc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));\r
+                                       x = (wxCoord)nx, y = (wxCoord)ny;\r
+       \r
+                                       if (pts.GetOnCurve(poly, next))\r
+                                               i++;                                    // Following point is on curve, so move past it\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+//             SelectObject(hdc, oldPen);                              // Restore the stuff we disrupted...\r
+       dc.SetPen(wxNullPen);\r
+//             SelectObject(hdc, oldBrush);\r
+//             EndPaint(hWnd, &ps);\r
+}\r
+\r
+void TTEditWindow::OnMouseEvent(wxMouseEvent &e)\r
+{\r
+       if (e.RightDown())\r
+       {\r
+               wxPoint pt = ClientToScreen(e.GetPosition());\r
+               wxGetApp().toolPalette->Move(pt);\r
+               wxGetApp().toolPalette->Show(true);\r
+               wxGetApp().toolPalette->SetFocus();\r
+               wxGetApp().toolPalette->CaptureMouse();\r
+               SetCursor(*wxSTANDARD_CURSOR);\r
+       }\r
+       else if (e.LeftDown())\r
+       {\r
+               if (currentTool == TOOLScroll || currentTool == TOOLZoom)\r
+                       CaptureMouse();                                         // Make sure we capture the mouse when in scroll/zoom mode\r
+               else if (currentTool == TOOLAddPt)              // "Add Point" tool\r
+               {\r
+                       if (pts.GetNumPoints() > 0)\r
+                       {\r
+                               wxPoint pt = GetAdjustedMousePosition(e);\r
+                               pts.InsertPoint(pts.GetNext(ptHighlight), pt.x, pt.y, (e.ShiftDown() | e.ControlDown() ? false : true));\r
+                               ptHighlight = ptNextHighlight;\r
+                               Refresh();\r
+                       }\r
+               }\r
+               else if (currentTool == TOOLAddPoly)    // "Add Poly" tool\r
+               {\r
+#ifdef DEBUGFOO\r
+WriteLogMsg("Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());\r
+#endif\r
+                       if (polyFirstPoint)\r
+                       {\r
+                               polyFirstPoint = false;\r
+                               pts.AddNewPolyAtEnd();\r
+                       }\r
+\r
+                       wxPoint pt = GetAdjustedMousePosition(e);\r
+                       // Append a point to the end of the structure\r
+                       pts += IPoint(pt.x, pt.y, (e.ShiftDown() | e.ControlDown() ? false : true));\r
+                       ptHighlight = pts.GetNumPoints() - 1;\r
+                       Refresh();\r
+#ifdef DEBUGFOO\r
+WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumPoints());\r
+#endif\r
+               }\r
+               else if (currentTool == TOOLSelect || currentTool == TOOLPolySelect)\r
+               {\r
+                       if (pts.GetNumPoints() > 0)\r
+                       {\r
+                               pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));\r
+                               WarpPointer(pt.x, pt.y);\r
+\r
+                               if (e.ShiftDown() | e.ControlDown())\r
+                                       pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));\r
+                       }\r
+               }\r
+               else if (currentTool == TOOLDelPt)\r
+               {\r
+                       if (pts.GetNumPoints() > 0)\r
+//Or could use:\r
+//                     if (ptHighlight != -1)\r
+                       {\r
+//This assumes that WM_MOUSEMOVE happens before this!\r
+//The above commented out line should take care of this contingency... !!! FIX !!!\r
+                               pts.DeletePoint(ptHighlight);\r
+                               Refresh();\r
+                       }\r
+               }\r
+       }\r
+       else if (e.LeftUp())\r
+       {\r
+//             mouseDown = false;\r
+\r
+               if (currentTool == TOOLScroll || currentTool == TOOLZoom)\r
+//                     ReleaseCapture();\r
+                       ReleaseMouse();\r
+       }\r
+       else if (e.Dragging())\r
+       {\r
+//Do this here? Needed?                SetCursor(hCur[currentTool]);\r
+\r
+           // Extract current point from lParam/calc offset from previous point\r
+\r
+               pt = e.GetPosition();\r
+               ptOffset.x = pt.x - ptPrevious.x,\r
+               ptOffset.y = pt.y - ptPrevious.y;\r
+\r
+//             if (e.LeftIsDown())\r
+//             {\r
+                       if (currentTool == TOOLScroll)\r
+                       {\r
+                               // NOTE: OffsetViewportOrg operates in DEVICE UNITS...\r
+\r
+//Seems there's no equivalent for this in wxWidgets...!\r
+//!!! FIX !!!\r
+//                             hdc = GetDC(hWnd);\r
+//                             OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);\r
+//                             ReleaseDC(hWnd, hdc);\r
+\r
+// this shows that it works, so the logic above must be faulty...\r
+// And it is. It should convert the coords first, then do the subtraction to figure the offset...\r
+// Above: DONE\r
+// Then multiply it by the scaling factor. Whee!\r
+                               // This looks wacky because we're using screen coords for the offset...\r
+                               // Otherwise, we would subtract both offsets!\r
+                               offsetX -= ptOffset.x, offsetY += ptOffset.y;\r
+                               Refresh();\r
+                       }\r
+                       else if (currentTool == TOOLAddPt || currentTool == TOOLAddPoly || currentTool == TOOLSelect)\r
+                       {\r
+                               if (currentTool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.\r
+                               {\r
+                                       wxPoint pt2 = GetAdjustedMousePosition(e);\r
+                                       pts.SetXY(ptHighlight, pt2.x, pt2.y);\r
+                                       Refresh();\r
+                               }\r
+                       }\r
+                       else if (currentTool == TOOLPolySelect)\r
+                       {\r
+                               if (pts.GetNumPoints() > 0)\r
+                               {\r
+                                       wxPoint pt2 = GetAdjustedMousePosition(e);\r
+                                       // Should also set onCurve here as well, depending on keystate\r
+//Or should we?\r
+                                       pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));\r
+                                       Refresh();\r
+                               }\r
+                       }\r
+//             }\r
+\r
+               ptPrevious = pt;\r
+       }\r
+       else if (e.Moving())\r
+       {\r
+//             else    // Moving, not dragging...\r
+//             {\r
+                       if (currentTool == TOOLSelect || currentTool == TOOLDelPt || currentTool == TOOLAddPt\r
+                               || currentTool == TOOLPolySelect)// || currentTool == TOOLAddPoly)\r
+                       {\r
+                               wxPoint pt2 = GetAdjustedMousePosition(e);\r
+                               double closest = 1.0e+99;\r
+\r
+                               for(int i=0; i<pts.GetNumPoints(); i++)\r
+                               {\r
+                                       double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))\r
+                                               + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));\r
+\r
+                                       if (dist < closest)\r
+                                               closest = dist, ptHighlight = i;\r
+                               }\r
+\r
+                               if (ptHighlight != oldPtHighlight)\r
+                               {\r
+                                       oldPtHighlight = ptHighlight;\r
+                                       Refresh();\r
+                               }\r
+\r
+                               // What follows here looks like voodoo, but is really simple. What we do is\r
+                               // check to see if the mouse point has a perpendicular intersection with any of\r
+                               // the line segments. If it does, calculate the length of the perpendicular\r
+                               // and choose the smallest length. If there is no perpendicular, then choose the\r
+                               // length of line connecting the closer of either the first endpoint or the\r
+                               // second and choose the smallest of those.\r
+\r
+                               // There is one bit of math that looks like voodoo to me ATM--will explain once\r
+                               // I understand it better (the calculation of the length of the perpendicular).\r
+\r
+                               if (pts.GetNumPoints() > 1 && currentTool == TOOLAddPt)\r
+                               {\r
+                                       double smallest = 1.0e+99;\r
+\r
+                                       for(int i=0; i<pts.GetNumPoints(); i++)\r
+                                       {\r
+                                               int32 p1x = pts.GetX(i), p1y = pts.GetY(i),\r
+                                                       p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));\r
+\r
+                                               vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x, pt2.y, 0, p1x, p1y, 0),\r
+                                                       v2(pt2.x, pt2.y, 0, p2x, p2y, 0);\r
+                                               double pp = ls.dot(v1) / ls.length(), dist;\r
+// Geometric interpretation:\r
+// pp is the paremeterized point on the vector ls where the perpendicular intersects ls.\r
+// If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,\r
+// then the perpendicular lies beyond the 2nd endpoint.\r
+\r
+                                               if (pp < 0.0)\r
+                                                       dist = v1.length();\r
+                                               else if (pp > ls.length())\r
+                                                       dist = v2.length();\r
+                                               else                                    // distance = ?Det?(ls, v1) / |ls|\r
+                                                       dist = fabs((ls.x * v1.y - v1.x * ls.y) / ls.length());\r
+\r
+//The answer to the above looks like it might be found here:\r
+//\r
+//If the segment endpoints are s and e, and the point is p, then the test for the perpendicular\r
+//intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and\r
+//{e-s}.{e-p} are both non-negative.  Perpendicular distance from the point to the segment is\r
+//computed by first computing the area of the triangle the three points form, then dividing by the\r
+//length of the segment.  Distances are done just by the Pythagorean theorem.  Twice the area of the\r
+//triangle formed by three points is the determinant of the following matrix:\r
+//\r
+//sx sy 1\r
+//ex ey 1\r
+//px py 1\r
+//\r
+//(???) By translating the start point to the origin, this can be rewritten as:\r
+//By subtracting row 1 from all rows, you get the following:\r
+//\r
+//0         0         0\r
+//(ex - sx) (ey - sy) 0\r
+//(px - sx) (py - sy) 0\r
+//\r
+//which greatly simplifies the calculation of the determinant.\r
+\r
+                                               if (dist < smallest)\r
+                                                       smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;\r
+                                       }\r
+\r
+                                       if (ptNextHighlight != oldPtNextHighlight)\r
+                                       {\r
+                                               oldPtNextHighlight = ptNextHighlight;\r
+                                               Refresh();\r
+                                       }\r
+                               }\r
+                       }\r
+//             }\r
+\r
+               ptPrevious = e.GetPosition();\r
+       }\r
+}\r
+\r
+\r
+wxPoint TTEditWindow::GetAdjustedMousePosition(wxMouseEvent &e)\r
+{\r
+       wxCoord width, height;\r
+       wxClientDC dc(this);\r
+\r
+       dc.GetSize(&width, &height);\r
+       dc.SetDeviceOrigin(-offsetX, height - (-offsetY));\r
+       dc.SetAxisOrientation(true, true);\r
+\r
+/*wxStatusBar * sb = ((wxFrame *)GetParent())->GetStatusBar();\r
+wxString s;\r
+s.Printf("Logical mouse pos: %d, %d (%d, %d)", pt.x, pt.y, width, height);\r
+sb->SetStatusText(s);//*/\r
+\r
+       return e.GetLogicalPosition(dc);\r
+}\r
+\r
+wxPoint TTEditWindow::GetAdjustedClientPosition(wxCoord x, wxCoord y)\r
+{\r
+       wxCoord width, height;\r
+       wxClientDC dc(this);\r
+\r
+       dc.GetSize(&width, &height);\r
+       dc.SetDeviceOrigin(-offsetX, height - (-offsetY));\r
+       dc.SetAxisOrientation(true, true);\r
+\r
+       return wxPoint(dc.LogicalToDeviceX(x), dc.LogicalToDeviceY(y));\r
+}\r
+\r
+//\r
+\r
+void CreateResources(void)\r
+{\r
+       // This is a sucky way to create cursors, but at least it's cross-platform...\r
+       // NOTE: Need to fix hotspots on a few... !!! FIX !!!\r
+\r
+       wxBitmap cursorBM1(cur1_xpm);\r
+       wxImage cursorImage1 = cursorBM1.ConvertToImage();\r
+       cursorImage1.SetMaskFromImage(cursorImage1, 0xFF, 0xFF, 0xFF);\r
+       cur[0] = new wxCursor(cursorImage1);\r
+\r
+       wxBitmap cursorBM2(cur2_xpm);\r
+       wxImage cursorImage2 = cursorBM2.ConvertToImage();\r
+       cursorImage2.SetMaskFromImage(cursorImage2, 0xFF, 0xFF, 0xFF);\r
+       cur[1] = new wxCursor(cursorImage2);\r
+\r
+       wxBitmap cursorBM3(cur3_xpm);\r
+       wxImage cursorImage3 = cursorBM3.ConvertToImage();\r
+       cursorImage3.SetMaskFromImage(cursorImage3, 0xFF, 0xFF, 0xFF);\r
+       cur[2] = new wxCursor(cursorImage3);\r
+\r
+       wxBitmap cursorBM4(cur4_xpm);\r
+       wxImage cursorImage4 = cursorBM4.ConvertToImage();\r
+       cursorImage4.SetMaskFromImage(cursorImage4, 0xFF, 0xFF, 0xFF);\r
+       cur[3] = new wxCursor(cursorImage4);\r
+\r
+       wxBitmap cursorBM5(cur5_xpm);\r
+       wxImage cursorImage5 = cursorBM5.ConvertToImage();\r
+       cursorImage5.SetMaskFromImage(cursorImage5, 0xFF, 0xFF, 0xFF);\r
+       cur[4] = new wxCursor(cursorImage5);\r
+\r
+       wxBitmap cursorBM6(cur6_xpm);\r
+       wxImage cursorImage6 = cursorBM6.ConvertToImage();\r
+       cursorImage6.SetMaskFromImage(cursorImage6, 0xFF, 0xFF, 0xFF);\r
+       cur[5] = new wxCursor(cursorImage6);\r
+\r
+       wxBitmap cursorBM7(cur7_xpm);\r
+       wxImage cursorImage7 = cursorBM7.ConvertToImage();\r
+       cursorImage7.SetMaskFromImage(cursorImage7, 0xFF, 0xFF, 0xFF);\r
+       cur[6] = new wxCursor(cursorImage7);\r
+\r
+       wxBitmap cursorBM8(cur8_xpm);\r
+       wxImage cursorImage8 = cursorBM8.ConvertToImage();\r
+       cursorImage8.SetMaskFromImage(cursorImage8, 0xFF, 0xFF, 0xFF);\r
+       cur[7] = new wxCursor(cursorImage8);\r
+}\r
+\r
+//\r
+// Draw a round dot (5x5, centered on [x, y])\r
+//\r
+void DrawRoundDot(wxDC &dc, int32 x, int32 y)\r
+{\r
+       wxPoint pt[8];\r
+\r
+       pt[0].x = x - 1, pt[0].y = y - 2;\r
+       pt[1].x = x + 1, pt[1].y = y - 2;\r
+       pt[2].x = x + 2, pt[2].y = y - 1;\r
+       pt[3].x = x + 2, pt[3].y = y + 1;\r
+       pt[4].x = x + 1, pt[4].y = y + 2;\r
+       pt[5].x = x - 1, pt[5].y = y + 2;\r
+       pt[6].x = x - 2, pt[6].y = y + 1;\r
+       pt[7].x = x - 2, pt[7].y = y - 1;\r
+\r
+       dc.DrawPolygon(8, pt);\r
+}\r
+\r
+//\r
+// Draw a sqaure dot (5x5, centered on [x, y])\r
+//\r
+void DrawSquareDot(wxDC &dc, int32 x, int32 y)\r
+{\r
+       wxPoint pt[4];\r
+\r
+       pt[0].x = x - 2, pt[0].y = y - 2;\r
+       pt[1].x = x + 2, pt[1].y = y - 2;\r
+       pt[2].x = x + 2, pt[2].y = y + 2;\r
+       pt[3].x = x - 2, pt[3].y = y + 2;\r
+\r
+       dc.DrawPolygon(4, pt);\r
+}\r
+\r
+//\r
+// Draw a sqaure dot (nxn, centered on [x, y])\r
+//\r
+void DrawSquareDotN(wxDC &dc, int32 x, int32 y, uint32 n)\r
+{\r
+       wxPoint pt[4];\r
+       uint32 offset = (n - 1) / 2;\r
+\r
+       pt[0].x = x - offset, pt[0].y = y - offset;\r
+       pt[1].x = x + offset, pt[1].y = y - offset;\r
+       pt[2].x = x + offset, pt[2].y = y + offset;\r
+       pt[3].x = x - offset, pt[3].y = y + offset;\r
+\r
+       dc.DrawPolygon(4, pt);\r
+}\r
+\r
+//\r
+// Draw a round dot (nxn, centered on [x, y])\r
+//\r
+void DrawRoundDotN(wxDC &dc, int32 x, int32 y, uint32 n)\r
+{\r
+       dc.DrawCircle(x, y, (n / 2) + 1);\r
+}\r
+\r
+\r
+BEGIN_EVENT_TABLE(CharWindow, wxWindow)\r
+//     EVT_PAINT(CharWindow::OnPaint)\r
+//     EVT_MOUSE_EVENTS(CharWindow::OnMouseEvent)\r
+END_EVENT_TABLE()\r
+\r
+CharWindow::CharWindow(wxFrame * parent, const wxPoint &pos, const wxSize &size, long style):\r
+       wxWindow(parent, -1, pos, size, style)\r
+{\r
+} \r
+\r
+CharWindow::~CharWindow()\r
+{\r
+}\r
+\r
+\r
+BEGIN_EVENT_TABLE(ToolWindow, wxWindow)\r
+       EVT_PAINT(ToolWindow::OnPaint)\r
+       EVT_MOUSE_EVENTS(ToolWindow::OnMouseEvent)\r
+END_EVENT_TABLE()\r
+\r
+ToolWindow::ToolWindow(wxFrame * parent, const wxString &title, const wxPoint &pos,\r
+       const wxSize &size, long style): wxFrame(parent, -1, title, pos, size, style)\r
+//ToolWindow::ToolWindow(wxFrame * parent, const wxPoint &pos, const wxSize &size, long style):\r
+//     wxWindow(parent, -1, pos, size, style)\r
+{\r
+       bmp = new wxBitmap(toolpal1_xpm);\r
+       prevTool = -1;\r
+\r
+       // Set up sizes\r
+\r
+       sizeTPBM.x = bmp->GetWidth(), sizeTPBM.y = bmp->GetHeight();\r
+       sizeStamp.x = sizeTPBM.x / 4, sizeStamp.y = sizeTPBM.y / 2;\r
+\r
+       SetSize(10, 10, sizeTPBM.x, sizeTPBM.y);\r
+       Show(false);\r
+}\r
+\r
+ToolWindow::~ToolWindow()\r
+{\r
+}\r
+\r
+void ToolWindow::OnPaint(wxPaintEvent &e)\r
+{\r
+       wxPaintDC dc(this);\r
+\r
+       wxMemoryDC memDC;\r
+       memDC.SelectObject(*bmp);\r
+       dc.Blit(0, 0, sizeTPBM.x, sizeTPBM.y, &memDC, 0, 0, wxCOPY);\r
+\r
+       int32 tool = FindSelectedTool();\r
+\r
+       if (tool != -1)\r
+       {\r
+           //need ul corner of bitmap, ul corner of dest, width/height\r
+               wxPoint pt(sizeStamp.x * (tool & 0x03), sizeStamp.y * (tool >> 2));\r
+               dc.Blit(pt.x, pt.y, sizeStamp.x, sizeStamp.y, &memDC, pt.x, pt.y, wxSRC_INVERT);\r
+       }\r
+\r
+       memDC.SelectObject(wxNullBitmap);\r
+}\r
+\r
+void ToolWindow::OnMouseEvent(wxMouseEvent &e)\r
+{\r
+//     if (e.Moving())\r
+       if (e.Dragging())\r
+       {\r
+               int32 tool = FindSelectedTool();\r
+\r
+               if (tool != prevTool)\r
+               {\r
+                       prevTool = tool;\r
+                       Refresh(false);\r
+               }\r
+       }\r
+\r
+       if (e.RightUp())\r
+       {\r
+               int32 tool = FindSelectedTool(), oldTool = currentTool;\r
+\r
+               if (tool != -1)\r
+                       currentTool = tool;\r
+\r
+               if (currentTool != TOOLSelect && currentTool != TOOLDelPt && currentTool != TOOLAddPt\r
+                       && currentTool != TOOLPolySelect)\r
+                       ptHighlight = -1;\r
+\r
+               if (currentTool != oldTool)\r
+                       Refresh(false);\r
+\r
+               if (currentTool == TOOLAddPoly)\r
+#ifdef DEBUGFOO\r
+{\r
+#endif\r
+                       polyFirstPoint = true;\r
+#ifdef DEBUGFOO\r
+sprintf(strBuf, "--> Selected poly tool, polyFirstPoint is %s\n", polyFirstPoint ? "true" : "false");\r
+WriteLogMsg(strBuf);\r
+}\r
+#endif\r
+\r
+               ReleaseMouse();\r
+               Show(false);\r
+               wxGetApp().mainFrame->mainWindow->SetCursor(*cur[currentTool]);\r
+               wxGetApp().mainFrame->mainWindow->SetFocus();   // Make sure the main wnd keeps focus!\r
+       }\r
+}\r
+\r
+//\r
+// Find which tool we're pointing at\r
+// Use: xcoord = mouse.x / (bmsize.x/4), ycoord = mouse.y / (bmsize.y/2)\r
+//\r
+int32 ToolWindow::FindSelectedTool(void)\r
+{\r
+       wxPoint pt = ScreenToClient(wxGetMousePosition());\r
+       uint32 x = (uint32)pt.x / sizeStamp.x, y = (uint32)pt.y / sizeStamp.y, tool = (uint32)-1;\r
+\r
+       if (x < 4 && y < 2)\r
+               tool = (y * 4) + x;\r
+\r
+       return tool;\r
+}\r
+\r
+\r
+/*\r
+LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)\r
+{\r
+       RECT rc1, rc2;\r
+       HDC hdc;\r
+       POINT pt, ptOffset;\r
+       SIZE sz;\r
+       PAINTSTRUCT ps;\r
+\r
+       switch (msgID)\r
+       {\r
+       case WM_CREATE:\r
+\r
+               MiscCenterWnd(hWnd, GetDesktopWindow());\r
+               InitCommonControls();\r
+               hStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE, statusBarTxt, hWnd, ID_STATUSBAR);\r
+\r
+               if (!hStatusBar)\r
+                       return -1;\r
+\r
+// clean this crap up!\r
+// well, the only crappy thing here is using a POINT as an int array, but otherwise, this is OK\r
+               wsprintf(strBuf, zoom, 1000);\r
+               hdc = GetDC(hWnd);\r
+               GetTextExtentPoint32(hdc, strBuf, lstrlen(strBuf), &sz);\r
+               ReleaseDC(hWnd, hdc);\r
+               zoomWndWidth = sz.cx;\r
+               wsprintf(strBuf, zoom, 100);\r
+\r
+               GetClientRect(hWnd, &rc1);\r
+               pt.x = rc1.right - zoomWndWidth, pt.y = -1;\r
+               SendMessage(hStatusBar, SB_SETPARTS, 2, (LPARAM)&pt);\r
+               SendMessage(hStatusBar, SB_SETTEXT, (0 | SBT_NOBORDERS), (LPARAM)statusBarTxt);\r
+               SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM)strBuf);\r
+\r
+               hToolBar = CreateToolbarEx(hWnd, WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS,\r
+                       IDR_TOOLBAR1, 3, hInst, IDB_TOOLBAR1, tbButtons, 4, 16, 16, 16, 16, sizeof(TBBUTTON));\r
+\r
+               if (!hToolBar)\r
+                       return -1;\r
+\r
+               CreateNewDoc();\r
+\r
+// The following can only be done because we use a private DC (using "CS_OWNDC")\r
+// (Is that true???)\r
+// Set the mapping to draw the character so it fits in the viewport...\r
+               hdc = GetDC(hWnd);\r
+               GetClientRect(hWnd, &rc1);\r
+               GetClientRect(hStatusBar, &rc2);\r
+               rc1.bottom -= rc2.bottom;\r
+               SetMapMode(hdc, MM_ISOTROPIC);\r
+               SetWindowExtEx(hdc, rc1.right, rc1.bottom, NULL);\r
+               SetViewportExtEx(hdc, rc1.right, -rc1.bottom, NULL);\r
+               SetViewportOrgEx(hdc, 0, rc1.bottom, NULL);\r
+               ReleaseDC(hWnd, hdc);\r
+               break;\r
+\r
+       case WM_CLOSE:\r
+\r
+               if (SaveChanges())\r
+               {\r
+                       wpM.length = wpC.length = sizeof(WINDOWPLACEMENT);\r
+                       GetWindowPlacement(hMainWnd, &wpM);\r
+                       GetWindowPlacement(hCharWnd, &wpC);\r
+\r
+                       if (!IsWindowVisible(hCharWnd))         // Needed because Windows lies about visibility\r
+                               wpC.showCmd = SW_HIDE;\r
+\r
+                       hdc = GetDC(hWnd);\r
+                       GetViewportOrgEx(hdc, &ptVPM);\r
+                       ReleaseDC(hWnd, hdc);\r
+\r
+                       DestroyWindow(hWnd);\r
+               }\r
+\r
+               break;\r
+\r
+       case WM_DESTROY:\r
+\r
+               PostQuitMessage(0);\r
+               break;\r
+\r
+       case WM_NCLBUTTONDOWN:\r
+\r
+               if (wParam == HTCAPTION)\r
+               {\r
+                       NCMouseDown = true;\r
+                       GetWindowRect(hMainWnd, &rc1);\r
+                       GetWindowRect(hCharWnd, &rc2);\r
+                       ptWinOffset.x = rc2.left - rc1.left;\r
+                       ptWinOffset.y = rc2.top - rc1.top;\r
+               }\r
+                   \r
+               // Let Windows do its thing with this msg, or weird things will happen...\r
+\r
+               DefWindowProc(hWnd, msgID, wParam, lParam);\r
+               NCMouseDown = false;\r
+               break;\r
+\r
+       case WM_WINDOWPOSCHANGING:\r
+\r
+               if (NCMouseDown)\r
+               {\r
+                       WINDOWPOS * wp = (WINDOWPOS *)lParam;\r
+\r
+                       if (wp->hwnd == hMainWnd && !(wp->flags & SWP_NOMOVE))\r
+                               SetWindowPos(hCharWnd, 0, wp->x + ptWinOffset.x, wp->y + ptWinOffset.y,\r
+                                               0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);\r
+               }\r
+\r
+               return DefWindowProc(hWnd, msgID, wParam, lParam);      // Seems this is needed... Bleah!\r
+\r
+       case WM_PAINT:\r
+       {\r
+               hdc = BeginPaint(hWnd, &ps);\r
+\r
+// Scrolling can be done by using OffsetViewportOrgEx\r
+// Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)\r
+// you'd use: % = ViewportExt / WindowExt\r
+// But it makes the window look like crap: fuggetuboutit.\r
+// Instead, we have to scale EVERYTHING by hand. Crap!\r
+\r
+               // Apparently, you *must* save the individual object types (pen, brush, etc.)\r
+\r
+               HGDIOBJ oldPen = SelectObject(hdc, hBluePen1),\r
+                       oldBrush = SelectObject(hdc, hNullBrush);\r
+\r
+           // Draw coordinate axes\r
+\r
+               MoveToEx(hdc, 0, -32000, NULL);\r
+               LineTo(hdc, 0, 32000);\r
+               MoveToEx(hdc, -32000, 0, NULL);\r
+               LineTo(hdc, 32000, 0);\r
+\r
+           // Draw points\r
+\r
+               for(int i=0; i<pts.GetNumPoints(); i++)\r
+               {\r
+                       if (i == ptHighlight)\r
+                       {\r
+                               SelectObject(hdc, hRedPen1);\r
+\r
+                               if (pts.GetOnCurve(i))\r
+                               {\r
+                                       DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);\r
+                                       DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);\r
+                               }\r
+                               else\r
+                               {\r
+                                       DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);\r
+                                       DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);\r
+                               }\r
+                       }\r
+                       else if ((i == ptHighlight || i == ptNextHighlight) && currentTool == TOOLAddPt)\r
+                       {\r
+                               SelectObject(hdc, hGreenPen1);\r
+\r
+                               if (pts.GetOnCurve(i))\r
+                               {\r
+                                       DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);\r
+                                       DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);\r
+                               }\r
+                               else\r
+                               {\r
+                                       DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);\r
+                                       DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               SelectObject(hdc, hBlackPen1);\r
+\r
+                               if (pts.GetOnCurve(i))\r
+                                       DrawSquareDot(hdc, pts.GetX(i), pts.GetY(i));\r
+                               else\r
+                                       DrawRoundDot(hdc, pts.GetX(i), pts.GetY(i));\r
+                       }\r
+\r
+                       if (currentTool == TOOLDelPt && i == ptHighlight)\r
+                       {\r
+                               SelectObject(hdc, hRedPen1);\r
+                               MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);\r
+                               LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);\r
+                               LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!\r
+                               MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);\r
+                               LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);\r
+                               LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!\r
+                       }\r
+               }\r
+\r
+               SelectObject(hdc, hBlackPen1);\r
+\r
+               // Draw curve formed by points\r
+\r
+               for(int poly=0; poly<pts.GetNumPolys(); poly++)\r
+               {\r
+                       if (pts.GetNumPoints(poly) > 2)\r
+                       {\r
+                               // Initial move...\r
+                               // If it's not on curve, then move to it, otherwise move to last point...\r
+       \r
+                               if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))\r
+                                       MoveToEx(hdc, pts.GetX(poly, pts.GetNumPoints(poly) - 1), pts.GetY(poly, pts.GetNumPoints(poly) - 1), NULL);\r
+                               else\r
+                                       MoveToEx(hdc, pts.GetX(poly, 0), pts.GetY(poly, 0), NULL);\r
+       \r
+                               for(int i=0; i<pts.GetNumPoints(poly); i++)\r
+                               {\r
+                                       if (pts.GetOnCurve(poly, i))\r
+                                               LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));\r
+                                       else\r
+                                       {\r
+                                               uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);\r
+                                               float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),\r
+                                                       nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);\r
+       \r
+                                               if (!pts.GetOnCurve(poly, prev))\r
+                                                       px = (px + pts.GetX(poly, i)) / 2.0f,\r
+                                                       py = (py + pts.GetY(poly, i)) / 2.0f;\r
+       \r
+                                               if (!pts.GetOnCurve(poly, next))\r
+                                                       nx = (nx + pts.GetX(poly, i)) / 2.0f,\r
+                                                       ny = (ny + pts.GetY(poly, i)) / 2.0f;\r
+       \r
+                                               Bezier(hdc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));\r
+       \r
+                                               if (pts.GetOnCurve(poly, next))\r
+                                                       i++;                                    // Following point is on curve, so move past it\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               SelectObject(hdc, oldPen);                              // Restore the stuff we disrupted...\r
+               SelectObject(hdc, oldBrush);\r
+               EndPaint(hWnd, &ps);\r
+               break;\r
+       }\r
+       case WM_SIZE:\r
+\r
+               // Apparently this is needed since these windows don't update themselves.\r
+               SendMessage(hStatusBar, msgID, wParam, lParam);\r
+               SendMessage(hToolBar, msgID, wParam, lParam);\r
+\r
+               // This is needed to make the 2nd status pane visible\r
+               GetClientRect(hWnd, &rc1);\r
+               pt.x = rc1.right - zoomWndWidth, pt.y = -1;\r
+               SendMessage(hStatusBar, SB_SETPARTS, 2, (LPARAM)&pt);\r
+               break;\r
+\r
+       case WM_RBUTTONDOWN:\r
+\r
+               GetCursorPos(&pt);\r
+               SetWindowPos(hToolPalWnd, 0, pt.x, pt.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);\r
+               SetFocus(hToolPalWnd);\r
+               SetCapture(hToolPalWnd);                                // Ensure tool palette gets RButtonUp\r
+               SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)));        // Tool pallete has "regular" cursor\r
+               break;\r
+\r
+       case WM_LBUTTONDOWN:\r
+\r
+               mouseDown = true;\r
+\r
+               if (currentTool == TOOLScroll || currentTool == TOOLZoom)\r
+                       SetCapture(hWnd);                                       // Make sure we capture the mouse when in scroll/zoom mode\r
+               else if (currentTool == TOOLAddPt)              // "Add Point" tool\r
+               {\r
+                       if (pts.GetNumPoints() > 0)\r
+                       {\r
+//Do we really need to put a cap on this???\r
+//Maybe...\r
+//                             if (pts.GetNumPoints() < 16)\r
+//                             {\r
+                               pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;\r
+                               hdc = GetDC(hWnd);\r
+                               DPtoLP(hdc, &pt, 1);\r
+                               pts.InsertPoint(pts.GetNext(ptHighlight), pt.x, pt.y, (wParam & (MK_SHIFT | MK_CONTROL) ? false : true));\r
+                               ptHighlight = ptNextHighlight;\r
+                               ReleaseDC(hWnd, hdc);\r
+                               InvalidateRect(hWnd, NULL, TRUE);\r
+//                             }\r
+                       }\r
+               }\r
+               else if (currentTool == TOOLAddPoly)    // "Add Poly" tool\r
+               {\r
+#ifdef DEBUGFOO\r
+wsprintf(strBuf, "Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());\r
+WriteLogMsg(strBuf);\r
+#endif\r
+                       if (polyFirstPoint)\r
+                       {\r
+                               polyFirstPoint = false;\r
+                               pts.AddNewPolyAtEnd();\r
+                       }\r
+\r
+//Do we really need to put a cap on this???\r
+//Maybe...\r
+//                     if (pts.GetNumPoints() < 16)\r
+//                     {\r
+                       pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;\r
+                       hdc = GetDC(hWnd);\r
+                       DPtoLP(hdc, &pt, 1);\r
+                       ReleaseDC(hWnd, hdc);\r
+                       // Append a point to the end of the structure\r
+                       pts += IPoint(pt.x, pt.y, (wParam & (MK_SHIFT | MK_CONTROL) ? false : true));\r
+ptHighlight = pts.GetNumPoints() - 1;\r
+                       InvalidateRect(hWnd, NULL, TRUE);\r
+//                     }\r
+#ifdef DEBUGFOO\r
+wsprintf(strBuf, " --> [# polys: %u, # points: %u]\xD\xA", pts.GetNumPolys(), pts.GetNumPoints());\r
+WriteLogMsg(strBuf);\r
+#endif\r
+               }\r
+               else if (currentTool == TOOLSelect || currentTool == TOOLPolySelect)\r
+               {\r
+                       if (pts.GetNumPoints() > 0)\r
+                       {\r
+                               pt.x = pts.GetX(ptHighlight), pt.y = pts.GetY(ptHighlight);\r
+                               hdc = GetDC(hWnd);\r
+                               LPtoDP(hdc, &pt, 1);\r
+                               ClientToScreen(hWnd, &pt);\r
+                               SetCursorPos(pt.x, pt.y);\r
+                               ReleaseDC(hWnd, hdc);\r
+\r
+                               if (wParam & (MK_SHIFT | MK_CONTROL))\r
+                                       pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));\r
+                       }\r
+               }\r
+               else if (currentTool == TOOLDelPt)\r
+               {\r
+                       if (pts.GetNumPoints() > 0)\r
+//Or could use:\r
+//                     if (ptHighlight != -1)\r
+                       {\r
+//This assumes that WM_MOUSEMOVE happens before this!\r
+//The above commented out line should take care of this contingency... !!! FIX !!!\r
+                               pts.DeletePoint(ptHighlight);\r
+                               InvalidateRect(hWnd, NULL, TRUE);\r
+                       }\r
+               }\r
+\r
+               break;\r
+\r
+       case WM_LBUTTONUP:\r
+\r
+               mouseDown = false;\r
+\r
+               if (currentTool == TOOLScroll || currentTool == TOOLZoom)\r
+                       ReleaseCapture();\r
+\r
+               break;\r
+\r
+       case WM_MOUSEMOVE:\r
+\r
+               SetCursor(hCur[currentTool]);\r
+\r
+           // Extract current point from lParam/calc offset from previous point\r
+\r
+               pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;\r
+               ptOffset.x = pt.x - ptPrevious.x,\r
+               ptOffset.y = pt.y - ptPrevious.y;\r
+\r
+               if (mouseDown)\r
+               {\r
+                       if (currentTool == TOOLScroll)\r
+                       {\r
+                               // NOTE: OffsetViewportOrg operates in DEVICE UNITS...\r
+\r
+                               hdc = GetDC(hWnd);\r
+                               OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);\r
+                               ReleaseDC(hWnd, hdc);\r
+\r
+// this shows that it works, so the logic above must be faulty...\r
+// And it is. It should convert the coords first, then do the subtraction to figure the offset...\r
+// Above: DONE\r
+// Then multiply it by the scaling factor. Whee!\r
+\r
+                               InvalidateRect(hWnd, NULL, TRUE);\r
+//                             SendMessage(hWnd, WM_PAINT, NULL, NULL);\r
+                       }\r
+                       else if (currentTool == TOOLAddPt || currentTool == TOOLAddPoly || currentTool == TOOLSelect)\r
+                       {\r
+                               if (currentTool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.\r
+                               {\r
+                                       POINT pt2;\r
+                                       pt2.x = pt.x, pt2.y = pt.y;\r
+                                       // Should also set onCurve here as well, depending on keystate\r
+//Or should we?\r
+                                       hdc = GetDC(hWnd);\r
+                                       DPtoLP(hdc, &pt2, 1);\r
+                                       pts.SetXY(ptHighlight, pt2.x, pt2.y);\r
+                                       ReleaseDC(hWnd, hdc);\r
+                                       InvalidateRect(hWnd, NULL, TRUE);\r
+                               }\r
+                       }\r
+                       else if (currentTool == TOOLPolySelect)\r
+                       {\r
+                               if (pts.GetNumPoints() > 0)\r
+                               {\r
+                                       POINT pt2;\r
+                                       pt2.x = pt.x, pt2.y = pt.y;\r
+                                       // Should also set onCurve here as well, depending on keystate\r
+//Or should we?\r
+                                       hdc = GetDC(hWnd);\r
+                                       DPtoLP(hdc, &pt2, 1);\r
+                                       pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));\r
+                                       ReleaseDC(hWnd, hdc);\r
+                                       InvalidateRect(hWnd, NULL, TRUE);\r
+                               }\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       if (currentTool == TOOLSelect || currentTool == TOOLDelPt || currentTool == TOOLAddPt\r
+                               || currentTool == TOOLPolySelect)// || currentTool == TOOLAddPoly)\r
+                       {\r
+                               POINT pt2;\r
+                               pt2.x = pt.x, pt2.y = pt.y;\r
+                               hdc = GetDC(hWnd);\r
+                               DPtoLP(hdc, &pt2, 1);\r
+                               ReleaseDC(hWnd, hdc);\r
+\r
+                               double closest = 1.0e+99;\r
+\r
+                               for(int i=0; i<pts.GetNumPoints(); i++)\r
+                               {\r
+                                       double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))\r
+                                               + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));\r
+\r
+                                       if (dist < closest)\r
+                                               closest = dist, ptHighlight = i;\r
+                               }\r
+\r
+                               if (ptHighlight != oldPtHighlight)\r
+                               {\r
+                                       oldPtHighlight = ptHighlight;\r
+                                       InvalidateRect(hWnd, NULL, TRUE);\r
+                               }\r
+\r
+                               // What follows here looks like voodoo, but is really simple. What we do is\r
+                               // check to see if the mouse point has a perpendicular intersection with any of\r
+                               // the line segments. If it does, calculate the length of the perpendicular\r
+                               // and choose the smallest length. If there is no perpendicular, then choose the\r
+                               // length of line connecting the closer of either the first endpoint or the\r
+                               // second and choose the smallest of those.\r
+\r
+                               // There is one bit of math that looks like voodoo to me ATM--will explain once\r
+                               // I understand it better (the calculation of the length of the perpendicular).\r
+\r
+                               if (pts.GetNumPoints() > 1 && currentTool == TOOLAddPt)\r
+                               {\r
+                                       double smallest = 1.0e+99;\r
+\r
+                                       for(int i=0; i<pts.GetNumPoints(); i++)\r
+                                       {\r
+                                               int32 p1x = pts.GetX(i), p1y = pts.GetY(i),\r
+                                                       p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));\r
+\r
+                                               vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x, pt2.y, 0, p1x, p1y, 0),\r
+                                                       v2(pt2.x, pt2.y, 0, p2x, p2y, 0);\r
+                                               double pp = ls.dot(v1) / ls.length(), dist;\r
+// Geometric interpretation:\r
+// pp is the paremeterized point on the vector ls where the perpendicular intersects ls.\r
+// If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,\r
+// then the perpendicular lies beyond the 2nd endpoint.\r
+\r
+                                               if (pp < 0.0)\r
+                                                       dist = v1.length();\r
+                                               else if (pp > ls.length())\r
+                                                       dist = v2.length();\r
+                                               else                                    // distance = ?Det?(ls, v1) / |ls|\r
+                                                       dist = abs((ls.x * v1.y - v1.x * ls.y) / ls.length());\r
+\r
+//The answer to the above looks like it might be found here:\r
+//\r
+//If the segment endpoints are s and e, and the point is p, then the test for the perpendicular\r
+//intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and\r
+//{e-s}.{e-p} are both non-negative.  Perpendicular distance from the point to the segment is\r
+//computed by first computing the area of the triangle the three points form, then dividing by the\r
+//length of the segment.  Distances are done just by the Pythagorean theorem.  Twice the area of the\r
+//triangle formed by three points is the determinant of the following matrix:\r
+//\r
+//sx sy 1\r
+//ex ey 1\r
+//px py 1\r
+//\r
+//(???) By translating the start point to the origin, this can be rewritten as:\r
+//By subtracting row 1 from all rows, you get the following:\r
+//\r
+//0         0         0\r
+//(ex - sx) (ey - sy) 0\r
+//(px - sx) (py - sy) 0\r
+//\r
+//which greatly simplifies the calculation of the determinant.\r
+\r
+                                               if (dist < smallest)\r
+                                                       smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;\r
+                                       }\r
+\r
+                                       if (ptNextHighlight != oldPtNextHighlight)\r
+                                       {\r
+                                               oldPtNextHighlight = ptNextHighlight;\r
+                                               InvalidateRect(hWnd, NULL, TRUE);\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               ptPrevious.x = pt.x, ptPrevious.y = pt.y;\r
+\r
+               break;\r
+\r
+       case WM_NOTIFY:\r
+\r
+               if (((NMHDR *)lParam)->code == TTN_NEEDTEXT)\r
+               {\r
+                       LoadString(hInst, ((TOOLTIPTEXT *)lParam)->hdr.idFrom + 0x80, toolTipTxt, 16);\r
+                       ((TOOLTIPTEXT *)lParam)->lpszText = toolTipTxt;\r
+               }\r
+\r
+               break;\r
+\r
+       case WM_MENUSELECT:\r
+       {\r
+               statusBarTxt[0] = 0;                                    // Clear status bar text\r
+               uint16 flags = wParam >> 16;                    // Extract flags\r
+\r
+               if (!(flags & MFT_SEPARATOR))\r
+               {\r
+                       uint16 id = wParam & 0xFFFF;\r
+\r
+                       if (flags & MF_POPUP)\r
+                       {\r
+                               if (flags & MF_SYSMENU)\r
+                                       id = IDS_SYSMENU;\r
+                               else\r
+                                       id = IDM_FILEMENU + wParam;\r
+                       }\r
+\r
+                       LoadString(hInst, id, statusBarTxt, 64);\r
+               }\r
+\r
+               SendMessage(hStatusBar, SB_SETTEXT, 0 + SBT_NOBORDERS, (LPARAM)statusBarTxt);\r
+               break;\r
+       }\r
+       case WM_COMMAND:\r
+       {\r
+               uint16 cmd = wParam & 0xFFFF;\r
+\r
+               if (cmd == IDM_NEW)\r
+               {\r
+//                   call   CmdIDM_NEW\r
+               }\r
+               else if (cmd == IDM_OPEN)\r
+               {\r
+//                   call   SaveChanges\r
+//                   .IF (eax)\r
+//                     movmov ofn.hwndOwner, eax, hMainWnd\r
+//                     mov    ofn.Flags, OFN_PATHMUSTEXIST + OFN_FILEMUSTEXIST\r
+//                     invoke GetOpenFileName, ADDR ofn\r
+//                     .IF (eax)\r
+////////\r
+//jmp @F\r
+//szDMsg1a     BYTE    "Could not open the file (GetOpenFileName)...", 0\r
+//szDMsg1b     BYTE    "Open error!", 0\r
+//szDMsg1c     BYTE    "About to attempt to open file...", 0\r
+//@@:\r
+////invoke MessageBox, hWnd, ADDR szDMsg1a, ADDR szDMsg1b, MB_ICONERROR or MB_OK\r
+//invoke MessageBox, hMainWnd, ADDR szDMsg1c, ADDR szFile, MB_ICONERROR or MB_OK\r
+//                       invoke LoadTTF, ADDR szFile\r
+//\r
+//////\r
+//                       // <<< FILE OPEN CODE HERE >>>\r
+//                       or     fFileStatus, NAMEDbit\r
+//                       and    fFileStatus, NOT CHANGEDbit\r
+//                       call   NewWindowName\r
+//                       mov    eax, TRUE      // return TRUE\r
+//                       jmp    Return\r
+//                       //ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\r
+//OpenError:             invoke GetLastError\r
+//                       // <<< FILE OPEN ERROR CODE HERE >>>\r
+//                     .ENDIF\r
+//                     zero   eax      // return FALSE\r
+//                   .ENDIF\r
+               }\r
+               else if (cmd == IDM_SAVEAS)\r
+               {\r
+//                   and    fFileStatus, NOT NAMEDbit\r
+//                   call   CmdIDM_SAVE\r
+               }\r
+               else if (cmd == IDM_SAVE)\r
+               {\r
+//                   call   CmdIDM_SAVE\r
+               }\r
+               else if (cmd == IDM_ABOUT)\r
+                       DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ABOUT), hMainWnd, AboutProc, NULL);\r
+               else if (cmd == IDM_EXIT)\r
+                       SendMessage(hWnd, WM_CLOSE, 0, 0);\r
+               else if (cmd == ID_TBCHARWIN)\r
+               {\r
+                       ShowWindow(hCharWnd, (IsWindowVisible(hCharWnd) ? SW_HIDE : SW_SHOWNOACTIVATE));\r
+\r
+#ifdef DEBUGFOO\r
+wpC.length = sizeof(WINDOWPLACEMENT);\r
+GetWindowPlacement(hCharWnd, &wpC);\r
+wsprintf(strBuf, "Char window showCmd = %08X...\n", wpC.showCmd);\r
+WriteLogMsg(strBuf);\r
+#endif\r
+               }\r
+               else\r
+                       return DefWindowProc(hWnd, msgID, wParam, lParam);\r
+\r
+               break;\r
+       }\r
+       default:\r
+               return DefWindowProc(hWnd, msgID, wParam, lParam);\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+//\r
+// Initialize TTF data\r
+//\r
+void CreateNewDoc(void)\r
+{\r
+}\r
+\r
+//\r
+// Save changes to document before quitting\r
+//\r
+bool SaveChanges(void)\r
+{\r
+       return true;\r
+}\r
+\r
+\r
+\r
+//\r
+// ABOUT Dialog WndProc\r
+//\r
+BOOL CALLBACK AboutProc(HWND hDlg, UINT msgID, WPARAM wParam, LPARAM lParam)\r
+{\r
+       switch (msgID)\r
+       {\r
+       case WM_INITDIALOG:\r
+\r
+               MiscCenterWnd(hDlg, hMainWnd);\r
+               break;\r
+\r
+       case WM_COMMAND:\r
+\r
+               if (wParam == IDOK || wParam == IDCANCEL)\r
+                       EndDialog(hDlg, TRUE);\r
+\r
+               break;\r
+\r
+       default:\r
+               return FALSE;\r
+       }\r
+\r
+       return TRUE;\r
+}\r
+\r
+//\r
+// Character Window WndProc\r
+//\r
+WndProcCW      PROC  STDCALL, hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM\r
+\r
+               mov    eax, uMsg                // pickup our message\r
+               .IF (eax == WM_PAINT)\r
+                 mov    eax, 0                 // Non-sense... (placeholder!)\r
+// Scan conversion etc. goes here...\r
+               .ELSEIF (eax == WM_LBUTTONDOWN)\r
+                 invoke SetCapture, hCharWnd\r
+               .ELSEIF (eax == WM_LBUTTONUP)\r
+                 invoke ReleaseCapture\r
+                 invoke SetFocus, hMainWnd     // Make sure the main wnd keeps focus!\r
+               .ELSEIF (eax == WM_NCLBUTTONDOWN)\r
+                 invoke DefWindowProc, hWnd, uMsg, wParam, lParam // Let it do its thing\r
+                 invoke SetFocus, hMainWnd     // Make sure the main wnd keeps focus!\r
+               .ELSE\r
+DefProc:         invoke DefWindowProc, hWnd, uMsg, wParam, lParam\r
+               .ENDIF\r
+               ret\r
+\r
+WndProcCW      ENDP\r
+\r
+//\r
+// Character Window WndProc\r
+//\r
+LRESULT CALLBACK WndProcCW(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)\r
+{\r
+       switch (msgID)\r
+       {\r
+       default:\r
+               return DefWindowProc(hWnd, msgID, wParam, lParam);\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+// Function prototypes\r
+\r
+int32 FindSelectedTool(void);\r
+\r
+//\r
+// Tool Palette WndProc\r
+//\r
+LRESULT CALLBACK WndProcTP(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)\r
+{\r
+       PAINTSTRUCT ps;\r
+       HDC hdc;\r
+       POINT pt;\r
+       static uint32 prevTool = -1;\r
+\r
+       switch (msgID)\r
+       {\r
+       case WM_PAINT:\r
+       {\r
+               hdc = BeginPaint(hWnd, &ps);\r
+               HDC newDC = CreateCompatibleDC(NULL);\r
+               SelectObject(newDC, hBMToolPal1);\r
+               BitBlt(hdc, 0, 0, sizeTPBM.x, sizeTPBM.y, newDC, 0, 0, SRCCOPY);\r
+               DeleteDC(newDC);\r
+\r
+// This is crappy. Find some way to tighten this up!\r
+               int32 tool = FindSelectedTool();\r
+\r
+               if (tool != -1)\r
+               {\r
+                       newDC = CreateCompatibleDC(NULL);\r
+                       SelectObject(newDC, hBMToolPal1);\r
+                   //need ul corner of bitmap, ul corner of dest, width/height\r
+                       pt.x = sizeStamp.x * (tool & 0x03), pt.y = sizeStamp.y * (tool >> 2);\r
+                       BitBlt(hdc, pt.x, pt.y, sizeStamp.x, sizeStamp.y, newDC, pt.x, pt.y, NOTSRCCOPY);\r
+                       DeleteDC(newDC);\r
+               }\r
+\r
+               EndPaint(hWnd, &ps);\r
+               break;\r
+       }\r
+       case WM_MOUSEMOVE:\r
+       {\r
+               int32 tool = FindSelectedTool();\r
+\r
+               if (tool != prevTool)\r
+               {\r
+                       prevTool = tool;\r
+                       InvalidateRect(hWnd, NULL, FALSE);\r
+               }\r
+\r
+               break;\r
+       }\r
+       case WM_RBUTTONUP:\r
+       {\r
+               int32 tool = FindSelectedTool(), oldTool = currentTool;\r
+\r
+               if (tool != -1)\r
+                       currentTool = tool;\r
+\r
+               if (currentTool != TOOLSelect && currentTool != TOOLDelPt && currentTool != TOOLAddPt\r
+                       && currentTool != TOOLPolySelect)\r
+                       ptHighlight = -1;\r
+\r
+               if (currentTool != oldTool)\r
+                       InvalidateRect(hMainWnd, NULL, TRUE);\r
+\r
+               if (currentTool == TOOLAddPoly)\r
+#ifdef DEBUGFOO\r
+{\r
+#endif\r
+                       polyFirstPoint = true;\r
+#ifdef DEBUGFOO\r
+wsprintf(strBuf, "--> Selected poly tool, polyFirstPoint is %s\n", polyFirstPoint ? "true" : "false");\r
+WriteLogMsg(strBuf);\r
+}\r
+#endif\r
+\r
+               ReleaseCapture();\r
+               ShowWindow(hToolPalWnd, SW_HIDE);\r
+               SetFocus(hMainWnd);                                             // Make sure the main wnd keeps focus!\r
+\r
+               break;\r
+       }\r
+       default:\r
+               return DefWindowProc(hWnd, msgID, wParam, lParam);\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+//\r
+// Find which tool we're pointing at\r
+// Use: xcoord = mouse.x / (bmsize.x/4), ycoord = mouse.y / (bmsize.y/2)\r
+//\r
+int32 FindSelectedTool(void)\r
+{\r
+       POINT pt;\r
+               \r
+       GetCursorPos(&pt);\r
+       ScreenToClient(hToolPalWnd, &pt);\r
+\r
+       uint32 x = (uint32)pt.x / sizeStamp.x, y = (uint32)pt.y / sizeStamp.y, tool = -1;\r
+\r
+       if (x < 4 && y < 2)\r
+//     {\r
+               tool = (y * 4) + x;\r
+\r
+//             if (tool == 7)\r
+//                     tool = -1;                                                      // 7 has no tool...\r
+//     }\r
+\r
+       return tool;\r
+}\r
+\r
+\r
+//\r
+// Misc center window\r
+//\r
+void MiscCenterWnd(HWND hChild, HWND hParent)\r
+{\r
+       RECT parent, child;\r
+\r
+       if (!GetWindowRect(hParent, &parent) || !GetWindowRect(hChild, &child))\r
+               return;\r
+\r
+       int32 x = parent.left + (((parent.right - parent.left) - (child.right - child.left)) / 2),\r
+               y = parent.top + (((parent.bottom - parent.top) - (child.bottom - child.top)) / 2);\r
+\r
+       if (x < 0)\r
+               x = 0;\r
+       else if (x > GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left))\r
+               x = GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left);\r
+\r
+       if (y < 0)\r
+               y = 0;\r
+       else if (y > GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top))\r
+               y = GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top);\r
+\r
+       SetWindowPos(hChild, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);\r
+}\r
+\r
+//\r
+// Allow only one instance\r
+//\r
+bool OnlyOneInstance(void)\r
+{\r
+       HWND window = FindWindow(className, NULL);\r
+\r
+       if (window == NULL)\r
+               return true;\r
+\r
+       ShowWindow(window, SW_SHOWNORMAL);\r
+       SetWindowPos(window, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);\r
+\r
+       return false;\r
+}\r
+\r
+//\r
+// Load/Allocate all resources\r
+//\r
+bool LoadResources(void)\r
+{\r
+       hCur[0] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR1));\r
+       hCur[1] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR2));\r
+       hCur[2] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR3));\r
+       hCur[3] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR4));\r
+       hCur[4] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR5));\r
+       hCur[5] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR6));\r
+       hCur[6] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR7));\r
+       hCur[7] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR8));\r
+\r
+       BITMAP bm;\r
+\r
+       hBMToolPal1 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_TOOLPAL1));\r
+       GetObject(hBMToolPal1, sizeof(bm), &bm);\r
+\r
+       // Set up sizes\r
+\r
+       sizeTPBM.x = bm.bmWidth, sizeTPBM.y = bm.bmHeight;\r
+       sizeStamp.x = bm.bmWidth / 4, sizeStamp.y = bm.bmHeight / 2;\r
+\r
+       hBluePen1 = CreatePen(PS_DOT, 1, 0x00FF0000);\r
+       hRedPen1 = CreatePen(PS_SOLID, 1, 0x000000FF);\r
+       hGreenPen1 = CreatePen(PS_SOLID, 1, 0x0000AF00);\r
+       hBlackPen1 = CreatePen(PS_SOLID, 1, 0x00000000);\r
+\r
+       LOGBRUSH lb = { BS_NULL, 0, 0 };\r
+\r
+       hNullBrush = CreateBrushIndirect(&lb);\r
+\r
+       return true;\r
+}\r
+\r
+//\r
+// Deallocate all resources\r
+//\r
+void DeallocateResources(void)\r
+{\r
+       DeleteObject(hBMToolPal1);\r
+       DeleteObject(hBluePen1);\r
+       DeleteObject(hRedPen1);\r
+       DeleteObject(hGreenPen1);\r
+       DeleteObject(hBlackPen1);\r
+       DeleteObject(hNullBrush);\r
+}\r
+\r
+//\r
+// Save all application specific data, so we can pick up where we last left off...\r
+//\r
+void SaveAppState(void)\r
+{\r
+       SetINIInt("Main", "flags", wpM.flags);\r
+       SetINIInt("Main", "showCmd", wpM.showCmd);\r
+       SetINIInt("Main", "x1", wpM.rcNormalPosition.left);\r
+       SetINIInt("Main", "y1", wpM.rcNormalPosition.top);\r
+       SetINIInt("Main", "x2", wpM.rcNormalPosition.right);\r
+       SetINIInt("Main", "y2", wpM.rcNormalPosition.bottom);\r
+\r
+       SetINIInt("Main", "vpx", ptVPM.x);\r
+       SetINIInt("Main", "vpy", ptVPM.y);\r
+\r
+       SetINIInt("Char", "flags", wpC.flags);\r
+       SetINIInt("Char", "showCmd", wpC.showCmd);\r
+       SetINIInt("Char", "x1", wpC.rcNormalPosition.left);\r
+       SetINIInt("Char", "y1", wpC.rcNormalPosition.top);\r
+       SetINIInt("Char", "x2", wpC.rcNormalPosition.right);\r
+       SetINIInt("Char", "y2", wpC.rcNormalPosition.bottom);\r
+\r
+       // Need to write out currently opened font, character looking at, other misc. crap\r
+//     SetINIString("Main", "currentFile", pDoc->GetPathName());\r
+//     SetINIInt("Main", "currentChar", pDoc->character_num);\r
+}\r
+\r
+//\r
+// Restore all application specific data previously saved\r
+//\r
+bool RestoreAppState(void)\r
+{\r
+       InitINIFile();\r
+\r
+       WINDOWPLACEMENT wp;\r
+       wp.length = sizeof(WINDOWPLACEMENT);\r
+       GetWindowPlacement(hMainWnd, &wp);\r
+\r
+       wp.flags = GetINIInt("Main", "flags", wp.flags);\r
+       wp.showCmd = GetINIInt("Main", "showCmd", wp.showCmd);\r
+       wp.rcNormalPosition.left = GetINIInt("Main", "x1", wp.rcNormalPosition.left);\r
+       wp.rcNormalPosition.top = GetINIInt("Main", "y1", wp.rcNormalPosition.top);\r
+       wp.rcNormalPosition.right = GetINIInt("Main", "x2", wp.rcNormalPosition.right);\r
+       wp.rcNormalPosition.bottom = GetINIInt("Main", "y2", wp.rcNormalPosition.bottom);\r
+\r
+       SetWindowPlacement(hMainWnd, &wp);\r
+\r
+       HDC hdc;\r
+       POINT pt;\r
+       hdc = GetDC(hMainWnd);\r
+       GetViewportOrgEx(hdc, &pt);\r
+\r
+       pt.x = GetINIInt("Main", "vpx", pt.x);\r
+       pt.y = GetINIInt("Main", "vpy", pt.y);\r
+\r
+       SetViewportOrgEx(hdc, pt.x, pt.y, NULL);\r
+       ReleaseDC(hMainWnd, hdc);\r
+\r
+       GetWindowPlacement(hCharWnd, &wp);\r
+\r
+       wp.flags = GetINIInt("Char", "flags", wp.flags);\r
+       wp.showCmd = GetINIInt("Char", "showCmd", wp.showCmd);\r
+       wp.rcNormalPosition.left = GetINIInt("Char", "x1", wp.rcNormalPosition.left);\r
+       wp.rcNormalPosition.top = GetINIInt("Char", "y1", wp.rcNormalPosition.top);\r
+       wp.rcNormalPosition.right = GetINIInt("Char", "x2", wp.rcNormalPosition.right);\r
+       wp.rcNormalPosition.bottom = GetINIInt("Char", "y2", wp.rcNormalPosition.bottom);\r
+\r
+       SetWindowPlacement(hCharWnd, &wp);\r
+\r
+       if (wp.showCmd == SW_HIDE)\r
+               SendMessage(hToolBar, TB_SETSTATE, ID_TBCHARWIN, MAKELONG(TBSTATE_ENABLED, 0));\r
+\r
+//  CString lastFile = theApplicationObject.GetProfileString(version, "currentFile", "");\r
+//  int lastChar = theApplicationObject.GetProfileInt(version, "currentChar", 0);\r
+//  if (lastFile.GetLength())\r
+//  {\r
+//    // Attempt to restore the last session by open the last file used, etc...\r
+//    if (!pDoc->m_myFont.Load(lastFile))\r
+//    {\r
+//      // Err, make sure you can support any allegations you make below, buddy!\r
+//      AfxMessageBox("The last file opened with TTF Edit\n\rseems to have been moved or deleted.");\r
+//    }\r
+//    else\r
+//    {\r
+//      pDoc->m_myFont.SetGlyph(lastChar);  // Set TTF object to last used char\r
+//      pDoc->character_num = lastChar;\r
+//      pDoc->SetPathName(lastFile);\r
+//\r
+//      BYTE name[512];\r
+//      pDoc->m_myFont.GetCharName(lastChar, name);\r
+//      m_wndOwned.SetWindowText((char *)name);\r
+//    }\r
+//  }\r
+\r
+       return true;\r
+}\r
+\r
+//\r
+// Initialization\r
+//\r
+bool Initialization(void)\r
+{\r
+       WNDCLASSEX wcex;\r
+\r
+       if (!LoadResources())\r
+               return false;\r
+\r
+       RtlFillMemory(&wcex, sizeof(WNDCLASSEX), 0);\r
+       wcex.cbSize = sizeof(WNDCLASSEX);\r
+       wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;\r
+       wcex.lpfnWndProc = WndProc;\r
+       wcex.hInstance = hInst;\r
+       wcex.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON));\r
+       wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);\r
+       wcex.lpszMenuName = MAKEINTRESOURCE(IDM_MENU);\r
+       wcex.lpszClassName = className;\r
+       wcex.hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, NULL);\r
+\r
+       if (!RegisterClassEx(&wcex))\r
+               return false;\r
+\r
+       hMainWnd = CreateWindowEx(NULL, className, className, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,\r
+               0, 0, 0x1A0, 0x180, NULL, NULL, hInst, NULL);\r
+\r
+       if (!hMainWnd)\r
+               return false;\r
+\r
+       ShowWindow(hMainWnd, nCmdShow);\r
+       UpdateWindow(hMainWnd);\r
+\r
+       // Character window creation\r
+\r
+       wcex.lpfnWndProc = WndProcCW;\r
+       wcex.lpszMenuName = NULL;\r
+       wcex.lpszClassName = CNCharWin;\r
+       wcex.hCursor = LoadCursor(NULL, IDC_ARROW);     // Owned windows have "regular" cursors\r
+\r
+       if (!RegisterClassEx(&wcex))\r
+               return false;\r
+\r
+       hCharWnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW, CNCharWin,\r
+               curCharName, WS_POPUP | WS_CAPTION | WS_VISIBLE | WS_THICKFRAME,\r
+               100, 100, 120, 120, hMainWnd, NULL, hInst, NULL);\r
+\r
+       if (!hCharWnd)\r
+               return false;\r
+\r
+       ShowWindow(hCharWnd, SW_SHOWNORMAL);\r
+       UpdateWindow(hCharWnd);\r
+       SetFocus(hMainWnd);                                                     // Make sure main wnd has focus!\r
+\r
+       // Tool palette window creation\r
+\r
+       wcex.lpfnWndProc = WndProcTP;\r
+       wcex.lpszClassName = CNToolPal;\r
+\r
+       if (!RegisterClassEx(&wcex))\r
+               return false;\r
+\r
+       hToolPalWnd = CreateWindowEx(WS_EX_WINDOWEDGE, CNToolPal, NULL, WS_POPUP,\r
+               0, 0, sizeTPBM.x, sizeTPBM.y, hMainWnd, NULL, hInst, NULL);\r
+\r
+       if (!hToolPalWnd)\r
+               return false;\r
+\r
+// Note: A better way to handle this would be to have a sub that registers ALL\r
+//       classes beforehand and passes a TRUE/FALSE back depending on whether or not\r
+//       all the classes were able to be registered or not, THEN create the windows\r
+//       and controls...\r
+\r
+       RestoreAppState();                                                      // Restore app related stuff\r
+\r
+       return true;\r
+}\r
+\r
+*/\r
+\r
diff --git a/src/ttedit.h b/src/ttedit.h
new file mode 100755 (executable)
index 0000000..de526f8
--- /dev/null
@@ -0,0 +1,181 @@
+//\r
+// TTEDIT.H: Header file\r
+//\r
+// by James L. Hammons\r
+// (C) 2005 Underground Software\r
+//\r
+\r
+#ifndef __TTEDIT_H__\r
+#define __TTEDIT_H__\r
+\r
+#include <wx/wx.h>                                                             // So that whoever uses this can without having\r
+                                                                                               // to pull in a bunch of references manually\r
+#include "ttf.h"\r
+\r
+// Forward declarations\r
+\r
+class TTEditFrame;\r
+class TTEditWindow;\r
+class CharWindow;\r
+class ToolWindow;\r
+\r
+//\r
+// Class representing the entire Application\r
+//\r
+class TTEditApp: public wxApp\r
+{\r
+       public:\r
+               TTEditFrame * mainFrame;\r
+               CharWindow * charWin;\r
+               ToolWindow * toolPalette;\r
+               TTF font;\r
+\r
+               bool OnInit();\r
+               int OnExit();\r
+};\r
+\r
+DECLARE_APP(TTEditApp)\r
+\r
+class TTEditFrame: public wxFrame\r
+{\r
+       private:\r
+       protected:\r
+       public:\r
+               TTEditApp & app;                                                // Reference to the application object\r
+               // Subwindows for reference within the program.\r
+               TTEditWindow * mainWindow;\r
+               wxMenuBar * menuBar;\r
+\r
+               // Constructor and destructor\r
+               TTEditFrame(wxFrame * parent, const wxString &title, const wxPoint &pos, const wxSize &size, long style);\r
+               ~TTEditFrame(void);\r
+\r
+               void OnCloseWindow(wxCloseEvent &e);\r
+\r
+               void OnOpen(wxCommandEvent &e);\r
+               void OnExit(wxCommandEvent &e);\r
+               void OnAbout(wxCommandEvent &e);\r
+//             void OnEasy(wxCommandEvent &event);\r
+///            void OnMedium(wxCommandEvent &event);\r
+//             void OnDifficult(wxCommandEvent &event);\r
+\r
+       DECLARE_EVENT_TABLE()\r
+};\r
+\r
+class TTEditWindow: public wxWindow\r
+{\r
+       private:\r
+               TTEditApp & app;                                                // Reference to the application object\r
+               double scale;                                                   // Window scaling factor\r
+               int32 offsetX, offsetY;                                 // Window offsets\r
+\r
+       protected:\r
+       public:\r
+//             int field_width, field_height;\r
+//             int x_cell, y_cell;\r
+               wxBitmap * bmp;\r
+               wxPoint pt, ptOffset, ptPrevious;\r
+\r
+               // Constructor and destructor\r
+               TTEditWindow(wxFrame * parent, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = 0);\r
+               ~TTEditWindow(void);\r
+\r
+               void OnPaint(wxPaintEvent &e);\r
+               void OnMouseEvent(wxMouseEvent &e);\r
+//             void DrawField(wxDC *, int xc1, int yc1, int xc2, int yc2);\r
+//             void Refresh(int xc1, int yc1, int xc2, int yc2);\r
+//             void Uncover(int x, int y);\r
+//             void UpdateFieldSize();\r
+\r
+       protected:\r
+               wxPoint GetAdjustedMousePosition(wxMouseEvent &e);\r
+               wxPoint GetAdjustedClientPosition(wxCoord x, wxCoord y);\r
+\r
+       DECLARE_EVENT_TABLE()\r
+};\r
+\r
+class CharWindow: public wxWindow\r
+{\r
+       private:\r
+       protected:\r
+       public:\r
+//             int field_width, field_height;\r
+//             int x_cell, y_cell;\r
+               wxBitmap * bmp;\r
+\r
+               // Constructor and destructor\r
+               CharWindow(wxFrame * parent, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = 0);\r
+               ~CharWindow(void);\r
+\r
+               void OnPaint(wxPaintEvent &e);\r
+               void OnMouseEvent(wxMouseEvent &e);\r
+//             void DrawField(wxDC *, int xc1, int yc1, int xc2, int yc2);\r
+//             void Refresh(int xc1, int yc1, int xc2, int yc2);\r
+//             void Uncover(int x, int y);\r
+//             void UpdateFieldSize();\r
+\r
+       DECLARE_EVENT_TABLE()\r
+};\r
+\r
+class ToolWindow: public wxFrame\r
+//class ToolWindow: public wxWindow\r
+{\r
+       private:\r
+       protected:\r
+       public:\r
+               wxBitmap * bmp;\r
+               wxPoint sizeStamp, sizeTPBM;\r
+               int prevTool;\r
+\r
+               // Constructor and destructor\r
+               ToolWindow(wxFrame * parent, const wxString &title, const wxPoint &pos, const wxSize &size, long style);\r
+//             ToolFrame(wxFrame * parent, const wxString &title, const wxPoint &pos, const wxSize &size, long style);\r
+//             ToolWindow(wxFrame * parent, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = 0);\r
+               ~ToolWindow(void);\r
+\r
+               void OnPaint(wxPaintEvent &e);\r
+               void OnMouseEvent(wxMouseEvent &e);\r
+//             void DrawField(wxDC *, int xc1, int yc1, int xc2, int yc2);\r
+//             void Refresh(int xc1, int yc1, int xc2, int yc2);\r
+//             void Uncover(int x, int y);\r
+//             void UpdateFieldSize();\r
+               int32 FindSelectedTool(void);\r
+\r
+       DECLARE_EVENT_TABLE()\r
+};\r
+\r
+// Resource/control IDs\r
+/*\r
+#define        IDI_ICON                        0x01L           // IDs same as in ttedit.asm\r
+#define        IDM_MENU                        0x02L\r
+#define        IDA_ACCEL                       0x03L\r
+#define        IDD_ABOUT                       0x04L\r
+#define IDR_TOOLBAR1           0x05L\r
+#define IDB_TOOLBAR1           0x06L\r
+#define IDB_TOOLPAL1           0x07L\r
+#define IDC_CURSOR1                    0x08L\r
+#define IDC_CURSOR2                    0x09L\r
+#define IDC_CURSOR3                    0x0AL\r
+#define IDC_CURSOR4                    0x0BL\r
+#define IDC_CURSOR5                    0x0CL\r
+#define IDC_CURSOR6                    0x0DL\r
+#define IDC_CURSOR7                    0x0EL\r
+#define IDC_CURSOR8                    0x0FL\r
+\r
+#define        IDS_SYSMENU                     0x010L\r
+#define        IDM_FILEMENU            0x011L\r
+#define        IDM_HELPMENU            0x012L\r
+\r
+#define        IDM_NEW                         0x020L\r
+#define        IDM_OPEN                        0x021L\r
+#define        IDM_SAVE                        0x022L\r
+#define        IDM_SAVEAS                      0x023L\r
+#define        IDM_EXIT                        0x024L\r
+#define        IDM_HELPTOPICS          0x025L\r
+#define        IDM_ABOUT                       0x026L\r
+\r
+#define        ID_TBLEFT                       0x030L\r
+#define        ID_TBRIGHT                      0x031L\r
+#define        ID_TBCHARWIN            0x032L */\r
+\r
+#endif // __TTEDIT_H__\r
diff --git a/src/ttf.cpp b/src/ttf.cpp
new file mode 100755 (executable)
index 0000000..1244687
--- /dev/null
@@ -0,0 +1,1212 @@
+//\r
+// TTF.CPP - The TrueType class\r
+// by James L. Hammons\r
+// (C) 2005 Underground Software\r
+//\r
+// This class encapsulates all the complexity of a TrueType Font File\r
+// database.  Included are functions to load, save, & initialize the\r
+// TTF database, move, add, & delete points & glyphs, i.e. manipulate\r
+// a TTF file in just about any way imaginable!\r
+//\r
+// JLH = James L. Hammons <jlhamm@acm.org>\r
+//\r
+// Who  When        What\r
+// ---  ----------  -------------------------------------------------------------\r
+// JLH  ??/??/199?  Created this file\r
+//\r
+//\r
+// STILL TO BE DONE:\r
+//\r
+// - Eliminate ALL references to BYTE, WORD, SBYTE, SWORD, etc.\r
+//\r
+\r
+#include <stdio.h>                                                             // For file handling, etc.                                                                                              //\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include "charnames.h"\r
+#include "ttf.h"\r
+\r
+#define TTFDEBUG\r
+\r
+#ifdef TTFDEBUG\r
+#include "debug.h"\r
+#endif\r
+\r
+#define NUMTABS  24                   // Number of distinct tables\r
+\r
+\r
+/*void fskip(HANDLE file, uint32 bytesToSkip)\r
+{\r
+       SetFilePointer(file, (LONG)bytesToSkip, NULL, FILE_CURRENT);\r
+}*/\r
+\r
+//\r
+// Get a BYTE from the current file...\r
+//\r
+uint8 ReadByte(FILE * file)\r
+{\r
+       return (uint8)fgetc(file);\r
+}\r
+\r
+// The following routines get and put WORDs and DWORDs in little endian\r
+// format, so they should work no matter what endianess the platform that\r
+// holds the TTF object.\r
+\r
+//\r
+// Get a WORD from the current file...\r
+//\r
+uint16 ReadWord(FILE * file)\r
+{\r
+       uint16 word = (uint16)fgetc(file) << 8;\r
+       word |= (uint16)fgetc(file);\r
+\r
+       return word;\r
+}\r
+\r
+//\r
+// Get a double WORD from the current file...\r
+//\r
+uint32 ReadDWord(FILE * file)\r
+{\r
+       uint32 dword = 0;\r
+\r
+       for(int i=0; i<4; i++)\r
+       {\r
+               dword <<= 8;\r
+               dword |= (uint8)fgetc(file);\r
+       }\r
+\r
+       return dword;\r
+}\r
+\r
+//\r
+// Write a WORD to the current file...\r
+//\r
+void WriteWord(FILE * file, uint16 word)\r
+{\r
+       fputc(word >> 8, file);                                         // Hi byte\r
+       fputc(word & 0xFF, file);                                       // Lo byte\r
+}\r
+\r
+//\r
+// Write a double WORD to the current file...\r
+//\r
+void WriteDWord(FILE * file, uint32 dword)\r
+{\r
+       for(int i=0; i<4; i++)\r
+       {\r
+               fputc((char)(dword >> 24), file);\r
+               dword <<= 8;\r
+       }\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Table extraction helper routines (inline 'em?)\r
+////////////////////////////////////////////////////////////////////////////\r
+\r
+//\r
+// Return a BYTE from a BYTE based table\r
+//\r
+uint8 GetByte(uint8 * table, uint32 &ptr)\r
+{\r
+       return table[ptr++];\r
+}\r
+\r
+//\r
+// Return a WORD from a BYTE based table\r
+//\r
+uint16 GetWord(uint8 * table, uint32 &ptr)\r
+{\r
+       uint16 hi = table[ptr++];\r
+       uint16 lo = table[ptr++];\r
+\r
+       return (uint16)((hi<<8) | lo);\r
+}\r
+\r
+//\r
+// Return a double WORD from a BYTE based table\r
+//\r
+uint32 GetDWord(uint8 * table, uint32 &ptr)\r
+{\r
+       uint32 hi1 = table[ptr++];\r
+       uint32 lo1 = table[ptr++];\r
+       uint32 hi2 = table[ptr++];\r
+       uint32 lo2 = table[ptr++];\r
+\r
+       return (uint32)((hi1 << 24) | (lo1 << 16) | (hi2 << 8) | lo2);\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Table storage helper routines (inline 'em?)\r
+////////////////////////////////////////////////////////////////////////////\r
+\r
+//\r
+// Store a BYTE in a BYTE based table\r
+//\r
+void SetByte(uint8 * table, uint32 &ptr, uint8 data)\r
+{\r
+       table[ptr++] = data;\r
+}\r
+\r
+//\r
+// Store a WORD in a BYTE based table\r
+//\r
+void SetWord(uint8 * table, uint32 &ptr, uint16 data)\r
+{\r
+       table[ptr++] = data>>8;  table[ptr++] = data&0xFF;\r
+}\r
+\r
+//\r
+// Store a DWORD in a BYTE based table\r
+//\r
+void SetDWord(uint8 * table, uint32 &ptr, uint32 data)\r
+{\r
+       table[ptr++] = (uint8)(data >> 24); table[ptr++] = (uint8)(data >> 16);\r
+       table[ptr++] = (uint8)(data >> 8);  table[ptr++] = (uint8)(data & 0xFF);\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Fixed point to float (& vice versa) conversions\r
+/////////////////////////////////////////////////////////////////////////////\r
+float FixedToFloat(int16 fixed)\r
+{\r
+       return (float)fixed / 16384.0f;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// TTF Constructor\r
+/////////////////////////////////////////////////////////////////////////////\r
+TTF::TTF(void)\r
+{\r
+       loaded = false;                                                         // Set font initializer\r
+       isDirty = false;                                                        // Glyphs are clean\r
+       numberOfPolys = 0;                                                      // Set reasonable values\r
+       isCompositeGlyph = false;                                       // No composite glyph (yet)\r
+\r
+       parray[0] = &EBDT;  parray[1] = &EBLC;  parray[2] = &EBSC; // Init pointer\r
+       parray[3] = &LTSH;  parray[4] = &OS_2;  parray[5] = &PCLT; // array...\r
+       parray[6] = &VDMX;  parray[7] = &cmap;  parray[8] = &cvt; \r
+       parray[9] = &fpgm;  parray[10] = &gasp; parray[11] = &glyf;\r
+       parray[12] = &hdmx; parray[13] = &head; parray[14] = &hhea;\r
+       parray[15] = &hmtx; parray[16] = &kern; parray[17] = &loca;\r
+       parray[18] = &maxp; parray[19] = &name; parray[20] = &post;\r
+       parray[21] = &prep; parray[22] = &vhea; parray[23] = &vmtx;\r
+\r
+       larray[0] = &EBDT_len;  larray[1] = &EBLC_len;  larray[2] = &EBSC_len;\r
+       larray[3] = &LTSH_len;  larray[4] = &OS_2_len;  larray[5] = &PCLT_len;\r
+       larray[6] = &VDMX_len;  larray[7] = &cmap_len;  larray[8] = &cvt_len;\r
+       larray[9] = &fpgm_len;  larray[10] = &gasp_len; larray[11] = &glyf_len;\r
+       larray[12] = &hdmx_len; larray[13] = &head_len; larray[14] = &hhea_len;\r
+       larray[15] = &hmtx_len; larray[16] = &kern_len; larray[17] = &loca_len;\r
+       larray[18] = &maxp_len; larray[19] = &name_len; larray[20] = &post_len;\r
+       larray[21] = &prep_len; larray[22] = &vhea_len; larray[23] = &vmtx_len;\r
+\r
+       for(uint32 i=0; i<NUMTABS; i++)\r
+               *parray[i] = NULL;                                              // Init pointers...\r
+\r
+       for(uint32 i=0; i<MAXGLYPHS; i++)\r
+               glyph[i] = NULL;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// TTF Destructor\r
+/////////////////////////////////////////////////////////////////////////////\r
+TTF::~TTF()\r
+{\r
+       ClearTables();                                                          // This should handle deallocation correctly...\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: void Init(void)\r
+//\r
+// This function initializes the TTF object, setting reasonable values for\r
+// the various internal variables used by the object.\r
+// [distinct from New?]\r
+/////////////////////////////////////////////////////////////////////////////\r
+void TTF::Init(void)\r
+{\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Clear the tables so that file can be reloaded\r
+/////////////////////////////////////////////////////////////////////////////\r
+void TTF::ClearTables(void)\r
+{\r
+       for(uint32 i=0; i<NUMTABS; i++)\r
+       {\r
+               if ((*parray[i]) != NULL)\r
+               {\r
+                       free(*parray[i]);\r
+                       *parray[i] = NULL;\r
+                       *larray[i] = 0;\r
+               }\r
+       }  \r
+\r
+       for(uint32 i=0; i<MAXGLYPHS; i++)\r
+       {\r
+               if (glyph[i] != NULL)\r
+               {\r
+                       free(glyph[i]);\r
+                       glyph[i] = NULL;\r
+               }\r
+       }\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL Load(const char * filename)\r
+//\r
+// This loads the TTF database from an external file.  Returns 'true' if\r
+// successful.\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::Load(const char * filename)\r
+{\r
+//     unsigned char ch;                                                       // Temp variable\r
+//     UINT num_tabs;                                                          // Number of tables\r
+       uint32 offset[NUMTABS], length[NUMTABS];        // Temporary storage...\r
+       char names[NUMTABS][5];\r
+       char narray[NUMTABS][5] = { "EBDT", "EBLC", "EBSC", "LTSH", "OS/2", "PCLT",\r
+               "VDMX", "cmap", "cvt ", "fpgm", "gasp", "glyf", "hdmx", "head", "hhea",\r
+               "hmtx", "kern", "loca", "maxp", "name", "post", "prep", "vhea", "vmtx" };\r
+\r
+       //loaded = false;\r
+//     file.open(filename, ios::binary|ios::in);       // Open the file\r
+       FILE * file = fopen(filename, "rb");\r
+\r
+       if (file == NULL)\r
+#ifdef TTFDEBUG\r
+{\r
+WriteLogMsg("Failed to open file!\n");\r
+#endif\r
+               return false;\r
+#ifdef TTFDEBUG\r
+}\r
+#endif\r
+\r
+       if (ReadDWord(file) != 0x00010000)\r
+#ifdef TTFDEBUG\r
+{\r
+WriteLogMsg("File was NOT a TTF file!\n");\r
+#endif\r
+               return false;                                                   // Not a TTF file...\r
+#ifdef TTFDEBUG\r
+}\r
+#endif\r
+\r
+       uint32 num_tabs = ReadWord(file);                       // Get # of tables\r
+#ifdef TTFDEBUG\r
+WriteLogMsg("Number of tables is %u...\n", num_tabs);\r
+#endif\r
+//     fskip(file, 6);                                                         // Skip this shiat...\r
+       fseek(file, 6, SEEK_CUR);\r
+\r
+#ifdef TTFDEBUG\r
+WriteLogMsg("Reading names of tables...\n");\r
+#endif\r
+       for(uint32 i=0; i<num_tabs; i++)\r
+       {\r
+//             ReadFile(file, names[i], 4, &bytesRead, NULL);\r
+               fread(names[i], 1, 4, file);\r
+               names[i][4] = 0;\r
+//             fskip(file, 4);                                                 // Checksum\r
+               fseek(file, 4, SEEK_CUR);                               // Checksum\r
+               offset[i] = ReadDWord(file);                    // Offset from start of file\r
+               length[i] = ReadDWord(file);                    // Length of table\r
+       }\r
+\r
+#ifdef TTFDEBUG\r
+WriteLogMsg("Reading tables...\n");\r
+#endif\r
+       for(uint32 i=0; i<num_tabs; i++)\r
+       {\r
+               for(uint32 j=0; j<NUMTABS; j++)\r
+               {\r
+                       if ((strcmp(names[i], narray[j])) == 0) // Found a match...\r
+                       {\r
+//                             *parray[j] = (uint8 *)GlobalAlloc(GMEM_FIXED, length[i]);       // Allocate space\r
+                               *parray[j] = (uint8 *)malloc(length[i]); // Alloc space\r
+\r
+                               if (*parray[j] == NULL)\r
+                                       return false;                           // Bail out if nothing allocated\r
+\r
+                               *larray[j] = length[i];                 // Set its length...\r
+//                             SetFilePointer(file, (LONG)offset[i], NULL, FILE_BEGIN);\r
+//                             ReadFile(file, *parray[j], length[i], &bytesRead, NULL);\r
+                               fseek(file, offset[i], SEEK_SET);\r
+                               fread(*parray[j], 1, length[i], file);\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+\r
+       fclose(file);\r
+\r
+// This shouldn't be necessary, since it's irrelevant (loaded flag)\r
+//    loaded = true;                       // Set 'loaded' flag...\r
+    isDirty = false;                     // Glyphs are clean\r
+    ExtractTables();                     // Move table data to my structs\r
+                                         // & ignore return val\r
+                                         // (should handle errors here)\r
+       return true;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL Save(const char * filename)\r
+//\r
+// Save the TT font currently in the object\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::Save(const char * filename)\r
+{\r
+//  fstream file;\r
+//     ULONG offset = 12;\r
+       uint32 numtabs = 0;\r
+       char padding[3] = { 0, 0, 0 };\r
+       // Convert this to a table of ULONGs to decrease complexity...\r
+//wouldn't be endian safe then...\r
+       char narray[NUMTABS][5] = { "EBDT", "EBLC", "EBSC", "LTSH", "OS/2", "PCLT",\r
+               "VDMX", "cmap", "cvt ", "fpgm", "gasp", "glyf", "hdmx", "head", "hhea",\r
+               "hmtx", "kern", "loca", "maxp", "name", "post", "prep", "vhea", "vmtx" };\r
+\r
+       if (isDirty)\r
+               EncodeGlyph(currentGlyph);\r
+\r
+       BuildTables();                                                          // Ignore return value...  \r
+\r
+       for(uint32 i=0; i<NUMTABS; i++)                         // Figure out how many tables there are\r
+               if ((*parray[i]) != NULL)\r
+                       numtabs++;\r
+\r
+       uint32 offset = 12 + (numtabs * 16);            // Calc correct offset to start of data\r
+\r
+//     HANDLE file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+//             NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);\r
+       FILE * file = fopen(filename, "wb");\r
+\r
+       WriteDWord(file, 0x00010000);                           // Write header...\r
+       WriteWord(file, numtabs);\r
+       WriteWord(file, 0);                                                     // SearchRange (Max power of 2 <= numTables) x 16.\r
+       WriteWord(file, 0);                                                     // entrySelector Log2(max power of 2 <= numTables).\r
+       WriteWord(file, 0);                                                     // NumTables x 16 - searchRange.\r
+\r
+       for(uint32 i=0; i<NUMTABS; i++)                                 // Write out table directory...\r
+       {\r
+               if ((*parray[i]) != NULL)\r
+               {\r
+//                     for(int j=0; j<4; j++)\r
+//                             file.put(narray[i][j]);                 // Name\r
+//                     WriteFile(file, narray[i], 4, &bytesWritten, NULL);\r
+                       fwrite(narray[i], 1, 4, file);          // Name\r
+\r
+                       WriteDWord(file, 0);                            // Checksum\r
+                       WriteDWord(file, offset);                       // Offset\r
+                       WriteDWord(file, (*larray[i]));         // Length\r
+\r
+                       offset += (((*larray[i]) + 3) & ~3);    // Pad out to 4-uint8 boundary...\r
+               }\r
+       }\r
+\r
+       for(uint32 i=0; i<NUMTABS; i++)                                 // Write out the tables...\r
+       {\r
+               if ((*parray[i]) != NULL)\r
+               {\r
+//                     for(uint32 j=0; j<(*larray[i]); j++)\r
+//                             file.put((*parray[i])[j]);\r
+//                     WriteFile(file, *parray[i], *larray[i], &bytesWritten, NULL);\r
+                       fwrite(*parray[i], 1, *larray[i], file);\r
+\r
+                       uint32 remainder = ((*larray[i]) & 0x3);\r
+                       if (remainder)               // i.e., it's not evenly div by 4\r
+//                             for(j=remainder; j<4; j++)\r
+//                                     file.put((char)0);       // pad it!\r
+//                             WriteFile(file, padding, 4 - remainder, &bytesWritten, NULL);\r
+                               fwrite(padding, 1, 4 - remainder, file);\r
+               }\r
+       }\r
+\r
+       fclose(file);\r
+\r
+       return true;                                                            // Whether or not it was successful...\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL EncodeGlyph(int glyphnum)\r
+//\r
+// This function encodes the glyph data and stores it to the 'glyf' table.\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::EncodeGlyph(uint16 glyphnum)\r
+{\r
+       bool retval = false;                                            // Assume failure\r
+       uint8 flag, xbuf[4000], ybuf[4000], fbuf[2000];\r
+       uint32 xp = 0, yp = 0, fp = 0;                          // Table pointers\r
+\r
+       if (glyphnum < myMaxp.numGlyphs)  // numofgls is 1 based ind, glyph# 0 based\r
+       {\r
+               // need to add composite encoding...\r
+               int lastx = 0, lasty = 0;\r
+\r
+               for(uint32 i=0; i<numberOfPoints; i++)\r
+               {\r
+                       flag = 0;\r
+                       int curx = gx[i] - lastx, cury = gy[i] - lasty;\r
+\r
+                       if (onCurve[i])\r
+                               flag |= 0x01;                                   // Set on curve info\r
+\r
+                       if (curx)\r
+                       {\r
+                               if ((curx > 255) || (curx < -255)) // I.e., it's 2 uint8 value\r
+                                       SetWord(xbuf, xp, curx);\r
+                               else\r
+                               {\r
+                                       if (curx & 0x100)\r
+                                       {\r
+                                               flag |= 0x02; // I.e., it's negative\r
+                                               curx *= -1;   // Flip it so correct value is stored\r
+                                       }\r
+                                       else\r
+                                               flag |= 0x12;\r
+\r
+                                       SetByte(xbuf, xp, curx);        // Automagically strips neg bit\r
+                               }\r
+                       }\r
+                       else\r
+                               flag |= 0x10;                                   // X-coord is same...\r
+  \r
+                       if (cury)\r
+                       {\r
+                               if ((cury > 255) || (cury < -255)) // I.e., it's 2 uint8 value\r
+                                       SetWord(ybuf, yp, cury);\r
+                               else\r
+                               {\r
+                                       if (cury & 0x100)\r
+                                       {\r
+                                               flag |= 0x04; // I.e., it's negative\r
+                                               cury *= -1;\r
+                                       }\r
+                                       else\r
+                                               flag |= 0x24;\r
+            \r
+                                       SetByte(ybuf, yp, cury);\r
+                               }\r
+                       }\r
+                       else\r
+                               flag |= 0x20;                 // Y-coord is same...\r
+  \r
+                       fbuf[i] = flag;\r
+                       lastx = gx[i];  lasty = gy[i];\r
+               }\r
+\r
+               // Now crunch flags...  ugly, ugly, ugly.\r
+/*\r
+    fbuf[numberOfPoints] = 0;  // Set sentinel value (ugly way to do this)\r
+    for(i=0; i<numberOfPoints; i++);\r
+    {\r
+      if (fbuf[i] == fbuf[i+1])  // \r
+      {\r
+        uint8 count = 0;  // Sentinel takes care of check for end of flags...\r
+        while (fbuf[i] == fbuf[++i])  count++; // Count number of repeats\r
+        i--;\r
+        fbuf[fp++] = fbuf[i] | 0x08; // Set repeat flag\r
+        fbuf[fp++] = count;          // & number of repeats\r
+      }\r
+      else  fbuf[fp++] = fbuf[i];    // Otherwise, just copy...\r
+    }\r
+*/\r
+               fp = numberOfPoints;\r
+               // Find length of glyph and reallocate space if necessary\r
+\r
+               uint32 newLength = 12 + numberOfPolys*2 + numberOfHints + fp + xp + yp;\r
+\r
+               if (newLength & 0x03)\r
+                       newLength += (4 - newLength & 0x03);\r
+\r
+               if (glyphLen[glyphnum] != newLength)\r
+               {\r
+                       glyph[glyphnum] = (uint8 *)realloc(glyph[glyphnum], newLength);\r
+                       glyphLen[glyphnum] = newLength;\r
+               }\r
+\r
+               // And finally, store it!\r
+\r
+               uint32 gp = 0;                                                  // Glyph pointer...\r
+               SetWord(glyph[glyphnum], gp, numberOfPolys);\r
+               SetWord(glyph[glyphnum], gp, llx);\r
+               SetWord(glyph[glyphnum], gp, lly);\r
+               SetWord(glyph[glyphnum], gp, urx);\r
+               SetWord(glyph[glyphnum], gp, ury);\r
+               for(uint32 i=0; i<numberOfPolys; i++)\r
+                       SetWord(glyph[glyphnum], gp, poly[i]);\r
+               SetWord(glyph[glyphnum], gp, numberOfHints);\r
+               for(uint32 i=0; i<numberOfHints; i++)\r
+                       SetByte(glyph[glyphnum], gp, hint[i]);\r
+               for(uint32 i=0; i<fp; i++)\r
+                       SetByte(glyph[glyphnum], gp, fbuf[i]);\r
+               for(uint32 i=0; i<xp; i++)\r
+                       SetByte(glyph[glyphnum], gp, xbuf[i]);\r
+               for(uint32 i=0; i<yp; i++)\r
+                       SetByte(glyph[glyphnum], gp, ybuf[i]);\r
+\r
+               retval = true;                                                  // Successfully encoded!\r
+       }\r
+\r
+       return retval;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL DecodeGlyph(int glyphnum)\r
+//\r
+// This function decodes the glyph data and stores it to the object's\r
+// internal array.\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::DecodeGlyph(uint16 glyphnum)\r
+{\r
+       bool retval = false;\r
+       uint32 i, dp;\r
+\r
+       // glyphnum is 0 based index, while numGlyphs is 1 based\r
+       if (glyphnum >= myMaxp.numGlyphs)\r
+               return false;  // Invalid char #\r
+\r
+       if (!glyphLen[glyphnum])\r
+       {\r
+               numberOfPoints = numberOfPolys = 0;\r
+               return true;                                                    // Zero length IS valid...\r
+       }\r
+//     else                                                                            // Get character data...\r
+//     {\r
+    // Now get the character data...\r
+       dp = 0;                     // Reset data pointer\r
+       isCompositeGlyph = false;   // Default is no\r
+       numberOfPolys = GetWord(glyph[glyphnum], dp);  // # of polygons\r
+\r
+       llx = (int16)GetWord(glyph[glyphnum], dp);           // Lower left X\r
+       lly = (int16)GetWord(glyph[glyphnum], dp);           // Lower left Y\r
+       urx = (int16)GetWord(glyph[glyphnum], dp);           // Upper right X\r
+       ury = (int16)GetWord(glyph[glyphnum], dp);           // Upper right Y\r
+\r
+       // Need to handle composite glyphs better here.  The ways things\r
+       // are set now is a recipe for disaster...\r
+\r
+       if (numberOfPolys == 0xFFFF)\r
+       {\r
+               isCompositeGlyph = true;\r
+               numberOfPolys = 0;                                              // Set for no points\r
+\r
+               Composite cmpst;\r
+\r
+               while (!compositeList.IsEmpty())                // Empty composite list...\r
+                       compositeList.GetFront();\r
+\r
+               do\r
+               {\r
+                       cmpst.flags = GetWord(glyph[glyphnum], dp);\r
+                       cmpst.glyphIndex = GetWord(glyph[glyphnum], dp);\r
+                       cmpst.arg1 = (cmpst.flags & 0x01 ? (int16)GetWord(glyph[glyphnum], dp) : (int8)GetByte(glyph[glyphnum], dp));\r
+                       cmpst.arg2 = (cmpst.flags & 0x01 ? (int16)GetWord(glyph[glyphnum], dp) : (int8)GetByte(glyph[glyphnum], dp));\r
+\r
+                       if (cmpst.flags & 0x08)\r
+                               cmpst.xScale = cmpst.yScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp));\r
+                       else if (cmpst.flags & 0x40)\r
+                               cmpst.xScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp)),\r
+                               cmpst.yScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp));\r
+                       else if (cmpst.flags & 0x80)\r
+                               cmpst.xScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp)),\r
+                               cmpst.scale01 = FixedToFloat((int16)GetWord(glyph[glyphnum], dp)),\r
+                               cmpst.scale10 = FixedToFloat((int16)GetWord(glyph[glyphnum], dp)),\r
+                               cmpst.yScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp));\r
+\r
+                       compositeList.AddAtRear(cmpst);\r
+               }\r
+               while (cmpst.flags & 0x20); //*/\r
+\r
+               return true;\r
+       }\r
+\r
+//do {\r
+//     USHORT flags;\r
+//     USHORT glyphIndex;\r
+//     if ( flags & ARG_1_AND_2_ARE_uint16S) {\r
+//     (SHORT or Fuint16) argument1;\r
+//     (SHORT or Fuint16) argument2;\r
+//     } else {\r
+//             USHORT arg1and2; /* (arg1 << 8) | arg2 */\r
+//     }\r
+//     if ( flags & WE_HAVE_A_SCALE ) {\r
+//             F2Dot14  scale;    /* Format 2.14 */\r
+//     } else if ( flags & WE_HAVE_AN_X_AND_Y_SCALE ) {\r
+//             F2Dot14  xscale;    /* Format 2.14 */\r
+//             F2Dot14  yscale;    /* Format 2.14 */\r
+//     } else if ( flags & WE_HAVE_A_TWO_BY_TWO ) {\r
+//             F2Dot14  xscale;    /* Format 2.14 */\r
+//             F2Dot14  scale01;   /* Format 2.14 */\r
+//             F2Dot14  scale10;   /* Format 2.14 */\r
+//             F2Dot14  yscale;    /* Format 2.14 */\r
+//     }\r
+//} while ( flags & MORE_COMPONENTS ) \r
+//if (flags & WE_HAVE_INSTR){\r
+//     USHORT numInstr\r
+//     uint8 instr[numInstr]\r
+//\r
+//Flags                    Bit     Description \r
+//ARG_1_AND_2_ARE_uint16S    0       If this is set, the arguments are uint16s;\r
+//                                 otherwise, they are uint8s.\r
+//ARGS_ARE_XY_VALUES       1       If this is set, the arguments are xy values;\r
+//                                 otherwise, they are points.\r
+//ROUND_XY_TO_GRID         2       For the xy values if the preceding is true.\r
+//WE_HAVE_A_SCALE          3       This indicates that there is a simple scale\r
+//                                 for the component. Otherwise, scale = 1.0.\r
+//RESERVED                 4       This bit is reserved.  Set it to 0. \r
+//MORE_COMPONENTS          5       Indicates at least one more glyph after this\r
+//                                 one.\r
+//WE_HAVE_AN_X_AND_Y_SCALE 6       The x direction will use a different scale\r
+//                                 from the y direction.\r
+//WE_HAVE_A_TWO_BY_TWO     7       There is a 2 by 2 transformation that will\r
+//                                 be used to scale the component.\r
+//WE_HAVE_INSTRUCTIONS     8       Following the last component are\r
+//                                 instructions for the composite character.\r
+//USE_MY_METRICS           9       If set, this forces the aw and lsb (and rsb)\r
+//                                 for the composite to be equal to those from\r
+//                                 this original glyph. This works for hinted\r
+//                                 and unhinted characters.\r
+\r
+       for(i=0; i<numberOfPolys; i++)\r
+               poly[i] = GetWord(glyph[glyphnum], dp);\r
+\r
+       numberOfHints = GetWord(glyph[glyphnum], dp);\r
+\r
+       for(i=0; i<numberOfHints; i++)\r
+               hint[i] = GetByte(glyph[glyphnum], dp);\r
+\r
+       // Decode the dots...\r
+\r
+       uint32 num_pts = poly[numberOfPolys-1] + 1;\r
+       numberOfPoints = num_pts; // necessary??\r
+       uint32 xptr, yptr;        // pointers to beginning of coord data\r
+       uint32 numXs = 0;\r
+       int xx = 0, yy = 0, repeat;\r
+       uint32 numTokens = num_pts, k, numRep;\r
+\r
+       // We make an educated guess that num_pts = num_tokens; but if there\r
+       // is repeated data in the tokens, then we need to adjust the # of\r
+       // tokens down appropriately.\r
+\r
+       for(uint32 i=0; i<numTokens; i++)\r
+       {\r
+               uint8 token = glyph[glyphnum][dp+i];  uint32 rpts = 1;\r
+\r
+               if (token & 0x08)      // Repeated token?\r
+               {\r
+                       i++;                 // Yes, bump pointer to # of times to repeat\r
+                       numRep = glyph[glyphnum][dp+i];\r
+                       rpts += numRep;\r
+\r
+                       if (numRep > 1)      // Do we need to adjust numTokens?\r
+   // this is bad, modifying numTokens while it's used as a compare value\r
+   // in the above loop...\r
+   // Is it necessary to do so in order to keep from going too far?\r
+                       numTokens -= (numRep - 1); // Yes, adjust.\r
+               }\r
+\r
+               // 10 = same x(0uint8s), 00 = 2uint8s, 02&12 = 1uint8\r
+               if ((token & 0x02) == 0x02)\r
+                       numXs += rpts;\r
+\r
+               if ((token & 0x12) == 0x00)\r
+                       numXs += (rpts*2);\r
+       }\r
+\r
+       xptr = dp + numTokens;\r
+       yptr = dp + numTokens + numXs;\r
+\r
+       // & continue decoding X/Y-coords...\r
+\r
+       k = 0;                               // Index to the point array\r
+\r
+       for(uint32 i=0; i<numTokens; i++)\r
+       {\r
+               uint8 token = glyph[glyphnum][dp+i];\r
+               repeat = 1;\r
+\r
+               if (token & 0x08)\r
+               {\r
+                       i++;\r
+                       repeat += glyph[glyphnum][dp+i]; // Set repeat data...\r
+               }\r
+\r
+               while (repeat--)\r
+               {\r
+                       if ((token & 0x12) == 0x12)\r
+                               xx += GetByte(glyph[glyphnum], xptr);\r
+\r
+                       if ((token & 0x12) == 0x02)\r
+                               xx -= GetByte(glyph[glyphnum], xptr);\r
+\r
+                       if ((token & 0x12) == 0x00)\r
+                               xx += (int16)GetWord(glyph[glyphnum], xptr);\r
+\r
+                       gx[k] = xx;                      // Store x-coordinate\r
+\r
+                       if ((token & 0x24) == 0x24)\r
+                               yy += GetByte(glyph[glyphnum], yptr);\r
+\r
+                       if ((token & 0x24) == 0x04)\r
+                               yy -= GetByte(glyph[glyphnum], yptr);\r
+\r
+                       if ((token & 0x24) == 0x00)\r
+                               yy += (int16)GetWord(glyph[glyphnum], yptr);\r
+\r
+                       gy[k] = yy;                      // Store y-coordinate\r
+\r
+                       onCurve[k++] = (token & 0x01 ? true : false);  // If bit 0 set, then it's on curve\r
+               }\r
+       }\r
+\r
+       retval = true;                                                  // Hmm. Successfully decoded a glyph...\r
+//     }\r
+\r
+       isDirty = false;  // do it here?\r
+\r
+       return retval;\r
+}\r
+\r
+/*****************************************************************************\r
+ Member function:\r
+\r
+ This function decodes the 'glyf' data for a non-composite (atomic) glyph and\r
+ returns it as a GlyphPoints object. Helper function.\r
+ *****************************************************************************/\r
+GlyphPoints TTF::GetGlyphPoints(uint16 glyphNum)\r
+{\r
+       if (DecodeGlyph(glyphNum))\r
+               return GlyphPoints(numberOfPoints, numberOfPolys, gx, gy, onCurve, poly);\r
+\r
+       return GlyphPoints();\r
+}\r
+\r
+/*****************************************************************************\r
+ Member function:\r
+\r
+ This function decodes the 'glyf' data for a composite glyph and returns\r
+ it as a GlyphPoints object.\r
+ *****************************************************************************/\r
+GlyphPoints TTF::GetAllCompositePoints(uint16 glyphNum)\r
+{\r
+//  int tmpGlyph = currentGlyph;\r
+  \r
+       DecodeGlyph(glyphNum);         // Check for composite-ness\r
+\r
+       if (!isCompositeGlyph)\r
+               return GlyphPoints();\r
+\r
+/*\r
+  for(int i=1; i<=pDoc->m_myFont.compositeList.Length(); i++)\r
+  {\r
+    TComposite cmpst = fnt->compositeList.PeekPosition(i);\r
+    fnt->SetGlyph(cmpst.glyphIndex);\r
+    if (cmpst.flags & 0x0002)\r
+      m_nXOffset = cmpst.arg1, m_nYOffset = cmpst.arg2;\r
+    ScanConvertSingleGlyph(pDC, nScanlines, nHorzLines, nXOffset, nYOffset);\r
+  }\r
+  fnt->SetGlyph(pDoc->character_num);\r
+*/\r
+\r
+       GlyphPoints retVal;\r
+\r
+       for(int i=1; i<=compositeList.Length(); i++)\r
+       {\r
+               Composite cmpst = compositeList.PeekPosition(i);\r
+    \r
+//    SetGlyph(cmpst.glyphIndex);\r
+//    if (cmpst.flags & 0x0002)\r
+//      m_nXOffset = cmpst.arg1, m_nYOffset = cmpst.arg2;\r
+//    ScanConvertSingleGlyph(pDC, nScanlines, nHorzLines, nXOffset, nYOffset);\r
+               GlyphPoints gp = GetGlyphPoints(cmpst.glyphIndex);\r
+\r
+               if (cmpst.flags & 0x0002)\r
+                       gp.OffsetPoints(cmpst.arg1, cmpst.arg2);\r
+\r
+               retVal = retVal + gp;\r
+               // NOTE: May have to adjust scanlines as per 0x0002 above...\r
+       }\r
+\r
+//  SetGlyph(tmpGlyph);\r
+       DecodeGlyph(currentGlyph);     // Reset needed here...\r
+\r
+       return retVal;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: void GetCharName(int cNum, uint8 * buf)\r
+//\r
+// This function returns the character name of the glyph number passed in.\r
+/////////////////////////////////////////////////////////////////////////////\r
+void TTF::GetCharName(int cNum, uint8 * buf)\r
+{\r
+       buf[0] = 0;                                                                     // Set failure as default condition\r
+  \r
+       if (!post)                                                                      // PS names are here...\r
+               return;\r
+\r
+       if (post[1] != 0x02 || post[2] != 0x00)         // i.e., it's NOT a V2.0 table\r
+               return;\r
+\r
+       uint8 * pTab = NULL;\r
+       uint32 tabOff = 34, numGlyphs = (uint32)((post[32] << 8) | post[33]);\r
+       uint32 index = (uint32)((post[tabOff + cNum * 2] << 8) | post[tabOff + cNum * 2 + 1]);\r
+       uint32 nInd2;\r
+\r
+       if (index > 257)\r
+       {\r
+               index -= 258;\r
+               nInd2 = tabOff + (2 * numGlyphs);\r
+               pTab = post;\r
+       }\r
+       else\r
+       {\r
+               nInd2 = 0;\r
+               pTab = macStdNames;\r
+       }\r
+\r
+       for(uint32 i=0; i<index; i++)\r
+               nInd2 = nInd2 + pTab[nInd2] + 1; // 1st uint8 is length of string + that uint8\r
+\r
+       uint8 len = pTab[nInd2];\r
+       nInd2++;\r
+\r
+       for(uint8 i=0; i<len; i++)\r
+               buf[i] = pTab[nInd2 + i];\r
+\r
+       buf[len] = 0;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL ExtractTables(void)\r
+//\r
+// This function extracts the data from the various tables and puts them in\r
+// various structs for easier handling of the font data.\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::ExtractTables(void)\r
+{\r
+       if (head_len != 54)\r
+       {\r
+#ifdef TTFDEBUG\r
+WriteLogMsg("Bad HEAD header: Expected 54, found %u...\n", head_len);\r
+#endif\r
+               return false;                                                   // Corrupt data?\r
+       }\r
+\r
+       uint32 tp = 0;\r
+       myHead.version            = GetDWord(head, tp);\r
+       myHead.fontRevision       = GetDWord(head, tp);\r
+       myHead.checkSumAdjustment = GetDWord(head, tp);\r
+       myHead.magicNumber        = GetDWord(head, tp);\r
+       myHead.flags              = GetWord(head, tp);\r
+       myHead.unitsPerEm         = GetWord(head, tp);\r
+       myHead.createdh           = GetDWord(head, tp);\r
+       myHead.createdl           = GetDWord(head, tp);\r
+       myHead.modifiedh          = GetDWord(head, tp);\r
+       myHead.modifiedl          = GetDWord(head, tp);\r
+       myHead.xMin               = GetWord(head, tp);\r
+       myHead.yMin               = GetWord(head, tp);\r
+       myHead.xMax               = GetWord(head, tp);\r
+       myHead.yMax               = GetWord(head, tp);\r
+       myHead.macStyle           = GetWord(head, tp);\r
+       myHead.lowestRecPPEM      = GetWord(head, tp);\r
+       myHead.fontDirectionHint  = (int16)GetWord(head, tp);\r
+       myHead.indexToLocFormat   = (int16)GetWord(head, tp);\r
+       myHead.glyphDataFormat    = (int16)GetWord(head, tp);\r
+\r
+       if (maxp_len != 32)\r
+       {\r
+#ifdef TDEBUG\r
+WriteLogMsg("Bad MAXP header: Expected 32, found %u...\n", maxp_len);\r
+#endif\r
+               return false;                                                   // Corrupt data?\r
+       }\r
+\r
+       tp = 0;                                                                         // Reset table pointer\r
+       myMaxp.version               = GetDWord(maxp, tp);\r
+       myMaxp.numGlyphs             = GetWord(maxp, tp);\r
+       myMaxp.maxPoints             = GetWord(maxp, tp);\r
+       myMaxp.maxContours           = GetWord(maxp, tp);\r
+       myMaxp.maxCompositePoints    = GetWord(maxp, tp);\r
+       myMaxp.maxCompositeContours  = GetWord(maxp, tp);\r
+       myMaxp.maxZones              = GetWord(maxp, tp);\r
+       myMaxp.maxTwilightPoints     = GetWord(maxp, tp);\r
+       myMaxp.maxStorage            = GetWord(maxp, tp);\r
+       myMaxp.maxFunctionDefs       = GetWord(maxp, tp);\r
+       myMaxp.maxInstructionDefs    = GetWord(maxp, tp);\r
+       myMaxp.maxStackElements      = GetWord(maxp, tp);\r
+       myMaxp.maxSizeOfInstructions = GetWord(maxp, tp);\r
+       myMaxp.maxComponentElements  = GetWord(maxp, tp);\r
+       myMaxp.maxComponentDepth     = GetWord(maxp, tp);\r
+\r
+       tp = 0;                                                                         // Reset table pointer\r
+       uint32 start = (myHead.indexToLocFormat ? GetDWord(loca, tp) : GetWord(loca, tp) << 1);\r
+\r
+       for(uint32 i=0; i<myMaxp.numGlyphs; i++)\r
+       {\r
+               uint32 end = (myHead.indexToLocFormat ? GetDWord(loca, tp) : GetWord(loca, tp) << 1);\r
+               uint32 length = end - start;\r
+               glyphLen[i] = length;                                   // Lengths are saved 'cause malloc is sloppy\r
+\r
+               if (length)     // loca+start? pointer arithmetic?\r
+               {\r
+                       glyph[i] = (uint8 *)malloc(length);     // Allocate space,\r
+                       memcpy(glyph[i], glyf+start, length);   // and move it!\r
+               }\r
+               else\r
+                       glyph[i] = NULL;\r
+\r
+               start = end;                                                    // Reset start value\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL BuildTables(void)\r
+//\r
+// This function builds the various TTF tables using info in the various\r
+// structs so that a TTF file can be written out to disk.\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::BuildTables(void)\r
+{\r
+       uint32 i, tp, start;\r
+\r
+       myHead.indexToLocFormat = 1;                            // We don't bother with [uint16s*2] format...\r
+\r
+       // Build HEAD table\r
+\r
+       tp = 0;                                                                         // Reset table pointer\r
+       SetDWord(head, tp, myHead.version);//            = GetDWord(head, tp);\r
+       SetDWord(head, tp, myHead.fontRevision);//       = GetDWord(head, tp);\r
+       SetDWord(head, tp, myHead.checkSumAdjustment);// = GetDWord(head, tp);\r
+       SetDWord(head, tp, myHead.magicNumber);//        = GetDWord(head, tp);\r
+       SetWord(head, tp, myHead.flags);//              = GetWord(head, tp);\r
+       SetWord(head, tp, myHead.unitsPerEm);//         = GetWord(head, tp);\r
+       SetDWord(head, tp, myHead.createdh);//           = GetDWord(head, tp);\r
+       SetDWord(head, tp, myHead.createdl);//           = GetDWord(head, tp);\r
+       SetDWord(head, tp, myHead.modifiedh);//          = GetDWord(head, tp);\r
+       SetDWord(head, tp, myHead.modifiedl);//          = GetDWord(head, tp);\r
+       SetWord(head, tp, myHead.xMin);//               = GetWord(head, tp);\r
+       SetWord(head, tp, myHead.yMin);//               = GetWord(head, tp);\r
+       SetWord(head, tp, myHead.xMax);//               = GetWord(head, tp);\r
+       SetWord(head, tp, myHead.yMax);//               = GetWord(head, tp);\r
+       SetWord(head, tp, myHead.macStyle);//           = GetWord(head, tp);\r
+       SetWord(head, tp, myHead.lowestRecPPEM);//      = GetWord(head, tp);\r
+       SetWord(head, tp, myHead.fontDirectionHint);//  = (int16)GetWord(head, tp);\r
+       SetWord(head, tp, myHead.indexToLocFormat);//   = (int16)GetWord(head, tp);\r
+       SetWord(head, tp, myHead.glyphDataFormat);//    = (int16)GetWord(head, tp);\r
+\r
+       // Build MAXP table\r
+\r
+       tp = 0;                                                                         // Reset table pointer\r
+       SetDWord(maxp, tp, myMaxp.version);//               = GetDWord(maxp, tp);\r
+       SetWord(maxp, tp, myMaxp.numGlyphs);//             = GetWord(maxp, tp);\r
+       SetWord(maxp, tp, myMaxp.maxPoints);//             = GetWord(maxp, tp);\r
+       SetWord(maxp, tp, myMaxp.maxContours);//           = GetWord(maxp, tp);\r
+       SetWord(maxp, tp, myMaxp.maxCompositePoints);//    = GetWord(maxp, tp);\r
+       SetWord(maxp, tp, myMaxp.maxCompositeContours);//  = GetWord(maxp, tp);\r
+       SetWord(maxp, tp, myMaxp.maxZones);//              = GetWord(maxp, tp);\r
+       SetWord(maxp, tp, myMaxp.maxTwilightPoints);//     = GetWord(maxp, tp);\r
+       SetWord(maxp, tp, myMaxp.maxStorage);//            = GetWord(maxp, tp);\r
+       SetWord(maxp, tp, myMaxp.maxFunctionDefs);//       = GetWord(maxp, tp);\r
+       SetWord(maxp, tp, myMaxp.maxInstructionDefs);//    = GetWord(maxp, tp);\r
+       SetWord(maxp, tp, myMaxp.maxStackElements);//      = GetWord(maxp, tp);\r
+       SetWord(maxp, tp, myMaxp.maxSizeOfInstructions);// = GetWord(maxp, tp);\r
+       SetWord(maxp, tp, myMaxp.maxComponentElements);//  = GetWord(maxp, tp);\r
+       SetWord(maxp, tp, myMaxp.maxComponentDepth);//     = GetWord(maxp, tp);\r
+\r
+       // Build LOCA & GLYF tables\r
+\r
+       loca_len = (myMaxp.numGlyphs+1) * 4;            // Set size of table\r
+\r
+       if (loca)\r
+               free(loca);                                                             // And create/reallocate it...\r
+\r
+       loca = (uint8 *) malloc(loca_len);\r
+\r
+       glyf_len = 0;                                                           // Refigure glyf table length\r
+\r
+       for(i=0; i<myMaxp.numGlyphs; i++)\r
+               glyf_len += glyphLen[i];\r
+\r
+       if (glyf)\r
+               free(glyf);\r
+\r
+       glyf = (uint8 *) malloc(glyf_len);\r
+\r
+       start = tp = 0;                                                         // Reset table pointer\r
+\r
+       for(i=0; i<myMaxp.numGlyphs; i++)\r
+       {\r
+               SetDWord(loca, tp, start);                              // Store glyph start address\r
+\r
+               if (glyphLen[i])\r
+                       memcpy(glyf+start, glyph[i], glyphLen[i]);\r
+\r
+               start += glyphLen[i];\r
+       }\r
+\r
+       SetDWord(loca, tp, start);                                      // Finally, store end of glyphs+1\r
+\r
+       return true;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL SetGlyph(int glyphnum)\r
+//\r
+// This function decodes the glyph data and stores the points in its own\r
+// internal array.  If the flag isDirty is set, it also encodes the internal\r
+// array and stores it to the 'glyf' table.\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::SetGlyph(uint16 glyphnum)\r
+{\r
+       bool retval = false;                                            // Set failure as default\r
+\r
+       if (isDirty)\r
+               EncodeGlyph(currentGlyph);\r
+\r
+       isDirty = false;\r
+\r
+       if (glyphnum < myMaxp.numGlyphs)                        // numofgls is 1 based ind, glyph# 0 based\r
+       {\r
+               currentGlyph = glyphnum;\r
+               DecodeGlyph(currentGlyph);\r
+               retval = true;\r
+       }\r
+\r
+       return retval;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL AddGlyph(int glyphnum)\r
+//\r
+// This function adds a glyph of zero size at position glyphnum.  If glyphnum\r
+// is greater than the number of glyphs, glyph is added at end of list. This\r
+// glyph then becomes the current glyph.\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::AddGlyph(uint16 glyphnum)\r
+{\r
+       // incomplete: JLH\r
+       bool retval = false;\r
+\r
+       if (isDirty)\r
+               EncodeGlyph(currentGlyph);\r
+\r
+       isDirty = false;\r
+\r
+       return retval;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL DeleteGlyph(int glyphnum)\r
+//\r
+// This function deletes the glyph at position glyphnum.  All glyphs after\r
+// this glyph are moved down in position.\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::DeleteGlyph(uint16 glyphnum)\r
+{\r
+       // incomplete: JLH\r
+       bool retval = false;\r
+\r
+       return retval;\r
+}\r
+\r
+//\r
+// Various & sundry member functions implementation\r
+//\r
+// NOTE: For error handling, should throw exceptions--not return values...! !!! FIX !!!\r
+//\r
+\r
+Box TTF::GetBoundingBox(void)\r
+{\r
+       return Box(llx, lly, urx, ury);\r
+}\r
+\r
+GlyphPt TTF::GetPoint(uint16 pointno)\r
+{\r
+       GlyphPt p;\r
+\r
+       if (pointno >= MAXPOINTS)\r
+               return p; // Fix to make invalid\r
+\r
+       p.x = gx[pointno], p.y = gy[pointno], p.onCurve = onCurve[pointno];\r
+       return p;\r
+}\r
+\r
+uint16 TTF::GetNumberOfPolys(void)\r
+{\r
+       return numberOfPolys;\r
+}\r
+\r
+uint16 TTF::GetPolyEnd(uint16 polynum)\r
+{\r
+       if (polynum >= numberOfPolys)\r
+               return 0;\r
+\r
+       return poly[polynum];\r
+}\r
+\r
+int TTF::GetPointX(uint16 pointno)\r
+{\r
+       if (pointno >= MAXPOINTS)\r
+               return 0;\r
+\r
+       return gx[pointno];\r
+}\r
+\r
+int TTF::GetPointY(uint16 pointno)\r
+{\r
+       if (pointno >= MAXPOINTS)\r
+               return 0;\r
+\r
+       return gy[pointno];\r
+}\r
+\r
+bool TTF::GetOnCurve(uint16 pointno)\r
+{\r
+       if (pointno >= MAXPOINTS)\r
+               return true;\r
+\r
+       return onCurve[pointno];\r
+}\r
+\r
+bool TTF::SetOnCurve(uint16 pointno, bool state)\r
+{\r
+       if (pointno >= numberOfPoints)\r
+               return false;\r
+\r
+       onCurve[pointno] = state;\r
+       isDirty = true;\r
+\r
+       return true;\r
+}\r
+\r
+bool TTF::MovePoint(uint16 pointno, int x, int y)\r
+{\r
+       if (pointno >= numberOfPoints)\r
+               return false;\r
+\r
+       gx[pointno] = x;  gy[pointno] = y;\r
+       isDirty = true;\r
+\r
+       return true;\r
+}\r
+\r
+bool TTF::MovePoint(uint16 pointno, GlyphPt p)\r
+{\r
+       if (pointno >= numberOfPoints)\r
+               return false;\r
+\r
+       gx[pointno] = p.x;  gy[pointno] = p.y;  onCurve[pointno] = p.onCurve;\r
+       isDirty = true;\r
+\r
+       return true;\r
+}\r
+\r
+bool TTF::IsCompositeGlyph(void)\r
+{\r
+       return isCompositeGlyph;\r
+}\r
+\r
diff --git a/src/ttf.h b/src/ttf.h
new file mode 100755 (executable)
index 0000000..07aac36
--- /dev/null
+++ b/src/ttf.h
@@ -0,0 +1,296 @@
+//\r
+// TTF.H: TTF Class\r
+// by James L. Hammons\r
+// (C) 1999 Underground Software\r
+//\r
+// This class encapsulates all the complexity of a TrueType Font File\r
+// database.  Included are functions to load, save, & initialize the\r
+// TTF database.\r
+//\r
+\r
+// These really shouldn't be included here, but are for now...\r
+//#include <string.h>\r
+////#include <afxwin.h>  // This is needed only for things like BOOL, etc.\r
+//#include <fstream.h>\r
+//#include <stdlib.h>\r
+//#include <malloc.h>  // Both for malloc, free, _msize, realloc\r
+\r
+#ifndef __TTF_H__\r
+#define __TTF_H__\r
+\r
+#include "list.h"\r
+#include "types.h"\r
+#include "glyphpoints.h"\r
+\r
+#define MAXGLYPHS 4096                 // Number of glyphs in object\r
+#define MAXPOINTS 2000                 // Number of points in a glyph\r
+#define MAXHINTS  2000                 // Number of hint uint8s in glyph\r
+\r
+//\r
+// "head" struct\r
+//\r
+struct Head\r
+{\r
+       uint32 version;                         // Fixed - Table version number (0x00010000 for version 1.0.)\r
+       uint32 fontRevision;            // Fixed - fontRevision (Set by font manufacturer.)\r
+       uint32 checkSumAdjustment;      // To compute: Set it to 0, sum the entire font\r
+                                                               // as ULONG, then store 0xB1B0AFBA - sum.\r
+       uint32 magicNumber;                     // Set to 0x5F0F3CF5.\r
+       uint16 flags;                           /* Bit 0 - baseline for font at y=0;\r
+                                                                  Bit 1 - left sidebearing at x=0;\r
+                                                                  Bit 2 - instructions may depend on point     size;\r
+                                                                  Bit 3 - force ppem to integer values for all\r
+                                                                                       internal scaler math; may use\r
+                                                                                       fractional ppem sizes if this bit is clear;\r
+                                                                  Bit 4 - instructions may alter advance width\r
+                                                                                       (the advance widths might not scale linearly);\r
+                                                                  Note: All other bits must be zero.*/\r
+       uint16 unitsPerEm;                      // Valid range is from 16 to 16384\r
+       uint32 /*longDateTime*/ createdh, createdl;             // International date (8-uint8 field).\r
+       uint32 /*longDateTime*/ modifiedh, modifiedl;   // International date (8-uint8 field).\r
+       uint16 xMin;                            // For all glyph bounding boxes.\r
+       uint16 yMin;                            // For all glyph bounding boxes.\r
+       uint16 xMax;                            // For all glyph bounding boxes.\r
+       uint16 yMax;                            // For all glyph bounding boxes.\r
+       uint16 macStyle;                        /* Bit 0 bold (if set to 1); Bit 1 italic (if set to 1)\r
+                                                                  Bits 2-15 reserved (set to 0).*/\r
+       uint16 lowestRecPPEM;           // Smallest readable size in pixels.\r
+       int16  fontDirectionHint;       /* 0   Fully mixed directional glyphs;\r
+                                                                  1   Only strongly left to right;\r
+                                                                  2   Like 1 but also contains neutrals;\r
+                                                                 -1   Only strongly right to left;\r
+                                                                 -2   Like -1 but also contains neutrals.*/\r
+       int16  indexToLocFormat;        // 0 for short offsets, 1 for long.\r
+       int16  glyphDataFormat;         // 0 for current format.\r
+};\r
+\r
+//\r
+// "maxp" struct\r
+//\r
+struct Maxp\r
+{\r
+       uint32 version;                                 // Table version number 0x00010000 for version 1.0. \r
+       uint16 numGlyphs;                               // The number of glyphs in the font. \r
+       uint16 maxPoints;                               // Maximum points in a non-composite glyph. \r
+       uint16 maxContours;                             // Maximum contours in a non-composite glyph. \r
+       uint16 maxCompositePoints;              // Maximum points in a composite glyph. \r
+       uint16 maxCompositeContours;    // Maximum contours in a composite glyph. \r
+       uint16 maxZones;                                // 1 if instructions do not use the twilight\r
+                                                                       // zone (Z0), or 2 if instructions do use Z0;\r
+                                                                       // should be set to 2 in most cases. \r
+       uint16 maxTwilightPoints;               // Maximum points used in Z0. \r
+       uint16 maxStorage;                              // Number of Storage Area locations.  \r
+       uint16 maxFunctionDefs;                 // Number of FDEFs. \r
+       uint16 maxInstructionDefs;              // Number of IDEFs. \r
+       uint16 maxStackElements;                // Maximum stack depth. \r
+       uint16 maxSizeOfInstructions;   // Maximum uint8 count for glyph instructions. \r
+       uint16 maxComponentElements;    // Maximum number of components referenced at\r
+                                                                       // "top level" for any composite glyph. \r
+       uint16 maxComponentDepth;               // Maximum levels of recursion; 1 for simple components.\r
+};\r
+\r
+//\r
+// "cmap" struct\r
+//\r
+/*\r
+USHORT Table version number (0).\r
+USHORT Number of encoding tables, n.   \r
+\r
+This is followed by an entry for each of the n encoding table specifying the\r
+particular encoding, and the offset to the actual subtable:\r
+\r
+Type   Description     \r
+USHORT Platform ID.    \r
+USHORT Platform-specific encoding ID.  \r
+ULONG  uint8 offset from beginning of table to the subtable for this encoding. \r
+\r
+USHORT  format          Format number is set to 4.  \r
+USHORT  length          Length in uint8s.  \r
+USHORT version Version number (starts at 0).   \r
+USHORT segCountX2      2 x segCount.   \r
+USHORT searchRange     2 x (2**floor(log2(segCount)))  \r
+USHORT entrySelector   log2(searchRange/2)     \r
+USHORT rangeShift      2 x segCount - searchRange      \r
+USHORT endCount[segCount]      End characterCode for each segment,\r
+                        last =0xFFFF. \r
+USHORT reservedPad     Set to 0.       \r
+USHORT startCount[segCount]    Start character code for each segment.  \r
+USHORT idDelta[segCount]       Delta for all character codes in segment.       \r
+USHORT idRangeOffset[segCount] Offsets into glyphIdArray or 0  \r
+USHORT glyphIdArray[ ] Glyph index array (arbitrary length)    \r
+\r
+The number of segments is specified by segCount, which is not explicitly in\r
+the header; however, all of the header parameters are derived from it. The\r
+searchRange value is twice the largest power of 2 that is less than or equal\r
+to  segCount. For example, if segCount=39, we have the following:\r
+\r
+segCountX2     78\r
+searchRange     64      (2 * largest power of 2 <= 39)\r
+entrySelector  5       log2(32)\r
+rangeShift     14      2 x 39 - 64\r
+*/\r
+\r
+struct GlyphPt\r
+{\r
+       int x, y;\r
+       bool onCurve;\r
+\r
+       // Default constructor\r
+       GlyphPt(int xx = 0, int yy = 0, bool oc = true): x(xx), y(yy), onCurve(oc) {}\r
+};\r
+\r
+struct Box\r
+{\r
+       int16 llx, lly, urx, ury;\r
+\r
+       // Default constructor\r
+       Box(int16 lx = 0, int16 ly = 0, int16 rx = 0, int16 ry = 0):\r
+               llx(lx), lly(ly), urx(rx), ury(ry) {}\r
+};\r
+\r
+struct NameRec\r
+{\r
+       uint16 platformID, platformSpecID, languageID, nameID, length;\r
+       uint8 * str;\r
+\r
+       NameRec(): str(NULL) {}\r
+\r
+       NameRec(NameRec &c): str(NULL)\r
+       {\r
+               *this = c;\r
+       }\r
+\r
+       ~NameRec()\r
+       {\r
+               if (str)\r
+                       delete[] str;\r
+       }\r
+\r
+       void operator=(const NameRec &c)\r
+       {\r
+               if (this == &c)\r
+                       return;                                                         // Take care of self-assignment\r
+\r
+               if (str)\r
+                       delete[] str;\r
+\r
+               platformID     = c.platformID;\r
+               platformSpecID = c.platformSpecID;\r
+               languageID     = c.languageID;\r
+               nameID         = c.nameID;\r
+               length         = c.length;\r
+//Fix this             str            = (uint8 *)strdup((char *)c.str);\r
+       }\r
+};\r
+\r
+struct Composite\r
+{\r
+       uint16 flags, glyphIndex;\r
+       int16 arg1, arg2;\r
+       float xScale, yScale, scale01, scale10;\r
+\r
+       Composite(uint16 fl = 0, uint16 gl = 0, int16 a1 = 0, int16 a2 = 0,\r
+               float xs = 1.0f, float ys = 1.0f, float s01 = 1.0f, float s10 = 1.0f):\r
+               flags(fl), glyphIndex(gl), arg1(a1), arg2(a2), xScale(xs), yScale(ys),\r
+               scale01(s01), scale10(s10) {}\r
+};\r
+\r
+//\r
+// The TTF class\r
+//\r
+// The following is a set of member functions that needs to be implemented\r
+// to fully encapsulate a TTF database.\r
+//\r
+// SetGlyph(glyphno)\r
+// DeleteGlyph(glyphno)\r
+// AddGlyph()\r
+// GetNumberOfPolys()\r
+// GetPolyStart(polyno)\r
+// SetPolyStart(polyno)\r
+// AddPoly(polyno)\r
+// DeletePoly(polyno)\r
+// IsCompositeGlyph()\r
+// MovePoint(pointno, x, y)\r
+// AddPoint(pointno, x, y)\r
+// DeletePoint(pointno)\r
+// maybe:  TGlyphPt GetPointInfo(pointno) instead of three following...\r
+// GetPointX(pointno)\r
+// GetPointY(pointno)\r
+// GetOnCurve(pointno)\r
+// SetOnCurve(pointno)\r
+// ConnectGlyphToChar(glyphno, charno)\r
+// EncodeGlyph(glyphno)\r
+// DecodeGlyph(glyphno)\r
+// GetNumberOfPoints()\r
+// SwapPoints(pointno1, pointno2)\r
+//\r
+// More to be added, as necessary...\r
+//\r
+class TTF\r
+{\r
+       private:\r
+               bool EncodeGlyph(uint16);\r
+               bool DecodeGlyph(uint16);\r
+               bool ExtractTables(void);\r
+               bool BuildTables(void);\r
+\r
+       public:\r
+               TTF(void);                                                              // Constructor\r
+               ~TTF();                                                                 // Destructor\r
+               void Init(void);                                                // Initalize font database\r
+               bool Load(const char *);                                // Load font database\r
+               bool Save(const char *);                                // Save font database\r
+               void ClearTables(void);                                 // Deallocate memory...\r
+               bool SetGlyph(uint16 glyphnum);                 // Set internal pointer/encode/decode\r
+               bool AddGlyph(uint16 glyphnum);\r
+               bool DeleteGlyph(uint16 glyphnum);\r
+               Box GetBoundingBox(void);\r
+               GlyphPt GetPoint(uint16 pointno);\r
+               uint16 GetNumberOfPolys(void);\r
+               uint16 GetPolyEnd(uint16 polynum);\r
+               int GetPointX(uint16 pointno);\r
+               int GetPointY(uint16 pointno);\r
+               bool GetOnCurve(uint16 pointno);\r
+               bool SetOnCurve(uint16 pointno, bool state);\r
+               bool MovePoint(uint16 pointno, int x, int y);\r
+               bool MovePoint(uint16 pointno, GlyphPt p);\r
+               bool AddPoint(uint16 pointno, int x, int y, bool state);\r
+               bool DeletePoint(uint16 pointno);\r
+               bool IsCompositeGlyph(void);\r
+               GlyphPoints GetGlyphPoints(uint16);\r
+               GlyphPoints GetAllCompositePoints(uint16);\r
+               void GetCharName(int, uint8 *);\r
+\r
+       private:\r
+               bool isDirty;                                                   // Has glyph been modified?\r
+               bool isCompositeGlyph;                                  // Is it a composite? (need structs to store composite info...)\r
+               uint16 currentGlyph;                                    // The glyph currently decoded\r
+               uint16 numberOfPoints;\r
+               int gx[MAXPOINTS];                                              // Internal point arrays...\r
+               int gy[MAXPOINTS];                                              // These could be dynamically allocated in the\r
+               bool onCurve[MAXPOINTS];                                // constructor, with default values being set\r
+               uint16 numberOfHints;\r
+               uint8 hint[MAXHINTS];                                   // Hints storage\r
+               uint16 numberOfPolys;                                   // Number of polygons in glyph\r
+               uint16 poly[200];                                               // End points of polygons\r
+               int16 llx, lly, urx, ury;                               // Lower left/Upper right X/Y\r
+//     public://remove after debugging...\r
+               uint8 * glyph[MAXGLYPHS];                               // Placeholders for glyphs\r
+               uint32 glyphLen[MAXGLYPHS];                             // Glyph lengths are stored since malloc() is sloppy\r
+               Maxp myMaxp;                                                    // Internal placeholders for this shiat\r
+               Head myHead;\r
+//     public: //private: later...\r
+               List<Composite> compositeList;                  // Composite glyph list\r
+               uint8 * EBDT, * EBLC, * EBSC, * LTSH, * OS_2, * PCLT, * VDMX, * cmap, * cvt,  * fpgm,\r
+                       * gasp, * glyf, * hdmx, * head, * hhea, * hmtx, * kern, * loca, * maxp, * name,\r
+                       * post, * prep, * vhea, * vmtx;\r
+               uint32 EBDT_len, EBLC_len, EBSC_len, LTSH_len, OS_2_len, PCLT_len, VDMX_len, cmap_len,\r
+                       cvt_len,  fpgm_len, gasp_len, glyf_len, hdmx_len, head_len, hhea_len, hmtx_len,\r
+                       kern_len, loca_len, maxp_len, name_len, post_len, prep_len, vhea_len, vmtx_len;\r
+               uint8 * * parray[24];                                   // Pointer array\r
+               uint32 * larray[24];                                    // Length array\r
+               bool loaded;                                                    // Font loaded/init'ed?\r
+};\r
+\r
+#endif // __TTF_H__\r
+\r
diff --git a/src/types.h b/src/types.h
new file mode 100755 (executable)
index 0000000..7f589aa
--- /dev/null
@@ -0,0 +1,33 @@
+//\r
+// Basic types for platform independent code\r
+//\r
+\r
+#ifndef __TYPES_H__\r
+#define __TYPES_H__\r
+\r
+// This is only good on certain intel 32-bit platforms...\r
+// You may need to tweak to suit your specific platform.\r
+\r
+typedef unsigned char          uint8;\r
+typedef signed char                    int8;\r
+typedef unsigned short         uint16;\r
+typedef signed short           int16;\r
+typedef unsigned                       uint32;\r
+typedef signed                         int32;\r
+//typedef unsigned long long   uint64;\r
+//typedef signed long long     int64;\r
+\r
+//typedef signed char                  SBYTE;\r
+//typedef signed short int     SWORD;\r
+//typedef signed long int              SDWORD;\r
+\r
+/*#ifndef _WINDOWS_\r
+#define NULL   0\r
+// This is for non-compliant compilers that don't follow proper scoping rules (and suck). ;-)\r
+#define for if(false);else for\r
+#endif*/\r
+#ifndef NULL\r
+#define NULL    0\r
+#endif\r
+\r
+#endif // __TYPES_H__\r
diff --git a/src/vector.cpp b/src/vector.cpp
new file mode 100755 (executable)
index 0000000..fc008f3
--- /dev/null
@@ -0,0 +1,141 @@
+//\r
+// VECTOR.H - vector class definition\r
+//\r
+// by James L. Hammons\r
+// (C) 2004 Underground Software\r
+//\r
+// JLH = James L. Hammons <jlhamm@acm.org>\r
+//\r
+// Who  When        What\r
+// ---  ----------  -------------------------------------------------------------\r
+// JLH  ??/??/2003  Created original implementation\r
+// JLH  05/14/2004  Separated header from implementation, added operator-\r
+//                  function\r
+// JLH  05/15/2004  Added operator+ function\r
+//\r
+\r
+#include <math.h>\r
+#include "vector.h"\r
+\r
+vector::vector(double a1/*= 0.0*/, double b1/*= 0.0*/, double c1/*= 0.0*/,\r
+       double a2/*= 0.0*/, double b2/*= 0.0*/, double c2/*= 0.0*/):\r
+       x(a1 - a2), y(b1 - b2), z(c1 - c2)\r
+{\r
+}\r
+\r
+vector::vector(const vector &v1, const vector &v2):\r
+       x(v1.x - v2.x), y(v1.y - v2.y), z(v1.z - v2.z)\r
+{\r
+}\r
+\r
+vector& vector::operator=(const vector &v)\r
+{\r
+       x = v.x, y = v.y, z = v.z;\r
+       return *this;\r
+}\r
+\r
+bool vector::operator==(const vector &v)\r
+{\r
+       if ((x == v.x) && (y == v.y) && (z == v.z))\r
+               return true;\r
+\r
+       return false;\r
+}\r
+\r
+void vector::unitize(void)\r
+{\r
+       double dist = sqrt(x*x + y*y + z*z);\r
+\r
+       if (dist != 0.0)\r
+               x /= dist, y /= dist, z /= dist;\r
+\r
+       if (x == -0.0)\r
+               x = +0.0;\r
+\r
+       if (y == -0.0)\r
+               y = +0.0;\r
+\r
+       if (z == -0.0)\r
+               z = +0.0;\r
+}\r
+\r
+vector vector::operator*(const vector &v)              // Cross product: "this" x "v"\r
+{\r
+       vector r;\r
+\r
+       r.x = (y * v.z) - (v.y * z);\r
+       r.y = -((x * v.z) - (v.x * z));\r
+       r.z = (x * v.y) - (v.x * y);\r
+\r
+       return r;\r
+}\r
+\r
+vector vector::operator+(const vector &v)\r
+{\r
+       return vector(x + v.x, y + v.y, z + v.z);\r
+}\r
+\r
+vector vector::operator-(const vector &v)\r
+{\r
+       return vector(x, y, z, v.x, v.y, v.z);\r
+}\r
+\r
+double vector::dot(const vector &v1, const vector &v2)\r
+{\r
+       return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;\r
+}\r
+\r
+double vector::dot(const vector &v)\r
+{\r
+       return x * v.x + y * v.y + z * v.z;\r
+}\r
+\r
+double vector::distance(const vector &v)               // Pythagoras extended to 3 dimensions\r
+{\r
+       double a = x - v.x, b = y - v.y, c = z - v.z;\r
+\r
+       return sqrt(a * a + b * b + c * c);\r
+}\r
+\r
+double vector::length(void)\r
+{\r
+       return sqrt(x * x + y * y + z * z);\r
+}\r
+\r
+void vector::operator*=(const double &d)\r
+{\r
+       x *= d, y *= d, z *= d;\r
+}\r
+\r
+void vector::operator/=(const double &d)\r
+{\r
+       if (d != 0.0)\r
+               x /= d, y /= d, z /= d;\r
+}\r
+\r
+void vector::operator+=(const vector &v)\r
+{\r
+       x += v.x, y += v.y, z += v.z;\r
+}\r
+\r
+void vector::operator-=(const vector &v)\r
+{\r
+       x -= v.x, y -= v.y, z -= v.z;\r
+}\r
+\r
+vector vector::operator*(const double &d)              // Scale vector by amount\r
+{\r
+       return vector(x * d, y * d, z * d);\r
+}\r
+\r
+void vector::zero(const double epsilon)\r
+{\r
+       if (fabs(x) < epsilon)\r
+               x = 0.0;\r
+\r
+       if (fabs(y) < epsilon)\r
+               y = 0.0;\r
+\r
+       if (fabs(z) < epsilon)\r
+               z = 0.0;\r
+}\r
diff --git a/src/vector.h b/src/vector.h
new file mode 100755 (executable)
index 0000000..a7e36ee
--- /dev/null
@@ -0,0 +1,35 @@
+//\r
+// VECTOR.H - vector class definition\r
+//\r
+// by James L. Hammons\r
+// (C) 2003 Underground Software\r
+//\r
+\r
+#ifndef __VECTOR_H__\r
+#define __VECTOR_H__\r
+\r
+struct vector\r
+{\r
+       double x, y, z;\r
+\r
+       vector(double a1=0.0, double b1=0.0, double c1=0.0, double a2=0.0, double b2=0.0, double c2=0.0);\r
+       vector(const vector &v1, const vector &v2);\r
+       vector& operator=(const vector &v);\r
+       bool operator==(const vector &v);\r
+       void unitize(void);\r
+       vector operator*(const vector &v);                      // Cross product: "this" x "v"\r
+       vector operator+(const vector &v);\r
+       vector operator-(const vector &v);\r
+       double dot(const vector &v1, const vector &v2);\r
+       double dot(const vector &v);\r
+       double distance(const vector &v);                       // Pythagoras extended to 3 dimensions\r
+       double length(void);\r
+       void operator*=(const double &d);\r
+       void operator/=(const double &d);\r
+       void operator+=(const vector &v);\r
+       void operator-=(const vector &v);\r
+       vector operator*(const double &d);                      // Scale vector by amount\r
+       void zero(const double epsilon);\r
+};\r
+\r
+#endif // __VECTOR_H__\r