source: libyaml/trunk/src/reader.c @ 181

Revision 181, 14.4 KB checked in by xi, 9 years ago (diff)

Complete UTF-8 and UTF-16 decoders.

Reader is mostly done (though untested).

RevLine 
[179]1
[180]2#if HAVE_CONFIG_H
3#include <config.h>
4#endif
[179]5
[180]6#include <yaml/yaml.h>
7
8#include <assert.h>
9
[179]10/*
[181]11 * Set the reader error and return 0.
[180]12 */
13
[181]14int
15yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem)
16{
17    parser->error = YAML_READER_ERROR;
18    parser->problem = problem;
19    parser->problem_offset = parser->offset;
[180]20
[181]21    return 0;
22}
[180]23
24
25/*
[179]26 * Ensure that the buffer contains at least length characters.
27 * Return 1 on success, 0 on failure.
[180]28 *
29 * The length is supposed to be significantly less that the buffer size.
[179]30 */
31
32int
[180]33yaml_parser_update_buffer(yaml_parser_t *parser, size_t length)
[179]34{
35    /* If the EOF flag is set, do nothing. */
36
37    if (parser->eof)
38        return 1;
39
[180]40    /* Return if the buffer contains enough characters. */
[179]41
[180]42    if (parser->unread >= length)
43        return 1;
44
45    /* Determine the input encoding if it is not known yet. */
46
47    if (!parser->encoding) {
48        if (!yaml_parser_determine_encoding(parser))
[179]49            return 0;
50    }
51
[180]52    /* Move the unread characters to the beginning of the buffer. */
53
54    if (parser->buffer < parser->pointer
55            && parser->pointer < parser->buffer_end) {
56        size_t size = parser->buffer_end - parser->pointer;
57        memmove(parser->buffer, parser->pointer, size);
58        parser->pointer = parser->buffer;
59        parser->buffer_end -= size;
60    }
61    else if (parser->pointer == parser->buffer_end) {
62        parser->pointer = parser->buffer;
63        parser->buffer_end = parser->buffer;
64    }
65
66    /* Fill the buffer until it has enough characters. */
67
68    while (parser->unread < length)
69    {
70        /* Fill the raw buffer. */
71
72        if (!yaml_parser_update_raw_buffer(parser)) return 0;
73
[181]74        /* If the raw buffer is empty, it is EOF. */
75
76        if (!parser->raw_unread) return 1;
77
[180]78        /* Decode the raw buffer. */
79
80        while (parser->raw_unread)
81        {
[181]82            unsigned int value, value2;
[180]83            int incomplete = 0;
[181]84            unsigned char utf8_octet;
85            unsigned int utf8_length;
86            int k, low, high;
[180]87
88            /* Decode the next character. */
89
90            switch (parser->encoding)
91            {
92                case YAML_UTF8_ENCODING:
93
[181]94                    /*
95                     * Decode a UTF-8 character.  Check RFC 3629
96                     * (http://www.ietf.org/rfc/rfc3629.txt) for more details.
97                     *
98                     * The following table (taken from the RFC) is used for
99                     * decoding.
100                     *
101                     *    Char. number range |        UTF-8 octet sequence
102                     *      (hexadecimal)    |              (binary)
103                     *   --------------------+------------------------------------
104                     *   0000 0000-0000 007F | 0xxxxxxx
105                     *   0000 0080-0000 07FF | 110xxxxx 10xxxxxx
106                     *   0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
107                     *   0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
108                     *
109                     * Additionally, the characters in the range 0xD800-0xDFFF
110                     * are prohibited as they are reserved for use with UTF-16
111                     * surrogate pairs.
112                     */
[180]113
[181]114                    /* Determine the length of the UTF-8 sequence. */
115
116                    utf8_octet = parser->raw_pointer[0];
117                    utf8_length = (
118                            (utf8_octet & 0x80) == 0x00 ? 1 :
119                            (utf8_octet & 0xE0) == 0xC0 ? 2 :
120                            (utf8_octet & 0xF0) == 0xE0 ? 3 :
121                            (utf8_octet & 0xF8) == 0xF0 ? 4 : 0);
122
123                    /* Check if the leading octet is valid. */
124
125                    if (!utf8_length)
126                        return yaml_parser_set_reader_error(parser,
127                                "Invalid leading UTF-8 octet");
128
[180]129                    /* Check if the raw buffer contains an incomplete character. */
130
131                    if (utf8_length > parser->raw_unread) {
132                        if (parser->eof) {
[181]133                            return yaml_parser_set_reader_error(parser,
134                                    "Incomplete UTF-8 octet sequence");
[180]135                        }
136                        incomplete = 1;
[181]137                        break;
[180]138                    }
139
[181]140                    /* Decode the leading octet. */
[180]141
[181]142                    value = (
143                        (utf8_octet & 0x80) == 0x00 ? utf8_octet & 0x7F :
144                        (utf8_octet & 0xE0) == 0xC0 ? utf8_octet & 0x1F :
145                        (utf8_octet & 0xF0) == 0xE0 ? utf8_octet & 0x0F :
146                        (utf8_octet & 0xF8) == 0xF0 ? utf8_octet & 0x07 : 0);
147
148                    /* Check and decode the trailing octets. */
149
150                    for (k = 1; k < utf8_length; k ++)
151                    {
152                        utf8_octet = parser->raw_pointer[k];
153
154                        /* Check if the octet is valid. */
155
156                        if ((utf8_octet & 0xC0) != 0x80)
157                            return yaml_parser_set_reader_error(parser,
158                                    "Invalid trailing UTF-8 octet");
159
160                        /* Decode the octet. */
161
162                        value = (value << 6) + (utf8_octet & 0x3F);
[180]163                    }
164
[181]165                    /* Check the length of the sequence against the value. */
166
167                    if (!((utf8_length == 1) ||
168                            (utf8_length == 2 && value >= 0x80) ||
169                            (utf8_length == 3 && value >= 0x800) ||
170                            (utf8_length == 4 && value >= 0x10000)))
171                        return yaml_parser_set_reader_error(parser,
172                                "Invalid length of a UTF-8 sequence");
173
174                    /* Check the range of the value. */
175
176                    if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF)
177                        return yaml_parser_set_reader_error(parser,
178                                "Invalid Unicode character");
179
180                    parser->raw_pointer += utf8_length;
181                    parser->raw_unread -= utf8_length;
182                    parser->offset += utf8_length;
183
[180]184                    break;
185               
186                case YAML_UTF16LE_ENCODING:
[181]187                case YAML_UTF16BE_ENCODING:
[180]188
[181]189                    low = (parser->encoding == YAML_UTF16LE_ENCODING ? 0 : 1);
190                    high = (parser->encoding == YAML_UTF16LE_ENCODING ? 1 : 0);
[180]191
[181]192                    /*
193                     * The UTF-16 encoding is not as simple as one might
194                     * naively think.  Check RFC 2781
195                     * (http://www.ietf.org/rfc/rfc2781.txt).
196                     *
197                     * Normally, two subsequent bytes describe a Unicode
198                     * character.  However a special technique (called a
199                     * surrogate pair) is used for specifying character
200                     * values larger than 0xFFFF.
201                     *
202                     * A surrogate pair consists of two pseudo-characters:
203                     *      high surrogate area (0xD800-0xDBFF)
204                     *      low surrogate area (0xDC00-0xDFFF)
205                     *
206                     * The following formulas are used for decoding
207                     * and encoding characters using surrogate pairs:
208                     *
209                     *  U  = U' + 0x10000   (0x01 00 00 <= U <= 0x10 FF FF)
210                     *  U' = yyyyyyyyyyxxxxxxxxxx   (0 <= U' <= 0x0F FF FF)
211                     *  W1 = 110110yyyyyyyyyy
212                     *  W2 = 110111xxxxxxxxxx
213                     *
214                     * where U is the character value, W1 is the high surrogate
215                     * area, W2 is the low surrogate area.
216                     */
217
218                    /* Check for incomplete UTF-16 character. */
219
[180]220                    if (parser->raw_unread < 2) {
221                        if (parser->eof) {
[181]222                            return yaml_parser_set_reader_error(parser,
223                                    "Incomplete UTF-16 character");
[180]224                        }
225                        incomplete = 1;
[181]226                        break;
[180]227                    }
228
[181]229                    /* Get the character. */
[180]230
[181]231                    value = parser->raw_pointer[low]
232                        + (parser->raw_pointer[high] << 8);
[180]233
[181]234                    /* Check for unexpected low surrogate area. */
[180]235
[181]236                    if ((value & 0xFC00) == 0xDC00)
237                        return yaml_parser_set_reader_error(parser,
238                                "Unexpected low surrogate area");
[180]239
[181]240                    /* Check for a high surrogate area. */
[180]241
[181]242                    if ((value & 0xFC00) == 0xD800) {
243
244                        /* Check for incomplete surrogate pair. */
245
246                        if (parser->raw_unread < 4) {
247                            if (parser->eof) {
248                                return yaml_parser_set_reader_error(parser,
249                                        "Incomplete UTF-16 surrogate pair");
250                            }
251                            incomplete = 1;
252                            break;
[180]253                        }
[181]254
255                        /* Get the next character. */
256
257                        unsigned int value2 = parser->raw_pointer[low+2]
258                            + (parser->raw_pointer[high+2] << 8);
259
260                        /* Check for a low surrogate area. */
261
262                        if ((value2 & 0xFC00) != 0xDC00)
263                            return yaml_parser_set_reader_error(parser,
264                                    "Expected low surrogate area");
265
266                        /* Generate the value of the surrogate pair. */
267
268                        value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF);
269
270                        parser->raw_pointer += 4;
271                        parser->raw_unread -= 4;
272                        parser->offset += 4;
[180]273                    }
274
[181]275                    else {
276                        parser->raw_pointer += 2;
277                        parser->raw_unread -= 2;
278                        parser->offset += 4;
279                    }
[180]280
281                    break;
282            }
283
[181]284            /* Check if the raw buffer contains enough bytes to form a character. */
285
286            if (incomplete) break;
287
[180]288            /*
289             * Check if the character is in the allowed range:
290             *      #x9 | #xA | #xD | [#x20-#x7E]               (8 bit)
291             *      | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD]    (16 bit)
292             *      | [#x10000-#x10FFFF]                        (32 bit)
293             */
294
[181]295            if (! (value == 0x09 || value == 0x0A || value == 0x0D
296                        || (value >= 0x20 && value <= 0x7E)
297                        || (value == 0x85) || (value >= 0xA0 && value <= 0xD7FF)
298                        || (value >= 0xE000 && value <= 0xFFFD)
299                        || (value >= 0x10000 && value <= 0x10FFFF)))
300                return yaml_parser_set_reader_error(parser,
301                        "Control characters are not allowed");
[180]302
303            /* Finally put the character into the buffer. */
304
305            /* 0000 0000-0000 007F -> 0xxxxxxx */
[181]306            if (value <= 0x7F) {
307                *(parser->buffer_end++) = value;
[180]308            }
309            /* 0000 0080-0000 07FF -> 110xxxxx 10xxxxxx */
[181]310            else if (value <= 0x7FF) {
311                *(parser->buffer_end++) = 0xC0 + (value >> 6);
312                *(parser->buffer_end++) = 0x80 + value & 0x3F;
[180]313            }
314            /* 0000 0800-0000 FFFF -> 1110xxxx 10xxxxxx 10xxxxxx */
[181]315            else if (value <= 0xFFFF) {
316                *(parser->buffer_end++) = 0xE0 + (value >> 12);
317                *(parser->buffer_end++) = 0x80 + (value >> 6) & 0x3F;
318                *(parser->buffer_end++) = 0x80 + value & 0x3F;
[180]319            }
320            /* 0001 0000-0010 FFFF -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
321            else {
[181]322                *(parser->buffer_end++) = 0xF0 + (value >> 18);
323                *(parser->buffer_end++) = 0x80 + (value >> 12) & 0x3F;
324                *(parser->buffer_end++) = 0x80 + (value >> 6) & 0x3F;
325                *(parser->buffer_end++) = 0x80 + value & 0x3F;
[180]326            }
[179]327        }
328    }
329
[181]330    return 1;
[180]331}
[179]332
[180]333/*
334 * Determine the input stream encoding by checking the BOM symbol. If no BOM is
335 * found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure.
336 */
337
[181]338#define BOM_UTF8    "\xef\xbb\xbf"
339#define BOM_UTF16LE "\xff\xfe"
340#define BOM_UTF16BE "\xfe\xff"
341
[180]342int
343yaml_parser_determine_encoding(yaml_parser_t *parser)
344{
345    /* Ensure that we had enough bytes in the raw buffer. */
346
[181]347    while (!parser->eof && parser->raw_unread < 3) {
[180]348        if (!yaml_parser_update_raw_buffer(parser)) {
[179]349            return 0;
[180]350        }
[179]351    }
352
[180]353    /* Determine the encoding. */
[179]354
[181]355    if (parser->raw_unread >= 2
356            && !memcmp(parser->raw_pointer, BOM_UTF16LE, 2)) {
357        parser->encoding = YAML_UTF16LE_ENCODING;
358        parser->raw_pointer += 2;
359        parser->raw_unread -= 2;
360    }
361    else if (parser->raw_unread >= 2
362            && !memcmp(parser->raw_pointer, BOM_UTF16BE, 2)) {
[180]363        parser->encoding = YAML_UTF16BE_ENCODING;
[181]364        parser->raw_pointer += 2;
365        parser->raw_unread -= 2;
[180]366    }
[181]367    else if (parser->raw_unread >= 3
368            && !memcmp(parser->raw_pointer, BOM_UTF8, 3)) {
369        parser->encoding = YAML_UTF8_ENCODING;
370        parser->raw_pointer += 3;
371        parser->raw_unread -= 3;
[180]372    }
373    else {
374        parser->encoding = YAML_UTF8_ENCODING;
375    }
[181]376
377    return 1;
[179]378}
379
[180]380/*
381 * Update the raw buffer.
382 */
[179]383
[180]384int
385yaml_parser_update_raw_buffer(yaml_parser_t *parser)
386{
387    size_t size_read = 0;
[179]388
[180]389    /* Return if the raw buffer is full. */
390
391    if (parser->raw_unread == YAML_RAW_BUFFER_SIZE) return 1;
392
393    /* Return on EOF. */
394
395    if (parser->eof) return 1;
396
397    /* Move the remaining bytes in the raw buffer to the beginning. */
398
399    if (parser->raw_unread && parser->raw_buffer < parser->raw_pointer) {
400        memmove(parser->raw_buffer, parser->raw_pointer, parser->raw_unread);
401    }
402    parser->raw_pointer = parser->raw_buffer;
403
404    /* Call the read handler to fill the buffer. */
405
406    if (!parser->read_handler(parser->read_handler_data,
407                parser->raw_buffer + parser->raw_unread,
408                YAML_RAW_BUFFER_SIZE - parser->raw_unread,
409                &size_read)) {
[181]410        return yaml_parser_set_reader_error(parser, "Input error");
[180]411    }
412    parser->raw_unread += size_read;
413    if (!size_read) {
414        parser->eof = 1;
415    }
416
417    return 1;
418}
419
Note: See TracBrowser for help on using the repository browser.