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/SUniMap.h"
21 #include "stoolkit/SBMap.h"
22 #include "stoolkit/SBinHashtable.h"
23 #include "stoolkit/SIO.h"
24 #include "stoolkit/SUtil.h"
25 #include <stdio.h>
26 
27 static SS_UCS4 getMaxBytes (unsigned int inp);
28 
29 /**
30  * A unicode Map. It maps SV_UCS2 to SV_UCS4 or SString<->SV_UCS4
31  * It is generally useful when mapping UCS4 to Font encodings and
32  * Keyboard trasliterations to unicode strings.
33  *
34  * This is a tamed version of SBMap.
35  * @author: Gaspar Sinai <gaspar@yudit.org>
36  * @version: 2000-05-12
37  */
38 
39 class SUniMapDelegate
40 {
41 public:
42   SUniMapDelegate(const SString& name, SBMap* _map);
43   ~SUniMapDelegate();
44   /* these routines supposed to speed it up */
45   SString name;
46   int    count;
47   SBMap* map;
48 };
49 
50 
51 /**
52  * We use the delegate to hide the ugly SBMap and
53  * maintain one reference in a chache
54  */
SUniMapDelegate(const SString & n,SBMap * _map)55 SUniMapDelegate::SUniMapDelegate(const SString& n, SBMap* _map)
56 {
57   name = n;
58   map = _map;
59   count = 1;
60 }
~SUniMapDelegate()61 SUniMapDelegate::~SUniMapDelegate()
62 {
63   delete map;
64 }
65 
66 typedef SBinHashtable<SUniMapDelegate*> SUniMapHashtable;
67 /*
68  * This canche is consulted when a new map is requested.
69  */
70 static SUniMapHashtable mapCache;
71 
72 static SStringVector searchPath("/,maps,../maps,/etc/maps,../mytool/uni,../mytool/kmap,../mytool/mys,mytool/uni,mytool/kmap,mytool/mys,uni,kmap,mys");
73 
74 static void _uniAppend (SString* s, SS_UCS4 u);
75 
76 void
setPath(const SStringVector & l)77 SUniMap::setPath (const SStringVector& l)
78 {
79   searchPath = l;
80 }
81 
82 /**
83  * search files for property in order and set the path to the
84  * property. Always add YUDIT_DATA/data
85  */
86 void
guessPath(const SStringVector & files,const SString & property)87 SUniMap::guessPath (const SStringVector& files, const SString& property)
88 {
89 
90   SStringVector outDataPath;
91   for (unsigned int i=0; i<files.size(); i++)
92   {
93     SProperties p;
94     loadProperties (files[i], &p);
95     if (p.get (property))
96     {
97       SStringVector v(p[property], ",:;");
98       for (unsigned int j=0; j<v.size(); j++)
99       {
100          outDataPath.append (v[j]);
101       }
102     }
103   }
104   SString c1 = getHome();
105   c1.append ("/.yudit/data");
106   SString c2 = getPrefix();
107   c2.append ("/data");
108   if (outDataPath.size()!=0)
109   {
110     outDataPath.append (c1);
111     outDataPath.append (c2);
112     setPath (outDataPath);
113   }
114   else
115   {
116     outDataPath.append (c1);
117     outDataPath.append (c2);
118     outDataPath.append (getPath());
119     setPath (outDataPath);
120   }
121 }
122 /**
123  * get the path using the "yudit.default.path"
124  */
125 void
guessPath()126 SUniMap::guessPath()
127 {
128   SString c1 = getHome();
129   c1.append ("/.yudit/yudit.properties");
130   SString c2 = getPrefix();
131   c2.append ("/config/yudit.properties");
132   SStringVector v;
133   v.append (c1);
134   v.append (c2);
135   guessPath (v, "yudit.datapath");
136 }
137 
138 const SStringVector&
getPath()139 SUniMap::getPath ()
140 {
141   return searchPath;
142 }
143 
144 /**
145  * Vector available maps
146  */
147 SStringVector
list()148 SUniMap::list()
149 {
150   SStringVector ret;
151   for (unsigned int i=0; i<searchPath.size(); i++)
152   {
153     SDir d(searchPath[i]);
154     SStringVector l = d.list("*.my");
155     for (unsigned int j=0; j<l.size(); j++)
156     {
157       SString s = l[j];
158       s.truncate(s.size()-3);
159       ret.append (s);
160     }
161   }
162   return SStringVector (ret);
163 }
164 
165 /**
166  * This is a straight map.
167  */
SUniMap(void)168 SUniMap::SUniMap (void)
169 {
170   delegate = 0;
171   dmodel = 0;
172   emodel = 0;
173   dmodel4 = 0;
174   emodel4 = 0;
175   eindex = -1;
176   dindex = -1;
177   bumap = 0;
178   ok = true;
179 }
180 
181 /**
182  * Try to load the delegate with the name.
183  * The suffix ".my" will be added to the name here in this routine.
184  */
SUniMap(const SString & name)185 SUniMap::SUniMap (const SString& name)
186 {
187   bumap = 0;
188   load (name);
189 }
190 
191 /**
192  * Try to load the map. The name is the name without file extension .my
193  */
194 void
load(const SString & name)195 SUniMap::load (const SString& name)
196 {
197   delegate = 0;
198   dmodel = 0;
199   emodel = 0;
200   dmodel4 = 0;
201   emodel4 = 0;
202   eindex = -1;
203   dindex = -1;
204   ok = false;
205 
206   if (mapCache.get (name))
207   {
208     SUniMapDelegate* d = mapCache[name];
209     d->count++;
210     delegate = d;
211     ok = true;
212     setModel(1, 2, 2, 1);
213     return;
214   }
215   SString n (name);
216   n.append (".my");
217   SFile f(n, searchPath);
218   if (f.size()  <= 0) return ;
219   SFileImage i = f.getFileImage();
220   if ( i.size() <= 0) return;
221   SBMap* b = new SBMap();
222   CHECK_NEW (b);
223   if (!b->setFileImage(i))
224   {
225     delete b;
226     return;
227   }
228   SUniMapDelegate* ud = new SUniMapDelegate(name, b);
229   CHECK_NEW (ud);
230   delegate = ud;
231   mapCache.put (name, ud);
232   setModel(1, 2, 2, 1);
233   bumap = (ud->map->isUMap()) ? ud->map : 0;
234   ok = true;
235 }
236 
237 /**
238  * Allocates new models
239  * @param din is the decode input size 0=SS_WORD8 1=SS_WORD16 3=SS_WORD32
240  * @param dout is the decode output size
241  * @param ein is the encode input size
242  * @param eout is the encode output size
243  */
244 void
setModel(int din,int dout,int ein,int eout)245 SUniMap::setModel(int din, int dout, int ein, int eout)
246 {
247   SUniMapDelegate* d = (SUniMapDelegate*) delegate;
248   SBMap *map = d->map;
249 
250   eindex = indexOf(true);
251   dindex = indexOf(false);
252 
253   emodel = 0; dmodel = 0;
254   if (eindex>=0)
255   {
256       /* From 4 byte  to 2 byte */
257       emodel = new SStateModel (ein, map->getInWordSize (eindex),
258             map->getOutWordSize (eindex), eout);
259       emodel4 = new SStateModel (2, map->getInWordSize (eindex),
260             map->getOutWordSize (eindex), 2);
261   }
262 
263   if (dindex>=0)
264   {
265       /* From 2byte  to 4 byte */
266       dmodel = new SStateModel (din, map->getInWordSize (dindex),
267             map->getOutWordSize (dindex), dout);
268       dmodel4 = new SStateModel (2, map->getInWordSize (dindex),
269             map->getOutWordSize (dindex), 2);
270   }
271 }
272 
273 /**
274  * Copy an existing map
275  * @param m is an existing map
276  */
SUniMap(const SUniMap & m)277 SUniMap::SUniMap (const SUniMap &m)
278 {
279   dmodel = 0;
280   emodel = 0;
281   dmodel4 = 0;
282   emodel4 = 0;
283   delegate = 0;
284   dindex = -1;
285   eindex = -1;
286   bumap = m.bumap;
287   if (!m.isOK())
288   {
289     ok = false;
290   }
291   else
292   {
293     SUniMapDelegate* d = (SUniMapDelegate*) m.delegate;
294     if (d)
295     {
296       d->count++;
297       delegate = d;
298       dindex = m.dindex;
299       eindex = m.eindex;
300       setModel(1, 2, 2, 1);
301     }
302     ok = true;
303   }
304 }
305 
306 /**
307  * Assign a map
308  */
309 SUniMap&
operator =(const SUniMap & m)310 SUniMap::operator = (const SUniMap &m)
311 {
312   if (&m == this) return *this;
313   derefer();
314   dmodel = 0;
315   emodel = 0;
316   dmodel4 = 0;
317   emodel4 = 0;
318   delegate = 0;
319   dindex = -1;
320   eindex = -1;
321   bumap = m.bumap;
322   reset();
323   if (!m.isOK())
324   {
325     ok = false;
326   }
327   else
328   {
329     SUniMapDelegate* d = (SUniMapDelegate*) m.delegate;
330     if (d)
331     {
332       d->count++;
333       delegate = d;
334       dindex = m.dindex;
335       eindex = m.eindex;
336       setModel(1, 2, 2, 1);
337     }
338     ok = true;
339   }
340   return *this;
341 }
342 
~SUniMap()343 SUniMap::~SUniMap()
344 {
345   if (delegate !=0) derefer();
346 }
347 
348 /**
349  * dereference the current map
350  */
351 void
derefer()352 SUniMap::derefer()
353 {
354   if (isOK())
355   {
356     SUniMapDelegate* d = (SUniMapDelegate*) delegate;
357     if (d!=0)
358     {
359       d->count--;
360       if (d->count==0)
361       {
362         // FIXME: if I delete it it gets deleted twice !
363         //mapCache.remove (d->name);
364         //fprintf (stderr, "FIXME: STRANGE DELETE %*.*s\n", SSARGS(d->name));
365         //delete d;
366       }
367       if (dmodel) delete ((SStateModel*) dmodel);
368       if (emodel) delete ((SStateModel*) emodel);
369       if (dmodel4) delete ((SStateModel*) dmodel4);
370       if (emodel4) delete ((SStateModel*) emodel4);
371     }
372   }
373 }
374 
375 /**
376  * A simplistic encoder.
377  * @return the UCS2 value of the first decoded value or zero
378  */
379 SS_UCS2
encode(SS_UCS4 in)380 SUniMap::encode (SS_UCS4 in)
381 {
382   if (bumap)
383   {
384     if (in > 0xffff) return 0;
385     return ((SBMap*) bumap)->encode (in);
386   }
387   if (!ok) return 0;
388   if (in > 0xffff) return 0;
389   if (delegate==0) return (SS_UCS2) in;
390   SUniMapDelegate* d = (SUniMapDelegate*) delegate;
391   SBMap *map = d->map;
392 
393   SStateModel* enc = (SStateModel*) emodel;
394   if (enc == 0) return 0;
395   SS_UCS2 maxBytes = getMaxBytes (map->getInWordSize (eindex));
396   if (in > maxBytes || maxBytes==0) return 0;
397 
398   int len = map->encode (eindex, &in, 1, enc, 0);
399   if (len < 0)
400   {
401     enc->reset(); return 0;
402   }
403   if (enc->out.length != 1)
404   {
405     enc->reset(); return 0;
406   }
407   SS_UCS2 retVle = enc->out.u.u16[0];
408   enc->reset();
409   return retVle;
410 }
411 
412 /**
413  * A simplistic decoder.
414  * @return the UCS4 value of the first decoded value or zero
415  */
416 SS_UCS4
decode(SS_UCS2 in)417 SUniMap::decode (SS_UCS2 in)
418 {
419   if (bumap)
420   {
421     return ((SBMap*) bumap)->decode (in);
422   }
423   if (!ok) return 0;
424   if (delegate==0) return (SS_UCS4) in;
425   SUniMapDelegate* d = (SUniMapDelegate*) delegate;
426   SBMap *map = d->map;
427 
428   SStateModel* dec = (SStateModel*) dmodel;
429   if (dec == 0) return 0;
430 
431   SS_UCS4 maxBytes = getMaxBytes (map->getInWordSize (dindex));
432   if (in > maxBytes && maxBytes == 0) return 0;
433   int len = map->encode (dindex, &in, 1, dec, 0);
434   if (len < 0)
435   {
436     dec->reset(); return 0;
437   }
438   if (dec->out.length != 1)
439   {
440     dec->reset(); return 0;
441   }
442   SS_UCS4 retVle = dec->out.u.u32[0];
443   dec->reset();
444   return retVle;
445 }
446 
447 SObject*
clone() const448 SUniMap::clone() const
449 {
450   SObject* n = new SUniMap(*this);
451   CHECK_NEW (n);
452   return n;
453 }
454 
455 /**
456  * @param encode is true if we are looking at the encoding map
457  * return 0 if map was designed to accept SS_WORD8
458  *        1 if map was designed to accept SS_WORD16
459  *        2 if map was designed to accept SS_WORD32
460  *        3 if map was designed to accept SS_WORD64
461  *        -1 if map is not initialized
462  */
463 int
getInWordSize(bool encode)464 SUniMap::getInWordSize (bool encode)
465 {
466   if (!ok) return -1;
467   if (delegate ==0) return 1;
468   int index = indexOf(encode);
469   if (index < 0) return -1;
470   SUniMapDelegate* d = (SUniMapDelegate*) delegate;
471   return d->map->getInWordSize(index);
472 }
473 
474 /**
475  * @param encode is true if we are looking at the encoding map
476  * return 0 if map was designed to produce SS_WORD8
477  *        1 if map was designed to produce SS_WORD16
478  *        2 if map was designed to produce SS_WORD32
479  *        3 if map was designed to produce SS_WORD64
480  *        -1 if map is not initialized
481  */
482 int
getOutWordSize(bool encode)483 SUniMap::getOutWordSize (bool encode)
484 {
485   if (!ok) return -1;
486   if (delegate ==0) return 1;
487   int index = indexOf(encode);
488   if (index < 0) return -1;
489   SUniMapDelegate* d = (SUniMapDelegate*) delegate;
490   return d->map->getOutWordSize(index);
491 }
492 
493 /**
494  * Get the index in the map
495  * @param encode is true if we are looking at the encoding map
496  * @return the index in the SBMap or -1
497  */
498 int
indexOf(bool encode) const499 SUniMap::indexOf(bool encode) const
500 {
501   SUniMapDelegate* d = (SUniMapDelegate*) delegate;
502   if (d==0) return -1;
503   SBMap *map = d->map;
504   for (int i=0; i<map->getSize(); i++)
505   {
506     if (map->getType(i)==(encode ? SBMap::SBMap_ENCODE : SBMap::SBMap_DECODE))
507     {
508       return i;
509     }
510   }
511   return -1;
512 }
513 
514 /**
515  * return true if the map is 'usable'
516  * a useless map is a map that could not be found.
517  */
518 bool
isOK() const519 SUniMap::isOK() const
520 {
521   return ok;
522 }
523 
524 void
reset()525 SUniMap::reset ()
526 {
527   reset (false);
528   reset (true);
529 }
530 
531 void
reset(bool en)532 SUniMap::reset(bool en)
533 {
534   if (en)
535   {
536     ucs4vIn.clear();
537     sstringOut.clear();
538   }
539   else
540   {
541     sstringIn.clear();
542     ucs4vOut.clear();
543   }
544 }
545 
546 void
undo(bool encode)547 SUniMap::undo (bool encode)
548 {
549   if (encode)
550   {
551     if (ucs4vIn.size() > 0) ucs4vIn.truncate(ucs4vIn.size()-1);
552   }
553   else
554   {
555     if (sstringIn.size() > 0) sstringIn.truncate(sstringIn.size()-1);
556   }
557 }
558 
559 /**
560  * Decode the input string
561  * if in.size() is zero flush it.
562  * It can return a zero sized array, in this case more input is needed.
563  */
564 const SV_UCS4&
decode(const SString & in)565 SUniMap::decode (const SString& in)
566 {
567   ucs4vOut.clear ();
568   sstringIn.append(in);
569   unsigned int i;
570   if (dmodel==0)
571   {
572     for (i=0; i<sstringIn.size(); i++)
573     {
574       ucs4vOut.append (sstringIn[i]);
575     }
576     sstringIn.clear();
577     return ucs4vOut;
578   }
579   SV_UCS2 buffer;
580   for (i=0; i<sstringIn.size(); i++)
581   {
582     buffer.append (SS_UCS2((unsigned char)sstringIn[i]));
583   }
584   SStateModel* model = (SStateModel*) dmodel;
585   model->reset();
586   SUniMapDelegate* delg = (SUniMapDelegate*) delegate;
587   SBMap* map = (delg==0 || model==0) ? 0 : delg->map;
588 
589   // Now go in circles and append till matches.
590   int st;
591   unsigned int fullsize = buffer.size();
592   i=0;
593   while (i<fullsize)
594   {
595     if (map ==0)
596     {
597       st = SS_REJECT;
598     }
599     else
600     {
601       model->reset ();
602       int more = (in.size()>0)?1:0;
603       /* imposing a limit of 10 because map->circle sucks. */
604       /* FIXME we really need a better map and encoding  */
605       unsigned int bsz = ((int)(buffer.size()-i) > 10)
606           ? 10 : buffer.size()-i;
607       st = map->circle (SBMap::SBMap_DECODE, &buffer.array()[i],
608           (int)(bsz), model, more);
609     }
610 
611     if (st == SS_ACCEPT)
612     {
613        model->reset ();
614        int more = (in.size()>0)?1:0;
615        st = map->circle (SBMap::SBMap_DECODE, &buffer.array()[i],
616           (int)(buffer.size()-i), model, more);
617        if (st == SS_ACCEPT)
618        {
619          break;
620        }
621     }
622 
623     // Append stuff as it is and crunch buffer.
624     if (st == SS_REJECT)
625     {
626       ucs4vOut.append ((SS_UCS4)buffer[i]);
627       i++;
628     }
629     // There is a match here. append the output and
630     // Shift the input.
631     else if (st>0)
632     {
633       ucs4vOut.append ((SS_UCS4*)model->out.u.u32, model->out.length);
634       while (st--)
635       {
636         i++;
637       }
638     }
639     // Provision for the bad maps.
640     else
641     {
642       //fprintf (stderr, "SUniMap:: decode bad map zero matched!\n");
643       ucs4vOut.append ((SS_UCS4)buffer[i]);
644       i++;
645     }
646   }
647   SString vrest;
648   while (i<fullsize)
649   {
650     vrest.append (sstringIn[i]);
651     i++;
652   }
653   sstringIn = vrest;
654   return ucs4vOut;
655 }
656 
657 const SString&
remainder() const658 SUniMap::remainder() const
659 {
660   return sstringIn;
661 }
662 
663 const SString&
encode(const SV_UCS4 & in)664 SUniMap::encode (const SV_UCS4& in)
665 {
666   sstringOut.clear ();
667   ucs4vIn.append(in);
668   unsigned int i;
669   if (emodel==0)
670   {
671     for (i=0; i<ucs4vIn.size(); i++)
672     {
673       _uniAppend (&sstringOut, ucs4vIn[i]);
674     }
675     ucs4vIn.clear();
676     return sstringOut;
677   }
678   SStateModel* model = (SStateModel*) emodel;
679   model->reset();
680   SUniMapDelegate* delg = (SUniMapDelegate*) delegate;
681   SBMap* map = (delg==0 || model==0) ? 0 : delg->map;
682 
683   // Now go in circles and append till matches.
684   int st;
685   unsigned int fullsize = ucs4vIn.size();
686   i=0;
687   while (i<fullsize)
688   {
689     if (map ==0)
690     {
691       st = SS_REJECT;
692     }
693     else
694     {
695       model->reset ();
696       int more = (in.size()>0)?1:0;
697       /* check if map can possible handle our input */
698       SS_UCS4 maxBytes = getMaxBytes (map->getInWordSize (eindex));
699       unsigned int k;
700       for (k=i; k<ucs4vIn.size(); k++)
701       {
702         if (ucs4vIn[k] > maxBytes) break;
703         if ((k-i) >= 10) break; /* FIXME self-imposed limit - map->circle sucks */
704       }
705       if (k==i)
706       {
707         st = SS_REJECT;
708       }
709       else
710       {
711         st = map->circle (SBMap::SBMap_ENCODE,
712               &ucs4vIn.array()[i], (int)(k-i), model, more);
713       }
714     }
715 
716     if (st == SS_ACCEPT)
717     {
718        /* remove self-imposed limit */
719        model->reset ();
720        int more = (in.size()>0)?1:0;
721        /* check if map can possible handle our input */
722        SS_UCS4 maxBytes = getMaxBytes (map->getInWordSize (eindex));
723        unsigned int k;
724        for (k=i; k<ucs4vIn.size(); k++)
725        {
726           if (ucs4vIn[k] > maxBytes) break;
727        }
728        /* k==i was checked before */
729        st = map->circle (SBMap::SBMap_ENCODE,
730             &ucs4vIn.array()[i], (int)(k-i), model, more);
731        if (st == SS_ACCEPT)
732        {
733            break;
734        }
735     }
736 
737     // Append stuff as it is and crunch buffer.
738     if (st == SS_REJECT)
739     {
740       _uniAppend (&sstringOut, ucs4vIn[i]);
741       i++;
742     }
743     // There is a match here. append the output and
744     // Shift the input.
745     else if (st>0)
746     {
747       // Model is not char !
748       for (int j = 0; j<model->out.length; j++)
749       {
750         _uniAppend (&sstringOut, (SS_UCS4) model->out.u.u16[j]);
751       }
752       while (st--)
753       {
754         i++;
755       }
756     }
757     // Provision for the bad maps.
758     else
759     {
760       fprintf (stderr, "SUniMap:: decode bad map zero matched!\n");
761       _uniAppend (&sstringOut, ucs4vIn[i]);
762       i++;
763     }
764   }
765   SV_UCS4 vrest;
766   while (i<fullsize)
767   {
768     vrest.append (ucs4vIn[i]);
769     i++;
770   }
771   ucs4vIn = vrest;
772   return sstringOut;
773 }
774 
775 const SString&
encodeBuffer()776 SUniMap::encodeBuffer()
777 {
778   return sstringIn;
779 }
780 
781 const SV_UCS4&
decodeBuffer()782 SUniMap::decodeBuffer()
783 {
784   return ucs4vIn;
785 }
786 
787 static void
_uniAppend(SString * s,SS_UCS4 u)788 _uniAppend (SString* s, SS_UCS4 u)
789 {
790   if (u < 0x100)
791   {
792     char u8= (char) u;
793     s->append (&u8, 1);
794   }
795   else if (u < 0x10000)
796   {
797     char u16[32];
798     sprintf (u16, "\\u%04x", (unsigned int) u);
799     s->append (u16);
800   }
801   else
802   {
803     char u32[32];
804     sprintf (u32, "\\U%04x", (unsigned int) u);
805     s->append (u32);
806   }
807 }
808 
809 /**
810  * Lift off whetever can be decoded/encoded
811  * This version does not work with circular maps.
812  * @param in is the input
813  * @param inindex is the starting point to process input.
814  * @param out is the output. It can be null.
815  * @praram decode is true if we are decoding.
816  * @return the new index after liftoff.
817  */
818 unsigned int
lift(const SV_UCS4 & in,unsigned int inindex,bool isdecode,SV_UCS4 * out)819 SUniMap::lift (const SV_UCS4& in, unsigned int inindex,
820     bool isdecode, SV_UCS4* out)
821 {
822   if (!ok) return inindex;
823   if (delegate==0) return inindex;
824 
825   /* make sure we don't have too big values */
826   SBMap *map = ((SUniMapDelegate*) delegate)->map;
827 
828   int mindex = isdecode ? dindex : eindex;
829   SS_UCS4 maxBytes = getMaxBytes (map->getInWordSize (mindex));
830   if (in[inindex] > maxBytes || maxBytes == 0) return inindex;
831 
832   if (mindex < 0) return inindex;
833 
834   SStateModel* model = isdecode ?
835        (SStateModel*) dmodel4 : (SStateModel*) emodel4;
836 
837   model->reset();
838 
839   unsigned int realend = in.size();
840   int more = 1;
841   int status = SS_ACCEPT;
842   unsigned int i;
843   for (i=inindex; status == SS_ACCEPT && i < realend; i++)
844   {
845     /* more == 0 would return - correctly, the whole string */
846     if (i+1>=realend || in[i+1] > maxBytes)
847     {
848       more = 0;
849     }
850     status = map->encode (mindex, &in.array()[i], 1, model, more);
851   }
852 
853   if (status <= 0) return inindex;
854   if (out == 0) return inindex + (unsigned int) status;
855 
856   for (i=0; (int)i< model->out.length; i++)
857   {
858     out->append ((SS_UCS4)(model->out.u.u32[i]));
859   }
860   return inindex + (unsigned int) status;
861 }
862 
863 /**
864  * return key value map to see what decodes to what
865  * @param key will contain the keys
866  * @param value will contain the values
867  * @param _size is the maximum size of returned arrays
868  * @return the real size of the arrays.
869  */
870 unsigned int
getDecoderMap(SStringVector * key,SStringVector * value,unsigned int _size)871 SUniMap::getDecoderMap (SStringVector* key, SStringVector* value,
872         unsigned int _size)
873 {
874   if (delegate==0) return 0;
875   /* make sure we don't have too big values */
876   SBMap *map = ((SUniMapDelegate*) delegate)->map;
877   return map->getDecoderMap (key, value, _size);
878 }
879 
880 /**
881  * return true if this is an UMap.
882  * umaps are generally faster.
883  */
884 bool
isUMap() const885 SUniMap::isUMap() const
886 {
887   if (delegate ==0) return true;
888   return ((((SUniMapDelegate*) delegate)->map)->isUMap() !=0);
889 }
890 
891 /**
892  * return true if this is a type 4 bumap
893  */
894 bool
isClustered() const895 SUniMap::isClustered() const
896 {
897   if (delegate ==0) return true;
898   return ((((SUniMapDelegate*) delegate)->map)->mapType==4);
899 }
900 
901   /* For maps with holes */
902 unsigned int
getDecodePosition(SS_UCS4 key)903 SUniMap::getDecodePosition (SS_UCS4 key)
904 {
905   if (dindex < 0) return 0;
906   SUniMapDelegate* d = (SUniMapDelegate*) delegate;
907   SBMap *map = d->map;
908   return map->getLinearPosition((unsigned int)dindex, key);
909 }
910 SS_UCS4
getDecodeKey(unsigned int position)911 SUniMap::getDecodeKey (unsigned int position)
912 {
913   if (dindex < 0) return 0;
914   SUniMapDelegate* d = (SUniMapDelegate*) delegate;
915   SBMap *map = d->map;
916   return map->getLinearKey((unsigned int)dindex, position);
917 }
918 SS_UCS4
getDecodeValue(unsigned int position)919 SUniMap::getDecodeValue (unsigned int position)
920 {
921   if (dindex < 0) return 0;
922   SUniMapDelegate* d = (SUniMapDelegate*) delegate;
923   SBMap *map = d->map;
924   return map->getLinearValue((unsigned int)dindex, position);
925 }
926 
927 unsigned int
getEncodePosition(SS_UCS4 key)928 SUniMap::getEncodePosition (SS_UCS4 key)
929 {
930   if (eindex < 0) return 0;
931   SUniMapDelegate* d = (SUniMapDelegate*) delegate;
932   SBMap *map = d->map;
933   return map->getLinearPosition((unsigned int)eindex, key);
934 }
935 SS_UCS4
getEncodeKey(unsigned int position)936 SUniMap::getEncodeKey (unsigned int position)
937 {
938   if (eindex < 0) return 0;
939   SUniMapDelegate* d = (SUniMapDelegate*) delegate;
940   SBMap *map = d->map;
941   return map->getLinearKey((unsigned int)eindex, position);
942 }
943 SS_UCS4
getEncodeValue(unsigned int position)944 SUniMap::getEncodeValue (unsigned int position)
945 {
946   if (eindex < 0) return 0;
947   SUniMapDelegate* d = (SUniMapDelegate*) delegate;
948   SBMap *map = d->map;
949   return map->getLinearValue((unsigned int)eindex, position);
950 }
951 
952 /**
953  * Convert mys length to max value.
954  * return 0 on fail.
955  */
956 static SS_UCS4
getMaxBytes(unsigned int inp)957 getMaxBytes (unsigned int inp)
958 {
959   /* FIXME: maxBytes algorithm is fixed here. please fix it
960    * in decode and encode - look for maxBytes.
961    */
962   switch (inp)
963   {
964   case 0: return (0xff);
965   case 1: return (0xffff);
966   case 2: return (0xffffffff);
967   }
968   /* don't support 64 bit */
969   return 0;
970 }
971