Add header computation function

This commit is contained in:
Riyyi
2026-08-03 09:13:34 +02:00
parent 87d20f2ae5
commit 34f7b70039
5 changed files with 123 additions and 33 deletions
+2 -2
View File
@@ -7,8 +7,8 @@ import "core:strings"
Options :: struct {
verbose: bool `args:"name=verbose" usage:"Enable verbose output"`,
compression: u8 `args:"name=compression" usage:"Compression level, 0-12"`,
size: i64 `args:"name=size" usage:"Chunk size in bytes"`,
compression: u16 `args:"name=compression" usage:"Compression level, 0-12"`,
size: u64 `args:"name=size" usage:"Chunk size in bytes"`,
input: ^os.File `args:"name=input,file=r,required" usage:"Path to input directory"`,
output: ^os.File `args:"name=output,file=wc" usage:"Path to ouput directory"`,
// overflow: [dynamic]string,
+89
View File
@@ -0,0 +1,89 @@
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
}
+7 -10
View File
@@ -7,7 +7,7 @@ import "core:strings"
// -----------------------------------------
DirectoryEntry :: struct #all_or_none {
FileEntry :: struct #all_or_none {
relpath: string, // NOTE: owning string
size: i64,
}
@@ -18,7 +18,7 @@ DirectoryEntry :: struct #all_or_none {
list_dir_recursive :: proc(
f: ^os.File,
allocator := context.allocator,
) -> [dynamic]DirectoryEntry {
) -> [dynamic]FileEntry {
path := os.name(f)
return list_dir_recursive_by_path_impl(path, allocator)
}
@@ -27,7 +27,7 @@ list_dir_recursive :: proc(
list_dir_recursive_by_path :: proc(
path: string,
allocator := context.allocator,
) -> [dynamic]DirectoryEntry {
) -> [dynamic]FileEntry {
return list_dir_recursive_by_path_impl(path, allocator)
}
@@ -35,13 +35,13 @@ list_dir_recursive_by_path :: proc(
list_dir_recursive_by_path_impl :: proc(
path: string,
allocator: runtime.Allocator,
) -> [dynamic]DirectoryEntry {
) -> [dynamic]FileEntry {
if !os.is_dir(path) {
fmt.eprintln("error: path is not a directory:", path)
os.exit(1)
}
result := make([dynamic]DirectoryEntry, allocator)
result := make([dynamic]FileEntry, allocator)
queue := make([dynamic]string, 0, 1, allocator) // reserve 1 slot
defer delete(queue) // dynamic array embeds allocator
@@ -57,7 +57,7 @@ list_dir_recursive_by_path_impl :: proc(
@(private)
list_dir_queue :: proc(
queue: ^[dynamic]string,
result: ^[dynamic]DirectoryEntry,
result: ^[dynamic]FileEntry,
working_dir: string,
allocator: runtime.Allocator,
) {
@@ -99,10 +99,7 @@ list_dir_queue :: proc(
if !was_allocation {
relpath = strings.clone(relpath, result^.allocator)
}
append(
result,
DirectoryEntry{relpath = relpath, size = entry.size},
)
append(result, FileEntry{relpath = relpath, size = entry.size})
}
case: // skip other types
}
+4
View File
@@ -24,4 +24,8 @@ main :: proc() {
entries := file.list_dir_recursive_by_path("./src")
fmt.println("entries:", entries)
header, asset_index_array := file.compute_header(entries)
fmt.println("header:", header)
fmt.println("aia:", asset_index_array)
}