summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorMarcoen Hirschberg <marcoen@gmail.com>2005-12-06 13:27:15 +0000
committerMarcoen Hirschberg <marcoen@gmail.com>2005-12-06 13:27:15 +0000
commitb0fee17d6e1a463dcd84568e5997663b69488998 (patch)
treefffce775c4d1636a8bbc9e97669aa99b9378fc15 /firmware
parent01917ec9809f1abff87cb372b700fc09476d343e (diff)
downloadrockbox-b0fee17d6e1a463dcd84568e5997663b69488998.tar.gz
rockbox-b0fee17d6e1a463dcd84568e5997663b69488998.zip
waiting is over: initial unicode commit
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8169 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r--firmware/SOURCES3
-rw-r--r--firmware/arabjoin.h205
-rw-r--r--firmware/bidi.c186
-rw-r--r--firmware/common/unicode.c307
-rw-r--r--firmware/drivers/fat.c165
-rw-r--r--firmware/drivers/lcd-16bit.c26
-rw-r--r--firmware/drivers/lcd-h100-remote.c26
-rw-r--r--firmware/drivers/lcd-h100.c18
-rw-r--r--firmware/drivers/lcd-player.c40
-rw-r--r--firmware/drivers/lcd-recorder.c18
-rw-r--r--firmware/export/bidi.h4
-rw-r--r--firmware/export/font.h13
-rw-r--r--firmware/export/id3.h2
-rw-r--r--firmware/font.c392
-rw-r--r--firmware/font_cache.c224
-rw-r--r--firmware/id3.c211
-rw-r--r--firmware/include/font_cache.h48
-rw-r--r--firmware/include/lru.h46
-rw-r--r--firmware/include/rbunicode.h29
-rw-r--r--firmware/lru.c119
-rw-r--r--firmware/mpeg.c9
-rw-r--r--firmware/powermgmt.c8
22 files changed, 1706 insertions, 393 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index e2e0e44e5d..5a1c9adb7a 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -1,3 +1,4 @@
1common/unicode.c
1#ifdef ROCKBOX_HAS_LOGF 2#ifdef ROCKBOX_HAS_LOGF
2logf.c 3logf.c
3#endif 4#endif
@@ -103,6 +104,8 @@ drivers/rtc.c
103drivers/serial.c 104drivers/serial.c
104#endif /* !SIMULATOR */ 105#endif /* !SIMULATOR */
105#ifdef HAVE_LCD_BITMAP 106#ifdef HAVE_LCD_BITMAP
107lru.c
108font_cache.c
106font.c 109font.c
107#endif 110#endif
108id3.c 111id3.c
diff --git a/firmware/arabjoin.h b/firmware/arabjoin.h
new file mode 100644
index 0000000000..cba498660c
--- /dev/null
+++ b/firmware/arabjoin.h
@@ -0,0 +1,205 @@
1typedef struct {
2 unsigned short isolated;
3 unsigned short final;
4 unsigned short medial;
5 unsigned short initial;
6} arab_t;
7
8//static arab_t dummy = {0,0,0,0};
9static arab_t zwj = {0x20,0x20,0x20,0x20}; //zero-width joiner
10
11static arab_t lamaleph[] = {
12 {0xfefb,0xfefc,0,0},
13 {0xfef9,0xfefa,0,0},
14 {0xfef7,0xfef8,0,0},
15 {0xfef5,0xfef6,0,0}
16};
17
18static arab_t jointable[] = {
19{0xfe80,0x0000,0x0000,0x0000}, // 0x0621
20{0xfe81,0xfe82,0x0000,0x0000}, // 0x0622
21{0xfe83,0xfe84,0x0000,0x0000}, // 0x0623
22{0xfe85,0xfe86,0x0000,0x0000}, // 0x0624
23{0xfe87,0xfe88,0x0000,0x0000}, // 0x0625
24{0xfe89,0xfe8a,0xfe8c,0xfe8b}, // 0x0626
25{0xfe8d,0xfe8e,0x0000,0x0000}, // 0x0627
26{0xfe8f,0xfe90,0xfe92,0xfe91}, // 0x0628
27{0xfe93,0xfe94,0x0000,0x0000}, // 0x0629
28{0xfe95,0xfe96,0xfe98,0xfe97}, // 0x062a
29{0xfe99,0xfe9a,0xfe9c,0xfe9b}, // 0x062b
30{0xfe9d,0xfe9e,0xfea0,0xfe9f}, // 0x062c
31{0xfea1,0xfea2,0xfea4,0xfea3}, // 0x062d
32{0xfea5,0xfea6,0xfea8,0xfea7}, // 0x062e
33{0xfea9,0xfeaa,0x0000,0x0000}, // 0x062f
34{0xfeab,0xfeac,0x0000,0x0000}, // 0x0630
35{0xfead,0xfeae,0x0000,0x0000}, // 0x0631
36{0xfeaf,0xfeb0,0x0000,0x0000}, // 0x0632
37{0xfeb1,0xfeb2,0xfeb4,0xfeb3}, // 0x0633
38{0xfeb5,0xfeb6,0xfeb8,0xfeb7}, // 0x0634
39{0xfeb9,0xfeba,0xfebc,0xfebb}, // 0x0635
40{0xfebd,0xfebe,0xfec0,0xfebf}, // 0x0636
41{0xfec1,0xfec2,0xfec4,0xfec3}, // 0x0637
42{0xfec5,0xfec6,0xfec8,0xfec7}, // 0x0638
43{0xfec9,0xfeca,0xfecc,0xfecb}, // 0x0639
44{0xfecd,0xfece,0xfed0,0xfecf}, // 0x063a
45#if 0
46{0x0000,0x0000,0x0000,0x0000}, // 0x063b
47{0x0000,0x0000,0x0000,0x0000}, // 0x063c
48{0x0000,0x0000,0x0000,0x0000}, // 0x063d
49{0x0000,0x0000,0x0000,0x0000}, // 0x063e
50{0x0000,0x0000,0x0000,0x0000}, // 0x063f
51#endif
52{0x0640,0x0640,0x0640,0x0640}, // 0x0640
53{0xfed1,0xfed2,0xfed4,0xfed3}, // 0x0641
54{0xfed5,0xfed6,0xfed8,0xfed7}, // 0x0642
55{0xfed9,0xfeda,0xfedc,0xfedb}, // 0x0643
56{0xfedd,0xfede,0xfee0,0xfedf}, // 0x0644
57{0xfee1,0xfee2,0xfee4,0xfee3}, // 0x0645
58{0xfee5,0xfee6,0xfee8,0xfee7}, // 0x0646
59{0xfee9,0xfeea,0xfeec,0xfeeb}, // 0x0647
60{0xfeed,0xfeee,0x0000,0x0000}, // 0x0648
61{0xfeef,0xfef0,0x0000,0x0000}, // 0x0649
62{0xfef1,0xfef2,0xfef4,0xfef3}, // 0x064a
63# if 0
64{0x0000,0x0000,0x0000,0x0000}, // 0x064b
65{0x0000,0x0000,0x0000,0x0000}, // 0x064c
66{0x0000,0x0000,0x0000,0x0000}, // 0x064d
67{0x0000,0x0000,0x0000,0x0000}, // 0x064e
68{0x0000,0x0000,0x0000,0x0000}, // 0x064f
69{0x0000,0x0000,0x0000,0x0000}, // 0x0650
70{0x0000,0x0000,0x0000,0x0000}, // 0x0651
71{0x0000,0x0000,0x0000,0x0000}, // 0x0652
72{0x0000,0x0000,0x0000,0x0000}, // 0x0653
73{0x0000,0x0000,0x0000,0x0000}, // 0x0654
74{0x0000,0x0000,0x0000,0x0000}, // 0x0655
75{0x0000,0x0000,0x0000,0x0000}, // 0x0656
76{0x0000,0x0000,0x0000,0x0000}, // 0x0657
77{0x0000,0x0000,0x0000,0x0000}, // 0x0658
78{0x0000,0x0000,0x0000,0x0000}, // 0x0659
79{0x0000,0x0000,0x0000,0x0000}, // 0x065a
80{0x0000,0x0000,0x0000,0x0000}, // 0x065b
81{0x0000,0x0000,0x0000,0x0000}, // 0x065c
82{0x0000,0x0000,0x0000,0x0000}, // 0x065d
83{0x0000,0x0000,0x0000,0x0000}, // 0x065e
84{0x0000,0x0000,0x0000,0x0000}, // 0x065f
85{0x0000,0x0000,0x0000,0x0000}, // 0x0660
86{0x0000,0x0000,0x0000,0x0000}, // 0x0661
87{0x0000,0x0000,0x0000,0x0000}, // 0x0662
88{0x0000,0x0000,0x0000,0x0000}, // 0x0663
89{0x0000,0x0000,0x0000,0x0000}, // 0x0664
90{0x0000,0x0000,0x0000,0x0000}, // 0x0665
91{0x0000,0x0000,0x0000,0x0000}, // 0x0666
92{0x0000,0x0000,0x0000,0x0000}, // 0x0667
93{0x0000,0x0000,0x0000,0x0000}, // 0x0668
94{0x0000,0x0000,0x0000,0x0000}, // 0x0669
95{0x0000,0x0000,0x0000,0x0000}, // 0x066a
96{0x0000,0x0000,0x0000,0x0000}, // 0x066b
97{0x0000,0x0000,0x0000,0x0000}, // 0x066c
98{0x0000,0x0000,0x0000,0x0000}, // 0x066d
99{0x0000,0x0000,0x0000,0x0000}, // 0x066e
100{0x0000,0x0000,0x0000,0x0000}, // 0x066f
101{0x0000,0x0000,0x0000,0x0000}, // 0x0670
102#endif
103{0xfb50,0x0000,0x0000,0x0000}, // 0x0671
104{0x0672,0x0672,0x0000,0x0000}, // 0x0672
105{0x0673,0x0673,0x0000,0x0000}, // 0x0673
106{0x0674,0x0000,0x0000,0x0000}, // 0x0674
107{0x0675,0x0675,0x0000,0x0000}, // 0x0675
108{0x0676,0x0676,0x0000,0x0000}, // 0x0676
109{0xfbdd,0x0677,0x0000,0x0000}, // 0x0677
110{0x0678,0x0678,0x0678,0x0678}, // 0x0678
111{0xfb66,0xfb67,0xfb69,0xfb68}, // 0x0679
112{0xfb5e,0xfb5f,0xfb61,0xfb60}, // 0x067a
113{0xfb52,0xfb53,0xfb55,0xfb54}, // 0x067b
114{0x067c,0x067c,0x067c,0x067c}, // 0x067c
115{0x067d,0x067d,0x067d,0x067d}, // 0x067d
116{0xfb56,0xfb57,0xfb59,0xfb58}, // 0x067e
117{0xfb62,0xfb63,0xfb65,0xfb64}, // 0x067f
118{0xfb5a,0xfb5b,0xfb5d,0xfb5c}, // 0x0680
119{0x0681,0x0681,0x0681,0x0681}, // 0x0681
120{0x0682,0x0682,0x0682,0x0682}, // 0x0682
121{0xfb76,0xfb77,0xfb79,0xfb78}, // 0x0683
122{0xfb72,0xfb73,0xfb75,0xfb74}, // 0x0684
123{0x0685,0x0685,0x0685,0x0685}, // 0x0685
124{0xfb7a,0xfb7b,0xfb7d,0xfb7c}, // 0x0686
125{0xfb7e,0xfb7f,0xfb81,0xfb80}, // 0x0687
126{0xfb88,0xfb89,0x0000,0x0000}, // 0x0688
127{0x0689,0x0689,0x0000,0x0000}, // 0x0689
128{0x068a,0x068a,0x0000,0x0000}, // 0x068a
129{0x068b,0x068b,0x0000,0x0000}, // 0x068b
130{0xfb84,0xfb85,0x0000,0x0000}, // 0x068c
131{0xfb82,0xfb83,0x0000,0x0000}, // 0x068d
132{0xfb86,0xfb87,0x0000,0x0000}, // 0x068e
133{0x068f,0x068f,0x0000,0x0000}, // 0x068f
134{0x0690,0x0690,0x0000,0x0000}, // 0x0690
135{0xfb8c,0xfb8d,0x0000,0x0000}, // 0x0691
136{0x0692,0x0692,0x0000,0x0000}, // 0x0692
137{0x0693,0x0693,0x0000,0x0000}, // 0x0693
138{0x0694,0x0694,0x0000,0x0000}, // 0x0694
139{0x0695,0x0695,0x0000,0x0000}, // 0x0695
140{0x0695,0x0696,0x0000,0x0000}, // 0x0696
141{0x0697,0x0697,0x0000,0x0000}, // 0x0697
142{0xfb8a,0xfb8b,0x0000,0x0000}, // 0x0698
143{0x0699,0x0699,0x0000,0x0000}, // 0x0699
144{0x069a,0x069a,0x069a,0x069a}, // 0x069a
145{0x069b,0x069b,0x069b,0x069b}, // 0x069b
146{0x069c,0x069c,0x069c,0x069c}, // 0x069c
147{0x069d,0x069d,0x069d,0x069d}, // 0x069d
148{0x069e,0x069e,0x069e,0x069e}, // 0x069e
149{0x069f,0x069f,0x069f,0x069f}, // 0x069f
150{0x06a0,0x06a0,0x06a0,0x06a0}, // 0x06a0
151{0x06a1,0x06a1,0x06a1,0x06a1}, // 0x06a1
152{0x06a2,0x06a2,0x06a2,0x06a2}, // 0x06a2
153{0x06a3,0x06a3,0x06a3,0x06a3}, // 0x06a3
154{0xfb6a,0xfb6b,0xfb6d,0xfb6c}, // 0x06a4
155{0x06a5,0x06a5,0x06a5,0x06a5}, // 0x06a5
156{0xfb6e,0xfb6f,0xfb71,0xfb70}, // 0x06a6
157{0x06a7,0x06a7,0x06a7,0x06a7}, // 0x06a7
158{0x06a8,0x06a8,0x06a8,0x06a8}, // 0x06a8
159{0xfb8e,0xfb8f,0xfb91,0xfb90}, // 0x06a9
160{0x06aa,0x06aa,0x06aa,0x06aa}, // 0x06aa
161{0x06ab,0x06ab,0x06ab,0x06ab}, // 0x06ab
162{0x06ac,0x06ac,0x06ac,0x06ac}, // 0x06ac
163{0xfbd3,0xfbd4,0xfbd6,0xfbd5}, // 0x06ad
164{0x06ae,0x06ae,0x06ae,0x06ae}, // 0x06ae
165{0xfb92,0xfb93,0xfb95,0xfb94}, // 0x06af
166{0x06b0,0x06b0,0x06b0,0x06b0}, // 0x06b0
167{0xfb9a,0xfb9b,0xfb9d,0xfb9c}, // 0x06b1
168{0x06b2,0x06b2,0x06b2,0x06b2}, // 0x06b2
169{0xfb96,0xfb97,0xfb99,0xfb98}, // 0x06b3
170{0x06b4,0x06b4,0x06b4,0x06b4}, // 0x06b4
171{0x06b5,0x06b5,0x06b5,0x06b5}, // 0x06b5
172{0x06b6,0x06b6,0x06b6,0x06b6}, // 0x06b6
173{0x06b7,0x06b7,0x06b7,0x06b7}, // 0x06b7
174{0x0000,0x0000,0x0000,0x0000}, // 0x06b8
175{0x0000,0x0000,0x0000,0x0000}, // 0x06b9
176{0xfb9e,0xfb9f,0x06ba,0x06ba}, // 0x06ba
177{0xfba0,0xfba1,0xfba3,0xfba2}, // 0x06bb
178{0x06bc,0x06bc,0x06bc,0x06bc}, // 0x06bc
179{0x06bd,0x06bd,0x06bd,0x06bd}, // 0x06bd
180{0xfbaa,0xfbab,0xfbad,0xfbac}, // 0x06be
181{0x0000,0x0000,0x0000,0x0000}, // 0x06bf
182{0xfba4,0xfba5,0x0000,0x0000}, // 0x06c0
183{0x06c1,0x06c1,0x06c1,0x06c1}, // 0x06c1
184{0x06c2,0x06c2,0x0000,0x0000}, // 0x06c2
185{0x06c3,0x06c3,0x0000,0x0000}, // 0x06c3
186{0x06c4,0x06c4,0x0000,0x0000}, // 0x06c4
187{0x06c5,0x06c5,0x0000,0x0000}, // 0x06c5
188{0x06c6,0x06c6,0x0000,0x0000}, // 0x06c6
189{0x06c7,0x06c7,0x0000,0x0000}, // 0x06c7
190{0x06c8,0x06c8,0x0000,0x0000}, // 0x06c8
191{0x06c9,0x06c9,0x0000,0x0000}, // 0x06c9
192{0x06ca,0x06ca,0x0000,0x0000}, // 0x06ca
193{0x06cb,0x06cb,0x0000,0x0000}, // 0x06cb
194{0x06cc,0x06cc,0x06cc,0x06cc}, // 0x06cc
195{0x06cd,0x06cd,0x0000,0x0000}, // 0x06cd
196{0x06ce,0x06ce,0x06ce,0x06ce}, // 0x06ce
197{0x0000,0x0000,0x0000,0x0000}, // 0x06cf
198{0x06d0,0x06d0,0x06d0,0x06d0}, // 0x06d0
199{0x06d1,0x06d1,0x06d1,0x06d1}, // 0x06d1
200{0xfbae,0xfbaf,0x0000,0x0000}, // 0x06d2
201{0xfbb0,0xfbb1,0x0000,0x0000}, // 0x06d3
202{0x0000,0x0000,0x0000,0x0000}, // 0x06d4
203{0x06d5,0x0000,0x0000,0x0000} // 0x06d5
204};
205
diff --git a/firmware/bidi.c b/firmware/bidi.c
index dcb44999ec..93c1dd0951 100644
--- a/firmware/bidi.c
+++ b/firmware/bidi.c
@@ -24,75 +24,168 @@
24#include <ctype.h> 24#include <ctype.h>
25#include "file.h" 25#include "file.h"
26#include "lcd.h" 26#include "lcd.h"
27#include "rbunicode.h"
28#include "arabjoin.h"
27 29
28#define _HEB_BUFFER_LENGTH MAX_PATH + LCD_WIDTH/2 + 3 + 2 + 2 30//#define _HEB_BUFFER_LENGTH (MAX_PATH + LCD_WIDTH/2 + 3 + 2 + 2) * 2
29#define _HEB_BLOCK_TYPE_ENG 1 31#define _HEB_BLOCK_TYPE_ENG 1
30#define _HEB_BLOCK_TYPE_HEB 0 32#define _HEB_BLOCK_TYPE_HEB 0
31#define _HEB_ORIENTATION_LTR 1 33#define _HEB_ORIENTATION_LTR 1
32#define _HEB_ORIENTATION_RTL 0 34#define _HEB_ORIENTATION_RTL 0
33 35
34#define ischar(c) (((((unsigned char) c)>=193) && (((unsigned char) c)<=250)) ? 1 : 0) 36#define ischar(c) ((c > 0x0589 && c < 0x0700) || (c >= 0xfb50 && c <= 0xfefc) ? 1 : 0)
35#define _isblank(c) (((((unsigned char) c)==' ' || ((unsigned char) c)=='\t')) ? 1 : 0) 37#define _isblank(c) ((c==' ' || c=='\t') ? 1 : 0)
36#define _isnewline(c) (((((unsigned char) c)=='\n' || ((unsigned char) c)=='\r')) ? 1 : 0) 38#define _isnewline(c) ((c=='\n' || c=='\r') ? 1 : 0)
37#define XOR(a,b) ((a||b) && !(a&&b)) 39#define XOR(a,b) ((a||b) && !(a&&b))
38 40
39bool bidi_support_enabled = false; 41arab_t * arab_lookup(unsigned short uchar)
42{
43 if (uchar >= 0x621 && uchar <= 0x63a)
44 return &(jointable[uchar - 0x621]);
45 if (uchar >= 0x640 && uchar <= 0x64a)
46 return &(jointable[uchar - 0x621 - 5]);
47 if (uchar >= 0x671 && uchar <= 0x6d5)
48 return &(jointable[uchar - 0x621 - 5 - 38]);
49 if (uchar == 0x200D) /* Support for the zero-width joiner */
50 return &zwj;
51 return 0;
52}
53
54void arabjoin(unsigned short * stringprt, int length){
55
56 bool connected = false;
57 unsigned short * writeprt = stringprt;
58
59 arab_t * prev = 0;
60 arab_t * cur;
61 arab_t * ligature = 0;
62 short uchar;
40 63
41unsigned char *bidi_l2v(const char *str, int orientation) 64 int i;
65 for (i = 0; i <= length; i++) {
66 cur = arab_lookup(uchar = *stringprt++);
67
68 /* Skip non-arabic chars */
69 if (cur == 0) {
70 if (prev) {
71 /* Finish the last char */
72 if (connected) {
73 *writeprt++ = prev->final;
74 connected = false;
75 } else
76 *writeprt++ = prev->isolated;
77 prev = 0;
78 *writeprt++ = uchar;
79 } else {
80 *writeprt++ = uchar;
81 }
82 continue;
83 }
84
85 /* nothing to do for arabic char if the previous was non-arabic */
86 if (prev == 0) {
87 prev = cur;
88 continue;
89 }
90
91 /* if it's LAM, check for LAM+ALEPH ligatures */
92 if (prev->isolated == 0xfedd) {
93 switch (cur->isolated) {
94 case 0xfe8d:
95 ligature = &(lamaleph[0]);
96 break;
97 case 0xfe87:
98 ligature = &(lamaleph[1]);
99 break;
100 case 0xfe83:
101 ligature = &(lamaleph[2]);
102 break;
103 case 0xfe81:
104 ligature = &(lamaleph[3]);
105 }
106 }
107
108 if (ligature) { /* replace the 2 glyphs by their ligature */
109 prev = ligature;
110 ligature = 0;
111 } else {
112 if (connected) { /* previous char has something connected to it */
113 if (prev->medial && cur->final) /* Can we connect to it? */
114 *writeprt++ = prev->medial;
115 else {
116 *writeprt++ = prev->final;
117 connected = false;
118 }
119 } else {
120 if (prev->initial && cur->final) { /* Can we connect to it? */
121 *writeprt++ = prev->initial;
122 connected = true;
123 } else
124 *writeprt++ = prev->isolated;
125 }
126 prev = cur;
127 }
128 }
129}
130
131unsigned short *bidi_l2v(const unsigned char *str, int orientation)
42{ 132{
43 static unsigned char buf_heb_str[_HEB_BUFFER_LENGTH]; 133 int length = utf8length(str);
44 static unsigned char buf_broken_str[_HEB_BUFFER_LENGTH]; 134 static unsigned short utf16_buf[MAX_PATH+1];
45 const unsigned char *tmp; 135 static unsigned short bidi_buf[MAX_PATH+1];
46 unsigned char *heb_str, *target, *opposite_target, *broken_str; 136 unsigned short *heb_str, *target, *tmp; // *broken_str
47 int block_start, block_end, block_type, block_length, i; 137 int block_start, block_end, block_type, block_length, i;
48 int block_ended; 138 //long max_chars=0;
49 long max_chars=0; 139 //int begin, end, char_count, orig_begin;
50 int begin, end, char_count, orig_begin;
51 140
52 if (!str || !*str) 141 if (!str || !*str)
53 return (unsigned char *)""; 142 return &(unsigned short){0};
143
144 //tmp = str;
145 target = tmp = utf16_buf;
146 while (*str)
147 str = utf8decode(str, target++);
148 *target = 0;
54 149
55 tmp = (unsigned char *)str; 150 /* properly join any arabic chars */
56 block_start=block_end=0; 151 arabjoin(utf16_buf, length);
57 block_ended=0;
58 152
59 heb_str = buf_heb_str; 153 block_start=block_end=block_length=0;
154
155 heb_str = bidi_buf;
60 if (orientation) { 156 if (orientation) {
61 target = heb_str; 157 target = heb_str;
62 opposite_target = heb_str + strlen(str);
63 } else { 158 } else {
64 target = heb_str + strlen(str); 159 target = heb_str + length;
65 opposite_target = heb_str;
66 *target = 0; 160 *target = 0;
67 target--; 161 target--;
68 } 162 }
69 163
70 block_length=0;
71 if (ischar(*tmp)) 164 if (ischar(*tmp))
72 block_type = _HEB_BLOCK_TYPE_HEB; 165 block_type = _HEB_BLOCK_TYPE_HEB;
73 else 166 else
74 block_type = _HEB_BLOCK_TYPE_ENG; 167 block_type = _HEB_BLOCK_TYPE_ENG;
75 168
76 do { 169 do {
77 while((XOR(ischar((int)*(tmp+1)),block_type) 170 while((XOR(ischar(*(tmp+1)),block_type)
78 || _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1)) 171 || _isblank(*(tmp+1)) || ispunct((int)*(tmp+1))
79 || (int)*(tmp+1)=='\n') 172 || *(tmp+1)=='\n')
80 && block_end<(int)strlen(str)-1) { 173 && block_end < length-1) {
81 tmp++; 174 tmp++;
82 block_end++; 175 block_end++;
83 block_length++; 176 block_length++;
84 } 177 }
85 178
86 if (block_type != orientation) { 179 if (block_type != orientation) {
87 while ((_isblank((int)*tmp) || ispunct((int)*tmp)) 180 while ((_isblank(*tmp) || ispunct((int)*tmp))
88 && *tmp!='/' && *tmp!='-' && block_end>block_start) { 181 && *tmp!='/' && *tmp!='-' && block_end>block_start) {
89 tmp--; 182 tmp--;
90 block_end--; 183 block_end--;
91 } 184 }
92 } 185 }
93 186
94 for (i=block_start; i<=block_end; i++) { 187 for (i=block_start; i<=block_end; i++) {
95 *target = (block_type == orientation) ? *(str+i) : *(str+block_end-i+block_start); 188 *target = (block_type == orientation) ? *(utf16_buf+i) : *(utf16_buf+block_end-i+block_start);
96 if (block_type!=orientation) { 189 if (block_type!=orientation) {
97 switch (*target) { 190 switch (*target) {
98 case '(': 191 case '(':
@@ -109,12 +202,15 @@ unsigned char *bidi_l2v(const char *str, int orientation)
109 } 202 }
110 block_type = !block_type; 203 block_type = !block_type;
111 block_start=block_end+1; 204 block_start=block_end+1;
112 } while(block_end<(int)strlen(str)-1); 205 } while(block_end<length-1);
113 206
114 broken_str = buf_broken_str; 207 *target = 0;
115 begin=end=strlen(str)-1; 208
209#if 0 /* Is this code really necessary? */
210 broken_str = utf16_buf;
211 begin=end=length-1;
116 target = broken_str; 212 target = broken_str;
117 213
118 while (1) { 214 while (1) {
119 char_count=0; 215 char_count=0;
120 while ((!max_chars || char_count<max_chars) && begin>0) { 216 while ((!max_chars || char_count<max_chars) && begin>0) {
@@ -147,9 +243,9 @@ unsigned char *bidi_l2v(const char *str, int orientation)
147 } 243 }
148 orig_begin=begin; 244 orig_begin=begin;
149 245
150 if (_isblank(heb_str[begin])) { 246 /* if (_isblank(heb_str[begin])) {
151 heb_str[begin]='\n'; 247 heb_str[begin]='\n';
152 } 248 } */
153 249
154 /* skip leading newlines */ 250 /* skip leading newlines */
155 while (begin<=end && _isnewline(heb_str[begin])) { 251 while (begin<=end && _isnewline(heb_str[begin])) {
@@ -176,9 +272,7 @@ unsigned char *bidi_l2v(const char *str, int orientation)
176 end=begin; 272 end=begin;
177 } 273 }
178 return broken_str; 274 return broken_str;
275#endif
276 return heb_str;
179} 277}
180 278
181void set_bidi_support(bool setting)
182{
183 bidi_support_enabled = setting;
184}
diff --git a/firmware/common/unicode.c b/firmware/common/unicode.c
new file mode 100644
index 0000000000..a82327e1b1
--- /dev/null
+++ b/firmware/common/unicode.c
@@ -0,0 +1,307 @@
1/* Some conversion functions for handling UTF-8
2 *
3 * copyright Marcoen Hirschberg (2004,2005)
4 *
5 * I got all the info from:
6 * http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
7 * and
8 * http://en.wikipedia.org/wiki/Unicode
9 */
10
11#include <stdio.h>
12#include "file.h"
13#include "debug.h"
14#include "rbunicode.h"
15
16#ifndef O_BINARY
17#define O_BINARY 0
18#endif
19
20#define NUM_TABLES 5
21#define NUM_CODEPAGES 13
22
23static int default_codepage = 0;
24static unsigned short codepage_table[MAX_CP_TABLE_SIZE];
25static int loaded_cp_table = 0;
26
27
28static const unsigned char utf8comp[6] =
29{
30 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
31};
32
33static const char *filename[NUM_TABLES] =
34{
35 CODEPAGE_DIR"/iso.cp",
36 CODEPAGE_DIR"/932.cp", /* SJIS */
37 CODEPAGE_DIR"/936.cp", /* GB2312 */
38 CODEPAGE_DIR"/949.cp", /* KSX1001 */
39 CODEPAGE_DIR"/950.cp" /* BIG5 */
40};
41
42static const char cp_2_table[NUM_CODEPAGES] =
43{
44 0, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5
45};
46
47/* Load codepage file into memory */
48int load_cp_table(int cp)
49{
50 int i=0;
51 int table = cp_2_table[cp];
52 int file, tablesize;
53 unsigned char tmp[2];
54
55 if (cp == 0 || table == loaded_cp_table)
56 return 1;
57
58 file = open(filename[table-1], O_RDONLY|O_BINARY);
59
60 if (file < 0) {
61 DEBUGF("Can't open codepage file: %s.cp\n", filename[table-1]);
62 return 0;
63 }
64
65 tablesize = lseek(file, 0, SEEK_END) / 2;
66 lseek(file, 0, SEEK_SET);
67
68 if (tablesize > MAX_CP_TABLE_SIZE) {
69 DEBUGF("Invalid codepage file: %s.cp\n", filename[table-1]);
70 close(file);
71 return 0;
72 }
73
74 while (i < tablesize) {
75 if (!read(file, tmp, 2)) {
76 DEBUGF("Can't read from codepage file: %s.cp\n", filename[table-1]);
77 loaded_cp_table = 0;
78 return 0;
79 }
80 codepage_table[i++] = (tmp[1] << 8) | tmp[0];
81 }
82
83 loaded_cp_table = table;
84 close(file);
85 return 1;
86}
87
88/* Encode a UCS value as UTF-8 and return a pointer after this UTF-8 char. */
89unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8)
90{
91 int tail = 0;
92
93 if (ucs > 0x7F)
94 while (ucs >> (6*tail + 2))
95 tail++;
96
97 *utf8++ = (ucs >> (6*tail)) | utf8comp[tail];
98 while (tail--)
99 *utf8++ = ((ucs >> (6*tail)) & (MASK ^ 0xFF)) | COMP;
100
101 return utf8;
102}
103
104/* Recode an iso encoded string to UTF-8 */
105unsigned char* iso_decode(const unsigned char *iso, unsigned char *utf8,
106 int cp, int count)
107{
108 unsigned short ucs, tmp;
109
110 if (cp == -1) /* use default codepage */
111 cp = default_codepage;
112
113 if (!load_cp_table(cp)) cp = 0;
114
115 while (count--) {
116 if (*iso < 128)
117 *utf8++ = *iso++;
118
119 else {
120
121 /* cp tells us which codepage to convert from */
122 switch (cp) {
123 case 0x01: /* Greek (ISO-8859-7) */
124 case 0x02: /* Hebrew (ISO-8859-8) */
125 case 0x03: /* Russian (CP1251) */
126 case 0x04: /* Thai (ISO-8859-11) */
127 case 0x05: /* Arabic (ISO-8859-6) */
128 case 0x06: /* Turkish (ISO-8859-9) */
129 case 0x07: /* Latin Extended (ISO-8859-2) */
130 tmp = ((cp-1)*128) + (*iso++ - 128);
131 ucs = codepage_table[tmp];
132 break;
133
134 case 0x08: /* Japanese (SJIS) */
135 if (*iso > 0xA0 && *iso < 0xE0) {
136 tmp = *iso | 0xA100;
137 ucs = codepage_table[tmp];
138 break;
139 }
140
141 case 0x09: /* Simplified Chinese (GB2312) */
142 case 0x0A: /* Korean (KSX1001) */
143 case 0x0B: /* Traditional Chinese (BIG5) */
144 if (count < 1 || !iso[1]) {
145 ucs = *iso++;
146 break;
147 }
148
149 /* we assume all cjk strings are written
150 in big endian order */
151 tmp = *iso++ << 8;
152 tmp |= *iso++;
153 tmp -= 0x8000;
154 ucs = codepage_table[tmp];
155 count--;
156 break;
157
158 case 0x0C: /* UTF-8, do nothing */
159 default:
160 ucs = *iso++;
161 break;
162 }
163
164 if (ucs == 0) /* unknown char, assume invalid encoding */
165 ucs = 0xffff;
166 utf8 = utf8encode(ucs, utf8);
167 }
168 }
169 return utf8;
170}
171
172/* Recode a UTF-16 string with little-endian byte ordering to UTF-8 */
173unsigned char* utf16LEdecode(const unsigned char *utf16, unsigned char *utf8, unsigned int count)
174{
175 unsigned long ucs;
176
177 while (count != 0) {
178 if (utf16[1] >= 0xD8 && utf16[1] < 0xE0) { /* Check for a surrogate pair */
179 ucs = 0x10000 + ((utf16[0] << 10) | ((utf16[1] - 0xD8) << 18) | utf16[2] | ((utf16[3] - 0xDC) << 8));
180 utf16 += 4;
181 count -= 2;
182 } else {
183 ucs = (utf16[0] | (utf16[1] << 8));
184 utf16 += 2;
185 count -= 1;
186 }
187 utf8 = utf8encode(ucs, utf8);
188 }
189 return utf8;
190}
191
192/* Recode a UTF-16 string with big-endian byte ordering to UTF-8 */
193unsigned char* utf16BEdecode(const unsigned char *utf16, unsigned char *utf8, unsigned int count)
194{
195 unsigned long ucs;
196
197 while (count != 0) {
198 if (*utf16 >= 0xD8 && *utf16 < 0xE0) { /* Check for a surrogate pair */
199 ucs = 0x10000 + (((utf16[0] - 0xD8) << 18) | (utf16[1] << 10) | ((utf16[2] - 0xDC) << 8) | utf16[3]);
200 utf16 += 4;
201 count -= 2;
202 } else {
203 ucs = (utf16[0] << 8) | utf16[1];
204 utf16 += 2;
205 count -= 1;
206 }
207 utf8 = utf8encode(ucs, utf8);
208 }
209 return utf8;
210}
211
212/* Recode any UTF-16 string to UTF-8 */
213//unsigned char* utf16decode(unsigned const char *utf16, unsigned char *utf8, unsigned int count)
214unsigned char* utf16decode(const unsigned char *utf16, unsigned char *utf8, unsigned int count)
215{
216 unsigned long ucs;
217
218 ucs = *(utf16++) << 8;
219 ucs |= *(utf16++);
220
221 if (ucs == 0xFEFF) /* Check for BOM */
222 return utf16BEdecode(utf16, utf8, count-1);
223 else if (ucs == 0xFFFE)
224 return utf16LEdecode(utf16, utf8, count-1);
225 else { /* ADDME: Should default be LE or BE? */
226 utf16 -= 2;
227 return utf16BEdecode(utf16, utf8, count);
228 }
229}
230
231/* Return the number of UTF-8 chars in a string */
232unsigned long utf8length(const unsigned char *utf8)
233{
234 unsigned long l = 0;
235
236 while (*utf8 != 0)
237 if ((*utf8++ & MASK) != COMP)
238 l++;
239
240 return l;
241}
242
243/* Decode 1 UTF-8 char and return a pointer to the next char. */
244const unsigned char* utf8decode(const unsigned char *utf8, unsigned short *ucs)
245{
246 unsigned char c = *utf8++;
247 unsigned long code;
248 int tail = 0;
249
250 if ((c <= 0x7f) || (c >= 0xc2)) {
251 /* Start of new character. */
252 if (c < 0x80) { /* U-00000000 - U-0000007F, 1 byte */
253 code = c;
254 } else if (c < 0xe0) { /* U-00000080 - U-000007FF, 2 bytes */
255 tail = 1;
256 code = c & 0x1f;
257 } else if (c < 0xf0) { /* U-00000800 - U-0000FFFF, 3 bytes */
258 tail = 2;
259 code = c & 0x0f;
260 } else if (c < 0xf5) { /* U-00010000 - U-001FFFFF, 4 bytes */
261 tail = 3;
262 code = c & 0x07;
263 } else {
264 /* Invalid size. */
265 code = 0xffff;
266 }
267
268 while (tail-- && ((c = *utf8++) != 0)) {
269 if ((c & 0xc0) == 0x80) {
270 /* Valid continuation character. */
271 code = (code << 6) | (c & 0x3f);
272
273 } else {
274 /* Invalid continuation char */
275 code = 0xffff;
276 utf8--;
277 break;
278 }
279 }
280 } else {
281 /* Invalid UTF-8 char */
282 code = 0xffff;
283 }
284 /* currently we don't support chars above U-FFFF */
285 *ucs = (code < 0x10000) ? code : 0xffff;
286 return utf8;
287}
288
289void set_codepage(int cp)
290{
291 default_codepage = cp;
292 return;
293}
294
295/* seek to a given char in a utf8 string and
296 return its start position in the string */
297int utf8seek(const unsigned char* utf8, int offset)
298{
299 int pos = 0;
300
301 while (offset--) {
302 pos++;
303 while ((utf8[pos] & MASK) == COMP)
304 pos++;
305 }
306 return pos;
307}
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c
index fd09bff0da..559d00b2b9 100644
--- a/firmware/drivers/fat.c
+++ b/firmware/drivers/fat.c
@@ -28,6 +28,7 @@
28#include "system.h" 28#include "system.h"
29#include "timefuncs.h" 29#include "timefuncs.h"
30#include "kernel.h" 30#include "kernel.h"
31#include "rbunicode.h"
31 32
32#define BYTES2INT16(array,pos) \ 33#define BYTES2INT16(array,pos) \
33 (array[pos] | (array[pos+1] << 8 )) 34 (array[pos] | (array[pos+1] << 8 ))
@@ -115,74 +116,6 @@
115#define FAT_BAD_MARK 0x0ffffff7 116#define FAT_BAD_MARK 0x0ffffff7
116#define FAT_EOF_MARK 0x0ffffff8 117#define FAT_EOF_MARK 0x0ffffff8
117 118
118/* filename charset conversion table */
119static const unsigned char unicode2iso8859_2[] = {
120 0x00, 0x00, 0xc3, 0xe3, 0xa1, 0xb1, 0xc6, 0xe6, /* 0x0100 */
121 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0xcf, 0xef, /* 0x0108 */
122 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0110 */
123 0xca, 0xea, 0xcc, 0xec, 0x00, 0x00, 0x00, 0x00, /* 0x0118 */
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0120 */
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0128 */
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0130 */
127 0x00, 0xc5, 0xe5, 0x00, 0x00, 0xa5, 0xb5, 0x00, /* 0x0138 */
128 0x00, 0xa3, 0xb3, 0xd1, 0xf1, 0x00, 0x00, 0xd2, /* 0x0140 */
129 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0148 */
130 0xd5, 0xf5, 0x00, 0x00, 0xc0, 0xe0, 0x00, 0x00, /* 0x0150 */
131 0xd8, 0xf8, 0xa6, 0xb6, 0x00, 0x00, 0xaa, 0xba, /* 0x0158 */
132 0xa9, 0xb9, 0xde, 0xfe, 0xab, 0xbb, 0x00, 0x00, /* 0x0160 */
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0xf9, /* 0x0168 */
134 0xdb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0170 */
135 0x00, 0xac, 0xbc, 0xaf, 0xbf, 0xae, 0xbe, 0x00, /* 0x0178 */
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0180 */
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0188 */
138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0190 */
139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0198 */
140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01a0 */
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01a8 */
142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01b0 */
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01b8 */
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01c0 */
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01c8 */
146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01d0 */
147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01d8 */
148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01e0 */
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01e8 */
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01f0 */
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01f8 */
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0200 */
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0208 */
154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0210 */
155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0218 */
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0220 */
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0228 */
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0230 */
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0238 */
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0240 */
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0248 */
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0250 */
163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0258 */
164 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0260 */
165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0268 */
166 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0270 */
167 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0278 */
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0280 */
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0288 */
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0290 */
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0298 */
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02a0 */
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02a8 */
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02b0 */
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02b8 */
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, /* 0x02c0 */
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02c8 */
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02d0 */
179 0xa2, 0xff, 0x00, 0xb2, 0x00, 0xbd, 0x00, 0x00, /* 0x02d8 */
180 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02e0 */
181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02e8 */
182 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02f0 */
183 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0x02f8 */
184};
185
186struct fsinfo { 119struct fsinfo {
187 unsigned long freecount; /* last known free cluster count */ 120 unsigned long freecount; /* last known free cluster count */
188 unsigned long nextfree; /* first cluster to start looking for free 121 unsigned long nextfree; /* first cluster to start looking for free
@@ -1106,10 +1039,11 @@ static int write_long_name(struct fat_file* file,
1106 unsigned char* entry; 1039 unsigned char* entry;
1107 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR; 1040 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1108 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR; 1041 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1109 unsigned int i, j=0;
1110 unsigned char chksum = 0; 1042 unsigned char chksum = 0;
1111 int nameidx=0, namelen = strlen(name); 1043 unsigned int i, j=0;
1044 unsigned int nameidx=0, namelen = utf8length(name);
1112 int rc; 1045 int rc;
1046 unsigned short name_utf16[namelen + 1];
1113 1047
1114 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n", 1048 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1115 file->firstcluster, firstentry, numentries, name); 1049 file->firstcluster, firstentry, numentries, name);
@@ -1132,6 +1066,11 @@ static int write_long_name(struct fat_file* file,
1132 nameidx < (namelen - NAME_BYTES_PER_ENTRY); 1066 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1133 nameidx += NAME_BYTES_PER_ENTRY); 1067 nameidx += NAME_BYTES_PER_ENTRY);
1134 1068
1069 /* we need to convert the name first */
1070 /* since it is written in reverse order */
1071 for (i = 0; i <= namelen; i++)
1072 name = utf8decode(name, &name_utf16[i]);
1073
1135 for (i=0; i < numentries; i++) { 1074 for (i=0; i < numentries; i++) {
1136 /* new sector? */ 1075 /* new sector? */
1137 if ( idx >= DIR_ENTRIES_PER_SECTOR ) { 1076 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
@@ -1170,7 +1109,7 @@ static int write_long_name(struct fat_file* file,
1170 memset(entry, 0, DIR_ENTRY_SIZE); 1109 memset(entry, 0, DIR_ENTRY_SIZE);
1171 if ( i+1 < numentries ) { 1110 if ( i+1 < numentries ) {
1172 /* longname entry */ 1111 /* longname entry */
1173 int k, l = nameidx; 1112 unsigned int k, l = nameidx;
1174 1113
1175 entry[FATLONG_ORDER] = numentries-i-1; 1114 entry[FATLONG_ORDER] = numentries-i-1;
1176 if (i==0) { 1115 if (i==0) {
@@ -1178,22 +1117,22 @@ static int write_long_name(struct fat_file* file,
1178 entry[FATLONG_ORDER] |= 0x40; 1117 entry[FATLONG_ORDER] |= 0x40;
1179 1118
1180 /* pad name with 0xffff */ 1119 /* pad name with 0xffff */
1181 for (k=1; k<12; k++) entry[k] = 0xff; 1120 for (k=1; k<11; k++) entry[k] = 0xff;
1182 for (k=14; k<26; k++) entry[k] = 0xff; 1121 for (k=14; k<26; k++) entry[k] = 0xff;
1183 for (k=28; k<32; k++) entry[k] = 0xff; 1122 for (k=28; k<32; k++) entry[k] = 0xff;
1184 }; 1123 };
1185 /* set name */ 1124 /* set name */
1186 for (k=0; k<5 && l <= namelen; k++) { 1125 for (k=0; k<5 && l <= namelen; k++) {
1187 entry[k*2 + 1] = name[l++]; 1126 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1188 entry[k*2 + 2] = 0; 1127 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1189 } 1128 }
1190 for (k=0; k<6 && l <= namelen; k++) { 1129 for (k=0; k<6 && l <= namelen; k++) {
1191 entry[k*2 + 14] = name[l++]; 1130 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1192 entry[k*2 + 15] = 0; 1131 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1193 } 1132 }
1194 for (k=0; k<2 && l <= namelen; k++) { 1133 for (k=0; k<2 && l <= namelen; k++) {
1195 entry[k*2 + 28] = name[l++]; 1134 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1196 entry[k*2 + 29] = 0; 1135 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1197 } 1136 }
1198 1137
1199 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME; 1138 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
@@ -1291,7 +1230,7 @@ static int add_dir_entry(struct fat_dir* dir,
1291 1230
1292 /* one dir entry needed for every 13 bytes of filename, 1231 /* one dir entry needed for every 13 bytes of filename,
1293 plus one entry for the short name */ 1232 plus one entry for the short name */
1294 entries_needed = (strlen(name) + (NAME_BYTES_PER_ENTRY-1)) 1233 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1295 / NAME_BYTES_PER_ENTRY + 1; 1234 / NAME_BYTES_PER_ENTRY + 1;
1296 } 1235 }
1297 1236
@@ -2226,58 +2165,6 @@ int fat_opendir(IF_MV2(int volume,)
2226 return 0; 2165 return 0;
2227} 2166}
2228 2167
2229/* convert from unicode to a single-byte charset */
2230static void unicode2iso(const unsigned char* unicode, unsigned char* iso,
2231 int count)
2232{
2233 int i;
2234
2235 for (i=0; i<count; i++) {
2236 int x = i*2;
2237 switch (unicode[x+1]) {
2238 case 0x01: /* latin extended. convert to ISO 8859-2 */
2239 case 0x02:
2240 iso[i] = unicode2iso8859_2[unicode[x]];
2241 break;
2242
2243 case 0x03: /* greek, convert to ISO 8859-7 */
2244 iso[i] = unicode[x] + 0x30;
2245 break;
2246
2247 /* Sergei says most russians use Win1251, so we will too.
2248 Win1251 differs from ISO 8859-5 by an offset of 0x10. */
2249 case 0x04: /* cyrillic, convert to Win1251 */
2250 switch (unicode[x]) {
2251 case 1:
2252 iso[i] = 168;
2253 break;
2254
2255 case 81:
2256 iso[i] = 184;
2257 break;
2258
2259 default:
2260 iso[i] = unicode[x] + 0xb0; /* 0xa0 for ISO 8859-5 */
2261 break;
2262 }
2263 break;
2264
2265 case 0x05: /* hebrew, convert to ISO 8859-8 */
2266 iso[i] = unicode[x] + 0x10;
2267 break;
2268
2269 case 0x06: /* arabic, convert to ISO 8859-6 */
2270 case 0x0e: /* thai, convert to ISO 8859-11 */
2271 iso[i] = unicode[x] + 0xa0;
2272 break;
2273
2274 default:
2275 iso[i] = unicode[x];
2276 break;
2277 }
2278 }
2279}
2280
2281int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) 2168int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2282{ 2169{
2283 bool done = false; 2170 bool done = false;
@@ -2348,7 +2235,8 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2348 2235
2349 /* replace shortname with longname? */ 2236 /* replace shortname with longname? */
2350 if ( longs ) { 2237 if ( longs ) {
2351 int j,l=0; 2238 int j;
2239 unsigned char* utf8 = entry->name;
2352 /* iterate backwards through the dir entries */ 2240 /* iterate backwards through the dir entries */
2353 for (j=longs-1; j>=0; j--) { 2241 for (j=longs-1; j>=0; j--) {
2354 unsigned char* ptr = cached_buf; 2242 unsigned char* ptr = cached_buf;
@@ -2370,16 +2258,11 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2370 index &= SECTOR_SIZE-1; 2258 index &= SECTOR_SIZE-1;
2371 } 2259 }
2372 2260
2373 /* names are stored in unicode, but we 2261 utf8 = utf16LEdecode(ptr + index + 1, utf8, 5);
2374 only grab the low byte (iso8859-1). */ 2262 utf8 = utf16LEdecode(ptr + index + 14, utf8, 6);
2375 unicode2iso(ptr + index + 1, entry->name + l, 5); 2263 utf8 = utf16LEdecode(ptr + index + 28, utf8, 2);
2376 l+= 5;
2377 unicode2iso(ptr + index + 14, entry->name + l, 6);
2378 l+= 6;
2379 unicode2iso(ptr + index + 28, entry->name + l, 2);
2380 l+= 2;
2381 } 2264 }
2382 entry->name[l]=0; 2265 *utf8 = 0;
2383 } 2266 }
2384 done = true; 2267 done = true;
2385 sectoridx = 0; 2268 sectoridx = 0;
diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c
index a4ae6cd553..582050c878 100644
--- a/firmware/drivers/lcd-16bit.c
+++ b/firmware/drivers/lcd-16bit.c
@@ -30,6 +30,7 @@
30#include "debug.h" 30#include "debug.h"
31#include "system.h" 31#include "system.h"
32#include "font.h" 32#include "font.h"
33#include "rbunicode.h"
33#include "bidi.h" 34#include "bidi.h"
34 35
35#define SCROLLABLE_LINES 26 36#define SCROLLABLE_LINES 26
@@ -542,13 +543,13 @@ void lcd_bitmap(const fb_data *src, int x, int y, int width, int height)
542/* put a string at a given pixel position, skipping first ofs pixel columns */ 543/* put a string at a given pixel position, skipping first ofs pixel columns */
543static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) 544static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
544{ 545{
545 int ch; 546 unsigned short ch;
547 unsigned short *ucs;
546 struct font* pf = font_get(curfont); 548 struct font* pf = font_get(curfont);
547 549
548 if (bidi_support_enabled) 550 ucs = bidi_l2v(str, 1);
549 str = bidi_l2v(str, 1);
550 551
551 while ((ch = *str++) != '\0' && x < LCD_WIDTH) 552 while ((ch = *ucs++) != 0 && x < LCD_WIDTH)
552 { 553 {
553 int width; 554 int width;
554 const unsigned char *bits; 555 const unsigned char *bits;
@@ -559,7 +560,7 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
559 ch -= pf->firstchar; 560 ch -= pf->firstchar;
560 561
561 /* get proportional width and glyph bits */ 562 /* get proportional width and glyph bits */
562 width = pf->width ? pf->width[ch] : pf->maxwidth; 563 width = font_get_width(pf,ch);
563 564
564 if (ofs > width) 565 if (ofs > width)
565 { 566 {
@@ -567,8 +568,7 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
567 continue; 568 continue;
568 } 569 }
569 570
570 bits = pf->bits + (pf->offset ? 571 bits = font_get_bits(pf, ch);
571 pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch));
572 572
573 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height); 573 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
574 574
@@ -597,7 +597,7 @@ void lcd_puts_style(int x, int y, const unsigned char *str, int style)
597 return; 597 return;
598 598
599 lcd_getstringsize(str, &w, &h); 599 lcd_getstringsize(str, &w, &h);
600 xpos = xmargin + x*w / strlen(str); 600 xpos = xmargin + x*w / utf8length(str);
601 ypos = ymargin + y*h; 601 ypos = ymargin + y*h;
602 lcd_putsxy(xpos, ypos, str); 602 lcd_putsxy(xpos, ypos, str);
603 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID); 603 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID);
@@ -707,7 +707,7 @@ void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style)
707 end = strchr(s->line, '\0'); 707 end = strchr(s->line, '\0');
708 strncpy(end, string, LCD_WIDTH/2); 708 strncpy(end, string, LCD_WIDTH/2);
709 709
710 s->len = strlen(string); 710 s->len = utf8length(string);
711 s->offset = 0; 711 s->offset = 0;
712 s->startx = x; 712 s->startx = x;
713 s->backward = false; 713 s->backward = false;
@@ -765,9 +765,11 @@ static void scroll_thread(void)
765 } 765 }
766 } 766 }
767 else { 767 else {
768 /* scroll forward the whole time */ 768 /* pause at beginning of line */
769 if (s->offset >= s->width) 769 if (s->offset >= s->width) {
770 s->offset %= s->width; 770 s->offset = 0;
771 s->start_tick = current_tick + scroll_delay * 2;
772 }
771 } 773 }
772 774
773 lastmode = drawmode; 775 lastmode = drawmode;
diff --git a/firmware/drivers/lcd-h100-remote.c b/firmware/drivers/lcd-h100-remote.c
index 33a8b3790d..a2fe63ee97 100644
--- a/firmware/drivers/lcd-h100-remote.c
+++ b/firmware/drivers/lcd-h100-remote.c
@@ -29,6 +29,7 @@
29#include "debug.h" 29#include "debug.h"
30#include "system.h" 30#include "system.h"
31#include "font.h" 31#include "font.h"
32#include "rbunicode.h"
32#include "bidi.h" 33#include "bidi.h"
33 34
34/*** definitions ***/ 35/*** definitions ***/
@@ -1091,13 +1092,13 @@ void lcd_remote_bitmap(const unsigned char *src, int x, int y, int width,
1091/* put a string at a given pixel position, skipping first ofs pixel columns */ 1092/* put a string at a given pixel position, skipping first ofs pixel columns */
1092static void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str) 1093static void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str)
1093{ 1094{
1094 int ch; 1095 unsigned short ch;
1096 unsigned short *ucs;
1095 struct font* pf = font_get(curfont); 1097 struct font* pf = font_get(curfont);
1096 1098
1097 if (bidi_support_enabled) 1099 ucs = bidi_l2v(str, 1);
1098 str = bidi_l2v(str, 1);
1099 1100
1100 while ((ch = *str++) != '\0' && x < LCD_REMOTE_WIDTH) 1101 while ((ch = *ucs++) != 0 && x < LCD_REMOTE_WIDTH)
1101 { 1102 {
1102 int width; 1103 int width;
1103 const unsigned char *bits; 1104 const unsigned char *bits;
@@ -1108,7 +1109,7 @@ static void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str
1108 ch -= pf->firstchar; 1109 ch -= pf->firstchar;
1109 1110
1110 /* get proportional width and glyph bits */ 1111 /* get proportional width and glyph bits */
1111 width = pf->width ? pf->width[ch] : pf->maxwidth; 1112 width = font_get_width(pf, ch);
1112 1113
1113 if (ofs > width) 1114 if (ofs > width)
1114 { 1115 {
@@ -1116,8 +1117,7 @@ static void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str
1116 continue; 1117 continue;
1117 } 1118 }
1118 1119
1119 bits = pf->bits + (pf->offset ? 1120 bits = font_get_bits(pf, ch);
1120 pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch));
1121 1121
1122 lcd_remote_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, 1122 lcd_remote_bitmap_part(bits, ofs, 0, width, x, y, width - ofs,
1123 pf->height); 1123 pf->height);
@@ -1153,7 +1153,7 @@ void lcd_remote_puts_style(int x, int y, const unsigned char *str, int style)
1153 return; 1153 return;
1154 1154
1155 lcd_remote_getstringsize(str, &w, &h); 1155 lcd_remote_getstringsize(str, &w, &h);
1156 xpos = xmargin + x*w / strlen((char *)str); 1156 xpos = xmargin + x*w / utf8length((char *)str);
1157 ypos = ymargin + y*h; 1157 ypos = ymargin + y*h;
1158 lcd_remote_putsxy(xpos, ypos, str); 1158 lcd_remote_putsxy(xpos, ypos, str);
1159 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID); 1159 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID);
@@ -1256,7 +1256,7 @@ void lcd_remote_puts_scroll_style(int x, int y, const unsigned char *string, int
1256 end = strchr(s->line, '\0'); 1256 end = strchr(s->line, '\0');
1257 strncpy(end, (char *)string, LCD_REMOTE_WIDTH/2); 1257 strncpy(end, (char *)string, LCD_REMOTE_WIDTH/2);
1258 1258
1259 s->len = strlen((char *)string); 1259 s->len = utf8length((char *)string);
1260 s->offset = 0; 1260 s->offset = 0;
1261 s->startx = x; 1261 s->startx = x;
1262 s->backward = false; 1262 s->backward = false;
@@ -1323,9 +1323,11 @@ static void scroll_thread(void)
1323 } 1323 }
1324 } 1324 }
1325 else { 1325 else {
1326 /* scroll forward the whole time */ 1326 /* pause at beginning of line */
1327 if (s->offset >= s->width) 1327 if (s->offset >= s->width) {
1328 s->offset %= s->width; 1328 s->offset = 0;
1329 s->start_tick = current_tick + scroll_delay * 2;
1330 }
1329 } 1331 }
1330 1332
1331 lastmode = drawmode; 1333 lastmode = drawmode;
diff --git a/firmware/drivers/lcd-h100.c b/firmware/drivers/lcd-h100.c
index ba959d23de..1199bf04a1 100644
--- a/firmware/drivers/lcd-h100.c
+++ b/firmware/drivers/lcd-h100.c
@@ -28,6 +28,7 @@
28#include "debug.h" 28#include "debug.h"
29#include "system.h" 29#include "system.h"
30#include "font.h" 30#include "font.h"
31#include "rbunicode.h"
31#include "bidi.h" 32#include "bidi.h"
32 33
33/*** definitions ***/ 34/*** definitions ***/
@@ -1014,13 +1015,13 @@ void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height)
1014/* put a string at a given pixel position, skipping first ofs pixel columns */ 1015/* put a string at a given pixel position, skipping first ofs pixel columns */
1015static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) 1016static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
1016{ 1017{
1017 int ch; 1018 unsigned short ch;
1019 unsigned short *ucs;
1018 struct font* pf = font_get(curfont); 1020 struct font* pf = font_get(curfont);
1019 1021
1020 if (bidi_support_enabled) 1022 ucs = bidi_l2v(str, 1);
1021 str = bidi_l2v(str, 1);
1022 1023
1023 while ((ch = *str++) != '\0' && x < LCD_WIDTH) 1024 while ((ch = *ucs++) != 0 && x < LCD_WIDTH)
1024 { 1025 {
1025 int width; 1026 int width;
1026 const unsigned char *bits; 1027 const unsigned char *bits;
@@ -1031,7 +1032,7 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
1031 ch -= pf->firstchar; 1032 ch -= pf->firstchar;
1032 1033
1033 /* get proportional width and glyph bits */ 1034 /* get proportional width and glyph bits */
1034 width = pf->width ? pf->width[ch] : pf->maxwidth; 1035 width = font_get_width(pf,ch);
1035 1036
1036 if (ofs > width) 1037 if (ofs > width)
1037 { 1038 {
@@ -1039,8 +1040,7 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
1039 continue; 1040 continue;
1040 } 1041 }
1041 1042
1042 bits = pf->bits + (pf->offset ? 1043 bits = font_get_bits(pf, ch);
1043 pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch));
1044 1044
1045 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height); 1045 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
1046 1046
@@ -1069,7 +1069,7 @@ void lcd_puts_style(int x, int y, const unsigned char *str, int style)
1069 return; 1069 return;
1070 1070
1071 lcd_getstringsize(str, &w, &h); 1071 lcd_getstringsize(str, &w, &h);
1072 xpos = xmargin + x*w / strlen((char *)str); 1072 xpos = xmargin + x*w / utf8length((char *)str);
1073 ypos = ymargin + y*h; 1073 ypos = ymargin + y*h;
1074 lcd_putsxy(xpos, ypos, str); 1074 lcd_putsxy(xpos, ypos, str);
1075 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID); 1075 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID);
@@ -1178,7 +1178,7 @@ void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style)
1178 end = strchr(s->line, '\0'); 1178 end = strchr(s->line, '\0');
1179 strncpy(end, (char *)string, LCD_WIDTH/2); 1179 strncpy(end, (char *)string, LCD_WIDTH/2);
1180 1180
1181 s->len = strlen((char *)string); 1181 s->len = utf8length((char *)string);
1182 s->offset = 0; 1182 s->offset = 0;
1183 s->startx = x; 1183 s->startx = x;
1184 s->backward = false; 1184 s->backward = false;
diff --git a/firmware/drivers/lcd-player.c b/firmware/drivers/lcd-player.c
index 566c868d7f..d01ec3447f 100644
--- a/firmware/drivers/lcd-player.c
+++ b/firmware/drivers/lcd-player.c
@@ -31,6 +31,7 @@
31#include "system.h" 31#include "system.h"
32#include "font.h" 32#include "font.h"
33#include "lcd-player-charset.h" 33#include "lcd-player-charset.h"
34#include "rbunicode.h"
34 35
35/*** definitions ***/ 36/*** definitions ***/
36 37
@@ -323,9 +324,24 @@ static void lcd_puts_cont_scroll(int x, int y, const unsigned char *string)
323} 324}
324void lcd_puts(int x, int y, const unsigned char *string) 325void lcd_puts(int x, int y, const unsigned char *string)
325{ 326{
327 int i=0;
328 unsigned short ucs;
329 const unsigned char *utf8 = string;
330 unsigned char tmp[12];
331
332 while (*utf8 && i<11) {
333 utf8 = utf8decode(utf8, &ucs);
334 if (ucs < 256)
335 tmp[i++] = ucs;
336 else
337 tmp[i++] = '?';
338 }
339
340 tmp[i] = 0;
341
326 DEBUGF("lcd_puts(%d, %d) -> ", x, y); 342 DEBUGF("lcd_puts(%d, %d) -> ", x, y);
327 scroll[y].mode=SCROLL_MODE_OFF; 343 scroll[y].mode=SCROLL_MODE_OFF;
328 return lcd_puts_cont_scroll(x, y, string); 344 return lcd_puts_cont_scroll(x, y, tmp);
329} 345}
330 346
331void lcd_put_cursor(int x, int y, char cursor_char) 347void lcd_put_cursor(int x, int y, char cursor_char)
@@ -627,14 +643,28 @@ void lcd_bidir_scroll(int percent)
627void lcd_puts_scroll(int x, int y, const unsigned char* string ) 643void lcd_puts_scroll(int x, int y, const unsigned char* string )
628{ 644{
629 struct scrollinfo* s; 645 struct scrollinfo* s;
630 int i; 646 int i=0;
647 unsigned short ucs;
648 const unsigned char *utf8 = string;
649 unsigned char tmp[utf8length(string)+1];
650
651 while (*utf8) {
652 utf8 = utf8decode(utf8, &ucs);
653 if (ucs < 256)
654 tmp[i++] = ucs;
655 else
656 tmp[i++] = '?';
657 }
658
659 tmp[i] = 0;
660
631 661
632 DEBUGF("lcd_puts_scroll(%d, %d, %s)\n", x, y, string); 662 DEBUGF("lcd_puts_scroll(%d, %d, %s)\n", x, y, string);
633 663
634 s = &scroll[y]; 664 s = &scroll[y];
635 665
636 lcd_puts_cont_scroll(x,y,string); 666 lcd_puts_cont_scroll(x,y,tmp);
637 s->textlen = strlen(string); 667 s->textlen = strlen(tmp);
638 668
639 if ( s->textlen > 11-x ) { 669 if ( s->textlen > 11-x ) {
640 s->mode = SCROLL_MODE_RUN; 670 s->mode = SCROLL_MODE_RUN;
@@ -649,7 +679,7 @@ void lcd_puts_scroll(int x, int y, const unsigned char* string )
649 s->jump_scroll_steps=11-x; 679 s->jump_scroll_steps=11-x;
650 s->jump_scroll=jump_scroll; 680 s->jump_scroll=jump_scroll;
651 } 681 }
652 strncpy(s->text,string,sizeof s->text); 682 strncpy(s->text,tmp,sizeof s->text);
653 s->turn_offset=-1; 683 s->turn_offset=-1;
654 if (bidir_limit && (s->textlen < ((11-x)*(100+bidir_limit))/100)) { 684 if (bidir_limit && (s->textlen < ((11-x)*(100+bidir_limit))/100)) {
655 s->turn_offset=s->textlen+x-11; 685 s->turn_offset=s->textlen+x-11;
diff --git a/firmware/drivers/lcd-recorder.c b/firmware/drivers/lcd-recorder.c
index 7e064b8001..081a7a5267 100644
--- a/firmware/drivers/lcd-recorder.c
+++ b/firmware/drivers/lcd-recorder.c
@@ -28,6 +28,7 @@
28#include "system.h" 28#include "system.h"
29#include "font.h" 29#include "font.h"
30#include "hwcompat.h" 30#include "hwcompat.h"
31#include "rbunicode.h"
31#include "bidi.h" 32#include "bidi.h"
32 33
33/*** definitions ***/ 34/*** definitions ***/
@@ -844,13 +845,13 @@ void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height)
844/* put a string at a given pixel position, skipping first ofs pixel columns */ 845/* put a string at a given pixel position, skipping first ofs pixel columns */
845static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) 846static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
846{ 847{
847 int ch; 848 unsigned short ch;
849 unsigned short *ucs;
848 struct font* pf = font_get(curfont); 850 struct font* pf = font_get(curfont);
849 851
850 if (bidi_support_enabled) 852 ucs = bidi_l2v(str, 1);
851 str = bidi_l2v(str, 1);
852 853
853 while ((ch = *str++) != '\0' && x < LCD_WIDTH) 854 while ((ch = *ucs++) != 0 && x < LCD_WIDTH)
854 { 855 {
855 int width; 856 int width;
856 const unsigned char *bits; 857 const unsigned char *bits;
@@ -861,7 +862,7 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
861 ch -= pf->firstchar; 862 ch -= pf->firstchar;
862 863
863 /* get proportional width and glyph bits */ 864 /* get proportional width and glyph bits */
864 width = pf->width ? pf->width[ch] : pf->maxwidth; 865 width = font_get_width(pf,ch);
865 866
866 if (ofs > width) 867 if (ofs > width)
867 { 868 {
@@ -869,8 +870,7 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
869 continue; 870 continue;
870 } 871 }
871 872
872 bits = pf->bits + (pf->offset ? 873 bits = font_get_bits(pf, ch);
873 pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch));
874 874
875 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height); 875 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
876 876
@@ -898,7 +898,7 @@ void lcd_puts_style(int x, int y, const unsigned char *str, int style)
898 return; 898 return;
899 899
900 lcd_getstringsize(str, &w, &h); 900 lcd_getstringsize(str, &w, &h);
901 xpos = xmargin + x*w / strlen(str); 901 xpos = xmargin + x*w / utf8length(str);
902 ypos = ymargin + y*h; 902 ypos = ymargin + y*h;
903 lcd_putsxy(xpos, ypos, str); 903 lcd_putsxy(xpos, ypos, str);
904 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID); 904 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID);
@@ -1007,7 +1007,7 @@ void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style)
1007 end = strchr(s->line, '\0'); 1007 end = strchr(s->line, '\0');
1008 strncpy(end, string, LCD_WIDTH/2); 1008 strncpy(end, string, LCD_WIDTH/2);
1009 1009
1010 s->len = strlen(string); 1010 s->len = utf8length(string);
1011 s->offset = 0; 1011 s->offset = 0;
1012 s->startx = x; 1012 s->startx = x;
1013 s->backward = false; 1013 s->backward = false;
diff --git a/firmware/export/bidi.h b/firmware/export/bidi.h
index 88e2eeb07e..36ff46c6c0 100644
--- a/firmware/export/bidi.h
+++ b/firmware/export/bidi.h
@@ -17,7 +17,5 @@
17 * 17 *
18 ****************************************************************************/ 18 ****************************************************************************/
19#ifndef BIDI_H 19#ifndef BIDI_H
20extern unsigned char *bidi_l2v(const unsigned char *str, int orientation); 20extern unsigned short *bidi_l2v(const unsigned char *str, int orientation);
21extern bool bidi_support_enabled;
22extern void set_bidi_support(bool setting);
23#endif 21#endif
diff --git a/firmware/export/font.h b/firmware/export/font.h
index beb63470bf..ccdb30ff00 100644
--- a/firmware/export/font.h
+++ b/firmware/export/font.h
@@ -31,10 +31,16 @@
31#if LCD_HEIGHT > 64 31#if LCD_HEIGHT > 64
32#define MAX_FONT_SIZE 10000 32#define MAX_FONT_SIZE 10000
33#else 33#else
34#define MAX_FONT_SIZE 4000 34#define MAX_FONT_SIZE 4000
35#endif 35#endif
36#endif 36#endif
37 37
38#ifndef FONT_HEADER_SIZE
39#define FONT_HEADER_SIZE 36
40#endif
41
42#define GLYPH_CACHE_FILE "/.rockbox/.glyphcache"
43
38/* 44/*
39 * Fonts are specified by number, and used for display 45 * Fonts are specified by number, and used for display
40 * of menu information as well as mp3 filename data. 46 * of menu information as well as mp3 filename data.
@@ -88,6 +94,7 @@ struct font {
88 const unsigned short *offset; /* offsets into bitmap data*/ 94 const unsigned short *offset; /* offsets into bitmap data*/
89 const unsigned char *width; /* character widths or NULL if fixed*/ 95 const unsigned char *width; /* character widths or NULL if fixed*/
90 int defaultchar; /* default char (not glyph index)*/ 96 int defaultchar; /* default char (not glyph index)*/
97 long bits_size; /* # bytes of glyph bits*/
91}; 98};
92 99
93/* font routines*/ 100/* font routines*/
@@ -96,6 +103,10 @@ struct font* font_load(const char *path);
96struct font* font_get(int font); 103struct font* font_get(int font);
97void font_reset(void); 104void font_reset(void);
98int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber); 105int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber);
106int font_get_width(struct font* ft, unsigned short ch);
107const unsigned char * font_get_bits(struct font* ft, unsigned short ch);
108void glyph_cache_save(void);
109void glyph_cache_load(void);
99 110
100#else /* HAVE_LCD_BITMAP */ 111#else /* HAVE_LCD_BITMAP */
101 112
diff --git a/firmware/export/id3.h b/firmware/export/id3.h
index df0c61f473..5090534e99 100644
--- a/firmware/export/id3.h
+++ b/firmware/export/id3.h
@@ -94,7 +94,7 @@ struct mp3entry {
94 94
95 /* these following two fields are used for local buffering */ 95 /* these following two fields are used for local buffering */
96 char id3v2buf[300]; 96 char id3v2buf[300];
97 char id3v1buf[3][32]; 97 char id3v1buf[3][92];
98 98
99 /* resume related */ 99 /* resume related */
100 unsigned long offset; /* bytes played */ 100 unsigned long offset; /* bytes played */
diff --git a/firmware/font.c b/firmware/font.c
index 303887701d..e8d5db46b9 100644
--- a/firmware/font.c
+++ b/firmware/font.c
@@ -33,6 +33,10 @@
33#include "file.h" 33#include "file.h"
34#include "debug.h" 34#include "debug.h"
35#include "panic.h" 35#include "panic.h"
36#include "rbunicode.h"
37/* Font cache includes */
38#include "font_cache.h"
39#include "lru.h"
36 40
37#ifndef O_BINARY 41#ifndef O_BINARY
38#define O_BINARY 0 42#define O_BINARY 0
@@ -53,6 +57,16 @@ static unsigned char *freeptr = mbuf;
53static unsigned char *fileptr; 57static unsigned char *fileptr;
54static unsigned char *eofptr; 58static unsigned char *eofptr;
55 59
60/* Font cache structures */
61static struct font_cache font_cache_ui;
62static int fnt_file = -1; /* >=0 if font is cached */
63unsigned long file_width_offset; /* offset to file width data */
64unsigned long file_offset_offset; /* offset to file offset data */
65static void cache_create(int maxwidth, int height);
66static int long_offset = 0;
67static int glyph_file;
68/* End Font cache structures */
69
56void font_init(void) 70void font_init(void)
57{ 71{
58 memset(&font_ui, 0, sizeof(struct font)); 72 memset(&font_ui, 0, sizeof(struct font));
@@ -94,41 +108,12 @@ void font_reset(void)
94 memset(&font_ui, 0, sizeof(struct font)); 108 memset(&font_ui, 0, sizeof(struct font));
95} 109}
96 110
97/* read and load font into incore font structure*/ 111static struct font* font_load_header(struct font *pf)
98struct font* font_load(const char *path)
99{ 112{
100 int fd, filesize; 113 char version[4+1];
101 unsigned short maxwidth, height, ascent, pad; 114 unsigned short maxwidth, height, ascent, pad;
102 unsigned long firstchar, defaultchar, size; 115 unsigned long firstchar, defaultchar, size;
103 unsigned long i, nbits, noffset, nwidth; 116 unsigned long nbits;
104 char version[4+1];
105 struct font* pf = &font_ui;
106
107 /* open and read entire font file*/
108 fd = open(path, O_RDONLY|O_BINARY);
109 if (fd < 0) {
110 DEBUGF("Can't open font: %s\n", path);
111 return NULL;
112 }
113
114 font_reset();
115
116 /* currently, font loading replaces earlier font allocation*/
117 freeptr = (unsigned char *)(((int)mbuf + 3) & ~3);
118
119 fileptr = freeptr;
120 filesize = read(fd, fileptr, MAX_FONT_SIZE);
121 eofptr = fileptr + filesize;
122
123 /* no need for multiple font loads currently*/
124 /*freeptr += filesize;*/
125 /*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/ /* pad freeptr*/
126
127 close(fd);
128 if (filesize == MAX_FONT_SIZE) {
129 DEBUGF("Font %s too large: %d\n", path, filesize);
130 return NULL;
131 }
132 117
133 /* read magic and version #*/ 118 /* read magic and version #*/
134 memset(version, 0, sizeof(version)); 119 memset(version, 0, sizeof(version));
@@ -163,6 +148,14 @@ struct font* font_load(const char *path)
163 /* # words of bitmap_t*/ 148 /* # words of bitmap_t*/
164 if (!readlong(&nbits)) 149 if (!readlong(&nbits))
165 return NULL; 150 return NULL;
151 pf->bits_size = nbits;
152
153 return pf;
154}
155/* Load memory font */
156struct font* font_load_in_memory(struct font* pf)
157{
158 long i, noffset, nwidth;
166 159
167 /* # longs of offset*/ 160 /* # longs of offset*/
168 if (!readlong(&noffset)) 161 if (!readlong(&noffset))
@@ -174,19 +167,44 @@ struct font* font_load(const char *path)
174 167
175 /* variable font data*/ 168 /* variable font data*/
176 pf->bits = (unsigned char *)fileptr; 169 pf->bits = (unsigned char *)fileptr;
177 fileptr += nbits*sizeof(unsigned char); 170 fileptr += pf->bits_size*sizeof(unsigned char);
178 171
179 /* pad to 16 bit boundary*/ 172 if ( pf->bits_size < 0xFFDB )
180 fileptr = (unsigned char *)(((long)fileptr + 1) & ~1); 173 {
174 /* pad to 16-bit boundary */
175 fileptr = (unsigned char *)(((int)fileptr + 1) & ~1);
176 }
177 else
178 {
179 /* pad to 32-bit boundary*/
180 fileptr = (unsigned char *)(((int)fileptr + 3) & ~3);
181 }
181 182
182 if (noffset) { 183 if (noffset)
183 pf->offset = (unsigned short *)fileptr; 184 {
184 for (i=0; i<noffset; ++i) 185 if ( pf->bits_size < 0xFFDB )
186 {
187 long_offset = 0;
188 pf->offset = (unsigned short *)fileptr;
189 for (i=0; i<noffset; ++i)
190 {
191 unsigned short offset;
192 if (!readshort(&offset))
193 return NULL;
194 ((unsigned short*)(pf->offset))[i] = (unsigned short)offset;
195 }
196 }
197 else
185 { 198 {
186 unsigned short offset; 199 long_offset = 1;
187 if (!readshort(&offset)) 200 pf->offset = (unsigned short *)fileptr;
188 return NULL; 201 for (i=0; i<noffset; ++i)
189 ((unsigned short*)(pf->offset))[i] = (unsigned short)offset; 202 {
203 unsigned long offset;
204 if (!readlong(&offset))
205 return NULL;
206 ((unsigned long*)(pf->offset))[i] = (unsigned long)offset;
207 }
190 } 208 }
191 } 209 }
192 else 210 else
@@ -205,6 +223,141 @@ struct font* font_load(const char *path)
205 return pf; /* success!*/ 223 return pf; /* success!*/
206} 224}
207 225
226/* Load cached font */
227struct font* font_load_cached(struct font* pf)
228{
229 unsigned long noffset, nwidth;
230 unsigned char* oldfileptr = fileptr;
231
232 /* # longs of offset*/
233 if (!readlong(&noffset))
234 return NULL;
235
236 /* # bytes of width*/
237 if (!readlong(&nwidth))
238 return NULL;
239
240 /* We are now at the bitmap data, this is fixed at 36.. */
241 pf->bits = NULL;
242
243 /* Calculate offset to offset data */
244 fileptr += pf->bits_size * sizeof(unsigned char);
245
246 if ( pf->bits_size < 0xFFDB )
247 {
248 long_offset = 0;
249 /* pad to 16-bit boundary */
250 fileptr = (unsigned char *)(((int)fileptr + 1) & ~1);
251 }
252 else
253 {
254 long_offset = 1;
255 /* pad to 32-bit boundary*/
256 fileptr = (unsigned char *)(((int)fileptr + 3) & ~3);
257 }
258
259 if (noffset)
260 file_offset_offset = (unsigned long)(fileptr - freeptr);
261 else
262 file_offset_offset = 0;
263
264 /* Calculate offset to widths data */
265 if ( pf->bits_size < 0xFFDB )
266 fileptr += noffset * sizeof(unsigned short);
267 else
268 fileptr += noffset * sizeof(unsigned long);
269
270 if (nwidth)
271 file_width_offset = (unsigned long)(fileptr - freeptr);
272 else
273 file_width_offset = 0;
274
275 fileptr = oldfileptr;
276
277 /* Create the cache */
278 cache_create(pf->maxwidth, pf->height);
279
280 return pf;
281}
282
283/* read and load font into incore font structure*/
284struct font* font_load(const char *path)
285{
286 int filesize;
287 struct font* pf = &font_ui;
288
289 /* save loaded glyphs */
290 glyph_cache_save();
291
292 /* Close font file handle */
293 if (fnt_file >= 0)
294 close(fnt_file);
295
296 /* open and read entire font file*/
297 fnt_file = open(path, O_RDONLY|O_BINARY);
298
299 if (fnt_file < 0) {
300 DEBUGF("Can't open font: %s\n", path);
301 return NULL;
302 }
303
304 /* Check file size */
305 filesize = lseek(fnt_file, 0, SEEK_END);
306 lseek(fnt_file, 0, SEEK_SET);
307
308 font_reset();
309
310 /* currently, font loading replaces earlier font allocation*/
311 freeptr = (unsigned char *)(((int)mbuf + 3) & ~3);
312 fileptr = freeptr;
313
314
315 if (filesize > MAX_FONT_SIZE)
316 {
317 read(fnt_file, fileptr, FONT_HEADER_SIZE);
318 eofptr = fileptr + FONT_HEADER_SIZE;
319
320 if (!font_load_header(pf))
321 {
322 DEBUGF("Failed font header load");
323 return NULL;
324 }
325
326 if (!font_load_cached(pf))
327 {
328 DEBUGF("Failed font cache load");
329 return NULL;
330 }
331
332 glyph_cache_load();
333 }
334 else
335 {
336 read(fnt_file, fileptr, MAX_FONT_SIZE);
337 eofptr = fileptr + filesize;
338 close(fnt_file);
339 fnt_file = -1;
340
341 if (!font_load_header(pf))
342 {
343 DEBUGF("Failed font header load");
344 return NULL;
345 }
346
347 if (!font_load_in_memory(pf))
348 {
349 DEBUGF("Failed mem load");
350 return NULL;
351 }
352 }
353
354 /* no need for multiple font loads currently*/
355 /*freeptr += filesize;*/
356 /*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/ /* pad freeptr*/
357
358 return pf; /* success!*/
359}
360
208/* 361/*
209 * Return a pointer to an incore font structure. 362 * Return a pointer to an incore font structure.
210 * If the requested font isn't loaded/compiled-in, 363 * If the requested font isn't loaded/compiled-in,
@@ -231,17 +384,18 @@ struct font* font_get(int font)
231int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber) 384int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
232{ 385{
233 struct font* pf = font_get(fontnumber); 386 struct font* pf = font_get(fontnumber);
234 int ch; 387 unsigned short ch;
235 int width = 0; 388 int width = 0;
236 389
237 while((ch = *str++)) { 390 for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch))
391 {
238 /* check input range*/ 392 /* check input range*/
239 if (ch < pf->firstchar || ch >= pf->firstchar+pf->size) 393 if (ch < pf->firstchar || ch >= pf->firstchar+pf->size)
240 ch = pf->defaultchar; 394 ch = pf->defaultchar;
241 ch -= pf->firstchar; 395 ch -= pf->firstchar;
242 396
243 /* get proportional width and glyph bits*/ 397 /* get proportional width and glyph bits*/
244 width += pf->width? pf->width[ch]: pf->maxwidth; 398 width += font_get_width(pf,ch);
245 } 399 }
246 if ( w ) 400 if ( w )
247 *w = width; 401 *w = width;
@@ -250,6 +404,154 @@ int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
250 return width; 404 return width;
251} 405}
252 406
407/*
408 * Reads an entry into cache entry
409 */
410static void
411load_cache_entry(struct font_cache_entry* p, void* callback_data)
412{
413 struct font* pf = callback_data;
414 unsigned short char_code = p->_char_code;
415 unsigned char tmp[2];
416
417 if (file_width_offset)
418 {
419 int width_offset = file_width_offset + char_code;
420 lseek(fnt_file, width_offset, SEEK_SET);
421 read(fnt_file, &(p->width), 1);
422 }
423 else
424 {
425 p->width = pf->maxwidth;
426 }
427
428 long bitmap_offset = 0;
429
430 if (file_offset_offset)
431 {
432 long offset = file_offset_offset + char_code * (long_offset ? sizeof(long) : sizeof(short));
433 lseek(fnt_file, offset, SEEK_SET);
434 read (fnt_file, tmp, 2);
435 bitmap_offset = tmp[0] | (tmp[1] << 8);
436 if (long_offset) {
437 read (fnt_file, tmp, 2);
438 bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
439 }
440 }
441 else
442 {
443 bitmap_offset = ((pf->height + 7) / 8) * p->width * char_code;
444 }
445
446 long file_offset = FONT_HEADER_SIZE + bitmap_offset;
447 lseek(fnt_file, file_offset, SEEK_SET);
448
449 int src_bytes = p->width * ((pf->height + 7) / 8);
450 read(fnt_file, p->bitmap, src_bytes);
451}
452
453/*
454 * Converts cbuf into a font cache
455 */
456static void cache_create(int maxwidth, int height)
457{
458 /* maximum size of rotated bitmap */
459 int bitmap_size = maxwidth * ((height + 7) / 8);
460
461 /* Initialise cache */
462 font_cache_create(&font_cache_ui, mbuf, MAX_FONT_SIZE, bitmap_size);
463}
464
465/*
466 * Returns width of character
467 */
468int font_get_width(struct font* pf, unsigned short char_code)
469{
470 return (fnt_file >= 0 && pf != &sysfont)?
471 font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->width:
472 pf->width? pf->width[char_code]: pf->maxwidth;
473}
474
475const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
476{
477 const unsigned char* bits;
478 if (fnt_file >= 0 && pf != &sysfont)
479 {
480 bits =
481 (unsigned char*)font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->bitmap;
482 }
483 else
484 {
485 bits = pf->bits + (pf->offset?
486 pf->offset[char_code]:
487 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
488 }
489
490 return bits;
491}
492
493void glyph_file_write(void* data)
494{
495 struct font_cache_entry* p = data;
496 unsigned char tmp[2];
497
498 if (p->_char_code != 0xffff && glyph_file >= 0) {
499 tmp[0] = p->_char_code >> 8;
500 tmp[1] = p->_char_code & 0xff;
501 if (write(glyph_file, tmp, 2) != 2) {
502 close(glyph_file);
503 glyph_file = -1;
504 }
505 }
506 return;
507}
508
509/* save the char codes of the loaded glyphs to a file */
510void glyph_cache_save(void)
511{
512
513 if (fnt_file >= 0) {
514
515 glyph_file = creat(GLYPH_CACHE_FILE, 0);
516
517 if (glyph_file < 0) return;
518
519 lru_traverse(&font_cache_ui._lru, glyph_file_write);
520
521 if (glyph_file >= 0)
522 close(glyph_file);
523 }
524 return;
525}
526
527void glyph_cache_load(void)
528{
529 if (fnt_file >= 0) {
530
531 int fd;
532 unsigned char tmp[2];
533 unsigned short ch;
534 struct font* pf = &font_ui;
535
536 fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);
537
538 if (fd >= 0) {
539
540 while (read(fd, tmp, 2) == 2) {
541 ch = (tmp[0] << 8) | tmp[1];
542 font_get_bits(pf, ch);
543 }
544
545 close(fd);
546 } else {
547 /* load latin1 chars into cache */
548 ch = 255 - pf->firstchar;
549 while (ch--)
550 font_get_bits(pf, ch);
551 }
552 }
553 return;
554}
253 555
254#endif /* HAVE_LCD_BITMAP */ 556#endif /* HAVE_LCD_BITMAP */
255 557
diff --git a/firmware/font_cache.c b/firmware/font_cache.c
new file mode 100644
index 0000000000..34a14e0551
--- /dev/null
+++ b/firmware/font_cache.c
@@ -0,0 +1,224 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2003 Tat Tang
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#include <string.h>
20#include "font_cache.h"
21#include "debug.h"
22
23/*******************************************************************************
24 * font_cache_lru_init
25 ******************************************************************************/
26void font_cache_lru_init(void* data)
27{
28 struct font_cache_entry* p = data;
29 p->_char_code = 0xffff; /* assume invalid char */
30}
31
32/*******************************************************************************
33 * font_cache_create
34 ******************************************************************************/
35void font_cache_create(
36 struct font_cache* fcache,
37 void *buf,
38 int buf_size,
39 int bitmap_bytes_size)
40{
41 int font_cache_entry_size =
42 sizeof(struct font_cache_entry) + bitmap_bytes_size;
43
44 /* make sure font cache entries are a multiple of 16 bits */
45 if (font_cache_entry_size % 2 != 0)
46 font_cache_entry_size++;
47
48 int cache_size = buf_size /
49 (font_cache_entry_size + LRU_SLOT_OVERHEAD + sizeof(short));
50
51 fcache->_size = 1;
52 fcache->_capacity = cache_size;
53
54 /* set up index */
55 fcache->_index = buf;
56
57 /* set up lru list */
58 unsigned char* lru_buf = buf;
59 lru_buf += sizeof(short) * cache_size;
60 lru_create(&fcache->_lru, lru_buf, cache_size, font_cache_entry_size);
61
62 /* initialise cache */
63 lru_traverse(&fcache->_lru, font_cache_lru_init);
64 short i;
65 for (i = 0; i < cache_size; i++)
66 fcache->_index[i] = i; /* small cheat here */
67}
68
69/*******************************************************************************
70 * font_cache_index_of
71 ******************************************************************************/
72int font_cache_index_of(
73 struct font_cache* fcache,
74 unsigned short char_code)
75{
76 struct font_cache_entry* p;
77 int left, right, mid, c;
78 left = 0;
79 right = fcache->_size - 1;
80
81 do
82 {
83 mid = (left + right) / 2;
84
85 p = lru_data(&fcache->_lru, fcache->_index[mid]);
86 c = p->_char_code - char_code;
87
88 if (c == 0)
89 return mid;
90
91 if (c < 0)
92 left = mid + 1;
93 else
94 right = mid - 1;
95 }
96 while (left <= right);
97
98 return -1;
99}
100
101/*******************************************************************************
102 * font_cache_insertion_point
103 ******************************************************************************/
104int font_cache_insertion_point(
105 struct font_cache* fcache,
106 unsigned short char_code)
107{
108 struct font_cache_entry* p;
109 short *index = fcache->_index;
110
111 p = lru_data(&fcache->_lru, index[0]);
112 if (char_code < p->_char_code)
113 return -1;
114
115 p = lru_data(&fcache->_lru, index[fcache->_capacity - 1]);
116 if (char_code > p->_char_code)
117 return fcache->_capacity - 1;
118
119 int left, right, mid, c;
120
121 left = 0;
122 right = fcache->_capacity - 1;
123
124 do
125 {
126 mid = (left + right) / 2;
127
128 p = lru_data(&fcache->_lru, index[mid]);
129 c = char_code - p->_char_code;
130
131 if (c >= 0)
132 {
133 p = lru_data(&fcache->_lru, index[mid+1]);
134 int z = char_code - p->_char_code;
135
136 if (z < 0)
137 return mid;
138
139 if (z == 0)
140 return mid + 1;
141 }
142
143
144 if (c > 0)
145 left = mid + 1;
146 else
147 right = mid - 1;
148 }
149 while (left <= right);
150
151 /* not found */
152 return -2;
153}
154
155/*******************************************************************************
156 * font_cache_get
157 ******************************************************************************/
158struct font_cache_entry* font_cache_get(
159 struct font_cache* fcache,
160 unsigned short char_code,
161 void (*callback) (struct font_cache_entry* p, void *callback_data),
162 void *callback_data)
163{
164 int insertion_point = font_cache_insertion_point(fcache, char_code);
165 if (insertion_point >= 0)
166 {
167 short lru_handle = fcache->_index[insertion_point];
168 struct font_cache_entry* p = lru_data(&fcache->_lru, lru_handle);
169 if (p->_char_code == char_code)
170 {
171 lru_touch(&fcache->_lru, lru_handle);
172 return lru_data(&fcache->_lru, lru_handle);
173 }
174 }
175
176 /* not found */
177 short lru_handle_to_replace = fcache->_lru._head;
178 struct font_cache_entry* p =
179 lru_data(&fcache->_lru, lru_handle_to_replace);
180 int index_to_replace = font_cache_index_of(fcache, p->_char_code);
181
182 if (insertion_point < index_to_replace)
183 {
184 /* shift memory down */
185 int dest = insertion_point+2;
186 int src = insertion_point+1;
187 int len = index_to_replace - insertion_point - 1;
188
189 int desti = dest + len - 1;
190 int srci = src + len - 1;
191
192 int i;
193 for (i = 0; i < len; i++)
194 fcache->_index[desti--] = fcache->_index[srci--];
195
196 /* add to index */
197 fcache->_index[insertion_point + 1] = lru_handle_to_replace;
198 }
199 else if (insertion_point > index_to_replace)
200 {
201 /* shift memory up */
202 int dest = index_to_replace;
203 int src = index_to_replace + 1;
204 int len = insertion_point - index_to_replace;
205
206 int i;
207 for (i=0; i < len; i++)
208 fcache->_index[dest++] = fcache->_index[src++];
209
210 /* add to index */
211 fcache->_index[insertion_point] = lru_handle_to_replace;
212 }
213
214 /* load new entry into cache */
215 lru_touch(&fcache->_lru, lru_handle_to_replace);
216
217 if (fcache->_size < fcache->_capacity)
218 fcache->_size++;
219
220 p->_char_code = char_code;
221 callback(p, callback_data);
222
223 return p;
224}
diff --git a/firmware/id3.c b/firmware/id3.c
index 13e00c3941..ad7c8280d0 100644
--- a/firmware/id3.c
+++ b/firmware/id3.c
@@ -42,6 +42,7 @@
42#include "mp3data.h" 42#include "mp3data.h"
43#include "system.h" 43#include "system.h"
44#include "replaygain.h" 44#include "replaygain.h"
45#include "rbunicode.h"
45 46
46#define UNSYNC(b0,b1,b2,b3) (((long)(b0 & 0x7F) << (3*7)) | \ 47#define UNSYNC(b0,b1,b2,b3) (((long)(b0 & 0x7F) << (3*7)) | \
47 ((long)(b1 & 0x7F) << (2*7)) | \ 48 ((long)(b1 & 0x7F) << (2*7)) | \
@@ -359,100 +360,83 @@ static const struct tag_resolver taglist[] = {
359#define TAGLIST_SIZE ((int)(sizeof(taglist) / sizeof(taglist[0]))) 360#define TAGLIST_SIZE ((int)(sizeof(taglist) / sizeof(taglist[0])))
360 361
361/* Checks to see if the passed in string is a 16-bit wide Unicode v2 362/* Checks to see if the passed in string is a 16-bit wide Unicode v2
362 string. If it is, we attempt to convert it to a 8-bit ASCII string 363 string. If it is, we convert it to a UTF-8 string. If it's not unicode,
363 (for valid 8-bit ASCII characters). If it's not unicode, we leave 364 we convert from the default codepage */
364 it alone. At some point we should fully support unicode strings */ 365static int unicode_munge(char* string, char* utf8buf, int *len) {
365static int unicode_munge(char* string, int *len) { 366 long tmp;
366 long tmp; 367 bool le = false;
367 bool le = false; 368 int i = 0;
368 int i; 369 char *str = string;
369 char *str = string; 370 int templen = 0;
370 char *outstr = string; 371 char* utf8 = utf8buf;
371 bool bom = false; 372
372 int outlen; 373 switch (str[0]) {
373 374 case 0x00: /* Type 0x00 is ordinary ISO 8859-1 */
374 if(str[0] > 0x03) { 375 str++;
375 /* Plain old string */ 376 (*len)--;
376 return 0; 377 utf8 = iso_decode(str, utf8, -1, *len);
377 } 378 *utf8 = 0;
378 379 *len = strlen(utf8buf);
379 /* Type 0x00 is ordinary ISO 8859-1 */ 380 break;
380 if(str[0] == 0x00) {
381 int i = --(*len);
382
383 /* We must move the string to the left */
384 while (i--) {
385 string[0] = string[1];
386 string++;
387 }
388
389 return 0;
390 }
391
392 /* Unicode with or without BOM */
393 if(str[0] == 0x01 || str[0] == 0x02) {
394 (*len)--;
395 str++;
396 i = 0;
397
398 /* Handle frames with more than one string (needed for TXXX frames).
399 */
400 do {
401 tmp = BYTES2INT(0, 0, str[0], str[1]);
402
403 /* Now check if there is a BOM (zero-width non-breaking space, 0xfeff)
404 and if it is in little or big endian format */
405 if(tmp == 0xfffe) { /* Little endian? */
406 bom = true;
407 le = true;
408 str += 2;
409 (*len)-=2;
410 }
411
412 if(tmp == 0xfeff) { /* Big endian? */
413 bom = true;
414 str += 2;
415 (*len)-=2;
416 }
417
418 /* If there is no BOM (which is a specification violation),
419 let's try to guess it. If one of the bytes is 0x00, it is
420 probably the most significant one. */
421 if(!bom) {
422 if(str[1] == 0)
423 le = true;
424 }
425
426 outlen = *len / 2;
427
428 do {
429 if(le) {
430 if(str[1])
431 outstr[i++] = '.';
432 else
433 outstr[i++] = str[0];
434 } else {
435 if(str[0])
436 outstr[i++] = '.';
437 else
438 outstr[i++] = str[1];
439 }
440 str += 2;
441 } while((str[0] || str[1]) && (i < outlen));
442
443 str += 2;
444 outstr[i++] = 0; /* Terminate the string */
445 } while(i < outlen);
446 381
447 *len = i - 1; 382 case 0x01: /* Unicode with or without BOM */
383 case 0x02:
384 (*len)--;
385 str++;
386
387 /* Handle frames with more than one string
388 (needed for TXXX frames).*/
389 do {
390 tmp = BYTES2INT(0, 0, str[0], str[1]);
391
392 /* Now check if there is a BOM
393 (zero-width non-breaking space, 0xfeff)
394 and if it is in little or big endian format */
395 if(tmp == 0xfffe) { /* Little endian? */
396 le = true;
397 str += 2;
398 (*len)-=2;
399 } else if(tmp == 0xfeff) { /* Big endian? */
400 str += 2;
401 (*len)-=2;
402 } else
403 /* If there is no BOM (which is a specification violation),
404 let's try to guess it. If one of the bytes is 0x00, it is
405 probably the most significant one. */
406 if(str[1] == 0)
407 le = true;
408
409 do {
410 if(le)
411 utf8 = utf16LEdecode(str, utf8, 1);
412 else
413 utf8 = utf16BEdecode(str, utf8, 1);
414
415 str+=2;
416 i += 2;
417 } while((str[0] || str[1]) && (i < *len));
418
419 *utf8++ = 0; /* Terminate the string */
420 templen += (strlen(&utf8buf[templen]) + 1);
421 str += 2;
422 i+=2;
423 } while(i < *len);
424 *len = templen - 1;
425 break;
448 426
449 return 0; 427 case 0x03: /* UTF-8 encoded string */
450 } 428 for(i=0; i < *len; i++)
429 utf8[i] = str[i+1];
430 *len = strlen(utf8buf);
431 break;
451 432
452 /* If we come here, the string was of an unsupported type */ 433 default: /* Plain old string */
453 *len = 1; 434 utf8 = iso_decode(str, utf8, -1, *len);
454 outstr[0] = 0; 435 *utf8 = 0;
455 return -1; 436 *len = strlen(utf8buf);
437 break;
438 }
439 return 0;
456} 440}
457 441
458/* 442/*
@@ -468,6 +452,7 @@ static bool setid3v1title(int fd, struct mp3entry *entry)
468 unsigned char buffer[128]; 452 unsigned char buffer[128];
469 static const char offsets[] = {3, 33, 63, 93, 125, 127}; 453 static const char offsets[] = {3, 33, 63, 93, 125, 127};
470 int i, j; 454 int i, j;
455 unsigned char* utf8;
471 456
472 if (-1 == lseek(fd, -128, SEEK_END)) 457 if (-1 == lseek(fd, -128, SEEK_END))
473 return false; 458 return false;
@@ -482,8 +467,8 @@ static bool setid3v1title(int fd, struct mp3entry *entry)
482 entry->id3version = ID3_VER_1_0; 467 entry->id3version = ID3_VER_1_0;
483 468
484 for (i=0; i < (int)sizeof offsets; i++) { 469 for (i=0; i < (int)sizeof offsets; i++) {
485 char* ptr = (char *)buffer + offsets[i]; 470 unsigned char* ptr = (unsigned char *)buffer + offsets[i];
486 471
487 if (i<3) { 472 if (i<3) {
488 /* kill trailing space in strings */ 473 /* kill trailing space in strings */
489 for (j=29; j && ptr[j]==' '; j--) 474 for (j=29; j && ptr[j]==' '; j--)
@@ -492,18 +477,13 @@ static bool setid3v1title(int fd, struct mp3entry *entry)
492 477
493 switch(i) { 478 switch(i) {
494 case 0: 479 case 0:
495 strncpy(entry->id3v1buf[2], ptr, 30);
496 entry->title = entry->id3v1buf[2];
497 break;
498
499 case 1: 480 case 1:
500 strncpy(entry->id3v1buf[0], ptr, 30);
501 entry->artist = entry->id3v1buf[0];
502 break;
503
504 case 2: 481 case 2:
505 strncpy(entry->id3v1buf[1], ptr, 30); 482 /* convert string to utf8 */
506 entry->album = entry->id3v1buf[1]; 483 utf8 = entry->id3v1buf[i];
484 utf8 = iso_decode(ptr, utf8, -1, 30);
485 /* make sure string is terminated */
486 *utf8 = 0;
507 break; 487 break;
508 488
509 case 3: 489 case 3:
@@ -527,6 +507,10 @@ static bool setid3v1title(int fd, struct mp3entry *entry)
527 } 507 }
528 } 508 }
529 509
510 entry->title = entry->id3v1buf[0];
511 entry->artist = entry->id3v1buf[1];
512 entry->album = entry->id3v1buf[2];
513
530 return true; 514 return true;
531} 515}
532 516
@@ -556,7 +540,7 @@ static void setid3v2title(int fd, struct mp3entry *entry)
556 bool global_unsynch = false; 540 bool global_unsynch = false;
557 bool unsynch = false; 541 bool unsynch = false;
558 int data_length_ind; 542 int data_length_ind;
559 int i; 543 int i, j;
560 int rc; 544 int rc;
561 545
562 global_ff_found = false; 546 global_ff_found = false;
@@ -789,7 +773,18 @@ static void setid3v2title(int fd, struct mp3entry *entry)
789 if(unsynch || (global_unsynch && version >= ID3_VER_2_4)) 773 if(unsynch || (global_unsynch && version >= ID3_VER_2_4))
790 bytesread = unsynchronize_frame(tag, bytesread); 774 bytesread = unsynchronize_frame(tag, bytesread);
791 775
792 unicode_munge( tag, &bytesread ); 776
777 /* UTF-8 could potentially be 3 times larger */
778 /* so we need to create a new buffer */
779 char utf8buf[(3 * bytesread) + 1];
780
781 unicode_munge( tag, utf8buf, &bytesread );
782
783 if(bytesread >= buffersize - bufferpos)
784 bytesread = buffersize - bufferpos - 1;
785
786 for (j = 0; j < bytesread; j++)
787 tag[j] = utf8buf[j];
793 788
794 if (ptag) 789 if (ptag)
795 *ptag = tag; 790 *ptag = tag;
@@ -809,7 +804,7 @@ static void setid3v2title(int fd, struct mp3entry *entry)
809 break; 804 break;
810 } 805 }
811 } 806 }
812 807
813 if( i == TAGLIST_SIZE ) { 808 if( i == TAGLIST_SIZE ) {
814 /* no tag in tagList was found, or it was a repeat. 809 /* no tag in tagList was found, or it was a repeat.
815 skip it using the total size */ 810 skip it using the total size */
@@ -839,7 +834,7 @@ int getid3v2len(int fd)
839{ 834{
840 char buf[6]; 835 char buf[6];
841 int offset; 836 int offset;
842 837
843 /* Make sure file has a ID3 tag */ 838 /* Make sure file has a ID3 tag */
844 if((-1 == lseek(fd, 0, SEEK_SET)) || 839 if((-1 == lseek(fd, 0, SEEK_SET)) ||
845 (read(fd, buf, 6) != 6) || 840 (read(fd, buf, 6) != 6) ||
@@ -955,7 +950,7 @@ bool mp3info(struct mp3entry *entry, const char *filename, bool v1first)
955#if CONFIG_CODEC != SWCODEC 950#if CONFIG_CODEC != SWCODEC
956 memset(entry, 0, sizeof(struct mp3entry)); 951 memset(entry, 0, sizeof(struct mp3entry));
957#endif 952#endif
958 953
959 strncpy(entry->path, filename, sizeof(entry->path)); 954 strncpy(entry->path, filename, sizeof(entry->path));
960 955
961 entry->title = NULL; 956 entry->title = NULL;
diff --git a/firmware/include/font_cache.h b/firmware/include/font_cache.h
new file mode 100644
index 0000000000..813cd18987
--- /dev/null
+++ b/firmware/include/font_cache.h
@@ -0,0 +1,48 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2003 Tat Tang
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#include "lru.h"
20
21/*******************************************************************************
22 *
23 ******************************************************************************/
24struct font_cache
25{
26 struct lru _lru;
27 int _size;
28 int _capacity;
29 short *_index; /* index of lru handles in char_code order */
30};
31
32struct font_cache_entry
33{
34 unsigned short _char_code;
35 unsigned char width;
36 unsigned char bitmap[1]; /* place holder */
37};
38
39/* void (*f) (void*, struct font_cache_entry*); */
40/* Create an auto sized font cache from buf */
41void font_cache_create(
42 struct font_cache* fcache, void* buf, int buf_size, int bitmap_bytes_size);
43/* Get font cache entry */
44struct font_cache_entry* font_cache_get(
45 struct font_cache* fcache,
46 unsigned short char_code,
47 void (*callback) (struct font_cache_entry* p, void *callback_data),
48 void *callback_data);
diff --git a/firmware/include/lru.h b/firmware/include/lru.h
new file mode 100644
index 0000000000..8c74aa64ef
--- /dev/null
+++ b/firmware/include/lru.h
@@ -0,0 +1,46 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2003 Tat Tang
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#ifndef LRU_H
20#define LRU_H
21
22/*******************************************************************************
23 * LRU manager
24 ******************************************************************************/
25struct lru
26{
27 short _head;
28 short _tail;
29 short _size;
30 short _slot_size;
31 void *_base;
32};
33
34#define LRU_SLOT_OVERHEAD (2 * sizeof(short))
35
36/* Create LRU list with specified size from buf. */
37void lru_create(struct lru* pl, void *buf, short size, short data_size);
38/* Touch an entry. Moves handle to back of LRU list */
39void lru_touch(struct lru* pl, short handle);
40/* Data */
41void *lru_data(struct lru* pl, short handle);
42/* Traverse lru-wise */
43void lru_traverse(struct lru* pl, void (*callback)(void* data));
44
45#endif /* LRU_H */
46
diff --git a/firmware/include/rbunicode.h b/firmware/include/rbunicode.h
new file mode 100644
index 0000000000..1d4bc43096
--- /dev/null
+++ b/firmware/include/rbunicode.h
@@ -0,0 +1,29 @@
1/* Some conversion functions for handling UTF-8
2 *
3 * copyright Marcoen Hirschberg (2004,2005)
4 *
5 * I got all the info from:
6 * http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
7 * and
8 * http://en.wikipedia.org/wiki/Unicode
9 */
10
11#define CODEPAGE_DIR "/.rockbox/codepages"
12
13#define MAX_CP_TABLE_SIZE 32768
14
15#define MASK 0xC0 /* 11000000 */
16#define COMP 0x80 /* 10x */
17
18extern int codepage;
19
20/* Encode a UCS value as UTF-8 and return a pointer after this UTF-8 char. */
21unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8);
22unsigned char* iso_decode(const unsigned char *latin1, unsigned char *utf8, int cp, int count);
23unsigned char* utf16LEdecode(const unsigned char *utf16, unsigned char *utf8, unsigned int count);
24unsigned char* utf16BEdecode(const unsigned char *utf16, unsigned char *utf8, unsigned int count);
25unsigned char* utf16decode(const unsigned char *utf16, unsigned char *utf8, unsigned int count);
26unsigned long utf8length(const unsigned char *utf8);
27const unsigned char* utf8decode(const unsigned char *utf8, unsigned short *ucs);
28void set_codepage(int cp);
29int utf8seek(const unsigned char* utf8, int offset);
diff --git a/firmware/lru.c b/firmware/lru.c
new file mode 100644
index 0000000000..6834c3da1b
--- /dev/null
+++ b/firmware/lru.c
@@ -0,0 +1,119 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2003 Tat Tang
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#include "lru.h"
20
21struct lru_node
22{
23 short _next;
24 short _prev;
25 unsigned char data[1]; /* place holder */
26};
27
28#define lru_node_p(pl, x) \
29 ((struct lru_node*)(pl->_base + pl->_slot_size * x))
30
31/*******************************************************************************
32 * lru_create
33 ******************************************************************************/
34void lru_create(struct lru* pl, void *buf, short size, short data_size)
35{
36 pl->_base = (unsigned char*) buf;
37 pl->_slot_size = data_size + LRU_SLOT_OVERHEAD;
38
39 pl->_size = size;
40
41 pl->_head = 0;
42 pl->_tail = pl->_size - 1;
43
44 /* Initialise slots */
45 int i;
46 for (i=0; i<pl->_size; i++)
47 {
48 lru_node_p(pl, i)->_next = i + 1;
49 lru_node_p(pl, i)->_prev = i - 1;
50 }
51
52 /* Fix up head and tail to form circular buffer */
53 lru_node_p(pl, 0)->_prev = pl->_tail;
54 lru_node_p(pl, pl->_tail)->_next = pl->_head;
55}
56
57/*******************************************************************************
58 * lru_traverse
59 ******************************************************************************/
60void lru_traverse(struct lru* pl, void (*callback)(void* data))
61{
62 short i;
63 struct lru_node* slot;
64 short loc = pl->_head;
65
66 for (i = 0; i < pl->_size; i++)
67 {
68 slot = lru_node_p(pl, loc);
69 callback(slot->data);
70 loc = slot->_next;
71 }
72}
73
74/*******************************************************************************
75 * lru_touch
76 ******************************************************************************/
77void lru_touch(struct lru* pl, short handle)
78{
79 if (handle == pl->_head)
80 {
81 pl->_head = lru_node_p(pl, pl->_head)->_next;
82 pl->_tail = lru_node_p(pl, pl->_tail)->_next;
83 return;
84 }
85
86 if (handle == pl->_tail)
87 {
88 return;
89 }
90
91 /* Remove current node from linked list */
92 struct lru_node* curr_node = lru_node_p(pl, handle);
93 struct lru_node* prev_node = lru_node_p(pl, curr_node->_prev);
94 struct lru_node* next_node = lru_node_p(pl, curr_node->_next);
95
96 prev_node->_next = curr_node->_next;
97 next_node->_prev = curr_node->_prev;
98
99 /* insert current node at tail */
100 struct lru_node* tail_node = lru_node_p(pl, pl->_tail);
101 short tail_node_next_handle = tail_node->_next; /* Bug fix */
102 struct lru_node* tail_node_next = lru_node_p(pl, tail_node_next_handle); /* Bug fix */
103
104 curr_node->_next = tail_node->_next;
105 curr_node->_prev = pl->_tail;
106 tail_node_next->_prev = handle; /* Bug fix */
107 tail_node->_next = handle;
108
109 pl->_tail = handle;
110}
111
112/*******************************************************************************
113 * lru_data
114 ******************************************************************************/
115void *lru_data(struct lru* pl, short handle)
116{
117 return lru_node_p(pl, handle)->data;
118}
119
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index a162887fd9..b5f1ef83c7 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -46,6 +46,9 @@
46#include "file.h" 46#include "file.h"
47#include "hwcompat.h" 47#include "hwcompat.h"
48#endif /* !SIMULATOR */ 48#endif /* !SIMULATOR */
49#ifdef HAVE_LCD_BITMAP
50#include "lcd.h"
51#endif
49 52
50#ifndef SIMULATOR 53#ifndef SIMULATOR
51extern unsigned long mas_version_code; 54extern unsigned long mas_version_code;
@@ -916,6 +919,12 @@ static struct trackdata *add_track_to_tag_list(const char *filename)
916 } 919 }
917 track->mempos = audiobuf_write; 920 track->mempos = audiobuf_write;
918 track->id3.elapsed = 0; 921 track->id3.elapsed = 0;
922#ifdef HAVE_LCD_BITMAP
923 int w, h;
924 lcd_getstringsize(track->id3.title, &w, &h);
925 lcd_getstringsize(track->id3.artist, &w, &h);
926 lcd_getstringsize(track->id3.album, &w, &h);
927#endif
919 928
920 track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK; 929 track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK;
921 debug_tags(); 930 debug_tags();
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c
index e061f7043b..a60a35c8cb 100644
--- a/firmware/powermgmt.c
+++ b/firmware/powermgmt.c
@@ -46,6 +46,9 @@
46#elif HAVE_TLV320 46#elif HAVE_TLV320
47#include "tlv320.h" 47#include "tlv320.h"
48#endif 48#endif
49#ifdef HAVE_LCD_BITMAP
50#include "font.h"
51#endif
49#include "logf.h" 52#include "logf.h"
50#include "lcd-remote.h" 53#include "lcd-remote.h"
51 54
@@ -378,7 +381,7 @@ static void handle_auto_poweroff(void)
378 * Inhibit shutdown as long as the charger is plugged in. If it is 381 * Inhibit shutdown as long as the charger is plugged in. If it is
379 * unplugged, wait for a timeout period and then shut down. 382 * unplugged, wait for a timeout period and then shut down.
380 */ 383 */
381 if(charger_input_state == CHARGER) { 384 if(charger_input_state == CHARGER || audio_stat == AUDIO_STATUS_PLAY) {
382 last_event_tick = current_tick; 385 last_event_tick = current_tick;
383 } 386 }
384#endif 387#endif
@@ -899,6 +902,9 @@ void shutdown_hw(void)
899 } 902 }
900#endif 903#endif
901 audio_stop(); 904 audio_stop();
905#ifdef HAVE_LCD_BITMAP
906 glyph_cache_save();
907#endif
902 ata_flush(); 908 ata_flush();
903 ata_spindown(1); 909 ata_spindown(1);
904 while(ata_disk_is_active()) 910 while(ata_disk_is_active())