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
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later

use std::io::{Read, Seek, SeekFrom};

use binrw::BinRead;

use crate::compression::no_header_decompress;
use crate::dat::{BlockHeader, CompressionMode};

pub fn read_data_block<T: Read + Seek>(mut buf: T, starting_position: u64) -> Option<Vec<u8>> {
    buf.seek(SeekFrom::Start(starting_position)).ok()?;

    let block_header = BlockHeader::read(&mut buf).unwrap();

    match block_header.compression {
        CompressionMode::Compressed {
            compressed_length,
            decompressed_length,
        } => {
            let mut compressed_data: Vec<u8> = vec![0; compressed_length as usize];
            buf.read_exact(&mut compressed_data).ok()?;

            let mut decompressed_data: Vec<u8> = vec![0; decompressed_length as usize];
            if !no_header_decompress(&mut compressed_data, &mut decompressed_data) {
                return None;
            }

            Some(decompressed_data)
        }
        CompressionMode::Uncompressed { file_size } => {
            let mut local_data: Vec<u8> = vec![0; file_size as usize];
            buf.read_exact(&mut local_data).ok()?;

            Some(local_data)
        }
    }
}

/// A fixed version of read_data_block accounting for differing compressed block sizes in ZiPatch files.
pub fn read_data_block_patch<T: Read + Seek>(mut buf: T) -> Option<Vec<u8>> {
    let block_header = BlockHeader::read(&mut buf).unwrap();

    match block_header.compression {
        CompressionMode::Compressed {
            compressed_length,
            decompressed_length,
        } => {
            let compressed_length: usize =
                ((compressed_length as usize + 143) & 0xFFFFFF80) - (block_header.size as usize);

            let mut compressed_data: Vec<u8> = vec![0; compressed_length];
            buf.read_exact(&mut compressed_data).ok()?;

            let mut decompressed_data: Vec<u8> = vec![0; decompressed_length as usize];
            if !no_header_decompress(&mut compressed_data, &mut decompressed_data) {
                return None;
            }

            Some(decompressed_data)
        }
        CompressionMode::Uncompressed { file_size } => {
            let new_file_size: usize = (file_size as usize + 143) & 0xFFFFFF80;

            let mut local_data: Vec<u8> = vec![0; file_size as usize];
            buf.read_exact(&mut local_data).ok()?;

            buf.seek(SeekFrom::Current(
                (new_file_size - block_header.size as usize - file_size as usize) as i64,
            ))
            .ok()?;

            Some(local_data)
        }
    }
}