| /* | |
| * Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>. | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU General Public License as | |
| * published by the Free Software Foundation; either version 2 of the | |
| * License, or any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, but | |
| * WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU General Public License | |
| * along with this program; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| * 02110-1301, USA. | |
| * | |
| * You can also choose to distribute this program under the terms of | |
| * the Unmodified Binary Distribution Licence (as given in the file | |
| * COPYING.UBDL), provided that you have satisfied its requirements. | |
| */ | |
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); | |
| FILE_SECBOOT ( PERMITTED ); | |
| #include <stdint.h> | |
| #include <assert.h> | |
| #include <ipxe/utf8.h> | |
| /** @file | |
| * | |
| * UTF-8 Unicode encoding | |
| * | |
| */ | |
| /** | |
| * Accumulate Unicode character from UTF-8 byte sequence | |
| * | |
| * @v utf8 UTF-8 accumulator | |
| * @v byte UTF-8 byte | |
| * @ret character Unicode character, or 0 if incomplete | |
| */ | |
| unsigned int utf8_accumulate ( struct utf8_accumulator *utf8, uint8_t byte ) { | |
| static unsigned int min[] = { | |
| UTF8_MIN_TWO, | |
| UTF8_MIN_THREE, | |
| UTF8_MIN_FOUR, | |
| }; | |
| unsigned int shift; | |
| unsigned int len; | |
| uint8_t tmp; | |
| /* Handle continuation bytes */ | |
| if ( UTF8_IS_CONTINUATION ( byte ) ) { | |
| /* Fail if this is an unexpected continuation byte */ | |
| if ( utf8->remaining == 0 ) { | |
| DBGC ( utf8, "UTF8 %p unexpected %02x\n", utf8, byte ); | |
| return UTF8_INVALID; | |
| } | |
| /* Apply continuation byte */ | |
| utf8->character <<= UTF8_CONTINUATION_BITS; | |
| utf8->character |= ( byte & UTF8_CONTINUATION_MASK ); | |
| /* Return 0 if more continuation bytes are expected */ | |
| if ( --utf8->remaining != 0 ) | |
| return 0; | |
| /* Fail if sequence is illegal */ | |
| if ( utf8->character < utf8->min ) { | |
| DBGC ( utf8, "UTF8 %p illegal %02x\n", utf8, | |
| utf8->character ); | |
| return UTF8_INVALID; | |
| } | |
| /* Sanity check */ | |
| assert ( utf8->character != 0 ); | |
| /* Return completed character */ | |
| DBGC2 ( utf8, "UTF8 %p accumulated %02x\n", | |
| utf8, utf8->character ); | |
| return utf8->character; | |
| } | |
| /* Reset state and report failure if this is an unexpected | |
| * non-continuation byte. Do not return UTF8_INVALID since | |
| * doing so could cause us to drop a valid ASCII character. | |
| */ | |
| if ( utf8->remaining != 0 ) { | |
| shift = ( utf8->remaining * UTF8_CONTINUATION_BITS ); | |
| DBGC ( utf8, "UTF8 %p unexpected %02x (partial %02x/%02x)\n", | |
| utf8, byte, ( utf8->character << shift ), | |
| ( ( 1 << shift ) - 1 ) ); | |
| utf8->remaining = 0; | |
| } | |
| /* Handle initial bytes */ | |
| if ( ! UTF8_IS_ASCII ( byte ) ) { | |
| /* Sanity check */ | |
| assert ( utf8->remaining == 0 ); | |
| /* Count total number of bytes in sequence */ | |
| tmp = byte; | |
| len = 0; | |
| while ( tmp & UTF8_HIGH_BIT ) { | |
| tmp <<= 1; | |
| len++; | |
| } | |
| /* Check for illegal length */ | |
| if ( len > UTF8_MAX_LEN ) { | |
| DBGC ( utf8, "UTF8 %p illegal %02x length %d\n", | |
| utf8, byte, len ); | |
| return UTF8_INVALID; | |
| } | |
| /* Store initial bits of character */ | |
| utf8->character = ( tmp >> len ); | |
| /* Store number of bytes remaining */ | |
| len--; | |
| utf8->remaining = len; | |
| assert ( utf8->remaining > 0 ); | |
| /* Store minimum legal value */ | |
| utf8->min = min[ len - 1 ]; | |
| assert ( utf8->min > 0 ); | |
| /* Await continuation bytes */ | |
| return 0; | |
| } | |
| /* Handle ASCII bytes */ | |
| return byte; | |
| } |