90 lines
2.1 KiB
Odin
90 lines
2.1 KiB
Odin
package file
|
|
|
|
import "core:fmt"
|
|
import "core:mem"
|
|
import "core:os"
|
|
|
|
MAGIC_STRING :: 0x514D21 // SINDRI
|
|
VERSION :: 1
|
|
COMPRESSION :: 0
|
|
SIZE_PER_CHUNK :: 2 * (1 << 30) // 2GiB
|
|
PATH_SIZE :: 512
|
|
|
|
// -----------------------------------------
|
|
|
|
Header :: struct #packed #all_or_none {
|
|
magic_string: u32,
|
|
version: u16,
|
|
compression: u16,
|
|
size_per_chunk: u64,
|
|
total_size: u64,
|
|
number_of_assets: u32,
|
|
// asset_index: []AssetIndex,
|
|
}
|
|
|
|
AssetIndex :: struct #packed #all_or_none {
|
|
relpath: [PATH_SIZE]u8,
|
|
size: u64,
|
|
offset: u64,
|
|
}
|
|
|
|
// -----------------------------------------
|
|
|
|
// remove :: proc(name: string) -> Error {…}
|
|
// create :: proc(name: string) -> (^File, Error) {…}
|
|
// write_at :: proc(f: ^File, p: []u8, offset: i64) -> (n: int, err: Error) {…}
|
|
|
|
// Returning `[]u8` is owned by the caller.
|
|
compute_header :: proc(
|
|
entries: [dynamic]FileEntry,
|
|
compression: u16 = COMPRESSION,
|
|
size_per_chunk: u64 = SIZE_PER_CHUNK,
|
|
allocator := context.allocator,
|
|
) -> (
|
|
header: Header,
|
|
asset_index: []AssetIndex,
|
|
) {
|
|
number_of_assets := cast(u32)len(entries)
|
|
|
|
index_size: u64 = size_of(AssetIndex) * cast(u64)number_of_assets
|
|
data_offset: u64 = size_of(Header) + index_size
|
|
total_size: u64 = data_offset
|
|
|
|
bytes := make([]u8, index_size, allocator)
|
|
|
|
for f, i in entries {
|
|
|
|
path_length := len(f.relpath)
|
|
if path_length > 512 {
|
|
fmt.eprintln("error: path exeeds maximum of 512:", f.relpath)
|
|
os.exit(1)
|
|
}
|
|
|
|
offset_in_bytes := size_of(AssetIndex) * cast(u64)i
|
|
offset_pointer := mem.ptr_offset(
|
|
&bytes[0],
|
|
offset_in_bytes,
|
|
)
|
|
|
|
ai := cast(^AssetIndex)offset_pointer
|
|
copy(ai.relpath[:PATH_SIZE], f.relpath)
|
|
ai.size = cast(u64)f.size
|
|
ai.offset = data_offset
|
|
data_offset += ai.size
|
|
|
|
total_size += ai.size
|
|
}
|
|
|
|
header = Header {
|
|
magic_string = MAGIC_STRING,
|
|
version = VERSION,
|
|
compression = compression,
|
|
size_per_chunk = size_per_chunk,
|
|
total_size = total_size,
|
|
number_of_assets = number_of_assets,
|
|
}
|
|
|
|
assert(len(bytes) % size_of(AssetIndex) == 0) // clean multiple
|
|
return header, mem.slice_data_cast([]AssetIndex, bytes) // transmute slice with proper size
|
|
}
|