~ubuntu-branches/ubuntu/karmic/fastjar/karmic-security

« back to all changes in this revision

Viewing changes to lib/mbrtowc.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-09-09 11:45:33 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20090909114533-72sxsqnxfctc9xck
Tags: 2:0.98-1
* New upstream release.
* Bump policy version to 3.8.3.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Convert multibyte character to wide character.
 
2
   Copyright (C) 1999-2002, 2005-2008 Free Software Foundation, Inc.
 
3
   Written by Bruno Haible <bruno@clisp.org>, 2008.
 
4
 
 
5
   This program 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
   This program is distributed in the hope that it will be useful,
 
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
   GNU General Public License for more details.
 
14
 
 
15
   You should have received a copy of the GNU General Public License
 
16
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
17
 
 
18
#include <config.h>
 
19
 
 
20
/* Specification.  */
 
21
#include <wchar.h>
 
22
 
 
23
#if GNULIB_defined_mbstate_t
 
24
/* Implement mbrtowc() on top of mbtowc().  */
 
25
 
 
26
# include <errno.h>
 
27
# include <stdlib.h>
 
28
 
 
29
# include "localcharset.h"
 
30
# include "streq.h"
 
31
# include "verify.h"
 
32
 
 
33
 
 
34
verify (sizeof (mbstate_t) >= 4);
 
35
 
 
36
static char internal_state[4];
 
37
 
 
38
size_t
 
39
mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
 
40
{
 
41
  char *pstate = (char *)ps;
 
42
 
 
43
  if (pstate == NULL)
 
44
    pstate = internal_state;
 
45
 
 
46
  if (s == NULL)
 
47
    {
 
48
      pwc = NULL;
 
49
      s = "";
 
50
      n = 1;
 
51
    }
 
52
 
 
53
  if (n == 0)
 
54
    return (size_t)(-2);
 
55
 
 
56
  /* Here n > 0.  */
 
57
  {
 
58
    size_t nstate = pstate[0];
 
59
    char buf[4];
 
60
    const char *p;
 
61
    size_t m;
 
62
 
 
63
    switch (nstate)
 
64
      {
 
65
      case 0:
 
66
        p = s;
 
67
        m = n;
 
68
        break;
 
69
      case 3:
 
70
        buf[2] = pstate[3];
 
71
        /*FALLTHROUGH*/
 
72
      case 2:
 
73
        buf[1] = pstate[2];
 
74
        /*FALLTHROUGH*/
 
75
      case 1:
 
76
        buf[0] = pstate[1];
 
77
        p = buf;
 
78
        m = nstate;
 
79
        buf[m++] = s[0];
 
80
        if (n >= 2 && m < 4)
 
81
          {
 
82
            buf[m++] = s[1];
 
83
            if (n >= 3 && m < 4)
 
84
              buf[m++] = s[2];
 
85
          }
 
86
        break;
 
87
      default:
 
88
        errno = EINVAL;
 
89
        return (size_t)(-1);
 
90
      }
 
91
 
 
92
    /* Here 0 < m ≤ 4.  */
 
93
 
 
94
# if __GLIBC__
 
95
    /* Work around bug <http://sourceware.org/bugzilla/show_bug.cgi?id=9674> */
 
96
    mbtowc (NULL, NULL, 0);
 
97
# endif
 
98
    {
 
99
      int res = mbtowc (pwc, p, m);
 
100
 
 
101
      if (res >= 0)
 
102
        {
 
103
          if (pwc != NULL && ((*pwc == 0) != (res == 0)))
 
104
            abort ();
 
105
          if (nstate >= (res > 0 ? res : 1))
 
106
            abort ();
 
107
          res -= nstate;
 
108
          pstate[0] = 0;
 
109
          return res;
 
110
        }
 
111
 
 
112
      /* mbtowc does not distinguish between invalid and incomplete multibyte
 
113
         sequences.  But mbrtowc needs to make this distinction.
 
114
         There are two possible approaches:
 
115
           - Use iconv() and its return value.
 
116
           - Use built-in knowledge about the possible encodings.
 
117
         Given the low quality of implementation of iconv() on the systems that
 
118
         lack mbrtowc(), we use the second approach.
 
119
         The possible encodings are:
 
120
           - 8-bit encodings,
 
121
           - EUC-JP, EUC-KR, GB2312, EUC-TW, BIG5, SJIS,
 
122
           - UTF-8.
 
123
         Use specialized code for each.  */
 
124
      if (m >= 4 || m >= MB_CUR_MAX)
 
125
        goto invalid;
 
126
      /* Here MB_CUR_MAX > 1 and 0 < m < 4.  */
 
127
      {
 
128
        const char *encoding = locale_charset ();
 
129
 
 
130
        if (STREQ (encoding, "UTF-8", 'U', 'T', 'F', '-', '8', 0, 0, 0, 0))
 
131
          {
 
132
            /* Cf. unistr/u8-mblen.c.  */
 
133
            unsigned char c = (unsigned char) p[0];
 
134
 
 
135
            if (c >= 0xc2)
 
136
              {
 
137
                if (c < 0xe0)
 
138
                  {
 
139
                    if (m == 1)
 
140
                      goto incomplete;
 
141
                  }
 
142
                else if (c < 0xf0)
 
143
                  {
 
144
                    if (m == 1)
 
145
                      goto incomplete;
 
146
                    if (m == 2)
 
147
                      {
 
148
                        unsigned char c2 = (unsigned char) p[1];
 
149
 
 
150
                        if ((c2 ^ 0x80) < 0x40
 
151
                            && (c >= 0xe1 || c2 >= 0xa0)
 
152
                            && (c != 0xed || c2 < 0xa0))
 
153
                          goto incomplete;
 
154
                      }
 
155
                  }
 
156
                else if (c <= 0xf4)
 
157
                  {
 
158
                    if (m == 1)
 
159
                      goto incomplete;
 
160
                    else /* m == 2 || m == 3 */
 
161
                      {
 
162
                        unsigned char c2 = (unsigned char) p[1];
 
163
 
 
164
                        if ((c2 ^ 0x80) < 0x40
 
165
                            && (c >= 0xf1 || c2 >= 0x90)
 
166
                            && (c < 0xf4 || (c == 0xf4 && c2 < 0x90)))
 
167
                          {
 
168
                            if (m == 2)
 
169
                              goto incomplete;
 
170
                            else /* m == 3 */
 
171
                              {
 
172
                                unsigned char c3 = (unsigned char) p[2];
 
173
 
 
174
                                if ((c3 ^ 0x80) < 0x40)
 
175
                                  goto incomplete;
 
176
                              }
 
177
                          }
 
178
                      }
 
179
                  }
 
180
              }
 
181
            goto invalid;
 
182
          }
 
183
 
 
184
        /* As a reference for this code, you can use the GNU libiconv
 
185
           implementation.  Look for uses of the RET_TOOFEW macro.  */
 
186
 
 
187
        if (STREQ (encoding, "EUC-JP", 'E', 'U', 'C', '-', 'J', 'P', 0, 0, 0))
 
188
          {
 
189
            if (m == 1)
 
190
              {
 
191
                unsigned char c = (unsigned char) p[0];
 
192
 
 
193
                if ((c >= 0xa1 && c < 0xff) || c == 0x8e || c == 0x8f)
 
194
                  goto incomplete;
 
195
              }
 
196
            if (m == 2)
 
197
              {
 
198
                unsigned char c = (unsigned char) p[0];
 
199
 
 
200
                if (c == 0x8f)
 
201
                  {
 
202
                    unsigned char c2 = (unsigned char) p[1];
 
203
 
 
204
                    if (c2 >= 0xa1 && c2 < 0xff)
 
205
                      goto incomplete;
 
206
                  }
 
207
              }
 
208
            goto invalid;
 
209
          }
 
210
        if (STREQ (encoding, "EUC-KR", 'E', 'U', 'C', '-', 'K', 'R', 0, 0, 0)
 
211
            || STREQ (encoding, "GB2312", 'G', 'B', '2', '3', '1', '2', 0, 0, 0)
 
212
            || STREQ (encoding, "BIG5", 'B', 'I', 'G', '5', 0, 0, 0, 0, 0))
 
213
          {
 
214
            if (m == 1)
 
215
              {
 
216
                unsigned char c = (unsigned char) p[0];
 
217
 
 
218
                if (c >= 0xa1 && c < 0xff)
 
219
                  goto incomplete;
 
220
              }
 
221
            goto invalid;
 
222
          }
 
223
        if (STREQ (encoding, "EUC-TW", 'E', 'U', 'C', '-', 'T', 'W', 0, 0, 0))
 
224
          {
 
225
            if (m == 1)
 
226
              {
 
227
                unsigned char c = (unsigned char) p[0];
 
228
 
 
229
                if ((c >= 0xa1 && c < 0xff) || c == 0x8e)
 
230
                  goto incomplete;
 
231
              }
 
232
            else /* m == 2 || m == 3 */
 
233
              {
 
234
                unsigned char c = (unsigned char) p[0];
 
235
 
 
236
                if (c == 0x8e)
 
237
                  goto incomplete;
 
238
              }
 
239
            goto invalid;
 
240
          }
 
241
        if (STREQ (encoding, "SJIS", 'S', 'J', 'I', 'S', 0, 0, 0, 0, 0))
 
242
          {
 
243
            if (m == 1)
 
244
              {
 
245
                unsigned char c = (unsigned char) p[0];
 
246
 
 
247
                if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xea)
 
248
                    || (c >= 0xf0 && c <= 0xf9))
 
249
                  goto incomplete;
 
250
              }
 
251
            goto invalid;
 
252
          }
 
253
 
 
254
        /* An unknown multibyte encoding.  */
 
255
        goto incomplete;
 
256
      }
 
257
 
 
258
     incomplete:
 
259
      {
 
260
        size_t k = nstate;
 
261
        /* Here 0 < k < m < 4.  */
 
262
        pstate[++k] = s[0];
 
263
        if (k < m)
 
264
          pstate[++k] = s[1];
 
265
        if (k != m)
 
266
          abort ();
 
267
      }
 
268
      pstate[0] = m;
 
269
      return (size_t)(-2);
 
270
 
 
271
     invalid:
 
272
      errno = EILSEQ;
 
273
      /* The conversion state is undefined, says POSIX.  */
 
274
      return (size_t)(-1);
 
275
    }
 
276
  }
 
277
}
 
278
 
 
279
#else
 
280
/* Override the system's mbrtowc() function.  */
 
281
 
 
282
# undef mbrtowc
 
283
 
 
284
size_t
 
285
rpl_mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
 
286
{
 
287
# if MBRTOWC_NULL_ARG_BUG || MBRTOWC_RETVAL_BUG
 
288
  if (s == NULL)
 
289
    {
 
290
      pwc = NULL;
 
291
      s = "";
 
292
      n = 1;
 
293
    }
 
294
# endif
 
295
 
 
296
# if MBRTOWC_RETVAL_BUG
 
297
  {
 
298
    static mbstate_t internal_state;
 
299
 
 
300
    /* Override mbrtowc's internal state.  We can not call mbsinit() on the
 
301
       hidden internal state, but we can call it on our variable.  */
 
302
    if (ps == NULL)
 
303
      ps = &internal_state;
 
304
 
 
305
    if (!mbsinit (ps))
 
306
      {
 
307
        /* Parse the rest of the multibyte character byte for byte.  */
 
308
        size_t count = 0;
 
309
        for (; n > 0; s++, n--)
 
310
          {
 
311
            wchar_t wc;
 
312
            size_t ret = mbrtowc (&wc, s, 1, ps);
 
313
 
 
314
            if (ret == (size_t)(-1))
 
315
              return (size_t)(-1);
 
316
            count++;
 
317
            if (ret != (size_t)(-2))
 
318
              {
 
319
                /* The multibyte character has been completed.  */
 
320
                if (pwc != NULL)
 
321
                  *pwc = wc;
 
322
                return (wc == 0 ? 0 : count);
 
323
              }
 
324
          }
 
325
        return (size_t)(-2);
 
326
      }
 
327
  }
 
328
# endif
 
329
 
 
330
# if MBRTOWC_NUL_RETVAL_BUG
 
331
  {
 
332
    wchar_t wc;
 
333
    size_t ret = mbrtowc (&wc, s, n, ps);
 
334
 
 
335
    if (ret != (size_t)(-1) && ret != (size_t)(-2))
 
336
      {
 
337
        if (pwc != NULL)
 
338
          *pwc = wc;
 
339
        if (wc == 0)
 
340
          ret = 0;
 
341
      }
 
342
    return ret;
 
343
  }
 
344
# else
 
345
  return mbrtowc (pwc, s, n, ps);
 
346
# endif
 
347
}
 
348
 
 
349
#endif