Add more tests and some impl improvements from their results
This commit is contained in:
+79
-52
@@ -7,7 +7,7 @@ import "core:strings"
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
file_exists :: proc(
|
||||
asset_exists :: proc(
|
||||
r: ^Reader,
|
||||
path: string,
|
||||
allocator := context.allocator,
|
||||
@@ -17,6 +17,13 @@ file_exists :: proc(
|
||||
error: Error,
|
||||
) {
|
||||
clean_path := os.clean_path(path, allocator) or_return
|
||||
|
||||
// Check filesystem first
|
||||
if os.exists(clean_path) {
|
||||
return true, max(u32), nil
|
||||
}
|
||||
|
||||
// Check chunk
|
||||
for i in 0 ..< r.header.number_of_assets {
|
||||
str := string(r.indices[i].relpath[:])
|
||||
relpath := strings.trim_right_null(str)
|
||||
@@ -27,7 +34,7 @@ file_exists :: proc(
|
||||
}
|
||||
|
||||
// Returning `[]u8` is owned by the caller.
|
||||
read_file :: proc(
|
||||
read_asset :: proc(
|
||||
r: ^Reader,
|
||||
path: string,
|
||||
allocator := context.allocator,
|
||||
@@ -37,8 +44,15 @@ read_file :: proc(
|
||||
) {
|
||||
clean_path := os.clean_path(path, allocator) or_return
|
||||
|
||||
found, i := asset_exists(r, clean_path) or_return
|
||||
|
||||
if !found {
|
||||
fmt.eprintln("asset: ", clean_path)
|
||||
return nil, .Asset_Not_Exist
|
||||
}
|
||||
|
||||
// Check filesystem first, so chunks can be overriden
|
||||
if os.exists(clean_path) {
|
||||
if i == max(u32) {
|
||||
// Open file
|
||||
file := os.open(clean_path, {.Read}) or_return
|
||||
defer os.close(file)
|
||||
@@ -51,56 +65,69 @@ read_file :: proc(
|
||||
return bytes, nil
|
||||
}
|
||||
|
||||
// Check chunk
|
||||
if found, i := file_exists(r, clean_path) or_return; found {
|
||||
output_path := os.name(r.output)
|
||||
entry := r.indices[i]
|
||||
// Otherwise, read from chunk
|
||||
return read_asset_from_chunk(r, i, allocator)
|
||||
}
|
||||
|
||||
// Find correct chunk
|
||||
chunk_index := entry.offset / r.header.size_per_chunk
|
||||
|
||||
// Find offset within this chunk
|
||||
chunk_offset := entry.offset % r.header.size_per_chunk
|
||||
|
||||
bytes = make([]u8, entry.size, allocator)
|
||||
n_left: u64
|
||||
n_read: u64
|
||||
|
||||
for entry.size > n_read {
|
||||
// Chunk path
|
||||
chunk_path := compute_chunk_path(
|
||||
output_path,
|
||||
cast(int)chunk_index,
|
||||
allocator,
|
||||
) or_return
|
||||
defer delete(chunk_path, allocator)
|
||||
|
||||
// Open chunk
|
||||
file := os.open(chunk_path, {.Read}) or_return
|
||||
defer os.close(file)
|
||||
|
||||
// Calculate how much of the current chunk should be read
|
||||
if entry.size > n_read + r.header.size_per_chunk - chunk_offset {
|
||||
n_left = r.header.size_per_chunk - chunk_offset
|
||||
} else {
|
||||
n_left = entry.size - n_read
|
||||
}
|
||||
|
||||
// Read
|
||||
n_read += cast(u64)os.read_at(
|
||||
file,
|
||||
bytes[n_read:n_read + n_left],
|
||||
cast(i64)chunk_offset,
|
||||
) or_return
|
||||
|
||||
// Overflow to next chunk
|
||||
chunk_index += 1
|
||||
chunk_offset = 0
|
||||
}
|
||||
|
||||
return bytes, nil
|
||||
// Returning `[]u8` is owned by the caller.
|
||||
read_asset_from_chunk :: proc(
|
||||
r: ^Reader,
|
||||
index: u32,
|
||||
allocator: runtime.Allocator,
|
||||
) -> (
|
||||
bytes: []u8,
|
||||
err: Error,
|
||||
) {
|
||||
if cast(u32)len(r.indices) < index {
|
||||
fmt.eprintf("asset[{}]\n", index)
|
||||
return nil, .Asset_Index_Out_Of_Bounds
|
||||
}
|
||||
|
||||
fmt.eprintln("asset: ", clean_path)
|
||||
return nil, .Asset_Not_Exist
|
||||
// Check chunk
|
||||
output_path := os.name(r.output)
|
||||
entry := r.indices[index]
|
||||
|
||||
// Find correct chunk
|
||||
chunk_index := entry.offset / r.header.size_per_chunk
|
||||
|
||||
// Find offset within this chunk
|
||||
chunk_offset := entry.offset % r.header.size_per_chunk
|
||||
|
||||
bytes = make([]u8, entry.size, allocator)
|
||||
n_left: u64
|
||||
n_read: u64
|
||||
|
||||
for entry.size > n_read {
|
||||
// Chunk path
|
||||
chunk_path := compute_chunk_path(
|
||||
output_path,
|
||||
cast(int)chunk_index,
|
||||
allocator,
|
||||
) or_return
|
||||
defer delete(chunk_path, allocator)
|
||||
|
||||
// Open chunk
|
||||
file := os.open(chunk_path, {.Read}) or_return
|
||||
defer os.close(file)
|
||||
|
||||
// Calculate how much of the current chunk should be read
|
||||
if entry.size > n_read + r.header.size_per_chunk - chunk_offset {
|
||||
n_left = r.header.size_per_chunk - chunk_offset
|
||||
} else {
|
||||
n_left = entry.size - n_read
|
||||
}
|
||||
|
||||
// Read
|
||||
n_read += cast(u64)os.read_at(
|
||||
file,
|
||||
bytes[n_read:n_read + n_left],
|
||||
cast(i64)chunk_offset,
|
||||
) or_return
|
||||
|
||||
// Overflow to next chunk
|
||||
chunk_index += 1
|
||||
chunk_offset = 0
|
||||
}
|
||||
|
||||
return bytes, nil
|
||||
}
|
||||
|
||||
+11
-9
@@ -12,20 +12,22 @@ Reader :: struct {
|
||||
}
|
||||
|
||||
Read_Error :: enum u8 {
|
||||
None = 0,
|
||||
File_Not_A_Chunk = 1,
|
||||
Asset_Not_Exist = 2,
|
||||
Unimplemented = 127,
|
||||
Okay = None,
|
||||
None = 0,
|
||||
File_Not_A_Chunk = 1,
|
||||
Asset_Not_Exist = 2,
|
||||
Asset_Index_Out_Of_Bounds = 3,
|
||||
Unimplemented = 127,
|
||||
Okay = None,
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
read_error_strings := #sparse[Read_Error]string { // enumerated array
|
||||
.None = "",
|
||||
.File_Not_A_Chunk = "file is not a chunk file",
|
||||
.Asset_Not_Exist = "asset does not exist",
|
||||
.Unimplemented = "feature is unimplemented",
|
||||
.None = "",
|
||||
.File_Not_A_Chunk = "file is not a chunk file",
|
||||
.Asset_Not_Exist = "asset does not exist",
|
||||
.Asset_Index_Out_Of_Bounds = "asset index out of bounds",
|
||||
.Unimplemented = "feature is unimplemented",
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
@@ -62,6 +62,11 @@ write_assets :: proc(
|
||||
|
||||
// ----------------------------------------
|
||||
|
||||
// We cant open non-existing assets
|
||||
if number_of_assets == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Open asset
|
||||
asset_stream, asset_size := open_asset(
|
||||
w,
|
||||
|
||||
@@ -42,10 +42,16 @@ write_header :: proc(
|
||||
size_per_chunk: u64 = SIZE_PER_CHUNK,
|
||||
compression: u16 = COMPRESSION,
|
||||
) -> Error {
|
||||
last_offset :=
|
||||
w.asset_table.asset_offsets[len(w.asset_table.asset_offsets) - 1]
|
||||
last_size := w.asset_table.asset_sizes[len(w.asset_table.asset_sizes) - 1]
|
||||
total_size := last_offset + last_size
|
||||
|
||||
// Get total_size
|
||||
total_size: u64 = 0
|
||||
offset_len := len(w.asset_table.asset_offsets)
|
||||
size_len := len(w.asset_table.asset_sizes)
|
||||
if offset_len > 0 && size_len > 0 {
|
||||
last_offset := w.asset_table.asset_offsets[offset_len - 1]
|
||||
last_size := w.asset_table.asset_sizes[size_len - 1]
|
||||
total_size = last_offset + last_size
|
||||
}
|
||||
|
||||
header := Header {
|
||||
magic_string = MAGIC_STRING,
|
||||
|
||||
Reference in New Issue
Block a user