~ubuntu-branches/debian/stretch/grub2/stretch

« back to all changes in this revision

Viewing changes to lib/charset.c

Tags: upstream-1.98+20100705
ImportĀ upstreamĀ versionĀ 1.98+20100705

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *  GRUB  --  GRand Unified Bootloader
3
 
 *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009  Free Software Foundation, Inc.
4
 
 *
5
 
 *  GRUB is free software: you can redistribute it and/or modify
6
 
 *  it under the terms of the GNU General Public License as published by
7
 
 *  the Free Software Foundation, either version 3 of the License, or
8
 
 *  (at your option) any later version.
9
 
 *
10
 
 *  GRUB is distributed in the hope that it will be useful,
11
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 *  GNU General Public License for more details.
14
 
 *
15
 
 *  You should have received a copy of the GNU General Public License
16
 
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
17
 
 */
18
 
 
19
 
/* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE
20
 
   bytes (if SRCSIZE is -1, it is ignored) in length to a UTF-16 string.
21
 
   Return the number of characters converted. DEST must be able to hold
22
 
   at least DESTSIZE characters. If an invalid sequence is found, return -1.
23
 
   If SRCEND is not NULL, then *SRCEND is set to the next byte after the
24
 
   last byte used in SRC.  */
25
 
 
26
 
#include <grub/charset.h>
27
 
#include <grub/mm.h>
28
 
#include <grub/misc.h>
29
 
 
30
 
grub_ssize_t
31
 
grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize,
32
 
                    const grub_uint8_t *src, grub_size_t srcsize,
33
 
                    const grub_uint8_t **srcend)
34
 
{
35
 
  grub_uint16_t *p = dest;
36
 
  int count = 0;
37
 
  grub_uint32_t code = 0;
38
 
 
39
 
  if (srcend)
40
 
    *srcend = src;
41
 
 
42
 
  while (srcsize && destsize)
43
 
    {
44
 
      grub_uint32_t c = *src++;
45
 
      if (srcsize != (grub_size_t)-1)
46
 
        srcsize--;
47
 
      if (count)
48
 
        {
49
 
          if ((c & GRUB_UINT8_2_LEADINGBITS) != GRUB_UINT8_1_LEADINGBIT)
50
 
            {
51
 
              /* invalid */
52
 
              return -1;
53
 
            }
54
 
          else
55
 
            {
56
 
              code <<= 6;
57
 
              code |= (c & GRUB_UINT8_6_TRAILINGBITS);
58
 
              count--;
59
 
            }
60
 
        }
61
 
      else
62
 
        {
63
 
          if (c == 0)
64
 
            break;
65
 
 
66
 
          if ((c & GRUB_UINT8_1_LEADINGBIT) == 0)
67
 
            code = c;
68
 
          else if ((c & GRUB_UINT8_3_LEADINGBITS) == GRUB_UINT8_2_LEADINGBITS)
69
 
            {
70
 
              count = 1;
71
 
              code = c & GRUB_UINT8_5_TRAILINGBITS;
72
 
            }
73
 
          else if ((c & GRUB_UINT8_4_LEADINGBITS) == GRUB_UINT8_3_LEADINGBITS)
74
 
            {
75
 
              count = 2;
76
 
              code = c & GRUB_UINT8_4_TRAILINGBITS;
77
 
            }
78
 
          else if ((c & GRUB_UINT8_5_LEADINGBITS) == GRUB_UINT8_4_LEADINGBITS)
79
 
            {
80
 
              count = 3;
81
 
              code = c & GRUB_UINT8_3_TRAILINGBITS;
82
 
            }
83
 
          else if ((c & GRUB_UINT8_6_LEADINGBITS) == GRUB_UINT8_5_LEADINGBITS)
84
 
            {
85
 
              count = 4;
86
 
              code = c & GRUB_UINT8_2_TRAILINGBITS;
87
 
            }
88
 
          else if ((c & GRUB_UINT8_7_LEADINGBITS) == GRUB_UINT8_6_LEADINGBITS)
89
 
            {
90
 
              count = 5;
91
 
              code = c & GRUB_UINT8_1_TRAILINGBIT;
92
 
            }
93
 
          else
94
 
            return -1;
95
 
        }
96
 
 
97
 
      if (count == 0)
98
 
        {
99
 
          if (destsize < 2 && code >= GRUB_UCS2_LIMIT)
100
 
            break;
101
 
          if (code >= GRUB_UCS2_LIMIT)
102
 
            {
103
 
              *p++ = GRUB_UTF16_UPPER_SURROGATE (code);
104
 
              *p++ = GRUB_UTF16_LOWER_SURROGATE (code);
105
 
              destsize -= 2;
106
 
            }
107
 
          else
108
 
            {
109
 
              *p++ = code;
110
 
              destsize--;
111
 
            }
112
 
        }
113
 
    }
114
 
 
115
 
  if (srcend)
116
 
    *srcend = src;
117
 
  return p - dest;
118
 
}
119
 
 
120
 
/* Convert UCS-4 to UTF-8.  */
121
 
char *
122
 
grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size)
123
 
{
124
 
  grub_size_t remaining;
125
 
  grub_uint32_t *ptr;
126
 
  grub_size_t cnt = 0;
127
 
  grub_uint8_t *ret, *dest;
128
 
 
129
 
  remaining = size;
130
 
  ptr = src;
131
 
  while (remaining--)
132
 
    {
133
 
      grub_uint32_t code = *ptr++;
134
 
      
135
 
      if (code <= 0x007F)
136
 
        cnt++;
137
 
      else if (code <= 0x07FF)
138
 
        cnt += 2;
139
 
      else if ((code >= 0xDC00 && code <= 0xDFFF)
140
 
               || (code >= 0xD800 && code <= 0xDBFF))
141
 
        /* No surrogates in UCS-4... */
142
 
        cnt++;
143
 
      else
144
 
        cnt += 3;
145
 
    }
146
 
  cnt++;
147
 
 
148
 
  ret = grub_malloc (cnt);
149
 
  if (!ret)
150
 
    return 0;
151
 
 
152
 
  dest = ret;
153
 
  remaining = size;
154
 
  ptr = src;
155
 
  while (remaining--)
156
 
    {
157
 
      grub_uint32_t code = *ptr++;
158
 
 
159
 
      if (code <= 0x007F)
160
 
        *dest++ = code;
161
 
      else if (code <= 0x07FF)
162
 
        {
163
 
          *dest++ = (code >> 6) | 0xC0;
164
 
          *dest++ = (code & 0x3F) | 0x80;
165
 
        }
166
 
      else if ((code >= 0xDC00 && code <= 0xDFFF)
167
 
               || (code >= 0xD800 && code <= 0xDBFF))
168
 
        {
169
 
          /* No surrogates in UCS-4... */
170
 
          *dest++ = '?';
171
 
        }
172
 
      else
173
 
        {
174
 
          *dest++ = (code >> 12) | 0xE0;
175
 
          *dest++ = ((code >> 6) & 0x3F) | 0x80;
176
 
          *dest++ = (code & 0x3F) | 0x80;
177
 
        }
178
 
    }
179
 
  *dest = 0;
180
 
 
181
 
  return (char *) ret;
182
 
}
183
 
 
184
 
int
185
 
grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize)
186
 
{
187
 
  grub_uint32_t code = 0;
188
 
  int count = 0;
189
 
 
190
 
  while (srcsize)
191
 
    {
192
 
      grub_uint32_t c = *src++;
193
 
      if (srcsize != (grub_size_t)-1)
194
 
        srcsize--;
195
 
      if (count)
196
 
        {
197
 
          if ((c & 0xc0) != 0x80)
198
 
            {
199
 
              /* invalid */
200
 
              return 0;
201
 
            }
202
 
          else
203
 
            {
204
 
              code <<= 6;
205
 
              code |= (c & 0x3f);
206
 
              count--;
207
 
            }
208
 
        }
209
 
      else
210
 
        {
211
 
          if (c == 0)
212
 
            break;
213
 
 
214
 
          if ((c & 0x80) == 0x00)
215
 
            code = c;
216
 
          else if ((c & 0xe0) == 0xc0)
217
 
            {
218
 
              count = 1;
219
 
              code = c & 0x1f;
220
 
            }
221
 
          else if ((c & 0xf0) == 0xe0)
222
 
            {
223
 
              count = 2;
224
 
              code = c & 0x0f;
225
 
            }
226
 
          else if ((c & 0xf8) == 0xf0)
227
 
            {
228
 
              count = 3;
229
 
              code = c & 0x07;
230
 
            }
231
 
          else if ((c & 0xfc) == 0xf8)
232
 
            {
233
 
              count = 4;
234
 
              code = c & 0x03;
235
 
            }
236
 
          else if ((c & 0xfe) == 0xfc)
237
 
            {
238
 
              count = 5;
239
 
              code = c & 0x01;
240
 
            }
241
 
          else
242
 
            return 0;
243
 
        }
244
 
    }
245
 
 
246
 
  return 1;
247
 
}
248
 
 
249
 
int
250
 
grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg,
251
 
                        grub_uint32_t **last_position)
252
 
{
253
 
  grub_size_t msg_len = grub_strlen (msg);
254
 
 
255
 
  *unicode_msg = grub_malloc (grub_strlen (msg) * sizeof (grub_uint32_t));
256
 
 
257
 
  if (!*unicode_msg)
258
 
    {
259
 
      grub_printf ("utf8_to_ucs4 ERROR1: %s", msg);
260
 
      return -1;
261
 
    }
262
 
 
263
 
  msg_len = grub_utf8_to_ucs4 (*unicode_msg, msg_len,
264
 
                              (grub_uint8_t *) msg, -1, 0);
265
 
 
266
 
  *last_position = *unicode_msg + msg_len;
267
 
 
268
 
  return msg_len;
269
 
}