diff --git a/src/client.zig b/src/client.zig index 102e36b..f228702 100644 --- a/src/client.zig +++ b/src/client.zig @@ -22,11 +22,11 @@ pub const Client = struct { pub fn handshake(s: *Client) !void { const magic = 0x42b33f00; - try write.add_int(s.stream.writer(), magic); - try write.add_int(s.stream.writer(), 0x80000002); - var flags = try read.get_byte(s.stream.reader()); - var extra = try read.get_short(s.stream.reader()); - var version = try read.get_signed_byte(s.stream.reader()); + try write.writeUInt(s.stream.writer(), magic); + try write.writeUInt(s.stream.writer(), 0x80000002); + var flags = try read.readByte(s.stream.reader()); + var extra = try read.readShort(s.stream.reader()); + var version = try read.readSignedByte(s.stream.reader()); std.debug.print("Handshake: flags={d} extra={d} version={d} \n", .{ flags, extra, version }); } @@ -35,31 +35,26 @@ pub const Client = struct { var map = std.StringHashMap(qvar.QVariant).init(s.allocator); - try map.put("MsgType", .{ .string = "ClientInit" }); - try map.put("ProtocolVersion", .{ .int = 10 }); - try map.put("ClientVersion", .{ .string = "0.1 (quasselclient)" }); - try map.put("ClientDate", .{ .string = "Wed, 02 Jun 2021 17:30:30 +0100" }); - try map.put("Features", .{ .int = 0 }); + try map.put("MsgType", .{ .String = "ClientInit" }); + try map.put("ProtocolVersion", .{ .UInt = 10 }); + try map.put("ClientVersion", .{ .String = "0.1 (quasselclient)" }); + try map.put("ClientDate", .{ .String = "Wed, 02 Jun 2021 17:30:30 +0100" }); + try map.put("Features", .{ .Int = 0 }); var empty = std.ArrayList([]const u8).init(s.allocator); - try map.put("FeatureList", .{ .stringlist = empty }); + try map.put("FeatureList", .{ .QStringList = empty }); - try write.add_message(list.writer(), s.allocator, map); + try write.writeFrame(list.writer(), s.allocator, map); try dumpDebug("ClientInit.bin", list); try s.stream.writer().writeAll(list.items); std.debug.print("\n\nInitPacket: \n", .{}); - qvar.pretty_print_variant(.{.qmap = map}, 0); - - - - var size = read.get_int(s.stream.reader()); - //std.debug.print("InitResp: size={d} \n", .{size}); + qvar.pretty_print_variant(.{.QVariantMap = map}, 0); + var size = read.readUInt(s.stream.reader()); std.debug.print("\n\nInitResponse: \n", .{}); - var varient = try read.get_variant(s.stream.reader(), s.allocator); + var varient = try read.readQVariant(s.stream.reader(), s.allocator); qvar.pretty_print_variant(varient, 0); - //std.debug.print("InitResp: type={s} \n", .{varient.qmap.get("MsgType").?.string}); } pub fn quassel_login(s: *Client, username: []const u8, password: []const u8) !void { @@ -67,11 +62,11 @@ pub const Client = struct { var map = std.StringHashMap(qvar.QVariant).init(s.allocator); - try map.put("MsgType", .{ .string = "ClientLogin" }); - try map.put("User", .{ .string = username }); - try map.put("Password", .{ .string = password }); + try map.put("MsgType", .{ .String = "ClientLogin" }); + try map.put("User", .{ .String = username }); + try map.put("Password", .{ .String = password }); - try write.add_message(list.writer(), s.allocator, map); + try write.writeFrame(list.writer(), s.allocator, map); try dumpDebug("ClientLogin.bin", list); try s.stream.writer().writeAll(list.items); diff --git a/src/qtshit/qvariant.zig b/src/qtshit/qvariant.zig index 019e78f..5833344 100644 --- a/src/qtshit/qvariant.zig +++ b/src/qtshit/qvariant.zig @@ -2,58 +2,57 @@ const std = @import("std"); const range = @import("./rangeiter.zig").range; pub const QVariant = union(enum) { - int: u32, - short: u16, - byte: u8, - bytearray: std.ArrayList(u8), - string: []const u8, - stringlist: std.ArrayList([]const u8), - qmap: std.StringHashMap(QVariant), - qvarlist: std.ArrayList(QVariant), - empty: bool, + Int: i32, + UInt: u32, + Short: u16, + Byte: u8, + String: []const u8, + QByteArray: std.ArrayList(u8), + QStringList: std.ArrayList([]const u8), + QVariantMap: std.StringHashMap(QVariant), + QVariantList: std.ArrayList(QVariant), }; pub const QVariantTypes = enum(u32) { - byte = 1, - // IDK why there is 2??? - int_1 = 2, - int_2 = 3, - qmap = 8, - qvarlist = 9, - string = 10, - stringlist = 11, - bytearray = 12, - short = 133, + Byte = 1, + Int = 2, + UInt = 3, + QVariantMap = 8, + QVariantList = 9, + String = 10, + QStringList = 11, + QByteArray = 12, + Short = 133, }; pub fn qvariant_type_id(variant: QVariant) !u32 { switch (variant) { - .byte => { - return @enumToInt(QVariantTypes.byte); + .Byte => { + return @enumToInt(QVariantTypes.Byte); }, - .int => { - return @enumToInt(QVariantTypes.int_2); + .Int => { + return @enumToInt(QVariantTypes.Int); }, - .qmap => { - return @enumToInt(QVariantTypes.qmap); + .UInt => { + return @enumToInt(QVariantTypes.UInt); }, - .qvarlist => { - return @enumToInt(QVariantTypes.qvarlist); + .QVariantMap => { + return @enumToInt(QVariantTypes.QVariantMap); }, - .string => { - return @enumToInt(QVariantTypes.string); + .QVariantList => { + return @enumToInt(QVariantTypes.QVariantList); }, - .stringlist => { - return @enumToInt(QVariantTypes.stringlist); + .String => { + return @enumToInt(QVariantTypes.String); }, - .bytearray => { - return @enumToInt(QVariantTypes.bytearray); + .QStringList => { + return @enumToInt(QVariantTypes.QStringList); }, - .short => { - return @enumToInt(QVariantTypes.short); + .QByteArray => { + return @enumToInt(QVariantTypes.QByteArray); }, - else => { - return 0; + .Short => { + return @enumToInt(QVariantTypes.Short); }, } } @@ -69,14 +68,17 @@ pub fn pretty_print_variant(variant: QVariant, indentLevel: u64) void { print_indent_level(indentLevel); switch (variant) { - .byte => |b| { + .Byte => |b| { std.debug.print("Byte: {d}\n", .{b}); }, - .int => |i| { + .Int => |i| { std.debug.print("Int: {d}\n", .{i}); }, - .qmap => |q| { - std.debug.print("QMap:\n", .{}); + .UInt => |i| { + std.debug.print("UInt: {d}\n", .{i}); + }, + .QVariantMap => |q| { + std.debug.print("QVariantMap:\n", .{}); var qMapIter = q.iterator(); while (qMapIter.next()) |v| { print_indent_level(indentLevel + 1); @@ -86,8 +88,8 @@ pub fn pretty_print_variant(variant: QVariant, indentLevel: u64) void { pretty_print_variant(v.value, indentLevel + 2); } }, - .qvarlist => |l| { - std.debug.print("QVarList:\n", .{}); + .QVariantList => |l| { + std.debug.print("QVariantList:\n", .{}); for (l.items) |varient, i| { print_indent_level(indentLevel + 1); @@ -95,14 +97,20 @@ pub fn pretty_print_variant(variant: QVariant, indentLevel: u64) void { pretty_print_variant(varient, indentLevel + 2); } }, - .string => |s| { + .String => |s| { std.debug.print("String: \"{s}\"\n", .{s}); }, - .stringlist => {}, - .bytearray => {}, - .short => |s| { + .QStringList => |l| { + std.debug.print("QStringList:\n", .{}); + + for (l.items) |str, i| { + print_indent_level(indentLevel + 1); + std.debug.print("\"{s}\" \n", .{str}); + } + }, + .QByteArray => {}, + .Short => |s| { std.debug.print("Short: \"{d}\"\n", .{s}); }, - else => {}, } } diff --git a/src/qtshit/read.zig b/src/qtshit/read.zig index a8aa4df..d235da4 100644 --- a/src/qtshit/read.zig +++ b/src/qtshit/read.zig @@ -2,48 +2,52 @@ const std = @import("std"); const qvar = @import("./qvariant.zig"); const range = @import("./rangeiter.zig").range; -pub fn get_int(reader: anytype) !u32 { +pub fn readInt(reader: anytype) !i32 { + return try reader.readIntBig(i32); +} + +pub fn readUInt(reader: anytype) !u32 { return try reader.readIntBig(u32); } -pub fn get_short(reader: anytype) !u16 { +pub fn readShort(reader: anytype) !u16 { return try reader.readIntBig(u16); } -pub fn get_byte(reader: anytype) !u8 { +pub fn readByte(reader: anytype) !u8 { return try reader.readByte(); } -pub fn get_signed_byte(reader: anytype) !i8 { +pub fn readSignedByte(reader: anytype) !i8 { return try reader.readIntBig(i8); } -pub fn get_bytearray(reader: anytype, allocator: *std.mem.Allocator) !std.ArrayList(u8) { +pub fn readQByteArray(reader: anytype, allocator: *std.mem.Allocator) !std.ArrayList(u8) { var byteList = std.ArrayList(u8).init(allocator); - var length = try get_int(reader); + var length = try readUInt(reader); var index: usize = 0; while (true) { if (index == length) return byteList; - const byte = try reader.readByte(); + const byte = try readByte(reader); try byteList.append(byte); index += 1; } } -pub fn get_string(reader: anytype, allocator: *std.mem.Allocator) ![]u8 { +pub fn readString(reader: anytype, allocator: *std.mem.Allocator) ![]u8 { var data = std.ArrayList(u8).init(allocator); defer data.deinit(); - var length = try reader.readIntBig(i32); + var length = try readInt(reader); var chars = @divTrunc(length, 2); var index: usize = 0; while (true) { if (index == chars) break; - const byte = try reader.readIntBig(u16); + const byte = try readShort(reader); try data.append(@truncate(u8, byte)); index += 1; } @@ -56,84 +60,87 @@ pub fn get_string(reader: anytype, allocator: *std.mem.Allocator) ![]u8 { return ut8Str; } -pub fn get_qvarlist(reader: anytype, allocator: *std.mem.Allocator) !std.ArrayList(qvar.QVariant) { +pub fn readQVariantList(reader: anytype, allocator: *std.mem.Allocator) !std.ArrayList(qvar.QVariant) { var varlist = std.ArrayList(qvar.QVariant).init(allocator); - var size = try get_int(reader); + var size = try readUInt(reader); var i: u32 = 0; while (i < size) { - try varlist.append(try get_variant(reader, allocator)); + try varlist.append(try readQVariant(reader, allocator)); i = i + 1; } return varlist; } -pub fn get_stringlist(reader: anytype, allocator: *std.mem.Allocator) !std.ArrayList([]const u8) { +pub fn readQStringList(reader: anytype, allocator: *std.mem.Allocator) !std.ArrayList([]const u8) { var strList = std.ArrayList([]const u8).init(allocator); - var size = try get_int(reader); + var size = try readUInt(reader); var i: u32 = 0; while (i < size) { - try strList.append(try get_string(reader, allocator)); + try strList.append(try readString(reader, allocator)); i = i + 1; } return strList; } -pub fn get_variant_t(reader: anytype, type_id: u32, allocator: *std.mem.Allocator) (@TypeOf(reader).Error || error{EndOfStream} || error{OutOfMemory})!qvar.QVariant { +pub fn readQVariantT(reader: anytype, type_id: u32, allocator: *std.mem.Allocator) (@TypeOf(reader).Error || error{EndOfStream} || error{OutOfMemory})!qvar.QVariant { switch (type_id) { - @enumToInt(qvar.QVariantTypes.byte) => { - var byte = try get_byte(reader); - return qvar.QVariant{ .byte = byte }; + @enumToInt(qvar.QVariantTypes.Byte) => { + var byte = try readByte(reader); + return qvar.QVariant{ .Byte = byte }; }, - @enumToInt(qvar.QVariantTypes.int_1), @enumToInt(qvar.QVariantTypes.int_2) => { - var int = try get_int(reader); - return qvar.QVariant{ .int = int }; + @enumToInt(qvar.QVariantTypes.Int) => { + var int = try readInt(reader); + return qvar.QVariant{ .Int = int }; }, - @enumToInt(qvar.QVariantTypes.qmap) => { - var map = try get_qvariantmap(reader, allocator); - return qvar.QVariant{ .qmap = map }; + @enumToInt(qvar.QVariantTypes.UInt) => { + var uint = try readUInt(reader); + return qvar.QVariant{ .UInt = uint }; }, - @enumToInt(qvar.QVariantTypes.qvarlist) => { - var list = try get_qvarlist(reader, allocator); - return qvar.QVariant{ .qvarlist = list }; + @enumToInt(qvar.QVariantTypes.QVariantMap) => { + var map = try readQVariantMap(reader, allocator); + return qvar.QVariant{ .QVariantMap = map }; }, - @enumToInt(qvar.QVariantTypes.string) => { - var str = try get_string(reader, allocator); - return qvar.QVariant{ .string = str }; + @enumToInt(qvar.QVariantTypes.QVariantList) => { + var list = try readQVariantList(reader, allocator); + return qvar.QVariant{ .QVariantList = list }; }, - @enumToInt(qvar.QVariantTypes.stringlist) => { - var strlist = try get_stringlist(reader, allocator); - return qvar.QVariant{ .stringlist = strlist }; + @enumToInt(qvar.QVariantTypes.String) => { + var str = try readString(reader, allocator); + return qvar.QVariant{ .String = str }; }, - @enumToInt(qvar.QVariantTypes.bytearray) => { - var bArray = try get_bytearray(reader, allocator); - return qvar.QVariant{ .bytearray = bArray }; + @enumToInt(qvar.QVariantTypes.QStringList) => { + var strlist = try readQStringList(reader, allocator); + return qvar.QVariant{ .QStringList = strlist }; }, - @enumToInt(qvar.QVariantTypes.short) => { - var short = try get_short(reader); - return qvar.QVariant{ .short = short }; + @enumToInt(qvar.QVariantTypes.QByteArray) => { + var bArray = try readQByteArray(reader, allocator); + return qvar.QVariant{ .QByteArray = bArray }; + }, + @enumToInt(qvar.QVariantTypes.Short) => { + var short = try readShort(reader); + return qvar.QVariant{ .Short = short }; }, else => { - @panic("Unsupported!"); - - }, + @panic("Unknown Type"); + } } return qvar.QVariant{ .empty = true }; } -pub fn get_variant(reader: anytype, allocator: *std.mem.Allocator) !qvar.QVariant { - var type_id = try get_int(reader); - _ = try get_byte(reader); - return try get_variant_t(reader, type_id, allocator); +pub fn readQVariant(reader: anytype, allocator: *std.mem.Allocator) !qvar.QVariant { + var type_id = try readUInt(reader); + _ = try readByte(reader); + return try readQVariantT(reader, type_id, allocator); } -pub fn get_qvariantmap(reader: anytype, allocator: *std.mem.Allocator) !std.StringHashMap(qvar.QVariant) { +pub fn readQVariantMap(reader: anytype, allocator: *std.mem.Allocator) !std.StringHashMap(qvar.QVariant) { var map = std.StringHashMap(qvar.QVariant).init(allocator); - var numItems = try get_int(reader); + var numItems = try readUInt(reader); var iter = range(u32, 0, numItems); while (iter.next()) |i| { - var key = try get_string(reader, allocator); - var value = try get_variant(reader, allocator); + var key = try readString(reader, allocator); + var value = try readQVariant(reader, allocator); try map.put(key, value); } diff --git a/src/qtshit/write.zig b/src/qtshit/write.zig index fbe2335..1b86590 100644 --- a/src/qtshit/write.zig +++ b/src/qtshit/write.zig @@ -1,108 +1,119 @@ const std = @import("std"); const qvar = @import("./qvariant.zig"); -pub fn add_int(writer: anytype, number: u32) !void { +const AllKnownErrors = (std.os.WriteError || error{OutOfMemory}); + +pub fn writeInt(writer: anytype, number: i32) !void { + try writer.writeIntBig(i32, number); +} + +pub fn writeUInt(writer: anytype, number: u32) !void { try writer.writeIntBig(u32, number); } -pub fn add_short(writer: anytype, number: u16) !void { +pub fn writeShort(writer: anytype, number: u16) !void { try writer.writeIntBig(u16, number); } -pub fn add_byte(writer: anytype, byte: u8) !void { +pub fn writeByte(writer: anytype, byte: u8) !void { try writer.writeByte(byte); } -pub fn add_bytearray(writer: anytype, array: std.ArrayList(u8)) !void { - try add_int(writer, @intCast(u32, array.items.len)); +pub fn writeByteArray(writer: anytype, array: std.ArrayList(u8)) !void { + try writeUInt(writer, @intCast(u32, array.items.len)); try writer.writeAll(array.items); } -pub fn add_string(writer: anytype, allocator: *std.mem.Allocator, str: []const u8) !void { +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)); } -// std.debug.print("add_lenchars: {d} {d} \n", .{@intCast(i32, ut16Str.len*8*2), str.len}); - try writer.writeIntBig(i32, @intCast(i32, ut16Str.len*2)); - try writer.writeAll(std.mem.sliceAsBytes(ut16Str)); + try writeInt(writer, @intCast(i32, ut16Str.len * 2)); + try writer.writeAll(std.mem.sliceAsBytes(ut16Str)); } -pub fn add_stringlist(writer: anytype, allocator: *std.mem.Allocator, strList: std.ArrayList([]const u8)) !void { - try add_int(writer, @intCast(u32, strList.items.len)); +pub fn writeQStringList(writer: anytype, allocator: *std.mem.Allocator, strList: std.ArrayList([]const u8)) !void { + try writeUInt(writer, @intCast(u32, strList.items.len)); for (strList.items) |string| { - try add_string(writer, allocator, string); + try writeString(writer, allocator, string); } } -pub fn add_variantlist(writer: anytype, allocator: *std.mem.Allocator, varList: std.ArrayList([]qvar.QVariant)) !void { - try add_int(writer, @intCast(u32, varList.items.len)); +pub fn writeQVariantList(writer: anytype, allocator: *std.mem.Allocator, varList: std.ArrayList(qvar.QVariant)) AllKnownErrors!void { + try writeUInt(writer, @intCast(u32, varList.items.len)); for (varList.items) |v| { - try add_variant(writer, allocator, v); + try writeQVariant(writer, allocator, v); } } // Call this and Then write your type -pub fn add_qvariant_with_id(writer: anytype, type_id: u32) !void { - try add_int(writer, type_id); - try add_byte(writer, 0); +pub fn writeQVariantHeader(writer: anytype, type_id: u32) !void { + try writeUInt(writer, type_id); + try writeByte(writer, 0); } -pub fn add_qvariant(writer: anytype, allocator: *std.mem.Allocator, variant: qvar.QVariant) !void { - try add_qvariant_with_id(writer, try qvar.qvariant_type_id(variant)); +pub fn writeQVariant(writer: anytype, allocator: *std.mem.Allocator, variant: qvar.QVariant) !void { + try writeQVariantHeader(writer, try qvar.qvariant_type_id(variant)); switch (variant) { - .byte => |out| { - try add_byte(writer, out); + .Byte => |out| { + try writeByte(writer, out); }, - .int => |out| { - try add_int(writer, out); + .Int => |out| { + try writeInt(writer, out); }, - .qmap => |out| { - try add_qvariantmap(writer, allocator, out); + .UInt => |out| { + try writeUInt(writer, out); }, - .string => |out| { - try add_string(writer, allocator, out); + .QVariantMap => |out| { + try writeQVariantMap(writer, allocator, out); }, - .stringlist => |out| { - try add_stringlist(writer, allocator, out); + .QVariantList => |out| { + try writeQVariantList(writer, allocator, out); }, - .bytearray => |out| { - try add_bytearray(writer, out); + .String => |out| { + try writeString(writer, allocator, out); }, - .short => |out| { - try add_short(writer, out); + .QStringList => |out| { + try writeQStringList(writer, allocator, out); }, - else => { - @panic("Unsupported!"); + .QByteArray => |out| { + try writeByteArray(writer, out); }, + .Short => |out| { + try writeShort(writer, out); + }, + //else => { + // @panic("Unsupported!"); + //}, } } -pub fn add_qvariantmap(writer: anytype, allocator: *std.mem.Allocator, map: std.StringHashMap(qvar.QVariant)) (@TypeOf(writer).Error || std.os.WriteError || error{OutOfMemory})!void { +pub fn writeQVariantMap(writer: anytype, allocator: *std.mem.Allocator, map: std.StringHashMap(qvar.QVariant)) (@TypeOf(writer).Error || std.os.WriteError || error{OutOfMemory})!void { var data = std.ArrayList(u8).init(allocator); defer data.deinit(); + var writeIterator = map.iterator(); while (writeIterator.next()) |entry| { - try add_string(data.writer(), allocator, entry.key); - try add_qvariant(data.writer(), allocator, entry.value); + try writeString(data.writer(), allocator, entry.key); + try writeQVariant(data.writer(), allocator, entry.value); } - // qvariantmap type - try add_int(writer, @enumToInt(qvar.QVariantTypes.qmap)); - try add_byte(writer, 0); - try add_int(writer, map.count()); - + try writeUInt(writer, map.count()); try writer.writeAll(data.items); + return; } -pub fn add_message(writer: anytype, allocator: *std.mem.Allocator, map: std.StringHashMap(qvar.QVariant)) (@TypeOf(writer).Error || std.os.WriteError || error{OutOfMemory})!void { +pub fn writeFrame(writer: anytype, allocator: *std.mem.Allocator, map: std.StringHashMap(qvar.QVariant)) (@TypeOf(writer).Error || std.os.WriteError || error{OutOfMemory})!void { var data = std.ArrayList(u8).init(allocator); - try add_qvariantmap(data.writer(), allocator, map); + try writeQVariant(data.writer(), allocator, .{ + .QVariantMap = map, + }); - try add_int(writer, @intCast(u32, data.items.len)); + try writeUInt(writer, @intCast(u32, data.items.len)); try writer.writeAll(data.items); return;