diff --git a/src/client.zig b/src/client.zig index eae8ba3..2b0860a 100644 --- a/src/client.zig +++ b/src/client.zig @@ -61,9 +61,9 @@ pub const Client = struct { try dumpDebug("ClientInit.bin", list); try s.stream.writer().writeAll(list.items); - std.debug.print("\n\nInitPacket: \n", .{}); + //std.debug.print("\n\nInitPacket: \n", .{}); - prettyPrintQVariant(.{ .QVariantMap = map }, 0); + //prettyPrintQVariant(.{ .QVariantMap = map }, 0); try s.read_quassel_packet(); } diff --git a/src/qtshit/test.zig b/src/qtshit/test.zig deleted file mode 100644 index 32ec287..0000000 --- a/src/qtshit/test.zig +++ /dev/null @@ -1,147 +0,0 @@ -const std = @import("std"); -const expect = std.testing.expect; -const global_allocator = std.testing.allocator; - -const read = @import("./read.zig"); -const write = @import("./write.zig"); -const QVariant = @import("./types/QVariant.zig").QVariant; -const freeQVariant = @import("./utils/freeQVariant.zig").freeQVariant; - -test "UInt serialization/deserialization" { - var byteList = std.ArrayList(u8).init(global_allocator); - defer byteList.deinit(); - - try write.writeUInt(byteList.writer(), 4242); - - var fBS = std.io.fixedBufferStream(byteList.items); - var val = try read.readUInt(fBS.reader()); - - try expect(val == 4242); -} - -test "Short serialization/deserialization" { - var byteList = std.ArrayList(u8).init(global_allocator); - defer byteList.deinit(); - - try write.writeShort(byteList.writer(), 6969); - - var fBS = std.io.fixedBufferStream(byteList.items); - var val = try read.readShort(fBS.reader()); - - try expect(val == 6969); -} - -test "Byte serialization/deserialization" { - var byteList = std.ArrayList(u8).init(global_allocator); - defer byteList.deinit(); - - try write.writeByte(byteList.writer(), 'a'); - - var fBS = std.io.fixedBufferStream(byteList.items); - var val = try read.readByte(fBS.reader()); - - try expect(val == 'a'); -} - -test "String serialization/deserialization" { - var byteList = std.ArrayList(u8).init(global_allocator); - defer byteList.deinit(); - - var arr = "Hello World!".*; - - try write.writeString(byteList.writer(), global_allocator, &arr); - - var fBS = std.io.fixedBufferStream(byteList.items); - var val = try read.readString(fBS.reader(), global_allocator); - defer global_allocator.free(val); - - try std.testing.expectEqualStrings("Hello World!", val); -} - -test "QByteArray serialization/deserialization" { - var byteList = std.ArrayList(u8).init(global_allocator); - defer byteList.deinit(); - - var arr = std.ArrayList(u8).init(global_allocator); - defer arr.deinit(); - try arr.append(13); - try arr.append(12); - - try write.writeQByteArray(byteList.writer(), arr.items); - - var fBS = std.io.fixedBufferStream(byteList.items); - var val = try read.readQByteArray(fBS.reader(), global_allocator); - defer global_allocator.free(val); - - try expect(arr.items.len == val.len); - for (arr.items) |item, index| { - try std.testing.expect(item == val[index]); - } -} - -test "QStringList serialization/deserialization" { - var byteList = std.ArrayList(u8).init(global_allocator); - defer byteList.deinit(); - - var arr = std.ArrayList([]const u8).init(global_allocator); - defer arr.deinit(); - try arr.append("Hewwo"); - try arr.append("World"); - - try write.writeQStringList(byteList.writer(), global_allocator, arr.items); - - var fBS = std.io.fixedBufferStream(byteList.items); - var val = try read.readQStringList(fBS.reader(), global_allocator); - defer { - for (val) |str| { - global_allocator.free(str); - } - global_allocator.free(val); - } - - try expect(arr.items.len == val.len); - for (arr.items) |str, index| { - try std.testing.expectEqualStrings(str, val[index]); - } -} - -test "QVariant UInt serialization/deserialization" { - var byteList = std.ArrayList(u8).init(global_allocator); - defer byteList.deinit(); - - // ACAB - try write.writeQVariant(byteList.writer(), global_allocator, .{ .UInt = 1312 }); - - var fBS = std.io.fixedBufferStream(byteList.items); - - var variant = try read.readQVariant(fBS.reader(), global_allocator); - - try expect(variant.UInt == 1312); -} - -test "QVariant QVariantMap serialization/deserialization" { - var byteList = std.ArrayList(u8).init(global_allocator); - defer byteList.deinit(); - - var map = std.StringHashMap(QVariant).init(global_allocator); - defer map.deinit(); - try map.put("testkey", .{ .UInt = 1337 }); - - try write.writeQVariant(byteList.writer(), global_allocator, .{ - .QVariantMap = map, - }); - - var fBS = std.io.fixedBufferStream(byteList.items); - - var varient = try read.readQVariant(fBS.reader(), global_allocator); - defer freeQVariant(varient, global_allocator); - - var qVariantMap = varient.QVariantMap; - - var testKey = qVariantMap.get("testkey"); - if (testKey) |key| { - try expect(key.UInt == 1337); - } else { - try expect(!true); - } -} diff --git a/src/qtshit/utils/unicode.zig b/src/qtshit/utils/unicode.zig new file mode 100644 index 0000000..acd11d1 --- /dev/null +++ b/src/qtshit/utils/unicode.zig @@ -0,0 +1,43 @@ +const std = @import("std"); +const testing = std.testing; + +// Operates on the pointer you give it, doing the byte swaps in place. +// Returns deref'd pointer for convinience. +pub fn byteSwapArray(comptime T: type, ptr: *[]T) []T { + for (ptr.*) |byte, index| { + ptr.*[index] = @byteSwap(T, byte); + } + return ptr.*; +} + +pub fn utf8ToUtf16BE(allocator: *std.mem.Allocator, utf8: []const u8) ![]u16 { + var utf16LE = try std.unicode.utf8ToUtf16LeWithNull(allocator, utf8); + // Little Endian to Big Endian + var utf16BE = byteSwapArray(u16, &utf16LE); + return utf16BE; +} + +pub fn utf16BEToUtf8(allocator: *std.mem.Allocator, utf16: []u16) ![]u8 { + // Copy the strong so can do byte swap in place on it. + var utf16BE = try allocator.alloc(u16, utf16.len); + defer allocator.free(utf16BE); + std.mem.copy(u16, utf16BE, utf16); + + // Big Endian to Little Endian + var utf16LE = byteSwapArray(u16, &utf16BE); + + var utf8 = try std.unicode.utf16leToUtf8AllocZ(allocator, utf16LE); + return utf8; +} + +test "utf8 and utf16BE conversion" { + var utf8 = "1312"; + + var utf16BE = try utf8ToUtf16BE(testing.allocator, utf8); + defer testing.allocator.free(utf16BE); + + var utf8Decoded = try utf16BEToUtf8(testing.allocator, utf16BE); + defer testing.allocator.free(utf8Decoded); + + try testing.expectEqualStrings(utf8, utf8Decoded); +} \ No newline at end of file diff --git a/src/qtshit/write/writeFrame.zig b/src/qtshit/write/writeFrame.zig index be81a5e..64eda3e 100644 --- a/src/qtshit/write/writeFrame.zig +++ b/src/qtshit/write/writeFrame.zig @@ -4,7 +4,7 @@ const QVariantType = @import("../types/QVariant.zig").QVariant; const writeUInt = @import("./writeUInt.zig").writeUInt; const writeQVariant = @import("./writeQVariant.zig").writeQVariant; -pub fn writeFrame(writer: anytype, allocator: *std.mem.Allocator, map: std.StringHashMap(QVariantType)) (@TypeOf(writer).Error || std.os.WriteError || error{OutOfMemory})!void { +pub fn writeFrame(writer: anytype, allocator: *std.mem.Allocator, map: std.StringHashMap(QVariantType)) !void { var data = std.ArrayList(u8).init(allocator); try writeQVariant(data.writer(), allocator, .{ .QVariantMap = map, diff --git a/src/qtshit/write/writeQVariant.zig b/src/qtshit/write/writeQVariant.zig index bca505f..1e0f62c 100644 --- a/src/qtshit/write/writeQVariant.zig +++ b/src/qtshit/write/writeQVariant.zig @@ -14,7 +14,7 @@ const writeQVariantHeader = @import("./writeQVariantHeader.zig").writeQVariantHe const writeQVariantMap = @import("./writeQVariantMap.zig").writeQVariantMap; const writeQStringList = @import("./writeQStringList.zig").writeQStringList; -pub fn writeQVariant(writer: anytype, allocator: *std.mem.Allocator, variant: QVariantType) !void { +pub fn writeQVariant(writer: anytype, allocator: *std.mem.Allocator, variant: QVariantType) (@TypeOf(writer).Error || std.os.WriteError || error{OutOfMemory} || error{InvalidUtf8})!void { try writeQVariantHeader(writer, try QVariantTypeID(variant)); switch (variant) { .Byte => |out| { diff --git a/src/qtshit/write/writeQVariantList.zig b/src/qtshit/write/writeQVariantList.zig index 4bddfc1..5258d5c 100644 --- a/src/qtshit/write/writeQVariantList.zig +++ b/src/qtshit/write/writeQVariantList.zig @@ -3,8 +3,7 @@ const QVariantType = @import("../types/QVariant.zig").QVariant; const writeUInt = @import("./writeUInt.zig").writeUInt; const writeQVariant = @import("./writeQVariant.zig").writeQVariant; -const AllKnownErrors = (std.os.WriteError || error{OutOfMemory}); -pub fn writeQVariantList(writer: anytype, allocator: *std.mem.Allocator, varList: []QVariantType) AllKnownErrors!void { +pub fn writeQVariantList(writer: anytype, allocator: *std.mem.Allocator, varList: []QVariantType) !void { try writeUInt(writer, @intCast(u32, varList.len)); for (varList) |v| { try writeQVariant(writer, allocator, v); diff --git a/src/qtshit/write/writeQVariantMap.zig b/src/qtshit/write/writeQVariantMap.zig index 7ac1f4f..e778d65 100644 --- a/src/qtshit/write/writeQVariantMap.zig +++ b/src/qtshit/write/writeQVariantMap.zig @@ -5,7 +5,7 @@ const writeUInt = @import("./writeUInt.zig").writeUInt; const writeQVariant = @import("./writeQVariant.zig").writeQVariant; -pub fn writeQVariantMap(writer: anytype, allocator: *std.mem.Allocator, map: std.StringHashMap(QVariantType)) (@TypeOf(writer).Error || std.os.WriteError || error{OutOfMemory})!void { +pub fn writeQVariantMap(writer: anytype, allocator: *std.mem.Allocator, map: std.StringHashMap(QVariantType)) !void { var data = std.ArrayList(u8).init(allocator); defer data.deinit(); diff --git a/src/qtshit/write/writeString.zig b/src/qtshit/write/writeString.zig index e47d34b..8a0fe68 100644 --- a/src/qtshit/write/writeString.zig +++ b/src/qtshit/write/writeString.zig @@ -1,13 +1,11 @@ const std = @import("std"); const writeInt = @import("./writeInt.zig").writeInt; +const unicode = @import("../utils/unicode.zig"); -pub fn writeString(writer: anytype, allocator: *std.mem.Allocator, str: []const u8) !void { - var ut16Str = try allocator.alloc(u16, str.len); - defer allocator.free(ut16Str); - for (str) |character, index| { - ut16Str[index] = std.mem.nativeToBig(u16, @as(u16, character)); - } - try writeInt(writer, @intCast(i32, ut16Str.len * 2)); - try writer.writeAll(std.mem.sliceAsBytes(ut16Str)); +pub fn writeString(writer: anytype, allocator: *std.mem.Allocator, str: []const u8) (error{InvalidUtf8} || error{OutOfMemory})!void { + var str_utf16BE = try unicode.utf8ToUtf16BE(allocator, str); + defer allocator.free(str_utf16BE); + try writeInt(writer, @intCast(i32, str_utf16BE.len)); + try writer.writeAll(std.mem.sliceAsBytes(str_utf16BE)); } \ No newline at end of file