aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bencode.zig23
-rw-r--r--src/main.zig5
-rw-r--r--src/metainfo.zig47
-rw-r--r--src/sample.torrent1
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