diff --git a/crates/molotov-core/src/assets/asset.rs b/crates/molotov-core/src/assets/asset.rs new file mode 100644 index 0000000..d57f070 --- /dev/null +++ b/crates/molotov-core/src/assets/asset.rs @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +use super::types::{SEEK_CUR, SEEK_END, SEEK_SET}; +use std::ffi::c_void; + +pub struct AssetFile { + data: Vec, + cursor: usize, +} + +impl AssetFile { + pub fn new(data: Vec) -> Self { + Self { data, cursor: 0 } + } + + pub fn length(&self) -> i64 { + self.data.len() as i64 + } + + pub fn remaining_length(&self) -> i64 { + self.data.len().saturating_sub(self.cursor) as i64 + } + + pub fn get_buffer(&self) -> *const c_void { + self.data.as_ptr() as *const c_void + } + + pub fn read(&mut self, buf: &mut [u8]) -> usize { + let available = self.data.len().saturating_sub(self.cursor); + let to_read = buf.len().min(available); + if to_read > 0 { + buf[..to_read].copy_from_slice(&self.data[self.cursor..self.cursor + to_read]); + self.cursor += to_read; + } + to_read + } + + pub fn seek(&mut self, offset: i64, whence: i32) -> i64 { + let new_pos: i64 = match whence { + SEEK_SET => offset, + SEEK_CUR => self.cursor as i64 + offset, + SEEK_END => self.data.len() as i64 + offset, + _ => return -1, + }; + + if new_pos >= 0 && (new_pos as usize) <= self.data.len() { + self.cursor = new_pos as usize; + self.cursor as i64 + } else { + -1 + } + } +} diff --git a/crates/molotov-core/src/assets/mod.rs b/crates/molotov-core/src/assets/mod.rs new file mode 100644 index 0000000..ebdd1a4 --- /dev/null +++ b/crates/molotov-core/src/assets/mod.rs @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pub mod asset; +pub mod types; diff --git a/crates/molotov-core/src/assets/types.rs b/crates/molotov-core/src/assets/types.rs new file mode 100644 index 0000000..92e3102 --- /dev/null +++ b/crates/molotov-core/src/assets/types.rs @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pub const AASSET_MODE_UNKNOWN: i32 = 0; +pub const AASSET_MODE_RANDOM: i32 = 1; +pub const AASSET_MODE_STREAMING: i32 = 2; +pub const AASSET_MODE_BUFFER: i32 = 3; + +pub const SEEK_SET: i32 = 0; +pub const SEEK_CUR: i32 = 1; +pub const SEEK_END: i32 = 2; diff --git a/crates/molotov-core/src/lib.rs b/crates/molotov-core/src/lib.rs index aa7bdf5..61ec6f1 100644 --- a/crates/molotov-core/src/lib.rs +++ b/crates/molotov-core/src/lib.rs @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later +pub mod assets; pub mod audio; pub mod dynamic; pub mod elf; diff --git a/crates/molotov-core/tests/asset_read_test.rs b/crates/molotov-core/tests/asset_read_test.rs new file mode 100644 index 0000000..c7b5998 --- /dev/null +++ b/crates/molotov-core/tests/asset_read_test.rs @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +use molotov_core::assets::asset::AssetFile; + +#[test] +fn test_asset_read_and_seek_flow() { + let data = b"ROBLOX_ASSET_CONTENT_12345".to_vec(); + let mut asset = AssetFile::new(data); + + assert_eq!(asset.length(), 26); + assert_eq!(asset.remaining_length(), 26); + + let mut buf = [0u8; 6]; + assert_eq!(asset.read(&mut buf), 6); + assert_eq!(&buf, b"ROBLOX"); + assert_eq!(asset.remaining_length(), 20); + + // Seek to offset 7 (SEEK_SET = 0) + assert_eq!(asset.seek(7, 0), 7); + assert_eq!(asset.remaining_length(), 19); + + let mut next_buf = [0u8; 5]; + assert_eq!(asset.read(&mut next_buf), 5); + assert_eq!(&next_buf, b"ASSET"); +}