@@ -2,7 +2,7 @@ use std::{
22 collections:: HashMap ,
33 fs:: File ,
44 io:: { BufRead , BufReader , BufWriter , Read , Write } ,
5- path:: Path ,
5+ path:: { Path , PathBuf } ,
66} ;
77
88use countio:: Counter ;
@@ -74,6 +74,27 @@ pub struct AssetBundleHeader {
7474 level_ends : Vec < LevelEnds > ,
7575 bundle_size : u32 ,
7676}
77+ impl std:: fmt:: Display for AssetBundleHeader {
78+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
79+ writeln ! ( f, "Signature: {}" , self . signature) ?;
80+ writeln ! ( f, "Stream version: {}" , self . stream_version) ?;
81+ writeln ! ( f, "Player version: {}" , self . player_version) ?;
82+ writeln ! ( f, "Engine version: {}" , self . engine_version) ?;
83+ writeln ! ( f, "Min streamed bytes: {}" , self . min_streamed_bytes) ?;
84+ writeln ! ( f, "Header size: {}" , self . header_size) ?;
85+ writeln ! ( f, "Number of levels: {}" , self . num_levels) ?;
86+ writeln ! ( f, "Min levels for load: {}" , self . min_levels_for_load) ?;
87+ writeln ! ( f, "Level ends:" ) ?;
88+ for ( i, level) in self . level_ends . iter ( ) . enumerate ( ) {
89+ writeln ! (
90+ f,
91+ " Level {}: compressed @ {}, uncompressed @ {}" ,
92+ i, level. compressed_end, level. uncompressed_end
93+ ) ?;
94+ }
95+ write ! ( f, "Bundle size: {}" , self . bundle_size)
96+ }
97+ }
7798impl AssetBundleHeader {
7899 fn new ( level_ends : Vec < LevelEnds > ) -> Self {
79100 let num_levels = level_ends. len ( ) as u32 ;
@@ -253,15 +274,47 @@ impl LevelHeader {
253274struct LevelFile {
254275 name : String ,
255276 data : Vec < u8 > ,
277+ hash : Option < String > ,
256278}
257279impl std:: fmt:: Debug for LevelFile {
258280 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
259281 f. debug_struct ( "LevelFile" )
260282 . field ( "name" , & self . name )
261283 . field ( "data" , & format_args ! ( "{} bytes" , self . data. len( ) ) )
284+ . field ( "hash" , & self . hash )
262285 . finish ( )
263286 }
264287}
288+ impl std:: fmt:: Display for LevelFile {
289+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
290+ match self . hash . as_ref ( ) {
291+ Some ( hash) => write ! (
292+ f,
293+ "{} - {} ({} bytes) - {}" ,
294+ self . name,
295+ util:: bytes_to_human_readable( self . data. len( ) as u64 ) ,
296+ self . data. len( ) ,
297+ hash
298+ ) ,
299+ None => write ! (
300+ f,
301+ "{} - {} ({} bytes)" ,
302+ self . name,
303+ util:: bytes_to_human_readable( self . data. len( ) as u64 ) ,
304+ self . data. len( )
305+ ) ,
306+ }
307+ }
308+ }
309+ impl LevelFile {
310+ fn new ( name : String , data : Vec < u8 > ) -> Self {
311+ Self {
312+ name,
313+ data,
314+ hash : None ,
315+ }
316+ }
317+ }
265318
266319#[ derive( Debug ) ]
267320struct Level {
@@ -278,10 +331,7 @@ impl Level {
278331 skip_exact ( & mut reader, file. offset as usize - offset) ?;
279332 let mut data = vec ! [ 0 ; file. size as usize ] ;
280333 reader. read_exact ( & mut data) ?;
281- files. push ( LevelFile {
282- name : file. name ,
283- data,
284- } ) ;
334+ files. push ( LevelFile :: new ( file. name , data) ) ;
285335 }
286336 Ok ( Self { files } )
287337 }
@@ -345,8 +395,23 @@ impl Level {
345395pub struct AssetBundle {
346396 levels : Vec < Level > ,
347397}
398+ impl std:: fmt:: Display for AssetBundle {
399+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
400+ for ( i, level) in self . levels . iter ( ) . enumerate ( ) {
401+ writeln ! ( f, "Level {}" , i) ?;
402+ for file in & level. files {
403+ writeln ! ( f, " {}" , file) ?;
404+ }
405+ write ! ( f, "End" ) ?;
406+ }
407+ Ok ( ( ) )
408+ }
409+ }
348410impl AssetBundle {
349- fn read < R : Read + BufRead > ( reader : & mut R , expected_size : u32 ) -> Result < Self , Error > {
411+ fn read < R : Read + BufRead > (
412+ reader : & mut R ,
413+ expected_size : u32 ,
414+ ) -> Result < ( AssetBundleHeader , Self ) , Error > {
350415 let mut reader = Counter :: new ( reader) ;
351416
352417 let header = AssetBundleHeader :: read ( & mut reader) ?;
@@ -374,7 +439,7 @@ impl AssetBundle {
374439 }
375440 }
376441
377- Ok ( Self { levels } )
442+ Ok ( ( header , Self { levels } ) )
378443 }
379444
380445 fn write < W : Write > ( & self , writer : & mut W , compression : u32 ) -> Result < ( ) , Error > {
@@ -399,7 +464,27 @@ impl AssetBundle {
399464 Ok ( ( ) )
400465 }
401466
402- pub fn from_file ( path : & str ) -> Result < Self , String > {
467+ fn get_level_files_from_dir ( dir_path : & Path ) -> Result < Vec < LevelFile > , Error > {
468+ let mut files = Vec :: new ( ) ;
469+ for entry in std:: fs:: read_dir ( dir_path) ? {
470+ let Ok ( entry) = entry else {
471+ continue ;
472+ } ;
473+ let path = entry. path ( ) ;
474+ if path. is_file ( ) {
475+ let Some ( name) = path. file_name ( ) . unwrap ( ) . to_str ( ) else {
476+ continue ;
477+ } ;
478+ let Ok ( data) = std:: fs:: read ( & path) else {
479+ continue ;
480+ } ;
481+ files. push ( LevelFile :: new ( name. to_string ( ) , data) ) ;
482+ }
483+ }
484+ Ok ( files)
485+ }
486+
487+ pub fn from_file ( path : & str ) -> Result < ( AssetBundleHeader , Self ) , String > {
403488 let file = File :: open ( path) . map_err ( |e| format ! ( "Couldn't open file {}: {}" , path, e) ) ?;
404489 let metadata = file. metadata ( ) . unwrap ( ) ;
405490 let mut reader = BufReader :: new ( file) ;
@@ -419,24 +504,6 @@ impl AssetBundle {
419504 Ok ( ( ) )
420505 }
421506
422- pub fn get_uncompressed_info ( & self , level : usize ) -> Result < HashMap < String , FileInfo > , Error > {
423- let mut result = HashMap :: new ( ) ;
424- if level >= self . levels . len ( ) {
425- return Err ( format ! ( "Level {} does not exist" , level) . into ( ) ) ;
426- }
427-
428- for file in & self . levels [ level] . files {
429- let hash = util:: get_buffer_hash ( & file. data ) ;
430- let info = FileInfo {
431- hash,
432- size : file. data . len ( ) as u64 ,
433- } ;
434- result. insert ( file. name . clone ( ) , info) ;
435- }
436-
437- Ok ( result)
438- }
439-
440507 pub fn extract_files ( & self , output_dir : & str ) -> Result < ( ) , String > {
441508 let make_subdirs = self . levels . len ( ) > 1 ;
442509 for ( i, level) in self . levels . iter ( ) . enumerate ( ) {
@@ -458,4 +525,32 @@ impl AssetBundle {
458525 }
459526 Ok ( ( ) )
460527 }
528+
529+ pub fn recalculate_all_hashes ( & mut self ) {
530+ for level in & mut self . levels {
531+ for file in & mut level. files {
532+ file. hash = Some ( util:: get_buffer_hash ( & file. data ) ) ;
533+ }
534+ }
535+ }
536+
537+ pub fn get_uncompressed_info ( & self , level : usize ) -> Result < HashMap < String , FileInfo > , Error > {
538+ let mut result = HashMap :: new ( ) ;
539+ if level >= self . levels . len ( ) {
540+ return Err ( format ! ( "Level {} does not exist" , level) . into ( ) ) ;
541+ }
542+
543+ for file in & self . levels [ level] . files {
544+ let info = FileInfo {
545+ hash : file
546+ . hash
547+ . clone ( )
548+ . unwrap_or_else ( || util:: get_buffer_hash ( & file. data ) ) ,
549+ size : file. data . len ( ) as u64 ,
550+ } ;
551+ result. insert ( file. name . clone ( ) , info) ;
552+ }
553+
554+ Ok ( result)
555+ }
461556}
0 commit comments