1use crate::ogg_xor::{validate_subrange, BoundedFile};
6use crate::vorbis;
7use anyhow::{bail, Result};
8use std::fs::File;
9use std::io::{Read, Seek, SeekFrom};
10use std::path::{Path, PathBuf};
11
12#[derive(Debug, Clone, Copy)]
13pub struct OvkEntry {
14 pub size: u32,
15 pub offset: u32,
16 pub no: u32,
17 pub sample_count: u32,
18}
19
20#[derive(Debug, Clone)]
21pub struct OvkPack {
22 path: PathBuf,
23 entries: Vec<OvkEntry>,
24 file_len: u64,
25}
26
27impl OvkPack {
28 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
29 let path = path.as_ref().to_path_buf();
30 let mut f = File::open(&path)?;
31 let file_len = f.metadata()?.len();
32
33 let mut head = [0u8; 4];
34 f.read_exact(&mut head)?;
35 let count = u32::from_le_bytes(head) as usize;
36 if count == 0 {
37 bail!("OVK: zero entries");
38 }
39 let mut entries = Vec::with_capacity(count);
40 for _ in 0..count {
41 let mut buf = [0u8; 16];
42 f.read_exact(&mut buf)?;
43 let size = u32::from_le_bytes(buf[0..4].try_into().unwrap());
44 let offset = u32::from_le_bytes(buf[4..8].try_into().unwrap());
45 let no = u32::from_le_bytes(buf[8..12].try_into().unwrap());
46 let smp = u32::from_le_bytes(buf[12..16].try_into().unwrap());
47 entries.push(OvkEntry {
48 size,
49 offset,
50 no,
51 sample_count: smp,
52 });
53 }
54 for (i, e) in entries.iter().enumerate() {
56 if e.size == 0 {
57 continue;
58 }
59 validate_subrange(file_len, e.offset as u64, e.size as u64)
60 .map_err(|err| anyhow::anyhow!("OVK entry[{i}] out of range: {err}"))?;
61 }
62
63 Ok(Self {
64 path,
65 entries,
66 file_len,
67 })
68 }
69
70 pub fn entries(&self) -> &[OvkEntry] {
71 &self.entries
72 }
73
74 pub fn get(&self, idx: usize) -> Option<OvkEntry> {
75 self.entries.get(idx).copied()
76 }
77
78 pub fn open_entry_stream(&self, idx: usize) -> Result<BoundedFile> {
80 let e = self
81 .entries
82 .get(idx)
83 .copied()
84 .ok_or_else(|| anyhow::anyhow!("OVK: entry index out of range: {idx}"))?;
85 if e.size == 0 {
86 bail!("OVK: entry[{idx}] has zero size");
87 }
88 BoundedFile::open(&self.path, e.offset as u64, e.size as u64, None)
89 }
90
91 pub fn extract_entry(&self, idx: usize) -> Result<Vec<u8>> {
93 self.open_entry_stream(idx)?.read_all()
94 }
95
96 pub fn decode_entry_vorbis_pcm16(&self, idx: usize) -> Result<vorbis::Pcm16> {
98 let s = self.open_entry_stream(idx)?;
99 vorbis::decode_ogg_vorbis_reader(s)
100 }
101
102 pub fn decode_entry_vorbis_wav(&self, idx: usize) -> Result<Vec<u8>> {
104 let s = self.open_entry_stream(idx)?;
105 vorbis::decode_ogg_vorbis_reader_to_wav(s)
106 }
107}
108
109#[derive(Debug, Clone)]
111pub struct OwpFile {
112 path: PathBuf,
113 file_len: u64,
114 pub xor_key: u8,
115}
116
117impl OwpFile {
118 pub const DEFAULT_XOR_KEY: u8 = 0x39;
119
120 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
121 let path = path.as_ref().to_path_buf();
122 let file_len = File::open(&path)?.metadata()?.len();
123 Ok(Self {
124 path,
125 file_len,
126 xor_key: Self::DEFAULT_XOR_KEY,
127 })
128 }
129
130 pub fn open_stream(&self) -> Result<BoundedFile> {
131 BoundedFile::open(&self.path, 0, self.file_len, Some(self.xor_key))
132 }
133
134 pub fn decrypt_to_vec(&self) -> Result<Vec<u8>> {
135 self.open_stream()?.read_all()
136 }
137
138 pub fn decode_vorbis_pcm16(&self) -> Result<vorbis::Pcm16> {
140 let s = self.open_stream()?;
141 vorbis::decode_ogg_vorbis_reader(s)
142 }
143
144 pub fn decode_vorbis_wav(&self) -> Result<Vec<u8>> {
146 let s = self.open_stream()?;
147 vorbis::decode_ogg_vorbis_reader_to_wav(s)
148 }
149}