1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 only, as
6  * published by the Free Software Foundation.  Oracle designates this
7  * particular file as subject to the "Classpath" exception as provided
8  * by Oracle in the LICENSE file that accompanied this code.
9  *
10  * This code is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * version 2 for more details (a copy is included in the LICENSE file that
14  * accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License version
17  * 2 along with this work; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21  * or visit www.oracle.com if you need additional information or have any
22  * questions.
23  *
24  */
25 
26 /*
27  *
28  * (C) Copyright IBM Corp.  and others 1998-2013 - All Rights Reserved
29  *
30  */
31 
32 #include "LETypes.h"
33 #include "MorphTables.h"
34 #include "StateTables.h"
35 #include "MorphStateTables.h"
36 #include "SubtableProcessor2.h"
37 #include "StateTableProcessor2.h"
38 #include "IndicRearrangementProcessor2.h"
39 #include "LEGlyphStorage.h"
40 #include "LESwaps.h"
41 
42 U_NAMESPACE_BEGIN
43 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndicRearrangementProcessor2)44 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndicRearrangementProcessor2)
45 
46 IndicRearrangementProcessor2::IndicRearrangementProcessor2(
47       const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success)
48   : StateTableProcessor2(morphSubtableHeader, success), indicRearrangementSubtableHeader(morphSubtableHeader, success),
49   entryTable(stHeader, success, entryTableOffset, LE_UNBOUNDED_ARRAY)
50 {
51 }
52 
~IndicRearrangementProcessor2()53 IndicRearrangementProcessor2::~IndicRearrangementProcessor2()
54 {
55 }
56 
beginStateTable()57 void IndicRearrangementProcessor2::beginStateTable()
58 {
59     firstGlyph = 0;
60     lastGlyph = 0;
61 }
62 
processStateEntry(LEGlyphStorage & glyphStorage,le_int32 & currGlyph,EntryTableIndex2 index,LEErrorCode & success)63 le_uint16 IndicRearrangementProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph,
64                                                           EntryTableIndex2 index, LEErrorCode &success)
65 {
66     const IndicRearrangementStateEntry2 *entry = entryTable.getAlias(index, success);
67     if (LE_FAILURE(success)) return 0; // TODO - what to return in bad state?
68     le_uint16 newState = SWAPW(entry->newStateIndex); // index to the new state
69     IndicRearrangementFlags  flags =  (IndicRearrangementFlags) SWAPW(entry->flags);
70 
71     if (currGlyph < 0 || currGlyph >= glyphStorage.getGlyphCount()) {
72        success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
73        return 0;
74     }
75 
76     if (flags & irfMarkFirst) {
77         firstGlyph = currGlyph;
78     }
79 
80     if (flags & irfMarkLast) {
81         lastGlyph = currGlyph;
82     }
83 
84     doRearrangementAction(glyphStorage, (IndicRearrangementVerb) (flags & irfVerbMask), success);
85 
86     if (!(flags & irfDontAdvance)) {
87         currGlyph += dir;
88     }
89 
90     return newState; // index to new state
91 }
92 
endStateTable()93 void IndicRearrangementProcessor2::endStateTable()
94 {
95 }
96 
doRearrangementAction(LEGlyphStorage & glyphStorage,IndicRearrangementVerb verb,LEErrorCode & success) const97 void IndicRearrangementProcessor2::doRearrangementAction(LEGlyphStorage &glyphStorage, IndicRearrangementVerb verb, LEErrorCode &success) const
98 {
99     LEGlyphID a, b, c, d;
100     le_int32 ia, ib, ic, id, ix, x;
101 
102     if (LE_FAILURE(success)) return;
103 
104     if (verb == irvNoAction) {
105         return;
106     }
107     if (firstGlyph > lastGlyph) {
108         success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
109         return;
110     }
111 
112     switch(verb)
113     {
114     case irvxA:
115         if (firstGlyph == lastGlyph) break;
116         if (firstGlyph + 1 < firstGlyph) {
117             success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
118             break;
119         }
120         a = glyphStorage[firstGlyph];
121         ia = glyphStorage.getCharIndex(firstGlyph, success);
122         x = firstGlyph + 1;
123 
124         while (x <= lastGlyph) {
125             glyphStorage[x - 1] = glyphStorage[x];
126             ix = glyphStorage.getCharIndex(x, success);
127             glyphStorage.setCharIndex(x - 1, ix, success);
128             x += 1;
129         }
130 
131         glyphStorage[lastGlyph] = a;
132         glyphStorage.setCharIndex(lastGlyph, ia, success);
133         break;
134 
135     case irvDx:
136         if (firstGlyph == lastGlyph) break;
137         if (lastGlyph - 1 > lastGlyph) {
138             success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
139             break;
140         }
141         d = glyphStorage[lastGlyph];
142         id = glyphStorage.getCharIndex(lastGlyph, success);
143         x = lastGlyph - 1;
144 
145         while (x >= firstGlyph) {
146             glyphStorage[x + 1] = glyphStorage[x];
147             ix = glyphStorage.getCharIndex(x, success);
148             glyphStorage.setCharIndex(x + 1, ix, success);
149             x -= 1;
150         }
151 
152         glyphStorage[firstGlyph] = d;
153         glyphStorage.setCharIndex(firstGlyph, id, success);
154         break;
155 
156     case irvDxA:
157         a = glyphStorage[firstGlyph];
158         ia = glyphStorage.getCharIndex(firstGlyph, success);
159         id = glyphStorage.getCharIndex(lastGlyph,  success);
160 
161         glyphStorage[firstGlyph] = glyphStorage[lastGlyph];
162         glyphStorage[lastGlyph] = a;
163 
164         glyphStorage.setCharIndex(firstGlyph, id, success);
165         glyphStorage.setCharIndex(lastGlyph,  ia, success);
166         break;
167 
168     case irvxAB:
169         if ((firstGlyph + 2 < firstGlyph) ||
170             (lastGlyph - firstGlyph < 1)) { // difference == 1 is a no-op, < 1 is an error.
171             success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
172             break;
173         }
174         a = glyphStorage[firstGlyph];
175         b = glyphStorage[firstGlyph + 1];
176         ia = glyphStorage.getCharIndex(firstGlyph, success);
177         ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
178         x = firstGlyph + 2;
179 
180         while (x <= lastGlyph) {
181             glyphStorage[x - 2] = glyphStorage[x];
182             ix = glyphStorage.getCharIndex(x, success);
183             glyphStorage.setCharIndex(x - 2, ix, success);
184             x += 1;
185         }
186 
187         glyphStorage[lastGlyph - 1] = a;
188         glyphStorage[lastGlyph] = b;
189 
190         glyphStorage.setCharIndex(lastGlyph - 1, ia, success);
191         glyphStorage.setCharIndex(lastGlyph, ib, success);
192         break;
193 
194     case irvxBA:
195         if ((firstGlyph + 2 < firstGlyph) ||
196             (lastGlyph - firstGlyph < 1)) {
197             success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
198             break;
199         }
200         a = glyphStorage[firstGlyph];
201         b = glyphStorage[firstGlyph + 1];
202         ia = glyphStorage.getCharIndex(firstGlyph, success);
203         ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
204         x = firstGlyph + 2;
205 
206         while (x <= lastGlyph) {
207             glyphStorage[x - 2] = glyphStorage[x];
208             ix = glyphStorage.getCharIndex(x, success);
209             glyphStorage.setCharIndex(x - 2, ix, success);
210             x += 1;
211         }
212 
213         glyphStorage[lastGlyph - 1] = b;
214         glyphStorage[lastGlyph] = a;
215 
216         glyphStorage.setCharIndex(lastGlyph - 1, ib, success);
217         glyphStorage.setCharIndex(lastGlyph, ia, success);
218         break;
219 
220     case irvCDx:
221         if ((lastGlyph - 2 > lastGlyph) ||
222             (lastGlyph - firstGlyph < 1)) {
223             success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
224             break;
225         }
226         c = glyphStorage[lastGlyph - 1];
227         d = glyphStorage[lastGlyph];
228         ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
229         id = glyphStorage.getCharIndex(lastGlyph, success);
230         x = lastGlyph - 2;
231 
232         while (x >= firstGlyph) {
233             glyphStorage[x + 2] = glyphStorage[x];
234             ix = glyphStorage.getCharIndex(x, success);
235             glyphStorage.setCharIndex(x + 2, ix, success);
236             x -= 1;
237         }
238 
239         glyphStorage[firstGlyph] = c;
240         glyphStorage[firstGlyph + 1] = d;
241 
242         glyphStorage.setCharIndex(firstGlyph, ic, success);
243         glyphStorage.setCharIndex(firstGlyph + 1, id, success);
244         break;
245 
246     case irvDCx:
247         if ((lastGlyph - 2 > lastGlyph) ||
248             (lastGlyph - firstGlyph < 1)) {
249             success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
250             break;
251         }
252         c = glyphStorage[lastGlyph - 1];
253         d = glyphStorage[lastGlyph];
254         ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
255         id = glyphStorage.getCharIndex(lastGlyph, success);
256         x = lastGlyph - 2;
257 
258         while (x >= firstGlyph) {
259             glyphStorage[x + 2] = glyphStorage[x];
260             ix = glyphStorage.getCharIndex(x, success);
261             glyphStorage.setCharIndex(x + 2, ix, success);
262             x -= 1;
263         }
264 
265         glyphStorage[firstGlyph] = d;
266         glyphStorage[firstGlyph + 1] = c;
267 
268         glyphStorage.setCharIndex(firstGlyph, id, success);
269         glyphStorage.setCharIndex(firstGlyph + 1, ic, success);
270         break;
271 
272     case irvCDxA:
273         if ((lastGlyph - 2 > lastGlyph) ||
274             (lastGlyph - firstGlyph < 2)) {
275             success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
276             break;
277         }
278         a = glyphStorage[firstGlyph];
279         c = glyphStorage[lastGlyph - 1];
280         d = glyphStorage[lastGlyph];
281         ia = glyphStorage.getCharIndex(firstGlyph, success);
282         ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
283         id = glyphStorage.getCharIndex(lastGlyph, success);
284         x = lastGlyph - 2;
285 
286         while (x > firstGlyph) {
287             glyphStorage[x + 1] = glyphStorage[x];
288             ix = glyphStorage.getCharIndex(x, success);
289             glyphStorage.setCharIndex(x + 1, ix, success);
290             x -= 1;
291         }
292 
293         glyphStorage[firstGlyph] = c;
294         glyphStorage[firstGlyph + 1] = d;
295         glyphStorage[lastGlyph] = a;
296 
297         glyphStorage.setCharIndex(firstGlyph, ic, success);
298         glyphStorage.setCharIndex(firstGlyph + 1, id, success);
299         glyphStorage.setCharIndex(lastGlyph, ia, success);
300         break;
301 
302     case irvDCxA:
303         if ((lastGlyph - 2 > lastGlyph) ||
304             (lastGlyph - firstGlyph < 2)) {
305             success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
306             break;
307         }
308         a = glyphStorage[firstGlyph];
309         c = glyphStorage[lastGlyph - 1];
310         d = glyphStorage[lastGlyph];
311         ia = glyphStorage.getCharIndex(firstGlyph, success);
312         ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
313         id = glyphStorage.getCharIndex(lastGlyph, success);
314         x = lastGlyph - 2;
315 
316         while (x > firstGlyph) {
317             glyphStorage[x + 1] = glyphStorage[x];
318             ix = glyphStorage.getCharIndex(x, success);
319             glyphStorage.setCharIndex(x + 1, ix, success);
320             x -= 1;
321         }
322 
323         glyphStorage[firstGlyph] = d;
324         glyphStorage[firstGlyph + 1] = c;
325         glyphStorage[lastGlyph] = a;
326 
327         glyphStorage.setCharIndex(firstGlyph, id, success);
328         glyphStorage.setCharIndex(firstGlyph + 1, ic, success);
329         glyphStorage.setCharIndex(lastGlyph, ia, success);
330         break;
331 
332     case irvDxAB:
333         if ((firstGlyph + 2 < firstGlyph) ||
334             (lastGlyph - firstGlyph < 2)) {
335             success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
336             break;
337         }
338         a = glyphStorage[firstGlyph];
339         b = glyphStorage[firstGlyph + 1];
340         d = glyphStorage[lastGlyph];
341         ia = glyphStorage.getCharIndex(firstGlyph, success);
342         ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
343         id = glyphStorage.getCharIndex(lastGlyph, success);
344         x = firstGlyph + 2;
345 
346         while (x < lastGlyph) {
347             glyphStorage[x - 2] = glyphStorage[x];
348             ix = glyphStorage.getCharIndex(x, success);
349             glyphStorage.setCharIndex(x - 2, ix, success);
350             x += 1;
351         }
352 
353         glyphStorage[firstGlyph] = d;
354         glyphStorage[lastGlyph - 1] = a;
355         glyphStorage[lastGlyph] = b;
356 
357         glyphStorage.setCharIndex(firstGlyph, id, success);
358         glyphStorage.setCharIndex(lastGlyph - 1, ia, success);
359         glyphStorage.setCharIndex(lastGlyph, ib, success);
360         break;
361 
362     case irvDxBA:
363         if ((firstGlyph + 2 < firstGlyph) ||
364             (lastGlyph - firstGlyph < 2)) {
365             success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
366             break;
367         }
368         a = glyphStorage[firstGlyph];
369         b = glyphStorage[firstGlyph + 1];
370         d = glyphStorage[lastGlyph];
371         ia = glyphStorage.getCharIndex(firstGlyph, success);
372         ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
373         id = glyphStorage.getCharIndex(lastGlyph, success);
374         x = firstGlyph + 2;
375 
376         while (x < lastGlyph) {
377             glyphStorage[x - 2] = glyphStorage[x];
378             ix = glyphStorage.getCharIndex(x, success);
379             glyphStorage.setCharIndex(x - 2, ix, success);
380             x += 1;
381         }
382 
383         glyphStorage[firstGlyph] = d;
384         glyphStorage[lastGlyph - 1] = b;
385         glyphStorage[lastGlyph] = a;
386 
387         glyphStorage.setCharIndex(firstGlyph, id, success);
388         glyphStorage.setCharIndex(lastGlyph - 1, ib, success);
389         glyphStorage.setCharIndex(lastGlyph, ia, success);
390         break;
391 
392     case irvCDxAB:
393         if (lastGlyph - firstGlyph < 3) {
394             success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
395             break;
396         }
397         a = glyphStorage[firstGlyph];
398         b = glyphStorage[firstGlyph + 1];
399 
400         glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1];
401         glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph];
402 
403         glyphStorage[lastGlyph - 1] = a;
404         glyphStorage[lastGlyph] = b;
405 
406         ia = glyphStorage.getCharIndex(firstGlyph, success);
407         ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
408         ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
409         id = glyphStorage.getCharIndex(lastGlyph, success);
410 
411         glyphStorage.setCharIndex(firstGlyph, ic, success);
412         glyphStorage.setCharIndex(firstGlyph + 1, id, success);
413 
414         glyphStorage.setCharIndex(lastGlyph - 1, ia, success);
415         glyphStorage.setCharIndex(lastGlyph, ib, success);
416         break;
417 
418     case irvCDxBA:
419         if (lastGlyph - firstGlyph < 3) {
420             success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
421             break;
422         }
423         a = glyphStorage[firstGlyph];
424         b = glyphStorage[firstGlyph + 1];
425 
426         glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1];
427         glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph];
428 
429         glyphStorage[lastGlyph - 1] = b;
430         glyphStorage[lastGlyph] = a;
431 
432         ia = glyphStorage.getCharIndex(firstGlyph, success);
433         ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
434         ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
435         id = glyphStorage.getCharIndex(lastGlyph, success);
436 
437         glyphStorage.setCharIndex(firstGlyph, ic, success);
438         glyphStorage.setCharIndex(firstGlyph + 1, id, success);
439 
440         glyphStorage.setCharIndex(lastGlyph - 1, ib, success);
441         glyphStorage.setCharIndex(lastGlyph, ia, success);
442         break;
443 
444     case irvDCxAB:
445         if (lastGlyph - firstGlyph < 3) {
446             success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
447             break;
448         }
449         a = glyphStorage[firstGlyph];
450         b = glyphStorage[firstGlyph + 1];
451 
452         glyphStorage[firstGlyph] = glyphStorage[lastGlyph];
453         glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1];
454 
455         glyphStorage[lastGlyph - 1] = a;
456         glyphStorage[lastGlyph] = b;
457 
458         ia = glyphStorage.getCharIndex(firstGlyph, success);
459         ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
460         ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
461         id = glyphStorage.getCharIndex(lastGlyph, success);
462 
463         glyphStorage.setCharIndex(firstGlyph, id, success);
464         glyphStorage.setCharIndex(firstGlyph + 1, ic, success);
465 
466         glyphStorage.setCharIndex(lastGlyph - 1, ia, success);
467         glyphStorage.setCharIndex(lastGlyph, ib, success);
468         break;
469 
470     case irvDCxBA:
471         if (lastGlyph - firstGlyph < 3) {
472             success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
473             break;
474         }
475         a = glyphStorage[firstGlyph];
476         b = glyphStorage[firstGlyph + 1];
477 
478         glyphStorage[firstGlyph] = glyphStorage[lastGlyph];
479         glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1];
480 
481         glyphStorage[lastGlyph - 1] = b;
482         glyphStorage[lastGlyph] = a;
483 
484         ia = glyphStorage.getCharIndex(firstGlyph, success);
485         ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
486         ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
487         id = glyphStorage.getCharIndex(lastGlyph, success);
488 
489         glyphStorage.setCharIndex(firstGlyph, id, success);
490         glyphStorage.setCharIndex(firstGlyph + 1, ic, success);
491 
492         glyphStorage.setCharIndex(lastGlyph - 1, ib, success);
493         glyphStorage.setCharIndex(lastGlyph, ia, success);
494         break;
495 
496     default:
497         break;
498     }
499 
500 }
501 
502 U_NAMESPACE_END
503