char = $char; } /** * Convert to UTF-16 */ public function toUtf16(int $endianness) : string { switch ($endianness) { case System::BIG_ENDIAN: $format = 'n'; break; case System::LITTLE_ENDIAN: $format = 'v'; break; default: throw new InvalidArgumentException("Unknown endianness '$endianness'"); break; } $ucs_string = pack($format, self::convertCharToUtf16Int($this->char)); //error_log(sprintf("UCS %04x -> %02x,%02x",$char,ord($ucs_string[0]),ord($ucs_string[1]))); return $ucs_string; } /** * Convert a character to UTF-16 */ private static function convertCharToUtf16Int(string $char) : int { $c0 = ord($char[0]); // Easy case, code is 0xxxxxxx - just use it as is if ($c0 < 0x80) { return $c0; } $cn = ord($char[1]) ^ 0x80; $ucs = ($c0 << 6) | $cn; // Two byte codes: 110xxxxx 10xxxxxx if ($c0 < 0xE0) { $ucs &= ~0x3000; return $ucs; } $cn = ord($char[2]) ^ 0x80; $ucs = ($ucs << 6) | $cn; // Three byte codes: 1110xxxx 10xxxxxx 10xxxxxx if ($c0 < 0xF0) { $ucs &= ~0xE0000; return $ucs; } $cn = ord($char[3]) ^ 0x80; $ucs = ($ucs << 6) | $cn; // Four byte codes: 11110xxx 10xxxxxxx 10xxxxxx 10xxxxxx if ($c0 < 0xF8) { $ucs &= ~0x3C00000; return $ucs; } throw new RuntimeException("Shouldn't get here."); } }