X-Git-Url: http://andersk.mit.edu/gitweb/libyaml.git/blobdiff_plain/3d790dfd5e1b802ce1ab82ff830d72eadd25e901..e4fd0393e6e97439666527db71c1fa18482778a7:/src/reader.c diff --git a/src/reader.c b/src/reader.c index 5ee8c43..f1a06de 100644 --- a/src/reader.c +++ b/src/reader.c @@ -1,40 +1,153 @@ -#if HAVE_CONFIG_H -#include -#endif +#include "yaml_private.h" -#include +/* + * Declarations. + */ + +static int +yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem, + size_t offset, int value); + +static int +yaml_parser_update_raw_buffer(yaml_parser_t *parser); + +static int +yaml_parser_determine_encoding(yaml_parser_t *parser); -#include +YAML_DECLARE(int) +yaml_parser_update_buffer(yaml_parser_t *parser, size_t length); /* * Set the reader error and return 0. */ -int -yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem) +static int +yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem, + size_t offset, int value) { parser->error = YAML_READER_ERROR; parser->problem = problem; - parser->problem_offset = parser->offset; + parser->problem_offset = offset; + parser->problem_value = value; return 0; } +/* + * Byte order marks. + */ + +#define BOM_UTF8 "\xef\xbb\xbf" +#define BOM_UTF16LE "\xff\xfe" +#define BOM_UTF16BE "\xfe\xff" /* - * Ensure that the buffer contains at least length characters. + * Determine the input stream encoding by checking the BOM symbol. If no BOM is + * found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure. + */ + +static int +yaml_parser_determine_encoding(yaml_parser_t *parser) +{ + /* Ensure that we had enough bytes in the raw buffer. */ + + while (!parser->eof + && parser->raw_buffer.last - parser->raw_buffer.pointer < 3) { + if (!yaml_parser_update_raw_buffer(parser)) { + return 0; + } + } + + /* Determine the encoding. */ + + if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 2 + && !memcmp(parser->raw_buffer.pointer, BOM_UTF16LE, 2)) { + parser->encoding = YAML_UTF16LE_ENCODING; + parser->raw_buffer.pointer += 2; + parser->offset += 2; + } + else if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 2 + && !memcmp(parser->raw_buffer.pointer, BOM_UTF16BE, 2)) { + parser->encoding = YAML_UTF16BE_ENCODING; + parser->raw_buffer.pointer += 2; + parser->offset += 2; + } + else if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 3 + && !memcmp(parser->raw_buffer.pointer, BOM_UTF8, 3)) { + parser->encoding = YAML_UTF8_ENCODING; + parser->raw_buffer.pointer += 3; + parser->offset += 3; + } + else { + parser->encoding = YAML_UTF8_ENCODING; + } + + return 1; +} + +/* + * Update the raw buffer. + */ + +static int +yaml_parser_update_raw_buffer(yaml_parser_t *parser) +{ + size_t size_read = 0; + + /* Return if the raw buffer is full. */ + + if (parser->raw_buffer.start == parser->raw_buffer.pointer + && parser->raw_buffer.last == parser->raw_buffer.end) + return 1; + + /* Return on EOF. */ + + if (parser->eof) return 1; + + /* Move the remaining bytes in the raw buffer to the beginning. */ + + if (parser->raw_buffer.start < parser->raw_buffer.pointer + && parser->raw_buffer.pointer < parser->raw_buffer.last) { + memmove(parser->raw_buffer.start, parser->raw_buffer.pointer, + parser->raw_buffer.last - parser->raw_buffer.pointer); + } + parser->raw_buffer.last -= + parser->raw_buffer.pointer - parser->raw_buffer.start; + parser->raw_buffer.pointer = parser->raw_buffer.start; + + /* Call the read handler to fill the buffer. */ + + if (!parser->read_handler(parser->read_handler_data, parser->raw_buffer.last, + parser->raw_buffer.end - parser->raw_buffer.last, &size_read)) { + return yaml_parser_set_reader_error(parser, "input error", + parser->offset, -1); + } + parser->raw_buffer.last += size_read; + if (!size_read) { + parser->eof = 1; + } + + return 1; +} + +/* + * Ensure that the buffer contains at least `length` characters. * Return 1 on success, 0 on failure. * * The length is supposed to be significantly less that the buffer size. */ -int +YAML_DECLARE(int) yaml_parser_update_buffer(yaml_parser_t *parser, size_t length) { - /* If the EOF flag is set, do nothing. */ + int first = 1; + + assert(parser->read_handler); /* Read handler must be set. */ - if (parser->eof) + /* If the EOF flag is set and the raw buffer is empty, do nothing. */ + + if (parser->eof && parser->raw_buffer.pointer == parser->raw_buffer.last) return 1; /* Return if the buffer contains enough characters. */ @@ -51,39 +164,40 @@ yaml_parser_update_buffer(yaml_parser_t *parser, size_t length) /* Move the unread characters to the beginning of the buffer. */ - if (parser->buffer < parser->pointer - && parser->pointer < parser->buffer_end) { - size_t size = parser->buffer_end - parser->pointer; - memmove(parser->buffer, parser->pointer, size); - parser->pointer = parser->buffer; - parser->buffer_end -= size; + if (parser->buffer.start < parser->buffer.pointer + && parser->buffer.pointer < parser->buffer.last) { + size_t size = parser->buffer.last - parser->buffer.pointer; + memmove(parser->buffer.start, parser->buffer.pointer, size); + parser->buffer.pointer = parser->buffer.start; + parser->buffer.last = parser->buffer.start + size; } - else if (parser->pointer == parser->buffer_end) { - parser->pointer = parser->buffer; - parser->buffer_end = parser->buffer; + else if (parser->buffer.pointer == parser->buffer.last) { + parser->buffer.pointer = parser->buffer.start; + parser->buffer.last = parser->buffer.start; } /* Fill the buffer until it has enough characters. */ while (parser->unread < length) { - /* Fill the raw buffer. */ - - if (!yaml_parser_update_raw_buffer(parser)) return 0; - - /* If the raw buffer is empty, it is EOF. */ + /* Fill the raw buffer if necessary. */ - if (!parser->raw_unread) return 1; + if (!first || parser->raw_buffer.pointer == parser->raw_buffer.last) { + if (!yaml_parser_update_raw_buffer(parser)) return 0; + } + first = 0; /* Decode the raw buffer. */ - while (parser->raw_unread) + while (parser->raw_buffer.pointer != parser->raw_buffer.last) { - unsigned int value, value2; + unsigned int value = 0, value2 = 0; int incomplete = 0; - unsigned char utf8_octet; - unsigned int utf8_length; - int k, low, high; + unsigned char octet; + unsigned int width = 0; + int low, high; + size_t k; + size_t raw_unread = parser->raw_buffer.last - parser->raw_buffer.pointer; /* Decode the next character. */ @@ -113,25 +227,26 @@ yaml_parser_update_buffer(yaml_parser_t *parser, size_t length) /* Determine the length of the UTF-8 sequence. */ - utf8_octet = parser->raw_pointer[0]; - utf8_length = ( - (utf8_octet & 0x80) == 0x00 ? 1 : - (utf8_octet & 0xE0) == 0xC0 ? 2 : - (utf8_octet & 0xF0) == 0xE0 ? 3 : - (utf8_octet & 0xF8) == 0xF0 ? 4 : 0); + octet = parser->raw_buffer.pointer[0]; + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; /* Check if the leading octet is valid. */ - if (!utf8_length) + if (!width) return yaml_parser_set_reader_error(parser, - "Invalid leading UTF-8 octet"); + "invalid leading UTF-8 octet", + parser->offset, octet); /* Check if the raw buffer contains an incomplete character. */ - if (utf8_length > parser->raw_unread) { + if (width > raw_unread) { if (parser->eof) { return yaml_parser_set_reader_error(parser, - "Incomplete UTF-8 octet sequence"); + "incomplete UTF-8 octet sequence", + parser->offset, -1); } incomplete = 1; break; @@ -139,50 +254,48 @@ yaml_parser_update_buffer(yaml_parser_t *parser, size_t length) /* Decode the leading octet. */ - value = ( - (utf8_octet & 0x80) == 0x00 ? utf8_octet & 0x7F : - (utf8_octet & 0xE0) == 0xC0 ? utf8_octet & 0x1F : - (utf8_octet & 0xF0) == 0xE0 ? utf8_octet & 0x0F : - (utf8_octet & 0xF8) == 0xF0 ? utf8_octet & 0x07 : 0); + value = (octet & 0x80) == 0x00 ? octet & 0x7F : + (octet & 0xE0) == 0xC0 ? octet & 0x1F : + (octet & 0xF0) == 0xE0 ? octet & 0x0F : + (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; /* Check and decode the trailing octets. */ - for (k = 1; k < utf8_length; k ++) + for (k = 1; k < width; k ++) { - utf8_octet = parser->raw_pointer[k]; + octet = parser->raw_buffer.pointer[k]; /* Check if the octet is valid. */ - if ((utf8_octet & 0xC0) != 0x80) + if ((octet & 0xC0) != 0x80) return yaml_parser_set_reader_error(parser, - "Invalid trailing UTF-8 octet"); + "invalid trailing UTF-8 octet", + parser->offset+k, octet); /* Decode the octet. */ - value = (value << 6) + (utf8_octet & 0x3F); + value = (value << 6) + (octet & 0x3F); } /* Check the length of the sequence against the value. */ - if (!((utf8_length == 1) || - (utf8_length == 2 && value >= 0x80) || - (utf8_length == 3 && value >= 0x800) || - (utf8_length == 4 && value >= 0x10000))) + if (!((width == 1) || + (width == 2 && value >= 0x80) || + (width == 3 && value >= 0x800) || + (width == 4 && value >= 0x10000))) return yaml_parser_set_reader_error(parser, - "Invalid length of a UTF-8 sequence"); + "invalid length of a UTF-8 sequence", + parser->offset, -1); /* Check the range of the value. */ if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) return yaml_parser_set_reader_error(parser, - "Invalid Unicode character"); - - parser->raw_pointer += utf8_length; - parser->raw_unread -= utf8_length; - parser->offset += utf8_length; + "invalid Unicode character", + parser->offset, value); break; - + case YAML_UTF16LE_ENCODING: case YAML_UTF16BE_ENCODING: @@ -205,7 +318,7 @@ yaml_parser_update_buffer(yaml_parser_t *parser, size_t length) * * The following formulas are used for decoding * and encoding characters using surrogate pairs: - * + * * U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF) * U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF) * W1 = 110110yyyyyyyyyy @@ -217,10 +330,11 @@ yaml_parser_update_buffer(yaml_parser_t *parser, size_t length) /* Check for incomplete UTF-16 character. */ - if (parser->raw_unread < 2) { + if (raw_unread < 2) { if (parser->eof) { return yaml_parser_set_reader_error(parser, - "Incomplete UTF-16 character"); + "incomplete UTF-16 character", + parser->offset, -1); } incomplete = 1; break; @@ -228,25 +342,29 @@ yaml_parser_update_buffer(yaml_parser_t *parser, size_t length) /* Get the character. */ - value = parser->raw_pointer[low] - + (parser->raw_pointer[high] << 8); + value = parser->raw_buffer.pointer[low] + + (parser->raw_buffer.pointer[high] << 8); /* Check for unexpected low surrogate area. */ if ((value & 0xFC00) == 0xDC00) return yaml_parser_set_reader_error(parser, - "Unexpected low surrogate area"); + "unexpected low surrogate area", + parser->offset, value); /* Check for a high surrogate area. */ if ((value & 0xFC00) == 0xD800) { + width = 4; + /* Check for incomplete surrogate pair. */ - if (parser->raw_unread < 4) { + if (raw_unread < 4) { if (parser->eof) { return yaml_parser_set_reader_error(parser, - "Incomplete UTF-16 surrogate pair"); + "incomplete UTF-16 surrogate pair", + parser->offset, -1); } incomplete = 1; break; @@ -254,31 +372,29 @@ yaml_parser_update_buffer(yaml_parser_t *parser, size_t length) /* Get the next character. */ - unsigned int value2 = parser->raw_pointer[low+2] - + (parser->raw_pointer[high+2] << 8); + value2 = parser->raw_buffer.pointer[low+2] + + (parser->raw_buffer.pointer[high+2] << 8); /* Check for a low surrogate area. */ if ((value2 & 0xFC00) != 0xDC00) return yaml_parser_set_reader_error(parser, - "Expected low surrogate area"); + "expected low surrogate area", + parser->offset+2, value2); /* Generate the value of the surrogate pair. */ value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF); - - parser->raw_pointer += 4; - parser->raw_unread -= 4; - parser->offset += 4; } else { - parser->raw_pointer += 2; - parser->raw_unread -= 2; - parser->offset += 4; + width = 2; } break; + + default: + assert(1); /* Impossible. */ } /* Check if the raw buffer contains enough bytes to form a character. */ @@ -298,121 +414,55 @@ yaml_parser_update_buffer(yaml_parser_t *parser, size_t length) || (value >= 0xE000 && value <= 0xFFFD) || (value >= 0x10000 && value <= 0x10FFFF))) return yaml_parser_set_reader_error(parser, - "Control characters are not allowed"); + "control characters are not allowed", + parser->offset, value); + + /* Move the raw pointers. */ + + parser->raw_buffer.pointer += width; + parser->offset += width; /* Finally put the character into the buffer. */ /* 0000 0000-0000 007F -> 0xxxxxxx */ if (value <= 0x7F) { - *(parser->buffer_end++) = value; + *(parser->buffer.last++) = value; } /* 0000 0080-0000 07FF -> 110xxxxx 10xxxxxx */ else if (value <= 0x7FF) { - *(parser->buffer_end++) = 0xC0 + (value >> 6); - *(parser->buffer_end++) = 0x80 + value & 0x3F; + *(parser->buffer.last++) = 0xC0 + (value >> 6); + *(parser->buffer.last++) = 0x80 + (value & 0x3F); } /* 0000 0800-0000 FFFF -> 1110xxxx 10xxxxxx 10xxxxxx */ else if (value <= 0xFFFF) { - *(parser->buffer_end++) = 0xE0 + (value >> 12); - *(parser->buffer_end++) = 0x80 + (value >> 6) & 0x3F; - *(parser->buffer_end++) = 0x80 + value & 0x3F; + *(parser->buffer.last++) = 0xE0 + (value >> 12); + *(parser->buffer.last++) = 0x80 + ((value >> 6) & 0x3F); + *(parser->buffer.last++) = 0x80 + (value & 0x3F); } /* 0001 0000-0010 FFFF -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ else { - *(parser->buffer_end++) = 0xF0 + (value >> 18); - *(parser->buffer_end++) = 0x80 + (value >> 12) & 0x3F; - *(parser->buffer_end++) = 0x80 + (value >> 6) & 0x3F; - *(parser->buffer_end++) = 0x80 + value & 0x3F; + *(parser->buffer.last++) = 0xF0 + (value >> 18); + *(parser->buffer.last++) = 0x80 + ((value >> 12) & 0x3F); + *(parser->buffer.last++) = 0x80 + ((value >> 6) & 0x3F); + *(parser->buffer.last++) = 0x80 + (value & 0x3F); } - } - } - return 1; -} - -/* - * Determine the input stream encoding by checking the BOM symbol. If no BOM is - * found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure. - */ - -#define BOM_UTF8 "\xef\xbb\xbf" -#define BOM_UTF16LE "\xff\xfe" -#define BOM_UTF16BE "\xfe\xff" - -int -yaml_parser_determine_encoding(yaml_parser_t *parser) -{ - /* Ensure that we had enough bytes in the raw buffer. */ - - while (!parser->eof && parser->raw_unread < 3) { - if (!yaml_parser_update_raw_buffer(parser)) { - return 0; + parser->unread ++; } - } - - /* Determine the encoding. */ - if (parser->raw_unread >= 2 - && !memcmp(parser->raw_pointer, BOM_UTF16LE, 2)) { - parser->encoding = YAML_UTF16LE_ENCODING; - parser->raw_pointer += 2; - parser->raw_unread -= 2; - } - else if (parser->raw_unread >= 2 - && !memcmp(parser->raw_pointer, BOM_UTF16BE, 2)) { - parser->encoding = YAML_UTF16BE_ENCODING; - parser->raw_pointer += 2; - parser->raw_unread -= 2; - } - else if (parser->raw_unread >= 3 - && !memcmp(parser->raw_pointer, BOM_UTF8, 3)) { - parser->encoding = YAML_UTF8_ENCODING; - parser->raw_pointer += 3; - parser->raw_unread -= 3; - } - else { - parser->encoding = YAML_UTF8_ENCODING; - } + /* On EOF, put NUL into the buffer and return. */ - return 1; -} - -/* - * Update the raw buffer. - */ - -int -yaml_parser_update_raw_buffer(yaml_parser_t *parser) -{ - size_t size_read = 0; - - /* Return if the raw buffer is full. */ - - if (parser->raw_unread == YAML_RAW_BUFFER_SIZE) return 1; - - /* Return on EOF. */ - - if (parser->eof) return 1; - - /* Move the remaining bytes in the raw buffer to the beginning. */ + if (parser->eof) { + *(parser->buffer.last++) = '\0'; + parser->unread ++; + return 1; + } - if (parser->raw_unread && parser->raw_buffer < parser->raw_pointer) { - memmove(parser->raw_buffer, parser->raw_pointer, parser->raw_unread); } - parser->raw_pointer = parser->raw_buffer; - - /* Call the read handler to fill the buffer. */ - if (!parser->read_handler(parser->read_handler_data, - parser->raw_buffer + parser->raw_unread, - YAML_RAW_BUFFER_SIZE - parser->raw_unread, - &size_read)) { - return yaml_parser_set_reader_error(parser, "Input error"); - } - parser->raw_unread += size_read; - if (!size_read) { - parser->eof = 1; - } + if (parser->offset >= PTRDIFF_MAX) + return yaml_parser_set_reader_error(parser, "input is too long", + PTRDIFF_MAX, -1); return 1; }