initial load of upstream version 1.06.32
[xmlrpc-c] / src / xmlrpc_utf8.c
1 /* Copyright (C) 2001 by Eric Kidd. All rights reserved.
2 **
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
5 ** are met:
6 ** 1. Redistributions of source code must retain the above copyright
7 **    notice, this list of conditions and the following disclaimer.
8 ** 2. Redistributions in binary form must reproduce the above copyright
9 **    notice, this list of conditions and the following disclaimer in the
10 **    documentation and/or other materials provided with the distribution.
11 ** 3. The name of the author may not be used to endorse or promote products
12 **    derived from this software without specific prior written permission. 
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
27 /*=========================================================================
28 **  XML-RPC UTF-8 Utilities
29 **=========================================================================
30 **  Routines for validating, encoding and decoding UTF-8 data.  We try to
31 **  be very, very strict about invalid UTF-8 data.
32 **
33 **  All of the code in this file assumes that your machine represents
34 **  wchar_t as a 16-bit (or wider) character containing UCS-2 data.  If this
35 **  assumption is incorrect, you may need to replace this file.
36 **
37 **  For lots of information on Unicode and UTF-8 decoding, see:
38 **    http://www.cl.cam.ac.uk/~mgk25/unicode.html
39 */
40
41 #include "xmlrpc_config.h"
42
43 #include "xmlrpc-c/base.h"
44
45 #if HAVE_UNICODE_WCHAR
46
47 /*=========================================================================
48 **  Tables and Constants
49 **=========================================================================
50 **  We use a variety of tables and constants to help decode and validate
51 **  UTF-8 data.
52 */
53
54 /* The number of bytes in a UTF-8 sequence starting with the character used
55 ** as the array index.  A zero entry indicates an illegal initial byte.
56 ** This table was generated using a Perl script and information from the
57 ** UTF-8 standard.
58 **
59 ** Fredrik Lundh's UTF-8 decoder Python 2.0 uses a similar table.  But
60 ** since Python 2.0 has the icky CNRI license, I regenerated this
61 ** table from scratch and wrote my own decoder. */
62 static unsigned char utf8_seq_length[256] = {
63     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
64     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
65     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
66     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
67     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
68     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
69     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
70     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
71     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
72     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
74     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
75     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
76     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
77     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
78     4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0
79 };
80
81 /* The minimum legal character value for a UTF-8 sequence of the given
82 ** length.  We have to check this to avoid accepting "overlong" UTF-8
83 ** sequences, which use more bytes than necessary to encode a given
84 ** character.  Such sequences are commonly used by evil people to bypass
85 ** filters and security checks.  This table is based on the UTF-8-test.txt
86 ** file by Markus Kuhn <mkuhn@acm.org>. */
87 static wchar_t utf8_min_char_for_length[4] = {
88     0,          /* Length 0: Not used (meaningless) */
89     0x0000,     /* Length 1: Not used (special-cased) */
90     0x0080,     /* Length 2 */
91     0x0800      /* Length 3 */
92
93 #if 0
94     /* These are only useful on systems where wchar_t is 32-bits wide
95     ** and supports full UCS-4. */
96     0x00010000, /* Length 4 */
97     0x00200000, /* Length 5 */
98     0x04000000  /* Length 6 */
99 #endif
100 };
101
102 /* This is the maximum legal 16-byte (UCS-2) character.  Again, this
103 ** information is based on UTF-8-test.txt. */
104 #define UCS2_MAX_LEGAL_CHARACTER (0xFFFD)
105
106 /* First and last UTF-16 surrogate characters.  These are *not* legal UCS-2
107 ** characters--they're used to code for UCS-4 characters when using
108 ** UTF-16.  They should never appear in decoded UTF-8 data!  Again, these
109 ** could hypothetically be used to bypass security measures on some machines.
110 ** Based on UTF-8-test.txt. */
111 #define UTF16_FIRST_SURROGATE (0xD800)
112 #define UTF16_LAST_SURROGATE  (0xDFFF)
113
114 /* Is the character 'c' a UTF-8 continuation character? */
115 #define IS_CONTINUATION(c) (((c) & 0xC0) == 0x80)
116
117 /* Maximum number of bytes needed to encode a supported character. */
118 #define MAX_ENCODED_BYTES (3)
119
120
121 /*=========================================================================
122 **  decode_utf8
123 **=========================================================================
124 **  Internal routine which decodes (or validates) a UTF-8 string.
125 **  To validate, set io_buff and out_buff_len to NULL.  To decode, allocate
126 **  a sufficiently large buffer, pass it as io_buff, and pass a pointer as
127 **  as out_buff_len.  The data will be written to the buffer, and the
128 **  length to out_buff_len.
129 **
130 **  We assume that wchar_t holds a single UCS-2 character in native-endian
131 **  byte ordering.
132 */
133
134 static void 
135 decode_utf8(xmlrpc_env * const env,
136             const char * const utf8_data,
137             size_t       const utf8_len,
138             wchar_t *    const io_buff,
139             size_t *     const out_buff_len) {
140
141     size_t i, length, out_pos;
142     char init, con1, con2;
143     wchar_t wc;
144
145     XMLRPC_ASSERT_ENV_OK(env);
146     XMLRPC_ASSERT_PTR_OK(utf8_data);
147     XMLRPC_ASSERT((!io_buff && !out_buff_len) ||
148                   (io_buff && out_buff_len));
149
150     /* Suppress GCC warning about possibly undefined variable. */
151     wc = 0;
152
153     i = 0;
154     out_pos = 0;
155     while (i < utf8_len) {
156         init = utf8_data[i];
157         if ((init & 0x80) == 0x00) {
158             /* Convert ASCII character to wide character. */
159             wc = init;
160             i++;
161         } else {
162             /* Look up the length of this UTF-8 sequence. */
163             length = utf8_seq_length[(unsigned char) init];
164             
165             /* Check to make sure we have enough bytes to convert. */
166             if (i + length > utf8_len)
167                 XMLRPC_FAIL(env, XMLRPC_INVALID_UTF8_ERROR,
168                             "Truncated UTF-8 sequence");
169             
170             /* Decode a multibyte UTF-8 sequence. */
171             switch (length) {
172             case 0:
173                 XMLRPC_FAIL(env, XMLRPC_INVALID_UTF8_ERROR,
174                             "Invalid UTF-8 initial byte");
175                 
176             case 2:
177                 /* 110xxxxx 10xxxxxx */
178                 con1 = utf8_data[i+1];
179                 if (!IS_CONTINUATION(con1))
180                     XMLRPC_FAIL(env, XMLRPC_INVALID_UTF8_ERROR,
181                                 "UTF-8 sequence too short");
182                 wc = ((((wchar_t) (init & 0x1F)) <<  6) |
183                       (((wchar_t) (con1 & 0x3F))));
184                 break;
185                 
186             case 3:
187                 /* 1110xxxx 10xxxxxx 10xxxxxx */
188                 con1 = utf8_data[i+1];
189                 con2 = utf8_data[i+2];
190                 if (!IS_CONTINUATION(con1) || !IS_CONTINUATION(con2))
191                     XMLRPC_FAIL(env, XMLRPC_INVALID_UTF8_ERROR,
192                                 "UTF-8 sequence too short");
193                 wc = ((((wchar_t) (init & 0x0F)) << 12) |
194                       (((wchar_t) (con1 & 0x3F)) <<  6) |
195                       (((wchar_t) (con2 & 0x3F))));
196                 break;
197                 
198             case 4:
199                 /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
200             case 5:
201                 /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
202             case 6:
203                 /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
204                 XMLRPC_FAIL(env, XMLRPC_INVALID_UTF8_ERROR,
205                             "UCS-4 characters not supported");
206                 
207             default:
208                 XMLRPC_ASSERT("Error in UTF-8 decoder tables");
209             }
210             
211             /* Advance to the end of the sequence. */
212             i += length;
213             
214             /* Check for illegal UCS-2 characters. */
215             if (wc > UCS2_MAX_LEGAL_CHARACTER)
216                 XMLRPC_FAIL(env, XMLRPC_INVALID_UTF8_ERROR,
217                             "UCS-2 characters > U+FFFD are illegal");
218             
219             /* Check for UTF-16 surrogates. */
220             if (UTF16_FIRST_SURROGATE <= wc && wc <= UTF16_LAST_SURROGATE)
221                 XMLRPC_FAIL(env, XMLRPC_INVALID_UTF8_ERROR,
222                             "UTF-16 surrogates may not appear in UTF-8 data");
223             
224             /* Check for overlong sequences. */
225             if (wc < utf8_min_char_for_length[length])
226                 XMLRPC_FAIL(env, XMLRPC_INVALID_UTF8_ERROR,
227                             "Overlong UTF-8 sequence not allowed");
228         }
229         
230         /* If we have a buffer, write our character to it. */
231         if (io_buff) {
232             io_buff[out_pos++] = wc;
233         }
234     }
235     
236     /* Record the number of characters we found. */
237     if (out_buff_len)
238         *out_buff_len = out_pos;
239     
240             cleanup:
241     if (env->fault_occurred) {
242         if (out_buff_len)
243             *out_buff_len = 0;
244     }
245 }
246
247
248
249 /*=========================================================================
250 **  xmlrpc_validate_utf8
251 **=========================================================================
252 **  Make sure that a UTF-8 string is valid.
253 */
254
255 void 
256 xmlrpc_validate_utf8 (xmlrpc_env * const env,
257                       const char * const utf8_data,
258                       size_t       const utf8_len) {
259
260     decode_utf8(env, utf8_data, utf8_len, NULL, NULL);
261 }
262
263
264
265 xmlrpc_mem_block *
266 xmlrpc_utf8_to_wcs(xmlrpc_env * const envP,
267                    const char * const utf8_data,
268                    size_t       const utf8_len) {
269 /*----------------------------------------------------------------------------
270   Decode UTF-8 string to a "wide character string".  This function
271   returns an xmlrpc_mem_block with an element type of wchar_t.  Don't
272   try to intepret the block in a bytewise fashion--it won't work in
273   any useful or portable fashion.
274 -----------------------------------------------------------------------------*/
275     xmlrpc_mem_block *output;
276     size_t wcs_length;
277
278     /* Allocate a memory block large enough to hold any possible output.
279        We assume that each byte of the input may decode to a whcar_t.
280     */
281     output = XMLRPC_MEMBLOCK_NEW(wchar_t, envP, utf8_len);
282     if (!envP->fault_occurred) {
283         /* Decode the UTF-8 data. */
284         decode_utf8(envP, utf8_data, utf8_len,
285                     XMLRPC_MEMBLOCK_CONTENTS(wchar_t, output),
286                     &wcs_length);
287         if (!envP->fault_occurred) {
288             /* We can't have overrun our buffer. */
289             XMLRPC_ASSERT(wcs_length <= utf8_len);
290
291             /* Correct the length of the memory block. */
292             XMLRPC_MEMBLOCK_RESIZE(wchar_t, envP, output, wcs_length);
293         }
294         if (envP->fault_occurred)
295             xmlrpc_mem_block_free(output);
296     }
297     if (envP->fault_occurred)
298         output = NULL;
299
300     return output;
301 }
302
303
304
305 /*=========================================================================
306 **  xmlrpc_utf8_to_wcs
307 **=========================================================================
308 **  Encode a "wide character string" as UTF-8.
309 */
310
311 xmlrpc_mem_block *xmlrpc_wcs_to_utf8 (xmlrpc_env *env,
312                                       wchar_t *wcs_data,
313                                       size_t wcs_len)
314 {
315     size_t estimate, bytes_used, i;
316     xmlrpc_mem_block *output;
317     unsigned char *buffer;
318     wchar_t wc;
319
320     XMLRPC_ASSERT_ENV_OK(env);
321     XMLRPC_ASSERT_PTR_OK(wcs_data);
322
323     /* Error-handling preconditions. */
324     output = NULL;
325
326     /* Allocate a memory block large enough to hold any possible output.
327     ** We assume that every wchar might encode to the maximum length. */
328     estimate = wcs_len * MAX_ENCODED_BYTES;
329     output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, env, estimate);
330     XMLRPC_FAIL_IF_FAULT(env);
331
332     /* Output our characters. */
333     buffer = (unsigned char*) XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output);
334     bytes_used = 0;
335     for (i = 0; i < wcs_len; i++) {
336         wc = wcs_data[i];
337         if (wc <= 0x007F) {
338             buffer[bytes_used++] = wc & 0x7F;
339         } else if (wc <= 0x07FF) {
340             /* 110xxxxx 10xxxxxx */
341             buffer[bytes_used++] = 0xC0 | (wc >> 6);
342             buffer[bytes_used++] = 0x80 | (wc & 0x3F);
343         } else if (wc <= 0xFFFF) {
344             /* 1110xxxx 10xxxxxx 10xxxxxx */
345             buffer[bytes_used++] = 0xE0 | (wc >> 12);
346             buffer[bytes_used++] = 0x80 | ((wc >> 6) & 0x3F);
347             buffer[bytes_used++] = 0x80 | (wc & 0x3F);
348         } else {
349             XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR,
350                         "Don't know how to encode UCS-4 characters yet");
351         }
352     }
353
354     /* Make sure we didn't overrun our buffer. */
355     XMLRPC_ASSERT(bytes_used <= estimate);
356
357     /* Correct the length of the memory block. */
358     XMLRPC_TYPED_MEM_BLOCK_RESIZE(char, env, output, bytes_used);
359     XMLRPC_FAIL_IF_FAULT(env);
360
361  cleanup:
362     if (env->fault_occurred) {
363         if (output)
364             xmlrpc_mem_block_free(output);
365         return NULL;
366     }
367     return output;
368 }
369
370
371
372 #else /* HAVE_UNICODE_WCHAR */
373
374 xmlrpc_mem_block *
375 xmlrpc_utf8_to_wcs(xmlrpc_env * const envP,
376                    const char * const utf8_data ATTR_UNUSED,
377                    size_t       const utf8_len ATTR_UNUSED) {
378
379     xmlrpc_faultf(envP, "INTERNAL ERROR: xmlrpc_utf8_to_wcs() called "
380                   "on a system that doesn't do Unicode!");
381
382     return NULL;
383 }
384 #endif /* HAVE_UNICODE_WCHAR */
385
386