| ... | @@ -317,9 +317,9 @@ pub const Utf16LeIterator = struct { | ... | @@ -317,9 +317,9 @@ pub const Utf16LeIterator = struct { |
| 317 | assert(it.i <= it.bytes.len); | 317 | assert(it.i <= it.bytes.len); |
| 318 | if (it.i == it.bytes.len) return null; | 318 | if (it.i == it.bytes.len) return null; |
| 319 | const c0: u21 = mem.readIntLittle(u16, it.bytes[it.i..][0..2]); | 319 | const c0: u21 = mem.readIntLittle(u16, it.bytes[it.i..][0..2]); |
| | 320 | it.i += 2; |
| 320 | if (c0 & ~@as(u21, 0x03ff) == 0xd800) { | 321 | if (c0 & ~@as(u21, 0x03ff) == 0xd800) { |
| 321 | // surrogate pair | 322 | // surrogate pair |
| 322 | it.i += 2; | | |
| 323 | if (it.i >= it.bytes.len) return error.DanglingSurrogateHalf; | 323 | if (it.i >= it.bytes.len) return error.DanglingSurrogateHalf; |
| 324 | const c1: u21 = mem.readIntLittle(u16, it.bytes[it.i..][0..2]); | 324 | const c1: u21 = mem.readIntLittle(u16, it.bytes[it.i..][0..2]); |
| 325 | if (c1 & ~@as(u21, 0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf; | 325 | if (c1 & ~@as(u21, 0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf; |
| ... | @@ -328,7 +328,6 @@ pub const Utf16LeIterator = struct { | ... | @@ -328,7 +328,6 @@ pub const Utf16LeIterator = struct { |
| 328 | } else if (c0 & ~@as(u21, 0x03ff) == 0xdc00) { | 328 | } else if (c0 & ~@as(u21, 0x03ff) == 0xdc00) { |
| 329 | return error.UnexpectedSecondSurrogateHalf; | 329 | return error.UnexpectedSecondSurrogateHalf; |
| 330 | } else { | 330 | } else { |
| 331 | it.i += 2; | | |
| 332 | return c0; | 331 | return c0; |
| 333 | } | 332 | } |
| 334 | } | 333 | } |
| ... | @@ -769,6 +768,48 @@ fn calcUtf16LeLen(utf8: []const u8) usize { | ... | @@ -769,6 +768,48 @@ fn calcUtf16LeLen(utf8: []const u8) usize { |
| 769 | return dest_len; | 768 | return dest_len; |
| 770 | } | 769 | } |
| 771 | | 770 | |
| | 771 | /// Print the given `utf16le` string |
| | 772 | fn formatUtf16le( |
| | 773 | utf16le: []const u16, |
| | 774 | comptime fmt: []const u8, |
| | 775 | options: std.fmt.FormatOptions, |
| | 776 | writer: anytype, |
| | 777 | ) !void { |
| | 778 | const unknown_codepoint = 0xfffd; |
| | 779 | _ = fmt; |
| | 780 | _ = options; |
| | 781 | var buf: [300]u8 = undefined; // just a random size I chose |
| | 782 | var it = Utf16LeIterator.init(utf16le); |
| | 783 | var u8len: usize = 0; |
| | 784 | while (it.nextCodepoint() catch unknown_codepoint) |codepoint| { |
| | 785 | u8len += utf8Encode(codepoint, buf[u8len..]) catch |
| | 786 | utf8Encode(unknown_codepoint, buf[u8len..]) catch unreachable; |
| | 787 | if (u8len + 3 >= buf.len) { |
| | 788 | try writer.writeAll(buf[0..u8len]); |
| | 789 | u8len = 0; |
| | 790 | } |
| | 791 | } |
| | 792 | try writer.writeAll(buf[0..u8len]); |
| | 793 | } |
| | 794 | |
| | 795 | /// Return a Formatter for a Utf16le string |
| | 796 | pub fn fmtUtf16le(utf16le: []const u16) std.fmt.Formatter(formatUtf16le) { |
| | 797 | return .{ .data = utf16le }; |
| | 798 | } |
| | 799 | |
| | 800 | test "fmtUtf16le" { |
| | 801 | const expectFmt = std.testing.expectFmt; |
| | 802 | try expectFmt("", "{}", .{fmtUtf16le(utf8ToUtf16LeStringLiteral(""))}); |
| | 803 | try expectFmt("foo", "{}", .{fmtUtf16le(utf8ToUtf16LeStringLiteral("foo"))}); |
| | 804 | try expectFmt("𐐷", "{}", .{fmtUtf16le(utf8ToUtf16LeStringLiteral("𐐷"))}); |
| | 805 | try expectFmt("", "{}", .{fmtUtf16le(&[_]u16{std.mem.readIntNative(u16, "\xff\xd7")})}); |
| | 806 | try expectFmt("�", "{}", .{fmtUtf16le(&[_]u16{std.mem.readIntNative(u16, "\x00\xd8")})}); |
| | 807 | try expectFmt("�", "{}", .{fmtUtf16le(&[_]u16{std.mem.readIntNative(u16, "\xff\xdb")})}); |
| | 808 | try expectFmt("�", "{}", .{fmtUtf16le(&[_]u16{std.mem.readIntNative(u16, "\x00\xdc")})}); |
| | 809 | try expectFmt("�", "{}", .{fmtUtf16le(&[_]u16{std.mem.readIntNative(u16, "\xff\xdf")})}); |
| | 810 | try expectFmt("", "{}", .{fmtUtf16le(&[_]u16{std.mem.readIntNative(u16, "\x00\xe0")})}); |
| | 811 | } |
| | 812 | |
| 772 | test "utf8ToUtf16LeStringLiteral" { | 813 | test "utf8ToUtf16LeStringLiteral" { |
| 773 | { | 814 | { |
| 774 | const bytes = [_:0]u16{ | 815 | const bytes = [_:0]u16{ |