use crate::error::Result;
use super::super::utils::crc32;
use super::Gr2Writer;
use super::constants::{NUM_SECTIONS, TAG_BG3, VERSION};
use super::section::Section;
use crate::formats::gr2::magic;
impl Gr2Writer {
pub(super) fn build_file_bytes(
&self,
sections_data: &(Vec<Section>, u32, u32),
) -> Result<Vec<u8>> {
let (sections, root_offset, root_type_offset) = sections_data;
let magic_size = 32;
let header_size = 72; let section_header_size = 44 * NUM_SECTIONS as usize;
let headers_total = magic_size + header_size + section_header_size;
let data_start = (headers_total + 15) & !15;
let mut section_offsets = Vec::new();
let mut current_offset = data_start;
for section in sections {
section_offsets.push(current_offset);
current_offset += section.len();
current_offset = (current_offset + 3) & !3;
}
let mut reloc_offsets = Vec::new();
for section in sections {
reloc_offsets.push(current_offset);
if !section.fixups.is_empty() {
current_offset += section.fixups.len() * 12;
}
}
let file_size = current_offset;
let mut output = Vec::with_capacity(file_size);
output.extend_from_slice(&magic::LE64);
output.extend_from_slice(&(data_start as u32).to_le_bytes());
output.extend_from_slice(&0u32.to_le_bytes()); output.extend_from_slice(&[0u8; 8]);
output.extend_from_slice(&VERSION.to_le_bytes());
output.extend_from_slice(&(file_size as u32).to_le_bytes());
output.extend_from_slice(&0u32.to_le_bytes()); output.extend_from_slice(&(header_size as u32).to_le_bytes());
output.extend_from_slice(&NUM_SECTIONS.to_le_bytes());
output.extend_from_slice(&4u32.to_le_bytes()); output.extend_from_slice(&root_type_offset.to_le_bytes());
output.extend_from_slice(&0u32.to_le_bytes()); output.extend_from_slice(&root_offset.to_le_bytes());
output.extend_from_slice(&TAG_BG3.to_le_bytes());
output.extend_from_slice(&[0u8; 16]);
output.extend_from_slice(&0u32.to_le_bytes());
output.extend_from_slice(&[0u8; 12]);
for (i, section) in sections.iter().enumerate() {
output.extend_from_slice(&0u32.to_le_bytes()); output.extend_from_slice(&(section_offsets[i] as u32).to_le_bytes());
output.extend_from_slice(&(section.len() as u32).to_le_bytes()); output.extend_from_slice(&(section.len() as u32).to_le_bytes());
output.extend_from_slice(&4u32.to_le_bytes()); output.extend_from_slice(&0u32.to_le_bytes()); output.extend_from_slice(&0u32.to_le_bytes()); output.extend_from_slice(&(reloc_offsets[i] as u32).to_le_bytes());
output.extend_from_slice(&(section.fixups.len() as u32).to_le_bytes());
output.extend_from_slice(&0u32.to_le_bytes()); output.extend_from_slice(&0u32.to_le_bytes()); }
while output.len() < data_start {
output.push(0);
}
for (i, section) in sections.iter().enumerate() {
while output.len() < section_offsets[i] {
output.push(0);
}
output.extend_from_slice(§ion.data);
while output.len() % 4 != 0 {
output.push(0);
}
}
for (i, section) in sections.iter().enumerate() {
if !section.fixups.is_empty() {
while output.len() < reloc_offsets[i] {
output.push(0);
}
for fixup in §ion.fixups {
output.extend_from_slice(&fixup.offset_in_section.to_le_bytes());
output.extend_from_slice(&fixup.target_section.to_le_bytes());
output.extend_from_slice(&fixup.target_offset.to_le_bytes());
}
}
}
let crc = crc32(&output[0x20 + 8..]);
output[0x20 + 8..0x20 + 12].copy_from_slice(&crc.to_le_bytes());
Ok(output)
}
}