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