diff options
| -rw-r--r-- | src/pugixml.cpp | 51 | 
1 files changed, 31 insertions, 20 deletions
| diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 4efb259..e42f64c 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -1034,6 +1034,30 @@ namespace  			return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;  	} +	xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) +	{ +		// look for BOM in first few bytes +		if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be; +		if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le; +		if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be; +		if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le; +		if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8; + +		// look for <, <? or <?xm in various encodings +		if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c) return encoding_utf32_be; +		if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0) return encoding_utf32_le; +		if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f) return encoding_utf16_be; +		if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0) return encoding_utf16_le; +		if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d) return encoding_utf8; + +		// look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early) +		if (d0 == 0 && d1 == 0x3c) return encoding_utf16_be; +		if (d0 == 0x3c && d1 == 0) return encoding_utf16_le; + +		// no known BOM detected, assume utf8 +		return encoding_utf8; +	} +  	xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size)  	{  		// replace wchar encoding with utf implementation @@ -1048,29 +1072,13 @@ namespace  		// only do autodetection if no explicit encoding is requested  		if (encoding != encoding_auto) return encoding; +		// skip encoding autodetection if input buffer is too small +		if (size < 4) return encoding_utf8; +  		// try to guess encoding (based on XML specification, Appendix F.1)  		const uint8_t* data = static_cast<const uint8_t*>(contents); -		// look for BOM in first few bytes -		if (size > 4 && data[0] == 0 && data[1] == 0 && data[2] == 0xfe && data[3] == 0xff) return encoding_utf32_be; -		if (size > 4 && data[0] == 0xff && data[1] == 0xfe && data[2] == 0 && data[3] == 0) return encoding_utf32_le; -		if (size > 2 && data[0] == 0xfe && data[1] == 0xff) return encoding_utf16_be; -		if (size > 2 && data[0] == 0xff && data[1] == 0xfe) return encoding_utf16_le; -		if (size > 3 && data[0] == 0xef && data[1] == 0xbb && data[2] == 0xbf) return encoding_utf8; - -		// look for <, <? or <?xm in various encodings -		if (size > 4 && data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 0x3c) return encoding_utf32_be; -		if (size > 4 && data[0] == 0x3c && data[1] == 0 && data[2] == 0 && data[3] == 0) return encoding_utf32_le; -		if (size > 4 && data[0] == 0 && data[1] == 0x3c && data[2] == 0 && data[3] == 0x3f) return encoding_utf16_be; -		if (size > 4 && data[0] == 0x3c && data[1] == 0 && data[2] == 0x3f && data[3] == 0) return encoding_utf16_le; -		if (size > 4 && data[0] == 0x3c && data[1] == 0x3f && data[2] == 0x78 && data[3] == 0x6d) return encoding_utf8; - -		// look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early) -		if (size > 2 && data[0] == 0 && data[1] == 0x3c) return encoding_utf16_be; -		if (size > 2 && data[0] == 0x3c && data[1] == 0) return encoding_utf16_le; - -		// no known BOM detected, assume utf8 -		return encoding_utf8; +		return guess_buffer_encoding(data[0], data[1], data[2], data[3]);  	}  	bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) @@ -4401,6 +4409,9 @@ namespace pugi  	{  		reset(); +		// check input buffer +		assert(contents || size == 0); +  		// get actual encoding  		xml_encoding buffer_encoding = get_buffer_encoding(encoding, contents, size); | 
