Gigabeat needs to be power-cycled after bootloader installation.
[Rockbox.git] / firmware / bidi.c
blob336291f68d5d068937fd779922e6251e0b96f8cb
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Gadi Cohen
12 * Largely based on php_hebrev by Zeev Suraski <zeev@php.net>
13 * Heavily modified by Gadi Cohen aka Kinslayer <dragon@wastelands.net>
15 * All files in this archive are subject to the GNU General Public License.
16 * See the file COPYING in the source tree root for full license agreement.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include <stdio.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include "file.h"
26 #include "lcd.h"
27 #include "rbunicode.h"
28 #include "arabjoin.h"
29 #include "scroll_engine.h"
31 //#define _HEB_BUFFER_LENGTH (MAX_PATH + LCD_WIDTH/2 + 3 + 2 + 2) * 2
32 #define _HEB_BLOCK_TYPE_ENG 1
33 #define _HEB_BLOCK_TYPE_HEB 0
34 #define _HEB_ORIENTATION_LTR 1
35 #define _HEB_ORIENTATION_RTL 0
37 #define ischar(c) ((c > 0x0589 && c < 0x0700) || (c >= 0xfb50 && c <= 0xfefc) ? 1 : 0)
38 #define _isblank(c) ((c==' ' || c=='\t') ? 1 : 0)
39 #define _isnewline(c) ((c=='\n' || c=='\r') ? 1 : 0)
40 #define XOR(a,b) ((a||b) && !(a&&b))
42 const arab_t * arab_lookup(unsigned short uchar)
44 if (uchar >= 0x621 && uchar <= 0x63a)
45 return &(jointable[uchar - 0x621]);
46 if (uchar >= 0x640 && uchar <= 0x64a)
47 return &(jointable[uchar - 0x621 - 5]);
48 if (uchar >= 0x671 && uchar <= 0x6d5)
49 return &(jointable[uchar - 0x621 - 5 - 38]);
50 if (uchar == 0x200D) /* Support for the zero-width joiner */
51 return &zwj;
52 return 0;
55 void arabjoin(unsigned short * stringprt, int length){
57 bool connected = false;
58 unsigned short * writeprt = stringprt;
60 const arab_t * prev = 0;
61 const arab_t * cur;
62 const arab_t * ligature = 0;
63 short uchar;
65 int i;
66 for (i = 0; i <= length; i++) {
67 cur = arab_lookup(uchar = *stringprt++);
69 /* Skip non-arabic chars */
70 if (cur == 0) {
71 if (prev) {
72 /* Finish the last char */
73 if (connected) {
74 *writeprt++ = prev->final;
75 connected = false;
76 } else
77 *writeprt++ = prev->isolated;
78 prev = 0;
79 *writeprt++ = uchar;
80 } else {
81 *writeprt++ = uchar;
83 continue;
86 /* nothing to do for arabic char if the previous was non-arabic */
87 if (prev == 0) {
88 prev = cur;
89 continue;
92 /* if it's LAM, check for LAM+ALEPH ligatures */
93 if (prev->isolated == 0xfedd) {
94 switch (cur->isolated) {
95 case 0xfe8d:
96 ligature = &(lamaleph[0]);
97 break;
98 case 0xfe87:
99 ligature = &(lamaleph[1]);
100 break;
101 case 0xfe83:
102 ligature = &(lamaleph[2]);
103 break;
104 case 0xfe81:
105 ligature = &(lamaleph[3]);
109 if (ligature) { /* replace the 2 glyphs by their ligature */
110 prev = ligature;
111 ligature = 0;
112 } else {
113 if (connected) { /* previous char has something connected to it */
114 if (prev->medial && cur->final) /* Can we connect to it? */
115 *writeprt++ = prev->medial;
116 else {
117 *writeprt++ = prev->final;
118 connected = false;
120 } else {
121 if (prev->initial && cur->final) { /* Can we connect to it? */
122 *writeprt++ = prev->initial;
123 connected = true;
124 } else
125 *writeprt++ = prev->isolated;
127 prev = cur;
132 unsigned short *bidi_l2v(const unsigned char *str, int orientation)
134 int length = utf8length(str);
135 static unsigned short utf16_buf[SCROLL_LINE_SIZE];
136 static unsigned short bidi_buf[SCROLL_LINE_SIZE];
137 unsigned short *heb_str, *target, *tmp; // *broken_str
138 int block_start, block_end, block_type, block_length, i;
139 //long max_chars=0;
140 //int begin, end, char_count, orig_begin;
142 //tmp = str;
143 target = tmp = utf16_buf;
144 while (*str)
145 str = utf8decode(str, target++);
146 *target = 0;
148 if (target == utf16_buf) /* empty string */
149 return target;
151 /* properly join any arabic chars */
152 arabjoin(utf16_buf, length);
154 block_start=block_end=block_length=0;
156 heb_str = bidi_buf;
157 if (orientation) {
158 target = heb_str;
159 } else {
160 target = heb_str + length;
161 *target = 0;
162 target--;
165 if (ischar(*tmp))
166 block_type = _HEB_BLOCK_TYPE_HEB;
167 else
168 block_type = _HEB_BLOCK_TYPE_ENG;
170 do {
171 while((XOR(ischar(*(tmp+1)),block_type)
172 || _isblank(*(tmp+1)) || ispunct((int)*(tmp+1))
173 || *(tmp+1)=='\n')
174 && block_end < length-1) {
175 tmp++;
176 block_end++;
177 block_length++;
180 if (block_type != orientation) {
181 while ((_isblank(*tmp) || ispunct((int)*tmp))
182 && *tmp!='/' && *tmp!='-' && block_end>block_start) {
183 tmp--;
184 block_end--;
188 for (i=block_start; i<=block_end; i++) {
189 *target = (block_type == orientation) ? *(utf16_buf+i) : *(utf16_buf+block_end-i+block_start);
190 if (block_type!=orientation) {
191 switch (*target) {
192 case '(':
193 *target = ')';
194 break;
195 case ')':
196 *target = '(';
197 break;
198 default:
199 break;
202 target += orientation ? 1 : -1;
204 block_type = !block_type;
205 block_start=block_end+1;
206 } while(block_end<length-1);
208 *target = 0;
210 #if 0 /* Is this code really necessary? */
211 broken_str = utf16_buf;
212 begin=end=length-1;
213 target = broken_str;
215 while (1) {
216 char_count=0;
217 while ((!max_chars || char_count<max_chars) && begin>0) {
218 char_count++;
219 begin--;
220 if (begin<=0 || _isnewline(heb_str[begin])) {
221 while(begin>0 && _isnewline(heb_str[begin-1])) {
222 begin--;
223 char_count++;
225 break;
228 if (char_count==max_chars) { /* try to avoid breaking words */
229 int new_char_count = char_count;
230 int new_begin = begin;
232 while (new_char_count>0) {
233 if (_isblank(heb_str[new_begin]) ||
234 _isnewline(heb_str[new_begin])) {
235 break;
237 new_begin++;
238 new_char_count--;
240 if (new_char_count>0) {
241 char_count=new_char_count;
242 begin=new_begin;
245 orig_begin=begin;
247 /* if (_isblank(heb_str[begin])) {
248 heb_str[begin]='\n';
249 } */
251 /* skip leading newlines */
252 while (begin<=end && _isnewline(heb_str[begin])) {
253 begin++;
256 /* copy content */
257 for (i=begin; i<=end; i++) {
258 *target = heb_str[i];
259 target++;
262 for (i=orig_begin; i<=end && _isnewline(heb_str[i]); i++) {
263 *target = heb_str[i];
264 target++;
266 begin=orig_begin;
268 if (begin<=0) {
269 *target = 0;
270 break;
272 begin--;
273 end=begin;
275 return broken_str;
276 #endif
277 return heb_str;