1use std::{borrow::Cow, io};
2
3use serde::{Deserialize, Serialize};
4
5use super::raw::{self, FileAlloc, OverlayCompressedSize, RawHeaderError};
6use crate::compress::lz77::{Lz77, Lz77DecompressError};
7
8#[derive(Clone)]
10pub struct Overlay<'a> {
11 originally_compressed: bool,
12 info: OverlayInfo,
13 data: Cow<'a, [u8]>,
14}
15
16const LZ77: Lz77 = Lz77 {};
17
18impl<'a> Overlay<'a> {
19 pub fn new<T: Into<Cow<'a, [u8]>>>(data: T, info: OverlayInfo, originally_compressed: bool) -> Self {
21 Self { originally_compressed, info, data: data.into() }
22 }
23
24 pub fn parse(overlay: &raw::Overlay, fat: &[FileAlloc], rom: &'a raw::Rom) -> Result<Self, RawHeaderError> {
26 let alloc = fat[overlay.file_id as usize];
27 let data = &rom.data()[alloc.range()];
28 Ok(Self {
29 originally_compressed: overlay.compressed.is_compressed() != 0,
30 info: OverlayInfo::new(overlay),
31 data: Cow::Borrowed(data),
32 })
33 }
34
35 pub fn build(&self) -> raw::Overlay {
37 raw::Overlay {
38 id: self.id() as u32,
39 base_addr: self.base_address(),
40 code_size: self.code_size(),
41 bss_size: self.bss_size(),
42 ctor_start: self.ctor_start(),
43 ctor_end: self.ctor_end(),
44 file_id: self.file_id(),
45 compressed: if self.is_compressed() {
46 OverlayCompressedSize::new().with_size(self.data.len()).with_is_compressed(1)
47 } else {
48 OverlayCompressedSize::new().with_size(0).with_is_compressed(0)
49 },
50 }
51 }
52
53 pub fn id(&self) -> u16 {
55 self.info.id as u16
56 }
57
58 pub fn base_address(&self) -> u32 {
60 self.info.base_address
61 }
62
63 pub fn end_address(&self) -> u32 {
65 self.info.base_address + self.info.code_size + self.info.bss_size
66 }
67
68 pub fn code_size(&self) -> u32 {
70 self.info.code_size
71 }
72
73 pub fn bss_size(&self) -> u32 {
75 self.info.bss_size
76 }
77
78 pub fn ctor_start(&self) -> u32 {
80 self.info.ctor_start
81 }
82
83 pub fn ctor_end(&self) -> u32 {
85 self.info.ctor_end
86 }
87
88 pub fn file_id(&self) -> u32 {
90 self.info.file_id
91 }
92
93 pub fn is_compressed(&self) -> bool {
96 self.info.compressed
97 }
98
99 pub fn decompress(&mut self) -> Result<(), Lz77DecompressError> {
101 if !self.is_compressed() {
102 return Ok(());
103 }
104 self.data = LZ77.decompress(&self.data)?.into_vec().into();
105 self.info.compressed = false;
106 Ok(())
107 }
108
109 pub fn compress(&mut self) -> Result<(), io::Error> {
115 if self.is_compressed() {
116 return Ok(());
117 }
118 self.data = LZ77.compress(&self.data, 0)?.into_vec().into();
119 self.info.compressed = true;
120 Ok(())
121 }
122
123 pub fn code(&self) -> &[u8] {
125 &self.data[..self.code_size() as usize]
126 }
127
128 pub fn full_data(&self) -> &[u8] {
130 &self.data
131 }
132
133 pub fn info(&self) -> &OverlayInfo {
135 &self.info
136 }
137
138 pub fn originally_compressed(&self) -> bool {
140 self.originally_compressed
141 }
142}
143
144#[derive(Serialize, Deserialize, Clone)]
146pub struct OverlayInfo {
147 pub id: u32,
149 pub base_address: u32,
151 pub code_size: u32,
153 pub bss_size: u32,
155 pub ctor_start: u32,
157 pub ctor_end: u32,
159 pub file_id: u32,
161 pub compressed: bool,
163}
164
165impl OverlayInfo {
166 pub fn new(overlay: &raw::Overlay) -> Self {
168 Self {
169 id: overlay.id,
170 base_address: overlay.base_addr,
171 code_size: overlay.code_size,
172 bss_size: overlay.bss_size,
173 ctor_start: overlay.ctor_start,
174 ctor_end: overlay.ctor_end,
175 file_id: overlay.file_id,
176 compressed: overlay.compressed.is_compressed() != 0,
177 }
178 }
179}