package SWF::Parser; use strict; use Carp; use SWF; use vars qw(@ISA $VERSION); @ISA = qw(SWF); $VERSION = .1; my $debug = 0; sub new { # Usage: my $swf = SWF::Parser->new($infile); # my $swf = SWF::Parser->new(\*FILEHANDLE); # my $swf = SWF::Parser->new($swfstring); my $class = shift; $class = ref($class) || $class; my $input = shift || return; my $flag = shift || ""; my $self = $class->SUPER::new(); $debug = 1 if ($flag eq 'debug'); print " SWF::Parser - Debug mode on.\n" if $debug; # Initialize the SWF object content $self->{'content'} = SWF::Readable->new->init; my $content; if (ref $input eq "GLOB") { # passed a filehandle for input - read whole file in print " Reading from filehandle:\n\n" if $debug; local $/ = undef; $content = <$input>; } elsif (-f $input) { # we think they passed us a file - try to open and read it print " Reading from file \"$input\":\n\n" if $debug; local *INFILE; open (INFILE, $input) || die "SWF::Parser - can't open $input: $!"; { local $/ = undef; $content = ; } } else { # we're assuming the string passed is the contents of a SWF print " Reading from string:\n\n" if $debug; $content = $input; } $self->{'content'}->content($content); # Initialize handler lookup $self->{'_handlers'} = {}; for my $tag (SWF::validTags) { $self->{'_handlers'}->{$tag} = eval("\\\&p$tag"); } return $self; } sub parse { # Usage: $swf->parse; # This is the bit that takes the actual SWF and digests it into # a nice, easy-to-use data structure. my $self = shift; # go to the beginning of content and clear stuff out $self->{'content'}->seek; $self->_tagList([]); # process the header &{$self->{'_handlers'}->{'Header'}}($self); # start reading in the tags my $frameNum = 0; # current frame number my $movieP = 1; # true while processing movie while ($movieP) { my $frameP = 1; # true while we process the frame print "\n Reading frame $frameNum:\n" if $debug; while ($frameP) { # read in the tag and get some useful info my $tag = SWF::Tag->new; $tag->read($self->content); $tag->frame($frameNum); my $tagnum = $tag->tagID; my $taglen = $tag->length; my $taglabel = SWF::tagName($tagnum); print " $tagnum: \t$taglabel\n" if $debug; print " $taglen bytes\n" if ($debug && $taglen); # process the tag - first, do mandatory stuff for control tags if ($tagnum == 1) { # ShowFrame - go to next frame $frameP = 0; } elsif ($tagnum == 0) { # End - last tag - end of movie $frameP = 0; $movieP = 0; } elsif ($tagnum == 43) { # FrameLabel - add a label to frame my $label = $tag->{'SWF::Tag::content'}->readString; $tag->{'Name'} = $label; $self->addLabel($label, $frameNum); } elsif ($tagnum == 24) { # Protect $self->protect(1); } # now, process according to handlers $tag = &{$self->{'_handlers'}->{$taglabel}}($tag); # after processing, add tag to {'_tagList'} $self->appendTag($tag) || die "Bad tag in frame $frameNum: $tagnum - $taglabel"; } $frameNum++; } print "\nDone parsing.\n\n" if $debug; } sub listTags { # for debugging only. my $self = shift; my $taglist = $self->_tagList; for my $tag (@$taglist) { my $tagnum = $tag->tagID; my $taglen = $tag->length; my $taglabel = SWF::tagName($tagnum); my $tagframe = $tag->frame; print "Frame $tagframe:\t$taglabel - $taglen bytes\n"; } } sub setHandlers { # Usage: $swf->setHandlers("tag1" => \&tag1handler, # "tag2" => \&tag2handler...) # # This allows the user to set custom handlers that are executed # during the parsing process instead of (*not* in addition to # the default handlers. my ($self, @handler_pairs) = @_; die ("Uneven number of arguments to setHandlers method") if (int(@handler_pairs) & 1); my @ret; while (@handler_pairs) { my $type = shift @handler_pairs; my $handler = shift @handler_pairs; if (ref $handler ne "CODE") { die("Handler for $type must be coderef!"); } unless (defined SWF::tagNum($type)) { my @types = SWF::validTags; die("Unknown Parser handler type: $type\n Valid types: @types"); } $self->{'_handlers'}->{$type} = $handler; } } # # Start defining tag handlers # # # So, I've decided I've been doing this all wrong - it is morally evil # to access or set instance data by directly accessing the object hash. # However, each tag type needs different types of data, and there is no # way of knowing which types we'll need beforehand. So, there are three # solutions to this: 1) add ALL data type getter/setters to the tag # class, and only use the ones we need. 2) use a base 'tag' class, and # create a subclass for each type of tag with the proper data methods. # 1) and 2) are, for various reasons, unacceptable to me. So, when I # get some time, I'll do 3) add a method to the 'tag' class which allows # the user to dynamically create new methods. something like: # $tag->addMethods('ShapeId', 'BoundRect', 'ColorTransform', ...) # I think I like that. Yeah, I'll do it. Later. # sub pHeader { my $self = shift; # read and verify SWF signature #use Data::Dumper; #print "CONTENT:\n". Dumper $self->{'content'}; my $signature = $self->{'content'}->readBytes(3) || die "SWF::Parser ERROR -signature too short"; if ($signature ne "FWS" and $signature ne "CWS") { die "SWF::Parser ERROR - bad signature: $signature"; } print " Signature: $signature\n" if $debug; # read version my $version = $self->{'content'}->readBytes(1) || die "no version number"; print "VERS: $version\n"; $version = ord($version); $self->version($version); print " SWF Version $version\n" if $debug; # read and verify file length my $fileLength = $self->{'content'}->readBytes(4) || die "file length too short"; $fileLength = unpack("L",$fileLength); if ($fileLength != $self->content->rlength) { die "SWF::Parser ERROR - file length $fileLength not correct"; } $self->fileLength($fileLength); print " FileLength: $fileLength bytes\n" if $debug; # read rect for frame size my $frameSize = SWF::Rect->new; $frameSize->read($self->content) || die "can't read rect for frame size"; $self->frameSize($frameSize); print " FrameSize: " if $debug; $frameSize->debug if $debug; # read numbers for frame rate my $FR_aft = ord($self->{'content'}->readBytes(1)); my $FR_fore = ord($self->{'content'}->readBytes(1)); my $frameRate = "$FR_fore\.$FR_aft"; $self->frameRate($frameRate); print " FrameRate: $frameRate FPS\n" if $debug; # read number of frames my $frameCount = unpack("S",$self->{'content'}->readBytes(2)); $self->frameCount($frameCount); print " FrameCount: $frameCount\n" if $debug; } sub pEnd { # End tag - no action necessary my $tag = shift; return $tag; } sub pShowFrame { # Show Frame - no action necessary my $tag = shift; return $tag; } sub pDefineShape { my $tag = shift; my $shapeID = unpack("S",$tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'ShapeId'} = $shapeID; print " ShapeID: $shapeID\n" if $debug; my $shapeBounds = SWF::Rect->new->read($tag->content); $tag->{'ShapeBounds'} = $shapeBounds; print " ShapeBounds: " if $debug; $shapeBounds->debug if $debug; my $shape = SWF::ShapeWithStyle->new; $shape->ShapeType(1); $shape->read($tag->{'content'}); $tag->{'Shapes'} = $shape; return $tag; } sub pFreeCharacter { # Free Character - I can't find ANY documentation on this tag. my $tag = shift; print "Free Character? What is this?\n" if $debug; return $tag; } sub pPlaceObject { my $tag = shift; my $charID = unpack("S", $tag->{'content'}->readBytes(2)); $tag->{'CharacterID'} = $charID; print " CharID: $charID\n" if $debug; my $depth = unpack("S", $tag->{'content'}->readBytes(2)); $tag->{'Depth'} = $depth; print " Depth: $depth\n" if $debug; my $matrix = SWF::Matrix->new->read($tag->content); $tag->{'Matrix'} = $matrix; $matrix->debug if $debug; if (my $cxform = SWF::CXform->new->read($tag->content)) { $tag->{'ColorTransform'} = $cxform; $cxform->debug if $debug; } return $tag; } sub pRemoveObject { my $tag = shift; my $charID = unpack("S", $tag->{'content'}->readBytes(2)); $tag->{'CharacterID'} = $charID; print " CharID: $charID\n" if $debug; my $depth = unpack("S", $tag->{'content'}->readBytes(2)); $tag->{'Depth'} = $depth; print " Depth: $depth\n" if $debug; return $tag; } sub pDefineBits { my $tag = shift; my $bitmapID = unpack("S", $tag->{'content'}->readBytes(2)); $tag->{'BitmapId'} = $bitmapID; my ($byte, $jpeg); while ($byte = unpack("C", $tag->{'content'}->readBytes(1))) { $jpeg .= $byte; } $tag->{'BitmapJPEGImage'} = $jpeg; return $tag; } sub pDefineButton { my $tag = shift; # this is a little wonky, because I have to check for end of # buttonrecord and actionrecord bytes before I can read them. # luckily, my readable seek and tell methods should do for this. my $buttonID = unpack("S", $tag->{'content'}->readBytes(2)); $tag->{'ButtonId'} = $buttonID; my @buttons = (); my $readBR = 1; while ($readBR) { my $pos = $tag->{'content'}->tell; my $flag = ord($tag->{'content'}->readBytes(1)); if ($flag == 0) { $readBR = 0; } else { $tag->{'content'}->seek($pos-1); my $buttonrecord = SWF::ButtonRecord->new->read($tag->content); push @buttons, $buttonrecord; } } my @actions = (); my $readAR = 1; while ($readAR) { my $pos = $tag->{'content'}->tell; my $flag = ord($tag->{'content'}->readBytes(1)); if ($flag == 0) { $readAR = 0; } else { $tag->{'content'}->seek($pos-1); my $actionrecord = SWF::ActionRecord->new->read($tag->content); push @actions, $actionrecord; } } $tag->{'Buttons'} = \@buttons; $tag->{'Actions'} = \@actions; return $tag; } sub pJPEGTables { my $tag = shift; return $tag; } sub pSetBackgroundColor { # Set Background Color - parse and display RGB my $tag = shift; my $RGB = SWF::RGB->new->read($tag->content); $tag->{'BackgroundColor'} = $RGB; $RGB->debug if $debug; return $tag; } sub pDefineFont { my $tag = shift; my $fontid = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'FontId'} = $fontid; my @offsets; my @shapes; $offsets[0] = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); my $numElem = $offsets[0] / 2; my $i = 1; while ($i < $numElem) { $offsets[$i] = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $i++; } $i = 0; while ($i < $numElem) { $shapes[$i] = SWF::Shape->new->read($tag->content); $i++; } $tag->{'OffsetTable'} = \@offsets; $tag->{'ShapeTable'} = \@shapes; return $tag; } sub pDefineText { my $tag = shift; my $textid = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); my $bounds = SWF::Rect->new->read($tag->content); my $matrix = SWF::Matrix->new->read($tag->content); my $glyphbits = ord($tag->{'SWF::Tag::content'}->readBytes(1)); my $advancebits = ord($tag->{'SWF::Tag::content'}->readBytes(1)); $tag->{'TextId'} = $textid; $tag->{'TextBounds'} = $bounds; $tag->{'TextMatrix'} = $matrix; $tag->{'TextGlyphBits'} = $glyphbits; $tag->{'TextAdvanceBits'} = $advancebits; my @records = (); my $readrec = 1; while ($readrec) { my $pos = $tag->{'SWF::Tag::content'}->tell; my $flag = ord($tag->{'SWF::Tag::content'}->readBytes(1)); if ($flag == 0) { $readrec = 0; } else { $tag->{'SWF::Tag::content'}->seek($pos-1); my $textrecord = SWF::TextRecord->new; $textrecord->GlyphBits($glyphbits); $textrecord->advancebits($advancebits); $textrecord->read($tag->content); push @records, $textrecord; } } $tag->{'TextRecords'} = \@records; return $tag; } sub pDoAction { my $tag = shift; my @actions = (); my $readAR = 1; while ($readAR) { my $pos = $tag->{'SWF::Tag::content'}->tell; my $flag = ord($tag->{'SWF::Tag::content'}->readBytes(1)); # if ($flag == 0) { $readAR = 0; # } # else { # $tag->{'SWF::Tag::content'}->seek($pos-1); # my $actionrecord = SWF::ActionRecord->new->read($tag->content); # push @actions, $actionrecord; # } } $tag->{'Actions'} = \@actions; return $tag; } sub pDefineFontInfo { my $tag = shift; my $fontid = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); my $namelen = ord($tag->{'SWF::Tag::content'}->readBytes(1)); my $name = $tag->{'SWF::Tag::content'}->readBytes($namelen); my $flagsReserved = $tag->{'SWF::Tag::content'}->readBits(2); my $flagsUnicode = $tag->{'SWF::Tag::content'}->readBits(1); my $flagsShiftJIS = $tag->{'SWF::Tag::content'}->readBits(1); my $flagsANSI = $tag->{'SWF::Tag::content'}->readBits(1); my $flagsItalic = $tag->{'SWF::Tag::content'}->readBits(1); my $flagsBold = $tag->{'SWF::Tag::content'}->readBits(1); my $flagsWideCodes = $tag->{'SWF::Tag::content'}->readBits(1); $tag->{'FontId'} = $fontid; $tag->{'FontNameLen'} = $namelen; $tag->{'FontName'} = $name; $tag->{'FontFlagsReserved'} = $flagsReserved; $tag->{'FontFlagsUnicode'} = $flagsUnicode; $tag->{'FontFlagsShiftJIS'} = $flagsShiftJIS; $tag->{'FontFlagsANSI'} = $flagsANSI; $tag->{'FontFlagsItalic'} = $flagsItalic; $tag->{'FontFlagsBold'} = $flagsBold; $tag->{'FontFlagsWideCodes'} = $flagsWideCodes; my $codetable; if ($flagsWideCodes) { $codetable = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); } else { $codetable = ord($tag->{'SWF::Tag::content'}->readBytes(1)); } $tag->CodeTable($codetable); return $tag; } sub pDefineSound { my $tag = shift; my $soundID = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'SoundId'} = $soundID; my $soundformat = SWF::_bits2int($tag->{'SWF::Tag::content'}->readBits(4)); $tag->{'SoundFormat'} = $soundformat; my $soundrate = SWF::_bits2int($tag->{'SWF::Tag::content'}->readBits(2)); $tag->{'SoundRate'} = $soundrate; my $soundsize = $tag->{'SWF::Tag::content'}->readBits(1); $tag->{'SoundSize'} = $soundsize; my $soundtype = $tag->{'SWF::Tag::content'}->readBits(1); $tag->{'SoundType'} = $soundtype; my $samplecount = unpack("L", $tag->{'SWF::Tag::content'}->readBytes(4)); $tag->{'SoundSampleCount'} = $samplecount; my $sounddata = $tag->{'SWF::Tag::content'}->readBytes($tag->{'SWF::Tag::content'}->length); $tag->{'SoundData'} = $sounddata; return $tag; } sub pStartSound { my $tag = shift; my $soundID = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'SoundId'} = $soundID; my $soundInfo = SWF::SoundInfo->new->read($tag->{'SWF::Tag::content'}); $tag->{'SOUNDINFO'} = $soundInfo; return $tag; } sub pDefineButtonSound { my $tag = shift; my $buttonID = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'ButtonId'} = $buttonID; my $buttonSC0 = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'ButtonSoundChar0'} = $buttonSC0; my $buttonSI0 = SWF::SoundInfo->new->read($tag->content); $tag->{'ButtonSoundInfo0'} = $buttonSI0; my $buttonSC1 = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'ButtonSoundChar1'} = $buttonSC1; my $buttonSI1 = SWF::SoundInfo->new->read($tag->content); $tag->{'ButtonSoundInfo1'} = $buttonSI1; my $buttonSC2 = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'ButtonSoundChar2'} = $buttonSC2; my $buttonSI2 = SWF::SoundInfo->new->read($tag->content); $tag->{'ButtonSoundInfo2'} = $buttonSI2; my $buttonSC3 = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'ButtonSoundChar3'} = $buttonSC3; my $buttonSI3 = SWF::SoundInfo->new->read($tag->content); $tag->{'ButtonSoundInfo3'} = $buttonSI3; return $tag; } sub pSoundStreamHead { my $tag = shift; my $reserved = $tag->{'SWF::Tag::content'}->readBits(4); my $pbRate = SWF::_bits2int($tag->{'SWF::Tag::content'}->readBits(2)); my $pbSize = SWF::_bits2int($tag->{'SWF::Tag::content'}->readBits(1)); my $pbType = SWF::_bits2int($tag->{'SWF::Tag::content'}->readBits(1)); my $sCompression = SWF::_bits2int($tag->{'SWF::Tag::content'}->readBits(4)); my $sRate = SWF::_bits2int($tag->{'SWF::Tag::content'}->readBits(2)); my $sSize = SWF::_bits2int($tag->{'SWF::Tag::content'}->readBits(1)); my $sType = SWF::_bits2int($tag->{'SWF::Tag::content'}->readBits(1)); my $sCount = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'PlaybackSoundRate'} = $pbRate; $tag->{'PlaybackSoundSize'} = $pbSize; $tag->{'PlaybackSoundType'} = $pbType; $tag->{'StreamSoundCompression'} = $sCompression; $tag->{'StreamSoundRate'} = $sRate; $tag->{'StreamSoundSize'} = $sSize; $tag->{'StreamSoundType'} = $sType; $tag->{'StreamSoundSampleCount'} = $sCount; return $tag; } sub pSoundStreamBlock { my $tag = shift; return $tag; } sub pDefineBitsLossless { my $tag = shift; return $tag; } sub pDefineBitsJPEG2 { my $tag = shift; return $tag; } sub pDefineShape2 { my $tag = shift; my $shapeID = unpack("S",$tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'ShapeId'} = $shapeID; print " ShapeID: $shapeID\n" if $debug; my $shapeBounds = SWF::Rect->new->read($tag->content); $tag->{'ShapeBounds'} = $shapeBounds; print " ShapeBounds: " if $debug; $shapeBounds->debug if $debug; my $shape = SWF::ShapeWithStyle->new; $shape->ShapeType(2); $shape->read($tag->{'SWF::Tag::content'}); $tag->{'Shapes'} = $shape; return $tag; } sub pDefineButtonCxform { my $tag = shift; my $buttonID = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'ButtonId'} = $buttonID; my $cxform = SWF::CXform->new->read($tag->content); $tag->{'ButtonColorTransform'} = $cxform; return $tag; } sub pProtect { # Protect tag - no action necessary my $tag = shift; return $tag; } sub pPathsArePostScript { my $tag = shift; return $tag; } sub pPlaceObject2 { my $tag = shift; my $pfReserved = $tag->{'SWF::Tag::content'}->readBits(1); my $pfHasDefineClip = $tag->{'SWF::Tag::content'}->readBits(1); my $pfHasName = $tag->{'SWF::Tag::content'}->readBits(1); my $pfHasRatio = $tag->{'SWF::Tag::content'}->readBits(1); my $pfHasColorTransform = $tag->{'SWF::Tag::content'}->readBits(1); my $pfHasMatrix = $tag->{'SWF::Tag::content'}->readBits(1); my $pfHasCharacter = $tag->{'SWF::Tag::content'}->readBits(1); my $pfMove = $tag->{'SWF::Tag::content'}->readBits(1); my $depth = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'Depth'} = $depth; print " Depth: $depth\n" if $debug; if ($pfHasCharacter) { my $charID = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'CharacterID'} = $charID; print " CharID: $charID\n" if $debug; } if ($pfHasMatrix) { my $matrix = SWF::Matrix->new->read($tag->content); $tag->{'Matrix'} = $matrix; $matrix->debug if $debug; } if ($pfHasColorTransform) { my $cxform = SWF::CXform->new->read($tag->content); $tag->{'ColorTransform'} = $cxform; $cxform->debug if $debug; } if ($pfHasRatio) { my $ratio = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'Ratio'} = $ratio; print " Ratio: $ratio\n" if $debug; } if ($pfHasDefineClip) { my $clipDepth = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'ClipDepth'} = $clipDepth; print " ClipDepth: $clipDepth\n" if $debug; } if ($pfHasName) { my $name = $tag->{'SWF::Tag::content'}->readString; $tag->{'Name'} = $name; print " Name: $name\n" if $debug; } return $tag; } sub pRemoveObject2 { my $tag = shift; my $depth = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'Depth'} = $depth; print " Depth: $depth\n" if $debug; return $tag; } sub pSyncFrame { my $tag = shift; return $tag; } sub pFreeAll { my $tag = shift; return $tag; } sub pDefineShape3 { my $tag = shift; my $shapeID = unpack("S",$tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'ShapeId'} = $shapeID; print " ShapeID: $shapeID\n" if $debug; my $shapeBounds = SWF::Rect->new->read($tag->content); $tag->{'ShapeBounds'} = $shapeBounds; print " ShapeBounds: " if $debug; $shapeBounds->debug if $debug; my $shape = SWF::ShapeWithStyle->new; $shape->ShapeType(3); $shape->read($tag->{'SWF::Tag::content'}); $tag->{'Shapes'} = $shape; return $tag; } sub pDefineText2 { my $tag = shift; my $textid = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); my $bounds = SWF::Rect->new->read($tag->content); my $matrix = SWF::Matrix->new->read($tag->content); my $glyphbits = ord($tag->{'SWF::Tag::content'}->readBytes(1)); my $advancebits = ord($tag->{'SWF::Tag::content'}->readBytes(1)); $tag->{'TextId'} = $textid; $tag->{'TextBounds'} = $bounds; $tag->{'TextMatrix'} = $matrix; $tag->{'TextGlyphBits'} = $glyphbits; $tag->{'TextAdvanceBits'} = $advancebits; my @records = (); my $readrec = 1; while ($readrec) { my $pos = $tag->{'SWF::Tag::content'}->tell; my $flag = ord($tag->{'SWF::Tag::content'}->readBytes(1)); if ($flag == 0) { $readrec = 0; } else { $tag->{'SWF::Tag::content'}->seek($pos-1); my $textrecord = SWF::TextRecord->new; $textrecord->GlyphBits($glyphbits); $textrecord->AdvanceBits($advancebits); $textrecord->TextType(2); $textrecord->read($tag->content); push @records, $textrecord; } } $tag->{'TextRecords'} = \@records; return $tag; } sub pDefineButton2 { # I'm not sure I understand this whole Button2ActionCondition offset # thing - I'll have to investigate some more before this tag is complete. my $tag = shift; my $buttonID = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'ButtonId'} = $buttonID; my $flags = ord($tag->{'SWF::Tag::content'}->readBytes(1)); $tag->{'Flags'} = $flags; my $offset = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'Offset'} = $offset; return $tag; } sub pDefineBitsJPEG3 { my $tag = shift; return $tag; } sub pDefineBitsLossless2 { my $tag = shift; return $tag; } sub pDefineEditText { my $tag = shift; my $textid = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); my $bounds = SWF::Rect->new->read($tag->content); my $hastext = $tag->{'SWF::Tag::content'}->readBits(1); my $wordwrap = $tag->{'SWF::Tag::content'}->readBits(1); my $multiline = $tag->{'SWF::Tag::content'}->readBits(1); my $password = $tag->{'SWF::Tag::content'}->readBits(1); my $readonly = $tag->{'SWF::Tag::content'}->readBits(1); my $hastextcolor = $tag->{'SWF::Tag::content'}->readBits(1); my $hasmaxlength = $tag->{'SWF::Tag::content'}->readBits(1); my $hasfont = $tag->{'SWF::Tag::content'}->readBits(1); my $reserved = $tag->{'SWF::Tag::content'}->readBits(2); my $haslayout = $tag->{'SWF::Tag::content'}->readBits(1); my $noselect = $tag->{'SWF::Tag::content'}->readBits(1); my $border = $tag->{'SWF::Tag::content'}->readBits(1); my $reserved2 = $tag->{'SWF::Tag::content'}->readBits(2); my $useoutlines = $tag->{'SWF::Tag::content'}->readBits(1); $tag->{'TextId'} = $textid; $tag->{'Bounds'} = $bounds; $tag->{'HasText'} = $hastext; $tag->{'WordWrap'} = $wordwrap; $tag->{'Multiline'} = $multiline; $tag->{'Password'} = $password; $tag->{'ReadOnly'} = $readonly; $tag->{'HasTextColor'} = $hastextcolor; $tag->{'HasMaxLength'} = $hasmaxlength; $tag->{'HasFont'} = $hasfont; $tag->{'HasLayout'} = $haslayout; $tag->{'NoSelect'} = $noselect; $tag->{'Border'} = $border; $tag->{'UseOutlines'} = $useoutlines; if ($hasfont) { my $fontid = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); my $fontheight = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'FontID'} = $fontid; $tag->{'FontHeight'} = $fontheight; } if ($hastextcolor) { my $textcolor = SWF::RGBA->new->read($tag->content); $tag->{'TextColor'} = $textcolor; } if ($hasmaxlength) { my $maxlength = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'MaxLength'} = $maxlength; } if ($haslayout) { my $align = ord($tag->{'SWF::Tag::content'}->readBytes(1)); my $leftmargin = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); my $rightmargin = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); my $indent = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); my $leading = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'Align'} = $align; $tag->{'LeftMargin'} = $leftmargin; $tag->{'RightMargin'} = $rightmargin; $tag->{'Indent'} = $indent; $tag->{'Leading'} = $leading; } my $variablename = SWF::String->new->read($tag->content); $tag->{'VariableName'} = $variablename; if ($hastext) { my $initialtext = SWF::String->new->read($tag->content); $tag->{'InitialText'} = $initialtext; } return $tag; } sub pDefineMovie { my $tag = shift; my $movieID = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'MovieID'} = $movieID; my $movieName = $tag->{'SWF::Tag::content'}->readString; $tag->{'MovieName'} = $movieName; return $tag; } sub pDefineSprite { my $tag = shift; return $tag; } sub pNameCharacter { my $tag = shift; return $tag; } sub pSerialNumber { my $tag = shift; return $tag; } sub pDefineTextFormat { my $tag = shift; return $tag; } sub pFrameLabel { # Add Frame Label - taken care of in control tag stuff up there my $tag = shift; print " Label: \"".$tag->{'Name'}."\" Frame: ".$tag->frame."\n" if $debug; return $tag; } sub pSoundStreamHead2 { my $tag = shift; my $reserved = $tag->{'SWF::Tag::content'}->readBits(4); my $pbRate = SWF::_bits2int($tag->{'SWF::Tag::content'}->readBits(2)); my $pbSize = SWF::_bits2int($tag->{'SWF::Tag::content'}->readBits(1)); my $pbType = SWF::_bits2int($tag->{'SWF::Tag::content'}->readBits(1)); my $sCompression = SWF::_bits2int($tag->{'SWF::Tag::content'}->readBits(4)); my $sRate = SWF::_bits2int($tag->{'SWF::Tag::content'}->readBits(2)); my $sSize = SWF::_bits2int($tag->{'SWF::Tag::content'}->readBits(1)); my $sType = SWF::_bits2int($tag->{'SWF::Tag::content'}->readBits(1)); my $sCount = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'PlaybackSoundRate'} = $pbRate; $tag->{'PlaybackSoundSize'} = $pbSize; $tag->{'PlaybackSoundType'} = $pbType; $tag->{'StreamSoundCompression'} = $sCompression; $tag->{'StreamSoundRate'} = $sRate; $tag->{'StreamSoundSize'} = $sSize; $tag->{'StreamSoundType'} = $sType; $tag->{'StreamSoundSampleCount'} = $sCount; return $tag; } sub pDefineMorphShape { my $tag = shift; my $charID = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); my $startbounds = SWF::Rect->new->read($tag->content); my $endbounds = SWF::Rect->new->read($tag->content); my $offset = unpack("L", $tag->{'SWF::Tag::content'}->readBytes(4)); my $mFillStyles = SWF::MorphFillStyles->new->read($tag->content); my $mLineStyles = SWF::MorphLineStyles->new->read($tag->content); my $startEdges = SWF::Shape->new->read($tag->content); my $endEdges = SWF::Shape->new->read($tag->content); $tag->{'CharacterID'} = $charID; $tag->{'StartBounds'} = $startbounds; $tag->{'EndBounds'} = $endbounds; $tag->{'Offset'} = $offset; $tag->{'MorphFillStyles'} = $mFillStyles; $tag->{'MorphLineStyles'} = $mLineStyles; $tag->{'StartEdges'} = $startEdges; $tag->{'EndEdges'} = $endEdges; return $tag; } sub pFrameTag { my $tag = shift; return $tag; } sub pDefineFont2 { my $tag = shift; my $fontid = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'FontId'} = $fontid; my $haslayout = $tag->{'SWF::Tag::content'}->readBits(1); my $shiftJIS = $tag->{'SWF::Tag::content'}->readBits(1); my $unicode = $tag->{'SWF::Tag::content'}->readBits(1); my $ANSI = $tag->{'SWF::Tag::content'}->readBits(1); my $wideoffsets = $tag->{'SWF::Tag::content'}->readBits(1); my $widecodes = $tag->{'SWF::Tag::content'}->readBits(1); my $italic = $tag->{'SWF::Tag::content'}->readBits(1); my $bold = $tag->{'SWF::Tag::content'}->readBits(1); my $reserved = $tag->{'SWF::Tag::content'}->readBits(8); my $namelen = ord($tag->{'SWF::Tag::content'}->readBytes(1)); my $name = $tag->{'SWF::Tag::content'}->readBytes($namelen); my $glyphcount = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'FontFlagsHasLayout'} = $haslayout; $tag->{'FontFlagsShiftJIS'} = $shiftJIS; $tag->{'FontFlagsUnicode'} = $unicode; $tag->{'FontFlagsAnsi'} = $ANSI; $tag->{'FontFlagsWideOffsets'} = $wideoffsets; $tag->{'FontFlagsWideCodes'} = $widecodes; $tag->{'FontFlagsItalic'} = $italic; $tag->{'FontFlagsBold'} = $bold; $tag->{'FontFlagsReserved'} = $reserved; $tag->{'FontNameLen'} = $namelen; $tag->{'FontName'} = $name; no warnings; my @offsets; my $i = 0; while ($i < $glyphcount) { my $offset; if ($wideoffsets) { $offset = unpack("L", $tag->{'SWF::Tag::content'}->readBytes(4)); } else { $offset = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); } push @offsets, $offset; $i++; } $tag->{'FontOffsetTable'} = \@offsets; my $codeoffset; if ($wideoffsets) { $codeoffset = unpack("L", $tag->{'SWF::Tag::content'}->readBytes(4)); } else { $codeoffset = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); } $tag->{'FontCodeOffset'} = $codeoffset; my @shapes; $i = 0; while ($i < $glyphcount) { my $shape = SWF::Shape->new->read($tag->content); push @shapes, $shape; $i++; } $tag->{'FontShapeTable'} = \@shapes; my @codes; $i = 0; while ($i < $glyphcount) { my $code; if ($widecodes) { $code = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); } else { $code = unpack("C", $tag->{'SWF::Tag::content'}->readBytes(1)); } push @codes, $code; $i++; } $tag->{'FontCodeTable'} = \@codes; if ($haslayout) { my $ascent = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); my $descent = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); my $leading = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'FontAscent'} = $ascent; $tag->{'FontDescent'} = $descent; $tag->{'FontLeading'} = $leading; my @advances; $i = 0; while ($i < $glyphcount) { my $advance = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); push @advances, $advance; $i++; } $tag->{'FontAdvanceTable'} = \@advances; my @bounds; $i = 0; while ($i < $glyphcount) { my $bound = SWF::Rect->new->read($tag->content); push @bounds, $bound; $i++; } $tag->{'FontBoundsTable'} = \@bounds; my $kerningcount = unpack("S", $tag->{'SWF::Tag::content'}->readBytes(2)); $tag->{'FontKerningCount'} = $kerningcount; my @kernings; $i = 0; while ($i < $kerningcount) { my $kerning = SWF::KerningRecord->new->read($tag->content); push @kernings, $kerning; $i++; } $tag->{'FontKerningTable'} = \@kernings; } return $tag; } sub pGenCommand { my $tag = shift; return $tag; } sub pDefineCommandObj { my $tag = shift; return $tag; } sub pCharacterSet { my $tag = shift; return $tag; } sub pFontRef { my $tag = shift; return $tag; } sub pDefineBitsPtr { my $tag = shift; return $tag; } 1;