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 
21 #include "stoolkit/SBMap.h"
22 #include "stoolkit/STypes.h"
23 #include "stoolkit/SUtil.h"
24 #include "ProcessFile.h"
25 
26 #include <string.h>
27 #include <stdlib.h>
28 
29 #include <time.h>
30 
31 /* They'll stone me for this */
32 #include <stdio.h>
33 
34 #ifdef USE_WINAPI
35 #include <windows.h>
36 #else
37 #include <unistd.h>
38 #endif
39 
40 unsigned int hexVle (char in);
41 char hexStr (SS_WORD64, int nibble);
42 int encode(void* buffer, char* input, int bytesize);
43 
44 void decode(char* buffer, void* input, int bytesize, int len);
45 int doBenchMark(SBMap* map, int index);
46 
47 #define ISHEX(a) ((a>='A' && a<='F') || (a>='a' && a<='f') || (a>='0' && a<='9'))
48 
49 #define MAX_INPUT_FILES 256
50 typedef enum {KMAP, RKMAP, UNI, RUNI, MYS, RMYS } MapType;
51 
52 typedef struct
53 {
54   MapType    type;
55   int    from;
56   int    to;
57   const char*  name;
58   SBMapItemVector*  item;
59 } InputFiles;
60 
61 char    shortComment[MAX_COMMENT_SIZE];
62 
63 InputFiles  inputFiles[MAX_INPUT_FILES];
64 int    inputFileCount=0;
65 char    inputName[32];
66 int  inputType = -1;
67 
68 char  nameb[1024];
69 char  commentb[1024];
70 char  in[1024];
71 char  enc[1024];
72 
73 int  strip=0;
74 int  info=0;
75 int  test=0;
76 int  stateEnc = 0;
77 int  stateDec = 0;
78 int  mapType = -1;
79 char*  mapName = 0;
80 char*  mapComment = 0;
81 char*   file=0;
82 char*   mapFile=0;
83 int  showKeys=0;
84 int  benchmark=0;
85 int  circle=-1;
86 int  highLow=0;
87 int  keySize=1;
88 int  nocomment=0;
89 
90 SFileFormat  outformat=SS_BINARY;
91 
92 static void usage();
93 static void print_version ();
94 
95 #define BUFFER_SIZE 512
96 char  readBuffer[BUFFER_SIZE];
97 
98 /**
99  * @author Gaspar Sinai <gsinai@iname.com> 1999-12-18
100  * @version 1.0
101  * This is a program to create, convert and test character maps.
102  */
103 int
main(int argc,char * argv[])104 main (int argc, char* argv[])
105 {
106   int    i, j;
107 
108   if (argc < 2)
109   {
110     usage();
111     exit (1);
112   }
113 
114   if (argc==3 && strcmp ("-installdir", argv[1])==0)
115   {
116     SString pref(argv[2]);
117     SDir d (pref);
118     bool ret = false;
119     if (d.exists() && d.readable())
120     {
121       ret = setPrefix (pref);
122     }
123     else
124     {
125       fprintf (stderr, "Can not read directory [%*.*s]\n", SSARGS(pref));
126     }
127     return (ret);
128   }
129 
130   /**
131    * This option puts everything in a tmp file and
132    * calls the program with agruents specified after cmd,
133    * with the filename as the last argument.
134    * when porgram exists remove the tmp file.
135   */
136   if (argc>=3 && strcmp ("-pipecmd", argv[1])==0)
137   {
138     FILE* input=stdin;
139     SString tmpfile = getTemporaryFileName ();
140     if (tmpfile.size()==0)
141     {
142       fprintf (stderr, "Can not create tmp file.\n");
143       return (1);
144     }
145     tmpfile.append ((char)0);
146     FILE* output=stdout;
147 #ifdef USE_WINAPI
148     if ((output = fopen (tmpfile.array(), "wb")) == 0)
149 #else
150     if ((output = fopen (tmpfile.array(), "w")) == 0)
151 #endif
152     {
153       fprintf (stderr, "mytool: can not open '%s' to write.\n",
154         tmpfile.array());
155       return 1;
156     }
157     int len;
158     while (!feof(input) && (len=fread(readBuffer, 1, BUFFER_SIZE, input))>0)
159     {
160       int wlen = fwrite(readBuffer, 1, len, output);
161       if (wlen!= len)
162       {
163         fprintf (stderr, "mytool: failed to write %*.*s.\n", SSARGS(tmpfile));
164         return 1;
165       }
166     }
167     fclose (output);
168     /* call argv[2]...argc - with this file */
169     SStringVector vargs;
170     /* on linux it is foreground by default */
171     for (int i=2; i<argc; i++)
172     {
173        SString arg (argv[i]);
174        arg.insert (0, "\"");
175        arg.append ("\"");
176        vargs.append (arg);
177     }
178 
179     SString farg (tmpfile.array());
180     farg.insert (0, "\"");
181     farg.append ("\"");
182     vargs.append (farg);
183 
184     SPipe pipe (vargs.join (" "));
185     {
186       /* we have to use input stream if we want to wait. Hack in SIO.cpp */
187       SInputStream is = pipe.getInputStream();
188       is.close();
189     }
190 
191     /* wait till it exits */
192     int ret = pipe.wait();
193     /* remove tmp file after it openend it  */
194 #ifdef USE_WINAPI
195     Sleep(10 * 1000);
196 #else
197     sleep (10);
198 #endif
199     unlink (tmpfile.array());
200     return ret;
201   }
202 
203   SBMap  map;
204 
205   for (i=1; i<argc; i++)
206   {
207     if (inputFileCount >= MAX_INPUT_FILES)
208     {
209       fprintf (stderr,  "mytool: maximum % input files can be specified.\n",
210 		MAX_INPUT_FILES);
211       exit (1);
212     }
213     if (strcmp (argv[i],"-info")==0)
214     {
215       info=1;
216       continue;
217     }
218     if (strcmp (argv[i],"-test")==0)
219     {
220       test=1;
221       continue;
222     }
223     if (strcmp (argv[i],"-benchmark")==0)
224     {
225       benchmark=1;
226       continue;
227     }
228     if (strcmp (argv[i],"-strip")==0)
229     {
230       strip=1;
231       continue;
232     }
233     if (strcmp (argv[i],"-version")==0)
234     {
235       print_version ();
236       exit (0);
237     }
238     if (strcmp (argv[i],"-encode")==0)
239     {
240       stateEnc=1;
241       continue;
242     }
243     if (strcmp (argv[i],"-decode")==0)
244     {
245       stateDec=1;
246       continue;
247     }
248     if (strcmp (argv[i],"-high")==0)
249     {
250       highLow=1;
251       continue;
252     }
253     if (strcmp (argv[i],"-8")==0)
254     {
255       keySize=0;
256       continue;
257     }
258     if (strcmp (argv[i],"-low")==0)
259     {
260       highLow=-1;
261       continue;
262     }
263     if (strcmp (argv[i],"-showkeys")==0)
264     {
265       showKeys=1;
266       continue;
267     }
268     if (strcmp (argv[i],"-nocomment")==0)
269     {
270       nocomment=1;
271       continue;
272     }
273     if (i < argc-1 && strcmp (argv[i],"-kmap")==0)
274     {
275       inputFiles [inputFileCount].name = argv[++i];
276       inputFiles [inputFileCount].type = KMAP;
277       inputFileCount++;
278       continue;
279     }
280     if (i < argc-1 && strcmp (argv[i],"-rkmap")==0)
281     {
282       inputFiles [inputFileCount].name = argv[++i];
283       inputFiles [inputFileCount].type = RKMAP;
284       inputFileCount++;
285       continue;
286     }
287     if (i < argc-1 && strcmp (argv[i],"-mys")==0)
288     {
289       inputFiles [inputFileCount].name = argv[++i];
290       inputFiles [inputFileCount].type = MYS;
291       inputFileCount++;
292       continue;
293     }
294     if (i < argc-1 && strcmp (argv[i],"-rmys")==0)
295     {
296       inputFiles [inputFileCount].name = argv[++i];
297       inputFiles [inputFileCount].type = RMYS;
298       inputFileCount++;
299       continue;
300     }
301     if (i < argc-1 && sscanf (argv[i],"-uni:%d,%d",
302       &inputFiles[inputFileCount].from,
303       &inputFiles[inputFileCount].to)==2)
304     {
305       inputFiles [inputFileCount].name = argv[++i];
306       inputFiles [inputFileCount].type = UNI;
307       inputFileCount++;
308       continue;
309     }
310     if (i < argc-1 && sscanf (argv[i],"-runi:%d,%d",
311       &inputFiles[inputFileCount].from,
312       &inputFiles[inputFileCount].to)==2)
313     {
314       inputFiles [inputFileCount].name = argv[++i];
315       inputFiles [inputFileCount].type = RUNI;
316       inputFileCount++;
317       continue;
318     }
319 
320     if (i < argc-1 && strcmp (argv[i],"-write")==0)
321     {
322       if (file != 0)
323       {
324         fprintf (stderr,  "mytool: only one '-write' option can be specified.\n");
325         exit (1);
326       }
327       file = argv[++i];
328       continue;
329     }
330     if (i < argc-1 && strcmp (argv[i],"-type")==0)
331     {
332       i++;
333       if (strcmp (argv[i], "kmap")==0)
334       {
335         mapType = 1;
336       }
337       else if (strcmp (argv[i], "clkmap")==0)
338       {
339         mapType = 4;
340       }
341       else if (strcmp (argv[i], "fontmap")==0)
342       {
343         mapType = 2;
344       }
345       else
346       {
347         fprintf (stderr,  "mytool: unknown maptype '%s'\n", argv[i]);
348         exit (1);
349       }
350 
351       continue;
352     }
353     if (i < argc-1 && strcmp (argv[i],"-name")==0)
354     {
355       mapName = argv[++i];
356       continue;
357     }
358     if (i < argc-1 && strcmp (argv[i],"-comment")==0)
359     {
360       mapComment = argv[++i];
361       continue;
362     }
363     if (i < argc-1 && strcmp (argv[i],"-my")==0)
364     {
365       if (mapFile != 0)
366       {
367         fprintf (stderr,  "mytool: only one '-my' option can be specified.\n");
368         exit (1);
369       }
370       mapFile = argv[++i];
371       continue;
372     }
373     if (i < argc-1 && strcmp (argv[i],"-convert")==0)
374     {
375       i++;
376       if (strcmp (argv[i],"my")==0)
377       {
378         outformat = SS_BINARY;
379       }
380       else if (strcmp (argv[i],"mys")==0)
381       {
382         outformat = SS_TEXT_MAP;
383       }
384       else if (strcmp (argv[i],"myc")==0)
385       {
386         outformat = SS_CTEXT;
387       }
388       else if (strcmp (argv[i],"bumap")==0)
389       {
390         outformat = SS_BUMAP;
391       }
392       else if (strcmp (argv[i],"cumap")==0)
393       {
394         outformat = SS_CUMAP;
395       }
396       else
397       {
398         usage ();
399         return (1);
400       }
401       continue;
402     }
403     usage ();
404     exit (1);
405   }
406 
407   if (mapFile!=0)
408   {
409     SFile f(mapFile);
410     map.setFileImage (f.getFileImage());
411     if (f.size() < 0 || !map.getStatus())
412     {
413       if (mapFile==0)
414       {
415         usage ();
416         return (1);
417       }
418       fprintf (stderr,  "mytool: can not find valid '%s' map file\n", mapFile);
419       return (1);
420      }
421     if (strip)
422     {
423       map.strip ();
424     }
425   }
426 
427   // Process input files
428   for (i=0; i<inputFileCount; i++)
429   {
430     inputFiles[i].item = 0;
431   }
432   shortComment[0] = 0;
433   inputName[0] = 0;
434   inputType = -1;
435 
436 
437   for (i=0; i<inputFileCount; i++)
438   {
439     SFile in(inputFiles[i].name);
440     if (in.size() < 0)
441     {
442       do {
443         if (inputFiles[i].item!=0)
444         {
445           for (j=0; j<inputFiles[i].item->count; j++)
446           {
447             delete inputFiles[i].item->maps[j];
448           }
449           delete inputFiles[i].item;
450           inputFiles[i].item = 0;
451         }
452       } while (i-->0);
453       fprintf (stderr,  "mytool: can not read '%s'.\n", inputFiles[i].name);
454       return (1);
455     }
456     SInputStream is = in.getInputStream();
457     switch (inputFiles[i].type)
458     {
459     case KMAP:
460       inputFiles[i].item = processKMap (inputFiles[i].name, is, nocomment, 0, shortComment, inputName, &inputType);
461       break;
462     case RKMAP:
463       inputFiles[i].item = processKMap (inputFiles[i].name, is, nocomment, 1, shortComment, inputName, &inputType);
464       break;
465     case MYS:
466       inputFiles[i].item = processMYS (inputFiles[i].name, is, nocomment, 0, shortComment, inputName, &inputType);
467       break;
468     case RMYS:
469       inputFiles[i].item = processMYS (inputFiles[i].name, is, nocomment, 1, shortComment, inputName, &inputType);
470       break;
471     case UNI:
472       inputFiles[i].item = processUNI (inputFiles[i].name, is, nocomment, keySize, highLow, inputFiles[i].from, inputFiles[i].to, 0, shortComment, inputName, &inputType);
473       break;
474     case RUNI:
475       inputFiles[i].item = processUNI (inputFiles[i].name, is, nocomment, keySize, highLow, inputFiles[i].from, inputFiles[i].to, 1, shortComment, inputName, &inputType);
476       break;
477     default:
478       fprintf (stderr,  "mytool: internal error: %d \n", inputFiles[i].type);
479       break;
480     }
481 
482     if (inputFiles[i].item==0)
483     {
484       fprintf (stderr,  "mytool: bad source file '%s'.\n", inputFiles[i].name);
485       do {
486         if (inputFiles[i].item!=0)
487         {
488           delete inputFiles[i].item;
489           inputFiles[i].item = 0;
490         }
491       } while (i-->0);
492       return (1);
493     }
494   }
495   if (mapComment != 0)
496   {
497     map.setComment ((const unsigned char*) mapComment, strlen (mapComment));
498   }
499   else if (shortComment[0] != 0)
500   {
501     map.setComment ((const unsigned char*) shortComment, strlen (shortComment));
502   }
503   else if (inputFileCount)
504   {
505     time_t  tim;
506     char *source_date_epoch = getenv ("SOURCE_DATE_EPOCH");
507     if (source_date_epoch == NULL || (tim = (time_t)strtol (source_date_epoch, NULL, 10)) <= 0)
508       tim = time(0);
509     struct tm* ts = localtime (&tim);
510     sprintf (shortComment, "created by mytool %04d-%02d-%02d",
511       ts->tm_year+1900, ts->tm_mon+1, ts->tm_mday);
512     map.setComment ((const unsigned char*) shortComment,
513       strlen (shortComment));
514   }
515 
516   if (mapType > 0)
517   {
518     map.setType (mapType);
519   }
520   else if (inputType > 0)
521   {
522     map.setType (inputType);
523   }
524 
525   if (mapName != 0)
526   {
527     map.setName ((const unsigned char*) mapName);
528   }
529   else if (inputName[0] != 0)
530   {
531     map.setName ((const unsigned char*) inputName);
532   }
533 
534   for (i=0; i<inputFileCount; i++)
535   {
536     // ownership is passed to map
537     for (j=0; j<inputFiles[i].item->count; j++)
538     {
539       map.add (inputFiles[i].item->maps[j]);
540       inputFiles[i].item->maps[j] = 0;
541     }
542     delete inputFiles[i].item;
543     inputFiles[i].item = 0;
544   }
545 
546   // Build encoding state machine.
547   if (stateEnc)
548   {
549     for (i=0; i<map.getSize(); i++)
550     {
551       if (map.getType(i)==SBMap::SBMap_DECODE) continue;
552       map.buildStateMachine (i);
553     }
554   }
555 
556   if (stateDec)
557   {
558     for (i=0; i<map.getSize(); i++)
559     {
560       if (map.getType(i)==SBMap::SBMap_ENCODE) continue;
561       map.buildStateMachine (i);
562     }
563   }
564   if (info)
565   {
566     const char*  type = 0;
567     if (map.mapType==1) type="kmap";
568     if (map.mapType==4) type="clkmap";
569     if (map.mapType==2) type="fontmap";
570     if (type==0)
571     {
572       fprintf (stdout, "type...: undefined (%d)\n", map.mapType);
573     }
574     else
575     {
576       fprintf (stdout, "type...: %s\n", type);
577     }
578     fprintf (stdout, "size...: %d\n", map.getSize());
579     map.getName (nameb, 1024);
580     fprintf (stdout, "name...: [%s]\n", nameb);
581     map.getComment (commentb, 1024);
582     fprintf (stdout, "comment: [%s]\n", commentb);
583     int   integ;
584     for (i=0; i<map.getSize(); i++)
585     {
586       SBMapItem* mp = map.getItem(i);
587       fprintf (stdout, "info:----------------: map[%d]\n", i);
588       map.getName (nameb, 1024, i);
589       fprintf (stdout, "%d.name...............: [%s]\n", i, nameb);
590       map.getComment (commentb, 1024, i);
591       fprintf (stdout, "%d.comment............: [%s]\n", i, commentb);
592       type = "unknown";
593       if (mp->itemType == SBMapItem::SBMapNToN)
594         type = "my";
595       if (mp->itemType == SBMapItem::SBMapBumap)
596         type = "bumap";
597 
598       fprintf (stdout, "%d.itemType...........: %s\n", i, type);
599       fprintf (stdout, "%d.size...............: %d matches \n",
600 		i, map.getSize(i));
601       type="unknown";
602       if (map.getType(i)==SBMap::SBMap_DECODE) type="decode";
603       if (map.getType(i)==SBMap::SBMap_ENCODE) type="encode";
604       fprintf (stdout, "%d.type...............: %s\n",i,  type);
605 
606       type = (map.getStateMachine(i) ==0) ? "no" : "yes";
607       fprintf (stdout, "%d.state machine based: %s\n",i, type);
608       integ = 8 << map.getInWordSize(i);
609       fprintf (stdout, "%d.input..............: %d bits\n", i, integ);
610       integ = 8 << map.getOutWordSize(i);
611       fprintf (stdout, "%d.output.............: %d bits\n", i, integ);
612       if (showKeys)
613       {
614         char   buf[256];
615         int  k;
616         const unsigned char* tmp;
617         unsigned int len;
618         unsigned int matched;
619         for (k=0; k<map.getSize(i); k++)
620         {
621           tmp = mp->getKey (k, &len, &matched);
622           memcpy (buf, tmp, len);
623           buf[len] = 0;
624           fprintf (stdout, "%d.keys............: [%d] |%s|\n" ,i, k, buf);
625         }
626       }
627       if (benchmark)
628       {
629         fprintf (stdout,  "%d.benchmark.speed......: %d\n", i, doBenchMark (&map, i));
630       }
631 
632     }
633     if (benchmark)
634     {
635       fprintf (stdout, "encode.benchmark.speed.: %d\n",
636 	doBenchMark (&map, -1-(int)SBMap::SBMap_ENCODE));
637       fprintf (stdout, "decode.benchmark.speed.: %d\n",
638 	doBenchMark (&map, -1-(int)SBMap::SBMap_DECODE));
639     }
640   }
641   else if (benchmark)
642   {
643     for (i=0; i<map.getSize(); i++)
644     {
645       fprintf(stdout, "%d.benchmark.speed......: %d\n", i,
646 	doBenchMark (&map, i));
647     }
648     if (benchmark)
649     {
650       fprintf (stderr, "encode.benchmark.speed.: %d\n",
651 	   doBenchMark (&map, -1-(int)SBMap::SBMap_ENCODE));
652       fprintf(stderr,  "decode.benchmark.speed.: %d\n",
653 	   doBenchMark (&map, -1-(int)SBMap::SBMap_DECODE));
654     }
655   }
656 
657 
658   if (test)
659   {
660     char  ce[256];
661 
662     fprintf (stdout, "Enter map-index-or-d-or-e  in-bytesize out-bytesize: ");
663     fflush (stdout);;
664 
665     int index, in_bytesize, out_bytesize;
666     int len, in_bytesize_orig, out_bytesize_orig;
667     ce[255] = 0;
668     if (fscanf (stdin, "%255s", ce) == 0) {
669       fprintf (stderr,  "Can not parse line.\n");
670       return (1);
671     }
672     index = 0;
673     if (ce[0] == 'd')
674     {
675       circle = (int) SBMap::SBMap_DECODE;
676       for (i=0; i<map.getSize(); i++)
677       {
678         if (map.getType(i)==circle)
679         {
680           index = i;
681           break;
682         }
683       }
684     }
685     else if (ce[0] == 'e')
686     {
687       circle = (int) SBMap::SBMap_ENCODE;
688       index = 0;
689       for (i=0; i<map.getSize(); i++)
690       {
691         if (map.getType(i)==circle)
692         {
693           index = i;
694           break;
695         }
696       }
697     }
698     else
699     {
700       index = atoi(ce);
701     }
702     if (fscanf (stdin, "%d", &in_bytesize_orig) == 0) {
703       fprintf (stderr,  "Can not parse line.\n");
704       return (1);
705     }
706     if (fscanf (stdin, "%d", &out_bytesize_orig) == 0) {
707       fprintf (stderr,  "Can not parse line.\n");
708       return (1);
709     }
710 
711     switch (in_bytesize_orig)
712     {
713     case 1: in_bytesize=0; break;
714     case 8: in_bytesize=0; break;
715     case 16: in_bytesize=1; break;
716     case 32: in_bytesize=2; break;
717     case 64: in_bytesize=3; break;
718     default:
719       fprintf (stderr,  "Bad argument for in_bytesize. Should be {1|8|16|32|64}\n");
720       return (1);
721     }
722     switch (out_bytesize_orig)
723     {
724     case 1: out_bytesize=0; break;
725     case 8: out_bytesize=0; break;
726     case 16: out_bytesize=1; break;
727     case 32: out_bytesize=2; break;
728     case 64: out_bytesize=3; break;
729     default:
730       fprintf (stderr,  "Bad argument for out_bytesize. Should be {1|8|16|32|64}\n");
731       return (1);
732     }
733     if (index < 0 || index >= map.getSize())
734     {
735       fprintf (stderr,  "Bad argument for index. Should be [0..%d]\n", (int) map.getSize()-1);
736       return (1);
737     }
738 
739     SStateModel model (in_bytesize, map.getInWordSize (index),
740        map.getOutWordSize (index), out_bytesize);
741     while (!feof(stdin))
742     {
743       if (in_bytesize_orig==1)
744       {
745         fprintf (stdout,  "Enter bytestring: ");
746       }
747       else
748       {
749         fprintf (stdout,  "Enter hex bytestring nibbles: ");
750       }
751       fflush (stdout);
752       in[1023] = 0;
753       if (fscanf (stdin, "%1023s", in) == 0) {
754         fprintf (stdout,  "Can not parse line");
755         return (1);
756       }
757       if (in_bytesize_orig==1)
758       {
759         len = strlen (in);
760         memcpy (enc, in, len);
761       }
762       else
763       {
764         len = encode (enc, in, in_bytesize);
765       }
766       if (circle>=0)
767       {
768 	fprintf (stderr,  "circle..\n");
769         len = map.circle ((SBMap::SBMapType)circle, enc, len, &model, 1);
770       }
771       else
772       {
773         len = map.encode (index, enc, len, &model, 1);
774       }
775       switch (len)
776       {
777       case SS_REJECT:
778         model.reset();
779         fprintf(stdout, "reposnse: REJECT\n");
780         break;
781       case SS_ACCEPT:
782         fprintf(stdout, "reposnse: ACCEPT\n");
783         break;
784       default:
785 	fprintf (stdout, "result:  MATCH length %d -> %d:",
786 		len, model.out.length);
787         switch (out_bytesize)
788         {
789         case 0:
790           memcpy (enc, model.out.u.u8, model.out.length);
791           break;
792         case 1:
793           memcpy (enc, model.out.u.u16, model.out.length*2);
794           break;
795         case 2:
796           memcpy (enc, model.out.u.u32, model.out.length*4);
797           break;
798         case 3:
799           memcpy (enc, model.out.u.u64, model.out.length*64);
800           break;
801         default:
802           // Debug it..
803           return (1);
804         }
805         if (out_bytesize_orig==1)
806         {
807           memcpy (in, enc, model.out.length);
808           in[model.out.length] = 0;
809         }
810         else
811         {
812           decode (in, enc, out_bytesize, model.out.length);
813         }
814         fprintf (stdout, "'%s'\n", in);
815         model.reset();
816       }
817     }
818   }
819 
820   if (file != 0)
821   {
822     SFile f(file);
823     SOutputStream os = f.getOutputStream();
824     if (!os.isOK())
825     {
826       fprintf (stderr,  "mytool: can not open file: '%s'\n",file);
827       return (1);
828     }
829     int size = map.serialize (os, outformat);
830     if (size <= 0)
831     {
832       fprintf (stderr,  "mytool: can serialize map into file: '%s'\n", file);
833       return (1);
834     }
835   }
836 
837   return (0);
838 }
839 
840 int
encode(void * buffer,char * input,int bytesize)841 encode(void* buffer, char* input, int bytesize)
842 {
843   SS_WORD8  o8[1024];
844   SS_WORD16  o16[1024];
845   SS_WORD32  o32[1024];
846   SS_WORD64  o64[1024];
847   int    i, index;
848   SS_WORD64  result;
849 
850   index = 0; i=0; result=0;
851   switch (bytesize)
852   {
853   case 0:
854     for (i=0; input[i]!=0; i++)
855     {
856       if (!ISHEX(input[i])) continue;
857       result = (result << 4) + hexVle(input[i]);
858       index++;
859       if ((index%2)==0)
860       {
861         o8[index/2-1] = (SS_WORD8) result;
862         result = 0;
863       }
864     }
865     memcpy (buffer, o8, index/2);
866     return index/2;
867   case 1:
868     for (i=0; input[i]!=0; i++)
869     {
870       if (!ISHEX(input[i])) continue;
871       result = (result << 4) + hexVle(input[i]);
872       index++;
873       if ((index%4)==0)
874       {
875         o16[index/4-1] = (SS_WORD16) result;
876         result = 0;
877       }
878     }
879     memcpy (buffer, o16, index/2);
880     return index/4;
881   case 2:
882     for (i=0; input[i]!=0; i++)
883     {
884       if (!ISHEX(input[i])) continue;
885       result = (result << 4) + hexVle(input[i]);
886       index++;
887       if ((index%8)==0)
888       {
889         o32[index/8-1] = (SS_WORD32) result;
890         result = 0;
891       }
892     }
893     memcpy (buffer, o32, index/2);
894     return index/8;
895   case 3:
896     for (i=0; input[i]!=0; i++)
897     {
898       if (!ISHEX(input[i])) continue;
899       result = (result << 4) + hexVle(input[i]);
900       index++;
901       if ((index%16)==0)
902       {
903         o64[index/16-1] = (SS_WORD32) result;
904         result = 0;
905       }
906     }
907     memcpy (buffer, o64, index/2);
908     return index/16;
909   default:
910     break;
911   }
912   return 0;
913 }
914 
915 void
decode(char * buffer,void * input,int bytesize,int len)916 decode(char* buffer, void* input, int bytesize, int len)
917 {
918   int  i;
919   int  index;
920   SS_WORD64  word;
921   unsigned char*  in = (unsigned char*) input;
922   switch (bytesize)
923   {
924   case 0:
925     index=0;
926     for (i=0; i<len; i++)
927     {
928       word = (SS_WORD64) (((SS_WORD8*)in)[i]);
929       buffer[index++] = hexStr(word, 1);
930       buffer[index++] = hexStr(word, 0);
931       buffer[index++] = ' ';
932     }
933     buffer[index++] = 0;
934     break;
935   case 1:
936     index=0;
937     for (i=0; i<len; i++)
938     {
939       word = (SS_WORD64) (((SS_WORD16*)in)[i]);
940       buffer[index++] = hexStr(word, 3);
941       buffer[index++] = hexStr(word, 2);
942       buffer[index++] = hexStr(word, 1);
943       buffer[index++] = hexStr(word, 0);
944       buffer[index++] = ' ';
945     }
946     buffer[index++] = 0;
947     break;
948   case 2:
949     index=0;
950     for (i=0; i<len; i++)
951     {
952       word = (SS_WORD64) (((SS_WORD32*)in)[i]);
953       buffer[index++] = hexStr(word, 7);
954       buffer[index++] = hexStr(word, 6);
955       buffer[index++] = hexStr(word, 5);
956       buffer[index++] = hexStr(word, 4);
957       buffer[index++] = hexStr(word, 3);
958       buffer[index++] = hexStr(word, 2);
959       buffer[index++] = hexStr(word, 1);
960       buffer[index++] = hexStr(word, 0);
961       buffer[index++] = ' ';
962     }
963     buffer[index++] = 0;
964     break;
965   case 3:
966     index=0;
967     for (i=0; i<len; i++)
968     {
969       word = (SS_WORD64) (((SS_WORD64*)in)[i]);
970       buffer[index++] = hexStr(word, 15);
971       buffer[index++] = hexStr(word, 14);
972       buffer[index++] = hexStr(word, 13);
973       buffer[index++] = hexStr(word, 12);
974       buffer[index++] = hexStr(word, 11);
975       buffer[index++] = hexStr(word, 10);
976       buffer[index++] = hexStr(word, 9);
977       buffer[index++] = hexStr(word, 8);
978       buffer[index++] = hexStr(word, 7);
979       buffer[index++] = hexStr(word, 6);
980       buffer[index++] = hexStr(word, 5);
981       buffer[index++] = hexStr(word, 4);
982       buffer[index++] = hexStr(word, 3);
983       buffer[index++] = hexStr(word, 2);
984       buffer[index++] = hexStr(word, 1);
985       buffer[index++] = hexStr(word, 0);
986       buffer[index++] = ' ';
987     }
988     buffer[index++] = 0;
989     break;
990   default:
991     buffer[0] = 0;
992     break;
993   }
994 }
995 
996 unsigned int
hexVle(char in)997 hexVle (char in)
998 {
999   if (in>='0' && in<='9') return in-'0';
1000   if (in>='a' && in<='z') return in-'a'+10;
1001   if (in>='A' && in<='Z') return in-'A'+10;
1002   return 256;
1003 }
1004 char
hexStr(SS_WORD64 in,int nibble)1005 hexStr (SS_WORD64 in, int nibble)
1006 {
1007   SS_WORD64 newIn;
1008   newIn = (in>>(4*nibble))&0x0f;
1009   if (newIn < 10) return (char) (newIn + '0');
1010   return (char) (newIn + 'A' - 10);
1011 }
1012 
1013 int
doBenchMark(SBMap * map,int index)1014 doBenchMark(SBMap* map, int index)
1015 {
1016   SS_WORD16  in;
1017   SS_WORD16  input[256];
1018   int    ind;
1019 
1020   int    count = 0;
1021   time_t    t0, t1;
1022   int    len;
1023   t0 = time(0);
1024   ind=0;
1025   in = 0;
1026   int  i;
1027 
1028   int  which=index;
1029 
1030   if (which < 0)
1031   {
1032     for (i=0; i<map->getSize(); i++)
1033     {
1034       if (map->getType(i) == (SBMap::SBMapType)(-index-1))
1035       {
1036         which = i;
1037         break;
1038       }
1039     }
1040   }
1041   if (which < 0)
1042   {
1043     return 0;
1044   }
1045   SStateModel model (1, map->getInWordSize (which),
1046        map->getOutWordSize (which), 1);
1047   while (1)
1048   {
1049     input[ind]++;
1050     if (input[ind]==0 && ind>0)
1051     {
1052       ind--;
1053     }
1054     model.reset();
1055     if (index<0)
1056     {
1057       len = map->circle ((SBMap::SBMapType)(-index-1), input, ind+1, &model, 1);
1058     }
1059     else
1060     {
1061       len = map->encode (index, input, ind+1, &model, 1);
1062     }
1063     switch (len)
1064     {
1065     case SS_REJECT:
1066       break;
1067 
1068     case 0:
1069       if (index<0) fprintf (stderr,  "Match 0.\n");
1070     default:
1071       if (ind<255)
1072       {
1073         ind++;
1074         input[ind] = 0;
1075       }
1076       break;
1077     }
1078     in++;
1079     if ((in&0x0f)==0)
1080     {
1081       count++;
1082       t1 = time(0);
1083       if (t1-t0 > 5 || t0-t1 > 5)
1084       {
1085         break;
1086       }
1087     }
1088   }
1089   return count;
1090 }
1091 
1092 static void
print_version()1093 print_version ()
1094 {
1095   fprintf (stderr, "mytool version %s GNU (C) Gaspar Sinai\n", SD_YUDIT_VERSION);
1096 }
1097 
1098 static void
usage()1099 usage ()
1100 {
1101   fprintf (stderr,  "usage: mytool [-convert {myc|mys|my|bumap|cumap} [-info [-showkeys]] [-test] [-encode] [-decode]");
1102   fprintf (stderr,  " [-write new-map] [-name map-name]  [-nocomment] [-comment comment] [-type map-type]");
1103   fprintf (stderr,  " [-my binary-mapfile] [-benchmark] [-high|-low]");
1104   fprintf (stderr,  " [-uni:1,2 plainfile [-8]] [-runi:1,2 plainfile [-8]]");
1105   fprintf (stderr,  " [-mys mapfile] [-rmys reverse-map-file]");
1106   fprintf (stderr,  " [-kmap keymap-file] [-rkmap reverse-keymap-file]\n");
1107   fprintf (stderr,  " [-installdir \"Install Dir\"] [-pipecmd command [args]]\n");
1108   fprintf (stderr,  "   -info     print out useful info about the map.\n");
1109   fprintf (stderr,  "   -test     print out useful info about the map and test it.\n");
1110   fprintf (stderr,  "   -strip    delete the state machine, before doing anything else.\n");
1111   fprintf (stderr,  "   -name     Assign a max 32-byte-long name.\n");
1112   fprintf (stderr,  "   -comment  Assign a comment of arbitrary length.\n");
1113   fprintf (stderr,  "   -type     Assign a map type. 0=None, 1=Font, 2=kmap - not used.\n");
1114   fprintf (stderr,  "   -encode   build a state machine for all encoding maps.\n");
1115   fprintf (stderr,  "   -decode   build a state machine for all decoding maps.\n");
1116   fprintf (stderr,  "   -write    write out the latest map before exiting.\n");
1117   fprintf (stderr,  "   -convert  {mys|c|my} convert the file to 'c' or 'my' \n");
1118   fprintf (stderr,  "   -uni:local,unicode  a 16 bit file format with columns precified.\n");
1119   fprintf (stderr,  "   -runi:local,unicode  a 16 bit file format in reverse with columns precified.\n");
1120   fprintf (stderr,  "   -my       assign a fully specified binary mapfile to input.\n");
1121   fprintf (stderr,  "   -mys      assign a fully specified mapfile source to input.\n");
1122   fprintf (stderr,  "   -rmys     same as mys but key - value pairs will be reversed.\n");
1123   fprintf (stderr,  "   -kmap     assign a fully specified keymap file source to input.\n");
1124   fprintf (stderr,  "   -rkmap    same as kmap but key - value pairs will be reversed.\n");
1125 }
1126