244 lines · 6.1 KB · C
RawDownload
/* * This file is part of LibParserUtils. * Licensed under the MIT License, *                http://www.opensource.org/licenses/mit-license.php * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org> */ /** \file * UTF-16 manipulation functions (implementation). */ #include <stdbool.h>#include <stdlib.h>#include <string.h> #include <parserutils/charset/utf16.h> /** * Convert a UTF-16 sequence into a single UCS-4 character * * \param s     The sequence to process * \param len   Length of sequence in bytes * \param ucs4  Pointer to location to receive UCS-4 character (host endian) * \param clen  Pointer to location to receive byte length of UTF-16 sequence * \return PARSERUTILS_OK on success, appropriate error otherwise */parserutils_error parserutils_charset_utf16_to_ucs4(const uint8_t *s, 		size_t len, uint32_t *ucs4, size_t *clen){	const uint16_t *ss = (const uint16_t *) (const void *) s; 	if (s == NULL || ucs4 == NULL || clen == NULL)		return PARSERUTILS_BADPARM; 	if (len < 2)		return PARSERUTILS_NEEDDATA; 	if (*ss < 0xD800 || *ss > 0xDFFF) {		*ucs4 = *ss;		*clen = 2;	} else if (0xD800 <= *ss && *ss <= 0xDBFF) {		/* High-surrogate code unit.  */		if (len < 4)			return PARSERUTILS_NEEDDATA; 		if (0xDC00 <= ss[1] && ss[1] <= 0xDFFF) {			/* We have a valid surrogate pair.  */			*ucs4 = (((ss[0] & 0x3FF) << 10) | (ss[1] & 0x3FF))				+ (1<<16);			*clen = 4;		} else {			return PARSERUTILS_INVALID;		}	} else {		/* Low-surrogate code unit.  */		return PARSERUTILS_INVALID;	} 	return PARSERUTILS_OK;} /** * Convert a single UCS-4 character into a UTF-16 sequence * * \param ucs4  The character to process (0 <= c <= 0x7FFFFFFF) (host endian) * \param s     Pointer to 4 byte long output buffer * \param len   Pointer to location to receive length of multibyte sequence * \return PARSERUTILS_OK on success, appropriate error otherwise */parserutils_error parserutils_charset_utf16_from_ucs4(uint32_t ucs4, uint8_t *s,		size_t *len){	uint16_t *ss = (uint16_t *) (void *) s;	uint32_t l = 0; 	if (s == NULL || len == NULL)		return PARSERUTILS_BADPARM;	else if (ucs4 < 0x10000) {		*ss = (uint16_t) ucs4;		l = 2;	} else if (ucs4 < 0x110000) {		ss[0] = 0xD800 | (((ucs4 >> 16) & 0x1f) - 1) | (ucs4 >> 10);		ss[1] = 0xDC00 | (ucs4 & 0x3ff);		l = 4;	} else {		return PARSERUTILS_INVALID;	} 	*len = l; 	return PARSERUTILS_OK;} /** * Calculate the length (in characters) of a bounded UTF-16 string * * \param s    The string * \param max  Maximum length * \param len  Pointer to location to receive length of string * \return PARSERUTILS_OK on success, appropriate error otherwise */parserutils_error parserutils_charset_utf16_length(const uint8_t *s, size_t max,		size_t *len){	const uint16_t *ss = (const uint16_t *) (const void *) s;	const uint16_t *end = (const uint16_t *) (const void *) (s + max);	int l = 0; 	if (s == NULL || len == NULL)		return PARSERUTILS_BADPARM; 	while (ss < end) {		if (*ss < 0xD800 || 0xDFFF < *ss)			ss++;		else			ss += 2; 		l++;	} 	*len = l; 	return PARSERUTILS_OK;} /** * Calculate the length (in bytes) of a UTF-16 character * * \param s    Pointer to start of character * \param len  Pointer to location to receive length * \return PARSERUTILS_OK on success, appropriate error otherwise */parserutils_error parserutils_charset_utf16_char_byte_length(const uint8_t *s,		size_t *len){	const uint16_t *ss = (const uint16_t *) (const void *) s; 	if (s == NULL || len == NULL)		return PARSERUTILS_BADPARM; 	if (*ss < 0xD800 || 0xDFFF < *ss)		*len = 2;	else		*len = 4; 	return PARSERUTILS_OK;} /** * Find previous legal UTF-16 char in string * * \param s        The string * \param off      Offset in the string to start at * \param prevoff  Pointer to location to receive offset of first byte of *                 previous legal character * \return PARSERUTILS_OK on success, appropriate error otherwise */parserutils_error parserutils_charset_utf16_prev(const uint8_t *s, uint32_t off,		uint32_t *prevoff){	const uint16_t *ss = (const uint16_t *) (const void *) s; 	if (s == NULL || prevoff == NULL)		return PARSERUTILS_BADPARM; 	if (off < 2)		*prevoff = 0;	else if (ss[-1] < 0xDC00 || ss[-1] > 0xDFFF)		*prevoff = off - 2;	else		*prevoff = (off < 4) ? 0 : off - 4; 	return PARSERUTILS_OK;} /** * Find next legal UTF-16 char in string * * \param s        The string (assumed valid) * \param len      Maximum offset in string * \param off      Offset in the string to start at * \param nextoff  Pointer to location to receive offset of first byte of *                 next legal character * \return PARSERUTILS_OK on success, appropriate error otherwise */parserutils_error parserutils_charset_utf16_next(const uint8_t *s, uint32_t len,		uint32_t off, uint32_t *nextoff){	const uint16_t *ss = (const uint16_t *) (const void *) s; 	if (s == NULL || off >= len || nextoff == NULL)		return PARSERUTILS_BADPARM; 	if (len - off < 4)		*nextoff = len;	else if (ss[1] < 0xD800 || ss[1] > 0xDBFF)		*nextoff = off + 2;	else		*nextoff = (len - off < 6) ? len : off + 4; 	return PARSERUTILS_OK;} /** * Find next legal UTF-16 char in string * * \param s        The string (assumed to be of dubious validity) * \param len      Maximum offset in string * \param off      Offset in the string to start at * \param nextoff  Pointer to location to receive offset of first byte of *                 next legal character * \return PARSERUTILS_OK on success, appropriate error otherwise */parserutils_error parserutils_charset_utf16_next_paranoid(const uint8_t *s,		uint32_t len, uint32_t off, uint32_t *nextoff){	const uint16_t *ss = (const uint16_t *) (const void *) s; 	if (s == NULL || off >= len || nextoff == NULL)		return PARSERUTILS_BADPARM; 	while (1) {		if (len - off < 4) {			return PARSERUTILS_NEEDDATA;		} else if (ss[1] < 0xD800 || ss[1] > 0xDFFF) {			*nextoff = off + 2;			break;		} else if (ss[1] >= 0xD800 && ss[1] <= 0xDBFF) {			if (len - off < 6)				return PARSERUTILS_NEEDDATA; 			if (ss[2] >= 0xDC00 && ss[2] <= 0xDFFF) {				*nextoff = off + 4;				break;			} else {				ss++;				off += 2;			}		}	} 	return PARSERUTILS_OK;} 

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t