diff --git a/src/file/chunks.odin b/src/file/chunks.odin index 0a98313..07935f8 100644 --- a/src/file/chunks.odin +++ b/src/file/chunks.odin @@ -29,25 +29,44 @@ AssetIndex :: struct #packed #all_or_none { offset: u64, } -Offsets :: struct { +AssetTable :: struct { asset_index_offset: u64, data_offset: u64, asset_offsets: [dynamic]u64, asset_sizes: [dynamic]u64, } -// ----------------------------------------- - -@(private) -offsets: Offsets +Writer :: struct { + chunk_file: ^os.File, + asset_file: ^os.File, + asset_table: AssetTable, +} // ----------------------------------------- -compute_metadata_offsets :: proc(number_of_assets: u64) { +writer_init :: proc( + number_of_assets: u64, + allocator := context.allocator, +) -> ( + w: Writer, + err: runtime.Allocator_Error, +) #optional_allocator_error { // [ Header ][ []Asset Index ][ Data ] - offsets.asset_index_offset = size_of(Header) - offsets.data_offset = + w.asset_table.asset_index_offset = size_of(Header) + w.asset_table.data_offset = size_of(Header) + (size_of(AssetIndex) * number_of_assets) + w.asset_table.asset_offsets = make([dynamic]u64, allocator) or_return + w.asset_table.asset_sizes = make([dynamic]u64, allocator) or_return + resize(&w.asset_table.asset_offsets, number_of_assets) + resize(&w.asset_table.asset_sizes, number_of_assets) + return w, nil +} + +writer_destroy :: proc(w: ^Writer) { + if w.chunk_file != nil do os.close(w.chunk_file) + if w.asset_file != nil do os.close(w.asset_file) + delete(w.asset_table.asset_offsets) + delete(w.asset_table.asset_sizes) } @(private) @@ -71,8 +90,3 @@ compute_chunk_path :: proc( return chunk_path // owning string } - -delete_offsets :: proc() { - delete(offsets.asset_offsets) - delete(offsets.asset_sizes) -} diff --git a/src/file/write_assets.odin b/src/file/write_assets.odin index 0c8b436..7d03a88 100644 --- a/src/file/write_assets.odin +++ b/src/file/write_assets.odin @@ -7,15 +7,8 @@ import "core:os" // ----------------------------------------- -@(private = "file") -chunk_file: ^os.File - -@(private = "file") -asset_file: ^os.File - -// ----------------------------------------- - write_assets :: proc( + w: ^Writer, output: ^os.File, entries: []FileEntry, size_per_chunk: u64 = SIZE_PER_CHUNK, @@ -27,15 +20,13 @@ write_assets :: proc( asset_index := 0 chunk_offset: u64 = 0 asset_offset: u64 = 0 - total_offset: u64 = offsets.data_offset + total_offset: u64 = w.asset_table.data_offset number_of_assets := len(entries) - resize(&offsets.asset_offsets, number_of_assets) - resize(&offsets.asset_sizes, number_of_assets) - if size_per_chunk < offsets.data_offset { + if size_per_chunk < w.asset_table.data_offset { fmt.eprintln( "error: chunk size too small to hold asset index:", - offsets.data_offset, + w.asset_table.data_offset, ) os.exit(1) } @@ -43,25 +34,25 @@ write_assets :: proc( // ---------------------------------------- // Create new chunk - chunk_stream := create_new_chunk(output_path, chunk_index, allocator) + chunk_stream := create_new_chunk(w, output_path, chunk_index, allocator) // Edge case of the chunk size being exactly the size of the data offset - if size_per_chunk == offsets.data_offset { + if size_per_chunk == w.asset_table.data_offset { chunk_index += 1 - chunk_stream = create_new_chunk(output_path, chunk_index, allocator) + chunk_stream = create_new_chunk(w, output_path, chunk_index, allocator) } // Chunk 0 starts after metadata if (chunk_index == 0) { - chunk_offset = offsets.data_offset + chunk_offset = w.asset_table.data_offset } // ---------------------------------------- // Open asset - asset_stream, asset_size := open_asset(entries[asset_index].relpath) - offsets.asset_offsets[asset_index] = total_offset - offsets.asset_sizes[asset_index] = asset_size + asset_stream, asset_size := open_asset(w, entries[asset_index].relpath) + w.asset_table.asset_offsets[asset_index] = total_offset + w.asset_table.asset_sizes[asset_index] = asset_size // ---------------------------------------- @@ -83,9 +74,12 @@ write_assets :: proc( asset_index += 1 asset_offset = 0 if asset_index == number_of_assets do break - asset_stream, asset_size = open_asset(entries[asset_index].relpath) - offsets.asset_offsets[asset_index] = total_offset - offsets.asset_sizes[asset_index] = asset_size + asset_stream, asset_size = open_asset( + w, + entries[asset_index].relpath, + ) + w.asset_table.asset_offsets[asset_index] = total_offset + w.asset_table.asset_sizes[asset_index] = asset_size } else if asset_remaining == chunk_remaining { @@ -97,14 +91,18 @@ write_assets :: proc( asset_index += 1 asset_offset = 0 if asset_index == number_of_assets do break - asset_stream, asset_size = open_asset(entries[asset_index].relpath) - offsets.asset_offsets[asset_index] = total_offset - offsets.asset_sizes[asset_index] = asset_size + asset_stream, asset_size = open_asset( + w, + entries[asset_index].relpath, + ) + w.asset_table.asset_offsets[asset_index] = total_offset + w.asset_table.asset_sizes[asset_index] = asset_size // Create new chunk chunk_index += 1 chunk_offset = 0 chunk_stream = create_new_chunk( + w, output_path, chunk_index, allocator, @@ -118,22 +116,18 @@ write_assets :: proc( chunk_index += 1 chunk_offset = 0 chunk_stream = create_new_chunk( + w, output_path, chunk_index, allocator, ) } } - - // ---------------------------------------- - - // Cleaup leftover - os.close(chunk_file) - os.close(asset_file) } @(private) create_new_chunk :: proc( + w: ^Writer, output_path: string, chunk_index: int, allocator: runtime.Allocator, @@ -149,24 +143,24 @@ create_new_chunk :: proc( } } - if chunk_file != nil do os.close(chunk_file) // close previous + if w.chunk_file != nil do os.close(w.chunk_file) // close previous // Create new chunk cf_err: os.Error - chunk_file, cf_err = os.create(chunk_path) + w.chunk_file, cf_err = os.create(chunk_path) if cf_err != nil { fmt.eprintln("error: create new chunk failed:", cf_err) os.exit(1) } - chunk_stream := os.to_stream(chunk_file) + chunk_stream := os.to_stream(w.chunk_file) return chunk_stream } @(private) -open_asset :: proc(path: string) -> (io.Stream, u64) { - if asset_file != nil do os.close(asset_file) // close previous +open_asset :: proc(w: ^Writer, path: string) -> (io.Stream, u64) { + if w.asset_file != nil do os.close(w.asset_file) // close previous // Open asset asset, open_err := os.open(path, {.Read}) diff --git a/src/file/write_metadata.odin b/src/file/write_metadata.odin index 849b10b..22c49a9 100644 --- a/src/file/write_metadata.odin +++ b/src/file/write_metadata.odin @@ -8,6 +8,7 @@ import "core:os" // ----------------------------------------- write_metadata :: proc( + w: ^Writer, output: ^os.File, entries: []FileEntry, size_per_chunk: u64 = SIZE_PER_CHUNK, @@ -28,20 +29,22 @@ write_metadata :: proc( } defer os.close(chunk_file) - write_header(chunk_file, number_of_assets, size_per_chunk, compression) + write_header(w, chunk_file, number_of_assets, size_per_chunk, compression) - write_asset_index(chunk_file, entries, number_of_assets, allocator) + write_asset_index(w, chunk_file, entries, number_of_assets, allocator) } @(private) write_header :: proc( + w: ^Writer, chunk_file: ^os.File, number_of_assets: u32, size_per_chunk: u64 = SIZE_PER_CHUNK, compression: u16 = COMPRESSION, ) { - last_offset := offsets.asset_offsets[len(offsets.asset_offsets) - 1] - last_size := offsets.asset_sizes[len(offsets.asset_sizes) - 1] + 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 header := Header { @@ -64,6 +67,7 @@ write_header :: proc( @(private) write_asset_index :: proc( + w: ^Writer, chunk_file: ^os.File, entries: []FileEntry, number_of_assets: u32, @@ -90,8 +94,8 @@ write_asset_index :: proc( ai := cast(^AssetIndex)offset_pointer copy(ai.relpath[:PATH_SIZE], f.relpath) - ai.size = offsets.asset_sizes[i] - ai.offset = offsets.asset_offsets[i] + ai.size = w.asset_table.asset_sizes[i] + ai.offset = w.asset_table.asset_offsets[i] } assert(len(index_bytes) % size_of(AssetIndex) == 0) // clean multiple @@ -100,7 +104,7 @@ write_asset_index :: proc( n, err := os.write_at( chunk_file, index_bytes, - cast(i64)offsets.asset_index_offset, + cast(i64)w.asset_table.asset_index_offset, ) if err != nil { fmt.eprintln("error: chunk write error:", err) diff --git a/src/main.odin b/src/main.odin index 5603f48..0e86cd1 100644 --- a/src/main.odin +++ b/src/main.odin @@ -20,8 +20,16 @@ main :: proc() { entries := file.list_dir_recursive(opts.input) defer file.delete_entries(&entries) - file.compute_metadata_offsets(cast(u64)len(entries)) - file.write_assets(opts.output, entries[:], opts.size, opts.compression) - file.write_metadata(opts.output, entries[:], opts.size, opts.compression) - file.delete_offsets() + w := file.writer_init(cast(u64)len(entries)) + defer file.writer_destroy(&w) + + file.write_assets(&w, opts.output, entries[:], opts.size, opts.compression) + + file.write_metadata( + &w, + opts.output, + entries[:], + opts.size, + opts.compression, + ) }