I have now decided to implement a (maybe temporary) solution, and it isn't that hard or kludgy as I thought :
sub RecSize {
# Returns the length of the data required by a string for unpack()
# Variable length (with "*") will result in an error
# Platform specific stuff like "i" and "I" also result in an error
my( $Data ) = @_;
my( $Result, $Len, $Repeat ) = 0;
my %Size = (
"a"=>1, # A string with arbitrary binary data, will be n
+ull padded.
"A"=>1, # An ascii string, will be space padded.
"b"=>1, # A bit string (ascending bit order, like vec())
+.
"B"=>1, # A bit string (descending bit order).
"h"=>1, # A hex string (low nybble first).
"H"=>1, # A hex string (high nybble first).
"c"=>1, # A signed char value.
"C"=>1, # An unsigned char value.
"s"=>2, # A signed short value.
"S"=>2, # An unsigned short value.
"n"=>2, # A short in "network" (big-endian) order.
"N"=>4, # A long in "network" (big-endian) order.
"l"=>4, # A signed long value.
"L"=>4, # An unsigned long value.
"v"=>2, # A short in "VAX" (little-endian) order.
"V"=>4, # A long in "VAX" (little-endian) order.
"q"=>8, # A signed quad (64-bit) value.
"Q"=>8, # An unsigned quad value.
"x"=>1, # A null byte.
"Z"=>1, # A zero terminated string (will need byte count
+ !)
);
while ( $Data =~ s/([aAbBhHcCsSlLnNvVqQxZ])(\d*)// ) {
$Repeat = $2 || 1;
$Len = $Size{$1};
if ($Len) {
$Result += $Len * $Repeat;
} else {
$Result = undef;
last;
};
};
return $Result;
};
sub decodeRecord {
my ($Value, $Records, @Names) = @_;
my (@Values) = unpack( $Records, $Value );
my (%Result);
foreach my $Name (@Names) {
$Result{$Name} = $Values[0] if ($Name);
shift @Values;
};
return \%Result;
};
This code is then used as follows :
$strMacBinaryHeader = "CZ64A4A4AAvvvaaNNVVvaA4A8VVaaN";
@nameMacBinaryHeader = (
"ID", "filename", "filetype", "filecreator", "fileflags",
undef, "yoffs", "xoffs", "fileid", "fileflags2", undef,
"dataforklength", "resourceforklength", "creationdate",
"lastmodified", "infolength", "fileflags3", "macbinary3id",
undef, "totalunpackedlength", "secondaryheaderlength",
"macbinary3requiredversion", "CRC"
);sub decodeMacBinaryHeader {
my ($Buffer) = @_;
my $Result = &decodeRecord($Buffer, $strMacBinaryHeader, @nameMacBin
+aryHeader );
roundUp( \$Result->{dataforklength}, 128 );
return $Result;
};
$HeaderSize = &RecSize($strMacBinaryHeader);
$Filename = shift || "../macicon/test/icon";
open FILE, "< $Filename" or die "Error opening \"$Filename\" : $!\n";
binmode FILE;
read FILE, $MacBinHeader, $HeaderSize;
$Header = decodeMacBinaryHeader($MacBinHeader);
$ResourceForkStart = $HeaderSize
+ $Header->{secondaryheaderlength}
+ $Header->{dataforklength};
&dump( $Header );
where &dump() is a simple routine that dumps a hash... |