~sircmpwn/btqd

4f9f3d35b5c9cfadf4c4812c241524587a54dc47 — Drew DeVault 2 years ago cde5ca5
Simplify torrent reader
3 files changed, 62 insertions(+), 42 deletions(-)

M cmd/btinfo/main.ha
M torrent/torrent.ha
M torrent/util.ha
M cmd/btinfo/main.ha => cmd/btinfo/main.ha +10 -0
@@ 1,3 1,5 @@
use crypto::sha1;
use encoding::hex;
use fmt;
use os;
use torrent;


@@ 12,10 14,18 @@ export fn main() void = {
	defer torrent::torrent_free(tor);
	fmt::printfln("announce: {}", tor.announce)!;
	fmt::printfln("name: {}", tor.info.name)!;

	match (tor.info.length) {
	case void =>
		yield;
	case let z: size =>
		fmt::printfln("bytes: {}", z)!;
	};

	for (let i = 0z; i < len(tor.info.pieces); i += sha1::SIZE) {
		const piece = tor.info.pieces[i..i + sha1::SIZE];
		fmt::printf("{}: ", i)!;
		hex::encode(os::stdout, piece)!;
		fmt::println()!;
	};
};

M torrent/torrent.ha => torrent/torrent.ha +15 -42
@@ 47,7 47,6 @@ export fn read(in: io::handle) (*torrent | error) = {

	t.announce = strings::dup(scan_str(dict, "announce")?);
	const info = scan_dict(dict, "info")?;
	let nexpect = 0z;
	for (true) {
		const rec = match (bencode::dict_next(info)?) {
		case let rec: (str, bencode::record) =>


@@ 58,51 57,27 @@ export fn read(in: io::handle) (*torrent | error) = {

		switch (rec.0) {
		case "name" =>
			if (!(rec.1 is []u8)) {
				return invalid;
			};
			const name = match (strings::try_fromutf8(rec.1 as []u8)) {
			case let s: str =>
				yield s;
			case =>
				return invalid;
			};
			t.info.name = strings::dup(name);
			nexpect += 1;
			t.info.name = strings::dup(getstr(rec.1)?);
		case "piece length" =>
			if (!(rec.1 is int)) {
				return invalid;
			};
			t.info.piecelen = rec.1 as int: size;
			nexpect += 1;
			t.info.piecelen = getint(rec.1)?: size;
		case "pieces" =>
			if (!(rec.1 is []u8)) {
				return invalid;
			};
			let pieces = rec.1: []u8;
			let pieces = getbytes(rec.1)?;
			if (len(pieces) % sha1::SIZE != 0) {
				return invalid;
			};
			t.info.pieces = alloc(pieces...);
			nexpect += 1;
		case "length" =>
			if (!(rec.1 is int)) {
				return invalid;
			};
			t.info.length = rec.1 as int: size;
			nexpect += 1;
			t.info.length = getint(rec.1)?: size;
		case "files" =>
			if (!(rec.1 is bencode::list_reader)) {
				return invalid;
			};
			scan_files(t, rec.1 as bencode::list_reader)?;
			nexpect += 1;
			scan_files(t, getlist(rec.1)?)?;
		case =>
			yield;
		};
	};

	if (nexpect != 4) {
	if (t.info.name == "" || t.info.piecelen == 0
			|| len(t.info.pieces) == 0
			|| (t.info.length is void && len(t.info.files) == 0)) {
		return invalid;
	};



@@ 120,26 95,24 @@ fn scan_files(t: *torrent, list: bencode::list_reader) (void | error) = {
			return invalid;
		};

		let file = file {
			length = scan_int(dict, "length")?: size,
			...
		};
		let file = file { ... };
		file.length = scan_int(dict, "length")?: size;

		let path = scan_list(dict, "path")?;
		for (true) {
			const item = match (bencode::list_next(list)?) {
			match (bencode::list_next(list)?) {
			case io::EOF =>
				return;
			case let rec: []u8 =>
				yield match (strings::try_fromutf8(rec)) {
				case let s: str =>
					yield s;
				match (strings::try_fromutf8(rec)) {
				case let item: str =>
					append(file.path, strings::dup(item));
				case =>
					return invalid;
				};
			case =>
				return invalid;
			};
			append(file.path, strings::dup(item));
		};
		append(t.info.files, file);
	};

M torrent/util.ha => torrent/util.ha +37 -0
@@ 2,6 2,43 @@ use bencode;
use io;
use strings;

fn getbytes(rec: bencode::record) ([]u8 | error) = {
	match (rec) {
	case let bytes: []u8 =>
		return bytes;
	case =>
		return invalid;
	};
};

fn getstr(rec: bencode::record) (str | error) = {
	const bytes = getbytes(rec)?;
	match (strings::try_fromutf8(bytes)) {
	case let s: str =>
		return s;
	case =>
		return invalid;
	};
};

fn getint(rec: bencode::record) (int | error) = {
	match (rec) {
	case let i: int =>
		return i;
	case =>
		return invalid;
	};
};

fn getlist(rec: bencode::record) (bencode::list_reader | error) = {
	match (rec) {
	case let list: bencode::list_reader =>
		return list;
	case =>
		return invalid;
	};
};

fn scan_bytes(dict: bencode::dict_reader, key: str) ([]u8 | error) = {
	const val = scan_key(dict, key)?;
	if (!(val is []u8)) {