aboutsummaryrefslogtreecommitdiff
path: root/src/zip/io.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/zip/io.rs')
-rw-r--r--src/zip/io.rs127
1 files changed, 116 insertions, 11 deletions
diff --git a/src/zip/io.rs b/src/zip/io.rs
index b79ad0d..c41607f 100644
--- a/src/zip/io.rs
+++ b/src/zip/io.rs
@@ -1,12 +1,18 @@
1use super::datatypes::*;
1use super::file::{FileInfo, FileReader, FileWriter}; 2use super::file::{FileInfo, FileReader, FileWriter};
2use crate::io::{ArchiveRead, ArchiveWrite}; 3use crate::io::{ArchiveRead, ArchiveWrite};
3use crate::result::ArchiveResult; 4use crate::result::{ArchiveError, ArchiveResult};
5use crate::utils::ReadHelper;
6use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
7use std::collections::HashMap;
4use std::fs::File; 8use std::fs::File;
5use std::io::Read; 9use std::io::Read;
6use std::io::{Seek, Write}; 10use std::io::{Seek, SeekFrom, Write};
7 11
8pub struct Reader<R: Read + Seek = File> { 12pub struct Reader<R: Read + Seek = File> {
9 reader: R, 13 reader: R,
14 files: HashMap<String, FileInfo>,
15 comment: String,
10} 16}
11 17
12impl<R: Read + Seek> ArchiveRead for Reader<R> { 18impl<R: Read + Seek> ArchiveRead for Reader<R> {
@@ -14,16 +20,115 @@ impl<R: Read + Seek> ArchiveRead for Reader<R> {
14 type FileInfo = FileInfo; 20 type FileInfo = FileInfo;
15 type FileReader = FileReader; 21 type FileReader = FileReader;
16 22
17 fn new(reader: Self::Reader) -> ArchiveResult<Self> { 23 fn new(mut reader: Self::Reader) -> ArchiveResult<Self> {
18 Ok(Self { reader }) 24 let cd_size: u64;
25 let cd_offset: u64;
26 let cd_entries: u64;
27
28 let (eocd_offset, eocd, comment) = EndOfCentralDirectoryRecord::find(&mut reader)?;
29 if let Some((eocd64_offset, eocd64, eocd64_extensible)) =
30 Zip64EndOfCentralDirectoryRecord::find(&mut reader, eocd_offset)?
31 {
32 cd_size = eocd64.size_of_cd_records;
33 cd_offset = eocd64.offset_of_cd_entries;
34 cd_entries = eocd64.entries_in_cd;
35 } else {
36 cd_size = eocd.size_of_cd_records as u64;
37 cd_offset = eocd.offset_of_cd_entries as u64;
38 cd_entries = eocd.entries_in_cd as u64;
39 }
40
41 let mut buf = vec![0; cd_size as usize];
42 reader.seek(SeekFrom::Start(cd_offset))?;
43 reader.read(&mut buf)?;
44
45 let mut buf: &[u8] = &buf;
46 let mut files = HashMap::with_capacity(cd_entries as usize);
47
48 for entry_number in 0..cd_entries {
49 let cd = CentralDirectoryRecord::read(&mut buf)?;
50
51 let file_name = String::from_utf8(buf.read2vec(cd.file_name_length as usize)?).or(
52 Err(ArchiveError::IncorrectString {
53 location: "file_name",
54 }),
55 )?;
56 let mut extra_field: &[u8] = &buf.read2vec(cd.extra_field_length as usize)?;
57 let file_comment = String::from_utf8(buf.read2vec(cd.file_comment_length as usize)?)
58 .or(Err(ArchiveError::IncorrectString {
59 location: "file_comment",
60 }))?;
61
62 let mut uncompressed_size: u64 = cd.uncompressed_size as u64;
63 let mut compressed_size: u64 = cd.compressed_size as u64;
64 let mut header_offset: u64 = cd.header_offset as u64;
65
66 while extra_field.len() > 0 {
67 let header = u16::from_le_bytes(extra_field.read2buf()?);
68 let size = u16::from_le_bytes(extra_field.read2buf()?);
69 let mut data: &[u8] = &extra_field.read2vec(size as usize)?;
70
71 match header {
72 0x0001 => {
73 if uncompressed_size == 0xFFFFFFFF {
74 uncompressed_size = u64::from_le_bytes(data.read2buf()?);
75 }
76 if compressed_size == 0xFFFFFFFF {
77 compressed_size = u64::from_le_bytes(data.read2buf()?);
78 }
79 if header_offset == 0xFFFFFFFF {
80 header_offset = u64::from_le_bytes(data.read2buf()?);
81 }
82 }
83 _ => {}
84 };
85 }
86
87 let year = ((cd.last_mod_file_date >> 9) & 0x7F) + 1980;
88 let month = (cd.last_mod_file_date >> 5) & 0xF;
89 let day = cd.last_mod_file_date & 0x1F;
90
91 let hour = (cd.last_mod_file_time >> 11) & 0x1F;
92 let min = (cd.last_mod_file_time >> 5) & 0x3F;
93 let sec = (cd.last_mod_file_time & 0x1F) * 2;
94
95 files.insert(
96 file_name.clone(),
97 FileInfo::new(
98 entry_number,
99 cd.version_made_by,
100 cd.version_needed,
101 super::file::GeneralPurposeBitFlag {},
102 cd.compression_method.try_into()?,
103 NaiveDateTime::new(
104 NaiveDate::from_ymd_opt(year as i32, month as u32, day as u32)
105 .ok_or(ArchiveError::IncorrectDate { year, month, day })?,
106 NaiveTime::from_hms_opt(hour as u32, min as u32, sec as u32)
107 .ok_or(ArchiveError::IncorrectTime { hour, min, sec })?,
108 ),
109 cd.crc32,
110 compressed_size,
111 uncompressed_size,
112 file_name,
113 file_comment,
114 header_offset,
115 ),
116 );
117 }
118
119 Ok(Self {
120 reader,
121 files,
122 comment,
123 })
19 } 124 }
20 125
21 fn files(&self) -> ArchiveResult<Vec<Self::FileInfo>> { 126 fn files(&self) -> ArchiveResult<Vec<Self::FileInfo>> {
22 Ok(Vec::new()) 127 todo!()
23 } 128 }
24 129
25 fn file_reader(&self, name: &str) -> ArchiveResult<Self::FileReader> { 130 fn open_file(&self, name: &str) -> ArchiveResult<Self::FileReader> {
26 Ok(Self::FileReader {}) 131 todo!()
27 } 132 }
28} 133}
29 134
@@ -33,17 +138,17 @@ pub struct Writer<W: Write = File> {
33 writer: W, 138 writer: W,
34} 139}
35 140
36impl<W: Write> ArchiveWrite for Writer<W> { 141impl<W: Write + Seek> ArchiveWrite for Writer<W> {
37 type Writer = W; 142 type Writer = W;
38 type FileInfo = FileInfo; 143 type FileInfo = FileInfo;
39 type FileWriter = FileWriter; 144 type FileWriter = FileWriter;
40 145
41 fn new(writer: Self::Writer) -> ArchiveResult<Self> { 146 fn new(writer: Self::Writer) -> ArchiveResult<Self> {
42 Ok(Self { writer }) 147 todo!()
43 } 148 }
44 149
45 fn file_writer(&self, name: &str) -> ArchiveResult<Self::FileWriter> { 150 fn create_file(&self, name: &str) -> ArchiveResult<Self::FileWriter> {
46 Ok(Self::FileWriter {}) 151 todo!()
47 } 152 }
48} 153}
49 154