1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
use std::{io, fs, path, cmp};

/// Creates an iterator over all blk .dat files
pub fn read_blk_dir<P>(path: P) -> Result<ReadBlkDir, io::Error> where P: AsRef<path::Path> {
	let read_blk_dir = ReadBlkDir {
		read_dir: try!(fs::read_dir(path)),
	};

	Ok(read_blk_dir)
}

pub struct ReadBlkDir {
	read_dir: fs::ReadDir,
}

#[derive(PartialEq, Eq)]
pub struct BlkEntry {
	pub path: path::PathBuf,
}

impl cmp::PartialOrd for BlkEntry {
	fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
		cmp::PartialOrd::partial_cmp(&self.path, &other.path)
	}
}

impl cmp::Ord for BlkEntry {
	fn cmp(&self, other: &Self) -> cmp::Ordering {
		cmp::Ord::cmp(&self.path, &other.path)
	}
}

fn is_blk_file_name(file_name: &str) -> bool {
	if file_name.len() != 12 || !file_name.starts_with("blk") || !file_name.ends_with(".dat") {
		return false;
	}

	file_name[3..8].parse::<u32>().is_ok()
}

impl BlkEntry {
	fn from_dir_entry(dir_entry: fs::DirEntry) -> Option<Self> {
		match dir_entry.metadata() {
			Err(_) => return None,
			Ok(ref metadata) => {
				if !metadata.is_file() {
					return None;
				}
			}
		}

		match dir_entry.file_name().into_string() {
			Err(_) => return None,
			Ok(ref file_name) => {
				if !is_blk_file_name(file_name) {
					return None;
				}
			}
		}

		let entry = BlkEntry {
			path: dir_entry.path(),
		};

		Some(entry)
	}
}

impl Iterator for ReadBlkDir {
	type Item = Result<BlkEntry, io::Error>;

	fn next(&mut self) -> Option<Self::Item> {
		let mut result = None;
		while result.is_none() {
			match self.read_dir.next() {
				None => return None,
				Some(Err(err)) => return Some(Err(err)),
				Some(Ok(entry)) => {
					result = BlkEntry::from_dir_entry(entry);
				}
			}
		}
		result.map(Ok)
	}
}

#[cfg(test)]
mod test {
	use super::is_blk_file_name;

	#[test]
	fn test_is_blk_file_name() {
		assert!(is_blk_file_name("blk00000.dat"));
		assert!(is_blk_file_name("blk00232.dat"));
		assert!(!is_blk_file_name("blk0000.dat"));
		assert!(!is_blk_file_name("blk00000.daw"));
		assert!(!is_blk_file_name("blk00032.daw"));
		assert!(!is_blk_file_name("blk000ff.dat"));
	}
}