#!perl -w # (C) 2003-2007 Willem Jan Hengeveld # Web: http://www.xs4all.nl/~itsme/ # http://wiki.xda-developers.com/ # # $Id$ # use strict; $|=1; use IO::File; use Getopt::Long; for my $fn (@ARGV) { print "--$fn\n" if (@ARGV>1); processfile($fn); } sub processfile { my ($fn)=@_; my $fh= IO::File->new($fn, "r") or die "$fn: $!"; binmode $fh; my $data; $fh->read($data, -s $fh); if ($data =~ /^BM/) { BMP::decode($data, 0); } elsif ($data =~ /^GIF/) { GIF::decode($data, 0); } elsif ($data =~ /^\xff\xd8/) { JPG::decode($data, 0); } elsif ($data =~ /^\x89PNG\x0d\x0a\x1a\x0a/s) { PNG::decode($data, 0); } elsif ($data =~ /^\x00\x00\x01\x00.\x00...\x00.\x00.\x00/) { ICO::decode($data, 0); } elsif ($data =~ /^\x00\x00\x02\x00.\x00...\x00.\x00.\x00/) { CUR::decode($data, 0); } else { printf("unknown image: hdr: %s\n", unpack("H32", $data)); } } sub decodestruct { my $ofs= $_[1]; my %struct; my @struct_fields= @{$_[4]}; my @struct_format= @{$_[5]}; if (0) { # for debugging formats die sprintf("fields=%d fmt=%d %s\n", scalar @struct_fields, scalar @struct_format, join(",", @struct_fields)) if (@struct_fields != @struct_format); die sprintf("fmt size=%d len=%d: %s\n", length(pack($_[3], 0..100)), $_[2], $_[3]) if (length(pack($_[3], 0..100)) != $_[2]); die sprintf("fmt fields=%d str=%d: %s\n", scalar unpack($_[3], "\x00" x $_[2]), scalar @struct_fields, $_[3]) if (scalar @{[unpack($_[3], "\x00" x $_[2])]} != @struct_fields); } my @struct_values= unpack($_[3], substr($_[0], $ofs, $_[2])); $struct{$struct_fields[$_]}=$struct_values[$_] for (0..$#struct_fields); printf("%-20s: $struct_format[$_]\n", $struct_fields[$_], $struct_values[$_]) for (0..$#struct_fields); return \%struct; } ################################################################################### package BMPInfo; sub decode { return main::decodestruct($_[0], $_[1], 40, "VVVvvVVVVVV", [qw(biSize biWidth biHeight biPlanes biBitCount biCompression biSizeImage biXPelsPerMeter biYPelsPerMeter biClrUsed biClrImportant)], [qw(0x%08x %5d %5d 0x%04x 0x%04x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x)]); } package BMPHdr; sub decode { return main::decodestruct($_[0], $_[1], 14, "vVvvV", [qw(bfType bfSize bfReserved1 bfReserved2 bfOffBits)], [qw(0x%04x 0x%08x 0x%04x 0x%04x 0x%08x)]); } package BMP; sub decode { my $ofs= $_[1]; my $hdr= BMPHdr::decode($_[0], $ofs); my $info= BMPInfo::decode($_[0], $ofs+14); return { hdr=>$hdr, info=>$info }; } ################################################################################### package ICOHdr; sub decode { return main::decodestruct($_[0], $_[1], 6, "vvv", [qw(idReserved idType idCount)], [qw(0x%04x 0x%04x 0x%04x)]); } package ICOEntry; sub decode { return main::decodestruct($_[0], $_[1], 16, "CCCCvvVV", [qw(bWidth bHeight bColorCount bReserved wPlanes wBitCount dwBytesInRes dwImageOffset)], [qw(%5d %5d 0x%02x 0x%02x 0x%04x 0x%04x 0x%08x 0x%08x)]); } package ICO; sub decode { my $hdr= ICOHdr::decode($_[0], $_[1]); my @entries= map { ICOEntry::decode($_[0], 6+16*$_) } (0..$hdr->{idCount}-1); my @icons= map { BMPInfo::decode($_[0], $entries[$_]{dwImageOffset}) } (0..$hdr->{idCount}-1); return { hdr=>$hdr, entries=>\@entries, icons=>\@icons }; } package CUR; sub decode { my $hdr= ICOHdr::decode($_[0], $_[1]); my @entries= map { ICOEntry::decode($_[0], 6+16*$_) } (0..$hdr->{idCount}-1); my @icons= map { BMPInfo::decode($_[0], $entries[$_]{dwImageOffset}) } (0..$hdr->{idCount}-1); return { hdr=>$hdr, entries=>\@entries, icons=>\@icons }; } ################################################################################### package GIFHdr; sub decode { my $hdr= main::decodestruct($_[0], $_[1], 13, "a3a3vvCCC", [qw(signature version width height packed backgroundColor aspectRatio)], [qw(%s %s %5d %5d 0x%02x 0x%02x 0x%02x)]); $hdr->{colortableEntrySize}= $hdr->{packed}&0x7; $hdr->{colortableSortFlag}= ($hdr->{packed}&0x8)>>3; $hdr->{colortableResolution}= ($hdr->{packed}&0x70)>>4; $hdr->{colortableFlag}= ($hdr->{packed}&0x80)>>7; return $hdr; } package GIF; sub decode { my $hdr= GIFHdr::decode($_[0], $_[1]); return { hdr=>$hdr }; } package JPG; our %markers; sub INIT { $markers{0xffe0}= { name=>'APP0', decoder=>sub { my ($magic, $version, $units, $xdensity, $ydensity, $xthumb, $ythumb, $rgb)= unpack("A5nCnnCCa*", $_[0]); printf("%-5s v0x%04x %s, density:(%d,%d) thumb:(%d,%d), rgb:%s\n", $magic, $version, $units==0?"pixel":$units==1?"inch":$units==2?"cm":$units, $xdensity, $ydensity, $xthumb, $ythumb, unpack("H*", $rgb)); } }; $markers{0xffc0}= { name=>'SOF0', decoder=>sub { my ($depth, $height, $width)= unpack("Cnn", $_[0]); printf("depth: %d\n", $depth); printf("width: %d\n", $width); printf("height: %d\n", $height); } }; }; sub decode { my $ofs= $_[1]; $ofs+=2; # skip 0xffd8 my @chunks; while ($ofs($content); } last if $type==0xffda; $ofs += $size+2; } } package PNG; sub decode { my $ofs= $_[1]+8; while ($ofs