public Torrent(byte[] torrent, File parent, boolean seeder)
		throws IOException, NoSuchAlgorithmException {
		this.encoded = torrent;
		this.seeder = seeder;

		this.decoded = BDecoder.bdecode(new ByteArrayInputStream(this.encoded)).getMap();

		this.decoded_info = this.decoded.get("info").getMap();
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		BEncoder.bencode(this.decoded_info, baos);
		this.encoded_info = baos.toByteArray();
		this.info_hash = Torrent.hash(this.encoded_info);
		this.hex_info_hash = Torrent.byteArrayToHexString(this.info_hash);

		this.announceUrl = this.decoded.get("announce").getString();
		this.createdBy = this.decoded.containsKey("created by")
			? this.decoded.get("created by").getString()
			: null;
		this.name = this.decoded_info.get("name").getString();

		this.files = new LinkedList<TorrentFile>();

		// Parse multi-file torrent file information structure.
		if (this.decoded_info.containsKey("files")) {
			for (BEValue file : this.decoded_info.get("files").getList()) {
				Map<String, BEValue> fileInfo = file.getMap();
				StringBuffer path = new StringBuffer();
				for (BEValue pathElement : fileInfo.get("path").getList()) {
					path.append(File.separator)
						.append(pathElement.getString());
				}
				this.files.add(new TorrentFile(
					new File(this.name, path.toString()),
					fileInfo.get("length").getLong()));
			}
		} else {
			// For single-file torrents, the name of the torrent is
			// directly the name of the file.
			this.files.add(new TorrentFile(
				new File(this.name),
				this.decoded_info.get("length").getLong()));
		}

		// Calculate the total size of this torrent from its files' sizes.
		long size = 0;
		for (TorrentFile file : this.files) {
			size += file.size;
		}
		this.size = size;

		logger.info("{}-file torrent information:",
			this.isMultifile() ? "Multi" : "Single");
		logger.info("  Torrent name: {}", this.name);
		logger.info("  Announced at: {}", this.announceUrl);
		if (this.createdBy != null) {
			logger.info("  Created by..: {}", this.createdBy);
		}

		if (this.isMultifile()) {
			logger.info("  Found {} file(s) in multi-file torrent structure.",
				this.files.size());
			int i = 0;
			for (TorrentFile file : this.files) {
				logger.debug("  {}. {} ({} byte(s))",
					new Object[] {
						String.format("%2d", ++i),
						file.file.getPath(),
						file.size
					});
			}
		}

		logger.info("  Total size: {} byte(s)", this.size);
	}