aboutsummaryrefslogtreecommitdiff
path: root/src/metainfo.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/metainfo.zig')
-rw-r--r--src/metainfo.zig47
1 files changed, 47 insertions, 0 deletions
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);
+}