diff options
author | Martin Ashby <martin@ashbysoft.com> | 2023-11-11 11:20:15 +0000 |
---|---|---|
committer | Martin Ashby <martin@ashbysoft.com> | 2023-11-11 11:20:15 +0000 |
commit | 7eff166e1f7b440392be1082e3edd0c38b92d77c (patch) | |
tree | b27da98df178cda5a5625634b8f4a27a881e0be3 /src | |
parent | 2d65d9d3515a523d9cb8d242c3fc89671ae97d63 (diff) | |
download | zbt-7eff166e1f7b440392be1082e3edd0c38b92d77c.tar.gz zbt-7eff166e1f7b440392be1082e3edd0c38b92d77c.tar.bz2 zbt-7eff166e1f7b440392be1082e3edd0c38b92d77c.tar.xz zbt-7eff166e1f7b440392be1082e3edd0c38b92d77c.zip |
Add basic meta info file parsing
Diffstat (limited to 'src')
-rw-r--r-- | src/bencode.zig | 23 | ||||
-rw-r--r-- | src/main.zig | 5 | ||||
-rw-r--r-- | src/metainfo.zig | 47 | ||||
-rw-r--r-- | src/sample.torrent | 1 |
4 files changed, 75 insertions, 1 deletions
diff --git a/src/bencode.zig b/src/bencode.zig index 44dec0d..d09f394 100644 --- a/src/bencode.zig +++ b/src/bencode.zig @@ -70,6 +70,29 @@ pub const BValue = union(enum) { .int => {}, } } + + pub fn asDict(self: BValue) !std.StringArrayHashMap(BValue) { + switch (self) { + .dict => |d| return d, + else => return error.WrongType, + } + } + + pub fn asInt(self: BValue, comptime itype: type) !itype { + switch (self) { + .int => |i| { + return std.math.cast(itype, i) orelse error.Overflow; + }, + else => return error.WrongType, + } + } + + pub fn asString(self: BValue) ![]const u8 { + switch (self) { + .string => |s| return s, + else => return error.WrongType, + } + } }; pub fn bdecodeBuf(a: std.mem.Allocator, buf: []const u8) !BValue { diff --git a/src/main.zig b/src/main.zig index fa8a1b6..14ab3c3 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,7 +1,10 @@ const std = @import("std"); -pub fn main() !void {} +pub fn main() !void { + std.log.info("Hello, World", .{}); +} test { _ = @import("bencode.zig"); + _ = @import("metainfo.zig"); } diff --git a/src/metainfo.zig b/src/metainfo.zig new file mode 100644 index 0000000..9fa4788 --- /dev/null +++ b/src/metainfo.zig @@ -0,0 +1,47 @@ +//! https://wiki.theory.org/BitTorrentSpecification#Metainfo_File_Structure +const std = @import("std"); +const bencode = @import("bencode.zig"); +const MetaInfo = @This(); + +pub const Info = struct { + pub const File = struct { + name: []const u8, + length: u64, + path: []const u8, + }; + piece_length: u64, + pieces: []const u8, + files: []File, + pub fn parse(b: bencode.BValue) !Info { + var d = b.asDict() catch return error.Malformatted; + const pl = d.get("piece length") orelse return error.Malformatted; + const pp = d.get("pieces") orelse return error.Malformatted; + return .{ + .piece_length = pl.asInt(u64) catch return error.Malformatted, + .pieces = pp.asString() catch return error.Malformatted, + .files = &[_]File{}, + }; + } +}; + +info: Info, +announce: []const u8, + +pub fn parse(b: bencode.BValue) !MetaInfo { + var d = b.asDict() catch return error.Malformatted; + const i = d.get("info") orelse return error.Malformatted; + const a = d.get("announce") orelse return error.Malformatted; + return .{ + .info = try Info.parse(i), + .announce = a.asString() catch return error.Malformatted, + }; +} + +test "sample" { + const a = std.testing.allocator; + const sample_str = @embedFile("sample.torrent"); + var b = try bencode.bdecodeBuf(a, sample_str); + defer b.deinit(a); + const mi = try MetaInfo.parse(b); + try std.testing.expectEqualStrings("http://bittorrent-test-tracker.codecrafters.io/announce", mi.announce); +} diff --git a/src/sample.torrent b/src/sample.torrent new file mode 100644 index 0000000..44d1411 --- /dev/null +++ b/src/sample.torrent @@ -0,0 +1 @@ +d8:announce55:http://bittorrent-test-tracker.codecrafters.io/announce10:created by13:mktorrent 1.14:infod6:lengthi92063e4:name10:sample.txt12:piece lengthi32768e6:pieces60:vz*kg&-n"uvfVsnR5
z r'ee
\ No newline at end of file |