read_single
This commit is contained in:
parent
95f311fd3e
commit
0b5746150c
1 changed files with 98 additions and 32 deletions
130
src/read.rs
130
src/read.rs
|
@ -74,6 +74,39 @@ fn unsupported_zip_error<T>(detail: &'static str) -> ZipResult<T>
|
||||||
Err(ZipError::UnsupportedArchive(detail))
|
Err(ZipError::UnsupportedArchive(detail))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn make_reader<'a>(
|
||||||
|
compression_method: ::compression::CompressionMethod,
|
||||||
|
crc32: u32,
|
||||||
|
reader: io::Take<&'a mut io::Read>)
|
||||||
|
-> ZipResult<ZipFileReader<'a>> {
|
||||||
|
|
||||||
|
match compression_method {
|
||||||
|
CompressionMethod::Stored =>
|
||||||
|
{
|
||||||
|
Ok(ZipFileReader::Stored(Crc32Reader::new(
|
||||||
|
reader,
|
||||||
|
crc32)))
|
||||||
|
},
|
||||||
|
CompressionMethod::Deflated =>
|
||||||
|
{
|
||||||
|
let deflate_reader = reader.deflate_decode();
|
||||||
|
Ok(ZipFileReader::Deflated(Crc32Reader::new(
|
||||||
|
deflate_reader,
|
||||||
|
crc32)))
|
||||||
|
},
|
||||||
|
#[cfg(feature = "bzip2")]
|
||||||
|
CompressionMethod::Bzip2 =>
|
||||||
|
{
|
||||||
|
let bzip2_reader = BzDecoder::new(reader);
|
||||||
|
Ok(ZipFileReader::Bzip2(Crc32Reader::new(
|
||||||
|
bzip2_reader,
|
||||||
|
crc32)))
|
||||||
|
},
|
||||||
|
_ => unsupported_zip_error("Compression method not supported"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<R: Read+io::Seek> ZipArchive<R>
|
impl<R: Read+io::Seek> ZipArchive<R>
|
||||||
{
|
{
|
||||||
/// Opens a Zip archive and parses the central directory
|
/// Opens a Zip archive and parses the central directory
|
||||||
|
@ -141,32 +174,7 @@ impl<R: Read+io::Seek> ZipArchive<R>
|
||||||
try!(self.reader.seek(io::SeekFrom::Start(pos)));
|
try!(self.reader.seek(io::SeekFrom::Start(pos)));
|
||||||
let limit_reader = (self.reader.by_ref() as &mut Read).take(data.compressed_size);
|
let limit_reader = (self.reader.by_ref() as &mut Read).take(data.compressed_size);
|
||||||
|
|
||||||
let reader = match data.compression_method
|
Ok(ZipFile { reader: try!(make_reader(data.compression_method, data.crc32, limit_reader)), data: data })
|
||||||
{
|
|
||||||
CompressionMethod::Stored =>
|
|
||||||
{
|
|
||||||
ZipFileReader::Stored(Crc32Reader::new(
|
|
||||||
limit_reader,
|
|
||||||
data.crc32))
|
|
||||||
},
|
|
||||||
CompressionMethod::Deflated =>
|
|
||||||
{
|
|
||||||
let deflate_reader = limit_reader.deflate_decode();
|
|
||||||
ZipFileReader::Deflated(Crc32Reader::new(
|
|
||||||
deflate_reader,
|
|
||||||
data.crc32))
|
|
||||||
},
|
|
||||||
#[cfg(feature = "bzip2")]
|
|
||||||
CompressionMethod::Bzip2 =>
|
|
||||||
{
|
|
||||||
let bzip2_reader = BzDecoder::new(limit_reader);
|
|
||||||
ZipFileReader::Bzip2(Crc32Reader::new(
|
|
||||||
bzip2_reader,
|
|
||||||
data.crc32))
|
|
||||||
},
|
|
||||||
_ => return unsupported_zip_error("Compression method not supported"),
|
|
||||||
};
|
|
||||||
Ok(ZipFile { reader: reader, data: data })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unwrap and return the inner reader object
|
/// Unwrap and return the inner reader object
|
||||||
|
@ -283,15 +291,19 @@ fn parse_extra_field(_file: &mut ZipFileData, data: &[u8]) -> ZipResult<()>
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_reader<'a>(reader: &'a mut ZipFileReader) -> &'a mut Read {
|
||||||
|
match *reader {
|
||||||
|
ZipFileReader::Stored(ref mut r) => r as &mut Read,
|
||||||
|
ZipFileReader::Deflated(ref mut r) => r as &mut Read,
|
||||||
|
#[cfg(feature = "bzip2")]
|
||||||
|
ZipFileReader::Bzip2(ref mut r) => r as &mut Read,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Methods for retreiving information on zip files
|
/// Methods for retreiving information on zip files
|
||||||
impl<'a> ZipFile<'a> {
|
impl<'a> ZipFile<'a> {
|
||||||
fn get_reader(&mut self) -> &mut Read {
|
fn get_reader(&mut self) -> &mut Read {
|
||||||
match self.reader {
|
get_reader(&mut self.reader)
|
||||||
ZipFileReader::Stored(ref mut r) => r as &mut Read,
|
|
||||||
ZipFileReader::Deflated(ref mut r) => r as &mut Read,
|
|
||||||
#[cfg(feature = "bzip2")]
|
|
||||||
ZipFileReader::Bzip2(ref mut r) => r as &mut Read,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/// Get the version of the file
|
/// Get the version of the file
|
||||||
pub fn version_made_by(&self) -> (u8, u8) {
|
pub fn version_made_by(&self) -> (u8, u8) {
|
||||||
|
@ -358,3 +370,57 @@ impl<'a> Read for ZipFile<'a> {
|
||||||
self.get_reader().read(buf)
|
self.get_reader().read(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ZipEntry<'a> {
|
||||||
|
pub name: String,
|
||||||
|
pub modified: ::time::Tm,
|
||||||
|
reader: ZipFileReader<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ZipEntry<'a> {
|
||||||
|
pub fn get_reader(&mut self) -> &mut Read {
|
||||||
|
get_reader(&mut self.reader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_single<'a, R: io::Read>(reader: &'a mut R) -> ZipResult<Option<ZipEntry>> {
|
||||||
|
let signature = try!(reader.read_u32::<LittleEndian>());
|
||||||
|
if signature != spec::LOCAL_FILE_HEADER_SIGNATURE
|
||||||
|
{
|
||||||
|
return if signature != spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE {
|
||||||
|
Err(ZipError::InvalidArchive("Invalid local file header"))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let version_made_by = try!(reader.read_u16::<LittleEndian>());
|
||||||
|
let flags = try!(reader.read_u16::<LittleEndian>());
|
||||||
|
let encrypted = flags & 1 == 1;
|
||||||
|
let is_utf8 = flags & (1 << 11) != 0;
|
||||||
|
let compression_method = CompressionMethod::from_u16(try!(reader.read_u16::<LittleEndian>()));
|
||||||
|
let last_mod_time = try!(reader.read_u16::<LittleEndian>());
|
||||||
|
let last_mod_date = try!(reader.read_u16::<LittleEndian>());
|
||||||
|
let crc32 = try!(reader.read_u32::<LittleEndian>());
|
||||||
|
let compressed_size = try!(reader.read_u32::<LittleEndian>());
|
||||||
|
let uncompressed_size = try!(reader.read_u32::<LittleEndian>());
|
||||||
|
let file_name_length = try!(reader.read_u16::<LittleEndian>()) as usize;
|
||||||
|
let extra_field_length = try!(reader.read_u16::<LittleEndian>()) as usize;
|
||||||
|
|
||||||
|
let file_name_raw = try!(ReadPodExt::read_exact(reader, file_name_length));
|
||||||
|
let extra_field = try!(ReadPodExt::read_exact(reader, extra_field_length));
|
||||||
|
|
||||||
|
let file_name = match is_utf8
|
||||||
|
{
|
||||||
|
true => String::from_utf8_lossy(&*file_name_raw).into_owned(),
|
||||||
|
false => file_name_raw.clone().from_cp437(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let limit_reader = (reader as &'a mut io::Read).take(compressed_size as u64);
|
||||||
|
|
||||||
|
Ok(Some(ZipEntry { name: file_name,
|
||||||
|
modified: try!(::time::Tm::from_msdos(MsDosDateTime::new(last_mod_time, last_mod_date))),
|
||||||
|
reader: try!(make_reader(compression_method, crc32, limit_reader))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue