~ubuntu-branches/ubuntu/natty/ibm-3270/natty

« back to all changes in this revision

Viewing changes to pr3287/utf8.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2009-12-14 11:48:53 UTC
  • mfrom: (1.1.4 upstream) (2.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20091214114853-mywixml32hct9jr1
Tags: 3.3.10ga4-2
* Fix section to match override.
* Use debhelper compat level 7.
* Use 3.0 (quilt) source format.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2007-2009, Paul Mattes.
 
3
 * 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 are met:
 
7
 *     * Redistributions of source code must retain the above copyright
 
8
 *       notice, this list of conditions and the following disclaimer.
 
9
 *     * Redistributions in binary form must reproduce the above copyright
 
10
 *       notice, this list of conditions and the following disclaimer in the
 
11
 *       documentation and/or other materials provided with the distribution.
 
12
 *     * Neither the names of Paul Mattes nor the names of his contributors
 
13
 *       may be used to endorse or promote products derived from this software
 
14
 *       without specific prior written permission.
 
15
 *
 
16
 * THIS SOFTWARE IS PROVIDED BY PAUL MATTES "AS IS" AND ANY EXPRESS OR IMPLIED
 
17
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 
18
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 
19
 * EVENT SHALL PAUL MATTES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
20
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
21
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 
22
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
23
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 
24
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
25
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
26
 */
 
27
 
 
28
/*
 
29
 *      utf8.c
 
30
 *              3270 Terminal Emulator
 
31
 *              UTF-8 conversions
 
32
 */
 
33
 
 
34
#include "globals.h"
 
35
 
 
36
#include "popupsc.h"
 
37
#include "utf8c.h"
 
38
 
 
39
char *locale_codeset = CN;
 
40
Boolean is_utf8 = False;
 
41
 
 
42
/*
 
43
 * Save the codeset from the locale, and set globals based on known values.
 
44
 */
 
45
void
 
46
set_codeset(char *codeset_name)
 
47
{
 
48
#if !defined(TCL3270) /*[*/
 
49
        is_utf8 = (!strcasecmp(codeset_name, "utf-8") ||
 
50
                   !strcasecmp(codeset_name, "utf8") ||
 
51
                   !strcasecmp(codeset_name, "utf_8"));
 
52
#else /*][*/
 
53
        /*
 
54
         * tcl3270 is always in UTF-8 mode, because it needs to
 
55
         * supply UTF-8 strings to libtcl and vice-versa.
 
56
         */
 
57
        is_utf8 = True;
 
58
#endif /*]*/
 
59
 
 
60
        Replace(locale_codeset, NewString(codeset_name));
 
61
}
 
62
 
 
63
/*
 
64
 * Convert from UCS-4 to UTF-8.
 
65
 * Returns:
 
66
 *    >0: length of converted character
 
67
 *    -1: invalid UCS-4
 
68
 */
 
69
int
 
70
unicode_to_utf8(ucs4_t ucs4, char *utf8)
 
71
{
 
72
    if (ucs4 & 0x80000000)
 
73
        return -1;
 
74
 
 
75
    if (ucs4 <= 0x0000007f) {
 
76
        utf8[0] = ucs4 & 0x7f;                          /*  7 bits */
 
77
        return 1;
 
78
    } else if (ucs4 <= 0x000007ff) {
 
79
        utf8[0] = 0xc0 | ((ucs4 >> 6)  & 0x1f);         /* upper 5 bits */
 
80
        utf8[1] = 0x80 | (ucs4         & 0x3f);         /* lower 6 bits */
 
81
        return 2;
 
82
    } else if (ucs4 <= 0x0000ffff) {
 
83
        utf8[0] = 0xe0 | ((ucs4 >> 12) & 0x0f);         /* upper 4 bits */
 
84
        utf8[1] = 0x80 | ((ucs4 >> 6)  & 0x3f);         /* next 6 bits */
 
85
        utf8[2] = 0x80 | (ucs4 &         0x3f);         /* last 6 bits */
 
86
        return 3;
 
87
    } else if (ucs4 <= 0x001fffff) {
 
88
        utf8[0] = 0xf0 | ((ucs4 >> 18) & 0x07);         /* upper 3 bits */
 
89
        utf8[1] = 0x80 | ((ucs4 >> 12) & 0x3f);         /* next 6 bits */
 
90
        utf8[2] = 0x80 | ((ucs4 >> 6)  & 0x3f);         /* next 6 bits */
 
91
        utf8[3] = 0x80 | (ucs4         & 0x3f);         /* last 6 bits */
 
92
        return 4;
 
93
    } else if (ucs4 <= 0x03ffffff) {
 
94
        utf8[0] = 0xf8 | ((ucs4 >> 24) & 0x03);         /* upper 2 bits */
 
95
        utf8[1] = 0x80 | ((ucs4 >> 18) & 0x3f);         /* next 6 bits */
 
96
        utf8[2] = 0x80 | ((ucs4 >> 12) & 0x3f);         /* next 6 bits */
 
97
        utf8[3] = 0x80 | ((ucs4 >> 6)  & 0x3f);         /* next 6 bits */
 
98
        utf8[4] = 0x80 | (ucs4 &         0x3f);         /* last 6 bits */
 
99
        return 5;
 
100
    } else {
 
101
        utf8[0] = 0xfc | ((ucs4 >> 30) & 0x01);         /* upper 1 bit */
 
102
        utf8[1] = 0x80 | ((ucs4 >> 24) & 0x3f);         /* next 6 bits */
 
103
        utf8[2] = 0x80 | ((ucs4 >> 18) & 0x3f);         /* next 6 bits */
 
104
        utf8[3] = 0x80 | ((ucs4 >> 12) & 0x3f);         /* next 6 bits */
 
105
        utf8[4] = 0x80 | ((ucs4 >> 6)  & 0x3f);         /* next 6 bits */
 
106
        utf8[5] = 0x80 | (ucs4         & 0x3f);         /* last 6 bits */
 
107
        return 6;
 
108
    }
 
109
}
 
110
 
 
111
/*
 
112
 * Convert at most 'len' bytes from a UTF-8 string to one UCS-4 character.
 
113
 * Returns:
 
114
 *    >0: Number of characters consumed.
 
115
 *     0: Incomplete sequence.
 
116
 *    -1: Invalid sequence.
 
117
 *    -2: Illegal (too-long) encoding.
 
118
 *    -3: Invalid lead byte.
 
119
 *
 
120
 * An invalid sequence can be either improperly composed, or using the wrong
 
121
 * encoding length (often used to get past spam filters and such).
 
122
 */
 
123
int
 
124
utf8_to_unicode(const char *utf8, int len, ucs4_t *ucs4)
 
125
{
 
126
    /* No input is by definition incomplete. */
 
127
    if (!len)
 
128
        return 0;
 
129
 
 
130
    /* See if it's ASCII-7. */
 
131
    if ((utf8[0] & 0xff) < 0x80) {
 
132
        *ucs4 = utf8[0] & 0x7f;
 
133
        return 1;
 
134
    }
 
135
 
 
136
    /* Now check for specific UTF-8 leading bytes. */
 
137
    if ((utf8[0] & 0xe0) == 0xc0) {
 
138
        /* 110xxxxx 10xxxxxx
 
139
         * 0x00000080-0x000007ff */
 
140
        if (len < 2)
 
141
            return 0;
 
142
        if ((utf8[1] & 0xc0) != 0x80)
 
143
            return -1;
 
144
        *ucs4 = ((utf8[0] << 6) & 0x7c0) |
 
145
                 (utf8[1] &       0x03f);
 
146
        if (*ucs4 < 0x00000080)
 
147
            return -1;
 
148
        return 2;
 
149
    }
 
150
 
 
151
    if ((utf8[0] & 0xf0) == 0xe0) {
 
152
        /* 1110xxxx 10xxxxxx 10xxxxxx
 
153
         * 0x00000800-0x0000ffff */
 
154
        if (len < 3)
 
155
            return 0;
 
156
        if (((utf8[1] & 0xc0) != 0x80) ||
 
157
            ((utf8[2] & 0xc0) != 0x80))
 
158
            return -1;
 
159
        *ucs4 = ((utf8[0] << 12) & 0xf000) |
 
160
                ((utf8[1] << 6)  & 0x0fc0) |
 
161
                ((utf8[2])       & 0x003f);
 
162
        if (*ucs4 < 0x00000800)
 
163
            return -2;
 
164
        return 3;
 
165
    }
 
166
 
 
167
    if ((utf8[0] & 0xf8) == 0xf0) {
 
168
        /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
 
169
         * 0x00010000-0x001fffff */
 
170
        if (len < 4)
 
171
            return 0;
 
172
        if (((utf8[1] & 0xc0) != 0x80) ||
 
173
            ((utf8[2] & 0xc0) != 0x80) ||
 
174
            ((utf8[3] & 0xc0) != 0x80))
 
175
            return -1;
 
176
        *ucs4 = ((utf8[0] << 18) & 0x1c0000) |
 
177
                ((utf8[1] << 12) & 0x03f000) |
 
178
                ((utf8[2] << 6)  & 0x000fc0) |
 
179
                ((utf8[3])       & 0x00003f);
 
180
        if (*ucs4 < 0x00010000)
 
181
            return -2;
 
182
        return 4;
 
183
    }
 
184
 
 
185
    if ((utf8[0] & 0xfc) == 0xf8) {
 
186
        /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
 
187
         * 0x00200000-0x03ffffff */
 
188
        if (len < 5)
 
189
            return 0;
 
190
        if (((utf8[1] & 0xc0) != 0x80) ||
 
191
            ((utf8[2] & 0xc0) != 0x80) ||
 
192
            ((utf8[3] & 0xc0) != 0x80) ||
 
193
            ((utf8[4] & 0xc0) != 0x80))
 
194
            return -1;
 
195
        *ucs4 = ((utf8[0] << 24) & 0x3000000) |
 
196
                ((utf8[1] << 18) & 0x0fc0000) |
 
197
                ((utf8[2] << 12) & 0x003f000) |
 
198
                ((utf8[3] << 6)  & 0x0000fc0) |
 
199
                ((utf8[4])       & 0x000003f);
 
200
        if (*ucs4 < 0x00200000)
 
201
            return -2;
 
202
        return 5;
 
203
    }
 
204
 
 
205
    if ((utf8[0] & 0xfe) == 0xfc) {
 
206
        /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
 
207
         * 0x04000000-0x7fffffff */
 
208
        if (len < 6)
 
209
            return 0;
 
210
        if (((utf8[1] & 0xc0) != 0x80) ||
 
211
            ((utf8[2] & 0xc0) != 0x80) ||
 
212
            ((utf8[3] & 0xc0) != 0x80) ||
 
213
            ((utf8[4] & 0xc0) != 0x80) ||
 
214
            ((utf8[5] & 0xc0) != 0x80))
 
215
            return -1;
 
216
        *ucs4 = ((utf8[0] << 30) & 0x40000000) |
 
217
                ((utf8[1] << 24) & 0x3f000000) |
 
218
                ((utf8[2] << 18) & 0x00fc0000) |
 
219
                ((utf8[3] << 12) & 0x0003f000) |
 
220
                ((utf8[4] << 6)  & 0x00000fc0) |
 
221
                ((utf8[5])       & 0x0000003f);
 
222
        if (*ucs4 < 0x04000000)
 
223
            return -2;
 
224
        return 6;
 
225
    }
 
226
 
 
227
    return -3;
 
228
}