1use std::{convert::TryFrom, io::{Cursor, Read, Write}};
8
9use byteorder::LittleEndian;
10use encoding::{DecoderTrap, EncoderTrap, Encoding, all::UTF_16LE};
11
12use crate::{XP3Error, XP3ErrorKind, XP3_INDEX_ADLR_IDENTIFIER, XP3_INDEX_INFO_IDENTIFIER, XP3_INDEX_SEGM_IDENTIFIER, XP3_INDEX_TIME_IDENTIFIER};
13use byteorder::{ReadBytesExt, WriteBytesExt};
14
15use super::XP3Index;
16
17#[derive(Debug, Clone)]
20pub struct XP3FileIndex {
21
22 info: XP3FileIndexInfo,
23 segments: Vec<XP3FileIndexSegment>,
24 adler: XP3FileIndexAdler,
25 time: Option<XP3FileIndexTime>
26
27}
28
29impl XP3FileIndex {
30
31 pub fn new(
32 info: XP3FileIndexInfo,
33 segments: Vec<XP3FileIndexSegment>,
34 adler: XP3FileIndexAdler,
35 time: Option<XP3FileIndexTime>
36 ) -> Self {
37 Self {
38 info,
39 segments,
40 adler,
41 time
42 }
43 }
44
45 pub fn time(&self) -> Option<XP3FileIndexTime> {
47 self.time
48 }
49
50 pub fn adler(&self) -> XP3FileIndexAdler {
52 self.adler
53 }
54
55 pub fn info(&self) -> &XP3FileIndexInfo {
57 &self.info
58 }
59
60 pub fn segments(&self) -> &Vec<XP3FileIndexSegment> {
62 &self.segments
63 }
64
65 pub fn from_bytes(file_size: u64, stream: &mut impl Read) -> Result<(u64, Self), XP3Error> {
68 let mut info: Option<XP3FileIndexInfo> = None;
69 let mut segm: Option<Vec<XP3FileIndexSegment>> = None;
70 let mut time: Option<XP3FileIndexTime> = None;
71 let mut adler32: Option<XP3FileIndexAdler> = None;
72
73 let mut total_read: u64 = 0;
74 while total_read < file_size {
75 let (read, index) = XP3Index::from_bytes(stream)?;
76
77 let mut data_stream = Cursor::new(&index.data);
78
79 match index.identifier {
80
81 XP3_INDEX_INFO_IDENTIFIER => {
82 if info.is_some() {
83 return Err(XP3Error::new(XP3ErrorKind::InvalidFileIndex, None));
84 }
85
86 info = Some(XP3FileIndexInfo::from_bytes(&mut data_stream)?.1);
87 },
88
89 XP3_INDEX_SEGM_IDENTIFIER => {
90 if segm.is_some() {
91 return Err(XP3Error::new(XP3ErrorKind::InvalidFileIndex, None));
92 }
93
94 let count = data_stream.get_ref().len() / 28;
95
96 let mut list: Vec<XP3FileIndexSegment> = Vec::new();
97 for _ in 0..count {
98 list.push(XP3FileIndexSegment::from_bytes(&mut data_stream)?.1);
99 }
100
101 segm = Some(list);
102 },
103
104 XP3_INDEX_ADLR_IDENTIFIER => {
105 adler32 = Some(XP3FileIndexAdler::from_bytes(&mut data_stream)?.1);
106 },
107
108 XP3_INDEX_TIME_IDENTIFIER => {
109 time = Some(XP3FileIndexTime::from_bytes(&mut data_stream)?.1);
110 },
111
112 _ => {
113 }
115 }
116
117
118 total_read += read;
119 }
120
121 if info.is_none() || adler32.is_none() || segm.is_none() {
122 return Err(XP3Error::new(XP3ErrorKind::InvalidFileIndex, None));
123 }
124
125 Ok((total_read, XP3FileIndex::new(info.unwrap(), segm.unwrap(), adler32.unwrap(), time)))
126 }
127
128 pub fn write_bytes(&self, stream: &mut impl Write) -> Result<u64, XP3Error> {
130 let mut written = 0_u64;
131
132 if self.time.is_some() {
133 let mut buffer = Vec::<u8>::new();
134 self.time.unwrap().write_bytes(&mut buffer)?;
135 written += XP3Index { identifier: XP3_INDEX_TIME_IDENTIFIER, data: buffer }.write_bytes(stream)?;
136 }
137
138 {
139 let mut buffer = Vec::<u8>::new();
140 self.adler.write_bytes(&mut buffer)?;
141 written += XP3Index { identifier: XP3_INDEX_ADLR_IDENTIFIER, data: buffer }.write_bytes(stream)?;
142 }
143
144 {
145 let mut buffer = Vec::<u8>::new();
146 for segment in self.segments.iter() {
147 segment.write_bytes(&mut buffer)?;
148 }
149
150 written += XP3Index { identifier: XP3_INDEX_SEGM_IDENTIFIER, data: buffer }.write_bytes(stream)?;
151 }
152
153 {
154 let mut buffer = Vec::<u8>::new();
155 self.info.write_bytes(&mut buffer)?;
156 written += XP3Index { identifier: XP3_INDEX_INFO_IDENTIFIER, data: buffer }.write_bytes(stream)?;
157 }
158
159 Ok(written)
160 }
161
162}
163
164#[derive(Debug, Copy, Clone)]
165#[repr(u32)]
166pub enum IndexInfoFlag {
167
168 NotProtected = 0,
169 Protected = 2147483648
170
171}
172
173impl TryFrom<u32> for IndexInfoFlag {
174
175 type Error = XP3Error;
176
177 fn try_from(value: u32) -> Result<Self, Self::Error> {
178 match value {
179
180 value if value == Self::NotProtected as u32 => Ok(Self::NotProtected),
181 value if value == Self::Protected as u32 => Ok(Self::Protected),
182
183 _ => Err(XP3Error::new(XP3ErrorKind::InvalidFileIndexFlag, None))
184 }
185 }
186}
187
188#[derive(Debug, Clone)]
189pub struct XP3FileIndexInfo {
191
192 flag: IndexInfoFlag,
193 file_size: u64,
194 saved_file_size: u64,
195 name: String
196
197}
198
199impl XP3FileIndexInfo {
200
201 pub fn new(
202 flag: IndexInfoFlag,
203 file_size: u64,
204 saved_file_size: u64,
205 name: String
206 ) -> Self {
207 Self {
208 flag,
209 file_size,
210 saved_file_size,
211 name
212 }
213 }
214
215 pub fn flag(&self) -> IndexInfoFlag {
216 self.flag
217 }
218
219 pub fn set_flag(&mut self, flag: IndexInfoFlag) {
220 self.flag = flag;
221 }
222
223 pub fn file_size(&self) -> u64 {
224 self.file_size
225 }
226
227 pub fn set_file_size(&mut self, file_size: u64) {
228 self.file_size = file_size;
229 }
230
231 pub fn saved_file_size(&self) -> u64 {
232 self.saved_file_size
233 }
234
235 pub fn set_saved_file_size(&mut self, saved_file_size: u64) {
236 self.saved_file_size = saved_file_size;
237 }
238
239 pub fn name(&self) -> &String {
240 &self.name
241 }
242
243 pub fn set_name(&mut self, name: String) {
244 self.name = name;
245 }
246
247 pub fn from_bytes(stream: &mut impl Read) -> Result<(u64, Self), XP3Error> {
249 let flag = IndexInfoFlag::try_from(stream.read_u32::<LittleEndian>()?)?;
250
251 let file_size = stream.read_u64::<LittleEndian>()?;
252 let saved_file_size = stream.read_u64::<LittleEndian>()?;
253
254 let name_byte_size = stream.read_u16::<LittleEndian>()? * 2;
255 let name = {
256 let mut name_buffer = Vec::with_capacity(name_byte_size as usize);
257 stream.take(name_byte_size as u64).read_to_end(&mut name_buffer)?;
258
259 UTF_16LE.decode(&name_buffer, DecoderTrap::Replace).unwrap()
260 };
261
262 Ok((22 + name_byte_size as u64, Self::new(flag, file_size, saved_file_size, name)))
263 }
264
265 pub fn write_bytes(&self, stream: &mut impl Write) -> Result<u64, XP3Error> {
268 stream.write_u32::<LittleEndian>(self.flag as u32)?;
269
270 stream.write_u64::<LittleEndian>(self.file_size)?;
271 stream.write_u64::<LittleEndian>(self.saved_file_size)?;
272
273 let encoded = UTF_16LE.encode(&self.name, EncoderTrap::Replace).unwrap();
274 let name_byte_size = encoded.len().min(65536);
275 stream.write_u16::<LittleEndian>((name_byte_size / 2) as u16)?;
276 stream.write_all(&encoded[..name_byte_size])?;
277
278 Ok(22 + name_byte_size as u64)
279 }
280
281}
282
283#[derive(Debug, Copy, Clone)]
284#[repr(u32)]
285pub enum IndexSegmentFlag {
286
287 UnCompressed = 0,
288 Compressed = 1
289
290}
291
292#[derive(Debug, Copy, Clone)]
293pub struct XP3FileIndexSegment {
296
297 flag: IndexSegmentFlag,
298 data_offset: u64,
299 original_size: u64,
300 saved_size: u64
301
302}
303
304impl XP3FileIndexSegment {
305
306 pub fn new(
307 flag: IndexSegmentFlag,
308 data_offset: u64,
309 original_size: u64,
310 saved_size: u64
311 ) -> Self {
312 Self {
313 flag, data_offset, original_size, saved_size
314 }
315 }
316
317 pub fn flag(&self) -> IndexSegmentFlag {
318 self.flag
319 }
320
321 pub fn set_flag(&mut self, flag: IndexSegmentFlag) {
322 self.flag = flag;
323 }
324
325 pub fn data_offset(&self) -> u64 {
326 self.data_offset
327 }
328
329 pub fn set_data_offset(&mut self, data_offset: u64) {
330 self.data_offset = data_offset;
331 }
332
333 pub fn original_size(&self) -> u64 {
334 self.original_size
335 }
336
337 pub fn set_original_size(&mut self, original_size: u64) {
338 self.original_size = original_size;
339 }
340
341 pub fn saved_size(&self) -> u64 {
342 self.saved_size
343 }
344
345 pub fn set_saved_size(&mut self, saved_size: u64) {
346 self.saved_size = saved_size;
347 }
348
349 pub fn from_bytes(stream: &mut impl Read) -> Result<(u64, Self), XP3Error> {
351 let flag = {
352 let raw_flag = stream.read_u32::<LittleEndian>()?;
353
354 if raw_flag == IndexSegmentFlag::UnCompressed as u32 {
355 Ok(IndexSegmentFlag::UnCompressed)
356 } else if raw_flag == IndexSegmentFlag::Compressed as u32 {
357 Ok(IndexSegmentFlag::Compressed)
358 } else {
359 Err(XP3Error::new(XP3ErrorKind::InvalidFileIndex, None))
360 }
361 }?;
362
363 let data_offset = stream.read_u64::<LittleEndian>()?;
364 let original_size = stream.read_u64::<LittleEndian>()?;
365 let saved_size = stream.read_u64::<LittleEndian>()?;
366
367 Ok((28, Self::new(flag, data_offset, original_size, saved_size)))
368 }
369
370 pub fn write_bytes(&self, stream: &mut impl Write) -> Result<u64, XP3Error> {
373 stream.write_u32::<LittleEndian>(self.flag as u32)?;
374
375 stream.write_u64::<LittleEndian>(self.data_offset)?;
376 stream.write_u64::<LittleEndian>(self.original_size)?;
377 stream.write_u64::<LittleEndian>(self.saved_size)?;
378
379 Ok(28)
380 }
381
382}
383
384#[derive(Debug, Copy, Clone)]
385pub struct XP3FileIndexTime {
387
388 timestamp: u64
389
390}
391
392impl XP3FileIndexTime {
393
394 pub fn new(timestamp: u64) -> Self {
395 Self {
396 timestamp
397 }
398 }
399
400 pub fn timestamp(&self) -> u64 {
401 self.timestamp
402 }
403
404 pub fn set_timestamp(&mut self, timestamp: u64) {
405 self.timestamp = timestamp;
406 }
407
408 pub fn from_bytes(stream: &mut impl Read) -> Result<(u64, Self), XP3Error> {
410 let timestamp = stream.read_u64::<LittleEndian>()?;
411
412 Ok((8, Self::new(timestamp)))
413 }
414
415 pub fn write_bytes(&self, stream: &mut impl Write) -> Result<u64, XP3Error> {
417 stream.write_u64::<LittleEndian>(self.timestamp)?;
418
419 Ok(8)
420 }
421
422}
423
424#[derive(Debug, Copy, Clone)]
425pub struct XP3FileIndexAdler {
427
428 checksum: u32
429
430}
431
432impl XP3FileIndexAdler {
433
434 pub fn new(checksum: u32) -> Self {
435 Self {
436 checksum
437 }
438 }
439
440 pub fn checksum(&self) -> u32 {
441 self.checksum
442 }
443
444 pub fn set_checksum(&mut self, checksum: u32) {
445 self.checksum = checksum;
446 }
447
448 pub fn from_bytes(stream: &mut impl Read) -> Result<(u64, Self), XP3Error> {
450 let checksum = stream.read_u32::<LittleEndian>()?;
451
452 Ok((4, Self::new(checksum)))
453 }
454
455 pub fn write_bytes(&self, stream: &mut impl Write) -> Result<u64, XP3Error> {
457 stream.write_u32::<LittleEndian>(self.checksum)?;
458
459 Ok(4)
460 }
461
462}