#!/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,
},
}
|