OSDN Git Service

2004-01-23 Artem B. Bityuckiy <abitytsky@softminecorp.com>
[pf3gnuchains/pf3gnuchains4x.git] / newlib / libc / iconv / ces / utf-16.c
1 /*-
2  * Copyright (c) 1999,2000
3  *    Konstantin Chuguev.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *    iconv (Charset Conversion Library) v2.0
27  */
28 #ifdef ENABLE_ICONV
29  
30 #include "../lib/deps.h"
31
32 #ifdef ICONV_CONVERTER_UTF_16
33
34 #include <_ansi.h>
35 #include <string.h>
36 #include "../lib/local.h"
37
38 static ssize_t
39 _DEFUN(convert_from_ucs, (ces, in, outbuf, outbytesleft),
40                          struct iconv_ces *ces  _AND
41                          ucs_t in               _AND
42                          unsigned char **outbuf _AND
43                          size_t *outbytesleft)
44 {
45     unsigned char *cp;
46     int *state;
47     int bytes;
48
49     if (in == UCS_CHAR_NONE)
50         return 1;    /* No state reinitialization for table charsets */
51     if (in > 0x10FFFF)
52         return -1;
53     bytes = *(state = (int *)(ces->data)) ? 2 : 4;
54     if (in > 0xFFFF)
55         bytes += 2;
56     if (*outbytesleft < bytes)
57         return 0;    /* No space in the output buffer */
58     cp = *outbuf;
59     if (*state == 0) {
60         *cp++ = 0xFE;
61         *cp++ = 0xFF;
62         *state = 1;
63     }
64     if (in > 0xFFFF) {
65         *cp++ = ((in -= 0x10000) >> 18) | 0xD8;
66         *cp++ = (in >> 10) & 0xFF;
67         *cp++ = ((in >> 8) & 3) | 0xDC;
68     } else
69         *cp++ = (in >> 8) & 0xFF;
70     *cp++ = in & 0xFF;
71     (*outbuf) += bytes;
72     *outbytesleft -= bytes;
73     return 1;
74 }
75
76 static __inline ucs_t
77 _DEFUN(msb, (buf), _CONST unsigned char *buf)
78 {
79     return (buf[0] << 8) | buf[1];
80 }
81
82 static ucs_t
83 _DEFUN(convert_to_ucs, (ces, inbuf, inbytesleft),
84                        struct iconv_ces *ces        _AND
85                        _CONST unsigned char **inbuf _AND
86                        size_t *inbytesleft)
87 {
88     ucs_t res, res2;
89     int *state, mark;
90
91     if (*inbytesleft < 2)
92         return UCS_CHAR_NONE;    /* Not enough bytes in the input buffer */
93     state = (int *)(ces->data);
94     res = msb(*inbuf);
95     switch (res) {
96         case UCS_CHAR_ZERO_WIDTH_NBSP:
97         if (*state == 0)
98             *state = 1;
99         mark = 1;
100         break;
101         case UCS_CHAR_INVALID:
102         if (*state == 0)
103             *state = 2;
104         mark = 1;
105         break;
106         default:
107         if (*state == 0)
108             *state = 1;
109         mark = 0;
110     }
111     if (mark) {
112         if (*inbytesleft < 4)
113             return UCS_CHAR_NONE;    /* Not enough bytes in the input buffer */
114         *inbytesleft -= 2;
115         res = msb((*inbuf) += 2);
116     }
117     if (*state == 2) {        /* LSB order */
118         res = (*(*inbuf) ++);
119         res |= (*(*inbuf) ++) << 8;
120     } else
121         *inbuf += 2;
122     *inbytesleft -= 2;
123     if ((res & 0xFC00) != 0xD800)    /* Non-surrogate character */
124         return res;
125     if (*inbytesleft < 2)
126         return UCS_CHAR_NONE;    /* Not enough bytes in the input buffer */
127     if (*state == 2) {
128         res2 = (*inbuf)[0];
129         res2 |= (*inbuf)[1] << 8;
130     } else
131         res2 = msb(*inbuf);
132     if ((res2 & 0xFC00) != 0xDC00)    /* Broken surrogate pair */
133         return -1;
134     (*inbuf) += 2;
135     (*inbytesleft) -= 2;
136     return (((res & 0x3FF) << 10) | (res2 & 0x3FF)) + 0x10000;
137 }
138
139 ICONV_CES_STATEFUL_MODULE_DECL(utf_16);
140
141 #endif /* #ifdef ICONV_CONVERTER_UTF_16 */
142
143 #endif /* #ifdef ENABLE_ICONV */
144