aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Ashby <martin@ashbysoft.com>2023-11-11 11:20:15 +0000
committerMartin Ashby <martin@ashbysoft.com>2023-11-11 11:20:15 +0000
commit7eff166e1f7b440392be1082e3edd0c38b92d77c (patch)
treeb27da98df178cda5a5625634b8f4a27a881e0be3
parent2d65d9d3515a523d9cb8d242c3fc89671ae97d63 (diff)
downloadzbt-7eff166e1f7b440392be1082e3edd0c38b92d77c.tar.gz
zbt-7eff166e1f7b440392be1082e3edd0c38b92d77c.tar.bz2
zbt-7eff166e1f7b440392be1082e3edd0c38b92d77c.tar.xz
zbt-7eff166e1f7b440392be1082e3edd0c38b92d77c.zip
Add basic meta info file parsing
-rw-r--r--src/bencode.zig23
-rw-r--r--src/main.zig5
-rw-r--r--src/metainfo.zig47
-rw-r--r--src/sample.torrent (renamed from sample.torrent)0
4 files changed, 74 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/sample.torrent b/src/sample.torrent
index 44d1411..44d1411 100644
--- a/sample.torrent
+++ b/src/sample.torrent