in reply to Re^2: Declaring Hash entries
in thread Declaring Hash entries

haha Re: Iteratively unpack structure from binary file ( ReadBytes, ReadFloat, ReadInt32 ), http://vitadevwiki.com/index.php?title=System_File_Object_%28SFO%29_%28PSF%29#Header_SFO

#!/usr/bin/perl -- use strict; use warnings; use Data::Dump qw/ dd /; Main( @ARGV ); exit( 0 ); sub ReadBytes { my( $fh, $bytes ) = @_; $bytes or Carp::croak 'Usage: ReadBytes( $filehandle, $bytes ) '; my $readed = read $fh, my($data) , $bytes; $readed == $bytes or Carp::carp "Only read($readed) but wanted($by +tes): $! ## $^E "; $data; } use constant CAN_PACK_QUADS => !! eval { my $f = pack 'q'; 1 }; sub Int8 { unpack 'c', $_[-1] } sub UInt8 { unpack 'C', $_[-1] } sub Int16 { unpack 's<', $_[-1] } sub UInt16 { unpack 'S<', $_[-1] } sub Int32 { unpack 'l<', $_[-1] } sub UInt32 { unpack 'L<', $_[-1] } sub Int64 { unpack( ( CAN_PACK_QUADS ? 'q<' : 'a8' ), $_[-1] ) } sub UInt64 { unpack( ( CAN_PACK_QUADS ? 'Q<' : 'a8' ), $_[-1] ) } sub ReadInt8 { Int8( ReadBytes( $_[-1], 8 /8 ) ); } sub ReadUInt8 { UInt8( ReadBytes( $_[-1], 8 /8 ) ); } sub ReadInt16 { Int16( ReadBytes( $_[-1], 16/8 ) ); } sub ReadUInt16 { UInt16( ReadBytes( $_[-1], 16/8 ) ); } sub ReadInt32 { Int32( ReadBytes( $_[-1], 32/8 ) ); } sub ReadUInt32 { UInt32( ReadBytes( $_[-1], 32/8 ) ); } sub ReadInt64 { Int64( ReadBytes( $_[-1], 64/8 ) ); } sub ReadUInt64 { UInt64( ReadBytes( $_[-1], 64/8 ) ); } sub Float { unpack 'f', $_[-1] } sub ReadFloat { Float( ReadBytes( $_[-1], 32/8 ) ); } #~ perlpacktut says #~ f A single-precision float in native format. #~ d A double-precision float in native format. #~ see perlport sub Double{ unpack 'd', $_[-1] } sub ReadDouble{ Float( ReadBytes( $_[-1], 32/8 ) ); } #~ sub Main { #~ my $file = shift; #~ use autodie qw/ open /; #~ open my($fh), '<:raw', $file; #~ seek $fh, 0x14, 0; #~ my %stuff; #~ $stuff{key_table_offset} = ReadBytes( $fh , 2); #~ #~ $stuff{key_table_offset} = ReadUInt16( $fh ); #~ dd( \%stuff ); #~ #~ } sub Main { for my $file ( @_ ){ Stuffing( $file ); } } sub Stuffing { my $file = shift; use autodie qw/ open /; open my( $fh ), '<:raw', $file; my %stuff; $stuff{header}{magic} = ReadBytes( $fh, 4 ); #~ $stuff{header}{version} = ReadInt64( $fh ); #~ $stuff{header}{key_table_start_offset} = ReadInt64( $fh ); #~ $stuff{header}{data_table_start_offset} = ReadInt64( $fh ); #~ $stuff{header}{number_entries} = ReadInt64( $fh ); $stuff{header}{version} = UInt32( ReadBytes( $fh, +4 ) ); $stuff{header}{key_table_start_offset} = UInt32( ReadBytes( $fh, +4 ) ); $stuff{header}{data_table_start_offset} = UInt32( ReadBytes( $fh, +4 ) ); $stuff{header}{number_entries} = UInt32( ReadBytes( $fh, +4 ) ); seek $fh, 0x14, 0; ## $stuff{index_table}{key_table_offset} = ReadUInt16( $fh ); $stuff{index_table}{param_fmt} = ReadUInt16( $fh ); #~ $stuff{index_table}{param_fmt} = ReadBytes( $fh, 2 ); $stuff{index_table}{param_format} = { 4 => 'utf-8-special', 516 => 'utf-8-charstring-nul', 1027 => 'uint32', }->{ $stuff{index_table}{param_fmt} }; #~ 04 00 Little Endian utf-8 Special Mode Used in contents + generated by the system (e.g.: save data) #~ 04 02 Little Endian utf-8 Character string, NULL finish +ed (0x00) #~ 04 04 Little Endian integer 32 bits unsigned #~ fail #~ perl -le " print pack qw/ L< /, $_ for qw/ 0400 0402 040 +4 /; " #~ fail #~ "\4\2", 516 #~ fail #~ perl -le" die pack 'H*', 516 " #~ #~ $ perl -le" binmode STDOUT; print qq/\4\0\4\2\4\4/ " |hexdump #~ 00000000: 04 00 04 02 04 04 0A - | + | #~ 00000007; #~ #~ { open my($fh), '<:raw', \qq/\4\0/; dd( ReadUInt16( $fh ) ); } + ## 4 #~ { open my($fh), '<:raw', \qq/\4\2/; dd( ReadUInt16( $fh ) ); } + ## 516 #~ { open my($fh), '<:raw', \qq/\4\4/; dd( ReadUInt16( $fh ) ); } + ## 1028 $stuff{index_table}{param_length} = ReadUInt32( $fh ); $stuff{index_table}{param_max_length} = ReadUInt32( $fh ); $stuff{index_table}{data_table_offset} = ReadUInt32( $fh ); #~ typedef struct{ #~ u16 keyOffset; //offset of keytable + keyOffset #~ u16 param_fmt; //enum (see below) #~ u32 paramLen; #~ u32 paramMaxLen; #~ u32 dataOffset; //offset of datatable + dataOffset #~ } indexTableEntry_t; dd( \%stuff ); } ## end sub Stuffing sub StuffingBytes { my $file = shift; use autodie qw/ open /; open my( $fh ), '<:raw', $file; my %stuff; $stuff{header}{magic} = ReadBytes( $fh, 4 ); $stuff{header}{version} = ReadBytes( $fh, 4 ); $stuff{header}{key_table_start_offset} = ReadBytes( $fh, 4 ); $stuff{header}{data_table_start_offset} = ReadBytes( $fh, 4 ); $stuff{header}{number_entries} = ReadBytes( $fh, 4 ); $stuff{index_table}{key_table_offset} = ReadBytes( $fh, 2 ); $stuff{index_table}{param_fmt} = ReadBytes( $fh, 2 ); $stuff{index_table}{param_length} = ReadBytes( $fh, 4 ); $stuff{index_table}{param_max_length} = ReadBytes( $fh, 4 ); $stuff{index_table}{data_table_offset} = ReadBytes( $fh, 4 ); dd( \%stuff ); } ## end sub StuffingBytes __END__ $ perl keytable.pl nonworking.file working.file { header => { data_table_start_offset => 684, key_table_start_offset => 404, magic => "\0PSF", number_entries => 24, version => 257, }, index_table => { data_table_offset => 0, key_table_offset => 0, param_fmt => 516, param_format => "utf-8-charstring-nul", param_length => 6, param_max_length => 8, }, } { header => { data_table_start_offset => 372, key_table_start_offset => 228, magic => "\0PSF", number_entries => 13, version => 257, }, index_table => { data_table_offset => 0, key_table_offset => 0, param_fmt => 516, param_format => "utf-8-charstring-nul", param_length => 6, param_max_length => 8, }, }

Replies are listed 'Best First'.
Re^4: Declaring Hash entries
by james28909 (Deacon) on Jan 05, 2015 at 04:44 UTC
    Very nice!
    but i was at psdevwiki param.sfo, but pretty much same format. In the header (which is 20 bytes long), has the values stored in which to parse the file. All i did was set it up the index table statically in the hash, then if you look, at offset 0x0C is the start of the key table. You can just read the key table 2 bytes at a time until it reaches 2 null characters. Then join all that data, then split on null characters. that will give you the parameters that are loaded in the file.

    Then sort it alphabetically, and compare with hash. then print results. I could also add formatting options into the hash as well, and just split it accordingly. Though i am unsure of how to test this code above, it def looks awesome!

      excitement ... Though i am unsure of how to test this code above, it def looks awesome!

      Why not?

      Its right there in __END__  perl keytable.pl nonworking.file working.file anyother.file

      My point like always is abstraction (sub sub sub), so that you can just read what you want following the docs of the format ... no copy/paste read statements when you can ReadBytes

        Yeah i did try that, but recieved an error message about expecting $bytes. But never the less, the code i posted works great and pretty quick for what i want to do :)

        Thanks for posting this tho, it will definitely show me a different approach to the same problem. Once i get back i will try to run the code above again to see why it wasnt working for me.

        Thanks! EDIT: Yes, just read bytes, the index table will tell you where each infos are inside the file, all i did was predeclare read lengths, and then i use 0x0C to go to the actual data, then use the predefined read lengths. I will work on this more soon and post a follow up code (which should be alot shorter that my original code).