"Fossies" - the Fresh Open Source Software Archive

Member "yudit-3.0.7/stoolkit/syntax/SHunspellPattern.cpp" (2 Jun 2020, 21575 Bytes) of package /linux/misc/yudit-3.0.7.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "SHunspellPattern.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.0.5_vs_3.0.7.

    1 /** 
    2  *  Yudit Unicode Editor Source File
    3  *
    4  *  GNU Copyright (C) 1997-2006  Gaspar Sinai <gaspar@yudit.org>  
    5  *
    6  *  This program is free software; you can redistribute it and/or modify
    7  *  it under the terms of the GNU General Public License, version 2,
    8  *  dated June 1991. See file COPYYING for details.
    9  *
   10  *  This program is distributed in the hope that it will be useful,
   11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13  *  GNU General Public License for more details.
   14  *
   15  *  You should have received a copy of the GNU General Public License
   16  *  along with this program; if not, write to the Free Software
   17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   18  */
   19  
   20 #include "stoolkit/syntax/SHunspellPattern.h"
   21 #include "stoolkit/SIO.h"
   22 #include "stoolkit/SCharClass.h"
   23 
   24 #ifdef USE_WINAPI
   25 #include <windows.h>
   26 #else
   27 #include <stdlib.h>
   28 #include <dlfcn.h>
   29 #include <string.h>
   30 #endif
   31 
   32 static void fixFileName (SString& str);
   33 static void convertRovasiras (const SV_UCS4& in, SV_UCS4& out);
   34 
   35 static void fixFileName (SString& str)
   36 {
   37 #ifdef USE_WINAPI
   38   str.replaceAll ("/", "\\");
   39   if (str.size() > 0 && str[0] == '\\') str.remove (0);
   40 #endif
   41 }
   42 
   43 static void* dynHandle = 0;
   44 
   45 SHunspellPattern::SHunspellPattern (const SString& _name, 
   46   const SStringVector& path)
   47 {
   48   name = _name;
   49   SString ps_dic = name;
   50   ps_dic.append (".dic");
   51   SFile fdic (ps_dic, path);
   52   if (fdic.size() < 0)
   53   {
   54     valid = false;
   55     fprintf (stderr, "Hunspell invalid fdic.size.\n");
   56   }
   57   else
   58   {
   59     dicFile = fdic.getName ();
   60     fixFileName (dicFile);
   61   }
   62 
   63   SString ps_aff = name;
   64   ps_aff.append (".aff");
   65   SFile faff (ps_aff, path);
   66   if (faff.size() < 0)
   67   {
   68     valid = false;
   69     fprintf (stderr, "Hunspell invalid faff.size.\n");
   70   }
   71   else
   72   {
   73     affFile = faff.getName ();
   74     fixFileName (affFile);
   75   }
   76 
   77 
   78   dicFile.append ((char)0);
   79   affFile.append ((char)0);
   80   SString mising = loadLibrary (path);
   81   hunspell = 0;
   82   functions.create = 0;
   83   functions.spell = 0;
   84   functions.destroy = 0;
   85   functions.get_dic_encoding = 0;
   86   entryEncoder = 0;
   87   if (dynHandle)
   88   {
   89 #ifdef USE_WINAPI
   90     functions.create = (void* (*)(const char*, const char*)) GetProcAddress((HMODULE)dynHandle, "hunspell_initialize");
   91     functions.spell = (int (*)(void*, const char*)) GetProcAddress((HMODULE)dynHandle, "hunspell_spell");
   92     functions.destroy = (int (*)(void*)) GetProcAddress((HMODULE)dynHandle, "hunspell_uninitialize");
   93     functions.get_dic_encoding = (char* (*)(void*))  GetProcAddress((HMODULE)dynHandle, "hunspell_get_dic_encoding");
   94 #else
   95     functions.create = (void* (*)(const char*, const char*)) dlsym(dynHandle, "Hunspell_create");
   96     functions.spell = (int (*)(void*, const char*)) dlsym(dynHandle, "Hunspell_spell");
   97     functions.destroy = (int (*)(void*)) dlsym(dynHandle, "Hunspell_destroy");
   98     functions.get_dic_encoding = (char* (*)(void*))  dlsym(dynHandle, "Hunspell_get_dic_encoding");
   99 #endif
  100     if (functions.create && functions.spell && functions.destroy &&
  101         functions.get_dic_encoding)
  102     {
  103       hunspell = (*functions.create)(affFile.array (), dicFile.array ());
  104       valid = (hunspell != 0);
  105     }
  106     else
  107     {
  108      fprintf (stderr, "hunspell: can not get function handles. create=%d spell=%d destroy=%d get_dic_encoding=%d\n",
  109          (int)(functions.create!=0),
  110          (int)(functions.spell!=0),
  111          (int)(functions.destroy!=0),
  112          (int)(functions.get_dic_encoding!=0)
  113       );
  114       functions.create = 0;
  115       functions.spell = 0;
  116       functions.destroy = 0;
  117       functions.get_dic_encoding = 0;
  118       valid = false;
  119     }
  120   }
  121   else
  122   {
  123      valid = false;
  124   }
  125   if (valid) {
  126     char* enc = (*functions.get_dic_encoding)(hunspell);
  127     // Get at least the ISO set that comes with Yudit.
  128     if (enc == 0) {
  129       entryEncoder = new SEncoder ("utf-8");
  130     } else if (strcmp (enc, "UTF-8") == 0) {
  131       entryEncoder = new SEncoder ("utf-8");
  132     } else if (strcmp (enc, "ISO8859-1") == 0) {
  133       entryEncoder = new SEncoder ("iso-8859-1");
  134     } else if (strcmp (enc, "ISO8859-2") == 0) {
  135       entryEncoder = new SEncoder ("iso-8859-2");
  136     } else if (strcmp (enc, "ISO8859-3") == 0) {
  137       entryEncoder = new SEncoder ("iso-8859-3");
  138     } else if (strcmp (enc, "ISO8859-4") == 0) {
  139       entryEncoder = new SEncoder ("iso-8859-4");
  140     } else if (strcmp (enc, "ISO8859-5") == 0) {
  141       entryEncoder = new SEncoder ("iso-8859-5");
  142     } else if (strcmp (enc, "ISO8859-6") == 0) {
  143       entryEncoder = new SEncoder ("iso-8859-6");
  144     } else if (strcmp (enc, "ISO8859-7") == 0) {
  145       entryEncoder = new SEncoder ("iso-8859-7");
  146     } else if (strcmp (enc, "ISO8859-8") == 0) {
  147       entryEncoder = new SEncoder ("iso-8859-8");
  148     } else if (strcmp (enc, "ISO8859-9") == 0) {
  149       entryEncoder = new SEncoder ("iso-8859-9");
  150     } else if (strcmp (enc, "ISO8859-13") == 0) {
  151       entryEncoder = new SEncoder ("iso-8859-13");
  152     } else if (strcmp (enc, "ISO8859-15") == 0) {
  153       entryEncoder = new SEncoder ("iso-8859-15");
  154     } else if (strcmp (enc, "ISO8859-16") == 0) {
  155       entryEncoder = new SEncoder ("iso-8859-16");
  156     } else if (strcmp (enc, "KOI8-R") == 0) {
  157       entryEncoder = new SEncoder ("koi8-r");
  158     } else {
  159       fprintf (stderr, "Need hunspell encoder for %s\n", enc);
  160       entryEncoder = new SEncoder ("utf-8");
  161     }
  162   }
  163 }
  164 
  165 SHunspellPattern::~SHunspellPattern ()
  166 {
  167   if (functions.destroy && hunspell)
  168   {
  169     (*functions.destroy) (hunspell);
  170   }
  171   if (entryEncoder) delete entryEncoder;
  172 }
  173 
  174 SString
  175 SHunspellPattern::loadLibrary (const SStringVector& path)
  176 {
  177   if (dynHandle == 0)
  178   {
  179     SString libFile;
  180 #ifdef USE_WINAPI
  181     libFile = "libhunspell.dll";
  182 #else
  183 #ifdef __APPLE__
  184     libFile = "libhunspell.dylib";
  185 #else
  186     libFile = "libhunspell.so";
  187 #endif
  188 #endif
  189     SString ret = libFile;
  190     SFile flib (libFile, path);
  191     if (flib.size() > 0)
  192     {
  193       libFile = flib.getName();
  194       fixFileName (libFile);
  195     }
  196     libFile.append ((char)0);
  197 #ifdef USE_WINAPI
  198     SEncoder u8("utf-8");
  199     SEncoder u16("utf-16-le");
  200     SString res = u16.encode (u8.decode (libFile));
  201     WCHAR* filenameW = (WCHAR *) res.array();
  202     dynHandle = LoadLibraryW (filenameW);
  203     if (!dynHandle) 
  204     {
  205       dynHandle = LoadLibraryA (libFile.array());
  206       if (!dynHandle) return SString(ret);
  207     }
  208 #else
  209     dynHandle = dlopen (libFile.array(), RTLD_LAZY);
  210     if (!dynHandle) 
  211     {
  212       fprintf (stderr, "Can not open shared library %s\n", libFile.array());
  213       return SString(ret);
  214     }
  215 #endif
  216     return SString ();
  217   }
  218   return SString ();
  219 }
  220 
  221 SString
  222 SHunspellPattern::getFolderFor (const SString& name, 
  223   const SStringVector& path)
  224 {
  225   for (unsigned int i=0; i<path.size(); i++)
  226   {
  227     SString f = path[i];
  228     f.append ("/");
  229     f.append (name);
  230     f.append (".dic");
  231     SFile file (f);
  232     if (file.size() > 0) return  SString (path[i]);
  233   }
  234   return SString ("");
  235 }
  236 
  237 // Return a non "" string in case there are some missing files
  238 SString
  239 SHunspellPattern::getMissingFile (const SString& name, 
  240   const SStringVector& path)
  241 {
  242   SString missLib = loadLibrary (path);
  243   if (missLib != "") return SString (missLib);
  244   if (name == "")
  245   {
  246     return SString ("*.dic *.aff");
  247   }
  248   for (unsigned int i=0; i<path.size(); i++)
  249   {
  250     SString f_dic = path[i];
  251     f_dic.append ("/");
  252     f_dic.append (name);
  253     f_dic.append (".dic");
  254     SFile file_dic (f_dic);
  255     // aff file should be in the same directory
  256     if (file_dic.size() > 0)
  257     {
  258       SString f_aff = path[i];
  259       f_aff.append ("/");
  260       f_aff.append (name);
  261       f_aff.append (".aff");
  262       SFile file_aff (f_aff);
  263       if (file_aff.size() > 0) return (SString (""));
  264       f_aff = name;
  265       f_aff.append (".aff");
  266       return (SString (f_aff));
  267     }
  268   }
  269   SString ret = name;
  270   ret.append (".dic");
  271   return SString (ret);
  272 }
  273 
  274 
  275 // This method updates matchBegin and matchEnd (exclusive)
  276 // variables in case of a match, in case of no match, this
  277 // will not be touched. Action will contain that action string.
  278 bool
  279 SHunspellPattern::checkMatch ()
  280 {
  281   if (current.size() == 0) return false;
  282   if (current.size() == 1) return false;
  283   // get the controls out first 
  284   SS_UCS4 chr = current[0];
  285   if (isNumber (chr))
  286   {
  287     action = ACT_NUMBER;
  288     matchBegin = matchEnd;
  289     matchEnd++;
  290     current.remove (0);
  291     return true;
  292   }
  293   if (isOther (chr))
  294   {
  295     action = ACT_OTHER;
  296     matchBegin = matchEnd;
  297     matchEnd++;
  298     current.remove (0);
  299     return true;
  300   }
  301   if (isSeparator (chr) || chr == (SS_UCS4) '-')
  302   {
  303     action = ACT_CONTROL;
  304     matchBegin = matchEnd;
  305     matchEnd++;
  306     current.remove (0);
  307     return true;
  308   }
  309   if (isJapanese (chr))
  310   {
  311     action = ACT_NONE;
  312     matchBegin = matchEnd;
  313     matchEnd++;
  314     current.remove (0);
  315     return true;
  316   }
  317   unsigned int i;
  318   for (i=0; i<current.size(); i++)
  319   {
  320     if (isSeparator (current[i])) break;
  321   }
  322   if (i==current.size()) return false;
  323   if (i==0) return false; // never
  324   action = ACT_NONE;
  325   SV_UCS4 v = current;
  326   v.truncate (v.size() -1);
  327 
  328   matchBegin = matchEnd;
  329   matchEnd = matchBegin + v.size(); 
  330   for (i=0; i<v.size(); i++)
  331   {
  332     current.remove (0);
  333   }
  334   SV_UCS4 v1;
  335   convertRovasiras (v, v1);
  336   SString str =  (entryEncoder==0) ? SString ("E_R_R_O_R") : entryEncoder->encode (v1);
  337   str.append ((char) 0);
  338 /*
  339 fprintf (stderr, "call %08lx %08lx %s\n",
  340    (unsigned long) functions.spell, (unsigned long) hunspell, str.array());
  341 */
  342   if ((*functions.spell)(hunspell, str.array())==0)
  343   {
  344     action = ACT_ERROR;
  345   }
  346   return true;
  347 }
  348 
  349 // There is no spell checking for japanese/chinese
  350 bool
  351 SHunspellPattern::isJapanese (SS_UCS4 chr) const
  352 {
  353   if (chr==SD_CD_ZWJ) return false;
  354   if (chr==SD_CD_ZWNJ) return false;
  355   SD_CharClass cc = getCharClass (chr);
  356   if (cc == SD_CC_Mn || cc == SD_CC_Me) return false;
  357 
  358 
  359   // CJK Symbols and Punctuation
  360   if (chr >= 0x3000 && chr <=0x303f) return true;
  361   // Hiragana
  362   if (chr >= 0x3040 && chr <=0x309f) return true;
  363   // Katakana
  364   if (chr >= 0x30A0 && chr <=0x30ff) return true;
  365   // 
  366   if (chr >= 0x31c0 && chr <=0x9fff) return true;
  367 
  368   // Japanes fullwidth alphabet
  369   if (chr >= 0xff21 && chr <=0xff5a) return false;
  370 
  371   // Halfwidth and Fullwidth Forms
  372   if (chr >= 0xff00 && chr <=0xffef) return true;
  373   // CJK Compatibility Ideographs
  374   if (chr >= 0xf900 && chr <=0xfaff) return true;
  375   // CJK Unified Ideographs Extension B
  376   if (chr >= 0x20000 && chr <=0x2A6DF) return true;
  377   // CJK Compatibility Ideographs Supplement    
  378   if (chr >= 0x2F800 && chr <=0x2FA1F) return true;
  379   return false;
  380 }
  381 
  382 // This includes numbers
  383 bool
  384 SHunspellPattern::isSeparator (SS_UCS4 chr) const
  385 {
  386   if (chr == 0xEE2F) return true; // HUNGARIAN RUNIC SEPARATOR in PUA
  387 
  388   if (chr==SD_CD_ZWJ) return false;
  389   if (chr==SD_CD_ZWNJ) return false; // this can be used within the word
  390   SD_CharClass cc = getCharClass (chr);
  391   // combined
  392   if (cc == SD_CC_Mn || cc == SD_CC_Me) return false;
  393 
  394   return (chr != (SS_UCS4) '-' 
  395        && cc != SD_CC_Lu && cc != SD_CC_Ll && cc != SD_CC_Lt 
  396        && cc != SD_CC_Lm && cc != SD_CC_Lo);
  397 }
  398 bool
  399 SHunspellPattern::isNumber (SS_UCS4 chr) const
  400 {
  401   SD_CharClass cc = getCharClass (chr);
  402   return (cc == SD_CC_Nd || cc == SD_CC_Nl || cc == SD_CC_No);
  403 }
  404 bool
  405 SHunspellPattern::isOther (SS_UCS4 chr) const
  406 {
  407   SD_CharClass cc = getCharClass (chr);
  408   return (cc == SD_CC_So);
  409 }
  410 
  411 // Convert rovasiras into standard hungarian, all caps
  412 static void
  413 convertRovasiras (const SV_UCS4& in, SV_UCS4& out)
  414 {
  415   SS_UCS4 chr;
  416   for (unsigned int i=0; i<in.size(); i++)
  417   {
  418     chr = in[i];
  419     switch  ((int)chr)
  420     {
  421     case 0xEE00: out.append ((SS_UCS4) 'A'); break;
  422     case 0xEE01: out.append ((SS_UCS4) 0xC1); break; // AA
  423     case 0xEE02: out.append ((SS_UCS4) 'B'); break;
  424     case 0xEE03: out.append ((SS_UCS4) 'C'); break;
  425     case 0xEE04: out.append ((SS_UCS4) 'C'); out.append ((SS_UCS4) 'S'); break;
  426     case 0xEE05: out.append ((SS_UCS4) 'D'); break;
  427     case 0xEE06: out.append ((SS_UCS4) 'E'); break; // AE
  428     case 0xEE07: out.append ((SS_UCS4) 'E'); break;
  429     case 0xEE08: out.append ((SS_UCS4) 0xC9); break; // EE
  430     case 0xEE09: out.append ((SS_UCS4) 'F'); break;
  431     case 0xEE0A: out.append ((SS_UCS4) 'G'); break;
  432     case 0xEE0B: out.append ((SS_UCS4) 'G'); out.append ((SS_UCS4) 'Y'); break;
  433     case 0xEE0C: out.append ((SS_UCS4) 'H'); break;
  434     case 0xEE0D: out.append ((SS_UCS4) 'I'); break;
  435     case 0xEE0E: out.append ((SS_UCS4) 0xCD); break; // II
  436     case 0xEE0F: out.append ((SS_UCS4) 'J'); break;
  437     case 0xEE10: out.append ((SS_UCS4) 'K'); break; // AK
  438     case 0xEE11: out.append ((SS_UCS4) 'K'); break; // EK
  439     case 0xEE12: out.append ((SS_UCS4) 'L'); break;
  440     case 0xEE13: out.append ((SS_UCS4) 'L'); out.append ((SS_UCS4) 'Y'); break;
  441     case 0xEE14: out.append ((SS_UCS4) 'M'); break;
  442     case 0xEE15: out.append ((SS_UCS4) 'N'); break;
  443     case 0xEE16: out.append ((SS_UCS4) 'N'); out.append ((SS_UCS4) 'Y'); break;
  444     case 0xEE17: out.append ((SS_UCS4) 'O'); break;
  445     case 0xEE18: out.append ((SS_UCS4) 0xD3); break; // OO
  446     case 0xEE19: out.append ((SS_UCS4) 0xD6); break; // OE
  447     case 0xEE1A: out.append ((SS_UCS4) 0x150); break; // OEE
  448     case 0xEE1B: out.append ((SS_UCS4) 'P'); break;
  449     case 0xEE1C: out.append ((SS_UCS4) 'R'); break;
  450     case 0xEE1D: out.append ((SS_UCS4) 'S'); break; // AS
  451     case 0xEE1E: out.append ((SS_UCS4) 'S'); break; // ES
  452     case 0xEE1F: out.append ((SS_UCS4) 'S'); out.append ((SS_UCS4) 'Z'); break;
  453     case 0xEE20: out.append ((SS_UCS4) 'T'); break;
  454     case 0xEE21: out.append ((SS_UCS4) 'T'); out.append ((SS_UCS4) 'Y'); break; // ATY
  455     case 0xEE22: out.append ((SS_UCS4) 'T'); out.append ((SS_UCS4) 'Y'); break; // ETY
  456     case 0xEE23: out.append ((SS_UCS4) 'U'); break;
  457     case 0xEE24: out.append ((SS_UCS4) 0xDA); break; // UU
  458     case 0xEE25: out.append ((SS_UCS4) 0xDC); break; // UE
  459     case 0xEE26: out.append ((SS_UCS4) 0x170); break; // UEE
  460     case 0xEE27: out.append ((SS_UCS4) 'V'); break;
  461     case 0xEE28: out.append ((SS_UCS4) 'Z'); break;
  462     case 0xEE29: out.append ((SS_UCS4) 'Z'); out.append ((SS_UCS4) 'S'); break; 
  463     case 0xEE2F: out.append ((SS_UCS4) ' '); break;
  464   
  465     // NUMBERS
  466     case 0xEE31: out.append ((SS_UCS4) '1'); break;
  467     case 0xEE35: out.append ((SS_UCS4) '5'); break;
  468     case 0xEE3A: out.append ((SS_UCS4) '1'); out.append ((SS_UCS4) '0'); break;
  469     case 0xEE3B: out.append ((SS_UCS4) '5'); out.append ((SS_UCS4) '0'); break;
  470     case 0xEE3C: out.append ((SS_UCS4) '1'); out.append ((SS_UCS4) '0'); out.append ((SS_UCS4) '0');break;
  471     case 0xEE3D: out.append ((SS_UCS4) '1'); out.append ((SS_UCS4) '0'); out.append ((SS_UCS4) '0'); out.append ((SS_UCS4) '0'); break;
  472   
  473     // LIGATURES
  474     case 0xEE40: out.append ((SS_UCS4) 'A'); out.append ((SS_UCS4) 'B'); break;
  475     case 0xEE41: out.append ((SS_UCS4) 'A'); out.append ((SS_UCS4) 'D'); break;
  476     case 0xEE42: out.append ((SS_UCS4) 'A'); out.append ((SS_UCS4) 'L'); break;
  477     case 0xEE43: out.append ((SS_UCS4) 'A'); out.append ((SS_UCS4) 'M'); out.append ((SS_UCS4) 'B'); break;
  478     case 0xEE44: out.append ((SS_UCS4) 'A'); out.append ((SS_UCS4) 'N'); out.append ((SS_UCS4) 'D'); break;
  479     case 0xEE45: out.append ((SS_UCS4) 'A'); out.append ((SS_UCS4) 'N'); out.append ((SS_UCS4) 'T'); break;
  480     case 0xEE46: out.append ((SS_UCS4) 'A'); out.append ((SS_UCS4) 'R'); break;
  481     case 0xEE47: out.append ((SS_UCS4) 'A'); out.append ((SS_UCS4) 'T'); out.append ((SS_UCS4) 'T'); break;
  482     // AAR
  483     case 0xEE48: out.append ((SS_UCS4) 0xC1); out.append ((SS_UCS4) 'R'); break;
  484     case 0xEE49: out.append ((SS_UCS4) 'B'); out.append ((SS_UCS4) 'A'); break;
  485     case 0xEE4A: out.append ((SS_UCS4) 'B'); out.append ((SS_UCS4) 'E'); break;
  486     case 0xEE4B: out.append ((SS_UCS4) 'B'); out.append ((SS_UCS4) 'E'); out.append ((SS_UCS4) 'T'); break;
  487     case 0xEE4C: out.append ((SS_UCS4) 'B'); out.append ((SS_UCS4) 'I'); break;
  488     case 0xEE4D: out.append ((SS_UCS4) 'B'); out.append ((SS_UCS4) 'O'); break;
  489     case 0xEE4E: out.append ((SS_UCS4) 'C'); out.append ((SS_UCS4) 'A'); out.append ((SS_UCS4) 'K'); break;
  490     case 0xEE4F: out.append ((SS_UCS4) 'C'); out.append ((SS_UCS4) 'K'); break;
  491   
  492     case 0xEE50: out.append ((SS_UCS4) 'C'); out.append ((SS_UCS4) 'S'); out.append ((SS_UCS4) 'A'); break;
  493     case 0xEE51: out.append ((SS_UCS4) 'C'); out.append ((SS_UCS4) 'S'); out.append ((SS_UCS4) 'I'); out.append ((SS_UCS4) 'N'); break;
  494     case 0xEE52: out.append ((SS_UCS4) 'D'); out.append ((SS_UCS4) 'U'); break;
  495     case 0xEE53: out.append ((SS_UCS4) 'E'); out.append ((SS_UCS4) 'M'); out.append ((SS_UCS4) 'P'); break;
  496     case 0xEE54: out.append ((SS_UCS4) 'E'); out.append ((SS_UCS4) 'N'); out.append ((SS_UCS4) 'T'); break;
  497     case 0xEE55: out.append ((SS_UCS4) 'G'); out.append ((SS_UCS4) 'A'); break;
  498     case 0xEE56: out.append ((SS_UCS4) 'G'); out.append ((SS_UCS4) 'E'); break;
  499     case 0xEE57: out.append ((SS_UCS4) 'G'); out.append ((SS_UCS4) 'I'); break;
  500     case 0xEE58: out.append ((SS_UCS4) 'G'); out.append ((SS_UCS4) 'O'); break;
  501     case 0xEE59: out.append ((SS_UCS4) 'H'); out.append ((SS_UCS4) 'A'); break;
  502     case 0xEE5A: out.append ((SS_UCS4) 'H'); out.append ((SS_UCS4) 'E'); break;
  503     case 0xEE5B: out.append ((SS_UCS4) 'H'); out.append ((SS_UCS4) 'I'); break;
  504     case 0xEE5C: out.append ((SS_UCS4) 'H'); out.append ((SS_UCS4) 'O'); break;
  505     case 0xEE5D: out.append ((SS_UCS4) 'I'); out.append ((SS_UCS4) 'T'); break;
  506     case 0xEE5E: out.append ((SS_UCS4) 'I'); out.append ((SS_UCS4) 'R'); out.append ((SS_UCS4) 'T'); break;
  507     case 0xEE5F: out.append ((SS_UCS4) 'L'); out.append ((SS_UCS4) 'A'); break;
  508   
  509     // LAA
  510     case 0xEE60: out.append ((SS_UCS4) 'L'); out.append ((SS_UCS4) 0xC1); break;
  511     case 0xEE61: out.append ((SS_UCS4) 'L'); out.append ((SS_UCS4) 'E'); break;
  512     case 0xEE62: out.append ((SS_UCS4) 'L'); out.append ((SS_UCS4) 'O'); break;
  513     case 0xEE63: out.append ((SS_UCS4) 'L'); out.append ((SS_UCS4) 'T'); break;
  514     case 0xEE64: out.append ((SS_UCS4) 'M'); out.append ((SS_UCS4) 'B'); break;
  515     case 0xEE65: out.append ((SS_UCS4) 'N'); out.append ((SS_UCS4) 'A'); break;
  516     case 0xEE66: out.append ((SS_UCS4) 'N'); out.append ((SS_UCS4) 'A'); out.append ((SS_UCS4) 'P'); break;
  517     case 0xEE67: out.append ((SS_UCS4) 'N'); out.append ((SS_UCS4) 'B'); break;
  518     case 0xEE68: out.append ((SS_UCS4) 'N'); out.append ((SS_UCS4) 'C'); break;
  519     case 0xEE69: out.append ((SS_UCS4) 'N'); out.append ((SS_UCS4) 'D'); break;
  520     case 0xEE6A: out.append ((SS_UCS4) 'N'); out.append ((SS_UCS4) 'G'); out.append ((SS_UCS4) 'Y'); break;
  521     case 0xEE6B: out.append ((SS_UCS4) 'N'); out.append ((SS_UCS4) 'I'); break;
  522     case 0xEE6C: out.append ((SS_UCS4) 'N'); out.append ((SS_UCS4) 'K'); break;
  523     case 0xEE6D: out.append ((SS_UCS4) 'N'); out.append ((SS_UCS4) 'T'); break;
  524     case 0xEE6E: out.append ((SS_UCS4) 'O'); out.append ((SS_UCS4) 'R'); break;
  525     case 0xEE6F: out.append ((SS_UCS4) 'R'); out.append ((SS_UCS4) 'A'); break;
  526   
  527   
  528     case 0xEE70: out.append ((SS_UCS4) 'R'); out.append ((SS_UCS4) 'E'); break;
  529     case 0xEE71: out.append ((SS_UCS4) 'R'); out.append ((SS_UCS4) 'I'); break;
  530     case 0xEE72: out.append ((SS_UCS4) 'R'); out.append ((SS_UCS4) 'O'); break;
  531     case 0xEE73: out.append ((SS_UCS4) 'R'); out.append ((SS_UCS4) 'T'); break;
  532     case 0xEE74: out.append ((SS_UCS4) 'R'); out.append ((SS_UCS4) 'U'); break;
  533     case 0xEE75: out.append ((SS_UCS4) 'S'); out.append ((SS_UCS4) 'A'); break;
  534     case 0xEE76: out.append ((SS_UCS4) 'S'); out.append ((SS_UCS4) 'E'); break;
  535     case 0xEE77: out.append ((SS_UCS4) 'S'); out.append ((SS_UCS4) 'I'); break;
  536     case 0xEE78: out.append ((SS_UCS4) 'S'); out.append ((SS_UCS4) 'K'); break;
  537     case 0xEE79: out.append ((SS_UCS4) 'S'); out.append ((SS_UCS4) 'M'); break;
  538     case 0xEE7A: out.append ((SS_UCS4) 'S'); out.append ((SS_UCS4) 'O'); break;
  539     case 0xEE7B: out.append ((SS_UCS4) 'S'); out.append ((SS_UCS4) 'P'); break;
  540     case 0xEE7C: out.append ((SS_UCS4) 'S'); out.append ((SS_UCS4) 'T'); break;
  541     case 0xEE7D: out.append ((SS_UCS4) 'S'); out.append ((SS_UCS4) 'Z'); out.append ((SS_UCS4) 'T'); break;
  542     case 0xEE7E: out.append ((SS_UCS4) 'T'); out.append ((SS_UCS4) 'I'); break;
  543     case 0xEE7F: out.append ((SS_UCS4) 'T'); out.append ((SS_UCS4) 'P'); out.append ((SS_UCS4) 'R'); out.append ((SS_UCS4) 'U'); break;
  544   
  545     case 0xEE80: out.append ((SS_UCS4) 'T'); out.append ((SS_UCS4) 'P'); out.append ((SS_UCS4) 'R'); out.append ((SS_UCS4) 'U'); out.append ((SS_UCS4) 'S'); break;
  546     case 0xEE81: out.append ((SS_UCS4) 'T'); out.append ((SS_UCS4) 'Y'); out.append ((SS_UCS4) 'A'); break;
  547     case 0xEE82: out.append ((SS_UCS4) 'U'); out.append ((SS_UCS4) 'L'); break;
  548     case 0xEE83: out.append ((SS_UCS4) 'U'); out.append ((SS_UCS4) 'M'); break;
  549     case 0xEE84: out.append ((SS_UCS4) 'U'); out.append ((SS_UCS4) 'N'); out.append ((SS_UCS4) 'K');break;
  550     case 0xEE85: out.append ((SS_UCS4) 'U'); out.append ((SS_UCS4) 'R'); break;
  551     case 0xEE86: out.append ((SS_UCS4) 'U'); out.append ((SS_UCS4) 'S'); break;
  552     case 0xEE87: out.append ((SS_UCS4) 'V'); out.append ((SS_UCS4) 'A'); break;
  553     // VAAR
  554     case 0xEE88: out.append ((SS_UCS4) 'V'); out.append ((SS_UCS4) 0xc1); out.append ((SS_UCS4) 'R'); break;
  555     case 0xEE89: out.append ((SS_UCS4) 'Z'); out.append ((SS_UCS4) 'A'); break;
  556     case 0xEE8A: out.append ((SS_UCS4) 'Z'); out.append ((SS_UCS4) 'R'); break;
  557     case 0xEE8B: out.append ((SS_UCS4) 'Z'); out.append ((SS_UCS4) 'T');  break;
  558     default: out.append (chr);
  559       break;
  560    }
  561  }
  562 }